diff --git a/Cargo.lock b/Cargo.lock index 938f7cf..1822715 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -423,6 +423,27 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +[[package]] +name = "errno" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "fastrand" version = "1.8.0" @@ -626,6 +647,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "io-lifetimes" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24c3f4eff5495aee4c0399d7b6a0dc2b6e81be84242ffbfcf253ebacccc1d0cb" + [[package]] name = "itertools" version = "0.10.3" @@ -662,6 +689,12 @@ version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +[[package]] +name = "linux-raw-sys" +version = "0.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d2456c373231a208ad294c33dc5bff30051eafd954cd4caae83a712b12854d" + [[package]] name = "lock_api" version = "0.4.7" @@ -974,15 +1007,15 @@ dependencies = [ [[package]] name = "procfs" -version = "0.12.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0941606b9934e2d98a3677759a971756eb821f75764d0e0d26946d08e74d9104" +checksum = "2dfb6451c91904606a1abe93e83a8ec851f45827fa84273f256ade45dc095818" dependencies = [ "bitflags", "byteorder", "hex", "lazy_static", - "libc", + "rustix", ] [[package]] @@ -1243,6 +1276,20 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "0.35.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d51cc38aa10f6bbb377ed28197aa052aa4e2b762c22be9d3153d01822587e787" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys", +] + [[package]] name = "rustls" version = "0.20.6" diff --git a/Cargo.toml b/Cargo.toml index 271ec85..1656a4b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,4 +67,4 @@ serde_yaml = "0.9" [target.'cfg(any(target_os = "linux", target_os = "freebsd"))'.dependencies] nix = "0.24" whoami = "1" -procfs = { version = "0.12", default-features = false } +procfs = { version = "0.14", default-features = false } diff --git a/lib/Cargo.toml b/lib/Cargo.toml index ab46138..0e43ddf 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -71,4 +71,4 @@ whoami = "1" # Linux / Freebsd [target.'cfg(any(target_os = "linux", target_os = "freebsd"))'.dependencies] -procfs = { version = "0.12", default-features = false } +procfs = { version = "0.14", default-features = false } diff --git a/lib/src/process_helper/linux.rs b/lib/src/process_helper/linux.rs index 9899265..468697a 100644 --- a/lib/src/process_helper/linux.rs +++ b/lib/src/process_helper/linux.rs @@ -260,7 +260,7 @@ fn send_signal_to_processes(processes: Vec, signal: Signal) { } /// Get all children of a specific process -fn get_child_processes(pid: i32) -> Vec { +fn get_child_processes(ppid: i32) -> Vec { let all_processes = match all_processes() { Err(error) => { warn!("Failed to get full process list: {error}"); @@ -269,9 +269,18 @@ fn get_child_processes(pid: i32) -> Vec { Ok(processes) => processes, }; + // Get all processes whose `stat` can be access without any errors. + // We then search for processes with the correct parent process id. all_processes .into_iter() - .filter(|process| process.stat.ppid == pid) + .filter_map(|process| process.ok()) + .filter(|process| { + if let Ok(stat) = process.stat() { + stat.ppid == ppid + } else { + false + } + }) .collect() } @@ -288,6 +297,7 @@ mod tests { use std::thread::sleep; use std::time::Duration; + use anyhow::Result; use pretty_assertions::assert_eq; use super::*; @@ -310,7 +320,7 @@ mod tests { #[test] /// Ensure a `sh -c` command will be properly killed without detached processes. - fn test_shell_command_is_killed() { + fn test_shell_command_is_killed() -> Result<()> { let mut child = compile_shell_command("sleep 60 & sleep 60 && echo 'this is a test'") .spawn() .expect("Failed to spawn echo"); @@ -336,14 +346,16 @@ mod tests { // Assert that all child processes have been killed. for child_process in child_processes { - assert!(process_is_gone(child_process.stat.pid)); + assert!(!child_process.is_alive()); } + + Ok(()) } #[test] /// Ensure a `sh -c` command will be properly killed without detached processes when using unix /// signals directly. - fn test_shell_command_is_killed_with_signal() { + fn test_shell_command_is_killed_with_signal() -> Result<()> { let child = compile_shell_command("sleep 60 & sleep 60 && echo 'this is a test'") .spawn() .expect("Failed to spawn echo"); @@ -369,14 +381,16 @@ mod tests { // Assert that all child processes have been killed. for child_process in child_processes { - assert!(process_is_gone(child_process.stat.pid)); + assert!(!child_process.is_alive()); } + + Ok(()) } #[test] /// Ensure that a `sh -c` process with a child process that has children of its own /// will properly kill all processes and their children's children without detached processes. - fn test_shell_command_children_are_killed() { + fn test_shell_command_children_are_killed() -> Result<()> { let mut child = compile_shell_command("bash -c 'sleep 60 && sleep 60' && sleep 60") .spawn() .expect("Failed to spawn echo"); @@ -393,7 +407,7 @@ mod tests { assert_eq!(child_processes.len(), 1); let mut childrens_children = Vec::new(); for child_process in &child_processes { - childrens_children.extend(get_child_processes(child_process.stat.pid)); + childrens_children.extend(get_child_processes(child_process.stat()?.pid)); } assert_eq!(childrens_children.len(), 1); @@ -408,18 +422,20 @@ mod tests { // Assert that all child processes have been killed. for child_process in child_processes { - assert!(process_is_gone(child_process.stat.pid)); + assert!(!child_process.is_alive()); } // Assert that all children's child processes have been killed. for child_process in childrens_children { - assert!(process_is_gone(child_process.stat.pid)); + assert!(!child_process.is_alive()); } + + Ok(()) } #[test] /// Ensure a normal command without `sh -c` will be killed. - fn test_normal_command_is_killed() { + fn test_normal_command_is_killed() -> Result<()> { let mut child = Command::new("sleep") .arg("60") .spawn() @@ -442,12 +458,14 @@ mod tests { sleep(Duration::from_millis(500)); assert!(process_is_gone(pid)); + + Ok(()) } #[test] /// Ensure a normal command and all its children will be /// properly killed without any detached processes. - fn test_normal_command_children_are_killed() { + fn test_normal_command_children_are_killed() -> Result<()> { let mut child = Command::new("bash") .arg("-c") .arg("sleep 60 & sleep 60 && sleep 60") @@ -475,7 +493,9 @@ mod tests { // Assert that all child processes have been killed. for child_process in child_processes { - assert!(process_is_gone(child_process.stat.pid)); + assert!(!child_process.is_alive()); } + + Ok(()) } }