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