ladybird/Kernel/ProcessExposed.cpp
Ben Wiederhake 143a64f9a2 Kernel: Remove unused includes of Kernel/Debug.h
These instances were detected by searching for files that include
Kernel/Debug.h, but don't match the regex:
\\bdbgln_if\(|_DEBUG\\b
This regex is pessimistic, so there might be more files that don't check
for any real *_DEBUG macro. There seem to be no corner cases anyway.

In theory, one might use LibCPP to detect things like this
automatically, but let's do this one step after another.
2023-01-02 20:27:20 -05:00

247 lines
8.5 KiB
C++

/*
* 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/LinkInode.h>
#include <Kernel/KBufferBuilder.h>
#include <Kernel/PerformanceEventBuffer.h>
#include <Kernel/Process.h>
#include <Kernel/ProcessExposed.h>
namespace Kernel {
static Spinlock<LockRank::None> s_index_lock {};
static InodeIndex s_next_inode_index = 0;
namespace SegmentedProcFSIndex {
static InodeIndex __build_raw_segmented_index(u32 primary, u16 sub_directory, u32 property)
{
VERIFY(primary < 0x10000000);
VERIFY(property < 0x100000);
// Note: The sub-directory part is already limited to 0xFFFF, so no need to VERIFY it.
return static_cast<u64>((static_cast<u64>(primary) << 36) | (static_cast<u64>(sub_directory) << 20) | property);
}
static InodeIndex build_segmented_index_with_known_pid(ProcessID pid, u16 sub_directory, u32 property)
{
return __build_raw_segmented_index(pid.value() + 1, sub_directory, property);
}
static InodeIndex build_segmented_index_with_unknown_property(ProcessID pid, ProcessSubDirectory sub_directory, unsigned property)
{
return build_segmented_index_with_known_pid(pid, to_underlying(sub_directory), static_cast<u32>(property));
}
InodeIndex build_segmented_index_for_pid_directory(ProcessID pid)
{
return build_segmented_index_with_unknown_property(pid, ProcessSubDirectory::Reserved, to_underlying(MainProcessProperty::Reserved));
}
InodeIndex build_segmented_index_for_sub_directory(ProcessID pid, ProcessSubDirectory sub_directory)
{
return build_segmented_index_with_unknown_property(pid, sub_directory, to_underlying(MainProcessProperty::Reserved));
}
InodeIndex build_segmented_index_for_main_property(ProcessID pid, ProcessSubDirectory sub_directory, MainProcessProperty property)
{
return build_segmented_index_with_known_pid(pid, to_underlying(sub_directory), to_underlying(property));
}
InodeIndex build_segmented_index_for_main_property_in_pid_directory(ProcessID pid, MainProcessProperty property)
{
return build_segmented_index_with_known_pid(pid, to_underlying(ProcessSubDirectory::Reserved), to_underlying(property));
}
InodeIndex build_segmented_index_for_thread_stack(ProcessID pid, ThreadID thread_id)
{
return build_segmented_index_with_unknown_property(pid, ProcessSubDirectory::Stacks, thread_id.value());
}
InodeIndex build_segmented_index_for_file_description(ProcessID pid, unsigned fd)
{
return build_segmented_index_with_unknown_property(pid, ProcessSubDirectory::OpenFileDescriptions, fd);
}
InodeIndex build_segmented_index_for_children(ProcessID pid, ProcessID child_pid)
{
return build_segmented_index_with_unknown_property(pid, ProcessSubDirectory::Children, child_pid.value());
}
}
static size_t s_allocate_global_inode_index()
{
SpinlockLocker lock(s_index_lock);
s_next_inode_index = s_next_inode_index.value() + 1;
// Note: Global ProcFS indices must be above 0 and up to maximum of what 36 bit (2 ^ 36 - 1) can represent.
VERIFY(s_next_inode_index > 0);
VERIFY(s_next_inode_index < 0x100000000);
return s_next_inode_index.value();
}
ProcFSExposedComponent::ProcFSExposedComponent() = default;
ProcFSExposedComponent::ProcFSExposedComponent(StringView name)
: m_component_index(s_allocate_global_inode_index())
{
auto name_or_error = KString::try_create(name);
if (name_or_error.is_error())
TODO();
m_name = name_or_error.release_value();
}
ProcFSExposedDirectory::ProcFSExposedDirectory(StringView name)
: ProcFSExposedComponent(name)
{
}
ProcFSExposedDirectory::ProcFSExposedDirectory(StringView name, ProcFSExposedDirectory const& parent_directory)
: ProcFSExposedComponent(name)
, m_parent_directory(parent_directory)
{
}
ProcFSExposedLink::ProcFSExposedLink(StringView name)
: ProcFSExposedComponent(name)
{
}
ErrorOr<size_t> ProcFSExposedLink::read_bytes(off_t offset, size_t count, UserOrKernelBuffer& buffer, OpenFileDescription*) const
{
VERIFY(offset == 0);
MutexLocker locker(m_lock);
auto builder = TRY(KBufferBuilder::try_create());
if (!const_cast<ProcFSExposedLink&>(*this).acquire_link(builder))
return Error::from_errno(EFAULT);
auto blob = builder.build();
if (!blob)
return Error::from_errno(EFAULT);
ssize_t nread = min(static_cast<off_t>(blob->size() - offset), static_cast<off_t>(count));
TRY(buffer.write(blob->data() + offset, nread));
return nread;
}
ErrorOr<NonnullLockRefPtr<Inode>> ProcFSExposedLink::to_inode(ProcFS const& procfs_instance) const
{
return TRY(ProcFSLinkInode::try_create(procfs_instance, *this));
}
ErrorOr<NonnullLockRefPtr<Inode>> ProcFSExposedDirectory::to_inode(ProcFS const& procfs_instance) const
{
return TRY(ProcFSDirectoryInode::try_create(procfs_instance, *this));
}
void ProcFSExposedDirectory::add_component(ProcFSExposedComponent const&)
{
TODO();
}
ErrorOr<NonnullLockRefPtr<ProcFSExposedComponent>> ProcFSExposedDirectory::lookup(StringView name)
{
for (auto& component : m_components) {
if (component.name() == name) {
return component;
}
}
return ENOENT;
}
ErrorOr<void> ProcFSExposedDirectory::traverse_as_directory(FileSystemID fsid, Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
{
MutexLocker locker(ProcFSComponentRegistry::the().get_lock());
auto parent_directory = m_parent_directory.strong_ref();
if (parent_directory.is_null())
return Error::from_errno(EINVAL);
TRY(callback({ "."sv, { fsid, component_index() }, DT_DIR }));
TRY(callback({ ".."sv, { fsid, parent_directory->component_index() }, DT_DIR }));
for (auto const& component : m_components) {
InodeIdentifier identifier = { fsid, component.component_index() };
TRY(callback({ component.name(), identifier, 0 }));
}
return {};
}
class ProcFSSelfProcessDirectory final : public ProcFSExposedLink {
public:
static NonnullLockRefPtr<ProcFSSelfProcessDirectory> must_create();
private:
ProcFSSelfProcessDirectory();
virtual bool acquire_link(KBufferBuilder& builder) override
{
return !builder.appendff("{}", Process::current().pid().value()).is_error();
}
};
UNMAP_AFTER_INIT NonnullLockRefPtr<ProcFSSelfProcessDirectory> ProcFSSelfProcessDirectory::must_create()
{
return adopt_lock_ref_if_nonnull(new (nothrow) ProcFSSelfProcessDirectory()).release_nonnull();
}
UNMAP_AFTER_INIT ProcFSSelfProcessDirectory::ProcFSSelfProcessDirectory()
: ProcFSExposedLink("self"sv)
{
}
UNMAP_AFTER_INIT NonnullLockRefPtr<ProcFSRootDirectory> ProcFSRootDirectory::must_create()
{
auto directory = adopt_lock_ref(*new (nothrow) ProcFSRootDirectory);
directory->m_components.append(ProcFSSelfProcessDirectory::must_create());
return directory;
}
ErrorOr<void> ProcFSRootDirectory::traverse_as_directory(FileSystemID fsid, Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
{
MutexLocker locker(ProcFSComponentRegistry::the().get_lock());
TRY(callback({ "."sv, { fsid, component_index() }, 0 }));
TRY(callback({ ".."sv, { fsid, 0 }, 0 }));
for (auto const& component : m_components) {
InodeIdentifier identifier = { fsid, component.component_index() };
TRY(callback({ component.name(), identifier, 0 }));
}
return Process::for_each_in_same_jail([&](Process& process) -> ErrorOr<void> {
VERIFY(!(process.pid() < 0));
u64 process_id = (u64)process.pid().value();
InodeIdentifier identifier = { fsid, static_cast<InodeIndex>(process_id << 36) };
auto process_id_string = TRY(KString::formatted("{:d}", process_id));
TRY(callback({ process_id_string->view(), identifier, 0 }));
return {};
});
}
ErrorOr<NonnullLockRefPtr<ProcFSExposedComponent>> ProcFSRootDirectory::lookup(StringView name)
{
auto maybe_candidate = ProcFSExposedDirectory::lookup(name);
if (maybe_candidate.is_error()) {
if (maybe_candidate.error().code() != ENOENT) {
return maybe_candidate.release_error();
}
} else {
return maybe_candidate.release_value();
}
auto pid = name.to_uint<unsigned>();
if (!pid.has_value())
return ESRCH;
auto actual_pid = pid.value();
if (auto maybe_process = Process::from_pid_in_same_jail(actual_pid))
return maybe_process->procfs_traits();
return ENOENT;
}
UNMAP_AFTER_INIT ProcFSRootDirectory::~ProcFSRootDirectory() = default;
UNMAP_AFTER_INIT ProcFSRootDirectory::ProcFSRootDirectory()
: ProcFSExposedDirectory("."sv)
{
}
}