]> git.lizzy.rs Git - rust.git/blob - library/std/src/os/unix/process.rs
Don't subst an adt def
[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(any(target_os = "vxworks", target_os = "espidf")))] id: u32,
28         #[cfg(any(target_os = "vxworks", target_os = "espidf"))] 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(any(target_os = "vxworks", target_os = "espidf")))] id: u32,
37         #[cfg(any(target_os = "vxworks", target_os = "espidf"))] 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 = "90747")]
43     fn groups(
44         &mut self,
45         #[cfg(not(any(target_os = "vxworks", target_os = "espidf")))] groups: &[u32],
46         #[cfg(any(target_os = "vxworks", target_os = "espidf"))] 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     /// 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;
157 }
158
159 #[stable(feature = "rust1", since = "1.0.0")]
160 impl CommandExt for process::Command {
161     fn uid(
162         &mut self,
163         #[cfg(not(any(target_os = "vxworks", target_os = "espidf")))] id: u32,
164         #[cfg(any(target_os = "vxworks", target_os = "espidf"))] id: u16,
165     ) -> &mut process::Command {
166         self.as_inner_mut().uid(id);
167         self
168     }
169
170     fn gid(
171         &mut self,
172         #[cfg(not(any(target_os = "vxworks", target_os = "espidf")))] id: u32,
173         #[cfg(any(target_os = "vxworks", target_os = "espidf"))] id: u16,
174     ) -> &mut process::Command {
175         self.as_inner_mut().gid(id);
176         self
177     }
178
179     fn groups(
180         &mut self,
181         #[cfg(not(any(target_os = "vxworks", target_os = "espidf")))] groups: &[u32],
182         #[cfg(any(target_os = "vxworks", target_os = "espidf"))] groups: &[u16],
183     ) -> &mut process::Command {
184         self.as_inner_mut().groups(groups);
185         self
186     }
187
188     unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
189     where
190         F: FnMut() -> io::Result<()> + Send + Sync + 'static,
191     {
192         self.as_inner_mut().pre_exec(Box::new(f));
193         self
194     }
195
196     fn exec(&mut self) -> io::Error {
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.
199         self.as_inner_mut().exec(sys::process::Stdio::Inherit)
200     }
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     }
209
210     fn process_group(&mut self, pgroup: i32) -> &mut process::Command {
211         self.as_inner_mut().pgroup(pgroup);
212         self
213     }
214 }
215
216 /// Unix-specific extensions to [`process::ExitStatus`] and
217 /// [`ExitStatusError`](process::ExitStatusError).
218 ///
219 /// On Unix, `ExitStatus` **does not necessarily represent an exit status**, as
220 /// passed to the `_exit` system call or returned by
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.
224 ///
225 /// A Unix wait status (a Rust `ExitStatus`) can represent a Unix exit status, but can also
226 /// represent other kinds of process event.
227 ///
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.
230 #[stable(feature = "rust1", since = "1.0.0")]
231 pub trait ExitStatusExt: Sealed {
232     /// Creates a new `ExitStatus` or `ExitStatusError` from the raw underlying integer status
233     /// value from `wait`
234     ///
235     /// The value should be a **wait status, not an exit status**.
236     ///
237     /// # Panics
238     ///
239     /// Panics on an attempt to make an `ExitStatusError` from a wait status of `0`.
240     ///
241     /// Making an `ExitStatus` always succeeds and never panics.
242     #[stable(feature = "exit_status_from", since = "1.12.0")]
243     fn from_raw(raw: i32) -> Self;
244
245     /// If the process was terminated by a signal, returns that signal.
246     ///
247     /// In other words, if `WIFSIGNALED`, this returns `WTERMSIG`.
248     #[stable(feature = "rust1", since = "1.0.0")]
249     fn signal(&self) -> Option<i32>;
250
251     /// If the process was terminated by a signal, says whether it dumped core.
252     #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
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
258     /// a `wait` system call which was passed `WUNTRACED`, and was then converted into an `ExitStatus`.
259     #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
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
265     /// which was passed `WCONTINUED`, and was then converted into an `ExitStatus`.
266     #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
267     fn continued(&self) -> bool;
268
269     /// Returns the underlying raw `wait` status.
270     ///
271     /// The returned integer is a **wait status, not an exit status**.
272     #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
273     fn into_raw(self) -> i32;
274 }
275
276 #[stable(feature = "rust1", since = "1.0.0")]
277 impl ExitStatusExt for process::ExitStatus {
278     fn from_raw(raw: i32) -> Self {
279         process::ExitStatus::from_inner(From::from(raw))
280     }
281
282     fn signal(&self) -> Option<i32> {
283         self.as_inner().signal()
284     }
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     }
301 }
302
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
332 #[stable(feature = "process_extensions", since = "1.2.0")]
333 impl FromRawFd for process::Stdio {
334     #[inline]
335     unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio {
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);
347         let io = sys::process::Stdio::Fd(fd);
348         process::Stdio::from_inner(io)
349     }
350 }
351
352 #[stable(feature = "process_extensions", since = "1.2.0")]
353 impl AsRawFd for process::ChildStdin {
354     #[inline]
355     fn as_raw_fd(&self) -> RawFd {
356         self.as_inner().as_raw_fd()
357     }
358 }
359
360 #[stable(feature = "process_extensions", since = "1.2.0")]
361 impl AsRawFd for process::ChildStdout {
362     #[inline]
363     fn as_raw_fd(&self) -> RawFd {
364         self.as_inner().as_raw_fd()
365     }
366 }
367
368 #[stable(feature = "process_extensions", since = "1.2.0")]
369 impl AsRawFd for process::ChildStderr {
370     #[inline]
371     fn as_raw_fd(&self) -> RawFd {
372         self.as_inner().as_raw_fd()
373     }
374 }
375
376 #[stable(feature = "into_raw_os", since = "1.4.0")]
377 impl IntoRawFd for process::ChildStdin {
378     #[inline]
379     fn into_raw_fd(self) -> RawFd {
380         self.into_inner().into_inner().into_raw_fd()
381     }
382 }
383
384 #[stable(feature = "into_raw_os", since = "1.4.0")]
385 impl IntoRawFd for process::ChildStdout {
386     #[inline]
387     fn into_raw_fd(self) -> RawFd {
388         self.into_inner().into_inner().into_raw_fd()
389     }
390 }
391
392 #[stable(feature = "into_raw_os", since = "1.4.0")]
393 impl IntoRawFd for process::ChildStderr {
394     #[inline]
395     fn into_raw_fd(self) -> RawFd {
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()
445     }
446 }
447
448 /// Returns the OS-assigned process identifier associated with this process's parent.
449 #[must_use]
450 #[stable(feature = "unix_ppid", since = "1.27.0")]
451 pub fn parent_id() -> u32 {
452     crate::sys::os::getppid()
453 }