use super::{check_liveness, read_state, write_state, ContainerStatus};
pub fn cmd_stop(name: &str, time: u64) -> Result<(), Box<dyn std::error::Error>> {
let mut state = read_state(name).map_err(|_| format!("no container named '{}'", name))?;
if state.status != ContainerStatus::Running {
return Ok(());
}
if state.pid == 0 && check_liveness(state.watcher_pid) {
let deadline = std::time::Instant::now() + std::time::Duration::from_secs(2);
while state.pid == 0
&& state.status == ContainerStatus::Running
&& check_liveness(state.watcher_pid)
&& std::time::Instant::now() < deadline
{
std::thread::sleep(std::time::Duration::from_millis(50));
if let Ok(s) = read_state(name) {
state = s;
}
}
}
if !check_liveness(state.pid) {
state.status = ContainerStatus::Exited;
write_state(&state)?;
return Ok(());
}
let pid = state.pid;
let stop_sig = state
.spawn_config
.as_ref()
.and_then(|sc| sc.stop_signal.as_deref())
.map(parse_signal)
.unwrap_or(libc::SIGTERM);
let r = unsafe { libc::kill(pid, stop_sig) };
if r != 0 {
let err = std::io::Error::last_os_error();
if err.raw_os_error() == Some(libc::ESRCH) {
} else {
return Err(format!("kill({}): {}", pid, err).into());
}
}
let deadline = std::time::Instant::now() + std::time::Duration::from_secs(time.max(1));
while check_liveness(pid) && std::time::Instant::now() < deadline {
std::thread::sleep(std::time::Duration::from_millis(100));
}
if check_liveness(pid) {
unsafe { libc::kill(pid, libc::SIGKILL) };
let kill_deadline = std::time::Instant::now() + std::time::Duration::from_secs(5);
while check_liveness(pid) && std::time::Instant::now() < kill_deadline {
std::thread::sleep(std::time::Duration::from_millis(100));
}
}
state.status = ContainerStatus::Exited;
write_state(&state)?;
Ok(())
}
fn parse_signal(s: &str) -> libc::c_int {
let upper = s.trim().to_uppercase();
let name = upper.strip_prefix("SIG").unwrap_or(&upper);
match name {
"HUP" => libc::SIGHUP,
"INT" => libc::SIGINT,
"QUIT" => libc::SIGQUIT,
"ILL" => libc::SIGILL,
"TRAP" => libc::SIGTRAP,
"ABRT" | "IOT" => libc::SIGABRT,
"BUS" => libc::SIGBUS,
"FPE" => libc::SIGFPE,
"KILL" => libc::SIGKILL,
"USR1" => libc::SIGUSR1,
"SEGV" => libc::SIGSEGV,
"USR2" => libc::SIGUSR2,
"PIPE" => libc::SIGPIPE,
"ALRM" => libc::SIGALRM,
"TERM" => libc::SIGTERM,
"CHLD" => libc::SIGCHLD,
"CONT" => libc::SIGCONT,
"STOP" => libc::SIGSTOP,
"TSTP" => libc::SIGTSTP,
"TTIN" => libc::SIGTTIN,
"TTOU" => libc::SIGTTOU,
"URG" => libc::SIGURG,
"XCPU" => libc::SIGXCPU,
"XFSZ" => libc::SIGXFSZ,
"WINCH" => libc::SIGWINCH,
_ => s.parse::<libc::c_int>().unwrap_or(libc::SIGTERM),
}
}