Skip to content

Commit 9d42b1b

Browse files
committed
Interpret shebangs on redox
This is no longer handled on the kernel side
1 parent 8c277d8 commit 9d42b1b

File tree

1 file changed

+80
-14
lines changed

1 file changed

+80
-14
lines changed

src/libstd/sys/redox/process.rs

Lines changed: 80 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,22 @@
1010

1111
use env::{split_paths};
1212
use ffi::{CStr, OsStr};
13+
use fs::File;
1314
use os::unix::ffi::OsStrExt;
1415
use fmt;
16+
<<<<<<< HEAD
1517
use io::{self, Error, ErrorKind};
1618
use iter;
19+
=======
20+
use io::{self, prelude::*, BufReader, Error, ErrorKind, SeekFrom};
21+
>>>>>>> b7b1d416a1... Interpret shebangs on redox
1722
use libc::{EXIT_SUCCESS, EXIT_FAILURE};
1823
use path::{Path, PathBuf};
1924
use ptr;
25+
use sys::ext::fs::MetadataExt;
26+
use sys::ext::io::AsRawFd;
2027
use sys::fd::FileDesc;
21-
use sys::fs::{File, OpenOptions};
28+
use sys::fs::{File as SysFile, OpenOptions};
2229
use sys::os::{ENV_LOCK, environ};
2330
use sys::pipe::{self, AnonPipe};
2431
use sys::{cvt, syscall};
@@ -317,20 +324,80 @@ impl Command {
317324
None
318325
};
319326

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()))
322329
} else {
323330
return io::Error::from_raw_os_error(syscall::ENOENT);
324331
};
325332

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());
331335

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
332399
let mut vars: Vec<[usize; 2]> = Vec::new();
333-
unsafe {
400+
{
334401
let _guard = ENV_LOCK.lock();
335402
let mut environ = *environ();
336403
while *environ != ptr::null() {
@@ -340,8 +407,7 @@ impl Command {
340407
}
341408
}
342409

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) {
345411
io::Error::from_raw_os_error(err.errno as i32)
346412
} else {
347413
panic!("return from exec without err");
@@ -408,7 +474,7 @@ impl Stdio {
408474
let mut opts = OpenOptions::new();
409475
opts.read(readable);
410476
opts.write(!readable);
411-
let fd = File::open(Path::new("null:"), &opts)?;
477+
let fd = SysFile::open(Path::new("null:"), &opts)?;
412478
Ok((ChildStdio::Owned(fd.into_fd()), None))
413479
}
414480
}
@@ -421,8 +487,8 @@ impl From<AnonPipe> for Stdio {
421487
}
422488
}
423489

424-
impl From<File> for Stdio {
425-
fn from(file: File) -> Stdio {
490+
impl From<SysFile> for Stdio {
491+
fn from(file: SysFile) -> Stdio {
426492
Stdio::Fd(file.into_fd())
427493
}
428494
}

0 commit comments

Comments
 (0)