Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redox: Update to new changes #55182

Merged
merged 6 commits into from
Nov 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions src/libstd/sys/redox/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,29 @@ pub fn cvt(result: Result<usize, syscall::Error>) -> io::Result<usize> {
result.map_err(|err| io::Error::from_raw_os_error(err.errno))
}

#[doc(hidden)]
pub trait IsMinusOne {
fn is_minus_one(&self) -> bool;
}

macro_rules! impl_is_minus_one {
($($t:ident)*) => ($(impl IsMinusOne for $t {
fn is_minus_one(&self) -> bool {
*self == -1
}
})*)
}

impl_is_minus_one! { i8 i16 i32 i64 isize }

pub fn cvt_libc<T: IsMinusOne>(t: T) -> io::Result<T> {
if t.is_minus_one() {
Err(io::Error::last_os_error())
} else {
Ok(t)
}
}

/// On Redox, use an illegal instruction to abort
pub unsafe fn abort_internal() -> ! {
::core::intrinsics::abort();
Expand Down
101 changes: 68 additions & 33 deletions src/libstd/sys/redox/os.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@

#![allow(unused_imports)] // lots of cfg code here

use libc::{self, c_char};

use os::unix::prelude::*;

use error::Error as StdError;
use ffi::{OsString, OsStr};
use ffi::{CStr, CString, OsStr, OsString};
use fmt;
use io::{self, Read, Write};
use iter;
Expand All @@ -27,7 +29,7 @@ use ptr;
use slice;
use str;
use sys_common::mutex::Mutex;
use sys::{cvt, fd, syscall};
use sys::{cvt, cvt_libc, fd, syscall};
use vec;

extern {
Expand Down Expand Up @@ -129,6 +131,8 @@ pub fn current_exe() -> io::Result<PathBuf> {
Ok(PathBuf::from(path))
}

pub static ENV_LOCK: Mutex = Mutex::new();

pub struct Env {
iter: vec::IntoIter<(OsString, OsString)>,
_dont_send_or_sync_me: PhantomData<*mut ()>,
Expand All @@ -140,52 +144,83 @@ impl Iterator for Env {
fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
}

pub unsafe fn environ() -> *mut *const *const c_char {
extern { static mut environ: *const *const c_char; }
&mut environ
}

/// Returns a vector of (variable, value) byte-vector pairs for all the
/// environment variables of the current process.
pub fn env() -> Env {
let mut variables: Vec<(OsString, OsString)> = Vec::new();
if let Ok(mut file) = ::fs::File::open("env:") {
let mut string = String::new();
if file.read_to_string(&mut string).is_ok() {
for line in string.lines() {
let mut parts = line.splitn(2, '=');
if let Some(name) = parts.next() {
let value = parts.next().unwrap_or("");
variables.push((OsString::from(name.to_string()),
OsString::from(value.to_string())));
}
unsafe {
let _guard = ENV_LOCK.lock();
let mut environ = *environ();
if environ == ptr::null() {
panic!("os::env() failure getting env string from OS: {}",
io::Error::last_os_error());
}
let mut result = Vec::new();
while *environ != ptr::null() {
if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) {
result.push(key_value);
}
environ = environ.offset(1);
}
return Env {
iter: result.into_iter(),
_dont_send_or_sync_me: PhantomData,
}
}

fn parse(input: &[u8]) -> Option<(OsString, OsString)> {
// Strategy (copied from glibc): Variable name and value are separated
// by an ASCII equals sign '='. Since a variable name must not be
// empty, allow variable names starting with an equals sign. Skip all
// malformed lines.
if input.is_empty() {
return None;
}
let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1);
pos.map(|p| (
OsStringExt::from_vec(input[..p].to_vec()),
OsStringExt::from_vec(input[p+1..].to_vec()),
))
}
Env { iter: variables.into_iter(), _dont_send_or_sync_me: PhantomData }
}

pub fn getenv(key: &OsStr) -> io::Result<Option<OsString>> {
if ! key.is_empty() {
if let Ok(mut file) = ::fs::File::open(&("env:".to_owned() + key.to_str().unwrap())) {
let mut string = String::new();
file.read_to_string(&mut string)?;
Ok(Some(OsString::from(string)))
pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
// environment variables with a nul byte can't be set, so their value is
// always None as well
let k = CString::new(k.as_bytes())?;
unsafe {
let _guard = ENV_LOCK.lock();
let s = libc::getenv(k.as_ptr()) as *const libc::c_char;
let ret = if s.is_null() {
None
} else {
Ok(None)
}
} else {
Ok(None)
Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec()))
};
Ok(ret)
}
}

pub fn setenv(key: &OsStr, value: &OsStr) -> io::Result<()> {
if ! key.is_empty() {
let mut file = ::fs::File::create(&("env:".to_owned() + key.to_str().unwrap()))?;
file.write_all(value.as_bytes())?;
file.set_len(value.len() as u64)?;
pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
let k = CString::new(k.as_bytes())?;
let v = CString::new(v.as_bytes())?;

unsafe {
let _guard = ENV_LOCK.lock();
cvt_libc(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(|_| ())
}
Ok(())
}

pub fn unsetenv(key: &OsStr) -> io::Result<()> {
::fs::remove_file(&("env:".to_owned() + key.to_str().unwrap()))?;
Ok(())
pub fn unsetenv(n: &OsStr) -> io::Result<()> {
let nbuf = CString::new(n.as_bytes())?;

unsafe {
let _guard = ENV_LOCK.lock();
cvt_libc(libc::unsetenv(nbuf.as_ptr())).map(|_| ())
}
}

pub fn page_size() -> usize {
Expand Down
115 changes: 96 additions & 19 deletions src/libstd/sys/redox/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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('/') {
Expand All @@ -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");
}
}

Expand Down Expand Up @@ -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))
}
}
Expand All @@ -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())
}
}
Expand Down
13 changes: 4 additions & 9 deletions src/libstd/sys/redox/syscall/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) }
Expand All @@ -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
Expand Down
Loading