1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
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 common::error::*;
use super::{
ns,
util::{checkable::Checkable, fs},
};
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 = || -> Result<()> {
// We are in our own mount namespace, so mounting into the shared ROOTFS_DIR is fine
let dev_target = paths::join(&[paths::ROOTFS_DIR, "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(&[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(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")
}
|