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
15 use error::{FromError, Error};
16 use ffi::{self, CString};
18 use io::{IoError, IoResult};
19 use libc::{self, c_int, c_char, c_void};
22 use path::{BytesContainer};
25 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 let p = p as *const _;
112 str::from_utf8(ffi::c_str_to_bytes(&p)).unwrap().to_string()
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> {
126 let mut buf = [0 as c_char; BUF_BYTES];
128 if libc::getcwd(buf.as_mut_ptr(), buf.len() as libc::size_t).is_null() {
129 Err(IoError::last_error())
131 Ok(Path::new(ffi::c_str_to_bytes(&buf.as_ptr())))
136 pub unsafe fn get_env_pairs() -> Vec<Vec<u8>> {
138 fn rust_env_pairs() -> *const *const c_char;
140 let mut environ = rust_env_pairs();
141 if environ as uint == 0 {
142 panic!("os::env() failure getting env string from OS: {}",
143 os::last_os_error());
145 let mut result = Vec::new();
146 while *environ != ptr::null() {
147 let env_pair = ffi::c_str_to_bytes(&*environ).to_vec();
148 result.push(env_pair);
149 environ = environ.offset(1);
154 pub fn split_paths(unparsed: &[u8]) -> Vec<Path> {
155 unparsed.split(|b| *b == b':').map(Path::new).collect()
158 pub fn join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static str> {
159 let mut joined = Vec::new();
162 for (i, path) in paths.iter().map(|p| p.container_as_bytes()).enumerate() {
163 if i > 0 { joined.push(sep) }
164 if path.contains(&sep) { return Err("path segment contains separator `:`") }
165 joined.push_all(path);
171 #[cfg(target_os = "freebsd")]
172 pub fn load_self() -> Option<Vec<u8>> {
174 use libc::funcs::bsd44::*;
175 use libc::consts::os::extra::*;
176 let mut mib = vec![CTL_KERN as c_int,
178 KERN_PROC_PATHNAME as c_int,
180 let mut sz: libc::size_t = 0;
181 let err = sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint,
182 ptr::null_mut(), &mut sz, ptr::null_mut(),
184 if err != 0 { return None; }
185 if sz == 0 { return None; }
186 let mut v: Vec<u8> = Vec::with_capacity(sz as uint);
187 let err = sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint,
188 v.as_mut_ptr() as *mut libc::c_void, &mut sz,
189 ptr::null_mut(), 0u as libc::size_t);
190 if err != 0 { return None; }
191 if sz == 0 { return None; }
192 v.set_len(sz as uint - 1); // chop off trailing NUL
197 #[cfg(target_os = "dragonfly")]
198 pub fn load_self() -> Option<Vec<u8>> {
201 match io::fs::readlink(&Path::new("/proc/curproc/file")) {
202 Ok(path) => Some(path.into_vec()),
207 #[cfg(any(target_os = "linux", target_os = "android"))]
208 pub fn load_self() -> Option<Vec<u8>> {
211 match io::fs::readlink(&Path::new("/proc/self/exe")) {
212 Ok(path) => Some(path.into_vec()),
217 #[cfg(any(target_os = "macos", target_os = "ios"))]
218 pub fn load_self() -> Option<Vec<u8>> {
220 use libc::funcs::extra::_NSGetExecutablePath;
222 _NSGetExecutablePath(ptr::null_mut(), &mut sz);
223 if sz == 0 { return None; }
224 let mut v: Vec<u8> = Vec::with_capacity(sz as uint);
225 let err = _NSGetExecutablePath(v.as_mut_ptr() as *mut i8, &mut sz);
226 if err != 0 { return None; }
227 v.set_len(sz as uint - 1); // chop off trailing NUL
232 pub fn chdir(p: &Path) -> IoResult<()> {
233 let p = CString::from_slice(p.as_vec());
235 match libc::chdir(p.as_ptr()) == (0 as c_int) {
237 false => Err(IoError::last_error()),
242 pub fn page_size() -> uint {
244 libc::sysconf(libc::_SC_PAGESIZE) as uint