@@ -1,4 +1,5 @@ |
| 1 | use std::collections::HashSet; | 1 | use std::collections::HashSet; |
| | 2 | +use std::os::unix::process::CommandExt; |
| 2 | use std::path::PathBuf; | 3 | use std::path::PathBuf; |
| 3 | use std::sync::{Arc, Mutex}; | 4 | use std::sync::{Arc, Mutex}; |
| 4 | | 5 | |
@@ -95,8 +96,10 @@ impl LuaState { |
| 95 | // SAFETY: Sending signal 0 just checks if process exists | 96 | // SAFETY: Sending signal 0 just checks if process exists |
| 96 | let exists = unsafe { libc::kill(pid as i32, 0) == 0 }; | 97 | let exists = unsafe { libc::kill(pid as i32, 0) == 0 }; |
| 97 | if exists { | 98 | if exists { |
| 98 | - tracing::debug!("Sending SIGTERM to PID {}", pid); | 99 | + // Kill the entire process group (negative PID) to get children too |
| 99 | - unsafe { libc::kill(pid as i32, libc::SIGTERM); } | 100 | + // This handles cases like "sh -c garterm" where sh spawns garterm |
| | 101 | + tracing::debug!("Sending SIGTERM to process group {}", pid); |
| | 102 | + unsafe { libc::kill(-(pid as i32), libc::SIGTERM); } |
| 100 | } | 103 | } |
| 101 | } | 104 | } |
| 102 | } | 105 | } |
@@ -643,9 +646,12 @@ impl LuaConfig { |
| 643 | let state = Arc::clone(&self.state); | 646 | let state = Arc::clone(&self.state); |
| 644 | let exec_fn = self.lua.create_function(move |_, cmd: String| { | 647 | let exec_fn = self.lua.create_function(move |_, cmd: String| { |
| 645 | tracing::debug!("exec: {}", cmd); | 648 | tracing::debug!("exec: {}", cmd); |
| | 649 | + // process_group(0) makes the child its own process group leader |
| | 650 | + // so we can kill the entire group (including grandchildren) on exit |
| 646 | if let Ok(child) = std::process::Command::new("sh") | 651 | if let Ok(child) = std::process::Command::new("sh") |
| 647 | .arg("-c") | 652 | .arg("-c") |
| 648 | .arg(&cmd) | 653 | .arg(&cmd) |
| | 654 | + .process_group(0) |
| 649 | .spawn() | 655 | .spawn() |
| 650 | { | 656 | { |
| 651 | let pid = child.id(); | 657 | let pid = child.id(); |
@@ -669,9 +675,12 @@ impl LuaConfig { |
| 669 | } | 675 | } |
| 670 | } | 676 | } |
| 671 | tracing::info!("exec_once: {}", cmd); | 677 | tracing::info!("exec_once: {}", cmd); |
| | 678 | + // process_group(0) makes the child its own process group leader |
| | 679 | + // so we can kill the entire group (including grandchildren) on exit |
| 672 | if let Ok(child) = std::process::Command::new("sh") | 680 | if let Ok(child) = std::process::Command::new("sh") |
| 673 | .arg("-c") | 681 | .arg("-c") |
| 674 | .arg(&cmd) | 682 | .arg(&cmd) |
| | 683 | + .process_group(0) |
| 675 | .spawn() | 684 | .spawn() |
| 676 | { | 685 | { |
| 677 | let pid = child.id(); | 686 | let pid = child.id(); |