(index<- )        ./libstd/rt/io/native/process.rs

   1  // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
   2  // file at the top-level directory of this distribution and at
   3  // http://rust-lang.org/COPYRIGHT.
   4  //
   5  // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
   6  // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
   7  // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
   8  // option. This file may not be copied, modified, or distributed
   9  // except according to those terms.
  10  
  11  use cast;
  12  use libc::{pid_t, c_void, c_int};
  13  use libc;
  14  use os;
  15  use prelude::*;
  16  use ptr;
  17  use rt::io;
  18  use super::file;
  19  
  20  /**
  21   * A value representing a child process.
  22   *
  23   * The lifetime of this value is linked to the lifetime of the actual
  24   * process - the Process destructor calls self.finish() which waits
  25   * for the process to terminate.
  26   */
  27  pub struct Process {
  28      /// The unique id of the process (this should never be negative).
  29      priv pid: pid_t,
  30  
  31      /// A handle to the process - on unix this will always be NULL, but on
  32      /// windows it will be a HANDLE to the process, which will prevent the
  33      /// pid being re-used until the handle is closed.
  34      priv handle: *(),
  35  
  36      /// Currently known stdin of the child, if any
  37      priv input: Option<file::FileDesc>,
  38      /// Currently known stdout of the child, if any
  39      priv output: Option<file::FileDesc>,
  40      /// Currently known stderr of the child, if any
  41      priv error: Option<file::FileDesc>,
  42  
  43      /// None until finish() is called.
  44      priv exit_code: Option<int>,
  45  }
  46  
  47  impl Process {
  48      /// Creates a new process using native process-spawning abilities provided
  49      /// by the OS. Operations on this process will be blocking instead of using
  50      /// the runtime for sleeping just this current task.
  51      ///
  52      /// # Arguments
  53      ///
  54      /// * prog - the program to run
  55      /// * args - the arguments to pass to the program, not including the program
  56      ///          itself
  57      /// * env - an optional envrionment to specify for the child process. If
  58      ///         this value is `None`, then the child will inherit the parent's
  59      ///         environment
  60      /// * cwd - an optionally specified current working directory of the child,
  61      ///         defaulting to the parent's current working directory
  62      /// * stdin, stdout, stderr - These optionally specified file descriptors
  63      ///     dictate where the stdin/out/err of the child process will go. If
  64      ///     these are `None`, then this module will bind the input/output to an
  65      ///     os pipe instead. This process takes ownership of these file
  66      ///     descriptors, closing them upon destruction of the process.
  67      pub fn new(prog&str, args&[~str], envOption<~[(~str, ~str)]>,
  68                 cwdOption<&Path>,
  69                 stdinOption<file::fd_t>,
  70                 stdoutOption<file::fd_t>,
  71                 stderrOption<file::fd_t>) -> Process {
  72          #[fixed_stack_segment]; #[inline(never)];
  73  
  74          let (in_pipe, in_fd) = match stdin {
  75              None => {
  76                  let pipe = os::pipe();
  77                  (Some(pipe), pipe.input)
  78              },
  79              Some(fd) => (None, fd)
  80          };
  81          let (out_pipe, out_fd) = match stdout {
  82              None => {
  83                  let pipe = os::pipe();
  84                  (Some(pipe), pipe.out)
  85              },
  86              Some(fd) => (None, fd)
  87          };
  88          let (err_pipe, err_fd) = match stderr {
  89              None => {
  90                  let pipe = os::pipe();
  91                  (Some(pipe), pipe.out)
  92              },
  93              Some(fd) => (None, fd)
  94          };
  95  
  96          let res = spawn_process_os(prog, args, env, cwd,
  97                                     in_fd, out_fd, err_fd);
  98  
  99          unsafe {
 100              for pipe in in_pipe.iter() { libc::close(pipe.input); }
 101              for pipe in out_pipe.iter() { libc::close(pipe.out); }
 102              for pipe in err_pipe.iter() { libc::close(pipe.out); }
 103          }
 104  
 105          Process {
 106              pid: res.pid,
 107              handle: res.handle,
 108              input: in_pipe.map(|pipe| file::FileDesc::new(pipe.out)),
 109              output: out_pipe.map(|pipe| file::FileDesc::new(pipe.input)),
 110              error: err_pipe.map(|pipe| file::FileDesc::new(pipe.input)),
 111              exit_code: None,
 112          }
 113      }
 114  
 115      /// Returns the unique id of the process
 116      pub fn id(&self) -> pid_t { self.pid }
 117  
 118      /**
 119       * Returns an io::Writer that can be used to write to this Process's stdin.
 120       *
 121       * Fails if there is no stdinavailable (it's already been removed by
 122       * take_input)
 123       */
 124      pub fn input<'a>(&'a mut self) -> &'a mut io::Writer {
 125          match self.input {
 126              Some(ref mut fd) => fd as &mut io::Writer,
 127              None => fail2!("This process has no stdin")
 128          }
 129      }
 130  
 131      /**
 132       * Returns an io::Reader that can be used to read from this Process's
 133       * stdout.
 134       *
 135       * Fails if there is no stdin available (it's already been removed by
 136       * take_output)
 137       */
 138      pub fn output<'a>(&'a mut self) -> &'a mut io::Reader {
 139          match self.input {
 140              Some(ref mut fd) => fd as &mut io::Reader,
 141              None => fail2!("This process has no stdout")
 142          }
 143      }
 144  
 145      /**
 146       * Returns an io::Reader that can be used to read from this Process's
 147       * stderr.
 148       *
 149       * Fails if there is no stdin available (it's already been removed by
 150       * take_error)
 151       */
 152      pub fn error<'a>(&'a mut self) -> &'a mut io::Reader {
 153          match self.error {
 154              Some(ref mut fd) => fd as &mut io::Reader,
 155              None => fail2!("This process has no stderr")
 156          }
 157      }
 158  
 159      /**
 160       * Takes the stdin of this process, transferring ownership to the caller.
 161       * Note that when the return value is destroyed, the handle will be closed
 162       * for the child process.
 163       */
 164      pub fn take_input(&mut self) -> Option<~io::Writer> {
 165          self.input.take().map(|fd| ~fd as ~io::Writer)
 166      }
 167  
 168      /**
 169       * Takes the stdout of this process, transferring ownership to the caller.
 170       * Note that when the return value is destroyed, the handle will be closed
 171       * for the child process.
 172       */
 173      pub fn take_output(&mut self) -> Option<~io::Reader> {
 174          self.output.take().map(|fd| ~fd as ~io::Reader)
 175      }
 176  
 177      /**
 178       * Takes the stderr of this process, transferring ownership to the caller.
 179       * Note that when the return value is destroyed, the handle will be closed
 180       * for the child process.
 181       */
 182      pub fn take_error(&mut self) -> Option<~io::Reader> {
 183          self.error.take().map(|fd| ~fd as ~io::Reader)
 184      }
 185  
 186      pub fn wait(&mut self) -> int {
 187          for &code in self.exit_code.iter() {
 188              return code;
 189          }
 190          let code = waitpid(self.pid);
 191          self.exit_code = Some(code);
 192          return code;
 193      }
 194  
 195      pub fn signal(&mut self, signumint) -> Result<(), io::IoError> {
 196          // if the process has finished, and therefore had waitpid called,
 197          // and we kill it, then on unix we might ending up killing a
 198          // newer process that happens to have the same (re-used) id
 199          match self.exit_code {
 200              Some(*) => return Err(io::IoError {
 201                  kind: io::OtherIoError,
 202                  desc: "can't kill an exited process",
 203                  detail: None,
 204              }),
 205              None => {}
 206          }
 207          return unsafe { killpid(self.pid, signum) };
 208  
 209          #[cfg(windows)]
 210          unsafe fn killpid(pid: pid_t, signal: int) -> Result<(), io::IoError> {
 211              #[fixed_stack_segment]; #[inline(never)];
 212              match signal {
 213                  io::process::PleaseExitSignal |
 214                  io::process::MustDieSignal => {
 215                      libc::funcs::extra::kernel32::TerminateProcess(
 216                          cast::transmute(pid), 1);
 217                      Ok(())
 218                  }
 219                  _ => Err(io::IoError {
 220                      kind: io::OtherIoError,
 221                      desc: "unsupported signal on windows",
 222                      detail: None,
 223                  })
 224              }
 225          }
 226  
 227          #[cfg(not(windows))]
 228          unsafe fn killpid(pidpid_t, signalint) -> Result<(), io::IoError> {
 229              #[fixed_stack_segment]; #[inline(never)];
 230              libc::funcs::posix88::signal::kill(pid, signal as c_int);
 231              Ok(())
 232          }
 233      }
 234  }
 235  
 236  impl Drop for Process {
 237      fn drop(&mut self) {
 238          // close all these handles
 239          self.take_input();
 240          self.take_output();
 241          self.take_error();
 242          self.wait();
 243          free_handle(self.handle);
 244      }
 245  }
 246  
 247  struct SpawnProcessResult {
 248      pid: pid_t,
 249      handle: *(),
 250  }
 251  
 252  #[cfg(windows)]
 253  fn spawn_process_os(prog: &str, args: &[~str],
 254                      env: Option<~[(~str, ~str)]>,
 255                      dir: Option<&Path>,
 256                      in_fd: c_int, out_fd: c_int, err_fd: c_int) -> SpawnProcessResult {
 257      #[fixed_stack_segment]; #[inline(never)];
 258  
 259      use libc::types::os::arch::extra::{DWORD, HANDLE, STARTUPINFO};
 260      use libc::consts::os::extra::{
 261          TRUE, FALSE,
 262          STARTF_USESTDHANDLES,
 263          INVALID_HANDLE_VALUE,
 264          DUPLICATE_SAME_ACCESS
 265      };
 266      use libc::funcs::extra::kernel32::{
 267          GetCurrentProcess,
 268          DuplicateHandle,
 269          CloseHandle,
 270          CreateProcessA
 271      };
 272      use libc::funcs::extra::msvcrt::get_osfhandle;
 273  
 274      use sys;
 275  
 276      unsafe {
 277  
 278          let mut si = zeroed_startupinfo();
 279          si.cb = sys::size_of::<STARTUPINFO>() as DWORD;
 280          si.dwFlags = STARTF_USESTDHANDLES;
 281  
 282          let cur_proc = GetCurrentProcess();
 283  
 284          let orig_std_in = get_osfhandle(in_fd) as HANDLE;
 285          if orig_std_in == INVALID_HANDLE_VALUE as HANDLE {
 286              fail2!("failure in get_osfhandle: {}", os::last_os_error());
 287          }
 288          if DuplicateHandle(cur_proc, orig_std_in, cur_proc, &mut si.hStdInput,
 289                             0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE {
 290              fail2!("failure in DuplicateHandle: {}", os::last_os_error());
 291          }
 292  
 293          let orig_std_out = get_osfhandle(out_fd) as HANDLE;
 294          if orig_std_out == INVALID_HANDLE_VALUE as HANDLE {
 295              fail2!("failure in get_osfhandle: {}", os::last_os_error());
 296          }
 297          if DuplicateHandle(cur_proc, orig_std_out, cur_proc, &mut si.hStdOutput,
 298                             0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE {
 299              fail2!("failure in DuplicateHandle: {}", os::last_os_error());
 300          }
 301  
 302          let orig_std_err = get_osfhandle(err_fd) as HANDLE;
 303          if orig_std_err == INVALID_HANDLE_VALUE as HANDLE {
 304              fail2!("failure in get_osfhandle: {}", os::last_os_error());
 305          }
 306          if DuplicateHandle(cur_proc, orig_std_err, cur_proc, &mut si.hStdError,
 307                             0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE {
 308              fail2!("failure in DuplicateHandle: {}", os::last_os_error());
 309          }
 310  
 311          let cmd = make_command_line(prog, args);
 312          let mut pi = zeroed_process_information();
 313          let mut create_err = None;
 314  
 315          do with_envp(env) |envp| {
 316              do with_dirp(dir) |dirp| {
 317                  do cmd.with_c_str |cmdp| {
 318                      let created = CreateProcessA(ptr::null(), cast::transmute(cmdp),
 319                                                   ptr::mut_null(), ptr::mut_null(), TRUE,
 320                                                   0, envp, dirp, &mut si, &mut pi);
 321                      if created == FALSE {
 322                          create_err = Some(os::last_os_error());
 323                      }
 324                  }
 325              }
 326          }
 327  
 328          CloseHandle(si.hStdInput);
 329          CloseHandle(si.hStdOutput);
 330          CloseHandle(si.hStdError);
 331  
 332          for msg in create_err.iter() {
 333              fail2!("failure in CreateProcess: {}", *msg);
 334          }
 335  
 336          // We close the thread handle because we don't care about keeping the
 337          // thread id valid, and we aren't keeping the thread handle around to be
 338          // able to close it later. We don't close the process handle however
 339          // because we want the process id to stay valid at least until the
 340          // calling code closes the process handle.
 341          CloseHandle(pi.hThread);
 342  
 343          SpawnProcessResult {
 344              pid: pi.dwProcessId as pid_t,
 345              handle: pi.hProcess as *()
 346          }
 347      }
 348  }
 349  
 350  #[cfg(windows)]
 351  fn zeroed_startupinfo() -> libc::types::os::arch::extra::STARTUPINFO {
 352      libc::types::os::arch::extra::STARTUPINFO {
 353          cb: 0,
 354          lpReserved: ptr::mut_null(),
 355          lpDesktop: ptr::mut_null(),
 356          lpTitle: ptr::mut_null(),
 357          dwX: 0,
 358          dwY: 0,
 359          dwXSize: 0,
 360          dwYSize: 0,
 361          dwXCountChars: 0,
 362          dwYCountCharts: 0,
 363          dwFillAttribute: 0,
 364          dwFlags: 0,
 365          wShowWindow: 0,
 366          cbReserved2: 0,
 367          lpReserved2: ptr::mut_null(),
 368          hStdInput: ptr::mut_null(),
 369          hStdOutput: ptr::mut_null(),
 370          hStdError: ptr::mut_null()
 371      }
 372  }
 373  
 374  #[cfg(windows)]
 375  fn zeroed_process_information() -> libc::types::os::arch::extra::PROCESS_INFORMATION {
 376      libc::types::os::arch::extra::PROCESS_INFORMATION {
 377          hProcess: ptr::mut_null(),
 378          hThread: ptr::mut_null(),
 379          dwProcessId: 0,
 380          dwThreadId: 0
 381      }
 382  }
 383  
 384  // FIXME: this is only pub so it can be tested (see issue #4536)
 385  #[cfg(windows)]
 386  pub fn make_command_line(prog: &str, args: &[~str]) -> ~str {
 387      let mut cmd = ~"";
 388      append_arg(&mut cmd, prog);
 389      for arg in args.iter() {
 390          cmd.push_char(' ');
 391          append_arg(&mut cmd, *arg);
 392      }
 393      return cmd;
 394  
 395      fn append_arg(cmd: &mut ~str, arg: &str) {
 396          let quote = arg.iter().any(|c| c == ' ' || c == '\t');
 397          if quote {
 398              cmd.push_char('"');
 399          }
 400          for i in range(0u, arg.len()) {
 401              append_char_at(cmd, arg, i);
 402          }
 403          if quote {
 404              cmd.push_char('"');
 405          }
 406      }
 407  
 408      fn append_char_at(cmd: &mut ~str, arg: &str, i: uint) {
 409          match arg[i] as char {
 410              '"' => {
 411                  // Escape quotes.
 412                  cmd.push_str("\\\"");
 413              }
 414              '\\' => {
 415                  if backslash_run_ends_in_quote(arg, i) {
 416                      // Double all backslashes that are in runs before quotes.
 417                      cmd.push_str("\\\\");
 418                  } else {
 419                      // Pass other backslashes through unescaped.
 420                      cmd.push_char('\\');
 421                  }
 422              }
 423              c => {
 424                  cmd.push_char(c);
 425              }
 426          }
 427      }
 428  
 429      fn backslash_run_ends_in_quote(s: &str, mut i: uint) -> bool {
 430          while i < s.len() && s[i] as char == '\\' {
 431              i += 1;
 432          }
 433          return i < s.len() && s[i] as char == '"';
 434      }
 435  }
 436  
 437  #[cfg(unix)]
 438  fn spawn_process_os(prog&str, args&[~str],
 439                      envOption<~[(~str, ~str)]>,
 440                      dirOption<&Path>,
 441                      in_fdc_int, out_fdc_int, err_fdc_int) -> SpawnProcessResult {
 442      #[fixed_stack_segment]; #[inline(never)];
 443  
 444      use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp};
 445      use libc::funcs::bsd44::getdtablesize;
 446  
 447      mod rustrt {
 448          #[abi = "cdecl"]
 449          extern {
 450              pub fn rust_unset_sigprocmask();
 451          }
 452      }
 453  
 454      #[cfg(windows)]
 455      unsafe fn set_environ(_envp: *c_void) {}
 456      #[cfg(target_os = "macos")]
 457      unsafe fn set_environ(envp: *c_void) {
 458          externfn!(fn _NSGetEnviron() -> *mut *c_void);
 459  
 460          *_NSGetEnviron() = envp;
 461      }
 462      #[cfg(not(target_os = "macos"), not(windows))]
 463      unsafe fn set_environ(envp*c_void) {
 464          extern {
 465              static mut environ: *c_void;
 466          }
 467          environ = envp;
 468      }
 469  
 470      unsafe {
 471  
 472          let pid = fork();
 473          if pid < 0 {
 474              fail2!("failure in fork: {}", os::last_os_error());
 475          } else if pid > 0 {
 476              return SpawnProcessResult {pid: pid, handle: ptr::null()};
 477          }
 478  
 479          rustrt::rust_unset_sigprocmask();
 480  
 481          if dup2(in_fd, 0) == -1 {
 482              fail2!("failure in dup2(in_fd, 0){}", os::last_os_error());
 483          }
 484          if dup2(out_fd, 1) == -1 {
 485              fail2!("failure in dup2(out_fd, 1){}", os::last_os_error());
 486          }
 487          if dup2(err_fd, 2) == -1 {
 488              fail2!("failure in dup3(err_fd, 2){}", os::last_os_error());
 489          }
 490          // close all other fds
 491          for fd in range(3, getdtablesize()).invert() {
 492              close(fd as c_int);
 493          }
 494  
 495          do with_dirp(dir) |dirp| {
 496              if !dirp.is_null() && chdir(dirp) == -1 {
 497                  fail2!("failure in chdir: {}", os::last_os_error());
 498              }
 499          }
 500  
 501          do with_envp(env) |envp| {
 502              if !envp.is_null() {
 503                  set_environ(envp);
 504              }
 505              do with_argv(prog, args) |argv| {
 506                  execvp(*argv, argv);
 507                  // execvp only returns if an error occurred
 508                  fail2!("failure in execvp: {}", os::last_os_error());
 509              }
 510          }
 511      }
 512  }
 513  
 514  #[cfg(unix)]
 515  fn with_argv<T>(prog&str, args&[~str], cb&fn(**libc::c_char) -> T) -> T {
 516      use vec;
 517  
 518      // We can't directly convert `str`s into `*char`s, as someone needs to hold
 519      // a reference to the intermediary byte buffers. So first build an array to
 520      // hold all the ~[u8] byte strings.
 521      let mut tmps = vec::with_capacity(args.len() + 1);
 522  
 523      tmps.push(prog.to_c_str());
 524  
 525      for arg in args.iter() {
 526          tmps.push(arg.to_c_str());
 527      }
 528  
 529      // Next, convert each of the byte strings into a pointer. This is
 530      // technically unsafe as the caller could leak these pointers out of our
 531      // scope.
 532      let mut ptrs = do tmps.map |tmp| {
 533          tmp.with_ref(|buf| buf)
 534      };
 535  
 536      // Finally, make sure we add a null pointer.
 537      ptrs.push(ptr::null());
 538  
 539      ptrs.as_imm_buf(|buf, _| cb(buf))
 540  }
 541  
 542  #[cfg(unix)]
 543  fn with_envp<T>(envOption<~[(~str, ~str)]>, cb&fn(*c_void) -> T) -> T {
 544      use vec;
 545  
 546      // On posixy systems we can pass a char** for envp, which is a
 547      // null-terminated array of "k=v\n" strings. Like `with_argv`, we have to
 548      // have a temporary buffer to hold the intermediary `~[u8]` byte strings.
 549      match env {
 550          Some(env) => {
 551              let mut tmps = vec::with_capacity(env.len());
 552  
 553              for pair in env.iter() {
 554                  let kv = format!("{}={}", pair.first(), pair.second());
 555                  tmps.push(kv.to_c_str());
 556              }
 557  
 558              // Once again, this is unsafe.
 559              let mut ptrs = do tmps.map |tmp| {
 560                  tmp.with_ref(|buf| buf)
 561              };
 562              ptrs.push(ptr::null());
 563  
 564              do ptrs.as_imm_buf |buf, _| {
 565                  unsafe { cb(cast::transmute(buf)) }
 566              }
 567          }
 568          _ => cb(ptr::null())
 569      }
 570  }
 571  
 572  #[cfg(windows)]
 573  fn with_envp<T>(env: Option<~[(~str, ~str)]>, cb: &fn(*mut c_void) -> T) -> T {
 574      // On win32 we pass an "environment block" which is not a char**, but
 575      // rather a concatenation of null-terminated k=v\0 sequences, with a final
 576      // \0 to terminate.
 577      match env {
 578          Some(env) => {
 579              let mut blk = ~[];
 580  
 581              for pair in env.iter() {
 582                  let kv = format!("{}={}", pair.first(), pair.second());
 583                  blk.push_all(kv.as_bytes());
 584                  blk.push(0);
 585              }
 586  
 587              blk.push(0);
 588  
 589              do blk.as_imm_buf |p, _len| {
 590                  unsafe { cb(cast::transmute(p)) }
 591              }
 592          }
 593          _ => cb(ptr::mut_null())
 594      }
 595  }
 596  
 597  fn with_dirp<T>(dOption<&Path>, cb&fn(*libc::c_char) -> T) -> T {
 598      match d {
 599        Some(dir) => dir.with_c_str(|buf| cb(buf)),
 600        None => cb(ptr::null())
 601      }
 602  }
 603  
 604  #[cfg(windows)]
 605  fn free_handle(handle: *()) {
 606      #[fixed_stack_segment]; #[inline(never)];
 607      unsafe {
 608          libc::funcs::extra::kernel32::CloseHandle(cast::transmute(handle));
 609      }
 610  }
 611  
 612  #[cfg(unix)]
 613  fn free_handle(_handle*()) {
 614      // unix has no process handle object, just a pid
 615  }
 616  
 617  /**
 618   * Waits for a process to exit and returns the exit code, failing
 619   * if there is no process with the specified id.
 620   *
 621   * Note that this is private to avoid race conditions on unix where if
 622   * a user calls waitpid(some_process.get_id()) then some_process.finish()
 623   * and some_process.destroy() and some_process.finalize() will then either
 624   * operate on a none-existent process or, even worse, on a newer process
 625   * with the same id.
 626   */
 627  fn waitpid(pidpid_t) -> int {
 628      return waitpid_os(pid);
 629  
 630      #[cfg(windows)]
 631      fn waitpid_os(pid: pid_t) -> int {
 632          #[fixed_stack_segment]; #[inline(never)];
 633  
 634          use libc::types::os::arch::extra::DWORD;
 635          use libc::consts::os::extra::{
 636              SYNCHRONIZE,
 637              PROCESS_QUERY_INFORMATION,
 638              FALSE,
 639              STILL_ACTIVE,
 640              INFINITE,
 641              WAIT_FAILED
 642          };
 643          use libc::funcs::extra::kernel32::{
 644              OpenProcess,
 645              GetExitCodeProcess,
 646              CloseHandle,
 647              WaitForSingleObject
 648          };
 649  
 650          unsafe {
 651  
 652              let proc = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, pid as DWORD);
 653              if proc.is_null() {
 654                  fail2!("failure in OpenProcess: {}", os::last_os_error());
 655              }
 656  
 657              loop {
 658                  let mut status = 0;
 659                  if GetExitCodeProcess(proc, &mut status) == FALSE {
 660                      CloseHandle(proc);
 661                      fail2!("failure in GetExitCodeProcess: {}", os::last_os_error());
 662                  }
 663                  if status != STILL_ACTIVE {
 664                      CloseHandle(proc);
 665                      return status as int;
 666                  }
 667                  if WaitForSingleObject(proc, INFINITE) == WAIT_FAILED {
 668                      CloseHandle(proc);
 669                      fail2!("failure in WaitForSingleObject: {}", os::last_os_error());
 670                  }
 671              }
 672          }
 673      }
 674  
 675      #[cfg(unix)]
 676      fn waitpid_os(pidpid_t) -> int {
 677          #[fixed_stack_segment]; #[inline(never)];
 678  
 679          use libc::funcs::posix01::wait::*;
 680  
 681          #[cfg(target_os = "linux")]
 682          #[cfg(target_os = "android")]
 683          fn WIFEXITED(statusi32) -> bool {
 684              (status & 0xffi32) == 0i32
 685          }
 686  
 687          #[cfg(target_os = "macos")]
 688          #[cfg(target_os = "freebsd")]
 689          fn WIFEXITED(status: i32) -> bool {
 690              (status & 0x7fi32) == 0i32
 691          }
 692  
 693          #[cfg(target_os = "linux")]
 694          #[cfg(target_os = "android")]
 695          fn WEXITSTATUS(statusi32) -> i32 {
 696              (status >> 8i32) & 0xffi32
 697          }
 698  
 699          #[cfg(target_os = "macos")]
 700          #[cfg(target_os = "freebsd")]
 701          fn WEXITSTATUS(status: i32) -> i32 {
 702              status >> 8i32
 703          }
 704  
 705          let mut status = 0 as c_int;
 706          if unsafe { waitpid(pid, &mut status, 0) } == -1 {
 707              fail2!("failure in waitpid: {}", os::last_os_error());
 708          }
 709  
 710          return if WIFEXITED(status) {
 711              WEXITSTATUS(status) as int
 712          } else {
 713              1
 714          };
 715      }
 716  }
 717  
 718  #[cfg(test)]
 719  mod tests {
 720  
 721      #[test] #[cfg(windows)]
 722      fn test_make_command_line() {
 723          use super::make_command_line;
 724          assert_eq!(
 725              make_command_line("prog", [~"aaa", ~"bbb", ~"ccc"]),
 726              ~"prog aaa bbb ccc"
 727          );
 728          assert_eq!(
 729              make_command_line("C:\\Program Files\\blah\\blah.exe", [~"aaa"]),
 730              ~"\"C:\\Program Files\\blah\\blah.exe\" aaa"
 731          );
 732          assert_eq!(
 733              make_command_line("C:\\Program Files\\test", [~"aa\"bb"]),
 734              ~"\"C:\\Program Files\\test\" aa\\\"bb"
 735          );
 736          assert_eq!(
 737              make_command_line("echo", [~"a b c"]),
 738              ~"echo \"a b c\""
 739          );
 740      }
 741  
 742      // Currently most of the tests of this functionality live inside std::run,
 743      // but they may move here eventually as a non-blocking backend is added to
 744      // std::run
 745  }

libstd/rt/io/native/process.rs:542:13-542:13 -fn- definition:
#[cfg(unix)]
fn with_envp<T>(env: Option<~[(~str, ~str)]>, cb: &fn(*c_void) -> T) -> T {
references:-
501:         do with_envp(env) |envp| {


libstd/rt/io/native/process.rs:514:13-514:13 -fn- definition:
#[cfg(unix)]
fn with_argv<T>(prog: &str, args: &[~str], cb: &fn(**libc::c_char) -> T) -> T {
references:-
505:             do with_argv(prog, args) |argv| {


libstd/rt/io/native/process.rs:695:8-695:8 -fn- definition:
        fn WEXITSTATUS(status: i32) -> i32 {
            (status >> 8i32) & 0xffi32
references:-
711:             WEXITSTATUS(status) as int


libstd/rt/io/native/process.rs:676:4-676:4 -fn- definition:
    fn waitpid_os(pid: pid_t) -> int {
        #[fixed_stack_segment]; #[inline(never)];
references:-
628:     return waitpid_os(pid);


libstd/rt/io/native/process.rs:463:4-463:4 -fn- definition:
    unsafe fn set_environ(envp: *c_void) {
        extern {
references:-
503:                 set_environ(envp);


libstd/rt/io/native/process.rs:228:8-228:8 -fn- definition:
        unsafe fn killpid(pid: pid_t, signal: int) -> Result<(), io::IoError> {
            #[fixed_stack_segment]; #[inline(never)];
references:-
207:         return unsafe { killpid(self.pid, signum) };


libstd/rt/io/native/process.rs:246:1-246:1 -struct- definition:

struct SpawnProcessResult {
references:-
441:                     in_fd: c_int, out_fd: c_int, err_fd: c_int) -> SpawnProcessResult {
476:             return SpawnProcessResult {pid: pid, handle: ptr::null()};


libstd/rt/io/native/process.rs:612:13-612:13 -fn- definition:
#[cfg(unix)]
fn free_handle(_handle: *()) {
references:-
243:         free_handle(self.handle);


libstd/rt/io/native/process.rs:683:8-683:8 -fn- definition:
        fn WIFEXITED(status: i32) -> bool {
            (status & 0xffi32) == 0i32
references:-
710:         return if WIFEXITED(status) {


libstd/rt/io/native/process.rs:626:4-626:4 -fn- definition:
 */
fn waitpid(pid: pid_t) -> int {
references:-
190:         let code = waitpid(self.pid);


libstd/rt/io/native/process.rs:596:1-596:1 -fn- definition:

fn with_dirp<T>(d: Option<&Path>, cb: &fn(*libc::c_char) -> T) -> T {
references:-
495:         do with_dirp(dir) |dirp| {


libstd/rt/io/native/process.rs:26:4-26:4 -struct- definition:
 */
pub struct Process {
references:-
47: impl Process {
236: impl Drop for Process {
71:                stderr: Option<file::fd_t>) -> Process {
105:         Process {
libstd/run.rs:
32:     priv inner: process::Process,


libstd/rt/io/native/process.rs:437:13-437:13 -fn- definition:
#[cfg(unix)]
fn spawn_process_os(prog: &str, args: &[~str],
references:-
96:         let res = spawn_process_os(prog, args, env, cwd,