1
+ use nix;
1
2
use nix:: mount:: { mount, MsFlags } ;
2
3
use nix:: sched:: { unshare, CloneFlags } ;
3
4
use nix:: sys:: signal:: { kill, Signal } ;
4
5
use nix:: sys:: wait:: { waitpid, WaitPidFlag , WaitStatus } ;
5
- use nix:: unistd;
6
- use nix:: unistd:: { fork, ForkResult } ;
6
+ use nix:: unistd:: { self , fork, ForkResult } ;
7
7
use std:: env;
8
8
use std:: fs;
9
9
use std:: io;
10
10
use std:: io:: prelude:: * ;
11
11
use std:: os:: unix:: fs:: symlink;
12
12
use std:: os:: unix:: process:: CommandExt ;
13
- use std:: path:: Path ;
14
- use std:: path:: PathBuf ;
13
+ use std:: path:: { Path , PathBuf } ;
15
14
use std:: process;
16
15
use std:: string:: String ;
17
- use tempfile:: TempDir ;
16
+
17
+ mod mkdtemp;
18
18
19
19
const NONE : Option < & ' static [ u8 ] > = None ;
20
20
@@ -48,8 +48,7 @@ impl<'a> RunChroot<'a> {
48
48
let mountpoint = self . rootdir . join ( entry. file_name ( ) ) ;
49
49
if let Err ( e) = fs:: create_dir ( & mountpoint) {
50
50
if e. kind ( ) != io:: ErrorKind :: AlreadyExists {
51
- let e2: io:: Result < ( ) > = Err ( e) ;
52
- e2. unwrap_or_else ( |_| panic ! ( "failed to create {}" , & mountpoint. display( ) ) ) ;
51
+ panic ! ( "failed to create {}: {}" , & mountpoint. display( ) , e) ;
53
52
}
54
53
}
55
54
@@ -59,15 +58,15 @@ impl<'a> RunChroot<'a> {
59
58
fn bind_mount_file ( & self , entry : & fs:: DirEntry ) {
60
59
let mountpoint = self . rootdir . join ( entry. file_name ( ) ) ;
61
60
fs:: File :: create ( & mountpoint)
62
- . unwrap_or_else ( |_ | panic ! ( "failed to create {}" , & mountpoint. display( ) ) ) ;
61
+ . unwrap_or_else ( |err | panic ! ( "failed to create {}: {} " , & mountpoint. display( ) , err ) ) ;
63
62
64
63
bind_mount ( & entry. path ( ) , & mountpoint)
65
64
}
66
65
67
66
fn mirror_symlink ( & self , entry : & fs:: DirEntry ) {
68
67
let path = entry. path ( ) ;
69
68
let target = fs:: read_link ( & path)
70
- . unwrap_or_else ( |_ | panic ! ( "failed to resolve symlink {}" , & path. display( ) ) ) ;
69
+ . unwrap_or_else ( |err | panic ! ( "failed to resolve symlink {}: {} " , & path. display( ) , err ) ) ;
71
70
let link_path = self . rootdir . join ( entry. file_name ( ) ) ;
72
71
symlink ( & target, & link_path) . unwrap_or_else ( |_| {
73
72
panic ! (
@@ -87,7 +86,7 @@ impl<'a> RunChroot<'a> {
87
86
let path = entry. path ( ) ;
88
87
let stat = entry
89
88
. metadata ( )
90
- . unwrap_or_else ( |_ | panic ! ( "cannot get stat of {}" , path. display( ) ) ) ;
89
+ . unwrap_or_else ( |err | panic ! ( "cannot get stat of {}: {} " , path. display( ) , err ) ) ;
91
90
if stat. is_dir ( ) {
92
91
self . bind_mount_directory ( & entry) ;
93
92
} else if stat. is_file ( ) {
@@ -115,19 +114,19 @@ impl<'a> RunChroot<'a> {
115
114
// mount the store
116
115
let nix_mount = self . rootdir . join ( "nix" ) ;
117
116
fs:: create_dir ( & nix_mount)
118
- . unwrap_or_else ( |_ | panic ! ( "failed to create {}" , & nix_mount. display( ) ) ) ;
117
+ . unwrap_or_else ( |err | panic ! ( "failed to create {}: {} " , & nix_mount. display( ) , err ) ) ;
119
118
mount (
120
119
Some ( nixdir) ,
121
120
& nix_mount,
122
121
Some ( "none" ) ,
123
122
MsFlags :: MS_BIND | MsFlags :: MS_REC ,
124
123
NONE ,
125
124
)
126
- . unwrap_or_else ( |_ | panic ! ( "failed to bind mount {} to /nix" , nixdir. display( ) ) ) ;
125
+ . unwrap_or_else ( |err | panic ! ( "failed to bind mount {} to /nix: {} " , nixdir. display( ) , err ) ) ;
127
126
128
127
// chroot
129
128
unistd:: chroot ( self . rootdir )
130
- . unwrap_or_else ( |_ | panic ! ( "chroot({})" , self . rootdir. display( ) , ) ) ;
129
+ . unwrap_or_else ( |err | panic ! ( "chroot({}): {} " , self . rootdir. display( ) , err ) ) ;
131
130
132
131
env:: set_current_dir ( "/" ) . expect ( "cannot change directory to /" ) ;
133
132
@@ -163,48 +162,38 @@ impl<'a> RunChroot<'a> {
163
162
}
164
163
}
165
164
166
- fn wait_for_child ( child_pid : unistd:: Pid , tempdir : TempDir , rootdir : & Path ) {
165
+ fn wait_for_child ( rootdir : & Path , child_pid : unistd:: Pid ) -> ! {
166
+ let mut exit_status = 1 ;
167
167
loop {
168
168
match waitpid ( child_pid, Some ( WaitPidFlag :: WUNTRACED ) ) {
169
169
Ok ( WaitStatus :: Signaled ( child, Signal :: SIGSTOP , _) ) => {
170
170
let _ = kill ( unistd:: getpid ( ) , Signal :: SIGSTOP ) ;
171
171
let _ = kill ( child, Signal :: SIGCONT ) ;
172
172
}
173
173
Ok ( WaitStatus :: Signaled ( _, signal, _) ) => {
174
- kill ( unistd:: getpid ( ) , signal)
175
- . unwrap_or_else ( |_| panic ! ( "failed to send {} signal to our self" , signal) ) ;
174
+ kill ( unistd:: getpid ( ) , signal) . unwrap_or_else ( |err| {
175
+ panic ! ( "failed to send {} signal to our self: {}" , signal, err)
176
+ } ) ;
176
177
}
177
178
Ok ( WaitStatus :: Exited ( _, status) ) => {
178
- tempdir. close ( ) . unwrap_or_else ( |_| {
179
- panic ! (
180
- "failed to remove temporary directory: {}" ,
181
- rootdir. display( )
182
- )
183
- } ) ;
184
- process:: exit ( status) ;
179
+ exit_status = status;
180
+ break ;
185
181
}
186
182
Ok ( what) => {
187
- tempdir. close ( ) . unwrap_or_else ( |_| {
188
- panic ! (
189
- "failed to remove temporary directory: {}" ,
190
- rootdir. display( )
191
- )
192
- } ) ;
193
183
eprintln ! ( "unexpected wait event happend: {:?}" , what) ;
194
- process :: exit ( 1 ) ;
184
+ break ;
195
185
}
196
186
Err ( e) => {
197
- tempdir. close ( ) . unwrap_or_else ( |_| {
198
- panic ! (
199
- "failed to remove temporary directory: {}" ,
200
- rootdir. display( )
201
- )
202
- } ) ;
203
187
eprintln ! ( "waitpid failed: {}" , e) ;
204
- process :: exit ( 1 ) ;
188
+ break ;
205
189
}
206
190
} ;
207
191
}
192
+
193
+ fs:: remove_dir_all ( rootdir)
194
+ . unwrap_or_else ( |err| panic ! ( "cannot remove tempdir {}: {}" , rootdir. display( ) , err) ) ;
195
+
196
+ process:: exit ( exit_status) ;
208
197
}
209
198
210
199
fn main ( ) {
@@ -213,14 +202,15 @@ fn main() {
213
202
eprintln ! ( "Usage: {} <nixpath> <command>\n " , args[ 0 ] ) ;
214
203
process:: exit ( 1 ) ;
215
204
}
216
- let tempdir = TempDir :: new ( ) . expect ( "failed to create temporary directory for mount point" ) ;
217
- let rootdir = PathBuf :: from ( tempdir. path ( ) ) ;
205
+
206
+ let rootdir = mkdtemp:: mkdtemp ( "nix-chroot.XXXXXX" )
207
+ . unwrap_or_else ( |err| panic ! ( "failed to create temporary directory: {}" , err) ) ;
218
208
219
209
let nixdir = fs:: canonicalize ( & args[ 1 ] )
220
- . unwrap_or_else ( |_ | panic ! ( "failed to resolve nix directory {}" , & args[ 1 ] ) ) ;
210
+ . unwrap_or_else ( |err | panic ! ( "failed to resolve nix directory {}: {} " , & args[ 1 ] , err ) ) ;
221
211
222
212
match unsafe { fork ( ) } {
223
- Ok ( ForkResult :: Parent { child, .. } ) => wait_for_child ( child , tempdir , & rootdir) ,
213
+ Ok ( ForkResult :: Parent { child, .. } ) => wait_for_child ( & rootdir, child ) ,
224
214
Ok ( ForkResult :: Child ) => RunChroot :: new ( & rootdir) . run_chroot ( & nixdir, & args[ 2 ] , & args[ 3 ..] ) ,
225
215
Err ( e) => {
226
216
eprintln ! ( "fork failed: {}" , e) ;
0 commit comments