ProcessSpecificExposed.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  1. /*
  2. * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/JsonArraySerializer.h>
  7. #include <AK/JsonObjectSerializer.h>
  8. #include <AK/JsonValue.h>
  9. #include <Kernel/Arch/x86/InterruptDisabler.h>
  10. #include <Kernel/FileSystem/Custody.h>
  11. #include <Kernel/KBufferBuilder.h>
  12. #include <Kernel/ProcessExposed.h>
  13. #include <Kernel/VM/AnonymousVMObject.h>
  14. #include <Kernel/VM/MemoryManager.h>
  15. namespace Kernel {
  16. class ProcFSProcessStacks;
  17. class ProcFSThreadStack final : public ProcFSProcessInformation {
  18. public:
  19. // Note: We pass const ProcFSProcessStacks& to enforce creation with this type of directory
  20. static NonnullRefPtr<ProcFSThreadStack> create(const ProcFSProcessDirectory& process_directory, const ProcFSProcessStacks&, const Thread& thread)
  21. {
  22. return adopt_ref(*new (nothrow) ProcFSThreadStack(process_directory, thread));
  23. }
  24. private:
  25. explicit ProcFSThreadStack(const ProcFSProcessDirectory& process_directory, const Thread& thread)
  26. : ProcFSProcessInformation(String::formatted("{}", thread.tid()), process_directory)
  27. , m_associated_thread(thread)
  28. {
  29. }
  30. virtual bool output(KBufferBuilder& builder) override
  31. {
  32. JsonArraySerializer array { builder };
  33. bool show_kernel_addresses = Process::current()->is_superuser();
  34. bool kernel_address_added = false;
  35. for (auto address : Processor::capture_stack_trace(*m_associated_thread, 1024)) {
  36. if (!show_kernel_addresses && !is_user_address(VirtualAddress { address })) {
  37. if (kernel_address_added)
  38. continue;
  39. address = 0xdeadc0de;
  40. kernel_address_added = true;
  41. }
  42. array.add(address);
  43. }
  44. array.finish();
  45. return true;
  46. }
  47. NonnullRefPtr<Thread> m_associated_thread;
  48. };
  49. class ProcFSProcessStacks final : public ProcFSExposedDirectory {
  50. // Note: This directory is special, because everything that is created here is dynamic!
  51. // This means we don't register anything in the m_components Vector, and every inode
  52. // is created in runtime when called to get it
  53. // Every ProcFSThreadStack (that represents a thread stack) is created only as a temporary object
  54. // therefore, we don't use m_components so when we are done with the ProcFSThreadStack object,
  55. // It should be deleted (as soon as possible)
  56. public:
  57. virtual KResult traverse_as_directory(unsigned, Function<bool(FileSystem::DirectoryEntryView const&)>) const override;
  58. virtual RefPtr<ProcFSExposedComponent> lookup(StringView name) override;
  59. static NonnullRefPtr<ProcFSProcessStacks> create(const ProcFSProcessDirectory& parent_directory)
  60. {
  61. auto directory = adopt_ref(*new (nothrow) ProcFSProcessStacks(parent_directory));
  62. return directory;
  63. }
  64. virtual void prepare_for_deletion() override
  65. {
  66. ProcFSExposedDirectory::prepare_for_deletion();
  67. m_process_directory.clear();
  68. }
  69. private:
  70. ProcFSProcessStacks(const ProcFSProcessDirectory& parent_directory)
  71. : ProcFSExposedDirectory("stacks"sv, parent_directory)
  72. , m_process_directory(parent_directory)
  73. {
  74. }
  75. WeakPtr<ProcFSProcessDirectory> m_process_directory;
  76. mutable Mutex m_lock;
  77. };
  78. KResult ProcFSProcessStacks::traverse_as_directory(unsigned fsid, Function<bool(FileSystem::DirectoryEntryView const&)> callback) const
  79. {
  80. MutexLocker locker(m_lock);
  81. auto parent_directory = m_process_directory.strong_ref();
  82. if (parent_directory.is_null())
  83. return KResult(EINVAL);
  84. callback({ ".", { fsid, component_index() }, 0 });
  85. callback({ "..", { fsid, parent_directory->component_index() }, 0 });
  86. auto process = parent_directory->associated_process();
  87. if (process.is_null())
  88. return KResult(ESRCH);
  89. process->for_each_thread([&](const Thread& thread) {
  90. int tid = thread.tid().value();
  91. InodeIdentifier identifier = { fsid, thread.global_procfs_inode_index() };
  92. callback({ String::number(tid), identifier, 0 });
  93. });
  94. return KSuccess;
  95. }
  96. RefPtr<ProcFSExposedComponent> ProcFSProcessStacks::lookup(StringView name)
  97. {
  98. MutexLocker locker(m_lock);
  99. auto parent_directory = m_process_directory.strong_ref();
  100. if (parent_directory.is_null())
  101. return nullptr;
  102. auto process = parent_directory->associated_process();
  103. if (process.is_null())
  104. return nullptr;
  105. RefPtr<ProcFSThreadStack> procfd_stack;
  106. // FIXME: Try to exit the loop earlier
  107. process->for_each_thread([&](const Thread& thread) {
  108. int tid = thread.tid().value();
  109. if (name == String::number(tid)) {
  110. procfd_stack = ProcFSThreadStack::create(*parent_directory, *this, thread);
  111. }
  112. });
  113. return procfd_stack;
  114. }
  115. class ProcFSProcessFileDescriptions;
  116. class ProcFSProcessFileDescription final : public ProcFSExposedLink {
  117. public:
  118. // Note: we pass const ProcFSProcessFileDescriptions& just to enforce creation of this in the correct directory.
  119. static NonnullRefPtr<ProcFSProcessFileDescription> create(unsigned fd_number, const FileDescription& fd, InodeIndex preallocated_index, const ProcFSProcessFileDescriptions&)
  120. {
  121. return adopt_ref(*new (nothrow) ProcFSProcessFileDescription(fd_number, fd, preallocated_index));
  122. }
  123. private:
  124. explicit ProcFSProcessFileDescription(unsigned fd_number, const FileDescription& fd, InodeIndex preallocated_index)
  125. : ProcFSExposedLink(String::formatted("{}", fd_number), preallocated_index)
  126. , m_associated_file_description(fd)
  127. {
  128. }
  129. virtual bool acquire_link(KBufferBuilder& builder) override
  130. {
  131. builder.append_bytes(m_associated_file_description->absolute_path().bytes());
  132. return true;
  133. }
  134. NonnullRefPtr<FileDescription> m_associated_file_description;
  135. };
  136. class ProcFSProcessFileDescriptions final : public ProcFSExposedDirectory {
  137. // Note: This directory is special, because everything that is created here is dynamic!
  138. // This means we don't register anything in the m_components Vector, and every inode
  139. // is created in runtime when called to get it
  140. // Every ProcFSProcessFileDescription (that represents a file descriptor) is created only as a temporary object
  141. // therefore, we don't use m_components so when we are done with the ProcFSProcessFileDescription object,
  142. // It should be deleted (as soon as possible)
  143. public:
  144. virtual KResult traverse_as_directory(unsigned, Function<bool(FileSystem::DirectoryEntryView const&)>) const override;
  145. virtual RefPtr<ProcFSExposedComponent> lookup(StringView name) override;
  146. static NonnullRefPtr<ProcFSProcessFileDescriptions> create(const ProcFSProcessDirectory& parent_directory)
  147. {
  148. return adopt_ref(*new (nothrow) ProcFSProcessFileDescriptions(parent_directory));
  149. }
  150. virtual void prepare_for_deletion() override
  151. {
  152. ProcFSExposedDirectory::prepare_for_deletion();
  153. m_process_directory.clear();
  154. }
  155. private:
  156. explicit ProcFSProcessFileDescriptions(const ProcFSProcessDirectory& parent_directory)
  157. : ProcFSExposedDirectory("fd"sv, parent_directory)
  158. , m_process_directory(parent_directory)
  159. {
  160. }
  161. WeakPtr<ProcFSProcessDirectory> m_process_directory;
  162. mutable Mutex m_lock;
  163. };
  164. KResult ProcFSProcessFileDescriptions::traverse_as_directory(unsigned fsid, Function<bool(FileSystem::DirectoryEntryView const&)> callback) const
  165. {
  166. MutexLocker locker(m_lock);
  167. auto parent_directory = m_process_directory.strong_ref();
  168. if (parent_directory.is_null())
  169. return KResult(EINVAL);
  170. callback({ ".", { fsid, component_index() }, 0 });
  171. callback({ "..", { fsid, parent_directory->component_index() }, 0 });
  172. auto process = parent_directory->associated_process();
  173. if (process.is_null())
  174. return KResult(ESRCH);
  175. size_t count = 0;
  176. process->fds().enumerate([&](auto& file_description_metadata) {
  177. if (!file_description_metadata.is_valid()) {
  178. count++;
  179. return;
  180. }
  181. InodeIdentifier identifier = { fsid, file_description_metadata.global_procfs_inode_index() };
  182. callback({ String::number(count), identifier, 0 });
  183. count++;
  184. });
  185. return KSuccess;
  186. }
  187. RefPtr<ProcFSExposedComponent> ProcFSProcessFileDescriptions::lookup(StringView name)
  188. {
  189. MutexLocker locker(m_lock);
  190. auto parent_directory = m_process_directory.strong_ref();
  191. if (parent_directory.is_null())
  192. return nullptr;
  193. auto process = parent_directory->associated_process();
  194. if (process.is_null())
  195. return nullptr;
  196. RefPtr<ProcFSProcessFileDescription> procfd_fd;
  197. // FIXME: Try to exit the loop earlier
  198. size_t count = 0;
  199. process->fds().enumerate([&](auto& file_description_metadata) {
  200. if (!file_description_metadata.is_valid()) {
  201. count++;
  202. return;
  203. }
  204. if (name == String::number(count)) {
  205. procfd_fd = ProcFSProcessFileDescription::create(count, *file_description_metadata.description(), file_description_metadata.global_procfs_inode_index(), *this);
  206. }
  207. count++;
  208. });
  209. return procfd_fd;
  210. }
  211. class ProcFSProcessPledge final : public ProcFSProcessInformation {
  212. public:
  213. static NonnullRefPtr<ProcFSProcessPledge> create(const ProcFSProcessDirectory& parent_directory)
  214. {
  215. return adopt_ref(*new (nothrow) ProcFSProcessPledge(parent_directory));
  216. }
  217. private:
  218. explicit ProcFSProcessPledge(const ProcFSProcessDirectory& parent_directory)
  219. : ProcFSProcessInformation("pledge"sv, parent_directory)
  220. {
  221. }
  222. virtual bool output(KBufferBuilder& builder) override
  223. {
  224. auto parent_directory = m_parent_directory.strong_ref();
  225. if (parent_directory.is_null())
  226. return false;
  227. auto process = parent_directory->associated_process();
  228. if (process.is_null())
  229. return false;
  230. JsonObjectSerializer obj { builder };
  231. #define __ENUMERATE_PLEDGE_PROMISE(x) \
  232. if (process->has_promised(Pledge::x)) { \
  233. if (!builder.is_empty()) \
  234. builder.append(' '); \
  235. builder.append(#x); \
  236. }
  237. if (process->has_promises()) {
  238. StringBuilder builder;
  239. ENUMERATE_PLEDGE_PROMISES
  240. obj.add("promises", builder.build());
  241. }
  242. #undef __ENUMERATE_PLEDGE_PROMISE
  243. obj.finish();
  244. return true;
  245. }
  246. };
  247. class ProcFSProcessUnveil final : public ProcFSProcessInformation {
  248. public:
  249. static NonnullRefPtr<ProcFSProcessUnveil> create(const ProcFSProcessDirectory& parent_directory)
  250. {
  251. return adopt_ref(*new (nothrow) ProcFSProcessUnveil(parent_directory));
  252. }
  253. private:
  254. explicit ProcFSProcessUnveil(const ProcFSProcessDirectory& parent_directory)
  255. : ProcFSProcessInformation("unveil"sv, parent_directory)
  256. {
  257. }
  258. virtual bool output(KBufferBuilder& builder) override
  259. {
  260. auto parent_directory = m_parent_directory.strong_ref();
  261. if (parent_directory.is_null())
  262. return false;
  263. auto process = parent_directory->associated_process();
  264. if (process.is_null())
  265. return false;
  266. JsonArraySerializer array { builder };
  267. for (auto& unveiled_path : process->unveiled_paths()) {
  268. if (!unveiled_path.was_explicitly_unveiled())
  269. continue;
  270. auto obj = array.add_object();
  271. obj.add("path", unveiled_path.path());
  272. StringBuilder permissions_builder;
  273. if (unveiled_path.permissions() & UnveilAccess::Read)
  274. permissions_builder.append('r');
  275. if (unveiled_path.permissions() & UnveilAccess::Write)
  276. permissions_builder.append('w');
  277. if (unveiled_path.permissions() & UnveilAccess::Execute)
  278. permissions_builder.append('x');
  279. if (unveiled_path.permissions() & UnveilAccess::CreateOrRemove)
  280. permissions_builder.append('c');
  281. if (unveiled_path.permissions() & UnveilAccess::Browse)
  282. permissions_builder.append('b');
  283. obj.add("permissions", permissions_builder.to_string());
  284. }
  285. array.finish();
  286. return true;
  287. }
  288. };
  289. class ProcFSProcessPerformanceEvents final : public ProcFSProcessInformation {
  290. public:
  291. static NonnullRefPtr<ProcFSProcessPerformanceEvents> create(const ProcFSProcessDirectory& parent_directory)
  292. {
  293. return adopt_ref(*new (nothrow) ProcFSProcessPerformanceEvents(parent_directory));
  294. }
  295. private:
  296. explicit ProcFSProcessPerformanceEvents(const ProcFSProcessDirectory& parent_directory)
  297. : ProcFSProcessInformation("perf_events"sv, parent_directory)
  298. {
  299. }
  300. virtual bool output(KBufferBuilder& builder) override
  301. {
  302. InterruptDisabler disabler;
  303. auto parent_directory = m_parent_directory.strong_ref();
  304. if (parent_directory.is_null())
  305. return false;
  306. auto process = parent_directory->associated_process();
  307. if (process.is_null())
  308. return false;
  309. if (!process->perf_events()) {
  310. dbgln("ProcFS: No perf events for {}", process->pid());
  311. return false;
  312. }
  313. return process->perf_events()->to_json(builder);
  314. }
  315. };
  316. class ProcFSProcessOverallFileDescriptions final : public ProcFSProcessInformation {
  317. public:
  318. static NonnullRefPtr<ProcFSProcessOverallFileDescriptions> create(const ProcFSProcessDirectory& parent_directory)
  319. {
  320. return adopt_ref(*new (nothrow) ProcFSProcessOverallFileDescriptions(parent_directory));
  321. }
  322. private:
  323. explicit ProcFSProcessOverallFileDescriptions(const ProcFSProcessDirectory& parent_directory)
  324. : ProcFSProcessInformation("fds"sv, parent_directory)
  325. {
  326. }
  327. virtual bool output(KBufferBuilder& builder) override
  328. {
  329. auto parent_directory = m_parent_directory.strong_ref();
  330. if (parent_directory.is_null())
  331. return false;
  332. JsonArraySerializer array { builder };
  333. auto process = parent_directory->associated_process();
  334. if (process.is_null())
  335. return false;
  336. if (process->fds().open_count() == 0) {
  337. array.finish();
  338. return true;
  339. }
  340. size_t count = 0;
  341. process->fds().enumerate([&](auto& file_description_metadata) {
  342. if (!file_description_metadata.is_valid()) {
  343. count++;
  344. return;
  345. }
  346. bool cloexec = file_description_metadata.flags() & FD_CLOEXEC;
  347. RefPtr<FileDescription> description = file_description_metadata.description();
  348. auto description_object = array.add_object();
  349. description_object.add("fd", count);
  350. description_object.add("absolute_path", description->absolute_path());
  351. description_object.add("seekable", description->file().is_seekable());
  352. description_object.add("class", description->file().class_name());
  353. description_object.add("offset", description->offset());
  354. description_object.add("cloexec", cloexec);
  355. description_object.add("blocking", description->is_blocking());
  356. description_object.add("can_read", description->can_read());
  357. description_object.add("can_write", description->can_write());
  358. count++;
  359. });
  360. array.finish();
  361. return true;
  362. }
  363. };
  364. class ProcFSProcessRoot final : public ProcFSExposedLink {
  365. public:
  366. static NonnullRefPtr<ProcFSProcessRoot> create(const ProcFSProcessDirectory& parent_directory)
  367. {
  368. return adopt_ref(*new (nothrow) ProcFSProcessRoot(parent_directory));
  369. }
  370. private:
  371. explicit ProcFSProcessRoot(const ProcFSProcessDirectory& parent_directory)
  372. : ProcFSExposedLink("root"sv)
  373. , m_parent_process_directory(parent_directory)
  374. {
  375. }
  376. virtual bool acquire_link(KBufferBuilder& builder) override
  377. {
  378. auto parent_directory = m_parent_process_directory.strong_ref();
  379. if (parent_directory.is_null())
  380. return false;
  381. auto process = parent_directory->associated_process();
  382. if (process.is_null())
  383. return false;
  384. builder.append_bytes(process->root_directory_relative_to_global_root().absolute_path().to_byte_buffer());
  385. return true;
  386. }
  387. WeakPtr<ProcFSProcessDirectory> m_parent_process_directory;
  388. };
  389. class ProcFSProcessVirtualMemory final : public ProcFSProcessInformation {
  390. public:
  391. static NonnullRefPtr<ProcFSProcessRoot> create(const ProcFSProcessDirectory& parent_directory)
  392. {
  393. return adopt_ref(*new (nothrow) ProcFSProcessVirtualMemory(parent_directory));
  394. }
  395. private:
  396. explicit ProcFSProcessVirtualMemory(const ProcFSProcessDirectory& parent_directory)
  397. : ProcFSProcessInformation("vm"sv, parent_directory)
  398. {
  399. }
  400. virtual bool output(KBufferBuilder& builder) override
  401. {
  402. auto parent_directory = m_parent_directory.strong_ref();
  403. if (parent_directory.is_null())
  404. return false;
  405. auto process = parent_directory->associated_process();
  406. if (process.is_null())
  407. return false;
  408. JsonArraySerializer array { builder };
  409. {
  410. ScopedSpinLock lock(process->space().get_lock());
  411. for (auto& region : process->space().regions()) {
  412. if (!region->is_user() && !Process::current()->is_superuser())
  413. continue;
  414. auto region_object = array.add_object();
  415. region_object.add("readable", region->is_readable());
  416. region_object.add("writable", region->is_writable());
  417. region_object.add("executable", region->is_executable());
  418. region_object.add("stack", region->is_stack());
  419. region_object.add("shared", region->is_shared());
  420. region_object.add("syscall", region->is_syscall_region());
  421. region_object.add("purgeable", region->vmobject().is_anonymous());
  422. if (region->vmobject().is_anonymous()) {
  423. region_object.add("volatile", static_cast<AnonymousVMObject const&>(region->vmobject()).is_volatile());
  424. }
  425. region_object.add("cacheable", region->is_cacheable());
  426. region_object.add("address", region->vaddr().get());
  427. region_object.add("size", region->size());
  428. region_object.add("amount_resident", region->amount_resident());
  429. region_object.add("amount_dirty", region->amount_dirty());
  430. region_object.add("cow_pages", region->cow_pages());
  431. region_object.add("name", region->name());
  432. region_object.add("vmobject", region->vmobject().class_name());
  433. StringBuilder pagemap_builder;
  434. for (size_t i = 0; i < region->page_count(); ++i) {
  435. auto* page = region->physical_page(i);
  436. if (!page)
  437. pagemap_builder.append('N');
  438. else if (page->is_shared_zero_page() || page->is_lazy_committed_page())
  439. pagemap_builder.append('Z');
  440. else
  441. pagemap_builder.append('P');
  442. }
  443. region_object.add("pagemap", pagemap_builder.to_string());
  444. }
  445. }
  446. array.finish();
  447. return true;
  448. }
  449. };
  450. class ProcFSProcessCurrentWorkDirectory final : public ProcFSExposedLink {
  451. public:
  452. static NonnullRefPtr<ProcFSProcessCurrentWorkDirectory> create(const ProcFSProcessDirectory& parent_directory)
  453. {
  454. return adopt_ref(*new (nothrow) ProcFSProcessCurrentWorkDirectory(parent_directory));
  455. }
  456. private:
  457. explicit ProcFSProcessCurrentWorkDirectory(const ProcFSProcessDirectory& parent_directory)
  458. : ProcFSExposedLink("cwd"sv)
  459. , m_parent_process_directory(parent_directory)
  460. {
  461. }
  462. virtual bool acquire_link(KBufferBuilder& builder) override
  463. {
  464. auto parent_directory = m_parent_process_directory.strong_ref();
  465. if (parent_directory.is_null())
  466. return false;
  467. auto process = parent_directory->associated_process();
  468. if (process.is_null())
  469. return false;
  470. builder.append_bytes(process->current_directory().absolute_path().bytes());
  471. return true;
  472. }
  473. WeakPtr<ProcFSProcessDirectory> m_parent_process_directory;
  474. };
  475. class ProcFSProcessBinary final : public ProcFSExposedLink {
  476. public:
  477. static NonnullRefPtr<ProcFSProcessBinary> create(const ProcFSProcessDirectory& parent_directory)
  478. {
  479. return adopt_ref(*new (nothrow) ProcFSProcessBinary(parent_directory));
  480. }
  481. virtual mode_t required_mode() const override
  482. {
  483. auto parent_directory = m_parent_process_directory.strong_ref();
  484. if (parent_directory.is_null())
  485. return false;
  486. auto process = parent_directory->associated_process();
  487. if (process.is_null())
  488. return false;
  489. if (!process->executable())
  490. return 0;
  491. return ProcFSExposedComponent::required_mode();
  492. }
  493. private:
  494. explicit ProcFSProcessBinary(const ProcFSProcessDirectory& parent_directory)
  495. : ProcFSExposedLink("exe"sv)
  496. , m_parent_process_directory(parent_directory)
  497. {
  498. }
  499. virtual bool acquire_link(KBufferBuilder& builder) override
  500. {
  501. auto parent_directory = m_parent_process_directory.strong_ref();
  502. if (parent_directory.is_null())
  503. return false;
  504. auto process = parent_directory->associated_process();
  505. if (process.is_null())
  506. return false;
  507. auto* custody = process->executable();
  508. if (!custody)
  509. return false;
  510. builder.append(custody->absolute_path().bytes());
  511. return true;
  512. }
  513. WeakPtr<ProcFSProcessDirectory> m_parent_process_directory;
  514. };
  515. void ProcFSProcessDirectory::on_attach()
  516. {
  517. VERIFY(m_components.size() == 0);
  518. m_components.append(ProcFSProcessPledge::create(*this));
  519. m_components.append(ProcFSProcessUnveil::create(*this));
  520. m_components.append(ProcFSProcessPerformanceEvents::create(*this));
  521. m_components.append(ProcFSProcessFileDescriptions::create(*this));
  522. m_components.append(ProcFSProcessOverallFileDescriptions::create(*this));
  523. m_components.append(ProcFSProcessRoot::create(*this));
  524. m_components.append(ProcFSProcessVirtualMemory::create(*this));
  525. m_components.append(ProcFSProcessCurrentWorkDirectory::create(*this));
  526. m_components.append(ProcFSProcessBinary::create(*this));
  527. m_components.append(ProcFSProcessStacks::create(*this));
  528. }
  529. RefPtr<ProcFSExposedComponent> ProcFSProcessDirectory::lookup(StringView name)
  530. {
  531. // Note: we need to allocate all sub components when doing a lookup, because
  532. // for some reason, the caller may not call ProcFSInode::attach method before calling this.
  533. if (m_components.size() == 0)
  534. on_attach();
  535. return ProcFSExposedDirectory::lookup(name);
  536. }
  537. KResult ProcFSProcessDirectory::refresh_data(FileDescription&) const
  538. {
  539. if (m_components.size() != 0)
  540. return KSuccess;
  541. const_cast<ProcFSProcessDirectory&>(*this).on_attach();
  542. return KSuccess;
  543. }
  544. NonnullRefPtr<ProcFSProcessDirectory> ProcFSProcessDirectory::create(const Process& process)
  545. {
  546. return adopt_ref_if_nonnull(new (nothrow) ProcFSProcessDirectory(process)).release_nonnull();
  547. }
  548. void ProcFSProcessDirectory::prepare_for_deletion()
  549. {
  550. ProcFSExposedDirectory::prepare_for_deletion();
  551. m_associated_process.clear();
  552. }
  553. ProcFSProcessDirectory::ProcFSProcessDirectory(const Process& process)
  554. : ProcFSExposedDirectory(String::formatted("{:d}", process.pid().value()), ProcFSComponentRegistry::the().root_directory())
  555. , m_associated_process(process)
  556. {
  557. }
  558. }