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(non_upper_case_globals)]
15 pub use self::StdioContainer
::*;
16 pub use self::ProcessExit
::*;
20 use collections
::HashMap
;
23 use old_io
::pipe
::{PipeStream, PipePair}
;
24 use old_io
::{IoResult, IoError}
;
28 use old_path
::BytesContainer
;
29 use sync
::mpsc
::{channel, Receiver}
;
30 use sys
::fs
::FileDesc
;
31 use sys
::process
::Process
as ProcessImp
;
35 #[cfg(windows)] use hash;
36 #[cfg(windows)] use str;
38 /// Signal a process to exit, without forcibly killing it. Corresponds to
39 /// SIGTERM on unix platforms.
40 #[cfg(windows)] pub const PleaseExitSignal: int = 15;
41 /// Signal a process to exit immediately, forcibly killing it. Corresponds to
42 /// SIGKILL on unix platforms.
43 #[cfg(windows)] pub const MustDieSignal: int = 9;
44 /// Signal a process to exit, without forcibly killing it. Corresponds to
45 /// SIGTERM on unix platforms.
46 #[cfg(not(windows))] pub const PleaseExitSignal: int = libc::SIGTERM as int;
47 /// Signal a process to exit immediately, forcibly killing it. Corresponds to
48 /// SIGKILL on unix platforms.
49 #[cfg(not(windows))] pub const MustDieSignal: int = libc::SIGKILL as int;
51 /// Representation of a running or exited child process.
53 /// This structure is used to represent and manage child processes. A child
54 /// process is created via the `Command` struct, which configures the spawning
55 /// process and can itself be constructed using a builder-style interface.
60 /// use std::old_io::Command;
62 /// let mut child = match Command::new("/bin/cat").arg("file.txt").spawn() {
63 /// Ok(child) => child,
64 /// Err(e) => panic!("failed to execute child: {}", e),
67 /// let contents = child.stdout.as_mut().unwrap().read_to_end();
68 /// assert!(child.wait().unwrap().success());
74 /// None until wait() is called.
75 exit_code
: Option
<ProcessExit
>,
77 /// Manually delivered signal
78 exit_signal
: Option
<int
>,
80 /// Deadline after which wait() will return
83 /// Handle to the child's stdin, if the `stdin` field of this process's
84 /// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`.
85 pub stdin
: Option
<PipeStream
>,
87 /// Handle to the child's stdout, if the `stdout` field of this process's
88 /// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`.
89 pub stdout
: Option
<PipeStream
>,
91 /// Handle to the child's stderr, if the `stderr` field of this process's
92 /// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`.
93 pub stderr
: Option
<PipeStream
>,
96 /// A representation of environment variable name
97 /// It compares case-insensitive on Windows and case-sensitive everywhere else.
99 #[derive(Hash, PartialEq, Eq, Clone, Debug)]
100 struct EnvKey(CString
);
104 #[derive(Eq, Clone, Debug)]
105 struct EnvKey(CString
);
107 #[cfg(all(windows, stage0))]
108 impl<H
: hash
::Writer
+ hash
::Hasher
> hash
::Hash
<H
> for EnvKey
{
109 fn hash(&self, state
: &mut H
) {
110 let &EnvKey(ref x
) = self;
111 match str::from_utf8(x
.as_bytes()) {
112 Ok(s
) => for ch
in s
.chars() {
113 (ch
as u8 as char).to_lowercase().hash(state
);
115 Err(..) => x
.hash(state
)
119 #[cfg(all(windows, not(stage0)))]
120 impl hash
::Hash
for EnvKey
{
121 fn hash
<H
: hash
::Hasher
>(&self, state
: &mut H
) {
122 let &EnvKey(ref x
) = self;
123 match str::from_utf8(x
.as_bytes()) {
124 Ok(s
) => for ch
in s
.chars() {
125 (ch
as u8 as char).to_lowercase().hash(state
);
127 Err(..) => x
.hash(state
)
133 impl PartialEq
for EnvKey
{
134 fn eq(&self, other
: &EnvKey
) -> bool
{
135 let &EnvKey(ref x
) = self;
136 let &EnvKey(ref y
) = other
;
137 match (str::from_utf8(x
.as_bytes()), str::from_utf8(y
.as_bytes())) {
138 (Ok(xs
), Ok(ys
)) => {
139 if xs
.len() != ys
.len() {
142 for (xch
, ych
) in xs
.chars().zip(ys
.chars()) {
143 if xch
.to_lowercase() != ych
.to_lowercase() {
150 // If either is not a valid utf8 string, just compare them byte-wise
156 impl BytesContainer
for EnvKey
{
157 fn container_as_bytes
<'a
>(&'a
self) -> &'a
[u8] {
158 let &EnvKey(ref k
) = self;
159 k
.container_as_bytes()
163 /// A HashMap representation of environment variables.
164 pub type EnvMap
= HashMap
<EnvKey
, CString
>;
166 /// The `Command` type acts as a process builder, providing fine-grained control
167 /// over how a new process should be spawned. A default configuration can be
168 /// generated using `Command::new(program)`, where `program` gives a path to the
169 /// program to be executed. Additional builder methods allow the configuration
170 /// to be changed (for example, by adding arguments) prior to spawning:
173 /// use std::old_io::Command;
175 /// let mut process = match Command::new("sh").arg("-c").arg("echo hello").spawn() {
177 /// Err(e) => panic!("failed to execute process: {}", e),
180 /// let output = process.stdout.as_mut().unwrap().read_to_end();
184 // The internal data for the builder. Documented by the builder
185 // methods below, and serialized into rt::rtio::ProcessConfig.
189 cwd
: Option
<CString
>,
190 stdin
: StdioContainer
,
191 stdout
: StdioContainer
,
192 stderr
: StdioContainer
,
198 // FIXME (#12938): Until DST lands, we cannot decompose &str into & and str, so
199 // we cannot usefully take BytesContainer arguments by reference (without forcing an
200 // additional & around &str). So we are instead temporarily adding an instance
201 // for &Path, so that we can take BytesContainer as owned. When DST lands, the &Path
202 // instance should be removed, and arguments bound by BytesContainer should be passed by
203 // reference. (Here: {new, arg, args, env}.)
206 /// Constructs a new `Command` for launching the program at
207 /// path `program`, with the following default configuration:
209 /// * No arguments to the program
210 /// * Inherit the current process's environment
211 /// * Inherit the current process's working directory
212 /// * A readable pipe for stdin (file descriptor 0)
213 /// * A writeable pipe for stdout and stderr (file descriptors 1 and 2)
215 /// Builder methods are provided to change these defaults and
216 /// otherwise configure the process.
217 pub fn new
<T
: BytesContainer
>(program
: T
) -> Command
{
219 program
: CString
::new(program
.container_as_bytes()).unwrap(),
223 stdin
: CreatePipe(true, false),
224 stdout
: CreatePipe(false, true),
225 stderr
: CreatePipe(false, true),
232 /// Add an argument to pass to the program.
233 pub fn arg
<'a
, T
: BytesContainer
>(&'a
mut self, arg
: T
) -> &'a
mut Command
{
234 self.args
.push(CString
::new(arg
.container_as_bytes()).unwrap());
238 /// Add multiple arguments to pass to the program.
239 pub fn args
<'a
, T
: BytesContainer
>(&'a
mut self, args
: &[T
]) -> &'a
mut Command
{
240 self.args
.extend(args
.iter().map(|arg
| {
241 CString
::new(arg
.container_as_bytes()).unwrap()
245 // Get a mutable borrow of the environment variable map for this `Command`.
247 fn get_env_map
<'a
>(&'a
mut self) -> &'a
mut EnvMap
{
249 Some(ref mut map
) => map
,
251 // if the env is currently just inheriting from the parent's,
252 // materialize the parent's env into a hashtable.
253 self.env
= Some(os
::env_as_bytes().into_iter().map(|(k
, v
)| {
254 (EnvKey(CString
::new(k
).unwrap()),
255 CString
::new(v
).unwrap())
257 self.env
.as_mut().unwrap()
262 /// Inserts or updates an environment variable mapping.
264 /// Note that environment variable names are case-insensitive (but case-preserving) on Windows,
265 /// and case-sensitive on all other platforms.
266 pub fn env
<'a
, T
, U
>(&'a
mut self, key
: T
, val
: U
)
268 where T
: BytesContainer
, U
: BytesContainer
{
269 let key
= EnvKey(CString
::new(key
.container_as_bytes()).unwrap());
270 let val
= CString
::new(val
.container_as_bytes()).unwrap();
271 self.get_env_map().insert(key
, val
);
275 /// Removes an environment variable mapping.
276 pub fn env_remove
<'a
, T
>(&'a
mut self, key
: T
) -> &'a
mut Command
277 where T
: BytesContainer
{
278 let key
= EnvKey(CString
::new(key
.container_as_bytes()).unwrap());
279 self.get_env_map().remove(&key
);
283 /// Sets the entire environment map for the child process.
285 /// If the given slice contains multiple instances of an environment
286 /// variable, the *rightmost* instance will determine the value.
287 pub fn env_set_all
<'a
, T
, U
>(&'a
mut self, env
: &[(T
,U
)])
289 where T
: BytesContainer
, U
: BytesContainer
{
290 self.env
= Some(env
.iter().map(|&(ref k
, ref v
)| {
291 (EnvKey(CString
::new(k
.container_as_bytes()).unwrap()),
292 CString
::new(v
.container_as_bytes()).unwrap())
297 /// Set the working directory for the child process.
298 pub fn cwd
<'a
>(&'a
mut self, dir
: &Path
) -> &'a
mut Command
{
299 self.cwd
= Some(CString
::new(dir
.as_vec()).unwrap());
303 /// Configuration for the child process's stdin handle (file descriptor 0).
304 /// Defaults to `CreatePipe(true, false)` so the input can be written to.
305 pub fn stdin
<'a
>(&'a
mut self, cfg
: StdioContainer
) -> &'a
mut Command
{
310 /// Configuration for the child process's stdout handle (file descriptor 1).
311 /// Defaults to `CreatePipe(false, true)` so the output can be collected.
312 pub fn stdout
<'a
>(&'a
mut self, cfg
: StdioContainer
) -> &'a
mut Command
{
317 /// Configuration for the child process's stderr handle (file descriptor 2).
318 /// Defaults to `CreatePipe(false, true)` so the output can be collected.
319 pub fn stderr
<'a
>(&'a
mut self, cfg
: StdioContainer
) -> &'a
mut Command
{
324 /// Sets the child process's user id. This translates to a `setuid` call in
325 /// the child process. Setting this value on windows will cause the spawn to
326 /// fail. Failure in the `setuid` call on unix will also cause the spawn to
328 pub fn uid
<'a
>(&'a
mut self, id
: uint
) -> &'a
mut Command
{
333 /// Similar to `uid`, but sets the group id of the child process. This has
334 /// the same semantics as the `uid` field.
335 pub fn gid
<'a
>(&'a
mut self, id
: uint
) -> &'a
mut Command
{
340 /// Sets the child process to be spawned in a detached state. On unix, this
341 /// means that the child is the leader of a new process group.
342 pub fn detached
<'a
>(&'a
mut self) -> &'a
mut Command
{
347 /// Executes the command as a child process, which is returned.
348 pub fn spawn(&self) -> IoResult
<Process
> {
349 let (their_stdin
, our_stdin
) = try
!(setup_io(self.stdin
));
350 let (their_stdout
, our_stdout
) = try
!(setup_io(self.stdout
));
351 let (their_stderr
, our_stderr
) = try
!(setup_io(self.stderr
));
353 match ProcessImp
::spawn(self, their_stdin
, their_stdout
, their_stderr
) {
355 Ok(handle
) => Ok(Process
{
368 /// Executes the command as a child process, waiting for it to finish and
369 /// collecting all of its output.
374 /// use std::old_io::Command;
376 /// let output = match Command::new("cat").arg("foot.txt").output() {
377 /// Ok(output) => output,
378 /// Err(e) => panic!("failed to execute process: {}", e),
381 /// println!("status: {}", output.status);
382 /// println!("stdout: {}", String::from_utf8_lossy(output.output.as_slice()));
383 /// println!("stderr: {}", String::from_utf8_lossy(output.error.as_slice()));
385 pub fn output(&self) -> IoResult
<ProcessOutput
> {
386 self.spawn().and_then(|p
| p
.wait_with_output())
389 /// Executes a command as a child process, waiting for it to finish and
390 /// collecting its exit status.
395 /// use std::old_io::Command;
397 /// let status = match Command::new("ls").status() {
398 /// Ok(status) => status,
399 /// Err(e) => panic!("failed to execute process: {}", e),
402 /// println!("process exited with: {}", status);
404 pub fn status(&self) -> IoResult
<ProcessExit
> {
405 self.spawn().and_then(|mut p
| p
.wait())
409 #[stable(feature = "rust1", since = "1.0.0")]
410 impl fmt
::Debug
for Command
{
411 /// Format the program and arguments of a Command for display. Any
412 /// non-utf8 data is lossily converted using the utf8 replacement
414 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
415 try
!(write
!(f
, "{:?}", self.program
));
416 for arg
in &self.args
{
417 try
!(write
!(f
, " '{:?}'", arg
));
423 fn setup_io(io
: StdioContainer
) -> IoResult
<(Option
<PipeStream
>, Option
<PipeStream
>)> {
432 theirs
= Some(PipeStream
::from_filedesc(FileDesc
::new(fd
, false)));
435 CreatePipe(readable
, _writable
) => {
436 let PipePair { reader, writer }
= try
!(PipeStream
::pair());
438 theirs
= Some(reader
);
441 theirs
= Some(writer
);
449 // Allow the sys module to get access to the Command state
450 impl sys
::process
::ProcessConfig
<EnvKey
, CString
> for Command
{
451 fn program(&self) -> &CString
{
454 fn args(&self) -> &[CString
] {
457 fn env(&self) -> Option
<&EnvMap
> {
460 fn cwd(&self) -> Option
<&CString
> {
463 fn uid(&self) -> Option
<uint
> {
466 fn gid(&self) -> Option
<uint
> {
469 fn detach(&self) -> bool
{
475 /// The output of a finished process.
476 #[derive(PartialEq, Eq, Clone)]
477 pub struct ProcessOutput
{
478 /// The status (exit code) of the process.
479 pub status
: ProcessExit
,
480 /// The data that the process wrote to stdout.
482 /// The data that the process wrote to stderr.
486 /// Describes what to do with a standard io stream for a child process.
487 #[derive(Clone, Copy)]
488 pub enum StdioContainer
{
489 /// This stream will be ignored. This is the equivalent of attaching the
490 /// stream to `/dev/null`
493 /// The specified file descriptor is inherited for the stream which it is
494 /// specified for. Ownership of the file descriptor is *not* taken, so the
495 /// caller must clean it up.
496 InheritFd(libc
::c_int
),
498 /// Creates a pipe for the specified file descriptor which will be created
499 /// when the process is spawned.
501 /// The first boolean argument is whether the pipe is readable, and the
502 /// second is whether it is writable. These properties are from the view of
503 /// the *child* process, not the parent process.
504 CreatePipe(bool
/* readable */, bool
/* writable */),
507 /// Describes the result of a process after it has terminated.
508 /// Note that Windows have no signals, so the result is usually ExitStatus.
509 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
510 pub enum ProcessExit
{
511 /// Normal termination with an exit status.
514 /// Termination by signal, with the signal number.
518 #[stable(feature = "rust1", since = "1.0.0")]
519 impl fmt
::Display
for ProcessExit
{
520 /// Format a ProcessExit enum, to nicely present the information.
521 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
523 ExitStatus(code
) => write
!(f
, "exit code: {}", code
),
524 ExitSignal(code
) => write
!(f
, "signal: {}", code
),
530 /// Was termination successful? Signal termination not considered a success,
531 /// and success is defined as a zero exit status.
532 pub fn success(&self) -> bool
{
533 return self.matches_exit_status(0);
536 /// Checks whether this ProcessExit matches the given exit status.
537 /// Termination by signal will never match an exit code.
538 pub fn matches_exit_status(&self, wanted
: int
) -> bool
{
539 *self == ExitStatus(wanted
)
544 /// Sends `signal` to another process in the system identified by `id`.
546 /// Note that windows doesn't quite have the same model as unix, so some
547 /// unix signals are mapped to windows signals. Notably, unix termination
548 /// signals (SIGTERM/SIGKILL/SIGINT) are translated to `TerminateProcess`.
550 /// Additionally, a signal number of 0 can check for existence of the target
551 /// process. Note, though, that on some platforms signals will continue to
552 /// be successfully delivered if the child has exited, but not yet been
554 pub fn kill(id
: libc
::pid_t
, signal
: int
) -> IoResult
<()> {
555 unsafe { ProcessImp::killpid(id, signal) }
558 /// Returns the process id of this child process
559 pub fn id(&self) -> libc
::pid_t { self.handle.id() }
561 /// Sends the specified signal to the child process, returning whether the
562 /// signal could be delivered or not.
564 /// Note that signal 0 is interpreted as a poll to check whether the child
565 /// process is still alive or not. If an error is returned, then the child
566 /// process has exited.
568 /// On some unix platforms signals will continue to be received after a
569 /// child has exited but not yet been reaped. In order to report the status
570 /// of signal delivery correctly, unix implementations may invoke
571 /// `waitpid()` with `WNOHANG` in order to reap the child as necessary.
575 /// If the signal delivery fails, the corresponding error is returned.
576 pub fn signal(&mut self, signal
: int
) -> IoResult
<()> {
577 #[cfg(unix)] fn collect_status(p: &mut Process) {
578 // On Linux (and possibly other unices), a process that has exited will
579 // continue to accept signals because it is "defunct". The delivery of
580 // signals will only fail once the child has been reaped. For this
581 // reason, if the process hasn't exited yet, then we attempt to collect
582 // their status with WNOHANG.
583 if p
.exit_code
.is_none() {
584 match p
.handle
.try_wait() {
585 Some(code
) => { p.exit_code = Some(code); }
590 #[cfg(windows)] fn collect_status(_p: &mut Process) {}
592 collect_status(self);
594 // if the process has finished, and therefore had waitpid called,
595 // and we kill it, then on unix we might ending up killing a
596 // newer process that happens to have the same (re-used) id
597 if self.exit_code
.is_some() {
599 kind
: old_io
::InvalidInput
,
600 desc
: "invalid argument: can't kill an exited process",
605 // A successfully delivered signal that isn't 0 (just a poll for being
606 // alive) is recorded for windows (see wait())
607 match unsafe { self.handle.kill(signal) }
{
608 Ok(()) if signal
== 0 => Ok(()),
609 Ok(()) => { self.exit_signal = Some(signal); Ok(()) }
615 /// Sends a signal to this child requesting that it exits. This is
616 /// equivalent to sending a SIGTERM on unix platforms.
617 pub fn signal_exit(&mut self) -> IoResult
<()> {
618 self.signal(PleaseExitSignal
)
621 /// Sends a signal to this child forcing it to exit. This is equivalent to
622 /// sending a SIGKILL on unix platforms.
623 pub fn signal_kill(&mut self) -> IoResult
<()> {
624 self.signal(MustDieSignal
)
627 /// Wait for the child to exit completely, returning the status that it
628 /// exited with. This function will continue to have the same return value
629 /// after it has been called at least once.
631 /// The stdin handle to the child process will be closed before waiting.
635 /// This function can fail if a timeout was previously specified via
636 /// `set_timeout` and the timeout expires before the child exits.
637 pub fn wait(&mut self) -> IoResult
<ProcessExit
> {
638 drop(self.stdin
.take());
639 match self.exit_code
{
640 Some(code
) => Ok(code
),
642 let code
= try
!(self.handle
.wait(self.deadline
));
643 // On windows, waitpid will never return a signal. If a signal
644 // was successfully delivered to the process, however, we can
645 // consider it as having died via a signal.
646 let code
= match self.exit_signal
{
648 Some(signal
) if cfg
!(windows
) => ExitSignal(signal
),
651 self.exit_code
= Some(code
);
657 /// Sets a timeout, in milliseconds, for future calls to wait().
659 /// The argument specified is a relative distance into the future, in
660 /// milliseconds, after which any call to wait() will return immediately
661 /// with a timeout error, and all future calls to wait() will not block.
663 /// A value of `None` will clear any previous timeout, and a value of `Some`
664 /// will override any previously set timeout.
669 /// use std::old_io::{Command, IoResult};
670 /// use std::old_io::process::ProcessExit;
672 /// fn run_gracefully(prog: &str) -> IoResult<ProcessExit> {
673 /// let mut p = try!(Command::new("long-running-process").spawn());
675 /// // give the process 10 seconds to finish completely
676 /// p.set_timeout(Some(10_000));
678 /// Ok(status) => return Ok(status),
682 /// // Attempt to exit gracefully, but don't wait for it too long
683 /// try!(p.signal_exit());
684 /// p.set_timeout(Some(1_000));
686 /// Ok(status) => return Ok(status),
690 /// // Well, we did our best, forcefully kill the process
691 /// try!(p.signal_kill());
692 /// p.set_timeout(None);
696 #[unstable(feature = "io",
697 reason
= "the type of the timeout is likely to change")]
698 pub fn set_timeout(&mut self, timeout_ms
: Option
<u64>) {
699 self.deadline
= timeout_ms
.map(|i
| i
+ sys
::timer
::now()).unwrap_or(0);
702 /// Simultaneously wait for the child to exit and collect all remaining
703 /// output on the stdout/stderr handles, returning a `ProcessOutput`
706 /// The stdin handle to the child is closed before waiting.
710 /// This function can fail for any of the same reasons that `wait()` can
712 pub fn wait_with_output(mut self) -> IoResult
<ProcessOutput
> {
713 drop(self.stdin
.take());
714 fn read(stream
: Option
<old_io
::PipeStream
>) -> Receiver
<IoResult
<Vec
<u8>>> {
715 let (tx
, rx
) = channel();
718 thread
::spawn(move || {
719 let mut stream
= stream
;
720 tx
.send(stream
.read_to_end()).unwrap();
723 None
=> tx
.send(Ok(Vec
::new())).unwrap()
727 let stdout
= read(self.stdout
.take());
728 let stderr
= read(self.stderr
.take());
730 let status
= try
!(self.wait());
734 output
: stdout
.recv().unwrap().unwrap_or(Vec
::new()),
735 error
: stderr
.recv().unwrap().unwrap_or(Vec
::new()),
739 /// Forgets this process, allowing it to outlive the parent
741 /// This function will forcefully prevent calling `wait()` on the child
742 /// process in the destructor, allowing the child to outlive the
743 /// parent. Note that this operation can easily lead to leaking the
744 /// resources of the child process, so care must be taken when
745 /// invoking this method.
746 pub fn forget(mut self) {
751 impl Drop
for Process
{
753 if self.forget { return }
755 // Close all I/O before exiting to ensure that the child doesn't wait
756 // forever to print some text or something similar.
757 drop(self.stdin
.take());
758 drop(self.stdout
.take());
759 drop(self.stderr
.take());
761 self.set_timeout(None
);
762 let _
= self.wait().unwrap();
768 use old_io
::{Truncate, Write, TimedOut, timer, process, FileNotFound}
;
769 use prelude
::v1
::{Ok, Err, range, drop, Some, None, Vec}
;
770 use prelude
::v1
::{Path, String, Reader, Writer, Clone}
;
771 use prelude
::v1
::{SliceExt, Str, StrExt, AsSlice, ToString, GenericPath}
;
772 use old_io
::fs
::PathExtensions
;
773 use old_io
::timer
::*;
774 use rt
::running_on_valgrind
;
776 use super::{CreatePipe}
;
777 use super::{InheritFd, Process, PleaseExitSignal, Command, ProcessOutput}
;
778 use sync
::mpsc
::channel
;
782 // FIXME(#10380) these tests should not all be ignored on android.
784 #[cfg(not(target_os="android"))]
787 let p
= Command
::new("true").spawn();
789 let mut p
= p
.unwrap();
790 assert
!(p
.wait().unwrap().success());
793 #[cfg(not(target_os="android"))]
796 match Command
::new("if-this-is-a-binary-then-the-world-has-ended").spawn() {
802 #[cfg(not(target_os="android"))]
804 fn exit_reported_right() {
805 let p
= Command
::new("false").spawn();
807 let mut p
= p
.unwrap();
808 assert
!(p
.wait().unwrap().matches_exit_status(1));
809 drop(p
.wait().clone());
812 #[cfg(all(unix, not(target_os="android")))]
814 fn signal_reported_right() {
815 let p
= Command
::new("/bin/sh").arg("-c").arg("kill -9 $$").spawn();
817 let mut p
= p
.unwrap();
818 match p
.wait().unwrap() {
819 process
::ExitSignal(9) => {}
,
820 result
=> panic
!("not terminated by signal 9 (instead, {})", result
),
824 pub fn read_all(input
: &mut Reader
) -> String
{
825 input
.read_to_string().unwrap()
828 pub fn run_output(cmd
: Command
) -> String
{
831 let mut p
= p
.unwrap();
832 assert
!(p
.stdout
.is_some());
833 let ret
= read_all(p
.stdout
.as_mut().unwrap() as &mut Reader
);
834 assert
!(p
.wait().unwrap().success());
838 #[cfg(not(target_os="android"))]
841 let mut cmd
= Command
::new("echo");
842 cmd
.arg("foobar").stdout(CreatePipe(false, true));
843 assert_eq
!(run_output(cmd
), "foobar\n");
846 #[cfg(all(unix, not(target_os="android")))]
849 let mut cmd
= Command
::new("/bin/sh");
850 cmd
.arg("-c").arg("pwd")
851 .cwd(&Path
::new("/"))
852 .stdout(CreatePipe(false, true));
853 assert_eq
!(run_output(cmd
), "/\n");
856 #[cfg(all(unix, not(target_os="android")))]
859 let mut p
= Command
::new("/bin/sh")
860 .arg("-c").arg("read line; echo $line")
861 .stdin(CreatePipe(true, false))
862 .stdout(CreatePipe(false, true))
864 p
.stdin
.as_mut().unwrap().write("foobar".as_bytes()).unwrap();
865 drop(p
.stdin
.take());
866 let out
= read_all(p
.stdout
.as_mut().unwrap() as &mut Reader
);
867 assert
!(p
.wait().unwrap().success());
868 assert_eq
!(out
, "foobar\n");
871 #[cfg(not(target_os="android"))]
874 let mut p
= Command
::new("true").detached().spawn().unwrap();
875 assert
!(p
.wait().unwrap().success());
880 fn uid_fails_on_windows() {
881 assert
!(Command
::new("test").uid(10).spawn().is_err());
884 #[cfg(all(unix, not(target_os="android")))]
888 let mut p
= Command
::new("/bin/sh")
889 .arg("-c").arg("true")
890 .uid(unsafe { libc::getuid() as uint }
)
891 .gid(unsafe { libc::getgid() as uint }
)
893 assert
!(p
.wait().unwrap().success());
896 #[cfg(all(unix, not(target_os="android")))]
898 fn uid_to_root_fails() {
901 // if we're already root, this isn't a valid test. Most of the bots run
902 // as non-root though (android is an exception).
903 if unsafe { libc::getuid() == 0 } { return }
904 assert
!(Command
::new("/bin/ls").uid(0).gid(0).spawn().is_err());
907 #[cfg(not(target_os="android"))]
909 fn test_process_status() {
910 let mut status
= Command
::new("false").status().unwrap();
911 assert
!(status
.matches_exit_status(1));
913 status
= Command
::new("true").status().unwrap();
914 assert
!(status
.success());
918 fn test_process_output_fail_to_start() {
919 match Command
::new("/no-binary-by-this-name-should-exist").output() {
920 Err(e
) => assert_eq
!(e
.kind
, FileNotFound
),
925 #[cfg(not(target_os="android"))]
927 fn test_process_output_output() {
928 let ProcessOutput {status, output, error}
929 = Command
::new("echo").arg("hello").output().unwrap();
930 let output_str
= str::from_utf8(&output
).unwrap();
932 assert
!(status
.success());
933 assert_eq
!(output_str
.trim().to_string(), "hello");
935 if !running_on_valgrind() {
936 assert_eq
!(error
, Vec
::new());
940 #[cfg(not(target_os="android"))]
942 fn test_process_output_error() {
943 let ProcessOutput {status, output, error}
944 = Command
::new("mkdir").arg(".").output().unwrap();
946 assert
!(status
.matches_exit_status(1));
947 assert_eq
!(output
, Vec
::new());
948 assert
!(!error
.is_empty());
951 #[cfg(not(target_os="android"))]
953 fn test_finish_once() {
954 let mut prog
= Command
::new("false").spawn().unwrap();
955 assert
!(prog
.wait().unwrap().matches_exit_status(1));
958 #[cfg(not(target_os="android"))]
960 fn test_finish_twice() {
961 let mut prog
= Command
::new("false").spawn().unwrap();
962 assert
!(prog
.wait().unwrap().matches_exit_status(1));
963 assert
!(prog
.wait().unwrap().matches_exit_status(1));
966 #[cfg(not(target_os="android"))]
968 fn test_wait_with_output_once() {
969 let prog
= Command
::new("echo").arg("hello").spawn().unwrap();
970 let ProcessOutput {status, output, error}
= prog
.wait_with_output().unwrap();
971 let output_str
= str::from_utf8(&output
).unwrap();
973 assert
!(status
.success());
974 assert_eq
!(output_str
.trim().to_string(), "hello");
976 if !running_on_valgrind() {
977 assert_eq
!(error
, Vec
::new());
981 #[cfg(all(unix, not(target_os="android")))]
982 pub fn pwd_cmd() -> Command
{
985 #[cfg(target_os="android")]
986 pub fn pwd_cmd() -> Command
{
987 let mut cmd
= Command
::new("/system/bin/sh");
988 cmd
.arg("-c").arg("pwd");
993 pub fn pwd_cmd() -> Command
{
994 let mut cmd
= Command
::new("cmd");
995 cmd
.arg("/c").arg("cd");
1000 fn test_keep_current_working_dir() {
1002 let prog
= pwd_cmd().spawn().unwrap();
1004 let output
= String
::from_utf8(prog
.wait_with_output().unwrap().output
).unwrap();
1005 let parent_dir
= os
::getcwd().unwrap();
1006 let child_dir
= Path
::new(output
.trim());
1008 let parent_stat
= parent_dir
.stat().unwrap();
1009 let child_stat
= child_dir
.stat().unwrap();
1011 assert_eq
!(parent_stat
.unstable
.device
, child_stat
.unstable
.device
);
1012 assert_eq
!(parent_stat
.unstable
.inode
, child_stat
.unstable
.inode
);
1016 fn test_change_working_directory() {
1018 // test changing to the parent of os::getcwd() because we know
1019 // the path exists (and os::getcwd() is not expected to be root)
1020 let parent_dir
= os
::getcwd().unwrap().dir_path();
1021 let prog
= pwd_cmd().cwd(&parent_dir
).spawn().unwrap();
1023 let output
= String
::from_utf8(prog
.wait_with_output().unwrap().output
).unwrap();
1024 let child_dir
= Path
::new(output
.trim());
1026 let parent_stat
= parent_dir
.stat().unwrap();
1027 let child_stat
= child_dir
.stat().unwrap();
1029 assert_eq
!(parent_stat
.unstable
.device
, child_stat
.unstable
.device
);
1030 assert_eq
!(parent_stat
.unstable
.inode
, child_stat
.unstable
.inode
);
1033 #[cfg(all(unix, not(target_os="android")))]
1034 pub fn env_cmd() -> Command
{
1037 #[cfg(target_os="android")]
1038 pub fn env_cmd() -> Command
{
1039 let mut cmd
= Command
::new("/system/bin/sh");
1040 cmd
.arg("-c").arg("set");
1045 pub fn env_cmd() -> Command
{
1046 let mut cmd
= Command
::new("cmd");
1047 cmd
.arg("/c").arg("set");
1051 #[cfg(not(target_os="android"))]
1053 fn test_inherit_env() {
1055 if running_on_valgrind() { return; }
1057 let prog
= env_cmd().spawn().unwrap();
1058 let output
= String
::from_utf8(prog
.wait_with_output().unwrap().output
).unwrap();
1061 for &(ref k
, ref v
) in &r
{
1062 // don't check windows magical empty-named variables
1063 assert
!(k
.is_empty() ||
1064 output
.contains(&format
!("{}={}", *k
, *v
)),
1065 "output doesn't contain `{}={}`\n{}",
1069 #[cfg(target_os="android")]
1071 fn test_inherit_env() {
1073 if running_on_valgrind() { return; }
1075 let mut prog
= env_cmd().spawn().unwrap();
1076 let output
= String
::from_utf8(prog
.wait_with_output().unwrap().output
).unwrap();
1079 for &(ref k
, ref v
) in &r
{
1080 // don't check android RANDOM variables
1081 if *k
!= "RANDOM".to_string() {
1082 assert
!(output
.contains(&format
!("{}={}",
1085 output
.contains(&format
!("{}=\'{}\'",
1093 fn test_override_env() {
1096 // In some build environments (such as chrooted Nix builds), `env` can
1097 // only be found in the explicitly-provided PATH env variable, not in
1098 // default places such as /bin or /usr/bin. So we need to pass through
1099 // PATH to our sub-process.
1100 let path_val
: String
;
1101 let mut new_env
= vec
![("RUN_TEST_NEW_ENV", "123")];
1102 match os
::getenv("PATH") {
1106 new_env
.push(("PATH", &path_val
))
1110 let prog
= env_cmd().env_set_all(&new_env
).spawn().unwrap();
1111 let result
= prog
.wait_with_output().unwrap();
1112 let output
= String
::from_utf8_lossy(&result
.output
).to_string();
1114 assert
!(output
.contains("RUN_TEST_NEW_ENV=123"),
1115 "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output
);
1119 fn test_add_to_env() {
1120 let prog
= env_cmd().env("RUN_TEST_NEW_ENV", "123").spawn().unwrap();
1121 let result
= prog
.wait_with_output().unwrap();
1122 let output
= String
::from_utf8_lossy(&result
.output
).to_string();
1124 assert
!(output
.contains("RUN_TEST_NEW_ENV=123"),
1125 "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output
);
1129 pub fn sleeper() -> Process
{
1130 Command
::new("sleep").arg("1000").spawn().unwrap()
1133 pub fn sleeper() -> Process
{
1134 // There's a `timeout` command on windows, but it doesn't like having
1135 // its output piped, so instead just ping ourselves a few times with
1136 // gaps in between so we're sure this process is alive for awhile
1137 Command
::new("ping").arg("127.0.0.1").arg("-n").arg("1000").spawn().unwrap()
1142 let mut p
= sleeper();
1143 Process
::kill(p
.id(), PleaseExitSignal
).unwrap();
1144 assert
!(!p
.wait().unwrap().success());
1149 let mut p
= sleeper();
1150 assert
!(Process
::kill(p
.id(), 0).is_ok());
1151 p
.signal_kill().unwrap();
1152 assert
!(!p
.wait().unwrap().success());
1157 let mut p
= sleeper();
1158 p
.signal_kill().unwrap();
1160 if p
.signal(0).is_err() {
1161 assert
!(!p
.wait().unwrap().success());
1164 timer
::sleep(Duration
::milliseconds(100));
1166 panic
!("never saw the child go away");
1171 let mut p
= sleeper();
1172 p
.set_timeout(Some(10));
1173 assert_eq
!(p
.wait().err().unwrap().kind
, TimedOut
);
1174 assert_eq
!(p
.wait().err().unwrap().kind
, TimedOut
);
1175 p
.signal_kill().unwrap();
1176 p
.set_timeout(None
);
1177 assert
!(p
.wait().is_ok());
1181 fn wait_timeout2() {
1182 let (tx
, rx
) = channel();
1183 let tx2
= tx
.clone();
1184 let _t
= thread
::spawn(move|| {
1185 let mut p
= sleeper();
1186 p
.set_timeout(Some(10));
1187 assert_eq
!(p
.wait().err().unwrap().kind
, TimedOut
);
1188 p
.signal_kill().unwrap();
1189 tx
.send(()).unwrap();
1191 let _t
= thread
::spawn(move|| {
1192 let mut p
= sleeper();
1193 p
.set_timeout(Some(10));
1194 assert_eq
!(p
.wait().err().unwrap().kind
, TimedOut
);
1195 p
.signal_kill().unwrap();
1196 tx2
.send(()).unwrap();
1207 assert
!(Process
::kill(id
, 0).is_ok());
1208 assert
!(Process
::kill(id
, PleaseExitSignal
).is_ok());
1212 fn dont_close_fd_on_command_spawn() {
1215 let path
= if cfg
!(windows
) {
1218 Path
::new("/dev/null")
1221 let fdes
= match fs
::open(&path
, Truncate
, Write
) {
1223 Err(_
) => panic
!("failed to open file descriptor"),
1226 let mut cmd
= pwd_cmd();
1227 let _
= cmd
.stdout(InheritFd(fdes
.fd()));
1228 assert
!(cmd
.status().unwrap().success());
1229 assert
!(fdes
.write("extra write\n".as_bytes()).is_ok());
1234 fn env_map_keys_ci() {
1237 let mut cmd
= Command
::new("");
1238 cmd
.env("path", "foo");
1239 cmd
.env("Path", "bar");
1240 let env
= &cmd
.env
.unwrap();
1241 let val
= env
.get(&EnvKey(CString
::new(b
"PATH").unwrap()));
1242 assert
!(val
.unwrap() == &CString
::new(b
"bar").unwrap());