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