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