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