use sysinfo::{System, Pid, ProcessesToUpdate, UpdateKind};
use std::collections::HashSet;
pub type ProcessInfo = (u32, String, f64);
pub fn list_processes() -> Result<Vec<u32>, String> {
let mut sys = System::new_all();
sys.refresh_processes(ProcessesToUpdate::All, true);
let pids: Vec<u32> = sys
.processes()
.keys()
.map(|pid| pid.as_u32())
.collect();
Ok(pids)
}
pub fn list_user_processes() -> Result<Vec<ProcessInfo>, String> {
let mut sys = System::new_all();
sys.refresh_processes(ProcessesToUpdate::All, true);
let current_uid = unsafe { libc::getuid() };
let mut processes: Vec<ProcessInfo> = sys
.processes()
.iter()
.filter_map(|(pid, process)| {
let proc_uid = process.user_id().map(|u| **u).unwrap_or(0);
if current_uid == 0 || proc_uid == current_uid {
let memory_mb = process.memory() as f64 / 1024.0 / 1024.0;
Some((pid.as_u32(), process.name().to_string_lossy().to_string(), memory_mb))
} else {
None
}
})
.collect();
processes.sort_by(|a, b| b.2.partial_cmp(&a.2).unwrap_or(std::cmp::Ordering::Equal));
Ok(processes)
}
pub fn get_process_name(pid: u32) -> Option<String> {
let mut sys = System::new();
sys.refresh_processes(ProcessesToUpdate::All, true);
sys.process(Pid::from_u32(pid))
.map(|p| p.name().to_string_lossy().to_string())
}
pub fn get_process_memory(pid: u32) -> Option<u64> {
let mut sys = System::new();
sys.refresh_processes(ProcessesToUpdate::All, true);
sys.process(Pid::from_u32(pid)).map(|p| p.memory())
}
pub fn get_parent_pid(pid: u32) -> Option<u32> {
let mut sys = System::new();
sys.refresh_processes(ProcessesToUpdate::All, true);
sys.process(Pid::from_u32(pid))
.and_then(|p| p.parent())
.map(|p| p.as_u32())
}
pub fn is_system_process(pid: u32) -> bool {
let mut sys = System::new();
sys.refresh_processes(ProcessesToUpdate::All, true);
if let Some(process) = sys.process(Pid::from_u32(pid)) {
if let Some(uid) = process.user_id() {
if **uid == 0 {
return true;
}
}
let name = process.name().to_string_lossy().to_lowercase();
super::safety::PROTECTED_PROCESSES
.iter()
.any(|p| name.contains(&p.to_lowercase()))
} else {
false
}
}
pub fn get_top_memory_processes(count: usize) -> Vec<ProcessInfo> {
list_user_processes()
.unwrap_or_default()
.into_iter()
.take(count)
.collect()
}
pub fn find_processes_by_name(pattern: &str) -> Vec<ProcessInfo> {
let pattern_lower = pattern.to_lowercase();
list_user_processes()
.unwrap_or_default()
.into_iter()
.filter(|(_, name, _)| name.to_lowercase().contains(&pattern_lower))
.collect()
}
pub fn get_memory_by_pattern(pattern: &str) -> f64 {
find_processes_by_name(pattern)
.iter()
.map(|(_, _, mem)| mem)
.sum()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_list_processes() {
let pids = list_processes().unwrap();
assert!(!pids.is_empty());
}
#[test]
fn test_list_user_processes() {
let procs = list_user_processes().unwrap();
assert!(!procs.is_empty());
}
}