1 | //! Linux-specific extensions to primitives in the [`std::process`] module. |
2 | //! |
3 | //! [`std::process`]: crate::process |
4 | |
5 | #![unstable (feature = "linux_pidfd" , issue = "82971" )] |
6 | |
7 | use crate::io::Result; |
8 | use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; |
9 | use crate::process; |
10 | use crate::sealed::Sealed; |
11 | #[cfg (not(doc))] |
12 | use crate::sys::fd::FileDesc; |
13 | use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; |
14 | |
15 | #[cfg (doc)] |
16 | struct FileDesc; |
17 | |
18 | /// This type represents a file descriptor that refers to a process. |
19 | /// |
20 | /// A `PidFd` can be obtained by setting the corresponding option on [`Command`] |
21 | /// with [`create_pidfd`]. Subsequently, the created pidfd can be retrieved |
22 | /// from the [`Child`] by calling [`pidfd`] or [`take_pidfd`]. |
23 | /// |
24 | /// Example: |
25 | /// ```no_run |
26 | /// #![feature(linux_pidfd)] |
27 | /// use std::os::linux::process::{CommandExt, ChildExt}; |
28 | /// use std::process::Command; |
29 | /// |
30 | /// let mut child = Command::new("echo" ) |
31 | /// .create_pidfd(true) |
32 | /// .spawn() |
33 | /// .expect("Failed to spawn child" ); |
34 | /// |
35 | /// let pidfd = child |
36 | /// .take_pidfd() |
37 | /// .expect("Failed to retrieve pidfd" ); |
38 | /// |
39 | /// // The file descriptor will be closed when `pidfd` is dropped. |
40 | /// ``` |
41 | /// Refer to the man page of [`pidfd_open(2)`] for further details. |
42 | /// |
43 | /// [`Command`]: process::Command |
44 | /// [`create_pidfd`]: CommandExt::create_pidfd |
45 | /// [`Child`]: process::Child |
46 | /// [`pidfd`]: fn@ChildExt::pidfd |
47 | /// [`take_pidfd`]: ChildExt::take_pidfd |
48 | /// [`pidfd_open(2)`]: https://man7.org/linux/man-pages/man2/pidfd_open.2.html |
49 | #[derive (Debug)] |
50 | pub struct PidFd { |
51 | inner: FileDesc, |
52 | } |
53 | |
54 | impl AsInner<FileDesc> for PidFd { |
55 | #[inline ] |
56 | fn as_inner(&self) -> &FileDesc { |
57 | &self.inner |
58 | } |
59 | } |
60 | |
61 | impl FromInner<FileDesc> for PidFd { |
62 | fn from_inner(inner: FileDesc) -> PidFd { |
63 | PidFd { inner } |
64 | } |
65 | } |
66 | |
67 | impl IntoInner<FileDesc> for PidFd { |
68 | fn into_inner(self) -> FileDesc { |
69 | self.inner |
70 | } |
71 | } |
72 | |
73 | impl AsRawFd for PidFd { |
74 | #[inline ] |
75 | fn as_raw_fd(&self) -> RawFd { |
76 | self.as_inner().as_raw_fd() |
77 | } |
78 | } |
79 | |
80 | impl FromRawFd for PidFd { |
81 | unsafe fn from_raw_fd(fd: RawFd) -> Self { |
82 | Self::from_inner(FileDesc::from_raw_fd(fd)) |
83 | } |
84 | } |
85 | |
86 | impl IntoRawFd for PidFd { |
87 | fn into_raw_fd(self) -> RawFd { |
88 | self.into_inner().into_raw_fd() |
89 | } |
90 | } |
91 | |
92 | impl AsFd for PidFd { |
93 | fn as_fd(&self) -> BorrowedFd<'_> { |
94 | self.as_inner().as_fd() |
95 | } |
96 | } |
97 | |
98 | impl From<OwnedFd> for PidFd { |
99 | fn from(fd: OwnedFd) -> Self { |
100 | Self::from_inner(FileDesc::from_inner(fd)) |
101 | } |
102 | } |
103 | |
104 | impl From<PidFd> for OwnedFd { |
105 | fn from(pid_fd: PidFd) -> Self { |
106 | pid_fd.into_inner().into_inner() |
107 | } |
108 | } |
109 | |
110 | /// Os-specific extensions for [`Child`] |
111 | /// |
112 | /// [`Child`]: process::Child |
113 | pub trait ChildExt: Sealed { |
114 | /// Obtains a reference to the [`PidFd`] created for this [`Child`], if available. |
115 | /// |
116 | /// A pidfd will only be available if its creation was requested with |
117 | /// [`create_pidfd`] when the corresponding [`Command`] was created. |
118 | /// |
119 | /// Even if requested, a pidfd may not be available due to an older |
120 | /// version of Linux being in use, or if some other error occurred. |
121 | /// |
122 | /// [`Command`]: process::Command |
123 | /// [`create_pidfd`]: CommandExt::create_pidfd |
124 | /// [`Child`]: process::Child |
125 | fn pidfd(&self) -> Result<&PidFd>; |
126 | |
127 | /// Takes ownership of the [`PidFd`] created for this [`Child`], if available. |
128 | /// |
129 | /// A pidfd will only be available if its creation was requested with |
130 | /// [`create_pidfd`] when the corresponding [`Command`] was created. |
131 | /// |
132 | /// Even if requested, a pidfd may not be available due to an older |
133 | /// version of Linux being in use, or if some other error occurred. |
134 | /// |
135 | /// [`Command`]: process::Command |
136 | /// [`create_pidfd`]: CommandExt::create_pidfd |
137 | /// [`Child`]: process::Child |
138 | fn take_pidfd(&mut self) -> Result<PidFd>; |
139 | } |
140 | |
141 | /// Os-specific extensions for [`Command`] |
142 | /// |
143 | /// [`Command`]: process::Command |
144 | pub trait CommandExt: Sealed { |
145 | /// Sets whether a [`PidFd`](struct@PidFd) should be created for the [`Child`] |
146 | /// spawned by this [`Command`]. |
147 | /// By default, no pidfd will be created. |
148 | /// |
149 | /// The pidfd can be retrieved from the child with [`pidfd`] or [`take_pidfd`]. |
150 | /// |
151 | /// A pidfd will only be created if it is possible to do so |
152 | /// in a guaranteed race-free manner. Otherwise, [`pidfd`] will return an error. |
153 | /// |
154 | /// If a pidfd has been successfully created and not been taken from the `Child` |
155 | /// then calls to `kill()`, `wait()` and `try_wait()` will use the pidfd |
156 | /// instead of the pid. This can prevent pid recycling races, e.g. |
157 | /// those caused by rogue libraries in the same process prematurely reaping |
158 | /// zombie children via `waitpid(-1, ...)` calls. |
159 | /// |
160 | /// [`Command`]: process::Command |
161 | /// [`Child`]: process::Child |
162 | /// [`pidfd`]: fn@ChildExt::pidfd |
163 | /// [`take_pidfd`]: ChildExt::take_pidfd |
164 | fn create_pidfd(&mut self, val: bool) -> &mut process::Command; |
165 | } |
166 | |
167 | impl CommandExt for process::Command { |
168 | fn create_pidfd(&mut self, val: bool) -> &mut process::Command { |
169 | self.as_inner_mut().create_pidfd(val); |
170 | self |
171 | } |
172 | } |
173 | |