From 30b2c2ea051d3c837edf82d595bf24a475da1431 Mon Sep 17 00:00:00 2001 From: Clement Tsang <34804052+ClementTsang@users.noreply.github.com> Date: Sun, 27 Dec 2020 10:25:04 -0500 Subject: feature: Adds uid and gid collection (no GUI yet) (#375) Just adds uid and gid collection to the process collection step. This does not add GUI changes, that'll come later. --- src/app/data_harvester/processes.rs | 146 ++++++++++++++++++++++++++---------- 1 file changed, 107 insertions(+), 39 deletions(-) (limited to 'src/app') diff --git a/src/app/data_harvester/processes.rs b/src/app/data_harvester/processes.rs index 94dcf635..81ccc7f8 100644 --- a/src/app/data_harvester/processes.rs +++ b/src/app/data_harvester/processes.rs @@ -79,6 +79,11 @@ pub struct ProcessHarvest { pub total_write_bytes: u64, pub process_state: String, pub process_state_char: char, + + /// This is the *effective* user ID. + pub uid: Option, + // pub real_uid: Option, // TODO: Add real user ID + pub gid: Option, } #[derive(Debug, Default, Clone)] @@ -87,6 +92,7 @@ pub struct PrevProcDetails { pub total_write_bytes: u64, pub cpu_time: f64, pub proc_stat_path: PathBuf, + pub proc_status_path: PathBuf, // pub proc_statm_path: PathBuf, // pub proc_exe_path: PathBuf, pub proc_io_path: PathBuf, @@ -100,6 +106,7 @@ impl PrevProcDetails { proc_io_path: PathBuf::from(format!("/proc/{}/io", pid)), // proc_exe_path: PathBuf::from(format!("/proc/{}/exe", pid)), proc_stat_path: PathBuf::from(format!("/proc/{}/stat", pid)), + proc_status_path: PathBuf::from(format!("/proc/{}/status", pid)), // proc_statm_path: PathBuf::from(format!("/proc/{}/statm", pid)), proc_cmdline_path: PathBuf::from(format!("/proc/{}/cmdline", pid)), ..PrevProcDetails::default() @@ -115,11 +122,8 @@ fn cpu_usage_calculation( use std::io::BufReader; // From SO answer: https://stackoverflow.com/a/23376195 - let mut path = std::path::PathBuf::new(); - path.push("/proc"); - path.push("stat"); - let mut reader = BufReader::new(std::fs::File::open(path)?); + let mut reader = BufReader::new(std::fs::File::open("/proc/stat")?); let mut first_line = String::new(); reader.read_line(&mut first_line)?; @@ -225,6 +229,42 @@ fn get_linux_cpu_usage( } } +#[cfg(target_os = "linux")] +fn get_uid_and_gid(path: &PathBuf) -> (Option, Option) { + // FIXME: [OPT] - can we merge our /stat and /status calls? + use std::io::prelude::*; + use std::io::BufReader; + + if let Ok(file) = std::fs::File::open(path) { + let reader = BufReader::new(file); + let mut lines = reader.lines().skip(8); + + let (_real_uid, effective_uid) = if let Some(Ok(read_uid_line)) = lines.next() { + let mut split_whitespace = read_uid_line.split_whitespace().skip(1); + ( + split_whitespace.next().and_then(|x| x.parse::().ok()), + split_whitespace.next().and_then(|x| x.parse::().ok()), + ) + } else { + (None, None) + }; + + let (_real_gid, effective_gid) = if let Some(Ok(read_gid_line)) = lines.next() { + let mut split_whitespace = read_gid_line.split_whitespace().skip(1); + ( + split_whitespace.next().and_then(|x| x.parse::().ok()), + split_whitespace.next().and_then(|x| x.parse::().ok()), + ) + } else { + (None, None) + }; + + (effective_uid, effective_gid) + } else { + (None, None) + } +} + #[allow(clippy::too_many_arguments)] #[cfg(target_os = "linux")] fn read_proc( @@ -357,6 +397,8 @@ fn read_proc( (0, 0, 0, 0) }; + let (uid, gid) = get_uid_and_gid(&pid_stat.proc_status_path); + Ok(ProcessHarvest { pid, parent_pid, @@ -371,6 +413,8 @@ fn read_proc( write_bytes_per_sec, process_state, process_state_char, + uid, + gid, }) } @@ -472,26 +516,54 @@ pub fn get_process_data( }; let disk_usage = process_val.disk_usage(); - - process_vector.push(ProcessHarvest { - pid: process_val.pid(), - parent_pid: process_val.parent(), - name, - command, - mem_usage_percent: if mem_total_kb > 0 { - process_val.memory() as f64 * 100.0 / mem_total_kb as f64 - } else { - 0.0 - }, - mem_usage_bytes: process_val.memory() * 1024, - cpu_usage_percent: process_cpu_usage, - read_bytes_per_sec: disk_usage.read_bytes, - write_bytes_per_sec: disk_usage.written_bytes, - total_read_bytes: disk_usage.total_read_bytes, - total_write_bytes: disk_usage.total_written_bytes, - process_state: process_val.status().to_string().to_string(), - process_state_char: convert_process_status_to_char(process_val.status()), - }); + #[cfg(target_os = "macos")] + { + process_vector.push(ProcessHarvest { + pid: process_val.pid(), + parent_pid: process_val.parent(), + name, + command, + mem_usage_percent: if mem_total_kb > 0 { + process_val.memory() as f64 * 100.0 / mem_total_kb as f64 + } else { + 0.0 + }, + mem_usage_bytes: process_val.memory() * 1024, + cpu_usage_percent: process_cpu_usage, + read_bytes_per_sec: disk_usage.read_bytes, + write_bytes_per_sec: disk_usage.written_bytes, + total_read_bytes: disk_usage.total_read_bytes, + total_write_bytes: disk_usage.total_written_bytes, + process_state: process_val.status().to_string().to_string(), + process_state_char: convert_process_status_to_char(process_val.status()), + uid: Some(process_val.uid), + gid: Some(process_val.gid), + }); + } + #[cfg(not(target_os = "macos"))] + { + process_vector.push(ProcessHarvest { + pid: process_val.pid(), + parent_pid: process_val.parent(), + name, + command, + mem_usage_percent: if mem_total_kb > 0 { + process_val.memory() as f64 * 100.0 / mem_total_kb as f64 + } else { + 0.0 + }, + mem_usage_bytes: process_val.memory() * 1024, + cpu_usage_percent: process_cpu_usage, + read_bytes_per_sec: disk_usage.read_bytes, + write_bytes_per_sec: disk_usage.written_bytes, + total_read_bytes: disk_usage.total_read_bytes, + total_write_bytes: disk_usage.total_written_bytes, + process_state: process_val.status().to_string().to_string(), + process_state_char: convert_process_status_to_char(process_val.status()), + uid: None, + gid: None, + }); + } } Ok(process_vector) @@ -500,22 +572,18 @@ pub fn get_process_data( #[allow(unused_variables)] #[cfg(not(target_os = "linux"))] fn convert_process_status_to_char(status: ProcessStatus) -> char { - if cfg!(target_os = "macos") { - #[cfg(target_os = "macos")] - { - match status { - ProcessStatus::Run => 'R', - ProcessStatus::Sleep => 'S', - ProcessStatus::Idle => 'D', - ProcessStatus::Zombie => 'Z', - _ => '?', - } + #[cfg(target_os = "macos")] + { + match status { + ProcessStatus::Run => 'R', + ProcessStatus::Sleep => 'S', + ProcessStatus::Idle => 'D', + ProcessStatus::Zombie => 'Z', + _ => '?', } - #[cfg(not(target_os = "macos"))] - { - '?' - } - } else { + } + #[cfg(not(target_os = "macos"))] + { 'R' } } -- cgit v1.2.3