ProcFS.cpp 36 KB

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