]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys/unix/os.rs
Merge pull request #20510 from tshepang/patch-6
[rust.git] / src / libstd / sys / unix / os.rs
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.
4 //
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.
10
11 //! Implementation of `std::os` functionality for unix systems
12
13 use prelude::v1::*;
14
15 use c_str::ToCStr;
16 use error::{FromError, Error};
17 use fmt;
18 use io::{IoError, IoResult};
19 use libc::{self, c_int, c_char, c_void};
20 use os;
21 use path::{BytesContainer};
22 use ptr;
23 use sys::fs::FileDesc;
24
25 use os::TMPBUF_SZ;
26
27 const BUF_BYTES : uint = 2048u;
28
29 /// Returns the platform-specific value of errno
30 pub fn errno() -> int {
31     #[cfg(any(target_os = "macos",
32               target_os = "ios",
33               target_os = "freebsd"))]
34     fn errno_location() -> *const c_int {
35         extern {
36             fn __error() -> *const c_int;
37         }
38         unsafe {
39             __error()
40         }
41     }
42
43     #[cfg(target_os = "dragonfly")]
44     fn errno_location() -> *const c_int {
45         extern {
46             fn __dfly_error() -> *const c_int;
47         }
48         unsafe {
49             __dfly_error()
50         }
51     }
52
53     #[cfg(any(target_os = "linux", target_os = "android"))]
54     fn errno_location() -> *const c_int {
55         extern {
56             fn __errno_location() -> *const c_int;
57         }
58         unsafe {
59             __errno_location()
60         }
61     }
62
63     unsafe {
64         (*errno_location()) as int
65     }
66 }
67
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",
71               target_os = "ios",
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)
76                   -> c_int {
77         extern {
78             fn strerror_r(errnum: c_int, buf: *mut c_char,
79                           buflen: libc::size_t) -> c_int;
80         }
81         unsafe {
82             strerror_r(errnum, buf, buflen)
83         }
84     }
85
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 {
92         extern {
93             fn __xpg_strerror_r(errnum: c_int,
94                                 buf: *mut c_char,
95                                 buflen: libc::size_t)
96                                 -> c_int;
97         }
98         unsafe {
99             __xpg_strerror_r(errnum, buf, buflen)
100         }
101     }
102
103     let mut buf = [0 as c_char; TMPBUF_SZ];
104
105     let p = buf.as_mut_ptr();
106     unsafe {
107         if strerror_r(errno as c_int, p, buf.len() as libc::size_t) < 0 {
108             panic!("strerror_r failure");
109         }
110
111         String::from_raw_buf(p as *const u8)
112     }
113 }
114
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)))
119     } else {
120         Err(super::last_error())
121     }
122 }
123
124 pub fn getcwd() -> IoResult<Path> {
125     use c_str::CString;
126
127     let mut buf = [0 as c_char; BUF_BYTES];
128     unsafe {
129         if libc::getcwd(buf.as_mut_ptr(), buf.len() as libc::size_t).is_null() {
130             Err(IoError::last_error())
131         } else {
132             Ok(Path::new(CString::new(buf.as_ptr(), false)))
133         }
134     }
135 }
136
137 pub unsafe fn get_env_pairs() -> Vec<Vec<u8>> {
138     use c_str::CString;
139
140     extern {
141         fn rust_env_pairs() -> *const *const c_char;
142     }
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());
147     }
148     let mut result = Vec::new();
149     while *environ != 0 as *const _ {
150         let env_pair =
151             CString::new(*environ, false).as_bytes_no_nul().to_vec();
152         result.push(env_pair);
153         environ = environ.offset(1);
154     }
155     result
156 }
157
158 pub fn split_paths(unparsed: &[u8]) -> Vec<Path> {
159     unparsed.split(|b| *b == b':').map(Path::new).collect()
160 }
161
162 pub fn join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static str> {
163     let mut joined = Vec::new();
164     let sep = b':';
165
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);
170     }
171
172     Ok(joined)
173 }
174
175 #[cfg(target_os = "freebsd")]
176 pub fn load_self() -> Option<Vec<u8>> {
177     unsafe {
178         use libc::funcs::bsd44::*;
179         use libc::consts::os::extra::*;
180         let mut mib = vec![CTL_KERN as c_int,
181                            KERN_PROC as c_int,
182                            KERN_PROC_PATHNAME as c_int,
183                            -1 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(),
187                          0u as libc::size_t);
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
197         Some(v)
198     }
199 }
200
201 #[cfg(target_os = "dragonfly")]
202 pub fn load_self() -> Option<Vec<u8>> {
203     use std::io;
204
205     match io::fs::readlink(&Path::new("/proc/curproc/file")) {
206         Ok(path) => Some(path.into_vec()),
207         Err(..) => None
208     }
209 }
210
211 #[cfg(any(target_os = "linux", target_os = "android"))]
212 pub fn load_self() -> Option<Vec<u8>> {
213     use std::io;
214
215     match io::fs::readlink(&Path::new("/proc/self/exe")) {
216         Ok(path) => Some(path.into_vec()),
217         Err(..) => None
218     }
219 }
220
221 #[cfg(any(target_os = "macos", target_os = "ios"))]
222 pub fn load_self() -> Option<Vec<u8>> {
223     unsafe {
224         use libc::funcs::extra::_NSGetExecutablePath;
225         let mut sz: u32 = 0;
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
232         Some(v)
233     }
234 }
235
236 pub fn chdir(p: &Path) -> IoResult<()> {
237     p.with_c_str(|buf| {
238         unsafe {
239             match libc::chdir(buf) == (0 as c_int) {
240                 true => Ok(()),
241                 false => Err(IoError::last_error()),
242             }
243         }
244     })
245 }
246
247 pub fn page_size() -> uint {
248     unsafe {
249         libc::sysconf(libc::_SC_PAGESIZE) as uint
250     }
251 }