]> git.lizzy.rs Git - rust.git/blob - library/std/src/os/unix/process.rs
Rollup merge of #89876 - AlexApps99:const_ops, r=oli-obk
[rust.git] / library / std / src / 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
7 use crate::ffi::OsStr;
8 use crate::io;
9 use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
10 use crate::process;
11 use crate::sealed::Sealed;
12 use crate::sys;
13 use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
14
15 /// Unix-specific extensions to the [`process::Command`] builder.
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.
19 #[stable(feature = "rust1", since = "1.0.0")]
20 pub trait CommandExt: Sealed {
21     /// Sets the child process's user ID. This translates to a
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")]
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;
30
31     /// Similar to `uid`, but sets the group ID of the child process. This has
32     /// the same semantics as the `uid` field.
33     #[stable(feature = "rust1", since = "1.0.0")]
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;
39
40     /// Sets the supplementary group IDs for the calling process. Translates to
41     /// a `setgroups` call in the child process.
42     #[unstable(feature = "setgroups", issue = "38527", reason = "")]
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
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     ///
61     /// # Notes and Safety
62     ///
63     /// This closure will be run in the context of the child process after a
64     /// `fork`. This primarily means that any modifications made to memory on
65     /// behalf of this closure will **not** be visible to the parent process.
66     /// This is often a very constrained environment where normal operations
67     /// like `malloc`, accessing environment variables through [`std::env`]
68     /// or acquiring a mutex are not guaranteed to work (due to
69     /// other threads perhaps still running when the `fork` was run).
70     ///
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     ///
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     ///
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     ///
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
88     /// locations might not appear where intended.
89     ///
90     /// [POSIX fork() specification]:
91     ///     https://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html
92     /// [`std::env`]: mod@crate::env
93     #[stable(feature = "process_pre_exec", since = "1.34.0")]
94     unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
95     where
96         F: FnMut() -> io::Result<()> + Send + Sync + 'static;
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     ///
104     /// [`pre_exec`]: CommandExt::pre_exec
105     #[stable(feature = "process_exec", since = "1.15.0")]
106     #[rustc_deprecated(since = "1.37.0", reason = "should be unsafe, use `pre_exec` instead")]
107     fn before_exec<F>(&mut self, f: F) -> &mut process::Command
108     where
109         F: FnMut() -> io::Result<()> + Send + Sync + 'static,
110     {
111         unsafe { self.pre_exec(f) }
112     }
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     ///
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     ///
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.
141     #[stable(feature = "process_exec2", since = "1.9.0")]
142     fn exec(&mut self) -> io::Error;
143
144     /// Set executable argument
145     ///
146     /// Set the first process argument, `argv[0]`, to something other than the
147     /// default executable path.
148     #[stable(feature = "process_set_argv0", since = "1.45.0")]
149     fn arg0<S>(&mut self, arg: S) -> &mut process::Command
150     where
151         S: AsRef<OsStr>;
152 }
153
154 #[stable(feature = "rust1", since = "1.0.0")]
155 impl CommandExt for process::Command {
156     fn uid(
157         &mut self,
158         #[cfg(not(target_os = "vxworks"))] id: u32,
159         #[cfg(target_os = "vxworks")] id: u16,
160     ) -> &mut process::Command {
161         self.as_inner_mut().uid(id);
162         self
163     }
164
165     fn gid(
166         &mut self,
167         #[cfg(not(target_os = "vxworks"))] id: u32,
168         #[cfg(target_os = "vxworks")] id: u16,
169     ) -> &mut process::Command {
170         self.as_inner_mut().gid(id);
171         self
172     }
173
174     fn groups(
175         &mut self,
176         #[cfg(not(target_os = "vxworks"))] groups: &[u32],
177         #[cfg(target_os = "vxworks")] groups: &[u16],
178     ) -> &mut process::Command {
179         self.as_inner_mut().groups(groups);
180         self
181     }
182
183     unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
184     where
185         F: FnMut() -> io::Result<()> + Send + Sync + 'static,
186     {
187         self.as_inner_mut().pre_exec(Box::new(f));
188         self
189     }
190
191     fn exec(&mut self) -> io::Error {
192         // NOTE: This may *not* be safe to call after `libc::fork`, because it
193         // may allocate. That may be worth fixing at some point in the future.
194         self.as_inner_mut().exec(sys::process::Stdio::Inherit)
195     }
196
197     fn arg0<S>(&mut self, arg: S) -> &mut process::Command
198     where
199         S: AsRef<OsStr>,
200     {
201         self.as_inner_mut().set_arg_0(arg.as_ref());
202         self
203     }
204 }
205
206 /// Unix-specific extensions to [`process::ExitStatus`] and
207 /// [`ExitStatusError`](process::ExitStatusError).
208 ///
209 /// On Unix, `ExitStatus` **does not necessarily represent an exit status**, as
210 /// passed to the `exit` system call or returned by
211 /// [`ExitStatus::code()`](crate::process::ExitStatus::code).  It represents **any wait status**
212 /// as returned by one of the `wait` family of system
213 /// calls.
214 ///
215 /// A Unix wait status (a Rust `ExitStatus`) can represent a Unix exit status, but can also
216 /// represent other kinds of process event.
217 ///
218 /// This trait is sealed: it cannot be implemented outside the standard library.
219 /// This is so that future additional methods are not breaking changes.
220 #[stable(feature = "rust1", since = "1.0.0")]
221 pub trait ExitStatusExt: Sealed {
222     /// Creates a new `ExitStatus` or `ExitStatusError` from the raw underlying integer status
223     /// value from `wait`
224     ///
225     /// The value should be a **wait status, not an exit status**.
226     ///
227     /// # Panics
228     ///
229     /// Panics on an attempt to make an `ExitStatusError` from a wait status of `0`.
230     ///
231     /// Making an `ExitStatus` always succeeds and never panics.
232     #[stable(feature = "exit_status_from", since = "1.12.0")]
233     fn from_raw(raw: i32) -> Self;
234
235     /// If the process was terminated by a signal, returns that signal.
236     ///
237     /// In other words, if `WIFSIGNALED`, this returns `WTERMSIG`.
238     #[stable(feature = "rust1", since = "1.0.0")]
239     fn signal(&self) -> Option<i32>;
240
241     /// If the process was terminated by a signal, says whether it dumped core.
242     #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
243     fn core_dumped(&self) -> bool;
244
245     /// If the process was stopped by a signal, returns that signal.
246     ///
247     /// In other words, if `WIFSTOPPED`, this returns `WSTOPSIG`.  This is only possible if the status came from
248     /// a `wait` system call which was passed `WUNTRACED`, and was then converted into an `ExitStatus`.
249     #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
250     fn stopped_signal(&self) -> Option<i32>;
251
252     /// Whether the process was continued from a stopped status.
253     ///
254     /// Ie, `WIFCONTINUED`.  This is only possible if the status came from a `wait` system call
255     /// which was passed `WCONTINUED`, and was then converted into an `ExitStatus`.
256     #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
257     fn continued(&self) -> bool;
258
259     /// Returns the underlying raw `wait` status.
260     ///
261     /// The returned integer is a **wait status, not an exit status**.
262     #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
263     fn into_raw(self) -> i32;
264 }
265
266 #[stable(feature = "rust1", since = "1.0.0")]
267 impl ExitStatusExt for process::ExitStatus {
268     fn from_raw(raw: i32) -> Self {
269         process::ExitStatus::from_inner(From::from(raw))
270     }
271
272     fn signal(&self) -> Option<i32> {
273         self.as_inner().signal()
274     }
275
276     fn core_dumped(&self) -> bool {
277         self.as_inner().core_dumped()
278     }
279
280     fn stopped_signal(&self) -> Option<i32> {
281         self.as_inner().stopped_signal()
282     }
283
284     fn continued(&self) -> bool {
285         self.as_inner().continued()
286     }
287
288     fn into_raw(self) -> i32 {
289         self.as_inner().into_raw().into()
290     }
291 }
292
293 #[unstable(feature = "exit_status_error", issue = "84908")]
294 impl ExitStatusExt for process::ExitStatusError {
295     fn from_raw(raw: i32) -> Self {
296         process::ExitStatus::from_raw(raw)
297             .exit_ok()
298             .expect_err("<ExitStatusError as ExitStatusExt>::from_raw(0) but zero is not an error")
299     }
300
301     fn signal(&self) -> Option<i32> {
302         self.into_status().signal()
303     }
304
305     fn core_dumped(&self) -> bool {
306         self.into_status().core_dumped()
307     }
308
309     fn stopped_signal(&self) -> Option<i32> {
310         self.into_status().stopped_signal()
311     }
312
313     fn continued(&self) -> bool {
314         self.into_status().continued()
315     }
316
317     fn into_raw(self) -> i32 {
318         self.into_status().into_raw()
319     }
320 }
321
322 #[stable(feature = "process_extensions", since = "1.2.0")]
323 impl FromRawFd for process::Stdio {
324     #[inline]
325     unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio {
326         let fd = sys::fd::FileDesc::from_raw_fd(fd);
327         let io = sys::process::Stdio::Fd(fd);
328         process::Stdio::from_inner(io)
329     }
330 }
331
332 #[unstable(feature = "io_safety", issue = "87074")]
333 impl From<OwnedFd> for process::Stdio {
334     #[inline]
335     fn from(fd: OwnedFd) -> process::Stdio {
336         let fd = sys::fd::FileDesc::from_inner(fd);
337         let io = sys::process::Stdio::Fd(fd);
338         process::Stdio::from_inner(io)
339     }
340 }
341
342 #[stable(feature = "process_extensions", since = "1.2.0")]
343 impl AsRawFd for process::ChildStdin {
344     #[inline]
345     fn as_raw_fd(&self) -> RawFd {
346         self.as_inner().as_raw_fd()
347     }
348 }
349
350 #[stable(feature = "process_extensions", since = "1.2.0")]
351 impl AsRawFd for process::ChildStdout {
352     #[inline]
353     fn as_raw_fd(&self) -> RawFd {
354         self.as_inner().as_raw_fd()
355     }
356 }
357
358 #[stable(feature = "process_extensions", since = "1.2.0")]
359 impl AsRawFd for process::ChildStderr {
360     #[inline]
361     fn as_raw_fd(&self) -> RawFd {
362         self.as_inner().as_raw_fd()
363     }
364 }
365
366 #[stable(feature = "into_raw_os", since = "1.4.0")]
367 impl IntoRawFd for process::ChildStdin {
368     #[inline]
369     fn into_raw_fd(self) -> RawFd {
370         self.into_inner().into_inner().into_raw_fd()
371     }
372 }
373
374 #[stable(feature = "into_raw_os", since = "1.4.0")]
375 impl IntoRawFd for process::ChildStdout {
376     #[inline]
377     fn into_raw_fd(self) -> RawFd {
378         self.into_inner().into_inner().into_raw_fd()
379     }
380 }
381
382 #[stable(feature = "into_raw_os", since = "1.4.0")]
383 impl IntoRawFd for process::ChildStderr {
384     #[inline]
385     fn into_raw_fd(self) -> RawFd {
386         self.into_inner().into_inner().into_raw_fd()
387     }
388 }
389
390 #[unstable(feature = "io_safety", issue = "87074")]
391 impl AsFd for crate::process::ChildStdin {
392     #[inline]
393     fn as_fd(&self) -> BorrowedFd<'_> {
394         self.as_inner().as_fd()
395     }
396 }
397
398 #[unstable(feature = "io_safety", issue = "87074")]
399 impl From<crate::process::ChildStdin> for OwnedFd {
400     #[inline]
401     fn from(child_stdin: crate::process::ChildStdin) -> OwnedFd {
402         child_stdin.into_inner().into_inner().into_inner()
403     }
404 }
405
406 #[unstable(feature = "io_safety", issue = "87074")]
407 impl AsFd for crate::process::ChildStdout {
408     #[inline]
409     fn as_fd(&self) -> BorrowedFd<'_> {
410         self.as_inner().as_fd()
411     }
412 }
413
414 #[unstable(feature = "io_safety", issue = "87074")]
415 impl From<crate::process::ChildStdout> for OwnedFd {
416     #[inline]
417     fn from(child_stdout: crate::process::ChildStdout) -> OwnedFd {
418         child_stdout.into_inner().into_inner().into_inner()
419     }
420 }
421
422 #[unstable(feature = "io_safety", issue = "87074")]
423 impl AsFd for crate::process::ChildStderr {
424     #[inline]
425     fn as_fd(&self) -> BorrowedFd<'_> {
426         self.as_inner().as_fd()
427     }
428 }
429
430 #[unstable(feature = "io_safety", issue = "87074")]
431 impl From<crate::process::ChildStderr> for OwnedFd {
432     #[inline]
433     fn from(child_stderr: crate::process::ChildStderr) -> OwnedFd {
434         child_stderr.into_inner().into_inner().into_inner()
435     }
436 }
437
438 /// Returns the OS-assigned process identifier associated with this process's parent.
439 #[stable(feature = "unix_ppid", since = "1.27.0")]
440 pub fn parent_id() -> u32 {
441     crate::sys::os::getppid()
442 }