Skip to main content

subprocess/
exec.rs

1#[cfg(unix)]
2mod os {
3    pub const SHELL: [&str; 2] = ["sh", "-c"];
4}
5
6#[cfg(windows)]
7mod os {
8    pub const SHELL: [&str; 2] = ["cmd.exe", "/c"];
9}
10
11use crate::communicate::Communicator;
12use crate::process::ExitStatus;
13use std::collections::HashMap;
14use std::env;
15use std::ffi::OsString;
16use std::fmt;
17use std::fs::File;
18use std::io::{self, Read, Write};
19use std::ops::BitOr;
20use std::path::Path;
21use std::sync::Arc;
22
23use crate::job::Job;
24pub(crate) use crate::job::{ReadAdapter, ReadErrAdapter, WriteAdapter};
25use crate::pipeline::Pipeline;
26use crate::spawn::{Arg, OsOptions, SpawnResult, display_escape, spawn};
27
28use os::*;
29
30/// Instruction what to do with a stream in the child process.
31///
32/// `Redirection` values are used for the `stdin`, `stdout`, and `stderr` parameters when
33/// configuring a subprocess via [`Exec`] or [`Pipeline`].
34///
35/// [`Exec`]: struct.Exec.html
36/// [`Pipeline`]: struct.Pipeline.html
37#[derive(Debug)]
38pub enum Redirection {
39    /// Do nothing with the stream.
40    ///
41    /// The stream is typically inherited from the parent. The corresponding pipe field in
42    /// [`Job`] will be `None`.
43    ///
44    /// [`Job`]: struct.Job.html
45    None,
46
47    /// Redirect the stream to a pipe.
48    ///
49    /// This variant requests that a stream be redirected to a unidirectional pipe. One
50    /// end of the pipe is passed to the child process and configured as one of its
51    /// standard streams, and the other end is available to the parent for communicating
52    /// with the child.
53    Pipe,
54
55    /// Merge the stream to the other output stream.
56    ///
57    /// This variant is only valid when configuring redirection of standard output and
58    /// standard error. Using `Redirection::Merge` for stderr requests the child's stderr
59    /// to refer to the same underlying file as the child's stdout (which may or may not
60    /// itself be redirected), equivalent to the `2>&1` operator of the Bourne
61    /// shell. Analogously, using `Redirection::Merge` for stdout is equivalent to `1>&2`
62    /// in the shell.
63    ///
64    /// Specifying `Redirection::Merge` for stdin or specifying it for both stdout and
65    /// stderr is invalid and will cause an error.
66    Merge,
67
68    /// Redirect the stream to the specified open `File`.
69    ///
70    /// This does not create a pipe, it simply spawns the child so that the specified
71    /// stream sees that file. The child can read from or write to the provided file on
72    /// its own, without any intervention by the parent.
73    File(File),
74
75    /// Redirect the stream to the null device (`/dev/null` on Unix, `nul` on Windows).
76    ///
77    /// This is equivalent to `Redirection::File` with a null device file, but more
78    /// convenient and portable.
79    Null,
80}
81
82/// A builder for creating subprocesses.
83///
84/// `Exec` provides a builder API for spawning subprocesses, and includes convenience
85/// methods for capturing the output and for connecting subprocesses into pipelines.
86///
87/// # Examples
88///
89/// Execute an external command and wait for it to complete:
90///
91/// ```no_run
92/// # use subprocess::*;
93/// # fn dummy() -> std::io::Result<()> {
94/// # let dirname = "some_dir";
95/// let exit_status = Exec::cmd("umount").arg(dirname).join()?;
96/// # Ok(())
97/// # }
98/// ```
99///
100/// Execute the command using the OS shell, like C's `system`:
101///
102/// ```no_run
103/// # use subprocess::*;
104/// # fn dummy() -> std::io::Result<()> {
105/// Exec::shell("shutdown -h now").join()?;
106/// # Ok(())
107/// # }
108/// ```
109///
110/// Start a subprocess and obtain its output as an `impl Read`, like C's `popen`:
111///
112/// ```
113/// # use subprocess::*;
114/// # fn dummy() -> std::io::Result<()> {
115/// let stream = Exec::cmd("ls").stream_stdout()?;
116/// // call stream.read_to_string, construct io::BufReader(stream), etc.
117/// # Ok(())
118/// # }
119/// ```
120///
121/// Capture the output of a command:
122///
123/// ```
124/// # use subprocess::*;
125/// # fn dummy() -> std::io::Result<()> {
126/// let out = Exec::cmd("ls").capture()?.stdout_str();
127/// # Ok(())
128/// # }
129/// ```
130///
131/// Redirect standard error to standard output, and capture both in a single stream:
132///
133/// ```
134/// # use subprocess::*;
135/// # fn dummy() -> std::io::Result<()> {
136/// let out_and_err = Exec::cmd("ls")
137///   .stderr(Redirection::Merge)
138///   .capture()?
139///   .stdout_str();
140/// # Ok(())
141/// # }
142/// ```
143///
144/// Provide input to the command and read its output:
145///
146/// ```
147/// # use subprocess::*;
148/// # fn dummy() -> std::io::Result<()> {
149/// let out = Exec::cmd("sort")
150///   .stdin("b\nc\na\n")
151///   .capture()?
152///   .stdout_str();
153/// assert!(out == "a\nb\nc\n");
154/// # Ok(())
155/// # }
156/// ```
157#[must_use]
158pub struct Exec {
159    command: OsString,
160    args: Vec<Arg>,
161    check_success: bool,
162    stdin_data: Option<InputData>,
163    pub(crate) stdin_redirect: Arc<Redirection>,
164    pub(crate) stdout_redirect: Arc<Redirection>,
165    pub(crate) stderr_redirect: Arc<Redirection>,
166    detached: bool,
167    executable: Option<OsString>,
168    env: Option<Vec<(OsString, OsString)>>,
169    cwd: Option<OsString>,
170    os_options: OsOptions,
171}
172
173impl Exec {
174    /// Constructs a new `Exec`, configured to run `command`.
175    ///
176    /// The command will be run directly in the OS, without an intervening shell. To run
177    /// it through a shell, use [`Exec::shell`] instead.
178    ///
179    /// By default, the command will be run without arguments, and none of the standard
180    /// streams will be modified.
181    ///
182    /// [`Exec::shell`]: struct.Exec.html#method.shell
183    pub fn cmd(command: impl Into<OsString>) -> Exec {
184        Exec {
185            command: command.into(),
186            args: vec![],
187            check_success: false,
188            stdin_data: None,
189            stdin_redirect: Arc::new(Redirection::None),
190            stdout_redirect: Arc::new(Redirection::None),
191            stderr_redirect: Arc::new(Redirection::None),
192            detached: false,
193            executable: None,
194            env: None,
195            cwd: None,
196            os_options: Default::default(),
197        }
198    }
199
200    /// Constructs a new `Exec`, configured to run `cmdstr` with the system shell.
201    ///
202    /// `subprocess` never spawns shells without an explicit request. This command
203    /// requests the shell to be used; on Unix-like systems, this is equivalent to
204    /// `Exec::cmd("sh").arg("-c").arg(cmdstr)`. On Windows, it runs
205    /// `Exec::cmd("cmd.exe").arg("/c").raw_arg(cmdstr)`, passing the command
206    /// string without quoting so that `cmd.exe` interprets it correctly.
207    ///
208    /// `shell` is useful for porting code that uses the C `system` function, which also
209    /// spawns a shell.
210    ///
211    /// When invoking this function, be careful not to interpolate arguments into the
212    /// string run by the shell, such as `Exec::shell(format!("sort {}", filename))`. Such
213    /// code is prone to errors and, if `filename` comes from an untrusted source, to
214    /// shell injection attacks. Instead, use `Exec::cmd("sort").arg(filename)`.
215    pub fn shell(cmdstr: impl Into<OsString>) -> Exec {
216        let cmd = Exec::cmd(SHELL[0]).args(&SHELL[1..]);
217        #[cfg(not(windows))]
218        {
219            cmd.arg(cmdstr)
220        }
221        #[cfg(windows)]
222        {
223            use crate::ExecExt;
224            cmd.raw_arg(cmdstr)
225        }
226    }
227
228    /// Appends `arg` to argument list.
229    pub fn arg(mut self, arg: impl Into<OsString>) -> Exec {
230        self.args.push(Arg::Regular(arg.into()));
231        self
232    }
233
234    /// Extends the argument list with `args`.
235    pub fn args(mut self, args: impl IntoIterator<Item = impl Into<OsString>>) -> Exec {
236        self.args
237            .extend(args.into_iter().map(|x| Arg::Regular(x.into())));
238        self
239    }
240
241    /// Specifies that the process is initially detached.
242    ///
243    /// A detached process means that we will not wait for the process to finish when the
244    /// object that owns it goes out of scope.
245    pub fn detached(mut self) -> Exec {
246        self.detached = true;
247        self
248    }
249
250    /// If called, [`join`](Self::join) and [`capture`](Self::capture) will return an
251    /// error if the process exits with a non-zero status.
252    pub fn checked(mut self) -> Exec {
253        self.check_success = true;
254        self
255    }
256
257    fn ensure_env(&mut self) -> &mut Vec<(OsString, OsString)> {
258        self.env.get_or_insert_with(|| env::vars_os().collect())
259    }
260
261    /// Clears the environment of the subprocess.
262    ///
263    /// When this is invoked, the subprocess will not inherit the environment of this
264    /// process.
265    pub fn env_clear(mut self) -> Exec {
266        self.env = Some(vec![]);
267        self
268    }
269
270    /// Sets an environment variable in the child process.
271    ///
272    /// If the same variable is set more than once, the last value is used.
273    ///
274    /// Other environment variables are by default inherited from the current process. If
275    /// this is undesirable, call `env_clear` first.
276    pub fn env(mut self, key: impl Into<OsString>, value: impl Into<OsString>) -> Exec {
277        self.ensure_env().push((key.into(), value.into()));
278        self
279    }
280
281    /// Sets multiple environment variables in the child process.
282    ///
283    /// The keys and values of the variables are specified by the iterable.  If the same
284    /// variable is set more than once, the last value is used.
285    ///
286    /// Other environment variables are by default inherited from the current process. If
287    /// this is undesirable, call `env_clear` first.
288    pub fn env_extend(
289        mut self,
290        vars: impl IntoIterator<Item = (impl Into<OsString>, impl Into<OsString>)>,
291    ) -> Exec {
292        self.ensure_env()
293            .extend(vars.into_iter().map(|(k, v)| (k.into(), v.into())));
294        self
295    }
296
297    /// Removes an environment variable from the child process.
298    ///
299    /// Other environment variables are inherited by default.
300    pub fn env_remove(mut self, key: impl Into<OsString>) -> Exec {
301        let key = key.into();
302        self.ensure_env().retain(|(k, _v)| *k != key);
303        self
304    }
305
306    /// Specifies the current working directory of the child process.
307    ///
308    /// If unspecified, the current working directory is inherited from the parent.
309    pub fn cwd(mut self, dir: impl AsRef<Path>) -> Exec {
310        self.cwd = Some(dir.as_ref().as_os_str().to_owned());
311        self
312    }
313
314    /// Specifies the source for the standard input of the child process.
315    ///
316    /// The source can be:
317    ///
318    /// * a [`Redirection`];
319    /// * a `File`, which is a shorthand for `Redirection::File(file)`;
320    /// * a `Vec<u8>`, `&str`, `&[u8]`, `Box<[u8]>`, or `[u8; N]`, which will set up a
321    ///   `Redirection::Pipe` for stdin, feeding that data into the standard input of the
322    ///   subprocess;
323    /// * an [`InputData`], which also sets up a pipe, but wraps any reader and feeds its
324    ///   content to the standard input of the subprocess. Use [`InputData::from_bytes`]
325    ///   for in-memory byte containers not covered by the above, like `bytes::Bytes` or
326    ///   `memmap2::Mmap`. Use [`InputData::from_reader`] for a custom `Read` that
327    ///   generates or transforms data.
328    ///
329    /// If the child exits before consuming all input, the `BrokenPipe` error is silently
330    /// ignored. Use the exit status and output to check if the child processed the input
331    /// correctly.
332    ///
333    /// [`Redirection`]: enum.Redirection.html
334    /// [`InputData`]: struct.InputData.html
335    pub fn stdin<T>(mut self, stdin: T) -> Exec
336    where
337        InputRedirection: FromSource<T>,
338    {
339        match InputRedirection::from_source(stdin) {
340            InputRedirection::Redirection(new) => {
341                self.stdin_redirect = Arc::new(new);
342                self.stdin_data = None;
343            }
344            InputRedirection::Data(data) => {
345                self.stdin_redirect = Arc::new(Redirection::Pipe);
346                self.stdin_data = Some(data);
347            }
348        }
349        self
350    }
351
352    /// Specifies the sink for the standard output of the child process.
353    ///
354    /// The sink can be:
355    ///
356    /// * a [`Redirection`];
357    /// * a `File`, which is a shorthand for `Redirection::File(file)`.
358    ///
359    /// [`Redirection`]: enum.Redirection.html
360    pub fn stdout<T>(mut self, stdout: T) -> Exec
361    where
362        Redirection: FromSink<T>,
363    {
364        self.stdout_redirect = Arc::new(Redirection::from_sink(stdout));
365        self
366    }
367
368    /// Specifies the sink for the standard error of the child process.
369    ///
370    /// The sink can be:
371    ///
372    /// * a [`Redirection`];
373    /// * a `File`, which is a shorthand for `Redirection::File(file)`.
374    ///
375    /// [`Redirection`]: enum.Redirection.html
376    pub fn stderr<T>(mut self, stderr: T) -> Exec
377    where
378        Redirection: FromSink<T>,
379    {
380        self.stderr_redirect = Arc::new(Redirection::from_sink(stderr));
381        self
382    }
383
384    fn check_no_stdin_data(&self, meth: &str) {
385        if self.stdin_data.is_some() {
386            panic!("{} called with input data specified", meth);
387        }
388    }
389
390    // Terminators
391
392    /// Spawn the process and return the raw spawn result.
393    ///
394    /// This is the low-level entry point used by both `start()` and
395    /// `Pipeline::start()`. It calls `crate::spawn::spawn()` with the Exec's fields.
396    pub(crate) fn spawn(self) -> io::Result<SpawnResult> {
397        let mut argv = self.args;
398        argv.insert(0, Arg::Regular(self.command));
399
400        spawn(
401            argv,
402            self.stdin_redirect,
403            self.stdout_redirect,
404            self.stderr_redirect,
405            self.detached,
406            self.executable.as_deref(),
407            self.env.as_deref(),
408            self.cwd.as_deref(),
409            self.os_options,
410        )
411    }
412
413    /// Starts the process and returns a [`Job`] handle with the running process and its
414    /// pipe ends.
415    pub fn start(mut self) -> io::Result<Job> {
416        let stdin_data = self.stdin_data.take().unwrap_or_default();
417        let check_success = self.check_success;
418
419        let result = self.spawn()?;
420
421        Ok(Job {
422            stdin: result.stdin,
423            stdout: result.stdout,
424            stderr: result.stderr,
425            stdin_data,
426            check_success,
427            processes: vec![result.process],
428        })
429    }
430
431    /// Starts the process, waits for it to finish, and returns the exit status.
432    pub fn join(self) -> io::Result<ExitStatus> {
433        self.start()?.join()
434    }
435
436    /// Starts the process and returns a value implementing the `Read` trait that reads
437    /// from the standard output of the child process.
438    ///
439    /// This will automatically set up `stdout(Redirection::Pipe)`, so it is not necessary
440    /// to do that beforehand.
441    ///
442    /// When the trait object is dropped, it will wait for the process to finish. If this
443    /// is undesirable, use `detached()`.
444    ///
445    /// # Panics
446    ///
447    /// Panics if input data was specified with [`stdin`](Self::stdin). Use
448    /// [`capture`](Self::capture) or [`communicate`](Self::communicate) to both feed
449    /// input and read output.
450    pub fn stream_stdout(self) -> io::Result<impl Read> {
451        self.check_no_stdin_data("stream_stdout");
452        Ok(ReadAdapter(self.stdout(Redirection::Pipe).start()?))
453    }
454
455    /// Starts the process and returns a value implementing the `Read` trait that reads
456    /// from the standard error of the child process.
457    ///
458    /// This will automatically set up `stderr(Redirection::Pipe)`, so it is not necessary
459    /// to do that beforehand.
460    ///
461    /// When the trait object is dropped, it will wait for the process to finish. If this
462    /// is undesirable, use `detached()`.
463    ///
464    /// # Panics
465    ///
466    /// Panics if input data was specified with [`stdin`](Self::stdin). Use
467    /// [`capture`](Self::capture) or [`communicate`](Self::communicate) to both feed
468    /// input and read output.
469    pub fn stream_stderr(self) -> io::Result<impl Read> {
470        self.check_no_stdin_data("stream_stderr");
471        Ok(ReadErrAdapter(self.stderr(Redirection::Pipe).start()?))
472    }
473
474    /// Starts the process and returns a value implementing the `Write` trait that writes
475    /// to the standard input of the child process.
476    ///
477    /// This will automatically set up `stdin(Redirection::Pipe)`, so it is not necessary
478    /// to do that beforehand.
479    ///
480    /// When the trait object is dropped, it will wait for the process to finish. If this
481    /// is undesirable, use `detached()`.
482    ///
483    /// # Panics
484    ///
485    /// Panics if input data was specified with [`stdin`](Self::stdin).
486    pub fn stream_stdin(self) -> io::Result<impl Write> {
487        self.check_no_stdin_data("stream_stdin");
488        Ok(WriteAdapter(self.stdin(Redirection::Pipe).start()?))
489    }
490
491    /// Starts the process and returns a `Communicator` handle.
492    ///
493    /// Unless already configured, stdout and stderr are redirected to pipes. If you
494    /// need different redirection (e.g. `stderr(Merge)`), set it up before calling
495    /// this method and it will be preserved.
496    ///
497    /// Compared to `capture()`, this offers more choice in how communication is
498    /// performed, such as read size limit and timeout. Unlike `capture()`, this
499    /// method doesn't wait for the process to finish, effectively detaching it.
500    pub fn communicate(mut self) -> io::Result<Communicator> {
501        self = self.detached();
502        if matches!(*self.stdout_redirect, Redirection::None) {
503            self = self.stdout(Redirection::Pipe);
504        }
505        if matches!(*self.stderr_redirect, Redirection::None) {
506            self = self.stderr(Redirection::Pipe);
507        }
508        self.start()?.communicate()
509    }
510
511    /// Starts the process, collects its output, and waits for it to finish.
512    ///
513    /// The return value provides the standard output and standard error as bytes or
514    /// optionally strings, as well as the exit status.
515    ///
516    /// Unless already configured, stdout and stderr are redirected to pipes so they
517    /// can be captured. If you need different redirection (e.g. `stderr(Merge)`),
518    /// set it up before calling this method and it will be preserved.
519    ///
520    /// This method waits for the process to finish, rather than simply waiting for
521    /// its standard streams to close. If this is undesirable, use `detached()`.
522    pub fn capture(mut self) -> io::Result<Capture> {
523        if matches!(*self.stdout_redirect, Redirection::None) {
524            self = self.stdout(Redirection::Pipe);
525        }
526        if matches!(*self.stderr_redirect, Redirection::None) {
527            self = self.stderr(Redirection::Pipe);
528        }
529        self.start()?.capture()
530    }
531
532    /// Show Exec as command-line string quoted in the Unix style.
533    pub fn to_cmdline_lossy(&self) -> String {
534        let mut out = String::new();
535        if let Some(cmd_env) = &self.env {
536            let current: Vec<_> = env::vars_os().collect();
537            let current_map: HashMap<_, _> = current.iter().map(|(x, y)| (x, y)).collect();
538            for (k, v) in cmd_env {
539                if current_map.get(k) == Some(&v) {
540                    continue;
541                }
542                out.push_str(&display_escape(&k.to_string_lossy()));
543                out.push('=');
544                out.push_str(&display_escape(&v.to_string_lossy()));
545                out.push(' ');
546            }
547            let cmd_env: HashMap<_, _> = cmd_env.iter().map(|(k, v)| (k, v)).collect();
548            for (k, _) in current {
549                if !cmd_env.contains_key(&k) {
550                    out.push_str(&display_escape(&k.to_string_lossy()));
551                    out.push('=');
552                    out.push(' ');
553                }
554            }
555        }
556        out.push_str(&display_escape(&self.command.to_string_lossy()));
557        for arg in &self.args {
558            out.push(' ');
559            out.push_str(&arg.display_escaped());
560        }
561        out
562    }
563
564    pub(crate) fn stdin_is_set(&self) -> bool {
565        !matches!(*self.stdin_redirect, Redirection::None)
566    }
567
568    pub(crate) fn stdout_is_set(&self) -> bool {
569        !matches!(*self.stdout_redirect, Redirection::None)
570    }
571
572    #[cfg(unix)]
573    pub(crate) fn setpgid_is_set(&self) -> bool {
574        self.os_options.setpgid_is_set()
575    }
576
577    #[cfg(unix)]
578    pub(crate) fn set_pgid_value(&mut self, pgid: u32) {
579        self.os_options.set_pgid_value(pgid);
580    }
581}
582
583impl BitOr for Exec {
584    type Output = Pipeline;
585
586    /// Create a `Pipeline` from `self` and `rhs`.
587    fn bitor(self, rhs: Exec) -> Pipeline {
588        Pipeline::new().pipe(self).pipe(rhs)
589    }
590}
591
592impl fmt::Debug for Exec {
593    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
594        write!(f, "Exec {{ {} }}", self.to_cmdline_lossy())
595    }
596}
597
598/// Data captured by [`Exec::capture`] and [`Pipeline::capture`].
599///
600/// [`Exec::capture`]: struct.Exec.html#method.capture
601/// [`Pipeline::capture`]: struct.Pipeline.html#method.capture
602#[derive(Debug)]
603pub struct Capture {
604    /// Standard output as bytes.
605    pub stdout: Vec<u8>,
606    /// Standard error as bytes.
607    pub stderr: Vec<u8>,
608    /// Exit status.
609    pub exit_status: ExitStatus,
610}
611
612impl Capture {
613    /// Returns the standard output as string, converted from bytes using
614    /// `String::from_utf8_lossy`.
615    pub fn stdout_str(&self) -> String {
616        String::from_utf8_lossy(&self.stdout).into_owned()
617    }
618
619    /// Returns the standard error as string, converted from bytes using
620    /// `String::from_utf8_lossy`.
621    pub fn stderr_str(&self) -> String {
622        String::from_utf8_lossy(&self.stderr).into_owned()
623    }
624
625    /// True if the exit status of the process or pipeline is 0.
626    pub fn success(&self) -> bool {
627        self.exit_status.success()
628    }
629
630    /// Returns `self` if the exit status is successful, or an error otherwise.
631    pub fn check(self) -> io::Result<Self> {
632        if self.success() {
633            Ok(self)
634        } else {
635            Err(io::Error::other(format!(
636                "command failed: {}",
637                self.exit_status
638            )))
639        }
640    }
641}
642
643/// Type-erased readable source for input data fed to a subprocess's stdin.
644///
645/// `InputData` wraps a reader, so it can supply stdin data from any readable source:
646/// in-memory bytes, a custom `Read` implementation that generates or transforms data,
647/// etc.
648///
649/// Use [`InputData::from_bytes`] for in-memory byte data (`Vec<u8>`, `bytes::Bytes`,
650/// `memmap2::Mmap`, etc.) and [`InputData::from_reader`] for a custom `Read`
651/// implementation.
652pub struct InputData(Box<dyn Read + Send + Sync>);
653
654impl InputData {
655    /// Create `InputData` from in-memory byte data.
656    ///
657    /// Accepts any type that implements `AsRef<[u8]>`, such as `Vec<u8>`, `Box<[u8]>`,
658    /// `bytes::Bytes`, or `memmap2::Mmap`.
659    pub fn from_bytes(data: impl AsRef<[u8]> + Send + Sync + 'static) -> Self {
660        InputData(Box::new(io::Cursor::new(data)))
661    }
662
663    /// Create `InputData` from a custom `Read` implementation that generates or
664    /// transforms data on the fly.
665    pub fn from_reader(reader: impl Read + Send + Sync + 'static) -> Self {
666        InputData(Box::new(reader))
667    }
668}
669
670impl Read for InputData {
671    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
672        self.0.read(buf)
673    }
674}
675
676impl Default for InputData {
677    fn default() -> Self {
678        InputData(Box::new(io::empty()))
679    }
680}
681
682impl fmt::Debug for InputData {
683    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
684        f.write_str("InputData(..)")
685    }
686}
687
688#[derive(Debug)]
689pub enum InputRedirection {
690    Redirection(Redirection),
691    Data(InputData),
692}
693
694/// Trait for converting a source type into an input redirection.
695///
696/// Implemented for each type accepted by [`Exec::stdin`] and
697/// [`Pipeline::stdin`](crate::Pipeline::stdin).
698pub trait FromSource<T> {
699    /// Create the input redirection from the given source.
700    fn from_source(source: T) -> Self;
701}
702
703/// Trait for converting a sink type into an output redirection.
704///
705/// Implemented on [`Redirection`] for each type accepted by
706/// [`Exec::stdout`], [`Exec::stderr`], and their `Pipeline` equivalents.
707pub trait FromSink<T> {
708    /// Create the output redirection from the given sink.
709    fn from_sink(sink: T) -> Self;
710}
711
712impl FromSource<Redirection> for InputRedirection {
713    fn from_source(source: Redirection) -> Self {
714        if let Redirection::Merge = source {
715            panic!("Redirection::Merge is only allowed for output streams");
716        }
717        InputRedirection::Redirection(source)
718    }
719}
720
721impl FromSource<File> for InputRedirection {
722    fn from_source(source: File) -> Self {
723        InputRedirection::Redirection(Redirection::File(source))
724    }
725}
726
727impl FromSource<InputData> for InputRedirection {
728    fn from_source(source: InputData) -> Self {
729        InputRedirection::Data(source)
730    }
731}
732
733impl FromSource<Vec<u8>> for InputRedirection {
734    fn from_source(source: Vec<u8>) -> Self {
735        InputRedirection::Data(InputData::from_bytes(source))
736    }
737}
738
739impl FromSource<&'static str> for InputRedirection {
740    fn from_source(source: &'static str) -> Self {
741        InputRedirection::Data(InputData::from_bytes(source))
742    }
743}
744
745impl FromSource<&'static [u8]> for InputRedirection {
746    fn from_source(source: &'static [u8]) -> Self {
747        InputRedirection::Data(InputData::from_bytes(source))
748    }
749}
750
751impl<const N: usize> FromSource<&'static [u8; N]> for InputRedirection {
752    fn from_source(source: &'static [u8; N]) -> Self {
753        InputRedirection::Data(InputData::from_bytes(source))
754    }
755}
756
757impl<const N: usize> FromSource<[u8; N]> for InputRedirection {
758    fn from_source(source: [u8; N]) -> Self {
759        InputRedirection::Data(InputData::from_bytes(source))
760    }
761}
762
763impl FromSource<Box<[u8]>> for InputRedirection {
764    fn from_source(source: Box<[u8]>) -> Self {
765        InputRedirection::Data(InputData::from_bytes(source))
766    }
767}
768
769impl FromSink<Redirection> for Redirection {
770    fn from_sink(sink: Redirection) -> Self {
771        sink
772    }
773}
774
775impl FromSink<File> for Redirection {
776    fn from_sink(sink: File) -> Self {
777        Redirection::File(sink)
778    }
779}
780
781#[cfg(unix)]
782pub mod unix {
783    use super::Exec;
784    use crate::job::Job;
785    use crate::pipeline::Pipeline;
786    use crate::unix::ProcessExt;
787    use std::io;
788
789    /// Unix-specific extension methods for [`Job`].
790    pub trait JobExt {
791        /// Send the specified signal to all processes in the pipeline.
792        ///
793        /// Delegates to [`ProcessExt::send_signal`] on each process.
794        fn send_signal(&self, signal: i32) -> io::Result<()>;
795
796        /// Send the specified signal to the process group of the first process.
797        ///
798        /// When used with [`PipelineExt::setpgid`], all pipeline processes share the
799        /// first process's group, so signaling it reaches the entire pipeline. For a
800        /// single process started with [`ExecExt::setpgid`], this signals its group.
801        fn send_signal_group(&self, signal: i32) -> io::Result<()>;
802    }
803
804    impl JobExt for Job {
805        fn send_signal(&self, signal: i32) -> io::Result<()> {
806            for p in &self.processes {
807                p.send_signal(signal)?;
808            }
809            Ok(())
810        }
811
812        fn send_signal_group(&self, signal: i32) -> io::Result<()> {
813            if let Some(p) = self.processes.first() {
814                p.send_signal_group(signal)?;
815            }
816            Ok(())
817        }
818    }
819
820    /// Extension trait for Unix-specific process creation options.
821    pub trait ExecExt {
822        /// Set the user ID for the spawned process.
823        ///
824        /// The child process will run with the specified user ID, which affects file
825        /// access permissions and process ownership. This calls `setuid(2)` in the child
826        /// process after `fork()` but before `exec()`.
827        fn setuid(self, uid: u32) -> Self;
828
829        /// Set the group ID for the spawned process.
830        ///
831        /// The child process will run with the specified group ID, which affects file
832        /// access permissions based on group ownership. This calls `setgid(2)` in the
833        /// child process after `fork()` but before `exec()`.
834        fn setgid(self, gid: u32) -> Self;
835
836        /// Put the subprocess into its own process group.
837        ///
838        /// This calls `setpgid(0, 0)` before execing the child process, making it the
839        /// leader of a new process group.  Useful for a single process that spawns
840        /// children, allowing them all to be signaled as a group with
841        /// [`ProcessExt::send_signal_group`].
842        ///
843        /// For pipelines, use [`PipelineExt::setpgid`] instead, which puts all pipeline
844        /// processes into a shared group.
845        ///
846        /// [`ProcessExt::send_signal_group`]: crate::unix::ProcessExt::send_signal_group
847        /// [`PipelineExt::setpgid`]: PipelineExt::setpgid
848        fn setpgid(self) -> Self;
849    }
850
851    impl ExecExt for Exec {
852        fn setuid(mut self, uid: u32) -> Exec {
853            self.os_options.setuid = Some(uid);
854            self
855        }
856
857        fn setgid(mut self, gid: u32) -> Exec {
858            self.os_options.setgid = Some(gid);
859            self
860        }
861
862        fn setpgid(mut self) -> Exec {
863            self.os_options.setpgid = Some(0);
864            self
865        }
866    }
867
868    /// Unix-specific extension methods for [`Pipeline`].
869    pub trait PipelineExt {
870        /// Put all pipeline processes into a shared process group.
871        ///
872        /// The first process becomes the group leader (via `setpgid(0, 0)`) and
873        /// subsequent processes join its group.  This allows signaling the entire
874        /// pipeline as a unit using [`JobExt::send_signal_group`].
875        ///
876        /// For single processes that spawn children, use [`ExecExt::setpgid`] instead.
877        fn setpgid(self) -> Self;
878    }
879
880    impl PipelineExt for Pipeline {
881        fn setpgid(mut self) -> Pipeline {
882            self.set_setpgid(true);
883            self
884        }
885    }
886}
887
888#[cfg(any(windows, docsrs))]
889pub mod windows {
890    use std::ffi::OsString;
891
892    use super::Exec;
893    #[cfg(windows)]
894    use crate::spawn::Arg;
895
896    /// Process creation flag: The process does not have a console window.
897    pub const CREATE_NO_WINDOW: u32 = 0x08000000;
898
899    /// Process creation flag: The new process has a new console.
900    pub const CREATE_NEW_CONSOLE: u32 = 0x00000010;
901
902    /// Process creation flag: The new process is the root of a new process
903    /// group.
904    pub const CREATE_NEW_PROCESS_GROUP: u32 = 0x00000200;
905
906    /// Process creation flag: The process does not inherit its parent's
907    /// console.
908    pub const DETACHED_PROCESS: u32 = 0x00000008;
909
910    /// Extension trait for Windows-specific process creation options.
911    pub trait ExecExt {
912        /// Set process creation flags for Windows.
913        ///
914        /// This value is passed to the `dwCreationFlags` parameter of
915        /// `CreateProcessW`. Use this to control process creation behavior
916        /// such as creating the process without a console window.
917        fn creation_flags(self, flags: u32) -> Self;
918
919        /// Appends `arg` to the command line without quoting or escaping.
920        ///
921        /// This is useful for passing arguments to programs that use non-standard command
922        /// line parsing, such as `cmd.exe /c`. For example, passing `git commit -m "feat:
923        /// widget"` through [`arg`](super::Exec::arg) would apply MSVC-style argv
924        /// quoting, producing backslash escapes that `cmd.exe` would interpret literally.
925        ///
926        /// [`Exec::shell`](super::Exec::shell) uses this method to pass the command
927        /// string to `cmd.exe /c`.
928        ///
929        /// # Background
930        ///
931        /// On Windows, process arguments are not passed as an array (as on Unix) but as a
932        /// single command-line string to `CreateProcessW`. The regular
933        /// [`arg`](super::Exec::arg) method applies MSVC C runtime quoting rules so that
934        /// programs using standard `CommandLineToArgvW` parsing can reconstruct the
935        /// original arguments. `raw_arg` bypasses all quoting and passes its argument to
936        /// the command line verbatim. This is equivalent to [`raw_arg` in the standard
937        /// library](https://doc.rust-lang.org/std/os/windows/process/trait.CommandExt.html#tymethod.raw_arg).
938        ///
939        /// Only use `raw_arg` with hardcoded or carefully validated input, as no quoting
940        /// or escaping is applied.  [`Exec::shell`](super::Exec::shell) is an exception -
941        /// a shell command must reach the shell verbatim, so quoting would corrupt it
942        /// rather than protect it.
943        fn raw_arg(self, arg: impl Into<OsString>) -> Self;
944    }
945
946    impl ExecExt for Exec {
947        fn creation_flags(mut self, flags: u32) -> Exec {
948            #[cfg(windows)]
949            {
950                self.os_options.creation_flags = flags;
951                self
952            }
953            #[cfg(not(windows))]
954            {
955                let _ = flags;
956                unimplemented!()
957            }
958        }
959
960        fn raw_arg(mut self, arg: impl Into<OsString>) -> Exec {
961            #[cfg(windows)]
962            {
963                self.args.push(Arg::Raw(arg.into()));
964                self
965            }
966            #[cfg(not(windows))]
967            {
968                let _ = arg;
969                unimplemented!()
970            }
971        }
972    }
973}