diff --git a/Kernel/Makefile b/Kernel/Makefile index 5fe43e0b44..e547fa091d 100644 --- a/Kernel/Makefile +++ b/Kernel/Makefile @@ -16,7 +16,7 @@ KERNEL_OBJS = \ Console.o \ IRQHandler.o \ kprintf.o \ - ProcFileSystem.o \ + ProcFS.o \ RTC.o \ TTY.o \ PTYMultiplexer.o \ diff --git a/Kernel/MemoryManager.h b/Kernel/MemoryManager.h index de189e9f8d..e546350d3d 100644 --- a/Kernel/MemoryManager.h +++ b/Kernel/MemoryManager.h @@ -201,7 +201,7 @@ class MemoryManager { friend class PhysicalPage; friend class Region; friend class VMObject; - friend ByteBuffer procfs$mm(SynthFSInode&); + friend ByteBuffer procfs$mm(InodeIdentifier); public: static MemoryManager& the() PURE; diff --git a/Kernel/ProcFS.cpp b/Kernel/ProcFS.cpp new file mode 100644 index 0000000000..66f18912cf --- /dev/null +++ b/Kernel/ProcFS.cpp @@ -0,0 +1,1002 @@ +#include "ProcFS.h" +#include "Process.h" +#include +#include "system.h" +#include "MemoryManager.h" +#include "StdLib.h" +#include "i386.h" +#include "KSyms.h" +#include "Console.h" +#include +#include + +enum ProcParentDirectory { + PDI_AbstractRoot = 0, + PDI_Root, + PDI_Root_sys, + PDI_PID, + PDI_PID_fd, +}; + +enum ProcFileType { + FI_Invalid = 0, + + FI_Root = 1, // directory + + __FI_Root_Start, + FI_Root_mm, + FI_Root_mounts, + FI_Root_kmalloc, + FI_Root_summary, + FI_Root_cpuinfo, + FI_Root_inodes, + FI_Root_dmesg, + FI_Root_self, // symlink + FI_Root_sys, // directory + __FI_Root_End, + + FI_PID, + + __FI_PID_Start, + FI_PID_vm, + FI_PID_vmo, + FI_PID_stack, + FI_PID_regs, + FI_PID_fds, + FI_PID_exe, // symlink + FI_PID_cwd, // symlink + FI_PID_fd, // directory + __FI_PID_End, + + FI_MaxStaticFileIndex, +}; + +static inline pid_t to_pid(const InodeIdentifier& identifier) +{ +#ifdef PROCFS_DEBUG + dbgprintf("to_pid, index=%08x -> %u\n", identifier.index(), identifier.index() >> 16); +#endif + return identifier.index() >> 16u; +} + +static inline ProcParentDirectory to_proc_parent_directory(const InodeIdentifier& identifier) +{ + return (ProcParentDirectory)((identifier.index() >> 12) & 0xf); +} + +static inline int to_fd(const InodeIdentifier& identifier) +{ + ASSERT(to_proc_parent_directory(identifier) == PDI_PID_fd); + return (identifier.index() & 0xff) - FI_MaxStaticFileIndex; +} + +static inline unsigned to_sys_index(const InodeIdentifier& identifier) +{ + ASSERT(to_proc_parent_directory(identifier) == PDI_Root_sys); + return identifier.index() & 0xff; +} + +static inline InodeIdentifier to_identifier(unsigned fsid, ProcParentDirectory parent, pid_t pid, ProcFileType proc_file_type) +{ + return { fsid, ((unsigned)parent << 12u) | ((unsigned)pid << 16u) | (unsigned)proc_file_type }; +} + +static inline InodeIdentifier to_identifier_with_fd(unsigned fsid, pid_t pid, int fd) +{ + return { fsid, (PDI_PID_fd << 12u) | ((unsigned)pid << 16u) | (FI_MaxStaticFileIndex + fd) }; +} + +static inline InodeIdentifier sys_var_to_identifier(unsigned fsid, unsigned index) +{ + ASSERT(index < 256); + return { fsid, (PDI_Root_sys << 12u) | index }; +} + +static inline InodeIdentifier to_parent_id(const InodeIdentifier& identifier) +{ + switch (to_proc_parent_directory(identifier)) { + case PDI_AbstractRoot: + case PDI_Root: + return { identifier.fsid(), FI_Root }; + case PDI_Root_sys: + return { identifier.fsid(), FI_Root_sys }; + case PDI_PID: + return to_identifier(identifier.fsid(), PDI_Root, to_pid(identifier), FI_PID); + case PDI_PID_fd: + return to_identifier(identifier.fsid(), PDI_PID, to_pid(identifier), FI_PID_fd); + } +} + +#if 0 +static inline byte to_unused_metadata(const InodeIdentifier& identifier) +{ + return (identifier.index() >> 8) & 0xf; +} +#endif + +static inline ProcFileType to_proc_file_type(const InodeIdentifier& identifier) +{ + return (ProcFileType)(identifier.index() & 0xff); +} + +static inline bool is_process_related_file(const InodeIdentifier& identifier) +{ + if (to_proc_file_type(identifier) == FI_PID) + return true; + auto proc_parent_directory = to_proc_parent_directory(identifier); + switch (proc_parent_directory) { + case PDI_PID: + case PDI_PID_fd: + return true; + default: + return false; + } +} + +static inline bool is_directory(const InodeIdentifier& identifier) +{ + auto proc_file_type = to_proc_file_type(identifier); + switch (proc_file_type) { + case FI_Root: + case FI_Root_sys: + case FI_PID: + case FI_PID_fd: + return true; + default: + return false; + } +} + +static inline bool is_persistent_inode(const InodeIdentifier& identifier) +{ + return to_proc_parent_directory(identifier) == PDI_Root_sys; +} + +static ProcFS* s_the; + +ProcFS& ProcFS::the() +{ + ASSERT(s_the); + return *s_the; +} + +RetainPtr ProcFS::create() +{ + return adopt(*new ProcFS); +} + +ProcFS::~ProcFS() +{ +} + +ByteBuffer procfs$pid_fds(InodeIdentifier identifier) +{ + auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier)); + if (!handle) + return { }; + auto& process = handle->process(); + if (process.number_of_open_file_descriptors() == 0) + return { }; + StringBuilder builder; + for (size_t i = 0; i < process.max_open_file_descriptors(); ++i) { + auto* descriptor = process.file_descriptor(i); + if (!descriptor) + continue; + builder.appendf("% 3u %s\n", i, descriptor->absolute_path().characters()); + } + return builder.to_byte_buffer(); +} + +ByteBuffer procfs$pid_fd_entry(InodeIdentifier identifier) +{ + auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier)); + if (!handle) + return { }; + auto& process = handle->process(); + int fd = to_fd(identifier); + auto* descriptor = process.file_descriptor(fd); + if (!descriptor) + return { }; + return descriptor->absolute_path().to_byte_buffer(); +} + +ByteBuffer procfs$pid_vm(InodeIdentifier identifier) +{ +#ifdef PROCFS_DEBUG + dbgprintf("pid_vm: pid=%d\n", to_pid(identifier)); +#endif + auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier)); + if (!handle) + return { }; + auto& process = handle->process(); + StringBuilder builder; + builder.appendf("BEGIN END SIZE COMMIT NAME\n"); + for (auto& region : process.regions()) { + builder.appendf("%x -- %x %x %x %s\n", + region->laddr().get(), + region->laddr().offset(region->size() - 1).get(), + region->size(), + region->committed(), + region->name().characters()); + } + return builder.to_byte_buffer(); +} + +ByteBuffer procfs$pid_vmo(InodeIdentifier identifier) +{ + auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier)); + if (!handle) + return { }; + auto& process = handle->process(); + StringBuilder builder; + builder.appendf("BEGIN END SIZE NAME\n"); + for (auto& region : process.regions()) { + builder.appendf("%x -- %x %x %s\n", + region->laddr().get(), + region->laddr().offset(region->size() - 1).get(), + region->size(), + region->name().characters()); + builder.appendf("VMO: %s \"%s\" @ %x(%u)\n", + region->vmo().is_anonymous() ? "anonymous" : "file-backed", + region->vmo().name().characters(), + ®ion->vmo(), + region->vmo().retain_count()); + for (size_t i = 0; i < region->vmo().page_count(); ++i) { + auto& physical_page = region->vmo().physical_pages()[i]; + builder.appendf("P%x%s(%u) ", + physical_page ? physical_page->paddr().get() : 0, + region->cow_map().get(i) ? "!" : "", + physical_page ? physical_page->retain_count() : 0 + ); + } + builder.appendf("\n"); + } + return builder.to_byte_buffer(); +} + +ByteBuffer procfs$pid_stack(InodeIdentifier identifier) +{ + auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier)); + if (!handle) + return { }; + auto& process = handle->process(); + ProcessPagingScope paging_scope(process); + struct RecognizedSymbol { + dword address; + const KSym* ksym; + }; + Vector recognized_symbols; + if (auto* eip_ksym = ksymbolicate(process.tss().eip)) + recognized_symbols.append({ process.tss().eip, eip_ksym }); + for (dword* stack_ptr = (dword*)process.frame_ptr(); process.validate_read_from_kernel(LinearAddress((dword)stack_ptr)); stack_ptr = (dword*)*stack_ptr) { + dword retaddr = stack_ptr[1]; + if (auto* ksym = ksymbolicate(retaddr)) + recognized_symbols.append({ retaddr, ksym }); + } + StringBuilder builder; + for (auto& symbol : recognized_symbols) { + unsigned offset = symbol.address - symbol.ksym->address; + builder.appendf("%p %s +%u\n", symbol.address, symbol.ksym->name, offset); + } + return builder.to_byte_buffer(); +} + +ByteBuffer procfs$pid_regs(InodeIdentifier identifier) +{ + auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier)); + if (!handle) + return { }; + auto& process = handle->process(); + auto& tss = process.tss(); + StringBuilder builder; + builder.appendf("eax: %x\n", tss.eax); + builder.appendf("ebx: %x\n", tss.ebx); + builder.appendf("ecx: %x\n", tss.ecx); + builder.appendf("edx: %x\n", tss.edx); + builder.appendf("esi: %x\n", tss.esi); + builder.appendf("edi: %x\n", tss.edi); + builder.appendf("ebp: %x\n", tss.ebp); + builder.appendf("cr3: %x\n", tss.cr3); + builder.appendf("flg: %x\n", tss.eflags); + builder.appendf("sp: %w:%x\n", tss.ss, tss.esp); + builder.appendf("pc: %w:%x\n", tss.cs, tss.eip); + return builder.to_byte_buffer(); +} + +ByteBuffer procfs$pid_exe(InodeIdentifier identifier) +{ + auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier)); + if (!handle) + return { }; + auto& process = handle->process(); + auto inode = process.executable_inode(); + ASSERT(inode); + return VFS::the().absolute_path(*inode).to_byte_buffer(); +} + +ByteBuffer procfs$pid_cwd(InodeIdentifier identifier) +{ + auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier)); + if (!handle) + return { }; + auto& process = handle->process(); + auto inode = process.cwd_inode(); + ASSERT(inode); + return VFS::the().absolute_path(*inode).to_byte_buffer(); +} + +ByteBuffer procfs$self(InodeIdentifier) +{ + char buffer[16]; + ksprintf(buffer, "%u", current->pid()); + return ByteBuffer::copy((const byte*)buffer, strlen(buffer)); +} + +ByteBuffer procfs$mm(InodeIdentifier) +{ + // FIXME: Implement + InterruptDisabler disabler; + StringBuilder builder; + for (auto* vmo : MM.m_vmos) { + builder.appendf("VMO: %p %s(%u): p:%4u %s\n", + vmo, + vmo->is_anonymous() ? "anon" : "file", + vmo->retain_count(), + vmo->page_count(), + vmo->name().characters()); + } + builder.appendf("VMO count: %u\n", MM.m_vmos.size()); + builder.appendf("Free physical pages: %u\n", MM.m_free_physical_pages.size()); + builder.appendf("Free supervisor physical pages: %u\n", MM.m_free_supervisor_physical_pages.size()); + return builder.to_byte_buffer(); +} + +ByteBuffer procfs$dmesg(InodeIdentifier) +{ + InterruptDisabler disabler; + StringBuilder builder; + for (char ch : Console::the().logbuffer()) + builder.append(ch); + return builder.to_byte_buffer(); +} + +ByteBuffer procfs$mounts(InodeIdentifier) +{ + // FIXME: This is obviously racy against the VFS mounts changing. + StringBuilder builder; + VFS::the().for_each_mount([&builder] (auto& mount) { + auto& fs = mount.guest_fs(); + builder.appendf("%s @ ", fs.class_name()); + if (!mount.host().is_valid()) + builder.appendf("/"); + else { + builder.appendf("%u:%u", mount.host().fsid(), mount.host().index()); + auto path = VFS::the().absolute_path(mount.host()); + builder.append(' '); + builder.append(path); + } + builder.append('\n'); + }); + return builder.to_byte_buffer(); +} + +ByteBuffer procfs$cpuinfo(InodeIdentifier) +{ + StringBuilder builder; + { + CPUID cpuid(0); + builder.appendf("cpuid: "); + auto emit_dword = [&] (dword value) { + builder.appendf("%c%c%c%c", + value & 0xff, + (value >> 8) & 0xff, + (value >> 16) & 0xff, + (value >> 24) & 0xff); + }; + emit_dword(cpuid.ebx()); + emit_dword(cpuid.edx()); + emit_dword(cpuid.ecx()); + builder.appendf("\n"); + } + { + CPUID cpuid(1); + dword stepping = cpuid.eax() & 0xf; + dword model = (cpuid.eax() >> 4) & 0xf; + dword family = (cpuid.eax() >> 8) & 0xf; + dword type = (cpuid.eax() >> 12) & 0x3; + dword extended_model = (cpuid.eax() >> 16) & 0xf; + dword extended_family = (cpuid.eax() >> 20) & 0xff; + dword display_model; + dword display_family; + if (family == 15) { + display_family = family + extended_family; + display_model = model + (extended_model << 4); + } else if (family == 6) { + display_family = family; + display_model = model + (extended_model << 4); + } else { + display_family = family; + display_model = model; + } + builder.appendf("family: %u\n", display_family); + builder.appendf("model: %u\n", display_model); + builder.appendf("stepping: %u\n", stepping); + builder.appendf("type: %u\n", type); + } + { + // FIXME: Check first that this is supported by calling CPUID with eax=0x80000000 + // and verifying that the returned eax>=0x80000004. + char buffer[48]; + dword* bufptr = reinterpret_cast(buffer); + auto copy_brand_string_part_to_buffer = [&] (dword i) { + CPUID cpuid(0x80000002 + i); + *bufptr++ = cpuid.eax(); + *bufptr++ = cpuid.ebx(); + *bufptr++ = cpuid.ecx(); + *bufptr++ = cpuid.edx(); + }; + copy_brand_string_part_to_buffer(0); + copy_brand_string_part_to_buffer(1); + copy_brand_string_part_to_buffer(2); + builder.appendf("brandstr: \"%s\"\n", buffer); + } + return builder.to_byte_buffer(); +} + +ByteBuffer procfs$kmalloc(InodeIdentifier) +{ + StringBuilder builder; + builder.appendf( + "eternal: %u\n" + "allocated: %u\n" + "free: %u\n", + kmalloc_sum_eternal, + sum_alloc, + sum_free + ); + return builder.to_byte_buffer(); +} + +ByteBuffer procfs$summary(InodeIdentifier) +{ + InterruptDisabler disabler; + auto processes = Process::all_processes(); + StringBuilder builder; + builder.appendf("PID TPG PGP SID OWNER STATE PPID NSCHED FDS TTY NAME\n"); + for (auto* process : processes) { + builder.appendf("% 3u % 3u % 3u % 3u % 4u % 8s % 3u % 9u % 3u % 4s %s\n", + process->pid(), + process->tty() ? process->tty()->pgid() : 0, + process->pgid(), + process->sid(), + process->uid(), + to_string(process->state()), + process->ppid(), + process->times_scheduled(), + process->number_of_open_file_descriptors(), + process->tty() ? strrchr(process->tty()->tty_name().characters(), '/') + 1 : "n/a", + process->name().characters()); + } + return builder.to_byte_buffer(); +} + +ByteBuffer procfs$inodes(InodeIdentifier) +{ + extern HashTable& all_inodes(); + auto& vfs = VFS::the(); + StringBuilder builder; + for (auto it : all_inodes()) { + RetainPtr inode = *it; + String path = vfs.absolute_path(*inode); + builder.appendf("Inode{K%x} %02u:%08u (%u) %s\n", inode.ptr(), inode->fsid(), inode->index(), inode->retain_count(), path.characters()); + } + return builder.to_byte_buffer(); +} + +struct SysVariableData final : public ProcFSInodeCustomData { + virtual ~SysVariableData() override { } + + enum Type { + Invalid, + Boolean, + }; + Type type { Invalid }; + Function notify_callback; + void* address; +}; + +static ByteBuffer read_sys_bool(InodeIdentifier inode_id) +{ + auto inode_ptr = ProcFS::the().get_inode(inode_id); + if (!inode_ptr) + return { }; + auto& inode = static_cast(*inode_ptr); + ASSERT(inode.custom_data()); + auto buffer = ByteBuffer::create_uninitialized(2); + auto& custom_data = *static_cast(inode.custom_data()); + ASSERT(custom_data.type == SysVariableData::Boolean); + ASSERT(custom_data.address); + buffer[0] = *reinterpret_cast(custom_data.address) ? '1' : '0'; + buffer[1] = '\n'; + return buffer; +} + +static ssize_t write_sys_bool(InodeIdentifier inode_id, const ByteBuffer& data) +{ + auto inode_ptr = ProcFS::the().get_inode(inode_id); + if (!inode_ptr) + return { }; + auto& inode = static_cast(*inode_ptr); + ASSERT(inode.custom_data()); + if (data.size() >= 1 && (data[0] == '0' || data[0] == '1')) { + auto& custom_data = *static_cast(inode.custom_data()); + ASSERT(custom_data.address); + bool new_value = data[0] == '1'; + *reinterpret_cast(custom_data.address) = new_value; + if (custom_data.notify_callback) + custom_data.notify_callback(); + } + return data.size(); +} + +void ProcFS::add_sys_bool(String&& name, bool* var, Function&& notify_callback) +{ + InterruptDisabler disabler; + + unsigned index = m_sys_entries.size(); + auto inode = adopt(*new ProcFSInode(*this, sys_var_to_identifier(fsid(), index).index())); + auto data = make(); + data->type = SysVariableData::Boolean; + data->notify_callback = move(notify_callback); + data->address = var; + inode->set_custom_data(move(data)); + m_sys_entries.append({ strdup(name.characters()), name.length(), read_sys_bool, write_sys_bool, move(inode) }); +} + +bool ProcFS::initialize() +{ + return true; +} + +const char* ProcFS::class_name() const +{ + return "ProcFS"; +} + +RetainPtr ProcFS::create_inode(InodeIdentifier parentInode, const String& name, mode_t mode, unsigned size, int& error) +{ + (void) parentInode; + (void) name; + (void) mode; + (void) size; + (void) error; + kprintf("FIXME: Implement ProcFS::create_inode()?\n"); + return { }; +} + +RetainPtr ProcFS::create_directory(InodeIdentifier, const String&, mode_t, int& error) +{ + error = -EROFS; + return nullptr; +} + +RetainPtr ProcFSInode::parent() const +{ + return fs().get_inode(to_parent_id(identifier())); +} + +InodeIdentifier ProcFS::root_inode() const +{ + return { fsid(), FI_Root }; +} + +RetainPtr ProcFS::get_inode(InodeIdentifier inode_id) const +{ +#ifdef PROCFS_DEBUG + dbgprintf("ProcFS::get_inode(%u)\n", inode_id.index()); +#endif + if (inode_id == root_inode()) + return m_root_inode; + + if (to_proc_parent_directory(inode_id) == ProcParentDirectory::PDI_Root_sys) { + auto sys_index = to_sys_index(inode_id); + if (sys_index < m_sys_entries.size()) + return m_sys_entries[sys_index].inode; + } + + LOCKER(m_inodes_lock); + auto it = m_inodes.find(inode_id.index()); + if (it == m_inodes.end()) { + auto inode = adopt(*new ProcFSInode(const_cast(*this), inode_id.index())); + m_inodes.set(inode_id.index(), inode.ptr()); + return inode; + } + return (*it).value; +} + +ProcFSInode::ProcFSInode(ProcFS& fs, unsigned index) + : Inode(fs, index) +{ +} + +ProcFSInode::~ProcFSInode() +{ + LOCKER(fs().m_inodes_lock); + fs().m_inodes.remove(index()); +} + +InodeMetadata ProcFSInode::metadata() const +{ +#ifdef PROCFS_DEBUG + dbgprintf("ProcFSInode::metadata(%u)\n", index()); +#endif + InodeMetadata metadata; + metadata.inode = identifier(); + metadata.ctime = mepoch; + metadata.atime = mepoch; + metadata.mtime = mepoch; + auto proc_parent_directory = to_proc_parent_directory(identifier()); + auto pid = to_pid(identifier()); + auto proc_file_type = to_proc_file_type(identifier()); + +#ifdef PROCFS_DEBUG + dbgprintf(" -> pid: %d, fi: %u, pdi: %u\n", pid, proc_file_type, proc_parent_directory); +#endif + + if (is_process_related_file(identifier())) { + auto handle = ProcessInspectionHandle::from_pid(pid); + metadata.uid = handle->process().sys$getuid(); + metadata.gid = handle->process().sys$getgid(); + } + + if (proc_parent_directory == PDI_PID_fd) { + metadata.mode = 00120777; + return metadata; + } + + switch (proc_file_type) { + case FI_Root_self: + case FI_PID_cwd: + case FI_PID_exe: + metadata.mode = 0120777; + break; + case FI_Root: + case FI_Root_sys: + case FI_PID: + case FI_PID_fd: + metadata.mode = 040777; + break; + default: + metadata.mode = 0100644; + break; + } +#ifdef PROCFS_DEBUG + dbgprintf("Returning mode %o\n", metadata.mode); +#endif + return metadata; +} + +ssize_t ProcFSInode::read_bytes(off_t offset, size_t count, byte* buffer, FileDescriptor* descriptor) const +{ +#ifdef PROCFS_DEBUG + dbgprintf("ProcFS: read_bytes %u\n", index()); +#endif + ASSERT(offset >= 0); + ASSERT(buffer); + + auto* directory_entry = fs().get_directory_entry(identifier()); + + Function callback_tmp; + Function* read_callback { nullptr }; + if (directory_entry) { + read_callback = &directory_entry->read_callback; + } else { + if (to_proc_parent_directory(identifier()) == PDI_PID_fd) { + callback_tmp = procfs$pid_fd_entry; + read_callback = &callback_tmp; + } + } + + ASSERT(read_callback); + + ByteBuffer generated_data; + if (!descriptor) { + generated_data = (*read_callback)(identifier()); + } else { + if (!descriptor->generator_cache()) + descriptor->generator_cache() = (*read_callback)(identifier()); + generated_data = descriptor->generator_cache(); + } + + auto& data = generated_data; + ssize_t nread = min(static_cast(data.size() - offset), static_cast(count)); + memcpy(buffer, data.pointer() + offset, nread); + if (nread == 0 && descriptor && descriptor->generator_cache()) + descriptor->generator_cache().clear(); + return nread; +} + +InodeIdentifier ProcFS::ProcFSDirectoryEntry::identifier(unsigned fsid) const +{ + return to_identifier(fsid, PDI_Root, 0, (ProcFileType)proc_file_type); +} + +bool ProcFSInode::traverse_as_directory(Function callback) const +{ +#ifdef PROCFS_DEBUG + dbgprintf("ProcFS: traverse_as_directory %u\n", index()); +#endif + + if (!::is_directory(identifier())) + return false; + + auto pid = to_pid(identifier()); + auto proc_file_type = to_proc_file_type(identifier()); + auto parent_id = to_parent_id(identifier()); + + callback({ ".", 1, identifier(), 2 }); + callback({ "..", 2, parent_id, 2 }); + + switch (proc_file_type) { + case FI_Root: + for (auto& entry : fs().m_entries) { + // FIXME: strlen() here is sad. + if (!entry.name) + continue; + if (entry.proc_file_type > __FI_Root_Start && entry.proc_file_type < __FI_Root_End) + callback({ entry.name, strlen(entry.name), to_identifier(fsid(), PDI_Root, 0, (ProcFileType)entry.proc_file_type), 0 }); + } + for (auto pid_child : Process::all_pids()) { + char name[16]; + size_t name_length = ksprintf(name, "%u", pid_child); + callback({ name, name_length, to_identifier(fsid(), PDI_Root, pid_child, FI_PID), 0 }); + } + break; + + case FI_Root_sys: + for (size_t i = 0; i < fs().m_sys_entries.size(); ++i) { + auto& entry = fs().m_sys_entries[i]; + callback({ entry.name, strlen(entry.name), sys_var_to_identifier(fsid(), i), 0 }); + } + break; + + case FI_PID: { + auto handle = ProcessInspectionHandle::from_pid(pid); + if (!handle) + return false; + auto& process = handle->process(); + for (auto& entry : fs().m_entries) { + if (entry.proc_file_type > __FI_PID_Start && entry.proc_file_type < __FI_PID_End) { + if (entry.proc_file_type == FI_PID_exe || entry.proc_file_type == FI_PID_cwd) { + if (entry.proc_file_type == FI_PID_exe && !process.executable_inode()) + continue; + if (entry.proc_file_type == FI_PID_cwd && !process.cwd_inode()) + continue; + } + // FIXME: strlen() here is sad. + callback({ entry.name, strlen(entry.name), to_identifier(fsid(), PDI_PID, pid, (ProcFileType)entry.proc_file_type), 0 }); + } + } + } + break; + + case FI_PID_fd: { + auto handle = ProcessInspectionHandle::from_pid(pid); + if (!handle) + return false; + auto& process = handle->process(); + for (size_t i = 0; i < process.max_open_file_descriptors(); ++i) { + auto* descriptor = process.file_descriptor(i); + if (!descriptor) + continue; + char name[16]; + size_t name_length = ksprintf(name, "%u", i); + callback({ name, name_length, to_identifier_with_fd(fsid(), pid, i), 0 }); + } + } + break; + default: + return true; + } + + return true; +} + +InodeIdentifier ProcFSInode::lookup(const String& name) +{ + ASSERT(is_directory()); + if (name == ".") + return identifier(); + if (name == "..") + return to_parent_id(identifier()); + + auto proc_file_type = to_proc_file_type(identifier()); + + if (proc_file_type == FI_Root) { + for (auto& entry : fs().m_entries) { + if (entry.name == nullptr) + continue; + if (entry.proc_file_type > __FI_Root_Start && entry.proc_file_type < __FI_Root_End) { + if (!strcmp(entry.name, name.characters())) { + return to_identifier(fsid(), PDI_Root, 0, (ProcFileType)entry.proc_file_type); + } + } + } + bool ok; + unsigned name_as_number = name.to_uint(ok); + if (ok) { + bool process_exists = false; + { + InterruptDisabler disabler; + process_exists = Process::from_pid(name_as_number); + } + if (process_exists) + return to_identifier(fsid(), PDI_Root, name_as_number, FI_PID); + } + return { }; + } + + if (proc_file_type == FI_Root_sys) { + for (size_t i = 0; i < fs().m_sys_entries.size(); ++i) { + auto& entry = fs().m_sys_entries[i]; + if (!strcmp(entry.name, name.characters())) + return sys_var_to_identifier(fsid(), i); + } + return { }; + } + + if (proc_file_type == FI_PID) { + auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier())); + if (!handle) + return { }; + auto& process = handle->process(); + for (auto& entry : fs().m_entries) { + if (entry.proc_file_type > __FI_PID_Start && entry.proc_file_type < __FI_PID_End) { + if (entry.proc_file_type == FI_PID_exe || entry.proc_file_type == FI_PID_cwd) { + if (entry.proc_file_type == FI_PID_exe && !process.executable_inode()) + continue; + if (entry.proc_file_type == FI_PID_cwd && !process.cwd_inode()) + continue; + } + if (entry.name == nullptr) + continue; + if (!strcmp(entry.name, name.characters())) { + return to_identifier(fsid(), PDI_PID, to_pid(identifier()), (ProcFileType)entry.proc_file_type); + } + } + } + return { }; + } + + if (proc_file_type == FI_PID_fd) { + bool ok; + unsigned name_as_number = name.to_uint(ok); + if (ok) { + bool fd_exists = false; + { + InterruptDisabler disabler; + if (auto* process = Process::from_pid(to_pid(identifier()))) + fd_exists = process->file_descriptor(name_as_number); + + } + if (fd_exists) + return to_identifier_with_fd(fsid(), to_pid(identifier()), name_as_number); + } + } + return { }; +} + +String ProcFSInode::reverse_lookup(InodeIdentifier child_id) +{ + ASSERT(is_directory()); + auto proc_file_type = to_proc_file_type(identifier()); + if (proc_file_type == FI_Root) { + for (auto& entry : fs().m_entries) { + if (child_id == to_identifier(fsid(), PDI_Root, 0, (ProcFileType)entry.proc_file_type)) { + return entry.name; + } + } + auto child_proc_file_type = to_proc_file_type(child_id); + if (child_proc_file_type == FI_PID) + return String::format("%u", to_pid(child_id)); + return { }; + } + // FIXME: Implement + ASSERT_NOT_REACHED(); + return { }; +} + +void ProcFSInode::flush_metadata() +{ +} + +ssize_t ProcFSInode::write_bytes(off_t offset, size_t size, const byte* buffer, FileDescriptor*) +{ + auto* directory_entry = fs().get_directory_entry(identifier()); + if (!directory_entry || !directory_entry->write_callback) + return -EPERM; + ASSERT(is_persistent_inode(identifier())); + // FIXME: Being able to write into ProcFS at a non-zero offset seems like something we should maybe support.. + ASSERT(offset == 0); + bool success = directory_entry->write_callback(identifier(), ByteBuffer::wrap((byte*)buffer, size)); + ASSERT(success); + return 0; +} + +bool ProcFSInode::add_child(InodeIdentifier child_id, const String& name, byte file_type, int& error) +{ + (void) child_id; + (void) name; + (void) file_type; + (void) error; + ASSERT_NOT_REACHED(); + return false; +} + +bool ProcFSInode::remove_child(const String& name, int& error) +{ + (void) name; + (void) error; + ASSERT_NOT_REACHED(); + return false; +} + +ProcFSInodeCustomData::~ProcFSInodeCustomData() +{ +} + +size_t ProcFSInode::directory_entry_count() const +{ + ASSERT(is_directory()); + size_t count = 0; + traverse_as_directory([&count] (const FS::DirectoryEntry&) { + ++count; + return true; + }); + return count; +} + +bool ProcFSInode::chmod(mode_t, int& error) +{ + error = -EPERM; + return false; +} + +ProcFS::ProcFS() +{ + s_the = this; + m_root_inode = adopt(*new ProcFSInode(*this, 1)); + m_entries.resize(FI_MaxStaticFileIndex); + m_entries[FI_Root_mm] = { "mm", FI_Root_mm, procfs$mm }; + m_entries[FI_Root_mounts] = { "mounts", FI_Root_mounts, procfs$mounts }; + m_entries[FI_Root_kmalloc] = { "kmalloc", FI_Root_kmalloc, procfs$kmalloc }; + m_entries[FI_Root_summary] = { "summary", FI_Root_summary, procfs$summary }; + m_entries[FI_Root_cpuinfo] = { "cpuinfo", FI_Root_summary, procfs$cpuinfo}; + m_entries[FI_Root_inodes] = { "inodes", FI_Root_inodes, procfs$inodes }; + m_entries[FI_Root_dmesg] = { "dmesg", FI_Root_dmesg, procfs$dmesg }; + m_entries[FI_Root_self] = { "self", FI_Root_self, procfs$self }; + m_entries[FI_Root_sys] = { "sys", FI_Root_sys }; + + m_entries[FI_PID_vm] = { "vm", FI_PID_vm, procfs$pid_vm }; + m_entries[FI_PID_vmo] = { "vmo", FI_PID_vmo, procfs$pid_vmo }; + m_entries[FI_PID_stack] = { "stack", FI_PID_stack, procfs$pid_stack }; + m_entries[FI_PID_regs] = { "regs", FI_PID_regs, procfs$pid_regs }; + m_entries[FI_PID_fds] = { "fds", FI_PID_fds, procfs$pid_fds }; + m_entries[FI_PID_exe] = { "exe", FI_PID_exe, procfs$pid_exe }; + m_entries[FI_PID_cwd] = { "cwd", FI_PID_cwd, procfs$pid_cwd }; + m_entries[FI_PID_fd] = { "fd", FI_PID_fd }; +} + +ProcFS::ProcFSDirectoryEntry* ProcFS::get_directory_entry(InodeIdentifier identifier) const +{ + if (to_proc_parent_directory(identifier) == PDI_Root_sys) { + auto sys_index = to_sys_index(identifier); + if (sys_index < m_sys_entries.size()) + return const_cast(&m_sys_entries[sys_index]); + return nullptr; + } + auto proc_file_type = to_proc_file_type(identifier); + if (proc_file_type != FI_Invalid && proc_file_type < FI_MaxStaticFileIndex) + return const_cast(&m_entries[proc_file_type]); + return nullptr; +} diff --git a/Kernel/ProcFS.h b/Kernel/ProcFS.h new file mode 100644 index 0000000000..a856bcbf7a --- /dev/null +++ b/Kernel/ProcFS.h @@ -0,0 +1,96 @@ +#pragma once + +#include +#include +#include + +class Process; + +class ProcFSInode; + +class ProcFS final : public FS { + friend class ProcFSInode; +public: + static ProcFS& the() PURE; + + virtual ~ProcFS() override; + static RetainPtr create(); + + virtual bool initialize() override; + virtual const char* class_name() const override; + + virtual InodeIdentifier root_inode() const override; + virtual RetainPtr get_inode(InodeIdentifier) const override; + + virtual RetainPtr create_inode(InodeIdentifier parent_id, const String& name, mode_t, unsigned size, int& error) override; + virtual RetainPtr create_directory(InodeIdentifier parent_id, const String& name, mode_t, int& error) override; + + void add_sys_file(String&&, Function&& read_callback, Function&& write_callback); + void add_sys_bool(String&&, bool*, Function&& notify_callback = nullptr); + +private: + ProcFS(); + + struct ProcFSDirectoryEntry { + ProcFSDirectoryEntry() { } + ProcFSDirectoryEntry(const char* a_name, unsigned a_proc_file_type, Function&& a_read_callback = nullptr, Function&& a_write_callback = nullptr, RetainPtr&& a_inode = nullptr) + : name(a_name) + , proc_file_type(a_proc_file_type) + , read_callback(move(a_read_callback)) + , write_callback(move(a_write_callback)) + , inode(move(a_inode)) + { + } + + const char* name { nullptr }; + unsigned proc_file_type { 0 }; + Function read_callback; + Function write_callback; + RetainPtr inode; + InodeIdentifier identifier(unsigned fsid) const; + }; + + ProcFSDirectoryEntry* get_directory_entry(InodeIdentifier) const; + + Vector m_entries; + Vector m_sys_entries; + + mutable Lock m_inodes_lock; + mutable HashMap m_inodes; + RetainPtr m_root_inode; +}; + +struct ProcFSInodeCustomData { + virtual ~ProcFSInodeCustomData(); +}; + +class ProcFSInode final : public Inode { + friend class ProcFS; +public: + virtual ~ProcFSInode() override; + + void set_custom_data(OwnPtr&& custom_data) { m_custom_data = move(custom_data); } + ProcFSInodeCustomData* custom_data() { return m_custom_data.ptr(); } + const ProcFSInodeCustomData* custom_data() const { return m_custom_data.ptr(); } + +private: + // ^Inode + virtual ssize_t read_bytes(off_t, size_t, byte* buffer, FileDescriptor*) const override; + virtual InodeMetadata metadata() const override; + virtual bool traverse_as_directory(Function) const override; + virtual InodeIdentifier lookup(const String& name) override; + virtual String reverse_lookup(InodeIdentifier) override; + virtual void flush_metadata() override; + virtual ssize_t write_bytes(off_t, size_t, const byte* buffer, FileDescriptor*) override; + virtual bool add_child(InodeIdentifier child_id, const String& name, byte file_type, int& error) override; + virtual bool remove_child(const String& name, int& error) override; + virtual RetainPtr parent() const override; + virtual size_t directory_entry_count() const override; + virtual bool chmod(mode_t, int& error) override; + + ProcFS& fs() { return static_cast(Inode::fs()); } + const ProcFS& fs() const { return static_cast(Inode::fs()); } + ProcFSInode(ProcFS&, unsigned index); + + OwnPtr m_custom_data; +}; diff --git a/Kernel/ProcFileSystem.cpp b/Kernel/ProcFileSystem.cpp deleted file mode 100644 index 5db983fc29..0000000000 --- a/Kernel/ProcFileSystem.cpp +++ /dev/null @@ -1,418 +0,0 @@ -#include "ProcFileSystem.h" -#include "Process.h" -#include -#include "system.h" -#include "MemoryManager.h" -#include "StdLib.h" -#include "i386.h" -#include "KSyms.h" -#include "Console.h" -#include - -static ProcFS* s_the; - -ProcFS& ProcFS::the() -{ - ASSERT(s_the); - return *s_the; -} - -RetainPtr ProcFS::create() -{ - return adopt(*new ProcFS); -} - -ProcFS::ProcFS() -{ - s_the = this; -} - -ProcFS::~ProcFS() -{ -} - -ByteBuffer procfs$pid_fds(Process& process) -{ - ProcessInspectionHandle handle(process); - if (process.number_of_open_file_descriptors() == 0) - return { }; - StringBuilder builder; - for (size_t i = 0; i < process.max_open_file_descriptors(); ++i) { - auto* descriptor = process.file_descriptor(i); - if (!descriptor) - continue; - builder.appendf("% 3u %s\n", i, descriptor->absolute_path().characters()); - } - return builder.to_byte_buffer(); -} - -ByteBuffer procfs$pid_vm(Process& process) -{ - ProcessInspectionHandle handle(process); - StringBuilder builder; - builder.appendf("BEGIN END SIZE COMMIT NAME\n"); - for (auto& region : process.regions()) { - builder.appendf("%x -- %x %x %x %s\n", - region->laddr().get(), - region->laddr().offset(region->size() - 1).get(), - region->size(), - region->committed(), - region->name().characters()); - } - return builder.to_byte_buffer(); -} - -ByteBuffer procfs$pid_vmo(Process& process) -{ - ProcessInspectionHandle handle(process); - StringBuilder builder; - builder.appendf("BEGIN END SIZE NAME\n"); - for (auto& region : process.regions()) { - builder.appendf("%x -- %x %x %s\n", - region->laddr().get(), - region->laddr().offset(region->size() - 1).get(), - region->size(), - region->name().characters()); - builder.appendf("VMO: %s \"%s\" @ %x(%u)\n", - region->vmo().is_anonymous() ? "anonymous" : "file-backed", - region->vmo().name().characters(), - ®ion->vmo(), - region->vmo().retain_count()); - for (size_t i = 0; i < region->vmo().page_count(); ++i) { - auto& physical_page = region->vmo().physical_pages()[i]; - builder.appendf("P%x%s(%u) ", - physical_page ? physical_page->paddr().get() : 0, - region->cow_map().get(i) ? "!" : "", - physical_page ? physical_page->retain_count() : 0 - ); - } - builder.appendf("\n"); - } - return builder.to_byte_buffer(); -} - -ByteBuffer procfs$pid_stack(Process& process) -{ - ProcessInspectionHandle handle(process); - ProcessPagingScope paging_scope(process); - struct RecognizedSymbol { - dword address; - const KSym* ksym; - }; - Vector recognized_symbols; - if (auto* eip_ksym = ksymbolicate(process.tss().eip)) - recognized_symbols.append({ process.tss().eip, eip_ksym }); - for (dword* stack_ptr = (dword*)process.frame_ptr(); process.validate_read_from_kernel(LinearAddress((dword)stack_ptr)); stack_ptr = (dword*)*stack_ptr) { - dword retaddr = stack_ptr[1]; - if (auto* ksym = ksymbolicate(retaddr)) - recognized_symbols.append({ retaddr, ksym }); - } - StringBuilder builder; - for (auto& symbol : recognized_symbols) { - unsigned offset = symbol.address - symbol.ksym->address; - builder.appendf("%p %s +%u\n", symbol.address, symbol.ksym->name, offset); - } - return builder.to_byte_buffer(); -} - -ByteBuffer procfs$pid_regs(Process& process) -{ - ProcessInspectionHandle handle(process); - auto& tss = process.tss(); - StringBuilder builder; - builder.appendf("eax: %x\n", tss.eax); - builder.appendf("ebx: %x\n", tss.ebx); - builder.appendf("ecx: %x\n", tss.ecx); - builder.appendf("edx: %x\n", tss.edx); - builder.appendf("esi: %x\n", tss.esi); - builder.appendf("edi: %x\n", tss.edi); - builder.appendf("ebp: %x\n", tss.ebp); - builder.appendf("cr3: %x\n", tss.cr3); - builder.appendf("flg: %x\n", tss.eflags); - builder.appendf("sp: %w:%x\n", tss.ss, tss.esp); - builder.appendf("pc: %w:%x\n", tss.cs, tss.eip); - return builder.to_byte_buffer(); -} - -ByteBuffer procfs$pid_exe(Process& process) -{ - ProcessInspectionHandle handle(process); - auto inode = process.executable_inode(); - ASSERT(inode); - return VFS::the().absolute_path(*inode).to_byte_buffer(); -} - -ByteBuffer procfs$pid_cwd(Process& process) -{ - ProcessInspectionHandle handle(process); - auto inode = process.cwd_inode(); - ASSERT(inode); - return VFS::the().absolute_path(*inode).to_byte_buffer(); -} - -ByteBuffer procfs$self(SynthFSInode&) -{ - char buffer[16]; - ksprintf(buffer, "%u", current->pid()); - return ByteBuffer::copy((const byte*)buffer, strlen(buffer)); -} - -void ProcFS::add_process(Process& process) -{ - InterruptDisabler disabler; - auto dir = add_file(create_directory(String::format("%d", process.pid()))); - m_pid2inode.set(process.pid(), dir.index()); - add_file(create_generated_file("vm", [&process] (SynthFSInode&) { return procfs$pid_vm(process); }), dir.index()); - add_file(create_generated_file("vmo", [&process] (SynthFSInode&) { return procfs$pid_vmo(process); }), dir.index()); - add_file(create_generated_file("stack", [&process] (SynthFSInode&) { return procfs$pid_stack(process); }), dir.index()); - add_file(create_generated_file("regs", [&process] (SynthFSInode&) { return procfs$pid_regs(process); }), dir.index()); - add_file(create_generated_file("fds", [&process] (SynthFSInode&) { return procfs$pid_fds(process); }), dir.index()); - if (process.executable_inode()) - add_file(create_generated_file("exe", [&process] (SynthFSInode&) { return procfs$pid_exe(process); }, 00120777), dir.index()); - if (process.cwd_inode()) - add_file(create_generated_file("cwd", [&process] (SynthFSInode&) { return procfs$pid_cwd(process); }, 00120777), dir.index()); -} - -void ProcFS::remove_process(Process& process) -{ - InterruptDisabler disabler; - auto pid = process.pid(); - auto it = m_pid2inode.find(pid); - if (it == m_pid2inode.end()) - return; - bool success = remove_file((*it).value); - ASSERT(success); - m_pid2inode.remove(pid); -} - -ByteBuffer procfs$mm(SynthFSInode&) -{ - // FIXME: Implement - InterruptDisabler disabler; - StringBuilder builder; - for (auto* vmo : MM.m_vmos) { - builder.appendf("VMO: %p %s(%u): p:%4u %s\n", - vmo, - vmo->is_anonymous() ? "anon" : "file", - vmo->retain_count(), - vmo->page_count(), - vmo->name().characters()); - } - builder.appendf("VMO count: %u\n", MM.m_vmos.size()); - builder.appendf("Free physical pages: %u\n", MM.m_free_physical_pages.size()); - builder.appendf("Free supervisor physical pages: %u\n", MM.m_free_supervisor_physical_pages.size()); - return builder.to_byte_buffer(); -} - -ByteBuffer procfs$dmesg(SynthFSInode&) -{ - InterruptDisabler disabler; - StringBuilder builder; - for (char ch : Console::the().logbuffer()) - builder.append(ch); - return builder.to_byte_buffer(); -} - -ByteBuffer procfs$mounts(SynthFSInode&) -{ - // FIXME: This is obviously racy against the VFS mounts changing. - StringBuilder builder; - VFS::the().for_each_mount([&builder] (auto& mount) { - auto& fs = mount.guest_fs(); - builder.appendf("%s @ ", fs.class_name()); - if (!mount.host().is_valid()) - builder.appendf("/"); - else { - builder.appendf("%u:%u", mount.host().fsid(), mount.host().index()); - auto path = VFS::the().absolute_path(mount.host()); - builder.append(' '); - builder.append(path); - } - builder.append('\n'); - }); - return builder.to_byte_buffer(); -} - -ByteBuffer procfs$cpuinfo(SynthFSInode&) -{ - StringBuilder builder; - { - CPUID cpuid(0); - builder.appendf("cpuid: "); - auto emit_dword = [&] (dword value) { - builder.appendf("%c%c%c%c", - value & 0xff, - (value >> 8) & 0xff, - (value >> 16) & 0xff, - (value >> 24) & 0xff); - }; - emit_dword(cpuid.ebx()); - emit_dword(cpuid.edx()); - emit_dword(cpuid.ecx()); - builder.appendf("\n"); - } - { - CPUID cpuid(1); - dword stepping = cpuid.eax() & 0xf; - dword model = (cpuid.eax() >> 4) & 0xf; - dword family = (cpuid.eax() >> 8) & 0xf; - dword type = (cpuid.eax() >> 12) & 0x3; - dword extended_model = (cpuid.eax() >> 16) & 0xf; - dword extended_family = (cpuid.eax() >> 20) & 0xff; - dword display_model; - dword display_family; - if (family == 15) { - display_family = family + extended_family; - display_model = model + (extended_model << 4); - } else if (family == 6) { - display_family = family; - display_model = model + (extended_model << 4); - } else { - display_family = family; - display_model = model; - } - builder.appendf("family: %u\n", display_family); - builder.appendf("model: %u\n", display_model); - builder.appendf("stepping: %u\n", stepping); - builder.appendf("type: %u\n", type); - } - { - // FIXME: Check first that this is supported by calling CPUID with eax=0x80000000 - // and verifying that the returned eax>=0x80000004. - char buffer[48]; - dword* bufptr = reinterpret_cast(buffer); - auto copy_brand_string_part_to_buffer = [&] (dword i) { - CPUID cpuid(0x80000002 + i); - *bufptr++ = cpuid.eax(); - *bufptr++ = cpuid.ebx(); - *bufptr++ = cpuid.ecx(); - *bufptr++ = cpuid.edx(); - }; - copy_brand_string_part_to_buffer(0); - copy_brand_string_part_to_buffer(1); - copy_brand_string_part_to_buffer(2); - builder.appendf("brandstr: \"%s\"\n", buffer); - } - return builder.to_byte_buffer(); -} - -ByteBuffer procfs$kmalloc(SynthFSInode&) -{ - StringBuilder builder; - builder.appendf( - "eternal: %u\n" - "allocated: %u\n" - "free: %u\n", - kmalloc_sum_eternal, - sum_alloc, - sum_free - ); - return builder.to_byte_buffer(); -} - -ByteBuffer procfs$summary(SynthFSInode&) -{ - InterruptDisabler disabler; - auto processes = Process::all_processes(); - StringBuilder builder; - builder.appendf("PID TPG PGP SID OWNER STATE PPID NSCHED FDS TTY NAME\n"); - for (auto* process : processes) { - builder.appendf("% 3u % 3u % 3u % 3u % 4u % 8s % 3u % 9u % 3u % 4s %s\n", - process->pid(), - process->tty() ? process->tty()->pgid() : 0, - process->pgid(), - process->sid(), - process->uid(), - to_string(process->state()), - process->ppid(), - process->times_scheduled(), - process->number_of_open_file_descriptors(), - process->tty() ? strrchr(process->tty()->tty_name().characters(), '/') + 1 : "n/a", - process->name().characters()); - } - return builder.to_byte_buffer(); -} - -ByteBuffer procfs$inodes(SynthFSInode&) -{ - extern HashTable& all_inodes(); - auto& vfs = VFS::the(); - StringBuilder builder; - for (auto it : all_inodes()) { - RetainPtr inode = *it; - String path = vfs.absolute_path(*inode); - builder.appendf("Inode{K%x} %02u:%08u (%u) %s\n", inode.ptr(), inode->fsid(), inode->index(), inode->retain_count(), path.characters()); - } - return builder.to_byte_buffer(); -} - -struct SysVariableData final : public SynthFSInodeCustomData { - virtual ~SysVariableData() override { } - - enum Type { - Invalid, - Boolean, - }; - Type type { Invalid }; - Function change_callback; - void* address; -}; - -static ByteBuffer read_sys_bool(SynthFSInode& inode) -{ - ASSERT(inode.custom_data()); - auto buffer = ByteBuffer::create_uninitialized(2); - auto& custom_data = *static_cast(inode.custom_data()); - ASSERT(custom_data.type == SysVariableData::Boolean); - ASSERT(custom_data.address); - buffer[0] = *reinterpret_cast(custom_data.address) ? '1' : '0'; - buffer[1] = '\n'; - return buffer; -} - -static ssize_t write_sys_bool(SynthFSInode& inode, const ByteBuffer& data) -{ - ASSERT(inode.custom_data()); - if (data.size() >= 1 && (data[0] == '0' || data[0] == '1')) { - auto& custom_data = *static_cast(inode.custom_data()); - ASSERT(custom_data.address); - bool old_value = *reinterpret_cast(custom_data.address); - bool new_value = data[0] == '1'; - *reinterpret_cast(custom_data.address) = new_value; - if (old_value != new_value && custom_data.change_callback) - custom_data.change_callback(); - } - return data.size(); -} - -void ProcFS::add_sys_bool(String&& name, bool* var, Function&& change_callback) -{ - auto file = create_generated_file(move(name), move(read_sys_bool), move(write_sys_bool)); - auto data = make(); - data->type = SysVariableData::Boolean; - data->change_callback = move(change_callback); - data->address = var; - file->set_custom_data(move(data)); - InterruptDisabler disabler; - add_file(move(file), m_sys_dir.index()); -} - -bool ProcFS::initialize() -{ - SynthFS::initialize(); - add_file(create_generated_file("mm", procfs$mm)); - add_file(create_generated_file("mounts", procfs$mounts)); - add_file(create_generated_file("kmalloc", procfs$kmalloc)); - add_file(create_generated_file("summary", procfs$summary)); - add_file(create_generated_file("cpuinfo", procfs$cpuinfo)); - add_file(create_generated_file("inodes", procfs$inodes)); - add_file(create_generated_file("dmesg", procfs$dmesg)); - add_file(create_generated_file("self", procfs$self, 00120777)); - m_sys_dir = add_file(create_directory("sys")); - return true; -} - -const char* ProcFS::class_name() const -{ - return "ProcFS"; -} diff --git a/Kernel/ProcFileSystem.h b/Kernel/ProcFileSystem.h deleted file mode 100644 index 11697d817c..0000000000 --- a/Kernel/ProcFileSystem.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include -#include - -class Process; - -class ProcFS final : public SynthFS { -public: - static ProcFS& the() PURE; - - virtual ~ProcFS() override; - static RetainPtr create(); - - virtual bool initialize() override; - virtual const char* class_name() const override; - - void add_process(Process&); - void remove_process(Process&); - - void add_sys_file(String&&, Function&& read_callback, Function&& write_callback); - void add_sys_bool(String&&, bool*, Function&& change_callback = nullptr); - -private: - ProcFS(); - - HashMap m_pid2inode; - InodeIdentifier m_sys_dir; -}; - diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index a1e1a62c37..317614cbd9 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -10,7 +10,6 @@ #include "MemoryManager.h" #include "i8253.h" #include "RTC.h" -#include "ProcFileSystem.h" #include #include #include @@ -60,13 +59,23 @@ void Process::initialize() initialize_gui_statics(); } +Vector Process::all_pids() +{ + InterruptDisabler disabler; + Vector pids; + pids.ensure_capacity(g_processes->size_slow()); + for (auto* process = g_processes->head(); process; process = process->next()) + pids.unchecked_append(process->pid()); + return pids; +} + Vector Process::all_processes() { InterruptDisabler disabler; Vector processes; processes.ensure_capacity(g_processes->size_slow()); for (auto* process = g_processes->head(); process; process = process->next()) - processes.append(process); + processes.unchecked_append(process); return processes; } @@ -266,8 +275,6 @@ Process* Process::fork(RegisterDump& regs) dbgprintf("fork: child will begin executing at %w:%x with stack %w:%x\n", child->m_tss.cs, child->m_tss.eip, child->m_tss.ss, child->m_tss.esp); #endif - ProcFS::the().add_process(*child); - { InterruptDisabler disabler; g_processes->prepend(child); @@ -507,8 +514,6 @@ Process* Process::create_user_process(const String& path, uid_t uid, gid_t gid, return nullptr; } - ProcFS::the().add_process(*process); - { InterruptDisabler disabler; g_processes->prepend(process); @@ -571,7 +576,6 @@ Process* Process::create_kernel_process(String&& name, void (*e)()) g_processes->prepend(process); system.nprocess++; } - ProcFS::the().add_process(*process); #ifdef TASK_DEBUG kprintf("Kernel process %u (%s) spawned @ %p\n", process->pid(), process->name().characters(), process->m_tss.eip); #endif @@ -703,7 +707,6 @@ Process::Process(String&& name, uid_t uid, gid_t gid, pid_t ppid, RingLevel ring Process::~Process() { InterruptDisabler disabler; - ProcFS::the().remove_process(*this); system.nprocess--; if (g_last_fpu_process == this) diff --git a/Kernel/Process.h b/Kernel/Process.h index ce465f3182..f4eb329c78 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -55,6 +55,7 @@ public: static Process* create_user_process(const String& path, uid_t, gid_t, pid_t ppid, int& error, Vector&& arguments = Vector(), Vector&& environment = Vector(), TTY* = nullptr); ~Process(); + static Vector all_pids(); static Vector all_processes(); enum State { @@ -406,6 +407,17 @@ public: m_process.set_state(m_original_state); } + Process& process() { return m_process; } + + static OwnPtr from_pid(pid_t pid) + { + InterruptDisabler disabler; + auto* process = Process::from_pid(pid); + if (process) + return make(*process); + return nullptr; + } + Process* operator->() { return &m_process; } Process& operator*() { return m_process; } private: diff --git a/Kernel/StdLib.cpp b/Kernel/StdLib.cpp index baadb8127b..59673d7ba0 100644 --- a/Kernel/StdLib.cpp +++ b/Kernel/StdLib.cpp @@ -92,10 +92,10 @@ int strcmp(const char *s1, const char *s2) char* strdup(const char *str) { - dword len = strlen(str); - char *s = (char*)kmalloc(len); - memcpy(s, str, len); - return s; + size_t len = strlen(str); + char* new_str = (char*)kmalloc(len + 1); + strcpy(new_str, str); + return new_str; } int memcmp(const void* v1, const void* v2, size_t n) diff --git a/Kernel/init.cpp b/Kernel/init.cpp index ead7becce8..81fd6ebaa1 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -16,7 +16,7 @@ #include #include "GUIEventDevice.h" #include "MemoryManager.h" -#include "ProcFileSystem.h" +#include "ProcFS.h" #include "RTC.h" #include "VirtualConsole.h" #include "Scheduler.h" @@ -171,8 +171,8 @@ void init() memset(&system, 0, sizeof(system)); - auto procfs = ProcFS::create(); - procfs->initialize(); + auto new_procfs = ProcFS::create(); + new_procfs->initialize(); auto devptsfs = DevPtsFS::create(); devptsfs->initialize(); diff --git a/Kernel/types.h b/Kernel/types.h index f7ce3abab1..b355315b46 100644 --- a/Kernel/types.h +++ b/Kernel/types.h @@ -14,7 +14,7 @@ typedef short __s16; typedef dword uid_t; typedef dword gid_t; -typedef int pid_t; +typedef signed_word pid_t; typedef dword time_t; typedef dword suseconds_t; diff --git a/LibC/sys/types.h b/LibC/sys/types.h index 7d283480a9..18a3fcb1aa 100644 --- a/LibC/sys/types.h +++ b/LibC/sys/types.h @@ -15,7 +15,7 @@ typedef __intmax_t intmax_t; typedef uint32_t uid_t; typedef uint32_t gid_t; -typedef int pid_t; +typedef int16_t pid_t; typedef uint32_t size_t; typedef int32_t ssize_t; diff --git a/WindowServer/WSWindowManager.cpp b/WindowServer/WSWindowManager.cpp index 4bf94b6f07..c4fcf0d471 100644 --- a/WindowServer/WSWindowManager.cpp +++ b/WindowServer/WSWindowManager.cpp @@ -4,7 +4,7 @@ #include "WSMessageLoop.h" #include "Process.h" #include "MemoryManager.h" -#include +#include #include #include #include