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;