@@ -9,15 +9,19 @@
// except according to those terms.

use env::{split_paths};
use ffi::OsStr;
use ffi::{CStr, OsStr};
use fs::File;
use os::unix::ffi::OsStrExt;
use fmt;
use io::{self, Error, ErrorKind};
use iter;
use io::{self, prelude::*, BufReader, Error, ErrorKind, SeekFrom};
use libc::{EXIT_SUCCESS, EXIT_FAILURE};
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,15 +301,7 @@ 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('/') {
let program_opt = if self.program.contains(':') || self.program.contains('/') {
Some(PathBuf::from(&self.program))
} else if let Ok(path_env) = ::env::var("PATH") {
let mut program = None;
@@ -321,14 +317,98 @@ 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_opt {
t!(File::open(program.as_os_str()))
} else {
return io::Error::from_raw_os_error(syscall::ENOENT);
};

self.env.apply();

// 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();
}

// TODO: 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()]);

for arg in self.args.iter() {
args.push([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 +472,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 +485,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())
}
}
@@ -0,0 +1,77 @@
use super::error::{Error, Result};

pub unsafe fn syscall0(mut a: usize) -> Result<usize> {
asm!("svc 0"
: "={x0}"(a)
: "{x8}"(a)
: "x0", "x8"
: "volatile");

Error::demux(a)
}

pub unsafe fn syscall1(mut a: usize, b: usize) -> Result<usize> {
asm!("svc 0"
: "={x0}"(a)
: "{x8}"(a), "{x0}"(b)
: "x0", "x8"
: "volatile");

Error::demux(a)
}

// Clobbers all registers - special for clone
pub unsafe fn syscall1_clobber(mut a: usize, b: usize) -> Result<usize> {
asm!("svc 0"
: "={x0}"(a)
: "{x8}"(a), "{x0}"(b)
: "memory",
"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
"x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
"x16", "x17","x18", "x19", "x20", "x21", "x22", "x23",
"x24", "x25", "x26", "x27", "x28", "x29", "x30"
: "volatile");

Error::demux(a)
}

pub unsafe fn syscall2(mut a: usize, b: usize, c: usize) -> Result<usize> {
asm!("svc 0"
: "={x0}"(a)
: "{x8}"(a), "{x0}"(b), "{x1}"(c)
: "x0", "x1", "x8"
: "volatile");

Error::demux(a)
}

pub unsafe fn syscall3(mut a: usize, b: usize, c: usize, d: usize) -> Result<usize> {
asm!("svc 0"
: "={x0}"(a)
: "{x8}"(a), "{x0}"(b), "{x1}"(c), "{x2}"(d)
: "x0", "x1", "x2", "x8"
: "volatile");

Error::demux(a)
}

pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) -> Result<usize> {
asm!("svc 0"
: "={x0}"(a)
: "{x8}"(a), "{x0}"(b), "{x1}"(c), "{x2}"(d), "{x3}"(e)
: "x0", "x1", "x2", "x3", "x8"
: "volatile");

Error::demux(a)
}

pub unsafe fn syscall5(mut a: usize, b: usize, c: usize, d: usize, e: usize, f: usize)
-> Result<usize> {
asm!("svc 0"
: "={x0}"(a)
: "{x8}"(a), "{x0}"(b), "{x1}"(c), "{x2}"(d), "{x3}"(e), "{x4}"(f)
: "x0", "x1", "x2", "x3", "x4", "x8"
: "volatile");

Error::demux(a)
}
@@ -82,12 +82,6 @@ pub fn dup2(fd: usize, newfd: usize, buf: &[u8]) -> Result<usize> {
unsafe { syscall4(SYS_DUP2, fd, newfd, buf.as_ptr() as usize, buf.len()) }
}

/// Replace the current process with a new executable
pub fn execve<T: AsRef<[u8]>>(path: T, args: &[[usize; 2]]) -> Result<usize> {
unsafe { syscall4(SYS_EXECVE, path.as_ref().as_ptr() as usize,
path.as_ref().len(), args.as_ptr() as usize, args.len()) }
}

