Skip to content

Commit 75dd87f

Browse files
authored
Merge pull request #8 from nix-community/symlinks
also bind mount files and symlinks
2 parents 186348f + b3e6fb1 commit 75dd87f

File tree

1 file changed

+59
-27
lines changed

1 file changed

+59
-27
lines changed

src/main.rs

Lines changed: 59 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use std::env;
88
use std::fs;
99
use std::io;
1010
use std::io::prelude::*;
11+
use std::os::unix::fs::symlink;
1112
use std::os::unix::process::CommandExt;
1213
use std::path::Path;
1314
use std::path::PathBuf;
@@ -17,20 +18,24 @@ use tempdir::TempDir;
1718

1819
const NONE: Option<&'static [u8]> = None;
1920

20-
fn bind_mount_direntry(entry: io::Result<fs::DirEntry>) {
21-
let entry = entry.expect("error while listing from /nix directory");
22-
// do not bind mount an existing nix installation
23-
if entry.file_name() == PathBuf::from("nix") {
24-
return;
25-
}
26-
let path = entry.path();
27-
let stat = entry
28-
.metadata()
29-
.unwrap_or_else(|_| panic!("cannot get stat of {}", path.display()));
30-
if !stat.is_dir() {
31-
return;
21+
fn bind_mount(source: &Path, dest: &Path) {
22+
if let Err(e) = mount(
23+
Some(source),
24+
dest,
25+
Some("none"),
26+
MsFlags::MS_BIND | MsFlags::MS_REC,
27+
NONE,
28+
) {
29+
eprintln!(
30+
"failed to bind mount {} to {}: {}",
31+
source.display(),
32+
dest.display(),
33+
e
34+
);
3235
}
36+
}
3337

38+
fn bind_mount_directory(entry: &fs::DirEntry) {
3439
let mountpoint = PathBuf::from("/").join(entry.file_name());
3540
if let Err(e) = fs::create_dir(&mountpoint) {
3641
if e.kind() != io::ErrorKind::AlreadyExists {
@@ -39,19 +44,47 @@ fn bind_mount_direntry(entry: io::Result<fs::DirEntry>) {
3944
}
4045
}
4146

42-
if let Err(e) = mount(
43-
Some(&path),
44-
&mountpoint,
45-
Some("none"),
46-
MsFlags::MS_BIND | MsFlags::MS_REC,
47-
NONE,
48-
) {
49-
eprintln!(
50-
"failed to bind mount {} to {}: {}",
51-
path.display(),
52-
mountpoint.display(),
53-
e
54-
);
47+
bind_mount(&entry.path(), &mountpoint)
48+
}
49+
50+
fn bind_mount_file(entry: &fs::DirEntry) {
51+
let mountpoint = PathBuf::from("/").join(entry.file_name());
52+
fs::File::create(&mountpoint)
53+
.unwrap_or_else(|_| panic!("failed to create {}", &mountpoint.display()));
54+
55+
bind_mount(&entry.path(), &mountpoint)
56+
}
57+
58+
fn mirror_symlink(entry: &fs::DirEntry) {
59+
let path = entry.path();
60+
let target = fs::read_link(&path)
61+
.unwrap_or_else(|_| panic!("failed to resolve symlink {}", &path.display()));
62+
let link_path = PathBuf::from("/").join(entry.file_name());
63+
symlink(&target, &link_path).unwrap_or_else(|_| {
64+
panic!(
65+
"failed to create symlink {} -> {}",
66+
&link_path.display(),
67+
&target.display()
68+
)
69+
});
70+
}
71+
72+
fn bind_mount_direntry(entry: io::Result<fs::DirEntry>) {
73+
let entry = entry.expect("error while listing from /nix directory");
74+
// do not bind mount an existing nix installation
75+
if entry.file_name() == PathBuf::from("nix") {
76+
return;
77+
}
78+
let path = entry.path();
79+
let stat = entry
80+
.metadata()
81+
.unwrap_or_else(|_| panic!("cannot get stat of {}", path.display()));
82+
if stat.is_dir() {
83+
bind_mount_directory(&entry);
84+
} else if stat.is_file() {
85+
bind_mount_file(&entry);
86+
} else if stat.file_type().is_symlink() {
87+
mirror_symlink(&entry);
5588
}
5689
}
5790

@@ -81,8 +114,7 @@ fn run_chroot(nixdir: &Path, rootdir: &Path, cmd: &str, args: &[String]) {
81114
Some("none"),
82115
MsFlags::MS_PRIVATE | MsFlags::MS_REC,
83116
NONE,
84-
)
85-
.expect("failed to re-mount our chroot as private mount");
117+
).expect("failed to re-mount our chroot as private mount");
86118

87119
// create the mount point for the old root
88120
// The old root cannot be unmounted/removed after pivot_root, the only way to

0 commit comments

Comments
 (0)