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