]>
Commit | Line | Data |
---|---|---|
c295e0f8 XL |
1 | //! Unix-specific extensions to primitives in the [`std::process`] module. |
2 | //! | |
3 | //! [`std::process`]: crate::process | |
d9579d0f AL |
4 | |
5 | #![stable(feature = "rust1", since = "1.0.0")] | |
6 | ||
60c5eb7d | 7 | use crate::ffi::OsStr; |
532ac7d7 | 8 | use crate::io; |
94222f64 | 9 | use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; |
532ac7d7 | 10 | use crate::process; |
6a06907d | 11 | use crate::sealed::Sealed; |
532ac7d7 | 12 | use crate::sys; |
60c5eb7d | 13 | use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; |
d9579d0f | 14 | |
923072b8 FG |
15 | #[cfg(not(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon")))] |
16 | type UserId = u32; | |
17 | #[cfg(not(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon")))] | |
18 | type GroupId = u32; | |
19 | ||
20 | #[cfg(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon"))] | |
21 | type UserId = u16; | |
22 | #[cfg(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon"))] | |
23 | type GroupId = u16; | |
24 | ||
83c7162d | 25 | /// Unix-specific extensions to the [`process::Command`] builder. |
6a06907d XL |
26 | /// |
27 | /// This trait is sealed: it cannot be implemented outside the standard library. | |
28 | /// This is so that future additional methods are not breaking changes. | |
d9579d0f | 29 | #[stable(feature = "rust1", since = "1.0.0")] |
6a06907d | 30 | pub trait CommandExt: Sealed { |
9fa01778 | 31 | /// Sets the child process's user ID. This translates to a |
d9579d0f AL |
32 | /// `setuid` call in the child process. Failure in the `setuid` |
33 | /// call will cause the spawn to fail. | |
34 | #[stable(feature = "rust1", since = "1.0.0")] | |
923072b8 | 35 | fn uid(&mut self, id: UserId) -> &mut process::Command; |
d9579d0f | 36 | |
9fa01778 | 37 | /// Similar to `uid`, but sets the group ID of the child process. This has |
d9579d0f AL |
38 | /// the same semantics as the `uid` field. |
39 | #[stable(feature = "rust1", since = "1.0.0")] | |
923072b8 | 40 | fn gid(&mut self, id: GroupId) -> &mut process::Command; |
e9174d1e | 41 | |
5869c6ff XL |
42 | /// Sets the supplementary group IDs for the calling process. Translates to |
43 | /// a `setgroups` call in the child process. | |
3c0e092e | 44 | #[unstable(feature = "setgroups", issue = "90747")] |
923072b8 | 45 | fn groups(&mut self, groups: &[GroupId]) -> &mut process::Command; |
5869c6ff | 46 | |
7453a54e SL |
47 | /// Schedules a closure to be run just before the `exec` function is |
48 | /// invoked. | |
49 | /// | |
50 | /// The closure is allowed to return an I/O error whose OS error code will | |
51 | /// be communicated back to the parent and returned as an error from when | |
52 | /// the spawn was requested. | |
53 | /// | |
54 | /// Multiple closures can be registered and they will be called in order of | |
55 | /// their registration. If a closure returns `Err` then no further closures | |
56 | /// will be called and the spawn operation will immediately return with a | |
57 | /// failure. | |
58 | /// | |
9fa01778 | 59 | /// # Notes and Safety |
7453a54e SL |
60 | /// |
61 | /// This closure will be run in the context of the child process after a | |
3b2f2976 | 62 | /// `fork`. This primarily means that any modifications made to memory on |
7453a54e SL |
63 | /// behalf of this closure will **not** be visible to the parent process. |
64 | /// This is often a very constrained environment where normal operations | |
6a06907d XL |
65 | /// like `malloc`, accessing environment variables through [`std::env`] |
66 | /// or acquiring a mutex are not guaranteed to work (due to | |
7453a54e SL |
67 | /// other threads perhaps still running when the `fork` was run). |
68 | /// | |
6a06907d XL |
69 | /// For further details refer to the [POSIX fork() specification] |
70 | /// and the equivalent documentation for any targeted | |
71 | /// platform, especially the requirements around *async-signal-safety*. | |
72 | /// | |
9fa01778 XL |
73 | /// This also means that all resources such as file descriptors and |
74 | /// memory-mapped regions got duplicated. It is your responsibility to make | |
75 | /// sure that the closure does not violate library invariants by making | |
76 | /// invalid use of these duplicates. | |
77 | /// | |
17df50a5 XL |
78 | /// Panicking in the closure is safe only if all the format arguments for the |
79 | /// panic message can be safely formatted; this is because although | |
80 | /// `Command` calls [`std::panic::always_abort`](crate::panic::always_abort) | |
81 | /// before calling the pre_exec hook, panic will still try to format the | |
82 | /// panic message. | |
83 | /// | |
7453a54e SL |
84 | /// When this closure is run, aspects such as the stdio file descriptors and |
85 | /// working directory have successfully been changed, so output to these | |
94222f64 | 86 | /// locations might not appear where intended. |
6a06907d XL |
87 | /// |
88 | /// [POSIX fork() specification]: | |
89 | /// https://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html | |
90 | /// [`std::env`]: mod@crate::env | |
9fa01778 XL |
91 | #[stable(feature = "process_pre_exec", since = "1.34.0")] |
92 | unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command | |
60c5eb7d XL |
93 | where |
94 | F: FnMut() -> io::Result<()> + Send + Sync + 'static; | |
9fa01778 XL |
95 | |
96 | /// Schedules a closure to be run just before the `exec` function is | |
97 | /// invoked. | |
98 | /// | |
99 | /// This method is stable and usable, but it should be unsafe. To fix | |
100 | /// that, it got deprecated in favor of the unsafe [`pre_exec`]. | |
101 | /// | |
3dfed10e | 102 | /// [`pre_exec`]: CommandExt::pre_exec |
476ff2be | 103 | #[stable(feature = "process_exec", since = "1.15.0")] |
04454e1e | 104 | #[deprecated(since = "1.37.0", note = "should be unsafe, use `pre_exec` instead")] |
7453a54e | 105 | fn before_exec<F>(&mut self, f: F) -> &mut process::Command |
60c5eb7d XL |
106 | where |
107 | F: FnMut() -> io::Result<()> + Send + Sync + 'static, | |
9fa01778 XL |
108 | { |
109 | unsafe { self.pre_exec(f) } | |
110 | } | |
7453a54e SL |
111 | |
112 | /// Performs all the required setup by this `Command`, followed by calling | |
113 | /// the `execvp` syscall. | |
114 | /// | |
115 | /// On success this function will not return, and otherwise it will return | |
116 | /// an error indicating why the exec (or another part of the setup of the | |
117 | /// `Command`) failed. | |
118 | /// | |
8bb4bdeb XL |
119 | /// `exec` not returning has the same implications as calling |
120 | /// [`process::exit`] – no destructors on the current stack or any other | |
121 | /// thread’s stack will be run. Therefore, it is recommended to only call | |
122 | /// `exec` at a point where it is fine to not run any destructors. Note, | |
123 | /// that the `execvp` syscall independently guarantees that all memory is | |
124 | /// freed and all file descriptors with the `CLOEXEC` option (set by default | |
125 | /// on all file descriptors opened by the standard library) are closed. | |
126 | /// | |
7453a54e SL |
127 | /// This function, unlike `spawn`, will **not** `fork` the process to create |
128 | /// a new child. Like spawn, however, the default behavior for the stdio | |
129 | /// descriptors will be to inherited from the current process. | |
130 | /// | |
131 | /// # Notes | |
132 | /// | |
133 | /// The process may be in a "broken state" if this function returns in | |
134 | /// error. For example the working directory, environment variables, signal | |
135 | /// handling settings, various user/group information, or aspects of stdio | |
136 | /// file descriptors may have changed. If a "transactional spawn" is | |
137 | /// required to gracefully handle errors it is recommended to use the | |
138 | /// cross-platform `spawn` instead. | |
54a0048b | 139 | #[stable(feature = "process_exec2", since = "1.9.0")] |
7453a54e | 140 | fn exec(&mut self) -> io::Error; |
60c5eb7d XL |
141 | |
142 | /// Set executable argument | |
143 | /// | |
144 | /// Set the first process argument, `argv[0]`, to something other than the | |
145 | /// default executable path. | |
f9f354fc | 146 | #[stable(feature = "process_set_argv0", since = "1.45.0")] |
60c5eb7d XL |
147 | fn arg0<S>(&mut self, arg: S) -> &mut process::Command |
148 | where | |
149 | S: AsRef<OsStr>; | |
5e7ed085 FG |
150 | |
151 | /// Sets the process group ID of the child process. Translates to a `setpgid` call in the child | |
152 | /// process. | |
153 | #[unstable(feature = "process_set_process_group", issue = "93857")] | |
154 | fn process_group(&mut self, pgroup: i32) -> &mut process::Command; | |
d9579d0f AL |
155 | } |
156 | ||
157 | #[stable(feature = "rust1", since = "1.0.0")] | |
158 | impl CommandExt for process::Command { | |
923072b8 | 159 | fn uid(&mut self, id: UserId) -> &mut process::Command { |
7453a54e | 160 | self.as_inner_mut().uid(id); |
d9579d0f AL |
161 | self |
162 | } | |
163 | ||
923072b8 | 164 | fn gid(&mut self, id: GroupId) -> &mut process::Command { |
7453a54e | 165 | self.as_inner_mut().gid(id); |
d9579d0f AL |
166 | self |
167 | } | |
e9174d1e | 168 | |
923072b8 | 169 | fn groups(&mut self, groups: &[GroupId]) -> &mut process::Command { |
5869c6ff XL |
170 | self.as_inner_mut().groups(groups); |
171 | self | |
172 | } | |
173 | ||
9fa01778 | 174 | unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command |
60c5eb7d XL |
175 | where |
176 | F: FnMut() -> io::Result<()> + Send + Sync + 'static, | |
7453a54e | 177 | { |
9fa01778 | 178 | self.as_inner_mut().pre_exec(Box::new(f)); |
e9174d1e SL |
179 | self |
180 | } | |
7453a54e SL |
181 | |
182 | fn exec(&mut self) -> io::Error { | |
6a06907d XL |
183 | // NOTE: This may *not* be safe to call after `libc::fork`, because it |
184 | // may allocate. That may be worth fixing at some point in the future. | |
7453a54e SL |
185 | self.as_inner_mut().exec(sys::process::Stdio::Inherit) |
186 | } | |
60c5eb7d XL |
187 | |
188 | fn arg0<S>(&mut self, arg: S) -> &mut process::Command | |
189 | where | |
190 | S: AsRef<OsStr>, | |
191 | { | |
192 | self.as_inner_mut().set_arg_0(arg.as_ref()); | |
193 | self | |
194 | } | |
5e7ed085 FG |
195 | |
196 | fn process_group(&mut self, pgroup: i32) -> &mut process::Command { | |
197 | self.as_inner_mut().pgroup(pgroup); | |
198 | self | |
199 | } | |
d9579d0f AL |
200 | } |
201 | ||
17df50a5 XL |
202 | /// Unix-specific extensions to [`process::ExitStatus`] and |
203 | /// [`ExitStatusError`](process::ExitStatusError). | |
5869c6ff | 204 | /// |
17df50a5 | 205 | /// On Unix, `ExitStatus` **does not necessarily represent an exit status**, as |
3c0e092e | 206 | /// passed to the `_exit` system call or returned by |
17df50a5 XL |
207 | /// [`ExitStatus::code()`](crate::process::ExitStatus::code). It represents **any wait status** |
208 | /// as returned by one of the `wait` family of system | |
209 | /// calls. | |
6a06907d | 210 | /// |
17df50a5 XL |
211 | /// A Unix wait status (a Rust `ExitStatus`) can represent a Unix exit status, but can also |
212 | /// represent other kinds of process event. | |
6a06907d | 213 | /// |
5869c6ff XL |
214 | /// This trait is sealed: it cannot be implemented outside the standard library. |
215 | /// This is so that future additional methods are not breaking changes. | |
d9579d0f | 216 | #[stable(feature = "rust1", since = "1.0.0")] |
6a06907d | 217 | pub trait ExitStatusExt: Sealed { |
17df50a5 XL |
218 | /// Creates a new `ExitStatus` or `ExitStatusError` from the raw underlying integer status |
219 | /// value from `wait` | |
6a06907d XL |
220 | /// |
221 | /// The value should be a **wait status, not an exit status**. | |
17df50a5 XL |
222 | /// |
223 | /// # Panics | |
224 | /// | |
225 | /// Panics on an attempt to make an `ExitStatusError` from a wait status of `0`. | |
226 | /// | |
136023e0 | 227 | /// Making an `ExitStatus` always succeeds and never panics. |
5bcae85e | 228 | #[stable(feature = "exit_status_from", since = "1.12.0")] |
a7813a04 XL |
229 | fn from_raw(raw: i32) -> Self; |
230 | ||
d9579d0f | 231 | /// If the process was terminated by a signal, returns that signal. |
5869c6ff XL |
232 | /// |
233 | /// In other words, if `WIFSIGNALED`, this returns `WTERMSIG`. | |
d9579d0f AL |
234 | #[stable(feature = "rust1", since = "1.0.0")] |
235 | fn signal(&self) -> Option<i32>; | |
5869c6ff XL |
236 | |
237 | /// If the process was terminated by a signal, says whether it dumped core. | |
3c0e092e | 238 | #[stable(feature = "unix_process_wait_more", since = "1.58.0")] |
5869c6ff XL |
239 | fn core_dumped(&self) -> bool; |
240 | ||
241 | /// If the process was stopped by a signal, returns that signal. | |
242 | /// | |
243 | /// In other words, if `WIFSTOPPED`, this returns `WSTOPSIG`. This is only possible if the status came from | |
cdc7bbd5 | 244 | /// a `wait` system call which was passed `WUNTRACED`, and was then converted into an `ExitStatus`. |
3c0e092e | 245 | #[stable(feature = "unix_process_wait_more", since = "1.58.0")] |
5869c6ff XL |
246 | fn stopped_signal(&self) -> Option<i32>; |
247 | ||
248 | /// Whether the process was continued from a stopped status. | |
249 | /// | |
250 | /// Ie, `WIFCONTINUED`. This is only possible if the status came from a `wait` system call | |
cdc7bbd5 | 251 | /// which was passed `WCONTINUED`, and was then converted into an `ExitStatus`. |
3c0e092e | 252 | #[stable(feature = "unix_process_wait_more", since = "1.58.0")] |
5869c6ff XL |
253 | fn continued(&self) -> bool; |
254 | ||
255 | /// Returns the underlying raw `wait` status. | |
6a06907d XL |
256 | /// |
257 | /// The returned integer is a **wait status, not an exit status**. | |
3c0e092e | 258 | #[stable(feature = "unix_process_wait_more", since = "1.58.0")] |
5869c6ff | 259 | fn into_raw(self) -> i32; |
d9579d0f AL |
260 | } |
261 | ||
262 | #[stable(feature = "rust1", since = "1.0.0")] | |
263 | impl ExitStatusExt for process::ExitStatus { | |
a7813a04 XL |
264 | fn from_raw(raw: i32) -> Self { |
265 | process::ExitStatus::from_inner(From::from(raw)) | |
266 | } | |
267 | ||
d9579d0f | 268 | fn signal(&self) -> Option<i32> { |
92a42be0 | 269 | self.as_inner().signal() |
d9579d0f | 270 | } |
5869c6ff XL |
271 | |
272 | fn core_dumped(&self) -> bool { | |
273 | self.as_inner().core_dumped() | |
274 | } | |
275 | ||
276 | fn stopped_signal(&self) -> Option<i32> { | |
277 | self.as_inner().stopped_signal() | |
278 | } | |
279 | ||
280 | fn continued(&self) -> bool { | |
281 | self.as_inner().continued() | |
282 | } | |
283 | ||
284 | fn into_raw(self) -> i32 { | |
285 | self.as_inner().into_raw().into() | |
286 | } | |
d9579d0f | 287 | } |
62682a34 | 288 | |
17df50a5 XL |
289 | #[unstable(feature = "exit_status_error", issue = "84908")] |
290 | impl ExitStatusExt for process::ExitStatusError { | |
291 | fn from_raw(raw: i32) -> Self { | |
292 | process::ExitStatus::from_raw(raw) | |
293 | .exit_ok() | |
294 | .expect_err("<ExitStatusError as ExitStatusExt>::from_raw(0) but zero is not an error") | |
295 | } | |
296 | ||
297 | fn signal(&self) -> Option<i32> { | |
298 | self.into_status().signal() | |
299 | } | |
300 | ||
301 | fn core_dumped(&self) -> bool { | |
302 | self.into_status().core_dumped() | |
303 | } | |
304 | ||
305 | fn stopped_signal(&self) -> Option<i32> { | |
306 | self.into_status().stopped_signal() | |
307 | } | |
308 | ||
309 | fn continued(&self) -> bool { | |
310 | self.into_status().continued() | |
311 | } | |
312 | ||
313 | fn into_raw(self) -> i32 { | |
314 | self.into_status().into_raw() | |
315 | } | |
316 | } | |
317 | ||
62682a34 SL |
318 | #[stable(feature = "process_extensions", since = "1.2.0")] |
319 | impl FromRawFd for process::Stdio { | |
cdc7bbd5 | 320 | #[inline] |
62682a34 | 321 | unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio { |
94222f64 XL |
322 | let fd = sys::fd::FileDesc::from_raw_fd(fd); |
323 | let io = sys::process::Stdio::Fd(fd); | |
324 | process::Stdio::from_inner(io) | |
325 | } | |
326 | } | |
327 | ||
923072b8 | 328 | #[stable(feature = "io_safety", since = "1.63.0")] |
94222f64 XL |
329 | impl From<OwnedFd> for process::Stdio { |
330 | #[inline] | |
331 | fn from(fd: OwnedFd) -> process::Stdio { | |
332 | let fd = sys::fd::FileDesc::from_inner(fd); | |
7453a54e SL |
333 | let io = sys::process::Stdio::Fd(fd); |
334 | process::Stdio::from_inner(io) | |
62682a34 SL |
335 | } |
336 | } | |
337 | ||
338 | #[stable(feature = "process_extensions", since = "1.2.0")] | |
339 | impl AsRawFd for process::ChildStdin { | |
cdc7bbd5 | 340 | #[inline] |
62682a34 | 341 | fn as_raw_fd(&self) -> RawFd { |
94222f64 | 342 | self.as_inner().as_raw_fd() |
62682a34 SL |
343 | } |
344 | } | |
345 | ||
346 | #[stable(feature = "process_extensions", since = "1.2.0")] | |
347 | impl AsRawFd for process::ChildStdout { | |
cdc7bbd5 | 348 | #[inline] |
62682a34 | 349 | fn as_raw_fd(&self) -> RawFd { |
94222f64 | 350 | self.as_inner().as_raw_fd() |
62682a34 SL |
351 | } |
352 | } | |
353 | ||
354 | #[stable(feature = "process_extensions", since = "1.2.0")] | |
355 | impl AsRawFd for process::ChildStderr { | |
cdc7bbd5 | 356 | #[inline] |
62682a34 | 357 | fn as_raw_fd(&self) -> RawFd { |
94222f64 | 358 | self.as_inner().as_raw_fd() |
62682a34 SL |
359 | } |
360 | } | |
c1a9b12d | 361 | |
c30ab7b3 | 362 | #[stable(feature = "into_raw_os", since = "1.4.0")] |
c1a9b12d | 363 | impl IntoRawFd for process::ChildStdin { |
cdc7bbd5 | 364 | #[inline] |
c1a9b12d | 365 | fn into_raw_fd(self) -> RawFd { |
94222f64 | 366 | self.into_inner().into_inner().into_raw_fd() |
c1a9b12d SL |
367 | } |
368 | } | |
369 | ||
c30ab7b3 | 370 | #[stable(feature = "into_raw_os", since = "1.4.0")] |
c1a9b12d | 371 | impl IntoRawFd for process::ChildStdout { |
cdc7bbd5 | 372 | #[inline] |
c1a9b12d | 373 | fn into_raw_fd(self) -> RawFd { |
94222f64 | 374 | self.into_inner().into_inner().into_raw_fd() |
c1a9b12d SL |
375 | } |
376 | } | |
377 | ||
c30ab7b3 | 378 | #[stable(feature = "into_raw_os", since = "1.4.0")] |
c1a9b12d | 379 | impl IntoRawFd for process::ChildStderr { |
cdc7bbd5 | 380 | #[inline] |
c1a9b12d | 381 | fn into_raw_fd(self) -> RawFd { |
94222f64 XL |
382 | self.into_inner().into_inner().into_raw_fd() |
383 | } | |
384 | } | |
385 | ||
923072b8 | 386 | #[stable(feature = "io_safety", since = "1.63.0")] |
94222f64 XL |
387 | impl AsFd for crate::process::ChildStdin { |
388 | #[inline] | |
389 | fn as_fd(&self) -> BorrowedFd<'_> { | |
390 | self.as_inner().as_fd() | |
391 | } | |
392 | } | |
393 | ||
923072b8 | 394 | #[stable(feature = "io_safety", since = "1.63.0")] |
94222f64 XL |
395 | impl From<crate::process::ChildStdin> for OwnedFd { |
396 | #[inline] | |
397 | fn from(child_stdin: crate::process::ChildStdin) -> OwnedFd { | |
398 | child_stdin.into_inner().into_inner().into_inner() | |
399 | } | |
400 | } | |
401 | ||
923072b8 | 402 | #[stable(feature = "io_safety", since = "1.63.0")] |
94222f64 XL |
403 | impl AsFd for crate::process::ChildStdout { |
404 | #[inline] | |
405 | fn as_fd(&self) -> BorrowedFd<'_> { | |
406 | self.as_inner().as_fd() | |
407 | } | |
408 | } | |
409 | ||
923072b8 | 410 | #[stable(feature = "io_safety", since = "1.63.0")] |
94222f64 XL |
411 | impl From<crate::process::ChildStdout> for OwnedFd { |
412 | #[inline] | |
413 | fn from(child_stdout: crate::process::ChildStdout) -> OwnedFd { | |
414 | child_stdout.into_inner().into_inner().into_inner() | |
415 | } | |
416 | } | |
417 | ||
923072b8 | 418 | #[stable(feature = "io_safety", since = "1.63.0")] |
94222f64 XL |
419 | impl AsFd for crate::process::ChildStderr { |
420 | #[inline] | |
421 | fn as_fd(&self) -> BorrowedFd<'_> { | |
422 | self.as_inner().as_fd() | |
423 | } | |
424 | } | |
425 | ||
923072b8 | 426 | #[stable(feature = "io_safety", since = "1.63.0")] |
94222f64 XL |
427 | impl From<crate::process::ChildStderr> for OwnedFd { |
428 | #[inline] | |
429 | fn from(child_stderr: crate::process::ChildStderr) -> OwnedFd { | |
430 | child_stderr.into_inner().into_inner().into_inner() | |
c1a9b12d SL |
431 | } |
432 | } | |
ff7c6d11 XL |
433 | |
434 | /// Returns the OS-assigned process identifier associated with this process's parent. | |
3c0e092e | 435 | #[must_use] |
83c7162d | 436 | #[stable(feature = "unix_ppid", since = "1.27.0")] |
ff7c6d11 | 437 | pub fn parent_id() -> u32 { |
532ac7d7 | 438 | crate::sys::os::getppid() |
ff7c6d11 | 439 | } |