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