]> git.proxmox.com Git - rustc.git/blob - src/libstd/old_io/process.rs
c803cfbcb7d85db2b9a77b33955b1ebce56c67a8
[rustc.git] / src / libstd / old_io / process.rs
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.
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 //! Bindings for executing child processes
12
13 #![allow(non_upper_case_globals)]
14
15 pub use self::StdioContainer::*;
16 pub use self::ProcessExit::*;
17
18 use prelude::v1::*;
19
20 use collections::HashMap;
21 use ffi::CString;
22 use fmt;
23 use old_io::pipe::{PipeStream, PipePair};
24 use old_io::{IoResult, IoError};
25 use old_io;
26 use libc;
27 use os;
28 use old_path::BytesContainer;
29 use sync::mpsc::{channel, Receiver};
30 use sys::fs::FileDesc;
31 use sys::process::Process as ProcessImp;
32 use sys;
33 use thread;
34
35 #[cfg(windows)] use hash;
36 #[cfg(windows)] use str;
37
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;
50
51 /// Representation of a running or exited child process.
52 ///
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.
56 ///
57 /// # Example
58 ///
59 /// ```should_fail
60 /// use std::old_io::Command;
61 ///
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),
65 /// };
66 ///
67 /// let contents = child.stdout.as_mut().unwrap().read_to_end();
68 /// assert!(child.wait().unwrap().success());
69 /// ```
70 pub struct Process {
71 handle: ProcessImp,
72 forget: bool,
73
74 /// None until wait() is called.
75 exit_code: Option<ProcessExit>,
76
77 /// Manually delivered signal
78 exit_signal: Option<int>,
79
80 /// Deadline after which wait() will return
81 deadline: u64,
82
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>,
86
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>,
90
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>,
94 }
95
96 /// A representation of environment variable name
97 /// It compares case-insensitive on Windows and case-sensitive everywhere else.
98 #[cfg(not(windows))]
99 #[derive(Hash, PartialEq, Eq, Clone, Debug)]
100 struct EnvKey(CString);
101
102 #[doc(hidden)]
103 #[cfg(windows)]
104 #[derive(Eq, Clone, Debug)]
105 struct EnvKey(CString);
106
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);
114 },
115 Err(..) => x.hash(state)
116 }
117 }
118 }
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);
126 },
127 Err(..) => x.hash(state)
128 }
129 }
130 }
131
132 #[cfg(windows)]
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() {
140 return false
141 } else {
142 for (xch, ych) in xs.chars().zip(ys.chars()) {
143 if xch.to_lowercase() != ych.to_lowercase() {
144 return false;
145 }
146 }
147 return true;
148 }
149 },
150 // If either is not a valid utf8 string, just compare them byte-wise
151 _ => return x.eq(y)
152 }
153 }
154 }
155
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()
160 }
161 }
162
163 /// A HashMap representation of environment variables.
164 pub type EnvMap = HashMap<EnvKey, CString>;
165
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:
171 ///
172 /// ```
173 /// use std::old_io::Command;
174 ///
175 /// let mut process = match Command::new("sh").arg("-c").arg("echo hello").spawn() {
176 /// Ok(p) => p,
177 /// Err(e) => panic!("failed to execute process: {}", e),
178 /// };
179 ///
180 /// let output = process.stdout.as_mut().unwrap().read_to_end();
181 /// ```
182 #[derive(Clone)]
183 pub struct Command {
184 // The internal data for the builder. Documented by the builder
185 // methods below, and serialized into rt::rtio::ProcessConfig.
186 program: CString,
187 args: Vec<CString>,
188 env: Option<EnvMap>,
189 cwd: Option<CString>,
190 stdin: StdioContainer,
191 stdout: StdioContainer,
192 stderr: StdioContainer,
193 uid: Option<uint>,
194 gid: Option<uint>,
195 detach: bool,
196 }
197
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}.)
204
205 impl Command {
206 /// Constructs a new `Command` for launching the program at
207 /// path `program`, with the following default configuration:
208 ///
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)
214 ///
215 /// Builder methods are provided to change these defaults and
216 /// otherwise configure the process.
217 pub fn new<T: BytesContainer>(program: T) -> Command {
218 Command {
219 program: CString::new(program.container_as_bytes()).unwrap(),
220 args: Vec::new(),
221 env: None,
222 cwd: None,
223 stdin: CreatePipe(true, false),
224 stdout: CreatePipe(false, true),
225 stderr: CreatePipe(false, true),
226 uid: None,
227 gid: None,
228 detach: false,
229 }
230 }
231
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());
235 self
236 }
237
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()
242 }));
243 self
244 }
245 // Get a mutable borrow of the environment variable map for this `Command`.
246 #[allow(deprecated)]
247 fn get_env_map<'a>(&'a mut self) -> &'a mut EnvMap {
248 match self.env {
249 Some(ref mut map) => map,
250 None => {
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())
256 }).collect());
257 self.env.as_mut().unwrap()
258 }
259 }
260 }
261
262 /// Inserts or updates an environment variable mapping.
263 ///
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)
267 -> &'a mut Command
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);
272 self
273 }
274
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);
280 self
281 }
282
283 /// Sets the entire environment map for the child process.
284 ///
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)])
288 -> &'a mut Command
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())
293 }).collect());
294 self
295 }
296
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());
300 self
301 }
302
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 {
306 self.stdin = cfg;
307 self
308 }
309
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 {
313 self.stdout = cfg;
314 self
315 }
316
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 {
320 self.stderr = cfg;
321 self
322 }
323
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
327 /// fail.
328 pub fn uid<'a>(&'a mut self, id: uint) -> &'a mut Command {
329 self.uid = Some(id);
330 self
331 }
332
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 {
336 self.gid = Some(id);
337 self
338 }
339
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 {
343 self.detach = true;
344 self
345 }
346
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));
352
353 match ProcessImp::spawn(self, their_stdin, their_stdout, their_stderr) {
354 Err(e) => Err(e),
355 Ok(handle) => Ok(Process {
356 handle: handle,
357 forget: false,
358 exit_code: None,
359 exit_signal: None,
360 deadline: 0,
361 stdin: our_stdin,
362 stdout: our_stdout,
363 stderr: our_stderr,
364 })
365 }
366 }
367
368 /// Executes the command as a child process, waiting for it to finish and
369 /// collecting all of its output.
370 ///
371 /// # Example
372 ///
373 /// ```
374 /// use std::old_io::Command;
375 ///
376 /// let output = match Command::new("cat").arg("foot.txt").output() {
377 /// Ok(output) => output,
378 /// Err(e) => panic!("failed to execute process: {}", e),
379 /// };
380 ///
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()));
384 /// ```
385 pub fn output(&self) -> IoResult<ProcessOutput> {
386 self.spawn().and_then(|p| p.wait_with_output())
387 }
388
389 /// Executes a command as a child process, waiting for it to finish and
390 /// collecting its exit status.
391 ///
392 /// # Example
393 ///
394 /// ```
395 /// use std::old_io::Command;
396 ///
397 /// let status = match Command::new("ls").status() {
398 /// Ok(status) => status,
399 /// Err(e) => panic!("failed to execute process: {}", e),
400 /// };
401 ///
402 /// println!("process exited with: {}", status);
403 /// ```
404 pub fn status(&self) -> IoResult<ProcessExit> {
405 self.spawn().and_then(|mut p| p.wait())
406 }
407 }
408
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
413 /// character.
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));
418 }
419 Ok(())
420 }
421 }
422
423 fn setup_io(io: StdioContainer) -> IoResult<(Option<PipeStream>, Option<PipeStream>)> {
424 let ours;
425 let theirs;
426 match io {
427 Ignored => {
428 theirs = None;
429 ours = None;
430 }
431 InheritFd(fd) => {
432 theirs = Some(PipeStream::from_filedesc(FileDesc::new(fd, false)));
433 ours = None;
434 }
435 CreatePipe(readable, _writable) => {
436 let PipePair { reader, writer } = try!(PipeStream::pair());
437 if readable {
438 theirs = Some(reader);
439 ours = Some(writer);
440 } else {
441 theirs = Some(writer);
442 ours = Some(reader);
443 }
444 }
445 }
446 Ok((theirs, ours))
447 }
448
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 {
452 &self.program
453 }
454 fn args(&self) -> &[CString] {
455 &self.args
456 }
457 fn env(&self) -> Option<&EnvMap> {
458 self.env.as_ref()
459 }
460 fn cwd(&self) -> Option<&CString> {
461 self.cwd.as_ref()
462 }
463 fn uid(&self) -> Option<uint> {
464 self.uid.clone()
465 }
466 fn gid(&self) -> Option<uint> {
467 self.gid.clone()
468 }
469 fn detach(&self) -> bool {
470 self.detach
471 }
472
473 }
474
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.
481 pub output: Vec<u8>,
482 /// The data that the process wrote to stderr.
483 pub error: Vec<u8>,
484 }
485
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`
491 Ignored,
492
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),
497
498 /// Creates a pipe for the specified file descriptor which will be created
499 /// when the process is spawned.
500 ///
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 */),
505 }
506
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.
512 ExitStatus(int),
513
514 /// Termination by signal, with the signal number.
515 ExitSignal(int),
516 }
517
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 {
522 match *self {
523 ExitStatus(code) => write!(f, "exit code: {}", code),
524 ExitSignal(code) => write!(f, "signal: {}", code),
525 }
526 }
527 }
528
529 impl ProcessExit {
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);
534 }
535
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)
540 }
541 }
542
543 impl Process {
544 /// Sends `signal` to another process in the system identified by `id`.
545 ///
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`.
549 ///
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
553 /// reaped.
554 pub fn kill(id: libc::pid_t, signal: int) -> IoResult<()> {
555 unsafe { ProcessImp::killpid(id, signal) }
556 }
557
558 /// Returns the process id of this child process
559 pub fn id(&self) -> libc::pid_t { self.handle.id() }
560
561 /// Sends the specified signal to the child process, returning whether the
562 /// signal could be delivered or not.
563 ///
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.
567 ///
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.
572 ///
573 /// # Errors
574 ///
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); }
586 None => {}
587 }
588 }
589 }
590 #[cfg(windows)] fn collect_status(_p: &mut Process) {}
591
592 collect_status(self);
593
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() {
598 return Err(IoError {
599 kind: old_io::InvalidInput,
600 desc: "invalid argument: can't kill an exited process",
601 detail: None,
602 })
603 }
604
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(()) }
610 Err(e) => Err(e),
611 }
612
613 }
614
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)
619 }
620
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)
625 }
626
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.
630 ///
631 /// The stdin handle to the child process will be closed before waiting.
632 ///
633 /// # Errors
634 ///
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),
641 None => {
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 {
647 None => code,
648 Some(signal) if cfg!(windows) => ExitSignal(signal),
649 Some(..) => code,
650 };
651 self.exit_code = Some(code);
652 Ok(code)
653 }
654 }
655 }
656
657 /// Sets a timeout, in milliseconds, for future calls to wait().
658 ///
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.
662 ///
663 /// A value of `None` will clear any previous timeout, and a value of `Some`
664 /// will override any previously set timeout.
665 ///
666 /// # Example
667 ///
668 /// ```no_run
669 /// use std::old_io::{Command, IoResult};
670 /// use std::old_io::process::ProcessExit;
671 ///
672 /// fn run_gracefully(prog: &str) -> IoResult<ProcessExit> {
673 /// let mut p = try!(Command::new("long-running-process").spawn());
674 ///
675 /// // give the process 10 seconds to finish completely
676 /// p.set_timeout(Some(10_000));
677 /// match p.wait() {
678 /// Ok(status) => return Ok(status),
679 /// Err(..) => {}
680 /// }
681 ///
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));
685 /// match p.wait() {
686 /// Ok(status) => return Ok(status),
687 /// Err(..) => {}
688 /// }
689 ///
690 /// // Well, we did our best, forcefully kill the process
691 /// try!(p.signal_kill());
692 /// p.set_timeout(None);
693 /// p.wait()
694 /// }
695 /// ```
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);
700 }
701
702 /// Simultaneously wait for the child to exit and collect all remaining
703 /// output on the stdout/stderr handles, returning a `ProcessOutput`
704 /// instance.
705 ///
706 /// The stdin handle to the child is closed before waiting.
707 ///
708 /// # Errors
709 ///
710 /// This function can fail for any of the same reasons that `wait()` can
711 /// fail.
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();
716 match stream {
717 Some(stream) => {
718 thread::spawn(move || {
719 let mut stream = stream;
720 tx.send(stream.read_to_end()).unwrap();
721 });
722 }
723 None => tx.send(Ok(Vec::new())).unwrap()
724 }
725 rx
726 }
727 let stdout = read(self.stdout.take());
728 let stderr = read(self.stderr.take());
729
730 let status = try!(self.wait());
731
732 Ok(ProcessOutput {
733 status: status,
734 output: stdout.recv().unwrap().unwrap_or(Vec::new()),
735 error: stderr.recv().unwrap().unwrap_or(Vec::new()),
736 })
737 }
738
739 /// Forgets this process, allowing it to outlive the parent
740 ///
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) {
747 self.forget = true;
748 }
749 }
750
751 impl Drop for Process {
752 fn drop(&mut self) {
753 if self.forget { return }
754
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());
760
761 self.set_timeout(None);
762 let _ = self.wait().unwrap();
763 }
764 }
765
766 #[cfg(test)]
767 mod tests {
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;
775 use str;
776 use super::{CreatePipe};
777 use super::{InheritFd, Process, PleaseExitSignal, Command, ProcessOutput};
778 use sync::mpsc::channel;
779 use thread;
780 use time::Duration;
781
782 // FIXME(#10380) these tests should not all be ignored on android.
783
784 #[cfg(not(target_os="android"))]
785 #[test]
786 fn smoke() {
787 let p = Command::new("true").spawn();
788 assert!(p.is_ok());
789 let mut p = p.unwrap();
790 assert!(p.wait().unwrap().success());
791 }
792
793 #[cfg(not(target_os="android"))]
794 #[test]
795 fn smoke_failure() {
796 match Command::new("if-this-is-a-binary-then-the-world-has-ended").spawn() {
797 Ok(..) => panic!(),
798 Err(..) => {}
799 }
800 }
801
802 #[cfg(not(target_os="android"))]
803 #[test]
804 fn exit_reported_right() {
805 let p = Command::new("false").spawn();
806 assert!(p.is_ok());
807 let mut p = p.unwrap();
808 assert!(p.wait().unwrap().matches_exit_status(1));
809 drop(p.wait().clone());
810 }
811
812 #[cfg(all(unix, not(target_os="android")))]
813 #[test]
814 fn signal_reported_right() {
815 let p = Command::new("/bin/sh").arg("-c").arg("kill -9 $$").spawn();
816 assert!(p.is_ok());
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),
821 }
822 }
823
824 pub fn read_all(input: &mut Reader) -> String {
825 input.read_to_string().unwrap()
826 }
827
828 pub fn run_output(cmd: Command) -> String {
829 let p = cmd.spawn();
830 assert!(p.is_ok());
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());
835 return ret;
836 }
837
838 #[cfg(not(target_os="android"))]
839 #[test]
840 fn stdout_works() {
841 let mut cmd = Command::new("echo");
842 cmd.arg("foobar").stdout(CreatePipe(false, true));
843 assert_eq!(run_output(cmd), "foobar\n");
844 }
845
846 #[cfg(all(unix, not(target_os="android")))]
847 #[test]
848 fn set_cwd_works() {
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");
854 }
855
856 #[cfg(all(unix, not(target_os="android")))]
857 #[test]
858 fn stdin_works() {
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))
863 .spawn().unwrap();
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");
869 }
870
871 #[cfg(not(target_os="android"))]
872 #[test]
873 fn detach_works() {
874 let mut p = Command::new("true").detached().spawn().unwrap();
875 assert!(p.wait().unwrap().success());
876 }
877
878 #[cfg(windows)]
879 #[test]
880 fn uid_fails_on_windows() {
881 assert!(Command::new("test").uid(10).spawn().is_err());
882 }
883
884 #[cfg(all(unix, not(target_os="android")))]
885 #[test]
886 fn uid_works() {
887 use libc;
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 })
892 .spawn().unwrap();
893 assert!(p.wait().unwrap().success());
894 }
895
896 #[cfg(all(unix, not(target_os="android")))]
897 #[test]
898 fn uid_to_root_fails() {
899 use libc;
900
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());
905 }
906
907 #[cfg(not(target_os="android"))]
908 #[test]
909 fn test_process_status() {
910 let mut status = Command::new("false").status().unwrap();
911 assert!(status.matches_exit_status(1));
912
913 status = Command::new("true").status().unwrap();
914 assert!(status.success());
915 }
916
917 #[test]
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),
921 Ok(..) => panic!()
922 }
923 }
924
925 #[cfg(not(target_os="android"))]
926 #[test]
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();
931
932 assert!(status.success());
933 assert_eq!(output_str.trim().to_string(), "hello");
934 // FIXME #7224
935 if !running_on_valgrind() {
936 assert_eq!(error, Vec::new());
937 }
938 }
939
940 #[cfg(not(target_os="android"))]
941 #[test]
942 fn test_process_output_error() {
943 let ProcessOutput {status, output, error}
944 = Command::new("mkdir").arg(".").output().unwrap();
945
946 assert!(status.matches_exit_status(1));
947 assert_eq!(output, Vec::new());
948 assert!(!error.is_empty());
949 }
950
951 #[cfg(not(target_os="android"))]
952 #[test]
953 fn test_finish_once() {
954 let mut prog = Command::new("false").spawn().unwrap();
955 assert!(prog.wait().unwrap().matches_exit_status(1));
956 }
957
958 #[cfg(not(target_os="android"))]
959 #[test]
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));
964 }
965
966 #[cfg(not(target_os="android"))]
967 #[test]
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();
972
973 assert!(status.success());
974 assert_eq!(output_str.trim().to_string(), "hello");
975 // FIXME #7224
976 if !running_on_valgrind() {
977 assert_eq!(error, Vec::new());
978 }
979 }
980
981 #[cfg(all(unix, not(target_os="android")))]
982 pub fn pwd_cmd() -> Command {
983 Command::new("pwd")
984 }
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");
989 cmd
990 }
991
992 #[cfg(windows)]
993 pub fn pwd_cmd() -> Command {
994 let mut cmd = Command::new("cmd");
995 cmd.arg("/c").arg("cd");
996 cmd
997 }
998
999 #[test]
1000 fn test_keep_current_working_dir() {
1001 use os;
1002 let prog = pwd_cmd().spawn().unwrap();
1003
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());
1007
1008 let parent_stat = parent_dir.stat().unwrap();
1009 let child_stat = child_dir.stat().unwrap();
1010
1011 assert_eq!(parent_stat.unstable.device, child_stat.unstable.device);
1012 assert_eq!(parent_stat.unstable.inode, child_stat.unstable.inode);
1013 }
1014
1015 #[test]
1016 fn test_change_working_directory() {
1017 use os;
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();
1022
1023 let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap();
1024 let child_dir = Path::new(output.trim());
1025
1026 let parent_stat = parent_dir.stat().unwrap();
1027 let child_stat = child_dir.stat().unwrap();
1028
1029 assert_eq!(parent_stat.unstable.device, child_stat.unstable.device);
1030 assert_eq!(parent_stat.unstable.inode, child_stat.unstable.inode);
1031 }
1032
1033 #[cfg(all(unix, not(target_os="android")))]
1034 pub fn env_cmd() -> Command {
1035 Command::new("env")
1036 }
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");
1041 cmd
1042 }
1043
1044 #[cfg(windows)]
1045 pub fn env_cmd() -> Command {
1046 let mut cmd = Command::new("cmd");
1047 cmd.arg("/c").arg("set");
1048 cmd
1049 }
1050
1051 #[cfg(not(target_os="android"))]
1052 #[test]
1053 fn test_inherit_env() {
1054 use os;
1055 if running_on_valgrind() { return; }
1056
1057 let prog = env_cmd().spawn().unwrap();
1058 let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap();
1059
1060 let r = os::env();
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{}",
1066 k, v, output);
1067 }
1068 }
1069 #[cfg(target_os="android")]
1070 #[test]
1071 fn test_inherit_env() {
1072 use os;
1073 if running_on_valgrind() { return; }
1074
1075 let mut prog = env_cmd().spawn().unwrap();
1076 let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap();
1077
1078 let r = os::env();
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!("{}={}",
1083 *k,
1084 *v)) ||
1085 output.contains(&format!("{}=\'{}\'",
1086 *k,
1087 *v)));
1088 }
1089 }
1090 }
1091
1092 #[test]
1093 fn test_override_env() {
1094 use os;
1095
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") {
1103 None => {}
1104 Some(val) => {
1105 path_val = val;
1106 new_env.push(("PATH", &path_val))
1107 }
1108 }
1109
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();
1113
1114 assert!(output.contains("RUN_TEST_NEW_ENV=123"),
1115 "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output);
1116 }
1117
1118 #[test]
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();
1123
1124 assert!(output.contains("RUN_TEST_NEW_ENV=123"),
1125 "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output);
1126 }
1127
1128 #[cfg(unix)]
1129 pub fn sleeper() -> Process {
1130 Command::new("sleep").arg("1000").spawn().unwrap()
1131 }
1132 #[cfg(windows)]
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()
1138 }
1139
1140 #[test]
1141 fn test_kill() {
1142 let mut p = sleeper();
1143 Process::kill(p.id(), PleaseExitSignal).unwrap();
1144 assert!(!p.wait().unwrap().success());
1145 }
1146
1147 #[test]
1148 fn test_exists() {
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());
1153 }
1154
1155 #[test]
1156 fn test_zero() {
1157 let mut p = sleeper();
1158 p.signal_kill().unwrap();
1159 for _ in 0..20 {
1160 if p.signal(0).is_err() {
1161 assert!(!p.wait().unwrap().success());
1162 return
1163 }
1164 timer::sleep(Duration::milliseconds(100));
1165 }
1166 panic!("never saw the child go away");
1167 }
1168
1169 #[test]
1170 fn wait_timeout() {
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());
1178 }
1179
1180 #[test]
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();
1190 });
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();
1197 });
1198 rx.recv().unwrap();
1199 rx.recv().unwrap();
1200 }
1201
1202 #[test]
1203 fn forget() {
1204 let p = sleeper();
1205 let id = p.id();
1206 p.forget();
1207 assert!(Process::kill(id, 0).is_ok());
1208 assert!(Process::kill(id, PleaseExitSignal).is_ok());
1209 }
1210
1211 #[test]
1212 fn dont_close_fd_on_command_spawn() {
1213 use sys::fs;
1214
1215 let path = if cfg!(windows) {
1216 Path::new("NUL")
1217 } else {
1218 Path::new("/dev/null")
1219 };
1220
1221 let fdes = match fs::open(&path, Truncate, Write) {
1222 Ok(f) => f,
1223 Err(_) => panic!("failed to open file descriptor"),
1224 };
1225
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());
1230 }
1231
1232 #[test]
1233 #[cfg(windows)]
1234 fn env_map_keys_ci() {
1235 use ffi::CString;
1236 use super::EnvKey;
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());
1243 }
1244 }