summaryrefslogtreecommitdiffstats
path: root/crates/runner/src/tar.rs
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2021-10-25 00:19:45 +0200
committerMatthias Schiffer <mschiffer@universe-factory.net>2021-10-25 00:19:45 +0200
commit34ac18d20c13a78914d447fee83204811a27b1e4 (patch)
tree56763d4ea46927105fcc6a71e03d5bd75a6947a6 /crates/runner/src/tar.rs
parenta1a185370da27f2cc3df84d3a8d7141f9ce7db16 (diff)
downloadrebel-34ac18d20c13a78914d447fee83204811a27b1e4.tar
rebel-34ac18d20c13a78914d447fee83204811a27b1e4.zip
Move runner into separate crate
Diffstat (limited to 'crates/runner/src/tar.rs')
-rw-r--r--crates/runner/src/tar.rs87
1 files changed, 87 insertions, 0 deletions
diff --git a/crates/runner/src/tar.rs b/crates/runner/src/tar.rs
new file mode 100644
index 0000000..9306775
--- /dev/null
+++ b/crates/runner/src/tar.rs
@@ -0,0 +1,87 @@
+use std::{
+ fs::File,
+ io::{self, Read, Write},
+ os::unix::prelude::CommandExt,
+ path::Path,
+ process::{self, Command, Stdio},
+};
+
+use nix::{
+ mount::{self, MsFlags},
+ sched::CloneFlags,
+ sys::wait,
+};
+
+use common::error::*;
+
+use super::{
+ ns,
+ util::{fs, Checkable},
+};
+use crate::paths;
+
+pub fn pack<W: Write, P: AsRef<Path>>(archive: &mut W, source: P) -> Result<()> {
+ let (mut piper, pipew) = fs::pipe()?;
+
+ let exec_tar = |stdout: File| -> Result<()> {
+ // We are in our own mount namespace, so mounting into the shared ROOTFS_DIR is fine
+ let mount_target = paths::join(&[paths::ROOTFS_DIR, paths::TASK_BUILDDIR]);
+ mount::mount::<_, _, str, str>(
+ Some(source.as_ref()),
+ mount_target.as_str(),
+ None,
+ MsFlags::MS_BIND,
+ None,
+ )?;
+
+ ns::pivot_root(paths::ROOTFS_DIR);
+
+ let err = Command::new("tar")
+ .args(&[
+ "-c",
+ "--sort=name",
+ "--numeric-owner",
+ "--owner=0",
+ "--group=0",
+ "--mtime=@0",
+ ".",
+ ])
+ .stdin(Stdio::null())
+ .stdout(stdout)
+ .current_dir(paths::TASK_BUILDDIR)
+ .env_clear()
+ .env("PATH", "/usr/sbin:/usr/bin:/sbin:/bin")
+ .exec();
+ eprintln!("{}", err);
+ process::exit(127);
+ };
+
+ let (pid, pipew) = unsafe {
+ ns::spawn(CloneFlags::CLONE_NEWNS, pipew, |pipew| {
+ exec_tar(pipew).unwrap()
+ })
+ }
+ .context("Failed to run tar")?;
+
+ drop(pipew);
+ 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")
+}