1 | //! Unix user, group, and process identifiers. |
2 | //! |
3 | //! # Safety |
4 | //! |
5 | //! The `Uid`, `Gid`, and `Pid` types can be constructed from raw integers, |
6 | //! which is marked unsafe because actual OS's assign special meaning to some |
7 | //! integer values. |
8 | #![allow (unsafe_code)] |
9 | |
10 | use crate::{backend, io}; |
11 | use alloc::vec::Vec; |
12 | #[cfg (linux_kernel)] |
13 | use backend::process::types::RawCpuid; |
14 | |
15 | /// The raw integer value of a Unix user ID. |
16 | pub use backend::process::types::RawUid; |
17 | |
18 | /// The raw integer value of a Unix group ID. |
19 | pub use backend::process::types::RawGid; |
20 | |
21 | /// The raw integer value of a Unix process ID. |
22 | pub use backend::process::types::RawPid; |
23 | |
24 | /// The raw integer value of a Unix process ID. |
25 | pub use backend::process::types::RawNonZeroPid; |
26 | |
27 | /// `uid_t`—A Unix user ID. |
28 | #[repr (transparent)] |
29 | #[derive (Copy, Clone, Eq, PartialEq, Debug, Hash)] |
30 | pub struct Uid(RawUid); |
31 | |
32 | /// `gid_t`—A Unix group ID. |
33 | #[repr (transparent)] |
34 | #[derive (Copy, Clone, Eq, PartialEq, Debug, Hash)] |
35 | pub struct Gid(RawGid); |
36 | |
37 | /// `pid_t`—A non-zero Unix process ID. |
38 | /// |
39 | /// This is a pid, and not a pidfd. It is not a file descriptor, and the |
40 | /// process it refers to could disappear at any time and be replaced by |
41 | /// another, unrelated, process. |
42 | #[repr (transparent)] |
43 | #[derive (Copy, Clone, Eq, PartialEq, Debug, Hash)] |
44 | pub struct Pid(RawNonZeroPid); |
45 | |
46 | /// A Linux CPU ID. |
47 | #[cfg (linux_kernel)] |
48 | #[repr (transparent)] |
49 | #[derive (Copy, Clone, Eq, PartialEq, Debug, Hash)] |
50 | pub struct Cpuid(RawCpuid); |
51 | |
52 | impl Uid { |
53 | /// A `Uid` corresponding to the root user (uid 0). |
54 | pub const ROOT: Self = Self(0); |
55 | |
56 | /// Converts a `RawUid` into a `Uid`. |
57 | /// |
58 | /// # Safety |
59 | /// |
60 | /// `raw` must be the value of a valid Unix user ID. |
61 | #[inline ] |
62 | pub const unsafe fn from_raw(raw: RawUid) -> Self { |
63 | Self(raw) |
64 | } |
65 | |
66 | /// Converts a `Uid` into a `RawUid`. |
67 | #[inline ] |
68 | pub const fn as_raw(self) -> RawUid { |
69 | self.0 |
70 | } |
71 | |
72 | /// Test whether this uid represents the root user (uid 0). |
73 | #[inline ] |
74 | pub const fn is_root(self) -> bool { |
75 | self.0 == Self::ROOT.0 |
76 | } |
77 | } |
78 | |
79 | impl Gid { |
80 | /// A `Gid` corresponding to the root group (gid 0). |
81 | pub const ROOT: Self = Self(0); |
82 | |
83 | /// Converts a `RawGid` into a `Gid`. |
84 | /// |
85 | /// # Safety |
86 | /// |
87 | /// `raw` must be the value of a valid Unix group ID. |
88 | #[inline ] |
89 | pub const unsafe fn from_raw(raw: RawGid) -> Self { |
90 | Self(raw) |
91 | } |
92 | |
93 | /// Converts a `Gid` into a `RawGid`. |
94 | #[inline ] |
95 | pub const fn as_raw(self) -> RawGid { |
96 | self.0 |
97 | } |
98 | |
99 | /// Test whether this gid represents the root group (gid 0). |
100 | #[inline ] |
101 | pub const fn is_root(self) -> bool { |
102 | self.0 == Self::ROOT.0 |
103 | } |
104 | } |
105 | |
106 | impl Pid { |
107 | /// A `Pid` corresponding to the init process (pid 1). |
108 | pub const INIT: Self = Self( |
109 | // SAFETY: The init process' pid is always valid. |
110 | unsafe { RawNonZeroPid::new_unchecked(1) }, |
111 | ); |
112 | |
113 | /// Converts a `RawPid` into a `Pid`. |
114 | /// |
115 | /// # Safety |
116 | /// |
117 | /// `raw` must be the value of a valid Unix process ID, or zero. |
118 | #[inline ] |
119 | pub const unsafe fn from_raw(raw: RawPid) -> Option<Self> { |
120 | match RawNonZeroPid::new(raw) { |
121 | Some(pid) => Some(Self(pid)), |
122 | None => None, |
123 | } |
124 | } |
125 | |
126 | /// Converts a known non-zero `RawPid` into a `Pid`. |
127 | /// |
128 | /// # Safety |
129 | /// |
130 | /// `raw` must be the value of a valid Unix process ID. It must not be |
131 | /// zero. |
132 | #[inline ] |
133 | pub const unsafe fn from_raw_nonzero(raw: RawNonZeroPid) -> Self { |
134 | Self(raw) |
135 | } |
136 | |
137 | /// Creates a `Pid` holding the ID of the given child process. |
138 | #[cfg (feature = "std" )] |
139 | #[inline ] |
140 | pub fn from_child(child: &std::process::Child) -> Self { |
141 | let id = child.id(); |
142 | debug_assert_ne!(id, 0); |
143 | |
144 | // SAFETY: We know the returned ID is valid because it came directly |
145 | // from an OS API. |
146 | unsafe { Self::from_raw_nonzero(RawNonZeroPid::new_unchecked(id as _)) } |
147 | } |
148 | |
149 | /// Converts a `Pid` into a `RawNonZeroPid`. |
150 | #[inline ] |
151 | pub const fn as_raw_nonzero(self) -> RawNonZeroPid { |
152 | self.0 |
153 | } |
154 | |
155 | /// Converts an `Option<Pid>` into a `RawPid`. |
156 | #[inline ] |
157 | pub fn as_raw(pid: Option<Self>) -> RawPid { |
158 | pid.map_or(0, |pid| pid.0.get()) |
159 | } |
160 | |
161 | /// Test whether this pid represents the init process (pid 0). |
162 | #[inline ] |
163 | pub const fn is_init(self) -> bool { |
164 | self.0.get() == Self::INIT.0.get() |
165 | } |
166 | } |
167 | |
168 | #[cfg (linux_kernel)] |
169 | impl Cpuid { |
170 | /// Converts a `RawCpuid` into a `Cpuid`. |
171 | /// |
172 | /// # Safety |
173 | /// |
174 | /// `raw` must be the value of a valid Linux CPU ID. |
175 | #[inline ] |
176 | pub const unsafe fn from_raw(raw: RawCpuid) -> Self { |
177 | Self(raw) |
178 | } |
179 | |
180 | /// Converts a `Cpuid` into a `RawCpuid`. |
181 | #[inline ] |
182 | pub const fn as_raw(self) -> RawCpuid { |
183 | self.0 |
184 | } |
185 | } |
186 | |
187 | /// `getuid()`—Returns the process' real user ID. |
188 | /// |
189 | /// # References |
190 | /// - [POSIX] |
191 | /// - [Linux] |
192 | /// |
193 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getuid.html |
194 | /// [Linux]: https://man7.org/linux/man-pages/man2/getuid.2.html |
195 | #[inline ] |
196 | #[must_use ] |
197 | pub fn getuid() -> Uid { |
198 | backend::process::syscalls::getuid() |
199 | } |
200 | |
201 | /// `geteuid()`—Returns the process' effective user ID. |
202 | /// |
203 | /// # References |
204 | /// - [POSIX] |
205 | /// - [Linux] |
206 | /// |
207 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/geteuid.html |
208 | /// [Linux]: https://man7.org/linux/man-pages/man2/geteuid.2.html |
209 | #[inline ] |
210 | #[must_use ] |
211 | pub fn geteuid() -> Uid { |
212 | backend::process::syscalls::geteuid() |
213 | } |
214 | |
215 | /// `getgid()`—Returns the process' real group ID. |
216 | /// |
217 | /// # References |
218 | /// - [POSIX] |
219 | /// - [Linux] |
220 | /// |
221 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getgid.html |
222 | /// [Linux]: https://man7.org/linux/man-pages/man2/getgid.2.html |
223 | #[inline ] |
224 | #[must_use ] |
225 | pub fn getgid() -> Gid { |
226 | backend::process::syscalls::getgid() |
227 | } |
228 | |
229 | /// `getegid()`—Returns the process' effective group ID. |
230 | /// |
231 | /// # References |
232 | /// - [POSIX] |
233 | /// - [Linux] |
234 | /// |
235 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getegid.html |
236 | /// [Linux]: https://man7.org/linux/man-pages/man2/getegid.2.html |
237 | #[inline ] |
238 | #[must_use ] |
239 | pub fn getegid() -> Gid { |
240 | backend::process::syscalls::getegid() |
241 | } |
242 | |
243 | /// `getpid()`—Returns the process' ID. |
244 | /// |
245 | /// # References |
246 | /// - [POSIX] |
247 | /// - [Linux] |
248 | /// |
249 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpid.html |
250 | /// [Linux]: https://man7.org/linux/man-pages/man2/getpid.2.html |
251 | #[inline ] |
252 | #[must_use ] |
253 | pub fn getpid() -> Pid { |
254 | backend::process::syscalls::getpid() |
255 | } |
256 | |
257 | /// `getppid()`—Returns the parent process' ID. |
258 | /// |
259 | /// # References |
260 | /// - [POSIX] |
261 | /// - [Linux] |
262 | /// |
263 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getppid.html |
264 | /// [Linux]: https://man7.org/linux/man-pages/man2/getppid.2.html |
265 | #[inline ] |
266 | #[must_use ] |
267 | pub fn getppid() -> Option<Pid> { |
268 | backend::process::syscalls::getppid() |
269 | } |
270 | |
271 | /// `getpgid(pid)`—Returns the process group ID of the given process. |
272 | /// |
273 | /// # References |
274 | /// - [POSIX] |
275 | /// - [Linux] |
276 | /// |
277 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpgid.html |
278 | /// [Linux]: https://man7.org/linux/man-pages/man2/getpgid.2.html |
279 | #[inline ] |
280 | pub fn getpgid(pid: Option<Pid>) -> io::Result<Pid> { |
281 | backend::process::syscalls::getpgid(pid) |
282 | } |
283 | |
284 | /// `setpgid(pid, pgid)`—Sets the process group ID of the given process. |
285 | /// |
286 | /// # References |
287 | /// - [POSIX] |
288 | /// - [Linux] |
289 | /// |
290 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setpgid.html |
291 | /// [Linux]: https://man7.org/linux/man-pages/man2/setpgid.2.html |
292 | #[inline ] |
293 | pub fn setpgid(pid: Option<Pid>, pgid: Option<Pid>) -> io::Result<()> { |
294 | backend::process::syscalls::setpgid(pid, pgid) |
295 | } |
296 | |
297 | /// `getpgrp()`—Returns the process' group ID. |
298 | /// |
299 | /// # References |
300 | /// - [POSIX] |
301 | /// - [Linux] |
302 | /// |
303 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpgrp.html |
304 | /// [Linux]: https://man7.org/linux/man-pages/man2/getpgrp.2.html |
305 | #[inline ] |
306 | #[must_use ] |
307 | pub fn getpgrp() -> Pid { |
308 | backend::process::syscalls::getpgrp() |
309 | } |
310 | |
311 | /// `getsid(pid)`—Get the session ID of the given process. |
312 | /// |
313 | /// # References |
314 | /// - [POSIX] |
315 | /// - [Linux] |
316 | /// |
317 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsid.html |
318 | /// [Linux]: https://man7.org/linux/man-pages/man2/getsid.2.html |
319 | #[cfg (not(target_os = "redox" ))] |
320 | #[inline ] |
321 | pub fn getsid(pid: Option<Pid>) -> io::Result<Pid> { |
322 | backend::process::syscalls::getsid(pid) |
323 | } |
324 | |
325 | /// `setsid()`—Create a new session. |
326 | /// |
327 | /// # References |
328 | /// - [POSIX] |
329 | /// - [Linux] |
330 | /// |
331 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsid.html |
332 | /// [Linux]: https://man7.org/linux/man-pages/man2/setsid.2.html |
333 | #[inline ] |
334 | pub fn setsid() -> io::Result<Pid> { |
335 | backend::process::syscalls::setsid() |
336 | } |
337 | |
338 | /// `getgroups()`—Return a list of the current user's groups. |
339 | /// |
340 | /// # References |
341 | /// - [POSIX] |
342 | /// - [Linux] |
343 | /// |
344 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getgroups.html |
345 | /// [Linux]: https://man7.org/linux/man-pages/man2/getgroups.2.html |
346 | pub fn getgroups() -> io::Result<Vec<Gid>> { |
347 | let mut buffer: Vec = Vec::new(); |
348 | |
349 | // This code would benefit from having a better way to read into |
350 | // uninitialized memory, but that requires `unsafe`. |
351 | buffer.reserve(additional:8); |
352 | buffer.resize(new_len:buffer.capacity(), value:Gid::ROOT); |
353 | |
354 | loop { |
355 | let ngroups: usize = backend::process::syscalls::getgroups(&mut buffer)?; |
356 | |
357 | let ngroups: usize = ngroups as usize; |
358 | assert!(ngroups <= buffer.len()); |
359 | if ngroups < buffer.len() { |
360 | buffer.resize(new_len:ngroups, value:Gid::ROOT); |
361 | return Ok(buffer); |
362 | } |
363 | buffer.reserve(additional:1); // use `Vec` reallocation strategy to grow capacity exponentially |
364 | buffer.resize(new_len:buffer.capacity(), value:Gid::ROOT); |
365 | } |
366 | } |
367 | |
368 | // Return the raw value of the IDs. In case of `None` it returns `u32::MAX` |
369 | // since it has the same bit pattern as `-1` indicating no change to the |
370 | // owner/group ID. |
371 | pub(crate) fn translate_fchown_args(owner: Option<Uid>, group: Option<Gid>) -> (u32, u32) { |
372 | let ow: u32 = match owner { |
373 | Some(o: Uid) => o.as_raw(), |
374 | None => u32::MAX, |
375 | }; |
376 | |
377 | let gr: u32 = match group { |
378 | Some(g: Gid) => g.as_raw(), |
379 | None => u32::MAX, |
380 | }; |
381 | |
382 | (ow, gr) |
383 | } |
384 | |