From 9f188837ae56e423c302afffb651ab2c653a450a Mon Sep 17 00:00:00 2001 From: Fabing Li Date: Mon, 14 Oct 2024 03:45:13 +0000 Subject: [PATCH] Add /proc/[pid]/stat and /proc/[pid]/status --- .typos.toml | 1 + kernel/src/fs/file_table.rs | 12 +++- kernel/src/fs/procfs/pid/mod.rs | 10 ++++ kernel/src/fs/procfs/pid/stat.rs | 47 ++++++++++++++++ kernel/src/fs/procfs/pid/status.rs | 89 ++++++++++++++++++++++++++++++ 5 files changed, 157 insertions(+), 2 deletions(-) create mode 100644 kernel/src/fs/procfs/pid/stat.rs create mode 100644 kernel/src/fs/procfs/pid/status.rs diff --git a/.typos.toml b/.typos.toml index 7acb6d861..b76fc0ec9 100644 --- a/.typos.toml +++ b/.typos.toml @@ -13,6 +13,7 @@ TME = "TME" BA = "BA" ND = "ND" Fo = "Fo" +Inh = "Inh" # Files with svg suffix are ignored to check. [type.svg] diff --git a/kernel/src/fs/file_table.rs b/kernel/src/fs/file_table.rs index dbdda393c..678dc230b 100644 --- a/kernel/src/fs/file_table.rs +++ b/kernel/src/fs/file_table.rs @@ -66,6 +66,14 @@ impl FileTable { } } + pub fn len(&self) -> usize { + self.table.slots_len() + } + + pub fn is_empty(&self) -> bool { + self.table.is_empty() + } + pub fn dup(&mut self, fd: FileDesc, new_fd: FileDesc, flags: FdFlags) -> Result { let file = self .table @@ -80,12 +88,12 @@ impl FileTable { return new_fd; } - for idx in new_fd + 1..self.table.slots_len() { + for idx in new_fd + 1..self.len() { if self.table.get(idx).is_none() { return idx; } } - self.table.slots_len() + self.len() }; let min_free_fd = get_min_free_fd(); diff --git a/kernel/src/fs/procfs/pid/mod.rs b/kernel/src/fs/procfs/pid/mod.rs index 8d2b7fbcd..c8f563138 100644 --- a/kernel/src/fs/procfs/pid/mod.rs +++ b/kernel/src/fs/procfs/pid/mod.rs @@ -16,6 +16,8 @@ mod cmdline; mod comm; mod exe; mod fd; +mod stat; +mod status; /// Represents the inode at `/proc/[pid]`. pub struct PidDirOps(Arc); @@ -51,6 +53,8 @@ impl DirOps for PidDirOps { "comm" => CommFileOps::new_inode(self.0.clone(), this_ptr.clone()), "fd" => FdDirOps::new_inode(self.0.clone(), this_ptr.clone()), "cmdline" => CmdlineFileOps::new_inode(self.0.clone(), this_ptr.clone()), + "status" => status::StatusFileOps::new_inode(self.0.clone(), this_ptr.clone()), + "stat" => stat::StatFileOps::new_inode(self.0.clone(), this_ptr.clone()), _ => return_errno!(Errno::ENOENT), }; Ok(inode) @@ -74,5 +78,11 @@ impl DirOps for PidDirOps { cached_children.put_entry_if_not_found("cmdline", || { CmdlineFileOps::new_inode(self.0.clone(), this_ptr.clone()) }); + cached_children.put_entry_if_not_found("status", || { + status::StatusFileOps::new_inode(self.0.clone(), this_ptr.clone()) + }); + cached_children.put_entry_if_not_found("stat", || { + stat::StatFileOps::new_inode(self.0.clone(), this_ptr.clone()) + }); } } diff --git a/kernel/src/fs/procfs/pid/stat.rs b/kernel/src/fs/procfs/pid/stat.rs new file mode 100644 index 000000000..a2a601b8d --- /dev/null +++ b/kernel/src/fs/procfs/pid/stat.rs @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: MPL-2.0 + +use core::fmt::Write; + +use crate::{ + fs::{ + procfs::template::{FileOps, ProcFileBuilder}, + utils::Inode, + }, + prelude::*, + Process, +}; + +/// Represents the inode at `/proc/[pid]/stat`. +/// The fields are the same as the ones in `/proc/[pid]/status`. But the format is different. +/// See https://github.com/torvalds/linux/blob/ce1c54fdff7c4556b08f5b875a331d8952e8b6b7/fs/proc/array.c#L467 +/// FIXME: Some fields are not implemented yet. +pub struct StatFileOps(Arc); + +impl StatFileOps { + pub fn new_inode(process_ref: Arc, parent: Weak) -> Arc { + ProcFileBuilder::new(Self(process_ref)) + .parent(parent) + .build() + .unwrap() + } +} + +impl FileOps for StatFileOps { + fn data(&self) -> Result> { + let process = &self.0; + let mut stat_output = String::new(); + writeln!( + stat_output, + "{} {} {} {} {} {} {}", + process.executable_path(), + process.pid(), + process.pid(), + process.parent().pid(), + process.parent().pid(), + process.file_table().lock().len(), + process.tasks().lock().len() + ) + .unwrap(); + Ok(stat_output.into_bytes()) + } +} diff --git a/kernel/src/fs/procfs/pid/status.rs b/kernel/src/fs/procfs/pid/status.rs new file mode 100644 index 000000000..072434ac3 --- /dev/null +++ b/kernel/src/fs/procfs/pid/status.rs @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: MPL-2.0 + +use core::fmt::Write; + +use crate::{ + fs::{ + procfs::template::{FileOps, ProcFileBuilder}, + utils::Inode, + }, + prelude::*, + Process, +}; + +/// Represents the inode at `/proc/[pid]/status`. +/// See https://github.com/torvalds/linux/blob/ce1c54fdff7c4556b08f5b875a331d8952e8b6b7/fs/proc/array.c#L148 +/// FIXME: Some fields are not implemented yet. +/// +/// Fields: +/// - Name: The name of the process. +/// - State: The current state of the process (e.g., R for running, S for sleeping). +/// - Tgid: The Thread Group ID, which is the same as the process ID for the main thread. +/// - Pid: The process ID. +/// - PPid: The parent process ID. +/// - TracerPid: The PID of the process tracing this process, or 0 if not being traced. +/// - Uid: Real, effective, saved set, and filesystem UIDs. +/// - Gid: Real, effective, saved set, and filesystem GIDs. +/// - FDSize: The number of file descriptor slots currently allocated. +/// - Groups: Supplementary group IDs. +/// - VmPeak: Peak virtual memory size. +/// - VmSize: Current virtual memory size. +/// - VmLck: Locked memory size. +/// - VmPin: Pinned memory size. +/// - VmHWM: Peak resident set size ("high water mark"). +/// - VmRSS: Resident set size. +/// - VmData: Size of data segment. +/// - VmStk: Size of stack segment. +/// - VmExe: Size of text segment. +/// - VmLib: Shared library code size. +/// - VmPTE: Page table entries size. +/// - VmSwap: Swapped-out virtual memory size by anonymous private pages. +/// - Threads: Number of threads in this process. +/// - SigQ: Current signal queue size and limit. +/// - SigPnd: Threads pending signals. +/// - ShdPnd: Shared pending signals. +/// - SigBlk: Blocked signals. +/// - SigIgn: Ignored signals. +/// - SigCgt: Caught signals. +/// - CapInh: Inheritable capabilities. +/// - CapPrm: Permitted capabilities. +/// - CapEff: Effective capabilities. +/// - CapBnd: Bounding set. +/// - CapAmb: Ambient capabilities. +/// - Seccomp: Seccomp mode. +/// - Cpus_allowed: CPUs allowed for this process. +/// - Cpus_allowed_list: List of CPUs allowed for this process. +/// - Mems_allowed: Memory nodes allowed for this process. +/// - Mems_allowed_list: List of memory nodes allowed for this process. +/// - voluntary_ctxt_switches: Number of voluntary context switches. +/// - nonvoluntary_ctxt_switches: Number of nonvoluntary context switches. +pub struct StatusFileOps(Arc); + +impl StatusFileOps { + pub fn new_inode(process_ref: Arc, parent: Weak) -> Arc { + ProcFileBuilder::new(Self(process_ref)) + .parent(parent) + .build() + .unwrap() + } +} + +impl FileOps for StatusFileOps { + fn data(&self) -> Result> { + let process = &self.0; + let mut status_output = String::new(); + writeln!(status_output, "Name:\t{}", process.executable_path()).unwrap(); + writeln!(status_output, "Tgid:\t{}", process.pid()).unwrap(); + writeln!(status_output, "Pid:\t{}", process.pid()).unwrap(); + writeln!(status_output, "PPid:\t{}", process.parent().pid()).unwrap(); + writeln!(status_output, "TracerPid:\t{}", process.parent().pid()).unwrap(); // Assuming TracerPid is the same as PPid + writeln!( + status_output, + "FDSize:\t{}", + process.file_table().lock().len() + ) + .unwrap(); + writeln!(status_output, "Threads:\t{}", process.tasks().lock().len()).unwrap(); + Ok(status_output.into_bytes()) + } +}