fix: treat EPERM from kill(pid, 0) as "process exists" in daemon liveness checks (#564)

Per POSIX, kill(pid, 0) returns EPERM when the process exists but the
caller lacks permission to signal it, and ESRCH when it does not exist.
The daemon liveness checks in both the Rust CLI and TypeScript daemon
treated any kill failure as "not running", which is incorrect when
running inside a macOS sandbox that restricts signal delivery to
(target self). This caused the CLI to delete the real daemon's socket
and PID files, then spawn a duplicate daemon.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
neilmix
2026-03-01 10:12:37 -06:00
committed by GitHub
co-authored by Claude Opus 4.6
parent 7238b7da4c
commit e912f541f2
3 changed files with 18 additions and 3 deletions
+7 -1
View File
@@ -159,7 +159,13 @@ fn is_daemon_running(session: &str) -> bool {
if let Ok(pid_str) = fs::read_to_string(&pid_path) {
if let Ok(pid) = pid_str.trim().parse::<i32>() {
unsafe {
return libc::kill(pid, 0) == 0;
if libc::kill(pid, 0) == 0 {
return true;
}
// EPERM means the process exists but we lack permission to
// signal it (e.g. inside a macOS sandbox). Only ESRCH means
// the process is genuinely gone.
return std::io::Error::last_os_error().raw_os_error() != Some(libc::ESRCH);
}
}
}