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