use anyhow::Result;
use nix::unistd;
use nix::unistd::Pid;
pub fn container_fork<F: FnOnce() -> Result<i32>>(cb: F) -> Result<Pid> {
match unsafe { unistd::fork()? } {
unistd::ForkResult::Parent { child } => Ok(child),
unistd::ForkResult::Child => {
let ret = match cb() {
Err(error) => {
log::debug!("failed to run fork: {:?}", error);
-1
}
Ok(exit_code) => exit_code,
};
std::process::exit(ret);
}
}
}
#[cfg(test)]
mod test {
use super::*;
use anyhow::{bail, Result};
use nix::sys::wait::{waitpid, WaitStatus};
#[test]
fn test_container_fork() -> Result<()> {
let pid = container_fork(|| Ok(0))?;
match waitpid(pid, None).expect("wait pid failed.") {
WaitStatus::Exited(p, status) => {
assert_eq!(pid, p);
assert_eq!(status, 0);
Ok(())
}
_ => bail!("test failed"),
}
}
#[test]
fn test_container_err_fork() -> Result<()> {
let pid = container_fork(|| bail!(""))?;
match waitpid(pid, None).expect("wait pid failed.") {
WaitStatus::Exited(p, status) => {
assert_eq!(pid, p);
assert_eq!(status, 255);
Ok(())
}
_ => bail!("test failed"),
}
}
}