]> git.lizzy.rs Git - rust.git/blob - src/libstd/os.rs
493dd86b2763a1a0605e158eee757ba1bd3a6e09
[rust.git] / src / libstd / os.rs
1 // Copyright 2012-2013 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 /*!
12  * Higher-level interfaces to libc::* functions and operating system services.
13  *
14  * In general these take and return rust types, use rust idioms (enums,
15  * closures, vectors) rather than C idioms, and do more extensive safety
16  * checks.
17  *
18  * This module is not meant to only contain 1:1 mappings to libc entries; any
19  * os-interface code that is reasonably useful and broadly applicable can go
20  * here. Including utility routines that merely build on other os code.
21  *
22  * We assume the general case is that users do not care, and do not want to
23  * be made to care, which operating system they are on. While they may want
24  * to special case various special cases -- and so we will not _hide_ the
25  * facts of which OS the user is on -- they should be given the opportunity
26  * to write OS-ignorant code by default.
27  */
28
29 #![allow(missing_doc)]
30
31 use clone::Clone;
32 use container::Container;
33 use fmt;
34 use iter::Iterator;
35 use libc::{c_void, c_int};
36 use libc;
37 use ops::Drop;
38 use option::{Some, None, Option};
39 use os;
40 use path::{Path, GenericPath};
41 use ptr::RawPtr;
42 use ptr;
43 use result::{Err, Ok, Result};
44 use slice::{Vector, ImmutableVector, MutableVector, OwnedVector};
45 use str::{Str, StrSlice, StrAllocating};
46 use str;
47 use strbuf::StrBuf;
48 use sync::atomics::{AtomicInt, INIT_ATOMIC_INT, SeqCst};
49 use vec::Vec;
50
51 #[cfg(unix)]
52 use c_str::ToCStr;
53 #[cfg(unix)]
54 use libc::c_char;
55 #[cfg(windows)]
56 use str::OwnedStr;
57
58 /// Delegates to the libc close() function, returning the same return value.
59 pub fn close(fd: int) -> int {
60     unsafe {
61         libc::close(fd as c_int) as int
62     }
63 }
64
65 pub static TMPBUF_SZ : uint = 1000u;
66 static BUF_BYTES : uint = 2048u;
67
68 /// Returns the current working directory.
69 #[cfg(unix)]
70 pub fn getcwd() -> Path {
71     use c_str::CString;
72
73     let mut buf = [0 as c_char, ..BUF_BYTES];
74     unsafe {
75         if libc::getcwd(buf.as_mut_ptr(), buf.len() as libc::size_t).is_null() {
76             fail!()
77         }
78         Path::new(CString::new(buf.as_ptr(), false))
79     }
80 }
81
82 /// Returns the current working directory.
83 #[cfg(windows)]
84 pub fn getcwd() -> Path {
85     use libc::DWORD;
86     use libc::GetCurrentDirectoryW;
87     use option::Expect;
88
89     let mut buf = [0 as u16, ..BUF_BYTES];
90     unsafe {
91         if libc::GetCurrentDirectoryW(buf.len() as DWORD, buf.as_mut_ptr()) == 0 as DWORD {
92             fail!();
93         }
94     }
95     Path::new(str::from_utf16(str::truncate_utf16_at_nul(buf))
96               .expect("GetCurrentDirectoryW returned invalid UTF-16"))
97 }
98
99 #[cfg(windows)]
100 pub mod win32 {
101     use libc::types::os::arch::extra::DWORD;
102     use libc;
103     use option::{None, Option, Expect};
104     use option;
105     use os::TMPBUF_SZ;
106     use slice::{MutableVector, ImmutableVector};
107     use strbuf::StrBuf;
108     use str::{StrSlice, StrAllocating};
109     use str;
110     use vec::Vec;
111
112     pub fn fill_utf16_buf_and_decode(f: |*mut u16, DWORD| -> DWORD)
113         -> Option<StrBuf> {
114
115         unsafe {
116             let mut n = TMPBUF_SZ as DWORD;
117             let mut res = None;
118             let mut done = false;
119             while !done {
120                 let mut buf = Vec::from_elem(n as uint, 0u16);
121                 let k = f(buf.as_mut_ptr(), n);
122                 if k == (0 as DWORD) {
123                     done = true;
124                 } else if k == n &&
125                           libc::GetLastError() ==
126                           libc::ERROR_INSUFFICIENT_BUFFER as DWORD {
127                     n *= 2 as DWORD;
128                 } else if k >= n {
129                     n = k;
130                 } else {
131                     done = true;
132                 }
133                 if k != 0 && done {
134                     let sub = buf.slice(0, k as uint);
135                     // We want to explicitly catch the case when the
136                     // closure returned invalid UTF-16, rather than
137                     // set `res` to None and continue.
138                     let s = str::from_utf16(sub)
139                         .expect("fill_utf16_buf_and_decode: closure created invalid UTF-16");
140                     res = option::Some(s)
141                 }
142             }
143             return res;
144         }
145     }
146
147     pub fn as_utf16_p<T>(s: &str, f: |*u16| -> T) -> T {
148         as_mut_utf16_p(s, |t| { f(t as *u16) })
149     }
150
151     pub fn as_mut_utf16_p<T>(s: &str, f: |*mut u16| -> T) -> T {
152         let mut t = s.to_utf16();
153         // Null terminate before passing on.
154         t.push(0u16);
155         f(t.as_mut_ptr())
156     }
157 }
158
159 /*
160 Accessing environment variables is not generally threadsafe.
161 Serialize access through a global lock.
162 */
163 fn with_env_lock<T>(f: || -> T) -> T {
164     use unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
165
166     static mut lock: StaticNativeMutex = NATIVE_MUTEX_INIT;
167
168     unsafe {
169         let _guard = lock.lock();
170         f()
171     }
172 }
173
174 /// Returns a vector of (variable, value) pairs for all the environment
175 /// variables of the current process.
176 ///
177 /// Invalid UTF-8 bytes are replaced with \uFFFD. See `str::from_utf8_lossy()`
178 /// for details.
179 pub fn env() -> Vec<(StrBuf,StrBuf)> {
180     env_as_bytes().move_iter().map(|(k,v)| {
181         let k = str::from_utf8_lossy(k.as_slice()).to_strbuf();
182         let v = str::from_utf8_lossy(v.as_slice()).to_strbuf();
183         (k,v)
184     }).collect()
185 }
186
187 /// Returns a vector of (variable, value) byte-vector pairs for all the
188 /// environment variables of the current process.
189 pub fn env_as_bytes() -> Vec<(Vec<u8>,Vec<u8>)> {
190     unsafe {
191         #[cfg(windows)]
192         unsafe fn get_env_pairs() -> Vec<Vec<u8>> {
193             use slice::raw;
194
195             use libc::funcs::extra::kernel32::{
196                 GetEnvironmentStringsW,
197                 FreeEnvironmentStringsW
198             };
199             let ch = GetEnvironmentStringsW();
200             if ch as uint == 0 {
201                 fail!("os::env() failure getting env string from OS: {}",
202                        os::last_os_error());
203             }
204             // Here, we lossily decode the string as UTF16.
205             //
206             // The docs suggest that the result should be in Unicode, but
207             // Windows doesn't guarantee it's actually UTF16 -- it doesn't
208             // validate the environment string passed to CreateProcess nor
209             // SetEnvironmentVariable.  Yet, it's unlikely that returning a
210             // raw u16 buffer would be of practical use since the result would
211             // be inherently platform-dependent and introduce additional
212             // complexity to this code.
213             //
214             // Using the non-Unicode version of GetEnvironmentStrings is even
215             // worse since the result is in an OEM code page.  Characters that
216             // can't be encoded in the code page would be turned into question
217             // marks.
218             let mut result = Vec::new();
219             let mut i = 0;
220             while *ch.offset(i) != 0 {
221                 let p = &*ch.offset(i);
222                 let len = ptr::position(p, |c| *c == 0);
223                 raw::buf_as_slice(p, len, |s| {
224                     result.push(str::from_utf16_lossy(s).into_bytes());
225                 });
226                 i += len as int + 1;
227             }
228             FreeEnvironmentStringsW(ch);
229             result
230         }
231         #[cfg(unix)]
232         unsafe fn get_env_pairs() -> Vec<Vec<u8>> {
233             use c_str::CString;
234
235             extern {
236                 fn rust_env_pairs() -> **c_char;
237             }
238             let environ = rust_env_pairs();
239             if environ as uint == 0 {
240                 fail!("os::env() failure getting env string from OS: {}",
241                        os::last_os_error());
242             }
243             let mut result = Vec::new();
244             ptr::array_each(environ, |e| {
245                 let env_pair =
246                     Vec::from_slice(CString::new(e, false).as_bytes_no_nul());
247                 result.push(env_pair);
248             });
249             result
250         }
251
252         fn env_convert(input: Vec<Vec<u8>>) -> Vec<(Vec<u8>, Vec<u8>)> {
253             let mut pairs = Vec::new();
254             for p in input.iter() {
255                 let mut it = p.as_slice().splitn(1, |b| *b == '=' as u8);
256                 let key = Vec::from_slice(it.next().unwrap());
257                 let val = Vec::from_slice(it.next().unwrap_or(&[]));
258                 pairs.push((key, val));
259             }
260             pairs
261         }
262         with_env_lock(|| {
263             let unparsed_environ = get_env_pairs();
264             env_convert(unparsed_environ)
265         })
266     }
267 }
268
269 #[cfg(unix)]
270 /// Fetches the environment variable `n` from the current process, returning
271 /// None if the variable isn't set.
272 ///
273 /// Any invalid UTF-8 bytes in the value are replaced by \uFFFD. See
274 /// `str::from_utf8_lossy()` for details.
275 ///
276 /// # Failure
277 ///
278 /// Fails if `n` has any interior NULs.
279 pub fn getenv(n: &str) -> Option<StrBuf> {
280     getenv_as_bytes(n).map(|v| str::from_utf8_lossy(v.as_slice()).to_strbuf())
281 }
282
283 #[cfg(unix)]
284 /// Fetches the environment variable `n` byte vector from the current process,
285 /// returning None if the variable isn't set.
286 ///
287 /// # Failure
288 ///
289 /// Fails if `n` has any interior NULs.
290 pub fn getenv_as_bytes(n: &str) -> Option<Vec<u8>> {
291     use c_str::CString;
292
293     unsafe {
294         with_env_lock(|| {
295             let s = n.with_c_str(|buf| libc::getenv(buf));
296             if s.is_null() {
297                 None
298             } else {
299                 Some(Vec::from_slice(CString::new(s,
300                                                   false).as_bytes_no_nul()))
301             }
302         })
303     }
304 }
305
306 #[cfg(windows)]
307 /// Fetches the environment variable `n` from the current process, returning
308 /// None if the variable isn't set.
309 pub fn getenv(n: &str) -> Option<StrBuf> {
310     unsafe {
311         with_env_lock(|| {
312             use os::win32::{as_utf16_p, fill_utf16_buf_and_decode};
313             as_utf16_p(n, |u| {
314                 fill_utf16_buf_and_decode(|buf, sz| {
315                     libc::GetEnvironmentVariableW(u, buf, sz)
316                 })
317             })
318         })
319     }
320 }
321
322 #[cfg(windows)]
323 /// Fetches the environment variable `n` byte vector from the current process,
324 /// returning None if the variable isn't set.
325 pub fn getenv_as_bytes(n: &str) -> Option<Vec<u8>> {
326     getenv(n).map(|s| s.into_bytes())
327 }
328
329
330 #[cfg(unix)]
331 /// Sets the environment variable `n` to the value `v` for the currently running
332 /// process
333 ///
334 /// # Failure
335 ///
336 /// Fails if `n` or `v` have any interior NULs.
337 pub fn setenv(n: &str, v: &str) {
338     unsafe {
339         with_env_lock(|| {
340             n.with_c_str(|nbuf| {
341                 v.with_c_str(|vbuf| {
342                     libc::funcs::posix01::unistd::setenv(nbuf, vbuf, 1);
343                 })
344             })
345         })
346     }
347 }
348
349
350 #[cfg(windows)]
351 /// Sets the environment variable `n` to the value `v` for the currently running
352 /// process
353 pub fn setenv(n: &str, v: &str) {
354     unsafe {
355         with_env_lock(|| {
356             use os::win32::as_utf16_p;
357             as_utf16_p(n, |nbuf| {
358                 as_utf16_p(v, |vbuf| {
359                     libc::SetEnvironmentVariableW(nbuf, vbuf);
360                 })
361             })
362         })
363     }
364 }
365
366 /// Remove a variable from the environment entirely
367 ///
368 /// # Failure
369 ///
370 /// Fails (on unix) if `n` has any interior NULs.
371 pub fn unsetenv(n: &str) {
372     #[cfg(unix)]
373     fn _unsetenv(n: &str) {
374         unsafe {
375             with_env_lock(|| {
376                 n.with_c_str(|nbuf| {
377                     libc::funcs::posix01::unistd::unsetenv(nbuf);
378                 })
379             })
380         }
381     }
382     #[cfg(windows)]
383     fn _unsetenv(n: &str) {
384         unsafe {
385             with_env_lock(|| {
386                 use os::win32::as_utf16_p;
387                 as_utf16_p(n, |nbuf| {
388                     libc::SetEnvironmentVariableW(nbuf, ptr::null());
389                 })
390             })
391         }
392     }
393
394     _unsetenv(n);
395 }
396
397 /// A low-level OS in-memory pipe.
398 pub struct Pipe {
399     /// A file descriptor representing the reading end of the pipe. Data written
400     /// on the `out` file descriptor can be read from this file descriptor.
401     pub input: c_int,
402     /// A file descriptor representing the write end of the pipe. Data written
403     /// to this file descriptor can be read from the `input` file descriptor.
404     pub out: c_int,
405 }
406
407 /// Creates a new low-level OS in-memory pipe.
408 #[cfg(unix)]
409 pub fn pipe() -> Pipe {
410     unsafe {
411         let mut fds = Pipe {input: 0,
412                             out: 0};
413         assert_eq!(libc::pipe(&mut fds.input), 0);
414         return Pipe {input: fds.input, out: fds.out};
415     }
416 }
417
418 /// Creates a new low-level OS in-memory pipe.
419 #[cfg(windows)]
420 pub fn pipe() -> Pipe {
421     unsafe {
422         // Windows pipes work subtly differently than unix pipes, and their
423         // inheritance has to be handled in a different way that I do not
424         // fully understand. Here we explicitly make the pipe non-inheritable,
425         // which means to pass it to a subprocess they need to be duplicated
426         // first, as in std::run.
427         let mut fds = Pipe {input: 0,
428                     out: 0};
429         let res = libc::pipe(&mut fds.input, 1024 as ::libc::c_uint,
430                              (libc::O_BINARY | libc::O_NOINHERIT) as c_int);
431         assert_eq!(res, 0);
432         assert!((fds.input != -1 && fds.input != 0 ));
433         assert!((fds.out != -1 && fds.input != 0));
434         return Pipe {input: fds.input, out: fds.out};
435     }
436 }
437
438 /// Returns the proper dll filename for the given basename of a file.
439 pub fn dll_filename(base: &str) -> StrBuf {
440     format_strbuf!("{}{}{}", consts::DLL_PREFIX, base, consts::DLL_SUFFIX)
441 }
442
443 /// Optionally returns the filesystem path of the current executable which is
444 /// running. If any failure occurs, None is returned.
445 pub fn self_exe_name() -> Option<Path> {
446
447     #[cfg(target_os = "freebsd")]
448     fn load_self() -> Option<Vec<u8>> {
449         unsafe {
450             use libc::funcs::bsd44::*;
451             use libc::consts::os::extra::*;
452             let mib = box [CTL_KERN as c_int,
453                         KERN_PROC as c_int,
454                         KERN_PROC_PATHNAME as c_int, -1 as c_int];
455             let mut sz: libc::size_t = 0;
456             let err = sysctl(mib.as_ptr(), mib.len() as ::libc::c_uint,
457                              ptr::mut_null(), &mut sz, ptr::null(),
458                              0u as libc::size_t);
459             if err != 0 { return None; }
460             if sz == 0 { return None; }
461             let mut v: Vec<u8> = Vec::with_capacity(sz as uint);
462             let err = sysctl(mib.as_ptr(), mib.len() as ::libc::c_uint,
463                              v.as_mut_ptr() as *mut c_void, &mut sz, ptr::null(),
464                              0u as libc::size_t);
465             if err != 0 { return None; }
466             if sz == 0 { return None; }
467             v.set_len(sz as uint - 1); // chop off trailing NUL
468             Some(v)
469         }
470     }
471
472     #[cfg(target_os = "linux")]
473     #[cfg(target_os = "android")]
474     fn load_self() -> Option<Vec<u8>> {
475         use std::io;
476
477         match io::fs::readlink(&Path::new("/proc/self/exe")) {
478             Ok(path) => Some(path.into_vec()),
479             Err(..) => None
480         }
481     }
482
483     #[cfg(target_os = "macos")]
484     fn load_self() -> Option<Vec<u8>> {
485         unsafe {
486             use libc::funcs::extra::_NSGetExecutablePath;
487             let mut sz: u32 = 0;
488             _NSGetExecutablePath(ptr::mut_null(), &mut sz);
489             if sz == 0 { return None; }
490             let mut v: Vec<u8> = Vec::with_capacity(sz as uint);
491             let err = _NSGetExecutablePath(v.as_mut_ptr() as *mut i8, &mut sz);
492             if err != 0 { return None; }
493             v.set_len(sz as uint - 1); // chop off trailing NUL
494             Some(v)
495         }
496     }
497
498     #[cfg(windows)]
499     fn load_self() -> Option<Vec<u8>> {
500         use str::OwnedStr;
501
502         unsafe {
503             use os::win32::fill_utf16_buf_and_decode;
504             fill_utf16_buf_and_decode(|buf, sz| {
505                 libc::GetModuleFileNameW(0u as libc::DWORD, buf, sz)
506             }).map(|s| s.into_strbuf().into_bytes())
507         }
508     }
509
510     load_self().and_then(Path::new_opt)
511 }
512
513 /// Optionally returns the filesystem path to the current executable which is
514 /// running. Like self_exe_name() but without the binary's name.
515 /// If any failure occurs, None is returned.
516 pub fn self_exe_path() -> Option<Path> {
517     self_exe_name().map(|mut p| { p.pop(); p })
518 }
519
520 /**
521  * Returns the path to the user's home directory, if known.
522  *
523  * On Unix, returns the value of the 'HOME' environment variable if it is set
524  * and not equal to the empty string.
525  *
526  * On Windows, returns the value of the 'HOME' environment variable if it is
527  * set and not equal to the empty string. Otherwise, returns the value of the
528  * 'USERPROFILE' environment variable if it is set and not equal to the empty
529  * string.
530  *
531  * Otherwise, homedir returns option::none.
532  */
533 pub fn homedir() -> Option<Path> {
534     // FIXME (#7188): getenv needs a Vec<u8> variant
535     return match getenv("HOME") {
536         Some(ref p) if !p.is_empty() => Path::new_opt(p.as_slice()),
537         _ => secondary()
538     };
539
540     #[cfg(unix)]
541     fn secondary() -> Option<Path> {
542         None
543     }
544
545     #[cfg(windows)]
546     fn secondary() -> Option<Path> {
547         getenv("USERPROFILE").and_then(|p| {
548             if !p.is_empty() {
549                 Path::new_opt(p)
550             } else {
551                 None
552             }
553         })
554     }
555 }
556
557 /**
558  * Returns the path to a temporary directory.
559  *
560  * On Unix, returns the value of the 'TMPDIR' environment variable if it is
561  * set, otherwise for non-Android it returns '/tmp'. If Android, since there
562  * is no global temporary folder (it is usually allocated per-app), we return
563  * '/data/local/tmp'.
564  *
565  * On Windows, returns the value of, in order, the 'TMP', 'TEMP',
566  * 'USERPROFILE' environment variable  if any are set and not the empty
567  * string. Otherwise, tmpdir returns the path to the Windows directory.
568  */
569 pub fn tmpdir() -> Path {
570     return lookup();
571
572     fn getenv_nonempty(v: &str) -> Option<Path> {
573         match getenv(v) {
574             Some(x) =>
575                 if x.is_empty() {
576                     None
577                 } else {
578                     Path::new_opt(x)
579                 },
580             _ => None
581         }
582     }
583
584     #[cfg(unix)]
585     fn lookup() -> Path {
586         let default = if cfg!(target_os = "android") {
587             Path::new("/data/local/tmp")
588         } else {
589             Path::new("/tmp")
590         };
591
592         getenv_nonempty("TMPDIR").unwrap_or(default)
593     }
594
595     #[cfg(windows)]
596     fn lookup() -> Path {
597         getenv_nonempty("TMP").or(
598             getenv_nonempty("TEMP").or(
599                 getenv_nonempty("USERPROFILE").or(
600                    getenv_nonempty("WINDIR")))).unwrap_or(Path::new("C:\\Windows"))
601     }
602 }
603
604 /**
605  * Convert a relative path to an absolute path
606  *
607  * If the given path is relative, return it prepended with the current working
608  * directory. If the given path is already an absolute path, return it
609  * as is.
610  */
611 // NB: this is here rather than in path because it is a form of environment
612 // querying; what it does depends on the process working directory, not just
613 // the input paths.
614 pub fn make_absolute(p: &Path) -> Path {
615     if p.is_absolute() {
616         p.clone()
617     } else {
618         let mut ret = getcwd();
619         ret.push(p);
620         ret
621     }
622 }
623
624 /// Changes the current working directory to the specified path, returning
625 /// whether the change was completed successfully or not.
626 pub fn change_dir(p: &Path) -> bool {
627     return chdir(p);
628
629     #[cfg(windows)]
630     fn chdir(p: &Path) -> bool {
631         unsafe {
632             use os::win32::as_utf16_p;
633             return as_utf16_p(p.as_str().unwrap(), |buf| {
634                 libc::SetCurrentDirectoryW(buf) != (0 as libc::BOOL)
635             });
636         }
637     }
638
639     #[cfg(unix)]
640     fn chdir(p: &Path) -> bool {
641         p.with_c_str(|buf| {
642             unsafe {
643                 libc::chdir(buf) == (0 as c_int)
644             }
645         })
646     }
647 }
648
649 #[cfg(unix)]
650 /// Returns the platform-specific value of errno
651 pub fn errno() -> int {
652     #[cfg(target_os = "macos")]
653     #[cfg(target_os = "freebsd")]
654     fn errno_location() -> *c_int {
655         extern {
656             fn __error() -> *c_int;
657         }
658         unsafe {
659             __error()
660         }
661     }
662
663     #[cfg(target_os = "linux")]
664     #[cfg(target_os = "android")]
665     fn errno_location() -> *c_int {
666         extern {
667             fn __errno_location() -> *c_int;
668         }
669         unsafe {
670             __errno_location()
671         }
672     }
673
674     unsafe {
675         (*errno_location()) as int
676     }
677 }
678
679 #[cfg(windows)]
680 /// Returns the platform-specific value of errno
681 pub fn errno() -> uint {
682     use libc::types::os::arch::extra::DWORD;
683
684     #[link_name = "kernel32"]
685     extern "system" {
686         fn GetLastError() -> DWORD;
687     }
688
689     unsafe {
690         GetLastError() as uint
691     }
692 }
693
694 /// Return the string corresponding to an `errno()` value of `errnum`.
695 pub fn error_string(errnum: uint) -> StrBuf {
696     return strerror(errnum);
697
698     #[cfg(unix)]
699     fn strerror(errnum: uint) -> StrBuf {
700         #[cfg(target_os = "macos")]
701         #[cfg(target_os = "android")]
702         #[cfg(target_os = "freebsd")]
703         fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t)
704                       -> c_int {
705             extern {
706                 fn strerror_r(errnum: c_int, buf: *mut c_char,
707                               buflen: libc::size_t) -> c_int;
708             }
709             unsafe {
710                 strerror_r(errnum, buf, buflen)
711             }
712         }
713
714         // GNU libc provides a non-compliant version of strerror_r by default
715         // and requires macros to instead use the POSIX compliant variant.
716         // So we just use __xpg_strerror_r which is always POSIX compliant
717         #[cfg(target_os = "linux")]
718         fn strerror_r(errnum: c_int, buf: *mut c_char,
719                       buflen: libc::size_t) -> c_int {
720             extern {
721                 fn __xpg_strerror_r(errnum: c_int,
722                                     buf: *mut c_char,
723                                     buflen: libc::size_t)
724                                     -> c_int;
725             }
726             unsafe {
727                 __xpg_strerror_r(errnum, buf, buflen)
728             }
729         }
730
731         let mut buf = [0 as c_char, ..TMPBUF_SZ];
732
733         let p = buf.as_mut_ptr();
734         unsafe {
735             if strerror_r(errnum as c_int, p, buf.len() as libc::size_t) < 0 {
736                 fail!("strerror_r failure");
737             }
738
739             str::raw::from_c_str(p as *c_char).into_strbuf()
740         }
741     }
742
743     #[cfg(windows)]
744     fn strerror(errnum: uint) -> StrBuf {
745         use libc::types::os::arch::extra::DWORD;
746         use libc::types::os::arch::extra::LPWSTR;
747         use libc::types::os::arch::extra::LPVOID;
748         use libc::types::os::arch::extra::WCHAR;
749
750         #[link_name = "kernel32"]
751         extern "system" {
752             fn FormatMessageW(flags: DWORD,
753                               lpSrc: LPVOID,
754                               msgId: DWORD,
755                               langId: DWORD,
756                               buf: LPWSTR,
757                               nsize: DWORD,
758                               args: *c_void)
759                               -> DWORD;
760         }
761
762         static FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000;
763         static FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200;
764
765         // This value is calculated from the macro
766         // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT)
767         let langId = 0x0800 as DWORD;
768
769         let mut buf = [0 as WCHAR, ..TMPBUF_SZ];
770
771         unsafe {
772             let res = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
773                                      FORMAT_MESSAGE_IGNORE_INSERTS,
774                                      ptr::mut_null(),
775                                      errnum as DWORD,
776                                      langId,
777                                      buf.as_mut_ptr(),
778                                      buf.len() as DWORD,
779                                      ptr::null());
780             if res == 0 {
781                 // Sometimes FormatMessageW can fail e.g. system doesn't like langId,
782                 let fm_err = errno();
783                 return format!("OS Error {} (FormatMessageW() returned error {})", errnum, fm_err);
784             }
785
786             let msg = str::from_utf16(str::truncate_utf16_at_nul(buf));
787             match msg {
788                 Some(msg) => format!("OS Error {}: {}", errnum, msg),
789                 None => format!("OS Error {} (FormatMessageW() returned invalid UTF-16)", errnum),
790             }
791         }
792     }
793 }
794
795 /// Get a string representing the platform-dependent last error
796 pub fn last_os_error() -> StrBuf {
797     error_string(errno() as uint)
798 }
799
800 static mut EXIT_STATUS: AtomicInt = INIT_ATOMIC_INT;
801
802 /**
803  * Sets the process exit code
804  *
805  * Sets the exit code returned by the process if all supervised tasks
806  * terminate successfully (without failing). If the current root task fails
807  * and is supervised by the scheduler then any user-specified exit status is
808  * ignored and the process exits with the default failure status.
809  *
810  * Note that this is not synchronized against modifications of other threads.
811  */
812 pub fn set_exit_status(code: int) {
813     unsafe { EXIT_STATUS.store(code, SeqCst) }
814 }
815
816 /// Fetches the process's current exit code. This defaults to 0 and can change
817 /// by calling `set_exit_status`.
818 pub fn get_exit_status() -> int {
819     unsafe { EXIT_STATUS.load(SeqCst) }
820 }
821
822 #[cfg(target_os = "macos")]
823 unsafe fn load_argc_and_argv(argc: int, argv: **c_char) -> Vec<Vec<u8>> {
824     use c_str::CString;
825
826     Vec::from_fn(argc as uint, |i| {
827         Vec::from_slice(CString::new(*argv.offset(i as int),
828                                      false).as_bytes_no_nul())
829     })
830 }
831
832 /**
833  * Returns the command line arguments
834  *
835  * Returns a list of the command line arguments.
836  */
837 #[cfg(target_os = "macos")]
838 fn real_args_as_bytes() -> Vec<Vec<u8>> {
839     unsafe {
840         let (argc, argv) = (*_NSGetArgc() as int,
841                             *_NSGetArgv() as **c_char);
842         load_argc_and_argv(argc, argv)
843     }
844 }
845
846 #[cfg(target_os = "linux")]
847 #[cfg(target_os = "android")]
848 #[cfg(target_os = "freebsd")]
849 fn real_args_as_bytes() -> Vec<Vec<u8>> {
850     use rt;
851
852     match rt::args::clone() {
853         Some(args) => args,
854         None => fail!("process arguments not initialized")
855     }
856 }
857
858 #[cfg(not(windows))]
859 fn real_args() -> Vec<StrBuf> {
860     real_args_as_bytes().move_iter()
861                         .map(|v| {
862                             str::from_utf8_lossy(v.as_slice()).into_strbuf()
863                         }).collect()
864 }
865
866 #[cfg(windows)]
867 fn real_args() -> Vec<StrBuf> {
868     use slice;
869     use option::Expect;
870
871     let mut nArgs: c_int = 0;
872     let lpArgCount: *mut c_int = &mut nArgs;
873     let lpCmdLine = unsafe { GetCommandLineW() };
874     let szArgList = unsafe { CommandLineToArgvW(lpCmdLine, lpArgCount) };
875
876     let args = Vec::from_fn(nArgs as uint, |i| unsafe {
877         // Determine the length of this argument.
878         let ptr = *szArgList.offset(i as int);
879         let mut len = 0;
880         while *ptr.offset(len as int) != 0 { len += 1; }
881
882         // Push it onto the list.
883         let opt_s = slice::raw::buf_as_slice(ptr, len, |buf| {
884             str::from_utf16(str::truncate_utf16_at_nul(buf))
885         });
886         opt_s.expect("CommandLineToArgvW returned invalid UTF-16")
887     });
888
889     unsafe {
890         LocalFree(szArgList as *c_void);
891     }
892
893     return args
894 }
895
896 #[cfg(windows)]
897 fn real_args_as_bytes() -> Vec<Vec<u8>> {
898     real_args().move_iter().map(|s| s.into_bytes()).collect()
899 }
900
901 type LPCWSTR = *u16;
902
903 #[cfg(windows)]
904 #[link_name="kernel32"]
905 extern "system" {
906     fn GetCommandLineW() -> LPCWSTR;
907     fn LocalFree(ptr: *c_void);
908 }
909
910 #[cfg(windows)]
911 #[link_name="shell32"]
912 extern "system" {
913     fn CommandLineToArgvW(lpCmdLine: LPCWSTR, pNumArgs: *mut c_int) -> **u16;
914 }
915
916 /// Returns the arguments which this program was started with (normally passed
917 /// via the command line).
918 ///
919 /// The arguments are interpreted as utf-8, with invalid bytes replaced with \uFFFD.
920 /// See `str::from_utf8_lossy` for details.
921 #[cfg(not(test))]
922 pub fn args() -> Vec<StrBuf> {
923     real_args()
924 }
925
926 #[cfg(test)]
927 #[allow(missing_doc)]
928 pub fn args() -> ::realstd::vec::Vec<::realstd::strbuf::StrBuf> {
929     ::realstd::os::args()
930 }
931
932 /// Returns the arguments which this program was started with (normally passed
933 /// via the command line) as byte vectors.
934 pub fn args_as_bytes() -> Vec<Vec<u8>> {
935     real_args_as_bytes()
936 }
937
938 #[cfg(target_os = "macos")]
939 extern {
940     // These functions are in crt_externs.h.
941     pub fn _NSGetArgc() -> *c_int;
942     pub fn _NSGetArgv() -> ***c_char;
943 }
944
945 // Round up `from` to be divisible by `to`
946 fn round_up(from: uint, to: uint) -> uint {
947     let r = if from % to == 0 {
948         from
949     } else {
950         from + to - (from % to)
951     };
952     if r == 0 {
953         to
954     } else {
955         r
956     }
957 }
958
959 /// Returns the page size of the current architecture in bytes.
960 #[cfg(unix)]
961 pub fn page_size() -> uint {
962     unsafe {
963         libc::sysconf(libc::_SC_PAGESIZE) as uint
964     }
965 }
966
967 /// Returns the page size of the current architecture in bytes.
968 #[cfg(windows)]
969 pub fn page_size() -> uint {
970     use mem;
971     unsafe {
972         let mut info = mem::uninit();
973         libc::GetSystemInfo(&mut info);
974
975         return info.dwPageSize as uint;
976     }
977 }
978
979 /// A memory mapped file or chunk of memory. This is a very system-specific
980 /// interface to the OS's memory mapping facilities (`mmap` on POSIX,
981 /// `VirtualAlloc`/`CreateFileMapping` on win32). It makes no attempt at
982 /// abstracting platform differences, besides in error values returned. Consider
983 /// yourself warned.
984 ///
985 /// The memory map is released (unmapped) when the destructor is run, so don't
986 /// let it leave scope by accident if you want it to stick around.
987 pub struct MemoryMap {
988     /// Pointer to the memory created or modified by this map.
989     pub data: *mut u8,
990     /// Number of bytes this map applies to
991     pub len: uint,
992     /// Type of mapping
993     pub kind: MemoryMapKind,
994 }
995
996 /// Type of memory map
997 pub enum MemoryMapKind {
998     /// Virtual memory map. Usually used to change the permissions of a given
999     /// chunk of memory.  Corresponds to `VirtualAlloc` on Windows.
1000     MapFile(*u8),
1001     /// Virtual memory map. Usually used to change the permissions of a given
1002     /// chunk of memory, or for allocation. Corresponds to `VirtualAlloc` on
1003     /// Windows.
1004     MapVirtual
1005 }
1006
1007 /// Options the memory map is created with
1008 pub enum MapOption {
1009     /// The memory should be readable
1010     MapReadable,
1011     /// The memory should be writable
1012     MapWritable,
1013     /// The memory should be executable
1014     MapExecutable,
1015     /// Create a map for a specific address range. Corresponds to `MAP_FIXED` on
1016     /// POSIX.
1017     MapAddr(*u8),
1018     /// Create a memory mapping for a file with a given fd.
1019     MapFd(c_int),
1020     /// When using `MapFd`, the start of the map is `uint` bytes from the start
1021     /// of the file.
1022     MapOffset(uint),
1023     /// On POSIX, this can be used to specify the default flags passed to
1024     /// `mmap`. By default it uses `MAP_PRIVATE` and, if not using `MapFd`,
1025     /// `MAP_ANON`. This will override both of those. This is platform-specific
1026     /// (the exact values used) and ignored on Windows.
1027     MapNonStandardFlags(c_int),
1028 }
1029
1030 /// Possible errors when creating a map.
1031 pub enum MapError {
1032     /// ## The following are POSIX-specific
1033     ///
1034     /// fd was not open for reading or, if using `MapWritable`, was not open for
1035     /// writing.
1036     ErrFdNotAvail,
1037     /// fd was not valid
1038     ErrInvalidFd,
1039     /// Either the address given by `MapAddr` or offset given by `MapOffset` was
1040     /// not a multiple of `MemoryMap::granularity` (unaligned to page size).
1041     ErrUnaligned,
1042     /// With `MapFd`, the fd does not support mapping.
1043     ErrNoMapSupport,
1044     /// If using `MapAddr`, the address + `min_len` was outside of the process's
1045     /// address space. If using `MapFd`, the target of the fd didn't have enough
1046     /// resources to fulfill the request.
1047     ErrNoMem,
1048     /// A zero-length map was requested. This is invalid according to
1049     /// [POSIX](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html).
1050     /// Not all platforms obey this, but this wrapper does.
1051     ErrZeroLength,
1052     /// Unrecognized error. The inner value is the unrecognized errno.
1053     ErrUnknown(int),
1054     /// ## The following are win32-specific
1055     ///
1056     /// Unsupported combination of protection flags
1057     /// (`MapReadable`/`MapWritable`/`MapExecutable`).
1058     ErrUnsupProt,
1059     /// When using `MapFd`, `MapOffset` was given (Windows does not support this
1060     /// at all)
1061     ErrUnsupOffset,
1062     /// When using `MapFd`, there was already a mapping to the file.
1063     ErrAlreadyExists,
1064     /// Unrecognized error from `VirtualAlloc`. The inner value is the return
1065     /// value of GetLastError.
1066     ErrVirtualAlloc(uint),
1067     /// Unrecognized error from `CreateFileMapping`. The inner value is the
1068     /// return value of `GetLastError`.
1069     ErrCreateFileMappingW(uint),
1070     /// Unrecognized error from `MapViewOfFile`. The inner value is the return
1071     /// value of `GetLastError`.
1072     ErrMapViewOfFile(uint)
1073 }
1074
1075 impl fmt::Show for MapError {
1076     fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
1077         let str = match *self {
1078             ErrFdNotAvail => "fd not available for reading or writing",
1079             ErrInvalidFd => "Invalid fd",
1080             ErrUnaligned => {
1081                 "Unaligned address, invalid flags, negative length or \
1082                  unaligned offset"
1083             }
1084             ErrNoMapSupport=> "File doesn't support mapping",
1085             ErrNoMem => "Invalid address, or not enough available memory",
1086             ErrUnsupProt => "Protection mode unsupported",
1087             ErrUnsupOffset => "Offset in virtual memory mode is unsupported",
1088             ErrAlreadyExists => "File mapping for specified file already exists",
1089             ErrZeroLength => "Zero-length mapping not allowed",
1090             ErrUnknown(code) => {
1091                 return write!(out, "Unknown error = {}", code)
1092             },
1093             ErrVirtualAlloc(code) => {
1094                 return write!(out, "VirtualAlloc failure = {}", code)
1095             },
1096             ErrCreateFileMappingW(code) => {
1097                 return write!(out, "CreateFileMappingW failure = {}", code)
1098             },
1099             ErrMapViewOfFile(code) => {
1100                 return write!(out, "MapViewOfFile failure = {}", code)
1101             }
1102         };
1103         write!(out, "{}", str)
1104     }
1105 }
1106
1107 #[cfg(unix)]
1108 impl MemoryMap {
1109     /// Create a new mapping with the given `options`, at least `min_len` bytes
1110     /// long. `min_len` must be greater than zero; see the note on
1111     /// `ErrZeroLength`.
1112     pub fn new(min_len: uint, options: &[MapOption]) -> Result<MemoryMap, MapError> {
1113         use libc::off_t;
1114         use cmp::Equiv;
1115
1116         if min_len == 0 {
1117             return Err(ErrZeroLength)
1118         }
1119         let mut addr: *u8 = ptr::null();
1120         let mut prot = 0;
1121         let mut flags = libc::MAP_PRIVATE;
1122         let mut fd = -1;
1123         let mut offset = 0;
1124         let mut custom_flags = false;
1125         let len = round_up(min_len, page_size());
1126
1127         for &o in options.iter() {
1128             match o {
1129                 MapReadable => { prot |= libc::PROT_READ; },
1130                 MapWritable => { prot |= libc::PROT_WRITE; },
1131                 MapExecutable => { prot |= libc::PROT_EXEC; },
1132                 MapAddr(addr_) => {
1133                     flags |= libc::MAP_FIXED;
1134                     addr = addr_;
1135                 },
1136                 MapFd(fd_) => {
1137                     flags |= libc::MAP_FILE;
1138                     fd = fd_;
1139                 },
1140                 MapOffset(offset_) => { offset = offset_ as off_t; },
1141                 MapNonStandardFlags(f) => { custom_flags = true; flags = f },
1142             }
1143         }
1144         if fd == -1 && !custom_flags { flags |= libc::MAP_ANON; }
1145
1146         let r = unsafe {
1147             libc::mmap(addr as *c_void, len as libc::size_t, prot, flags, fd,
1148                        offset)
1149         };
1150         if r.equiv(&libc::MAP_FAILED) {
1151             Err(match errno() as c_int {
1152                 libc::EACCES => ErrFdNotAvail,
1153                 libc::EBADF => ErrInvalidFd,
1154                 libc::EINVAL => ErrUnaligned,
1155                 libc::ENODEV => ErrNoMapSupport,
1156                 libc::ENOMEM => ErrNoMem,
1157                 code => ErrUnknown(code as int)
1158             })
1159         } else {
1160             Ok(MemoryMap {
1161                data: r as *mut u8,
1162                len: len,
1163                kind: if fd == -1 {
1164                    MapVirtual
1165                } else {
1166                    MapFile(ptr::null())
1167                }
1168             })
1169         }
1170     }
1171
1172     /// Granularity that the offset or address must be for `MapOffset` and
1173     /// `MapAddr` respectively.
1174     pub fn granularity() -> uint {
1175         page_size()
1176     }
1177 }
1178
1179 #[cfg(unix)]
1180 impl Drop for MemoryMap {
1181     /// Unmap the mapping. Fails the task if `munmap` fails.
1182     fn drop(&mut self) {
1183         if self.len == 0 { /* workaround for dummy_stack */ return; }
1184
1185         unsafe {
1186             // FIXME: what to do if this fails?
1187             let _ = libc::munmap(self.data as *c_void, self.len as libc::size_t);
1188         }
1189     }
1190 }
1191
1192 #[cfg(windows)]
1193 impl MemoryMap {
1194     /// Create a new mapping with the given `options`, at least `min_len` bytes long.
1195     pub fn new(min_len: uint, options: &[MapOption]) -> Result<MemoryMap, MapError> {
1196         use libc::types::os::arch::extra::{LPVOID, DWORD, SIZE_T, HANDLE};
1197
1198         let mut lpAddress: LPVOID = ptr::mut_null();
1199         let mut readable = false;
1200         let mut writable = false;
1201         let mut executable = false;
1202         let mut fd: c_int = -1;
1203         let mut offset: uint = 0;
1204         let len = round_up(min_len, page_size());
1205
1206         for &o in options.iter() {
1207             match o {
1208                 MapReadable => { readable = true; },
1209                 MapWritable => { writable = true; },
1210                 MapExecutable => { executable = true; }
1211                 MapAddr(addr_) => { lpAddress = addr_ as LPVOID; },
1212                 MapFd(fd_) => { fd = fd_; },
1213                 MapOffset(offset_) => { offset = offset_; },
1214                 MapNonStandardFlags(..) => {}
1215             }
1216         }
1217
1218         let flProtect = match (executable, readable, writable) {
1219             (false, false, false) if fd == -1 => libc::PAGE_NOACCESS,
1220             (false, true, false) => libc::PAGE_READONLY,
1221             (false, true, true) => libc::PAGE_READWRITE,
1222             (true, false, false) if fd == -1 => libc::PAGE_EXECUTE,
1223             (true, true, false) => libc::PAGE_EXECUTE_READ,
1224             (true, true, true) => libc::PAGE_EXECUTE_READWRITE,
1225             _ => return Err(ErrUnsupProt)
1226         };
1227
1228         if fd == -1 {
1229             if offset != 0 {
1230                 return Err(ErrUnsupOffset);
1231             }
1232             let r = unsafe {
1233                 libc::VirtualAlloc(lpAddress,
1234                                    len as SIZE_T,
1235                                    libc::MEM_COMMIT | libc::MEM_RESERVE,
1236                                    flProtect)
1237             };
1238             match r as uint {
1239                 0 => Err(ErrVirtualAlloc(errno())),
1240                 _ => Ok(MemoryMap {
1241                    data: r as *mut u8,
1242                    len: len,
1243                    kind: MapVirtual
1244                 })
1245             }
1246         } else {
1247             let dwDesiredAccess = match (executable, readable, writable) {
1248                 (false, true, false) => libc::FILE_MAP_READ,
1249                 (false, true, true) => libc::FILE_MAP_WRITE,
1250                 (true, true, false) => libc::FILE_MAP_READ | libc::FILE_MAP_EXECUTE,
1251                 (true, true, true) => libc::FILE_MAP_WRITE | libc::FILE_MAP_EXECUTE,
1252                 _ => return Err(ErrUnsupProt) // Actually, because of the check above,
1253                                               // we should never get here.
1254             };
1255             unsafe {
1256                 let hFile = libc::get_osfhandle(fd) as HANDLE;
1257                 let mapping = libc::CreateFileMappingW(hFile,
1258                                                        ptr::mut_null(),
1259                                                        flProtect,
1260                                                        0,
1261                                                        0,
1262                                                        ptr::null());
1263                 if mapping == ptr::mut_null() {
1264                     return Err(ErrCreateFileMappingW(errno()));
1265                 }
1266                 if errno() as c_int == libc::ERROR_ALREADY_EXISTS {
1267                     return Err(ErrAlreadyExists);
1268                 }
1269                 let r = libc::MapViewOfFile(mapping,
1270                                             dwDesiredAccess,
1271                                             ((len as u64) >> 32) as DWORD,
1272                                             (offset & 0xffff_ffff) as DWORD,
1273                                             0);
1274                 match r as uint {
1275                     0 => Err(ErrMapViewOfFile(errno())),
1276                     _ => Ok(MemoryMap {
1277                        data: r as *mut u8,
1278                        len: len,
1279                        kind: MapFile(mapping as *u8)
1280                     })
1281                 }
1282             }
1283         }
1284     }
1285
1286     /// Granularity of MapAddr() and MapOffset() parameter values.
1287     /// This may be greater than the value returned by page_size().
1288     pub fn granularity() -> uint {
1289         use mem;
1290         unsafe {
1291             let mut info = mem::uninit();
1292             libc::GetSystemInfo(&mut info);
1293
1294             return info.dwAllocationGranularity as uint;
1295         }
1296     }
1297 }
1298
1299 #[cfg(windows)]
1300 impl Drop for MemoryMap {
1301     /// Unmap the mapping. Fails the task if any of `VirtualFree`,
1302     /// `UnmapViewOfFile`, or `CloseHandle` fail.
1303     fn drop(&mut self) {
1304         use libc::types::os::arch::extra::{LPCVOID, HANDLE};
1305         use libc::consts::os::extra::FALSE;
1306         if self.len == 0 { return }
1307
1308         unsafe {
1309             match self.kind {
1310                 MapVirtual => {
1311                     if libc::VirtualFree(self.data as *mut c_void, 0,
1312                                          libc::MEM_RELEASE) == 0 {
1313                         println!("VirtualFree failed: {}", errno());
1314                     }
1315                 },
1316                 MapFile(mapping) => {
1317                     if libc::UnmapViewOfFile(self.data as LPCVOID) == FALSE {
1318                         println!("UnmapViewOfFile failed: {}", errno());
1319                     }
1320                     if libc::CloseHandle(mapping as HANDLE) == FALSE {
1321                         println!("CloseHandle failed: {}", errno());
1322                     }
1323                 }
1324             }
1325         }
1326     }
1327 }
1328
1329 #[cfg(target_os = "linux")]
1330 pub mod consts {
1331     pub use std::os::arch_consts::ARCH;
1332
1333     pub static FAMILY: &'static str = "unix";
1334
1335     /// A string describing the specific operating system in use: in this
1336     /// case, `linux`.
1337     pub static SYSNAME: &'static str = "linux";
1338
1339     /// Specifies the filename prefix used for shared libraries on this
1340     /// platform: in this case, `lib`.
1341     pub static DLL_PREFIX: &'static str = "lib";
1342
1343     /// Specifies the filename suffix used for shared libraries on this
1344     /// platform: in this case, `.so`.
1345     pub static DLL_SUFFIX: &'static str = ".so";
1346
1347     /// Specifies the file extension used for shared libraries on this
1348     /// platform that goes after the dot: in this case, `so`.
1349     pub static DLL_EXTENSION: &'static str = "so";
1350
1351     /// Specifies the filename suffix used for executable binaries on this
1352     /// platform: in this case, the empty string.
1353     pub static EXE_SUFFIX: &'static str = "";
1354
1355     /// Specifies the file extension, if any, used for executable binaries
1356     /// on this platform: in this case, the empty string.
1357     pub static EXE_EXTENSION: &'static str = "";
1358 }
1359
1360 #[cfg(target_os = "macos")]
1361 pub mod consts {
1362     pub use std::os::arch_consts::ARCH;
1363
1364     pub static FAMILY: &'static str = "unix";
1365
1366     /// A string describing the specific operating system in use: in this
1367     /// case, `macos`.
1368     pub static SYSNAME: &'static str = "macos";
1369
1370     /// Specifies the filename prefix used for shared libraries on this
1371     /// platform: in this case, `lib`.
1372     pub static DLL_PREFIX: &'static str = "lib";
1373
1374     /// Specifies the filename suffix used for shared libraries on this
1375     /// platform: in this case, `.dylib`.
1376     pub static DLL_SUFFIX: &'static str = ".dylib";
1377
1378     /// Specifies the file extension used for shared libraries on this
1379     /// platform that goes after the dot: in this case, `dylib`.
1380     pub static DLL_EXTENSION: &'static str = "dylib";
1381
1382     /// Specifies the filename suffix used for executable binaries on this
1383     /// platform: in this case, the empty string.
1384     pub static EXE_SUFFIX: &'static str = "";
1385
1386     /// Specifies the file extension, if any, used for executable binaries
1387     /// on this platform: in this case, the empty string.
1388     pub static EXE_EXTENSION: &'static str = "";
1389 }
1390
1391 #[cfg(target_os = "freebsd")]
1392 pub mod consts {
1393     pub use std::os::arch_consts::ARCH;
1394
1395     pub static FAMILY: &'static str = "unix";
1396
1397     /// A string describing the specific operating system in use: in this
1398     /// case, `freebsd`.
1399     pub static SYSNAME: &'static str = "freebsd";
1400
1401     /// Specifies the filename prefix used for shared libraries on this
1402     /// platform: in this case, `lib`.
1403     pub static DLL_PREFIX: &'static str = "lib";
1404
1405     /// Specifies the filename suffix used for shared libraries on this
1406     /// platform: in this case, `.so`.
1407     pub static DLL_SUFFIX: &'static str = ".so";
1408
1409     /// Specifies the file extension used for shared libraries on this
1410     /// platform that goes after the dot: in this case, `so`.
1411     pub static DLL_EXTENSION: &'static str = "so";
1412
1413     /// Specifies the filename suffix used for executable binaries on this
1414     /// platform: in this case, the empty string.
1415     pub static EXE_SUFFIX: &'static str = "";
1416
1417     /// Specifies the file extension, if any, used for executable binaries
1418     /// on this platform: in this case, the empty string.
1419     pub static EXE_EXTENSION: &'static str = "";
1420 }
1421
1422 #[cfg(target_os = "android")]
1423 pub mod consts {
1424     pub use std::os::arch_consts::ARCH;
1425
1426     pub static FAMILY: &'static str = "unix";
1427
1428     /// A string describing the specific operating system in use: in this
1429     /// case, `android`.
1430     pub static SYSNAME: &'static str = "android";
1431
1432     /// Specifies the filename prefix used for shared libraries on this
1433     /// platform: in this case, `lib`.
1434     pub static DLL_PREFIX: &'static str = "lib";
1435
1436     /// Specifies the filename suffix used for shared libraries on this
1437     /// platform: in this case, `.so`.
1438     pub static DLL_SUFFIX: &'static str = ".so";
1439
1440     /// Specifies the file extension used for shared libraries on this
1441     /// platform that goes after the dot: in this case, `so`.
1442     pub static DLL_EXTENSION: &'static str = "so";
1443
1444     /// Specifies the filename suffix used for executable binaries on this
1445     /// platform: in this case, the empty string.
1446     pub static EXE_SUFFIX: &'static str = "";
1447
1448     /// Specifies the file extension, if any, used for executable binaries
1449     /// on this platform: in this case, the empty string.
1450     pub static EXE_EXTENSION: &'static str = "";
1451 }
1452
1453 #[cfg(target_os = "win32")]
1454 pub mod consts {
1455     pub use std::os::arch_consts::ARCH;
1456
1457     pub static FAMILY: &'static str = "windows";
1458
1459     /// A string describing the specific operating system in use: in this
1460     /// case, `win32`.
1461     pub static SYSNAME: &'static str = "win32";
1462
1463     /// Specifies the filename prefix used for shared libraries on this
1464     /// platform: in this case, the empty string.
1465     pub static DLL_PREFIX: &'static str = "";
1466
1467     /// Specifies the filename suffix used for shared libraries on this
1468     /// platform: in this case, `.dll`.
1469     pub static DLL_SUFFIX: &'static str = ".dll";
1470
1471     /// Specifies the file extension used for shared libraries on this
1472     /// platform that goes after the dot: in this case, `dll`.
1473     pub static DLL_EXTENSION: &'static str = "dll";
1474
1475     /// Specifies the filename suffix used for executable binaries on this
1476     /// platform: in this case, `.exe`.
1477     pub static EXE_SUFFIX: &'static str = ".exe";
1478
1479     /// Specifies the file extension, if any, used for executable binaries
1480     /// on this platform: in this case, `exe`.
1481     pub static EXE_EXTENSION: &'static str = "exe";
1482 }
1483
1484 #[cfg(target_arch = "x86")]
1485 mod arch_consts {
1486     pub static ARCH: &'static str = "x86";
1487 }
1488
1489 #[cfg(target_arch = "x86_64")]
1490 mod arch_consts {
1491     pub static ARCH: &'static str = "x86_64";
1492 }
1493
1494 #[cfg(target_arch = "arm")]
1495 mod arch_consts {
1496     pub static ARCH: &'static str = "arm";
1497 }
1498
1499 #[cfg(target_arch = "mips")]
1500 mod arch_consts {
1501     pub static ARCH: &'static str = "mips";
1502 }
1503
1504
1505 #[cfg(test)]
1506 mod tests {
1507     use prelude::*;
1508     use c_str::ToCStr;
1509     use option;
1510     use os::{env, getcwd, getenv, make_absolute, args};
1511     use os::{setenv, unsetenv};
1512     use os;
1513     use rand::Rng;
1514     use rand;
1515
1516     #[test]
1517     pub fn last_os_error() {
1518         debug!("{}", os::last_os_error());
1519     }
1520
1521     #[test]
1522     pub fn test_args() {
1523         let a = args();
1524         assert!(a.len() >= 1);
1525     }
1526
1527     fn make_rand_name() -> StrBuf {
1528         let mut rng = rand::task_rng();
1529         let n = format_strbuf!("TEST{}", rng.gen_ascii_str(10u).as_slice());
1530         assert!(getenv(n.as_slice()).is_none());
1531         n
1532     }
1533
1534     #[test]
1535     fn test_setenv() {
1536         let n = make_rand_name();
1537         setenv(n.as_slice(), "VALUE");
1538         assert_eq!(getenv(n.as_slice()), option::Some("VALUE".to_strbuf()));
1539     }
1540
1541     #[test]
1542     fn test_unsetenv() {
1543         let n = make_rand_name();
1544         setenv(n.as_slice(), "VALUE");
1545         unsetenv(n.as_slice());
1546         assert_eq!(getenv(n.as_slice()), option::None);
1547     }
1548
1549     #[test]
1550     #[ignore]
1551     fn test_setenv_overwrite() {
1552         let n = make_rand_name();
1553         setenv(n.as_slice(), "1");
1554         setenv(n.as_slice(), "2");
1555         assert_eq!(getenv(n.as_slice()), option::Some("2".to_strbuf()));
1556         setenv(n.as_slice(), "");
1557         assert_eq!(getenv(n.as_slice()), option::Some("".to_strbuf()));
1558     }
1559
1560     // Windows GetEnvironmentVariable requires some extra work to make sure
1561     // the buffer the variable is copied into is the right size
1562     #[test]
1563     #[ignore]
1564     fn test_getenv_big() {
1565         let mut s = "".to_strbuf();
1566         let mut i = 0;
1567         while i < 100 {
1568             s.push_str("aaaaaaaaaa");
1569             i += 1;
1570         }
1571         let n = make_rand_name();
1572         setenv(n.as_slice(), s.as_slice());
1573         debug!("{}", s.clone());
1574         assert_eq!(getenv(n.as_slice()), option::Some(s));
1575     }
1576
1577     #[test]
1578     fn test_self_exe_name() {
1579         let path = os::self_exe_name();
1580         assert!(path.is_some());
1581         let path = path.unwrap();
1582         debug!("{:?}", path.clone());
1583
1584         // Hard to test this function
1585         assert!(path.is_absolute());
1586     }
1587
1588     #[test]
1589     fn test_self_exe_path() {
1590         let path = os::self_exe_path();
1591         assert!(path.is_some());
1592         let path = path.unwrap();
1593         debug!("{:?}", path.clone());
1594
1595         // Hard to test this function
1596         assert!(path.is_absolute());
1597     }
1598
1599     #[test]
1600     #[ignore]
1601     fn test_env_getenv() {
1602         let e = env();
1603         assert!(e.len() > 0u);
1604         for p in e.iter() {
1605             let (n, v) = (*p).clone();
1606             debug!("{:?}", n.clone());
1607             let v2 = getenv(n.as_slice());
1608             // MingW seems to set some funky environment variables like
1609             // "=C:=C:\MinGW\msys\1.0\bin" and "!::=::\" that are returned
1610             // from env() but not visible from getenv().
1611             assert!(v2.is_none() || v2 == option::Some(v));
1612         }
1613     }
1614
1615     #[test]
1616     fn test_env_set_get_huge() {
1617         let n = make_rand_name();
1618         let s = "x".repeat(10000).to_strbuf();
1619         setenv(n.as_slice(), s.as_slice());
1620         assert_eq!(getenv(n.as_slice()), Some(s));
1621         unsetenv(n.as_slice());
1622         assert_eq!(getenv(n.as_slice()), None);
1623     }
1624
1625     #[test]
1626     fn test_env_setenv() {
1627         let n = make_rand_name();
1628
1629         let mut e = env();
1630         setenv(n.as_slice(), "VALUE");
1631         assert!(!e.contains(&(n.clone(), "VALUE".to_strbuf())));
1632
1633         e = env();
1634         assert!(e.contains(&(n, "VALUE".to_strbuf())));
1635     }
1636
1637     #[test]
1638     fn test() {
1639         assert!((!Path::new("test-path").is_absolute()));
1640
1641         let cwd = getcwd();
1642         debug!("Current working directory: {}", cwd.display());
1643
1644         debug!("{:?}", make_absolute(&Path::new("test-path")));
1645         debug!("{:?}", make_absolute(&Path::new("/usr/bin")));
1646     }
1647
1648     #[test]
1649     #[cfg(unix)]
1650     fn homedir() {
1651         let oldhome = getenv("HOME");
1652
1653         setenv("HOME", "/home/MountainView");
1654         assert!(os::homedir() == Some(Path::new("/home/MountainView")));
1655
1656         setenv("HOME", "");
1657         assert!(os::homedir().is_none());
1658
1659         for s in oldhome.iter() {
1660             setenv("HOME", s.as_slice())
1661         }
1662     }
1663
1664     #[test]
1665     #[cfg(windows)]
1666     fn homedir() {
1667
1668         let oldhome = getenv("HOME");
1669         let olduserprofile = getenv("USERPROFILE");
1670
1671         setenv("HOME", "");
1672         setenv("USERPROFILE", "");
1673
1674         assert!(os::homedir().is_none());
1675
1676         setenv("HOME", "/home/MountainView");
1677         assert!(os::homedir() == Some(Path::new("/home/MountainView")));
1678
1679         setenv("HOME", "");
1680
1681         setenv("USERPROFILE", "/home/MountainView");
1682         assert!(os::homedir() == Some(Path::new("/home/MountainView")));
1683
1684         setenv("HOME", "/home/MountainView");
1685         setenv("USERPROFILE", "/home/PaloAlto");
1686         assert!(os::homedir() == Some(Path::new("/home/MountainView")));
1687
1688         for s in oldhome.iter() {
1689             setenv("HOME", s.as_slice())
1690         }
1691         for s in olduserprofile.iter() {
1692             setenv("USERPROFILE", s.as_slice())
1693         }
1694     }
1695
1696     #[test]
1697     fn memory_map_rw() {
1698         use result::{Ok, Err};
1699
1700         let chunk = match os::MemoryMap::new(16, [
1701             os::MapReadable,
1702             os::MapWritable
1703         ]) {
1704             Ok(chunk) => chunk,
1705             Err(msg) => fail!("{}", msg)
1706         };
1707         assert!(chunk.len >= 16);
1708
1709         unsafe {
1710             *chunk.data = 0xBE;
1711             assert!(*chunk.data == 0xBE);
1712         }
1713     }
1714
1715     #[test]
1716     fn memory_map_file() {
1717         use result::{Ok, Err};
1718         use os::*;
1719         use libc::*;
1720         use io::fs;
1721
1722         #[cfg(unix)]
1723         fn lseek_(fd: c_int, size: uint) {
1724             unsafe {
1725                 assert!(lseek(fd, size as off_t, SEEK_SET) == size as off_t);
1726             }
1727         }
1728         #[cfg(windows)]
1729         fn lseek_(fd: c_int, size: uint) {
1730            unsafe {
1731                assert!(lseek(fd, size as c_long, SEEK_SET) == size as c_long);
1732            }
1733         }
1734
1735         let mut path = tmpdir();
1736         path.push("mmap_file.tmp");
1737         let size = MemoryMap::granularity() * 2;
1738
1739         let fd = unsafe {
1740             let fd = path.with_c_str(|path| {
1741                 open(path, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR)
1742             });
1743             lseek_(fd, size);
1744             "x".with_c_str(|x| assert!(write(fd, x as *c_void, 1) == 1));
1745             fd
1746         };
1747         let chunk = match MemoryMap::new(size / 2, [
1748             MapReadable,
1749             MapWritable,
1750             MapFd(fd),
1751             MapOffset(size / 2)
1752         ]) {
1753             Ok(chunk) => chunk,
1754             Err(msg) => fail!("{}", msg)
1755         };
1756         assert!(chunk.len > 0);
1757
1758         unsafe {
1759             *chunk.data = 0xbe;
1760             assert!(*chunk.data == 0xbe);
1761             close(fd);
1762         }
1763         drop(chunk);
1764
1765         fs::unlink(&path).unwrap();
1766     }
1767
1768     // More recursive_mkdir tests are in extra::tempfile
1769 }