prs_lib/util/
proc.rs

1#[cfg(target_os = "linux")]
2pub fn pids_with_file_open(path: &std::path::Path) -> std::io::Result<Vec<nix::unistd::Pid>> {
3    use nix::libc::pid_t;
4    use nix::unistd::Pid;
5    use procfs::process::all_processes;
6
7    let mut pids = vec![];
8
9    let target = path.canonicalize()?;
10
11    for process in all_processes().unwrap() {
12        let Ok(process) = process else {
13            continue;
14        };
15
16        let Ok(fds) = process.fd() else {
17            continue;
18        };
19
20        for fd in fds {
21            let Ok(fd) = fd else {
22                continue;
23            };
24
25            if matches!(fd.target, procfs::process::FDTarget::Path(path) if path == target) {
26                pids.push(Pid::from_raw(process.pid as pid_t));
27            }
28        }
29    }
30
31    Ok(pids)
32}
33
34#[cfg(any(target_os = "macos", target_os = "freebsd"))]
35pub fn pids_with_file_open(path: &std::path::Path) -> std::io::Result<Vec<nix::unistd::Pid>> {
36    use nix::libc::pid_t;
37    use nix::unistd::Pid;
38    use std::process::Command;
39
40    // Use `lsof -t <file>` to get PIDs which is more portable across Unix systems
41    let output = Command::new("lsof")
42        .arg("-t")
43        .arg(path.to_string_lossy().as_ref())
44        .output()?;
45    if !output.status.success() {
46        return Ok(Vec::new());
47    }
48
49    let stdout = String::from_utf8_lossy(&output.stdout);
50    let mut pids = Vec::new();
51    for line in stdout.lines() {
52        if let Ok(pid) = line.trim().parse::<pid_t>() {
53            pids.push(Pid::from_raw(pid));
54        }
55    }
56
57    Ok(pids)
58}
59
60#[cfg(target_os = "linux")]
61pub fn cmdline(pid: nix::unistd::Pid) -> std::io::Result<String> {
62    use std::fs;
63
64    let cmdline = fs::read_to_string(format!("/proc/{pid}/cmdline"))?;
65    Ok(cmdline.replace('\0', " ").trim().to_string())
66}
67
68#[cfg(any(target_os = "macos", target_os = "freebsd"))]
69pub fn cmdline(pid: nix::unistd::Pid) -> std::io::Result<String> {
70    use std::process::Command;
71
72    let output = Command::new("ps")
73        .arg("-p")
74        .arg(pid.as_raw().to_string())
75        .arg("-o")
76        .arg("command=")
77        .output()?;
78    if !output.status.success() {
79        return Err(std::io::Error::other("Failed to get process command line"));
80    }
81
82    let cmdline = String::from_utf8_lossy(&output.stdout);
83    Ok(cmdline.trim().to_string())
84}