diff options
| author | Pietro Albini <pietro@pietroalbini.org> | 2018-11-15 11:04:27 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-11-15 11:04:27 +0100 |
| commit | f4ecc1f521e83c30d0c6beb3ccb9307cfa12ae9c (patch) | |
| tree | 098f9ce2fb23b287f7cff290c9432b4a664fcd56 /src/libstd/sys/redox/process.rs | |
| parent | 4ec0ba9545f7c848aafc0bc1b8762507395edd41 (diff) | |
| parent | 51e2a63fafba5ab38f8ebfea803daaef2ec87d02 (diff) | |
| download | rust-f4ecc1f521e83c30d0c6beb3ccb9307cfa12ae9c.tar.gz rust-f4ecc1f521e83c30d0c6beb3ccb9307cfa12ae9c.zip | |
Rollup merge of #55182 - jD91mZM2:rebased, r=alexcrichton
Redox: Update to new changes These are all cherry-picked from our fork: - Remove the `env:` scheme - Update `execve` system call to `fexec` - Interpret shebangs: these are no longer handled by the kernel, which like usual tries to be as minimal as possible
Diffstat (limited to 'src/libstd/sys/redox/process.rs')
| -rw-r--r-- | src/libstd/sys/redox/process.rs | 115 |
1 files changed, 96 insertions, 19 deletions
diff --git a/src/libstd/sys/redox/process.rs b/src/libstd/sys/redox/process.rs index 2037616e6ac..4370c1e0502 100644 --- a/src/libstd/sys/redox/process.rs +++ b/src/libstd/sys/redox/process.rs @@ -9,15 +9,19 @@ // except according to those terms. use env::{split_paths}; -use ffi::OsStr; -use os::unix::ffi::OsStrExt; +use ffi::{CStr, OsStr}; use fmt; -use io::{self, Error, ErrorKind}; -use iter; +use fs::File; +use io::{self, prelude::*, BufReader, Error, ErrorKind, SeekFrom}; use libc::{EXIT_SUCCESS, EXIT_FAILURE}; +use os::unix::ffi::OsStrExt; use path::{Path, PathBuf}; +use ptr; +use sys::ext::fs::MetadataExt; +use sys::ext::io::AsRawFd; use sys::fd::FileDesc; -use sys::fs::{File, OpenOptions}; +use sys::fs::{File as SysFile, OpenOptions}; +use sys::os::{ENV_LOCK, environ}; use sys::pipe::{self, AnonPipe}; use sys::{cvt, syscall}; use sys_common::process::{CommandEnv, DefaultEnvKey}; @@ -297,12 +301,6 @@ impl Command { t!(callback()); } - let args: Vec<[usize; 2]> = iter::once( - [self.program.as_ptr() as usize, self.program.len()] - ).chain( - self.args.iter().map(|arg| [arg.as_ptr() as usize, arg.len()]) - ).collect(); - self.env.apply(); let program = if self.program.contains(':') || self.program.contains('/') { @@ -321,14 +319,93 @@ impl Command { None }; - if let Some(program) = program { - if let Err(err) = syscall::execve(program.as_os_str().as_bytes(), &args) { - io::Error::from_raw_os_error(err.errno as i32) + let mut file = if let Some(program) = program { + t!(File::open(program.as_os_str())) + } else { + return io::Error::from_raw_os_error(syscall::ENOENT); + }; + + // Push all the arguments + let mut args: Vec<[usize; 2]> = Vec::with_capacity(1 + self.args.len()); + + let interpreter = { + let mut reader = BufReader::new(&file); + + let mut shebang = [0; 2]; + let mut read = 0; + loop { + match t!(reader.read(&mut shebang[read..])) { + 0 => break, + n => read += n, + } + } + + if &shebang == b"#!" { + // This is an interpreted script. + // First of all, since we'll be passing another file to + // fexec(), we need to manually check that we have permission + // to execute this file: + let uid = t!(cvt(syscall::getuid())); + let gid = t!(cvt(syscall::getgid())); + let meta = t!(file.metadata()); + + let mode = if uid == meta.uid() as usize { + meta.mode() >> 3*2 & 0o7 + } else if gid == meta.gid() as usize { + meta.mode() >> 3*1 & 0o7 + } else { + meta.mode() & 0o7 + }; + if mode & 1 == 0 { + return io::Error::from_raw_os_error(syscall::EPERM); + } + + // Second of all, we need to actually read which interpreter it wants + let mut interpreter = Vec::new(); + t!(reader.read_until(b'\n', &mut interpreter)); + // Pop one trailing newline, if any + if interpreter.ends_with(&[b'\n']) { + interpreter.pop().unwrap(); + } + + // FIXME: Here we could just reassign `file` directly, if it + // wasn't for lexical lifetimes. Remove the whole `let + // interpreter = { ... };` hack once NLL lands. + // NOTE: Although DO REMEMBER to make sure the interpreter path + // still lives long enough to reach fexec. + Some(interpreter) } else { - panic!("return from exec without err"); + None + } + }; + if let Some(ref interpreter) = interpreter { + let path: &OsStr = OsStr::from_bytes(&interpreter); + file = t!(File::open(path)); + + args.push([interpreter.as_ptr() as usize, interpreter.len()]); + } else { + t!(file.seek(SeekFrom::Start(0))); + } + + args.push([self.program.as_ptr() as usize, self.program.len()]); + args.extend(self.args.iter().map(|arg| [arg.as_ptr() as usize, arg.len()])); + + // Push all the variables + let mut vars: Vec<[usize; 2]> = Vec::new(); + { + let _guard = ENV_LOCK.lock(); + let mut environ = *environ(); + while *environ != ptr::null() { + let var = CStr::from_ptr(*environ).to_bytes(); + vars.push([var.as_ptr() as usize, var.len()]); + environ = environ.offset(1); } + } + + if let Err(err) = syscall::fexec(file.as_raw_fd(), &args, &vars) { + io::Error::from_raw_os_error(err.errno as i32) } else { - io::Error::from_raw_os_error(syscall::ENOENT) + panic!("return from exec without err"); } } @@ -392,7 +469,7 @@ impl Stdio { let mut opts = OpenOptions::new(); opts.read(readable); opts.write(!readable); - let fd = File::open(Path::new("null:"), &opts)?; + let fd = SysFile::open(Path::new("null:"), &opts)?; Ok((ChildStdio::Owned(fd.into_fd()), None)) } } @@ -405,8 +482,8 @@ impl From<AnonPipe> for Stdio { } } -impl From<File> for Stdio { - fn from(file: File) -> Stdio { +impl From<SysFile> for Stdio { + fn from(file: SysFile) -> Stdio { Stdio::Fd(file.into_fd()) } } |
