fix: Fix listen-var process cleanup

listenvars now run in their own process-groups. Thus, when they get
stopped, not only does the main script get killed, but also the spawned
children, rather than them being adopted by init.
This commit is contained in:
elkowar 2021-08-24 14:01:58 +02:00
parent 30868de604
commit 8de692da8a
No known key found for this signature in database
GPG key ID: E321AD71B1D1F27F

View file

@ -8,6 +8,10 @@ use anyhow::*;
use app::DaemonCommand;
use eww_shared_util::VarName;
use nix::{
sys::signal,
unistd::{setpgid, Pid},
};
use simplexpr::dynval::DynVal;
use tokio::{
io::{AsyncBufReadExt, BufReader},
@ -203,12 +207,17 @@ impl ListenVarHandler {
let evt_send = self.evt_send.clone();
tokio::spawn(async move {
crate::try_logging_errors!(format!("Executing listen var-command {}", &var.command) => {
let mut handle = tokio::process::Command::new("sh")
let mut handle = unsafe {
tokio::process::Command::new("sh")
.args(&["-c", &var.command])
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped())
.stdin(std::process::Stdio::null())
.spawn()?;
.pre_exec(|| {
let _ = setpgid(Pid::from_raw(0), Pid::from_raw(0));
Ok(())
}).spawn()?
};
let mut stdout_lines = BufReader::new(handle.stdout.take().unwrap()).lines();
let mut stderr_lines = BufReader::new(handle.stderr.take().unwrap()).lines();
crate::loop_select_exiting! {
@ -223,7 +232,7 @@ impl ListenVarHandler {
}
else => break,
}
let _ = handle.kill().await;
terminate_handle(handle).await;
});
});
}
@ -245,3 +254,17 @@ impl Drop for ListenVarHandler {
self.stop_all();
}
}
async fn terminate_handle(mut child: tokio::process::Child) {
if let Some(id) = child.id() {
let _ = signal::killpg(Pid::from_raw(id as i32), signal::SIGTERM);
tokio::select! {
_ = child.wait() => {},
_ = tokio::time::sleep(std::time::Duration::from_secs(10)) => {
let _ = child.kill().await;
}
};
} else {
let _ = child.kill().await;
}
}