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
9use super::super::c;
10use 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};
15use super::types::{RawCpuSet, RawUname};
16use crate::backend::conv::ret_owned_fd;
17use crate::fd::{AsRawFd, BorrowedFd, OwnedFd};
18use crate::ffi::CStr;
19use crate::io;
20use crate::process::{
21 Cpuid, Gid, MembarrierCommand, MembarrierQuery, Pid, PidfdFlags, RawNonZeroPid, RawPid,
22 Resource, Rlimit, Signal, Sysinfo, Uid, WaitId, WaitOptions, WaitStatus, WaitidOptions,
23 WaitidStatus,
24};
25use crate::utils::as_mut_ptr;
26use core::convert::TryInto;
27use core::mem::MaybeUninit;
28use core::num::NonZeroU32;
29use core::ptr::{null, null_mut};
30use 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};
34use linux_raw_sys::ioctl::TIOCSCTTY;
35#[cfg(not(target_os = "wasi"))]
36#[cfg(feature = "fs")]
37use {super::super::conv::ret_c_uint_infallible, crate::fs::Mode};
38
39#[inline]
40pub(crate) fn chdir(filename: &CStr) -> io::Result<()> {
41 unsafe { ret(raw:syscall_readonly!(__NR_chdir, filename)) }
42}
43
44#[inline]
45pub(crate) fn fchdir(fd: BorrowedFd<'_>) -> io::Result<()> {
46 unsafe { ret(raw:syscall_readonly!(__NR_fchdir, fd)) }
47}
48
49#[inline]
50pub(crate) fn chroot(filename: &CStr) -> io::Result<()> {
51 unsafe { ret(raw:syscall_readonly!(__NR_chroot, filename)) }
52}
53
54#[inline]
55pub(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]
61pub(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]
83pub(crate) fn membarrier(cmd: MembarrierCommand) -> io::Result<()> {
84 unsafe { ret(raw:syscall!(__NR_membarrier, cmd, c_uint(0))) }
85}
86
87#[inline]
88pub(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]
100pub(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]
109pub(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]
117pub(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]
128pub(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]
139pub(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]
159pub(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]
174pub(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]
189pub(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]
203pub(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]
218pub(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]
238pub(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]
250pub(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]
259pub(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]
269pub(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]
277pub(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]
292pub(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]
304pub(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]
316pub(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]
328pub(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]
340pub(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]
352pub(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]
364pub(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`.
385unsafe 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]
414pub(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`.
433unsafe 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]
439pub(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]
458fn 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]
474fn 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)]
488fn 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)]
504fn 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]
517pub(crate) fn wait(waitopts: WaitOptions) -> io::Result<Option<(Pid, WaitStatus)>> {
518 _waitpid(!0, waitopts)
519}
520
521#[inline]
522pub(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]
530pub(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]
553pub(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]
563fn _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]
582fn _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]
601fn _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]
627unsafe 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]
638pub(crate) fn exit_group(code: c::c_int) -> ! {
639 unsafe { syscall_noreturn!(__NR_exit_group, c_int(code)) }
640}
641
642#[inline]
643pub(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]
654pub(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]
665pub(crate) fn kill_process(pid: Pid, sig: Signal) -> io::Result<()> {
666 unsafe { ret(raw:syscall_readonly!(__NR_kill, pid, sig)) }
667}
668
669#[inline]
670pub(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]
675pub(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]
680pub(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]
685pub(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]
696pub(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]
701pub(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]
712pub(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]
723pub(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]
736pub(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]
745pub(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]
751pub(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