use super::{Container, ContainerStatus};
use crate::signal::Signal;
use anyhow::{bail, Context, Result};
use libcgroups::common::{create_cgroup_manager, get_cgroup_setup};
use nix::sys::signal::{self};
impl Container {
pub fn kill<S: Into<Signal>>(&mut self, signal: S, all: bool) -> Result<()> {
self.refresh_status()
.context("failed to refresh container status")?;
if self.can_kill() {
self.do_kill(signal, all)?;
} else {
if all && self.status() == ContainerStatus::Stopped {
self.do_kill(signal, all)?;
} else {
bail!(
"{} could not be killed because it was {:?}",
self.id(),
self.status()
)
}
}
self.set_status(ContainerStatus::Stopped).save()?;
Ok(())
}
pub(crate) fn do_kill<S: Into<Signal>>(&self, signal: S, all: bool) -> Result<()> {
if all {
self.kill_all_processes(signal)
} else {
self.kill_one_process(signal)
}
}
fn kill_one_process<S: Into<Signal>>(&self, signal: S) -> Result<()> {
let signal = signal.into().into_raw();
let pid = self.pid().unwrap();
log::debug!("kill signal {} to {}", signal, pid);
let res = signal::kill(pid, signal);
match res {
Err(nix::errno::Errno::ESRCH) => {
}
_ => res?,
}
if self.status() == ContainerStatus::Paused && signal == signal::Signal::SIGKILL {
match get_cgroup_setup()? {
libcgroups::common::CgroupSetup::Legacy
| libcgroups::common::CgroupSetup::Hybrid => {
let cgroups_path = self.spec()?.cgroup_path;
let use_systemd = self
.systemd()
.context("container state does not contain cgroup manager")?;
let cmanger = create_cgroup_manager(&cgroups_path, use_systemd, self.id())?;
cmanger.freeze(libcgroups::common::FreezerState::Thawed)?;
}
libcgroups::common::CgroupSetup::Unified => {}
}
}
Ok(())
}
fn kill_all_processes<S: Into<Signal>>(&self, signal: S) -> Result<()> {
let signal = signal.into().into_raw();
let cgroups_path = self.spec()?.cgroup_path;
let use_systemd = self
.systemd()
.context("container state does not contain cgroup manager")?;
let cmanger = create_cgroup_manager(&cgroups_path, use_systemd, self.id())?;
let ret = cmanger.freeze(libcgroups::common::FreezerState::Frozen);
if ret.is_err() {
log::warn!(
"failed to freeze container {}, error: {}",
self.id(),
ret.unwrap_err()
);
}
let pids = cmanger.get_all_pids()?;
pids.iter().try_for_each(|&pid| {
log::debug!("kill signal {} to {}", signal, pid);
let res = signal::kill(pid, signal);
match res {
Err(nix::errno::Errno::ESRCH) => {
Ok(())
}
_ => res,
}
})?;
let ret = cmanger.freeze(libcgroups::common::FreezerState::Thawed);
if ret.is_err() {
log::warn!(
"failed to thaw container {}, error: {}",
self.id(),
ret.unwrap_err()
);
}
Ok(())
}
}