#[cfg(unix)]
pub(crate) fn process_exists(pid: u32) -> bool {
let Ok(pid) = i32::try_from(pid) else {
return false;
};
!matches!(
nix::sys::signal::kill(nix::unistd::Pid::from_raw(pid), None),
Err(nix::errno::Errno::ESRCH)
)
}
#[cfg(not(unix))]
pub(crate) fn process_exists(_pid: u32) -> bool {
true
}
#[cfg(target_os = "linux")]
pub(crate) fn process_start_token(pid: u32) -> Option<String> {
let stat = std::fs::read_to_string(format!("/proc/{pid}/stat")).ok()?;
let after_comm = stat.rsplit_once(')')?.1;
let starttime = after_comm.split_whitespace().nth(19)?;
Some(starttime.to_string())
}
#[cfg(target_os = "macos")]
pub(crate) fn process_start_token(pid: u32) -> Option<String> {
let output = std::process::Command::new("/bin/ps")
.env("LC_ALL", "C")
.env("TZ", "UTC")
.args(["-o", "lstart=", "-p", &pid.to_string()])
.output()
.ok()?;
let text = String::from_utf8_lossy(&output.stdout).trim().to_string();
(!text.is_empty()).then_some(text)
}
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
pub(crate) fn process_start_token(_pid: u32) -> Option<String> {
None
}
#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used)]
mod tests {
use super::*;
#[test]
fn this_process_exists() {
assert!(process_exists(std::process::id()));
}
#[cfg(unix)]
#[test]
fn a_reaped_child_does_not_exist() {
let mut child = std::process::Command::new("true")
.spawn()
.expect("spawn `true`");
child.wait().expect("wait for `true`");
assert!(!process_exists(child.id()));
}
#[cfg(any(target_os = "linux", target_os = "macos"))]
#[test]
fn this_process_has_a_stable_start_token() {
let pid = std::process::id();
let a = process_start_token(pid).expect("a token for this running process");
let b = process_start_token(pid).expect("a second reading");
assert_eq!(
a, b,
"the same still-running process must read the same token twice"
);
}
#[cfg(unix)]
#[test]
fn a_reaped_child_has_no_start_token() {
let mut child = std::process::Command::new("true")
.spawn()
.expect("spawn `true`");
let pid = child.id();
child.wait().expect("wait for `true`");
assert_eq!(process_start_token(pid), None);
}
}