bandsocks 0.2.1

Experimental embeddable container sandbox
pub mod protocol {
    include! {"../sand/src/protocol.rs"}
}

#[cfg(not(doc))]
const PROGRAM_DATA: &[u8] = include_bytes!(concat!(
    env!("OUT_DIR"),
    "/sand/target/release/bandsocks-sand"
));

#[cfg(doc)]
const PROGRAM_DATA: &[u8] = b"";

use crate::errors::RuntimeError;
use protocol::{LogLevel, LogMessage, SysFd, VPid};
use std::{
    fs::File,
    io::Write,
    os::{
        raw::c_int,
        unix::{
            io::{AsRawFd, RawFd},
            process::CommandExt,
        },
    },
    process::{Command, Stdio},
};

lazy_static! {
    static ref PROGRAM_FILE: Result<File, RuntimeError> = create_program_file();
}

fn create_program_file() -> Result<File, RuntimeError> {
    let memfd = memfd::MemfdOptions::default()
        .allow_sealing(true)
        .create("bandsocks-sand")?;
    memfd.as_file().write_all(PROGRAM_DATA)?;
    memfd.add_seals(
        &[
            memfd::FileSeal::SealWrite,
            memfd::FileSeal::SealShrink,
            memfd::FileSeal::SealGrow,
            memfd::FileSeal::SealSeal,
        ]
        .iter()
        .cloned()
        .collect(),
    )?;
    Ok(memfd.into_file())
}

pub fn command(fd: RawFd) -> Result<Command, RuntimeError> {
    let file = match &*PROGRAM_FILE {
        Err(err) => return Err(RuntimeError::ProgramAllocError(err.to_string())),
        Ok(file) => file,
    };
    let mut cmd = Command::new(format!("/proc/self/fd/{}", file.as_raw_fd()));
    cmd.stdin(Stdio::null());
    cmd.stdout(Stdio::null());
    cmd.stderr(Stdio::piped());
    cmd.arg0("sand");
    cmd.env_clear();
    cmd.env("FD", fd.to_string());
    Ok(cmd)
}

impl AsRawFd for SysFd {
    fn as_raw_fd(&self) -> RawFd {
        self.0 as c_int
    }
}

pub fn max_log_level() -> LogLevel {
    if log::log_enabled!(log::Level::Trace) {
        LogLevel::Trace
    } else if log::log_enabled!(log::Level::Debug) {
        LogLevel::Debug
    } else if log::log_enabled!(log::Level::Info) {
        LogLevel::Info
    } else if log::log_enabled!(log::Level::Warn) {
        LogLevel::Warn
    } else if log::log_enabled!(log::Level::Error) {
        LogLevel::Error
    } else {
        LogLevel::Off
    }
}

pub fn task_log(task: VPid, level: LogLevel, message: LogMessage) {
    let level = match level {
        LogLevel::Off => return,
        LogLevel::Error => log::Level::Error,
        LogLevel::Warn => log::Level::Warn,
        LogLevel::Info => log::Level::Info,
        LogLevel::Debug => log::Level::Debug,
        LogLevel::Trace => log::Level::Trace,
    };
    log::log!(level, "{:?} {:?}", task, message);
}