chj_unix_util/
processes.rs

1use std::{
2    borrow::Cow,
3    path::{Path, PathBuf},
4    process::Command,
5};
6
7use anyhow::{anyhow, bail, Context, Result};
8use nix::unistd::Pid;
9
10#[derive(Debug, Clone)]
11pub enum ProcessSelection {
12    All,
13    User(Cow<'static, str>),
14}
15
16impl Default for ProcessSelection {
17    fn default() -> Self {
18        ProcessSelection::All
19    }
20}
21
22#[derive(Default)]
23pub struct Processes {
24    pub selection: ProcessSelection,
25    pub ps_path: Option<PathBuf>,
26}
27
28impl Processes {
29    pub fn get_list(&self) -> Result<Vec<Pid>> {
30        let Self { selection, ps_path } = self;
31        let ps: &Path = "ps".as_ref();
32        let ps_path: &Path = ps_path
33            .as_ref()
34            .map(|p| -> &Path { p.as_ref() })
35            .unwrap_or(ps);
36        let mut cmd = Command::new(ps_path);
37        match selection {
38            ProcessSelection::All => {
39                cmd.args(["-e", "-o", "pid="]);
40            }
41            ProcessSelection::User(cow) => {
42                cmd.args(["-u", cow.as_ref(), "-o", "pid="]);
43            }
44        }
45        let output = cmd
46            .output()
47            .with_context(|| anyhow!("running {ps_path:?}"))?;
48
49        if output.status.success() {
50            let s = std::str::from_utf8(&output.stdout)
51                .with_context(|| anyhow!("parsing output from {ps_path:?} as utf8"))?;
52            let mut vec = Vec::new();
53            for line in s.split("\n") {
54                let s = line.trim();
55                if s.is_empty() {
56                    continue;
57                }
58                let pid: i32 = s
59                    .parse()
60                    .with_context(|| anyhow!("parsing {s:?} from {ps_path:?} as an i32"))?;
61                if pid < 0 {
62                    bail!("{ps_path:?} gave a negative number: {s:?}")
63                } else {
64                    vec.push(Pid::from_raw(pid));
65                }
66            }
67            Ok(vec)
68        } else {
69            bail!("command {ps_path:?} did not exit successfully")
70        }
71    }
72}