]>
Commit | Line | Data |
---|---|---|
85aaf69f | 1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT |
1a4d82fc JJ |
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 | ||
c34b1796 AL |
13 | #![allow(unused_imports)] // lots of cfg code here |
14 | ||
1a4d82fc | 15 | use prelude::v1::*; |
c34b1796 | 16 | use os::unix::prelude::*; |
1a4d82fc | 17 | |
85aaf69f | 18 | use error::Error as StdError; |
c34b1796 | 19 | use ffi::{CString, CStr, OsString, OsStr}; |
1a4d82fc | 20 | use fmt; |
c34b1796 | 21 | use io; |
85aaf69f | 22 | use iter; |
1a4d82fc | 23 | use libc::{self, c_int, c_char, c_void}; |
85aaf69f | 24 | use mem; |
c34b1796 | 25 | #[allow(deprecated)] use old_io::{IoError, IoResult}; |
1a4d82fc | 26 | use ptr; |
c34b1796 | 27 | use path::{self, PathBuf}; |
85aaf69f | 28 | use slice; |
1a4d82fc | 29 | use str; |
85aaf69f SL |
30 | use sys::c; |
31 | use sys::fd; | |
1a4d82fc | 32 | use sys::fs::FileDesc; |
85aaf69f | 33 | use vec; |
1a4d82fc | 34 | |
85aaf69f SL |
35 | const BUF_BYTES: usize = 2048; |
36 | const TMPBUF_SZ: usize = 128; | |
1a4d82fc | 37 | |
c34b1796 AL |
38 | fn bytes2path(b: &[u8]) -> PathBuf { |
39 | PathBuf::from(<OsStr as OsStrExt>::from_bytes(b)) | |
40 | } | |
41 | ||
42 | fn os2path(os: OsString) -> PathBuf { | |
43 | bytes2path(os.as_bytes()) | |
44 | } | |
45 | ||
1a4d82fc | 46 | /// Returns the platform-specific value of errno |
85aaf69f | 47 | pub fn errno() -> i32 { |
1a4d82fc JJ |
48 | #[cfg(any(target_os = "macos", |
49 | target_os = "ios", | |
50 | target_os = "freebsd"))] | |
85aaf69f SL |
51 | unsafe fn errno_location() -> *const c_int { |
52 | extern { fn __error() -> *const c_int; } | |
53 | __error() | |
1a4d82fc JJ |
54 | } |
55 | ||
c34b1796 AL |
56 | #[cfg(target_os = "bitrig")] |
57 | fn errno_location() -> *const c_int { | |
58 | extern { | |
59 | fn __errno() -> *const c_int; | |
60 | } | |
61 | unsafe { | |
62 | __errno() | |
63 | } | |
64 | } | |
65 | ||
1a4d82fc | 66 | #[cfg(target_os = "dragonfly")] |
85aaf69f SL |
67 | unsafe fn errno_location() -> *const c_int { |
68 | extern { fn __dfly_error() -> *const c_int; } | |
69 | __dfly_error() | |
70 | } | |
71 | ||
72 | #[cfg(target_os = "openbsd")] | |
73 | unsafe fn errno_location() -> *const c_int { | |
74 | extern { fn __errno() -> *const c_int; } | |
75 | __errno() | |
1a4d82fc JJ |
76 | } |
77 | ||
78 | #[cfg(any(target_os = "linux", target_os = "android"))] | |
85aaf69f SL |
79 | unsafe fn errno_location() -> *const c_int { |
80 | extern { fn __errno_location() -> *const c_int; } | |
81 | __errno_location() | |
1a4d82fc JJ |
82 | } |
83 | ||
84 | unsafe { | |
85aaf69f | 85 | (*errno_location()) as i32 |
1a4d82fc JJ |
86 | } |
87 | } | |
88 | ||
89 | /// Get a detailed string description for the given error number | |
90 | pub fn error_string(errno: i32) -> String { | |
1a4d82fc | 91 | #[cfg(target_os = "linux")] |
85aaf69f SL |
92 | extern { |
93 | #[link_name = "__xpg_strerror_r"] | |
94 | fn strerror_r(errnum: c_int, buf: *mut c_char, | |
95 | buflen: libc::size_t) -> c_int; | |
96 | } | |
97 | #[cfg(not(target_os = "linux"))] | |
98 | extern { | |
99 | fn strerror_r(errnum: c_int, buf: *mut c_char, | |
100 | buflen: libc::size_t) -> c_int; | |
1a4d82fc JJ |
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 _; | |
85aaf69f | 112 | str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_string() |
1a4d82fc JJ |
113 | } |
114 | } | |
115 | ||
c34b1796 | 116 | pub fn getcwd() -> io::Result<PathBuf> { |
1a4d82fc JJ |
117 | let mut buf = [0 as c_char; BUF_BYTES]; |
118 | unsafe { | |
119 | if libc::getcwd(buf.as_mut_ptr(), buf.len() as libc::size_t).is_null() { | |
c34b1796 | 120 | Err(io::Error::last_os_error()) |
1a4d82fc | 121 | } else { |
c34b1796 | 122 | Ok(bytes2path(CStr::from_ptr(buf.as_ptr()).to_bytes())) |
1a4d82fc JJ |
123 | } |
124 | } | |
125 | } | |
126 | ||
c34b1796 AL |
127 | pub fn chdir(p: &path::Path) -> io::Result<()> { |
128 | let p: &OsStr = p.as_ref(); | |
129 | let p = try!(CString::new(p.as_bytes())); | |
85aaf69f SL |
130 | unsafe { |
131 | match libc::chdir(p.as_ptr()) == (0 as c_int) { | |
132 | true => Ok(()), | |
c34b1796 | 133 | false => Err(io::Error::last_os_error()), |
85aaf69f | 134 | } |
1a4d82fc | 135 | } |
85aaf69f SL |
136 | } |
137 | ||
138 | pub struct SplitPaths<'a> { | |
139 | iter: iter::Map<slice::Split<'a, u8, fn(&u8) -> bool>, | |
c34b1796 | 140 | fn(&'a [u8]) -> PathBuf>, |
85aaf69f SL |
141 | } |
142 | ||
143 | pub fn split_paths<'a>(unparsed: &'a OsStr) -> SplitPaths<'a> { | |
144 | fn is_colon(b: &u8) -> bool { *b == b':' } | |
145 | let unparsed = unparsed.as_bytes(); | |
146 | SplitPaths { | |
147 | iter: unparsed.split(is_colon as fn(&u8) -> bool) | |
c34b1796 | 148 | .map(bytes2path as fn(&'a [u8]) -> PathBuf) |
1a4d82fc | 149 | } |
1a4d82fc JJ |
150 | } |
151 | ||
85aaf69f | 152 | impl<'a> Iterator for SplitPaths<'a> { |
c34b1796 AL |
153 | type Item = PathBuf; |
154 | fn next(&mut self) -> Option<PathBuf> { self.iter.next() } | |
85aaf69f | 155 | fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() } |
1a4d82fc JJ |
156 | } |
157 | ||
85aaf69f SL |
158 | #[derive(Debug)] |
159 | pub struct JoinPathsError; | |
160 | ||
161 | pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError> | |
c34b1796 | 162 | where I: Iterator<Item=T>, T: AsRef<OsStr> |
85aaf69f | 163 | { |
1a4d82fc JJ |
164 | let mut joined = Vec::new(); |
165 | let sep = b':'; | |
166 | ||
85aaf69f | 167 | for (i, path) in paths.enumerate() { |
c34b1796 | 168 | let path = path.as_ref().as_bytes(); |
1a4d82fc | 169 | if i > 0 { joined.push(sep) } |
85aaf69f SL |
170 | if path.contains(&sep) { |
171 | return Err(JoinPathsError) | |
172 | } | |
1a4d82fc JJ |
173 | joined.push_all(path); |
174 | } | |
85aaf69f SL |
175 | Ok(OsStringExt::from_vec(joined)) |
176 | } | |
1a4d82fc | 177 | |
85aaf69f SL |
178 | impl fmt::Display for JoinPathsError { |
179 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
180 | "path segment contains separator `:`".fmt(f) | |
181 | } | |
182 | } | |
183 | ||
184 | impl StdError for JoinPathsError { | |
185 | fn description(&self) -> &str { "failed to join paths" } | |
1a4d82fc JJ |
186 | } |
187 | ||
188 | #[cfg(target_os = "freebsd")] | |
c34b1796 | 189 | pub fn current_exe() -> io::Result<PathBuf> { |
1a4d82fc JJ |
190 | unsafe { |
191 | use libc::funcs::bsd44::*; | |
192 | use libc::consts::os::extra::*; | |
193 | let mut mib = vec![CTL_KERN as c_int, | |
194 | KERN_PROC as c_int, | |
195 | KERN_PROC_PATHNAME as c_int, | |
196 | -1 as c_int]; | |
197 | let mut sz: libc::size_t = 0; | |
198 | let err = sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint, | |
199 | ptr::null_mut(), &mut sz, ptr::null_mut(), | |
85aaf69f | 200 | 0 as libc::size_t); |
c34b1796 AL |
201 | if err != 0 { return Err(io::Error::last_os_error()); } |
202 | if sz == 0 { return Err(io::Error::last_os_error()); } | |
203 | let mut v: Vec<u8> = Vec::with_capacity(sz as usize); | |
1a4d82fc JJ |
204 | let err = sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint, |
205 | v.as_mut_ptr() as *mut libc::c_void, &mut sz, | |
85aaf69f | 206 | ptr::null_mut(), 0 as libc::size_t); |
c34b1796 AL |
207 | if err != 0 { return Err(io::Error::last_os_error()); } |
208 | if sz == 0 { return Err(io::Error::last_os_error()); } | |
209 | v.set_len(sz as usize - 1); // chop off trailing NUL | |
210 | Ok(PathBuf::from(OsString::from_vec(v))) | |
1a4d82fc JJ |
211 | } |
212 | } | |
213 | ||
214 | #[cfg(target_os = "dragonfly")] | |
c34b1796 AL |
215 | pub fn current_exe() -> io::Result<PathBuf> { |
216 | ::fs::read_link("/proc/curproc/file") | |
85aaf69f SL |
217 | } |
218 | ||
c34b1796 AL |
219 | #[cfg(any(target_os = "bitrig", target_os = "openbsd"))] |
220 | pub fn current_exe() -> io::Result<PathBuf> { | |
85aaf69f | 221 | use sync::{StaticMutex, MUTEX_INIT}; |
85aaf69f SL |
222 | static LOCK: StaticMutex = MUTEX_INIT; |
223 | ||
224 | extern { | |
225 | fn rust_current_exe() -> *const c_char; | |
1a4d82fc | 226 | } |
1a4d82fc | 227 | |
85aaf69f | 228 | let _guard = LOCK.lock(); |
1a4d82fc | 229 | |
85aaf69f SL |
230 | unsafe { |
231 | let v = rust_current_exe(); | |
232 | if v.is_null() { | |
c34b1796 | 233 | Err(io::Error::last_os_error()) |
85aaf69f | 234 | } else { |
c34b1796 AL |
235 | let vec = CStr::from_ptr(v).to_bytes().to_vec(); |
236 | Ok(PathBuf::from(OsString::from_vec(vec))) | |
85aaf69f | 237 | } |
1a4d82fc JJ |
238 | } |
239 | } | |
240 | ||
85aaf69f | 241 | #[cfg(any(target_os = "linux", target_os = "android"))] |
c34b1796 AL |
242 | pub fn current_exe() -> io::Result<PathBuf> { |
243 | ::fs::read_link("/proc/self/exe") | |
85aaf69f SL |
244 | } |
245 | ||
1a4d82fc | 246 | #[cfg(any(target_os = "macos", target_os = "ios"))] |
c34b1796 | 247 | pub fn current_exe() -> io::Result<PathBuf> { |
1a4d82fc JJ |
248 | unsafe { |
249 | use libc::funcs::extra::_NSGetExecutablePath; | |
250 | let mut sz: u32 = 0; | |
251 | _NSGetExecutablePath(ptr::null_mut(), &mut sz); | |
c34b1796 AL |
252 | if sz == 0 { return Err(io::Error::last_os_error()); } |
253 | let mut v: Vec<u8> = Vec::with_capacity(sz as usize); | |
1a4d82fc | 254 | let err = _NSGetExecutablePath(v.as_mut_ptr() as *mut i8, &mut sz); |
c34b1796 AL |
255 | if err != 0 { return Err(io::Error::last_os_error()); } |
256 | v.set_len(sz as usize - 1); // chop off trailing NUL | |
257 | Ok(PathBuf::from(OsString::from_vec(v))) | |
1a4d82fc JJ |
258 | } |
259 | } | |
260 | ||
85aaf69f SL |
261 | pub struct Args { |
262 | iter: vec::IntoIter<OsString>, | |
263 | _dont_send_or_sync_me: *mut (), | |
264 | } | |
265 | ||
266 | impl Iterator for Args { | |
267 | type Item = OsString; | |
268 | fn next(&mut self) -> Option<OsString> { self.iter.next() } | |
269 | fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() } | |
270 | } | |
271 | ||
272 | impl ExactSizeIterator for Args { | |
273 | fn len(&self) -> usize { self.iter.len() } | |
274 | } | |
275 | ||
276 | /// Returns the command line arguments | |
277 | /// | |
278 | /// Returns a list of the command line arguments. | |
279 | #[cfg(target_os = "macos")] | |
280 | pub fn args() -> Args { | |
281 | extern { | |
282 | // These functions are in crt_externs.h. | |
283 | fn _NSGetArgc() -> *mut c_int; | |
284 | fn _NSGetArgv() -> *mut *mut *mut c_char; | |
285 | } | |
286 | ||
287 | let vec = unsafe { | |
288 | let (argc, argv) = (*_NSGetArgc() as isize, | |
289 | *_NSGetArgv() as *const *const c_char); | |
c34b1796 | 290 | (0.. argc as isize).map(|i| { |
85aaf69f SL |
291 | let bytes = CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec(); |
292 | OsStringExt::from_vec(bytes) | |
293 | }).collect::<Vec<_>>() | |
294 | }; | |
295 | Args { | |
296 | iter: vec.into_iter(), | |
297 | _dont_send_or_sync_me: 0 as *mut (), | |
298 | } | |
299 | } | |
300 | ||
301 | // As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs | |
302 | // and use underscores in their names - they're most probably | |
303 | // are considered private and therefore should be avoided | |
304 | // Here is another way to get arguments using Objective C | |
305 | // runtime | |
306 | // | |
307 | // In general it looks like: | |
308 | // res = Vec::new() | |
309 | // let args = [[NSProcessInfo processInfo] arguments] | |
c34b1796 | 310 | // for i in (0..[args count]) |
85aaf69f SL |
311 | // res.push([args objectAtIndex:i]) |
312 | // res | |
313 | #[cfg(target_os = "ios")] | |
314 | pub fn args() -> Args { | |
85aaf69f SL |
315 | use mem; |
316 | ||
317 | #[link(name = "objc")] | |
318 | extern { | |
319 | fn sel_registerName(name: *const libc::c_uchar) -> Sel; | |
320 | fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId; | |
321 | fn objc_getClass(class_name: *const libc::c_uchar) -> NsId; | |
322 | } | |
323 | ||
324 | #[link(name = "Foundation", kind = "framework")] | |
325 | extern {} | |
326 | ||
327 | type Sel = *const libc::c_void; | |
328 | type NsId = *const libc::c_void; | |
329 | ||
330 | let mut res = Vec::new(); | |
331 | ||
1a4d82fc | 332 | unsafe { |
85aaf69f SL |
333 | let process_info_sel = sel_registerName("processInfo\0".as_ptr()); |
334 | let arguments_sel = sel_registerName("arguments\0".as_ptr()); | |
335 | let utf8_sel = sel_registerName("UTF8String\0".as_ptr()); | |
336 | let count_sel = sel_registerName("count\0".as_ptr()); | |
337 | let object_at_sel = sel_registerName("objectAtIndex:\0".as_ptr()); | |
338 | ||
339 | let klass = objc_getClass("NSProcessInfo\0".as_ptr()); | |
340 | let info = objc_msgSend(klass, process_info_sel); | |
341 | let args = objc_msgSend(info, arguments_sel); | |
342 | ||
c34b1796 AL |
343 | let cnt: usize = mem::transmute(objc_msgSend(args, count_sel)); |
344 | for i in (0..cnt) { | |
85aaf69f SL |
345 | let tmp = objc_msgSend(args, object_at_sel, i); |
346 | let utf_c_str: *const libc::c_char = | |
347 | mem::transmute(objc_msgSend(tmp, utf8_sel)); | |
348 | let bytes = CStr::from_ptr(utf_c_str).to_bytes(); | |
c34b1796 | 349 | res.push(OsString::from(str::from_utf8(bytes).unwrap())) |
1a4d82fc JJ |
350 | } |
351 | } | |
85aaf69f SL |
352 | |
353 | Args { iter: res.into_iter(), _dont_send_or_sync_me: 0 as *mut _ } | |
354 | } | |
355 | ||
356 | #[cfg(any(target_os = "linux", | |
357 | target_os = "android", | |
358 | target_os = "freebsd", | |
359 | target_os = "dragonfly", | |
c34b1796 | 360 | target_os = "bitrig", |
85aaf69f SL |
361 | target_os = "openbsd"))] |
362 | pub fn args() -> Args { | |
363 | use rt; | |
364 | let bytes = rt::args::clone().unwrap_or(Vec::new()); | |
365 | let v: Vec<OsString> = bytes.into_iter().map(|v| { | |
366 | OsStringExt::from_vec(v) | |
367 | }).collect(); | |
368 | Args { iter: v.into_iter(), _dont_send_or_sync_me: 0 as *mut _ } | |
369 | } | |
370 | ||
371 | pub struct Env { | |
372 | iter: vec::IntoIter<(OsString, OsString)>, | |
373 | _dont_send_or_sync_me: *mut (), | |
374 | } | |
375 | ||
376 | impl Iterator for Env { | |
377 | type Item = (OsString, OsString); | |
378 | fn next(&mut self) -> Option<(OsString, OsString)> { self.iter.next() } | |
379 | fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() } | |
380 | } | |
381 | ||
382 | #[cfg(target_os = "macos")] | |
383 | pub unsafe fn environ() -> *mut *const *const c_char { | |
384 | extern { fn _NSGetEnviron() -> *mut *const *const c_char; } | |
385 | _NSGetEnviron() | |
386 | } | |
387 | ||
388 | #[cfg(not(target_os = "macos"))] | |
389 | pub unsafe fn environ() -> *mut *const *const c_char { | |
390 | extern { static mut environ: *const *const c_char; } | |
391 | &mut environ | |
392 | } | |
393 | ||
394 | /// Returns a vector of (variable, value) byte-vector pairs for all the | |
395 | /// environment variables of the current process. | |
396 | pub fn env() -> Env { | |
397 | return unsafe { | |
398 | let mut environ = *environ(); | |
399 | if environ as usize == 0 { | |
400 | panic!("os::env() failure getting env string from OS: {}", | |
c34b1796 | 401 | io::Error::last_os_error()); |
85aaf69f SL |
402 | } |
403 | let mut result = Vec::new(); | |
404 | while *environ != ptr::null() { | |
405 | result.push(parse(CStr::from_ptr(*environ).to_bytes())); | |
406 | environ = environ.offset(1); | |
407 | } | |
408 | Env { iter: result.into_iter(), _dont_send_or_sync_me: 0 as *mut _ } | |
409 | }; | |
410 | ||
411 | fn parse(input: &[u8]) -> (OsString, OsString) { | |
c34b1796 | 412 | let mut it = input.splitn(2, |b| *b == b'='); |
85aaf69f SL |
413 | let key = it.next().unwrap().to_vec(); |
414 | let default: &[u8] = &[]; | |
415 | let val = it.next().unwrap_or(default).to_vec(); | |
416 | (OsStringExt::from_vec(key), OsStringExt::from_vec(val)) | |
417 | } | |
1a4d82fc JJ |
418 | } |
419 | ||
85aaf69f | 420 | pub fn getenv(k: &OsStr) -> Option<OsString> { |
1a4d82fc | 421 | unsafe { |
85aaf69f SL |
422 | let s = k.to_cstring().unwrap(); |
423 | let s = libc::getenv(s.as_ptr()) as *const _; | |
424 | if s.is_null() { | |
425 | None | |
426 | } else { | |
427 | Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec())) | |
428 | } | |
429 | } | |
430 | } | |
431 | ||
432 | pub fn setenv(k: &OsStr, v: &OsStr) { | |
433 | unsafe { | |
434 | let k = k.to_cstring().unwrap(); | |
435 | let v = v.to_cstring().unwrap(); | |
436 | if libc::funcs::posix01::unistd::setenv(k.as_ptr(), v.as_ptr(), 1) != 0 { | |
c34b1796 | 437 | panic!("failed setenv: {}", io::Error::last_os_error()); |
85aaf69f SL |
438 | } |
439 | } | |
440 | } | |
441 | ||
442 | pub fn unsetenv(n: &OsStr) { | |
443 | unsafe { | |
444 | let nbuf = n.to_cstring().unwrap(); | |
445 | if libc::funcs::posix01::unistd::unsetenv(nbuf.as_ptr()) != 0 { | |
c34b1796 | 446 | panic!("failed unsetenv: {}", io::Error::last_os_error()); |
85aaf69f SL |
447 | } |
448 | } | |
449 | } | |
450 | ||
c34b1796 | 451 | #[allow(deprecated)] |
85aaf69f SL |
452 | pub unsafe fn pipe() -> IoResult<(FileDesc, FileDesc)> { |
453 | let mut fds = [0; 2]; | |
454 | if libc::pipe(fds.as_mut_ptr()) == 0 { | |
455 | Ok((FileDesc::new(fds[0], true), FileDesc::new(fds[1], true))) | |
456 | } else { | |
457 | Err(IoError::last_error()) | |
458 | } | |
459 | } | |
460 | ||
461 | pub fn page_size() -> usize { | |
462 | unsafe { | |
463 | libc::sysconf(libc::_SC_PAGESIZE) as usize | |
464 | } | |
465 | } | |
466 | ||
c34b1796 AL |
467 | pub fn temp_dir() -> PathBuf { |
468 | getenv("TMPDIR".as_ref()).map(os2path).unwrap_or_else(|| { | |
85aaf69f | 469 | if cfg!(target_os = "android") { |
c34b1796 | 470 | PathBuf::from("/data/local/tmp") |
85aaf69f | 471 | } else { |
c34b1796 | 472 | PathBuf::from("/tmp") |
85aaf69f SL |
473 | } |
474 | }) | |
475 | } | |
476 | ||
c34b1796 AL |
477 | pub fn home_dir() -> Option<PathBuf> { |
478 | return getenv("HOME".as_ref()).or_else(|| unsafe { | |
85aaf69f | 479 | fallback() |
c34b1796 | 480 | }).map(os2path); |
85aaf69f SL |
481 | |
482 | #[cfg(any(target_os = "android", | |
483 | target_os = "ios"))] | |
484 | unsafe fn fallback() -> Option<OsString> { None } | |
485 | #[cfg(not(any(target_os = "android", | |
486 | target_os = "ios")))] | |
487 | unsafe fn fallback() -> Option<OsString> { | |
c34b1796 | 488 | let amt = match libc::sysconf(c::_SC_GETPW_R_SIZE_MAX) { |
85aaf69f SL |
489 | n if n < 0 => 512 as usize, |
490 | n => n as usize, | |
491 | }; | |
492 | let me = libc::getuid(); | |
493 | loop { | |
494 | let mut buf = Vec::with_capacity(amt); | |
495 | let mut passwd: c::passwd = mem::zeroed(); | |
496 | let mut result = 0 as *mut _; | |
497 | match c::getpwuid_r(me, &mut passwd, buf.as_mut_ptr(), | |
498 | buf.capacity() as libc::size_t, | |
499 | &mut result) { | |
500 | 0 if !result.is_null() => {} | |
501 | _ => return None | |
502 | } | |
503 | let ptr = passwd.pw_dir as *const _; | |
504 | let bytes = CStr::from_ptr(ptr).to_bytes().to_vec(); | |
505 | return Some(OsStringExt::from_vec(bytes)) | |
506 | } | |
1a4d82fc JJ |
507 | } |
508 | } | |
c34b1796 AL |
509 | |
510 | pub fn exit(code: i32) -> ! { | |
511 | unsafe { libc::exit(code as c_int) } | |
512 | } |