1 | //! linux_raw syscalls supporting `rustix::process`. |
2 | //! |
3 | //! # Safety |
4 | //! |
5 | //! See the `rustix::backend` module documentation for details. |
6 | #![allow (unsafe_code, clippy::undocumented_unsafe_blocks)] |
7 | |
8 | use super::types::RawCpuSet; |
9 | use crate::backend::c; |
10 | #[cfg (all(feature = "alloc" , feature = "fs" ))] |
11 | use crate::backend::conv::slice_mut; |
12 | use crate::backend::conv::{ |
13 | by_mut, by_ref, c_int, c_uint, negative_pid, pass_usize, raw_fd, ret, ret_c_int, |
14 | ret_c_int_infallible, ret_c_uint, ret_infallible, ret_owned_fd, ret_usize, size_of, |
15 | slice_just_addr, zero, |
16 | }; |
17 | use crate::fd::{AsRawFd, BorrowedFd, OwnedFd, RawFd}; |
18 | #[cfg (feature = "fs" )] |
19 | use crate::ffi::CStr; |
20 | use crate::io; |
21 | use crate::pid::RawPid; |
22 | use crate::process::{ |
23 | Cpuid, MembarrierCommand, MembarrierQuery, Pid, PidfdFlags, PidfdGetfdFlags, Resource, Rlimit, |
24 | Uid, WaitId, WaitOptions, WaitStatus, WaitidOptions, WaitidStatus, |
25 | }; |
26 | use crate::signal::Signal; |
27 | use crate::utils::as_mut_ptr; |
28 | use core::mem::MaybeUninit; |
29 | use core::ptr::{null, null_mut}; |
30 | use linux_raw_sys::general::{ |
31 | membarrier_cmd, membarrier_cmd_flag, rlimit64, PRIO_PGRP, PRIO_PROCESS, PRIO_USER, |
32 | RLIM64_INFINITY, |
33 | }; |
34 | #[cfg (feature = "fs" )] |
35 | use {crate::backend::conv::ret_c_uint_infallible, crate::fs::Mode}; |
36 | #[cfg (feature = "alloc" )] |
37 | use {crate::backend::conv::slice_just_addr_mut, crate::process::Gid}; |
38 | |
39 | // `sched_getcpu` has special optimizations via the vDSO on some architectures. |
40 | #[cfg (any( |
41 | target_arch = "x86_64" , |
42 | target_arch = "x86" , |
43 | target_arch = "riscv64" , |
44 | target_arch = "powerpc64" |
45 | ))] |
46 | pub(crate) use crate::backend::vdso_wrappers::sched_getcpu; |
47 | |
48 | // `sched_getcpu` on platforms without a vDSO entry for it. |
49 | #[cfg (not(any( |
50 | target_arch = "x86_64" , |
51 | target_arch = "x86" , |
52 | target_arch = "riscv64" , |
53 | target_arch = "powerpc64" |
54 | )))] |
55 | #[inline ] |
56 | pub(crate) fn sched_getcpu() -> usize { |
57 | let mut cpu = MaybeUninit::<u32>::uninit(); |
58 | unsafe { |
59 | let r = ret(syscall!(__NR_getcpu, &mut cpu, zero(), zero())); |
60 | debug_assert!(r.is_ok()); |
61 | cpu.assume_init() as usize |
62 | } |
63 | } |
64 | |
65 | #[cfg (feature = "fs" )] |
66 | #[inline ] |
67 | pub(crate) fn chdir(filename: &CStr) -> io::Result<()> { |
68 | unsafe { ret(raw:syscall_readonly!(__NR_chdir, filename)) } |
69 | } |
70 | |
71 | #[inline ] |
72 | pub(crate) fn fchdir(fd: BorrowedFd<'_>) -> io::Result<()> { |
73 | unsafe { ret(raw:syscall_readonly!(__NR_fchdir, fd)) } |
74 | } |
75 | |
76 | #[cfg (feature = "fs" )] |
77 | #[inline ] |
78 | pub(crate) fn chroot(filename: &CStr) -> io::Result<()> { |
79 | unsafe { ret(raw:syscall_readonly!(__NR_chroot, filename)) } |
80 | } |
81 | |
82 | #[cfg (all(feature = "alloc" , feature = "fs" ))] |
83 | #[inline ] |
84 | pub(crate) fn getcwd(buf: &mut [MaybeUninit<u8>]) -> io::Result<usize> { |
85 | let (buf_addr_mut: ArgReg<'_, A0>, buf_len: ArgReg<'_, A1>) = slice_mut(buf); |
86 | unsafe { ret_usize(raw:syscall!(__NR_getcwd, buf_addr_mut, buf_len)) } |
87 | } |
88 | |
89 | #[inline ] |
90 | pub(crate) fn membarrier_query() -> MembarrierQuery { |
91 | unsafe { |
92 | match ret_c_uint(raw:syscall!( |
93 | __NR_membarrier, |
94 | c_int(membarrier_cmd::MEMBARRIER_CMD_QUERY as _), |
95 | c_uint(0) |
96 | )) { |
97 | Ok(query: u32) => MembarrierQuery::from_bits_retain(bits:query), |
98 | Err(_) => MembarrierQuery::empty(), |
99 | } |
100 | } |
101 | } |
102 | |
103 | #[inline ] |
104 | pub(crate) fn membarrier(cmd: MembarrierCommand) -> io::Result<()> { |
105 | unsafe { ret(raw:syscall!(__NR_membarrier, cmd, c_uint(0))) } |
106 | } |
107 | |
108 | #[inline ] |
109 | pub(crate) fn membarrier_cpu(cmd: MembarrierCommand, cpu: Cpuid) -> io::Result<()> { |
110 | unsafe { |
111 | ret(raw:syscall!( |
112 | __NR_membarrier, |
113 | cmd, |
114 | c_uint(membarrier_cmd_flag::MEMBARRIER_CMD_FLAG_CPU as _), |
115 | cpu |
116 | )) |
117 | } |
118 | } |
119 | |
120 | #[inline ] |
121 | pub(crate) fn getppid() -> Option<Pid> { |
122 | unsafe { |
123 | let ppid: i32 = ret_c_int_infallible(raw:syscall_readonly!(__NR_getppid)); |
124 | Pid::from_raw(ppid) |
125 | } |
126 | } |
127 | |
128 | #[inline ] |
129 | pub(crate) fn getpgid(pid: Option<Pid>) -> io::Result<Pid> { |
130 | unsafe { |
131 | let pgid: i32 = ret_c_int(raw:syscall_readonly!(__NR_getpgid, c_int(Pid::as_raw(pid))))?; |
132 | debug_assert!(pgid > 0); |
133 | Ok(Pid::from_raw_unchecked(raw:pgid)) |
134 | } |
135 | } |
136 | |
137 | #[inline ] |
138 | pub(crate) fn setpgid(pid: Option<Pid>, pgid: Option<Pid>) -> io::Result<()> { |
139 | unsafe { |
140 | ret(raw:syscall_readonly!( |
141 | __NR_setpgid, |
142 | c_int(Pid::as_raw(pid)), |
143 | c_int(Pid::as_raw(pgid)) |
144 | )) |
145 | } |
146 | } |
147 | |
148 | #[inline ] |
149 | pub(crate) fn getpgrp() -> Pid { |
150 | // Use the `getpgrp` syscall if available. |
151 | #[cfg (not(any(target_arch = "aarch64" , target_arch = "riscv64" )))] |
152 | unsafe { |
153 | let pgid: i32 = ret_c_int_infallible(raw:syscall_readonly!(__NR_getpgrp)); |
154 | debug_assert!(pgid > 0); |
155 | Pid::from_raw_unchecked(raw:pgid) |
156 | } |
157 | |
158 | // Otherwise use `getpgrp` and pass it zero. |
159 | #[cfg (any(target_arch = "aarch64" , target_arch = "riscv64" ))] |
160 | unsafe { |
161 | let pgid = ret_c_int_infallible(syscall_readonly!(__NR_getpgid, c_uint(0))); |
162 | debug_assert!(pgid > 0); |
163 | Pid::from_raw_unchecked(pgid) |
164 | } |
165 | } |
166 | |
167 | #[inline ] |
168 | pub(crate) fn sched_getaffinity(pid: Option<Pid>, cpuset: &mut RawCpuSet) -> io::Result<()> { |
169 | unsafe { |
170 | // The raw Linux syscall returns the size (in bytes) of the `cpumask_t` |
171 | // data type that is used internally by the kernel to represent the CPU |
172 | // set bit mask. |
173 | let size: usize = ret_usize(raw:syscall!( |
174 | __NR_sched_getaffinity, |
175 | c_int(Pid::as_raw(pid)), |
176 | size_of::<RawCpuSet, _>(), |
177 | by_mut(&mut cpuset.bits) |
178 | ))?; |
179 | let bytes: *mut u8 = as_mut_ptr(cpuset).cast::<u8>(); |
180 | let rest: *mut u8 = bytes.wrapping_add(count:size); |
181 | // Zero every byte in the cpuset not set by the kernel. |
182 | rest.write_bytes(val:0, count:core::mem::size_of::<RawCpuSet>() - size); |
183 | Ok(()) |
184 | } |
185 | } |
186 | |
187 | #[inline ] |
188 | pub(crate) fn sched_setaffinity(pid: Option<Pid>, cpuset: &RawCpuSet) -> io::Result<()> { |
189 | unsafe { |
190 | ret(raw:syscall_readonly!( |
191 | __NR_sched_setaffinity, |
192 | c_int(Pid::as_raw(pid)), |
193 | size_of::<RawCpuSet, _>(), |
194 | slice_just_addr(&cpuset.bits) |
195 | )) |
196 | } |
197 | } |
198 | |
199 | #[inline ] |
200 | pub(crate) fn sched_yield() { |
201 | unsafe { |
202 | // See the documentation for [`crate::process::sched_yield`] for why |
203 | // errors are ignored. |
204 | syscall_readonly!(__NR_sched_yield).decode_void(); |
205 | } |
206 | } |
207 | |
208 | #[cfg (feature = "fs" )] |
209 | #[inline ] |
210 | pub(crate) fn umask(mode: Mode) -> Mode { |
211 | unsafe { Mode::from_bits_retain(bits:ret_c_uint_infallible(raw:syscall_readonly!(__NR_umask, mode))) } |
212 | } |
213 | |
214 | #[inline ] |
215 | pub(crate) fn nice(inc: i32) -> io::Result<i32> { |
216 | let priority: i32 = (if inc > -40 && inc < 40 { |
217 | inc + getpriority_process(None)? |
218 | } else { |
219 | inc |
220 | }) |
221 | .clamp(min:-20, max:19); |
222 | setpriority_process(pid:None, priority)?; |
223 | Ok(priority) |
224 | } |
225 | |
226 | #[inline ] |
227 | pub(crate) fn getpriority_user(uid: Uid) -> io::Result<i32> { |
228 | unsafe { |
229 | Ok(20 |
230 | - ret_c_int(raw:syscall_readonly!( |
231 | __NR_getpriority, |
232 | c_uint(PRIO_USER), |
233 | c_uint(uid.as_raw()) |
234 | ))?) |
235 | } |
236 | } |
237 | |
238 | #[inline ] |
239 | pub(crate) fn getpriority_pgrp(pgid: Option<Pid>) -> io::Result<i32> { |
240 | unsafe { |
241 | Ok(20 |
242 | - ret_c_int(raw:syscall_readonly!( |
243 | __NR_getpriority, |
244 | c_uint(PRIO_PGRP), |
245 | c_int(Pid::as_raw(pgid)) |
246 | ))?) |
247 | } |
248 | } |
249 | |
250 | #[inline ] |
251 | pub(crate) fn getpriority_process(pid: Option<Pid>) -> io::Result<i32> { |
252 | unsafe { |
253 | Ok(20 |
254 | - ret_c_int(raw:syscall_readonly!( |
255 | __NR_getpriority, |
256 | c_uint(PRIO_PROCESS), |
257 | c_int(Pid::as_raw(pid)) |
258 | ))?) |
259 | } |
260 | } |
261 | |
262 | #[inline ] |
263 | pub(crate) fn setpriority_user(uid: Uid, priority: i32) -> io::Result<()> { |
264 | unsafe { |
265 | ret(raw:syscall_readonly!( |
266 | __NR_setpriority, |
267 | c_uint(PRIO_USER), |
268 | c_uint(uid.as_raw()), |
269 | c_int(priority) |
270 | )) |
271 | } |
272 | } |
273 | |
274 | #[inline ] |
275 | pub(crate) fn setpriority_pgrp(pgid: Option<Pid>, priority: i32) -> io::Result<()> { |
276 | unsafe { |
277 | ret(raw:syscall_readonly!( |
278 | __NR_setpriority, |
279 | c_uint(PRIO_PGRP), |
280 | c_int(Pid::as_raw(pgid)), |
281 | c_int(priority) |
282 | )) |
283 | } |
284 | } |
285 | |
286 | #[inline ] |
287 | pub(crate) fn setpriority_process(pid: Option<Pid>, priority: i32) -> io::Result<()> { |
288 | unsafe { |
289 | ret(raw:syscall_readonly!( |
290 | __NR_setpriority, |
291 | c_uint(PRIO_PROCESS), |
292 | c_int(Pid::as_raw(pid)), |
293 | c_int(priority) |
294 | )) |
295 | } |
296 | } |
297 | |
298 | #[inline ] |
299 | pub(crate) fn getrlimit(limit: Resource) -> Rlimit { |
300 | let mut result: MaybeUninit = MaybeUninit::<rlimit64>::uninit(); |
301 | unsafe { |
302 | ret_infallible(raw:syscall!( |
303 | __NR_prlimit64, |
304 | c_uint(0), |
305 | limit, |
306 | null::<c::c_void>(), |
307 | &mut result |
308 | )); |
309 | rlimit_from_linux(lim:result.assume_init()) |
310 | } |
311 | } |
312 | |
313 | #[inline ] |
314 | pub(crate) fn setrlimit(limit: Resource, new: Rlimit) -> io::Result<()> { |
315 | unsafe { |
316 | let lim: rlimit64 = rlimit_to_linux(lim:new.clone()); |
317 | match ret(raw:syscall_readonly!( |
318 | __NR_prlimit64, |
319 | c_uint(0), |
320 | limit, |
321 | by_ref(&lim), |
322 | null_mut::<c::c_void>() |
323 | )) { |
324 | Ok(()) => Ok(()), |
325 | Err(err: Errno) => Err(err), |
326 | } |
327 | } |
328 | } |
329 | |
330 | #[inline ] |
331 | pub(crate) fn prlimit(pid: Option<Pid>, limit: Resource, new: Rlimit) -> io::Result<Rlimit> { |
332 | let lim: rlimit64 = rlimit_to_linux(lim:new); |
333 | let mut result: MaybeUninit = MaybeUninit::<rlimit64>::uninit(); |
334 | unsafe { |
335 | match ret(raw:syscall!( |
336 | __NR_prlimit64, |
337 | c_int(Pid::as_raw(pid)), |
338 | limit, |
339 | by_ref(&lim), |
340 | &mut result |
341 | )) { |
342 | Ok(()) => Ok(rlimit_from_linux(lim:result.assume_init())), |
343 | Err(err: Errno) => Err(err), |
344 | } |
345 | } |
346 | } |
347 | |
348 | /// Convert a Rust [`Rlimit`] to a C `rlimit64`. |
349 | #[inline ] |
350 | fn rlimit_from_linux(lim: rlimit64) -> Rlimit { |
351 | let current: Option = if lim.rlim_cur == RLIM64_INFINITY as _ { |
352 | None |
353 | } else { |
354 | Some(lim.rlim_cur) |
355 | }; |
356 | let maximum: Option = if lim.rlim_max == RLIM64_INFINITY as _ { |
357 | None |
358 | } else { |
359 | Some(lim.rlim_max) |
360 | }; |
361 | Rlimit { current, maximum } |
362 | } |
363 | |
364 | /// Convert a C `rlimit64` to a Rust `Rlimit`. |
365 | #[inline ] |
366 | fn rlimit_to_linux(lim: Rlimit) -> rlimit64 { |
367 | let rlim_cur: u64 = match lim.current { |
368 | Some(r: u64) => r, |
369 | None => RLIM64_INFINITY as _, |
370 | }; |
371 | let rlim_max: u64 = match lim.maximum { |
372 | Some(r: u64) => r, |
373 | None => RLIM64_INFINITY as _, |
374 | }; |
375 | rlimit64 { rlim_cur, rlim_max } |
376 | } |
377 | |
378 | #[inline ] |
379 | pub(crate) fn wait(waitopts: WaitOptions) -> io::Result<Option<(Pid, WaitStatus)>> { |
380 | _waitpid(!0, waitopts) |
381 | } |
382 | |
383 | #[inline ] |
384 | pub(crate) fn waitpid( |
385 | pid: Option<Pid>, |
386 | waitopts: WaitOptions, |
387 | ) -> io::Result<Option<(Pid, WaitStatus)>> { |
388 | _waitpid(Pid::as_raw(pid), waitopts) |
389 | } |
390 | |
391 | #[inline ] |
392 | pub(crate) fn waitpgid(pgid: Pid, waitopts: WaitOptions) -> io::Result<Option<(Pid, WaitStatus)>> { |
393 | _waitpid(-pgid.as_raw_nonzero().get(), waitopts) |
394 | } |
395 | |
396 | #[inline ] |
397 | pub(crate) fn _waitpid( |
398 | pid: RawPid, |
399 | waitopts: WaitOptions, |
400 | ) -> io::Result<Option<(Pid, WaitStatus)>> { |
401 | unsafe { |
402 | let mut status: MaybeUninit = MaybeUninit::<u32>::uninit(); |
403 | let pid: i32 = ret_c_int(raw:syscall!( |
404 | __NR_wait4, |
405 | c_int(pid as _), |
406 | &mut status, |
407 | c_int(waitopts.bits() as _), |
408 | zero() |
409 | ))?; |
410 | Ok(Pid::from_raw(pid).map(|pid: Pid| (pid, WaitStatus::new(status:status.assume_init())))) |
411 | } |
412 | } |
413 | |
414 | #[inline ] |
415 | pub(crate) fn waitid(id: WaitId<'_>, options: WaitidOptions) -> io::Result<Option<WaitidStatus>> { |
416 | // Get the id to wait on. |
417 | match id { |
418 | WaitId::All => _waitid_all(options), |
419 | WaitId::Pid(pid: Pid) => _waitid_pid(pid, options), |
420 | WaitId::Pgid(pid: Option) => _waitid_pgid(pgid:pid, options), |
421 | WaitId::PidFd(fd: BorrowedFd<'_>) => _waitid_pidfd(fd, options), |
422 | } |
423 | } |
424 | |
425 | #[inline ] |
426 | fn _waitid_all(options: WaitidOptions) -> io::Result<Option<WaitidStatus>> { |
427 | // `waitid` can return successfully without initializing the struct (no |
428 | // children found when using `WNOHANG`) |
429 | let mut status: MaybeUninit = MaybeUninit::<c::siginfo_t>::zeroed(); |
430 | unsafe { |
431 | ret(raw:syscall!( |
432 | __NR_waitid, |
433 | c_uint(c::P_ALL), |
434 | c_uint(0), |
435 | by_mut(&mut status), |
436 | c_int(options.bits() as _), |
437 | zero() |
438 | ))? |
439 | }; |
440 | |
441 | Ok(unsafe { cvt_waitid_status(status) }) |
442 | } |
443 | |
444 | #[inline ] |
445 | fn _waitid_pid(pid: Pid, options: WaitidOptions) -> io::Result<Option<WaitidStatus>> { |
446 | // `waitid` can return successfully without initializing the struct (no |
447 | // children found when using `WNOHANG`) |
448 | let mut status: MaybeUninit = MaybeUninit::<c::siginfo_t>::zeroed(); |
449 | unsafe { |
450 | ret(raw:syscall!( |
451 | __NR_waitid, |
452 | c_uint(c::P_PID), |
453 | c_int(Pid::as_raw(Some(pid))), |
454 | by_mut(&mut status), |
455 | c_int(options.bits() as _), |
456 | zero() |
457 | ))? |
458 | }; |
459 | |
460 | Ok(unsafe { cvt_waitid_status(status) }) |
461 | } |
462 | |
463 | #[inline ] |
464 | fn _waitid_pgid(pgid: Option<Pid>, options: WaitidOptions) -> io::Result<Option<WaitidStatus>> { |
465 | // `waitid` can return successfully without initializing the struct (no |
466 | // children found when using `WNOHANG`) |
467 | let mut status: MaybeUninit = MaybeUninit::<c::siginfo_t>::zeroed(); |
468 | unsafe { |
469 | ret(raw:syscall!( |
470 | __NR_waitid, |
471 | c_uint(c::P_PGID), |
472 | c_int(Pid::as_raw(pgid)), |
473 | by_mut(&mut status), |
474 | c_int(options.bits() as _), |
475 | zero() |
476 | ))? |
477 | }; |
478 | |
479 | Ok(unsafe { cvt_waitid_status(status) }) |
480 | } |
481 | |
482 | #[inline ] |
483 | fn _waitid_pidfd(fd: BorrowedFd<'_>, options: WaitidOptions) -> io::Result<Option<WaitidStatus>> { |
484 | // `waitid` can return successfully without initializing the struct (no |
485 | // children found when using `WNOHANG`) |
486 | let mut status: MaybeUninit = MaybeUninit::<c::siginfo_t>::zeroed(); |
487 | unsafe { |
488 | ret(raw:syscall!( |
489 | __NR_waitid, |
490 | c_uint(c::P_PIDFD), |
491 | c_uint(fd.as_raw_fd() as _), |
492 | by_mut(&mut status), |
493 | c_int(options.bits() as _), |
494 | zero() |
495 | ))? |
496 | }; |
497 | |
498 | Ok(unsafe { cvt_waitid_status(status) }) |
499 | } |
500 | |
501 | /// Convert a `siginfo_t` to a `WaitidStatus`. |
502 | /// |
503 | /// # Safety |
504 | /// |
505 | /// The caller must ensure that `status` is initialized and that `waitid` |
506 | /// returned successfully. |
507 | #[inline ] |
508 | #[rustfmt::skip] |
509 | unsafe fn cvt_waitid_status(status: MaybeUninit<c::siginfo_t>) -> Option<WaitidStatus> { |
510 | let status: siginfo = status.assume_init(); |
511 | if status.__bindgen_anon_1.__bindgen_anon_1._sifields._sigchld._pid == 0 { |
512 | None |
513 | } else { |
514 | Some(WaitidStatus(status)) |
515 | } |
516 | } |
517 | |
518 | #[inline ] |
519 | pub(crate) fn getsid(pid: Option<Pid>) -> io::Result<Pid> { |
520 | unsafe { |
521 | let pid: i32 = ret_c_int(raw:syscall_readonly!(__NR_getsid, c_int(Pid::as_raw(pid))))?; |
522 | Ok(Pid::from_raw_unchecked(raw:pid)) |
523 | } |
524 | } |
525 | |
526 | #[inline ] |
527 | pub(crate) fn setsid() -> io::Result<Pid> { |
528 | unsafe { |
529 | let pid: i32 = ret_c_int(raw:syscall_readonly!(__NR_setsid))?; |
530 | Ok(Pid::from_raw_unchecked(raw:pid)) |
531 | } |
532 | } |
533 | |
534 | #[inline ] |
535 | pub(crate) fn kill_process(pid: Pid, sig: Signal) -> io::Result<()> { |
536 | unsafe { ret(raw:syscall_readonly!(__NR_kill, pid, sig)) } |
537 | } |
538 | |
539 | #[inline ] |
540 | pub(crate) fn kill_process_group(pid: Pid, sig: Signal) -> io::Result<()> { |
541 | unsafe { ret(raw:syscall_readonly!(__NR_kill, negative_pid(pid), sig)) } |
542 | } |
543 | |
544 | #[inline ] |
545 | pub(crate) fn kill_current_process_group(sig: Signal) -> io::Result<()> { |
546 | unsafe { ret(raw:syscall_readonly!(__NR_kill, pass_usize(0), sig)) } |
547 | } |
548 | |
549 | #[inline ] |
550 | pub(crate) fn test_kill_process(pid: Pid) -> io::Result<()> { |
551 | unsafe { ret(raw:syscall_readonly!(__NR_kill, pid, pass_usize(0))) } |
552 | } |
553 | |
554 | #[inline ] |
555 | pub(crate) fn test_kill_process_group(pid: Pid) -> io::Result<()> { |
556 | unsafe { |
557 | ret(raw:syscall_readonly!( |
558 | __NR_kill, |
559 | negative_pid(pid), |
560 | pass_usize(0) |
561 | )) |
562 | } |
563 | } |
564 | |
565 | #[inline ] |
566 | pub(crate) fn test_kill_current_process_group() -> io::Result<()> { |
567 | unsafe { ret(raw:syscall_readonly!(__NR_kill, pass_usize(0), pass_usize(0))) } |
568 | } |
569 | |
570 | #[inline ] |
571 | pub(crate) fn pidfd_getfd( |
572 | pidfd: BorrowedFd<'_>, |
573 | targetfd: RawFd, |
574 | flags: PidfdGetfdFlags, |
575 | ) -> io::Result<OwnedFd> { |
576 | unsafe { |
577 | ret_owned_fd(raw:syscall_readonly!( |
578 | __NR_pidfd_getfd, |
579 | pidfd, |
580 | raw_fd(targetfd), |
581 | c_int(flags.bits() as _) |
582 | )) |
583 | } |
584 | } |
585 | |
586 | #[inline ] |
587 | pub(crate) fn pidfd_open(pid: Pid, flags: PidfdFlags) -> io::Result<OwnedFd> { |
588 | unsafe { ret_owned_fd(raw:syscall_readonly!(__NR_pidfd_open, pid, flags)) } |
589 | } |
590 | |
591 | #[inline ] |
592 | pub(crate) fn pidfd_send_signal(fd: BorrowedFd<'_>, sig: Signal) -> io::Result<()> { |
593 | unsafe { |
594 | ret(raw:syscall_readonly!( |
595 | __NR_pidfd_send_signal, |
596 | fd, |
597 | sig, |
598 | pass_usize(0), |
599 | pass_usize(0) |
600 | )) |
601 | } |
602 | } |
603 | |
604 | #[cfg (feature = "alloc" )] |
605 | #[inline ] |
606 | pub(crate) fn getgroups(buf: &mut [Gid]) -> io::Result<usize> { |
607 | let len: i32 = buf.len().try_into().map_err(|_| io::Errno::NOMEM)?; |
608 | |
609 | unsafe { |
610 | ret_usize(raw:syscall!( |
611 | __NR_getgroups, |
612 | c_int(len), |
613 | slice_just_addr_mut(buf) |
614 | )) |
615 | } |
616 | } |
617 | |