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