hakoniwa 1.4.0

Process isolation for Linux using namespaces, resource limits, cgroups, landlock and seccomp.
Documentation
mod idmap;

use nix::unistd::Pid;
use std::process::Command;

use crate::{Container, error::*};

pub(crate) use idmap::IdMap;

pub(crate) fn mainp_setup(container: &Container, child: Pid) -> Result<()> {
    let program = "newuidmap";
    let uidmaps = container.uidmaps.clone().unwrap_or_default();
    mainp_setup_newidmap(program, &uidmaps, child)?;

    let program = "newgidmap";
    let gidmaps = container.gidmaps.clone().unwrap_or_default();
    mainp_setup_newidmap(program, &gidmaps, child)?;

    log::debug!("================================");
    Ok(())
}

fn mainp_setup_newidmap(program: &str, idmaps: &[IdMap], child: Pid) -> Result<()> {
    if idmaps.is_empty() {
        return Ok(());
    }

    let cmdline = newidmap_cmdline(program, idmaps, child);
    log::debug!("Configuring UID/GID mapping: Execve: {cmdline:?}");

    let output = Command::new(cmdline[0].clone())
        .args(&cmdline[1..])
        .output();
    match output {
        Ok(output) if output.status.success() => {
            let output = String::from_utf8_lossy(&output.stdout).trim().to_string();
            log::debug!("Configuring UID/GID mapping: Output: {output}");
            Ok(())
        }
        Ok(output) => {
            let errmsg = String::from_utf8_lossy(&output.stderr).trim().to_string();
            Err(ProcessErrorKind::SetupUGidmapFailed(errmsg))?
        }
        Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
            let errmsg = format!("command {program:?} not found");
            Err(ProcessErrorKind::SetupUGidmapFailed(errmsg))?
        }
        Err(err) => {
            let errmsg = format!("{err}");
            Err(ProcessErrorKind::SetupUGidmapFailed(errmsg))?
        }
    }
}

fn newidmap_cmdline(program: &str, idmaps: &[IdMap], child: Pid) -> Vec<String> {
    let mut idmaps = idmaps
        .iter()
        .flat_map(|idmap| {
            [
                idmap.container_id.to_string(),
                idmap.host_id.to_string(),
                idmap.size.to_string(),
            ]
        })
        .collect();

    let mut cmdline = vec![program.to_string(), child.to_string()];
    cmdline.append(&mut idmaps);
    cmdline
}