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