From 17e4810d3ed8b0c0bc268993afe55693b7b2c47d Mon Sep 17 00:00:00 2001 From: LI Qing Date: Tue, 20 Jul 2021 12:55:39 +0800 Subject: [PATCH] Add support for "/proc/[pid]/comm" and fix "/proc/[pid]/cmdline" --- src/libos/src/fs/procfs/pid_inode.rs | 34 +++++++++++++++++++++-- test/procfs/main.c | 41 ++++++++++++++++++++++++---- 2 files changed, 67 insertions(+), 8 deletions(-) diff --git a/src/libos/src/fs/procfs/pid_inode.rs b/src/libos/src/fs/procfs/pid_inode.rs index 5c756fc9..30a94b6d 100644 --- a/src/libos/src/fs/procfs/pid_inode.rs +++ b/src/libos/src/fs/procfs/pid_inode.rs @@ -1,6 +1,6 @@ use super::*; use crate::process::table::get_process; -use crate::process::ProcessRef; +use crate::process::{ProcessRef, ProcessStatus}; pub struct LockedPidDirINode(RwLock); @@ -41,7 +41,9 @@ impl LockedPidDirINode { // root let root_inode = ProcRootSymINode::new(&file.process_ref); file.entries.insert(String::from("root"), root_inode); - + // comm + let comm_inode = ProcCommINode::new(&file.process_ref); + file.entries.insert(String::from("comm"), comm_inode); Ok(()) } } @@ -136,7 +138,15 @@ impl ProcCmdlineINode { impl ProcINode for ProcCmdlineINode { fn generate_data_in_bytes(&self) -> vfs::Result> { - Ok(self.0.exec_path().to_owned().into_bytes()) + let cmdline = if let ProcessStatus::Zombie = self.0.status() { + Vec::new() + } else { + // Null-terminated bytes + std::ffi::CString::new(self.0.exec_path()) + .expect("failed to new CString") + .into_bytes_with_nul() + }; + Ok(cmdline) } } @@ -186,6 +196,24 @@ impl ProcINode for ProcRootSymINode { } } +pub struct ProcCommINode(ProcessRef); + +impl ProcCommINode { + pub fn new(process_ref: &ProcessRef) -> Arc { + Arc::new(File::new(Self(Arc::clone(process_ref)))) + } +} + +impl ProcINode for ProcCommINode { + fn generate_data_in_bytes(&self) -> vfs::Result> { + let main_thread = self.0.main_thread().ok_or(FsError::EntryNotFound)?; + let mut comm = main_thread.name().as_c_str().to_bytes().to_vec(); + // Add '\n' at the end to make the result same with Linux + comm.push(b'\n'); + Ok(comm) + } +} + pub struct FdSymINode(FileRef); impl FdSymINode { diff --git a/test/procfs/main.c b/test/procfs/main.c index 46ed5cf9..c3e9e288 100644 --- a/test/procfs/main.c +++ b/test/procfs/main.c @@ -1,3 +1,4 @@ +#define _GNU_SOURCE #include #include #include @@ -10,7 +11,8 @@ // Helper variable and function // ============================================================================ -const char **g_argv; +// Contains the name that was used to invoke the calling program +extern char *program_invocation_short_name; static int test_readlink_from_procfs(const char *proc_inode, char *buf, int buf_size, const char *expected_target) { @@ -36,7 +38,8 @@ static int test_readlink_from_proc_self_exe() { char absolute_path[PATH_MAX] = { 0 }; const char *proc_exe = "/proc/self/exe"; - int n = snprintf(absolute_path, sizeof(absolute_path), "/bin/%s", *g_argv); + int n = snprintf(absolute_path, sizeof(absolute_path), "/bin/%s", + program_invocation_short_name); if (n < 0) { THROW_ERROR("failed to call snprintf"); } @@ -94,13 +97,41 @@ static int test_read_from_proc_self_cmdline() { char absolute_path[PATH_MAX] = { 0 }; const char *proc_cmdline = "/proc/self/cmdline"; - int n = snprintf(absolute_path, sizeof(absolute_path), "/bin/%s", *g_argv); + int n = snprintf(absolute_path, sizeof(absolute_path), "/bin/%s", + program_invocation_short_name); if (n < 0) { THROW_ERROR("failed to call snprintf"); } - if (fs_check_file_content(proc_cmdline, absolute_path) < 0) { + char read_buf[PATH_MAX] = { 0 }; + int fd = open(proc_cmdline, O_RDONLY); + size_t len = read(fd, read_buf, sizeof(read_buf)); + if (len != strlen(absolute_path) + 1) { + THROW_ERROR("failed check the return value of reading from %s", proc_cmdline); + } + if (read_buf[strlen(absolute_path)] != '\0') { + THROW_ERROR("failed check the buffer of reading from %s", proc_cmdline); + } + if (strcmp(absolute_path, read_buf) != 0) { THROW_ERROR("failed to check result in %s", proc_cmdline); } + close(fd); + return 0; +} + +static int test_read_from_proc_self_comm() { + // The name can be up to 16 bytes long, including the terminating null byte. + char comm_name[16] = { 0 }; + const char *proc_comm = "/proc/self/comm"; + + if (snprintf(comm_name, sizeof(comm_name), "%s", program_invocation_short_name) < 0) { + THROW_ERROR("failed to call snprintf"); + } + // The last byte shoud be '\n' + int end_idx = strlen(comm_name); + comm_name[end_idx] = '\n'; + if (fs_check_file_content(proc_comm, comm_name) < 0) { + THROW_ERROR("failed to check result in %s", proc_comm); + } return 0; } @@ -169,12 +200,12 @@ static test_case_t test_cases[] = { TEST_CASE(test_readlink_from_proc_self_root), 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_meminfo), TEST_CASE(test_read_from_proc_cpuinfo), TEST_CASE(test_statfs), }; int main(int argc, const char *argv[]) { - g_argv = argv; return test_suite_run(test_cases, ARRAY_SIZE(test_cases)); }