mirror of
https://github.com/ClementTsang/bottom
synced 2024-11-30 16:09:11 +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 total_write_bytes: u64,
|
||||||
pub process_state: String,
|
pub process_state: String,
|
||||||
pub process_state_char: char,
|
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)]
|
#[derive(Debug, Default, Clone)]
|
||||||
|
@ -87,6 +92,7 @@ pub struct PrevProcDetails {
|
||||||
pub total_write_bytes: u64,
|
pub total_write_bytes: u64,
|
||||||
pub cpu_time: f64,
|
pub cpu_time: f64,
|
||||||
pub proc_stat_path: PathBuf,
|
pub proc_stat_path: PathBuf,
|
||||||
|
pub proc_status_path: PathBuf,
|
||||||
// pub proc_statm_path: PathBuf,
|
// pub proc_statm_path: PathBuf,
|
||||||
// pub proc_exe_path: PathBuf,
|
// pub proc_exe_path: PathBuf,
|
||||||
pub proc_io_path: PathBuf,
|
pub proc_io_path: PathBuf,
|
||||||
|
@ -100,6 +106,7 @@ impl PrevProcDetails {
|
||||||
proc_io_path: PathBuf::from(format!("/proc/{}/io", pid)),
|
proc_io_path: PathBuf::from(format!("/proc/{}/io", pid)),
|
||||||
// proc_exe_path: PathBuf::from(format!("/proc/{}/exe", pid)),
|
// proc_exe_path: PathBuf::from(format!("/proc/{}/exe", pid)),
|
||||||
proc_stat_path: PathBuf::from(format!("/proc/{}/stat", 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_statm_path: PathBuf::from(format!("/proc/{}/statm", pid)),
|
||||||
proc_cmdline_path: PathBuf::from(format!("/proc/{}/cmdline", pid)),
|
proc_cmdline_path: PathBuf::from(format!("/proc/{}/cmdline", pid)),
|
||||||
..PrevProcDetails::default()
|
..PrevProcDetails::default()
|
||||||
|
@ -115,11 +122,8 @@ fn cpu_usage_calculation(
|
||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
|
|
||||||
// From SO answer: https://stackoverflow.com/a/23376195
|
// 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();
|
let mut first_line = String::new();
|
||||||
reader.read_line(&mut first_line)?;
|
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)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
fn read_proc(
|
fn read_proc(
|
||||||
|
@ -357,6 +397,8 @@ fn read_proc(
|
||||||
(0, 0, 0, 0)
|
(0, 0, 0, 0)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let (uid, gid) = get_uid_and_gid(&pid_stat.proc_status_path);
|
||||||
|
|
||||||
Ok(ProcessHarvest {
|
Ok(ProcessHarvest {
|
||||||
pid,
|
pid,
|
||||||
parent_pid,
|
parent_pid,
|
||||||
|
@ -371,6 +413,8 @@ fn read_proc(
|
||||||
write_bytes_per_sec,
|
write_bytes_per_sec,
|
||||||
process_state,
|
process_state,
|
||||||
process_state_char,
|
process_state_char,
|
||||||
|
uid,
|
||||||
|
gid,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -472,26 +516,54 @@ pub fn get_process_data(
|
||||||
};
|
};
|
||||||
|
|
||||||
let disk_usage = process_val.disk_usage();
|
let disk_usage = process_val.disk_usage();
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
process_vector.push(ProcessHarvest {
|
{
|
||||||
pid: process_val.pid(),
|
process_vector.push(ProcessHarvest {
|
||||||
parent_pid: process_val.parent(),
|
pid: process_val.pid(),
|
||||||
name,
|
parent_pid: process_val.parent(),
|
||||||
command,
|
name,
|
||||||
mem_usage_percent: if mem_total_kb > 0 {
|
command,
|
||||||
process_val.memory() as f64 * 100.0 / mem_total_kb as f64
|
mem_usage_percent: if mem_total_kb > 0 {
|
||||||
} else {
|
process_val.memory() as f64 * 100.0 / mem_total_kb as f64
|
||||||
0.0
|
} else {
|
||||||
},
|
0.0
|
||||||
mem_usage_bytes: process_val.memory() * 1024,
|
},
|
||||||
cpu_usage_percent: process_cpu_usage,
|
mem_usage_bytes: process_val.memory() * 1024,
|
||||||
read_bytes_per_sec: disk_usage.read_bytes,
|
cpu_usage_percent: process_cpu_usage,
|
||||||
write_bytes_per_sec: disk_usage.written_bytes,
|
read_bytes_per_sec: disk_usage.read_bytes,
|
||||||
total_read_bytes: disk_usage.total_read_bytes,
|
write_bytes_per_sec: disk_usage.written_bytes,
|
||||||
total_write_bytes: disk_usage.total_written_bytes,
|
total_read_bytes: disk_usage.total_read_bytes,
|
||||||
process_state: process_val.status().to_string().to_string(),
|
total_write_bytes: disk_usage.total_written_bytes,
|
||||||
process_state_char: convert_process_status_to_char(process_val.status()),
|
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)
|
Ok(process_vector)
|
||||||
|
@ -500,22 +572,18 @@ pub fn get_process_data(
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[cfg(not(target_os = "linux"))]
|
||||||
fn convert_process_status_to_char(status: ProcessStatus) -> char {
|
fn convert_process_status_to_char(status: ProcessStatus) -> char {
|
||||||
if cfg!(target_os = "macos") {
|
#[cfg(target_os = "macos")]
|
||||||
#[cfg(target_os = "macos")]
|
{
|
||||||
{
|
match status {
|
||||||
match status {
|
ProcessStatus::Run => 'R',
|
||||||
ProcessStatus::Run => 'R',
|
ProcessStatus::Sleep => 'S',
|
||||||
ProcessStatus::Sleep => 'S',
|
ProcessStatus::Idle => 'D',
|
||||||
ProcessStatus::Idle => 'D',
|
ProcessStatus::Zombie => 'Z',
|
||||||
ProcessStatus::Zombie => 'Z',
|
_ => '?',
|
||||||
_ => '?',
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[cfg(not(target_os = "macos"))]
|
}
|
||||||
{
|
#[cfg(not(target_os = "macos"))]
|
||||||
'?'
|
{
|
||||||
}
|
|
||||||
} else {
|
|
||||||
'R'
|
'R'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue