Add support for '/proc/[pid]/stat'

Many field values are displayed as 0
This commit is contained in:
LI Qing 2021-08-05 10:27:10 +08:00 committed by Zongmin.Gu
parent 28c0d55c88
commit 865e38258b
3 changed files with 237 additions and 23 deletions

@ -8,6 +8,7 @@ use self::cwd::ProcCwdSymINode;
use self::exe::ProcExeSymINode;
use self::fd::LockedProcFdDirINode;
use self::root::ProcRootSymINode;
use self::stat::ProcStatINode;
mod cmdline;
mod comm;
@ -15,6 +16,7 @@ mod cwd;
mod exe;
mod fd;
mod root;
mod stat;
pub struct LockedPidDirINode(RwLock<PidDirINode>);
@ -58,6 +60,9 @@ impl LockedPidDirINode {
// comm
let comm_inode = ProcCommINode::new(&file.process_ref);
file.entries.insert(String::from("comm"), comm_inode);
// stat
let stat_inode = ProcStatINode::new(&file.process_ref);
file.entries.insert(String::from("stat"), stat_inode);
Ok(())
}

@ -0,0 +1,185 @@
use super::*;
pub struct ProcStatINode(ProcessRef);
impl ProcStatINode {
pub fn new(process_ref: &ProcessRef) -> Arc<dyn INode> {
Arc::new(File::new(Self(Arc::clone(process_ref))))
}
}
impl ProcINode for ProcStatINode {
fn generate_data_in_bytes(&self) -> vfs::Result<Vec<u8>> {
let main_thread = self.0.main_thread().ok_or(FsError::EntryNotFound)?;
// Get the process status information, some fields are filled with the
// dummy value 0, while some fields are denies to access with value 0.
// TODO: Fill in the dummy fields with meaningful values
let pid = main_thread.tid();
let comm = String::from_utf8(main_thread.name().as_c_str().to_bytes().to_vec()).unwrap();
let state = match self.0.status() {
ProcessStatus::Running => "R",
ProcessStatus::Stopped => "T",
ProcessStatus::Zombie => "Z",
};
let ppid = self.0.parent().pid();
let pgrp = self.0.pgid();
let session = pgrp.clone();
let tty_nr = 0;
let tpgid = pgrp.clone();
let flags = 0;
let minflt = 0;
let cminflt = 0;
let majflt = 0;
let cmajflt = 0;
let utime = 0;
let stime = 0;
let cutime = 0;
let cstime = 0;
let priority = 0;
let nice = 0;
let num_threads = self.0.threads().len();
let itrealvalue = 0;
let starttime = 0;
let vsize = main_thread.vm().get_process_range().size();
let rss = 0;
let rsslim = 0;
let startcode = 0;
let endcode = 0;
let startstack = 0;
let kstkesp = 0;
let kstkeip = 0;
let signal = 0;
let blocked = 0;
let sigignore = 0;
let sigcatch = 0;
let wchan = 0;
let nswap = 0;
let cnswap = 0;
let exit_signal = 0;
let processor = 0;
let rt_priority = 0;
let policy = 0;
let delayacct_blkio_ticks = 0;
let guest_time = 0;
let cguest_time = 0;
let start_data = 0;
let end_data = 0;
let start_brk = 0;
let arg_start = 0;
let arg_end = 0;
let env_start = 0;
let env_end = 0;
let exit_code = 0;
// Put the information together in the specific format
let result = format!(
"{} \
({}) \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{} \
{}",
pid,
comm,
state,
ppid,
pgrp,
session,
tty_nr,
tpgid,
flags,
minflt,
cminflt,
majflt,
cmajflt,
utime,
stime,
cutime,
cstime,
priority,
nice,
num_threads,
itrealvalue,
starttime,
vsize,
rss,
rsslim,
startcode,
endcode,
startstack,
kstkesp,
kstkeip,
signal,
blocked,
sigignore,
sigcatch,
wchan,
nswap,
cnswap,
exit_signal,
processor,
rt_priority,
policy,
delayacct_blkio_ticks,
guest_time,
cguest_time,
start_data,
end_data,
start_brk,
arg_start,
arg_end,
env_start,
env_end,
exit_code
)
.into_bytes();
Ok(result)
}
}

@ -29,6 +29,25 @@ static int test_readlink_from_procfs(const char *proc_inode, char *buf, int buf_
return 0;
}
static int test_read_from_procfs(const char *proc_inode) {
char buf[1024] = { 0 };
int len;
int fd = open(proc_inode, O_RDONLY);
if (fd < 0) {
THROW_ERROR("failed to open file: %s", proc_inode);
}
do {
len = read(fd, buf, sizeof(buf));
if (len < 0) {
THROW_ERROR("failed to read: %s", proc_inode);
}
} while (len == sizeof(buf));
close(fd);
return 0;
}
// ============================================================================
// Test cases for procfs
// ============================================================================
@ -136,41 +155,45 @@ static int test_read_from_proc_self_comm() {
return 0;
}
static int test_read_from_proc_self_stat() {
const char *proc_self_stat = "/proc/self/stat";
FILE *fp = fopen(proc_self_stat, "r");
if (fp == NULL) {
THROW_ERROR("failed to fopen: %s", proc_self_stat);
}
int pid, ppid, pgrp;
char comm[32] = { 0 };
char state[32] = { 0 };
int ret = fscanf(fp, "%d %s %s %d %d", &pid, comm, state, &ppid, &pgrp);
if (ret != 5) {
THROW_ERROR("failed to parse the first 5 items");
}
if (pid != getpid()) {
THROW_ERROR("failed to check the result in %s", proc_self_stat);
}
printf("cat %s with the first 5 items:\n%d %s %s %d %d\n", proc_self_stat, pid, comm,
state, ppid, pgrp);
fclose(fp);
return 0;
}
static int test_read_from_proc_meminfo() {
char meminfo[1024] = { 0 };
const char *proc_meminfo = "/proc/meminfo";
int fd = open(proc_meminfo, O_RDONLY);
if (fd < 0) {
THROW_ERROR("failed to open file: %s", proc_meminfo);
}
if (read(fd, meminfo, sizeof(meminfo)) < 0) {
if (test_read_from_procfs(proc_meminfo) < 0) {
THROW_ERROR("failed to read the meminfo");
}
close(fd);
return 0;
}
static int test_read_from_proc_cpuinfo() {
char cpuinfo[1024] = { 0 };
const char *proc_cpuinfo = "/proc/cpuinfo";
int len;
int fd = open(proc_cpuinfo, O_RDONLY);
if (fd < 0) {
THROW_ERROR("failed to open file: %s", proc_cpuinfo);
if (test_read_from_procfs(proc_cpuinfo) < 0) {
THROW_ERROR("failed to read the cpuinfo");
}
do {
len = read(fd, cpuinfo, sizeof(cpuinfo));
if (len < 0) {
THROW_ERROR("failed to read the cpuinfo");
} else if (len < sizeof(cpuinfo)) {
break;
}
} while (len == sizeof(cpuinfo));
close(fd);
return 0;
}
@ -252,6 +275,7 @@ static test_case_t test_cases[] = {
TEST_CASE(test_create_and_unlink_file_from_proc_self_root),
TEST_CASE(test_read_from_proc_self_cmdline),
TEST_CASE(test_read_from_proc_self_comm),
TEST_CASE(test_read_from_proc_self_stat),
TEST_CASE(test_read_from_proc_meminfo),
TEST_CASE(test_read_from_proc_cpuinfo),
TEST_CASE(test_statfs),