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)]
14 #![allow(non_upper_case_globals)]
16 pub use self::StdioContainer::*;
17 pub use self::ProcessExit::*;
21 use collections::HashMap;
25 use io::pipe::{PipeStream, PipePair};
26 use io::{IoResult, IoError};
30 use path::BytesContainer;
31 use sync::mpsc::{channel, Receiver};
32 use sys::fs::FileDesc;
33 use sys::process::Process as ProcessImp;
37 #[cfg(windows)] use std::hash::sip::SipState;
38 #[cfg(windows)] use str;
40 /// Signal a process to exit, without forcibly killing it. Corresponds to
41 /// SIGTERM on unix platforms.
42 #[cfg(windows)] pub const PleaseExitSignal: int = 15;
43 /// Signal a process to exit immediately, forcibly killing it. Corresponds to
44 /// SIGKILL on unix platforms.
45 #[cfg(windows)] pub const MustDieSignal: int = 9;
46 /// Signal a process to exit, without forcibly killing it. Corresponds to
47 /// SIGTERM on unix platforms.
48 #[cfg(not(windows))] pub const PleaseExitSignal: int = libc::SIGTERM as int;
49 /// Signal a process to exit immediately, forcibly killing it. Corresponds to
50 /// SIGKILL on unix platforms.
51 #[cfg(not(windows))] pub const MustDieSignal: int = libc::SIGKILL as int;
53 /// Representation of a running or exited child process.
55 /// This structure is used to represent and manage child processes. A child
56 /// process is created via the `Command` struct, which configures the spawning
57 /// process and can itself be constructed using a builder-style interface.
62 /// use std::io::Command;
64 /// let mut child = match Command::new("/bin/cat").arg("file.txt").spawn() {
65 /// Ok(child) => child,
66 /// Err(e) => panic!("failed to execute child: {}", e),
69 /// let contents = child.stdout.as_mut().unwrap().read_to_end();
70 /// assert!(child.wait().unwrap().success());
76 /// None until wait() is called.
77 exit_code: Option<ProcessExit>,
79 /// Manually delivered signal
80 exit_signal: Option<int>,
82 /// Deadline after which wait() will return
85 /// Handle to the child's stdin, if the `stdin` field of this process's
86 /// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`.
87 pub stdin: Option<PipeStream>,
89 /// Handle to the child's stdout, if the `stdout` field of this process's
90 /// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`.
91 pub stdout: Option<PipeStream>,
93 /// Handle to the child's stderr, if the `stderr` field of this process's
94 /// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`.
95 pub stderr: Option<PipeStream>,
98 /// A representation of environment variable name
99 /// It compares case-insensitive on Windows and case-sensitive everywhere else.
101 #[derive(PartialEq, Eq, Hash, Clone, Show)]
102 struct EnvKey(CString);
106 #[derive(Eq, Clone, Show)]
107 struct EnvKey(CString);
110 impl Hash for EnvKey {
111 fn hash(&self, state: &mut SipState) {
112 let &EnvKey(ref x) = self;
113 match str::from_utf8(x.as_bytes()) {
114 Ok(s) => for ch in s.chars() {
115 (ch as u8 as char).to_lowercase().hash(state);
117 Err(..) => x.hash(state)
123 impl PartialEq for EnvKey {
124 fn eq(&self, other: &EnvKey) -> bool {
125 let &EnvKey(ref x) = self;
126 let &EnvKey(ref y) = other;
127 match (str::from_utf8(x.as_bytes()), str::from_utf8(y.as_bytes())) {
128 (Ok(xs), Ok(ys)) => {
129 if xs.len() != ys.len() {
132 for (xch, ych) in xs.chars().zip(ys.chars()) {
133 if xch.to_lowercase() != ych.to_lowercase() {
140 // If either is not a valid utf8 string, just compare them byte-wise
146 impl BytesContainer for EnvKey {
147 fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
148 let &EnvKey(ref k) = self;
149 k.container_as_bytes()
153 /// A HashMap representation of environment variables.
154 pub type EnvMap = HashMap<EnvKey, CString>;
156 /// The `Command` type acts as a process builder, providing fine-grained control
157 /// over how a new process should be spawned. A default configuration can be
158 /// generated using `Command::new(program)`, where `program` gives a path to the
159 /// program to be executed. Additional builder methods allow the configuration
160 /// to be changed (for example, by adding arguments) prior to spawning:
163 /// use std::io::Command;
165 /// let mut process = match Command::new("sh").arg("-c").arg("echo hello").spawn() {
167 /// Err(e) => panic!("failed to execute process: {}", e),
170 /// let output = process.stdout.as_mut().unwrap().read_to_end();
174 // The internal data for the builder. Documented by the builder
175 // methods below, and serialized into rt::rtio::ProcessConfig.
179 cwd: Option<CString>,
180 stdin: StdioContainer,
181 stdout: StdioContainer,
182 stderr: StdioContainer,
188 // FIXME (#12938): Until DST lands, we cannot decompose &str into & and str, so
189 // we cannot usefully take BytesContainer arguments by reference (without forcing an
190 // additional & around &str). So we are instead temporarily adding an instance
191 // for &Path, so that we can take BytesContainer as owned. When DST lands, the &Path
192 // instance should be removed, and arguments bound by BytesContainer should be passed by
193 // reference. (Here: {new, arg, args, env}.)
196 /// Constructs a new `Command` for launching the program at
197 /// path `program`, with the following default configuration:
199 /// * No arguments to the program
200 /// * Inherit the current process's environment
201 /// * Inherit the current process's working directory
202 /// * A readable pipe for stdin (file descriptor 0)
203 /// * A writeable pipe for stdout and stderr (file descriptors 1 and 2)
205 /// Builder methods are provided to change these defaults and
206 /// otherwise configure the process.
207 pub fn new<T: BytesContainer>(program: T) -> Command {
209 program: CString::from_slice(program.container_as_bytes()),
213 stdin: CreatePipe(true, false),
214 stdout: CreatePipe(false, true),
215 stderr: CreatePipe(false, true),
222 /// Add an argument to pass to the program.
223 pub fn arg<'a, T: BytesContainer>(&'a mut self, arg: T) -> &'a mut Command {
224 self.args.push(CString::from_slice(arg.container_as_bytes()));
228 /// Add multiple arguments to pass to the program.
229 pub fn args<'a, T: BytesContainer>(&'a mut self, args: &[T]) -> &'a mut Command {
230 self.args.extend(args.iter().map(|arg| {
231 CString::from_slice(arg.container_as_bytes())
235 // Get a mutable borrow of the environment variable map for this `Command`.
236 fn get_env_map<'a>(&'a mut self) -> &'a mut EnvMap {
238 Some(ref mut map) => map,
240 // if the env is currently just inheriting from the parent's,
241 // materialize the parent's env into a hashtable.
242 self.env = Some(os::env_as_bytes().into_iter().map(|(k, v)| {
243 (EnvKey(CString::from_slice(k.as_slice())),
244 CString::from_slice(v.as_slice()))
246 self.env.as_mut().unwrap()
251 /// Inserts or updates an environment variable mapping.
253 /// Note that environment variable names are case-insensitive (but case-preserving) on Windows,
254 /// and case-sensitive on all other platforms.
255 pub fn env<'a, T, U>(&'a mut self, key: T, val: U)
257 where T: BytesContainer, U: BytesContainer {
258 let key = EnvKey(CString::from_slice(key.container_as_bytes()));
259 let val = CString::from_slice(val.container_as_bytes());
260 self.get_env_map().insert(key, val);
264 /// Removes an environment variable mapping.
265 pub fn env_remove<'a, T>(&'a mut self, key: T) -> &'a mut Command
266 where T: BytesContainer {
267 let key = EnvKey(CString::from_slice(key.container_as_bytes()));
268 self.get_env_map().remove(&key);
272 /// Sets the entire environment map for the child process.
274 /// If the given slice contains multiple instances of an environment
275 /// variable, the *rightmost* instance will determine the value.
276 pub fn env_set_all<'a, T, U>(&'a mut self, env: &[(T,U)])
278 where T: BytesContainer, U: BytesContainer {
279 self.env = Some(env.iter().map(|&(ref k, ref v)| {
280 (EnvKey(CString::from_slice(k.container_as_bytes())),
281 CString::from_slice(v.container_as_bytes()))
286 /// Set the working directory for the child process.
287 pub fn cwd<'a>(&'a mut self, dir: &Path) -> &'a mut Command {
288 self.cwd = Some(CString::from_slice(dir.as_vec()));
292 /// Configuration for the child process's stdin handle (file descriptor 0).
293 /// Defaults to `CreatePipe(true, false)` so the input can be written to.
294 pub fn stdin<'a>(&'a mut self, cfg: StdioContainer) -> &'a mut Command {
299 /// Configuration for the child process's stdout handle (file descriptor 1).
300 /// Defaults to `CreatePipe(false, true)` so the output can be collected.
301 pub fn stdout<'a>(&'a mut self, cfg: StdioContainer) -> &'a mut Command {
306 /// Configuration for the child process's stderr handle (file descriptor 2).
307 /// Defaults to `CreatePipe(false, true)` so the output can be collected.
308 pub fn stderr<'a>(&'a mut self, cfg: StdioContainer) -> &'a mut Command {
313 /// Sets the child process's user id. This translates to a `setuid` call in
314 /// the child process. Setting this value on windows will cause the spawn to
315 /// fail. Failure in the `setuid` call on unix will also cause the spawn to
317 pub fn uid<'a>(&'a mut self, id: uint) -> &'a mut Command {
322 /// Similar to `uid`, but sets the group id of the child process. This has
323 /// the same semantics as the `uid` field.
324 pub fn gid<'a>(&'a mut self, id: uint) -> &'a mut Command {
329 /// Sets the child process to be spawned in a detached state. On unix, this
330 /// means that the child is the leader of a new process group.
331 pub fn detached<'a>(&'a mut self) -> &'a mut Command {
336 /// Executes the command as a child process, which is returned.
337 pub fn spawn(&self) -> IoResult<Process> {
338 let (their_stdin, our_stdin) = try!(setup_io(self.stdin));
339 let (their_stdout, our_stdout) = try!(setup_io(self.stdout));
340 let (their_stderr, our_stderr) = try!(setup_io(self.stderr));
342 match ProcessImp::spawn(self, their_stdin, their_stdout, their_stderr) {
344 Ok(handle) => Ok(Process {
357 /// Executes the command as a child process, waiting for it to finish and
358 /// collecting all of its output.
363 /// use std::io::Command;
365 /// let output = match Command::new("cat").arg("foot.txt").output() {
366 /// Ok(output) => output,
367 /// Err(e) => panic!("failed to execute process: {}", e),
370 /// println!("status: {}", output.status);
371 /// println!("stdout: {}", String::from_utf8_lossy(output.output.as_slice()));
372 /// println!("stderr: {}", String::from_utf8_lossy(output.error.as_slice()));
374 pub fn output(&self) -> IoResult<ProcessOutput> {
375 self.spawn().and_then(|p| p.wait_with_output())
378 /// Executes a command as a child process, waiting for it to finish and
379 /// collecting its exit status.
384 /// use std::io::Command;
386 /// let status = match Command::new("ls").status() {
387 /// Ok(status) => status,
388 /// Err(e) => panic!("failed to execute process: {}", e),
391 /// println!("process exited with: {}", status);
393 pub fn status(&self) -> IoResult<ProcessExit> {
394 self.spawn().and_then(|mut p| p.wait())
399 impl fmt::Show for Command {
400 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
401 fmt::String::fmt(self, f)
405 impl fmt::String for Command {
406 /// Format the program and arguments of a Command for display. Any
407 /// non-utf8 data is lossily converted using the utf8 replacement
409 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
410 try!(write!(f, "{}", String::from_utf8_lossy(self.program.as_bytes())));
411 for arg in self.args.iter() {
412 try!(write!(f, " '{}'", String::from_utf8_lossy(arg.as_bytes())));
418 fn setup_io(io: StdioContainer) -> IoResult<(Option<PipeStream>, Option<PipeStream>)> {
427 theirs = Some(PipeStream::from_filedesc(FileDesc::new(fd, false)));
430 CreatePipe(readable, _writable) => {
431 let PipePair { reader, writer } = try!(PipeStream::pair());
433 theirs = Some(reader);
436 theirs = Some(writer);
444 // Allow the sys module to get access to the Command state
445 impl sys::process::ProcessConfig<EnvKey, CString> for Command {
446 fn program(&self) -> &CString {
449 fn args(&self) -> &[CString] {
452 fn env(&self) -> Option<&EnvMap> {
455 fn cwd(&self) -> Option<&CString> {
458 fn uid(&self) -> Option<uint> {
461 fn gid(&self) -> Option<uint> {
464 fn detach(&self) -> bool {
470 /// The output of a finished process.
471 #[derive(PartialEq, Eq, Clone)]
472 pub struct ProcessOutput {
473 /// The status (exit code) of the process.
474 pub status: ProcessExit,
475 /// The data that the process wrote to stdout.
477 /// The data that the process wrote to stderr.
481 /// Describes what to do with a standard io stream for a child process.
482 #[derive(Clone, Copy)]
483 pub enum StdioContainer {
484 /// This stream will be ignored. This is the equivalent of attaching the
485 /// stream to `/dev/null`
488 /// The specified file descriptor is inherited for the stream which it is
489 /// specified for. Ownership of the file descriptor is *not* taken, so the
490 /// caller must clean it up.
491 InheritFd(libc::c_int),
493 /// Creates a pipe for the specified file descriptor which will be created
494 /// when the process is spawned.
496 /// The first boolean argument is whether the pipe is readable, and the
497 /// second is whether it is writable. These properties are from the view of
498 /// the *child* process, not the parent process.
499 CreatePipe(bool /* readable */, bool /* writable */),
502 /// Describes the result of a process after it has terminated.
503 /// Note that Windows have no signals, so the result is usually ExitStatus.
504 #[derive(PartialEq, Eq, Clone, Copy)]
505 pub enum ProcessExit {
506 /// Normal termination with an exit status.
509 /// Termination by signal, with the signal number.
513 impl fmt::Show for ProcessExit {
514 /// Format a ProcessExit enum, to nicely present the information.
515 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
516 fmt::String::fmt(self, f)
521 impl fmt::String for ProcessExit {
522 /// Format a ProcessExit enum, to nicely present the information.
523 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
525 ExitStatus(code) => write!(f, "exit code: {}", code),
526 ExitSignal(code) => write!(f, "signal: {}", code),
532 /// Was termination successful? Signal termination not considered a success,
533 /// and success is defined as a zero exit status.
534 pub fn success(&self) -> bool {
535 return self.matches_exit_status(0);
538 /// Checks whether this ProcessExit matches the given exit status.
539 /// Termination by signal will never match an exit code.
540 pub fn matches_exit_status(&self, wanted: int) -> bool {
541 *self == ExitStatus(wanted)
546 /// Sends `signal` to another process in the system identified by `id`.
548 /// Note that windows doesn't quite have the same model as unix, so some
549 /// unix signals are mapped to windows signals. Notably, unix termination
550 /// signals (SIGTERM/SIGKILL/SIGINT) are translated to `TerminateProcess`.
552 /// Additionally, a signal number of 0 can check for existence of the target
553 /// process. Note, though, that on some platforms signals will continue to
554 /// be successfully delivered if the child has exited, but not yet been
556 pub fn kill(id: libc::pid_t, signal: int) -> IoResult<()> {
557 unsafe { ProcessImp::killpid(id, signal) }
560 /// Returns the process id of this child process
561 pub fn id(&self) -> libc::pid_t { self.handle.id() }
563 /// Sends the specified signal to the child process, returning whether the
564 /// signal could be delivered or not.
566 /// Note that signal 0 is interpreted as a poll to check whether the child
567 /// process is still alive or not. If an error is returned, then the child
568 /// process has exited.
570 /// On some unix platforms signals will continue to be received after a
571 /// child has exited but not yet been reaped. In order to report the status
572 /// of signal delivery correctly, unix implementations may invoke
573 /// `waitpid()` with `WNOHANG` in order to reap the child as necessary.
577 /// If the signal delivery fails, the corresponding error is returned.
578 pub fn signal(&mut self, signal: int) -> IoResult<()> {
579 #[cfg(unix)] fn collect_status(p: &mut Process) {
580 // On Linux (and possibly other unices), a process that has exited will
581 // continue to accept signals because it is "defunct". The delivery of
582 // signals will only fail once the child has been reaped. For this
583 // reason, if the process hasn't exited yet, then we attempt to collect
584 // their status with WNOHANG.
585 if p.exit_code.is_none() {
586 match p.handle.try_wait() {
587 Some(code) => { p.exit_code = Some(code); }
592 #[cfg(windows)] fn collect_status(_p: &mut Process) {}
594 collect_status(self);
596 // if the process has finished, and therefore had waitpid called,
597 // and we kill it, then on unix we might ending up killing a
598 // newer process that happens to have the same (re-used) id
599 if self.exit_code.is_some() {
601 kind: io::InvalidInput,
602 desc: "invalid argument: can't kill an exited process",
607 // A successfully delivered signal that isn't 0 (just a poll for being
608 // alive) is recorded for windows (see wait())
609 match unsafe { self.handle.kill(signal) } {
610 Ok(()) if signal == 0 => Ok(()),
611 Ok(()) => { self.exit_signal = Some(signal); Ok(()) }
617 /// Sends a signal to this child requesting that it exits. This is
618 /// equivalent to sending a SIGTERM on unix platforms.
619 pub fn signal_exit(&mut self) -> IoResult<()> {
620 self.signal(PleaseExitSignal)
623 /// Sends a signal to this child forcing it to exit. This is equivalent to
624 /// sending a SIGKILL on unix platforms.
625 pub fn signal_kill(&mut self) -> IoResult<()> {
626 self.signal(MustDieSignal)
629 /// Wait for the child to exit completely, returning the status that it
630 /// exited with. This function will continue to have the same return value
631 /// after it has been called at least once.
633 /// The stdin handle to the child process will be closed before waiting.
637 /// This function can fail if a timeout was previously specified via
638 /// `set_timeout` and the timeout expires before the child exits.
639 pub fn wait(&mut self) -> IoResult<ProcessExit> {
640 drop(self.stdin.take());
641 match self.exit_code {
642 Some(code) => Ok(code),
644 let code = try!(self.handle.wait(self.deadline));
645 // On windows, waitpid will never return a signal. If a signal
646 // was successfully delivered to the process, however, we can
647 // consider it as having died via a signal.
648 let code = match self.exit_signal {
650 Some(signal) if cfg!(windows) => ExitSignal(signal),
653 self.exit_code = Some(code);
659 /// Sets a timeout, in milliseconds, for future calls to wait().
661 /// The argument specified is a relative distance into the future, in
662 /// milliseconds, after which any call to wait() will return immediately
663 /// with a timeout error, and all future calls to wait() will not block.
665 /// A value of `None` will clear any previous timeout, and a value of `Some`
666 /// will override any previously set timeout.
671 /// # #![allow(experimental)]
672 /// use std::io::{Command, IoResult};
673 /// use std::io::process::ProcessExit;
675 /// fn run_gracefully(prog: &str) -> IoResult<ProcessExit> {
676 /// let mut p = try!(Command::new("long-running-process").spawn());
678 /// // give the process 10 seconds to finish completely
679 /// p.set_timeout(Some(10_000));
681 /// Ok(status) => return Ok(status),
685 /// // Attempt to exit gracefully, but don't wait for it too long
686 /// try!(p.signal_exit());
687 /// p.set_timeout(Some(1_000));
689 /// Ok(status) => return Ok(status),
693 /// // Well, we did our best, forcefully kill the process
694 /// try!(p.signal_kill());
695 /// p.set_timeout(None);
699 #[experimental = "the type of the timeout is likely to change"]
700 pub fn set_timeout(&mut self, timeout_ms: Option<u64>) {
701 self.deadline = timeout_ms.map(|i| i + sys::timer::now()).unwrap_or(0);
704 /// Simultaneously wait for the child to exit and collect all remaining
705 /// output on the stdout/stderr handles, returning a `ProcessOutput`
708 /// The stdin handle to the child is closed before waiting.
712 /// This function can fail for any of the same reasons that `wait()` can
714 pub fn wait_with_output(mut self) -> IoResult<ProcessOutput> {
715 drop(self.stdin.take());
716 fn read(stream: Option<io::PipeStream>) -> Receiver<IoResult<Vec<u8>>> {
717 let (tx, rx) = channel();
720 Thread::spawn(move |:| {
721 let mut stream = stream;
722 tx.send(stream.read_to_end()).unwrap();
725 None => tx.send(Ok(Vec::new())).unwrap()
729 let stdout = read(self.stdout.take());
730 let stderr = read(self.stderr.take());
732 let status = try!(self.wait());
736 output: stdout.recv().unwrap().unwrap_or(Vec::new()),
737 error: stderr.recv().unwrap().unwrap_or(Vec::new()),
741 /// Forgets this process, allowing it to outlive the parent
743 /// This function will forcefully prevent calling `wait()` on the child
744 /// process in the destructor, allowing the child to outlive the
745 /// parent. Note that this operation can easily lead to leaking the
746 /// resources of the child process, so care must be taken when
747 /// invoking this method.
748 pub fn forget(mut self) {
753 impl Drop for Process {
755 if self.forget { return }
757 // Close all I/O before exiting to ensure that the child doesn't wait
758 // forever to print some text or something similar.
759 drop(self.stdin.take());
760 drop(self.stdout.take());
761 drop(self.stderr.take());
763 self.set_timeout(None);
764 let _ = self.wait().unwrap();
770 use io::{Truncate, Write, TimedOut, timer, process, FileNotFound};
771 use prelude::v1::{Ok, Err, range, drop, Some, None, Vec};
772 use prelude::v1::{Path, String, Reader, Writer, Clone};
773 use prelude::v1::{SliceExt, Str, StrExt, AsSlice, ToString, GenericPath};
774 use io::fs::PathExtensions;
776 use rt::running_on_valgrind;
778 use super::{CreatePipe};
779 use super::{InheritFd, Process, PleaseExitSignal, Command, ProcessOutput};
780 use sync::mpsc::channel;
784 // FIXME(#10380) these tests should not all be ignored on android.
786 #[cfg(not(target_os="android"))]
789 let p = Command::new("true").spawn();
791 let mut p = p.unwrap();
792 assert!(p.wait().unwrap().success());
795 #[cfg(not(target_os="android"))]
798 match Command::new("if-this-is-a-binary-then-the-world-has-ended").spawn() {
804 #[cfg(not(target_os="android"))]
806 fn exit_reported_right() {
807 let p = Command::new("false").spawn();
809 let mut p = p.unwrap();
810 assert!(p.wait().unwrap().matches_exit_status(1));
811 drop(p.wait().clone());
814 #[cfg(all(unix, not(target_os="android")))]
816 fn signal_reported_right() {
817 let p = Command::new("/bin/sh").arg("-c").arg("kill -1 $$").spawn();
819 let mut p = p.unwrap();
820 match p.wait().unwrap() {
821 process::ExitSignal(1) => {},
822 result => panic!("not terminated by signal 1 (instead, {})", result),
826 pub fn read_all(input: &mut Reader) -> String {
827 input.read_to_string().unwrap()
830 pub fn run_output(cmd: Command) -> String {
833 let mut p = p.unwrap();
834 assert!(p.stdout.is_some());
835 let ret = read_all(p.stdout.as_mut().unwrap() as &mut Reader);
836 assert!(p.wait().unwrap().success());
840 #[cfg(not(target_os="android"))]
843 let mut cmd = Command::new("echo");
844 cmd.arg("foobar").stdout(CreatePipe(false, true));
845 assert_eq!(run_output(cmd), "foobar\n");
848 #[cfg(all(unix, not(target_os="android")))]
851 let mut cmd = Command::new("/bin/sh");
852 cmd.arg("-c").arg("pwd")
853 .cwd(&Path::new("/"))
854 .stdout(CreatePipe(false, true));
855 assert_eq!(run_output(cmd), "/\n");
858 #[cfg(all(unix, not(target_os="android")))]
861 let mut p = Command::new("/bin/sh")
862 .arg("-c").arg("read line; echo $line")
863 .stdin(CreatePipe(true, false))
864 .stdout(CreatePipe(false, true))
866 p.stdin.as_mut().unwrap().write("foobar".as_bytes()).unwrap();
867 drop(p.stdin.take());
868 let out = read_all(p.stdout.as_mut().unwrap() as &mut Reader);
869 assert!(p.wait().unwrap().success());
870 assert_eq!(out, "foobar\n");
873 #[cfg(not(target_os="android"))]
876 let mut p = Command::new("true").detached().spawn().unwrap();
877 assert!(p.wait().unwrap().success());
882 fn uid_fails_on_windows() {
883 assert!(Command::new("test").uid(10).spawn().is_err());
886 #[cfg(all(unix, not(target_os="android")))]
890 let mut p = Command::new("/bin/sh")
891 .arg("-c").arg("true")
892 .uid(unsafe { libc::getuid() as uint })
893 .gid(unsafe { libc::getgid() as uint })
895 assert!(p.wait().unwrap().success());
898 #[cfg(all(unix, not(target_os="android")))]
900 fn uid_to_root_fails() {
903 // if we're already root, this isn't a valid test. Most of the bots run
904 // as non-root though (android is an exception).
905 if unsafe { libc::getuid() == 0 } { return }
906 assert!(Command::new("/bin/ls").uid(0).gid(0).spawn().is_err());
909 #[cfg(not(target_os="android"))]
911 fn test_process_status() {
912 let mut status = Command::new("false").status().unwrap();
913 assert!(status.matches_exit_status(1));
915 status = Command::new("true").status().unwrap();
916 assert!(status.success());
920 fn test_process_output_fail_to_start() {
921 match Command::new("/no-binary-by-this-name-should-exist").output() {
922 Err(e) => assert_eq!(e.kind, FileNotFound),
927 #[cfg(not(target_os="android"))]
929 fn test_process_output_output() {
930 let ProcessOutput {status, output, error}
931 = Command::new("echo").arg("hello").output().unwrap();
932 let output_str = str::from_utf8(output.as_slice()).unwrap();
934 assert!(status.success());
935 assert_eq!(output_str.trim().to_string(), "hello");
937 if !running_on_valgrind() {
938 assert_eq!(error, Vec::new());
942 #[cfg(not(target_os="android"))]
944 fn test_process_output_error() {
945 let ProcessOutput {status, output, error}
946 = Command::new("mkdir").arg(".").output().unwrap();
948 assert!(status.matches_exit_status(1));
949 assert_eq!(output, Vec::new());
950 assert!(!error.is_empty());
953 #[cfg(not(target_os="android"))]
955 fn test_finish_once() {
956 let mut prog = Command::new("false").spawn().unwrap();
957 assert!(prog.wait().unwrap().matches_exit_status(1));
960 #[cfg(not(target_os="android"))]
962 fn test_finish_twice() {
963 let mut prog = Command::new("false").spawn().unwrap();
964 assert!(prog.wait().unwrap().matches_exit_status(1));
965 assert!(prog.wait().unwrap().matches_exit_status(1));
968 #[cfg(not(target_os="android"))]
970 fn test_wait_with_output_once() {
971 let prog = Command::new("echo").arg("hello").spawn().unwrap();
972 let ProcessOutput {status, output, error} = prog.wait_with_output().unwrap();
973 let output_str = str::from_utf8(output.as_slice()).unwrap();
975 assert!(status.success());
976 assert_eq!(output_str.trim().to_string(), "hello");
978 if !running_on_valgrind() {
979 assert_eq!(error, Vec::new());
983 #[cfg(all(unix, not(target_os="android")))]
984 pub fn pwd_cmd() -> Command {
987 #[cfg(target_os="android")]
988 pub fn pwd_cmd() -> Command {
989 let mut cmd = Command::new("/system/bin/sh");
990 cmd.arg("-c").arg("pwd");
995 pub fn pwd_cmd() -> Command {
996 let mut cmd = Command::new("cmd");
997 cmd.arg("/c").arg("cd");
1002 fn test_keep_current_working_dir() {
1004 let prog = pwd_cmd().spawn().unwrap();
1006 let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap();
1007 let parent_dir = os::getcwd().unwrap();
1008 let child_dir = Path::new(output.trim());
1010 let parent_stat = parent_dir.stat().unwrap();
1011 let child_stat = child_dir.stat().unwrap();
1013 assert_eq!(parent_stat.unstable.device, child_stat.unstable.device);
1014 assert_eq!(parent_stat.unstable.inode, child_stat.unstable.inode);
1018 fn test_change_working_directory() {
1020 // test changing to the parent of os::getcwd() because we know
1021 // the path exists (and os::getcwd() is not expected to be root)
1022 let parent_dir = os::getcwd().unwrap().dir_path();
1023 let prog = pwd_cmd().cwd(&parent_dir).spawn().unwrap();
1025 let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap();
1026 let child_dir = Path::new(output.trim());
1028 let parent_stat = parent_dir.stat().unwrap();
1029 let child_stat = child_dir.stat().unwrap();
1031 assert_eq!(parent_stat.unstable.device, child_stat.unstable.device);
1032 assert_eq!(parent_stat.unstable.inode, child_stat.unstable.inode);
1035 #[cfg(all(unix, not(target_os="android")))]
1036 pub fn env_cmd() -> Command {
1039 #[cfg(target_os="android")]
1040 pub fn env_cmd() -> Command {
1041 let mut cmd = Command::new("/system/bin/sh");
1042 cmd.arg("-c").arg("set");
1047 pub fn env_cmd() -> Command {
1048 let mut cmd = Command::new("cmd");
1049 cmd.arg("/c").arg("set");
1053 #[cfg(not(target_os="android"))]
1055 fn test_inherit_env() {
1057 if running_on_valgrind() { return; }
1059 let prog = env_cmd().spawn().unwrap();
1060 let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap();
1063 for &(ref k, ref v) in r.iter() {
1064 // don't check windows magical empty-named variables
1065 assert!(k.is_empty() ||
1066 output.contains(format!("{}={}", *k, *v).as_slice()),
1067 "output doesn't contain `{}={}`\n{}",
1071 #[cfg(target_os="android")]
1073 fn test_inherit_env() {
1075 if running_on_valgrind() { return; }
1077 let mut prog = env_cmd().spawn().unwrap();
1078 let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap();
1081 for &(ref k, ref v) in r.iter() {
1082 // don't check android RANDOM variables
1083 if *k != "RANDOM".to_string() {
1084 assert!(output.contains(format!("{}={}",
1087 output.contains(format!("{}=\'{}\'",
1095 fn test_override_env() {
1097 let mut new_env = vec![("RUN_TEST_NEW_ENV", "123")];
1099 // In some build environments (such as chrooted Nix builds), `env` can
1100 // only be found in the explicitly-provided PATH env variable, not in
1101 // default places such as /bin or /usr/bin. So we need to pass through
1102 // PATH to our sub-process.
1103 let path_val: String;
1104 match os::getenv("PATH") {
1108 new_env.push(("PATH", path_val.as_slice()))
1112 let prog = env_cmd().env_set_all(new_env.as_slice()).spawn().unwrap();
1113 let result = prog.wait_with_output().unwrap();
1114 let output = String::from_utf8_lossy(result.output.as_slice()).to_string();
1116 assert!(output.contains("RUN_TEST_NEW_ENV=123"),
1117 "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output);
1121 fn test_add_to_env() {
1122 let prog = env_cmd().env("RUN_TEST_NEW_ENV", "123").spawn().unwrap();
1123 let result = prog.wait_with_output().unwrap();
1124 let output = String::from_utf8_lossy(result.output.as_slice()).to_string();
1126 assert!(output.contains("RUN_TEST_NEW_ENV=123"),
1127 "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output);
1131 pub fn sleeper() -> Process {
1132 Command::new("sleep").arg("1000").spawn().unwrap()
1135 pub fn sleeper() -> Process {
1136 // There's a `timeout` command on windows, but it doesn't like having
1137 // its output piped, so instead just ping ourselves a few times with
1138 // gaps in between so we're sure this process is alive for awhile
1139 Command::new("ping").arg("127.0.0.1").arg("-n").arg("1000").spawn().unwrap()
1144 let mut p = sleeper();
1145 Process::kill(p.id(), PleaseExitSignal).unwrap();
1146 assert!(!p.wait().unwrap().success());
1151 let mut p = sleeper();
1152 assert!(Process::kill(p.id(), 0).is_ok());
1153 p.signal_kill().unwrap();
1154 assert!(!p.wait().unwrap().success());
1159 let mut p = sleeper();
1160 p.signal_kill().unwrap();
1161 for _ in range(0i, 20) {
1162 if p.signal(0).is_err() {
1163 assert!(!p.wait().unwrap().success());
1166 timer::sleep(Duration::milliseconds(100));
1168 panic!("never saw the child go away");
1173 let mut p = sleeper();
1174 p.set_timeout(Some(10));
1175 assert_eq!(p.wait().err().unwrap().kind, TimedOut);
1176 assert_eq!(p.wait().err().unwrap().kind, TimedOut);
1177 p.signal_kill().unwrap();
1178 p.set_timeout(None);
1179 assert!(p.wait().is_ok());
1183 fn wait_timeout2() {
1184 let (tx, rx) = channel();
1185 let tx2 = tx.clone();
1186 let _t = Thread::spawn(move|| {
1187 let mut p = sleeper();
1188 p.set_timeout(Some(10));
1189 assert_eq!(p.wait().err().unwrap().kind, TimedOut);
1190 p.signal_kill().unwrap();
1191 tx.send(()).unwrap();
1193 let _t = Thread::spawn(move|| {
1194 let mut p = sleeper();
1195 p.set_timeout(Some(10));
1196 assert_eq!(p.wait().err().unwrap().kind, TimedOut);
1197 p.signal_kill().unwrap();
1198 tx2.send(()).unwrap();
1209 assert!(Process::kill(id, 0).is_ok());
1210 assert!(Process::kill(id, PleaseExitSignal).is_ok());
1214 fn dont_close_fd_on_command_spawn() {
1217 let path = if cfg!(windows) {
1220 Path::new("/dev/null")
1223 let fdes = match fs::open(&path, Truncate, Write) {
1225 Err(_) => panic!("failed to open file descriptor"),
1228 let mut cmd = pwd_cmd();
1229 let _ = cmd.stdout(InheritFd(fdes.fd()));
1230 assert!(cmd.status().unwrap().success());
1231 assert!(fdes.write("extra write\n".as_bytes()).is_ok());
1236 fn env_map_keys_ci() {
1239 let mut cmd = Command::new("");
1240 cmd.env("path", "foo");
1241 cmd.env("Path", "bar");
1242 let env = &cmd.env.unwrap();
1243 let val = env.get(&EnvKey(CString::from_slice(b"PATH")));
1244 assert!(val.unwrap() == &CString::from_slice(b"bar"));