• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! libc syscalls supporting `rustix::process`.
2 
3 #[cfg(any(freebsdlike, linux_kernel, target_os = "fuchsia"))]
4 use super::types::RawCpuSet;
5 use crate::backend::c;
6 #[cfg(not(any(target_os = "wasi", target_os = "fuchsia")))]
7 use crate::backend::conv::borrowed_fd;
8 #[cfg(feature = "fs")]
9 use crate::backend::conv::c_str;
10 #[cfg(all(feature = "alloc", feature = "fs", not(target_os = "wasi")))]
11 use crate::backend::conv::ret_discarded_char_ptr;
12 #[cfg(not(any(
13     target_os = "espidf",
14     target_os = "fuchsia",
15     target_os = "redox",
16     target_os = "vita",
17     target_os = "wasi"
18 )))]
19 use crate::backend::conv::ret_infallible;
20 #[cfg(not(target_os = "wasi"))]
21 use crate::backend::conv::ret_pid_t;
22 #[cfg(linux_kernel)]
23 use crate::backend::conv::ret_u32;
24 #[cfg(all(feature = "alloc", not(target_os = "wasi")))]
25 use crate::backend::conv::ret_usize;
26 use crate::backend::conv::{ret, ret_c_int};
27 #[cfg(not(any(target_os = "wasi", target_os = "fuchsia")))]
28 use crate::fd::BorrowedFd;
29 #[cfg(target_os = "linux")]
30 use crate::fd::{AsRawFd, OwnedFd, RawFd};
31 #[cfg(feature = "fs")]
32 use crate::ffi::CStr;
33 #[cfg(feature = "fs")]
34 use crate::fs::Mode;
35 use crate::io;
36 #[cfg(all(feature = "alloc", not(target_os = "wasi")))]
37 use crate::process::Gid;
38 #[cfg(not(target_os = "wasi"))]
39 use crate::process::Pid;
40 #[cfg(not(any(target_os = "espidf", target_os = "wasi")))]
41 use crate::process::Signal;
42 #[cfg(not(any(
43     target_os = "espidf",
44     target_os = "fuchsia",
45     target_os = "vita",
46     target_os = "wasi"
47 )))]
48 use crate::process::Uid;
49 #[cfg(linux_kernel)]
50 use crate::process::{Cpuid, MembarrierCommand, MembarrierQuery};
51 #[cfg(not(any(target_os = "espidf", target_os = "vita", target_os = "wasi")))]
52 use crate::process::{RawPid, WaitOptions, WaitStatus};
53 #[cfg(not(any(
54     target_os = "espidf",
55     target_os = "fuchsia",
56     target_os = "redox",
57     target_os = "vita",
58     target_os = "wasi"
59 )))]
60 use crate::process::{Resource, Rlimit};
61 #[cfg(not(any(
62     target_os = "espidf",
63     target_os = "redox",
64     target_os = "openbsd",
65     target_os = "vita",
66     target_os = "wasi"
67 )))]
68 use crate::process::{WaitId, WaitidOptions, WaitidStatus};
69 use core::mem::MaybeUninit;
70 #[cfg(target_os = "linux")]
71 use {
72     super::super::conv::ret_owned_fd, crate::process::PidfdFlags, crate::process::PidfdGetfdFlags,
73 };
74 
75 use errno as libc_errno;
76 
77 #[cfg(any(linux_kernel, target_os = "dragonfly"))]
78 #[inline]
sched_getcpu() -> usize79 pub(crate) fn sched_getcpu() -> usize {
80     let r = unsafe { libc::sched_getcpu() };
81     debug_assert!(r >= 0);
82     r as usize
83 }
84 
85 #[cfg(feature = "fs")]
86 #[cfg(not(target_os = "wasi"))]
chdir(path: &CStr) -> io::Result<()>87 pub(crate) fn chdir(path: &CStr) -> io::Result<()> {
88     unsafe { ret(c::chdir(c_str(path))) }
89 }
90 
91 #[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))]
fchdir(dirfd: BorrowedFd<'_>) -> io::Result<()>92 pub(crate) fn fchdir(dirfd: BorrowedFd<'_>) -> io::Result<()> {
93     unsafe { ret(c::fchdir(borrowed_fd(dirfd))) }
94 }
95 
96 #[cfg(feature = "fs")]
97 #[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))]
chroot(path: &CStr) -> io::Result<()>98 pub(crate) fn chroot(path: &CStr) -> io::Result<()> {
99     unsafe { ret(c::chroot(c_str(path))) }
100 }
101 
102 #[cfg(all(feature = "alloc", feature = "fs"))]
103 #[cfg(not(target_os = "wasi"))]
getcwd(buf: &mut [MaybeUninit<u8>]) -> io::Result<()>104 pub(crate) fn getcwd(buf: &mut [MaybeUninit<u8>]) -> io::Result<()> {
105     unsafe { ret_discarded_char_ptr(c::getcwd(buf.as_mut_ptr().cast(), buf.len())) }
106 }
107 
108 // The `membarrier` syscall has a third argument, but it's only used when
109 // the `flags` argument is `MEMBARRIER_CMD_FLAG_CPU`.
110 #[cfg(linux_kernel)]
111 syscall! {
112     fn membarrier_all(
113         cmd: c::c_int,
114         flags: c::c_uint
115     ) via SYS_membarrier -> c::c_int
116 }
117 
118 #[cfg(linux_kernel)]
membarrier_query() -> MembarrierQuery119 pub(crate) fn membarrier_query() -> MembarrierQuery {
120     // glibc does not have a wrapper for `membarrier`; [the documentation]
121     // says to use `syscall`.
122     //
123     // [the documentation]: https://man7.org/linux/man-pages/man2/membarrier.2.html#NOTES
124     const MEMBARRIER_CMD_QUERY: u32 = 0;
125     unsafe {
126         match ret_u32(membarrier_all(MEMBARRIER_CMD_QUERY as i32, 0)) {
127             Ok(query) => MembarrierQuery::from_bits_retain(query),
128             Err(_) => MembarrierQuery::empty(),
129         }
130     }
131 }
132 
133 #[cfg(linux_kernel)]
membarrier(cmd: MembarrierCommand) -> io::Result<()>134 pub(crate) fn membarrier(cmd: MembarrierCommand) -> io::Result<()> {
135     unsafe { ret(membarrier_all(cmd as i32, 0)) }
136 }
137 
138 #[cfg(linux_kernel)]
membarrier_cpu(cmd: MembarrierCommand, cpu: Cpuid) -> io::Result<()>139 pub(crate) fn membarrier_cpu(cmd: MembarrierCommand, cpu: Cpuid) -> io::Result<()> {
140     const MEMBARRIER_CMD_FLAG_CPU: u32 = 1;
141 
142     syscall! {
143         fn membarrier_cpu(
144             cmd: c::c_int,
145             flags: c::c_uint,
146             cpu_id: c::c_int
147         ) via SYS_membarrier -> c::c_int
148     }
149 
150     unsafe {
151         ret(membarrier_cpu(
152             cmd as i32,
153             MEMBARRIER_CMD_FLAG_CPU,
154             bitcast!(cpu.as_raw()),
155         ))
156     }
157 }
158 
159 #[cfg(not(target_os = "wasi"))]
160 #[inline]
161 #[must_use]
getppid() -> Option<Pid>162 pub(crate) fn getppid() -> Option<Pid> {
163     unsafe {
164         let pid: i32 = c::getppid();
165         Pid::from_raw(pid)
166     }
167 }
168 
169 #[cfg(not(target_os = "wasi"))]
170 #[inline]
getpgid(pid: Option<Pid>) -> io::Result<Pid>171 pub(crate) fn getpgid(pid: Option<Pid>) -> io::Result<Pid> {
172     unsafe {
173         let pgid = ret_pid_t(c::getpgid(Pid::as_raw(pid) as _))?;
174         Ok(Pid::from_raw_unchecked(pgid))
175     }
176 }
177 
178 #[cfg(not(target_os = "wasi"))]
179 #[inline]
setpgid(pid: Option<Pid>, pgid: Option<Pid>) -> io::Result<()>180 pub(crate) fn setpgid(pid: Option<Pid>, pgid: Option<Pid>) -> io::Result<()> {
181     unsafe { ret(c::setpgid(Pid::as_raw(pid) as _, Pid::as_raw(pgid) as _)) }
182 }
183 
184 #[cfg(not(target_os = "wasi"))]
185 #[inline]
186 #[must_use]
getpgrp() -> Pid187 pub(crate) fn getpgrp() -> Pid {
188     unsafe {
189         let pgid = c::getpgrp();
190         Pid::from_raw_unchecked(pgid)
191     }
192 }
193 
194 #[cfg(any(freebsdlike, linux_kernel, target_os = "fuchsia"))]
195 #[inline]
sched_getaffinity(pid: Option<Pid>, cpuset: &mut RawCpuSet) -> io::Result<()>196 pub(crate) fn sched_getaffinity(pid: Option<Pid>, cpuset: &mut RawCpuSet) -> io::Result<()> {
197     unsafe {
198         ret(c::sched_getaffinity(
199             Pid::as_raw(pid) as _,
200             core::mem::size_of::<RawCpuSet>(),
201             cpuset,
202         ))
203     }
204 }
205 
206 #[cfg(any(freebsdlike, linux_kernel, target_os = "fuchsia"))]
207 #[inline]
sched_setaffinity(pid: Option<Pid>, cpuset: &RawCpuSet) -> io::Result<()>208 pub(crate) fn sched_setaffinity(pid: Option<Pid>, cpuset: &RawCpuSet) -> io::Result<()> {
209     unsafe {
210         ret(c::sched_setaffinity(
211             Pid::as_raw(pid) as _,
212             core::mem::size_of::<RawCpuSet>(),
213             cpuset,
214         ))
215     }
216 }
217 
218 #[inline]
sched_yield()219 pub(crate) fn sched_yield() {
220     unsafe {
221         let _ = c::sched_yield();
222     }
223 }
224 
225 #[cfg(not(target_os = "wasi"))]
226 #[cfg(feature = "fs")]
227 #[inline]
umask(mask: Mode) -> Mode228 pub(crate) fn umask(mask: Mode) -> Mode {
229     unsafe { Mode::from_bits_retain(c::umask(mask.bits() as c::mode_t).into()) }
230 }
231 
232 #[cfg(not(any(target_os = "fuchsia", target_os = "vita", target_os = "wasi")))]
233 #[inline]
nice(inc: i32) -> io::Result<i32>234 pub(crate) fn nice(inc: i32) -> io::Result<i32> {
235     libc_errno::set_errno(libc_errno::Errno(0));
236     let r = unsafe { c::nice(inc) };
237     if libc_errno::errno().0 != 0 {
238         ret_c_int(r)
239     } else {
240         Ok(r)
241     }
242 }
243 
244 #[cfg(not(any(
245     target_os = "espidf",
246     target_os = "fuchsia",
247     target_os = "vita",
248     target_os = "wasi"
249 )))]
250 #[inline]
getpriority_user(uid: Uid) -> io::Result<i32>251 pub(crate) fn getpriority_user(uid: Uid) -> io::Result<i32> {
252     libc_errno::set_errno(libc_errno::Errno(0));
253     let r = unsafe { c::getpriority(c::PRIO_USER, uid.as_raw() as _) };
254     if libc_errno::errno().0 != 0 {
255         ret_c_int(r)
256     } else {
257         Ok(r)
258     }
259 }
260 
261 #[cfg(not(any(
262     target_os = "espidf",
263     target_os = "fuchsia",
264     target_os = "vita",
265     target_os = "wasi"
266 )))]
267 #[inline]
getpriority_pgrp(pgid: Option<Pid>) -> io::Result<i32>268 pub(crate) fn getpriority_pgrp(pgid: Option<Pid>) -> io::Result<i32> {
269     libc_errno::set_errno(libc_errno::Errno(0));
270     let r = unsafe { c::getpriority(c::PRIO_PGRP, Pid::as_raw(pgid) as _) };
271     if libc_errno::errno().0 != 0 {
272         ret_c_int(r)
273     } else {
274         Ok(r)
275     }
276 }
277 
278 #[cfg(not(any(
279     target_os = "espidf",
280     target_os = "fuchsia",
281     target_os = "vita",
282     target_os = "wasi"
283 )))]
284 #[inline]
getpriority_process(pid: Option<Pid>) -> io::Result<i32>285 pub(crate) fn getpriority_process(pid: Option<Pid>) -> io::Result<i32> {
286     libc_errno::set_errno(libc_errno::Errno(0));
287     let r = unsafe { c::getpriority(c::PRIO_PROCESS, Pid::as_raw(pid) as _) };
288     if libc_errno::errno().0 != 0 {
289         ret_c_int(r)
290     } else {
291         Ok(r)
292     }
293 }
294 
295 #[cfg(not(any(
296     target_os = "espidf",
297     target_os = "fuchsia",
298     target_os = "vita",
299     target_os = "wasi"
300 )))]
301 #[inline]
setpriority_user(uid: Uid, priority: i32) -> io::Result<()>302 pub(crate) fn setpriority_user(uid: Uid, priority: i32) -> io::Result<()> {
303     unsafe { ret(c::setpriority(c::PRIO_USER, uid.as_raw() as _, priority)) }
304 }
305 
306 #[cfg(not(any(
307     target_os = "espidf",
308     target_os = "fuchsia",
309     target_os = "vita",
310     target_os = "wasi"
311 )))]
312 #[inline]
setpriority_pgrp(pgid: Option<Pid>, priority: i32) -> io::Result<()>313 pub(crate) fn setpriority_pgrp(pgid: Option<Pid>, priority: i32) -> io::Result<()> {
314     unsafe {
315         ret(c::setpriority(
316             c::PRIO_PGRP,
317             Pid::as_raw(pgid) as _,
318             priority,
319         ))
320     }
321 }
322 
323 #[cfg(not(any(
324     target_os = "espidf",
325     target_os = "fuchsia",
326     target_os = "vita",
327     target_os = "wasi"
328 )))]
329 #[inline]
setpriority_process(pid: Option<Pid>, priority: i32) -> io::Result<()>330 pub(crate) fn setpriority_process(pid: Option<Pid>, priority: i32) -> io::Result<()> {
331     unsafe {
332         ret(c::setpriority(
333             c::PRIO_PROCESS,
334             Pid::as_raw(pid) as _,
335             priority,
336         ))
337     }
338 }
339 
340 #[cfg(not(any(
341     target_os = "espidf",
342     target_os = "fuchsia",
343     target_os = "redox",
344     target_os = "vita",
345     target_os = "wasi"
346 )))]
347 #[inline]
getrlimit(limit: Resource) -> Rlimit348 pub(crate) fn getrlimit(limit: Resource) -> Rlimit {
349     let mut result = MaybeUninit::<c::rlimit>::uninit();
350     unsafe {
351         ret_infallible(c::getrlimit(limit as _, result.as_mut_ptr()));
352         rlimit_from_libc(result.assume_init())
353     }
354 }
355 
356 #[cfg(not(any(
357     target_os = "espidf",
358     target_os = "fuchsia",
359     target_os = "redox",
360     target_os = "vita",
361     target_os = "wasi"
362 )))]
363 #[inline]
setrlimit(limit: Resource, new: Rlimit) -> io::Result<()>364 pub(crate) fn setrlimit(limit: Resource, new: Rlimit) -> io::Result<()> {
365     let lim = rlimit_to_libc(new)?;
366     unsafe { ret(c::setrlimit(limit as _, &lim)) }
367 }
368 
369 #[cfg(linux_kernel)]
370 #[inline]
prlimit(pid: Option<Pid>, limit: Resource, new: Rlimit) -> io::Result<Rlimit>371 pub(crate) fn prlimit(pid: Option<Pid>, limit: Resource, new: Rlimit) -> io::Result<Rlimit> {
372     let lim = rlimit_to_libc(new)?;
373     let mut result = MaybeUninit::<c::rlimit>::uninit();
374     unsafe {
375         ret(c::prlimit(
376             Pid::as_raw(pid),
377             limit as _,
378             &lim,
379             result.as_mut_ptr(),
380         ))?;
381         Ok(rlimit_from_libc(result.assume_init()))
382     }
383 }
384 
385 /// Convert a Rust [`Rlimit`] to a C `c::rlimit`.
386 #[cfg(not(any(
387     target_os = "espidf",
388     target_os = "fuchsia",
389     target_os = "redox",
390     target_os = "vita",
391     target_os = "wasi"
392 )))]
rlimit_from_libc(lim: c::rlimit) -> Rlimit393 fn rlimit_from_libc(lim: c::rlimit) -> Rlimit {
394     let current = if lim.rlim_cur == c::RLIM_INFINITY {
395         None
396     } else {
397         Some(lim.rlim_cur.try_into().unwrap())
398     };
399     let maximum = if lim.rlim_max == c::RLIM_INFINITY {
400         None
401     } else {
402         Some(lim.rlim_max.try_into().unwrap())
403     };
404     Rlimit { current, maximum }
405 }
406 
407 /// Convert a C `c::rlimit` to a Rust `Rlimit`.
408 #[cfg(not(any(
409     target_os = "espidf",
410     target_os = "fuchsia",
411     target_os = "redox",
412     target_os = "vita",
413     target_os = "wasi"
414 )))]
rlimit_to_libc(lim: Rlimit) -> io::Result<c::rlimit>415 fn rlimit_to_libc(lim: Rlimit) -> io::Result<c::rlimit> {
416     let Rlimit { current, maximum } = lim;
417     let rlim_cur = match current {
418         Some(r) => r.try_into().map_err(|_e| io::Errno::INVAL)?,
419         None => c::RLIM_INFINITY as _,
420     };
421     let rlim_max = match maximum {
422         Some(r) => r.try_into().map_err(|_e| io::Errno::INVAL)?,
423         None => c::RLIM_INFINITY as _,
424     };
425     Ok(c::rlimit { rlim_cur, rlim_max })
426 }
427 
428 #[cfg(not(any(target_os = "espidf", target_os = "vita", target_os = "wasi")))]
429 #[inline]
wait(waitopts: WaitOptions) -> io::Result<Option<(Pid, WaitStatus)>>430 pub(crate) fn wait(waitopts: WaitOptions) -> io::Result<Option<(Pid, WaitStatus)>> {
431     _waitpid(!0, waitopts)
432 }
433 
434 #[cfg(not(any(target_os = "espidf", target_os = "vita", target_os = "wasi")))]
435 #[inline]
waitpid( pid: Option<Pid>, waitopts: WaitOptions, ) -> io::Result<Option<(Pid, WaitStatus)>>436 pub(crate) fn waitpid(
437     pid: Option<Pid>,
438     waitopts: WaitOptions,
439 ) -> io::Result<Option<(Pid, WaitStatus)>> {
440     _waitpid(Pid::as_raw(pid), waitopts)
441 }
442 
443 #[cfg(not(any(target_os = "espidf", target_os = "vita", target_os = "wasi")))]
444 #[inline]
waitpgid(pgid: Pid, waitopts: WaitOptions) -> io::Result<Option<(Pid, WaitStatus)>>445 pub(crate) fn waitpgid(pgid: Pid, waitopts: WaitOptions) -> io::Result<Option<(Pid, WaitStatus)>> {
446     _waitpid(-pgid.as_raw_nonzero().get(), waitopts)
447 }
448 
449 #[cfg(not(any(target_os = "espidf", target_os = "vita", target_os = "wasi")))]
450 #[inline]
_waitpid( pid: RawPid, waitopts: WaitOptions, ) -> io::Result<Option<(Pid, WaitStatus)>>451 pub(crate) fn _waitpid(
452     pid: RawPid,
453     waitopts: WaitOptions,
454 ) -> io::Result<Option<(Pid, WaitStatus)>> {
455     unsafe {
456         let mut status: c::c_int = 0;
457         let pid = ret_c_int(c::waitpid(pid as _, &mut status, waitopts.bits() as _))?;
458         Ok(Pid::from_raw(pid).map(|pid| (pid, WaitStatus::new(status as _))))
459     }
460 }
461 
462 #[cfg(not(any(
463     target_os = "espidf",
464     target_os = "redox",
465     target_os = "openbsd",
466     target_os = "vita",
467     target_os = "wasi"
468 )))]
469 #[inline]
waitid(id: WaitId<'_>, options: WaitidOptions) -> io::Result<Option<WaitidStatus>>470 pub(crate) fn waitid(id: WaitId<'_>, options: WaitidOptions) -> io::Result<Option<WaitidStatus>> {
471     // Get the id to wait on.
472     match id {
473         WaitId::All => _waitid_all(options),
474         WaitId::Pid(pid) => _waitid_pid(pid, options),
475         WaitId::Pgid(pgid) => _waitid_pgid(pgid, options),
476         #[cfg(target_os = "linux")]
477         WaitId::PidFd(fd) => _waitid_pidfd(fd, options),
478         #[cfg(not(target_os = "linux"))]
479         WaitId::__EatLifetime(_) => unreachable!(),
480     }
481 }
482 
483 #[cfg(not(any(
484     target_os = "espidf",
485     target_os = "redox",
486     target_os = "openbsd",
487     target_os = "vita",
488     target_os = "wasi"
489 )))]
490 #[inline]
_waitid_all(options: WaitidOptions) -> io::Result<Option<WaitidStatus>>491 fn _waitid_all(options: WaitidOptions) -> io::Result<Option<WaitidStatus>> {
492     // `waitid` can return successfully without initializing the struct (no
493     // children found when using `WNOHANG`)
494     let mut status = MaybeUninit::<c::siginfo_t>::zeroed();
495     unsafe {
496         ret(c::waitid(
497             c::P_ALL,
498             0,
499             status.as_mut_ptr(),
500             options.bits() as _,
501         ))?
502     };
503 
504     Ok(unsafe { cvt_waitid_status(status) })
505 }
506 
507 #[cfg(not(any(
508     target_os = "espidf",
509     target_os = "redox",
510     target_os = "openbsd",
511     target_os = "vita",
512     target_os = "wasi"
513 )))]
514 #[inline]
_waitid_pid(pid: Pid, options: WaitidOptions) -> io::Result<Option<WaitidStatus>>515 fn _waitid_pid(pid: Pid, options: WaitidOptions) -> io::Result<Option<WaitidStatus>> {
516     // `waitid` can return successfully without initializing the struct (no
517     // children found when using `WNOHANG`)
518     let mut status = MaybeUninit::<c::siginfo_t>::zeroed();
519     unsafe {
520         ret(c::waitid(
521             c::P_PID,
522             Pid::as_raw(Some(pid)) as _,
523             status.as_mut_ptr(),
524             options.bits() as _,
525         ))?
526     };
527 
528     Ok(unsafe { cvt_waitid_status(status) })
529 }
530 
531 #[cfg(not(any(
532     target_os = "espidf",
533     target_os = "redox",
534     target_os = "openbsd",
535     target_os = "vita",
536     target_os = "wasi"
537 )))]
538 #[inline]
_waitid_pgid(pgid: Option<Pid>, options: WaitidOptions) -> io::Result<Option<WaitidStatus>>539 fn _waitid_pgid(pgid: Option<Pid>, options: WaitidOptions) -> io::Result<Option<WaitidStatus>> {
540     // `waitid` can return successfully without initializing the struct (no
541     // children found when using `WNOHANG`)
542     let mut status = MaybeUninit::<c::siginfo_t>::zeroed();
543     unsafe {
544         ret(c::waitid(
545             c::P_PGID,
546             Pid::as_raw(pgid) as _,
547             status.as_mut_ptr(),
548             options.bits() as _,
549         ))?
550     };
551 
552     Ok(unsafe { cvt_waitid_status(status) })
553 }
554 
555 #[cfg(target_os = "linux")]
556 #[inline]
_waitid_pidfd(fd: BorrowedFd<'_>, options: WaitidOptions) -> io::Result<Option<WaitidStatus>>557 fn _waitid_pidfd(fd: BorrowedFd<'_>, options: WaitidOptions) -> io::Result<Option<WaitidStatus>> {
558     // `waitid` can return successfully without initializing the struct (no
559     // children found when using `WNOHANG`)
560     let mut status = MaybeUninit::<c::siginfo_t>::zeroed();
561     unsafe {
562         ret(c::waitid(
563             c::P_PIDFD,
564             fd.as_raw_fd() as _,
565             status.as_mut_ptr(),
566             options.bits() as _,
567         ))?
568     };
569 
570     Ok(unsafe { cvt_waitid_status(status) })
571 }
572 
573 /// Convert a `siginfo_t` to a `WaitidStatus`.
574 ///
575 /// # Safety
576 ///
577 /// The caller must ensure that `status` is initialized and that `waitid`
578 /// returned successfully.
579 #[cfg(not(any(
580     target_os = "espidf",
581     target_os = "openbsd",
582     target_os = "redox",
583     target_os = "vita",
584     target_os = "wasi"
585 )))]
586 #[inline]
cvt_waitid_status(status: MaybeUninit<c::siginfo_t>) -> Option<WaitidStatus>587 unsafe fn cvt_waitid_status(status: MaybeUninit<c::siginfo_t>) -> Option<WaitidStatus> {
588     let status = status.assume_init();
589     // `si_pid` is supposedly the better way to check that the struct has been
590     // filled, e.g. the Linux manpage says about the `WNOHANG` case “zero out
591     // the si_pid field before the call and check for a nonzero value”.
592     // But e.g. NetBSD/OpenBSD don't have it exposed in the libc crate for now,
593     // and some platforms don't have it at all. For simplicity, always check
594     // `si_signo`. We have zero-initialized the whole struct, and all kernels
595     // should set `SIGCHLD` here.
596     if status.si_signo == 0 {
597         None
598     } else {
599         Some(WaitidStatus(status))
600     }
601 }
602 
603 #[cfg(not(any(target_os = "redox", target_os = "wasi")))]
604 #[inline]
getsid(pid: Option<Pid>) -> io::Result<Pid>605 pub(crate) fn getsid(pid: Option<Pid>) -> io::Result<Pid> {
606     unsafe {
607         let pid = ret_pid_t(c::getsid(Pid::as_raw(pid) as _))?;
608         Ok(Pid::from_raw_unchecked(pid))
609     }
610 }
611 
612 #[cfg(not(target_os = "wasi"))]
613 #[inline]
setsid() -> io::Result<Pid>614 pub(crate) fn setsid() -> io::Result<Pid> {
615     unsafe {
616         let pid = ret_c_int(c::setsid())?;
617         Ok(Pid::from_raw_unchecked(pid))
618     }
619 }
620 
621 #[cfg(not(any(target_os = "espidf", target_os = "wasi")))]
622 #[inline]
kill_process(pid: Pid, sig: Signal) -> io::Result<()>623 pub(crate) fn kill_process(pid: Pid, sig: Signal) -> io::Result<()> {
624     unsafe { ret(c::kill(pid.as_raw_nonzero().get(), sig as i32)) }
625 }
626 
627 #[cfg(not(any(target_os = "espidf", target_os = "wasi")))]
628 #[inline]
kill_process_group(pid: Pid, sig: Signal) -> io::Result<()>629 pub(crate) fn kill_process_group(pid: Pid, sig: Signal) -> io::Result<()> {
630     unsafe {
631         ret(c::kill(
632             pid.as_raw_nonzero().get().wrapping_neg(),
633             sig as i32,
634         ))
635     }
636 }
637 
638 #[cfg(not(any(target_os = "espidf", target_os = "wasi")))]
639 #[inline]
kill_current_process_group(sig: Signal) -> io::Result<()>640 pub(crate) fn kill_current_process_group(sig: Signal) -> io::Result<()> {
641     unsafe { ret(c::kill(0, sig as i32)) }
642 }
643 
644 #[cfg(not(any(target_os = "espidf", target_os = "wasi")))]
test_kill_process(pid: Pid) -> io::Result<()>645 pub(crate) fn test_kill_process(pid: Pid) -> io::Result<()> {
646     unsafe { ret(c::kill(pid.as_raw_nonzero().get(), 0)) }
647 }
648 
649 #[cfg(not(any(target_os = "espidf", target_os = "wasi")))]
650 #[inline]
test_kill_process_group(pid: Pid) -> io::Result<()>651 pub(crate) fn test_kill_process_group(pid: Pid) -> io::Result<()> {
652     unsafe { ret(c::kill(pid.as_raw_nonzero().get().wrapping_neg(), 0)) }
653 }
654 
655 #[cfg(not(any(target_os = "espidf", target_os = "wasi")))]
656 #[inline]
test_kill_current_process_group() -> io::Result<()>657 pub(crate) fn test_kill_current_process_group() -> io::Result<()> {
658     unsafe { ret(c::kill(0, 0)) }
659 }
660 
661 #[cfg(freebsdlike)]
662 #[inline]
procctl( idtype: c::idtype_t, id: c::id_t, option: c::c_int, data: *mut c::c_void, ) -> io::Result<()>663 pub(crate) unsafe fn procctl(
664     idtype: c::idtype_t,
665     id: c::id_t,
666     option: c::c_int,
667     data: *mut c::c_void,
668 ) -> io::Result<()> {
669     ret(c::procctl(idtype, id, option, data))
670 }
671 
672 #[cfg(target_os = "linux")]
pidfd_open(pid: Pid, flags: PidfdFlags) -> io::Result<OwnedFd>673 pub(crate) fn pidfd_open(pid: Pid, flags: PidfdFlags) -> io::Result<OwnedFd> {
674     syscall! {
675         fn pidfd_open(
676             pid: c::pid_t,
677             flags: c::c_uint
678         ) via SYS_pidfd_open -> c::c_int
679     }
680     unsafe {
681         ret_owned_fd(pidfd_open(
682             pid.as_raw_nonzero().get(),
683             bitflags_bits!(flags),
684         ))
685     }
686 }
687 
688 #[cfg(target_os = "linux")]
pidfd_getfd( pidfd: BorrowedFd<'_>, targetfd: RawFd, flags: PidfdGetfdFlags, ) -> io::Result<OwnedFd>689 pub(crate) fn pidfd_getfd(
690     pidfd: BorrowedFd<'_>,
691     targetfd: RawFd,
692     flags: PidfdGetfdFlags,
693 ) -> io::Result<OwnedFd> {
694     syscall! {
695         fn pidfd_getfd(
696             pidfd: c::c_int,
697             targetfd: c::c_int,
698             flags: c::c_uint
699         ) via SYS_pidfd_getfd -> c::c_int
700     }
701     unsafe {
702         ret_owned_fd(pidfd_getfd(
703             borrowed_fd(pidfd),
704             targetfd,
705             bitflags_bits!(flags),
706         ))
707     }
708 }
709 
710 #[cfg(all(feature = "alloc", not(target_os = "wasi")))]
getgroups(buf: &mut [Gid]) -> io::Result<usize>711 pub(crate) fn getgroups(buf: &mut [Gid]) -> io::Result<usize> {
712     let len = buf.len().try_into().map_err(|_| io::Errno::NOMEM)?;
713 
714     unsafe { ret_usize(c::getgroups(len, buf.as_mut_ptr().cast()) as isize) }
715 }
716