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
10use crate::{backend, io};
11use alloc::vec::Vec;
12#[cfg(linux_kernel)]
13use backend::process::types::RawCpuid;
14
15/// The raw integer value of a Unix user ID.
16pub use backend::process::types::RawUid;
17
18/// The raw integer value of a Unix group ID.
19pub use backend::process::types::RawGid;
20
21/// The raw integer value of a Unix process ID.
22pub use backend::process::types::RawPid;
23
24/// The raw integer value of a Unix process ID.
25pub use backend::process::types::RawNonZeroPid;
26
27/// `uid_t`—A Unix user ID.
28#[repr(transparent)]
29#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
30pub struct Uid(RawUid);
31
32/// `gid_t`—A Unix group ID.
33#[repr(transparent)]
34#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
35pub 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)]
44pub struct Pid(RawNonZeroPid);
45
46/// A Linux CPU ID.
47#[cfg(linux_kernel)]
48#[repr(transparent)]
49#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
50pub struct Cpuid(RawCpuid);
51
52impl 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
79impl 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
106impl 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)]
169impl 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]
197pub 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]
211pub 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]
225pub 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]
239pub 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]
253pub 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]
267pub 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]
280pub 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]
293pub 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]
307pub 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]
321pub 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]
334pub 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
346pub 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.
371pub(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