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::{self, c_int, c_char, c_void};
21 use path::{BytesContainer};
23 use sys::fs::FileDesc;
27 const BUF_BYTES : uint = 2048u;
29 /// Returns the platform-specific value of errno
30 pub fn errno() -> int {
31 #[cfg(any(target_os = "macos",
33 target_os = "freebsd"))]
34 fn errno_location() -> *const c_int {
36 fn __error() -> *const c_int;
43 #[cfg(target_os = "dragonfly")]
44 fn errno_location() -> *const c_int {
46 fn __dfly_error() -> *const c_int;
53 #[cfg(any(target_os = "linux", target_os = "android"))]
54 fn errno_location() -> *const c_int {
56 fn __errno_location() -> *const c_int;
64 (*errno_location()) as int
68 /// Get a detailed string description for the given error number
69 pub fn error_string(errno: i32) -> String {
70 #[cfg(any(target_os = "macos",
72 target_os = "android",
73 target_os = "freebsd",
74 target_os = "dragonfly"))]
75 fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t)
78 fn strerror_r(errnum: c_int, buf: *mut c_char,
79 buflen: libc::size_t) -> c_int;
82 strerror_r(errnum, buf, buflen)
86 // GNU libc provides a non-compliant version of strerror_r by default
87 // and requires macros to instead use the POSIX compliant variant.
88 // So we just use __xpg_strerror_r which is always POSIX compliant
89 #[cfg(target_os = "linux")]
90 fn strerror_r(errnum: c_int, buf: *mut c_char,
91 buflen: libc::size_t) -> c_int {
93 fn __xpg_strerror_r(errnum: c_int,
99 __xpg_strerror_r(errnum, buf, buflen)
103 let mut buf = [0 as c_char; TMPBUF_SZ];
105 let p = buf.as_mut_ptr();
107 if strerror_r(errno as c_int, p, buf.len() as libc::size_t) < 0 {
108 panic!("strerror_r failure");
111 String::from_raw_buf(p as *const u8)
115 pub unsafe fn pipe() -> IoResult<(FileDesc, FileDesc)> {
116 let mut fds = [0; 2];
117 if libc::pipe(fds.as_mut_ptr()) == 0 {
118 Ok((FileDesc::new(fds[0], true), FileDesc::new(fds[1], true)))
120 Err(super::last_error())
124 pub fn getcwd() -> IoResult<Path> {
127 let mut buf = [0 as c_char; BUF_BYTES];
129 if libc::getcwd(buf.as_mut_ptr(), buf.len() as libc::size_t).is_null() {
130 Err(IoError::last_error())
132 Ok(Path::new(CString::new(buf.as_ptr(), false)))
137 pub unsafe fn get_env_pairs() -> Vec<Vec<u8>> {
141 fn rust_env_pairs() -> *const *const c_char;
143 let mut environ = rust_env_pairs();
144 if environ as uint == 0 {
145 panic!("os::env() failure getting env string from OS: {}",
146 os::last_os_error());
148 let mut result = Vec::new();
149 while *environ != 0 as *const _ {
151 CString::new(*environ, false).as_bytes_no_nul().to_vec();
152 result.push(env_pair);
153 environ = environ.offset(1);
158 pub fn split_paths(unparsed: &[u8]) -> Vec<Path> {
159 unparsed.split(|b| *b == b':').map(Path::new).collect()
162 pub fn join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static str> {
163 let mut joined = Vec::new();
166 for (i, path) in paths.iter().map(|p| p.container_as_bytes()).enumerate() {
167 if i > 0 { joined.push(sep) }
168 if path.contains(&sep) { return Err("path segment contains separator `:`") }
169 joined.push_all(path);
175 #[cfg(target_os = "freebsd")]
176 pub fn load_self() -> Option<Vec<u8>> {
178 use libc::funcs::bsd44::*;
179 use libc::consts::os::extra::*;
180 let mut mib = vec![CTL_KERN as c_int,
182 KERN_PROC_PATHNAME as c_int,
184 let mut sz: libc::size_t = 0;
185 let err = sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint,
186 ptr::null_mut(), &mut sz, ptr::null_mut(),
188 if err != 0 { return None; }
189 if sz == 0 { return None; }
190 let mut v: Vec<u8> = Vec::with_capacity(sz as uint);
191 let err = sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint,
192 v.as_mut_ptr() as *mut libc::c_void, &mut sz,
193 ptr::null_mut(), 0u as libc::size_t);
194 if err != 0 { return None; }
195 if sz == 0 { return None; }
196 v.set_len(sz as uint - 1); // chop off trailing NUL
201 #[cfg(target_os = "dragonfly")]
202 pub fn load_self() -> Option<Vec<u8>> {
205 match io::fs::readlink(&Path::new("/proc/curproc/file")) {
206 Ok(path) => Some(path.into_vec()),
211 #[cfg(any(target_os = "linux", target_os = "android"))]
212 pub fn load_self() -> Option<Vec<u8>> {
215 match io::fs::readlink(&Path::new("/proc/self/exe")) {
216 Ok(path) => Some(path.into_vec()),
221 #[cfg(any(target_os = "macos", target_os = "ios"))]
222 pub fn load_self() -> Option<Vec<u8>> {
224 use libc::funcs::extra::_NSGetExecutablePath;
226 _NSGetExecutablePath(ptr::null_mut(), &mut sz);
227 if sz == 0 { return None; }
228 let mut v: Vec<u8> = Vec::with_capacity(sz as uint);
229 let err = _NSGetExecutablePath(v.as_mut_ptr() as *mut i8, &mut sz);
230 if err != 0 { return None; }
231 v.set_len(sz as uint - 1); // chop off trailing NUL
236 pub fn chdir(p: &Path) -> IoResult<()> {
239 match libc::chdir(buf) == (0 as c_int) {
241 false => Err(IoError::last_error()),
247 pub fn page_size() -> uint {
249 libc::sysconf(libc::_SC_PAGESIZE) as uint