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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
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 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")
}
|