use std::io;
use std::process::Command as CommandSys;
pub fn kill_by_pid(pid: i64) -> Result<(), KillByPidError> {
let mut cmd = build_kill_command(true, std::iter::once(pid), None);
let output = cmd.output().map_err(KillByPidError::Output)?;
match output.status.success() {
true => Ok(()),
false => Err(KillByPidError::KillProcess),
}
}
pub enum KillByPidError {
Output(io::Error),
KillProcess,
}
pub fn build_kill_command(
force: bool,
pids: impl Iterator<Item = i64>,
signal: Option<u32>,
) -> CommandSys {
if cfg!(windows) {
let mut cmd = CommandSys::new("taskkill");
if force {
cmd.arg("/F");
}
for id in pids {
cmd.arg("/PID");
cmd.arg(id.to_string());
}
cmd
} else {
let mut cmd = CommandSys::new("kill");
if let Some(signal_value) = signal {
cmd.arg(format!("-{signal_value}"));
} else if force {
cmd.arg("-9");
}
cmd.arg("--");
cmd.args(pids.map(|id| id.to_string()));
cmd
}
}
#[cfg(all(test, unix))]
mod tests {
use super::*;
#[test]
fn build_kill_command_separates_options_from_negative_pids() {
let cmd = build_kill_command(false, std::iter::once(-9), None);
let args = cmd
.get_args()
.map(|arg| arg.to_string_lossy().into_owned())
.collect::<Vec<_>>();
assert_eq!(args, ["--", "-9"]);
}
#[test]
fn build_kill_command_keeps_signal_and_pid_separator() {
let cmd = build_kill_command(false, std::iter::once(123), Some(9));
let args = cmd
.get_args()
.map(|arg| arg.to_string_lossy().into_owned())
.collect::<Vec<_>>();
assert_eq!(args, ["-9", "--", "123"]);
}
}