summaryrefslogtreecommitdiff
path: root/Kernel/FileSystem
diff options
context:
space:
mode:
Diffstat (limited to 'Kernel/FileSystem')
-rw-r--r--Kernel/FileSystem/ProcFS.cpp610
-rw-r--r--Kernel/FileSystem/ProcFS.h201
-rw-r--r--Kernel/FileSystem/ProcFS/ComponentRegistry.cpp33
-rw-r--r--Kernel/FileSystem/ProcFS/DirectoryInode.cpp51
-rw-r--r--Kernel/FileSystem/ProcFS/DirectoryInode.h28
-rw-r--r--Kernel/FileSystem/ProcFS/FileSystem.cpp34
-rw-r--r--Kernel/FileSystem/ProcFS/FileSystem.h45
-rw-r--r--Kernel/FileSystem/ProcFS/GlobalInode.cpp88
-rw-r--r--Kernel/FileSystem/ProcFS/GlobalInode.h40
-rw-r--r--Kernel/FileSystem/ProcFS/Inode.cpp50
-rw-r--r--Kernel/FileSystem/ProcFS/Inode.h40
-rw-r--r--Kernel/FileSystem/ProcFS/LinkInode.cpp36
-rw-r--r--Kernel/FileSystem/ProcFS/LinkInode.h24
-rw-r--r--Kernel/FileSystem/ProcFS/ProcessAssociatedInode.cpp24
-rw-r--r--Kernel/FileSystem/ProcFS/ProcessAssociatedInode.h28
-rw-r--r--Kernel/FileSystem/ProcFS/ProcessDirectoryInode.cpp95
-rw-r--r--Kernel/FileSystem/ProcFS/ProcessDirectoryInode.h31
-rw-r--r--Kernel/FileSystem/ProcFS/ProcessPropertyInode.cpp236
-rw-r--r--Kernel/FileSystem/ProcFS/ProcessPropertyInode.h51
-rw-r--r--Kernel/FileSystem/ProcFS/ProcessSubDirectoryInode.cpp96
-rw-r--r--Kernel/FileSystem/ProcFS/ProcessSubDirectoryInode.h34
21 files changed, 1064 insertions, 811 deletions
diff --git a/Kernel/FileSystem/ProcFS.cpp b/Kernel/FileSystem/ProcFS.cpp
deleted file mode 100644
index 6eb4ad3771..0000000000
--- a/Kernel/FileSystem/ProcFS.cpp
+++ /dev/null
@@ -1,610 +0,0 @@
-/*
- * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
- * Copyright (c) 2021, Spencer Dixon <spencercdixon@gmail.com>
- * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
-
-#include <AK/Singleton.h>
-#include <Kernel/API/POSIX/errno.h>
-#include <Kernel/Debug.h>
-#include <Kernel/FileSystem/Custody.h>
-#include <Kernel/FileSystem/OpenFileDescription.h>
-#include <Kernel/FileSystem/ProcFS.h>
-#include <Kernel/FileSystem/VirtualFileSystem.h>
-#include <Kernel/Heap/kmalloc.h>
-#include <Kernel/Process.h>
-#include <Kernel/Sections.h>
-
-namespace Kernel {
-
-static Singleton<ProcFSComponentRegistry> s_the;
-
-ProcFSComponentRegistry& ProcFSComponentRegistry::the()
-{
- return *s_the;
-}
-
-UNMAP_AFTER_INIT void ProcFSComponentRegistry::initialize()
-{
- VERIFY(!s_the.is_initialized());
- s_the.ensure_instance();
-}
-
-UNMAP_AFTER_INIT ProcFSComponentRegistry::ProcFSComponentRegistry()
- : m_root_directory(ProcFSRootDirectory::must_create())
-{
-}
-
-ErrorOr<NonnullLockRefPtr<FileSystem>> ProcFS::try_create()
-{
- return TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFS));
-}
-
-ProcFS::ProcFS() = default;
-ProcFS::~ProcFS() = default;
-
-ErrorOr<void> ProcFS::initialize()
-{
- m_root_inode = static_ptr_cast<ProcFSDirectoryInode>(TRY(ProcFSComponentRegistry::the().root_directory().to_inode(*this)));
- return {};
-}
-
-Inode& ProcFS::root_inode()
-{
- return *m_root_inode;
-}
-
-ProcFSInode::ProcFSInode(ProcFS const& fs, InodeIndex index)
- : Inode(const_cast<ProcFS&>(fs), index)
-{
-}
-
-ProcFSInode::~ProcFSInode() = default;
-
-ErrorOr<void> ProcFSInode::flush_metadata()
-{
- return {};
-}
-
-ErrorOr<void> ProcFSInode::add_child(Inode&, StringView, mode_t)
-{
- return EROFS;
-}
-
-ErrorOr<NonnullLockRefPtr<Inode>> ProcFSInode::create_child(StringView, mode_t, dev_t, UserID, GroupID)
-{
- return EROFS;
-}
-
-ErrorOr<void> ProcFSInode::remove_child(StringView)
-{
- return EROFS;
-}
-
-ErrorOr<void> ProcFSInode::chmod(mode_t)
-{
- return EPERM;
-}
-
-ErrorOr<void> ProcFSInode::chown(UserID, GroupID)
-{
- return EPERM;
-}
-
-ErrorOr<NonnullLockRefPtr<ProcFSGlobalInode>> ProcFSGlobalInode::try_create(ProcFS const& fs, ProcFSExposedComponent const& component)
-{
- return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSGlobalInode(fs, component));
-}
-
-ProcFSGlobalInode::ProcFSGlobalInode(ProcFS const& fs, ProcFSExposedComponent const& component)
- : ProcFSInode(fs, component.component_index())
- , m_associated_component(component)
-{
-}
-
-void ProcFSGlobalInode::did_seek(OpenFileDescription& description, off_t new_offset)
-{
- if (new_offset != 0)
- return;
- auto result = m_associated_component->refresh_data(description);
- if (result.is_error()) {
- // Subsequent calls to read will return EIO!
- dbgln("ProcFS: Could not refresh contents: {}", result.error());
- }
-}
-
-ErrorOr<void> ProcFSGlobalInode::attach(OpenFileDescription& description)
-{
- return m_associated_component->refresh_data(description);
-}
-
-ErrorOr<size_t> ProcFSGlobalInode::read_bytes_locked(off_t offset, size_t count, UserOrKernelBuffer& buffer, OpenFileDescription* fd) const
-{
- return m_associated_component->read_bytes(offset, count, buffer, fd);
-}
-
-StringView ProcFSGlobalInode::name() const
-{
- return m_associated_component->name();
-}
-
-ErrorOr<void> ProcFSGlobalInode::traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const
-{
- VERIFY_NOT_REACHED();
-}
-
-ErrorOr<NonnullLockRefPtr<Inode>> ProcFSGlobalInode::lookup(StringView)
-{
- VERIFY_NOT_REACHED();
-}
-
-ErrorOr<void> ProcFSGlobalInode::truncate(u64 size)
-{
- return m_associated_component->truncate(size);
-}
-
-ErrorOr<void> ProcFSGlobalInode::update_timestamps(Optional<time_t>, Optional<time_t>, Optional<time_t>)
-{
- return {};
-}
-
-InodeMetadata ProcFSGlobalInode::metadata() const
-{
- MutexLocker locker(m_inode_lock);
- InodeMetadata metadata;
- metadata.inode = { fsid(), m_associated_component->component_index() };
- metadata.mode = S_IFREG | m_associated_component->required_mode();
- metadata.uid = m_associated_component->owner_user();
- metadata.gid = m_associated_component->owner_group();
- metadata.size = 0;
- metadata.mtime = m_associated_component->modified_time();
- return metadata;
-}
-
-ErrorOr<size_t> ProcFSGlobalInode::write_bytes_locked(off_t offset, size_t count, UserOrKernelBuffer const& buffer, OpenFileDescription* fd)
-{
- return m_associated_component->write_bytes(offset, count, buffer, fd);
-}
-
-ErrorOr<NonnullLockRefPtr<ProcFSDirectoryInode>> ProcFSDirectoryInode::try_create(ProcFS const& procfs, ProcFSExposedComponent const& component)
-{
- return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSDirectoryInode(procfs, component));
-}
-
-ProcFSDirectoryInode::ProcFSDirectoryInode(ProcFS const& fs, ProcFSExposedComponent const& component)
- : ProcFSGlobalInode(fs, component)
-{
-}
-
-ProcFSDirectoryInode::~ProcFSDirectoryInode() = default;
-InodeMetadata ProcFSDirectoryInode::metadata() const
-{
- MutexLocker locker(m_inode_lock);
- InodeMetadata metadata;
- metadata.inode = { fsid(), m_associated_component->component_index() };
- metadata.mode = S_IFDIR | m_associated_component->required_mode();
- metadata.uid = m_associated_component->owner_user();
- metadata.gid = m_associated_component->owner_group();
- metadata.size = 0;
- metadata.mtime = m_associated_component->modified_time();
- return metadata;
-}
-ErrorOr<void> ProcFSDirectoryInode::traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
-{
- MutexLocker locker(procfs().m_lock);
- return m_associated_component->traverse_as_directory(procfs().fsid(), move(callback));
-}
-
-ErrorOr<NonnullLockRefPtr<Inode>> ProcFSDirectoryInode::lookup(StringView name)
-{
- MutexLocker locker(procfs().m_lock);
- auto component = TRY(m_associated_component->lookup(name));
- return component->to_inode(procfs());
-}
-
-ErrorOr<NonnullLockRefPtr<ProcFSLinkInode>> ProcFSLinkInode::try_create(ProcFS const& procfs, ProcFSExposedComponent const& component)
-{
- return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSLinkInode(procfs, component));
-}
-
-ProcFSLinkInode::ProcFSLinkInode(ProcFS const& fs, ProcFSExposedComponent const& component)
- : ProcFSGlobalInode(fs, component)
-{
-}
-
-InodeMetadata ProcFSLinkInode::metadata() const
-{
- MutexLocker locker(m_inode_lock);
- InodeMetadata metadata;
- metadata.inode = { fsid(), m_associated_component->component_index() };
- metadata.mode = S_IFLNK | m_associated_component->required_mode();
- metadata.uid = m_associated_component->owner_user();
- metadata.gid = m_associated_component->owner_group();
- metadata.size = 0;
- metadata.mtime = m_associated_component->modified_time();
- return metadata;
-}
-
-ProcFSProcessAssociatedInode::ProcFSProcessAssociatedInode(ProcFS const& fs, ProcessID associated_pid, InodeIndex determined_index)
- : ProcFSInode(fs, determined_index)
- , m_pid(associated_pid)
-{
-}
-
-ErrorOr<size_t> ProcFSProcessAssociatedInode::write_bytes_locked(off_t, size_t, UserOrKernelBuffer const&, OpenFileDescription*)
-{
- return ENOTSUP;
-}
-
-ErrorOr<NonnullLockRefPtr<ProcFSProcessDirectoryInode>> ProcFSProcessDirectoryInode::try_create(ProcFS const& procfs, ProcessID pid)
-{
- return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSProcessDirectoryInode(procfs, pid));
-}
-
-ProcFSProcessDirectoryInode::ProcFSProcessDirectoryInode(ProcFS const& procfs, ProcessID pid)
- : ProcFSProcessAssociatedInode(procfs, pid, SegmentedProcFSIndex::build_segmented_index_for_pid_directory(pid))
-{
-}
-
-ErrorOr<void> ProcFSProcessDirectoryInode::attach(OpenFileDescription&)
-{
- return {};
-}
-
-InodeMetadata ProcFSProcessDirectoryInode::metadata() const
-{
- MutexLocker locker(m_inode_lock);
- auto process = Process::from_pid_in_same_jail(associated_pid());
- if (!process)
- return {};
-
- auto traits = process->procfs_traits();
- InodeMetadata metadata;
- metadata.inode = { fsid(), traits->component_index() };
- metadata.mode = S_IFDIR | traits->required_mode();
- metadata.uid = traits->owner_user();
- metadata.gid = traits->owner_group();
- metadata.size = 0;
- metadata.mtime = traits->modified_time();
- return metadata;
-}
-
-ErrorOr<size_t> ProcFSProcessDirectoryInode::read_bytes_locked(off_t, size_t, UserOrKernelBuffer&, OpenFileDescription*) const
-{
- VERIFY_NOT_REACHED();
-}
-
-ErrorOr<void> ProcFSProcessDirectoryInode::traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
-{
- MutexLocker locker(procfs().m_lock);
- auto process = Process::from_pid_in_same_jail(associated_pid());
- if (!process)
- return EINVAL;
- return process->procfs_traits()->traverse_as_directory(procfs().fsid(), move(callback));
-}
-
-ErrorOr<NonnullLockRefPtr<Inode>> ProcFSProcessDirectoryInode::lookup(StringView name)
-{
- MutexLocker locker(procfs().m_lock);
- auto process = Process::from_pid_in_same_jail(associated_pid());
- if (!process)
- return ESRCH;
- if (name == "fd"sv)
- return TRY(ProcFSProcessSubDirectoryInode::try_create(procfs(), SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions, associated_pid()));
- if (name == "stacks"sv)
- return TRY(ProcFSProcessSubDirectoryInode::try_create(procfs(), SegmentedProcFSIndex::ProcessSubDirectory::Stacks, associated_pid()));
- if (name == "children"sv)
- return TRY(ProcFSProcessSubDirectoryInode::try_create(procfs(), SegmentedProcFSIndex::ProcessSubDirectory::Children, associated_pid()));
- if (name == "unveil"sv)
- return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::Unveil, associated_pid()));
- if (name == "pledge"sv)
- return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::Pledge, associated_pid()));
- if (name == "fds"sv)
- return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::OpenFileDescriptions, associated_pid()));
- if (name == "exe"sv)
- return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::BinaryLink, associated_pid()));
- if (name == "cwd"sv)
- return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::CurrentWorkDirectoryLink, associated_pid()));
- if (name == "perf_events"sv)
- return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::PerformanceEvents, associated_pid()));
- if (name == "vm"sv)
- return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::VirtualMemoryStats, associated_pid()));
- if (name == "cmdline"sv)
- return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::CommandLine, associated_pid()));
- return ENOENT;
-}
-
-ErrorOr<NonnullLockRefPtr<ProcFSProcessSubDirectoryInode>> ProcFSProcessSubDirectoryInode::try_create(ProcFS const& procfs, SegmentedProcFSIndex::ProcessSubDirectory sub_directory_type, ProcessID pid)
-{
- return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSProcessSubDirectoryInode(procfs, sub_directory_type, pid));
-}
-
-ProcFSProcessSubDirectoryInode::ProcFSProcessSubDirectoryInode(ProcFS const& procfs, SegmentedProcFSIndex::ProcessSubDirectory sub_directory_type, ProcessID pid)
- : ProcFSProcessAssociatedInode(procfs, pid, SegmentedProcFSIndex::build_segmented_index_for_sub_directory(pid, sub_directory_type))
- , m_sub_directory_type(sub_directory_type)
-{
-}
-
-ErrorOr<size_t> ProcFSProcessSubDirectoryInode::read_bytes_locked(off_t, size_t, UserOrKernelBuffer&, OpenFileDescription*) const
-{
- VERIFY_NOT_REACHED();
-}
-
-ErrorOr<void> ProcFSProcessSubDirectoryInode::attach(OpenFileDescription&)
-{
- return {};
-}
-
-void ProcFSProcessSubDirectoryInode::did_seek(OpenFileDescription&, off_t)
-{
- VERIFY_NOT_REACHED();
-}
-
-InodeMetadata ProcFSProcessSubDirectoryInode::metadata() const
-{
- MutexLocker locker(m_inode_lock);
- auto process = Process::from_pid_in_same_jail(associated_pid());
- if (!process)
- return {};
-
- auto traits = process->procfs_traits();
- InodeMetadata metadata;
- metadata.inode = { fsid(), traits->component_index() };
- metadata.mode = S_IFDIR | traits->required_mode();
- metadata.uid = traits->owner_user();
- metadata.gid = traits->owner_group();
- metadata.size = 0;
- metadata.mtime = traits->modified_time();
- return metadata;
-}
-
-ErrorOr<void> ProcFSProcessSubDirectoryInode::traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
-{
- MutexLocker locker(procfs().m_lock);
- auto process = Process::from_pid_in_same_jail(associated_pid());
- if (!process)
- return EINVAL;
- switch (m_sub_directory_type) {
- case SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions:
- return process->traverse_file_descriptions_directory(procfs().fsid(), move(callback));
- case SegmentedProcFSIndex::ProcessSubDirectory::Stacks:
- return process->traverse_stacks_directory(procfs().fsid(), move(callback));
- case SegmentedProcFSIndex::ProcessSubDirectory::Children:
- return process->traverse_children_directory(procfs().fsid(), move(callback));
- default:
- VERIFY_NOT_REACHED();
- }
- VERIFY_NOT_REACHED();
-}
-
-ErrorOr<NonnullLockRefPtr<Inode>> ProcFSProcessSubDirectoryInode::lookup(StringView name)
-{
- MutexLocker locker(procfs().m_lock);
- auto process = Process::from_pid_in_same_jail(associated_pid());
- if (!process)
- return ESRCH;
- switch (m_sub_directory_type) {
- case SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions:
- return process->lookup_file_descriptions_directory(procfs(), name);
- case SegmentedProcFSIndex::ProcessSubDirectory::Stacks:
- return process->lookup_stacks_directory(procfs(), name);
- case SegmentedProcFSIndex::ProcessSubDirectory::Children:
- return process->lookup_children_directory(procfs(), name);
- default:
- VERIFY_NOT_REACHED();
- }
-}
-
-ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> ProcFSProcessPropertyInode::try_create_for_file_description_link(ProcFS const& procfs, unsigned file_description_index, ProcessID pid)
-{
- return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSProcessPropertyInode(procfs, file_description_index, pid));
-}
-ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> ProcFSProcessPropertyInode::try_create_for_thread_stack(ProcFS const& procfs, ThreadID stack_thread_index, ProcessID pid)
-{
- return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSProcessPropertyInode(procfs, stack_thread_index, pid));
-}
-ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> ProcFSProcessPropertyInode::try_create_for_pid_property(ProcFS const& procfs, SegmentedProcFSIndex::MainProcessProperty main_property_type, ProcessID pid)
-{
- return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSProcessPropertyInode(procfs, main_property_type, pid));
-}
-ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> ProcFSProcessPropertyInode::try_create_for_child_process_link(ProcFS const& procfs, ProcessID child_pid, ProcessID pid)
-{
- return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSProcessPropertyInode(procfs, child_pid, pid));
-}
-
-ProcFSProcessPropertyInode::ProcFSProcessPropertyInode(ProcFS const& procfs, SegmentedProcFSIndex::MainProcessProperty main_property_type, ProcessID pid)
- : ProcFSProcessAssociatedInode(procfs, pid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(pid, main_property_type))
- , m_parent_sub_directory_type(SegmentedProcFSIndex::ProcessSubDirectory::Reserved)
-{
- m_possible_data.property_type = main_property_type;
-}
-
-ProcFSProcessPropertyInode::ProcFSProcessPropertyInode(ProcFS const& procfs, unsigned file_description_index, ProcessID pid)
- : ProcFSProcessAssociatedInode(procfs, pid, SegmentedProcFSIndex::build_segmented_index_for_file_description(pid, file_description_index))
- , m_parent_sub_directory_type(SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions)
-{
- m_possible_data.property_index = file_description_index;
-}
-
-ProcFSProcessPropertyInode::ProcFSProcessPropertyInode(ProcFS const& procfs, ThreadID thread_stack_index, ProcessID pid)
- : ProcFSProcessAssociatedInode(procfs, pid, SegmentedProcFSIndex::build_segmented_index_for_thread_stack(pid, thread_stack_index))
- , m_parent_sub_directory_type(SegmentedProcFSIndex::ProcessSubDirectory::Stacks)
-{
- m_possible_data.property_index = thread_stack_index.value();
-}
-
-ProcFSProcessPropertyInode::ProcFSProcessPropertyInode(ProcFS const& procfs, ProcessID child_pid, ProcessID pid)
- : ProcFSProcessAssociatedInode(procfs, pid, SegmentedProcFSIndex::build_segmented_index_for_children(pid, child_pid))
- , m_parent_sub_directory_type(SegmentedProcFSIndex::ProcessSubDirectory::Children)
-{
- m_possible_data.property_index = child_pid.value();
-}
-
-ErrorOr<void> ProcFSProcessPropertyInode::attach(OpenFileDescription& description)
-{
- return refresh_data(description);
-}
-void ProcFSProcessPropertyInode::did_seek(OpenFileDescription& description, off_t offset)
-{
- if (offset != 0)
- return;
- (void)refresh_data(description);
-}
-
-static mode_t determine_procfs_process_inode_mode(SegmentedProcFSIndex::ProcessSubDirectory parent_sub_directory_type, SegmentedProcFSIndex::MainProcessProperty main_property)
-{
- if (parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions)
- return S_IFLNK | 0400;
- if (parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::Stacks)
- return S_IFREG | 0400;
- if (parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::Children)
- return S_IFLNK | 0400;
- VERIFY(parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::Reserved);
- if (main_property == SegmentedProcFSIndex::MainProcessProperty::BinaryLink)
- return S_IFLNK | 0777;
- if (main_property == SegmentedProcFSIndex::MainProcessProperty::CurrentWorkDirectoryLink)
- return S_IFLNK | 0777;
- return S_IFREG | 0400;
-}
-
-InodeMetadata ProcFSProcessPropertyInode::metadata() const
-{
- MutexLocker locker(m_inode_lock);
- auto process = Process::from_pid_in_same_jail(associated_pid());
- if (!process)
- return {};
-
- auto traits = process->procfs_traits();
- InodeMetadata metadata;
- metadata.inode = { fsid(), traits->component_index() };
- metadata.mode = determine_procfs_process_inode_mode(m_parent_sub_directory_type, m_possible_data.property_type);
- metadata.uid = traits->owner_user();
- metadata.gid = traits->owner_group();
- metadata.size = 0;
- metadata.mtime = traits->modified_time();
- return metadata;
-}
-ErrorOr<void> ProcFSProcessPropertyInode::traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const
-{
- VERIFY_NOT_REACHED();
-}
-ErrorOr<size_t> ProcFSProcessPropertyInode::read_bytes_locked(off_t offset, size_t count, UserOrKernelBuffer& buffer, OpenFileDescription* description) const
-{
- dbgln_if(PROCFS_DEBUG, "ProcFS ProcessInformation: read_bytes_locked offset: {} count: {}", offset, count);
-
- VERIFY(offset >= 0);
- VERIFY(buffer.user_or_kernel_ptr());
-
- if (!description) {
- auto builder = TRY(KBufferBuilder::try_create());
- auto process = Process::from_pid_in_same_jail(associated_pid());
- if (!process)
- return Error::from_errno(ESRCH);
- TRY(try_to_acquire_data(*process, builder));
- auto data_buffer = builder.build();
- if (!data_buffer)
- return Error::from_errno(EFAULT);
- ssize_t nread = min(static_cast<off_t>(data_buffer->size() - offset), static_cast<off_t>(count));
- TRY(buffer.write(data_buffer->data() + offset, nread));
- return nread;
- }
- if (!description->data()) {
- dbgln("ProcFS Process Information: Do not have cached data!");
- return Error::from_errno(EIO);
- }
-
- MutexLocker locker(m_refresh_lock);
-
- auto& typed_cached_data = static_cast<ProcFSInodeData&>(*description->data());
- auto& data_buffer = typed_cached_data.buffer;
-
- if (!data_buffer || (size_t)offset >= data_buffer->size())
- return 0;
-
- ssize_t nread = min(static_cast<off_t>(data_buffer->size() - offset), static_cast<off_t>(count));
- TRY(buffer.write(data_buffer->data() + offset, nread));
-
- return nread;
-}
-ErrorOr<NonnullLockRefPtr<Inode>> ProcFSProcessPropertyInode::lookup(StringView)
-{
- return EINVAL;
-}
-
-static ErrorOr<void> build_from_cached_data(KBufferBuilder& builder, ProcFSInodeData& cached_data)
-{
- cached_data.buffer = builder.build();
- if (!cached_data.buffer)
- return ENOMEM;
- return {};
-}
-
-ErrorOr<void> ProcFSProcessPropertyInode::try_to_acquire_data(Process& process, KBufferBuilder& builder) const
-{
- // FIXME: Verify process is already ref-counted
- if (m_parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions) {
- TRY(process.procfs_get_file_description_link(m_possible_data.property_index, builder));
- return {};
- }
- if (m_parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::Stacks) {
- TRY(process.procfs_get_thread_stack(m_possible_data.property_index, builder));
- return {};
- }
- if (m_parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::Children) {
- TRY(process.procfs_get_child_proccess_link(m_possible_data.property_index, builder));
- return {};
- }
-
- VERIFY(m_parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::Reserved);
- switch (m_possible_data.property_type) {
- case SegmentedProcFSIndex::MainProcessProperty::Unveil:
- return process.procfs_get_unveil_stats(builder);
- case SegmentedProcFSIndex::MainProcessProperty::Pledge:
- return process.procfs_get_pledge_stats(builder);
- case SegmentedProcFSIndex::MainProcessProperty::OpenFileDescriptions:
- return process.procfs_get_fds_stats(builder);
- case SegmentedProcFSIndex::MainProcessProperty::BinaryLink:
- return process.procfs_get_binary_link(builder);
- case SegmentedProcFSIndex::MainProcessProperty::CurrentWorkDirectoryLink:
- return process.procfs_get_current_work_directory_link(builder);
- case SegmentedProcFSIndex::MainProcessProperty::PerformanceEvents:
- return process.procfs_get_perf_events(builder);
- case SegmentedProcFSIndex::MainProcessProperty::VirtualMemoryStats:
- return process.procfs_get_virtual_memory_stats(builder);
- case SegmentedProcFSIndex::MainProcessProperty::CommandLine:
- return process.procfs_get_command_line(builder);
- default:
- VERIFY_NOT_REACHED();
- }
-}
-
-ErrorOr<void> ProcFSProcessPropertyInode::refresh_data(OpenFileDescription& description)
-{
- // For process-specific inodes, hold the process's ptrace lock across refresh
- // and refuse to load data if the process is not dumpable.
- // Without this, files opened before a process went non-dumpable could still be used for dumping.
- auto process = Process::from_pid_in_same_jail(associated_pid());
- if (!process)
- return Error::from_errno(ESRCH);
- process->ptrace_lock().lock();
- if (!process->is_dumpable()) {
- process->ptrace_lock().unlock();
- return EPERM;
- }
- ScopeGuard guard = [&] {
- process->ptrace_lock().unlock();
- };
- MutexLocker locker(m_refresh_lock);
- auto& cached_data = description.data();
- if (!cached_data) {
- cached_data = adopt_own_if_nonnull(new (nothrow) ProcFSInodeData);
- if (!cached_data)
- return ENOMEM;
- }
- auto builder = TRY(KBufferBuilder::try_create());
- TRY(try_to_acquire_data(*process, builder));
- return build_from_cached_data(builder, static_cast<ProcFSInodeData&>(*cached_data));
-}
-}
diff --git a/Kernel/FileSystem/ProcFS.h b/Kernel/FileSystem/ProcFS.h
deleted file mode 100644
index 58e384709b..0000000000
--- a/Kernel/FileSystem/ProcFS.h
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
-
-#pragma once
-
-#include <AK/HashMap.h>
-#include <AK/Types.h>
-#include <Kernel/FileSystem/FileSystem.h>
-#include <Kernel/FileSystem/Inode.h>
-#include <Kernel/Forward.h>
-#include <Kernel/KBufferBuilder.h>
-#include <Kernel/Locking/Mutex.h>
-#include <Kernel/ProcessExposed.h>
-#include <Kernel/UnixTypes.h>
-
-namespace Kernel {
-
-class ProcFS final : public FileSystem {
- friend class ProcFSInode;
- friend class ProcFSDirectoryInode;
- friend class ProcFSProcessDirectoryInode;
- friend class ProcFSGlobalInode;
- friend class ProcFSAssociatedProcessInode;
- friend class ProcFSProcessSubDirectoryInode;
-
-public:
- virtual ~ProcFS() override;
- static ErrorOr<NonnullLockRefPtr<FileSystem>> try_create();
-
- virtual ErrorOr<void> initialize() override;
- virtual StringView class_name() const override { return "ProcFS"sv; }
-
- virtual Inode& root_inode() override;
-
-private:
- ProcFS();
-
- LockRefPtr<ProcFSDirectoryInode> m_root_inode;
-};
-
-class ProcFSInode : public Inode {
- friend class ProcFS;
-
-public:
- virtual ~ProcFSInode() override;
-
-protected:
- ProcFSInode(ProcFS const&, InodeIndex);
-
- ProcFS& procfs() { return static_cast<ProcFS&>(Inode::fs()); }
- ProcFS const& procfs() const { return static_cast<ProcFS const&>(Inode::fs()); }
-
- // ^Inode
- virtual ErrorOr<void> attach(OpenFileDescription& description) override = 0;
- virtual void did_seek(OpenFileDescription&, off_t) override = 0;
- virtual ErrorOr<void> flush_metadata() override final;
- virtual ErrorOr<NonnullLockRefPtr<Inode>> create_child(StringView name, mode_t, dev_t, UserID, GroupID) override final;
- virtual ErrorOr<void> add_child(Inode&, StringView name, mode_t) override final;
- virtual ErrorOr<void> remove_child(StringView name) override final;
- virtual ErrorOr<void> chmod(mode_t) override final;
- virtual ErrorOr<void> chown(UserID, GroupID) override final;
-};
-
-class ProcFSGlobalInode : public ProcFSInode {
- friend class ProcFS;
-
-public:
- static ErrorOr<NonnullLockRefPtr<ProcFSGlobalInode>> try_create(ProcFS const&, ProcFSExposedComponent const&);
- virtual ~ProcFSGlobalInode() override {};
- StringView name() const;
-
-protected:
- ProcFSGlobalInode(ProcFS const&, ProcFSExposedComponent const&);
-
- // ^Inode
- virtual ErrorOr<void> attach(OpenFileDescription& description) override final;
- virtual ErrorOr<size_t> read_bytes_locked(off_t, size_t, UserOrKernelBuffer& buffer, OpenFileDescription*) const override final;
- virtual ErrorOr<size_t> write_bytes_locked(off_t, size_t, UserOrKernelBuffer const& buffer, OpenFileDescription*) override final;
- virtual void did_seek(OpenFileDescription&, off_t) override final;
- virtual InodeMetadata metadata() const override;
- virtual ErrorOr<void> traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const override;
- virtual ErrorOr<NonnullLockRefPtr<Inode>> lookup(StringView) override;
- virtual ErrorOr<void> truncate(u64) override final;
- virtual ErrorOr<void> update_timestamps(Optional<time_t> atime, Optional<time_t> ctime, Optional<time_t> mtime) override;
-
- NonnullLockRefPtr<ProcFSExposedComponent> m_associated_component;
-};
-
-class ProcFSLinkInode : public ProcFSGlobalInode {
- friend class ProcFS;
-
-public:
- static ErrorOr<NonnullLockRefPtr<ProcFSLinkInode>> try_create(ProcFS const&, ProcFSExposedComponent const&);
-
-protected:
- ProcFSLinkInode(ProcFS const&, ProcFSExposedComponent const&);
- virtual InodeMetadata metadata() const override;
-};
-
-class ProcFSDirectoryInode final : public ProcFSGlobalInode {
- friend class ProcFS;
-
-public:
- static ErrorOr<NonnullLockRefPtr<ProcFSDirectoryInode>> try_create(ProcFS const&, ProcFSExposedComponent const&);
- virtual ~ProcFSDirectoryInode() override;
-
-protected:
- ProcFSDirectoryInode(ProcFS const&, ProcFSExposedComponent const&);
- // ^Inode
- virtual InodeMetadata metadata() const override;
- virtual ErrorOr<void> traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const override;
- virtual ErrorOr<NonnullLockRefPtr<Inode>> lookup(StringView name) override;
-};
-
-class ProcFSProcessAssociatedInode : public ProcFSInode {
- friend class ProcFS;
-
-protected:
- ProcFSProcessAssociatedInode(ProcFS const&, ProcessID, InodeIndex);
- ProcessID associated_pid() const { return m_pid; }
-
- // ^Inode
- virtual ErrorOr<size_t> write_bytes_locked(off_t, size_t, UserOrKernelBuffer const& buffer, OpenFileDescription*) override final;
-
-private:
- const ProcessID m_pid;
-};
-
-class ProcFSProcessDirectoryInode final : public ProcFSProcessAssociatedInode {
- friend class ProcFS;
-
-public:
- static ErrorOr<NonnullLockRefPtr<ProcFSProcessDirectoryInode>> try_create(ProcFS const&, ProcessID);
-
-private:
- ProcFSProcessDirectoryInode(ProcFS const&, ProcessID);
- // ^Inode
- virtual ErrorOr<void> attach(OpenFileDescription& description) override;
- virtual void did_seek(OpenFileDescription&, off_t) override { }
- virtual InodeMetadata metadata() const override;
- virtual ErrorOr<void> traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const override;
- virtual ErrorOr<size_t> read_bytes_locked(off_t, size_t, UserOrKernelBuffer& buffer, OpenFileDescription*) const override final;
- virtual ErrorOr<NonnullLockRefPtr<Inode>> lookup(StringView name) override;
-};
-
-class ProcFSProcessSubDirectoryInode final : public ProcFSProcessAssociatedInode {
- friend class ProcFS;
-
-public:
- static ErrorOr<NonnullLockRefPtr<ProcFSProcessSubDirectoryInode>> try_create(ProcFS const&, SegmentedProcFSIndex::ProcessSubDirectory, ProcessID);
-
-private:
- ProcFSProcessSubDirectoryInode(ProcFS const&, SegmentedProcFSIndex::ProcessSubDirectory, ProcessID);
- // ^Inode
- virtual ErrorOr<void> attach(OpenFileDescription& description) override;
- virtual void did_seek(OpenFileDescription&, off_t) override;
- virtual InodeMetadata metadata() const override;
- virtual ErrorOr<void> traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const override;
- virtual ErrorOr<size_t> read_bytes_locked(off_t, size_t, UserOrKernelBuffer& buffer, OpenFileDescription*) const override final;
- virtual ErrorOr<NonnullLockRefPtr<Inode>> lookup(StringView name) override;
-
- const SegmentedProcFSIndex::ProcessSubDirectory m_sub_directory_type;
-};
-
-class ProcFSProcessPropertyInode final : public ProcFSProcessAssociatedInode {
- friend class ProcFS;
-
-public:
- static ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> try_create_for_file_description_link(ProcFS const&, unsigned, ProcessID);
- static ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> try_create_for_thread_stack(ProcFS const&, ThreadID, ProcessID);
- static ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> try_create_for_pid_property(ProcFS const&, SegmentedProcFSIndex::MainProcessProperty, ProcessID);
- static ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> try_create_for_child_process_link(ProcFS const&, ProcessID, ProcessID);
-
-private:
- ProcFSProcessPropertyInode(ProcFS const&, SegmentedProcFSIndex::MainProcessProperty, ProcessID);
- ProcFSProcessPropertyInode(ProcFS const&, ThreadID, ProcessID);
- ProcFSProcessPropertyInode(ProcFS const&, unsigned, ProcessID);
- ProcFSProcessPropertyInode(ProcFS const&, ProcessID, ProcessID);
-
- // ^Inode
- virtual ErrorOr<void> attach(OpenFileDescription& description) override;
- virtual void did_seek(OpenFileDescription&, off_t) override;
- virtual InodeMetadata metadata() const override;
- virtual ErrorOr<void> traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const override;
- virtual ErrorOr<size_t> read_bytes_locked(off_t, size_t, UserOrKernelBuffer& buffer, OpenFileDescription*) const override final;
- virtual ErrorOr<NonnullLockRefPtr<Inode>> lookup(StringView name) override final;
-
- ErrorOr<void> refresh_data(OpenFileDescription& description);
- ErrorOr<void> try_to_acquire_data(Process& process, KBufferBuilder& builder) const;
-
- const SegmentedProcFSIndex::ProcessSubDirectory m_parent_sub_directory_type;
- union {
- SegmentedProcFSIndex::MainProcessProperty property_type;
- unsigned property_index;
- } m_possible_data;
- mutable Mutex m_refresh_lock;
-};
-}
diff --git a/Kernel/FileSystem/ProcFS/ComponentRegistry.cpp b/Kernel/FileSystem/ProcFS/ComponentRegistry.cpp
new file mode 100644
index 0000000000..d0437ad302
--- /dev/null
+++ b/Kernel/FileSystem/ProcFS/ComponentRegistry.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2021, Spencer Dixon <spencercdixon@gmail.com>
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <AK/Singleton.h>
+#include <Kernel/ProcessExposed.h>
+#include <Kernel/Sections.h>
+
+namespace Kernel {
+
+static Singleton<ProcFSComponentRegistry> s_the;
+
+ProcFSComponentRegistry& ProcFSComponentRegistry::the()
+{
+ return *s_the;
+}
+
+UNMAP_AFTER_INIT void ProcFSComponentRegistry::initialize()
+{
+ VERIFY(!s_the.is_initialized());
+ s_the.ensure_instance();
+}
+
+UNMAP_AFTER_INIT ProcFSComponentRegistry::ProcFSComponentRegistry()
+ : m_root_directory(ProcFSRootDirectory::must_create())
+{
+}
+
+}
diff --git a/Kernel/FileSystem/ProcFS/DirectoryInode.cpp b/Kernel/FileSystem/ProcFS/DirectoryInode.cpp
new file mode 100644
index 0000000000..569fa480fd
--- /dev/null
+++ b/Kernel/FileSystem/ProcFS/DirectoryInode.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2021, Spencer Dixon <spencercdixon@gmail.com>
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <Kernel/FileSystem/ProcFS/DirectoryInode.h>
+
+namespace Kernel {
+
+ErrorOr<NonnullLockRefPtr<ProcFSDirectoryInode>> ProcFSDirectoryInode::try_create(ProcFS const& procfs, ProcFSExposedComponent const& component)
+{
+ return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSDirectoryInode(procfs, component));
+}
+
+ProcFSDirectoryInode::ProcFSDirectoryInode(ProcFS const& fs, ProcFSExposedComponent const& component)
+ : ProcFSGlobalInode(fs, component)
+{
+}
+
+ProcFSDirectoryInode::~ProcFSDirectoryInode() = default;
+
+InodeMetadata ProcFSDirectoryInode::metadata() const
+{
+ MutexLocker locker(m_inode_lock);
+ InodeMetadata metadata;
+ metadata.inode = { fsid(), m_associated_component->component_index() };
+ metadata.mode = S_IFDIR | m_associated_component->required_mode();
+ metadata.uid = m_associated_component->owner_user();
+ metadata.gid = m_associated_component->owner_group();
+ metadata.size = 0;
+ metadata.mtime = m_associated_component->modified_time();
+ return metadata;
+}
+
+ErrorOr<void> ProcFSDirectoryInode::traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
+{
+ MutexLocker locker(procfs().m_lock);
+ return m_associated_component->traverse_as_directory(procfs().fsid(), move(callback));
+}
+
+ErrorOr<NonnullLockRefPtr<Inode>> ProcFSDirectoryInode::lookup(StringView name)
+{
+ MutexLocker locker(procfs().m_lock);
+ auto component = TRY(m_associated_component->lookup(name));
+ return component->to_inode(procfs());
+}
+
+}
diff --git a/Kernel/FileSystem/ProcFS/DirectoryInode.h b/Kernel/FileSystem/ProcFS/DirectoryInode.h
new file mode 100644
index 0000000000..173af61667
--- /dev/null
+++ b/Kernel/FileSystem/ProcFS/DirectoryInode.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <Kernel/FileSystem/ProcFS/GlobalInode.h>
+
+namespace Kernel {
+
+class ProcFSDirectoryInode final : public ProcFSGlobalInode {
+ friend class ProcFS;
+
+public:
+ static ErrorOr<NonnullLockRefPtr<ProcFSDirectoryInode>> try_create(ProcFS const&, ProcFSExposedComponent const&);
+ virtual ~ProcFSDirectoryInode() override;
+
+protected:
+ ProcFSDirectoryInode(ProcFS const&, ProcFSExposedComponent const&);
+ // ^Inode
+ virtual InodeMetadata metadata() const override;
+ virtual ErrorOr<void> traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const override;
+ virtual ErrorOr<NonnullLockRefPtr<Inode>> lookup(StringView name) override;
+};
+
+}
diff --git a/Kernel/FileSystem/ProcFS/FileSystem.cpp b/Kernel/FileSystem/ProcFS/FileSystem.cpp
new file mode 100644
index 0000000000..7ea12c6344
--- /dev/null
+++ b/Kernel/FileSystem/ProcFS/FileSystem.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2021, Spencer Dixon <spencercdixon@gmail.com>
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <Kernel/FileSystem/ProcFS/DirectoryInode.h>
+#include <Kernel/FileSystem/ProcFS/FileSystem.h>
+#include <Kernel/ProcessExposed.h>
+
+namespace Kernel {
+
+ErrorOr<NonnullLockRefPtr<FileSystem>> ProcFS::try_create()
+{
+ return TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFS));
+}
+
+ProcFS::ProcFS() = default;
+ProcFS::~ProcFS() = default;
+
+ErrorOr<void> ProcFS::initialize()
+{
+ m_root_inode = static_ptr_cast<ProcFSDirectoryInode>(TRY(ProcFSComponentRegistry::the().root_directory().to_inode(*this)));
+ return {};
+}
+
+Inode& ProcFS::root_inode()
+{
+ return *m_root_inode;
+}
+
+}
diff --git a/Kernel/FileSystem/ProcFS/FileSystem.h b/Kernel/FileSystem/ProcFS/FileSystem.h
new file mode 100644
index 0000000000..f8d127e3c9
--- /dev/null
+++ b/Kernel/FileSystem/ProcFS/FileSystem.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/Types.h>
+#include <Kernel/FileSystem/FileSystem.h>
+#include <Kernel/FileSystem/Inode.h>
+#include <Kernel/Forward.h>
+
+namespace Kernel {
+
+class ProcFSInode;
+class ProcFSProcessDirectoryInode;
+class ProcFSGlobalInode;
+class ProcFSAssociatedProcessInode;
+class ProcFSProcessSubDirectoryInode;
+
+class ProcFS final : public FileSystem {
+ friend class ProcFSInode;
+ friend class ProcFSDirectoryInode;
+ friend class ProcFSProcessDirectoryInode;
+ friend class ProcFSGlobalInode;
+ friend class ProcFSAssociatedProcessInode;
+ friend class ProcFSProcessSubDirectoryInode;
+
+public:
+ virtual ~ProcFS() override;
+ static ErrorOr<NonnullLockRefPtr<FileSystem>> try_create();
+
+ virtual ErrorOr<void> initialize() override;
+ virtual StringView class_name() const override { return "ProcFS"sv; }
+
+ virtual Inode& root_inode() override;
+
+private:
+ ProcFS();
+
+ LockRefPtr<ProcFSDirectoryInode> m_root_inode;
+};
+
+}
diff --git a/Kernel/FileSystem/ProcFS/GlobalInode.cpp b/Kernel/FileSystem/ProcFS/GlobalInode.cpp
new file mode 100644
index 0000000000..67fda1947e
--- /dev/null
+++ b/Kernel/FileSystem/ProcFS/GlobalInode.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2021, Spencer Dixon <spencercdixon@gmail.com>
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <Kernel/FileSystem/ProcFS/GlobalInode.h>
+
+namespace Kernel {
+
+ErrorOr<NonnullLockRefPtr<ProcFSGlobalInode>> ProcFSGlobalInode::try_create(ProcFS const& fs, ProcFSExposedComponent const& component)
+{
+ return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSGlobalInode(fs, component));
+}
+
+ProcFSGlobalInode::ProcFSGlobalInode(ProcFS const& fs, ProcFSExposedComponent const& component)
+ : ProcFSInode(fs, component.component_index())
+ , m_associated_component(component)
+{
+}
+
+void ProcFSGlobalInode::did_seek(OpenFileDescription& description, off_t new_offset)
+{
+ if (new_offset != 0)
+ return;
+ auto result = m_associated_component->refresh_data(description);
+ if (result.is_error()) {
+ // Subsequent calls to read will return EIO!
+ dbgln("ProcFS: Could not refresh contents: {}", result.error());
+ }
+}
+
+ErrorOr<void> ProcFSGlobalInode::attach(OpenFileDescription& description)
+{
+ return m_associated_component->refresh_data(description);
+}
+
+ErrorOr<size_t> ProcFSGlobalInode::read_bytes_locked(off_t offset, size_t count, UserOrKernelBuffer& buffer, OpenFileDescription* fd) const
+{
+ return m_associated_component->read_bytes(offset, count, buffer, fd);
+}
+
+StringView ProcFSGlobalInode::name() const
+{
+ return m_associated_component->name();
+}
+
+ErrorOr<void> ProcFSGlobalInode::traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const
+{
+ VERIFY_NOT_REACHED();
+}
+
+ErrorOr<NonnullLockRefPtr<Inode>> ProcFSGlobalInode::lookup(StringView)
+{
+ VERIFY_NOT_REACHED();
+}
+
+ErrorOr<void> ProcFSGlobalInode::truncate(u64 size)
+{
+ return m_associated_component->truncate(size);
+}
+
+ErrorOr<void> ProcFSGlobalInode::update_timestamps(Optional<time_t>, Optional<time_t>, Optional<time_t>)
+{
+ return {};
+}
+
+InodeMetadata ProcFSGlobalInode::metadata() const
+{
+ MutexLocker locker(m_inode_lock);
+ InodeMetadata metadata;
+ metadata.inode = { fsid(), m_associated_component->component_index() };
+ metadata.mode = S_IFREG | m_associated_component->required_mode();
+ metadata.uid = m_associated_component->owner_user();
+ metadata.gid = m_associated_component->owner_group();
+ metadata.size = 0;
+ metadata.mtime = m_associated_component->modified_time();
+ return metadata;
+}
+
+ErrorOr<size_t> ProcFSGlobalInode::write_bytes_locked(off_t offset, size_t count, UserOrKernelBuffer const& buffer, OpenFileDescription* fd)
+{
+ return m_associated_component->write_bytes(offset, count, buffer, fd);
+}
+
+}
diff --git a/Kernel/FileSystem/ProcFS/GlobalInode.h b/Kernel/FileSystem/ProcFS/GlobalInode.h
new file mode 100644
index 0000000000..6a485cdfb8
--- /dev/null
+++ b/Kernel/FileSystem/ProcFS/GlobalInode.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <Kernel/FileSystem/ProcFS/FileSystem.h>
+#include <Kernel/FileSystem/ProcFS/Inode.h>
+#include <Kernel/ProcessExposed.h>
+
+namespace Kernel {
+
+class ProcFSGlobalInode : public ProcFSInode {
+ friend class ProcFS;
+
+public:
+ static ErrorOr<NonnullLockRefPtr<ProcFSGlobalInode>> try_create(ProcFS const&, ProcFSExposedComponent const&);
+ virtual ~ProcFSGlobalInode() override {};
+ StringView name() const;
+
+protected:
+ ProcFSGlobalInode(ProcFS const&, ProcFSExposedComponent const&);
+
+ // ^Inode
+ virtual ErrorOr<void> attach(OpenFileDescription& description) override final;
+ virtual ErrorOr<size_t> read_bytes_locked(off_t, size_t, UserOrKernelBuffer& buffer, OpenFileDescription*) const override final;
+ virtual ErrorOr<size_t> write_bytes_locked(off_t, size_t, UserOrKernelBuffer const& buffer, OpenFileDescription*) override final;
+ virtual void did_seek(OpenFileDescription&, off_t) override final;
+ virtual InodeMetadata metadata() const override;
+ virtual ErrorOr<void> traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const override;
+ virtual ErrorOr<NonnullLockRefPtr<Inode>> lookup(StringView) override;
+ virtual ErrorOr<void> truncate(u64) override final;
+ virtual ErrorOr<void> update_timestamps(Optional<time_t> atime, Optional<time_t> ctime, Optional<time_t> mtime) override;
+
+ NonnullLockRefPtr<ProcFSExposedComponent> m_associated_component;
+};
+
+}
diff --git a/Kernel/FileSystem/ProcFS/Inode.cpp b/Kernel/FileSystem/ProcFS/Inode.cpp
new file mode 100644
index 0000000000..6c774b0998
--- /dev/null
+++ b/Kernel/FileSystem/ProcFS/Inode.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2021, Spencer Dixon <spencercdixon@gmail.com>
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <Kernel/FileSystem/ProcFS/Inode.h>
+
+namespace Kernel {
+
+ProcFSInode::ProcFSInode(ProcFS const& fs, InodeIndex index)
+ : Inode(const_cast<ProcFS&>(fs), index)
+{
+}
+
+ProcFSInode::~ProcFSInode() = default;
+
+ErrorOr<void> ProcFSInode::flush_metadata()
+{
+ return {};
+}
+
+ErrorOr<void> ProcFSInode::add_child(Inode&, StringView, mode_t)
+{
+ return EROFS;
+}
+
+ErrorOr<NonnullLockRefPtr<Inode>> ProcFSInode::create_child(StringView, mode_t, dev_t, UserID, GroupID)
+{
+ return EROFS;
+}
+
+ErrorOr<void> ProcFSInode::remove_child(StringView)
+{
+ return EROFS;
+}
+
+ErrorOr<void> ProcFSInode::chmod(mode_t)
+{
+ return EPERM;
+}
+
+ErrorOr<void> ProcFSInode::chown(UserID, GroupID)
+{
+ return EPERM;
+}
+
+}
diff --git a/Kernel/FileSystem/ProcFS/Inode.h b/Kernel/FileSystem/ProcFS/Inode.h
new file mode 100644
index 0000000000..3fcf5847c4
--- /dev/null
+++ b/Kernel/FileSystem/ProcFS/Inode.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <Kernel/FileSystem/Inode.h>
+#include <Kernel/FileSystem/OpenFileDescription.h>
+#include <Kernel/FileSystem/ProcFS/FileSystem.h>
+#include <Kernel/ProcessExposed.h>
+#include <Kernel/UnixTypes.h>
+
+namespace Kernel {
+
+class ProcFSInode : public Inode {
+ friend class ProcFS;
+
+public:
+ virtual ~ProcFSInode() override;
+
+protected:
+ ProcFSInode(ProcFS const&, InodeIndex);
+
+ ProcFS& procfs() { return static_cast<ProcFS&>(Inode::fs()); }
+ ProcFS const& procfs() const { return static_cast<ProcFS const&>(Inode::fs()); }
+
+ // ^Inode
+ virtual ErrorOr<void> attach(OpenFileDescription& description) override = 0;
+ virtual void did_seek(OpenFileDescription&, off_t) override = 0;
+ virtual ErrorOr<void> flush_metadata() override final;
+ virtual ErrorOr<NonnullLockRefPtr<Inode>> create_child(StringView name, mode_t, dev_t, UserID, GroupID) override final;
+ virtual ErrorOr<void> add_child(Inode&, StringView name, mode_t) override final;
+ virtual ErrorOr<void> remove_child(StringView name) override final;
+ virtual ErrorOr<void> chmod(mode_t) override final;
+ virtual ErrorOr<void> chown(UserID, GroupID) override final;
+};
+
+}
diff --git a/Kernel/FileSystem/ProcFS/LinkInode.cpp b/Kernel/FileSystem/ProcFS/LinkInode.cpp
new file mode 100644
index 0000000000..4331d0b2a0
--- /dev/null
+++ b/Kernel/FileSystem/ProcFS/LinkInode.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2021, Spencer Dixon <spencercdixon@gmail.com>
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <Kernel/FileSystem/ProcFS/LinkInode.h>
+
+namespace Kernel {
+
+ErrorOr<NonnullLockRefPtr<ProcFSLinkInode>> ProcFSLinkInode::try_create(ProcFS const& procfs, ProcFSExposedComponent const& component)
+{
+ return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSLinkInode(procfs, component));
+}
+
+ProcFSLinkInode::ProcFSLinkInode(ProcFS const& fs, ProcFSExposedComponent const& component)
+ : ProcFSGlobalInode(fs, component)
+{
+}
+
+InodeMetadata ProcFSLinkInode::metadata() const
+{
+ MutexLocker locker(m_inode_lock);
+ InodeMetadata metadata;
+ metadata.inode = { fsid(), m_associated_component->component_index() };
+ metadata.mode = S_IFLNK | m_associated_component->required_mode();
+ metadata.uid = m_associated_component->owner_user();
+ metadata.gid = m_associated_component->owner_group();
+ metadata.size = 0;
+ metadata.mtime = m_associated_component->modified_time();
+ return metadata;
+}
+
+}
diff --git a/Kernel/FileSystem/ProcFS/LinkInode.h b/Kernel/FileSystem/ProcFS/LinkInode.h
new file mode 100644
index 0000000000..8b80471314
--- /dev/null
+++ b/Kernel/FileSystem/ProcFS/LinkInode.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <Kernel/FileSystem/ProcFS/GlobalInode.h>
+
+namespace Kernel {
+
+class ProcFSLinkInode : public ProcFSGlobalInode {
+ friend class ProcFS;
+
+public:
+ static ErrorOr<NonnullLockRefPtr<ProcFSLinkInode>> try_create(ProcFS const&, ProcFSExposedComponent const&);
+
+protected:
+ ProcFSLinkInode(ProcFS const&, ProcFSExposedComponent const&);
+ virtual InodeMetadata metadata() const override;
+};
+
+}
diff --git a/Kernel/FileSystem/ProcFS/ProcessAssociatedInode.cpp b/Kernel/FileSystem/ProcFS/ProcessAssociatedInode.cpp
new file mode 100644
index 0000000000..627a2fa980
--- /dev/null
+++ b/Kernel/FileSystem/ProcFS/ProcessAssociatedInode.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2021, Spencer Dixon <spencercdixon@gmail.com>
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <Kernel/FileSystem/ProcFS/ProcessAssociatedInode.h>
+
+namespace Kernel {
+
+ProcFSProcessAssociatedInode::ProcFSProcessAssociatedInode(ProcFS const& fs, ProcessID associated_pid, InodeIndex determined_index)
+ : ProcFSInode(fs, determined_index)
+ , m_pid(associated_pid)
+{
+}
+
+ErrorOr<size_t> ProcFSProcessAssociatedInode::write_bytes_locked(off_t, size_t, UserOrKernelBuffer const&, OpenFileDescription*)
+{
+ return ENOTSUP;
+}
+
+}
diff --git a/Kernel/FileSystem/ProcFS/ProcessAssociatedInode.h b/Kernel/FileSystem/ProcFS/ProcessAssociatedInode.h
new file mode 100644
index 0000000000..34a9ca1448
--- /dev/null
+++ b/Kernel/FileSystem/ProcFS/ProcessAssociatedInode.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <Kernel/FileSystem/ProcFS/Inode.h>
+#include <Kernel/Forward.h>
+
+namespace Kernel {
+
+class ProcFSProcessAssociatedInode : public ProcFSInode {
+ friend class ProcFS;
+
+protected:
+ ProcFSProcessAssociatedInode(ProcFS const&, ProcessID, InodeIndex);
+ ProcessID associated_pid() const { return m_pid; }
+
+ // ^Inode
+ virtual ErrorOr<size_t> write_bytes_locked(off_t, size_t, UserOrKernelBuffer const& buffer, OpenFileDescription*) override final;
+
+private:
+ const ProcessID m_pid;
+};
+
+}
diff --git a/Kernel/FileSystem/ProcFS/ProcessDirectoryInode.cpp b/Kernel/FileSystem/ProcFS/ProcessDirectoryInode.cpp
new file mode 100644
index 0000000000..a8e4593c6e
--- /dev/null
+++ b/Kernel/FileSystem/ProcFS/ProcessDirectoryInode.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2021, Spencer Dixon <spencercdixon@gmail.com>
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <Kernel/FileSystem/ProcFS/ProcessDirectoryInode.h>
+#include <Kernel/FileSystem/ProcFS/ProcessPropertyInode.h>
+#include <Kernel/FileSystem/ProcFS/ProcessSubDirectoryInode.h>
+#include <Kernel/Process.h>
+#include <Kernel/ProcessExposed.h>
+
+namespace Kernel {
+
+ErrorOr<NonnullLockRefPtr<ProcFSProcessDirectoryInode>> ProcFSProcessDirectoryInode::try_create(ProcFS const& procfs, ProcessID pid)
+{
+ return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSProcessDirectoryInode(procfs, pid));
+}
+
+ProcFSProcessDirectoryInode::ProcFSProcessDirectoryInode(ProcFS const& procfs, ProcessID pid)
+ : ProcFSProcessAssociatedInode(procfs, pid, SegmentedProcFSIndex::build_segmented_index_for_pid_directory(pid))
+{
+}
+
+ErrorOr<void> ProcFSProcessDirectoryInode::attach(OpenFileDescription&)
+{
+ return {};
+}
+
+InodeMetadata ProcFSProcessDirectoryInode::metadata() const
+{
+ MutexLocker locker(m_inode_lock);
+ auto process = Process::from_pid_in_same_jail(associated_pid());
+ if (!process)
+ return {};
+
+ auto traits = process->procfs_traits();
+ InodeMetadata metadata;
+ metadata.inode = { fsid(), traits->component_index() };
+ metadata.mode = S_IFDIR | traits->required_mode();
+ metadata.uid = traits->owner_user();
+ metadata.gid = traits->owner_group();
+ metadata.size = 0;
+ metadata.mtime = traits->modified_time();
+ return metadata;
+}
+
+ErrorOr<size_t> ProcFSProcessDirectoryInode::read_bytes_locked(off_t, size_t, UserOrKernelBuffer&, OpenFileDescription*) const
+{
+ VERIFY_NOT_REACHED();
+}
+
+ErrorOr<void> ProcFSProcessDirectoryInode::traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
+{
+ MutexLocker locker(procfs().m_lock);
+ auto process = Process::from_pid_in_same_jail(associated_pid());
+ if (!process)
+ return EINVAL;
+ return process->procfs_traits()->traverse_as_directory(procfs().fsid(), move(callback));
+}
+
+ErrorOr<NonnullLockRefPtr<Inode>> ProcFSProcessDirectoryInode::lookup(StringView name)
+{
+ MutexLocker locker(procfs().m_lock);
+ auto process = Process::from_pid_in_same_jail(associated_pid());
+ if (!process)
+ return ESRCH;
+ if (name == "fd"sv)
+ return TRY(ProcFSProcessSubDirectoryInode::try_create(procfs(), SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions, associated_pid()));
+ if (name == "stacks"sv)
+ return TRY(ProcFSProcessSubDirectoryInode::try_create(procfs(), SegmentedProcFSIndex::ProcessSubDirectory::Stacks, associated_pid()));
+ if (name == "children"sv)
+ return TRY(ProcFSProcessSubDirectoryInode::try_create(procfs(), SegmentedProcFSIndex::ProcessSubDirectory::Children, associated_pid()));
+ if (name == "unveil"sv)
+ return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::Unveil, associated_pid()));
+ if (name == "pledge"sv)
+ return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::Pledge, associated_pid()));
+ if (name == "fds"sv)
+ return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::OpenFileDescriptions, associated_pid()));
+ if (name == "exe"sv)
+ return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::BinaryLink, associated_pid()));
+ if (name == "cwd"sv)
+ return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::CurrentWorkDirectoryLink, associated_pid()));
+ if (name == "perf_events"sv)
+ return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::PerformanceEvents, associated_pid()));
+ if (name == "vm"sv)
+ return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::VirtualMemoryStats, associated_pid()));
+ if (name == "cmdline"sv)
+ return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::CommandLine, associated_pid()));
+ return ENOENT;
+}
+
+}
diff --git a/Kernel/FileSystem/ProcFS/ProcessDirectoryInode.h b/Kernel/FileSystem/ProcFS/ProcessDirectoryInode.h
new file mode 100644
index 0000000000..e3e9fb758a
--- /dev/null
+++ b/Kernel/FileSystem/ProcFS/ProcessDirectoryInode.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <Kernel/FileSystem/ProcFS/ProcessAssociatedInode.h>
+#include <Kernel/Forward.h>
+
+namespace Kernel {
+
+class ProcFSProcessDirectoryInode final : public ProcFSProcessAssociatedInode {
+ friend class ProcFS;
+
+public:
+ static ErrorOr<NonnullLockRefPtr<ProcFSProcessDirectoryInode>> try_create(ProcFS const&, ProcessID);
+
+private:
+ ProcFSProcessDirectoryInode(ProcFS const&, ProcessID);
+ // ^Inode
+ virtual ErrorOr<void> attach(OpenFileDescription& description) override;
+ virtual void did_seek(OpenFileDescription&, off_t) override { }
+ virtual InodeMetadata metadata() const override;
+ virtual ErrorOr<void> traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const override;
+ virtual ErrorOr<size_t> read_bytes_locked(off_t, size_t, UserOrKernelBuffer& buffer, OpenFileDescription*) const override final;
+ virtual ErrorOr<NonnullLockRefPtr<Inode>> lookup(StringView name) override;
+};
+
+}
diff --git a/Kernel/FileSystem/ProcFS/ProcessPropertyInode.cpp b/Kernel/FileSystem/ProcFS/ProcessPropertyInode.cpp
new file mode 100644
index 0000000000..5e701615b1
--- /dev/null
+++ b/Kernel/FileSystem/ProcFS/ProcessPropertyInode.cpp
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2021, Spencer Dixon <spencercdixon@gmail.com>
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <Kernel/API/POSIX/errno.h>
+#include <Kernel/Debug.h>
+#include <Kernel/FileSystem/OpenFileDescription.h>
+#include <Kernel/FileSystem/ProcFS/ProcessPropertyInode.h>
+#include <Kernel/Process.h>
+#include <Kernel/ProcessExposed.h>
+
+namespace Kernel {
+
+ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> ProcFSProcessPropertyInode::try_create_for_file_description_link(ProcFS const& procfs, unsigned file_description_index, ProcessID pid)
+{
+ return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSProcessPropertyInode(procfs, file_description_index, pid));
+}
+
+ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> ProcFSProcessPropertyInode::try_create_for_thread_stack(ProcFS const& procfs, ThreadID stack_thread_index, ProcessID pid)
+{
+ return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSProcessPropertyInode(procfs, stack_thread_index, pid));
+}
+
+ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> ProcFSProcessPropertyInode::try_create_for_pid_property(ProcFS const& procfs, SegmentedProcFSIndex::MainProcessProperty main_property_type, ProcessID pid)
+{
+ return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSProcessPropertyInode(procfs, main_property_type, pid));
+}
+
+ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> ProcFSProcessPropertyInode::try_create_for_child_process_link(ProcFS const& procfs, ProcessID child_pid, ProcessID pid)
+{
+ return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSProcessPropertyInode(procfs, child_pid, pid));
+}
+
+ProcFSProcessPropertyInode::ProcFSProcessPropertyInode(ProcFS const& procfs, SegmentedProcFSIndex::MainProcessProperty main_property_type, ProcessID pid)
+ : ProcFSProcessAssociatedInode(procfs, pid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(pid, main_property_type))
+ , m_parent_sub_directory_type(SegmentedProcFSIndex::ProcessSubDirectory::Reserved)
+{
+ m_possible_data.property_type = main_property_type;
+}
+
+ProcFSProcessPropertyInode::ProcFSProcessPropertyInode(ProcFS const& procfs, unsigned file_description_index, ProcessID pid)
+ : ProcFSProcessAssociatedInode(procfs, pid, SegmentedProcFSIndex::build_segmented_index_for_file_description(pid, file_description_index))
+ , m_parent_sub_directory_type(SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions)
+{
+ m_possible_data.property_index = file_description_index;
+}
+
+ProcFSProcessPropertyInode::ProcFSProcessPropertyInode(ProcFS const& procfs, ThreadID thread_stack_index, ProcessID pid)
+ : ProcFSProcessAssociatedInode(procfs, pid, SegmentedProcFSIndex::build_segmented_index_for_thread_stack(pid, thread_stack_index))
+ , m_parent_sub_directory_type(SegmentedProcFSIndex::ProcessSubDirectory::Stacks)
+{
+ m_possible_data.property_index = thread_stack_index.value();
+}
+
+ProcFSProcessPropertyInode::ProcFSProcessPropertyInode(ProcFS const& procfs, ProcessID child_pid, ProcessID pid)
+ : ProcFSProcessAssociatedInode(procfs, pid, SegmentedProcFSIndex::build_segmented_index_for_children(pid, child_pid))
+ , m_parent_sub_directory_type(SegmentedProcFSIndex::ProcessSubDirectory::Children)
+{
+ m_possible_data.property_index = child_pid.value();
+}
+
+ErrorOr<void> ProcFSProcessPropertyInode::attach(OpenFileDescription& description)
+{
+ return refresh_data(description);
+}
+
+void ProcFSProcessPropertyInode::did_seek(OpenFileDescription& description, off_t offset)
+{
+ if (offset != 0)
+ return;
+ (void)refresh_data(description);
+}
+
+static mode_t determine_procfs_process_inode_mode(SegmentedProcFSIndex::ProcessSubDirectory parent_sub_directory_type, SegmentedProcFSIndex::MainProcessProperty main_property)
+{
+ if (parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions)
+ return S_IFLNK | 0400;
+ if (parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::Stacks)
+ return S_IFREG | 0400;
+ if (parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::Children)
+ return S_IFLNK | 0400;
+ VERIFY(parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::Reserved);
+ if (main_property == SegmentedProcFSIndex::MainProcessProperty::BinaryLink)
+ return S_IFLNK | 0777;
+ if (main_property == SegmentedProcFSIndex::MainProcessProperty::CurrentWorkDirectoryLink)
+ return S_IFLNK | 0777;
+ return S_IFREG | 0400;
+}
+
+InodeMetadata ProcFSProcessPropertyInode::metadata() const
+{
+ MutexLocker locker(m_inode_lock);
+ auto process = Process::from_pid_in_same_jail(associated_pid());
+ if (!process)
+ return {};
+
+ auto traits = process->procfs_traits();
+ InodeMetadata metadata;
+ metadata.inode = { fsid(), traits->component_index() };
+ metadata.mode = determine_procfs_process_inode_mode(m_parent_sub_directory_type, m_possible_data.property_type);
+ metadata.uid = traits->owner_user();
+ metadata.gid = traits->owner_group();
+ metadata.size = 0;
+ metadata.mtime = traits->modified_time();
+ return metadata;
+}
+
+ErrorOr<void> ProcFSProcessPropertyInode::traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const
+{
+ VERIFY_NOT_REACHED();
+}
+
+ErrorOr<size_t> ProcFSProcessPropertyInode::read_bytes_locked(off_t offset, size_t count, UserOrKernelBuffer& buffer, OpenFileDescription* description) const
+{
+ dbgln_if(PROCFS_DEBUG, "ProcFS ProcessInformation: read_bytes_locked offset: {} count: {}", offset, count);
+
+ VERIFY(offset >= 0);
+ VERIFY(buffer.user_or_kernel_ptr());
+
+ if (!description) {
+ auto builder = TRY(KBufferBuilder::try_create());
+ auto process = Process::from_pid_in_same_jail(associated_pid());
+ if (!process)
+ return Error::from_errno(ESRCH);
+ TRY(try_to_acquire_data(*process, builder));
+ auto data_buffer = builder.build();
+ if (!data_buffer)
+ return Error::from_errno(EFAULT);
+ ssize_t nread = min(static_cast<off_t>(data_buffer->size() - offset), static_cast<off_t>(count));
+ TRY(buffer.write(data_buffer->data() + offset, nread));
+ return nread;
+ }
+ if (!description->data()) {
+ dbgln("ProcFS Process Information: Do not have cached data!");
+ return Error::from_errno(EIO);
+ }
+
+ MutexLocker locker(m_refresh_lock);
+
+ auto& typed_cached_data = static_cast<ProcFSInodeData&>(*description->data());
+ auto& data_buffer = typed_cached_data.buffer;
+
+ if (!data_buffer || (size_t)offset >= data_buffer->size())
+ return 0;
+
+ ssize_t nread = min(static_cast<off_t>(data_buffer->size() - offset), static_cast<off_t>(count));
+ TRY(buffer.write(data_buffer->data() + offset, nread));
+
+ return nread;
+}
+
+ErrorOr<NonnullLockRefPtr<Inode>> ProcFSProcessPropertyInode::lookup(StringView)
+{
+ return EINVAL;
+}
+
+static ErrorOr<void> build_from_cached_data(KBufferBuilder& builder, ProcFSInodeData& cached_data)
+{
+ cached_data.buffer = builder.build();
+ if (!cached_data.buffer)
+ return ENOMEM;
+ return {};
+}
+
+ErrorOr<void> ProcFSProcessPropertyInode::try_to_acquire_data(Process& process, KBufferBuilder& builder) const
+{
+ // FIXME: Verify process is already ref-counted
+ if (m_parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions) {
+ TRY(process.procfs_get_file_description_link(m_possible_data.property_index, builder));
+ return {};
+ }
+ if (m_parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::Stacks) {
+ TRY(process.procfs_get_thread_stack(m_possible_data.property_index, builder));
+ return {};
+ }
+ if (m_parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::Children) {
+ TRY(process.procfs_get_child_proccess_link(m_possible_data.property_index, builder));
+ return {};
+ }
+
+ VERIFY(m_parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::Reserved);
+ switch (m_possible_data.property_type) {
+ case SegmentedProcFSIndex::MainProcessProperty::Unveil:
+ return process.procfs_get_unveil_stats(builder);
+ case SegmentedProcFSIndex::MainProcessProperty::Pledge:
+ return process.procfs_get_pledge_stats(builder);
+ case SegmentedProcFSIndex::MainProcessProperty::OpenFileDescriptions:
+ return process.procfs_get_fds_stats(builder);
+ case SegmentedProcFSIndex::MainProcessProperty::BinaryLink:
+ return process.procfs_get_binary_link(builder);
+ case SegmentedProcFSIndex::MainProcessProperty::CurrentWorkDirectoryLink:
+ return process.procfs_get_current_work_directory_link(builder);
+ case SegmentedProcFSIndex::MainProcessProperty::PerformanceEvents:
+ return process.procfs_get_perf_events(builder);
+ case SegmentedProcFSIndex::MainProcessProperty::VirtualMemoryStats:
+ return process.procfs_get_virtual_memory_stats(builder);
+ case SegmentedProcFSIndex::MainProcessProperty::CommandLine:
+ return process.procfs_get_command_line(builder);
+ default:
+ VERIFY_NOT_REACHED();
+ }
+}
+
+ErrorOr<void> ProcFSProcessPropertyInode::refresh_data(OpenFileDescription& description)
+{
+ // For process-specific inodes, hold the process's ptrace lock across refresh
+ // and refuse to load data if the process is not dumpable.
+ // Without this, files opened before a process went non-dumpable could still be used for dumping.
+ auto process = Process::from_pid_in_same_jail(associated_pid());
+ if (!process)
+ return Error::from_errno(ESRCH);
+ process->ptrace_lock().lock();
+ if (!process->is_dumpable()) {
+ process->ptrace_lock().unlock();
+ return EPERM;
+ }
+ ScopeGuard guard = [&] {
+ process->ptrace_lock().unlock();
+ };
+ MutexLocker locker(m_refresh_lock);
+ auto& cached_data = description.data();
+ if (!cached_data) {
+ cached_data = adopt_own_if_nonnull(new (nothrow) ProcFSInodeData);
+ if (!cached_data)
+ return ENOMEM;
+ }
+ auto builder = TRY(KBufferBuilder::try_create());
+ TRY(try_to_acquire_data(*process, builder));
+ return build_from_cached_data(builder, static_cast<ProcFSInodeData&>(*cached_data));
+}
+
+}
diff --git a/Kernel/FileSystem/ProcFS/ProcessPropertyInode.h b/Kernel/FileSystem/ProcFS/ProcessPropertyInode.h
new file mode 100644
index 0000000000..9340d63080
--- /dev/null
+++ b/Kernel/FileSystem/ProcFS/ProcessPropertyInode.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <Kernel/FileSystem/ProcFS/ProcessAssociatedInode.h>
+#include <Kernel/Forward.h>
+#include <Kernel/KBufferBuilder.h>
+#include <Kernel/Locking/Mutex.h>
+#include <Kernel/ProcessExposed.h>
+#include <Kernel/UnixTypes.h>
+
+namespace Kernel {
+
+class ProcFSProcessPropertyInode final : public ProcFSProcessAssociatedInode {
+ friend class ProcFS;
+
+public:
+ static ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> try_create_for_file_description_link(ProcFS const&, unsigned, ProcessID);
+ static ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> try_create_for_thread_stack(ProcFS const&, ThreadID, ProcessID);
+ static ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> try_create_for_pid_property(ProcFS const&, SegmentedProcFSIndex::MainProcessProperty, ProcessID);
+ static ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> try_create_for_child_process_link(ProcFS const&, ProcessID, ProcessID);
+
+private:
+ ProcFSProcessPropertyInode(ProcFS const&, SegmentedProcFSIndex::MainProcessProperty, ProcessID);
+ ProcFSProcessPropertyInode(ProcFS const&, ThreadID, ProcessID);
+ ProcFSProcessPropertyInode(ProcFS const&, unsigned, ProcessID);
+ ProcFSProcessPropertyInode(ProcFS const&, ProcessID, ProcessID);
+
+ // ^Inode
+ virtual ErrorOr<void> attach(OpenFileDescription& description) override;
+ virtual void did_seek(OpenFileDescription&, off_t) override;
+ virtual InodeMetadata metadata() const override;
+ virtual ErrorOr<void> traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const override;
+ virtual ErrorOr<size_t> read_bytes_locked(off_t, size_t, UserOrKernelBuffer& buffer, OpenFileDescription*) const override final;
+ virtual ErrorOr<NonnullLockRefPtr<Inode>> lookup(StringView name) override final;
+
+ ErrorOr<void> refresh_data(OpenFileDescription& description);
+ ErrorOr<void> try_to_acquire_data(Process& process, KBufferBuilder& builder) const;
+
+ const SegmentedProcFSIndex::ProcessSubDirectory m_parent_sub_directory_type;
+ union {
+ SegmentedProcFSIndex::MainProcessProperty property_type;
+ unsigned property_index;
+ } m_possible_data;
+ mutable Mutex m_refresh_lock;
+};
+}
diff --git a/Kernel/FileSystem/ProcFS/ProcessSubDirectoryInode.cpp b/Kernel/FileSystem/ProcFS/ProcessSubDirectoryInode.cpp
new file mode 100644
index 0000000000..843daede7d
--- /dev/null
+++ b/Kernel/FileSystem/ProcFS/ProcessSubDirectoryInode.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2021, Spencer Dixon <spencercdixon@gmail.com>
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <Kernel/FileSystem/ProcFS/ProcessSubDirectoryInode.h>
+#include <Kernel/Process.h>
+#include <Kernel/ProcessExposed.h>
+
+namespace Kernel {
+
+ErrorOr<NonnullLockRefPtr<ProcFSProcessSubDirectoryInode>> ProcFSProcessSubDirectoryInode::try_create(ProcFS const& procfs, SegmentedProcFSIndex::ProcessSubDirectory sub_directory_type, ProcessID pid)
+{
+ return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSProcessSubDirectoryInode(procfs, sub_directory_type, pid));
+}
+
+ProcFSProcessSubDirectoryInode::ProcFSProcessSubDirectoryInode(ProcFS const& procfs, SegmentedProcFSIndex::ProcessSubDirectory sub_directory_type, ProcessID pid)
+ : ProcFSProcessAssociatedInode(procfs, pid, SegmentedProcFSIndex::build_segmented_index_for_sub_directory(pid, sub_directory_type))
+ , m_sub_directory_type(sub_directory_type)
+{
+}
+
+ErrorOr<size_t> ProcFSProcessSubDirectoryInode::read_bytes_locked(off_t, size_t, UserOrKernelBuffer&, OpenFileDescription*) const
+{
+ VERIFY_NOT_REACHED();
+}
+
+ErrorOr<void> ProcFSProcessSubDirectoryInode::attach(OpenFileDescription&)
+{
+ return {};
+}
+
+void ProcFSProcessSubDirectoryInode::did_seek(OpenFileDescription&, off_t)
+{
+ VERIFY_NOT_REACHED();
+}
+
+InodeMetadata ProcFSProcessSubDirectoryInode::metadata() const
+{
+ MutexLocker locker(m_inode_lock);
+ auto process = Process::from_pid_in_same_jail(associated_pid());
+ if (!process)
+ return {};
+
+ auto traits = process->procfs_traits();
+ InodeMetadata metadata;
+ metadata.inode = { fsid(), traits->component_index() };
+ metadata.mode = S_IFDIR | traits->required_mode();
+ metadata.uid = traits->owner_user();
+ metadata.gid = traits->owner_group();
+ metadata.size = 0;
+ metadata.mtime = traits->modified_time();
+ return metadata;
+}
+
+ErrorOr<void> ProcFSProcessSubDirectoryInode::traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
+{
+ MutexLocker locker(procfs().m_lock);
+ auto process = Process::from_pid_in_same_jail(associated_pid());
+ if (!process)
+ return EINVAL;
+ switch (m_sub_directory_type) {
+ case SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions:
+ return process->traverse_file_descriptions_directory(procfs().fsid(), move(callback));
+ case SegmentedProcFSIndex::ProcessSubDirectory::Stacks:
+ return process->traverse_stacks_directory(procfs().fsid(), move(callback));
+ case SegmentedProcFSIndex::ProcessSubDirectory::Children:
+ return process->traverse_children_directory(procfs().fsid(), move(callback));
+ default:
+ VERIFY_NOT_REACHED();
+ }
+ VERIFY_NOT_REACHED();
+}
+
+ErrorOr<NonnullLockRefPtr<Inode>> ProcFSProcessSubDirectoryInode::lookup(StringView name)
+{
+ MutexLocker locker(procfs().m_lock);
+ auto process = Process::from_pid_in_same_jail(associated_pid());
+ if (!process)
+ return ESRCH;
+ switch (m_sub_directory_type) {
+ case SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions:
+ return process->lookup_file_descriptions_directory(procfs(), name);
+ case SegmentedProcFSIndex::ProcessSubDirectory::Stacks:
+ return process->lookup_stacks_directory(procfs(), name);
+ case SegmentedProcFSIndex::ProcessSubDirectory::Children:
+ return process->lookup_children_directory(procfs(), name);
+ default:
+ VERIFY_NOT_REACHED();
+ }
+}
+
+}
diff --git a/Kernel/FileSystem/ProcFS/ProcessSubDirectoryInode.h b/Kernel/FileSystem/ProcFS/ProcessSubDirectoryInode.h
new file mode 100644
index 0000000000..4a64281194
--- /dev/null
+++ b/Kernel/FileSystem/ProcFS/ProcessSubDirectoryInode.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <Kernel/FileSystem/ProcFS/ProcessAssociatedInode.h>
+#include <Kernel/Forward.h>
+#include <Kernel/ProcessExposed.h>
+
+namespace Kernel {
+
+class ProcFSProcessSubDirectoryInode final : public ProcFSProcessAssociatedInode {
+ friend class ProcFS;
+
+public:
+ static ErrorOr<NonnullLockRefPtr<ProcFSProcessSubDirectoryInode>> try_create(ProcFS const&, SegmentedProcFSIndex::ProcessSubDirectory, ProcessID);
+
+private:
+ ProcFSProcessSubDirectoryInode(ProcFS const&, SegmentedProcFSIndex::ProcessSubDirectory, ProcessID);
+ // ^Inode
+ virtual ErrorOr<void> attach(OpenFileDescription& description) override;
+ virtual void did_seek(OpenFileDescription&, off_t) override;
+ virtual InodeMetadata metadata() const override;
+ virtual ErrorOr<void> traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const override;
+ virtual ErrorOr<size_t> read_bytes_locked(off_t, size_t, UserOrKernelBuffer& buffer, OpenFileDescription*) const override final;
+ virtual ErrorOr<NonnullLockRefPtr<Inode>> lookup(StringView name) override;
+
+ const SegmentedProcFSIndex::ProcessSubDirectory m_sub_directory_type;
+};
+
+}