1 use std::cell::RefCell;
2 use std::env;
3 use std::error::Error;
4 use std::ffi::{OsStr, OsString};
5 use std::fmt;
6 use std::fs::File;
7 use std::io;
8 use std::rc::Rc;
9 use std::result;
10 use std::time::Duration;
11
12 use crate::communicate;
13 use crate::os_common::{ExitStatus, StandardStream};
14
15 use self::ChildState::*;
16
17 pub use self::os::ext as os_ext;
18 pub use self::os::make_pipe;
19 pub use communicate::Communicator;
20
21 /// Interface to a running subprocess.
22 ///
23 /// `Popen` is the parent's interface to a created subprocess. The
24 /// child process is started in the constructor, so owning a `Popen`
25 /// value indicates that the specified program has been successfully
26 /// launched. To prevent accumulation of zombie processes, the child
27 /// is waited upon when a `Popen` goes out of scope, which can be
28 /// prevented using the [`detach`] method.
29 ///
30 /// Depending on how the subprocess was configured, its input, output, and
31 /// error streams can be connected to the parent and available as [`stdin`],
32 /// [`stdout`], and [`stderr`] public fields. If you need to read the output
33 /// and errors into memory (or provide input as a memory slice), use the
34 /// [`communicate`] family of methods.
35 ///
36 /// `Popen` instances can be obtained with the [`create`] method, or
37 /// using the [`popen`] method of the [`Exec`] type. Subprocesses
38 /// can be connected into pipes, most easily achieved using using
39 /// [`Exec`].
40 ///
41 /// [`Exec`]: struct.Exec.html
42 /// [`popen`]: struct.Exec.html#method.popen
43 /// [`stdin`]: struct.Popen.html#structfield.stdin
44 /// [`stdout`]: struct.Popen.html#structfield.stdout
45 /// [`stderr`]: struct.Popen.html#structfield.stderr
46 /// [`create`]: struct.Popen.html#method.create
47 /// [`communicate`]: struct.Popen.html#method.communicate
48 /// [`detach`]: struct.Popen.html#method.detach
49
50 #[derive(Debug)]
51 pub struct Popen {
52 /// If `stdin` was specified as `Redirection::Pipe`, this will
53 /// contain a writeble `File` connected to the standard input of
54 /// the child process.
55 pub stdin: Option<File>,
56
57 /// If `stdout` was specified as `Redirection::Pipe`, this will
58 /// contain a readable `File` connected to the standard output of
59 /// the child process.
60 pub stdout: Option<File>,
61
62 /// If `stderr` was specified as `Redirection::Pipe`, this will
63 /// contain a readable `File` connected to the standard error of
64 /// the child process.
65 pub stderr: Option<File>,
66
67 child_state: ChildState,
68 detached: bool,
69 }
70
71 #[derive(Debug)]
72 enum ChildState {
73 Preparing, // only during construction
74 Running { pid: u32, ext: os::ExtChildState },
75 Finished(ExitStatus),
76 }
77
78 /// Options for [`Popen::create`].
79 ///
80 /// When constructing `PopenConfig`, always use the [`Default`] trait,
81 /// such as:
82 ///
83 /// ```
84 /// # use subprocess::*;
85 /// # let argv = &["true"];
86 /// Popen::create(argv, PopenConfig {
87 /// stdout: Redirection::Pipe,
88 /// detached: true,
89 /// // ... other fields you want to override ...
90 /// ..Default::default()
91 /// })
92 /// # .unwrap();
93 /// ```
94 ///
95 /// This ensures that fields added later do not break existing code.
96 ///
97 /// An alternative to using `PopenConfig` directly is creating
98 /// processes using [`Exec`], a builder for `Popen`.
99 ///
100 /// [`Popen::create`]: struct.Popen.html#method.create
101 /// [`Exec`]: struct.Exec.html
102 /// [`Default`]: https://doc.rust-lang.org/core/default/trait.Default.html
103
104 #[derive(Debug)]
105 pub struct PopenConfig {
106 /// How to configure the executed program's standard input.
107 pub stdin: Redirection,
108 /// How to configure the executed program's standard output.
109 pub stdout: Redirection,
110 /// How to configure the executed program's standard error.
111 pub stderr: Redirection,
112 /// Whether the `Popen` instance is initially detached.
113 pub detached: bool,
114
115 /// Executable to run.
116 ///
117 /// If provided, this executable will be used to run the program
118 /// instead of `argv[0]`. However, `argv[0]` will still be passed
119 /// to the subprocess, which will see that as `argv[0]`. On some
120 /// Unix systems, `ps` will show the string passed as `argv[0]`,
121 /// even though `executable` is actually running.
122 pub executable: Option<OsString>,
123
124 /// Environment variables to pass to the subprocess.
125 ///
126 /// If this is None, environment variables are inherited from the calling
127 /// process. Otherwise, the specified variables are used instead.
128 ///
129 /// Duplicates are eliminated, with the value taken from the
130 /// variable appearing later in the vector.
131 pub env: Option<Vec<(OsString, OsString)>>,
132
133 /// Initial current working directory of the subprocess.
134 ///
135 /// None means inherit the working directory from the parent.
136 pub cwd: Option<OsString>,
137
138 /// Set user ID for the subprocess.
139 ///
140 /// If specified, calls `setuid()` before execing the child process.
141 #[cfg(unix)]
142 pub setuid: Option<u32>,
143
144 /// Set group ID for the subprocess.
145 ///
146 /// If specified, calls `setgid()` before execing the child process.
147 ///
148 /// Not to be confused with similarly named `setpgid`.
149 #[cfg(unix)]
150 pub setgid: Option<u32>,
151
152 /// Make the subprocess belong to a new process group.
153 ///
154 /// If specified, calls `setpgid(0, 0)` before execing the child process.
155 ///
156 /// Not to be confused with similarly named `setgid`.
157 #[cfg(unix)]
158 pub setpgid: bool,
159
160 // Add this field to force construction using ..Default::default() for
161 // backward compatibility. Unfortunately we can't mark this non-public
162 // because then ..Default::default() wouldn't work either.
163 #[doc(hidden)]
164 pub _use_default_to_construct: (),
165 }
166
167 impl PopenConfig {
168 /// Clone the underlying [`PopenConfig`], or return an error.
169 ///
170 /// This is guaranteed not to fail as long as no
171 /// [`Redirection::File`] variant is used for one of the standard
172 /// streams. Otherwise, it fails if `File::try_clone` fails on
173 /// one of the `Redirection`s.
174 ///
175 /// [`PopenConfig`]: struct.PopenConfig.html
176 /// [`Redirection::File`]: enum.Redirection.html#variant.File
try_clone(&self) -> io::Result<PopenConfig>177 pub fn try_clone(&self) -> io::Result<PopenConfig> {
178 Ok(PopenConfig {
179 stdin: self.stdin.try_clone()?,
180 stdout: self.stdout.try_clone()?,
181 stderr: self.stderr.try_clone()?,
182 detached: self.detached,
183 executable: self.executable.as_ref().cloned(),
184 env: self.env.clone(),
185 cwd: self.cwd.clone(),
186 #[cfg(unix)]
187 setuid: self.setuid,
188 #[cfg(unix)]
189 setgid: self.setgid,
190 #[cfg(unix)]
191 setpgid: self.setpgid,
192 _use_default_to_construct: (),
193 })
194 }
195
196 /// Returns the environment of the current process.
197 ///
198 /// The returned value is in the format accepted by the `env`
199 /// member of `PopenConfig`.
current_env() -> Vec<(OsString, OsString)>200 pub fn current_env() -> Vec<(OsString, OsString)> {
201 env::vars_os().collect()
202 }
203 }
204
205 impl Default for PopenConfig {
default() -> PopenConfig206 fn default() -> PopenConfig {
207 PopenConfig {
208 stdin: Redirection::None,
209 stdout: Redirection::None,
210 stderr: Redirection::None,
211 detached: false,
212 executable: None,
213 env: None,
214 cwd: None,
215 #[cfg(unix)]
216 setuid: None,
217 #[cfg(unix)]
218 setgid: None,
219 #[cfg(unix)]
220 setpgid: false,
221 _use_default_to_construct: (),
222 }
223 }
224 }
225
226 /// Instruction what to do with a stream in the child process.
227 ///
228 /// `Redirection` values are used for the `stdin`, `stdout`, and
229 /// `stderr` field of the `PopenConfig` struct. They tell
230 /// `Popen::create` how to set up the standard streams in the child
231 /// process and the corresponding fields of the `Popen` struct in the
232 /// parent.
233
234 #[derive(Debug)]
235 pub enum Redirection {
236 /// Do nothing with the stream.
237 ///
238 /// The stream is typically inherited from the parent. The field
239 /// in `Popen` corresponding to the stream will be `None`.
240 None,
241
242 /// Redirect the stream to a pipe.
243 ///
244 /// This variant requests that a stream be redirected to a
245 /// unidirectional pipe. One end of the pipe is passed to the
246 /// child process and configured as one of its standard streams,
247 /// and the other end is available to the parent for communicating
248 /// with the child.
249 ///
250 /// The field with `Popen` corresponding to the stream will be
251 /// `Some(file)`, `File` being the parent's end of the pipe.
252 Pipe,
253
254 /// Merge the stream to the other output stream.
255 ///
256 /// This variant is only valid when configuring redirection of
257 /// standard output and standard error. Using
258 /// `Redirection::Merge` for `PopenConfig::stderr` requests the
259 /// child's stderr to refer to the same underlying file as the
260 /// child's stdout (which may or may not itself be redirected),
261 /// equivalent to the `2>&1` operator of the Bourne shell.
262 /// Analogously, using `Redirection::Merge` for
263 /// `PopenConfig::stdout` is equivalent to `1>&2` in the shell.
264 ///
265 /// Specifying `Redirection::Merge` for `PopenConfig::stdin` or
266 /// specifying it for both `stdout` and `stderr` is invalid and
267 /// will cause `Popen::create` to return
268 /// `Err(PopenError::LogicError)`.
269 ///
270 /// The field in `Popen` corresponding to the stream will be
271 /// `None`.
272 Merge,
273
274 /// Redirect the stream to the specified open `File`.
275 ///
276 /// This does not create a pipe, it simply spawns the child so
277 /// that the specified stream sees that file. The child can read
278 /// from or write to the provided file on its own, without any
279 /// intervention by the parent.
280 ///
281 /// The field in `Popen` corresponding to the stream will be
282 /// `None`.
283 File(File),
284
285 /// Like `File`, but the file is specified as `Rc`.
286 ///
287 /// This allows the same file to be used in multiple redirections.
288 RcFile(Rc<File>),
289 }
290
291 impl Redirection {
292 /// Clone the underlying `Redirection`, or return an error.
293 ///
294 /// Can fail in `File` variant.
try_clone(&self) -> io::Result<Redirection>295 pub fn try_clone(&self) -> io::Result<Redirection> {
296 Ok(match *self {
297 Redirection::None => Redirection::None,
298 Redirection::Pipe => Redirection::Pipe,
299 Redirection::Merge => Redirection::Merge,
300 Redirection::File(ref f) => Redirection::File(f.try_clone()?),
301 Redirection::RcFile(ref f) => Redirection::RcFile(Rc::clone(&f)),
302 })
303 }
304 }
305
306 impl Popen {
307 /// Execute an external program in a new process.
308 ///
309 /// `argv` is a slice containing the program followed by its
310 /// arguments, such as `&["ps", "x"]`. `config` specifies details
311 /// how to create and interface to the process.
312 ///
313 /// For example, this launches the `cargo update` command:
314 ///
315 /// ```no_run
316 /// # use subprocess::*;
317 /// # fn dummy() -> Result<()> {
318 /// Popen::create(&["cargo", "update"], PopenConfig::default())?;
319 /// # Ok(())
320 /// # }
321 /// ```
322 ///
323 /// # Errors
324 ///
325 /// If the external program cannot be executed for any reason, an
326 /// error is returned. The most typical reason for execution to
327 /// fail is that the program is missing on the `PATH`, but other
328 /// errors are also possible. Note that this is distinct from the
329 /// program running and then exiting with a failure code - this
330 /// can be detected by calling the `wait` method to obtain its
331 /// exit status.
create(argv: &[impl AsRef<OsStr>], config: PopenConfig) -> Result<Popen>332 pub fn create(argv: &[impl AsRef<OsStr>], config: PopenConfig) -> Result<Popen> {
333 if argv.is_empty() {
334 return Err(PopenError::LogicError("argv must not be empty"));
335 }
336 let argv: Vec<OsString> = argv.iter().map(|p| p.as_ref().to_owned()).collect();
337 let mut inst = Popen {
338 stdin: None,
339 stdout: None,
340 stderr: None,
341 child_state: ChildState::Preparing,
342 detached: config.detached,
343 };
344 inst.os_start(argv, config)?;
345 Ok(inst)
346 }
347
348 // Create the pipes requested by stdin, stdout, and stderr from
349 // the PopenConfig used to construct us, and return the Files to
350 // be given to the child process.
351 //
352 // For Redirection::Pipe, this stores the parent end of the pipe
353 // to the appropriate self.std* field, and returns the child end
354 // of the pipe.
355 //
356 // For Redirection::File, this transfers the ownership of the File
357 // to the corresponding child.
setup_streams( &mut self, stdin: Redirection, stdout: Redirection, stderr: Redirection, ) -> Result<(Option<Rc<File>>, Option<Rc<File>>, Option<Rc<File>>)>358 fn setup_streams(
359 &mut self,
360 stdin: Redirection,
361 stdout: Redirection,
362 stderr: Redirection,
363 ) -> Result<(Option<Rc<File>>, Option<Rc<File>>, Option<Rc<File>>)> {
364 fn prepare_pipe(
365 parent_writes: bool,
366 parent_ref: &mut Option<File>,
367 child_ref: &mut Option<Rc<File>>,
368 ) -> Result<()> {
369 // Store the parent's end of the pipe into the given
370 // reference, and store the child end.
371 let (read, write) = os::make_pipe()?;
372 let (parent_end, child_end) = if parent_writes {
373 (write, read)
374 } else {
375 (read, write)
376 };
377 os::set_inheritable(&parent_end, false)?;
378 *parent_ref = Some(parent_end);
379 *child_ref = Some(Rc::new(child_end));
380 Ok(())
381 }
382 fn prepare_file(file: File, child_ref: &mut Option<Rc<File>>) -> io::Result<()> {
383 // Make the File inheritable and store it for use in the child.
384 os::set_inheritable(&file, true)?;
385 *child_ref = Some(Rc::new(file));
386 Ok(())
387 }
388 fn prepare_rc_file(file: Rc<File>, child_ref: &mut Option<Rc<File>>) -> io::Result<()> {
389 // Like prepare_file, but for Rc<File>
390 os::set_inheritable(&file, true)?;
391 *child_ref = Some(file);
392 Ok(())
393 }
394 fn reuse_stream(
395 dest: &mut Option<Rc<File>>,
396 src: &mut Option<Rc<File>>,
397 src_id: StandardStream,
398 ) -> io::Result<()> {
399 // For Redirection::Merge, make stdout and stderr refer to
400 // the same File. If the file is unavailable, use the
401 // appropriate system output stream.
402 if src.is_none() {
403 *src = Some(get_standard_stream(src_id)?);
404 }
405 *dest = Some(Rc::clone(src.as_ref().unwrap()));
406 Ok(())
407 }
408
409 enum MergeKind {
410 ErrToOut, // 2>&1
411 OutToErr, // 1>&2
412 None,
413 }
414 let mut merge: MergeKind = MergeKind::None;
415
416 let (mut child_stdin, mut child_stdout, mut child_stderr) = (None, None, None);
417
418 match stdin {
419 Redirection::Pipe => prepare_pipe(true, &mut self.stdin, &mut child_stdin)?,
420 Redirection::File(file) => prepare_file(file, &mut child_stdin)?,
421 Redirection::RcFile(file) => prepare_rc_file(file, &mut child_stdin)?,
422 Redirection::Merge => {
423 return Err(PopenError::LogicError(
424 "Redirection::Merge not valid for stdin",
425 ));
426 }
427 Redirection::None => (),
428 };
429 match stdout {
430 Redirection::Pipe => prepare_pipe(false, &mut self.stdout, &mut child_stdout)?,
431 Redirection::File(file) => prepare_file(file, &mut child_stdout)?,
432 Redirection::RcFile(file) => prepare_rc_file(file, &mut child_stdout)?,
433 Redirection::Merge => merge = MergeKind::OutToErr,
434 Redirection::None => (),
435 };
436 match stderr {
437 Redirection::Pipe => prepare_pipe(false, &mut self.stderr, &mut child_stderr)?,
438 Redirection::File(file) => prepare_file(file, &mut child_stderr)?,
439 Redirection::RcFile(file) => prepare_rc_file(file, &mut child_stderr)?,
440 Redirection::Merge => merge = MergeKind::ErrToOut,
441 Redirection::None => (),
442 };
443
444 // Handle Redirection::Merge after creating the output child
445 // streams. Merge by cloning the child stream, or the
446 // appropriate standard stream if we don't have a child stream
447 // requested using Redirection::Pipe or Redirection::File. In
448 // other words, 2>&1 (ErrToOut) is implemented by making
449 // child_stderr point to a dup of child_stdout, or of the OS's
450 // stdout stream.
451 match merge {
452 MergeKind::ErrToOut => {
453 reuse_stream(&mut child_stderr, &mut child_stdout, StandardStream::Output)?
454 }
455 MergeKind::OutToErr => {
456 reuse_stream(&mut child_stdout, &mut child_stderr, StandardStream::Error)?
457 }
458 MergeKind::None => (),
459 }
460
461 Ok((child_stdin, child_stdout, child_stderr))
462 }
463
464 /// Mark the process as detached.
465 ///
466 /// This method has no effect on the OS level, it simply tells
467 /// `Popen` not to wait for the subprocess to finish when going
468 /// out of scope. If the child process has already finished, or
469 /// if it is guaranteed to finish before `Popen` goes out of
470 /// scope, calling `detach` has no effect.
detach(&mut self)471 pub fn detach(&mut self) {
472 self.detached = true;
473 }
474
475 /// Return the PID of the subprocess, if it is known to be still running.
476 ///
477 /// Note that this method won't actually *check* whether the child
478 /// process is still running, it will only return the information
479 /// last set using one of `create`, `wait`, `wait_timeout`, or
480 /// `poll`. For a newly created `Popen`, `pid()` always returns
481 /// `Some`.
pid(&self) -> Option<u32>482 pub fn pid(&self) -> Option<u32> {
483 match self.child_state {
484 Running { pid, .. } => Some(pid),
485 _ => None,
486 }
487 }
488
489 /// Return the exit status of the subprocess, if it is known to have finished.
490 ///
491 /// Note that this method won't actually *check* whether the child
492 /// process has finished, it only returns the previously available
493 /// information. To check or wait for the process to finish, call
494 /// `wait`, `wait_timeout`, or `poll`.
exit_status(&self) -> Option<ExitStatus>495 pub fn exit_status(&self) -> Option<ExitStatus> {
496 match self.child_state {
497 Finished(exit_status) => Some(exit_status),
498 _ => None,
499 }
500 }
501
502 /// Prepare to communicate with the subprocess.
503 ///
504 /// Communicating refers to unattended data exchange with the subprocess.
505 /// During communication the given `input_data` is written to the
506 /// subprocess's standard input which is then closed, while simultaneously
507 /// its standard output and error streams are read until end-of-file is
508 /// reached.
509 ///
510 /// The difference between this and simply writing input data to
511 /// `self.stdin` and then reading output from `self.stdout` and
512 /// `self.stderr` is that the reading and the writing are performed
513 /// simultaneously. A naive implementation that writes and then reads has
514 /// an issue when the subprocess responds to part of the input by
515 /// providing output. The output must be read for the subprocess to
516 /// accept further input, but the parent process is still blocked on
517 /// writing the rest of the input daata. Since neither process can
518 /// proceed, a deadlock occurs. This is why a correct implementation must
519 /// write and read at the same time.
520 ///
521 /// This method does not perform the actual communication, it just sets it
522 /// up and returns a [`Communicator`]. Call the [`read`] or
523 /// [`read_string`] method on the `Communicator` to exchange data with the
524 /// subprocess.
525 ///
526 /// Compared to `communicate()` and `communicate_bytes()`, the
527 /// `Communicator` provides more control, such as timeout, read size
528 /// limit, and the ability to retrieve captured output in case of read
529 /// error.
530 ///
531 /// [`Communicator`]: struct.Communicator.html
532 /// [`read`]: struct.Communicator.html#method.read
533 /// [`read_string`]: struct.Communicator.html#method.read_string
communicate_start(&mut self, input_data: Option<Vec<u8>>) -> Communicator534 pub fn communicate_start(&mut self, input_data: Option<Vec<u8>>) -> Communicator {
535 communicate::communicate(
536 self.stdin.take(),
537 self.stdout.take(),
538 self.stderr.take(),
539 input_data,
540 )
541 }
542
543 /// Feed the subprocess with input data and capture its output.
544 ///
545 /// This will write the provided `input_data` to the subprocess's standard
546 /// input, and simultaneously read its standard output and error. The
547 /// output and error contents are returned as a pair of `Option<Vec<u8>>`.
548 /// The `None` options correspond to streams not specified as
549 /// `Redirection::Pipe` when creating the subprocess.
550 ///
551 /// This implementation reads and writes simultaneously, avoiding deadlock
552 /// in case the subprocess starts writing output before reading the whole
553 /// input - see [`communicate_start()`] for details.
554 ///
555 /// Note that this method does not wait for the subprocess to finish, only
556 /// to close its output/error streams. It is rare but possible for the
557 /// program to continue running after having closed the streams, in which
558 /// case `Popen::Drop` will wait for it to finish. If such a wait is
559 /// undesirable, it can be prevented by waiting explicitly using `wait()`,
560 /// by detaching the process using `detach()`, or by terminating it with
561 /// `terminate()`.
562 ///
563 /// For additional control over communication, such as timeout and size
564 /// limit, call [`communicate_start()`].
565 ///
566 /// # Panics
567 ///
568 /// If `input_data` is provided and `stdin` was not redirected to a pipe.
569 /// Also, if `input_data` is not provided and `stdin` was redirected to a
570 /// pipe.
571 ///
572 /// # Errors
573 ///
574 /// * `Err(::std::io::Error)` if a system call fails
575 ///
576 /// [`communicate_start()`]: struct.Popen.html#method.communicate_start
communicate_bytes( &mut self, input_data: Option<&[u8]>, ) -> io::Result<(Option<Vec<u8>>, Option<Vec<u8>>)>577 pub fn communicate_bytes(
578 &mut self,
579 input_data: Option<&[u8]>,
580 ) -> io::Result<(Option<Vec<u8>>, Option<Vec<u8>>)> {
581 self.communicate_start(input_data.map(|i| i.to_vec()))
582 .read()
583 .map_err(|e| e.error)
584 }
585
586 /// Feed the subprocess with data and capture its output as string.
587 ///
588 /// This is a convenience method equivalent to [`communicate_bytes`], but
589 /// with input as `&str` and output as `String`. Invalid UTF-8 sequences,
590 /// if found, are replaced with the the `U+FFFD` Unicode replacement
591 /// character.
592 ///
593 /// # Panics
594 ///
595 /// The same as with `communicate_bytes`.
596 ///
597 /// # Errors
598 ///
599 /// * `Err(::std::io::Error)` if a system call fails
600 ///
601 /// [`communicate_bytes`]: struct.Popen.html#method.communicate_bytes
communicate( &mut self, input_data: Option<&str>, ) -> io::Result<(Option<String>, Option<String>)>602 pub fn communicate(
603 &mut self,
604 input_data: Option<&str>,
605 ) -> io::Result<(Option<String>, Option<String>)> {
606 self.communicate_start(input_data.map(|s| s.as_bytes().to_vec()))
607 .read_string()
608 .map_err(|e| e.error)
609 }
610
611 /// Check whether the process is still running, without blocking or errors.
612 ///
613 /// This checks whether the process is still running and if it
614 /// is still running, `None` is returned, otherwise
615 /// `Some(exit_status)`. This method is guaranteed not to block
616 /// and is exactly equivalent to
617 /// `wait_timeout(Duration::from_secs(0)).unwrap_or(None)`.
poll(&mut self) -> Option<ExitStatus>618 pub fn poll(&mut self) -> Option<ExitStatus> {
619 self.wait_timeout(Duration::from_secs(0)).unwrap_or(None)
620 }
621
622 /// Wait for the process to finish, and return its exit status.
623 ///
624 /// If the process has already finished, it will exit immediately,
625 /// returning the exit status. Calling `wait` after that will
626 /// return the cached exit status without executing any system
627 /// calls.
628 ///
629 /// # Errors
630 ///
631 /// Returns an `Err` if a system call fails in an unpredicted way.
632 /// This should not happen in normal usage.
wait(&mut self) -> Result<ExitStatus>633 pub fn wait(&mut self) -> Result<ExitStatus> {
634 self.os_wait()
635 }
636
637 /// Wait for the process to finish, timing out after the specified duration.
638 ///
639 /// This function behaves like `wait()`, except that the caller
640 /// will be blocked for roughly no longer than `dur`. It returns
641 /// `Ok(None)` if the timeout is known to have elapsed.
642 ///
643 /// On Unix-like systems, timeout is implemented by calling
644 /// `waitpid(..., WNOHANG)` in a loop with adaptive sleep
645 /// intervals between iterations.
wait_timeout(&mut self, dur: Duration) -> Result<Option<ExitStatus>>646 pub fn wait_timeout(&mut self, dur: Duration) -> Result<Option<ExitStatus>> {
647 self.os_wait_timeout(dur)
648 }
649
650 /// Terminate the subprocess.
651 ///
652 /// On Unix-like systems, this sends the `SIGTERM` signal to the
653 /// child process, which can be caught by the child in order to
654 /// perform cleanup before exiting. On Windows, it is equivalent
655 /// to `kill()`.
terminate(&mut self) -> io::Result<()>656 pub fn terminate(&mut self) -> io::Result<()> {
657 self.os_terminate()
658 }
659
660 /// Kill the subprocess.
661 ///
662 /// On Unix-like systems, this sends the `SIGKILL` signal to the
663 /// child process, which cannot be caught.
664 ///
665 /// On Windows, it invokes [`TerminateProcess`] on the process
666 /// handle with equivalent semantics.
667 ///
668 /// [`TerminateProcess`]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms686714(v=vs.85).aspx
kill(&mut self) -> io::Result<()>669 pub fn kill(&mut self) -> io::Result<()> {
670 self.os_kill()
671 }
672 }
673
674 trait PopenOs {
os_start(&mut self, argv: Vec<OsString>, config: PopenConfig) -> Result<()>675 fn os_start(&mut self, argv: Vec<OsString>, config: PopenConfig) -> Result<()>;
os_wait(&mut self) -> Result<ExitStatus>676 fn os_wait(&mut self) -> Result<ExitStatus>;
os_wait_timeout(&mut self, dur: Duration) -> Result<Option<ExitStatus>>677 fn os_wait_timeout(&mut self, dur: Duration) -> Result<Option<ExitStatus>>;
os_terminate(&mut self) -> io::Result<()>678 fn os_terminate(&mut self) -> io::Result<()>;
os_kill(&mut self) -> io::Result<()>679 fn os_kill(&mut self) -> io::Result<()>;
680 }
681
682 #[cfg(unix)]
683 mod os {
684 use super::*;
685
686 use crate::posix;
687 use std::collections::HashSet;
688 use std::ffi::OsString;
689 use std::fs::File;
690 use std::io::{self, Read, Write};
691 use std::os::unix::io::AsRawFd;
692 use std::time::{Duration, Instant};
693
694 use crate::os_common::ExitStatus;
695 use crate::unix::PopenExt;
696
697 pub type ExtChildState = ();
698
699 impl super::PopenOs for Popen {
os_start(&mut self, argv: Vec<OsString>, config: PopenConfig) -> Result<()>700 fn os_start(&mut self, argv: Vec<OsString>, config: PopenConfig) -> Result<()> {
701 let mut exec_fail_pipe = posix::pipe()?;
702 set_inheritable(&exec_fail_pipe.0, false)?;
703 set_inheritable(&exec_fail_pipe.1, false)?;
704 {
705 let child_ends = self.setup_streams(config.stdin, config.stdout, config.stderr)?;
706 let child_env = config.env.as_deref().map(format_env);
707 let cmd_to_exec = config.executable.as_ref().unwrap_or(&argv[0]);
708 let just_exec = posix::prep_exec(cmd_to_exec, &argv, child_env.as_deref())?;
709 unsafe {
710 // unsafe because after the call to fork() the
711 // child is not allowed to allocate
712 match posix::fork()? {
713 Some(child_pid) => {
714 self.child_state = Running {
715 pid: child_pid,
716 ext: (),
717 };
718 }
719 None => {
720 drop(exec_fail_pipe.0);
721 let result = Popen::do_exec(
722 just_exec,
723 child_ends,
724 config.cwd.as_deref(),
725 config.setuid,
726 config.setgid,
727 config.setpgid,
728 );
729 // If we are here, it means that exec has failed. Notify
730 // the parent and exit.
731 let error_code = match result {
732 Ok(()) => unreachable!(),
733 Err(e) => e.raw_os_error().unwrap_or(-1),
734 } as u32;
735 exec_fail_pipe
736 .1
737 .write_all(&[
738 error_code as u8,
739 (error_code >> 8) as u8,
740 (error_code >> 16) as u8,
741 (error_code >> 24) as u8,
742 ])
743 .ok();
744 posix::_exit(127);
745 }
746 }
747 }
748 }
749 drop(exec_fail_pipe.1);
750 let mut error_buf = [0u8; 4];
751 let read_cnt = exec_fail_pipe.0.read(&mut error_buf)?;
752 if read_cnt == 0 {
753 Ok(())
754 } else if read_cnt == 4 {
755 let error_code: u32 = error_buf[0] as u32
756 | (error_buf[1] as u32) << 8
757 | (error_buf[2] as u32) << 16
758 | (error_buf[3] as u32) << 24;
759 Err(PopenError::from(io::Error::from_raw_os_error(
760 error_code as i32,
761 )))
762 } else {
763 Err(PopenError::LogicError("invalid read_count from exec pipe"))
764 }
765 }
766
os_wait(&mut self) -> Result<ExitStatus>767 fn os_wait(&mut self) -> Result<ExitStatus> {
768 while let Running { .. } = self.child_state {
769 self.waitpid(true)?;
770 }
771 Ok(self.exit_status().unwrap())
772 }
773
os_wait_timeout(&mut self, dur: Duration) -> Result<Option<ExitStatus>>774 fn os_wait_timeout(&mut self, dur: Duration) -> Result<Option<ExitStatus>> {
775 use std::cmp::min;
776
777 if let Finished(exit_status) = self.child_state {
778 return Ok(Some(exit_status));
779 }
780
781 let deadline = Instant::now() + dur;
782 // double delay at every iteration, maxing at 100ms
783 let mut delay = Duration::from_millis(1);
784
785 loop {
786 self.waitpid(false)?;
787 if let Finished(exit_status) = self.child_state {
788 return Ok(Some(exit_status));
789 }
790 let now = Instant::now();
791 if now >= deadline {
792 return Ok(None);
793 }
794 let remaining = deadline.duration_since(now);
795 ::std::thread::sleep(min(delay, remaining));
796 delay = min(delay * 2, Duration::from_millis(100));
797 }
798 }
799
os_terminate(&mut self) -> io::Result<()>800 fn os_terminate(&mut self) -> io::Result<()> {
801 self.send_signal(posix::SIGTERM)
802 }
803
os_kill(&mut self) -> io::Result<()>804 fn os_kill(&mut self) -> io::Result<()> {
805 self.send_signal(posix::SIGKILL)
806 }
807 }
808
format_env(env: &[(OsString, OsString)]) -> Vec<OsString>809 fn format_env(env: &[(OsString, OsString)]) -> Vec<OsString> {
810 // Convert Vec of (key, val) pairs to Vec of key=val, as required by
811 // execvpe. Eliminate dups, in favor of later-appearing entries.
812 let mut seen = HashSet::<&OsStr>::new();
813 let mut formatted: Vec<_> = env
814 .iter()
815 .rev()
816 .filter(|&(k, _)| seen.insert(k))
817 .map(|(k, v)| {
818 let mut fmt = k.clone();
819 fmt.push("=");
820 fmt.push(v);
821 fmt
822 })
823 .collect();
824 formatted.reverse();
825 formatted
826 }
827
828 trait PopenOsImpl: super::PopenOs {
do_exec( just_exec: impl FnOnce() -> io::Result<()>, child_ends: (Option<Rc<File>>, Option<Rc<File>>, Option<Rc<File>>), cwd: Option<&OsStr>, setuid: Option<u32>, setgid: Option<u32>, setpgid: bool, ) -> io::Result<()>829 fn do_exec(
830 just_exec: impl FnOnce() -> io::Result<()>,
831 child_ends: (Option<Rc<File>>, Option<Rc<File>>, Option<Rc<File>>),
832 cwd: Option<&OsStr>,
833 setuid: Option<u32>,
834 setgid: Option<u32>,
835 setpgid: bool,
836 ) -> io::Result<()>;
waitpid(&mut self, block: bool) -> io::Result<()>837 fn waitpid(&mut self, block: bool) -> io::Result<()>;
838 }
839
840 impl PopenOsImpl for Popen {
do_exec( just_exec: impl FnOnce() -> io::Result<()>, child_ends: (Option<Rc<File>>, Option<Rc<File>>, Option<Rc<File>>), cwd: Option<&OsStr>, setuid: Option<u32>, setgid: Option<u32>, setpgid: bool, ) -> io::Result<()>841 fn do_exec(
842 just_exec: impl FnOnce() -> io::Result<()>,
843 child_ends: (Option<Rc<File>>, Option<Rc<File>>, Option<Rc<File>>),
844 cwd: Option<&OsStr>,
845 setuid: Option<u32>,
846 setgid: Option<u32>,
847 setpgid: bool,
848 ) -> io::Result<()> {
849 if let Some(cwd) = cwd {
850 env::set_current_dir(cwd)?;
851 }
852
853 let (stdin, stdout, stderr) = child_ends;
854 if let Some(stdin) = stdin {
855 if stdin.as_raw_fd() != 0 {
856 posix::dup2(stdin.as_raw_fd(), 0)?;
857 }
858 }
859 if let Some(stdout) = stdout {
860 if stdout.as_raw_fd() != 1 {
861 posix::dup2(stdout.as_raw_fd(), 1)?;
862 }
863 }
864 if let Some(stderr) = stderr {
865 if stderr.as_raw_fd() != 2 {
866 posix::dup2(stderr.as_raw_fd(), 2)?;
867 }
868 }
869 posix::reset_sigpipe()?;
870
871 if let Some(uid) = setuid {
872 posix::setuid(uid)?;
873 }
874 if let Some(gid) = setgid {
875 posix::setgid(gid)?;
876 }
877 if setpgid {
878 posix::setpgid(0, 0)?;
879 }
880 just_exec()?;
881 unreachable!();
882 }
883
waitpid(&mut self, block: bool) -> io::Result<()>884 fn waitpid(&mut self, block: bool) -> io::Result<()> {
885 match self.child_state {
886 Preparing => panic!("child_state == Preparing"),
887 Running { pid, .. } => {
888 match posix::waitpid(pid, if block { 0 } else { posix::WNOHANG }) {
889 Err(e) => {
890 if let Some(errno) = e.raw_os_error() {
891 if errno == posix::ECHILD {
892 // Someone else has waited for the child
893 // (another thread, a signal handler...).
894 // The PID no longer exists and we cannot
895 // find its exit status.
896 self.child_state = Finished(ExitStatus::Undetermined);
897 return Ok(());
898 }
899 }
900 return Err(e);
901 }
902 Ok((pid_out, exit_status)) => {
903 if pid_out == pid {
904 self.child_state = Finished(exit_status);
905 }
906 }
907 }
908 }
909 Finished(..) => (),
910 }
911 Ok(())
912 }
913 }
914
set_inheritable(f: &File, inheritable: bool) -> io::Result<()>915 pub fn set_inheritable(f: &File, inheritable: bool) -> io::Result<()> {
916 if inheritable {
917 // Unix pipes are inheritable by default.
918 } else {
919 let fd = f.as_raw_fd();
920 let old = posix::fcntl(fd, posix::F_GETFD, None)?;
921 posix::fcntl(fd, posix::F_SETFD, Some(old | posix::FD_CLOEXEC))?;
922 }
923 Ok(())
924 }
925
926 /// Create a pipe.
927 ///
928 /// This is a safe wrapper over `libc::pipe` or
929 /// `winapi::um::namedpipeapi::CreatePipe`, depending on the operating
930 /// system.
make_pipe() -> io::Result<(File, File)>931 pub fn make_pipe() -> io::Result<(File, File)> {
932 posix::pipe()
933 }
934
935 pub mod ext {
936 use crate::popen::ChildState::*;
937 use crate::popen::Popen;
938 use crate::posix;
939 use std::io;
940
941 /// Unix-specific extension methods for `Popen`
942 pub trait PopenExt {
943 /// Send the specified signal to the child process.
944 ///
945 /// The signal numbers are best obtained from the [`libc`]
946 /// crate.
947 ///
948 /// If the child process is known to have finished (due to e.g.
949 /// a previous call to [`wait`] or [`poll`]), this will do
950 /// nothing and return `Ok`.
951 ///
952 /// [`poll`]: ../struct.Popen.html#method.poll
953 /// [`wait`]: ../struct.Popen.html#method.wait
954 /// [`libc`]: https://docs.rs/libc/
send_signal(&self, signal: i32) -> io::Result<()>955 fn send_signal(&self, signal: i32) -> io::Result<()>;
956 }
957 impl PopenExt for Popen {
send_signal(&self, signal: i32) -> io::Result<()>958 fn send_signal(&self, signal: i32) -> io::Result<()> {
959 match self.child_state {
960 Preparing => panic!("child_state == Preparing"),
961 Running { pid, .. } => posix::kill(pid, signal),
962 Finished(..) => Ok(()),
963 }
964 }
965 }
966 }
967 }
968
969 #[cfg(windows)]
970 mod os {
971 use super::*;
972
973 use std::collections::HashSet;
974 use std::env;
975 use std::ffi::{OsStr, OsString};
976 use std::fs::{self, File};
977 use std::io;
978 use std::os::windows::ffi::{OsStrExt, OsStringExt};
979 use std::os::windows::io::{AsRawHandle, RawHandle};
980 use std::time::Duration;
981
982 use crate::os_common::{ExitStatus, StandardStream};
983 use crate::win32;
984
985 #[derive(Debug)]
986 pub struct ExtChildState(win32::Handle);
987
988 impl super::PopenOs for Popen {
os_start(&mut self, argv: Vec<OsString>, config: PopenConfig) -> Result<()>989 fn os_start(&mut self, argv: Vec<OsString>, config: PopenConfig) -> Result<()> {
990 fn raw(opt: &Option<Rc<File>>) -> Option<RawHandle> {
991 opt.as_ref().map(|f| f.as_raw_handle())
992 }
993 let (mut child_stdin, mut child_stdout, mut child_stderr) =
994 self.setup_streams(config.stdin, config.stdout, config.stderr)?;
995 ensure_child_stream(&mut child_stdin, StandardStream::Input)?;
996 ensure_child_stream(&mut child_stdout, StandardStream::Output)?;
997 ensure_child_stream(&mut child_stderr, StandardStream::Error)?;
998 let cmdline = assemble_cmdline(argv)?;
999 let env_block = config.env.map(|env| format_env_block(&env));
1000 // CreateProcess doesn't search for appname in the PATH.
1001 // We do it ourselves to match the Unix behavior.
1002 let executable = config.executable.map(locate_in_path);
1003 let (handle, pid) = win32::CreateProcess(
1004 executable.as_ref().map(OsString::as_ref),
1005 &cmdline,
1006 &env_block,
1007 &config.cwd.as_deref(),
1008 true,
1009 0,
1010 raw(&child_stdin),
1011 raw(&child_stdout),
1012 raw(&child_stderr),
1013 win32::STARTF_USESTDHANDLES,
1014 )?;
1015 self.child_state = Running {
1016 pid: pid as u32,
1017 ext: ExtChildState(handle),
1018 };
1019 Ok(())
1020 }
1021
os_wait(&mut self) -> Result<ExitStatus>1022 fn os_wait(&mut self) -> Result<ExitStatus> {
1023 self.wait_handle(None)?;
1024 match self.child_state {
1025 Preparing => panic!("child_state == Preparing"),
1026 Finished(exit_status) => Ok(exit_status),
1027 // Since we invoked wait_handle without timeout, exit
1028 // status should exist at this point. The only way
1029 // for it not to exist would be if something strange
1030 // happened, like WaitForSingleObject returning
1031 // something other than OBJECT_0.
1032 Running { .. } => Err(PopenError::LogicError("Failed to obtain exit status")),
1033 }
1034 }
1035
os_wait_timeout(&mut self, dur: Duration) -> Result<Option<ExitStatus>>1036 fn os_wait_timeout(&mut self, dur: Duration) -> Result<Option<ExitStatus>> {
1037 if let Finished(exit_status) = self.child_state {
1038 return Ok(Some(exit_status));
1039 }
1040 self.wait_handle(Some(dur))?;
1041 Ok(self.exit_status())
1042 }
1043
os_terminate(&mut self) -> io::Result<()>1044 fn os_terminate(&mut self) -> io::Result<()> {
1045 let mut new_child_state = None;
1046 if let Running {
1047 ext: ExtChildState(ref handle),
1048 ..
1049 } = self.child_state
1050 {
1051 match win32::TerminateProcess(handle, 1) {
1052 Err(err) => {
1053 if err.raw_os_error() != Some(win32::ERROR_ACCESS_DENIED as i32) {
1054 return Err(err);
1055 }
1056 let rc = win32::GetExitCodeProcess(handle)?;
1057 if rc == win32::STILL_ACTIVE {
1058 return Err(err);
1059 }
1060 new_child_state = Some(Finished(ExitStatus::Exited(rc)));
1061 }
1062 Ok(_) => (),
1063 }
1064 }
1065 if let Some(new_child_state) = new_child_state {
1066 self.child_state = new_child_state;
1067 }
1068 Ok(())
1069 }
1070
os_kill(&mut self) -> io::Result<()>1071 fn os_kill(&mut self) -> io::Result<()> {
1072 self.terminate()
1073 }
1074 }
1075
format_env_block(env: &[(OsString, OsString)]) -> Vec<u16>1076 fn format_env_block(env: &[(OsString, OsString)]) -> Vec<u16> {
1077 fn to_uppercase(s: &OsStr) -> OsString {
1078 OsString::from_wide(
1079 &s.encode_wide()
1080 .map(|c| {
1081 if c < 128 {
1082 (c as u8 as char).to_ascii_uppercase() as u16
1083 } else {
1084 c
1085 }
1086 })
1087 .collect::<Vec<_>>(),
1088 )
1089 }
1090 let mut pruned: Vec<_> = {
1091 let mut seen = HashSet::<OsString>::new();
1092 env.iter()
1093 .rev()
1094 .filter(|&(k, _)| seen.insert(to_uppercase(k)))
1095 .collect()
1096 };
1097 pruned.reverse();
1098 let mut block = vec![];
1099 for (k, v) in pruned {
1100 block.extend(k.encode_wide());
1101 block.push('=' as u16);
1102 block.extend(v.encode_wide());
1103 block.push(0);
1104 }
1105 block.push(0);
1106 block
1107 }
1108
1109 trait PopenOsImpl {
wait_handle(&mut self, timeout: Option<Duration>) -> io::Result<Option<ExitStatus>>1110 fn wait_handle(&mut self, timeout: Option<Duration>) -> io::Result<Option<ExitStatus>>;
1111 }
1112
1113 impl PopenOsImpl for Popen {
wait_handle(&mut self, timeout: Option<Duration>) -> io::Result<Option<ExitStatus>>1114 fn wait_handle(&mut self, timeout: Option<Duration>) -> io::Result<Option<ExitStatus>> {
1115 let mut new_child_state = None;
1116 if let Running {
1117 ext: ExtChildState(ref handle),
1118 ..
1119 } = self.child_state
1120 {
1121 let event = win32::WaitForSingleObject(handle, timeout)?;
1122 if let win32::WaitEvent::OBJECT_0 = event {
1123 let exit_code = win32::GetExitCodeProcess(handle)?;
1124 new_child_state = Some(Finished(ExitStatus::Exited(exit_code)));
1125 }
1126 }
1127 if let Some(new_child_state) = new_child_state {
1128 self.child_state = new_child_state;
1129 }
1130 Ok(self.exit_status())
1131 }
1132 }
1133
ensure_child_stream(stream: &mut Option<Rc<File>>, which: StandardStream) -> io::Result<()>1134 fn ensure_child_stream(stream: &mut Option<Rc<File>>, which: StandardStream) -> io::Result<()> {
1135 // If no stream is sent to CreateProcess, the child doesn't
1136 // get a valid stream. This results in e.g.
1137 // Exec("sh").arg("-c").arg("echo foo >&2").stream_stderr()
1138 // failing because the shell tries to redirect stdout to
1139 // stderr, but fails because it didn't receive a valid stdout.
1140 if stream.is_none() {
1141 *stream = Some(get_standard_stream(which)?);
1142 }
1143 Ok(())
1144 }
1145
set_inheritable(f: &File, inheritable: bool) -> io::Result<()>1146 pub fn set_inheritable(f: &File, inheritable: bool) -> io::Result<()> {
1147 win32::SetHandleInformation(
1148 f,
1149 win32::HANDLE_FLAG_INHERIT,
1150 if inheritable { 1 } else { 0 },
1151 )?;
1152 Ok(())
1153 }
1154
1155 /// Create a pipe.
1156 ///
1157 /// This is a safe wrapper over `libc::pipe` or
1158 /// `winapi::um::namedpipeapi::CreatePipe`, depending on the operating
1159 /// system.
make_pipe() -> io::Result<(File, File)>1160 pub fn make_pipe() -> io::Result<(File, File)> {
1161 win32::CreatePipe(true)
1162 }
1163
locate_in_path(executable: OsString) -> OsString1164 fn locate_in_path(executable: OsString) -> OsString {
1165 if let Some(path) = env::var_os("PATH") {
1166 for path in env::split_paths(&path) {
1167 let path = path
1168 .join(&executable)
1169 .with_extension(::std::env::consts::EXE_EXTENSION);
1170 if fs::metadata(&path).is_ok() {
1171 return path.into_os_string();
1172 }
1173 }
1174 }
1175 executable
1176 }
1177
assemble_cmdline(argv: Vec<OsString>) -> io::Result<OsString>1178 fn assemble_cmdline(argv: Vec<OsString>) -> io::Result<OsString> {
1179 let mut cmdline = vec![];
1180 let mut is_first = true;
1181 for arg in argv {
1182 if !is_first {
1183 cmdline.push(' ' as u16);
1184 } else {
1185 is_first = false;
1186 }
1187 if arg.encode_wide().any(|c| c == 0) {
1188 return Err(io::Error::from_raw_os_error(
1189 win32::ERROR_BAD_PATHNAME as i32,
1190 ));
1191 }
1192 append_quoted(&arg, &mut cmdline);
1193 }
1194 Ok(OsString::from_wide(&cmdline))
1195 }
1196
1197 // Translated from ArgvQuote at http://tinyurl.com/zmgtnls
append_quoted(arg: &OsStr, cmdline: &mut Vec<u16>)1198 fn append_quoted(arg: &OsStr, cmdline: &mut Vec<u16>) {
1199 if !arg.is_empty()
1200 && !arg.encode_wide().any(|c| {
1201 c == ' ' as u16
1202 || c == '\t' as u16
1203 || c == '\n' as u16
1204 || c == '\x0b' as u16
1205 || c == '\"' as u16
1206 })
1207 {
1208 cmdline.extend(arg.encode_wide());
1209 return;
1210 }
1211 cmdline.push('"' as u16);
1212
1213 let arg: Vec<_> = arg.encode_wide().collect();
1214 let mut i = 0;
1215 while i < arg.len() {
1216 let mut num_backslashes = 0;
1217 while i < arg.len() && arg[i] == '\\' as u16 {
1218 i += 1;
1219 num_backslashes += 1;
1220 }
1221
1222 if i == arg.len() {
1223 for _ in 0..num_backslashes * 2 {
1224 cmdline.push('\\' as u16);
1225 }
1226 break;
1227 } else if arg[i] == b'"' as u16 {
1228 for _ in 0..num_backslashes * 2 + 1 {
1229 cmdline.push('\\' as u16);
1230 }
1231 cmdline.push(arg[i]);
1232 } else {
1233 for _ in 0..num_backslashes {
1234 cmdline.push('\\' as u16);
1235 }
1236 cmdline.push(arg[i]);
1237 }
1238 i += 1;
1239 }
1240 cmdline.push('"' as u16);
1241 }
1242
1243 pub mod ext {}
1244 }
1245
1246 impl Drop for Popen {
1247 // Wait for the process to exit. To avoid the wait, call
1248 // detach().
drop(&mut self)1249 fn drop(&mut self) {
1250 if let (false, &Running { .. }) = (self.detached, &self.child_state) {
1251 // Should we log error if one occurs during drop()?
1252 self.wait().ok();
1253 }
1254 }
1255 }
1256
1257 thread_local! {
1258 static STREAMS: RefCell<[Option<Rc<File>>; 3]> = RefCell::default();
1259 }
1260
1261 #[cfg(unix)]
1262 use crate::posix::make_standard_stream;
1263 #[cfg(windows)]
1264 use crate::win32::make_standard_stream;
1265
get_standard_stream(which: StandardStream) -> io::Result<Rc<File>>1266 fn get_standard_stream(which: StandardStream) -> io::Result<Rc<File>> {
1267 STREAMS.with(|streams| {
1268 if let Some(ref stream) = streams.borrow()[which as usize] {
1269 return Ok(Rc::clone(&stream));
1270 }
1271 let stream = make_standard_stream(which)?;
1272 streams.borrow_mut()[which as usize] = Some(Rc::clone(&stream));
1273 Ok(stream)
1274 })
1275 }
1276
1277 /// Error in [`Popen`] calls.
1278 ///
1279 /// [`Popen`]: struct.Popen.html
1280
1281 #[derive(Debug)]
1282 #[non_exhaustive]
1283 pub enum PopenError {
1284 /// An IO system call failed while executing the requested operation.
1285 IoError(io::Error),
1286 /// A logical error was made, e.g. invalid arguments detected at run-time.
1287 LogicError(&'static str),
1288 }
1289
1290 impl From<io::Error> for PopenError {
from(err: io::Error) -> PopenError1291 fn from(err: io::Error) -> PopenError {
1292 PopenError::IoError(err)
1293 }
1294 }
1295
1296 impl From<communicate::CommunicateError> for PopenError {
from(err: communicate::CommunicateError) -> PopenError1297 fn from(err: communicate::CommunicateError) -> PopenError {
1298 PopenError::IoError(err.error)
1299 }
1300 }
1301
1302 impl Error for PopenError {
source(&self) -> Option<&(dyn Error + 'static)>1303 fn source(&self) -> Option<&(dyn Error + 'static)> {
1304 match *self {
1305 PopenError::IoError(ref err) => Some(err),
1306 PopenError::LogicError(_msg) => None,
1307 }
1308 }
1309 }
1310
1311 impl fmt::Display for PopenError {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1312 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1313 match *self {
1314 PopenError::IoError(ref err) => fmt::Display::fmt(err, f),
1315 PopenError::LogicError(desc) => f.write_str(desc),
1316 }
1317 }
1318 }
1319
1320 /// Result returned by calls in the `subprocess` crate in places where
1321 /// `::std::io::Result` does not suffice.
1322 pub type Result<T> = result::Result<T, PopenError>;
1323