xref: /drstd/src/std/os/linux/process.rs (revision 0fe3ff0054d3aec7fbf9bddecfecb10bc7d23a51)
1 //! Linux-specific extensions to primitives in the [`std::process`] module.
2 //!
3 //! [`std::process`]: crate::std::process
4 
5 use crate::std::io::Result;
6 use crate::std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
7 use crate::std::process;
8 use crate::std::sealed::Sealed;
9 #[cfg(not(doc))]
10 use crate::std::sys::fd::FileDesc;
11 use crate::std::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
12 
13 #[cfg(doc)]
14 struct FileDesc;
15 
16 /// This type represents a file descriptor that refers to a process.
17 ///
18 /// A `PidFd` can be obtained by setting the corresponding option on [`Command`]
19 /// with [`create_pidfd`]. Subsequently, the created pidfd can be retrieved
20 /// from the [`Child`] by calling [`pidfd`] or [`take_pidfd`].
21 ///
22 /// Example:
23 /// ```no_run
24 /// #![feature(linux_pidfd)]
25 /// use std::os::linux::process::{CommandExt, ChildExt};
26 /// use std::process::Command;
27 ///
28 /// let mut child = Command::new("echo")
29 ///     .create_pidfd(true)
30 ///     .spawn()
31 ///     .expect("Failed to spawn child");
32 ///
33 /// let pidfd = child
34 ///     .take_pidfd()
35 ///     .expect("Failed to retrieve pidfd");
36 ///
37 /// // The file descriptor will be closed when `pidfd` is dropped.
38 /// ```
39 /// Refer to the man page of [`pidfd_open(2)`] for further details.
40 ///
41 /// [`Command`]: process::Command
42 /// [`create_pidfd`]: CommandExt::create_pidfd
43 /// [`Child`]: process::Child
44 /// [`pidfd`]: fn@ChildExt::pidfd
45 /// [`take_pidfd`]: ChildExt::take_pidfd
46 /// [`pidfd_open(2)`]: https://man7.org/linux/man-pages/man2/pidfd_open.2.html
47 #[derive(Debug)]
48 pub struct PidFd {
49     inner: FileDesc,
50 }
51 
52 impl AsInner<FileDesc> for PidFd {
53     #[inline]
54     fn as_inner(&self) -> &FileDesc {
55         &self.inner
56     }
57 }
58 
59 impl FromInner<FileDesc> for PidFd {
60     fn from_inner(inner: FileDesc) -> PidFd {
61         PidFd { inner }
62     }
63 }
64 
65 impl IntoInner<FileDesc> for PidFd {
66     fn into_inner(self) -> FileDesc {
67         self.inner
68     }
69 }
70 
71 impl AsRawFd for PidFd {
72     #[inline]
73     fn as_raw_fd(&self) -> RawFd {
74         self.as_inner().as_raw_fd()
75     }
76 }
77 
78 impl FromRawFd for PidFd {
79     unsafe fn from_raw_fd(fd: RawFd) -> Self {
80         Self::from_inner(FileDesc::from_raw_fd(fd))
81     }
82 }
83 
84 impl IntoRawFd for PidFd {
85     fn into_raw_fd(self) -> RawFd {
86         self.into_inner().into_raw_fd()
87     }
88 }
89 
90 impl AsFd for PidFd {
91     fn as_fd(&self) -> BorrowedFd<'_> {
92         self.as_inner().as_fd()
93     }
94 }
95 
96 impl From<OwnedFd> for PidFd {
97     fn from(fd: OwnedFd) -> Self {
98         Self::from_inner(FileDesc::from_inner(fd))
99     }
100 }
101 
102 impl From<PidFd> for OwnedFd {
103     fn from(pid_fd: PidFd) -> Self {
104         pid_fd.into_inner().into_inner()
105     }
106 }
107 
108 /// Os-specific extensions for [`Child`]
109 ///
110 /// [`Child`]: process::Child
111 pub trait ChildExt: Sealed {
112     /// Obtains a reference to the [`PidFd`] created for this [`Child`], if available.
113     ///
114     /// A pidfd will only be available if its creation was requested with
115     /// [`create_pidfd`] when the corresponding [`Command`] was created.
116     ///
117     /// Even if requested, a pidfd may not be available due to an older
118     /// version of Linux being in use, or if some other error occurred.
119     ///
120     /// [`Command`]: process::Command
121     /// [`create_pidfd`]: CommandExt::create_pidfd
122     /// [`Child`]: process::Child
123     fn pidfd(&self) -> Result<&PidFd>;
124 
125     /// Takes ownership of the [`PidFd`] created for this [`Child`], if available.
126     ///
127     /// A pidfd will only be available if its creation was requested with
128     /// [`create_pidfd`] when the corresponding [`Command`] was created.
129     ///
130     /// Even if requested, a pidfd may not be available due to an older
131     /// version of Linux being in use, or if some other error occurred.
132     ///
133     /// [`Command`]: process::Command
134     /// [`create_pidfd`]: CommandExt::create_pidfd
135     /// [`Child`]: process::Child
136     fn take_pidfd(&mut self) -> Result<PidFd>;
137 }
138 
139 /// Os-specific extensions for [`Command`]
140 ///
141 /// [`Command`]: process::Command
142 pub trait CommandExt: Sealed {
143     /// Sets whether a [`PidFd`](struct@PidFd) should be created for the [`Child`]
144     /// spawned by this [`Command`].
145     /// By default, no pidfd will be created.
146     ///
147     /// The pidfd can be retrieved from the child with [`pidfd`] or [`take_pidfd`].
148     ///
149     /// A pidfd will only be created if it is possible to do so
150     /// in a guaranteed race-free manner (e.g. if the `clone3` system call
151     /// is supported). Otherwise, [`pidfd`] will return an error.
152     ///
153     /// [`Command`]: process::Command
154     /// [`Child`]: process::Child
155     /// [`pidfd`]: fn@ChildExt::pidfd
156     /// [`take_pidfd`]: ChildExt::take_pidfd
157     fn create_pidfd(&mut self, val: bool) -> &mut process::Command;
158 }
159 
160 impl CommandExt for process::Command {
161     fn create_pidfd(&mut self, val: bool) -> &mut process::Command {
162         self.as_inner_mut().create_pidfd(val);
163         self
164     }
165 }
166