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