diff options
Diffstat (limited to 'src/app')
-rw-r--r-- | src/app/data_harvester/processes.rs | 67 | ||||
-rw-r--r-- | src/app/query.rs | 27 | ||||
-rw-r--r-- | src/app/states.rs | 56 |
3 files changed, 126 insertions, 24 deletions
diff --git a/src/app/data_harvester/processes.rs b/src/app/data_harvester/processes.rs index c9233337..56bf09d4 100644 --- a/src/app/data_harvester/processes.rs +++ b/src/app/data_harvester/processes.rs @@ -2,8 +2,11 @@ use crate::Pid; use std::path::PathBuf; use sysinfo::ProcessStatus; +#[cfg(target_family = "unix")] +use crate::utils::error; + #[cfg(target_os = "linux")] -use crate::utils::error::{self, BottomError}; +use crate::utils::error::BottomError; #[cfg(target_os = "linux")] use fnv::{FnvHashMap, FnvHashSet}; @@ -29,28 +32,29 @@ pub enum ProcessSorting { TotalRead, TotalWrite, State, + User, Count, } impl std::fmt::Display for ProcessSorting { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - use ProcessSorting::*; write!( f, "{}", match &self { - CpuPercent => "CPU%", - MemPercent => "Mem%", - Mem => "Mem", - ReadPerSecond => "R/s", - WritePerSecond => "W/s", - TotalRead => "T.Read", - TotalWrite => "T.Write", - State => "State", - ProcessName => "Name", - Command => "Command", - Pid => "PID", - Count => "Count", + ProcessSorting::CpuPercent => "CPU%", + ProcessSorting::MemPercent => "Mem%", + ProcessSorting::Mem => "Mem", + ProcessSorting::ReadPerSecond => "R/s", + ProcessSorting::WritePerSecond => "W/s", + ProcessSorting::TotalRead => "T.Read", + ProcessSorting::TotalWrite => "T.Write", + ProcessSorting::State => "State", + ProcessSorting::ProcessName => "Name", + ProcessSorting::Command => "Command", + ProcessSorting::Pid => "PID", + ProcessSorting::Count => "Count", + ProcessSorting::User => "User", } ) } @@ -81,9 +85,13 @@ pub struct ProcessHarvest { 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>, + #[cfg(target_family = "unix")] + pub uid: Option<libc::uid_t>, + + // TODO: Add real user ID + // pub real_uid: Option<u32>, + #[cfg(target_family = "unix")] + pub gid: Option<libc::gid_t>, } #[derive(Debug, Default, Clone)] @@ -114,6 +122,29 @@ impl PrevProcDetails { } } +#[cfg(target_family = "unix")] +#[derive(Debug, Default)] +pub struct UserTable { + pub uid_user_mapping: std::collections::HashMap<libc::uid_t, String>, +} + +#[cfg(target_family = "unix")] +impl UserTable { + pub fn get_uid_to_username_mapping(&mut self, uid: libc::uid_t) -> error::Result<String> { + if let Some(user) = self.uid_user_mapping.get(&uid) { + Ok(user.clone()) + } else { + let passwd = unsafe { libc::getpwuid(uid) }; + let username = unsafe { std::ffi::CStr::from_ptr((*passwd).pw_name) } + .to_str()? + .to_string(); + self.uid_user_mapping.insert(uid, username.clone()); + + Ok(username) + } + } +} + #[cfg(target_os = "linux")] fn cpu_usage_calculation( prev_idle: &mut f64, prev_non_idle: &mut f64, @@ -591,8 +622,6 @@ pub fn get_process_data( 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, }); } } diff --git a/src/app/query.rs b/src/app/query.rs index 79f61e73..5a827aec 100644 --- a/src/app/query.rs +++ b/src/app/query.rs @@ -26,7 +26,8 @@ pub trait ProcessQuery { /// - PIDs: Use prefix `pid`, can use regex or match word (case is irrelevant). /// - CPU: Use prefix `cpu`, cannot use r/m/c (regex, match word, case). Can compare. /// - MEM: Use prefix `mem`, cannot use r/m/c. Can compare. - /// - STATE: Use prefix `state`, TODO when we update how state looks in 0.5 probably. + /// - STATE: Use prefix `state`, can use regex, match word, or case. + /// - USER: Use prefix `user`, can use regex, match word, or case. /// - Read/s: Use prefix `r`. Can compare. /// - Write/s: Use prefix `w`. Can compare. /// - Total read: Use prefix `read`. Can compare. @@ -128,8 +129,6 @@ impl ProcessQuery for ProcWidgetState { fn process_prefix(query: &mut VecDeque<String>, inside_quotation: bool) -> Result<Prefix> { if let Some(queue_top) = query.pop_front() { - // debug!("Prefix QT: {:?}", queue_top); - if inside_quotation { if queue_top == "\"" { // This means we hit something like "". Return an empty prefix, and to deal with @@ -264,11 +263,20 @@ impl ProcessQuery for ProcWidgetState { compare_prefix: None, }) } - PrefixType::Pid | PrefixType::State => { + PrefixType::Pid | PrefixType::State | PrefixType::User => { // We have to check if someone put an "="... if content == "=" { // Check next string if possible if let Some(queue_next) = query.pop_front() { + // TODO: Need to consider the following cases: + // - (test) + // - (test + // - test) + // These are split into 2 to 3 different strings due to parentheses being + // delimiters in our query system. + // + // Do we want these to be valid? They should, as a string, right? + return Ok(Prefix { or: None, regex_prefix: Some(( @@ -580,6 +588,7 @@ pub enum PrefixType { TWrite, Name, State, + User, __Nonexhaustive, } @@ -602,6 +611,7 @@ impl std::str::FromStr for PrefixType { "twrite" | "t.write" => Ok(TWrite), "pid" => Ok(Pid), "state" => Ok(State), + "user" => Ok(User), _ => Ok(Name), } } @@ -628,7 +638,7 @@ impl Prefix { } else if let Some((prefix_type, StringQuery::Value(regex_string))) = &mut self.regex_prefix { match prefix_type { - PrefixType::Pid | PrefixType::Name | PrefixType::State => { + PrefixType::Pid | PrefixType::Name | PrefixType::State | PrefixType::User => { let escaped_regex: String; let final_regex_string = &format!( "{}{}{}{}", @@ -681,6 +691,13 @@ impl Prefix { }), PrefixType::Pid => r.is_match(process.pid.to_string().as_str()), PrefixType::State => r.is_match(process.process_state.as_str()), + PrefixType::User => { + if let Some(user) = &process.user { + r.is_match(user.as_str()) + } else { + false + } + } _ => true, } } else { diff --git a/src/app/states.rs b/src/app/states.rs index c2853337..39dd0222 100644 --- a/src/app/states.rs +++ b/src/app/states.rs @@ -174,6 +174,9 @@ impl ProcessSearchState { pub struct ColumnInfo { pub enabled: bool, pub shortcut: Option<&'static str>, + // FIXME: Move column width logic here! + // pub hard_width: Option<u16>, + // pub max_soft_width: Option<f64>, } pub struct ProcColumn { @@ -205,6 +208,7 @@ impl Default for ProcColumn { WritePerSecond, TotalRead, TotalWrite, + User, State, ]; @@ -219,6 +223,8 @@ impl Default for ProcColumn { ColumnInfo { enabled: true, shortcut: Some("c"), + // hard_width: None, + // max_soft_width: None, }, ); } @@ -228,6 +234,8 @@ impl Default for ProcColumn { ColumnInfo { enabled: true, shortcut: Some("m"), + // hard_width: None, + // max_soft_width: None, }, ); } @@ -237,6 +245,8 @@ impl Default for ProcColumn { ColumnInfo { enabled: false, shortcut: Some("m"), + // hard_width: None, + // max_soft_width: None, }, ); } @@ -246,6 +256,8 @@ impl Default for ProcColumn { ColumnInfo { enabled: true, shortcut: Some("n"), + // hard_width: None, + // max_soft_width: None, }, ); } @@ -255,6 +267,8 @@ impl Default for ProcColumn { ColumnInfo { enabled: false, shortcut: Some("n"), + // hard_width: None, + // max_soft_width: None, }, ); } @@ -264,6 +278,8 @@ impl Default for ProcColumn { ColumnInfo { enabled: true, shortcut: Some("p"), + // hard_width: None, + // max_soft_width: None, }, ); } @@ -273,6 +289,17 @@ impl Default for ProcColumn { ColumnInfo { enabled: false, shortcut: None, + // hard_width: None, + // max_soft_width: None, + }, + ); + } + User => { + column_mapping.insert( + column, + ColumnInfo { + enabled: cfg!(target_family = "unix"), + shortcut: None, }, ); } @@ -282,6 +309,8 @@ impl Default for ProcColumn { ColumnInfo { enabled: true, shortcut: None, + // hard_width: None, + // max_soft_width: None, }, ); } @@ -316,6 +345,33 @@ impl ProcColumn { } } + pub fn try_set(&mut self, column: &ProcessSorting, setting: bool) -> Option<bool> { + if let Some(mapping) = self.column_mapping.get_mut(column) { + mapping.enabled = setting; + Some(mapping.enabled) + } else { + None + } + } + + pub fn try_enable(&mut self, column: &ProcessSorting) -> Option<bool> { + if let Some(mapping) = self.column_mapping.get_mut(column) { + mapping.enabled = true; + Some(mapping.enabled) + } else { + None + } + } + + pub fn try_disable(&mut self, column: &ProcessSorting) -> Option<bool> { + if let Some(mapping) = self.column_mapping.get_mut(column) { + mapping.enabled = false; + Some(mapping.enabled) + } else { + None + } + } + pub fn is_enabled(&self, column: &ProcessSorting) -> bool { if let Some(mapping) = self.column_mapping.get(column) { mapping.enabled |