ProcFS.cpp 37 KB

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