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