1 //! linux_raw syscalls supporting `rustix::process`.
2 //!
3 //! # Safety
4 //!
5 //! See the `rustix::backend` module documentation for details.
6 #![allow(unsafe_code, clippy::undocumented_unsafe_blocks)]
7 
8 use super::types::RawCpuSet;
9 use crate::backend::c;
10 #[cfg(all(feature = "alloc", feature = "fs"))]
11 use crate::backend::conv::slice_mut;
12 use crate::backend::conv::{
13     by_mut, by_ref, c_int, c_uint, negative_pid, pass_usize, raw_fd, ret, ret_c_int,
14     ret_c_int_infallible, ret_c_uint, ret_infallible, ret_owned_fd, ret_usize, size_of,
15     slice_just_addr, zero,
16 };
17 use crate::fd::{AsRawFd, BorrowedFd, OwnedFd, RawFd};
18 #[cfg(feature = "fs")]
19 use crate::ffi::CStr;
20 use crate::io;
21 use crate::pid::RawPid;
22 use crate::process::{
23     Cpuid, MembarrierCommand, MembarrierQuery, Pid, PidfdFlags, PidfdGetfdFlags, Resource, Rlimit,
24     Uid, WaitId, WaitOptions, WaitStatus, WaitidOptions, WaitidStatus,
25 };
26 use crate::signal::Signal;
27 use crate::utils::as_mut_ptr;
28 use core::mem::MaybeUninit;
29 use core::ptr::{null, null_mut};
30 use linux_raw_sys::general::{
31     membarrier_cmd, membarrier_cmd_flag, rlimit64, PRIO_PGRP, PRIO_PROCESS, PRIO_USER,
32     RLIM64_INFINITY,
33 };
34 #[cfg(feature = "fs")]
35 use {crate::backend::conv::ret_c_uint_infallible, crate::fs::Mode};
36 #[cfg(feature = "alloc")]
37 use {crate::backend::conv::slice_just_addr_mut, crate::process::Gid};
38 
39 // `sched_getcpu` has special optimizations via the vDSO on some architectures.
40 #[cfg(any(
41     target_arch = "x86_64",
42     target_arch = "x86",
43     target_arch = "riscv64",
44     target_arch = "powerpc64"
45 ))]
46 pub(crate) use crate::backend::vdso_wrappers::sched_getcpu;
47 
48 // `sched_getcpu` on platforms without a vDSO entry for it.
49 #[cfg(not(any(
50     target_arch = "x86_64",
51     target_arch = "x86",
52     target_arch = "riscv64",
53     target_arch = "powerpc64"
54 )))]
55 #[inline]
sched_getcpu() -> usize56 pub(crate) fn sched_getcpu() -> usize {
57     let mut cpu = MaybeUninit::<u32>::uninit();
58     unsafe {
59         let r = ret(syscall!(__NR_getcpu, &mut cpu, zero(), zero()));
60         debug_assert!(r.is_ok());
61         cpu.assume_init() as usize
62     }
63 }
64 
65 #[cfg(feature = "fs")]
66 #[inline]
chdir(filename: &CStr) -> io::Result<()>67 pub(crate) fn chdir(filename: &CStr) -> io::Result<()> {
68     unsafe { ret(syscall_readonly!(__NR_chdir, filename)) }
69 }
70 
71 #[inline]
fchdir(fd: BorrowedFd<'_>) -> io::Result<()>72 pub(crate) fn fchdir(fd: BorrowedFd<'_>) -> io::Result<()> {
73     unsafe { ret(syscall_readonly!(__NR_fchdir, fd)) }
74 }
75 
76 #[cfg(feature = "fs")]
77 #[inline]
chroot(filename: &CStr) -> io::Result<()>78 pub(crate) fn chroot(filename: &CStr) -> io::Result<()> {
79     unsafe { ret(syscall_readonly!(__NR_chroot, filename)) }
80 }
81 
82 #[cfg(all(feature = "alloc", feature = "fs"))]
83 #[inline]
getcwd(buf: &mut [MaybeUninit<u8>]) -> io::Result<usize>84 pub(crate) fn getcwd(buf: &mut [MaybeUninit<u8>]) -> io::Result<usize> {
85     let (buf_addr_mut, buf_len) = slice_mut(buf);
86     unsafe { ret_usize(syscall!(__NR_getcwd, buf_addr_mut, buf_len)) }
87 }
88 
89 #[inline]
membarrier_query() -> MembarrierQuery90 pub(crate) fn membarrier_query() -> MembarrierQuery {
91     unsafe {
92         match ret_c_uint(syscall!(
93             __NR_membarrier,
94             c_int(membarrier_cmd::MEMBARRIER_CMD_QUERY as _),
95             c_uint(0)
96         )) {
97             Ok(query) => MembarrierQuery::from_bits_retain(query),
98             Err(_) => MembarrierQuery::empty(),
99         }
100     }
101 }
102 
103 #[inline]
membarrier(cmd: MembarrierCommand) -> io::Result<()>104 pub(crate) fn membarrier(cmd: MembarrierCommand) -> io::Result<()> {
105     unsafe { ret(syscall!(__NR_membarrier, cmd, c_uint(0))) }
106 }
107 
108 #[inline]
membarrier_cpu(cmd: MembarrierCommand, cpu: Cpuid) -> io::Result<()>109 pub(crate) fn membarrier_cpu(cmd: MembarrierCommand, cpu: Cpuid) -> io::Result<()> {
110     unsafe {
111         ret(syscall!(
112             __NR_membarrier,
113             cmd,
114             c_uint(membarrier_cmd_flag::MEMBARRIER_CMD_FLAG_CPU as _),
115             cpu
116         ))
117     }
118 }
119 
120 #[inline]
getppid() -> Option<Pid>121 pub(crate) fn getppid() -> Option<Pid> {
122     unsafe {
123         let ppid = ret_c_int_infallible(syscall_readonly!(__NR_getppid));
124         Pid::from_raw(ppid)
125     }
126 }
127 
128 #[inline]
getpgid(pid: Option<Pid>) -> io::Result<Pid>129 pub(crate) fn getpgid(pid: Option<Pid>) -> io::Result<Pid> {
130     unsafe {
131         let pgid = ret_c_int(syscall_readonly!(__NR_getpgid, c_int(Pid::as_raw(pid))))?;
132         debug_assert!(pgid > 0);
133         Ok(Pid::from_raw_unchecked(pgid))
134     }
135 }
136 
137 #[inline]
setpgid(pid: Option<Pid>, pgid: Option<Pid>) -> io::Result<()>138 pub(crate) fn setpgid(pid: Option<Pid>, pgid: Option<Pid>) -> io::Result<()> {
139     unsafe {
140         ret(syscall_readonly!(
141             __NR_setpgid,
142             c_int(Pid::as_raw(pid)),
143             c_int(Pid::as_raw(pgid))
144         ))
145     }
146 }
147 
148 #[inline]
getpgrp() -> Pid149 pub(crate) fn getpgrp() -> Pid {
150     // Use the `getpgrp` syscall if available.
151     #[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))]
152     unsafe {
153         let pgid = ret_c_int_infallible(syscall_readonly!(__NR_getpgrp));
154         debug_assert!(pgid > 0);
155         Pid::from_raw_unchecked(pgid)
156     }
157 
158     // Otherwise use `getpgrp` and pass it zero.
159     #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
160     unsafe {
161         let pgid = ret_c_int_infallible(syscall_readonly!(__NR_getpgid, c_uint(0)));
162         debug_assert!(pgid > 0);
163         Pid::from_raw_unchecked(pgid)
164     }
165 }
166 
167 #[inline]
sched_getaffinity(pid: Option<Pid>, cpuset: &mut RawCpuSet) -> io::Result<()>168 pub(crate) fn sched_getaffinity(pid: Option<Pid>, cpuset: &mut RawCpuSet) -> io::Result<()> {
169     unsafe {
170         // The raw Linux syscall returns the size (in bytes) of the `cpumask_t`
171         // data type that is used internally by the kernel to represent the CPU
172         // set bit mask.
173         let size = ret_usize(syscall!(
174             __NR_sched_getaffinity,
175             c_int(Pid::as_raw(pid)),
176             size_of::<RawCpuSet, _>(),
177             by_mut(&mut cpuset.bits)
178         ))?;
179         let bytes = as_mut_ptr(cpuset).cast::<u8>();
180         let rest = bytes.wrapping_add(size);
181         // Zero every byte in the cpuset not set by the kernel.
182         rest.write_bytes(0, core::mem::size_of::<RawCpuSet>() - size);
183         Ok(())
184     }
185 }
186 
187 #[inline]
sched_setaffinity(pid: Option<Pid>, cpuset: &RawCpuSet) -> io::Result<()>188 pub(crate) fn sched_setaffinity(pid: Option<Pid>, cpuset: &RawCpuSet) -> io::Result<()> {
189     unsafe {
190         ret(syscall_readonly!(
191             __NR_sched_setaffinity,
192             c_int(Pid::as_raw(pid)),
193             size_of::<RawCpuSet, _>(),
194             slice_just_addr(&cpuset.bits)
195         ))
196     }
197 }
198 
199 #[inline]
sched_yield()200 pub(crate) fn sched_yield() {
201     unsafe {
202         // See the documentation for [`crate::process::sched_yield`] for why
203         // errors are ignored.
204         syscall_readonly!(__NR_sched_yield).decode_void();
205     }
206 }
207 
208 #[cfg(feature = "fs")]
209 #[inline]
umask(mode: Mode) -> Mode210 pub(crate) fn umask(mode: Mode) -> Mode {
211     unsafe { Mode::from_bits_retain(ret_c_uint_infallible(syscall_readonly!(__NR_umask, mode))) }
212 }
213 
214 #[inline]
nice(inc: i32) -> io::Result<i32>215 pub(crate) fn nice(inc: i32) -> io::Result<i32> {
216     let priority = (if inc > -40 && inc < 40 {
217         inc + getpriority_process(None)?
218     } else {
219         inc
220     })
221     .clamp(-20, 19);
222     setpriority_process(None, priority)?;
223     Ok(priority)
224 }
225 
226 #[inline]
getpriority_user(uid: Uid) -> io::Result<i32>227 pub(crate) fn getpriority_user(uid: Uid) -> io::Result<i32> {
228     unsafe {
229         Ok(20
230             - ret_c_int(syscall_readonly!(
231                 __NR_getpriority,
232                 c_uint(PRIO_USER),
233                 c_uint(uid.as_raw())
234             ))?)
235     }
236 }
237 
238 #[inline]
getpriority_pgrp(pgid: Option<Pid>) -> io::Result<i32>239 pub(crate) fn getpriority_pgrp(pgid: Option<Pid>) -> io::Result<i32> {
240     unsafe {
241         Ok(20
242             - ret_c_int(syscall_readonly!(
243                 __NR_getpriority,
244                 c_uint(PRIO_PGRP),
245                 c_int(Pid::as_raw(pgid))
246             ))?)
247     }
248 }
249 
250 #[inline]
getpriority_process(pid: Option<Pid>) -> io::Result<i32>251 pub(crate) fn getpriority_process(pid: Option<Pid>) -> io::Result<i32> {
252     unsafe {
253         Ok(20
254             - ret_c_int(syscall_readonly!(
255                 __NR_getpriority,
256                 c_uint(PRIO_PROCESS),
257                 c_int(Pid::as_raw(pid))
258             ))?)
259     }
260 }
261 
262 #[inline]
setpriority_user(uid: Uid, priority: i32) -> io::Result<()>263 pub(crate) fn setpriority_user(uid: Uid, priority: i32) -> io::Result<()> {
264     unsafe {
265         ret(syscall_readonly!(
266             __NR_setpriority,
267             c_uint(PRIO_USER),
268             c_uint(uid.as_raw()),
269             c_int(priority)
270         ))
271     }
272 }
273 
274 #[inline]
setpriority_pgrp(pgid: Option<Pid>, priority: i32) -> io::Result<()>275 pub(crate) fn setpriority_pgrp(pgid: Option<Pid>, priority: i32) -> io::Result<()> {
276     unsafe {
277         ret(syscall_readonly!(
278             __NR_setpriority,
279             c_uint(PRIO_PGRP),
280             c_int(Pid::as_raw(pgid)),
281             c_int(priority)
282         ))
283     }
284 }
285 
286 #[inline]
setpriority_process(pid: Option<Pid>, priority: i32) -> io::Result<()>287 pub(crate) fn setpriority_process(pid: Option<Pid>, priority: i32) -> io::Result<()> {
288     unsafe {
289         ret(syscall_readonly!(
290             __NR_setpriority,
291             c_uint(PRIO_PROCESS),
292             c_int(Pid::as_raw(pid)),
293             c_int(priority)
294         ))
295     }
296 }
297 
298 #[inline]
getrlimit(limit: Resource) -> Rlimit299 pub(crate) fn getrlimit(limit: Resource) -> Rlimit {
300     let mut result = MaybeUninit::<rlimit64>::uninit();
301     unsafe {
302         ret_infallible(syscall!(
303             __NR_prlimit64,
304             c_uint(0),
305             limit,
306             null::<c::c_void>(),
307             &mut result
308         ));
309         rlimit_from_linux(result.assume_init())
310     }
311 }
312 
313 #[inline]
setrlimit(limit: Resource, new: Rlimit) -> io::Result<()>314 pub(crate) fn setrlimit(limit: Resource, new: Rlimit) -> io::Result<()> {
315     unsafe {
316         let lim = rlimit_to_linux(new.clone());
317         match ret(syscall_readonly!(
318             __NR_prlimit64,
319             c_uint(0),
320             limit,
321             by_ref(&lim),
322             null_mut::<c::c_void>()
323         )) {
324             Ok(()) => Ok(()),
325             Err(err) => Err(err),
326         }
327     }
328 }
329 
330 #[inline]
prlimit(pid: Option<Pid>, limit: Resource, new: Rlimit) -> io::Result<Rlimit>331 pub(crate) fn prlimit(pid: Option<Pid>, limit: Resource, new: Rlimit) -> io::Result<Rlimit> {
332     let lim = rlimit_to_linux(new);
333     let mut result = MaybeUninit::<rlimit64>::uninit();
334     unsafe {
335         match ret(syscall!(
336             __NR_prlimit64,
337             c_int(Pid::as_raw(pid)),
338             limit,
339             by_ref(&lim),
340             &mut result
341         )) {
342             Ok(()) => Ok(rlimit_from_linux(result.assume_init())),
343             Err(err) => Err(err),
344         }
345     }
346 }
347 
348 /// Convert a Rust [`Rlimit`] to a C `rlimit64`.
349 #[inline]
rlimit_from_linux(lim: rlimit64) -> Rlimit350 fn rlimit_from_linux(lim: rlimit64) -> Rlimit {
351     let current = if lim.rlim_cur == RLIM64_INFINITY as _ {
352         None
353     } else {
354         Some(lim.rlim_cur)
355     };
356     let maximum = if lim.rlim_max == RLIM64_INFINITY as _ {
357         None
358     } else {
359         Some(lim.rlim_max)
360     };
361     Rlimit { current, maximum }
362 }
363 
364 /// Convert a C `rlimit64` to a Rust `Rlimit`.
365 #[inline]
rlimit_to_linux(lim: Rlimit) -> rlimit64366 fn rlimit_to_linux(lim: Rlimit) -> rlimit64 {
367     let rlim_cur = match lim.current {
368         Some(r) => r,
369         None => RLIM64_INFINITY as _,
370     };
371     let rlim_max = match lim.maximum {
372         Some(r) => r,
373         None => RLIM64_INFINITY as _,
374     };
375     rlimit64 { rlim_cur, rlim_max }
376 }
377 
378 #[inline]
wait(waitopts: WaitOptions) -> io::Result<Option<(Pid, WaitStatus)>>379 pub(crate) fn wait(waitopts: WaitOptions) -> io::Result<Option<(Pid, WaitStatus)>> {
380     _waitpid(!0, waitopts)
381 }
382 
383 #[inline]
waitpid( pid: Option<Pid>, waitopts: WaitOptions, ) -> io::Result<Option<(Pid, WaitStatus)>>384 pub(crate) fn waitpid(
385     pid: Option<Pid>,
386     waitopts: WaitOptions,
387 ) -> io::Result<Option<(Pid, WaitStatus)>> {
388     _waitpid(Pid::as_raw(pid), waitopts)
389 }
390 
391 #[inline]
waitpgid(pgid: Pid, waitopts: WaitOptions) -> io::Result<Option<(Pid, WaitStatus)>>392 pub(crate) fn waitpgid(pgid: Pid, waitopts: WaitOptions) -> io::Result<Option<(Pid, WaitStatus)>> {
393     _waitpid(-pgid.as_raw_nonzero().get(), waitopts)
394 }
395 
396 #[inline]
_waitpid( pid: RawPid, waitopts: WaitOptions, ) -> io::Result<Option<(Pid, WaitStatus)>>397 pub(crate) fn _waitpid(
398     pid: RawPid,
399     waitopts: WaitOptions,
400 ) -> io::Result<Option<(Pid, WaitStatus)>> {
401     unsafe {
402         let mut status = MaybeUninit::<u32>::uninit();
403         let pid = ret_c_int(syscall!(
404             __NR_wait4,
405             c_int(pid as _),
406             &mut status,
407             c_int(waitopts.bits() as _),
408             zero()
409         ))?;
410         Ok(Pid::from_raw(pid).map(|pid| (pid, WaitStatus::new(status.assume_init()))))
411     }
412 }
413 
414 #[inline]
waitid(id: WaitId<'_>, options: WaitidOptions) -> io::Result<Option<WaitidStatus>>415 pub(crate) fn waitid(id: WaitId<'_>, options: WaitidOptions) -> io::Result<Option<WaitidStatus>> {
416     // Get the id to wait on.
417     match id {
418         WaitId::All => _waitid_all(options),
419         WaitId::Pid(pid) => _waitid_pid(pid, options),
420         WaitId::Pgid(pid) => _waitid_pgid(pid, options),
421         WaitId::PidFd(fd) => _waitid_pidfd(fd, options),
422     }
423 }
424 
425 #[inline]
_waitid_all(options: WaitidOptions) -> io::Result<Option<WaitidStatus>>426 fn _waitid_all(options: WaitidOptions) -> io::Result<Option<WaitidStatus>> {
427     // `waitid` can return successfully without initializing the struct (no
428     // children found when using `WNOHANG`)
429     let mut status = MaybeUninit::<c::siginfo_t>::zeroed();
430     unsafe {
431         ret(syscall!(
432             __NR_waitid,
433             c_uint(c::P_ALL),
434             c_uint(0),
435             by_mut(&mut status),
436             c_int(options.bits() as _),
437             zero()
438         ))?
439     };
440 
441     Ok(unsafe { cvt_waitid_status(status) })
442 }
443 
444 #[inline]
_waitid_pid(pid: Pid, options: WaitidOptions) -> io::Result<Option<WaitidStatus>>445 fn _waitid_pid(pid: Pid, options: WaitidOptions) -> io::Result<Option<WaitidStatus>> {
446     // `waitid` can return successfully without initializing the struct (no
447     // children found when using `WNOHANG`)
448     let mut status = MaybeUninit::<c::siginfo_t>::zeroed();
449     unsafe {
450         ret(syscall!(
451             __NR_waitid,
452             c_uint(c::P_PID),
453             c_int(Pid::as_raw(Some(pid))),
454             by_mut(&mut status),
455             c_int(options.bits() as _),
456             zero()
457         ))?
458     };
459 
460     Ok(unsafe { cvt_waitid_status(status) })
461 }
462 
463 #[inline]
_waitid_pgid(pgid: Option<Pid>, options: WaitidOptions) -> io::Result<Option<WaitidStatus>>464 fn _waitid_pgid(pgid: Option<Pid>, options: WaitidOptions) -> io::Result<Option<WaitidStatus>> {
465     // `waitid` can return successfully without initializing the struct (no
466     // children found when using `WNOHANG`)
467     let mut status = MaybeUninit::<c::siginfo_t>::zeroed();
468     unsafe {
469         ret(syscall!(
470             __NR_waitid,
471             c_uint(c::P_PGID),
472             c_int(Pid::as_raw(pgid)),
473             by_mut(&mut status),
474             c_int(options.bits() as _),
475             zero()
476         ))?
477     };
478 
479     Ok(unsafe { cvt_waitid_status(status) })
480 }
481 
482 #[inline]
_waitid_pidfd(fd: BorrowedFd<'_>, options: WaitidOptions) -> io::Result<Option<WaitidStatus>>483 fn _waitid_pidfd(fd: BorrowedFd<'_>, options: WaitidOptions) -> io::Result<Option<WaitidStatus>> {
484     // `waitid` can return successfully without initializing the struct (no
485     // children found when using `WNOHANG`)
486     let mut status = MaybeUninit::<c::siginfo_t>::zeroed();
487     unsafe {
488         ret(syscall!(
489             __NR_waitid,
490             c_uint(c::P_PIDFD),
491             c_uint(fd.as_raw_fd() as _),
492             by_mut(&mut status),
493             c_int(options.bits() as _),
494             zero()
495         ))?
496     };
497 
498     Ok(unsafe { cvt_waitid_status(status) })
499 }
500 
501 /// Convert a `siginfo_t` to a `WaitidStatus`.
502 ///
503 /// # Safety
504 ///
505 /// The caller must ensure that `status` is initialized and that `waitid`
506 /// returned successfully.
507 #[inline]
508 #[rustfmt::skip]
cvt_waitid_status(status: MaybeUninit<c::siginfo_t>) -> Option<WaitidStatus>509 unsafe fn cvt_waitid_status(status: MaybeUninit<c::siginfo_t>) -> Option<WaitidStatus> {
510     let status = status.assume_init();
511     if status.__bindgen_anon_1.__bindgen_anon_1._sifields._sigchld._pid == 0 {
512         None
513     } else {
514         Some(WaitidStatus(status))
515     }
516 }
517 
518 #[inline]
getsid(pid: Option<Pid>) -> io::Result<Pid>519 pub(crate) fn getsid(pid: Option<Pid>) -> io::Result<Pid> {
520     unsafe {
521         let pid = ret_c_int(syscall_readonly!(__NR_getsid, c_int(Pid::as_raw(pid))))?;
522         Ok(Pid::from_raw_unchecked(pid))
523     }
524 }
525 
526 #[inline]
setsid() -> io::Result<Pid>527 pub(crate) fn setsid() -> io::Result<Pid> {
528     unsafe {
529         let pid = ret_c_int(syscall_readonly!(__NR_setsid))?;
530         Ok(Pid::from_raw_unchecked(pid))
531     }
532 }
533 
534 #[inline]
kill_process(pid: Pid, sig: Signal) -> io::Result<()>535 pub(crate) fn kill_process(pid: Pid, sig: Signal) -> io::Result<()> {
536     unsafe { ret(syscall_readonly!(__NR_kill, pid, sig)) }
537 }
538 
539 #[inline]
kill_process_group(pid: Pid, sig: Signal) -> io::Result<()>540 pub(crate) fn kill_process_group(pid: Pid, sig: Signal) -> io::Result<()> {
541     unsafe { ret(syscall_readonly!(__NR_kill, negative_pid(pid), sig)) }
542 }
543 
544 #[inline]
kill_current_process_group(sig: Signal) -> io::Result<()>545 pub(crate) fn kill_current_process_group(sig: Signal) -> io::Result<()> {
546     unsafe { ret(syscall_readonly!(__NR_kill, pass_usize(0), sig)) }
547 }
548 
549 #[inline]
test_kill_process(pid: Pid) -> io::Result<()>550 pub(crate) fn test_kill_process(pid: Pid) -> io::Result<()> {
551     unsafe { ret(syscall_readonly!(__NR_kill, pid, pass_usize(0))) }
552 }
553 
554 #[inline]
test_kill_process_group(pid: Pid) -> io::Result<()>555 pub(crate) fn test_kill_process_group(pid: Pid) -> io::Result<()> {
556     unsafe {
557         ret(syscall_readonly!(
558             __NR_kill,
559             negative_pid(pid),
560             pass_usize(0)
561         ))
562     }
563 }
564 
565 #[inline]
test_kill_current_process_group() -> io::Result<()>566 pub(crate) fn test_kill_current_process_group() -> io::Result<()> {
567     unsafe { ret(syscall_readonly!(__NR_kill, pass_usize(0), pass_usize(0))) }
568 }
569 
570 #[inline]
pidfd_getfd( pidfd: BorrowedFd<'_>, targetfd: RawFd, flags: PidfdGetfdFlags, ) -> io::Result<OwnedFd>571 pub(crate) fn pidfd_getfd(
572     pidfd: BorrowedFd<'_>,
573     targetfd: RawFd,
574     flags: PidfdGetfdFlags,
575 ) -> io::Result<OwnedFd> {
576     unsafe {
577         ret_owned_fd(syscall_readonly!(
578             __NR_pidfd_getfd,
579             pidfd,
580             raw_fd(targetfd),
581             c_int(flags.bits() as _)
582         ))
583     }
584 }
585 
586 #[inline]
pidfd_open(pid: Pid, flags: PidfdFlags) -> io::Result<OwnedFd>587 pub(crate) fn pidfd_open(pid: Pid, flags: PidfdFlags) -> io::Result<OwnedFd> {
588     unsafe { ret_owned_fd(syscall_readonly!(__NR_pidfd_open, pid, flags)) }
589 }
590 
591 #[cfg(feature = "alloc")]
592 #[inline]
getgroups(buf: &mut [Gid]) -> io::Result<usize>593 pub(crate) fn getgroups(buf: &mut [Gid]) -> io::Result<usize> {
594     let len = buf.len().try_into().map_err(|_| io::Errno::NOMEM)?;
595 
596     unsafe {
597         ret_usize(syscall!(
598             __NR_getgroups,
599             c_int(len),
600             slice_just_addr_mut(buf)
601         ))
602     }
603 }
604