use libcgroups::common::{get_cgroup_setup, CgroupManager};
use nix::sys::signal::{self};
use super::{Container, ContainerStatus};
use crate::error::LibcontainerError;
use crate::signal::Signal;
impl Container {
pub fn kill<S: Into<Signal>>(&mut self, signal: S, all: bool) -> Result<(), LibcontainerError> {
self.refresh_status()?;
match self.can_kill() {
true => {
self.do_kill(signal, all)?;
}
false if all && self.status() == ContainerStatus::Stopped => {
self.do_kill(signal, all)?;
}
false => {
tracing::error!(id = ?self.id(), status = ?self.status(), "cannot kill container due to incorrect state");
return Err(LibcontainerError::IncorrectStatus);
}
}
self.set_status(ContainerStatus::Stopped).save()?;
Ok(())
}
pub(crate) fn do_kill<S: Into<Signal>>(
&self,
signal: S,
all: bool,
) -> Result<(), LibcontainerError> {
if all {
self.kill_all_processes(signal)
} else {
self.kill_one_process(signal)
}
}
fn kill_one_process<S: Into<Signal>>(&self, signal: S) -> Result<(), LibcontainerError> {
let signal = signal.into().into_raw();
let pid = self.pid().ok_or(LibcontainerError::Other(
"container process pid not found in state".into(),
))?;
tracing::debug!("kill signal {} to {}", signal, pid);
match signal::kill(pid, signal) {
Ok(_) => {}
Err(nix::errno::Errno::ESRCH) => {
}
Err(err) => {
tracing::error!(id = ?self.id(), err = ?err, ?pid, ?signal, "failed to kill process");
return Err(LibcontainerError::OtherSyscall(err));
}
}
if self.status() == ContainerStatus::Paused && signal == signal::Signal::SIGKILL {
match get_cgroup_setup()? {
libcgroups::common::CgroupSetup::Legacy
| libcgroups::common::CgroupSetup::Hybrid => {
let cmanager = libcgroups::common::create_cgroup_manager(
libcgroups::common::CgroupConfig {
cgroup_path: self.spec()?.cgroup_path,
systemd_cgroup: self.systemd(),
container_name: self.id().to_string(),
},
)?;
cmanager.freeze(libcgroups::common::FreezerState::Thawed)?;
}
libcgroups::common::CgroupSetup::Unified => {}
}
}
Ok(())
}
fn kill_all_processes<S: Into<Signal>>(&self, signal: S) -> Result<(), LibcontainerError> {
let signal = signal.into().into_raw();
let cmanager =
libcgroups::common::create_cgroup_manager(libcgroups::common::CgroupConfig {
cgroup_path: self.spec()?.cgroup_path,
systemd_cgroup: self.systemd(),
container_name: self.id().to_string(),
})?;
if let Err(e) = cmanager.freeze(libcgroups::common::FreezerState::Frozen) {
tracing::warn!(
err = ?e,
id = ?self.id(),
"failed to freeze container",
);
}
let pids = cmanager.get_all_pids()?;
pids.iter()
.try_for_each(|&pid| {
tracing::debug!("kill signal {} to {}", signal, pid);
let res = signal::kill(pid, signal);
match res {
Err(nix::errno::Errno::ESRCH) => {
Ok(())
}
_ => res,
}
})
.map_err(LibcontainerError::OtherSyscall)?;
if let Err(err) = cmanager.freeze(libcgroups::common::FreezerState::Thawed) {
tracing::warn!(
err = ?err,
id = ?self.id(),
"failed to thaw container",
);
}
Ok(())
}
}