use std::{ ffi::CString, fs::{DirBuilder, File}, io, os::unix::ffi::OsStrExt, path::Path, }; use nix::{ mount::{self, MsFlags}, sched::{self, CloneFlags}, }; use serde::{Deserialize, Serialize}; use crate::util::ToIOResult; fn prepare_buildtmp() -> io::Result<()> { mount::mount::<_, _, _, str>( Some("buildtmp"), "build/tmp", Some("tmpfs"), MsFlags::empty(), None, ) .to_io_result()?; DirBuilder::new().create("build/tmp/rootfs")?; { let file = File::open("build/rootfs.tar")?; let mut archive = tar::Archive::new(file); archive.set_preserve_permissions(true); archive.set_preserve_mtime(true); archive.set_unpack_xattrs(true); let dst = Path::new("build/tmp/rootfs"); for entry_r in archive.entries()? { let mut entry = entry_r?; if entry.unpack_in(dst)? { let header = entry.header(); let uid = header.uid()? as libc::uid_t; let gid = header.gid()? as libc::gid_t; let path = CString::new(dst.join(entry.path()?).as_os_str().as_bytes()) .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; if unsafe { libc::lchown(path.as_ptr(), uid, gid) } < 0 { return Err(io::Error::last_os_error()); } } } } DirBuilder::new().create("build/tmp/runc")?; DirBuilder::new().create("build/tmp/runc/rootfs")?; mount::mount::<_, _, str, str>( Some("build/tmp/rootfs"), "build/tmp/runc/rootfs", None, MsFlags::MS_BIND, None, ) .to_io_result()?; mount::mount::( None, "build/tmp/runc/rootfs", None, MsFlags::MS_BIND | MsFlags::MS_REMOUNT | MsFlags::MS_RDONLY, None, ) .to_io_result()?; Ok(()) } #[derive(Debug, Deserialize, Serialize)] pub enum Error { Code(i32), String(String), } impl From for Error { fn from(error: io::Error) -> Self { match error.raw_os_error() { Some(code) => Error::Code(code), None => Error::String(error.to_string()), } } } impl From for io::Error { fn from(error: Error) -> Self { match error { Error::Code(code) => io::Error::from_raw_os_error(code), Error::String(string) => io::Error::new(io::ErrorKind::Other, string), } } } pub fn runc_unshare() -> Result<(), Error> { sched::unshare(CloneFlags::CLONE_NEWUSER | CloneFlags::CLONE_NEWNS).to_io_result()?; Ok(()) } pub fn runc_initialize() -> Result<(), Error> { prepare_buildtmp()?; Ok(()) }