@@ -8,6 +8,7 @@ use std::env;
8
8
use std:: fs;
9
9
use std:: io;
10
10
use std:: io:: prelude:: * ;
11
+ use std:: os:: unix:: fs:: symlink;
11
12
use std:: os:: unix:: process:: CommandExt ;
12
13
use std:: path:: Path ;
13
14
use std:: path:: PathBuf ;
@@ -17,20 +18,24 @@ use tempdir::TempDir;
17
18
18
19
const NONE : Option < & ' static [ u8 ] > = None ;
19
20
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
+ ) ;
32
35
}
36
+ }
33
37
38
+ fn bind_mount_directory ( entry : & fs:: DirEntry ) {
34
39
let mountpoint = PathBuf :: from ( "/" ) . join ( entry. file_name ( ) ) ;
35
40
if let Err ( e) = fs:: create_dir ( & mountpoint) {
36
41
if e. kind ( ) != io:: ErrorKind :: AlreadyExists {
@@ -39,19 +44,47 @@ fn bind_mount_direntry(entry: io::Result<fs::DirEntry>) {
39
44
}
40
45
}
41
46
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) ;
55
88
}
56
89
}
57
90
@@ -81,8 +114,7 @@ fn run_chroot(nixdir: &Path, rootdir: &Path, cmd: &str, args: &[String]) {
81
114
Some ( "none" ) ,
82
115
MsFlags :: MS_PRIVATE | MsFlags :: MS_REC ,
83
116
NONE ,
84
- )
85
- . expect ( "failed to re-mount our chroot as private mount" ) ;
117
+ ) . expect ( "failed to re-mount our chroot as private mount" ) ;
86
118
87
119
// create the mount point for the old root
88
120
// The old root cannot be unmounted/removed after pivot_root, the only way to
0 commit comments