ProcFS.cpp 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177
  1. #include "ProcFS.h"
  2. #include "Process.h"
  3. #include <Kernel/VirtualFileSystem.h>
  4. #include "system.h"
  5. #include "MemoryManager.h"
  6. #include "StdLib.h"
  7. #include "i386.h"
  8. #include "KSyms.h"
  9. #include "Console.h"
  10. #include "Scheduler.h"
  11. #include <Kernel/PCI.h>
  12. #include <AK/StringBuilder.h>
  13. #include <LibC/errno_numbers.h>
  14. enum ProcParentDirectory {
  15. PDI_AbstractRoot = 0,
  16. PDI_Root,
  17. PDI_Root_sys,
  18. PDI_PID,
  19. PDI_PID_fd,
  20. };
  21. enum ProcFileType {
  22. FI_Invalid = 0,
  23. FI_Root = 1, // directory
  24. __FI_Root_Start,
  25. FI_Root_mm,
  26. FI_Root_mounts,
  27. FI_Root_df,
  28. FI_Root_kmalloc,
  29. FI_Root_all,
  30. FI_Root_memstat,
  31. FI_Root_summary,
  32. FI_Root_cpuinfo,
  33. FI_Root_inodes,
  34. FI_Root_dmesg,
  35. FI_Root_pci,
  36. FI_Root_self, // symlink
  37. FI_Root_sys, // directory
  38. __FI_Root_End,
  39. FI_PID,
  40. __FI_PID_Start,
  41. FI_PID_vm,
  42. FI_PID_vmo,
  43. FI_PID_stack,
  44. FI_PID_regs,
  45. FI_PID_fds,
  46. FI_PID_exe, // symlink
  47. FI_PID_cwd, // symlink
  48. FI_PID_fd, // directory
  49. __FI_PID_End,
  50. FI_MaxStaticFileIndex,
  51. };
  52. static inline pid_t to_pid(const InodeIdentifier& identifier)
  53. {
  54. #ifdef PROCFS_DEBUG
  55. dbgprintf("to_pid, index=%08x -> %u\n", identifier.index(), identifier.index() >> 16);
  56. #endif
  57. return identifier.index() >> 16u;
  58. }
  59. static inline ProcParentDirectory to_proc_parent_directory(const InodeIdentifier& identifier)
  60. {
  61. return (ProcParentDirectory)((identifier.index() >> 12) & 0xf);
  62. }
  63. static inline int to_fd(const InodeIdentifier& identifier)
  64. {
  65. ASSERT(to_proc_parent_directory(identifier) == PDI_PID_fd);
  66. return (identifier.index() & 0xff) - FI_MaxStaticFileIndex;
  67. }
  68. static inline unsigned to_sys_index(const InodeIdentifier& identifier)
  69. {
  70. ASSERT(to_proc_parent_directory(identifier) == PDI_Root_sys);
  71. return identifier.index() & 0xff;
  72. }
  73. static inline InodeIdentifier to_identifier(unsigned fsid, ProcParentDirectory parent, pid_t pid, ProcFileType proc_file_type)
  74. {
  75. return { fsid, ((unsigned)parent << 12u) | ((unsigned)pid << 16u) | (unsigned)proc_file_type };
  76. }
  77. static inline InodeIdentifier to_identifier_with_fd(unsigned fsid, pid_t pid, int fd)
  78. {
  79. return { fsid, (PDI_PID_fd << 12u) | ((unsigned)pid << 16u) | (FI_MaxStaticFileIndex + fd) };
  80. }
  81. static inline InodeIdentifier sys_var_to_identifier(unsigned fsid, unsigned index)
  82. {
  83. ASSERT(index < 256);
  84. return { fsid, (PDI_Root_sys << 12u) | index };
  85. }
  86. static inline InodeIdentifier to_parent_id(const InodeIdentifier& identifier)
  87. {
  88. switch (to_proc_parent_directory(identifier)) {
  89. case PDI_AbstractRoot:
  90. case PDI_Root:
  91. return { identifier.fsid(), FI_Root };
  92. case PDI_Root_sys:
  93. return { identifier.fsid(), FI_Root_sys };
  94. case PDI_PID:
  95. return to_identifier(identifier.fsid(), PDI_Root, to_pid(identifier), FI_PID);
  96. case PDI_PID_fd:
  97. return to_identifier(identifier.fsid(), PDI_PID, to_pid(identifier), FI_PID_fd);
  98. }
  99. ASSERT_NOT_REACHED();
  100. }
  101. #if 0
  102. static inline byte to_unused_metadata(const InodeIdentifier& identifier)
  103. {
  104. return (identifier.index() >> 8) & 0xf;
  105. }
  106. #endif
  107. static inline ProcFileType to_proc_file_type(const InodeIdentifier& identifier)
  108. {
  109. return (ProcFileType)(identifier.index() & 0xff);
  110. }
  111. static inline bool is_process_related_file(const InodeIdentifier& identifier)
  112. {
  113. if (to_proc_file_type(identifier) == FI_PID)
  114. return true;
  115. auto proc_parent_directory = to_proc_parent_directory(identifier);
  116. switch (proc_parent_directory) {
  117. case PDI_PID:
  118. case PDI_PID_fd:
  119. return true;
  120. default:
  121. return false;
  122. }
  123. }
  124. static inline bool is_directory(const InodeIdentifier& identifier)
  125. {
  126. auto proc_file_type = to_proc_file_type(identifier);
  127. switch (proc_file_type) {
  128. case FI_Root:
  129. case FI_Root_sys:
  130. case FI_PID:
  131. case FI_PID_fd:
  132. return true;
  133. default:
  134. return false;
  135. }
  136. }
  137. static inline bool is_persistent_inode(const InodeIdentifier& identifier)
  138. {
  139. return to_proc_parent_directory(identifier) == PDI_Root_sys;
  140. }
  141. static ProcFS* s_the;
  142. ProcFS& ProcFS::the()
  143. {
  144. ASSERT(s_the);
  145. return *s_the;
  146. }
  147. Retained<ProcFS> ProcFS::create()
  148. {
  149. return adopt(*new ProcFS);
  150. }
  151. ProcFS::~ProcFS()
  152. {
  153. }
  154. ByteBuffer procfs$pid_fds(InodeIdentifier identifier)
  155. {
  156. auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier));
  157. if (!handle)
  158. return { };
  159. auto& process = handle->process();
  160. if (process.number_of_open_file_descriptors() == 0)
  161. return { };
  162. StringBuilder builder;
  163. for (size_t i = 0; i < process.max_open_file_descriptors(); ++i) {
  164. auto* descriptor = process.file_descriptor(i);
  165. if (!descriptor)
  166. continue;
  167. auto result = descriptor->absolute_path();
  168. if (result.is_error())
  169. continue;
  170. builder.appendf("% 3u %s\n", i, result.value().characters());
  171. }
  172. return builder.to_byte_buffer();
  173. }
  174. ByteBuffer procfs$pid_fd_entry(InodeIdentifier identifier)
  175. {
  176. auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier));
  177. if (!handle)
  178. return { };
  179. auto& process = handle->process();
  180. int fd = to_fd(identifier);
  181. auto* descriptor = process.file_descriptor(fd);
  182. if (!descriptor)
  183. return { };
  184. auto result = descriptor->absolute_path();
  185. if (result.is_error())
  186. return { };
  187. return result.value().to_byte_buffer();
  188. }
  189. ByteBuffer procfs$pid_vm(InodeIdentifier identifier)
  190. {
  191. auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier));
  192. if (!handle)
  193. return { };
  194. auto& process = handle->process();
  195. StringBuilder builder;
  196. builder.appendf("BEGIN END SIZE COMMIT FLAGS NAME\n");
  197. for (auto& region : process.regions()) {
  198. StringBuilder flags_builder;
  199. if (region->is_readable())
  200. flags_builder.append('R');
  201. if (region->is_writable())
  202. flags_builder.append('W');
  203. if (region->is_bitmap())
  204. flags_builder.append('B');
  205. builder.appendf("%x -- %x %x %x % 4s %s\n",
  206. region->laddr().get(),
  207. region->laddr().offset(region->size() - 1).get(),
  208. region->size(),
  209. region->amount_resident(),
  210. flags_builder.to_string().characters(),
  211. region->name().characters());
  212. }
  213. return builder.to_byte_buffer();
  214. }
  215. ByteBuffer procfs$pci(InodeIdentifier)
  216. {
  217. StringBuilder builder;
  218. PCI::enumerate_all([&builder] (PCI::Address address, PCI::ID id) {
  219. builder.appendf("%b:%b.%b %w:%w\n", address.bus(), address.slot(), address.function(), id.vendor_id, id.device_id);
  220. });
  221. return builder.to_byte_buffer();
  222. }
  223. ByteBuffer procfs$pid_vmo(InodeIdentifier identifier)
  224. {
  225. auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier));
  226. if (!handle)
  227. return { };
  228. auto& process = handle->process();
  229. StringBuilder builder;
  230. builder.appendf("BEGIN END SIZE NAME\n");
  231. for (auto& region : process.regions()) {
  232. builder.appendf("%x -- %x %x %s\n",
  233. region->laddr().get(),
  234. region->laddr().offset(region->size() - 1).get(),
  235. region->size(),
  236. region->name().characters());
  237. builder.appendf("VMO: %s \"%s\" @ %x(%u)\n",
  238. region->vmo().is_anonymous() ? "anonymous" : "file-backed",
  239. region->vmo().name().characters(),
  240. &region->vmo(),
  241. region->vmo().retain_count());
  242. for (size_t i = 0; i < region->vmo().page_count(); ++i) {
  243. auto& physical_page = region->vmo().physical_pages()[i];
  244. builder.appendf("P%x%s(%u) ",
  245. physical_page ? physical_page->paddr().get() : 0,
  246. region->cow_map().get(i) ? "!" : "",
  247. physical_page ? physical_page->retain_count() : 0
  248. );
  249. }
  250. builder.appendf("\n");
  251. }
  252. return builder.to_byte_buffer();
  253. }
  254. ByteBuffer procfs$pid_stack(InodeIdentifier identifier)
  255. {
  256. auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier));
  257. if (!handle)
  258. return { };
  259. auto& process = handle->process();
  260. ProcessPagingScope paging_scope(process);
  261. struct RecognizedSymbol {
  262. dword address;
  263. const KSym* ksym;
  264. };
  265. StringBuilder builder;
  266. process.for_each_thread([&] (Thread& thread) {
  267. builder.appendf("Thread %d:\n", thread.tid());
  268. Vector<RecognizedSymbol> recognized_symbols;
  269. if (auto* eip_ksym = ksymbolicate(thread.tss().eip))
  270. recognized_symbols.append({ thread.tss().eip, eip_ksym });
  271. for (dword* stack_ptr = (dword*)thread.frame_ptr(); process.validate_read_from_kernel(LinearAddress((dword)stack_ptr)); stack_ptr = (dword*)*stack_ptr) {
  272. dword retaddr = stack_ptr[1];
  273. if (auto* ksym = ksymbolicate(retaddr))
  274. recognized_symbols.append({ retaddr, ksym });
  275. }
  276. for (auto& symbol : recognized_symbols) {
  277. unsigned offset = symbol.address - symbol.ksym->address;
  278. builder.appendf("%p %s +%u\n", symbol.address, symbol.ksym->name, offset);
  279. }
  280. return IterationDecision::Continue;
  281. });
  282. return builder.to_byte_buffer();
  283. }
  284. ByteBuffer procfs$pid_regs(InodeIdentifier identifier)
  285. {
  286. auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier));
  287. if (!handle)
  288. return { };
  289. auto& process = handle->process();
  290. StringBuilder builder;
  291. process.for_each_thread([&] (Thread& thread) {
  292. builder.appendf("Thread %d:\n", thread.tid());
  293. auto& tss = thread.tss();
  294. builder.appendf("eax: %x\n", tss.eax);
  295. builder.appendf("ebx: %x\n", tss.ebx);
  296. builder.appendf("ecx: %x\n", tss.ecx);
  297. builder.appendf("edx: %x\n", tss.edx);
  298. builder.appendf("esi: %x\n", tss.esi);
  299. builder.appendf("edi: %x\n", tss.edi);
  300. builder.appendf("ebp: %x\n", tss.ebp);
  301. builder.appendf("cr3: %x\n", tss.cr3);
  302. builder.appendf("flg: %x\n", tss.eflags);
  303. builder.appendf("sp: %w:%x\n", tss.ss, tss.esp);
  304. builder.appendf("pc: %w:%x\n", tss.cs, tss.eip);
  305. return IterationDecision::Continue;
  306. });
  307. return builder.to_byte_buffer();
  308. }
  309. ByteBuffer procfs$pid_exe(InodeIdentifier identifier)
  310. {
  311. auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier));
  312. if (!handle)
  313. return { };
  314. auto& process = handle->process();
  315. auto inode = process.executable_inode();
  316. ASSERT(inode);
  317. auto result = VFS::the().absolute_path(*inode);
  318. if (result.is_error())
  319. return { };
  320. return result.value().to_byte_buffer();
  321. }
  322. ByteBuffer procfs$pid_cwd(InodeIdentifier identifier)
  323. {
  324. auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier));
  325. if (!handle)
  326. return { };
  327. auto result = VFS::the().absolute_path(handle->process().cwd_inode());
  328. if (result.is_error())
  329. return { };
  330. return result.value().to_byte_buffer();
  331. }
  332. ByteBuffer procfs$self(InodeIdentifier)
  333. {
  334. char buffer[16];
  335. ksprintf(buffer, "%u", current->pid());
  336. return ByteBuffer::copy((const byte*)buffer, strlen(buffer));
  337. }
  338. ByteBuffer procfs$mm(InodeIdentifier)
  339. {
  340. // FIXME: Implement
  341. InterruptDisabler disabler;
  342. StringBuilder builder;
  343. for (auto* vmo : MM.m_vmos) {
  344. builder.appendf("VMO: %p %s(%u): p:%4u %s\n",
  345. vmo,
  346. vmo->is_anonymous() ? "anon" : "file",
  347. vmo->retain_count(),
  348. vmo->page_count(),
  349. vmo->name().characters());
  350. }
  351. builder.appendf("VMO count: %u\n", MM.m_vmos.size());
  352. builder.appendf("Free physical pages: %u\n", MM.m_free_physical_pages.size());
  353. builder.appendf("Free supervisor physical pages: %u\n", MM.m_free_supervisor_physical_pages.size());
  354. return builder.to_byte_buffer();
  355. }
  356. ByteBuffer procfs$dmesg(InodeIdentifier)
  357. {
  358. InterruptDisabler disabler;
  359. StringBuilder builder;
  360. for (char ch : Console::the().logbuffer())
  361. builder.append(ch);
  362. return builder.to_byte_buffer();
  363. }
  364. ByteBuffer procfs$mounts(InodeIdentifier)
  365. {
  366. // FIXME: This is obviously racy against the VFS mounts changing.
  367. StringBuilder builder;
  368. VFS::the().for_each_mount([&builder] (auto& mount) {
  369. auto& fs = mount.guest_fs();
  370. builder.appendf("%s @ ", fs.class_name());
  371. if (!mount.host().is_valid())
  372. builder.appendf("/");
  373. else {
  374. builder.appendf("%u:%u", mount.host().fsid(), mount.host().index());
  375. builder.append(' ');
  376. auto result = VFS::the().absolute_path(mount.host());
  377. if (result.is_error())
  378. builder.append("[error]");
  379. else
  380. builder.append(result.value());
  381. }
  382. builder.append('\n');
  383. });
  384. return builder.to_byte_buffer();
  385. }
  386. ByteBuffer procfs$df(InodeIdentifier)
  387. {
  388. // FIXME: This is obviously racy against the VFS mounts changing.
  389. StringBuilder builder;
  390. VFS::the().for_each_mount([&builder] (auto& mount) {
  391. auto& fs = mount.guest_fs();
  392. builder.appendf("%s,", fs.class_name());
  393. builder.appendf("%u,", fs.total_block_count());
  394. builder.appendf("%u,", fs.free_block_count());
  395. builder.appendf("%u,", fs.total_inode_count());
  396. builder.appendf("%u,", fs.free_inode_count());
  397. if (!mount.host().is_valid())
  398. builder.append("/");
  399. else {
  400. auto result = VFS::the().absolute_path(mount.host());
  401. if (result.is_error())
  402. builder.append("[Error]");
  403. else
  404. builder.append(result.value());
  405. }
  406. builder.append('\n');
  407. });
  408. return builder.to_byte_buffer();
  409. }
  410. ByteBuffer procfs$cpuinfo(InodeIdentifier)
  411. {
  412. StringBuilder builder;
  413. {
  414. CPUID cpuid(0);
  415. builder.appendf("cpuid: ");
  416. auto emit_dword = [&] (dword value) {
  417. builder.appendf("%c%c%c%c",
  418. value & 0xff,
  419. (value >> 8) & 0xff,
  420. (value >> 16) & 0xff,
  421. (value >> 24) & 0xff);
  422. };
  423. emit_dword(cpuid.ebx());
  424. emit_dword(cpuid.edx());
  425. emit_dword(cpuid.ecx());
  426. builder.appendf("\n");
  427. }
  428. {
  429. CPUID cpuid(1);
  430. dword stepping = cpuid.eax() & 0xf;
  431. dword model = (cpuid.eax() >> 4) & 0xf;
  432. dword family = (cpuid.eax() >> 8) & 0xf;
  433. dword type = (cpuid.eax() >> 12) & 0x3;
  434. dword extended_model = (cpuid.eax() >> 16) & 0xf;
  435. dword extended_family = (cpuid.eax() >> 20) & 0xff;
  436. dword display_model;
  437. dword display_family;
  438. if (family == 15) {
  439. display_family = family + extended_family;
  440. display_model = model + (extended_model << 4);
  441. } else if (family == 6) {
  442. display_family = family;
  443. display_model = model + (extended_model << 4);
  444. } else {
  445. display_family = family;
  446. display_model = model;
  447. }
  448. builder.appendf("family: %u\n", display_family);
  449. builder.appendf("model: %u\n", display_model);
  450. builder.appendf("stepping: %u\n", stepping);
  451. builder.appendf("type: %u\n", type);
  452. }
  453. {
  454. // FIXME: Check first that this is supported by calling CPUID with eax=0x80000000
  455. // and verifying that the returned eax>=0x80000004.
  456. char buffer[48];
  457. dword* bufptr = reinterpret_cast<dword*>(buffer);
  458. auto copy_brand_string_part_to_buffer = [&] (dword i) {
  459. CPUID cpuid(0x80000002 + i);
  460. *bufptr++ = cpuid.eax();
  461. *bufptr++ = cpuid.ebx();
  462. *bufptr++ = cpuid.ecx();
  463. *bufptr++ = cpuid.edx();
  464. };
  465. copy_brand_string_part_to_buffer(0);
  466. copy_brand_string_part_to_buffer(1);
  467. copy_brand_string_part_to_buffer(2);
  468. builder.appendf("brandstr: \"%s\"\n", buffer);
  469. }
  470. return builder.to_byte_buffer();
  471. }
  472. ByteBuffer procfs$kmalloc(InodeIdentifier)
  473. {
  474. StringBuilder builder;
  475. builder.appendf(
  476. "eternal: %u\n"
  477. "allocated: %u\n"
  478. "free: %u\n",
  479. kmalloc_sum_eternal,
  480. sum_alloc,
  481. sum_free
  482. );
  483. return builder.to_byte_buffer();
  484. }
  485. ByteBuffer procfs$summary(InodeIdentifier)
  486. {
  487. InterruptDisabler disabler;
  488. auto processes = Process::all_processes();
  489. StringBuilder builder;
  490. builder.appendf("PID TPG PGP SID OWNER STATE PPID NSCHED FDS TTY NAME\n");
  491. for (auto* process : processes) {
  492. builder.appendf("% 3u % 3u % 3u % 3u % 4u % 8s % 3u % 9u % 3u % 4s %s\n",
  493. process->pid(),
  494. process->tty() ? process->tty()->pgid() : 0,
  495. process->pgid(),
  496. process->sid(),
  497. process->uid(),
  498. to_string(process->state()),
  499. process->ppid(),
  500. process->main_thread().times_scheduled(), // FIXME(Thread): Bill all scheds to the process
  501. process->number_of_open_file_descriptors(),
  502. process->tty() ? strrchr(process->tty()->tty_name().characters(), '/') + 1 : "n/a",
  503. process->name().characters());
  504. }
  505. return builder.to_byte_buffer();
  506. }
  507. ByteBuffer procfs$memstat(InodeIdentifier)
  508. {
  509. InterruptDisabler disabler;
  510. StringBuilder builder;
  511. builder.appendf("%u,%u,%u,%u,%u,%u,%u\n",
  512. kmalloc_sum_eternal,
  513. sum_alloc,
  514. sum_free,
  515. MM.user_physical_pages_in_existence() - MM.m_free_physical_pages.size(),
  516. MM.m_free_physical_pages.size(),
  517. MM.super_physical_pages_in_existence() - MM.m_free_supervisor_physical_pages.size(),
  518. MM.m_free_supervisor_physical_pages.size()
  519. );
  520. return builder.to_byte_buffer();
  521. }
  522. ByteBuffer procfs$all(InodeIdentifier)
  523. {
  524. InterruptDisabler disabler;
  525. auto processes = Process::all_processes();
  526. StringBuilder builder;
  527. auto build_process_line = [&builder] (Process* process) {
  528. builder.appendf("%u,%u,%u,%u,%u,%u,%u,%s,%u,%u,%s,%s,%u,%u,%u,%u,%s\n",
  529. process->pid(),
  530. process->main_thread().times_scheduled(), // FIXME(Thread): Bill all scheds to the process
  531. process->tty() ? process->tty()->pgid() : 0,
  532. process->pgid(),
  533. process->sid(),
  534. process->uid(),
  535. process->gid(),
  536. to_string(process->state()),
  537. process->ppid(),
  538. process->number_of_open_file_descriptors(),
  539. process->tty() ? process->tty()->tty_name().characters() : "notty",
  540. process->name().characters(),
  541. process->amount_virtual(),
  542. process->amount_resident(),
  543. process->amount_shared(),
  544. process->main_thread().ticks(), // FIXME(Thread): Bill all ticks to the process
  545. to_string(process->priority())
  546. );
  547. };
  548. build_process_line(Scheduler::colonel());
  549. for (auto* process : processes)
  550. build_process_line(process);
  551. return builder.to_byte_buffer();
  552. }
  553. ByteBuffer procfs$inodes(InodeIdentifier)
  554. {
  555. extern HashTable<Inode*>& all_inodes();
  556. StringBuilder builder;
  557. for (auto it : all_inodes()) {
  558. RetainPtr<Inode> inode = *it;
  559. auto result = VFS::the().absolute_path(*inode);
  560. if (result.is_error())
  561. continue;
  562. auto path = result.value();
  563. builder.appendf("Inode{K%x} %02u:%08u (%u) %s\n", inode.ptr(), inode->fsid(), inode->index(), inode->retain_count(), path.characters());
  564. }
  565. return builder.to_byte_buffer();
  566. }
  567. struct SysVariableData final : public ProcFSInodeCustomData {
  568. virtual ~SysVariableData() override { }
  569. enum Type {
  570. Invalid,
  571. Boolean,
  572. String,
  573. };
  574. Type type { Invalid };
  575. Function<void()> notify_callback;
  576. void* address;
  577. };
  578. static ByteBuffer read_sys_bool(InodeIdentifier inode_id)
  579. {
  580. auto inode_ptr = ProcFS::the().get_inode(inode_id);
  581. if (!inode_ptr)
  582. return { };
  583. auto& inode = static_cast<ProcFSInode&>(*inode_ptr);
  584. ASSERT(inode.custom_data());
  585. auto buffer = ByteBuffer::create_uninitialized(2);
  586. auto& custom_data = *static_cast<const SysVariableData*>(inode.custom_data());
  587. ASSERT(custom_data.type == SysVariableData::Boolean);
  588. ASSERT(custom_data.address);
  589. auto* lockable_bool = reinterpret_cast<Lockable<bool>*>(custom_data.address);
  590. {
  591. LOCKER(lockable_bool->lock());
  592. buffer[0] = lockable_bool->resource() ? '1' : '0';
  593. }
  594. buffer[1] = '\n';
  595. return buffer;
  596. }
  597. static ssize_t write_sys_bool(InodeIdentifier inode_id, const ByteBuffer& data)
  598. {
  599. auto inode_ptr = ProcFS::the().get_inode(inode_id);
  600. if (!inode_ptr)
  601. return { };
  602. auto& inode = static_cast<ProcFSInode&>(*inode_ptr);
  603. ASSERT(inode.custom_data());
  604. if (data.is_empty() || !(data[0] == '0' || data[0] == '1'))
  605. return data.size();
  606. auto& custom_data = *static_cast<const SysVariableData*>(inode.custom_data());
  607. auto* lockable_bool = reinterpret_cast<Lockable<bool>*>(custom_data.address);
  608. {
  609. LOCKER(lockable_bool->lock());
  610. lockable_bool->resource() = data[0] == '1';
  611. }
  612. if (custom_data.notify_callback)
  613. custom_data.notify_callback();
  614. return data.size();
  615. }
  616. static ByteBuffer read_sys_string(InodeIdentifier inode_id)
  617. {
  618. auto inode_ptr = ProcFS::the().get_inode(inode_id);
  619. if (!inode_ptr)
  620. return { };
  621. auto& inode = static_cast<ProcFSInode&>(*inode_ptr);
  622. ASSERT(inode.custom_data());
  623. auto buffer = ByteBuffer::create_uninitialized(2);
  624. auto& custom_data = *static_cast<const SysVariableData*>(inode.custom_data());
  625. ASSERT(custom_data.type == SysVariableData::String);
  626. ASSERT(custom_data.address);
  627. auto* lockable_string = reinterpret_cast<Lockable<String>*>(custom_data.address);
  628. LOCKER(lockable_string->lock());
  629. return lockable_string->resource().to_byte_buffer();
  630. }
  631. static ssize_t write_sys_string(InodeIdentifier inode_id, const ByteBuffer& data)
  632. {
  633. auto inode_ptr = ProcFS::the().get_inode(inode_id);
  634. if (!inode_ptr)
  635. return { };
  636. auto& inode = static_cast<ProcFSInode&>(*inode_ptr);
  637. ASSERT(inode.custom_data());
  638. auto& custom_data = *static_cast<const SysVariableData*>(inode.custom_data());
  639. ASSERT(custom_data.address);
  640. {
  641. auto* lockable_string = reinterpret_cast<Lockable<String>*>(custom_data.address);
  642. LOCKER(lockable_string->lock());
  643. lockable_string->resource() = String((const char*)data.pointer(), data.size());
  644. }
  645. if (custom_data.notify_callback)
  646. custom_data.notify_callback();
  647. return data.size();
  648. }
  649. void ProcFS::add_sys_bool(String&& name, Lockable<bool>& var, Function<void()>&& notify_callback)
  650. {
  651. InterruptDisabler disabler;
  652. unsigned index = m_sys_entries.size();
  653. auto inode = adopt(*new ProcFSInode(*this, sys_var_to_identifier(fsid(), index).index()));
  654. auto data = make<SysVariableData>();
  655. data->type = SysVariableData::Boolean;
  656. data->notify_callback = move(notify_callback);
  657. data->address = &var;
  658. inode->set_custom_data(move(data));
  659. m_sys_entries.append({ strdup(name.characters()), name.length(), read_sys_bool, write_sys_bool, move(inode) });
  660. }
  661. void ProcFS::add_sys_string(String&& name, Lockable<String>& var, Function<void()>&& notify_callback)
  662. {
  663. InterruptDisabler disabler;
  664. unsigned index = m_sys_entries.size();
  665. auto inode = adopt(*new ProcFSInode(*this, sys_var_to_identifier(fsid(), index).index()));
  666. auto data = make<SysVariableData>();
  667. data->type = SysVariableData::String;
  668. data->notify_callback = move(notify_callback);
  669. data->address = &var;
  670. inode->set_custom_data(move(data));
  671. m_sys_entries.append({ strdup(name.characters()), name.length(), read_sys_string, write_sys_string, move(inode) });
  672. }
  673. bool ProcFS::initialize()
  674. {
  675. return true;
  676. }
  677. const char* ProcFS::class_name() const
  678. {
  679. return "ProcFS";
  680. }
  681. RetainPtr<Inode> ProcFS::create_inode(InodeIdentifier parentInode, const String& name, mode_t mode, unsigned size, int& error)
  682. {
  683. (void) parentInode;
  684. (void) name;
  685. (void) mode;
  686. (void) size;
  687. (void) error;
  688. kprintf("FIXME: Implement ProcFS::create_inode()?\n");
  689. return { };
  690. }
  691. RetainPtr<Inode> ProcFS::create_directory(InodeIdentifier, const String&, mode_t, int& error)
  692. {
  693. error = -EROFS;
  694. return nullptr;
  695. }
  696. RetainPtr<Inode> ProcFSInode::parent() const
  697. {
  698. return fs().get_inode(to_parent_id(identifier()));
  699. }
  700. InodeIdentifier ProcFS::root_inode() const
  701. {
  702. return { fsid(), FI_Root };
  703. }
  704. RetainPtr<Inode> ProcFS::get_inode(InodeIdentifier inode_id) const
  705. {
  706. #ifdef PROCFS_DEBUG
  707. dbgprintf("ProcFS::get_inode(%u)\n", inode_id.index());
  708. #endif
  709. if (inode_id == root_inode())
  710. return m_root_inode;
  711. if (to_proc_parent_directory(inode_id) == ProcParentDirectory::PDI_Root_sys) {
  712. auto sys_index = to_sys_index(inode_id);
  713. if (sys_index < m_sys_entries.size())
  714. return m_sys_entries[sys_index].inode;
  715. }
  716. LOCKER(m_inodes_lock);
  717. auto it = m_inodes.find(inode_id.index());
  718. if (it == m_inodes.end()) {
  719. auto inode = adopt(*new ProcFSInode(const_cast<ProcFS&>(*this), inode_id.index()));
  720. m_inodes.set(inode_id.index(), inode.ptr());
  721. return inode;
  722. }
  723. return (*it).value;
  724. }
  725. ProcFSInode::ProcFSInode(ProcFS& fs, unsigned index)
  726. : Inode(fs, index)
  727. {
  728. }
  729. ProcFSInode::~ProcFSInode()
  730. {
  731. LOCKER(fs().m_inodes_lock);
  732. fs().m_inodes.remove(index());
  733. }
  734. InodeMetadata ProcFSInode::metadata() const
  735. {
  736. #ifdef PROCFS_DEBUG
  737. dbgprintf("ProcFSInode::metadata(%u)\n", index());
  738. #endif
  739. InodeMetadata metadata;
  740. metadata.inode = identifier();
  741. metadata.ctime = mepoch;
  742. metadata.atime = mepoch;
  743. metadata.mtime = mepoch;
  744. auto proc_parent_directory = to_proc_parent_directory(identifier());
  745. auto pid = to_pid(identifier());
  746. auto proc_file_type = to_proc_file_type(identifier());
  747. #ifdef PROCFS_DEBUG
  748. dbgprintf(" -> pid: %d, fi: %u, pdi: %u\n", pid, proc_file_type, proc_parent_directory);
  749. #endif
  750. if (is_process_related_file(identifier())) {
  751. auto handle = ProcessInspectionHandle::from_pid(pid);
  752. metadata.uid = handle->process().sys$getuid();
  753. metadata.gid = handle->process().sys$getgid();
  754. }
  755. if (proc_parent_directory == PDI_PID_fd) {
  756. metadata.mode = 00120777;
  757. return metadata;
  758. }
  759. if (proc_parent_directory == PDI_Root_sys) {
  760. metadata.mode = 00100644;
  761. return metadata;
  762. }
  763. switch (proc_file_type) {
  764. case FI_Root_self:
  765. case FI_PID_cwd:
  766. case FI_PID_exe:
  767. metadata.mode = 0120777;
  768. break;
  769. case FI_Root:
  770. case FI_Root_sys:
  771. case FI_PID:
  772. case FI_PID_fd:
  773. metadata.mode = 040777;
  774. break;
  775. default:
  776. metadata.mode = 0100644;
  777. break;
  778. }
  779. #ifdef PROCFS_DEBUG
  780. dbgprintf("Returning mode %o\n", metadata.mode);
  781. #endif
  782. return metadata;
  783. }
  784. ssize_t ProcFSInode::read_bytes(off_t offset, ssize_t count, byte* buffer, FileDescriptor* descriptor) const
  785. {
  786. #ifdef PROCFS_DEBUG
  787. dbgprintf("ProcFS: read_bytes %u\n", index());
  788. #endif
  789. ASSERT(offset >= 0);
  790. ASSERT(buffer);
  791. auto* directory_entry = fs().get_directory_entry(identifier());
  792. Function<ByteBuffer(InodeIdentifier)> callback_tmp;
  793. Function<ByteBuffer(InodeIdentifier)>* read_callback { nullptr };
  794. if (directory_entry) {
  795. read_callback = &directory_entry->read_callback;
  796. } else {
  797. if (to_proc_parent_directory(identifier()) == PDI_PID_fd) {
  798. callback_tmp = procfs$pid_fd_entry;
  799. read_callback = &callback_tmp;
  800. }
  801. }
  802. ASSERT(read_callback);
  803. ByteBuffer generated_data;
  804. if (!descriptor) {
  805. generated_data = (*read_callback)(identifier());
  806. } else {
  807. if (!descriptor->generator_cache())
  808. descriptor->generator_cache() = (*read_callback)(identifier());
  809. generated_data = descriptor->generator_cache();
  810. }
  811. auto& data = generated_data;
  812. ssize_t nread = min(static_cast<off_t>(data.size() - offset), static_cast<off_t>(count));
  813. memcpy(buffer, data.pointer() + offset, nread);
  814. if (nread == 0 && descriptor && descriptor->generator_cache())
  815. descriptor->generator_cache().clear();
  816. return nread;
  817. }
  818. InodeIdentifier ProcFS::ProcFSDirectoryEntry::identifier(unsigned fsid) const
  819. {
  820. return to_identifier(fsid, PDI_Root, 0, (ProcFileType)proc_file_type);
  821. }
  822. bool ProcFSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntry&)> callback) const
  823. {
  824. #ifdef PROCFS_DEBUG
  825. dbgprintf("ProcFS: traverse_as_directory %u\n", index());
  826. #endif
  827. if (!::is_directory(identifier()))
  828. return false;
  829. auto pid = to_pid(identifier());
  830. auto proc_file_type = to_proc_file_type(identifier());
  831. auto parent_id = to_parent_id(identifier());
  832. callback({ ".", 1, identifier(), 2 });
  833. callback({ "..", 2, parent_id, 2 });
  834. switch (proc_file_type) {
  835. case FI_Root:
  836. for (auto& entry : fs().m_entries) {
  837. // FIXME: strlen() here is sad.
  838. if (!entry.name)
  839. continue;
  840. if (entry.proc_file_type > __FI_Root_Start && entry.proc_file_type < __FI_Root_End)
  841. callback({ entry.name, strlen(entry.name), to_identifier(fsid(), PDI_Root, 0, (ProcFileType)entry.proc_file_type), 0 });
  842. }
  843. for (auto pid_child : Process::all_pids()) {
  844. char name[16];
  845. int name_length = ksprintf(name, "%u", pid_child);
  846. callback({ name, name_length, to_identifier(fsid(), PDI_Root, pid_child, FI_PID), 0 });
  847. }
  848. break;
  849. case FI_Root_sys:
  850. for (int i = 0; i < fs().m_sys_entries.size(); ++i) {
  851. auto& entry = fs().m_sys_entries[i];
  852. callback({ entry.name, strlen(entry.name), sys_var_to_identifier(fsid(), i), 0 });
  853. }
  854. break;
  855. case FI_PID: {
  856. auto handle = ProcessInspectionHandle::from_pid(pid);
  857. if (!handle)
  858. return false;
  859. auto& process = handle->process();
  860. for (auto& entry : fs().m_entries) {
  861. if (entry.proc_file_type > __FI_PID_Start && entry.proc_file_type < __FI_PID_End) {
  862. if (entry.proc_file_type == FI_PID_exe && !process.executable_inode())
  863. continue;
  864. // FIXME: strlen() here is sad.
  865. callback({ entry.name, strlen(entry.name), to_identifier(fsid(), PDI_PID, pid, (ProcFileType)entry.proc_file_type), 0 });
  866. }
  867. }
  868. }
  869. break;
  870. case FI_PID_fd: {
  871. auto handle = ProcessInspectionHandle::from_pid(pid);
  872. if (!handle)
  873. return false;
  874. auto& process = handle->process();
  875. for (int i = 0; i < process.max_open_file_descriptors(); ++i) {
  876. auto* descriptor = process.file_descriptor(i);
  877. if (!descriptor)
  878. continue;
  879. char name[16];
  880. size_t name_length = ksprintf(name, "%u", i);
  881. callback({ name, name_length, to_identifier_with_fd(fsid(), pid, i), 0 });
  882. }
  883. }
  884. break;
  885. default:
  886. return true;
  887. }
  888. return true;
  889. }
  890. InodeIdentifier ProcFSInode::lookup(const String& name)
  891. {
  892. ASSERT(is_directory());
  893. if (name == ".")
  894. return identifier();
  895. if (name == "..")
  896. return to_parent_id(identifier());
  897. auto proc_file_type = to_proc_file_type(identifier());
  898. if (proc_file_type == FI_Root) {
  899. for (auto& entry : fs().m_entries) {
  900. if (entry.name == nullptr)
  901. continue;
  902. if (entry.proc_file_type > __FI_Root_Start && entry.proc_file_type < __FI_Root_End) {
  903. if (!strcmp(entry.name, name.characters())) {
  904. return to_identifier(fsid(), PDI_Root, 0, (ProcFileType)entry.proc_file_type);
  905. }
  906. }
  907. }
  908. bool ok;
  909. unsigned name_as_number = name.to_uint(ok);
  910. if (ok) {
  911. bool process_exists = false;
  912. {
  913. InterruptDisabler disabler;
  914. process_exists = Process::from_pid(name_as_number);
  915. }
  916. if (process_exists)
  917. return to_identifier(fsid(), PDI_Root, name_as_number, FI_PID);
  918. }
  919. return { };
  920. }
  921. if (proc_file_type == FI_Root_sys) {
  922. for (int i = 0; i < fs().m_sys_entries.size(); ++i) {
  923. auto& entry = fs().m_sys_entries[i];
  924. if (!strcmp(entry.name, name.characters()))
  925. return sys_var_to_identifier(fsid(), i);
  926. }
  927. return { };
  928. }
  929. if (proc_file_type == FI_PID) {
  930. auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier()));
  931. if (!handle)
  932. return { };
  933. auto& process = handle->process();
  934. for (auto& entry : fs().m_entries) {
  935. if (entry.proc_file_type > __FI_PID_Start && entry.proc_file_type < __FI_PID_End) {
  936. if (entry.proc_file_type == FI_PID_exe && !process.executable_inode())
  937. continue;
  938. if (entry.name == nullptr)
  939. continue;
  940. if (!strcmp(entry.name, name.characters())) {
  941. return to_identifier(fsid(), PDI_PID, to_pid(identifier()), (ProcFileType)entry.proc_file_type);
  942. }
  943. }
  944. }
  945. return { };
  946. }
  947. if (proc_file_type == FI_PID_fd) {
  948. bool ok;
  949. unsigned name_as_number = name.to_uint(ok);
  950. if (ok) {
  951. bool fd_exists = false;
  952. {
  953. InterruptDisabler disabler;
  954. if (auto* process = Process::from_pid(to_pid(identifier())))
  955. fd_exists = process->file_descriptor(name_as_number);
  956. }
  957. if (fd_exists)
  958. return to_identifier_with_fd(fsid(), to_pid(identifier()), name_as_number);
  959. }
  960. }
  961. return { };
  962. }
  963. String ProcFSInode::reverse_lookup(InodeIdentifier child_id)
  964. {
  965. ASSERT(is_directory());
  966. auto proc_file_type = to_proc_file_type(identifier());
  967. if (proc_file_type == FI_Root) {
  968. for (auto& entry : fs().m_entries) {
  969. if (child_id == to_identifier(fsid(), PDI_Root, 0, (ProcFileType)entry.proc_file_type)) {
  970. return entry.name;
  971. }
  972. }
  973. auto child_proc_file_type = to_proc_file_type(child_id);
  974. if (child_proc_file_type == FI_PID)
  975. return String::format("%u", to_pid(child_id));
  976. return { };
  977. }
  978. // FIXME: Implement
  979. ASSERT_NOT_REACHED();
  980. return { };
  981. }
  982. void ProcFSInode::flush_metadata()
  983. {
  984. }
  985. ssize_t ProcFSInode::write_bytes(off_t offset, ssize_t size, const byte* buffer, FileDescriptor*)
  986. {
  987. auto* directory_entry = fs().get_directory_entry(identifier());
  988. if (!directory_entry || !directory_entry->write_callback)
  989. return -EPERM;
  990. ASSERT(is_persistent_inode(identifier()));
  991. // FIXME: Being able to write into ProcFS at a non-zero offset seems like something we should maybe support..
  992. ASSERT(offset == 0);
  993. bool success = directory_entry->write_callback(identifier(), ByteBuffer::wrap((byte*)buffer, size));
  994. ASSERT(success);
  995. return 0;
  996. }
  997. KResult ProcFSInode::add_child(InodeIdentifier child_id, const String& name, byte file_type)
  998. {
  999. (void)child_id;
  1000. (void)name;
  1001. (void)file_type;
  1002. return KResult(-EPERM);
  1003. }
  1004. KResult ProcFSInode::remove_child(const String& name)
  1005. {
  1006. (void)name;
  1007. return KResult(-EPERM);
  1008. }
  1009. ProcFSInodeCustomData::~ProcFSInodeCustomData()
  1010. {
  1011. }
  1012. size_t ProcFSInode::directory_entry_count() const
  1013. {
  1014. ASSERT(is_directory());
  1015. size_t count = 0;
  1016. traverse_as_directory([&count] (const FS::DirectoryEntry&) {
  1017. ++count;
  1018. return true;
  1019. });
  1020. return count;
  1021. }
  1022. KResult ProcFSInode::chmod(mode_t)
  1023. {
  1024. return KResult(-EPERM);
  1025. }
  1026. ProcFS::ProcFS()
  1027. {
  1028. s_the = this;
  1029. m_root_inode = adopt(*new ProcFSInode(*this, 1));
  1030. m_entries.resize(FI_MaxStaticFileIndex);
  1031. m_entries[FI_Root_mm] = { "mm", FI_Root_mm, procfs$mm };
  1032. m_entries[FI_Root_mounts] = { "mounts", FI_Root_mounts, procfs$mounts };
  1033. m_entries[FI_Root_df] = { "df", FI_Root_df, procfs$df };
  1034. m_entries[FI_Root_kmalloc] = { "kmalloc", FI_Root_kmalloc, procfs$kmalloc };
  1035. m_entries[FI_Root_all] = { "all", FI_Root_all, procfs$all };
  1036. m_entries[FI_Root_memstat] = { "memstat", FI_Root_memstat, procfs$memstat };
  1037. m_entries[FI_Root_summary] = { "summary", FI_Root_summary, procfs$summary };
  1038. m_entries[FI_Root_cpuinfo] = { "cpuinfo", FI_Root_cpuinfo, procfs$cpuinfo};
  1039. m_entries[FI_Root_inodes] = { "inodes", FI_Root_inodes, procfs$inodes };
  1040. m_entries[FI_Root_dmesg] = { "dmesg", FI_Root_dmesg, procfs$dmesg };
  1041. m_entries[FI_Root_self] = { "self", FI_Root_self, procfs$self };
  1042. m_entries[FI_Root_pci] = { "pci", FI_Root_pci, procfs$pci };
  1043. m_entries[FI_Root_sys] = { "sys", FI_Root_sys };
  1044. m_entries[FI_PID_vm] = { "vm", FI_PID_vm, procfs$pid_vm };
  1045. m_entries[FI_PID_vmo] = { "vmo", FI_PID_vmo, procfs$pid_vmo };
  1046. m_entries[FI_PID_stack] = { "stack", FI_PID_stack, procfs$pid_stack };
  1047. m_entries[FI_PID_regs] = { "regs", FI_PID_regs, procfs$pid_regs };
  1048. m_entries[FI_PID_fds] = { "fds", FI_PID_fds, procfs$pid_fds };
  1049. m_entries[FI_PID_exe] = { "exe", FI_PID_exe, procfs$pid_exe };
  1050. m_entries[FI_PID_cwd] = { "cwd", FI_PID_cwd, procfs$pid_cwd };
  1051. m_entries[FI_PID_fd] = { "fd", FI_PID_fd };
  1052. }
  1053. ProcFS::ProcFSDirectoryEntry* ProcFS::get_directory_entry(InodeIdentifier identifier) const
  1054. {
  1055. if (to_proc_parent_directory(identifier) == PDI_Root_sys) {
  1056. auto sys_index = to_sys_index(identifier);
  1057. if (sys_index < m_sys_entries.size())
  1058. return const_cast<ProcFSDirectoryEntry*>(&m_sys_entries[sys_index]);
  1059. return nullptr;
  1060. }
  1061. auto proc_file_type = to_proc_file_type(identifier);
  1062. if (proc_file_type != FI_Invalid && proc_file_type < FI_MaxStaticFileIndex)
  1063. return const_cast<ProcFSDirectoryEntry*>(&m_entries[proc_file_type]);
  1064. return nullptr;
  1065. }
  1066. KResult ProcFSInode::chown(uid_t, gid_t)
  1067. {
  1068. return KResult(-EPERM);
  1069. }