]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys/unix/os.rs
rollup merge of #20642: michaelwoerister/sane-source-locations-pt1
[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 error::{FromError, Error};
16 use ffi::{self, CString};
17 use fmt;
18 use io::{IoError, IoResult};
19 use libc::{self, c_int, c_char, c_void};
20 use os::TMPBUF_SZ;
21 use os;
22 use path::{BytesContainer};
23 use ptr;
24 use str;
25 use sys::fs::FileDesc;
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         let p = p as *const _;
112         str::from_utf8(ffi::c_str_to_bytes(&p)).unwrap().to_string()
113     }
114 }
115
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)))
120     } else {
121         Err(super::last_error())
122     }
123 }
124
125 pub fn getcwd() -> IoResult<Path> {
126     let mut buf = [0 as c_char; BUF_BYTES];
127     unsafe {
128         if libc::getcwd(buf.as_mut_ptr(), buf.len() as libc::size_t).is_null() {
129             Err(IoError::last_error())
130         } else {
131             Ok(Path::new(ffi::c_str_to_bytes(&buf.as_ptr())))
132         }
133     }
134 }
135
136 pub unsafe fn get_env_pairs() -> Vec<Vec<u8>> {
137     extern {
138         fn rust_env_pairs() -> *const *const c_char;
139     }
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());
144     }
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);
150     }
151     result
152 }
153
154 pub fn split_paths(unparsed: &[u8]) -> Vec<Path> {
155     unparsed.split(|b| *b == b':').map(Path::new).collect()
156 }
157
158 pub fn join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static str> {
159     let mut joined = Vec::new();
160     let sep = b':';
161
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);
166     }
167
168     Ok(joined)
169 }
170
171 #[cfg(target_os = "freebsd")]
172 pub fn load_self() -> Option<Vec<u8>> {
173     unsafe {
174         use libc::funcs::bsd44::*;
175         use libc::consts::os::extra::*;
176         let mut mib = vec![CTL_KERN as c_int,
177                            KERN_PROC as c_int,
178                            KERN_PROC_PATHNAME as c_int,
179                            -1 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(),
183                          0u as libc::size_t);
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
193         Some(v)
194     }
195 }
196
197 #[cfg(target_os = "dragonfly")]
198 pub fn load_self() -> Option<Vec<u8>> {
199     use std::io;
200
201     match io::fs::readlink(&Path::new("/proc/curproc/file")) {
202         Ok(path) => Some(path.into_vec()),
203         Err(..) => None
204     }
205 }
206
207 #[cfg(any(target_os = "linux", target_os = "android"))]
208 pub fn load_self() -> Option<Vec<u8>> {
209     use std::io;
210
211     match io::fs::readlink(&Path::new("/proc/self/exe")) {
212         Ok(path) => Some(path.into_vec()),
213         Err(..) => None
214     }
215 }
216
217 #[cfg(any(target_os = "macos", target_os = "ios"))]
218 pub fn load_self() -> Option<Vec<u8>> {
219     unsafe {
220         use libc::funcs::extra::_NSGetExecutablePath;
221         let mut sz: u32 = 0;
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
228         Some(v)
229     }
230 }
231
232 pub fn chdir(p: &Path) -> IoResult<()> {
233     let p = CString::from_slice(p.as_vec());
234     unsafe {
235         match libc::chdir(p.as_ptr()) == (0 as c_int) {
236             true => Ok(()),
237             false => Err(IoError::last_error()),
238         }
239     }
240 }
241
242 pub fn page_size() -> uint {
243     unsafe {
244         libc::sysconf(libc::_SC_PAGESIZE) as uint
245     }
246 }