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.
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.
11 //! Bindings for executing child processes
13 #![allow(experimental)]
20 use io::{IoResult, IoError};
25 use rt::rtio::{RtioProcess, ProcessConfig, IoFactory, LocalIo};
28 use collections::HashMap;
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;
43 /// Representation of a running or exited child process.
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.
52 /// use std::io::Command;
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),
59 /// let contents = child.stdout.get_mut_ref().read_to_end();
60 /// assert!(child.wait().unwrap().success());
63 handle: Box<RtioProcess + Send>,
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>,
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>,
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>,
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>>,
83 /// A HashMap representation of environment variables.
84 pub type EnvMap = HashMap<CString, CString>;
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:
93 /// use std::io::Command;
95 /// let mut process = match Command::new("sh").arg("-c").arg("echo hello").spawn() {
97 /// Err(e) => fail!("failed to execute process: {}", e),
100 /// let output = process.stdout.get_mut_ref().read_to_end();
104 // The internal data for the builder. Documented by the builder
105 // methods below, and serialized into rt::rtio::ProcessConfig.
109 cwd: Option<CString>,
110 stdin: StdioContainer,
111 stdout: StdioContainer,
112 stderr: StdioContainer,
113 extra_io: Vec<StdioContainer>,
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}.)
127 /// Constructs a new `Command` for launching the program at
128 /// path `program`, with the following default configuration:
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)
136 /// Builder methods are provided to change these defaults and
137 /// otherwise configure the process.
138 pub fn new<T:ToCStr>(program: T) -> Command {
140 program: program.to_c_str(),
144 stdin: CreatePipe(true, false),
145 stdout: CreatePipe(false, true),
146 stderr: CreatePipe(false, true),
147 extra_io: Vec::new(),
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());
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()));;
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 {
168 Some(ref mut map) => map,
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()))
176 self.env.as_mut().unwrap()
181 /// Inserts or updates an environment variable mapping.
182 pub fn env<'a, T: ToCStr, U: ToCStr>(&'a mut self, key: T, val: U)
184 self.get_env_map().insert(key.to_c_str(), val.to_c_str());
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());
194 /// Sets the entire environment map for the child process.
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)])
200 self.env = Some(env.iter().map(|&(ref k, ref v)| (k.to_c_str(), v.to_c_str()))
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());
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 {
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 {
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 {
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);
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
244 pub fn uid<'a>(&'a mut self, id: uint) -> &'a mut Command {
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 {
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 {
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 {
267 Ignored => rtio::Ignored,
268 InheritFd(fd) => rtio::InheritFd(fd),
269 CreatePipe(a, b) => rtio::CreatePipe(a, b),
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 {
278 Some(env_map.iter().collect::<Vec<_>>())
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(),
293 io.spawn(cfg).map(|(p, io)| {
294 let mut io = io.move_iter().map(|p| {
295 p.map(|p| io::PipeStream::new(p))
300 stdin: io.next().unwrap(),
301 stdout: io.next().unwrap(),
302 stderr: io.next().unwrap(),
303 extra_io: io.collect(),
306 }).map_err(IoError::from_rtio_error)
309 /// Executes the command as a child process, waiting for it to finish and
310 /// collecting all of its output.
315 /// use std::io::Command;
318 /// let output = match Command::new("cat").arg("foot.txt").output() {
319 /// Ok(output) => output,
320 /// Err(e) => fail!("failed to execute process: {}", e),
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()));
327 pub fn output(&self) -> IoResult<ProcessOutput> {
328 self.spawn().and_then(|p| p.wait_with_output())
331 /// Executes a command as a child process, waiting for it to finish and
332 /// collecting its exit status.
337 /// use std::io::Command;
339 /// let status = match Command::new("ls").status() {
340 /// Ok(status) => status,
341 /// Err(e) => fail!("failed to execute process: {}", e),
344 /// println!("process exited with: {}", status);
346 pub fn status(&self) -> IoResult<ProcessExit> {
347 self.spawn().and_then(|mut p| p.wait())
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
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())));
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.
371 /// The data that the process wrote to stderr.
375 /// Describes what to do with a standard io stream for a child process.
377 pub enum StdioContainer {
378 /// This stream will be ignored. This is the equivalent of attaching the
379 /// stream to `/dev/null`
382 /// The specified file descriptor is inherited for the stream which it is
384 InheritFd(libc::c_int),
386 /// Creates a pipe for the specified file descriptor which will be created
387 /// when the process is spawned.
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 */),
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.
402 /// Termination by signal, with the signal number.
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 {
410 ExitStatus(code) => write!(f, "exit code: {}", code),
411 ExitSignal(code) => write!(f, "signal: {}", code),
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);
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)
431 /// Sends `signal` to another process in the system identified by `id`.
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`.
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
441 pub fn kill(id: libc::pid_t, signal: int) -> IoResult<()> {
442 LocalIo::maybe_raise(|io| {
444 }).map_err(IoError::from_rtio_error)
447 /// Returns the process id of this child process
448 pub fn id(&self) -> libc::pid_t { self.handle.id() }
450 /// Sends the specified signal to the child process, returning whether the
451 /// signal could be delivered or not.
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.
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.
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)
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)
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)
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.
485 /// The stdin handle to the child process will be closed before waiting.
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)),
500 /// Sets a timeout, in milliseconds, for future calls to wait().
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.
506 /// A value of `None` will clear any previous timeout, and a value of `Some`
507 /// will override any previously set timeout.
512 /// # #![allow(experimental)]
513 /// use std::io::{Command, IoResult};
514 /// use std::io::process::ProcessExit;
516 /// fn run_gracefully(prog: &str) -> IoResult<ProcessExit> {
517 /// let mut p = try!(Command::new("long-running-process").spawn());
519 /// // give the process 10 seconds to finish completely
520 /// p.set_timeout(Some(10_000));
522 /// Ok(status) => return Ok(status),
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));
530 /// Ok(status) => return Ok(status),
534 /// // Well, we did our best, forcefully kill the process
535 /// try!(p.signal_kill());
536 /// p.set_timeout(None);
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)
545 /// Simultaneously wait for the child to exit and collect all remaining
546 /// output on the stdout/stderr handles, returning a `ProcessOutput`
549 /// The stdin handle to the child is closed before waiting.
553 /// This function can fail for any of the same reasons that `wait()` can
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();
560 Some(stream) => spawn(proc() {
561 let mut stream = stream;
562 tx.send(stream.read_to_end())
564 None => tx.send(Ok(Vec::new()))
568 let stdout = read(self.stdout.take());
569 let stderr = read(self.stderr.take());
571 let status = try!(self.wait());
575 output: stdout.recv().ok().unwrap_or(Vec::new()),
576 error: stderr.recv().ok().unwrap_or(Vec::new()),
580 /// Forgets this process, allowing it to outlive the parent
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) {
592 impl Drop for Process {
594 if self.forget { return }
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()));
603 self.set_timeout(None);
604 let _ = self.wait().unwrap();
610 use io::process::{Command, Process};
613 // FIXME(#10380) these tests should not all be ignored on android.
615 #[cfg(not(target_os="android"))]
617 let p = Command::new("true").spawn();
619 let mut p = p.unwrap();
620 assert!(p.wait().unwrap().success());
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() {
631 #[cfg(not(target_os="android"))]
632 iotest!(fn exit_reported_right() {
633 let p = Command::new("false").spawn();
635 let mut p = p.unwrap();
636 assert!(p.wait().unwrap().matches_exit_status(1));
637 drop(p.wait().clone());
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();
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),
651 pub fn read_all(input: &mut Reader) -> String {
652 input.read_to_string().unwrap()
655 pub fn run_output(cmd: Command) -> String {
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());
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());
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());
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))
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());
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());
702 iotest!(fn uid_fails_on_windows() {
703 assert!(Command::new("test").uid(10).spawn().is_err());
706 #[cfg(unix, not(target_os="android"))]
707 iotest!(fn uid_works() {
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 })
714 assert!(p.wait().unwrap().success());
717 #[cfg(unix, not(target_os="android"))]
718 iotest!(fn uid_to_root_fails() {
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());
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));
732 status = Command::new("true").status().unwrap();
733 assert!(status.success());
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),
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();
749 assert!(status.success());
750 assert_eq!(output_str.trim().to_string(), "hello".to_string());
752 if !running_on_valgrind() {
753 assert_eq!(error, Vec::new());
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();
762 assert!(status.matches_exit_status(1));
763 assert_eq!(output, Vec::new());
764 assert!(!error.is_empty());
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));
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));
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();
786 assert!(status.success());
787 assert_eq!(output_str.trim().to_string(), "hello".to_string());
789 if !running_on_valgrind() {
790 assert_eq!(error, Vec::new());
794 #[cfg(unix,not(target_os="android"))]
795 pub fn pwd_cmd() -> Command {
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");
806 pub fn pwd_cmd() -> Command {
807 let mut cmd = Command::new("cmd");
808 cmd.arg("/c").arg("cd");
812 iotest!(fn test_keep_current_working_dir() {
814 let prog = pwd_cmd().spawn().unwrap();
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());
821 let parent_stat = parent_dir.stat().unwrap();
822 let child_stat = child_dir.stat().unwrap();
824 assert_eq!(parent_stat.unstable.device, child_stat.unstable.device);
825 assert_eq!(parent_stat.unstable.inode, child_stat.unstable.inode);
828 iotest!(fn test_change_working_directory() {
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();
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());
839 let parent_stat = parent_dir.stat().unwrap();
840 let child_stat = child_dir.stat().unwrap();
842 assert_eq!(parent_stat.unstable.device, child_stat.unstable.device);
843 assert_eq!(parent_stat.unstable.inode, child_stat.unstable.inode);
846 #[cfg(unix,not(target_os="android"))]
847 pub fn env_cmd() -> Command {
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");
858 pub fn env_cmd() -> Command {
859 let mut cmd = Command::new("cmd");
860 cmd.arg("/c").arg("set");
864 #[cfg(not(target_os="android"))]
865 iotest!(fn test_inherit_env() {
867 if running_on_valgrind() { return; }
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();
874 for &(ref k, ref v) in r.iter() {
875 // don't check windows magical empty-named variables
876 assert!(k.is_empty() ||
878 .contains(format!("{}={}", *k, *v).as_slice()));
881 #[cfg(target_os="android")]
882 iotest!(fn test_inherit_env() {
884 if running_on_valgrind() { return; }
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();
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!("{}={}",
900 .contains(format!("{}=\'{}\'",
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();
913 assert!(output.as_slice().contains("RUN_TEST_NEW_ENV=123"),
914 "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output);
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();
922 assert!(output.as_slice().contains("RUN_TEST_NEW_ENV=123"),
923 "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output);
926 iotest!(fn test_remove_from_env() {
929 // save original environment
930 let old_env = os::getenv("RUN_TEST_NEW_ENV");
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();
937 // restore original environment
940 os::unsetenv("RUN_TEST_NEW_ENV");
943 os::setenv("RUN_TEST_NEW_ENV", val.as_slice());
947 assert!(!output.as_slice().contains("RUN_TEST_NEW_ENV"),
948 "found RUN_TEST_NEW_ENV inside of:\n\n{}", output);
952 pub fn sleeper() -> Process {
953 Command::new("sleep").arg("1000").spawn().unwrap()
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()
963 iotest!(fn test_kill() {
964 let mut p = sleeper();
965 Process::kill(p.id(), PleaseExitSignal).unwrap();
966 assert!(!p.wait().unwrap().success());
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());
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());
986 fail!("never saw the child go away");
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();
996 assert!(p.wait().is_ok());
999 iotest!(fn wait_timeout2() {
1000 let (tx, rx) = channel();
1001 let tx2 = tx.clone();
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();
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();
1020 iotest!(fn forget() {
1024 assert!(Process::kill(id, 0).is_ok());
1025 assert!(Process::kill(id, PleaseExitSignal).is_ok());