]> git.proxmox.com Git - rustc.git/blob - vendor/rustix-0.37.20/src/backend/linux_raw/thread/syscalls.rs
New upstream version 1.72.1+dfsg1
[rustc.git] / vendor / rustix-0.37.20 / src / backend / linux_raw / thread / syscalls.rs
1 //! linux_raw syscalls supporting `rustix::thread`.
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, ret, ret_c_int, ret_usize, ret_usize_infallible,
12 slice_just_addr, slice_just_addr_mut, zero,
13 };
14 use crate::fd::BorrowedFd;
15 use crate::io;
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};
22
23 #[inline]
24 pub(crate) fn clock_nanosleep_relative(
25 id: ClockId,
26 req: &__kernel_timespec,
27 ) -> NanosleepRelativeResult {
28 #[cfg(target_pointer_width = "32")]
29 unsafe {
30 let mut rem = MaybeUninit::<__kernel_timespec>::uninit();
31 match ret(syscall!(
32 __NR_clock_nanosleep_time64,
33 id,
34 c_int(0),
35 by_ref(req),
36 &mut rem
37 ))
38 .or_else(|err| {
39 // See the comments in `rustix_clock_gettime_via_syscall` about
40 // emulation.
41 if err == io::Errno::NOSYS {
42 clock_nanosleep_relative_old(id, req, &mut rem)
43 } else {
44 Err(err)
45 }
46 }) {
47 Ok(()) => NanosleepRelativeResult::Ok,
48 Err(io::Errno::INTR) => NanosleepRelativeResult::Interrupted(rem.assume_init()),
49 Err(err) => NanosleepRelativeResult::Err(err),
50 }
51 }
52 #[cfg(target_pointer_width = "64")]
53 unsafe {
54 let mut rem = MaybeUninit::<__kernel_timespec>::uninit();
55 match ret(syscall!(
56 __NR_clock_nanosleep,
57 id,
58 c_int(0),
59 by_ref(req),
60 &mut rem
61 )) {
62 Ok(()) => NanosleepRelativeResult::Ok,
63 Err(io::Errno::INTR) => NanosleepRelativeResult::Interrupted(rem.assume_init()),
64 Err(err) => NanosleepRelativeResult::Err(err),
65 }
66 }
67 }
68
69 #[cfg(target_pointer_width = "32")]
70 unsafe fn clock_nanosleep_relative_old(
71 id: ClockId,
72 req: &__kernel_timespec,
73 rem: &mut MaybeUninit<__kernel_timespec>,
74 ) -> io::Result<()> {
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)?,
78 };
79 let mut old_rem = MaybeUninit::<__kernel_old_timespec>::uninit();
80 ret(syscall!(
81 __NR_clock_nanosleep,
82 id,
83 c_int(0),
84 by_ref(&old_req),
85 &mut old_rem
86 ))?;
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(),
92 });
93 Ok(())
94 }
95
96 #[inline]
97 pub(crate) fn clock_nanosleep_absolute(id: ClockId, req: &__kernel_timespec) -> io::Result<()> {
98 #[cfg(target_pointer_width = "32")]
99 unsafe {
100 ret(syscall_readonly!(
101 __NR_clock_nanosleep_time64,
102 id,
103 c_uint(TIMER_ABSTIME),
104 by_ref(req),
105 zero()
106 ))
107 .or_else(|err| {
108 // See the comments in `rustix_clock_gettime_via_syscall` about
109 // emulation.
110 if err == io::Errno::NOSYS {
111 clock_nanosleep_absolute_old(id, req)
112 } else {
113 Err(err)
114 }
115 })
116 }
117 #[cfg(target_pointer_width = "64")]
118 unsafe {
119 ret(syscall_readonly!(
120 __NR_clock_nanosleep,
121 id,
122 c_uint(TIMER_ABSTIME),
123 by_ref(req),
124 zero()
125 ))
126 }
127 }
128
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)?,
134 };
135 ret(syscall_readonly!(
136 __NR_clock_nanosleep,
137 id,
138 c_int(0),
139 by_ref(&old_req),
140 zero()
141 ))
142 }
143
144 #[inline]
145 pub(crate) fn nanosleep(req: &__kernel_timespec) -> NanosleepRelativeResult {
146 #[cfg(target_pointer_width = "32")]
147 unsafe {
148 let mut rem = MaybeUninit::<__kernel_timespec>::uninit();
149 match ret(syscall!(
150 __NR_clock_nanosleep_time64,
151 ClockId::Realtime,
152 c_int(0),
153 by_ref(req),
154 &mut rem
155 ))
156 .or_else(|err| {
157 // See the comments in `rustix_clock_gettime_via_syscall` about
158 // emulation.
159 if err == io::Errno::NOSYS {
160 nanosleep_old(req, &mut rem)
161 } else {
162 Err(err)
163 }
164 }) {
165 Ok(()) => NanosleepRelativeResult::Ok,
166 Err(io::Errno::INTR) => NanosleepRelativeResult::Interrupted(rem.assume_init()),
167 Err(err) => NanosleepRelativeResult::Err(err),
168 }
169 }
170 #[cfg(target_pointer_width = "64")]
171 unsafe {
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),
177 }
178 }
179 }
180
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)?,
189 };
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(),
197 });
198 Ok(())
199 }
200
201 #[inline]
202 pub(crate) fn gettid() -> Pid {
203 unsafe {
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))
207 }
208 }
209
210 // TODO: This could be de-multiplexed.
211 #[inline]
212 pub(crate) unsafe fn futex(
213 uaddr: *mut u32,
214 op: FutexOperation,
215 flags: FutexFlags,
216 val: u32,
217 utime: *const Timespec,
218 uaddr2: *mut u32,
219 val3: u32,
220 ) -> io::Result<usize> {
221 #[cfg(target_pointer_width = "32")]
222 {
223 ret_usize(syscall!(
224 __NR_futex_time64,
225 uaddr,
226 (op, flags),
227 c_uint(val),
228 utime,
229 uaddr2,
230 c_uint(val3)
231 ))
232 .or_else(|err| {
233 // See the comments in `rustix_clock_gettime_via_syscall` about
234 // emulation.
235 if err == io::Errno::NOSYS {
236 futex_old(uaddr, op, flags, val, utime, uaddr2, val3)
237 } else {
238 Err(err)
239 }
240 })
241 }
242 #[cfg(target_pointer_width = "64")]
243 ret_usize(syscall!(
244 __NR_futex,
245 uaddr,
246 (op, flags),
247 c_uint(val),
248 utime,
249 uaddr2,
250 c_uint(val3)
251 ))
252 }
253
254 #[cfg(target_pointer_width = "32")]
255 unsafe fn futex_old(
256 uaddr: *mut u32,
257 op: FutexOperation,
258 flags: FutexFlags,
259 val: u32,
260 utime: *const Timespec,
261 uaddr2: *mut u32,
262 val3: u32,
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)?,
267 };
268 ret_usize(syscall!(
269 __NR_futex,
270 uaddr,
271 (op, flags),
272 c_uint(val),
273 by_ref(&old_utime),
274 uaddr2,
275 c_uint(val3)
276 ))
277 }
278
279 #[cfg(linux_kernel)]
280 #[inline]
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))) }
283 }
284
285 #[cfg(linux_kernel)]
286 #[inline]
287 pub(crate) fn unshare(flags: crate::thread::UnshareFlags) -> io::Result<()> {
288 unsafe { ret(syscall_readonly!(__NR_unshare, c_uint(flags.bits()))) }
289 }
290
291 #[cfg(linux_kernel)]
292 #[inline]
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<()> {
297 unsafe {
298 ret(syscall!(
299 __NR_capget,
300 by_mut(header),
301 slice_just_addr_mut(data)
302 ))
303 }
304 }
305
306 #[cfg(linux_kernel)]
307 #[inline]
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))) }
313 }
314
315 #[inline]
316 pub(crate) fn setuid_thread(uid: crate::process::Uid) -> io::Result<()> {
317 unsafe { ret(syscall_readonly!(__NR_setuid, uid)) }
318 }
319
320 #[inline]
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"))]
327 unsafe {
328 ret(syscall_readonly!(__NR_setresuid32, ruid, euid, suid))
329 }
330 #[cfg(not(any(target_arch = "x86", target_arch = "arm", target_arch = "sparc")))]
331 unsafe {
332 ret(syscall_readonly!(__NR_setresuid, ruid, euid, suid))
333 }
334 }
335
336 #[inline]
337 pub(crate) fn setgid_thread(gid: crate::process::Gid) -> io::Result<()> {
338 unsafe { ret(syscall_readonly!(__NR_setgid, gid)) }
339 }
340
341 #[inline]
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"))]
348 unsafe {
349 ret(syscall_readonly!(__NR_setresgid32, rgid, egid, sgid))
350 }
351 #[cfg(not(any(target_arch = "x86", target_arch = "arm", target_arch = "sparc")))]
352 unsafe {
353 ret(syscall_readonly!(__NR_setresgid, rgid, egid, sgid))
354 }
355 }