1 | //! linux_raw syscalls supporting `rustix::process`. |
2 | //! |
3 | //! # Safety |
4 | //! |
5 | //! See the `rustix::backend` module documentation for details. |
6 | #![allow (unsafe_code)] |
7 | #![allow (clippy::undocumented_unsafe_blocks)] |
8 | |
9 | use super::super::c; |
10 | use super::super::conv::{ |
11 | by_mut, by_ref, c_int, c_uint, negative_pid, pass_usize, ret, ret_c_int, ret_c_uint, |
12 | ret_infallible, ret_usize, ret_usize_infallible, size_of, slice, slice_just_addr, |
13 | slice_just_addr_mut, slice_mut, zero, |
14 | }; |
15 | use super::types::{RawCpuSet, RawUname}; |
16 | use crate::backend::conv::ret_owned_fd; |
17 | use crate::fd::{AsRawFd, BorrowedFd, OwnedFd}; |
18 | use crate::ffi::CStr; |
19 | use crate::io; |
20 | use crate::process::{ |
21 | Cpuid, Gid, MembarrierCommand, MembarrierQuery, Pid, PidfdFlags, RawNonZeroPid, RawPid, |
22 | Resource, Rlimit, Signal, Sysinfo, Uid, WaitId, WaitOptions, WaitStatus, WaitidOptions, |
23 | WaitidStatus, |
24 | }; |
25 | use crate::utils::as_mut_ptr; |
26 | use core::convert::TryInto; |
27 | use core::mem::MaybeUninit; |
28 | use core::num::NonZeroU32; |
29 | use core::ptr::{null, null_mut}; |
30 | use linux_raw_sys::general::{ |
31 | __kernel_gid_t, __kernel_pid_t, __kernel_uid_t, membarrier_cmd, membarrier_cmd_flag, rlimit, |
32 | rlimit64, PRIO_PGRP, PRIO_PROCESS, PRIO_USER, RLIM64_INFINITY, RLIM_INFINITY, |
33 | }; |
34 | use linux_raw_sys::ioctl::TIOCSCTTY; |
35 | #[cfg (not(target_os = "wasi" ))] |
36 | #[cfg (feature = "fs" )] |
37 | use {super::super::conv::ret_c_uint_infallible, crate::fs::Mode}; |
38 | |
39 | #[inline ] |
40 | pub(crate) fn chdir(filename: &CStr) -> io::Result<()> { |
41 | unsafe { ret(raw:syscall_readonly!(__NR_chdir, filename)) } |
42 | } |
43 | |
44 | #[inline ] |
45 | pub(crate) fn fchdir(fd: BorrowedFd<'_>) -> io::Result<()> { |
46 | unsafe { ret(raw:syscall_readonly!(__NR_fchdir, fd)) } |
47 | } |
48 | |
49 | #[inline ] |
50 | pub(crate) fn chroot(filename: &CStr) -> io::Result<()> { |
51 | unsafe { ret(raw:syscall_readonly!(__NR_chroot, filename)) } |
52 | } |
53 | |
54 | #[inline ] |
55 | pub(crate) fn getcwd(buf: &mut [u8]) -> io::Result<usize> { |
56 | let (buf_addr_mut: ArgReg<'_, A0>, buf_len: ArgReg<'_, A1>) = slice_mut(buf); |
57 | unsafe { ret_usize(raw:syscall!(__NR_getcwd, buf_addr_mut, buf_len)) } |
58 | } |
59 | |
60 | #[inline ] |
61 | pub(crate) fn membarrier_query() -> MembarrierQuery { |
62 | unsafe { |
63 | match ret_c_uint(raw:syscall!( |
64 | __NR_membarrier, |
65 | c_int(membarrier_cmd::MEMBARRIER_CMD_QUERY as _), |
66 | c_uint(0) |
67 | )) { |
68 | Ok(query: u32) => { |
69 | // SAFETY: The safety of `from_bits_unchecked` is discussed |
70 | // [here]. Our "source of truth" is Linux, and here, the |
71 | // `query` value is coming from Linux, so we know it only |
72 | // contains "source of truth" valid bits. |
73 | // |
74 | // [here]: https://github.com/bitflags/bitflags/pull/207#issuecomment-671668662 |
75 | MembarrierQuery::from_bits_unchecked(bits:query) |
76 | } |
77 | Err(_) => MembarrierQuery::empty(), |
78 | } |
79 | } |
80 | } |
81 | |
82 | #[inline ] |
83 | pub(crate) fn membarrier(cmd: MembarrierCommand) -> io::Result<()> { |
84 | unsafe { ret(raw:syscall!(__NR_membarrier, cmd, c_uint(0))) } |
85 | } |
86 | |
87 | #[inline ] |
88 | pub(crate) fn membarrier_cpu(cmd: MembarrierCommand, cpu: Cpuid) -> io::Result<()> { |
89 | unsafe { |
90 | ret(raw:syscall!( |
91 | __NR_membarrier, |
92 | cmd, |
93 | c_uint(membarrier_cmd_flag::MEMBARRIER_CMD_FLAG_CPU as _), |
94 | cpu |
95 | )) |
96 | } |
97 | } |
98 | |
99 | #[inline ] |
100 | pub(crate) fn getpid() -> Pid { |
101 | unsafe { |
102 | let pid: i32 = ret_usize_infallible(raw:syscall_readonly!(__NR_getpid)) as __kernel_pid_t; |
103 | debug_assert!(pid > 0); |
104 | Pid::from_raw_nonzero(raw:RawNonZeroPid::new_unchecked(pid as u32)) |
105 | } |
106 | } |
107 | |
108 | #[inline ] |
109 | pub(crate) fn getppid() -> Option<Pid> { |
110 | unsafe { |
111 | let ppid: i32 = ret_usize_infallible(raw:syscall_readonly!(__NR_getppid)) as __kernel_pid_t; |
112 | Pid::from_raw(ppid as u32) |
113 | } |
114 | } |
115 | |
116 | #[inline ] |
117 | pub(crate) fn getpgid(pid: Option<Pid>) -> io::Result<Pid> { |
118 | unsafe { |
119 | let pgid: i32 = |
120 | ret_usize(raw:syscall_readonly!(__NR_getpgid, c_uint(Pid::as_raw(pid))))? as __kernel_pid_t; |
121 | Ok(Pid::from_raw_nonzero(raw:NonZeroU32::new_unchecked( |
122 | pgid as u32, |
123 | ))) |
124 | } |
125 | } |
126 | |
127 | #[inline ] |
128 | pub(crate) fn setpgid(pid: Option<Pid>, pgid: Option<Pid>) -> io::Result<()> { |
129 | unsafe { |
130 | ret(raw:syscall_readonly!( |
131 | __NR_setpgid, |
132 | c_uint(Pid::as_raw(pid)), |
133 | c_uint(Pid::as_raw(pgid)) |
134 | )) |
135 | } |
136 | } |
137 | |
138 | #[inline ] |
139 | pub(crate) fn getpgrp() -> Pid { |
140 | // Use the `getpgrp` syscall if available. |
141 | #[cfg (not(any(target_arch = "aarch64" , target_arch = "riscv64" )))] |
142 | unsafe { |
143 | let pgid: i32 = ret_usize_infallible(raw:syscall_readonly!(__NR_getpgrp)) as __kernel_pid_t; |
144 | debug_assert!(pgid > 0); |
145 | Pid::from_raw_nonzero(raw:RawNonZeroPid::new_unchecked(pgid as u32)) |
146 | } |
147 | |
148 | // Otherwise use `getpgrp` and pass it zero. |
149 | #[cfg (any(target_arch = "aarch64" , target_arch = "riscv64" ))] |
150 | unsafe { |
151 | let pgid: i32 = |
152 | ret_usize_infallible(syscall_readonly!(__NR_getpgid, c_uint(0))) as __kernel_pid_t; |
153 | debug_assert!(pgid > 0); |
154 | Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked(pgid as u32)) |
155 | } |
156 | } |
157 | |
158 | #[inline ] |
159 | pub(crate) fn getgid() -> Gid { |
160 | #[cfg (any(target_arch = "x86" , target_arch = "sparc" , target_arch = "arm" ))] |
161 | unsafe { |
162 | let gid: i32 = |
163 | (ret_usize_infallible(syscall_readonly!(__NR_getgid32)) as __kernel_gid_t).into(); |
164 | Gid::from_raw(gid as u32) |
165 | } |
166 | #[cfg (not(any(target_arch = "x86" , target_arch = "sparc" , target_arch = "arm" )))] |
167 | unsafe { |
168 | let gid: u32 = ret_usize_infallible(raw:syscall_readonly!(__NR_getgid)) as __kernel_gid_t; |
169 | Gid::from_raw(gid as u32) |
170 | } |
171 | } |
172 | |
173 | #[inline ] |
174 | pub(crate) fn getegid() -> Gid { |
175 | #[cfg (any(target_arch = "x86" , target_arch = "sparc" , target_arch = "arm" ))] |
176 | unsafe { |
177 | let gid: i32 = |
178 | (ret_usize_infallible(syscall_readonly!(__NR_getegid32)) as __kernel_gid_t).into(); |
179 | Gid::from_raw(gid as u32) |
180 | } |
181 | #[cfg (not(any(target_arch = "x86" , target_arch = "sparc" , target_arch = "arm" )))] |
182 | unsafe { |
183 | let gid: u32 = ret_usize_infallible(raw:syscall_readonly!(__NR_getegid)) as __kernel_gid_t; |
184 | Gid::from_raw(gid as u32) |
185 | } |
186 | } |
187 | |
188 | #[inline ] |
189 | pub(crate) fn getuid() -> Uid { |
190 | #[cfg (any(target_arch = "x86" , target_arch = "sparc" , target_arch = "arm" ))] |
191 | unsafe { |
192 | let uid = (ret_usize_infallible(syscall_readonly!(__NR_getuid32)) as __kernel_uid_t).into(); |
193 | Uid::from_raw(uid) |
194 | } |
195 | #[cfg (not(any(target_arch = "x86" , target_arch = "sparc" , target_arch = "arm" )))] |
196 | unsafe { |
197 | let uid: u32 = ret_usize_infallible(raw:syscall_readonly!(__NR_getuid)) as __kernel_uid_t; |
198 | Uid::from_raw(uid as u32) |
199 | } |
200 | } |
201 | |
202 | #[inline ] |
203 | pub(crate) fn geteuid() -> Uid { |
204 | #[cfg (any(target_arch = "x86" , target_arch = "sparc" , target_arch = "arm" ))] |
205 | unsafe { |
206 | let uid: i32 = |
207 | (ret_usize_infallible(syscall_readonly!(__NR_geteuid32)) as __kernel_uid_t).into(); |
208 | Uid::from_raw(uid as u32) |
209 | } |
210 | #[cfg (not(any(target_arch = "x86" , target_arch = "sparc" , target_arch = "arm" )))] |
211 | unsafe { |
212 | let uid: u32 = ret_usize_infallible(raw:syscall_readonly!(__NR_geteuid)) as __kernel_uid_t; |
213 | Uid::from_raw(uid as u32) |
214 | } |
215 | } |
216 | |
217 | #[inline ] |
218 | pub(crate) fn sched_getaffinity(pid: Option<Pid>, cpuset: &mut RawCpuSet) -> io::Result<()> { |
219 | unsafe { |
220 | // The raw linux syscall returns the size (in bytes) of the `cpumask_t` |
221 | // data type that is used internally by the kernel to represent the CPU |
222 | // set bit mask. |
223 | let size: usize = ret_usize(raw:syscall!( |
224 | __NR_sched_getaffinity, |
225 | c_uint(Pid::as_raw(pid)), |
226 | size_of::<RawCpuSet, _>(), |
227 | by_mut(&mut cpuset.bits) |
228 | ))?; |
229 | let bytes: *mut u8 = as_mut_ptr(cpuset).cast::<u8>(); |
230 | let rest: *mut u8 = bytes.wrapping_add(count:size); |
231 | // Zero every byte in the cpuset not set by the kernel. |
232 | rest.write_bytes(val:0, count:core::mem::size_of::<RawCpuSet>() - size); |
233 | Ok(()) |
234 | } |
235 | } |
236 | |
237 | #[inline ] |
238 | pub(crate) fn sched_setaffinity(pid: Option<Pid>, cpuset: &RawCpuSet) -> io::Result<()> { |
239 | unsafe { |
240 | ret(raw:syscall_readonly!( |
241 | __NR_sched_setaffinity, |
242 | c_uint(Pid::as_raw(pid)), |
243 | size_of::<RawCpuSet, _>(), |
244 | slice_just_addr(&cpuset.bits) |
245 | )) |
246 | } |
247 | } |
248 | |
249 | #[inline ] |
250 | pub(crate) fn sched_yield() { |
251 | unsafe { |
252 | // See the documentation for [`crate::process::sched_yield`] for why |
253 | // errors are ignored. |
254 | syscall_readonly!(__NR_sched_yield).decode_void(); |
255 | } |
256 | } |
257 | |
258 | #[inline ] |
259 | pub(crate) fn uname() -> RawUname { |
260 | let mut uname: MaybeUninit = MaybeUninit::<RawUname>::uninit(); |
261 | unsafe { |
262 | ret_infallible(raw:syscall!(__NR_uname, &mut uname)); |
263 | uname.assume_init() |
264 | } |
265 | } |
266 | |
267 | #[cfg (feature = "fs" )] |
268 | #[inline ] |
269 | pub(crate) fn umask(mode: Mode) -> Mode { |
270 | unsafe { |
271 | // TODO: Use `from_bits_retain` when we switch to bitflags 2.0. |
272 | Mode::from_bits_truncate(bits:ret_c_uint_infallible(raw:syscall_readonly!(__NR_umask, mode))) |
273 | } |
274 | } |
275 | |
276 | #[inline ] |
277 | pub(crate) fn nice(inc: i32) -> io::Result<i32> { |
278 | let priority: i32 = ifi32 inc > -40 && inc < 40 { |
279 | inc + getpriority_process(pid:None)? |
280 | } else { |
281 | inc |
282 | } |
283 | // TODO: With Rust 1.50, use `.clamp` instead of `.min` and `.max`. |
284 | //.clamp(-20, 19); |
285 | .min(19) |
286 | .max(-20); |
287 | setpriority_process(pid:None, priority)?; |
288 | Ok(priority) |
289 | } |
290 | |
291 | #[inline ] |
292 | pub(crate) fn getpriority_user(uid: Uid) -> io::Result<i32> { |
293 | unsafe { |
294 | Ok(20 |
295 | - ret_c_int(raw:syscall_readonly!( |
296 | __NR_getpriority, |
297 | c_uint(PRIO_USER), |
298 | c_uint(uid.as_raw()) |
299 | ))?) |
300 | } |
301 | } |
302 | |
303 | #[inline ] |
304 | pub(crate) fn getpriority_pgrp(pgid: Option<Pid>) -> io::Result<i32> { |
305 | unsafe { |
306 | Ok(20 |
307 | - ret_c_int(raw:syscall_readonly!( |
308 | __NR_getpriority, |
309 | c_uint(PRIO_PGRP), |
310 | c_uint(Pid::as_raw(pgid)) |
311 | ))?) |
312 | } |
313 | } |
314 | |
315 | #[inline ] |
316 | pub(crate) fn getpriority_process(pid: Option<Pid>) -> io::Result<i32> { |
317 | unsafe { |
318 | Ok(20 |
319 | - ret_c_int(raw:syscall_readonly!( |
320 | __NR_getpriority, |
321 | c_uint(PRIO_PROCESS), |
322 | c_uint(Pid::as_raw(pid)) |
323 | ))?) |
324 | } |
325 | } |
326 | |
327 | #[inline ] |
328 | pub(crate) fn setpriority_user(uid: Uid, priority: i32) -> io::Result<()> { |
329 | unsafe { |
330 | ret(raw:syscall_readonly!( |
331 | __NR_setpriority, |
332 | c_uint(PRIO_USER), |
333 | c_uint(uid.as_raw()), |
334 | c_int(priority) |
335 | )) |
336 | } |
337 | } |
338 | |
339 | #[inline ] |
340 | pub(crate) fn setpriority_pgrp(pgid: Option<Pid>, priority: i32) -> io::Result<()> { |
341 | unsafe { |
342 | ret(raw:syscall_readonly!( |
343 | __NR_setpriority, |
344 | c_uint(PRIO_PGRP), |
345 | c_uint(Pid::as_raw(pgid)), |
346 | c_int(priority) |
347 | )) |
348 | } |
349 | } |
350 | |
351 | #[inline ] |
352 | pub(crate) fn setpriority_process(pid: Option<Pid>, priority: i32) -> io::Result<()> { |
353 | unsafe { |
354 | ret(raw:syscall_readonly!( |
355 | __NR_setpriority, |
356 | c_uint(PRIO_PROCESS), |
357 | c_uint(Pid::as_raw(pid)), |
358 | c_int(priority) |
359 | )) |
360 | } |
361 | } |
362 | |
363 | #[inline ] |
364 | pub(crate) fn getrlimit(limit: Resource) -> Rlimit { |
365 | let mut result: MaybeUninit = MaybeUninit::<rlimit64>::uninit(); |
366 | unsafe { |
367 | match ret(raw:syscall!( |
368 | __NR_prlimit64, |
369 | c_uint(0), |
370 | limit, |
371 | null::<c::c_void>(), |
372 | &mut result |
373 | )) { |
374 | Ok(()) => rlimit_from_linux(lim:result.assume_init()), |
375 | Err(err: Errno) => { |
376 | debug_assert_eq!(err, io::Errno::NOSYS); |
377 | getrlimit_old(limit) |
378 | } |
379 | } |
380 | } |
381 | } |
382 | |
383 | /// The old 32-bit-only `getrlimit` syscall, for when we lack the new |
384 | /// `prlimit64`. |
385 | unsafe fn getrlimit_old(limit: Resource) -> Rlimit { |
386 | let mut result = MaybeUninit::<rlimit>::uninit(); |
387 | |
388 | // On these platforms, `__NR_getrlimit` is called `__NR_ugetrlimit`. |
389 | #[cfg (any( |
390 | target_arch = "arm" , |
391 | target_arch = "powerpc" , |
392 | target_arch = "powerpc64" , |
393 | target_arch = "x86" , |
394 | ))] |
395 | { |
396 | ret_infallible(syscall!(__NR_ugetrlimit, limit, &mut result)); |
397 | } |
398 | |
399 | // On these platforms, it's just `__NR_getrlimit`. |
400 | #[cfg (not(any( |
401 | target_arch = "arm" , |
402 | target_arch = "powerpc" , |
403 | target_arch = "powerpc64" , |
404 | target_arch = "x86" , |
405 | )))] |
406 | { |
407 | ret_infallible(syscall!(__NR_getrlimit, limit, &mut result)); |
408 | } |
409 | |
410 | rlimit_from_linux_old(result.assume_init()) |
411 | } |
412 | |
413 | #[inline ] |
414 | pub(crate) fn setrlimit(limit: Resource, new: Rlimit) -> io::Result<()> { |
415 | unsafe { |
416 | let lim: rlimit64 = rlimit_to_linux(lim:new.clone()); |
417 | match ret(raw:syscall_readonly!( |
418 | __NR_prlimit64, |
419 | c_uint(0), |
420 | limit, |
421 | by_ref(&lim), |
422 | null_mut::<c::c_void>() |
423 | )) { |
424 | Ok(()) => Ok(()), |
425 | Err(io::Errno::NOSYS) => setrlimit_old(limit, new), |
426 | Err(err: Errno) => Err(err), |
427 | } |
428 | } |
429 | } |
430 | |
431 | /// The old 32-bit-only `setrlimit` syscall, for when we lack the new |
432 | /// `prlimit64`. |
433 | unsafe fn setrlimit_old(limit: Resource, new: Rlimit) -> io::Result<()> { |
434 | let lim: rlimit = rlimit_to_linux_old(lim:new)?; |
435 | ret(raw:syscall_readonly!(__NR_setrlimit, limit, by_ref(&lim))) |
436 | } |
437 | |
438 | #[inline ] |
439 | pub(crate) fn prlimit(pid: Option<Pid>, limit: Resource, new: Rlimit) -> io::Result<Rlimit> { |
440 | let lim: rlimit64 = rlimit_to_linux(lim:new); |
441 | let mut result: MaybeUninit = MaybeUninit::<rlimit64>::uninit(); |
442 | unsafe { |
443 | match ret(raw:syscall!( |
444 | __NR_prlimit64, |
445 | c_uint(Pid::as_raw(pid)), |
446 | limit, |
447 | by_ref(&lim), |
448 | &mut result |
449 | )) { |
450 | Ok(()) => Ok(rlimit_from_linux(lim:result.assume_init())), |
451 | Err(err: Errno) => Err(err), |
452 | } |
453 | } |
454 | } |
455 | |
456 | /// Convert a Rust [`Rlimit`] to a C `rlimit64`. |
457 | #[inline ] |
458 | fn rlimit_from_linux(lim: rlimit64) -> Rlimit { |
459 | let current: Option = if lim.rlim_cur == RLIM64_INFINITY as _ { |
460 | None |
461 | } else { |
462 | Some(lim.rlim_cur) |
463 | }; |
464 | let maximum: Option = if lim.rlim_max == RLIM64_INFINITY as _ { |
465 | None |
466 | } else { |
467 | Some(lim.rlim_max) |
468 | }; |
469 | Rlimit { current, maximum } |
470 | } |
471 | |
472 | /// Convert a C `rlimit64` to a Rust `Rlimit`. |
473 | #[inline ] |
474 | fn rlimit_to_linux(lim: Rlimit) -> rlimit64 { |
475 | let rlim_cur: u64 = match lim.current { |
476 | Some(r: u64) => r, |
477 | None => RLIM64_INFINITY as _, |
478 | }; |
479 | let rlim_max: u64 = match lim.maximum { |
480 | Some(r: u64) => r, |
481 | None => RLIM64_INFINITY as _, |
482 | }; |
483 | rlimit64 { rlim_cur, rlim_max } |
484 | } |
485 | |
486 | /// Like `rlimit_from_linux` but uses Linux's old 32-bit `rlimit`. |
487 | #[allow (clippy::useless_conversion)] |
488 | fn rlimit_from_linux_old(lim: rlimit) -> Rlimit { |
489 | let current: Option = if lim.rlim_cur == RLIM_INFINITY as _ { |
490 | None |
491 | } else { |
492 | Some(lim.rlim_cur.into()) |
493 | }; |
494 | let maximum: Option = if lim.rlim_max == RLIM_INFINITY as _ { |
495 | None |
496 | } else { |
497 | Some(lim.rlim_max.into()) |
498 | }; |
499 | Rlimit { current, maximum } |
500 | } |
501 | |
502 | /// Like `rlimit_to_linux` but uses Linux's old 32-bit `rlimit`. |
503 | #[allow (clippy::useless_conversion)] |
504 | fn rlimit_to_linux_old(lim: Rlimit) -> io::Result<rlimit> { |
505 | let rlim_cur: u64 = match lim.current { |
506 | Some(r: u64) => r.try_into().map_err(|_e: Infallible| io::Errno::INVAL)?, |
507 | None => RLIM_INFINITY as _, |
508 | }; |
509 | let rlim_max: u64 = match lim.maximum { |
510 | Some(r: u64) => r.try_into().map_err(|_e: Infallible| io::Errno::INVAL)?, |
511 | None => RLIM_INFINITY as _, |
512 | }; |
513 | Ok(rlimit { rlim_cur, rlim_max }) |
514 | } |
515 | |
516 | #[inline ] |
517 | pub(crate) fn wait(waitopts: WaitOptions) -> io::Result<Option<(Pid, WaitStatus)>> { |
518 | _waitpid(!0, waitopts) |
519 | } |
520 | |
521 | #[inline ] |
522 | pub(crate) fn waitpid( |
523 | pid: Option<Pid>, |
524 | waitopts: WaitOptions, |
525 | ) -> io::Result<Option<(Pid, WaitStatus)>> { |
526 | _waitpid(Pid::as_raw(pid), waitopts) |
527 | } |
528 | |
529 | #[inline ] |
530 | pub(crate) fn _waitpid( |
531 | pid: RawPid, |
532 | waitopts: WaitOptions, |
533 | ) -> io::Result<Option<(Pid, WaitStatus)>> { |
534 | unsafe { |
535 | let mut status: MaybeUninit = MaybeUninit::<u32>::uninit(); |
536 | let pid: u32 = ret_c_uint(raw:syscall!( |
537 | __NR_wait4, |
538 | c_int(pid as _), |
539 | &mut status, |
540 | c_int(waitopts.bits() as _), |
541 | zero() |
542 | ))?; |
543 | Ok(RawNonZeroPid::new(pid).map(|non_zero: NonZero| { |
544 | ( |
545 | Pid::from_raw_nonzero(raw:non_zero), |
546 | WaitStatus::new(status:status.assume_init()), |
547 | ) |
548 | })) |
549 | } |
550 | } |
551 | |
552 | #[inline ] |
553 | pub(crate) fn waitid(id: WaitId<'_>, options: WaitidOptions) -> io::Result<Option<WaitidStatus>> { |
554 | // Get the id to wait on. |
555 | match id { |
556 | WaitId::All => _waitid_all(options), |
557 | WaitId::Pid(pid: Pid) => _waitid_pid(pid, options), |
558 | WaitId::PidFd(fd: BorrowedFd<'_>) => _waitid_pidfd(fd, options), |
559 | } |
560 | } |
561 | |
562 | #[inline ] |
563 | fn _waitid_all(options: WaitidOptions) -> io::Result<Option<WaitidStatus>> { |
564 | // `waitid` can return successfully without initializing the struct (no |
565 | // children found when using `WNOHANG`) |
566 | let mut status: MaybeUninit = MaybeUninit::<c::siginfo_t>::zeroed(); |
567 | unsafe { |
568 | ret(raw:syscall!( |
569 | __NR_waitid, |
570 | c_uint(c::P_ALL), |
571 | c_uint(0), |
572 | by_mut(&mut status), |
573 | c_int(options.bits() as _), |
574 | zero() |
575 | ))? |
576 | }; |
577 | |
578 | Ok(unsafe { cvt_waitid_status(status) }) |
579 | } |
580 | |
581 | #[inline ] |
582 | fn _waitid_pid(pid: Pid, options: WaitidOptions) -> io::Result<Option<WaitidStatus>> { |
583 | // `waitid` can return successfully without initializing the struct (no |
584 | // children found when using `WNOHANG`) |
585 | let mut status: MaybeUninit = MaybeUninit::<c::siginfo_t>::zeroed(); |
586 | unsafe { |
587 | ret(raw:syscall!( |
588 | __NR_waitid, |
589 | c_uint(c::P_PID), |
590 | c_uint(Pid::as_raw(Some(pid))), |
591 | by_mut(&mut status), |
592 | c_int(options.bits() as _), |
593 | zero() |
594 | ))? |
595 | }; |
596 | |
597 | Ok(unsafe { cvt_waitid_status(status) }) |
598 | } |
599 | |
600 | #[inline ] |
601 | fn _waitid_pidfd(fd: BorrowedFd<'_>, options: WaitidOptions) -> io::Result<Option<WaitidStatus>> { |
602 | // `waitid` can return successfully without initializing the struct (no |
603 | // children found when using `WNOHANG`) |
604 | let mut status: MaybeUninit = MaybeUninit::<c::siginfo_t>::zeroed(); |
605 | unsafe { |
606 | ret(raw:syscall!( |
607 | __NR_waitid, |
608 | c_uint(c::P_PIDFD), |
609 | c_uint(fd.as_raw_fd() as _), |
610 | by_mut(&mut status), |
611 | c_int(options.bits() as _), |
612 | zero() |
613 | ))? |
614 | }; |
615 | |
616 | Ok(unsafe { cvt_waitid_status(status) }) |
617 | } |
618 | |
619 | /// Convert a `siginfo_t` to a `WaitidStatus`. |
620 | /// |
621 | /// # Safety |
622 | /// |
623 | /// The caller must ensure that `status` is initialized and that `waitid` |
624 | /// returned successfully. |
625 | #[inline ] |
626 | #[rustfmt::skip] |
627 | unsafe fn cvt_waitid_status(status: MaybeUninit<c::siginfo_t>) -> Option<WaitidStatus> { |
628 | let status: siginfo = status.assume_init(); |
629 | if status.__bindgen_anon_1.__bindgen_anon_1._sifields._sigchld._pid == 0 { |
630 | None |
631 | } else { |
632 | Some(WaitidStatus(status)) |
633 | } |
634 | } |
635 | |
636 | #[cfg (feature = "runtime" )] |
637 | #[inline ] |
638 | pub(crate) fn exit_group(code: c::c_int) -> ! { |
639 | unsafe { syscall_noreturn!(__NR_exit_group, c_int(code)) } |
640 | } |
641 | |
642 | #[inline ] |
643 | pub(crate) fn getsid(pid: Option<Pid>) -> io::Result<Pid> { |
644 | unsafe { |
645 | let pid: usize = ret_usize(raw:syscall_readonly!(__NR_getsid, c_uint(Pid::as_raw(pid))))?; |
646 | debug_assert!(pid > 0); |
647 | Ok(Pid::from_raw_nonzero(raw:RawNonZeroPid::new_unchecked( |
648 | pid as u32, |
649 | ))) |
650 | } |
651 | } |
652 | |
653 | #[inline ] |
654 | pub(crate) fn setsid() -> io::Result<Pid> { |
655 | unsafe { |
656 | let pid: usize = ret_usize(raw:syscall_readonly!(__NR_setsid))?; |
657 | debug_assert!(pid > 0); |
658 | Ok(Pid::from_raw_nonzero(raw:RawNonZeroPid::new_unchecked( |
659 | pid as u32, |
660 | ))) |
661 | } |
662 | } |
663 | |
664 | #[inline ] |
665 | pub(crate) fn kill_process(pid: Pid, sig: Signal) -> io::Result<()> { |
666 | unsafe { ret(raw:syscall_readonly!(__NR_kill, pid, sig)) } |
667 | } |
668 | |
669 | #[inline ] |
670 | pub(crate) fn kill_process_group(pid: Pid, sig: Signal) -> io::Result<()> { |
671 | unsafe { ret(raw:syscall_readonly!(__NR_kill, negative_pid(pid), sig)) } |
672 | } |
673 | |
674 | #[inline ] |
675 | pub(crate) fn kill_current_process_group(sig: Signal) -> io::Result<()> { |
676 | unsafe { ret(raw:syscall_readonly!(__NR_kill, pass_usize(0), sig)) } |
677 | } |
678 | |
679 | #[inline ] |
680 | pub(crate) fn test_kill_process(pid: Pid) -> io::Result<()> { |
681 | unsafe { ret(raw:syscall_readonly!(__NR_kill, pid, pass_usize(0))) } |
682 | } |
683 | |
684 | #[inline ] |
685 | pub(crate) fn test_kill_process_group(pid: Pid) -> io::Result<()> { |
686 | unsafe { |
687 | ret(raw:syscall_readonly!( |
688 | __NR_kill, |
689 | negative_pid(pid), |
690 | pass_usize(0) |
691 | )) |
692 | } |
693 | } |
694 | |
695 | #[inline ] |
696 | pub(crate) fn test_kill_current_process_group() -> io::Result<()> { |
697 | unsafe { ret(raw:syscall_readonly!(__NR_kill, pass_usize(0), pass_usize(0))) } |
698 | } |
699 | |
700 | #[inline ] |
701 | pub(crate) unsafe fn prctl( |
702 | option: c::c_int, |
703 | arg2: *mut c::c_void, |
704 | arg3: *mut c::c_void, |
705 | arg4: *mut c::c_void, |
706 | arg5: *mut c::c_void, |
707 | ) -> io::Result<c::c_int> { |
708 | ret_c_int(raw:syscall!(__NR_prctl, c_int(option), arg2, arg3, arg4, arg5)) |
709 | } |
710 | |
711 | #[inline ] |
712 | pub(crate) fn pidfd_open(pid: Pid, flags: PidfdFlags) -> io::Result<OwnedFd> { |
713 | unsafe { |
714 | ret_owned_fd(raw:syscall_readonly!( |
715 | __NR_pidfd_open, |
716 | pid, |
717 | c_int(flags.bits() as _) |
718 | )) |
719 | } |
720 | } |
721 | |
722 | #[inline ] |
723 | pub(crate) fn getgroups(buf: &mut [Gid]) -> io::Result<usize> { |
724 | let len: i32 = buf.len().try_into().map_err(|_| io::Errno::NOMEM)?; |
725 | |
726 | unsafe { |
727 | ret_usize(raw:syscall!( |
728 | __NR_getgroups, |
729 | c_int(len), |
730 | slice_just_addr_mut(buf) |
731 | )) |
732 | } |
733 | } |
734 | |
735 | #[inline ] |
736 | pub(crate) fn sysinfo() -> Sysinfo { |
737 | let mut info: MaybeUninit = MaybeUninit::<Sysinfo>::uninit(); |
738 | unsafe { |
739 | ret_infallible(raw:syscall!(__NR_sysinfo, &mut info)); |
740 | info.assume_init() |
741 | } |
742 | } |
743 | |
744 | #[inline ] |
745 | pub(crate) fn sethostname(name: &[u8]) -> io::Result<()> { |
746 | let (ptr: ArgReg<'_, A0>, len: ArgReg<'_, A1>) = slice(name); |
747 | unsafe { ret(raw:syscall_readonly!(__NR_sethostname, ptr, len)) } |
748 | } |
749 | |
750 | #[inline ] |
751 | pub(crate) fn ioctl_tiocsctty(fd: BorrowedFd<'_>) -> io::Result<()> { |
752 | unsafe { |
753 | ret(raw:syscall_readonly!( |
754 | __NR_ioctl, |
755 | fd, |
756 | c_uint(TIOCSCTTY), |
757 | by_ref(&0_u32) |
758 | )) |
759 | } |
760 | } |
761 | |