Serenity Operating System
at hosted 1672 lines 58 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include "ProcFS.h" 28#include "KSyms.h" 29#include "Process.h" 30#include "Scheduler.h" 31#include <AK/JsonArraySerializer.h> 32#include <AK/JsonObject.h> 33#include <AK/JsonObjectSerializer.h> 34#include <AK/JsonValue.h> 35#include <Kernel/Arch/i386/CPU.h> 36#include <Kernel/CommandLine.h> 37#include <Kernel/Devices/BlockDevice.h> 38#include <Kernel/FileSystem/Custody.h> 39#include <Kernel/FileSystem/FileBackedFileSystem.h> 40#include <Kernel/FileSystem/FileDescription.h> 41#include <Kernel/FileSystem/VirtualFileSystem.h> 42#include <Kernel/Heap/kmalloc.h> 43#include <Kernel/Interrupts/GenericInterruptHandler.h> 44#include <Kernel/Interrupts/InterruptManagement.h> 45#include <Kernel/KBufferBuilder.h> 46#include <Kernel/Module.h> 47#include <Kernel/Net/LocalSocket.h> 48#include <Kernel/Net/NetworkAdapter.h> 49#include <Kernel/Net/Routing.h> 50#include <Kernel/Net/TCPSocket.h> 51#include <Kernel/Net/UDPSocket.h> 52#include <Kernel/PCI/Access.h> 53#include <Kernel/Profiling.h> 54#include <Kernel/TTY/TTY.h> 55#include <Kernel/VM/MemoryManager.h> 56#include <Kernel/VM/PurgeableVMObject.h> 57#include <LibBareMetal/Output/Console.h> 58#include <LibBareMetal/StdLib.h> 59#include <LibC/errno_numbers.h> 60 61namespace Kernel { 62 63enum ProcParentDirectory { 64 PDI_AbstractRoot = 0, 65 PDI_Root, 66 PDI_Root_sys, 67 PDI_Root_net, 68 PDI_PID, 69 PDI_PID_fd, 70}; 71 72enum ProcFileType { 73 FI_Invalid = 0, 74 75 FI_Root = 1, // directory 76 77 __FI_Root_Start, 78 FI_Root_mm, 79 FI_Root_mounts, 80 FI_Root_df, 81 FI_Root_all, 82 FI_Root_memstat, 83 FI_Root_cpuinfo, 84 FI_Root_inodes, 85 FI_Root_dmesg, 86 FI_Root_interrupts, 87 FI_Root_pci, 88 FI_Root_devices, 89 FI_Root_uptime, 90 FI_Root_cmdline, 91 FI_Root_modules, 92 FI_Root_profile, 93 FI_Root_self, // symlink 94 FI_Root_sys, // directory 95 FI_Root_net, // directory 96 __FI_Root_End, 97 98 FI_Root_sys_variable, 99 100 FI_Root_net_adapters, 101 FI_Root_net_arp, 102 FI_Root_net_tcp, 103 FI_Root_net_udp, 104 FI_Root_net_local, 105 106 FI_PID, 107 108 __FI_PID_Start, 109 FI_PID_vm, 110 FI_PID_vmobjects, 111 FI_PID_stack, 112 FI_PID_regs, 113 FI_PID_fds, 114 FI_PID_unveil, 115 FI_PID_exe, // symlink 116 FI_PID_cwd, // symlink 117 FI_PID_root, // symlink 118 FI_PID_fd, // directory 119 __FI_PID_End, 120 121 FI_MaxStaticFileIndex, 122}; 123 124static inline pid_t to_pid(const InodeIdentifier& identifier) 125{ 126#ifdef PROCFS_DEBUG 127 dbg() << "to_pid, index=" << String::format("%08x", identifier.index()) << " -> " << (identifier.index() >> 16); 128#endif 129 return identifier.index() >> 16u; 130} 131 132static inline ProcParentDirectory to_proc_parent_directory(const InodeIdentifier& identifier) 133{ 134 return (ProcParentDirectory)((identifier.index() >> 12) & 0xf); 135} 136 137static inline ProcFileType to_proc_file_type(const InodeIdentifier& identifier) 138{ 139 return (ProcFileType)(identifier.index() & 0xff); 140} 141 142static inline int to_fd(const InodeIdentifier& identifier) 143{ 144 ASSERT(to_proc_parent_directory(identifier) == PDI_PID_fd); 145 return (identifier.index() & 0xff) - FI_MaxStaticFileIndex; 146} 147 148static inline size_t to_sys_index(const InodeIdentifier& identifier) 149{ 150 ASSERT(to_proc_parent_directory(identifier) == PDI_Root_sys); 151 ASSERT(to_proc_file_type(identifier) == FI_Root_sys_variable); 152 return identifier.index() >> 16u; 153} 154 155static inline InodeIdentifier to_identifier(unsigned fsid, ProcParentDirectory parent, pid_t pid, ProcFileType proc_file_type) 156{ 157 return { fsid, ((unsigned)parent << 12u) | ((unsigned)pid << 16u) | (unsigned)proc_file_type }; 158} 159 160static inline InodeIdentifier to_identifier_with_fd(unsigned fsid, pid_t pid, int fd) 161{ 162 return { fsid, (PDI_PID_fd << 12u) | ((unsigned)pid << 16u) | (FI_MaxStaticFileIndex + fd) }; 163} 164 165static inline InodeIdentifier sys_var_to_identifier(unsigned fsid, unsigned index) 166{ 167 ASSERT(index < 256); 168 return { fsid, (PDI_Root_sys << 12u) | (index << 16u) | FI_Root_sys_variable }; 169} 170 171static inline InodeIdentifier to_parent_id(const InodeIdentifier& identifier) 172{ 173 switch (to_proc_parent_directory(identifier)) { 174 case PDI_AbstractRoot: 175 case PDI_Root: 176 return { identifier.fsid(), FI_Root }; 177 case PDI_Root_sys: 178 return { identifier.fsid(), FI_Root_sys }; 179 case PDI_Root_net: 180 return { identifier.fsid(), FI_Root_net }; 181 case PDI_PID: 182 return to_identifier(identifier.fsid(), PDI_Root, to_pid(identifier), FI_PID); 183 case PDI_PID_fd: 184 return to_identifier(identifier.fsid(), PDI_PID, to_pid(identifier), FI_PID_fd); 185 } 186 ASSERT_NOT_REACHED(); 187} 188 189#if 0 190static inline u8 to_unused_metadata(const InodeIdentifier& identifier) 191{ 192 return (identifier.index() >> 8) & 0xf; 193} 194#endif 195 196static inline bool is_process_related_file(const InodeIdentifier& identifier) 197{ 198 if (to_proc_file_type(identifier) == FI_PID) 199 return true; 200 auto proc_parent_directory = to_proc_parent_directory(identifier); 201 switch (proc_parent_directory) { 202 case PDI_PID: 203 case PDI_PID_fd: 204 return true; 205 default: 206 return false; 207 } 208} 209 210static inline bool is_directory(const InodeIdentifier& identifier) 211{ 212 auto proc_file_type = to_proc_file_type(identifier); 213 switch (proc_file_type) { 214 case FI_Root: 215 case FI_Root_sys: 216 case FI_Root_net: 217 case FI_PID: 218 case FI_PID_fd: 219 return true; 220 default: 221 return false; 222 } 223} 224 225static inline bool is_persistent_inode(const InodeIdentifier& identifier) 226{ 227 return to_proc_parent_directory(identifier) == PDI_Root_sys; 228} 229 230NonnullRefPtr<ProcFS> ProcFS::create() 231{ 232 return adopt(*new ProcFS); 233} 234 235ProcFS::~ProcFS() 236{ 237} 238 239Optional<KBuffer> procfs$pid_fds(InodeIdentifier identifier) 240{ 241 KBufferBuilder builder; 242 JsonArraySerializer array { builder }; 243 244 auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier)); 245 if (!handle) { 246 array.finish(); 247 return builder.build(); 248 } 249 auto& process = handle->process(); 250 if (process.number_of_open_file_descriptors() == 0) { 251 array.finish(); 252 return builder.build(); 253 } 254 255 for (int i = 0; i < process.max_open_file_descriptors(); ++i) { 256 auto description = process.file_description(i); 257 if (!description) 258 continue; 259 bool cloexec = process.fd_flags(i) & FD_CLOEXEC; 260 261 auto description_object = array.add_object(); 262 description_object.add("fd", i); 263 description_object.add("absolute_path", description->absolute_path()); 264 description_object.add("seekable", description->file().is_seekable()); 265 description_object.add("class", description->file().class_name()); 266 description_object.add("offset", description->offset()); 267 description_object.add("cloexec", cloexec); 268 description_object.add("blocking", description->is_blocking()); 269 description_object.add("can_read", description->can_read()); 270 description_object.add("can_write", description->can_write()); 271 } 272 array.finish(); 273 return builder.build(); 274} 275 276Optional<KBuffer> procfs$pid_fd_entry(InodeIdentifier identifier) 277{ 278 auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier)); 279 if (!handle) 280 return {}; 281 auto& process = handle->process(); 282 int fd = to_fd(identifier); 283 auto description = process.file_description(fd); 284 if (!description) 285 return {}; 286 return description->absolute_path().to_byte_buffer(); 287} 288 289Optional<KBuffer> procfs$pid_vm(InodeIdentifier identifier) 290{ 291 auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier)); 292 if (!handle) 293 return {}; 294 auto& process = handle->process(); 295 KBufferBuilder builder; 296 JsonArraySerializer array { builder }; 297 for (auto& region : process.regions()) { 298 if (!region.is_user_accessible() && !Process::current->is_superuser()) 299 continue; 300 auto region_object = array.add_object(); 301 region_object.add("readable", region.is_readable()); 302 region_object.add("writable", region.is_writable()); 303 region_object.add("executable", region.is_executable()); 304 region_object.add("stack", region.is_stack()); 305 region_object.add("shared", region.is_shared()); 306 region_object.add("user_accessible", region.is_user_accessible()); 307 region_object.add("purgeable", region.vmobject().is_purgeable()); 308 if (region.vmobject().is_purgeable()) { 309 region_object.add("volatile", static_cast<const PurgeableVMObject&>(region.vmobject()).is_volatile()); 310 } 311 region_object.add("purgeable", region.vmobject().is_purgeable()); 312 region_object.add("address", region.vaddr().get()); 313 region_object.add("size", (u32)region.size()); 314 region_object.add("amount_resident", (u32)region.amount_resident()); 315 region_object.add("amount_dirty", (u32)region.amount_dirty()); 316 region_object.add("cow_pages", region.cow_pages()); 317 region_object.add("name", region.name()); 318 region_object.add("vmobject", region.vmobject().class_name()); 319 320 StringBuilder pagemap_builder; 321 for (size_t i = 0; i < region.page_count(); ++i) { 322 auto page_index = region.first_page_index() + i; 323 auto& physical_page_slot = region.vmobject().physical_pages()[page_index]; 324 if (!physical_page_slot) 325 pagemap_builder.append('N'); 326 else if (physical_page_slot == MM.shared_zero_page()) 327 pagemap_builder.append('Z'); 328 else 329 pagemap_builder.append('P'); 330 } 331 region_object.add("pagemap", pagemap_builder.to_string()); 332 } 333 array.finish(); 334 return builder.build(); 335} 336 337Optional<KBuffer> procfs$pci(InodeIdentifier) 338{ 339 KBufferBuilder builder; 340 JsonArraySerializer array { builder }; 341 PCI::enumerate_all([&array](PCI::Address address, PCI::ID id) { 342 auto obj = array.add_object(); 343 obj.add("seg", address.seg()); 344 obj.add("bus", address.bus()); 345 obj.add("slot", address.slot()); 346 obj.add("function", address.function()); 347 obj.add("vendor_id", id.vendor_id); 348 obj.add("device_id", id.device_id); 349 obj.add("revision_id", PCI::get_revision_id(address)); 350 obj.add("subclass", PCI::get_subclass(address)); 351 obj.add("class", PCI::get_class(address)); 352 obj.add("subsystem_id", PCI::get_subsystem_id(address)); 353 obj.add("subsystem_vendor_id", PCI::get_subsystem_vendor_id(address)); 354 }); 355 array.finish(); 356 return builder.build(); 357} 358 359Optional<KBuffer> procfs$interrupts(InodeIdentifier) 360{ 361 KBufferBuilder builder; 362 JsonArraySerializer array { builder }; 363 InterruptManagement::the().enumerate_interrupt_handlers([&array](GenericInterruptHandler& handler) { 364 auto obj = array.add_object(); 365 obj.add("purpose", handler.purpose()); 366 obj.add("interrupt_line", handler.interrupt_number()); 367 obj.add("controller", handler.controller()); 368 obj.add("cpu_handler", 0); // FIXME: Determine the responsible CPU for each interrupt handler. 369 obj.add("device_sharing", (unsigned)handler.sharing_devices_count()); 370 obj.add("call_count", (unsigned)handler.get_invoking_count()); 371 }); 372 array.finish(); 373 return builder.build(); 374} 375 376Optional<KBuffer> procfs$devices(InodeIdentifier) 377{ 378 KBufferBuilder builder; 379 JsonArraySerializer array { builder }; 380 Device::for_each([&array](auto& device) { 381 auto obj = array.add_object(); 382 obj.add("major", device.major()); 383 obj.add("minor", device.minor()); 384 obj.add("class_name", device.class_name()); 385 386 if (device.is_block_device()) 387 obj.add("type", "block"); 388 else if (device.is_character_device()) 389 obj.add("type", "character"); 390 else 391 ASSERT_NOT_REACHED(); 392 }); 393 array.finish(); 394 return builder.build(); 395} 396 397Optional<KBuffer> procfs$uptime(InodeIdentifier) 398{ 399 KBufferBuilder builder; 400 builder.appendf("%u\n", (u32)(g_uptime / 1000)); 401 return builder.build(); 402} 403 404Optional<KBuffer> procfs$cmdline(InodeIdentifier) 405{ 406 KBufferBuilder builder; 407 builder.append(kernel_command_line().string()); 408 builder.append('\n'); 409 return builder.build(); 410} 411 412Optional<KBuffer> procfs$modules(InodeIdentifier) 413{ 414 extern HashMap<String, OwnPtr<Module>>* g_modules; 415 KBufferBuilder builder; 416 JsonArraySerializer array { builder }; 417 for (auto& it : *g_modules) { 418 auto obj = array.add_object(); 419 obj.add("name", it.value->name); 420 obj.add("module_init", (u32)it.value->module_init); 421 obj.add("module_fini", (u32)it.value->module_fini); 422 u32 size = 0; 423 for (auto& section : it.value->sections) { 424 size += section.capacity(); 425 } 426 obj.add("size", size); 427 } 428 array.finish(); 429 return builder.build(); 430} 431 432Optional<KBuffer> procfs$profile(InodeIdentifier) 433{ 434 InterruptDisabler disabler; 435 KBufferBuilder builder; 436 437 JsonObjectSerializer object(builder); 438 object.add("pid", Profiling::pid()); 439 object.add("executable", Profiling::executable_path()); 440 441 auto array = object.add_array("events"); 442 bool mask_kernel_addresses = !Process::current->is_superuser(); 443 Profiling::for_each_sample([&](auto& sample) { 444 auto object = array.add_object(); 445 object.add("type", "sample"); 446 object.add("tid", sample.tid); 447 object.add("timestamp", sample.timestamp); 448 auto frames_array = object.add_array("stack"); 449 for (size_t i = 0; i < Profiling::max_stack_frame_count; ++i) { 450 if (sample.frames[i] == 0) 451 break; 452 u32 address = (u32)sample.frames[i]; 453 if (mask_kernel_addresses && !is_user_address(VirtualAddress(address))) 454 address = 0xdeadc0de; 455 frames_array.add(address); 456 } 457 frames_array.finish(); 458 }); 459 array.finish(); 460 object.finish(); 461 return builder.build(); 462} 463 464Optional<KBuffer> procfs$net_adapters(InodeIdentifier) 465{ 466 KBufferBuilder builder; 467 JsonArraySerializer array { builder }; 468 NetworkAdapter::for_each([&array](auto& adapter) { 469 auto obj = array.add_object(); 470 obj.add("name", adapter.name()); 471 obj.add("class_name", adapter.class_name()); 472 obj.add("mac_address", adapter.mac_address().to_string()); 473 if (!adapter.ipv4_address().is_zero()) { 474 obj.add("ipv4_address", adapter.ipv4_address().to_string()); 475 obj.add("ipv4_netmask", adapter.ipv4_netmask().to_string()); 476 } 477 if (!adapter.ipv4_gateway().is_zero()) 478 obj.add("ipv4_gateway", adapter.ipv4_gateway().to_string()); 479 obj.add("packets_in", adapter.packets_in()); 480 obj.add("bytes_in", adapter.bytes_in()); 481 obj.add("packets_out", adapter.packets_out()); 482 obj.add("bytes_out", adapter.bytes_out()); 483 obj.add("link_up", adapter.link_up()); 484 obj.add("mtu", adapter.mtu()); 485 }); 486 array.finish(); 487 return builder.build(); 488} 489 490Optional<KBuffer> procfs$net_arp(InodeIdentifier) 491{ 492 KBufferBuilder builder; 493 JsonArraySerializer array { builder }; 494 LOCKER(arp_table().lock()); 495 for (auto& it : arp_table().resource()) { 496 auto obj = array.add_object(); 497 obj.add("mac_address", it.value.to_string()); 498 obj.add("ip_address", it.key.to_string()); 499 } 500 array.finish(); 501 return builder.build(); 502} 503 504Optional<KBuffer> procfs$net_tcp(InodeIdentifier) 505{ 506 KBufferBuilder builder; 507 JsonArraySerializer array { builder }; 508 TCPSocket::for_each([&array](auto& socket) { 509 auto obj = array.add_object(); 510 obj.add("local_address", socket.local_address().to_string()); 511 obj.add("local_port", socket.local_port()); 512 obj.add("peer_address", socket.peer_address().to_string()); 513 obj.add("peer_port", socket.peer_port()); 514 obj.add("state", TCPSocket::to_string(socket.state())); 515 obj.add("ack_number", socket.ack_number()); 516 obj.add("sequence_number", socket.sequence_number()); 517 obj.add("packets_in", socket.packets_in()); 518 obj.add("bytes_in", socket.bytes_in()); 519 obj.add("packets_out", socket.packets_out()); 520 obj.add("bytes_out", socket.bytes_out()); 521 }); 522 array.finish(); 523 return builder.build(); 524} 525 526Optional<KBuffer> procfs$net_udp(InodeIdentifier) 527{ 528 KBufferBuilder builder; 529 JsonArraySerializer array { builder }; 530 UDPSocket::for_each([&array](auto& socket) { 531 auto obj = array.add_object(); 532 obj.add("local_address", socket.local_address().to_string()); 533 obj.add("local_port", socket.local_port()); 534 obj.add("peer_address", socket.peer_address().to_string()); 535 obj.add("peer_port", socket.peer_port()); 536 }); 537 array.finish(); 538 return builder.build(); 539} 540 541Optional<KBuffer> procfs$net_local(InodeIdentifier) 542{ 543 KBufferBuilder builder; 544 JsonArraySerializer array { builder }; 545 LocalSocket::for_each([&array](auto& socket) { 546 auto obj = array.add_object(); 547 obj.add("path", String(socket.socket_path())); 548 obj.add("origin_pid", socket.origin_pid()); 549 obj.add("origin_uid", socket.origin_uid()); 550 obj.add("origin_gid", socket.origin_gid()); 551 obj.add("acceptor_pid", socket.acceptor_pid()); 552 obj.add("acceptor_uid", socket.acceptor_uid()); 553 obj.add("acceptor_gid", socket.acceptor_gid()); 554 }); 555 array.finish(); 556 return builder.build(); 557} 558 559Optional<KBuffer> procfs$pid_vmobjects(InodeIdentifier identifier) 560{ 561 auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier)); 562 if (!handle) 563 return {}; 564 auto& process = handle->process(); 565 KBufferBuilder builder; 566 builder.appendf("BEGIN END SIZE NAME\n"); 567 for (auto& region : process.regions()) { 568 builder.appendf("%x -- %x %x %s\n", 569 region.vaddr().get(), 570 region.vaddr().offset(region.size() - 1).get(), 571 region.size(), 572 region.name().characters()); 573 builder.appendf("VMO: %s @ %x(%u)\n", 574 region.vmobject().is_anonymous() ? "anonymous" : "file-backed", 575 &region.vmobject(), 576 region.vmobject().ref_count()); 577 for (size_t i = 0; i < region.vmobject().page_count(); ++i) { 578 auto& physical_page = region.vmobject().physical_pages()[i]; 579 builder.appendf("P%x%s(%u) ", 580 physical_page ? physical_page->paddr().get() : 0, 581 region.should_cow(i) ? "!" : "", 582 physical_page ? physical_page->ref_count() : 0); 583 } 584 builder.appendf("\n"); 585 } 586 return builder.build(); 587} 588 589Optional<KBuffer> procfs$pid_unveil(InodeIdentifier identifier) 590{ 591 auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier)); 592 if (!handle) 593 return {}; 594 auto& process = handle->process(); 595 KBufferBuilder builder; 596 JsonArraySerializer array { builder }; 597 for (auto& unveiled_path : process.unveiled_paths()) { 598 auto obj = array.add_object(); 599 obj.add("path", unveiled_path.path); 600 StringBuilder permissions_builder; 601 if (unveiled_path.permissions & UnveiledPath::Access::Read) 602 permissions_builder.append('r'); 603 if (unveiled_path.permissions & UnveiledPath::Access::Write) 604 permissions_builder.append('w'); 605 if (unveiled_path.permissions & UnveiledPath::Access::Execute) 606 permissions_builder.append('x'); 607 if (unveiled_path.permissions & UnveiledPath::Access::CreateOrRemove) 608 permissions_builder.append('c'); 609 obj.add("permissions", permissions_builder.to_string()); 610 } 611 array.finish(); 612 return builder.build(); 613} 614 615Optional<KBuffer> procfs$pid_stack(InodeIdentifier identifier) 616{ 617 auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier)); 618 if (!handle) 619 return {}; 620 auto& process = handle->process(); 621 return process.backtrace(*handle); 622} 623 624Optional<KBuffer> procfs$pid_regs(InodeIdentifier identifier) 625{ 626 auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier)); 627 if (!handle) 628 return {}; 629 auto& process = handle->process(); 630 KBufferBuilder builder; 631 process.for_each_thread([&](Thread& thread) { 632 builder.appendf("Thread %d:\n", thread.tid()); 633 auto& tss = thread.tss(); 634 builder.appendf("eax: %x\n", tss.eax); 635 builder.appendf("ebx: %x\n", tss.ebx); 636 builder.appendf("ecx: %x\n", tss.ecx); 637 builder.appendf("edx: %x\n", tss.edx); 638 builder.appendf("esi: %x\n", tss.esi); 639 builder.appendf("edi: %x\n", tss.edi); 640 builder.appendf("ebp: %x\n", tss.ebp); 641 builder.appendf("cr3: %x\n", tss.cr3); 642 builder.appendf("flg: %x\n", tss.eflags); 643 builder.appendf("sp: %w:%x\n", tss.ss, tss.esp); 644 builder.appendf("pc: %w:%x\n", tss.cs, tss.eip); 645 return IterationDecision::Continue; 646 }); 647 return builder.build(); 648} 649 650Optional<KBuffer> procfs$pid_exe(InodeIdentifier identifier) 651{ 652 auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier)); 653 if (!handle) 654 return {}; 655 auto& process = handle->process(); 656 auto* custody = process.executable(); 657 ASSERT(custody); 658 return custody->absolute_path().to_byte_buffer(); 659} 660 661Optional<KBuffer> procfs$pid_cwd(InodeIdentifier identifier) 662{ 663 auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier)); 664 if (!handle) 665 return {}; 666 return handle->process().current_directory().absolute_path().to_byte_buffer(); 667} 668 669Optional<KBuffer> procfs$pid_root(InodeIdentifier identifier) 670{ 671 auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier)); 672 if (!handle) 673 return {}; 674 return handle->process().root_directory_relative_to_global_root().absolute_path().to_byte_buffer(); 675} 676 677Optional<KBuffer> procfs$self(InodeIdentifier) 678{ 679 char buffer[16]; 680 sprintf(buffer, "%u", Process::current->pid()); 681 return KBuffer::copy((const u8*)buffer, strlen(buffer)); 682} 683 684Optional<KBuffer> procfs$mm(InodeIdentifier) 685{ 686 InterruptDisabler disabler; 687 KBufferBuilder builder; 688 u32 vmobject_count = 0; 689 MemoryManager::for_each_vmobject([&](auto& vmobject) { 690 ++vmobject_count; 691 builder.appendf("VMObject: %p %s(%u): p:%4u\n", 692 &vmobject, 693 vmobject.is_anonymous() ? "anon" : "file", 694 vmobject.ref_count(), 695 vmobject.page_count()); 696 return IterationDecision::Continue; 697 }); 698 builder.appendf("VMO count: %u\n", vmobject_count); 699 builder.appendf("Free physical pages: %u\n", MM.user_physical_pages() - MM.user_physical_pages_used()); 700 builder.appendf("Free supervisor physical pages: %u\n", MM.super_physical_pages() - MM.super_physical_pages_used()); 701 return builder.build(); 702} 703 704Optional<KBuffer> procfs$dmesg(InodeIdentifier) 705{ 706 InterruptDisabler disabler; 707 KBufferBuilder builder; 708 for (char ch : Console::the().logbuffer()) 709 builder.append(ch); 710 return builder.build(); 711} 712 713Optional<KBuffer> procfs$mounts(InodeIdentifier) 714{ 715 // FIXME: This is obviously racy against the VFS mounts changing. 716 KBufferBuilder builder; 717 VFS::the().for_each_mount([&builder](auto& mount) { 718 auto& fs = mount.guest_fs(); 719 builder.appendf("%s @ ", fs.class_name()); 720 if (!mount.host().is_valid()) 721 builder.appendf("/"); 722 else { 723 builder.appendf("%u:%u", mount.host().fsid(), mount.host().index()); 724 builder.append(' '); 725 builder.append(mount.absolute_path()); 726 } 727 builder.append('\n'); 728 }); 729 return builder.build(); 730} 731 732Optional<KBuffer> procfs$df(InodeIdentifier) 733{ 734 // FIXME: This is obviously racy against the VFS mounts changing. 735 KBufferBuilder builder; 736 JsonArraySerializer array { builder }; 737 VFS::the().for_each_mount([&array](auto& mount) { 738 auto& fs = mount.guest_fs(); 739 auto fs_object = array.add_object(); 740 fs_object.add("class_name", fs.class_name()); 741 fs_object.add("total_block_count", fs.total_block_count()); 742 fs_object.add("free_block_count", fs.free_block_count()); 743 fs_object.add("total_inode_count", fs.total_inode_count()); 744 fs_object.add("free_inode_count", fs.free_inode_count()); 745 fs_object.add("mount_point", mount.absolute_path()); 746 fs_object.add("block_size", fs.block_size()); 747 fs_object.add("readonly", fs.is_readonly()); 748 fs_object.add("mount_flags", mount.flags()); 749 750 if (fs.is_file_backed()) 751 fs_object.add("source", static_cast<const FileBackedFS&>(fs).file_description().absolute_path()); 752 else 753 fs_object.add("source", fs.class_name()); 754 }); 755 array.finish(); 756 return builder.build(); 757} 758 759Optional<KBuffer> procfs$cpuinfo(InodeIdentifier) 760{ 761 KBufferBuilder builder; 762 { 763 CPUID cpuid(0); 764 builder.appendf("cpuid: "); 765 auto emit_u32 = [&](u32 value) { 766 builder.appendf("%c%c%c%c", 767 value & 0xff, 768 (value >> 8) & 0xff, 769 (value >> 16) & 0xff, 770 (value >> 24) & 0xff); 771 }; 772 emit_u32(cpuid.ebx()); 773 emit_u32(cpuid.edx()); 774 emit_u32(cpuid.ecx()); 775 builder.appendf("\n"); 776 } 777 { 778 CPUID cpuid(1); 779 u32 stepping = cpuid.eax() & 0xf; 780 u32 model = (cpuid.eax() >> 4) & 0xf; 781 u32 family = (cpuid.eax() >> 8) & 0xf; 782 u32 type = (cpuid.eax() >> 12) & 0x3; 783 u32 extended_model = (cpuid.eax() >> 16) & 0xf; 784 u32 extended_family = (cpuid.eax() >> 20) & 0xff; 785 u32 display_model; 786 u32 display_family; 787 if (family == 15) { 788 display_family = family + extended_family; 789 display_model = model + (extended_model << 4); 790 } else if (family == 6) { 791 display_family = family; 792 display_model = model + (extended_model << 4); 793 } else { 794 display_family = family; 795 display_model = model; 796 } 797 builder.appendf("family: %u\n", display_family); 798 builder.appendf("model: %u\n", display_model); 799 builder.appendf("stepping: %u\n", stepping); 800 builder.appendf("type: %u\n", type); 801 } 802 { 803 // FIXME: Check first that this is supported by calling CPUID with eax=0x80000000 804 // and verifying that the returned eax>=0x80000004. 805 alignas(u32) char buffer[48]; 806 u32* bufptr = reinterpret_cast<u32*>(buffer); 807 auto copy_brand_string_part_to_buffer = [&](u32 i) { 808 CPUID cpuid(0x80000002 + i); 809 *bufptr++ = cpuid.eax(); 810 *bufptr++ = cpuid.ebx(); 811 *bufptr++ = cpuid.ecx(); 812 *bufptr++ = cpuid.edx(); 813 }; 814 copy_brand_string_part_to_buffer(0); 815 copy_brand_string_part_to_buffer(1); 816 copy_brand_string_part_to_buffer(2); 817 builder.appendf("brandstr: \"%s\"\n", buffer); 818 } 819 return builder.build(); 820} 821 822Optional<KBuffer> procfs$memstat(InodeIdentifier) 823{ 824 InterruptDisabler disabler; 825 KBufferBuilder builder; 826 JsonObjectSerializer<KBufferBuilder> json { builder }; 827 json.add("kmalloc_allocated", (u32)sum_alloc); 828 json.add("kmalloc_available", (u32)sum_free); 829 json.add("kmalloc_eternal_allocated", (u32)kmalloc_sum_eternal); 830 json.add("user_physical_allocated", MM.user_physical_pages_used()); 831 json.add("user_physical_available", MM.user_physical_pages() - MM.user_physical_pages_used()); 832 json.add("super_physical_allocated", MM.super_physical_pages_used()); 833 json.add("super_physical_available", MM.super_physical_pages() - MM.super_physical_pages_used()); 834 json.add("kmalloc_call_count", g_kmalloc_call_count); 835 json.add("kfree_call_count", g_kfree_call_count); 836 slab_alloc_stats([&json](size_t slab_size, size_t num_allocated, size_t num_free) { 837 auto prefix = String::format("slab_%zu", slab_size); 838 json.add(String::format("%s_num_allocated", prefix.characters()), (u32)num_allocated); 839 json.add(String::format("%s_num_free", prefix.characters()), (u32)num_free); 840 }); 841 json.finish(); 842 return builder.build(); 843} 844 845Optional<KBuffer> procfs$all(InodeIdentifier) 846{ 847 InterruptDisabler disabler; 848 auto processes = Process::all_processes(); 849 KBufferBuilder builder; 850 JsonArraySerializer array { builder }; 851 852 // Keep this in sync with CProcessStatistics. 853 auto build_process = [&](const Process& process) { 854 auto process_object = array.add_object(); 855 856 StringBuilder pledge_builder; 857#define __ENUMERATE_PLEDGE_PROMISE(promise) \ 858 if (process.has_promised(Pledge::promise)) { \ 859 pledge_builder.append(#promise " "); \ 860 } 861 ENUMERATE_PLEDGE_PROMISES 862#undef __ENUMERATE_PLEDGE_PROMISE 863 864 process_object.add("pledge", pledge_builder.to_string()); 865 866 switch (process.veil_state()) { 867 case VeilState::None: 868 process_object.add("veil", "None"); 869 break; 870 case VeilState::Dropped: 871 process_object.add("veil", "Dropped"); 872 break; 873 case VeilState::Locked: 874 process_object.add("veil", "Locked"); 875 break; 876 } 877 878 process_object.add("pid", process.pid()); 879 process_object.add("pgid", process.tty() ? process.tty()->pgid() : 0); 880 process_object.add("pgp", process.pgid()); 881 process_object.add("sid", process.sid()); 882 process_object.add("uid", process.uid()); 883 process_object.add("gid", process.gid()); 884 process_object.add("ppid", process.ppid()); 885 process_object.add("nfds", process.number_of_open_file_descriptors()); 886 process_object.add("name", process.name()); 887 process_object.add("tty", process.tty() ? process.tty()->tty_name() : "notty"); 888 process_object.add("amount_virtual", (u32)process.amount_virtual()); 889 process_object.add("amount_resident", (u32)process.amount_resident()); 890 process_object.add("amount_dirty_private", (u32)process.amount_dirty_private()); 891 process_object.add("amount_clean_inode", (u32)process.amount_clean_inode()); 892 process_object.add("amount_shared", (u32)process.amount_shared()); 893 process_object.add("amount_purgeable_volatile", (u32)process.amount_purgeable_volatile()); 894 process_object.add("amount_purgeable_nonvolatile", (u32)process.amount_purgeable_nonvolatile()); 895 process_object.add("icon_id", process.icon_id()); 896 auto thread_array = process_object.add_array("threads"); 897 process.for_each_thread([&](const Thread& thread) { 898 auto thread_object = thread_array.add_object(); 899 thread_object.add("tid", thread.tid()); 900 thread_object.add("name", thread.name()); 901 thread_object.add("times_scheduled", thread.times_scheduled()); 902 thread_object.add("ticks", thread.ticks()); 903 thread_object.add("state", thread.state_string()); 904 thread_object.add("priority", thread.priority()); 905 thread_object.add("effective_priority", thread.effective_priority()); 906 thread_object.add("syscall_count", thread.syscall_count()); 907 thread_object.add("inode_faults", thread.inode_faults()); 908 thread_object.add("zero_faults", thread.zero_faults()); 909 thread_object.add("cow_faults", thread.cow_faults()); 910 thread_object.add("file_read_bytes", thread.file_read_bytes()); 911 thread_object.add("file_write_bytes", thread.file_write_bytes()); 912 thread_object.add("unix_socket_read_bytes", thread.unix_socket_read_bytes()); 913 thread_object.add("unix_socket_write_bytes", thread.unix_socket_write_bytes()); 914 thread_object.add("ipv4_socket_read_bytes", thread.ipv4_socket_read_bytes()); 915 thread_object.add("ipv4_socket_write_bytes", thread.ipv4_socket_write_bytes()); 916 return IterationDecision::Continue; 917 }); 918 }; 919 build_process(*Scheduler::colonel()); 920 for (auto* process : processes) 921 build_process(*process); 922 array.finish(); 923 return builder.build(); 924} 925 926Optional<KBuffer> procfs$inodes(InodeIdentifier) 927{ 928 extern InlineLinkedList<Inode>& all_inodes(); 929 KBufferBuilder builder; 930 InterruptDisabler disabler; 931 for (auto& inode : all_inodes()) { 932 builder.appendf("Inode{K%x} %02u:%08u (%u)\n", &inode, inode.fsid(), inode.index(), inode.ref_count()); 933 } 934 return builder.build(); 935} 936 937struct SysVariable { 938 String name; 939 enum class Type : u8 { 940 Invalid, 941 Boolean, 942 String, 943 }; 944 Type type { Type::Invalid }; 945 Function<void()> notify_callback; 946 void* address { nullptr }; 947 948 static SysVariable& for_inode(InodeIdentifier); 949 950 void notify() 951 { 952 if (notify_callback) 953 notify_callback(); 954 } 955}; 956 957static Vector<SysVariable, 16>* s_sys_variables; 958 959static inline Vector<SysVariable, 16>& sys_variables() 960{ 961 if (s_sys_variables == nullptr) { 962 s_sys_variables = new Vector<SysVariable, 16>; 963 s_sys_variables->append({ "", SysVariable::Type::Invalid, nullptr, nullptr }); 964 } 965 return *s_sys_variables; 966} 967 968SysVariable& SysVariable::for_inode(InodeIdentifier id) 969{ 970 auto index = to_sys_index(id); 971 if (index >= sys_variables().size()) 972 return sys_variables()[0]; 973 auto& variable = sys_variables()[index]; 974 ASSERT(variable.address); 975 return variable; 976} 977 978static ByteBuffer read_sys_bool(InodeIdentifier inode_id) 979{ 980 auto& variable = SysVariable::for_inode(inode_id); 981 ASSERT(variable.type == SysVariable::Type::Boolean); 982 983 auto buffer = ByteBuffer::create_uninitialized(2); 984 auto* lockable_bool = reinterpret_cast<Lockable<bool>*>(variable.address); 985 { 986 LOCKER(lockable_bool->lock()); 987 buffer[0] = lockable_bool->resource() ? '1' : '0'; 988 } 989 buffer[1] = '\n'; 990 return buffer; 991} 992 993static ssize_t write_sys_bool(InodeIdentifier inode_id, const ByteBuffer& data) 994{ 995 auto& variable = SysVariable::for_inode(inode_id); 996 ASSERT(variable.type == SysVariable::Type::Boolean); 997 998 if (data.is_empty() || !(data[0] == '0' || data[0] == '1')) 999 return data.size(); 1000 1001 auto* lockable_bool = reinterpret_cast<Lockable<bool>*>(variable.address); 1002 { 1003 LOCKER(lockable_bool->lock()); 1004 lockable_bool->resource() = data[0] == '1'; 1005 } 1006 variable.notify(); 1007 return data.size(); 1008} 1009 1010static ByteBuffer read_sys_string(InodeIdentifier inode_id) 1011{ 1012 auto& variable = SysVariable::for_inode(inode_id); 1013 ASSERT(variable.type == SysVariable::Type::String); 1014 1015 auto* lockable_string = reinterpret_cast<Lockable<String>*>(variable.address); 1016 LOCKER(lockable_string->lock()); 1017 return lockable_string->resource().to_byte_buffer(); 1018} 1019 1020static ssize_t write_sys_string(InodeIdentifier inode_id, const ByteBuffer& data) 1021{ 1022 auto& variable = SysVariable::for_inode(inode_id); 1023 ASSERT(variable.type == SysVariable::Type::String); 1024 1025 { 1026 auto* lockable_string = reinterpret_cast<Lockable<String>*>(variable.address); 1027 LOCKER(lockable_string->lock()); 1028 lockable_string->resource() = String((const char*)data.data(), data.size()); 1029 } 1030 variable.notify(); 1031 return data.size(); 1032} 1033 1034void ProcFS::add_sys_bool(String&& name, Lockable<bool>& var, Function<void()>&& notify_callback) 1035{ 1036 InterruptDisabler disabler; 1037 1038 SysVariable variable; 1039 variable.name = move(name); 1040 variable.type = SysVariable::Type::Boolean; 1041 variable.notify_callback = move(notify_callback); 1042 variable.address = &var; 1043 1044 sys_variables().append(move(variable)); 1045} 1046 1047void ProcFS::add_sys_string(String&& name, Lockable<String>& var, Function<void()>&& notify_callback) 1048{ 1049 InterruptDisabler disabler; 1050 1051 SysVariable variable; 1052 variable.name = move(name); 1053 variable.type = SysVariable::Type::String; 1054 variable.notify_callback = move(notify_callback); 1055 variable.address = &var; 1056 1057 sys_variables().append(move(variable)); 1058} 1059 1060bool ProcFS::initialize() 1061{ 1062 static Lockable<bool>* kmalloc_stack_helper; 1063 1064 if (kmalloc_stack_helper == nullptr) { 1065 kmalloc_stack_helper = new Lockable<bool>(); 1066 kmalloc_stack_helper->resource() = g_dump_kmalloc_stacks; 1067 ProcFS::add_sys_bool("kmalloc_stacks", *kmalloc_stack_helper, [] { 1068 g_dump_kmalloc_stacks = kmalloc_stack_helper->resource(); 1069 }); 1070 } 1071 return true; 1072} 1073 1074const char* ProcFS::class_name() const 1075{ 1076 return "ProcFS"; 1077} 1078 1079KResultOr<NonnullRefPtr<Inode>> ProcFS::create_inode(InodeIdentifier, const String&, mode_t, off_t, dev_t, uid_t, gid_t) 1080{ 1081 return KResult(-EROFS); 1082} 1083 1084KResult ProcFS::create_directory(InodeIdentifier, const String&, mode_t, uid_t, gid_t) 1085{ 1086 return KResult(-EROFS); 1087} 1088 1089InodeIdentifier ProcFS::root_inode() const 1090{ 1091 return { fsid(), FI_Root }; 1092} 1093 1094RefPtr<Inode> ProcFS::get_inode(InodeIdentifier inode_id) const 1095{ 1096#ifdef PROCFS_DEBUG 1097 dbg() << "ProcFS::get_inode(" << inode_id.index() << ")"; 1098#endif 1099 if (inode_id == root_inode()) 1100 return m_root_inode; 1101 1102 LOCKER(m_inodes_lock); 1103 auto it = m_inodes.find(inode_id.index()); 1104 if (it == m_inodes.end()) { 1105 auto inode = adopt(*new ProcFSInode(const_cast<ProcFS&>(*this), inode_id.index())); 1106 m_inodes.set(inode_id.index(), inode.ptr()); 1107 return inode; 1108 } 1109 return (*it).value; 1110} 1111 1112ProcFSInode::ProcFSInode(ProcFS& fs, unsigned index) 1113 : Inode(fs, index) 1114{ 1115} 1116 1117ProcFSInode::~ProcFSInode() 1118{ 1119 LOCKER(fs().m_inodes_lock); 1120 fs().m_inodes.remove(index()); 1121} 1122 1123InodeMetadata ProcFSInode::metadata() const 1124{ 1125#ifdef PROCFS_DEBUG 1126 dbg() << "ProcFSInode::metadata(" << index() << ")"; 1127#endif 1128 InodeMetadata metadata; 1129 metadata.inode = identifier(); 1130 metadata.ctime = mepoch; 1131 metadata.atime = mepoch; 1132 metadata.mtime = mepoch; 1133 auto proc_parent_directory = to_proc_parent_directory(identifier()); 1134 auto pid = to_pid(identifier()); 1135 auto proc_file_type = to_proc_file_type(identifier()); 1136 1137#ifdef PROCFS_DEBUG 1138 dbg() << " -> pid: " << pid << ", fi: " << proc_file_type << ", pdi: " << proc_parent_directory; 1139#endif 1140 1141 if (is_process_related_file(identifier())) { 1142 auto handle = ProcessInspectionHandle::from_pid(pid); 1143 metadata.uid = handle->process().sys$getuid(); 1144 metadata.gid = handle->process().sys$getgid(); 1145 } 1146 1147 if (proc_parent_directory == PDI_PID_fd) { 1148 metadata.mode = 00120700; 1149 return metadata; 1150 } 1151 1152 switch (proc_file_type) { 1153 case FI_Root_self: 1154 metadata.mode = 0120444; 1155 break; 1156 case FI_PID_cwd: 1157 case FI_PID_exe: 1158 case FI_PID_root: 1159 metadata.mode = 0120400; 1160 break; 1161 case FI_Root: 1162 case FI_Root_sys: 1163 case FI_Root_net: 1164 metadata.mode = 040555; 1165 break; 1166 case FI_PID: 1167 case FI_PID_fd: 1168 metadata.mode = 040500; 1169 break; 1170 default: 1171 metadata.mode = 0100444; 1172 break; 1173 } 1174 1175 if (proc_file_type > FI_Invalid && proc_file_type < FI_MaxStaticFileIndex) { 1176 if (fs().m_entries[proc_file_type].supervisor_only) { 1177 metadata.uid = 0; 1178 metadata.gid = 0; 1179 metadata.mode &= ~077; 1180 } 1181 } 1182 1183#ifdef PROCFS_DEBUG 1184 dbg() << "Returning mode " << String::format("%o", metadata.mode); 1185#endif 1186 return metadata; 1187} 1188 1189ssize_t ProcFSInode::read_bytes(off_t offset, ssize_t count, u8* buffer, FileDescription* description) const 1190{ 1191#ifdef PROCFS_DEBUG 1192 dbg() << "ProcFS: read_bytes " << index(); 1193#endif 1194 ASSERT(offset >= 0); 1195 ASSERT(buffer); 1196 1197 auto* directory_entry = fs().get_directory_entry(identifier()); 1198 1199 Function<Optional<KBuffer>(InodeIdentifier)> callback_tmp; 1200 Function<Optional<KBuffer>(InodeIdentifier)>* read_callback { nullptr }; 1201 if (directory_entry) 1202 read_callback = &directory_entry->read_callback; 1203 else 1204 switch (to_proc_parent_directory(identifier())) { 1205 case PDI_PID_fd: 1206 callback_tmp = procfs$pid_fd_entry; 1207 read_callback = &callback_tmp; 1208 break; 1209 case PDI_Root_sys: 1210 switch (SysVariable::for_inode(identifier()).type) { 1211 case SysVariable::Type::Invalid: 1212 ASSERT_NOT_REACHED(); 1213 case SysVariable::Type::Boolean: 1214 callback_tmp = read_sys_bool; 1215 break; 1216 case SysVariable::Type::String: 1217 callback_tmp = read_sys_string; 1218 break; 1219 } 1220 read_callback = &callback_tmp; 1221 break; 1222 default: 1223 ASSERT_NOT_REACHED(); 1224 } 1225 1226 ASSERT(read_callback); 1227 1228 Optional<KBuffer> generated_data; 1229 if (!description) { 1230 generated_data = (*read_callback)(identifier()); 1231 } else { 1232 if (!description->generator_cache().has_value()) 1233 description->generator_cache() = (*read_callback)(identifier()); 1234 generated_data = description->generator_cache(); 1235 } 1236 1237 auto& data = generated_data; 1238 if (!data.has_value()) 1239 return 0; 1240 1241 if ((size_t)offset >= data.value().size()) 1242 return 0; 1243 1244 ssize_t nread = min(static_cast<off_t>(data.value().size() - offset), static_cast<off_t>(count)); 1245 memcpy(buffer, data.value().data() + offset, nread); 1246 if (nread == 0 && description && description->generator_cache().has_value()) 1247 description->generator_cache().clear(); 1248 1249 return nread; 1250} 1251 1252InodeIdentifier ProcFS::ProcFSDirectoryEntry::identifier(unsigned fsid) const 1253{ 1254 return to_identifier(fsid, PDI_Root, 0, (ProcFileType)proc_file_type); 1255} 1256 1257bool ProcFSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntry&)> callback) const 1258{ 1259#ifdef PROCFS_DEBUG 1260 dbg() << "ProcFS: traverse_as_directory " << index(); 1261#endif 1262 1263 if (!Kernel::is_directory(identifier())) 1264 return false; 1265 1266 auto pid = to_pid(identifier()); 1267 auto proc_file_type = to_proc_file_type(identifier()); 1268 auto parent_id = to_parent_id(identifier()); 1269 1270 callback({ ".", 1, identifier(), 2 }); 1271 callback({ "..", 2, parent_id, 2 }); 1272 1273 switch (proc_file_type) { 1274 case FI_Root: 1275 for (auto& entry : fs().m_entries) { 1276 // FIXME: strlen() here is sad. 1277 if (!entry.name) 1278 continue; 1279 if (entry.proc_file_type > __FI_Root_Start && entry.proc_file_type < __FI_Root_End) 1280 callback({ entry.name, strlen(entry.name), to_identifier(fsid(), PDI_Root, 0, (ProcFileType)entry.proc_file_type), 0 }); 1281 } 1282 for (auto pid_child : Process::all_pids()) { 1283 char name[16]; 1284 size_t name_length = (size_t)sprintf(name, "%u", pid_child); 1285 callback({ name, name_length, to_identifier(fsid(), PDI_Root, pid_child, FI_PID), 0 }); 1286 } 1287 break; 1288 1289 case FI_Root_sys: 1290 for (size_t i = 1; i < sys_variables().size(); ++i) { 1291 auto& variable = sys_variables()[i]; 1292 callback({ variable.name.characters(), variable.name.length(), sys_var_to_identifier(fsid(), i), 0 }); 1293 } 1294 break; 1295 1296 case FI_Root_net: 1297 callback({ "adapters", 8, to_identifier(fsid(), PDI_Root_net, 0, FI_Root_net_adapters), 0 }); 1298 callback({ "arp", 3, to_identifier(fsid(), PDI_Root_net, 0, FI_Root_net_arp), 0 }); 1299 callback({ "tcp", 3, to_identifier(fsid(), PDI_Root_net, 0, FI_Root_net_tcp), 0 }); 1300 callback({ "udp", 3, to_identifier(fsid(), PDI_Root_net, 0, FI_Root_net_udp), 0 }); 1301 callback({ "local", 5, to_identifier(fsid(), PDI_Root_net, 0, FI_Root_net_local), 0 }); 1302 break; 1303 1304 case FI_PID: { 1305 auto handle = ProcessInspectionHandle::from_pid(pid); 1306 if (!handle) 1307 return false; 1308 auto& process = handle->process(); 1309 for (auto& entry : fs().m_entries) { 1310 if (entry.proc_file_type > __FI_PID_Start && entry.proc_file_type < __FI_PID_End) { 1311 if (entry.proc_file_type == FI_PID_exe && !process.executable()) 1312 continue; 1313 // FIXME: strlen() here is sad. 1314 callback({ entry.name, strlen(entry.name), to_identifier(fsid(), PDI_PID, pid, (ProcFileType)entry.proc_file_type), 0 }); 1315 } 1316 } 1317 } break; 1318 1319 case FI_PID_fd: { 1320 auto handle = ProcessInspectionHandle::from_pid(pid); 1321 if (!handle) 1322 return false; 1323 auto& process = handle->process(); 1324 for (int i = 0; i < process.max_open_file_descriptors(); ++i) { 1325 auto description = process.file_description(i); 1326 if (!description) 1327 continue; 1328 char name[16]; 1329 size_t name_length = (size_t)sprintf(name, "%u", i); 1330 callback({ name, name_length, to_identifier_with_fd(fsid(), pid, i), 0 }); 1331 } 1332 } break; 1333 default: 1334 return true; 1335 } 1336 1337 return true; 1338} 1339 1340RefPtr<Inode> ProcFSInode::lookup(StringView name) 1341{ 1342 ASSERT(is_directory()); 1343 if (name == ".") 1344 return fs().get_inode(identifier()); 1345 if (name == "..") 1346 return fs().get_inode(to_parent_id(identifier())); 1347 1348 auto proc_file_type = to_proc_file_type(identifier()); 1349 1350 if (proc_file_type == FI_Root) { 1351 for (auto& entry : fs().m_entries) { 1352 if (entry.name == nullptr) 1353 continue; 1354 if (entry.proc_file_type > __FI_Root_Start && entry.proc_file_type < __FI_Root_End) { 1355 if (name == entry.name) { 1356 return fs().get_inode(to_identifier(fsid(), PDI_Root, 0, (ProcFileType)entry.proc_file_type)); 1357 } 1358 } 1359 } 1360 bool ok; 1361 unsigned name_as_number = name.to_uint(ok); 1362 if (ok) { 1363 bool process_exists = false; 1364 { 1365 InterruptDisabler disabler; 1366 process_exists = Process::from_pid(name_as_number); 1367 } 1368 if (process_exists) 1369 return fs().get_inode(to_identifier(fsid(), PDI_Root, name_as_number, FI_PID)); 1370 } 1371 return {}; 1372 } 1373 1374 if (proc_file_type == FI_Root_sys) { 1375 for (size_t i = 1; i < sys_variables().size(); ++i) { 1376 auto& variable = sys_variables()[i]; 1377 if (name == variable.name) 1378 return fs().get_inode(sys_var_to_identifier(fsid(), i)); 1379 } 1380 return {}; 1381 } 1382 1383 if (proc_file_type == FI_Root_net) { 1384 if (name == "adapters") 1385 return fs().get_inode(to_identifier(fsid(), PDI_Root, 0, FI_Root_net_adapters)); 1386 if (name == "arp") 1387 return fs().get_inode(to_identifier(fsid(), PDI_Root, 0, FI_Root_net_arp)); 1388 if (name == "tcp") 1389 return fs().get_inode(to_identifier(fsid(), PDI_Root, 0, FI_Root_net_tcp)); 1390 if (name == "udp") 1391 return fs().get_inode(to_identifier(fsid(), PDI_Root, 0, FI_Root_net_udp)); 1392 if (name == "local") 1393 return fs().get_inode(to_identifier(fsid(), PDI_Root, 0, FI_Root_net_local)); 1394 return {}; 1395 } 1396 1397 if (proc_file_type == FI_PID) { 1398 auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier())); 1399 if (!handle) 1400 return {}; 1401 auto& process = handle->process(); 1402 for (auto& entry : fs().m_entries) { 1403 if (entry.proc_file_type > __FI_PID_Start && entry.proc_file_type < __FI_PID_End) { 1404 if (entry.proc_file_type == FI_PID_exe && !process.executable()) 1405 continue; 1406 if (entry.name == nullptr) 1407 continue; 1408 if (name == entry.name) { 1409 return fs().get_inode(to_identifier(fsid(), PDI_PID, to_pid(identifier()), (ProcFileType)entry.proc_file_type)); 1410 } 1411 } 1412 } 1413 return {}; 1414 } 1415 1416 if (proc_file_type == FI_PID_fd) { 1417 bool ok; 1418 unsigned name_as_number = name.to_uint(ok); 1419 if (ok) { 1420 bool fd_exists = false; 1421 { 1422 InterruptDisabler disabler; 1423 if (auto* process = Process::from_pid(to_pid(identifier()))) 1424 fd_exists = process->file_description(name_as_number); 1425 } 1426 if (fd_exists) 1427 return fs().get_inode(to_identifier_with_fd(fsid(), to_pid(identifier()), name_as_number)); 1428 } 1429 } 1430 return {}; 1431} 1432 1433void ProcFSInode::flush_metadata() 1434{ 1435} 1436 1437ssize_t ProcFSInode::write_bytes(off_t offset, ssize_t size, const u8* buffer, FileDescription*) 1438{ 1439 auto result = prepare_to_write_data(); 1440 if (result.is_error()) 1441 return result; 1442 1443 auto* directory_entry = fs().get_directory_entry(identifier()); 1444 1445 Function<ssize_t(InodeIdentifier, const ByteBuffer&)> callback_tmp; 1446 Function<ssize_t(InodeIdentifier, const ByteBuffer&)>* write_callback { nullptr }; 1447 1448 if (directory_entry == nullptr) { 1449 if (to_proc_parent_directory(identifier()) == PDI_Root_sys) { 1450 switch (SysVariable::for_inode(identifier()).type) { 1451 case SysVariable::Type::Invalid: 1452 ASSERT_NOT_REACHED(); 1453 case SysVariable::Type::Boolean: 1454 callback_tmp = write_sys_bool; 1455 break; 1456 case SysVariable::Type::String: 1457 callback_tmp = write_sys_string; 1458 break; 1459 } 1460 write_callback = &callback_tmp; 1461 } else 1462 return -EPERM; 1463 } else { 1464 if (!directory_entry->write_callback) 1465 return -EPERM; 1466 write_callback = &directory_entry->write_callback; 1467 } 1468 1469 ASSERT(is_persistent_inode(identifier())); 1470 // FIXME: Being able to write into ProcFS at a non-zero offset seems like something we should maybe support.. 1471 ASSERT(offset == 0); 1472 bool success = (*write_callback)(identifier(), ByteBuffer::wrap(buffer, size)); 1473 ASSERT(success); 1474 return 0; 1475} 1476 1477KResultOr<NonnullRefPtr<Custody>> ProcFSInode::resolve_as_link(Custody& base, RefPtr<Custody>* out_parent, int options, int symlink_recursion_level) const 1478{ 1479 if (!is_process_related_file(identifier())) 1480 return Inode::resolve_as_link(base, out_parent, options, symlink_recursion_level); 1481 1482 // FIXME: We should return a custody for FI_PID or FI_PID_fd here 1483 // for correctness. It's impossible to create files in ProcFS, 1484 // so returning null shouldn't break much. 1485 if (out_parent) 1486 *out_parent = nullptr; 1487 1488 auto pid = to_pid(identifier()); 1489 auto proc_file_type = to_proc_file_type(identifier()); 1490 auto handle = ProcessInspectionHandle::from_pid(pid); 1491 if (!handle) 1492 return KResult(-ENOENT); 1493 auto& process = handle->process(); 1494 1495 if (to_proc_parent_directory(identifier()) == PDI_PID_fd) { 1496 if (out_parent) 1497 *out_parent = base; 1498 int fd = to_fd(identifier()); 1499 auto description = process.file_description(fd); 1500 if (!description) 1501 return KResult(-ENOENT); 1502 auto proxy_inode = ProcFSProxyInode::create(const_cast<ProcFS&>(fs()), *description); 1503 return Custody::create(&base, "", proxy_inode, base.mount_flags()); 1504 } 1505 1506 Custody* res = nullptr; 1507 1508 switch (proc_file_type) { 1509 case FI_PID_cwd: 1510 res = &process.current_directory(); 1511 break; 1512 case FI_PID_exe: 1513 res = process.executable(); 1514 break; 1515 case FI_PID_root: 1516 // Note: we open root_directory() here, not 1517 // root_directory_relative_to_global_root(). 1518 // This seems more useful. 1519 res = &process.root_directory(); 1520 break; 1521 default: 1522 ASSERT_NOT_REACHED(); 1523 } 1524 1525 if (!res) 1526 return KResult(-ENOENT); 1527 1528 return *res; 1529} 1530 1531ProcFSProxyInode::ProcFSProxyInode(ProcFS& fs, FileDescription& fd) 1532 : Inode(fs, 0) 1533 , m_fd(fd) 1534{ 1535} 1536 1537ProcFSProxyInode::~ProcFSProxyInode() 1538{ 1539} 1540 1541InodeMetadata ProcFSProxyInode::metadata() const 1542{ 1543 InodeMetadata metadata = m_fd->metadata(); 1544 1545 if (m_fd->is_readable()) 1546 metadata.mode |= 0444; 1547 else 1548 metadata.mode &= ~0444; 1549 1550 if (m_fd->is_writable()) 1551 metadata.mode |= 0222; 1552 else 1553 metadata.mode &= ~0222; 1554 1555 if (!metadata.is_directory()) 1556 metadata.mode &= ~0111; 1557 1558 return metadata; 1559} 1560 1561KResult ProcFSProxyInode::add_child(InodeIdentifier child_id, const StringView& name, mode_t mode) 1562{ 1563 if (!m_fd->inode()) 1564 return KResult(-EINVAL); 1565 return m_fd->inode()->add_child(child_id, name, mode); 1566} 1567 1568KResult ProcFSProxyInode::remove_child(const StringView& name) 1569{ 1570 if (!m_fd->inode()) 1571 return KResult(-EINVAL); 1572 return m_fd->inode()->remove_child(name); 1573} 1574 1575RefPtr<Inode> ProcFSProxyInode::lookup(StringView name) 1576{ 1577 if (!m_fd->inode()) 1578 return {}; 1579 return m_fd->inode()->lookup(name); 1580} 1581 1582size_t ProcFSProxyInode::directory_entry_count() const 1583{ 1584 if (!m_fd->inode()) 1585 return 0; 1586 return m_fd->inode()->directory_entry_count(); 1587} 1588 1589KResult ProcFSInode::add_child(InodeIdentifier child_id, const StringView& name, mode_t) 1590{ 1591 (void)child_id; 1592 (void)name; 1593 return KResult(-EPERM); 1594} 1595 1596KResult ProcFSInode::remove_child(const StringView& name) 1597{ 1598 (void)name; 1599 return KResult(-EPERM); 1600} 1601 1602size_t ProcFSInode::directory_entry_count() const 1603{ 1604 ASSERT(is_directory()); 1605 size_t count = 0; 1606 traverse_as_directory([&count](const FS::DirectoryEntry&) { 1607 ++count; 1608 return true; 1609 }); 1610 return count; 1611} 1612 1613KResult ProcFSInode::chmod(mode_t) 1614{ 1615 return KResult(-EPERM); 1616} 1617 1618ProcFS::ProcFS() 1619{ 1620 m_root_inode = adopt(*new ProcFSInode(*this, 1)); 1621 m_entries.resize(FI_MaxStaticFileIndex); 1622 m_entries[FI_Root_mm] = { "mm", FI_Root_mm, true, procfs$mm }; 1623 m_entries[FI_Root_mounts] = { "mounts", FI_Root_mounts, false, procfs$mounts }; 1624 m_entries[FI_Root_df] = { "df", FI_Root_df, false, procfs$df }; 1625 m_entries[FI_Root_all] = { "all", FI_Root_all, false, procfs$all }; 1626 m_entries[FI_Root_memstat] = { "memstat", FI_Root_memstat, false, procfs$memstat }; 1627 m_entries[FI_Root_cpuinfo] = { "cpuinfo", FI_Root_cpuinfo, false, procfs$cpuinfo }; 1628 m_entries[FI_Root_inodes] = { "inodes", FI_Root_inodes, true, procfs$inodes }; 1629 m_entries[FI_Root_dmesg] = { "dmesg", FI_Root_dmesg, true, procfs$dmesg }; 1630 m_entries[FI_Root_self] = { "self", FI_Root_self, false, procfs$self }; 1631 m_entries[FI_Root_pci] = { "pci", FI_Root_pci, false, procfs$pci }; 1632 m_entries[FI_Root_interrupts] = { "interrupts", FI_Root_interrupts, false, procfs$interrupts }; 1633 m_entries[FI_Root_devices] = { "devices", FI_Root_devices, false, procfs$devices }; 1634 m_entries[FI_Root_uptime] = { "uptime", FI_Root_uptime, false, procfs$uptime }; 1635 m_entries[FI_Root_cmdline] = { "cmdline", FI_Root_cmdline, true, procfs$cmdline }; 1636 m_entries[FI_Root_modules] = { "modules", FI_Root_modules, true, procfs$modules }; 1637 m_entries[FI_Root_profile] = { "profile", FI_Root_profile, false, procfs$profile }; 1638 m_entries[FI_Root_sys] = { "sys", FI_Root_sys, true }; 1639 m_entries[FI_Root_net] = { "net", FI_Root_net, false }; 1640 1641 m_entries[FI_Root_net_adapters] = { "adapters", FI_Root_net_adapters, false, procfs$net_adapters }; 1642 m_entries[FI_Root_net_arp] = { "arp", FI_Root_net_arp, true, procfs$net_arp }; 1643 m_entries[FI_Root_net_tcp] = { "tcp", FI_Root_net_tcp, false, procfs$net_tcp }; 1644 m_entries[FI_Root_net_udp] = { "udp", FI_Root_net_udp, false, procfs$net_udp }; 1645 m_entries[FI_Root_net_local] = { "local", FI_Root_net_local, false, procfs$net_local }; 1646 1647 m_entries[FI_PID_vm] = { "vm", FI_PID_vm, false, procfs$pid_vm }; 1648 m_entries[FI_PID_vmobjects] = { "vmobjects", FI_PID_vmobjects, true, procfs$pid_vmobjects }; 1649 m_entries[FI_PID_stack] = { "stack", FI_PID_stack, false, procfs$pid_stack }; 1650 m_entries[FI_PID_regs] = { "regs", FI_PID_regs, true, procfs$pid_regs }; 1651 m_entries[FI_PID_fds] = { "fds", FI_PID_fds, false, procfs$pid_fds }; 1652 m_entries[FI_PID_exe] = { "exe", FI_PID_exe, false, procfs$pid_exe }; 1653 m_entries[FI_PID_cwd] = { "cwd", FI_PID_cwd, false, procfs$pid_cwd }; 1654 m_entries[FI_PID_unveil] = { "unveil", FI_PID_unveil, false, procfs$pid_unveil }; 1655 m_entries[FI_PID_root] = { "root", FI_PID_root, false, procfs$pid_root }; 1656 m_entries[FI_PID_fd] = { "fd", FI_PID_fd, false }; 1657} 1658 1659ProcFS::ProcFSDirectoryEntry* ProcFS::get_directory_entry(InodeIdentifier identifier) const 1660{ 1661 auto proc_file_type = to_proc_file_type(identifier); 1662 if (proc_file_type != FI_Invalid && proc_file_type != FI_Root_sys_variable && proc_file_type < FI_MaxStaticFileIndex) 1663 return const_cast<ProcFSDirectoryEntry*>(&m_entries[proc_file_type]); 1664 return nullptr; 1665} 1666 1667KResult ProcFSInode::chown(uid_t, gid_t) 1668{ 1669 return KResult(-EPERM); 1670} 1671 1672}