summaryrefslogtreecommitdiff
path: root/vendor/rustix/src/backend/linux_raw
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/rustix/src/backend/linux_raw')
-rw-r--r--vendor/rustix/src/backend/linux_raw/arch/aarch64.rs269
-rw-r--r--vendor/rustix/src/backend/linux_raw/arch/arm.rs266
-rw-r--r--vendor/rustix/src/backend/linux_raw/arch/mips.rs544
-rw-r--r--vendor/rustix/src/backend/linux_raw/arch/mips32r6.rs544
-rw-r--r--vendor/rustix/src/backend/linux_raw/arch/mips64.rs467
-rw-r--r--vendor/rustix/src/backend/linux_raw/arch/mips64r6.rs471
-rw-r--r--vendor/rustix/src/backend/linux_raw/arch/mod.rs321
-rw-r--r--vendor/rustix/src/backend/linux_raw/arch/powerpc.rs414
-rw-r--r--vendor/rustix/src/backend/linux_raw/arch/powerpc64.rs414
-rw-r--r--vendor/rustix/src/backend/linux_raw/arch/riscv64.rs266
-rw-r--r--vendor/rustix/src/backend/linux_raw/arch/s390x.rs288
-rw-r--r--vendor/rustix/src/backend/linux_raw/arch/thumb.rs323
-rw-r--r--vendor/rustix/src/backend/linux_raw/arch/x86.rs492
-rw-r--r--vendor/rustix/src/backend/linux_raw/arch/x86_64.rs294
-rw-r--r--vendor/rustix/src/backend/linux_raw/c.rs385
-rw-r--r--vendor/rustix/src/backend/linux_raw/conv.rs1021
-rw-r--r--vendor/rustix/src/backend/linux_raw/event/epoll.rs74
-rw-r--r--vendor/rustix/src/backend/linux_raw/event/mod.rs4
-rw-r--r--vendor/rustix/src/backend/linux_raw/event/poll_fd.rs98
-rw-r--r--vendor/rustix/src/backend/linux_raw/event/syscalls.rs358
-rw-r--r--vendor/rustix/src/backend/linux_raw/event/types.rs21
-rw-r--r--vendor/rustix/src/backend/linux_raw/fs/dir.rs373
-rw-r--r--vendor/rustix/src/backend/linux_raw/fs/inotify.rs124
-rw-r--r--vendor/rustix/src/backend/linux_raw/fs/makedev.rs19
-rw-r--r--vendor/rustix/src/backend/linux_raw/fs/mod.rs13
-rw-r--r--vendor/rustix/src/backend/linux_raw/fs/syscalls.rs1722
-rw-r--r--vendor/rustix/src/backend/linux_raw/fs/types.rs848
-rw-r--r--vendor/rustix/src/backend/linux_raw/io/errno.rs552
-rw-r--r--vendor/rustix/src/backend/linux_raw/io/mod.rs3
-rw-r--r--vendor/rustix/src/backend/linux_raw/io/syscalls.rs364
-rw-r--r--vendor/rustix/src/backend/linux_raw/io/types.rs57
-rw-r--r--vendor/rustix/src/backend/linux_raw/io_uring/mod.rs1
-rw-r--r--vendor/rustix/src/backend/linux_raw/io_uring/syscalls.rs79
-rw-r--r--vendor/rustix/src/backend/linux_raw/mm/mod.rs2
-rw-r--r--vendor/rustix/src/backend/linux_raw/mm/syscalls.rs239
-rw-r--r--vendor/rustix/src/backend/linux_raw/mm/types.rs297
-rw-r--r--vendor/rustix/src/backend/linux_raw/mod.rs112
-rw-r--r--vendor/rustix/src/backend/linux_raw/mount/mod.rs2
-rw-r--r--vendor/rustix/src/backend/linux_raw/mount/syscalls.rs237
-rw-r--r--vendor/rustix/src/backend/linux_raw/mount/types.rs335
-rw-r--r--vendor/rustix/src/backend/linux_raw/net/addr.rs300
-rw-r--r--vendor/rustix/src/backend/linux_raw/net/mod.rs8
-rw-r--r--vendor/rustix/src/backend/linux_raw/net/msghdr.rs125
-rw-r--r--vendor/rustix/src/backend/linux_raw/net/netdevice.rs70
-rw-r--r--vendor/rustix/src/backend/linux_raw/net/read_sockaddr.rs155
-rw-r--r--vendor/rustix/src/backend/linux_raw/net/send_recv.rs87
-rw-r--r--vendor/rustix/src/backend/linux_raw/net/sockopt.rs1099
-rw-r--r--vendor/rustix/src/backend/linux_raw/net/syscalls.rs731
-rw-r--r--vendor/rustix/src/backend/linux_raw/net/write_sockaddr.rs31
-rw-r--r--vendor/rustix/src/backend/linux_raw/param/auxv.rs583
-rw-r--r--vendor/rustix/src/backend/linux_raw/param/init.rs175
-rw-r--r--vendor/rustix/src/backend/linux_raw/param/libc_auxv.rs198
-rw-r--r--vendor/rustix/src/backend/linux_raw/param/mod.rs15
-rw-r--r--vendor/rustix/src/backend/linux_raw/pid/mod.rs1
-rw-r--r--vendor/rustix/src/backend/linux_raw/pid/syscalls.rs18
-rw-r--r--vendor/rustix/src/backend/linux_raw/pipe/mod.rs2
-rw-r--r--vendor/rustix/src/backend/linux_raw/pipe/syscalls.rs135
-rw-r--r--vendor/rustix/src/backend/linux_raw/pipe/types.rs85
-rw-r--r--vendor/rustix/src/backend/linux_raw/prctl/mod.rs1
-rw-r--r--vendor/rustix/src/backend/linux_raw/prctl/syscalls.rs21
-rw-r--r--vendor/rustix/src/backend/linux_raw/process/mod.rs3
-rw-r--r--vendor/rustix/src/backend/linux_raw/process/syscalls.rs560
-rw-r--r--vendor/rustix/src/backend/linux_raw/process/types.rs43
-rw-r--r--vendor/rustix/src/backend/linux_raw/process/wait.rs123
-rw-r--r--vendor/rustix/src/backend/linux_raw/pty/mod.rs1
-rw-r--r--vendor/rustix/src/backend/linux_raw/pty/syscalls.rs43
-rw-r--r--vendor/rustix/src/backend/linux_raw/rand/mod.rs2
-rw-r--r--vendor/rustix/src/backend/linux_raw/rand/syscalls.rs15
-rw-r--r--vendor/rustix/src/backend/linux_raw/rand/types.rs20
-rw-r--r--vendor/rustix/src/backend/linux_raw/reg.rs259
-rw-r--r--vendor/rustix/src/backend/linux_raw/runtime/mod.rs2
-rw-r--r--vendor/rustix/src/backend/linux_raw/runtime/syscalls.rs346
-rw-r--r--vendor/rustix/src/backend/linux_raw/runtime/tls.rs7
-rw-r--r--vendor/rustix/src/backend/linux_raw/shm/mod.rs2
-rw-r--r--vendor/rustix/src/backend/linux_raw/shm/syscalls.rs46
-rw-r--r--vendor/rustix/src/backend/linux_raw/shm/types.rs30
-rw-r--r--vendor/rustix/src/backend/linux_raw/system/mod.rs2
-rw-r--r--vendor/rustix/src/backend/linux_raw/system/syscalls.rs91
-rw-r--r--vendor/rustix/src/backend/linux_raw/system/types.rs39
-rw-r--r--vendor/rustix/src/backend/linux_raw/termios/mod.rs2
-rw-r--r--vendor/rustix/src/backend/linux_raw/termios/syscalls.rs425
-rw-r--r--vendor/rustix/src/backend/linux_raw/termios/types.rs13
-rw-r--r--vendor/rustix/src/backend/linux_raw/thread/cpu_set.rs51
-rw-r--r--vendor/rustix/src/backend/linux_raw/thread/futex.rs89
-rw-r--r--vendor/rustix/src/backend/linux_raw/thread/mod.rs4
-rw-r--r--vendor/rustix/src/backend/linux_raw/thread/syscalls.rs549
-rw-r--r--vendor/rustix/src/backend/linux_raw/thread/types.rs62
-rw-r--r--vendor/rustix/src/backend/linux_raw/time/mod.rs2
-rw-r--r--vendor/rustix/src/backend/linux_raw/time/syscalls.rs238
-rw-r--r--vendor/rustix/src/backend/linux_raw/time/types.rs93
-rw-r--r--vendor/rustix/src/backend/linux_raw/ugid/mod.rs1
-rw-r--r--vendor/rustix/src/backend/linux_raw/ugid/syscalls.rs70
-rw-r--r--vendor/rustix/src/backend/linux_raw/vdso.rs545
-rw-r--r--vendor/rustix/src/backend/linux_raw/vdso_wrappers.rs623
94 files changed, 20954 insertions, 0 deletions
diff --git a/vendor/rustix/src/backend/linux_raw/arch/aarch64.rs b/vendor/rustix/src/backend/linux_raw/arch/aarch64.rs
new file mode 100644
index 00000000..4f9e52af
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/arch/aarch64.rs
@@ -0,0 +1,269 @@
+//! aarch64 Linux system calls.
+
+use crate::backend::reg::{
+ ArgReg, FromAsm, RetReg, SyscallNumber, ToAsm as _, 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::backend) unsafe fn syscall0_readonly(nr: SyscallNumber<'_>) -> RetReg<R0> {
+ let r0;
+ asm!(
+ "svc 0",
+ in("x8") nr.to_asm(),
+ lateout("x0") 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("x8") nr.to_asm(),
+ inlateout("x0") 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("x8") nr.to_asm(),
+ inlateout("x0") 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",
+ "brk #0x1",
+ in("x8") nr.to_asm(),
+ in("x0") a0.to_asm(),
+ options(nostack, 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("x8") nr.to_asm(),
+ inlateout("x0") a0.to_asm() => r0,
+ in("x1") 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("x8") nr.to_asm(),
+ inlateout("x0") a0.to_asm() => r0,
+ in("x1") 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("x8") nr.to_asm(),
+ inlateout("x0") a0.to_asm() => r0,
+ in("x1") a1.to_asm(),
+ in("x2") 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("x8") nr.to_asm(),
+ inlateout("x0") a0.to_asm() => r0,
+ in("x1") a1.to_asm(),
+ in("x2") 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("x8") nr.to_asm(),
+ inlateout("x0") a0.to_asm() => r0,
+ in("x1") a1.to_asm(),
+ in("x2") a2.to_asm(),
+ in("x3") 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("x8") nr.to_asm(),
+ inlateout("x0") a0.to_asm() => r0,
+ in("x1") a1.to_asm(),
+ in("x2") a2.to_asm(),
+ in("x3") 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("x8") nr.to_asm(),
+ inlateout("x0") a0.to_asm() => r0,
+ in("x1") a1.to_asm(),
+ in("x2") a2.to_asm(),
+ in("x3") a3.to_asm(),
+ in("x4") 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("x8") nr.to_asm(),
+ inlateout("x0") a0.to_asm() => r0,
+ in("x1") a1.to_asm(),
+ in("x2") a2.to_asm(),
+ in("x3") a3.to_asm(),
+ in("x4") 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("x8") nr.to_asm(),
+ inlateout("x0") a0.to_asm() => r0,
+ in("x1") a1.to_asm(),
+ in("x2") a2.to_asm(),
+ in("x3") a3.to_asm(),
+ in("x4") a4.to_asm(),
+ in("x5") 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("x8") nr.to_asm(),
+ inlateout("x0") a0.to_asm() => r0,
+ in("x1") a1.to_asm(),
+ in("x2") a2.to_asm(),
+ in("x3") a3.to_asm(),
+ in("x4") a4.to_asm(),
+ in("x5") a5.to_asm(),
+ options(nostack, preserves_flags, readonly)
+ );
+ FromAsm::from_asm(r0)
+}
diff --git a/vendor/rustix/src/backend/linux_raw/arch/arm.rs b/vendor/rustix/src/backend/linux_raw/arch/arm.rs
new file mode 100644
index 00000000..4317154f
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/arch/arm.rs
@@ -0,0 +1,266 @@
+//! arm Linux system calls.
+
+use crate::backend::reg::{
+ ArgReg, FromAsm, RetReg, SyscallNumber, ToAsm as _, 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",
+ "udf #16",
+ in("r7") nr.to_asm(),
+ in("r0") a0.to_asm(),
+ options(nostack, 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/backend/linux_raw/arch/mips.rs b/vendor/rustix/src/backend/linux_raw/arch/mips.rs
new file mode 100644
index 00000000..eb66e261
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/arch/mips.rs
@@ -0,0 +1,544 @@
+//! mipsel Linux system calls.
+//!
+//! On mipsel, Linux indicates success or failure using `$a3` rather
+//! than by returning a negative error code as most other architectures do.
+//!
+//! 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::backend::reg::{
+ ArgReg, FromAsm, RetReg, SyscallNumber, ToAsm as _, A0, A1, A2, A3, A4, A5, A6, R0,
+};
+use core::arch::asm;
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall0_readonly(nr: SyscallNumber) -> RetReg<R0> {
+ let x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ lateout("$7" /*$a3*/) err,
+ lateout("$8" /*$t0*/) _,
+ lateout("$9" /*$t1*/) _,
+ lateout("$10" /*$t2*/) _,
+ lateout("$11" /*$t3*/) _,
+ lateout("$12" /*$t4*/) _,
+ lateout("$13" /*$t5*/) _,
+ lateout("$14" /*$t6*/) _,
+ lateout("$15" /*$t7*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags, readonly)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> RetReg<R0> {
+ let x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ lateout("$7" /*$a3*/) err,
+ lateout("$8" /*$t0*/) _,
+ lateout("$9" /*$t1*/) _,
+ lateout("$10" /*$t2*/) _,
+ lateout("$11" /*$t3*/) _,
+ lateout("$12" /*$t4*/) _,
+ lateout("$13" /*$t5*/) _,
+ lateout("$14" /*$t6*/) _,
+ lateout("$15" /*$t7*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall1_readonly(
+ nr: SyscallNumber<'_>,
+ a0: ArgReg<'_, A0>,
+) -> RetReg<R0> {
+ let x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ lateout("$7" /*$a3*/) err,
+ lateout("$8" /*$t0*/) _,
+ lateout("$9" /*$t1*/) _,
+ lateout("$10" /*$t2*/) _,
+ lateout("$11" /*$t3*/) _,
+ lateout("$12" /*$t4*/) _,
+ lateout("$13" /*$t5*/) _,
+ lateout("$14" /*$t6*/) _,
+ lateout("$15" /*$t7*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags, readonly)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> ! {
+ asm!(
+ "syscall",
+ "teq $0,$0",
+ in("$2" /*$v0*/) nr.to_asm(),
+ in("$4" /*$a0*/) a0.to_asm(),
+ options(nostack, noreturn)
+ )
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall2(
+ nr: SyscallNumber<'_>,
+ a0: ArgReg<'_, A0>,
+ a1: ArgReg<'_, A1>,
+) -> RetReg<R0> {
+ let x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ lateout("$7" /*$a3*/) err,
+ lateout("$8" /*$t0*/) _,
+ lateout("$9" /*$t1*/) _,
+ lateout("$10" /*$t2*/) _,
+ lateout("$11" /*$t3*/) _,
+ lateout("$12" /*$t4*/) _,
+ lateout("$13" /*$t5*/) _,
+ lateout("$14" /*$t6*/) _,
+ lateout("$15" /*$t7*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall2_readonly(
+ nr: SyscallNumber<'_>,
+ a0: ArgReg<'_, A0>,
+ a1: ArgReg<'_, A1>,
+) -> RetReg<R0> {
+ let x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ lateout("$7" /*$a3*/) err,
+ lateout("$8" /*$t0*/) _,
+ lateout("$9" /*$t1*/) _,
+ lateout("$10" /*$t2*/) _,
+ lateout("$11" /*$t3*/) _,
+ lateout("$12" /*$t4*/) _,
+ lateout("$13" /*$t5*/) _,
+ lateout("$14" /*$t6*/) _,
+ lateout("$15" /*$t7*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags, readonly)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall3(
+ nr: SyscallNumber<'_>,
+ a0: ArgReg<'_, A0>,
+ a1: ArgReg<'_, A1>,
+ a2: ArgReg<'_, A2>,
+) -> RetReg<R0> {
+ let x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ in("$6" /*$a2*/) a2.to_asm(),
+ lateout("$7" /*$a3*/) err,
+ lateout("$8" /*$t0*/) _,
+ lateout("$9" /*$t1*/) _,
+ lateout("$10" /*$t2*/) _,
+ lateout("$11" /*$t3*/) _,
+ lateout("$12" /*$t4*/) _,
+ lateout("$13" /*$t5*/) _,
+ lateout("$14" /*$t6*/) _,
+ lateout("$15" /*$t7*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall3_readonly(
+ nr: SyscallNumber<'_>,
+ a0: ArgReg<'_, A0>,
+ a1: ArgReg<'_, A1>,
+ a2: ArgReg<'_, A2>,
+) -> RetReg<R0> {
+ let x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ in("$6" /*$a2*/) a2.to_asm(),
+ lateout("$7" /*$a3*/) err,
+ lateout("$8" /*$t0*/) _,
+ lateout("$9" /*$t1*/) _,
+ lateout("$10" /*$t2*/) _,
+ lateout("$11" /*$t3*/) _,
+ lateout("$12" /*$t4*/) _,
+ lateout("$13" /*$t5*/) _,
+ lateout("$14" /*$t6*/) _,
+ lateout("$15" /*$t7*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags, readonly)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[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 x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ in("$6" /*$a2*/) a2.to_asm(),
+ inlateout("$7" /*$a3*/) a3.to_asm() => err,
+ lateout("$8" /*$t0*/) _,
+ lateout("$9" /*$t1*/) _,
+ lateout("$10" /*$t2*/) _,
+ lateout("$11" /*$t3*/) _,
+ lateout("$12" /*$t4*/) _,
+ lateout("$13" /*$t5*/) _,
+ lateout("$14" /*$t6*/) _,
+ lateout("$15" /*$t7*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[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 x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ in("$6" /*$a2*/) a2.to_asm(),
+ inlateout("$7" /*$a3*/) a3.to_asm() => err,
+ lateout("$8" /*$t0*/) _,
+ lateout("$9" /*$t1*/) _,
+ lateout("$10" /*$t2*/) _,
+ lateout("$11" /*$t3*/) _,
+ lateout("$12" /*$t4*/) _,
+ lateout("$13" /*$t5*/) _,
+ lateout("$14" /*$t6*/) _,
+ lateout("$15" /*$t7*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags, readonly)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[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 x0;
+ let err: usize;
+ asm!(
+ ".set noat",
+ "subu $sp, 32",
+ "sw {}, 16($sp)",
+ "syscall",
+ "addu $sp, 32",
+ ".set at",
+ in(reg) a4.to_asm(),
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ in("$6" /*$a2*/) a2.to_asm(),
+ inlateout("$7" /*$a3*/) a3.to_asm() => err,
+ lateout("$8" /*$t0*/) _,
+ lateout("$9" /*$t1*/) _,
+ lateout("$10" /*$t2*/) _,
+ lateout("$11" /*$t3*/) _,
+ lateout("$12" /*$t4*/) _,
+ lateout("$13" /*$t5*/) _,
+ lateout("$14" /*$t6*/) _,
+ lateout("$15" /*$t7*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(preserves_flags)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[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 x0;
+ let err: usize;
+ asm!(
+ ".set noat",
+ "subu $sp, 32",
+ "sw {}, 16($sp)",
+ "syscall",
+ "addu $sp, 32",
+ ".set at",
+ in(reg) a4.to_asm(),
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ in("$6" /*$a2*/) a2.to_asm(),
+ inlateout("$7" /*$a3*/) a3.to_asm() => err,
+ lateout("$8" /*$t0*/) _,
+ lateout("$9" /*$t1*/) _,
+ lateout("$10" /*$t2*/) _,
+ lateout("$11" /*$t3*/) _,
+ lateout("$12" /*$t4*/) _,
+ lateout("$13" /*$t5*/) _,
+ lateout("$14" /*$t6*/) _,
+ lateout("$15" /*$t7*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(preserves_flags, readonly)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[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 x0;
+ let err: usize;
+ asm!(
+ ".set noat",
+ "subu $sp, 32",
+ "sw {}, 16($sp)",
+ "sw {}, 20($sp)",
+ "syscall",
+ "addu $sp, 32",
+ ".set at",
+ in(reg) a4.to_asm(),
+ in(reg) a5.to_asm(),
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ in("$6" /*$a2*/) a2.to_asm(),
+ inlateout("$7" /*$a3*/) a3.to_asm() => err,
+ lateout("$8" /*$t0*/) _,
+ lateout("$9" /*$t1*/) _,
+ lateout("$10" /*$t2*/) _,
+ lateout("$11" /*$t3*/) _,
+ lateout("$12" /*$t4*/) _,
+ lateout("$13" /*$t5*/) _,
+ lateout("$14" /*$t6*/) _,
+ lateout("$15" /*$t7*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(preserves_flags)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[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 x0;
+ let err: usize;
+ asm!(
+ ".set noat",
+ "subu $sp, 32",
+ "sw {}, 16($sp)",
+ "sw {}, 20($sp)",
+ "syscall",
+ "addu $sp, 32",
+ ".set at",
+ in(reg) a4.to_asm(),
+ in(reg) a5.to_asm(),
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ in("$6" /*$a2*/) a2.to_asm(),
+ inlateout("$7" /*$a3*/) a3.to_asm() => err,
+ lateout("$8" /*$t0*/) _,
+ lateout("$9" /*$t1*/) _,
+ lateout("$10" /*$t2*/) _,
+ lateout("$11" /*$t3*/) _,
+ lateout("$12" /*$t4*/) _,
+ lateout("$13" /*$t5*/) _,
+ lateout("$14" /*$t6*/) _,
+ lateout("$15" /*$t7*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(preserves_flags, readonly)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall7_readonly(
+ nr: SyscallNumber<'_>,
+ a0: ArgReg<'_, A0>,
+ a1: ArgReg<'_, A1>,
+ a2: ArgReg<'_, A2>,
+ a3: ArgReg<'_, A3>,
+ a4: ArgReg<'_, A4>,
+ a5: ArgReg<'_, A5>,
+ a6: ArgReg<'_, A6>,
+) -> RetReg<R0> {
+ let x0;
+ let err: usize;
+ asm!(
+ ".set noat",
+ "subu $sp, 32",
+ "sw {}, 16($sp)",
+ "sw {}, 20($sp)",
+ "sw {}, 24($sp)",
+ "syscall",
+ "addu $sp, 32",
+ ".set at",
+ in(reg) a4.to_asm(),
+ in(reg) a5.to_asm(),
+ in(reg) a6.to_asm(),
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ in("$6" /*$a2*/) a2.to_asm(),
+ inlateout("$7" /*$a3*/) a3.to_asm() => err,
+ lateout("$8" /*$t0*/) _,
+ lateout("$9" /*$t1*/) _,
+ lateout("$10" /*$t2*/) _,
+ lateout("$11" /*$t3*/) _,
+ lateout("$12" /*$t4*/) _,
+ lateout("$13" /*$t5*/) _,
+ lateout("$14" /*$t6*/) _,
+ lateout("$15" /*$t7*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(preserves_flags, readonly)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
diff --git a/vendor/rustix/src/backend/linux_raw/arch/mips32r6.rs b/vendor/rustix/src/backend/linux_raw/arch/mips32r6.rs
new file mode 100644
index 00000000..d273a968
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/arch/mips32r6.rs
@@ -0,0 +1,544 @@
+//! mipsisa32r6el Linux system calls.
+//!
+//! On mipsisa32r6el, Linux indicates success or failure using `$a3` rather
+//! than by returning a negative error code as most other architectures do.
+//!
+//! 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::backend::reg::{
+ ArgReg, FromAsm, RetReg, SyscallNumber, ToAsm as _, A0, A1, A2, A3, A4, A5, A6, R0,
+};
+use core::arch::asm;
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall0_readonly(nr: SyscallNumber) -> RetReg<R0> {
+ let x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ lateout("$7" /*$a3*/) err,
+ lateout("$8" /*$t0*/) _,
+ lateout("$9" /*$t1*/) _,
+ lateout("$10" /*$t2*/) _,
+ lateout("$11" /*$t3*/) _,
+ lateout("$12" /*$t4*/) _,
+ lateout("$13" /*$t5*/) _,
+ lateout("$14" /*$t6*/) _,
+ lateout("$15" /*$t7*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags, readonly)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> RetReg<R0> {
+ let x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ lateout("$7" /*$a3*/) err,
+ lateout("$8" /*$t0*/) _,
+ lateout("$9" /*$t1*/) _,
+ lateout("$10" /*$t2*/) _,
+ lateout("$11" /*$t3*/) _,
+ lateout("$12" /*$t4*/) _,
+ lateout("$13" /*$t5*/) _,
+ lateout("$14" /*$t6*/) _,
+ lateout("$15" /*$t7*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall1_readonly(
+ nr: SyscallNumber<'_>,
+ a0: ArgReg<'_, A0>,
+) -> RetReg<R0> {
+ let x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ lateout("$7" /*$a3*/) err,
+ lateout("$8" /*$t0*/) _,
+ lateout("$9" /*$t1*/) _,
+ lateout("$10" /*$t2*/) _,
+ lateout("$11" /*$t3*/) _,
+ lateout("$12" /*$t4*/) _,
+ lateout("$13" /*$t5*/) _,
+ lateout("$14" /*$t6*/) _,
+ lateout("$15" /*$t7*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags, readonly)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> ! {
+ asm!(
+ "syscall",
+ "teq $0,$0",
+ in("$2" /*$v0*/) nr.to_asm(),
+ in("$4" /*$a0*/) a0.to_asm(),
+ options(nostack, noreturn)
+ )
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall2(
+ nr: SyscallNumber<'_>,
+ a0: ArgReg<'_, A0>,
+ a1: ArgReg<'_, A1>,
+) -> RetReg<R0> {
+ let x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ lateout("$7" /*$a3*/) err,
+ lateout("$8" /*$t0*/) _,
+ lateout("$9" /*$t1*/) _,
+ lateout("$10" /*$t2*/) _,
+ lateout("$11" /*$t3*/) _,
+ lateout("$12" /*$t4*/) _,
+ lateout("$13" /*$t5*/) _,
+ lateout("$14" /*$t6*/) _,
+ lateout("$15" /*$t7*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall2_readonly(
+ nr: SyscallNumber<'_>,
+ a0: ArgReg<'_, A0>,
+ a1: ArgReg<'_, A1>,
+) -> RetReg<R0> {
+ let x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ lateout("$7" /*$a3*/) err,
+ lateout("$8" /*$t0*/) _,
+ lateout("$9" /*$t1*/) _,
+ lateout("$10" /*$t2*/) _,
+ lateout("$11" /*$t3*/) _,
+ lateout("$12" /*$t4*/) _,
+ lateout("$13" /*$t5*/) _,
+ lateout("$14" /*$t6*/) _,
+ lateout("$15" /*$t7*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags, readonly)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall3(
+ nr: SyscallNumber<'_>,
+ a0: ArgReg<'_, A0>,
+ a1: ArgReg<'_, A1>,
+ a2: ArgReg<'_, A2>,
+) -> RetReg<R0> {
+ let x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ in("$6" /*$a2*/) a2.to_asm(),
+ lateout("$7" /*$a3*/) err,
+ lateout("$8" /*$t0*/) _,
+ lateout("$9" /*$t1*/) _,
+ lateout("$10" /*$t2*/) _,
+ lateout("$11" /*$t3*/) _,
+ lateout("$12" /*$t4*/) _,
+ lateout("$13" /*$t5*/) _,
+ lateout("$14" /*$t6*/) _,
+ lateout("$15" /*$t7*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall3_readonly(
+ nr: SyscallNumber<'_>,
+ a0: ArgReg<'_, A0>,
+ a1: ArgReg<'_, A1>,
+ a2: ArgReg<'_, A2>,
+) -> RetReg<R0> {
+ let x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ in("$6" /*$a2*/) a2.to_asm(),
+ lateout("$7" /*$a3*/) err,
+ lateout("$8" /*$t0*/) _,
+ lateout("$9" /*$t1*/) _,
+ lateout("$10" /*$t2*/) _,
+ lateout("$11" /*$t3*/) _,
+ lateout("$12" /*$t4*/) _,
+ lateout("$13" /*$t5*/) _,
+ lateout("$14" /*$t6*/) _,
+ lateout("$15" /*$t7*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags, readonly)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[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 x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ in("$6" /*$a2*/) a2.to_asm(),
+ inlateout("$7" /*$a3*/) a3.to_asm() => err,
+ lateout("$8" /*$t0*/) _,
+ lateout("$9" /*$t1*/) _,
+ lateout("$10" /*$t2*/) _,
+ lateout("$11" /*$t3*/) _,
+ lateout("$12" /*$t4*/) _,
+ lateout("$13" /*$t5*/) _,
+ lateout("$14" /*$t6*/) _,
+ lateout("$15" /*$t7*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[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 x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ in("$6" /*$a2*/) a2.to_asm(),
+ inlateout("$7" /*$a3*/) a3.to_asm() => err,
+ lateout("$8" /*$t0*/) _,
+ lateout("$9" /*$t1*/) _,
+ lateout("$10" /*$t2*/) _,
+ lateout("$11" /*$t3*/) _,
+ lateout("$12" /*$t4*/) _,
+ lateout("$13" /*$t5*/) _,
+ lateout("$14" /*$t6*/) _,
+ lateout("$15" /*$t7*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags, readonly)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[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 x0;
+ let err: usize;
+ asm!(
+ ".set noat",
+ "subu $sp, 32",
+ "sw {}, 16($sp)",
+ "syscall",
+ "addu $sp, 32",
+ ".set at",
+ in(reg) a4.to_asm(),
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ in("$6" /*$a2*/) a2.to_asm(),
+ inlateout("$7" /*$a3*/) a3.to_asm() => err,
+ lateout("$8" /*$t0*/) _,
+ lateout("$9" /*$t1*/) _,
+ lateout("$10" /*$t2*/) _,
+ lateout("$11" /*$t3*/) _,
+ lateout("$12" /*$t4*/) _,
+ lateout("$13" /*$t5*/) _,
+ lateout("$14" /*$t6*/) _,
+ lateout("$15" /*$t7*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(preserves_flags)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[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 x0;
+ let err: usize;
+ asm!(
+ ".set noat",
+ "subu $sp, 32",
+ "sw {}, 16($sp)",
+ "syscall",
+ "addu $sp, 32",
+ ".set at",
+ in(reg) a4.to_asm(),
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ in("$6" /*$a2*/) a2.to_asm(),
+ inlateout("$7" /*$a3*/) a3.to_asm() => err,
+ lateout("$8" /*$t0*/) _,
+ lateout("$9" /*$t1*/) _,
+ lateout("$10" /*$t2*/) _,
+ lateout("$11" /*$t3*/) _,
+ lateout("$12" /*$t4*/) _,
+ lateout("$13" /*$t5*/) _,
+ lateout("$14" /*$t6*/) _,
+ lateout("$15" /*$t7*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(preserves_flags, readonly)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[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 x0;
+ let err: usize;
+ asm!(
+ ".set noat",
+ "subu $sp, 32",
+ "sw {}, 16($sp)",
+ "sw {}, 20($sp)",
+ "syscall",
+ "addu $sp, 32",
+ ".set at",
+ in(reg) a4.to_asm(),
+ in(reg) a5.to_asm(),
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ in("$6" /*$a2*/) a2.to_asm(),
+ inlateout("$7" /*$a3*/) a3.to_asm() => err,
+ lateout("$8" /*$t0*/) _,
+ lateout("$9" /*$t1*/) _,
+ lateout("$10" /*$t2*/) _,
+ lateout("$11" /*$t3*/) _,
+ lateout("$12" /*$t4*/) _,
+ lateout("$13" /*$t5*/) _,
+ lateout("$14" /*$t6*/) _,
+ lateout("$15" /*$t7*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(preserves_flags)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[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 x0;
+ let err: usize;
+ asm!(
+ ".set noat",
+ "subu $sp, 32",
+ "sw {}, 16($sp)",
+ "sw {}, 20($sp)",
+ "syscall",
+ "addu $sp, 32",
+ ".set at",
+ in(reg) a4.to_asm(),
+ in(reg) a5.to_asm(),
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ in("$6" /*$a2*/) a2.to_asm(),
+ inlateout("$7" /*$a3*/) a3.to_asm() => err,
+ lateout("$8" /*$t0*/) _,
+ lateout("$9" /*$t1*/) _,
+ lateout("$10" /*$t2*/) _,
+ lateout("$11" /*$t3*/) _,
+ lateout("$12" /*$t4*/) _,
+ lateout("$13" /*$t5*/) _,
+ lateout("$14" /*$t6*/) _,
+ lateout("$15" /*$t7*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(preserves_flags, readonly)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall7_readonly(
+ nr: SyscallNumber<'_>,
+ a0: ArgReg<'_, A0>,
+ a1: ArgReg<'_, A1>,
+ a2: ArgReg<'_, A2>,
+ a3: ArgReg<'_, A3>,
+ a4: ArgReg<'_, A4>,
+ a5: ArgReg<'_, A5>,
+ a6: ArgReg<'_, A6>,
+) -> RetReg<R0> {
+ let x0;
+ let err: usize;
+ asm!(
+ ".set noat",
+ "subu $sp, 32",
+ "sw {}, 16($sp)",
+ "sw {}, 20($sp)",
+ "sw {}, 24($sp)",
+ "syscall",
+ "addu $sp, 32",
+ ".set at",
+ in(reg) a4.to_asm(),
+ in(reg) a5.to_asm(),
+ in(reg) a6.to_asm(),
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ in("$6" /*$a2*/) a2.to_asm(),
+ inlateout("$7" /*$a3*/) a3.to_asm() => err,
+ lateout("$8" /*$t0*/) _,
+ lateout("$9" /*$t1*/) _,
+ lateout("$10" /*$t2*/) _,
+ lateout("$11" /*$t3*/) _,
+ lateout("$12" /*$t4*/) _,
+ lateout("$13" /*$t5*/) _,
+ lateout("$14" /*$t6*/) _,
+ lateout("$15" /*$t7*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(preserves_flags, readonly)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
diff --git a/vendor/rustix/src/backend/linux_raw/arch/mips64.rs b/vendor/rustix/src/backend/linux_raw/arch/mips64.rs
new file mode 100644
index 00000000..821812f2
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/arch/mips64.rs
@@ -0,0 +1,467 @@
+//! mips64el Linux system calls.
+//!
+//! On mips64el, Linux indicates success or failure using `$a3` (`$7`) rather
+//! than by returning a negative error code as most other architectures do.
+//!
+//! 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::backend::reg::{
+ ArgReg, FromAsm, RetReg, SyscallNumber, ToAsm as _, 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 x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ lateout("$7" /*$a3*/) err,
+ lateout("$8" /*$a4*/) _,
+ lateout("$9" /*$a5*/) _,
+ lateout("$10" /*$a6*/) _,
+ lateout("$11" /*$a7*/) _,
+ lateout("$12" /*$t0*/) _,
+ lateout("$13" /*$t1*/) _,
+ lateout("$14" /*$t2*/) _,
+ lateout("$15" /*$t3*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags, readonly)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> RetReg<R0> {
+ let x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ lateout("$7" /*$a3*/) err,
+ lateout("$8" /*$a4*/) _,
+ lateout("$9" /*$a5*/) _,
+ lateout("$10" /*$a6*/) _,
+ lateout("$11" /*$a7*/) _,
+ lateout("$12" /*$t0*/) _,
+ lateout("$13" /*$t1*/) _,
+ lateout("$14" /*$t2*/) _,
+ lateout("$15" /*$t3*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall1_readonly(
+ nr: SyscallNumber<'_>,
+ a0: ArgReg<'_, A0>,
+) -> RetReg<R0> {
+ let x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ lateout("$7" /*$a3*/) err,
+ lateout("$8" /*$a4*/) _,
+ lateout("$9" /*$a5*/) _,
+ lateout("$10" /*$a6*/) _,
+ lateout("$11" /*$a7*/) _,
+ lateout("$12" /*$t0*/) _,
+ lateout("$13" /*$t1*/) _,
+ lateout("$14" /*$t2*/) _,
+ lateout("$15" /*$t3*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags, readonly)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> ! {
+ asm!(
+ "syscall",
+ "teq $0,$0",
+ in("$2" /*$v0*/) nr.to_asm(),
+ in("$4" /*$a0*/) a0.to_asm(),
+ options(nostack, noreturn)
+ )
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall2(
+ nr: SyscallNumber<'_>,
+ a0: ArgReg<'_, A0>,
+ a1: ArgReg<'_, A1>,
+) -> RetReg<R0> {
+ let x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ lateout("$7" /*$a3*/) err,
+ lateout("$8" /*$a4*/) _,
+ lateout("$9" /*$a5*/) _,
+ lateout("$10" /*$a6*/) _,
+ lateout("$11" /*$a7*/) _,
+ lateout("$12" /*$t0*/) _,
+ lateout("$13" /*$t1*/) _,
+ lateout("$14" /*$t2*/) _,
+ lateout("$15" /*$t3*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall2_readonly(
+ nr: SyscallNumber<'_>,
+ a0: ArgReg<'_, A0>,
+ a1: ArgReg<'_, A1>,
+) -> RetReg<R0> {
+ let x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ lateout("$7" /*$a3*/) err,
+ lateout("$8" /*$a4*/) _,
+ lateout("$9" /*$a5*/) _,
+ lateout("$10" /*$a6*/) _,
+ lateout("$11" /*$a7*/) _,
+ lateout("$12" /*$t0*/) _,
+ lateout("$13" /*$t1*/) _,
+ lateout("$14" /*$t2*/) _,
+ lateout("$15" /*$t3*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags, readonly)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall3(
+ nr: SyscallNumber<'_>,
+ a0: ArgReg<'_, A0>,
+ a1: ArgReg<'_, A1>,
+ a2: ArgReg<'_, A2>,
+) -> RetReg<R0> {
+ let x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ in("$6" /*$a2*/) a2.to_asm(),
+ lateout("$7" /*$a3*/) err,
+ lateout("$8" /*$a4*/) _,
+ lateout("$9" /*$a5*/) _,
+ lateout("$10" /*$a6*/) _,
+ lateout("$11" /*$a7*/) _,
+ lateout("$12" /*$t0*/) _,
+ lateout("$13" /*$t1*/) _,
+ lateout("$14" /*$t2*/) _,
+ lateout("$15" /*$t3*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall3_readonly(
+ nr: SyscallNumber<'_>,
+ a0: ArgReg<'_, A0>,
+ a1: ArgReg<'_, A1>,
+ a2: ArgReg<'_, A2>,
+) -> RetReg<R0> {
+ let x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ in("$6" /*$a2*/) a2.to_asm(),
+ lateout("$7" /*$a3*/) err,
+ lateout("$8" /*$a4*/) _,
+ lateout("$9" /*$a5*/) _,
+ lateout("$10" /*$a6*/) _,
+ lateout("$11" /*$a7*/) _,
+ lateout("$12" /*$t0*/) _,
+ lateout("$13" /*$t1*/) _,
+ lateout("$14" /*$t2*/) _,
+ lateout("$15" /*$t3*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags, readonly)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[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 x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ in("$6" /*$a2*/) a2.to_asm(),
+ inlateout("$7" /*$a3*/) a3.to_asm() => err,
+ lateout("$8" /*$a4*/) _,
+ lateout("$9" /*$a5*/) _,
+ lateout("$10" /*$a6*/) _,
+ lateout("$11" /*$a7*/) _,
+ lateout("$12" /*$t0*/) _,
+ lateout("$13" /*$t1*/) _,
+ lateout("$14" /*$t2*/) _,
+ lateout("$15" /*$t3*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[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 x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ in("$6" /*$a2*/) a2.to_asm(),
+ inlateout("$7" /*$a3*/) a3.to_asm() => err,
+ lateout("$8" /*$a4*/) _,
+ lateout("$9" /*$a5*/) _,
+ lateout("$10" /*$a6*/) _,
+ lateout("$11" /*$a7*/) _,
+ lateout("$12" /*$t0*/) _,
+ lateout("$13" /*$t1*/) _,
+ lateout("$14" /*$t2*/) _,
+ lateout("$15" /*$t3*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags, readonly)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[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 x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ in("$6" /*$a2*/) a2.to_asm(),
+ inlateout("$7" /*$a3*/) a3.to_asm() => err,
+ inlateout("$8" /*$a4*/) a4.to_asm() => _,
+ lateout("$9" /*$a5*/) _,
+ lateout("$10" /*$a6*/) _,
+ lateout("$11" /*$a7*/) _,
+ lateout("$12" /*$t0*/) _,
+ lateout("$13" /*$t1*/) _,
+ lateout("$14" /*$t2*/) _,
+ lateout("$15" /*$t3*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[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 x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ in("$6" /*$a2*/) a2.to_asm(),
+ inlateout("$7" /*$a3*/) a3.to_asm() => err,
+ inlateout("$8" /*$a4*/) a4.to_asm() => _,
+ lateout("$9" /*$a5*/) _,
+ lateout("$10" /*$a6*/) _,
+ lateout("$11" /*$a7*/) _,
+ lateout("$12" /*$t0*/) _,
+ lateout("$13" /*$t1*/) _,
+ lateout("$14" /*$t2*/) _,
+ lateout("$15" /*$t3*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags, readonly)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[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 x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ in("$6" /*$a2*/) a2.to_asm(),
+ inlateout("$7" /*$a3*/) a3.to_asm() => err,
+ inlateout("$8" /*$a4*/) a4.to_asm() => _,
+ inlateout("$9" /*$a5*/) a5.to_asm() => _,
+ lateout("$10" /*$a6*/) _,
+ lateout("$11" /*$a7*/) _,
+ lateout("$12" /*$t0*/) _,
+ lateout("$13" /*$t1*/) _,
+ lateout("$14" /*$t2*/) _,
+ lateout("$15" /*$t3*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[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 x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ in("$6" /*$a2*/) a2.to_asm(),
+ inlateout("$7" /*$a3*/) a3.to_asm() => err,
+ inlateout("$8" /*$a4*/) a4.to_asm() => _,
+ inlateout("$9" /*$a5*/) a5.to_asm() => _,
+ lateout("$10" /*$a6*/) _,
+ lateout("$11" /*$a7*/) _,
+ lateout("$12" /*$t0*/) _,
+ lateout("$13" /*$t1*/) _,
+ lateout("$14" /*$t2*/) _,
+ lateout("$15" /*$t3*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags, readonly)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
diff --git a/vendor/rustix/src/backend/linux_raw/arch/mips64r6.rs b/vendor/rustix/src/backend/linux_raw/arch/mips64r6.rs
new file mode 100644
index 00000000..2a3cf564
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/arch/mips64r6.rs
@@ -0,0 +1,471 @@
+//! mipsisa64r6el Linux system calls.
+//!
+//! On mipsisa64r6el, Linux indicates success or failure using `$a3` (`$7`)
+//! rather than by returning a negative error code as most other architectures
+//! do.
+//!
+//! MIPS-family platforms have a special calling convention for `__NR_pipe`,
+//! however we use `__NR_pipe2` instead to avoid having to implement it.
+//!
+//! MIPS R6 inline assembly currently doesn't differ from MIPS, because no
+//! explicit call of R6-only or R2-only instructions exist here.
+
+use crate::backend::reg::{
+ ArgReg, FromAsm, RetReg, SyscallNumber, ToAsm as _, 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 x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ lateout("$7" /*$a3*/) err,
+ lateout("$8" /*$a4*/) _,
+ lateout("$9" /*$a5*/) _,
+ lateout("$10" /*$a6*/) _,
+ lateout("$11" /*$a7*/) _,
+ lateout("$12" /*$t0*/) _,
+ lateout("$13" /*$t1*/) _,
+ lateout("$14" /*$t2*/) _,
+ lateout("$15" /*$t3*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags, readonly)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> RetReg<R0> {
+ let x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ lateout("$7" /*$a3*/) err,
+ lateout("$8" /*$a4*/) _,
+ lateout("$9" /*$a5*/) _,
+ lateout("$10" /*$a6*/) _,
+ lateout("$11" /*$a7*/) _,
+ lateout("$12" /*$t0*/) _,
+ lateout("$13" /*$t1*/) _,
+ lateout("$14" /*$t2*/) _,
+ lateout("$15" /*$t3*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall1_readonly(
+ nr: SyscallNumber<'_>,
+ a0: ArgReg<'_, A0>,
+) -> RetReg<R0> {
+ let x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ lateout("$7" /*$a3*/) err,
+ lateout("$8" /*$a4*/) _,
+ lateout("$9" /*$a5*/) _,
+ lateout("$10" /*$a6*/) _,
+ lateout("$11" /*$a7*/) _,
+ lateout("$12" /*$t0*/) _,
+ lateout("$13" /*$t1*/) _,
+ lateout("$14" /*$t2*/) _,
+ lateout("$15" /*$t3*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags, readonly)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> ! {
+ asm!(
+ "syscall",
+ "teq $0,$0",
+ in("$2" /*$v0*/) nr.to_asm(),
+ in("$4" /*$a0*/) a0.to_asm(),
+ options(nostack, noreturn)
+ )
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall2(
+ nr: SyscallNumber<'_>,
+ a0: ArgReg<'_, A0>,
+ a1: ArgReg<'_, A1>,
+) -> RetReg<R0> {
+ let x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ lateout("$7" /*$a3*/) err,
+ lateout("$8" /*$a4*/) _,
+ lateout("$9" /*$a5*/) _,
+ lateout("$10" /*$a6*/) _,
+ lateout("$11" /*$a7*/) _,
+ lateout("$12" /*$t0*/) _,
+ lateout("$13" /*$t1*/) _,
+ lateout("$14" /*$t2*/) _,
+ lateout("$15" /*$t3*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall2_readonly(
+ nr: SyscallNumber<'_>,
+ a0: ArgReg<'_, A0>,
+ a1: ArgReg<'_, A1>,
+) -> RetReg<R0> {
+ let x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ lateout("$7" /*$a3*/) err,
+ lateout("$8" /*$a4*/) _,
+ lateout("$9" /*$a5*/) _,
+ lateout("$10" /*$a6*/) _,
+ lateout("$11" /*$a7*/) _,
+ lateout("$12" /*$t0*/) _,
+ lateout("$13" /*$t1*/) _,
+ lateout("$14" /*$t2*/) _,
+ lateout("$15" /*$t3*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags, readonly)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall3(
+ nr: SyscallNumber<'_>,
+ a0: ArgReg<'_, A0>,
+ a1: ArgReg<'_, A1>,
+ a2: ArgReg<'_, A2>,
+) -> RetReg<R0> {
+ let x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ in("$6" /*$a2*/) a2.to_asm(),
+ lateout("$7" /*$a3*/) err,
+ lateout("$8" /*$a4*/) _,
+ lateout("$9" /*$a5*/) _,
+ lateout("$10" /*$a6*/) _,
+ lateout("$11" /*$a7*/) _,
+ lateout("$12" /*$t0*/) _,
+ lateout("$13" /*$t1*/) _,
+ lateout("$14" /*$t2*/) _,
+ lateout("$15" /*$t3*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall3_readonly(
+ nr: SyscallNumber<'_>,
+ a0: ArgReg<'_, A0>,
+ a1: ArgReg<'_, A1>,
+ a2: ArgReg<'_, A2>,
+) -> RetReg<R0> {
+ let x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ in("$6" /*$a2*/) a2.to_asm(),
+ lateout("$7" /*$a3*/) err,
+ lateout("$8" /*$a4*/) _,
+ lateout("$9" /*$a5*/) _,
+ lateout("$10" /*$a6*/) _,
+ lateout("$11" /*$a7*/) _,
+ lateout("$12" /*$t0*/) _,
+ lateout("$13" /*$t1*/) _,
+ lateout("$14" /*$t2*/) _,
+ lateout("$15" /*$t3*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags, readonly)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[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 x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ in("$6" /*$a2*/) a2.to_asm(),
+ inlateout("$7" /*$a3*/) a3.to_asm() => err,
+ lateout("$8" /*$a4*/) _,
+ lateout("$9" /*$a5*/) _,
+ lateout("$10" /*$a6*/) _,
+ lateout("$11" /*$a7*/) _,
+ lateout("$12" /*$t0*/) _,
+ lateout("$13" /*$t1*/) _,
+ lateout("$14" /*$t2*/) _,
+ lateout("$15" /*$t3*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[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 x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ in("$6" /*$a2*/) a2.to_asm(),
+ inlateout("$7" /*$a3*/) a3.to_asm() => err,
+ lateout("$8" /*$a4*/) _,
+ lateout("$9" /*$a5*/) _,
+ lateout("$10" /*$a6*/) _,
+ lateout("$11" /*$a7*/) _,
+ lateout("$12" /*$t0*/) _,
+ lateout("$13" /*$t1*/) _,
+ lateout("$14" /*$t2*/) _,
+ lateout("$15" /*$t3*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags, readonly)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[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 x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ in("$6" /*$a2*/) a2.to_asm(),
+ inlateout("$7" /*$a3*/) a3.to_asm() => err,
+ inlateout("$8" /*$a4*/) a4.to_asm() => _,
+ lateout("$9" /*$a5*/) _,
+ lateout("$10" /*$a6*/) _,
+ lateout("$11" /*$a7*/) _,
+ lateout("$12" /*$t0*/) _,
+ lateout("$13" /*$t1*/) _,
+ lateout("$14" /*$t2*/) _,
+ lateout("$15" /*$t3*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[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 x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ in("$6" /*$a2*/) a2.to_asm(),
+ inlateout("$7" /*$a3*/) a3.to_asm() => err,
+ inlateout("$8" /*$a4*/) a4.to_asm() => _,
+ lateout("$9" /*$a5*/) _,
+ lateout("$10" /*$a6*/) _,
+ lateout("$11" /*$a7*/) _,
+ lateout("$12" /*$t0*/) _,
+ lateout("$13" /*$t1*/) _,
+ lateout("$14" /*$t2*/) _,
+ lateout("$15" /*$t3*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags, readonly)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[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 x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ in("$6" /*$a2*/) a2.to_asm(),
+ inlateout("$7" /*$a3*/) a3.to_asm() => err,
+ inlateout("$8" /*$a4*/) a4.to_asm() => _,
+ inlateout("$9" /*$a5*/) a5.to_asm() => _,
+ lateout("$10" /*$a6*/) _,
+ lateout("$11" /*$a7*/) _,
+ lateout("$12" /*$t0*/) _,
+ lateout("$13" /*$t1*/) _,
+ lateout("$14" /*$t2*/) _,
+ lateout("$15" /*$t3*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
+
+#[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 x0;
+ let err: usize;
+ asm!(
+ "syscall",
+ inlateout("$2" /*$v0*/) nr.to_asm() => x0,
+ in("$4" /*$a0*/) a0.to_asm(),
+ in("$5" /*$a1*/) a1.to_asm(),
+ in("$6" /*$a2*/) a2.to_asm(),
+ inlateout("$7" /*$a3*/) a3.to_asm() => err,
+ inlateout("$8" /*$a4*/) a4.to_asm() => _,
+ inlateout("$9" /*$a5*/) a5.to_asm() => _,
+ lateout("$10" /*$a6*/) _,
+ lateout("$11" /*$a7*/) _,
+ lateout("$12" /*$t0*/) _,
+ lateout("$13" /*$t1*/) _,
+ lateout("$14" /*$t2*/) _,
+ lateout("$15" /*$t3*/) _,
+ lateout("$24" /*$t8*/) _,
+ lateout("$25" /*$t9*/) _,
+ options(nostack, preserves_flags, readonly)
+ );
+ FromAsm::from_asm(if err != 0 {
+ (x0 as usize).wrapping_neg() as *mut _
+ } else {
+ x0
+ })
+}
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 00000000..8d675adb
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/arch/mod.rs
@@ -0,0 +1,321 @@
+//! Architecture-specific syscall code.
+//!
+//! This module also has a `choose` submodule which chooses a scheme and is
+//! what most of the `rustix` syscalls use.
+//!
+//! 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.
+//!
+//! The calling conventions for Linux syscalls are [documented here].
+//!
+//! [documented here]: https://man7.org/linux/man-pages/man2/syscall.2.html
+//!
+//! # Safety
+//!
+//! This contains the inline `asm` statements performing the 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)]
+
+// These functions always use the machine's syscall instruction, even when it
+// isn't the fastest option available.
+#[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 = "mips32r6", path = "mips32r6.rs")]
+#[cfg_attr(target_arch = "mips64", path = "mips64.rs")]
+#[cfg_attr(target_arch = "mips64r6", path = "mips64r6.rs")]
+#[cfg_attr(target_arch = "powerpc", path = "powerpc.rs")]
+#[cfg_attr(target_arch = "powerpc64", path = "powerpc64.rs")]
+#[cfg_attr(target_arch = "riscv64", path = "riscv64.rs")]
+#[cfg_attr(target_arch = "s390x", path = "s390x.rs")]
+#[cfg_attr(target_arch = "x86", path = "x86.rs")]
+#[cfg_attr(target_arch = "x86_64", path = "x86_64.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 = "mips32r6",
+ target_arch = "mips64",
+ target_arch = "mips64r6",
+ target_arch = "powerpc",
+ target_arch = "powerpc64",
+ target_arch = "riscv64",
+ target_arch = "s390x",
+ 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 to invoke a syscall that always uses direct assembly, rather than the
+// vDSO. Useful when still finding the vDSO.
+#[allow(unused_macros)]
+macro_rules! syscall_always_asm {
+ ($nr:ident) => {
+ $crate::backend::arch::asm::syscall0($crate::backend::reg::nr(linux_raw_sys::general::$nr))
+ };
+
+ ($nr:ident, $a0:expr) => {
+ $crate::backend::arch::asm::syscall1(
+ $crate::backend::reg::nr(linux_raw_sys::general::$nr),
+ $a0.into(),
+ )
+ };
+
+ ($nr:ident, $a0:expr, $a1:expr) => {
+ $crate::backend::arch::asm::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::asm::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::asm::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::asm::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::asm::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::asm::syscall7(
+ $crate::backend::reg::nr(linux_raw_sys::general::$nr),
+ $a0.into(),
+ $a1.into(),
+ $a2.into(),
+ $a3.into(),
+ $a4.into(),
+ $a5.into(),
+ $a6.into(),
+ )
+ };
+}
+
+/// Like `syscall`, but adds the `readonly` attribute to the inline asm, which
+/// indicates that the syscall does not mutate any memory.
+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(),
+ )
+ };
+}
+
+/// Like `syscall`, but indicates that the syscall does not return.
+#[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/backend/linux_raw/arch/powerpc.rs b/vendor/rustix/src/backend/linux_raw/arch/powerpc.rs
new file mode 100644
index 00000000..481b49f4
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/arch/powerpc.rs
@@ -0,0 +1,414 @@
+//! powerpc Linux system calls.
+//!
+//! On powerpc, Linux indicates success or failure using `cr0.SO` rather
+//! than by returning a negative error code as most other architectures do. In
+//! theory we could immediately translate this into a `Result`, and it'd save a
+//! few branches. And in theory we could have specialized sequences for use
+//! with syscalls that are known to never fail. However, those would require
+//! more extensive changes in rustix's platform-independent code. For now, we
+//! check the flag and negate the error value to make PowerPC look like other
+//! architectures.
+
+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!(
+ "sc",
+ "bns 0f",
+ "neg 3, 3",
+ "0:",
+ inlateout("r0") nr.to_asm() => _,
+ lateout("r3") r0,
+ lateout("r4") _,
+ lateout("r5") _,
+ lateout("r6") _,
+ lateout("r7") _,
+ lateout("r8") _,
+ lateout("r9") _,
+ lateout("r10") _,
+ lateout("r11") _,
+ lateout("r12") _,
+ lateout("cr0") _,
+ 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!(
+ "sc",
+ "bns 0f",
+ "neg 3, 3",
+ "0:",
+ inlateout("r0") nr.to_asm() => _,
+ inlateout("r3") a0.to_asm() => r0,
+ lateout("r4") _,
+ lateout("r5") _,
+ lateout("r6") _,
+ lateout("r7") _,
+ lateout("r8") _,
+ lateout("r9") _,
+ lateout("r10") _,
+ lateout("r11") _,
+ lateout("r12") _,
+ lateout("cr0") _,
+ 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!(
+ "sc",
+ "bns 0f",
+ "neg 3, 3",
+ "0:",
+ inlateout("r0") nr.to_asm() => _,
+ inlateout("r3") a0.to_asm() => r0,
+ lateout("r4") _,
+ lateout("r5") _,
+ lateout("r6") _,
+ lateout("r7") _,
+ lateout("r8") _,
+ lateout("r9") _,
+ lateout("r10") _,
+ lateout("r11") _,
+ lateout("r12") _,
+ lateout("cr0") _,
+ options(nostack, preserves_flags, readonly)
+ );
+ FromAsm::from_asm(r0)
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> ! {
+ asm!(
+ "sc",
+ "trap",
+ in("r0") nr.to_asm(),
+ in("r3") a0.to_asm(),
+ options(nostack, noreturn)
+ )
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall2(
+ nr: SyscallNumber<'_>,
+ a0: ArgReg<'_, A0>,
+ a1: ArgReg<'_, A1>,
+) -> RetReg<R0> {
+ let r0;
+ asm!(
+ "sc",
+ "bns 0f",
+ "neg 3, 3",
+ "0:",
+ inlateout("r0") nr.to_asm() => _,
+ inlateout("r3") a0.to_asm() => r0,
+ inlateout("r4") a1.to_asm() => _,
+ lateout("r5") _,
+ lateout("r6") _,
+ lateout("r7") _,
+ lateout("r8") _,
+ lateout("r9") _,
+ lateout("r10") _,
+ lateout("r11") _,
+ lateout("r12") _,
+ lateout("cr0") _,
+ 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!(
+ "sc",
+ "bns 0f",
+ "neg 3, 3",
+ "0:",
+ inlateout("r0") nr.to_asm() => _,
+ inlateout("r3") a0.to_asm() => r0,
+ inlateout("r4") a1.to_asm() => _,
+ lateout("r5") _,
+ lateout("r6") _,
+ lateout("r7") _,
+ lateout("r8") _,
+ lateout("r9") _,
+ lateout("r10") _,
+ lateout("r11") _,
+ lateout("r12") _,
+ lateout("cr0") _,
+ 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!(
+ "sc",
+ "bns 0f",
+ "neg 3, 3",
+ "0:",
+ inlateout("r0") nr.to_asm() => _,
+ inlateout("r3") a0.to_asm() => r0,
+ inlateout("r4") a1.to_asm() => _,
+ inlateout("r5") a2.to_asm() => _,
+ lateout("r6") _,
+ lateout("r7") _,
+ lateout("r8") _,
+ lateout("r9") _,
+ lateout("r10") _,
+ lateout("r11") _,
+ lateout("r12") _,
+ lateout("cr0") _,
+ 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!(
+ "sc",
+ "bns 0f",
+ "neg 3, 3",
+ "0:",
+ inlateout("r0") nr.to_asm() => _,
+ inlateout("r3") a0.to_asm() => r0,
+ inlateout("r4") a1.to_asm() => _,
+ inlateout("r5") a2.to_asm() => _,
+ lateout("r6") _,
+ lateout("r7") _,
+ lateout("r8") _,
+ lateout("r9") _,
+ lateout("r10") _,
+ lateout("r11") _,
+ lateout("r12") _,
+ lateout("cr0") _,
+ 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!(
+ "sc",
+ "bns 0f",
+ "neg 3, 3",
+ "0:",
+ inlateout("r0") nr.to_asm() => _,
+ inlateout("r3") a0.to_asm() => r0,
+ inlateout("r4") a1.to_asm() => _,
+ inlateout("r5") a2.to_asm() => _,
+ inlateout("r6") a3.to_asm() => _,
+ lateout("r7") _,
+ lateout("r8") _,
+ lateout("r9") _,
+ lateout("r10") _,
+ lateout("r11") _,
+ lateout("r12") _,
+ lateout("cr0") _,
+ 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!(
+ "sc",
+ "bns 0f",
+ "neg 3, 3",
+ "0:",
+ inlateout("r0") nr.to_asm() => _,
+ inlateout("r3") a0.to_asm() => r0,
+ inlateout("r4") a1.to_asm() => _,
+ inlateout("r5") a2.to_asm() => _,
+ inlateout("r6") a3.to_asm() => _,
+ lateout("r7") _,
+ lateout("r8") _,
+ lateout("r9") _,
+ lateout("r10") _,
+ lateout("r11") _,
+ lateout("r12") _,
+ lateout("cr0") _,
+ 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!(
+ "sc",
+ "bns 0f",
+ "neg 3, 3",
+ "0:",
+ inlateout("r0") nr.to_asm() => _,
+ inlateout("r3") a0.to_asm() => r0,
+ inlateout("r4") a1.to_asm() => _,
+ inlateout("r5") a2.to_asm() => _,
+ inlateout("r6") a3.to_asm() => _,
+ inlateout("r7") a4.to_asm() => _,
+ lateout("r8") _,
+ lateout("r9") _,
+ lateout("r10") _,
+ lateout("r11") _,
+ lateout("r12") _,
+ lateout("cr0") _,
+ 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!(
+ "sc",
+ "bns 0f",
+ "neg 3, 3",
+ "0:",
+ inlateout("r0") nr.to_asm() => _,
+ inlateout("r3") a0.to_asm() => r0,
+ inlateout("r4") a1.to_asm() => _,
+ inlateout("r5") a2.to_asm() => _,
+ inlateout("r6") a3.to_asm() => _,
+ inlateout("r7") a4.to_asm() => _,
+ lateout("r8") _,
+ lateout("r9") _,
+ lateout("r10") _,
+ lateout("r11") _,
+ lateout("r12") _,
+ lateout("cr0") _,
+ 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!(
+ "sc",
+ "bns 0f",
+ "neg 3, 3",
+ "0:",
+ inlateout("r0") nr.to_asm() => _,
+ inlateout("r3") a0.to_asm() => r0,
+ inlateout("r4") a1.to_asm() => _,
+ inlateout("r5") a2.to_asm() => _,
+ inlateout("r6") a3.to_asm() => _,
+ inlateout("r7") a4.to_asm() => _,
+ inlateout("r8") a5.to_asm() => _,
+ lateout("r9") _,
+ lateout("r10") _,
+ lateout("r11") _,
+ lateout("r12") _,
+ lateout("cr0") _,
+ 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!(
+ "sc",
+ "bns 0f",
+ "neg 3, 3",
+ "0:",
+ inlateout("r0") nr.to_asm() => _,
+ inlateout("r3") a0.to_asm() => r0,
+ inlateout("r4") a1.to_asm() => _,
+ inlateout("r5") a2.to_asm() => _,
+ inlateout("r6") a3.to_asm() => _,
+ inlateout("r7") a4.to_asm() => _,
+ inlateout("r8") a5.to_asm() => _,
+ lateout("r9") _,
+ lateout("r10") _,
+ lateout("r11") _,
+ lateout("r12") _,
+ lateout("cr0") _,
+ options(nostack, preserves_flags, readonly)
+ );
+ FromAsm::from_asm(r0)
+}
diff --git a/vendor/rustix/src/backend/linux_raw/arch/powerpc64.rs b/vendor/rustix/src/backend/linux_raw/arch/powerpc64.rs
new file mode 100644
index 00000000..f21ed6aa
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/arch/powerpc64.rs
@@ -0,0 +1,414 @@
+//! powerpc64le Linux system calls.
+//!
+//! On powerpc64le, Linux indicates success or failure using `cr0.SO` rather
+//! than by returning a negative error code as most other architectures do. In
+//! theory we could immediately translate this into a `Result`, and it'd save a
+//! few branches. And in theory we could have specialized sequences for use
+//! with syscalls that are known to never fail. However, those would require
+//! more extensive changes in rustix's platform-independent code. For now, we
+//! check the flag and negate the error value to make PowerPC64 look like other
+//! architectures.
+
+use crate::backend::reg::{
+ ArgReg, FromAsm, RetReg, SyscallNumber, ToAsm as _, 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!(
+ "sc",
+ "bns 0f",
+ "neg 3, 3",
+ "0:",
+ inlateout("r0") nr.to_asm() => _,
+ lateout("r3") r0,
+ lateout("r4") _,
+ lateout("r5") _,
+ lateout("r6") _,
+ lateout("r7") _,
+ lateout("r8") _,
+ lateout("r9") _,
+ lateout("r10") _,
+ lateout("r11") _,
+ lateout("r12") _,
+ lateout("cr0") _,
+ 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!(
+ "sc",
+ "bns 0f",
+ "neg 3, 3",
+ "0:",
+ inlateout("r0") nr.to_asm() => _,
+ inlateout("r3") a0.to_asm() => r0,
+ lateout("r4") _,
+ lateout("r5") _,
+ lateout("r6") _,
+ lateout("r7") _,
+ lateout("r8") _,
+ lateout("r9") _,
+ lateout("r10") _,
+ lateout("r11") _,
+ lateout("r12") _,
+ lateout("cr0") _,
+ 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!(
+ "sc",
+ "bns 0f",
+ "neg 3, 3",
+ "0:",
+ inlateout("r0") nr.to_asm() => _,
+ inlateout("r3") a0.to_asm() => r0,
+ lateout("r4") _,
+ lateout("r5") _,
+ lateout("r6") _,
+ lateout("r7") _,
+ lateout("r8") _,
+ lateout("r9") _,
+ lateout("r10") _,
+ lateout("r11") _,
+ lateout("r12") _,
+ lateout("cr0") _,
+ options(nostack, preserves_flags, readonly)
+ );
+ FromAsm::from_asm(r0)
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> ! {
+ asm!(
+ "sc",
+ "trap",
+ in("r0") nr.to_asm(),
+ in("r3") a0.to_asm(),
+ options(nostack, noreturn)
+ )
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall2(
+ nr: SyscallNumber<'_>,
+ a0: ArgReg<'_, A0>,
+ a1: ArgReg<'_, A1>,
+) -> RetReg<R0> {
+ let r0;
+ asm!(
+ "sc",
+ "bns 0f",
+ "neg 3, 3",
+ "0:",
+ inlateout("r0") nr.to_asm() => _,
+ inlateout("r3") a0.to_asm() => r0,
+ inlateout("r4") a1.to_asm() => _,
+ lateout("r5") _,
+ lateout("r6") _,
+ lateout("r7") _,
+ lateout("r8") _,
+ lateout("r9") _,
+ lateout("r10") _,
+ lateout("r11") _,
+ lateout("r12") _,
+ lateout("cr0") _,
+ 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!(
+ "sc",
+ "bns 0f",
+ "neg 3, 3",
+ "0:",
+ inlateout("r0") nr.to_asm() => _,
+ inlateout("r3") a0.to_asm() => r0,
+ inlateout("r4") a1.to_asm() => _,
+ lateout("r5") _,
+ lateout("r6") _,
+ lateout("r7") _,
+ lateout("r8") _,
+ lateout("r9") _,
+ lateout("r10") _,
+ lateout("r11") _,
+ lateout("r12") _,
+ lateout("cr0") _,
+ 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!(
+ "sc",
+ "bns 0f",
+ "neg 3, 3",
+ "0:",
+ inlateout("r0") nr.to_asm() => _,
+ inlateout("r3") a0.to_asm() => r0,
+ inlateout("r4") a1.to_asm() => _,
+ inlateout("r5") a2.to_asm() => _,
+ lateout("r6") _,
+ lateout("r7") _,
+ lateout("r8") _,
+ lateout("r9") _,
+ lateout("r10") _,
+ lateout("r11") _,
+ lateout("r12") _,
+ lateout("cr0") _,
+ 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!(
+ "sc",
+ "bns 0f",
+ "neg 3, 3",
+ "0:",
+ inlateout("r0") nr.to_asm() => _,
+ inlateout("r3") a0.to_asm() => r0,
+ inlateout("r4") a1.to_asm() => _,
+ inlateout("r5") a2.to_asm() => _,
+ lateout("r6") _,
+ lateout("r7") _,
+ lateout("r8") _,
+ lateout("r9") _,
+ lateout("r10") _,
+ lateout("r11") _,
+ lateout("r12") _,
+ lateout("cr0") _,
+ 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!(
+ "sc",
+ "bns 0f",
+ "neg 3, 3",
+ "0:",
+ inlateout("r0") nr.to_asm() => _,
+ inlateout("r3") a0.to_asm() => r0,
+ inlateout("r4") a1.to_asm() => _,
+ inlateout("r5") a2.to_asm() => _,
+ inlateout("r6") a3.to_asm() => _,
+ lateout("r7") _,
+ lateout("r8") _,
+ lateout("r9") _,
+ lateout("r10") _,
+ lateout("r11") _,
+ lateout("r12") _,
+ lateout("cr0") _,
+ 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!(
+ "sc",
+ "bns 0f",
+ "neg 3, 3",
+ "0:",
+ inlateout("r0") nr.to_asm() => _,
+ inlateout("r3") a0.to_asm() => r0,
+ inlateout("r4") a1.to_asm() => _,
+ inlateout("r5") a2.to_asm() => _,
+ inlateout("r6") a3.to_asm() => _,
+ lateout("r7") _,
+ lateout("r8") _,
+ lateout("r9") _,
+ lateout("r10") _,
+ lateout("r11") _,
+ lateout("r12") _,
+ lateout("cr0") _,
+ 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!(
+ "sc",
+ "bns 0f",
+ "neg 3, 3",
+ "0:",
+ inlateout("r0") nr.to_asm() => _,
+ inlateout("r3") a0.to_asm() => r0,
+ inlateout("r4") a1.to_asm() => _,
+ inlateout("r5") a2.to_asm() => _,
+ inlateout("r6") a3.to_asm() => _,
+ inlateout("r7") a4.to_asm() => _,
+ lateout("r8") _,
+ lateout("r9") _,
+ lateout("r10") _,
+ lateout("r11") _,
+ lateout("r12") _,
+ lateout("cr0") _,
+ 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!(
+ "sc",
+ "bns 0f",
+ "neg 3, 3",
+ "0:",
+ inlateout("r0") nr.to_asm() => _,
+ inlateout("r3") a0.to_asm() => r0,
+ inlateout("r4") a1.to_asm() => _,
+ inlateout("r5") a2.to_asm() => _,
+ inlateout("r6") a3.to_asm() => _,
+ inlateout("r7") a4.to_asm() => _,
+ lateout("r8") _,
+ lateout("r9") _,
+ lateout("r10") _,
+ lateout("r11") _,
+ lateout("r12") _,
+ lateout("cr0") _,
+ 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!(
+ "sc",
+ "bns 0f",
+ "neg 3, 3",
+ "0:",
+ inlateout("r0") nr.to_asm() => _,
+ inlateout("r3") a0.to_asm() => r0,
+ inlateout("r4") a1.to_asm() => _,
+ inlateout("r5") a2.to_asm() => _,
+ inlateout("r6") a3.to_asm() => _,
+ inlateout("r7") a4.to_asm() => _,
+ inlateout("r8") a5.to_asm() => _,
+ lateout("r9") _,
+ lateout("r10") _,
+ lateout("r11") _,
+ lateout("r12") _,
+ lateout("cr0") _,
+ 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!(
+ "sc",
+ "bns 0f",
+ "neg 3, 3",
+ "0:",
+ inlateout("r0") nr.to_asm() => _,
+ inlateout("r3") a0.to_asm() => r0,
+ inlateout("r4") a1.to_asm() => _,
+ inlateout("r5") a2.to_asm() => _,
+ inlateout("r6") a3.to_asm() => _,
+ inlateout("r7") a4.to_asm() => _,
+ inlateout("r8") a5.to_asm() => _,
+ lateout("r9") _,
+ lateout("r10") _,
+ lateout("r11") _,
+ lateout("r12") _,
+ lateout("cr0") _,
+ options(nostack, preserves_flags, readonly)
+ );
+ FromAsm::from_asm(r0)
+}
diff --git a/vendor/rustix/src/backend/linux_raw/arch/riscv64.rs b/vendor/rustix/src/backend/linux_raw/arch/riscv64.rs
new file mode 100644
index 00000000..512657ac
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/arch/riscv64.rs
@@ -0,0 +1,266 @@
+//! riscv64 Linux system calls.
+
+use crate::backend::reg::{
+ ArgReg, FromAsm, RetReg, SyscallNumber, ToAsm as _, 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!(
+ "ecall",
+ in("a7") nr.to_asm(),
+ lateout("a0") 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!(
+ "ecall",
+ in("a7") nr.to_asm(),
+ inlateout("a0") 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!(
+ "ecall",
+ in("a7") nr.to_asm(),
+ inlateout("a0") 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!(
+ "ecall",
+ "unimp",
+ in("a7") nr.to_asm(),
+ in("a0") a0.to_asm(),
+ options(nostack, noreturn)
+ );
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall2(
+ nr: SyscallNumber<'_>,
+ a0: ArgReg<'_, A0>,
+ a1: ArgReg<'_, A1>,
+) -> RetReg<R0> {
+ let r0;
+ asm!(
+ "ecall",
+ in("a7") nr.to_asm(),
+ inlateout("a0") a0.to_asm() => r0,
+ in("a1") 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!(
+ "ecall",
+ in("a7") nr.to_asm(),
+ inlateout("a0") a0.to_asm() => r0,
+ in("a1") 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!(
+ "ecall",
+ in("a7") nr.to_asm(),
+ inlateout("a0") a0.to_asm() => r0,
+ in("a1") a1.to_asm(),
+ in("a2") 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!(
+ "ecall",
+ in("a7") nr.to_asm(),
+ inlateout("a0") a0.to_asm() => r0,
+ in("a1") a1.to_asm(),
+ in("a2") 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!(
+ "ecall",
+ in("a7") nr.to_asm(),
+ inlateout("a0") a0.to_asm() => r0,
+ in("a1") a1.to_asm(),
+ in("a2") a2.to_asm(),
+ in("a3") 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!(
+ "ecall",
+ in("a7") nr.to_asm(),
+ inlateout("a0") a0.to_asm() => r0,
+ in("a1") a1.to_asm(),
+ in("a2") a2.to_asm(),
+ in("a3") 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!(
+ "ecall",
+ in("a7") nr.to_asm(),
+ inlateout("a0") a0.to_asm() => r0,
+ in("a1") a1.to_asm(),
+ in("a2") a2.to_asm(),
+ in("a3") a3.to_asm(),
+ in("a4") 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!(
+ "ecall",
+ in("a7") nr.to_asm(),
+ inlateout("a0") a0.to_asm() => r0,
+ in("a1") a1.to_asm(),
+ in("a2") a2.to_asm(),
+ in("a3") a3.to_asm(),
+ in("a4") 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!(
+ "ecall",
+ in("a7") nr.to_asm(),
+ inlateout("a0") a0.to_asm() => r0,
+ in("a1") a1.to_asm(),
+ in("a2") a2.to_asm(),
+ in("a3") a3.to_asm(),
+ in("a4") a4.to_asm(),
+ in("a5") 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!(
+ "ecall",
+ in("a7") nr.to_asm(),
+ inlateout("a0") a0.to_asm() => r0,
+ in("a1") a1.to_asm(),
+ in("a2") a2.to_asm(),
+ in("a3") a3.to_asm(),
+ in("a4") a4.to_asm(),
+ in("a5") a5.to_asm(),
+ options(nostack, preserves_flags, readonly)
+ );
+ FromAsm::from_asm(r0)
+}
diff --git a/vendor/rustix/src/backend/linux_raw/arch/s390x.rs b/vendor/rustix/src/backend/linux_raw/arch/s390x.rs
new file mode 100644
index 00000000..5d6e14f1
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/arch/s390x.rs
@@ -0,0 +1,288 @@
+//! s390x Linux system calls.
+
+use crate::backend::reg::{
+ ArgReg, FromAsm, RetReg, SyscallNumber, ToAsm as _, 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("r1") nr.to_asm(),
+ lateout("r2") 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("r1") nr.to_asm(),
+ inlateout("r2") 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("r1") nr.to_asm(),
+ inlateout("r2") 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",
+ "j .+2",
+ in("r1") nr.to_asm(),
+ in("r2") a0.to_asm(),
+ options(nostack, 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("r1") nr.to_asm(),
+ inlateout("r2") a0.to_asm() => r0,
+ in("r3") 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("r1") nr.to_asm(),
+ inlateout("r2") a0.to_asm() => r0,
+ in("r3") 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("r1") nr.to_asm(),
+ inlateout("r2") a0.to_asm() => r0,
+ in("r3") a1.to_asm(),
+ in("r4") 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("r1") nr.to_asm(),
+ inlateout("r2") a0.to_asm() => r0,
+ in("r3") a1.to_asm(),
+ in("r4") 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("r1") nr.to_asm(),
+ inlateout("r2") a0.to_asm() => r0,
+ in("r3") a1.to_asm(),
+ in("r4") a2.to_asm(),
+ in("r5") 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("r1") nr.to_asm(),
+ inlateout("r2") a0.to_asm() => r0,
+ in("r3") a1.to_asm(),
+ in("r4") a2.to_asm(),
+ in("r5") 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("r1") nr.to_asm(),
+ inlateout("r2") a0.to_asm() => r0,
+ in("r3") a1.to_asm(),
+ in("r4") a2.to_asm(),
+ in("r5") a3.to_asm(),
+ in("r6") 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("r1") nr.to_asm(),
+ inlateout("r2") a0.to_asm() => r0,
+ in("r3") a1.to_asm(),
+ in("r4") a2.to_asm(),
+ in("r5") a3.to_asm(),
+ in("r6") 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> {
+ if nr.nr == linux_raw_sys::general::__NR_mmap as usize {
+ let mut a = [
+ a0.to_asm(),
+ a1.to_asm(),
+ a2.to_asm(),
+ a3.to_asm(),
+ a4.to_asm(),
+ a5.to_asm(),
+ ];
+ return syscall1(nr, a.as_mut_ptr().into());
+ }
+ let r0;
+ asm!(
+ "svc 0",
+ in("r1") nr.to_asm(),
+ inlateout("r2") a0.to_asm() => r0,
+ in("r3") a1.to_asm(),
+ in("r4") a2.to_asm(),
+ in("r5") a3.to_asm(),
+ in("r6") a4.to_asm(),
+ in("r7") 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> {
+ if nr.nr == linux_raw_sys::general::__NR_mmap as usize {
+ let a = [
+ a0.to_asm(),
+ a1.to_asm(),
+ a2.to_asm(),
+ a3.to_asm(),
+ a4.to_asm(),
+ a5.to_asm(),
+ ];
+ return syscall1_readonly(nr, a.as_ptr().into());
+ }
+ let r0;
+ asm!(
+ "svc 0",
+ in("r1") nr.to_asm(),
+ inlateout("r2") a0.to_asm() => r0,
+ in("r3") a1.to_asm(),
+ in("r4") a2.to_asm(),
+ in("r5") a3.to_asm(),
+ in("r6") a4.to_asm(),
+ in("r7") a5.to_asm(),
+ options(nostack, preserves_flags, readonly)
+ );
+ FromAsm::from_asm(r0)
+}
diff --git a/vendor/rustix/src/backend/linux_raw/arch/thumb.rs b/vendor/rustix/src/backend/linux_raw/arch/thumb.rs
new file mode 100644
index 00000000..0989430d
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/arch/thumb.rs
@@ -0,0 +1,323 @@
+//! 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 as _, 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",
+ "udf #16",
+ nr = in(reg) nr.to_asm(),
+ in("r0") a0.to_asm(),
+ options(nostack, 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/x86.rs b/vendor/rustix/src/backend/linux_raw/arch/x86.rs
new file mode 100644
index 00000000..95376415
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/arch/x86.rs
@@ -0,0 +1,492 @@
+//! 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, as vsyscall is much faster.
+//!
+//! Syscalls made with `int 0x80` preserve the flags register, while syscalls
+//! made using vsyscall do not.
+
+#![allow(dead_code)]
+
+use crate::backend::reg::{
+ ArgReg, FromAsm, RetReg, SyscallNumber, ToAsm as _, 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,
+ );
+ 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(),
+ );
+ FromAsm::from_asm(r0)
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn indirect_syscall1_noreturn(
+ callee: SyscallType,
+ nr: SyscallNumber<'_>,
+ a0: ArgReg<'_, A0>,
+) -> ! {
+ asm!(
+ "call {callee}",
+ "ud2",
+ 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(),
+ );
+ 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(),
+ );
+ 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(),
+ );
+ 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 [eax + 0]",
+ "mov esi, [eax + 4]",
+ "mov eax, [eax + 8]",
+ "call [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(),
+ );
+ FromAsm::from_asm(r0)
+}
+
+#[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 [eax + 0]",
+ "mov esi, [eax + 4]",
+ "mov ebp, [eax + 8]",
+ "mov eax, [eax + 12]",
+ "call [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(),
+ );
+ 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",
+ "ud2",
+ in("eax") nr.to_asm(),
+ in("ebx") a0.to_asm(),
+ options(nostack, 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;
+ // See the comments in `syscall4`.
+ 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, [eax + 0]",
+ "mov ebp, [eax + 4]",
+ "mov eax, [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, [eax + 0]",
+ "mov ebp, [eax + 4]",
+ "mov eax, [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/backend/linux_raw/arch/x86_64.rs b/vendor/rustix/src/backend/linux_raw/arch/x86_64.rs
new file mode 100644
index 00000000..6d105c08
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/arch/x86_64.rs
@@ -0,0 +1,294 @@
+//! x86-64 Linux system calls.
+
+use crate::backend::reg::{
+ ArgReg, FromAsm, RetReg, SyscallNumber, ToAsm as _, 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::backend) unsafe fn syscall0_readonly(nr: SyscallNumber<'_>) -> RetReg<R0> {
+ let r0;
+ asm!(
+ "syscall",
+ inlateout("rax") nr.to_asm() => r0,
+ lateout("rcx") _,
+ lateout("r11") _,
+ 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!(
+ "syscall",
+ inlateout("rax") nr.to_asm() => r0,
+ in("rdi") a0.to_asm(),
+ lateout("rcx") _,
+ lateout("r11") _,
+ 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!(
+ "syscall",
+ inlateout("rax") nr.to_asm() => r0,
+ in("rdi") a0.to_asm(),
+ lateout("rcx") _,
+ lateout("r11") _,
+ options(nostack, preserves_flags, readonly)
+ );
+ FromAsm::from_asm(r0)
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> ! {
+ asm!(
+ "syscall",
+ "ud2",
+ in("rax") nr.to_asm(),
+ in("rdi") a0.to_asm(),
+ options(nostack, noreturn)
+ )
+}
+
+#[inline]
+pub(in crate::backend) unsafe fn syscall2(
+ nr: SyscallNumber<'_>,
+ a0: ArgReg<'_, A0>,
+ a1: ArgReg<'_, A1>,
+) -> RetReg<R0> {
+ let r0;
+ asm!(
+ "syscall",
+ inlateout("rax") nr.to_asm() => r0,
+ in("rdi") a0.to_asm(),
+ in("rsi") a1.to_asm(),
+ lateout("rcx") _,
+ lateout("r11") _,
+ 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!(
+ "syscall",
+ inlateout("rax") nr.to_asm() => r0,
+ in("rdi") a0.to_asm(),
+ in("rsi") a1.to_asm(),
+ lateout("rcx") _,
+ lateout("r11") _,
+ 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!(
+ "syscall",
+ inlateout("rax") nr.to_asm() => r0,
+ in("rdi") a0.to_asm(),
+ in("rsi") a1.to_asm(),
+ in("rdx") a2.to_asm(),
+ lateout("rcx") _,
+ lateout("r11") _,
+ 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!(
+ "syscall",
+ inlateout("rax") nr.to_asm() => r0,
+ in("rdi") a0.to_asm(),
+ in("rsi") a1.to_asm(),
+ in("rdx") a2.to_asm(),
+ lateout("rcx") _,
+ lateout("r11") _,
+ 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!(
+ "syscall",
+ inlateout("rax") nr.to_asm() => r0,
+ in("rdi") a0.to_asm(),
+ in("rsi") a1.to_asm(),
+ in("rdx") a2.to_asm(),
+ in("r10") a3.to_asm(),
+ lateout("rcx") _,
+ lateout("r11") _,
+ 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!(
+ "syscall",
+ inlateout("rax") nr.to_asm() => r0,
+ in("rdi") a0.to_asm(),
+ in("rsi") a1.to_asm(),
+ in("rdx") a2.to_asm(),
+ in("r10") a3.to_asm(),
+ lateout("rcx") _,
+ lateout("r11") _,
+ 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!(
+ "syscall",
+ inlateout("rax") nr.to_asm() => r0,
+ in("rdi") a0.to_asm(),
+ in("rsi") a1.to_asm(),
+ in("rdx") a2.to_asm(),
+ in("r10") a3.to_asm(),
+ in("r8") a4.to_asm(),
+ lateout("rcx") _,
+ lateout("r11") _,
+ 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!(
+ "syscall",
+ inlateout("rax") nr.to_asm() => r0,
+ in("rdi") a0.to_asm(),
+ in("rsi") a1.to_asm(),
+ in("rdx") a2.to_asm(),
+ in("r10") a3.to_asm(),
+ in("r8") a4.to_asm(),
+ lateout("rcx") _,
+ lateout("r11") _,
+ 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!(
+ "syscall",
+ inlateout("rax") nr.to_asm() => r0,
+ in("rdi") a0.to_asm(),
+ in("rsi") a1.to_asm(),
+ in("rdx") a2.to_asm(),
+ in("r10") a3.to_asm(),
+ in("r8") a4.to_asm(),
+ in("r9") a5.to_asm(),
+ lateout("rcx") _,
+ lateout("r11") _,
+ 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!(
+ "syscall",
+ inlateout("rax") nr.to_asm() => r0,
+ in("rdi") a0.to_asm(),
+ in("rsi") a1.to_asm(),
+ in("rdx") a2.to_asm(),
+ in("r10") a3.to_asm(),
+ in("r8") a4.to_asm(),
+ in("r9") a5.to_asm(),
+ lateout("rcx") _,
+ lateout("r11") _,
+ options(nostack, preserves_flags, readonly)
+ );
+ FromAsm::from_asm(r0)
+}
diff --git a/vendor/rustix/src/backend/linux_raw/c.rs b/vendor/rustix/src/backend/linux_raw/c.rs
new file mode 100644
index 00000000..755dadcd
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/c.rs
@@ -0,0 +1,385 @@
+//! Adapt the Linux API to resemble a POSIX-style libc API.
+//!
+//! The linux_raw backend doesn't use actual libc; this just defines certain
+//! types that are convenient to have defined.
+
+#![allow(unused_imports)]
+#![allow(non_camel_case_types)]
+
+pub(crate) type size_t = usize;
+pub(crate) use linux_raw_sys::ctypes::*;
+pub(crate) use linux_raw_sys::errno::{EBADF, EINVAL};
+pub(crate) use linux_raw_sys::general::{__kernel_fd_set as fd_set, __FD_SETSIZE as FD_SETSIZE};
+pub(crate) use linux_raw_sys::ioctl::{FIONBIO, FIONREAD};
+// Import the kernel's `uid_t` and `gid_t` if they're 32-bit.
+#[cfg(feature = "thread")]
+pub(crate) use linux_raw_sys::general::futex_waitv;
+#[cfg(not(any(target_arch = "arm", target_arch = "sparc", target_arch = "x86")))]
+pub(crate) use linux_raw_sys::general::{__kernel_gid_t as gid_t, __kernel_uid_t as uid_t};
+pub(crate) use linux_raw_sys::general::{
+ __kernel_pid_t as pid_t, __kernel_time64_t as time_t, __kernel_timespec as timespec, iovec,
+ O_CLOEXEC, O_NOCTTY, O_NONBLOCK, O_RDWR,
+};
+#[cfg(feature = "system")]
+pub(crate) use linux_raw_sys::system::sysinfo;
+
+#[cfg(feature = "fs")]
+#[cfg(target_arch = "x86")]
+#[cfg(test)]
+pub(crate) use linux_raw_sys::general::stat64;
+#[cfg(feature = "fs")]
+#[cfg(test)]
+pub(crate) use linux_raw_sys::general::{
+ __kernel_fsid_t as fsid_t, stat, statfs64, statx, statx_timestamp,
+};
+
+#[cfg(feature = "event")]
+#[cfg(test)]
+pub(crate) use linux_raw_sys::general::epoll_event;
+
+#[cfg(feature = "mm")]
+mod mm {
+ pub(crate) use linux_raw_sys::general::{MAP_HUGETLB, MAP_HUGE_SHIFT};
+}
+#[cfg(feature = "mm")]
+pub(crate) use mm::*;
+
+#[cfg(any(
+ feature = "fs",
+ all(
+ not(feature = "use-libc-auxv"),
+ not(feature = "use-explicitly-provided-auxv"),
+ any(
+ feature = "param",
+ feature = "runtime",
+ feature = "thread",
+ feature = "time",
+ target_arch = "x86",
+ )
+ )
+))]
+pub(crate) use linux_raw_sys::general::{
+ AT_FDCWD, NFS_SUPER_MAGIC, O_LARGEFILE, PROC_SUPER_MAGIC, UTIME_NOW, UTIME_OMIT, XATTR_CREATE,
+ XATTR_REPLACE,
+};
+
+pub(crate) use linux_raw_sys::ioctl::{BLKPBSZGET, BLKSSZGET, FICLONE};
+#[cfg(target_pointer_width = "32")]
+pub(crate) use linux_raw_sys::ioctl::{FS_IOC32_GETFLAGS, FS_IOC32_SETFLAGS};
+#[cfg(target_pointer_width = "64")]
+pub(crate) use linux_raw_sys::ioctl::{FS_IOC_GETFLAGS, FS_IOC_SETFLAGS};
+
+#[cfg(feature = "io_uring")]
+pub(crate) use linux_raw_sys::{general::open_how, io_uring::*};
+
+#[cfg(feature = "net")]
+pub(crate) use linux_raw_sys::{
+ cmsg_macros::*,
+ general::{O_CLOEXEC as SOCK_CLOEXEC, O_NONBLOCK as SOCK_NONBLOCK},
+ if_ether::*,
+ net::{
+ __kernel_sa_family_t as sa_family_t, __kernel_sockaddr_storage as sockaddr_storage,
+ cmsghdr, in6_addr, in_addr, ip_mreq, ip_mreq_source, ip_mreqn, ipv6_mreq, linger, mmsghdr,
+ msghdr, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_un, socklen_t, AF_DECnet,
+ AF_APPLETALK, AF_ASH, AF_ATMPVC, AF_ATMSVC, AF_AX25, AF_BLUETOOTH, AF_BRIDGE, AF_CAN,
+ AF_ECONET, AF_IEEE802154, AF_INET, AF_INET6, AF_IPX, AF_IRDA, AF_ISDN, AF_IUCV, AF_KEY,
+ AF_LLC, AF_NETBEUI, AF_NETLINK, AF_NETROM, AF_PACKET, AF_PHONET, AF_PPPOX, AF_RDS, AF_ROSE,
+ AF_RXRPC, AF_SECURITY, AF_SNA, AF_TIPC, AF_UNIX, AF_UNSPEC, AF_WANPIPE, AF_X25, AF_XDP,
+ IP6T_SO_ORIGINAL_DST, IPPROTO_FRAGMENT, IPPROTO_ICMPV6, IPPROTO_MH, IPPROTO_ROUTING,
+ IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP, IPV6_FREEBIND, IPV6_MULTICAST_HOPS,
+ IPV6_MULTICAST_LOOP, IPV6_RECVTCLASS, IPV6_TCLASS, IPV6_UNICAST_HOPS, IPV6_V6ONLY,
+ IP_ADD_MEMBERSHIP, IP_ADD_SOURCE_MEMBERSHIP, IP_DROP_MEMBERSHIP, IP_DROP_SOURCE_MEMBERSHIP,
+ IP_FREEBIND, IP_MULTICAST_LOOP, IP_MULTICAST_TTL, IP_RECVTOS, IP_TOS, IP_TTL,
+ MSG_CMSG_CLOEXEC, MSG_CONFIRM, MSG_CTRUNC, MSG_DONTROUTE, MSG_DONTWAIT, MSG_EOR,
+ MSG_ERRQUEUE, MSG_MORE, MSG_NOSIGNAL, MSG_OOB, MSG_PEEK, MSG_TRUNC, MSG_WAITALL,
+ SCM_CREDENTIALS, SCM_RIGHTS, SHUT_RD, SHUT_RDWR, SHUT_WR, SOCK_DGRAM, SOCK_RAW, SOCK_RDM,
+ SOCK_SEQPACKET, SOCK_STREAM, SOL_SOCKET, SOL_XDP, SO_ACCEPTCONN, SO_BROADCAST, SO_COOKIE,
+ SO_DOMAIN, SO_ERROR, SO_INCOMING_CPU, SO_KEEPALIVE, SO_LINGER, SO_OOBINLINE,
+ SO_ORIGINAL_DST, SO_PASSCRED, SO_PROTOCOL, SO_RCVBUF, SO_RCVBUFFORCE, SO_RCVTIMEO_NEW,
+ SO_RCVTIMEO_NEW as SO_RCVTIMEO, SO_RCVTIMEO_OLD, SO_REUSEADDR, SO_REUSEPORT, SO_SNDBUF,
+ SO_SNDBUFFORCE, SO_SNDTIMEO_NEW, SO_SNDTIMEO_NEW as SO_SNDTIMEO, SO_SNDTIMEO_OLD, SO_TYPE,
+ TCP_CONGESTION, TCP_CORK, TCP_KEEPCNT, TCP_KEEPIDLE, TCP_KEEPINTVL, TCP_NODELAY,
+ TCP_QUICKACK, TCP_THIN_LINEAR_TIMEOUTS, TCP_USER_TIMEOUT,
+ },
+ netlink::*,
+ xdp::{
+ sockaddr_xdp, xdp_desc, xdp_mmap_offsets, xdp_mmap_offsets_v1, xdp_options,
+ xdp_ring_offset, xdp_ring_offset_v1, xdp_statistics, xdp_statistics_v1, xdp_umem_reg,
+ xdp_umem_reg_v1, XDP_COPY, XDP_MMAP_OFFSETS, XDP_OPTIONS, XDP_OPTIONS_ZEROCOPY,
+ XDP_PGOFF_RX_RING, XDP_PGOFF_TX_RING, XDP_PKT_CONTD, XDP_RING_NEED_WAKEUP, XDP_RX_RING,
+ XDP_SHARED_UMEM, XDP_STATISTICS, XDP_TX_RING, XDP_UMEM_COMPLETION_RING, XDP_UMEM_FILL_RING,
+ XDP_UMEM_PGOFF_COMPLETION_RING, XDP_UMEM_PGOFF_FILL_RING, XDP_UMEM_REG,
+ XDP_UMEM_UNALIGNED_CHUNK_FLAG, XDP_USE_NEED_WAKEUP, XDP_USE_SG, XDP_ZEROCOPY,
+ XSK_UNALIGNED_BUF_ADDR_MASK, XSK_UNALIGNED_BUF_OFFSET_SHIFT,
+ },
+};
+
+// Cast away bindgen's `enum` type to make these consistent with the other
+// `setsockopt`/`getsockopt` level values.
+#[cfg(feature = "net")]
+pub(crate) const IPPROTO_IP: u32 = linux_raw_sys::net::IPPROTO_IP as _;
+#[cfg(feature = "net")]
+pub(crate) const IPPROTO_ICMP: u32 = linux_raw_sys::net::IPPROTO_ICMP as _;
+#[cfg(feature = "net")]
+pub(crate) const IPPROTO_IGMP: u32 = linux_raw_sys::net::IPPROTO_IGMP as _;
+#[cfg(feature = "net")]
+pub(crate) const IPPROTO_IPIP: u32 = linux_raw_sys::net::IPPROTO_IPIP as _;
+#[cfg(feature = "net")]
+pub(crate) const IPPROTO_TCP: u32 = linux_raw_sys::net::IPPROTO_TCP as _;
+#[cfg(feature = "net")]
+pub(crate) const IPPROTO_EGP: u32 = linux_raw_sys::net::IPPROTO_EGP as _;
+#[cfg(feature = "net")]
+pub(crate) const IPPROTO_PUP: u32 = linux_raw_sys::net::IPPROTO_PUP as _;
+#[cfg(feature = "net")]
+pub(crate) const IPPROTO_UDP: u32 = linux_raw_sys::net::IPPROTO_UDP as _;
+#[cfg(feature = "net")]
+pub(crate) const IPPROTO_IDP: u32 = linux_raw_sys::net::IPPROTO_IDP as _;
+#[cfg(feature = "net")]
+pub(crate) const IPPROTO_TP: u32 = linux_raw_sys::net::IPPROTO_TP as _;
+#[cfg(feature = "net")]
+pub(crate) const IPPROTO_DCCP: u32 = linux_raw_sys::net::IPPROTO_DCCP as _;
+#[cfg(feature = "net")]
+pub(crate) const IPPROTO_IPV6: u32 = linux_raw_sys::net::IPPROTO_IPV6 as _;
+#[cfg(feature = "net")]
+pub(crate) const IPPROTO_RSVP: u32 = linux_raw_sys::net::IPPROTO_RSVP as _;
+#[cfg(feature = "net")]
+pub(crate) const IPPROTO_GRE: u32 = linux_raw_sys::net::IPPROTO_GRE as _;
+#[cfg(feature = "net")]
+pub(crate) const IPPROTO_ESP: u32 = linux_raw_sys::net::IPPROTO_ESP as _;
+#[cfg(feature = "net")]
+pub(crate) const IPPROTO_AH: u32 = linux_raw_sys::net::IPPROTO_AH as _;
+#[cfg(feature = "net")]
+pub(crate) const IPPROTO_MTP: u32 = linux_raw_sys::net::IPPROTO_MTP as _;
+#[cfg(feature = "net")]
+pub(crate) const IPPROTO_BEETPH: u32 = linux_raw_sys::net::IPPROTO_BEETPH as _;
+#[cfg(feature = "net")]
+pub(crate) const IPPROTO_ENCAP: u32 = linux_raw_sys::net::IPPROTO_ENCAP as _;
+#[cfg(feature = "net")]
+pub(crate) const IPPROTO_PIM: u32 = linux_raw_sys::net::IPPROTO_PIM as _;
+#[cfg(feature = "net")]
+pub(crate) const IPPROTO_COMP: u32 = linux_raw_sys::net::IPPROTO_COMP as _;
+#[cfg(feature = "net")]
+pub(crate) const IPPROTO_SCTP: u32 = linux_raw_sys::net::IPPROTO_SCTP as _;
+#[cfg(feature = "net")]
+pub(crate) const IPPROTO_UDPLITE: u32 = linux_raw_sys::net::IPPROTO_UDPLITE as _;
+#[cfg(feature = "net")]
+pub(crate) const IPPROTO_MPLS: u32 = linux_raw_sys::net::IPPROTO_MPLS as _;
+#[cfg(feature = "net")]
+pub(crate) const IPPROTO_ETHERNET: u32 = linux_raw_sys::net::IPPROTO_ETHERNET as _;
+#[cfg(feature = "net")]
+pub(crate) const IPPROTO_RAW: u32 = linux_raw_sys::net::IPPROTO_RAW as _;
+#[cfg(feature = "net")]
+pub(crate) const IPPROTO_MPTCP: u32 = linux_raw_sys::net::IPPROTO_MPTCP as _;
+
+#[cfg(any(feature = "process", feature = "runtime"))]
+pub(crate) use linux_raw_sys::general::siginfo_t;
+
+#[cfg(any(feature = "process", feature = "runtime"))]
+pub(crate) const EXIT_SUCCESS: c_int = 0;
+#[cfg(any(feature = "process", feature = "runtime"))]
+pub(crate) const EXIT_FAILURE: c_int = 1;
+#[cfg(feature = "process")]
+pub(crate) const EXIT_SIGNALED_SIGABRT: c_int = 128 + linux_raw_sys::general::SIGABRT as c_int;
+#[cfg(feature = "runtime")]
+pub(crate) const CLONE_CHILD_SETTID: c_int = linux_raw_sys::general::CLONE_CHILD_SETTID as c_int;
+
+#[cfg(feature = "process")]
+pub(crate) use linux_raw_sys::{
+ general::{
+ CLD_CONTINUED, CLD_DUMPED, CLD_EXITED, CLD_KILLED, CLD_STOPPED, CLD_TRAPPED, F_RDLCK,
+ F_UNLCK, F_WRLCK, O_NONBLOCK as PIDFD_NONBLOCK, P_ALL, P_PGID, P_PID, P_PIDFD, SEEK_CUR,
+ SEEK_END, SEEK_SET,
+ },
+ ioctl::TIOCSCTTY,
+};
+
+#[cfg(feature = "process")]
+#[cfg(target_pointer_width = "32")]
+pub(crate) use linux_raw_sys::general::{flock64 as flock, F_GETLK64};
+
+#[cfg(feature = "process")]
+#[cfg(target_pointer_width = "64")]
+pub(crate) use linux_raw_sys::general::{flock, F_GETLK};
+
+#[cfg(feature = "pty")]
+pub(crate) use linux_raw_sys::ioctl::TIOCGPTPEER;
+
+#[cfg(feature = "termios")]
+pub(crate) use linux_raw_sys::{
+ general::{
+ cc_t, speed_t, tcflag_t, termios, termios2, winsize, B0, B1000000, B110, B115200, B1152000,
+ B1200, B134, B150, B1500000, B1800, B19200, B200, B2000000, B230400, B2400, B2500000, B300,
+ B3000000, B3500000, B38400, B4000000, B460800, B4800, B50, B500000, B57600, B576000, B600,
+ B75, B921600, B9600, BOTHER, BRKINT, BS0, BS1, BSDLY, CBAUD, CBAUDEX, CIBAUD, CLOCAL,
+ CMSPAR, CR0, CR1, CR2, CR3, CRDLY, CREAD, CRTSCTS, CS5, CS6, CS7, CS8, CSIZE, CSTOPB, ECHO,
+ ECHOCTL, ECHOE, ECHOK, ECHOKE, ECHONL, ECHOPRT, EXTA, EXTB, EXTPROC, FF0, FF1, FFDLY,
+ FLUSHO, HUPCL, IBSHIFT, ICANON, ICRNL, IEXTEN, IGNBRK, IGNCR, IGNPAR, IMAXBEL, INLCR,
+ INPCK, ISIG, ISTRIP, IUCLC, IUTF8, IXANY, IXOFF, IXON, NCCS, NL0, NL1, NLDLY, NOFLSH,
+ OCRNL, OFDEL, OFILL, OLCUC, ONLCR, ONLRET, ONOCR, OPOST, PARENB, PARMRK, PARODD, PENDIN,
+ TAB0, TAB1, TAB2, TAB3, TABDLY, TCIFLUSH, TCIOFF, TCIOFLUSH, TCION, TCOFLUSH, TCOOFF,
+ TCOON, TCSADRAIN, TCSAFLUSH, TCSANOW, TOSTOP, VDISCARD, VEOF, VEOL, VEOL2, VERASE, VINTR,
+ VKILL, VLNEXT, VMIN, VQUIT, VREPRINT, VSTART, VSTOP, VSUSP, VSWTC, VT0, VT1, VTDLY, VTIME,
+ VWERASE, XCASE, XTABS,
+ },
+ ioctl::{
+ TCFLSH, TCGETS, TCGETS2, TCSBRK, TCSETS, TCSETS2, TCSETSF2, TCSETSW2, TCXONC, TIOCEXCL,
+ TIOCGPGRP, TIOCGSID, TIOCGWINSZ, TIOCNXCL, TIOCSPGRP, TIOCSWINSZ,
+ },
+};
+
+// Define our own `uid_t` and `gid_t` if the kernel's versions are not 32-bit.
+#[cfg(any(target_arch = "arm", target_arch = "sparc", target_arch = "x86"))]
+pub(crate) type uid_t = u32;
+#[cfg(any(target_arch = "arm", target_arch = "sparc", target_arch = "x86"))]
+pub(crate) type gid_t = u32;
+
+// Bindgen infers `u32` for many of these macro types which meant to be
+// used with `c_int` in the C APIs, so cast them to `c_int`.
+
+// Convert the signal constants from `u32` to `c_int`.
+pub(crate) const SIGHUP: c_int = linux_raw_sys::general::SIGHUP as _;
+pub(crate) const SIGINT: c_int = linux_raw_sys::general::SIGINT as _;
+pub(crate) const SIGQUIT: c_int = linux_raw_sys::general::SIGQUIT as _;
+pub(crate) const SIGILL: c_int = linux_raw_sys::general::SIGILL as _;
+pub(crate) const SIGTRAP: c_int = linux_raw_sys::general::SIGTRAP as _;
+pub(crate) const SIGABRT: c_int = linux_raw_sys::general::SIGABRT as _;
+pub(crate) const SIGBUS: c_int = linux_raw_sys::general::SIGBUS as _;
+pub(crate) const SIGFPE: c_int = linux_raw_sys::general::SIGFPE as _;
+pub(crate) const SIGKILL: c_int = linux_raw_sys::general::SIGKILL as _;
+pub(crate) const SIGUSR1: c_int = linux_raw_sys::general::SIGUSR1 as _;
+pub(crate) const SIGSEGV: c_int = linux_raw_sys::general::SIGSEGV as _;
+pub(crate) const SIGUSR2: c_int = linux_raw_sys::general::SIGUSR2 as _;
+pub(crate) const SIGPIPE: c_int = linux_raw_sys::general::SIGPIPE as _;
+pub(crate) const SIGALRM: c_int = linux_raw_sys::general::SIGALRM as _;
+pub(crate) const SIGTERM: c_int = linux_raw_sys::general::SIGTERM as _;
+#[cfg(not(any(
+ target_arch = "mips",
+ target_arch = "mips32r6",
+ target_arch = "mips64",
+ target_arch = "mips64r6",
+ target_arch = "sparc",
+ target_arch = "sparc64"
+)))]
+pub(crate) const SIGSTKFLT: c_int = linux_raw_sys::general::SIGSTKFLT as _;
+pub(crate) const SIGCHLD: c_int = linux_raw_sys::general::SIGCHLD as _;
+pub(crate) const SIGCONT: c_int = linux_raw_sys::general::SIGCONT as _;
+pub(crate) const SIGSTOP: c_int = linux_raw_sys::general::SIGSTOP as _;
+pub(crate) const SIGTSTP: c_int = linux_raw_sys::general::SIGTSTP as _;
+pub(crate) const SIGTTIN: c_int = linux_raw_sys::general::SIGTTIN as _;
+pub(crate) const SIGTTOU: c_int = linux_raw_sys::general::SIGTTOU as _;
+pub(crate) const SIGURG: c_int = linux_raw_sys::general::SIGURG as _;
+pub(crate) const SIGXCPU: c_int = linux_raw_sys::general::SIGXCPU as _;
+pub(crate) const SIGXFSZ: c_int = linux_raw_sys::general::SIGXFSZ as _;
+pub(crate) const SIGVTALRM: c_int = linux_raw_sys::general::SIGVTALRM as _;
+pub(crate) const SIGPROF: c_int = linux_raw_sys::general::SIGPROF as _;
+pub(crate) const SIGWINCH: c_int = linux_raw_sys::general::SIGWINCH as _;
+pub(crate) const SIGIO: c_int = linux_raw_sys::general::SIGIO as _;
+pub(crate) const SIGPWR: c_int = linux_raw_sys::general::SIGPWR as _;
+pub(crate) const SIGSYS: c_int = linux_raw_sys::general::SIGSYS as _;
+#[cfg(any(
+ target_arch = "mips",
+ target_arch = "mips32r6",
+ target_arch = "mips64",
+ target_arch = "mips64r6",
+ target_arch = "sparc",
+ target_arch = "sparc64"
+))]
+pub(crate) const SIGEMT: c_int = linux_raw_sys::general::SIGEMT as _;
+
+#[cfg(feature = "stdio")]
+pub(crate) const STDIN_FILENO: c_int = linux_raw_sys::general::STDIN_FILENO as _;
+#[cfg(feature = "stdio")]
+pub(crate) const STDOUT_FILENO: c_int = linux_raw_sys::general::STDOUT_FILENO as _;
+#[cfg(feature = "stdio")]
+pub(crate) const STDERR_FILENO: c_int = linux_raw_sys::general::STDERR_FILENO as _;
+
+pub(crate) const PIPE_BUF: usize = linux_raw_sys::general::PIPE_BUF as _;
+
+pub(crate) const CLOCK_MONOTONIC: c_int = linux_raw_sys::general::CLOCK_MONOTONIC as _;
+pub(crate) const CLOCK_REALTIME: c_int = linux_raw_sys::general::CLOCK_REALTIME as _;
+pub(crate) const CLOCK_MONOTONIC_RAW: c_int = linux_raw_sys::general::CLOCK_MONOTONIC_RAW as _;
+pub(crate) const CLOCK_MONOTONIC_COARSE: c_int =
+ linux_raw_sys::general::CLOCK_MONOTONIC_COARSE as _;
+pub(crate) const CLOCK_REALTIME_COARSE: c_int = linux_raw_sys::general::CLOCK_REALTIME_COARSE as _;
+pub(crate) const CLOCK_THREAD_CPUTIME_ID: c_int =
+ linux_raw_sys::general::CLOCK_THREAD_CPUTIME_ID as _;
+pub(crate) const CLOCK_PROCESS_CPUTIME_ID: c_int =
+ linux_raw_sys::general::CLOCK_PROCESS_CPUTIME_ID as _;
+#[cfg(any(feature = "thread", feature = "time"))]
+pub(crate) const CLOCK_BOOTTIME: c_int = linux_raw_sys::general::CLOCK_BOOTTIME as _;
+#[cfg(any(feature = "thread", feature = "time"))]
+pub(crate) const CLOCK_BOOTTIME_ALARM: c_int = linux_raw_sys::general::CLOCK_BOOTTIME_ALARM as _;
+#[cfg(any(feature = "thread", feature = "time"))]
+pub(crate) const CLOCK_TAI: c_int = linux_raw_sys::general::CLOCK_TAI as _;
+#[cfg(any(feature = "thread", feature = "time"))]
+pub(crate) const CLOCK_REALTIME_ALARM: c_int = linux_raw_sys::general::CLOCK_REALTIME_ALARM as _;
+
+#[cfg(feature = "system")]
+mod reboot_symbols {
+ use super::c_int;
+
+ pub(crate) const LINUX_REBOOT_MAGIC1: c_int = linux_raw_sys::general::LINUX_REBOOT_MAGIC1 as _;
+ pub(crate) const LINUX_REBOOT_MAGIC2: c_int = linux_raw_sys::general::LINUX_REBOOT_MAGIC2 as _;
+
+ pub(crate) const LINUX_REBOOT_CMD_RESTART: c_int =
+ linux_raw_sys::general::LINUX_REBOOT_CMD_RESTART as _;
+ pub(crate) const LINUX_REBOOT_CMD_HALT: c_int =
+ linux_raw_sys::general::LINUX_REBOOT_CMD_HALT as _;
+ pub(crate) const LINUX_REBOOT_CMD_CAD_ON: c_int =
+ linux_raw_sys::general::LINUX_REBOOT_CMD_CAD_ON as _;
+ pub(crate) const LINUX_REBOOT_CMD_CAD_OFF: c_int =
+ linux_raw_sys::general::LINUX_REBOOT_CMD_CAD_OFF as _;
+ pub(crate) const LINUX_REBOOT_CMD_POWER_OFF: c_int =
+ linux_raw_sys::general::LINUX_REBOOT_CMD_POWER_OFF as _;
+ pub(crate) const LINUX_REBOOT_CMD_SW_SUSPEND: c_int =
+ linux_raw_sys::general::LINUX_REBOOT_CMD_SW_SUSPEND as _;
+ pub(crate) const LINUX_REBOOT_CMD_KEXEC: c_int =
+ linux_raw_sys::general::LINUX_REBOOT_CMD_KEXEC as _;
+}
+#[cfg(feature = "system")]
+pub(crate) use reboot_symbols::*;
+
+#[cfg(any(
+ feature = "fs",
+ all(
+ linux_raw,
+ not(feature = "use-libc-auxv"),
+ not(feature = "use-explicitly-provided-auxv"),
+ any(
+ feature = "param",
+ feature = "runtime",
+ feature = "thread",
+ feature = "time",
+ target_arch = "x86",
+ )
+ )
+))]
+mod statx_flags {
+ pub(crate) use linux_raw_sys::general::{
+ STATX_ALL, STATX_ATIME, STATX_BASIC_STATS, STATX_BLOCKS, STATX_BTIME, STATX_CTIME,
+ STATX_DIOALIGN, STATX_GID, STATX_INO, STATX_MNT_ID, STATX_MODE, STATX_MTIME, STATX_NLINK,
+ STATX_SIZE, STATX_TYPE, STATX_UID,
+ };
+
+ pub(crate) use linux_raw_sys::general::{
+ STATX_ATTR_APPEND, STATX_ATTR_AUTOMOUNT, STATX_ATTR_COMPRESSED, STATX_ATTR_DAX,
+ STATX_ATTR_ENCRYPTED, STATX_ATTR_IMMUTABLE, STATX_ATTR_MOUNT_ROOT, STATX_ATTR_NODUMP,
+ STATX_ATTR_VERITY,
+ };
+}
+#[cfg(any(
+ feature = "fs",
+ all(
+ linux_raw,
+ not(feature = "use-libc-auxv"),
+ not(feature = "use-explicitly-provided-auxv"),
+ any(
+ feature = "param",
+ feature = "runtime",
+ feature = "thread",
+ feature = "time",
+ target_arch = "x86",
+ )
+ )
+))]
+pub(crate) use statx_flags::*;
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 00000000..901451ae
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/conv.rs
@@ -0,0 +1,1021 @@
+//! 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 as _, BorrowedFd, FromRawFd as _, RawFd};
+#[cfg(any(feature = "event", feature = "runtime", feature = "system"))]
+use super::io::errno::try_decode_error;
+#[cfg(target_pointer_width = "64")]
+use super::io::errno::try_decode_u64;
+#[cfg(not(debug_assertions))]
+use super::io::errno::{
+ decode_c_int_infallible, decode_c_uint_infallible, decode_usize_infallible,
+};
+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(feature = "time")]
+use super::time::types::TimerfdClockId;
+#[cfg(any(feature = "thread", feature = "time"))]
+use crate::clockid::ClockId;
+use crate::fd::OwnedFd;
+use crate::ffi::CStr;
+use crate::io;
+#[cfg(any(feature = "process", feature = "runtime", feature = "termios"))]
+use crate::pid::Pid;
+#[cfg(feature = "process")]
+use crate::process::Resource;
+#[cfg(any(feature = "process", feature = "runtime"))]
+use crate::signal::Signal;
+use crate::utils::{as_mut_ptr, as_ptr};
+use core::mem::MaybeUninit;
+use core::ptr::null_mut;
+#[cfg(any(feature = "thread", feature = "time"))]
+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::net::socklen_t;
+
+/// 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) -> Self {
+ raw_arg(c.cast())
+ }
+}
+
+impl<'a, Num: ArgNumber, T> From<*const T> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(c: *const T) -> Self {
+ 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 == crate::fs::ABS.as_raw_fd() || fd >= 0);
+
+ // Don't pass the `IORING_REGISTER_FILES_SKIP` sentry value this way.
+ #[cfg(feature = "io_uring")]
+ debug_assert_ne!(fd, crate::io_uring::IORING_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_just_addr_mut<T: Sized, Num: ArgNumber>(v: &mut [T]) -> ArgReg<'_, Num> {
+ raw_arg(v.as_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.
+#[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"))]
+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(any(
+ feature = "fs",
+ all(
+ not(feature = "use-libc-auxv"),
+ not(feature = "use-explicitly-provided-auxv"),
+ any(
+ feature = "param",
+ feature = "runtime",
+ feature = "thread",
+ feature = "time",
+ target_arch = "x86",
+ )
+ )
+))]
+pub(crate) mod fs {
+ use super::*;
+ use crate::fs::{FileType, Mode, OFlags};
+ #[cfg(target_pointer_width = "32")]
+ use linux_raw_sys::general::O_LARGEFILE;
+
+ impl<'a, Num: ArgNumber> From<Mode> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(mode: Mode) -> Self {
+ pass_usize(mode.bits() as usize)
+ }
+ }
+
+ 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)
+ }
+ }
+
+ impl<'a, Num: ArgNumber> From<crate::fs::AtFlags> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(flags: crate::fs::AtFlags) -> Self {
+ c_uint(flags.bits())
+ }
+ }
+
+ impl<'a, Num: ArgNumber> From<crate::fs::XattrFlags> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(flags: crate::fs::XattrFlags) -> Self {
+ c_uint(flags.bits())
+ }
+ }
+
+ impl<'a, Num: ArgNumber> From<crate::fs::inotify::CreateFlags> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(flags: crate::fs::inotify::CreateFlags) -> Self {
+ c_uint(flags.bits())
+ }
+ }
+
+ impl<'a, Num: ArgNumber> From<crate::fs::inotify::WatchFlags> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(flags: crate::fs::inotify::WatchFlags) -> Self {
+ c_uint(flags.bits())
+ }
+ }
+
+ impl<'a, Num: ArgNumber> From<crate::fs::MemfdFlags> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(flags: crate::fs::MemfdFlags) -> Self {
+ c_uint(flags.bits())
+ }
+ }
+
+ impl<'a, Num: ArgNumber> From<crate::fs::RenameFlags> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(flags: crate::fs::RenameFlags) -> Self {
+ c_uint(flags.bits())
+ }
+ }
+
+ impl<'a, Num: ArgNumber> From<crate::fs::StatxFlags> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(flags: crate::fs::StatxFlags) -> Self {
+ c_uint(flags.bits())
+ }
+ }
+
+ #[cfg(target_pointer_width = "32")]
+ #[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")]
+ #[inline]
+ const fn oflags_bits(oflags: OFlags) -> c::c_uint {
+ oflags.bits()
+ }
+
+ 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.
+ #[inline]
+ pub(crate) fn oflags_for_open_how(oflags: OFlags) -> u64 {
+ u64::from(oflags_bits(oflags))
+ }
+
+ impl<'a, Num: ArgNumber> From<crate::fs::FallocateFlags> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(flags: crate::fs::FallocateFlags) -> Self {
+ c_uint(flags.bits())
+ }
+ }
+
+ 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)
+ }
+ }
+
+ impl<'a, Num: ArgNumber> From<crate::fs::SealFlags> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(flags: crate::fs::SealFlags) -> Self {
+ c_uint(flags.bits())
+ }
+ }
+
+ 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 = "mount")]
+impl<'a, Num: ArgNumber> From<crate::backend::mount::types::MountFlagsArg> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(flags: crate::backend::mount::types::MountFlagsArg) -> Self {
+ c_uint(flags.0)
+ }
+}
+
+#[cfg(feature = "mount")]
+impl<'a, Num: ArgNumber> From<crate::backend::mount::types::UnmountFlags> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(flags: crate::backend::mount::types::UnmountFlags) -> Self {
+ c_uint(flags.bits())
+ }
+}
+
+#[cfg(feature = "mount")]
+impl<'a, Num: ArgNumber> From<crate::mount::FsConfigCmd> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(cmd: crate::mount::FsConfigCmd) -> Self {
+ c_uint(cmd as c::c_uint)
+ }
+}
+
+#[cfg(feature = "mount")]
+impl<'a, Num: ArgNumber> From<crate::backend::mount::types::FsOpenFlags> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(flags: crate::backend::mount::types::FsOpenFlags) -> Self {
+ c_uint(flags.bits())
+ }
+}
+
+#[cfg(feature = "mount")]
+impl<'a, Num: ArgNumber> From<crate::backend::mount::types::FsMountFlags> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(flags: crate::backend::mount::types::FsMountFlags) -> Self {
+ c_uint(flags.bits())
+ }
+}
+
+#[cfg(feature = "mount")]
+impl<'a, Num: ArgNumber> From<crate::backend::mount::types::MountAttrFlags> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(flags: crate::backend::mount::types::MountAttrFlags) -> Self {
+ c_uint(flags.bits())
+ }
+}
+
+#[cfg(feature = "mount")]
+impl<'a, Num: ArgNumber> From<crate::backend::mount::types::OpenTreeFlags> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(flags: crate::backend::mount::types::OpenTreeFlags) -> Self {
+ c_uint(flags.bits())
+ }
+}
+
+#[cfg(feature = "mount")]
+impl<'a, Num: ArgNumber> From<crate::backend::mount::types::FsPickFlags> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(flags: crate::backend::mount::types::FsPickFlags) -> Self {
+ c_uint(flags.bits())
+ }
+}
+
+#[cfg(feature = "mount")]
+impl<'a, Num: ArgNumber> From<crate::backend::mount::types::MoveMountFlags> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(flags: crate::backend::mount::types::MoveMountFlags) -> 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())
+ }
+}
+
+#[cfg(feature = "pipe")]
+impl<'a, Num: ArgNumber> From<crate::pipe::PipeFlags> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(flags: crate::pipe::PipeFlags) -> Self {
+ c_uint(flags.bits())
+ }
+}
+
+#[cfg(feature = "pipe")]
+impl<'a, Num: ArgNumber> From<crate::pipe::SpliceFlags> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(flags: crate::pipe::SpliceFlags) -> 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())
+ }
+}
+
+#[cfg(feature = "process")]
+impl<'a, Num: ArgNumber> From<crate::process::PidfdFlags> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(flags: crate::process::PidfdFlags) -> Self {
+ c_uint(flags.bits())
+ }
+}
+
+#[cfg(feature = "pty")]
+impl<'a, Num: ArgNumber> From<crate::pty::OpenptFlags> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(flags: crate::pty::OpenptFlags) -> Self {
+ c_uint(flags.bits())
+ }
+}
+
+#[cfg(feature = "thread")]
+impl<'a, Num: ArgNumber> From<crate::thread::UnshareFlags> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(flags: crate::thread::UnshareFlags) -> Self {
+ c_uint(flags.bits())
+ }
+}
+
+#[cfg(feature = "event")]
+impl<'a, Num: ArgNumber> From<crate::event::EventfdFlags> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(flags: crate::event::EventfdFlags) -> Self {
+ c_uint(flags.bits())
+ }
+}
+
+#[cfg(feature = "event")]
+impl<'a, Num: ArgNumber> From<crate::event::epoll::CreateFlags> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(flags: crate::event::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::MlockAllFlags> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(flags: crate::backend::mm::types::MlockAllFlags) -> 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())
+ }
+}
+
+#[cfg(feature = "thread")]
+impl<'a, Num: ArgNumber> From<crate::backend::thread::types::MembarrierCommand>
+ for ArgReg<'a, Num>
+{
+ #[inline]
+ fn from(cmd: crate::backend::thread::types::MembarrierCommand) -> Self {
+ c_uint(cmd as u32)
+ }
+}
+
+#[cfg(feature = "thread")]
+impl<'a, Num: ArgNumber> From<crate::thread::Cpuid> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(cpuid: crate::thread::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>> {
+ Ok(pass_usize(dev.try_into().map_err(|_err| io::Errno::INVAL)?))
+}
+
+/// Convert a `Resource` into a syscall argument.
+#[cfg(feature = "process")]
+impl<'a, Num: ArgNumber> From<Resource> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(resource: Resource) -> Self {
+ c_uint(resource as c::c_uint)
+ }
+}
+
+#[cfg(any(feature = "process", feature = "runtime", feature = "termios"))]
+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)
+ }
+}
+
+#[cfg(feature = "process")]
+#[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)
+}
+
+#[cfg(any(feature = "process", feature = "runtime"))]
+impl<'a, Num: ArgNumber> From<Signal> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(sig: Signal) -> Self {
+ pass_usize(sig.as_raw() as usize)
+ }
+}
+
+#[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::SocketFlags> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(flags: crate::net::SocketFlags) -> 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::backend::thread::futex::Operation,
+ crate::thread::futex::Flags,
+ )> for ArgReg<'a, Num>
+{
+ #[inline]
+ fn from(
+ pair: (
+ crate::backend::thread::futex::Operation,
+ crate::thread::futex::Flags,
+ ),
+ ) -> Self {
+ c_uint(pair.0 as u32 | pair.1.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<Option<crate::net::Protocol>> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(protocol: Option<crate::net::Protocol>) -> Self {
+ c_uint(match protocol {
+ Some(p) => p.0.get(),
+ None => 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())
+ }
+}
+
+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())
+ }
+}
+
+#[cfg(any(feature = "process", feature = "thread"))]
+impl<'a, Num: ArgNumber> From<crate::ugid::Uid> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(t: crate::ugid::Uid) -> Self {
+ c_uint(t.as_raw())
+ }
+}
+
+#[cfg(any(feature = "process", feature = "thread"))]
+impl<'a, Num: ArgNumber> From<crate::ugid::Gid> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(t: crate::ugid::Gid) -> Self {
+ c_uint(t.as_raw())
+ }
+}
+
+#[cfg(feature = "runtime")]
+impl<'a, Num: ArgNumber> From<crate::runtime::How> for ArgReg<'a, Num> {
+ #[inline]
+ fn from(flags: crate::runtime::How) -> Self {
+ c_uint(flags as u32)
+ }
+}
+
+/// 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(any(feature = "event", feature = "runtime", feature = "system"))]
+#[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 `c_int` returned from a syscall that effectively always
+/// returns a `c_int`.
+///
+/// # Safety
+///
+/// This function must only be used with return values from infallible
+/// syscalls.
+#[inline]
+pub(super) unsafe fn ret_c_int_infallible(raw: RetReg<R0>) -> c::c_int {
+ #[cfg(debug_assertions)]
+ {
+ try_decode_c_int(raw).unwrap()
+ }
+ #[cfg(not(debug_assertions))]
+ {
+ decode_c_int_infallible(raw)
+ }
+}
+
+/// Convert a `c_uint` returned from a syscall that effectively always
+/// returns a `c_uint`.
+///
+/// # Safety
+///
+/// This function must only be used with return values from infallible
+/// syscalls.
+#[inline]
+pub(super) unsafe fn ret_c_uint_infallible(raw: RetReg<R0>) -> c::c_uint {
+ #[cfg(debug_assertions)]
+ {
+ try_decode_c_uint(raw).unwrap()
+ }
+ #[cfg(not(debug_assertions))]
+ {
+ decode_c_uint_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/event/epoll.rs b/vendor/rustix/src/backend/linux_raw/event/epoll.rs
new file mode 100644
index 00000000..093129db
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/event/epoll.rs
@@ -0,0 +1,74 @@
+use crate::ffi;
+use bitflags::bitflags;
+
+bitflags! {
+ /// `EPOLL_*` for use with [`epoll::create`].
+ ///
+ /// [`epoll::create`]: crate::event::epoll::create
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct CreateFlags: ffi::c_uint {
+ /// `EPOLL_CLOEXEC`
+ const CLOEXEC = linux_raw_sys::general::EPOLL_CLOEXEC;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+bitflags! {
+ /// `EPOLL*` for use with [`epoll::add`].
+ ///
+ /// [`epoll::add`]: crate::event::epoll::add
+ #[repr(transparent)]
+ #[derive(Default, Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ 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;
+
+ /// `EPOLLRDNORM`
+ const RDNORM = linux_raw_sys::general::EPOLLRDNORM as u32;
+
+ /// `EPOLLRDBAND`
+ const RDBAND = linux_raw_sys::general::EPOLLRDBAND as u32;
+
+ /// `EPOLLWRNORM`
+ const WRNORM = linux_raw_sys::general::EPOLLWRNORM as u32;
+
+ /// `EPOLLWRBAND`
+ const WRBAND = linux_raw_sys::general::EPOLLWRBAND as u32;
+
+ /// `EPOLLMSG`
+ const MSG = linux_raw_sys::general::EPOLLMSG as u32;
+
+ /// `EPOLLRDHUP`
+ const RDHUP = linux_raw_sys::general::EPOLLRDHUP 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;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
diff --git a/vendor/rustix/src/backend/linux_raw/event/mod.rs b/vendor/rustix/src/backend/linux_raw/event/mod.rs
new file mode 100644
index 00000000..605de253
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/event/mod.rs
@@ -0,0 +1,4 @@
+pub mod epoll;
+pub(crate) mod poll_fd;
+pub(crate) mod syscalls;
+pub(crate) mod types;
diff --git a/vendor/rustix/src/backend/linux_raw/event/poll_fd.rs b/vendor/rustix/src/backend/linux_raw/event/poll_fd.rs
new file mode 100644
index 00000000..9de43f26
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/event/poll_fd.rs
@@ -0,0 +1,98 @@
+use crate::fd::{AsFd, BorrowedFd};
+use bitflags::bitflags;
+
+bitflags! {
+ /// `POLL*` flags for use with [`poll`].
+ ///
+ /// [`poll`]: crate::event::poll
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct PollFlags: u16 {
+ /// `POLLIN`
+ const IN = linux_raw_sys::general::POLLIN as u16;
+ /// `POLLPRI`
+ const PRI = linux_raw_sys::general::POLLPRI as u16;
+ /// `POLLOUT`
+ const OUT = linux_raw_sys::general::POLLOUT as u16;
+ /// `POLLRDNORM`
+ const RDNORM = linux_raw_sys::general::POLLRDNORM as u16;
+ /// `POLLWRNORM`
+ const WRNORM = linux_raw_sys::general::POLLWRNORM as u16;
+ /// `POLLRDBAND`
+ const RDBAND = linux_raw_sys::general::POLLRDBAND as u16;
+ /// `POLLWRBAND`
+ const WRBAND = linux_raw_sys::general::POLLWRBAND as u16;
+ /// `POLLERR`
+ const ERR = linux_raw_sys::general::POLLERR as u16;
+ /// `POLLHUP`
+ const HUP = linux_raw_sys::general::POLLHUP as u16;
+ /// `POLLNVAL`
+ const NVAL = linux_raw_sys::general::POLLNVAL as u16;
+ /// `POLLRDHUP`
+ const RDHUP = linux_raw_sys::general::POLLRDHUP as u16;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+/// `struct pollfd`—File descriptor and flags for use with [`poll`].
+///
+/// [`poll`]: crate::event::poll
+#[doc(alias = "pollfd")]
+#[repr(C)]
+#[derive(Debug, Clone)]
+pub struct PollFd<'fd> {
+ pub(crate) fd: BorrowedFd<'fd>,
+ pub(crate) events: u16,
+ pub(crate) revents: u16,
+}
+
+impl<'fd> PollFd<'fd> {
+ /// Constructs a new `PollFd` holding `fd` and `events`.
+ #[inline]
+ pub fn new<Fd: AsFd>(fd: &'fd Fd, events: PollFlags) -> Self {
+ Self::from_borrowed_fd(fd.as_fd(), events)
+ }
+
+ /// Sets the contained file descriptor to `fd`.
+ #[inline]
+ pub fn set_fd<Fd: AsFd>(&mut self, fd: &'fd Fd) {
+ self.fd = fd.as_fd();
+ }
+
+ /// Clears the ready events.
+ #[inline]
+ pub fn clear_revents(&mut self) {
+ self.revents = 0;
+ }
+
+ /// Constructs a new `PollFd` holding `fd` and `events`.
+ ///
+ /// This is the same as `new`, but can be used to avoid borrowing the
+ /// `BorrowedFd`, which can be tricky in situations where the `BorrowedFd`
+ /// is a temporary.
+ #[inline]
+ pub fn from_borrowed_fd(fd: BorrowedFd<'fd>, events: PollFlags) -> Self {
+ Self {
+ fd,
+ events: events.bits(),
+ revents: 0,
+ }
+ }
+
+ /// Returns the ready events.
+ #[inline]
+ pub fn revents(&self) -> PollFlags {
+ // Use `.unwrap()` here because in theory we know we know all the bits
+ // the OS might set here, but OS's have added extensions in the past.
+ PollFlags::from_bits(self.revents).unwrap()
+ }
+}
+
+impl<'fd> AsFd for PollFd<'fd> {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ self.fd.as_fd()
+ }
+}
diff --git a/vendor/rustix/src/backend/linux_raw/event/syscalls.rs b/vendor/rustix/src/backend/linux_raw/event/syscalls.rs
new file mode 100644
index 00000000..8a4e24bd
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/event/syscalls.rs
@@ -0,0 +1,358 @@
+//! linux_raw syscalls supporting `rustix::event`.
+//!
+//! # Safety
+//!
+//! See the `rustix::backend` module documentation for details.
+#![allow(unsafe_code, clippy::undocumented_unsafe_blocks)]
+
+use crate::backend::conv::{
+ by_ref, c_int, c_uint, opt_mut, opt_ref, pass_usize, ret, ret_c_int, ret_error, ret_owned_fd,
+ ret_usize, size_of, slice_mut, zero,
+};
+use crate::event::{epoll, EventfdFlags, FdSetElement, PollFd, Timespec};
+use crate::fd::{BorrowedFd, OwnedFd};
+use crate::io;
+use core::ptr::null_mut;
+use linux_raw_sys::general::{kernel_sigset_t, EPOLL_CTL_ADD, EPOLL_CTL_DEL, EPOLL_CTL_MOD};
+
+#[inline]
+pub(crate) fn poll(fds: &mut [PollFd<'_>], timeout: Option<&Timespec>) -> io::Result<usize> {
+ let (fds_addr_mut, fds_len) = slice_mut(fds);
+
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ // If we don't have Linux 5.1, and the timeout fits in a
+ // `__kernel_old_timespec`, use plain `ppoll`.
+ //
+ // We do this unconditionally, rather than trying `ppoll_time64` and
+ // falling back on `Errno::NOSYS`, because seccomp configurations will
+ // sometimes abort the process on syscalls they don't recognize.
+ #[cfg(not(feature = "linux_5_1"))]
+ {
+ use linux_raw_sys::general::__kernel_old_timespec;
+
+ // If we don't have a timeout, or if we can convert the timeout to
+ // a `__kernel_old_timespec`, the use `__NR_ppoll`.
+ fn convert(timeout: &Timespec) -> Option<__kernel_old_timespec> {
+ Some(__kernel_old_timespec {
+ tv_sec: timeout.tv_sec.try_into().ok()?,
+ tv_nsec: timeout.tv_nsec.try_into().ok()?,
+ })
+ }
+ let old_timeout = if let Some(timeout) = timeout {
+ match convert(timeout) {
+ // Could not convert timeout.
+ None => None,
+ // Could convert timeout. Ok!
+ Some(old_timeout) => Some(Some(old_timeout)),
+ }
+ } else {
+ // No timeout. Ok!
+ Some(None)
+ };
+ if let Some(mut old_timeout) = old_timeout {
+ // Call `ppoll`.
+ //
+ // Linux's `ppoll` mutates the timeout argument. Our public
+ // interface does not do this, because it's not portable to other
+ // platforms, so we create a temporary value to hide this behavior.
+ return ret_usize(syscall!(
+ __NR_ppoll,
+ fds_addr_mut,
+ fds_len,
+ opt_mut(old_timeout.as_mut()),
+ zero(),
+ size_of::<kernel_sigset_t, _>()
+ ));
+ }
+ }
+
+ // We either have Linux 5.1 or the timeout didn't fit in
+ // `__kernel_old_timespec` so `__NR_ppoll_time64` will either
+ // succeed or fail due to our having no other options.
+
+ // Call `ppoll_time64`.
+ //
+ // Linux's `ppoll_time64` mutates the timeout argument. Our public
+ // interface does not do this, because it's not portable to other
+ // platforms, so we create a temporary value to hide this behavior.
+ ret_usize(syscall!(
+ __NR_ppoll_time64,
+ fds_addr_mut,
+ fds_len,
+ opt_mut(timeout.copied().as_mut()),
+ zero(),
+ size_of::<kernel_sigset_t, _>()
+ ))
+ }
+
+ #[cfg(target_pointer_width = "64")]
+ unsafe {
+ // Call `ppoll`.
+ //
+ // Linux's `ppoll` mutates the timeout argument. Our public interface
+ // does not do this, because it's not portable to other platforms, so
+ // we create a temporary value to hide this behavior.
+ ret_usize(syscall!(
+ __NR_ppoll,
+ fds_addr_mut,
+ fds_len,
+ opt_mut(timeout.copied().as_mut()),
+ zero(),
+ size_of::<kernel_sigset_t, _>()
+ ))
+ }
+}
+
+pub(crate) unsafe fn select(
+ nfds: i32,
+ readfds: Option<&mut [FdSetElement]>,
+ writefds: Option<&mut [FdSetElement]>,
+ exceptfds: Option<&mut [FdSetElement]>,
+ timeout: Option<&crate::timespec::Timespec>,
+) -> io::Result<i32> {
+ let len = crate::event::fd_set_num_elements_for_bitvector(nfds);
+
+ let readfds = match readfds {
+ Some(readfds) => {
+ assert!(readfds.len() >= len);
+ readfds.as_mut_ptr()
+ }
+ None => null_mut(),
+ };
+ let writefds = match writefds {
+ Some(writefds) => {
+ assert!(writefds.len() >= len);
+ writefds.as_mut_ptr()
+ }
+ None => null_mut(),
+ };
+ let exceptfds = match exceptfds {
+ Some(exceptfds) => {
+ assert!(exceptfds.len() >= len);
+ exceptfds.as_mut_ptr()
+ }
+ None => null_mut(),
+ };
+
+ #[cfg(target_pointer_width = "32")]
+ {
+ // If we don't have Linux 5.1, and the timeout fits in a
+ // `__kernel_old_timespec`, use plain `pselect6`.
+ //
+ // We do this unconditionally, rather than trying `pselect6_time64` and
+ // falling back on `Errno::NOSYS`, because seccomp configurations will
+ // sometimes abort the process on syscalls they don't recognize.
+ #[cfg(not(feature = "linux_5_1"))]
+ {
+ use linux_raw_sys::general::__kernel_old_timespec;
+
+ // If we don't have a timeout, or if we can convert the timeout to
+ // a `__kernel_old_timespec`, the use `__NR_pselect6`.
+ fn convert(timeout: &Timespec) -> Option<__kernel_old_timespec> {
+ Some(__kernel_old_timespec {
+ tv_sec: timeout.tv_sec.try_into().ok()?,
+ tv_nsec: timeout.tv_nsec.try_into().ok()?,
+ })
+ }
+ let old_timeout = if let Some(timeout) = timeout {
+ match convert(timeout) {
+ // Could not convert timeout.
+ None => None,
+ // Could convert timeout. Ok!
+ Some(old_timeout) => Some(Some(old_timeout)),
+ }
+ } else {
+ // No timeout. Ok!
+ Some(None)
+ };
+ if let Some(mut old_timeout) = old_timeout {
+ // Call `pselect6`.
+ //
+ // Linux's `pselect6` mutates the timeout argument. Our public
+ // interface does not do this, because it's not portable to other
+ // platforms, so we create a temporary value to hide this behavior.
+ return ret_c_int(syscall!(
+ __NR_pselect6,
+ c_int(nfds),
+ readfds,
+ writefds,
+ exceptfds,
+ opt_mut(old_timeout.as_mut()),
+ zero()
+ ));
+ }
+ }
+
+ // We either have Linux 5.1 or the timeout didn't fit in
+ // `__kernel_old_timespec` so `__NR_pselect6_time64` will either
+ // succeed or fail due to our having no other options.
+
+ // Call `pselect6_time64`.
+ //
+ // Linux's `pselect6_time64` mutates the timeout argument. Our public
+ // interface does not do this, because it's not portable to other
+ // platforms, so we create a temporary value to hide this behavior.
+ ret_c_int(syscall!(
+ __NR_pselect6_time64,
+ c_int(nfds),
+ readfds,
+ writefds,
+ exceptfds,
+ opt_mut(timeout.copied().as_mut()),
+ zero()
+ ))
+ }
+
+ #[cfg(target_pointer_width = "64")]
+ {
+ // Call `pselect6`.
+ //
+ // Linux's `pselect6` mutates the timeout argument. Our public interface
+ // does not do this, because it's not portable to other platforms, so we
+ // create a temporary value to hide this behavior.
+ ret_c_int(syscall!(
+ __NR_pselect6,
+ c_int(nfds),
+ readfds,
+ writefds,
+ exceptfds,
+ opt_mut(timeout.copied().as_mut()),
+ zero()
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn epoll_create(flags: epoll::CreateFlags) -> io::Result<OwnedFd> {
+ // SAFETY: `__NR_epoll_create1` doesn't access any user memory.
+ unsafe { ret_owned_fd(syscall_readonly!(__NR_epoll_create1, flags)) }
+}
+
+#[inline]
+pub(crate) fn epoll_add(
+ epfd: BorrowedFd<'_>,
+ fd: BorrowedFd<'_>,
+ event: &epoll::Event,
+) -> io::Result<()> {
+ // SAFETY: `__NR_epoll_ctl` with `EPOLL_CTL_ADD` doesn't modify any user
+ // memory, and it only reads from `event`.
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_epoll_ctl,
+ epfd,
+ c_uint(EPOLL_CTL_ADD),
+ fd,
+ by_ref(event)
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn epoll_mod(
+ epfd: BorrowedFd<'_>,
+ fd: BorrowedFd<'_>,
+ event: &epoll::Event,
+) -> io::Result<()> {
+ // SAFETY: `__NR_epoll_ctl` with `EPOLL_CTL_MOD` doesn't modify any user
+ // memory, and it only reads from `event`.
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_epoll_ctl,
+ epfd,
+ c_uint(EPOLL_CTL_MOD),
+ fd,
+ by_ref(event)
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn epoll_del(epfd: BorrowedFd<'_>, fd: BorrowedFd<'_>) -> io::Result<()> {
+ // SAFETY: `__NR_epoll_ctl` with `EPOLL_CTL_DEL` doesn't access any user
+ // memory.
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_epoll_ctl,
+ epfd,
+ c_uint(EPOLL_CTL_DEL),
+ fd,
+ zero()
+ ))
+ }
+}
+
+#[inline]
+pub(crate) unsafe fn epoll_wait(
+ epfd: BorrowedFd<'_>,
+ events: (*mut crate::event::epoll::Event, usize),
+ timeout: Option<&Timespec>,
+) -> io::Result<usize> {
+ // If we don't have Linux 5.1, and the timeout fits in an `i32`, use plain
+ // `epoll_pwait`.
+ //
+ // We do this unconditionally, rather than trying `epoll_pwait2` and
+ // falling back on `Errno::NOSYS`, because seccomp configurations will
+ // sometimes abort the process on syscalls they don't recognize.
+ #[cfg(not(feature = "linux_5_11"))]
+ {
+ // If we don't have a timeout, or if we can convert the timeout to an
+ // `i32`, the use `__NR_epoll_pwait`.
+ let old_timeout = if let Some(timeout) = timeout {
+ // Try to convert the timeout; if this is `Some`, we're ok!
+ timeout.as_c_int_millis()
+ } else {
+ // No timeout. Ok!
+ Some(-1)
+ };
+ if let Some(old_timeout) = old_timeout {
+ // Call `epoll_pwait`.
+ return ret_usize(syscall!(
+ __NR_epoll_pwait,
+ epfd,
+ events.0,
+ pass_usize(events.1),
+ c_int(old_timeout),
+ zero()
+ ));
+ }
+ }
+
+ // Call `epoll_pwait2`.
+ //
+ // We either have Linux 5.1 or the timeout didn't fit in an `i32`, so
+ // `__NR_epoll_pwait2` will either succeed or fail due to our having no
+ // other options.
+ ret_usize(syscall!(
+ __NR_epoll_pwait2,
+ epfd,
+ events.0,
+ pass_usize(events.1),
+ opt_ref(timeout),
+ zero()
+ ))
+}
+
+#[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 pause() {
+ unsafe {
+ #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
+ let error = ret_error(syscall_readonly!(
+ __NR_ppoll,
+ zero(),
+ zero(),
+ zero(),
+ zero()
+ ));
+
+ #[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))]
+ let error = ret_error(syscall_readonly!(__NR_pause));
+
+ debug_assert_eq!(error, io::Errno::INTR);
+ }
+}
diff --git a/vendor/rustix/src/backend/linux_raw/event/types.rs b/vendor/rustix/src/backend/linux_raw/event/types.rs
new file mode 100644
index 00000000..9d320dfe
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/event/types.rs
@@ -0,0 +1,21 @@
+use crate::ffi;
+use bitflags::bitflags;
+
+bitflags! {
+ /// `EFD_*` flags for use with [`eventfd`].
+ ///
+ /// [`eventfd`]: crate::event::eventfd
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct EventfdFlags: ffi::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;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
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 00000000..31ebc543
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/fs/dir.rs
@@ -0,0 +1,373 @@
+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;
+#[cfg(feature = "process")]
+use crate::process::fchdir;
+use crate::utils::as_ptr;
+use alloc::borrow::ToOwned as _;
+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,
+
+ /// Have we seen any errors in this iteration?
+ any_errors: bool,
+
+ /// Should we rewind the stream on the next iteration?
+ rewind: bool,
+
+ /// The buffer for `linux_dirent64` entries.
+ buf: Vec<u8>,
+
+ /// Where we are in the buffer.
+ pos: usize,
+}
+
+impl Dir {
+ /// Take ownership of `fd` and construct a `Dir` that reads entries from
+ /// the given directory file descriptor.
+ #[inline]
+ pub fn new<Fd: Into<OwnedFd>>(fd: Fd) -> io::Result<Self> {
+ Self::_new(fd.into())
+ }
+
+ #[inline]
+ fn _new(fd: OwnedFd) -> io::Result<Self> {
+ Ok(Self {
+ fd,
+ any_errors: false,
+ rewind: false,
+ buf: Vec::new(),
+ pos: 0,
+ })
+ }
+
+ /// Borrow `fd` and 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,
+ any_errors: false,
+ rewind: false,
+ buf: Vec::new(),
+ pos: 0,
+ })
+ }
+
+ /// `rewinddir(self)`
+ #[inline]
+ pub fn rewind(&mut self) {
+ self.any_errors = false;
+ self.rewind = true;
+ self.pos = self.buf.len();
+ }
+
+ /// `seekdir(self, offset)`
+ ///
+ /// This function is only available on 64-bit platforms because it's
+ /// implemented using [`libc::seekdir`] which only supports offsets that
+ /// fit in a `c_long`.
+ ///
+ /// [`libc::seekdir`]: https://docs.rs/libc/*/arm-unknown-linux-gnueabihf/libc/fn.seekdir.html
+ // In the linux_raw backend here, we don't use `libc::seekdir` and don't
+ // have this limitation, but it's a goal of rustix to support the same API
+ // on both the linux_raw and libc backends.
+ #[cfg(target_pointer_width = "64")]
+ #[cfg_attr(docsrs, doc(cfg(target_pointer_width = "64")))]
+ #[doc(alias = "seekdir")]
+ #[inline]
+ pub fn seek(&mut self, offset: i64) -> io::Result<()> {
+ self.any_errors = false;
+ self.rewind = false;
+ self.pos = self.buf.len();
+ match io::retry_on_intr(|| {
+ crate::backend::fs::syscalls::_seek(self.fd.as_fd(), offset, SEEK_SET)
+ }) {
+ Ok(_) => Ok(()),
+ Err(err) => {
+ self.any_errors = true;
+ Err(err)
+ }
+ }
+ }
+
+ /// `readdir(self)`, where `None` means the end of the directory.
+ pub fn read(&mut self) -> Option<io::Result<DirEntry>> {
+ // If we've seen errors, don't continue to try to read anything
+ // further.
+ if self.any_errors {
+ return None;
+ }
+
+ // If a rewind was requested, seek to the beginning.
+ if self.rewind {
+ self.rewind = false;
+ match io::retry_on_intr(|| {
+ crate::backend::fs::syscalls::_seek(self.fd.as_fd(), 0, SEEK_SET)
+ }) {
+ Ok(_) => (),
+ Err(err) => {
+ self.any_errors = true;
+ 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_off = (as_ptr(&z.d_off) 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(err) => return Some(Err(err)),
+ }
+ }
+
+ // 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_len]).unwrap();
+ let name = name.to_owned();
+ assert!(name.as_bytes().len() <= self.buf.len() - name_start);
+
+ // Do an unaligned `u64` load for `d_ino`.
+ 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],
+ ]);
+
+ // Do an unaligned `i64` load for `d_off`.
+ let d_off = i64::from_ne_bytes([
+ self.buf[pos + offsetof_d_off],
+ self.buf[pos + offsetof_d_off + 1],
+ self.buf[pos + offsetof_d_off + 2],
+ self.buf[pos + offsetof_d_off + 3],
+ self.buf[pos + offsetof_d_off + 4],
+ self.buf[pos + offsetof_d_off + 5],
+ self.buf[pos + offsetof_d_off + 6],
+ self.buf[pos + offsetof_d_off + 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,
+ d_type,
+ d_reclen,
+ d_name: Default::default(),
+ };
+
+ Some(Ok(DirEntry {
+ d_ino,
+ d_off,
+ d_type,
+ name,
+ }))
+ }
+
+ #[must_use]
+ fn read_more(&mut self) -> Option<io::Result<()>> {
+ // The first few times we're called, we allocate a relatively small
+ // buffer, because many directories are small. If we're called more,
+ // use progressively larger allocations, up to a fixed maximum.
+ //
+ // The specific sizes and policy here have not been tuned in detail yet
+ // and may need to be adjusted. In doing so, we should be careful to
+ // avoid unbounded buffer growth. This buffer only exists to share the
+ // cost of a `getdents` call over many entries, so if it gets too big,
+ // cache and heap usage will outweigh the benefit. And ultimately,
+ // directories can contain more entries than we can allocate contiguous
+ // memory for, so we'll always need to cap the size at some point.
+ if self.buf.len() < 1024 * size_of::<linux_dirent64>() {
+ self.buf.reserve(32 * size_of::<linux_dirent64>());
+ }
+ self.buf.resize(self.buf.capacity(), 0);
+ let nread = match io::retry_on_intr(|| {
+ crate::backend::fs::syscalls::getdents(self.fd.as_fd(), &mut self.buf)
+ }) {
+ Ok(nread) => nread,
+ Err(io::Errno::NOENT) => {
+ self.any_errors = true;
+ return None;
+ }
+ Err(err) => {
+ self.any_errors = true;
+ 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)`
+ #[cfg(feature = "process")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "process")))]
+ #[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,
+ d_off: i64,
+ name: CString,
+}
+
+impl DirEntry {
+ /// Returns the file name of this directory entry.
+ #[inline]
+ pub fn file_name(&self) -> &CStr {
+ &self.name
+ }
+
+ /// Returns the “offset” of this directory entry. This is not a true
+ /// numerical offset but an opaque cookie that identifies a position in the
+ /// given stream.
+ #[inline]
+ pub fn offset(&self) -> i64 {
+ self.d_off
+ }
+
+ /// 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
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn dir_iterator_handles_io_errors() {
+ // create a dir, keep the FD, then delete the dir
+ let tmp = tempfile::tempdir().unwrap();
+ let fd = crate::fs::openat(
+ crate::fs::CWD,
+ tmp.path(),
+ crate::fs::OFlags::RDONLY | crate::fs::OFlags::CLOEXEC,
+ crate::fs::Mode::empty(),
+ )
+ .unwrap();
+
+ let file_fd = crate::fs::openat(
+ &fd,
+ tmp.path().join("test.txt"),
+ crate::fs::OFlags::WRONLY | crate::fs::OFlags::CREATE,
+ crate::fs::Mode::RWXU,
+ )
+ .unwrap();
+
+ let mut dir = Dir::read_from(&fd).unwrap();
+
+ // Reach inside the `Dir` and replace its directory with a file, which
+ // will cause the subsequent `getdents64` to fail.
+ crate::io::dup2(&file_fd, &mut dir.fd).unwrap();
+
+ assert!(matches!(dir.next(), Some(Err(_))));
+ assert!(dir.next().is_none());
+ }
+}
diff --git a/vendor/rustix/src/backend/linux_raw/fs/inotify.rs b/vendor/rustix/src/backend/linux_raw/fs/inotify.rs
new file mode 100644
index 00000000..eb13d910
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/fs/inotify.rs
@@ -0,0 +1,124 @@
+//! inotify support for working with inotify objects.
+
+use crate::ffi;
+use bitflags::bitflags;
+
+bitflags! {
+ /// `IN_*` for use with [`inotify::init`].
+ ///
+ /// [`inotify::init`]: crate::fs::inotify::init
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct CreateFlags: ffi::c_uint {
+ /// `IN_CLOEXEC`
+ const CLOEXEC = linux_raw_sys::general::IN_CLOEXEC;
+ /// `IN_NONBLOCK`
+ const NONBLOCK = linux_raw_sys::general::IN_NONBLOCK;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+bitflags! {
+ /// `IN*` for use with [`inotify::add_watch`].
+ ///
+ /// [`inotify::add_watch`]: crate::fs::inotify::add_watch
+ #[repr(transparent)]
+ #[derive(Default, Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct WatchFlags: ffi::c_uint {
+ /// `IN_ACCESS`
+ const ACCESS = linux_raw_sys::general::IN_ACCESS;
+ /// `IN_ATTRIB`
+ const ATTRIB = linux_raw_sys::general::IN_ATTRIB;
+ /// `IN_CLOSE_NOWRITE`
+ const CLOSE_NOWRITE = linux_raw_sys::general::IN_CLOSE_NOWRITE;
+ /// `IN_CLOSE_WRITE`
+ const CLOSE_WRITE = linux_raw_sys::general::IN_CLOSE_WRITE;
+ /// `IN_CREATE`
+ const CREATE = linux_raw_sys::general::IN_CREATE;
+ /// `IN_DELETE`
+ const DELETE = linux_raw_sys::general::IN_DELETE;
+ /// `IN_DELETE_SELF`
+ const DELETE_SELF = linux_raw_sys::general::IN_DELETE_SELF;
+ /// `IN_MODIFY`
+ const MODIFY = linux_raw_sys::general::IN_MODIFY;
+ /// `IN_MOVE_SELF`
+ const MOVE_SELF = linux_raw_sys::general::IN_MOVE_SELF;
+ /// `IN_MOVED_FROM`
+ const MOVED_FROM = linux_raw_sys::general::IN_MOVED_FROM;
+ /// `IN_MOVED_TO`
+ const MOVED_TO = linux_raw_sys::general::IN_MOVED_TO;
+ /// `IN_OPEN`
+ const OPEN = linux_raw_sys::general::IN_OPEN;
+
+ /// `IN_CLOSE`
+ const CLOSE = linux_raw_sys::general::IN_CLOSE;
+ /// `IN_MOVE`
+ const MOVE = linux_raw_sys::general::IN_MOVE;
+ /// `IN_ALL_EVENTS`
+ const ALL_EVENTS = linux_raw_sys::general::IN_ALL_EVENTS;
+
+ /// `IN_DONT_FOLLOW`
+ const DONT_FOLLOW = linux_raw_sys::general::IN_DONT_FOLLOW;
+ /// `IN_EXCL_UNLINK`
+ const EXCL_UNLINK = linux_raw_sys::general::IN_EXCL_UNLINK;
+ /// `IN_MASK_ADD`
+ const MASK_ADD = linux_raw_sys::general::IN_MASK_ADD;
+ /// `IN_MASK_CREATE`
+ const MASK_CREATE = linux_raw_sys::general::IN_MASK_CREATE;
+ /// `IN_ONESHOT`
+ const ONESHOT = linux_raw_sys::general::IN_ONESHOT;
+ /// `IN_ONLYDIR`
+ const ONLYDIR = linux_raw_sys::general::IN_ONLYDIR;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+bitflags! {
+ /// `IN*` for use with [`inotify::Reader`].
+ ///
+ /// [`inotify::Reader`]: crate::fs::inotify::InotifyReader
+ #[repr(transparent)]
+ #[derive(Default, Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct ReadFlags: ffi::c_uint {
+ /// `IN_ACCESS`
+ const ACCESS = linux_raw_sys::general::IN_ACCESS;
+ /// `IN_ATTRIB`
+ const ATTRIB = linux_raw_sys::general::IN_ATTRIB;
+ /// `IN_CLOSE_NOWRITE`
+ const CLOSE_NOWRITE = linux_raw_sys::general::IN_CLOSE_NOWRITE;
+ /// `IN_CLOSE_WRITE`
+ const CLOSE_WRITE = linux_raw_sys::general::IN_CLOSE_WRITE;
+ /// `IN_CREATE`
+ const CREATE = linux_raw_sys::general::IN_CREATE;
+ /// `IN_DELETE`
+ const DELETE = linux_raw_sys::general::IN_DELETE;
+ /// `IN_DELETE_SELF`
+ const DELETE_SELF = linux_raw_sys::general::IN_DELETE_SELF;
+ /// `IN_MODIFY`
+ const MODIFY = linux_raw_sys::general::IN_MODIFY;
+ /// `IN_MOVE_SELF`
+ const MOVE_SELF = linux_raw_sys::general::IN_MOVE_SELF;
+ /// `IN_MOVED_FROM`
+ const MOVED_FROM = linux_raw_sys::general::IN_MOVED_FROM;
+ /// `IN_MOVED_TO`
+ const MOVED_TO = linux_raw_sys::general::IN_MOVED_TO;
+ /// `IN_OPEN`
+ const OPEN = linux_raw_sys::general::IN_OPEN;
+
+ /// `IN_IGNORED`
+ const IGNORED = linux_raw_sys::general::IN_IGNORED;
+ /// `IN_ISDIR`
+ const ISDIR = linux_raw_sys::general::IN_ISDIR;
+ /// `IN_Q_OVERFLOW`
+ const QUEUE_OVERFLOW = linux_raw_sys::general::IN_Q_OVERFLOW;
+ /// `IN_UNMOUNT`
+ const UNMOUNT = linux_raw_sys::general::IN_UNMOUNT;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
diff --git a/vendor/rustix/src/backend/linux_raw/fs/makedev.rs b/vendor/rustix/src/backend/linux_raw/fs/makedev.rs
new file mode 100644
index 00000000..284ba2f1
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/fs/makedev.rs
@@ -0,0 +1,19 @@
+use crate::fs::Dev;
+
+#[inline]
+pub(crate) fn makedev(maj: u32, min: u32) -> Dev {
+ ((u64::from(maj) & 0xffff_f000_u64) << 32)
+ | ((u64::from(maj) & 0x0000_0fff_u64) << 8)
+ | ((u64::from(min) & 0xffff_ff00_u64) << 12)
+ | (u64::from(min) & 0x0000_00ff_u64)
+}
+
+#[inline]
+pub(crate) fn major(dev: Dev) -> u32 {
+ (((dev >> 31 >> 1) & 0xffff_f000) | ((dev >> 8) & 0x0000_0fff)) as u32
+}
+
+#[inline]
+pub(crate) fn minor(dev: Dev) -> u32 {
+ (((dev >> 12) & 0xffff_ff00) | (dev & 0x0000_00ff)) as u32
+}
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 00000000..9f53c5db
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/fs/mod.rs
@@ -0,0 +1,13 @@
+#[cfg(feature = "alloc")]
+pub(crate) mod dir;
+pub mod inotify;
+pub(crate) mod makedev;
+pub(crate) mod syscalls;
+pub(crate) mod types;
+
+// TODO: Fix linux-raw-sys to define ioctl codes for sparc.
+#[cfg(any(target_arch = "sparc", target_arch = "sparc64"))]
+pub(crate) const EXT4_IOC_RESIZE_FS: u32 = 0x8008_6610;
+
+#[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))]
+pub(crate) use linux_raw_sys::ioctl::EXT4_IOC_RESIZE_FS;
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 00000000..872dd8e3
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/fs/syscalls.rs
@@ -0,0 +1,1722 @@
+//! linux_raw syscalls supporting `rustix::fs`.
+//!
+//! # Safety
+//!
+//! See the `rustix::backend` module documentation for details.
+#![allow(unsafe_code)]
+#![allow(clippy::undocumented_unsafe_blocks)]
+
+use crate::backend::c;
+use crate::backend::conv::fs::oflags_for_open_how;
+#[cfg(any(
+ not(feature = "linux_4_11"),
+ target_arch = "aarch64",
+ target_arch = "riscv64",
+ target_arch = "mips",
+ target_arch = "mips32r6",
+))]
+use crate::backend::conv::zero;
+use crate::backend::conv::{
+ by_ref, c_int, c_uint, dev_t, opt_mut, pass_usize, raw_fd, ret, ret_c_int, ret_c_uint,
+ ret_infallible, ret_owned_fd, ret_usize, size_of, slice, slice_mut,
+};
+#[cfg(target_pointer_width = "64")]
+use crate::backend::conv::{loff_t, loff_t_from_u64, ret_u64};
+use crate::fd::{BorrowedFd, OwnedFd};
+use crate::ffi::CStr;
+#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
+use crate::fs::CWD;
+use crate::fs::{
+ inotify, Access, Advice, AtFlags, FallocateFlags, FileType, FlockOperation, Fsid, Gid,
+ MemfdFlags, Mode, OFlags, RenameFlags, ResolveFlags, SealFlags, SeekFrom, Stat, StatFs,
+ StatVfs, StatVfsMountFlags, Statx, StatxFlags, Timestamps, Uid, XattrFlags,
+};
+use crate::io;
+use core::mem::MaybeUninit;
+use core::num::NonZeroU64;
+#[cfg(any(target_arch = "mips64", target_arch = "mips64r6"))]
+use linux_raw_sys::general::stat as linux_stat64;
+use linux_raw_sys::general::{
+ open_how, AT_EACCESS, AT_FDCWD, AT_REMOVEDIR, AT_SYMLINK_NOFOLLOW, F_ADD_SEALS, F_GETFL,
+ F_GET_SEALS, F_SETFL, SEEK_CUR, SEEK_DATA, SEEK_END, SEEK_HOLE, SEEK_SET, STATX__RESERVED,
+};
+#[cfg(target_pointer_width = "32")]
+use {
+ crate::backend::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(path: &CStr, flags: OFlags, mode: Mode) -> io::Result<OwnedFd> {
+ // Always enable support for large files.
+ let flags = flags | OFlags::LARGEFILE;
+
+ #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
+ {
+ openat(CWD, path, flags, mode)
+ }
+ #[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))]
+ unsafe {
+ ret_owned_fd(syscall_readonly!(__NR_open, path, flags, mode))
+ }
+}
+
+#[inline]
+pub(crate) fn openat(
+ dirfd: BorrowedFd<'_>,
+ path: &CStr,
+ flags: OFlags,
+ mode: Mode,
+) -> io::Result<OwnedFd> {
+ // Always enable support for large files.
+ let flags = flags | OFlags::LARGEFILE;
+
+ unsafe { ret_owned_fd(syscall_readonly!(__NR_openat, dirfd, path, flags, mode)) }
+}
+
+#[inline]
+pub(crate) fn openat2(
+ dirfd: BorrowedFd<'_>,
+ path: &CStr,
+ mut flags: OFlags,
+ mode: Mode,
+ resolve: ResolveFlags,
+) -> io::Result<OwnedFd> {
+ // Enable support for large files, but not with `O_PATH` because
+ // `openat2` doesn't like those flags together.
+ if !flags.contains(OFlags::PATH) {
+ flags |= OFlags::from_bits_retain(c::O_LARGEFILE);
+ }
+
+ unsafe {
+ ret_owned_fd(syscall_readonly!(
+ __NR_openat2,
+ dirfd,
+ path,
+ 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(path: &CStr, mode: Mode) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_fchmodat,
+ raw_fd(AT_FDCWD),
+ path,
+ mode
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn chmodat(
+ dirfd: BorrowedFd<'_>,
+ path: &CStr,
+ mode: Mode,
+ flags: AtFlags,
+) -> io::Result<()> {
+ if flags == AtFlags::SYMLINK_NOFOLLOW {
+ return Err(io::Errno::OPNOTSUPP);
+ }
+ if !flags.is_empty() {
+ return Err(io::Errno::INVAL);
+ }
+ unsafe { ret(syscall_readonly!(__NR_fchmodat, dirfd, path, 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<'_>,
+ path: &CStr,
+ owner: Option<Uid>,
+ group: Option<Gid>,
+ flags: AtFlags,
+) -> io::Result<()> {
+ unsafe {
+ let (ow, gr) = crate::ugid::translate_fchown_args(owner, group);
+ ret(syscall_readonly!(
+ __NR_fchownat,
+ dirfd,
+ path,
+ c_uint(ow),
+ c_uint(gr),
+ flags
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn chown(path: &CStr, owner: Option<Uid>, group: Option<Gid>) -> io::Result<()> {
+ // Most architectures have a `chown` syscall.
+ #[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))]
+ unsafe {
+ let (ow, gr) = crate::ugid::translate_fchown_args(owner, group);
+ ret(syscall_readonly!(__NR_chown, path, c_uint(ow), c_uint(gr)))
+ }
+
+ // Aarch64 and RISC-V don't, so use `fchownat`.
+ #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
+ unsafe {
+ let (ow, gr) = crate::ugid::translate_fchown_args(owner, group);
+ ret(syscall_readonly!(
+ __NR_fchownat,
+ raw_fd(AT_FDCWD),
+ path,
+ c_uint(ow),
+ c_uint(gr),
+ zero()
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn fchown(fd: BorrowedFd<'_>, owner: Option<Uid>, group: Option<Gid>) -> io::Result<()> {
+ unsafe {
+ let (ow, gr) = crate::ugid::translate_fchown_args(owner, group);
+ ret(syscall_readonly!(__NR_fchown, fd, c_uint(ow), c_uint(gr)))
+ }
+}
+
+#[inline]
+pub(crate) fn mknodat(
+ dirfd: BorrowedFd<'_>,
+ path: &CStr,
+ file_type: FileType,
+ mode: Mode,
+ dev: u64,
+) -> io::Result<()> {
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_mknodat,
+ dirfd,
+ path,
+ (mode, file_type),
+ dev_t(dev)?
+ ))
+ }
+ #[cfg(target_pointer_width = "64")]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_mknodat,
+ dirfd,
+ path,
+ (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),
+ SeekFrom::Data(pos) => {
+ let pos: u64 = pos;
+ // Silently cast; we'll get `EINVAL` if the value is negative.
+ (SEEK_DATA, pos as i64)
+ }
+ SeekFrom::Hole(pos) => {
+ let pos: u64 = pos;
+ // Silently cast; we'll get `EINVAL` if the value is negative.
+ (SEEK_HOLE, pos as i64)
+ }
+ };
+ _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://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm64/kernel/sys32.c?h=v6.13#n89>
+ #[cfg(all(
+ target_pointer_width = "32",
+ any(
+ target_arch = "arm",
+ target_arch = "mips",
+ target_arch = "mips32r6",
+ 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 = "mips32r6",
+ 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: Option<NonZeroU64>,
+ advice: Advice,
+) -> io::Result<()> {
+ let len = match len {
+ None => 0,
+ Some(len) => len.get(),
+ };
+
+ // 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(any(target_arch = "mips", target_arch = "mips32r6"))]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_fadvise64,
+ fd,
+ zero(),
+ hi(pos),
+ lo(pos),
+ hi(len),
+ lo(len),
+ advice
+ ))
+ }
+
+ // For all other 32-bit architectures, use `fadvise64_64` so that we get a
+ // 64-bit length.
+ #[cfg(all(
+ target_pointer_width = "32",
+ not(any(
+ target_arch = "arm",
+ target_arch = "mips",
+ target_arch = "mips32r6",
+ target_arch = "powerpc"
+ )),
+ ))]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_fadvise64_64,
+ fd,
+ hi(pos),
+ lo(pos),
+ hi(len),
+ lo(len),
+ advice
+ ))
+ }
+
+ // On 64-bit architectures, use `fadvise64` which is sufficient.
+ #[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_readonly!(
+ __NR_flock,
+ fd,
+ c_uint(operation as c::c_uint)
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn syncfs(fd: BorrowedFd<'_>) -> io::Result<()> {
+ unsafe { ret(syscall_readonly!(__NR_syncfs, fd)) }
+}
+
+#[inline]
+pub(crate) fn sync() {
+ unsafe { ret_infallible(syscall_readonly!(__NR_sync)) }
+}
+
+#[inline]
+pub(crate) fn fstat(fd: BorrowedFd<'_>) -> io::Result<Stat> {
+ // 32-bit and mips64 Linux: `struct stat64` is not y2038 compatible; use
+ // `statx`.
+ //
+ // And, some old platforms don't support `statx`, and some fail with a
+ // confusing error code, so we call `crate::fs::statx` to handle that. If
+ // `statx` isn't available, fall back to the buggy system call.
+ #[cfg(any(
+ target_pointer_width = "32",
+ target_arch = "mips64",
+ target_arch = "mips64r6"
+ ))]
+ {
+ match crate::fs::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"),
+ not(target_arch = "mips64r6")
+ ))]
+ 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",
+ target_arch = "mips64r6",
+))]
+fn fstat_old(fd: BorrowedFd<'_>) -> io::Result<Stat> {
+ let mut result = MaybeUninit::<linux_stat64>::uninit();
+
+ #[cfg(any(target_arch = "mips64", target_arch = "mips64r6"))]
+ 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(path: &CStr) -> io::Result<Stat> {
+ // See the comments in `fstat` about using `crate::fs::statx` here.
+ #[cfg(any(
+ target_pointer_width = "32",
+ target_arch = "mips64",
+ target_arch = "mips64r6"
+ ))]
+ {
+ match crate::fs::statx(
+ crate::fs::CWD,
+ path,
+ AtFlags::empty(),
+ StatxFlags::BASIC_STATS,
+ ) {
+ Ok(x) => statx_to_stat(x),
+ Err(io::Errno::NOSYS) => stat_old(path),
+ Err(err) => Err(err),
+ }
+ }
+
+ #[cfg(all(
+ target_pointer_width = "64",
+ not(target_arch = "mips64"),
+ not(target_arch = "mips64r6"),
+ ))]
+ unsafe {
+ let mut result = MaybeUninit::<Stat>::uninit();
+ ret(syscall!(
+ __NR_newfstatat,
+ raw_fd(AT_FDCWD),
+ path,
+ &mut result,
+ c_uint(0)
+ ))?;
+ Ok(result.assume_init())
+ }
+}
+
+#[cfg(any(
+ target_pointer_width = "32",
+ target_arch = "mips64",
+ target_arch = "mips64r6"
+))]
+fn stat_old(path: &CStr) -> io::Result<Stat> {
+ let mut result = MaybeUninit::<linux_stat64>::uninit();
+
+ #[cfg(any(target_arch = "mips64", target_arch = "mips64r6"))]
+ unsafe {
+ ret(syscall!(
+ __NR_newfstatat,
+ raw_fd(AT_FDCWD),
+ path,
+ &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),
+ path,
+ &mut result,
+ c_uint(0)
+ ))?;
+ stat_to_stat(result.assume_init())
+ }
+}
+
+#[inline]
+pub(crate) fn statat(dirfd: BorrowedFd<'_>, path: &CStr, flags: AtFlags) -> io::Result<Stat> {
+ // See the comments in `fstat` about using `crate::fs::statx` here.
+ #[cfg(any(
+ target_pointer_width = "32",
+ target_arch = "mips64",
+ target_arch = "mips64r6"
+ ))]
+ {
+ match crate::fs::statx(dirfd, path, flags, StatxFlags::BASIC_STATS) {
+ Ok(x) => statx_to_stat(x),
+ Err(io::Errno::NOSYS) => statat_old(dirfd, path, flags),
+ Err(err) => Err(err),
+ }
+ }
+
+ #[cfg(all(
+ target_pointer_width = "64",
+ not(target_arch = "mips64"),
+ not(target_arch = "mips64r6"),
+ ))]
+ unsafe {
+ let mut result = MaybeUninit::<Stat>::uninit();
+ ret(syscall!(__NR_newfstatat, dirfd, path, &mut result, flags))?;
+ Ok(result.assume_init())
+ }
+}
+
+#[cfg(any(
+ target_pointer_width = "32",
+ target_arch = "mips64",
+ target_arch = "mips64r6"
+))]
+fn statat_old(dirfd: BorrowedFd<'_>, path: &CStr, flags: AtFlags) -> io::Result<Stat> {
+ let mut result = MaybeUninit::<linux_stat64>::uninit();
+
+ #[cfg(any(target_arch = "mips64", target_arch = "mips64r6"))]
+ unsafe {
+ ret(syscall!(__NR_newfstatat, dirfd, path, &mut result, flags))?;
+ stat_to_stat(result.assume_init())
+ }
+
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ ret(syscall!(__NR_fstatat64, dirfd, path, &mut result, flags))?;
+ stat_to_stat(result.assume_init())
+ }
+}
+
+#[inline]
+pub(crate) fn lstat(path: &CStr) -> io::Result<Stat> {
+ // See the comments in `fstat` about using `crate::fs::statx` here.
+ #[cfg(any(target_pointer_width = "32", target_arch = "mips64"))]
+ {
+ match crate::fs::statx(
+ crate::fs::CWD,
+ path,
+ AtFlags::SYMLINK_NOFOLLOW,
+ StatxFlags::BASIC_STATS,
+ ) {
+ Ok(x) => statx_to_stat(x),
+ Err(io::Errno::NOSYS) => lstat_old(path),
+ 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),
+ path,
+ &mut result,
+ c_uint(AT_SYMLINK_NOFOLLOW)
+ ))?;
+ Ok(result.assume_init())
+ }
+}
+
+#[cfg(any(target_pointer_width = "32", target_arch = "mips64"))]
+fn lstat_old(path: &CStr) -> io::Result<Stat> {
+ let mut result = MaybeUninit::<linux_stat64>::uninit();
+
+ #[cfg(any(target_arch = "mips64", target_arch = "mips64r6"))]
+ unsafe {
+ ret(syscall!(
+ __NR_newfstatat,
+ raw_fd(AT_FDCWD),
+ path,
+ &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),
+ path,
+ &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",
+ target_arch = "mips64r6"
+))]
+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: i64::from(x.stx_atime.tv_sec),
+ st_atime_nsec: x.stx_atime.tv_nsec.into(),
+ st_mtime: i64::from(x.stx_mtime.tv_sec),
+ st_mtime_nsec: x.stx_mtime.tv_nsec.into(),
+ st_ctime: i64::from(x.stx_ctime.tv_sec),
+ 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: i64::from(s64.st_atime.to_signed()),
+ st_atime_nsec: s64
+ .st_atime_nsec
+ .try_into()
+ .map_err(|_| io::Errno::OVERFLOW)?,
+ st_mtime: i64::from(s64.st_mtime.to_signed()),
+ st_mtime_nsec: s64
+ .st_mtime_nsec
+ .try_into()
+ .map_err(|_| io::Errno::OVERFLOW)?,
+ st_ctime: i64::from(s64.st_ctime.to_signed()),
+ 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(any(target_arch = "mips64", target_arch = "mips64r6"))]
+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: i64::from(s.st_atime.to_signed()),
+ st_atime_nsec: s
+ .st_atime_nsec
+ .try_into()
+ .map_err(|_| io::Errno::OVERFLOW)?,
+ st_mtime: i64::from(s.st_mtime.to_signed()),
+ st_mtime_nsec: s
+ .st_mtime_nsec
+ .try_into()
+ .map_err(|_| io::Errno::OVERFLOW)?,
+ st_ctime: i64::from(s.st_ctime.to_signed()),
+ 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<'_>,
+ path: &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,
+ path,
+ flags,
+ mask,
+ &mut statx_buf
+ ))?;
+ Ok(statx_buf.assume_init())
+ }
+}
+
+#[cfg(not(feature = "linux_4_11"))]
+#[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. This can use
+ // "readonly" because we don't pass it a buffer to mutate.
+ matches!(
+ ret(syscall_readonly!(
+ __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(path: &CStr) -> io::Result<StatFs> {
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ let mut result = MaybeUninit::<StatFs>::uninit();
+ ret(syscall!(
+ __NR_statfs64,
+ path,
+ 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, path, &mut result))?;
+ Ok(result.assume_init())
+ }
+}
+
+#[inline]
+pub(crate) fn statvfs(path: &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(path)?;
+
+ Ok(statfs_to_statvfs(statfs))
+}
+
+fn statfs_to_statvfs(statfs: StatFs) -> StatVfs {
+ let Fsid { val } = Fsid {
+ val: statfs.f_fsid.val,
+ };
+ 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: u64::from(f_fsid_val0 as u32) | (u64::from(f_fsid_val1 as u32) << 32),
+ f_flag: StatVfsMountFlags::from_bits_retain(statfs.f_flags as u64),
+ f_namemax: statfs.f_namelen as u64,
+ }
+}
+
+#[cfg(feature = "alloc")]
+#[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) unsafe fn readlinkat(
+ dirfd: BorrowedFd<'_>,
+ path: &CStr,
+ buf: (*mut u8, usize),
+) -> io::Result<usize> {
+ ret_usize(syscall!(
+ __NR_readlinkat,
+ dirfd,
+ path,
+ buf.0,
+ pass_usize(buf.1)
+ ))
+}
+
+#[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_retain)
+ }
+ #[cfg(target_pointer_width = "64")]
+ unsafe {
+ ret_c_uint(syscall_readonly!(__NR_fcntl, fd, c_uint(F_GETFL))).map(OFlags::from_bits_retain)
+ }
+}
+
+#[inline]
+pub(crate) fn fcntl_setfl(fd: BorrowedFd<'_>, flags: OFlags) -> io::Result<()> {
+ // Always enable support for large files.
+ let flags = flags | OFlags::from_bits_retain(c::O_LARGEFILE);
+
+ #[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_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_retain(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_retain(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 fcntl_lock(fd: BorrowedFd<'_>, operation: FlockOperation) -> io::Result<()> {
+ #[cfg(target_pointer_width = "64")]
+ use linux_raw_sys::general::{flock, F_SETLK, F_SETLKW};
+ #[cfg(target_pointer_width = "32")]
+ use linux_raw_sys::general::{flock64 as flock, F_SETLK64 as F_SETLK, F_SETLKW64 as F_SETLKW};
+ use linux_raw_sys::general::{F_RDLCK, F_UNLCK, F_WRLCK};
+
+ let (cmd, l_type) = match operation {
+ FlockOperation::LockShared => (F_SETLKW, F_RDLCK),
+ FlockOperation::LockExclusive => (F_SETLKW, F_WRLCK),
+ FlockOperation::Unlock => (F_SETLKW, F_UNLCK),
+ FlockOperation::NonBlockingLockShared => (F_SETLK, F_RDLCK),
+ FlockOperation::NonBlockingLockExclusive => (F_SETLK, F_WRLCK),
+ FlockOperation::NonBlockingUnlock => (F_SETLK, F_UNLCK),
+ };
+
+ let lock = flock {
+ l_type: l_type as _,
+
+ // When `l_len` is zero, this locks all the bytes from
+ // `l_whence`/`l_start` to the end of the file, even as the
+ // file grows dynamically.
+ l_whence: SEEK_SET as _,
+ l_start: 0,
+ l_len: 0,
+
+ // Unused.
+ l_pid: 0,
+ };
+
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_fcntl64,
+ fd,
+ c_uint(cmd),
+ by_ref(&lock)
+ ))
+ }
+ #[cfg(target_pointer_width = "64")]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_fcntl,
+ fd,
+ c_uint(cmd),
+ by_ref(&lock)
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn rename(old_path: &CStr, new_path: &CStr) -> io::Result<()> {
+ #[cfg(target_arch = "riscv64")]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_renameat2,
+ raw_fd(AT_FDCWD),
+ old_path,
+ raw_fd(AT_FDCWD),
+ new_path,
+ c_uint(0)
+ ))
+ }
+ #[cfg(not(target_arch = "riscv64"))]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_renameat,
+ raw_fd(AT_FDCWD),
+ old_path,
+ raw_fd(AT_FDCWD),
+ new_path
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn renameat(
+ old_dirfd: BorrowedFd<'_>,
+ old_path: &CStr,
+ new_dirfd: BorrowedFd<'_>,
+ new_path: &CStr,
+) -> io::Result<()> {
+ #[cfg(target_arch = "riscv64")]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_renameat2,
+ old_dirfd,
+ old_path,
+ new_dirfd,
+ new_path,
+ c_uint(0)
+ ))
+ }
+ #[cfg(not(target_arch = "riscv64"))]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_renameat,
+ old_dirfd,
+ old_path,
+ new_dirfd,
+ new_path
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn renameat2(
+ old_dirfd: BorrowedFd<'_>,
+ old_path: &CStr,
+ new_dirfd: BorrowedFd<'_>,
+ new_path: &CStr,
+ flags: RenameFlags,
+) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_renameat2,
+ old_dirfd,
+ old_path,
+ new_dirfd,
+ new_path,
+ flags
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn unlink(path: &CStr) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_unlinkat,
+ raw_fd(AT_FDCWD),
+ path,
+ c_uint(0)
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn unlinkat(dirfd: BorrowedFd<'_>, path: &CStr, flags: AtFlags) -> io::Result<()> {
+ unsafe { ret(syscall_readonly!(__NR_unlinkat, dirfd, path, flags)) }
+}
+
+#[inline]
+pub(crate) fn rmdir(path: &CStr) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_unlinkat,
+ raw_fd(AT_FDCWD),
+ path,
+ c_uint(AT_REMOVEDIR)
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn link(old_path: &CStr, new_path: &CStr) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_linkat,
+ raw_fd(AT_FDCWD),
+ old_path,
+ raw_fd(AT_FDCWD),
+ new_path,
+ c_uint(0)
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn linkat(
+ old_dirfd: BorrowedFd<'_>,
+ old_path: &CStr,
+ new_dirfd: BorrowedFd<'_>,
+ new_path: &CStr,
+ flags: AtFlags,
+) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_linkat,
+ old_dirfd,
+ old_path,
+ new_dirfd,
+ new_path,
+ flags
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn symlink(old_path: &CStr, new_path: &CStr) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_symlinkat,
+ old_path,
+ raw_fd(AT_FDCWD),
+ new_path
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn symlinkat(old_path: &CStr, dirfd: BorrowedFd<'_>, new_path: &CStr) -> io::Result<()> {
+ unsafe { ret(syscall_readonly!(__NR_symlinkat, old_path, dirfd, new_path)) }
+}
+
+#[inline]
+pub(crate) fn mkdir(path: &CStr, mode: Mode) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_mkdirat,
+ raw_fd(AT_FDCWD),
+ path,
+ mode
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn mkdirat(dirfd: BorrowedFd<'_>, path: &CStr, mode: Mode) -> io::Result<()> {
+ unsafe { ret(syscall_readonly!(__NR_mkdirat, dirfd, path, mode)) }
+}
+
+#[cfg(feature = "alloc")]
+#[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 getdents_uninit(
+ fd: BorrowedFd<'_>,
+ dirent: &mut [MaybeUninit<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<'_>,
+ path: &CStr,
+ times: &Timestamps,
+ flags: AtFlags,
+) -> io::Result<()> {
+ _utimensat(dirfd, Some(path), times, flags)
+}
+
+#[inline]
+fn _utimensat(
+ dirfd: BorrowedFd<'_>,
+ path: Option<&CStr>,
+ times: &Timestamps,
+ flags: AtFlags,
+) -> io::Result<()> {
+ // `utimensat_time64` was introduced in Linux 5.1. The old `utimensat`
+ // syscall is not y2038-compatible on 32-bit architectures.
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ match ret(syscall_readonly!(
+ __NR_utimensat_time64,
+ dirfd,
+ path,
+ by_ref(times),
+ flags
+ )) {
+ Err(io::Errno::NOSYS) => _utimensat_old(dirfd, path, times, flags),
+ otherwise => otherwise,
+ }
+ }
+ #[cfg(target_pointer_width = "64")]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_utimensat,
+ dirfd,
+ path,
+ by_ref(times),
+ flags
+ ))
+ }
+}
+
+#[cfg(target_pointer_width = "32")]
+unsafe fn _utimensat_old(
+ dirfd: BorrowedFd<'_>,
+ path: Option<&CStr>,
+ times: &Timestamps,
+ flags: AtFlags,
+) -> io::Result<()> {
+ // See the comments in `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,
+ path,
+ old_times_addr,
+ flags
+ ))
+}
+
+#[inline]
+pub(crate) fn futimens(fd: BorrowedFd<'_>, times: &Timestamps) -> io::Result<()> {
+ _utimensat(fd, None, times, AtFlags::empty())
+}
+
+#[inline]
+pub(crate) fn access(path: &CStr, access: Access) -> io::Result<()> {
+ #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
+ {
+ accessat_noflags(CWD, path, access)
+ }
+
+ #[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))]
+ unsafe {
+ ret(syscall_readonly!(__NR_access, path, access))
+ }
+}
+
+pub(crate) fn accessat(
+ dirfd: BorrowedFd<'_>,
+ path: &CStr,
+ access: Access,
+ flags: AtFlags,
+) -> io::Result<()> {
+ if !flags
+ .difference(AtFlags::EACCESS | AtFlags::SYMLINK_NOFOLLOW)
+ .is_empty()
+ {
+ return Err(io::Errno::INVAL);
+ }
+
+ // Linux's `faccessat` syscall doesn't have a flags argument, so if we have
+ // any flags, use the newer `faccessat2` introduced in Linux 5.8 which
+ // does. Unless we're on Android where using newer system calls can cause
+ // seccomp to abort the process.
+ #[cfg(not(target_os = "android"))]
+ if !flags.is_empty() {
+ unsafe {
+ match ret(syscall_readonly!(
+ __NR_faccessat2,
+ dirfd,
+ path,
+ access,
+ flags
+ )) {
+ Ok(()) => return Ok(()),
+ Err(io::Errno::NOSYS) => {}
+ Err(other) => return Err(other),
+ }
+ }
+ }
+
+ // 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::backend::ugid::syscalls::getuid()
+ == crate::backend::ugid::syscalls::geteuid()
+ && crate::backend::ugid::syscalls::getgid()
+ == crate::backend::ugid::syscalls::getegid())
+ {
+ return accessat_noflags(dirfd, path, access);
+ }
+
+ Err(io::Errno::NOSYS)
+}
+
+#[inline]
+fn accessat_noflags(dirfd: BorrowedFd<'_>, path: &CStr, access: Access) -> io::Result<()> {
+ unsafe { ret(syscall_readonly!(__NR_faccessat, dirfd, path, access)) }
+}
+
+#[inline]
+pub(crate) fn copy_file_range(
+ fd_in: BorrowedFd<'_>,
+ off_in: Option<&mut u64>,
+ fd_out: BorrowedFd<'_>,
+ off_out: Option<&mut u64>,
+ len: usize,
+) -> 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(0)
+ ))
+ }
+}
+
+#[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)
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn inotify_init1(flags: inotify::CreateFlags) -> io::Result<OwnedFd> {
+ unsafe { ret_owned_fd(syscall_readonly!(__NR_inotify_init1, flags)) }
+}
+
+#[inline]
+pub(crate) fn inotify_add_watch(
+ infd: BorrowedFd<'_>,
+ path: &CStr,
+ flags: inotify::WatchFlags,
+) -> io::Result<i32> {
+ unsafe { ret_c_int(syscall_readonly!(__NR_inotify_add_watch, infd, path, flags)) }
+}
+
+#[inline]
+pub(crate) fn inotify_rm_watch(infd: BorrowedFd<'_>, wfd: i32) -> io::Result<()> {
+ unsafe { ret(syscall_readonly!(__NR_inotify_rm_watch, infd, c_int(wfd))) }
+}
+
+#[inline]
+pub(crate) unsafe fn getxattr(
+ path: &CStr,
+ name: &CStr,
+ value: (*mut u8, usize),
+) -> io::Result<usize> {
+ ret_usize(syscall!(
+ __NR_getxattr,
+ path,
+ name,
+ value.0,
+ pass_usize(value.1)
+ ))
+}
+
+#[inline]
+pub(crate) unsafe fn lgetxattr(
+ path: &CStr,
+ name: &CStr,
+ value: (*mut u8, usize),
+) -> io::Result<usize> {
+ ret_usize(syscall!(
+ __NR_lgetxattr,
+ path,
+ name,
+ value.0,
+ pass_usize(value.1)
+ ))
+}
+
+#[inline]
+pub(crate) unsafe fn fgetxattr(
+ fd: BorrowedFd<'_>,
+ name: &CStr,
+ value: (*mut u8, usize),
+) -> io::Result<usize> {
+ ret_usize(syscall!(
+ __NR_fgetxattr,
+ fd,
+ name,
+ value.0,
+ pass_usize(value.1)
+ ))
+}
+
+#[inline]
+pub(crate) fn setxattr(
+ path: &CStr,
+ name: &CStr,
+ value: &[u8],
+ flags: XattrFlags,
+) -> io::Result<()> {
+ let (value_addr, value_len) = slice(value);
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_setxattr,
+ path,
+ name,
+ value_addr,
+ value_len,
+ flags
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn lsetxattr(
+ path: &CStr,
+ name: &CStr,
+ value: &[u8],
+ flags: XattrFlags,
+) -> io::Result<()> {
+ let (value_addr, value_len) = slice(value);
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_lsetxattr,
+ path,
+ name,
+ value_addr,
+ value_len,
+ flags
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn fsetxattr(
+ fd: BorrowedFd<'_>,
+ name: &CStr,
+ value: &[u8],
+ flags: XattrFlags,
+) -> io::Result<()> {
+ let (value_addr, value_len) = slice(value);
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_fsetxattr,
+ fd,
+ name,
+ value_addr,
+ value_len,
+ flags
+ ))
+ }
+}
+
+#[inline]
+pub(crate) unsafe fn listxattr(path: &CStr, list: (*mut u8, usize)) -> io::Result<usize> {
+ ret_usize(syscall!(__NR_listxattr, path, list.0, pass_usize(list.1)))
+}
+
+#[inline]
+pub(crate) unsafe fn llistxattr(path: &CStr, list: (*mut u8, usize)) -> io::Result<usize> {
+ ret_usize(syscall!(__NR_llistxattr, path, list.0, pass_usize(list.1)))
+}
+
+#[inline]
+pub(crate) unsafe fn flistxattr(fd: BorrowedFd<'_>, list: (*mut u8, usize)) -> io::Result<usize> {
+ ret_usize(syscall!(__NR_flistxattr, fd, list.0, pass_usize(list.1)))
+}
+
+#[inline]
+pub(crate) fn removexattr(path: &CStr, name: &CStr) -> io::Result<()> {
+ unsafe { ret(syscall_readonly!(__NR_removexattr, path, name)) }
+}
+
+#[inline]
+pub(crate) fn lremovexattr(path: &CStr, name: &CStr) -> io::Result<()> {
+ unsafe { ret(syscall_readonly!(__NR_lremovexattr, path, name)) }
+}
+
+#[inline]
+pub(crate) fn fremovexattr(fd: BorrowedFd<'_>, name: &CStr) -> io::Result<()> {
+ unsafe { ret(syscall_readonly!(__NR_fremovexattr, fd, name)) }
+}
+
+// Some linux_raw_sys structs have unsigned types for values which are
+// interpreted as signed. This defines a utility or casting to the
+// same-sized signed type.
+#[cfg(any(
+ target_pointer_width = "32",
+ target_arch = "mips64",
+ target_arch = "mips64r6"
+))]
+mod to_signed {
+ pub(super) trait ToSigned {
+ type Signed;
+ fn to_signed(self) -> Self::Signed;
+ }
+ impl ToSigned for u32 {
+ type Signed = i32;
+
+ fn to_signed(self) -> Self::Signed {
+ self as _
+ }
+ }
+ impl ToSigned for i32 {
+ type Signed = i32;
+
+ fn to_signed(self) -> Self::Signed {
+ self
+ }
+ }
+ impl ToSigned for u64 {
+ type Signed = i64;
+
+ fn to_signed(self) -> Self::Signed {
+ self as _
+ }
+ }
+ impl ToSigned for i64 {
+ type Signed = i64;
+
+ fn to_signed(self) -> Self::Signed {
+ self
+ }
+ }
+}
+#[cfg(any(
+ target_pointer_width = "32",
+ target_arch = "mips64",
+ target_arch = "mips64r6"
+))]
+use to_signed::*;
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_sizes() {
+ assert_eq_size!(linux_raw_sys::general::__kernel_loff_t, u64);
+ assert_eq_align!(linux_raw_sys::general::__kernel_loff_t, u64);
+
+ // Assert that `Timestamps` has the expected layout.
+ assert_eq_size!([linux_raw_sys::general::__kernel_timespec; 2], Timestamps);
+ assert_eq_align!([linux_raw_sys::general::__kernel_timespec; 2], Timestamps);
+ }
+}
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 00000000..ce6461c3
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/fs/types.rs
@@ -0,0 +1,848 @@
+use crate::ffi;
+use bitflags::bitflags;
+
+bitflags! {
+ /// `*_OK` constants for use with [`accessat`].
+ ///
+ /// [`accessat`]: fn.accessat.html
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct Access: ffi::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;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+bitflags! {
+ /// `AT_*` constants for use with [`openat`], [`statat`], and other `*at`
+ /// functions.
+ ///
+ /// [`openat`]: crate::fs::openat
+ /// [`statat`]: crate::fs::statat
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct AtFlags: ffi::c_uint {
+ /// `AT_SYMLINK_NOFOLLOW`
+ const SYMLINK_NOFOLLOW = linux_raw_sys::general::AT_SYMLINK_NOFOLLOW;
+
+ /// `AT_EACCESS`
+ const EACCESS = linux_raw_sys::general::AT_EACCESS;
+
+ /// `AT_REMOVEDIR`
+ const REMOVEDIR = linux_raw_sys::general::AT_REMOVEDIR;
+
+ /// `AT_SYMLINK_FOLLOW`
+ const SYMLINK_FOLLOW = linux_raw_sys::general::AT_SYMLINK_FOLLOW;
+
+ /// `AT_NO_AUTOMOUNT`
+ const NO_AUTOMOUNT = linux_raw_sys::general::AT_NO_AUTOMOUNT;
+
+ /// `AT_EMPTY_PATH`
+ const EMPTY_PATH = linux_raw_sys::general::AT_EMPTY_PATH;
+
+ /// `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;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+bitflags! {
+ /// `S_I*` constants for use with [`openat`], [`chmodat`], and [`fchmod`].
+ ///
+ /// [`openat`]: crate::fs::openat
+ /// [`chmodat`]: crate::fs::chmodat
+ /// [`fchmod`]: crate::fs::fchmod
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ 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;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+impl Mode {
+ /// Construct a `Mode` from the mode bits of the `st_mode` field of a
+ /// `Mode`.
+ #[inline]
+ pub const fn from_raw_mode(st_mode: RawMode) -> Self {
+ Self::from_bits_truncate(st_mode & !linux_raw_sys::general::S_IFMT)
+ }
+
+ /// Construct an `st_mode` value from a `Mode`.
+ #[inline]
+ pub const fn as_raw_mode(self) -> RawMode {
+ self.bits()
+ }
+}
+
+impl From<RawMode> for Mode {
+ /// Support conversions from raw mode values to `Mode`.
+ ///
+ /// ```
+ /// use rustix::fs::{Mode, RawMode};
+ /// assert_eq!(Mode::from(0o700), Mode::RWXU);
+ /// ```
+ #[inline]
+ fn from(st_mode: RawMode) -> Self {
+ Self::from_raw_mode(st_mode)
+ }
+}
+
+impl From<Mode> for RawMode {
+ /// Support conversions from `Mode` to raw mode values.
+ ///
+ /// ```
+ /// use rustix::fs::{Mode, RawMode};
+ /// assert_eq!(RawMode::from(Mode::RWXU), 0o700);
+ /// ```
+ #[inline]
+ fn from(mode: Mode) -> Self {
+ mode.as_raw_mode()
+ }
+}
+
+bitflags! {
+ /// `O_*` constants for use with [`openat`].
+ ///
+ /// [`openat`]: crate::fs::openat
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct OFlags: ffi::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.
+ ///
+ /// On some platforms, `PATH` may be included in `ACCMODE`, when
+ /// sometimes we really just want the read/write bits. Caution is
+ /// indicated, as the presence of `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`
+ const DSYNC = linux_raw_sys::general::O_SYNC;
+
+ /// `O_EXCL`
+ const EXCL = linux_raw_sys::general::O_EXCL;
+
+ /// `O_FSYNC`
+ 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`
+ ///
+ /// This is not equal to `RDONLY | WRONLY`. It's a distinct flag.
+ const RDWR = linux_raw_sys::general::O_RDWR;
+
+ /// `O_NOCTTY`
+ const NOCTTY = linux_raw_sys::general::O_NOCTTY;
+
+ /// `O_RSYNC`
+ 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;
+
+ /// `O_DIRECT`
+ const DIRECT = linux_raw_sys::general::O_DIRECT;
+
+ /// `O_LARGEFILE`
+ ///
+ /// Rustix and/or libc will automatically set this flag when
+ /// appropriate in the [`rustix::fs::open`] family of functions, so
+ /// typical users do not need to care about it. It may be reported in
+ /// the return of `fcntl_getfl`, though.
+ const LARGEFILE = linux_raw_sys::general::O_LARGEFILE;
+
+ /// `O_ASYNC`, `FASYNC`
+ ///
+ /// This flag can't be used with the [`rustix::fs::open`] family of
+ /// functions, use [`rustix::fs::fcntl_setfl`] instead.
+ const ASYNC = linux_raw_sys::general::FASYNC;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+bitflags! {
+ /// `RESOLVE_*` constants for use with [`openat2`].
+ ///
+ /// [`openat2`]: crate::fs::openat2
+ #[repr(transparent)]
+ #[derive(Default, Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ 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;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+bitflags! {
+ /// `RENAME_*` constants for use with [`renameat_with`].
+ ///
+ /// [`renameat_with`]: crate::fs::renameat_with
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct RenameFlags: ffi::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;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+/// `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`
+ #[doc(alias = "IFO")]
+ 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 a `FileType`.
+ #[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 `c::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
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct MemfdFlags: ffi::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_NOEXEC_SEAL` (since Linux 6.3)
+ const NOEXEC_SEAL = linux_raw_sys::general::MFD_NOEXEC_SEAL;
+ /// `MFD_EXEC` (since Linux 6.3)
+ const EXEC = linux_raw_sys::general::MFD_EXEC;
+
+ /// `MFD_HUGE_64KB`
+ const HUGE_64KB = linux_raw_sys::general::MFD_HUGE_64KB;
+ /// `MFD_HUGE_512KB`
+ 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;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+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
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ 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;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+bitflags! {
+ /// `FALLOC_FL_*` constants for use with [`fallocate`].
+ ///
+ /// [`fallocate`]: crate::fs::fallocate
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ 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;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+bitflags! {
+ /// `ST_*` constants for use with [`StatVfs`].
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ 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;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+/// `LOCK_*` constants for use with [`flock`] and [`fcntl_lock`].
+///
+/// [`flock`]: crate::fs::flock
+/// [`fcntl_lock`]: crate::fs::fcntl_lock
+#[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 with `struct stat64` and mips64 with `struct stat`, Linux's
+// `st_mtime` and friends are 32-bit, 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",
+ target_arch = "mips64r6"
+))]
+#[derive(Debug, Copy, Clone)]
+#[allow(missing_docs)]
+#[non_exhaustive]
+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: i64,
+ pub st_atime_nsec: u32,
+ pub st_mtime: i64,
+ pub st_mtime_nsec: u32,
+ pub st_ctime: i64,
+ 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
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+#[allow(missing_docs)]
+#[non_exhaustive]
+#[cfg(target_arch = "x86_64")]
+pub struct Stat {
+ pub st_dev: ffi::c_ulong,
+ pub st_ino: ffi::c_ulong,
+ pub st_nlink: ffi::c_ulong,
+ pub st_mode: ffi::c_uint,
+ pub st_uid: ffi::c_uint,
+ pub st_gid: ffi::c_uint,
+ pub(crate) __pad0: ffi::c_uint,
+ pub st_rdev: ffi::c_ulong,
+ pub st_size: ffi::c_long,
+ pub st_blksize: ffi::c_long,
+ pub st_blocks: ffi::c_long,
+ pub st_atime: ffi::c_long,
+ pub st_atime_nsec: ffi::c_ulong,
+ pub st_mtime: ffi::c_long,
+ pub st_mtime_nsec: ffi::c_ulong,
+ pub st_ctime: ffi::c_long,
+ pub st_ctime_nsec: ffi::c_ulong,
+ pub(crate) __unused: [ffi::c_long; 3],
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+#[allow(missing_docs)]
+#[non_exhaustive]
+#[cfg(target_arch = "aarch64")]
+pub struct Stat {
+ pub st_dev: ffi::c_ulong,
+ pub st_ino: ffi::c_ulong,
+ pub st_mode: ffi::c_uint,
+ pub st_nlink: ffi::c_uint,
+ pub st_uid: ffi::c_uint,
+ pub st_gid: ffi::c_uint,
+ pub st_rdev: ffi::c_ulong,
+ pub(crate) __pad1: ffi::c_ulong,
+ pub st_size: ffi::c_long,
+ pub st_blksize: ffi::c_int,
+ pub(crate) __pad2: ffi::c_int,
+ pub st_blocks: ffi::c_long,
+ pub st_atime: ffi::c_long,
+ pub st_atime_nsec: ffi::c_ulong,
+ pub st_mtime: ffi::c_long,
+ pub st_mtime_nsec: ffi::c_ulong,
+ pub st_ctime: ffi::c_long,
+ pub st_ctime_nsec: ffi::c_ulong,
+ pub(crate) __unused4: ffi::c_uint,
+ pub(crate) __unused5: ffi::c_uint,
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+#[allow(missing_docs)]
+#[non_exhaustive]
+#[cfg(target_arch = "riscv64")]
+pub struct Stat {
+ pub st_dev: ffi::c_ulong,
+ pub st_ino: ffi::c_ulong,
+ pub st_mode: ffi::c_uint,
+ pub st_nlink: ffi::c_uint,
+ pub st_uid: ffi::c_uint,
+ pub st_gid: ffi::c_uint,
+ pub st_rdev: ffi::c_ulong,
+ pub(crate) __pad1: ffi::c_ulong,
+ pub st_size: ffi::c_long,
+ pub st_blksize: ffi::c_int,
+ pub(crate) __pad2: ffi::c_int,
+ pub st_blocks: ffi::c_long,
+ pub st_atime: ffi::c_long,
+ pub st_atime_nsec: ffi::c_ulong,
+ pub st_mtime: ffi::c_long,
+ pub st_mtime_nsec: ffi::c_ulong,
+ pub st_ctime: ffi::c_long,
+ pub st_ctime_nsec: ffi::c_ulong,
+ pub(crate) __unused4: ffi::c_uint,
+ pub(crate) __unused5: ffi::c_uint,
+}
+// This follows `stat`. powerpc64 defines a `stat64` but it's not used.
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+#[allow(missing_docs)]
+#[non_exhaustive]
+#[cfg(target_arch = "powerpc64")]
+pub struct Stat {
+ pub st_dev: ffi::c_ulong,
+ pub st_ino: ffi::c_ulong,
+ pub st_nlink: ffi::c_ulong,
+ pub st_mode: ffi::c_uint,
+ pub st_uid: ffi::c_uint,
+ pub st_gid: ffi::c_uint,
+ pub st_rdev: ffi::c_ulong,
+ pub st_size: ffi::c_long,
+ pub st_blksize: ffi::c_ulong,
+ pub st_blocks: ffi::c_ulong,
+ pub st_atime: ffi::c_long,
+ pub st_atime_nsec: ffi::c_ulong,
+ pub st_mtime: ffi::c_long,
+ pub st_mtime_nsec: ffi::c_ulong,
+ pub st_ctime: ffi::c_long,
+ pub st_ctime_nsec: ffi::c_ulong,
+ pub(crate) __unused4: ffi::c_ulong,
+ pub(crate) __unused5: ffi::c_ulong,
+ pub(crate) __unused6: ffi::c_ulong,
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+#[allow(missing_docs)]
+#[non_exhaustive]
+#[cfg(target_arch = "s390x")]
+pub struct Stat {
+ pub st_dev: ffi::c_ulong,
+ pub st_ino: ffi::c_ulong,
+ pub st_nlink: ffi::c_ulong,
+ pub st_mode: ffi::c_uint,
+ pub st_uid: ffi::c_uint,
+ pub st_gid: ffi::c_uint,
+ pub(crate) __pad1: ffi::c_uint,
+ pub st_rdev: ffi::c_ulong,
+ pub st_size: ffi::c_long, // Linux has `c_ulong` but we make it signed.
+ pub st_atime: ffi::c_long,
+ pub st_atime_nsec: ffi::c_ulong,
+ pub st_mtime: ffi::c_long,
+ pub st_mtime_nsec: ffi::c_ulong,
+ pub st_ctime: ffi::c_long,
+ pub st_ctime_nsec: ffi::c_ulong,
+ pub st_blksize: ffi::c_ulong,
+ pub st_blocks: ffi::c_long,
+ pub(crate) __unused: [ffi::c_ulong; 3],
+}
+
+/// `struct statfs` for use with [`statfs`] and [`fstatfs`].
+///
+/// [`statfs`]: crate::fs::statfs
+/// [`fstatfs`]: crate::fs::fstatfs
+#[allow(clippy::module_name_repetitions)]
+#[repr(C)]
+#[cfg_attr(target_arch = "arm", repr(packed(4)))]
+#[derive(Debug, Copy, Clone)]
+#[allow(missing_docs)]
+#[non_exhaustive]
+pub struct StatFs {
+ pub f_type: FsWord,
+ #[cfg(not(any(target_arch = "arm", target_arch = "s390x")))]
+ pub f_bsize: ffi::c_long,
+ #[cfg(any(target_arch = "arm", target_arch = "s390x"))]
+ pub f_bsize: ffi::c_uint,
+ pub f_blocks: u64,
+ pub f_bfree: u64,
+ pub f_bavail: u64,
+ pub f_files: u64,
+ pub f_ffree: u64,
+ pub f_fsid: Fsid,
+ #[cfg(not(any(target_arch = "arm", target_arch = "s390x")))]
+ pub f_namelen: ffi::c_long,
+ #[cfg(any(target_arch = "arm", target_arch = "s390x"))]
+ pub f_namelen: ffi::c_uint,
+ #[cfg(not(any(target_arch = "arm", target_arch = "s390x")))]
+ pub f_frsize: ffi::c_long,
+ #[cfg(any(target_arch = "arm", target_arch = "s390x"))]
+ pub f_frsize: ffi::c_uint,
+ #[cfg(not(any(target_arch = "arm", target_arch = "s390x")))]
+ pub f_flags: ffi::c_long,
+ #[cfg(any(target_arch = "arm", target_arch = "s390x"))]
+ pub f_flags: ffi::c_uint,
+ #[cfg(not(target_arch = "s390x"))]
+ pub(crate) f_spare: [ffi::c_long; 4],
+ #[cfg(target_arch = "s390x")]
+ pub(crate) f_spare: [ffi::c_uint; 5],
+}
+
+/// `fsid_t` for use with [`StatFs`].
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+#[allow(missing_docs)]
+pub struct Fsid {
+ pub(crate) val: [ffi::c_int; 2],
+}
+
+/// `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,
+}
+
+/// `mode_t`
+pub type RawMode = ffi::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(any(
+ target_arch = "mips64",
+ target_arch = "mips64r6",
+ target_arch = "s390x"
+)))]
+pub type FsWord = ffi::c_long;
+
+/// `__fsword_t`
+#[cfg(any(target_arch = "mips64", target_arch = "mips64r6"))]
+pub type FsWord = i64;
+
+/// `__fsword_t`
+#[cfg(target_arch = "s390x")]
+pub type FsWord = u32;
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 00000000..4ddf6df5
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/io/errno.rs
@@ -0,0 +1,552 @@
+//! 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 crate::backend::c;
+use crate::backend::fd::RawFd;
+use crate::backend::reg::{RetNumber, RetReg};
+use crate::io;
+use linux_raw_sys::errno;
+
+/// `errno`—An error code.
+///
+/// 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.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+/// - [Winsock]
+/// - [FreeBSD]
+/// - [NetBSD]
+/// - [OpenBSD]
+/// - [DragonFly BSD]
+/// - [illumos]
+/// - [glibc]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/errno.html
+/// [Linux]: https://man7.org/linux/man-pages/man3/errno.3.html
+/// [Winsock]: https://learn.microsoft.com/en-us/windows/win32/winsock/windows-sockets-error-codes-2
+/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?errno
+/// [NetBSD]: https://man.netbsd.org/errno.2
+/// [OpenBSD]: https://man.openbsd.org/errno.2
+/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=errno&section=2
+/// [illumos]: https://illumos.org/man/3C/errno
+/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Error-Codes.html
+#[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`.
+ 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(any(feature = "event", feature = "runtime", feature = "system"))]
+#[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()
+}
+
+/// Return the contained `c_int` value.
+#[cfg(not(debug_assertions))]
+#[inline]
+pub(in crate::backend) fn decode_c_int_infallible<Num: RetNumber>(raw: RetReg<Num>) -> c::c_int {
+ raw.decode_c_int()
+}
+
+/// Return the contained `c_uint` value.
+#[cfg(not(debug_assertions))]
+#[inline]
+pub(in crate::backend) fn decode_c_uint_infallible<Num: RetNumber>(raw: RetReg<Num>) -> c::c_uint {
+ raw.decode_c_uint()
+}
+
+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/backend/linux_raw/io/mod.rs b/vendor/rustix/src/backend/linux_raw/io/mod.rs
new file mode 100644
index 00000000..9477b9b9
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/io/mod.rs
@@ -0,0 +1,3 @@
+pub(crate) mod errno;
+pub(crate) mod syscalls;
+pub(crate) mod types;
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 00000000..f40dfe5e
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/io/syscalls.rs
@@ -0,0 +1,364 @@
+//! linux_raw syscalls supporting `rustix::io`.
+//!
+//! # Safety
+//!
+//! See the `rustix::backend` module documentation for details.
+#![allow(unsafe_code)]
+#![allow(clippy::undocumented_unsafe_blocks)]
+
+#[cfg(target_pointer_width = "64")]
+use crate::backend::conv::loff_t_from_u64;
+#[cfg(all(
+ target_pointer_width = "32",
+ any(
+ target_arch = "arm",
+ target_arch = "mips",
+ target_arch = "mips32r6",
+ target_arch = "powerpc"
+ ),
+))]
+use crate::backend::conv::zero;
+use crate::backend::conv::{
+ c_uint, pass_usize, raw_fd, ret, ret_c_int, ret_c_uint, ret_discarded_fd, ret_owned_fd,
+ ret_usize, slice,
+};
+#[cfg(target_pointer_width = "32")]
+use crate::backend::conv::{hi, lo};
+use crate::backend::{c, MAX_IOV};
+use crate::fd::{AsFd as _, BorrowedFd, OwnedFd, RawFd};
+use crate::io::{self, DupFlags, FdFlags, IoSlice, IoSliceMut, ReadWriteFlags};
+use crate::ioctl::{IoctlOutput, Opcode};
+use core::cmp;
+use linux_raw_sys::general::{F_DUPFD_CLOEXEC, F_GETFD, F_SETFD};
+
+#[inline]
+pub(crate) unsafe fn read(fd: BorrowedFd<'_>, buf: (*mut u8, usize)) -> io::Result<usize> {
+ ret_usize(syscall!(__NR_read, fd, buf.0, pass_usize(buf.1)))
+}
+
+#[inline]
+pub(crate) unsafe fn pread(
+ fd: BorrowedFd<'_>,
+ buf: (*mut u8, usize),
+ pos: u64,
+) -> io::Result<usize> {
+ // <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm64/kernel/sys32.c?h=v6.13#n70>
+ #[cfg(all(
+ target_pointer_width = "32",
+ any(
+ target_arch = "arm",
+ target_arch = "mips",
+ target_arch = "mips32r6",
+ target_arch = "powerpc"
+ ),
+ ))]
+ {
+ ret_usize(syscall!(
+ __NR_pread64,
+ fd,
+ buf.0,
+ pass_usize(buf.1),
+ zero(),
+ hi(pos),
+ lo(pos)
+ ))
+ }
+ #[cfg(all(
+ target_pointer_width = "32",
+ not(any(
+ target_arch = "arm",
+ target_arch = "mips",
+ target_arch = "mips32r6",
+ target_arch = "powerpc"
+ )),
+ ))]
+ {
+ ret_usize(syscall!(
+ __NR_pread64,
+ fd,
+ buf.0,
+ pass_usize(buf.1),
+ hi(pos),
+ lo(pos)
+ ))
+ }
+ #[cfg(target_pointer_width = "64")]
+ ret_usize(syscall!(
+ __NR_pread64,
+ fd,
+ buf.0,
+ pass_usize(buf.1),
+ 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)]);
+
+ // Unlike the plain "p" functions, the "pv" functions pass their offset in
+ // an endian-independent way, and always in two registers.
+ unsafe {
+ ret_usize(syscall!(
+ __NR_preadv,
+ fd,
+ bufs_addr,
+ bufs_len,
+ pass_usize(pos as usize),
+ pass_usize((pos >> 32) as usize)
+ ))
+ }
+}
+
+#[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)]);
+
+ // Unlike the plain "p" functions, the "pv" functions pass their offset in
+ // an endian-independent way, and always in two registers.
+ unsafe {
+ ret_usize(syscall!(
+ __NR_preadv2,
+ fd,
+ bufs_addr,
+ bufs_len,
+ pass_usize(pos as usize),
+ pass_usize((pos >> 32) as usize),
+ 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://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm64/kernel/sys32.c?h=v6.13#n76>
+ #[cfg(all(
+ target_pointer_width = "32",
+ any(
+ target_arch = "arm",
+ target_arch = "mips",
+ target_arch = "mips32r6",
+ target_arch = "powerpc"
+ ),
+ ))]
+ 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 = "mips32r6",
+ target_arch = "powerpc"
+ )),
+ ))]
+ 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)]);
+
+ // Unlike the plain "p" functions, the "pv" functions pass their offset in
+ // an endian-independent way, and always in two registers.
+ unsafe {
+ ret_usize(syscall_readonly!(
+ __NR_pwritev,
+ fd,
+ bufs_addr,
+ bufs_len,
+ pass_usize(pos as usize),
+ pass_usize((pos >> 32) as usize)
+ ))
+ }
+}
+
+#[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)]);
+
+ // Unlike the plain "p" functions, the "pv" functions pass their offset in
+ // an endian-independent way, and always in two registers.
+ unsafe {
+ ret_usize(syscall_readonly!(
+ __NR_pwritev2,
+ fd,
+ bufs_addr,
+ bufs_len,
+ pass_usize(pos as usize),
+ pass_usize((pos >> 32) as usize),
+ flags
+ ))
+ }
+}
+
+#[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();
+}
+
+#[cfg(feature = "try_close")]
+#[inline]
+pub(crate) unsafe fn try_close(fd: RawFd) -> io::Result<()> {
+ ret(syscall_readonly!(__NR_close, raw_fd(fd)))
+}
+
+#[inline]
+pub(crate) unsafe fn ioctl(
+ fd: BorrowedFd<'_>,
+ request: Opcode,
+ arg: *mut c::c_void,
+) -> io::Result<IoctlOutput> {
+ ret_c_int(syscall!(__NR_ioctl, fd, c_uint(request), arg))
+}
+
+#[inline]
+pub(crate) unsafe fn ioctl_readonly(
+ fd: BorrowedFd<'_>,
+ request: Opcode,
+ arg: *mut c::c_void,
+) -> io::Result<IoctlOutput> {
+ ret_c_int(syscall_readonly!(__NR_ioctl, fd, c_uint(request), arg))
+}
+
+#[inline]
+pub(crate) fn dup(fd: BorrowedFd<'_>) -> io::Result<OwnedFd> {
+ unsafe { ret_owned_fd(syscall_readonly!(__NR_dup, fd)) }
+}
+
+#[allow(clippy::needless_pass_by_ref_mut)]
+#[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()))
+ }
+}
+
+#[allow(clippy::needless_pass_by_ref_mut)]
+#[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_retain)
+ }
+ #[cfg(target_pointer_width = "64")]
+ unsafe {
+ ret_c_uint(syscall_readonly!(__NR_fcntl, fd, c_uint(F_GETFD)))
+ .map(FdFlags::from_bits_retain)
+ }
+}
+
+#[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))
+ }
+}
+
+#[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)
+ ))
+ }
+}
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 00000000..533f9732
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/io/types.rs
@@ -0,0 +1,57 @@
+use crate::ffi;
+use bitflags::bitflags;
+
+bitflags! {
+ /// `FD_*` constants for use with [`fcntl_getfd`] and [`fcntl_setfd`].
+ ///
+ /// [`fcntl_getfd`]: crate::io::fcntl_getfd
+ /// [`fcntl_setfd`]: crate::io::fcntl_setfd
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct FdFlags: ffi::c_uint {
+ /// `FD_CLOEXEC`
+ const CLOEXEC = linux_raw_sys::general::FD_CLOEXEC;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+bitflags! {
+ /// `RWF_*` constants for use with [`preadv2`] and [`pwritev2`].
+ ///
+ /// [`preadv2`]: crate::io::preadv2
+ /// [`pwritev2`]: crate::io::pwritev
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct ReadWriteFlags: ffi::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;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+bitflags! {
+ /// `O_*` constants for use with [`dup2`].
+ ///
+ /// [`dup2`]: crate::io::dup2
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct DupFlags: ffi::c_uint {
+ /// `O_CLOEXEC`
+ const CLOEXEC = linux_raw_sys::general::O_CLOEXEC;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
diff --git a/vendor/rustix/src/backend/linux_raw/io_uring/mod.rs b/vendor/rustix/src/backend/linux_raw/io_uring/mod.rs
new file mode 100644
index 00000000..ef944f04
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/io_uring/mod.rs
@@ -0,0 +1 @@
+pub(crate) mod syscalls;
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 00000000..3e61b7aa
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/io_uring/syscalls.rs
@@ -0,0 +1,79 @@
+//! linux_raw syscalls supporting `rustix::io_uring`.
+//!
+//! # Safety
+//!
+//! See the `rustix::backend::syscalls` module documentation for details.
+#![allow(unsafe_code, clippy::undocumented_unsafe_blocks)]
+
+use crate::backend::conv::{by_mut, c_uint, pass_usize, ret_c_uint, ret_owned_fd};
+use crate::fd::{BorrowedFd, OwnedFd};
+use crate::io;
+use crate::io_uring::{io_uring_params, IoringEnterFlags, IoringRegisterFlags, 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<u32> {
+ ret_c_uint(syscall_readonly!(
+ __NR_io_uring_register,
+ fd,
+ c_uint(opcode as u32),
+ arg,
+ c_uint(nr_args)
+ ))
+}
+
+#[inline]
+pub(crate) unsafe fn io_uring_register_with(
+ fd: BorrowedFd<'_>,
+ opcode: IoringRegisterOp,
+ flags: IoringRegisterFlags,
+ arg: *const c_void,
+ nr_args: u32,
+) -> io::Result<u32> {
+ ret_c_uint(syscall_readonly!(
+ __NR_io_uring_register,
+ fd,
+ c_uint((opcode as u32) | bitflags_bits!(flags)),
+ 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/backend/linux_raw/mm/mod.rs b/vendor/rustix/src/backend/linux_raw/mm/mod.rs
new file mode 100644
index 00000000..1e0181a9
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/mm/mod.rs
@@ -0,0 +1,2 @@
+pub(crate) mod syscalls;
+pub(crate) mod types;
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 00000000..84881906
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/mm/syscalls.rs
@@ -0,0 +1,239 @@
+//! 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::types::{
+ Advice, MapFlags, MlockAllFlags, MlockFlags, MprotectFlags, MremapFlags, MsyncFlags, ProtFlags,
+ UserfaultfdFlags,
+};
+use crate::backend::c;
+#[cfg(target_pointer_width = "64")]
+use crate::backend::conv::loff_t_from_u64;
+use crate::backend::conv::{c_uint, no_fd, pass_usize, ret, ret_owned_fd, ret_void_star};
+use crate::fd::{BorrowedFd, OwnedFd};
+use crate::ffi::c_void;
+use crate::io;
+use linux_raw_sys::general::{MAP_ANONYMOUS, MREMAP_FIXED};
+
+#[inline]
+pub(crate) fn madvise(addr: *mut 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_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_void,
+ length: usize,
+ prot: ProtFlags,
+ flags: MapFlags,
+ fd: BorrowedFd<'_>,
+ offset: u64,
+) -> io::Result<*mut 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_void,
+ length: usize,
+ prot: ProtFlags,
+ flags: MapFlags,
+) -> io::Result<*mut 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_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_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_void,
+ old_size: usize,
+ new_size: usize,
+ flags: MremapFlags,
+) -> io::Result<*mut 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_void,
+ old_size: usize,
+ new_size: usize,
+ flags: MremapFlags,
+ new_address: *mut c_void,
+) -> io::Result<*mut c_void> {
+ ret_void_star(syscall!(
+ __NR_mremap,
+ old_address,
+ pass_usize(old_size),
+ pass_usize(new_size),
+ c_uint(flags.bits() | MREMAP_FIXED),
+ 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_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_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_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))
+}
+
+/// Locks all pages mapped into the address space of the calling process.
+///
+/// This includes the pages of the code, data, and stack segment, as well as
+/// shared libraries, user space kernel data, shared memory, and memory-mapped
+/// files. All mapped pages are guaranteed to be resident in RAM when the call
+/// returns successfully; the pages are guaranteed to stay in RAM until later
+/// unlocked.
+#[inline]
+pub(crate) fn mlockall(flags: MlockAllFlags) -> io::Result<()> {
+ // When `mlockall` is used with `MCL_ONFAULT | MCL_FUTURE`, the ordering
+ // of `mlockall` with respect to arbitrary loads may be significant,
+ // because if a load happens and evokes a fault before the `mlockall`,
+ // the memory doesn't get locked, but if the load and therefore
+ // the fault happens after, then the memory does get locked.
+ //
+ // So to be conservative in this regard, we use `syscall` instead of
+ // `syscall_readonly`
+ unsafe { ret(syscall!(__NR_mlockall, flags)) }
+}
+
+/// Unlocks all pages mapped into the address space of the calling process.
+#[inline]
+pub(crate) fn munlockall() -> io::Result<()> {
+ unsafe { ret(syscall_readonly!(__NR_munlockall)) }
+}
diff --git a/vendor/rustix/src/backend/linux_raw/mm/types.rs b/vendor/rustix/src/backend/linux_raw/mm/types.rs
new file mode 100644
index 00000000..c6806fc4
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/mm/types.rs
@@ -0,0 +1,297 @@
+use crate::ffi;
+use bitflags::bitflags;
+
+bitflags! {
+ /// `PROT_*` flags for use with [`mmap`].
+ ///
+ /// For `PROT_NONE`, use `ProtFlags::empty()`.
+ ///
+ /// [`mmap`]: crate::mm::mmap
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct ProtFlags: u32 {
+ /// `PROT_READ`
+ const READ = linux_raw_sys::general::PROT_READ;
+ /// `PROT_WRITE`
+ const WRITE = linux_raw_sys::general::PROT_WRITE;
+ /// `PROT_EXEC`
+ const EXEC = linux_raw_sys::general::PROT_EXEC;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+bitflags! {
+ /// `PROT_*` flags for use with [`mprotect`].
+ ///
+ /// For `PROT_NONE`, use `MprotectFlags::empty()`.
+ ///
+ /// [`mprotect`]: crate::mm::mprotect
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct MprotectFlags: u32 {
+ /// `PROT_READ`
+ const READ = linux_raw_sys::general::PROT_READ;
+ /// `PROT_WRITE`
+ const WRITE = linux_raw_sys::general::PROT_WRITE;
+ /// `PROT_EXEC`
+ const EXEC = linux_raw_sys::general::PROT_EXEC;
+ /// `PROT_GROWSUP`
+ const GROWSUP = linux_raw_sys::general::PROT_GROWSUP;
+ /// `PROT_GROWSDOWN`
+ const GROWSDOWN = linux_raw_sys::general::PROT_GROWSDOWN;
+ /// `PROT_SEM`
+ const SEM = linux_raw_sys::general::PROT_SEM;
+ /// `PROT_BTI`
+ #[cfg(target_arch = "aarch64")]
+ const BTI = linux_raw_sys::general::PROT_BTI;
+ /// `PROT_MTE`
+ #[cfg(target_arch = "aarch64")]
+ const MTE = linux_raw_sys::general::PROT_MTE;
+ /// `PROT_SAO`
+ #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
+ const SAO = linux_raw_sys::general::PROT_SAO;
+ /// `PROT_ADI`
+ #[cfg(any(target_arch = "sparc", target_arch = "sparc64"))]
+ const ADI = linux_raw_sys::general::PROT_ADI;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+bitflags! {
+ /// `MAP_*` flags for use with [`mmap`].
+ ///
+ /// For `MAP_ANONYMOUS` (aka `MAP_ANON`), see [`mmap_anonymous`].
+ ///
+ /// [`mmap`]: crate::mm::mmap
+ /// [`mmap_anonymous`]: crates::mm::mmap_anonymous
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct MapFlags: u32 {
+ /// `MAP_SHARED`
+ const SHARED = linux_raw_sys::general::MAP_SHARED;
+ /// `MAP_SHARED_VALIDATE` (since Linux 4.15)
+ const SHARED_VALIDATE = linux_raw_sys::general::MAP_SHARED_VALIDATE;
+ /// `MAP_PRIVATE`
+ const PRIVATE = linux_raw_sys::general::MAP_PRIVATE;
+ /// `MAP_DENYWRITE`
+ const DENYWRITE = linux_raw_sys::general::MAP_DENYWRITE;
+ /// `MAP_FIXED`
+ const FIXED = linux_raw_sys::general::MAP_FIXED;
+ /// `MAP_FIXED_NOREPLACE` (since Linux 4.17)
+ const FIXED_NOREPLACE = linux_raw_sys::general::MAP_FIXED_NOREPLACE;
+ /// `MAP_GROWSDOWN`
+ const GROWSDOWN = linux_raw_sys::general::MAP_GROWSDOWN;
+ /// `MAP_HUGETLB`
+ const HUGETLB = linux_raw_sys::general::MAP_HUGETLB;
+ /// `MAP_HUGE_2MB` (since Linux 3.8)
+ const HUGE_2MB = linux_raw_sys::general::MAP_HUGE_2MB;
+ /// `MAP_HUGE_1GB` (since Linux 3.8)
+ const HUGE_1GB = linux_raw_sys::general::MAP_HUGE_1GB;
+ /// `MAP_LOCKED`
+ const LOCKED = linux_raw_sys::general::MAP_LOCKED;
+ /// `MAP_NORESERVE`
+ const NORESERVE = linux_raw_sys::general::MAP_NORESERVE;
+ /// `MAP_POPULATE`
+ const POPULATE = linux_raw_sys::general::MAP_POPULATE;
+ /// `MAP_STACK`
+ const STACK = linux_raw_sys::general::MAP_STACK;
+ /// `MAP_SYNC` (since Linux 4.15)
+ #[cfg(not(any(target_arch = "mips", target_arch = "mips32r6", target_arch = "mips64", target_arch = "mips64r6")))]
+ const SYNC = linux_raw_sys::general::MAP_SYNC;
+ /// `MAP_UNINITIALIZED`
+ #[cfg(not(any(target_arch = "mips", target_arch = "mips32r6", target_arch = "mips64", target_arch = "mips64r6")))]
+ const UNINITIALIZED = linux_raw_sys::general::MAP_UNINITIALIZED;
+ /// `MAP_DROPPABLE`
+ const DROPPABLE = linux_raw_sys::general::MAP_DROPPABLE;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+bitflags! {
+ /// `MREMAP_*` flags for use with [`mremap`].
+ ///
+ /// For `MREMAP_FIXED`, see [`mremap_fixed`].
+ ///
+ /// [`mremap`]: crate::mm::mremap
+ /// [`mremap_fixed`]: crate::mm::mremap_fixed
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct MremapFlags: u32 {
+ /// `MREMAP_MAYMOVE`
+ const MAYMOVE = linux_raw_sys::general::MREMAP_MAYMOVE;
+ /// `MREMAP_DONTUNMAP` (since Linux 5.7)
+ const DONTUNMAP = linux_raw_sys::general::MREMAP_DONTUNMAP;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+bitflags! {
+ /// `MS_*` flags for use with [`msync`].
+ ///
+ /// [`msync`]: crate::mm::msync
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct MsyncFlags: u32 {
+ /// `MS_SYNC`—Requests an update and waits for it to complete.
+ const SYNC = linux_raw_sys::general::MS_SYNC;
+ /// `MS_ASYNC`—Specifies that an update be scheduled, but the call
+ /// returns immediately.
+ const ASYNC = linux_raw_sys::general::MS_ASYNC;
+ /// `MS_INVALIDATE`—Asks to invalidate other mappings of the same
+ /// file (so that they can be updated with the fresh values just
+ /// written).
+ const INVALIDATE = linux_raw_sys::general::MS_INVALIDATE;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+bitflags! {
+ /// `MLOCK_*` flags for use with [`mlock_with`].
+ ///
+ /// [`mlock_with`]: crate::mm::mlock_with
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct MlockFlags: u32 {
+ /// `MLOCK_ONFAULT`
+ const ONFAULT = linux_raw_sys::general::MLOCK_ONFAULT;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+/// `POSIX_MADV_*` constants for use with [`madvise`].
+///
+/// [`madvise`]: crate::mm::madvise
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+#[repr(u32)]
+#[non_exhaustive]
+pub enum Advice {
+ /// `POSIX_MADV_NORMAL`
+ Normal = linux_raw_sys::general::MADV_NORMAL,
+
+ /// `POSIX_MADV_SEQUENTIAL`
+ Sequential = linux_raw_sys::general::MADV_SEQUENTIAL,
+
+ /// `POSIX_MADV_RANDOM`
+ Random = linux_raw_sys::general::MADV_RANDOM,
+
+ /// `POSIX_MADV_WILLNEED`
+ WillNeed = linux_raw_sys::general::MADV_WILLNEED,
+
+ /// `MADV_DONTNEED`
+ LinuxDontNeed = linux_raw_sys::general::MADV_DONTNEED,
+
+ /// `MADV_FREE` (since Linux 4.5)
+ LinuxFree = linux_raw_sys::general::MADV_FREE,
+ /// `MADV_REMOVE`
+ LinuxRemove = linux_raw_sys::general::MADV_REMOVE,
+ /// `MADV_DONTFORK`
+ LinuxDontFork = linux_raw_sys::general::MADV_DONTFORK,
+ /// `MADV_DOFORK`
+ LinuxDoFork = linux_raw_sys::general::MADV_DOFORK,
+ /// `MADV_HWPOISON`
+ LinuxHwPoison = linux_raw_sys::general::MADV_HWPOISON,
+ /// `MADV_SOFT_OFFLINE`
+ #[cfg(not(any(
+ target_arch = "mips",
+ target_arch = "mips32r6",
+ target_arch = "mips64",
+ target_arch = "mips64r6"
+ )))]
+ LinuxSoftOffline = linux_raw_sys::general::MADV_SOFT_OFFLINE,
+ /// `MADV_MERGEABLE`
+ LinuxMergeable = linux_raw_sys::general::MADV_MERGEABLE,
+ /// `MADV_UNMERGEABLE`
+ LinuxUnmergeable = linux_raw_sys::general::MADV_UNMERGEABLE,
+ /// `MADV_HUGEPAGE`
+ LinuxHugepage = linux_raw_sys::general::MADV_HUGEPAGE,
+ /// `MADV_NOHUGEPAGE`
+ LinuxNoHugepage = linux_raw_sys::general::MADV_NOHUGEPAGE,
+ /// `MADV_DONTDUMP` (since Linux 3.4)
+ LinuxDontDump = linux_raw_sys::general::MADV_DONTDUMP,
+ /// `MADV_DODUMP` (since Linux 3.4)
+ LinuxDoDump = linux_raw_sys::general::MADV_DODUMP,
+ /// `MADV_WIPEONFORK` (since Linux 4.14)
+ LinuxWipeOnFork = linux_raw_sys::general::MADV_WIPEONFORK,
+ /// `MADV_KEEPONFORK` (since Linux 4.14)
+ LinuxKeepOnFork = linux_raw_sys::general::MADV_KEEPONFORK,
+ /// `MADV_COLD` (since Linux 5.4)
+ LinuxCold = linux_raw_sys::general::MADV_COLD,
+ /// `MADV_PAGEOUT` (since Linux 5.4)
+ LinuxPageOut = linux_raw_sys::general::MADV_PAGEOUT,
+ /// `MADV_POPULATE_READ` (since Linux 5.14)
+ LinuxPopulateRead = linux_raw_sys::general::MADV_POPULATE_READ,
+ /// `MADV_POPULATE_WRITE` (since Linux 5.14)
+ LinuxPopulateWrite = linux_raw_sys::general::MADV_POPULATE_WRITE,
+ /// `MADV_DONTNEED_LOCKED` (since Linux 5.18)
+ LinuxDontneedLocked = linux_raw_sys::general::MADV_DONTNEED_LOCKED,
+}
+
+#[allow(non_upper_case_globals)]
+impl Advice {
+ /// `POSIX_MADV_DONTNEED`
+ ///
+ /// On Linux, this is mapped to `POSIX_MADV_NORMAL` because Linux's
+ /// `MADV_DONTNEED` differs from `POSIX_MADV_DONTNEED`. See `LinuxDontNeed`
+ /// for the Linux behavior.
+ pub const DontNeed: Self = Self::Normal;
+}
+
+bitflags! {
+ /// `O_*` flags for use with [`userfaultfd`].
+ ///
+ /// [`userfaultfd`]: crate::mm::userfaultfd
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct UserfaultfdFlags: ffi::c_uint {
+ /// `O_CLOEXEC`
+ const CLOEXEC = linux_raw_sys::general::O_CLOEXEC;
+ /// `O_NONBLOCK`
+ const NONBLOCK = linux_raw_sys::general::O_NONBLOCK;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+bitflags! {
+ /// `MCL_*` flags for use with [`mlockall`].
+ ///
+ /// [`mlockall`]: crate::mm::mlockall
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct MlockAllFlags: u32 {
+ /// Used together with `MCL_CURRENT`, `MCL_FUTURE`, or both. Mark all
+ /// current (with `MCL_CURRENT`) or future (with `MCL_FUTURE`) mappings
+ /// to lock pages when they are faulted in. When used with
+ /// `MCL_CURRENT`, all present pages are locked, but `mlockall` will
+ /// not fault in non-present pages. When used with `MCL_FUTURE`, all
+ /// future mappings will be marked to lock pages when they are faulted
+ /// in, but they will not be populated by the lock when the mapping is
+ /// created. `MCL_ONFAULT` must be used with either `MCL_CURRENT` or
+ /// `MCL_FUTURE` or both.
+ const ONFAULT = linux_raw_sys::general::MCL_ONFAULT;
+ /// Lock all pages which will become mapped into the address space of
+ /// the process in the future. These could be, for instance, new pages
+ /// required by a growing heap and stack as well as new memory-mapped
+ /// files or shared memory regions.
+ const FUTURE = linux_raw_sys::general::MCL_FUTURE;
+ /// Lock all pages which are currently mapped into the address space of
+ /// the process.
+ const CURRENT = linux_raw_sys::general::MCL_CURRENT;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
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 00000000..581dcc97
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/mod.rs
@@ -0,0 +1,112 @@
+//! 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 module 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 reg;
+#[cfg(any(feature = "time", feature = "thread", target_arch = "x86"))]
+mod vdso;
+#[cfg(any(feature = "time", feature = "thread", target_arch = "x86"))]
+mod vdso_wrappers;
+
+#[cfg(feature = "event")]
+pub(crate) mod event;
+#[cfg(any(
+ feature = "fs",
+ all(
+ not(feature = "use-libc-auxv"),
+ not(feature = "use-explicitly-provided-auxv"),
+ any(
+ feature = "param",
+ feature = "runtime",
+ feature = "thread",
+ feature = "time",
+ target_arch = "x86",
+ )
+ )
+))]
+pub(crate) mod fs;
+pub(crate) mod io;
+#[cfg(feature = "io_uring")]
+pub(crate) mod io_uring;
+#[cfg(feature = "mm")]
+pub(crate) mod mm;
+#[cfg(feature = "mount")]
+pub(crate) mod mount;
+#[cfg(feature = "net")]
+pub(crate) mod net;
+#[cfg(any(
+ feature = "param",
+ feature = "runtime",
+ feature = "thread",
+ feature = "time",
+ target_arch = "x86",
+))]
+pub(crate) mod param;
+#[cfg(feature = "pipe")]
+pub(crate) mod pipe;
+#[cfg(feature = "process")]
+pub(crate) mod process;
+#[cfg(feature = "pty")]
+pub(crate) mod pty;
+#[cfg(feature = "rand")]
+pub(crate) mod rand;
+#[cfg(feature = "runtime")]
+pub(crate) mod runtime;
+#[cfg(feature = "shm")]
+pub(crate) mod shm;
+#[cfg(feature = "system")]
+pub(crate) mod system;
+#[cfg(feature = "termios")]
+pub(crate) mod termios;
+#[cfg(feature = "thread")]
+pub(crate) mod thread;
+#[cfg(feature = "time")]
+pub(crate) mod time;
+
+// Re-export the maybe-polyfill `core::os::fd`.
+pub(crate) use crate::maybe_polyfill::os::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;
+
+// Private modules used by multiple public modules.
+#[cfg(any(feature = "process", feature = "runtime"))]
+pub(crate) mod pid;
+#[cfg(any(feature = "process", feature = "thread"))]
+pub(crate) mod prctl;
+#[cfg(any(
+ feature = "fs",
+ feature = "process",
+ feature = "thread",
+ all(
+ not(feature = "use-libc-auxv"),
+ not(feature = "use-explicitly-provided-auxv"),
+ any(
+ feature = "param",
+ feature = "runtime",
+ feature = "time",
+ target_arch = "x86",
+ )
+ )
+))]
+pub(crate) mod ugid;
+
+/// The maximum number of buffers that can be passed into a vectored I/O system
+/// call on the current platform.
+const MAX_IOV: usize = linux_raw_sys::general::UIO_MAXIOV as usize;
diff --git a/vendor/rustix/src/backend/linux_raw/mount/mod.rs b/vendor/rustix/src/backend/linux_raw/mount/mod.rs
new file mode 100644
index 00000000..1e0181a9
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/mount/mod.rs
@@ -0,0 +1,2 @@
+pub(crate) mod syscalls;
+pub(crate) mod types;
diff --git a/vendor/rustix/src/backend/linux_raw/mount/syscalls.rs b/vendor/rustix/src/backend/linux_raw/mount/syscalls.rs
new file mode 100644
index 00000000..6fc69240
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/mount/syscalls.rs
@@ -0,0 +1,237 @@
+//! linux_raw syscalls supporting `rustix::mount`.
+//!
+//! # Safety
+//!
+//! See the `rustix::backend` module documentation for details.
+#![allow(unsafe_code)]
+#![allow(clippy::undocumented_unsafe_blocks)]
+
+use crate::backend::conv::{ret, ret_owned_fd, slice, zero};
+use crate::fd::{BorrowedFd, OwnedFd};
+use crate::ffi::CStr;
+use crate::io;
+
+#[inline]
+pub(crate) fn mount(
+ source: Option<&CStr>,
+ target: &CStr,
+ file_system_type: Option<&CStr>,
+ flags: super::types::MountFlagsArg,
+ data: Option<&CStr>,
+) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_mount,
+ source,
+ target,
+ file_system_type,
+ flags,
+ data
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn unmount(target: &CStr, flags: super::types::UnmountFlags) -> io::Result<()> {
+ unsafe { ret(syscall_readonly!(__NR_umount2, target, flags)) }
+}
+
+#[inline]
+pub(crate) fn fsopen(fs_name: &CStr, flags: super::types::FsOpenFlags) -> io::Result<OwnedFd> {
+ unsafe { ret_owned_fd(syscall_readonly!(__NR_fsopen, fs_name, flags)) }
+}
+
+#[inline]
+pub(crate) fn fsmount(
+ fs_fd: BorrowedFd<'_>,
+ flags: super::types::FsMountFlags,
+ attr_flags: super::types::MountAttrFlags,
+) -> io::Result<OwnedFd> {
+ unsafe { ret_owned_fd(syscall_readonly!(__NR_fsmount, fs_fd, flags, attr_flags)) }
+}
+
+#[inline]
+pub(crate) fn move_mount(
+ from_dfd: BorrowedFd<'_>,
+ from_pathname: &CStr,
+ to_dfd: BorrowedFd<'_>,
+ to_pathname: &CStr,
+ flags: super::types::MoveMountFlags,
+) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_move_mount,
+ from_dfd,
+ from_pathname,
+ to_dfd,
+ to_pathname,
+ flags
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn open_tree(
+ dfd: BorrowedFd<'_>,
+ filename: &CStr,
+ flags: super::types::OpenTreeFlags,
+) -> io::Result<OwnedFd> {
+ unsafe { ret_owned_fd(syscall_readonly!(__NR_open_tree, dfd, filename, flags)) }
+}
+
+#[inline]
+pub(crate) fn fspick(
+ dfd: BorrowedFd<'_>,
+ path: &CStr,
+ flags: super::types::FsPickFlags,
+) -> io::Result<OwnedFd> {
+ unsafe { ret_owned_fd(syscall_readonly!(__NR_fspick, dfd, path, flags)) }
+}
+
+#[inline]
+pub(crate) fn fsconfig_set_flag(fs_fd: BorrowedFd<'_>, key: &CStr) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_fsconfig,
+ fs_fd,
+ super::types::FsConfigCmd::SetFlag,
+ key,
+ zero(),
+ zero()
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn fsconfig_set_string(
+ fs_fd: BorrowedFd<'_>,
+ key: &CStr,
+ value: &CStr,
+) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_fsconfig,
+ fs_fd,
+ super::types::FsConfigCmd::SetString,
+ key,
+ value,
+ zero()
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn fsconfig_set_binary(
+ fs_fd: BorrowedFd<'_>,
+ key: &CStr,
+ value: &[u8],
+) -> io::Result<()> {
+ let (value_addr, value_len) = slice(value);
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_fsconfig,
+ fs_fd,
+ super::types::FsConfigCmd::SetBinary,
+ key,
+ value_addr,
+ value_len
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn fsconfig_set_fd(
+ fs_fd: BorrowedFd<'_>,
+ key: &CStr,
+ fd: BorrowedFd<'_>,
+) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_fsconfig,
+ fs_fd,
+ super::types::FsConfigCmd::SetFd,
+ key,
+ zero(),
+ fd
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn fsconfig_set_path(
+ fs_fd: BorrowedFd<'_>,
+ key: &CStr,
+ path: &CStr,
+ fd: BorrowedFd<'_>,
+) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_fsconfig,
+ fs_fd,
+ super::types::FsConfigCmd::SetPath,
+ key,
+ path,
+ fd
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn fsconfig_set_path_empty(
+ fs_fd: BorrowedFd<'_>,
+ key: &CStr,
+ fd: BorrowedFd<'_>,
+) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_fsconfig,
+ fs_fd,
+ super::types::FsConfigCmd::SetPathEmpty,
+ key,
+ cstr!(""),
+ fd
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn fsconfig_create(fs_fd: BorrowedFd<'_>) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_fsconfig,
+ fs_fd,
+ super::types::FsConfigCmd::Create,
+ zero(),
+ zero(),
+ zero()
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn fsconfig_reconfigure(fs_fd: BorrowedFd<'_>) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_fsconfig,
+ fs_fd,
+ super::types::FsConfigCmd::Reconfigure,
+ zero(),
+ zero(),
+ zero()
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn fsconfig_create_excl(fs_fd: BorrowedFd<'_>) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_fsconfig,
+ fs_fd,
+ super::types::FsConfigCmd::CreateExclusive,
+ zero(),
+ zero(),
+ zero()
+ ))
+ }
+}
diff --git a/vendor/rustix/src/backend/linux_raw/mount/types.rs b/vendor/rustix/src/backend/linux_raw/mount/types.rs
new file mode 100644
index 00000000..548b74ed
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/mount/types.rs
@@ -0,0 +1,335 @@
+use crate::ffi;
+use bitflags::bitflags;
+
+bitflags! {
+ /// `MS_*` constants for use with [`mount`].
+ ///
+ /// [`mount`]: crate::mount::mount
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct MountFlags: ffi::c_uint {
+ /// `MS_BIND`
+ const BIND = linux_raw_sys::general::MS_BIND;
+
+ /// `MS_DIRSYNC`
+ const DIRSYNC = linux_raw_sys::general::MS_DIRSYNC;
+
+ /// `MS_LAZYTIME`
+ const LAZYTIME = linux_raw_sys::general::MS_LAZYTIME;
+
+ /// `MS_MANDLOCK`
+ #[doc(alias = "MANDLOCK")]
+ const PERMIT_MANDATORY_FILE_LOCKING = linux_raw_sys::general::MS_MANDLOCK;
+
+ /// `MS_NOATIME`
+ const NOATIME = linux_raw_sys::general::MS_NOATIME;
+
+ /// `MS_NODEV`
+ const NODEV = linux_raw_sys::general::MS_NODEV;
+
+ /// `MS_NODIRATIME`
+ const NODIRATIME = linux_raw_sys::general::MS_NODIRATIME;
+
+ /// `MS_NOEXEC`
+ const NOEXEC = linux_raw_sys::general::MS_NOEXEC;
+
+ /// `MS_NOSUID`
+ const NOSUID = linux_raw_sys::general::MS_NOSUID;
+
+ /// `MS_RDONLY`
+ const RDONLY = linux_raw_sys::general::MS_RDONLY;
+
+ /// `MS_REC`
+ const REC = linux_raw_sys::general::MS_REC;
+
+ /// `MS_RELATIME`
+ const RELATIME = linux_raw_sys::general::MS_RELATIME;
+
+ /// `MS_SILENT`
+ const SILENT = linux_raw_sys::general::MS_SILENT;
+
+ /// `MS_STRICTATIME`
+ const STRICTATIME = linux_raw_sys::general::MS_STRICTATIME;
+
+ /// `MS_SYNCHRONOUS`
+ const SYNCHRONOUS = linux_raw_sys::general::MS_SYNCHRONOUS;
+
+ /// `MS_NOSYMFOLLOW`
+ const NOSYMFOLLOW = linux_raw_sys::general::MS_NOSYMFOLLOW;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+bitflags! {
+ /// `MNT_*` constants for use with [`unmount`].
+ ///
+ /// [`unmount`]: crate::mount::unmount
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct UnmountFlags: ffi::c_uint {
+ /// `MNT_FORCE`
+ const FORCE = linux_raw_sys::general::MNT_FORCE;
+ /// `MNT_DETACH`
+ const DETACH = linux_raw_sys::general::MNT_DETACH;
+ /// `MNT_EXPIRE`
+ const EXPIRE = linux_raw_sys::general::MNT_EXPIRE;
+ /// `UMOUNT_NOFOLLOW`
+ const NOFOLLOW = linux_raw_sys::general::UMOUNT_NOFOLLOW;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+bitflags! {
+ /// `FSOPEN_*` constants for use with [`fsopen`].
+ ///
+ /// [`fsopen`]: crate::mount::fsopen
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct FsOpenFlags: ffi::c_uint {
+ /// `FSOPEN_CLOEXEC`
+ const FSOPEN_CLOEXEC = linux_raw_sys::general::FSOPEN_CLOEXEC;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+bitflags! {
+ /// `FSMOUNT_*` constants for use with [`fsmount`].
+ ///
+ /// [`fsmount`]: crate::mount::fsmount
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct FsMountFlags: ffi::c_uint {
+ /// `FSMOUNT_CLOEXEC`
+ const FSMOUNT_CLOEXEC = linux_raw_sys::general::FSMOUNT_CLOEXEC;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+/// `FSCONFIG_*` constants for use with the `fsconfig` syscall.
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+#[repr(u32)]
+pub(crate) enum FsConfigCmd {
+ /// `FSCONFIG_SET_FLAG`
+ SetFlag = linux_raw_sys::general::fsconfig_command::FSCONFIG_SET_FLAG as u32,
+
+ /// `FSCONFIG_SET_STRING`
+ SetString = linux_raw_sys::general::fsconfig_command::FSCONFIG_SET_STRING as u32,
+
+ /// `FSCONFIG_SET_BINARY`
+ SetBinary = linux_raw_sys::general::fsconfig_command::FSCONFIG_SET_BINARY as u32,
+
+ /// `FSCONFIG_SET_PATH`
+ SetPath = linux_raw_sys::general::fsconfig_command::FSCONFIG_SET_PATH as u32,
+
+ /// `FSCONFIG_SET_PATH_EMPTY`
+ SetPathEmpty = linux_raw_sys::general::fsconfig_command::FSCONFIG_SET_PATH_EMPTY as u32,
+
+ /// `FSCONFIG_SET_FD`
+ SetFd = linux_raw_sys::general::fsconfig_command::FSCONFIG_SET_FD as u32,
+
+ /// `FSCONFIG_CMD_CREATE`
+ Create = linux_raw_sys::general::fsconfig_command::FSCONFIG_CMD_CREATE as u32,
+
+ /// `FSCONFIG_CMD_RECONFIGURE`
+ Reconfigure = linux_raw_sys::general::fsconfig_command::FSCONFIG_CMD_RECONFIGURE as u32,
+
+ /// `FSCONFIG_CMD_CREATE_EXCL` (since Linux 6.6)
+ CreateExclusive = linux_raw_sys::general::fsconfig_command::FSCONFIG_CMD_CREATE_EXCL as u32,
+}
+
+bitflags! {
+ /// `MOUNT_ATTR_*` constants for use with [`fsmount`].
+ ///
+ /// [`fsmount`]: crate::mount::fsmount
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct MountAttrFlags: ffi::c_uint {
+ /// `MOUNT_ATTR_RDONLY`
+ const MOUNT_ATTR_RDONLY = linux_raw_sys::general::MOUNT_ATTR_RDONLY;
+
+ /// `MOUNT_ATTR_NOSUID`
+ const MOUNT_ATTR_NOSUID = linux_raw_sys::general::MOUNT_ATTR_NOSUID;
+
+ /// `MOUNT_ATTR_NODEV`
+ const MOUNT_ATTR_NODEV = linux_raw_sys::general::MOUNT_ATTR_NODEV;
+
+ /// `MOUNT_ATTR_NOEXEC`
+ const MOUNT_ATTR_NOEXEC = linux_raw_sys::general::MOUNT_ATTR_NOEXEC;
+
+ /// `MOUNT_ATTR__ATIME`
+ const MOUNT_ATTR__ATIME = linux_raw_sys::general::MOUNT_ATTR__ATIME;
+
+ /// `MOUNT_ATTR_RELATIME`
+ const MOUNT_ATTR_RELATIME = linux_raw_sys::general::MOUNT_ATTR_RELATIME;
+
+ /// `MOUNT_ATTR_NOATIME`
+ const MOUNT_ATTR_NOATIME = linux_raw_sys::general::MOUNT_ATTR_NOATIME;
+
+ /// `MOUNT_ATTR_STRICTATIME`
+ const MOUNT_ATTR_STRICTATIME = linux_raw_sys::general::MOUNT_ATTR_STRICTATIME;
+
+ /// `MOUNT_ATTR_NODIRATIME`
+ const MOUNT_ATTR_NODIRATIME = linux_raw_sys::general::MOUNT_ATTR_NODIRATIME;
+
+ /// `MOUNT_ATTR_NOUSER`
+ const MOUNT_ATTR_IDMAP = linux_raw_sys::general::MOUNT_ATTR_IDMAP;
+
+ /// `MOUNT_ATTR__ATIME_FLAGS`
+ const MOUNT_ATTR_NOSYMFOLLOW = linux_raw_sys::general::MOUNT_ATTR_NOSYMFOLLOW;
+
+ /// `MOUNT_ATTR__ATIME_FLAGS`
+ const MOUNT_ATTR_SIZE_VER0 = linux_raw_sys::general::MOUNT_ATTR_SIZE_VER0;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+bitflags! {
+ /// `MOVE_MOUNT_*` constants for use with [`move_mount`].
+ ///
+ /// [`move_mount`]: crate::mount::move_mount
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct MoveMountFlags: ffi::c_uint {
+ /// `MOVE_MOUNT_F_EMPTY_PATH`
+ const MOVE_MOUNT_F_SYMLINKS = linux_raw_sys::general::MOVE_MOUNT_F_SYMLINKS;
+
+ /// `MOVE_MOUNT_F_AUTOMOUNTS`
+ const MOVE_MOUNT_F_AUTOMOUNTS = linux_raw_sys::general::MOVE_MOUNT_F_AUTOMOUNTS;
+
+ /// `MOVE_MOUNT_F_EMPTY_PATH`
+ const MOVE_MOUNT_F_EMPTY_PATH = linux_raw_sys::general::MOVE_MOUNT_F_EMPTY_PATH;
+
+ /// `MOVE_MOUNT_T_SYMLINKS`
+ const MOVE_MOUNT_T_SYMLINKS = linux_raw_sys::general::MOVE_MOUNT_T_SYMLINKS;
+
+ /// `MOVE_MOUNT_T_AUTOMOUNTS`
+ const MOVE_MOUNT_T_AUTOMOUNTS = linux_raw_sys::general::MOVE_MOUNT_T_AUTOMOUNTS;
+
+ /// `MOVE_MOUNT_T_EMPTY_PATH`
+ const MOVE_MOUNT_T_EMPTY_PATH = linux_raw_sys::general::MOVE_MOUNT_T_EMPTY_PATH;
+
+ /// `MOVE_MOUNT__MASK`
+ const MOVE_MOUNT_SET_GROUP = linux_raw_sys::general::MOVE_MOUNT_SET_GROUP;
+
+ /// `MOVE_MOUNT_BENEATH` (since Linux 6.5)
+ const MOVE_MOUNT_BENEATH = linux_raw_sys::general::MOVE_MOUNT_BENEATH;
+
+ /// `MOVE_MOUNT__MASK`
+ const MOVE_MOUNT__MASK = linux_raw_sys::general::MOVE_MOUNT__MASK;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+bitflags! {
+ /// `OPENTREE_*` constants for use with [`open_tree`].
+ ///
+ /// [`open_tree`]: crate::mount::open_tree
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct OpenTreeFlags: ffi::c_uint {
+ /// `OPENTREE_CLONE`
+ const OPEN_TREE_CLONE = linux_raw_sys::general::OPEN_TREE_CLONE;
+
+ /// `OPENTREE_CLOEXEC`
+ const OPEN_TREE_CLOEXEC = linux_raw_sys::general::OPEN_TREE_CLOEXEC;
+
+ /// `AT_EMPTY_PATH`
+ const AT_EMPTY_PATH = linux_raw_sys::general::AT_EMPTY_PATH;
+
+ /// `AT_NO_AUTOMOUNT`
+ const AT_NO_AUTOMOUNT = linux_raw_sys::general::AT_NO_AUTOMOUNT;
+
+ /// `AT_RECURSIVE`
+ const AT_RECURSIVE = linux_raw_sys::general::AT_RECURSIVE;
+
+ /// `AT_SYMLINK_NOFOLLOW`
+ const AT_SYMLINK_NOFOLLOW = linux_raw_sys::general::AT_SYMLINK_NOFOLLOW;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+bitflags! {
+ /// `FSPICK_*` constants for use with [`fspick`].
+ ///
+ /// [`fspick`]: crate::mount::fspick
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct FsPickFlags: ffi::c_uint {
+ /// `FSPICK_CLOEXEC`
+ const FSPICK_CLOEXEC = linux_raw_sys::general::FSPICK_CLOEXEC;
+
+ /// `FSPICK_SYMLINK_NOFOLLOW`
+ const FSPICK_SYMLINK_NOFOLLOW = linux_raw_sys::general::FSPICK_SYMLINK_NOFOLLOW;
+
+ /// `FSPICK_NO_AUTOMOUNT`
+ const FSPICK_NO_AUTOMOUNT = linux_raw_sys::general::FSPICK_NO_AUTOMOUNT;
+
+ /// `FSPICK_EMPTY_PATH`
+ const FSPICK_EMPTY_PATH = linux_raw_sys::general::FSPICK_EMPTY_PATH;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+bitflags! {
+ /// `MS_*` constants for use with [`mount_change`].
+ ///
+ /// [`mount_change`]: crate::mount::mount_change
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct MountPropagationFlags: ffi::c_uint {
+ /// `MS_SILENT`
+ const SILENT = linux_raw_sys::general::MS_SILENT;
+ /// `MS_SHARED`
+ const SHARED = linux_raw_sys::general::MS_SHARED;
+ /// `MS_PRIVATE`
+ const PRIVATE = linux_raw_sys::general::MS_PRIVATE;
+ /// Mark a mount as a downstream of its current peer group.
+ ///
+ /// Mount and unmount events propagate from the upstream peer group
+ /// into the downstream.
+ ///
+ /// In Linux documentation, this flag is named `MS_SLAVE`, and the
+ /// concepts of “upstream” and “downstream” are called
+ /// “master” and “slave”.
+ #[doc(alias = "SLAVE")]
+ const DOWNSTREAM = linux_raw_sys::general::MS_SLAVE;
+ /// `MS_UNBINDABLE`
+ const UNBINDABLE = linux_raw_sys::general::MS_UNBINDABLE;
+ /// `MS_REC`
+ const REC = linux_raw_sys::general::MS_REC;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+bitflags! {
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub(crate) struct InternalMountFlags: ffi::c_uint {
+ const REMOUNT = linux_raw_sys::general::MS_REMOUNT;
+ const MOVE = linux_raw_sys::general::MS_MOVE;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+#[repr(transparent)]
+pub(crate) struct MountFlagsArg(pub(crate) ffi::c_uint);
diff --git a/vendor/rustix/src/backend/linux_raw/net/addr.rs b/vendor/rustix/src/backend/linux_raw/net/addr.rs
new file mode 100644
index 00000000..7138b571
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/net/addr.rs
@@ -0,0 +1,300 @@
+//! Socket address utilities.
+//!
+//! # Safety
+//!
+//! This file uses `CStr::from_bytes_with_nul_unchecked` on a string it knows
+//! to be NUL-terminated.
+#![allow(unsafe_code)]
+
+use crate::backend::c;
+use crate::ffi::CStr;
+use crate::net::addr::SocketAddrLen;
+use crate::net::AddressFamily;
+use crate::{io, path};
+use core::cmp::Ordering;
+use core::hash::{Hash, Hasher};
+use core::{fmt, slice};
+#[cfg(feature = "alloc")]
+use {crate::ffi::CString, alloc::borrow::Cow, alloc::vec::Vec};
+
+/// `struct sockaddr_un`
+#[derive(Clone)]
+#[doc(alias = "sockaddr_un")]
+pub struct SocketAddrUnix {
+ pub(crate) unix: c::sockaddr_un,
+ len: c::socklen_t,
+}
+
+impl SocketAddrUnix {
+ /// Construct a new Unix-domain address from a filesystem path.
+ #[inline]
+ pub fn new<P: path::Arg>(path: P) -> io::Result<Self> {
+ path.into_with_c_str(Self::_new)
+ }
+
+ #[inline]
+ fn _new(path: &CStr) -> io::Result<Self> {
+ let mut unix = Self::init();
+ let mut bytes = path.to_bytes_with_nul();
+ if bytes.len() > unix.sun_path.len() {
+ bytes = path.to_bytes(); // without NUL
+ if bytes.len() > unix.sun_path.len() {
+ return Err(io::Errno::NAMETOOLONG);
+ }
+ }
+ for (i, b) in bytes.iter().enumerate() {
+ unix.sun_path[i] = bitcast!(*b);
+ }
+ let len = offsetof_sun_path() + bytes.len();
+ let len = len.try_into().unwrap();
+ Ok(Self { unix, len })
+ }
+
+ /// Construct a new abstract Unix-domain address from a byte slice.
+ #[inline]
+ pub fn new_abstract_name(name: &[u8]) -> io::Result<Self> {
+ let mut unix = Self::init();
+ let id = &mut unix.sun_path[1..];
+
+ // SAFETY: Convert `&mut [c_char]` to `&mut [u8]`.
+ let id = unsafe { slice::from_raw_parts_mut(id.as_mut_ptr().cast::<u8>(), id.len()) };
+
+ if let Some(id) = id.get_mut(..name.len()) {
+ id.copy_from_slice(name);
+ let len = offsetof_sun_path() + 1 + name.len();
+ let len = len.try_into().unwrap();
+ Ok(Self { unix, len })
+ } else {
+ Err(io::Errno::NAMETOOLONG)
+ }
+ }
+
+ /// Construct a new unnamed address.
+ ///
+ /// The kernel will assign an abstract Unix-domain address to the socket
+ /// when you call [`bind`][crate::net::bind]. You can inspect the assigned
+ /// name with [`getsockname`][crate::net::getsockname].
+ ///
+ /// # References
+ /// - [Linux]
+ ///
+ /// [Linux]: https://www.man7.org/linux/man-pages/man7/unix.7.html
+ #[inline]
+ pub fn new_unnamed() -> Self {
+ Self {
+ unix: Self::init(),
+ len: offsetof_sun_path() as SocketAddrLen,
+ }
+ }
+
+ const fn init() -> c::sockaddr_un {
+ c::sockaddr_un {
+ sun_family: c::AF_UNIX as _,
+ sun_path: [0; 108],
+ }
+ }
+
+ /// For a filesystem path address, return the path.
+ #[inline]
+ #[cfg(feature = "alloc")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
+ pub fn path(&self) -> Option<Cow<'_, CStr>> {
+ let bytes = self.bytes()?;
+ if !bytes.is_empty() && bytes[0] != 0 {
+ if self.unix.sun_path.len() == bytes.len() {
+ // SAFETY: There are no NULs contained in bytes.
+ unsafe { Self::path_with_termination(bytes) }
+ } else {
+ // SAFETY: `from_bytes_with_nul_unchecked` since the string is
+ // NUL-terminated.
+ Some(unsafe { CStr::from_bytes_with_nul_unchecked(bytes) }.into())
+ }
+ } else {
+ None
+ }
+ }
+
+ /// If the `sun_path` field is not NUL-terminated, terminate it.
+ ///
+ /// SAFETY: The input `bytes` must not contain any NULs.
+ #[cfg(feature = "alloc")]
+ #[cold]
+ unsafe fn path_with_termination(bytes: &[u8]) -> Option<Cow<'_, CStr>> {
+ let mut owned = Vec::with_capacity(bytes.len() + 1);
+ owned.extend_from_slice(bytes);
+ owned.push(b'\0');
+ // SAFETY: `from_vec_with_nul_unchecked` since the string is
+ // NUL-terminated and `bytes` does not contain any NULs.
+ Some(Cow::Owned(
+ CString::from_vec_with_nul_unchecked(owned).into(),
+ ))
+ }
+
+ /// For a filesystem path address, return the path as a byte sequence,
+ /// excluding the NUL terminator.
+ #[inline]
+ pub fn path_bytes(&self) -> Option<&[u8]> {
+ let bytes = self.bytes()?;
+ if !bytes.is_empty() && bytes[0] != 0 {
+ if self.unix.sun_path.len() == self.len() - offsetof_sun_path() {
+ // There is no NUL terminator.
+ Some(bytes)
+ } else {
+ // Remove the NUL terminator.
+ Some(&bytes[..bytes.len() - 1])
+ }
+ } else {
+ None
+ }
+ }
+
+ /// For an abstract address, return the identifier.
+ #[inline]
+ pub fn abstract_name(&self) -> Option<&[u8]> {
+ if let [0, bytes @ ..] = self.bytes()? {
+ Some(bytes)
+ } else {
+ None
+ }
+ }
+
+ /// `true` if the socket address is unnamed.
+ #[inline]
+ pub fn is_unnamed(&self) -> bool {
+ self.bytes() == Some(&[])
+ }
+
+ #[inline]
+ pub(crate) fn addr_len(&self) -> SocketAddrLen {
+ bitcast!(self.len)
+ }
+
+ #[inline]
+ pub(crate) fn len(&self) -> usize {
+ self.addr_len() as usize
+ }
+
+ #[inline]
+ fn bytes(&self) -> Option<&[u8]> {
+ let len = self.len();
+ if len != 0 {
+ let bytes = &self.unix.sun_path[..len - offsetof_sun_path()];
+ // SAFETY: `from_raw_parts` to convert from `&[c_char]` to `&[u8]`.
+ Some(unsafe { slice::from_raw_parts(bytes.as_ptr().cast(), bytes.len()) })
+ } else {
+ None
+ }
+ }
+}
+
+impl PartialEq for SocketAddrUnix {
+ #[inline]
+ fn eq(&self, other: &Self) -> bool {
+ let self_len = self.len() - offsetof_sun_path();
+ let other_len = other.len() - offsetof_sun_path();
+ self.unix.sun_path[..self_len].eq(&other.unix.sun_path[..other_len])
+ }
+}
+
+impl Eq for SocketAddrUnix {}
+
+impl PartialOrd for SocketAddrUnix {
+ #[inline]
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Ord for SocketAddrUnix {
+ #[inline]
+ fn cmp(&self, other: &Self) -> Ordering {
+ let self_len = self.len() - offsetof_sun_path();
+ let other_len = other.len() - offsetof_sun_path();
+ self.unix.sun_path[..self_len].cmp(&other.unix.sun_path[..other_len])
+ }
+}
+
+impl Hash for SocketAddrUnix {
+ #[inline]
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ let self_len = self.len() - offsetof_sun_path();
+ self.unix.sun_path[..self_len].hash(state)
+ }
+}
+
+impl fmt::Debug for SocketAddrUnix {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ #[cfg(feature = "alloc")]
+ if let Some(path) = self.path() {
+ return path.fmt(f);
+ }
+ if let Some(bytes) = self.path_bytes() {
+ if let Ok(s) = core::str::from_utf8(bytes) {
+ return s.fmt(f);
+ }
+ return bytes.fmt(f);
+ }
+ if let Some(name) = self.abstract_name() {
+ return name.fmt(f);
+ }
+ "(unnamed)".fmt(f)
+ }
+}
+
+/// `struct sockaddr_storage`
+///
+/// This type is guaranteed to be large enough to hold any encoded socket
+/// address.
+#[repr(transparent)]
+#[derive(Copy, Clone)]
+#[doc(alias = "sockaddr_storage")]
+pub struct SocketAddrStorage(c::sockaddr_storage);
+
+// SAFETY: Bindgen adds a union with a raw pointer for alignment but it's never
+// used. `sockaddr_storage` is just a bunch of bytes and it doesn't hold
+// pointers.
+unsafe impl Send for SocketAddrStorage {}
+
+// SAFETY: Same as with `Send`.
+unsafe impl Sync for SocketAddrStorage {}
+
+impl SocketAddrStorage {
+ /// Return a socket addr storage initialized to all zero bytes. The
+ /// `sa_family` is set to [`AddressFamily::UNSPEC`].
+ pub fn zeroed() -> Self {
+ assert_eq!(c::AF_UNSPEC, 0);
+ // SAFETY: `sockaddr_storage` is meant to be zero-initializable.
+ unsafe { core::mem::zeroed() }
+ }
+
+ /// Return the `sa_family` of this socket address.
+ pub fn family(&self) -> AddressFamily {
+ // SAFETY: `self.0` is a `sockaddr_storage` so it has enough space.
+ unsafe {
+ AddressFamily::from_raw(crate::backend::net::read_sockaddr::read_sa_family(
+ crate::utils::as_ptr(&self.0).cast::<c::sockaddr>(),
+ ))
+ }
+ }
+
+ /// Clear the `sa_family` of this socket address to
+ /// [`AddressFamily::UNSPEC`].
+ pub fn clear_family(&mut self) {
+ // SAFETY: `self.0` is a `sockaddr_storage` so it has enough space.
+ unsafe {
+ crate::backend::net::read_sockaddr::initialize_family_to_unspec(
+ crate::utils::as_mut_ptr(&mut self.0).cast::<c::sockaddr>(),
+ )
+ }
+ }
+}
+
+/// Return the offset of the `sun_path` field of `sockaddr_un`.
+#[inline]
+pub(crate) fn offsetof_sun_path() -> usize {
+ let z = c::sockaddr_un {
+ sun_family: 0_u16,
+ sun_path: [0; 108],
+ };
+ (crate::utils::as_ptr(&z.sun_path) as usize) - (crate::utils::as_ptr(&z) as usize)
+}
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 00000000..169954f2
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/net/mod.rs
@@ -0,0 +1,8 @@
+pub(crate) mod addr;
+pub(crate) mod msghdr;
+pub(crate) mod netdevice;
+pub(crate) mod read_sockaddr;
+pub(crate) mod send_recv;
+pub(crate) mod sockopt;
+pub(crate) mod syscalls;
+pub(crate) mod write_sockaddr;
diff --git a/vendor/rustix/src/backend/linux_raw/net/msghdr.rs b/vendor/rustix/src/backend/linux_raw/net/msghdr.rs
new file mode 100644
index 00000000..0343e18c
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/net/msghdr.rs
@@ -0,0 +1,125 @@
+//! Utilities for dealing with message headers.
+//!
+//! These take closures rather than returning a `c::msghdr` directly because
+//! the message headers may reference stack-local data.
+
+#![allow(unsafe_code)]
+
+use crate::backend::c;
+
+use crate::io::{self, IoSlice, IoSliceMut};
+use crate::net::addr::SocketAddrArg;
+use crate::net::{RecvAncillaryBuffer, SendAncillaryBuffer, SocketAddrBuf};
+
+use core::ptr::null_mut;
+
+fn msg_iov_len(len: usize) -> c::size_t {
+ // This cast cannot overflow.
+ len as c::size_t
+}
+
+fn msg_control_len(len: usize) -> c::size_t {
+ // Same as above.
+ len as c::size_t
+}
+
+/// Create a message header intended to receive a datagram.
+///
+/// # Safety
+///
+/// If `f` dereferences the pointers in the `msghdr`, it must do so only within
+/// the bounds indicated by the associated lengths in the `msghdr`.
+///
+/// And, if `f` returns `Ok`, it must have updated the `msg_controllen` field
+/// of the `msghdr` to indicate how many bytes it initialized.
+pub(crate) unsafe fn with_recv_msghdr<R>(
+ name: &mut SocketAddrBuf,
+ iov: &mut [IoSliceMut<'_>],
+ control: &mut RecvAncillaryBuffer<'_>,
+ f: impl FnOnce(&mut c::msghdr) -> io::Result<R>,
+) -> io::Result<R> {
+ control.clear();
+
+ let mut msghdr = c::msghdr {
+ msg_name: name.storage.as_mut_ptr().cast(),
+ msg_namelen: bitcast!(name.len),
+ msg_iov: iov.as_mut_ptr().cast(),
+ msg_iovlen: msg_iov_len(iov.len()),
+ msg_control: control.as_control_ptr().cast(),
+ msg_controllen: msg_control_len(control.control_len()),
+ msg_flags: 0,
+ };
+
+ let res = f(&mut msghdr);
+
+ // Reset the control length.
+ if res.is_ok() {
+ // SAFETY: `f` returned `Ok`, so our safety condition requires `f` to
+ // have initialized `msg_controllen` bytes.
+ control.set_control_len(msghdr.msg_controllen as usize);
+ }
+
+ name.len = bitcast!(msghdr.msg_namelen);
+
+ res
+}
+
+/// Create a message header intended to send without an address.
+///
+/// The returned `msghdr` will contain raw pointers to the memory
+/// referenced by `iov` and `control`.
+pub(crate) fn noaddr_msghdr(
+ iov: &[IoSlice<'_>],
+ control: &mut SendAncillaryBuffer<'_, '_, '_>,
+) -> c::msghdr {
+ c::msghdr {
+ msg_name: null_mut(),
+ msg_namelen: 0,
+ msg_iov: iov.as_ptr() as _,
+ msg_iovlen: msg_iov_len(iov.len()),
+ msg_control: control.as_control_ptr().cast(),
+ msg_controllen: msg_control_len(control.control_len()),
+ msg_flags: 0,
+ }
+}
+
+/// Create a message header intended to send with the specified address.
+///
+/// This creates a `c::msghdr` and calls a function `f` on it. The `msghdr`'s
+/// raw pointers may point to temporaries, so this function should avoid
+/// storing the pointers anywhere that would outlive the function call.
+///
+/// # Safety
+///
+/// If `f` dereferences the pointers in the `msghdr`, it must do so only within
+/// the bounds indicated by the associated lengths in the `msghdr`.
+pub(crate) unsafe fn with_msghdr<R>(
+ addr: &impl SocketAddrArg,
+ iov: &[IoSlice<'_>],
+ control: &mut SendAncillaryBuffer<'_, '_, '_>,
+ f: impl FnOnce(&c::msghdr) -> R,
+) -> R {
+ addr.with_sockaddr(|addr_ptr, addr_len| {
+ // Pass a reference to the `c::msghdr` instead of passing it by value
+ // because it may contain pointers to temporary objects that won't live
+ // beyond the call to `with_sockaddr`.
+ let mut msghdr = noaddr_msghdr(iov, control);
+ msghdr.msg_name = addr_ptr as _;
+ msghdr.msg_namelen = bitcast!(addr_len);
+
+ f(&msghdr)
+ })
+}
+
+/// Create a zero-initialized message header struct value.
+pub(crate) fn zero_msghdr() -> c::msghdr {
+ c::msghdr {
+ msg_name: null_mut(),
+ msg_namelen: 0,
+ msg_iov: null_mut(),
+ msg_iovlen: 0,
+ msg_control: null_mut(),
+ msg_controllen: 0,
+ msg_flags: 0,
+ }
+}
diff --git a/vendor/rustix/src/backend/linux_raw/net/netdevice.rs b/vendor/rustix/src/backend/linux_raw/net/netdevice.rs
new file mode 100644
index 00000000..d3c2a964
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/net/netdevice.rs
@@ -0,0 +1,70 @@
+//! Wrappers for netdevice ioctls.
+
+#![allow(unsafe_code)]
+
+use crate::backend::io::syscalls::ioctl;
+use crate::fd::BorrowedFd;
+use crate::io;
+use core::ptr::addr_of_mut;
+use core::{slice, str};
+use linux_raw_sys::ctypes::c_char;
+use linux_raw_sys::ioctl::SIOCGIFINDEX;
+#[cfg(feature = "alloc")]
+use linux_raw_sys::ioctl::SIOCGIFNAME;
+use linux_raw_sys::net::{ifreq, ifreq__bindgen_ty_1, ifreq__bindgen_ty_2, IFNAMSIZ};
+#[cfg(feature = "alloc")]
+use {alloc::borrow::ToOwned, alloc::string::String};
+
+pub(crate) fn name_to_index(fd: BorrowedFd<'_>, if_name: &str) -> io::Result<u32> {
+ let if_name_bytes = if_name.as_bytes();
+ if if_name_bytes.len() >= IFNAMSIZ as usize {
+ return Err(io::Errno::NODEV);
+ }
+ if if_name_bytes.contains(&0) {
+ return Err(io::Errno::NODEV);
+ }
+
+ // SAFETY: Convert `&[u8]` to `&[c_char]`.
+ let if_name_bytes = unsafe {
+ slice::from_raw_parts(if_name_bytes.as_ptr().cast::<c_char>(), if_name_bytes.len())
+ };
+
+ let mut ifreq = ifreq {
+ ifr_ifrn: ifreq__bindgen_ty_1 { ifrn_name: [0; 16] },
+ ifr_ifru: ifreq__bindgen_ty_2 { ifru_ivalue: 0 },
+ };
+ unsafe { ifreq.ifr_ifrn.ifrn_name[..if_name_bytes.len()].copy_from_slice(if_name_bytes) };
+
+ unsafe { ioctl(fd, SIOCGIFINDEX, addr_of_mut!(ifreq).cast()) }?;
+ let index = unsafe { ifreq.ifr_ifru.ifru_ivalue };
+ Ok(index as u32)
+}
+
+#[cfg(feature = "alloc")]
+pub(crate) fn index_to_name(fd: BorrowedFd<'_>, index: u32) -> io::Result<String> {
+ let mut ifreq = ifreq {
+ ifr_ifrn: ifreq__bindgen_ty_1 { ifrn_name: [0; 16] },
+ ifr_ifru: ifreq__bindgen_ty_2 {
+ ifru_ivalue: index as _,
+ },
+ };
+
+ unsafe { ioctl(fd, SIOCGIFNAME, addr_of_mut!(ifreq).cast()) }?;
+
+ if let Some(nul_byte) = unsafe { ifreq.ifr_ifrn.ifrn_name }
+ .iter()
+ .position(|ch| *ch == 0)
+ {
+ let ifrn_name = unsafe { &ifreq.ifr_ifrn.ifrn_name[..nul_byte] };
+
+ // SAFETY: Convert `&[c_char]` to `&[u8]`.
+ let ifrn_name =
+ unsafe { slice::from_raw_parts(ifrn_name.as_ptr().cast::<u8>(), ifrn_name.len()) };
+
+ str::from_utf8(ifrn_name)
+ .map_err(|_| io::Errno::ILSEQ)
+ .map(ToOwned::to_owned)
+ } else {
+ Err(io::Errno::INVAL)
+ }
+}
diff --git a/vendor/rustix/src/backend/linux_raw/net/read_sockaddr.rs b/vendor/rustix/src/backend/linux_raw/net/read_sockaddr.rs
new file mode 100644
index 00000000..f18cd483
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/net/read_sockaddr.rs
@@ -0,0 +1,155 @@
+//! The BSD sockets API requires us to read the `sa_family` field before we can
+//! interpret the rest of a `sockaddr` produced by the kernel.
+#![allow(unsafe_code)]
+
+use crate::backend::c;
+use crate::io::Errno;
+use crate::net::addr::SocketAddrLen;
+use crate::net::netlink::SocketAddrNetlink;
+#[cfg(target_os = "linux")]
+use crate::net::xdp::{SocketAddrXdp, SocketAddrXdpFlags};
+use crate::net::{
+ AddressFamily, Ipv4Addr, Ipv6Addr, SocketAddrAny, SocketAddrUnix, SocketAddrV4, SocketAddrV6,
+};
+use core::mem::size_of;
+use core::slice;
+
+// This must match the header of `sockaddr`.
+#[repr(C)]
+pub(crate) struct sockaddr_header {
+ sa_family: u16,
+}
+
+/// Read the `sa_family` field from a socket address returned from the OS.
+///
+/// # Safety
+///
+/// `storage` must point to a least an initialized `sockaddr_header`.
+#[inline]
+pub(crate) const unsafe fn read_sa_family(storage: *const c::sockaddr) -> u16 {
+ // Assert that we know the layout of `sockaddr`.
+ let _ = c::sockaddr {
+ __storage: c::sockaddr_storage {
+ __bindgen_anon_1: linux_raw_sys::net::__kernel_sockaddr_storage__bindgen_ty_1 {
+ __bindgen_anon_1:
+ linux_raw_sys::net::__kernel_sockaddr_storage__bindgen_ty_1__bindgen_ty_1 {
+ ss_family: 0_u16,
+ __data: [0; 126_usize],
+ },
+ },
+ },
+ };
+
+ (*storage.cast::<sockaddr_header>()).sa_family
+}
+
+/// Set the `sa_family` field of a socket address to `AF_UNSPEC`, so that we
+/// can test for `AF_UNSPEC` to test whether it was stored to.
+///
+/// # Safety
+///
+/// `storage` must point to a least an initialized `sockaddr_header`.
+#[inline]
+pub(crate) unsafe fn initialize_family_to_unspec(storage: *mut c::sockaddr) {
+ (*storage.cast::<sockaddr_header>()).sa_family = c::AF_UNSPEC as _;
+}
+
+/// Check if a socket address returned from the OS is considered non-empty.
+#[inline]
+pub(crate) unsafe fn sockaddr_nonempty(_storage: *const c::sockaddr, len: SocketAddrLen) -> bool {
+ len != 0
+}
+
+#[inline]
+pub(crate) fn read_sockaddr_v4(addr: &SocketAddrAny) -> Result<SocketAddrV4, Errno> {
+ if addr.address_family() != AddressFamily::INET {
+ return Err(Errno::AFNOSUPPORT);
+ }
+ assert!(addr.addr_len() as usize >= size_of::<c::sockaddr_in>());
+ let decode = unsafe { &*addr.as_ptr().cast::<c::sockaddr_in>() };
+ Ok(SocketAddrV4::new(
+ Ipv4Addr::from(u32::from_be(decode.sin_addr.s_addr)),
+ u16::from_be(decode.sin_port),
+ ))
+}
+
+#[inline]
+pub(crate) fn read_sockaddr_v6(addr: &SocketAddrAny) -> Result<SocketAddrV6, Errno> {
+ if addr.address_family() != AddressFamily::INET6 {
+ return Err(Errno::AFNOSUPPORT);
+ }
+ assert!(addr.addr_len() as usize >= size_of::<c::sockaddr_in6>());
+ let decode = unsafe { &*addr.as_ptr().cast::<c::sockaddr_in6>() };
+ Ok(SocketAddrV6::new(
+ Ipv6Addr::from(unsafe { decode.sin6_addr.in6_u.u6_addr8 }),
+ u16::from_be(decode.sin6_port),
+ u32::from_be(decode.sin6_flowinfo),
+ decode.sin6_scope_id,
+ ))
+}
+
+#[inline]
+pub(crate) fn read_sockaddr_unix(addr: &SocketAddrAny) -> Result<SocketAddrUnix, Errno> {
+ if addr.address_family() != AddressFamily::UNIX {
+ return Err(Errno::AFNOSUPPORT);
+ }
+ let offsetof_sun_path = super::addr::offsetof_sun_path();
+ let len = addr.addr_len() as usize;
+
+ assert!(len >= offsetof_sun_path);
+
+ if len == offsetof_sun_path {
+ SocketAddrUnix::new(&[][..])
+ } else {
+ let decode = unsafe { &*addr.as_ptr().cast::<c::sockaddr_un>() };
+
+ // On Linux check for Linux's [abstract namespace].
+ //
+ // [abstract namespace]: https://man7.org/linux/man-pages/man7/unix.7.html
+ if decode.sun_path[0] == 0 {
+ let bytes = &decode.sun_path[1..len - offsetof_sun_path];
+
+ // SAFETY: Convert `&[c_char]` to `&[u8]`.
+ let bytes = unsafe { slice::from_raw_parts(bytes.as_ptr().cast::<u8>(), bytes.len()) };
+
+ return SocketAddrUnix::new_abstract_name(bytes);
+ }
+
+ // Otherwise we expect a NUL-terminated filesystem path.
+ let bytes = &decode.sun_path[..len - 1 - offsetof_sun_path];
+
+ // SAFETY: Convert `&[c_char]` to `&[u8]`.
+ let bytes = unsafe { slice::from_raw_parts(bytes.as_ptr().cast::<u8>(), bytes.len()) };
+
+ assert_eq!(decode.sun_path[len - 1 - offsetof_sun_path], 0);
+ SocketAddrUnix::new(bytes)
+ }
+}
+
+#[inline]
+pub(crate) fn read_sockaddr_xdp(addr: &SocketAddrAny) -> Result<SocketAddrXdp, Errno> {
+ if addr.address_family() != AddressFamily::XDP {
+ return Err(Errno::AFNOSUPPORT);
+ }
+ assert!(addr.addr_len() as usize >= size_of::<c::sockaddr_xdp>());
+ let decode = unsafe { &*addr.as_ptr().cast::<c::sockaddr_xdp>() };
+
+ // This ignores the `sxdp_shared_umem_fd` field, which is only expected to
+ // be significant in `bind` calls, and not returned from `acceptfrom` or
+ // `recvmsg` or similar.
+ Ok(SocketAddrXdp::new(
+ SocketAddrXdpFlags::from_bits_retain(decode.sxdp_flags),
+ u32::from_be(decode.sxdp_ifindex),
+ u32::from_be(decode.sxdp_queue_id),
+ ))
+}
+
+#[inline]
+pub(crate) fn read_sockaddr_netlink(addr: &SocketAddrAny) -> Result<SocketAddrNetlink, Errno> {
+ if addr.address_family() != AddressFamily::NETLINK {
+ return Err(Errno::AFNOSUPPORT);
+ }
+ assert!(addr.addr_len() as usize >= size_of::<c::sockaddr_nl>());
+ let decode = unsafe { &*addr.as_ptr().cast::<c::sockaddr_nl>() };
+ Ok(SocketAddrNetlink::new(decode.nl_pid, decode.nl_groups))
+}
diff --git a/vendor/rustix/src/backend/linux_raw/net/send_recv.rs b/vendor/rustix/src/backend/linux_raw/net/send_recv.rs
new file mode 100644
index 00000000..3262d01f
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/net/send_recv.rs
@@ -0,0 +1,87 @@
+use crate::backend::c;
+use bitflags::bitflags;
+
+bitflags! {
+ /// `MSG_*` flags for use with [`send`], [`sendto`], and related
+ /// functions.
+ ///
+ /// [`send`]: crate::net::send
+ /// [`sendto`]: crate::net::sendto
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct SendFlags: u32 {
+ /// `MSG_CONFIRM`
+ const CONFIRM = c::MSG_CONFIRM;
+ /// `MSG_DONTROUTE`
+ const DONTROUTE = c::MSG_DONTROUTE;
+ /// `MSG_DONTWAIT`
+ const DONTWAIT = c::MSG_DONTWAIT;
+ /// `MSG_EOR`
+ const EOR = c::MSG_EOR;
+ /// `MSG_MORE`
+ const MORE = c::MSG_MORE;
+ /// `MSG_NOSIGNAL`
+ const NOSIGNAL = c::MSG_NOSIGNAL;
+ /// `MSG_OOB`
+ const OOB = c::MSG_OOB;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+bitflags! {
+ /// `MSG_*` flags for use with [`recv`], [`recvfrom`], and related
+ /// functions.
+ ///
+ /// [`recv`]: crate::net::recv
+ /// [`recvfrom`]: crate::net::recvfrom
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct RecvFlags: u32 {
+ /// `MSG_CMSG_CLOEXEC`
+ const CMSG_CLOEXEC = c::MSG_CMSG_CLOEXEC;
+ /// `MSG_DONTWAIT`
+ const DONTWAIT = c::MSG_DONTWAIT;
+ /// `MSG_ERRQUEUE`
+ const ERRQUEUE = c::MSG_ERRQUEUE;
+ /// `MSG_OOB`
+ const OOB = c::MSG_OOB;
+ /// `MSG_PEEK`
+ const PEEK = c::MSG_PEEK;
+ /// `MSG_TRUNC`
+ const TRUNC = c::MSG_TRUNC;
+ /// `MSG_WAITALL`
+ const WAITALL = c::MSG_WAITALL;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+bitflags! {
+ /// `MSG_*` flags returned from [`recvmsg`], in the `flags` field of
+ /// [`RecvMsg`]
+ ///
+ /// [`recvmsg`]: crate::net::recvmsg
+ /// [`RecvMsg`]: crate::net::RecvMsg
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct ReturnFlags: u32 {
+ /// `MSG_OOB`
+ const OOB = c::MSG_OOB;
+ /// `MSG_EOR`
+ const EOR = c::MSG_EOR;
+ /// `MSG_TRUNC`
+ const TRUNC = c::MSG_TRUNC;
+ /// `MSG_CTRUNC`
+ const CTRUNC = c::MSG_CTRUNC;
+ /// `MSG_ERRQUEUE`
+ const ERRQUEUE = c::MSG_ERRQUEUE;
+ /// `MSG_CMSG_CLOEXEC`
+ const CMSG_CLOEXEC = c::MSG_CMSG_CLOEXEC;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
diff --git a/vendor/rustix/src/backend/linux_raw/net/sockopt.rs b/vendor/rustix/src/backend/linux_raw/net/sockopt.rs
new file mode 100644
index 00000000..3e5ea1fd
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/net/sockopt.rs
@@ -0,0 +1,1099 @@
+//! linux_raw syscalls supporting `rustix::net::sockopt`.
+//!
+//! # Safety
+//!
+//! See the `rustix::backend` module documentation for details.
+#![allow(unsafe_code, clippy::undocumented_unsafe_blocks)]
+
+use crate::backend::c;
+use crate::backend::conv::{by_mut, c_uint, ret, socklen_t};
+use crate::fd::BorrowedFd;
+#[cfg(feature = "alloc")]
+use crate::ffi::CStr;
+use crate::io;
+use crate::net::sockopt::Timeout;
+#[cfg(target_os = "linux")]
+use crate::net::xdp::{XdpMmapOffsets, XdpOptionsFlags, XdpRingOffset, XdpStatistics, XdpUmemReg};
+use crate::net::{
+ AddressFamily, Ipv4Addr, Ipv6Addr, Protocol, RawProtocol, SocketAddrBuf, SocketAddrV4,
+ SocketAddrV6, SocketType, UCred,
+};
+#[cfg(feature = "alloc")]
+use alloc::borrow::ToOwned as _;
+#[cfg(feature = "alloc")]
+use alloc::string::String;
+use core::mem::{size_of, MaybeUninit};
+use core::time::Duration;
+use linux_raw_sys::general::{__kernel_old_timeval, __kernel_sock_timeval};
+use linux_raw_sys::net::{IPV6_MTU, IPV6_MULTICAST_IF, IP_MTU, IP_MULTICAST_IF};
+#[cfg(target_os = "linux")]
+use linux_raw_sys::xdp::{xdp_mmap_offsets, xdp_statistics, xdp_statistics_v1};
+#[cfg(target_arch = "x86")]
+use {
+ crate::backend::conv::{slice_just_addr, x86_sys},
+ crate::backend::reg::{ArgReg, SocketArg},
+ linux_raw_sys::net::{SYS_GETSOCKOPT, SYS_SETSOCKOPT},
+};
+
+#[inline]
+fn getsockopt<T: Copy>(fd: BorrowedFd<'_>, level: u32, optname: u32) -> io::Result<T> {
+ let mut optlen: c::socklen_t = size_of::<T>().try_into().unwrap();
+ debug_assert!(
+ optlen as usize >= size_of::<c::c_int>(),
+ "Socket APIs don't ever use `bool` directly"
+ );
+
+ let mut value = MaybeUninit::<T>::uninit();
+ getsockopt_raw(fd, level, optname, &mut value, &mut optlen)?;
+
+ assert_eq!(
+ optlen as usize,
+ size_of::<T>(),
+ "unexpected getsockopt size"
+ );
+
+ unsafe { Ok(value.assume_init()) }
+}
+
+#[inline]
+fn getsockopt_raw<T>(
+ fd: BorrowedFd<'_>,
+ level: u32,
+ optname: u32,
+ value: &mut MaybeUninit<T>,
+ optlen: &mut c::socklen_t,
+) -> io::Result<()> {
+ #[cfg(not(target_arch = "x86"))]
+ unsafe {
+ ret(syscall!(
+ __NR_getsockopt,
+ fd,
+ c_uint(level),
+ c_uint(optname),
+ value,
+ by_mut(optlen)
+ ))
+ }
+ #[cfg(target_arch = "x86")]
+ unsafe {
+ ret(syscall!(
+ __NR_socketcall,
+ x86_sys(SYS_GETSOCKOPT),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
+ fd.into(),
+ c_uint(level),
+ c_uint(optname),
+ value.into(),
+ by_mut(optlen),
+ ])
+ ))
+ }
+}
+
+#[inline]
+fn setsockopt<T: Copy>(fd: BorrowedFd<'_>, level: u32, optname: u32, value: T) -> io::Result<()> {
+ let optlen = size_of::<T>().try_into().unwrap();
+ debug_assert!(
+ optlen as usize >= size_of::<c::c_int>(),
+ "Socket APIs don't ever use `bool` directly"
+ );
+ setsockopt_raw(fd, level, optname, &value, optlen)
+}
+
+#[inline]
+fn setsockopt_raw<T>(
+ fd: BorrowedFd<'_>,
+ level: u32,
+ optname: u32,
+ ptr: *const T,
+ optlen: c::socklen_t,
+) -> io::Result<()> {
+ #[cfg(not(target_arch = "x86"))]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_setsockopt,
+ fd,
+ c_uint(level),
+ c_uint(optname),
+ ptr,
+ 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),
+ ptr.into(),
+ socklen_t(optlen),
+ ])
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn socket_type(fd: BorrowedFd<'_>) -> io::Result<SocketType> {
+ getsockopt(fd, c::SOL_SOCKET, c::SO_TYPE)
+}
+
+#[inline]
+pub(crate) fn set_socket_reuseaddr(fd: BorrowedFd<'_>, reuseaddr: bool) -> io::Result<()> {
+ setsockopt(fd, c::SOL_SOCKET, c::SO_REUSEADDR, from_bool(reuseaddr))
+}
+
+#[inline]
+pub(crate) fn socket_reuseaddr(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::SOL_SOCKET, c::SO_REUSEADDR).map(to_bool)
+}
+
+#[inline]
+pub(crate) fn set_socket_broadcast(fd: BorrowedFd<'_>, broadcast: bool) -> io::Result<()> {
+ setsockopt(fd, c::SOL_SOCKET, c::SO_BROADCAST, from_bool(broadcast))
+}
+
+#[inline]
+pub(crate) fn socket_broadcast(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::SOL_SOCKET, 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 {
+ duration_to_secs(linger)?
+ } else {
+ 0
+ };
+ let linger = c::linger {
+ l_onoff: c::c_int::from(linger.is_some()),
+ l_linger,
+ };
+ setsockopt(fd, c::SOL_SOCKET, c::SO_LINGER, linger)
+}
+
+#[inline]
+pub(crate) fn socket_linger(fd: BorrowedFd<'_>) -> io::Result<Option<Duration>> {
+ let linger: c::linger = getsockopt(fd, c::SOL_SOCKET, c::SO_LINGER)?;
+ Ok((linger.l_onoff != 0).then(|| Duration::from_secs(linger.l_linger as u64)))
+}
+
+#[inline]
+pub(crate) fn set_socket_passcred(fd: BorrowedFd<'_>, passcred: bool) -> io::Result<()> {
+ setsockopt(fd, c::SOL_SOCKET, c::SO_PASSCRED, from_bool(passcred))
+}
+
+#[inline]
+pub(crate) fn socket_passcred(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::SOL_SOCKET, 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_sock_timeval(timeout)?;
+ let optname = match id {
+ Timeout::Recv => c::SO_RCVTIMEO_NEW,
+ Timeout::Send => c::SO_SNDTIMEO_NEW,
+ };
+ match setsockopt(fd, c::SOL_SOCKET, optname, time) {
+ Err(io::Errno::NOPROTOOPT) if c::SO_RCVTIMEO_NEW != c::SO_RCVTIMEO_OLD => {
+ set_socket_timeout_old(fd, id, timeout)
+ }
+ otherwise => otherwise,
+ }
+}
+
+/// Same as `set_socket_timeout` but uses `__kernel_old_timeval` instead of
+/// `__kernel_sock_timeval` 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_timeval(timeout)?;
+ let optname = match id {
+ Timeout::Recv => c::SO_RCVTIMEO_OLD,
+ Timeout::Send => c::SO_SNDTIMEO_OLD,
+ };
+ setsockopt(fd, c::SOL_SOCKET, optname, time)
+}
+
+#[inline]
+pub(crate) fn socket_timeout(fd: BorrowedFd<'_>, id: Timeout) -> io::Result<Option<Duration>> {
+ let optname = match id {
+ Timeout::Recv => c::SO_RCVTIMEO_NEW,
+ Timeout::Send => c::SO_SNDTIMEO_NEW,
+ };
+ let time: __kernel_sock_timeval = match getsockopt(fd, c::SOL_SOCKET, optname) {
+ Err(io::Errno::NOPROTOOPT) if c::SO_RCVTIMEO_NEW != c::SO_RCVTIMEO_OLD => {
+ return socket_timeout_old(fd, id)
+ }
+ otherwise => otherwise?,
+ };
+ Ok(duration_from_linux_sock_timeval(time))
+}
+
+/// Same as `get_socket_timeout` but uses `__kernel_old_timeval` instead of
+/// `__kernel_sock_timeval` and `_OLD` constants instead of `_NEW`.
+fn socket_timeout_old(fd: BorrowedFd<'_>, id: Timeout) -> io::Result<Option<Duration>> {
+ let optname = match id {
+ Timeout::Recv => c::SO_RCVTIMEO_OLD,
+ Timeout::Send => c::SO_SNDTIMEO_OLD,
+ };
+ let time: __kernel_old_timeval = getsockopt(fd, c::SOL_SOCKET, optname)?;
+ Ok(duration_from_linux_old_timeval(time))
+}
+
+/// Convert a `__linux_sock_timeval` to a Rust `Option<Duration>`.
+#[inline]
+fn duration_from_linux_sock_timeval(time: __kernel_sock_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))
+ }
+}
+
+/// Like `duration_from_linux_sock_timeval` but uses Linux's old 32-bit
+/// `__kernel_old_timeval`.
+fn duration_from_linux_old_timeval(time: __kernel_old_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 `__kernel_sock_timeval`.
+#[inline]
+fn duration_to_linux_sock_timeval(timeout: Option<Duration>) -> io::Result<__kernel_sock_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 = __kernel_sock_timeval {
+ tv_sec: timeout.as_secs().try_into().unwrap_or(i64::MAX),
+ tv_usec: ((timeout.subsec_nanos() + 999) / 1000) as _,
+ };
+ if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
+ timeout.tv_usec = 1;
+ }
+ timeout
+ }
+ None => __kernel_sock_timeval {
+ tv_sec: 0,
+ tv_usec: 0,
+ },
+ })
+}
+
+/// Like `duration_to_linux_sock_timeval` but uses Linux's old 32-bit
+/// `__kernel_old_timeval`.
+fn duration_to_linux_old_timeval(timeout: Option<Duration>) -> io::Result<__kernel_old_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 = __kernel_old_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 => __kernel_old_timeval {
+ tv_sec: 0,
+ tv_usec: 0,
+ },
+ })
+}
+
+#[inline]
+pub(crate) fn socket_error(fd: BorrowedFd<'_>) -> io::Result<Result<(), io::Errno>> {
+ let err: c::c_int = getsockopt(fd, c::SOL_SOCKET, c::SO_ERROR)?;
+ Ok(if err == 0 {
+ Ok(())
+ } else {
+ Err(io::Errno::from_raw_os_error(err))
+ })
+}
+
+#[inline]
+pub(crate) fn set_socket_keepalive(fd: BorrowedFd<'_>, keepalive: bool) -> io::Result<()> {
+ setsockopt(fd, c::SOL_SOCKET, c::SO_KEEPALIVE, from_bool(keepalive))
+}
+
+#[inline]
+pub(crate) fn socket_keepalive(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::SOL_SOCKET, c::SO_KEEPALIVE).map(to_bool)
+}
+
+#[inline]
+pub(crate) fn set_socket_recv_buffer_size(fd: BorrowedFd<'_>, size: usize) -> io::Result<()> {
+ let size: c::c_int = size.try_into().map_err(|_| io::Errno::INVAL)?;
+ setsockopt(fd, c::SOL_SOCKET, c::SO_RCVBUF, size)
+}
+
+#[inline]
+pub(crate) fn set_socket_recv_buffer_size_force(fd: BorrowedFd<'_>, size: usize) -> io::Result<()> {
+ let size: c::c_int = size.try_into().map_err(|_| io::Errno::INVAL)?;
+ setsockopt(fd, c::SOL_SOCKET, c::SO_RCVBUFFORCE, size)
+}
+
+#[inline]
+pub(crate) fn socket_recv_buffer_size(fd: BorrowedFd<'_>) -> io::Result<usize> {
+ getsockopt(fd, c::SOL_SOCKET, c::SO_RCVBUF).map(|size: u32| size as usize)
+}
+
+#[inline]
+pub(crate) fn set_socket_send_buffer_size(fd: BorrowedFd<'_>, size: usize) -> io::Result<()> {
+ let size: c::c_int = size.try_into().map_err(|_| io::Errno::INVAL)?;
+ setsockopt(fd, c::SOL_SOCKET, c::SO_SNDBUF, size)
+}
+
+#[inline]
+pub(crate) fn set_socket_send_buffer_size_force(fd: BorrowedFd<'_>, size: usize) -> io::Result<()> {
+ let size: c::c_int = size.try_into().map_err(|_| io::Errno::INVAL)?;
+ setsockopt(fd, c::SOL_SOCKET, c::SO_SNDBUFFORCE, size)
+}
+
+#[inline]
+pub(crate) fn socket_send_buffer_size(fd: BorrowedFd<'_>) -> io::Result<usize> {
+ getsockopt(fd, c::SOL_SOCKET, c::SO_SNDBUF).map(|size: u32| size as usize)
+}
+
+#[inline]
+pub(crate) fn socket_domain(fd: BorrowedFd<'_>) -> io::Result<AddressFamily> {
+ let domain: c::c_int = getsockopt(fd, c::SOL_SOCKET, c::SO_DOMAIN)?;
+ Ok(AddressFamily(
+ domain.try_into().map_err(|_| io::Errno::OPNOTSUPP)?,
+ ))
+}
+
+#[inline]
+pub(crate) fn socket_acceptconn(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::SOL_SOCKET, c::SO_ACCEPTCONN).map(to_bool)
+}
+
+#[inline]
+pub(crate) fn set_socket_oobinline(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
+ setsockopt(fd, c::SOL_SOCKET, c::SO_OOBINLINE, from_bool(value))
+}
+
+#[inline]
+pub(crate) fn socket_oobinline(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::SOL_SOCKET, c::SO_OOBINLINE).map(to_bool)
+}
+
+#[inline]
+pub(crate) fn set_socket_reuseport(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
+ setsockopt(fd, c::SOL_SOCKET, c::SO_REUSEPORT, from_bool(value))
+}
+
+#[inline]
+pub(crate) fn socket_reuseport(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::SOL_SOCKET, c::SO_REUSEPORT).map(to_bool)
+}
+
+#[inline]
+pub(crate) fn socket_protocol(fd: BorrowedFd<'_>) -> io::Result<Option<Protocol>> {
+ getsockopt(fd, c::SOL_SOCKET, c::SO_PROTOCOL)
+ .map(|raw: u32| RawProtocol::new(raw).map(Protocol::from_raw))
+}
+
+#[inline]
+pub(crate) fn socket_cookie(fd: BorrowedFd<'_>) -> io::Result<u64> {
+ getsockopt(fd, c::SOL_SOCKET, c::SO_COOKIE)
+}
+
+#[inline]
+pub(crate) fn socket_incoming_cpu(fd: BorrowedFd<'_>) -> io::Result<u32> {
+ getsockopt(fd, c::SOL_SOCKET, c::SO_INCOMING_CPU)
+}
+
+#[inline]
+pub(crate) fn set_socket_incoming_cpu(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> {
+ setsockopt(fd, c::SOL_SOCKET, c::SO_INCOMING_CPU, value)
+}
+
+#[inline]
+pub(crate) fn set_ip_ttl(fd: BorrowedFd<'_>, ttl: u32) -> io::Result<()> {
+ setsockopt(fd, c::IPPROTO_IP, c::IP_TTL, ttl)
+}
+
+#[inline]
+pub(crate) fn ip_ttl(fd: BorrowedFd<'_>) -> io::Result<u32> {
+ getsockopt(fd, c::IPPROTO_IP, c::IP_TTL)
+}
+
+#[inline]
+pub(crate) fn set_ipv6_v6only(fd: BorrowedFd<'_>, only_v6: bool) -> io::Result<()> {
+ setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_V6ONLY, from_bool(only_v6))
+}
+
+#[inline]
+pub(crate) fn ipv6_v6only(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_V6ONLY).map(to_bool)
+}
+
+#[inline]
+pub(crate) fn ip_mtu(fd: BorrowedFd<'_>) -> io::Result<u32> {
+ getsockopt(fd, c::IPPROTO_IP, IP_MTU)
+}
+
+#[inline]
+pub(crate) fn ipv6_mtu(fd: BorrowedFd<'_>) -> io::Result<u32> {
+ getsockopt(fd, c::IPPROTO_IPV6, IPV6_MTU)
+}
+
+#[inline]
+pub(crate) fn set_ip_multicast_if_with_ifindex(
+ fd: BorrowedFd<'_>,
+ multiaddr: &Ipv4Addr,
+ address: &Ipv4Addr,
+ ifindex: u32,
+) -> io::Result<()> {
+ let mreqn = to_ip_mreqn(multiaddr, address, ifindex as i32);
+ setsockopt(fd, c::IPPROTO_IP, IP_MULTICAST_IF, mreqn)
+}
+
+#[inline]
+pub(crate) fn set_ip_multicast_if(fd: BorrowedFd<'_>, value: &Ipv4Addr) -> io::Result<()> {
+ setsockopt(fd, c::IPPROTO_IP, IP_MULTICAST_IF, to_imr_addr(value))
+}
+
+#[inline]
+pub(crate) fn ip_multicast_if(fd: BorrowedFd<'_>) -> io::Result<Ipv4Addr> {
+ getsockopt(fd, c::IPPROTO_IP, IP_MULTICAST_IF).map(from_in_addr)
+}
+
+#[inline]
+pub(crate) fn set_ipv6_multicast_if(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> {
+ setsockopt(fd, c::IPPROTO_IPV6, IPV6_MULTICAST_IF, value as c::c_int)
+}
+
+#[inline]
+pub(crate) fn ipv6_multicast_if(fd: BorrowedFd<'_>) -> io::Result<u32> {
+ getsockopt(fd, c::IPPROTO_IPV6, IPV6_MULTICAST_IF)
+}
+
+#[inline]
+pub(crate) fn set_ip_multicast_loop(fd: BorrowedFd<'_>, multicast_loop: bool) -> io::Result<()> {
+ setsockopt(
+ fd,
+ c::IPPROTO_IP,
+ c::IP_MULTICAST_LOOP,
+ from_bool(multicast_loop),
+ )
+}
+
+#[inline]
+pub(crate) fn ip_multicast_loop(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::IPPROTO_IP, 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, c::IP_MULTICAST_TTL, multicast_ttl)
+}
+
+#[inline]
+pub(crate) fn ip_multicast_ttl(fd: BorrowedFd<'_>) -> io::Result<u32> {
+ getsockopt(fd, c::IPPROTO_IP, c::IP_MULTICAST_TTL)
+}
+
+#[inline]
+pub(crate) fn set_ipv6_multicast_loop(fd: BorrowedFd<'_>, multicast_loop: bool) -> io::Result<()> {
+ setsockopt(
+ fd,
+ c::IPPROTO_IPV6,
+ c::IPV6_MULTICAST_LOOP,
+ from_bool(multicast_loop),
+ )
+}
+
+#[inline]
+pub(crate) fn ipv6_multicast_loop(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::IPPROTO_IPV6, 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, c::IPV6_MULTICAST_HOPS, multicast_hops)
+}
+
+#[inline]
+pub(crate) fn ipv6_multicast_hops(fd: BorrowedFd<'_>) -> io::Result<u32> {
+ getsockopt(fd, c::IPPROTO_IP, c::IPV6_MULTICAST_HOPS)
+}
+
+#[inline]
+pub(crate) fn set_ip_add_membership(
+ fd: BorrowedFd<'_>,
+ multiaddr: &Ipv4Addr,
+ interface: &Ipv4Addr,
+) -> io::Result<()> {
+ let mreq = to_ip_mreq(multiaddr, interface);
+ setsockopt(fd, c::IPPROTO_IP, c::IP_ADD_MEMBERSHIP, mreq)
+}
+
+#[inline]
+pub(crate) fn set_ip_add_membership_with_ifindex(
+ fd: BorrowedFd<'_>,
+ multiaddr: &Ipv4Addr,
+ address: &Ipv4Addr,
+ ifindex: u32,
+) -> io::Result<()> {
+ let mreqn = to_ip_mreqn(multiaddr, address, ifindex as i32);
+ setsockopt(fd, c::IPPROTO_IP, c::IP_ADD_MEMBERSHIP, mreqn)
+}
+
+#[inline]
+pub(crate) fn set_ip_add_source_membership(
+ fd: BorrowedFd<'_>,
+ multiaddr: &Ipv4Addr,
+ interface: &Ipv4Addr,
+ sourceaddr: &Ipv4Addr,
+) -> io::Result<()> {
+ let mreq_source = to_imr_source(multiaddr, interface, sourceaddr);
+ setsockopt(fd, c::IPPROTO_IP, c::IP_ADD_SOURCE_MEMBERSHIP, mreq_source)
+}
+
+#[inline]
+pub(crate) fn set_ip_drop_source_membership(
+ fd: BorrowedFd<'_>,
+ multiaddr: &Ipv4Addr,
+ interface: &Ipv4Addr,
+ sourceaddr: &Ipv4Addr,
+) -> io::Result<()> {
+ let mreq_source = to_imr_source(multiaddr, interface, sourceaddr);
+ setsockopt(fd, c::IPPROTO_IP, c::IP_DROP_SOURCE_MEMBERSHIP, mreq_source)
+}
+
+#[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, c::IPV6_ADD_MEMBERSHIP, mreq)
+}
+
+#[inline]
+pub(crate) fn set_ip_drop_membership(
+ fd: BorrowedFd<'_>,
+ multiaddr: &Ipv4Addr,
+ interface: &Ipv4Addr,
+) -> io::Result<()> {
+ let mreq = to_ip_mreq(multiaddr, interface);
+ setsockopt(fd, c::IPPROTO_IP, c::IP_DROP_MEMBERSHIP, mreq)
+}
+
+#[inline]
+pub(crate) fn set_ip_drop_membership_with_ifindex(
+ fd: BorrowedFd<'_>,
+ multiaddr: &Ipv4Addr,
+ address: &Ipv4Addr,
+ ifindex: u32,
+) -> io::Result<()> {
+ let mreqn = to_ip_mreqn(multiaddr, address, ifindex as i32);
+ setsockopt(fd, c::IPPROTO_IP, c::IP_DROP_MEMBERSHIP, mreqn)
+}
+
+#[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, c::IPV6_DROP_MEMBERSHIP, mreq)
+}
+
+#[inline]
+pub(crate) fn ipv6_unicast_hops(fd: BorrowedFd<'_>) -> io::Result<u8> {
+ getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS).map(|hops: c::c_int| hops as u8)
+}
+
+#[inline]
+pub(crate) fn set_ipv6_unicast_hops(fd: BorrowedFd<'_>, hops: Option<u8>) -> io::Result<()> {
+ let hops = match hops {
+ Some(hops) => hops.into(),
+ None => -1,
+ };
+ setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS, hops)
+}
+
+#[inline]
+pub(crate) fn set_ip_tos(fd: BorrowedFd<'_>, value: u8) -> io::Result<()> {
+ setsockopt(fd, c::IPPROTO_IP, c::IP_TOS, i32::from(value))
+}
+
+#[inline]
+pub(crate) fn ip_tos(fd: BorrowedFd<'_>) -> io::Result<u8> {
+ let value: i32 = getsockopt(fd, c::IPPROTO_IP, c::IP_TOS)?;
+ Ok(value as u8)
+}
+
+#[inline]
+pub(crate) fn set_ip_recvtos(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
+ setsockopt(fd, c::IPPROTO_IP, c::IP_RECVTOS, from_bool(value))
+}
+
+#[inline]
+pub(crate) fn ip_recvtos(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::IPPROTO_IP, c::IP_RECVTOS).map(to_bool)
+}
+
+#[inline]
+pub(crate) fn set_ipv6_recvtclass(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
+ setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_RECVTCLASS, from_bool(value))
+}
+
+#[inline]
+pub(crate) fn ipv6_recvtclass(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_RECVTCLASS).map(to_bool)
+}
+
+#[inline]
+pub(crate) fn set_ip_freebind(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
+ setsockopt(fd, c::IPPROTO_IP, c::IP_FREEBIND, from_bool(value))
+}
+
+#[inline]
+pub(crate) fn ip_freebind(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::IPPROTO_IP, c::IP_FREEBIND).map(to_bool)
+}
+
+#[inline]
+pub(crate) fn set_ipv6_freebind(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
+ setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_FREEBIND, from_bool(value))
+}
+
+#[inline]
+pub(crate) fn ipv6_freebind(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_FREEBIND).map(to_bool)
+}
+
+#[inline]
+pub(crate) fn ip_original_dst(fd: BorrowedFd<'_>) -> io::Result<SocketAddrV4> {
+ let level = c::IPPROTO_IP;
+ let optname = c::SO_ORIGINAL_DST;
+ let mut addr = SocketAddrBuf::new();
+
+ getsockopt_raw(fd, level, optname, &mut addr.storage, &mut addr.len)?;
+
+ Ok(unsafe { addr.into_any() }.try_into().unwrap())
+}
+
+#[inline]
+pub(crate) fn ipv6_original_dst(fd: BorrowedFd<'_>) -> io::Result<SocketAddrV6> {
+ let level = c::IPPROTO_IPV6;
+ let optname = c::IP6T_SO_ORIGINAL_DST;
+ let mut addr = SocketAddrBuf::new();
+
+ getsockopt_raw(fd, level, optname, &mut addr.storage, &mut addr.len)?;
+
+ Ok(unsafe { addr.into_any() }.try_into().unwrap())
+}
+
+#[inline]
+pub(crate) fn set_ipv6_tclass(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> {
+ setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_TCLASS, value)
+}
+
+#[inline]
+pub(crate) fn ipv6_tclass(fd: BorrowedFd<'_>) -> io::Result<u32> {
+ getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_TCLASS)
+}
+
+#[inline]
+pub(crate) fn set_tcp_nodelay(fd: BorrowedFd<'_>, nodelay: bool) -> io::Result<()> {
+ setsockopt(fd, c::IPPROTO_TCP, c::TCP_NODELAY, from_bool(nodelay))
+}
+
+#[inline]
+pub(crate) fn tcp_nodelay(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::IPPROTO_TCP, c::TCP_NODELAY).map(to_bool)
+}
+
+#[inline]
+pub(crate) fn set_tcp_keepcnt(fd: BorrowedFd<'_>, count: u32) -> io::Result<()> {
+ setsockopt(fd, c::IPPROTO_TCP, c::TCP_KEEPCNT, count)
+}
+
+#[inline]
+pub(crate) fn tcp_keepcnt(fd: BorrowedFd<'_>) -> io::Result<u32> {
+ getsockopt(fd, c::IPPROTO_TCP, c::TCP_KEEPCNT)
+}
+
+#[inline]
+pub(crate) fn set_tcp_keepidle(fd: BorrowedFd<'_>, duration: Duration) -> io::Result<()> {
+ let secs: c::c_uint = duration_to_secs(duration)?;
+ setsockopt(fd, c::IPPROTO_TCP, c::TCP_KEEPIDLE, secs)
+}
+
+#[inline]
+pub(crate) fn tcp_keepidle(fd: BorrowedFd<'_>) -> io::Result<Duration> {
+ let secs: c::c_uint = getsockopt(fd, c::IPPROTO_TCP, c::TCP_KEEPIDLE)?;
+ Ok(Duration::from_secs(secs.into()))
+}
+
+#[inline]
+pub(crate) fn set_tcp_keepintvl(fd: BorrowedFd<'_>, duration: Duration) -> io::Result<()> {
+ let secs: c::c_uint = duration_to_secs(duration)?;
+ setsockopt(fd, c::IPPROTO_TCP, c::TCP_KEEPINTVL, secs)
+}
+
+#[inline]
+pub(crate) fn tcp_keepintvl(fd: BorrowedFd<'_>) -> io::Result<Duration> {
+ let secs: c::c_uint = getsockopt(fd, c::IPPROTO_TCP, c::TCP_KEEPINTVL)?;
+ Ok(Duration::from_secs(secs.into()))
+}
+
+#[inline]
+pub(crate) fn set_tcp_user_timeout(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> {
+ setsockopt(fd, c::IPPROTO_TCP, c::TCP_USER_TIMEOUT, value)
+}
+
+#[inline]
+pub(crate) fn tcp_user_timeout(fd: BorrowedFd<'_>) -> io::Result<u32> {
+ getsockopt(fd, c::IPPROTO_TCP, c::TCP_USER_TIMEOUT)
+}
+
+#[inline]
+pub(crate) fn set_tcp_quickack(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
+ setsockopt(fd, c::IPPROTO_TCP, c::TCP_QUICKACK, from_bool(value))
+}
+
+#[inline]
+pub(crate) fn tcp_quickack(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::IPPROTO_TCP, c::TCP_QUICKACK).map(to_bool)
+}
+
+#[inline]
+pub(crate) fn set_tcp_congestion(fd: BorrowedFd<'_>, value: &str) -> io::Result<()> {
+ let level = c::IPPROTO_TCP;
+ let optname = c::TCP_CONGESTION;
+ let optlen = value.len().try_into().unwrap();
+ setsockopt_raw(fd, level, optname, value.as_ptr(), optlen)
+}
+
+#[cfg(feature = "alloc")]
+#[inline]
+pub(crate) fn tcp_congestion(fd: BorrowedFd<'_>) -> io::Result<String> {
+ const OPTLEN: c::socklen_t = 16;
+
+ let level = c::IPPROTO_TCP;
+ let optname = c::TCP_CONGESTION;
+ let mut value = MaybeUninit::<[MaybeUninit<u8>; OPTLEN as usize]>::uninit();
+ let mut optlen = OPTLEN;
+ getsockopt_raw(fd, level, optname, &mut value, &mut optlen)?;
+ unsafe {
+ let value = value.assume_init();
+ let slice: &[u8] = core::mem::transmute(&value[..optlen as usize]);
+ assert!(slice.contains(&b'\0'));
+ Ok(
+ core::str::from_utf8(CStr::from_ptr(slice.as_ptr().cast()).to_bytes())
+ .unwrap()
+ .to_owned(),
+ )
+ }
+}
+
+#[inline]
+pub(crate) fn set_tcp_thin_linear_timeouts(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
+ setsockopt(
+ fd,
+ c::IPPROTO_TCP,
+ c::TCP_THIN_LINEAR_TIMEOUTS,
+ from_bool(value),
+ )
+}
+
+#[inline]
+pub(crate) fn tcp_thin_linear_timeouts(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::IPPROTO_TCP, c::TCP_THIN_LINEAR_TIMEOUTS).map(to_bool)
+}
+
+#[inline]
+pub(crate) fn set_tcp_cork(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
+ setsockopt(fd, c::IPPROTO_TCP, c::TCP_CORK, from_bool(value))
+}
+
+#[inline]
+pub(crate) fn tcp_cork(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::IPPROTO_TCP, c::TCP_CORK).map(to_bool)
+}
+
+#[inline]
+pub(crate) fn socket_peercred(fd: BorrowedFd<'_>) -> io::Result<UCred> {
+ getsockopt(fd, c::SOL_SOCKET, linux_raw_sys::net::SO_PEERCRED)
+}
+
+#[cfg(target_os = "linux")]
+#[inline]
+pub(crate) fn set_xdp_umem_reg(fd: BorrowedFd<'_>, value: XdpUmemReg) -> io::Result<()> {
+ setsockopt(fd, c::SOL_XDP, c::XDP_UMEM_REG, value)
+}
+
+#[cfg(target_os = "linux")]
+#[inline]
+pub(crate) fn set_xdp_umem_fill_ring_size(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> {
+ setsockopt(fd, c::SOL_XDP, c::XDP_UMEM_FILL_RING, value)
+}
+
+#[cfg(target_os = "linux")]
+#[inline]
+pub(crate) fn set_xdp_umem_completion_ring_size(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> {
+ setsockopt(fd, c::SOL_XDP, c::XDP_UMEM_COMPLETION_RING, value)
+}
+
+#[cfg(target_os = "linux")]
+#[inline]
+pub(crate) fn set_xdp_tx_ring_size(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> {
+ setsockopt(fd, c::SOL_XDP, c::XDP_TX_RING, value)
+}
+
+#[cfg(target_os = "linux")]
+#[inline]
+pub(crate) fn set_xdp_rx_ring_size(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> {
+ setsockopt(fd, c::SOL_XDP, c::XDP_RX_RING, value)
+}
+
+#[cfg(target_os = "linux")]
+#[inline]
+pub(crate) fn xdp_mmap_offsets(fd: BorrowedFd<'_>) -> io::Result<XdpMmapOffsets> {
+ // The kernel will write `xdp_mmap_offsets` or `xdp_mmap_offsets_v1` to the
+ // supplied pointer, depending on the kernel version. Both structs only
+ // contain u64 values. By using the larger of both as the parameter, we can
+ // shuffle the values to the non-v1 version returned by
+ // `get_xdp_mmap_offsets` while keeping the return type unaffected by the
+ // kernel version. This works because C will layout all struct members one
+ // after the other.
+
+ let mut optlen = size_of::<xdp_mmap_offsets>().try_into().unwrap();
+ debug_assert!(
+ optlen as usize >= size_of::<c::c_int>(),
+ "Socket APIs don't ever use `bool` directly"
+ );
+ let mut value = MaybeUninit::<xdp_mmap_offsets>::zeroed();
+ getsockopt_raw(fd, c::SOL_XDP, c::XDP_MMAP_OFFSETS, &mut value, &mut optlen)?;
+
+ if optlen as usize == size_of::<c::xdp_mmap_offsets_v1>() {
+ // SAFETY: All members of xdp_mmap_offsets are `u64` and thus are
+ // correctly initialized by `MaybeUninit::<xdp_statistics>::zeroed()`.
+ let xpd_mmap_offsets = unsafe { value.assume_init() };
+ Ok(XdpMmapOffsets {
+ rx: XdpRingOffset {
+ producer: xpd_mmap_offsets.rx.producer,
+ consumer: xpd_mmap_offsets.rx.consumer,
+ desc: xpd_mmap_offsets.rx.desc,
+ flags: None,
+ },
+ tx: XdpRingOffset {
+ producer: xpd_mmap_offsets.rx.flags,
+ consumer: xpd_mmap_offsets.tx.producer,
+ desc: xpd_mmap_offsets.tx.consumer,
+ flags: None,
+ },
+ fr: XdpRingOffset {
+ producer: xpd_mmap_offsets.tx.desc,
+ consumer: xpd_mmap_offsets.tx.flags,
+ desc: xpd_mmap_offsets.fr.producer,
+ flags: None,
+ },
+ cr: XdpRingOffset {
+ producer: xpd_mmap_offsets.fr.consumer,
+ consumer: xpd_mmap_offsets.fr.desc,
+ desc: xpd_mmap_offsets.fr.flags,
+ flags: None,
+ },
+ })
+ } else {
+ assert_eq!(
+ optlen as usize,
+ size_of::<xdp_mmap_offsets>(),
+ "unexpected getsockopt size"
+ );
+ // SAFETY: All members of xdp_mmap_offsets are `u64` and thus are
+ // correctly initialized by `MaybeUninit::<xdp_statistics>::zeroed()`.
+ let xpd_mmap_offsets = unsafe { value.assume_init() };
+ Ok(XdpMmapOffsets {
+ rx: XdpRingOffset {
+ producer: xpd_mmap_offsets.rx.producer,
+ consumer: xpd_mmap_offsets.rx.consumer,
+ desc: xpd_mmap_offsets.rx.desc,
+ flags: Some(xpd_mmap_offsets.rx.flags),
+ },
+ tx: XdpRingOffset {
+ producer: xpd_mmap_offsets.tx.producer,
+ consumer: xpd_mmap_offsets.tx.consumer,
+ desc: xpd_mmap_offsets.tx.desc,
+ flags: Some(xpd_mmap_offsets.tx.flags),
+ },
+ fr: XdpRingOffset {
+ producer: xpd_mmap_offsets.fr.producer,
+ consumer: xpd_mmap_offsets.fr.consumer,
+ desc: xpd_mmap_offsets.fr.desc,
+ flags: Some(xpd_mmap_offsets.fr.flags),
+ },
+ cr: XdpRingOffset {
+ producer: xpd_mmap_offsets.cr.producer,
+ consumer: xpd_mmap_offsets.cr.consumer,
+ desc: xpd_mmap_offsets.cr.desc,
+ flags: Some(xpd_mmap_offsets.cr.flags),
+ },
+ })
+ }
+}
+
+#[cfg(target_os = "linux")]
+#[inline]
+pub(crate) fn xdp_statistics(fd: BorrowedFd<'_>) -> io::Result<XdpStatistics> {
+ let mut optlen = size_of::<xdp_statistics>().try_into().unwrap();
+ debug_assert!(
+ optlen as usize >= size_of::<c::c_int>(),
+ "Socket APIs don't ever use `bool` directly"
+ );
+ let mut value = MaybeUninit::<xdp_statistics>::zeroed();
+ getsockopt_raw(fd, c::SOL_XDP, c::XDP_STATISTICS, &mut value, &mut optlen)?;
+
+ if optlen as usize == size_of::<xdp_statistics_v1>() {
+ // SAFETY: All members of xdp_statistics are `u64` and thus are
+ // correctly initialized by `MaybeUninit::<xdp_statistics>::zeroed()`.
+ let xdp_statistics = unsafe { value.assume_init() };
+ Ok(XdpStatistics {
+ rx_dropped: xdp_statistics.rx_dropped,
+ rx_invalid_descs: xdp_statistics.rx_dropped,
+ tx_invalid_descs: xdp_statistics.rx_dropped,
+ rx_ring_full: None,
+ rx_fill_ring_empty_descs: None,
+ tx_ring_empty_descs: None,
+ })
+ } else {
+ assert_eq!(
+ optlen as usize,
+ size_of::<xdp_statistics>(),
+ "unexpected getsockopt size"
+ );
+ // SAFETY: All members of xdp_statistics are `u64` and thus are
+ // correctly initialized by `MaybeUninit::<xdp_statistics>::zeroed()`.
+ let xdp_statistics = unsafe { value.assume_init() };
+ Ok(XdpStatistics {
+ rx_dropped: xdp_statistics.rx_dropped,
+ rx_invalid_descs: xdp_statistics.rx_invalid_descs,
+ tx_invalid_descs: xdp_statistics.tx_invalid_descs,
+ rx_ring_full: Some(xdp_statistics.rx_ring_full),
+ rx_fill_ring_empty_descs: Some(xdp_statistics.rx_fill_ring_empty_descs),
+ tx_ring_empty_descs: Some(xdp_statistics.tx_ring_empty_descs),
+ })
+ }
+}
+
+#[cfg(target_os = "linux")]
+#[inline]
+pub(crate) fn xdp_options(fd: BorrowedFd<'_>) -> io::Result<XdpOptionsFlags> {
+ getsockopt(fd, c::SOL_XDP, c::XDP_OPTIONS)
+}
+
+#[inline]
+fn from_in_addr(in_addr: c::in_addr) -> Ipv4Addr {
+ Ipv4Addr::from(in_addr.s_addr.to_ne_bytes())
+}
+
+#[inline]
+fn to_ip_mreq(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_ip_mreqn(multiaddr: &Ipv4Addr, address: &Ipv4Addr, ifindex: i32) -> c::ip_mreqn {
+ c::ip_mreqn {
+ imr_multiaddr: to_imr_addr(multiaddr),
+ imr_address: to_imr_addr(address),
+ imr_ifindex: ifindex,
+ }
+}
+
+#[inline]
+fn to_imr_source(
+ multiaddr: &Ipv4Addr,
+ interface: &Ipv4Addr,
+ sourceaddr: &Ipv4Addr,
+) -> c::ip_mreq_source {
+ c::ip_mreq_source {
+ imr_multiaddr: to_imr_addr(multiaddr).s_addr,
+ imr_interface: to_imr_addr(interface).s_addr,
+ imr_sourceaddr: to_imr_addr(sourceaddr).s_addr,
+ }
+}
+
+#[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::net::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
+}
+
+/// Convert to seconds, rounding up if necessary.
+#[inline]
+fn duration_to_secs<T: TryFrom<u64>>(duration: Duration) -> io::Result<T> {
+ let mut secs = duration.as_secs();
+ if duration.subsec_nanos() != 0 {
+ secs = secs.checked_add(1).ok_or(io::Errno::INVAL)?;
+ }
+ T::try_from(secs).map_err(|_e| io::Errno::INVAL)
+}
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 00000000..488e08f0
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/net/syscalls.rs
@@ -0,0 +1,731 @@
+//! linux_raw syscalls supporting `rustix::net`.
+//!
+//! # Safety
+//!
+//! See the `rustix::backend` module documentation for details.
+#![allow(unsafe_code, clippy::undocumented_unsafe_blocks)]
+
+use super::msghdr::{noaddr_msghdr, with_msghdr, with_recv_msghdr};
+use super::read_sockaddr::initialize_family_to_unspec;
+use super::send_recv::{RecvFlags, ReturnFlags, SendFlags};
+use crate::backend::c;
+#[cfg(target_os = "linux")]
+use crate::backend::conv::slice_mut;
+use crate::backend::conv::{
+ by_mut, by_ref, c_int, c_uint, pass_usize, ret, ret_owned_fd, ret_usize, size_of, slice,
+ socklen_t, zero,
+};
+use crate::backend::reg::raw_arg;
+use crate::fd::{BorrowedFd, OwnedFd};
+use crate::io::{self, IoSlice, IoSliceMut};
+use crate::net::addr::SocketAddrArg;
+#[cfg(target_os = "linux")]
+use crate::net::MMsgHdr;
+use crate::net::{
+ AddressFamily, Protocol, RecvAncillaryBuffer, RecvMsg, SendAncillaryBuffer, Shutdown,
+ SocketAddrAny, SocketAddrBuf, SocketFlags, SocketType,
+};
+use core::mem::MaybeUninit;
+#[cfg(target_arch = "x86")]
+use {
+ crate::backend::conv::{slice_just_addr, x86_sys},
+ crate::backend::reg::{ArgReg, SocketArg},
+ linux_raw_sys::net::{
+ SYS_ACCEPT, SYS_ACCEPT4, SYS_BIND, SYS_CONNECT, SYS_GETPEERNAME, SYS_GETSOCKNAME,
+ SYS_LISTEN, SYS_RECV, SYS_RECVFROM, SYS_RECVMSG, SYS_SEND, SYS_SENDMMSG, SYS_SENDMSG,
+ SYS_SENDTO, SYS_SHUTDOWN, SYS_SOCKET, SYS_SOCKETPAIR,
+ },
+};
+
+#[inline]
+pub(crate) fn socket(
+ family: AddressFamily,
+ type_: SocketType,
+ protocol: Option<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: Option<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: Option<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(any(target_arch = "x86", target_arch = "s390x")))]
+ 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)
+ }
+ #[cfg(target_arch = "s390x")]
+ {
+ // accept is not available on s390x
+ accept_with(fd, SocketFlags::empty())
+ }
+}
+
+#[inline]
+pub(crate) fn accept_with(fd: BorrowedFd<'_>, flags: SocketFlags) -> 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(any(target_arch = "x86", target_arch = "s390x")))]
+ unsafe {
+ let mut addr = SocketAddrBuf::new();
+ let fd = ret_owned_fd(syscall!(
+ __NR_accept,
+ fd,
+ &mut addr.storage,
+ by_mut(&mut addr.len)
+ ))?;
+ Ok((fd, addr.into_any_option()))
+ }
+ #[cfg(target_arch = "x86")]
+ unsafe {
+ let mut addr = SocketAddrBuf::new();
+ let fd = ret_owned_fd(syscall!(
+ __NR_socketcall,
+ x86_sys(SYS_ACCEPT),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
+ fd.into(),
+ (&mut addr.storage).into(),
+ by_mut(&mut addr.len),
+ ])
+ ))?;
+ Ok((fd, addr.into_any_option()))
+ }
+ #[cfg(target_arch = "s390x")]
+ {
+ // accept is not available on s390x
+ acceptfrom_with(fd, SocketFlags::empty())
+ }
+}
+
+#[inline]
+pub(crate) fn acceptfrom_with(
+ fd: BorrowedFd<'_>,
+ flags: SocketFlags,
+) -> io::Result<(OwnedFd, Option<SocketAddrAny>)> {
+ #[cfg(not(target_arch = "x86"))]
+ unsafe {
+ let mut addr = SocketAddrBuf::new();
+ let fd = ret_owned_fd(syscall!(
+ __NR_accept4,
+ fd,
+ &mut addr.storage,
+ by_mut(&mut addr.len),
+ flags
+ ))?;
+ Ok((fd, addr.into_any_option()))
+ }
+ #[cfg(target_arch = "x86")]
+ unsafe {
+ let mut addr = SocketAddrBuf::new();
+ let fd = ret_owned_fd(syscall!(
+ __NR_socketcall,
+ x86_sys(SYS_ACCEPT4),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
+ fd.into(),
+ (&mut addr.storage).into(),
+ by_mut(&mut addr.len),
+ flags.into(),
+ ])
+ ))?;
+ Ok((fd, addr.into_any_option()))
+ }
+}
+
+#[inline]
+pub(crate) fn recvmsg(
+ sockfd: BorrowedFd<'_>,
+ iov: &mut [IoSliceMut<'_>],
+ control: &mut RecvAncillaryBuffer<'_>,
+ msg_flags: RecvFlags,
+) -> io::Result<RecvMsg> {
+ let mut addr = SocketAddrBuf::new();
+
+ // SAFETY: This passes the `msghdr` reference to the OS which reads the
+ // buffers only within the designated bounds.
+ let (bytes, flags) = unsafe {
+ with_recv_msghdr(&mut addr, iov, control, |msghdr| {
+ #[cfg(not(target_arch = "x86"))]
+ let result = ret_usize(syscall!(__NR_recvmsg, sockfd, by_mut(msghdr), msg_flags));
+
+ #[cfg(target_arch = "x86")]
+ let result = ret_usize(syscall!(
+ __NR_socketcall,
+ x86_sys(SYS_RECVMSG),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
+ sockfd.into(),
+ by_mut(msghdr),
+ msg_flags.into(),
+ ])
+ ));
+
+ result.map(|bytes| (bytes, msghdr.msg_flags))
+ })?
+ };
+
+ // Get the address of the sender, if any.
+ Ok(RecvMsg {
+ bytes,
+ address: unsafe { addr.into_any_option() },
+ flags: ReturnFlags::from_bits_retain(flags),
+ })
+}
+
+#[inline]
+pub(crate) fn sendmsg(
+ sockfd: BorrowedFd<'_>,
+ iov: &[IoSlice<'_>],
+ control: &mut SendAncillaryBuffer<'_, '_, '_>,
+ msg_flags: SendFlags,
+) -> io::Result<usize> {
+ let msghdr = noaddr_msghdr(iov, control);
+
+ #[cfg(not(target_arch = "x86"))]
+ let result = unsafe { ret_usize(syscall!(__NR_sendmsg, sockfd, by_ref(&msghdr), msg_flags)) };
+
+ #[cfg(target_arch = "x86")]
+ let result = unsafe {
+ ret_usize(syscall!(
+ __NR_socketcall,
+ x86_sys(SYS_SENDMSG),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
+ sockfd.into(),
+ by_ref(&msghdr),
+ msg_flags.into()
+ ])
+ ))
+ };
+
+ result
+}
+
+#[inline]
+pub(crate) fn sendmsg_addr(
+ sockfd: BorrowedFd<'_>,
+ addr: &impl SocketAddrArg,
+ iov: &[IoSlice<'_>],
+ control: &mut SendAncillaryBuffer<'_, '_, '_>,
+ msg_flags: SendFlags,
+) -> io::Result<usize> {
+ // SAFETY: This passes the `msghdr` reference to the OS which reads the
+ // buffers only within the designated bounds.
+ unsafe {
+ with_msghdr(addr, iov, control, |msghdr| {
+ #[cfg(not(target_arch = "x86"))]
+ let result = ret_usize(syscall!(__NR_sendmsg, sockfd, by_ref(msghdr), msg_flags));
+
+ #[cfg(target_arch = "x86")]
+ let result = ret_usize(syscall!(
+ __NR_socketcall,
+ x86_sys(SYS_SENDMSG),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
+ sockfd.into(),
+ by_ref(msghdr),
+ msg_flags.into(),
+ ])
+ ));
+
+ result
+ })
+ }
+}
+
+#[cfg(target_os = "linux")]
+#[inline]
+pub(crate) fn sendmmsg(
+ sockfd: BorrowedFd<'_>,
+ msgs: &mut [MMsgHdr<'_>],
+ flags: SendFlags,
+) -> io::Result<usize> {
+ let (msgs, len) = slice_mut(msgs);
+
+ #[cfg(not(target_arch = "x86"))]
+ let result = unsafe { ret_usize(syscall!(__NR_sendmmsg, sockfd, msgs, len, flags)) };
+
+ #[cfg(target_arch = "x86")]
+ let result = unsafe {
+ ret_usize(syscall!(
+ __NR_socketcall,
+ x86_sys(SYS_SENDMMSG),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[sockfd.into(), msgs, len, flags.into()])
+ ))
+ };
+
+ result
+}
+
+#[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 = "mips64r6",
+ target_arch = "riscv64",
+ target_arch = "s390x",
+ 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 = "mips64r6",
+ target_arch = "riscv64",
+ target_arch = "s390x",
+ 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(
+ fd: BorrowedFd<'_>,
+ buf: &[u8],
+ flags: SendFlags,
+ addr: &impl SocketAddrArg,
+) -> io::Result<usize> {
+ let (buf_addr, buf_len) = slice(buf);
+
+ // SAFETY: This passes the `addr_ptr` reference to the OS which reads the
+ // buffers only within the `addr_len` bound.
+ unsafe {
+ addr.with_sockaddr(|addr_ptr, addr_len| {
+ #[cfg(not(target_arch = "x86"))]
+ {
+ ret_usize(syscall_readonly!(
+ __NR_sendto,
+ fd,
+ buf_addr,
+ buf_len,
+ flags,
+ raw_arg(addr_ptr as *mut _),
+ socklen_t(addr_len)
+ ))
+ }
+ #[cfg(target_arch = "x86")]
+ {
+ ret_usize(syscall_readonly!(
+ __NR_socketcall,
+ x86_sys(SYS_SENDTO),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
+ fd.into(),
+ buf_addr,
+ buf_len,
+ flags.into(),
+ raw_arg(addr_ptr as *mut _),
+ socklen_t(addr_len)
+ ])
+ ))
+ }
+ })
+ }
+}
+
+#[inline]
+pub(crate) unsafe fn recv(
+ fd: BorrowedFd<'_>,
+ buf: (*mut u8, usize),
+ flags: RecvFlags,
+) -> io::Result<usize> {
+ #[cfg(not(any(
+ target_arch = "aarch64",
+ target_arch = "mips64",
+ target_arch = "mips64r6",
+ target_arch = "riscv64",
+ target_arch = "s390x",
+ target_arch = "x86",
+ target_arch = "x86_64",
+ )))]
+ {
+ ret_usize(syscall!(__NR_recv, fd, buf.0, pass_usize(buf.1), flags))
+ }
+ #[cfg(any(
+ target_arch = "aarch64",
+ target_arch = "mips64",
+ target_arch = "mips64r6",
+ target_arch = "riscv64",
+ target_arch = "s390x",
+ target_arch = "x86_64",
+ ))]
+ {
+ ret_usize(syscall!(
+ __NR_recvfrom,
+ fd,
+ buf.0,
+ pass_usize(buf.1),
+ flags,
+ zero(),
+ zero()
+ ))
+ }
+ #[cfg(target_arch = "x86")]
+ {
+ ret_usize(syscall!(
+ __NR_socketcall,
+ x86_sys(SYS_RECV),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
+ fd.into(),
+ buf.0.into(),
+ pass_usize(buf.1),
+ flags.into(),
+ ])
+ ))
+ }
+}
+
+#[inline]
+pub(crate) unsafe fn recvfrom(
+ fd: BorrowedFd<'_>,
+ buf: (*mut u8, usize),
+ flags: RecvFlags,
+) -> io::Result<(usize, Option<SocketAddrAny>)> {
+ let mut addr = SocketAddrBuf::new();
+
+ // `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(addr.storage.as_mut_ptr().cast::<c::sockaddr>());
+
+ #[cfg(not(target_arch = "x86"))]
+ let nread = ret_usize(syscall!(
+ __NR_recvfrom,
+ fd,
+ buf.0,
+ pass_usize(buf.1),
+ flags,
+ &mut addr.storage,
+ by_mut(&mut addr.len)
+ ))?;
+ #[cfg(target_arch = "x86")]
+ let nread = ret_usize(syscall!(
+ __NR_socketcall,
+ x86_sys(SYS_RECVFROM),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
+ fd.into(),
+ buf.0.into(),
+ pass_usize(buf.1),
+ flags.into(),
+ (&mut addr.storage).into(),
+ by_mut(&mut addr.len),
+ ])
+ ))?;
+
+ Ok((nread, addr.into_any_option()))
+}
+
+#[inline]
+pub(crate) fn getpeername(fd: BorrowedFd<'_>) -> io::Result<Option<SocketAddrAny>> {
+ #[cfg(not(target_arch = "x86"))]
+ unsafe {
+ let mut addr = SocketAddrBuf::new();
+ ret(syscall!(
+ __NR_getpeername,
+ fd,
+ &mut addr.storage,
+ by_mut(&mut addr.len)
+ ))?;
+ Ok(addr.into_any_option())
+ }
+ #[cfg(target_arch = "x86")]
+ unsafe {
+ let mut addr = SocketAddrBuf::new();
+ ret(syscall!(
+ __NR_socketcall,
+ x86_sys(SYS_GETPEERNAME),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
+ fd.into(),
+ (&mut addr.storage).into(),
+ by_mut(&mut addr.len),
+ ])
+ ))?;
+ Ok(addr.into_any_option())
+ }
+}
+
+#[inline]
+pub(crate) fn getsockname(fd: BorrowedFd<'_>) -> io::Result<SocketAddrAny> {
+ #[cfg(not(target_arch = "x86"))]
+ unsafe {
+ let mut addr = SocketAddrBuf::new();
+ ret(syscall!(
+ __NR_getsockname,
+ fd,
+ &mut addr.storage,
+ by_mut(&mut addr.len)
+ ))?;
+ Ok(addr.into_any())
+ }
+ #[cfg(target_arch = "x86")]
+ unsafe {
+ let mut addr = SocketAddrBuf::new();
+ ret(syscall!(
+ __NR_socketcall,
+ x86_sys(SYS_GETSOCKNAME),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
+ fd.into(),
+ (&mut addr.storage).into(),
+ by_mut(&mut addr.len),
+ ])
+ ))?;
+ Ok(addr.into_any())
+ }
+}
+
+#[inline]
+pub(crate) fn bind(fd: BorrowedFd<'_>, addr: &impl SocketAddrArg) -> io::Result<()> {
+ // SAFETY: This passes the `addr_ptr` reference to the OS which reads the
+ // buffers only within the `addr_len` bound.
+ unsafe {
+ addr.with_sockaddr(|addr_ptr, addr_len| {
+ #[cfg(not(target_arch = "x86"))]
+ {
+ ret(syscall_readonly!(
+ __NR_bind,
+ fd,
+ raw_arg(addr_ptr as *mut _),
+ socklen_t(addr_len)
+ ))
+ }
+ #[cfg(target_arch = "x86")]
+ {
+ ret(syscall_readonly!(
+ __NR_socketcall,
+ x86_sys(SYS_BIND),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
+ fd.into(),
+ raw_arg(addr_ptr as *mut _),
+ socklen_t(addr_len)
+ ])
+ ))
+ }
+ })
+ }
+}
+
+#[inline]
+pub(crate) fn connect(fd: BorrowedFd<'_>, addr: &impl SocketAddrArg) -> io::Result<()> {
+ // SAFETY: This passes the `addr_ptr` reference to the OS which reads the
+ // buffers only within the `addr_len` bound.
+ unsafe {
+ addr.with_sockaddr(|addr_ptr, addr_len| {
+ #[cfg(not(target_arch = "x86"))]
+ {
+ ret(syscall_readonly!(
+ __NR_connect,
+ fd,
+ raw_arg(addr_ptr as *mut _),
+ socklen_t(addr_len)
+ ))
+ }
+ #[cfg(target_arch = "x86")]
+ {
+ ret(syscall_readonly!(
+ __NR_socketcall,
+ x86_sys(SYS_CONNECT),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
+ fd.into(),
+ raw_arg(addr_ptr as *mut _),
+ socklen_t(addr_len)
+ ])
+ ))
+ }
+ })
+ }
+}
+
+#[inline]
+pub(crate) fn connect_unspec(fd: BorrowedFd<'_>) -> io::Result<()> {
+ debug_assert_eq!(c::AF_UNSPEC, 0);
+ let addr = MaybeUninit::<c::sockaddr_storage>::zeroed();
+
+ #[cfg(not(target_arch = "x86"))]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_connect,
+ fd,
+ by_ref(&addr),
+ size_of::<c::sockaddr_storage, _>()
+ ))
+ }
+ #[cfg(target_arch = "x86")]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_socketcall,
+ x86_sys(SYS_CONNECT),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
+ fd.into(),
+ by_ref(&addr),
+ size_of::<c::sockaddr_storage, _>(),
+ ])
+ ))
+ }
+}
+
+#[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)])
+ ))
+ }
+}
diff --git a/vendor/rustix/src/backend/linux_raw/net/write_sockaddr.rs b/vendor/rustix/src/backend/linux_raw/net/write_sockaddr.rs
new file mode 100644
index 00000000..3b348221
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/net/write_sockaddr.rs
@@ -0,0 +1,31 @@
+//! The BSD sockets API requires us to read the `sa_family` field before we can
+//! interpret the rest of a `sockaddr` produced by the kernel.
+#![allow(unsafe_code)]
+
+use crate::backend::c;
+use crate::net::{SocketAddrV4, SocketAddrV6};
+
+pub(crate) fn encode_sockaddr_v4(v4: &SocketAddrV4) -> c::sockaddr_in {
+ c::sockaddr_in {
+ sin_family: c::AF_INET as _,
+ sin_port: u16::to_be(v4.port()),
+ sin_addr: c::in_addr {
+ s_addr: u32::from_ne_bytes(v4.ip().octets()),
+ },
+ __pad: [0_u8; 8],
+ }
+}
+
+pub(crate) fn encode_sockaddr_v6(v6: &SocketAddrV6) -> c::sockaddr_in6 {
+ c::sockaddr_in6 {
+ sin6_family: c::AF_INET6 as _,
+ sin6_port: u16::to_be(v6.port()),
+ sin6_flowinfo: u32::to_be(v6.flowinfo()),
+ sin6_addr: c::in6_addr {
+ in6_u: linux_raw_sys::net::in6_addr__bindgen_ty_1 {
+ u6_addr8: v6.ip().octets(),
+ },
+ },
+ sin6_scope_id: v6.scope_id(),
+ }
+}
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 00000000..d748219a
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/param/auxv.rs
@@ -0,0 +1,583 @@
+//! Linux auxv support.
+//!
+//! # Safety
+//!
+//! This uses raw pointers to locate and read the kernel-provided auxv array.
+#![allow(unsafe_code)]
+
+use super::super::conv::{c_int, pass_usize, ret_usize};
+use crate::backend::c;
+use crate::fd::OwnedFd;
+#[cfg(feature = "param")]
+use crate::ffi::CStr;
+use crate::fs::{Mode, OFlags};
+use crate::utils::{as_ptr, check_raw_pointer};
+#[cfg(feature = "alloc")]
+use alloc::vec::Vec;
+use core::mem::size_of;
+use core::ptr::{null_mut, read_unaligned, NonNull};
+#[cfg(feature = "runtime")]
+use core::sync::atomic::AtomicU8;
+use core::sync::atomic::Ordering::Relaxed;
+use core::sync::atomic::{AtomicPtr, AtomicUsize};
+use linux_raw_sys::elf::*;
+use linux_raw_sys::general::{
+ AT_BASE, AT_CLKTCK, AT_EXECFN, AT_HWCAP, AT_HWCAP2, AT_MINSIGSTKSZ, AT_NULL, AT_PAGESZ,
+ AT_SYSINFO_EHDR,
+};
+#[cfg(feature = "runtime")]
+use linux_raw_sys::general::{
+ AT_EGID, AT_ENTRY, AT_EUID, AT_GID, AT_PHDR, AT_PHENT, AT_PHNUM, AT_RANDOM, AT_SECURE, AT_UID,
+};
+#[cfg(feature = "alloc")]
+use {alloc::borrow::Cow, alloc::vec};
+
+#[cfg(feature = "param")]
+#[inline]
+pub(crate) fn page_size() -> usize {
+ let mut page_size = PAGE_SIZE.load(Relaxed);
+
+ if page_size == 0 {
+ init_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_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_auxv();
+ hwcap = HWCAP.load(Relaxed);
+ hwcap2 = HWCAP2.load(Relaxed);
+ }
+
+ (hwcap, hwcap2)
+}
+
+#[cfg(feature = "param")]
+#[inline]
+pub(crate) fn linux_minsigstksz() -> usize {
+ let mut minsigstksz = MINSIGSTKSZ.load(Relaxed);
+
+ if minsigstksz == 0 {
+ init_auxv();
+ minsigstksz = MINSIGSTKSZ.load(Relaxed);
+ }
+
+ minsigstksz
+}
+
+#[cfg(feature = "param")]
+#[inline]
+pub(crate) fn linux_execfn() -> &'static CStr {
+ let mut execfn = EXECFN.load(Relaxed);
+
+ if execfn.is_null() {
+ init_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 linux_secure() -> bool {
+ let mut secure = SECURE.load(Relaxed);
+
+ // 0 means not initialized yet.
+ if secure == 0 {
+ init_auxv();
+ secure = SECURE.load(Relaxed);
+ }
+
+ // 0 means not present. Libc `getauxval(AT_SECURE)` would return 0.
+ // 1 means not in secure mode.
+ // 2 means in secure mode.
+ secure > 1
+}
+
+#[cfg(feature = "runtime")]
+#[inline]
+pub(crate) fn exe_phdrs() -> (*const c::c_void, usize, usize) {
+ let mut phdr = PHDR.load(Relaxed);
+ let mut phent = PHENT.load(Relaxed);
+ let mut phnum = PHNUM.load(Relaxed);
+
+ if phdr.is_null() || phnum == 0 {
+ init_auxv();
+ phdr = PHDR.load(Relaxed);
+ phent = PHENT.load(Relaxed);
+ phnum = PHNUM.load(Relaxed);
+ }
+
+ (phdr.cast(), phent, 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.
+///
+/// And, this function returns a null pointer, rather than panicking, if the
+/// auxv records can't be read.
+#[inline]
+pub(in super::super) fn sysinfo_ehdr() -> *const Elf_Ehdr {
+ let mut ehdr = SYSINFO_EHDR.load(Relaxed);
+
+ if ehdr.is_null() {
+ // Use `maybe_init_auxv` to read the aux vectors if it can, but do
+ // nothing if it can't. If it can't, then we'll get a null pointer
+ // here, which our callers are prepared to deal with.
+ maybe_init_auxv();
+
+ ehdr = SYSINFO_EHDR.load(Relaxed);
+ }
+
+ ehdr
+}
+
+#[cfg(feature = "runtime")]
+#[inline]
+pub(crate) fn entry() -> usize {
+ let mut entry = ENTRY.load(Relaxed);
+
+ if entry == 0 {
+ init_auxv();
+ entry = ENTRY.load(Relaxed);
+ }
+
+ entry
+}
+
+#[cfg(feature = "runtime")]
+#[inline]
+pub(crate) fn random() -> *const [u8; 16] {
+ let mut random = RANDOM.load(Relaxed);
+
+ if random.is_null() {
+ init_auxv();
+ random = RANDOM.load(Relaxed);
+ }
+
+ random
+}
+
+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 MINSIGSTKSZ: AtomicUsize = AtomicUsize::new(0);
+static EXECFN: AtomicPtr<c::c_char> = AtomicPtr::new(null_mut());
+static SYSINFO_EHDR: AtomicPtr<Elf_Ehdr> = AtomicPtr::new(null_mut());
+#[cfg(feature = "runtime")]
+static SECURE: AtomicU8 = AtomicU8::new(0);
+#[cfg(feature = "runtime")]
+static PHDR: AtomicPtr<Elf_Phdr> = AtomicPtr::new(null_mut());
+#[cfg(feature = "runtime")]
+static PHENT: AtomicUsize = AtomicUsize::new(0);
+#[cfg(feature = "runtime")]
+static PHNUM: AtomicUsize = AtomicUsize::new(0);
+#[cfg(feature = "runtime")]
+static ENTRY: AtomicUsize = AtomicUsize::new(0);
+#[cfg(feature = "runtime")]
+static RANDOM: AtomicPtr<[u8; 16]> = AtomicPtr::new(null_mut());
+
+const PR_GET_AUXV: c::c_int = 0x4155_5856;
+
+/// Use Linux ≥ 6.4's [`PR_GET_AUXV`] to read the aux records, into a provided
+/// statically-sized buffer. Return:
+/// - `Ok(…)` if the buffer is big enough.
+/// - `Err(Ok(len))` if we need a buffer of length `len`.
+/// - `Err(Err(err))` if we failed with `err`.
+///
+/// [`PR_GET_AUXV`]: https://www.man7.org/linux/man-pages/man2/PR_GET_AUXV.2const.html
+#[cold]
+fn pr_get_auxv_static(buffer: &mut [u8; 512]) -> Result<&mut [u8], crate::io::Result<usize>> {
+ let len = unsafe {
+ ret_usize(syscall_always_asm!(
+ __NR_prctl,
+ c_int(PR_GET_AUXV),
+ buffer.as_mut_ptr(),
+ pass_usize(buffer.len()),
+ pass_usize(0),
+ pass_usize(0)
+ ))
+ .map_err(Err)?
+ };
+ if len <= buffer.len() {
+ return Ok(&mut buffer[..len]);
+ }
+ Err(Ok(len))
+}
+
+/// Use Linux ≥ 6.4's [`PR_GET_AUXV`] to read the aux records, using a
+/// provided statically-sized buffer if possible, or a dynamically allocated
+/// buffer otherwise. Return:
+/// - Ok(…) on success.
+/// - Err(err) on failure.
+///
+/// [`PR_GET_AUXV`]: https://www.man7.org/linux/man-pages/man2/PR_GET_AUXV.2const.html
+#[cfg(feature = "alloc")]
+#[cold]
+fn pr_get_auxv_dynamic(buffer: &mut [u8; 512]) -> crate::io::Result<Cow<'_, [u8]>> {
+ // First try use the static buffer.
+ let len = match pr_get_auxv_static(buffer) {
+ Ok(buffer) => return Ok(Cow::Borrowed(buffer)),
+ Err(Ok(len)) => len,
+ Err(Err(err)) => return Err(err),
+ };
+
+ // If that indicates it needs a bigger buffer, allocate one.
+ let mut buffer = vec![0_u8; len];
+ let len = unsafe {
+ ret_usize(syscall_always_asm!(
+ __NR_prctl,
+ c_int(PR_GET_AUXV),
+ buffer.as_mut_ptr(),
+ pass_usize(buffer.len()),
+ pass_usize(0),
+ pass_usize(0)
+ ))?
+ };
+ assert_eq!(len, buffer.len());
+ Ok(Cow::Owned(buffer))
+}
+
+/// Read the auxv records and initialize the various static variables. Panic
+/// if an error is encountered.
+#[cold]
+fn init_auxv() {
+ init_auxv_impl().unwrap();
+}
+
+/// Like `init_auxv`, but don't panic if an error is encountered. The caller
+/// must be prepared for initialization to be skipped.
+#[cold]
+fn maybe_init_auxv() {
+ let _ = init_auxv_impl();
+}
+
+/// If we don't have "use-explicitly-provided-auxv" or "use-libc-auxv", we
+/// read the aux vector via the `prctl` `PR_GET_AUXV`, with a fallback to
+/// /proc/self/auxv for kernels that don't support `PR_GET_AUXV`.
+#[cold]
+fn init_auxv_impl() -> Result<(), ()> {
+ // 512 bytes of AUX elements ought to be enough for anybody…
+ let mut buffer = [0_u8; 512];
+
+ // If we don't have "alloc", just try to read into our statically-sized
+ // buffer. This might fail due to the buffer being insufficient; we're
+ // prepared to cope, though we may do suboptimal things.
+ #[cfg(not(feature = "alloc"))]
+ let result = pr_get_auxv_static(&mut buffer);
+
+ // If we do have "alloc" then read into our statically-sized buffer if
+ // it fits, or fall back to a dynamically-allocated buffer.
+ #[cfg(feature = "alloc")]
+ let result = pr_get_auxv_dynamic(&mut buffer);
+
+ if let Ok(buffer) = result {
+ // SAFETY: We assume the kernel returns a valid auxv.
+ unsafe {
+ init_from_aux_iter(AuxPointer(buffer.as_ptr().cast())).unwrap();
+ }
+ return Ok(());
+ }
+
+ // If `PR_GET_AUXV` is unavailable, or if we don't have "alloc" and
+ // the aux records don't fit in our static buffer, then fall back to trying
+ // to open "/proc/self/auxv". We don't use `proc_self_fd` because its extra
+ // checking breaks on QEMU.
+ if let Ok(file) = crate::fs::open("/proc/self/auxv", OFlags::RDONLY, Mode::empty()) {
+ #[cfg(feature = "alloc")]
+ init_from_auxv_file(file).unwrap();
+
+ #[cfg(not(feature = "alloc"))]
+ unsafe {
+ init_from_aux_iter(AuxFile(file)).unwrap();
+ }
+
+ return Ok(());
+ }
+
+ Err(())
+}
+
+/// Process auxv entries from the open file `auxv`.
+#[cfg(feature = "alloc")]
+#[cold]
+#[must_use]
+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_aux_iter(AuxPointer(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.
+#[cold]
+#[must_use]
+unsafe fn init_from_aux_iter(aux_iter: impl Iterator<Item = Elf_auxv_t>) -> Option<()> {
+ let mut pagesz = 0;
+ let mut clktck = 0;
+ let mut hwcap = 0;
+ let mut hwcap2 = 0;
+ let mut minsigstksz = 0;
+ let mut execfn = null_mut();
+ let mut sysinfo_ehdr = null_mut();
+ #[cfg(feature = "runtime")]
+ let mut secure = 0;
+ #[cfg(feature = "runtime")]
+ let mut phdr = null_mut();
+ #[cfg(feature = "runtime")]
+ let mut phnum = 0;
+ #[cfg(feature = "runtime")]
+ let mut phent = 0;
+ #[cfg(feature = "runtime")]
+ let mut entry = 0;
+ #[cfg(feature = "runtime")]
+ let mut uid = None;
+ #[cfg(feature = "runtime")]
+ let mut euid = None;
+ #[cfg(feature = "runtime")]
+ let mut gid = None;
+ #[cfg(feature = "runtime")]
+ let mut egid = None;
+ #[cfg(feature = "runtime")]
+ let mut random = null_mut();
+
+ for Elf_auxv_t { a_type, a_val } in aux_iter {
+ 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_MINSIGSTKSZ => minsigstksz = a_val as usize,
+ AT_EXECFN => execfn = check_raw_pointer::<c::c_char>(a_val as *mut _)?.as_ptr(),
+ AT_SYSINFO_EHDR => sysinfo_ehdr = check_elf_base(a_val as *mut _)?.as_ptr(),
+
+ AT_BASE => {
+ // The `AT_BASE` value can be null in a static executable that
+ // doesn't use a dynamic linker. If so, ignore it.
+ if !a_val.is_null() {
+ let _ = check_elf_base(a_val.cast())?;
+ }
+ }
+
+ #[cfg(feature = "runtime")]
+ AT_SECURE => secure = (a_val as usize != 0) as u8 + 1,
+ #[cfg(feature = "runtime")]
+ AT_UID => uid = Some(a_val),
+ #[cfg(feature = "runtime")]
+ AT_EUID => euid = Some(a_val),
+ #[cfg(feature = "runtime")]
+ AT_GID => gid = Some(a_val),
+ #[cfg(feature = "runtime")]
+ AT_EGID => egid = Some(a_val),
+ #[cfg(feature = "runtime")]
+ AT_PHDR => phdr = check_raw_pointer::<Elf_Phdr>(a_val as *mut _)?.as_ptr(),
+ #[cfg(feature = "runtime")]
+ AT_PHNUM => phnum = a_val as usize,
+ #[cfg(feature = "runtime")]
+ AT_PHENT => phent = a_val as usize,
+ #[cfg(feature = "runtime")]
+ AT_ENTRY => entry = a_val as usize,
+ #[cfg(feature = "runtime")]
+ AT_RANDOM => random = check_raw_pointer::<[u8; 16]>(a_val as *mut _)?.as_ptr(),
+
+ AT_NULL => break,
+ _ => (),
+ }
+ }
+
+ #[cfg(feature = "runtime")]
+ assert_eq!(phent, size_of::<Elf_Phdr>());
+
+ // If we're running set-uid or set-gid, enable “secure execution” mode,
+ // which doesn't do much, but users may be depending on the things that
+ // it does do.
+ #[cfg(feature = "runtime")]
+ if uid != euid || gid != egid {
+ secure = 2;
+ }
+
+ // 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);
+ MINSIGSTKSZ.store(minsigstksz, Relaxed);
+ EXECFN.store(execfn, Relaxed);
+ SYSINFO_EHDR.store(sysinfo_ehdr, Relaxed);
+ #[cfg(feature = "runtime")]
+ SECURE.store(secure, Relaxed);
+ #[cfg(feature = "runtime")]
+ PHDR.store(phdr, Relaxed);
+ #[cfg(feature = "runtime")]
+ PHNUM.store(phnum, Relaxed);
+ #[cfg(feature = "runtime")]
+ ENTRY.store(entry, Relaxed);
+ #[cfg(feature = "runtime")]
+ RANDOM.store(random, Relaxed);
+
+ 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.
+#[cold]
+#[must_use]
+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 = check_raw_pointer::<Elf_Ehdr>(base as *mut _)?;
+
+ 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 _))
+}
+
+// Aux reading utilities
+
+// Read auxv records from an array in memory.
+struct AuxPointer(*const Elf_auxv_t);
+
+impl Iterator for AuxPointer {
+ type Item = Elf_auxv_t;
+
+ #[cold]
+ fn next(&mut self) -> Option<Self::Item> {
+ unsafe {
+ let value = read_unaligned(self.0);
+ self.0 = self.0.add(1);
+ Some(value)
+ }
+ }
+}
+
+// Read auxv records from a file.
+#[cfg(not(feature = "alloc"))]
+struct AuxFile(OwnedFd);
+
+#[cfg(not(feature = "alloc"))]
+impl Iterator for AuxFile {
+ type Item = Elf_auxv_t;
+
+ // This implementation does lots of `read`s and it isn't amazing, but
+ // hopefully we won't use it often.
+ #[cold]
+ fn next(&mut self) -> Option<Self::Item> {
+ let mut buf = [0_u8; size_of::<Self::Item>()];
+ let mut slice = &mut buf[..];
+ while !slice.is_empty() {
+ match crate::io::read(&self.0, &mut *slice) {
+ Ok(0) => panic!("unexpected end of auxv file"),
+ Ok(n) => slice = &mut slice[n..],
+ Err(crate::io::Errno::INTR) => continue,
+ Err(err) => panic!("{:?}", err),
+ }
+ }
+ Some(unsafe { read_unaligned(buf.as_ptr().cast()) })
+ }
+}
diff --git a/vendor/rustix/src/backend/linux_raw/param/init.rs b/vendor/rustix/src/backend/linux_raw/param/init.rs
new file mode 100644
index 00000000..de1e5949
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/param/init.rs
@@ -0,0 +1,175 @@
+//! Linux auxv `init` function, for "use-explicitly-provided-auxv" mode.
+//!
+//! # Safety
+//!
+//! This uses raw pointers to locate and read the kernel-provided auxv array.
+#![allow(unsafe_code)]
+
+use crate::backend::c;
+#[cfg(feature = "param")]
+use crate::ffi::CStr;
+use core::ffi::c_void;
+use core::ptr::{null_mut, read, NonNull};
+#[cfg(feature = "runtime")]
+use core::sync::atomic::AtomicBool;
+use core::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
+use linux_raw_sys::elf::*;
+use linux_raw_sys::general::{
+ AT_CLKTCK, AT_EXECFN, AT_HWCAP, AT_HWCAP2, AT_MINSIGSTKSZ, AT_NULL, AT_PAGESZ, AT_SYSINFO_EHDR,
+};
+#[cfg(feature = "runtime")]
+use linux_raw_sys::general::{AT_ENTRY, AT_PHDR, AT_PHENT, AT_PHNUM, AT_RANDOM, AT_SECURE};
+
+#[cfg(feature = "param")]
+#[inline]
+pub(crate) fn page_size() -> usize {
+ PAGE_SIZE.load(Ordering::Relaxed)
+}
+
+#[cfg(feature = "param")]
+#[inline]
+pub(crate) fn clock_ticks_per_second() -> u64 {
+ CLOCK_TICKS_PER_SECOND.load(Ordering::Relaxed) as u64
+}
+
+#[cfg(feature = "param")]
+#[inline]
+pub(crate) fn linux_hwcap() -> (usize, usize) {
+ (
+ HWCAP.load(Ordering::Relaxed),
+ HWCAP2.load(Ordering::Relaxed),
+ )
+}
+
+#[cfg(feature = "param")]
+#[inline]
+pub(crate) fn linux_minsigstksz() -> usize {
+ MINSIGSTKSZ.load(Ordering::Relaxed)
+}
+
+#[cfg(feature = "param")]
+#[inline]
+pub(crate) fn linux_execfn() -> &'static CStr {
+ let execfn = EXECFN.load(Ordering::Relaxed);
+
+ // SAFETY: We initialize `EXECFN` to a valid `CStr` pointer, and we assume
+ // the `AT_EXECFN` value provided by the kernel points to a valid C string.
+ unsafe { CStr::from_ptr(execfn.cast()) }
+}
+
+#[cfg(feature = "runtime")]
+#[inline]
+pub(crate) fn linux_secure() -> bool {
+ SECURE.load(Ordering::Relaxed)
+}
+
+#[cfg(feature = "runtime")]
+#[inline]
+pub(crate) fn exe_phdrs() -> (*const c_void, usize, usize) {
+ (
+ PHDR.load(Ordering::Relaxed).cast(),
+ PHENT.load(Ordering::Relaxed),
+ PHNUM.load(Ordering::Relaxed),
+ )
+}
+
+/// `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 {
+ SYSINFO_EHDR.load(Ordering::Relaxed)
+}
+
+#[cfg(feature = "runtime")]
+#[inline]
+pub(crate) fn entry() -> usize {
+ ENTRY.load(Ordering::Relaxed)
+}
+
+#[cfg(feature = "runtime")]
+#[inline]
+pub(crate) fn random() -> *const [u8; 16] {
+ RANDOM.load(Ordering::Relaxed)
+}
+
+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 MINSIGSTKSZ: AtomicUsize = AtomicUsize::new(0);
+static SYSINFO_EHDR: AtomicPtr<Elf_Ehdr> = AtomicPtr::new(null_mut());
+// Initialize `EXECFN` to a valid `CStr` pointer so that we don't need to check
+// for null on every `execfn` call.
+static EXECFN: AtomicPtr<c::c_char> = AtomicPtr::new(b"\0".as_ptr() as _);
+#[cfg(feature = "runtime")]
+static SECURE: AtomicBool = AtomicBool::new(false);
+// Use `dangling` so that we can always treat it like an empty slice.
+#[cfg(feature = "runtime")]
+static PHDR: AtomicPtr<Elf_Phdr> = AtomicPtr::new(NonNull::dangling().as_ptr());
+#[cfg(feature = "runtime")]
+static PHENT: AtomicUsize = AtomicUsize::new(0);
+#[cfg(feature = "runtime")]
+static PHNUM: AtomicUsize = AtomicUsize::new(0);
+#[cfg(feature = "runtime")]
+static ENTRY: AtomicUsize = AtomicUsize::new(0);
+#[cfg(feature = "runtime")]
+static RANDOM: AtomicPtr<[u8; 16]> = AtomicPtr::new(NonNull::dangling().as_ptr());
+
+/// When "use-explicitly-provided-auxv" is enabled, 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.store(a_val as usize, Ordering::Relaxed),
+ AT_CLKTCK => CLOCK_TICKS_PER_SECOND.store(a_val as usize, Ordering::Relaxed),
+ AT_HWCAP => HWCAP.store(a_val as usize, Ordering::Relaxed),
+ AT_HWCAP2 => HWCAP2.store(a_val as usize, Ordering::Relaxed),
+ AT_MINSIGSTKSZ => MINSIGSTKSZ.store(a_val as usize, Ordering::Relaxed),
+ AT_EXECFN => EXECFN.store(a_val.cast::<c::c_char>(), Ordering::Relaxed),
+ AT_SYSINFO_EHDR => SYSINFO_EHDR.store(a_val.cast::<Elf_Ehdr>(), Ordering::Relaxed),
+
+ #[cfg(feature = "runtime")]
+ AT_SECURE => SECURE.store(a_val as usize != 0, Ordering::Relaxed),
+ #[cfg(feature = "runtime")]
+ AT_PHDR => PHDR.store(a_val.cast::<Elf_Phdr>(), Ordering::Relaxed),
+ #[cfg(feature = "runtime")]
+ AT_PHNUM => PHNUM.store(a_val as usize, Ordering::Relaxed),
+ #[cfg(feature = "runtime")]
+ AT_PHENT => PHENT.store(a_val as usize, Ordering::Relaxed),
+ #[cfg(feature = "runtime")]
+ AT_ENTRY => ENTRY.store(a_val as usize, Ordering::Relaxed),
+ #[cfg(feature = "runtime")]
+ AT_RANDOM => RANDOM.store(a_val.cast::<[u8; 16]>(), Ordering::Relaxed),
+
+ AT_NULL => break,
+ _ => (),
+ }
+ auxp = auxp.add(1);
+ }
+}
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 00000000..d77d3a84
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/param/libc_auxv.rs
@@ -0,0 +1,198 @@
+//! Linux auxv support, using libc.
+//!
+//! # Safety
+//!
+//! This uses raw pointers to locate and read the kernel-provided auxv array.
+#![allow(unsafe_code)]
+
+use crate::backend::c;
+#[cfg(feature = "param")]
+use crate::ffi::CStr;
+#[cfg(not(feature = "runtime"))]
+use core::ptr::null;
+use linux_raw_sys::elf::*;
+
+// `getauxval` wasn't supported in glibc until 2.16. Also this lets us use
+// `*mut` as the return type to preserve strict provenance.
+#[cfg(not(feature = "runtime"))]
+weak!(fn getauxval(c::c_ulong) -> *mut c::c_void);
+
+// With the "runtime" feature, go ahead and depend on `getauxval` existing so
+// that we never fail.
+#[cfg(feature = "runtime")]
+extern "C" {
+ fn getauxval(type_: c::c_ulong) -> *mut c::c_void;
+}
+
+#[cfg(feature = "runtime")]
+const AT_PHDR: c::c_ulong = 3;
+#[cfg(feature = "runtime")]
+const AT_PHENT: c::c_ulong = 4;
+#[cfg(feature = "runtime")]
+const AT_PHNUM: c::c_ulong = 5;
+#[cfg(feature = "runtime")]
+const AT_ENTRY: c::c_ulong = 9;
+const AT_HWCAP: c::c_ulong = 16;
+#[cfg(feature = "runtime")]
+const AT_RANDOM: c::c_ulong = 25;
+const AT_HWCAP2: c::c_ulong = 26;
+const AT_SECURE: c::c_ulong = 23;
+const AT_EXECFN: c::c_ulong = 31;
+const AT_SYSINFO_EHDR: c::c_ulong = 33;
+const AT_MINSIGSTKSZ: c::c_ulong = 51;
+
+// Declare `sysconf` ourselves so that we don't depend on all of libc just for
+// this.
+extern "C" {
+ fn sysconf(name: c::c_int) -> c::c_long;
+}
+
+#[cfg(target_os = "android")]
+const _SC_PAGESIZE: c::c_int = 39;
+#[cfg(target_os = "linux")]
+const _SC_PAGESIZE: c::c_int = 30;
+#[cfg(target_os = "android")]
+const _SC_CLK_TCK: c::c_int = 6;
+#[cfg(target_os = "linux")]
+const _SC_CLK_TCK: c::c_int = 2;
+
+#[cfg(feature = "param")]
+#[inline]
+pub(crate) fn page_size() -> usize {
+ unsafe { sysconf(_SC_PAGESIZE) as usize }
+}
+
+#[cfg(feature = "param")]
+#[inline]
+pub(crate) fn clock_ticks_per_second() -> u64 {
+ unsafe { sysconf(_SC_CLK_TCK) as u64 }
+}
+
+#[cfg(feature = "param")]
+#[inline]
+pub(crate) fn linux_hwcap() -> (usize, usize) {
+ #[cfg(not(feature = "runtime"))]
+ unsafe {
+ if let Some(libc_getauxval) = getauxval.get() {
+ let hwcap = libc_getauxval(AT_HWCAP) as usize;
+ let hwcap2 = libc_getauxval(AT_HWCAP2) as usize;
+ (hwcap, hwcap2)
+ } else {
+ (0, 0)
+ }
+ }
+
+ #[cfg(feature = "runtime")]
+ unsafe {
+ let hwcap = getauxval(AT_HWCAP) as usize;
+ let hwcap2 = getauxval(AT_HWCAP2) as usize;
+ (hwcap, hwcap2)
+ }
+}
+
+#[cfg(feature = "param")]
+#[inline]
+pub(crate) fn linux_minsigstksz() -> usize {
+ #[cfg(not(feature = "runtime"))]
+ if let Some(libc_getauxval) = getauxval.get() {
+ unsafe { libc_getauxval(AT_MINSIGSTKSZ) as usize }
+ } else {
+ 0
+ }
+
+ #[cfg(feature = "runtime")]
+ unsafe {
+ getauxval(AT_MINSIGSTKSZ) as usize
+ }
+}
+
+#[cfg(feature = "param")]
+#[inline]
+pub(crate) fn linux_execfn() -> &'static CStr {
+ #[cfg(not(feature = "runtime"))]
+ unsafe {
+ if let Some(libc_getauxval) = getauxval.get() {
+ CStr::from_ptr(libc_getauxval(AT_EXECFN).cast())
+ } else {
+ cstr!("")
+ }
+ }
+
+ #[cfg(feature = "runtime")]
+ unsafe {
+ CStr::from_ptr(getauxval(AT_EXECFN).cast())
+ }
+}
+
+#[cfg(feature = "runtime")]
+#[inline]
+pub(crate) fn linux_secure() -> bool {
+ unsafe { getauxval(AT_SECURE) as usize != 0 }
+}
+
+#[cfg(feature = "runtime")]
+#[inline]
+pub(crate) fn exe_phdrs() -> (*const c::c_void, usize, usize) {
+ unsafe {
+ let phdr: *const c::c_void = getauxval(AT_PHDR);
+ let phent = getauxval(AT_PHENT) as usize;
+ let phnum = getauxval(AT_PHNUM) as usize;
+ (phdr, phent, 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 {
+ #[cfg(not(feature = "runtime"))]
+ unsafe {
+ if let Some(libc_getauxval) = getauxval.get() {
+ libc_getauxval(AT_SYSINFO_EHDR) as *const Elf_Ehdr
+ } else {
+ null()
+ }
+ }
+
+ #[cfg(feature = "runtime")]
+ unsafe {
+ getauxval(AT_SYSINFO_EHDR) as *const Elf_Ehdr
+ }
+}
+
+#[cfg(feature = "runtime")]
+#[inline]
+pub(crate) fn entry() -> usize {
+ unsafe { getauxval(AT_ENTRY) as usize }
+}
+
+#[cfg(feature = "runtime")]
+#[inline]
+pub(crate) fn random() -> *const [u8; 16] {
+ unsafe { getauxval(AT_RANDOM) as *const [u8; 16] }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_abi() {
+ const_assert_eq!(self::_SC_PAGESIZE, ::libc::_SC_PAGESIZE);
+ const_assert_eq!(self::_SC_CLK_TCK, ::libc::_SC_CLK_TCK);
+ const_assert_eq!(self::AT_HWCAP, ::libc::AT_HWCAP);
+ const_assert_eq!(self::AT_HWCAP2, ::libc::AT_HWCAP2);
+ const_assert_eq!(self::AT_EXECFN, ::libc::AT_EXECFN);
+ const_assert_eq!(self::AT_SECURE, ::libc::AT_SECURE);
+ const_assert_eq!(self::AT_SYSINFO_EHDR, ::libc::AT_SYSINFO_EHDR);
+ const_assert_eq!(self::AT_MINSIGSTKSZ, ::libc::AT_MINSIGSTKSZ);
+ #[cfg(feature = "runtime")]
+ const_assert_eq!(self::AT_PHDR, ::libc::AT_PHDR);
+ #[cfg(feature = "runtime")]
+ const_assert_eq!(self::AT_PHNUM, ::libc::AT_PHNUM);
+ #[cfg(feature = "runtime")]
+ const_assert_eq!(self::AT_ENTRY, ::libc::AT_ENTRY);
+ #[cfg(feature = "runtime")]
+ const_assert_eq!(self::AT_RANDOM, ::libc::AT_RANDOM);
+ }
+}
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 00000000..365f0160
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/param/mod.rs
@@ -0,0 +1,15 @@
+// With "use-explicitly-provided-auxv" enabled, we expect to be initialized
+// with an explicit `rustix::param::init` call.
+//
+// With "use-libc-auxv" enabled, use libc's `getauxval`.
+//
+// Otherwise, we read aux values from /proc/self/auxv.
+#[cfg_attr(feature = "use-explicitly-provided-auxv", path = "init.rs")]
+#[cfg_attr(
+ all(
+ not(feature = "use-explicitly-provided-auxv"),
+ feature = "use-libc-auxv"
+ ),
+ path = "libc_auxv.rs"
+)]
+pub(crate) mod auxv;
diff --git a/vendor/rustix/src/backend/linux_raw/pid/mod.rs b/vendor/rustix/src/backend/linux_raw/pid/mod.rs
new file mode 100644
index 00000000..ef944f04
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/pid/mod.rs
@@ -0,0 +1 @@
+pub(crate) mod syscalls;
diff --git a/vendor/rustix/src/backend/linux_raw/pid/syscalls.rs b/vendor/rustix/src/backend/linux_raw/pid/syscalls.rs
new file mode 100644
index 00000000..49aaf43e
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/pid/syscalls.rs
@@ -0,0 +1,18 @@
+//! linux_raw syscalls for PIDs
+//!
+//! # Safety
+//!
+//! See the `rustix::backend` module documentation for details.
+#![allow(unsafe_code, clippy::undocumented_unsafe_blocks)]
+
+use crate::backend::conv::ret_usize_infallible;
+use crate::pid::{Pid, RawPid};
+
+#[inline]
+#[must_use]
+pub(crate) fn getpid() -> Pid {
+ unsafe {
+ let pid = ret_usize_infallible(syscall_readonly!(__NR_getpid)) as RawPid;
+ Pid::from_raw_unchecked(pid)
+ }
+}
diff --git a/vendor/rustix/src/backend/linux_raw/pipe/mod.rs b/vendor/rustix/src/backend/linux_raw/pipe/mod.rs
new file mode 100644
index 00000000..1e0181a9
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/pipe/mod.rs
@@ -0,0 +1,2 @@
+pub(crate) mod syscalls;
+pub(crate) mod types;
diff --git a/vendor/rustix/src/backend/linux_raw/pipe/syscalls.rs b/vendor/rustix/src/backend/linux_raw/pipe/syscalls.rs
new file mode 100644
index 00000000..86fe0855
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/pipe/syscalls.rs
@@ -0,0 +1,135 @@
+//! linux_raw syscalls supporting `rustix::pipe`.
+//!
+//! # Safety
+//!
+//! See the `rustix::backend` module documentation for details.
+#![allow(unsafe_code, clippy::undocumented_unsafe_blocks)]
+
+use crate::backend::conv::{c_int, c_uint, opt_mut, pass_usize, ret, ret_usize, slice};
+use crate::backend::{c, MAX_IOV};
+use crate::fd::{BorrowedFd, OwnedFd};
+use crate::io;
+use crate::pipe::{IoSliceRaw, PipeFlags, SpliceFlags};
+use core::cmp;
+use core::mem::MaybeUninit;
+use linux_raw_sys::general::{F_GETPIPE_SZ, F_SETPIPE_SZ};
+
+#[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 = "mips32r6",
+ target_arch = "mips64",
+ target_arch = "mips64r6",
+ target_arch = "riscv64",
+ ))]
+ {
+ pipe_with(PipeFlags::empty())
+ }
+ #[cfg(not(any(
+ target_arch = "aarch64",
+ target_arch = "mips",
+ target_arch = "mips32r6",
+ target_arch = "mips64",
+ target_arch = "mips64r6",
+ 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 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 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),
+ flags
+ ))
+ }
+}
+
+#[inline]
+pub(crate) 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, flags))
+}
+
+#[inline]
+pub(crate) fn tee(
+ fd_in: BorrowedFd<'_>,
+ fd_out: BorrowedFd<'_>,
+ len: usize,
+ flags: SpliceFlags,
+) -> io::Result<usize> {
+ unsafe { ret_usize(syscall!(__NR_tee, fd_in, fd_out, pass_usize(len), flags)) }
+}
+
+#[inline]
+pub(crate) fn fcntl_getpipe_size(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_size(fd: BorrowedFd<'_>, size: usize) -> io::Result<usize> {
+ let size: c::c_int = size.try_into().map_err(|_| io::Errno::PERM)?;
+
+ #[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)
+ ))
+ }
+}
diff --git a/vendor/rustix/src/backend/linux_raw/pipe/types.rs b/vendor/rustix/src/backend/linux_raw/pipe/types.rs
new file mode 100644
index 00000000..ae185562
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/pipe/types.rs
@@ -0,0 +1,85 @@
+use crate::backend::c;
+use crate::ffi;
+use bitflags::bitflags;
+use core::marker::PhantomData;
+
+bitflags! {
+ /// `O_*` constants for use with [`pipe_with`].
+ ///
+ /// [`pipe_with`]: crate::pipe::pipe_with
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct PipeFlags: ffi::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;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+bitflags! {
+ /// `SPLICE_F_*` constants for use with [`splice`], [`vmsplice`], and
+ /// [`tee`].
+ ///
+ /// [`splice`]: crate::pipe::splice
+ /// [`vmsplice`]: crate::pipe::splice
+ /// [`tee`]: crate::pipe::tee
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct SpliceFlags: ffi::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;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+/// A buffer type for use 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.
+///
+/// [`vmsplice`]: crate::pipe::vmsplice
+#[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).cast::<ffi::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().cast::<ffi::c_void>(),
+ iov_len: buf.len() as _,
+ },
+ _lifetime: PhantomData,
+ }
+ }
+}
diff --git a/vendor/rustix/src/backend/linux_raw/prctl/mod.rs b/vendor/rustix/src/backend/linux_raw/prctl/mod.rs
new file mode 100644
index 00000000..ef944f04
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/prctl/mod.rs
@@ -0,0 +1 @@
+pub(crate) mod syscalls;
diff --git a/vendor/rustix/src/backend/linux_raw/prctl/syscalls.rs b/vendor/rustix/src/backend/linux_raw/prctl/syscalls.rs
new file mode 100644
index 00000000..1410d512
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/prctl/syscalls.rs
@@ -0,0 +1,21 @@
+//! linux_raw syscalls supporting modules that use `prctl`.
+//!
+//! # Safety
+//!
+//! See the `rustix::backend` module documentation for details.
+#![allow(unsafe_code, clippy::undocumented_unsafe_blocks)]
+
+use crate::backend::c;
+use crate::backend::conv::{c_int, ret_c_int};
+use crate::io;
+
+#[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/backend/linux_raw/process/mod.rs b/vendor/rustix/src/backend/linux_raw/process/mod.rs
new file mode 100644
index 00000000..6bc9443d
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/process/mod.rs
@@ -0,0 +1,3 @@
+pub(crate) mod syscalls;
+pub(crate) mod types;
+pub(crate) mod wait;
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 00000000..c9c1fd82
--- /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, clippy::undocumented_unsafe_blocks)]
+
+use crate::backend::c;
+#[cfg(all(feature = "alloc", feature = "fs"))]
+use crate::backend::conv::slice_mut;
+use crate::backend::conv::{
+ by_mut, by_ref, c_int, c_uint, negative_pid, pass_usize, raw_fd, ret, ret_c_int,
+ ret_c_int_infallible, ret_infallible, ret_owned_fd, zero,
+};
+use crate::fd::{AsRawFd as _, BorrowedFd, OwnedFd, RawFd};
+#[cfg(feature = "fs")]
+use crate::ffi::CStr;
+use crate::io;
+use crate::pid::RawPid;
+use crate::process::{
+ Flock, Pid, PidfdFlags, PidfdGetfdFlags, Resource, Rlimit, Uid, WaitId, WaitIdOptions,
+ WaitIdStatus, WaitOptions, WaitStatus,
+};
+use crate::signal::Signal;
+use core::mem::MaybeUninit;
+use core::ptr::{null, null_mut};
+use linux_raw_sys::general::{rlimit64, PRIO_PGRP, PRIO_PROCESS, PRIO_USER, RLIM64_INFINITY};
+#[cfg(feature = "fs")]
+use {crate::backend::conv::ret_c_uint_infallible, crate::fs::Mode};
+#[cfg(feature = "alloc")]
+use {
+ crate::backend::conv::{ret_usize, slice_just_addr_mut},
+ crate::process::Gid,
+};
+
+#[cfg(feature = "fs")]
+#[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)) }
+}
+
+#[cfg(feature = "fs")]
+#[inline]
+pub(crate) fn chroot(filename: &CStr) -> io::Result<()> {
+ unsafe { ret(syscall_readonly!(__NR_chroot, filename)) }
+}
+
+#[cfg(all(feature = "alloc", feature = "fs"))]
+#[inline]
+pub(crate) fn getcwd(buf: &mut [MaybeUninit<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]
+#[must_use]
+pub(crate) fn getppid() -> Option<Pid> {
+ unsafe {
+ let ppid = ret_c_int_infallible(syscall_readonly!(__NR_getppid));
+ Pid::from_raw(ppid)
+ }
+}
+
+#[inline]
+pub(crate) fn getpgid(pid: Option<Pid>) -> io::Result<Pid> {
+ unsafe {
+ let pgid = ret_c_int(syscall_readonly!(__NR_getpgid, c_int(Pid::as_raw(pid))))?;
+ debug_assert!(pgid > 0);
+ Ok(Pid::from_raw_unchecked(pgid))
+ }
+}
+
+#[inline]
+pub(crate) fn setpgid(pid: Option<Pid>, pgid: Option<Pid>) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_setpgid,
+ c_int(Pid::as_raw(pid)),
+ c_int(Pid::as_raw(pgid))
+ ))
+ }
+}
+
+#[inline]
+#[must_use]
+pub(crate) fn getpgrp() -> Pid {
+ // Use the `getpgrp` syscall if available.
+ #[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))]
+ unsafe {
+ let pgid = ret_c_int_infallible(syscall_readonly!(__NR_getpgrp));
+ debug_assert!(pgid > 0);
+ Pid::from_raw_unchecked(pgid)
+ }
+
+ // Otherwise use `getpgrp` and pass it zero.
+ #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
+ unsafe {
+ let pgid = ret_c_int_infallible(syscall_readonly!(__NR_getpgid, c_uint(0)));
+ debug_assert!(pgid > 0);
+ Pid::from_raw_unchecked(pgid)
+ }
+}
+
+#[cfg(feature = "fs")]
+#[inline]
+pub(crate) fn umask(mode: Mode) -> Mode {
+ unsafe { Mode::from_bits_retain(ret_c_uint_infallible(syscall_readonly!(__NR_umask, mode))) }
+}
+
+#[inline]
+pub(crate) fn nice(inc: i32) -> io::Result<i32> {
+ let priority = (if inc > -40 && inc < 40 {
+ inc + getpriority_process(None)?
+ } else {
+ inc
+ })
+ .clamp(-20, 19);
+ 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_int(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_int(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_int(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_int(Pid::as_raw(pid)),
+ c_int(priority)
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn getrlimit(limit: Resource) -> Rlimit {
+ let mut result = MaybeUninit::<rlimit64>::uninit();
+ unsafe {
+ ret_infallible(syscall!(
+ __NR_prlimit64,
+ c_uint(0),
+ limit,
+ null::<c::c_void>(),
+ &mut result
+ ));
+ rlimit_from_linux(result.assume_init())
+ }
+}
+
+#[inline]
+pub(crate) fn setrlimit(limit: Resource, new: Rlimit) -> io::Result<()> {
+ unsafe {
+ let lim = rlimit_to_linux(new);
+ match ret(syscall_readonly!(
+ __NR_prlimit64,
+ c_uint(0),
+ limit,
+ by_ref(&lim),
+ null_mut::<c::c_void>()
+ )) {
+ Ok(()) => Ok(()),
+ Err(err) => Err(err),
+ }
+ }
+}
+
+#[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_int(Pid::as_raw(pid)),
+ limit,
+ by_ref(&lim),
+ &mut result
+ )) {
+ Ok(()) => Ok(rlimit_from_linux(result.assume_init())),
+ Err(err) => Err(err),
+ }
+ }
+}
+
+/// Convert a C `rlimit64` to a Rust `Rlimit`.
+#[inline]
+fn rlimit_from_linux(lim: rlimit64) -> Rlimit {
+ let current = if lim.rlim_cur == RLIM64_INFINITY as u64 {
+ None
+ } else {
+ Some(lim.rlim_cur)
+ };
+ let maximum = if lim.rlim_max == RLIM64_INFINITY as u64 {
+ None
+ } else {
+ Some(lim.rlim_max)
+ };
+ Rlimit { current, maximum }
+}
+
+/// Convert a Rust [`Rlimit`] to a C `rlimit64`.
+#[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 }
+}
+
+#[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 waitpgid(pgid: Pid, waitopts: WaitOptions) -> io::Result<Option<(Pid, WaitStatus)>> {
+ _waitpid(-pgid.as_raw_nonzero().get(), waitopts)
+}
+
+#[inline]
+pub(crate) fn _waitpid(
+ pid: RawPid,
+ waitopts: WaitOptions,
+) -> io::Result<Option<(Pid, WaitStatus)>> {
+ unsafe {
+ let mut status = MaybeUninit::<i32>::uninit();
+ let pid = ret_c_int(syscall!(
+ __NR_wait4,
+ c_int(pid as _),
+ &mut status,
+ c_int(waitopts.bits() as _),
+ zero()
+ ))?;
+ Ok(Pid::from_raw(pid).map(|pid| (pid, WaitStatus::new(status.assume_init()))))
+ }
+}
+
+#[inline]
+pub(crate) fn waitid(id: WaitId<'_>, options: WaitIdOptions) -> io::Result<Option<WaitIdStatus>> {
+ // Get the id to wait on.
+ match id {
+ WaitId::All => _waitid_all(options),
+ WaitId::Pid(pid) => _waitid_pid(pid, options),
+ WaitId::Pgid(pid) => _waitid_pgid(pid, options),
+ WaitId::PidFd(fd) => _waitid_pidfd(fd, options),
+ }
+}
+
+#[inline]
+fn _waitid_all(options: WaitIdOptions) -> io::Result<Option<WaitIdStatus>> {
+ // `waitid` can return successfully without initializing the struct (no
+ // children found when using `WNOHANG`)
+ let mut status = MaybeUninit::<c::siginfo_t>::zeroed();
+ unsafe {
+ ret(syscall!(
+ __NR_waitid,
+ c_uint(c::P_ALL),
+ c_uint(0),
+ &mut status,
+ c_int(options.bits() as _),
+ zero()
+ ))?
+ };
+
+ Ok(unsafe { cvt_waitid_status(status) })
+}
+
+#[inline]
+fn _waitid_pid(pid: Pid, options: WaitIdOptions) -> io::Result<Option<WaitIdStatus>> {
+ // `waitid` can return successfully without initializing the struct (no
+ // children found when using `WNOHANG`)
+ let mut status = MaybeUninit::<c::siginfo_t>::zeroed();
+ unsafe {
+ ret(syscall!(
+ __NR_waitid,
+ c_uint(c::P_PID),
+ c_int(Pid::as_raw(Some(pid))),
+ &mut status,
+ c_int(options.bits() as _),
+ zero()
+ ))?
+ };
+
+ Ok(unsafe { cvt_waitid_status(status) })
+}
+
+#[inline]
+fn _waitid_pgid(pgid: Option<Pid>, options: WaitIdOptions) -> io::Result<Option<WaitIdStatus>> {
+ // `waitid` can return successfully without initializing the struct (no
+ // children found when using `WNOHANG`)
+ let mut status = MaybeUninit::<c::siginfo_t>::zeroed();
+ unsafe {
+ ret(syscall!(
+ __NR_waitid,
+ c_uint(c::P_PGID),
+ c_int(Pid::as_raw(pgid)),
+ &mut status,
+ c_int(options.bits() as _),
+ zero()
+ ))?
+ };
+
+ Ok(unsafe { cvt_waitid_status(status) })
+}
+
+#[inline]
+fn _waitid_pidfd(fd: BorrowedFd<'_>, options: WaitIdOptions) -> io::Result<Option<WaitIdStatus>> {
+ // `waitid` can return successfully without initializing the struct (no
+ // children found when using `WNOHANG`)
+ let mut status = MaybeUninit::<c::siginfo_t>::zeroed();
+ unsafe {
+ ret(syscall!(
+ __NR_waitid,
+ c_uint(c::P_PIDFD),
+ c_uint(fd.as_raw_fd() as _),
+ &mut status,
+ c_int(options.bits() as _),
+ zero()
+ ))?
+ };
+
+ Ok(unsafe { cvt_waitid_status(status) })
+}
+
+/// Convert a `siginfo_t` to a `WaitIdStatus`.
+///
+/// # Safety
+///
+/// The caller must ensure that `status` is initialized and that `waitid`
+/// returned successfully.
+#[inline]
+unsafe fn cvt_waitid_status(status: MaybeUninit<c::siginfo_t>) -> Option<WaitIdStatus> {
+ let status = status.assume_init();
+ if status
+ .__bindgen_anon_1
+ .__bindgen_anon_1
+ ._sifields
+ ._sigchld
+ ._pid
+ == 0
+ {
+ None
+ } else {
+ Some(WaitIdStatus(status))
+ }
+}
+
+#[inline]
+pub(crate) fn getsid(pid: Option<Pid>) -> io::Result<Pid> {
+ unsafe {
+ let pid = ret_c_int(syscall_readonly!(__NR_getsid, c_int(Pid::as_raw(pid))))?;
+ Ok(Pid::from_raw_unchecked(pid))
+ }
+}
+
+#[inline]
+pub(crate) fn setsid() -> io::Result<Pid> {
+ unsafe {
+ let pid = ret_c_int(syscall_readonly!(__NR_setsid))?;
+ Ok(Pid::from_raw_unchecked(pid))
+ }
+}
+
+#[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) fn test_kill_process(pid: Pid) -> io::Result<()> {
+ unsafe { ret(syscall_readonly!(__NR_kill, pid, pass_usize(0))) }
+}
+
+#[inline]
+pub(crate) fn test_kill_process_group(pid: Pid) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_kill,
+ negative_pid(pid),
+ pass_usize(0)
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn test_kill_current_process_group() -> io::Result<()> {
+ unsafe { ret(syscall_readonly!(__NR_kill, pass_usize(0), pass_usize(0))) }
+}
+
+#[inline]
+pub(crate) fn pidfd_getfd(
+ pidfd: BorrowedFd<'_>,
+ targetfd: RawFd,
+ flags: PidfdGetfdFlags,
+) -> io::Result<OwnedFd> {
+ unsafe {
+ ret_owned_fd(syscall_readonly!(
+ __NR_pidfd_getfd,
+ pidfd,
+ raw_fd(targetfd),
+ c_int(flags.bits() as _)
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn pidfd_open(pid: Pid, flags: PidfdFlags) -> io::Result<OwnedFd> {
+ unsafe { ret_owned_fd(syscall_readonly!(__NR_pidfd_open, pid, flags)) }
+}
+
+#[inline]
+pub(crate) fn pidfd_send_signal(fd: BorrowedFd<'_>, sig: Signal) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_pidfd_send_signal,
+ fd,
+ sig,
+ pass_usize(0),
+ pass_usize(0)
+ ))
+ }
+}
+
+#[cfg(feature = "fs")]
+#[inline]
+pub(crate) fn pivot_root(new_root: &CStr, put_old: &CStr) -> io::Result<()> {
+ unsafe { ret(syscall_readonly!(__NR_pivot_root, new_root, put_old)) }
+}
+
+#[cfg(feature = "alloc")]
+#[inline]
+pub(crate) fn getgroups(buf: &mut [Gid]) -> io::Result<usize> {
+ let len = buf.len().try_into().map_err(|_| io::Errno::NOMEM)?;
+
+ unsafe {
+ ret_usize(syscall!(
+ __NR_getgroups,
+ c_int(len),
+ slice_just_addr_mut(buf)
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn fcntl_getlk(fd: BorrowedFd<'_>, lock: &Flock) -> io::Result<Option<Flock>> {
+ let mut curr_lock: c::flock = lock.as_raw();
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ ret(syscall!(
+ __NR_fcntl64,
+ fd,
+ c_uint(c::F_GETLK64),
+ by_mut(&mut curr_lock)
+ ))?
+ }
+ #[cfg(target_pointer_width = "64")]
+ unsafe {
+ ret(syscall!(
+ __NR_fcntl,
+ fd,
+ c_uint(c::F_GETLK),
+ by_mut(&mut curr_lock)
+ ))?
+ }
+
+ // If no blocking lock is found, `fcntl(GETLK, ..)` sets `l_type` to
+ // `F_UNLCK`.
+ if curr_lock.l_type == c::F_UNLCK as _ {
+ Ok(None)
+ } else {
+ Ok(Some(unsafe { Flock::from_raw_unchecked(curr_lock) }))
+ }
+}
diff --git a/vendor/rustix/src/backend/linux_raw/process/types.rs b/vendor/rustix/src/backend/linux_raw/process/types.rs
new file mode 100644
index 00000000..58b8cc14
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/process/types.rs
@@ -0,0 +1,43 @@
+/// A resource value for use with [`getrlimit`], [`setrlimit`], and
+/// [`prlimit`].
+///
+/// [`getrlimit`]: crate::process::getrlimit
+/// [`setrlimit`]: crate::process::setrlimit
+/// [`prlimit`]: crate::process::prlimit
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[repr(u32)]
+#[non_exhaustive]
+pub enum Resource {
+ /// `RLIMIT_CPU`
+ Cpu = linux_raw_sys::general::RLIMIT_CPU,
+ /// `RLIMIT_FSIZE`
+ Fsize = linux_raw_sys::general::RLIMIT_FSIZE,
+ /// `RLIMIT_DATA`
+ Data = linux_raw_sys::general::RLIMIT_DATA,
+ /// `RLIMIT_STACK`
+ Stack = linux_raw_sys::general::RLIMIT_STACK,
+ /// `RLIMIT_CORE`
+ Core = linux_raw_sys::general::RLIMIT_CORE,
+ /// `RLIMIT_RSS`
+ Rss = linux_raw_sys::general::RLIMIT_RSS,
+ /// `RLIMIT_NPROC`
+ Nproc = linux_raw_sys::general::RLIMIT_NPROC,
+ /// `RLIMIT_NOFILE`
+ Nofile = linux_raw_sys::general::RLIMIT_NOFILE,
+ /// `RLIMIT_MEMLOCK`
+ Memlock = linux_raw_sys::general::RLIMIT_MEMLOCK,
+ /// `RLIMIT_AS`
+ As = linux_raw_sys::general::RLIMIT_AS,
+ /// `RLIMIT_LOCKS`
+ Locks = linux_raw_sys::general::RLIMIT_LOCKS,
+ /// `RLIMIT_SIGPENDING`
+ Sigpending = linux_raw_sys::general::RLIMIT_SIGPENDING,
+ /// `RLIMIT_MSGQUEUE`
+ Msgqueue = linux_raw_sys::general::RLIMIT_MSGQUEUE,
+ /// `RLIMIT_NICE`
+ Nice = linux_raw_sys::general::RLIMIT_NICE,
+ /// `RLIMIT_RTPRIO`
+ Rtprio = linux_raw_sys::general::RLIMIT_RTPRIO,
+ /// `RLIMIT_RTTIME`
+ Rttime = linux_raw_sys::general::RLIMIT_RTTIME,
+}
diff --git a/vendor/rustix/src/backend/linux_raw/process/wait.rs b/vendor/rustix/src/backend/linux_raw/process/wait.rs
new file mode 100644
index 00000000..89b3eadb
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/process/wait.rs
@@ -0,0 +1,123 @@
+// The functions replacing the C macros use the same names as in libc.
+#![allow(non_snake_case, unsafe_code)]
+
+use crate::ffi::c_int;
+pub(crate) use linux_raw_sys::general::{
+ siginfo_t, WCONTINUED, WEXITED, WNOHANG, WNOWAIT, WSTOPPED, WUNTRACED,
+};
+
+#[inline]
+pub(crate) fn WIFSTOPPED(status: i32) -> bool {
+ (status & 0xff) == 0x7f
+}
+
+#[inline]
+pub(crate) fn WSTOPSIG(status: i32) -> i32 {
+ (status >> 8) & 0xff
+}
+
+#[inline]
+pub(crate) fn WIFCONTINUED(status: i32) -> bool {
+ status == 0xffff
+}
+
+#[inline]
+pub(crate) fn WIFSIGNALED(status: i32) -> bool {
+ ((status & 0x7f) + 1) as i8 >= 2
+}
+
+#[inline]
+pub(crate) fn WTERMSIG(status: i32) -> i32 {
+ status & 0x7f
+}
+
+#[inline]
+pub(crate) fn WIFEXITED(status: i32) -> bool {
+ (status & 0x7f) == 0
+}
+
+#[inline]
+pub(crate) fn WEXITSTATUS(status: i32) -> i32 {
+ (status >> 8) & 0xff
+}
+
+pub(crate) trait SiginfoExt {
+ fn si_signo(&self) -> c_int;
+ fn si_errno(&self) -> c_int;
+ fn si_code(&self) -> c_int;
+ unsafe fn si_status(&self) -> c_int;
+}
+
+impl SiginfoExt for siginfo_t {
+ #[inline]
+ fn si_signo(&self) -> c_int {
+ // SAFETY: This is technically a union access, but it's only a union
+ // with padding.
+ unsafe { self.__bindgen_anon_1.__bindgen_anon_1.si_signo }
+ }
+
+ #[inline]
+ fn si_errno(&self) -> c_int {
+ // SAFETY: This is technically a union access, but it's only a union
+ // with padding.
+ unsafe { self.__bindgen_anon_1.__bindgen_anon_1.si_errno }
+ }
+
+ #[inline]
+ fn si_code(&self) -> c_int {
+ // SAFETY: This is technically a union access, but it's only a union
+ // with padding.
+ unsafe { self.__bindgen_anon_1.__bindgen_anon_1.si_code }
+ }
+
+ /// Return the exit status or signal number recorded in a `siginfo_t`.
+ ///
+ /// # Safety
+ ///
+ /// `si_signo` must equal `SIGCHLD` (as it is guaranteed to do after a
+ /// `waitid` call).
+ #[inline]
+ unsafe fn si_status(&self) -> c_int {
+ self.__bindgen_anon_1
+ .__bindgen_anon_1
+ ._sifields
+ ._sigchld
+ ._status
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_libc_correspondence() {
+ for status in [
+ 0,
+ 1,
+ 63,
+ 64,
+ 65,
+ 127,
+ 128,
+ 129,
+ 255,
+ 256,
+ 257,
+ 4095,
+ 4096,
+ 4097,
+ i32::MAX,
+ i32::MIN,
+ u32::MAX as i32,
+ ] {
+ assert_eq!(WIFSTOPPED(status), libc::WIFSTOPPED(status));
+ assert_eq!(WSTOPSIG(status), libc::WSTOPSIG(status));
+ assert_eq!(WIFCONTINUED(status), libc::WIFCONTINUED(status));
+ assert_eq!(WIFSIGNALED(status), libc::WIFSIGNALED(status));
+ assert_eq!(WTERMSIG(status), libc::WTERMSIG(status));
+ assert_eq!(WIFEXITED(status), libc::WIFEXITED(status));
+ assert_eq!(WEXITSTATUS(status), libc::WEXITSTATUS(status));
+ }
+ }
+}
diff --git a/vendor/rustix/src/backend/linux_raw/pty/mod.rs b/vendor/rustix/src/backend/linux_raw/pty/mod.rs
new file mode 100644
index 00000000..ef944f04
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/pty/mod.rs
@@ -0,0 +1 @@
+pub(crate) mod syscalls;
diff --git a/vendor/rustix/src/backend/linux_raw/pty/syscalls.rs b/vendor/rustix/src/backend/linux_raw/pty/syscalls.rs
new file mode 100644
index 00000000..b64344fb
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/pty/syscalls.rs
@@ -0,0 +1,43 @@
+//! linux_raw syscalls supporting `rustix::pty`.
+//!
+//! # Safety
+//!
+//! See the `rustix::backend` module documentation for details.
+#![allow(unsafe_code, clippy::undocumented_unsafe_blocks)]
+
+use crate::backend::conv::{by_ref, c_uint, ret};
+use crate::fd::BorrowedFd;
+use crate::io;
+use linux_raw_sys::ioctl::TIOCSPTLCK;
+#[cfg(feature = "alloc")]
+use {
+ crate::backend::c, crate::ffi::CString, crate::path::DecInt, alloc::vec::Vec,
+ core::mem::MaybeUninit, linux_raw_sys::ioctl::TIOCGPTN,
+};
+
+#[cfg(feature = "alloc")]
+#[inline]
+pub(crate) fn ptsname(fd: BorrowedFd<'_>, mut buffer: Vec<u8>) -> io::Result<CString> {
+ unsafe {
+ let mut n = MaybeUninit::<c::c_int>::uninit();
+ ret(syscall!(__NR_ioctl, fd, c_uint(TIOCGPTN), &mut n))?;
+
+ buffer.clear();
+ buffer.extend_from_slice(b"/dev/pts/");
+ buffer.extend_from_slice(DecInt::new(n.assume_init()).as_bytes());
+ buffer.push(b'\0');
+ Ok(CString::from_vec_with_nul_unchecked(buffer))
+ }
+}
+
+#[inline]
+pub(crate) fn unlockpt(fd: BorrowedFd<'_>) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_ioctl,
+ fd,
+ c_uint(TIOCSPTLCK),
+ by_ref(&0)
+ ))
+ }
+}
diff --git a/vendor/rustix/src/backend/linux_raw/rand/mod.rs b/vendor/rustix/src/backend/linux_raw/rand/mod.rs
new file mode 100644
index 00000000..1e0181a9
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/rand/mod.rs
@@ -0,0 +1,2 @@
+pub(crate) mod syscalls;
+pub(crate) mod types;
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 00000000..acea3968
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/rand/syscalls.rs
@@ -0,0 +1,15 @@
+//! linux_raw syscalls supporting `rustix::rand`.
+//!
+//! # Safety
+//!
+//! See the `rustix::backend` module documentation for details.
+#![allow(unsafe_code, clippy::undocumented_unsafe_blocks)]
+
+use crate::backend::conv::{pass_usize, ret_usize};
+use crate::io;
+use crate::rand::GetRandomFlags;
+
+#[inline]
+pub(crate) unsafe fn getrandom(buf: (*mut u8, usize), flags: GetRandomFlags) -> io::Result<usize> {
+ ret_usize(syscall!(__NR_getrandom, buf.0, pass_usize(buf.1), flags))
+}
diff --git a/vendor/rustix/src/backend/linux_raw/rand/types.rs b/vendor/rustix/src/backend/linux_raw/rand/types.rs
new file mode 100644
index 00000000..9bc857fd
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/rand/types.rs
@@ -0,0 +1,20 @@
+use bitflags::bitflags;
+
+bitflags! {
+ /// `GRND_*` flags for use with [`getrandom`].
+ ///
+ /// [`getrandom`]: crate::rand::getrandom
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct GetRandomFlags: u32 {
+ /// `GRND_RANDOM`
+ const RANDOM = linux_raw_sys::general::GRND_RANDOM;
+ /// `GRND_NONBLOCK`
+ const NONBLOCK = linux_raw_sys::general::GRND_NONBLOCK;
+ /// `GRND_INSECURE`
+ const INSECURE = linux_raw_sys::general::GRND_INSECURE;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
diff --git a/vendor/rustix/src/backend/linux_raw/reg.rs b/vendor/rustix/src/backend/linux_raw/reg.rs
new file mode 100644
index 00000000..57a8d269
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/reg.rs
@@ -0,0 +1,259 @@
+//! Encapsulation for system call arguments and return values.
+//!
+//! The inline-asm code paths do some amount of reordering of arguments; to
+//! ensure that we don't accidentally misroute an argument or return value, we
+//! use distinct types for each argument index and return value.
+//!
+//! # Safety
+//!
+//! The `ToAsm` and `FromAsm` traits are unsafe to use; they should only be
+//! used by the syscall code which executes actual syscall machine
+//! instructions.
+
+#![allow(unsafe_code)]
+
+use super::c;
+use super::fd::RawFd;
+use core::marker::PhantomData;
+use core::ops::Range;
+
+pub(super) trait ToAsm: private::Sealed {
+ /// Convert `self` to a `usize` ready to be passed to a syscall
+ /// machine instruction.
+ ///
+ /// # Safety
+ ///
+ /// This should be used immediately before the syscall instruction, and the
+ /// returned value shouldn't be used for any other purpose.
+ #[must_use]
+ unsafe fn to_asm(self) -> *mut Opaque;
+}
+
+pub(super) trait FromAsm: private::Sealed {
+ /// Convert `raw` from a value produced by a syscall machine instruction
+ /// into a `Self`.
+ ///
+ /// # Safety
+ ///
+ /// This should be used immediately after the syscall instruction, and the
+ /// operand value shouldn't be used for any other purpose.
+ #[must_use]
+ unsafe fn from_asm(raw: *mut Opaque) -> Self;
+}
+
+/// To preserve provenance, syscall arguments and return values are passed as
+/// pointer types. They need a type to point to, so we define a custom private
+/// type, to prevent it from being used for anything else.
+#[repr(transparent)]
+#[allow(dead_code)]
+pub(super) struct Opaque(c::c_void);
+
+// Argument numbers.
+pub(super) struct A0(());
+pub(super) struct A1(());
+pub(super) struct A2(());
+pub(super) struct A3(());
+pub(super) struct A4(());
+pub(super) struct A5(());
+#[cfg(any(target_arch = "mips", target_arch = "mips32r6"))]
+pub(super) struct A6(());
+#[cfg(target_arch = "x86")]
+pub(super) struct SocketArg;
+
+pub(super) trait ArgNumber: private::Sealed {}
+impl ArgNumber for A0 {}
+impl ArgNumber for A1 {}
+impl ArgNumber for A2 {}
+impl ArgNumber for A3 {}
+impl ArgNumber for A4 {}
+impl ArgNumber for A5 {}
+#[cfg(any(target_arch = "mips", target_arch = "mips32r6"))]
+impl ArgNumber for A6 {}
+#[cfg(target_arch = "x86")]
+impl ArgNumber for SocketArg {}
+
+// Return value numbers.
+pub(super) struct R0(());
+
+pub(super) trait RetNumber: private::Sealed {}
+impl RetNumber for R0 {}
+
+/// Syscall arguments use register-sized types. We use a newtype to
+/// discourage accidental misuse of the raw integer values.
+///
+/// This type doesn't implement `Clone` or `Copy`; it should be used exactly
+/// once. And it has a lifetime to ensure that it doesn't outlive any resources
+/// it might be pointing to.
+#[repr(transparent)]
+#[must_use]
+pub(super) struct ArgReg<'a, Num: ArgNumber> {
+ raw: *mut Opaque,
+ _phantom: PhantomData<(&'a (), Num)>,
+}
+
+impl<'a, Num: ArgNumber> ToAsm for ArgReg<'a, Num> {
+ #[inline]
+ unsafe fn to_asm(self) -> *mut Opaque {
+ self.raw
+ }
+}
+
+/// Syscall return values use register-sized types. We use a newtype to
+/// discourage accidental misuse of the raw integer values.
+///
+/// This type doesn't implement `Clone` or `Copy`; it should be used exactly
+/// once.
+#[repr(transparent)]
+#[must_use]
+pub(super) struct RetReg<Num: RetNumber> {
+ raw: *mut Opaque,
+ _phantom: PhantomData<Num>,
+}
+
+impl<Num: RetNumber> RetReg<Num> {
+ #[inline]
+ pub(super) fn decode_usize(self) -> usize {
+ debug_assert!(!(-4095..0).contains(&(self.raw as isize)));
+ self.raw as usize
+ }
+
+ #[inline]
+ pub(super) fn decode_raw_fd(self) -> RawFd {
+ let bits = self.decode_usize();
+ let raw_fd = bits as RawFd;
+
+ // Converting `raw` to `RawFd` should be lossless.
+ debug_assert_eq!(raw_fd as usize, bits);
+
+ raw_fd
+ }
+
+ #[inline]
+ pub(super) fn decode_c_int(self) -> c::c_int {
+ let bits = self.decode_usize();
+ let c_int_ = bits as c::c_int;
+
+ // Converting `raw` to `c_int` should be lossless.
+ debug_assert_eq!(c_int_ as usize, bits);
+
+ c_int_
+ }
+
+ #[inline]
+ pub(super) fn decode_c_uint(self) -> c::c_uint {
+ let bits = self.decode_usize();
+ let c_uint_ = bits as c::c_uint;
+
+ // Converting `raw` to `c_uint` should be lossless.
+ debug_assert_eq!(c_uint_ as usize, bits);
+
+ c_uint_
+ }
+
+ #[inline]
+ pub(super) fn decode_void_star(self) -> *mut c::c_void {
+ self.raw.cast()
+ }
+
+ #[cfg(target_pointer_width = "64")]
+ #[inline]
+ pub(super) fn decode_u64(self) -> u64 {
+ self.decode_usize() as u64
+ }
+
+ #[inline]
+ pub(super) fn decode_void(self) {
+ let ignore = self.decode_usize();
+ debug_assert_eq!(ignore, 0);
+ }
+
+ #[inline]
+ pub(super) fn decode_error_code(self) -> u16 {
+ let bits = self.raw as usize;
+
+ // `raw` must be in `-4095..0`. Linux always returns errors in
+ // `-4095..0`, and we double-check it here.
+ debug_assert!((-4095..0).contains(&(bits as isize)));
+
+ bits as u16
+ }
+
+ #[inline]
+ pub(super) fn is_nonzero(&self) -> bool {
+ !self.raw.is_null()
+ }
+
+ #[inline]
+ pub(super) fn is_negative(&self) -> bool {
+ (self.raw as isize) < 0
+ }
+
+ #[inline]
+ pub(super) fn is_in_range(&self, range: Range<isize>) -> bool {
+ range.contains(&(self.raw as isize))
+ }
+}
+
+impl<Num: RetNumber> FromAsm for RetReg<Num> {
+ #[inline]
+ unsafe fn from_asm(raw: *mut Opaque) -> Self {
+ Self {
+ raw,
+ _phantom: PhantomData,
+ }
+ }
+}
+
+#[repr(transparent)]
+pub(super) struct SyscallNumber<'a> {
+ pub(super) nr: usize,
+ _phantom: PhantomData<&'a ()>,
+}
+
+impl<'a> ToAsm for SyscallNumber<'a> {
+ #[inline]
+ unsafe fn to_asm(self) -> *mut Opaque {
+ self.nr as usize as *mut Opaque
+ }
+}
+
+/// Encode a system call argument as an `ArgReg`.
+#[inline]
+pub(super) fn raw_arg<'a, Num: ArgNumber>(raw: *mut Opaque) -> ArgReg<'a, Num> {
+ ArgReg {
+ raw,
+ _phantom: PhantomData,
+ }
+}
+
+/// Encode a system call number (a `__NR_*` constant) as a `SyscallNumber`.
+#[inline]
+pub(super) const fn nr<'a>(nr: u32) -> SyscallNumber<'a> {
+ SyscallNumber {
+ nr: nr as usize,
+ _phantom: PhantomData,
+ }
+}
+
+/// Seal our various traits using the technique documented [here].
+///
+/// [here]: https://rust-lang.github.io/api-guidelines/future-proofing.html
+mod private {
+ pub trait Sealed {}
+
+ // Implement for those same types, but no others.
+ impl<'a, Num: super::ArgNumber> Sealed for super::ArgReg<'a, Num> {}
+ impl<Num: super::RetNumber> Sealed for super::RetReg<Num> {}
+ impl<'a> Sealed for super::SyscallNumber<'a> {}
+ impl Sealed for super::A0 {}
+ impl Sealed for super::A1 {}
+ impl Sealed for super::A2 {}
+ impl Sealed for super::A3 {}
+ impl Sealed for super::A4 {}
+ impl Sealed for super::A5 {}
+ #[cfg(any(target_arch = "mips", target_arch = "mips32r6"))]
+ impl Sealed for super::A6 {}
+ #[cfg(target_arch = "x86")]
+ impl Sealed for super::SocketArg {}
+ impl Sealed for super::R0 {}
+}
diff --git a/vendor/rustix/src/backend/linux_raw/runtime/mod.rs b/vendor/rustix/src/backend/linux_raw/runtime/mod.rs
new file mode 100644
index 00000000..0b48649c
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/runtime/mod.rs
@@ -0,0 +1,2 @@
+pub(crate) mod syscalls;
+pub(crate) mod tls;
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 00000000..1e00030c
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/runtime/syscalls.rs
@@ -0,0 +1,346 @@
+//! linux_raw syscalls supporting `rustix::runtime`.
+//!
+//! # Safety
+//!
+//! See the `rustix::backend` module documentation for details.
+#![allow(unsafe_code, clippy::undocumented_unsafe_blocks)]
+
+use crate::backend::c;
+#[cfg(target_arch = "x86")]
+use crate::backend::conv::by_mut;
+#[cfg(target_arch = "x86_64")]
+use crate::backend::conv::c_uint;
+use crate::backend::conv::{
+ by_ref, c_int, opt_ref, ret, ret_c_int, ret_c_int_infallible, ret_error, ret_infallible,
+ ret_void_star, size_of, zero,
+};
+#[cfg(feature = "fs")]
+use crate::fd::BorrowedFd;
+use crate::ffi::CStr;
+#[cfg(feature = "fs")]
+use crate::fs::AtFlags;
+use crate::io;
+use crate::pid::{Pid, RawPid};
+use crate::runtime::{Fork, How, KernelSigSet, KernelSigaction, Siginfo, Stack};
+use crate::signal::Signal;
+use crate::timespec::Timespec;
+use core::ffi::c_void;
+use core::mem::MaybeUninit;
+#[cfg(all(target_pointer_width = "32", not(feature = "linux_5_1")))]
+use linux_raw_sys::general::__kernel_old_timespec;
+#[cfg(target_arch = "x86_64")]
+use linux_raw_sys::general::ARCH_SET_FS;
+
+#[inline]
+pub(crate) unsafe fn kernel_fork() -> io::Result<Fork> {
+ let mut child_pid = MaybeUninit::<RawPid>::uninit();
+
+ // Unix `fork` only returns the child PID in the parent; we'd like it in
+ // the child too, so set `CLONE_CHILD_SETTID` and pass in the address of a
+ // memory location to store it to in the child.
+ //
+ // Architectures differ on the order of the parameters.
+ #[cfg(target_arch = "x86_64")]
+ let pid = ret_c_int(syscall!(
+ __NR_clone,
+ c_int(c::SIGCHLD | c::CLONE_CHILD_SETTID),
+ zero(),
+ zero(),
+ &mut child_pid,
+ zero()
+ ))?;
+ #[cfg(any(
+ target_arch = "aarch64",
+ target_arch = "arm",
+ target_arch = "mips",
+ target_arch = "mips32r6",
+ target_arch = "mips64",
+ target_arch = "mips64r6",
+ target_arch = "powerpc",
+ target_arch = "powerpc64",
+ target_arch = "riscv64",
+ target_arch = "s390x",
+ target_arch = "x86"
+ ))]
+ let pid = ret_c_int(syscall!(
+ __NR_clone,
+ c_int(c::SIGCHLD | c::CLONE_CHILD_SETTID),
+ zero(),
+ zero(),
+ zero(),
+ &mut child_pid
+ ))?;
+
+ Ok(if let Some(pid) = Pid::from_raw(pid) {
+ Fork::ParentOf(pid)
+ } else {
+ Fork::Child(Pid::from_raw_unchecked(child_pid.assume_init()))
+ })
+}
+
+#[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 {
+ use super::*;
+ #[cfg(target_arch = "x86")]
+ use crate::backend::runtime::tls::UserDesc;
+
+ #[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,
+ zero(),
+ zero(),
+ zero()
+ ))
+ }
+
+ #[inline]
+ pub(crate) unsafe fn set_tid_address(data: *mut c::c_void) -> Pid {
+ let tid: i32 = ret_c_int_infallible(syscall_readonly!(__NR_set_tid_address, data));
+ Pid::from_raw_unchecked(tid)
+ }
+
+ #[inline]
+ pub(crate) fn exit_thread(code: c::c_int) -> ! {
+ unsafe { syscall_noreturn!(__NR_exit, c_int(code)) }
+ }
+}
+
+#[inline]
+pub(crate) unsafe fn kernel_sigaction(
+ signal: Signal,
+ new: Option<KernelSigaction>,
+) -> io::Result<KernelSigaction> {
+ let mut old = MaybeUninit::<KernelSigaction>::uninit();
+ let new = opt_ref(new.as_ref());
+ ret(syscall!(
+ __NR_rt_sigaction,
+ signal,
+ new,
+ &mut old,
+ size_of::<KernelSigSet, _>()
+ ))?;
+ Ok(old.assume_init())
+}
+
+#[inline]
+pub(crate) unsafe fn kernel_sigaltstack(new: Option<Stack>) -> io::Result<Stack> {
+ let mut old = MaybeUninit::<Stack>::uninit();
+ let new = opt_ref(new.as_ref());
+ ret(syscall!(__NR_sigaltstack, new, &mut old))?;
+ Ok(old.assume_init())
+}
+
+#[inline]
+pub(crate) unsafe fn tkill(tid: Pid, sig: Signal) -> io::Result<()> {
+ ret(syscall_readonly!(__NR_tkill, tid, sig))
+}
+
+#[inline]
+pub(crate) unsafe fn kernel_sigprocmask(
+ how: How,
+ new: Option<&KernelSigSet>,
+) -> io::Result<KernelSigSet> {
+ let mut old = MaybeUninit::<KernelSigSet>::uninit();
+ let new = opt_ref(new);
+ ret(syscall!(
+ __NR_rt_sigprocmask,
+ how,
+ new,
+ &mut old,
+ size_of::<KernelSigSet, _>()
+ ))?;
+ Ok(old.assume_init())
+}
+
+#[inline]
+pub(crate) fn kernel_sigpending() -> KernelSigSet {
+ let mut pending = MaybeUninit::<KernelSigSet>::uninit();
+ unsafe {
+ ret_infallible(syscall!(
+ __NR_rt_sigpending,
+ &mut pending,
+ size_of::<KernelSigSet, _>()
+ ));
+ pending.assume_init()
+ }
+}
+
+#[inline]
+pub(crate) fn kernel_sigsuspend(set: &KernelSigSet) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_rt_sigsuspend,
+ by_ref(set),
+ size_of::<KernelSigSet, _>()
+ ))
+ }
+}
+
+#[inline]
+pub(crate) unsafe fn kernel_sigwait(set: &KernelSigSet) -> io::Result<Signal> {
+ Ok(Signal::from_raw_unchecked(ret_c_int(syscall_readonly!(
+ __NR_rt_sigtimedwait,
+ by_ref(set),
+ zero(),
+ zero(),
+ size_of::<KernelSigSet, _>()
+ ))?))
+}
+
+#[inline]
+pub(crate) unsafe fn kernel_sigwaitinfo(set: &KernelSigSet) -> io::Result<Siginfo> {
+ let mut info = MaybeUninit::<Siginfo>::uninit();
+ let _signum = ret_c_int(syscall!(
+ __NR_rt_sigtimedwait,
+ by_ref(set),
+ &mut info,
+ zero(),
+ size_of::<KernelSigSet, _>()
+ ))?;
+ Ok(info.assume_init())
+}
+
+#[inline]
+pub(crate) unsafe fn kernel_sigtimedwait(
+ set: &KernelSigSet,
+ timeout: Option<&Timespec>,
+) -> io::Result<Siginfo> {
+ let mut info = MaybeUninit::<Siginfo>::uninit();
+
+ // `rt_sigtimedwait_time64` was introduced in Linux 5.1. The old
+ // `rt_sigtimedwait` syscall is not y2038-compatible on 32-bit
+ // architectures.
+ #[cfg(target_pointer_width = "32")]
+ {
+ // If we don't have Linux 5.1, and the timeout fits in a
+ // `__kernel_old_timespec`, use plain `rt_sigtimedwait`.
+ //
+ // We do this unconditionally, rather than trying
+ // `rt_sigtimedwait_time64` and falling back on `Errno::NOSYS`, because
+ // seccomp configurations will sometimes abort the process on syscalls
+ // they don't recognize.
+ #[cfg(not(feature = "linux_5_1"))]
+ {
+ // If we don't have a timeout, or if we can convert the timeout to
+ // a `__kernel_old_timespec`, the use `__NR_futex`.
+ fn convert(timeout: &Timespec) -> Option<__kernel_old_timespec> {
+ Some(__kernel_old_timespec {
+ tv_sec: timeout.tv_sec.try_into().ok()?,
+ tv_nsec: timeout.tv_nsec.try_into().ok()?,
+ })
+ }
+ let old_timeout = if let Some(timeout) = timeout {
+ match convert(timeout) {
+ // Could not convert timeout.
+ None => None,
+ // Could convert timeout. Ok!
+ Some(old_timeout) => Some(Some(old_timeout)),
+ }
+ } else {
+ // No timeout. Ok!
+ Some(None)
+ };
+ if let Some(old_timeout) = old_timeout {
+ return ret_c_int(syscall!(
+ __NR_rt_sigtimedwait,
+ by_ref(set),
+ &mut info,
+ opt_ref(old_timeout.as_ref()),
+ size_of::<KernelSigSet, _>()
+ ))
+ .map(|sig| {
+ debug_assert_eq!(
+ sig,
+ info.assume_init_ref()
+ .__bindgen_anon_1
+ .__bindgen_anon_1
+ .si_signo
+ );
+ info.assume_init()
+ });
+ }
+ }
+
+ ret_c_int(syscall!(
+ __NR_rt_sigtimedwait_time64,
+ by_ref(set),
+ &mut info,
+ opt_ref(timeout),
+ size_of::<KernelSigSet, _>()
+ ))
+ .map(|sig| {
+ debug_assert_eq!(
+ sig,
+ info.assume_init_ref()
+ .__bindgen_anon_1
+ .__bindgen_anon_1
+ .si_signo
+ );
+ info.assume_init()
+ })
+ }
+
+ #[cfg(target_pointer_width = "64")]
+ {
+ let _signum = ret_c_int(syscall!(
+ __NR_rt_sigtimedwait,
+ by_ref(set),
+ &mut info,
+ opt_ref(timeout),
+ size_of::<KernelSigSet, _>()
+ ))?;
+ Ok(info.assume_init())
+ }
+}
+
+#[inline]
+pub(crate) fn exit_group(code: c::c_int) -> ! {
+ unsafe { syscall_noreturn!(__NR_exit_group, c_int(code)) }
+}
+
+#[inline]
+pub(crate) unsafe fn kernel_brk(addr: *mut c::c_void) -> io::Result<*mut c_void> {
+ // This is non-`readonly`, to prevent loads from being reordered past it.
+ ret_void_star(syscall!(__NR_brk, addr))
+}
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 00000000..bc04a706
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/runtime/tls.rs
@@ -0,0 +1,7 @@
+//! TLS utilities.
+
+/// 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;
diff --git a/vendor/rustix/src/backend/linux_raw/shm/mod.rs b/vendor/rustix/src/backend/linux_raw/shm/mod.rs
new file mode 100644
index 00000000..1e0181a9
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/shm/mod.rs
@@ -0,0 +1,2 @@
+pub(crate) mod syscalls;
+pub(crate) mod types;
diff --git a/vendor/rustix/src/backend/linux_raw/shm/syscalls.rs b/vendor/rustix/src/backend/linux_raw/shm/syscalls.rs
new file mode 100644
index 00000000..77b96d9e
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/shm/syscalls.rs
@@ -0,0 +1,46 @@
+use crate::ffi::CStr;
+
+use crate::backend::fs::syscalls::{open, unlink};
+use crate::backend::fs::types::{Mode, OFlags};
+use crate::fd::OwnedFd;
+use crate::{io, shm};
+
+const NAME_MAX: usize = 255;
+const SHM_DIR: &[u8] = b"/dev/shm/";
+
+fn get_shm_name(name: &CStr) -> io::Result<([u8; NAME_MAX + SHM_DIR.len() + 1], usize)> {
+ let name = name.to_bytes();
+
+ if name.len() > NAME_MAX {
+ return Err(io::Errno::NAMETOOLONG);
+ }
+
+ let num_slashes = name.iter().take_while(|x| **x == b'/').count();
+ let after_slashes = &name[num_slashes..];
+ if after_slashes.is_empty()
+ || after_slashes == b"."
+ || after_slashes == b".."
+ || after_slashes.contains(&b'/')
+ {
+ return Err(io::Errno::INVAL);
+ }
+
+ let mut path = [0; NAME_MAX + SHM_DIR.len() + 1];
+ path[..SHM_DIR.len()].copy_from_slice(SHM_DIR);
+ path[SHM_DIR.len()..SHM_DIR.len() + name.len()].copy_from_slice(name);
+ Ok((path, SHM_DIR.len() + name.len() + 1))
+}
+
+pub(crate) fn shm_open(name: &CStr, oflags: shm::OFlags, mode: Mode) -> io::Result<OwnedFd> {
+ let (path, len) = get_shm_name(name)?;
+ open(
+ CStr::from_bytes_with_nul(&path[..len]).unwrap(),
+ OFlags::from_bits(oflags.bits()).unwrap() | OFlags::CLOEXEC,
+ mode,
+ )
+}
+
+pub(crate) fn shm_unlink(name: &CStr) -> io::Result<()> {
+ let (path, len) = get_shm_name(name)?;
+ unlink(CStr::from_bytes_with_nul(&path[..len]).unwrap())
+}
diff --git a/vendor/rustix/src/backend/linux_raw/shm/types.rs b/vendor/rustix/src/backend/linux_raw/shm/types.rs
new file mode 100644
index 00000000..e1e8fc02
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/shm/types.rs
@@ -0,0 +1,30 @@
+use crate::ffi;
+use bitflags::bitflags;
+
+bitflags! {
+ /// `O_*` constants for use with [`shm::open`].
+ ///
+ /// [`shm::open`]: crate:shm::open
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct ShmOFlags: ffi::c_uint {
+ /// `O_CREAT`
+ #[doc(alias = "CREAT")]
+ const CREATE = linux_raw_sys::general::O_CREAT;
+
+ /// `O_EXCL`
+ const EXCL = linux_raw_sys::general::O_EXCL;
+
+ /// `O_RDONLY`
+ const RDONLY = linux_raw_sys::general::O_RDONLY;
+
+ /// `O_RDWR`
+ const RDWR = linux_raw_sys::general::O_RDWR;
+
+ /// `O_TRUNC`
+ const TRUNC = linux_raw_sys::general::O_TRUNC;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
diff --git a/vendor/rustix/src/backend/linux_raw/system/mod.rs b/vendor/rustix/src/backend/linux_raw/system/mod.rs
new file mode 100644
index 00000000..1e0181a9
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/system/mod.rs
@@ -0,0 +1,2 @@
+pub(crate) mod syscalls;
+pub(crate) mod types;
diff --git a/vendor/rustix/src/backend/linux_raw/system/syscalls.rs b/vendor/rustix/src/backend/linux_raw/system/syscalls.rs
new file mode 100644
index 00000000..bbee2680
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/system/syscalls.rs
@@ -0,0 +1,91 @@
+//! linux_raw syscalls supporting `rustix::system`.
+//!
+//! # Safety
+//!
+//! See the `rustix::backend` module documentation for details.
+#![allow(unsafe_code, clippy::undocumented_unsafe_blocks)]
+
+use super::types::RawUname;
+use crate::backend::c;
+use crate::backend::conv::{c_int, ret, ret_infallible, slice};
+use crate::fd::BorrowedFd;
+use crate::ffi::CStr;
+use crate::io;
+use crate::system::{RebootCommand, Sysinfo};
+use core::mem::MaybeUninit;
+
+#[inline]
+pub(crate) fn uname() -> RawUname {
+ let mut uname = MaybeUninit::<RawUname>::uninit();
+ unsafe {
+ ret_infallible(syscall!(__NR_uname, &mut uname));
+ uname.assume_init()
+ }
+}
+
+#[inline]
+pub(crate) fn sysinfo() -> Sysinfo {
+ let mut info = MaybeUninit::<Sysinfo>::uninit();
+ unsafe {
+ ret_infallible(syscall!(__NR_sysinfo, &mut info));
+ info.assume_init()
+ }
+}
+
+#[inline]
+pub(crate) fn sethostname(name: &[u8]) -> io::Result<()> {
+ let (ptr, len) = slice(name);
+ unsafe { ret(syscall_readonly!(__NR_sethostname, ptr, len)) }
+}
+
+#[inline]
+pub(crate) fn setdomainname(name: &[u8]) -> io::Result<()> {
+ let (ptr, len) = slice(name);
+ unsafe { ret(syscall_readonly!(__NR_setdomainname, ptr, len)) }
+}
+
+#[inline]
+pub(crate) fn reboot(cmd: RebootCommand) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_reboot,
+ c_int(c::LINUX_REBOOT_MAGIC1),
+ c_int(c::LINUX_REBOOT_MAGIC2),
+ c_int(cmd as i32)
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn init_module(image: &[u8], param_values: &CStr) -> io::Result<()> {
+ let (image, len) = slice(image);
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_init_module,
+ image,
+ len,
+ param_values
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn finit_module(
+ fd: BorrowedFd<'_>,
+ param_values: &CStr,
+ flags: c::c_int,
+) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_finit_module,
+ fd,
+ param_values,
+ c_int(flags)
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn delete_module(name: &CStr, flags: c::c_int) -> io::Result<()> {
+ unsafe { ret(syscall_readonly!(__NR_delete_module, name, c_int(flags))) }
+}
diff --git a/vendor/rustix/src/backend/linux_raw/system/types.rs b/vendor/rustix/src/backend/linux_raw/system/types.rs
new file mode 100644
index 00000000..92cc5278
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/system/types.rs
@@ -0,0 +1,39 @@
+use crate::ffi;
+use core::mem::size_of;
+
+/// `sysinfo`
+#[non_exhaustive]
+#[repr(C)]
+pub struct Sysinfo {
+ /// Seconds since boot
+ pub uptime: ffi::c_long,
+ /// 1, 5, and 15 minute load averages
+ pub loads: [ffi::c_ulong; 3],
+ /// Total usable main memory size
+ pub totalram: ffi::c_ulong,
+ /// Available memory size
+ pub freeram: ffi::c_ulong,
+ /// Amount of shared memory
+ pub sharedram: ffi::c_ulong,
+ /// Memory used by buffers
+ pub bufferram: ffi::c_ulong,
+ /// Total swap space size
+ pub totalswap: ffi::c_ulong,
+ /// Swap space still available
+ pub freeswap: ffi::c_ulong,
+ /// Number of current processes
+ pub procs: ffi::c_ushort,
+
+ pub(crate) pad: ffi::c_ushort,
+
+ /// Total high memory size
+ pub totalhigh: ffi::c_ulong,
+ /// Available high memory size
+ pub freehigh: ffi::c_ulong,
+ /// Memory unit size in bytes
+ pub mem_unit: ffi::c_uint,
+
+ pub(crate) f: [u8; 20 - 2 * size_of::<ffi::c_long>() - size_of::<ffi::c_int>()],
+}
+
+pub(crate) type RawUname = linux_raw_sys::system::new_utsname;
diff --git a/vendor/rustix/src/backend/linux_raw/termios/mod.rs b/vendor/rustix/src/backend/linux_raw/termios/mod.rs
new file mode 100644
index 00000000..1e0181a9
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/termios/mod.rs
@@ -0,0 +1,2 @@
+pub(crate) mod syscalls;
+pub(crate) mod types;
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 00000000..07c3a3d9
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/termios/syscalls.rs
@@ -0,0 +1,425 @@
+//! linux_raw syscalls supporting `rustix::termios`.
+//!
+//! # Safety
+//!
+//! See the `rustix::backend` module documentation for details.
+#![allow(unsafe_code, clippy::undocumented_unsafe_blocks)]
+
+use crate::backend::c;
+use crate::backend::conv::{by_ref, c_uint, ret};
+use crate::fd::BorrowedFd;
+#[cfg(feature = "alloc")]
+use crate::ffi::CStr;
+use crate::io;
+use crate::pid::Pid;
+use crate::termios::{
+ speed, Action, ControlModes, InputModes, LocalModes, OptionalActions, OutputModes,
+ QueueSelector, SpecialCodeIndex, Termios, Winsize,
+};
+#[cfg(feature = "alloc")]
+#[cfg(feature = "fs")]
+use crate::{fs::FileType, path::DecInt};
+use core::mem::MaybeUninit;
+
+#[inline]
+pub(crate) fn tcgetwinsize(fd: BorrowedFd<'_>) -> io::Result<Winsize> {
+ unsafe {
+ let mut result = MaybeUninit::<Winsize>::uninit();
+ ret(syscall!(__NR_ioctl, fd, c_uint(c::TIOCGWINSZ), &mut result))?;
+ Ok(result.assume_init())
+ }
+}
+
+#[inline]
+pub(crate) fn tcgetattr(fd: BorrowedFd<'_>) -> io::Result<Termios> {
+ let mut result = MaybeUninit::<Termios>::uninit();
+
+ // SAFETY: This invokes the `TCGETS2` ioctl, which initializes the full
+ // `Termios` structure.
+ unsafe {
+ match ret(syscall!(__NR_ioctl, fd, c_uint(c::TCGETS2), &mut result)) {
+ Ok(()) => Ok(result.assume_init()),
+
+ // A `NOTTY` or `ACCESS` might mean the OS doesn't support
+ // `TCGETS2`, for example a seccomp environment or WSL that only
+ // knows about `TCGETS`. Fall back to the old `TCGETS`.
+ #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))]
+ Err(io::Errno::NOTTY) | Err(io::Errno::ACCESS) => tcgetattr_fallback(fd),
+
+ Err(err) => Err(err),
+ }
+ }
+}
+
+/// Implement `tcgetattr` using the old `TCGETS` ioctl.
+#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))]
+#[cold]
+fn tcgetattr_fallback(fd: BorrowedFd<'_>) -> io::Result<Termios> {
+ use core::ptr::{addr_of, addr_of_mut};
+
+ let mut result = MaybeUninit::<Termios>::uninit();
+
+ // SAFETY: This invokes the `TCGETS` ioctl which initializes the `Termios`
+ // structure except for the `input_speed` and `output_speed` fields, which
+ // we manually initialize before forming a reference to the full `Termios`.
+ unsafe {
+ // Do the old `TCGETS` call.
+ ret(syscall!(__NR_ioctl, fd, c_uint(c::TCGETS), &mut result))?;
+
+ // Read the `control_modes` field without forming a reference to the
+ // `Termios` because it isn't fully initialized yet.
+ let ptr = result.as_mut_ptr();
+ let control_modes = addr_of!((*ptr).control_modes).read();
+
+ // Infer the output speed and set `output_speed`.
+ let encoded_out = control_modes.bits() & c::CBAUD;
+ let output_speed = match speed::decode(encoded_out) {
+ Some(output_speed) => output_speed,
+ None => return Err(io::Errno::RANGE),
+ };
+ addr_of_mut!((*ptr).output_speed).write(output_speed);
+
+ // Infer the input speed and set `input_speed`. `B0` is a special-case
+ // that means the input speed is the same as the output speed.
+ let encoded_in = (control_modes.bits() & c::CIBAUD) >> c::IBSHIFT;
+ let input_speed = if encoded_in == c::B0 {
+ output_speed
+ } else {
+ match speed::decode(encoded_in) {
+ Some(input_speed) => input_speed,
+ None => return Err(io::Errno::RANGE),
+ }
+ };
+ addr_of_mut!((*ptr).input_speed).write(input_speed);
+
+ // Now all the fields are set.
+ Ok(result.assume_init())
+ }
+}
+
+#[inline]
+pub(crate) fn tcgetpgrp(fd: BorrowedFd<'_>) -> io::Result<Pid> {
+ unsafe {
+ let mut result = MaybeUninit::<c::pid_t>::uninit();
+ ret(syscall!(__NR_ioctl, fd, c_uint(c::TIOCGPGRP), &mut result))?;
+ let pid = result.assume_init();
+
+ // This doesn't appear to be documented, but it appears `tcsetpgrp` can
+ // succeed and set the pid to 0 if we pass it a pseudo-terminal device
+ // fd. For now, fail with `OPNOTSUPP`.
+ if pid == 0 {
+ return Err(io::Errno::OPNOTSUPP);
+ }
+
+ Ok(Pid::from_raw_unchecked(pid))
+ }
+}
+
+#[inline]
+pub(crate) fn tcsetattr(
+ fd: BorrowedFd<'_>,
+ optional_actions: OptionalActions,
+ termios: &Termios,
+) -> io::Result<()> {
+ // Translate from `optional_actions` into a `TCSETS2` ioctl request code.
+ // On MIPS, `optional_actions` has `TCSETS` added to it.
+ let request = c::TCSETS2
+ + if cfg!(any(
+ target_arch = "mips",
+ target_arch = "mips32r6",
+ target_arch = "mips64",
+ target_arch = "mips64r6"
+ )) {
+ optional_actions as u32 - c::TCSETS
+ } else {
+ optional_actions as u32
+ };
+
+ // SAFETY: This invokes the `TCSETS2` ioctl.
+ unsafe {
+ match ret(syscall_readonly!(
+ __NR_ioctl,
+ fd,
+ c_uint(request),
+ by_ref(termios)
+ )) {
+ Ok(()) => Ok(()),
+
+ // Similar to `tcgetattr_fallback`, `NOTTY` or `ACCESS` might mean
+ // the OS doesn't support `TCSETS2`. Fall back to the old `TCSETS`.
+ #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))]
+ Err(io::Errno::NOTTY) | Err(io::Errno::ACCESS) => {
+ tcsetattr_fallback(fd, optional_actions, termios)
+ }
+
+ Err(err) => Err(err),
+ }
+ }
+}
+
+/// Implement `tcsetattr` using the old `TCSETS` ioctl.
+#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))]
+#[cold]
+fn tcsetattr_fallback(
+ fd: BorrowedFd<'_>,
+ optional_actions: OptionalActions,
+ termios: &Termios,
+) -> io::Result<()> {
+ // `TCSETS` silently accepts `BOTHER` in `c_cflag` even though it doesn't
+ // read `c_ispeed`/`c_ospeed`, so detect this case and fail if needed.
+ let control_modes_bits = termios.control_modes.bits();
+ let encoded_out = control_modes_bits & c::CBAUD;
+ let encoded_in = (control_modes_bits & c::CIBAUD) >> c::IBSHIFT;
+ if encoded_out == c::BOTHER || encoded_in == c::BOTHER {
+ return Err(io::Errno::RANGE);
+ }
+
+ // Translate from `optional_actions` into a `TCSETS` ioctl request code. On
+ // MIPS, `optional_actions` already has `TCSETS` added to it.
+ let request = if cfg!(any(
+ target_arch = "mips",
+ target_arch = "mips32r6",
+ target_arch = "mips64",
+ target_arch = "mips64r6"
+ )) {
+ optional_actions as u32
+ } else {
+ optional_actions as u32 + c::TCSETS
+ };
+
+ // SAFETY: This invokes the `TCSETS` ioctl.
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_ioctl,
+ fd,
+ c_uint(request),
+ by_ref(termios)
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn tcsendbreak(fd: BorrowedFd<'_>) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_ioctl,
+ fd,
+ c_uint(c::TCSBRK),
+ c_uint(0)
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn tcdrain(fd: BorrowedFd<'_>) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_ioctl,
+ fd,
+ c_uint(c::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(c::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(c::TCXONC),
+ c_uint(action as u32)
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn tcgetsid(fd: BorrowedFd<'_>) -> io::Result<Pid> {
+ unsafe {
+ let mut result = MaybeUninit::<c::pid_t>::uninit();
+ ret(syscall!(__NR_ioctl, fd, c_uint(c::TIOCGSID), &mut result))?;
+ let pid = result.assume_init();
+ Ok(Pid::from_raw_unchecked(pid))
+ }
+}
+
+#[inline]
+pub(crate) fn tcsetwinsize(fd: BorrowedFd<'_>, winsize: Winsize) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_ioctl,
+ fd,
+ c_uint(c::TIOCSWINSZ),
+ by_ref(&winsize)
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn tcsetpgrp(fd: BorrowedFd<'_>, pid: Pid) -> io::Result<()> {
+ let raw_pid: c::c_int = pid.as_raw_nonzero().get();
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_ioctl,
+ fd,
+ c_uint(c::TIOCSPGRP),
+ by_ref(&raw_pid)
+ ))
+ }
+}
+
+/// A wrapper around a conceptual `cfsetspeed` which handles an arbitrary
+/// integer speed value.
+#[inline]
+pub(crate) fn set_speed(termios: &mut Termios, arbitrary_speed: u32) -> io::Result<()> {
+ let encoded_speed = speed::encode(arbitrary_speed).unwrap_or(c::BOTHER);
+
+ debug_assert_eq!(encoded_speed & !c::CBAUD, 0);
+
+ termios.control_modes -= ControlModes::from_bits_retain(c::CBAUD | c::CIBAUD);
+ termios.control_modes |=
+ ControlModes::from_bits_retain(encoded_speed | (encoded_speed << c::IBSHIFT));
+
+ termios.input_speed = arbitrary_speed;
+ termios.output_speed = arbitrary_speed;
+
+ Ok(())
+}
+
+/// A wrapper around a conceptual `cfsetospeed` which handles an arbitrary
+/// integer speed value.
+#[inline]
+pub(crate) fn set_output_speed(termios: &mut Termios, arbitrary_speed: u32) -> io::Result<()> {
+ let encoded_speed = speed::encode(arbitrary_speed).unwrap_or(c::BOTHER);
+
+ debug_assert_eq!(encoded_speed & !c::CBAUD, 0);
+
+ termios.control_modes -= ControlModes::from_bits_retain(c::CBAUD);
+ termios.control_modes |= ControlModes::from_bits_retain(encoded_speed);
+
+ termios.output_speed = arbitrary_speed;
+
+ Ok(())
+}
+
+/// A wrapper around a conceptual `cfsetispeed` which handles an arbitrary
+/// integer speed value.
+#[inline]
+pub(crate) fn set_input_speed(termios: &mut Termios, arbitrary_speed: u32) -> io::Result<()> {
+ let encoded_speed = speed::encode(arbitrary_speed).unwrap_or(c::BOTHER);
+
+ debug_assert_eq!(encoded_speed & !c::CBAUD, 0);
+
+ termios.control_modes -= ControlModes::from_bits_retain(c::CIBAUD);
+ termios.control_modes |= ControlModes::from_bits_retain(encoded_speed << c::IBSHIFT);
+
+ termios.input_speed = arbitrary_speed;
+
+ Ok(())
+}
+
+#[inline]
+pub(crate) fn cfmakeraw(termios: &mut Termios) {
+ // From the Linux [`cfmakeraw` manual page]:
+ //
+ // [`cfmakeraw` manual page]: https://man7.org/linux/man-pages/man3/cfmakeraw.3.html
+ termios.input_modes -= InputModes::IGNBRK
+ | InputModes::BRKINT
+ | InputModes::PARMRK
+ | InputModes::ISTRIP
+ | InputModes::INLCR
+ | InputModes::IGNCR
+ | InputModes::ICRNL
+ | InputModes::IXON;
+ termios.output_modes -= OutputModes::OPOST;
+ termios.local_modes -= LocalModes::ECHO
+ | LocalModes::ECHONL
+ | LocalModes::ICANON
+ | LocalModes::ISIG
+ | LocalModes::IEXTEN;
+ termios.control_modes -= ControlModes::CSIZE | ControlModes::PARENB;
+ termios.control_modes |= ControlModes::CS8;
+
+ // Musl and glibc also do these:
+ termios.special_codes[SpecialCodeIndex::VMIN] = 1;
+ termios.special_codes[SpecialCodeIndex::VTIME] = 0;
+}
+
+#[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 = "alloc")]
+#[cfg(feature = "fs")]
+pub(crate) fn ttyname(fd: BorrowedFd<'_>, buf: &mut [MaybeUninit<u8>]) -> io::Result<usize> {
+ let fd_stat = crate::backend::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(io::Errno::NOTTY);
+ }
+
+ // Check that `fd` is really a tty.
+ tcgetwinsize(fd)?;
+
+ // Create the "/proc/self/fd/<fd>" string.
+ let mut proc_self_fd_buf: [u8; 25] = *b"/proc/self/fd/\0\0\0\0\0\0\0\0\0\0\0";
+ let dec_int = DecInt::from_fd(fd);
+ let bytes_with_nul = dec_int.as_bytes_with_nul();
+ proc_self_fd_buf[b"/proc/self/fd/".len()..][..bytes_with_nul.len()]
+ .copy_from_slice(bytes_with_nul);
+
+ // SAFETY: We just wrote a valid C String.
+ let proc_self_fd_path = unsafe { CStr::from_ptr(proc_self_fd_buf.as_ptr().cast()) };
+
+ let ptr = buf.as_mut_ptr();
+ let len = {
+ // Gather the ttyname by reading the "fd" file inside `proc_self_fd`.
+ let (init, uninit) = crate::fs::readlinkat_raw(crate::fs::CWD, proc_self_fd_path, 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 uninit.is_empty() {
+ return Err(io::Errno::RANGE);
+ }
+
+ // `readlinkat` returns the number of bytes placed in the buffer.
+ // NUL-terminate the string at that offset.
+ uninit[0].write(b'\0');
+
+ init.len()
+ };
+
+ // Check that the path we read refers to the same file as `fd`.
+ {
+ // SAFETY: We just wrote the NUL byte above.
+ let path = unsafe { CStr::from_ptr(ptr.cast()) };
+
+ let path_stat = crate::backend::fs::syscalls::stat(path)?;
+ if path_stat.st_dev != fd_stat.st_dev || path_stat.st_ino != fd_stat.st_ino {
+ return Err(io::Errno::NODEV);
+ }
+ }
+
+ // Return the length, excluding the NUL terminator.
+ Ok(len)
+}
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 00000000..a8aaee39
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/termios/types.rs
@@ -0,0 +1,13 @@
+//! Types for the `termios` module.
+
+#![allow(non_camel_case_types)]
+
+use crate::ffi;
+
+// We don't want to use `tcflag_t` directly so we don't expose linux_raw_sys
+// publicly. It appears to be `c_ulong `on SPARC and `c_uint` everywhere else.
+
+#[cfg(target_arch = "sparc")]
+pub type tcflag_t = ffi::c_ulong;
+#[cfg(not(target_arch = "sparc"))]
+pub type tcflag_t = ffi::c_uint;
diff --git a/vendor/rustix/src/backend/linux_raw/thread/cpu_set.rs b/vendor/rustix/src/backend/linux_raw/thread/cpu_set.rs
new file mode 100644
index 00000000..8c39d57c
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/thread/cpu_set.rs
@@ -0,0 +1,51 @@
+//! Rust implementation of the `CPU_*` macro API.
+
+#![allow(non_snake_case)]
+
+use super::types::RawCpuSet;
+use core::mem::{size_of, size_of_val};
+
+#[inline]
+pub(crate) fn CPU_SET(cpu: usize, cpuset: &mut RawCpuSet) {
+ let size_in_bits = 8 * size_of_val(&cpuset.bits[0]); // 32, 64 etc
+ let (idx, offset) = (cpu / size_in_bits, cpu % size_in_bits);
+ cpuset.bits[idx] |= 1 << offset
+}
+
+#[inline]
+pub(crate) fn CPU_ZERO(cpuset: &mut RawCpuSet) {
+ cpuset.bits.fill(0)
+}
+
+#[inline]
+pub(crate) fn CPU_CLR(cpu: usize, cpuset: &mut RawCpuSet) {
+ let size_in_bits = 8 * size_of_val(&cpuset.bits[0]); // 32, 64 etc
+ let (idx, offset) = (cpu / size_in_bits, cpu % size_in_bits);
+ cpuset.bits[idx] &= !(1 << offset)
+}
+
+#[inline]
+pub(crate) fn CPU_ISSET(cpu: usize, cpuset: &RawCpuSet) -> bool {
+ let size_in_bits = 8 * size_of_val(&cpuset.bits[0]);
+ let (idx, offset) = (cpu / size_in_bits, cpu % size_in_bits);
+ (cpuset.bits[idx] & (1 << offset)) != 0
+}
+
+#[inline]
+pub(crate) fn CPU_COUNT_S(size_in_bytes: usize, cpuset: &RawCpuSet) -> u32 {
+ let size_of_mask = size_of_val(&cpuset.bits[0]);
+ let idx = size_in_bytes / size_of_mask;
+ cpuset.bits[..idx]
+ .iter()
+ .fold(0, |acc, i| acc + i.count_ones())
+}
+
+#[inline]
+pub(crate) fn CPU_COUNT(cpuset: &RawCpuSet) -> u32 {
+ CPU_COUNT_S(size_of::<RawCpuSet>(), cpuset)
+}
+
+#[inline]
+pub(crate) fn CPU_EQUAL(this: &RawCpuSet, that: &RawCpuSet) -> bool {
+ this.bits == that.bits
+}
diff --git a/vendor/rustix/src/backend/linux_raw/thread/futex.rs b/vendor/rustix/src/backend/linux_raw/thread/futex.rs
new file mode 100644
index 00000000..726cea11
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/thread/futex.rs
@@ -0,0 +1,89 @@
+bitflags::bitflags! {
+ /// `FUTEX_*` flags for use with the functions in [`futex`].
+ ///
+ /// [`futex`]: mod@crate::thread::futex
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct Flags: u32 {
+ /// `FUTEX_PRIVATE_FLAG`
+ const PRIVATE = linux_raw_sys::general::FUTEX_PRIVATE_FLAG;
+ /// `FUTEX_CLOCK_REALTIME`
+ const CLOCK_REALTIME = linux_raw_sys::general::FUTEX_CLOCK_REALTIME;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+bitflags::bitflags! {
+ /// `FUTEX2_*` flags for use with the functions in [`Waitv`].
+ ///
+ /// Not to be confused with [`WaitvFlags`], which is passed as an argument
+ /// to the `waitv` function.
+ ///
+ /// [`Waitv`]: crate::thread::futex::Waitv
+ /// [`WaitvFlags`]: crate::thread::futex::WaitvFlags
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct WaitFlags: u32 {
+ /// `FUTEX_U8`
+ const SIZE_U8 = linux_raw_sys::general::FUTEX2_SIZE_U8;
+ /// `FUTEX_U16`
+ const SIZE_U16 = linux_raw_sys::general::FUTEX2_SIZE_U16;
+ /// `FUTEX_U32`
+ const SIZE_U32 = linux_raw_sys::general::FUTEX2_SIZE_U32;
+ /// `FUTEX_U64`
+ const SIZE_U64 = linux_raw_sys::general::FUTEX2_SIZE_U64;
+ /// `FUTEX_SIZE_MASK`
+ const SIZE_MASK = linux_raw_sys::general::FUTEX2_SIZE_MASK;
+
+ /// `FUTEX2_NUMA`
+ const NUMA = linux_raw_sys::general::FUTEX2_NUMA;
+
+ /// `FUTEX2_PRIVATE`
+ const PRIVATE = linux_raw_sys::general::FUTEX2_PRIVATE;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+/// `FUTEX_*` operations for use with the futex syscall wrappers.
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+#[repr(u32)]
+pub(crate) enum Operation {
+ /// `FUTEX_WAIT`
+ Wait = linux_raw_sys::general::FUTEX_WAIT,
+ /// `FUTEX_WAKE`
+ Wake = linux_raw_sys::general::FUTEX_WAKE,
+ /// `FUTEX_FD`
+ Fd = linux_raw_sys::general::FUTEX_FD,
+ /// `FUTEX_REQUEUE`
+ Requeue = linux_raw_sys::general::FUTEX_REQUEUE,
+ /// `FUTEX_CMP_REQUEUE`
+ CmpRequeue = linux_raw_sys::general::FUTEX_CMP_REQUEUE,
+ /// `FUTEX_WAKE_OP`
+ WakeOp = linux_raw_sys::general::FUTEX_WAKE_OP,
+ /// `FUTEX_LOCK_PI`
+ LockPi = linux_raw_sys::general::FUTEX_LOCK_PI,
+ /// `FUTEX_UNLOCK_PI`
+ UnlockPi = linux_raw_sys::general::FUTEX_UNLOCK_PI,
+ /// `FUTEX_TRYLOCK_PI`
+ TrylockPi = linux_raw_sys::general::FUTEX_TRYLOCK_PI,
+ /// `FUTEX_WAIT_BITSET`
+ WaitBitset = linux_raw_sys::general::FUTEX_WAIT_BITSET,
+ /// `FUTEX_WAKE_BITSET`
+ WakeBitset = linux_raw_sys::general::FUTEX_WAKE_BITSET,
+ /// `FUTEX_WAIT_REQUEUE_PI`
+ WaitRequeuePi = linux_raw_sys::general::FUTEX_WAIT_REQUEUE_PI,
+ /// `FUTEX_CMP_REQUEUE_PI`
+ CmpRequeuePi = linux_raw_sys::general::FUTEX_CMP_REQUEUE_PI,
+ /// `FUTEX_LOCK_PI2`
+ LockPi2 = linux_raw_sys::general::FUTEX_LOCK_PI2,
+}
+
+/// `FUTEX_WAITERS`
+pub const WAITERS: u32 = linux_raw_sys::general::FUTEX_WAITERS;
+
+/// `FUTEX_OWNER_DIED`
+pub const OWNER_DIED: u32 = linux_raw_sys::general::FUTEX_OWNER_DIED;
diff --git a/vendor/rustix/src/backend/linux_raw/thread/mod.rs b/vendor/rustix/src/backend/linux_raw/thread/mod.rs
new file mode 100644
index 00000000..c1843edd
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/thread/mod.rs
@@ -0,0 +1,4 @@
+pub(crate) mod cpu_set;
+pub(crate) mod futex;
+pub(crate) mod syscalls;
+pub(crate) mod types;
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 00000000..352e0615
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/thread/syscalls.rs
@@ -0,0 +1,549 @@
+//! linux_raw syscalls supporting `rustix::thread`.
+//!
+//! # Safety
+//!
+//! See the `rustix::backend` module documentation for details.
+#![allow(unsafe_code, clippy::undocumented_unsafe_blocks)]
+
+use super::types::RawCpuSet;
+use crate::backend::c;
+use crate::backend::conv::{
+ by_mut, by_ref, c_int, c_uint, opt_ref, ret, ret_c_int, ret_c_int_infallible, ret_c_uint,
+ ret_usize, size_of, slice, slice_just_addr, slice_just_addr_mut, zero,
+};
+use crate::fd::BorrowedFd;
+use crate::io;
+use crate::pid::Pid;
+use crate::thread::{
+ futex, ClockId, Cpuid, MembarrierCommand, MembarrierQuery, NanosleepRelativeResult, Timespec,
+};
+use crate::utils::as_mut_ptr;
+use core::mem::MaybeUninit;
+use core::sync::atomic::AtomicU32;
+#[cfg(target_pointer_width = "32")]
+use linux_raw_sys::general::timespec as __kernel_old_timespec;
+use linux_raw_sys::general::{membarrier_cmd, membarrier_cmd_flag, TIMER_ABSTIME};
+
+#[inline]
+pub(crate) fn clock_nanosleep_relative(id: ClockId, req: &Timespec) -> NanosleepRelativeResult {
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ let mut rem = MaybeUninit::<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 `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::<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: &Timespec,
+ rem: &mut MaybeUninit<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();
+ rem.write(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: &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 `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: &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: &Timespec) -> NanosleepRelativeResult {
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ let mut rem = MaybeUninit::<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 `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::<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: &Timespec, rem: &mut MaybeUninit<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();
+ rem.write(Timespec {
+ tv_sec: old_rem.tv_sec.into(),
+ tv_nsec: old_rem.tv_nsec.into(),
+ });
+ Ok(())
+}
+
+#[inline]
+#[must_use]
+pub(crate) fn gettid() -> Pid {
+ unsafe {
+ let tid = ret_c_int_infallible(syscall_readonly!(__NR_gettid));
+ Pid::from_raw_unchecked(tid)
+ }
+}
+
+/// # Safety
+///
+/// The raw pointers must point to valid aligned memory.
+#[inline]
+pub(crate) unsafe fn futex_val2(
+ uaddr: *const AtomicU32,
+ op: super::futex::Operation,
+ flags: futex::Flags,
+ val: u32,
+ val2: u32,
+ uaddr2: *const AtomicU32,
+ val3: u32,
+) -> io::Result<usize> {
+ // Pass `val2` in the least-significant bytes of the `timeout` argument.
+ // [“the kernel casts the timeout value first to unsigned long, then to
+ // uint32_t”], so we perform that exact conversion in reverse to create
+ // the pointer.
+ //
+ // [“the kernel casts the timeout value first to unsigned long, then to uint32_t”]: https://man7.org/linux/man-pages/man2/futex.2.html
+ let timeout = val2 as usize as *const Timespec;
+
+ #[cfg(target_pointer_width = "32")]
+ {
+ // Linux 5.1 added `futex_time64`; if we have that, use it. We don't
+ // need it here, because `timeout` is just passing `val2` and not a
+ // real timeout, but it's nice to use `futex_time64` for consistency
+ // with the other futex calls that do.
+ #[cfg(feature = "linux_5_1")]
+ {
+ ret_usize(syscall!(
+ __NR_futex_time64,
+ uaddr,
+ (op, flags),
+ c_uint(val),
+ timeout,
+ uaddr2,
+ c_uint(val3)
+ ))
+ }
+
+ // If we don't have Linux 5.1, use plain `futex`.
+ #[cfg(not(feature = "linux_5_1"))]
+ {
+ ret_usize(syscall!(
+ __NR_futex,
+ uaddr,
+ (op, flags),
+ c_uint(val),
+ timeout,
+ uaddr2,
+ c_uint(val3)
+ ))
+ }
+ }
+ #[cfg(target_pointer_width = "64")]
+ ret_usize(syscall!(
+ __NR_futex,
+ uaddr,
+ (op, flags),
+ c_uint(val),
+ timeout,
+ uaddr2,
+ c_uint(val3)
+ ))
+}
+
+/// # Safety
+///
+/// The raw pointers must point to valid aligned memory.
+#[inline]
+pub(crate) unsafe fn futex_timeout(
+ uaddr: *const AtomicU32,
+ op: super::futex::Operation,
+ flags: futex::Flags,
+ val: u32,
+ timeout: Option<&Timespec>,
+ uaddr2: *const AtomicU32,
+ val3: u32,
+) -> io::Result<usize> {
+ #[cfg(target_pointer_width = "32")]
+ {
+ // If we don't have Linux 5.1, and the timeout fits in a
+ // `__kernel_old_timespec`, use plain `futex`.
+ //
+ // We do this unconditionally, rather than trying `futex_time64` and
+ // falling back on `Errno::NOSYS`, because seccomp configurations will
+ // sometimes abort the process on syscalls they don't recognize.
+ #[cfg(not(feature = "linux_5_1"))]
+ {
+ // If we don't have a timeout, or if we can convert the timeout to
+ // a `__kernel_old_timespec`, the use `__NR_futex`.
+ fn convert(timeout: &Timespec) -> Option<__kernel_old_timespec> {
+ Some(__kernel_old_timespec {
+ tv_sec: timeout.tv_sec.try_into().ok()?,
+ tv_nsec: timeout.tv_nsec.try_into().ok()?,
+ })
+ }
+ let old_timeout = if let Some(timeout) = timeout {
+ match convert(timeout) {
+ // Could not convert timeout.
+ None => None,
+ // Could convert timeout. Ok!
+ Some(old_timeout) => Some(Some(old_timeout)),
+ }
+ } else {
+ // No timeout. Ok!
+ Some(None)
+ };
+ if let Some(old_timeout) = old_timeout {
+ return ret_usize(syscall!(
+ __NR_futex,
+ uaddr,
+ (op, flags),
+ c_uint(val),
+ opt_ref(old_timeout.as_ref()),
+ uaddr2,
+ c_uint(val3)
+ ));
+ }
+ }
+
+ // We either have Linux 5.1 or the timeout didn't fit in
+ // `__kernel_old_timespec` so `__NR_futex_time64` will either succeed
+ // or fail due to our having no other options.
+ ret_usize(syscall!(
+ __NR_futex_time64,
+ uaddr,
+ (op, flags),
+ c_uint(val),
+ opt_ref(timeout),
+ uaddr2,
+ c_uint(val3)
+ ))
+ }
+ #[cfg(target_pointer_width = "64")]
+ ret_usize(syscall!(
+ __NR_futex,
+ uaddr,
+ (op, flags),
+ c_uint(val),
+ opt_ref(timeout),
+ uaddr2,
+ c_uint(val3)
+ ))
+}
+
+#[inline]
+pub(crate) fn futex_waitv(
+ waiters: &[futex::Wait],
+ flags: futex::WaitvFlags,
+ timeout: Option<&Timespec>,
+ clockid: ClockId,
+) -> io::Result<usize> {
+ let (waiters_addr, waiters_len) = slice(waiters);
+ unsafe {
+ ret_usize(syscall!(
+ __NR_futex_waitv,
+ waiters_addr,
+ waiters_len,
+ c_uint(flags.bits()),
+ opt_ref(timeout),
+ clockid
+ ))
+ }
+}
+
+#[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))) }
+}
+
+#[inline]
+pub(crate) fn unshare(flags: crate::thread::UnshareFlags) -> io::Result<()> {
+ unsafe { ret(syscall_readonly!(__NR_unshare, flags)) }
+}
+
+#[inline]
+pub(crate) fn capget(
+ header: &mut linux_raw_sys::general::__user_cap_header_struct,
+ data: &mut [MaybeUninit<linux_raw_sys::general::__user_cap_data_struct>],
+) -> io::Result<()> {
+ unsafe {
+ ret(syscall!(
+ __NR_capget,
+ by_mut(header),
+ slice_just_addr_mut(data)
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn capset(
+ header: &mut linux_raw_sys::general::__user_cap_header_struct,
+ data: &[linux_raw_sys::general::__user_cap_data_struct],
+) -> io::Result<()> {
+ unsafe { ret(syscall!(__NR_capset, by_mut(header), slice_just_addr(data))) }
+}
+
+#[inline]
+pub(crate) fn setuid_thread(uid: crate::ugid::Uid) -> io::Result<()> {
+ unsafe { ret(syscall_readonly!(__NR_setuid, uid)) }
+}
+
+#[inline]
+pub(crate) fn setresuid_thread(
+ ruid: crate::ugid::Uid,
+ euid: crate::ugid::Uid,
+ suid: crate::ugid::Uid,
+) -> io::Result<()> {
+ #[cfg(any(target_arch = "x86", target_arch = "arm", target_arch = "sparc"))]
+ unsafe {
+ ret(syscall_readonly!(__NR_setresuid32, ruid, euid, suid))
+ }
+ #[cfg(not(any(target_arch = "x86", target_arch = "arm", target_arch = "sparc")))]
+ unsafe {
+ ret(syscall_readonly!(__NR_setresuid, ruid, euid, suid))
+ }
+}
+
+#[inline]
+pub(crate) fn setgid_thread(gid: crate::ugid::Gid) -> io::Result<()> {
+ unsafe { ret(syscall_readonly!(__NR_setgid, gid)) }
+}
+
+#[inline]
+pub(crate) fn setresgid_thread(
+ rgid: crate::ugid::Gid,
+ egid: crate::ugid::Gid,
+ sgid: crate::ugid::Gid,
+) -> io::Result<()> {
+ #[cfg(any(target_arch = "x86", target_arch = "arm", target_arch = "sparc"))]
+ unsafe {
+ ret(syscall_readonly!(__NR_setresgid32, rgid, egid, sgid))
+ }
+ #[cfg(not(any(target_arch = "x86", target_arch = "arm", target_arch = "sparc")))]
+ unsafe {
+ ret(syscall_readonly!(__NR_setresgid, rgid, egid, sgid))
+ }
+}
+
+#[inline]
+pub(crate) fn setgroups_thread(gids: &[crate::ugid::Gid]) -> io::Result<()> {
+ let (addr, len) = slice(gids);
+ unsafe { ret(syscall_readonly!(__NR_setgroups, len, addr)) }
+}
+
+// `sched_getcpu` has special optimizations via the vDSO on some architectures.
+#[cfg(any(
+ target_arch = "x86_64",
+ target_arch = "x86",
+ target_arch = "riscv64",
+ target_arch = "powerpc",
+ target_arch = "powerpc64",
+ target_arch = "s390x"
+))]
+pub(crate) use crate::backend::vdso_wrappers::sched_getcpu;
+
+// `sched_getcpu` on platforms without a vDSO entry for it.
+#[cfg(not(any(
+ target_arch = "x86_64",
+ target_arch = "x86",
+ target_arch = "riscv64",
+ target_arch = "powerpc",
+ target_arch = "powerpc64",
+ target_arch = "s390x"
+)))]
+#[inline]
+pub(crate) fn sched_getcpu() -> usize {
+ let mut cpu = MaybeUninit::<u32>::uninit();
+ unsafe {
+ let r = ret(syscall!(__NR_getcpu, &mut cpu, zero(), zero()));
+ debug_assert!(r.is_ok());
+ cpu.assume_init() as usize
+ }
+}
+
+#[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_int(Pid::as_raw(pid)),
+ size_of::<RawCpuSet, _>(),
+ by_mut(&mut cpuset.bits)
+ ))?;
+ let bytes = as_mut_ptr(cpuset).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_int(Pid::as_raw(pid)),
+ size_of::<RawCpuSet, _>(),
+ slice_just_addr(&cpuset.bits)
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn sched_yield() {
+ unsafe {
+ // See the documentation for [`crate::thread::sched_yield`] for why
+ // errors are ignored.
+ syscall_readonly!(__NR_sched_yield).decode_void();
+ }
+}
+
+#[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) => MembarrierQuery::from_bits_retain(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
+ ))
+ }
+}
diff --git a/vendor/rustix/src/backend/linux_raw/thread/types.rs b/vendor/rustix/src/backend/linux_raw/thread/types.rs
new file mode 100644
index 00000000..be92235e
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/thread/types.rs
@@ -0,0 +1,62 @@
+use linux_raw_sys::general::membarrier_cmd;
+
+/// A command for use with [`membarrier`] and [`membarrier_cpu`].
+///
+/// For `MEMBARRIER_CMD_QUERY`, see [`membarrier_query`].
+///
+/// [`membarrier`]: crate::thread::membarrier
+/// [`membarrier_cpu`]: crate::thread::membarrier_cpu
+/// [`membarrier_query`]: crate::thread::membarrier_query
+#[derive(Copy, Clone, Eq, PartialEq, Debug)]
+#[repr(u32)]
+#[non_exhaustive]
+pub enum MembarrierCommand {
+ /// `MEMBARRIER_CMD_GLOBAL`
+ #[doc(alias = "Shared")]
+ #[doc(alias = "MEMBARRIER_CMD_SHARED")]
+ Global = membarrier_cmd::MEMBARRIER_CMD_GLOBAL as _,
+ /// `MEMBARRIER_CMD_GLOBAL_EXPEDITED`
+ GlobalExpedited = membarrier_cmd::MEMBARRIER_CMD_GLOBAL_EXPEDITED as _,
+ /// `MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED`
+ RegisterGlobalExpedited = membarrier_cmd::MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED as _,
+ /// `MEMBARRIER_CMD_PRIVATE_EXPEDITED`
+ PrivateExpedited = membarrier_cmd::MEMBARRIER_CMD_PRIVATE_EXPEDITED as _,
+ /// `MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED`
+ RegisterPrivateExpedited = membarrier_cmd::MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED as _,
+ /// `MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE`
+ PrivateExpeditedSyncCore = membarrier_cmd::MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE as _,
+ /// `MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE`
+ RegisterPrivateExpeditedSyncCore =
+ membarrier_cmd::MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE as _,
+ /// `MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ` (since Linux 5.10)
+ PrivateExpeditedRseq = membarrier_cmd::MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ as _,
+ /// `MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ` (since Linux 5.10)
+ RegisterPrivateExpeditedRseq =
+ membarrier_cmd::MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ as _,
+}
+
+/// A CPU identifier as a raw integer.
+pub type RawCpuid = u32;
+
+#[repr(transparent)]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+pub(crate) struct RawCpuSet {
+ #[cfg(all(target_pointer_width = "32", not(target_arch = "x86_64")))]
+ pub(crate) bits: [u32; 32],
+ #[cfg(not(all(target_pointer_width = "32", not(target_arch = "x86_64"))))]
+ pub(crate) bits: [u64; 16],
+}
+
+#[inline]
+pub(crate) fn raw_cpu_set_new() -> RawCpuSet {
+ #[cfg(all(target_pointer_width = "32", not(target_arch = "x86_64")))]
+ {
+ RawCpuSet { bits: [0; 32] }
+ }
+ #[cfg(not(all(target_pointer_width = "32", not(target_arch = "x86_64"))))]
+ {
+ RawCpuSet { bits: [0; 16] }
+ }
+}
+
+pub(crate) const CPU_SETSIZE: usize = 8 * core::mem::size_of::<RawCpuSet>();
diff --git a/vendor/rustix/src/backend/linux_raw/time/mod.rs b/vendor/rustix/src/backend/linux_raw/time/mod.rs
new file mode 100644
index 00000000..1e0181a9
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/time/mod.rs
@@ -0,0 +1,2 @@
+pub(crate) mod syscalls;
+pub(crate) mod types;
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 00000000..58a969d1
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/time/syscalls.rs
@@ -0,0 +1,238 @@
+//! linux_raw syscalls supporting `rustix::time`.
+//!
+//! # Safety
+//!
+//! See the `rustix::backend` module documentation for details.
+#![allow(unsafe_code, clippy::undocumented_unsafe_blocks)]
+
+use crate::backend::conv::{by_ref, ret, ret_infallible, ret_owned_fd};
+use crate::clockid::ClockId;
+use crate::fd::{BorrowedFd, OwnedFd};
+use crate::io;
+use crate::time::{Itimerspec, TimerfdClockId, TimerfdFlags, TimerfdTimerFlags};
+use crate::timespec::Timespec;
+use core::mem::MaybeUninit;
+#[cfg(target_pointer_width = "32")]
+use linux_raw_sys::general::itimerspec as __kernel_old_itimerspec;
+#[cfg(target_pointer_width = "32")]
+use linux_raw_sys::general::timespec as __kernel_old_timespec;
+
+// `clock_gettime` has special optimizations via the vDSO.
+pub(crate) use crate::backend::vdso_wrappers::{clock_gettime, clock_gettime_dynamic};
+
+#[inline]
+#[must_use]
+pub(crate) fn clock_getres(id: ClockId) -> Timespec {
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ let mut result = MaybeUninit::<Timespec>::uninit();
+ if let Err(err) = ret(syscall!(__NR_clock_getres_time64, id, &mut result)) {
+ // See the comments in `clock_gettime_via_syscall` about emulation.
+ debug_assert_eq!(err, io::Errno::NOSYS);
+ clock_getres_old(id, &mut result);
+ }
+ result.assume_init()
+ }
+ #[cfg(target_pointer_width = "64")]
+ unsafe {
+ let mut result = MaybeUninit::<Timespec>::uninit();
+ ret_infallible(syscall!(__NR_clock_getres, id, &mut result));
+ result.assume_init()
+ }
+}
+
+#[cfg(target_pointer_width = "32")]
+unsafe fn clock_getres_old(id: ClockId, result: &mut MaybeUninit<Timespec>) {
+ let mut old_result = MaybeUninit::<__kernel_old_timespec>::uninit();
+ ret_infallible(syscall!(__NR_clock_getres, id, &mut old_result));
+ let old_result = old_result.assume_init();
+ result.write(Timespec {
+ tv_sec: old_result.tv_sec.into(),
+ tv_nsec: old_result.tv_nsec.into(),
+ });
+}
+
+#[inline]
+pub(crate) fn clock_settime(id: ClockId, timespec: Timespec) -> io::Result<()> {
+ // `clock_settime64` was introduced in Linux 5.1. The old `clock_settime`
+ // syscall is not y2038-compatible on 32-bit architectures.
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ match ret(syscall_readonly!(
+ __NR_clock_settime64,
+ id,
+ by_ref(&timespec)
+ )) {
+ Err(io::Errno::NOSYS) => clock_settime_old(id, timespec),
+ otherwise => otherwise,
+ }
+ }
+ #[cfg(target_pointer_width = "64")]
+ unsafe {
+ ret(syscall_readonly!(__NR_clock_settime, id, by_ref(&timespec)))
+ }
+}
+
+#[cfg(target_pointer_width = "32")]
+unsafe fn clock_settime_old(id: ClockId, timespec: Timespec) -> io::Result<()> {
+ let old_timespec = __kernel_old_timespec {
+ tv_sec: timespec
+ .tv_sec
+ .try_into()
+ .map_err(|_| io::Errno::OVERFLOW)?,
+ tv_nsec: timespec.tv_nsec as _,
+ };
+ ret(syscall_readonly!(
+ __NR_clock_settime,
+ id,
+ by_ref(&old_timespec)
+ ))
+}
+
+#[inline]
+pub(crate) fn timerfd_create(clockid: TimerfdClockId, flags: TimerfdFlags) -> io::Result<OwnedFd> {
+ unsafe { ret_owned_fd(syscall_readonly!(__NR_timerfd_create, clockid, flags)) }
+}
+
+#[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 `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(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();
+ result.write(Itimerspec {
+ it_interval: Timespec {
+ tv_sec: old_result.it_interval.tv_sec.into(),
+ tv_nsec: old_result.it_interval.tv_nsec.into(),
+ },
+ it_value: Timespec {
+ tv_sec: old_result.it_value.tv_sec.into(),
+ tv_nsec: old_result.it_value.tv_nsec.into(),
+ },
+ });
+ Ok(())
+}
+
+#[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 `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(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();
+ result.write(Itimerspec {
+ it_interval: Timespec {
+ tv_sec: old_result.it_interval.tv_sec.into(),
+ tv_nsec: old_result.it_interval.tv_nsec.into(),
+ },
+ it_value: 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/backend/linux_raw/time/types.rs b/vendor/rustix/src/backend/linux_raw/time/types.rs
new file mode 100644
index 00000000..ec6c91f5
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/time/types.rs
@@ -0,0 +1,93 @@
+use crate::ffi;
+use bitflags::bitflags;
+
+bitflags! {
+ /// `TFD_*` flags for use with [`timerfd_create`].
+ ///
+ /// [`timerfd_create`]: crate::time::timerfd_create
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct TimerfdFlags: ffi::c_uint {
+ /// `TFD_NONBLOCK`
+ #[doc(alias = "TFD_NONBLOCK")]
+ const NONBLOCK = linux_raw_sys::general::TFD_NONBLOCK;
+
+ /// `TFD_CLOEXEC`
+ #[doc(alias = "TFD_CLOEXEC")]
+ const CLOEXEC = linux_raw_sys::general::TFD_CLOEXEC;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+bitflags! {
+ /// `TFD_TIMER_*` flags for use with [`timerfd_settime`].
+ ///
+ /// [`timerfd_settime`]: crate::time::timerfd_settime
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct TimerfdTimerFlags: ffi::c_uint {
+ /// `TFD_TIMER_ABSTIME`
+ #[doc(alias = "TFD_TIMER_ABSTIME")]
+ const ABSTIME = linux_raw_sys::general::TFD_TIMER_ABSTIME;
+
+ /// `TFD_TIMER_CANCEL_ON_SET`
+ #[doc(alias = "TFD_TIMER_CANCEL_ON_SET")]
+ const CANCEL_ON_SET = linux_raw_sys::general::TFD_TIMER_CANCEL_ON_SET;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+/// `CLOCK_*` constants for use with [`timerfd_create`].
+///
+/// [`timerfd_create`]: crate::time::timerfd_create
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
+#[repr(u32)]
+#[non_exhaustive]
+pub enum TimerfdClockId {
+ /// `CLOCK_REALTIME`—A clock that tells the “real” time.
+ ///
+ /// This is a clock that tells the amount of time elapsed since the Unix
+ /// epoch, 1970-01-01T00:00:00Z. The clock is externally settable, so it is
+ /// not monotonic. Successive reads may see decreasing times, so it isn't
+ /// reliable for measuring durations.
+ #[doc(alias = "CLOCK_REALTIME")]
+ Realtime = linux_raw_sys::general::CLOCK_REALTIME,
+
+ /// `CLOCK_MONOTONIC`—A clock that tells an abstract time.
+ ///
+ /// Unlike `Realtime`, this clock is not based on a fixed known epoch, so
+ /// individual times aren't meaningful. However, since it isn't settable,
+ /// it is reliable for measuring durations.
+ ///
+ /// This clock does not advance while the system is suspended; see
+ /// `Boottime` for a clock that does.
+ #[doc(alias = "CLOCK_MONOTONIC")]
+ Monotonic = linux_raw_sys::general::CLOCK_MONOTONIC,
+
+ /// `CLOCK_BOOTTIME`—Like `Monotonic`, but advances while suspended.
+ ///
+ /// This clock is similar to `Monotonic`, but does advance while the system
+ /// is suspended.
+ #[doc(alias = "CLOCK_BOOTTIME")]
+ Boottime = linux_raw_sys::general::CLOCK_BOOTTIME,
+
+ /// `CLOCK_REALTIME_ALARM`—Like `Realtime`, but wakes a suspended system.
+ ///
+ /// This clock is like `Realtime`, but can wake up a suspended system.
+ ///
+ /// Use of this clock requires the `CAP_WAKE_ALARM` Linux capability.
+ #[doc(alias = "CLOCK_REALTIME_ALARM")]
+ RealtimeAlarm = linux_raw_sys::general::CLOCK_REALTIME_ALARM,
+
+ /// `CLOCK_BOOTTIME_ALARM`—Like `Boottime`, but wakes a suspended system.
+ ///
+ /// This clock is like `Boottime`, but can wake up a suspended system.
+ ///
+ /// Use of this clock requires the `CAP_WAKE_ALARM` Linux capability.
+ #[doc(alias = "CLOCK_BOOTTIME_ALARM")]
+ BoottimeAlarm = linux_raw_sys::general::CLOCK_BOOTTIME_ALARM,
+}
diff --git a/vendor/rustix/src/backend/linux_raw/ugid/mod.rs b/vendor/rustix/src/backend/linux_raw/ugid/mod.rs
new file mode 100644
index 00000000..ef944f04
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/ugid/mod.rs
@@ -0,0 +1 @@
+pub(crate) mod syscalls;
diff --git a/vendor/rustix/src/backend/linux_raw/ugid/syscalls.rs b/vendor/rustix/src/backend/linux_raw/ugid/syscalls.rs
new file mode 100644
index 00000000..4aac5f24
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/ugid/syscalls.rs
@@ -0,0 +1,70 @@
+//! linux_raw syscalls for UIDs and GIDs
+//!
+//! # Safety
+//!
+//! See the `rustix::backend` module documentation for details.
+#![allow(unsafe_code, clippy::undocumented_unsafe_blocks)]
+
+use crate::backend::c;
+use crate::backend::conv::ret_usize_infallible;
+use crate::ugid::{Gid, Uid};
+
+#[inline]
+#[must_use]
+pub(crate) fn getuid() -> Uid {
+ #[cfg(any(target_arch = "arm", target_arch = "sparc", target_arch = "x86"))]
+ unsafe {
+ let uid = ret_usize_infallible(syscall_readonly!(__NR_getuid32)) as c::uid_t;
+ Uid::from_raw(uid)
+ }
+ #[cfg(not(any(target_arch = "arm", target_arch = "sparc", target_arch = "x86")))]
+ unsafe {
+ let uid = ret_usize_infallible(syscall_readonly!(__NR_getuid)) as c::uid_t;
+ Uid::from_raw(uid)
+ }
+}
+
+#[inline]
+#[must_use]
+pub(crate) fn geteuid() -> Uid {
+ #[cfg(any(target_arch = "arm", target_arch = "sparc", target_arch = "x86"))]
+ unsafe {
+ let uid = ret_usize_infallible(syscall_readonly!(__NR_geteuid32)) as c::uid_t;
+ Uid::from_raw(uid)
+ }
+ #[cfg(not(any(target_arch = "arm", target_arch = "sparc", target_arch = "x86")))]
+ unsafe {
+ let uid = ret_usize_infallible(syscall_readonly!(__NR_geteuid)) as c::uid_t;
+ Uid::from_raw(uid)
+ }
+}
+
+#[inline]
+#[must_use]
+pub(crate) fn getgid() -> Gid {
+ #[cfg(any(target_arch = "arm", target_arch = "sparc", target_arch = "x86"))]
+ unsafe {
+ let gid = ret_usize_infallible(syscall_readonly!(__NR_getgid32)) as c::gid_t;
+ Gid::from_raw(gid)
+ }
+ #[cfg(not(any(target_arch = "arm", target_arch = "sparc", target_arch = "x86")))]
+ unsafe {
+ let gid = ret_usize_infallible(syscall_readonly!(__NR_getgid)) as c::gid_t;
+ Gid::from_raw(gid)
+ }
+}
+
+#[inline]
+#[must_use]
+pub(crate) fn getegid() -> Gid {
+ #[cfg(any(target_arch = "arm", target_arch = "sparc", target_arch = "x86"))]
+ unsafe {
+ let gid = ret_usize_infallible(syscall_readonly!(__NR_getegid32)) as c::gid_t;
+ Gid::from_raw(gid)
+ }
+ #[cfg(not(any(target_arch = "arm", target_arch = "sparc", target_arch = "x86")))]
+ unsafe {
+ let gid = ret_usize_infallible(syscall_readonly!(__NR_getegid)) as c::gid_t;
+ Gid::from_raw(gid)
+ }
+}
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 00000000..4fa1d1cc
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/vdso.rs
@@ -0,0 +1,545 @@
+//! Parse the Linux vDSO.
+//!
+//! The following code is transliterated from
+//! tools/testing/selftests/vDSO/parse_vdso.c in Linux 6.13, which is licensed
+//! with Creative Commons Zero License, version 1.0,
+//! available at <https://creativecommons.org/publicdomain/zero/1.0/legalcode>
+//!
+//! It also incorporates the patch at:
+//! <https://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest.git/commit/tools/testing/selftests/vDSO?h=next&id=01587d80b04f29747b6fd6d766c3bfa632f14eb0>,
+//! with changes to fix the pointer arithmetic on s390x.
+//!
+//! # 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 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};
+use linux_raw_sys::elf::*;
+
+#[cfg(target_arch = "s390x")]
+type ElfHashEntry = u64;
+#[cfg(not(target_arch = "s390x"))]
+type ElfHashEntry = u32;
+
+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,
+ gnu_hash: *const u32,
+ bucket: *const ElfHashEntry,
+ chain: *const ElfHashEntry,
+ nbucket: ElfHashEntry,
+ //nchain: ElfHashEntry,
+
+ // Version table
+ versym: *const u16,
+ verdef: *const Elf_Verdef,
+}
+
+/// Straight from the ELF specification…and then tweaked slightly, in order to
+/// avoid a few clang warnings.
+/// (And then translated to Rust).
+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
+}
+
+fn gnu_hash(name: &CStr) -> u32 {
+ let mut h: u32 = 5381;
+ for s in name.to_bytes() {
+ h = h
+ .wrapping_add(h.wrapping_mul(32))
+ .wrapping_add(u32::from(*s));
+ }
+ 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(),
+ gnu_hash: 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_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 ElfHashEntry = 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_un.d_ptr)? as *mut _)?
+ .as_ptr();
+ }
+ DT_SYMTAB => {
+ vdso.symtab =
+ check_raw_pointer::<Elf_Sym>(vdso.addr_from_elf(d.d_un.d_ptr)? as *mut _)?
+ .as_ptr();
+ }
+ DT_HASH => {
+ hash = check_raw_pointer::<ElfHashEntry>(
+ vdso.addr_from_elf(d.d_un.d_ptr)? as *mut _
+ )?
+ .as_ptr();
+ }
+ DT_GNU_HASH => {
+ vdso.gnu_hash =
+ check_raw_pointer::<u32>(vdso.addr_from_elf(d.d_un.d_ptr)? as *mut _)?
+ .as_ptr()
+ }
+ DT_VERSYM => {
+ vdso.versym =
+ check_raw_pointer::<u16>(vdso.addr_from_elf(d.d_un.d_ptr)? as *mut _)?
+ .as_ptr();
+ }
+ DT_VERDEF => {
+ vdso.verdef = check_raw_pointer::<Elf_Verdef>(
+ vdso.addr_from_elf(d.d_un.d_ptr)? as *mut _,
+ )?
+ .as_ptr();
+ }
+ DT_SYMENT => {
+ if d.d_un.d_ptr != size_of::<Elf_Sym>() {
+ return None; // Failed
+ }
+ }
+ DT_NULL => break,
+ _ => {}
+ }
+ i = i.checked_add(1)?;
+ }
+ // `check_raw_pointer` will have checked these pointers for null,
+ // however they could still be null if the expected dynamic table
+ // entries are absent.
+ if vdso.symstrings.is_null()
+ || vdso.symtab.is_null()
+ || (hash.is_null() && vdso.gnu_hash.is_null())
+ {
+ return None; // Failed
+ }
+
+ if vdso.verdef.is_null() {
+ vdso.versym = null();
+ }
+
+ // Parse the hash table header.
+ if !vdso.gnu_hash.is_null() {
+ vdso.nbucket = ElfHashEntry::from(*vdso.gnu_hash);
+ // The bucket array is located after the header (4 uint32) and the
+ // bloom filter (size_t array of gnu_hash[2] elements).
+ vdso.bucket = vdso
+ .gnu_hash
+ .add(4)
+ .add(size_of::<c::size_t>() / 4 * *vdso.gnu_hash.add(2) as usize)
+ .cast();
+ } else {
+ 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()))
+ }
+
+ /// Check to see if the symbol is the one we're looking for.
+ ///
+ /// # Safety
+ ///
+ /// The raw pointers inside `self` must be valid.
+ unsafe fn check_sym(
+ &self,
+ sym: &Elf_Sym,
+ i: ElfHashEntry,
+ name: &CStr,
+ version: &CStr,
+ ver_hash: u32,
+ ) -> bool {
+ // Check for a defined global or weak function w/ right name.
+ //
+ // Accept `STT_NOTYPE` in addition to `STT_FUNC` for the symbol
+ // type, for compatibility with some versions of Linux on
+ // PowerPC64. See [this commit] in Linux for more background.
+ //
+ // [this commit]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/tools/testing/selftests/vDSO/parse_vdso.c?id=0161bd38c24312853ed5ae9a425a1c41c4ac674a
+ if ELF_ST_TYPE(sym.st_info) != STT_FUNC && ELF_ST_TYPE(sym.st_info) != STT_NOTYPE {
+ return false;
+ }
+ if ELF_ST_BIND(sym.st_info) != STB_GLOBAL && ELF_ST_BIND(sym.st_info) != STB_WEAK {
+ return false;
+ }
+ if name != CStr::from_ptr(self.symstrings.add(sym.st_name as usize).cast()) {
+ return false;
+ }
+
+ // Check symbol version.
+ if !self.versym.is_null()
+ && !self.match_version(*self.versym.add(i as usize), version, ver_hash)
+ {
+ return false;
+ }
+
+ true
+ }
+
+ /// 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);
+
+ // SAFETY: The pointers in `self` must be valid.
+ unsafe {
+ if !self.gnu_hash.is_null() {
+ let mut h1: u32 = gnu_hash(name);
+
+ // Changes to fix the pointer arithmetic on s390x: cast
+ // `self.bucket` to `*const u32` here, because even though
+ // s390x's `ElfHashEntry` is 64-bit for `DT_HASH` tables,
+ // it uses 32-bit entries for `DT_GNU_HASH` tables.
+ let mut i = *self
+ .bucket
+ .cast::<u32>()
+ .add((ElfHashEntry::from(h1) % self.nbucket) as usize);
+ if i == 0 {
+ return null_mut();
+ }
+ h1 |= 1;
+ // Changes to fix the pointer arithmetic on s390x: As above,
+ // cast `self.bucket` to `*const u32`.
+ let mut hashval = self
+ .bucket
+ .cast::<u32>()
+ .add(self.nbucket as usize)
+ .add((i - *self.gnu_hash.add(1)) as usize);
+ loop {
+ let sym: &Elf_Sym = &*self.symtab.add(i as usize);
+ let h2 = *hashval;
+ hashval = hashval.add(1);
+ if h1 == (h2 | 1)
+ && self.check_sym(sym, ElfHashEntry::from(i), name, version, ver_hash)
+ {
+ 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;
+ }
+ if (h2 & 1) != 0 {
+ break;
+ }
+ i += 1;
+ }
+ } else {
+ let mut i = *self
+ .bucket
+ .add((ElfHashEntry::from(elf_hash(name)) % self.nbucket) as usize);
+ while i != 0 {
+ let sym: &Elf_Sym = &*self.symtab.add(i as usize);
+ if sym.st_shndx != SHN_UNDEF && self.check_sym(sym, i, name, version, ver_hash)
+ {
+ 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;
+ }
+ i = *self.chain.add(i as usize);
+ }
+ }
+ }
+
+ 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))
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ // Disable on MIPS since QEMU on MIPS doesn't provide a vDSO.
+ #[cfg(linux_raw)]
+ #[test]
+ #[cfg_attr(any(target_arch = "mips", target_arch = "mips64"), ignore)]
+ #[allow(unused_variables)]
+ fn test_vdso() {
+ let vdso = Vdso::new().unwrap();
+ assert!(!vdso.symtab.is_null());
+ assert!(!vdso.symstrings.is_null());
+
+ {
+ #[cfg(target_arch = "x86_64")]
+ let ptr = vdso.sym(cstr!("LINUX_2.6"), cstr!("__vdso_clock_gettime"));
+ #[cfg(target_arch = "arm")]
+ let ptr = vdso.sym(cstr!("LINUX_2.6"), cstr!("__vdso_clock_gettime64"));
+ #[cfg(target_arch = "aarch64")]
+ let ptr = vdso.sym(cstr!("LINUX_2.6.39"), cstr!("__kernel_clock_gettime"));
+ #[cfg(target_arch = "x86")]
+ let ptr = vdso.sym(cstr!("LINUX_2.6"), cstr!("__vdso_clock_gettime64"));
+ #[cfg(target_arch = "riscv64")]
+ let ptr = vdso.sym(cstr!("LINUX_4.15"), cstr!("__vdso_clock_gettime"));
+ #[cfg(target_arch = "powerpc")]
+ let _ptr = vdso.sym(cstr!("LINUX_5.11"), cstr!("__kernel_clock_gettime64"));
+ #[cfg(target_arch = "powerpc64")]
+ let ptr = vdso.sym(cstr!("LINUX_2.6.15"), cstr!("__kernel_clock_gettime"));
+ #[cfg(target_arch = "s390x")]
+ let ptr = vdso.sym(cstr!("LINUX_2.6.29"), cstr!("__kernel_clock_gettime"));
+ #[cfg(any(target_arch = "mips", target_arch = "mips32r6"))]
+ let ptr = vdso.sym(cstr!("LINUX_2.6"), cstr!("__vdso_clock_gettime64"));
+ #[cfg(any(target_arch = "mips64", target_arch = "mips64r6"))]
+ let ptr = vdso.sym(cstr!("LINUX_2.6"), cstr!("__vdso_clock_gettime"));
+
+ // On PowerPC, "__kernel_clock_gettime64" isn't available in
+ // Linux < 5.11.
+ // On x86, "__vdso_clock_gettime64" isn't available in
+ // Linux < 5.3.
+ #[cfg(not(any(target_arch = "powerpc", target_arch = "x86")))]
+ assert!(!ptr.is_null());
+ }
+
+ {
+ #[cfg(target_arch = "x86_64")]
+ let ptr = vdso.sym(cstr!("LINUX_2.6"), cstr!("__vdso_clock_getres"));
+ #[cfg(target_arch = "arm")]
+ let ptr = vdso.sym(cstr!("LINUX_2.6"), cstr!("__vdso_clock_getres"));
+ #[cfg(target_arch = "aarch64")]
+ let ptr = vdso.sym(cstr!("LINUX_2.6.39"), cstr!("__kernel_clock_getres"));
+ #[cfg(target_arch = "x86")]
+ let ptr = vdso.sym(cstr!("LINUX_2.6"), cstr!("__vdso_clock_getres"));
+ #[cfg(target_arch = "riscv64")]
+ let ptr = vdso.sym(cstr!("LINUX_4.15"), cstr!("__vdso_clock_getres"));
+ #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
+ let ptr = vdso.sym(cstr!("LINUX_2.6.15"), cstr!("__kernel_clock_getres"));
+ #[cfg(target_arch = "s390x")]
+ let ptr = vdso.sym(cstr!("LINUX_2.6.29"), cstr!("__kernel_clock_getres"));
+ #[cfg(any(target_arch = "mips", target_arch = "mips32r6"))]
+ let ptr = vdso.sym(cstr!("LINUX_2.6"), cstr!("__vdso_clock_getres"));
+ #[cfg(any(target_arch = "mips64", target_arch = "mips64r6"))]
+ let ptr = vdso.sym(cstr!("LINUX_2.6"), cstr!("__vdso_clock_getres"));
+
+ // Some versions of Linux appear to lack "__vdso_clock_getres" on x86.
+ #[cfg(not(target_arch = "x86"))]
+ assert!(!ptr.is_null());
+ }
+
+ {
+ #[cfg(target_arch = "x86_64")]
+ let ptr = vdso.sym(cstr!("LINUX_2.6"), cstr!("__vdso_gettimeofday"));
+ #[cfg(target_arch = "arm")]
+ let ptr = vdso.sym(cstr!("LINUX_2.6"), cstr!("__vdso_gettimeofday"));
+ #[cfg(target_arch = "aarch64")]
+ let ptr = vdso.sym(cstr!("LINUX_2.6.39"), cstr!("__kernel_gettimeofday"));
+ #[cfg(target_arch = "x86")]
+ let ptr = vdso.sym(cstr!("LINUX_2.6"), cstr!("__vdso_gettimeofday"));
+ #[cfg(target_arch = "riscv64")]
+ let ptr = vdso.sym(cstr!("LINUX_4.15"), cstr!("__vdso_gettimeofday"));
+ #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
+ let ptr = vdso.sym(cstr!("LINUX_2.6.15"), cstr!("__kernel_gettimeofday"));
+ #[cfg(target_arch = "s390x")]
+ let ptr = vdso.sym(cstr!("LINUX_2.6.29"), cstr!("__kernel_gettimeofday"));
+ #[cfg(any(target_arch = "mips", target_arch = "mips32r6"))]
+ let ptr = vdso.sym(cstr!("LINUX_2.6"), cstr!("__vdso_gettimeofday"));
+ #[cfg(any(target_arch = "mips64", target_arch = "mips64r6"))]
+ let ptr = vdso.sym(cstr!("LINUX_2.6"), cstr!("__vdso_gettimeofday"));
+
+ // Some versions of Linux appear to lack "__vdso_gettimeofday" on x86.
+ #[cfg(not(target_arch = "x86"))]
+ assert!(!ptr.is_null());
+ }
+
+ #[cfg(any(
+ target_arch = "x86_64",
+ target_arch = "x86",
+ target_arch = "riscv64",
+ target_arch = "powerpc",
+ target_arch = "powerpc64",
+ target_arch = "s390x",
+ ))]
+ {
+ #[cfg(target_arch = "x86_64")]
+ let ptr = vdso.sym(cstr!("LINUX_2.6"), cstr!("__vdso_getcpu"));
+ #[cfg(target_arch = "x86")]
+ let ptr = vdso.sym(cstr!("LINUX_2.6"), cstr!("__vdso_getcpu"));
+ #[cfg(target_arch = "riscv64")]
+ let ptr = vdso.sym(cstr!("LINUX_4.15"), cstr!("__vdso_getcpu"));
+ #[cfg(target_arch = "powerpc")]
+ let ptr = vdso.sym(cstr!("LINUX_2.6.15"), cstr!("__kernel_getcpu"));
+ #[cfg(target_arch = "powerpc64")]
+ let ptr = vdso.sym(cstr!("LINUX_2.6.15"), cstr!("__kernel_getcpu"));
+ #[cfg(target_arch = "s390x")]
+ let ptr = vdso.sym(cstr!("LINUX_2.6.29"), cstr!("__kernel_getcpu"));
+
+ // On PowerPC, "__kernel_getcpu" isn't available in 32-bit kernels.
+ // Some versions of Linux appear to lack "__vdso_getcpu" on x86.
+ #[cfg(not(any(target_arch = "powerpc", target_arch = "x86")))]
+ assert!(!ptr.is_null());
+ }
+ }
+}
diff --git a/vendor/rustix/src/backend/linux_raw/vdso_wrappers.rs b/vendor/rustix/src/backend/linux_raw/vdso_wrappers.rs
new file mode 100644
index 00000000..338f4548
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/vdso_wrappers.rs
@@ -0,0 +1,623 @@
+//! Implement syscalls using the vDSO.
+//!
+//! <https://man7.org/linux/man-pages/man7/vdso.7.html>
+//!
+//! # Safety
+//!
+//! Similar to syscalls.rs, this file performs raw system calls, and sometimes
+//! passes them uninitialized memory buffers. This file also calls vDSO
+//! functions.
+#![allow(unsafe_code)]
+#![allow(clippy::missing_transmute_annotations)]
+
+#[cfg(target_arch = "x86")]
+use super::reg::{ArgReg, RetReg, SyscallNumber, A0, A1, A2, A3, A4, A5, R0};
+use super::vdso;
+#[cfg(target_arch = "x86")]
+use core::arch::global_asm;
+#[cfg(feature = "thread")]
+#[cfg(any(
+ target_arch = "x86_64",
+ target_arch = "x86",
+ target_arch = "riscv64",
+ target_arch = "powerpc",
+ target_arch = "powerpc64",
+ target_arch = "s390x",
+))]
+use core::ffi::c_void;
+use core::mem::transmute;
+use core::ptr::null_mut;
+use core::sync::atomic::AtomicPtr;
+use core::sync::atomic::Ordering::Relaxed;
+#[cfg(target_pointer_width = "32")]
+#[cfg(feature = "time")]
+use linux_raw_sys::general::timespec as __kernel_old_timespec;
+#[cfg(any(
+ all(
+ feature = "thread",
+ any(
+ target_arch = "x86_64",
+ target_arch = "x86",
+ target_arch = "riscv64",
+ target_arch = "powerpc",
+ target_arch = "powerpc64",
+ target_arch = "s390x"
+ )
+ ),
+ feature = "time"
+))]
+use {super::c, super::conv::ret, core::mem::MaybeUninit};
+#[cfg(feature = "time")]
+use {
+ super::conv::c_int,
+ crate::clockid::{ClockId, DynamicClockId},
+ crate::io,
+ crate::timespec::Timespec,
+ linux_raw_sys::general::__kernel_clockid_t,
+};
+
+#[cfg(feature = "time")]
+#[inline]
+#[must_use]
+pub(crate) fn clock_gettime(id: ClockId) -> Timespec {
+ // SAFETY: `CLOCK_GETTIME` contains either null or the address of a
+ // function with an ABI like libc `clock_gettime`, and calling it has the
+ // side effect of writing to the result buffer, and no others.
+ unsafe {
+ let mut result = MaybeUninit::<Timespec>::uninit();
+ let callee = match transmute(CLOCK_GETTIME.load(Relaxed)) {
+ Some(callee) => callee,
+ None => init_clock_gettime(),
+ };
+ let r0 = callee(id as c::c_int, result.as_mut_ptr());
+ // The `ClockId` enum only contains clocks which never fail. It may be
+ // tempting to change this to `debug_assert_eq`, however they can still
+ // fail on uncommon kernel configs, so we leave this in place to ensure
+ // that we don't execute undefined behavior if they ever do fail.
+ assert_eq!(r0, 0);
+ result.assume_init()
+ }
+}
+
+#[cfg(feature = "time")]
+#[inline]
+pub(crate) fn clock_gettime_dynamic(id: DynamicClockId<'_>) -> io::Result<Timespec> {
+ let id = match id {
+ DynamicClockId::Known(id) => id as __kernel_clockid_t,
+
+ DynamicClockId::Dynamic(fd) => {
+ // See `FD_TO_CLOCKID` in Linux's `clock_gettime` documentation.
+ use crate::backend::fd::AsRawFd as _;
+ const CLOCKFD: i32 = 3;
+ ((!fd.as_raw_fd() << 3) | CLOCKFD) as __kernel_clockid_t
+ }
+
+ DynamicClockId::RealtimeAlarm => c::CLOCK_REALTIME_ALARM as __kernel_clockid_t,
+ DynamicClockId::Tai => c::CLOCK_TAI as __kernel_clockid_t,
+ DynamicClockId::Boottime => c::CLOCK_BOOTTIME as __kernel_clockid_t,
+ DynamicClockId::BoottimeAlarm => c::CLOCK_BOOTTIME_ALARM as __kernel_clockid_t,
+ };
+
+ // SAFETY: `CLOCK_GETTIME` contains either null or the address of a
+ // function with an ABI like libc `clock_gettime`, and calling it has the
+ // side effect of writing to the result buffer, and no others.
+ unsafe {
+ const EINVAL: c::c_int = -(c::EINVAL as c::c_int);
+ let mut timespec = MaybeUninit::<Timespec>::uninit();
+ let callee = match transmute(CLOCK_GETTIME.load(Relaxed)) {
+ Some(callee) => callee,
+ None => init_clock_gettime(),
+ };
+ match callee(id, timespec.as_mut_ptr()) {
+ 0 => (),
+ EINVAL => return Err(io::Errno::INVAL),
+ _ => _clock_gettime_via_syscall(id, timespec.as_mut_ptr())?,
+ }
+ Ok(timespec.assume_init())
+ }
+}
+
+#[cfg(feature = "thread")]
+#[cfg(any(
+ target_arch = "x86_64",
+ target_arch = "x86",
+ target_arch = "riscv64",
+ target_arch = "powerpc",
+ target_arch = "powerpc64",
+ target_arch = "s390x",
+))]
+#[inline]
+pub(crate) fn sched_getcpu() -> usize {
+ // SAFETY: `GETCPU` contains either null or the address of a function with
+ // an ABI like libc `getcpu`, and calling it has the side effect of writing
+ // to the result buffers, and no others.
+ unsafe {
+ let mut cpu = MaybeUninit::<u32>::uninit();
+ let callee = match transmute(GETCPU.load(Relaxed)) {
+ Some(callee) => callee,
+ None => init_getcpu(),
+ };
+ let r0 = callee(cpu.as_mut_ptr(), null_mut(), null_mut());
+ debug_assert_eq!(r0, 0);
+ cpu.assume_init() as usize
+ }
+}
+
+#[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::backend::arch::asm;
+
+ #[inline]
+ 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(),
+ };
+ asm::indirect_syscall0(callee, nr)
+ }
+
+ #[inline]
+ pub(in crate::backend) unsafe fn syscall1<'a>(
+ nr: SyscallNumber<'a>,
+ a0: ArgReg<'a, A0>,
+ ) -> RetReg<R0> {
+ let callee = match transmute(super::SYSCALL.load(Relaxed)) {
+ Some(callee) => callee,
+ None => super::init_syscall(),
+ };
+ asm::indirect_syscall1(callee, nr, a0)
+ }
+
+ #[inline]
+ pub(in crate::backend) unsafe fn syscall1_noreturn<'a>(
+ nr: SyscallNumber<'a>,
+ a0: ArgReg<'a, A0>,
+ ) -> ! {
+ let callee = match transmute(super::SYSCALL.load(Relaxed)) {
+ Some(callee) => callee,
+ None => super::init_syscall(),
+ };
+ asm::indirect_syscall1_noreturn(callee, nr, a0)
+ }
+
+ #[inline]
+ pub(in crate::backend) unsafe fn syscall2<'a>(
+ nr: SyscallNumber<'a>,
+ a0: ArgReg<'a, A0>,
+ a1: ArgReg<'a, A1>,
+ ) -> RetReg<R0> {
+ let callee = match transmute(super::SYSCALL.load(Relaxed)) {
+ Some(callee) => callee,
+ None => super::init_syscall(),
+ };
+ asm::indirect_syscall2(callee, nr, a0, a1)
+ }
+
+ #[inline]
+ pub(in crate::backend) unsafe fn syscall3<'a>(
+ nr: SyscallNumber<'a>,
+ a0: ArgReg<'a, A0>,
+ a1: ArgReg<'a, A1>,
+ a2: ArgReg<'a, A2>,
+ ) -> RetReg<R0> {
+ let callee = match transmute(super::SYSCALL.load(Relaxed)) {
+ Some(callee) => callee,
+ None => super::init_syscall(),
+ };
+ asm::indirect_syscall3(callee, nr, a0, a1, a2)
+ }
+
+ #[inline]
+ pub(in crate::backend) unsafe fn syscall4<'a>(
+ nr: SyscallNumber<'a>,
+ a0: ArgReg<'a, A0>,
+ a1: ArgReg<'a, A1>,
+ a2: ArgReg<'a, A2>,
+ a3: ArgReg<'a, A3>,
+ ) -> RetReg<R0> {
+ let callee = match transmute(super::SYSCALL.load(Relaxed)) {
+ Some(callee) => callee,
+ None => super::init_syscall(),
+ };
+ asm::indirect_syscall4(callee, nr, a0, a1, a2, a3)
+ }
+
+ #[inline]
+ pub(in crate::backend) unsafe fn syscall5<'a>(
+ nr: SyscallNumber<'a>,
+ a0: ArgReg<'a, A0>,
+ a1: ArgReg<'a, A1>,
+ a2: ArgReg<'a, A2>,
+ a3: ArgReg<'a, A3>,
+ a4: ArgReg<'a, A4>,
+ ) -> RetReg<R0> {
+ let callee = match transmute(super::SYSCALL.load(Relaxed)) {
+ Some(callee) => callee,
+ None => super::init_syscall(),
+ };
+ asm::indirect_syscall5(callee, nr, a0, a1, a2, a3, a4)
+ }
+
+ #[inline]
+ pub(in crate::backend) unsafe fn syscall6<'a>(
+ nr: SyscallNumber<'a>,
+ a0: ArgReg<'a, A0>,
+ a1: ArgReg<'a, A1>,
+ a2: ArgReg<'a, A2>,
+ a3: ArgReg<'a, A3>,
+ a4: ArgReg<'a, A4>,
+ a5: ArgReg<'a, A5>,
+ ) -> RetReg<R0> {
+ let callee = match transmute(super::SYSCALL.load(Relaxed)) {
+ Some(callee) => callee,
+ None => super::init_syscall(),
+ };
+ asm::indirect_syscall6(callee, nr, a0, a1, a2, a3, a4, a5)
+ }
+
+ // With the indirect call, it isn't meaningful to do a separate
+ // `_readonly` optimization.
+ #[allow(unused_imports)]
+ 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,
+ };
+}
+
+#[cfg(feature = "time")]
+type ClockGettimeType = unsafe extern "C" fn(c::c_int, *mut Timespec) -> c::c_int;
+
+#[cfg(feature = "thread")]
+#[cfg(any(
+ target_arch = "x86_64",
+ target_arch = "x86",
+ target_arch = "riscv64",
+ target_arch = "powerpc",
+ target_arch = "powerpc64",
+ target_arch = "s390x",
+))]
+type GetcpuType = unsafe extern "C" fn(*mut u32, *mut u32, *mut c_void) -> c::c_int;
+
+/// The underlying syscall functions are only called from asm, using the
+/// special syscall calling convention to pass arguments and return values,
+/// which the signature here doesn't reflect.
+#[cfg(target_arch = "x86")]
+pub(super) type SyscallType = unsafe extern "C" fn();
+
+/// Initialize `CLOCK_GETTIME` and return its value.
+#[cfg(feature = "time")]
+#[cold]
+fn init_clock_gettime() -> ClockGettimeType {
+ init();
+ // SAFETY: Load the function address from static storage that we just
+ // initialized.
+ unsafe { transmute(CLOCK_GETTIME.load(Relaxed)) }
+}
+
+/// Initialize `GETCPU` and return its value.
+#[cfg(feature = "thread")]
+#[cfg(any(
+ target_arch = "x86_64",
+ target_arch = "x86",
+ target_arch = "riscv64",
+ target_arch = "powerpc",
+ target_arch = "powerpc64",
+ target_arch = "s390x",
+))]
+#[cold]
+fn init_getcpu() -> GetcpuType {
+ init();
+ // SAFETY: Load the function address from static storage that we just
+ // initialized.
+ unsafe { transmute(GETCPU.load(Relaxed)) }
+}
+
+/// Initialize `SYSCALL` and return its value.
+#[cfg(target_arch = "x86")]
+#[cold]
+fn init_syscall() -> SyscallType {
+ init();
+ // SAFETY: Load the function address from static storage that we just
+ // initialized.
+ unsafe { transmute(SYSCALL.load(Relaxed)) }
+}
+
+/// `AtomicPtr` can't hold a `fn` pointer, so we use a `*` pointer to this
+/// placeholder type, and cast it as needed.
+struct Function;
+#[cfg(feature = "time")]
+static CLOCK_GETTIME: AtomicPtr<Function> = AtomicPtr::new(null_mut());
+#[cfg(feature = "thread")]
+#[cfg(any(
+ target_arch = "x86_64",
+ target_arch = "x86",
+ target_arch = "riscv64",
+ target_arch = "powerpc",
+ target_arch = "powerpc64",
+ target_arch = "s390x",
+))]
+static GETCPU: AtomicPtr<Function> = AtomicPtr::new(null_mut());
+#[cfg(target_arch = "x86")]
+static SYSCALL: AtomicPtr<Function> = AtomicPtr::new(null_mut());
+
+#[cfg(feature = "time")]
+#[must_use]
+unsafe extern "C" fn clock_gettime_via_syscall(clockid: c::c_int, res: *mut Timespec) -> c::c_int {
+ match _clock_gettime_via_syscall(clockid, res) {
+ Ok(()) => 0,
+ Err(err) => err.raw_os_error().wrapping_neg(),
+ }
+}
+
+#[cfg(feature = "time")]
+#[cfg(target_pointer_width = "32")]
+unsafe fn _clock_gettime_via_syscall(clockid: c::c_int, res: *mut Timespec) -> io::Result<()> {
+ let r0 = syscall!(__NR_clock_gettime64, c_int(clockid), res);
+ match ret(r0) {
+ Err(io::Errno::NOSYS) => _clock_gettime_via_syscall_old(clockid, res),
+ otherwise => otherwise,
+ }
+}
+
+#[cfg(feature = "time")]
+#[cfg(target_pointer_width = "32")]
+unsafe fn _clock_gettime_via_syscall_old(clockid: c::c_int, res: *mut Timespec) -> io::Result<()> {
+ // Ordinarily `rustix` doesn't like to emulate system calls, but in the
+ // case of time APIs, it's specific to Linux, specific to 32-bit
+ // architectures *and* specific to old kernel versions, and it's not that
+ // hard to fix up here, so that no other code needs to worry about this.
+ let mut old_result = MaybeUninit::<__kernel_old_timespec>::uninit();
+ let r0 = syscall!(__NR_clock_gettime, c_int(clockid), &mut old_result);
+ match ret(r0) {
+ Ok(()) => {
+ let old_result = old_result.assume_init();
+ *res = Timespec {
+ tv_sec: old_result.tv_sec.into(),
+ tv_nsec: old_result.tv_nsec.into(),
+ };
+ Ok(())
+ }
+ otherwise => otherwise,
+ }
+}
+
+#[cfg(feature = "time")]
+#[cfg(target_pointer_width = "64")]
+unsafe fn _clock_gettime_via_syscall(clockid: c::c_int, res: *mut Timespec) -> io::Result<()> {
+ ret(syscall!(__NR_clock_gettime, c_int(clockid), res))
+}
+
+#[cfg(feature = "thread")]
+#[cfg(any(
+ target_arch = "x86_64",
+ target_arch = "x86",
+ target_arch = "riscv64",
+ target_arch = "powerpc",
+ target_arch = "powerpc64",
+ target_arch = "s390x",
+))]
+unsafe extern "C" fn getcpu_via_syscall(
+ cpu: *mut u32,
+ node: *mut u32,
+ unused: *mut c_void,
+) -> c::c_int {
+ match ret(syscall!(__NR_getcpu, cpu, node, unused)) {
+ Ok(()) => 0,
+ Err(err) => err.raw_os_error().wrapping_neg(),
+ }
+}
+
+#[cfg(target_arch = "x86")]
+extern "C" {
+ /// A symbol pointing to an x86 `int 0x80` instruction. This “function”
+ /// is only called from assembly, and only with the x86 syscall calling
+ /// convention, so its signature here is not its true signature.
+ ///
+ /// This extern block and the `global_asm!` below can be replaced with
+ /// `#[naked]` if it's stabilized.
+ fn rustix_x86_int_0x80();
+}
+
+// This uses `.weak` so that it doesn't conflict if multiple versions of rustix
+// are linked in in non-lto builds, and `.ifndef` so that it doesn't conflict
+// if multiple versions of rustix are linked in in lto builds.
+#[cfg(target_arch = "x86")]
+global_asm!(
+ r#"
+ .ifndef rustix_x86_int_0x80
+ .section .text.rustix_x86_int_0x80,"ax",@progbits
+ .p2align 4
+ .weak rustix_x86_int_0x80
+ .hidden rustix_x86_int_0x80
+ .type rustix_x86_int_0x80, @function
+rustix_x86_int_0x80:
+ .cfi_startproc
+ int 0x80
+ ret
+ .cfi_endproc
+ .size rustix_x86_int_0x80, .-rustix_x86_int_0x80
+ .endif
+"#
+);
+
+fn minimal_init() {
+ // Store default function addresses in static storage so that if we
+ // end up making any system calls while we read the vDSO, they'll work. If
+ // the memory happens to already be initialized, this is redundant, but not
+ // harmful.
+ #[cfg(feature = "time")]
+ {
+ CLOCK_GETTIME
+ .compare_exchange(
+ null_mut(),
+ clock_gettime_via_syscall as *mut Function,
+ Relaxed,
+ Relaxed,
+ )
+ .ok();
+ }
+
+ #[cfg(feature = "thread")]
+ #[cfg(any(
+ target_arch = "x86_64",
+ target_arch = "x86",
+ target_arch = "riscv64",
+ target_arch = "powerpc",
+ target_arch = "powerpc64",
+ target_arch = "s390x",
+ ))]
+ {
+ GETCPU
+ .compare_exchange(
+ null_mut(),
+ getcpu_via_syscall as *mut Function,
+ Relaxed,
+ Relaxed,
+ )
+ .ok();
+ }
+
+ #[cfg(target_arch = "x86")]
+ {
+ SYSCALL
+ .compare_exchange(
+ null_mut(),
+ rustix_x86_int_0x80 as *mut Function,
+ Relaxed,
+ Relaxed,
+ )
+ .ok();
+ }
+}
+
+fn init() {
+ minimal_init();
+
+ if let Some(vdso) = vdso::Vdso::new() {
+ #[cfg(feature = "time")]
+ {
+ // Look up the platform-specific `clock_gettime` symbol as
+ // documented [here], except on 32-bit platforms where we look up
+ // the `64`-suffixed variant and fail if we don't find it.
+ //
+ // [here]: https://man7.org/linux/man-pages/man7/vdso.7.html
+ #[cfg(target_arch = "x86_64")]
+ let ptr = vdso.sym(cstr!("LINUX_2.6"), cstr!("__vdso_clock_gettime"));
+ #[cfg(target_arch = "arm")]
+ let ptr = vdso.sym(cstr!("LINUX_2.6"), cstr!("__vdso_clock_gettime64"));
+ #[cfg(target_arch = "aarch64")]
+ let ptr = vdso.sym(cstr!("LINUX_2.6.39"), cstr!("__kernel_clock_gettime"));
+ #[cfg(target_arch = "x86")]
+ let ptr = vdso.sym(cstr!("LINUX_2.6"), cstr!("__vdso_clock_gettime64"));
+ #[cfg(target_arch = "riscv64")]
+ let ptr = vdso.sym(cstr!("LINUX_4.15"), cstr!("__vdso_clock_gettime"));
+ #[cfg(target_arch = "powerpc")]
+ let ptr = vdso.sym(cstr!("LINUX_5.11"), cstr!("__kernel_clock_gettime64"));
+ #[cfg(target_arch = "powerpc64")]
+ let ptr = vdso.sym(cstr!("LINUX_2.6.15"), cstr!("__kernel_clock_gettime"));
+ #[cfg(target_arch = "s390x")]
+ let ptr = vdso.sym(cstr!("LINUX_2.6.29"), cstr!("__kernel_clock_gettime"));
+ #[cfg(any(target_arch = "mips", target_arch = "mips32r6"))]
+ let ptr = vdso.sym(cstr!("LINUX_2.6"), cstr!("__vdso_clock_gettime64"));
+ #[cfg(any(target_arch = "mips64", target_arch = "mips64r6"))]
+ let ptr = vdso.sym(cstr!("LINUX_2.6"), cstr!("__vdso_clock_gettime"));
+
+ // On all 64-bit platforms, the 64-bit `clock_gettime` symbols are
+ // always available.
+ #[cfg(target_pointer_width = "64")]
+ let ok = true;
+
+ // On some 32-bit platforms, the 64-bit `clock_gettime` symbols are
+ // not available on older kernel versions.
+ #[cfg(any(
+ target_arch = "arm",
+ target_arch = "mips",
+ target_arch = "mips32r6",
+ target_arch = "powerpc",
+ target_arch = "x86"
+ ))]
+ let ok = !ptr.is_null();
+
+ if ok {
+ assert!(!ptr.is_null());
+
+ // Store the computed function addresses in static storage so
+ // that we don't need to compute them again (but if we do, it
+ // doesn't hurt anything).
+ CLOCK_GETTIME.store(ptr.cast(), Relaxed);
+ }
+ }
+
+ #[cfg(feature = "thread")]
+ #[cfg(any(
+ target_arch = "x86_64",
+ target_arch = "x86",
+ target_arch = "riscv64",
+ target_arch = "powerpc",
+ target_arch = "powerpc64",
+ target_arch = "s390x",
+ ))]
+ {
+ // Look up the platform-specific `getcpu` symbol as documented
+ // [here].
+ //
+ // [here]: https://man7.org/linux/man-pages/man7/vdso.7.html
+ #[cfg(target_arch = "x86_64")]
+ let ptr = vdso.sym(cstr!("LINUX_2.6"), cstr!("__vdso_getcpu"));
+ #[cfg(target_arch = "x86")]
+ let ptr = vdso.sym(cstr!("LINUX_2.6"), cstr!("__vdso_getcpu"));
+ #[cfg(target_arch = "riscv64")]
+ let ptr = vdso.sym(cstr!("LINUX_4.15"), cstr!("__vdso_getcpu"));
+ #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
+ let ptr = vdso.sym(cstr!("LINUX_2.6.15"), cstr!("__kernel_getcpu"));
+ #[cfg(target_arch = "s390x")]
+ let ptr = vdso.sym(cstr!("LINUX_2.6.29"), cstr!("__kernel_getcpu"));
+
+ #[cfg(any(
+ target_arch = "x86_64",
+ target_arch = "riscv64",
+ target_arch = "powerpc",
+ target_arch = "powerpc64",
+ target_arch = "s390x"
+ ))]
+ let ok = true;
+
+ // On 32-bit x86, the symbol doesn't appear present sometimes.
+ #[cfg(target_arch = "x86")]
+ let ok = !ptr.is_null();
+
+ #[cfg(any(
+ target_arch = "aarch64",
+ target_arch = "arm",
+ target_arch = "mips",
+ target_arch = "mips32r6",
+ target_arch = "mips64",
+ target_arch = "mips64r6",
+ ))]
+ let ok = false;
+
+ if ok {
+ assert!(!ptr.is_null());
+
+ // Store the computed function addresses in static storage so
+ // that we don't need to compute them again (but if we do, it
+ // doesn't hurt anything).
+ GETCPU.store(ptr.cast(), Relaxed);
+ }
+ }
+
+ // On x86, also look up the vsyscall entry point.
+ #[cfg(target_arch = "x86")]
+ {
+ let ptr = vdso.sym(cstr!("LINUX_2.5"), cstr!("__kernel_vsyscall"));
+ assert!(!ptr.is_null());
+
+ // As above, store the computed function addresses in
+ // static storage.
+ SYSCALL.store(ptr.cast(), Relaxed);
+ }
+ }
+}