]> git.proxmox.com Git - rustc.git/blob - src/libstd/process.rs
61398e16ba03613e4063433b155e1fb97d41a081
[rustc.git] / src / libstd / process.rs
1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! Working with processes.
12
13 #![stable(feature = "process", since = "1.0.0")]
14 #![allow(non_upper_case_globals)]
15
16 use prelude::v1::*;
17 use io::prelude::*;
18
19 use ffi::OsStr;
20 use fmt;
21 use io::{self, Error, ErrorKind};
22 use path;
23 use sync::mpsc::{channel, Receiver};
24 use sys::pipe::{self, AnonPipe};
25 use sys::process::Command as CommandImp;
26 use sys::process::Process as ProcessImp;
27 use sys::process::ExitStatus as ExitStatusImp;
28 use sys::process::Stdio as StdioImp2;
29 use sys_common::{AsInner, AsInnerMut};
30 use thread;
31
32 /// Representation of a running or exited child process.
33 ///
34 /// This structure is used to represent and manage child processes. A child
35 /// process is created via the `Command` struct, which configures the spawning
36 /// process and can itself be constructed using a builder-style interface.
37 ///
38 /// # Examples
39 ///
40 /// ```should_panic
41 /// use std::process::Command;
42 ///
43 /// let mut child = Command::new("/bin/cat")
44 /// .arg("file.txt")
45 /// .spawn()
46 /// .unwrap_or_else(|e| { panic!("failed to execute child: {}", e) });
47 ///
48 /// let ecode = child.wait()
49 /// .unwrap_or_else(|e| { panic!("failed to wait on child: {}", e) });
50 ///
51 /// assert!(ecode.success());
52 /// ```
53 #[stable(feature = "process", since = "1.0.0")]
54 pub struct Child {
55 handle: ProcessImp,
56
57 /// None until wait() or wait_with_output() is called.
58 status: Option<ExitStatusImp>,
59
60 /// The handle for writing to the child's stdin, if it has been captured
61 #[stable(feature = "process", since = "1.0.0")]
62 pub stdin: Option<ChildStdin>,
63
64 /// The handle for reading from the child's stdout, if it has been captured
65 #[stable(feature = "process", since = "1.0.0")]
66 pub stdout: Option<ChildStdout>,
67
68 /// The handle for reading from the child's stderr, if it has been captured
69 #[stable(feature = "process", since = "1.0.0")]
70 pub stderr: Option<ChildStderr>,
71 }
72
73 /// A handle to a child procesess's stdin
74 #[stable(feature = "process", since = "1.0.0")]
75 pub struct ChildStdin {
76 inner: AnonPipe
77 }
78
79 #[stable(feature = "process", since = "1.0.0")]
80 impl Write for ChildStdin {
81 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
82 self.inner.write(buf)
83 }
84
85 fn flush(&mut self) -> io::Result<()> {
86 Ok(())
87 }
88 }
89
90 /// A handle to a child procesess's stdout
91 #[stable(feature = "process", since = "1.0.0")]
92 pub struct ChildStdout {
93 inner: AnonPipe
94 }
95
96 #[stable(feature = "process", since = "1.0.0")]
97 impl Read for ChildStdout {
98 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
99 self.inner.read(buf)
100 }
101 }
102
103 /// A handle to a child procesess's stderr
104 #[stable(feature = "process", since = "1.0.0")]
105 pub struct ChildStderr {
106 inner: AnonPipe
107 }
108
109 #[stable(feature = "process", since = "1.0.0")]
110 impl Read for ChildStderr {
111 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
112 self.inner.read(buf)
113 }
114 }
115
116 /// The `Command` type acts as a process builder, providing fine-grained control
117 /// over how a new process should be spawned. A default configuration can be
118 /// generated using `Command::new(program)`, where `program` gives a path to the
119 /// program to be executed. Additional builder methods allow the configuration
120 /// to be changed (for example, by adding arguments) prior to spawning:
121 ///
122 /// ```
123 /// use std::process::Command;
124 ///
125 /// let output = Command::new("sh")
126 /// .arg("-c")
127 /// .arg("echo hello")
128 /// .output()
129 /// .unwrap_or_else(|e| { panic!("failed to execute process: {}", e) });
130 /// let hello = output.stdout;
131 /// ```
132 #[stable(feature = "process", since = "1.0.0")]
133 pub struct Command {
134 inner: CommandImp,
135
136 // Details explained in the builder methods
137 stdin: Option<StdioImp>,
138 stdout: Option<StdioImp>,
139 stderr: Option<StdioImp>,
140 }
141
142 impl Command {
143 /// Constructs a new `Command` for launching the program at
144 /// path `program`, with the following default configuration:
145 ///
146 /// * No arguments to the program
147 /// * Inherit the current process's environment
148 /// * Inherit the current process's working directory
149 /// * Inherit stdin/stdout/stderr for `spawn` or `status`, but create pipes for `output`
150 ///
151 /// Builder methods are provided to change these defaults and
152 /// otherwise configure the process.
153 #[stable(feature = "process", since = "1.0.0")]
154 pub fn new<S: AsRef<OsStr>>(program: S) -> Command {
155 Command {
156 inner: CommandImp::new(program.as_ref()),
157 stdin: None,
158 stdout: None,
159 stderr: None,
160 }
161 }
162
163 /// Add an argument to pass to the program.
164 #[stable(feature = "process", since = "1.0.0")]
165 pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Command {
166 self.inner.arg(arg.as_ref());
167 self
168 }
169
170 /// Add multiple arguments to pass to the program.
171 #[stable(feature = "process", since = "1.0.0")]
172 pub fn args<S: AsRef<OsStr>>(&mut self, args: &[S]) -> &mut Command {
173 self.inner.args(args.iter().map(AsRef::as_ref));
174 self
175 }
176
177 /// Inserts or updates an environment variable mapping.
178 ///
179 /// Note that environment variable names are case-insensitive (but case-preserving) on Windows,
180 /// and case-sensitive on all other platforms.
181 #[stable(feature = "process", since = "1.0.0")]
182 pub fn env<K, V>(&mut self, key: K, val: V) -> &mut Command
183 where K: AsRef<OsStr>, V: AsRef<OsStr>
184 {
185 self.inner.env(key.as_ref(), val.as_ref());
186 self
187 }
188
189 /// Removes an environment variable mapping.
190 #[stable(feature = "process", since = "1.0.0")]
191 pub fn env_remove<K: AsRef<OsStr>>(&mut self, key: K) -> &mut Command {
192 self.inner.env_remove(key.as_ref());
193 self
194 }
195
196 /// Clears the entire environment map for the child process.
197 #[stable(feature = "process", since = "1.0.0")]
198 pub fn env_clear(&mut self) -> &mut Command {
199 self.inner.env_clear();
200 self
201 }
202
203 /// Sets the working directory for the child process.
204 #[stable(feature = "process", since = "1.0.0")]
205 pub fn current_dir<P: AsRef<path::Path>>(&mut self, dir: P) -> &mut Command {
206 self.inner.cwd(dir.as_ref().as_ref());
207 self
208 }
209
210 /// Configuration for the child process's stdin handle (file descriptor 0).
211 #[stable(feature = "process", since = "1.0.0")]
212 pub fn stdin(&mut self, cfg: Stdio) -> &mut Command {
213 self.stdin = Some(cfg.0);
214 self
215 }
216
217 /// Configuration for the child process's stdout handle (file descriptor 1).
218 #[stable(feature = "process", since = "1.0.0")]
219 pub fn stdout(&mut self, cfg: Stdio) -> &mut Command {
220 self.stdout = Some(cfg.0);
221 self
222 }
223
224 /// Configuration for the child process's stderr handle (file descriptor 2).
225 #[stable(feature = "process", since = "1.0.0")]
226 pub fn stderr(&mut self, cfg: Stdio) -> &mut Command {
227 self.stderr = Some(cfg.0);
228 self
229 }
230
231 fn spawn_inner(&self, default_io: StdioImp) -> io::Result<Child> {
232 let (their_stdin, our_stdin) = try!(
233 setup_io(self.stdin.as_ref().unwrap_or(&default_io), true)
234 );
235 let (their_stdout, our_stdout) = try!(
236 setup_io(self.stdout.as_ref().unwrap_or(&default_io), false)
237 );
238 let (their_stderr, our_stderr) = try!(
239 setup_io(self.stderr.as_ref().unwrap_or(&default_io), false)
240 );
241
242 match ProcessImp::spawn(&self.inner, their_stdin, their_stdout, their_stderr) {
243 Err(e) => Err(e),
244 Ok(handle) => Ok(Child {
245 handle: handle,
246 status: None,
247 stdin: our_stdin.map(|fd| ChildStdin { inner: fd }),
248 stdout: our_stdout.map(|fd| ChildStdout { inner: fd }),
249 stderr: our_stderr.map(|fd| ChildStderr { inner: fd }),
250 })
251 }
252 }
253
254 /// Executes the command as a child process, returning a handle to it.
255 ///
256 /// By default, stdin, stdout and stderr are inherited by the parent.
257 #[stable(feature = "process", since = "1.0.0")]
258 pub fn spawn(&mut self) -> io::Result<Child> {
259 self.spawn_inner(StdioImp::Inherit)
260 }
261
262 /// Executes the command as a child process, waiting for it to finish and
263 /// collecting all of its output.
264 ///
265 /// By default, stdin, stdout and stderr are captured (and used to
266 /// provide the resulting output).
267 ///
268 /// # Examples
269 ///
270 /// ```
271 /// use std::process::Command;
272 /// let output = Command::new("cat").arg("foo.txt").output().unwrap_or_else(|e| {
273 /// panic!("failed to execute process: {}", e)
274 /// });
275 ///
276 /// println!("status: {}", output.status);
277 /// println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
278 /// println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
279 /// ```
280 #[stable(feature = "process", since = "1.0.0")]
281 pub fn output(&mut self) -> io::Result<Output> {
282 self.spawn_inner(StdioImp::Piped).and_then(|p| p.wait_with_output())
283 }
284
285 /// Executes a command as a child process, waiting for it to finish and
286 /// collecting its exit status.
287 ///
288 /// By default, stdin, stdout and stderr are inherited by the parent.
289 ///
290 /// # Examples
291 ///
292 /// ```
293 /// use std::process::Command;
294 ///
295 /// let status = Command::new("ls").status().unwrap_or_else(|e| {
296 /// panic!("failed to execute process: {}", e)
297 /// });
298 ///
299 /// println!("process exited with: {}", status);
300 /// ```
301 #[stable(feature = "process", since = "1.0.0")]
302 pub fn status(&mut self) -> io::Result<ExitStatus> {
303 self.spawn().and_then(|mut p| p.wait())
304 }
305 }
306
307 #[stable(feature = "rust1", since = "1.0.0")]
308 impl fmt::Debug for Command {
309 /// Format the program and arguments of a Command for display. Any
310 /// non-utf8 data is lossily converted using the utf8 replacement
311 /// character.
312 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
313 try!(write!(f, "{:?}", self.inner.program));
314 for arg in &self.inner.args {
315 try!(write!(f, " {:?}", arg));
316 }
317 Ok(())
318 }
319 }
320
321 impl AsInner<CommandImp> for Command {
322 fn as_inner(&self) -> &CommandImp { &self.inner }
323 }
324
325 impl AsInnerMut<CommandImp> for Command {
326 fn as_inner_mut(&mut self) -> &mut CommandImp { &mut self.inner }
327 }
328
329 fn setup_io(io: &StdioImp, readable: bool)
330 -> io::Result<(StdioImp2, Option<AnonPipe>)>
331 {
332 use self::StdioImp::*;
333 Ok(match *io {
334 Null => (StdioImp2::None, None),
335 Inherit => (StdioImp2::Inherit, None),
336 Piped => {
337 let (reader, writer) = try!(pipe::anon_pipe());
338 if readable {
339 (StdioImp2::Piped(reader), Some(writer))
340 } else {
341 (StdioImp2::Piped(writer), Some(reader))
342 }
343 }
344 })
345 }
346
347 /// The output of a finished process.
348 #[derive(PartialEq, Eq, Clone)]
349 #[stable(feature = "process", since = "1.0.0")]
350 pub struct Output {
351 /// The status (exit code) of the process.
352 #[stable(feature = "process", since = "1.0.0")]
353 pub status: ExitStatus,
354 /// The data that the process wrote to stdout.
355 #[stable(feature = "process", since = "1.0.0")]
356 pub stdout: Vec<u8>,
357 /// The data that the process wrote to stderr.
358 #[stable(feature = "process", since = "1.0.0")]
359 pub stderr: Vec<u8>,
360 }
361
362 /// Describes what to do with a standard I/O stream for a child process.
363 #[stable(feature = "process", since = "1.0.0")]
364 pub struct Stdio(StdioImp);
365
366 // The internal enum for stdio setup; see below for descriptions.
367 #[derive(Clone)]
368 enum StdioImp {
369 Piped,
370 Inherit,
371 Null,
372 }
373
374 impl Stdio {
375 /// A new pipe should be arranged to connect the parent and child processes.
376 #[stable(feature = "process", since = "1.0.0")]
377 pub fn piped() -> Stdio { Stdio(StdioImp::Piped) }
378
379 /// The child inherits from the corresponding parent descriptor.
380 #[stable(feature = "process", since = "1.0.0")]
381 pub fn inherit() -> Stdio { Stdio(StdioImp::Inherit) }
382
383 /// This stream will be ignored. This is the equivalent of attaching the
384 /// stream to `/dev/null`
385 #[stable(feature = "process", since = "1.0.0")]
386 pub fn null() -> Stdio { Stdio(StdioImp::Null) }
387 }
388
389 /// Describes the result of a process after it has terminated.
390 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
391 #[stable(feature = "process", since = "1.0.0")]
392 pub struct ExitStatus(ExitStatusImp);
393
394 impl ExitStatus {
395 /// Was termination successful? Signal termination not considered a success,
396 /// and success is defined as a zero exit status.
397 #[stable(feature = "process", since = "1.0.0")]
398 pub fn success(&self) -> bool {
399 self.0.success()
400 }
401
402 /// Returns the exit code of the process, if any.
403 ///
404 /// On Unix, this will return `None` if the process was terminated
405 /// by a signal; `std::os::unix` provides an extension trait for
406 /// extracting the signal and other details from the `ExitStatus`.
407 #[stable(feature = "process", since = "1.0.0")]
408 pub fn code(&self) -> Option<i32> {
409 self.0.code()
410 }
411 }
412
413 impl AsInner<ExitStatusImp> for ExitStatus {
414 fn as_inner(&self) -> &ExitStatusImp { &self.0 }
415 }
416
417 #[stable(feature = "process", since = "1.0.0")]
418 impl fmt::Display for ExitStatus {
419 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
420 self.0.fmt(f)
421 }
422 }
423
424 impl Child {
425 /// Forces the child to exit. This is equivalent to sending a
426 /// SIGKILL on unix platforms.
427 #[stable(feature = "process", since = "1.0.0")]
428 pub fn kill(&mut self) -> io::Result<()> {
429 #[cfg(unix)] fn collect_status(p: &mut Child) {
430 // On Linux (and possibly other unices), a process that has exited will
431 // continue to accept signals because it is "defunct". The delivery of
432 // signals will only fail once the child has been reaped. For this
433 // reason, if the process hasn't exited yet, then we attempt to collect
434 // their status with WNOHANG.
435 if p.status.is_none() {
436 match p.handle.try_wait() {
437 Some(status) => { p.status = Some(status); }
438 None => {}
439 }
440 }
441 }
442 #[cfg(windows)] fn collect_status(_p: &mut Child) {}
443
444 collect_status(self);
445
446 // if the process has finished, and therefore had waitpid called,
447 // and we kill it, then on unix we might ending up killing a
448 // newer process that happens to have the same (re-used) id
449 if self.status.is_some() {
450 return Err(Error::new(
451 ErrorKind::InvalidInput,
452 "invalid argument: can't kill an exited process",
453 ))
454 }
455
456 unsafe { self.handle.kill() }
457 }
458
459 /// Waits for the child to exit completely, returning the status that it
460 /// exited with. This function will continue to have the same return value
461 /// after it has been called at least once.
462 ///
463 /// The stdin handle to the child process, if any, will be closed
464 /// before waiting. This helps avoid deadlock: it ensures that the
465 /// child does not block waiting for input from the parent, while
466 /// the parent waits for the child to exit.
467 #[stable(feature = "process", since = "1.0.0")]
468 pub fn wait(&mut self) -> io::Result<ExitStatus> {
469 drop(self.stdin.take());
470 match self.status {
471 Some(code) => Ok(ExitStatus(code)),
472 None => {
473 let status = try!(self.handle.wait());
474 self.status = Some(status);
475 Ok(ExitStatus(status))
476 }
477 }
478 }
479
480 /// Simultaneously waits for the child to exit and collect all remaining
481 /// output on the stdout/stderr handles, returning a `Output`
482 /// instance.
483 ///
484 /// The stdin handle to the child process, if any, will be closed
485 /// before waiting. This helps avoid deadlock: it ensures that the
486 /// child does not block waiting for input from the parent, while
487 /// the parent waits for the child to exit.
488 #[stable(feature = "process", since = "1.0.0")]
489 pub fn wait_with_output(mut self) -> io::Result<Output> {
490 drop(self.stdin.take());
491 fn read<T: Read + Send + 'static>(stream: Option<T>) -> Receiver<io::Result<Vec<u8>>> {
492 let (tx, rx) = channel();
493 match stream {
494 Some(stream) => {
495 thread::spawn(move || {
496 let mut stream = stream;
497 let mut ret = Vec::new();
498 let res = stream.read_to_end(&mut ret);
499 tx.send(res.map(|_| ret)).unwrap();
500 });
501 }
502 None => tx.send(Ok(Vec::new())).unwrap()
503 }
504 rx
505 }
506 let stdout = read(self.stdout.take());
507 let stderr = read(self.stderr.take());
508 let status = try!(self.wait());
509
510 Ok(Output {
511 status: status,
512 stdout: stdout.recv().unwrap().unwrap_or(Vec::new()),
513 stderr: stderr.recv().unwrap().unwrap_or(Vec::new()),
514 })
515 }
516 }
517
518 /// Terminates the current process with the specified exit code.
519 ///
520 /// This function will never return and will immediately terminate the current
521 /// process. The exit code is passed through to the underlying OS and will be
522 /// available for consumption by another process.
523 ///
524 /// Note that because this function never returns, and that it terminates the
525 /// process, no destructors on the current stack or any other thread's stack
526 /// will be run. If a clean shutdown is needed it is recommended to only call
527 /// this function at a known point where there are no more destructors left
528 /// to run.
529 #[stable(feature = "rust1", since = "1.0.0")]
530 pub fn exit(code: i32) -> ! {
531 ::sys::os::exit(code)
532 }
533
534 #[cfg(test)]
535 mod tests {
536 use prelude::v1::*;
537 use io::prelude::*;
538
539 use io::ErrorKind;
540 use rt::running_on_valgrind;
541 use str;
542 use super::{Command, Output, Stdio};
543
544 // FIXME(#10380) these tests should not all be ignored on android.
545
546 #[cfg(not(target_os="android"))]
547 #[test]
548 fn smoke() {
549 let p = Command::new("true").spawn();
550 assert!(p.is_ok());
551 let mut p = p.unwrap();
552 assert!(p.wait().unwrap().success());
553 }
554
555 #[cfg(not(target_os="android"))]
556 #[test]
557 fn smoke_failure() {
558 match Command::new("if-this-is-a-binary-then-the-world-has-ended").spawn() {
559 Ok(..) => panic!(),
560 Err(..) => {}
561 }
562 }
563
564 #[cfg(not(target_os="android"))]
565 #[test]
566 fn exit_reported_right() {
567 let p = Command::new("false").spawn();
568 assert!(p.is_ok());
569 let mut p = p.unwrap();
570 assert!(p.wait().unwrap().code() == Some(1));
571 drop(p.wait());
572 }
573
574 #[cfg(all(unix, not(target_os="android")))]
575 #[test]
576 fn signal_reported_right() {
577 use os::unix::process::ExitStatusExt;
578
579 let p = Command::new("/bin/sh").arg("-c").arg("kill -9 $$").spawn();
580 assert!(p.is_ok());
581 let mut p = p.unwrap();
582 match p.wait().unwrap().signal() {
583 Some(9) => {},
584 result => panic!("not terminated by signal 9 (instead, {:?})", result),
585 }
586 }
587
588 pub fn run_output(mut cmd: Command) -> String {
589 let p = cmd.spawn();
590 assert!(p.is_ok());
591 let mut p = p.unwrap();
592 assert!(p.stdout.is_some());
593 let mut ret = String::new();
594 p.stdout.as_mut().unwrap().read_to_string(&mut ret).unwrap();
595 assert!(p.wait().unwrap().success());
596 return ret;
597 }
598
599 #[cfg(not(target_os="android"))]
600 #[test]
601 fn stdout_works() {
602 let mut cmd = Command::new("echo");
603 cmd.arg("foobar").stdout(Stdio::piped());
604 assert_eq!(run_output(cmd), "foobar\n");
605 }
606
607 #[cfg(all(unix, not(target_os="android")))]
608 #[test]
609 fn set_current_dir_works() {
610 let mut cmd = Command::new("/bin/sh");
611 cmd.arg("-c").arg("pwd")
612 .current_dir("/")
613 .stdout(Stdio::piped());
614 assert_eq!(run_output(cmd), "/\n");
615 }
616
617 #[cfg(all(unix, not(target_os="android")))]
618 #[test]
619 fn stdin_works() {
620 let mut p = Command::new("/bin/sh")
621 .arg("-c").arg("read line; echo $line")
622 .stdin(Stdio::piped())
623 .stdout(Stdio::piped())
624 .spawn().unwrap();
625 p.stdin.as_mut().unwrap().write("foobar".as_bytes()).unwrap();
626 drop(p.stdin.take());
627 let mut out = String::new();
628 p.stdout.as_mut().unwrap().read_to_string(&mut out).unwrap();
629 assert!(p.wait().unwrap().success());
630 assert_eq!(out, "foobar\n");
631 }
632
633
634 #[cfg(all(unix, not(target_os="android")))]
635 #[test]
636 fn uid_works() {
637 use os::unix::prelude::*;
638 use libc;
639 let mut p = Command::new("/bin/sh")
640 .arg("-c").arg("true")
641 .uid(unsafe { libc::getuid() })
642 .gid(unsafe { libc::getgid() })
643 .spawn().unwrap();
644 assert!(p.wait().unwrap().success());
645 }
646
647 #[cfg(all(unix, not(target_os="android")))]
648 #[test]
649 fn uid_to_root_fails() {
650 use os::unix::prelude::*;
651 use libc;
652
653 // if we're already root, this isn't a valid test. Most of the bots run
654 // as non-root though (android is an exception).
655 if unsafe { libc::getuid() == 0 } { return }
656 assert!(Command::new("/bin/ls").uid(0).gid(0).spawn().is_err());
657 }
658
659 #[cfg(not(target_os="android"))]
660 #[test]
661 fn test_process_status() {
662 let mut status = Command::new("false").status().unwrap();
663 assert!(status.code() == Some(1));
664
665 status = Command::new("true").status().unwrap();
666 assert!(status.success());
667 }
668
669 #[test]
670 fn test_process_output_fail_to_start() {
671 match Command::new("/no-binary-by-this-name-should-exist").output() {
672 Err(e) => assert_eq!(e.kind(), ErrorKind::NotFound),
673 Ok(..) => panic!()
674 }
675 }
676
677 #[cfg(not(target_os="android"))]
678 #[test]
679 fn test_process_output_output() {
680 let Output {status, stdout, stderr}
681 = Command::new("echo").arg("hello").output().unwrap();
682 let output_str = str::from_utf8(&stdout).unwrap();
683
684 assert!(status.success());
685 assert_eq!(output_str.trim().to_string(), "hello");
686 // FIXME #7224
687 if !running_on_valgrind() {
688 assert_eq!(stderr, Vec::new());
689 }
690 }
691
692 #[cfg(not(target_os="android"))]
693 #[test]
694 fn test_process_output_error() {
695 let Output {status, stdout, stderr}
696 = Command::new("mkdir").arg(".").output().unwrap();
697
698 assert!(status.code() == Some(1));
699 assert_eq!(stdout, Vec::new());
700 assert!(!stderr.is_empty());
701 }
702
703 #[cfg(not(target_os="android"))]
704 #[test]
705 fn test_finish_once() {
706 let mut prog = Command::new("false").spawn().unwrap();
707 assert!(prog.wait().unwrap().code() == Some(1));
708 }
709
710 #[cfg(not(target_os="android"))]
711 #[test]
712 fn test_finish_twice() {
713 let mut prog = Command::new("false").spawn().unwrap();
714 assert!(prog.wait().unwrap().code() == Some(1));
715 assert!(prog.wait().unwrap().code() == Some(1));
716 }
717
718 #[cfg(not(target_os="android"))]
719 #[test]
720 fn test_wait_with_output_once() {
721 let prog = Command::new("echo").arg("hello").stdout(Stdio::piped())
722 .spawn().unwrap();
723 let Output {status, stdout, stderr} = prog.wait_with_output().unwrap();
724 let output_str = str::from_utf8(&stdout).unwrap();
725
726 assert!(status.success());
727 assert_eq!(output_str.trim().to_string(), "hello");
728 // FIXME #7224
729 if !running_on_valgrind() {
730 assert_eq!(stderr, Vec::new());
731 }
732 }
733
734 #[cfg(all(unix, not(target_os="android")))]
735 pub fn pwd_cmd() -> Command {
736 Command::new("pwd")
737 }
738 #[cfg(target_os="android")]
739 pub fn pwd_cmd() -> Command {
740 let mut cmd = Command::new("/system/bin/sh");
741 cmd.arg("-c").arg("pwd");
742 cmd
743 }
744
745 #[cfg(windows)]
746 pub fn pwd_cmd() -> Command {
747 let mut cmd = Command::new("cmd");
748 cmd.arg("/c").arg("cd");
749 cmd
750 }
751
752 #[cfg(all(unix, not(target_os="android")))]
753 pub fn env_cmd() -> Command {
754 Command::new("env")
755 }
756 #[cfg(target_os="android")]
757 pub fn env_cmd() -> Command {
758 let mut cmd = Command::new("/system/bin/sh");
759 cmd.arg("-c").arg("set");
760 cmd
761 }
762
763 #[cfg(windows)]
764 pub fn env_cmd() -> Command {
765 let mut cmd = Command::new("cmd");
766 cmd.arg("/c").arg("set");
767 cmd
768 }
769
770 #[cfg(not(target_os="android"))]
771 #[test]
772 fn test_inherit_env() {
773 use std::env;
774 if running_on_valgrind() { return; }
775
776 let result = env_cmd().output().unwrap();
777 let output = String::from_utf8(result.stdout).unwrap();
778
779 for (ref k, ref v) in env::vars() {
780 // don't check windows magical empty-named variables
781 assert!(k.is_empty() ||
782 output.contains(&format!("{}={}", *k, *v)),
783 "output doesn't contain `{}={}`\n{}",
784 k, v, output);
785 }
786 }
787 #[cfg(target_os="android")]
788 #[test]
789 fn test_inherit_env() {
790 use std::env;
791 if running_on_valgrind() { return; }
792
793 let mut result = env_cmd().output().unwrap();
794 let output = String::from_utf8(result.stdout).unwrap();
795
796 for (ref k, ref v) in env::vars() {
797 // don't check android RANDOM variables
798 if *k != "RANDOM".to_string() {
799 assert!(output.contains(&format!("{}={}",
800 *k,
801 *v)) ||
802 output.contains(&format!("{}=\'{}\'",
803 *k,
804 *v)));
805 }
806 }
807 }
808
809 #[test]
810 fn test_override_env() {
811 use env;
812
813 // In some build environments (such as chrooted Nix builds), `env` can
814 // only be found in the explicitly-provided PATH env variable, not in
815 // default places such as /bin or /usr/bin. So we need to pass through
816 // PATH to our sub-process.
817 let mut cmd = env_cmd();
818 cmd.env_clear().env("RUN_TEST_NEW_ENV", "123");
819 if let Some(p) = env::var_os("PATH") {
820 cmd.env("PATH", &p);
821 }
822 let result = cmd.output().unwrap();
823 let output = String::from_utf8_lossy(&result.stdout).to_string();
824
825 assert!(output.contains("RUN_TEST_NEW_ENV=123"),
826 "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output);
827 }
828
829 #[test]
830 fn test_add_to_env() {
831 let result = env_cmd().env("RUN_TEST_NEW_ENV", "123").output().unwrap();
832 let output = String::from_utf8_lossy(&result.stdout).to_string();
833
834 assert!(output.contains("RUN_TEST_NEW_ENV=123"),
835 "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output);
836 }
837 }