diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:18:21 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:18:21 +0000 |
commit | 4e8199b572f2035b7749cba276ece3a26630d23e (patch) | |
tree | f09feeed6a0fe39d027b1908aa63ea6b35e4b631 /vendor/rustix/src/backend/linux_raw | |
parent | Adding upstream version 1.66.0+dfsg1. (diff) | |
download | rustc-4e8199b572f2035b7749cba276ece3a26630d23e.tar.xz rustc-4e8199b572f2035b7749cba276ece3a26630d23e.zip |
Adding upstream version 1.67.1+dfsg1.upstream/1.67.1+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
77 files changed, 11364 insertions, 116 deletions
diff --git a/vendor/rustix/src/imp/linux_raw/arch/inline/aarch64.rs b/vendor/rustix/src/backend/linux_raw/arch/inline/aarch64.rs index 7d33a4a52..0f4465d51 100644 --- a/vendor/rustix/src/imp/linux_raw/arch/inline/aarch64.rs +++ b/vendor/rustix/src/backend/linux_raw/arch/inline/aarch64.rs @@ -1,13 +1,15 @@ //! aarch64 Linux system calls. -use crate::imp::reg::{ArgReg, FromAsm, RetReg, SyscallNumber, ToAsm, A0, A1, A2, A3, A4, A5, R0}; +use crate::backend::reg::{ + ArgReg, FromAsm, RetReg, SyscallNumber, ToAsm, A0, A1, A2, A3, A4, A5, R0, +}; use core::arch::asm; #[cfg(target_pointer_width = "32")] compile_error!("arm64-ilp32 is not supported yet"); #[inline] -pub(in crate::imp) unsafe fn syscall0_readonly(nr: SyscallNumber<'_>) -> RetReg<R0> { +pub(in crate::backend) unsafe fn syscall0_readonly(nr: SyscallNumber<'_>) -> RetReg<R0> { let r0; asm!( "svc 0", @@ -19,7 +21,7 @@ pub(in crate::imp) unsafe fn syscall0_readonly(nr: SyscallNumber<'_>) -> RetReg< } #[inline] -pub(in crate::imp) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> RetReg<R0> { +pub(in crate::backend) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> RetReg<R0> { let r0; asm!( "svc 0", @@ -31,7 +33,7 @@ pub(in crate::imp) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) } #[inline] -pub(in crate::imp) unsafe fn syscall1_readonly( +pub(in crate::backend) unsafe fn syscall1_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, ) -> RetReg<R0> { @@ -46,7 +48,7 @@ pub(in crate::imp) unsafe fn syscall1_readonly( } #[inline] -pub(in crate::imp) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> ! { +pub(in crate::backend) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> ! { asm!( "svc 0", in("x8") nr.to_asm(), @@ -56,7 +58,7 @@ pub(in crate::imp) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg } #[inline] -pub(in crate::imp) unsafe fn syscall2( +pub(in crate::backend) unsafe fn syscall2( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -73,7 +75,7 @@ pub(in crate::imp) unsafe fn syscall2( } #[inline] -pub(in crate::imp) unsafe fn syscall2_readonly( +pub(in crate::backend) unsafe fn syscall2_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -90,7 +92,7 @@ pub(in crate::imp) unsafe fn syscall2_readonly( } #[inline] -pub(in crate::imp) unsafe fn syscall3( +pub(in crate::backend) unsafe fn syscall3( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -109,7 +111,7 @@ pub(in crate::imp) unsafe fn syscall3( } #[inline] -pub(in crate::imp) unsafe fn syscall3_readonly( +pub(in crate::backend) unsafe fn syscall3_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -128,7 +130,7 @@ pub(in crate::imp) unsafe fn syscall3_readonly( } #[inline] -pub(in crate::imp) unsafe fn syscall4( +pub(in crate::backend) unsafe fn syscall4( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -149,7 +151,7 @@ pub(in crate::imp) unsafe fn syscall4( } #[inline] -pub(in crate::imp) unsafe fn syscall4_readonly( +pub(in crate::backend) unsafe fn syscall4_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -170,7 +172,7 @@ pub(in crate::imp) unsafe fn syscall4_readonly( } #[inline] -pub(in crate::imp) unsafe fn syscall5( +pub(in crate::backend) unsafe fn syscall5( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -193,7 +195,7 @@ pub(in crate::imp) unsafe fn syscall5( } #[inline] -pub(in crate::imp) unsafe fn syscall5_readonly( +pub(in crate::backend) unsafe fn syscall5_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -216,7 +218,7 @@ pub(in crate::imp) unsafe fn syscall5_readonly( } #[inline] -pub(in crate::imp) unsafe fn syscall6( +pub(in crate::backend) unsafe fn syscall6( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -241,7 +243,7 @@ pub(in crate::imp) unsafe fn syscall6( } #[inline] -pub(in crate::imp) unsafe fn syscall6_readonly( +pub(in crate::backend) unsafe fn syscall6_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, diff --git a/vendor/rustix/src/backend/linux_raw/arch/inline/arm.rs b/vendor/rustix/src/backend/linux_raw/arch/inline/arm.rs new file mode 100644 index 000000000..9695c6028 --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/arch/inline/arm.rs @@ -0,0 +1,265 @@ +//! arm Linux system calls. + +use crate::backend::reg::{ + ArgReg, FromAsm, RetReg, SyscallNumber, ToAsm, A0, A1, A2, A3, A4, A5, R0, +}; +use core::arch::asm; + +#[inline] +pub(in crate::backend) unsafe fn syscall0_readonly(nr: SyscallNumber<'_>) -> RetReg<R0> { + let r0; + asm!( + "svc 0", + in("r7") nr.to_asm(), + lateout("r0") r0, + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> RetReg<R0> { + let r0; + asm!( + "svc 0", + in("r7") nr.to_asm(), + inlateout("r0") a0.to_asm() => r0, + options(nostack, preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall1_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, +) -> RetReg<R0> { + let r0; + asm!( + "svc 0", + in("r7") nr.to_asm(), + inlateout("r0") a0.to_asm() => r0, + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> ! { + asm!( + "svc 0", + in("r7") nr.to_asm(), + in("r0") a0.to_asm(), + options(noreturn) + ) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall2( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, +) -> RetReg<R0> { + let r0; + asm!( + "svc 0", + in("r7") nr.to_asm(), + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + options(nostack, preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall2_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, +) -> RetReg<R0> { + let r0; + asm!( + "svc 0", + in("r7") nr.to_asm(), + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall3( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, +) -> RetReg<R0> { + let r0; + asm!( + "svc 0", + in("r7") nr.to_asm(), + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + in("r2") a2.to_asm(), + options(nostack, preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall3_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, +) -> RetReg<R0> { + let r0; + asm!( + "svc 0", + in("r7") nr.to_asm(), + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + in("r2") a2.to_asm(), + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall4( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, +) -> RetReg<R0> { + let r0; + asm!( + "svc 0", + in("r7") nr.to_asm(), + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + in("r2") a2.to_asm(), + in("r3") a3.to_asm(), + options(nostack, preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall4_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, +) -> RetReg<R0> { + let r0; + asm!( + "svc 0", + in("r7") nr.to_asm(), + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + in("r2") a2.to_asm(), + in("r3") a3.to_asm(), + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall5( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, +) -> RetReg<R0> { + let r0; + asm!( + "svc 0", + in("r7") nr.to_asm(), + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + in("r2") a2.to_asm(), + in("r3") a3.to_asm(), + in("r4") a4.to_asm(), + options(nostack, preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall5_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, +) -> RetReg<R0> { + let r0; + asm!( + "svc 0", + in("r7") nr.to_asm(), + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + in("r2") a2.to_asm(), + in("r3") a3.to_asm(), + in("r4") a4.to_asm(), + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall6( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, + a5: ArgReg<'_, A5>, +) -> RetReg<R0> { + let r0; + asm!( + "svc 0", + in("r7") nr.to_asm(), + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + in("r2") a2.to_asm(), + in("r3") a3.to_asm(), + in("r4") a4.to_asm(), + in("r5") a5.to_asm(), + options(nostack, preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall6_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, + a5: ArgReg<'_, A5>, +) -> RetReg<R0> { + let r0; + asm!( + "svc 0", + in("r7") nr.to_asm(), + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + in("r2") a2.to_asm(), + in("r3") a3.to_asm(), + in("r4") a4.to_asm(), + in("r5") a5.to_asm(), + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} diff --git a/vendor/rustix/src/imp/linux_raw/arch/inline/mips.rs b/vendor/rustix/src/backend/linux_raw/arch/inline/mips.rs index 0f2b9d9d2..b39a16847 100644 --- a/vendor/rustix/src/imp/linux_raw/arch/inline/mips.rs +++ b/vendor/rustix/src/backend/linux_raw/arch/inline/mips.rs @@ -6,13 +6,13 @@ //! Mips-family platforms have a special calling convention for `__NR_pipe`, //! however we use `__NR_pipe2` instead to avoid having to implement it. -use crate::imp::reg::{ +use crate::backend::reg::{ ArgReg, FromAsm, RetReg, SyscallNumber, ToAsm, A0, A1, A2, A3, A4, A5, A6, R0, }; use core::arch::asm; #[inline] -pub(in crate::imp) unsafe fn syscall0_readonly(nr: SyscallNumber) -> RetReg<R0> { +pub(in crate::backend) unsafe fn syscall0_readonly(nr: SyscallNumber) -> RetReg<R0> { let x0; let err: usize; asm!( @@ -39,7 +39,7 @@ pub(in crate::imp) unsafe fn syscall0_readonly(nr: SyscallNumber) -> RetReg<R0> } #[inline] -pub(in crate::imp) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> RetReg<R0> { +pub(in crate::backend) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> RetReg<R0> { let x0; let err: usize; asm!( @@ -67,7 +67,7 @@ pub(in crate::imp) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) } #[inline] -pub(in crate::imp) unsafe fn syscall1_readonly( +pub(in crate::backend) unsafe fn syscall1_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, ) -> RetReg<R0> { @@ -98,7 +98,7 @@ pub(in crate::imp) unsafe fn syscall1_readonly( } #[inline] -pub(in crate::imp) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> ! { +pub(in crate::backend) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> ! { asm!( "syscall", in("$2" /*$v0*/) nr.to_asm(), @@ -108,7 +108,7 @@ pub(in crate::imp) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg } #[inline] -pub(in crate::imp) unsafe fn syscall2( +pub(in crate::backend) unsafe fn syscall2( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -141,7 +141,7 @@ pub(in crate::imp) unsafe fn syscall2( } #[inline] -pub(in crate::imp) unsafe fn syscall2_readonly( +pub(in crate::backend) unsafe fn syscall2_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -174,7 +174,7 @@ pub(in crate::imp) unsafe fn syscall2_readonly( } #[inline] -pub(in crate::imp) unsafe fn syscall3( +pub(in crate::backend) unsafe fn syscall3( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -209,7 +209,7 @@ pub(in crate::imp) unsafe fn syscall3( } #[inline] -pub(in crate::imp) unsafe fn syscall3_readonly( +pub(in crate::backend) unsafe fn syscall3_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -244,7 +244,7 @@ pub(in crate::imp) unsafe fn syscall3_readonly( } #[inline] -pub(in crate::imp) unsafe fn syscall4( +pub(in crate::backend) unsafe fn syscall4( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -280,7 +280,7 @@ pub(in crate::imp) unsafe fn syscall4( } #[inline] -pub(in crate::imp) unsafe fn syscall4_readonly( +pub(in crate::backend) unsafe fn syscall4_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -316,7 +316,7 @@ pub(in crate::imp) unsafe fn syscall4_readonly( } #[inline] -pub(in crate::imp) unsafe fn syscall5( +pub(in crate::backend) unsafe fn syscall5( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -359,7 +359,7 @@ pub(in crate::imp) unsafe fn syscall5( } #[inline] -pub(in crate::imp) unsafe fn syscall5_readonly( +pub(in crate::backend) unsafe fn syscall5_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -402,7 +402,7 @@ pub(in crate::imp) unsafe fn syscall5_readonly( } #[inline] -pub(in crate::imp) unsafe fn syscall6( +pub(in crate::backend) unsafe fn syscall6( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -448,7 +448,7 @@ pub(in crate::imp) unsafe fn syscall6( } #[inline] -pub(in crate::imp) unsafe fn syscall6_readonly( +pub(in crate::backend) unsafe fn syscall6_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -494,7 +494,7 @@ pub(in crate::imp) unsafe fn syscall6_readonly( } #[inline] -pub(in crate::imp) unsafe fn syscall7_readonly( +pub(in crate::backend) unsafe fn syscall7_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, diff --git a/vendor/rustix/src/imp/linux_raw/arch/inline/mips64.rs b/vendor/rustix/src/backend/linux_raw/arch/inline/mips64.rs index 36dd79316..d3c7d341f 100644 --- a/vendor/rustix/src/imp/linux_raw/arch/inline/mips64.rs +++ b/vendor/rustix/src/backend/linux_raw/arch/inline/mips64.rs @@ -6,11 +6,13 @@ //! Mips-family platforms have a special calling convention for `__NR_pipe`, //! however we use `__NR_pipe2` instead to avoid having to implement it. -use crate::imp::reg::{ArgReg, FromAsm, RetReg, SyscallNumber, ToAsm, A0, A1, A2, A3, A4, A5, R0}; +use crate::backend::reg::{ + ArgReg, FromAsm, RetReg, SyscallNumber, ToAsm, A0, A1, A2, A3, A4, A5, R0, +}; use core::arch::asm; #[inline] -pub(in crate::imp) unsafe fn syscall0_readonly(nr: SyscallNumber) -> RetReg<R0> { +pub(in crate::backend) unsafe fn syscall0_readonly(nr: SyscallNumber) -> RetReg<R0> { let x0; let err: usize; asm!( @@ -37,7 +39,7 @@ pub(in crate::imp) unsafe fn syscall0_readonly(nr: SyscallNumber) -> RetReg<R0> } #[inline] -pub(in crate::imp) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> RetReg<R0> { +pub(in crate::backend) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> RetReg<R0> { let x0; let err: usize; asm!( @@ -65,7 +67,7 @@ pub(in crate::imp) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) } #[inline] -pub(in crate::imp) unsafe fn syscall1_readonly( +pub(in crate::backend) unsafe fn syscall1_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, ) -> RetReg<R0> { @@ -96,7 +98,7 @@ pub(in crate::imp) unsafe fn syscall1_readonly( } #[inline] -pub(in crate::imp) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> ! { +pub(in crate::backend) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> ! { asm!( "syscall", in("$2" /*$v0*/) nr.to_asm(), @@ -106,7 +108,7 @@ pub(in crate::imp) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg } #[inline] -pub(in crate::imp) unsafe fn syscall2( +pub(in crate::backend) unsafe fn syscall2( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -139,7 +141,7 @@ pub(in crate::imp) unsafe fn syscall2( } #[inline] -pub(in crate::imp) unsafe fn syscall2_readonly( +pub(in crate::backend) unsafe fn syscall2_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -172,7 +174,7 @@ pub(in crate::imp) unsafe fn syscall2_readonly( } #[inline] -pub(in crate::imp) unsafe fn syscall3( +pub(in crate::backend) unsafe fn syscall3( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -207,7 +209,7 @@ pub(in crate::imp) unsafe fn syscall3( } #[inline] -pub(in crate::imp) unsafe fn syscall3_readonly( +pub(in crate::backend) unsafe fn syscall3_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -242,7 +244,7 @@ pub(in crate::imp) unsafe fn syscall3_readonly( } #[inline] -pub(in crate::imp) unsafe fn syscall4( +pub(in crate::backend) unsafe fn syscall4( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -278,7 +280,7 @@ pub(in crate::imp) unsafe fn syscall4( } #[inline] -pub(in crate::imp) unsafe fn syscall4_readonly( +pub(in crate::backend) unsafe fn syscall4_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -314,7 +316,7 @@ pub(in crate::imp) unsafe fn syscall4_readonly( } #[inline] -pub(in crate::imp) unsafe fn syscall5( +pub(in crate::backend) unsafe fn syscall5( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -351,7 +353,7 @@ pub(in crate::imp) unsafe fn syscall5( } #[inline] -pub(in crate::imp) unsafe fn syscall5_readonly( +pub(in crate::backend) unsafe fn syscall5_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -388,7 +390,7 @@ pub(in crate::imp) unsafe fn syscall5_readonly( } #[inline] -pub(in crate::imp) unsafe fn syscall6( +pub(in crate::backend) unsafe fn syscall6( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -426,7 +428,7 @@ pub(in crate::imp) unsafe fn syscall6( } #[inline] -pub(in crate::imp) unsafe fn syscall6_readonly( +pub(in crate::backend) unsafe fn syscall6_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, diff --git a/vendor/rustix/src/backend/linux_raw/arch/inline/mod.rs b/vendor/rustix/src/backend/linux_raw/arch/inline/mod.rs new file mode 100644 index 000000000..524c449d9 --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/arch/inline/mod.rs @@ -0,0 +1,18 @@ +//! Inline asm for making system calls. +//! +//! Compilers should really have intrinsics for making system calls. They're +//! much like regular calls, with custom calling conventions, and calling +//! conventions are otherwise the compiler's job. But for now, use inline asm. + +#[cfg_attr(target_arch = "aarch64", path = "aarch64.rs")] +#[cfg_attr(all(target_arch = "arm", not(thumb_mode)), path = "arm.rs")] +#[cfg_attr(all(target_arch = "arm", thumb_mode), path = "thumb.rs")] +#[cfg_attr(target_arch = "mips", path = "mips.rs")] +#[cfg_attr(target_arch = "mips64", path = "mips64.rs")] +#[cfg_attr(target_arch = "powerpc64", path = "powerpc64.rs")] +#[cfg_attr(target_arch = "riscv64", path = "riscv64.rs")] +#[cfg_attr(target_arch = "x86", path = "x86.rs")] +#[cfg_attr(target_arch = "x86_64", path = "x86_64.rs")] +mod target_arch; + +pub(in crate::backend) use self::target_arch::*; diff --git a/vendor/rustix/src/imp/linux_raw/arch/inline/powerpc64.rs b/vendor/rustix/src/backend/linux_raw/arch/inline/powerpc64.rs index 520bd4d79..8cca7dca7 100644 --- a/vendor/rustix/src/imp/linux_raw/arch/inline/powerpc64.rs +++ b/vendor/rustix/src/backend/linux_raw/arch/inline/powerpc64.rs @@ -9,11 +9,13 @@ //! check the flag and negate the error value to make PowerPC64 look like other //! architectures. -use crate::imp::reg::{ArgReg, FromAsm, RetReg, SyscallNumber, ToAsm, A0, A1, A2, A3, A4, A5, R0}; +use crate::backend::reg::{ + ArgReg, FromAsm, RetReg, SyscallNumber, ToAsm, A0, A1, A2, A3, A4, A5, R0, +}; use core::arch::asm; #[inline] -pub(in crate::imp) unsafe fn syscall0_readonly(nr: SyscallNumber) -> RetReg<R0> { +pub(in crate::backend) unsafe fn syscall0_readonly(nr: SyscallNumber) -> RetReg<R0> { let r0; asm!( "sc", @@ -38,7 +40,7 @@ pub(in crate::imp) unsafe fn syscall0_readonly(nr: SyscallNumber) -> RetReg<R0> } #[inline] -pub(in crate::imp) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> RetReg<R0> { +pub(in crate::backend) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> RetReg<R0> { let r0; asm!( "sc", @@ -63,7 +65,7 @@ pub(in crate::imp) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) } #[inline] -pub(in crate::imp) unsafe fn syscall1_readonly( +pub(in crate::backend) unsafe fn syscall1_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, ) -> RetReg<R0> { @@ -91,7 +93,7 @@ pub(in crate::imp) unsafe fn syscall1_readonly( } #[inline] -pub(in crate::imp) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> ! { +pub(in crate::backend) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> ! { asm!( "sc", in("r0") nr.to_asm(), @@ -101,7 +103,7 @@ pub(in crate::imp) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg } #[inline] -pub(in crate::imp) unsafe fn syscall2( +pub(in crate::backend) unsafe fn syscall2( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -130,7 +132,7 @@ pub(in crate::imp) unsafe fn syscall2( } #[inline] -pub(in crate::imp) unsafe fn syscall2_readonly( +pub(in crate::backend) unsafe fn syscall2_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -159,7 +161,7 @@ pub(in crate::imp) unsafe fn syscall2_readonly( } #[inline] -pub(in crate::imp) unsafe fn syscall3( +pub(in crate::backend) unsafe fn syscall3( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -189,7 +191,7 @@ pub(in crate::imp) unsafe fn syscall3( } #[inline] -pub(in crate::imp) unsafe fn syscall3_readonly( +pub(in crate::backend) unsafe fn syscall3_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -219,7 +221,7 @@ pub(in crate::imp) unsafe fn syscall3_readonly( } #[inline] -pub(in crate::imp) unsafe fn syscall4( +pub(in crate::backend) unsafe fn syscall4( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -250,7 +252,7 @@ pub(in crate::imp) unsafe fn syscall4( } #[inline] -pub(in crate::imp) unsafe fn syscall4_readonly( +pub(in crate::backend) unsafe fn syscall4_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -281,7 +283,7 @@ pub(in crate::imp) unsafe fn syscall4_readonly( } #[inline] -pub(in crate::imp) unsafe fn syscall5( +pub(in crate::backend) unsafe fn syscall5( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -313,7 +315,7 @@ pub(in crate::imp) unsafe fn syscall5( } #[inline] -pub(in crate::imp) unsafe fn syscall5_readonly( +pub(in crate::backend) unsafe fn syscall5_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -345,7 +347,7 @@ pub(in crate::imp) unsafe fn syscall5_readonly( } #[inline] -pub(in crate::imp) unsafe fn syscall6( +pub(in crate::backend) unsafe fn syscall6( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -378,7 +380,7 @@ pub(in crate::imp) unsafe fn syscall6( } #[inline] -pub(in crate::imp) unsafe fn syscall6_readonly( +pub(in crate::backend) unsafe fn syscall6_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, diff --git a/vendor/rustix/src/imp/linux_raw/arch/inline/riscv64.rs b/vendor/rustix/src/backend/linux_raw/arch/inline/riscv64.rs index 3ed36a16c..b1e306266 100644 --- a/vendor/rustix/src/imp/linux_raw/arch/inline/riscv64.rs +++ b/vendor/rustix/src/backend/linux_raw/arch/inline/riscv64.rs @@ -1,10 +1,12 @@ //! riscv64 Linux system calls. -use crate::imp::reg::{ArgReg, FromAsm, RetReg, SyscallNumber, ToAsm, A0, A1, A2, A3, A4, A5, R0}; +use crate::backend::reg::{ + ArgReg, FromAsm, RetReg, SyscallNumber, ToAsm, A0, A1, A2, A3, A4, A5, R0, +}; use core::arch::asm; #[inline] -pub(in crate::imp) unsafe fn syscall0_readonly(nr: SyscallNumber<'_>) -> RetReg<R0> { +pub(in crate::backend) unsafe fn syscall0_readonly(nr: SyscallNumber<'_>) -> RetReg<R0> { let r0; asm!( "ecall", @@ -16,7 +18,7 @@ pub(in crate::imp) unsafe fn syscall0_readonly(nr: SyscallNumber<'_>) -> RetReg< } #[inline] -pub(in crate::imp) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> RetReg<R0> { +pub(in crate::backend) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> RetReg<R0> { let r0; asm!( "ecall", @@ -28,7 +30,7 @@ pub(in crate::imp) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) } #[inline] -pub(in crate::imp) unsafe fn syscall1_readonly( +pub(in crate::backend) unsafe fn syscall1_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, ) -> RetReg<R0> { @@ -43,7 +45,7 @@ pub(in crate::imp) unsafe fn syscall1_readonly( } #[inline] -pub(in crate::imp) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> ! { +pub(in crate::backend) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> ! { asm!( "ecall", in("a7") nr.to_asm(), @@ -53,7 +55,7 @@ pub(in crate::imp) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg } #[inline] -pub(in crate::imp) unsafe fn syscall2( +pub(in crate::backend) unsafe fn syscall2( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -70,7 +72,7 @@ pub(in crate::imp) unsafe fn syscall2( } #[inline] -pub(in crate::imp) unsafe fn syscall2_readonly( +pub(in crate::backend) unsafe fn syscall2_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -87,7 +89,7 @@ pub(in crate::imp) unsafe fn syscall2_readonly( } #[inline] -pub(in crate::imp) unsafe fn syscall3( +pub(in crate::backend) unsafe fn syscall3( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -106,7 +108,7 @@ pub(in crate::imp) unsafe fn syscall3( } #[inline] -pub(in crate::imp) unsafe fn syscall3_readonly( +pub(in crate::backend) unsafe fn syscall3_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -125,7 +127,7 @@ pub(in crate::imp) unsafe fn syscall3_readonly( } #[inline] -pub(in crate::imp) unsafe fn syscall4( +pub(in crate::backend) unsafe fn syscall4( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -146,7 +148,7 @@ pub(in crate::imp) unsafe fn syscall4( } #[inline] -pub(in crate::imp) unsafe fn syscall4_readonly( +pub(in crate::backend) unsafe fn syscall4_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -167,7 +169,7 @@ pub(in crate::imp) unsafe fn syscall4_readonly( } #[inline] -pub(in crate::imp) unsafe fn syscall5( +pub(in crate::backend) unsafe fn syscall5( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -190,7 +192,7 @@ pub(in crate::imp) unsafe fn syscall5( } #[inline] -pub(in crate::imp) unsafe fn syscall5_readonly( +pub(in crate::backend) unsafe fn syscall5_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -213,7 +215,7 @@ pub(in crate::imp) unsafe fn syscall5_readonly( } #[inline] -pub(in crate::imp) unsafe fn syscall6( +pub(in crate::backend) unsafe fn syscall6( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -238,7 +240,7 @@ pub(in crate::imp) unsafe fn syscall6( } #[inline] -pub(in crate::imp) unsafe fn syscall6_readonly( +pub(in crate::backend) unsafe fn syscall6_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, diff --git a/vendor/rustix/src/backend/linux_raw/arch/inline/thumb.rs b/vendor/rustix/src/backend/linux_raw/arch/inline/thumb.rs new file mode 100644 index 000000000..398a73dfe --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/arch/inline/thumb.rs @@ -0,0 +1,322 @@ +//! arm Linux system calls, using thumb-mode. +//! +//! In thumb-mode, r7 is the frame pointer and is not permitted to be used in +//! an inline asm operand, so we have to use a different register and copy it +//! into r7 inside the inline asm. + +use crate::backend::reg::{ + ArgReg, FromAsm, RetReg, SyscallNumber, ToAsm, A0, A1, A2, A3, A4, A5, R0, +}; +use core::arch::asm; + +#[inline] +pub(in crate::backend) unsafe fn syscall0_readonly(nr: SyscallNumber<'_>) -> RetReg<R0> { + let r0; + asm!( + "mov {tmp}, r7", + "mov r7, {nr}", + "svc 0", + "mov r7, {tmp}", + nr = in(reg) nr.to_asm(), + tmp = out(reg) _, + lateout("r0") r0, + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> RetReg<R0> { + let r0; + asm!( + "mov {tmp}, r7", + "mov r7, {nr}", + "svc 0", + "mov r7, {tmp}", + nr = in(reg) nr.to_asm(), + tmp = out(reg) _, + inlateout("r0") a0.to_asm() => r0, + options(nostack, preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall1_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, +) -> RetReg<R0> { + let r0; + asm!( + "mov {tmp}, r7", + "mov r7, {nr}", + "svc 0", + "mov r7, {tmp}", + nr = in(reg) nr.to_asm(), + tmp = out(reg) _, + inlateout("r0") a0.to_asm() => r0, + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> ! { + asm!( + "mov r7, {nr}", + "svc 0", + nr = in(reg) nr.to_asm(), + in("r0") a0.to_asm(), + options(noreturn) + ) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall2( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, +) -> RetReg<R0> { + let r0; + asm!( + "mov {tmp}, r7", + "mov r7, {nr}", + "svc 0", + "mov r7, {tmp}", + nr = in(reg) nr.to_asm(), + tmp = out(reg) _, + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + options(nostack, preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall2_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, +) -> RetReg<R0> { + let r0; + asm!( + "mov {tmp}, r7", + "mov r7, {nr}", + "svc 0", + "mov r7, {tmp}", + nr = in(reg) nr.to_asm(), + tmp = out(reg) _, + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall3( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, +) -> RetReg<R0> { + let r0; + asm!( + "mov {tmp}, r7", + "mov r7, {nr}", + "svc 0", + "mov r7, {tmp}", + nr = in(reg) nr.to_asm(), + tmp = out(reg) _, + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + in("r2") a2.to_asm(), + options(nostack, preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall3_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, +) -> RetReg<R0> { + let r0; + asm!( + "mov {tmp}, r7", + "mov r7, {nr}", + "svc 0", + "mov r7, {tmp}", + nr = in(reg) nr.to_asm(), + tmp = out(reg) _, + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + in("r2") a2.to_asm(), + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall4( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, +) -> RetReg<R0> { + let r0; + asm!( + "mov {tmp}, r7", + "mov r7, {nr}", + "svc 0", + "mov r7, {tmp}", + nr = in(reg) nr.to_asm(), + tmp = out(reg) _, + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + in("r2") a2.to_asm(), + in("r3") a3.to_asm(), + options(nostack, preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall4_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, +) -> RetReg<R0> { + let r0; + asm!( + "mov {tmp}, r7", + "mov r7, {nr}", + "svc 0", + "mov r7, {tmp}", + nr = in(reg) nr.to_asm(), + tmp = out(reg) _, + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + in("r2") a2.to_asm(), + in("r3") a3.to_asm(), + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall5( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, +) -> RetReg<R0> { + let r0; + asm!( + "mov {tmp}, r7", + "mov r7, {nr}", + "svc 0", + "mov r7, {tmp}", + nr = in(reg) nr.to_asm(), + tmp = out(reg) _, + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + in("r2") a2.to_asm(), + in("r3") a3.to_asm(), + in("r4") a4.to_asm(), + options(nostack, preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall5_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, +) -> RetReg<R0> { + let r0; + asm!( + "mov {tmp}, r7", + "mov r7, {nr}", + "svc 0", + "mov r7, {tmp}", + nr = in(reg) nr.to_asm(), + tmp = out(reg) _, + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + in("r2") a2.to_asm(), + in("r3") a3.to_asm(), + in("r4") a4.to_asm(), + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall6( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, + a5: ArgReg<'_, A5>, +) -> RetReg<R0> { + let r0; + asm!( + "mov {tmp}, r7", + "mov r7, {nr}", + "svc 0", + "mov r7, {tmp}", + nr = in(reg) nr.to_asm(), + tmp = out(reg) _, + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + in("r2") a2.to_asm(), + in("r3") a3.to_asm(), + in("r4") a4.to_asm(), + in("r5") a5.to_asm(), + options(nostack, preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall6_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, + a5: ArgReg<'_, A5>, +) -> RetReg<R0> { + let r0; + asm!( + "mov {tmp}, r7", + "mov r7, {nr}", + "svc 0", + "mov r7, {tmp}", + nr = in(reg) nr.to_asm(), + tmp = out(reg) _, + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + in("r2") a2.to_asm(), + in("r3") a3.to_asm(), + in("r4") a4.to_asm(), + in("r5") a5.to_asm(), + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} diff --git a/vendor/rustix/src/backend/linux_raw/arch/inline/x86.rs b/vendor/rustix/src/backend/linux_raw/arch/inline/x86.rs new file mode 100644 index 000000000..8e115148d --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/arch/inline/x86.rs @@ -0,0 +1,494 @@ +//! 32-bit x86 Linux system calls. +//! +//! There are two forms; `indirect_*` which take a callee, which allow calling +//! through the vDSO when possible, and plain forms, which use the `int 0x80` +//! instruction. +//! +//! Most `rustix` syscalls use the vsyscall mechanism rather than going using +//! `int 0x80` sequences. + +#![allow(dead_code)] + +use crate::backend::reg::{ + ArgReg, FromAsm, RetReg, SyscallNumber, ToAsm, A0, A1, A2, A3, A4, A5, R0, +}; +use crate::backend::vdso_wrappers::SyscallType; +use core::arch::asm; + +#[inline] +pub(in crate::backend) unsafe fn indirect_syscall0( + callee: SyscallType, + nr: SyscallNumber<'_>, +) -> RetReg<R0> { + let r0; + asm!( + "call {callee}", + callee = in(reg) callee, + inlateout("eax") nr.to_asm() => r0, + options(preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn indirect_syscall1( + callee: SyscallType, + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, +) -> RetReg<R0> { + let r0; + asm!( + "call {callee}", + callee = in(reg) callee, + inlateout("eax") nr.to_asm() => r0, + in("ebx") a0.to_asm(), + options(preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn indirect_syscall1_noreturn( + callee: SyscallType, + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, +) -> ! { + asm!( + "call {callee}", + callee = in(reg) callee, + in("eax") nr.to_asm(), + in("ebx") a0.to_asm(), + options(noreturn) + ) +} + +#[inline] +pub(in crate::backend) unsafe fn indirect_syscall2( + callee: SyscallType, + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, +) -> RetReg<R0> { + let r0; + asm!( + "call {callee}", + callee = in(reg) callee, + inlateout("eax") nr.to_asm() => r0, + in("ebx") a0.to_asm(), + in("ecx") a1.to_asm(), + options(preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn indirect_syscall3( + callee: SyscallType, + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, +) -> RetReg<R0> { + let r0; + asm!( + "call {callee}", + callee = in(reg) callee, + inlateout("eax") nr.to_asm() => r0, + in("ebx") a0.to_asm(), + in("ecx") a1.to_asm(), + in("edx") a2.to_asm(), + options(preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn indirect_syscall4( + callee: SyscallType, + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, +) -> RetReg<R0> { + let r0; + // a3 should go in esi, but `asm!` won't let us use it as an operand. + // temporarily swap it into place, and then swap it back afterward. + // + // We hard-code the callee operand to use edi instead of `in(reg)` because + // even though we can't name esi as an operand, the compiler can use esi to + // satisfy `in(reg)`. + asm!( + "xchg esi, {a3}", + "call edi", + "xchg esi, {a3}", + a3 = in(reg) a3.to_asm(), + in("edi") callee, + inlateout("eax") nr.to_asm() => r0, + in("ebx") a0.to_asm(), + in("ecx") a1.to_asm(), + in("edx") a2.to_asm(), + options(preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn indirect_syscall5( + callee: SyscallType, + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, +) -> RetReg<R0> { + let r0; + // Oof. a3 should go in esi, and `asm!` won't let us use that register as + // an operand. And we can't request stack slots. And there are no other + // registers free. Use eax as a temporary pointer to a slice, since it + // gets clobbered as the return value anyway. + asm!( + "push esi", + "push DWORD PTR [eax + 0]", + "mov esi, DWORD PTR [eax + 4]", + "mov eax, DWORD PTR [eax + 8]", + "call DWORD PTR [esp]", + "pop esi", + "pop esi", + inout("eax") &[callee as _, a3.to_asm(), nr.to_asm()] => r0, + in("ebx") a0.to_asm(), + in("ecx") a1.to_asm(), + in("edx") a2.to_asm(), + in("edi") a4.to_asm(), + options(preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[allow(clippy::too_many_arguments)] +#[inline] +pub(in crate::backend) unsafe fn indirect_syscall6( + callee: SyscallType, + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, + a5: ArgReg<'_, A5>, +) -> RetReg<R0> { + let r0; + // Oof again. a3 should go in esi, and a5 should go in ebp, and `asm!` + // won't let us use either of those registers as operands. And we can't + // request stack slots. And there are no other registers free. Use eax as a + // temporary pointer to a slice, since it gets clobbered as the return + // value anyway. + // + // This is another reason that syscalls should be compiler intrinsics + // rather than inline asm. + asm!( + "push ebp", + "push esi", + "push DWORD PTR [eax + 0]", + "mov esi, DWORD PTR [eax + 4]", + "mov ebp, DWORD PTR [eax + 8]", + "mov eax, DWORD PTR [eax + 12]", + "call DWORD PTR [esp]", + "pop esi", + "pop esi", + "pop ebp", + inout("eax") &[callee as _, a3.to_asm(), a5.to_asm(), nr.to_asm()] => r0, + in("ebx") a0.to_asm(), + in("ecx") a1.to_asm(), + in("edx") a2.to_asm(), + in("edi") a4.to_asm(), + options(preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall0_readonly(nr: SyscallNumber<'_>) -> RetReg<R0> { + let r0; + asm!( + "int $$0x80", + inlateout("eax") nr.to_asm() => r0, + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> RetReg<R0> { + let r0; + asm!( + "int $$0x80", + inlateout("eax") nr.to_asm() => r0, + in("ebx") a0.to_asm(), + options(nostack, preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall1_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, +) -> RetReg<R0> { + let r0; + asm!( + "int $$0x80", + inlateout("eax") nr.to_asm() => r0, + in("ebx") a0.to_asm(), + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> ! { + asm!( + "int $$0x80", + in("eax") nr.to_asm(), + in("ebx") a0.to_asm(), + options(noreturn) + ) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall2( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, +) -> RetReg<R0> { + let r0; + asm!( + "int $$0x80", + inlateout("eax") nr.to_asm() => r0, + in("ebx") a0.to_asm(), + in("ecx") a1.to_asm(), + options(nostack, preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall2_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, +) -> RetReg<R0> { + let r0; + asm!( + "int $$0x80", + inlateout("eax") nr.to_asm() => r0, + in("ebx") a0.to_asm(), + in("ecx") a1.to_asm(), + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall3( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, +) -> RetReg<R0> { + let r0; + asm!( + "int $$0x80", + inlateout("eax") nr.to_asm() => r0, + in("ebx") a0.to_asm(), + in("ecx") a1.to_asm(), + in("edx") a2.to_asm(), + options(nostack, preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall3_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, +) -> RetReg<R0> { + let r0; + asm!( + "int $$0x80", + inlateout("eax") nr.to_asm() => r0, + in("ebx") a0.to_asm(), + in("ecx") a1.to_asm(), + in("edx") a2.to_asm(), + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall4( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, +) -> RetReg<R0> { + let r0; + // a3 should go in esi, but `asm!` won't let us use it as an operand. + // Temporarily swap it into place, and then swap it back afterward. + asm!( + "xchg esi, {a3}", + "int $$0x80", + "xchg esi, {a3}", + a3 = in(reg) a3.to_asm(), + inlateout("eax") nr.to_asm() => r0, + in("ebx") a0.to_asm(), + in("ecx") a1.to_asm(), + in("edx") a2.to_asm(), + options(nostack, preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall4_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, +) -> RetReg<R0> { + let r0; + asm!( + "xchg esi, {a3}", + "int $$0x80", + "xchg esi, {a3}", + a3 = in(reg) a3.to_asm(), + inlateout("eax") nr.to_asm() => r0, + in("ebx") a0.to_asm(), + in("ecx") a1.to_asm(), + in("edx") a2.to_asm(), + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall5( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, +) -> RetReg<R0> { + let r0; + // As in `syscall4`, use xchg to handle a3. a4 should go in edi, and we can + // use that register as an operand. Unlike in `indirect_syscall5`, we don't + // have a `callee` operand taking up a register, so we have enough + // registers and don't need to use a slice. + asm!( + "xchg esi, {a3}", + "int $$0x80", + "xchg esi, {a3}", + a3 = in(reg) a3.to_asm(), + inlateout("eax") nr.to_asm() => r0, + in("ebx") a0.to_asm(), + in("ecx") a1.to_asm(), + in("edx") a2.to_asm(), + in("edi") a4.to_asm(), + options(nostack, preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall5_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, +) -> RetReg<R0> { + let r0; + // See the comments in `syscall5`. + asm!( + "xchg esi, {a3}", + "int $$0x80", + "xchg esi, {a3}", + a3 = in(reg) a3.to_asm(), + inlateout("eax") nr.to_asm() => r0, + in("ebx") a0.to_asm(), + in("ecx") a1.to_asm(), + in("edx") a2.to_asm(), + in("edi") a4.to_asm(), + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall6( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, + a5: ArgReg<'_, A5>, +) -> RetReg<R0> { + let r0; + // See the comments in `indirect_syscall6`. + asm!( + "push ebp", + "push esi", + "mov esi, DWORD PTR [eax + 0]", + "mov ebp, DWORD PTR [eax + 4]", + "mov eax, DWORD PTR [eax + 8]", + "int $$0x80", + "pop esi", + "pop ebp", + inout("eax") &[a3.to_asm(), a5.to_asm(), nr.to_asm()] => r0, + in("ebx") a0.to_asm(), + in("ecx") a1.to_asm(), + in("edx") a2.to_asm(), + in("edi") a4.to_asm(), + options(preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall6_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, + a5: ArgReg<'_, A5>, +) -> RetReg<R0> { + let r0; + // See the comments in `indirect_syscall6`. + asm!( + "push ebp", + "push esi", + "mov esi, DWORD PTR [eax + 0]", + "mov ebp, DWORD PTR [eax + 4]", + "mov eax, DWORD PTR [eax + 8]", + "int $$0x80", + "pop esi", + "pop ebp", + inout("eax") &[a3.to_asm(), a5.to_asm(), nr.to_asm()] => r0, + in("ebx") a0.to_asm(), + in("ecx") a1.to_asm(), + in("edx") a2.to_asm(), + in("edi") a4.to_asm(), + options(preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} diff --git a/vendor/rustix/src/imp/linux_raw/arch/inline/x86_64.rs b/vendor/rustix/src/backend/linux_raw/arch/inline/x86_64.rs index 75d6124f7..084f5fee4 100644 --- a/vendor/rustix/src/imp/linux_raw/arch/inline/x86_64.rs +++ b/vendor/rustix/src/backend/linux_raw/arch/inline/x86_64.rs @@ -1,13 +1,15 @@ //! x86-64 Linux system calls. -use crate::imp::reg::{ArgReg, FromAsm, RetReg, SyscallNumber, ToAsm, A0, A1, A2, A3, A4, A5, R0}; +use crate::backend::reg::{ + ArgReg, FromAsm, RetReg, SyscallNumber, ToAsm, A0, A1, A2, A3, A4, A5, R0, +}; use core::arch::asm; #[cfg(target_pointer_width = "32")] compile_error!("x32 is not yet supported"); #[inline] -pub(in crate::imp) unsafe fn syscall0_readonly(nr: SyscallNumber<'_>) -> RetReg<R0> { +pub(in crate::backend) unsafe fn syscall0_readonly(nr: SyscallNumber<'_>) -> RetReg<R0> { let r0; asm!( "syscall", @@ -20,7 +22,7 @@ pub(in crate::imp) unsafe fn syscall0_readonly(nr: SyscallNumber<'_>) -> RetReg< } #[inline] -pub(in crate::imp) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> RetReg<R0> { +pub(in crate::backend) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> RetReg<R0> { let r0; asm!( "syscall", @@ -34,7 +36,7 @@ pub(in crate::imp) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) } #[inline] -pub(in crate::imp) unsafe fn syscall1_readonly( +pub(in crate::backend) unsafe fn syscall1_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, ) -> RetReg<R0> { @@ -51,7 +53,7 @@ pub(in crate::imp) unsafe fn syscall1_readonly( } #[inline] -pub(in crate::imp) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> ! { +pub(in crate::backend) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> ! { asm!( "syscall", in("rax") nr.to_asm(), @@ -61,7 +63,7 @@ pub(in crate::imp) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg } #[inline] -pub(in crate::imp) unsafe fn syscall2( +pub(in crate::backend) unsafe fn syscall2( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -80,7 +82,7 @@ pub(in crate::imp) unsafe fn syscall2( } #[inline] -pub(in crate::imp) unsafe fn syscall2_readonly( +pub(in crate::backend) unsafe fn syscall2_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -99,7 +101,7 @@ pub(in crate::imp) unsafe fn syscall2_readonly( } #[inline] -pub(in crate::imp) unsafe fn syscall3( +pub(in crate::backend) unsafe fn syscall3( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -120,7 +122,7 @@ pub(in crate::imp) unsafe fn syscall3( } #[inline] -pub(in crate::imp) unsafe fn syscall3_readonly( +pub(in crate::backend) unsafe fn syscall3_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -141,7 +143,7 @@ pub(in crate::imp) unsafe fn syscall3_readonly( } #[inline] -pub(in crate::imp) unsafe fn syscall4( +pub(in crate::backend) unsafe fn syscall4( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -164,7 +166,7 @@ pub(in crate::imp) unsafe fn syscall4( } #[inline] -pub(in crate::imp) unsafe fn syscall4_readonly( +pub(in crate::backend) unsafe fn syscall4_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -187,7 +189,7 @@ pub(in crate::imp) unsafe fn syscall4_readonly( } #[inline] -pub(in crate::imp) unsafe fn syscall5( +pub(in crate::backend) unsafe fn syscall5( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -212,7 +214,7 @@ pub(in crate::imp) unsafe fn syscall5( } #[inline] -pub(in crate::imp) unsafe fn syscall5_readonly( +pub(in crate::backend) unsafe fn syscall5_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -237,7 +239,7 @@ pub(in crate::imp) unsafe fn syscall5_readonly( } #[inline] -pub(in crate::imp) unsafe fn syscall6( +pub(in crate::backend) unsafe fn syscall6( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -264,7 +266,7 @@ pub(in crate::imp) unsafe fn syscall6( } #[inline] -pub(in crate::imp) unsafe fn syscall6_readonly( +pub(in crate::backend) unsafe fn syscall6_readonly( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, diff --git a/vendor/rustix/src/backend/linux_raw/arch/mod.rs b/vendor/rustix/src/backend/linux_raw/arch/mod.rs new file mode 100644 index 000000000..e13f675fd --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/arch/mod.rs @@ -0,0 +1,222 @@ +//! Architecture-specific syscall code. +//! +//! `rustix` has inline assembly sequences using `asm!`, but that requires +//! nightly Rust, so it also has out-of-line ("outline") assembly sequences +//! in .s files. And 32-bit x86 is special (see comments below). +//! +//! This module also has a `choose` submodule which chooses a scheme and is +//! what most of the `rustix` syscalls use. +//! +//! # Safety +//! +//! This contains the inline `asm` statements performing the syscall +//! instructions and FFI declarations declaring the out-of-line ("outline") +//! syscall instructions. + +#![allow(unsafe_code)] +#![cfg_attr(not(feature = "all-apis"), allow(unused_imports))] +// We'll use as many arguments as syscalls need. +#![allow(clippy::too_many_arguments)] + +// When inline asm is available, use it. Otherwise, use out-of-line asm. These +// functions always use the machine's syscall instruction, even when it isn't +// the fastest option available. +#[cfg_attr(asm, path = "inline/mod.rs")] +#[cfg_attr(not(asm), path = "outline/mod.rs")] +pub(in crate::backend) mod asm; + +// On most architectures, the architecture syscall instruction is fast, so use +// it directly. +#[cfg(any( + target_arch = "arm", + target_arch = "aarch64", + target_arch = "mips", + target_arch = "mips64", + target_arch = "powerpc64", + target_arch = "riscv64", + target_arch = "x86_64", +))] +pub(in crate::backend) use self::asm as choose; + +// On 32-bit x86, use vDSO wrappers for all syscalls. We could use the +// architecture syscall instruction (`int 0x80`), but the vDSO kernel_vsyscall +// mechanism is much faster. +#[cfg(target_arch = "x86")] +pub(in crate::backend) use super::vdso_wrappers::x86_via_vdso as choose; + +// This would be the code for always using `int 0x80` on 32-bit x86. +//#[cfg(target_arch = "x86")] +//pub(in crate::backend) use self::asm as choose; + +// Macros for invoking system calls. +// +// These factor out: +// - Calling `nr` on the syscall number to convert it into `SyscallNumber`. +// - Calling `.into()` on each of the arguments to convert them into `ArgReg`. +// - Qualifying the `syscall*` and `__NR_*` identifiers. +// - Counting the number of arguments. +macro_rules! syscall { + ($nr:ident) => { + $crate::backend::arch::choose::syscall0($crate::backend::reg::nr( + linux_raw_sys::general::$nr, + )) + }; + + ($nr:ident, $a0:expr) => { + $crate::backend::arch::choose::syscall1( + $crate::backend::reg::nr(linux_raw_sys::general::$nr), + $a0.into(), + ) + }; + + ($nr:ident, $a0:expr, $a1:expr) => { + $crate::backend::arch::choose::syscall2( + $crate::backend::reg::nr(linux_raw_sys::general::$nr), + $a0.into(), + $a1.into(), + ) + }; + + ($nr:ident, $a0:expr, $a1:expr, $a2:expr) => { + $crate::backend::arch::choose::syscall3( + $crate::backend::reg::nr(linux_raw_sys::general::$nr), + $a0.into(), + $a1.into(), + $a2.into(), + ) + }; + + ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr) => { + $crate::backend::arch::choose::syscall4( + $crate::backend::reg::nr(linux_raw_sys::general::$nr), + $a0.into(), + $a1.into(), + $a2.into(), + $a3.into(), + ) + }; + + ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr) => { + $crate::backend::arch::choose::syscall5( + $crate::backend::reg::nr(linux_raw_sys::general::$nr), + $a0.into(), + $a1.into(), + $a2.into(), + $a3.into(), + $a4.into(), + ) + }; + + ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr) => { + $crate::backend::arch::choose::syscall6( + $crate::backend::reg::nr(linux_raw_sys::general::$nr), + $a0.into(), + $a1.into(), + $a2.into(), + $a3.into(), + $a4.into(), + $a5.into(), + ) + }; + + ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr, $a6:expr) => { + $crate::backend::arch::choose::syscall7( + $crate::backend::reg::nr(linux_raw_sys::general::$nr), + $a0.into(), + $a1.into(), + $a2.into(), + $a3.into(), + $a4.into(), + $a5.into(), + $a6.into(), + ) + }; +} + +macro_rules! syscall_readonly { + ($nr:ident) => { + $crate::backend::arch::choose::syscall0_readonly($crate::backend::reg::nr( + linux_raw_sys::general::$nr, + )) + }; + + ($nr:ident, $a0:expr) => { + $crate::backend::arch::choose::syscall1_readonly( + $crate::backend::reg::nr(linux_raw_sys::general::$nr), + $a0.into(), + ) + }; + + ($nr:ident, $a0:expr, $a1:expr) => { + $crate::backend::arch::choose::syscall2_readonly( + $crate::backend::reg::nr(linux_raw_sys::general::$nr), + $a0.into(), + $a1.into(), + ) + }; + + ($nr:ident, $a0:expr, $a1:expr, $a2:expr) => { + $crate::backend::arch::choose::syscall3_readonly( + $crate::backend::reg::nr(linux_raw_sys::general::$nr), + $a0.into(), + $a1.into(), + $a2.into(), + ) + }; + + ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr) => { + $crate::backend::arch::choose::syscall4_readonly( + $crate::backend::reg::nr(linux_raw_sys::general::$nr), + $a0.into(), + $a1.into(), + $a2.into(), + $a3.into(), + ) + }; + + ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr) => { + $crate::backend::arch::choose::syscall5_readonly( + $crate::backend::reg::nr(linux_raw_sys::general::$nr), + $a0.into(), + $a1.into(), + $a2.into(), + $a3.into(), + $a4.into(), + ) + }; + + ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr) => { + $crate::backend::arch::choose::syscall6_readonly( + $crate::backend::reg::nr(linux_raw_sys::general::$nr), + $a0.into(), + $a1.into(), + $a2.into(), + $a3.into(), + $a4.into(), + $a5.into(), + ) + }; + + ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr, $a6:expr) => { + $crate::backend::arch::choose::syscall7_readonly( + $crate::backend::reg::nr(linux_raw_sys::general::$nr), + $a0.into(), + $a1.into(), + $a2.into(), + $a3.into(), + $a4.into(), + $a5.into(), + $a6.into(), + ) + }; +} + +#[cfg(feature = "runtime")] +macro_rules! syscall_noreturn { + ($nr:ident, $a0:expr) => { + $crate::backend::arch::choose::syscall1_noreturn( + $crate::backend::reg::nr(linux_raw_sys::general::$nr), + $a0.into(), + ) + }; +} diff --git a/vendor/rustix/src/imp/linux_raw/arch/outline/aarch64.s b/vendor/rustix/src/backend/linux_raw/arch/outline/aarch64.s index 1fad2fa6d..1fad2fa6d 100644 --- a/vendor/rustix/src/imp/linux_raw/arch/outline/aarch64.s +++ b/vendor/rustix/src/backend/linux_raw/arch/outline/aarch64.s diff --git a/vendor/rustix/src/imp/linux_raw/arch/outline/arm.s b/vendor/rustix/src/backend/linux_raw/arch/outline/arm.s index 7001686f1..7001686f1 100644 --- a/vendor/rustix/src/imp/linux_raw/arch/outline/arm.s +++ b/vendor/rustix/src/backend/linux_raw/arch/outline/arm.s diff --git a/vendor/rustix/src/imp/linux_raw/arch/outline/mips.s b/vendor/rustix/src/backend/linux_raw/arch/outline/mips.s index ab1bbfa2d..ab1bbfa2d 100644 --- a/vendor/rustix/src/imp/linux_raw/arch/outline/mips.s +++ b/vendor/rustix/src/backend/linux_raw/arch/outline/mips.s diff --git a/vendor/rustix/src/imp/linux_raw/arch/outline/mips64.s b/vendor/rustix/src/backend/linux_raw/arch/outline/mips64.s index 3c5e76e36..3c5e76e36 100644 --- a/vendor/rustix/src/imp/linux_raw/arch/outline/mips64.s +++ b/vendor/rustix/src/backend/linux_raw/arch/outline/mips64.s diff --git a/vendor/rustix/src/backend/linux_raw/arch/outline/mod.rs b/vendor/rustix/src/backend/linux_raw/arch/outline/mod.rs new file mode 100644 index 000000000..a6a5f270d --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/arch/outline/mod.rs @@ -0,0 +1,33 @@ +//! Declare functions defined in out-of-line ("outline") asm files. +//! +//! Kernel calling conventions differ from userspace calling conventions, +//! so we also define inline function wrappers which reorder the arguments +//! so that they match with the kernel convention as closely as possible, +//! to minimize the amount of out-of-line code we need. + +#[cfg(target_arch = "x86")] +mod x86; +// For these architectures, pass the `nr` argument last. +#[cfg(any( + target_arch = "arm", + target_arch = "aarch64", + target_arch = "mips", + target_arch = "mips64", + target_arch = "powerpc64", + target_arch = "riscv64", + target_arch = "x86_64", +))] +mod nr_last; + +#[cfg(any( + target_arch = "arm", + target_arch = "aarch64", + target_arch = "mips", + target_arch = "mips64", + target_arch = "powerpc64", + target_arch = "riscv64", + target_arch = "x86_64", +))] +pub(in crate::backend) use nr_last::*; +#[cfg(target_arch = "x86")] +pub(in crate::backend) use x86::*; diff --git a/vendor/rustix/src/imp/linux_raw/arch/outline/nr_last.rs b/vendor/rustix/src/backend/linux_raw/arch/outline/nr_last.rs index fdcd11021..4af64d6c4 100644 --- a/vendor/rustix/src/imp/linux_raw/arch/outline/nr_last.rs +++ b/vendor/rustix/src/backend/linux_raw/arch/outline/nr_last.rs @@ -13,8 +13,8 @@ //! other arguments mostly as they are. #[cfg(target_arch = "mips")] -use crate::imp::reg::A6; -use crate::imp::reg::{ArgReg, RetReg, SyscallNumber, A0, A1, A2, A3, A4, A5, R0}; +use crate::backend::reg::A6; +use crate::backend::reg::{ArgReg, RetReg, SyscallNumber, A0, A1, A2, A3, A4, A5, R0}; // First we declare the actual assembly routines with `*_nr_last` names and // reordered arguments. If the signatures or calling conventions are ever @@ -78,19 +78,19 @@ extern "C" { // Then we define inline wrapper functions that do the reordering. #[inline] -pub(in crate::imp) unsafe fn syscall0(nr: SyscallNumber<'_>) -> RetReg<R0> { +pub(in crate::backend) unsafe fn syscall0(nr: SyscallNumber<'_>) -> RetReg<R0> { rustix_syscall0_nr_last(nr) } #[inline] -pub(in crate::imp) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> RetReg<R0> { +pub(in crate::backend) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> RetReg<R0> { rustix_syscall1_nr_last(a0, nr) } #[inline] -pub(in crate::imp) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> ! { +pub(in crate::backend) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> ! { rustix_syscall1_noreturn_nr_last(a0, nr) } #[inline] -pub(in crate::imp) unsafe fn syscall2( +pub(in crate::backend) unsafe fn syscall2( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -98,7 +98,7 @@ pub(in crate::imp) unsafe fn syscall2( rustix_syscall2_nr_last(a0, a1, nr) } #[inline] -pub(in crate::imp) unsafe fn syscall3( +pub(in crate::backend) unsafe fn syscall3( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -107,7 +107,7 @@ pub(in crate::imp) unsafe fn syscall3( rustix_syscall3_nr_last(a0, a1, a2, nr) } #[inline] -pub(in crate::imp) unsafe fn syscall4( +pub(in crate::backend) unsafe fn syscall4( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -117,7 +117,7 @@ pub(in crate::imp) unsafe fn syscall4( rustix_syscall4_nr_last(a0, a1, a2, a3, nr) } #[inline] -pub(in crate::imp) unsafe fn syscall5( +pub(in crate::backend) unsafe fn syscall5( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -128,7 +128,7 @@ pub(in crate::imp) unsafe fn syscall5( rustix_syscall5_nr_last(a0, a1, a2, a3, a4, nr) } #[inline] -pub(in crate::imp) unsafe fn syscall6( +pub(in crate::backend) unsafe fn syscall6( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -141,7 +141,7 @@ pub(in crate::imp) unsafe fn syscall6( } #[cfg(target_arch = "mips")] #[inline] -pub(in crate::imp) unsafe fn syscall7( +pub(in crate::backend) unsafe fn syscall7( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, @@ -158,8 +158,8 @@ pub(in crate::imp) unsafe fn syscall7( // separate `_readonly` implementations, so these can just be aliases to // their non-`_readonly` counterparts. #[cfg(target_arch = "mips")] -pub(in crate::imp) use syscall7 as syscall7_readonly; -pub(in crate::imp) use { +pub(in crate::backend) use syscall7 as syscall7_readonly; +pub(in crate::backend) use { syscall0 as syscall0_readonly, syscall1 as syscall1_readonly, syscall2 as syscall2_readonly, syscall3 as syscall3_readonly, syscall4 as syscall4_readonly, syscall5 as syscall5_readonly, syscall6 as syscall6_readonly, diff --git a/vendor/rustix/src/imp/linux_raw/arch/outline/powerpc64.s b/vendor/rustix/src/backend/linux_raw/arch/outline/powerpc64.s index 29d4c0a95..29d4c0a95 100644 --- a/vendor/rustix/src/imp/linux_raw/arch/outline/powerpc64.s +++ b/vendor/rustix/src/backend/linux_raw/arch/outline/powerpc64.s diff --git a/vendor/rustix/src/imp/linux_raw/arch/outline/riscv64.s b/vendor/rustix/src/backend/linux_raw/arch/outline/riscv64.s index 28d692f7c..28d692f7c 100644 --- a/vendor/rustix/src/imp/linux_raw/arch/outline/riscv64.s +++ b/vendor/rustix/src/backend/linux_raw/arch/outline/riscv64.s diff --git a/vendor/rustix/src/backend/linux_raw/arch/outline/x86.rs b/vendor/rustix/src/backend/linux_raw/arch/outline/x86.rs new file mode 100644 index 000000000..e74b8d2aa --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/arch/outline/x86.rs @@ -0,0 +1,285 @@ +//! Syscall wrappers for 32-bit x86. +//! +//! This module is similar to the `nr_last` module, except specialized for +//! 32-bit x86. +//! +//! The syscall convention passes all arguments in registers. The closest we +//! can easily get to that from Rust is to use the fastcall convention which +//! passes the first two arguments in `ecx` and `edx`, which are the second +//! and third Linux syscall arguments. To line them up, this function passes +//! the second and third syscall argument as the first and second argument to +//! the outline assembly, followed by the first syscall argument, and then the +//! rest of the syscall arguments. The assembly code still has to do some work, +//! but at least we can get up to two arguments into the right place for it. + +#![allow(dead_code, unused_imports)] + +use crate::backend::reg::{ArgReg, RetReg, SyscallNumber, A0, A1, A2, A3, A4, A5, R0}; +use crate::backend::vdso_wrappers::SyscallType; + +// First we declare the actual assembly routines with `*_nr_last_fastcall` +// names and reordered arguments. If the signatures or calling conventions are +// ever changed, the symbol names should also be updated accordingly, to avoid +// collisions with other versions of this crate. +// +// We don't define `_readonly` versions of these because we have no way to tell +// Rust that calls to our outline assembly are readonly. +extern "fastcall" { + fn rustix_syscall0_nr_last_fastcall(nr: SyscallNumber<'_>) -> RetReg<R0>; + fn rustix_syscall1_nr_last_fastcall(a0: ArgReg<'_, A0>, nr: SyscallNumber<'_>) -> RetReg<R0>; + fn rustix_syscall1_noreturn_nr_last_fastcall(a0: ArgReg<'_, A0>, nr: SyscallNumber<'_>) -> !; + fn rustix_syscall2_nr_last_fastcall( + a1: ArgReg<'_, A1>, + a0: ArgReg<'_, A0>, + nr: SyscallNumber<'_>, + ) -> RetReg<R0>; + fn rustix_syscall3_nr_last_fastcall( + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a0: ArgReg<'_, A0>, + nr: SyscallNumber<'_>, + ) -> RetReg<R0>; + fn rustix_syscall4_nr_last_fastcall( + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a0: ArgReg<'_, A0>, + a3: ArgReg<'_, A3>, + nr: SyscallNumber<'_>, + ) -> RetReg<R0>; + fn rustix_syscall5_nr_last_fastcall( + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a0: ArgReg<'_, A0>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, + nr: SyscallNumber<'_>, + ) -> RetReg<R0>; + fn rustix_syscall6_nr_last_fastcall( + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a0: ArgReg<'_, A0>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, + a5: ArgReg<'_, A5>, + nr: SyscallNumber<'_>, + ) -> RetReg<R0>; +} + +// Then we define inline wrapper functions that do the reordering. + +#[inline] +pub(in crate::backend) unsafe fn syscall0(nr: SyscallNumber<'_>) -> RetReg<R0> { + rustix_syscall0_nr_last_fastcall(nr) +} +#[inline] +pub(in crate::backend) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> RetReg<R0> { + rustix_syscall1_nr_last_fastcall(a0, nr) +} +#[inline] +pub(in crate::backend) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> ! { + rustix_syscall1_noreturn_nr_last_fastcall(a0, nr) +} +#[inline] +pub(in crate::backend) unsafe fn syscall2( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, +) -> RetReg<R0> { + rustix_syscall2_nr_last_fastcall(a1, a0, nr) +} +#[inline] +pub(in crate::backend) unsafe fn syscall3( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, +) -> RetReg<R0> { + rustix_syscall3_nr_last_fastcall(a1, a2, a0, nr) +} +#[inline] +pub(in crate::backend) unsafe fn syscall4( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, +) -> RetReg<R0> { + rustix_syscall4_nr_last_fastcall(a1, a2, a0, a3, nr) +} +#[inline] +pub(in crate::backend) unsafe fn syscall5( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, +) -> RetReg<R0> { + rustix_syscall5_nr_last_fastcall(a1, a2, a0, a3, a4, nr) +} +#[inline] +pub(in crate::backend) unsafe fn syscall6( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, + a5: ArgReg<'_, A5>, +) -> RetReg<R0> { + rustix_syscall6_nr_last_fastcall(a1, a2, a0, a3, a4, a5, nr) +} + +// Then we define the `_readonly` versions of the wrappers. We don't have +// separate `_readonly` implementations, so these can just be aliases to +// their non-`_readonly` counterparts. +pub(in crate::backend) use { + syscall0 as syscall0_readonly, syscall1 as syscall1_readonly, syscall2 as syscall2_readonly, + syscall3 as syscall3_readonly, syscall4 as syscall4_readonly, syscall5 as syscall5_readonly, + syscall6 as syscall6_readonly, +}; + +// x86 prefers to route all syscalls through the vDSO, though this isn't +// always possible, so it also has a special form for doing the dispatch. +// +// First we declare the actual assembly routines with `*_nr_last_fastcall` +// names and reordered arguments. If the signatures or calling conventions are +// ever changed, the symbol names should also be updated accordingly, to avoid +// collisions with other versions of this crate. +extern "fastcall" { + fn rustix_indirect_syscall0_nr_last_fastcall( + nr: SyscallNumber<'_>, + callee: SyscallType, + ) -> RetReg<R0>; + fn rustix_indirect_syscall1_nr_last_fastcall( + a0: ArgReg<'_, A0>, + nr: SyscallNumber<'_>, + callee: SyscallType, + ) -> RetReg<R0>; + fn rustix_indirect_syscall1_noreturn_nr_last_fastcall( + a0: ArgReg<'_, A0>, + nr: SyscallNumber<'_>, + callee: SyscallType, + ) -> !; + fn rustix_indirect_syscall2_nr_last_fastcall( + a1: ArgReg<'_, A1>, + a0: ArgReg<'_, A0>, + nr: SyscallNumber<'_>, + callee: SyscallType, + ) -> RetReg<R0>; + fn rustix_indirect_syscall3_nr_last_fastcall( + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a0: ArgReg<'_, A0>, + nr: SyscallNumber<'_>, + callee: SyscallType, + ) -> RetReg<R0>; + fn rustix_indirect_syscall4_nr_last_fastcall( + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a0: ArgReg<'_, A0>, + a3: ArgReg<'_, A3>, + nr: SyscallNumber<'_>, + callee: SyscallType, + ) -> RetReg<R0>; + fn rustix_indirect_syscall5_nr_last_fastcall( + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a0: ArgReg<'_, A0>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, + nr: SyscallNumber<'_>, + callee: SyscallType, + ) -> RetReg<R0>; + fn rustix_indirect_syscall6_nr_last_fastcall( + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a0: ArgReg<'_, A0>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, + a5: ArgReg<'_, A5>, + nr: SyscallNumber<'_>, + callee: SyscallType, + ) -> RetReg<R0>; +} + +// Then we define inline wrapper functions that do the reordering. + +#[inline] +pub(in crate::backend) unsafe fn indirect_syscall0( + callee: SyscallType, + nr: SyscallNumber<'_>, +) -> RetReg<R0> { + rustix_indirect_syscall0_nr_last_fastcall(nr, callee) +} +#[inline] +pub(in crate::backend) unsafe fn indirect_syscall1( + callee: SyscallType, + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, +) -> RetReg<R0> { + rustix_indirect_syscall1_nr_last_fastcall(a0, nr, callee) +} +#[inline] +pub(in crate::backend) unsafe fn indirect_syscall1_noreturn( + callee: SyscallType, + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, +) -> ! { + rustix_indirect_syscall1_noreturn_nr_last_fastcall(a0, nr, callee) +} +#[inline] +pub(in crate::backend) unsafe fn indirect_syscall2( + callee: SyscallType, + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, +) -> RetReg<R0> { + rustix_indirect_syscall2_nr_last_fastcall(a1, a0, nr, callee) +} +#[inline] +pub(in crate::backend) unsafe fn indirect_syscall3( + callee: SyscallType, + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, +) -> RetReg<R0> { + rustix_indirect_syscall3_nr_last_fastcall(a1, a2, a0, nr, callee) +} +#[inline] +pub(in crate::backend) unsafe fn indirect_syscall4( + callee: SyscallType, + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, +) -> RetReg<R0> { + rustix_indirect_syscall4_nr_last_fastcall(a1, a2, a0, a3, nr, callee) +} +#[inline] +pub(in crate::backend) unsafe fn indirect_syscall5( + callee: SyscallType, + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, +) -> RetReg<R0> { + rustix_indirect_syscall5_nr_last_fastcall(a1, a2, a0, a3, a4, nr, callee) +} +#[inline] +pub(in crate::backend) unsafe fn indirect_syscall6( + callee: SyscallType, + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, + a5: ArgReg<'_, A5>, +) -> RetReg<R0> { + rustix_indirect_syscall6_nr_last_fastcall(a1, a2, a0, a3, a4, a5, nr, callee) +} diff --git a/vendor/rustix/src/imp/linux_raw/arch/outline/x86.s b/vendor/rustix/src/backend/linux_raw/arch/outline/x86.s index bda234e1a..bda234e1a 100644 --- a/vendor/rustix/src/imp/linux_raw/arch/outline/x86.s +++ b/vendor/rustix/src/backend/linux_raw/arch/outline/x86.s diff --git a/vendor/rustix/src/imp/linux_raw/arch/outline/x86_64.s b/vendor/rustix/src/backend/linux_raw/arch/outline/x86_64.s index 2beda323b..2beda323b 100644 --- a/vendor/rustix/src/imp/linux_raw/arch/outline/x86_64.s +++ b/vendor/rustix/src/backend/linux_raw/arch/outline/x86_64.s diff --git a/vendor/rustix/src/imp/linux_raw/c.rs b/vendor/rustix/src/backend/linux_raw/c.rs index a6f0b8ff6..a6f0b8ff6 100644 --- a/vendor/rustix/src/imp/linux_raw/c.rs +++ b/vendor/rustix/src/backend/linux_raw/c.rs diff --git a/vendor/rustix/src/backend/linux_raw/conv.rs b/vendor/rustix/src/backend/linux_raw/conv.rs new file mode 100644 index 000000000..7e09cdf80 --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/conv.rs @@ -0,0 +1,790 @@ +//! Convert values to [`ArgReg`] and from [`RetReg`]. +//! +//! System call arguments and return values are all communicated with inline +//! asm and FFI as `*mut Opaque`. To protect these raw pointers from escaping +//! or being accidentally misused as they travel through the code, we wrap +//! them in [`ArgReg`] and [`RetReg`] structs. This file provides `From` +//! implementations and explicit conversion functions for converting values +//! into and out of these wrapper structs. +//! +//! # Safety +//! +//! Some of this code is `unsafe` in order to work with raw file descriptors, +//! and some is `unsafe` to interpret the values in a `RetReg`. +#![allow(unsafe_code)] + +use super::c; +use super::fd::{AsRawFd, BorrowedFd, FromRawFd, RawFd}; +#[cfg(not(debug_assertions))] +use super::io::errno::decode_usize_infallible; +#[cfg(feature = "runtime")] +use super::io::errno::try_decode_error; +#[cfg(target_pointer_width = "64")] +use super::io::errno::try_decode_u64; +use super::io::errno::{ + try_decode_c_int, try_decode_c_uint, try_decode_raw_fd, try_decode_usize, try_decode_void, + try_decode_void_star, +}; +use super::reg::{raw_arg, ArgNumber, ArgReg, RetReg, R0}; +#[cfg(any(feature = "thread", feature = "time", target_arch = "x86"))] +use super::time::types::ClockId; +#[cfg(feature = "time")] +use super::time::types::TimerfdClockId; +use crate::fd::OwnedFd; +use crate::ffi::CStr; +#[cfg(feature = "fs")] +use crate::fs::{FileType, Mode, OFlags}; +use crate::io; +use crate::process::{Pid, Resource, Signal}; +use crate::utils::{as_mut_ptr, as_ptr}; +use core::mem::MaybeUninit; +use core::ptr::null_mut; +#[cfg(any(feature = "thread", feature = "time", target_arch = "x86"))] +use linux_raw_sys::general::__kernel_clockid_t; +#[cfg(target_pointer_width = "64")] +use linux_raw_sys::general::__kernel_loff_t; +#[cfg(feature = "net")] +use linux_raw_sys::general::socklen_t; +#[cfg(target_pointer_width = "32")] +#[cfg(feature = "fs")] +use linux_raw_sys::general::O_LARGEFILE; + +/// Convert `SYS_*` constants for socketcall. +#[cfg(target_arch = "x86")] +#[inline] +pub(super) fn x86_sys<'a, Num: ArgNumber>(sys: u32) -> ArgReg<'a, Num> { + pass_usize(sys as usize) +} + +/// Pass the "low" half of the endian-specific memory encoding of a `u64`, for +/// 32-bit architectures. +#[cfg(target_pointer_width = "32")] +#[inline] +pub(super) fn lo<'a, Num: ArgNumber>(x: u64) -> ArgReg<'a, Num> { + #[cfg(target_endian = "little")] + let x = x >> 32; + #[cfg(target_endian = "big")] + let x = x & 0xffff_ffff; + + pass_usize(x as usize) +} + +/// Pass the "high" half of the endian-specific memory encoding of a `u64`, for +/// 32-bit architectures. +#[cfg(target_pointer_width = "32")] +#[inline] +pub(super) fn hi<'a, Num: ArgNumber>(x: u64) -> ArgReg<'a, Num> { + #[cfg(target_endian = "little")] + let x = x & 0xffff_ffff; + #[cfg(target_endian = "big")] + let x = x >> 32; + + pass_usize(x as usize) +} + +/// Pass a zero, or null, argument. +#[inline] +pub(super) fn zero<'a, Num: ArgNumber>() -> ArgReg<'a, Num> { + raw_arg(null_mut()) +} + +/// Pass the `mem::size_of` of a type. +#[inline] +pub(super) fn size_of<'a, T: Sized, Num: ArgNumber>() -> ArgReg<'a, Num> { + pass_usize(core::mem::size_of::<T>()) +} + +/// Pass an arbitrary `usize` value. +/// +/// For passing pointers, use `void_star` or other functions which take a raw +/// pointer instead of casting to `usize`, so that provenance is preserved. +#[inline] +pub(super) fn pass_usize<'a, Num: ArgNumber>(t: usize) -> ArgReg<'a, Num> { + raw_arg(t as *mut _) +} + +impl<'a, Num: ArgNumber, T> From<*mut T> for ArgReg<'a, Num> { + #[inline] + fn from(c: *mut T) -> ArgReg<'a, Num> { + raw_arg(c.cast()) + } +} + +impl<'a, Num: ArgNumber, T> From<*const T> for ArgReg<'a, Num> { + #[inline] + fn from(c: *const T) -> ArgReg<'a, Num> { + let mut_ptr = c as *mut T; + raw_arg(mut_ptr.cast()) + } +} + +impl<'a, Num: ArgNumber> From<&'a CStr> for ArgReg<'a, Num> { + #[inline] + fn from(c: &'a CStr) -> Self { + let mut_ptr = c.as_ptr() as *mut u8; + raw_arg(mut_ptr.cast()) + } +} + +impl<'a, Num: ArgNumber> From<Option<&'a CStr>> for ArgReg<'a, Num> { + #[inline] + fn from(t: Option<&'a CStr>) -> Self { + raw_arg(match t { + Some(s) => { + let mut_ptr = s.as_ptr() as *mut u8; + mut_ptr.cast() + } + None => null_mut(), + }) + } +} + +/// Pass a borrowed file-descriptor argument. +impl<'a, Num: ArgNumber> From<BorrowedFd<'a>> for ArgReg<'a, Num> { + #[inline] + fn from(fd: BorrowedFd<'a>) -> Self { + // Safety: `BorrowedFd` ensures that the file descriptor is valid, and the + // lifetime parameter on the resulting `ArgReg` ensures that the result is + // bounded by the `BorrowedFd`'s lifetime. + unsafe { raw_fd(fd.as_raw_fd()) } + } +} + +/// Pass a raw file-descriptor argument. Most users should use [`ArgReg::from`] +/// instead, to preserve I/O safety as long as possible. +/// +/// # Safety +/// +/// `fd` must be a valid open file descriptor. +#[inline] +pub(super) unsafe fn raw_fd<'a, Num: ArgNumber>(fd: RawFd) -> ArgReg<'a, Num> { + // Use `no_fd` when passing `-1` is intended. + #[cfg(feature = "fs")] + debug_assert!(fd == crate::fs::cwd().as_raw_fd() || fd >= 0); + + // Don't pass the `io_uring_register_files_skip` sentry value this way. + #[cfg(feature = "io_uring")] + debug_assert_ne!( + fd, + crate::io_uring::io_uring_register_files_skip().as_raw_fd() + ); + + // Linux doesn't look at the high bits beyond the `c_int`, so use + // zero-extension rather than sign-extension because it's a smaller + // instruction. + let fd: c::c_int = fd; + pass_usize(fd as c::c_uint as usize) +} + +/// Deliberately pass `-1` to a file-descriptor argument, for system calls +/// like `mmap` where this indicates the argument is omitted. +#[inline] +pub(super) fn no_fd<'a, Num: ArgNumber>() -> ArgReg<'a, Num> { + pass_usize(!0_usize) +} + +#[inline] +pub(super) fn slice_just_addr<T: Sized, Num: ArgNumber>(v: &[T]) -> ArgReg<Num> { + let mut_ptr = v.as_ptr() as *mut T; + raw_arg(mut_ptr.cast()) +} + +#[inline] +pub(super) fn slice<T: Sized, Num0: ArgNumber, Num1: ArgNumber>( + v: &[T], +) -> (ArgReg<Num0>, ArgReg<Num1>) { + (slice_just_addr(v), pass_usize(v.len())) +} + +#[inline] +pub(super) fn slice_mut<T: Sized, Num0: ArgNumber, Num1: ArgNumber>( + v: &mut [T], +) -> (ArgReg<Num0>, ArgReg<Num1>) { + (raw_arg(v.as_mut_ptr().cast()), pass_usize(v.len())) +} + +#[inline] +pub(super) fn by_ref<T: Sized, Num: ArgNumber>(t: &T) -> ArgReg<Num> { + let mut_ptr = as_ptr(t) as *mut T; + raw_arg(mut_ptr.cast()) +} + +#[inline] +pub(super) fn by_mut<T: Sized, Num: ArgNumber>(t: &mut T) -> ArgReg<Num> { + raw_arg(as_mut_ptr(t).cast()) +} + +/// Convert an optional mutable reference into a `usize` for passing to a +/// syscall. +#[inline] +pub(super) fn opt_mut<T: Sized, Num: ArgNumber>(t: Option<&mut T>) -> ArgReg<Num> { + // This optimizes into the equivalent of `transmute(t)`, and has the + // advantage of not requiring `unsafe`. + match t { + Some(t) => by_mut(t), + None => raw_arg(null_mut()), + } +} + +/// Convert an optional immutable reference into a `usize` for passing to a +/// syscall. +#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] +#[inline] +pub(super) fn opt_ref<T: Sized, Num: ArgNumber>(t: Option<&T>) -> ArgReg<Num> { + // This optimizes into the equivalent of `transmute(t)`, and has the + // advantage of not requiring `unsafe`. + match t { + Some(t) => by_ref(t), + None => raw_arg(null_mut()), + } +} + +/// Convert a `c_int` into an `ArgReg`. +/// +/// Be sure to use `raw_fd` to pass `RawFd` values. +#[inline] +pub(super) fn c_int<'a, Num: ArgNumber>(i: c::c_int) -> ArgReg<'a, Num> { + pass_usize(i as usize) +} + +/// Convert a `c_uint` into an `ArgReg`. +#[inline] +pub(super) fn c_uint<'a, Num: ArgNumber>(i: c::c_uint) -> ArgReg<'a, Num> { + pass_usize(i as usize) +} + +#[cfg(target_pointer_width = "64")] +#[inline] +pub(super) fn loff_t<'a, Num: ArgNumber>(i: __kernel_loff_t) -> ArgReg<'a, Num> { + pass_usize(i as usize) +} + +#[cfg(target_pointer_width = "64")] +#[inline] +pub(super) fn loff_t_from_u64<'a, Num: ArgNumber>(i: u64) -> ArgReg<'a, Num> { + // `loff_t` is signed, but syscalls which expect `loff_t` return `EINVAL` + // if it's outside the signed `i64` range, so we can silently cast. + pass_usize(i as usize) +} + +#[cfg(any(feature = "thread", feature = "time", target_arch = "x86"))] +impl<'a, Num: ArgNumber> From<ClockId> for ArgReg<'a, Num> { + #[inline] + fn from(i: ClockId) -> Self { + pass_usize(i as __kernel_clockid_t as usize) + } +} + +#[cfg(feature = "time")] +impl<'a, Num: ArgNumber> From<TimerfdClockId> for ArgReg<'a, Num> { + #[inline] + fn from(i: TimerfdClockId) -> Self { + pass_usize(i as __kernel_clockid_t as usize) + } +} + +#[cfg(feature = "net")] +#[inline] +pub(super) fn socklen_t<'a, Num: ArgNumber>(i: socklen_t) -> ArgReg<'a, Num> { + pass_usize(i as usize) +} + +#[cfg(feature = "fs")] +impl<'a, Num: ArgNumber> From<Mode> for ArgReg<'a, Num> { + #[inline] + fn from(mode: Mode) -> Self { + pass_usize(mode.bits() as usize) + } +} + +#[cfg(feature = "fs")] +impl<'a, Num: ArgNumber> From<(Mode, FileType)> for ArgReg<'a, Num> { + #[inline] + fn from(pair: (Mode, FileType)) -> Self { + pass_usize(pair.0.as_raw_mode() as usize | pair.1.as_raw_mode() as usize) + } +} + +#[cfg(feature = "fs")] +impl<'a, Num: ArgNumber> From<crate::fs::AtFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::fs::AtFlags) -> Self { + c_uint(flags.bits()) + } +} + +#[cfg(feature = "fs")] +impl<'a, Num: ArgNumber> From<crate::fs::MemfdFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::fs::MemfdFlags) -> Self { + c_uint(flags.bits()) + } +} + +#[cfg(feature = "fs")] +impl<'a, Num: ArgNumber> From<crate::fs::RenameFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::fs::RenameFlags) -> Self { + c_uint(flags.bits()) + } +} + +#[cfg(feature = "fs")] +impl<'a, Num: ArgNumber> From<crate::fs::StatxFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::fs::StatxFlags) -> Self { + c_uint(flags.bits()) + } +} + +impl<'a, Num: ArgNumber> From<crate::io::FdFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::io::FdFlags) -> Self { + c_uint(flags.bits()) + } +} + +impl<'a, Num: ArgNumber> From<crate::io::PipeFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::io::PipeFlags) -> Self { + c_uint(flags.bits()) + } +} + +impl<'a, Num: ArgNumber> From<crate::io::DupFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::io::DupFlags) -> Self { + c_uint(flags.bits()) + } +} + +impl<'a, Num: ArgNumber> From<crate::io::ReadWriteFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::io::ReadWriteFlags) -> Self { + c_uint(flags.bits()) + } +} + +impl<'a, Num: ArgNumber> From<crate::io::EventfdFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::io::EventfdFlags) -> Self { + c_uint(flags.bits()) + } +} + +impl<'a, Num: ArgNumber> From<crate::io::epoll::CreateFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::io::epoll::CreateFlags) -> Self { + c_uint(flags.bits()) + } +} + +#[cfg(feature = "mm")] +impl<'a, Num: ArgNumber> From<crate::backend::mm::types::ProtFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::backend::mm::types::ProtFlags) -> Self { + c_uint(flags.bits()) + } +} + +#[cfg(feature = "mm")] +impl<'a, Num: ArgNumber> From<crate::backend::mm::types::MsyncFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::backend::mm::types::MsyncFlags) -> Self { + c_uint(flags.bits()) + } +} + +#[cfg(feature = "mm")] +impl<'a, Num: ArgNumber> From<crate::backend::mm::types::MremapFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::backend::mm::types::MremapFlags) -> Self { + c_uint(flags.bits()) + } +} + +#[cfg(feature = "mm")] +impl<'a, Num: ArgNumber> From<crate::backend::mm::types::MlockFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::backend::mm::types::MlockFlags) -> Self { + c_uint(flags.bits()) + } +} + +#[cfg(feature = "mm")] +impl<'a, Num: ArgNumber> From<crate::backend::mm::types::MapFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::backend::mm::types::MapFlags) -> Self { + c_uint(flags.bits()) + } +} + +#[cfg(feature = "mm")] +impl<'a, Num: ArgNumber> From<crate::backend::mm::types::MprotectFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::backend::mm::types::MprotectFlags) -> Self { + c_uint(flags.bits()) + } +} + +#[cfg(feature = "mm")] +impl<'a, Num: ArgNumber> From<crate::backend::mm::types::UserfaultfdFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::backend::mm::types::UserfaultfdFlags) -> Self { + c_uint(flags.bits()) + } +} + +impl<'a, Num: ArgNumber> From<crate::backend::process::types::MembarrierCommand> + for ArgReg<'a, Num> +{ + #[inline] + fn from(cmd: crate::backend::process::types::MembarrierCommand) -> Self { + c_uint(cmd as u32) + } +} + +impl<'a, Num: ArgNumber> From<crate::process::Cpuid> for ArgReg<'a, Num> { + #[inline] + fn from(cpuid: crate::process::Cpuid) -> Self { + c_uint(cpuid.as_raw()) + } +} + +#[cfg(target_pointer_width = "64")] +#[inline] +pub(super) fn dev_t<'a, Num: ArgNumber>(dev: u64) -> ArgReg<'a, Num> { + pass_usize(dev as usize) +} + +#[cfg(target_pointer_width = "32")] +#[inline] +pub(super) fn dev_t<'a, Num: ArgNumber>(dev: u64) -> io::Result<ArgReg<'a, Num>> { + use core::convert::TryInto; + Ok(pass_usize(dev.try_into().map_err(|_err| io::Errno::INVAL)?)) +} + +#[cfg(target_pointer_width = "32")] +#[cfg(feature = "fs")] +#[inline] +fn oflags_bits(oflags: OFlags) -> c::c_uint { + let mut bits = oflags.bits(); + // Add `O_LARGEFILE`, unless `O_PATH` is set, as Linux returns `EINVAL` + // when both are set. + if !oflags.contains(OFlags::PATH) { + bits |= O_LARGEFILE; + } + bits +} + +#[cfg(target_pointer_width = "64")] +#[cfg(feature = "fs")] +#[inline] +const fn oflags_bits(oflags: OFlags) -> c::c_uint { + oflags.bits() +} + +#[cfg(feature = "fs")] +impl<'a, Num: ArgNumber> From<OFlags> for ArgReg<'a, Num> { + #[inline] + fn from(oflags: OFlags) -> Self { + pass_usize(oflags_bits(oflags) as usize) + } +} + +/// Convert an `OFlags` into a `u64` for use in the `open_how` struct. +#[cfg(feature = "fs")] +#[inline] +pub(super) fn oflags_for_open_how(oflags: OFlags) -> u64 { + u64::from(oflags_bits(oflags)) +} + +#[cfg(feature = "fs")] +impl<'a, Num: ArgNumber> From<crate::fs::FallocateFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::fs::FallocateFlags) -> Self { + c_uint(flags.bits()) + } +} + +/// Convert a `Resource` into a syscall argument. +impl<'a, Num: ArgNumber> From<Resource> for ArgReg<'a, Num> { + #[inline] + fn from(resource: Resource) -> Self { + c_uint(resource as c::c_uint) + } +} + +impl<'a, Num: ArgNumber> From<Pid> for ArgReg<'a, Num> { + #[inline] + fn from(pid: Pid) -> Self { + pass_usize(pid.as_raw_nonzero().get() as usize) + } +} + +#[inline] +pub(super) fn negative_pid<'a, Num: ArgNumber>(pid: Pid) -> ArgReg<'a, Num> { + pass_usize(pid.as_raw_nonzero().get().wrapping_neg() as usize) +} + +impl<'a, Num: ArgNumber> From<Signal> for ArgReg<'a, Num> { + #[inline] + fn from(sig: Signal) -> Self { + pass_usize(sig as usize) + } +} + +#[cfg(feature = "fs")] +impl<'a, Num: ArgNumber> From<crate::fs::Advice> for ArgReg<'a, Num> { + #[inline] + fn from(advice: crate::fs::Advice) -> Self { + c_uint(advice as c::c_uint) + } +} + +#[cfg(feature = "fs")] +impl<'a, Num: ArgNumber> From<crate::fs::SealFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::fs::SealFlags) -> Self { + c_uint(flags.bits()) + } +} + +#[cfg(feature = "io_uring")] +impl<'a, Num: ArgNumber> From<crate::io_uring::IoringEnterFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::io_uring::IoringEnterFlags) -> Self { + c_uint(flags.bits()) + } +} + +#[cfg(feature = "time")] +impl<'a, Num: ArgNumber> From<crate::time::TimerfdFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::time::TimerfdFlags) -> Self { + c_uint(flags.bits()) + } +} + +#[cfg(feature = "time")] +impl<'a, Num: ArgNumber> From<crate::time::TimerfdTimerFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::time::TimerfdTimerFlags) -> Self { + c_uint(flags.bits()) + } +} + +#[cfg(feature = "rand")] +impl<'a, Num: ArgNumber> From<crate::rand::GetRandomFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::rand::GetRandomFlags) -> Self { + c_uint(flags.bits()) + } +} + +#[cfg(feature = "net")] +impl<'a, Num: ArgNumber> From<crate::net::RecvFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::net::RecvFlags) -> Self { + c_uint(flags.bits()) + } +} + +#[cfg(feature = "net")] +impl<'a, Num: ArgNumber> From<crate::net::SendFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::net::SendFlags) -> Self { + c_uint(flags.bits()) + } +} + +#[cfg(feature = "net")] +impl<'a, Num: ArgNumber> From<crate::net::AcceptFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::net::AcceptFlags) -> Self { + c_uint(flags.bits()) + } +} + +#[cfg(feature = "net")] +impl<'a, Num: ArgNumber> From<crate::net::AddressFamily> for ArgReg<'a, Num> { + #[inline] + fn from(family: crate::net::AddressFamily) -> Self { + c_uint(family.0.into()) + } +} + +#[cfg(feature = "net")] +impl<'a, Num: ArgNumber> From<(crate::net::SocketType, crate::net::SocketFlags)> + for ArgReg<'a, Num> +{ + #[inline] + fn from(pair: (crate::net::SocketType, crate::net::SocketFlags)) -> Self { + c_uint(pair.0 .0 | pair.1.bits()) + } +} + +#[cfg(feature = "thread")] +impl<'a, Num: ArgNumber> From<(crate::thread::FutexOperation, crate::thread::FutexFlags)> + for ArgReg<'a, Num> +{ + #[inline] + fn from(pair: (crate::thread::FutexOperation, crate::thread::FutexFlags)) -> Self { + c_uint(pair.0 as u32 | pair.1.bits()) + } +} + +#[cfg(feature = "fs")] +impl<'a, Num: ArgNumber> From<crate::fs::Access> for ArgReg<'a, Num> { + #[inline] + fn from(access: crate::fs::Access) -> Self { + c_uint(access.bits()) + } +} + +#[cfg(feature = "net")] +impl<'a, Num: ArgNumber> From<crate::net::SocketType> for ArgReg<'a, Num> { + #[inline] + fn from(type_: crate::net::SocketType) -> Self { + c_uint(type_.0) + } +} + +#[cfg(feature = "net")] +impl<'a, Num: ArgNumber> From<crate::net::Protocol> for ArgReg<'a, Num> { + #[inline] + fn from(protocol: crate::net::Protocol) -> Self { + c_uint(protocol.0) + } +} + +impl<'a, Num: ArgNumber, T> From<&'a mut MaybeUninit<T>> for ArgReg<'a, Num> { + #[inline] + fn from(t: &'a mut MaybeUninit<T>) -> Self { + raw_arg(t.as_mut_ptr().cast()) + } +} + +/// Convert a `usize` returned from a syscall that effectively returns `()` on +/// success. +/// +/// # Safety +/// +/// The caller must ensure that this is the return value of a syscall which +/// just returns 0 on success. +#[inline] +pub(super) unsafe fn ret(raw: RetReg<R0>) -> io::Result<()> { + try_decode_void(raw) +} + +/// Convert a `usize` returned from a syscall that doesn't return on success. +/// +/// # Safety +/// +/// The caller must ensure that this is the return value of a syscall which +/// doesn't return on success. +#[cfg(feature = "runtime")] +#[inline] +pub(super) unsafe fn ret_error(raw: RetReg<R0>) -> io::Errno { + try_decode_error(raw) +} + +/// Convert a `usize` returned from a syscall that effectively always returns +/// `()`. +/// +/// # Safety +/// +/// The caller must ensure that this is the return value of a syscall which +/// always returns `()`. +#[inline] +pub(super) unsafe fn ret_infallible(raw: RetReg<R0>) { + #[cfg(debug_assertions)] + { + try_decode_void(raw).unwrap() + } + #[cfg(not(debug_assertions))] + drop(raw); +} + +/// Convert a `usize` returned from a syscall that effectively returns a +/// `c_int` on success. +#[inline] +pub(super) fn ret_c_int(raw: RetReg<R0>) -> io::Result<c::c_int> { + try_decode_c_int(raw) +} + +/// Convert a `usize` returned from a syscall that effectively returns a +/// `c_uint` on success. +#[inline] +pub(super) fn ret_c_uint(raw: RetReg<R0>) -> io::Result<c::c_uint> { + try_decode_c_uint(raw) +} + +/// Convert a `usize` returned from a syscall that effectively returns a `u64` +/// on success. +#[cfg(target_pointer_width = "64")] +#[inline] +pub(super) fn ret_u64(raw: RetReg<R0>) -> io::Result<u64> { + try_decode_u64(raw) +} + +/// Convert a `usize` returned from a syscall that effectively returns a +/// `usize` on success. +#[inline] +pub(super) fn ret_usize(raw: RetReg<R0>) -> io::Result<usize> { + try_decode_usize(raw) +} + +/// Convert a `usize` returned from a syscall that effectively always +/// returns a `usize`. +/// +/// # Safety +/// +/// This function must only be used with return values from infallible +/// syscalls. +#[inline] +pub(super) unsafe fn ret_usize_infallible(raw: RetReg<R0>) -> usize { + #[cfg(debug_assertions)] + { + try_decode_usize(raw).unwrap() + } + #[cfg(not(debug_assertions))] + { + decode_usize_infallible(raw) + } +} + +/// Convert a `usize` returned from a syscall that effectively returns an +/// `OwnedFd` on success. +/// +/// # Safety +/// +/// The caller must ensure that this is the return value of a syscall which +/// returns an owned file descriptor. +#[inline] +pub(super) unsafe fn ret_owned_fd(raw: RetReg<R0>) -> io::Result<OwnedFd> { + let raw_fd = try_decode_raw_fd(raw)?; + Ok(crate::backend::fd::OwnedFd::from_raw_fd(raw_fd)) +} + +/// Convert the return value of `dup2` and `dup3`. +/// +/// When these functions succeed, they return the same value as their second +/// argument, so we don't construct a new `OwnedFd`. +/// +/// # Safety +/// +/// The caller must ensure that this is the return value of a syscall which +/// returns a file descriptor. +#[inline] +pub(super) unsafe fn ret_discarded_fd(raw: RetReg<R0>) -> io::Result<()> { + let _raw_fd = try_decode_raw_fd(raw)?; + Ok(()) +} + +/// Convert a `usize` returned from a syscall that effectively returns a +/// `*mut c_void` on success. +#[inline] +pub(super) fn ret_void_star(raw: RetReg<R0>) -> io::Result<*mut c::c_void> { + try_decode_void_star(raw) +} diff --git a/vendor/rustix/src/backend/linux_raw/elf.rs b/vendor/rustix/src/backend/linux_raw/elf.rs new file mode 100644 index 000000000..87fb5fa0f --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/elf.rs @@ -0,0 +1,176 @@ +//! The ELF ABI. + +#![allow(non_snake_case)] +#![cfg_attr( + all(not(target_vendor = "mustang"), feature = "use-libc-auxv"), + allow(dead_code) +)] + +pub(super) const SELFMAG: usize = 4; +pub(super) const ELFMAG: [u8; SELFMAG] = [0x7f, b'E', b'L', b'F']; +pub(super) const EI_CLASS: usize = 4; +pub(super) const EI_DATA: usize = 5; +pub(super) const EI_VERSION: usize = 6; +pub(super) const EI_OSABI: usize = 7; +pub(super) const EI_ABIVERSION: usize = 8; +pub(super) const EV_CURRENT: u8 = 1; +#[cfg(target_pointer_width = "32")] +pub(super) const ELFCLASS: u8 = 1; // ELFCLASS32 +#[cfg(target_pointer_width = "64")] +pub(super) const ELFCLASS: u8 = 2; // ELFCLASS64 +#[cfg(target_endian = "little")] +pub(super) const ELFDATA: u8 = 1; // ELFDATA2LSB +#[cfg(target_endian = "big")] +pub(super) const ELFDATA: u8 = 2; // ELFDATA2MSB +pub(super) const ELFOSABI_SYSV: u8 = 0; +pub(super) const ELFOSABI_LINUX: u8 = 3; +// At present all of our supported platforms use 0. +pub(super) const ELFABIVERSION: u8 = 0; +pub(super) const ET_DYN: u16 = 3; +pub(super) const EI_NIDENT: usize = 16; +pub(super) const SHN_UNDEF: u16 = 0; +pub(super) const SHN_ABS: u16 = 0xfff1; +pub(super) const PN_XNUM: u16 = 0xffff; +pub(super) const PT_LOAD: u32 = 1; +pub(super) const PT_DYNAMIC: u32 = 2; +pub(super) const PT_INTERP: u32 = 3; +pub(super) const PT_PHDR: u32 = 6; +pub(super) const PT_TLS: u32 = 7; +pub(super) const PT_GNU_STACK: u32 = 0x6474_e551; +pub(super) const PT_GNU_RELRO: u32 = 0x6474_e552; +pub(super) const PF_X: u32 = 1; +pub(super) const PF_W: u32 = 2; +pub(super) const PF_R: u32 = 4; +pub(super) const DT_NULL: i32 = 0; +pub(super) const DT_HASH: i32 = 4; +pub(super) const DT_STRTAB: i32 = 5; +pub(super) const DT_SYMTAB: i32 = 6; +pub(super) const DT_SYMENT: i32 = 11; +pub(super) const DT_VERSYM: i32 = 0x6fff_fff0; +pub(super) const DT_VERDEF: i32 = 0x6fff_fffc; +pub(super) const STB_WEAK: u8 = 2; +pub(super) const STB_GLOBAL: u8 = 1; +pub(super) const STT_NOTYPE: u8 = 0; +pub(super) const STT_FUNC: u8 = 2; +pub(super) const STN_UNDEF: u32 = 0; +pub(super) const VER_FLG_BASE: u16 = 0x1; +pub(super) const VER_DEF_CURRENT: u16 = 1; +pub(super) const STV_DEFAULT: u8 = 0; +#[cfg(target_arch = "arm")] +pub(super) const EM_CURRENT: u16 = 40; // EM_ARM +#[cfg(target_arch = "x86")] +pub(super) const EM_CURRENT: u16 = 3; // EM_386 +#[cfg(target_arch = "powerpc64")] +pub(super) const EM_CURRENT: u16 = 21; // EM_PPC64 +#[cfg(any(target_arch = "mips", target_arch = "mips64"))] +pub(super) const EM_CURRENT: u16 = 8; // EM_MIPS +#[cfg(target_arch = "x86_64")] +pub(super) const EM_CURRENT: u16 = 62; // EM_X86_64 +#[cfg(target_arch = "aarch64")] +pub(super) const EM_CURRENT: u16 = 183; // EM_AARCH64 +#[cfg(target_arch = "riscv64")] +pub(super) const EM_CURRENT: u16 = 243; // EM_RISCV + +#[inline] +pub(super) const fn ELF_ST_VISIBILITY(o: u8) -> u8 { + o & 0x03 +} + +#[inline] +pub(super) const fn ELF_ST_BIND(val: u8) -> u8 { + val >> 4 +} + +#[inline] +pub(super) const fn ELF_ST_TYPE(val: u8) -> u8 { + val & 0xf +} + +#[repr(C)] +pub(super) struct Elf_Ehdr { + pub(super) e_ident: [u8; EI_NIDENT], + pub(super) e_type: u16, + pub(super) e_machine: u16, + pub(super) e_version: u32, + pub(super) e_entry: usize, + pub(super) e_phoff: usize, + pub(super) e_shoff: usize, + pub(super) e_flags: u32, + pub(super) e_ehsize: u16, + pub(super) e_phentsize: u16, + pub(super) e_phnum: u16, + pub(super) e_shentsize: u16, + pub(super) e_shnum: u16, + pub(super) e_shstrndx: u16, +} + +#[cfg(target_pointer_width = "32")] +#[repr(C)] +pub(super) struct Elf_Phdr { + pub(super) p_type: u32, + pub(super) p_offset: usize, + pub(super) p_vaddr: usize, + pub(super) p_paddr: usize, + pub(super) p_filesz: usize, + pub(super) p_memsz: usize, + pub(super) p_flags: u32, + pub(super) p_align: usize, +} + +#[cfg(target_pointer_width = "64")] +#[repr(C)] +pub(super) struct Elf_Phdr { + pub(super) p_type: u32, + pub(super) p_flags: u32, + pub(super) p_offset: usize, + pub(super) p_vaddr: usize, + pub(super) p_paddr: usize, + pub(super) p_filesz: usize, + pub(super) p_memsz: usize, + pub(super) p_align: usize, +} + +#[cfg(target_pointer_width = "32")] +#[repr(C)] +pub(super) struct Elf_Sym { + pub(super) st_name: u32, + pub(super) st_value: usize, + pub(super) st_size: usize, + pub(super) st_info: u8, + pub(super) st_other: u8, + pub(super) st_shndx: u16, +} + +#[cfg(target_pointer_width = "64")] +#[repr(C)] +pub(super) struct Elf_Sym { + pub(super) st_name: u32, + pub(super) st_info: u8, + pub(super) st_other: u8, + pub(super) st_shndx: u16, + pub(super) st_value: usize, + pub(super) st_size: usize, +} + +#[repr(C)] +pub(super) struct Elf_Dyn { + pub(super) d_tag: i32, + pub(super) d_val: usize, +} + +#[repr(C)] +pub(super) struct Elf_Verdef { + pub(super) vd_version: u16, + pub(super) vd_flags: u16, + pub(super) vd_ndx: u16, + pub(super) vd_cnt: u16, + pub(super) vd_hash: u32, + pub(super) vd_aux: u32, + pub(super) vd_next: u32, +} + +#[repr(C)] +pub(super) struct Elf_Verdaux { + pub(super) vda_name: u32, + pub(super) _vda_next: u32, +} diff --git a/vendor/rustix/src/backend/linux_raw/fs/dir.rs b/vendor/rustix/src/backend/linux_raw/fs/dir.rs new file mode 100644 index 000000000..cfa347d03 --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/fs/dir.rs @@ -0,0 +1,225 @@ +use crate::fd::{AsFd, BorrowedFd, OwnedFd}; +use crate::ffi::{CStr, CString}; +use crate::fs::{ + fcntl_getfl, fstat, fstatfs, fstatvfs, openat, FileType, Mode, OFlags, Stat, StatFs, StatVfs, +}; +use crate::io; +use crate::process::fchdir; +use crate::utils::as_ptr; +use alloc::borrow::ToOwned; +use alloc::vec::Vec; +use core::fmt; +use core::mem::size_of; +use linux_raw_sys::general::{linux_dirent64, SEEK_SET}; + +/// `DIR*` +pub struct Dir { + /// The `OwnedFd` that we read directory entries from. + fd: OwnedFd, + + buf: Vec<u8>, + pos: usize, + next: Option<u64>, +} + +impl Dir { + /// Construct a `Dir` that reads entries from the given directory + /// file descriptor. + #[inline] + pub fn read_from<Fd: AsFd>(fd: Fd) -> io::Result<Self> { + Self::_read_from(fd.as_fd()) + } + + #[inline] + fn _read_from(fd: BorrowedFd<'_>) -> io::Result<Self> { + let flags = fcntl_getfl(fd)?; + let fd_for_dir = openat(fd, cstr!("."), flags | OFlags::CLOEXEC, Mode::empty())?; + + Ok(Self { + fd: fd_for_dir, + buf: Vec::new(), + pos: 0, + next: None, + }) + } + + /// `rewinddir(self)` + #[inline] + pub fn rewind(&mut self) { + self.pos = self.buf.len(); + self.next = Some(0); + } + + /// `readdir(self)`, where `None` means the end of the directory. + pub fn read(&mut self) -> Option<io::Result<DirEntry>> { + if let Some(next) = self.next.take() { + match crate::backend::fs::syscalls::_seek(self.fd.as_fd(), next as i64, SEEK_SET) { + Ok(_) => (), + Err(err) => return Some(Err(err)), + } + } + + // Compute linux_dirent64 field offsets. + let z = linux_dirent64 { + d_ino: 0_u64, + d_off: 0_i64, + d_type: 0_u8, + d_reclen: 0_u16, + d_name: Default::default(), + }; + let base = as_ptr(&z) as usize; + let offsetof_d_reclen = (as_ptr(&z.d_reclen) as usize) - base; + let offsetof_d_name = (as_ptr(&z.d_name) as usize) - base; + let offsetof_d_ino = (as_ptr(&z.d_ino) as usize) - base; + let offsetof_d_type = (as_ptr(&z.d_type) as usize) - base; + + // Test if we need more entries, and if so, read more. + if self.buf.len() - self.pos < size_of::<linux_dirent64>() { + match self.read_more()? { + Ok(()) => (), + Err(e) => return Some(Err(e)), + } + } + + // We successfully read an entry. Extract the fields. + let pos = self.pos; + + // Do an unaligned u16 load. + let d_reclen = u16::from_ne_bytes([ + self.buf[pos + offsetof_d_reclen], + self.buf[pos + offsetof_d_reclen + 1], + ]); + assert!(self.buf.len() - pos >= d_reclen as usize); + self.pos += d_reclen as usize; + + // Read the NUL-terminated name from the `d_name` field. Without + // `unsafe`, we need to scan for the NUL twice: once to obtain a size + // for the slice, and then once within `CStr::from_bytes_with_nul`. + let name_start = pos + offsetof_d_name; + let name_len = self.buf[name_start..] + .iter() + .position(|x| *x == b'\0') + .unwrap(); + let name = + CStr::from_bytes_with_nul(&self.buf[name_start..name_start + name_len + 1]).unwrap(); + let name = name.to_owned(); + assert!(name.as_bytes().len() <= self.buf.len() - name_start); + + // Do an unaligned u64 load. + let d_ino = u64::from_ne_bytes([ + self.buf[pos + offsetof_d_ino], + self.buf[pos + offsetof_d_ino + 1], + self.buf[pos + offsetof_d_ino + 2], + self.buf[pos + offsetof_d_ino + 3], + self.buf[pos + offsetof_d_ino + 4], + self.buf[pos + offsetof_d_ino + 5], + self.buf[pos + offsetof_d_ino + 6], + self.buf[pos + offsetof_d_ino + 7], + ]); + + let d_type = self.buf[pos + offsetof_d_type]; + + // Check that our types correspond to the `linux_dirent64` types. + let _ = linux_dirent64 { + d_ino, + d_off: 0, + d_type, + d_reclen, + d_name: Default::default(), + }; + + Some(Ok(DirEntry { + d_ino, + d_type, + name, + })) + } + + fn read_more(&mut self) -> Option<io::Result<()>> { + let og_len = self.buf.len(); + // Capacity increment currently chosen by wild guess. + self.buf + .resize(self.buf.capacity() + 32 * size_of::<linux_dirent64>(), 0); + let nread = match crate::backend::fs::syscalls::getdents(self.fd.as_fd(), &mut self.buf) { + Ok(nread) => nread, + Err(err) => { + self.buf.resize(og_len, 0); + return Some(Err(err)); + } + }; + self.buf.resize(nread, 0); + self.pos = 0; + if nread == 0 { + None + } else { + Some(Ok(())) + } + } + + /// `fstat(self)` + #[inline] + pub fn stat(&self) -> io::Result<Stat> { + fstat(&self.fd) + } + + /// `fstatfs(self)` + #[inline] + pub fn statfs(&self) -> io::Result<StatFs> { + fstatfs(&self.fd) + } + + /// `fstatvfs(self)` + #[inline] + pub fn statvfs(&self) -> io::Result<StatVfs> { + fstatvfs(&self.fd) + } + + /// `fchdir(self)` + #[inline] + pub fn chdir(&self) -> io::Result<()> { + fchdir(&self.fd) + } +} + +impl Iterator for Dir { + type Item = io::Result<DirEntry>; + + #[inline] + fn next(&mut self) -> Option<Self::Item> { + Self::read(self) + } +} + +impl fmt::Debug for Dir { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Dir").field("fd", &self.fd).finish() + } +} + +/// `struct dirent` +#[derive(Debug)] +pub struct DirEntry { + d_ino: u64, + d_type: u8, + name: CString, +} + +impl DirEntry { + /// Returns the file name of this directory entry. + #[inline] + pub fn file_name(&self) -> &CStr { + &self.name + } + + /// Returns the type of this directory entry. + #[inline] + pub fn file_type(&self) -> FileType { + FileType::from_dirent_d_type(self.d_type) + } + + /// Return the inode number of this directory entry. + #[inline] + pub fn ino(&self) -> u64 { + self.d_ino + } +} diff --git a/vendor/rustix/src/imp/linux_raw/fs/makedev.rs b/vendor/rustix/src/backend/linux_raw/fs/makedev.rs index 284ba2f10..284ba2f10 100644 --- a/vendor/rustix/src/imp/linux_raw/fs/makedev.rs +++ b/vendor/rustix/src/backend/linux_raw/fs/makedev.rs diff --git a/vendor/rustix/src/backend/linux_raw/fs/mod.rs b/vendor/rustix/src/backend/linux_raw/fs/mod.rs new file mode 100644 index 000000000..015c6baec --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/fs/mod.rs @@ -0,0 +1,4 @@ +pub(crate) mod dir; +pub(crate) mod makedev; +pub(crate) mod syscalls; +pub(crate) mod types; diff --git a/vendor/rustix/src/backend/linux_raw/fs/syscalls.rs b/vendor/rustix/src/backend/linux_raw/fs/syscalls.rs new file mode 100644 index 000000000..ff58f0a7b --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/fs/syscalls.rs @@ -0,0 +1,1384 @@ +//! linux_raw syscalls supporting `rustix::fs`. +//! +//! # Safety +//! +//! See the `rustix::backend` module documentation for details. +#![allow(unsafe_code)] +#![allow(dead_code)] +#![allow(clippy::undocumented_unsafe_blocks)] + +use super::super::c; +use super::super::conv::{ + by_ref, c_int, c_uint, dev_t, oflags_for_open_how, opt_mut, pass_usize, raw_fd, ret, ret_c_int, + ret_c_uint, ret_owned_fd, ret_usize, size_of, slice_mut, zero, +}; +#[cfg(target_pointer_width = "64")] +use super::super::conv::{loff_t, loff_t_from_u64, ret_u64}; +#[cfg(any( + target_arch = "aarch64", + target_arch = "riscv64", + target_arch = "mips64", + target_pointer_width = "32", +))] +use crate::fd::AsFd; +use crate::fd::{BorrowedFd, OwnedFd}; +use crate::ffi::CStr; +use crate::fs::{ + Access, Advice, AtFlags, FallocateFlags, FileType, FlockOperation, MemfdFlags, Mode, OFlags, + RenameFlags, ResolveFlags, SealFlags, Stat, StatFs, StatVfs, StatVfsMountFlags, StatxFlags, + Timestamps, +}; +use crate::io::{self, SeekFrom}; +use crate::process::{Gid, Uid}; +use core::convert::TryInto; +use core::mem::MaybeUninit; +#[cfg(target_arch = "mips64")] +use linux_raw_sys::general::stat as linux_stat64; +use linux_raw_sys::general::{ + __kernel_fsid_t, __kernel_timespec, open_how, statx, AT_EACCESS, AT_FDCWD, AT_REMOVEDIR, + AT_SYMLINK_NOFOLLOW, F_ADD_SEALS, F_GETFL, F_GETLEASE, F_GETOWN, F_GETPIPE_SZ, F_GETSIG, + F_GET_SEALS, F_SETFL, F_SETPIPE_SZ, SEEK_CUR, SEEK_END, SEEK_SET, STATX__RESERVED, +}; +#[cfg(target_pointer_width = "32")] +use { + super::super::conv::{hi, lo, slice_just_addr}, + linux_raw_sys::general::stat64 as linux_stat64, + linux_raw_sys::general::timespec as __kernel_old_timespec, +}; + +#[inline] +pub(crate) fn open(filename: &CStr, flags: OFlags, mode: Mode) -> io::Result<OwnedFd> { + #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + { + openat(crate::fs::cwd().as_fd(), filename, flags, mode) + } + #[cfg(all( + target_pointer_width = "32", + not(any(target_arch = "aarch64", target_arch = "riscv64")), + ))] + unsafe { + ret_owned_fd(syscall_readonly!(__NR_open, filename, flags, mode)) + } + #[cfg(all( + target_pointer_width = "64", + not(any(target_arch = "aarch64", target_arch = "riscv64")), + ))] + unsafe { + ret_owned_fd(syscall_readonly!(__NR_open, filename, flags, mode)) + } +} + +#[inline] +pub(crate) fn openat( + dirfd: BorrowedFd<'_>, + filename: &CStr, + flags: OFlags, + mode: Mode, +) -> io::Result<OwnedFd> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret_owned_fd(syscall_readonly!(__NR_openat, dirfd, filename, flags, mode)) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_owned_fd(syscall_readonly!(__NR_openat, dirfd, filename, flags, mode)) + } +} + +#[inline] +pub(crate) fn openat2( + dirfd: BorrowedFd<'_>, + pathname: &CStr, + flags: OFlags, + mode: Mode, + resolve: ResolveFlags, +) -> io::Result<OwnedFd> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret_owned_fd(syscall_readonly!( + __NR_openat2, + dirfd, + pathname, + by_ref(&open_how { + flags: oflags_for_open_how(flags), + mode: u64::from(mode.bits()), + resolve: resolve.bits(), + }), + size_of::<open_how, _>() + )) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_owned_fd(syscall_readonly!( + __NR_openat2, + dirfd, + pathname, + by_ref(&open_how { + flags: oflags_for_open_how(flags), + mode: u64::from(mode.bits()), + resolve: resolve.bits(), + }), + size_of::<open_how, _>() + )) + } +} + +#[inline] +pub(crate) fn chmod(filename: &CStr, mode: Mode) -> io::Result<()> { + unsafe { + ret(syscall_readonly!( + __NR_fchmodat, + raw_fd(AT_FDCWD), + filename, + mode + )) + } +} + +#[inline] +pub(crate) fn chmodat(dirfd: BorrowedFd<'_>, filename: &CStr, mode: Mode) -> io::Result<()> { + unsafe { ret(syscall_readonly!(__NR_fchmodat, dirfd, filename, mode)) } +} + +#[inline] +pub(crate) fn fchmod(fd: BorrowedFd<'_>, mode: Mode) -> io::Result<()> { + unsafe { ret(syscall_readonly!(__NR_fchmod, fd, mode)) } +} + +#[inline] +pub(crate) fn chownat( + dirfd: BorrowedFd<'_>, + filename: &CStr, + owner: Option<Uid>, + group: Option<Gid>, + flags: AtFlags, +) -> io::Result<()> { + unsafe { + let (ow, gr) = crate::process::translate_fchown_args(owner, group); + ret(syscall_readonly!( + __NR_fchownat, + dirfd, + filename, + c_uint(ow), + c_uint(gr), + flags + )) + } +} + +#[inline] +pub(crate) fn fchown(fd: BorrowedFd<'_>, owner: Option<Uid>, group: Option<Gid>) -> io::Result<()> { + unsafe { + let (ow, gr) = crate::process::translate_fchown_args(owner, group); + ret(syscall_readonly!(__NR_fchown, fd, c_uint(ow), c_uint(gr))) + } +} + +#[inline] +pub(crate) fn mknodat( + dirfd: BorrowedFd<'_>, + filename: &CStr, + file_type: FileType, + mode: Mode, + dev: u64, +) -> io::Result<()> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret(syscall_readonly!( + __NR_mknodat, + dirfd, + filename, + (mode, file_type), + dev_t(dev)? + )) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret(syscall_readonly!( + __NR_mknodat, + dirfd, + filename, + (mode, file_type), + dev_t(dev) + )) + } +} + +#[inline] +pub(crate) fn seek(fd: BorrowedFd<'_>, pos: SeekFrom) -> io::Result<u64> { + let (whence, offset) = match pos { + SeekFrom::Start(pos) => { + let pos: u64 = pos; + // Silently cast; we'll get `EINVAL` if the value is negative. + (SEEK_SET, pos as i64) + } + SeekFrom::End(offset) => (SEEK_END, offset), + SeekFrom::Current(offset) => (SEEK_CUR, offset), + }; + _seek(fd, offset, whence) +} + +#[inline] +pub(crate) fn _seek(fd: BorrowedFd<'_>, offset: i64, whence: c::c_uint) -> io::Result<u64> { + #[cfg(target_pointer_width = "32")] + unsafe { + let mut result = MaybeUninit::<u64>::uninit(); + ret(syscall!( + __NR__llseek, + fd, + // Don't use the hi/lo functions here because Linux's llseek + // takes its 64-bit argument differently from everything else. + pass_usize((offset >> 32) as usize), + pass_usize(offset as usize), + &mut result, + c_uint(whence) + ))?; + Ok(result.assume_init()) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_u64(syscall_readonly!( + __NR_lseek, + fd, + loff_t(offset), + c_uint(whence) + )) + } +} + +#[inline] +pub(crate) fn tell(fd: BorrowedFd<'_>) -> io::Result<u64> { + _seek(fd, 0, SEEK_CUR).map(|x| x as u64) +} + +#[inline] +pub(crate) fn ftruncate(fd: BorrowedFd<'_>, length: u64) -> io::Result<()> { + // <https://github.com/torvalds/linux/blob/fcadab740480e0e0e9fa9bd272acd409884d431a/arch/arm64/kernel/sys32.c#L81-L83> + #[cfg(all( + target_pointer_width = "32", + any(target_arch = "arm", target_arch = "mips", target_arch = "powerpc"), + ))] + unsafe { + ret(syscall_readonly!( + __NR_ftruncate64, + fd, + zero(), + hi(length), + lo(length) + )) + } + #[cfg(all( + target_pointer_width = "32", + not(any(target_arch = "arm", target_arch = "mips", target_arch = "powerpc")), + ))] + unsafe { + ret(syscall_readonly!( + __NR_ftruncate64, + fd, + hi(length), + lo(length) + )) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret(syscall_readonly!( + __NR_ftruncate, + fd, + loff_t_from_u64(length) + )) + } +} + +#[inline] +pub(crate) fn fallocate( + fd: BorrowedFd<'_>, + mode: FallocateFlags, + offset: u64, + len: u64, +) -> io::Result<()> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret(syscall_readonly!( + __NR_fallocate, + fd, + mode, + hi(offset), + lo(offset), + hi(len), + lo(len) + )) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret(syscall_readonly!( + __NR_fallocate, + fd, + mode, + loff_t_from_u64(offset), + loff_t_from_u64(len) + )) + } +} + +#[inline] +pub(crate) fn fadvise(fd: BorrowedFd<'_>, pos: u64, len: u64, advice: Advice) -> io::Result<()> { + // On ARM, the arguments are reordered so that the len and pos argument + // pairs are aligned. And ARM has a custom syscall code for this. + #[cfg(target_arch = "arm")] + unsafe { + ret(syscall_readonly!( + __NR_arm_fadvise64_64, + fd, + advice, + hi(pos), + lo(pos), + hi(len), + lo(len) + )) + } + + // On powerpc, the arguments are reordered as on ARM. + #[cfg(target_arch = "powerpc")] + unsafe { + ret(syscall_readonly!( + __NR_fadvise64_64, + fd, + advice, + hi(pos), + lo(pos), + hi(len), + lo(len) + )) + } + // On mips, the arguments are not reordered, and padding is inserted + // instead to ensure alignment. + #[cfg(target_arch = "mips")] + unsafe { + ret(syscall_readonly!( + __NR_fadvise64, + fd, + zero(), + hi(pos), + lo(pos), + hi(len), + lo(len), + advice + )) + } + #[cfg(all( + target_pointer_width = "32", + not(any(target_arch = "arm", target_arch = "mips", target_arch = "powerpc")), + ))] + unsafe { + ret(syscall_readonly!( + __NR_fadvise64_64, + fd, + hi(pos), + lo(pos), + hi(len), + lo(len), + advice + )) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret(syscall_readonly!( + __NR_fadvise64, + fd, + loff_t_from_u64(pos), + loff_t_from_u64(len), + advice + )) + } +} + +#[inline] +pub(crate) fn fsync(fd: BorrowedFd<'_>) -> io::Result<()> { + unsafe { ret(syscall_readonly!(__NR_fsync, fd)) } +} + +#[inline] +pub(crate) fn fdatasync(fd: BorrowedFd<'_>) -> io::Result<()> { + unsafe { ret(syscall_readonly!(__NR_fdatasync, fd)) } +} + +#[inline] +pub(crate) fn flock(fd: BorrowedFd<'_>, operation: FlockOperation) -> io::Result<()> { + unsafe { ret(syscall!(__NR_flock, fd, c_uint(operation as c::c_uint))) } +} + +#[inline] +pub(crate) fn fstat(fd: BorrowedFd<'_>) -> io::Result<Stat> { + #[cfg(any(target_pointer_width = "32", target_arch = "mips64"))] + { + match statx(fd, cstr!(""), AtFlags::EMPTY_PATH, StatxFlags::BASIC_STATS) { + Ok(x) => statx_to_stat(x), + Err(io::Errno::NOSYS) => fstat_old(fd), + Err(err) => Err(err), + } + } + + #[cfg(all(target_pointer_width = "64", not(target_arch = "mips64")))] + unsafe { + let mut result = MaybeUninit::<Stat>::uninit(); + ret(syscall!(__NR_fstat, fd, &mut result))?; + Ok(result.assume_init()) + } +} + +#[cfg(any(target_pointer_width = "32", target_arch = "mips64"))] +fn fstat_old(fd: BorrowedFd<'_>) -> io::Result<Stat> { + let mut result = MaybeUninit::<linux_stat64>::uninit(); + + #[cfg(target_arch = "mips64")] + unsafe { + ret(syscall!(__NR_fstat, fd, &mut result))?; + stat_to_stat(result.assume_init()) + } + + #[cfg(target_pointer_width = "32")] + unsafe { + ret(syscall!(__NR_fstat64, fd, &mut result))?; + stat_to_stat(result.assume_init()) + } +} + +#[inline] +pub(crate) fn stat(filename: &CStr) -> io::Result<Stat> { + #[cfg(any(target_pointer_width = "32", target_arch = "mips64"))] + { + match statx( + crate::fs::cwd().as_fd(), + filename, + AtFlags::empty(), + StatxFlags::BASIC_STATS, + ) { + Ok(x) => statx_to_stat(x), + Err(io::Errno::NOSYS) => stat_old(filename), + Err(err) => Err(err), + } + } + + #[cfg(all(target_pointer_width = "64", not(target_arch = "mips64")))] + unsafe { + let mut result = MaybeUninit::<Stat>::uninit(); + ret(syscall!( + __NR_newfstatat, + raw_fd(AT_FDCWD), + filename, + &mut result, + c_uint(0) + ))?; + Ok(result.assume_init()) + } +} + +#[cfg(any(target_pointer_width = "32", target_arch = "mips64"))] +fn stat_old(filename: &CStr) -> io::Result<Stat> { + let mut result = MaybeUninit::<linux_stat64>::uninit(); + + #[cfg(target_arch = "mips64")] + unsafe { + ret(syscall!( + __NR_newfstatat, + raw_fd(AT_FDCWD), + filename, + &mut result, + c_uint(0) + ))?; + stat_to_stat(result.assume_init()) + } + + #[cfg(target_pointer_width = "32")] + unsafe { + ret(syscall!( + __NR_fstatat64, + raw_fd(AT_FDCWD), + filename, + &mut result, + c_uint(0) + ))?; + stat_to_stat(result.assume_init()) + } +} + +#[inline] +pub(crate) fn statat(dirfd: BorrowedFd<'_>, filename: &CStr, flags: AtFlags) -> io::Result<Stat> { + #[cfg(any(target_pointer_width = "32", target_arch = "mips64"))] + { + match statx(dirfd, filename, flags, StatxFlags::BASIC_STATS) { + Ok(x) => statx_to_stat(x), + Err(io::Errno::NOSYS) => statat_old(dirfd, filename, flags), + Err(err) => Err(err), + } + } + + #[cfg(all(target_pointer_width = "64", not(target_arch = "mips64")))] + unsafe { + let mut result = MaybeUninit::<Stat>::uninit(); + ret(syscall!( + __NR_newfstatat, + dirfd, + filename, + &mut result, + flags + ))?; + Ok(result.assume_init()) + } +} + +#[cfg(any(target_pointer_width = "32", target_arch = "mips64"))] +fn statat_old(dirfd: BorrowedFd<'_>, filename: &CStr, flags: AtFlags) -> io::Result<Stat> { + let mut result = MaybeUninit::<linux_stat64>::uninit(); + + #[cfg(target_arch = "mips64")] + unsafe { + ret(syscall!( + __NR_newfstatat, + dirfd, + filename, + &mut result, + flags + ))?; + stat_to_stat(result.assume_init()) + } + + #[cfg(target_pointer_width = "32")] + unsafe { + ret(syscall!( + __NR_fstatat64, + dirfd, + filename, + &mut result, + flags + ))?; + stat_to_stat(result.assume_init()) + } +} + +#[inline] +pub(crate) fn lstat(filename: &CStr) -> io::Result<Stat> { + #[cfg(any(target_pointer_width = "32", target_arch = "mips64"))] + { + match statx( + crate::fs::cwd().as_fd(), + filename, + AtFlags::SYMLINK_NOFOLLOW, + StatxFlags::BASIC_STATS, + ) { + Ok(x) => statx_to_stat(x), + Err(io::Errno::NOSYS) => lstat_old(filename), + Err(err) => Err(err), + } + } + + #[cfg(all(target_pointer_width = "64", not(target_arch = "mips64")))] + unsafe { + let mut result = MaybeUninit::<Stat>::uninit(); + ret(syscall!( + __NR_newfstatat, + raw_fd(AT_FDCWD), + filename, + &mut result, + c_uint(AT_SYMLINK_NOFOLLOW) + ))?; + Ok(result.assume_init()) + } +} + +#[cfg(any(target_pointer_width = "32", target_arch = "mips64"))] +fn lstat_old(filename: &CStr) -> io::Result<Stat> { + let mut result = MaybeUninit::<linux_stat64>::uninit(); + + #[cfg(target_arch = "mips64")] + unsafe { + ret(syscall!( + __NR_newfstatat, + raw_fd(AT_FDCWD), + filename, + &mut result, + c_uint(AT_SYMLINK_NOFOLLOW) + ))?; + stat_to_stat(result.assume_init()) + } + + #[cfg(target_pointer_width = "32")] + unsafe { + ret(syscall!( + __NR_fstatat64, + raw_fd(AT_FDCWD), + filename, + &mut result, + c_uint(AT_SYMLINK_NOFOLLOW) + ))?; + stat_to_stat(result.assume_init()) + } +} + +/// Convert from a Linux `statx` value to rustix's `Stat`. +#[cfg(any(target_pointer_width = "32", target_arch = "mips64"))] +fn statx_to_stat(x: crate::fs::Statx) -> io::Result<Stat> { + Ok(Stat { + st_dev: crate::fs::makedev(x.stx_dev_major, x.stx_dev_minor), + st_mode: x.stx_mode.into(), + st_nlink: x.stx_nlink.into(), + st_uid: x.stx_uid.into(), + st_gid: x.stx_gid.into(), + st_rdev: crate::fs::makedev(x.stx_rdev_major, x.stx_rdev_minor), + st_size: x.stx_size.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_blksize: x.stx_blksize.into(), + st_blocks: x.stx_blocks.into(), + st_atime: x + .stx_atime + .tv_sec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + st_atime_nsec: x.stx_atime.tv_nsec.into(), + st_mtime: x + .stx_mtime + .tv_sec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + st_mtime_nsec: x.stx_mtime.tv_nsec.into(), + st_ctime: x + .stx_ctime + .tv_sec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + st_ctime_nsec: x.stx_ctime.tv_nsec.into(), + st_ino: x.stx_ino.into(), + }) +} + +/// Convert from a Linux `stat64` value to rustix's `Stat`. +#[cfg(target_pointer_width = "32")] +fn stat_to_stat(s64: linux_raw_sys::general::stat64) -> io::Result<Stat> { + Ok(Stat { + st_dev: s64.st_dev.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_mode: s64.st_mode.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_nlink: s64.st_nlink.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_uid: s64.st_uid.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_gid: s64.st_gid.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_rdev: s64.st_rdev.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_size: s64.st_size.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_blksize: s64.st_blksize.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_blocks: s64.st_blocks.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_atime: s64.st_atime.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_atime_nsec: s64 + .st_atime_nsec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + st_mtime: s64.st_mtime.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_mtime_nsec: s64 + .st_mtime_nsec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + st_ctime: s64.st_ctime.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_ctime_nsec: s64 + .st_ctime_nsec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + st_ino: s64.st_ino.try_into().map_err(|_| io::Errno::OVERFLOW)?, + }) +} + +/// Convert from a Linux `stat` value to rustix's `Stat`. +#[cfg(target_arch = "mips64")] +fn stat_to_stat(s: linux_raw_sys::general::stat) -> io::Result<Stat> { + Ok(Stat { + st_dev: s.st_dev.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_mode: s.st_mode.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_nlink: s.st_nlink.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_uid: s.st_uid.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_gid: s.st_gid.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_rdev: s.st_rdev.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_size: s.st_size.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_blksize: s.st_blksize.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_blocks: s.st_blocks.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_atime: s.st_atime.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_atime_nsec: s + .st_atime_nsec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + st_mtime: s.st_mtime.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_mtime_nsec: s + .st_mtime_nsec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + st_ctime: s.st_ctime.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_ctime_nsec: s + .st_ctime_nsec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + st_ino: s.st_ino.try_into().map_err(|_| io::Errno::OVERFLOW)?, + }) +} + +#[inline] +pub(crate) fn statx( + dirfd: BorrowedFd<'_>, + pathname: &CStr, + flags: AtFlags, + mask: StatxFlags, +) -> io::Result<statx> { + // If a future Linux kernel adds more fields to `struct statx` and users + // passing flags unknown to rustix in `StatxFlags`, we could end up + // writing outside of the buffer. To prevent this possibility, we mask off + // any flags that we don't know about. + // + // This includes `STATX__RESERVED`, which has a value that we know, but + // which could take on arbitrary new meaning in the future. Linux currently + // rejects this flag with `EINVAL`, so we do the same. + // + // This doesn't rely on `STATX_ALL` because [it's deprecated] and already + // doesn't represent all the known flags. + // + // [it's deprecated]: https://patchwork.kernel.org/project/linux-fsdevel/patch/20200505095915.11275-7-mszeredi@redhat.com/ + if (mask.bits() & STATX__RESERVED) == STATX__RESERVED { + return Err(io::Errno::INVAL); + } + let mask = mask & StatxFlags::all(); + + unsafe { + let mut statx_buf = MaybeUninit::<statx>::uninit(); + ret(syscall!( + __NR_statx, + dirfd, + pathname, + flags, + mask, + &mut statx_buf + ))?; + Ok(statx_buf.assume_init()) + } +} + +#[inline] +pub(crate) fn is_statx_available() -> bool { + unsafe { + // Call `statx` with null pointers so that if it fails for any reason + // other than `EFAULT`, we know it's not supported. + matches!( + ret(syscall!( + __NR_statx, + raw_fd(AT_FDCWD), + zero(), + zero(), + zero(), + zero() + )), + Err(io::Errno::FAULT) + ) + } +} + +#[inline] +pub(crate) fn fstatfs(fd: BorrowedFd<'_>) -> io::Result<StatFs> { + #[cfg(target_pointer_width = "32")] + unsafe { + let mut result = MaybeUninit::<StatFs>::uninit(); + ret(syscall!( + __NR_fstatfs64, + fd, + size_of::<StatFs, _>(), + &mut result + ))?; + Ok(result.assume_init()) + } + + #[cfg(target_pointer_width = "64")] + unsafe { + let mut result = MaybeUninit::<StatFs>::uninit(); + ret(syscall!(__NR_fstatfs, fd, &mut result))?; + Ok(result.assume_init()) + } +} + +#[inline] +pub(crate) fn fstatvfs(fd: BorrowedFd<'_>) -> io::Result<StatVfs> { + // Linux doesn't have an `fstatvfs` syscall; we have to do `fstatfs` and + // translate the fields as best we can. + let statfs = fstatfs(fd)?; + + Ok(statfs_to_statvfs(statfs)) +} + +#[inline] +pub(crate) fn statfs(filename: &CStr) -> io::Result<StatFs> { + #[cfg(target_pointer_width = "32")] + unsafe { + let mut result = MaybeUninit::<StatFs>::uninit(); + ret(syscall!( + __NR_statfs64, + filename, + size_of::<StatFs, _>(), + &mut result + ))?; + Ok(result.assume_init()) + } + #[cfg(target_pointer_width = "64")] + unsafe { + let mut result = MaybeUninit::<StatFs>::uninit(); + ret(syscall!(__NR_statfs, filename, &mut result))?; + Ok(result.assume_init()) + } +} + +#[inline] +pub(crate) fn statvfs(filename: &CStr) -> io::Result<StatVfs> { + // Linux doesn't have a `statvfs` syscall; we have to do `statfs` and + // translate the fields as best we can. + let statfs = statfs(filename)?; + + Ok(statfs_to_statvfs(statfs)) +} + +fn statfs_to_statvfs(statfs: StatFs) -> StatVfs { + let __kernel_fsid_t { val } = statfs.f_fsid; + let [f_fsid_val0, f_fsid_val1]: [i32; 2] = val; + + StatVfs { + f_bsize: statfs.f_bsize as u64, + f_frsize: if statfs.f_frsize != 0 { + statfs.f_frsize + } else { + statfs.f_bsize + } as u64, + f_blocks: statfs.f_blocks as u64, + f_bfree: statfs.f_bfree as u64, + f_bavail: statfs.f_bavail as u64, + f_files: statfs.f_files as u64, + f_ffree: statfs.f_ffree as u64, + f_favail: statfs.f_ffree as u64, + f_fsid: f_fsid_val0 as u32 as u64 | ((f_fsid_val1 as u32 as u64) << 32), + f_flag: unsafe { StatVfsMountFlags::from_bits_unchecked(statfs.f_flags as u64) }, + f_namemax: statfs.f_namelen as u64, + } +} + +#[inline] +pub(crate) fn readlink(path: &CStr, buf: &mut [u8]) -> io::Result<usize> { + let (buf_addr_mut, buf_len) = slice_mut(buf); + unsafe { + ret_usize(syscall!( + __NR_readlinkat, + raw_fd(AT_FDCWD), + path, + buf_addr_mut, + buf_len + )) + } +} + +#[inline] +pub(crate) fn readlinkat(dirfd: BorrowedFd<'_>, path: &CStr, buf: &mut [u8]) -> io::Result<usize> { + let (buf_addr_mut, buf_len) = slice_mut(buf); + unsafe { + ret_usize(syscall!( + __NR_readlinkat, + dirfd, + path, + buf_addr_mut, + buf_len + )) + } +} + +#[inline] +pub(crate) fn fcntl_getfl(fd: BorrowedFd<'_>) -> io::Result<OFlags> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret_c_uint(syscall_readonly!(__NR_fcntl64, fd, c_uint(F_GETFL))) + .map(OFlags::from_bits_truncate) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_c_uint(syscall_readonly!(__NR_fcntl, fd, c_uint(F_GETFL))) + .map(OFlags::from_bits_truncate) + } +} + +#[inline] +pub(crate) fn fcntl_setfl(fd: BorrowedFd<'_>, flags: OFlags) -> io::Result<()> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret(syscall_readonly!(__NR_fcntl64, fd, c_uint(F_SETFL), flags)) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret(syscall_readonly!(__NR_fcntl, fd, c_uint(F_SETFL), flags)) + } +} + +#[inline] +pub(crate) fn fcntl_getlease(fd: BorrowedFd<'_>) -> io::Result<c::c_int> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret_c_int(syscall_readonly!(__NR_fcntl64, fd, c_uint(F_GETLEASE))) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_c_int(syscall_readonly!(__NR_fcntl, fd, c_uint(F_GETLEASE))) + } +} + +#[inline] +pub(crate) fn fcntl_getown(fd: BorrowedFd<'_>) -> io::Result<c::c_int> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret_c_int(syscall_readonly!(__NR_fcntl64, fd, c_uint(F_GETOWN))) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_c_int(syscall_readonly!(__NR_fcntl, fd, c_uint(F_GETOWN))) + } +} + +#[inline] +pub(crate) fn fcntl_getsig(fd: BorrowedFd<'_>) -> io::Result<c::c_int> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret_c_int(syscall_readonly!(__NR_fcntl64, fd, c_uint(F_GETSIG))) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_c_int(syscall_readonly!(__NR_fcntl, fd, c_uint(F_GETSIG))) + } +} + +#[inline] +pub(crate) fn fcntl_getpipe_sz(fd: BorrowedFd<'_>) -> io::Result<usize> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret_usize(syscall_readonly!(__NR_fcntl64, fd, c_uint(F_GETPIPE_SZ))) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_usize(syscall_readonly!(__NR_fcntl, fd, c_uint(F_GETPIPE_SZ))) + } +} + +#[inline] +pub(crate) fn fcntl_setpipe_sz(fd: BorrowedFd<'_>, size: c::c_int) -> io::Result<usize> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret_usize(syscall_readonly!( + __NR_fcntl64, + fd, + c_uint(F_SETPIPE_SZ), + c_int(size) + )) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_usize(syscall_readonly!( + __NR_fcntl, + fd, + c_uint(F_SETPIPE_SZ), + c_int(size) + )) + } +} + +#[inline] +pub(crate) fn fcntl_get_seals(fd: BorrowedFd<'_>) -> io::Result<SealFlags> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret_c_int(syscall_readonly!(__NR_fcntl64, fd, c_uint(F_GET_SEALS))) + .map(|seals| SealFlags::from_bits_unchecked(seals as u32)) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_c_int(syscall_readonly!(__NR_fcntl, fd, c_uint(F_GET_SEALS))) + .map(|seals| SealFlags::from_bits_unchecked(seals as u32)) + } +} + +#[inline] +pub(crate) fn fcntl_add_seals(fd: BorrowedFd<'_>, seals: SealFlags) -> io::Result<()> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret(syscall_readonly!( + __NR_fcntl64, + fd, + c_uint(F_ADD_SEALS), + seals + )) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret(syscall_readonly!( + __NR_fcntl, + fd, + c_uint(F_ADD_SEALS), + seals + )) + } +} + +#[inline] +pub(crate) fn rename(oldname: &CStr, newname: &CStr) -> io::Result<()> { + #[cfg(target_arch = "riscv64")] + unsafe { + ret(syscall_readonly!( + __NR_renameat2, + raw_fd(AT_FDCWD), + oldname, + raw_fd(AT_FDCWD), + newname, + c_uint(0) + )) + } + #[cfg(not(target_arch = "riscv64"))] + unsafe { + ret(syscall_readonly!( + __NR_renameat, + raw_fd(AT_FDCWD), + oldname, + raw_fd(AT_FDCWD), + newname + )) + } +} + +#[inline] +pub(crate) fn renameat( + old_dirfd: BorrowedFd<'_>, + oldname: &CStr, + new_dirfd: BorrowedFd<'_>, + newname: &CStr, +) -> io::Result<()> { + #[cfg(target_arch = "riscv64")] + unsafe { + ret(syscall_readonly!( + __NR_renameat2, + old_dirfd, + oldname, + new_dirfd, + newname, + c_uint(0) + )) + } + #[cfg(not(target_arch = "riscv64"))] + unsafe { + ret(syscall_readonly!( + __NR_renameat, + old_dirfd, + oldname, + new_dirfd, + newname + )) + } +} + +#[inline] +pub(crate) fn renameat2( + old_dirfd: BorrowedFd<'_>, + oldname: &CStr, + new_dirfd: BorrowedFd<'_>, + newname: &CStr, + flags: RenameFlags, +) -> io::Result<()> { + unsafe { + ret(syscall_readonly!( + __NR_renameat2, + old_dirfd, + oldname, + new_dirfd, + newname, + flags + )) + } +} + +#[inline] +pub(crate) fn unlink(pathname: &CStr) -> io::Result<()> { + unsafe { + ret(syscall_readonly!( + __NR_unlinkat, + raw_fd(AT_FDCWD), + pathname, + c_uint(0) + )) + } +} + +#[inline] +pub(crate) fn unlinkat(dirfd: BorrowedFd<'_>, pathname: &CStr, flags: AtFlags) -> io::Result<()> { + unsafe { ret(syscall_readonly!(__NR_unlinkat, dirfd, pathname, flags)) } +} + +#[inline] +pub(crate) fn rmdir(pathname: &CStr) -> io::Result<()> { + unsafe { + ret(syscall_readonly!( + __NR_unlinkat, + raw_fd(AT_FDCWD), + pathname, + c_uint(AT_REMOVEDIR) + )) + } +} + +#[inline] +pub(crate) fn link(oldname: &CStr, newname: &CStr) -> io::Result<()> { + unsafe { + ret(syscall_readonly!( + __NR_linkat, + raw_fd(AT_FDCWD), + oldname, + raw_fd(AT_FDCWD), + newname, + c_uint(0) + )) + } +} + +#[inline] +pub(crate) fn linkat( + old_dirfd: BorrowedFd<'_>, + oldname: &CStr, + new_dirfd: BorrowedFd<'_>, + newname: &CStr, + flags: AtFlags, +) -> io::Result<()> { + unsafe { + ret(syscall_readonly!( + __NR_linkat, + old_dirfd, + oldname, + new_dirfd, + newname, + flags + )) + } +} + +#[inline] +pub(crate) fn symlink(oldname: &CStr, newname: &CStr) -> io::Result<()> { + unsafe { + ret(syscall_readonly!( + __NR_symlinkat, + oldname, + raw_fd(AT_FDCWD), + newname + )) + } +} + +#[inline] +pub(crate) fn symlinkat(oldname: &CStr, dirfd: BorrowedFd<'_>, newname: &CStr) -> io::Result<()> { + unsafe { ret(syscall_readonly!(__NR_symlinkat, oldname, dirfd, newname)) } +} + +#[inline] +pub(crate) fn mkdir(pathname: &CStr, mode: Mode) -> io::Result<()> { + unsafe { + ret(syscall_readonly!( + __NR_mkdirat, + raw_fd(AT_FDCWD), + pathname, + mode + )) + } +} + +#[inline] +pub(crate) fn mkdirat(dirfd: BorrowedFd<'_>, pathname: &CStr, mode: Mode) -> io::Result<()> { + unsafe { ret(syscall_readonly!(__NR_mkdirat, dirfd, pathname, mode)) } +} + +#[inline] +pub(crate) fn getdents(fd: BorrowedFd<'_>, dirent: &mut [u8]) -> io::Result<usize> { + let (dirent_addr_mut, dirent_len) = slice_mut(dirent); + + unsafe { ret_usize(syscall!(__NR_getdents64, fd, dirent_addr_mut, dirent_len)) } +} + +#[inline] +pub(crate) fn utimensat( + dirfd: BorrowedFd<'_>, + pathname: &CStr, + times: &Timestamps, + flags: AtFlags, +) -> io::Result<()> { + _utimensat(dirfd, Some(pathname), times, flags) +} + +#[inline] +fn _utimensat( + dirfd: BorrowedFd<'_>, + pathname: Option<&CStr>, + times: &Timestamps, + flags: AtFlags, +) -> io::Result<()> { + // Assert that `Timestamps` has the expected layout. + let _ = unsafe { core::mem::transmute::<Timestamps, [__kernel_timespec; 2]>(times.clone()) }; + + #[cfg(target_pointer_width = "32")] + unsafe { + match ret(syscall_readonly!( + __NR_utimensat_time64, + dirfd, + pathname, + by_ref(times), + flags + )) { + Err(io::Errno::NOSYS) => _utimensat_old(dirfd, pathname, times, flags), + otherwise => otherwise, + } + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret(syscall_readonly!( + __NR_utimensat, + dirfd, + pathname, + by_ref(times), + flags + )) + } +} + +#[cfg(target_pointer_width = "32")] +unsafe fn _utimensat_old( + dirfd: BorrowedFd<'_>, + pathname: Option<&CStr>, + times: &Timestamps, + flags: AtFlags, +) -> io::Result<()> { + // See the comments in `rustix_clock_gettime_via_syscall` about + // emulation. + let old_times = [ + __kernel_old_timespec { + tv_sec: times + .last_access + .tv_sec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + tv_nsec: times + .last_access + .tv_nsec + .try_into() + .map_err(|_| io::Errno::INVAL)?, + }, + __kernel_old_timespec { + tv_sec: times + .last_modification + .tv_sec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + tv_nsec: times + .last_modification + .tv_nsec + .try_into() + .map_err(|_| io::Errno::INVAL)?, + }, + ]; + // The length of the array is fixed and not passed into the syscall. + let old_times_addr = slice_just_addr(&old_times); + ret(syscall_readonly!( + __NR_utimensat, + dirfd, + pathname, + old_times_addr, + flags + )) +} + +#[inline] +pub(crate) fn futimens(fd: BorrowedFd<'_>, times: &Timestamps) -> io::Result<()> { + _utimensat(fd, None, times, AtFlags::empty()) +} + +pub(crate) fn accessat( + dirfd: BorrowedFd<'_>, + path: &CStr, + access: Access, + flags: AtFlags, +) -> io::Result<()> { + // Linux's `faccessat` doesn't have a flags parameter. If we have + // `AT_EACCESS` and we're not setuid or setgid, we can emulate it. + if flags.is_empty() + || (flags.bits() == AT_EACCESS + && crate::process::getuid() == crate::process::geteuid() + && crate::process::getgid() == crate::process::getegid()) + { + return unsafe { ret(syscall_readonly!(__NR_faccessat, dirfd, path, access)) }; + } + + if flags.bits() != AT_EACCESS { + return Err(io::Errno::INVAL); + } + + // TODO: Use faccessat2 in newer Linux versions. + Err(io::Errno::NOSYS) +} + +#[inline] +pub(crate) fn copy_file_range( + fd_in: BorrowedFd<'_>, + off_in: Option<&mut u64>, + fd_out: BorrowedFd<'_>, + off_out: Option<&mut u64>, + len: u64, +) -> io::Result<u64> { + let len: usize = len.try_into().unwrap_or(usize::MAX); + _copy_file_range(fd_in, off_in, fd_out, off_out, len, 0).map(|result| result as u64) +} + +#[inline] +fn _copy_file_range( + fd_in: BorrowedFd<'_>, + off_in: Option<&mut u64>, + fd_out: BorrowedFd<'_>, + off_out: Option<&mut u64>, + len: usize, + flags: c::c_uint, +) -> io::Result<usize> { + unsafe { + ret_usize(syscall!( + __NR_copy_file_range, + fd_in, + opt_mut(off_in), + fd_out, + opt_mut(off_out), + pass_usize(len), + c_uint(flags) + )) + } +} + +#[inline] +pub(crate) fn memfd_create(name: &CStr, flags: MemfdFlags) -> io::Result<OwnedFd> { + unsafe { ret_owned_fd(syscall_readonly!(__NR_memfd_create, name, flags)) } +} + +#[inline] +pub(crate) fn sendfile( + out_fd: BorrowedFd<'_>, + in_fd: BorrowedFd<'_>, + offset: Option<&mut u64>, + count: usize, +) -> io::Result<usize> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret_usize(syscall!( + __NR_sendfile64, + out_fd, + in_fd, + opt_mut(offset), + pass_usize(count) + )) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_usize(syscall!( + __NR_sendfile, + out_fd, + in_fd, + opt_mut(offset), + pass_usize(count) + )) + } +} diff --git a/vendor/rustix/src/backend/linux_raw/fs/types.rs b/vendor/rustix/src/backend/linux_raw/fs/types.rs new file mode 100644 index 000000000..a8d225ede --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/fs/types.rs @@ -0,0 +1,646 @@ +use super::super::c; +use bitflags::bitflags; + +bitflags! { + /// `*_OK` constants for use with [`accessat`]. + /// + /// [`accessat`]: fn.accessat.html + pub struct Access: c::c_uint { + /// `R_OK` + const READ_OK = linux_raw_sys::general::R_OK; + + /// `W_OK` + const WRITE_OK = linux_raw_sys::general::W_OK; + + /// `X_OK` + const EXEC_OK = linux_raw_sys::general::X_OK; + + /// `F_OK` + const EXISTS = linux_raw_sys::general::F_OK; + } +} + +bitflags! { + /// `AT_*` constants for use with [`openat`], [`statat`], and other `*at` + /// functions. + /// + /// [`openat`]: crate::fs::openat + /// [`statat`]: crate::fs::statat + pub struct AtFlags: c::c_uint { + /// `AT_REMOVEDIR` + const REMOVEDIR = linux_raw_sys::general::AT_REMOVEDIR; + + /// `AT_SYMLINK_FOLLOW` + const SYMLINK_FOLLOW = linux_raw_sys::general::AT_SYMLINK_FOLLOW; + + /// `AT_SYMLINK_NOFOLLOW` + const SYMLINK_NOFOLLOW = linux_raw_sys::general::AT_SYMLINK_NOFOLLOW; + + /// `AT_EMPTY_PATH` + const EMPTY_PATH = linux_raw_sys::general::AT_EMPTY_PATH; + + /// `AT_EACCESS` + const EACCESS = linux_raw_sys::general::AT_EACCESS; + + /// `AT_STATX_SYNC_AS_STAT` + const STATX_SYNC_AS_STAT = linux_raw_sys::general::AT_STATX_SYNC_AS_STAT; + + /// `AT_STATX_FORCE_SYNC` + const STATX_FORCE_SYNC = linux_raw_sys::general::AT_STATX_FORCE_SYNC; + + /// `AT_STATX_DONT_SYNC` + const STATX_DONT_SYNC = linux_raw_sys::general::AT_STATX_DONT_SYNC; + } +} + +bitflags! { + /// `S_I*` constants for use with [`openat`], [`chmodat`], and [`fchmod`]. + /// + /// [`openat`]: crate::fs::openat + /// [`chmodat`]: crate::fs::chmodat + /// [`fchmod`]: crate::fs::fchmod + pub struct Mode: RawMode { + /// `S_IRWXU` + const RWXU = linux_raw_sys::general::S_IRWXU; + + /// `S_IRUSR` + const RUSR = linux_raw_sys::general::S_IRUSR; + + /// `S_IWUSR` + const WUSR = linux_raw_sys::general::S_IWUSR; + + /// `S_IXUSR` + const XUSR = linux_raw_sys::general::S_IXUSR; + + /// `S_IRWXG` + const RWXG = linux_raw_sys::general::S_IRWXG; + + /// `S_IRGRP` + const RGRP = linux_raw_sys::general::S_IRGRP; + + /// `S_IWGRP` + const WGRP = linux_raw_sys::general::S_IWGRP; + + /// `S_IXGRP` + const XGRP = linux_raw_sys::general::S_IXGRP; + + /// `S_IRWXO` + const RWXO = linux_raw_sys::general::S_IRWXO; + + /// `S_IROTH` + const ROTH = linux_raw_sys::general::S_IROTH; + + /// `S_IWOTH` + const WOTH = linux_raw_sys::general::S_IWOTH; + + /// `S_IXOTH` + const XOTH = linux_raw_sys::general::S_IXOTH; + + /// `S_ISUID` + const SUID = linux_raw_sys::general::S_ISUID; + + /// `S_ISGID` + const SGID = linux_raw_sys::general::S_ISGID; + + /// `S_ISVTX` + const SVTX = linux_raw_sys::general::S_ISVTX; + } +} + +impl Mode { + /// Construct a `Mode` from the mode bits of the `st_mode` field of a + /// `Stat`. + #[inline] + pub const fn from_raw_mode(st_mode: RawMode) -> Self { + Self::from_bits_truncate(st_mode) + } + + /// Construct an `st_mode` value from `Stat`. + #[inline] + pub const fn as_raw_mode(self) -> RawMode { + self.bits() + } +} + +bitflags! { + /// `O_*` constants for use with [`openat`]. + /// + /// [`openat`]: crate::fs::openat + pub struct OFlags: c::c_uint { + /// `O_ACCMODE` + const ACCMODE = linux_raw_sys::general::O_ACCMODE; + + /// Similar to `ACCMODE`, but just includes the read/write flags, and + /// no other flags. + /// + /// Some implementations include `O_PATH` in `O_ACCMODE`, when + /// sometimes we really just want the read/write bits. Caution is + /// indicated, as the presence of `O_PATH` may mean that the read/write + /// bits don't have their usual meaning. + const RWMODE = linux_raw_sys::general::O_RDONLY | + linux_raw_sys::general::O_WRONLY | + linux_raw_sys::general::O_RDWR; + + /// `O_APPEND` + const APPEND = linux_raw_sys::general::O_APPEND; + + /// `O_CREAT` + #[doc(alias = "CREAT")] + const CREATE = linux_raw_sys::general::O_CREAT; + + /// `O_DIRECTORY` + const DIRECTORY = linux_raw_sys::general::O_DIRECTORY; + + /// `O_DSYNC`. Linux 2.6.32 only supports `O_SYNC`. + const DSYNC = linux_raw_sys::general::O_SYNC; + + /// `O_EXCL` + const EXCL = linux_raw_sys::general::O_EXCL; + + /// `O_FSYNC`. Linux 2.6.32 only supports `O_SYNC`. + const FSYNC = linux_raw_sys::general::O_SYNC; + + /// `O_NOFOLLOW` + const NOFOLLOW = linux_raw_sys::general::O_NOFOLLOW; + + /// `O_NONBLOCK` + const NONBLOCK = linux_raw_sys::general::O_NONBLOCK; + + /// `O_RDONLY` + const RDONLY = linux_raw_sys::general::O_RDONLY; + + /// `O_WRONLY` + const WRONLY = linux_raw_sys::general::O_WRONLY; + + /// `O_RDWR` + const RDWR = linux_raw_sys::general::O_RDWR; + + /// `O_NOCTTY` + const NOCTTY = linux_raw_sys::general::O_NOCTTY; + + /// `O_RSYNC`. Linux 2.6.32 only supports `O_SYNC`. + const RSYNC = linux_raw_sys::general::O_SYNC; + + /// `O_SYNC` + const SYNC = linux_raw_sys::general::O_SYNC; + + /// `O_TRUNC` + const TRUNC = linux_raw_sys::general::O_TRUNC; + + /// `O_PATH` + const PATH = linux_raw_sys::general::O_PATH; + + /// `O_CLOEXEC` + const CLOEXEC = linux_raw_sys::general::O_CLOEXEC; + + /// `O_TMPFILE` + const TMPFILE = linux_raw_sys::general::O_TMPFILE; + + /// `O_NOATIME` + const NOATIME = linux_raw_sys::general::O_NOATIME; + } +} + +bitflags! { + /// `RESOLVE_*` constants for use with [`openat2`]. + /// + /// [`openat2`]: crate::fs::openat2 + #[derive(Default)] + pub struct ResolveFlags: u64 { + /// `RESOLVE_NO_XDEV` + const NO_XDEV = linux_raw_sys::general::RESOLVE_NO_XDEV as u64; + + /// `RESOLVE_NO_MAGICLINKS` + const NO_MAGICLINKS = linux_raw_sys::general::RESOLVE_NO_MAGICLINKS as u64; + + /// `RESOLVE_NO_SYMLINKS` + const NO_SYMLINKS = linux_raw_sys::general::RESOLVE_NO_SYMLINKS as u64; + + /// `RESOLVE_BENEATH` + const BENEATH = linux_raw_sys::general::RESOLVE_BENEATH as u64; + + /// `RESOLVE_IN_ROOT` + const IN_ROOT = linux_raw_sys::general::RESOLVE_IN_ROOT as u64; + + /// `RESOLVE_CACHED` (since Linux 5.12) + const CACHED = linux_raw_sys::general::RESOLVE_CACHED as u64; + } +} + +bitflags! { + /// `RENAME_*` constants for use with [`renameat_with`]. + /// + /// [`renameat_with`]: crate::fs::renameat_with + pub struct RenameFlags: c::c_uint { + /// `RENAME_EXCHANGE` + const EXCHANGE = linux_raw_sys::general::RENAME_EXCHANGE; + + /// `RENAME_NOREPLACE` + const NOREPLACE = linux_raw_sys::general::RENAME_NOREPLACE; + + /// `RENAME_WHITEOUT` + const WHITEOUT = linux_raw_sys::general::RENAME_WHITEOUT; + } +} + +/// `S_IF*` constants for use with [`mknodat`] and [`Stat`]'s `st_mode` field. +/// +/// [`mknodat`]: crate::fs::mknodat +/// [`Stat`]: crate::fs::Stat +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum FileType { + /// `S_IFREG` + RegularFile = linux_raw_sys::general::S_IFREG as isize, + + /// `S_IFDIR` + Directory = linux_raw_sys::general::S_IFDIR as isize, + + /// `S_IFLNK` + Symlink = linux_raw_sys::general::S_IFLNK as isize, + + /// `S_IFIFO` + Fifo = linux_raw_sys::general::S_IFIFO as isize, + + /// `S_IFSOCK` + Socket = linux_raw_sys::general::S_IFSOCK as isize, + + /// `S_IFCHR` + CharacterDevice = linux_raw_sys::general::S_IFCHR as isize, + + /// `S_IFBLK` + BlockDevice = linux_raw_sys::general::S_IFBLK as isize, + + /// An unknown filesystem object. + Unknown, +} + +impl FileType { + /// Construct a `FileType` from the `S_IFMT` bits of the `st_mode` field of + /// a `Stat`. + #[inline] + pub const fn from_raw_mode(st_mode: RawMode) -> Self { + match st_mode & linux_raw_sys::general::S_IFMT { + linux_raw_sys::general::S_IFREG => Self::RegularFile, + linux_raw_sys::general::S_IFDIR => Self::Directory, + linux_raw_sys::general::S_IFLNK => Self::Symlink, + linux_raw_sys::general::S_IFIFO => Self::Fifo, + linux_raw_sys::general::S_IFSOCK => Self::Socket, + linux_raw_sys::general::S_IFCHR => Self::CharacterDevice, + linux_raw_sys::general::S_IFBLK => Self::BlockDevice, + _ => Self::Unknown, + } + } + + /// Construct an `st_mode` value from `Stat`. + #[inline] + pub const fn as_raw_mode(self) -> RawMode { + match self { + Self::RegularFile => linux_raw_sys::general::S_IFREG, + Self::Directory => linux_raw_sys::general::S_IFDIR, + Self::Symlink => linux_raw_sys::general::S_IFLNK, + Self::Fifo => linux_raw_sys::general::S_IFIFO, + Self::Socket => linux_raw_sys::general::S_IFSOCK, + Self::CharacterDevice => linux_raw_sys::general::S_IFCHR, + Self::BlockDevice => linux_raw_sys::general::S_IFBLK, + Self::Unknown => linux_raw_sys::general::S_IFMT, + } + } + + /// Construct a `FileType` from the `d_type` field of a `dirent`. + #[inline] + pub(crate) const fn from_dirent_d_type(d_type: u8) -> Self { + match d_type as u32 { + linux_raw_sys::general::DT_REG => Self::RegularFile, + linux_raw_sys::general::DT_DIR => Self::Directory, + linux_raw_sys::general::DT_LNK => Self::Symlink, + linux_raw_sys::general::DT_SOCK => Self::Socket, + linux_raw_sys::general::DT_FIFO => Self::Fifo, + linux_raw_sys::general::DT_CHR => Self::CharacterDevice, + linux_raw_sys::general::DT_BLK => Self::BlockDevice, + // linux_raw_sys::general::DT_UNKNOWN | + _ => Self::Unknown, + } + } +} + +/// `POSIX_FADV_*` constants for use with [`fadvise`]. +/// +/// [`fadvise`]: crate::fs::fadvise +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[repr(u32)] +pub enum Advice { + /// `POSIX_FADV_NORMAL` + Normal = linux_raw_sys::general::POSIX_FADV_NORMAL, + + /// `POSIX_FADV_SEQUENTIAL` + Sequential = linux_raw_sys::general::POSIX_FADV_SEQUENTIAL, + + /// `POSIX_FADV_RANDOM` + Random = linux_raw_sys::general::POSIX_FADV_RANDOM, + + /// `POSIX_FADV_NOREUSE` + NoReuse = linux_raw_sys::general::POSIX_FADV_NOREUSE, + + /// `POSIX_FADV_WILLNEED` + WillNeed = linux_raw_sys::general::POSIX_FADV_WILLNEED, + + /// `POSIX_FADV_DONTNEED` + DontNeed = linux_raw_sys::general::POSIX_FADV_DONTNEED, +} + +bitflags! { + /// `MFD_*` constants for use with [`memfd_create`]. + /// + /// [`memfd_create`]: crate::fs::memfd_create + pub struct MemfdFlags: c::c_uint { + /// `MFD_CLOEXEC` + const CLOEXEC = linux_raw_sys::general::MFD_CLOEXEC; + + /// `MFD_ALLOW_SEALING` + const ALLOW_SEALING = linux_raw_sys::general::MFD_ALLOW_SEALING; + + /// `MFD_HUGETLB` (since Linux 4.14) + const HUGETLB = linux_raw_sys::general::MFD_HUGETLB; + + /// `MFD_HUGE_64KB` + const HUGE_64KB = linux_raw_sys::general::MFD_HUGE_64KB; + /// `MFD_HUGE_512JB` + const HUGE_512KB = linux_raw_sys::general::MFD_HUGE_512KB; + /// `MFD_HUGE_1MB` + const HUGE_1MB = linux_raw_sys::general::MFD_HUGE_1MB; + /// `MFD_HUGE_2MB` + const HUGE_2MB = linux_raw_sys::general::MFD_HUGE_2MB; + /// `MFD_HUGE_8MB` + const HUGE_8MB = linux_raw_sys::general::MFD_HUGE_8MB; + /// `MFD_HUGE_16MB` + const HUGE_16MB = linux_raw_sys::general::MFD_HUGE_16MB; + /// `MFD_HUGE_32MB` + const HUGE_32MB = linux_raw_sys::general::MFD_HUGE_32MB; + /// `MFD_HUGE_256MB` + const HUGE_256MB = linux_raw_sys::general::MFD_HUGE_256MB; + /// `MFD_HUGE_512MB` + const HUGE_512MB = linux_raw_sys::general::MFD_HUGE_512MB; + /// `MFD_HUGE_1GB` + const HUGE_1GB = linux_raw_sys::general::MFD_HUGE_1GB; + /// `MFD_HUGE_2GB` + const HUGE_2GB = linux_raw_sys::general::MFD_HUGE_2GB; + /// `MFD_HUGE_16GB` + const HUGE_16GB = linux_raw_sys::general::MFD_HUGE_16GB; + } +} + +bitflags! { + /// `F_SEAL_*` constants for use with [`fcntl_add_seals`] and + /// [`fcntl_get_seals`]. + /// + /// [`fcntl_add_seals`]: crate::fs::fcntl_add_seals + /// [`fcntl_get_seals`]: crate::fs::fcntl_get_seals + pub struct SealFlags: u32 { + /// `F_SEAL_SEAL`. + const SEAL = linux_raw_sys::general::F_SEAL_SEAL; + /// `F_SEAL_SHRINK`. + const SHRINK = linux_raw_sys::general::F_SEAL_SHRINK; + /// `F_SEAL_GROW`. + const GROW = linux_raw_sys::general::F_SEAL_GROW; + /// `F_SEAL_WRITE`. + const WRITE = linux_raw_sys::general::F_SEAL_WRITE; + /// `F_SEAL_FUTURE_WRITE` (since Linux 5.1) + const FUTURE_WRITE = linux_raw_sys::general::F_SEAL_FUTURE_WRITE; + } +} + +bitflags! { + /// `STATX_*` constants for use with [`statx`]. + /// + /// [`statx`]: crate::fs::statx + pub struct StatxFlags: u32 { + /// `STATX_TYPE` + const TYPE = linux_raw_sys::general::STATX_TYPE; + + /// `STATX_MODE` + const MODE = linux_raw_sys::general::STATX_MODE; + + /// `STATX_NLINK` + const NLINK = linux_raw_sys::general::STATX_NLINK; + + /// `STATX_UID` + const UID = linux_raw_sys::general::STATX_UID; + + /// `STATX_GID` + const GID = linux_raw_sys::general::STATX_GID; + + /// `STATX_ATIME` + const ATIME = linux_raw_sys::general::STATX_ATIME; + + /// `STATX_MTIME` + const MTIME = linux_raw_sys::general::STATX_MTIME; + + /// `STATX_CTIME` + const CTIME = linux_raw_sys::general::STATX_CTIME; + + /// `STATX_INO` + const INO = linux_raw_sys::general::STATX_INO; + + /// `STATX_SIZE` + const SIZE = linux_raw_sys::general::STATX_SIZE; + + /// `STATX_BLOCKS` + const BLOCKS = linux_raw_sys::general::STATX_BLOCKS; + + /// `STATX_BASIC_STATS` + const BASIC_STATS = linux_raw_sys::general::STATX_BASIC_STATS; + + /// `STATX_BTIME` + const BTIME = linux_raw_sys::general::STATX_BTIME; + + /// `STATX_MNT_ID` (since Linux 5.8) + const MNT_ID = linux_raw_sys::general::STATX_MNT_ID; + + /// `STATX_ALL` + const ALL = linux_raw_sys::general::STATX_ALL; + } +} + +bitflags! { + /// `FALLOC_FL_*` constants for use with [`fallocate`]. + /// + /// [`fallocate`]: crate::fs::fallocate + pub struct FallocateFlags: u32 { + /// `FALLOC_FL_KEEP_SIZE` + const KEEP_SIZE = linux_raw_sys::general::FALLOC_FL_KEEP_SIZE; + /// `FALLOC_FL_PUNCH_HOLE` + const PUNCH_HOLE = linux_raw_sys::general::FALLOC_FL_PUNCH_HOLE; + /// `FALLOC_FL_NO_HIDE_STALE` + const NO_HIDE_STALE = linux_raw_sys::general::FALLOC_FL_NO_HIDE_STALE; + /// `FALLOC_FL_COLLAPSE_RANGE` + const COLLAPSE_RANGE = linux_raw_sys::general::FALLOC_FL_COLLAPSE_RANGE; + /// `FALLOC_FL_ZERO_RANGE` + const ZERO_RANGE = linux_raw_sys::general::FALLOC_FL_ZERO_RANGE; + /// `FALLOC_FL_INSERT_RANGE` + const INSERT_RANGE = linux_raw_sys::general::FALLOC_FL_INSERT_RANGE; + /// `FALLOC_FL_UNSHARE_RANGE` + const UNSHARE_RANGE = linux_raw_sys::general::FALLOC_FL_UNSHARE_RANGE; + } +} + +bitflags! { + /// `ST_*` constants for use with [`StatVfs`]. + pub struct StatVfsMountFlags: u64 { + /// `ST_MANDLOCK` + const MANDLOCK = linux_raw_sys::general::MS_MANDLOCK as u64; + + /// `ST_NOATIME` + const NOATIME = linux_raw_sys::general::MS_NOATIME as u64; + + /// `ST_NODEV` + const NODEV = linux_raw_sys::general::MS_NODEV as u64; + + /// `ST_NODIRATIME` + const NODIRATIME = linux_raw_sys::general::MS_NODIRATIME as u64; + + /// `ST_NOEXEC` + const NOEXEC = linux_raw_sys::general::MS_NOEXEC as u64; + + /// `ST_NOSUID` + const NOSUID = linux_raw_sys::general::MS_NOSUID as u64; + + /// `ST_RDONLY` + const RDONLY = linux_raw_sys::general::MS_RDONLY as u64; + + /// `ST_RELATIME` + const RELATIME = linux_raw_sys::general::MS_RELATIME as u64; + + /// `ST_SYNCHRONOUS` + const SYNCHRONOUS = linux_raw_sys::general::MS_SYNCHRONOUS as u64; + } +} + +/// `LOCK_*` constants for use with [`flock`] +/// +/// [`flock`]: crate::fs::flock +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[repr(u32)] +pub enum FlockOperation { + /// `LOCK_SH` + LockShared = linux_raw_sys::general::LOCK_SH, + /// `LOCK_EX` + LockExclusive = linux_raw_sys::general::LOCK_EX, + /// `LOCK_UN` + Unlock = linux_raw_sys::general::LOCK_UN, + /// `LOCK_SH | LOCK_NB` + NonBlockingLockShared = linux_raw_sys::general::LOCK_SH | linux_raw_sys::general::LOCK_NB, + /// `LOCK_EX | LOCK_NB` + NonBlockingLockExclusive = linux_raw_sys::general::LOCK_EX | linux_raw_sys::general::LOCK_NB, + /// `LOCK_UN | LOCK_NB` + NonBlockingUnlock = linux_raw_sys::general::LOCK_UN | linux_raw_sys::general::LOCK_NB, +} + +/// `struct stat` for use with [`statat`] and [`fstat`]. +/// +/// [`statat`]: crate::fs::statat +/// [`fstat`]: crate::fs::fstat +// On 32-bit, and mips64, Linux's `struct stat64` has a 32-bit `st_mtime` and +// friends, so we use our own struct, populated from `statx` where possible, to +// avoid the y2038 bug. +#[cfg(any(target_pointer_width = "32", target_arch = "mips64"))] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +#[allow(missing_docs)] +pub struct Stat { + pub st_dev: u64, + pub st_mode: u32, + pub st_nlink: u32, + pub st_uid: u32, + pub st_gid: u32, + pub st_rdev: u64, + pub st_size: i64, + pub st_blksize: u32, + pub st_blocks: u64, + pub st_atime: u64, + pub st_atime_nsec: u32, + pub st_mtime: u64, + pub st_mtime_nsec: u32, + pub st_ctime: u64, + pub st_ctime_nsec: u32, + pub st_ino: u64, +} + +/// `struct stat` for use with [`statat`] and [`fstat`]. +/// +/// [`statat`]: crate::fs::statat +/// [`fstat`]: crate::fs::fstat +#[cfg(all(target_pointer_width = "64", not(target_arch = "mips64")))] +pub type Stat = linux_raw_sys::general::stat; + +/// `struct statfs` for use with [`statfs`] and [`fstatfs`]. +/// +/// [`statfs`]: crate::fs::statfs +/// [`fstatfs`]: crate::fs::fstatfs +#[allow(clippy::module_name_repetitions)] +pub type StatFs = linux_raw_sys::general::statfs64; + +/// `struct statvfs` for use with [`statvfs`] and [`fstatvfs`]. +/// +/// [`statvfs`]: crate::fs::statvfs +/// [`fstatvfs`]: crate::fs::fstatvfs +#[allow(missing_docs)] +pub struct StatVfs { + pub f_bsize: u64, + pub f_frsize: u64, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + pub f_fsid: u64, + pub f_flag: StatVfsMountFlags, + pub f_namemax: u64, +} + +/// `struct statx` for use with [`statx`]. +/// +/// [`statx`]: crate::fs::statx +pub type Statx = linux_raw_sys::general::statx; + +/// `struct statx_timestamp` for use with [`Statx`]. +pub type StatxTimestamp = linux_raw_sys::general::statx_timestamp; + +/// `mode_t` +#[cfg(not(any( + target_arch = "x86", + target_arch = "sparc", + target_arch = "avr", + target_arch = "arm", +)))] +pub type RawMode = linux_raw_sys::general::__kernel_mode_t; + +/// `mode_t +#[cfg(any( + target_arch = "x86", + target_arch = "sparc", + target_arch = "avr", + target_arch = "arm", +))] +// Don't use `__kernel_mode_t` since it's `u16` which differs from `st_size`. +pub type RawMode = c::c_uint; + +/// `dev_t` +// Within the kernel the dev_t is 32-bit, but userspace uses a 64-bit field. +pub type Dev = u64; + +/// `__fsword_t` +#[cfg(not(target_arch = "mips64"))] +pub type FsWord = linux_raw_sys::general::__fsword_t; + +/// `__fsword_t` +#[cfg(target_arch = "mips64")] +pub type FsWord = i64; + +pub use linux_raw_sys::general::{UTIME_NOW, UTIME_OMIT}; + +/// `PROC_SUPER_MAGIC`—The magic number for the procfs filesystem. +pub const PROC_SUPER_MAGIC: FsWord = linux_raw_sys::general::PROC_SUPER_MAGIC as FsWord; + +/// `NFS_SUPER_MAGIC`—The magic number for the NFS filesystem. +pub const NFS_SUPER_MAGIC: FsWord = linux_raw_sys::general::NFS_SUPER_MAGIC as FsWord; diff --git a/vendor/rustix/src/backend/linux_raw/io/epoll.rs b/vendor/rustix/src/backend/linux_raw/io/epoll.rs new file mode 100644 index 000000000..d55ad75b1 --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/io/epoll.rs @@ -0,0 +1,555 @@ +//! epoll support. +//! +//! This is an experiment, and it isn't yet clear whether epoll is the right +//! level of abstraction at which to introduce safety. But it works fairly well +//! in simple examples 🙂. +//! +//! # Examples +//! +//! ```rust,no_run +//! # #![cfg_attr(io_lifetimes_use_std, feature(io_safety))] +//! # #[cfg(feature = "net")] +//! # fn main() -> std::io::Result<()> { +//! use io_lifetimes::AsFd; +//! use rustix::io::epoll::{self, Epoll}; +//! use rustix::io::{ioctl_fionbio, read, write}; +//! use rustix::net::{ +//! accept, bind_v4, listen, socket, AddressFamily, Ipv4Addr, Protocol, SocketAddrV4, +//! SocketType, +//! }; +//! use std::os::unix::io::AsRawFd; +//! +//! // Create a socket and listen on it. +//! let listen_sock = socket(AddressFamily::INET, SocketType::STREAM, Protocol::default())?; +//! bind_v4(&listen_sock, &SocketAddrV4::new(Ipv4Addr::LOCALHOST, 0))?; +//! listen(&listen_sock, 1)?; +//! +//! // Create an epoll object. Using `Owning` here means the epoll object will +//! // take ownership of the file descriptors registered with it. +//! let epoll = Epoll::new(epoll::CreateFlags::CLOEXEC, epoll::Owning::new())?; +//! +//! // Remember the socket raw fd, which we use for comparisons only. +//! let raw_listen_sock = listen_sock.as_fd().as_raw_fd(); +//! +//! // Register the socket with the epoll object. +//! epoll.add(listen_sock, epoll::EventFlags::IN)?; +//! +//! // Process events. +//! let mut event_list = epoll::EventVec::with_capacity(4); +//! loop { +//! epoll.wait(&mut event_list, -1)?; +//! for (_event_flags, target) in &event_list { +//! if target.as_raw_fd() == raw_listen_sock { +//! // Accept a new connection, set it to non-blocking, and +//! // register to be notified when it's ready to write to. +//! let conn_sock = accept(&*target)?; +//! ioctl_fionbio(&conn_sock, true)?; +//! epoll.add(conn_sock, epoll::EventFlags::OUT | epoll::EventFlags::ET)?; +//! } else { +//! // Write a message to the stream and then unregister it. +//! write(&*target, b"hello\n")?; +//! let _ = epoll.del(target)?; +//! } +//! } +//! } +//! # } +//! # #[cfg(not(feature = "net"))] +//! # fn main() {} +//! ``` + +#![allow(unsafe_code)] + +use super::super::c; +use crate::backend::io::syscalls::{epoll_add, epoll_create, epoll_del, epoll_mod, epoll_wait}; +use crate::fd::{AsFd, AsRawFd, BorrowedFd, OwnedFd, RawFd}; +#[cfg(feature = "std")] +use crate::fd::{FromRawFd, IntoRawFd}; +use crate::io; +use alloc::vec::Vec; +use bitflags::bitflags; +use core::fmt; +use core::marker::PhantomData; +use core::ops::Deref; +use core::ptr::null; + +bitflags! { + /// `EPOLL_*` for use with [`Epoll::new`]. + pub struct CreateFlags: c::c_uint { + /// `EPOLL_CLOEXEC` + const CLOEXEC = linux_raw_sys::general::EPOLL_CLOEXEC; + } +} + +bitflags! { + /// `EPOLL*` for use with [`Epoll::add`]. + #[derive(Default)] + pub struct EventFlags: u32 { + /// `EPOLLIN` + const IN = linux_raw_sys::general::EPOLLIN as u32; + + /// `EPOLLOUT` + const OUT = linux_raw_sys::general::EPOLLOUT as u32; + + /// `EPOLLPRI` + const PRI = linux_raw_sys::general::EPOLLPRI as u32; + + /// `EPOLLERR` + const ERR = linux_raw_sys::general::EPOLLERR as u32; + + /// `EPOLLHUP` + const HUP = linux_raw_sys::general::EPOLLHUP as u32; + + /// `EPOLLET` + const ET = linux_raw_sys::general::EPOLLET as u32; + + /// `EPOLLONESHOT` + const ONESHOT = linux_raw_sys::general::EPOLLONESHOT as u32; + + /// `EPOLLWAKEUP` + const WAKEUP = linux_raw_sys::general::EPOLLWAKEUP as u32; + + /// `EPOLLEXCLUSIVE` + const EXCLUSIVE = linux_raw_sys::general::EPOLLEXCLUSIVE as u32; + } +} + +/// A reference to a `T`. +pub struct Ref<'a, T> { + t: T, + _phantom: PhantomData<&'a T>, +} + +impl<'a, T> Ref<'a, T> { + #[inline] + fn new(t: T) -> Self { + Self { + t, + _phantom: PhantomData, + } + } + + #[inline] + fn consume(self) -> T { + self.t + } +} + +impl<'a, T> Deref for Ref<'a, T> { + type Target = T; + + #[inline] + fn deref(&self) -> &T { + &self.t + } +} + +impl<'a, T: fmt::Debug> fmt::Debug for Ref<'a, T> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + self.t.fmt(fmt) + } +} + +/// A trait for data stored within an [`Epoll`] instance. +pub trait Context { + /// The type of an element owned by this context. + type Data; + + /// The type of a value used to refer to an element owned by this context. + type Target: AsFd; + + /// Assume ownership of `data`, and returning a `Target`. + fn acquire<'call>(&self, data: Self::Data) -> Ref<'call, Self::Target>; + + /// Encode `target` as a `u64`. The only requirement on this value is that + /// it be decodable by `decode`. + fn encode(&self, target: Ref<'_, Self::Target>) -> u64; + + /// Decode `raw`, which is a value encoded by `encode`, into a `Target`. + /// + /// # Safety + /// + /// `raw` must be a `u64` value returned from `encode`, from the same + /// context, and within the context's lifetime. + unsafe fn decode<'call>(&self, raw: u64) -> Ref<'call, Self::Target>; + + /// Release ownership of the value referred to by `target` and return it. + fn release(&self, target: Ref<'_, Self::Target>) -> Self::Data; +} + +/// A type implementing [`Context`] where the `Data` type is `BorrowedFd<'a>`. +pub struct Borrowing<'a> { + _phantom: PhantomData<BorrowedFd<'a>>, +} + +impl<'a> Context for Borrowing<'a> { + type Data = BorrowedFd<'a>; + type Target = BorrowedFd<'a>; + + #[inline] + fn acquire<'call>(&self, data: Self::Data) -> Ref<'call, Self::Target> { + Ref::new(data) + } + + #[inline] + fn encode(&self, target: Ref<'_, Self::Target>) -> u64 { + target.as_raw_fd() as u64 + } + + #[inline] + unsafe fn decode<'call>(&self, raw: u64) -> Ref<'call, Self::Target> { + Ref::new(BorrowedFd::<'a>::borrow_raw(raw as RawFd)) + } + + #[inline] + fn release(&self, target: Ref<'_, Self::Target>) -> Self::Data { + target.consume() + } +} + +/// A type implementing [`Context`] where the `Data` type is `T`, a type +/// implementing `From<OwnedFd>` and `From<T> of OwnedFd`. +/// +/// This may be used with [`OwnedFd`], or higher-level types like +/// [`std::fs::File`] or [`std::net::TcpStream`]. +#[cfg(feature = "std")] +pub struct Owning<'context, T: Into<OwnedFd> + From<OwnedFd>> { + _phantom: PhantomData<&'context T>, +} + +#[cfg(feature = "std")] +impl<'context, T: Into<OwnedFd> + From<OwnedFd>> Owning<'context, T> { + /// Creates a new empty `Owning`. + #[allow(clippy::new_without_default)] // This is a specialized type that doesn't need to be generically constructible. + #[inline] + pub fn new() -> Self { + Self { + _phantom: PhantomData, + } + } +} + +#[cfg(feature = "std")] +impl<'context, T: AsFd + Into<OwnedFd> + From<OwnedFd>> Context for Owning<'context, T> { + type Data = T; + type Target = BorrowedFd<'context>; + + #[inline] + fn acquire<'call>(&self, data: Self::Data) -> Ref<'call, Self::Target> { + let raw_fd = data.into().into_raw_fd(); + // Safety: `epoll` will assign ownership of the file descriptor to the + // kernel epoll object. We use `Into<OwnedFd>`+`IntoRawFd` to consume + // the `Data` and extract the raw file descriptor and then "borrow" it + // with `borrow_raw` knowing that the borrow won't outlive the + // kernel epoll object. + unsafe { Ref::new(BorrowedFd::<'context>::borrow_raw(raw_fd)) } + } + + #[inline] + fn encode(&self, target: Ref<'_, Self::Target>) -> u64 { + target.as_fd().as_raw_fd() as u64 + } + + #[inline] + unsafe fn decode<'call>(&self, raw: u64) -> Ref<'call, Self::Target> { + Ref::new(BorrowedFd::<'context>::borrow_raw(raw as RawFd)) + } + + #[inline] + fn release(&self, target: Ref<'_, Self::Target>) -> Self::Data { + let raw_fd = target.consume().as_raw_fd(); + + // Safety: The file descriptor was held by the kernel epoll object and + // is now being released, so we can create a new `OwnedFd` that assumes + // ownership. + unsafe { T::from(io_lifetimes::OwnedFd::from_raw_fd(raw_fd)) } + } +} + +/// An "epoll", an interface to an OS object allowing one to repeatedly wait +/// for events from a set of file descriptors efficiently. +pub struct Epoll<Context: self::Context> { + epoll_fd: OwnedFd, + context: Context, +} + +impl<Context: self::Context> Epoll<Context> { + /// `epoll_create1(flags)`—Creates a new `Epoll`. + /// + /// Use the [`CreateFlags::CLOEXEC`] flag to prevent the resulting file + /// descriptor from being implicitly passed across `exec` boundaries. + #[inline] + #[doc(alias = "epoll_create1")] + pub fn new(flags: CreateFlags, context: Context) -> io::Result<Self> { + // Safety: We're calling `epoll_create1` via FFI and we know how it + // behaves. + Ok(Self { + epoll_fd: epoll_create(flags)?, + context, + }) + } + + /// `epoll_ctl(self, EPOLL_CTL_ADD, data, event)`—Adds an element to an + /// `Epoll`. + /// + /// This registers interest in any of the events set in `events` occurring + /// on the file descriptor associated with `data`. + #[doc(alias = "epoll_ctl")] + pub fn add( + &self, + data: Context::Data, + event_flags: EventFlags, + ) -> io::Result<Ref<'_, Context::Target>> { + // Safety: We're calling `epoll_ctl` via FFI and we know how it + // behaves. + unsafe { + let target = self.context.acquire(data); + let raw_fd = target.as_fd().as_raw_fd(); + let encoded = self.context.encode(target); + epoll_add( + self.epoll_fd.as_fd(), + raw_fd, + &linux_raw_sys::general::epoll_event { + events: event_flags.bits(), + data: encoded, + }, + )?; + Ok(self.context.decode(encoded)) + } + } + + /// `epoll_ctl(self, EPOLL_CTL_MOD, target, event)`—Modifies an element in + /// this `Epoll`. + /// + /// This sets the events of interest with `target` to `events`. + #[doc(alias = "epoll_ctl")] + pub fn mod_( + &self, + target: Ref<'_, Context::Target>, + event_flags: EventFlags, + ) -> io::Result<()> { + let raw_fd = target.as_fd().as_raw_fd(); + let encoded = self.context.encode(target); + // Safety: We're calling `epoll_ctl` via FFI and we know how it + // behaves. + unsafe { + epoll_mod( + self.epoll_fd.as_fd(), + raw_fd, + &linux_raw_sys::general::epoll_event { + events: event_flags.bits(), + data: encoded, + }, + ) + } + } + + /// `epoll_ctl(self, EPOLL_CTL_DEL, target, NULL)`—Removes an element in + /// this `Epoll`. + /// + /// This also returns the owning `Data`. + #[doc(alias = "epoll_ctl")] + pub fn del(&self, target: Ref<'_, Context::Target>) -> io::Result<Context::Data> { + // Safety: We're calling `epoll_ctl` via FFI and we know how it + // behaves. + unsafe { + let raw_fd = target.as_fd().as_raw_fd(); + epoll_del(self.epoll_fd.as_fd(), raw_fd)?; + } + Ok(self.context.release(target)) + } + + /// `epoll_wait(self, events, timeout)`—Waits for registered events of + /// interest. + /// + /// For each event of interest, an element is written to `events`. On + /// success, this returns the number of written elements. + #[doc(alias = "epoll_wait")] + pub fn wait<'context>( + &'context self, + event_list: &mut EventVec<'context, Context>, + timeout: c::c_int, + ) -> io::Result<()> { + // Safety: We're calling `epoll_wait` via FFI and we know how it + // behaves. + unsafe { + event_list.events.set_len(0); + let nfds = epoll_wait( + self.epoll_fd.as_fd(), + event_list.events[..].as_mut_ptr().cast(), + event_list.events.capacity(), + timeout, + )?; + event_list.events.set_len(nfds); + event_list.context = &self.context; + } + + Ok(()) + } +} + +#[cfg(feature = "std")] +impl<'context, T: AsFd + Into<OwnedFd> + From<OwnedFd>> AsRawFd for Epoll<Owning<'context, T>> { + fn as_raw_fd(&self) -> RawFd { + self.epoll_fd.as_raw_fd() + } +} + +#[cfg(feature = "std")] +impl<'context, T: AsFd + Into<OwnedFd> + From<OwnedFd>> IntoRawFd for Epoll<Owning<'context, T>> { + fn into_raw_fd(self) -> RawFd { + self.epoll_fd.into_raw_fd() + } +} + +#[cfg(feature = "std")] +impl<'context, T: AsFd + Into<OwnedFd> + From<OwnedFd>> FromRawFd for Epoll<Owning<'context, T>> { + unsafe fn from_raw_fd(fd: RawFd) -> Self { + Self { + epoll_fd: OwnedFd::from_raw_fd(fd), + context: Owning::new(), + } + } +} + +#[cfg(feature = "std")] +impl<'context, T: AsFd + Into<OwnedFd> + From<OwnedFd>> AsFd for Epoll<Owning<'context, T>> { + fn as_fd(&self) -> BorrowedFd<'_> { + self.epoll_fd.as_fd() + } +} + +#[cfg(feature = "std")] +impl<'context, T: AsFd + Into<OwnedFd> + From<OwnedFd>> From<Epoll<Owning<'context, T>>> + for OwnedFd +{ + fn from(epoll: Epoll<Owning<'context, T>>) -> Self { + epoll.epoll_fd + } +} + +#[cfg(feature = "std")] +impl<'context, T: AsFd + Into<OwnedFd> + From<OwnedFd>> From<OwnedFd> + for Epoll<Owning<'context, T>> +{ + fn from(fd: OwnedFd) -> Self { + Self { + epoll_fd: fd, + context: Owning::new(), + } + } +} + +/// An iterator over the `Event`s in an `EventVec`. +pub struct Iter<'context, Context: self::Context> { + iter: core::slice::Iter<'context, Event>, + context: *const Context, + _phantom: PhantomData<&'context Context>, +} + +impl<'context, Context: self::Context> Iterator for Iter<'context, Context> { + type Item = (EventFlags, Ref<'context, Context::Target>); + + fn next(&mut self) -> Option<Self::Item> { + self.iter.next().map(|event| { + // Safety: `self.context` is guaranteed to be valid because we hold + // `'context` for it. And we know this event is associated with this + // context because `wait` sets both. + let decoded = unsafe { (*self.context).decode(event.encoded) }; + + (event.event_flags, decoded) + }) + } +} + +/// A record of an event that occurred. +#[repr(C)] +#[cfg_attr(target_arch = "x86_64", repr(packed))] +struct Event { + // Match the layout of `linux_raw_sys::general::epoll_event`. We just use a + // `u64` instead of the full union; `Context` implementations will simply + // need to deal with casting the value into and out of the `u64` + // themselves. + event_flags: EventFlags, + encoded: u64, +} + +/// A vector of `Event`s, plus context for interpreting them. +pub struct EventVec<'context, Context: self::Context> { + events: Vec<Event>, + context: *const Context, + _phantom: PhantomData<&'context Context>, +} + +impl<'context, Context: self::Context> EventVec<'context, Context> { + /// Constructs an `EventVec` with memory for `capacity` `Event`s. + #[inline] + pub fn with_capacity(capacity: usize) -> Self { + Self { + events: Vec::with_capacity(capacity), + context: null(), + _phantom: PhantomData, + } + } + + /// Returns the current `Event` capacity of this `EventVec`. + #[inline] + pub fn capacity(&self) -> usize { + self.events.capacity() + } + + /// Reserves enough memory for at least `additional` more `Event`s. + #[inline] + pub fn reserve(&mut self, additional: usize) { + self.events.reserve(additional); + } + + /// Reserves enough memory for exactly `additional` more `Event`s. + #[inline] + pub fn reserve_exact(&mut self, additional: usize) { + self.events.reserve_exact(additional); + } + + /// Clears all the `Events` out of this `EventVec`. + #[inline] + pub fn clear(&mut self) { + self.events.clear(); + } + + /// Shrinks the capacity of this `EventVec` as much as possible. + #[inline] + pub fn shrink_to_fit(&mut self) { + self.events.shrink_to_fit(); + } + + /// Returns an iterator over the `Event`s in this `EventVec`. + #[inline] + pub fn iter(&self) -> Iter<'_, Context> { + Iter { + iter: self.events.iter(), + context: self.context, + _phantom: PhantomData, + } + } + + /// Returns the number of `Event`s logically contained in this `EventVec`. + #[inline] + pub fn len(&mut self) -> usize { + self.events.len() + } + + /// Tests whether this `EventVec` is logically empty. + #[inline] + pub fn is_empty(&mut self) -> bool { + self.events.is_empty() + } +} + +impl<'context, Context: self::Context> IntoIterator for &'context EventVec<'context, Context> { + type IntoIter = Iter<'context, Context>; + type Item = (EventFlags, Ref<'context, Context::Target>); + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} diff --git a/vendor/rustix/src/backend/linux_raw/io/errno.rs b/vendor/rustix/src/backend/linux_raw/io/errno.rs new file mode 100644 index 000000000..5c7b2fcd5 --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/io/errno.rs @@ -0,0 +1,517 @@ +//! The `rustix` `Errno` type. +//! +//! This type holds an OS error code, which conceptually corresponds to an +//! `errno` value. +//! +//! # Safety +//! +//! Linux uses error codes in `-4095..0`; we use rustc attributes to describe +//! this restricted range of values. +#![allow(unsafe_code)] +#![cfg_attr(not(rustc_attrs), allow(unused_unsafe))] + +use super::super::c; +use crate::backend::fd::RawFd; +use crate::backend::reg::{RetNumber, RetReg}; +use crate::io; +use linux_raw_sys::errno; + +/// The error type for `rustix` APIs. +/// +/// This is similar to `std::io::Error`, but only holds an OS error code, +/// and no extra error value. +#[repr(transparent)] +#[doc(alias = "errno")] +#[derive(Eq, PartialEq, Hash, Copy, Clone)] +// Linux returns negated error codes, and we leave them in negated form, so +// error codes are in `-4095..0`. +#[cfg_attr(rustc_attrs, rustc_layout_scalar_valid_range_start(0xf001))] +#[cfg_attr(rustc_attrs, rustc_layout_scalar_valid_range_end(0xffff))] +pub struct Errno(u16); + +impl Errno { + /// Extract an `Errno` value from a `std::io::Error`. + /// + /// This isn't a `From` conversion because it's expected to be relatively + /// uncommon. + #[cfg(feature = "std")] + #[inline] + pub fn from_io_error(io_err: &std::io::Error) -> Option<Self> { + io_err.raw_os_error().and_then(|raw| { + // `std::io::Error` could theoretically have arbitrary "OS error" + // values, so check that they're in Linux's range. + if (1..4096).contains(&raw) { + Some(Self::from_errno(raw as u32)) + } else { + None + } + }) + } + + /// Extract the raw OS error number from this error. + #[inline] + pub const fn raw_os_error(self) -> i32 { + (self.0 as i16 as i32).wrapping_neg() + } + + /// Construct an `Errno` from a raw OS error number. + #[inline] + pub const fn from_raw_os_error(raw: i32) -> Self { + Self::from_errno(raw as u32) + } + + /// Convert from a C errno value (which is positive) to an `Errno`. + const fn from_errno(raw: u32) -> Self { + // We store error values in negated form, so that we don't have to negate + // them after every syscall. + let encoded = raw.wrapping_neg() as u16; + + // TODO: Use Range::contains, once that's `const`. + const_assert!(encoded >= 0xf001); + + // Safety: Linux syscalls return negated error values in the range + // `-4095..0`, which we just asserted. + unsafe { Self(encoded) } + } +} + +/// Check for an error from the result of a syscall which encodes a +/// `c::c_int` on success. +#[inline] +pub(in crate::backend) fn try_decode_c_int<Num: RetNumber>( + raw: RetReg<Num>, +) -> io::Result<c::c_int> { + if raw.is_in_range(-4095..0) { + // Safety: `raw` must be in `-4095..0`, and we just checked that raw is + // in that range. + return Err(unsafe { Errno(raw.decode_error_code()) }); + } + + Ok(raw.decode_c_int()) +} + +/// Check for an error from the result of a syscall which encodes a +/// `c::c_uint` on success. +#[inline] +pub(in crate::backend) fn try_decode_c_uint<Num: RetNumber>( + raw: RetReg<Num>, +) -> io::Result<c::c_uint> { + if raw.is_in_range(-4095..0) { + // Safety: `raw` must be in `-4095..0`, and we just checked that raw is + // in that range. + return Err(unsafe { Errno(raw.decode_error_code()) }); + } + + Ok(raw.decode_c_uint()) +} + +/// Check for an error from the result of a syscall which encodes a `usize` on +/// success. +#[inline] +pub(in crate::backend) fn try_decode_usize<Num: RetNumber>(raw: RetReg<Num>) -> io::Result<usize> { + if raw.is_in_range(-4095..0) { + // Safety: `raw` must be in `-4095..0`, and we just checked that raw is + // in that range. + return Err(unsafe { Errno(raw.decode_error_code()) }); + } + + Ok(raw.decode_usize()) +} + +/// Check for an error from the result of a syscall which encodes a +/// `*mut c_void` on success. +#[inline] +pub(in crate::backend) fn try_decode_void_star<Num: RetNumber>( + raw: RetReg<Num>, +) -> io::Result<*mut c::c_void> { + if raw.is_in_range(-4095..0) { + // Safety: `raw` must be in `-4095..0`, and we just checked that raw is + // in that range. + return Err(unsafe { Errno(raw.decode_error_code()) }); + } + + Ok(raw.decode_void_star()) +} + +/// Check for an error from the result of a syscall which encodes a +/// `u64` on success. +#[cfg(target_pointer_width = "64")] +#[inline] +pub(in crate::backend) fn try_decode_u64<Num: RetNumber>(raw: RetReg<Num>) -> io::Result<u64> { + if raw.is_in_range(-4095..0) { + // Safety: `raw` must be in `-4095..0`, and we just checked that raw is + // in that range. + return Err(unsafe { Errno(raw.decode_error_code()) }); + } + + Ok(raw.decode_u64()) +} + +/// Check for an error from the result of a syscall which encodes a file +/// descriptor on success. +/// +/// # Safety +/// +/// This must only be used with syscalls which return file descriptors on +/// success. +#[inline] +pub(in crate::backend) unsafe fn try_decode_raw_fd<Num: RetNumber>( + raw: RetReg<Num>, +) -> io::Result<RawFd> { + // Instead of using `check_result` here, we just check for negative, since + // this function is only used for system calls which return file + // descriptors, and this produces smaller code. + if raw.is_negative() { + debug_assert!(raw.is_in_range(-4095..0)); + + // Tell the optimizer that we know the value is in the error range. + // This helps it avoid unnecessary integer conversions. + #[cfg(core_intrinsics)] + { + core::intrinsics::assume(raw.is_in_range(-4095..0)); + } + + return Err(Errno(raw.decode_error_code())); + } + + Ok(raw.decode_raw_fd()) +} + +/// Check for an error from the result of a syscall which encodes no value on +/// success. On success, return the unconsumed `raw` value. +/// +/// # Safety +/// +/// This must only be used with syscalls which return no value on success. +#[inline] +pub(in crate::backend) unsafe fn try_decode_void<Num: RetNumber>( + raw: RetReg<Num>, +) -> io::Result<()> { + // Instead of using `check_result` here, we just check for zero, since this + // function is only used for system calls which have no other return value, + // and this produces smaller code. + if raw.is_nonzero() { + debug_assert!(raw.is_in_range(-4095..0)); + + // Tell the optimizer that we know the value is in the error range. + // This helps it avoid unnecessary integer conversions. + #[cfg(core_intrinsics)] + { + core::intrinsics::assume(raw.is_in_range(-4095..0)); + } + + return Err(Errno(raw.decode_error_code())); + } + + raw.decode_void(); + + Ok(()) +} + +/// Check for an error from the result of a syscall which does not return on +/// success. On success, return the unconsumed `raw` value. +/// +/// # Safety +/// +/// This must only be used with syscalls which do not return on success. +#[cfg(feature = "runtime")] +#[inline] +pub(in crate::backend) unsafe fn try_decode_error<Num: RetNumber>(raw: RetReg<Num>) -> io::Errno { + debug_assert!(raw.is_in_range(-4095..0)); + + // Tell the optimizer that we know the value is in the error range. + // This helps it avoid unnecessary integer conversions. + #[cfg(core_intrinsics)] + { + core::intrinsics::assume(raw.is_in_range(-4095..0)); + } + + Errno(raw.decode_error_code()) +} + +/// Return the contained `usize` value. +#[cfg(not(debug_assertions))] +#[inline] +pub(in crate::backend) fn decode_usize_infallible<Num: RetNumber>(raw: RetReg<Num>) -> usize { + raw.decode_usize() +} + +impl Errno { + /// `EACCES` + #[doc(alias = "ACCES")] + pub const ACCESS: Self = Self::from_errno(errno::EACCES); + /// `EADDRINUSE` + pub const ADDRINUSE: Self = Self::from_errno(errno::EADDRINUSE); + /// `EADDRNOTAVAIL` + pub const ADDRNOTAVAIL: Self = Self::from_errno(errno::EADDRNOTAVAIL); + /// `EADV` + pub const ADV: Self = Self::from_errno(errno::EADV); + /// `EAFNOSUPPORT` + pub const AFNOSUPPORT: Self = Self::from_errno(errno::EAFNOSUPPORT); + /// `EAGAIN` + pub const AGAIN: Self = Self::from_errno(errno::EAGAIN); + /// `EALREADY` + pub const ALREADY: Self = Self::from_errno(errno::EALREADY); + /// `EBADE` + pub const BADE: Self = Self::from_errno(errno::EBADE); + /// `EBADF` + pub const BADF: Self = Self::from_errno(errno::EBADF); + /// `EBADFD` + pub const BADFD: Self = Self::from_errno(errno::EBADFD); + /// `EBADMSG` + pub const BADMSG: Self = Self::from_errno(errno::EBADMSG); + /// `EBADR` + pub const BADR: Self = Self::from_errno(errno::EBADR); + /// `EBADRQC` + pub const BADRQC: Self = Self::from_errno(errno::EBADRQC); + /// `EBADSLT` + pub const BADSLT: Self = Self::from_errno(errno::EBADSLT); + /// `EBFONT` + pub const BFONT: Self = Self::from_errno(errno::EBFONT); + /// `EBUSY` + pub const BUSY: Self = Self::from_errno(errno::EBUSY); + /// `ECANCELED` + pub const CANCELED: Self = Self::from_errno(errno::ECANCELED); + /// `ECHILD` + pub const CHILD: Self = Self::from_errno(errno::ECHILD); + /// `ECHRNG` + pub const CHRNG: Self = Self::from_errno(errno::ECHRNG); + /// `ECOMM` + pub const COMM: Self = Self::from_errno(errno::ECOMM); + /// `ECONNABORTED` + pub const CONNABORTED: Self = Self::from_errno(errno::ECONNABORTED); + /// `ECONNREFUSED` + pub const CONNREFUSED: Self = Self::from_errno(errno::ECONNREFUSED); + /// `ECONNRESET` + pub const CONNRESET: Self = Self::from_errno(errno::ECONNRESET); + /// `EDEADLK` + pub const DEADLK: Self = Self::from_errno(errno::EDEADLK); + /// `EDEADLOCK` + pub const DEADLOCK: Self = Self::from_errno(errno::EDEADLOCK); + /// `EDESTADDRREQ` + pub const DESTADDRREQ: Self = Self::from_errno(errno::EDESTADDRREQ); + /// `EDOM` + pub const DOM: Self = Self::from_errno(errno::EDOM); + /// `EDOTDOT` + pub const DOTDOT: Self = Self::from_errno(errno::EDOTDOT); + /// `EDQUOT` + pub const DQUOT: Self = Self::from_errno(errno::EDQUOT); + /// `EEXIST` + pub const EXIST: Self = Self::from_errno(errno::EEXIST); + /// `EFAULT` + pub const FAULT: Self = Self::from_errno(errno::EFAULT); + /// `EFBIG` + pub const FBIG: Self = Self::from_errno(errno::EFBIG); + /// `EHOSTDOWN` + pub const HOSTDOWN: Self = Self::from_errno(errno::EHOSTDOWN); + /// `EHOSTUNREACH` + pub const HOSTUNREACH: Self = Self::from_errno(errno::EHOSTUNREACH); + /// `EHWPOISON` + pub const HWPOISON: Self = Self::from_errno(errno::EHWPOISON); + /// `EIDRM` + pub const IDRM: Self = Self::from_errno(errno::EIDRM); + /// `EILSEQ` + pub const ILSEQ: Self = Self::from_errno(errno::EILSEQ); + /// `EINPROGRESS` + pub const INPROGRESS: Self = Self::from_errno(errno::EINPROGRESS); + /// `EINTR`. + /// + /// For a convenient way to retry system calls that exit with `INTR`, use + /// [`retry_on_intr`]. + /// + /// [`retry_on_intr`]: io::retry_on_intr + pub const INTR: Self = Self::from_errno(errno::EINTR); + /// `EINVAL` + pub const INVAL: Self = Self::from_errno(errno::EINVAL); + /// `EIO` + pub const IO: Self = Self::from_errno(errno::EIO); + /// `EISCONN` + pub const ISCONN: Self = Self::from_errno(errno::EISCONN); + /// `EISDIR` + pub const ISDIR: Self = Self::from_errno(errno::EISDIR); + /// `EISNAM` + pub const ISNAM: Self = Self::from_errno(errno::EISNAM); + /// `EKEYEXPIRED` + pub const KEYEXPIRED: Self = Self::from_errno(errno::EKEYEXPIRED); + /// `EKEYREJECTED` + pub const KEYREJECTED: Self = Self::from_errno(errno::EKEYREJECTED); + /// `EKEYREVOKED` + pub const KEYREVOKED: Self = Self::from_errno(errno::EKEYREVOKED); + /// `EL2HLT` + pub const L2HLT: Self = Self::from_errno(errno::EL2HLT); + /// `EL2NSYNC` + pub const L2NSYNC: Self = Self::from_errno(errno::EL2NSYNC); + /// `EL3HLT` + pub const L3HLT: Self = Self::from_errno(errno::EL3HLT); + /// `EL3RST` + pub const L3RST: Self = Self::from_errno(errno::EL3RST); + /// `ELIBACC` + pub const LIBACC: Self = Self::from_errno(errno::ELIBACC); + /// `ELIBBAD` + pub const LIBBAD: Self = Self::from_errno(errno::ELIBBAD); + /// `ELIBEXEC` + pub const LIBEXEC: Self = Self::from_errno(errno::ELIBEXEC); + /// `ELIBMAX` + pub const LIBMAX: Self = Self::from_errno(errno::ELIBMAX); + /// `ELIBSCN` + pub const LIBSCN: Self = Self::from_errno(errno::ELIBSCN); + /// `ELNRNG` + pub const LNRNG: Self = Self::from_errno(errno::ELNRNG); + /// `ELOOP` + pub const LOOP: Self = Self::from_errno(errno::ELOOP); + /// `EMEDIUMTYPE` + pub const MEDIUMTYPE: Self = Self::from_errno(errno::EMEDIUMTYPE); + /// `EMFILE` + pub const MFILE: Self = Self::from_errno(errno::EMFILE); + /// `EMLINK` + pub const MLINK: Self = Self::from_errno(errno::EMLINK); + /// `EMSGSIZE` + pub const MSGSIZE: Self = Self::from_errno(errno::EMSGSIZE); + /// `EMULTIHOP` + pub const MULTIHOP: Self = Self::from_errno(errno::EMULTIHOP); + /// `ENAMETOOLONG` + pub const NAMETOOLONG: Self = Self::from_errno(errno::ENAMETOOLONG); + /// `ENAVAIL` + pub const NAVAIL: Self = Self::from_errno(errno::ENAVAIL); + /// `ENETDOWN` + pub const NETDOWN: Self = Self::from_errno(errno::ENETDOWN); + /// `ENETRESET` + pub const NETRESET: Self = Self::from_errno(errno::ENETRESET); + /// `ENETUNREACH` + pub const NETUNREACH: Self = Self::from_errno(errno::ENETUNREACH); + /// `ENFILE` + pub const NFILE: Self = Self::from_errno(errno::ENFILE); + /// `ENOANO` + pub const NOANO: Self = Self::from_errno(errno::ENOANO); + /// `ENOBUFS` + pub const NOBUFS: Self = Self::from_errno(errno::ENOBUFS); + /// `ENOCSI` + pub const NOCSI: Self = Self::from_errno(errno::ENOCSI); + /// `ENODATA` + #[doc(alias = "NOATTR")] + pub const NODATA: Self = Self::from_errno(errno::ENODATA); + /// `ENODEV` + pub const NODEV: Self = Self::from_errno(errno::ENODEV); + /// `ENOENT` + pub const NOENT: Self = Self::from_errno(errno::ENOENT); + /// `ENOEXEC` + pub const NOEXEC: Self = Self::from_errno(errno::ENOEXEC); + /// `ENOKEY` + pub const NOKEY: Self = Self::from_errno(errno::ENOKEY); + /// `ENOLCK` + pub const NOLCK: Self = Self::from_errno(errno::ENOLCK); + /// `ENOLINK` + pub const NOLINK: Self = Self::from_errno(errno::ENOLINK); + /// `ENOMEDIUM` + pub const NOMEDIUM: Self = Self::from_errno(errno::ENOMEDIUM); + /// `ENOMEM` + pub const NOMEM: Self = Self::from_errno(errno::ENOMEM); + /// `ENOMSG` + pub const NOMSG: Self = Self::from_errno(errno::ENOMSG); + /// `ENONET` + pub const NONET: Self = Self::from_errno(errno::ENONET); + /// `ENOPKG` + pub const NOPKG: Self = Self::from_errno(errno::ENOPKG); + /// `ENOPROTOOPT` + pub const NOPROTOOPT: Self = Self::from_errno(errno::ENOPROTOOPT); + /// `ENOSPC` + pub const NOSPC: Self = Self::from_errno(errno::ENOSPC); + /// `ENOSR` + pub const NOSR: Self = Self::from_errno(errno::ENOSR); + /// `ENOSTR` + pub const NOSTR: Self = Self::from_errno(errno::ENOSTR); + /// `ENOSYS` + pub const NOSYS: Self = Self::from_errno(errno::ENOSYS); + /// `ENOTBLK` + pub const NOTBLK: Self = Self::from_errno(errno::ENOTBLK); + /// `ENOTCONN` + pub const NOTCONN: Self = Self::from_errno(errno::ENOTCONN); + /// `ENOTDIR` + pub const NOTDIR: Self = Self::from_errno(errno::ENOTDIR); + /// `ENOTEMPTY` + pub const NOTEMPTY: Self = Self::from_errno(errno::ENOTEMPTY); + /// `ENOTNAM` + pub const NOTNAM: Self = Self::from_errno(errno::ENOTNAM); + /// `ENOTRECOVERABLE` + pub const NOTRECOVERABLE: Self = Self::from_errno(errno::ENOTRECOVERABLE); + /// `ENOTSOCK` + pub const NOTSOCK: Self = Self::from_errno(errno::ENOTSOCK); + /// `ENOTSUP` + // On Linux, `ENOTSUP` has the same value as `EOPNOTSUPP`. + pub const NOTSUP: Self = Self::from_errno(errno::EOPNOTSUPP); + /// `ENOTTY` + pub const NOTTY: Self = Self::from_errno(errno::ENOTTY); + /// `ENOTUNIQ` + pub const NOTUNIQ: Self = Self::from_errno(errno::ENOTUNIQ); + /// `ENXIO` + pub const NXIO: Self = Self::from_errno(errno::ENXIO); + /// `EOPNOTSUPP` + pub const OPNOTSUPP: Self = Self::from_errno(errno::EOPNOTSUPP); + /// `EOVERFLOW` + pub const OVERFLOW: Self = Self::from_errno(errno::EOVERFLOW); + /// `EOWNERDEAD` + pub const OWNERDEAD: Self = Self::from_errno(errno::EOWNERDEAD); + /// `EPERM` + pub const PERM: Self = Self::from_errno(errno::EPERM); + /// `EPFNOSUPPORT` + pub const PFNOSUPPORT: Self = Self::from_errno(errno::EPFNOSUPPORT); + /// `EPIPE` + pub const PIPE: Self = Self::from_errno(errno::EPIPE); + /// `EPROTO` + pub const PROTO: Self = Self::from_errno(errno::EPROTO); + /// `EPROTONOSUPPORT` + pub const PROTONOSUPPORT: Self = Self::from_errno(errno::EPROTONOSUPPORT); + /// `EPROTOTYPE` + pub const PROTOTYPE: Self = Self::from_errno(errno::EPROTOTYPE); + /// `ERANGE` + pub const RANGE: Self = Self::from_errno(errno::ERANGE); + /// `EREMCHG` + pub const REMCHG: Self = Self::from_errno(errno::EREMCHG); + /// `EREMOTE` + pub const REMOTE: Self = Self::from_errno(errno::EREMOTE); + /// `EREMOTEIO` + pub const REMOTEIO: Self = Self::from_errno(errno::EREMOTEIO); + /// `ERESTART` + pub const RESTART: Self = Self::from_errno(errno::ERESTART); + /// `ERFKILL` + pub const RFKILL: Self = Self::from_errno(errno::ERFKILL); + /// `EROFS` + pub const ROFS: Self = Self::from_errno(errno::EROFS); + /// `ESHUTDOWN` + pub const SHUTDOWN: Self = Self::from_errno(errno::ESHUTDOWN); + /// `ESOCKTNOSUPPORT` + pub const SOCKTNOSUPPORT: Self = Self::from_errno(errno::ESOCKTNOSUPPORT); + /// `ESPIPE` + pub const SPIPE: Self = Self::from_errno(errno::ESPIPE); + /// `ESRCH` + pub const SRCH: Self = Self::from_errno(errno::ESRCH); + /// `ESRMNT` + pub const SRMNT: Self = Self::from_errno(errno::ESRMNT); + /// `ESTALE` + pub const STALE: Self = Self::from_errno(errno::ESTALE); + /// `ESTRPIPE` + pub const STRPIPE: Self = Self::from_errno(errno::ESTRPIPE); + /// `ETIME` + pub const TIME: Self = Self::from_errno(errno::ETIME); + /// `ETIMEDOUT` + pub const TIMEDOUT: Self = Self::from_errno(errno::ETIMEDOUT); + /// `E2BIG` + #[doc(alias = "2BIG")] + pub const TOOBIG: Self = Self::from_errno(errno::E2BIG); + /// `ETOOMANYREFS` + pub const TOOMANYREFS: Self = Self::from_errno(errno::ETOOMANYREFS); + /// `ETXTBSY` + pub const TXTBSY: Self = Self::from_errno(errno::ETXTBSY); + /// `EUCLEAN` + pub const UCLEAN: Self = Self::from_errno(errno::EUCLEAN); + /// `EUNATCH` + pub const UNATCH: Self = Self::from_errno(errno::EUNATCH); + /// `EUSERS` + pub const USERS: Self = Self::from_errno(errno::EUSERS); + /// `EWOULDBLOCK` + pub const WOULDBLOCK: Self = Self::from_errno(errno::EWOULDBLOCK); + /// `EXDEV` + pub const XDEV: Self = Self::from_errno(errno::EXDEV); + /// `EXFULL` + pub const XFULL: Self = Self::from_errno(errno::EXFULL); +} diff --git a/vendor/rustix/src/imp/linux_raw/io/io_slice.rs b/vendor/rustix/src/backend/linux_raw/io/io_slice.rs index fc8e64698..fc8e64698 100644 --- a/vendor/rustix/src/imp/linux_raw/io/io_slice.rs +++ b/vendor/rustix/src/backend/linux_raw/io/io_slice.rs diff --git a/vendor/rustix/src/imp/linux_raw/io/mod.rs b/vendor/rustix/src/backend/linux_raw/io/mod.rs index f5c2bf3c0..f5c2bf3c0 100644 --- a/vendor/rustix/src/imp/linux_raw/io/mod.rs +++ b/vendor/rustix/src/backend/linux_raw/io/mod.rs diff --git a/vendor/rustix/src/imp/linux_raw/io/poll_fd.rs b/vendor/rustix/src/backend/linux_raw/io/poll_fd.rs index 252358331..252358331 100644 --- a/vendor/rustix/src/imp/linux_raw/io/poll_fd.rs +++ b/vendor/rustix/src/backend/linux_raw/io/poll_fd.rs diff --git a/vendor/rustix/src/backend/linux_raw/io/syscalls.rs b/vendor/rustix/src/backend/linux_raw/io/syscalls.rs new file mode 100644 index 000000000..2cc7898af --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/io/syscalls.rs @@ -0,0 +1,676 @@ +//! linux_raw syscalls supporting `rustix::io`. +//! +//! # Safety +//! +//! See the `rustix::backend` module documentation for details. +#![allow(unsafe_code)] +#![allow(clippy::undocumented_unsafe_blocks)] + +use super::super::c; +#[cfg(target_pointer_width = "64")] +use super::super::conv::loff_t_from_u64; +use super::super::conv::{ + by_ref, c_int, c_uint, opt_mut, pass_usize, raw_fd, ret, ret_c_uint, ret_discarded_fd, + ret_owned_fd, ret_usize, slice, slice_mut, zero, +}; +#[cfg(target_pointer_width = "32")] +use super::super::conv::{hi, lo}; +use crate::fd::{AsFd, BorrowedFd, OwnedFd, RawFd}; +#[cfg(any(target_os = "android", target_os = "linux"))] +use crate::io::SpliceFlags; +use crate::io::{ + self, epoll, DupFlags, EventfdFlags, FdFlags, IoSlice, IoSliceMut, IoSliceRaw, PipeFlags, + PollFd, ReadWriteFlags, +}; +#[cfg(all(feature = "fs", feature = "net"))] +use crate::net::{RecvFlags, SendFlags}; +use core::cmp; +use core::mem::MaybeUninit; +#[cfg(target_os = "espidf")] +use linux_raw_sys::general::F_DUPFD; +use linux_raw_sys::general::{ + epoll_event, EPOLL_CTL_ADD, EPOLL_CTL_DEL, EPOLL_CTL_MOD, F_DUPFD_CLOEXEC, F_GETFD, F_SETFD, + UIO_MAXIOV, +}; +use linux_raw_sys::ioctl::{BLKPBSZGET, BLKSSZGET, FIONBIO, FIONREAD, TIOCEXCL, TIOCNXCL}; +#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] +use { + super::super::conv::{opt_ref, size_of}, + linux_raw_sys::general::{__kernel_timespec, sigset_t}, +}; + +#[inline] +pub(crate) fn read(fd: BorrowedFd<'_>, buf: &mut [u8]) -> io::Result<usize> { + let (buf_addr_mut, buf_len) = slice_mut(buf); + + unsafe { ret_usize(syscall!(__NR_read, fd, buf_addr_mut, buf_len)) } +} + +#[inline] +pub(crate) fn pread(fd: BorrowedFd<'_>, buf: &mut [u8], pos: u64) -> io::Result<usize> { + let (buf_addr_mut, buf_len) = slice_mut(buf); + + // <https://github.com/torvalds/linux/blob/fcadab740480e0e0e9fa9bd272acd409884d431a/arch/arm64/kernel/sys32.c#L75> + #[cfg(all( + target_pointer_width = "32", + any(target_arch = "arm", target_arch = "mips", target_arch = "power"), + ))] + unsafe { + ret_usize(syscall!( + __NR_pread64, + fd, + buf_addr_mut, + buf_len, + zero(), + hi(pos), + lo(pos) + )) + } + #[cfg(all( + target_pointer_width = "32", + not(any(target_arch = "arm", target_arch = "mips", target_arch = "power")), + ))] + unsafe { + ret_usize(syscall!( + __NR_pread64, + fd, + buf_addr_mut, + buf_len, + hi(pos), + lo(pos) + )) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_usize(syscall!( + __NR_pread64, + fd, + buf_addr_mut, + buf_len, + loff_t_from_u64(pos) + )) + } +} + +#[inline] +pub(crate) fn readv(fd: BorrowedFd<'_>, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { + let (bufs_addr, bufs_len) = slice(&bufs[..cmp::min(bufs.len(), max_iov())]); + + unsafe { ret_usize(syscall!(__NR_readv, fd, bufs_addr, bufs_len)) } +} + +#[inline] +pub(crate) fn preadv( + fd: BorrowedFd<'_>, + bufs: &mut [IoSliceMut<'_>], + pos: u64, +) -> io::Result<usize> { + let (bufs_addr, bufs_len) = slice(&bufs[..cmp::min(bufs.len(), max_iov())]); + + #[cfg(target_pointer_width = "32")] + unsafe { + ret_usize(syscall!( + __NR_preadv, + fd, + bufs_addr, + bufs_len, + hi(pos), + lo(pos) + )) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_usize(syscall!( + __NR_preadv, + fd, + bufs_addr, + bufs_len, + loff_t_from_u64(pos) + )) + } +} + +#[inline] +pub(crate) fn preadv2( + fd: BorrowedFd<'_>, + bufs: &mut [IoSliceMut<'_>], + pos: u64, + flags: ReadWriteFlags, +) -> io::Result<usize> { + let (bufs_addr, bufs_len) = slice(&bufs[..cmp::min(bufs.len(), max_iov())]); + + #[cfg(target_pointer_width = "32")] + unsafe { + ret_usize(syscall!( + __NR_preadv2, + fd, + bufs_addr, + bufs_len, + hi(pos), + lo(pos), + flags + )) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_usize(syscall!( + __NR_preadv2, + fd, + bufs_addr, + bufs_len, + loff_t_from_u64(pos), + flags + )) + } +} + +#[inline] +pub(crate) fn write(fd: BorrowedFd<'_>, buf: &[u8]) -> io::Result<usize> { + let (buf_addr, buf_len) = slice(buf); + + unsafe { ret_usize(syscall_readonly!(__NR_write, fd, buf_addr, buf_len)) } +} + +#[inline] +pub(crate) fn pwrite(fd: BorrowedFd<'_>, buf: &[u8], pos: u64) -> io::Result<usize> { + let (buf_addr, buf_len) = slice(buf); + + // <https://github.com/torvalds/linux/blob/fcadab740480e0e0e9fa9bd272acd409884d431a/arch/arm64/kernel/sys32.c#L81-L83> + #[cfg(all( + target_pointer_width = "32", + any(target_arch = "arm", target_arch = "mips", target_arch = "power"), + ))] + unsafe { + ret_usize(syscall_readonly!( + __NR_pwrite64, + fd, + buf_addr, + buf_len, + zero(), + hi(pos), + lo(pos) + )) + } + #[cfg(all( + target_pointer_width = "32", + not(any(target_arch = "arm", target_arch = "mips", target_arch = "power")), + ))] + unsafe { + ret_usize(syscall_readonly!( + __NR_pwrite64, + fd, + buf_addr, + buf_len, + hi(pos), + lo(pos) + )) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_usize(syscall_readonly!( + __NR_pwrite64, + fd, + buf_addr, + buf_len, + loff_t_from_u64(pos) + )) + } +} + +#[inline] +pub(crate) fn writev(fd: BorrowedFd<'_>, bufs: &[IoSlice<'_>]) -> io::Result<usize> { + let (bufs_addr, bufs_len) = slice(&bufs[..cmp::min(bufs.len(), max_iov())]); + + unsafe { ret_usize(syscall_readonly!(__NR_writev, fd, bufs_addr, bufs_len)) } +} + +#[inline] +pub(crate) fn pwritev(fd: BorrowedFd<'_>, bufs: &[IoSlice<'_>], pos: u64) -> io::Result<usize> { + let (bufs_addr, bufs_len) = slice(&bufs[..cmp::min(bufs.len(), max_iov())]); + + #[cfg(target_pointer_width = "32")] + unsafe { + ret_usize(syscall_readonly!( + __NR_pwritev, + fd, + bufs_addr, + bufs_len, + hi(pos), + lo(pos) + )) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_usize(syscall_readonly!( + __NR_pwritev, + fd, + bufs_addr, + bufs_len, + loff_t_from_u64(pos) + )) + } +} + +#[inline] +pub(crate) fn pwritev2( + fd: BorrowedFd<'_>, + bufs: &[IoSlice<'_>], + pos: u64, + flags: ReadWriteFlags, +) -> io::Result<usize> { + let (bufs_addr, bufs_len) = slice(&bufs[..cmp::min(bufs.len(), max_iov())]); + + #[cfg(target_pointer_width = "32")] + unsafe { + ret_usize(syscall_readonly!( + __NR_pwritev2, + fd, + bufs_addr, + bufs_len, + hi(pos), + lo(pos), + flags + )) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_usize(syscall_readonly!( + __NR_pwritev2, + fd, + bufs_addr, + bufs_len, + loff_t_from_u64(pos), + flags + )) + } +} + +/// The maximum number of buffers that can be passed into a vectored I/O system +/// call on the current platform. +const fn max_iov() -> usize { + UIO_MAXIOV as usize +} + +#[inline] +pub(crate) unsafe fn close(fd: RawFd) { + // See the documentation for [`io::close`] for why errors are ignored. + syscall_readonly!(__NR_close, raw_fd(fd)).decode_void(); +} + +#[inline] +pub(crate) fn eventfd(initval: u32, flags: EventfdFlags) -> io::Result<OwnedFd> { + unsafe { ret_owned_fd(syscall_readonly!(__NR_eventfd2, c_uint(initval), flags)) } +} + +#[inline] +pub(crate) fn ioctl_fionread(fd: BorrowedFd<'_>) -> io::Result<u64> { + unsafe { + let mut result = MaybeUninit::<c::c_int>::uninit(); + ret(syscall!(__NR_ioctl, fd, c_uint(FIONREAD), &mut result))?; + Ok(result.assume_init() as u64) + } +} + +#[inline] +pub(crate) fn ioctl_fionbio(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> { + unsafe { + let data = c::c_int::from(value); + ret(syscall_readonly!( + __NR_ioctl, + fd, + c_uint(FIONBIO), + by_ref(&data) + )) + } +} + +#[inline] +pub(crate) fn ioctl_tiocexcl(fd: BorrowedFd<'_>) -> io::Result<()> { + unsafe { ret(syscall_readonly!(__NR_ioctl, fd, c_uint(TIOCEXCL))) } +} + +#[inline] +pub(crate) fn ioctl_tiocnxcl(fd: BorrowedFd<'_>) -> io::Result<()> { + unsafe { ret(syscall_readonly!(__NR_ioctl, fd, c_uint(TIOCNXCL))) } +} + +#[inline] +pub(crate) fn ioctl_blksszget(fd: BorrowedFd) -> io::Result<u32> { + let mut result = MaybeUninit::<c::c_uint>::uninit(); + unsafe { + ret(syscall!(__NR_ioctl, fd, c_uint(BLKSSZGET), &mut result))?; + Ok(result.assume_init() as u32) + } +} + +#[inline] +pub(crate) fn ioctl_blkpbszget(fd: BorrowedFd) -> io::Result<u32> { + let mut result = MaybeUninit::<c::c_uint>::uninit(); + unsafe { + ret(syscall!(__NR_ioctl, fd, c_uint(BLKPBSZGET), &mut result))?; + Ok(result.assume_init() as u32) + } +} + +#[cfg(all(feature = "fs", feature = "net"))] +pub(crate) fn is_read_write(fd: BorrowedFd<'_>) -> io::Result<(bool, bool)> { + let (mut read, mut write) = crate::fs::fd::_is_file_read_write(fd)?; + let mut not_socket = false; + if read { + // Do a `recv` with `PEEK` and `DONTWAIT` for 1 byte. A 0 indicates + // the read side is shut down; an `EWOULDBLOCK` indicates the read + // side is still open. + // + // TODO: This code would benefit from having a better way to read into + // uninitialized memory. + let mut buf = [0]; + match super::super::net::syscalls::recv(fd, &mut buf, RecvFlags::PEEK | RecvFlags::DONTWAIT) + { + Ok(0) => read = false, + Err(err) => { + #[allow(unreachable_patterns)] // `EAGAIN` may equal `EWOULDBLOCK` + match err { + io::Errno::AGAIN | io::Errno::WOULDBLOCK => (), + io::Errno::NOTSOCK => not_socket = true, + _ => return Err(err), + } + } + Ok(_) => (), + } + } + if write && !not_socket { + // Do a `send` with `DONTWAIT` for 0 bytes. An `EPIPE` indicates + // the write side is shut down. + #[allow(unreachable_patterns)] // `EAGAIN` equals `EWOULDBLOCK` + match super::super::net::syscalls::send(fd, &[], SendFlags::DONTWAIT) { + // TODO or-patterns when we don't need 1.51 + Err(io::Errno::AGAIN) => (), + Err(io::Errno::WOULDBLOCK) => (), + Err(io::Errno::NOTSOCK) => (), + Err(io::Errno::PIPE) => write = false, + Err(err) => return Err(err), + Ok(_) => (), + } + } + Ok((read, write)) +} + +#[inline] +pub(crate) fn dup(fd: BorrowedFd<'_>) -> io::Result<OwnedFd> { + unsafe { ret_owned_fd(syscall_readonly!(__NR_dup, fd)) } +} + +#[inline] +pub(crate) fn dup2(fd: BorrowedFd<'_>, new: &mut OwnedFd) -> io::Result<()> { + #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + { + // We don't need to worry about the difference between `dup2` and + // `dup3` when the file descriptors are equal because we have an + // `&mut OwnedFd` which means `fd` doesn't alias it. + dup3(fd, new, DupFlags::empty()) + } + + #[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))] + unsafe { + ret_discarded_fd(syscall_readonly!(__NR_dup2, fd, new.as_fd())) + } +} + +#[inline] +pub(crate) fn dup3(fd: BorrowedFd<'_>, new: &mut OwnedFd, flags: DupFlags) -> io::Result<()> { + unsafe { ret_discarded_fd(syscall_readonly!(__NR_dup3, fd, new.as_fd(), flags)) } +} + +#[inline] +pub(crate) fn fcntl_getfd(fd: BorrowedFd<'_>) -> io::Result<FdFlags> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret_c_uint(syscall_readonly!(__NR_fcntl64, fd, c_uint(F_GETFD))) + .map(FdFlags::from_bits_truncate) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_c_uint(syscall_readonly!(__NR_fcntl, fd, c_uint(F_GETFD))) + .map(FdFlags::from_bits_truncate) + } +} + +#[inline] +pub(crate) fn fcntl_setfd(fd: BorrowedFd<'_>, flags: FdFlags) -> io::Result<()> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret(syscall_readonly!(__NR_fcntl64, fd, c_uint(F_SETFD), flags)) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret(syscall_readonly!(__NR_fcntl, fd, c_uint(F_SETFD), flags)) + } +} + +#[cfg(target_os = "espidf")] +#[inline] +pub(crate) fn fcntl_dupfd(fd: BorrowedFd<'_>, min: RawFd) -> io::Result<OwnedFd> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret_owned_fd(syscall_readonly!( + __NR_fcntl64, + fd, + c_uint(F_DUPFD), + raw_fd(min) + )) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_owned_fd(syscall_readonly!( + __NR_fcntl, + fd, + c_uint(F_DUPFD), + raw_fd(min) + )) + } +} + +#[inline] +pub(crate) fn fcntl_dupfd_cloexec(fd: BorrowedFd<'_>, min: RawFd) -> io::Result<OwnedFd> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret_owned_fd(syscall_readonly!( + __NR_fcntl64, + fd, + c_uint(F_DUPFD_CLOEXEC), + raw_fd(min) + )) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_owned_fd(syscall_readonly!( + __NR_fcntl, + fd, + c_uint(F_DUPFD_CLOEXEC), + raw_fd(min) + )) + } +} + +#[inline] +pub(crate) fn pipe_with(flags: PipeFlags) -> io::Result<(OwnedFd, OwnedFd)> { + unsafe { + let mut result = MaybeUninit::<[OwnedFd; 2]>::uninit(); + ret(syscall!(__NR_pipe2, &mut result, flags))?; + let [p0, p1] = result.assume_init(); + Ok((p0, p1)) + } +} + +#[inline] +pub(crate) fn pipe() -> io::Result<(OwnedFd, OwnedFd)> { + // aarch64 and risc64 omit `__NR_pipe`. On mips, `__NR_pipe` uses a special + // calling convention, but using it is not worth complicating our syscall + // wrapping infrastructure at this time. + #[cfg(any( + target_arch = "aarch64", + target_arch = "mips", + target_arch = "mips64", + target_arch = "riscv64", + ))] + { + pipe_with(PipeFlags::empty()) + } + #[cfg(not(any( + target_arch = "aarch64", + target_arch = "mips", + target_arch = "mips64", + target_arch = "riscv64", + )))] + unsafe { + let mut result = MaybeUninit::<[OwnedFd; 2]>::uninit(); + ret(syscall!(__NR_pipe, &mut result))?; + let [p0, p1] = result.assume_init(); + Ok((p0, p1)) + } +} + +#[inline] +pub(crate) fn poll(fds: &mut [PollFd<'_>], timeout: c::c_int) -> io::Result<usize> { + let (fds_addr_mut, fds_len) = slice_mut(fds); + + #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + unsafe { + let timeout = if timeout >= 0 { + Some(__kernel_timespec { + tv_sec: (timeout as i64) / 1000, + tv_nsec: (timeout as i64) % 1000 * 1_000_000, + }) + } else { + None + }; + ret_usize(syscall!( + __NR_ppoll, + fds_addr_mut, + fds_len, + opt_ref(timeout.as_ref()), + zero(), + size_of::<sigset_t, _>() + )) + } + #[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))] + unsafe { + ret_usize(syscall!(__NR_poll, fds_addr_mut, fds_len, c_int(timeout))) + } +} + +#[inline] +pub(crate) fn epoll_create(flags: epoll::CreateFlags) -> io::Result<OwnedFd> { + unsafe { ret_owned_fd(syscall_readonly!(__NR_epoll_create1, flags)) } +} + +#[inline] +pub(crate) unsafe fn epoll_add( + epfd: BorrowedFd<'_>, + fd: c::c_int, + event: &epoll_event, +) -> io::Result<()> { + ret(syscall_readonly!( + __NR_epoll_ctl, + epfd, + c_uint(EPOLL_CTL_ADD), + raw_fd(fd), + by_ref(event) + )) +} + +#[inline] +pub(crate) unsafe fn epoll_mod( + epfd: BorrowedFd<'_>, + fd: c::c_int, + event: &epoll_event, +) -> io::Result<()> { + ret(syscall_readonly!( + __NR_epoll_ctl, + epfd, + c_uint(EPOLL_CTL_MOD), + raw_fd(fd), + by_ref(event) + )) +} + +#[inline] +pub(crate) unsafe fn epoll_del(epfd: BorrowedFd<'_>, fd: c::c_int) -> io::Result<()> { + ret(syscall_readonly!( + __NR_epoll_ctl, + epfd, + c_uint(EPOLL_CTL_DEL), + raw_fd(fd), + zero() + )) +} + +#[inline] +pub(crate) fn epoll_wait( + epfd: BorrowedFd<'_>, + events: *mut epoll_event, + num_events: usize, + timeout: c::c_int, +) -> io::Result<usize> { + #[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))] + unsafe { + ret_usize(syscall!( + __NR_epoll_wait, + epfd, + events, + pass_usize(num_events), + c_int(timeout) + )) + } + #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + unsafe { + ret_usize(syscall!( + __NR_epoll_pwait, + epfd, + events, + pass_usize(num_events), + c_int(timeout), + zero() + )) + } +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[inline] +pub fn splice( + fd_in: BorrowedFd, + off_in: Option<&mut u64>, + fd_out: BorrowedFd, + off_out: Option<&mut u64>, + len: usize, + flags: SpliceFlags, +) -> io::Result<usize> { + unsafe { + ret_usize(syscall!( + __NR_splice, + fd_in, + opt_mut(off_in), + fd_out, + opt_mut(off_out), + pass_usize(len), + c_uint(flags.bits()) + )) + } +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[inline] +pub unsafe fn vmsplice( + fd: BorrowedFd, + bufs: &[IoSliceRaw], + flags: SpliceFlags, +) -> io::Result<usize> { + let (bufs_addr, bufs_len) = slice(&bufs[..cmp::min(bufs.len(), max_iov())]); + ret_usize(syscall!( + __NR_vmsplice, + fd, + bufs_addr, + bufs_len, + c_uint(flags.bits()) + )) +} diff --git a/vendor/rustix/src/backend/linux_raw/io/types.rs b/vendor/rustix/src/backend/linux_raw/io/types.rs new file mode 100644 index 000000000..51ab61d94 --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/io/types.rs @@ -0,0 +1,128 @@ +use super::super::c; +use bitflags::bitflags; +use core::marker::PhantomData; + +bitflags! { + /// `FD_*` constants for use with [`fcntl_getfd`] and [`fcntl_setfd`]. + /// + /// [`fcntl_getfd`]: crate::io::fcntl_getfd + /// [`fcntl_setfd`]: crate::io::fcntl_setfd + pub struct FdFlags: c::c_uint { + /// `FD_CLOEXEC` + const CLOEXEC = linux_raw_sys::general::FD_CLOEXEC; + } +} + +bitflags! { + /// `RWF_*` constants for use with [`preadv2`] and [`pwritev2`]. + /// + /// [`preadv2`]: crate::io::preadv2 + /// [`pwritev2`]: crate::io::pwritev + pub struct ReadWriteFlags: c::c_uint { + /// `RWF_DSYNC` (since Linux 4.7) + const DSYNC = linux_raw_sys::general::RWF_DSYNC; + /// `RWF_HIPRI` (since Linux 4.6) + const HIPRI = linux_raw_sys::general::RWF_HIPRI; + /// `RWF_SYNC` (since Linux 4.7) + const SYNC = linux_raw_sys::general::RWF_SYNC; + /// `RWF_NOWAIT` (since Linux 4.14) + const NOWAIT = linux_raw_sys::general::RWF_NOWAIT; + /// `RWF_APPEND` (since Linux 4.16) + const APPEND = linux_raw_sys::general::RWF_APPEND; + } +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +bitflags! { + /// `SPLICE_F_*` constants for use with [`splice`] and [`vmsplice`]. + pub struct SpliceFlags: c::c_uint { + /// `SPLICE_F_MOVE` + const MOVE = linux_raw_sys::general::SPLICE_F_MOVE; + /// `SPLICE_F_NONBLOCK` + const NONBLOCK = linux_raw_sys::general::SPLICE_F_NONBLOCK; + /// `SPLICE_F_MORE` + const MORE = linux_raw_sys::general::SPLICE_F_MORE; + /// `SPLICE_F_GIFT` + const GIFT = linux_raw_sys::general::SPLICE_F_GIFT; + } +} + +bitflags! { + /// `O_*` constants for use with [`dup2`]. + /// + /// [`dup2`]: crate::io::dup2 + pub struct DupFlags: c::c_uint { + /// `O_CLOEXEC` + const CLOEXEC = linux_raw_sys::general::O_CLOEXEC; + } +} + +bitflags! { + /// `O_*` constants for use with [`pipe_with`]. + /// + /// [`pipe_with`]: crate::io::pipe_with + pub struct PipeFlags: c::c_uint { + /// `O_CLOEXEC` + const CLOEXEC = linux_raw_sys::general::O_CLOEXEC; + /// `O_DIRECT` + const DIRECT = linux_raw_sys::general::O_DIRECT; + /// `O_NONBLOCK` + const NONBLOCK = linux_raw_sys::general::O_NONBLOCK; + } +} + +bitflags! { + /// `EFD_*` flags for use with [`eventfd`]. + /// + /// [`eventfd`]: crate::io::eventfd + pub struct EventfdFlags: c::c_uint { + /// `EFD_CLOEXEC` + const CLOEXEC = linux_raw_sys::general::EFD_CLOEXEC; + /// `EFD_NONBLOCK` + const NONBLOCK = linux_raw_sys::general::EFD_NONBLOCK; + /// `EFD_SEMAPHORE` + const SEMAPHORE = linux_raw_sys::general::EFD_SEMAPHORE; + } +} + +/// `PIPE_BUF`—The maximum size of a write to a pipe guaranteed to be atomic. +pub const PIPE_BUF: usize = linux_raw_sys::general::PIPE_BUF as usize; + +pub(crate) const AT_FDCWD: c::c_int = linux_raw_sys::general::AT_FDCWD; +pub(crate) const STDIN_FILENO: c::c_uint = linux_raw_sys::general::STDIN_FILENO; +pub(crate) const STDOUT_FILENO: c::c_uint = linux_raw_sys::general::STDOUT_FILENO; +pub(crate) const STDERR_FILENO: c::c_uint = linux_raw_sys::general::STDERR_FILENO; + +/// A buffer type used with `vmsplice`. +/// It is guaranteed to be ABI compatible with the iovec type on Unix platforms and WSABUF on Windows. +/// Unlike `IoSlice` and `IoSliceMut` it is semantically like a raw pointer, +/// and therefore can be shared or mutated as needed. +#[repr(transparent)] +pub struct IoSliceRaw<'a> { + _buf: c::iovec, + _lifetime: PhantomData<&'a ()>, +} + +impl<'a> IoSliceRaw<'a> { + /// Creates a new IoSlice wrapping a byte slice. + pub fn from_slice(buf: &'a [u8]) -> Self { + IoSliceRaw { + _buf: c::iovec { + iov_base: buf.as_ptr() as *mut u8 as *mut c::c_void, + iov_len: buf.len() as _, + }, + _lifetime: PhantomData, + } + } + + /// Creates a new IoSlice wrapping a mutable byte slice. + pub fn from_slice_mut(buf: &'a mut [u8]) -> Self { + IoSliceRaw { + _buf: c::iovec { + iov_base: buf.as_mut_ptr() as *mut c::c_void, + iov_len: buf.len() as _, + }, + _lifetime: PhantomData, + } + } +} diff --git a/vendor/rustix/src/imp/linux_raw/io_uring/mod.rs b/vendor/rustix/src/backend/linux_raw/io_uring/mod.rs index ef944f04d..ef944f04d 100644 --- a/vendor/rustix/src/imp/linux_raw/io_uring/mod.rs +++ b/vendor/rustix/src/backend/linux_raw/io_uring/mod.rs diff --git a/vendor/rustix/src/backend/linux_raw/io_uring/syscalls.rs b/vendor/rustix/src/backend/linux_raw/io_uring/syscalls.rs new file mode 100644 index 000000000..196676985 --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/io_uring/syscalls.rs @@ -0,0 +1,63 @@ +//! linux_raw syscalls supporting `rustix::io_uring`. +//! +//! # Safety +//! +//! See the `rustix::backend::syscalls` module documentation for details. +#![allow(unsafe_code)] +#![allow(clippy::undocumented_unsafe_blocks)] + +use super::super::conv::{by_mut, c_uint, pass_usize, ret, ret_c_uint, ret_owned_fd}; +use crate::fd::{BorrowedFd, OwnedFd}; +use crate::io; +use crate::io_uring::{io_uring_params, IoringEnterFlags, IoringRegisterOp}; +use core::ffi::c_void; + +#[inline] +pub(crate) fn io_uring_setup(entries: u32, params: &mut io_uring_params) -> io::Result<OwnedFd> { + unsafe { + ret_owned_fd(syscall!( + __NR_io_uring_setup, + c_uint(entries), + by_mut(params) + )) + } +} + +#[inline] +pub(crate) unsafe fn io_uring_register( + fd: BorrowedFd<'_>, + opcode: IoringRegisterOp, + arg: *const c_void, + nr_args: u32, +) -> io::Result<()> { + ret(syscall_readonly!( + __NR_io_uring_register, + fd, + c_uint(opcode as u32), + arg, + c_uint(nr_args) + )) +} + +#[inline] +pub(crate) unsafe fn io_uring_enter( + fd: BorrowedFd<'_>, + to_submit: u32, + min_complete: u32, + flags: IoringEnterFlags, + arg: *const c_void, + size: usize, +) -> io::Result<u32> { + // This is not `_readonly` because `io_uring_enter` waits for I/O to + // complete, and I/O could involve writing to memory buffers, which + // could be a side effect depended on by the caller. + ret_c_uint(syscall!( + __NR_io_uring_enter, + fd, + c_uint(to_submit), + c_uint(min_complete), + flags, + arg, + pass_usize(size) + )) +} diff --git a/vendor/rustix/src/imp/linux_raw/mm/mod.rs b/vendor/rustix/src/backend/linux_raw/mm/mod.rs index 1e0181a99..1e0181a99 100644 --- a/vendor/rustix/src/imp/linux_raw/mm/mod.rs +++ b/vendor/rustix/src/backend/linux_raw/mm/mod.rs diff --git a/vendor/rustix/src/backend/linux_raw/mm/syscalls.rs b/vendor/rustix/src/backend/linux_raw/mm/syscalls.rs new file mode 100644 index 000000000..8fa6a3ec3 --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/mm/syscalls.rs @@ -0,0 +1,214 @@ +//! linux_raw syscalls supporting `rustix::io`. +//! +//! # Safety +//! +//! See the `rustix::backend` module documentation for details. +#![allow(unsafe_code)] +#![allow(clippy::undocumented_unsafe_blocks)] + +use super::super::c; +#[cfg(target_pointer_width = "64")] +use super::super::conv::loff_t_from_u64; +use super::super::conv::{c_uint, no_fd, pass_usize, ret, ret_owned_fd, ret_void_star}; +use super::types::{ + Advice, MapFlags, MlockFlags, MprotectFlags, MremapFlags, MsyncFlags, ProtFlags, + UserfaultfdFlags, +}; +use crate::fd::{BorrowedFd, OwnedFd}; +use crate::io; +#[cfg(target_pointer_width = "32")] +use core::convert::TryInto; +use linux_raw_sys::general::MAP_ANONYMOUS; + +#[inline] +pub(crate) fn madvise(addr: *mut c::c_void, len: usize, advice: Advice) -> io::Result<()> { + unsafe { + ret(syscall!( + __NR_madvise, + addr, + pass_usize(len), + c_uint(advice as c::c_uint) + )) + } +} + +#[inline] +pub(crate) unsafe fn msync(addr: *mut c::c_void, len: usize, flags: MsyncFlags) -> io::Result<()> { + ret(syscall!(__NR_msync, addr, pass_usize(len), flags)) +} + +/// # Safety +/// +/// `mmap` is primarily unsafe due to the `addr` parameter, as anything working +/// with memory pointed to by raw pointers is unsafe. +#[inline] +pub(crate) unsafe fn mmap( + addr: *mut c::c_void, + length: usize, + prot: ProtFlags, + flags: MapFlags, + fd: BorrowedFd<'_>, + offset: u64, +) -> io::Result<*mut c::c_void> { + #[cfg(target_pointer_width = "32")] + { + ret_void_star(syscall!( + __NR_mmap2, + addr, + pass_usize(length), + prot, + flags, + fd, + (offset / 4096) + .try_into() + .map(pass_usize) + .map_err(|_| io::Errno::INVAL)? + )) + } + #[cfg(target_pointer_width = "64")] + { + ret_void_star(syscall!( + __NR_mmap, + addr, + pass_usize(length), + prot, + flags, + fd, + loff_t_from_u64(offset) + )) + } +} + +/// # Safety +/// +/// `mmap` is primarily unsafe due to the `addr` parameter, as anything working +/// with memory pointed to by raw pointers is unsafe. +#[inline] +pub(crate) unsafe fn mmap_anonymous( + addr: *mut c::c_void, + length: usize, + prot: ProtFlags, + flags: MapFlags, +) -> io::Result<*mut c::c_void> { + #[cfg(target_pointer_width = "32")] + { + ret_void_star(syscall!( + __NR_mmap2, + addr, + pass_usize(length), + prot, + c_uint(flags.bits() | MAP_ANONYMOUS), + no_fd(), + pass_usize(0) + )) + } + #[cfg(target_pointer_width = "64")] + { + ret_void_star(syscall!( + __NR_mmap, + addr, + pass_usize(length), + prot, + c_uint(flags.bits() | MAP_ANONYMOUS), + no_fd(), + loff_t_from_u64(0) + )) + } +} + +#[inline] +pub(crate) unsafe fn mprotect( + ptr: *mut c::c_void, + len: usize, + flags: MprotectFlags, +) -> io::Result<()> { + ret(syscall!(__NR_mprotect, ptr, pass_usize(len), flags)) +} + +/// # Safety +/// +/// `munmap` is primarily unsafe due to the `addr` parameter, as anything +/// working with memory pointed to by raw pointers is unsafe. +#[inline] +pub(crate) unsafe fn munmap(addr: *mut c::c_void, length: usize) -> io::Result<()> { + ret(syscall!(__NR_munmap, addr, pass_usize(length))) +} + +/// # Safety +/// +/// `mremap` is primarily unsafe due to the `old_address` parameter, as +/// anything working with memory pointed to by raw pointers is unsafe. +#[inline] +pub(crate) unsafe fn mremap( + old_address: *mut c::c_void, + old_size: usize, + new_size: usize, + flags: MremapFlags, +) -> io::Result<*mut c::c_void> { + ret_void_star(syscall!( + __NR_mremap, + old_address, + pass_usize(old_size), + pass_usize(new_size), + flags + )) +} + +/// # Safety +/// +/// `mremap_fixed` is primarily unsafe due to the `old_address` and +/// `new_address` parameters, as anything working with memory pointed to by raw +/// pointers is unsafe. +#[inline] +pub(crate) unsafe fn mremap_fixed( + old_address: *mut c::c_void, + old_size: usize, + new_size: usize, + flags: MremapFlags, + new_address: *mut c::c_void, +) -> io::Result<*mut c::c_void> { + ret_void_star(syscall!( + __NR_mremap, + old_address, + pass_usize(old_size), + pass_usize(new_size), + flags, + new_address + )) +} + +/// # Safety +/// +/// `mlock` operates on raw pointers and may round out to the nearest page +/// boundaries. +#[inline] +pub(crate) unsafe fn mlock(addr: *mut c::c_void, length: usize) -> io::Result<()> { + ret(syscall!(__NR_mlock, addr, pass_usize(length))) +} + +/// # Safety +/// +/// `mlock_with` operates on raw pointers and may round out to the nearest page +/// boundaries. +#[inline] +pub(crate) unsafe fn mlock_with( + addr: *mut c::c_void, + length: usize, + flags: MlockFlags, +) -> io::Result<()> { + ret(syscall!(__NR_mlock2, addr, pass_usize(length), flags)) +} + +/// # Safety +/// +/// `munlock` operates on raw pointers and may round out to the nearest page +/// boundaries. +#[inline] +pub(crate) unsafe fn munlock(addr: *mut c::c_void, length: usize) -> io::Result<()> { + ret(syscall!(__NR_munlock, addr, pass_usize(length))) +} + +#[inline] +pub(crate) unsafe fn userfaultfd(flags: UserfaultfdFlags) -> io::Result<OwnedFd> { + ret_owned_fd(syscall_readonly!(__NR_userfaultfd, flags)) +} diff --git a/vendor/rustix/src/imp/linux_raw/mm/types.rs b/vendor/rustix/src/backend/linux_raw/mm/types.rs index a58dd76be..a58dd76be 100644 --- a/vendor/rustix/src/imp/linux_raw/mm/types.rs +++ b/vendor/rustix/src/backend/linux_raw/mm/types.rs diff --git a/vendor/rustix/src/backend/linux_raw/mod.rs b/vendor/rustix/src/backend/linux_raw/mod.rs new file mode 100644 index 000000000..231dc37b6 --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/mod.rs @@ -0,0 +1,68 @@ +//! The linux_raw backend. +//! +//! This makes Linux syscalls directly, without going through libc. +//! +//! # Safety +//! +//! These files performs raw system calls, and sometimes passes them +//! uninitialized memory buffers. The signatures in this file are currently +//! manually maintained and must correspond with the signatures of the actual +//! Linux syscalls. +//! +//! Some of this could be auto-generated from the Linux header file +//! <linux/syscalls.h>, but we often need more information than it provides, +//! such as which pointers are array slices, out parameters, or in-out +//! parameters, which integers are owned or borrowed file descriptors, etc. + +#[macro_use] +mod arch; +mod conv; +mod elf; +mod reg; +#[cfg(any(feature = "time", target_arch = "x86"))] +mod vdso; +#[cfg(any(feature = "time", target_arch = "x86"))] +mod vdso_wrappers; + +#[cfg(feature = "fs")] +pub(crate) mod fs; +pub(crate) mod io; +#[cfg(feature = "io_uring")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "io_uring")))] +pub(crate) mod io_uring; +#[cfg(feature = "mm")] +pub(crate) mod mm; +#[cfg(feature = "net")] +pub(crate) mod net; +#[cfg(any( + feature = "param", + feature = "runtime", + feature = "time", + target_arch = "x86", +))] +pub(crate) mod param; +pub(crate) mod process; +#[cfg(feature = "rand")] +pub(crate) mod rand; +#[cfg(feature = "runtime")] +pub(crate) mod runtime; +#[cfg(feature = "termios")] +pub(crate) mod termios; +#[cfg(feature = "thread")] +pub(crate) mod thread; +pub(crate) mod time; + +#[cfg(feature = "std")] +pub(crate) mod fd { + pub use io_lifetimes::*; + #[allow(unused_imports)] + pub(crate) use std::os::unix::io::RawFd as LibcFd; + pub use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +} + +#[cfg(not(feature = "std"))] +pub(crate) use crate::io::fd; + +// The linux_raw backend doesn't use actual libc, so we define selected +// libc-like definitions in a module called `c`. +pub(crate) mod c; diff --git a/vendor/rustix/src/imp/linux_raw/net/addr.rs b/vendor/rustix/src/backend/linux_raw/net/addr.rs index d5683f34e..d5683f34e 100644 --- a/vendor/rustix/src/imp/linux_raw/net/addr.rs +++ b/vendor/rustix/src/backend/linux_raw/net/addr.rs diff --git a/vendor/rustix/src/backend/linux_raw/net/mod.rs b/vendor/rustix/src/backend/linux_raw/net/mod.rs new file mode 100644 index 000000000..f2273db1b --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/net/mod.rs @@ -0,0 +1,6 @@ +pub(crate) mod addr; +pub(crate) mod read_sockaddr; +pub(crate) mod send_recv; +pub(crate) mod syscalls; +pub(crate) mod types; +pub(crate) mod write_sockaddr; diff --git a/vendor/rustix/src/imp/linux_raw/net/read_sockaddr.rs b/vendor/rustix/src/backend/linux_raw/net/read_sockaddr.rs index b9bc09b96..b9bc09b96 100644 --- a/vendor/rustix/src/imp/linux_raw/net/read_sockaddr.rs +++ b/vendor/rustix/src/backend/linux_raw/net/read_sockaddr.rs diff --git a/vendor/rustix/src/imp/linux_raw/net/send_recv.rs b/vendor/rustix/src/backend/linux_raw/net/send_recv.rs index 888e81e2b..888e81e2b 100644 --- a/vendor/rustix/src/imp/linux_raw/net/send_recv.rs +++ b/vendor/rustix/src/backend/linux_raw/net/send_recv.rs diff --git a/vendor/rustix/src/backend/linux_raw/net/syscalls.rs b/vendor/rustix/src/backend/linux_raw/net/syscalls.rs new file mode 100644 index 000000000..7b9947a03 --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/net/syscalls.rs @@ -0,0 +1,1248 @@ +//! linux_raw syscalls supporting `rustix::net`. +//! +//! # Safety +//! +//! See the `rustix::backend` module documentation for details. +#![allow(unsafe_code)] +#![allow(clippy::undocumented_unsafe_blocks)] + +use super::super::c; +use super::super::conv::{ + by_mut, by_ref, c_int, c_uint, ret, ret_owned_fd, ret_usize, size_of, slice, slice_mut, + socklen_t, zero, +}; +use super::read_sockaddr::{initialize_family_to_unspec, maybe_read_sockaddr_os, read_sockaddr_os}; +use super::send_recv::{RecvFlags, SendFlags}; +use super::types::{AcceptFlags, AddressFamily, Protocol, Shutdown, SocketFlags, SocketType}; +use super::write_sockaddr::{encode_sockaddr_v4, encode_sockaddr_v6}; +use crate::fd::{BorrowedFd, OwnedFd}; +use crate::io; +use crate::net::{SocketAddrAny, SocketAddrUnix, SocketAddrV4, SocketAddrV6}; +use c::{sockaddr, sockaddr_in, sockaddr_in6, socklen_t}; +use core::convert::TryInto; +use core::mem::MaybeUninit; +#[cfg(target_arch = "x86")] +use { + super::super::conv::{slice_just_addr, x86_sys}, + super::super::reg::{ArgReg, SocketArg}, + linux_raw_sys::general::{ + SYS_ACCEPT, SYS_ACCEPT4, SYS_BIND, SYS_CONNECT, SYS_GETPEERNAME, SYS_GETSOCKNAME, + SYS_GETSOCKOPT, SYS_LISTEN, SYS_RECV, SYS_RECVFROM, SYS_SEND, SYS_SENDTO, SYS_SETSOCKOPT, + SYS_SHUTDOWN, SYS_SOCKET, SYS_SOCKETPAIR, + }, +}; + +#[inline] +pub(crate) fn socket( + family: AddressFamily, + type_: SocketType, + protocol: Protocol, +) -> io::Result<OwnedFd> { + #[cfg(not(target_arch = "x86"))] + unsafe { + ret_owned_fd(syscall_readonly!(__NR_socket, family, type_, protocol)) + } + #[cfg(target_arch = "x86")] + unsafe { + ret_owned_fd(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_SOCKET), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + family.into(), + type_.into(), + protocol.into(), + ]) + )) + } +} + +#[inline] +pub(crate) fn socket_with( + family: AddressFamily, + type_: SocketType, + flags: SocketFlags, + protocol: Protocol, +) -> io::Result<OwnedFd> { + #[cfg(not(target_arch = "x86"))] + unsafe { + ret_owned_fd(syscall_readonly!( + __NR_socket, + family, + (type_, flags), + protocol + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret_owned_fd(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_SOCKET), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + family.into(), + (type_, flags).into(), + protocol.into(), + ]) + )) + } +} + +#[inline] +pub(crate) fn socketpair( + family: AddressFamily, + type_: SocketType, + flags: SocketFlags, + protocol: Protocol, +) -> io::Result<(OwnedFd, OwnedFd)> { + #[cfg(not(target_arch = "x86"))] + unsafe { + let mut result = MaybeUninit::<[OwnedFd; 2]>::uninit(); + ret(syscall!( + __NR_socketpair, + family, + (type_, flags), + protocol, + &mut result + ))?; + let [fd0, fd1] = result.assume_init(); + Ok((fd0, fd1)) + } + #[cfg(target_arch = "x86")] + unsafe { + let mut result = MaybeUninit::<[OwnedFd; 2]>::uninit(); + ret(syscall!( + __NR_socketcall, + x86_sys(SYS_SOCKETPAIR), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + family.into(), + (type_, flags).into(), + protocol.into(), + (&mut result).into(), + ]) + ))?; + let [fd0, fd1] = result.assume_init(); + Ok((fd0, fd1)) + } +} + +#[inline] +pub(crate) fn accept(fd: BorrowedFd<'_>) -> io::Result<OwnedFd> { + #[cfg(not(target_arch = "x86"))] + unsafe { + let fd = ret_owned_fd(syscall_readonly!(__NR_accept, fd, zero(), zero()))?; + Ok(fd) + } + #[cfg(target_arch = "x86")] + unsafe { + let fd = ret_owned_fd(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_ACCEPT), + slice_just_addr::<ArgReg<SocketArg>, _>(&[fd.into(), zero(), zero()]) + ))?; + Ok(fd) + } +} + +#[inline] +pub(crate) fn accept_with(fd: BorrowedFd<'_>, flags: AcceptFlags) -> io::Result<OwnedFd> { + #[cfg(not(target_arch = "x86"))] + unsafe { + let fd = ret_owned_fd(syscall_readonly!(__NR_accept4, fd, zero(), zero(), flags))?; + Ok(fd) + } + #[cfg(target_arch = "x86")] + unsafe { + let fd = ret_owned_fd(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_ACCEPT4), + slice_just_addr::<ArgReg<SocketArg>, _>(&[fd.into(), zero(), zero(), flags.into()]) + ))?; + Ok(fd) + } +} + +#[inline] +pub(crate) fn acceptfrom(fd: BorrowedFd<'_>) -> io::Result<(OwnedFd, Option<SocketAddrAny>)> { + #[cfg(not(target_arch = "x86"))] + unsafe { + let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t; + let mut storage = MaybeUninit::<sockaddr>::uninit(); + let fd = ret_owned_fd(syscall!( + __NR_accept, + fd, + &mut storage, + by_mut(&mut addrlen) + ))?; + Ok(( + fd, + maybe_read_sockaddr_os(&storage.assume_init(), addrlen.try_into().unwrap()), + )) + } + #[cfg(target_arch = "x86")] + unsafe { + let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t; + let mut storage = MaybeUninit::<sockaddr>::uninit(); + let fd = ret_owned_fd(syscall!( + __NR_socketcall, + x86_sys(SYS_ACCEPT), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + (&mut storage).into(), + by_mut(&mut addrlen), + ]) + ))?; + Ok(( + fd, + maybe_read_sockaddr_os(&storage.assume_init(), addrlen.try_into().unwrap()), + )) + } +} + +#[inline] +pub(crate) fn acceptfrom_with( + fd: BorrowedFd<'_>, + flags: AcceptFlags, +) -> io::Result<(OwnedFd, Option<SocketAddrAny>)> { + #[cfg(not(target_arch = "x86"))] + unsafe { + let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t; + let mut storage = MaybeUninit::<sockaddr>::uninit(); + let fd = ret_owned_fd(syscall!( + __NR_accept4, + fd, + &mut storage, + by_mut(&mut addrlen), + flags + ))?; + Ok(( + fd, + maybe_read_sockaddr_os(&storage.assume_init(), addrlen.try_into().unwrap()), + )) + } + #[cfg(target_arch = "x86")] + unsafe { + let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t; + let mut storage = MaybeUninit::<sockaddr>::uninit(); + let fd = ret_owned_fd(syscall!( + __NR_socketcall, + x86_sys(SYS_ACCEPT4), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + (&mut storage).into(), + by_mut(&mut addrlen), + flags.into(), + ]) + ))?; + Ok(( + fd, + maybe_read_sockaddr_os(&storage.assume_init(), addrlen.try_into().unwrap()), + )) + } +} + +#[inline] +pub(crate) fn shutdown(fd: BorrowedFd<'_>, how: Shutdown) -> io::Result<()> { + #[cfg(not(target_arch = "x86"))] + unsafe { + ret(syscall_readonly!( + __NR_shutdown, + fd, + c_uint(how as c::c_uint) + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_SHUTDOWN), + slice_just_addr::<ArgReg<SocketArg>, _>(&[fd.into(), c_uint(how as c::c_uint)]) + )) + } +} + +#[inline] +pub(crate) fn send(fd: BorrowedFd<'_>, buf: &[u8], flags: SendFlags) -> io::Result<usize> { + let (buf_addr, buf_len) = slice(buf); + + #[cfg(not(any( + target_arch = "aarch64", + target_arch = "mips64", + target_arch = "riscv64", + target_arch = "x86", + target_arch = "x86_64", + )))] + unsafe { + ret_usize(syscall_readonly!(__NR_send, fd, buf_addr, buf_len, flags)) + } + #[cfg(any( + target_arch = "aarch64", + target_arch = "mips64", + target_arch = "riscv64", + target_arch = "x86_64", + ))] + unsafe { + ret_usize(syscall_readonly!( + __NR_sendto, + fd, + buf_addr, + buf_len, + flags, + zero(), + zero() + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret_usize(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_SEND), + slice_just_addr::<ArgReg<SocketArg>, _>(&[fd.into(), buf_addr, buf_len, flags.into()]) + )) + } +} + +#[inline] +pub(crate) fn sendto_v4( + fd: BorrowedFd<'_>, + buf: &[u8], + flags: SendFlags, + addr: &SocketAddrV4, +) -> io::Result<usize> { + let (buf_addr, buf_len) = slice(buf); + + #[cfg(not(target_arch = "x86"))] + unsafe { + ret_usize(syscall_readonly!( + __NR_sendto, + fd, + buf_addr, + buf_len, + flags, + by_ref(&encode_sockaddr_v4(addr)), + size_of::<sockaddr_in, _>() + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret_usize(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_SENDTO), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + buf_addr, + buf_len, + flags.into(), + by_ref(&encode_sockaddr_v4(addr)), + size_of::<sockaddr_in, _>(), + ]) + )) + } +} + +#[inline] +pub(crate) fn sendto_v6( + fd: BorrowedFd<'_>, + buf: &[u8], + flags: SendFlags, + addr: &SocketAddrV6, +) -> io::Result<usize> { + let (buf_addr, buf_len) = slice(buf); + + #[cfg(not(target_arch = "x86"))] + unsafe { + ret_usize(syscall_readonly!( + __NR_sendto, + fd, + buf_addr, + buf_len, + flags, + by_ref(&encode_sockaddr_v6(addr)), + size_of::<sockaddr_in6, _>() + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret_usize(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_SENDTO), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + buf_addr, + buf_len, + flags.into(), + by_ref(&encode_sockaddr_v6(addr)), + size_of::<sockaddr_in6, _>(), + ]) + )) + } +} + +#[inline] +pub(crate) fn sendto_unix( + fd: BorrowedFd<'_>, + buf: &[u8], + flags: SendFlags, + addr: &SocketAddrUnix, +) -> io::Result<usize> { + let (buf_addr, buf_len) = slice(buf); + + #[cfg(not(target_arch = "x86"))] + unsafe { + ret_usize(syscall_readonly!( + __NR_sendto, + fd, + buf_addr, + buf_len, + flags, + by_ref(&addr.unix), + socklen_t(addr.addr_len()) + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret_usize(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_SENDTO), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + buf_addr, + buf_len, + flags.into(), + by_ref(&addr.unix), + socklen_t(addr.addr_len()), + ]) + )) + } +} + +#[inline] +pub(crate) fn recv(fd: BorrowedFd<'_>, buf: &mut [u8], flags: RecvFlags) -> io::Result<usize> { + let (buf_addr_mut, buf_len) = slice_mut(buf); + + #[cfg(not(any( + target_arch = "aarch64", + target_arch = "mips64", + target_arch = "riscv64", + target_arch = "x86", + target_arch = "x86_64", + )))] + unsafe { + ret_usize(syscall!(__NR_recv, fd, buf_addr_mut, buf_len, flags)) + } + #[cfg(any( + target_arch = "aarch64", + target_arch = "mips64", + target_arch = "riscv64", + target_arch = "x86_64", + ))] + unsafe { + ret_usize(syscall!( + __NR_recvfrom, + fd, + buf_addr_mut, + buf_len, + flags, + zero(), + zero() + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret_usize(syscall!( + __NR_socketcall, + x86_sys(SYS_RECV), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + buf_addr_mut, + buf_len, + flags.into(), + ]) + )) + } +} + +#[inline] +pub(crate) fn recvfrom( + fd: BorrowedFd<'_>, + buf: &mut [u8], + flags: RecvFlags, +) -> io::Result<(usize, Option<SocketAddrAny>)> { + let (buf_addr_mut, buf_len) = slice_mut(buf); + + let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t; + let mut storage = MaybeUninit::<sockaddr>::uninit(); + + unsafe { + // `recvfrom` does not write to the storage if the socket is + // connection-oriented sockets, so we initialize the family field to + // `AF_UNSPEC` so that we can detect this case. + initialize_family_to_unspec(storage.as_mut_ptr()); + + #[cfg(not(target_arch = "x86"))] + let nread = ret_usize(syscall!( + __NR_recvfrom, + fd, + buf_addr_mut, + buf_len, + flags, + &mut storage, + by_mut(&mut addrlen) + ))?; + #[cfg(target_arch = "x86")] + let nread = ret_usize(syscall!( + __NR_socketcall, + x86_sys(SYS_RECVFROM), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + buf_addr_mut, + buf_len, + flags.into(), + (&mut storage).into(), + by_mut(&mut addrlen), + ]) + ))?; + + Ok(( + nread, + maybe_read_sockaddr_os(&storage.assume_init(), addrlen.try_into().unwrap()), + )) + } +} + +#[inline] +pub(crate) fn getpeername(fd: BorrowedFd<'_>) -> io::Result<Option<SocketAddrAny>> { + #[cfg(not(target_arch = "x86"))] + unsafe { + let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t; + let mut storage = MaybeUninit::<sockaddr>::uninit(); + ret(syscall!( + __NR_getpeername, + fd, + &mut storage, + by_mut(&mut addrlen) + ))?; + Ok(maybe_read_sockaddr_os( + &storage.assume_init(), + addrlen.try_into().unwrap(), + )) + } + #[cfg(target_arch = "x86")] + unsafe { + let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t; + let mut storage = MaybeUninit::<sockaddr>::uninit(); + ret(syscall!( + __NR_socketcall, + x86_sys(SYS_GETPEERNAME), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + (&mut storage).into(), + by_mut(&mut addrlen), + ]) + ))?; + Ok(maybe_read_sockaddr_os( + &storage.assume_init(), + addrlen.try_into().unwrap(), + )) + } +} + +#[inline] +pub(crate) fn getsockname(fd: BorrowedFd<'_>) -> io::Result<SocketAddrAny> { + #[cfg(not(target_arch = "x86"))] + unsafe { + let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t; + let mut storage = MaybeUninit::<sockaddr>::uninit(); + ret(syscall!( + __NR_getsockname, + fd, + &mut storage, + by_mut(&mut addrlen) + ))?; + Ok(read_sockaddr_os( + &storage.assume_init(), + addrlen.try_into().unwrap(), + )) + } + #[cfg(target_arch = "x86")] + unsafe { + let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t; + let mut storage = MaybeUninit::<sockaddr>::uninit(); + ret(syscall!( + __NR_socketcall, + x86_sys(SYS_GETSOCKNAME), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + (&mut storage).into(), + by_mut(&mut addrlen), + ]) + ))?; + Ok(read_sockaddr_os( + &storage.assume_init(), + addrlen.try_into().unwrap(), + )) + } +} + +#[inline] +pub(crate) fn bind_v4(fd: BorrowedFd<'_>, addr: &SocketAddrV4) -> io::Result<()> { + #[cfg(not(target_arch = "x86"))] + unsafe { + ret(syscall_readonly!( + __NR_bind, + fd, + by_ref(&encode_sockaddr_v4(addr)), + size_of::<sockaddr_in, _>() + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_BIND), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + by_ref(&encode_sockaddr_v4(addr)), + size_of::<sockaddr_in, _>(), + ]) + )) + } +} + +#[inline] +pub(crate) fn bind_v6(fd: BorrowedFd<'_>, addr: &SocketAddrV6) -> io::Result<()> { + #[cfg(not(target_arch = "x86"))] + unsafe { + ret(syscall_readonly!( + __NR_bind, + fd, + by_ref(&encode_sockaddr_v6(addr)), + size_of::<sockaddr_in6, _>() + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_BIND), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + by_ref(&encode_sockaddr_v6(addr)), + size_of::<sockaddr_in6, _>(), + ]) + )) + } +} + +#[inline] +pub(crate) fn bind_unix(fd: BorrowedFd<'_>, addr: &SocketAddrUnix) -> io::Result<()> { + #[cfg(not(target_arch = "x86"))] + unsafe { + ret(syscall_readonly!( + __NR_bind, + fd, + by_ref(&addr.unix), + socklen_t(addr.addr_len()) + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_BIND), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + by_ref(&addr.unix), + socklen_t(addr.addr_len()), + ]) + )) + } +} + +#[inline] +pub(crate) fn connect_v4(fd: BorrowedFd<'_>, addr: &SocketAddrV4) -> io::Result<()> { + #[cfg(not(target_arch = "x86"))] + unsafe { + ret(syscall_readonly!( + __NR_connect, + fd, + by_ref(&encode_sockaddr_v4(addr)), + size_of::<sockaddr_in, _>() + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_CONNECT), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + by_ref(&encode_sockaddr_v4(addr)), + size_of::<sockaddr_in, _>(), + ]) + )) + } +} + +#[inline] +pub(crate) fn connect_v6(fd: BorrowedFd<'_>, addr: &SocketAddrV6) -> io::Result<()> { + #[cfg(not(target_arch = "x86"))] + unsafe { + ret(syscall_readonly!( + __NR_connect, + fd, + by_ref(&encode_sockaddr_v6(addr)), + size_of::<sockaddr_in6, _>() + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_CONNECT), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + by_ref(&encode_sockaddr_v6(addr)), + size_of::<sockaddr_in6, _>(), + ]) + )) + } +} + +#[inline] +pub(crate) fn connect_unix(fd: BorrowedFd<'_>, addr: &SocketAddrUnix) -> io::Result<()> { + #[cfg(not(target_arch = "x86"))] + unsafe { + ret(syscall_readonly!( + __NR_connect, + fd, + by_ref(&addr.unix), + socklen_t(addr.addr_len()) + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_CONNECT), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + by_ref(&addr.unix), + socklen_t(addr.addr_len()), + ]) + )) + } +} + +#[inline] +pub(crate) fn listen(fd: BorrowedFd<'_>, backlog: c::c_int) -> io::Result<()> { + #[cfg(not(target_arch = "x86"))] + unsafe { + ret(syscall_readonly!(__NR_listen, fd, c_int(backlog))) + } + #[cfg(target_arch = "x86")] + unsafe { + ret(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_LISTEN), + slice_just_addr::<ArgReg<SocketArg>, _>(&[fd.into(), c_int(backlog)]) + )) + } +} + +pub(crate) mod sockopt { + use super::{c, BorrowedFd}; + use crate::io; + use crate::net::sockopt::Timeout; + use crate::net::{Ipv4Addr, Ipv6Addr, SocketType}; + use c::{SO_RCVTIMEO_NEW, SO_RCVTIMEO_OLD, SO_SNDTIMEO_NEW, SO_SNDTIMEO_OLD}; + use core::convert::TryInto; + use core::time::Duration; + use linux_raw_sys::general::{__kernel_timespec, timeval}; + + // TODO: With Rust 1.53 we can use `Duration::ZERO` instead. + const DURATION_ZERO: Duration = Duration::from_secs(0); + + #[inline] + fn getsockopt<T: Copy>(fd: BorrowedFd<'_>, level: u32, optname: u32) -> io::Result<T> { + use super::*; + + let mut optlen = core::mem::size_of::<T>(); + debug_assert!( + optlen as usize >= core::mem::size_of::<c::c_int>(), + "Socket APIs don't ever use `bool` directly" + ); + + #[cfg(not(target_arch = "x86"))] + unsafe { + let mut value = MaybeUninit::<T>::uninit(); + ret(syscall!( + __NR_getsockopt, + fd, + c_uint(level), + c_uint(optname), + &mut value, + by_mut(&mut optlen) + ))?; + + assert_eq!( + optlen as usize, + core::mem::size_of::<T>(), + "unexpected getsockopt size" + ); + Ok(value.assume_init()) + } + #[cfg(target_arch = "x86")] + unsafe { + let mut value = MaybeUninit::<T>::uninit(); + ret(syscall!( + __NR_socketcall, + x86_sys(SYS_GETSOCKOPT), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + c_uint(level), + c_uint(optname), + (&mut value).into(), + by_mut(&mut optlen), + ]) + ))?; + assert_eq!( + optlen as usize, + core::mem::size_of::<T>(), + "unexpected getsockopt size" + ); + Ok(value.assume_init()) + } + } + + #[inline] + fn setsockopt<T: Copy>( + fd: BorrowedFd<'_>, + level: u32, + optname: u32, + value: T, + ) -> io::Result<()> { + use super::*; + + let optlen = core::mem::size_of::<T>().try_into().unwrap(); + debug_assert!( + optlen as usize >= core::mem::size_of::<c::c_int>(), + "Socket APIs don't ever use `bool` directly" + ); + + #[cfg(not(target_arch = "x86"))] + unsafe { + ret(syscall_readonly!( + __NR_setsockopt, + fd, + c_uint(level), + c_uint(optname), + by_ref(&value), + socklen_t(optlen) + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_SETSOCKOPT), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + c_uint(level), + c_uint(optname), + by_ref(&value), + socklen_t(optlen), + ]) + )) + } + } + + #[inline] + pub(crate) fn get_socket_type(fd: BorrowedFd<'_>) -> io::Result<SocketType> { + getsockopt(fd, c::SOL_SOCKET as _, c::SO_TYPE) + } + + #[inline] + pub(crate) fn set_socket_reuseaddr(fd: BorrowedFd<'_>, reuseaddr: bool) -> io::Result<()> { + setsockopt( + fd, + c::SOL_SOCKET as _, + c::SO_REUSEADDR, + from_bool(reuseaddr), + ) + } + + #[inline] + pub(crate) fn set_socket_broadcast(fd: BorrowedFd<'_>, broadcast: bool) -> io::Result<()> { + setsockopt( + fd, + c::SOL_SOCKET as _, + c::SO_BROADCAST, + from_bool(broadcast), + ) + } + + #[inline] + pub(crate) fn get_socket_broadcast(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::SOL_SOCKET as _, c::SO_BROADCAST).map(to_bool) + } + + #[inline] + pub(crate) fn set_socket_linger( + fd: BorrowedFd<'_>, + linger: Option<Duration>, + ) -> io::Result<()> { + // Convert `linger` to seconds, rounding up. + let l_linger = if let Some(linger) = linger { + let mut l_linger = linger.as_secs(); + if linger.subsec_nanos() != 0 { + l_linger = l_linger.checked_add(1).ok_or(io::Errno::INVAL)?; + } + l_linger.try_into().map_err(|_e| io::Errno::INVAL)? + } else { + 0 + }; + let linger = c::linger { + l_onoff: c::c_int::from(linger.is_some()), + l_linger, + }; + setsockopt(fd, c::SOL_SOCKET as _, c::SO_LINGER, linger) + } + + #[inline] + pub(crate) fn get_socket_linger(fd: BorrowedFd<'_>) -> io::Result<Option<Duration>> { + let linger: c::linger = getsockopt(fd, c::SOL_SOCKET as _, c::SO_LINGER)?; + // TODO: With Rust 1.50, this could use `.then`. + Ok(if linger.l_onoff != 0 { + Some(Duration::from_secs(linger.l_linger as u64)) + } else { + None + }) + } + + #[inline] + pub(crate) fn set_socket_passcred(fd: BorrowedFd<'_>, passcred: bool) -> io::Result<()> { + setsockopt(fd, c::SOL_SOCKET as _, c::SO_PASSCRED, from_bool(passcred)) + } + + #[inline] + pub(crate) fn get_socket_passcred(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::SOL_SOCKET as _, c::SO_PASSCRED).map(to_bool) + } + + #[inline] + pub(crate) fn set_socket_timeout( + fd: BorrowedFd<'_>, + id: Timeout, + timeout: Option<Duration>, + ) -> io::Result<()> { + let time = duration_to_linux(timeout)?; + let optname = match id { + Timeout::Recv => SO_RCVTIMEO_NEW, + Timeout::Send => SO_SNDTIMEO_NEW, + }; + match setsockopt(fd, c::SOL_SOCKET, optname, time) { + Err(io::Errno::NOPROTOOPT) if SO_RCVTIMEO_NEW != SO_RCVTIMEO_OLD => { + set_socket_timeout_old(fd, id, timeout) + } + otherwise => otherwise, + } + } + + /// Same as `set_socket_timeout` but uses `timeval` instead of + /// `__kernel_timespec` and `_OLD` constants instead of `_NEW`. + fn set_socket_timeout_old( + fd: BorrowedFd<'_>, + id: Timeout, + timeout: Option<Duration>, + ) -> io::Result<()> { + let time = duration_to_linux_old(timeout)?; + let optname = match id { + Timeout::Recv => SO_RCVTIMEO_OLD, + Timeout::Send => SO_SNDTIMEO_OLD, + }; + setsockopt(fd, c::SOL_SOCKET, optname, time) + } + + #[inline] + pub(crate) fn get_socket_timeout( + fd: BorrowedFd<'_>, + id: Timeout, + ) -> io::Result<Option<Duration>> { + let optname = match id { + Timeout::Recv => SO_RCVTIMEO_NEW, + Timeout::Send => SO_SNDTIMEO_NEW, + }; + let time: __kernel_timespec = match getsockopt(fd, c::SOL_SOCKET, optname) { + Err(io::Errno::NOPROTOOPT) if SO_RCVTIMEO_NEW != SO_RCVTIMEO_OLD => { + return get_socket_timeout_old(fd, id) + } + otherwise => otherwise?, + }; + Ok(duration_from_linux(time)) + } + + /// Same as `get_socket_timeout` but uses `timeval` instead of + /// `__kernel_timespec` and `_OLD` constants instead of `_NEW`. + fn get_socket_timeout_old(fd: BorrowedFd<'_>, id: Timeout) -> io::Result<Option<Duration>> { + let optname = match id { + Timeout::Recv => SO_RCVTIMEO_OLD, + Timeout::Send => SO_SNDTIMEO_OLD, + }; + let time: timeval = getsockopt(fd, c::SOL_SOCKET, optname)?; + Ok(duration_from_linux_old(time)) + } + + /// Convert a C `timespec` to a Rust `Option<Duration>`. + #[inline] + fn duration_from_linux(time: __kernel_timespec) -> Option<Duration> { + if time.tv_sec == 0 && time.tv_nsec == 0 { + None + } else { + Some( + Duration::from_secs(time.tv_sec as u64) + Duration::from_nanos(time.tv_nsec as u64), + ) + } + } + + /// Like `duration_from_linux` but uses Linux's old 32-bit `timeval`. + fn duration_from_linux_old(time: timeval) -> Option<Duration> { + if time.tv_sec == 0 && time.tv_usec == 0 { + None + } else { + Some( + Duration::from_secs(time.tv_sec as u64) + + Duration::from_micros(time.tv_usec as u64), + ) + } + } + + /// Convert a Rust `Option<Duration>` to a C `timespec`. + #[inline] + fn duration_to_linux(timeout: Option<Duration>) -> io::Result<__kernel_timespec> { + Ok(match timeout { + Some(timeout) => { + if timeout == DURATION_ZERO { + return Err(io::Errno::INVAL); + } + let mut timeout = __kernel_timespec { + tv_sec: timeout.as_secs().try_into().unwrap_or(i64::MAX), + tv_nsec: timeout.subsec_nanos().into(), + }; + if timeout.tv_sec == 0 && timeout.tv_nsec == 0 { + timeout.tv_nsec = 1; + } + timeout + } + None => __kernel_timespec { + tv_sec: 0, + tv_nsec: 0, + }, + }) + } + + /// Like `duration_to_linux` but uses Linux's old 32-bit `timeval`. + fn duration_to_linux_old(timeout: Option<Duration>) -> io::Result<timeval> { + Ok(match timeout { + Some(timeout) => { + if timeout == DURATION_ZERO { + return Err(io::Errno::INVAL); + } + + // `subsec_micros` rounds down, so we use `subsec_nanos` and + // manually round up. + let mut timeout = timeval { + tv_sec: timeout.as_secs().try_into().unwrap_or(c::c_long::MAX), + tv_usec: ((timeout.subsec_nanos() + 999) / 1000) as _, + }; + if timeout.tv_sec == 0 && timeout.tv_usec == 0 { + timeout.tv_usec = 1; + } + timeout + } + None => timeval { + tv_sec: 0, + tv_usec: 0, + }, + }) + } + + #[inline] + pub(crate) fn set_ip_ttl(fd: BorrowedFd<'_>, ttl: u32) -> io::Result<()> { + setsockopt(fd, c::IPPROTO_IP as _, c::IP_TTL, ttl) + } + + #[inline] + pub(crate) fn get_ip_ttl(fd: BorrowedFd<'_>) -> io::Result<u32> { + getsockopt(fd, c::IPPROTO_IP as _, c::IP_TTL) + } + + #[inline] + pub(crate) fn set_ipv6_v6only(fd: BorrowedFd<'_>, only_v6: bool) -> io::Result<()> { + setsockopt(fd, c::IPPROTO_IPV6 as _, c::IPV6_V6ONLY, from_bool(only_v6)) + } + + #[inline] + pub(crate) fn get_ipv6_v6only(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::IPPROTO_IPV6 as _, c::IPV6_V6ONLY).map(to_bool) + } + + #[inline] + pub(crate) fn set_ip_multicast_loop( + fd: BorrowedFd<'_>, + multicast_loop: bool, + ) -> io::Result<()> { + setsockopt( + fd, + c::IPPROTO_IP as _, + c::IP_MULTICAST_LOOP, + from_bool(multicast_loop), + ) + } + + #[inline] + pub(crate) fn get_ip_multicast_loop(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::IPPROTO_IP as _, c::IP_MULTICAST_LOOP).map(to_bool) + } + + #[inline] + pub(crate) fn set_ip_multicast_ttl(fd: BorrowedFd<'_>, multicast_ttl: u32) -> io::Result<()> { + setsockopt(fd, c::IPPROTO_IP as _, c::IP_MULTICAST_TTL, multicast_ttl) + } + + #[inline] + pub(crate) fn get_ip_multicast_ttl(fd: BorrowedFd<'_>) -> io::Result<u32> { + getsockopt(fd, c::IPPROTO_IP as _, c::IP_MULTICAST_TTL) + } + + #[inline] + pub(crate) fn set_ipv6_multicast_loop( + fd: BorrowedFd<'_>, + multicast_loop: bool, + ) -> io::Result<()> { + setsockopt( + fd, + c::IPPROTO_IPV6 as _, + c::IPV6_MULTICAST_LOOP, + from_bool(multicast_loop), + ) + } + + #[inline] + pub(crate) fn get_ipv6_multicast_loop(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::IPPROTO_IPV6 as _, c::IPV6_MULTICAST_LOOP).map(to_bool) + } + + #[inline] + pub(crate) fn set_ipv6_multicast_hops( + fd: BorrowedFd<'_>, + multicast_hops: u32, + ) -> io::Result<()> { + setsockopt( + fd, + c::IPPROTO_IP as _, + c::IPV6_MULTICAST_LOOP, + multicast_hops, + ) + } + + #[inline] + pub(crate) fn get_ipv6_multicast_hops(fd: BorrowedFd<'_>) -> io::Result<u32> { + getsockopt(fd, c::IPPROTO_IP as _, c::IPV6_MULTICAST_LOOP) + } + + #[inline] + pub(crate) fn set_ip_add_membership( + fd: BorrowedFd<'_>, + multiaddr: &Ipv4Addr, + interface: &Ipv4Addr, + ) -> io::Result<()> { + let mreq = to_imr(multiaddr, interface); + setsockopt(fd, c::IPPROTO_IP as _, c::IP_ADD_MEMBERSHIP, mreq) + } + + #[inline] + pub(crate) fn set_ipv6_add_membership( + fd: BorrowedFd<'_>, + multiaddr: &Ipv6Addr, + interface: u32, + ) -> io::Result<()> { + let mreq = to_ipv6mr(multiaddr, interface); + setsockopt(fd, c::IPPROTO_IPV6 as _, c::IPV6_ADD_MEMBERSHIP, mreq) + } + + #[inline] + pub(crate) fn set_ip_drop_membership( + fd: BorrowedFd<'_>, + multiaddr: &Ipv4Addr, + interface: &Ipv4Addr, + ) -> io::Result<()> { + let mreq = to_imr(multiaddr, interface); + setsockopt(fd, c::IPPROTO_IP as _, c::IP_DROP_MEMBERSHIP, mreq) + } + + #[inline] + pub(crate) fn set_ipv6_drop_membership( + fd: BorrowedFd<'_>, + multiaddr: &Ipv6Addr, + interface: u32, + ) -> io::Result<()> { + let mreq = to_ipv6mr(multiaddr, interface); + setsockopt(fd, c::IPPROTO_IPV6 as _, c::IPV6_DROP_MEMBERSHIP, mreq) + } + + #[inline] + pub(crate) fn set_tcp_nodelay(fd: BorrowedFd<'_>, nodelay: bool) -> io::Result<()> { + setsockopt(fd, c::IPPROTO_TCP as _, c::TCP_NODELAY, from_bool(nodelay)) + } + + #[inline] + pub(crate) fn get_tcp_nodelay(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::IPPROTO_TCP as _, c::TCP_NODELAY).map(to_bool) + } + + #[inline] + fn to_imr(multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> c::ip_mreq { + c::ip_mreq { + imr_multiaddr: to_imr_addr(multiaddr), + imr_interface: to_imr_addr(interface), + } + } + + #[inline] + fn to_imr_addr(addr: &Ipv4Addr) -> c::in_addr { + c::in_addr { + s_addr: u32::from_ne_bytes(addr.octets()), + } + } + + #[inline] + fn to_ipv6mr(multiaddr: &Ipv6Addr, interface: u32) -> c::ipv6_mreq { + c::ipv6_mreq { + ipv6mr_multiaddr: to_ipv6mr_multiaddr(multiaddr), + ipv6mr_ifindex: to_ipv6mr_interface(interface), + } + } + + #[inline] + fn to_ipv6mr_multiaddr(multiaddr: &Ipv6Addr) -> c::in6_addr { + c::in6_addr { + in6_u: linux_raw_sys::general::in6_addr__bindgen_ty_1 { + u6_addr8: multiaddr.octets(), + }, + } + } + + #[inline] + fn to_ipv6mr_interface(interface: u32) -> c::c_int { + interface as c::c_int + } + + #[inline] + fn from_bool(value: bool) -> c::c_uint { + c::c_uint::from(value) + } + + #[inline] + fn to_bool(value: c::c_uint) -> bool { + value != 0 + } +} diff --git a/vendor/rustix/src/imp/linux_raw/net/types.rs b/vendor/rustix/src/backend/linux_raw/net/types.rs index b8f786b3f..b8f786b3f 100644 --- a/vendor/rustix/src/imp/linux_raw/net/types.rs +++ b/vendor/rustix/src/backend/linux_raw/net/types.rs diff --git a/vendor/rustix/src/imp/linux_raw/net/write_sockaddr.rs b/vendor/rustix/src/backend/linux_raw/net/write_sockaddr.rs index 17abd96a0..17abd96a0 100644 --- a/vendor/rustix/src/imp/linux_raw/net/write_sockaddr.rs +++ b/vendor/rustix/src/backend/linux_raw/net/write_sockaddr.rs diff --git a/vendor/rustix/src/backend/linux_raw/param/auxv.rs b/vendor/rustix/src/backend/linux_raw/param/auxv.rs new file mode 100644 index 000000000..20a3d5da6 --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/param/auxv.rs @@ -0,0 +1,370 @@ +//! Linux auxv support. +//! +//! # Safety +//! +//! This uses raw pointers to locate and read the kernel-provided auxv array. +#![allow(unsafe_code)] + +use super::super::c; +use super::super::elf::*; +use crate::fd::OwnedFd; +#[cfg(feature = "param")] +use crate::ffi::CStr; +use crate::fs::{Mode, OFlags}; +use crate::utils::{as_ptr, check_raw_pointer}; +use alloc::vec::Vec; +use core::ffi::c_void; +use core::mem::size_of; +use core::ptr::{null_mut, read_unaligned, NonNull}; +#[cfg(feature = "runtime")] +use core::slice; +use core::sync::atomic::Ordering::Relaxed; +use core::sync::atomic::{AtomicPtr, AtomicUsize}; +use linux_raw_sys::general::{ + AT_BASE, AT_CLKTCK, AT_EXECFN, AT_HWCAP, AT_HWCAP2, AT_NULL, AT_PAGESZ, AT_PHDR, AT_PHENT, + AT_PHNUM, AT_SYSINFO_EHDR, +}; + +#[cfg(feature = "param")] +#[inline] +pub(crate) fn page_size() -> usize { + let mut page_size = PAGE_SIZE.load(Relaxed); + + if page_size == 0 { + init_from_proc_self_auxv(); + page_size = PAGE_SIZE.load(Relaxed); + } + + page_size +} + +#[cfg(feature = "param")] +#[inline] +pub(crate) fn clock_ticks_per_second() -> u64 { + let mut ticks = CLOCK_TICKS_PER_SECOND.load(Relaxed); + + if ticks == 0 { + init_from_proc_self_auxv(); + ticks = CLOCK_TICKS_PER_SECOND.load(Relaxed); + } + + ticks as u64 +} + +#[cfg(feature = "param")] +#[inline] +pub(crate) fn linux_hwcap() -> (usize, usize) { + let mut hwcap = HWCAP.load(Relaxed); + let mut hwcap2 = HWCAP2.load(Relaxed); + + if hwcap == 0 || hwcap2 == 0 { + init_from_proc_self_auxv(); + hwcap = HWCAP.load(Relaxed); + hwcap2 = HWCAP2.load(Relaxed); + } + + (hwcap, hwcap2) +} + +#[cfg(feature = "param")] +#[inline] +pub(crate) fn linux_execfn() -> &'static CStr { + let mut execfn = EXECFN.load(Relaxed); + + if execfn.is_null() { + init_from_proc_self_auxv(); + execfn = EXECFN.load(Relaxed); + } + + // Safety: We assume the `AT_EXECFN` value provided by the kernel is a + // valid pointer to a valid NUL-terminated array of bytes. + unsafe { CStr::from_ptr(execfn.cast()) } +} + +#[cfg(feature = "runtime")] +#[inline] +pub(crate) fn exe_phdrs() -> (*const c::c_void, usize) { + let mut phdr = PHDR.load(Relaxed); + let mut phnum = PHNUM.load(Relaxed); + + if phdr.is_null() || phnum == 0 { + init_from_proc_self_auxv(); + phdr = PHDR.load(Relaxed); + phnum = PHNUM.load(Relaxed); + } + + (phdr.cast(), phnum) +} + +#[cfg(feature = "runtime")] +#[inline] +pub(in super::super) fn exe_phdrs_slice() -> &'static [Elf_Phdr] { + let (phdr, phnum) = exe_phdrs(); + + // Safety: We assume the `AT_PHDR` and `AT_PHNUM` values provided by the + // kernel form a valid slice. + unsafe { slice::from_raw_parts(phdr.cast(), phnum) } +} + +/// `AT_SYSINFO_EHDR` isn't present on all platforms in all configurations, +/// so if we don't see it, this function returns a null pointer. +#[inline] +pub(in super::super) fn sysinfo_ehdr() -> *const Elf_Ehdr { + let mut ehdr = SYSINFO_EHDR.load(Relaxed); + + if ehdr.is_null() { + init_from_proc_self_auxv(); + ehdr = SYSINFO_EHDR.load(Relaxed); + } + + ehdr +} + +static PAGE_SIZE: AtomicUsize = AtomicUsize::new(0); +static CLOCK_TICKS_PER_SECOND: AtomicUsize = AtomicUsize::new(0); +static HWCAP: AtomicUsize = AtomicUsize::new(0); +static HWCAP2: AtomicUsize = AtomicUsize::new(0); +static SYSINFO_EHDR: AtomicPtr<Elf_Ehdr> = AtomicPtr::new(null_mut()); +static PHDR: AtomicPtr<Elf_Phdr> = AtomicPtr::new(null_mut()); +static PHNUM: AtomicUsize = AtomicUsize::new(0); +static EXECFN: AtomicPtr<c::c_char> = AtomicPtr::new(null_mut()); + +/// On non-Mustang platforms, we read the aux vector from /proc/self/auxv. +fn init_from_proc_self_auxv() { + // Open "/proc/self/auxv", either because we trust "/proc", or because + // we're running inside QEMU and `proc_self_auxv`'s extra checking foils + // QEMU's emulation so we need to do a plain open to get the right + // auxv records. + let file = crate::fs::openat( + crate::fs::cwd(), + "/proc/self/auxv", + OFlags::empty(), + Mode::empty(), + ) + .unwrap(); + + let _ = init_from_auxv_file(file); +} + +/// Process auxv entries from the open file `auxv`. +fn init_from_auxv_file(auxv: OwnedFd) -> Option<()> { + let mut buffer = Vec::<u8>::with_capacity(512); + loop { + let cur = buffer.len(); + + // Request one extra byte; `Vec` will often allocate more. + buffer.reserve(1); + + // Use all the space it allocated. + buffer.resize(buffer.capacity(), 0); + + // Read up to that many bytes. + let n = match crate::io::read(&auxv, &mut buffer[cur..]) { + Err(crate::io::Errno::INTR) => 0, + Err(_err) => panic!(), + Ok(0) => break, + Ok(n) => n, + }; + + // Account for the number of bytes actually read. + buffer.resize(cur + n, 0_u8); + } + + // Safety: We loaded from an auxv file into the buffer. + unsafe { init_from_auxp(buffer.as_ptr().cast()) } +} + +/// Process auxv entries from the auxv array pointed to by `auxp`. +/// +/// # Safety +/// +/// This must be passed a pointer to an auxv array. +/// +/// The buffer contains `Elf_aux_t` elements, though it need not be aligned; +/// function uses `read_unaligned` to read from it. +unsafe fn init_from_auxp(mut auxp: *const Elf_auxv_t) -> Option<()> { + let mut pagesz = 0; + let mut clktck = 0; + let mut hwcap = 0; + let mut hwcap2 = 0; + let mut phdr = null_mut(); + let mut phnum = 0; + let mut execfn = null_mut(); + let mut sysinfo_ehdr = null_mut(); + let mut phent = 0; + + loop { + let Elf_auxv_t { a_type, a_val } = read_unaligned(auxp); + + match a_type as _ { + AT_PAGESZ => pagesz = a_val as usize, + AT_CLKTCK => clktck = a_val as usize, + AT_HWCAP => hwcap = a_val as usize, + AT_HWCAP2 => hwcap2 = a_val as usize, + AT_PHDR => phdr = check_raw_pointer::<Elf_Phdr>(a_val as *mut _)?.as_ptr(), + AT_PHNUM => phnum = a_val as usize, + AT_PHENT => phent = a_val as usize, + AT_EXECFN => execfn = check_raw_pointer::<c::c_char>(a_val as *mut _)?.as_ptr(), + AT_BASE => check_interpreter_base(a_val.cast())?, + AT_SYSINFO_EHDR => sysinfo_ehdr = check_vdso_base(a_val as *mut _)?.as_ptr(), + AT_NULL => break, + _ => (), + } + auxp = auxp.add(1); + } + + assert_eq!(phent, size_of::<Elf_Phdr>()); + + // The base and sysinfo_ehdr (if present) matches our platform. Accept + // the aux values. + PAGE_SIZE.store(pagesz, Relaxed); + CLOCK_TICKS_PER_SECOND.store(clktck, Relaxed); + HWCAP.store(hwcap, Relaxed); + HWCAP2.store(hwcap2, Relaxed); + PHDR.store(phdr, Relaxed); + PHNUM.store(phnum, Relaxed); + EXECFN.store(execfn, Relaxed); + SYSINFO_EHDR.store(sysinfo_ehdr, Relaxed); + + Some(()) +} + +/// Check that `base` is a valid pointer to the program interpreter. +/// +/// `base` is some value we got from a `AT_BASE` aux record somewhere, +/// which hopefully holds the value of the program interpreter in memory. Do a +/// series of checks to be as sure as we can that it's safe to use. +unsafe fn check_interpreter_base(base: *const Elf_Ehdr) -> Option<()> { + check_elf_base(base)?; + Some(()) +} + +/// Check that `base` is a valid pointer to the kernel-provided vDSO. +/// +/// `base` is some value we got from a `AT_SYSINFO_EHDR` aux record somewhere, +/// which hopefully holds the value of the kernel-provided vDSO in memory. Do a +/// series of checks to be as sure as we can that it's safe to use. +unsafe fn check_vdso_base(base: *const Elf_Ehdr) -> Option<NonNull<Elf_Ehdr>> { + // In theory, we could check that we're not attempting to parse our own ELF + // image, as an additional check. However, older Linux toolchains don't + // support this, and Rust's `#[linkage = "extern_weak"]` isn't stable yet, + // so just disable this for now. + /* + { + extern "C" { + static __ehdr_start: c::c_void; + } + + let ehdr_start: *const c::c_void = &__ehdr_start; + if base == ehdr_start { + return None; + } + } + */ + + let hdr = check_elf_base(base)?; + + // Check that the ELF is not writable, since that would indicate that this + // isn't the ELF we think it is. Here we're just using `clock_getres` just + // as an arbitrary system call which writes to a buffer and fails with + // `EFAULT` if the buffer is not writable. + { + use super::super::conv::{c_uint, ret}; + if ret(syscall!( + __NR_clock_getres, + c_uint(linux_raw_sys::general::CLOCK_MONOTONIC), + base + )) != Err(crate::io::Errno::FAULT) + { + // We can't gracefully fail here because we would seem to have just + // mutated some unknown memory. + #[cfg(feature = "std")] + { + std::process::abort(); + } + #[cfg(all(not(feature = "std"), feature = "rustc-dep-of-std"))] + { + core::intrinsics::abort(); + } + } + } + + Some(hdr) +} + +/// Check that `base` is a valid pointer to an ELF image. +unsafe fn check_elf_base(base: *const Elf_Ehdr) -> Option<NonNull<Elf_Ehdr>> { + // If we're reading a 64-bit auxv on a 32-bit platform, we'll see + // a zero `a_val` because `AT_*` values are never greater than + // `u32::MAX`. Zero is used by libc's `getauxval` to indicate + // errors, so it should never be a valid value. + if base.is_null() { + return None; + } + + let hdr = match check_raw_pointer::<Elf_Ehdr>(base as *mut _) { + Some(hdr) => hdr, + None => return None, + }; + + let hdr = hdr.as_ref(); + if hdr.e_ident[..SELFMAG] != ELFMAG { + return None; // Wrong ELF magic + } + if !matches!(hdr.e_ident[EI_OSABI], ELFOSABI_SYSV | ELFOSABI_LINUX) { + return None; // Unrecognized ELF OS ABI + } + if hdr.e_ident[EI_ABIVERSION] != ELFABIVERSION { + return None; // Unrecognized ELF ABI version + } + if hdr.e_type != ET_DYN { + return None; // Wrong ELF type + } + + // If ELF is extended, we'll need to adjust. + if hdr.e_ident[EI_VERSION] != EV_CURRENT + || hdr.e_ehsize as usize != size_of::<Elf_Ehdr>() + || hdr.e_phentsize as usize != size_of::<Elf_Phdr>() + { + return None; + } + // We don't currently support extra-large numbers of segments. + if hdr.e_phnum == PN_XNUM { + return None; + } + + // If `e_phoff` is zero, it's more likely that we're looking at memory that + // has been zeroed than that the kernel has somehow aliased the `Ehdr` and + // the `Phdr`. + if hdr.e_phoff < size_of::<Elf_Ehdr>() { + return None; + } + + // Verify that the `EI_CLASS`/`EI_DATA`/`e_machine` fields match the + // architecture we're running as. This helps catch cases where we're + // running under QEMU. + if hdr.e_ident[EI_CLASS] != ELFCLASS { + return None; // Wrong ELF class + } + if hdr.e_ident[EI_DATA] != ELFDATA { + return None; // Wrong ELF data + } + if hdr.e_machine != EM_CURRENT { + return None; // Wrong machine type + } + + Some(NonNull::new_unchecked(as_ptr(hdr) as *mut _)) +} + +// ELF ABI + +#[repr(C)] +#[derive(Copy, Clone)] +struct Elf_auxv_t { + a_type: usize, + + // Some of the values in the auxv array are pointers, so we make `a_val` a + // pointer, in order to preserve their provenance. For the values which are + // integers, we cast this to `usize`. + a_val: *const c_void, +} diff --git a/vendor/rustix/src/backend/linux_raw/param/libc_auxv.rs b/vendor/rustix/src/backend/linux_raw/param/libc_auxv.rs new file mode 100644 index 000000000..1597fd727 --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/param/libc_auxv.rs @@ -0,0 +1,74 @@ +//! Linux auxv support, using libc. +//! +//! # Safety +//! +//! This uses raw pointers to locate and read the kernel-provided auxv array. +#![allow(unsafe_code)] + +#[cfg(any(feature = "param", feature = "runtime"))] +use super::super::c; +use super::super::elf::*; +#[cfg(feature = "param")] +use crate::ffi::CStr; +#[cfg(feature = "runtime")] +use core::slice; + +#[cfg(feature = "param")] +#[inline] +pub(crate) fn page_size() -> usize { + unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize } +} + +#[cfg(feature = "param")] +#[inline] +pub(crate) fn clock_ticks_per_second() -> u64 { + unsafe { libc::getauxval(libc::AT_CLKTCK) as u64 } +} + +#[cfg(feature = "param")] +#[inline] +pub(crate) fn linux_hwcap() -> (usize, usize) { + unsafe { + ( + libc::getauxval(libc::AT_HWCAP) as usize, + libc::getauxval(libc::AT_HWCAP2) as usize, + ) + } +} + +#[cfg(feature = "param")] +#[inline] +pub(crate) fn linux_execfn() -> &'static CStr { + unsafe { + let execfn = libc::getauxval(libc::AT_EXECFN) as *const c::c_char; + CStr::from_ptr(execfn.cast()) + } +} + +#[cfg(feature = "runtime")] +#[inline] +pub(crate) fn exe_phdrs() -> (*const c::c_void, usize) { + unsafe { + ( + libc::getauxval(libc::AT_PHDR) as *const c::c_void, + libc::getauxval(libc::AT_PHNUM) as usize, + ) + } +} + +#[cfg(feature = "runtime")] +#[inline] +pub(in super::super) fn exe_phdrs_slice() -> &'static [Elf_Phdr] { + let (phdr, phnum) = exe_phdrs(); + + // Safety: We assume the `AT_PHDR` and `AT_PHNUM` values provided by the + // kernel form a valid slice. + unsafe { slice::from_raw_parts(phdr.cast(), phnum) } +} + +/// `AT_SYSINFO_EHDR` isn't present on all platforms in all configurations, +/// so if we don't see it, this function returns a null pointer. +#[inline] +pub(in super::super) fn sysinfo_ehdr() -> *const Elf_Ehdr { + unsafe { libc::getauxval(linux_raw_sys::general::AT_SYSINFO_EHDR.into()) as *const Elf_Ehdr } +} diff --git a/vendor/rustix/src/backend/linux_raw/param/mod.rs b/vendor/rustix/src/backend/linux_raw/param/mod.rs new file mode 100644 index 000000000..956282074 --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/param/mod.rs @@ -0,0 +1,12 @@ +// On Mustang, origin is in control of program startup and can access the +// incoming aux values on the stack. +// +// With "use-libc-auxv" enabled, use libc's `getauxval`. +// +// Otherwise, we read aux values from /proc/self/auxv. +#[cfg_attr(target_vendor = "mustang", path = "mustang_auxv.rs")] +#[cfg_attr( + all(not(target_vendor = "mustang"), feature = "use-libc-auxv"), + path = "libc_auxv.rs" +)] +pub(crate) mod auxv; diff --git a/vendor/rustix/src/backend/linux_raw/param/mustang_auxv.rs b/vendor/rustix/src/backend/linux_raw/param/mustang_auxv.rs new file mode 100644 index 000000000..e9b89b500 --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/param/mustang_auxv.rs @@ -0,0 +1,159 @@ +//! Linux auxv support, for Mustang. +//! +//! # Safety +//! +//! This uses raw pointers to locate and read the kernel-provided auxv array. +#![allow(unsafe_code)] + +use super::super::c; +use super::super::elf::*; +#[cfg(feature = "param")] +use crate::ffi::CStr; +use core::ffi::c_void; +use core::mem::size_of; +use core::ptr::{null, read}; +#[cfg(feature = "runtime")] +use core::slice; +use linux_raw_sys::general::{ + AT_CLKTCK, AT_EXECFN, AT_HWCAP, AT_HWCAP2, AT_NULL, AT_PAGESZ, AT_PHDR, AT_PHENT, AT_PHNUM, + AT_SYSINFO_EHDR, +}; + +#[cfg(feature = "param")] +#[inline] +pub(crate) fn page_size() -> usize { + // Safety: This is initialized during program startup. + unsafe { PAGE_SIZE } +} + +#[cfg(feature = "param")] +#[inline] +pub(crate) fn clock_ticks_per_second() -> u64 { + // Safety: This is initialized during program startup. + unsafe { CLOCK_TICKS_PER_SECOND as u64 } +} + +#[cfg(feature = "param")] +#[inline] +pub(crate) fn linux_hwcap() -> (usize, usize) { + // Safety: This is initialized during program startup. + unsafe { (HWCAP, HWCAP2) } +} + +#[cfg(feature = "param")] +#[inline] +pub(crate) fn linux_execfn() -> &'static CStr { + // Safety: This is initialized during program startup. And we + // assume it's a valid pointer to a NUL-terminated string. + unsafe { CStr::from_ptr(EXECFN.0.cast()) } +} + +#[cfg(feature = "runtime")] +#[inline] +pub(crate) fn exe_phdrs() -> (*const c_void, usize) { + // Safety: This is initialized during program startup. + unsafe { (PHDR.0.cast(), PHNUM) } +} + +#[cfg(feature = "runtime")] +#[inline] +pub(in super::super) fn exe_phdrs_slice() -> &'static [Elf_Phdr] { + let (phdr, phnum) = exe_phdrs(); + + // Safety: We assume the `AT_PHDR` and `AT_PHNUM` values provided by the + // kernel form a valid slice. + unsafe { slice::from_raw_parts(phdr.cast(), phnum) } +} + +/// `AT_SYSINFO_EHDR` isn't present on all platforms in all configurations, +/// so if we don't see it, this function returns a null pointer. +#[inline] +pub(in super::super) fn sysinfo_ehdr() -> *const Elf_Ehdr { + // Safety: This is initialized during program startup. + unsafe { SYSINFO_EHDR.0 } +} + +/// A const pointer to `T` that implements [`Sync`]. +#[repr(transparent)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct SyncConstPtr<T>(*const T); +unsafe impl<T> Sync for SyncConstPtr<T> {} + +impl<T> SyncConstPtr<T> { + /// Creates a `SyncConstPointer` from a raw pointer. + /// + /// Behavior is undefined if `ptr` is actually not + /// safe to share across threads. + pub const unsafe fn new(ptr: *const T) -> Self { + Self(ptr) + } +} + +static mut PAGE_SIZE: usize = 0; +static mut CLOCK_TICKS_PER_SECOND: usize = 0; +static mut HWCAP: usize = 0; +static mut HWCAP2: usize = 0; +static mut SYSINFO_EHDR: SyncConstPtr<Elf_Ehdr> = unsafe { SyncConstPtr::new(null()) }; +static mut PHDR: SyncConstPtr<Elf_Phdr> = unsafe { SyncConstPtr::new(null()) }; +static mut PHNUM: usize = 0; +static mut EXECFN: SyncConstPtr<c::c_char> = unsafe { SyncConstPtr::new(null()) }; + +/// On mustang, we export a function to be called during initialization, and +/// passed a pointer to the original environment variable block set up by the +/// OS. +pub(crate) unsafe fn init(envp: *mut *mut u8) { + init_from_envp(envp); +} + +/// # Safety +/// +/// This must be passed a pointer to the environment variable buffer +/// provided by the kernel, which is followed in memory by the auxv array. +unsafe fn init_from_envp(mut envp: *mut *mut u8) { + while !(*envp).is_null() { + envp = envp.add(1); + } + init_from_auxp(envp.add(1).cast()) +} + +/// Process auxv entries from the auxv array pointed to by `auxp`. +/// +/// # Safety +/// +/// This must be passed a pointer to an auxv array. +/// +/// The buffer contains `Elf_aux_t` elements, though it need not be aligned; +/// function uses `read_unaligned` to read from it. +unsafe fn init_from_auxp(mut auxp: *const Elf_auxv_t) { + loop { + let Elf_auxv_t { a_type, a_val } = read(auxp); + + match a_type as _ { + AT_PAGESZ => PAGE_SIZE = a_val as usize, + AT_CLKTCK => CLOCK_TICKS_PER_SECOND = a_val as usize, + AT_HWCAP => HWCAP = a_val as usize, + AT_HWCAP2 => HWCAP2 = a_val as usize, + AT_PHDR => PHDR = SyncConstPtr::new(a_val.cast::<Elf_Phdr>()), + AT_PHNUM => PHNUM = a_val as usize, + AT_PHENT => assert_eq!(a_val as usize, size_of::<Elf_Phdr>()), + AT_EXECFN => EXECFN = SyncConstPtr::new(a_val.cast::<c::c_char>()), + AT_SYSINFO_EHDR => SYSINFO_EHDR = SyncConstPtr::new(a_val.cast::<Elf_Ehdr>()), + AT_NULL => break, + _ => (), + } + auxp = auxp.add(1); + } +} + +// ELF ABI + +#[repr(C)] +#[derive(Copy, Clone)] +struct Elf_auxv_t { + a_type: usize, + + // Some of the values in the auxv array are pointers, so we make `a_val` a + // pointer, in order to preserve their provenance. For the values which are + // integers, we cast this to `usize`. + a_val: *const c_void, +} diff --git a/vendor/rustix/src/imp/linux_raw/process/cpu_set.rs b/vendor/rustix/src/backend/linux_raw/process/cpu_set.rs index 10c5f478e..10c5f478e 100644 --- a/vendor/rustix/src/imp/linux_raw/process/cpu_set.rs +++ b/vendor/rustix/src/backend/linux_raw/process/cpu_set.rs diff --git a/vendor/rustix/src/imp/linux_raw/process/mod.rs b/vendor/rustix/src/backend/linux_raw/process/mod.rs index 9b2c25f91..9b2c25f91 100644 --- a/vendor/rustix/src/imp/linux_raw/process/mod.rs +++ b/vendor/rustix/src/backend/linux_raw/process/mod.rs diff --git a/vendor/rustix/src/backend/linux_raw/process/syscalls.rs b/vendor/rustix/src/backend/linux_raw/process/syscalls.rs new file mode 100644 index 000000000..ac62e6944 --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/process/syscalls.rs @@ -0,0 +1,560 @@ +//! linux_raw syscalls supporting `rustix::process`. +//! +//! # Safety +//! +//! See the `rustix::backend` module documentation for details. +#![allow(unsafe_code)] +#![allow(clippy::undocumented_unsafe_blocks)] + +use super::super::c; +use super::super::conv::{ + by_mut, by_ref, c_int, c_uint, negative_pid, pass_usize, ret, ret_c_int, ret_c_uint, + ret_infallible, ret_usize, ret_usize_infallible, size_of, slice_just_addr, slice_mut, zero, +}; +use super::types::{RawCpuSet, RawUname}; +use crate::fd::BorrowedFd; +use crate::ffi::CStr; +use crate::io; +use crate::process::{ + Cpuid, Gid, MembarrierCommand, MembarrierQuery, Pid, RawNonZeroPid, RawPid, Resource, Rlimit, + Signal, Uid, WaitOptions, WaitStatus, +}; +use core::convert::TryInto; +use core::mem::MaybeUninit; +use core::num::NonZeroU32; +use core::ptr::{null, null_mut}; +use linux_raw_sys::general::{ + __kernel_gid_t, __kernel_pid_t, __kernel_uid_t, membarrier_cmd, membarrier_cmd_flag, rlimit, + rlimit64, PRIO_PGRP, PRIO_PROCESS, PRIO_USER, RLIM64_INFINITY, RLIM_INFINITY, +}; + +#[inline] +pub(crate) fn chdir(filename: &CStr) -> io::Result<()> { + unsafe { ret(syscall_readonly!(__NR_chdir, filename)) } +} + +#[inline] +pub(crate) fn fchdir(fd: BorrowedFd<'_>) -> io::Result<()> { + unsafe { ret(syscall_readonly!(__NR_fchdir, fd)) } +} + +#[inline] +pub(crate) fn getcwd(buf: &mut [u8]) -> io::Result<usize> { + let (buf_addr_mut, buf_len) = slice_mut(buf); + unsafe { ret_usize(syscall!(__NR_getcwd, buf_addr_mut, buf_len)) } +} + +#[inline] +pub(crate) fn membarrier_query() -> MembarrierQuery { + unsafe { + match ret_c_uint(syscall!( + __NR_membarrier, + c_int(membarrier_cmd::MEMBARRIER_CMD_QUERY as _), + c_uint(0) + )) { + Ok(query) => { + // Safety: The safety of `from_bits_unchecked` is discussed + // [here]. Our "source of truth" is Linux, and here, the + // `query` value is coming from Linux, so we know it only + // contains "source of truth" valid bits. + // + // [here]: https://github.com/bitflags/bitflags/pull/207#issuecomment-671668662 + MembarrierQuery::from_bits_unchecked(query) + } + Err(_) => MembarrierQuery::empty(), + } + } +} + +#[inline] +pub(crate) fn membarrier(cmd: MembarrierCommand) -> io::Result<()> { + unsafe { ret(syscall!(__NR_membarrier, cmd, c_uint(0))) } +} + +#[inline] +pub(crate) fn membarrier_cpu(cmd: MembarrierCommand, cpu: Cpuid) -> io::Result<()> { + unsafe { + ret(syscall!( + __NR_membarrier, + cmd, + c_uint(membarrier_cmd_flag::MEMBARRIER_CMD_FLAG_CPU as _), + cpu + )) + } +} + +#[inline] +pub(crate) fn getpid() -> Pid { + unsafe { + let pid: i32 = ret_usize_infallible(syscall_readonly!(__NR_getpid)) as __kernel_pid_t; + debug_assert!(pid > 0); + Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked(pid as u32)) + } +} + +#[inline] +pub(crate) fn getppid() -> Option<Pid> { + unsafe { + let ppid: i32 = ret_usize_infallible(syscall_readonly!(__NR_getppid)) as __kernel_pid_t; + Pid::from_raw(ppid as u32) + } +} + +#[inline] +pub(crate) fn getpgid(pid: Option<Pid>) -> io::Result<Pid> { + unsafe { + let pgid: i32 = + ret_usize(syscall_readonly!(__NR_getpgid, c_uint(Pid::as_raw(pid))))? as __kernel_pid_t; + Ok(Pid::from_raw_nonzero(NonZeroU32::new_unchecked( + pgid as u32, + ))) + } +} + +#[inline] +pub(crate) fn getpgrp() -> Pid { + // Use the `getpgrp` syscall if available. + #[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))] + unsafe { + let pgid: i32 = ret_usize_infallible(syscall_readonly!(__NR_getpgrp)) as __kernel_pid_t; + debug_assert!(pgid > 0); + Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked(pgid as u32)) + } + + // Otherwise use `getpgrp` and pass it zero. + #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + unsafe { + let pgid: i32 = + ret_usize_infallible(syscall_readonly!(__NR_getpgid, c_uint(0))) as __kernel_pid_t; + debug_assert!(pgid > 0); + Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked(pgid as u32)) + } +} + +#[inline] +pub(crate) fn getgid() -> Gid { + #[cfg(any(target_arch = "x86", target_arch = "sparc", target_arch = "arm"))] + unsafe { + let gid: i32 = + (ret_usize_infallible(syscall_readonly!(__NR_getgid32)) as __kernel_gid_t).into(); + Gid::from_raw(gid as u32) + } + #[cfg(not(any(target_arch = "x86", target_arch = "sparc", target_arch = "arm")))] + unsafe { + let gid = ret_usize_infallible(syscall_readonly!(__NR_getgid)) as __kernel_gid_t; + Gid::from_raw(gid as u32) + } +} + +#[inline] +pub(crate) fn getegid() -> Gid { + #[cfg(any(target_arch = "x86", target_arch = "sparc", target_arch = "arm"))] + unsafe { + let gid: i32 = + (ret_usize_infallible(syscall_readonly!(__NR_getegid32)) as __kernel_gid_t).into(); + Gid::from_raw(gid as u32) + } + #[cfg(not(any(target_arch = "x86", target_arch = "sparc", target_arch = "arm")))] + unsafe { + let gid = ret_usize_infallible(syscall_readonly!(__NR_getegid)) as __kernel_gid_t; + Gid::from_raw(gid as u32) + } +} + +#[inline] +pub(crate) fn getuid() -> Uid { + #[cfg(any(target_arch = "x86", target_arch = "sparc", target_arch = "arm"))] + unsafe { + let uid = (ret_usize_infallible(syscall_readonly!(__NR_getuid32)) as __kernel_uid_t).into(); + Uid::from_raw(uid) + } + #[cfg(not(any(target_arch = "x86", target_arch = "sparc", target_arch = "arm")))] + unsafe { + let uid = ret_usize_infallible(syscall_readonly!(__NR_getuid)) as __kernel_uid_t; + Uid::from_raw(uid as u32) + } +} + +#[inline] +pub(crate) fn geteuid() -> Uid { + #[cfg(any(target_arch = "x86", target_arch = "sparc", target_arch = "arm"))] + unsafe { + let uid: i32 = + (ret_usize_infallible(syscall_readonly!(__NR_geteuid32)) as __kernel_uid_t).into(); + Uid::from_raw(uid as u32) + } + #[cfg(not(any(target_arch = "x86", target_arch = "sparc", target_arch = "arm")))] + unsafe { + let uid = ret_usize_infallible(syscall_readonly!(__NR_geteuid)) as __kernel_uid_t; + Uid::from_raw(uid as u32) + } +} + +#[inline] +pub(crate) fn sched_getaffinity(pid: Option<Pid>, cpuset: &mut RawCpuSet) -> io::Result<()> { + unsafe { + // The raw linux syscall returns the size (in bytes) of the `cpumask_t` + // data type that is used internally by the kernel to represent the CPU + // set bit mask. + let size = ret_usize(syscall!( + __NR_sched_getaffinity, + c_uint(Pid::as_raw(pid)), + size_of::<RawCpuSet, _>(), + by_mut(&mut cpuset.bits) + ))?; + let bytes = (cpuset as *mut RawCpuSet).cast::<u8>(); + let rest = bytes.wrapping_add(size); + // Zero every byte in the cpuset not set by the kernel. + rest.write_bytes(0, core::mem::size_of::<RawCpuSet>() - size); + Ok(()) + } +} + +#[inline] +pub(crate) fn sched_setaffinity(pid: Option<Pid>, cpuset: &RawCpuSet) -> io::Result<()> { + unsafe { + ret(syscall_readonly!( + __NR_sched_setaffinity, + c_uint(Pid::as_raw(pid)), + size_of::<RawCpuSet, _>(), + slice_just_addr(&cpuset.bits) + )) + } +} + +#[inline] +pub(crate) fn sched_yield() { + unsafe { + // See the documentation for [`crate::process::sched_yield`] for why + // errors are ignored. + syscall_readonly!(__NR_sched_yield).decode_void(); + } +} + +#[inline] +pub(crate) fn uname() -> RawUname { + let mut uname = MaybeUninit::<RawUname>::uninit(); + unsafe { + ret(syscall!(__NR_uname, &mut uname)).unwrap(); + uname.assume_init() + } +} + +#[inline] +pub(crate) fn nice(inc: i32) -> io::Result<i32> { + let priority = if inc > -40 && inc < 40 { + inc + getpriority_process(None)? + } else { + inc + } + // TODO: With Rust 1.50, use `.clamp` instead of `.min` and `.max`. + //.clamp(-20, 19); + .min(19) + .max(-20); + setpriority_process(None, priority)?; + Ok(priority) +} + +#[inline] +pub(crate) fn getpriority_user(uid: Uid) -> io::Result<i32> { + unsafe { + Ok(20 + - ret_c_int(syscall_readonly!( + __NR_getpriority, + c_uint(PRIO_USER), + c_uint(uid.as_raw()) + ))?) + } +} + +#[inline] +pub(crate) fn getpriority_pgrp(pgid: Option<Pid>) -> io::Result<i32> { + unsafe { + Ok(20 + - ret_c_int(syscall_readonly!( + __NR_getpriority, + c_uint(PRIO_PGRP), + c_uint(Pid::as_raw(pgid)) + ))?) + } +} + +#[inline] +pub(crate) fn getpriority_process(pid: Option<Pid>) -> io::Result<i32> { + unsafe { + Ok(20 + - ret_c_int(syscall_readonly!( + __NR_getpriority, + c_uint(PRIO_PROCESS), + c_uint(Pid::as_raw(pid)) + ))?) + } +} + +#[inline] +pub(crate) fn setpriority_user(uid: Uid, priority: i32) -> io::Result<()> { + unsafe { + ret(syscall_readonly!( + __NR_setpriority, + c_uint(PRIO_USER), + c_uint(uid.as_raw()), + c_int(priority) + )) + } +} + +#[inline] +pub(crate) fn setpriority_pgrp(pgid: Option<Pid>, priority: i32) -> io::Result<()> { + unsafe { + ret(syscall_readonly!( + __NR_setpriority, + c_uint(PRIO_PGRP), + c_uint(Pid::as_raw(pgid)), + c_int(priority) + )) + } +} + +#[inline] +pub(crate) fn setpriority_process(pid: Option<Pid>, priority: i32) -> io::Result<()> { + unsafe { + ret(syscall_readonly!( + __NR_setpriority, + c_uint(PRIO_PROCESS), + c_uint(Pid::as_raw(pid)), + c_int(priority) + )) + } +} + +#[inline] +pub(crate) fn getrlimit(limit: Resource) -> Rlimit { + let mut result = MaybeUninit::<rlimit64>::uninit(); + unsafe { + match ret(syscall!( + __NR_prlimit64, + c_uint(0), + limit, + null::<c::c_void>(), + &mut result + )) { + Ok(()) => rlimit_from_linux(result.assume_init()), + Err(err) => { + debug_assert_eq!(err, io::Errno::NOSYS); + getrlimit_old(limit) + } + } + } +} + +/// The old 32-bit-only `getrlimit` syscall, for when we lack the new +/// `prlimit64`. +unsafe fn getrlimit_old(limit: Resource) -> Rlimit { + let mut result = MaybeUninit::<rlimit>::uninit(); + + // On these platforms, `__NR_getrlimit` is called `__NR_ugetrlimit`. + #[cfg(any( + target_arch = "arm", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "x86", + ))] + { + ret_infallible(syscall!(__NR_ugetrlimit, limit, &mut result)); + } + + // On these platforms, it's just `__NR_getrlimit`. + #[cfg(not(any( + target_arch = "arm", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "x86", + )))] + { + ret_infallible(syscall!(__NR_getrlimit, limit, &mut result)); + } + + rlimit_from_linux_old(result.assume_init()) +} + +#[inline] +pub(crate) fn setrlimit(limit: Resource, new: Rlimit) -> io::Result<()> { + unsafe { + let lim = rlimit_to_linux(new.clone()); + match ret(syscall_readonly!( + __NR_prlimit64, + c_uint(0), + limit, + by_ref(&lim), + null_mut::<c::c_void>() + )) { + Ok(()) => Ok(()), + Err(io::Errno::NOSYS) => setrlimit_old(limit, new), + Err(err) => Err(err), + } + } +} + +/// The old 32-bit-only `setrlimit` syscall, for when we lack the new +/// `prlimit64`. +unsafe fn setrlimit_old(limit: Resource, new: Rlimit) -> io::Result<()> { + let lim = rlimit_to_linux_old(new)?; + ret(syscall_readonly!(__NR_setrlimit, limit, by_ref(&lim))) +} + +#[inline] +pub(crate) fn prlimit(pid: Option<Pid>, limit: Resource, new: Rlimit) -> io::Result<Rlimit> { + let lim = rlimit_to_linux(new); + let mut result = MaybeUninit::<rlimit64>::uninit(); + unsafe { + match ret(syscall!( + __NR_prlimit64, + c_uint(Pid::as_raw(pid)), + limit, + by_ref(&lim), + &mut result + )) { + Ok(()) => Ok(rlimit_from_linux(result.assume_init())), + Err(err) => Err(err), + } + } +} + +/// Convert a Rust [`Rlimit`] to a C `rlimit64`. +#[inline] +fn rlimit_from_linux(lim: rlimit64) -> Rlimit { + let current = if lim.rlim_cur == RLIM64_INFINITY as _ { + None + } else { + Some(lim.rlim_cur) + }; + let maximum = if lim.rlim_max == RLIM64_INFINITY as _ { + None + } else { + Some(lim.rlim_max) + }; + Rlimit { current, maximum } +} + +/// Convert a C `rlimit64` to a Rust `Rlimit`. +#[inline] +fn rlimit_to_linux(lim: Rlimit) -> rlimit64 { + let rlim_cur = match lim.current { + Some(r) => r, + None => RLIM64_INFINITY as _, + }; + let rlim_max = match lim.maximum { + Some(r) => r, + None => RLIM64_INFINITY as _, + }; + rlimit64 { rlim_cur, rlim_max } +} + +/// Like `rlimit_from_linux` but uses Linux's old 32-bit `rlimit`. +#[allow(clippy::useless_conversion)] +fn rlimit_from_linux_old(lim: rlimit) -> Rlimit { + let current = if lim.rlim_cur == RLIM_INFINITY as _ { + None + } else { + Some(lim.rlim_cur.into()) + }; + let maximum = if lim.rlim_max == RLIM_INFINITY as _ { + None + } else { + Some(lim.rlim_max.into()) + }; + Rlimit { current, maximum } +} + +/// Like `rlimit_to_linux` but uses Linux's old 32-bit `rlimit`. +#[allow(clippy::useless_conversion)] +fn rlimit_to_linux_old(lim: Rlimit) -> io::Result<rlimit> { + let rlim_cur = match lim.current { + Some(r) => r.try_into().map_err(|_e| io::Errno::INVAL)?, + None => RLIM_INFINITY as _, + }; + let rlim_max = match lim.maximum { + Some(r) => r.try_into().map_err(|_e| io::Errno::INVAL)?, + None => RLIM_INFINITY as _, + }; + Ok(rlimit { rlim_cur, rlim_max }) +} + +#[inline] +pub(crate) fn wait(waitopts: WaitOptions) -> io::Result<Option<(Pid, WaitStatus)>> { + _waitpid(!0, waitopts) +} + +#[inline] +pub(crate) fn waitpid( + pid: Option<Pid>, + waitopts: WaitOptions, +) -> io::Result<Option<(Pid, WaitStatus)>> { + _waitpid(Pid::as_raw(pid), waitopts) +} + +#[inline] +pub(crate) fn _waitpid( + pid: RawPid, + waitopts: WaitOptions, +) -> io::Result<Option<(Pid, WaitStatus)>> { + unsafe { + let mut status = MaybeUninit::<u32>::uninit(); + let pid = ret_c_uint(syscall!( + __NR_wait4, + c_int(pid as _), + &mut status, + c_int(waitopts.bits() as _), + zero() + ))?; + Ok(RawNonZeroPid::new(pid).map(|non_zero| { + ( + Pid::from_raw_nonzero(non_zero), + WaitStatus::new(status.assume_init()), + ) + })) + } +} + +#[cfg(feature = "runtime")] +#[inline] +pub(crate) fn exit_group(code: c::c_int) -> ! { + unsafe { syscall_noreturn!(__NR_exit_group, c_int(code)) } +} + +#[inline] +pub(crate) fn setsid() -> io::Result<Pid> { + unsafe { + let pid = ret_usize(syscall_readonly!(__NR_setsid))?; + debug_assert!(pid > 0); + Ok(Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked( + pid as u32, + ))) + } +} + +#[inline] +pub(crate) fn kill_process(pid: Pid, sig: Signal) -> io::Result<()> { + unsafe { ret(syscall_readonly!(__NR_kill, pid, sig)) } +} + +#[inline] +pub(crate) fn kill_process_group(pid: Pid, sig: Signal) -> io::Result<()> { + unsafe { ret(syscall_readonly!(__NR_kill, negative_pid(pid), sig)) } +} + +#[inline] +pub(crate) fn kill_current_process_group(sig: Signal) -> io::Result<()> { + unsafe { ret(syscall_readonly!(__NR_kill, pass_usize(0), sig)) } +} + +#[inline] +pub(crate) unsafe fn prctl( + option: c::c_int, + arg2: *mut c::c_void, + arg3: *mut c::c_void, + arg4: *mut c::c_void, + arg5: *mut c::c_void, +) -> io::Result<c::c_int> { + ret_c_int(syscall!(__NR_prctl, c_int(option), arg2, arg3, arg4, arg5)) +} diff --git a/vendor/rustix/src/imp/linux_raw/process/types.rs b/vendor/rustix/src/backend/linux_raw/process/types.rs index 53e2c7db1..53e2c7db1 100644 --- a/vendor/rustix/src/imp/linux_raw/process/types.rs +++ b/vendor/rustix/src/backend/linux_raw/process/types.rs diff --git a/vendor/rustix/src/imp/linux_raw/process/wait.rs b/vendor/rustix/src/backend/linux_raw/process/wait.rs index 701b4ac0c..701b4ac0c 100644 --- a/vendor/rustix/src/imp/linux_raw/process/wait.rs +++ b/vendor/rustix/src/backend/linux_raw/process/wait.rs diff --git a/vendor/rustix/src/imp/linux_raw/rand/mod.rs b/vendor/rustix/src/backend/linux_raw/rand/mod.rs index 1e0181a99..1e0181a99 100644 --- a/vendor/rustix/src/imp/linux_raw/rand/mod.rs +++ b/vendor/rustix/src/backend/linux_raw/rand/mod.rs diff --git a/vendor/rustix/src/backend/linux_raw/rand/syscalls.rs b/vendor/rustix/src/backend/linux_raw/rand/syscalls.rs new file mode 100644 index 000000000..5533f75e0 --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/rand/syscalls.rs @@ -0,0 +1,17 @@ +//! linux_raw syscalls supporting `rustix::rand`. +//! +//! # Safety +//! +//! See the `rustix::backend` module documentation for details. +#![allow(unsafe_code)] +#![allow(clippy::undocumented_unsafe_blocks)] + +use super::super::conv::{ret_usize, slice_mut}; +use crate::io; +use crate::rand::GetRandomFlags; + +#[inline] +pub(crate) fn getrandom(buf: &mut [u8], flags: GetRandomFlags) -> io::Result<usize> { + let (buf_addr_mut, buf_len) = slice_mut(buf); + unsafe { ret_usize(syscall!(__NR_getrandom, buf_addr_mut, buf_len, flags)) } +} diff --git a/vendor/rustix/src/imp/linux_raw/rand/types.rs b/vendor/rustix/src/backend/linux_raw/rand/types.rs index 75f17443e..75f17443e 100644 --- a/vendor/rustix/src/imp/linux_raw/rand/types.rs +++ b/vendor/rustix/src/backend/linux_raw/rand/types.rs diff --git a/vendor/rustix/src/imp/linux_raw/reg.rs b/vendor/rustix/src/backend/linux_raw/reg.rs index afe99c5f4..afe99c5f4 100644 --- a/vendor/rustix/src/imp/linux_raw/reg.rs +++ b/vendor/rustix/src/backend/linux_raw/reg.rs diff --git a/vendor/rustix/src/imp/linux_raw/runtime/mod.rs b/vendor/rustix/src/backend/linux_raw/runtime/mod.rs index 0b48649ce..0b48649ce 100644 --- a/vendor/rustix/src/imp/linux_raw/runtime/mod.rs +++ b/vendor/rustix/src/backend/linux_raw/runtime/mod.rs diff --git a/vendor/rustix/src/backend/linux_raw/runtime/syscalls.rs b/vendor/rustix/src/backend/linux_raw/runtime/syscalls.rs new file mode 100644 index 000000000..a331786f9 --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/runtime/syscalls.rs @@ -0,0 +1,107 @@ +//! linux_raw syscalls supporting `rustix::runtime`. +//! +//! # Safety +//! +//! See the `rustix::backend` module documentation for details. +#![allow(unsafe_code)] +#![allow(clippy::undocumented_unsafe_blocks)] + +use super::super::c; +#[cfg(target_arch = "x86")] +use super::super::conv::by_mut; +use super::super::conv::{c_int, c_uint, ret, ret_c_uint, ret_error, ret_usize_infallible, zero}; +#[cfg(feature = "fs")] +use crate::fd::BorrowedFd; +use crate::ffi::CStr; +#[cfg(feature = "fs")] +use crate::fs::AtFlags; +use crate::io; +use crate::process::{Pid, RawNonZeroPid}; +use linux_raw_sys::general::{__kernel_pid_t, PR_SET_NAME, SIGCHLD}; +#[cfg(target_arch = "x86_64")] +use {super::super::conv::ret_infallible, linux_raw_sys::general::ARCH_SET_FS}; + +#[inline] +pub(crate) unsafe fn fork() -> io::Result<Option<Pid>> { + let pid = ret_c_uint(syscall_readonly!( + __NR_clone, + c_uint(SIGCHLD), + zero(), + zero(), + zero(), + zero() + ))?; + Ok(Pid::from_raw(pid)) +} + +#[cfg(feature = "fs")] +pub(crate) unsafe fn execveat( + dirfd: BorrowedFd<'_>, + path: &CStr, + args: *const *const u8, + env_vars: *const *const u8, + flags: AtFlags, +) -> io::Errno { + ret_error(syscall_readonly!( + __NR_execveat, + dirfd, + path, + args, + env_vars, + flags + )) +} + +pub(crate) unsafe fn execve( + path: &CStr, + args: *const *const u8, + env_vars: *const *const u8, +) -> io::Errno { + ret_error(syscall_readonly!(__NR_execve, path, args, env_vars)) +} + +pub(crate) mod tls { + #[cfg(target_arch = "x86")] + use super::super::tls::UserDesc; + use super::*; + + #[cfg(target_arch = "x86")] + #[inline] + pub(crate) unsafe fn set_thread_area(u_info: &mut UserDesc) -> io::Result<()> { + ret(syscall!(__NR_set_thread_area, by_mut(u_info))) + } + + #[cfg(target_arch = "arm")] + #[inline] + pub(crate) unsafe fn arm_set_tls(data: *mut c::c_void) -> io::Result<()> { + ret(syscall_readonly!(__ARM_NR_set_tls, data)) + } + + #[cfg(target_arch = "x86_64")] + #[inline] + pub(crate) unsafe fn set_fs(data: *mut c::c_void) { + ret_infallible(syscall_readonly!( + __NR_arch_prctl, + c_uint(ARCH_SET_FS), + data + )) + } + + #[inline] + pub(crate) unsafe fn set_tid_address(data: *mut c::c_void) -> Pid { + let tid: i32 = + ret_usize_infallible(syscall_readonly!(__NR_set_tid_address, data)) as __kernel_pid_t; + debug_assert_ne!(tid, 0); + Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked(tid as u32)) + } + + #[inline] + pub(crate) unsafe fn set_thread_name(name: &CStr) -> io::Result<()> { + ret(syscall_readonly!(__NR_prctl, c_uint(PR_SET_NAME), name)) + } + + #[inline] + pub(crate) fn exit_thread(code: c::c_int) -> ! { + unsafe { syscall_noreturn!(__NR_exit, c_int(code)) } + } +} diff --git a/vendor/rustix/src/backend/linux_raw/runtime/tls.rs b/vendor/rustix/src/backend/linux_raw/runtime/tls.rs new file mode 100644 index 000000000..43ed25d7d --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/runtime/tls.rs @@ -0,0 +1,57 @@ +#![allow(unsafe_code)] + +use super::super::c; +use super::super::elf::*; +use super::super::param::auxv::exe_phdrs_slice; +use core::ptr::null; + +/// For use with [`set_thread_area`]. +/// +/// [`set_thread_area`]: crate::runtime::set_thread_area +#[cfg(target_arch = "x86")] +pub type UserDesc = linux_raw_sys::general::user_desc; + +pub(crate) fn startup_tls_info() -> StartupTlsInfo { + let mut base = null(); + let mut tls_phdr = null(); + let mut stack_size = 0; + + let phdrs = exe_phdrs_slice(); + + // Safety: We assume the phdr array pointer and length the kernel provided + // to the process describe a valid phdr array. + unsafe { + for phdr in phdrs { + match phdr.p_type { + PT_PHDR => base = phdrs.as_ptr().cast::<u8>().offset(-(phdr.p_vaddr as isize)), + PT_TLS => tls_phdr = phdr, + PT_GNU_STACK => stack_size = phdr.p_memsz, + _ => {} + } + } + + StartupTlsInfo { + addr: base.cast::<u8>().add((*tls_phdr).p_vaddr).cast(), + mem_size: (*tls_phdr).p_memsz, + file_size: (*tls_phdr).p_filesz, + align: (*tls_phdr).p_align, + stack_size, + } + } +} + +/// The values returned from [`startup_tls_info`]. +/// +/// [`startup_tls_info`]: crate::runtime::startup_tls_info +pub struct StartupTlsInfo { + /// The base address of the TLS segment. + pub addr: *const c::c_void, + /// The size of the memory region. + pub mem_size: usize, + /// The size beyond which all memory is zero-initialized. + pub file_size: usize, + /// The required alignment for the TLS segment. + pub align: usize, + /// The requested minimum size for stacks. + pub stack_size: usize, +} diff --git a/vendor/rustix/src/imp/linux_raw/termios/mod.rs b/vendor/rustix/src/backend/linux_raw/termios/mod.rs index 1e0181a99..1e0181a99 100644 --- a/vendor/rustix/src/imp/linux_raw/termios/mod.rs +++ b/vendor/rustix/src/backend/linux_raw/termios/mod.rs diff --git a/vendor/rustix/src/backend/linux_raw/termios/syscalls.rs b/vendor/rustix/src/backend/linux_raw/termios/syscalls.rs new file mode 100644 index 000000000..a8dda5f81 --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/termios/syscalls.rs @@ -0,0 +1,252 @@ +//! linux_raw syscalls supporting `rustix::termios`. +//! +//! # Safety +//! +//! See the `rustix::backend` module documentation for details. +#![allow(unsafe_code)] +#![allow(clippy::undocumented_unsafe_blocks)] + +use super::super::conv::{by_ref, c_uint, ret}; +use crate::fd::BorrowedFd; +use crate::io; +use crate::process::{Pid, RawNonZeroPid}; +use crate::termios::{ + Action, OptionalActions, QueueSelector, Termios, Winsize, BRKINT, CBAUD, CS8, CSIZE, ECHO, + ECHONL, ICANON, ICRNL, IEXTEN, IGNBRK, IGNCR, INLCR, ISIG, ISTRIP, IXON, OPOST, PARENB, PARMRK, + VMIN, VTIME, +}; +#[cfg(feature = "procfs")] +use crate::{ffi::CStr, fs::FileType, path::DecInt}; +use core::mem::MaybeUninit; +use linux_raw_sys::general::__kernel_pid_t; +use linux_raw_sys::ioctl::{ + TCFLSH, TCGETS, TCSBRK, TCSETS, TCXONC, TIOCGPGRP, TIOCGSID, TIOCGWINSZ, TIOCSPGRP, TIOCSWINSZ, +}; + +#[inline] +pub(crate) fn tcgetwinsize(fd: BorrowedFd<'_>) -> io::Result<Winsize> { + unsafe { + let mut result = MaybeUninit::<Winsize>::uninit(); + ret(syscall!(__NR_ioctl, fd, c_uint(TIOCGWINSZ), &mut result))?; + Ok(result.assume_init()) + } +} + +#[inline] +pub(crate) fn tcgetattr(fd: BorrowedFd<'_>) -> io::Result<Termios> { + unsafe { + let mut result = MaybeUninit::<Termios>::uninit(); + ret(syscall!(__NR_ioctl, fd, c_uint(TCGETS), &mut result))?; + Ok(result.assume_init()) + } +} + +#[inline] +pub(crate) fn tcgetpgrp(fd: BorrowedFd<'_>) -> io::Result<Pid> { + unsafe { + let mut result = MaybeUninit::<__kernel_pid_t>::uninit(); + ret(syscall!(__NR_ioctl, fd, c_uint(TIOCGPGRP), &mut result))?; + let pid = result.assume_init(); + debug_assert!(pid > 0); + Ok(Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked( + pid as u32, + ))) + } +} + +#[inline] +pub(crate) fn tcsetattr( + fd: BorrowedFd, + optional_actions: OptionalActions, + termios: &Termios, +) -> io::Result<()> { + // Translate from `optional_actions` into an ioctl request code. On MIPS, + // `optional_actions` already has `TCGETS` added to it. + let request = if cfg!(any(target_arch = "mips", target_arch = "mips64")) { + optional_actions as u32 + } else { + TCSETS + optional_actions as u32 + }; + unsafe { + ret(syscall_readonly!( + __NR_ioctl, + fd, + c_uint(request as u32), + by_ref(termios) + )) + } +} + +#[inline] +pub(crate) fn tcsendbreak(fd: BorrowedFd) -> io::Result<()> { + unsafe { ret(syscall_readonly!(__NR_ioctl, fd, c_uint(TCSBRK), c_uint(0))) } +} + +#[inline] +pub(crate) fn tcdrain(fd: BorrowedFd) -> io::Result<()> { + unsafe { ret(syscall_readonly!(__NR_ioctl, fd, c_uint(TCSBRK), c_uint(1))) } +} + +#[inline] +pub(crate) fn tcflush(fd: BorrowedFd, queue_selector: QueueSelector) -> io::Result<()> { + unsafe { + ret(syscall_readonly!( + __NR_ioctl, + fd, + c_uint(TCFLSH), + c_uint(queue_selector as u32) + )) + } +} + +#[inline] +pub(crate) fn tcflow(fd: BorrowedFd, action: Action) -> io::Result<()> { + unsafe { + ret(syscall_readonly!( + __NR_ioctl, + fd, + c_uint(TCXONC), + c_uint(action as u32) + )) + } +} + +#[inline] +pub(crate) fn tcgetsid(fd: BorrowedFd) -> io::Result<Pid> { + unsafe { + let mut result = MaybeUninit::<__kernel_pid_t>::uninit(); + ret(syscall!(__NR_ioctl, fd, c_uint(TIOCGSID), &mut result))?; + let pid = result.assume_init(); + debug_assert!(pid > 0); + Ok(Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked( + pid as u32, + ))) + } +} + +#[inline] +pub(crate) fn tcsetwinsize(fd: BorrowedFd, winsize: Winsize) -> io::Result<()> { + unsafe { + ret(syscall!( + __NR_ioctl, + fd, + c_uint(TIOCSWINSZ), + by_ref(&winsize) + )) + } +} + +#[inline] +pub(crate) fn tcsetpgrp(fd: BorrowedFd<'_>, pid: Pid) -> io::Result<()> { + unsafe { ret(syscall!(__NR_ioctl, fd, c_uint(TIOCSPGRP), pid)) } +} + +#[inline] +#[must_use] +#[allow(clippy::missing_const_for_fn)] +pub(crate) fn cfgetospeed(termios: &Termios) -> u32 { + termios.c_cflag & CBAUD +} + +#[inline] +#[must_use] +#[allow(clippy::missing_const_for_fn)] +pub(crate) fn cfgetispeed(termios: &Termios) -> u32 { + termios.c_cflag & CBAUD +} + +#[inline] +pub(crate) fn cfmakeraw(termios: &mut Termios) { + // From the Linux [`cfmakeraw` man page]: + // + // [`cfmakeraw` man page]: https://man7.org/linux/man-pages/man3/cfmakeraw.3.html + termios.c_iflag &= !(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); + termios.c_oflag &= !OPOST; + termios.c_lflag &= !(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + termios.c_cflag &= !(CSIZE | PARENB); + termios.c_cflag |= CS8; + + // Musl and glibc also do these: + termios.c_cc[VMIN] = 1; + termios.c_cc[VTIME] = 0; +} + +#[inline] +pub(crate) fn cfsetospeed(termios: &mut Termios, speed: u32) -> io::Result<()> { + if (speed & !CBAUD) != 0 { + return Err(io::Errno::INVAL); + } + termios.c_cflag &= !CBAUD; + termios.c_cflag |= speed; + Ok(()) +} + +#[inline] +pub(crate) fn cfsetispeed(termios: &mut Termios, speed: u32) -> io::Result<()> { + if speed == 0 { + return Ok(()); + } + if (speed & !CBAUD) != 0 { + return Err(io::Errno::INVAL); + } + termios.c_cflag &= !CBAUD; + termios.c_cflag |= speed; + Ok(()) +} + +#[inline] +pub(crate) fn cfsetspeed(termios: &mut Termios, speed: u32) -> io::Result<()> { + if (speed & !CBAUD) != 0 { + return Err(io::Errno::INVAL); + } + termios.c_cflag &= !CBAUD; + termios.c_cflag |= speed; + Ok(()) +} + +#[inline] +pub(crate) fn isatty(fd: BorrowedFd<'_>) -> bool { + // On error, Linux will return either `EINVAL` (2.6.32) or `ENOTTY` + // (otherwise), because we assume we're never passing an invalid + // file descriptor (which would get `EBADF`). Either way, an error + // means we don't have a tty. + tcgetwinsize(fd).is_ok() +} + +#[cfg(feature = "procfs")] +pub(crate) fn ttyname(fd: BorrowedFd<'_>, buf: &mut [u8]) -> io::Result<usize> { + let fd_stat = super::super::fs::syscalls::fstat(fd)?; + + // Quick check: if `fd` isn't a character device, it's not a tty. + if FileType::from_raw_mode(fd_stat.st_mode) != FileType::CharacterDevice { + return Err(crate::io::Errno::NOTTY); + } + + // Check that `fd` is really a tty. + tcgetwinsize(fd)?; + + // Get a fd to '/proc/self/fd'. + let proc_self_fd = io::proc_self_fd()?; + + // Gather the ttyname by reading the 'fd' file inside 'proc_self_fd'. + let r = + super::super::fs::syscalls::readlinkat(proc_self_fd, DecInt::from_fd(fd).as_c_str(), buf)?; + + // If the number of bytes is equal to the buffer length, truncation may + // have occurred. This check also ensures that we have enough space for + // adding a NUL terminator. + if r == buf.len() { + return Err(io::Errno::RANGE); + } + buf[r] = b'\0'; + + // Check that the path we read refers to the same file as `fd`. + let path = CStr::from_bytes_with_nul(&buf[..=r]).unwrap(); + + let path_stat = super::super::fs::syscalls::stat(path)?; + if path_stat.st_dev != fd_stat.st_dev || path_stat.st_ino != fd_stat.st_ino { + return Err(crate::io::Errno::NODEV); + } + + Ok(r) +} diff --git a/vendor/rustix/src/backend/linux_raw/termios/types.rs b/vendor/rustix/src/backend/linux_raw/termios/types.rs new file mode 100644 index 000000000..88db4e1c9 --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/termios/types.rs @@ -0,0 +1,460 @@ +use super::super::c; + +/// `TCSA*` values for use with [`tcsetattr`]. +/// +/// [`tcsetattr`]: crate::termios::tcsetattr +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[repr(u32)] +pub enum OptionalActions { + /// `TCSANOW`—Make the change immediately. + Now = linux_raw_sys::general::TCSANOW, + + /// `TCSADRAIN`—Make the change after all output has been transmitted. + Drain = linux_raw_sys::general::TCSADRAIN, + + /// `TCSAFLUSH`—Discard any pending input and then make the change + /// after all output has been transmitted. + Flush = linux_raw_sys::general::TCSAFLUSH, +} + +/// `TC*` values for use with [`tcflush`]. +/// +/// [`tcflush`]: crate::termios::tcflush +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[repr(u32)] +pub enum QueueSelector { + /// `TCIFLUSH`—Flush data received but not read. + IFlush = linux_raw_sys::general::TCIFLUSH, + + /// `TCOFLUSH`—Flush data written but not transmitted. + OFlush = linux_raw_sys::general::TCOFLUSH, + + /// `TCIOFLUSH`—`IFlush` and `OFlush` combined. + IOFlush = linux_raw_sys::general::TCIOFLUSH, +} + +/// `TC*` values for use with [`tcflow`]. +/// +/// [`tcflow`]: crate::termios::tcflow +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[repr(u32)] +pub enum Action { + /// `TCOOFF`—Suspend output. + OOff = linux_raw_sys::general::TCOOFF, + + /// `TCOON`—Restart suspended output. + OOn = linux_raw_sys::general::TCOON, + + /// `TCIOFF`—Transmits a STOP byte. + IOff = linux_raw_sys::general::TCIOFF, + + /// `TCION`—Transmits a START byte. + IOn = linux_raw_sys::general::TCION, +} + +/// `struct termios` for use with [`tcgetattr`]. +/// +/// [`tcgetattr`]: crate::termios::tcgetattr +pub type Termios = linux_raw_sys::general::termios; + +/// `struct winsize` for use with [`tcgetwinsize`]. +/// +/// [`tcgetwinsize`]: crate::termios::tcgetwinsize +pub type Winsize = linux_raw_sys::general::winsize; + +/// `tcflag_t`—A type for the flags fields of [`Termios`]. +pub type Tcflag = linux_raw_sys::general::tcflag_t; + +/// `speed_t`—A return type for [`cfsetspeed`] and similar. +/// +/// [`cfsetspeed`]: crate::termios::cfsetspeed +pub type Speed = linux_raw_sys::general::speed_t; + +/// `VINTR` +pub const VINTR: usize = linux_raw_sys::general::VINTR as usize; + +/// `VQUIT` +pub const VQUIT: usize = linux_raw_sys::general::VQUIT as usize; + +/// `VERASE` +pub const VERASE: usize = linux_raw_sys::general::VERASE as usize; + +/// `VKILL` +pub const VKILL: usize = linux_raw_sys::general::VKILL as usize; + +/// `VEOF` +pub const VEOF: usize = linux_raw_sys::general::VEOF as usize; + +/// `VTIME` +pub const VTIME: usize = linux_raw_sys::general::VTIME as usize; + +/// `VMIN` +pub const VMIN: usize = linux_raw_sys::general::VMIN as usize; + +/// `VSWTC` +pub const VSWTC: usize = linux_raw_sys::general::VSWTC as usize; + +/// `VSTART` +pub const VSTART: usize = linux_raw_sys::general::VSTART as usize; + +/// `VSTOP` +pub const VSTOP: usize = linux_raw_sys::general::VSTOP as usize; + +/// `VSUSP` +pub const VSUSP: usize = linux_raw_sys::general::VSUSP as usize; + +/// `VEOL` +pub const VEOL: usize = linux_raw_sys::general::VEOL as usize; + +/// `VREPRINT` +pub const VREPRINT: usize = linux_raw_sys::general::VREPRINT as usize; + +/// `VDISCARD` +pub const VDISCARD: usize = linux_raw_sys::general::VDISCARD as usize; + +/// `VWERASE` +pub const VWERASE: usize = linux_raw_sys::general::VWERASE as usize; + +/// `VLNEXT` +pub const VLNEXT: usize = linux_raw_sys::general::VLNEXT as usize; + +/// `VEOL2` +pub const VEOL2: usize = linux_raw_sys::general::VEOL2 as usize; + +/// `IGNBRK` +pub const IGNBRK: c::c_uint = linux_raw_sys::general::IGNBRK; + +/// `BRKINT` +pub const BRKINT: c::c_uint = linux_raw_sys::general::BRKINT; + +/// `IGNPAR` +pub const IGNPAR: c::c_uint = linux_raw_sys::general::IGNPAR; + +/// `PARMRK` +pub const PARMRK: c::c_uint = linux_raw_sys::general::PARMRK; + +/// `INPCK` +pub const INPCK: c::c_uint = linux_raw_sys::general::INPCK; + +/// `ISTRIP` +pub const ISTRIP: c::c_uint = linux_raw_sys::general::ISTRIP; + +/// `INLCR` +pub const INLCR: c::c_uint = linux_raw_sys::general::INLCR; + +/// `IGNCR` +pub const IGNCR: c::c_uint = linux_raw_sys::general::IGNCR; + +/// `ICRNL` +pub const ICRNL: c::c_uint = linux_raw_sys::general::ICRNL; + +/// `IUCLC` +pub const IUCLC: c::c_uint = linux_raw_sys::general::IUCLC; + +/// `IXON` +pub const IXON: c::c_uint = linux_raw_sys::general::IXON; + +/// `IXANY` +pub const IXANY: c::c_uint = linux_raw_sys::general::IXANY; + +/// `IXOFF` +pub const IXOFF: c::c_uint = linux_raw_sys::general::IXOFF; + +/// `IMAXBEL` +pub const IMAXBEL: c::c_uint = linux_raw_sys::general::IMAXBEL; + +/// `IUTF8` +pub const IUTF8: c::c_uint = linux_raw_sys::general::IUTF8; + +/// `OPOST` +pub const OPOST: c::c_uint = linux_raw_sys::general::OPOST; + +/// `OLCUC` +pub const OLCUC: c::c_uint = linux_raw_sys::general::OLCUC; + +/// `ONLCR` +pub const ONLCR: c::c_uint = linux_raw_sys::general::ONLCR; + +/// `OCRNL` +pub const OCRNL: c::c_uint = linux_raw_sys::general::OCRNL; + +/// `ONOCR` +pub const ONOCR: c::c_uint = linux_raw_sys::general::ONOCR; + +/// `ONLRET` +pub const ONLRET: c::c_uint = linux_raw_sys::general::ONLRET; + +/// `OFILL` +pub const OFILL: c::c_uint = linux_raw_sys::general::OFILL; + +/// `OFDEL` +pub const OFDEL: c::c_uint = linux_raw_sys::general::OFDEL; + +/// `NLDLY` +pub const NLDLY: c::c_uint = linux_raw_sys::general::NLDLY; + +/// `NL0` +pub const NL0: c::c_uint = linux_raw_sys::general::NL0; + +/// `NL1` +pub const NL1: c::c_uint = linux_raw_sys::general::NL1; + +/// `CRDLY` +pub const CRDLY: c::c_uint = linux_raw_sys::general::CRDLY; + +/// `CR0` +pub const CR0: c::c_uint = linux_raw_sys::general::CR0; + +/// `CR1` +pub const CR1: c::c_uint = linux_raw_sys::general::CR1; + +/// `CR2` +pub const CR2: c::c_uint = linux_raw_sys::general::CR2; + +/// `CR3` +pub const CR3: c::c_uint = linux_raw_sys::general::CR3; + +/// `TABDLY` +pub const TABDLY: c::c_uint = linux_raw_sys::general::TABDLY; + +/// `TAB0` +pub const TAB0: c::c_uint = linux_raw_sys::general::TAB0; + +/// `TAB1` +pub const TAB1: c::c_uint = linux_raw_sys::general::TAB1; + +/// `TAB2` +pub const TAB2: c::c_uint = linux_raw_sys::general::TAB2; + +/// `TAB3` +pub const TAB3: c::c_uint = linux_raw_sys::general::TAB3; + +/// `BSDLY` +pub const BSDLY: c::c_uint = linux_raw_sys::general::BSDLY; + +/// `BS0` +pub const BS0: c::c_uint = linux_raw_sys::general::BS0; + +/// `BS1` +pub const BS1: c::c_uint = linux_raw_sys::general::BS1; + +/// `FFDLY` +pub const FFDLY: c::c_uint = linux_raw_sys::general::FFDLY; + +/// `FF0` +pub const FF0: c::c_uint = linux_raw_sys::general::FF0; + +/// `FF1` +pub const FF1: c::c_uint = linux_raw_sys::general::FF1; + +/// `VTDLY` +pub const VTDLY: c::c_uint = linux_raw_sys::general::VTDLY; + +/// `VT0` +pub const VT0: c::c_uint = linux_raw_sys::general::VT0; + +/// `VT1` +pub const VT1: c::c_uint = linux_raw_sys::general::VT1; + +/// `B0` +pub const B0: Speed = linux_raw_sys::general::B0; + +/// `B50` +pub const B50: Speed = linux_raw_sys::general::B50; + +/// `B75` +pub const B75: Speed = linux_raw_sys::general::B75; + +/// `B110` +pub const B110: Speed = linux_raw_sys::general::B110; + +/// `B134` +pub const B134: Speed = linux_raw_sys::general::B134; + +/// `B150` +pub const B150: Speed = linux_raw_sys::general::B150; + +/// `B200` +pub const B200: Speed = linux_raw_sys::general::B200; + +/// `B300` +pub const B300: Speed = linux_raw_sys::general::B300; + +/// `B600` +pub const B600: Speed = linux_raw_sys::general::B600; + +/// `B1200` +pub const B1200: Speed = linux_raw_sys::general::B1200; + +/// `B1800` +pub const B1800: Speed = linux_raw_sys::general::B1800; + +/// `B2400` +pub const B2400: Speed = linux_raw_sys::general::B2400; + +/// `B4800` +pub const B4800: Speed = linux_raw_sys::general::B4800; + +/// `B9600` +pub const B9600: Speed = linux_raw_sys::general::B9600; + +/// `B19200` +pub const B19200: Speed = linux_raw_sys::general::B19200; + +/// `B38400` +pub const B38400: Speed = linux_raw_sys::general::B38400; + +/// `B57600` +pub const B57600: Speed = linux_raw_sys::general::B57600; + +/// `B115200` +pub const B115200: Speed = linux_raw_sys::general::B115200; + +/// `B230400` +pub const B230400: Speed = linux_raw_sys::general::B230400; + +/// `B460800` +pub const B460800: Speed = linux_raw_sys::general::B460800; + +/// `B500000` +pub const B500000: Speed = linux_raw_sys::general::B500000; + +/// `B576000` +pub const B576000: Speed = linux_raw_sys::general::B576000; + +/// `B921600` +pub const B921600: Speed = linux_raw_sys::general::B921600; + +/// `B1000000` +pub const B1000000: Speed = linux_raw_sys::general::B1000000; + +/// `B1152000` +pub const B1152000: Speed = linux_raw_sys::general::B1152000; + +/// `B1500000` +pub const B1500000: Speed = linux_raw_sys::general::B1500000; + +/// `B2000000` +pub const B2000000: Speed = linux_raw_sys::general::B2000000; + +/// `B2500000` +#[cfg(not(any(target_arch = "sparc", target_arch = "sparc64",)))] +pub const B2500000: Speed = linux_raw_sys::general::B2500000; + +/// `B3000000` +#[cfg(not(any(target_arch = "sparc", target_arch = "sparc64",)))] +pub const B3000000: Speed = linux_raw_sys::general::B3000000; + +/// `B3500000` +#[cfg(not(any(target_arch = "sparc", target_arch = "sparc64",)))] +pub const B3500000: Speed = linux_raw_sys::general::B3500000; + +/// `B4000000` +#[cfg(not(any(target_arch = "sparc", target_arch = "sparc64",)))] +pub const B4000000: Speed = linux_raw_sys::general::B4000000; + +/// `CSIZE` +pub const CSIZE: c::c_uint = linux_raw_sys::general::CSIZE; + +/// `CS5` +pub const CS5: c::c_uint = linux_raw_sys::general::CS5; + +/// `CS6` +pub const CS6: c::c_uint = linux_raw_sys::general::CS6; + +/// `CS7` +pub const CS7: c::c_uint = linux_raw_sys::general::CS7; + +/// `CS8` +pub const CS8: c::c_uint = linux_raw_sys::general::CS8; + +/// `CSTOPB` +pub const CSTOPB: c::c_uint = linux_raw_sys::general::CSTOPB; + +/// `CREAD` +pub const CREAD: c::c_uint = linux_raw_sys::general::CREAD; + +/// `PARENB` +pub const PARENB: c::c_uint = linux_raw_sys::general::PARENB; + +/// `PARODD` +pub const PARODD: c::c_uint = linux_raw_sys::general::PARODD; + +/// `HUPCL` +pub const HUPCL: c::c_uint = linux_raw_sys::general::HUPCL; + +/// `CLOCAL` +pub const CLOCAL: c::c_uint = linux_raw_sys::general::CLOCAL; + +/// `ISIG` +pub const ISIG: c::c_uint = linux_raw_sys::general::ISIG; + +/// `ICANON`—A flag for the `c_lflag` field of [`Termios`] indicating +/// canonical mode. +pub const ICANON: Tcflag = linux_raw_sys::general::ICANON; + +/// `ECHO` +pub const ECHO: c::c_uint = linux_raw_sys::general::ECHO; + +/// `ECHOE` +pub const ECHOE: c::c_uint = linux_raw_sys::general::ECHOE; + +/// `ECHOK` +pub const ECHOK: c::c_uint = linux_raw_sys::general::ECHOK; + +/// `ECHONL` +pub const ECHONL: c::c_uint = linux_raw_sys::general::ECHONL; + +/// `NOFLSH` +pub const NOFLSH: c::c_uint = linux_raw_sys::general::NOFLSH; + +/// `TOSTOP` +pub const TOSTOP: c::c_uint = linux_raw_sys::general::TOSTOP; + +/// `IEXTEN` +pub const IEXTEN: c::c_uint = linux_raw_sys::general::IEXTEN; + +/// `EXTA` +pub const EXTA: c::c_uint = linux_raw_sys::general::EXTA; + +/// `EXTB` +pub const EXTB: c::c_uint = linux_raw_sys::general::EXTB; + +/// `CBAUD` +pub const CBAUD: c::c_uint = linux_raw_sys::general::CBAUD; + +/// `CBAUDEX` +pub const CBAUDEX: c::c_uint = linux_raw_sys::general::CBAUDEX; + +/// `CIBAUD` +pub const CIBAUD: c::c_uint = linux_raw_sys::general::CIBAUD; + +/// `CMSPAR` +pub const CMSPAR: c::c_uint = linux_raw_sys::general::CMSPAR; + +/// `CRTSCTS` +pub const CRTSCTS: c::c_uint = linux_raw_sys::general::CRTSCTS; + +/// `XCASE` +pub const XCASE: c::c_uint = linux_raw_sys::general::XCASE; + +/// `ECHOCTL` +pub const ECHOCTL: c::c_uint = linux_raw_sys::general::ECHOCTL; + +/// `ECHOPRT` +pub const ECHOPRT: c::c_uint = linux_raw_sys::general::ECHOPRT; + +/// `ECHOKE` +pub const ECHOKE: c::c_uint = linux_raw_sys::general::ECHOKE; + +/// `FLUSHO` +pub const FLUSHO: c::c_uint = linux_raw_sys::general::FLUSHO; + +/// `PENDIN` +pub const PENDIN: c::c_uint = linux_raw_sys::general::PENDIN; + +/// `EXTPROC` +pub const EXTPROC: c::c_uint = linux_raw_sys::general::EXTPROC; + +/// `XTABS` +pub const XTABS: c::c_uint = linux_raw_sys::general::XTABS; diff --git a/vendor/rustix/src/imp/linux_raw/thread/futex.rs b/vendor/rustix/src/backend/linux_raw/thread/futex.rs index 9e087f9f1..9e087f9f1 100644 --- a/vendor/rustix/src/imp/linux_raw/thread/futex.rs +++ b/vendor/rustix/src/backend/linux_raw/thread/futex.rs diff --git a/vendor/rustix/src/imp/linux_raw/thread/mod.rs b/vendor/rustix/src/backend/linux_raw/thread/mod.rs index 8bb80c33a..8bb80c33a 100644 --- a/vendor/rustix/src/imp/linux_raw/thread/mod.rs +++ b/vendor/rustix/src/backend/linux_raw/thread/mod.rs diff --git a/vendor/rustix/src/backend/linux_raw/thread/syscalls.rs b/vendor/rustix/src/backend/linux_raw/thread/syscalls.rs new file mode 100644 index 000000000..99c632e7e --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/thread/syscalls.rs @@ -0,0 +1,290 @@ +//! linux_raw syscalls supporting `rustix::thread`. +//! +//! # Safety +//! +//! See the `rustix::backend` module documentation for details. +#![allow(unsafe_code)] +#![allow(clippy::undocumented_unsafe_blocks)] + +use super::super::c; +use super::super::conv::{ + by_ref, c_int, c_uint, ret, ret_c_int, ret_usize, ret_usize_infallible, zero, +}; +use crate::fd::BorrowedFd; +use crate::io; +use crate::process::{Pid, RawNonZeroPid}; +use crate::thread::{ClockId, FutexFlags, FutexOperation, NanosleepRelativeResult, Timespec}; +use core::mem::MaybeUninit; +use linux_raw_sys::general::{__kernel_pid_t, __kernel_timespec, TIMER_ABSTIME}; +#[cfg(target_pointer_width = "32")] +use { + core::convert::TryInto, core::ptr, linux_raw_sys::general::timespec as __kernel_old_timespec, +}; + +#[inline] +pub(crate) fn clock_nanosleep_relative( + id: ClockId, + req: &__kernel_timespec, +) -> NanosleepRelativeResult { + #[cfg(target_pointer_width = "32")] + unsafe { + let mut rem = MaybeUninit::<__kernel_timespec>::uninit(); + match ret(syscall!( + __NR_clock_nanosleep_time64, + id, + c_int(0), + by_ref(req), + &mut rem + )) + .or_else(|err| { + // See the comments in `rustix_clock_gettime_via_syscall` about + // emulation. + if err == io::Errno::NOSYS { + clock_nanosleep_relative_old(id, req, &mut rem) + } else { + Err(err) + } + }) { + Ok(()) => NanosleepRelativeResult::Ok, + Err(io::Errno::INTR) => NanosleepRelativeResult::Interrupted(rem.assume_init()), + Err(err) => NanosleepRelativeResult::Err(err), + } + } + #[cfg(target_pointer_width = "64")] + unsafe { + let mut rem = MaybeUninit::<__kernel_timespec>::uninit(); + match ret(syscall!( + __NR_clock_nanosleep, + id, + c_int(0), + by_ref(req), + &mut rem + )) { + Ok(()) => NanosleepRelativeResult::Ok, + Err(io::Errno::INTR) => NanosleepRelativeResult::Interrupted(rem.assume_init()), + Err(err) => NanosleepRelativeResult::Err(err), + } + } +} + +#[cfg(target_pointer_width = "32")] +unsafe fn clock_nanosleep_relative_old( + id: ClockId, + req: &__kernel_timespec, + rem: &mut MaybeUninit<__kernel_timespec>, +) -> io::Result<()> { + let old_req = __kernel_old_timespec { + tv_sec: req.tv_sec.try_into().map_err(|_| io::Errno::INVAL)?, + tv_nsec: req.tv_nsec.try_into().map_err(|_| io::Errno::INVAL)?, + }; + let mut old_rem = MaybeUninit::<__kernel_old_timespec>::uninit(); + ret(syscall!( + __NR_clock_nanosleep, + id, + c_int(0), + by_ref(&old_req), + &mut old_rem + ))?; + let old_rem = old_rem.assume_init(); + // TODO: With Rust 1.55, we can use MaybeUninit::write here. + ptr::write( + rem.as_mut_ptr(), + __kernel_timespec { + tv_sec: old_rem.tv_sec.into(), + tv_nsec: old_rem.tv_nsec.into(), + }, + ); + Ok(()) +} + +#[inline] +pub(crate) fn clock_nanosleep_absolute(id: ClockId, req: &__kernel_timespec) -> io::Result<()> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret(syscall_readonly!( + __NR_clock_nanosleep_time64, + id, + c_uint(TIMER_ABSTIME), + by_ref(req), + zero() + )) + .or_else(|err| { + // See the comments in `rustix_clock_gettime_via_syscall` about + // emulation. + if err == io::Errno::NOSYS { + clock_nanosleep_absolute_old(id, req) + } else { + Err(err) + } + }) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret(syscall_readonly!( + __NR_clock_nanosleep, + id, + c_uint(TIMER_ABSTIME), + by_ref(req), + zero() + )) + } +} + +#[cfg(target_pointer_width = "32")] +unsafe fn clock_nanosleep_absolute_old(id: ClockId, req: &__kernel_timespec) -> io::Result<()> { + let old_req = __kernel_old_timespec { + tv_sec: req.tv_sec.try_into().map_err(|_| io::Errno::INVAL)?, + tv_nsec: req.tv_nsec.try_into().map_err(|_| io::Errno::INVAL)?, + }; + ret(syscall_readonly!( + __NR_clock_nanosleep, + id, + c_int(0), + by_ref(&old_req), + zero() + )) +} + +#[inline] +pub(crate) fn nanosleep(req: &__kernel_timespec) -> NanosleepRelativeResult { + #[cfg(target_pointer_width = "32")] + unsafe { + let mut rem = MaybeUninit::<__kernel_timespec>::uninit(); + match ret(syscall!( + __NR_clock_nanosleep_time64, + ClockId::Realtime, + c_int(0), + by_ref(req), + &mut rem + )) + .or_else(|err| { + // See the comments in `rustix_clock_gettime_via_syscall` about + // emulation. + if err == io::Errno::NOSYS { + nanosleep_old(req, &mut rem) + } else { + Err(err) + } + }) { + Ok(()) => NanosleepRelativeResult::Ok, + Err(io::Errno::INTR) => NanosleepRelativeResult::Interrupted(rem.assume_init()), + Err(err) => NanosleepRelativeResult::Err(err), + } + } + #[cfg(target_pointer_width = "64")] + unsafe { + let mut rem = MaybeUninit::<__kernel_timespec>::uninit(); + match ret(syscall!(__NR_nanosleep, by_ref(req), &mut rem)) { + Ok(()) => NanosleepRelativeResult::Ok, + Err(io::Errno::INTR) => NanosleepRelativeResult::Interrupted(rem.assume_init()), + Err(err) => NanosleepRelativeResult::Err(err), + } + } +} + +#[cfg(target_pointer_width = "32")] +unsafe fn nanosleep_old( + req: &__kernel_timespec, + rem: &mut MaybeUninit<__kernel_timespec>, +) -> io::Result<()> { + let old_req = __kernel_old_timespec { + tv_sec: req.tv_sec.try_into().map_err(|_| io::Errno::INVAL)?, + tv_nsec: req.tv_nsec.try_into().map_err(|_| io::Errno::INVAL)?, + }; + let mut old_rem = MaybeUninit::<__kernel_old_timespec>::uninit(); + ret(syscall!(__NR_nanosleep, by_ref(&old_req), &mut old_rem))?; + let old_rem = old_rem.assume_init(); + // TODO: With Rust 1.55, we can use MaybeUninit::write here. + ptr::write( + rem.as_mut_ptr(), + __kernel_timespec { + tv_sec: old_rem.tv_sec.into(), + tv_nsec: old_rem.tv_nsec.into(), + }, + ); + Ok(()) +} + +#[inline] +pub(crate) fn gettid() -> Pid { + unsafe { + let tid: i32 = ret_usize_infallible(syscall_readonly!(__NR_gettid)) as __kernel_pid_t; + debug_assert_ne!(tid, 0); + Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked(tid as u32)) + } +} + +// TODO: This could be de-multiplexed. +#[inline] +pub(crate) unsafe fn futex( + uaddr: *mut u32, + op: FutexOperation, + flags: FutexFlags, + val: u32, + utime: *const Timespec, + uaddr2: *mut u32, + val3: u32, +) -> io::Result<usize> { + #[cfg(target_pointer_width = "32")] + { + ret_usize(syscall!( + __NR_futex_time64, + uaddr, + (op, flags), + c_uint(val), + utime, + uaddr2, + c_uint(val3) + )) + .or_else(|err| { + // See the comments in `rustix_clock_gettime_via_syscall` about + // emulation. + if err == io::Errno::NOSYS { + futex_old(uaddr, op, flags, val, utime, uaddr2, val3) + } else { + Err(err) + } + }) + } + #[cfg(target_pointer_width = "64")] + ret_usize(syscall!( + __NR_futex, + uaddr, + (op, flags), + c_uint(val), + utime, + uaddr2, + c_uint(val3) + )) +} + +#[cfg(target_pointer_width = "32")] +unsafe fn futex_old( + uaddr: *mut u32, + op: FutexOperation, + flags: FutexFlags, + val: u32, + utime: *const Timespec, + uaddr2: *mut u32, + val3: u32, +) -> io::Result<usize> { + let old_utime = __kernel_old_timespec { + tv_sec: (*utime).tv_sec.try_into().map_err(|_| io::Errno::INVAL)?, + tv_nsec: (*utime).tv_nsec.try_into().map_err(|_| io::Errno::INVAL)?, + }; + ret_usize(syscall!( + __NR_futex, + uaddr, + (op, flags), + c_uint(val), + by_ref(&old_utime), + uaddr2, + c_uint(val3) + )) +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[inline] +pub(crate) fn setns(fd: BorrowedFd, nstype: c::c_int) -> io::Result<c::c_int> { + unsafe { ret_c_int(syscall_readonly!(__NR_setns, fd, c_int(nstype))) } +} diff --git a/vendor/rustix/src/imp/linux_raw/time/mod.rs b/vendor/rustix/src/backend/linux_raw/time/mod.rs index c42592c4f..c42592c4f 100644 --- a/vendor/rustix/src/imp/linux_raw/time/mod.rs +++ b/vendor/rustix/src/backend/linux_raw/time/mod.rs diff --git a/vendor/rustix/src/backend/linux_raw/time/syscalls.rs b/vendor/rustix/src/backend/linux_raw/time/syscalls.rs new file mode 100644 index 000000000..6e73a921b --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/time/syscalls.rs @@ -0,0 +1,229 @@ +//! linux_raw syscalls supporting `rustix::time`. +//! +//! # Safety +//! +//! See the `rustix::backend` module documentation for details. +#![allow(unsafe_code)] +#![allow(clippy::undocumented_unsafe_blocks)] + +#[cfg(feature = "time")] +use super::super::conv::{by_ref, ret_owned_fd}; +use super::super::conv::{ret, ret_infallible}; +use super::types::ClockId; +#[cfg(feature = "time")] +use crate::fd::BorrowedFd; +#[cfg(feature = "time")] +use crate::fd::OwnedFd; +use crate::io; +#[cfg(feature = "time")] +use crate::time::{Itimerspec, TimerfdClockId, TimerfdFlags, TimerfdTimerFlags}; +use core::mem::MaybeUninit; +use linux_raw_sys::general::__kernel_timespec; +#[cfg(feature = "time")] +#[cfg(target_pointer_width = "32")] +use {core::convert::TryInto, linux_raw_sys::general::itimerspec as __kernel_old_itimerspec}; +#[cfg(target_pointer_width = "32")] +use {core::ptr, linux_raw_sys::general::timespec as __kernel_old_timespec}; + +// `clock_gettime` has special optimizations via the vDSO. +#[cfg(feature = "time")] +pub(crate) use super::super::vdso_wrappers::{clock_gettime, clock_gettime_dynamic}; + +#[inline] +pub(crate) fn clock_getres(which_clock: ClockId) -> __kernel_timespec { + #[cfg(target_pointer_width = "32")] + unsafe { + let mut result = MaybeUninit::<__kernel_timespec>::uninit(); + if let Err(err) = ret(syscall!(__NR_clock_getres_time64, which_clock, &mut result)) { + // See the comments in `rustix_clock_gettime_via_syscall` about + // emulation. + debug_assert_eq!(err, io::Errno::NOSYS); + clock_getres_old(which_clock, &mut result); + } + result.assume_init() + } + #[cfg(target_pointer_width = "64")] + unsafe { + let mut result = MaybeUninit::<__kernel_timespec>::uninit(); + ret_infallible(syscall!(__NR_clock_getres, which_clock, &mut result)); + result.assume_init() + } +} + +#[cfg(target_pointer_width = "32")] +unsafe fn clock_getres_old(which_clock: ClockId, result: &mut MaybeUninit<__kernel_timespec>) { + let mut old_result = MaybeUninit::<__kernel_old_timespec>::uninit(); + ret_infallible(syscall!(__NR_clock_getres, which_clock, &mut old_result)); + let old_result = old_result.assume_init(); + // TODO: With Rust 1.55, we can use MaybeUninit::write here. + ptr::write( + result.as_mut_ptr(), + __kernel_timespec { + tv_sec: old_result.tv_sec.into(), + tv_nsec: old_result.tv_nsec.into(), + }, + ); +} + +#[cfg(feature = "time")] +#[inline] +pub(crate) fn timerfd_create(clockid: TimerfdClockId, flags: TimerfdFlags) -> io::Result<OwnedFd> { + unsafe { ret_owned_fd(syscall!(__NR_timerfd_create, clockid, flags)) } +} + +#[cfg(feature = "time")] +#[inline] +pub(crate) fn timerfd_settime( + fd: BorrowedFd<'_>, + flags: TimerfdTimerFlags, + new_value: &Itimerspec, +) -> io::Result<Itimerspec> { + let mut result = MaybeUninit::<Itimerspec>::uninit(); + + #[cfg(target_pointer_width = "64")] + unsafe { + ret(syscall!( + __NR_timerfd_settime, + fd, + flags, + by_ref(new_value), + &mut result + ))?; + Ok(result.assume_init()) + } + + #[cfg(target_pointer_width = "32")] + unsafe { + ret(syscall!( + __NR_timerfd_settime64, + fd, + flags, + by_ref(new_value), + &mut result + )) + .or_else(|err| { + // See the comments in `rustix_clock_gettime_via_syscall` about + // emulation. + if err == io::Errno::NOSYS { + timerfd_settime_old(fd, flags, new_value, &mut result) + } else { + Err(err) + } + })?; + Ok(result.assume_init()) + } +} + +#[cfg(feature = "time")] +#[cfg(target_pointer_width = "32")] +unsafe fn timerfd_settime_old( + fd: BorrowedFd<'_>, + flags: TimerfdTimerFlags, + new_value: &Itimerspec, + result: &mut MaybeUninit<Itimerspec>, +) -> io::Result<()> { + let mut old_result = MaybeUninit::<__kernel_old_itimerspec>::uninit(); + + // Convert `new_value` to the old `__kernel_old_itimerspec` format. + let old_new_value = __kernel_old_itimerspec { + it_interval: __kernel_old_timespec { + tv_sec: new_value + .it_interval + .tv_sec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + tv_nsec: new_value + .it_interval + .tv_nsec + .try_into() + .map_err(|_| io::Errno::INVAL)?, + }, + it_value: __kernel_old_timespec { + tv_sec: new_value + .it_value + .tv_sec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + tv_nsec: new_value + .it_value + .tv_nsec + .try_into() + .map_err(|_| io::Errno::INVAL)?, + }, + }; + ret(syscall!( + __NR_timerfd_settime, + fd, + flags, + by_ref(&old_new_value), + &mut old_result + ))?; + let old_result = old_result.assume_init(); + // TODO: With Rust 1.55, we can use MaybeUninit::write here. + ptr::write( + result.as_mut_ptr(), + Itimerspec { + it_interval: __kernel_timespec { + tv_sec: old_result.it_interval.tv_sec.into(), + tv_nsec: old_result.it_interval.tv_nsec.into(), + }, + it_value: __kernel_timespec { + tv_sec: old_result.it_value.tv_sec.into(), + tv_nsec: old_result.it_value.tv_nsec.into(), + }, + }, + ); + Ok(()) +} + +#[cfg(feature = "time")] +#[inline] +pub(crate) fn timerfd_gettime(fd: BorrowedFd<'_>) -> io::Result<Itimerspec> { + let mut result = MaybeUninit::<Itimerspec>::uninit(); + + #[cfg(target_pointer_width = "64")] + unsafe { + ret(syscall!(__NR_timerfd_gettime, fd, &mut result))?; + Ok(result.assume_init()) + } + + #[cfg(target_pointer_width = "32")] + unsafe { + ret(syscall!(__NR_timerfd_gettime64, fd, &mut result)).or_else(|err| { + // See the comments in `rustix_clock_gettime_via_syscall` about + // emulation. + if err == io::Errno::NOSYS { + timerfd_gettime_old(fd, &mut result) + } else { + Err(err) + } + })?; + Ok(result.assume_init()) + } +} + +#[cfg(feature = "time")] +#[cfg(target_pointer_width = "32")] +unsafe fn timerfd_gettime_old( + fd: BorrowedFd<'_>, + result: &mut MaybeUninit<Itimerspec>, +) -> io::Result<()> { + let mut old_result = MaybeUninit::<__kernel_old_itimerspec>::uninit(); + ret(syscall!(__NR_timerfd_gettime, fd, &mut old_result))?; + let old_result = old_result.assume_init(); + // TODO: With Rust 1.55, we can use MaybeUninit::write here. + ptr::write( + result.as_mut_ptr(), + Itimerspec { + it_interval: __kernel_timespec { + tv_sec: old_result.it_interval.tv_sec.into(), + tv_nsec: old_result.it_interval.tv_nsec.into(), + }, + it_value: __kernel_timespec { + tv_sec: old_result.it_value.tv_sec.into(), + tv_nsec: old_result.it_value.tv_nsec.into(), + }, + }, + ); + Ok(()) +} diff --git a/vendor/rustix/src/imp/linux_raw/time/types.rs b/vendor/rustix/src/backend/linux_raw/time/types.rs index 5a0fcc6f5..5a0fcc6f5 100644 --- a/vendor/rustix/src/imp/linux_raw/time/types.rs +++ b/vendor/rustix/src/backend/linux_raw/time/types.rs diff --git a/vendor/rustix/src/backend/linux_raw/vdso.rs b/vendor/rustix/src/backend/linux_raw/vdso.rs new file mode 100644 index 000000000..da7910b88 --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/vdso.rs @@ -0,0 +1,310 @@ +//! Parse the Linux vDSO. +//! +//! The following code is transliterated from +//! tools/testing/selftests/vDSO/parse_vdso.c in Linux 5.11, which is licensed +//! with Creative Commons Zero License, version 1.0, +//! available at <https://creativecommons.org/publicdomain/zero/1.0/legalcode> +//! +//! # Safety +//! +//! Parsing the vDSO involves a lot of raw pointer manipulation. This +//! implementation follows Linux's reference implementation, and adds several +//! additional safety checks. +#![allow(unsafe_code)] + +use super::c; +use super::elf::*; +use crate::ffi::CStr; +use crate::utils::check_raw_pointer; +use core::ffi::c_void; +use core::mem::size_of; +use core::ptr::{null, null_mut}; + +pub(super) struct Vdso { + // Load information + load_addr: *const Elf_Ehdr, + load_end: *const c_void, // the end of the `PT_LOAD` segment + pv_offset: usize, // recorded paddr - recorded vaddr + + // Symbol table + symtab: *const Elf_Sym, + symstrings: *const u8, + bucket: *const u32, + chain: *const u32, + nbucket: u32, + //nchain: u32, + + // Version table + versym: *const u16, + verdef: *const Elf_Verdef, +} + +// Straight from the ELF specification. +fn elf_hash(name: &CStr) -> u32 { + let mut h: u32 = 0; + for b in name.to_bytes() { + h = (h << 4).wrapping_add(u32::from(*b)); + let g = h & 0xf000_0000; + if g != 0 { + h ^= g >> 24; + } + h &= !g; + } + h +} + +/// Create a `Vdso` value by parsing the vDSO at the `sysinfo_ehdr` address. +fn init_from_sysinfo_ehdr() -> Option<Vdso> { + // Safety: the auxv initialization code does extensive checks to ensure + // that the value we get really is an `AT_SYSINFO_EHDR` value from the + // kernel. + unsafe { + let hdr = super::param::auxv::sysinfo_ehdr(); + + // If the platform doesn't provide a `AT_SYSINFO_EHDR`, we can't locate + // the vDSO. + if hdr.is_null() { + return None; + } + + let mut vdso = Vdso { + load_addr: hdr, + load_end: hdr.cast(), + pv_offset: 0, + symtab: null(), + symstrings: null(), + bucket: null(), + chain: null(), + nbucket: 0, + //nchain: 0, + versym: null(), + verdef: null(), + }; + + let hdr = &*hdr; + let pt = check_raw_pointer::<Elf_Phdr>(vdso.base_plus(hdr.e_phoff)? as *mut _)?.as_ptr(); + let mut dyn_: *const Elf_Dyn = null(); + let mut num_dyn = 0; + + // We need two things from the segment table: the load offset + // and the dynamic table. + let mut found_vaddr = false; + for i in 0..hdr.e_phnum { + let phdr = &*pt.add(i as usize); + if phdr.p_flags & PF_W != 0 { + // Don't trust any vDSO that claims to be loading writable + // segments into memory. + return None; + } + if phdr.p_type == PT_LOAD && !found_vaddr { + // The segment should be readable and executable, because it + // contains the symbol table and the function bodies. + if phdr.p_flags & (PF_R | PF_X) != (PF_R | PF_X) { + return None; + } + found_vaddr = true; + vdso.load_end = vdso.base_plus(phdr.p_offset.checked_add(phdr.p_memsz)?)?; + vdso.pv_offset = phdr.p_offset.wrapping_sub(phdr.p_vaddr); + } else if phdr.p_type == PT_DYNAMIC { + // If `p_offset` is zero, it's more likely that we're looking at memory + // that has been zeroed than that the kernel has somehow aliased the + // `Ehdr` and the `Elf_Dyn` array. + if phdr.p_offset < size_of::<Elf_Ehdr>() { + return None; + } + + dyn_ = check_raw_pointer::<Elf_Dyn>(vdso.base_plus(phdr.p_offset)? as *mut _)? + .as_ptr(); + num_dyn = phdr.p_memsz / size_of::<Elf_Dyn>(); + } else if phdr.p_type == PT_INTERP || phdr.p_type == PT_GNU_RELRO { + // Don't trust any ELF image that has an "interpreter" or that uses + // RELRO, which is likely to be a user ELF image rather and not the + // kernel vDSO. + return None; + } + } + + if !found_vaddr || dyn_.is_null() { + return None; // Failed + } + + // Fish out the useful bits of the dynamic table. + let mut hash: *const u32 = null(); + vdso.symstrings = null(); + vdso.symtab = null(); + vdso.versym = null(); + vdso.verdef = null(); + let mut i = 0; + loop { + if i == num_dyn { + return None; + } + let d = &*dyn_.add(i); + match d.d_tag { + DT_STRTAB => { + vdso.symstrings = + check_raw_pointer::<u8>(vdso.addr_from_elf(d.d_val)? as *mut _)?.as_ptr(); + } + DT_SYMTAB => { + vdso.symtab = + check_raw_pointer::<Elf_Sym>(vdso.addr_from_elf(d.d_val)? as *mut _)? + .as_ptr(); + } + DT_HASH => { + hash = + check_raw_pointer::<u32>(vdso.addr_from_elf(d.d_val)? as *mut _)?.as_ptr(); + } + DT_VERSYM => { + vdso.versym = + check_raw_pointer::<u16>(vdso.addr_from_elf(d.d_val)? as *mut _)?.as_ptr(); + } + DT_VERDEF => { + vdso.verdef = + check_raw_pointer::<Elf_Verdef>(vdso.addr_from_elf(d.d_val)? as *mut _)? + .as_ptr(); + } + DT_SYMENT => { + if d.d_val != size_of::<Elf_Sym>() { + return None; // Failed + } + } + DT_NULL => break, + _ => {} + } + i = i.checked_add(1)?; + } + // The upstream code checks `symstrings`, `symtab`, and `hash` for null; + // here, `check_raw_pointer` has already done that. + + if vdso.verdef.is_null() { + vdso.versym = null(); + } + + // Parse the hash table header. + vdso.nbucket = *hash.add(0); + //vdso.nchain = *hash.add(1); + vdso.bucket = hash.add(2); + vdso.chain = hash.add(vdso.nbucket as usize + 2); + + // That's all we need. + Some(vdso) + } +} + +impl Vdso { + /// Parse the vDSO. + /// + /// Returns `None` if the vDSO can't be located or if it doesn't conform + /// to our expectations. + #[inline] + pub(super) fn new() -> Option<Self> { + init_from_sysinfo_ehdr() + } + + /// Check the version for a symbol. + /// + /// # Safety + /// + /// The raw pointers inside `self` must be valid. + unsafe fn match_version(&self, mut ver: u16, name: &CStr, hash: u32) -> bool { + // This is a helper function to check if the version indexed by + // ver matches name (which hashes to hash). + // + // The version definition table is a mess, and I don't know how + // to do this in better than linear time without allocating memory + // to build an index. I also don't know why the table has + // variable size entries in the first place. + // + // For added fun, I can't find a comprehensible specification of how + // to parse all the weird flags in the table. + // + // So I just parse the whole table every time. + + // First step: find the version definition + ver &= 0x7fff; // Apparently bit 15 means "hidden" + let mut def = self.verdef; + loop { + if (*def).vd_version != VER_DEF_CURRENT { + return false; // Failed + } + + if ((*def).vd_flags & VER_FLG_BASE) == 0 && ((*def).vd_ndx & 0x7fff) == ver { + break; + } + + if (*def).vd_next == 0 { + return false; // No definition. + } + + def = def + .cast::<u8>() + .add((*def).vd_next as usize) + .cast::<Elf_Verdef>(); + } + + // Now figure out whether it matches. + let aux = &*(def.cast::<u8>()) + .add((*def).vd_aux as usize) + .cast::<Elf_Verdaux>(); + (*def).vd_hash == hash + && (name == CStr::from_ptr(self.symstrings.add(aux.vda_name as usize).cast())) + } + + /// Look up a symbol in the vDSO. + pub(super) fn sym(&self, version: &CStr, name: &CStr) -> *mut c::c_void { + let ver_hash = elf_hash(version); + let name_hash = elf_hash(name); + + // Safety: The pointers in `self` must be valid. + unsafe { + let mut chain = *self.bucket.add((name_hash % self.nbucket) as usize); + + while chain != STN_UNDEF { + let sym = &*self.symtab.add(chain as usize); + + // Check for a defined global or weak function w/ right name. + // + // The reference parser in Linux's parse_vdso.c requires + // symbols to have type `STT_FUNC`, but on powerpc64, the vDSO + // uses `STT_NOTYPE`, so allow that too. + if (ELF_ST_TYPE(sym.st_info) != STT_FUNC && + ELF_ST_TYPE(sym.st_info) != STT_NOTYPE) + || (ELF_ST_BIND(sym.st_info) != STB_GLOBAL + && ELF_ST_BIND(sym.st_info) != STB_WEAK) + || sym.st_shndx == SHN_UNDEF + || sym.st_shndx == SHN_ABS + || ELF_ST_VISIBILITY(sym.st_other) != STV_DEFAULT + || (name != CStr::from_ptr(self.symstrings.add(sym.st_name as usize).cast())) + // Check symbol version. + || (!self.versym.is_null() + && !self.match_version(*self.versym.add(chain as usize), version, ver_hash)) + { + chain = *self.chain.add(chain as usize); + continue; + } + + let sum = self.addr_from_elf(sym.st_value).unwrap(); + assert!( + sum as usize >= self.load_addr as usize + && sum as usize <= self.load_end as usize + ); + return sum as *mut c::c_void; + } + } + + null_mut() + } + + /// Add the given address to the vDSO base address. + unsafe fn base_plus(&self, offset: usize) -> Option<*const c_void> { + // Check for overflow. + let _ = (self.load_addr as usize).checked_add(offset)?; + // Add the offset to the base. + Some(self.load_addr.cast::<u8>().add(offset).cast()) + } + + /// Translate an ELF-address-space address into a usable virtual address. + unsafe fn addr_from_elf(&self, elf_addr: usize) -> Option<*const c_void> { + self.base_plus(elf_addr.wrapping_add(self.pv_offset)) + } +} diff --git a/vendor/rustix/src/imp/linux_raw/vdso_wrappers.rs b/vendor/rustix/src/backend/linux_raw/vdso_wrappers.rs index 80c8dbefd..487835314 100644 --- a/vendor/rustix/src/imp/linux_raw/vdso_wrappers.rs +++ b/vendor/rustix/src/backend/linux_raw/vdso_wrappers.rs @@ -49,7 +49,7 @@ pub(crate) fn clock_gettime_dynamic(which_clock: DynamicClockId<'_>) -> io::Resu DynamicClockId::Dynamic(fd) => { // See `FD_TO_CLOCKID` in Linux's `clock_gettime` documentation. - use crate::imp::fd::AsRawFd; + use crate::backend::fd::AsRawFd; const CLOCKFD: i32 = 3; ((!fd.as_raw_fd() << 3) | CLOCKFD) as __kernel_clockid_t } @@ -86,10 +86,10 @@ pub(crate) fn clock_gettime_dynamic(which_clock: DynamicClockId<'_>) -> io::Resu #[cfg(target_arch = "x86")] pub(super) mod x86_via_vdso { use super::{transmute, ArgReg, Relaxed, RetReg, SyscallNumber, A0, A1, A2, A3, A4, A5, R0}; - use crate::imp::arch::asm; + use crate::backend::arch::asm; #[inline] - pub(in crate::imp) unsafe fn syscall0(nr: SyscallNumber<'_>) -> RetReg<R0> { + pub(in crate::backend) unsafe fn syscall0(nr: SyscallNumber<'_>) -> RetReg<R0> { let callee = match transmute(super::SYSCALL.load(Relaxed)) { Some(callee) => callee, None => super::init_syscall(), @@ -98,7 +98,7 @@ pub(super) mod x86_via_vdso { } #[inline] - pub(in crate::imp) unsafe fn syscall1<'a>( + pub(in crate::backend) unsafe fn syscall1<'a>( nr: SyscallNumber<'a>, a0: ArgReg<'a, A0>, ) -> RetReg<R0> { @@ -110,7 +110,7 @@ pub(super) mod x86_via_vdso { } #[inline] - pub(in crate::imp) unsafe fn syscall1_noreturn<'a>( + pub(in crate::backend) unsafe fn syscall1_noreturn<'a>( nr: SyscallNumber<'a>, a0: ArgReg<'a, A0>, ) -> ! { @@ -122,7 +122,7 @@ pub(super) mod x86_via_vdso { } #[inline] - pub(in crate::imp) unsafe fn syscall2<'a>( + pub(in crate::backend) unsafe fn syscall2<'a>( nr: SyscallNumber<'a>, a0: ArgReg<'a, A0>, a1: ArgReg<'a, A1>, @@ -135,7 +135,7 @@ pub(super) mod x86_via_vdso { } #[inline] - pub(in crate::imp) unsafe fn syscall3<'a>( + pub(in crate::backend) unsafe fn syscall3<'a>( nr: SyscallNumber<'a>, a0: ArgReg<'a, A0>, a1: ArgReg<'a, A1>, @@ -149,7 +149,7 @@ pub(super) mod x86_via_vdso { } #[inline] - pub(in crate::imp) unsafe fn syscall4<'a>( + pub(in crate::backend) unsafe fn syscall4<'a>( nr: SyscallNumber<'a>, a0: ArgReg<'a, A0>, a1: ArgReg<'a, A1>, @@ -164,7 +164,7 @@ pub(super) mod x86_via_vdso { } #[inline] - pub(in crate::imp) unsafe fn syscall5<'a>( + pub(in crate::backend) unsafe fn syscall5<'a>( nr: SyscallNumber<'a>, a0: ArgReg<'a, A0>, a1: ArgReg<'a, A1>, @@ -180,7 +180,7 @@ pub(super) mod x86_via_vdso { } #[inline] - pub(in crate::imp) unsafe fn syscall6<'a>( + pub(in crate::backend) unsafe fn syscall6<'a>( nr: SyscallNumber<'a>, a0: ArgReg<'a, A0>, a1: ArgReg<'a, A1>, @@ -198,7 +198,7 @@ pub(super) mod x86_via_vdso { // With the indirect call, it isn't meaningful to do a separate // `_readonly` optimization. - pub(in crate::imp) use { + pub(in crate::backend) use { syscall0 as syscall0_readonly, syscall1 as syscall1_readonly, syscall2 as syscall2_readonly, syscall3 as syscall3_readonly, syscall4 as syscall4_readonly, syscall5 as syscall5_readonly, @@ -214,6 +214,7 @@ type ClockGettimeType = unsafe extern "C" fn(c::c_int, *mut Timespec) -> c::c_in #[cfg(target_arch = "x86")] pub(super) type SyscallType = unsafe extern "C" fn(); +/// Initialize `CLOCK_GETTIME` and return its value. fn init_clock_gettime() -> ClockGettimeType { init(); // Safety: Load the function address from static storage that we @@ -221,6 +222,7 @@ fn init_clock_gettime() -> ClockGettimeType { unsafe { transmute(CLOCK_GETTIME.load(Relaxed)) } } +/// Initialize `SYSCALL` and return its value. #[cfg(target_arch = "x86")] fn init_syscall() -> SyscallType { init(); @@ -242,7 +244,7 @@ unsafe extern "C" fn rustix_clock_gettime_via_syscall( ) -> c::c_int { match _rustix_clock_gettime_via_syscall(clockid, res) { Ok(()) => 0, - Err(e) => e.raw_os_error().wrapping_neg(), + Err(err) => err.raw_os_error().wrapping_neg(), } } |