2014-09-30 17:03:56 -07:00
|
|
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// 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-24 16:21:39 -08:00
|
|
|
//! Implementation of `std::os` functionality for unix systems
|
|
|
|
|
2014-12-22 09:04:23 -08:00
|
|
|
use prelude::v1::*;
|
2014-11-24 16:21:39 -08:00
|
|
|
|
|
|
|
use error::{FromError, Error};
|
2014-11-25 13:28:35 -08:00
|
|
|
use ffi::{self, CString};
|
2014-11-24 16:21:39 -08:00
|
|
|
use fmt;
|
2015-01-22 16:31:00 -08:00
|
|
|
use old_io::{IoError, IoResult};
|
2015-01-03 22:42:21 -05:00
|
|
|
use libc::{self, c_int, c_char, c_void};
|
2014-11-25 13:28:35 -08:00
|
|
|
use os::TMPBUF_SZ;
|
2014-12-22 09:04:23 -08:00
|
|
|
use os;
|
|
|
|
use path::{BytesContainer};
|
2014-12-15 06:03:00 +02:00
|
|
|
use ptr;
|
2014-11-25 13:28:35 -08:00
|
|
|
use str;
|
2014-10-10 10:11:49 -07:00
|
|
|
use sys::fs::FileDesc;
|
2014-09-30 17:03:56 -07:00
|
|
|
|
2014-11-24 16:21:39 -08:00
|
|
|
const BUF_BYTES : uint = 2048u;
|
|
|
|
|
2014-09-30 17:03:56 -07:00
|
|
|
/// Returns the platform-specific value of errno
|
|
|
|
pub fn errno() -> int {
|
|
|
|
#[cfg(any(target_os = "macos",
|
|
|
|
target_os = "ios",
|
|
|
|
target_os = "freebsd"))]
|
|
|
|
fn errno_location() -> *const c_int {
|
|
|
|
extern {
|
|
|
|
fn __error() -> *const c_int;
|
|
|
|
}
|
|
|
|
unsafe {
|
|
|
|
__error()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(target_os = "dragonfly")]
|
|
|
|
fn errno_location() -> *const c_int {
|
|
|
|
extern {
|
|
|
|
fn __dfly_error() -> *const c_int;
|
|
|
|
}
|
|
|
|
unsafe {
|
|
|
|
__dfly_error()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(any(target_os = "linux", target_os = "android"))]
|
|
|
|
fn errno_location() -> *const c_int {
|
|
|
|
extern {
|
|
|
|
fn __errno_location() -> *const c_int;
|
|
|
|
}
|
|
|
|
unsafe {
|
|
|
|
__errno_location()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
(*errno_location()) as int
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get a detailed string description for the given error number
|
|
|
|
pub fn error_string(errno: i32) -> String {
|
|
|
|
#[cfg(any(target_os = "macos",
|
|
|
|
target_os = "ios",
|
|
|
|
target_os = "android",
|
|
|
|
target_os = "freebsd",
|
|
|
|
target_os = "dragonfly"))]
|
|
|
|
fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t)
|
|
|
|
-> c_int {
|
|
|
|
extern {
|
|
|
|
fn strerror_r(errnum: c_int, buf: *mut c_char,
|
|
|
|
buflen: libc::size_t) -> c_int;
|
|
|
|
}
|
|
|
|
unsafe {
|
|
|
|
strerror_r(errnum, buf, buflen)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// GNU libc provides a non-compliant version of strerror_r by default
|
|
|
|
// and requires macros to instead use the POSIX compliant variant.
|
|
|
|
// So we just use __xpg_strerror_r which is always POSIX compliant
|
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
fn strerror_r(errnum: c_int, buf: *mut c_char,
|
|
|
|
buflen: libc::size_t) -> c_int {
|
|
|
|
extern {
|
|
|
|
fn __xpg_strerror_r(errnum: c_int,
|
|
|
|
buf: *mut c_char,
|
|
|
|
buflen: libc::size_t)
|
|
|
|
-> c_int;
|
|
|
|
}
|
|
|
|
unsafe {
|
|
|
|
__xpg_strerror_r(errnum, buf, buflen)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-01 17:40:24 +13:00
|
|
|
let mut buf = [0 as c_char; TMPBUF_SZ];
|
2014-09-30 17:03:56 -07: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 13:28:35 -08:00
|
|
|
let p = p as *const _;
|
|
|
|
str::from_utf8(ffi::c_str_to_bytes(&p)).unwrap().to_string()
|
2014-09-30 17:03:56 -07:00
|
|
|
}
|
|
|
|
}
|
2014-10-10 10:11:49 -07:00
|
|
|
|
|
|
|
pub unsafe fn pipe() -> IoResult<(FileDesc, FileDesc)> {
|
2014-12-30 21:19:41 +13:00
|
|
|
let mut fds = [0; 2];
|
2014-10-10 10:11:49 -07:00
|
|
|
if libc::pipe(fds.as_mut_ptr()) == 0 {
|
|
|
|
Ok((FileDesc::new(fds[0], true), FileDesc::new(fds[1], true)))
|
|
|
|
} else {
|
|
|
|
Err(super::last_error())
|
|
|
|
}
|
|
|
|
}
|
2014-11-24 16:21:39 -08:00
|
|
|
|
|
|
|
pub fn getcwd() -> IoResult<Path> {
|
2015-01-01 17:40:24 +13:00
|
|
|
let mut buf = [0 as c_char; BUF_BYTES];
|
2014-11-24 16:21:39 -08:00
|
|
|
unsafe {
|
|
|
|
if libc::getcwd(buf.as_mut_ptr(), buf.len() as libc::size_t).is_null() {
|
|
|
|
Err(IoError::last_error())
|
|
|
|
} else {
|
2014-11-25 13:28:35 -08:00
|
|
|
Ok(Path::new(ffi::c_str_to_bytes(&buf.as_ptr())))
|
2014-11-24 16:21:39 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn get_env_pairs() -> Vec<Vec<u8>> {
|
|
|
|
extern {
|
|
|
|
fn rust_env_pairs() -> *const *const c_char;
|
|
|
|
}
|
|
|
|
let mut environ = rust_env_pairs();
|
|
|
|
if environ as uint == 0 {
|
|
|
|
panic!("os::env() failure getting env string from OS: {}",
|
|
|
|
os::last_os_error());
|
|
|
|
}
|
|
|
|
let mut result = Vec::new();
|
2015-01-19 08:27:09 +03:00
|
|
|
while *environ != ptr::null() {
|
2014-11-25 13:28:35 -08:00
|
|
|
let env_pair = ffi::c_str_to_bytes(&*environ).to_vec();
|
2014-11-24 16:21:39 -08:00
|
|
|
result.push(env_pair);
|
|
|
|
environ = environ.offset(1);
|
|
|
|
}
|
|
|
|
result
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn split_paths(unparsed: &[u8]) -> Vec<Path> {
|
|
|
|
unparsed.split(|b| *b == b':').map(Path::new).collect()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static str> {
|
|
|
|
let mut joined = Vec::new();
|
|
|
|
let sep = b':';
|
|
|
|
|
|
|
|
for (i, path) in paths.iter().map(|p| p.container_as_bytes()).enumerate() {
|
|
|
|
if i > 0 { joined.push(sep) }
|
|
|
|
if path.contains(&sep) { return Err("path segment contains separator `:`") }
|
|
|
|
joined.push_all(path);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(joined)
|
|
|
|
}
|
|
|
|
|
2014-12-19 13:05:06 +01:00
|
|
|
#[cfg(target_os = "freebsd")]
|
2014-11-24 16:21:39 -08:00
|
|
|
pub fn load_self() -> Option<Vec<u8>> {
|
|
|
|
unsafe {
|
|
|
|
use libc::funcs::bsd44::*;
|
|
|
|
use libc::consts::os::extra::*;
|
|
|
|
let mut mib = vec![CTL_KERN as c_int,
|
|
|
|
KERN_PROC as c_int,
|
|
|
|
KERN_PROC_PATHNAME as c_int,
|
|
|
|
-1 as c_int];
|
|
|
|
let mut sz: libc::size_t = 0;
|
|
|
|
let err = sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint,
|
|
|
|
ptr::null_mut(), &mut sz, ptr::null_mut(),
|
|
|
|
0u as libc::size_t);
|
|
|
|
if err != 0 { return None; }
|
|
|
|
if sz == 0 { return None; }
|
|
|
|
let mut v: Vec<u8> = Vec::with_capacity(sz as uint);
|
|
|
|
let err = sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint,
|
2014-12-22 12:56:18 -08:00
|
|
|
v.as_mut_ptr() as *mut libc::c_void, &mut sz,
|
2014-11-24 16:21:39 -08:00
|
|
|
ptr::null_mut(), 0u as libc::size_t);
|
|
|
|
if err != 0 { return None; }
|
|
|
|
if sz == 0 { return None; }
|
|
|
|
v.set_len(sz as uint - 1); // chop off trailing NUL
|
|
|
|
Some(v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-19 13:05:06 +01:00
|
|
|
#[cfg(target_os = "dragonfly")]
|
2014-12-19 22:19:37 +01:00
|
|
|
pub fn load_self() -> Option<Vec<u8>> {
|
2015-01-29 01:56:59 +01:00
|
|
|
use old_io;
|
2014-12-19 13:05:06 +01:00
|
|
|
|
2015-01-22 16:31:00 -08:00
|
|
|
match old_io::fs::readlink(&Path::new("/proc/curproc/file")) {
|
2014-12-19 13:05:06 +01:00
|
|
|
Ok(path) => Some(path.into_vec()),
|
|
|
|
Err(..) => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-24 16:21:39 -08:00
|
|
|
#[cfg(any(target_os = "linux", target_os = "android"))]
|
|
|
|
pub fn load_self() -> Option<Vec<u8>> {
|
2015-01-22 16:31:00 -08:00
|
|
|
use old_io;
|
2014-11-24 16:21:39 -08:00
|
|
|
|
2015-01-22 16:31:00 -08:00
|
|
|
match old_io::fs::readlink(&Path::new("/proc/self/exe")) {
|
2014-11-24 16:21:39 -08:00
|
|
|
Ok(path) => Some(path.into_vec()),
|
|
|
|
Err(..) => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
|
|
|
pub fn load_self() -> Option<Vec<u8>> {
|
|
|
|
unsafe {
|
|
|
|
use libc::funcs::extra::_NSGetExecutablePath;
|
|
|
|
let mut sz: u32 = 0;
|
|
|
|
_NSGetExecutablePath(ptr::null_mut(), &mut sz);
|
|
|
|
if sz == 0 { return None; }
|
|
|
|
let mut v: Vec<u8> = Vec::with_capacity(sz as uint);
|
|
|
|
let err = _NSGetExecutablePath(v.as_mut_ptr() as *mut i8, &mut sz);
|
|
|
|
if err != 0 { return None; }
|
|
|
|
v.set_len(sz as uint - 1); // chop off trailing NUL
|
|
|
|
Some(v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn chdir(p: &Path) -> IoResult<()> {
|
2014-11-25 13:28:35 -08:00
|
|
|
let p = CString::from_slice(p.as_vec());
|
|
|
|
unsafe {
|
|
|
|
match libc::chdir(p.as_ptr()) == (0 as c_int) {
|
|
|
|
true => Ok(()),
|
|
|
|
false => Err(IoError::last_error()),
|
2014-11-24 16:21:39 -08:00
|
|
|
}
|
2014-11-25 13:28:35 -08:00
|
|
|
}
|
2014-11-24 16:21:39 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn page_size() -> uint {
|
|
|
|
unsafe {
|
|
|
|
libc::sysconf(libc::_SC_PAGESIZE) as uint
|
|
|
|
}
|
|
|
|
}
|