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