xref: /drstd/src/std/os/unix/process.rs (revision a1cd34728e2d4a5d4cf41974e4db28602cbb1b1c)
1 //! Unix-specific extensions to primitives in the [`std::process`] module.
2 //!
3 //! [`std::process`]: crate::std::process
4 
5 use crate::std::ffi::OsStr;
6 use crate::std::io;
7 use crate::std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
8 use crate::std::process;
9 use crate::std::sealed::Sealed;
10 use crate::std::sys;
11 use crate::std::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
12 
13 use cfg_if::cfg_if;
14 
15 cfg_if! {
16     if #[cfg(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon", target_os = "vita"))] {
17         type UserId = u16;
18         type GroupId = u16;
19     } else if #[cfg(target_os = "nto")] {
20         // Both IDs are signed, see `sys/target_nto.h` of the QNX Neutrino SDP.
21         // Only positive values should be used, see e.g.
22         // https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/s/setuid.html
23         type UserId = i32;
24         type GroupId = i32;
25     } else {
26         type UserId = u32;
27         type GroupId = u32;
28     }
29 }
30 
31 /// Unix-specific extensions to the [`process::Command`] builder.
32 ///
33 /// This trait is sealed: it cannot be implemented outside the standard library.
34 /// This is so that future additional methods are not breaking changes.
35 pub trait CommandExt: Sealed {
36     /// Sets the child process's user ID. This translates to a
37     /// `setuid` call in the child process. Failure in the `setuid`
38     /// call will cause the spawn to fail.
39     fn uid(&mut self, id: UserId) -> &mut process::Command;
40 
41     /// Similar to `uid`, but sets the group ID of the child process. This has
42     /// the same semantics as the `uid` field.
43     fn gid(&mut self, id: GroupId) -> &mut process::Command;
44 
45     /// Sets the supplementary group IDs for the calling process. Translates to
46     /// a `setgroups` call in the child process.
47     fn groups(&mut self, groups: &[GroupId]) -> &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::std::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::std::env
93     unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
94     where
95         F: FnMut() -> io::Result<()> + Send + Sync + 'static;
96 
97     /// Schedules a closure to be run just before the `exec` function is
98     /// invoked.
99     ///
100     /// This method is stable and usable, but it should be unsafe. To fix
101     /// that, it got deprecated in favor of the unsafe [`pre_exec`].
102     ///
103     /// [`pre_exec`]: CommandExt::pre_exec
104     #[deprecated(since = "1.37.0", note = "should be unsafe, use `pre_exec` instead")]
105     fn before_exec<F>(&mut self, f: F) -> &mut process::Command
106     where
107         F: FnMut() -> io::Result<()> + Send + Sync + 'static,
108     {
109         unsafe { self.pre_exec(f) }
110     }
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     ///
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     ///
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.
139     fn exec(&mut self) -> io::Error;
140 
141     /// Set executable argument
142     ///
143     /// Set the first process argument, `argv[0]`, to something other than the
144     /// default executable path.
145     fn arg0<S>(&mut self, arg: S) -> &mut process::Command
146     where
147         S: AsRef<OsStr>;
148 
149     /// Sets the process group ID (PGID) of the child process. Equivalent to a
150     /// `setpgid` call in the child process, but may be more efficient.
151     ///
152     /// Process groups determine which processes receive signals.
153     ///
154     /// # Examples
155     ///
156     /// Pressing Ctrl-C in a terminal will send SIGINT to all processes in
157     /// the current foreground process group. By spawning the `sleep`
158     /// subprocess in a new process group, it will not receive SIGINT from the
159     /// terminal.
160     ///
161     /// The parent process could install a signal handler and manage the
162     /// subprocess on its own terms.
163     ///
164     /// A process group ID of 0 will use the process ID as the PGID.
165     ///
166     /// ```no_run
167     /// use std::process::Command;
168     /// use std::os::unix::process::CommandExt;
169     ///
170     /// Command::new("sleep")
171     ///     .arg("10")
172     ///     .process_group(0)
173     ///     .spawn()?
174     ///     .wait()?;
175     /// #
176     /// # Ok::<_, Box<dyn std::error::Error>>(())
177     /// ```
178     fn process_group(&mut self, pgroup: i32) -> &mut process::Command;
179 }
180 
181 impl CommandExt for process::Command {
182     fn uid(&mut self, id: UserId) -> &mut process::Command {
183         self.as_inner_mut().uid(id);
184         self
185     }
186 
187     fn gid(&mut self, id: GroupId) -> &mut process::Command {
188         self.as_inner_mut().gid(id);
189         self
190     }
191 
192     fn groups(&mut self, groups: &[GroupId]) -> &mut process::Command {
193         self.as_inner_mut().groups(groups);
194         self
195     }
196 
197     unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
198     where
199         F: FnMut() -> io::Result<()> + Send + Sync + 'static,
200     {
201         self.as_inner_mut().pre_exec(Box::new(f));
202         self
203     }
204 
205     fn exec(&mut self) -> io::Error {
206         // NOTE: This may *not* be safe to call after `dlibc::fork`, because it
207         // may allocate. That may be worth fixing at some point in the future.
208         self.as_inner_mut().exec(sys::process::Stdio::Inherit)
209     }
210 
211     fn arg0<S>(&mut self, arg: S) -> &mut process::Command
212     where
213         S: AsRef<OsStr>,
214     {
215         self.as_inner_mut().set_arg_0(arg.as_ref());
216         self
217     }
218 
219     fn process_group(&mut self, pgroup: i32) -> &mut process::Command {
220         self.as_inner_mut().pgroup(pgroup);
221         self
222     }
223 }
224 
225 /// Unix-specific extensions to [`process::ExitStatus`] and
226 /// [`ExitStatusError`](process::ExitStatusError).
227 ///
228 /// On Unix, `ExitStatus` **does not necessarily represent an exit status**, as
229 /// passed to the `_exit` system call or returned by
230 /// [`ExitStatus::code()`](crate::std::process::ExitStatus::code).  It represents **any wait status**
231 /// as returned by one of the `wait` family of system
232 /// calls.
233 ///
234 /// A Unix wait status (a Rust `ExitStatus`) can represent a Unix exit status, but can also
235 /// represent other kinds of process event.
236 ///
237 /// This trait is sealed: it cannot be implemented outside the standard library.
238 /// This is so that future additional methods are not breaking changes.
239 pub trait ExitStatusExt: Sealed {
240     /// Creates a new `ExitStatus` or `ExitStatusError` from the raw underlying integer status
241     /// value from `wait`
242     ///
243     /// The value should be a **wait status, not an exit status**.
244     ///
245     /// # Panics
246     ///
247     /// Panics on an attempt to make an `ExitStatusError` from a wait status of `0`.
248     ///
249     /// Making an `ExitStatus` always succeeds and never panics.
250     fn from_raw(raw: i32) -> Self;
251 
252     /// If the process was terminated by a signal, returns that signal.
253     ///
254     /// In other words, if `WIFSIGNALED`, this returns `WTERMSIG`.
255     fn signal(&self) -> Option<i32>;
256 
257     /// If the process was terminated by a signal, says whether it dumped core.
258     fn core_dumped(&self) -> bool;
259 
260     /// If the process was stopped by a signal, returns that signal.
261     ///
262     /// In other words, if `WIFSTOPPED`, this returns `WSTOPSIG`.  This is only possible if the status came from
263     /// a `wait` system call which was passed `WUNTRACED`, and was then converted into an `ExitStatus`.
264     fn stopped_signal(&self) -> Option<i32>;
265 
266     /// Whether the process was continued from a stopped status.
267     ///
268     /// Ie, `WIFCONTINUED`.  This is only possible if the status came from a `wait` system call
269     /// which was passed `WCONTINUED`, and was then converted into an `ExitStatus`.
270     fn continued(&self) -> bool;
271 
272     /// Returns the underlying raw `wait` status.
273     ///
274     /// The returned integer is a **wait status, not an exit status**.
275     fn into_raw(self) -> i32;
276 }
277 
278 impl ExitStatusExt for process::ExitStatus {
279     fn from_raw(raw: i32) -> Self {
280         process::ExitStatus::from_inner(From::from(raw))
281     }
282 
283     fn signal(&self) -> Option<i32> {
284         self.as_inner().signal()
285     }
286 
287     fn core_dumped(&self) -> bool {
288         self.as_inner().core_dumped()
289     }
290 
291     fn stopped_signal(&self) -> Option<i32> {
292         self.as_inner().stopped_signal()
293     }
294 
295     fn continued(&self) -> bool {
296         self.as_inner().continued()
297     }
298 
299     fn into_raw(self) -> i32 {
300         self.as_inner().into_raw().into()
301     }
302 }
303 
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 impl FromRawFd for process::Stdio {
333     #[inline]
334     unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio {
335         let fd = sys::fd::FileDesc::from_raw_fd(fd);
336         let io = sys::process::Stdio::Fd(fd);
337         process::Stdio::from_inner(io)
338     }
339 }
340 
341 impl From<OwnedFd> for process::Stdio {
342     #[inline]
343     fn from(fd: OwnedFd) -> process::Stdio {
344         let fd = sys::fd::FileDesc::from_inner(fd);
345         let io = sys::process::Stdio::Fd(fd);
346         process::Stdio::from_inner(io)
347     }
348 }
349 
350 impl AsRawFd for process::ChildStdin {
351     #[inline]
352     fn as_raw_fd(&self) -> RawFd {
353         self.as_inner().as_raw_fd()
354     }
355 }
356 
357 impl AsRawFd for process::ChildStdout {
358     #[inline]
359     fn as_raw_fd(&self) -> RawFd {
360         self.as_inner().as_raw_fd()
361     }
362 }
363 
364 impl AsRawFd for process::ChildStderr {
365     #[inline]
366     fn as_raw_fd(&self) -> RawFd {
367         self.as_inner().as_raw_fd()
368     }
369 }
370 
371 impl IntoRawFd for process::ChildStdin {
372     #[inline]
373     fn into_raw_fd(self) -> RawFd {
374         self.into_inner().into_inner().into_raw_fd()
375     }
376 }
377 
378 impl IntoRawFd for process::ChildStdout {
379     #[inline]
380     fn into_raw_fd(self) -> RawFd {
381         self.into_inner().into_inner().into_raw_fd()
382     }
383 }
384 
385 impl IntoRawFd for process::ChildStderr {
386     #[inline]
387     fn into_raw_fd(self) -> RawFd {
388         self.into_inner().into_inner().into_raw_fd()
389     }
390 }
391 
392 impl AsFd for crate::std::process::ChildStdin {
393     #[inline]
394     fn as_fd(&self) -> BorrowedFd<'_> {
395         self.as_inner().as_fd()
396     }
397 }
398 
399 impl From<crate::std::process::ChildStdin> for OwnedFd {
400     #[inline]
401     fn from(child_stdin: crate::std::process::ChildStdin) -> OwnedFd {
402         child_stdin.into_inner().into_inner().into_inner()
403     }
404 }
405 
406 impl AsFd for crate::std::process::ChildStdout {
407     #[inline]
408     fn as_fd(&self) -> BorrowedFd<'_> {
409         self.as_inner().as_fd()
410     }
411 }
412 
413 impl From<crate::std::process::ChildStdout> for OwnedFd {
414     #[inline]
415     fn from(child_stdout: crate::std::process::ChildStdout) -> OwnedFd {
416         child_stdout.into_inner().into_inner().into_inner()
417     }
418 }
419 
420 impl AsFd for crate::std::process::ChildStderr {
421     #[inline]
422     fn as_fd(&self) -> BorrowedFd<'_> {
423         self.as_inner().as_fd()
424     }
425 }
426 
427 impl From<crate::std::process::ChildStderr> for OwnedFd {
428     #[inline]
429     fn from(child_stderr: crate::std::process::ChildStderr) -> OwnedFd {
430         child_stderr.into_inner().into_inner().into_inner()
431     }
432 }
433 
434 /// Returns the OS-assigned process identifier associated with this process's parent.
435 #[must_use]
436 pub fn parent_id() -> u32 {
437     crate::std::sys::os::getppid()
438 }
439