about summary refs log tree commit diff
path: root/src/libstd/sys/redox/process.rs
diff options
context:
space:
mode:
authorPietro Albini <pietro@pietroalbini.org>2018-11-15 11:04:27 +0100
committerGitHub <noreply@github.com>2018-11-15 11:04:27 +0100
commitf4ecc1f521e83c30d0c6beb3ccb9307cfa12ae9c (patch)
tree098f9ce2fb23b287f7cff290c9432b4a664fcd56 /src/libstd/sys/redox/process.rs
parent4ec0ba9545f7c848aafc0bc1b8762507395edd41 (diff)
parent51e2a63fafba5ab38f8ebfea803daaef2ec87d02 (diff)
downloadrust-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.rs115
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())
     }
 }