1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Implementation of `std::os` functionality for unix systems
16 use error::{FromError, Error};
18 use io::{IoError, IoResult};
19 use libc::{mod, c_int, c_char, c_void};
21 use path::{BytesContainer};
23 use sync::atomic::{AtomicInt, SeqCst};
24 use sys::fs::FileDesc;
28 const BUF_BYTES : uint = 2048u;
30 /// Returns the platform-specific value of errno
31 pub fn errno() -> int {
32 #[cfg(any(target_os = "macos",
34 target_os = "freebsd"))]
35 fn errno_location() -> *const c_int {
37 fn __error() -> *const c_int;
44 #[cfg(target_os = "dragonfly")]
45 fn errno_location() -> *const c_int {
47 fn __dfly_error() -> *const c_int;
54 #[cfg(any(target_os = "linux", target_os = "android"))]
55 fn errno_location() -> *const c_int {
57 fn __errno_location() -> *const c_int;
65 (*errno_location()) as int
69 /// Get a detailed string description for the given error number
70 pub fn error_string(errno: i32) -> String {
71 #[cfg(any(target_os = "macos",
73 target_os = "android",
74 target_os = "freebsd",
75 target_os = "dragonfly"))]
76 fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t)
79 fn strerror_r(errnum: c_int, buf: *mut c_char,
80 buflen: libc::size_t) -> c_int;
83 strerror_r(errnum, buf, buflen)
87 // GNU libc provides a non-compliant version of strerror_r by default
88 // and requires macros to instead use the POSIX compliant variant.
89 // So we just use __xpg_strerror_r which is always POSIX compliant
90 #[cfg(target_os = "linux")]
91 fn strerror_r(errnum: c_int, buf: *mut c_char,
92 buflen: libc::size_t) -> c_int {
94 fn __xpg_strerror_r(errnum: c_int,
100 __xpg_strerror_r(errnum, buf, buflen)
104 let mut buf = [0 as c_char; TMPBUF_SZ];
106 let p = buf.as_mut_ptr();
108 if strerror_r(errno as c_int, p, buf.len() as libc::size_t) < 0 {
109 panic!("strerror_r failure");
112 String::from_raw_buf(p as *const u8)
116 pub unsafe fn pipe() -> IoResult<(FileDesc, FileDesc)> {
117 let mut fds = [0; 2];
118 if libc::pipe(fds.as_mut_ptr()) == 0 {
119 Ok((FileDesc::new(fds[0], true), FileDesc::new(fds[1], true)))
121 Err(super::last_error())
125 pub fn getcwd() -> IoResult<Path> {
128 let mut buf = [0 as c_char; BUF_BYTES];
130 if libc::getcwd(buf.as_mut_ptr(), buf.len() as libc::size_t).is_null() {
131 Err(IoError::last_error())
133 Ok(Path::new(CString::new(buf.as_ptr(), false)))
138 pub unsafe fn get_env_pairs() -> Vec<Vec<u8>> {
142 fn rust_env_pairs() -> *const *const c_char;
144 let mut environ = rust_env_pairs();
145 if environ as uint == 0 {
146 panic!("os::env() failure getting env string from OS: {}",
147 os::last_os_error());
149 let mut result = Vec::new();
150 while *environ != 0 as *const _ {
152 CString::new(*environ, false).as_bytes_no_nul().to_vec();
153 result.push(env_pair);
154 environ = environ.offset(1);
159 pub fn split_paths(unparsed: &[u8]) -> Vec<Path> {
160 unparsed.split(|b| *b == b':').map(Path::new).collect()
163 pub fn join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static str> {
164 let mut joined = Vec::new();
167 for (i, path) in paths.iter().map(|p| p.container_as_bytes()).enumerate() {
168 if i > 0 { joined.push(sep) }
169 if path.contains(&sep) { return Err("path segment contains separator `:`") }
170 joined.push_all(path);
176 #[cfg(target_os = "freebsd")]
177 pub fn load_self() -> Option<Vec<u8>> {
179 use libc::funcs::bsd44::*;
180 use libc::consts::os::extra::*;
181 let mut mib = vec![CTL_KERN as c_int,
183 KERN_PROC_PATHNAME as c_int,
185 let mut sz: libc::size_t = 0;
186 let err = sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint,
187 ptr::null_mut(), &mut sz, ptr::null_mut(),
189 if err != 0 { return None; }
190 if sz == 0 { return None; }
191 let mut v: Vec<u8> = Vec::with_capacity(sz as uint);
192 let err = sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint,
193 v.as_mut_ptr() as *mut libc::c_void, &mut sz,
194 ptr::null_mut(), 0u as libc::size_t);
195 if err != 0 { return None; }
196 if sz == 0 { return None; }
197 v.set_len(sz as uint - 1); // chop off trailing NUL
202 #[cfg(target_os = "dragonfly")]
203 pub fn load_self() -> Option<Vec<u8>> {
206 match io::fs::readlink(&Path::new("/proc/curproc/file")) {
207 Ok(path) => Some(path.into_vec()),
212 #[cfg(any(target_os = "linux", target_os = "android"))]
213 pub fn load_self() -> Option<Vec<u8>> {
216 match io::fs::readlink(&Path::new("/proc/self/exe")) {
217 Ok(path) => Some(path.into_vec()),
222 #[cfg(any(target_os = "macos", target_os = "ios"))]
223 pub fn load_self() -> Option<Vec<u8>> {
225 use libc::funcs::extra::_NSGetExecutablePath;
227 _NSGetExecutablePath(ptr::null_mut(), &mut sz);
228 if sz == 0 { return None; }
229 let mut v: Vec<u8> = Vec::with_capacity(sz as uint);
230 let err = _NSGetExecutablePath(v.as_mut_ptr() as *mut i8, &mut sz);
231 if err != 0 { return None; }
232 v.set_len(sz as uint - 1); // chop off trailing NUL
237 pub fn chdir(p: &Path) -> IoResult<()> {
240 match libc::chdir(buf) == (0 as c_int) {
242 false => Err(IoError::last_error()),
248 pub fn page_size() -> uint {
250 libc::sysconf(libc::_SC_PAGESIZE) as uint