diff --git a/Cargo.lock b/Cargo.lock index af420a2..1666d3b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -346,6 +346,7 @@ version = "0.1.0" dependencies = [ "chrono", "clap", + "libc", "nix", "serde", "toml", diff --git a/Cargo.toml b/Cargo.toml index 1f08332..e3806e1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,3 +9,4 @@ serde = { version = "1", features = ["derive"] } toml = "0.8" chrono = "0.4" nix = { version = "0.29", default-features = false, features = ["signal", "fs"] } +libc = "0.2" diff --git a/src/daemon.rs b/src/daemon.rs index f297bf6..fe28922 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -3,6 +3,7 @@ use std::fs; use std::io::{BufRead, BufReader, Write}; use std::os::unix::fs::PermissionsExt; use std::os::unix::net::{UnixListener, UnixStream}; +use std::os::unix::process::CommandExt; use std::process::{Child, Command, Stdio}; use std::time::{Duration, SystemTime}; use std::sync::atomic::{AtomicBool, Ordering}; @@ -165,20 +166,28 @@ fn spawn(name: &str, cfg: &ServiceConfig) -> Option { let log_path = log_path.to_string_lossy().to_string(); let cmd = cfg.resolve_command(name, &log_path); - let mut child = match Command::new("sh") - .arg("-c") - .arg(&cmd) - .current_dir(&cfg.workdir) - .envs(&cfg.env) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .stdin(Stdio::null()) - .spawn() - { - Ok(c) => c, - Err(e) => { - append_log(&log_path, &format!("E: spawn failed: {}", e)); - return None; + let mut child = { + let mut sh = Command::new("sh"); + sh.arg("-c") + .arg(&cmd) + .current_dir(&cfg.workdir) + .envs(&cfg.env) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .stdin(Stdio::null()); + // SAFETY: pre_exec runs in the child after fork; minimal ops only + unsafe { + sh.pre_exec(|| { + libc::prctl(libc::PR_SET_PDEATHSIG, libc::SIGTERM); + Ok(()) + }); + } + match sh.spawn() { + Ok(c) => c, + Err(e) => { + append_log(&log_path, &format!("E: spawn failed: {}", e)); + return None; + } } };