ProcFS.cpp 36 KB

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