about summary refs log tree commit diff
path: root/src/libstd/sys/unix/os.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstd/sys/unix/os.rs')
-rw-r--r--src/libstd/sys/unix/os.rs116
1 files changed, 53 insertions, 63 deletions
diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs
index 59b385b9481..3c53db53f85 100644
--- a/src/libstd/sys/unix/os.rs
+++ b/src/libstd/sys/unix/os.rs
@@ -26,38 +26,25 @@ use path::{self, PathBuf};
 use ptr;
 use slice;
 use str;
-use sys::c;
+use sync::StaticMutex;
+use sys::cvt;
 use sys::fd;
 use vec;
 
 const TMPBUF_SZ: usize = 128;
+static ENV_LOCK: StaticMutex = StaticMutex::new();
 
 /// Returns the platform-specific value of errno
 pub fn errno() -> i32 {
-    #[cfg(any(target_os = "macos",
-              target_os = "ios",
-              target_os = "freebsd"))]
-    unsafe fn errno_location() -> *const c_int {
-        extern { fn __error() -> *const c_int; }
-        __error()
-    }
-
-    #[cfg(target_os = "dragonfly")]
-    unsafe fn errno_location() -> *const c_int {
-        extern { fn __dfly_error() -> *const c_int; }
-        __dfly_error()
-    }
-
-    #[cfg(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"))]
-    unsafe fn errno_location() -> *const c_int {
-        extern { fn __errno() -> *const c_int; }
-        __errno()
-    }
-
-    #[cfg(any(target_os = "linux", target_os = "android"))]
-    unsafe fn errno_location() -> *const c_int {
-        extern { fn __errno_location() -> *const c_int; }
-        __errno_location()
+    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;
     }
 
     unsafe {
@@ -67,14 +54,9 @@ pub fn errno() -> i32 {
 
 /// Gets a detailed string description for the given error number.
 pub fn error_string(errno: i32) -> String {
-    #[cfg(target_os = "linux")]
-    extern {
-        #[link_name = "__xpg_strerror_r"]
-        fn strerror_r(errnum: c_int, buf: *mut c_char,
-                      buflen: libc::size_t) -> c_int;
-    }
-    #[cfg(not(target_os = "linux"))]
     extern {
+        #[cfg_attr(any(target_os = "linux", target_env = "newlib"),
+                   link_name = "__xpg_strerror_r")]
         fn strerror_r(errnum: c_int, buf: *mut c_char,
                       buflen: libc::size_t) -> c_int;
     }
@@ -247,8 +229,11 @@ pub fn current_exe() -> io::Result<PathBuf> {
 
 #[cfg(any(target_os = "macos", target_os = "ios"))]
 pub fn current_exe() -> io::Result<PathBuf> {
+    extern {
+        fn _NSGetExecutablePath(buf: *mut libc::c_char,
+                                bufsize: *mut u32) -> libc::c_int;
+    }
     unsafe {
-        use libc::funcs::extra::_NSGetExecutablePath;
         let mut sz: u32 = 0;
         _NSGetExecutablePath(ptr::null_mut(), &mut sz);
         if sz == 0 { return Err(io::Error::last_os_error()); }
@@ -361,7 +346,8 @@ pub fn args() -> Args {
           target_os = "dragonfly",
           target_os = "bitrig",
           target_os = "netbsd",
-          target_os = "openbsd"))]
+          target_os = "openbsd",
+          target_os = "nacl"))]
 pub fn args() -> Args {
     use sys_common;
     let bytes = sys_common::args::clone().unwrap_or(Vec::new());
@@ -397,6 +383,7 @@ pub unsafe fn environ() -> *mut *const *const c_char {
 /// Returns a vector of (variable, value) byte-vector pairs for all the
 /// environment variables of the current process.
 pub fn env() -> Env {
+    let _g = ENV_LOCK.lock();
     return unsafe {
         let mut environ = *environ();
         if environ as usize == 0 {
@@ -420,35 +407,36 @@ pub fn env() -> Env {
     }
 }
 
-pub fn getenv(k: &OsStr) -> Option<OsString> {
-    unsafe {
-        let s = k.to_cstring().unwrap();
-        let s = libc::getenv(s.as_ptr()) as *const _;
+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 _;
         if s.is_null() {
             None
         } else {
             Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec()))
         }
-    }
+    })
 }
 
-pub fn setenv(k: &OsStr, v: &OsStr) {
-    unsafe {
-        let k = k.to_cstring().unwrap();
-        let v = v.to_cstring().unwrap();
-        if libc::funcs::posix01::unistd::setenv(k.as_ptr(), v.as_ptr(), 1) != 0 {
-            panic!("failed setenv: {}", io::Error::last_os_error());
-        }
-    }
+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 {
+        libc::setenv(k.as_ptr(), v.as_ptr(), 1)
+    }).map(|_| ())
 }
 
-pub fn unsetenv(n: &OsStr) {
-    unsafe {
-        let nbuf = n.to_cstring().unwrap();
-        if libc::funcs::posix01::unistd::unsetenv(nbuf.as_ptr()) != 0 {
-            panic!("failed unsetenv: {}", io::Error::last_os_error());
-        }
-    }
+pub fn unsetenv(n: &OsStr) -> io::Result<()> {
+    let nbuf = try!(CString::new(n.as_bytes()));
+    let _g = ENV_LOCK.lock();
+    cvt(unsafe {
+        libc::unsetenv(nbuf.as_ptr())
+    }).map(|_| ())
 }
 
 pub fn page_size() -> usize {
@@ -458,7 +446,7 @@ pub fn page_size() -> usize {
 }
 
 pub fn temp_dir() -> PathBuf {
-    getenv("TMPDIR".as_ref()).map(PathBuf::from).unwrap_or_else(|| {
+    ::env::var_os("TMPDIR").map(PathBuf::from).unwrap_or_else(|| {
         if cfg!(target_os = "android") {
             PathBuf::from("/data/local/tmp")
         } else {
@@ -468,28 +456,30 @@ pub fn temp_dir() -> PathBuf {
 }
 
 pub fn home_dir() -> Option<PathBuf> {
-    return getenv("HOME".as_ref()).or_else(|| unsafe {
+    return ::env::var_os("HOME").or_else(|| unsafe {
         fallback()
     }).map(PathBuf::from);
 
     #[cfg(any(target_os = "android",
-              target_os = "ios"))]
+              target_os = "ios",
+              target_os = "nacl"))]
     unsafe fn fallback() -> Option<OsString> { None }
     #[cfg(not(any(target_os = "android",
-                  target_os = "ios")))]
+                  target_os = "ios",
+                  target_os = "nacl")))]
     unsafe fn fallback() -> Option<OsString> {
-        let amt = match libc::sysconf(c::_SC_GETPW_R_SIZE_MAX) {
+        let amt = match libc::sysconf(libc::_SC_GETPW_R_SIZE_MAX) {
             n if n < 0 => 512 as usize,
             n => n as usize,
         };
         let me = libc::getuid();
         loop {
             let mut buf = Vec::with_capacity(amt);
-            let mut passwd: c::passwd = mem::zeroed();
+            let mut passwd: libc::passwd = mem::zeroed();
             let mut result = ptr::null_mut();
-            match c::getpwuid_r(me, &mut passwd, buf.as_mut_ptr(),
-                                buf.capacity() as libc::size_t,
-                                &mut result) {
+            match libc::getpwuid_r(me, &mut passwd, buf.as_mut_ptr(),
+                                   buf.capacity() as libc::size_t,
+                                   &mut result) {
                 0 if !result.is_null() => {}
                 _ => return None
             }