/// Exit the current process
pub fn exit(status: usize) -> Result<usize> {
unsafe { syscall1(SYS_EXIT, status) }
@@ -110,9 +104,10 @@ pub fn fcntl(fd: usize, cmd: usize, arg: usize) -> Result<usize> {
unsafe { syscall3(SYS_FCNTL, fd, cmd, arg) }
}

/// Register a file for event-based I/O
pub fn fevent(fd: usize, flags: usize) -> Result<usize> {
unsafe { syscall2(SYS_FEVENT, fd, flags) }
/// Replace the current process with a new executable
pub fn fexec(fd: usize, args: &[[usize; 2]], vars: &[[usize; 2]]) -> Result<usize> {
unsafe { syscall5(SYS_FEXEC, fd, args.as_ptr() as usize, args.len(),
vars.as_ptr() as usize, vars.len()) }
}

/// Map a file into memory
@@ -113,4 +113,46 @@ pub const SA_RESTART: usize = 0x10000000;
pub const SA_NODEFER: usize = 0x40000000;
pub const SA_RESETHAND: usize = 0x80000000;

pub const WNOHANG: usize = 1;
pub const WNOHANG: usize = 0x01;
pub const WUNTRACED: usize = 0x02;
pub const WCONTINUED: usize = 0x08;

/// True if status indicates the child is stopped.
pub fn wifstopped(status: usize) -> bool {
(status & 0xff) == 0x7f
}

/// If wifstopped(status), the signal that stopped the child.
pub fn wstopsig(status: usize) -> usize {
(status >> 8) & 0xff
}

/// True if status indicates the child continued after a stop.
pub fn wifcontinued(status: usize) -> bool {
status == 0xffff
}

/// True if STATUS indicates termination by a signal.
pub fn wifsignaled(status: usize) -> bool {
((status & 0x7f) + 1) as i8 >= 2
}

/// If wifsignaled(status), the terminating signal.
pub fn wtermsig(status: usize) -> usize {
status & 0x7f
}

/// True if status indicates normal termination.
pub fn wifexited(status: usize) -> bool {
wtermsig(status) == 0
}

/// If wifexited(status), the exit status.
pub fn wexitstatus(status: usize) -> usize {
(status >> 8) & 0xff
}

/// True if status indicates a core dump was created.
pub fn wcoredump(status: usize) -> bool {
(status & 0x80) != 0
}
@@ -19,6 +19,10 @@ pub use self::number::*;
#[path="arch/arm.rs"]
mod arch;

#[cfg(target_arch = "aarch64")]
#[path="arch/aarch64.rs"]
mod arch;

#[cfg(target_arch = "x86")]
#[path="arch/x86.rs"]
mod arch;
@@ -36,6 +36,7 @@ pub const SYS_FCHMOD: usize = SYS_CLASS_FILE | 94;
pub const SYS_FCHOWN: usize = SYS_CLASS_FILE | 207;
pub const SYS_FCNTL: usize = SYS_CLASS_FILE | 55;
pub const SYS_FEVENT: usize = SYS_CLASS_FILE | 927;
pub const SYS_FEXEC: usize = SYS_CLASS_FILE | 11;
pub const SYS_FMAP: usize = SYS_CLASS_FILE | 90;
pub const SYS_FUNMAP: usize = SYS_CLASS_FILE | 91;
pub const SYS_FPATH: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 928;
@@ -50,7 +51,6 @@ pub const SYS_BRK: usize = 45;
pub const SYS_CHDIR: usize = 12;
pub const SYS_CLOCK_GETTIME: usize = 265;
pub const SYS_CLONE: usize = 120;
pub const SYS_EXECVE: usize = 11;
pub const SYS_EXIT: usize = 1;
pub const SYS_FUTEX: usize = 240;
pub const SYS_GETCWD: usize = 183;
Submodule llvm updated from 7051ea to f8d511
@@ -34,7 +34,7 @@ cc = "1.0.1"

[features]
c = []
default = ["c", "rustbuild", "compiler-builtins"]
default = ["rustbuild", "compiler-builtins"]
mem = []
rustbuild = []
compiler-builtins = []
@@ -51,6 +51,7 @@ static TARGETS: &'static [&'static str] = &[
"aarch64-unknown-cloudabi",
"aarch64-unknown-linux-gnu",
"aarch64-unknown-linux-musl",
"aarch64-unknown-redox",
"arm-linux-androideabi",
"arm-unknown-linux-gnueabi",
"arm-unknown-linux-gnueabihf",