(index<- )        ./libstd/os.rs

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


libstd/os.rs:261:40-261:40 -fn- definition:
/// Fails if `n` has any interior NULs.
pub fn getenv_as_bytes(n: &str) -> Option<~[u8]> {
    use c_str::CString;
references:- 2
libstd/unstable/dynamic_lib.rs:
77:         };
78:         let newenv = os::getenv_as_bytes(envvar).unwrap_or(box []);
79:         let mut newenv = newenv.move_iter().collect::<Vec<_>>();
libstd/os.rs:
251: pub fn getenv(n: &str) -> Option<~str> {
252:     getenv_as_bytes(n).map(|v| str::from_utf8_lossy(v).into_owned())
253: }


libstd/os.rs:816:30-816:30 -fn- definition:
fn real_args_as_bytes() -> Vec<~[u8]> {
    use rt;
    match rt::args::clone() {
references:- 2
827: fn real_args() -> Vec<~str> {
828:     real_args_as_bytes().move_iter().map(|v| str::from_utf8_lossy(v).into_owned()).collect()
829: }
--
892: pub fn args_as_bytes() -> Vec<~[u8]> {
893:     real_args_as_bytes()
894: }


libstd/os.rs:155:3-155:3 -fn- definition:
*/
fn with_env_lock<T>(f: || -> T) -> T {
    use unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
references:- 4
345:         unsafe {
346:             with_env_lock(|| {
347:                 n.with_c_str(|nbuf| {


libstd/os.rs:619:49-619:49 -fn- definition:
/// Returns the platform-specific value of errno
pub fn errno() -> int {
    #[cfg(target_os = "macos")]
references:- 3
1108:         if r.equiv(&libc::MAP_FAILED) {
1109:             Err(match errno() as c_int {
1110:                 libc::EACCES => ErrFdNotAvail,
libstd/io/mod.rs:
383:     pub fn last_error() -> IoError {
384:         IoError::from_errno(os::errno() as uint, true)
385:     }


libstd/os.rs:663:71-663:71 -fn- definition:
/// Return the string corresponding to an `errno()` value of `errnum`.
pub fn error_string(errnum: uint) -> ~str {
    return strerror(errnum);
references:- 2
libstd/io/mod.rs:
372:             desc: desc,
373:             detail: if detail {Some(os::error_string(errno))} else {None},
374:         }
libstd/os.rs:
765: pub fn last_os_error() -> ~str {
766:     error_string(errno() as uint)
767: }


libstd/os.rs:918:13-918:13 -fn- definition:
pub fn page_size() -> uint {
    unsafe {
        libc::sysconf(libc::_SC_PAGESIZE) as uint
references:- 3
1082:         let mut custom_flags = false;
1083:         let len = round_up(min_len, page_size());
libstd/rt/thread.rs:
246:                 // Round up to the neareast page and try again.
247:                 let page_size = os::page_size();
248:                 let stack_size = (stack_size + page_size - 1) & (-(page_size - 1) - 1);
libstd/os.rs:
1132:     pub fn granularity() -> uint {
1133:         page_size()
1134:     }


libstd/os.rs:368:35-368:35 -struct- definition:
/// A low-level OS in-memory pipe.
pub struct Pipe {
    /// A file descriptor representing the reading end of the pipe. Data written
references:- 3
381:     unsafe {
382:         let mut fds = Pipe {input: 0,
383:                             out: 0};
384:         assert_eq!(libc::pipe(&mut fds.input), 0);
385:         return Pipe {input: fds.input, out: fds.out};
386:     }


libstd/os.rs:66:13-66:13 -fn- definition:
pub fn getcwd() -> Path {
    use c_str::CString;
    let mut buf = [0 as c_char, ..BUF_BYTES];
references:- 2
libstd/io/test.rs:
114:     // FIXME (#9639): This needs to handle non-utf8 paths
115:     let path = os::getcwd();
116:     let path_s = path.as_str().unwrap();
libstd/os.rs:
586:     } else {
587:         let mut ret = getcwd();
588:         ret.push(p);


libstd/os.rs:988:41-988:41 -enum- definition:
/// Possible errors when creating a map.
pub enum MapError {
    /// ## The following are POSIX-specific
references:- 2
1033: impl fmt::Show for MapError {
1034:     fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
--
1069:     /// `ErrZeroLength`.
1070:     pub fn new(min_len: uint, options: &[MapOption]) -> Result<MemoryMap, MapError> {
1071:         use libc::off_t;


libstd/os.rs:944:67-944:67 -struct- definition:
/// let it leave scope by accident if you want it to stick around.
pub struct MemoryMap {
    /// Pointer to the memory created or modified by this map.
references:- 4
1117:         } else {
1118:             Ok(MemoryMap {
1119:                data: r as *mut u8,
--
1138: impl Drop for MemoryMap {
1139:     /// Unmap the mapping. Fails the task if `munmap` fails.


libstd/os.rs:764:64-764:64 -fn- definition:
/// Get a string representing the platform-dependent last error
pub fn last_os_error() -> ~str {
    error_string(errno() as uint)
references:- 3
213:                 fail!("os::env() failure getting env string from OS: {}",
214:                        os::last_os_error());
215:             }
libstd/rt/thread.rs:
252:                 // This cannot really happen.
253:                 fail!("pthread_attr_setstacksize() error: {} ({})", os::last_os_error(), errno);
254:             },
--
263:             let _p: Box<proc():Send> = cast::transmute(arg);
264:             fail!("failed to spawn native thread: {}", os::last_os_error());
265:         }


libstd/os.rs:539:4-539:4 -fn- definition:
 */
pub fn tmpdir() -> Path {
    return lookup();
references:- 2
libstd/io/tempfile.rs:
62:     pub fn new(suffix: &str) -> Option<TempDir> {
63:         TempDir::new_in(&os::tmpdir(), suffix)
64:     }
libstd/io/test.rs:
74:     if cfg!(unix) {
75:         os::tmpdir().join(string)
76:     } else {


libstd/os.rs:415:54-415:54 -fn- definition:
/// running. If any failure occurs, None is returned.
pub fn self_exe_name() -> Option<Path> {
    #[cfg(target_os = "freebsd")]
references:- 2
487: pub fn self_exe_path() -> Option<Path> {
488:     self_exe_name().map(|mut p| { p.pop(); p })
489: }
libstd/rt/backtrace.rs:
428:             let selfname = if cfg!(target_os = "freebsd") {
429:                 os::self_exe_name()
430:             } else {


libstd/os.rs:250:40-250:40 -fn- definition:
/// Fails if `n` has any interior NULs.
pub fn getenv(n: &str) -> Option<~str> {
    getenv_as_bytes(n).map(|v| str::from_utf8_lossy(v).into_owned())
references:- 7
543:     fn getenv_nonempty(v: &str) -> Option<Path> {
544:         match getenv(v) {
545:             Some(x) =>
libstd/rt/env.rs:
33:         }
34:         match os::getenv("RUST_MAX_CACHED_STACKS") {
35:             Some(max) => MAX_CACHED_STACKS = from_str(max).expect("expected positive integer in \
--
38:         }
39:         match os::getenv("RUST_DEBUG_BORROW") {
40:             Some(_) => DEBUG_BORROW = true,
libstd/rt/backtrace.rs:
40:     let val = match os::getenv("RUST_BACKTRACE") {
41:         Some(..) => 2,
libstd/rt/util.rs:
55: pub fn default_sched_threads() -> uint {
56:     match os::getenv("RUST_THREADS") {
57:         Some(nstr) => {
libstd/os.rs:
505:     // FIXME (#7188): getenv needs a ~[u8] variant
506:     return match getenv("HOME") {
507:         Some(ref p) if !p.is_empty() => Path::new_opt(p.as_slice()),