Skip to main content

std/os/unix/
process.rs

1//! Unix-specific extensions to primitives in the [`std::process`] module.
2//!
3//! [`std::process`]: crate::process
4
5#![stable(feature = "rust1", since = "1.0.0")]
6
7use crate::ffi::OsStr;
8use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
9use crate::path::Path;
10#[cfg(doc)]
11use crate::process::{ExitStatus, ExitStatusError};
12use crate::sys::process::ChildPipe;
13use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner};
14use crate::{io, process, sys};
15
16cfg_select! {
17    any(target_os = "vxworks", target_os = "espidf", target_os = "horizon", target_os = "vita") => {
18        type UserId = u16;
19        type GroupId = u16;
20    }
21    any(target_os = "nto", target_os = "qnx") => {
22        // Both IDs are signed, see `sys/target_nto.h` of the QNX SDP.
23        // Only positive values should be used, see e.g.
24        // https://www.qnx.com/developers/docs/7.1/com.qnx.doc.neutrino.lib_ref/topic/s/setuid.html
25        type UserId = i32;
26        type GroupId = i32;
27    }
28    _ => {
29        type UserId = u32;
30        type GroupId = u32;
31    }
32}
33
34/// Unix-specific extensions to the [`process::Command`] builder.
35#[stable(feature = "rust1", since = "1.0.0")]
36pub impl(self) trait CommandExt {
37    /// Sets the child process's user ID. This translates to a
38    /// `setuid` call in the child process. Failure in the `setuid`
39    /// call will cause the spawn to fail.
40    ///
41    /// # Notes
42    ///
43    /// This will also trigger a call to `setgroups(0, NULL)` in the child
44    /// process if no groups have been specified.
45    /// This removes supplementary groups that might have given the child
46    /// unwanted permissions.
47    #[stable(feature = "rust1", since = "1.0.0")]
48    fn uid(&mut self, id: UserId) -> &mut process::Command;
49
50    /// Similar to `uid`, but sets the group ID of the child process. This has
51    /// the same semantics as the `uid` field.
52    #[stable(feature = "rust1", since = "1.0.0")]
53    fn gid(&mut self, id: GroupId) -> &mut process::Command;
54
55    /// Sets the supplementary group IDs for the calling process. Translates to
56    /// a `setgroups` call in the child process.
57    #[unstable(feature = "setgroups", issue = "90747")]
58    fn groups(&mut self, groups: &[GroupId]) -> &mut process::Command;
59
60    /// Schedules a closure to be run just before the `exec` function is
61    /// invoked.
62    ///
63    /// The closure is allowed to return an I/O error whose OS error code will
64    /// be communicated back to the parent and returned as an error from when
65    /// the spawn was requested.
66    ///
67    /// Multiple closures can be registered and they will be called in order of
68    /// their registration. If a closure returns `Err` then no further closures
69    /// will be called and the spawn operation will immediately return with a
70    /// failure.
71    ///
72    /// # Notes and Safety
73    ///
74    /// This closure will be run in the context of the child process after a
75    /// `fork`. This primarily means that any modifications made to memory on
76    /// behalf of this closure will **not** be visible to the parent process.
77    /// This is often a very constrained environment where normal operations
78    /// like `malloc`, accessing environment variables through [`std::env`]
79    /// or acquiring a mutex are not guaranteed to work (due to
80    /// other threads perhaps still running when the `fork` was run).
81    ///
82    /// Note that the list of allocating functions includes [`Error::new`] and
83    /// [`Error::other`]. To signal a non-trivial error, prefer [`panic!`].
84    ///
85    /// For further details refer to the [POSIX fork() specification]
86    /// and the equivalent documentation for any targeted
87    /// platform, especially the requirements around *async-signal-safety*.
88    ///
89    /// This also means that all resources such as file descriptors and
90    /// memory-mapped regions got duplicated. It is your responsibility to make
91    /// sure that the closure does not violate library invariants by making
92    /// invalid use of these duplicates.
93    ///
94    /// Panicking in the closure is safe only if all the format arguments for the
95    /// panic message can be safely formatted; this is because although
96    /// `Command` calls [`std::panic::always_abort`](crate::panic::always_abort)
97    /// before calling the pre_exec hook, panic will still try to format the
98    /// panic message.
99    ///
100    /// When this closure is run, aspects such as the stdio file descriptors and
101    /// working directory have successfully been changed, so output to these
102    /// locations might not appear where intended.
103    ///
104    /// [POSIX fork() specification]:
105    ///     https://pubs.opengroup.org/onlinepubs/9799919799/functions/fork.html
106    /// [`std::env`]: mod@crate::env
107    /// [`Error::new`]: ../../../io/struct.Error.html#method.new
108    /// [`Error::other`]: ../../../io/struct.Error.html#method.other
109    #[stable(feature = "process_pre_exec", since = "1.34.0")]
110    unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
111    where
112        F: FnMut() -> io::Result<()> + Send + Sync + 'static;
113
114    /// Schedules a closure to be run just before the `exec` function is
115    /// invoked.
116    ///
117    /// `before_exec` used to be a safe method, but it needs to be unsafe since the closure may only
118    /// perform operations that are *async-signal-safe*. Hence it got deprecated in favor of the
119    /// unsafe [`pre_exec`]. Meanwhile, Rust gained the ability to make an existing safe method
120    /// fully unsafe in a new edition, which is how `before_exec` became `unsafe`. It still also
121    /// remains deprecated; `pre_exec` should be used instead.
122    ///
123    /// [`pre_exec`]: CommandExt::pre_exec
124    #[stable(feature = "process_exec", since = "1.15.0")]
125    #[deprecated(since = "1.37.0", note = "should be unsafe, use `pre_exec` instead")]
126    #[rustc_deprecated_safe_2024(audit_that = "the closure is async-signal-safe")]
127    unsafe fn before_exec<F>(&mut self, f: F) -> &mut process::Command
128    where
129        F: FnMut() -> io::Result<()> + Send + Sync + 'static,
130    {
131        unsafe { self.pre_exec(f) }
132    }
133
134    /// Performs all the required setup by this `Command`, followed by calling
135    /// the `execvp` syscall.
136    ///
137    /// On success this function will not return, and otherwise it will return
138    /// an error indicating why the exec (or another part of the setup of the
139    /// `Command`) failed.
140    ///
141    /// `exec` not returning has the same implications as calling
142    /// [`process::exit`] – no destructors on the current stack or any other
143    /// thread’s stack will be run. Therefore, it is recommended to only call
144    /// `exec` at a point where it is fine to not run any destructors. Note,
145    /// that the `execvp` syscall independently guarantees that all memory is
146    /// freed and all file descriptors with the `CLOEXEC` option (set by default
147    /// on all file descriptors opened by the standard library) are closed.
148    ///
149    /// This function, unlike `spawn`, will **not** `fork` the process to create
150    /// a new child. Like spawn, however, the default behavior for the stdio
151    /// descriptors will be to inherit them from the current process.
152    ///
153    /// # Notes
154    ///
155    /// The process may be in a "broken state" if this function returns in
156    /// error. For example the working directory, environment variables, signal
157    /// handling settings, various user/group information, or aspects of stdio
158    /// file descriptors may have changed. If a "transactional spawn" is
159    /// required to gracefully handle errors it is recommended to use the
160    /// cross-platform `spawn` instead.
161    #[stable(feature = "process_exec2", since = "1.9.0")]
162    #[must_use]
163    fn exec(&mut self) -> io::Error;
164
165    /// Set executable argument
166    ///
167    /// Set the first process argument, `argv[0]`, to something other than the
168    /// default executable path.
169    #[stable(feature = "process_set_argv0", since = "1.45.0")]
170    fn arg0<S>(&mut self, arg: S) -> &mut process::Command
171    where
172        S: AsRef<OsStr>;
173
174    /// Sets the process group ID (PGID) of the child process. Equivalent to a
175    /// `setpgid` call in the child process, but may be more efficient.
176    ///
177    /// Process groups determine which processes receive signals.
178    ///
179    /// # Examples
180    ///
181    /// Pressing Ctrl-C in a terminal will send SIGINT to all processes in
182    /// the current foreground process group. By spawning the `sleep`
183    /// subprocess in a new process group, it will not receive SIGINT from the
184    /// terminal.
185    ///
186    /// The parent process could install a signal handler and manage the
187    /// subprocess on its own terms.
188    ///
189    /// A process group ID of 0 will use the process ID as the PGID.
190    ///
191    #[cfg_attr(target_family = "unix", doc = "```no_run")]
192    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
193    /// use std::process::Command;
194    /// use std::os::unix::process::CommandExt;
195    ///
196    /// Command::new("sleep")
197    ///     .arg("10")
198    ///     .process_group(0)
199    ///     .spawn()?
200    ///     .wait()?;
201    /// #
202    /// # Ok::<_, Box<dyn std::error::Error>>(())
203    /// ```
204    #[stable(feature = "process_set_process_group", since = "1.64.0")]
205    fn process_group(&mut self, pgroup: i32) -> &mut process::Command;
206
207    /// Set the root of the child process. This calls `chroot` in the child process before executing
208    /// the command.
209    ///
210    /// This happens before changing to the directory specified with
211    /// [`process::Command::current_dir`], and that directory will be relative to the new root.
212    ///
213    /// If no directory has been specified with [`process::Command::current_dir`], this will set the
214    /// directory to `/`, to avoid leaving the current directory outside the chroot. (This is an
215    /// intentional difference from the underlying `chroot` system call.)
216    ///
217    /// This typically requires privileges, such as root or a specific capability.
218    ///
219    /// Note that `chroot` is not guaranteed to be async-signal-safe on all OSes, and functions
220    /// called between `fork` and `exec` must be async-signal-safe. However, in practice, the
221    /// ability to `fork` then `chroot` then `exec` is a capability widely provided by Rust targets
222    /// and relied upon by numerous programs.
223    ///
224    /// `chroot` is not, by itself, a complete security or sandboxing measure. It may form some part
225    /// of a containment mechanism, but fully containing a process requires additional steps.
226    ///
227    /// See the [`chroot`] manual page for more details.
228    ///
229    /// [`chroot`]: https://man7.org/linux/man-pages/man2/chroot.2.html
230    ///
231    /// # Examples
232    ///
233    #[cfg_attr(target_family = "unix", doc = "```no_run")]
234    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
235    /// #![feature(process_chroot)]
236    /// use std::process::Command;
237    /// use std::os::unix::process::CommandExt;
238    ///
239    /// Command::new("binary-within-new-root")
240    ///    .chroot("/new-root")
241    ///    .spawn()?
242    ///    .wait()?;
243    /// #
244    /// # Ok::<_, Box<dyn std::error::Error>>(())
245    #[doc = "```"]
246    #[unstable(feature = "process_chroot", issue = "141298")]
247    fn chroot<P: AsRef<Path>>(&mut self, dir: P) -> &mut process::Command;
248
249    #[unstable(feature = "process_setsid", issue = "105376")]
250    fn setsid(&mut self, setsid: bool) -> &mut process::Command;
251}
252
253#[stable(feature = "rust1", since = "1.0.0")]
254impl CommandExt for process::Command {
255    fn uid(&mut self, id: UserId) -> &mut process::Command {
256        self.as_inner_mut().uid(id);
257        self
258    }
259
260    fn gid(&mut self, id: GroupId) -> &mut process::Command {
261        self.as_inner_mut().gid(id);
262        self
263    }
264
265    fn groups(&mut self, groups: &[GroupId]) -> &mut process::Command {
266        self.as_inner_mut().groups(groups);
267        self
268    }
269
270    unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
271    where
272        F: FnMut() -> io::Result<()> + Send + Sync + 'static,
273    {
274        self.as_inner_mut().pre_exec(Box::new(f));
275        self
276    }
277
278    fn exec(&mut self) -> io::Error {
279        // NOTE: This may *not* be safe to call after `libc::fork`, because it
280        // may allocate. That may be worth fixing at some point in the future.
281        self.as_inner_mut().exec(sys::process::Stdio::Inherit)
282    }
283
284    fn arg0<S>(&mut self, arg: S) -> &mut process::Command
285    where
286        S: AsRef<OsStr>,
287    {
288        self.as_inner_mut().set_arg_0(arg.as_ref());
289        self
290    }
291
292    fn process_group(&mut self, pgroup: i32) -> &mut process::Command {
293        self.as_inner_mut().pgroup(pgroup);
294        self
295    }
296
297    fn chroot<P: AsRef<Path>>(&mut self, dir: P) -> &mut process::Command {
298        self.as_inner_mut().chroot(dir.as_ref());
299        self
300    }
301
302    fn setsid(&mut self, setsid: bool) -> &mut process::Command {
303        self.as_inner_mut().setsid(setsid);
304        self
305    }
306}
307
308/// Unix-specific extensions to [`ExitStatus`] and [`ExitStatusError`].
309///
310/// On Unix, [`ExitStatus`] **does not necessarily represent an exit status**, as
311/// passed to the `_exit` system call or returned by
312/// [`ExitStatus::code()`](ExitStatus::code).  It represents **any wait status**
313/// as returned by one of the [`wait`] family of system
314/// calls.
315///
316/// A Unix wait status (a Rust [`ExitStatus`]) can represent a Unix exit status, but can also
317/// represent other kinds of process event.
318///
319/// [`wait`]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/wait.html
320#[stable(feature = "rust1", since = "1.0.0")]
321pub impl(self) trait ExitStatusExt {
322    /// Creates a new [`ExitStatus`] or [`ExitStatusError`] from the raw underlying integer status
323    /// value from [`wait`].
324    ///
325    /// The value should be a **wait status, not an exit status**.
326    ///
327    /// # Example
328    ///
329    /// A signal-terminated [`wait`] status carries the signal number, which [`ExitStatus::signal`]
330    /// recovers using the platform's [`WTERMSIG`][`wait`] macro. Note that the bit layout of a
331    /// wait status is **not** specified by POSIX and is platform-specific. By convention on most
332    /// Unix platforms, the signal number occupies the low 7 bits with the exit-code byte left
333    /// zero, so a bare signal number between 1 and 126 is treated as a signal-terminated wait
334    /// status. The following example relies on that convention and is therefore not guaranteed to
335    /// hold on every target:
336    ///
337    #[cfg_attr(target_family = "unix", doc = "```no_run")]
338    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
339    /// # if cfg!(target_os = "fuchsia") { return; }
340    /// use std::os::unix::process::ExitStatusExt;
341    /// use std::process::ExitStatus;
342    ///
343    /// let signal = 15; // SIGTERM
344    /// assert!(signal > 0 && signal < 0x7f, "not a valid Unix termination signal: {signal}");
345    ///
346    /// let status = ExitStatus::from_raw(signal);
347    /// assert!(!status.success());
348    /// assert_eq!(status.code(), None);
349    /// assert_eq!(status.signal(), Some(15));
350    /// ```
351    ///
352    /// Generating an [`ExitStatus`] with a given exit code (0-255) is system-dependent.
353    /// The value returned by [`ExitStatus::code`] is specified to come from applying the
354    /// [`WEXITSTATUS`][`wait`] macro, but there is no POSIX-specified constructor and the bit
355    /// layout is left unspecified. By near-universal convention every Unix libc stores the
356    /// 8-bit exit code in bits 8..16, so a status built with `(code & 0xff) << 8` will usually
357    /// round-trip back to the original exit code:
358    ///
359    #[cfg_attr(target_family = "unix", doc = "```no_run")]
360    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
361    /// # if cfg!(target_os = "fuchsia") { return; }
362    /// use std::os::unix::process::ExitStatusExt;
363    /// use std::process::ExitStatus;
364    ///
365    /// let code = 41;
366    /// let status = ExitStatus::from_raw((code & 0xff) << 8);
367    /// assert_eq!(status.code(), Some(41));
368    /// assert!(!status.success());
369    /// ```
370    ///
371    /// # Panics
372    ///
373    /// - `ExitStatusError::from_raw` panics on an attempt to make an [`ExitStatusError`] from a
374    ///    [`wait`] status of `0`.
375    /// - `ExitStatus::from_raw` always succeeds and never panics.
376    ///
377    /// [`wait`]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/wait.html
378    #[stable(feature = "exit_status_from", since = "1.12.0")]
379    fn from_raw(raw: i32) -> Self;
380
381    /// If the process was terminated by a signal, returns that signal.
382    ///
383    /// In other words, if [`WIFSIGNALED`][`wait`], this returns [`WTERMSIG`][`wait`]. For such a status,
384    /// [`ExitStatus::code`] returns `None`:
385    ///
386    #[cfg_attr(target_family = "unix", doc = "```no_run")]
387    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
388    /// # if cfg!(target_os = "fuchsia") { return; }
389    /// use std::os::unix::process::ExitStatusExt;
390    /// use std::process::ExitStatus;
391    ///
392    /// let sigterm = 15;
393    /// let status = ExitStatus::from_raw(sigterm);
394    /// assert_eq!(status.code(), None);
395    /// assert_eq!(status.signal(), Some(sigterm));
396    /// ```
397    ///
398    /// A process that receives a signal may catch and handle it, then exit normally with an
399    /// exit code. When that happens, `signal` returns `None`.
400    ///
401    /// Rust does not pass commands through a shell, such as `bash` and `sh`, but it
402    /// is possible to do so manually. When invoking a shell, the signal value indicates whether
403    /// the top-level shell itself received a terminating signal. If instead a command *within*
404    /// an invoked shell receives a terminating signal, many shells convert the signal number
405    /// into an exit code by adding 128. For example, a command run under `sh` that receives a
406    /// [`SIGTERM`] canonically causes the shell to report an exit code of `15 + 128`, i.e. `143`.
407    ///
408    /// [`SIGTERM`]: https://pubs.opengroup.org/onlinepubs/9799919799/utilities/kill.html
409    /// [`wait`]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/wait.html
410    #[stable(feature = "rust1", since = "1.0.0")]
411    fn signal(&self) -> Option<i32>;
412
413    /// If the process was terminated by a signal, says whether it dumped core.
414    #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
415    fn core_dumped(&self) -> bool;
416
417    /// If the process was stopped by a signal, returns that signal.
418    ///
419    /// In other words, if [`WIFSTOPPED`][`wait`], this returns [`WSTOPSIG`][`wait`].  This is only possible if the status came from
420    /// a [`wait`] system call which was passed [`WUNTRACED`][`wait`], and was then converted into an [`ExitStatus`].
421    ///
422    /// [`wait`]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/wait.html
423    #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
424    fn stopped_signal(&self) -> Option<i32>;
425
426    /// Whether the process was continued from a stopped status.
427    ///
428    /// I.e. [`WIFCONTINUED`][`wait`].  This is only possible if the status came from a [`wait`] system call
429    /// which was passed [`WCONTINUED`][`wait`], and was then converted into an [`ExitStatus`].
430    ///
431    /// [`wait`]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/wait.html
432    #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
433    fn continued(&self) -> bool;
434
435    /// Returns the underlying raw [`wait`] status.
436    ///
437    /// The returned integer is a **wait status, not an exit status**.
438    ///
439    /// [`wait`]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/wait.html
440    #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
441    fn into_raw(self) -> i32;
442}
443
444#[stable(feature = "rust1", since = "1.0.0")]
445impl ExitStatusExt for process::ExitStatus {
446    fn from_raw(raw: i32) -> Self {
447        process::ExitStatus::from_inner(From::from(raw))
448    }
449
450    fn signal(&self) -> Option<i32> {
451        self.as_inner().signal()
452    }
453
454    fn core_dumped(&self) -> bool {
455        self.as_inner().core_dumped()
456    }
457
458    fn stopped_signal(&self) -> Option<i32> {
459        self.as_inner().stopped_signal()
460    }
461
462    fn continued(&self) -> bool {
463        self.as_inner().continued()
464    }
465
466    fn into_raw(self) -> i32 {
467        self.as_inner().into_raw().into()
468    }
469}
470
471#[unstable(feature = "exit_status_error", issue = "84908")]
472impl ExitStatusExt for process::ExitStatusError {
473    fn from_raw(raw: i32) -> Self {
474        process::ExitStatus::from_raw(raw)
475            .exit_ok()
476            .expect_err("<ExitStatusError as ExitStatusExt>::from_raw(0) but zero is not an error")
477    }
478
479    fn signal(&self) -> Option<i32> {
480        self.into_status().signal()
481    }
482
483    fn core_dumped(&self) -> bool {
484        self.into_status().core_dumped()
485    }
486
487    fn stopped_signal(&self) -> Option<i32> {
488        self.into_status().stopped_signal()
489    }
490
491    fn continued(&self) -> bool {
492        self.into_status().continued()
493    }
494
495    fn into_raw(self) -> i32 {
496        self.into_status().into_raw()
497    }
498}
499
500#[unstable(feature = "unix_send_signal", issue = "141975")]
501pub impl(self) trait ChildExt {
502    /// Sends a signal to a child process.
503    ///
504    /// # Errors
505    ///
506    /// This function will return an error if the signal is invalid. The integer values associated
507    /// with signals are implementation-specific, so it's encouraged to use a crate that provides
508    /// posix bindings.
509    ///
510    /// # Examples
511    ///
512    #[cfg_attr(target_family = "unix", doc = "```no_run")]
513    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
514    /// #![feature(unix_send_signal)]
515    ///
516    /// use std::{io, os::unix::process::ChildExt, process::{Command, Stdio}};
517    ///
518    /// use libc::SIGTERM;
519    ///
520    /// fn main() -> io::Result<()> {
521    ///     # if cfg!(not(all(target_vendor = "apple", not(target_os = "macos")))) {
522    ///     let child = Command::new("cat").stdin(Stdio::piped()).spawn()?;
523    ///     child.send_signal(SIGTERM)?;
524    ///     # }
525    ///     Ok(())
526    /// }
527    /// ```
528    fn send_signal(&self, signal: i32) -> io::Result<()>;
529
530    /// Sends a signal to a child process's process group.
531    ///
532    /// # Errors
533    ///
534    /// This function will return an error if the signal is invalid or if the
535    /// child process does not have a process group. The integer values
536    /// associated with signals are implementation-specific, so it's encouraged
537    /// to use a crate that provides posix bindings.
538    ///
539    /// # Examples
540    ///
541    #[cfg_attr(target_family = "unix", doc = "```no_run")]
542    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
543    /// #![feature(unix_send_signal)]
544    ///
545    /// use std::{io, os::unix::process::{ChildExt, CommandExt}, process::{Command, Stdio}};
546    ///
547    /// use libc::SIGTERM;
548    ///
549    /// fn main() -> io::Result<()> {
550    ///     # if cfg!(not(all(target_vendor = "apple", not(target_os = "macos")))) {
551    ///     let child = Command::new("cat")
552    ///         .stdin(Stdio::piped())
553    ///         .process_group(0)
554    ///         .spawn()?;
555    ///     child.send_process_group_signal(SIGTERM)?;
556    ///     # }
557    ///     Ok(())
558    /// }
559    /// ```
560    #[unstable(feature = "unix_send_signal", issue = "141975")]
561    fn send_process_group_signal(&self, signal: i32) -> io::Result<()>;
562
563    /// Forces the child process's process group to exit.
564    ///
565    /// This is analogous to [`Child::kill`] but applies to every process in
566    /// the child process's process group.
567    ///
568    /// Use [`CommandExt::process_group`] to assign a child process to an
569    /// existing process group, or to make it the leader of a new process group.
570    /// By default spawned processes are in the parent's process group.
571    ///
572    /// # Examples
573    ///
574    #[cfg_attr(target_family = "unix", doc = "```no_run")]
575    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
576    /// #![feature(unix_kill_process_group)]
577    ///
578    /// use std::{os::unix::process::{ChildExt, CommandExt}, process::{Command, Stdio}};
579    ///
580    /// fn main() -> std::io::Result<()> {
581    ///     let mut child = Command::new("cat")
582    ///         .stdin(Stdio::piped())
583    ///         .process_group(0)
584    ///         .spawn()?;
585    ///     child.kill_process_group()?;
586    ///     Ok(())
587    /// }
588    /// ```
589    ///
590    /// [`Child::kill`]: process::Child::kill
591    #[unstable(feature = "unix_kill_process_group", issue = "156537")]
592    fn kill_process_group(&mut self) -> io::Result<()>;
593}
594
595#[unstable(feature = "unix_send_signal", issue = "141975")]
596impl ChildExt for process::Child {
597    fn send_signal(&self, signal: i32) -> io::Result<()> {
598        self.handle.send_signal(signal)
599    }
600
601    fn send_process_group_signal(&self, signal: i32) -> io::Result<()> {
602        self.handle.send_process_group_signal(signal)
603    }
604
605    #[cfg(not(target_os = "espidf"))]
606    fn kill_process_group(&mut self) -> io::Result<()> {
607        self.handle.send_process_group_signal(libc::SIGKILL)
608    }
609
610    #[cfg(target_os = "espidf")]
611    fn kill_process_group(&mut self) -> io::Result<()> {
612        Err(io::Error::new(
613            io::ErrorKind::Unsupported,
614            "process groups are not supported on espidf",
615        ))
616    }
617}
618
619#[stable(feature = "process_extensions", since = "1.2.0")]
620impl FromRawFd for process::Stdio {
621    #[inline]
622    unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio {
623        let fd = sys::fd::FileDesc::from_raw_fd(fd);
624        let io = sys::process::Stdio::Fd(fd);
625        process::Stdio::from_inner(io)
626    }
627}
628
629#[stable(feature = "io_safety", since = "1.63.0")]
630impl From<OwnedFd> for process::Stdio {
631    /// Takes ownership of a file descriptor and returns a [`Stdio`](process::Stdio)
632    /// that can attach a stream to it.
633    #[inline]
634    fn from(fd: OwnedFd) -> process::Stdio {
635        let fd = sys::fd::FileDesc::from_inner(fd);
636        let io = sys::process::Stdio::Fd(fd);
637        process::Stdio::from_inner(io)
638    }
639}
640
641#[stable(feature = "process_extensions", since = "1.2.0")]
642impl AsRawFd for process::ChildStdin {
643    #[inline]
644    fn as_raw_fd(&self) -> RawFd {
645        self.as_inner().as_raw_fd()
646    }
647}
648
649#[stable(feature = "process_extensions", since = "1.2.0")]
650impl AsRawFd for process::ChildStdout {
651    #[inline]
652    fn as_raw_fd(&self) -> RawFd {
653        self.as_inner().as_raw_fd()
654    }
655}
656
657#[stable(feature = "process_extensions", since = "1.2.0")]
658impl AsRawFd for process::ChildStderr {
659    #[inline]
660    fn as_raw_fd(&self) -> RawFd {
661        self.as_inner().as_raw_fd()
662    }
663}
664
665#[stable(feature = "into_raw_os", since = "1.4.0")]
666impl IntoRawFd for process::ChildStdin {
667    #[inline]
668    fn into_raw_fd(self) -> RawFd {
669        self.into_inner().into_inner().into_raw_fd()
670    }
671}
672
673#[stable(feature = "into_raw_os", since = "1.4.0")]
674impl IntoRawFd for process::ChildStdout {
675    #[inline]
676    fn into_raw_fd(self) -> RawFd {
677        self.into_inner().into_inner().into_raw_fd()
678    }
679}
680
681#[stable(feature = "into_raw_os", since = "1.4.0")]
682impl IntoRawFd for process::ChildStderr {
683    #[inline]
684    fn into_raw_fd(self) -> RawFd {
685        self.into_inner().into_inner().into_raw_fd()
686    }
687}
688
689#[stable(feature = "io_safety", since = "1.63.0")]
690impl AsFd for crate::process::ChildStdin {
691    #[inline]
692    fn as_fd(&self) -> BorrowedFd<'_> {
693        self.as_inner().as_fd()
694    }
695}
696
697#[stable(feature = "io_safety", since = "1.63.0")]
698impl From<crate::process::ChildStdin> for OwnedFd {
699    /// Takes ownership of a [`ChildStdin`](crate::process::ChildStdin)'s file descriptor.
700    #[inline]
701    fn from(child_stdin: crate::process::ChildStdin) -> OwnedFd {
702        child_stdin.into_inner().into_inner()
703    }
704}
705
706/// Creates a `ChildStdin` from the provided `OwnedFd`.
707///
708/// The provided file descriptor must point to a pipe
709/// with the `CLOEXEC` flag set.
710#[stable(feature = "child_stream_from_fd", since = "1.74.0")]
711impl From<OwnedFd> for process::ChildStdin {
712    #[inline]
713    fn from(fd: OwnedFd) -> process::ChildStdin {
714        let pipe = ChildPipe::from_inner(fd);
715        process::ChildStdin::from_inner(pipe)
716    }
717}
718
719#[stable(feature = "io_safety", since = "1.63.0")]
720impl AsFd for crate::process::ChildStdout {
721    #[inline]
722    fn as_fd(&self) -> BorrowedFd<'_> {
723        self.as_inner().as_fd()
724    }
725}
726
727#[stable(feature = "io_safety", since = "1.63.0")]
728impl From<crate::process::ChildStdout> for OwnedFd {
729    /// Takes ownership of a [`ChildStdout`](crate::process::ChildStdout)'s file descriptor.
730    #[inline]
731    fn from(child_stdout: crate::process::ChildStdout) -> OwnedFd {
732        child_stdout.into_inner().into_inner()
733    }
734}
735
736/// Creates a `ChildStdout` from the provided `OwnedFd`.
737///
738/// The provided file descriptor must point to a pipe
739/// with the `CLOEXEC` flag set.
740#[stable(feature = "child_stream_from_fd", since = "1.74.0")]
741impl From<OwnedFd> for process::ChildStdout {
742    #[inline]
743    fn from(fd: OwnedFd) -> process::ChildStdout {
744        let pipe = ChildPipe::from_inner(fd);
745        process::ChildStdout::from_inner(pipe)
746    }
747}
748
749#[stable(feature = "io_safety", since = "1.63.0")]
750impl AsFd for crate::process::ChildStderr {
751    #[inline]
752    fn as_fd(&self) -> BorrowedFd<'_> {
753        self.as_inner().as_fd()
754    }
755}
756
757#[stable(feature = "io_safety", since = "1.63.0")]
758impl From<crate::process::ChildStderr> for OwnedFd {
759    /// Takes ownership of a [`ChildStderr`](crate::process::ChildStderr)'s file descriptor.
760    #[inline]
761    fn from(child_stderr: crate::process::ChildStderr) -> OwnedFd {
762        child_stderr.into_inner().into_inner()
763    }
764}
765
766/// Creates a `ChildStderr` from the provided `OwnedFd`.
767///
768/// The provided file descriptor must point to a pipe
769/// with the `CLOEXEC` flag set.
770#[stable(feature = "child_stream_from_fd", since = "1.74.0")]
771impl From<OwnedFd> for process::ChildStderr {
772    #[inline]
773    fn from(fd: OwnedFd) -> process::ChildStderr {
774        let pipe = ChildPipe::from_inner(fd);
775        process::ChildStderr::from_inner(pipe)
776    }
777}
778
779/// Returns the OS-assigned process identifier associated with this process's parent.
780///
781/// # Example
782///
783#[cfg_attr(target_family = "unix", doc = "```")]
784#[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
785/// use std::os::unix::process;
786/// let parent = process::parent_id();
787/// println!("The parent process has ID {}", parent);
788/// ```
789#[must_use]
790#[stable(feature = "unix_ppid", since = "1.27.0")]
791pub fn parent_id() -> u32 {
792    crate::sys::process::getppid()
793}