mirror of
https://github.com/ClementTsang/bottom
synced 2024-11-10 22:54:21 +00:00
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.
This commit is contained in:
parent
c864f53d24
commit
30b2c2ea05
1 changed files with 107 additions and 39 deletions
|
@ -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<u32>,
|
||||
// pub real_uid: Option<u32>, // TODO: Add real user ID
|
||||
pub gid: Option<u32>,
|
||||
}
|
||||
|
||||
#[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<u32>, Option<u32>) {
|
||||
// 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::<u32>().ok()),
|
||||
split_whitespace.next().and_then(|x| x.parse::<u32>().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::<u32>().ok()),
|
||||
split_whitespace.next().and_then(|x| x.parse::<u32>().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'
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue