diff options
Diffstat (limited to 'crates/rebel-runner/src/tar.rs')
-rw-r--r-- | crates/rebel-runner/src/tar.rs | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/crates/rebel-runner/src/tar.rs b/crates/rebel-runner/src/tar.rs new file mode 100644 index 0000000..891c603 --- /dev/null +++ b/crates/rebel-runner/src/tar.rs @@ -0,0 +1,105 @@ +use std::{ + io::{self, Read, Write}, + os::unix::prelude::CommandExt, + path::Path, + process::{self, Command, Stdio}, +}; + +use nix::{ + mount::{self, MsFlags}, + sched::CloneFlags, + sys::wait, +}; + +use rebel_common::{error::*, string_hash::ArchiveHash}; + +use super::{ + ns, + util::{checkable::Checkable, fs}, +}; +use crate::paths; + +pub fn pack<W: Write, P: AsRef<Path>>( + rootfs_hash: &ArchiveHash, + archive: &mut W, + source: P, +) -> Result<()> { + let rootfs = paths::depend_dir(rootfs_hash); + let _rootfs_mount = fs::mount(&rootfs, &rootfs, None, MsFlags::MS_BIND, None) + .with_context(|| format!("Failed to bind mount rootfs to {:?}", rootfs))?; + mount::mount::<str, str, str, str>( + None, + &rootfs, + None, + MsFlags::MS_REMOUNT | MsFlags::MS_BIND | MsFlags::MS_RDONLY, + None, + ) + .context("Failed to mount container rootfs read-only")?; + + let (mut piper, pipew) = fs::pipe()?; + + let exec_tar = || -> Result<()> { + // We are in our own mount namespace, so mounting into the shared rootfs is fine + let dev_target = paths::join(&[&rootfs, "dev"]); + mount::mount::<_, _, str, str>( + Some(paths::DEV_DIR), + dev_target.as_str(), + None, + MsFlags::MS_BIND | MsFlags::MS_REC, + None, + )?; + let mount_target = paths::join(&[&rootfs, paths::TASK_BUILDDIR]); + mount::mount::<_, _, str, str>( + Some(source.as_ref()), + mount_target.as_str(), + None, + MsFlags::MS_BIND, + None, + )?; + + ns::pivot_root(&rootfs); + + let err = Command::new("tar") + .args([ + "-c", + "--sort=name", + "--numeric-owner", + "--owner=0", + "--group=0", + "--mtime=@0", + ".", + ]) + .stdin(Stdio::null()) + .stdout(pipew) + .current_dir(paths::TASK_BUILDDIR) + .env_clear() + .env("PATH", "/usr/sbin:/usr/bin:/sbin:/bin") + .exec(); + eprintln!("{}", err); + process::exit(127); + }; + + let pid = unsafe { ns::spawn(CloneFlags::CLONE_NEWNS, || exec_tar().unwrap()) } + .context("Failed to run tar")?; + + let result = io::copy(&mut piper, archive).context("Failed to write TAR archive"); + + wait::waitpid(pid, None)? + .check() + .context("tar did not exit successfully")?; + + result?; + Ok(()) +} + +pub fn unpack<R: Read, P: AsRef<Path>>(archive: R, dest: P) -> Result<()> { + fs::mkdir(&dest)?; + + let mut ar = tar::Archive::new(archive); + ar.set_preserve_permissions(true); + ar.set_preserve_mtime(true); + ar.set_unpack_xattrs(true); + ar.set_overwrite(false); + + ar.unpack(dest).context("Failed to unpack TAR archive") +} |