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