#[cfg(any(target_os = "macos", test))]
fn pidfile_path() -> std::path::PathBuf {
std::env::temp_dir().join("teamctl-caffeinate.pid")
}
#[cfg(any(target_os = "macos", test))]
fn read_pid(contents: &str) -> Option<i32> {
match contents.trim().parse::<i32>() {
Ok(pid) if pid > 0 => Some(pid),
_ => None,
}
}
#[cfg(all(unix, any(target_os = "macos", test)))]
fn pid_alive(pid: i32) -> bool {
let ret = unsafe { libc::kill(pid as libc::pid_t, 0) };
ret == 0 || std::io::Error::last_os_error().raw_os_error() == Some(libc::EPERM)
}
#[cfg(target_os = "macos")]
pub fn ensure_running() {
use std::fs;
use std::process::{Command, Stdio};
let pf = pidfile_path();
if let Ok(s) = fs::read_to_string(&pf) {
if let Some(pid) = read_pid(&s) {
if pid_alive(pid) {
return;
}
}
}
match Command::new("caffeinate")
.args(["-i", "-s"])
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()
{
Ok(child) => {
if let Err(e) = fs::write(&pf, child.id().to_string()) {
eprintln!("warn · caffeinate: started but could not record pid ({e})");
}
}
Err(e) => {
eprintln!("warn · caffeinate: could not start, host may idle-sleep ({e})");
}
}
}
#[cfg(not(target_os = "macos"))]
pub fn ensure_running() {}
#[cfg(target_os = "macos")]
pub fn stop_if_last() {
use std::fs;
if super::sessions::any_teamctl_session_running() {
return;
}
let pf = pidfile_path();
if let Ok(s) = fs::read_to_string(&pf) {
if let Some(pid) = read_pid(&s) {
if pid_alive(pid) {
unsafe { libc::kill(pid as libc::pid_t, libc::SIGTERM) };
}
}
}
let _ = fs::remove_file(&pf);
}
#[cfg(not(target_os = "macos"))]
pub fn stop_if_last() {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn read_pid_parses_valid_and_rejects_garbage() {
assert_eq!(read_pid("1234\n"), Some(1234));
assert_eq!(read_pid(" 42 "), Some(42));
assert_eq!(read_pid(""), None);
assert_eq!(read_pid("abc"), None);
assert_eq!(read_pid("0"), None);
assert_eq!(read_pid("-5"), None);
}
#[test]
fn pidfile_path_is_host_global_named() {
let p = pidfile_path();
assert_eq!(p.file_name().unwrap(), "teamctl-caffeinate.pid");
assert_eq!(p.parent().unwrap(), std::env::temp_dir());
}
#[cfg(unix)]
#[test]
fn pid_alive_true_for_self_false_for_sentinel() {
assert!(pid_alive(std::process::id() as i32));
assert!(!pid_alive(i32::MAX));
}
}