ProcessSpecificExposed.cpp 24 KB

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