mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 09:02:43 +00:00 
			
		
		
		
	Kernel: Rewrite ProcFS.
Now the filesystem is generated on-the-fly instead of manually adding and removing inodes as processes spawn and die. The code is convoluted and bloated as I wrote it while sleepless. However, it's still vastly better than the old ProcFS, so I'm committing it. I also added /proc/PID/fd/N symlinks for each of a process's open fd's.
This commit is contained in:
		
							parent
							
								
									ab56f36bfb
								
							
						
					
					
						commit
						5e9ba2ac84
					
				
					 13 changed files with 1133 additions and 468 deletions
				
			
		|  | @ -16,7 +16,7 @@ KERNEL_OBJS = \ | ||||||
|        Console.o \
 |        Console.o \
 | ||||||
|        IRQHandler.o \
 |        IRQHandler.o \
 | ||||||
|        kprintf.o \
 |        kprintf.o \
 | ||||||
|        ProcFileSystem.o \
 |        ProcFS.o \
 | ||||||
|        RTC.o \
 |        RTC.o \
 | ||||||
|        TTY.o \
 |        TTY.o \
 | ||||||
|        PTYMultiplexer.o \
 |        PTYMultiplexer.o \
 | ||||||
|  |  | ||||||
|  | @ -201,7 +201,7 @@ class MemoryManager { | ||||||
|     friend class PhysicalPage; |     friend class PhysicalPage; | ||||||
|     friend class Region; |     friend class Region; | ||||||
|     friend class VMObject; |     friend class VMObject; | ||||||
|     friend ByteBuffer procfs$mm(SynthFSInode&); |     friend ByteBuffer procfs$mm(InodeIdentifier); | ||||||
| public: | public: | ||||||
|     static MemoryManager& the() PURE; |     static MemoryManager& the() PURE; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										1002
									
								
								Kernel/ProcFS.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1002
									
								
								Kernel/ProcFS.cpp
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										96
									
								
								Kernel/ProcFS.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								Kernel/ProcFS.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,96 @@ | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <AK/Lock.h> | ||||||
|  | #include <AK/Types.h> | ||||||
|  | #include <Kernel/FileSystem.h> | ||||||
|  | 
 | ||||||
|  | class Process; | ||||||
|  | 
 | ||||||
|  | class ProcFSInode; | ||||||
|  | 
 | ||||||
|  | class ProcFS final : public FS { | ||||||
|  |     friend class ProcFSInode; | ||||||
|  | public: | ||||||
|  |     static ProcFS& the() PURE; | ||||||
|  | 
 | ||||||
|  |     virtual ~ProcFS() override; | ||||||
|  |     static RetainPtr<ProcFS> create(); | ||||||
|  | 
 | ||||||
|  |     virtual bool initialize() override; | ||||||
|  |     virtual const char* class_name() const override; | ||||||
|  | 
 | ||||||
|  |     virtual InodeIdentifier root_inode() const override; | ||||||
|  |     virtual RetainPtr<Inode> get_inode(InodeIdentifier) const override; | ||||||
|  | 
 | ||||||
|  |     virtual RetainPtr<Inode> create_inode(InodeIdentifier parent_id, const String& name, mode_t, unsigned size, int& error) override; | ||||||
|  |     virtual RetainPtr<Inode> create_directory(InodeIdentifier parent_id, const String& name, mode_t, int& error) override; | ||||||
|  | 
 | ||||||
|  |     void add_sys_file(String&&, Function<ByteBuffer(ProcFSInode&)>&& read_callback, Function<ssize_t(ProcFSInode&, const ByteBuffer&)>&& write_callback); | ||||||
|  |     void add_sys_bool(String&&, bool*, Function<void()>&& notify_callback = nullptr); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     ProcFS(); | ||||||
|  | 
 | ||||||
|  |     struct ProcFSDirectoryEntry { | ||||||
|  |         ProcFSDirectoryEntry() { } | ||||||
|  |         ProcFSDirectoryEntry(const char* a_name, unsigned a_proc_file_type, Function<ByteBuffer(InodeIdentifier)>&& a_read_callback = nullptr, Function<ssize_t(InodeIdentifier, const ByteBuffer&)>&& a_write_callback = nullptr, RetainPtr<ProcFSInode>&& 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<ByteBuffer(InodeIdentifier)> read_callback; | ||||||
|  |         Function<ssize_t(InodeIdentifier, const ByteBuffer&)> write_callback; | ||||||
|  |         RetainPtr<ProcFSInode> inode; | ||||||
|  |         InodeIdentifier identifier(unsigned fsid) const; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     ProcFSDirectoryEntry* get_directory_entry(InodeIdentifier) const; | ||||||
|  | 
 | ||||||
|  |     Vector<ProcFSDirectoryEntry> m_entries; | ||||||
|  |     Vector<ProcFSDirectoryEntry> m_sys_entries; | ||||||
|  | 
 | ||||||
|  |     mutable Lock m_inodes_lock; | ||||||
|  |     mutable HashMap<unsigned, ProcFSInode*> m_inodes; | ||||||
|  |     RetainPtr<ProcFSInode> m_root_inode; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct ProcFSInodeCustomData { | ||||||
|  |     virtual ~ProcFSInodeCustomData(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | class ProcFSInode final : public Inode { | ||||||
|  |     friend class ProcFS; | ||||||
|  | public: | ||||||
|  |     virtual ~ProcFSInode() override; | ||||||
|  | 
 | ||||||
|  |     void set_custom_data(OwnPtr<ProcFSInodeCustomData>&& 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<bool(const FS::DirectoryEntry&)>) 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<Inode> parent() const override; | ||||||
|  |     virtual size_t directory_entry_count() const override; | ||||||
|  |     virtual bool chmod(mode_t, int& error) override; | ||||||
|  | 
 | ||||||
|  |     ProcFS& fs() { return static_cast<ProcFS&>(Inode::fs()); } | ||||||
|  |     const ProcFS& fs() const { return static_cast<const ProcFS&>(Inode::fs()); } | ||||||
|  |     ProcFSInode(ProcFS&, unsigned index); | ||||||
|  | 
 | ||||||
|  |     OwnPtr<ProcFSInodeCustomData> m_custom_data; | ||||||
|  | }; | ||||||
|  | @ -1,418 +0,0 @@ | ||||||
| #include "ProcFileSystem.h" |  | ||||||
| #include "Process.h" |  | ||||||
| #include <Kernel/VirtualFileSystem.h> |  | ||||||
| #include "system.h" |  | ||||||
| #include "MemoryManager.h" |  | ||||||
| #include "StdLib.h" |  | ||||||
| #include "i386.h" |  | ||||||
| #include "KSyms.h" |  | ||||||
| #include "Console.h" |  | ||||||
| #include <AK/StringBuilder.h> |  | ||||||
| 
 |  | ||||||
| static ProcFS* s_the; |  | ||||||
| 
 |  | ||||||
| ProcFS& ProcFS::the() |  | ||||||
| { |  | ||||||
|     ASSERT(s_the); |  | ||||||
|     return *s_the; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| RetainPtr<ProcFS> 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<RecognizedSymbol> 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<dword*>(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<Inode*>& all_inodes(); |  | ||||||
|     auto& vfs = VFS::the(); |  | ||||||
|     StringBuilder builder; |  | ||||||
|     for (auto it : all_inodes()) { |  | ||||||
|         RetainPtr<Inode> 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<void()> 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<const SysVariableData*>(inode.custom_data()); |  | ||||||
|     ASSERT(custom_data.type == SysVariableData::Boolean); |  | ||||||
|     ASSERT(custom_data.address); |  | ||||||
|     buffer[0] = *reinterpret_cast<bool*>(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<const SysVariableData*>(inode.custom_data()); |  | ||||||
|         ASSERT(custom_data.address); |  | ||||||
|         bool old_value = *reinterpret_cast<bool*>(custom_data.address); |  | ||||||
|         bool new_value = data[0] == '1'; |  | ||||||
|         *reinterpret_cast<bool*>(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<void()>&& change_callback) |  | ||||||
| { |  | ||||||
|     auto file = create_generated_file(move(name), move(read_sys_bool), move(write_sys_bool)); |  | ||||||
|     auto data = make<SysVariableData>(); |  | ||||||
|     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"; |  | ||||||
| } |  | ||||||
|  | @ -1,30 +0,0 @@ | ||||||
| #pragma once |  | ||||||
| 
 |  | ||||||
| #include <AK/Types.h> |  | ||||||
| #include <Kernel/SyntheticFileSystem.h> |  | ||||||
| 
 |  | ||||||
| class Process; |  | ||||||
| 
 |  | ||||||
| class ProcFS final : public SynthFS { |  | ||||||
| public: |  | ||||||
|     static ProcFS& the() PURE; |  | ||||||
| 
 |  | ||||||
|     virtual ~ProcFS() override; |  | ||||||
|     static RetainPtr<ProcFS> 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<ByteBuffer(SynthFSInode&)>&& read_callback, Function<ssize_t(SynthFSInode&, const ByteBuffer&)>&& write_callback); |  | ||||||
|     void add_sys_bool(String&&, bool*, Function<void()>&& change_callback = nullptr); |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
|     ProcFS(); |  | ||||||
| 
 |  | ||||||
|     HashMap<pid_t, InodeIndex> m_pid2inode; |  | ||||||
|     InodeIdentifier m_sys_dir; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
|  | @ -10,7 +10,6 @@ | ||||||
| #include "MemoryManager.h" | #include "MemoryManager.h" | ||||||
| #include "i8253.h" | #include "i8253.h" | ||||||
| #include "RTC.h" | #include "RTC.h" | ||||||
| #include "ProcFileSystem.h" |  | ||||||
| #include <AK/StdLibExtras.h> | #include <AK/StdLibExtras.h> | ||||||
| #include <LibC/signal_numbers.h> | #include <LibC/signal_numbers.h> | ||||||
| #include <LibC/errno_numbers.h> | #include <LibC/errno_numbers.h> | ||||||
|  | @ -60,13 +59,23 @@ void Process::initialize() | ||||||
|     initialize_gui_statics(); |     initialize_gui_statics(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | Vector<pid_t> Process::all_pids() | ||||||
|  | { | ||||||
|  |     InterruptDisabler disabler; | ||||||
|  |     Vector<pid_t> 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*> Process::all_processes() | Vector<Process*> Process::all_processes() | ||||||
| { | { | ||||||
|     InterruptDisabler disabler; |     InterruptDisabler disabler; | ||||||
|     Vector<Process*> processes; |     Vector<Process*> processes; | ||||||
|     processes.ensure_capacity(g_processes->size_slow()); |     processes.ensure_capacity(g_processes->size_slow()); | ||||||
|     for (auto* process = g_processes->head(); process; process = process->next()) |     for (auto* process = g_processes->head(); process; process = process->next()) | ||||||
|         processes.append(process); |         processes.unchecked_append(process); | ||||||
|     return processes; |     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); |     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 | #endif | ||||||
| 
 | 
 | ||||||
|     ProcFS::the().add_process(*child); |  | ||||||
| 
 |  | ||||||
|     { |     { | ||||||
|         InterruptDisabler disabler; |         InterruptDisabler disabler; | ||||||
|         g_processes->prepend(child); |         g_processes->prepend(child); | ||||||
|  | @ -507,8 +514,6 @@ Process* Process::create_user_process(const String& path, uid_t uid, gid_t gid, | ||||||
|         return nullptr; |         return nullptr; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     ProcFS::the().add_process(*process); |  | ||||||
| 
 |  | ||||||
|     { |     { | ||||||
|         InterruptDisabler disabler; |         InterruptDisabler disabler; | ||||||
|         g_processes->prepend(process); |         g_processes->prepend(process); | ||||||
|  | @ -571,7 +576,6 @@ Process* Process::create_kernel_process(String&& name, void (*e)()) | ||||||
|             g_processes->prepend(process); |             g_processes->prepend(process); | ||||||
|             system.nprocess++; |             system.nprocess++; | ||||||
|         } |         } | ||||||
|         ProcFS::the().add_process(*process); |  | ||||||
| #ifdef TASK_DEBUG | #ifdef TASK_DEBUG | ||||||
|         kprintf("Kernel process %u (%s) spawned @ %p\n", process->pid(), process->name().characters(), process->m_tss.eip); |         kprintf("Kernel process %u (%s) spawned @ %p\n", process->pid(), process->name().characters(), process->m_tss.eip); | ||||||
| #endif | #endif | ||||||
|  | @ -703,7 +707,6 @@ Process::Process(String&& name, uid_t uid, gid_t gid, pid_t ppid, RingLevel ring | ||||||
| Process::~Process() | Process::~Process() | ||||||
| { | { | ||||||
|     InterruptDisabler disabler; |     InterruptDisabler disabler; | ||||||
|     ProcFS::the().remove_process(*this); |  | ||||||
|     system.nprocess--; |     system.nprocess--; | ||||||
| 
 | 
 | ||||||
|     if (g_last_fpu_process == this) |     if (g_last_fpu_process == this) | ||||||
|  |  | ||||||
|  | @ -55,6 +55,7 @@ public: | ||||||
|     static Process* create_user_process(const String& path, uid_t, gid_t, pid_t ppid, int& error, Vector<String>&& arguments = Vector<String>(), Vector<String>&& environment = Vector<String>(), TTY* = nullptr); |     static Process* create_user_process(const String& path, uid_t, gid_t, pid_t ppid, int& error, Vector<String>&& arguments = Vector<String>(), Vector<String>&& environment = Vector<String>(), TTY* = nullptr); | ||||||
|     ~Process(); |     ~Process(); | ||||||
| 
 | 
 | ||||||
|  |     static Vector<pid_t> all_pids(); | ||||||
|     static Vector<Process*> all_processes(); |     static Vector<Process*> all_processes(); | ||||||
| 
 | 
 | ||||||
|     enum State { |     enum State { | ||||||
|  | @ -406,6 +407,17 @@ public: | ||||||
|         m_process.set_state(m_original_state); |         m_process.set_state(m_original_state); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     Process& process() { return m_process; } | ||||||
|  | 
 | ||||||
|  |     static OwnPtr<ProcessInspectionHandle> from_pid(pid_t pid) | ||||||
|  |     { | ||||||
|  |         InterruptDisabler disabler; | ||||||
|  |         auto* process = Process::from_pid(pid); | ||||||
|  |         if (process) | ||||||
|  |             return make<ProcessInspectionHandle>(*process); | ||||||
|  |         return nullptr; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     Process* operator->() { return &m_process; } |     Process* operator->() { return &m_process; } | ||||||
|     Process& operator*() { return m_process; } |     Process& operator*() { return m_process; } | ||||||
| private: | private: | ||||||
|  |  | ||||||
|  | @ -92,10 +92,10 @@ int strcmp(const char *s1, const char *s2) | ||||||
| 
 | 
 | ||||||
| char* strdup(const char *str) | char* strdup(const char *str) | ||||||
| { | { | ||||||
|     dword len = strlen(str); |     size_t len = strlen(str); | ||||||
|     char *s = (char*)kmalloc(len); |     char* new_str = (char*)kmalloc(len + 1); | ||||||
|     memcpy(s, str, len); |     strcpy(new_str, str); | ||||||
|     return s; |     return new_str; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int memcmp(const void* v1, const void* v2, size_t n) | int memcmp(const void* v1, const void* v2, size_t n) | ||||||
|  |  | ||||||
|  | @ -16,7 +16,7 @@ | ||||||
| #include <Kernel/VirtualFileSystem.h> | #include <Kernel/VirtualFileSystem.h> | ||||||
| #include "GUIEventDevice.h" | #include "GUIEventDevice.h" | ||||||
| #include "MemoryManager.h" | #include "MemoryManager.h" | ||||||
| #include "ProcFileSystem.h" | #include "ProcFS.h" | ||||||
| #include "RTC.h" | #include "RTC.h" | ||||||
| #include "VirtualConsole.h" | #include "VirtualConsole.h" | ||||||
| #include "Scheduler.h" | #include "Scheduler.h" | ||||||
|  | @ -171,8 +171,8 @@ void init() | ||||||
| 
 | 
 | ||||||
|     memset(&system, 0, sizeof(system)); |     memset(&system, 0, sizeof(system)); | ||||||
| 
 | 
 | ||||||
|     auto procfs = ProcFS::create(); |     auto new_procfs = ProcFS::create(); | ||||||
|     procfs->initialize(); |     new_procfs->initialize(); | ||||||
| 
 | 
 | ||||||
|     auto devptsfs = DevPtsFS::create(); |     auto devptsfs = DevPtsFS::create(); | ||||||
|     devptsfs->initialize(); |     devptsfs->initialize(); | ||||||
|  |  | ||||||
|  | @ -14,7 +14,7 @@ typedef short __s16; | ||||||
| 
 | 
 | ||||||
| typedef dword uid_t; | typedef dword uid_t; | ||||||
| typedef dword gid_t; | typedef dword gid_t; | ||||||
| typedef int pid_t; | typedef signed_word pid_t; | ||||||
| typedef dword time_t; | typedef dword time_t; | ||||||
| typedef dword suseconds_t; | typedef dword suseconds_t; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -15,7 +15,7 @@ typedef __intmax_t intmax_t; | ||||||
| 
 | 
 | ||||||
| typedef uint32_t uid_t; | typedef uint32_t uid_t; | ||||||
| typedef uint32_t gid_t; | typedef uint32_t gid_t; | ||||||
| typedef int pid_t; | typedef int16_t pid_t; | ||||||
| 
 | 
 | ||||||
| typedef uint32_t size_t; | typedef uint32_t size_t; | ||||||
| typedef int32_t ssize_t; | typedef int32_t ssize_t; | ||||||
|  |  | ||||||
|  | @ -4,7 +4,7 @@ | ||||||
| #include "WSMessageLoop.h" | #include "WSMessageLoop.h" | ||||||
| #include "Process.h" | #include "Process.h" | ||||||
| #include "MemoryManager.h" | #include "MemoryManager.h" | ||||||
| #include <Kernel/ProcFileSystem.h> | #include <Kernel/ProcFS.h> | ||||||
| #include <SharedGraphics/Font.h> | #include <SharedGraphics/Font.h> | ||||||
| #include <SharedGraphics/Painter.h> | #include <SharedGraphics/Painter.h> | ||||||
| #include <SharedGraphics/CharacterBitmap.h> | #include <SharedGraphics/CharacterBitmap.h> | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling