2015-01-27 20:20:58 +00:00
|
|
|
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
2014-10-01 00:03:56 +00:00
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2014-11-25 00:21:39 +00:00
|
|
|
//! Implementation of `std::os` functionality for unix systems
|
|
|
|
|
2015-03-10 03:04:35 +00:00
|
|
|
#![allow(unused_imports)] // lots of cfg code here
|
|
|
|
|
2014-12-22 17:04:23 +00:00
|
|
|
use prelude::v1::*;
|
std: Stabilize portions of `std::os::$platform`
This commit starts to organize the `std::os::$platform` modules and in the
process stabilizes some of the functionality contained within. The organization
of these modules will reflect the organization of the standard library itself
with extension traits for primitives in the same corresponding module.
The OS-specific modules will grow more functionality over time including
concrete types that are not extending functionality of other structures, and
these will either go into the closest module in `std::os::$platform` or they
will grow a new module in the hierarchy.
The following items are now stable:
* `os::{unix, windows}`
* `unix::ffi`
* `unix::ffi::OsStrExt`
* `unix::ffi::OsStrExt::{from_bytes, as_bytes, to_cstring}`
* `unix::ffi::OsString`
* `unix::ffi::OsStringExt::{from_vec, into_vec}`
* `unix::process`
* `unix::process::CommandExt`
* `unix::process::CommandExt::{uid, gid}`
* `unix::process::ExitStatusExt`
* `unix::process::ExitStatusExt::signal`
* `unix::prelude`
* `windows::ffi`
* `windows::ffi::OsStringExt`
* `windows::ffi::OsStringExt::from_wide`
* `windows::ffi::OsStrExt`
* `windows::ffi::OsStrExt::encode_wide`
* `windows::prelude`
The following items remain unstable:
* `unix::io`
* `unix::io::{Fd, AsRawFd}`
* `unix::fs::{PermissionsExt, OpenOptionsExt}`
* `windows::io`
* `windows::io::{Handle, AsRawHandle}`
* `windows::io::{Socket, AsRawSocket}`
* `windows::fs`
* `windows::fs::OpenOptionsExt`
Due to the reorgnization of the platform extension modules, this commit is a
breaking change. Most imports can be fixed by adding the relevant libstd module
in the `use` path (such as `ffi` or `fs`).
[breaking-change]
2015-03-14 00:12:38 +00:00
|
|
|
use os::unix::prelude::*;
|
2014-11-25 00:21:39 +00:00
|
|
|
|
2015-01-27 20:20:58 +00:00
|
|
|
use error::Error as StdError;
|
2015-03-30 18:00:05 +00:00
|
|
|
use ffi::{CString, CStr, OsString, OsStr};
|
2014-11-25 00:21:39 +00:00
|
|
|
use fmt;
|
2015-02-23 18:59:17 +00:00
|
|
|
use io;
|
2015-01-27 20:20:58 +00:00
|
|
|
use iter;
|
2015-01-04 03:42:21 +00:00
|
|
|
use libc::{self, c_int, c_char, c_void};
|
2015-01-27 20:20:58 +00:00
|
|
|
use mem;
|
2015-12-14 23:03:42 +00:00
|
|
|
use memchr;
|
2015-02-23 18:59:17 +00:00
|
|
|
use path::{self, PathBuf};
|
2015-07-08 19:36:46 +00:00
|
|
|
use ptr;
|
2015-01-27 20:20:58 +00:00
|
|
|
use slice;
|
2014-11-25 21:28:35 +00:00
|
|
|
use str;
|
2015-10-25 17:19:35 +00:00
|
|
|
use sync::StaticMutex;
|
|
|
|
use sys::cvt;
|
2015-11-03 00:23:22 +00:00
|
|
|
use sys::fd;
|
2015-01-27 20:20:58 +00:00
|
|
|
use vec;
|
2014-10-01 00:03:56 +00:00
|
|
|
|
2015-01-27 20:20:58 +00:00
|
|
|
const TMPBUF_SZ: usize = 128;
|
2015-10-25 17:19:35 +00:00
|
|
|
static ENV_LOCK: StaticMutex = StaticMutex::new();
|
2014-11-25 00:21:39 +00:00
|
|
|
|
2014-10-01 00:03:56 +00:00
|
|
|
/// Returns the platform-specific value of errno
|
2015-01-27 20:20:58 +00:00
|
|
|
pub fn errno() -> i32 {
|
2015-10-25 01:51:34 +00:00
|
|
|
extern {
|
|
|
|
#[cfg_attr(any(target_os = "linux", target_os = "android"), link_name = "__errno_location")]
|
|
|
|
#[cfg_attr(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd",
|
|
|
|
target_env = "newlib"),
|
|
|
|
link_name = "__errno")]
|
|
|
|
#[cfg_attr(target_os = "dragonfly", link_name = "__dfly_error")]
|
|
|
|
#[cfg_attr(any(target_os = "macos", target_os = "ios", target_os = "freebsd"),
|
|
|
|
link_name = "__error")]
|
|
|
|
fn errno_location() -> *const c_int;
|
2014-10-01 00:03:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
unsafe {
|
2015-01-27 20:20:58 +00:00
|
|
|
(*errno_location()) as i32
|
2014-10-01 00:03:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-13 14:21:32 +00:00
|
|
|
/// Gets a detailed string description for the given error number.
|
2014-10-01 00:03:56 +00:00
|
|
|
pub fn error_string(errno: i32) -> String {
|
2015-01-27 20:20:58 +00:00
|
|
|
extern {
|
2015-10-25 01:51:34 +00:00
|
|
|
#[cfg_attr(any(target_os = "linux", target_env = "newlib"),
|
|
|
|
link_name = "__xpg_strerror_r")]
|
2015-01-27 20:20:58 +00:00
|
|
|
fn strerror_r(errnum: c_int, buf: *mut c_char,
|
|
|
|
buflen: libc::size_t) -> c_int;
|
2014-10-01 00:03:56 +00:00
|
|
|
}
|
|
|
|
|
2015-01-01 04:40:24 +00:00
|
|
|
let mut buf = [0 as c_char; TMPBUF_SZ];
|
2014-10-01 00:03:56 +00:00
|
|
|
|
|
|
|
let p = buf.as_mut_ptr();
|
|
|
|
unsafe {
|
|
|
|
if strerror_r(errno as c_int, p, buf.len() as libc::size_t) < 0 {
|
|
|
|
panic!("strerror_r failure");
|
|
|
|
}
|
|
|
|
|
2014-11-25 21:28:35 +00:00
|
|
|
let p = p as *const _;
|
2015-09-07 22:36:29 +00:00
|
|
|
str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_owned()
|
2014-10-01 00:03:56 +00:00
|
|
|
}
|
|
|
|
}
|
2014-10-10 17:11:49 +00:00
|
|
|
|
2015-02-23 18:59:17 +00:00
|
|
|
pub fn getcwd() -> io::Result<PathBuf> {
|
2015-08-26 12:27:32 +00:00
|
|
|
let mut buf = Vec::with_capacity(512);
|
2015-07-10 10:33:10 +00:00
|
|
|
loop {
|
2015-07-08 19:36:46 +00:00
|
|
|
unsafe {
|
2015-07-09 13:03:10 +00:00
|
|
|
let ptr = buf.as_mut_ptr() as *mut libc::c_char;
|
2015-07-10 10:33:10 +00:00
|
|
|
if !libc::getcwd(ptr, buf.capacity() as libc::size_t).is_null() {
|
2015-07-09 13:03:10 +00:00
|
|
|
let len = CStr::from_ptr(buf.as_ptr() as *const libc::c_char).to_bytes().len();
|
|
|
|
buf.set_len(len);
|
2015-07-10 10:33:10 +00:00
|
|
|
buf.shrink_to_fit();
|
|
|
|
return Ok(PathBuf::from(OsString::from_vec(buf)));
|
2015-07-08 19:36:46 +00:00
|
|
|
} else {
|
|
|
|
let error = io::Error::last_os_error();
|
2015-07-10 10:33:10 +00:00
|
|
|
if error.raw_os_error() != Some(libc::ERANGE) {
|
|
|
|
return Err(error);
|
2015-07-08 19:36:46 +00:00
|
|
|
}
|
2015-07-10 10:33:10 +00:00
|
|
|
}
|
2015-08-26 12:27:32 +00:00
|
|
|
|
|
|
|
// Trigger the internal buffer resizing logic of `Vec` by requiring
|
|
|
|
// more space than the current capacity.
|
|
|
|
let cap = buf.capacity();
|
|
|
|
buf.set_len(cap);
|
|
|
|
buf.reserve(1);
|
2014-11-25 00:21:39 +00:00
|
|
|
}
|
2015-07-10 10:33:10 +00:00
|
|
|
}
|
2014-11-25 00:21:39 +00:00
|
|
|
}
|
|
|
|
|
2015-02-23 18:59:17 +00:00
|
|
|
pub fn chdir(p: &path::Path) -> io::Result<()> {
|
2015-03-30 18:00:05 +00:00
|
|
|
let p: &OsStr = p.as_ref();
|
|
|
|
let p = try!(CString::new(p.as_bytes()));
|
2015-01-27 20:20:58 +00:00
|
|
|
unsafe {
|
|
|
|
match libc::chdir(p.as_ptr()) == (0 as c_int) {
|
|
|
|
true => Ok(()),
|
2015-02-23 18:59:17 +00:00
|
|
|
false => Err(io::Error::last_os_error()),
|
2015-01-27 20:20:58 +00:00
|
|
|
}
|
2014-11-25 00:21:39 +00:00
|
|
|
}
|
2015-01-27 20:20:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct SplitPaths<'a> {
|
2015-02-02 19:04:58 +00:00
|
|
|
iter: iter::Map<slice::Split<'a, u8, fn(&u8) -> bool>,
|
2015-02-23 18:59:17 +00:00
|
|
|
fn(&'a [u8]) -> PathBuf>,
|
2015-01-27 20:20:58 +00:00
|
|
|
}
|
|
|
|
|
2015-09-07 22:36:29 +00:00
|
|
|
pub fn split_paths(unparsed: &OsStr) -> SplitPaths {
|
2015-07-09 13:03:10 +00:00
|
|
|
fn bytes_to_path(b: &[u8]) -> PathBuf {
|
|
|
|
PathBuf::from(<OsStr as OsStrExt>::from_bytes(b))
|
|
|
|
}
|
2015-01-27 20:20:58 +00:00
|
|
|
fn is_colon(b: &u8) -> bool { *b == b':' }
|
2015-02-06 17:42:57 +00:00
|
|
|
let unparsed = unparsed.as_bytes();
|
2015-01-27 20:20:58 +00:00
|
|
|
SplitPaths {
|
2015-09-08 05:41:50 +00:00
|
|
|
iter: unparsed.split(is_colon as fn(&u8) -> bool)
|
2015-09-08 06:05:59 +00:00
|
|
|
.map(bytes_to_path as fn(&[u8]) -> PathBuf)
|
2014-11-25 00:21:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-27 20:20:58 +00:00
|
|
|
impl<'a> Iterator for SplitPaths<'a> {
|
2015-02-23 18:59:17 +00:00
|
|
|
type Item = PathBuf;
|
|
|
|
fn next(&mut self) -> Option<PathBuf> { self.iter.next() }
|
2015-01-27 20:20:58 +00:00
|
|
|
fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
|
2014-11-25 00:21:39 +00:00
|
|
|
}
|
|
|
|
|
2015-01-27 20:20:58 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct JoinPathsError;
|
|
|
|
|
|
|
|
pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
|
2015-03-30 18:00:05 +00:00
|
|
|
where I: Iterator<Item=T>, T: AsRef<OsStr>
|
2015-01-27 20:20:58 +00:00
|
|
|
{
|
2014-11-25 00:21:39 +00:00
|
|
|
let mut joined = Vec::new();
|
|
|
|
let sep = b':';
|
|
|
|
|
2015-01-27 20:20:58 +00:00
|
|
|
for (i, path) in paths.enumerate() {
|
2015-03-30 18:00:05 +00:00
|
|
|
let path = path.as_ref().as_bytes();
|
2014-11-25 00:21:39 +00:00
|
|
|
if i > 0 { joined.push(sep) }
|
2015-01-27 20:20:58 +00:00
|
|
|
if path.contains(&sep) {
|
|
|
|
return Err(JoinPathsError)
|
|
|
|
}
|
2015-12-03 01:31:49 +00:00
|
|
|
joined.extend_from_slice(path);
|
2014-11-25 00:21:39 +00:00
|
|
|
}
|
2015-01-27 20:20:58 +00:00
|
|
|
Ok(OsStringExt::from_vec(joined))
|
|
|
|
}
|
2014-11-25 00:21:39 +00:00
|
|
|
|
2015-01-27 20:20:58 +00:00
|
|
|
impl fmt::Display for JoinPathsError {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
"path segment contains separator `:`".fmt(f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl StdError for JoinPathsError {
|
|
|
|
fn description(&self) -> &str { "failed to join paths" }
|
2014-11-25 00:21:39 +00:00
|
|
|
}
|
|
|
|
|
2014-12-19 12:05:06 +00:00
|
|
|
#[cfg(target_os = "freebsd")]
|
2015-02-25 08:45:24 +00:00
|
|
|
pub fn current_exe() -> io::Result<PathBuf> {
|
2014-11-25 00:21:39 +00:00
|
|
|
unsafe {
|
2015-11-17 00:53:06 +00:00
|
|
|
let mut mib = [libc::CTL_KERN as c_int,
|
|
|
|
libc::KERN_PROC as c_int,
|
|
|
|
libc::KERN_PROC_PATHNAME as c_int,
|
2015-10-12 10:37:28 +00:00
|
|
|
-1 as c_int];
|
2014-11-25 00:21:39 +00:00
|
|
|
let mut sz: libc::size_t = 0;
|
2015-11-17 00:53:06 +00:00
|
|
|
let err = libc::sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint,
|
|
|
|
ptr::null_mut(), &mut sz, ptr::null_mut(),
|
|
|
|
0 as libc::size_t);
|
2015-02-25 08:45:24 +00:00
|
|
|
if err != 0 { return Err(io::Error::last_os_error()); }
|
|
|
|
if sz == 0 { return Err(io::Error::last_os_error()); }
|
2015-03-26 00:06:52 +00:00
|
|
|
let mut v: Vec<u8> = Vec::with_capacity(sz as usize);
|
2015-11-17 00:53:06 +00:00
|
|
|
let err = libc::sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint,
|
|
|
|
v.as_mut_ptr() as *mut libc::c_void, &mut sz,
|
|
|
|
ptr::null_mut(), 0 as libc::size_t);
|
2015-02-25 08:45:24 +00:00
|
|
|
if err != 0 { return Err(io::Error::last_os_error()); }
|
|
|
|
if sz == 0 { return Err(io::Error::last_os_error()); }
|
2015-03-26 00:06:52 +00:00
|
|
|
v.set_len(sz as usize - 1); // chop off trailing NUL
|
2015-03-25 07:42:15 +00:00
|
|
|
Ok(PathBuf::from(OsString::from_vec(v)))
|
2014-11-25 00:21:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-19 12:05:06 +00:00
|
|
|
#[cfg(target_os = "dragonfly")]
|
2015-02-23 18:59:17 +00:00
|
|
|
pub fn current_exe() -> io::Result<PathBuf> {
|
|
|
|
::fs::read_link("/proc/curproc/file")
|
2014-12-19 12:05:06 +00:00
|
|
|
}
|
|
|
|
|
2015-09-20 15:39:52 +00:00
|
|
|
#[cfg(target_os = "netbsd")]
|
|
|
|
pub fn current_exe() -> io::Result<PathBuf> {
|
|
|
|
::fs::read_link("/proc/curproc/exe")
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(any(target_os = "bitrig", target_os = "openbsd"))]
|
2015-02-23 18:59:17 +00:00
|
|
|
pub fn current_exe() -> io::Result<PathBuf> {
|
2015-05-27 08:18:36 +00:00
|
|
|
use sync::StaticMutex;
|
|
|
|
static LOCK: StaticMutex = StaticMutex::new();
|
2015-01-30 07:15:28 +00:00
|
|
|
|
2015-01-29 07:19:28 +00:00
|
|
|
extern {
|
2015-02-05 14:24:17 +00:00
|
|
|
fn rust_current_exe() -> *const c_char;
|
2015-01-29 07:19:28 +00:00
|
|
|
}
|
2015-01-30 07:15:28 +00:00
|
|
|
|
|
|
|
let _guard = LOCK.lock();
|
|
|
|
|
2015-01-29 07:19:28 +00:00
|
|
|
unsafe {
|
2015-02-05 14:24:17 +00:00
|
|
|
let v = rust_current_exe();
|
2015-01-29 07:19:28 +00:00
|
|
|
if v.is_null() {
|
2015-02-25 08:45:24 +00:00
|
|
|
Err(io::Error::last_os_error())
|
2015-01-29 07:19:28 +00:00
|
|
|
} else {
|
2015-02-26 05:16:41 +00:00
|
|
|
let vec = CStr::from_ptr(v).to_bytes().to_vec();
|
2015-03-25 07:42:15 +00:00
|
|
|
Ok(PathBuf::from(OsString::from_vec(vec)))
|
2015-01-29 07:19:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-25 00:21:39 +00:00
|
|
|
#[cfg(any(target_os = "linux", target_os = "android"))]
|
2015-02-23 18:59:17 +00:00
|
|
|
pub fn current_exe() -> io::Result<PathBuf> {
|
|
|
|
::fs::read_link("/proc/self/exe")
|
2014-11-25 00:21:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
2015-02-25 08:45:24 +00:00
|
|
|
pub fn current_exe() -> io::Result<PathBuf> {
|
2015-11-03 00:23:22 +00:00
|
|
|
extern {
|
|
|
|
fn _NSGetExecutablePath(buf: *mut libc::c_char,
|
|
|
|
bufsize: *mut u32) -> libc::c_int;
|
|
|
|
}
|
2014-11-25 00:21:39 +00:00
|
|
|
unsafe {
|
|
|
|
let mut sz: u32 = 0;
|
|
|
|
_NSGetExecutablePath(ptr::null_mut(), &mut sz);
|
2015-02-25 08:45:24 +00:00
|
|
|
if sz == 0 { return Err(io::Error::last_os_error()); }
|
2015-03-26 00:06:52 +00:00
|
|
|
let mut v: Vec<u8> = Vec::with_capacity(sz as usize);
|
2014-11-25 00:21:39 +00:00
|
|
|
let err = _NSGetExecutablePath(v.as_mut_ptr() as *mut i8, &mut sz);
|
2015-02-25 08:45:24 +00:00
|
|
|
if err != 0 { return Err(io::Error::last_os_error()); }
|
2015-03-26 00:06:52 +00:00
|
|
|
v.set_len(sz as usize - 1); // chop off trailing NUL
|
2015-03-18 16:14:54 +00:00
|
|
|
Ok(PathBuf::from(OsString::from_vec(v)))
|
2014-11-25 00:21:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-27 20:20:58 +00:00
|
|
|
pub struct Args {
|
|
|
|
iter: vec::IntoIter<OsString>,
|
|
|
|
_dont_send_or_sync_me: *mut (),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Iterator for Args {
|
|
|
|
type Item = OsString;
|
|
|
|
fn next(&mut self) -> Option<OsString> { self.iter.next() }
|
|
|
|
fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
|
|
|
|
}
|
|
|
|
|
2015-02-16 10:15:30 +00:00
|
|
|
impl ExactSizeIterator for Args {
|
|
|
|
fn len(&self) -> usize { self.iter.len() }
|
|
|
|
}
|
|
|
|
|
2015-01-27 20:20:58 +00:00
|
|
|
/// Returns the command line arguments
|
|
|
|
///
|
|
|
|
/// Returns a list of the command line arguments.
|
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
pub fn args() -> Args {
|
|
|
|
extern {
|
|
|
|
// These functions are in crt_externs.h.
|
|
|
|
fn _NSGetArgc() -> *mut c_int;
|
|
|
|
fn _NSGetArgv() -> *mut *mut *mut c_char;
|
|
|
|
}
|
|
|
|
|
|
|
|
let vec = unsafe {
|
|
|
|
let (argc, argv) = (*_NSGetArgc() as isize,
|
|
|
|
*_NSGetArgv() as *const *const c_char);
|
2015-03-13 18:35:53 +00:00
|
|
|
(0.. argc as isize).map(|i| {
|
2015-02-19 02:02:58 +00:00
|
|
|
let bytes = CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec();
|
2015-01-27 20:20:58 +00:00
|
|
|
OsStringExt::from_vec(bytes)
|
|
|
|
}).collect::<Vec<_>>()
|
|
|
|
};
|
|
|
|
Args {
|
|
|
|
iter: vec.into_iter(),
|
2015-09-03 06:49:50 +00:00
|
|
|
_dont_send_or_sync_me: ptr::null_mut(),
|
2015-01-27 20:20:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
|
|
|
|
// and use underscores in their names - they're most probably
|
|
|
|
// are considered private and therefore should be avoided
|
|
|
|
// Here is another way to get arguments using Objective C
|
|
|
|
// runtime
|
|
|
|
//
|
|
|
|
// In general it looks like:
|
|
|
|
// res = Vec::new()
|
|
|
|
// let args = [[NSProcessInfo processInfo] arguments]
|
2015-03-18 15:15:53 +00:00
|
|
|
// for i in (0..[args count])
|
2015-01-27 20:20:58 +00:00
|
|
|
// res.push([args objectAtIndex:i])
|
|
|
|
// res
|
|
|
|
#[cfg(target_os = "ios")]
|
|
|
|
pub fn args() -> Args {
|
|
|
|
use mem;
|
|
|
|
|
|
|
|
#[link(name = "objc")]
|
|
|
|
extern {
|
|
|
|
fn sel_registerName(name: *const libc::c_uchar) -> Sel;
|
|
|
|
fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
|
|
|
|
fn objc_getClass(class_name: *const libc::c_uchar) -> NsId;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[link(name = "Foundation", kind = "framework")]
|
|
|
|
extern {}
|
|
|
|
|
|
|
|
type Sel = *const libc::c_void;
|
|
|
|
type NsId = *const libc::c_void;
|
|
|
|
|
|
|
|
let mut res = Vec::new();
|
|
|
|
|
2014-11-25 21:28:35 +00:00
|
|
|
unsafe {
|
2015-02-03 13:30:10 +00:00
|
|
|
let process_info_sel = sel_registerName("processInfo\0".as_ptr());
|
|
|
|
let arguments_sel = sel_registerName("arguments\0".as_ptr());
|
|
|
|
let utf8_sel = sel_registerName("UTF8String\0".as_ptr());
|
|
|
|
let count_sel = sel_registerName("count\0".as_ptr());
|
|
|
|
let object_at_sel = sel_registerName("objectAtIndex:\0".as_ptr());
|
2015-01-27 20:20:58 +00:00
|
|
|
|
|
|
|
let klass = objc_getClass("NSProcessInfo\0".as_ptr());
|
2015-02-03 13:30:10 +00:00
|
|
|
let info = objc_msgSend(klass, process_info_sel);
|
|
|
|
let args = objc_msgSend(info, arguments_sel);
|
2015-01-27 20:20:58 +00:00
|
|
|
|
2015-03-28 15:18:03 +00:00
|
|
|
let cnt: usize = mem::transmute(objc_msgSend(args, count_sel));
|
2015-10-15 01:43:05 +00:00
|
|
|
for i in 0..cnt {
|
2015-02-03 13:30:10 +00:00
|
|
|
let tmp = objc_msgSend(args, object_at_sel, i);
|
2015-01-27 20:20:58 +00:00
|
|
|
let utf_c_str: *const libc::c_char =
|
2015-02-03 13:30:10 +00:00
|
|
|
mem::transmute(objc_msgSend(tmp, utf8_sel));
|
2015-02-18 06:47:40 +00:00
|
|
|
let bytes = CStr::from_ptr(utf_c_str).to_bytes();
|
2015-03-25 01:48:14 +00:00
|
|
|
res.push(OsString::from(str::from_utf8(bytes).unwrap()))
|
2014-11-25 00:21:39 +00:00
|
|
|
}
|
2014-11-25 21:28:35 +00:00
|
|
|
}
|
2015-01-27 20:20:58 +00:00
|
|
|
|
2015-09-03 06:49:50 +00:00
|
|
|
Args { iter: res.into_iter(), _dont_send_or_sync_me: ptr::null_mut() }
|
2015-01-27 20:20:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(any(target_os = "linux",
|
|
|
|
target_os = "android",
|
|
|
|
target_os = "freebsd",
|
2015-02-05 14:24:17 +00:00
|
|
|
target_os = "dragonfly",
|
2015-01-17 07:51:04 +00:00
|
|
|
target_os = "bitrig",
|
2015-07-01 03:37:11 +00:00
|
|
|
target_os = "netbsd",
|
2015-10-25 01:51:34 +00:00
|
|
|
target_os = "openbsd",
|
|
|
|
target_os = "nacl"))]
|
2015-01-27 20:20:58 +00:00
|
|
|
pub fn args() -> Args {
|
2015-09-08 22:53:46 +00:00
|
|
|
use sys_common;
|
|
|
|
let bytes = sys_common::args::clone().unwrap_or(Vec::new());
|
2015-01-27 20:20:58 +00:00
|
|
|
let v: Vec<OsString> = bytes.into_iter().map(|v| {
|
|
|
|
OsStringExt::from_vec(v)
|
|
|
|
}).collect();
|
2015-09-03 06:49:50 +00:00
|
|
|
Args { iter: v.into_iter(), _dont_send_or_sync_me: ptr::null_mut() }
|
2015-01-27 20:20:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Env {
|
|
|
|
iter: vec::IntoIter<(OsString, OsString)>,
|
|
|
|
_dont_send_or_sync_me: *mut (),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Iterator for Env {
|
|
|
|
type Item = (OsString, OsString);
|
|
|
|
fn next(&mut self) -> Option<(OsString, OsString)> { self.iter.next() }
|
|
|
|
fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
|
2014-11-25 00:21:39 +00:00
|
|
|
}
|
|
|
|
|
2015-01-27 20:20:58 +00:00
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
pub unsafe fn environ() -> *mut *const *const c_char {
|
|
|
|
extern { fn _NSGetEnviron() -> *mut *const *const c_char; }
|
|
|
|
_NSGetEnviron()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(target_os = "macos"))]
|
|
|
|
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 {
|
2015-10-25 17:19:35 +00:00
|
|
|
let _g = ENV_LOCK.lock();
|
2015-01-27 20:20:58 +00:00
|
|
|
return unsafe {
|
|
|
|
let mut environ = *environ();
|
2015-10-25 12:05:34 +00:00
|
|
|
if environ == ptr::null() {
|
2015-01-27 20:20:58 +00:00
|
|
|
panic!("os::env() failure getting env string from OS: {}",
|
2015-03-11 22:24:14 +00:00
|
|
|
io::Error::last_os_error());
|
2015-01-27 20:20:58 +00:00
|
|
|
}
|
|
|
|
let mut result = Vec::new();
|
|
|
|
while *environ != ptr::null() {
|
2015-10-25 12:05:34 +00:00
|
|
|
if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) {
|
|
|
|
result.push(key_value);
|
|
|
|
}
|
2015-01-27 20:20:58 +00:00
|
|
|
environ = environ.offset(1);
|
|
|
|
}
|
2015-09-03 06:49:50 +00:00
|
|
|
Env { iter: result.into_iter(), _dont_send_or_sync_me: ptr::null_mut() }
|
2015-01-27 20:20:58 +00:00
|
|
|
};
|
|
|
|
|
2015-10-25 12:05:34 +00:00
|
|
|
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;
|
|
|
|
}
|
2015-12-14 23:03:42 +00:00
|
|
|
let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1);
|
2015-10-25 12:05:34 +00:00
|
|
|
pos.map(|p| (
|
|
|
|
OsStringExt::from_vec(input[..p].to_vec()),
|
|
|
|
OsStringExt::from_vec(input[p+1..].to_vec()),
|
|
|
|
))
|
2015-01-27 20:20:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-25 17:19:35 +00:00
|
|
|
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 = try!(CString::new(k.as_bytes()));
|
|
|
|
let _g = ENV_LOCK.lock();
|
|
|
|
Ok(unsafe {
|
|
|
|
let s = libc::getenv(k.as_ptr()) as *const _;
|
2015-01-27 20:20:58 +00:00
|
|
|
if s.is_null() {
|
|
|
|
None
|
|
|
|
} else {
|
2015-02-18 06:47:40 +00:00
|
|
|
Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec()))
|
2015-01-27 20:20:58 +00:00
|
|
|
}
|
2015-10-25 17:19:35 +00:00
|
|
|
})
|
2015-01-27 20:20:58 +00:00
|
|
|
}
|
|
|
|
|
2015-10-25 17:19:35 +00:00
|
|
|
pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
|
|
|
|
let k = try!(CString::new(k.as_bytes()));
|
|
|
|
let v = try!(CString::new(v.as_bytes()));
|
|
|
|
let _g = ENV_LOCK.lock();
|
|
|
|
cvt(unsafe {
|
2015-11-03 00:23:22 +00:00
|
|
|
libc::setenv(k.as_ptr(), v.as_ptr(), 1)
|
2015-10-25 17:19:35 +00:00
|
|
|
}).map(|_| ())
|
2014-11-25 00:21:39 +00:00
|
|
|
}
|
2015-01-27 20:20:58 +00:00
|
|
|
|
2015-10-25 17:19:35 +00:00
|
|
|
pub fn unsetenv(n: &OsStr) -> io::Result<()> {
|
|
|
|
let nbuf = try!(CString::new(n.as_bytes()));
|
|
|
|
let _g = ENV_LOCK.lock();
|
|
|
|
cvt(unsafe {
|
2015-11-03 00:23:22 +00:00
|
|
|
libc::unsetenv(nbuf.as_ptr())
|
2015-10-25 17:19:35 +00:00
|
|
|
}).map(|_| ())
|
2014-11-25 00:21:39 +00:00
|
|
|
}
|
|
|
|
|
2015-01-27 20:20:58 +00:00
|
|
|
pub fn page_size() -> usize {
|
2014-11-25 00:21:39 +00:00
|
|
|
unsafe {
|
2015-01-27 20:20:58 +00:00
|
|
|
libc::sysconf(libc::_SC_PAGESIZE) as usize
|
2014-11-25 00:21:39 +00:00
|
|
|
}
|
|
|
|
}
|
2015-01-27 20:20:58 +00:00
|
|
|
|
2015-02-23 18:59:17 +00:00
|
|
|
pub fn temp_dir() -> PathBuf {
|
2015-10-25 17:19:35 +00:00
|
|
|
::env::var_os("TMPDIR").map(PathBuf::from).unwrap_or_else(|| {
|
2015-01-27 20:20:58 +00:00
|
|
|
if cfg!(target_os = "android") {
|
2015-03-18 16:14:54 +00:00
|
|
|
PathBuf::from("/data/local/tmp")
|
2015-01-27 20:20:58 +00:00
|
|
|
} else {
|
2015-03-18 16:14:54 +00:00
|
|
|
PathBuf::from("/tmp")
|
2015-01-27 20:20:58 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2015-02-23 18:59:17 +00:00
|
|
|
pub fn home_dir() -> Option<PathBuf> {
|
2015-10-25 17:19:35 +00:00
|
|
|
return ::env::var_os("HOME").or_else(|| unsafe {
|
2015-02-02 19:04:58 +00:00
|
|
|
fallback()
|
2015-07-09 13:03:10 +00:00
|
|
|
}).map(PathBuf::from);
|
2015-02-02 19:04:58 +00:00
|
|
|
|
2015-02-03 13:30:10 +00:00
|
|
|
#[cfg(any(target_os = "android",
|
2015-10-25 01:51:34 +00:00
|
|
|
target_os = "ios",
|
|
|
|
target_os = "nacl"))]
|
2015-02-02 19:04:58 +00:00
|
|
|
unsafe fn fallback() -> Option<OsString> { None }
|
2015-02-03 13:30:10 +00:00
|
|
|
#[cfg(not(any(target_os = "android",
|
2015-10-25 01:51:34 +00:00
|
|
|
target_os = "ios",
|
|
|
|
target_os = "nacl")))]
|
2015-02-02 19:04:58 +00:00
|
|
|
unsafe fn fallback() -> Option<OsString> {
|
2015-11-03 00:23:22 +00:00
|
|
|
let amt = match libc::sysconf(libc::_SC_GETPW_R_SIZE_MAX) {
|
2015-01-27 20:20:58 +00:00
|
|
|
n if n < 0 => 512 as usize,
|
|
|
|
n => n as usize,
|
|
|
|
};
|
|
|
|
let me = libc::getuid();
|
|
|
|
loop {
|
|
|
|
let mut buf = Vec::with_capacity(amt);
|
2015-11-03 00:23:22 +00:00
|
|
|
let mut passwd: libc::passwd = mem::zeroed();
|
2015-09-03 06:49:50 +00:00
|
|
|
let mut result = ptr::null_mut();
|
2015-11-03 00:23:22 +00:00
|
|
|
match libc::getpwuid_r(me, &mut passwd, buf.as_mut_ptr(),
|
|
|
|
buf.capacity() as libc::size_t,
|
|
|
|
&mut result) {
|
2015-01-27 20:20:58 +00:00
|
|
|
0 if !result.is_null() => {}
|
|
|
|
_ => return None
|
|
|
|
}
|
|
|
|
let ptr = passwd.pw_dir as *const _;
|
2015-02-18 06:47:40 +00:00
|
|
|
let bytes = CStr::from_ptr(ptr).to_bytes().to_vec();
|
2015-01-27 20:20:58 +00:00
|
|
|
return Some(OsStringExt::from_vec(bytes))
|
|
|
|
}
|
2015-02-02 19:04:58 +00:00
|
|
|
}
|
2015-01-27 20:20:58 +00:00
|
|
|
}
|
2015-03-31 21:41:59 +00:00
|
|
|
|
|
|
|
pub fn exit(code: i32) -> ! {
|
|
|
|
unsafe { libc::exit(code as c_int) }
|
|
|
|
}
|