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 #[unstable(feature = "process_chroot", issue = "141298")]
217 fn chroot<P: AsRef<Path>>(&mut self, dir: P) -> &mut process::Command;
218
219 #[unstable(feature = "process_setsid", issue = "105376")]
220 fn setsid(&mut self, setsid: bool) -> &mut process::Command;
221}
222
223#[stable(feature = "rust1", since = "1.0.0")]
224impl CommandExt for process::Command {
225 fn uid(&mut self, id: UserId) -> &mut process::Command {
226 self.as_inner_mut().uid(id);
227 self
228 }
229
230 fn gid(&mut self, id: GroupId) -> &mut process::Command {
231 self.as_inner_mut().gid(id);
232 self
233 }
234
235 fn groups(&mut self, groups: &[GroupId]) -> &mut process::Command {
236 self.as_inner_mut().groups(groups);
237 self
238 }
239
240 unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
241 where
242 F: FnMut() -> io::Result<()> + Send + Sync + 'static,
243 {
244 self.as_inner_mut().pre_exec(Box::new(f));
245 self
246 }
247
248 fn exec(&mut self) -> io::Error {
249 // NOTE: This may *not* be safe to call after `libc::fork`, because it
250 // may allocate. That may be worth fixing at some point in the future.
251 self.as_inner_mut().exec(sys::process::Stdio::Inherit)
252 }
253
254 fn arg0<S>(&mut self, arg: S) -> &mut process::Command
255 where
256 S: AsRef<OsStr>,
257 {
258 self.as_inner_mut().set_arg_0(arg.as_ref());
259 self
260 }
261
262 fn process_group(&mut self, pgroup: i32) -> &mut process::Command {
263 self.as_inner_mut().pgroup(pgroup);
264 self
265 }
266
267 fn chroot<P: AsRef<Path>>(&mut self, dir: P) -> &mut process::Command {
268 self.as_inner_mut().chroot(dir.as_ref());
269 self
270 }
271
272 fn setsid(&mut self, setsid: bool) -> &mut process::Command {
273 self.as_inner_mut().setsid(setsid);
274 self
275 }
276}
277
278/// Unix-specific extensions to [`ExitStatus`] and [`ExitStatusError`].
279///
280/// On Unix, [`ExitStatus`] **does not necessarily represent an exit status**, as
281/// passed to the `_exit` system call or returned by
282/// [`ExitStatus::code()`](ExitStatus::code). It represents **any wait status**
283/// as returned by one of the [`wait`] family of system
284/// calls.
285///
286/// A Unix wait status (a Rust [`ExitStatus`]) can represent a Unix exit status, but can also
287/// represent other kinds of process event.
288///
289/// [`wait`]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/wait.html
290#[stable(feature = "rust1", since = "1.0.0")]
291pub impl(self) trait ExitStatusExt {
292 /// Creates a new [`ExitStatus`] or [`ExitStatusError`] from the raw underlying integer status
293 /// value from [`wait`].
294 ///
295 /// The value should be a **wait status, not an exit status**.
296 ///
297 /// # Example
298 ///
299 /// A signal-terminated [`wait`] status carries the signal number, which [`ExitStatus::signal`]
300 /// recovers using the platform's [`WTERMSIG`][`wait`] macro. Note that the bit layout of a
301 /// wait status is **not** specified by POSIX and is platform-specific. By convention on most
302 /// Unix platforms, the signal number occupies the low 7 bits with the exit-code byte left
303 /// zero, so a bare signal number between 1 and 126 is treated as a signal-terminated wait
304 /// status. The following example relies on that convention and is therefore not guaranteed to
305 /// hold on every target:
306 ///
307 #[cfg_attr(target_family = "unix", doc = "```no_run")]
308 #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
309 /// # if cfg!(target_os = "fuchsia") { return; }
310 /// use std::os::unix::process::ExitStatusExt;
311 /// use std::process::ExitStatus;
312 ///
313 /// let signal = 15; // SIGTERM
314 /// assert!(signal > 0 && signal < 0x7f, "not a valid Unix termination signal: {signal}");
315 ///
316 /// let status = ExitStatus::from_raw(signal);
317 /// assert!(!status.success());
318 /// assert_eq!(status.code(), None);
319 /// assert_eq!(status.signal(), Some(15));
320 /// ```
321 ///
322 /// Generating an [`ExitStatus`] with a given exit code (0-255) is system-dependent.
323 /// The value returned by [`ExitStatus::code`] is specified to come from applying the
324 /// [`WEXITSTATUS`][`wait`] macro, but there is no POSIX-specified constructor and the bit
325 /// layout is left unspecified. By near-universal convention every Unix libc stores the
326 /// 8-bit exit code in bits 8..16, so a status built with `(code & 0xff) << 8` will usually
327 /// round-trip back to the original exit code:
328 ///
329 #[cfg_attr(target_family = "unix", doc = "```no_run")]
330 #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
331 /// # if cfg!(target_os = "fuchsia") { return; }
332 /// use std::os::unix::process::ExitStatusExt;
333 /// use std::process::ExitStatus;
334 ///
335 /// let code = 41;
336 /// let status = ExitStatus::from_raw((code & 0xff) << 8);
337 /// assert_eq!(status.code(), Some(41));
338 /// assert!(!status.success());
339 /// ```
340 ///
341 /// # Panics
342 ///
343 /// - `ExitStatusError::from_raw` panics on an attempt to make an [`ExitStatusError`] from a
344 /// [`wait`] status of `0`.
345 /// - `ExitStatus::from_raw` always succeeds and never panics.
346 ///
347 /// [`wait`]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/wait.html
348 #[stable(feature = "exit_status_from", since = "1.12.0")]
349 fn from_raw(raw: i32) -> Self;
350
351 /// If the process was terminated by a signal, returns that signal.
352 ///
353 /// In other words, if [`WIFSIGNALED`][`wait`], this returns [`WTERMSIG`][`wait`]. For such a status,
354 /// [`ExitStatus::code`] returns `None`:
355 ///
356 #[cfg_attr(target_family = "unix", doc = "```no_run")]
357 #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
358 /// # if cfg!(target_os = "fuchsia") { return; }
359 /// use std::os::unix::process::ExitStatusExt;
360 /// use std::process::ExitStatus;
361 ///
362 /// let sigterm = 15;
363 /// let status = ExitStatus::from_raw(sigterm);
364 /// assert_eq!(status.code(), None);
365 /// assert_eq!(status.signal(), Some(sigterm));
366 /// ```
367 ///
368 /// A process that receives a signal may catch and handle it, then exit normally with an
369 /// exit code. When that happens, `signal` returns `None`.
370 ///
371 /// Rust does not pass commands through a shell, such as `bash` and `sh`, but it
372 /// is possible to do so manually. When invoking a shell, the signal value indicates whether
373 /// the top-level shell itself received a terminating signal. If instead a command *within*
374 /// an invoked shell receives a terminating signal, many shells convert the signal number
375 /// into an exit code by adding 128. For example, a command run under `sh` that receives a
376 /// [`SIGTERM`] canonically causes the shell to report an exit code of `15 + 128`, i.e. `143`.
377 ///
378 /// [`SIGTERM`]: https://pubs.opengroup.org/onlinepubs/9799919799/utilities/kill.html
379 /// [`wait`]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/wait.html
380 #[stable(feature = "rust1", since = "1.0.0")]
381 fn signal(&self) -> Option<i32>;
382
383 /// If the process was terminated by a signal, says whether it dumped core.
384 #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
385 fn core_dumped(&self) -> bool;
386
387 /// If the process was stopped by a signal, returns that signal.
388 ///
389 /// In other words, if [`WIFSTOPPED`][`wait`], this returns [`WSTOPSIG`][`wait`]. This is only possible if the status came from
390 /// a [`wait`] system call which was passed [`WUNTRACED`][`wait`], and was then converted into an [`ExitStatus`].
391 ///
392 /// [`wait`]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/wait.html
393 #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
394 fn stopped_signal(&self) -> Option<i32>;
395
396 /// Whether the process was continued from a stopped status.
397 ///
398 /// I.e. [`WIFCONTINUED`][`wait`]. This is only possible if the status came from a [`wait`] system call
399 /// which was passed [`WCONTINUED`][`wait`], and was then converted into an [`ExitStatus`].
400 ///
401 /// [`wait`]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/wait.html
402 #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
403 fn continued(&self) -> bool;
404
405 /// Returns the underlying raw [`wait`] status.
406 ///
407 /// The returned integer is a **wait status, not an exit status**.
408 ///
409 /// [`wait`]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/wait.html
410 #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
411 fn into_raw(self) -> i32;
412}
413
414#[stable(feature = "rust1", since = "1.0.0")]
415impl ExitStatusExt for process::ExitStatus {
416 fn from_raw(raw: i32) -> Self {
417 process::ExitStatus::from_inner(From::from(raw))
418 }
419
420 fn signal(&self) -> Option<i32> {
421 self.as_inner().signal()
422 }
423
424 fn core_dumped(&self) -> bool {
425 self.as_inner().core_dumped()
426 }
427
428 fn stopped_signal(&self) -> Option<i32> {
429 self.as_inner().stopped_signal()
430 }
431
432 fn continued(&self) -> bool {
433 self.as_inner().continued()
434 }
435
436 fn into_raw(self) -> i32 {
437 self.as_inner().into_raw().into()
438 }
439}
440
441#[unstable(feature = "exit_status_error", issue = "84908")]
442impl ExitStatusExt for process::ExitStatusError {
443 fn from_raw(raw: i32) -> Self {
444 process::ExitStatus::from_raw(raw)
445 .exit_ok()
446 .expect_err("<ExitStatusError as ExitStatusExt>::from_raw(0) but zero is not an error")
447 }
448
449 fn signal(&self) -> Option<i32> {
450 self.into_status().signal()
451 }
452
453 fn core_dumped(&self) -> bool {
454 self.into_status().core_dumped()
455 }
456
457 fn stopped_signal(&self) -> Option<i32> {
458 self.into_status().stopped_signal()
459 }
460
461 fn continued(&self) -> bool {
462 self.into_status().continued()
463 }
464
465 fn into_raw(self) -> i32 {
466 self.into_status().into_raw()
467 }
468}
469
470#[unstable(feature = "unix_send_signal", issue = "141975")]
471pub impl(self) trait ChildExt {
472 /// Sends a signal to a child process.
473 ///
474 /// # Errors
475 ///
476 /// This function will return an error if the signal is invalid. The integer values associated
477 /// with signals are implementation-specific, so it's encouraged to use a crate that provides
478 /// posix bindings.
479 ///
480 /// # Examples
481 ///
482 #[cfg_attr(target_family = "unix", doc = "```no_run")]
483 #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
484 /// #![feature(unix_send_signal)]
485 ///
486 /// use std::{io, os::unix::process::ChildExt, process::{Command, Stdio}};
487 ///
488 /// use libc::SIGTERM;
489 ///
490 /// fn main() -> io::Result<()> {
491 /// # if cfg!(not(all(target_vendor = "apple", not(target_os = "macos")))) {
492 /// let child = Command::new("cat").stdin(Stdio::piped()).spawn()?;
493 /// child.send_signal(SIGTERM)?;
494 /// # }
495 /// Ok(())
496 /// }
497 /// ```
498 fn send_signal(&self, signal: i32) -> io::Result<()>;
499
500 /// Sends a signal to a child process's process group.
501 ///
502 /// # Errors
503 ///
504 /// This function will return an error if the signal is invalid or if the
505 /// child process does not have a process group. The integer values
506 /// associated with signals are implementation-specific, so it's encouraged
507 /// to use a crate that provides posix bindings.
508 ///
509 /// # Examples
510 ///
511 #[cfg_attr(target_family = "unix", doc = "```no_run")]
512 #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
513 /// #![feature(unix_send_signal)]
514 ///
515 /// use std::{io, os::unix::process::{ChildExt, CommandExt}, process::{Command, Stdio}};
516 ///
517 /// use libc::SIGTERM;
518 ///
519 /// fn main() -> io::Result<()> {
520 /// # if cfg!(not(all(target_vendor = "apple", not(target_os = "macos")))) {
521 /// let child = Command::new("cat")
522 /// .stdin(Stdio::piped())
523 /// .process_group(0)
524 /// .spawn()?;
525 /// child.send_process_group_signal(SIGTERM)?;
526 /// # }
527 /// Ok(())
528 /// }
529 /// ```
530 #[unstable(feature = "unix_send_signal", issue = "141975")]
531 fn send_process_group_signal(&self, signal: i32) -> io::Result<()>;
532
533 /// Forces the child process's process group to exit.
534 ///
535 /// This is analogous to [`Child::kill`] but applies to every process in
536 /// the child process's process group.
537 ///
538 /// Use [`CommandExt::process_group`] to assign a child process to an
539 /// existing process group, or to make it the leader of a new process group.
540 /// By default spawned processes are in the parent's process group.
541 ///
542 /// # Examples
543 ///
544 #[cfg_attr(target_family = "unix", doc = "```no_run")]
545 #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
546 /// #![feature(unix_kill_process_group)]
547 ///
548 /// use std::{os::unix::process::{ChildExt, CommandExt}, process::{Command, Stdio}};
549 ///
550 /// fn main() -> std::io::Result<()> {
551 /// let mut child = Command::new("cat")
552 /// .stdin(Stdio::piped())
553 /// .process_group(0)
554 /// .spawn()?;
555 /// child.kill_process_group()?;
556 /// Ok(())
557 /// }
558 /// ```
559 ///
560 /// [`Child::kill`]: process::Child::kill
561 #[unstable(feature = "unix_kill_process_group", issue = "156537")]
562 fn kill_process_group(&mut self) -> io::Result<()>;
563}
564
565#[unstable(feature = "unix_send_signal", issue = "141975")]
566impl ChildExt for process::Child {
567 fn send_signal(&self, signal: i32) -> io::Result<()> {
568 self.handle.send_signal(signal)
569 }
570
571 fn send_process_group_signal(&self, signal: i32) -> io::Result<()> {
572 self.handle.send_process_group_signal(signal)
573 }
574
575 #[cfg(not(target_os = "espidf"))]
576 fn kill_process_group(&mut self) -> io::Result<()> {
577 self.handle.send_process_group_signal(libc::SIGKILL)
578 }
579
580 #[cfg(target_os = "espidf")]
581 fn kill_process_group(&mut self) -> io::Result<()> {
582 Err(io::Error::new(
583 io::ErrorKind::Unsupported,
584 "process groups are not supported on espidf",
585 ))
586 }
587}
588
589#[stable(feature = "process_extensions", since = "1.2.0")]
590impl FromRawFd for process::Stdio {
591 #[inline]
592 unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio {
593 let fd = sys::fd::FileDesc::from_raw_fd(fd);
594 let io = sys::process::Stdio::Fd(fd);
595 process::Stdio::from_inner(io)
596 }
597}
598
599#[stable(feature = "io_safety", since = "1.63.0")]
600impl From<OwnedFd> for process::Stdio {
601 /// Takes ownership of a file descriptor and returns a [`Stdio`](process::Stdio)
602 /// that can attach a stream to it.
603 #[inline]
604 fn from(fd: OwnedFd) -> process::Stdio {
605 let fd = sys::fd::FileDesc::from_inner(fd);
606 let io = sys::process::Stdio::Fd(fd);
607 process::Stdio::from_inner(io)
608 }
609}
610
611#[stable(feature = "process_extensions", since = "1.2.0")]
612impl AsRawFd for process::ChildStdin {
613 #[inline]
614 fn as_raw_fd(&self) -> RawFd {
615 self.as_inner().as_raw_fd()
616 }
617}
618
619#[stable(feature = "process_extensions", since = "1.2.0")]
620impl AsRawFd for process::ChildStdout {
621 #[inline]
622 fn as_raw_fd(&self) -> RawFd {
623 self.as_inner().as_raw_fd()
624 }
625}
626
627#[stable(feature = "process_extensions", since = "1.2.0")]
628impl AsRawFd for process::ChildStderr {
629 #[inline]
630 fn as_raw_fd(&self) -> RawFd {
631 self.as_inner().as_raw_fd()
632 }
633}
634
635#[stable(feature = "into_raw_os", since = "1.4.0")]
636impl IntoRawFd for process::ChildStdin {
637 #[inline]
638 fn into_raw_fd(self) -> RawFd {
639 self.into_inner().into_inner().into_raw_fd()
640 }
641}
642
643#[stable(feature = "into_raw_os", since = "1.4.0")]
644impl IntoRawFd for process::ChildStdout {
645 #[inline]
646 fn into_raw_fd(self) -> RawFd {
647 self.into_inner().into_inner().into_raw_fd()
648 }
649}
650
651#[stable(feature = "into_raw_os", since = "1.4.0")]
652impl IntoRawFd for process::ChildStderr {
653 #[inline]
654 fn into_raw_fd(self) -> RawFd {
655 self.into_inner().into_inner().into_raw_fd()
656 }
657}
658
659#[stable(feature = "io_safety", since = "1.63.0")]
660impl AsFd for crate::process::ChildStdin {
661 #[inline]
662 fn as_fd(&self) -> BorrowedFd<'_> {
663 self.as_inner().as_fd()
664 }
665}
666
667#[stable(feature = "io_safety", since = "1.63.0")]
668impl From<crate::process::ChildStdin> for OwnedFd {
669 /// Takes ownership of a [`ChildStdin`](crate::process::ChildStdin)'s file descriptor.
670 #[inline]
671 fn from(child_stdin: crate::process::ChildStdin) -> OwnedFd {
672 child_stdin.into_inner().into_inner()
673 }
674}
675
676/// Creates a `ChildStdin` from the provided `OwnedFd`.
677///
678/// The provided file descriptor must point to a pipe
679/// with the `CLOEXEC` flag set.
680#[stable(feature = "child_stream_from_fd", since = "1.74.0")]
681impl From<OwnedFd> for process::ChildStdin {
682 #[inline]
683 fn from(fd: OwnedFd) -> process::ChildStdin {
684 let pipe = ChildPipe::from_inner(fd);
685 process::ChildStdin::from_inner(pipe)
686 }
687}
688
689#[stable(feature = "io_safety", since = "1.63.0")]
690impl AsFd for crate::process::ChildStdout {
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::ChildStdout> for OwnedFd {
699 /// Takes ownership of a [`ChildStdout`](crate::process::ChildStdout)'s file descriptor.
700 #[inline]
701 fn from(child_stdout: crate::process::ChildStdout) -> OwnedFd {
702 child_stdout.into_inner().into_inner()
703 }
704}
705
706/// Creates a `ChildStdout` 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::ChildStdout {
712 #[inline]
713 fn from(fd: OwnedFd) -> process::ChildStdout {
714 let pipe = ChildPipe::from_inner(fd);
715 process::ChildStdout::from_inner(pipe)
716 }
717}
718
719#[stable(feature = "io_safety", since = "1.63.0")]
720impl AsFd for crate::process::ChildStderr {
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::ChildStderr> for OwnedFd {
729 /// Takes ownership of a [`ChildStderr`](crate::process::ChildStderr)'s file descriptor.
730 #[inline]
731 fn from(child_stderr: crate::process::ChildStderr) -> OwnedFd {
732 child_stderr.into_inner().into_inner()
733 }
734}
735
736/// Creates a `ChildStderr` 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::ChildStderr {
742 #[inline]
743 fn from(fd: OwnedFd) -> process::ChildStderr {
744 let pipe = ChildPipe::from_inner(fd);
745 process::ChildStderr::from_inner(pipe)
746 }
747}
748
749/// Returns the OS-assigned process identifier associated with this process's parent.
750#[must_use]
751#[stable(feature = "unix_ppid", since = "1.27.0")]
752pub fn parent_id() -> u32 {
753 crate::sys::process::getppid()
754}