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