1 //! linux_raw syscalls supporting `rustix::thread`.
5 //! See the `rustix::backend` module documentation for details.
7 #![allow(clippy::undocumented_unsafe_blocks)]
10 use super::super::conv
::{
11 by_mut
, by_ref
, c_int
, c_uint
, ret
, ret_c_int
, ret_usize
, ret_usize_infallible
,
12 slice_just_addr
, slice_just_addr_mut
, zero
,
14 use crate::fd
::BorrowedFd
;
16 use crate::process
::{Pid, RawNonZeroPid}
;
17 use crate::thread
::{ClockId, FutexFlags, FutexOperation, NanosleepRelativeResult, Timespec}
;
18 use core
::mem
::MaybeUninit
;
19 use linux_raw_sys
::general
::{__kernel_pid_t, __kernel_timespec, TIMER_ABSTIME}
;
20 #[cfg(target_pointer_width = "32")]
21 use {core::convert::TryInto, linux_raw_sys::general::timespec as __kernel_old_timespec}
;
24 pub(crate) fn clock_nanosleep_relative(
26 req
: &__kernel_timespec
,
27 ) -> NanosleepRelativeResult
{
28 #[cfg(target_pointer_width = "32")]
30 let mut rem
= MaybeUninit
::<__kernel_timespec
>::uninit();
32 __NR_clock_nanosleep_time64
,
39 // See the comments in `rustix_clock_gettime_via_syscall` about
41 if err
== io
::Errno
::NOSYS
{
42 clock_nanosleep_relative_old(id
, req
, &mut rem
)
47 Ok(()) => NanosleepRelativeResult
::Ok
,
48 Err(io
::Errno
::INTR
) => NanosleepRelativeResult
::Interrupted(rem
.assume_init()),
49 Err(err
) => NanosleepRelativeResult
::Err(err
),
52 #[cfg(target_pointer_width = "64")]
54 let mut rem
= MaybeUninit
::<__kernel_timespec
>::uninit();
62 Ok(()) => NanosleepRelativeResult
::Ok
,
63 Err(io
::Errno
::INTR
) => NanosleepRelativeResult
::Interrupted(rem
.assume_init()),
64 Err(err
) => NanosleepRelativeResult
::Err(err
),
69 #[cfg(target_pointer_width = "32")]
70 unsafe fn clock_nanosleep_relative_old(
72 req
: &__kernel_timespec
,
73 rem
: &mut MaybeUninit
<__kernel_timespec
>,
75 let old_req
= __kernel_old_timespec
{
76 tv_sec
: req
.tv_sec
.try_into().map_err(|_
| io
::Errno
::INVAL
)?
,
77 tv_nsec
: req
.tv_nsec
.try_into().map_err(|_
| io
::Errno
::INVAL
)?
,
79 let mut old_rem
= MaybeUninit
::<__kernel_old_timespec
>::uninit();
87 let old_rem
= old_rem
.assume_init();
88 // TODO: With Rust 1.55, we can use MaybeUninit::write here.
89 rem
.as_mut_ptr().write(__kernel_timespec
{
90 tv_sec
: old_rem
.tv_sec
.into(),
91 tv_nsec
: old_rem
.tv_nsec
.into(),
97 pub(crate) fn clock_nanosleep_absolute(id
: ClockId
, req
: &__kernel_timespec
) -> io
::Result
<()> {
98 #[cfg(target_pointer_width = "32")]
100 ret(syscall_readonly
!(
101 __NR_clock_nanosleep_time64
,
103 c_uint(TIMER_ABSTIME
),
108 // See the comments in `rustix_clock_gettime_via_syscall` about
110 if err
== io
::Errno
::NOSYS
{
111 clock_nanosleep_absolute_old(id
, req
)
117 #[cfg(target_pointer_width = "64")]
119 ret(syscall_readonly
!(
120 __NR_clock_nanosleep
,
122 c_uint(TIMER_ABSTIME
),
129 #[cfg(target_pointer_width = "32")]
130 unsafe fn clock_nanosleep_absolute_old(id
: ClockId
, req
: &__kernel_timespec
) -> io
::Result
<()> {
131 let old_req
= __kernel_old_timespec
{
132 tv_sec
: req
.tv_sec
.try_into().map_err(|_
| io
::Errno
::INVAL
)?
,
133 tv_nsec
: req
.tv_nsec
.try_into().map_err(|_
| io
::Errno
::INVAL
)?
,
135 ret(syscall_readonly
!(
136 __NR_clock_nanosleep
,
145 pub(crate) fn nanosleep(req
: &__kernel_timespec
) -> NanosleepRelativeResult
{
146 #[cfg(target_pointer_width = "32")]
148 let mut rem
= MaybeUninit
::<__kernel_timespec
>::uninit();
150 __NR_clock_nanosleep_time64
,
157 // See the comments in `rustix_clock_gettime_via_syscall` about
159 if err
== io
::Errno
::NOSYS
{
160 nanosleep_old(req
, &mut rem
)
165 Ok(()) => NanosleepRelativeResult
::Ok
,
166 Err(io
::Errno
::INTR
) => NanosleepRelativeResult
::Interrupted(rem
.assume_init()),
167 Err(err
) => NanosleepRelativeResult
::Err(err
),
170 #[cfg(target_pointer_width = "64")]
172 let mut rem
= MaybeUninit
::<__kernel_timespec
>::uninit();
173 match ret(syscall
!(__NR_nanosleep
, by_ref(req
), &mut rem
)) {
174 Ok(()) => NanosleepRelativeResult
::Ok
,
175 Err(io
::Errno
::INTR
) => NanosleepRelativeResult
::Interrupted(rem
.assume_init()),
176 Err(err
) => NanosleepRelativeResult
::Err(err
),
181 #[cfg(target_pointer_width = "32")]
182 unsafe fn nanosleep_old(
183 req
: &__kernel_timespec
,
184 rem
: &mut MaybeUninit
<__kernel_timespec
>,
185 ) -> io
::Result
<()> {
186 let old_req
= __kernel_old_timespec
{
187 tv_sec
: req
.tv_sec
.try_into().map_err(|_
| io
::Errno
::INVAL
)?
,
188 tv_nsec
: req
.tv_nsec
.try_into().map_err(|_
| io
::Errno
::INVAL
)?
,
190 let mut old_rem
= MaybeUninit
::<__kernel_old_timespec
>::uninit();
191 ret(syscall
!(__NR_nanosleep
, by_ref(&old_req
), &mut old_rem
))?
;
192 let old_rem
= old_rem
.assume_init();
193 // TODO: With Rust 1.55, we can use MaybeUninit::write here.
194 rem
.as_mut_ptr().write(__kernel_timespec
{
195 tv_sec
: old_rem
.tv_sec
.into(),
196 tv_nsec
: old_rem
.tv_nsec
.into(),
202 pub(crate) fn gettid() -> Pid
{
204 let tid
: i32 = ret_usize_infallible(syscall_readonly
!(__NR_gettid
)) as __kernel_pid_t
;
205 debug_assert_ne
!(tid
, 0);
206 Pid
::from_raw_nonzero(RawNonZeroPid
::new_unchecked(tid
as u32))
210 // TODO: This could be de-multiplexed.
212 pub(crate) unsafe fn futex(
217 utime
: *const Timespec
,
220 ) -> io
::Result
<usize> {
221 #[cfg(target_pointer_width = "32")]
233 // See the comments in `rustix_clock_gettime_via_syscall` about
235 if err
== io
::Errno
::NOSYS
{
236 futex_old(uaddr
, op
, flags
, val
, utime
, uaddr2
, val3
)
242 #[cfg(target_pointer_width = "64")]
254 #[cfg(target_pointer_width = "32")]
260 utime
: *const Timespec
,
263 ) -> io
::Result
<usize> {
264 let old_utime
= __kernel_old_timespec
{
265 tv_sec
: (*utime
).tv_sec
.try_into().map_err(|_
| io
::Errno
::INVAL
)?
,
266 tv_nsec
: (*utime
).tv_nsec
.try_into().map_err(|_
| io
::Errno
::INVAL
)?
,
281 pub(crate) fn setns(fd
: BorrowedFd
, nstype
: c
::c_int
) -> io
::Result
<c
::c_int
> {
282 unsafe { ret_c_int(syscall_readonly!(__NR_setns, fd, c_int(nstype))) }
287 pub(crate) fn unshare(flags
: crate::thread
::UnshareFlags
) -> io
::Result
<()> {
288 unsafe { ret(syscall_readonly!(__NR_unshare, c_uint(flags.bits()))) }
293 pub(crate) fn capget(
294 header
: &mut linux_raw_sys
::general
::__user_cap_header_struct
,
295 data
: &mut [MaybeUninit
<linux_raw_sys
::general
::__user_cap_data_struct
>],
296 ) -> io
::Result
<()> {
301 slice_just_addr_mut(data
)
308 pub(crate) fn capset(
309 header
: &mut linux_raw_sys
::general
::__user_cap_header_struct
,
310 data
: &[linux_raw_sys
::general
::__user_cap_data_struct
],
311 ) -> io
::Result
<()> {
312 unsafe { ret(syscall!(__NR_capset, by_mut(header), slice_just_addr(data))) }
316 pub(crate) fn setuid_thread(uid
: crate::process
::Uid
) -> io
::Result
<()> {
317 unsafe { ret(syscall_readonly!(__NR_setuid, uid)) }
321 pub(crate) fn setresuid_thread(
322 ruid
: crate::process
::Uid
,
323 euid
: crate::process
::Uid
,
324 suid
: crate::process
::Uid
,
325 ) -> io
::Result
<()> {
326 #[cfg(any(target_arch = "x86", target_arch = "arm", target_arch = "sparc"))]
328 ret(syscall_readonly
!(__NR_setresuid32
, ruid
, euid
, suid
))
330 #[cfg(not(any(target_arch = "x86", target_arch = "arm", target_arch = "sparc")))]
332 ret(syscall_readonly
!(__NR_setresuid
, ruid
, euid
, suid
))
337 pub(crate) fn setgid_thread(gid
: crate::process
::Gid
) -> io
::Result
<()> {
338 unsafe { ret(syscall_readonly!(__NR_setgid, gid)) }
342 pub(crate) fn setresgid_thread(
343 rgid
: crate::process
::Gid
,
344 egid
: crate::process
::Gid
,
345 sgid
: crate::process
::Gid
,
346 ) -> io
::Result
<()> {
347 #[cfg(any(target_arch = "x86", target_arch = "arm", target_arch = "sparc"))]
349 ret(syscall_readonly
!(__NR_setresgid32
, rgid
, egid
, sgid
))
351 #[cfg(not(any(target_arch = "x86", target_arch = "arm", target_arch = "sparc")))]
353 ret(syscall_readonly
!(__NR_setresgid
, rgid
, egid
, sgid
))