use std::collections::HashMap; use std::fs; pub struct ProcessHelper; #[derive(Debug)] pub struct ProcessInfo { pub pid: u32, pub name: String, pub state: String, pub ppid: u32, pub memory_kb: u64, pub cpu_percent: f32, } impl ProcessHelper { pub fn list_processes() -> std::io::Result> { let mut processes = Vec::new(); let proc_path = fs::read_dir("/proc")?; for entry in proc_path.flatten() { let path = entry.path(); if !path.is_dir() { continue; } let pid: u32 = match path.file_name() { Some(name) => match name.to_str() { Some(s) => s.parse().ok(), None => None, } .ok_or(std::io::Error::new( std::io::ErrorKind::InvalidData, "invalid pid", ))?, None => continue, }; if let Ok(info) = Self::process_info(pid) { processes.push(info); } } Ok(processes) } pub fn process_info(pid: u32) -> std::io::Result { let status_path = format!("/proc/{}/status", pid); let content = fs::read_to_string(status_path)?; let mut name = String::new(); let mut state = String::new(); let mut ppid: u32 = 0; let mut memory_kb: u64 = 0; for line in content.lines() { if line.starts_with("Name:") { name = line .split_whitespace() .skip(1) .collect::>() .join(" "); } else if line.starts_with("State:") { state = line.split_whitespace().nth(1).unwrap_or("").to_string(); } else if line.starts_with("PPid:") { ppid = line .split_whitespace() .nth(1) .and_then(|s| s.parse().ok()) .unwrap_or(0); } else if line.starts_with("VmRSS:") { memory_kb = line .split_whitespace() .nth(1) .and_then(|s| s.parse().ok()) .unwrap_or(0); } } Ok(ProcessInfo { pid, name, state, ppid, memory_kb, cpu_percent: 0.0, }) } pub fn zombie_processes() -> std::io::Result> { Ok(Self::list_processes()? .into_iter() .filter(|p| p.state.starts_with('Z')) .collect()) } pub fn process_count() -> std::io::Result> { let mut counts = HashMap::new(); counts.insert("total".to_string(), 0); counts.insert("running".to_string(), 0); counts.insert("sleeping".to_string(), 0); counts.insert("zombie".to_string(), 0); for proc in Self::list_processes()? { *counts.get_mut("total").unwrap() += 1; let first_char = proc.state.chars().next().unwrap_or(' '); match first_char { 'R' => *counts.get_mut("running").unwrap() += 1, 'S' | 'D' => *counts.get_mut("sleeping").unwrap() += 1, 'Z' => *counts.get_mut("zombie").unwrap() += 1, _ => {} } } Ok(counts) } pub fn top_memory_processes(count: usize) -> std::io::Result> { let mut processes = Self::list_processes()?; processes.sort_by(|a, b| b.memory_kb.cmp(&a.memory_kb)); processes.truncate(count); Ok(processes) } pub fn top_cpu_processes(count: usize) -> std::io::Result> { let mut processes = Self::list_processes()?; processes.sort_by(|a, b| { b.cpu_percent .partial_cmp(&a.cpu_percent) .unwrap_or(std::cmp::Ordering::Equal) }); processes.truncate(count); Ok(processes) } }