1//! linux_raw syscalls supporting `rustix::thread`.
2//!
3//! # Safety
4//!
5//! See the `rustix::backend` module documentation for details.
6#![allow(unsafe_code, clippy::undocumented_unsafe_blocks)]
7
8use crate::backend::c;
9use crate::backend::conv::{
10 by_mut, by_ref, c_int, c_uint, ret, ret_c_int, ret_c_int_infallible, ret_usize, slice,
11 slice_just_addr, slice_just_addr_mut, zero,
12};
13use crate::fd::BorrowedFd;
14use crate::io;
15use crate::pid::Pid;
16use crate::thread::{ClockId, FutexFlags, FutexOperation, NanosleepRelativeResult, Timespec};
17use core::mem::MaybeUninit;
18#[cfg(target_pointer_width = "32")]
19use linux_raw_sys::general::timespec as __kernel_old_timespec;
20use linux_raw_sys::general::{__kernel_timespec, TIMER_ABSTIME};
21
22#[inline]
23pub(crate) fn clock_nanosleep_relative(
24 id: ClockId,
25 req: &__kernel_timespec,
26) -> NanosleepRelativeResult {
27 #[cfg(target_pointer_width = "32")]
28 unsafe {
29 let mut rem = MaybeUninit::<__kernel_timespec>::uninit();
30 match ret(syscall!(
31 __NR_clock_nanosleep_time64,
32 id,
33 c_int(0),
34 by_ref(req),
35 &mut rem
36 ))
37 .or_else(|err| {
38 // See the comments in `rustix_clock_gettime_via_syscall` about
39 // emulation.
40 if err == io::Errno::NOSYS {
41 clock_nanosleep_relative_old(id, req, &mut rem)
42 } else {
43 Err(err)
44 }
45 }) {
46 Ok(()) => NanosleepRelativeResult::Ok,
47 Err(io::Errno::INTR) => NanosleepRelativeResult::Interrupted(rem.assume_init()),
48 Err(err) => NanosleepRelativeResult::Err(err),
49 }
50 }
51 #[cfg(target_pointer_width = "64")]
52 unsafe {
53 let mut rem = MaybeUninit::<__kernel_timespec>::uninit();
54 match ret(syscall!(
55 __NR_clock_nanosleep,
56 id,
57 c_int(0),
58 by_ref(req),
59 &mut rem
60 )) {
61 Ok(()) => NanosleepRelativeResult::Ok,
62 Err(io::Errno::INTR) => NanosleepRelativeResult::Interrupted(rem.assume_init()),
63 Err(err) => NanosleepRelativeResult::Err(err),
64 }
65 }
66}
67
68#[cfg(target_pointer_width = "32")]
69unsafe fn clock_nanosleep_relative_old(
70 id: ClockId,
71 req: &__kernel_timespec,
72 rem: &mut MaybeUninit<__kernel_timespec>,
73) -> io::Result<()> {
74 let old_req = __kernel_old_timespec {
75 tv_sec: req.tv_sec.try_into().map_err(|_| io::Errno::INVAL)?,
76 tv_nsec: req.tv_nsec.try_into().map_err(|_| io::Errno::INVAL)?,
77 };
78 let mut old_rem = MaybeUninit::<__kernel_old_timespec>::uninit();
79 ret(syscall!(
80 __NR_clock_nanosleep,
81 id,
82 c_int(0),
83 by_ref(&old_req),
84 &mut old_rem
85 ))?;
86 let old_rem = old_rem.assume_init();
87 rem.write(__kernel_timespec {
88 tv_sec: old_rem.tv_sec.into(),
89 tv_nsec: old_rem.tv_nsec.into(),
90 });
91 Ok(())
92}
93
94#[inline]
95pub(crate) fn clock_nanosleep_absolute(id: ClockId, req: &__kernel_timespec) -> io::Result<()> {
96 #[cfg(target_pointer_width = "32")]
97 unsafe {
98 ret(syscall_readonly!(
99 __NR_clock_nanosleep_time64,
100 id,
101 c_uint(TIMER_ABSTIME),
102 by_ref(req),
103 zero()
104 ))
105 .or_else(|err| {
106 // See the comments in `rustix_clock_gettime_via_syscall` about
107 // emulation.
108 if err == io::Errno::NOSYS {
109 clock_nanosleep_absolute_old(id, req)
110 } else {
111 Err(err)
112 }
113 })
114 }
115 #[cfg(target_pointer_width = "64")]
116 unsafe {
117 ret(syscall_readonly!(
118 __NR_clock_nanosleep,
119 id,
120 c_uint(TIMER_ABSTIME),
121 by_ref(req),
122 zero()
123 ))
124 }
125}
126
127#[cfg(target_pointer_width = "32")]
128unsafe fn clock_nanosleep_absolute_old(id: ClockId, req: &__kernel_timespec) -> io::Result<()> {
129 let old_req = __kernel_old_timespec {
130 tv_sec: req.tv_sec.try_into().map_err(|_| io::Errno::INVAL)?,
131 tv_nsec: req.tv_nsec.try_into().map_err(|_| io::Errno::INVAL)?,
132 };
133 ret(syscall_readonly!(
134 __NR_clock_nanosleep,
135 id,
136 c_int(0),
137 by_ref(&old_req),
138 zero()
139 ))
140}
141
142#[inline]
143pub(crate) fn nanosleep(req: &__kernel_timespec) -> NanosleepRelativeResult {
144 #[cfg(target_pointer_width = "32")]
145 unsafe {
146 let mut rem = MaybeUninit::<__kernel_timespec>::uninit();
147 match ret(syscall!(
148 __NR_clock_nanosleep_time64,
149 ClockId::Realtime,
150 c_int(0),
151 by_ref(req),
152 &mut rem
153 ))
154 .or_else(|err| {
155 // See the comments in `rustix_clock_gettime_via_syscall` about
156 // emulation.
157 if err == io::Errno::NOSYS {
158 nanosleep_old(req, &mut rem)
159 } else {
160 Err(err)
161 }
162 }) {
163 Ok(()) => NanosleepRelativeResult::Ok,
164 Err(io::Errno::INTR) => NanosleepRelativeResult::Interrupted(rem.assume_init()),
165 Err(err) => NanosleepRelativeResult::Err(err),
166 }
167 }
168 #[cfg(target_pointer_width = "64")]
169 unsafe {
170 let mut rem = MaybeUninit::<__kernel_timespec>::uninit();
171 match ret(syscall!(__NR_nanosleep, by_ref(req), &mut rem)) {
172 Ok(()) => NanosleepRelativeResult::Ok,
173 Err(io::Errno::INTR) => NanosleepRelativeResult::Interrupted(rem.assume_init()),
174 Err(err) => NanosleepRelativeResult::Err(err),
175 }
176 }
177}
178
179#[cfg(target_pointer_width = "32")]
180unsafe fn nanosleep_old(
181 req: &__kernel_timespec,
182 rem: &mut MaybeUninit<__kernel_timespec>,
183) -> io::Result<()> {
184 let old_req = __kernel_old_timespec {
185 tv_sec: req.tv_sec.try_into().map_err(|_| io::Errno::INVAL)?,
186 tv_nsec: req.tv_nsec.try_into().map_err(|_| io::Errno::INVAL)?,
187 };
188 let mut old_rem = MaybeUninit::<__kernel_old_timespec>::uninit();
189 ret(syscall!(__NR_nanosleep, by_ref(&old_req), &mut old_rem))?;
190 let old_rem = old_rem.assume_init();
191 rem.write(__kernel_timespec {
192 tv_sec: old_rem.tv_sec.into(),
193 tv_nsec: old_rem.tv_nsec.into(),
194 });
195 Ok(())
196}
197
198#[inline]
199pub(crate) fn gettid() -> Pid {
200 unsafe {
201 let tid: i32 = ret_c_int_infallible(raw:syscall_readonly!(__NR_gettid));
202 Pid::from_raw_unchecked(raw:tid)
203 }
204}
205
206// TODO: This could be de-multiplexed.
207#[inline]
208pub(crate) unsafe fn futex(
209 uaddr: *mut u32,
210 op: FutexOperation,
211 flags: FutexFlags,
212 val: u32,
213 utime: *const Timespec,
214 uaddr2: *mut u32,
215 val3: u32,
216) -> io::Result<usize> {
217 #[cfg(target_pointer_width = "32")]
218 {
219 ret_usize(syscall!(
220 __NR_futex_time64,
221 uaddr,
222 (op, flags),
223 c_uint(val),
224 utime,
225 uaddr2,
226 c_uint(val3)
227 ))
228 .or_else(|err| {
229 // See the comments in `rustix_clock_gettime_via_syscall` about
230 // emulation.
231 if err == io::Errno::NOSYS {
232 futex_old(uaddr, op, flags, val, utime, uaddr2, val3)
233 } else {
234 Err(err)
235 }
236 })
237 }
238 #[cfg(target_pointer_width = "64")]
239 ret_usize(syscall!(
240 __NR_futex,
241 uaddr,
242 (op, flags),
243 c_uint(val),
244 utime,
245 uaddr2,
246 c_uint(val3)
247 ))
248}
249
250#[cfg(target_pointer_width = "32")]
251unsafe fn futex_old(
252 uaddr: *mut u32,
253 op: FutexOperation,
254 flags: FutexFlags,
255 val: u32,
256 utime: *const Timespec,
257 uaddr2: *mut u32,
258 val3: u32,
259) -> io::Result<usize> {
260 let old_utime = __kernel_old_timespec {
261 tv_sec: (*utime).tv_sec.try_into().map_err(|_| io::Errno::INVAL)?,
262 tv_nsec: (*utime).tv_nsec.try_into().map_err(|_| io::Errno::INVAL)?,
263 };
264 ret_usize(syscall!(
265 __NR_futex,
266 uaddr,
267 (op, flags),
268 c_uint(val),
269 by_ref(&old_utime),
270 uaddr2,
271 c_uint(val3)
272 ))
273}
274
275#[inline]
276pub(crate) fn setns(fd: BorrowedFd<'_>, nstype: c::c_int) -> io::Result<c::c_int> {
277 unsafe { ret_c_int(raw:syscall_readonly!(__NR_setns, fd, c_int(nstype))) }
278}
279
280#[inline]
281pub(crate) fn unshare(flags: crate::thread::UnshareFlags) -> io::Result<()> {
282 unsafe { ret(raw:syscall_readonly!(__NR_unshare, flags)) }
283}
284
285#[inline]
286pub(crate) fn capget(
287 header: &mut linux_raw_sys::general::__user_cap_header_struct,
288 data: &mut [MaybeUninit<linux_raw_sys::general::__user_cap_data_struct>],
289) -> io::Result<()> {
290 unsafe {
291 ret(raw:syscall!(
292 __NR_capget,
293 by_mut(header),
294 slice_just_addr_mut(data)
295 ))
296 }
297}
298
299#[inline]
300pub(crate) fn capset(
301 header: &mut linux_raw_sys::general::__user_cap_header_struct,
302 data: &[linux_raw_sys::general::__user_cap_data_struct],
303) -> io::Result<()> {
304 unsafe { ret(raw:syscall!(__NR_capset, by_mut(header), slice_just_addr(data))) }
305}
306
307#[inline]
308pub(crate) fn setuid_thread(uid: crate::ugid::Uid) -> io::Result<()> {
309 unsafe { ret(raw:syscall_readonly!(__NR_setuid, uid)) }
310}
311
312#[inline]
313pub(crate) fn setresuid_thread(
314 ruid: crate::ugid::Uid,
315 euid: crate::ugid::Uid,
316 suid: crate::ugid::Uid,
317) -> io::Result<()> {
318 #[cfg(any(target_arch = "x86", target_arch = "arm", target_arch = "sparc"))]
319 unsafe {
320 ret(syscall_readonly!(__NR_setresuid32, ruid, euid, suid))
321 }
322 #[cfg(not(any(target_arch = "x86", target_arch = "arm", target_arch = "sparc")))]
323 unsafe {
324 ret(raw:syscall_readonly!(__NR_setresuid, ruid, euid, suid))
325 }
326}
327
328#[inline]
329pub(crate) fn setgid_thread(gid: crate::ugid::Gid) -> io::Result<()> {
330 unsafe { ret(raw:syscall_readonly!(__NR_setgid, gid)) }
331}
332
333#[inline]
334pub(crate) fn setresgid_thread(
335 rgid: crate::ugid::Gid,
336 egid: crate::ugid::Gid,
337 sgid: crate::ugid::Gid,
338) -> io::Result<()> {
339 #[cfg(any(target_arch = "x86", target_arch = "arm", target_arch = "sparc"))]
340 unsafe {
341 ret(syscall_readonly!(__NR_setresgid32, rgid, egid, sgid))
342 }
343 #[cfg(not(any(target_arch = "x86", target_arch = "arm", target_arch = "sparc")))]
344 unsafe {
345 ret(raw:syscall_readonly!(__NR_setresgid, rgid, egid, sgid))
346 }
347}
348
349#[inline]
350pub(crate) fn setgroups_thread(gids: &[crate::ugid::Gid]) -> io::Result<()> {
351 let (addr: ArgReg<'_, A1>, len: ArgReg<'_, A0>) = slice(gids);
352 unsafe { ret(raw:syscall_readonly!(__NR_setgroups, len, addr)) }
353}
354