pitchfork_cli/
procs.rs

1use crate::Result;
2use miette::IntoDiagnostic;
3use once_cell::sync::Lazy;
4use std::sync::Mutex;
5use sysinfo::ProcessesToUpdate;
6#[cfg(unix)]
7use sysinfo::Signal;
8
9pub struct Procs {
10    system: Mutex<sysinfo::System>,
11}
12
13pub static PROCS: Lazy<Procs> = Lazy::new(Procs::new);
14
15impl Default for Procs {
16    fn default() -> Self {
17        Self::new()
18    }
19}
20
21impl Procs {
22    pub fn new() -> Self {
23        let procs = Self {
24            system: Mutex::new(sysinfo::System::new()),
25        };
26        procs.refresh_processes();
27        procs
28    }
29
30    pub fn title(&self, pid: u32) -> Option<String> {
31        self.system
32            .lock()
33            .unwrap()
34            .process(sysinfo::Pid::from_u32(pid))
35            .map(|p| p.name().to_string_lossy().to_string())
36    }
37
38    pub fn is_running(&self, pid: u32) -> bool {
39        self.system
40            .lock()
41            .unwrap()
42            .process(sysinfo::Pid::from_u32(pid))
43            .is_some()
44    }
45
46    pub fn all_children(&self, pid: u32) -> Vec<u32> {
47        let system = self.system.lock().unwrap();
48        let all = system.processes();
49        let mut children = vec![];
50        for (child_pid, process) in all {
51            let mut process = process;
52            while let Some(parent) = process.parent() {
53                if parent == sysinfo::Pid::from_u32(pid) {
54                    children.push(child_pid.as_u32());
55                    break;
56                }
57                process = system.process(parent).unwrap();
58            }
59        }
60        children
61    }
62
63    pub async fn kill_async(&self, pid: u32) -> Result<bool> {
64        let result = tokio::task::spawn_blocking(move || PROCS.kill(pid))
65            .await
66            .into_diagnostic()?;
67        Ok(result)
68    }
69
70    fn kill(&self, pid: u32) -> bool {
71        if let Some(process) = self
72            .system
73            .lock()
74            .unwrap()
75            .process(sysinfo::Pid::from_u32(pid))
76        {
77            debug!("killing process {}", pid);
78            #[cfg(windows)]
79            process.kill();
80            #[cfg(unix)]
81            process.kill_with(Signal::Term);
82            process.wait();
83            true
84        } else {
85            false
86        }
87    }
88
89    pub(crate) fn refresh_processes(&self) {
90        self.system
91            .lock()
92            .unwrap()
93            .refresh_processes(ProcessesToUpdate::All, true);
94    }
95}