]>
Commit | Line | Data |
---|---|---|
85aaf69f SL |
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 | ||
c30ab7b3 SL |
11 | //! A module for working with processes. |
12 | //! | |
abe05a73 XL |
13 | //! This module is mostly concerned with spawning and interacting with child |
14 | //! processes, but it also provides [`abort`] and [`exit`] for terminating the | |
15 | //! current process. | |
c30ab7b3 | 16 | //! |
abe05a73 | 17 | //! # Spawning a process |
c30ab7b3 | 18 | //! |
abe05a73 XL |
19 | //! The [`Command`] struct is used to configure and spawn processes: |
20 | //! | |
21 | //! ``` | |
c30ab7b3 SL |
22 | //! use std::process::Command; |
23 | //! | |
abe05a73 XL |
24 | //! let output = Command::new("echo") |
25 | //! .arg("Hello world") | |
26 | //! .output() | |
27 | //! .expect("Failed to execute command"); | |
28 | //! | |
29 | //! assert_eq!(b"Hello world\n", output.stdout.as_slice()); | |
30 | //! ``` | |
31 | //! | |
32 | //! Several methods on [`Command`], such as [`spawn`] or [`output`], can be used | |
33 | //! to spawn a process. In particular, [`output`] spawns the child process and | |
34 | //! waits until the process terminates, while [`spawn`] will return a [`Child`] | |
35 | //! that represents the spawned child process. | |
36 | //! | |
37 | //! # Handling I/O | |
38 | //! | |
39 | //! The [`stdout`], [`stdin`], and [`stderr`] of a child process can be | |
40 | //! configured by passing an [`Stdio`] to the corresponding method on | |
41 | //! [`Command`]. Once spawned, they can be accessed from the [`Child`]. For | |
42 | //! example, piping output from one command into another command can be done | |
43 | //! like so: | |
44 | //! | |
45 | //! ```no_run | |
46 | //! use std::process::{Command, Stdio}; | |
47 | //! | |
48 | //! // stdout must be configured with `Stdio::piped` in order to use | |
49 | //! // `echo_child.stdout` | |
50 | //! let echo_child = Command::new("echo") | |
51 | //! .arg("Oh no, a tpyo!") | |
52 | //! .stdout(Stdio::piped()) | |
53 | //! .spawn() | |
54 | //! .expect("Failed to start echo process"); | |
55 | //! | |
56 | //! // Note that `echo_child` is moved here, but we won't be needing | |
57 | //! // `echo_child` anymore | |
58 | //! let echo_out = echo_child.stdout.expect("Failed to open echo stdout"); | |
c30ab7b3 | 59 | //! |
abe05a73 XL |
60 | //! let mut sed_child = Command::new("sed") |
61 | //! .arg("s/tpyo/typo/") | |
62 | //! .stdin(Stdio::from(echo_out)) | |
63 | //! .stdout(Stdio::piped()) | |
64 | //! .spawn() | |
65 | //! .expect("Failed to start sed process"); | |
c30ab7b3 | 66 | //! |
abe05a73 XL |
67 | //! let output = sed_child.wait_with_output().expect("Failed to wait on sed"); |
68 | //! assert_eq!(b"Oh no, a typo!\n", output.stdout.as_slice()); | |
c30ab7b3 | 69 | //! ``` |
8bb4bdeb | 70 | //! |
2c00a5a8 XL |
71 | //! Note that [`ChildStderr`] and [`ChildStdout`] implement [`Read`] and |
72 | //! [`ChildStdin`] implements [`Write`]: | |
8bb4bdeb XL |
73 | //! |
74 | //! ```no_run | |
75 | //! use std::process::{Command, Stdio}; | |
76 | //! use std::io::Write; | |
77 | //! | |
78 | //! let mut child = Command::new("/bin/cat") | |
79 | //! .stdin(Stdio::piped()) | |
80 | //! .stdout(Stdio::piped()) | |
81 | //! .spawn() | |
82 | //! .expect("failed to execute child"); | |
83 | //! | |
84 | //! { | |
85 | //! // limited borrow of stdin | |
86 | //! let stdin = child.stdin.as_mut().expect("failed to get stdin"); | |
87 | //! stdin.write_all(b"test").expect("failed to write to stdin"); | |
88 | //! } | |
89 | //! | |
90 | //! let output = child | |
91 | //! .wait_with_output() | |
92 | //! .expect("failed to wait on child"); | |
93 | //! | |
94 | //! assert_eq!(b"test", output.stdout.as_slice()); | |
95 | //! ``` | |
abe05a73 XL |
96 | //! |
97 | //! [`abort`]: fn.abort.html | |
98 | //! [`exit`]: fn.exit.html | |
99 | //! | |
100 | //! [`Command`]: struct.Command.html | |
101 | //! [`spawn`]: struct.Command.html#method.spawn | |
102 | //! [`output`]: struct.Command.html#method.output | |
103 | //! | |
104 | //! [`Child`]: struct.Child.html | |
105 | //! [`ChildStdin`]: struct.ChildStdin.html | |
106 | //! [`ChildStdout`]: struct.ChildStdout.html | |
107 | //! [`ChildStderr`]: struct.ChildStderr.html | |
108 | //! [`Stdio`]: struct.Stdio.html | |
109 | //! | |
110 | //! [`stdout`]: struct.Command.html#method.stdout | |
111 | //! [`stdin`]: struct.Command.html#method.stdin | |
112 | //! [`stderr`]: struct.Command.html#method.stderr | |
113 | //! | |
114 | //! [`Write`]: ../io/trait.Write.html | |
115 | //! [`Read`]: ../io/trait.Read.html | |
85aaf69f | 116 | |
c34b1796 | 117 | #![stable(feature = "process", since = "1.0.0")] |
85aaf69f | 118 | |
85aaf69f SL |
119 | use io::prelude::*; |
120 | ||
c34b1796 | 121 | use ffi::OsStr; |
85aaf69f | 122 | use fmt; |
041b39d2 XL |
123 | use fs; |
124 | use io::{self, Initializer}; | |
7453a54e | 125 | use path::Path; |
9cc50fc6 | 126 | use str; |
54a0048b | 127 | use sys::pipe::{read2, AnonPipe}; |
62682a34 | 128 | use sys::process as imp; |
c1a9b12d | 129 | use sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; |
85aaf69f SL |
130 | |
131 | /// Representation of a running or exited child process. | |
132 | /// | |
133 | /// This structure is used to represent and manage child processes. A child | |
5bcae85e SL |
134 | /// process is created via the [`Command`] struct, which configures the |
135 | /// spawning process and can itself be constructed using a builder-style | |
136 | /// interface. | |
85aaf69f | 137 | /// |
cc61c64b XL |
138 | /// There is no implementation of [`Drop`] for child processes, |
139 | /// so if you do not ensure the `Child` has exited then it will continue to | |
140 | /// run, even after the `Child` handle to the child process has gone out of | |
141 | /// scope. | |
142 | /// | |
143 | /// Calling [`wait`](#method.wait) (or other functions that wrap around it) will make | |
144 | /// the parent process wait until the child has actually exited before | |
145 | /// continuing. | |
146 | /// | |
c34b1796 | 147 | /// # Examples |
85aaf69f | 148 | /// |
c34b1796 | 149 | /// ```should_panic |
85aaf69f SL |
150 | /// use std::process::Command; |
151 | /// | |
bd371182 AL |
152 | /// let mut child = Command::new("/bin/cat") |
153 | /// .arg("file.txt") | |
154 | /// .spawn() | |
a7813a04 | 155 | /// .expect("failed to execute child"); |
bd371182 AL |
156 | /// |
157 | /// let ecode = child.wait() | |
a7813a04 | 158 | /// .expect("failed to wait on child"); |
bd371182 AL |
159 | /// |
160 | /// assert!(ecode.success()); | |
85aaf69f | 161 | /// ``` |
7453a54e | 162 | /// |
5bcae85e SL |
163 | /// [`Command`]: struct.Command.html |
164 | /// [`Drop`]: ../../core/ops/trait.Drop.html | |
165 | /// [`wait`]: #method.wait | |
c34b1796 | 166 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f | 167 | pub struct Child { |
62682a34 | 168 | handle: imp::Process, |
85aaf69f | 169 | |
ea8adc8c XL |
170 | /// The handle for writing to the child's standard input (stdin), if it has |
171 | /// been captured. | |
c34b1796 | 172 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
173 | pub stdin: Option<ChildStdin>, |
174 | ||
ea8adc8c XL |
175 | /// The handle for reading from the child's standard output (stdout), if it |
176 | /// has been captured. | |
c34b1796 | 177 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
178 | pub stdout: Option<ChildStdout>, |
179 | ||
ea8adc8c XL |
180 | /// The handle for reading from the child's standard error (stderr), if it |
181 | /// has been captured. | |
c34b1796 | 182 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
183 | pub stderr: Option<ChildStderr>, |
184 | } | |
185 | ||
62682a34 SL |
186 | impl AsInner<imp::Process> for Child { |
187 | fn as_inner(&self) -> &imp::Process { &self.handle } | |
188 | } | |
189 | ||
7453a54e SL |
190 | impl FromInner<(imp::Process, imp::StdioPipes)> for Child { |
191 | fn from_inner((handle, io): (imp::Process, imp::StdioPipes)) -> Child { | |
192 | Child { | |
3b2f2976 | 193 | handle, |
7453a54e SL |
194 | stdin: io.stdin.map(ChildStdin::from_inner), |
195 | stdout: io.stdout.map(ChildStdout::from_inner), | |
196 | stderr: io.stderr.map(ChildStderr::from_inner), | |
197 | } | |
198 | } | |
199 | } | |
200 | ||
c1a9b12d SL |
201 | impl IntoInner<imp::Process> for Child { |
202 | fn into_inner(self) -> imp::Process { self.handle } | |
203 | } | |
204 | ||
8bb4bdeb | 205 | #[stable(feature = "std_debug", since = "1.16.0")] |
32a655c1 SL |
206 | impl fmt::Debug for Child { |
207 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
208 | f.debug_struct("Child") | |
209 | .field("stdin", &self.stdin) | |
210 | .field("stdout", &self.stdout) | |
211 | .field("stderr", &self.stderr) | |
212 | .finish() | |
213 | } | |
214 | } | |
215 | ||
ea8adc8c | 216 | /// A handle to a child process's standard input (stdin). |
7cac9316 XL |
217 | /// |
218 | /// This struct is used in the [`stdin`] field on [`Child`]. | |
5bcae85e | 219 | /// |
ea8adc8c XL |
220 | /// When an instance of `ChildStdin` is [dropped], the `ChildStdin`'s underlying |
221 | /// file handle will be closed. If the child process was blocked on input prior | |
222 | /// to being dropped, it will become unblocked after dropping. | |
223 | /// | |
5bcae85e SL |
224 | /// [`Child`]: struct.Child.html |
225 | /// [`stdin`]: struct.Child.html#structfield.stdin | |
ea8adc8c | 226 | /// [dropped]: ../ops/trait.Drop.html |
c34b1796 | 227 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
228 | pub struct ChildStdin { |
229 | inner: AnonPipe | |
230 | } | |
231 | ||
c34b1796 | 232 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
233 | impl Write for ChildStdin { |
234 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { | |
235 | self.inner.write(buf) | |
236 | } | |
237 | ||
238 | fn flush(&mut self) -> io::Result<()> { | |
239 | Ok(()) | |
240 | } | |
241 | } | |
242 | ||
62682a34 SL |
243 | impl AsInner<AnonPipe> for ChildStdin { |
244 | fn as_inner(&self) -> &AnonPipe { &self.inner } | |
245 | } | |
246 | ||
c1a9b12d SL |
247 | impl IntoInner<AnonPipe> for ChildStdin { |
248 | fn into_inner(self) -> AnonPipe { self.inner } | |
249 | } | |
250 | ||
7453a54e SL |
251 | impl FromInner<AnonPipe> for ChildStdin { |
252 | fn from_inner(pipe: AnonPipe) -> ChildStdin { | |
253 | ChildStdin { inner: pipe } | |
254 | } | |
255 | } | |
256 | ||
8bb4bdeb | 257 | #[stable(feature = "std_debug", since = "1.16.0")] |
32a655c1 SL |
258 | impl fmt::Debug for ChildStdin { |
259 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
260 | f.pad("ChildStdin { .. }") | |
261 | } | |
262 | } | |
263 | ||
ea8adc8c | 264 | /// A handle to a child process's standard output (stdout). |
7cac9316 XL |
265 | /// |
266 | /// This struct is used in the [`stdout`] field on [`Child`]. | |
5bcae85e | 267 | /// |
ea8adc8c XL |
268 | /// When an instance of `ChildStdout` is [dropped], the `ChildStdout`'s |
269 | /// underlying file handle will be closed. | |
270 | /// | |
5bcae85e SL |
271 | /// [`Child`]: struct.Child.html |
272 | /// [`stdout`]: struct.Child.html#structfield.stdout | |
ea8adc8c | 273 | /// [dropped]: ../ops/trait.Drop.html |
c34b1796 | 274 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
275 | pub struct ChildStdout { |
276 | inner: AnonPipe | |
277 | } | |
278 | ||
c34b1796 | 279 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
280 | impl Read for ChildStdout { |
281 | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | |
282 | self.inner.read(buf) | |
283 | } | |
041b39d2 XL |
284 | #[inline] |
285 | unsafe fn initializer(&self) -> Initializer { | |
286 | Initializer::nop() | |
54a0048b | 287 | } |
85aaf69f SL |
288 | } |
289 | ||
62682a34 SL |
290 | impl AsInner<AnonPipe> for ChildStdout { |
291 | fn as_inner(&self) -> &AnonPipe { &self.inner } | |
292 | } | |
293 | ||
c1a9b12d SL |
294 | impl IntoInner<AnonPipe> for ChildStdout { |
295 | fn into_inner(self) -> AnonPipe { self.inner } | |
296 | } | |
297 | ||
7453a54e SL |
298 | impl FromInner<AnonPipe> for ChildStdout { |
299 | fn from_inner(pipe: AnonPipe) -> ChildStdout { | |
300 | ChildStdout { inner: pipe } | |
301 | } | |
302 | } | |
303 | ||
8bb4bdeb | 304 | #[stable(feature = "std_debug", since = "1.16.0")] |
32a655c1 SL |
305 | impl fmt::Debug for ChildStdout { |
306 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
307 | f.pad("ChildStdout { .. }") | |
308 | } | |
309 | } | |
310 | ||
cc61c64b XL |
311 | /// A handle to a child process's stderr. |
312 | /// | |
313 | /// This struct is used in the [`stderr`] field on [`Child`]. | |
5bcae85e | 314 | /// |
ea8adc8c XL |
315 | /// When an instance of `ChildStderr` is [dropped], the `ChildStderr`'s |
316 | /// underlying file handle will be closed. | |
317 | /// | |
5bcae85e SL |
318 | /// [`Child`]: struct.Child.html |
319 | /// [`stderr`]: struct.Child.html#structfield.stderr | |
ea8adc8c | 320 | /// [dropped]: ../ops/trait.Drop.html |
c34b1796 | 321 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
322 | pub struct ChildStderr { |
323 | inner: AnonPipe | |
324 | } | |
325 | ||
c34b1796 | 326 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
327 | impl Read for ChildStderr { |
328 | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | |
329 | self.inner.read(buf) | |
330 | } | |
041b39d2 XL |
331 | #[inline] |
332 | unsafe fn initializer(&self) -> Initializer { | |
333 | Initializer::nop() | |
54a0048b | 334 | } |
85aaf69f SL |
335 | } |
336 | ||
62682a34 SL |
337 | impl AsInner<AnonPipe> for ChildStderr { |
338 | fn as_inner(&self) -> &AnonPipe { &self.inner } | |
339 | } | |
340 | ||
c1a9b12d SL |
341 | impl IntoInner<AnonPipe> for ChildStderr { |
342 | fn into_inner(self) -> AnonPipe { self.inner } | |
343 | } | |
344 | ||
7453a54e SL |
345 | impl FromInner<AnonPipe> for ChildStderr { |
346 | fn from_inner(pipe: AnonPipe) -> ChildStderr { | |
347 | ChildStderr { inner: pipe } | |
348 | } | |
349 | } | |
350 | ||
8bb4bdeb | 351 | #[stable(feature = "std_debug", since = "1.16.0")] |
32a655c1 SL |
352 | impl fmt::Debug for ChildStderr { |
353 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
354 | f.pad("ChildStderr { .. }") | |
355 | } | |
356 | } | |
357 | ||
3157f602 XL |
358 | /// A process builder, providing fine-grained control |
359 | /// over how a new process should be spawned. | |
360 | /// | |
361 | /// A default configuration can be | |
85aaf69f SL |
362 | /// generated using `Command::new(program)`, where `program` gives a path to the |
363 | /// program to be executed. Additional builder methods allow the configuration | |
364 | /// to be changed (for example, by adding arguments) prior to spawning: | |
365 | /// | |
366 | /// ``` | |
85aaf69f SL |
367 | /// use std::process::Command; |
368 | /// | |
32a655c1 SL |
369 | /// let output = if cfg!(target_os = "windows") { |
370 | /// Command::new("cmd") | |
371 | /// .args(&["/C", "echo hello"]) | |
372 | /// .output() | |
373 | /// .expect("failed to execute process") | |
374 | /// } else { | |
375 | /// Command::new("sh") | |
376 | /// .arg("-c") | |
377 | /// .arg("echo hello") | |
378 | /// .output() | |
379 | /// .expect("failed to execute process") | |
380 | /// }; | |
a7813a04 | 381 | /// |
85aaf69f SL |
382 | /// let hello = output.stdout; |
383 | /// ``` | |
b7449926 XL |
384 | /// |
385 | /// `Command` can be reused to spawn multiple processes. The builder methods | |
386 | /// change the command without needing to immediately spawn the process. | |
387 | /// | |
388 | /// ```no_run | |
389 | /// use std::process::Command; | |
390 | /// | |
391 | /// let mut echo_hello = Command::new("sh"); | |
392 | /// echo_hello.arg("-c") | |
393 | /// .arg("echo hello"); | |
394 | /// let hello_1 = echo_hello.output().expect("failed to execute process"); | |
395 | /// let hello_2 = echo_hello.output().expect("failed to execute process"); | |
396 | /// ``` | |
397 | /// | |
398 | /// Similarly, you can call builder methods after spawning a process and then | |
399 | /// spawn a new process with the modified settings. | |
400 | /// | |
401 | /// ```no_run | |
402 | /// use std::process::Command; | |
403 | /// | |
404 | /// let mut list_dir = Command::new("ls"); | |
405 | /// | |
406 | /// // Execute `ls` in the current directory of the program. | |
407 | /// list_dir.status().expect("process failed to execute"); | |
408 | /// | |
409 | /// println!(""); | |
410 | /// | |
411 | /// // Change `ls` to execute in the root directory. | |
412 | /// list_dir.current_dir("/"); | |
413 | /// | |
414 | /// // And then execute `ls` again but in the root directory. | |
415 | /// list_dir.status().expect("process failed to execute"); | |
416 | /// ``` | |
c34b1796 | 417 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f | 418 | pub struct Command { |
62682a34 | 419 | inner: imp::Command, |
85aaf69f SL |
420 | } |
421 | ||
422 | impl Command { | |
423 | /// Constructs a new `Command` for launching the program at | |
424 | /// path `program`, with the following default configuration: | |
425 | /// | |
426 | /// * No arguments to the program | |
427 | /// * Inherit the current process's environment | |
428 | /// * Inherit the current process's working directory | |
bd371182 | 429 | /// * Inherit stdin/stdout/stderr for `spawn` or `status`, but create pipes for `output` |
85aaf69f SL |
430 | /// |
431 | /// Builder methods are provided to change these defaults and | |
432 | /// otherwise configure the process. | |
a7813a04 | 433 | /// |
476ff2be SL |
434 | /// If `program` is not an absolute path, the `PATH` will be searched in |
435 | /// an OS-defined way. | |
436 | /// | |
437 | /// The search path to be used may be controlled by setting the | |
438 | /// `PATH` environment variable on the Command, | |
439 | /// but this has some implementation limitations on Windows | |
abe05a73 | 440 | /// (see <https://github.com/rust-lang/rust/issues/37519>). |
476ff2be | 441 | /// |
a7813a04 XL |
442 | /// # Examples |
443 | /// | |
444 | /// Basic usage: | |
445 | /// | |
446 | /// ```no_run | |
447 | /// use std::process::Command; | |
448 | /// | |
449 | /// Command::new("sh") | |
450 | /// .spawn() | |
451 | /// .expect("sh command failed to start"); | |
452 | /// ``` | |
c34b1796 AL |
453 | #[stable(feature = "process", since = "1.0.0")] |
454 | pub fn new<S: AsRef<OsStr>>(program: S) -> Command { | |
7453a54e | 455 | Command { inner: imp::Command::new(program.as_ref()) } |
85aaf69f SL |
456 | } |
457 | ||
458 | /// Add an argument to pass to the program. | |
a7813a04 | 459 | /// |
cc61c64b XL |
460 | /// Only one argument can be passed per use. So instead of: |
461 | /// | |
041b39d2 XL |
462 | /// ```no_run |
463 | /// # std::process::Command::new("sh") | |
cc61c64b | 464 | /// .arg("-C /path/to/repo") |
041b39d2 | 465 | /// # ; |
cc61c64b XL |
466 | /// ``` |
467 | /// | |
468 | /// usage would be: | |
469 | /// | |
041b39d2 XL |
470 | /// ```no_run |
471 | /// # std::process::Command::new("sh") | |
cc61c64b XL |
472 | /// .arg("-C") |
473 | /// .arg("/path/to/repo") | |
041b39d2 | 474 | /// # ; |
cc61c64b XL |
475 | /// ``` |
476 | /// | |
477 | /// To pass multiple arguments see [`args`]. | |
478 | /// | |
479 | /// [`args`]: #method.args | |
480 | /// | |
a7813a04 XL |
481 | /// # Examples |
482 | /// | |
483 | /// Basic usage: | |
484 | /// | |
485 | /// ```no_run | |
486 | /// use std::process::Command; | |
487 | /// | |
488 | /// Command::new("ls") | |
489 | /// .arg("-l") | |
490 | /// .arg("-a") | |
491 | /// .spawn() | |
492 | /// .expect("ls command failed to start"); | |
493 | /// ``` | |
c34b1796 AL |
494 | #[stable(feature = "process", since = "1.0.0")] |
495 | pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Command { | |
496 | self.inner.arg(arg.as_ref()); | |
85aaf69f SL |
497 | self |
498 | } | |
499 | ||
500 | /// Add multiple arguments to pass to the program. | |
a7813a04 | 501 | /// |
cc61c64b XL |
502 | /// To pass a single argument see [`arg`]. |
503 | /// | |
504 | /// [`arg`]: #method.arg | |
505 | /// | |
a7813a04 XL |
506 | /// # Examples |
507 | /// | |
508 | /// Basic usage: | |
509 | /// | |
510 | /// ```no_run | |
511 | /// use std::process::Command; | |
512 | /// | |
513 | /// Command::new("ls") | |
514 | /// .args(&["-l", "-a"]) | |
515 | /// .spawn() | |
516 | /// .expect("ls command failed to start"); | |
517 | /// ``` | |
c34b1796 | 518 | #[stable(feature = "process", since = "1.0.0")] |
32a655c1 SL |
519 | pub fn args<I, S>(&mut self, args: I) -> &mut Command |
520 | where I: IntoIterator<Item=S>, S: AsRef<OsStr> | |
521 | { | |
7453a54e SL |
522 | for arg in args { |
523 | self.arg(arg.as_ref()); | |
524 | } | |
85aaf69f SL |
525 | self |
526 | } | |
527 | ||
528 | /// Inserts or updates an environment variable mapping. | |
529 | /// | |
530 | /// Note that environment variable names are case-insensitive (but case-preserving) on Windows, | |
531 | /// and case-sensitive on all other platforms. | |
a7813a04 XL |
532 | /// |
533 | /// # Examples | |
534 | /// | |
535 | /// Basic usage: | |
536 | /// | |
537 | /// ```no_run | |
538 | /// use std::process::Command; | |
539 | /// | |
540 | /// Command::new("ls") | |
541 | /// .env("PATH", "/bin") | |
542 | /// .spawn() | |
543 | /// .expect("ls command failed to start"); | |
544 | /// ``` | |
c34b1796 AL |
545 | #[stable(feature = "process", since = "1.0.0")] |
546 | pub fn env<K, V>(&mut self, key: K, val: V) -> &mut Command | |
547 | where K: AsRef<OsStr>, V: AsRef<OsStr> | |
85aaf69f | 548 | { |
ff7c6d11 | 549 | self.inner.env_mut().set(key.as_ref(), val.as_ref()); |
85aaf69f SL |
550 | self |
551 | } | |
552 | ||
32a655c1 SL |
553 | /// Add or update multiple environment variable mappings. |
554 | /// | |
555 | /// # Examples | |
556 | /// | |
557 | /// Basic usage: | |
cc61c64b | 558 | /// |
32a655c1 SL |
559 | /// ```no_run |
560 | /// use std::process::{Command, Stdio}; | |
561 | /// use std::env; | |
562 | /// use std::collections::HashMap; | |
563 | /// | |
564 | /// let filtered_env : HashMap<String, String> = | |
565 | /// env::vars().filter(|&(ref k, _)| | |
566 | /// k == "TERM" || k == "TZ" || k == "LANG" || k == "PATH" | |
567 | /// ).collect(); | |
568 | /// | |
569 | /// Command::new("printenv") | |
570 | /// .stdin(Stdio::null()) | |
571 | /// .stdout(Stdio::inherit()) | |
572 | /// .env_clear() | |
573 | /// .envs(&filtered_env) | |
574 | /// .spawn() | |
575 | /// .expect("printenv failed to start"); | |
576 | /// ``` | |
7cac9316 | 577 | #[stable(feature = "command_envs", since = "1.19.0")] |
32a655c1 SL |
578 | pub fn envs<I, K, V>(&mut self, vars: I) -> &mut Command |
579 | where I: IntoIterator<Item=(K, V)>, K: AsRef<OsStr>, V: AsRef<OsStr> | |
580 | { | |
581 | for (ref key, ref val) in vars { | |
ff7c6d11 | 582 | self.inner.env_mut().set(key.as_ref(), val.as_ref()); |
32a655c1 SL |
583 | } |
584 | self | |
585 | } | |
586 | ||
85aaf69f | 587 | /// Removes an environment variable mapping. |
a7813a04 XL |
588 | /// |
589 | /// # Examples | |
590 | /// | |
591 | /// Basic usage: | |
592 | /// | |
593 | /// ```no_run | |
594 | /// use std::process::Command; | |
595 | /// | |
596 | /// Command::new("ls") | |
597 | /// .env_remove("PATH") | |
598 | /// .spawn() | |
599 | /// .expect("ls command failed to start"); | |
600 | /// ``` | |
c34b1796 AL |
601 | #[stable(feature = "process", since = "1.0.0")] |
602 | pub fn env_remove<K: AsRef<OsStr>>(&mut self, key: K) -> &mut Command { | |
ff7c6d11 | 603 | self.inner.env_mut().remove(key.as_ref()); |
85aaf69f SL |
604 | self |
605 | } | |
606 | ||
607 | /// Clears the entire environment map for the child process. | |
a7813a04 XL |
608 | /// |
609 | /// # Examples | |
610 | /// | |
611 | /// Basic usage: | |
612 | /// | |
613 | /// ```no_run | |
614 | /// use std::process::Command; | |
615 | /// | |
616 | /// Command::new("ls") | |
617 | /// .env_clear() | |
618 | /// .spawn() | |
619 | /// .expect("ls command failed to start"); | |
620 | /// ``` | |
c34b1796 | 621 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f | 622 | pub fn env_clear(&mut self) -> &mut Command { |
ff7c6d11 | 623 | self.inner.env_mut().clear(); |
85aaf69f SL |
624 | self |
625 | } | |
626 | ||
9346a6ac | 627 | /// Sets the working directory for the child process. |
a7813a04 | 628 | /// |
b7449926 XL |
629 | /// # Platform-specific behavior |
630 | /// | |
631 | /// If the program path is relative (e.g. `"./script.sh"`), it's ambiguous | |
632 | /// whether it should be interpreted relative to the parent's working | |
633 | /// directory or relative to `current_dir`. The behavior in this case is | |
634 | /// platform specific and unstable, and it's recommended to use | |
635 | /// [`canonicalize`] to get an absolute program path instead. | |
636 | /// | |
a7813a04 XL |
637 | /// # Examples |
638 | /// | |
639 | /// Basic usage: | |
640 | /// | |
641 | /// ```no_run | |
642 | /// use std::process::Command; | |
643 | /// | |
644 | /// Command::new("ls") | |
645 | /// .current_dir("/bin") | |
646 | /// .spawn() | |
647 | /// .expect("ls command failed to start"); | |
648 | /// ``` | |
b7449926 XL |
649 | /// |
650 | /// [`canonicalize`]: ../fs/fn.canonicalize.html | |
c34b1796 | 651 | #[stable(feature = "process", since = "1.0.0")] |
7453a54e | 652 | pub fn current_dir<P: AsRef<Path>>(&mut self, dir: P) -> &mut Command { |
c34b1796 | 653 | self.inner.cwd(dir.as_ref().as_ref()); |
85aaf69f SL |
654 | self |
655 | } | |
656 | ||
ea8adc8c | 657 | /// Configuration for the child process's standard input (stdin) handle. |
a7813a04 | 658 | /// |
abe05a73 XL |
659 | /// Defaults to [`inherit`] when used with `spawn` or `status`, and |
660 | /// defaults to [`piped`] when used with `output`. | |
661 | /// | |
662 | /// [`inherit`]: struct.Stdio.html#method.inherit | |
663 | /// [`piped`]: struct.Stdio.html#method.piped | |
664 | /// | |
a7813a04 XL |
665 | /// # Examples |
666 | /// | |
667 | /// Basic usage: | |
668 | /// | |
669 | /// ```no_run | |
670 | /// use std::process::{Command, Stdio}; | |
671 | /// | |
672 | /// Command::new("ls") | |
673 | /// .stdin(Stdio::null()) | |
674 | /// .spawn() | |
675 | /// .expect("ls command failed to start"); | |
676 | /// ``` | |
c34b1796 | 677 | #[stable(feature = "process", since = "1.0.0")] |
041b39d2 XL |
678 | pub fn stdin<T: Into<Stdio>>(&mut self, cfg: T) -> &mut Command { |
679 | self.inner.stdin(cfg.into().0); | |
85aaf69f SL |
680 | self |
681 | } | |
682 | ||
ea8adc8c | 683 | /// Configuration for the child process's standard output (stdout) handle. |
a7813a04 | 684 | /// |
abe05a73 XL |
685 | /// Defaults to [`inherit`] when used with `spawn` or `status`, and |
686 | /// defaults to [`piped`] when used with `output`. | |
687 | /// | |
688 | /// [`inherit`]: struct.Stdio.html#method.inherit | |
689 | /// [`piped`]: struct.Stdio.html#method.piped | |
690 | /// | |
a7813a04 XL |
691 | /// # Examples |
692 | /// | |
693 | /// Basic usage: | |
694 | /// | |
695 | /// ```no_run | |
696 | /// use std::process::{Command, Stdio}; | |
697 | /// | |
698 | /// Command::new("ls") | |
699 | /// .stdout(Stdio::null()) | |
700 | /// .spawn() | |
701 | /// .expect("ls command failed to start"); | |
702 | /// ``` | |
c34b1796 | 703 | #[stable(feature = "process", since = "1.0.0")] |
041b39d2 XL |
704 | pub fn stdout<T: Into<Stdio>>(&mut self, cfg: T) -> &mut Command { |
705 | self.inner.stdout(cfg.into().0); | |
85aaf69f SL |
706 | self |
707 | } | |
708 | ||
ea8adc8c | 709 | /// Configuration for the child process's standard error (stderr) handle. |
a7813a04 | 710 | /// |
abe05a73 XL |
711 | /// Defaults to [`inherit`] when used with `spawn` or `status`, and |
712 | /// defaults to [`piped`] when used with `output`. | |
713 | /// | |
714 | /// [`inherit`]: struct.Stdio.html#method.inherit | |
715 | /// [`piped`]: struct.Stdio.html#method.piped | |
716 | /// | |
a7813a04 XL |
717 | /// # Examples |
718 | /// | |
719 | /// Basic usage: | |
720 | /// | |
721 | /// ```no_run | |
722 | /// use std::process::{Command, Stdio}; | |
723 | /// | |
724 | /// Command::new("ls") | |
725 | /// .stderr(Stdio::null()) | |
726 | /// .spawn() | |
727 | /// .expect("ls command failed to start"); | |
728 | /// ``` | |
c34b1796 | 729 | #[stable(feature = "process", since = "1.0.0")] |
041b39d2 XL |
730 | pub fn stderr<T: Into<Stdio>>(&mut self, cfg: T) -> &mut Command { |
731 | self.inner.stderr(cfg.into().0); | |
85aaf69f SL |
732 | self |
733 | } | |
734 | ||
85aaf69f SL |
735 | /// Executes the command as a child process, returning a handle to it. |
736 | /// | |
62682a34 | 737 | /// By default, stdin, stdout and stderr are inherited from the parent. |
a7813a04 XL |
738 | /// |
739 | /// # Examples | |
740 | /// | |
741 | /// Basic usage: | |
742 | /// | |
743 | /// ```no_run | |
744 | /// use std::process::Command; | |
745 | /// | |
746 | /// Command::new("ls") | |
747 | /// .spawn() | |
748 | /// .expect("ls command failed to start"); | |
749 | /// ``` | |
c34b1796 | 750 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f | 751 | pub fn spawn(&mut self) -> io::Result<Child> { |
54a0048b | 752 | self.inner.spawn(imp::Stdio::Inherit, true).map(Child::from_inner) |
85aaf69f SL |
753 | } |
754 | ||
755 | /// Executes the command as a child process, waiting for it to finish and | |
756 | /// collecting all of its output. | |
757 | /// | |
ff7c6d11 XL |
758 | /// By default, stdout and stderr are captured (and used to provide the |
759 | /// resulting output). Stdin is not inherited from the parent and any | |
760 | /// attempt by the child process to read from the stdin stream will result | |
761 | /// in the stream immediately closing. | |
85aaf69f | 762 | /// |
c34b1796 | 763 | /// # Examples |
85aaf69f | 764 | /// |
a7813a04 | 765 | /// ```should_panic |
85aaf69f | 766 | /// use std::process::Command; |
a7813a04 XL |
767 | /// let output = Command::new("/bin/cat") |
768 | /// .arg("file.txt") | |
769 | /// .output() | |
770 | /// .expect("failed to execute process"); | |
85aaf69f SL |
771 | /// |
772 | /// println!("status: {}", output.status); | |
c34b1796 AL |
773 | /// println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); |
774 | /// println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); | |
a7813a04 XL |
775 | /// |
776 | /// assert!(output.status.success()); | |
85aaf69f | 777 | /// ``` |
c34b1796 | 778 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f | 779 | pub fn output(&mut self) -> io::Result<Output> { |
54a0048b | 780 | self.inner.spawn(imp::Stdio::MakePipe, false).map(Child::from_inner) |
7453a54e | 781 | .and_then(|p| p.wait_with_output()) |
85aaf69f SL |
782 | } |
783 | ||
784 | /// Executes a command as a child process, waiting for it to finish and | |
785 | /// collecting its exit status. | |
786 | /// | |
62682a34 | 787 | /// By default, stdin, stdout and stderr are inherited from the parent. |
85aaf69f | 788 | /// |
c34b1796 | 789 | /// # Examples |
85aaf69f | 790 | /// |
a7813a04 | 791 | /// ```should_panic |
85aaf69f SL |
792 | /// use std::process::Command; |
793 | /// | |
a7813a04 XL |
794 | /// let status = Command::new("/bin/cat") |
795 | /// .arg("file.txt") | |
796 | /// .status() | |
797 | /// .expect("failed to execute process"); | |
85aaf69f SL |
798 | /// |
799 | /// println!("process exited with: {}", status); | |
a7813a04 XL |
800 | /// |
801 | /// assert!(status.success()); | |
85aaf69f | 802 | /// ``` |
c34b1796 | 803 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f | 804 | pub fn status(&mut self) -> io::Result<ExitStatus> { |
54a0048b SL |
805 | self.inner.spawn(imp::Stdio::Inherit, true).map(Child::from_inner) |
806 | .and_then(|mut p| p.wait()) | |
85aaf69f SL |
807 | } |
808 | } | |
809 | ||
810 | #[stable(feature = "rust1", since = "1.0.0")] | |
811 | impl fmt::Debug for Command { | |
812 | /// Format the program and arguments of a Command for display. Any | |
813 | /// non-utf8 data is lossily converted using the utf8 replacement | |
814 | /// character. | |
815 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
7453a54e | 816 | self.inner.fmt(f) |
85aaf69f SL |
817 | } |
818 | } | |
819 | ||
62682a34 SL |
820 | impl AsInner<imp::Command> for Command { |
821 | fn as_inner(&self) -> &imp::Command { &self.inner } | |
85aaf69f SL |
822 | } |
823 | ||
62682a34 SL |
824 | impl AsInnerMut<imp::Command> for Command { |
825 | fn as_inner_mut(&mut self) -> &mut imp::Command { &mut self.inner } | |
85aaf69f SL |
826 | } |
827 | ||
85aaf69f | 828 | /// The output of a finished process. |
abe05a73 XL |
829 | /// |
830 | /// This is returned in a Result by either the [`output`] method of a | |
831 | /// [`Command`], or the [`wait_with_output`] method of a [`Child`] | |
832 | /// process. | |
833 | /// | |
834 | /// [`Command`]: struct.Command.html | |
835 | /// [`Child`]: struct.Child.html | |
836 | /// [`output`]: struct.Command.html#method.output | |
837 | /// [`wait_with_output`]: struct.Child.html#method.wait_with_output | |
85aaf69f | 838 | #[derive(PartialEq, Eq, Clone)] |
c34b1796 | 839 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
840 | pub struct Output { |
841 | /// The status (exit code) of the process. | |
c34b1796 | 842 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
843 | pub status: ExitStatus, |
844 | /// The data that the process wrote to stdout. | |
c34b1796 | 845 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
846 | pub stdout: Vec<u8>, |
847 | /// The data that the process wrote to stderr. | |
c34b1796 | 848 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
849 | pub stderr: Vec<u8>, |
850 | } | |
851 | ||
9cc50fc6 SL |
852 | // If either stderr or stdout are valid utf8 strings it prints the valid |
853 | // strings, otherwise it prints the byte sequence instead | |
854 | #[stable(feature = "process_output_debug", since = "1.7.0")] | |
855 | impl fmt::Debug for Output { | |
856 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | |
857 | ||
858 | let stdout_utf8 = str::from_utf8(&self.stdout); | |
8faf50e0 | 859 | let stdout_debug: &dyn fmt::Debug = match stdout_utf8 { |
9cc50fc6 SL |
860 | Ok(ref str) => str, |
861 | Err(_) => &self.stdout | |
862 | }; | |
863 | ||
864 | let stderr_utf8 = str::from_utf8(&self.stderr); | |
8faf50e0 | 865 | let stderr_debug: &dyn fmt::Debug = match stderr_utf8 { |
9cc50fc6 SL |
866 | Ok(ref str) => str, |
867 | Err(_) => &self.stderr | |
868 | }; | |
869 | ||
870 | fmt.debug_struct("Output") | |
871 | .field("status", &self.status) | |
872 | .field("stdout", stdout_debug) | |
873 | .field("stderr", stderr_debug) | |
874 | .finish() | |
875 | } | |
876 | } | |
877 | ||
abe05a73 XL |
878 | /// Describes what to do with a standard I/O stream for a child process when |
879 | /// passed to the [`stdin`], [`stdout`], and [`stderr`] methods of [`Command`]. | |
880 | /// | |
881 | /// [`stdin`]: struct.Command.html#method.stdin | |
882 | /// [`stdout`]: struct.Command.html#method.stdout | |
883 | /// [`stderr`]: struct.Command.html#method.stderr | |
884 | /// [`Command`]: struct.Command.html | |
c34b1796 | 885 | #[stable(feature = "process", since = "1.0.0")] |
7453a54e | 886 | pub struct Stdio(imp::Stdio); |
85aaf69f SL |
887 | |
888 | impl Stdio { | |
889 | /// A new pipe should be arranged to connect the parent and child processes. | |
abe05a73 XL |
890 | /// |
891 | /// # Examples | |
892 | /// | |
893 | /// With stdout: | |
894 | /// | |
895 | /// ```no_run | |
896 | /// use std::process::{Command, Stdio}; | |
897 | /// | |
898 | /// let output = Command::new("echo") | |
899 | /// .arg("Hello, world!") | |
900 | /// .stdout(Stdio::piped()) | |
901 | /// .output() | |
902 | /// .expect("Failed to execute command"); | |
903 | /// | |
904 | /// assert_eq!(String::from_utf8_lossy(&output.stdout), "Hello, world!\n"); | |
905 | /// // Nothing echoed to console | |
906 | /// ``` | |
907 | /// | |
908 | /// With stdin: | |
909 | /// | |
910 | /// ```no_run | |
911 | /// use std::io::Write; | |
912 | /// use std::process::{Command, Stdio}; | |
913 | /// | |
914 | /// let mut child = Command::new("rev") | |
915 | /// .stdin(Stdio::piped()) | |
916 | /// .stdout(Stdio::piped()) | |
917 | /// .spawn() | |
918 | /// .expect("Failed to spawn child process"); | |
919 | /// | |
920 | /// { | |
921 | /// let mut stdin = child.stdin.as_mut().expect("Failed to open stdin"); | |
922 | /// stdin.write_all("Hello, world!".as_bytes()).expect("Failed to write to stdin"); | |
923 | /// } | |
924 | /// | |
925 | /// let output = child.wait_with_output().expect("Failed to read stdout"); | |
926 | /// assert_eq!(String::from_utf8_lossy(&output.stdout), "!dlrow ,olleH\n"); | |
927 | /// ``` | |
c34b1796 | 928 | #[stable(feature = "process", since = "1.0.0")] |
7453a54e | 929 | pub fn piped() -> Stdio { Stdio(imp::Stdio::MakePipe) } |
85aaf69f SL |
930 | |
931 | /// The child inherits from the corresponding parent descriptor. | |
abe05a73 XL |
932 | /// |
933 | /// # Examples | |
934 | /// | |
935 | /// With stdout: | |
936 | /// | |
937 | /// ```no_run | |
938 | /// use std::process::{Command, Stdio}; | |
939 | /// | |
940 | /// let output = Command::new("echo") | |
941 | /// .arg("Hello, world!") | |
942 | /// .stdout(Stdio::inherit()) | |
943 | /// .output() | |
944 | /// .expect("Failed to execute command"); | |
945 | /// | |
946 | /// assert_eq!(String::from_utf8_lossy(&output.stdout), ""); | |
947 | /// // "Hello, world!" echoed to console | |
948 | /// ``` | |
949 | /// | |
950 | /// With stdin: | |
951 | /// | |
952 | /// ```no_run | |
953 | /// use std::process::{Command, Stdio}; | |
954 | /// | |
955 | /// let output = Command::new("rev") | |
956 | /// .stdin(Stdio::inherit()) | |
957 | /// .stdout(Stdio::piped()) | |
958 | /// .output() | |
959 | /// .expect("Failed to execute command"); | |
960 | /// | |
961 | /// println!("You piped in the reverse of: {}", String::from_utf8_lossy(&output.stdout)); | |
962 | /// ``` | |
c34b1796 | 963 | #[stable(feature = "process", since = "1.0.0")] |
7453a54e | 964 | pub fn inherit() -> Stdio { Stdio(imp::Stdio::Inherit) } |
85aaf69f SL |
965 | |
966 | /// This stream will be ignored. This is the equivalent of attaching the | |
967 | /// stream to `/dev/null` | |
abe05a73 XL |
968 | /// |
969 | /// # Examples | |
970 | /// | |
971 | /// With stdout: | |
972 | /// | |
973 | /// ```no_run | |
974 | /// use std::process::{Command, Stdio}; | |
975 | /// | |
976 | /// let output = Command::new("echo") | |
977 | /// .arg("Hello, world!") | |
978 | /// .stdout(Stdio::null()) | |
979 | /// .output() | |
980 | /// .expect("Failed to execute command"); | |
981 | /// | |
982 | /// assert_eq!(String::from_utf8_lossy(&output.stdout), ""); | |
983 | /// // Nothing echoed to console | |
984 | /// ``` | |
985 | /// | |
986 | /// With stdin: | |
987 | /// | |
988 | /// ```no_run | |
989 | /// use std::process::{Command, Stdio}; | |
990 | /// | |
991 | /// let output = Command::new("rev") | |
992 | /// .stdin(Stdio::null()) | |
993 | /// .stdout(Stdio::piped()) | |
994 | /// .output() | |
995 | /// .expect("Failed to execute command"); | |
996 | /// | |
997 | /// assert_eq!(String::from_utf8_lossy(&output.stdout), ""); | |
998 | /// // Ignores any piped-in input | |
999 | /// ``` | |
c34b1796 | 1000 | #[stable(feature = "process", since = "1.0.0")] |
7453a54e | 1001 | pub fn null() -> Stdio { Stdio(imp::Stdio::Null) } |
62682a34 SL |
1002 | } |
1003 | ||
7453a54e SL |
1004 | impl FromInner<imp::Stdio> for Stdio { |
1005 | fn from_inner(inner: imp::Stdio) -> Stdio { | |
1006 | Stdio(inner) | |
62682a34 | 1007 | } |
85aaf69f SL |
1008 | } |
1009 | ||
8bb4bdeb | 1010 | #[stable(feature = "std_debug", since = "1.16.0")] |
32a655c1 SL |
1011 | impl fmt::Debug for Stdio { |
1012 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
1013 | f.pad("Stdio { .. }") | |
1014 | } | |
1015 | } | |
1016 | ||
041b39d2 XL |
1017 | #[stable(feature = "stdio_from", since = "1.20.0")] |
1018 | impl From<ChildStdin> for Stdio { | |
1019 | fn from(child: ChildStdin) -> Stdio { | |
1020 | Stdio::from_inner(child.into_inner().into()) | |
1021 | } | |
1022 | } | |
1023 | ||
1024 | #[stable(feature = "stdio_from", since = "1.20.0")] | |
1025 | impl From<ChildStdout> for Stdio { | |
1026 | fn from(child: ChildStdout) -> Stdio { | |
1027 | Stdio::from_inner(child.into_inner().into()) | |
1028 | } | |
1029 | } | |
1030 | ||
1031 | #[stable(feature = "stdio_from", since = "1.20.0")] | |
1032 | impl From<ChildStderr> for Stdio { | |
1033 | fn from(child: ChildStderr) -> Stdio { | |
1034 | Stdio::from_inner(child.into_inner().into()) | |
1035 | } | |
1036 | } | |
1037 | ||
1038 | #[stable(feature = "stdio_from", since = "1.20.0")] | |
1039 | impl From<fs::File> for Stdio { | |
1040 | fn from(file: fs::File) -> Stdio { | |
1041 | Stdio::from_inner(file.into_inner().into()) | |
1042 | } | |
1043 | } | |
1044 | ||
85aaf69f | 1045 | /// Describes the result of a process after it has terminated. |
7cac9316 XL |
1046 | /// |
1047 | /// This `struct` is used to represent the exit status of a child process. | |
1048 | /// Child processes are created via the [`Command`] struct and their exit | |
1049 | /// status is exposed through the [`status`] method. | |
1050 | /// | |
1051 | /// [`Command`]: struct.Command.html | |
1052 | /// [`status`]: struct.Command.html#method.status | |
85aaf69f | 1053 | #[derive(PartialEq, Eq, Clone, Copy, Debug)] |
c34b1796 | 1054 | #[stable(feature = "process", since = "1.0.0")] |
62682a34 | 1055 | pub struct ExitStatus(imp::ExitStatus); |
85aaf69f SL |
1056 | |
1057 | impl ExitStatus { | |
3b2f2976 XL |
1058 | /// Was termination successful? Signal termination is not considered a |
1059 | /// success, and success is defined as a zero exit status. | |
5bcae85e SL |
1060 | /// |
1061 | /// # Examples | |
1062 | /// | |
1063 | /// ```rust,no_run | |
1064 | /// use std::process::Command; | |
1065 | /// | |
1066 | /// let status = Command::new("mkdir") | |
1067 | /// .arg("projects") | |
1068 | /// .status() | |
1069 | /// .expect("failed to execute mkdir"); | |
1070 | /// | |
1071 | /// if status.success() { | |
1072 | /// println!("'projects/' directory created"); | |
1073 | /// } else { | |
1074 | /// println!("failed to create 'projects/' directory"); | |
1075 | /// } | |
1076 | /// ``` | |
c34b1796 | 1077 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
1078 | pub fn success(&self) -> bool { |
1079 | self.0.success() | |
1080 | } | |
1081 | ||
9346a6ac | 1082 | /// Returns the exit code of the process, if any. |
85aaf69f SL |
1083 | /// |
1084 | /// On Unix, this will return `None` if the process was terminated | |
1085 | /// by a signal; `std::os::unix` provides an extension trait for | |
1086 | /// extracting the signal and other details from the `ExitStatus`. | |
7cac9316 XL |
1087 | /// |
1088 | /// # Examples | |
1089 | /// | |
1090 | /// ```no_run | |
1091 | /// use std::process::Command; | |
1092 | /// | |
1093 | /// let status = Command::new("mkdir") | |
1094 | /// .arg("projects") | |
1095 | /// .status() | |
1096 | /// .expect("failed to execute mkdir"); | |
1097 | /// | |
1098 | /// match status.code() { | |
1099 | /// Some(code) => println!("Exited with status code: {}", code), | |
1100 | /// None => println!("Process terminated by signal") | |
1101 | /// } | |
1102 | /// ``` | |
c34b1796 | 1103 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
1104 | pub fn code(&self) -> Option<i32> { |
1105 | self.0.code() | |
1106 | } | |
1107 | } | |
1108 | ||
62682a34 SL |
1109 | impl AsInner<imp::ExitStatus> for ExitStatus { |
1110 | fn as_inner(&self) -> &imp::ExitStatus { &self.0 } | |
85aaf69f SL |
1111 | } |
1112 | ||
a7813a04 XL |
1113 | impl FromInner<imp::ExitStatus> for ExitStatus { |
1114 | fn from_inner(s: imp::ExitStatus) -> ExitStatus { | |
1115 | ExitStatus(s) | |
1116 | } | |
1117 | } | |
1118 | ||
c34b1796 | 1119 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
1120 | impl fmt::Display for ExitStatus { |
1121 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
1122 | self.0.fmt(f) | |
1123 | } | |
1124 | } | |
1125 | ||
0531ce1d XL |
1126 | /// This type represents the status code a process can return to its |
1127 | /// parent under normal termination. | |
1128 | /// | |
1129 | /// Numeric values used in this type don't have portable meanings, and | |
1130 | /// different platforms may mask different amounts of them. | |
1131 | /// | |
1132 | /// For the platform's canonical successful and unsuccessful codes, see | |
1133 | /// the [`SUCCESS`] and [`FAILURE`] associated items. | |
1134 | /// | |
1135 | /// [`SUCCESS`]: #associatedconstant.SUCCESS | |
1136 | /// [`FAILURE`]: #associatedconstant.FAILURE | |
1137 | /// | |
1138 | /// **Warning**: While various forms of this were discussed in [RFC #1937], | |
1139 | /// it was ultimately cut from that RFC, and thus this type is more subject | |
1140 | /// to change even than the usual unstable item churn. | |
1141 | /// | |
1142 | /// [RFC #1937]: https://github.com/rust-lang/rfcs/pull/1937 | |
1143 | #[derive(Clone, Copy, Debug)] | |
1144 | #[unstable(feature = "process_exitcode_placeholder", issue = "48711")] | |
1145 | pub struct ExitCode(imp::ExitCode); | |
1146 | ||
1147 | #[unstable(feature = "process_exitcode_placeholder", issue = "48711")] | |
1148 | impl ExitCode { | |
1149 | /// The canonical ExitCode for successful termination on this platform. | |
1150 | /// | |
1151 | /// Note that a `()`-returning `main` implicitly results in a successful | |
1152 | /// termination, so there's no need to return this from `main` unless | |
1153 | /// you're also returning other possible codes. | |
1154 | #[unstable(feature = "process_exitcode_placeholder", issue = "48711")] | |
1155 | pub const SUCCESS: ExitCode = ExitCode(imp::ExitCode::SUCCESS); | |
1156 | ||
1157 | /// The canonical ExitCode for unsuccessful termination on this platform. | |
1158 | /// | |
1159 | /// If you're only returning this and `SUCCESS` from `main`, consider | |
1160 | /// instead returning `Err(_)` and `Ok(())` respectively, which will | |
1161 | /// return the same codes (but will also `eprintln!` the error). | |
1162 | #[unstable(feature = "process_exitcode_placeholder", issue = "48711")] | |
1163 | pub const FAILURE: ExitCode = ExitCode(imp::ExitCode::FAILURE); | |
1164 | } | |
1165 | ||
85aaf69f | 1166 | impl Child { |
83c7162d XL |
1167 | /// Forces the child process to exit. If the child has already exited, an [`InvalidInput`] |
1168 | /// error is returned. | |
1169 | /// | |
1170 | /// The mapping to [`ErrorKind`]s is not part of the compatibility contract of the function, | |
1171 | /// especially the [`Other`] kind might change to more specific kinds in the future. | |
1172 | /// | |
1173 | /// This is equivalent to sending a SIGKILL on Unix platforms. | |
a7813a04 XL |
1174 | /// |
1175 | /// # Examples | |
1176 | /// | |
1177 | /// Basic usage: | |
1178 | /// | |
1179 | /// ```no_run | |
1180 | /// use std::process::Command; | |
1181 | /// | |
1182 | /// let mut command = Command::new("yes"); | |
1183 | /// if let Ok(mut child) = command.spawn() { | |
1184 | /// child.kill().expect("command wasn't running"); | |
1185 | /// } else { | |
1186 | /// println!("yes command didn't start"); | |
1187 | /// } | |
1188 | /// ``` | |
83c7162d XL |
1189 | /// |
1190 | /// [`ErrorKind`]: ../io/enum.ErrorKind.html | |
1191 | /// [`InvalidInput`]: ../io/enum.ErrorKind.html#variant.InvalidInput | |
1192 | /// [`Other`]: ../io/enum.ErrorKind.html#variant.Other | |
c34b1796 | 1193 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f | 1194 | pub fn kill(&mut self) -> io::Result<()> { |
7453a54e | 1195 | self.handle.kill() |
85aaf69f SL |
1196 | } |
1197 | ||
62682a34 | 1198 | /// Returns the OS-assigned process identifier associated with this child. |
a7813a04 XL |
1199 | /// |
1200 | /// # Examples | |
1201 | /// | |
1202 | /// Basic usage: | |
1203 | /// | |
1204 | /// ```no_run | |
1205 | /// use std::process::Command; | |
1206 | /// | |
1207 | /// let mut command = Command::new("ls"); | |
1208 | /// if let Ok(child) = command.spawn() { | |
1209 | /// println!("Child's id is {}", child.id()); | |
1210 | /// } else { | |
1211 | /// println!("ls command didn't start"); | |
1212 | /// } | |
1213 | /// ``` | |
c1a9b12d | 1214 | #[stable(feature = "process_id", since = "1.3.0")] |
62682a34 SL |
1215 | pub fn id(&self) -> u32 { |
1216 | self.handle.id() | |
1217 | } | |
1218 | ||
9346a6ac | 1219 | /// Waits for the child to exit completely, returning the status that it |
85aaf69f SL |
1220 | /// exited with. This function will continue to have the same return value |
1221 | /// after it has been called at least once. | |
1222 | /// | |
1223 | /// The stdin handle to the child process, if any, will be closed | |
1224 | /// before waiting. This helps avoid deadlock: it ensures that the | |
1225 | /// child does not block waiting for input from the parent, while | |
1226 | /// the parent waits for the child to exit. | |
a7813a04 XL |
1227 | /// |
1228 | /// # Examples | |
1229 | /// | |
1230 | /// Basic usage: | |
1231 | /// | |
1232 | /// ```no_run | |
1233 | /// use std::process::Command; | |
1234 | /// | |
1235 | /// let mut command = Command::new("ls"); | |
1236 | /// if let Ok(mut child) = command.spawn() { | |
1237 | /// child.wait().expect("command wasn't running"); | |
1238 | /// println!("Child has finished its execution!"); | |
1239 | /// } else { | |
1240 | /// println!("ls command didn't start"); | |
1241 | /// } | |
1242 | /// ``` | |
c34b1796 | 1243 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
1244 | pub fn wait(&mut self) -> io::Result<ExitStatus> { |
1245 | drop(self.stdin.take()); | |
7453a54e | 1246 | self.handle.wait().map(ExitStatus) |
85aaf69f SL |
1247 | } |
1248 | ||
32a655c1 SL |
1249 | /// Attempts to collect the exit status of the child if it has already |
1250 | /// exited. | |
1251 | /// | |
1252 | /// This function will not block the calling thread and will only advisorily | |
1253 | /// check to see if the child process has exited or not. If the child has | |
1254 | /// exited then on Unix the process id is reaped. This function is | |
1255 | /// guaranteed to repeatedly return a successful exit status so long as the | |
1256 | /// child has already exited. | |
1257 | /// | |
8bb4bdeb XL |
1258 | /// If the child has exited, then `Ok(Some(status))` is returned. If the |
1259 | /// exit status is not available at this time then `Ok(None)` is returned. | |
1260 | /// If an error occurs, then that error is returned. | |
32a655c1 SL |
1261 | /// |
1262 | /// Note that unlike `wait`, this function will not attempt to drop stdin. | |
1263 | /// | |
1264 | /// # Examples | |
1265 | /// | |
1266 | /// Basic usage: | |
1267 | /// | |
1268 | /// ```no_run | |
32a655c1 SL |
1269 | /// use std::process::Command; |
1270 | /// | |
1271 | /// let mut child = Command::new("ls").spawn().unwrap(); | |
1272 | /// | |
1273 | /// match child.try_wait() { | |
8bb4bdeb XL |
1274 | /// Ok(Some(status)) => println!("exited with: {}", status), |
1275 | /// Ok(None) => { | |
32a655c1 SL |
1276 | /// println!("status not ready yet, let's really wait"); |
1277 | /// let res = child.wait(); | |
1278 | /// println!("result: {:?}", res); | |
1279 | /// } | |
1280 | /// Err(e) => println!("error attempting to wait: {}", e), | |
1281 | /// } | |
1282 | /// ``` | |
cc61c64b | 1283 | #[stable(feature = "process_try_wait", since = "1.18.0")] |
8bb4bdeb XL |
1284 | pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> { |
1285 | Ok(self.handle.try_wait()?.map(ExitStatus)) | |
32a655c1 SL |
1286 | } |
1287 | ||
9346a6ac | 1288 | /// Simultaneously waits for the child to exit and collect all remaining |
92a42be0 | 1289 | /// output on the stdout/stderr handles, returning an `Output` |
85aaf69f SL |
1290 | /// instance. |
1291 | /// | |
1292 | /// The stdin handle to the child process, if any, will be closed | |
1293 | /// before waiting. This helps avoid deadlock: it ensures that the | |
1294 | /// child does not block waiting for input from the parent, while | |
1295 | /// the parent waits for the child to exit. | |
a7813a04 XL |
1296 | /// |
1297 | /// By default, stdin, stdout and stderr are inherited from the parent. | |
1298 | /// In order to capture the output into this `Result<Output>` it is | |
1299 | /// necessary to create new pipes between parent and child. Use | |
1300 | /// `stdout(Stdio::piped())` or `stderr(Stdio::piped())`, respectively. | |
1301 | /// | |
1302 | /// # Examples | |
1303 | /// | |
1304 | /// ```should_panic | |
1305 | /// use std::process::{Command, Stdio}; | |
1306 | /// | |
3157f602 XL |
1307 | /// let child = Command::new("/bin/cat") |
1308 | /// .arg("file.txt") | |
1309 | /// .stdout(Stdio::piped()) | |
1310 | /// .spawn() | |
1311 | /// .expect("failed to execute child"); | |
a7813a04 | 1312 | /// |
3157f602 XL |
1313 | /// let output = child |
1314 | /// .wait_with_output() | |
1315 | /// .expect("failed to wait on child"); | |
a7813a04 | 1316 | /// |
3157f602 | 1317 | /// assert!(output.status.success()); |
a7813a04 XL |
1318 | /// ``` |
1319 | /// | |
c34b1796 | 1320 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
1321 | pub fn wait_with_output(mut self) -> io::Result<Output> { |
1322 | drop(self.stdin.take()); | |
54a0048b SL |
1323 | |
1324 | let (mut stdout, mut stderr) = (Vec::new(), Vec::new()); | |
1325 | match (self.stdout.take(), self.stderr.take()) { | |
1326 | (None, None) => {} | |
1327 | (Some(mut out), None) => { | |
1328 | let res = out.read_to_end(&mut stdout); | |
1329 | res.unwrap(); | |
1330 | } | |
1331 | (None, Some(mut err)) => { | |
1332 | let res = err.read_to_end(&mut stderr); | |
1333 | res.unwrap(); | |
1334 | } | |
1335 | (Some(out), Some(err)) => { | |
1336 | let res = read2(out.inner, &mut stdout, err.inner, &mut stderr); | |
1337 | res.unwrap(); | |
1338 | } | |
85aaf69f | 1339 | } |
85aaf69f | 1340 | |
54a0048b | 1341 | let status = self.wait()?; |
85aaf69f | 1342 | Ok(Output { |
3b2f2976 XL |
1343 | status, |
1344 | stdout, | |
1345 | stderr, | |
85aaf69f SL |
1346 | }) |
1347 | } | |
1348 | } | |
1349 | ||
c34b1796 AL |
1350 | /// Terminates the current process with the specified exit code. |
1351 | /// | |
1352 | /// This function will never return and will immediately terminate the current | |
1353 | /// process. The exit code is passed through to the underlying OS and will be | |
1354 | /// available for consumption by another process. | |
1355 | /// | |
1356 | /// Note that because this function never returns, and that it terminates the | |
1357 | /// process, no destructors on the current stack or any other thread's stack | |
1358 | /// will be run. If a clean shutdown is needed it is recommended to only call | |
1359 | /// this function at a known point where there are no more destructors left | |
1360 | /// to run. | |
476ff2be SL |
1361 | /// |
1362 | /// ## Platform-specific behavior | |
1363 | /// | |
1364 | /// **Unix**: On Unix-like platforms, it is unlikely that all 32 bits of `exit` | |
1365 | /// will be visible to a parent process inspecting the exit code. On most | |
1366 | /// Unix-like platforms, only the eight least-significant bits are considered. | |
1367 | /// | |
1368 | /// # Examples | |
1369 | /// | |
8bb4bdeb XL |
1370 | /// Due to this function’s behavior regarding destructors, a conventional way |
1371 | /// to use the function is to extract the actual computation to another | |
1372 | /// function and compute the exit code from its return value: | |
1373 | /// | |
476ff2be | 1374 | /// ``` |
8bb4bdeb XL |
1375 | /// fn run_app() -> Result<(), ()> { |
1376 | /// // Application logic here | |
1377 | /// Ok(()) | |
1378 | /// } | |
476ff2be | 1379 | /// |
8bb4bdeb XL |
1380 | /// fn main() { |
1381 | /// ::std::process::exit(match run_app() { | |
1382 | /// Ok(_) => 0, | |
1383 | /// Err(err) => { | |
abe05a73 | 1384 | /// eprintln!("error: {:?}", err); |
8bb4bdeb XL |
1385 | /// 1 |
1386 | /// } | |
1387 | /// }); | |
1388 | /// } | |
476ff2be SL |
1389 | /// ``` |
1390 | /// | |
1391 | /// Due to [platform-specific behavior], the exit code for this example will be | |
1392 | /// `0` on Linux, but `256` on Windows: | |
1393 | /// | |
1394 | /// ```no_run | |
1395 | /// use std::process; | |
1396 | /// | |
7cac9316 | 1397 | /// process::exit(0x0100); |
476ff2be SL |
1398 | /// ``` |
1399 | /// | |
1400 | /// [platform-specific behavior]: #platform-specific-behavior | |
c34b1796 AL |
1401 | #[stable(feature = "rust1", since = "1.0.0")] |
1402 | pub fn exit(code: i32) -> ! { | |
e9174d1e | 1403 | ::sys_common::cleanup(); |
c34b1796 AL |
1404 | ::sys::os::exit(code) |
1405 | } | |
1406 | ||
476ff2be SL |
1407 | /// Terminates the process in an abnormal fashion. |
1408 | /// | |
1409 | /// The function will never return and will immediately terminate the current | |
1410 | /// process in a platform specific "abnormal" manner. | |
1411 | /// | |
1412 | /// Note that because this function never returns, and that it terminates the | |
1413 | /// process, no destructors on the current stack or any other thread's stack | |
ea8adc8c XL |
1414 | /// will be run. |
1415 | /// | |
1416 | /// This is in contrast to the default behaviour of [`panic!`] which unwinds | |
1417 | /// the current thread's stack and calls all destructors. | |
1418 | /// When `panic="abort"` is set, either as an argument to `rustc` or in a | |
1419 | /// crate's Cargo.toml, [`panic!`] and `abort` are similar. However, | |
1420 | /// [`panic!`] will still call the [panic hook] while `abort` will not. | |
1421 | /// | |
1422 | /// If a clean shutdown is needed it is recommended to only call | |
476ff2be SL |
1423 | /// this function at a known point where there are no more destructors left |
1424 | /// to run. | |
cc61c64b XL |
1425 | /// |
1426 | /// # Examples | |
1427 | /// | |
1428 | /// ```no_run | |
1429 | /// use std::process; | |
1430 | /// | |
1431 | /// fn main() { | |
1432 | /// println!("aborting"); | |
1433 | /// | |
1434 | /// process::abort(); | |
1435 | /// | |
1436 | /// // execution never gets here | |
1437 | /// } | |
1438 | /// ``` | |
1439 | /// | |
ea8adc8c | 1440 | /// The `abort` function terminates the process, so the destructor will not |
cc61c64b XL |
1441 | /// get run on the example below: |
1442 | /// | |
1443 | /// ```no_run | |
1444 | /// use std::process; | |
1445 | /// | |
1446 | /// struct HasDrop; | |
1447 | /// | |
1448 | /// impl Drop for HasDrop { | |
1449 | /// fn drop(&mut self) { | |
1450 | /// println!("This will never be printed!"); | |
1451 | /// } | |
1452 | /// } | |
1453 | /// | |
1454 | /// fn main() { | |
1455 | /// let _x = HasDrop; | |
1456 | /// process::abort(); | |
1457 | /// // the destructor implemented for HasDrop will never get run | |
1458 | /// } | |
1459 | /// ``` | |
ea8adc8c XL |
1460 | /// |
1461 | /// [`panic!`]: ../../std/macro.panic.html | |
1462 | /// [panic hook]: ../../std/panic/fn.set_hook.html | |
8bb4bdeb | 1463 | #[stable(feature = "process_abort", since = "1.17.0")] |
476ff2be SL |
1464 | pub fn abort() -> ! { |
1465 | unsafe { ::sys::abort_internal() }; | |
1466 | } | |
1467 | ||
abe05a73 XL |
1468 | /// Returns the OS-assigned process identifier associated with this process. |
1469 | /// | |
1470 | /// # Examples | |
1471 | /// | |
1472 | /// Basic usage: | |
1473 | /// | |
1474 | /// ```no_run | |
abe05a73 XL |
1475 | /// use std::process; |
1476 | /// | |
1477 | /// println!("My pid is {}", process::id()); | |
1478 | /// ``` | |
1479 | /// | |
1480 | /// | |
0531ce1d | 1481 | #[stable(feature = "getpid", since = "1.26.0")] |
abe05a73 XL |
1482 | pub fn id() -> u32 { |
1483 | ::sys::os::getpid() | |
1484 | } | |
1485 | ||
0531ce1d XL |
1486 | /// A trait for implementing arbitrary return types in the `main` function. |
1487 | /// | |
1488 | /// The c-main function only supports to return integers as return type. | |
1489 | /// So, every type implementing the `Termination` trait has to be converted | |
1490 | /// to an integer. | |
1491 | /// | |
1492 | /// The default implementations are returning `libc::EXIT_SUCCESS` to indicate | |
1493 | /// a successful execution. In case of a failure, `libc::EXIT_FAILURE` is returned. | |
1494 | #[cfg_attr(not(test), lang = "termination")] | |
1495 | #[unstable(feature = "termination_trait_lib", issue = "43301")] | |
1496 | #[rustc_on_unimplemented( | |
1497 | message="`main` has invalid return type `{Self}`", | |
1498 | label="`main` can only return types that implement `{Termination}`")] | |
1499 | pub trait Termination { | |
1500 | /// Is called to get the representation of the value as status code. | |
1501 | /// This status code is returned to the operating system. | |
1502 | fn report(self) -> i32; | |
1503 | } | |
1504 | ||
1505 | #[unstable(feature = "termination_trait_lib", issue = "43301")] | |
1506 | impl Termination for () { | |
83c7162d | 1507 | #[inline] |
0531ce1d XL |
1508 | fn report(self) -> i32 { ExitCode::SUCCESS.report() } |
1509 | } | |
1510 | ||
1511 | #[unstable(feature = "termination_trait_lib", issue = "43301")] | |
1512 | impl<E: fmt::Debug> Termination for Result<(), E> { | |
1513 | fn report(self) -> i32 { | |
1514 | match self { | |
1515 | Ok(()) => ().report(), | |
1516 | Err(err) => Err::<!, _>(err).report(), | |
1517 | } | |
1518 | } | |
1519 | } | |
1520 | ||
1521 | #[unstable(feature = "termination_trait_lib", issue = "43301")] | |
1522 | impl Termination for ! { | |
1523 | fn report(self) -> i32 { self } | |
1524 | } | |
1525 | ||
1526 | #[unstable(feature = "termination_trait_lib", issue = "43301")] | |
1527 | impl<E: fmt::Debug> Termination for Result<!, E> { | |
1528 | fn report(self) -> i32 { | |
1529 | let Err(err) = self; | |
1530 | eprintln!("Error: {:?}", err); | |
1531 | ExitCode::FAILURE.report() | |
1532 | } | |
1533 | } | |
1534 | ||
1535 | #[unstable(feature = "termination_trait_lib", issue = "43301")] | |
1536 | impl Termination for ExitCode { | |
83c7162d | 1537 | #[inline] |
0531ce1d XL |
1538 | fn report(self) -> i32 { |
1539 | self.0.as_i32() | |
1540 | } | |
1541 | } | |
1542 | ||
2c00a5a8 | 1543 | #[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))] |
85aaf69f | 1544 | mod tests { |
85aaf69f | 1545 | use io::prelude::*; |
c34b1796 AL |
1546 | |
1547 | use io::ErrorKind; | |
85aaf69f | 1548 | use str; |
c34b1796 | 1549 | use super::{Command, Output, Stdio}; |
85aaf69f SL |
1550 | |
1551 | // FIXME(#10380) these tests should not all be ignored on android. | |
1552 | ||
85aaf69f | 1553 | #[test] |
7453a54e | 1554 | #[cfg_attr(target_os = "android", ignore)] |
85aaf69f | 1555 | fn smoke() { |
32a655c1 SL |
1556 | let p = if cfg!(target_os = "windows") { |
1557 | Command::new("cmd").args(&["/C", "exit 0"]).spawn() | |
1558 | } else { | |
1559 | Command::new("true").spawn() | |
1560 | }; | |
85aaf69f SL |
1561 | assert!(p.is_ok()); |
1562 | let mut p = p.unwrap(); | |
1563 | assert!(p.wait().unwrap().success()); | |
1564 | } | |
1565 | ||
85aaf69f | 1566 | #[test] |
7453a54e | 1567 | #[cfg_attr(target_os = "android", ignore)] |
85aaf69f SL |
1568 | fn smoke_failure() { |
1569 | match Command::new("if-this-is-a-binary-then-the-world-has-ended").spawn() { | |
1570 | Ok(..) => panic!(), | |
1571 | Err(..) => {} | |
1572 | } | |
1573 | } | |
1574 | ||
85aaf69f | 1575 | #[test] |
7453a54e | 1576 | #[cfg_attr(target_os = "android", ignore)] |
85aaf69f | 1577 | fn exit_reported_right() { |
32a655c1 SL |
1578 | let p = if cfg!(target_os = "windows") { |
1579 | Command::new("cmd").args(&["/C", "exit 1"]).spawn() | |
1580 | } else { | |
1581 | Command::new("false").spawn() | |
1582 | }; | |
85aaf69f SL |
1583 | assert!(p.is_ok()); |
1584 | let mut p = p.unwrap(); | |
1585 | assert!(p.wait().unwrap().code() == Some(1)); | |
c34b1796 | 1586 | drop(p.wait()); |
85aaf69f SL |
1587 | } |
1588 | ||
85aaf69f | 1589 | #[test] |
7453a54e SL |
1590 | #[cfg(unix)] |
1591 | #[cfg_attr(target_os = "android", ignore)] | |
85aaf69f | 1592 | fn signal_reported_right() { |
c34b1796 | 1593 | use os::unix::process::ExitStatusExt; |
85aaf69f | 1594 | |
b039eaaf SL |
1595 | let mut p = Command::new("/bin/sh") |
1596 | .arg("-c").arg("read a") | |
1597 | .stdin(Stdio::piped()) | |
1598 | .spawn().unwrap(); | |
1599 | p.kill().unwrap(); | |
85aaf69f SL |
1600 | match p.wait().unwrap().signal() { |
1601 | Some(9) => {}, | |
b039eaaf SL |
1602 | result => panic!("not terminated by signal 9 (instead, {:?})", |
1603 | result), | |
85aaf69f SL |
1604 | } |
1605 | } | |
1606 | ||
1607 | pub fn run_output(mut cmd: Command) -> String { | |
1608 | let p = cmd.spawn(); | |
1609 | assert!(p.is_ok()); | |
1610 | let mut p = p.unwrap(); | |
1611 | assert!(p.stdout.is_some()); | |
1612 | let mut ret = String::new(); | |
1613 | p.stdout.as_mut().unwrap().read_to_string(&mut ret).unwrap(); | |
1614 | assert!(p.wait().unwrap().success()); | |
1615 | return ret; | |
1616 | } | |
1617 | ||
85aaf69f | 1618 | #[test] |
7453a54e | 1619 | #[cfg_attr(target_os = "android", ignore)] |
85aaf69f | 1620 | fn stdout_works() { |
32a655c1 SL |
1621 | if cfg!(target_os = "windows") { |
1622 | let mut cmd = Command::new("cmd"); | |
1623 | cmd.args(&["/C", "echo foobar"]).stdout(Stdio::piped()); | |
1624 | assert_eq!(run_output(cmd), "foobar\r\n"); | |
1625 | } else { | |
1626 | let mut cmd = Command::new("echo"); | |
1627 | cmd.arg("foobar").stdout(Stdio::piped()); | |
1628 | assert_eq!(run_output(cmd), "foobar\n"); | |
1629 | } | |
85aaf69f SL |
1630 | } |
1631 | ||
85aaf69f | 1632 | #[test] |
7453a54e | 1633 | #[cfg_attr(any(windows, target_os = "android"), ignore)] |
85aaf69f SL |
1634 | fn set_current_dir_works() { |
1635 | let mut cmd = Command::new("/bin/sh"); | |
1636 | cmd.arg("-c").arg("pwd") | |
1637 | .current_dir("/") | |
c34b1796 | 1638 | .stdout(Stdio::piped()); |
85aaf69f SL |
1639 | assert_eq!(run_output(cmd), "/\n"); |
1640 | } | |
1641 | ||
85aaf69f | 1642 | #[test] |
7453a54e | 1643 | #[cfg_attr(any(windows, target_os = "android"), ignore)] |
85aaf69f SL |
1644 | fn stdin_works() { |
1645 | let mut p = Command::new("/bin/sh") | |
1646 | .arg("-c").arg("read line; echo $line") | |
c34b1796 AL |
1647 | .stdin(Stdio::piped()) |
1648 | .stdout(Stdio::piped()) | |
85aaf69f SL |
1649 | .spawn().unwrap(); |
1650 | p.stdin.as_mut().unwrap().write("foobar".as_bytes()).unwrap(); | |
1651 | drop(p.stdin.take()); | |
1652 | let mut out = String::new(); | |
1653 | p.stdout.as_mut().unwrap().read_to_string(&mut out).unwrap(); | |
1654 | assert!(p.wait().unwrap().success()); | |
1655 | assert_eq!(out, "foobar\n"); | |
1656 | } | |
1657 | ||
1658 | ||
85aaf69f | 1659 | #[test] |
7453a54e SL |
1660 | #[cfg_attr(target_os = "android", ignore)] |
1661 | #[cfg(unix)] | |
85aaf69f | 1662 | fn uid_works() { |
c34b1796 | 1663 | use os::unix::prelude::*; |
85aaf69f SL |
1664 | use libc; |
1665 | let mut p = Command::new("/bin/sh") | |
1666 | .arg("-c").arg("true") | |
1667 | .uid(unsafe { libc::getuid() }) | |
1668 | .gid(unsafe { libc::getgid() }) | |
1669 | .spawn().unwrap(); | |
1670 | assert!(p.wait().unwrap().success()); | |
1671 | } | |
1672 | ||
85aaf69f | 1673 | #[test] |
7453a54e SL |
1674 | #[cfg_attr(target_os = "android", ignore)] |
1675 | #[cfg(unix)] | |
85aaf69f | 1676 | fn uid_to_root_fails() { |
c34b1796 | 1677 | use os::unix::prelude::*; |
85aaf69f SL |
1678 | use libc; |
1679 | ||
1680 | // if we're already root, this isn't a valid test. Most of the bots run | |
1681 | // as non-root though (android is an exception). | |
1682 | if unsafe { libc::getuid() == 0 } { return } | |
1683 | assert!(Command::new("/bin/ls").uid(0).gid(0).spawn().is_err()); | |
1684 | } | |
1685 | ||
85aaf69f | 1686 | #[test] |
7453a54e | 1687 | #[cfg_attr(target_os = "android", ignore)] |
85aaf69f | 1688 | fn test_process_status() { |
32a655c1 SL |
1689 | let mut status = if cfg!(target_os = "windows") { |
1690 | Command::new("cmd").args(&["/C", "exit 1"]).status().unwrap() | |
1691 | } else { | |
1692 | Command::new("false").status().unwrap() | |
1693 | }; | |
85aaf69f SL |
1694 | assert!(status.code() == Some(1)); |
1695 | ||
32a655c1 SL |
1696 | status = if cfg!(target_os = "windows") { |
1697 | Command::new("cmd").args(&["/C", "exit 0"]).status().unwrap() | |
1698 | } else { | |
1699 | Command::new("true").status().unwrap() | |
1700 | }; | |
85aaf69f SL |
1701 | assert!(status.success()); |
1702 | } | |
1703 | ||
1704 | #[test] | |
1705 | fn test_process_output_fail_to_start() { | |
1706 | match Command::new("/no-binary-by-this-name-should-exist").output() { | |
c34b1796 | 1707 | Err(e) => assert_eq!(e.kind(), ErrorKind::NotFound), |
85aaf69f SL |
1708 | Ok(..) => panic!() |
1709 | } | |
1710 | } | |
1711 | ||
85aaf69f | 1712 | #[test] |
7453a54e | 1713 | #[cfg_attr(target_os = "android", ignore)] |
85aaf69f SL |
1714 | fn test_process_output_output() { |
1715 | let Output {status, stdout, stderr} | |
32a655c1 SL |
1716 | = if cfg!(target_os = "windows") { |
1717 | Command::new("cmd").args(&["/C", "echo hello"]).output().unwrap() | |
1718 | } else { | |
1719 | Command::new("echo").arg("hello").output().unwrap() | |
1720 | }; | |
c34b1796 | 1721 | let output_str = str::from_utf8(&stdout).unwrap(); |
85aaf69f SL |
1722 | |
1723 | assert!(status.success()); | |
1724 | assert_eq!(output_str.trim().to_string(), "hello"); | |
c1a9b12d | 1725 | assert_eq!(stderr, Vec::new()); |
85aaf69f SL |
1726 | } |
1727 | ||
85aaf69f | 1728 | #[test] |
7453a54e | 1729 | #[cfg_attr(target_os = "android", ignore)] |
85aaf69f SL |
1730 | fn test_process_output_error() { |
1731 | let Output {status, stdout, stderr} | |
32a655c1 SL |
1732 | = if cfg!(target_os = "windows") { |
1733 | Command::new("cmd").args(&["/C", "mkdir ."]).output().unwrap() | |
1734 | } else { | |
ff7c6d11 | 1735 | Command::new("mkdir").arg("./").output().unwrap() |
32a655c1 | 1736 | }; |
85aaf69f SL |
1737 | |
1738 | assert!(status.code() == Some(1)); | |
1739 | assert_eq!(stdout, Vec::new()); | |
1740 | assert!(!stderr.is_empty()); | |
1741 | } | |
1742 | ||
85aaf69f | 1743 | #[test] |
7453a54e | 1744 | #[cfg_attr(target_os = "android", ignore)] |
85aaf69f | 1745 | fn test_finish_once() { |
32a655c1 SL |
1746 | let mut prog = if cfg!(target_os = "windows") { |
1747 | Command::new("cmd").args(&["/C", "exit 1"]).spawn().unwrap() | |
1748 | } else { | |
1749 | Command::new("false").spawn().unwrap() | |
1750 | }; | |
85aaf69f SL |
1751 | assert!(prog.wait().unwrap().code() == Some(1)); |
1752 | } | |
1753 | ||
85aaf69f | 1754 | #[test] |
7453a54e | 1755 | #[cfg_attr(target_os = "android", ignore)] |
85aaf69f | 1756 | fn test_finish_twice() { |
32a655c1 SL |
1757 | let mut prog = if cfg!(target_os = "windows") { |
1758 | Command::new("cmd").args(&["/C", "exit 1"]).spawn().unwrap() | |
1759 | } else { | |
1760 | Command::new("false").spawn().unwrap() | |
1761 | }; | |
85aaf69f SL |
1762 | assert!(prog.wait().unwrap().code() == Some(1)); |
1763 | assert!(prog.wait().unwrap().code() == Some(1)); | |
1764 | } | |
1765 | ||
85aaf69f | 1766 | #[test] |
7453a54e | 1767 | #[cfg_attr(target_os = "android", ignore)] |
85aaf69f | 1768 | fn test_wait_with_output_once() { |
32a655c1 SL |
1769 | let prog = if cfg!(target_os = "windows") { |
1770 | Command::new("cmd").args(&["/C", "echo hello"]).stdout(Stdio::piped()).spawn().unwrap() | |
1771 | } else { | |
1772 | Command::new("echo").arg("hello").stdout(Stdio::piped()).spawn().unwrap() | |
1773 | }; | |
1774 | ||
85aaf69f | 1775 | let Output {status, stdout, stderr} = prog.wait_with_output().unwrap(); |
c34b1796 | 1776 | let output_str = str::from_utf8(&stdout).unwrap(); |
85aaf69f SL |
1777 | |
1778 | assert!(status.success()); | |
1779 | assert_eq!(output_str.trim().to_string(), "hello"); | |
c1a9b12d | 1780 | assert_eq!(stderr, Vec::new()); |
85aaf69f SL |
1781 | } |
1782 | ||
85aaf69f SL |
1783 | #[cfg(all(unix, not(target_os="android")))] |
1784 | pub fn env_cmd() -> Command { | |
1785 | Command::new("env") | |
1786 | } | |
1787 | #[cfg(target_os="android")] | |
1788 | pub fn env_cmd() -> Command { | |
1789 | let mut cmd = Command::new("/system/bin/sh"); | |
1790 | cmd.arg("-c").arg("set"); | |
1791 | cmd | |
1792 | } | |
1793 | ||
1794 | #[cfg(windows)] | |
1795 | pub fn env_cmd() -> Command { | |
1796 | let mut cmd = Command::new("cmd"); | |
1797 | cmd.arg("/c").arg("set"); | |
1798 | cmd | |
1799 | } | |
1800 | ||
85aaf69f SL |
1801 | #[test] |
1802 | fn test_inherit_env() { | |
c1a9b12d | 1803 | use env; |
85aaf69f SL |
1804 | |
1805 | let result = env_cmd().output().unwrap(); | |
1806 | let output = String::from_utf8(result.stdout).unwrap(); | |
1807 | ||
c34b1796 | 1808 | for (ref k, ref v) in env::vars() { |
3b2f2976 XL |
1809 | // Don't check android RANDOM variable which seems to change |
1810 | // whenever the shell runs, and our `env_cmd` is indeed running a | |
1811 | // shell which means it'll get a different RANDOM than we probably | |
1812 | // have. | |
1813 | // | |
1814 | // Also skip env vars with `-` in the name on android because, well, | |
1815 | // I'm not sure. It appears though that the `set` command above does | |
1816 | // not print env vars with `-` in the name, so we just skip them | |
1817 | // here as we won't find them in the output. Note that most env vars | |
1818 | // use `_` instead of `-`, but our build system sets a few env vars | |
1819 | // with `-` in the name. | |
1820 | if cfg!(target_os = "android") && | |
1821 | (*k == "RANDOM" || k.contains("-")) { | |
7453a54e SL |
1822 | continue |
1823 | } | |
1824 | ||
92a42be0 SL |
1825 | // Windows has hidden environment variables whose names start with |
1826 | // equals signs (`=`). Those do not show up in the output of the | |
1827 | // `set` command. | |
1828 | assert!((cfg!(windows) && k.starts_with("=")) || | |
1829 | k.starts_with("DYLD") || | |
7453a54e SL |
1830 | output.contains(&format!("{}={}", *k, *v)) || |
1831 | output.contains(&format!("{}='{}'", *k, *v)), | |
85aaf69f SL |
1832 | "output doesn't contain `{}={}`\n{}", |
1833 | k, v, output); | |
1834 | } | |
1835 | } | |
85aaf69f SL |
1836 | |
1837 | #[test] | |
1838 | fn test_override_env() { | |
1839 | use env; | |
1840 | ||
1841 | // In some build environments (such as chrooted Nix builds), `env` can | |
1842 | // only be found in the explicitly-provided PATH env variable, not in | |
1843 | // default places such as /bin or /usr/bin. So we need to pass through | |
1844 | // PATH to our sub-process. | |
1845 | let mut cmd = env_cmd(); | |
1846 | cmd.env_clear().env("RUN_TEST_NEW_ENV", "123"); | |
1847 | if let Some(p) = env::var_os("PATH") { | |
1848 | cmd.env("PATH", &p); | |
1849 | } | |
1850 | let result = cmd.output().unwrap(); | |
c34b1796 | 1851 | let output = String::from_utf8_lossy(&result.stdout).to_string(); |
85aaf69f SL |
1852 | |
1853 | assert!(output.contains("RUN_TEST_NEW_ENV=123"), | |
1854 | "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output); | |
1855 | } | |
1856 | ||
1857 | #[test] | |
1858 | fn test_add_to_env() { | |
1859 | let result = env_cmd().env("RUN_TEST_NEW_ENV", "123").output().unwrap(); | |
c34b1796 | 1860 | let output = String::from_utf8_lossy(&result.stdout).to_string(); |
85aaf69f SL |
1861 | |
1862 | assert!(output.contains("RUN_TEST_NEW_ENV=123"), | |
1863 | "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output); | |
1864 | } | |
7453a54e | 1865 | |
ff7c6d11 XL |
1866 | #[test] |
1867 | fn test_capture_env_at_spawn() { | |
1868 | use env; | |
1869 | ||
1870 | let mut cmd = env_cmd(); | |
1871 | cmd.env("RUN_TEST_NEW_ENV1", "123"); | |
1872 | ||
1873 | // This variable will not be present if the environment has already | |
1874 | // been captured above. | |
1875 | env::set_var("RUN_TEST_NEW_ENV2", "456"); | |
1876 | let result = cmd.output().unwrap(); | |
1877 | env::remove_var("RUN_TEST_NEW_ENV2"); | |
1878 | ||
1879 | let output = String::from_utf8_lossy(&result.stdout).to_string(); | |
1880 | ||
1881 | assert!(output.contains("RUN_TEST_NEW_ENV1=123"), | |
1882 | "didn't find RUN_TEST_NEW_ENV1 inside of:\n\n{}", output); | |
1883 | assert!(output.contains("RUN_TEST_NEW_ENV2=456"), | |
1884 | "didn't find RUN_TEST_NEW_ENV2 inside of:\n\n{}", output); | |
1885 | } | |
1886 | ||
7453a54e SL |
1887 | // Regression tests for #30858. |
1888 | #[test] | |
1889 | fn test_interior_nul_in_progname_is_error() { | |
1890 | match Command::new("has-some-\0\0s-inside").spawn() { | |
1891 | Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), | |
1892 | Ok(_) => panic!(), | |
1893 | } | |
1894 | } | |
1895 | ||
1896 | #[test] | |
1897 | fn test_interior_nul_in_arg_is_error() { | |
1898 | match Command::new("echo").arg("has-some-\0\0s-inside").spawn() { | |
1899 | Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), | |
1900 | Ok(_) => panic!(), | |
1901 | } | |
1902 | } | |
1903 | ||
1904 | #[test] | |
1905 | fn test_interior_nul_in_args_is_error() { | |
1906 | match Command::new("echo").args(&["has-some-\0\0s-inside"]).spawn() { | |
1907 | Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), | |
1908 | Ok(_) => panic!(), | |
1909 | } | |
1910 | } | |
1911 | ||
1912 | #[test] | |
1913 | fn test_interior_nul_in_current_dir_is_error() { | |
1914 | match Command::new("echo").current_dir("has-some-\0\0s-inside").spawn() { | |
1915 | Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), | |
1916 | Ok(_) => panic!(), | |
1917 | } | |
1918 | } | |
1919 | ||
1920 | // Regression tests for #30862. | |
1921 | #[test] | |
1922 | fn test_interior_nul_in_env_key_is_error() { | |
1923 | match env_cmd().env("has-some-\0\0s-inside", "value").spawn() { | |
1924 | Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), | |
1925 | Ok(_) => panic!(), | |
1926 | } | |
1927 | } | |
1928 | ||
1929 | #[test] | |
1930 | fn test_interior_nul_in_env_value_is_error() { | |
1931 | match env_cmd().env("key", "has-some-\0\0s-inside").spawn() { | |
1932 | Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), | |
1933 | Ok(_) => panic!(), | |
1934 | } | |
1935 | } | |
476ff2be SL |
1936 | |
1937 | /// Test that process creation flags work by debugging a process. | |
1938 | /// Other creation flags make it hard or impossible to detect | |
1939 | /// behavioral changes in the process. | |
1940 | #[test] | |
1941 | #[cfg(windows)] | |
1942 | fn test_creation_flags() { | |
1943 | use os::windows::process::CommandExt; | |
1944 | use sys::c::{BOOL, DWORD, INFINITE}; | |
1945 | #[repr(C, packed)] | |
1946 | struct DEBUG_EVENT { | |
1947 | pub event_code: DWORD, | |
1948 | pub process_id: DWORD, | |
1949 | pub thread_id: DWORD, | |
1950 | // This is a union in the real struct, but we don't | |
1951 | // need this data for the purposes of this test. | |
1952 | pub _junk: [u8; 164], | |
1953 | } | |
1954 | ||
1955 | extern "system" { | |
1956 | fn WaitForDebugEvent(lpDebugEvent: *mut DEBUG_EVENT, dwMilliseconds: DWORD) -> BOOL; | |
1957 | fn ContinueDebugEvent(dwProcessId: DWORD, dwThreadId: DWORD, | |
1958 | dwContinueStatus: DWORD) -> BOOL; | |
1959 | } | |
1960 | ||
1961 | const DEBUG_PROCESS: DWORD = 1; | |
1962 | const EXIT_PROCESS_DEBUG_EVENT: DWORD = 5; | |
1963 | const DBG_EXCEPTION_NOT_HANDLED: DWORD = 0x80010001; | |
1964 | ||
1965 | let mut child = Command::new("cmd") | |
1966 | .creation_flags(DEBUG_PROCESS) | |
1967 | .stdin(Stdio::piped()).spawn().unwrap(); | |
1968 | child.stdin.take().unwrap().write_all(b"exit\r\n").unwrap(); | |
1969 | let mut events = 0; | |
1970 | let mut event = DEBUG_EVENT { | |
1971 | event_code: 0, | |
1972 | process_id: 0, | |
1973 | thread_id: 0, | |
1974 | _junk: [0; 164], | |
1975 | }; | |
1976 | loop { | |
1977 | if unsafe { WaitForDebugEvent(&mut event as *mut DEBUG_EVENT, INFINITE) } == 0 { | |
1978 | panic!("WaitForDebugEvent failed!"); | |
1979 | } | |
1980 | events += 1; | |
1981 | ||
1982 | if event.event_code == EXIT_PROCESS_DEBUG_EVENT { | |
1983 | break; | |
1984 | } | |
1985 | ||
1986 | if unsafe { ContinueDebugEvent(event.process_id, | |
1987 | event.thread_id, | |
1988 | DBG_EXCEPTION_NOT_HANDLED) } == 0 { | |
1989 | panic!("ContinueDebugEvent failed!"); | |
1990 | } | |
1991 | } | |
1992 | assert!(events > 0); | |
1993 | } | |
2c00a5a8 XL |
1994 | |
1995 | #[test] | |
1996 | fn test_command_implements_send() { | |
1997 | fn take_send_type<T: Send>(_: T) {} | |
1998 | take_send_type(Command::new("")) | |
1999 | } | |
85aaf69f | 2000 | } |