]> git.lizzy.rs Git - rust.git/blob - src/libstd/os.rs
7d3758d621d32249627a723cab852ec5dd4159d8
[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 string::String;
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 string::String;
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<String> {
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<(String,String)> {
180     env_as_bytes().move_iter().map(|(k,v)| {
181         let k = str::from_utf8_lossy(k.as_slice()).to_string();
182         let v = str::from_utf8_lossy(v.as_slice()).to_string();
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<String> {
280     getenv_as_bytes(n).map(|v| str::from_utf8_lossy(v.as_slice()).to_string())
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<String> {
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) -> String {
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_string().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) -> String {
696     return strerror(errnum);
697
698     #[cfg(unix)]
699     fn strerror(errnum: uint) -> String {
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_string()
740         }
741     }
742
743     #[cfg(windows)]
744     fn strerror(errnum: uint) -> String {
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() -> String {
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<String> {
860     real_args_as_bytes().move_iter()
861                         .map(|v| {
862                             str::from_utf8_lossy(v.as_slice()).into_string()
863                         }).collect()
864 }
865
866 #[cfg(windows)]
867 fn real_args() -> Vec<String> {
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 pub fn args() -> Vec<String> {
922     real_args()
923 }
924
925 /// Returns the arguments which this program was started with (normally passed
926 /// via the command line) as byte vectors.
927 pub fn args_as_bytes() -> Vec<Vec<u8>> {
928     real_args_as_bytes()
929 }
930
931 #[cfg(target_os = "macos")]
932 extern {
933     // These functions are in crt_externs.h.
934     pub fn _NSGetArgc() -> *c_int;
935     pub fn _NSGetArgv() -> ***c_char;
936 }
937
938 // Round up `from` to be divisible by `to`
939 fn round_up(from: uint, to: uint) -> uint {
940     let r = if from % to == 0 {
941         from
942     } else {
943         from + to - (from % to)
944     };
945     if r == 0 {
946         to
947     } else {
948         r
949     }
950 }
951
952 /// Returns the page size of the current architecture in bytes.
953 #[cfg(unix)]
954 pub fn page_size() -> uint {
955     unsafe {
956         libc::sysconf(libc::_SC_PAGESIZE) as uint
957     }
958 }
959
960 /// Returns the page size of the current architecture in bytes.
961 #[cfg(windows)]
962 pub fn page_size() -> uint {
963     use mem;
964     unsafe {
965         let mut info = mem::zeroed();
966         libc::GetSystemInfo(&mut info);
967
968         return info.dwPageSize as uint;
969     }
970 }
971
972 /// A memory mapped file or chunk of memory. This is a very system-specific
973 /// interface to the OS's memory mapping facilities (`mmap` on POSIX,
974 /// `VirtualAlloc`/`CreateFileMapping` on win32). It makes no attempt at
975 /// abstracting platform differences, besides in error values returned. Consider
976 /// yourself warned.
977 ///
978 /// The memory map is released (unmapped) when the destructor is run, so don't
979 /// let it leave scope by accident if you want it to stick around.
980 pub struct MemoryMap {
981     /// Pointer to the memory created or modified by this map.
982     pub data: *mut u8,
983     /// Number of bytes this map applies to
984     pub len: uint,
985     /// Type of mapping
986     pub kind: MemoryMapKind,
987 }
988
989 /// Type of memory map
990 pub enum MemoryMapKind {
991     /// Virtual memory map. Usually used to change the permissions of a given
992     /// chunk of memory.  Corresponds to `VirtualAlloc` on Windows.
993     MapFile(*u8),
994     /// Virtual memory map. Usually used to change the permissions of a given
995     /// chunk of memory, or for allocation. Corresponds to `VirtualAlloc` on
996     /// Windows.
997     MapVirtual
998 }
999
1000 /// Options the memory map is created with
1001 pub enum MapOption {
1002     /// The memory should be readable
1003     MapReadable,
1004     /// The memory should be writable
1005     MapWritable,
1006     /// The memory should be executable
1007     MapExecutable,
1008     /// Create a map for a specific address range. Corresponds to `MAP_FIXED` on
1009     /// POSIX.
1010     MapAddr(*u8),
1011     /// Create a memory mapping for a file with a given fd.
1012     MapFd(c_int),
1013     /// When using `MapFd`, the start of the map is `uint` bytes from the start
1014     /// of the file.
1015     MapOffset(uint),
1016     /// On POSIX, this can be used to specify the default flags passed to
1017     /// `mmap`. By default it uses `MAP_PRIVATE` and, if not using `MapFd`,
1018     /// `MAP_ANON`. This will override both of those. This is platform-specific
1019     /// (the exact values used) and ignored on Windows.
1020     MapNonStandardFlags(c_int),
1021 }
1022
1023 /// Possible errors when creating a map.
1024 pub enum MapError {
1025     /// ## The following are POSIX-specific
1026     ///
1027     /// fd was not open for reading or, if using `MapWritable`, was not open for
1028     /// writing.
1029     ErrFdNotAvail,
1030     /// fd was not valid
1031     ErrInvalidFd,
1032     /// Either the address given by `MapAddr` or offset given by `MapOffset` was
1033     /// not a multiple of `MemoryMap::granularity` (unaligned to page size).
1034     ErrUnaligned,
1035     /// With `MapFd`, the fd does not support mapping.
1036     ErrNoMapSupport,
1037     /// If using `MapAddr`, the address + `min_len` was outside of the process's
1038     /// address space. If using `MapFd`, the target of the fd didn't have enough
1039     /// resources to fulfill the request.
1040     ErrNoMem,
1041     /// A zero-length map was requested. This is invalid according to
1042     /// [POSIX](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html).
1043     /// Not all platforms obey this, but this wrapper does.
1044     ErrZeroLength,
1045     /// Unrecognized error. The inner value is the unrecognized errno.
1046     ErrUnknown(int),
1047     /// ## The following are win32-specific
1048     ///
1049     /// Unsupported combination of protection flags
1050     /// (`MapReadable`/`MapWritable`/`MapExecutable`).
1051     ErrUnsupProt,
1052     /// When using `MapFd`, `MapOffset` was given (Windows does not support this
1053     /// at all)
1054     ErrUnsupOffset,
1055     /// When using `MapFd`, there was already a mapping to the file.
1056     ErrAlreadyExists,
1057     /// Unrecognized error from `VirtualAlloc`. The inner value is the return
1058     /// value of GetLastError.
1059     ErrVirtualAlloc(uint),
1060     /// Unrecognized error from `CreateFileMapping`. The inner value is the
1061     /// return value of `GetLastError`.
1062     ErrCreateFileMappingW(uint),
1063     /// Unrecognized error from `MapViewOfFile`. The inner value is the return
1064     /// value of `GetLastError`.
1065     ErrMapViewOfFile(uint)
1066 }
1067
1068 impl fmt::Show for MapError {
1069     fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
1070         let str = match *self {
1071             ErrFdNotAvail => "fd not available for reading or writing",
1072             ErrInvalidFd => "Invalid fd",
1073             ErrUnaligned => {
1074                 "Unaligned address, invalid flags, negative length or \
1075                  unaligned offset"
1076             }
1077             ErrNoMapSupport=> "File doesn't support mapping",
1078             ErrNoMem => "Invalid address, or not enough available memory",
1079             ErrUnsupProt => "Protection mode unsupported",
1080             ErrUnsupOffset => "Offset in virtual memory mode is unsupported",
1081             ErrAlreadyExists => "File mapping for specified file already exists",
1082             ErrZeroLength => "Zero-length mapping not allowed",
1083             ErrUnknown(code) => {
1084                 return write!(out, "Unknown error = {}", code)
1085             },
1086             ErrVirtualAlloc(code) => {
1087                 return write!(out, "VirtualAlloc failure = {}", code)
1088             },
1089             ErrCreateFileMappingW(code) => {
1090                 return write!(out, "CreateFileMappingW failure = {}", code)
1091             },
1092             ErrMapViewOfFile(code) => {
1093                 return write!(out, "MapViewOfFile failure = {}", code)
1094             }
1095         };
1096         write!(out, "{}", str)
1097     }
1098 }
1099
1100 #[cfg(unix)]
1101 impl MemoryMap {
1102     /// Create a new mapping with the given `options`, at least `min_len` bytes
1103     /// long. `min_len` must be greater than zero; see the note on
1104     /// `ErrZeroLength`.
1105     pub fn new(min_len: uint, options: &[MapOption]) -> Result<MemoryMap, MapError> {
1106         use libc::off_t;
1107         use cmp::Equiv;
1108
1109         if min_len == 0 {
1110             return Err(ErrZeroLength)
1111         }
1112         let mut addr: *u8 = ptr::null();
1113         let mut prot = 0;
1114         let mut flags = libc::MAP_PRIVATE;
1115         let mut fd = -1;
1116         let mut offset = 0;
1117         let mut custom_flags = false;
1118         let len = round_up(min_len, page_size());
1119
1120         for &o in options.iter() {
1121             match o {
1122                 MapReadable => { prot |= libc::PROT_READ; },
1123                 MapWritable => { prot |= libc::PROT_WRITE; },
1124                 MapExecutable => { prot |= libc::PROT_EXEC; },
1125                 MapAddr(addr_) => {
1126                     flags |= libc::MAP_FIXED;
1127                     addr = addr_;
1128                 },
1129                 MapFd(fd_) => {
1130                     flags |= libc::MAP_FILE;
1131                     fd = fd_;
1132                 },
1133                 MapOffset(offset_) => { offset = offset_ as off_t; },
1134                 MapNonStandardFlags(f) => { custom_flags = true; flags = f },
1135             }
1136         }
1137         if fd == -1 && !custom_flags { flags |= libc::MAP_ANON; }
1138
1139         let r = unsafe {
1140             libc::mmap(addr as *c_void, len as libc::size_t, prot, flags, fd,
1141                        offset)
1142         };
1143         if r.equiv(&libc::MAP_FAILED) {
1144             Err(match errno() as c_int {
1145                 libc::EACCES => ErrFdNotAvail,
1146                 libc::EBADF => ErrInvalidFd,
1147                 libc::EINVAL => ErrUnaligned,
1148                 libc::ENODEV => ErrNoMapSupport,
1149                 libc::ENOMEM => ErrNoMem,
1150                 code => ErrUnknown(code as int)
1151             })
1152         } else {
1153             Ok(MemoryMap {
1154                data: r as *mut u8,
1155                len: len,
1156                kind: if fd == -1 {
1157                    MapVirtual
1158                } else {
1159                    MapFile(ptr::null())
1160                }
1161             })
1162         }
1163     }
1164
1165     /// Granularity that the offset or address must be for `MapOffset` and
1166     /// `MapAddr` respectively.
1167     pub fn granularity() -> uint {
1168         page_size()
1169     }
1170 }
1171
1172 #[cfg(unix)]
1173 impl Drop for MemoryMap {
1174     /// Unmap the mapping. Fails the task if `munmap` fails.
1175     fn drop(&mut self) {
1176         if self.len == 0 { /* workaround for dummy_stack */ return; }
1177
1178         unsafe {
1179             // FIXME: what to do if this fails?
1180             let _ = libc::munmap(self.data as *c_void, self.len as libc::size_t);
1181         }
1182     }
1183 }
1184
1185 #[cfg(windows)]
1186 impl MemoryMap {
1187     /// Create a new mapping with the given `options`, at least `min_len` bytes long.
1188     pub fn new(min_len: uint, options: &[MapOption]) -> Result<MemoryMap, MapError> {
1189         use libc::types::os::arch::extra::{LPVOID, DWORD, SIZE_T, HANDLE};
1190
1191         let mut lpAddress: LPVOID = ptr::mut_null();
1192         let mut readable = false;
1193         let mut writable = false;
1194         let mut executable = false;
1195         let mut fd: c_int = -1;
1196         let mut offset: uint = 0;
1197         let len = round_up(min_len, page_size());
1198
1199         for &o in options.iter() {
1200             match o {
1201                 MapReadable => { readable = true; },
1202                 MapWritable => { writable = true; },
1203                 MapExecutable => { executable = true; }
1204                 MapAddr(addr_) => { lpAddress = addr_ as LPVOID; },
1205                 MapFd(fd_) => { fd = fd_; },
1206                 MapOffset(offset_) => { offset = offset_; },
1207                 MapNonStandardFlags(..) => {}
1208             }
1209         }
1210
1211         let flProtect = match (executable, readable, writable) {
1212             (false, false, false) if fd == -1 => libc::PAGE_NOACCESS,
1213             (false, true, false) => libc::PAGE_READONLY,
1214             (false, true, true) => libc::PAGE_READWRITE,
1215             (true, false, false) if fd == -1 => libc::PAGE_EXECUTE,
1216             (true, true, false) => libc::PAGE_EXECUTE_READ,
1217             (true, true, true) => libc::PAGE_EXECUTE_READWRITE,
1218             _ => return Err(ErrUnsupProt)
1219         };
1220
1221         if fd == -1 {
1222             if offset != 0 {
1223                 return Err(ErrUnsupOffset);
1224             }
1225             let r = unsafe {
1226                 libc::VirtualAlloc(lpAddress,
1227                                    len as SIZE_T,
1228                                    libc::MEM_COMMIT | libc::MEM_RESERVE,
1229                                    flProtect)
1230             };
1231             match r as uint {
1232                 0 => Err(ErrVirtualAlloc(errno())),
1233                 _ => Ok(MemoryMap {
1234                    data: r as *mut u8,
1235                    len: len,
1236                    kind: MapVirtual
1237                 })
1238             }
1239         } else {
1240             let dwDesiredAccess = match (executable, readable, writable) {
1241                 (false, true, false) => libc::FILE_MAP_READ,
1242                 (false, true, true) => libc::FILE_MAP_WRITE,
1243                 (true, true, false) => libc::FILE_MAP_READ | libc::FILE_MAP_EXECUTE,
1244                 (true, true, true) => libc::FILE_MAP_WRITE | libc::FILE_MAP_EXECUTE,
1245                 _ => return Err(ErrUnsupProt) // Actually, because of the check above,
1246                                               // we should never get here.
1247             };
1248             unsafe {
1249                 let hFile = libc::get_osfhandle(fd) as HANDLE;
1250                 let mapping = libc::CreateFileMappingW(hFile,
1251                                                        ptr::mut_null(),
1252                                                        flProtect,
1253                                                        0,
1254                                                        0,
1255                                                        ptr::null());
1256                 if mapping == ptr::mut_null() {
1257                     return Err(ErrCreateFileMappingW(errno()));
1258                 }
1259                 if errno() as c_int == libc::ERROR_ALREADY_EXISTS {
1260                     return Err(ErrAlreadyExists);
1261                 }
1262                 let r = libc::MapViewOfFile(mapping,
1263                                             dwDesiredAccess,
1264                                             ((len as u64) >> 32) as DWORD,
1265                                             (offset & 0xffff_ffff) as DWORD,
1266                                             0);
1267                 match r as uint {
1268                     0 => Err(ErrMapViewOfFile(errno())),
1269                     _ => Ok(MemoryMap {
1270                        data: r as *mut u8,
1271                        len: len,
1272                        kind: MapFile(mapping as *u8)
1273                     })
1274                 }
1275             }
1276         }
1277     }
1278
1279     /// Granularity of MapAddr() and MapOffset() parameter values.
1280     /// This may be greater than the value returned by page_size().
1281     pub fn granularity() -> uint {
1282         use mem;
1283         unsafe {
1284             let mut info = mem::zeroed();
1285             libc::GetSystemInfo(&mut info);
1286
1287             return info.dwAllocationGranularity as uint;
1288         }
1289     }
1290 }
1291
1292 #[cfg(windows)]
1293 impl Drop for MemoryMap {
1294     /// Unmap the mapping. Fails the task if any of `VirtualFree`,
1295     /// `UnmapViewOfFile`, or `CloseHandle` fail.
1296     fn drop(&mut self) {
1297         use libc::types::os::arch::extra::{LPCVOID, HANDLE};
1298         use libc::consts::os::extra::FALSE;
1299         if self.len == 0 { return }
1300
1301         unsafe {
1302             match self.kind {
1303                 MapVirtual => {
1304                     if libc::VirtualFree(self.data as *mut c_void, 0,
1305                                          libc::MEM_RELEASE) == 0 {
1306                         println!("VirtualFree failed: {}", errno());
1307                     }
1308                 },
1309                 MapFile(mapping) => {
1310                     if libc::UnmapViewOfFile(self.data as LPCVOID) == FALSE {
1311                         println!("UnmapViewOfFile failed: {}", errno());
1312                     }
1313                     if libc::CloseHandle(mapping as HANDLE) == FALSE {
1314                         println!("CloseHandle failed: {}", errno());
1315                     }
1316                 }
1317             }
1318         }
1319     }
1320 }
1321
1322 #[cfg(target_os = "linux")]
1323 pub mod consts {
1324     pub use os::arch_consts::ARCH;
1325
1326     pub static FAMILY: &'static str = "unix";
1327
1328     /// A string describing the specific operating system in use: in this
1329     /// case, `linux`.
1330     pub static SYSNAME: &'static str = "linux";
1331
1332     /// Specifies the filename prefix used for shared libraries on this
1333     /// platform: in this case, `lib`.
1334     pub static DLL_PREFIX: &'static str = "lib";
1335
1336     /// Specifies the filename suffix used for shared libraries on this
1337     /// platform: in this case, `.so`.
1338     pub static DLL_SUFFIX: &'static str = ".so";
1339
1340     /// Specifies the file extension used for shared libraries on this
1341     /// platform that goes after the dot: in this case, `so`.
1342     pub static DLL_EXTENSION: &'static str = "so";
1343
1344     /// Specifies the filename suffix used for executable binaries on this
1345     /// platform: in this case, the empty string.
1346     pub static EXE_SUFFIX: &'static str = "";
1347
1348     /// Specifies the file extension, if any, used for executable binaries
1349     /// on this platform: in this case, the empty string.
1350     pub static EXE_EXTENSION: &'static str = "";
1351 }
1352
1353 #[cfg(target_os = "macos")]
1354 pub mod consts {
1355     pub use os::arch_consts::ARCH;
1356
1357     pub static FAMILY: &'static str = "unix";
1358
1359     /// A string describing the specific operating system in use: in this
1360     /// case, `macos`.
1361     pub static SYSNAME: &'static str = "macos";
1362
1363     /// Specifies the filename prefix used for shared libraries on this
1364     /// platform: in this case, `lib`.
1365     pub static DLL_PREFIX: &'static str = "lib";
1366
1367     /// Specifies the filename suffix used for shared libraries on this
1368     /// platform: in this case, `.dylib`.
1369     pub static DLL_SUFFIX: &'static str = ".dylib";
1370
1371     /// Specifies the file extension used for shared libraries on this
1372     /// platform that goes after the dot: in this case, `dylib`.
1373     pub static DLL_EXTENSION: &'static str = "dylib";
1374
1375     /// Specifies the filename suffix used for executable binaries on this
1376     /// platform: in this case, the empty string.
1377     pub static EXE_SUFFIX: &'static str = "";
1378
1379     /// Specifies the file extension, if any, used for executable binaries
1380     /// on this platform: in this case, the empty string.
1381     pub static EXE_EXTENSION: &'static str = "";
1382 }
1383
1384 #[cfg(target_os = "freebsd")]
1385 pub mod consts {
1386     pub use os::arch_consts::ARCH;
1387
1388     pub static FAMILY: &'static str = "unix";
1389
1390     /// A string describing the specific operating system in use: in this
1391     /// case, `freebsd`.
1392     pub static SYSNAME: &'static str = "freebsd";
1393
1394     /// Specifies the filename prefix used for shared libraries on this
1395     /// platform: in this case, `lib`.
1396     pub static DLL_PREFIX: &'static str = "lib";
1397
1398     /// Specifies the filename suffix used for shared libraries on this
1399     /// platform: in this case, `.so`.
1400     pub static DLL_SUFFIX: &'static str = ".so";
1401
1402     /// Specifies the file extension used for shared libraries on this
1403     /// platform that goes after the dot: in this case, `so`.
1404     pub static DLL_EXTENSION: &'static str = "so";
1405
1406     /// Specifies the filename suffix used for executable binaries on this
1407     /// platform: in this case, the empty string.
1408     pub static EXE_SUFFIX: &'static str = "";
1409
1410     /// Specifies the file extension, if any, used for executable binaries
1411     /// on this platform: in this case, the empty string.
1412     pub static EXE_EXTENSION: &'static str = "";
1413 }
1414
1415 #[cfg(target_os = "android")]
1416 pub mod consts {
1417     pub use os::arch_consts::ARCH;
1418
1419     pub static FAMILY: &'static str = "unix";
1420
1421     /// A string describing the specific operating system in use: in this
1422     /// case, `android`.
1423     pub static SYSNAME: &'static str = "android";
1424
1425     /// Specifies the filename prefix used for shared libraries on this
1426     /// platform: in this case, `lib`.
1427     pub static DLL_PREFIX: &'static str = "lib";
1428
1429     /// Specifies the filename suffix used for shared libraries on this
1430     /// platform: in this case, `.so`.
1431     pub static DLL_SUFFIX: &'static str = ".so";
1432
1433     /// Specifies the file extension used for shared libraries on this
1434     /// platform that goes after the dot: in this case, `so`.
1435     pub static DLL_EXTENSION: &'static str = "so";
1436
1437     /// Specifies the filename suffix used for executable binaries on this
1438     /// platform: in this case, the empty string.
1439     pub static EXE_SUFFIX: &'static str = "";
1440
1441     /// Specifies the file extension, if any, used for executable binaries
1442     /// on this platform: in this case, the empty string.
1443     pub static EXE_EXTENSION: &'static str = "";
1444 }
1445
1446 #[cfg(target_os = "win32")]
1447 pub mod consts {
1448     pub use os::arch_consts::ARCH;
1449
1450     pub static FAMILY: &'static str = "windows";
1451
1452     /// A string describing the specific operating system in use: in this
1453     /// case, `win32`.
1454     pub static SYSNAME: &'static str = "win32";
1455
1456     /// Specifies the filename prefix used for shared libraries on this
1457     /// platform: in this case, the empty string.
1458     pub static DLL_PREFIX: &'static str = "";
1459
1460     /// Specifies the filename suffix used for shared libraries on this
1461     /// platform: in this case, `.dll`.
1462     pub static DLL_SUFFIX: &'static str = ".dll";
1463
1464     /// Specifies the file extension used for shared libraries on this
1465     /// platform that goes after the dot: in this case, `dll`.
1466     pub static DLL_EXTENSION: &'static str = "dll";
1467
1468     /// Specifies the filename suffix used for executable binaries on this
1469     /// platform: in this case, `.exe`.
1470     pub static EXE_SUFFIX: &'static str = ".exe";
1471
1472     /// Specifies the file extension, if any, used for executable binaries
1473     /// on this platform: in this case, `exe`.
1474     pub static EXE_EXTENSION: &'static str = "exe";
1475 }
1476
1477 #[cfg(target_arch = "x86")]
1478 mod arch_consts {
1479     pub static ARCH: &'static str = "x86";
1480 }
1481
1482 #[cfg(target_arch = "x86_64")]
1483 mod arch_consts {
1484     pub static ARCH: &'static str = "x86_64";
1485 }
1486
1487 #[cfg(target_arch = "arm")]
1488 mod arch_consts {
1489     pub static ARCH: &'static str = "arm";
1490 }
1491
1492 #[cfg(target_arch = "mips")]
1493 mod arch_consts {
1494     pub static ARCH: &'static str = "mips";
1495 }
1496
1497
1498 #[cfg(test)]
1499 mod tests {
1500     use prelude::*;
1501     use c_str::ToCStr;
1502     use option;
1503     use os::{env, getcwd, getenv, make_absolute};
1504     use os::{setenv, unsetenv};
1505     use os;
1506     use rand::Rng;
1507     use rand;
1508
1509     #[test]
1510     pub fn last_os_error() {
1511         debug!("{}", os::last_os_error());
1512     }
1513
1514     fn make_rand_name() -> String {
1515         let mut rng = rand::task_rng();
1516         let n = format_strbuf!("TEST{}", rng.gen_ascii_str(10u).as_slice());
1517         assert!(getenv(n.as_slice()).is_none());
1518         n
1519     }
1520
1521     #[test]
1522     fn test_setenv() {
1523         let n = make_rand_name();
1524         setenv(n.as_slice(), "VALUE");
1525         assert_eq!(getenv(n.as_slice()), option::Some("VALUE".to_string()));
1526     }
1527
1528     #[test]
1529     fn test_unsetenv() {
1530         let n = make_rand_name();
1531         setenv(n.as_slice(), "VALUE");
1532         unsetenv(n.as_slice());
1533         assert_eq!(getenv(n.as_slice()), option::None);
1534     }
1535
1536     #[test]
1537     #[ignore]
1538     fn test_setenv_overwrite() {
1539         let n = make_rand_name();
1540         setenv(n.as_slice(), "1");
1541         setenv(n.as_slice(), "2");
1542         assert_eq!(getenv(n.as_slice()), option::Some("2".to_string()));
1543         setenv(n.as_slice(), "");
1544         assert_eq!(getenv(n.as_slice()), option::Some("".to_string()));
1545     }
1546
1547     // Windows GetEnvironmentVariable requires some extra work to make sure
1548     // the buffer the variable is copied into is the right size
1549     #[test]
1550     #[ignore]
1551     fn test_getenv_big() {
1552         let mut s = "".to_string();
1553         let mut i = 0;
1554         while i < 100 {
1555             s.push_str("aaaaaaaaaa");
1556             i += 1;
1557         }
1558         let n = make_rand_name();
1559         setenv(n.as_slice(), s.as_slice());
1560         debug!("{}", s.clone());
1561         assert_eq!(getenv(n.as_slice()), option::Some(s));
1562     }
1563
1564     #[test]
1565     fn test_self_exe_name() {
1566         let path = os::self_exe_name();
1567         assert!(path.is_some());
1568         let path = path.unwrap();
1569         debug!("{:?}", path.clone());
1570
1571         // Hard to test this function
1572         assert!(path.is_absolute());
1573     }
1574
1575     #[test]
1576     fn test_self_exe_path() {
1577         let path = os::self_exe_path();
1578         assert!(path.is_some());
1579         let path = path.unwrap();
1580         debug!("{:?}", path.clone());
1581
1582         // Hard to test this function
1583         assert!(path.is_absolute());
1584     }
1585
1586     #[test]
1587     #[ignore]
1588     fn test_env_getenv() {
1589         let e = env();
1590         assert!(e.len() > 0u);
1591         for p in e.iter() {
1592             let (n, v) = (*p).clone();
1593             debug!("{:?}", n.clone());
1594             let v2 = getenv(n.as_slice());
1595             // MingW seems to set some funky environment variables like
1596             // "=C:=C:\MinGW\msys\1.0\bin" and "!::=::\" that are returned
1597             // from env() but not visible from getenv().
1598             assert!(v2.is_none() || v2 == option::Some(v));
1599         }
1600     }
1601
1602     #[test]
1603     fn test_env_set_get_huge() {
1604         let n = make_rand_name();
1605         let s = "x".repeat(10000).to_string();
1606         setenv(n.as_slice(), s.as_slice());
1607         assert_eq!(getenv(n.as_slice()), Some(s));
1608         unsetenv(n.as_slice());
1609         assert_eq!(getenv(n.as_slice()), None);
1610     }
1611
1612     #[test]
1613     fn test_env_setenv() {
1614         let n = make_rand_name();
1615
1616         let mut e = env();
1617         setenv(n.as_slice(), "VALUE");
1618         assert!(!e.contains(&(n.clone(), "VALUE".to_string())));
1619
1620         e = env();
1621         assert!(e.contains(&(n, "VALUE".to_string())));
1622     }
1623
1624     #[test]
1625     fn test() {
1626         assert!((!Path::new("test-path").is_absolute()));
1627
1628         let cwd = getcwd();
1629         debug!("Current working directory: {}", cwd.display());
1630
1631         debug!("{:?}", make_absolute(&Path::new("test-path")));
1632         debug!("{:?}", make_absolute(&Path::new("/usr/bin")));
1633     }
1634
1635     #[test]
1636     #[cfg(unix)]
1637     fn homedir() {
1638         let oldhome = getenv("HOME");
1639
1640         setenv("HOME", "/home/MountainView");
1641         assert!(os::homedir() == Some(Path::new("/home/MountainView")));
1642
1643         setenv("HOME", "");
1644         assert!(os::homedir().is_none());
1645
1646         for s in oldhome.iter() {
1647             setenv("HOME", s.as_slice())
1648         }
1649     }
1650
1651     #[test]
1652     #[cfg(windows)]
1653     fn homedir() {
1654
1655         let oldhome = getenv("HOME");
1656         let olduserprofile = getenv("USERPROFILE");
1657
1658         setenv("HOME", "");
1659         setenv("USERPROFILE", "");
1660
1661         assert!(os::homedir().is_none());
1662
1663         setenv("HOME", "/home/MountainView");
1664         assert!(os::homedir() == Some(Path::new("/home/MountainView")));
1665
1666         setenv("HOME", "");
1667
1668         setenv("USERPROFILE", "/home/MountainView");
1669         assert!(os::homedir() == Some(Path::new("/home/MountainView")));
1670
1671         setenv("HOME", "/home/MountainView");
1672         setenv("USERPROFILE", "/home/PaloAlto");
1673         assert!(os::homedir() == Some(Path::new("/home/MountainView")));
1674
1675         for s in oldhome.iter() {
1676             setenv("HOME", s.as_slice())
1677         }
1678         for s in olduserprofile.iter() {
1679             setenv("USERPROFILE", s.as_slice())
1680         }
1681     }
1682
1683     #[test]
1684     fn memory_map_rw() {
1685         use result::{Ok, Err};
1686
1687         let chunk = match os::MemoryMap::new(16, [
1688             os::MapReadable,
1689             os::MapWritable
1690         ]) {
1691             Ok(chunk) => chunk,
1692             Err(msg) => fail!("{}", msg)
1693         };
1694         assert!(chunk.len >= 16);
1695
1696         unsafe {
1697             *chunk.data = 0xBE;
1698             assert!(*chunk.data == 0xBE);
1699         }
1700     }
1701
1702     #[test]
1703     fn memory_map_file() {
1704         use result::{Ok, Err};
1705         use os::*;
1706         use libc::*;
1707         use io::fs;
1708
1709         #[cfg(unix)]
1710         fn lseek_(fd: c_int, size: uint) {
1711             unsafe {
1712                 assert!(lseek(fd, size as off_t, SEEK_SET) == size as off_t);
1713             }
1714         }
1715         #[cfg(windows)]
1716         fn lseek_(fd: c_int, size: uint) {
1717            unsafe {
1718                assert!(lseek(fd, size as c_long, SEEK_SET) == size as c_long);
1719            }
1720         }
1721
1722         let mut path = tmpdir();
1723         path.push("mmap_file.tmp");
1724         let size = MemoryMap::granularity() * 2;
1725
1726         let fd = unsafe {
1727             let fd = path.with_c_str(|path| {
1728                 open(path, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR)
1729             });
1730             lseek_(fd, size);
1731             "x".with_c_str(|x| assert!(write(fd, x as *c_void, 1) == 1));
1732             fd
1733         };
1734         let chunk = match MemoryMap::new(size / 2, [
1735             MapReadable,
1736             MapWritable,
1737             MapFd(fd),
1738             MapOffset(size / 2)
1739         ]) {
1740             Ok(chunk) => chunk,
1741             Err(msg) => fail!("{}", msg)
1742         };
1743         assert!(chunk.len > 0);
1744
1745         unsafe {
1746             *chunk.data = 0xbe;
1747             assert!(*chunk.data == 0xbe);
1748             close(fd);
1749         }
1750         drop(chunk);
1751
1752         fs::unlink(&path).unwrap();
1753     }
1754
1755     // More recursive_mkdir tests are in extra::tempfile
1756 }