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)]
19 use io::{IoResult, IoError};
24 use rt::rtio::{RtioProcess, ProcessConfig, IoFactory, LocalIo};
28 /// Signal a process to exit, without forcibly killing it. Corresponds to
29 /// SIGTERM on unix platforms.
30 #[cfg(windows)] pub static PleaseExitSignal: int = 15;
31 /// Signal a process to exit immediately, forcibly killing it. Corresponds to
32 /// SIGKILL on unix platforms.
33 #[cfg(windows)] pub static MustDieSignal: int = 9;
34 /// Signal a process to exit, without forcibly killing it. Corresponds to
35 /// SIGTERM on unix platforms.
36 #[cfg(not(windows))] pub static PleaseExitSignal: int = libc::SIGTERM as int;
37 /// Signal a process to exit immediately, forcibly killing it. Corresponds to
38 /// SIGKILL on unix platforms.
39 #[cfg(not(windows))] pub static MustDieSignal: int = libc::SIGKILL as int;
41 /// Representation of a running or exited child process.
43 /// This structure is used to represent and manage child processes. A child
44 /// process is created via the `Command` struct, which configures the spawning
45 /// process and can itself be constructed using a builder-style interface.
50 /// use std::io::Command;
52 /// let mut child = match Command::new("/bin/cat").arg("file.txt").spawn() {
53 /// Ok(child) => child,
54 /// Err(e) => fail!("failed to execute child: {}", e),
57 /// let contents = child.stdout.get_mut_ref().read_to_end();
58 /// assert!(child.wait().unwrap().success());
61 handle: Box<RtioProcess:Send>,
63 /// Handle to the child's stdin, if the `stdin` field of this process's
64 /// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`.
65 pub stdin: Option<io::PipeStream>,
67 /// Handle to the child's stdout, if the `stdout` field of this process's
68 /// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`.
69 pub stdout: Option<io::PipeStream>,
71 /// Handle to the child's stderr, if the `stderr` field of this process's
72 /// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`.
73 pub stderr: Option<io::PipeStream>,
75 /// Extra I/O handles as configured by the original `ProcessConfig` when
76 /// this process was created. This is by default empty.
77 pub extra_io: Vec<Option<io::PipeStream>>,
80 /// The `Command` type acts as a process builder, providing fine-grained control
81 /// over how a new process should be spawned. A default configuration can be
82 /// generated using `Command::new(program)`, where `program` gives a path to the
83 /// program to be executed. Additional builder methods allow the configuration
84 /// to be changed (for example, by adding arguments) prior to spawning:
87 /// use std::io::Command;
89 /// let mut process = match Command::new("sh").arg("-c").arg("echo hello").spawn() {
91 /// Err(e) => fail!("failed to execute process: {}", e),
94 /// let output = process.stdout.get_mut_ref().read_to_end();
97 // The internal data for the builder. Documented by the builder
98 // methods below, and serialized into rt::rtio::ProcessConfig.
101 env: Option<Vec<(CString, CString)>>,
102 cwd: Option<CString>,
103 stdin: StdioContainer,
104 stdout: StdioContainer,
105 stderr: StdioContainer,
106 extra_io: Vec<StdioContainer>,
112 // FIXME (#12938): Until DST lands, we cannot decompose &str into & and str, so
113 // we cannot usefully take ToCStr arguments by reference (without forcing an
114 // additional & around &str). So we are instead temporarily adding an instance
115 // for &Path, so that we can take ToCStr as owned. When DST lands, the &Path
116 // instance should be removed, and arguments bound by ToCStr should be passed by
117 // reference. (Here: {new, arg, args, env}.)
120 /// Constructs a new `Command` for launching the program at
121 /// path `program`, with the following default configuration:
123 /// * No arguments to the program
124 /// * Inherit the current process's environment
125 /// * Inherit the current process's working directory
126 /// * A readable pipe for stdin (file descriptor 0)
127 /// * A writeable pipe for stdout and stderr (file descriptors 1 and 2)
129 /// Builder methods are provided to change these defaults and
130 /// otherwise configure the process.
131 pub fn new<T:ToCStr>(program: T) -> Command {
133 program: program.to_c_str(),
137 stdin: CreatePipe(true, false),
138 stdout: CreatePipe(false, true),
139 stderr: CreatePipe(false, true),
140 extra_io: Vec::new(),
147 /// Add an argument to pass to the program.
148 pub fn arg<'a, T:ToCStr>(&'a mut self, arg: T) -> &'a mut Command {
149 self.args.push(arg.to_c_str());
153 /// Add multiple arguments to pass to the program.
154 pub fn args<'a, T:ToCStr>(&'a mut self, args: &[T]) -> &'a mut Command {
155 self.args.extend(args.iter().map(|arg| arg.to_c_str()));;
159 /// Sets the environment for the child process (rather than inheriting it
160 /// from the current process).
162 // FIXME (#13851): We should change this interface to allow clients to (1)
163 // build up the env vector incrementally and (2) allow both inheriting the
164 // current process's environment AND overriding/adding additional
165 // environment variables. The underlying syscalls assume that the
166 // environment has no duplicate names, so we really want to use a hashtable
167 // to compute the environment to pass down to the syscall; resolving issue
168 // #13851 will make it possible to use the standard hashtable.
169 pub fn env<'a, T:ToCStr>(&'a mut self, env: &[(T,T)]) -> &'a mut Command {
170 self.env = Some(env.iter().map(|&(ref name, ref val)| {
171 (name.to_c_str(), val.to_c_str())
176 /// Set the working directory for the child process.
177 pub fn cwd<'a>(&'a mut self, dir: &Path) -> &'a mut Command {
178 self.cwd = Some(dir.to_c_str());
182 /// Configuration for the child process's stdin handle (file descriptor 0).
183 /// Defaults to `CreatePipe(true, false)` so the input can be written to.
184 pub fn stdin<'a>(&'a mut self, cfg: StdioContainer) -> &'a mut Command {
189 /// Configuration for the child process's stdout handle (file descriptor 1).
190 /// Defaults to `CreatePipe(false, true)` so the output can be collected.
191 pub fn stdout<'a>(&'a mut self, cfg: StdioContainer) -> &'a mut Command {
196 /// Configuration for the child process's stderr handle (file descriptor 2).
197 /// Defaults to `CreatePipe(false, true)` so the output can be collected.
198 pub fn stderr<'a>(&'a mut self, cfg: StdioContainer) -> &'a mut Command {
202 /// Attaches a stream/file descriptor/pipe to the child process. Inherited
203 /// file descriptors are numbered consecutively, starting at 3; the first
204 /// three file descriptors (stdin/stdout/stderr) are configured with the
205 /// `stdin`, `stdout`, and `stderr` methods.
206 pub fn extra_io<'a>(&'a mut self, cfg: StdioContainer) -> &'a mut Command {
207 self.extra_io.push(cfg);
211 /// Sets the child process's user id. This translates to a `setuid` call in
212 /// the child process. Setting this value on windows will cause the spawn to
213 /// fail. Failure in the `setuid` call on unix will also cause the spawn to
215 pub fn uid<'a>(&'a mut self, id: uint) -> &'a mut Command {
220 /// Similar to `uid`, but sets the group id of the child process. This has
221 /// the same semantics as the `uid` field.
222 pub fn gid<'a>(&'a mut self, id: uint) -> &'a mut Command {
227 /// Sets the child process to be spawned in a detached state. On unix, this
228 /// means that the child is the leader of a new process group.
229 pub fn detached<'a>(&'a mut self) -> &'a mut Command {
234 /// Executes the command as a child process, which is returned.
235 pub fn spawn(&self) -> IoResult<Process> {
236 fn to_rtio(p: StdioContainer) -> rtio::StdioContainer {
238 Ignored => rtio::Ignored,
239 InheritFd(fd) => rtio::InheritFd(fd),
240 CreatePipe(a, b) => rtio::CreatePipe(a, b),
243 let extra_io: Vec<rtio::StdioContainer> =
244 self.extra_io.iter().map(|x| to_rtio(*x)).collect();
245 LocalIo::maybe_raise(|io| {
246 let cfg = ProcessConfig {
247 program: &self.program,
248 args: self.args.as_slice(),
249 env: self.env.as_ref().map(|env| env.as_slice()),
250 cwd: self.cwd.as_ref(),
251 stdin: to_rtio(self.stdin),
252 stdout: to_rtio(self.stdout),
253 stderr: to_rtio(self.stderr),
254 extra_io: extra_io.as_slice(),
259 io.spawn(cfg).map(|(p, io)| {
260 let mut io = io.move_iter().map(|p| {
261 p.map(|p| io::PipeStream::new(p))
265 stdin: io.next().unwrap(),
266 stdout: io.next().unwrap(),
267 stderr: io.next().unwrap(),
268 extra_io: io.collect(),
271 }).map_err(IoError::from_rtio_error)
274 /// Executes the command as a child process, waiting for it to finish and
275 /// collecting all of its output.
280 /// use std::io::Command;
283 /// let output = match Command::new("cat").arg("foot.txt").output() {
284 /// Ok(output) => output,
285 /// Err(e) => fail!("failed to execute process: {}", e),
288 /// println!("status: {}", output.status);
289 /// println!("stdout: {}", str::from_utf8_lossy(output.output.as_slice()));
290 /// println!("stderr: {}", str::from_utf8_lossy(output.error.as_slice()));
292 pub fn output(&self) -> IoResult<ProcessOutput> {
293 self.spawn().and_then(|p| p.wait_with_output())
296 /// Executes a command as a child process, waiting for it to finish and
297 /// collecting its exit status.
302 /// use std::io::Command;
304 /// let status = match Command::new("ls").status() {
305 /// Ok(status) => status,
306 /// Err(e) => fail!("failed to execute process: {}", e),
309 /// println!("process exited with: {}", status);
311 pub fn status(&self) -> IoResult<ProcessExit> {
312 self.spawn().and_then(|mut p| p.wait())
316 impl fmt::Show for Command {
317 /// Format the program and arguments of a Command for display. Any
318 /// non-utf8 data is lossily converted using the utf8 replacement
320 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
321 try!(write!(f, "{}", str::from_utf8_lossy(self.program.as_bytes_no_nul())));
322 for arg in self.args.iter() {
323 try!(write!(f, " '{}'", str::from_utf8_lossy(arg.as_bytes_no_nul())));
329 /// The output of a finished process.
330 #[deriving(PartialEq, Eq, Clone)]
331 pub struct ProcessOutput {
332 /// The status (exit code) of the process.
333 pub status: ProcessExit,
334 /// The data that the process wrote to stdout.
336 /// The data that the process wrote to stderr.
340 /// Describes what to do with a standard io stream for a child process.
341 pub enum StdioContainer {
342 /// This stream will be ignored. This is the equivalent of attaching the
343 /// stream to `/dev/null`
346 /// The specified file descriptor is inherited for the stream which it is
348 InheritFd(libc::c_int),
350 /// Creates a pipe for the specified file descriptor which will be created
351 /// when the process is spawned.
353 /// The first boolean argument is whether the pipe is readable, and the
354 /// second is whether it is writable. These properties are from the view of
355 /// the *child* process, not the parent process.
356 CreatePipe(bool /* readable */, bool /* writable */),
359 /// Describes the result of a process after it has terminated.
360 /// Note that Windows have no signals, so the result is usually ExitStatus.
361 #[deriving(PartialEq, Eq, Clone)]
362 pub enum ProcessExit {
363 /// Normal termination with an exit status.
366 /// Termination by signal, with the signal number.
370 impl fmt::Show for ProcessExit {
371 /// Format a ProcessExit enum, to nicely present the information.
372 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
374 ExitStatus(code) => write!(f, "exit code: {}", code),
375 ExitSignal(code) => write!(f, "signal: {}", code),
381 /// Was termination successful? Signal termination not considered a success,
382 /// and success is defined as a zero exit status.
383 pub fn success(&self) -> bool {
384 return self.matches_exit_status(0);
387 /// Checks whether this ProcessExit matches the given exit status.
388 /// Termination by signal will never match an exit code.
389 pub fn matches_exit_status(&self, wanted: int) -> bool {
390 *self == ExitStatus(wanted)
395 /// Sends `signal` to another process in the system identified by `id`.
397 /// Note that windows doesn't quite have the same model as unix, so some
398 /// unix signals are mapped to windows signals. Notably, unix termination
399 /// signals (SIGTERM/SIGKILL/SIGINT) are translated to `TerminateProcess`.
401 /// Additionally, a signal number of 0 can check for existence of the target
402 /// process. Note, though, that on some platforms signals will continue to
403 /// be successfully delivered if the child has exited, but not yet been
405 pub fn kill(id: libc::pid_t, signal: int) -> IoResult<()> {
406 LocalIo::maybe_raise(|io| {
408 }).map_err(IoError::from_rtio_error)
411 /// Returns the process id of this child process
412 pub fn id(&self) -> libc::pid_t { self.handle.id() }
414 /// Sends the specified signal to the child process, returning whether the
415 /// signal could be delivered or not.
417 /// Note that signal 0 is interpreted as a poll to check whether the child
418 /// process is still alive or not. If an error is returned, then the child
419 /// process has exited.
421 /// On some unix platforms signals will continue to be received after a
422 /// child has exited but not yet been reaped. In order to report the status
423 /// of signal delivery correctly, unix implementations may invoke
424 /// `waitpid()` with `WNOHANG` in order to reap the child as necessary.
428 /// If the signal delivery fails, the corresponding error is returned.
429 pub fn signal(&mut self, signal: int) -> IoResult<()> {
430 self.handle.kill(signal).map_err(IoError::from_rtio_error)
433 /// Sends a signal to this child requesting that it exits. This is
434 /// equivalent to sending a SIGTERM on unix platforms.
435 pub fn signal_exit(&mut self) -> IoResult<()> {
436 self.signal(PleaseExitSignal)
439 /// Sends a signal to this child forcing it to exit. This is equivalent to
440 /// sending a SIGKILL on unix platforms.
441 pub fn signal_kill(&mut self) -> IoResult<()> {
442 self.signal(MustDieSignal)
445 /// Wait for the child to exit completely, returning the status that it
446 /// exited with. This function will continue to have the same return value
447 /// after it has been called at least once.
449 /// The stdin handle to the child process will be closed before waiting.
453 /// This function can fail if a timeout was previously specified via
454 /// `set_timeout` and the timeout expires before the child exits.
455 pub fn wait(&mut self) -> IoResult<ProcessExit> {
456 drop(self.stdin.take());
457 match self.handle.wait() {
458 Ok(rtio::ExitSignal(s)) => Ok(ExitSignal(s)),
459 Ok(rtio::ExitStatus(s)) => Ok(ExitStatus(s)),
460 Err(e) => Err(IoError::from_rtio_error(e)),
464 /// Sets a timeout, in milliseconds, for future calls to wait().
466 /// The argument specified is a relative distance into the future, in
467 /// milliseconds, after which any call to wait() will return immediately
468 /// with a timeout error, and all future calls to wait() will not block.
470 /// A value of `None` will clear any previous timeout, and a value of `Some`
471 /// will override any previously set timeout.
476 /// # #![allow(experimental)]
477 /// use std::io::process::{Command, ProcessExit};
478 /// use std::io::IoResult;
480 /// fn run_gracefully(prog: &str) -> IoResult<ProcessExit> {
481 /// let mut p = try!(Command::new("long-running-process").spawn());
483 /// // give the process 10 seconds to finish completely
484 /// p.set_timeout(Some(10_000));
486 /// Ok(status) => return Ok(status),
490 /// // Attempt to exit gracefully, but don't wait for it too long
491 /// try!(p.signal_exit());
492 /// p.set_timeout(Some(1_000));
494 /// Ok(status) => return Ok(status),
498 /// // Well, we did our best, forcefully kill the process
499 /// try!(p.signal_kill());
500 /// p.set_timeout(None);
504 #[experimental = "the type of the timeout is likely to change"]
505 pub fn set_timeout(&mut self, timeout_ms: Option<u64>) {
506 self.handle.set_timeout(timeout_ms)
509 /// Simultaneously wait for the child to exit and collect all remaining
510 /// output on the stdout/stderr handles, returning a `ProcessOutput`
513 /// The stdin handle to the child is closed before waiting.
517 /// This function can fail for any of the same reasons that `wait()` can
519 pub fn wait_with_output(mut self) -> IoResult<ProcessOutput> {
520 drop(self.stdin.take());
521 fn read(stream: Option<io::PipeStream>) -> Receiver<IoResult<Vec<u8>>> {
522 let (tx, rx) = channel();
524 Some(stream) => spawn(proc() {
525 let mut stream = stream;
526 tx.send(stream.read_to_end())
528 None => tx.send(Ok(Vec::new()))
532 let stdout = read(self.stdout.take());
533 let stderr = read(self.stderr.take());
535 let status = try!(self.wait());
539 output: stdout.recv().ok().unwrap_or(Vec::new()),
540 error: stderr.recv().ok().unwrap_or(Vec::new()),
545 impl Drop for Process {
547 // Close all I/O before exiting to ensure that the child doesn't wait
548 // forever to print some text or something similar.
549 drop(self.stdin.take());
550 drop(self.stdout.take());
551 drop(self.stderr.take());
552 drop(mem::replace(&mut self.extra_io, Vec::new()));
554 self.set_timeout(None);
555 let _ = self.wait().unwrap();
561 use io::process::{Command, Process};
564 // FIXME(#10380) these tests should not all be ignored on android.
566 #[cfg(not(target_os="android"))]
568 let p = Command::new("true").spawn();
570 let mut p = p.unwrap();
571 assert!(p.wait().unwrap().success());
574 #[cfg(not(target_os="android"))]
575 iotest!(fn smoke_failure() {
576 match Command::new("if-this-is-a-binary-then-the-world-has-ended").spawn() {
582 #[cfg(not(target_os="android"))]
583 iotest!(fn exit_reported_right() {
584 let p = Command::new("false").spawn();
586 let mut p = p.unwrap();
587 assert!(p.wait().unwrap().matches_exit_status(1));
588 drop(p.wait().clone());
591 #[cfg(unix, not(target_os="android"))]
592 iotest!(fn signal_reported_right() {
593 let p = Command::new("/bin/sh").arg("-c").arg("kill -1 $$").spawn();
595 let mut p = p.unwrap();
596 match p.wait().unwrap() {
597 process::ExitSignal(1) => {},
598 result => fail!("not terminated by signal 1 (instead, {})", result),
602 pub fn read_all(input: &mut Reader) -> String {
603 input.read_to_str().unwrap()
606 pub fn run_output(cmd: Command) -> String {
609 let mut p = p.unwrap();
610 assert!(p.stdout.is_some());
611 let ret = read_all(p.stdout.get_mut_ref() as &mut Reader);
612 assert!(p.wait().unwrap().success());
616 #[cfg(not(target_os="android"))]
617 iotest!(fn stdout_works() {
618 let mut cmd = Command::new("echo");
619 cmd.arg("foobar").stdout(CreatePipe(false, true));
620 assert_eq!(run_output(cmd), "foobar\n".to_string());
623 #[cfg(unix, not(target_os="android"))]
624 iotest!(fn set_cwd_works() {
625 let mut cmd = Command::new("/bin/sh");
626 cmd.arg("-c").arg("pwd")
627 .cwd(&Path::new("/"))
628 .stdout(CreatePipe(false, true));
629 assert_eq!(run_output(cmd), "/\n".to_string());
632 #[cfg(unix, not(target_os="android"))]
633 iotest!(fn stdin_works() {
634 let mut p = Command::new("/bin/sh")
635 .arg("-c").arg("read line; echo $line")
636 .stdin(CreatePipe(true, false))
637 .stdout(CreatePipe(false, true))
639 p.stdin.get_mut_ref().write("foobar".as_bytes()).unwrap();
640 drop(p.stdin.take());
641 let out = read_all(p.stdout.get_mut_ref() as &mut Reader);
642 assert!(p.wait().unwrap().success());
643 assert_eq!(out, "foobar\n".to_string());
646 #[cfg(not(target_os="android"))]
647 iotest!(fn detach_works() {
648 let mut p = Command::new("true").detached().spawn().unwrap();
649 assert!(p.wait().unwrap().success());
653 iotest!(fn uid_fails_on_windows() {
654 assert!(Command::new("test").uid(10).spawn().is_err());
657 #[cfg(unix, not(target_os="android"))]
658 iotest!(fn uid_works() {
660 let mut p = Command::new("/bin/sh")
661 .arg("-c").arg("true")
662 .uid(unsafe { libc::getuid() as uint })
663 .gid(unsafe { libc::getgid() as uint })
665 assert!(p.wait().unwrap().success());
668 #[cfg(unix, not(target_os="android"))]
669 iotest!(fn uid_to_root_fails() {
672 // if we're already root, this isn't a valid test. Most of the bots run
673 // as non-root though (android is an exception).
674 if unsafe { libc::getuid() == 0 } { return }
675 assert!(Command::new("/bin/ls").uid(0).gid(0).spawn().is_err());
678 #[cfg(not(target_os="android"))]
679 iotest!(fn test_process_status() {
680 let mut status = Command::new("false").status().unwrap();
681 assert!(status.matches_exit_status(1));
683 status = Command::new("true").status().unwrap();
684 assert!(status.success());
687 iotest!(fn test_process_output_fail_to_start() {
688 match Command::new("/no-binary-by-this-name-should-exist").output() {
689 Err(e) => assert_eq!(e.kind, FileNotFound),
694 #[cfg(not(target_os="android"))]
695 iotest!(fn test_process_output_output() {
696 let ProcessOutput {status, output, error}
697 = Command::new("echo").arg("hello").output().unwrap();
698 let output_str = str::from_utf8(output.as_slice()).unwrap();
700 assert!(status.success());
701 assert_eq!(output_str.trim().to_string(), "hello".to_string());
703 if !running_on_valgrind() {
704 assert_eq!(error, Vec::new());
708 #[cfg(not(target_os="android"))]
709 iotest!(fn test_process_output_error() {
710 let ProcessOutput {status, output, error}
711 = Command::new("mkdir").arg(".").output().unwrap();
713 assert!(status.matches_exit_status(1));
714 assert_eq!(output, Vec::new());
715 assert!(!error.is_empty());
718 #[cfg(not(target_os="android"))]
719 iotest!(fn test_finish_once() {
720 let mut prog = Command::new("false").spawn().unwrap();
721 assert!(prog.wait().unwrap().matches_exit_status(1));
724 #[cfg(not(target_os="android"))]
725 iotest!(fn test_finish_twice() {
726 let mut prog = Command::new("false").spawn().unwrap();
727 assert!(prog.wait().unwrap().matches_exit_status(1));
728 assert!(prog.wait().unwrap().matches_exit_status(1));
731 #[cfg(not(target_os="android"))]
732 iotest!(fn test_wait_with_output_once() {
733 let prog = Command::new("echo").arg("hello").spawn().unwrap();
734 let ProcessOutput {status, output, error} = prog.wait_with_output().unwrap();
735 let output_str = str::from_utf8(output.as_slice()).unwrap();
737 assert!(status.success());
738 assert_eq!(output_str.trim().to_string(), "hello".to_string());
740 if !running_on_valgrind() {
741 assert_eq!(error, Vec::new());
745 #[cfg(unix,not(target_os="android"))]
746 pub fn pwd_cmd() -> Command {
749 #[cfg(target_os="android")]
750 pub fn pwd_cmd() -> Command {
751 let mut cmd = Command::new("/system/bin/sh");
752 cmd.arg("-c").arg("pwd");
757 pub fn pwd_cmd() -> Command {
758 let mut cmd = Command::new("cmd");
759 cmd.arg("/c").arg("cd");
763 iotest!(fn test_keep_current_working_dir() {
765 let prog = pwd_cmd().spawn().unwrap();
767 let output = str::from_utf8(prog.wait_with_output().unwrap()
768 .output.as_slice()).unwrap().to_string();
769 let parent_dir = os::getcwd();
770 let child_dir = Path::new(output.as_slice().trim());
772 let parent_stat = parent_dir.stat().unwrap();
773 let child_stat = child_dir.stat().unwrap();
775 assert_eq!(parent_stat.unstable.device, child_stat.unstable.device);
776 assert_eq!(parent_stat.unstable.inode, child_stat.unstable.inode);
779 iotest!(fn test_change_working_directory() {
781 // test changing to the parent of os::getcwd() because we know
782 // the path exists (and os::getcwd() is not expected to be root)
783 let parent_dir = os::getcwd().dir_path();
784 let prog = pwd_cmd().cwd(&parent_dir).spawn().unwrap();
786 let output = str::from_utf8(prog.wait_with_output().unwrap()
787 .output.as_slice()).unwrap().to_string();
788 let child_dir = Path::new(output.as_slice().trim().into_string());
790 let parent_stat = parent_dir.stat().unwrap();
791 let child_stat = child_dir.stat().unwrap();
793 assert_eq!(parent_stat.unstable.device, child_stat.unstable.device);
794 assert_eq!(parent_stat.unstable.inode, child_stat.unstable.inode);
797 #[cfg(unix,not(target_os="android"))]
798 pub fn env_cmd() -> Command {
801 #[cfg(target_os="android")]
802 pub fn env_cmd() -> Command {
803 let mut cmd = Command::new("/system/bin/sh");
804 cmd.arg("-c").arg("set");
809 pub fn env_cmd() -> Command {
810 let mut cmd = Command::new("cmd");
811 cmd.arg("/c").arg("set");
815 #[cfg(not(target_os="android"))]
816 iotest!(fn test_inherit_env() {
818 if running_on_valgrind() { return; }
820 let prog = env_cmd().spawn().unwrap();
821 let output = str::from_utf8(prog.wait_with_output().unwrap()
822 .output.as_slice()).unwrap().to_string();
825 for &(ref k, ref v) in r.iter() {
826 // don't check windows magical empty-named variables
827 assert!(k.is_empty() ||
829 .contains(format!("{}={}", *k, *v).as_slice()));
832 #[cfg(target_os="android")]
833 iotest!(fn test_inherit_env() {
835 if running_on_valgrind() { return; }
837 let mut prog = env_cmd().spawn().unwrap();
838 let output = str::from_utf8(prog.wait_with_output()
839 .unwrap().output.as_slice())
840 .unwrap().to_string();
843 for &(ref k, ref v) in r.iter() {
844 // don't check android RANDOM variables
845 if *k != "RANDOM".to_string() {
846 assert!(output.as_slice()
847 .contains(format!("{}={}",
851 .contains(format!("{}=\'{}\'",
858 iotest!(fn test_add_to_env() {
859 let new_env = vec![("RUN_TEST_NEW_ENV", "123")];
860 let prog = env_cmd().env(new_env.as_slice()).spawn().unwrap();
861 let result = prog.wait_with_output().unwrap();
862 let output = str::from_utf8_lossy(result.output.as_slice()).into_string();
864 assert!(output.as_slice().contains("RUN_TEST_NEW_ENV=123"),
865 "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output);
869 pub fn sleeper() -> Process {
870 Command::new("sleep").arg("1000").spawn().unwrap()
873 pub fn sleeper() -> Process {
874 // There's a `timeout` command on windows, but it doesn't like having
875 // its output piped, so instead just ping ourselves a few times with
876 // gaps in between so we're sure this process is alive for awhile
877 Command::new("ping").arg("127.0.0.1").arg("-n").arg("1000").spawn().unwrap()
880 iotest!(fn test_kill() {
881 let mut p = sleeper();
882 Process::kill(p.id(), PleaseExitSignal).unwrap();
883 assert!(!p.wait().unwrap().success());
886 iotest!(fn test_exists() {
887 let mut p = sleeper();
888 assert!(Process::kill(p.id(), 0).is_ok());
889 p.signal_kill().unwrap();
890 assert!(!p.wait().unwrap().success());
893 iotest!(fn test_zero() {
894 let mut p = sleeper();
895 p.signal_kill().unwrap();
896 for _ in range(0, 20) {
897 if p.signal(0).is_err() {
898 assert!(!p.wait().unwrap().success());
903 fail!("never saw the child go away");
906 iotest!(fn wait_timeout() {
907 let mut p = sleeper();
908 p.set_timeout(Some(10));
909 assert_eq!(p.wait().err().unwrap().kind, TimedOut);
910 assert_eq!(p.wait().err().unwrap().kind, TimedOut);
911 p.signal_kill().unwrap();
913 assert!(p.wait().is_ok());
916 iotest!(fn wait_timeout2() {
917 let (tx, rx) = channel();
918 let tx2 = tx.clone();
920 let mut p = sleeper();
921 p.set_timeout(Some(10));
922 assert_eq!(p.wait().err().unwrap().kind, TimedOut);
923 p.signal_kill().unwrap();
927 let mut p = sleeper();
928 p.set_timeout(Some(10));
929 assert_eq!(p.wait().err().unwrap().kind, TimedOut);
930 p.signal_kill().unwrap();