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 app::DaemonCommand;
use eww_shared_util::VarName; use eww_shared_util::VarName;
use nix::{
sys::signal,
unistd::{setpgid, Pid},
};
use simplexpr::dynval::DynVal; use simplexpr::dynval::DynVal;
use tokio::{ use tokio::{
io::{AsyncBufReadExt, BufReader}, io::{AsyncBufReadExt, BufReader},
@ -203,12 +207,17 @@ impl ListenVarHandler {
let evt_send = self.evt_send.clone(); let evt_send = self.evt_send.clone();
tokio::spawn(async move { tokio::spawn(async move {
crate::try_logging_errors!(format!("Executing listen var-command {}", &var.command) => { 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]) .args(&["-c", &var.command])
.stdout(std::process::Stdio::piped()) .stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped()) .stderr(std::process::Stdio::piped())
.stdin(std::process::Stdio::null()) .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 stdout_lines = BufReader::new(handle.stdout.take().unwrap()).lines();
let mut stderr_lines = BufReader::new(handle.stderr.take().unwrap()).lines(); let mut stderr_lines = BufReader::new(handle.stderr.take().unwrap()).lines();
crate::loop_select_exiting! { crate::loop_select_exiting! {
@ -223,7 +232,7 @@ impl ListenVarHandler {
} }
else => break, else => break,
} }
let _ = handle.kill().await; terminate_handle(handle).await;
}); });
}); });
} }
@ -245,3 +254,17 @@ impl Drop for ListenVarHandler {
self.stop_all(); 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;
}
}