use std::io;
use std::process::Command;
pub fn tree_kill_sync(pid: u32, _signal: Option<&str>) -> io::Result<()> {
#[cfg(windows)]
{
let status = Command::new("taskkill")
.args(["/pid", &pid.to_string(), "/T", "/F"])
.status()?;
return status.success().then_some(()).ok_or_else(|| {
io::Error::new(
io::ErrorKind::Other,
format!("taskkill failed for pid {pid}"),
)
});
}
#[cfg(not(windows))]
{
for child_pid in get_all_childs(pid)? {
kill_pid(child_pid, _signal)?;
}
kill_pid(pid, _signal)
}
}
#[cfg(not(windows))]
fn get_all_pid() -> io::Result<Vec<(u32, u32)>> {
let output = Command::new("ps").args(["-A", "-o", "pid,ppid"]).output()?;
if !output.status.success() {
return Ok(Vec::new());
}
let stdout = String::from_utf8_lossy(&output.stdout);
Ok(stdout
.lines()
.skip(1)
.filter_map(|line| {
let mut parts = line.split_whitespace();
let pid = parts.next()?.parse::<u32>().ok()?;
let ppid = parts.next()?.parse::<u32>().ok()?;
Some((pid, ppid))
})
.collect())
}
#[cfg(not(windows))]
fn get_all_childs(pid: u32) -> io::Result<Vec<u32>> {
let all_pid = get_all_pid()?;
let mut result = Vec::new();
collect_childs(pid, &all_pid, &mut result);
Ok(result)
}
#[cfg(not(windows))]
fn collect_childs(pid: u32, all_pid: &[(u32, u32)], result: &mut Vec<u32>) {
for (child_pid, ppid) in all_pid.iter().copied().filter(|(_, ppid)| *ppid == pid) {
result.push(child_pid);
collect_childs(child_pid, all_pid, result);
}
}
#[cfg(not(windows))]
fn kill_pid(pid: u32, signal: Option<&str>) -> io::Result<()> {
let signal = signal.unwrap_or("TERM").trim_start_matches("SIG");
let status = Command::new("kill")
.args([format!("-{signal}"), pid.to_string()])
.status()?;
if status.success() {
Ok(())
} else {
Err(io::Error::new(
io::ErrorKind::Other,
format!("kill failed for pid {pid}"),
))
}
}