9
9
// except according to those terms.
10
10
11
11
use env:: { split_paths} ;
12
- use ffi:: OsStr ;
13
- use os:: unix:: ffi:: OsStrExt ;
12
+ use ffi:: { CStr , OsStr } ;
14
13
use fmt;
15
- use io :: { self , Error , ErrorKind } ;
16
- use iter ;
14
+ use fs :: File ;
15
+ use io :: { self , prelude :: * , BufReader , Error , ErrorKind , SeekFrom } ;
17
16
use libc:: { EXIT_SUCCESS , EXIT_FAILURE } ;
17
+ use os:: unix:: ffi:: OsStrExt ;
18
18
use path:: { Path , PathBuf } ;
19
+ use ptr;
20
+ use sys:: ext:: fs:: MetadataExt ;
21
+ use sys:: ext:: io:: AsRawFd ;
19
22
use sys:: fd:: FileDesc ;
20
- use sys:: fs:: { File , OpenOptions } ;
23
+ use sys:: fs:: { File as SysFile , OpenOptions } ;
24
+ use sys:: os:: { ENV_LOCK , environ} ;
21
25
use sys:: pipe:: { self , AnonPipe } ;
22
26
use sys:: { cvt, syscall} ;
23
27
use sys_common:: process:: { CommandEnv , DefaultEnvKey } ;
@@ -297,12 +301,6 @@ impl Command {
297
301
t ! ( callback( ) ) ;
298
302
}
299
303
300
- let args: Vec < [ usize ; 2 ] > = iter:: once (
301
- [ self . program . as_ptr ( ) as usize , self . program . len ( ) ]
302
- ) . chain (
303
- self . args . iter ( ) . map ( |arg| [ arg. as_ptr ( ) as usize , arg. len ( ) ] )
304
- ) . collect ( ) ;
305
-
306
304
self . env . apply ( ) ;
307
305
308
306
let program = if self . program . contains ( ':' ) || self . program . contains ( '/' ) {
@@ -321,14 +319,93 @@ impl Command {
321
319
None
322
320
} ;
323
321
324
- if let Some ( program) = program {
325
- if let Err ( err) = syscall:: execve ( program. as_os_str ( ) . as_bytes ( ) , & args) {
326
- io:: Error :: from_raw_os_error ( err. errno as i32 )
322
+ let mut file = if let Some ( program) = program {
323
+ t ! ( File :: open( program. as_os_str( ) ) )
324
+ } else {
325
+ return io:: Error :: from_raw_os_error ( syscall:: ENOENT ) ;
326
+ } ;
327
+
328
+ // Push all the arguments
329
+ let mut args: Vec < [ usize ; 2 ] > = Vec :: with_capacity ( 1 + self . args . len ( ) ) ;
330
+
331
+ let interpreter = {
332
+ let mut reader = BufReader :: new ( & file) ;
333
+
334
+ let mut shebang = [ 0 ; 2 ] ;
335
+ let mut read = 0 ;
336
+ loop {
337
+ match t ! ( reader. read( & mut shebang[ read..] ) ) {
338
+ 0 => break ,
339
+ n => read += n,
340
+ }
341
+ }
342
+
343
+ if & shebang == b"#!" {
344
+ // This is an interpreted script.
345
+ // First of all, since we'll be passing another file to
346
+ // fexec(), we need to manually check that we have permission
347
+ // to execute this file:
348
+ let uid = t ! ( cvt( syscall:: getuid( ) ) ) ;
349
+ let gid = t ! ( cvt( syscall:: getgid( ) ) ) ;
350
+ let meta = t ! ( file. metadata( ) ) ;
351
+
352
+ let mode = if uid == meta. uid ( ) as usize {
353
+ meta. mode ( ) >> 3 * 2 & 0o7
354
+ } else if gid == meta. gid ( ) as usize {
355
+ meta. mode ( ) >> 3 * 1 & 0o7
356
+ } else {
357
+ meta. mode ( ) & 0o7
358
+ } ;
359
+ if mode & 1 == 0 {
360
+ return io:: Error :: from_raw_os_error ( syscall:: EPERM ) ;
361
+ }
362
+
363
+ // Second of all, we need to actually read which interpreter it wants
364
+ let mut interpreter = Vec :: new ( ) ;
365
+ t ! ( reader. read_until( b'\n' , & mut interpreter) ) ;
366
+ // Pop one trailing newline, if any
367
+ if interpreter. ends_with ( & [ b'\n' ] ) {
368
+ interpreter. pop ( ) . unwrap ( ) ;
369
+ }
370
+
371
+ // FIXME: Here we could just reassign `file` directly, if it
372
+ // wasn't for lexical lifetimes. Remove the whole `let
373
+ // interpreter = { ... };` hack once NLL lands.
374
+ // NOTE: Although DO REMEMBER to make sure the interpreter path
375
+ // still lives long enough to reach fexec.
376
+ Some ( interpreter)
327
377
} else {
328
- panic ! ( "return from exec without err" ) ;
378
+ None
379
+ }
380
+ } ;
381
+ if let Some ( ref interpreter) = interpreter {
382
+ let path: & OsStr = OsStr :: from_bytes ( & interpreter) ;
383
+ file = t ! ( File :: open( path) ) ;
384
+
385
+ args. push ( [ interpreter. as_ptr ( ) as usize , interpreter. len ( ) ] ) ;
386
+ } else {
387
+ t ! ( file. seek( SeekFrom :: Start ( 0 ) ) ) ;
388
+ }
389
+
390
+ args. push ( [ self . program . as_ptr ( ) as usize , self . program . len ( ) ] ) ;
391
+ args. extend ( self . args . iter ( ) . map ( |arg| [ arg. as_ptr ( ) as usize , arg. len ( ) ] ) ) ;
392
+
393
+ // Push all the variables
394
+ let mut vars: Vec < [ usize ; 2 ] > = Vec :: new ( ) ;
395
+ {
396
+ let _guard = ENV_LOCK . lock ( ) ;
397
+ let mut environ = * environ ( ) ;
398
+ while * environ != ptr:: null ( ) {
399
+ let var = CStr :: from_ptr ( * environ) . to_bytes ( ) ;
400
+ vars. push ( [ var. as_ptr ( ) as usize , var. len ( ) ] ) ;
401
+ environ = environ. offset ( 1 ) ;
329
402
}
403
+ }
404
+
405
+ if let Err ( err) = syscall:: fexec ( file. as_raw_fd ( ) , & args, & vars) {
406
+ io:: Error :: from_raw_os_error ( err. errno as i32 )
330
407
} else {
331
- io :: Error :: from_raw_os_error ( syscall :: ENOENT )
408
+ panic ! ( "return from exec without err" ) ;
332
409
}
333
410
}
334
411
@@ -392,7 +469,7 @@ impl Stdio {
392
469
let mut opts = OpenOptions :: new ( ) ;
393
470
opts. read ( readable) ;
394
471
opts. write ( !readable) ;
395
- let fd = File :: open ( Path :: new ( "null:" ) , & opts) ?;
472
+ let fd = SysFile :: open ( Path :: new ( "null:" ) , & opts) ?;
396
473
Ok ( ( ChildStdio :: Owned ( fd. into_fd ( ) ) , None ) )
397
474
}
398
475
}
@@ -405,8 +482,8 @@ impl From<AnonPipe> for Stdio {
405
482
}
406
483
}
407
484
408
- impl From < File > for Stdio {
409
- fn from ( file : File ) -> Stdio {
485
+ impl From < SysFile > for Stdio {
486
+ fn from ( file : SysFile ) -> Stdio {
410
487
Stdio :: Fd ( file. into_fd ( ) )
411
488
}
412
489
}
0 commit comments