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