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

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 2014
   1  // Copyright 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  //! Bindings for executing child processes
  12  
  13  use prelude::*;
  14  
  15  use fmt;
  16  use io::IoResult;
  17  use io;
  18  use libc;
  19  use mem;
  20  use owned::Box;
  21  use rt::rtio::{RtioProcess, IoFactory, LocalIo};
  22  
  23  /// Signal a process to exit, without forcibly killing it. Corresponds to
  24  /// SIGTERM on unix platforms.
  25  #[cfg(windows)] pub static PleaseExitSignal: int = 15;
  26  /// Signal a process to exit immediately, forcibly killing it. Corresponds to
  27  /// SIGKILL on unix platforms.
  28  #[cfg(windows)] pub static MustDieSignal: int = 9;
  29  /// Signal a process to exit, without forcibly killing it. Corresponds to
  30  /// SIGTERM on unix platforms.
  31  #[cfg(not(windows))] pub static PleaseExitSignal: int = libc::SIGTERM as int;
  32  /// Signal a process to exit immediately, forcibly killing it. Corresponds to
  33  /// SIGKILL on unix platforms.
  34  #[cfg(not(windows))] pub static MustDieSignal: int = libc::SIGKILL as int;
  35  
  36  /// Representation of a running or exited child process.
  37  ///
  38  /// This structure is used to create, run, and manage child processes. A process
  39  /// is configured with the `ProcessConfig` struct which contains specific
  40  /// options for dictating how the child is spawned.
  41  ///
  42  /// # Example
  43  ///
  44  /// ```should_fail
  45  /// use std::io::Process;
  46  ///
  47  /// let mut child = match Process::new("/bin/cat", ["file.txt".to_owned()]) {
  48  ///     Ok(child) => child,
  49  ///     Err(e) => fail!("failed to execute child: {}", e),
  50  /// };
  51  ///
  52  /// let contents = child.stdout.get_mut_ref().read_to_end();
  53  /// assert!(child.wait().success());
  54  /// ```
  55  pub struct Process {
  56      handle: Box<RtioProcess:Send>,
  57  
  58      /// Handle to the child's stdin, if the `stdin` field of this process's
  59      /// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`.
  60      pub stdin: Option<io::PipeStream>,
  61  
  62      /// Handle to the child's stdout, if the `stdout` field of this process's
  63      /// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`.
  64      pub stdout: Option<io::PipeStream>,
  65  
  66      /// Handle to the child's stderr, if the `stderr` field of this process's
  67      /// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`.
  68      pub stderr: Option<io::PipeStream>,
  69  
  70      /// Extra I/O handles as configured by the original `ProcessConfig` when
  71      /// this process was created. This is by default empty.
  72      pub extra_io: Vec<Option<io::PipeStream>>,
  73  }
  74  
  75  /// This configuration describes how a new process should be spawned. A blank
  76  /// configuration can be created with `ProcessConfig::new()`. It is also
  77  /// recommented to use a functional struct update pattern when creating process
  78  /// configuration:
  79  ///
  80  /// ```
  81  /// use std::io::ProcessConfig;
  82  ///
  83  /// let config = ProcessConfig {
  84  ///     program: "/bin/sh",
  85  ///     args: &["-c".to_owned(), "true".to_owned()],
  86  ///     .. ProcessConfig::new()
  87  /// };
  88  /// ```
  89  pub struct ProcessConfig<'a> {
  90      /// Path to the program to run
  91      pub program: &'a str,
  92  
  93      /// Arguments to pass to the program (doesn't include the program itself)
  94      pub args: &'a [~str],
  95  
  96      /// Optional environment to specify for the program. If this is None, then
  97      /// it will inherit the current process's environment.
  98      pub env: Option<&'a [(~str, ~str)]>,
  99  
 100      /// Optional working directory for the new process. If this is None, then
 101      /// the current directory of the running process is inherited.
 102      pub cwd: Option<&'a Path>,
 103  
 104      /// Configuration for the child process's stdin handle (file descriptor 0).
 105      /// This field defaults to `CreatePipe(true, false)` so the input can be
 106      /// written to.
 107      pub stdin: StdioContainer,
 108  
 109      /// Configuration for the child process's stdout handle (file descriptor 1).
 110      /// This field defaults to `CreatePipe(false, true)` so the output can be
 111      /// collected.
 112      pub stdout: StdioContainer,
 113  
 114      /// Configuration for the child process's stdout handle (file descriptor 2).
 115      /// This field defaults to `CreatePipe(false, true)` so the output can be
 116      /// collected.
 117      pub stderr: StdioContainer,
 118  
 119      /// Any number of streams/file descriptors/pipes may be attached to this
 120      /// process. This list enumerates the file descriptors and such for the
 121      /// process to be spawned, and the file descriptors inherited will start at
 122      /// 3 and go to the length of this array. The first three file descriptors
 123      /// (stdin/stdout/stderr) are configured with the `stdin`, `stdout`, and
 124      /// `stderr` fields.
 125      pub extra_io: &'a [StdioContainer],
 126  
 127      /// Sets the child process's user id. This translates to a `setuid` call in
 128      /// the child process. Setting this value on windows will cause the spawn to
 129      /// fail. Failure in the `setuid` call on unix will also cause the spawn to
 130      /// fail.
 131      pub uid: Option<uint>,
 132  
 133      /// Similar to `uid`, but sets the group id of the child process. This has
 134      /// the same semantics as the `uid` field.
 135      pub gid: Option<uint>,
 136  
 137      /// If true, the child process is spawned in a detached state. On unix, this
 138      /// means that the child is the leader of a new process group.
 139      pub detach: bool,
 140  }
 141  
 142  /// The output of a finished process.
 143  pub struct ProcessOutput {
 144      /// The status (exit code) of the process.
 145      pub status: ProcessExit,
 146      /// The data that the process wrote to stdout.
 147      pub output: Vec<u8>,
 148      /// The data that the process wrote to stderr.
 149      pub error: Vec<u8>,
 150  }
 151  
 152  /// Describes what to do with a standard io stream for a child process.
 153  pub enum StdioContainer {
 154      /// This stream will be ignored. This is the equivalent of attaching the
 155      /// stream to `/dev/null`
 156      Ignored,
 157  
 158      /// The specified file descriptor is inherited for the stream which it is
 159      /// specified for.
 160      InheritFd(libc::c_int),
 161  
 162      /// Creates a pipe for the specified file descriptor which will be created
 163      /// when the process is spawned.
 164      ///
 165      /// The first boolean argument is whether the pipe is readable, and the
 166      /// second is whether it is writable. These properties are from the view of
 167      /// the *child* process, not the parent process.
 168      CreatePipe(bool /* readable */, bool /* writable */),
 169  }
 170  
 171  /// Describes the result of a process after it has terminated.
 172  /// Note that Windows have no signals, so the result is usually ExitStatus.
 173  #[deriving(Eq, TotalEq, Clone)]
 174  pub enum ProcessExit {
 175      /// Normal termination with an exit status.
 176      ExitStatus(int),
 177  
 178      /// Termination by signal, with the signal number.
 179      ExitSignal(int),
 180  }
 181  
 182  impl fmt::Show for ProcessExit {
 183      /// Format a ProcessExit enum, to nicely present the information.
 184      fn fmt(&self, f&mut fmt::Formatter) -> fmt::Result {
 185          match *self {
 186              ExitStatus(code) =>  write!(f.buf, "exit code: {}", code),
 187              ExitSignal(code) =>  write!(f.buf, "signal: {}", code),
 188          }
 189      }
 190  }
 191  
 192  impl ProcessExit {
 193      /// Was termination successful? Signal termination not considered a success,
 194      /// and success is defined as a zero exit status.
 195      pub fn success(&self) -> bool {
 196          return self.matches_exit_status(0);
 197      }
 198  
 199      /// Checks whether this ProcessExit matches the given exit status.
 200      /// Termination by signal will never match an exit code.
 201      pub fn matches_exit_status(&self, wantedint) -> bool {
 202          *self == ExitStatus(wanted)
 203      }
 204  }
 205  
 206  impl<'a> ProcessConfig<'a> {
 207      /// Creates a new configuration with blanks as all of the defaults. This is
 208      /// useful when using functional struct updates:
 209      ///
 210      /// ```rust
 211      /// use std::io::process::{ProcessConfig, Process};
 212      ///
 213      /// let config = ProcessConfig {
 214      ///     program: "/bin/sh",
 215      ///     args: &["-c".to_owned(), "echo hello".to_owned()],
 216      ///     .. ProcessConfig::new()
 217      /// };
 218      ///
 219      /// let p = Process::configure(config);
 220      /// ```
 221      ///
 222      pub fn new<'a>() -> ProcessConfig<'a> {
 223          ProcessConfig {
 224              program: "",
 225              args: &[],
 226              env: None,
 227              cwd: None,
 228              stdin: CreatePipe(true, false),
 229              stdout: CreatePipe(false, true),
 230              stderr: CreatePipe(false, true),
 231              extra_io: &[],
 232              uid: None,
 233              gid: None,
 234              detach: false,
 235          }
 236      }
 237  }
 238  
 239  impl Process {
 240      /// Creates a new process for the specified program/arguments, using
 241      /// otherwise default configuration.
 242      ///
 243      /// By default, new processes have their stdin/stdout/stderr handles created
 244      /// as pipes the can be manipulated through the respective fields of the
 245      /// returned `Process`.
 246      ///
 247      /// # Example
 248      ///
 249      /// ```
 250      /// use std::io::Process;
 251      ///
 252      /// let mut process = match Process::new("sh", &["c".to_owned(), "echo hello".to_owned()]) {
 253      ///     Ok(p) => p,
 254      ///     Err(e) => fail!("failed to execute process: {}", e),
 255      /// };
 256      ///
 257      /// let output = process.stdout.get_mut_ref().read_to_end();
 258      /// ```
 259      pub fn new(prog&str, args&[~str]) -> IoResult<Process> {
 260          Process::configure(ProcessConfig {
 261              program: prog,
 262              args: args,
 263              .. ProcessConfig::new()
 264          })
 265      }
 266  
 267      /// Executes the specified program with arguments, waiting for it to finish
 268      /// and collecting all of its output.
 269      ///
 270      /// # Example
 271      ///
 272      /// ```
 273      /// use std::io::Process;
 274      /// use std::str;
 275      ///
 276      /// let output = match Process::output("cat", ["foo.txt".to_owned()]) {
 277      ///     Ok(output) => output,
 278      ///     Err(e) => fail!("failed to execute process: {}", e),
 279      /// };
 280      ///
 281      /// println!("status: {}", output.status);
 282      /// println!("stdout: {}", str::from_utf8_lossy(output.output.as_slice()));
 283      /// println!("stderr: {}", str::from_utf8_lossy(output.error.as_slice()));
 284      /// ```
 285      pub fn output(prog&str, args&[~str]) -> IoResult<ProcessOutput> {
 286          Process::new(prog, args).map(|mut p| p.wait_with_output())
 287      }
 288  
 289      /// Executes a child process and collects its exit status. This will block
 290      /// waiting for the child to exit.
 291      ///
 292      /// # Example
 293      ///
 294      /// ```
 295      /// use std::io::Process;
 296      ///
 297      /// let status = match Process::status("ls", []) {
 298      ///     Ok(status) => status,
 299      ///     Err(e) => fail!("failed to execute process: {}", e),
 300      /// };
 301      ///
 302      /// println!("process exited with: {}", status);
 303      /// ```
 304      pub fn status(prog&str, args&[~str]) -> IoResult<ProcessExit> {
 305          Process::new(prog, args).map(|mut p| p.wait())
 306      }
 307  
 308      /// Creates a new process with the specified configuration.
 309      pub fn configure(configProcessConfig) -> IoResult<Process> {
 310          let mut config = Some(config);
 311          LocalIo::maybe_raise(|io| {
 312              io.spawn(config.take_unwrap()).map(|(p, io)| {
 313                  let mut io = io.move_iter().map(|p| {
 314                      p.map(|p| io::PipeStream::new(p))
 315                  });
 316                  Process {
 317                      handle: p,
 318                      stdin: io.next().unwrap(),
 319                      stdout: io.next().unwrap(),
 320                      stderr: io.next().unwrap(),
 321                      extra_io: io.collect(),
 322                  }
 323              })
 324          })
 325      }
 326  
 327      /// Sends `signal` to another process in the system identified by `id`.
 328      ///
 329      /// Note that windows doesn't quite have the same model as unix, so some
 330      /// unix signals are mapped to windows signals. Notably, unix termination
 331      /// signals (SIGTERM/SIGKILL/SIGINT) are translated to `TerminateProcess`.
 332      ///
 333      /// Additionally, a signal number of 0 can check for existence of the target
 334      /// process. Note, though, that on some platforms signals will continue to
 335      /// be successfully delivered if the child has exited, but not yet been
 336      /// reaped.
 337      pub fn kill(idlibc::pid_t, signalint) -> IoResult<()> {
 338          LocalIo::maybe_raise(|io| io.kill(id, signal))
 339      }
 340  
 341      /// Returns the process id of this child process
 342      pub fn id(&self) -> libc::pid_t { self.handle.id() }
 343  
 344      /// Sends the specified signal to the child process, returning whether the
 345      /// signal could be delivered or not.
 346      ///
 347      /// Note that signal 0 is interpreted as a poll to check whether the child
 348      /// process is still alive or not. If an error is returned, then the child
 349      /// process has exited.
 350      ///
 351      /// On some unix platforms signals will continue to be received after a
 352      /// child has exited but not yet been reaped. In order to report the status
 353      /// of signal delivery correctly, unix implementations may invoke
 354      /// `waitpid()` with `WNOHANG` in order to reap the child as necessary.
 355      ///
 356      /// # Errors
 357      ///
 358      /// If the signal delivery fails, the corresponding error is returned.
 359      pub fn signal(&mut self, signalint) -> IoResult<()> {
 360          self.handle.kill(signal)
 361      }
 362  
 363      /// Sends a signal to this child requesting that it exits. This is
 364      /// equivalent to sending a SIGTERM on unix platforms.
 365      pub fn signal_exit(&mut self) -> IoResult<()> {
 366          self.signal(PleaseExitSignal)
 367      }
 368  
 369      /// Sends a signal to this child forcing it to exit. This is equivalent to
 370      /// sending a SIGKILL on unix platforms.
 371      pub fn signal_kill(&mut self) -> IoResult<()> {
 372          self.signal(MustDieSignal)
 373      }
 374  
 375      /// Wait for the child to exit completely, returning the status that it
 376      /// exited with. This function will continue to have the same return value
 377      /// after it has been called at least once.
 378      ///
 379      /// The stdin handle to the child process will be closed before waiting.
 380      pub fn wait(&mut self) -> ProcessExit {
 381          drop(self.stdin.take());
 382          self.handle.wait()
 383      }
 384  
 385      /// Simultaneously wait for the child to exit and collect all remaining
 386      /// output on the stdout/stderr handles, returning a `ProcessOutput`
 387      /// instance.
 388      ///
 389      /// The stdin handle to the child is closed before waiting.
 390      pub fn wait_with_output(&mut self) -> ProcessOutput {
 391          drop(self.stdin.take());
 392          fn read(streamOption<io::PipeStream>) -> Receiver<IoResult<Vec<u8>>> {
 393              let (tx, rx) = channel();
 394              match stream {
 395                  Some(stream) => spawn(proc() {
 396                      let mut stream = stream;
 397                      tx.send(stream.read_to_end())
 398                  }),
 399                  None => tx.send(Ok(Vec::new()))
 400              }
 401              rx
 402          }
 403          let stdout = read(self.stdout.take());
 404          let stderr = read(self.stderr.take());
 405  
 406          let status = self.wait();
 407  
 408          ProcessOutput { status: status,
 409                          output: stdout.recv().ok().unwrap_or(Vec::new()),
 410                          error:  stderr.recv().ok().unwrap_or(Vec::new()) }
 411      }
 412  }
 413  
 414  impl Drop for Process {
 415      fn drop(&mut self) {
 416          // Close all I/O before exiting to ensure that the child doesn't wait
 417          // forever to print some text or something similar.
 418          drop(self.stdin.take());
 419          drop(self.stdout.take());
 420          drop(self.stderr.take());
 421          drop(mem::replace(&mut self.extra_io, Vec::new()));
 422  
 423          self.wait();
 424      }
 425  }
 426  
 427  #[cfg(test)]
 428  mod tests {
 429      use io::process::{ProcessConfig, Process};
 430      use prelude::*;
 431  
 432      // FIXME(#10380) these tests should not all be ignored on android.
 433  
 434      #[cfg(not(target_os="android"))]
 435      iotest!(fn smoke() {
 436          let args = ProcessConfig {
 437              program: "true",
 438              .. ProcessConfig::new()
 439          };
 440          let p = Process::configure(args);
 441          assert!(p.is_ok());
 442          let mut p = p.unwrap();
 443          assert!(p.wait().success());
 444      })
 445  
 446      #[cfg(not(target_os="android"))]
 447      iotest!(fn smoke_failure() {
 448          let args = ProcessConfig {
 449              program: "if-this-is-a-binary-then-the-world-has-ended",
 450              .. ProcessConfig::new()
 451          };
 452          match Process::configure(args) {
 453              Ok(..) => fail!(),
 454              Err(..) => {}
 455          }
 456      })
 457  
 458      #[cfg(not(target_os="android"))]
 459      iotest!(fn exit_reported_right() {
 460          let args = ProcessConfig {
 461              program: "false",
 462              .. ProcessConfig::new()
 463          };
 464          let p = Process::configure(args);
 465          assert!(p.is_ok());
 466          let mut p = p.unwrap();
 467          assert!(p.wait().matches_exit_status(1));
 468          drop(p.wait().clone());
 469      })
 470  
 471      #[cfg(unix, not(target_os="android"))]
 472      iotest!(fn signal_reported_right() {
 473          let args = ProcessConfig {
 474              program: "/bin/sh",
 475              args: &["-c".to_owned(), "kill -1 $$".to_owned()],
 476              .. ProcessConfig::new()
 477          };
 478          let p = Process::configure(args);
 479          assert!(p.is_ok());
 480          let mut p = p.unwrap();
 481          match p.wait() {
 482              process::ExitSignal(1) => {},
 483              result => fail!("not terminated by signal 1 (instead, {})", result),
 484          }
 485      })
 486  
 487      pub fn read_all(input: &mut Reader) -> ~str {
 488          input.read_to_str().unwrap()
 489      }
 490  
 491      pub fn run_output(args: ProcessConfig) -> ~str {
 492          let p = Process::configure(args);
 493          assert!(p.is_ok());
 494          let mut p = p.unwrap();
 495          assert!(p.stdout.is_some());
 496          let ret = read_all(p.stdout.get_mut_ref() as &mut Reader);
 497          assert!(p.wait().success());
 498          return ret;
 499      }
 500  
 501      #[cfg(not(target_os="android"))]
 502      iotest!(fn stdout_works() {
 503          let args = ProcessConfig {
 504              program: "echo",
 505              args: &["foobar".to_owned()],
 506              stdout: CreatePipe(false, true),
 507              .. ProcessConfig::new()
 508          };
 509          assert_eq!(run_output(args), "foobar\n".to_owned());
 510      })
 511  
 512      #[cfg(unix, not(target_os="android"))]
 513      iotest!(fn set_cwd_works() {
 514          let cwd = Path::new("/");
 515          let args = ProcessConfig {
 516              program: "/bin/sh",
 517              args: &["-c".to_owned(), "pwd".to_owned()],
 518              cwd: Some(&cwd),
 519              stdout: CreatePipe(false, true),
 520              .. ProcessConfig::new()
 521          };
 522          assert_eq!(run_output(args), "/\n".to_owned());
 523      })
 524  
 525      #[cfg(unix, not(target_os="android"))]
 526      iotest!(fn stdin_works() {
 527          let args = ProcessConfig {
 528              program: "/bin/sh",
 529              args: &["-c".to_owned(), "read line; echo $line".to_owned()],
 530              stdin: CreatePipe(true, false),
 531              stdout: CreatePipe(false, true),
 532              .. ProcessConfig::new()
 533          };
 534          let mut p = Process::configure(args).unwrap();
 535          p.stdin.get_mut_ref().write("foobar".as_bytes()).unwrap();
 536          drop(p.stdin.take());
 537          let out = read_all(p.stdout.get_mut_ref() as &mut Reader);
 538          assert!(p.wait().success());
 539          assert_eq!(out, "foobar\n".to_owned());
 540      })
 541  
 542      #[cfg(not(target_os="android"))]
 543      iotest!(fn detach_works() {
 544          let args = ProcessConfig {
 545              program: "true",
 546              detach: true,
 547              .. ProcessConfig::new()
 548          };
 549          let mut p = Process::configure(args).unwrap();
 550          assert!(p.wait().success());
 551      })
 552  
 553      #[cfg(windows)]
 554      iotest!(fn uid_fails_on_windows() {
 555          let args = ProcessConfig {
 556              program: "test",
 557              uid: Some(10),
 558              .. ProcessConfig::new()
 559          };
 560          assert!(Process::configure(args).is_err());
 561      })
 562  
 563      #[cfg(unix, not(target_os="android"))]
 564      iotest!(fn uid_works() {
 565          use libc;
 566          let args = ProcessConfig {
 567              program: "/bin/sh",
 568              args: &["-c".to_owned(), "true".to_owned()],
 569              uid: Some(unsafe { libc::getuid() as uint }),
 570              gid: Some(unsafe { libc::getgid() as uint }),
 571              .. ProcessConfig::new()
 572          };
 573          let mut p = Process::configure(args).unwrap();
 574          assert!(p.wait().success());
 575      })
 576  
 577      #[cfg(unix, not(target_os="android"))]
 578      iotest!(fn uid_to_root_fails() {
 579          use libc;
 580  
 581          // if we're already root, this isn't a valid test. Most of the bots run
 582          // as non-root though (android is an exception).
 583          if unsafe { libc::getuid() == 0 } { return }
 584          let args = ProcessConfig {
 585              program: "/bin/ls",
 586              uid: Some(0),
 587              gid: Some(0),
 588              .. ProcessConfig::new()
 589          };
 590          assert!(Process::configure(args).is_err());
 591      })
 592  
 593      #[cfg(not(target_os="android"))]
 594      iotest!(fn test_process_status() {
 595          let mut status = Process::status("false", []).unwrap();
 596          assert!(status.matches_exit_status(1));
 597  
 598          status = Process::status("true", []).unwrap();
 599          assert!(status.success());
 600      })
 601  
 602      iotest!(fn test_process_output_fail_to_start() {
 603          match Process::output("/no-binary-by-this-name-should-exist", []) {
 604              Err(e) => assert_eq!(e.kind, FileNotFound),
 605              Ok(..) => fail!()
 606          }
 607      })
 608  
 609      #[cfg(not(target_os="android"))]
 610      iotest!(fn test_process_output_output() {
 611  
 612          let ProcessOutput {status, output, error}
 613               = Process::output("echo", ["hello".to_owned()]).unwrap();
 614          let output_str = str::from_utf8(output.as_slice()).unwrap();
 615  
 616          assert!(status.success());
 617          assert_eq!(output_str.trim().to_owned(), "hello".to_owned());
 618          // FIXME #7224
 619          if !running_on_valgrind() {
 620              assert_eq!(error, Vec::new());
 621          }
 622      })
 623  
 624      #[cfg(not(target_os="android"))]
 625      iotest!(fn test_process_output_error() {
 626          let ProcessOutput {status, output, error}
 627               = Process::output("mkdir", [".".to_owned()]).unwrap();
 628  
 629          assert!(status.matches_exit_status(1));
 630          assert_eq!(output, Vec::new());
 631          assert!(!error.is_empty());
 632      })
 633  
 634      #[cfg(not(target_os="android"))]
 635      iotest!(fn test_finish_once() {
 636          let mut prog = Process::new("false", []).unwrap();
 637          assert!(prog.wait().matches_exit_status(1));
 638      })
 639  
 640      #[cfg(not(target_os="android"))]
 641      iotest!(fn test_finish_twice() {
 642          let mut prog = Process::new("false", []).unwrap();
 643          assert!(prog.wait().matches_exit_status(1));
 644          assert!(prog.wait().matches_exit_status(1));
 645      })
 646  
 647      #[cfg(not(target_os="android"))]
 648      iotest!(fn test_wait_with_output_once() {
 649  
 650          let mut prog = Process::new("echo", ["hello".to_owned()]).unwrap();
 651          let ProcessOutput {status, output, error} = prog.wait_with_output();
 652          let output_str = str::from_utf8(output.as_slice()).unwrap();
 653  
 654          assert!(status.success());
 655          assert_eq!(output_str.trim().to_owned(), "hello".to_owned());
 656          // FIXME #7224
 657          if !running_on_valgrind() {
 658              assert_eq!(error, Vec::new());
 659          }
 660      })
 661  
 662      #[cfg(not(target_os="android"))]
 663      iotest!(fn test_wait_with_output_twice() {
 664          let mut prog = Process::new("echo", ["hello".to_owned()]).unwrap();
 665          let ProcessOutput {status, output, error} = prog.wait_with_output();
 666  
 667          let output_str = str::from_utf8(output.as_slice()).unwrap();
 668  
 669          assert!(status.success());
 670          assert_eq!(output_str.trim().to_owned(), "hello".to_owned());
 671          // FIXME #7224
 672          if !running_on_valgrind() {
 673              assert_eq!(error, Vec::new());
 674          }
 675  
 676          let ProcessOutput {status, output, error} = prog.wait_with_output();
 677  
 678          assert!(status.success());
 679          assert_eq!(output, Vec::new());
 680          // FIXME #7224
 681          if !running_on_valgrind() {
 682              assert_eq!(error, Vec::new());
 683          }
 684      })
 685  
 686      #[cfg(unix,not(target_os="android"))]
 687      pub fn run_pwd(dir: Option<&Path>) -> Process {
 688          Process::configure(ProcessConfig {
 689              program: "pwd",
 690              cwd: dir,
 691              .. ProcessConfig::new()
 692          }).unwrap()
 693      }
 694      #[cfg(target_os="android")]
 695      pub fn run_pwd(dir: Option<&Path>) -> Process {
 696          Process::configure(ProcessConfig {
 697              program: "/system/bin/sh",
 698              args: &["-c".to_owned(),"pwd".to_owned()],
 699              cwd: dir.map(|a| &*a),
 700              .. ProcessConfig::new()
 701          }).unwrap()
 702      }
 703  
 704      #[cfg(windows)]
 705      pub fn run_pwd(dir: Option<&Path>) -> Process {
 706          Process::configure(ProcessConfig {
 707              program: "cmd",
 708              args: &["/c".to_owned(), "cd".to_owned()],
 709              cwd: dir.map(|a| &*a),
 710              .. ProcessConfig::new()
 711          }).unwrap()
 712      }
 713  
 714      iotest!(fn test_keep_current_working_dir() {
 715          use os;
 716          let mut prog = run_pwd(None);
 717  
 718          let output = str::from_utf8(prog.wait_with_output().output.as_slice()).unwrap().to_owned();
 719          let parent_dir = os::getcwd();
 720          let child_dir = Path::new(output.trim());
 721  
 722          let parent_stat = parent_dir.stat().unwrap();
 723          let child_stat = child_dir.stat().unwrap();
 724  
 725          assert_eq!(parent_stat.unstable.device, child_stat.unstable.device);
 726          assert_eq!(parent_stat.unstable.inode, child_stat.unstable.inode);
 727      })
 728  
 729      iotest!(fn test_change_working_directory() {
 730          use os;
 731          // test changing to the parent of os::getcwd() because we know
 732          // the path exists (and os::getcwd() is not expected to be root)
 733          let parent_dir = os::getcwd().dir_path();
 734          let mut prog = run_pwd(Some(&parent_dir));
 735  
 736          let output = str::from_utf8(prog.wait_with_output().output.as_slice()).unwrap().to_owned();
 737          let child_dir = Path::new(output.trim());
 738  
 739          let parent_stat = parent_dir.stat().unwrap();
 740          let child_stat = child_dir.stat().unwrap();
 741  
 742          assert_eq!(parent_stat.unstable.device, child_stat.unstable.device);
 743          assert_eq!(parent_stat.unstable.inode, child_stat.unstable.inode);
 744      })
 745  
 746      #[cfg(unix,not(target_os="android"))]
 747      pub fn run_env(env: Option<~[(~str, ~str)]>) -> Process {
 748          Process::configure(ProcessConfig {
 749              program: "env",
 750              env: env.as_ref().map(|e| e.as_slice()),
 751              .. ProcessConfig::new()
 752          }).unwrap()
 753      }
 754      #[cfg(target_os="android")]
 755      pub fn run_env(env: Option<~[(~str, ~str)]>) -> Process {
 756          Process::configure(ProcessConfig {
 757              program: "/system/bin/sh",
 758              args: &["-c".to_owned(),"set".to_owned()],
 759              env: env.as_ref().map(|e| e.as_slice()),
 760              .. ProcessConfig::new()
 761          }).unwrap()
 762      }
 763  
 764      #[cfg(windows)]
 765      pub fn run_env(env: Option<~[(~str, ~str)]>) -> Process {
 766          Process::configure(ProcessConfig {
 767              program: "cmd",
 768              args: &["/c".to_owned(), "set".to_owned()],
 769              env: env.as_ref().map(|e| e.as_slice()),
 770              .. ProcessConfig::new()
 771          }).unwrap()
 772      }
 773  
 774      #[cfg(not(target_os="android"))]
 775      iotest!(fn test_inherit_env() {
 776          use os;
 777          if running_on_valgrind() { return; }
 778  
 779          let mut prog = run_env(None);
 780          let output = str::from_utf8(prog.wait_with_output().output.as_slice()).unwrap().to_owned();
 781  
 782          let r = os::env();
 783          for &(ref k, ref v) in r.iter() {
 784              // don't check windows magical empty-named variables
 785              assert!(k.is_empty() || output.contains(format!("{}={}", *k, *v)));
 786          }
 787      })
 788      #[cfg(target_os="android")]
 789      iotest!(fn test_inherit_env() {
 790          use os;
 791          if running_on_valgrind() { return; }
 792  
 793          let mut prog = run_env(None);
 794          let output = str::from_utf8(prog.wait_with_output().output.as_slice()).unwrap().to_owned();
 795  
 796          let r = os::env();
 797          for &(ref k, ref v) in r.iter() {
 798              // don't check android RANDOM variables
 799              if *k != "RANDOM".to_owned() {
 800                  assert!(output.contains(format!("{}={}", *k, *v)) ||
 801                          output.contains(format!("{}=\'{}\'", *k, *v)));
 802              }
 803          }
 804      })
 805  
 806      iotest!(fn test_add_to_env() {
 807          let new_env = box [("RUN_TEST_NEW_ENV".to_owned(), "123".to_owned())];
 808  
 809          let mut prog = run_env(Some(new_env));
 810          let result = prog.wait_with_output();
 811          let output = str::from_utf8_lossy(result.output.as_slice()).into_owned();
 812  
 813          assert!(output.contains("RUN_TEST_NEW_ENV=123"),
 814                  "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output);
 815      })
 816  
 817      #[cfg(unix)]
 818      pub fn sleeper() -> Process {
 819          Process::new("sleep", ["1000".to_owned()]).unwrap()
 820      }
 821      #[cfg(windows)]
 822      pub fn sleeper() -> Process {
 823          // There's a `timeout` command on windows, but it doesn't like having
 824          // its output piped, so instead just ping ourselves a few times with
 825          // gaps inbetweeen so we're sure this process is alive for awhile
 826          Process::new("ping", ["127.0.0.1".to_owned(), "-n".to_owned(), "1000".to_owned()]).unwrap()
 827      }
 828  
 829      iotest!(fn test_kill() {
 830          let mut p = sleeper();
 831          Process::kill(p.id(), PleaseExitSignal).unwrap();
 832          assert!(!p.wait().success());
 833      })
 834  
 835      iotest!(fn test_exists() {
 836          let mut p = sleeper();
 837          assert!(Process::kill(p.id(), 0).is_ok());
 838          p.signal_kill().unwrap();
 839          assert!(!p.wait().success());
 840      })
 841  
 842      iotest!(fn test_zero() {
 843          let mut p = sleeper();
 844          p.signal_kill().unwrap();
 845          for _ in range(0, 20) {
 846              if p.signal(0).is_err() {
 847                  assert!(!p.wait().success());
 848                  return
 849              }
 850              timer::sleep(100);
 851          }
 852          fail!("never saw the child go away");
 853      })
 854  }


libstd/io/process.rs:142:38-142:38 -struct- definition:
/// The output of a finished process.
pub struct ProcessOutput {
    /// The status (exit code) of the process.
references:- 3
408:         ProcessOutput { status: status,
409:                         output: stdout.recv().ok().unwrap_or(Vec::new()),


libstd/io/process.rs:88:8-88:8 -struct- definition:
/// ```
pub struct ProcessConfig<'a> {
    /// Path to the program to run
references:- 6
222:     pub fn new<'a>() -> ProcessConfig<'a> {
223:         ProcessConfig {
224:             program: "",
--
259:     pub fn new(prog: &str, args: &[~str]) -> IoResult<Process> {
260:         Process::configure(ProcessConfig {
261:             program: prog,
--
308:     /// Creates a new process with the specified configuration.
309:     pub fn configure(config: ProcessConfig) -> IoResult<Process> {
310:         let mut config = Some(config);
libstd/rt/rtio.rs:
191:     fn timer_init(&mut self) -> IoResult<Box<RtioTimer:Send>>;
192:     fn spawn(&mut self, config: ProcessConfig)
193:             -> IoResult<(Box<RtioProcess:Send>,


libstd/io/process.rs:54:8-54:8 -struct- definition:
/// ```
pub struct Process {
    handle: Box<RtioProcess:Send>,
references:- 5
414: impl Drop for Process {
415:     fn drop(&mut self) {


libstd/io/process.rs:152:72-152:72 -enum- definition:
/// Describes what to do with a standard io stream for a child process.
pub enum StdioContainer {
    /// This stream will be ignored. This is the equivalent of attaching the
references:- 4
124:     /// `stderr` fields.
125:     pub extra_io: &'a [StdioContainer],


libstd/io/process.rs:173:32-173:32 -enum- definition:
pub enum ProcessExit {
    /// Normal termination with an exit status.
    ExitStatus(int),
references:- 12
172: /// Note that Windows have no signals, so the result is usually ExitStatus.
174: pub enum ProcessExit {
--
182: impl fmt::Show for ProcessExit {
183:     /// Format a ProcessExit enum, to nicely present the information.
--
379:     /// The stdin handle to the child process will be closed before waiting.
380:     pub fn wait(&mut self) -> ProcessExit {
381:         drop(self.stdin.take());
libstd/rt/rtio.rs:
276:     fn kill(&mut self, signal: int) -> IoResult<()>;
277:     fn wait(&mut self) -> ProcessExit;
278: }
libstd/io/process.rs:
192: impl ProcessExit {
193:     /// Was termination successful? Signal termination not considered a success,


libstd/io/process.rs:392:8-392:8 -fn- definition:
        fn read(stream: Option<io::PipeStream>) -> Receiver<IoResult<Vec<u8>>> {
            let (tx, rx) = channel();
            match stream {
references:- 2
403:         let stdout = read(self.stdout.take());
404:         let stderr = read(self.stderr.take());