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