1 #[cfg(unix)]
2 mod os {
3     pub const NULL_DEVICE: &str = "/dev/null";
4     pub const SHELL: [&str; 2] = ["sh", "-c"];
5 }
6 
7 #[cfg(windows)]
8 mod os {
9     pub const NULL_DEVICE: &str = "nul";
10     pub const SHELL: [&str; 2] = ["cmd.exe", "/c"];
11 }
12 
13 pub use self::exec::{CaptureData, Exec, NullFile};
14 pub use self::os::*;
15 pub use self::pipeline::Pipeline;
16 
17 #[cfg(unix)]
18 pub use exec::unix;
19 
20 mod exec {
21     use std::ffi::{OsStr, OsString};
22     use std::fmt;
23     use std::fs::{File, OpenOptions};
24     use std::io::{self, Read, Write};
25     use std::ops::BitOr;
26     use std::path::Path;
27 
28     use crate::communicate::Communicator;
29     use crate::os_common::ExitStatus;
30     use crate::popen::{Popen, PopenConfig, Redirection, Result as PopenResult};
31 
32     use super::os::*;
33     use super::Pipeline;
34 
35     /// A builder for [`Popen`] instances, providing control and
36     /// convenience methods.
37     ///
38     /// `Exec` provides a builder API for [`Popen::create`], and
39     /// includes convenience methods for capturing the output, and for
40     /// connecting subprocesses into pipelines.
41     ///
42     /// # Examples
43     ///
44     /// Execute an external command and wait for it to complete:
45     ///
46     /// ```no_run
47     /// # use subprocess::*;
48     /// # fn dummy() -> Result<()> {
49     /// # let dirname = "some_dir";
50     /// let exit_status = Exec::cmd("umount").arg(dirname).join()?;
51     /// # Ok(())
52     /// # }
53     /// ```
54     ///
55     /// Execute the command using the OS shell, like C's `system`:
56     ///
57     /// ```no_run
58     /// # use subprocess::*;
59     /// # fn dummy() -> Result<()> {
60     /// Exec::shell("shutdown -h now").join()?;
61     /// # Ok(())
62     /// # }
63     /// ```
64     ///
65     /// Start a subprocess and obtain its output as a `Read` trait object,
66     /// like C's `popen`:
67     ///
68     /// ```
69     /// # use subprocess::*;
70     /// # fn dummy() -> Result<()> {
71     /// let stream = Exec::cmd("ls").stream_stdout()?;
72     /// // call stream.read_to_string, construct io::BufReader(stream), etc.
73     /// # Ok(())
74     /// # }
75     /// ```
76     ///
77     /// Capture the output of a command:
78     ///
79     /// ```
80     /// # use subprocess::*;
81     /// # fn dummy() -> Result<()> {
82     /// let out = Exec::cmd("ls")
83     ///   .stdout(Redirection::Pipe)
84     ///   .capture()?
85     ///   .stdout_str();
86     /// # Ok(())
87     /// # }
88     /// ```
89     ///
90     /// Redirect errors to standard output, and capture both in a single stream:
91     ///
92     /// ```
93     /// # use subprocess::*;
94     /// # fn dummy() -> Result<()> {
95     /// let out_and_err = Exec::cmd("ls")
96     ///   .stdout(Redirection::Pipe)
97     ///   .stderr(Redirection::Merge)
98     ///   .capture()?
99     ///   .stdout_str();
100     /// # Ok(())
101     /// # }
102     /// ```
103     ///
104     /// Provide input to the command and read its output:
105     ///
106     /// ```
107     /// # use subprocess::*;
108     /// # fn dummy() -> Result<()> {
109     /// let out = Exec::cmd("sort")
110     ///   .stdin("b\nc\na\n")
111     ///   .stdout(Redirection::Pipe)
112     ///   .capture()?
113     ///   .stdout_str();
114     /// assert!(out == "a\nb\nc\n");
115     /// # Ok(())
116     /// # }
117     /// ```
118     ///
119     /// [`Popen`]: struct.Popen.html
120     /// [`Popen::create`]: struct.Popen.html#method.create
121 
122     #[must_use]
123     pub struct Exec {
124         command: OsString,
125         args: Vec<OsString>,
126         config: PopenConfig,
127         stdin_data: Option<Vec<u8>>,
128     }
129 
130     impl Exec {
131         /// Constructs a new `Exec`, configured to run `command`.
132         ///
133         /// The command will be run directly in the OS, without an
134         /// intervening shell.  To run it through a shell, use
135         /// [`Exec::shell`] instead.
136         ///
137         /// By default, the command will be run without arguments, and
138         /// none of the standard streams will be modified.
139         ///
140         /// [`Exec::shell`]: struct.Exec.html#method.shell
cmd(command: impl AsRef<OsStr>) -> Exec141         pub fn cmd(command: impl AsRef<OsStr>) -> Exec {
142             Exec {
143                 command: command.as_ref().to_owned(),
144                 args: vec![],
145                 config: PopenConfig::default(),
146                 stdin_data: None,
147             }
148         }
149 
150         /// Constructs a new `Exec`, configured to run `cmdstr` with
151         /// the system shell.
152         ///
153         /// `subprocess` never spawns shells without an explicit
154         /// request.  This command requests the shell to be used; on
155         /// Unix-like systems, this is equivalent to
156         /// `Exec::cmd("sh").arg("-c").arg(cmdstr)`.  On Windows, it
157         /// runs `Exec::cmd("cmd.exe").arg("/c")`.
158         ///
159         /// `shell` is useful for porting code that uses the C
160         /// `system` function, which also spawns a shell.
161         ///
162         /// When invoking this function, be careful not to interpolate
163         /// arguments into the string run by the shell, such as
164         /// `Exec::shell(format!("sort {}", filename))`.  Such code is
165         /// prone to errors and, if `filename` comes from an untrusted
166         /// source, to shell injection attacks.  Instead, use
167         /// `Exec::cmd("sort").arg(filename)`.
shell(cmdstr: impl AsRef<OsStr>) -> Exec168         pub fn shell(cmdstr: impl AsRef<OsStr>) -> Exec {
169             Exec::cmd(SHELL[0]).args(&SHELL[1..]).arg(cmdstr)
170         }
171 
172         /// Appends `arg` to argument list.
arg(mut self, arg: impl AsRef<OsStr>) -> Exec173         pub fn arg(mut self, arg: impl AsRef<OsStr>) -> Exec {
174             self.args.push(arg.as_ref().to_owned());
175             self
176         }
177 
178         /// Extends the argument list with `args`.
args(mut self, args: &[impl AsRef<OsStr>]) -> Exec179         pub fn args(mut self, args: &[impl AsRef<OsStr>]) -> Exec {
180             self.args.extend(args.iter().map(|x| x.as_ref().to_owned()));
181             self
182         }
183 
184         /// Specifies that the process is initially detached.
185         ///
186         /// A detached process means that we will not wait for the
187         /// process to finish when the object that owns it goes out of
188         /// scope.
detached(mut self) -> Exec189         pub fn detached(mut self) -> Exec {
190             self.config.detached = true;
191             self
192         }
193 
ensure_env(&mut self)194         fn ensure_env(&mut self) {
195             if self.config.env.is_none() {
196                 self.config.env = Some(PopenConfig::current_env());
197             }
198         }
199 
200         /// Clears the environment of the subprocess.
201         ///
202         /// When this is invoked, the subprocess will not inherit the
203         /// environment of this process.
env_clear(mut self) -> Exec204         pub fn env_clear(mut self) -> Exec {
205             self.config.env = Some(vec![]);
206             self
207         }
208 
209         /// Sets an environment variable in the child process.
210         ///
211         /// If the same variable is set more than once, the last value
212         /// is used.
213         ///
214         /// Other environment variables are by default inherited from
215         /// the current process.  If this is undesirable, call
216         /// `env_clear` first.
env(mut self, key: impl AsRef<OsStr>, value: impl AsRef<OsStr>) -> Exec217         pub fn env(mut self, key: impl AsRef<OsStr>, value: impl AsRef<OsStr>) -> Exec {
218             self.ensure_env();
219             self.config
220                 .env
221                 .as_mut()
222                 .unwrap()
223                 .push((key.as_ref().to_owned(), value.as_ref().to_owned()));
224             self
225         }
226 
227         /// Sets multiple environment variables in the child process.
228         ///
229         /// The keys and values of the variables are specified by the
230         /// slice.  If the same variable is set more than once, the
231         /// last value is used.
232         ///
233         /// Other environment variables are by default inherited from
234         /// the current process.  If this is undesirable, call
235         /// `env_clear` first.
env_extend(mut self, vars: &[(impl AsRef<OsStr>, impl AsRef<OsStr>)]) -> Exec236         pub fn env_extend(mut self, vars: &[(impl AsRef<OsStr>, impl AsRef<OsStr>)]) -> Exec {
237             self.ensure_env();
238             {
239                 let envvec = self.config.env.as_mut().unwrap();
240                 for &(ref k, ref v) in vars {
241                     envvec.push((k.as_ref().to_owned(), v.as_ref().to_owned()));
242                 }
243             }
244             self
245         }
246 
247         /// Removes an environment variable from the child process.
248         ///
249         /// Other environment variables are inherited by default.
env_remove(mut self, key: impl AsRef<OsStr>) -> Exec250         pub fn env_remove(mut self, key: impl AsRef<OsStr>) -> Exec {
251             self.ensure_env();
252             self.config
253                 .env
254                 .as_mut()
255                 .unwrap()
256                 .retain(|&(ref k, ref _v)| k != key.as_ref());
257             self
258         }
259 
260         /// Specifies the current working directory of the child process.
261         ///
262         /// If unspecified, the current working directory is inherited
263         /// from the parent.
cwd(mut self, dir: impl AsRef<Path>) -> Exec264         pub fn cwd(mut self, dir: impl AsRef<Path>) -> Exec {
265             self.config.cwd = Some(dir.as_ref().as_os_str().to_owned());
266             self
267         }
268 
269         /// Specifies how to set up the standard input of the child process.
270         ///
271         /// Argument can be:
272         ///
273         /// * a [`Redirection`];
274         /// * a `File`, which is a shorthand for `Redirection::File(file)`;
275         /// * a `Vec<u8>` or `&str`, which will set up a `Redirection::Pipe`
276         ///   for stdin, making sure that `capture` feeds that data into the
277         ///   standard input of the subprocess;
278         /// * [`NullFile`], which will redirect the standard input to read from
279         ///    `/dev/null`.
280         ///
281         /// [`Redirection`]: enum.Redirection.html
282         /// [`NullFile`]: struct.NullFile.html
stdin(mut self, stdin: impl Into<InputRedirection>) -> Exec283         pub fn stdin(mut self, stdin: impl Into<InputRedirection>) -> Exec {
284             match (&self.config.stdin, stdin.into()) {
285                 (&Redirection::None, InputRedirection::AsRedirection(new)) => {
286                     self.config.stdin = new
287                 }
288                 (&Redirection::Pipe, InputRedirection::AsRedirection(Redirection::Pipe)) => (),
289                 (&Redirection::None, InputRedirection::FeedData(data)) => {
290                     self.config.stdin = Redirection::Pipe;
291                     self.stdin_data = Some(data);
292                 }
293                 (_, _) => panic!("stdin is already set"),
294             }
295             self
296         }
297 
298         /// Specifies how to set up the standard output of the child process.
299         ///
300         /// Argument can be:
301         ///
302         /// * a [`Redirection`];
303         /// * a `File`, which is a shorthand for `Redirection::File(file)`;
304         /// * [`NullFile`], which will redirect the standard output to go to
305         ///    `/dev/null`.
306         ///
307         /// [`Redirection`]: enum.Redirection.html
308         /// [`NullFile`]: struct.NullFile.html
stdout(mut self, stdout: impl Into<OutputRedirection>) -> Exec309         pub fn stdout(mut self, stdout: impl Into<OutputRedirection>) -> Exec {
310             match (&self.config.stdout, stdout.into().into_redirection()) {
311                 (&Redirection::None, new) => self.config.stdout = new,
312                 (&Redirection::Pipe, Redirection::Pipe) => (),
313                 (_, _) => panic!("stdout is already set"),
314             }
315             self
316         }
317 
318         /// Specifies how to set up the standard error of the child process.
319         ///
320         /// Argument can be:
321         ///
322         /// * a [`Redirection`];
323         /// * a `File`, which is a shorthand for `Redirection::File(file)`;
324         /// * [`NullFile`], which will redirect the standard error to go to
325         ///    `/dev/null`.
326         ///
327         /// [`Redirection`]: enum.Redirection.html
328         /// [`NullFile`]: struct.NullFile.html
stderr(mut self, stderr: impl Into<OutputRedirection>) -> Exec329         pub fn stderr(mut self, stderr: impl Into<OutputRedirection>) -> Exec {
330             match (&self.config.stderr, stderr.into().into_redirection()) {
331                 (&Redirection::None, new) => self.config.stderr = new,
332                 (&Redirection::Pipe, Redirection::Pipe) => (),
333                 (_, _) => panic!("stderr is already set"),
334             }
335             self
336         }
337 
check_no_stdin_data(&self, meth: &str)338         fn check_no_stdin_data(&self, meth: &str) {
339             if self.stdin_data.is_some() {
340                 panic!("{} called with input data specified", meth);
341             }
342         }
343 
344         // Terminators
345 
346         /// Starts the process, returning a `Popen` for the running process.
popen(mut self) -> PopenResult<Popen>347         pub fn popen(mut self) -> PopenResult<Popen> {
348             self.check_no_stdin_data("popen");
349             self.args.insert(0, self.command);
350             let p = Popen::create(&self.args, self.config)?;
351             Ok(p)
352         }
353 
354         /// Starts the process, waits for it to finish, and returns
355         /// the exit status.
356         ///
357         /// This method will wait for as long as necessary for the process to
358         /// finish.  If a timeout is needed, use
359         /// `<...>.detached().popen()?.wait_timeout(...)` instead.
join(self) -> PopenResult<ExitStatus>360         pub fn join(self) -> PopenResult<ExitStatus> {
361             self.check_no_stdin_data("join");
362             self.popen()?.wait()
363         }
364 
365         /// Starts the process and returns a value implementing the `Read`
366         /// trait that reads from the standard output of the child process.
367         ///
368         /// This will automatically set up
369         /// `stdout(Redirection::Pipe)`, so it is not necessary to do
370         /// that beforehand.
371         ///
372         /// When the trait object is dropped, it will wait for the
373         /// process to finish.  If this is undesirable, use
374         /// `detached()`.
stream_stdout(self) -> PopenResult<impl Read>375         pub fn stream_stdout(self) -> PopenResult<impl Read> {
376             self.check_no_stdin_data("stream_stdout");
377             let p = self.stdout(Redirection::Pipe).popen()?;
378             Ok(ReadOutAdapter(p))
379         }
380 
381         /// Starts the process and returns a value implementing the `Read`
382         /// trait that reads from the standard error of the child process.
383         ///
384         /// This will automatically set up
385         /// `stderr(Redirection::Pipe)`, so it is not necessary to do
386         /// that beforehand.
387         ///
388         /// When the trait object is dropped, it will wait for the
389         /// process to finish.  If this is undesirable, use
390         /// `detached()`.
stream_stderr(self) -> PopenResult<impl Read>391         pub fn stream_stderr(self) -> PopenResult<impl Read> {
392             self.check_no_stdin_data("stream_stderr");
393             let p = self.stderr(Redirection::Pipe).popen()?;
394             Ok(ReadErrAdapter(p))
395         }
396 
397         /// Starts the process and returns a value implementing the `Write`
398         /// trait that writes to the standard input of the child process.
399         ///
400         /// This will automatically set up `stdin(Redirection::Pipe)`,
401         /// so it is not necessary to do that beforehand.
402         ///
403         /// When the trait object is dropped, it will wait for the
404         /// process to finish.  If this is undesirable, use
405         /// `detached()`.
stream_stdin(self) -> PopenResult<impl Write>406         pub fn stream_stdin(self) -> PopenResult<impl Write> {
407             self.check_no_stdin_data("stream_stdin");
408             let p = self.stdin(Redirection::Pipe).popen()?;
409             Ok(WriteAdapter(p))
410         }
411 
setup_communicate(mut self) -> PopenResult<(Communicator, Popen)>412         fn setup_communicate(mut self) -> PopenResult<(Communicator, Popen)> {
413             let stdin_data = self.stdin_data.take();
414             if let (&Redirection::None, &Redirection::None) =
415                 (&self.config.stdout, &self.config.stderr)
416             {
417                 self = self.stdout(Redirection::Pipe);
418             }
419             let mut p = self.popen()?;
420 
421             Ok((p.communicate_start(stdin_data), p))
422         }
423 
424         /// Starts the process and returns a `Communicator` handle.
425         ///
426         /// This is a lower-level API that offers more choice in how
427         /// communication is performed, such as read size limit and timeout,
428         /// equivalent to [`Popen::communicate`].
429         ///
430         /// Unlike `capture()`, this method doesn't wait for the process to
431         /// finish, effectively detaching it.
432         ///
433         /// [`Popen::communicate`]: struct.Popen.html#method.communicate
communicate(self) -> PopenResult<Communicator>434         pub fn communicate(self) -> PopenResult<Communicator> {
435             let comm = self.detached().setup_communicate()?.0;
436             Ok(comm)
437         }
438 
439         /// Starts the process, collects its output, and waits for it
440         /// to finish.
441         ///
442         /// The return value provides the standard output and standard
443         /// error as bytes or optionally strings, as well as the exit
444         /// status.
445         ///
446         /// Unlike `Popen::communicate`, this method actually waits
447         /// for the process to finish, rather than simply waiting for
448         /// its standard streams to close.  If this is undesirable,
449         /// use `detached()`.
capture(self) -> PopenResult<CaptureData>450         pub fn capture(self) -> PopenResult<CaptureData> {
451             let (mut comm, mut p) = self.setup_communicate()?;
452             let (maybe_out, maybe_err) = comm.read()?;
453             Ok(CaptureData {
454                 stdout: maybe_out.unwrap_or_else(Vec::new),
455                 stderr: maybe_err.unwrap_or_else(Vec::new),
456                 exit_status: p.wait()?,
457             })
458         }
459 
460         /// Show Exec as command-line string quoted in the Unix style.
to_cmdline_lossy(&self) -> String461         pub fn to_cmdline_lossy(&self) -> String {
462             fn nice_char(c: char) -> bool {
463                 match c {
464                     '-' | '_' | '.' | ',' | '/' => true,
465                     c if c.is_ascii_alphanumeric() => true,
466                     _ => false,
467                 }
468             }
469             fn write_quoted(out: &mut String, s: &str) {
470                 if !s.chars().all(nice_char) {
471                     out.push_str(&format!("'{}'", s.replace("'", r#"'\''"#)));
472                 } else {
473                     out.push_str(s);
474                 }
475             }
476             let mut out = String::new();
477             write_quoted(&mut out, &self.command.to_string_lossy());
478             for arg in &self.args {
479                 out.push(' ');
480                 write_quoted(&mut out, &arg.to_string_lossy());
481             }
482             out
483         }
484     }
485 
486     impl Clone for Exec {
487         /// Returns a copy of the value.
488         ///
489         /// This method is guaranteed not to fail as long as none of
490         /// the `Redirection` values contain a `Redirection::File`
491         /// variant.  If a redirection to `File` is present, cloning
492         /// that field will use `File::try_clone` method, which
493         /// duplicates a file descriptor and can (but is not likely
494         /// to) fail.  In that scenario, `Exec::clone` panics.
clone(&self) -> Exec495         fn clone(&self) -> Exec {
496             Exec {
497                 command: self.command.clone(),
498                 args: self.args.clone(),
499                 config: self.config.try_clone().unwrap(),
500                 stdin_data: self.stdin_data.as_ref().cloned(),
501             }
502         }
503     }
504 
505     impl BitOr for Exec {
506         type Output = Pipeline;
507 
508         /// Create a `Pipeline` from `self` and `rhs`.
bitor(self, rhs: Exec) -> Pipeline509         fn bitor(self, rhs: Exec) -> Pipeline {
510             Pipeline::new(self, rhs)
511         }
512     }
513 
514     impl fmt::Debug for Exec {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result515         fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
516             write!(f, "Exec {{ {} }}", self.to_cmdline_lossy())
517         }
518     }
519 
520     #[derive(Debug)]
521     struct ReadOutAdapter(Popen);
522 
523     impl Read for ReadOutAdapter {
read(&mut self, buf: &mut [u8]) -> io::Result<usize>524         fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
525             self.0.stdout.as_mut().unwrap().read(buf)
526         }
527     }
528 
529     #[derive(Debug)]
530     struct ReadErrAdapter(Popen);
531 
532     impl Read for ReadErrAdapter {
read(&mut self, buf: &mut [u8]) -> io::Result<usize>533         fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
534             self.0.stderr.as_mut().unwrap().read(buf)
535         }
536     }
537 
538     #[derive(Debug)]
539     struct WriteAdapter(Popen);
540 
541     impl Write for WriteAdapter {
write(&mut self, buf: &[u8]) -> io::Result<usize>542         fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
543             self.0.stdin.as_mut().unwrap().write(buf)
544         }
flush(&mut self) -> io::Result<()>545         fn flush(&mut self) -> io::Result<()> {
546             self.0.stdin.as_mut().unwrap().flush()
547         }
548     }
549 
550     // We must implement Drop in order to close the stream.  The typical
551     // use case for stream_stdin() is a process that reads something from
552     // stdin.  WriteAdapter going out of scope invokes Popen::drop(),
553     // which waits for the process to exit.  Without closing stdin, this
554     // deadlocks because the child process hangs reading its stdin.
555 
556     impl Drop for WriteAdapter {
drop(&mut self)557         fn drop(&mut self) {
558             self.0.stdin.take();
559         }
560     }
561 
562     /// Data captured by [`Exec::capture`] and [`Pipeline::capture`].
563     ///
564     /// [`Exec::capture`]: struct.Exec.html#method.capture
565     /// [`Pipeline::capture`]: struct.Pipeline.html#method.capture
566     pub struct CaptureData {
567         /// Standard output as bytes.
568         pub stdout: Vec<u8>,
569         /// Standard error as bytes.
570         pub stderr: Vec<u8>,
571         /// Exit status.
572         pub exit_status: ExitStatus,
573     }
574 
575     impl CaptureData {
576         /// Returns the standard output as string, converted from bytes using
577         /// `String::from_utf8_lossy`.
stdout_str(&self) -> String578         pub fn stdout_str(&self) -> String {
579             String::from_utf8_lossy(&self.stdout).into_owned()
580         }
581 
582         /// Returns the standard error as string, converted from bytes using
583         /// `String::from_utf8_lossy`.
stderr_str(&self) -> String584         pub fn stderr_str(&self) -> String {
585             String::from_utf8_lossy(&self.stderr).into_owned()
586         }
587 
588         /// True if the exit status of the process or pipeline is 0.
success(&self) -> bool589         pub fn success(&self) -> bool {
590             self.exit_status.success()
591         }
592     }
593 
594     pub enum InputRedirection {
595         AsRedirection(Redirection),
596         FeedData(Vec<u8>),
597     }
598 
599     impl From<Redirection> for InputRedirection {
from(r: Redirection) -> Self600         fn from(r: Redirection) -> Self {
601             if let Redirection::Merge = r {
602                 panic!("Redirection::Merge is only allowed for output streams");
603             }
604             InputRedirection::AsRedirection(r)
605         }
606     }
607 
608     impl From<File> for InputRedirection {
from(f: File) -> Self609         fn from(f: File) -> Self {
610             InputRedirection::AsRedirection(Redirection::File(f))
611         }
612     }
613 
614     /// Marker value for [`stdin`], [`stdout`], and [`stderr`] methods
615     /// of [`Exec`] and [`Pipeline`].
616     ///
617     /// Use of this value means that the corresponding stream should
618     /// be redirected to the devnull device.
619     ///
620     /// [`stdin`]: struct.Exec.html#method.stdin
621     /// [`stdout`]: struct.Exec.html#method.stdout
622     /// [`stderr`]: struct.Exec.html#method.stderr
623     /// [`Exec`]: struct.Exec.html
624     /// [`Pipeline`]: struct.Pipeline.html
625     #[derive(Debug)]
626     pub struct NullFile;
627 
628     impl From<NullFile> for InputRedirection {
from(_nf: NullFile) -> Self629         fn from(_nf: NullFile) -> Self {
630             let null_file = OpenOptions::new().read(true).open(NULL_DEVICE).unwrap();
631             InputRedirection::AsRedirection(Redirection::File(null_file))
632         }
633     }
634 
635     impl From<Vec<u8>> for InputRedirection {
from(v: Vec<u8>) -> Self636         fn from(v: Vec<u8>) -> Self {
637             InputRedirection::FeedData(v)
638         }
639     }
640 
641     impl<'a> From<&'a str> for InputRedirection {
from(s: &'a str) -> Self642         fn from(s: &'a str) -> Self {
643             InputRedirection::FeedData(s.as_bytes().to_vec())
644         }
645     }
646 
647     #[derive(Debug)]
648     pub struct OutputRedirection(Redirection);
649 
650     impl OutputRedirection {
into_redirection(self) -> Redirection651         pub fn into_redirection(self) -> Redirection {
652             self.0
653         }
654     }
655 
656     impl From<Redirection> for OutputRedirection {
from(r: Redirection) -> Self657         fn from(r: Redirection) -> Self {
658             OutputRedirection(r)
659         }
660     }
661 
662     impl From<File> for OutputRedirection {
from(f: File) -> Self663         fn from(f: File) -> Self {
664             OutputRedirection(Redirection::File(f))
665         }
666     }
667 
668     impl From<NullFile> for OutputRedirection {
from(_nf: NullFile) -> Self669         fn from(_nf: NullFile) -> Self {
670             let null_file = OpenOptions::new().write(true).open(NULL_DEVICE).unwrap();
671             OutputRedirection(Redirection::File(null_file))
672         }
673     }
674 
675     #[cfg(unix)]
676     pub mod unix {
677         use super::Exec;
678 
679         pub trait ExecExt {
setuid(self, uid: u32) -> Self680             fn setuid(self, uid: u32) -> Self;
setgid(self, gid: u32) -> Self681             fn setgid(self, gid: u32) -> Self;
682         }
683 
684         impl ExecExt for Exec {
setuid(mut self, uid: u32) -> Exec685             fn setuid(mut self, uid: u32) -> Exec {
686                 self.config.setuid = Some(uid);
687                 self
688             }
689 
setgid(mut self, gid: u32) -> Exec690             fn setgid(mut self, gid: u32) -> Exec {
691                 self.config.setgid = Some(gid);
692                 self
693             }
694         }
695     }
696 }
697 
698 mod pipeline {
699     use std::fmt;
700     use std::fs::File;
701     use std::io::{self, Read, Write};
702     use std::ops::BitOr;
703     use std::rc::Rc;
704 
705     use crate::communicate::{self, Communicator};
706     use crate::os_common::ExitStatus;
707     use crate::popen::{Popen, Redirection, Result as PopenResult};
708 
709     use super::exec::{CaptureData, Exec, InputRedirection, OutputRedirection};
710 
711     /// A builder for multiple [`Popen`] instances connected via
712     /// pipes.
713     ///
714     /// A pipeline is a sequence of two or more [`Exec`] commands
715     /// connected via pipes.  Just like in a Unix shell pipeline, each
716     /// command receives standard input from the previous command, and
717     /// passes standard output to the next command.  Optionally, the
718     /// standard input of the first command can be provided from the
719     /// outside, and the output of the last command can be captured.
720     ///
721     /// In most cases you do not need to create [`Pipeline`] instances
722     /// directly; instead, combine [`Exec`] instances using the `|`
723     /// operator which produces `Pipeline`.
724     ///
725     /// # Examples
726     ///
727     /// Execute a pipeline and return the exit status of the last command:
728     ///
729     /// ```no_run
730     /// # use subprocess::*;
731     /// # fn dummy() -> Result<()> {
732     /// let exit_status =
733     ///   (Exec::shell("ls *.bak") | Exec::cmd("xargs").arg("rm")).join()?;
734     /// # Ok(())
735     /// # }
736     /// ```
737     ///
738     /// Capture the pipeline's output:
739     ///
740     /// ```no_run
741     /// # use subprocess::*;
742     /// # fn dummy() -> Result<()> {
743     /// let dir_checksum = {
744     ///     Exec::cmd("find . -type f") | Exec::cmd("sort") | Exec::cmd("sha1sum")
745     /// }.capture()?.stdout_str();
746     /// # Ok(())
747     /// # }
748     /// ```
749     ///
750     /// [`Popen`]: struct.Popen.html
751     /// [`Exec`]: struct.Exec.html
752     /// [`Pipeline`]: struct.Pipeline.html
753 
754     #[must_use]
755     pub struct Pipeline {
756         cmds: Vec<Exec>,
757         stdin: Redirection,
758         stdout: Redirection,
759         stderr_file: Option<File>,
760         stdin_data: Option<Vec<u8>>,
761     }
762 
763     impl Pipeline {
764         /// Creates a new pipeline by combining two commands.
765         ///
766         /// Equivalent to `cmd1 | cmd2`.
new(cmd1: Exec, cmd2: Exec) -> Pipeline767         pub fn new(cmd1: Exec, cmd2: Exec) -> Pipeline {
768             Pipeline {
769                 cmds: vec![cmd1, cmd2],
770                 stdin: Redirection::None,
771                 stdout: Redirection::None,
772                 stderr_file: None,
773                 stdin_data: None,
774             }
775         }
776 
777         /// Specifies how to set up the standard input of the first
778         /// command in the pipeline.
779         ///
780         /// Argument can be:
781         ///
782         /// * a [`Redirection`];
783         /// * a `File`, which is a shorthand for `Redirection::File(file)`;
784         /// * a `Vec<u8>` or `&str`, which will set up a `Redirection::Pipe`
785         ///   for stdin, making sure that `capture` feeds that data into the
786         ///   standard input of the subprocess.
787         /// * `NullFile`, which will redirect the standard input to read from
788         ///    /dev/null.
789         ///
790         /// [`Redirection`]: enum.Redirection.html
stdin(mut self, stdin: impl Into<InputRedirection>) -> Pipeline791         pub fn stdin(mut self, stdin: impl Into<InputRedirection>) -> Pipeline {
792             match stdin.into() {
793                 InputRedirection::AsRedirection(r) => self.stdin = r,
794                 InputRedirection::FeedData(data) => {
795                     self.stdin = Redirection::Pipe;
796                     self.stdin_data = Some(data);
797                 }
798             };
799             self
800         }
801 
802         /// Specifies how to set up the standard output of the last
803         /// command in the pipeline.
804         ///
805         /// Argument can be:
806         ///
807         /// * a [`Redirection`];
808         /// * a `File`, which is a shorthand for `Redirection::File(file)`;
809         /// * `NullFile`, which will redirect the standard output to write to
810         ///    /dev/null.
811         ///
812         /// [`Redirection`]: enum.Redirection.html
stdout(mut self, stdout: impl Into<OutputRedirection>) -> Pipeline813         pub fn stdout(mut self, stdout: impl Into<OutputRedirection>) -> Pipeline {
814             self.stdout = stdout.into().into_redirection();
815             self
816         }
817 
818         /// Specifies a file to which to redirect the standard error of all
819         /// the commands in the pipeline.
820         ///
821         /// It is useful for capturing the standard error of the pipeline as a
822         /// whole.  Unlike `stdout()`, which only affects the last command in
823         /// the pipeline, this affects all commands.  The difference is
824         /// because standard output is piped from one command to the next, so
825         /// only the output of the last command is "free".  In contrast, the
826         /// standard errors are not connected in any way.  This is also the
827         /// reason only a `File` is supported - it allows for efficient
828         /// sharing of the same file by all commands.
stderr_to(mut self, to: File) -> Pipeline829         pub fn stderr_to(mut self, to: File) -> Pipeline {
830             self.stderr_file = Some(to);
831             self
832         }
833 
check_no_stdin_data(&self, meth: &str)834         fn check_no_stdin_data(&self, meth: &str) {
835             if self.stdin_data.is_some() {
836                 panic!("{} called with input data specified", meth);
837             }
838         }
839 
840         // Terminators:
841 
842         /// Starts all commands in the pipeline, and returns a
843         /// `Vec<Popen>` whose members correspond to running commands.
844         ///
845         /// If some command fails to start, the remaining commands
846         /// will not be started, and the appropriate error will be
847         /// returned.  The commands that have already started will be
848         /// waited to finish (but will probably exit immediately due
849         /// to missing output), except for the ones for which
850         /// `detached()` was called.  This is equivalent to what the
851         /// shell does.
popen(mut self) -> PopenResult<Vec<Popen>>852         pub fn popen(mut self) -> PopenResult<Vec<Popen>> {
853             self.check_no_stdin_data("popen");
854             assert!(self.cmds.len() >= 2);
855 
856             if let Some(stderr_to) = self.stderr_file {
857                 let stderr_to = Rc::new(stderr_to);
858                 self.cmds = self
859                     .cmds
860                     .into_iter()
861                     .map(|cmd| cmd.stderr(Redirection::RcFile(Rc::clone(&stderr_to))))
862                     .collect();
863             }
864 
865             let first_cmd = self.cmds.drain(..1).next().unwrap();
866             self.cmds.insert(0, first_cmd.stdin(self.stdin));
867 
868             let last_cmd = self.cmds.drain(self.cmds.len() - 1..).next().unwrap();
869             self.cmds.push(last_cmd.stdout(self.stdout));
870 
871             let mut ret = Vec::<Popen>::new();
872             let cnt = self.cmds.len();
873 
874             for (idx, mut runner) in self.cmds.into_iter().enumerate() {
875                 if idx != 0 {
876                     let prev_stdout = ret[idx - 1].stdout.take().unwrap();
877                     runner = runner.stdin(prev_stdout);
878                 }
879                 if idx != cnt - 1 {
880                     runner = runner.stdout(Redirection::Pipe);
881                 }
882                 ret.push(runner.popen()?);
883             }
884             Ok(ret)
885         }
886 
887         /// Starts the pipeline, waits for it to finish, and returns
888         /// the exit status of the last command.
join(self) -> PopenResult<ExitStatus>889         pub fn join(self) -> PopenResult<ExitStatus> {
890             self.check_no_stdin_data("join");
891             let mut v = self.popen()?;
892             // Waiting on a pipeline waits for all commands, but
893             // returns the status of the last one.  This is how the
894             // shells do it.  If the caller needs more precise control
895             // over which status is returned, they can call popen().
896             v.last_mut().unwrap().wait()
897         }
898 
899         /// Starts the pipeline and returns a value implementing the `Read`
900         /// trait that reads from the standard output of the last command.
901         ///
902         /// This will automatically set up
903         /// `stdout(Redirection::Pipe)`, so it is not necessary to do
904         /// that beforehand.
905         ///
906         /// When the trait object is dropped, it will wait for the
907         /// pipeline to finish.  If this is undesirable, use
908         /// `detached()`.
stream_stdout(self) -> PopenResult<impl Read>909         pub fn stream_stdout(self) -> PopenResult<impl Read> {
910             self.check_no_stdin_data("stream_stdout");
911             let v = self.stdout(Redirection::Pipe).popen()?;
912             Ok(ReadPipelineAdapter(v))
913         }
914 
915         /// Starts the pipeline and returns a value implementing the `Write`
916         /// trait that writes to the standard input of the last command.
917         ///
918         /// This will automatically set up `stdin(Redirection::Pipe)`,
919         /// so it is not necessary to do that beforehand.
920         ///
921         /// When the trait object is dropped, it will wait for the
922         /// process to finish.  If this is undesirable, use
923         /// `detached()`.
stream_stdin(self) -> PopenResult<impl Write>924         pub fn stream_stdin(self) -> PopenResult<impl Write> {
925             self.check_no_stdin_data("stream_stdin");
926             let v = self.stdin(Redirection::Pipe).popen()?;
927             Ok(WritePipelineAdapter(v))
928         }
929 
setup_communicate(mut self) -> PopenResult<(Communicator, Vec<Popen>)>930         fn setup_communicate(mut self) -> PopenResult<(Communicator, Vec<Popen>)> {
931             assert!(self.cmds.len() >= 2);
932 
933             let (err_read, err_write) = crate::popen::make_pipe()?;
934             self = self.stderr_to(err_write);
935 
936             let stdin_data = self.stdin_data.take();
937             let mut v = self.stdout(Redirection::Pipe).popen()?;
938             let vlen = v.len();
939 
940             let comm = communicate::communicate(
941                 v[0].stdin.take(),
942                 v[vlen - 1].stdout.take(),
943                 Some(err_read),
944                 stdin_data,
945             );
946             Ok((comm, v))
947         }
948 
949         /// Starts the pipeline and returns a `Communicator` handle.
950         ///
951         /// This is a lower-level API that offers more choice in how
952         /// communication is performed, such as read size limit and timeout,
953         /// equivalent to [`Popen::communicate`].
954         ///
955         /// Unlike `capture()`, this method doesn't wait for the pipeline to
956         /// finish, effectively detaching it.
957         ///
958         /// [`Popen::communicate`]: struct.Popen.html#method.communicate
communicate(mut self) -> PopenResult<Communicator>959         pub fn communicate(mut self) -> PopenResult<Communicator> {
960             self.cmds = self.cmds.into_iter().map(|cmd| cmd.detached()).collect();
961             let comm = self.setup_communicate()?.0;
962             Ok(comm)
963         }
964 
965         /// Starts the pipeline, collects its output, and waits for all
966         /// commands to finish.
967         ///
968         /// The return value provides the standard output of the last command,
969         /// the combined standard error of all commands, and the exit status
970         /// of the last command.  The captured outputs can be accessed as
971         /// bytes or strings.
972         ///
973         /// Unlike `Popen::communicate`, this method actually waits for the
974         /// processes to finish, rather than simply waiting for the output to
975         /// close.  If this is undesirable, use `detached()`.
capture(self) -> PopenResult<CaptureData>976         pub fn capture(self) -> PopenResult<CaptureData> {
977             let (mut comm, mut v) = self.setup_communicate()?;
978             let (out, err) = comm.read()?;
979             let out = out.unwrap_or_else(Vec::new);
980             let err = err.unwrap();
981 
982             let vlen = v.len();
983             let status = v[vlen - 1].wait()?;
984 
985             Ok(CaptureData {
986                 stdout: out,
987                 stderr: err,
988                 exit_status: status,
989             })
990         }
991     }
992 
993     impl Clone for Pipeline {
994         /// Returns a copy of the value.
995         ///
996         /// This method is guaranteed not to fail as long as none of
997         /// the `Redirection` values contain a `Redirection::File`
998         /// variant.  If a redirection to `File` is present, cloning
999         /// that field will use `File::try_clone` method, which
1000         /// duplicates a file descriptor and can (but is not likely
1001         /// to) fail.  In that scenario, `Exec::clone` panics.
clone(&self) -> Pipeline1002         fn clone(&self) -> Pipeline {
1003             Pipeline {
1004                 cmds: self.cmds.clone(),
1005                 stdin: self.stdin.try_clone().unwrap(),
1006                 stdout: self.stdout.try_clone().unwrap(),
1007                 stderr_file: self.stderr_file.as_ref().map(|f| f.try_clone().unwrap()),
1008                 stdin_data: self.stdin_data.clone(),
1009             }
1010         }
1011     }
1012 
1013     impl BitOr<Exec> for Pipeline {
1014         type Output = Pipeline;
1015 
1016         /// Append a command to the pipeline and return a new pipeline.
bitor(mut self, rhs: Exec) -> Pipeline1017         fn bitor(mut self, rhs: Exec) -> Pipeline {
1018             self.cmds.push(rhs);
1019             self
1020         }
1021     }
1022 
1023     impl BitOr for Pipeline {
1024         type Output = Pipeline;
1025 
1026         /// Append a pipeline to the pipeline and return a new pipeline.
bitor(mut self, rhs: Pipeline) -> Pipeline1027         fn bitor(mut self, rhs: Pipeline) -> Pipeline {
1028             self.cmds.extend(rhs.cmds);
1029             self.stdout = rhs.stdout;
1030             self
1031         }
1032     }
1033 
1034     impl fmt::Debug for Pipeline {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1035         fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1036             let mut args = vec![];
1037             for cmd in &self.cmds {
1038                 args.push(cmd.to_cmdline_lossy());
1039             }
1040             write!(f, "Pipeline {{ {} }}", args.join(" | "))
1041         }
1042     }
1043 
1044     #[derive(Debug)]
1045     struct ReadPipelineAdapter(Vec<Popen>);
1046 
1047     impl Read for ReadPipelineAdapter {
read(&mut self, buf: &mut [u8]) -> io::Result<usize>1048         fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
1049             let last = self.0.last_mut().unwrap();
1050             last.stdout.as_mut().unwrap().read(buf)
1051         }
1052     }
1053 
1054     #[derive(Debug)]
1055     struct WritePipelineAdapter(Vec<Popen>);
1056 
1057     impl WritePipelineAdapter {
stdin(&mut self) -> &mut File1058         fn stdin(&mut self) -> &mut File {
1059             let first = self.0.first_mut().unwrap();
1060             first.stdin.as_mut().unwrap()
1061         }
1062     }
1063 
1064     impl Write for WritePipelineAdapter {
write(&mut self, buf: &[u8]) -> io::Result<usize>1065         fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1066             self.stdin().write(buf)
1067         }
flush(&mut self) -> io::Result<()>1068         fn flush(&mut self) -> io::Result<()> {
1069             self.stdin().flush()
1070         }
1071     }
1072 
1073     impl Drop for WritePipelineAdapter {
1074         // the same rationale as Drop for WriteAdapter
drop(&mut self)1075         fn drop(&mut self) {
1076             let first = &mut self.0[0];
1077             first.stdin.take();
1078         }
1079     }
1080 }
1081