1 //! libc syscalls supporting `rustix::thread`.
4 use super::super::conv
::ret
;
5 #[cfg(any(target_os = "android", target_os = "linux"))]
6 use super::super::conv
::{borrowed_fd, ret_c_int, syscall_ret}
;
7 use super::super::time
::types
::LibcTimespec
;
8 #[cfg(any(target_os = "android", target_os = "linux"))]
9 use crate::fd
::BorrowedFd
;
11 #[cfg(any(target_os = "android", target_os = "linux"))]
12 use crate::process
::{Pid, RawNonZeroPid}
;
13 #[cfg(not(target_os = "redox"))]
14 use crate::thread
::{NanosleepRelativeResult, Timespec}
;
15 use core
::mem
::MaybeUninit
;
19 target_os
= "emscripten",
21 target_os
= "openbsd",
25 use {crate::thread::ClockId, core::ptr::null_mut}
;
28 any(target_arch
= "arm", target_arch
= "mips", target_arch
= "x86"),
31 weak
!(fn __clock_nanosleep_time64(c
::clockid_t
, c
::c_int
, *const LibcTimespec
, *mut LibcTimespec
) -> c
::c_int
);
33 any(target_arch
= "arm", target_arch
= "mips", target_arch
= "x86"),
36 weak
!(fn __nanosleep64(*const LibcTimespec
, *mut LibcTimespec
) -> c
::c_int
);
40 target_os
= "dragonfly",
41 target_os
= "emscripten",
42 target_os
= "freebsd", // FreeBSD 12 has clock_nanosleep, but libc targets FreeBSD 11.
44 target_os
= "openbsd",
49 pub(crate) fn clock_nanosleep_relative(id
: ClockId
, request
: &Timespec
) -> NanosleepRelativeResult
{
50 let mut remain
= MaybeUninit
::<LibcTimespec
>::uninit();
53 // 32-bit gnu version: libc has `clock_nanosleep` but it is not y2038 safe by
56 any(target_arch
= "arm", target_arch
= "mips", target_arch
= "x86"),
60 if let Some(libc_clock_nanosleep
) = __clock_nanosleep_time64
.get() {
61 match libc_clock_nanosleep(
64 &request
.clone().into(),
67 0 => NanosleepRelativeResult
::Ok
,
68 err
if err
== io
::Errno
::INTR
.0 => {
69 NanosleepRelativeResult
::Interrupted(remain
.assume_init().into())
71 err
=> NanosleepRelativeResult
::Err(io
::Errno(err
)),
74 clock_nanosleep_relative_old(id
, request
)
78 // Main version: libc is y2038 safe and has `clock_nanosleep`.
80 any(target_arch
= "arm", target_arch
= "mips", target_arch
= "x86"),
84 match c
::clock_nanosleep(id
as c
::clockid_t
, flags
, request
, remain
.as_mut_ptr()) {
85 0 => NanosleepRelativeResult
::Ok
,
86 err
if err
== io
::Errno
::INTR
.0 => {
87 NanosleepRelativeResult
::Interrupted(remain
.assume_init())
89 err
=> NanosleepRelativeResult
::Err(io
::Errno(err
)),
95 any(target_arch
= "arm", target_arch
= "mips", target_arch
= "x86"),
98 unsafe fn clock_nanosleep_relative_old(id
: ClockId
, request
: &Timespec
) -> NanosleepRelativeResult
{
99 use core
::convert
::TryInto
;
100 let tv_sec
= match request
.tv_sec
.try_into() {
101 Ok(tv_sec
) => tv_sec
,
102 Err(_
) => return NanosleepRelativeResult
::Err(io
::Errno
::OVERFLOW
),
104 let tv_nsec
= match request
.tv_nsec
.try_into() {
105 Ok(tv_nsec
) => tv_nsec
,
106 Err(_
) => return NanosleepRelativeResult
::Err(io
::Errno
::INVAL
),
108 let old_request
= c
::timespec { tv_sec, tv_nsec }
;
109 let mut old_remain
= MaybeUninit
::<c
::timespec
>::uninit();
112 match c
::clock_nanosleep(
116 old_remain
.as_mut_ptr(),
118 0 => NanosleepRelativeResult
::Ok
,
119 err
if err
== io
::Errno
::INTR
.0 => {
120 let old_remain
= old_remain
.assume_init();
121 let remain
= Timespec
{
122 tv_sec
: old_remain
.tv_sec
.into(),
123 tv_nsec
: old_remain
.tv_nsec
.into(),
125 NanosleepRelativeResult
::Interrupted(remain
)
127 err
=> NanosleepRelativeResult
::Err(io
::Errno(err
)),
133 target_os
= "dragonfly",
134 target_os
= "emscripten",
135 target_os
= "freebsd", // FreeBSD 12 has clock_nanosleep, but libc targets FreeBSD 11.
137 target_os
= "openbsd",
142 pub(crate) fn clock_nanosleep_absolute(id
: ClockId
, request
: &Timespec
) -> io
::Result
<()> {
143 let flags
= c
::TIMER_ABSTIME
;
145 // 32-bit gnu version: libc has `clock_nanosleep` but it is not y2038 safe by
148 any(target_arch
= "arm", target_arch
= "mips", target_arch
= "x86"),
152 if let Some(libc_clock_nanosleep
) = __clock_nanosleep_time64
.get() {
154 libc_clock_nanosleep(
157 &request
.clone().into(),
162 err
=> Err(io
::Errno(err
)),
165 clock_nanosleep_absolute_old(id
, request
)
169 // Main version: libc is y2038 safe and has `clock_nanosleep`.
171 any(target_arch
= "arm", target_arch
= "mips", target_arch
= "x86"),
174 match unsafe { c::clock_nanosleep(id as c::clockid_t, flags, request, null_mut()) }
{
176 err
=> Err(io
::Errno(err
)),
181 any(target_arch
= "arm", target_arch
= "mips", target_arch
= "x86"),
184 fn clock_nanosleep_absolute_old(id
: ClockId
, request
: &Timespec
) -> io
::Result
<()> {
185 use core
::convert
::TryInto
;
187 let flags
= c
::TIMER_ABSTIME
;
189 let old_request
= c
::timespec
{
190 tv_sec
: request
.tv_sec
.try_into().map_err(|_
| io
::Errno
::OVERFLOW
)?
,
191 tv_nsec
: request
.tv_nsec
.try_into().map_err(|_
| io
::Errno
::INVAL
)?
,
193 match unsafe { c::clock_nanosleep(id as c::clockid_t, flags, &old_request, null_mut()) }
{
195 err
=> Err(io
::Errno(err
)),
199 #[cfg(not(target_os = "redox"))]
201 pub(crate) fn nanosleep(request
: &Timespec
) -> NanosleepRelativeResult
{
202 let mut remain
= MaybeUninit
::<LibcTimespec
>::uninit();
204 // 32-bit gnu version: libc has `nanosleep` but it is not y2038 safe by
207 any(target_arch
= "arm", target_arch
= "mips", target_arch
= "x86"),
211 if let Some(libc_nanosleep
) = __nanosleep64
.get() {
212 match ret(libc_nanosleep(&request
.clone().into(), remain
.as_mut_ptr())) {
213 Ok(()) => NanosleepRelativeResult
::Ok
,
214 Err(io
::Errno
::INTR
) => {
215 NanosleepRelativeResult
::Interrupted(remain
.assume_init().into())
217 Err(err
) => NanosleepRelativeResult
::Err(err
),
220 nanosleep_old(request
)
224 // Main version: libc is y2038 safe and has `nanosleep`.
226 any(target_arch
= "arm", target_arch
= "mips", target_arch
= "x86"),
230 match ret(c
::nanosleep(request
, remain
.as_mut_ptr())) {
231 Ok(()) => NanosleepRelativeResult
::Ok
,
232 Err(io
::Errno
::INTR
) => NanosleepRelativeResult
::Interrupted(remain
.assume_init()),
233 Err(err
) => NanosleepRelativeResult
::Err(err
),
239 any(target_arch
= "arm", target_arch
= "mips", target_arch
= "x86"),
242 unsafe fn nanosleep_old(request
: &Timespec
) -> NanosleepRelativeResult
{
243 use core
::convert
::TryInto
;
244 let tv_sec
= match request
.tv_sec
.try_into() {
245 Ok(tv_sec
) => tv_sec
,
246 Err(_
) => return NanosleepRelativeResult
::Err(io
::Errno
::OVERFLOW
),
248 let tv_nsec
= match request
.tv_nsec
.try_into() {
249 Ok(tv_nsec
) => tv_nsec
,
250 Err(_
) => return NanosleepRelativeResult
::Err(io
::Errno
::INVAL
),
252 let old_request
= c
::timespec { tv_sec, tv_nsec }
;
253 let mut old_remain
= MaybeUninit
::<c
::timespec
>::uninit();
255 match ret(c
::nanosleep(&old_request
, old_remain
.as_mut_ptr())) {
256 Ok(()) => NanosleepRelativeResult
::Ok
,
257 Err(io
::Errno
::INTR
) => {
258 let old_remain
= old_remain
.assume_init();
259 let remain
= Timespec
{
260 tv_sec
: old_remain
.tv_sec
.into(),
261 tv_nsec
: old_remain
.tv_nsec
.into(),
263 NanosleepRelativeResult
::Interrupted(remain
)
265 Err(err
) => NanosleepRelativeResult
::Err(err
),
269 #[cfg(any(target_os = "android", target_os = "linux"))]
272 pub(crate) fn gettid() -> Pid
{
273 // `gettid` wasn't supported in glibc until 2.30, and musl until 1.2.2,
275 // <https://sourceware.org/bugzilla/show_bug.cgi?id=6399#c62>
277 fn gettid() via SYS_gettid
-> c
::pid_t
282 debug_assert_ne
!(tid
, 0);
283 Pid
::from_raw_nonzero(RawNonZeroPid
::new_unchecked(tid
))
287 #[cfg(any(target_os = "android", target_os = "linux"))]
289 pub(crate) fn setns(fd
: BorrowedFd
, nstype
: c
::c_int
) -> io
::Result
<c
::c_int
> {
290 // `setns` wasn't supported in glibc until 2.14, and musl until 0.9.5,
293 fn setns(fd
: c
::c_int
, nstype
: c
::c_int
) via SYS_setns
-> c
::c_int
296 unsafe { ret_c_int(setns(borrowed_fd(fd), nstype)) }
299 #[cfg(any(target_os = "android", target_os = "linux"))]
301 pub(crate) fn unshare(flags
: crate::thread
::UnshareFlags
) -> io
::Result
<()> {
302 unsafe { ret(c::unshare(flags.bits() as i32)) }
305 #[cfg(any(target_os = "android", target_os = "linux"))]
307 pub(crate) fn capget(
308 header
: &mut linux_raw_sys
::general
::__user_cap_header_struct
,
309 data
: &mut [MaybeUninit
<linux_raw_sys
::general
::__user_cap_data_struct
>],
310 ) -> io
::Result
<()> {
311 let header
: *mut _
= header
;
312 unsafe { syscall_ret(c::syscall(c::SYS_capget, header, data.as_mut_ptr())) }
315 #[cfg(any(target_os = "android", target_os = "linux"))]
317 pub(crate) fn capset(
318 header
: &mut linux_raw_sys
::general
::__user_cap_header_struct
,
319 data
: &[linux_raw_sys
::general
::__user_cap_data_struct
],
320 ) -> io
::Result
<()> {
321 let header
: *mut _
= header
;
322 unsafe { syscall_ret(c::syscall(c::SYS_capset, header, data.as_ptr())) }
325 #[cfg(any(target_os = "android", target_os = "linux"))]
327 pub(crate) fn setuid_thread(uid
: crate::process
::Uid
) -> io
::Result
<()> {
328 unsafe { syscall_ret(c::syscall(c::SYS_setuid, uid.as_raw())) }
331 #[cfg(any(target_os = "android", target_os = "linux"))]
333 pub(crate) fn setresuid_thread(
334 ruid
: crate::process
::Uid
,
335 euid
: crate::process
::Uid
,
336 suid
: crate::process
::Uid
,
337 ) -> io
::Result
<()> {
338 #[cfg(any(target_arch = "x86", target_arch = "arm", target_arch = "sparc"))]
339 const SYS
: c
::c_long
= c
::SYS_setresuid32
as c
::c_long
;
340 #[cfg(not(any(target_arch = "x86", target_arch = "arm", target_arch = "sparc")))]
341 const SYS
: c
::c_long
= c
::SYS_setresuid
as c
::c_long
;
342 unsafe { syscall_ret(c::syscall(SYS, ruid.as_raw(), euid.as_raw(), suid.as_raw())) }
345 #[cfg(any(target_os = "android", target_os = "linux"))]
347 pub(crate) fn setgid_thread(gid
: crate::process
::Gid
) -> io
::Result
<()> {
348 unsafe { syscall_ret(c::syscall(c::SYS_setgid, gid.as_raw())) }
351 #[cfg(any(target_os = "android", target_os = "linux"))]
353 pub(crate) fn setresgid_thread(
354 rgid
: crate::process
::Gid
,
355 egid
: crate::process
::Gid
,
356 sgid
: crate::process
::Gid
,
357 ) -> io
::Result
<()> {
358 #[cfg(any(target_arch = "x86", target_arch = "arm", target_arch = "sparc"))]
359 const SYS
: c
::c_long
= c
::SYS_setresgid32
as c
::c_long
;
360 #[cfg(not(any(target_arch = "x86", target_arch = "arm", target_arch = "sparc")))]
361 const SYS
: c
::c_long
= c
::SYS_setresgid
as c
::c_long
;
362 unsafe { syscall_ret(c::syscall(SYS, rgid.as_raw(), egid.as_raw(), sgid.as_raw())) }