agnostic_process/
lib.rs

1#![doc = include_str!("../README.md")]
2#![deny(warnings, missing_docs)]
3#![cfg_attr(not(test), forbid(unsafe_code))]
4#![cfg_attr(docsrs, feature(doc_cfg))]
5#![cfg_attr(docsrs, allow(unused_attributes))]
6#![allow(unused_macros)]
7
8macro_rules! cfg_unix {
9  ($($item:item)*) => {
10    $(
11      #[cfg(unix)]
12      #[cfg_attr(docsrs, doc(cfg(unix)))]
13      $item
14    )*
15  }
16}
17
18macro_rules! cfg_windows {
19  ($($item:item)*) => {
20    $(
21      #[cfg(windows)]
22      #[cfg_attr(docsrs, doc(cfg(windows)))]
23      $item
24    )*
25  };
26}
27
28macro_rules! cfg_linux {
29  ($($item:item)*) => {
30    $(
31      #[cfg(target_os = "linux")]
32      #[cfg_attr(docsrs, doc(cfg(target_os = "linux")))]
33      $item
34    )*
35  };
36}
37
38/// Traits, helpers, and type definitions for asynchronous I/O functionality.
39pub use agnostic_io as io;
40
41use std::{
42  ffi::OsStr,
43  future::Future,
44  path::Path,
45  process::{ExitStatus, Output, Stdio},
46};
47
48#[cfg(test)]
49mod tests;
50
51/// A trait for converting into a [`Stdio`].
52pub trait IntoStdio {
53  /// Convert into [`std::process::Stdio`].
54  fn into_stdio(self) -> impl Future<Output = io::Result<Stdio>> + Send;
55}
56
57macro_rules! std_trait {
58  (
59    $(#[$attr:meta])*
60    trait $name:ident: $trait:ident
61  ) => {
62    $(#[$attr])*
63    #[cfg(unix)]
64    pub trait $name: std::os::fd::AsFd + std::os::fd::AsRawFd {}
65
66    #[cfg(unix)]
67    impl<T> $name for T where T: std::os::fd::AsFd + std::os::fd::AsRawFd {}
68
69    $(#[$attr])*
70    #[cfg(not(unix))]
71    pub trait $name {}
72
73    #[cfg(not(unix))]
74    impl<T> $name for T {}
75  };
76}
77
78macro_rules! child_std {
79  (
80    $(#[$attr:meta])*
81    $name:ident
82  ) => {
83    $(#[$attr])*
84    pub struct $name<T>(T);
85
86    impl<T> From<T> for $name<T> {
87      fn from(inner: T) -> Self {
88        $name(inner)
89      }
90    }
91
92    impl<T> core::convert::AsRef<T> for $name<T> {
93      fn as_ref(&self) -> &T {
94        &self.0
95      }
96    }
97
98    impl<T> core::convert::AsMut<T> for $name<T> {
99      fn as_mut(&mut self) -> &mut T {
100        &mut self.0
101      }
102    }
103
104    impl<T> core::ops::Deref for $name<T> {
105      type Target = T;
106
107      fn deref(&self) -> &Self::Target {
108        &self.0
109      }
110    }
111
112    impl<T> core::ops::DerefMut for $name<T> {
113      fn deref_mut(&mut self) -> &mut Self::Target {
114        &mut self.0
115      }
116    }
117
118    impl<T> $name<T> {
119      /// Creates a new instance of the wrapper.
120      #[inline]
121      pub const fn new(inner: T) -> Self {
122        Self(inner)
123      }
124
125      /// Consumes the wrapper, returning the inner value.
126      #[inline]
127      pub fn into_inner(self) -> T {
128        self.0
129      }
130
131      /// Gets a reference to the inner value.
132      #[inline]
133      pub const fn as_inner(&self) -> &T {
134        &self.0
135      }
136
137      /// Gets a mutable reference to the inner value.
138      #[inline]
139      pub const fn as_inner_mut(&mut self) -> &mut T {
140        &mut self.0
141      }
142    }
143  };
144}
145
146macro_rules! converter {
147  ($outer:ident($inner:ty)) => {
148    impl From<$outer<$inner>> for $inner {
149      fn from(outer: $outer<$inner>) -> Self {
150        outer.0
151      }
152    }
153
154    impl<'a> From<$outer<&'a mut $inner>> for &'a mut $inner {
155      fn from(outer: $outer<&'a mut $inner>) -> &'a mut $inner {
156        outer.0
157      }
158    }
159
160    impl<'a> From<$outer<&'a $inner>> for &'a $inner {
161      fn from(outer: $outer<&'a $inner>) -> &'a $inner {
162        outer.0
163      }
164    }
165
166    cfg_unix!(
167      impl std::os::fd::AsFd for $outer<$inner> {
168        fn as_fd(&self) -> std::os::fd::BorrowedFd<'_> {
169          self.0.as_fd()
170        }
171      }
172
173      impl std::os::fd::AsRawFd for $outer<$inner> {
174        fn as_raw_fd(&self) -> std::os::raw::c_int {
175          self.0.as_raw_fd()
176        }
177      }
178
179      impl std::os::fd::AsFd for $outer<&mut $inner> {
180        fn as_fd(&self) -> std::os::fd::BorrowedFd<'_> {
181          self.0.as_fd()
182        }
183      }
184
185      impl std::os::fd::AsRawFd for $outer<&mut $inner> {
186        fn as_raw_fd(&self) -> std::os::raw::c_int {
187          self.0.as_raw_fd()
188        }
189      }
190
191      impl std::os::fd::AsFd for $outer<&$inner> {
192        fn as_fd(&self) -> std::os::fd::BorrowedFd<'_> {
193          self.0.as_fd()
194        }
195      }
196
197      impl std::os::fd::AsRawFd for $outer<&$inner> {
198        fn as_raw_fd(&self) -> std::os::raw::c_int {
199          self.0.as_raw_fd()
200        }
201      }
202    );
203  };
204}
205
206std_trait!(
207  /// Marker trait for the standard input (stdin) handle of a child process.
208  trait Stdin: AsyncWrite
209);
210
211std_trait!(
212  /// Marker trait for the standard output (stdout) handle of a child process.
213  trait Stdout: AsyncRead
214);
215
216std_trait!(
217  /// Marker trait for the standard error (stderr) handle of a child process.
218  trait Stderr: AsyncRead
219);
220
221child_std!(
222  /// A handle to a child process’s standard input (stdin).
223  ChildStdin
224);
225
226child_std!(
227  /// A handle to a child process’s standard output (stdout).
228  ChildStdout
229);
230
231child_std!(
232  /// A handle to a child process’s standard error (stderr).
233  ChildStderr
234);
235
236/// An abstraction of a spawned child process.
237pub trait Child {
238  /// The standard input (stdin) handle type.
239  type Stdin: Stdin + IntoStdio;
240  /// The standard output (stdout) handle type.
241  type Stdout: Stdout + IntoStdio;
242  /// The standard error (stderr) handle type.
243  type Stderr: Stderr + IntoStdio;
244
245  /// Returns the stdin handle if it was configured.
246  fn stdin(&self) -> Option<ChildStdin<&Self::Stdin>>;
247
248  /// Returns the stdout handle if it was configured.
249  fn stdout(&self) -> Option<ChildStdout<&Self::Stdout>>;
250
251  /// Returns the stderr handle if it was configured.
252  fn stderr(&self) -> Option<ChildStderr<&Self::Stderr>>;
253
254  /// Returns a mutable reference to the stdin handle if it was configured.
255  fn stdin_mut(&mut self) -> Option<ChildStdin<&mut Self::Stdin>>;
256
257  /// Returns a mutable reference to the stdout handle if it was configured.
258  fn stdout_mut(&mut self) -> Option<ChildStdout<&mut Self::Stdout>>;
259
260  /// Returns a mutable reference to the stderr handle if it was configured.
261  fn stderr_mut(&mut self) -> Option<ChildStderr<&mut Self::Stderr>>;
262
263  /// Sets the stdin handle.
264  fn set_stdin(&mut self, stdin: Option<Self::Stdin>);
265
266  /// Sets the stdout handle.
267  fn set_stdout(&mut self, stdout: Option<Self::Stdout>);
268
269  /// Sets the stderr handle.
270  fn set_stderr(&mut self, stderr: Option<Self::Stderr>);
271
272  /// Takes the stdin handle.
273  fn take_stdin(&mut self) -> Option<ChildStdin<Self::Stdin>>;
274
275  /// Takes the stdout handle.
276  fn take_stdout(&mut self) -> Option<ChildStdout<Self::Stdout>>;
277
278  /// Takes the stderr handle.
279  fn take_stderr(&mut self) -> Option<ChildStderr<Self::Stderr>>;
280
281  /// Returns the OS-assigned process identifier associated with this child.
282  fn id(&self) -> Option<u32>;
283
284  /// Forces the child process to exit.
285  ///
286  /// If the child has already exited, an [`InvalidInput`] error is returned.
287  ///
288  /// This is equivalent to sending a SIGKILL on Unix platforms.
289  ///
290  /// [`InvalidInput`]: `std::io::ErrorKind::InvalidInput`
291  fn kill(&mut self) -> impl Future<Output = io::Result<()>> + Send;
292
293  /// Returns the exit status if the process has exited.
294  ///
295  /// Unlike [`wait()`][Child::wait], this method will not drop the stdin handle.
296  fn try_wait(&mut self) -> io::Result<Option<ExitStatus>>;
297
298  /// Drops the stdin handle and waits for the process to exit.
299  ///
300  /// Closing the stdin of the process helps avoid deadlocks. It ensures that the process does
301  /// not block waiting for input from the parent process while the parent waits for the child to
302  /// exit.
303  fn wait(&mut self) -> impl Future<Output = io::Result<ExitStatus>> + Send;
304
305  /// Drops the stdin handle and collects the output of the process.
306  ///
307  /// Closing the stdin of the process helps avoid deadlocks. It ensures that the process does
308  /// not block waiting for input from the parent process while the parent waits for the child to
309  /// exit.
310  ///
311  /// In order to capture the output of the process, [`Command::stdout()`] and
312  /// [`Command::stderr()`] must be configured with [`Stdio::piped()`].
313  fn wait_with_output(self) -> impl Future<Output = io::Result<Output>> + Send;
314
315  cfg_windows!(
316    /// Extracts the raw handle of the process associated with this child while
317    /// it is still running. Returns `None` if the child has exited.
318    fn raw_handle(&self) -> Option<std::os::windows::io::RawHandle>;
319  );
320}
321
322/// An abstraction of a builder for spawning processes.
323pub trait Command: Sized + From<std::process::Command> {
324  /// A spawned child process.
325  type Child: Child;
326
327  /// Constructs a new [`Command`] for launching `program`.
328  ///
329  /// The initial configuration (the working directory and environment variables) is inherited
330  /// from the current process.
331  fn new<S>(program: S) -> Self
332  where
333    S: AsRef<OsStr>;
334
335  /// Adds a single argument to pass to the program.
336  fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Self;
337
338  /// Adds multiple arguments to pass to the program.
339  fn args<I, S>(&mut self, args: I) -> &mut Self
340  where
341    I: IntoIterator<Item = S>,
342    S: AsRef<OsStr>;
343
344  /// Configures an environment variable for the new process.
345  ///
346  /// Note that environment variable names are case-insensitive (but case-preserving) on Windows,
347  /// and case-sensitive on all other platforms.
348  fn env<K, V>(&mut self, key: K, val: V) -> &mut Self
349  where
350    K: AsRef<OsStr>,
351    V: AsRef<OsStr>;
352
353  /// Configures multiple environment variables for the new process.
354  ///
355  /// Note that environment variable names are case-insensitive (but case-preserving) on Windows,
356  /// and case-sensitive on all other platforms.
357  fn envs<I, K, V>(&mut self, vars: I) -> &mut Self
358  where
359    I: IntoIterator<Item = (K, V)>,
360    K: AsRef<OsStr>,
361    V: AsRef<OsStr>;
362
363  /// Removes an environment variable mapping.
364  fn env_remove<K: AsRef<OsStr>>(&mut self, key: K) -> &mut Self;
365
366  /// Removes all environment variable mappings.
367  fn env_clear(&mut self) -> &mut Self;
368
369  /// Configures the working directory for the new process.
370  fn current_dir<P: AsRef<Path>>(&mut self, dir: P) -> &mut Self;
371
372  /// Configures the standard input (stdin) for the new process.
373  fn stdin<T: Into<Stdio>>(&mut self, cfg: T) -> &mut Self;
374
375  /// Configures the standard output (stdout) for the new process.
376  fn stdout<T: Into<Stdio>>(&mut self, cfg: T) -> &mut Self;
377
378  /// Configures the standard error (stderr) for the new process.
379  fn stderr<T: Into<Stdio>>(&mut self, cfg: T) -> &mut Self;
380
381  // /// Configures whether to reap the zombie process when [`Child`] is dropped.
382  // ///
383  // /// When the process finishes, it becomes a "zombie" and some resources associated with it
384  // /// remain until [`Child::try_status()`], [`Child::status()`], or [`Child::output()`] collects
385  // /// its exit code.
386  // ///
387  // /// If its exit code is never collected, the resources may leak forever. This crate has a
388  // /// background thread named "async-process" that collects such "zombie" processes and then
389  // /// "reaps" them, thus preventing the resource leaks.
390  // ///
391  // /// The default value of this option is `true`.
392  // ///
393  // /// # Examples
394  // ///
395  // /// ```
396  // /// use async_process::{Command, Stdio};
397  // ///
398  // /// let mut cmd = Command::new("cat");
399  // /// cmd.reap_on_drop(false);
400  // /// ```
401  // fn reap_on_drop(&mut self, reap_on_drop: bool) -> &mut Self;
402
403  /// Configures whether to kill the process when [`Child`] is dropped.
404  ///
405  /// The default value of this option is `false`.
406  fn kill_on_drop(&mut self, kill_on_drop: bool) -> &mut Self;
407
408  /// Executes the command and returns the [`Child`] handle to it.
409  ///
410  /// If not configured, stdin, stdout and stderr will be set to [`Stdio::inherit()`].
411  fn spawn(&mut self) -> io::Result<Self::Child>;
412
413  /// Executes the command, waits for it to exit, and returns the exit status.
414  ///
415  /// If not configured, stdin, stdout and stderr will be set to [`Stdio::inherit()`].
416  fn status(&mut self) -> impl Future<Output = io::Result<ExitStatus>> + Send;
417
418  /// Executes the command and collects its output.
419  ///
420  /// If not configured, stdin will be set to [`Stdio::null()`], and stdout and stderr will be
421  /// set to [`Stdio::piped()`].
422  fn output(&mut self) -> impl Future<Output = io::Result<Output>> + Send;
423
424  cfg_unix!(
425    /// Sets the child process's user ID. This translates to a
426    /// `setuid` call in the child process. Failure in the `setuid`
427    /// call will cause the spawn to fail.
428    fn uid(&mut self, id: u32) -> &mut Self;
429
430    /// Similar to `uid`, but sets the group ID of the child process. This has
431    /// the same semantics as the `uid` field.
432    fn gid(&mut self, id: u32) -> &mut Self;
433
434    /// Performs all the required setup by this `Command`, followed by calling
435    /// the `execvp` syscall.
436    ///
437    /// On success this function will not return, and otherwise it will return
438    /// an error indicating why the exec (or another part of the setup of the
439    /// `Command`) failed.
440    ///
441    /// `exec` not returning has the same implications as calling
442    /// [`std::process::exit`] – no destructors on the current stack or any other
443    /// thread’s stack will be run. Therefore, it is recommended to only call
444    /// `exec` at a point where it is fine to not run any destructors. Note,
445    /// that the `execvp` syscall independently guarantees that all memory is
446    /// freed and all file descriptors with the `CLOEXEC` option (set by default
447    /// on all file descriptors opened by the standard library) are closed.
448    ///
449    /// This function, unlike `spawn`, will **not** `fork` the process to create
450    /// a new child. Like spawn, however, the default behavior for the stdio
451    /// descriptors will be to inherited from the current process.
452    ///
453    /// # Notes
454    ///
455    /// The process may be in a "broken state" if this function returns in
456    /// error. For example the working directory, environment variables, signal
457    /// handling settings, various user/group information, or aspects of stdio
458    /// file descriptors may have changed. If a "transactional spawn" is
459    /// required to gracefully handle errors it is recommended to use the
460    /// cross-platform `spawn` instead.
461    fn exec(&mut self) -> io::Error;
462
463    /// Set executable argument
464    ///
465    /// Set the first process argument, `argv[0]`, to something other than the
466    /// default executable path.
467    fn arg0<S>(&mut self, arg: S) -> &mut Self
468    where
469      S: AsRef<OsStr>;
470  );
471
472  cfg_windows!(
473    /// Sets the [process creation flags][1] to be passed to `CreateProcess`.
474    ///
475    /// These will always be ORed with `CREATE_UNICODE_ENVIRONMENT`.
476    ///
477    /// [1]: https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags
478    fn creation_flags(&mut self, flags: u32) -> &mut Self;
479
480    /// Append literal text to the command line without any quoting or escaping.
481    ///
482    /// This is useful for passing arguments to applications that don't follow
483    /// the standard C run-time escaping rules, such as `cmd.exe /c`.
484    fn raw_arg<S: AsRef<OsStr>>(&mut self, text_to_append_as_is: S) -> &mut Self;
485  );
486
487  // TODO: feature(linux_pidfd)
488  // cfg_linux!(
489  //   /// Sets whether a [`PidFd`](struct@PidFd) should be created for the [`Child`]
490  //   /// spawned by this [`Command`].
491  //   /// By default, no pidfd will be created.
492  //   ///
493  //   /// The pidfd can be retrieved from the child with [`pidfd`] or [`into_pidfd`].
494  //   ///
495  //   /// A pidfd will only be created if it is possible to do so
496  //   /// in a guaranteed race-free manner. Otherwise, [`pidfd`] will return an error.
497  //   ///
498  //   /// If a pidfd has been successfully created and not been taken from the `Child`
499  //   /// then calls to `kill()`, `wait()` and `try_wait()` will use the pidfd
500  //   /// instead of the pid. This can prevent pid recycling races, e.g.
501  //   /// those  caused by rogue libraries in the same process prematurely reaping
502  //   /// zombie children via `waitpid(-1, ...)` calls.
503  //   ///
504  //   /// [`Child`]: process::Child
505  //   /// [`pidfd`]: fn@ChildExt::pidfd
506  //   /// [`into_pidfd`]: ChildExt::into_pidfd
507  //   fn create_pidfd(&mut self, val: bool) -> &mut Self;
508  // );
509}
510
511/// Trait for spawning a child process.
512pub trait Process {
513  /// The command type.
514  type Command: Command<Child = Self::Child>;
515  /// The child process type.
516  type Child: Child<Stdin = Self::Stdin, Stdout = Self::Stdout, Stderr = Self::Stderr>;
517  /// The standard input (stdin) handle type.
518  type Stdin: Stdin + IntoStdio;
519  /// The standard output (stdout) handle type.
520  type Stdout: Stdout + IntoStdio;
521  /// The standard error (stderr) handle type.
522  type Stderr: Stderr + IntoStdio;
523}
524
525#[cfg(feature = "async-process")]
526mod async_process_impl;
527
528/// Async process related implementations for `tokio` runtime.
529#[cfg(feature = "tokio")]
530#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
531pub mod tokio;
532
533/// Async process related implementations for `smol` runtime.
534#[cfg(feature = "smol")]
535#[cfg_attr(docsrs, doc(cfg(feature = "smol")))]
536pub mod smol;