summaryrefslogtreecommitdiffhomepage
path: root/talpid-macos/src/process.rs
blob: 69722e054ceb8ce5207b5ec0241dee1548d0a06a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
use libc::{c_void, pid_t, proc_listallpids, proc_pidpath};
use std::{
    io,
    path::{Path, PathBuf},
};

/// Return the first process identifier matching a specified path, if one exists.
pub fn pid_of_path(find_path: impl AsRef<Path>) -> Option<pid_t> {
    match list_pids() {
        Ok(pids) => {
            for pid in pids {
                if let Ok(path) = process_path(pid) {
                    if path == find_path.as_ref() {
                        return Some(pid);
                    }
                }
            }
            None
        }
        Err(error) => {
            log::error!("Failed to list processes: {error}");
            None
        }
    }
}

/// Obtain a list of all process identifiers
pub fn list_pids() -> io::Result<Vec<pid_t>> {
    // SAFETY: Passing in null and 0 returns the number of processes
    let num_pids = unsafe { proc_listallpids(std::ptr::null_mut(), 0) };
    if num_pids <= 0 {
        return Err(io::Error::last_os_error());
    }
    let num_pids = usize::try_from(num_pids).unwrap();
    let mut pids = vec![0i32; num_pids];

    let buf_sz = (num_pids * std::mem::size_of::<pid_t>()) as i32;
    // SAFETY: 'pids' is large enough to contain 'num_pids' processes
    let num_pids = unsafe { proc_listallpids(pids.as_mut_ptr() as *mut c_void, buf_sz) };
    if num_pids == -1 {
        return Err(io::Error::last_os_error());
    }

    pids.resize(usize::try_from(num_pids).unwrap(), 0);

    Ok(pids)
}

/// Return the path of the process `pid`
pub fn process_path(pid: pid_t) -> io::Result<PathBuf> {
    let mut buffer = [0u8; libc::MAXPATHLEN as usize];
    // SAFETY: `proc_pidpath` returns at most `buffer.len()` bytes
    let buf_len = unsafe {
        proc_pidpath(
            pid,
            buffer.as_mut_ptr() as *mut c_void,
            u32::try_from(buffer.len()).unwrap(),
        )
    };
    if buf_len == -1 {
        return Err(io::Error::last_os_error());
    }
    Ok(PathBuf::from(
        std::str::from_utf8(&buffer[0..buf_len as usize])
            .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid process path"))?,
    ))
}