ProcFS.cpp 32 KB

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