ProcessExposed.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. /*
  2. * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <Kernel/FileSystem/ProcFS/DirectoryInode.h>
  7. #include <Kernel/FileSystem/ProcFS/LinkInode.h>
  8. #include <Kernel/KBufferBuilder.h>
  9. #include <Kernel/PerformanceEventBuffer.h>
  10. #include <Kernel/Process.h>
  11. #include <Kernel/ProcessExposed.h>
  12. namespace Kernel {
  13. static Spinlock<LockRank::None> s_index_lock {};
  14. static InodeIndex s_next_inode_index = 0;
  15. namespace SegmentedProcFSIndex {
  16. static InodeIndex __build_raw_segmented_index(u32 primary, u16 sub_directory, u32 property)
  17. {
  18. VERIFY(primary < 0x10000000);
  19. VERIFY(property < 0x100000);
  20. // Note: The sub-directory part is already limited to 0xFFFF, so no need to VERIFY it.
  21. return static_cast<u64>((static_cast<u64>(primary) << 36) | (static_cast<u64>(sub_directory) << 20) | property);
  22. }
  23. static InodeIndex build_segmented_index_with_known_pid(ProcessID pid, u16 sub_directory, u32 property)
  24. {
  25. return __build_raw_segmented_index(pid.value() + 1, sub_directory, property);
  26. }
  27. static InodeIndex build_segmented_index_with_unknown_property(ProcessID pid, ProcessSubDirectory sub_directory, unsigned property)
  28. {
  29. return build_segmented_index_with_known_pid(pid, to_underlying(sub_directory), static_cast<u32>(property));
  30. }
  31. InodeIndex build_segmented_index_for_pid_directory(ProcessID pid)
  32. {
  33. return build_segmented_index_with_unknown_property(pid, ProcessSubDirectory::Reserved, to_underlying(MainProcessProperty::Reserved));
  34. }
  35. InodeIndex build_segmented_index_for_sub_directory(ProcessID pid, ProcessSubDirectory sub_directory)
  36. {
  37. return build_segmented_index_with_unknown_property(pid, sub_directory, to_underlying(MainProcessProperty::Reserved));
  38. }
  39. InodeIndex build_segmented_index_for_main_property(ProcessID pid, ProcessSubDirectory sub_directory, MainProcessProperty property)
  40. {
  41. return build_segmented_index_with_known_pid(pid, to_underlying(sub_directory), to_underlying(property));
  42. }
  43. InodeIndex build_segmented_index_for_main_property_in_pid_directory(ProcessID pid, MainProcessProperty property)
  44. {
  45. return build_segmented_index_with_known_pid(pid, to_underlying(ProcessSubDirectory::Reserved), to_underlying(property));
  46. }
  47. InodeIndex build_segmented_index_for_thread_stack(ProcessID pid, ThreadID thread_id)
  48. {
  49. return build_segmented_index_with_unknown_property(pid, ProcessSubDirectory::Stacks, thread_id.value());
  50. }
  51. InodeIndex build_segmented_index_for_file_description(ProcessID pid, unsigned fd)
  52. {
  53. return build_segmented_index_with_unknown_property(pid, ProcessSubDirectory::OpenFileDescriptions, fd);
  54. }
  55. InodeIndex build_segmented_index_for_children(ProcessID pid, ProcessID child_pid)
  56. {
  57. return build_segmented_index_with_unknown_property(pid, ProcessSubDirectory::Children, child_pid.value());
  58. }
  59. }
  60. static size_t s_allocate_global_inode_index()
  61. {
  62. SpinlockLocker lock(s_index_lock);
  63. s_next_inode_index = s_next_inode_index.value() + 1;
  64. // Note: Global ProcFS indices must be above 0 and up to maximum of what 36 bit (2 ^ 36 - 1) can represent.
  65. VERIFY(s_next_inode_index > 0);
  66. VERIFY(s_next_inode_index < 0x100000000);
  67. return s_next_inode_index.value();
  68. }
  69. ProcFSExposedComponent::ProcFSExposedComponent() = default;
  70. ProcFSExposedComponent::ProcFSExposedComponent(StringView name)
  71. : m_component_index(s_allocate_global_inode_index())
  72. {
  73. auto name_or_error = KString::try_create(name);
  74. if (name_or_error.is_error())
  75. TODO();
  76. m_name = name_or_error.release_value();
  77. }
  78. ProcFSExposedDirectory::ProcFSExposedDirectory(StringView name)
  79. : ProcFSExposedComponent(name)
  80. {
  81. }
  82. ProcFSExposedDirectory::ProcFSExposedDirectory(StringView name, ProcFSExposedDirectory const& parent_directory)
  83. : ProcFSExposedComponent(name)
  84. , m_parent_directory(parent_directory)
  85. {
  86. }
  87. ProcFSExposedLink::ProcFSExposedLink(StringView name)
  88. : ProcFSExposedComponent(name)
  89. {
  90. }
  91. ErrorOr<size_t> ProcFSExposedLink::read_bytes(off_t offset, size_t count, UserOrKernelBuffer& buffer, OpenFileDescription*) const
  92. {
  93. VERIFY(offset == 0);
  94. MutexLocker locker(m_lock);
  95. auto builder = TRY(KBufferBuilder::try_create());
  96. if (!const_cast<ProcFSExposedLink&>(*this).acquire_link(builder))
  97. return Error::from_errno(EFAULT);
  98. auto blob = builder.build();
  99. if (!blob)
  100. return Error::from_errno(EFAULT);
  101. ssize_t nread = min(static_cast<off_t>(blob->size() - offset), static_cast<off_t>(count));
  102. TRY(buffer.write(blob->data() + offset, nread));
  103. return nread;
  104. }
  105. ErrorOr<NonnullLockRefPtr<Inode>> ProcFSExposedLink::to_inode(ProcFS const& procfs_instance) const
  106. {
  107. return TRY(ProcFSLinkInode::try_create(procfs_instance, *this));
  108. }
  109. ErrorOr<NonnullLockRefPtr<Inode>> ProcFSExposedDirectory::to_inode(ProcFS const& procfs_instance) const
  110. {
  111. return TRY(ProcFSDirectoryInode::try_create(procfs_instance, *this));
  112. }
  113. void ProcFSExposedDirectory::add_component(ProcFSExposedComponent const&)
  114. {
  115. TODO();
  116. }
  117. ErrorOr<NonnullLockRefPtr<ProcFSExposedComponent>> ProcFSExposedDirectory::lookup(StringView name)
  118. {
  119. for (auto& component : m_components) {
  120. if (component.name() == name) {
  121. return component;
  122. }
  123. }
  124. return ENOENT;
  125. }
  126. ErrorOr<void> ProcFSExposedDirectory::traverse_as_directory(FileSystemID fsid, Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
  127. {
  128. MutexLocker locker(ProcFSComponentRegistry::the().get_lock());
  129. auto parent_directory = m_parent_directory.strong_ref();
  130. if (parent_directory.is_null())
  131. return Error::from_errno(EINVAL);
  132. TRY(callback({ "."sv, { fsid, component_index() }, DT_DIR }));
  133. TRY(callback({ ".."sv, { fsid, parent_directory->component_index() }, DT_DIR }));
  134. for (auto const& component : m_components) {
  135. InodeIdentifier identifier = { fsid, component.component_index() };
  136. TRY(callback({ component.name(), identifier, 0 }));
  137. }
  138. return {};
  139. }
  140. class ProcFSSelfProcessDirectory final : public ProcFSExposedLink {
  141. public:
  142. static NonnullLockRefPtr<ProcFSSelfProcessDirectory> must_create();
  143. private:
  144. ProcFSSelfProcessDirectory();
  145. virtual bool acquire_link(KBufferBuilder& builder) override
  146. {
  147. return !builder.appendff("{}", Process::current().pid().value()).is_error();
  148. }
  149. };
  150. UNMAP_AFTER_INIT NonnullLockRefPtr<ProcFSSelfProcessDirectory> ProcFSSelfProcessDirectory::must_create()
  151. {
  152. return adopt_lock_ref_if_nonnull(new (nothrow) ProcFSSelfProcessDirectory()).release_nonnull();
  153. }
  154. UNMAP_AFTER_INIT ProcFSSelfProcessDirectory::ProcFSSelfProcessDirectory()
  155. : ProcFSExposedLink("self"sv)
  156. {
  157. }
  158. UNMAP_AFTER_INIT NonnullLockRefPtr<ProcFSRootDirectory> ProcFSRootDirectory::must_create()
  159. {
  160. auto directory = adopt_lock_ref(*new (nothrow) ProcFSRootDirectory);
  161. directory->m_components.append(ProcFSSelfProcessDirectory::must_create());
  162. return directory;
  163. }
  164. ErrorOr<void> ProcFSRootDirectory::traverse_as_directory(FileSystemID fsid, Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
  165. {
  166. MutexLocker locker(ProcFSComponentRegistry::the().get_lock());
  167. TRY(callback({ "."sv, { fsid, component_index() }, 0 }));
  168. TRY(callback({ ".."sv, { fsid, 0 }, 0 }));
  169. for (auto const& component : m_components) {
  170. InodeIdentifier identifier = { fsid, component.component_index() };
  171. TRY(callback({ component.name(), identifier, 0 }));
  172. }
  173. return Process::for_each_in_same_jail([&](Process& process) -> ErrorOr<void> {
  174. VERIFY(!(process.pid() < 0));
  175. u64 process_id = (u64)process.pid().value();
  176. InodeIdentifier identifier = { fsid, static_cast<InodeIndex>(process_id << 36) };
  177. auto process_id_string = TRY(KString::formatted("{:d}", process_id));
  178. TRY(callback({ process_id_string->view(), identifier, 0 }));
  179. return {};
  180. });
  181. }
  182. ErrorOr<NonnullLockRefPtr<ProcFSExposedComponent>> ProcFSRootDirectory::lookup(StringView name)
  183. {
  184. auto maybe_candidate = ProcFSExposedDirectory::lookup(name);
  185. if (maybe_candidate.is_error()) {
  186. if (maybe_candidate.error().code() != ENOENT) {
  187. return maybe_candidate.release_error();
  188. }
  189. } else {
  190. return maybe_candidate.release_value();
  191. }
  192. auto pid = name.to_uint<unsigned>();
  193. if (!pid.has_value())
  194. return ESRCH;
  195. auto actual_pid = pid.value();
  196. if (auto maybe_process = Process::from_pid_in_same_jail(actual_pid))
  197. return maybe_process->procfs_traits();
  198. return ENOENT;
  199. }
  200. UNMAP_AFTER_INIT ProcFSRootDirectory::~ProcFSRootDirectory() = default;
  201. UNMAP_AFTER_INIT ProcFSRootDirectory::ProcFSRootDirectory()
  202. : ProcFSExposedDirectory("."sv)
  203. {
  204. }
  205. }