From 1376c5a617be5c25655d0d7cb63e3beaa5a6e026 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:20:39 +0200 Subject: Merging upstream version 1.70.0+dfsg1. Signed-off-by: Daniel Baumann --- vendor/rustix/src/backend/linux_raw/c.rs | 32 +- vendor/rustix/src/backend/linux_raw/conv.rs | 73 ++- vendor/rustix/src/backend/linux_raw/fs/inotify.rs | 108 +++++ vendor/rustix/src/backend/linux_raw/fs/mod.rs | 1 + vendor/rustix/src/backend/linux_raw/fs/syscalls.rs | 170 ++++++- vendor/rustix/src/backend/linux_raw/fs/types.rs | 138 +++++- vendor/rustix/src/backend/linux_raw/io/epoll.rs | 519 ++++++--------------- vendor/rustix/src/backend/linux_raw/io/errno.rs | 19 +- vendor/rustix/src/backend/linux_raw/io/syscalls.rs | 7 +- vendor/rustix/src/backend/linux_raw/io/types.rs | 11 +- .../src/backend/linux_raw/io_uring/syscalls.rs | 6 +- vendor/rustix/src/backend/linux_raw/mod.rs | 5 + vendor/rustix/src/backend/linux_raw/net/addr.rs | 4 +- .../rustix/src/backend/linux_raw/net/syscalls.rs | 10 + vendor/rustix/src/backend/linux_raw/param/auxv.rs | 6 +- .../src/backend/linux_raw/param/libc_auxv.rs | 39 +- .../src/backend/linux_raw/param/mustang_auxv.rs | 14 +- .../src/backend/linux_raw/process/cpu_set.rs | 2 + .../src/backend/linux_raw/process/syscalls.rs | 111 ++++- .../rustix/src/backend/linux_raw/process/wait.rs | 4 +- vendor/rustix/src/backend/linux_raw/runtime/tls.rs | 8 +- .../src/backend/linux_raw/termios/syscalls.rs | 50 ++ .../rustix/src/backend/linux_raw/termios/types.rs | 37 +- .../src/backend/linux_raw/thread/syscalls.rs | 62 +++ .../rustix/src/backend/linux_raw/time/syscalls.rs | 41 ++ vendor/rustix/src/backend/linux_raw/vdso.rs | 4 +- .../rustix/src/backend/linux_raw/vdso_wrappers.rs | 14 +- vendor/rustix/src/backend/linux_raw/weak.rs | 228 +++++++++ 28 files changed, 1255 insertions(+), 468 deletions(-) create mode 100644 vendor/rustix/src/backend/linux_raw/fs/inotify.rs create mode 100644 vendor/rustix/src/backend/linux_raw/weak.rs (limited to 'vendor/rustix/src/backend/linux_raw') diff --git a/vendor/rustix/src/backend/linux_raw/c.rs b/vendor/rustix/src/backend/linux_raw/c.rs index a6f0b8ff6..e7263305a 100644 --- a/vendor/rustix/src/backend/linux_raw/c.rs +++ b/vendor/rustix/src/backend/linux_raw/c.rs @@ -9,21 +9,23 @@ pub(crate) use linux_raw_sys::ctypes::*; pub(crate) use linux_raw_sys::errno::EINVAL; pub(crate) use linux_raw_sys::general::{ AF_DECnet, __kernel_sa_family_t as sa_family_t, __kernel_sockaddr_storage as sockaddr_storage, - in6_addr, in_addr, iovec, ip_mreq, ipv6_mreq, linger, sockaddr, sockaddr_in, sockaddr_in6, - sockaddr_un, socklen_t, 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, IPPROTO_AH, IPPROTO_BEETPH, IPPROTO_COMP, IPPROTO_DCCP, IPPROTO_EGP, IPPROTO_ENCAP, - IPPROTO_ESP, IPPROTO_ETHERNET, IPPROTO_FRAGMENT, IPPROTO_GRE, IPPROTO_ICMP, IPPROTO_ICMPV6, - IPPROTO_IDP, IPPROTO_IGMP, IPPROTO_IP, IPPROTO_IPIP, IPPROTO_IPV6, IPPROTO_MH, IPPROTO_MPLS, - IPPROTO_MPTCP, IPPROTO_MTP, IPPROTO_PIM, IPPROTO_PUP, IPPROTO_RAW, IPPROTO_ROUTING, - IPPROTO_RSVP, IPPROTO_SCTP, IPPROTO_TCP, IPPROTO_TP, IPPROTO_UDP, IPPROTO_UDPLITE, - IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP, IPV6_MULTICAST_LOOP, IPV6_V6ONLY, IP_ADD_MEMBERSHIP, - IP_DROP_MEMBERSHIP, IP_MULTICAST_LOOP, IP_MULTICAST_TTL, IP_TTL, MSG_CMSG_CLOEXEC, MSG_CONFIRM, - MSG_DONTROUTE, MSG_DONTWAIT, MSG_EOR, MSG_ERRQUEUE, MSG_MORE, MSG_NOSIGNAL, MSG_OOB, MSG_PEEK, - MSG_TRUNC, MSG_WAITALL, O_CLOEXEC, O_NONBLOCK, SHUT_RD, SHUT_RDWR, SHUT_WR, SOCK_DGRAM, - SOCK_RAW, SOCK_RDM, SOCK_SEQPACKET, SOCK_STREAM, SOL_SOCKET, SO_BROADCAST, SO_LINGER, + in6_addr, in_addr, iovec, ip_mreq, ipv6_mreq, linger, siginfo_t, sockaddr, sockaddr_in, + sockaddr_in6, sockaddr_un, socklen_t, 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, IPPROTO_AH, IPPROTO_BEETPH, IPPROTO_COMP, IPPROTO_DCCP, IPPROTO_EGP, + IPPROTO_ENCAP, IPPROTO_ESP, IPPROTO_ETHERNET, IPPROTO_FRAGMENT, IPPROTO_GRE, IPPROTO_ICMP, + IPPROTO_ICMPV6, IPPROTO_IDP, IPPROTO_IGMP, IPPROTO_IP, IPPROTO_IPIP, IPPROTO_IPV6, IPPROTO_MH, + IPPROTO_MPLS, IPPROTO_MPTCP, IPPROTO_MTP, IPPROTO_PIM, IPPROTO_PUP, IPPROTO_RAW, + IPPROTO_ROUTING, IPPROTO_RSVP, IPPROTO_SCTP, IPPROTO_TCP, IPPROTO_TP, IPPROTO_UDP, + IPPROTO_UDPLITE, IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP, IPV6_MULTICAST_LOOP, IPV6_V6ONLY, + IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP, IP_MULTICAST_LOOP, IP_MULTICAST_TTL, IP_TTL, + MSG_CMSG_CLOEXEC, MSG_CONFIRM, MSG_DONTROUTE, MSG_DONTWAIT, MSG_EOR, MSG_ERRQUEUE, MSG_MORE, + MSG_NOSIGNAL, MSG_OOB, MSG_PEEK, MSG_TRUNC, MSG_WAITALL, O_CLOEXEC, O_NONBLOCK, + O_NONBLOCK as PIDFD_NONBLOCK, P_ALL, P_PID, P_PIDFD, SHUT_RD, SHUT_RDWR, SHUT_WR, SOCK_DGRAM, + SOCK_RAW, SOCK_RDM, SOCK_SEQPACKET, SOCK_STREAM, SOL_SOCKET, SO_BROADCAST, SO_ERROR, SO_LINGER, SO_PASSCRED, SO_RCVTIMEO_NEW, SO_RCVTIMEO_OLD, SO_REUSEADDR, SO_SNDTIMEO_NEW, SO_SNDTIMEO_OLD, SO_TYPE, TCP_NODELAY, }; +pub(crate) use linux_raw_sys::general::{NFS_SUPER_MAGIC, PROC_SUPER_MAGIC, UTIME_NOW, UTIME_OMIT}; diff --git a/vendor/rustix/src/backend/linux_raw/conv.rs b/vendor/rustix/src/backend/linux_raw/conv.rs index 7e09cdf80..b9fe725bb 100644 --- a/vendor/rustix/src/backend/linux_raw/conv.rs +++ b/vendor/rustix/src/backend/linux_raw/conv.rs @@ -15,12 +15,12 @@ use super::c; use super::fd::{AsRawFd, BorrowedFd, FromRawFd, RawFd}; -#[cfg(not(debug_assertions))] -use super::io::errno::decode_usize_infallible; #[cfg(feature = "runtime")] use super::io::errno::try_decode_error; #[cfg(target_pointer_width = "64")] use super::io::errno::try_decode_u64; +#[cfg(not(debug_assertions))] +use super::io::errno::{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, @@ -143,7 +143,7 @@ impl<'a, Num: ArgNumber> From> for ArgReg<'a, Num> { impl<'a, Num: ArgNumber> From> for ArgReg<'a, Num> { #[inline] fn from(fd: BorrowedFd<'a>) -> Self { - // Safety: `BorrowedFd` ensures that the file descriptor is valid, and the + // 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()) } @@ -313,6 +313,22 @@ impl<'a, Num: ArgNumber> From for ArgReg<'a, Num> { } } +#[cfg(feature = "fs")] +impl<'a, Num: ArgNumber> From for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::fs::inotify::CreateFlags) -> Self { + c_uint(flags.bits()) + } +} + +#[cfg(feature = "fs")] +impl<'a, Num: ArgNumber> From for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::fs::inotify::WatchFlags) -> Self { + c_uint(flags.bits()) + } +} + #[cfg(feature = "fs")] impl<'a, Num: ArgNumber> From for ArgReg<'a, Num> { #[inline] @@ -665,6 +681,38 @@ impl<'a, Num: ArgNumber, T> From<&'a mut MaybeUninit> for ArgReg<'a, Num> { } } +#[cfg(feature = "fs")] +#[cfg(any(target_os = "android", target_os = "linux"))] +impl<'a, Num: ArgNumber> From for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::backend::fs::types::MountFlagsArg) -> Self { + c_uint(flags.0) + } +} + +#[cfg(feature = "fs")] +#[cfg(any(target_os = "android", target_os = "linux"))] +impl<'a, Num: ArgNumber> From for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::backend::fs::types::UnmountFlags) -> Self { + c_uint(flags.bits()) + } +} + +impl<'a, Num: ArgNumber> From for ArgReg<'a, Num> { + #[inline] + fn from(t: crate::process::Uid) -> Self { + c_uint(t.as_raw()) + } +} + +impl<'a, Num: ArgNumber> From for ArgReg<'a, Num> { + #[inline] + fn from(t: crate::process::Gid) -> Self { + c_uint(t.as_raw()) + } +} + /// Convert a `usize` returned from a syscall that effectively returns `()` on /// success. /// @@ -754,6 +802,25 @@ pub(super) unsafe fn ret_usize_infallible(raw: RetReg) -> usize { } } +/// 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) -> 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. /// 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 000000000..4221565a6 --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/fs/inotify.rs @@ -0,0 +1,108 @@ +//! inotify support for working with inotifies + +use super::super::c; +use crate::backend::fs::syscalls; +use crate::fd::{BorrowedFd, OwnedFd}; +use crate::io; +use bitflags::bitflags; + +bitflags! { + /// `IN_*` for use with [`inotify_init`]. + /// + /// [`inotify_init`]: crate::fs::inotify::inotify_init + pub struct CreateFlags: c::c_uint { + /// `IN_CLOEXEC` + const CLOEXEC = linux_raw_sys::general::IN_CLOEXEC; + /// `IN_NONBLOCK` + const NONBLOCK = linux_raw_sys::general::IN_NONBLOCK; + } +} + +bitflags! { + /// `IN*` for use with [`inotify_add_watch`]. + /// + /// [`inotify_add_watch`]: crate::fs::inotify::inotify_add_watch + #[derive(Default)] + pub struct WatchFlags: c::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; + } +} + +/// `inotify_init1(flags)`—Creates a new inotify object. +/// +/// Use the [`CreateFlags::CLOEXEC`] flag to prevent the resulting file +/// descriptor from being implicitly passed across `exec` boundaries. +#[doc(alias = "inotify_init1")] +pub fn inotify_init(flags: CreateFlags) -> io::Result { + syscalls::inotify_init1(flags) +} + +/// `inotify_add_watch(self, path, flags)`—Adds a watch to inotify +/// +/// This registers or updates a watch for the filesystem path `path` +/// and returns a watch descriptor corresponding to this watch. +/// +/// Note: Due to the existence of hardlinks, providing two +/// different paths to this method may result in it returning +/// the same watch descriptor. An application should keep track of this +/// externally to avoid logic errors. +pub fn inotify_add_watch( + inot: BorrowedFd<'_>, + path: P, + flags: WatchFlags, +) -> io::Result { + let path = path.as_cow_c_str().unwrap(); + syscalls::inotify_add_watch(inot, &path, flags) +} + +/// `inotify_rm_watch(self, wd)`—Removes a watch from this inotify +/// +/// The watch descriptor provided should have previously been returned +/// by [`inotify_add_watch`] and not previously have been removed. +#[doc(alias = "inotify_rm_watch")] +pub fn inotify_remove_watch(inot: BorrowedFd<'_>, wd: i32) -> io::Result<()> { + syscalls::inotify_rm_watch(inot, wd) +} diff --git a/vendor/rustix/src/backend/linux_raw/fs/mod.rs b/vendor/rustix/src/backend/linux_raw/fs/mod.rs index 015c6baec..acf43ce4f 100644 --- a/vendor/rustix/src/backend/linux_raw/fs/mod.rs +++ b/vendor/rustix/src/backend/linux_raw/fs/mod.rs @@ -1,4 +1,5 @@ pub(crate) mod dir; +pub mod inotify; pub(crate) mod makedev; pub(crate) mod syscalls; pub(crate) mod types; diff --git a/vendor/rustix/src/backend/linux_raw/fs/syscalls.rs b/vendor/rustix/src/backend/linux_raw/fs/syscalls.rs index ff58f0a7b..8bd9ccc27 100644 --- a/vendor/rustix/src/backend/linux_raw/fs/syscalls.rs +++ b/vendor/rustix/src/backend/linux_raw/fs/syscalls.rs @@ -10,7 +10,7 @@ use super::super::c; use super::super::conv::{ by_ref, c_int, c_uint, dev_t, oflags_for_open_how, opt_mut, pass_usize, raw_fd, ret, ret_c_int, - ret_c_uint, ret_owned_fd, ret_usize, size_of, slice_mut, zero, + ret_c_uint, ret_infallible, ret_owned_fd, ret_usize, size_of, slice_mut, zero, }; #[cfg(target_pointer_width = "64")] use super::super::conv::{loff_t, loff_t_from_u64, ret_u64}; @@ -24,12 +24,13 @@ use crate::fd::AsFd; use crate::fd::{BorrowedFd, OwnedFd}; use crate::ffi::CStr; use crate::fs::{ - Access, Advice, AtFlags, FallocateFlags, FileType, FlockOperation, MemfdFlags, Mode, OFlags, - RenameFlags, ResolveFlags, SealFlags, Stat, StatFs, StatVfs, StatVfsMountFlags, StatxFlags, - Timestamps, + inotify, Access, Advice, AtFlags, FallocateFlags, FileType, FlockOperation, MemfdFlags, Mode, + OFlags, RenameFlags, ResolveFlags, SealFlags, Stat, StatFs, StatVfs, StatVfsMountFlags, + StatxFlags, Timestamps, }; use crate::io::{self, SeekFrom}; use crate::process::{Gid, Uid}; +#[cfg(any(target_pointer_width = "32", target_arch = "mips64"))] use core::convert::TryInto; use core::mem::MaybeUninit; #[cfg(target_arch = "mips64")] @@ -37,7 +38,8 @@ use linux_raw_sys::general::stat as linux_stat64; use linux_raw_sys::general::{ __kernel_fsid_t, __kernel_timespec, open_how, statx, AT_EACCESS, AT_FDCWD, AT_REMOVEDIR, AT_SYMLINK_NOFOLLOW, F_ADD_SEALS, F_GETFL, F_GETLEASE, F_GETOWN, F_GETPIPE_SZ, F_GETSIG, - F_GET_SEALS, F_SETFL, F_SETPIPE_SZ, SEEK_CUR, SEEK_END, SEEK_SET, STATX__RESERVED, + F_GET_SEALS, F_SETFL, F_SETPIPE_SZ, SEEK_CUR, SEEK_DATA, SEEK_END, SEEK_HOLE, SEEK_SET, + STATX__RESERVED, }; #[cfg(target_pointer_width = "32")] use { @@ -136,7 +138,18 @@ pub(crate) fn chmod(filename: &CStr, mode: Mode) -> io::Result<()> { } #[inline] -pub(crate) fn chmodat(dirfd: BorrowedFd<'_>, filename: &CStr, mode: Mode) -> io::Result<()> { +pub(crate) fn chmodat( + dirfd: BorrowedFd<'_>, + filename: &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, filename, mode)) } } @@ -214,6 +227,10 @@ pub(crate) fn seek(fd: BorrowedFd<'_>, pos: SeekFrom) -> io::Result { } SeekFrom::End(offset) => (SEEK_END, offset), SeekFrom::Current(offset) => (SEEK_CUR, offset), + #[cfg(any(freebsdlike, target_os = "linux", target_os = "solaris"))] + SeekFrom::Data(offset) => (SEEK_DATA, offset), + #[cfg(any(freebsdlike, target_os = "linux", target_os = "solaris"))] + SeekFrom::Hole(offset) => (SEEK_HOLE, offset), }; _seek(fd, offset, whence) } @@ -404,7 +421,23 @@ pub(crate) fn fdatasync(fd: BorrowedFd<'_>) -> io::Result<()> { #[inline] pub(crate) fn flock(fd: BorrowedFd<'_>, operation: FlockOperation) -> io::Result<()> { - unsafe { ret(syscall!(__NR_flock, fd, c_uint(operation as c::c_uint))) } + 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] @@ -1016,6 +1049,58 @@ pub(crate) fn fcntl_add_seals(fd: BorrowedFd<'_>, seals: SealFlags) -> io::Resul } } +#[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), + }; + + unsafe { + 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, + + ..core::mem::zeroed() + }; + + #[cfg(target_pointer_width = "32")] + { + ret(syscall_readonly!( + __NR_fcntl64, + fd, + c_uint(cmd), + by_ref(&lock) + )) + } + #[cfg(target_pointer_width = "64")] + { + ret(syscall_readonly!( + __NR_fcntl, + fd, + c_uint(cmd), + by_ref(&lock) + )) + } + } +} + #[inline] pub(crate) fn rename(oldname: &CStr, newname: &CStr) -> io::Result<()> { #[cfg(target_arch = "riscv64")] @@ -1195,6 +1280,16 @@ pub(crate) fn getdents(fd: BorrowedFd<'_>, dirent: &mut [u8]) -> io::Result, + dirent: &mut [MaybeUninit], +) -> io::Result { + 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<'_>, @@ -1317,24 +1412,11 @@ pub(crate) fn accessat( #[inline] pub(crate) fn copy_file_range( - fd_in: BorrowedFd<'_>, - off_in: Option<&mut u64>, - fd_out: BorrowedFd<'_>, - off_out: Option<&mut u64>, - len: u64, -) -> io::Result { - let len: usize = len.try_into().unwrap_or(usize::MAX); - _copy_file_range(fd_in, off_in, fd_out, off_out, len, 0).map(|result| result as u64) -} - -#[inline] -fn _copy_file_range( fd_in: BorrowedFd<'_>, off_in: Option<&mut u64>, fd_out: BorrowedFd<'_>, off_out: Option<&mut u64>, len: usize, - flags: c::c_uint, ) -> io::Result { unsafe { ret_usize(syscall!( @@ -1344,7 +1426,7 @@ fn _copy_file_range( fd_out, opt_mut(off_out), pass_usize(len), - c_uint(flags) + c_uint(0) )) } } @@ -1382,3 +1464,49 @@ pub(crate) fn sendfile( )) } } + +#[inline] +#[cfg(any(target_os = "android", target_os = "linux"))] +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] +#[cfg(any(target_os = "android", target_os = "linux"))] +pub(crate) fn unmount(target: &CStr, flags: super::types::UnmountFlags) -> io::Result<()> { + unsafe { ret(syscall_readonly!(__NR_umount2, target, flags)) } +} + +#[inline] +pub(crate) fn inotify_init1(flags: inotify::CreateFlags) -> io::Result { + 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 { + 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))) } +} diff --git a/vendor/rustix/src/backend/linux_raw/fs/types.rs b/vendor/rustix/src/backend/linux_raw/fs/types.rs index a8d225ede..9bafb8ac0 100644 --- a/vendor/rustix/src/backend/linux_raw/fs/types.rs +++ b/vendor/rustix/src/backend/linux_raw/fs/types.rs @@ -122,6 +122,32 @@ impl Mode { } } +impl From 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 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`]. /// @@ -198,6 +224,9 @@ bitflags! { /// `O_NOATIME` const NOATIME = linux_raw_sys::general::O_NOATIME; + + /// `O_DIRECT` + const DIRECT = linux_raw_sys::general::O_DIRECT; } } @@ -515,9 +544,10 @@ bitflags! { } } -/// `LOCK_*` constants for use with [`flock`] +/// `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 { @@ -637,10 +667,106 @@ pub type FsWord = linux_raw_sys::general::__fsword_t; #[cfg(target_arch = "mips64")] pub type FsWord = i64; -pub use linux_raw_sys::general::{UTIME_NOW, UTIME_OMIT}; +#[cfg(any(target_os = "android", target_os = "linux"))] +bitflags! { + /// `MS_*` constants for use with [`mount`]. + /// + /// [`mount`]: crate::fs::mount + pub struct MountFlags: c::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; -/// `PROC_SUPER_MAGIC`—The magic number for the procfs filesystem. -pub const PROC_SUPER_MAGIC: FsWord = linux_raw_sys::general::PROC_SUPER_MAGIC as FsWord; + /// `MS_REC` + const REC = linux_raw_sys::general::MS_REC; -/// `NFS_SUPER_MAGIC`—The magic number for the NFS filesystem. -pub const NFS_SUPER_MAGIC: FsWord = linux_raw_sys::general::NFS_SUPER_MAGIC as FsWord; + /// `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; + } +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +bitflags! { + /// `MS_*` constants for use with [`change_mount`]. + /// + /// [`change_mount`]: crate::fs::mount::change_mount + pub struct MountPropagationFlags: c::c_uint { + /// `MS_SHARED` + const SHARED = linux_raw_sys::general::MS_SHARED; + /// `MS_PRIVATE` + const PRIVATE = linux_raw_sys::general::MS_PRIVATE; + /// `MS_SLAVE` + const SLAVE = 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; + } +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +bitflags! { + pub(crate) struct InternalMountFlags: c::c_uint { + const REMOUNT = linux_raw_sys::general::MS_REMOUNT; + const MOVE = linux_raw_sys::general::MS_MOVE; + } +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +pub(crate) struct MountFlagsArg(pub(crate) c::c_uint); + +#[cfg(any(target_os = "android", target_os = "linux"))] +bitflags! { + /// `MNT_*` constants for use with [`unmount`]. + /// + /// [`unmount`]: crate::fs::mount::unmount + pub struct UnmountFlags: c::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; + } +} diff --git a/vendor/rustix/src/backend/linux_raw/io/epoll.rs b/vendor/rustix/src/backend/linux_raw/io/epoll.rs index d55ad75b1..3fc6462a2 100644 --- a/vendor/rustix/src/backend/linux_raw/io/epoll.rs +++ b/vendor/rustix/src/backend/linux_raw/io/epoll.rs @@ -6,17 +6,17 @@ //! //! # Examples //! -//! ```rust,no_run +//! ```no_run //! # #![cfg_attr(io_lifetimes_use_std, feature(io_safety))] //! # #[cfg(feature = "net")] //! # fn main() -> std::io::Result<()> { //! use io_lifetimes::AsFd; -//! use rustix::io::epoll::{self, Epoll}; -//! use rustix::io::{ioctl_fionbio, read, write}; +//! use rustix::io::{epoll, ioctl_fionbio, read, write}; //! use rustix::net::{ //! accept, bind_v4, listen, socket, AddressFamily, Ipv4Addr, Protocol, SocketAddrV4, //! SocketType, //! }; +//! use std::collections::HashMap; //! use std::os::unix::io::AsRawFd; //! //! // Create a socket and listen on it. @@ -26,29 +26,40 @@ //! //! // Create an epoll object. Using `Owning` here means the epoll object will //! // take ownership of the file descriptors registered with it. -//! let epoll = Epoll::new(epoll::CreateFlags::CLOEXEC, epoll::Owning::new())?; -//! -//! // Remember the socket raw fd, which we use for comparisons only. -//! let raw_listen_sock = listen_sock.as_fd().as_raw_fd(); +//! let epoll = epoll::epoll_create(epoll::CreateFlags::CLOEXEC)?; //! //! // Register the socket with the epoll object. -//! epoll.add(listen_sock, epoll::EventFlags::IN)?; +//! epoll::epoll_add(&epoll, &listen_sock, 1, epoll::EventFlags::IN)?; +//! +//! // Keep track of the sockets we've opened. +//! let mut next_id = 2; +//! let mut sockets = HashMap::new(); //! //! // Process events. //! let mut event_list = epoll::EventVec::with_capacity(4); //! loop { -//! epoll.wait(&mut event_list, -1)?; +//! epoll::epoll_wait(&epoll, &mut event_list, -1)?; //! for (_event_flags, target) in &event_list { -//! if target.as_raw_fd() == raw_listen_sock { +//! if target == 1 { //! // Accept a new connection, set it to non-blocking, and //! // register to be notified when it's ready to write to. -//! let conn_sock = accept(&*target)?; +//! let conn_sock = accept(&listen_sock)?; //! ioctl_fionbio(&conn_sock, true)?; -//! epoll.add(conn_sock, epoll::EventFlags::OUT | epoll::EventFlags::ET)?; +//! epoll::epoll_add( +//! &epoll, +//! &conn_sock, +//! next_id, +//! epoll::EventFlags::OUT | epoll::EventFlags::ET, +//! )?; +//! +//! // Keep track of the socket. +//! sockets.insert(next_id, conn_sock); +//! next_id += 1; //! } else { //! // Write a message to the stream and then unregister it. -//! write(&*target, b"hello\n")?; -//! let _ = epoll.del(target)?; +//! let target = sockets.remove(&target).unwrap(); +//! write(&target, b"hello\n")?; +//! let _ = epoll::epoll_del(&epoll, &target)?; //! } //! } //! } @@ -60,17 +71,11 @@ #![allow(unsafe_code)] use super::super::c; -use crate::backend::io::syscalls::{epoll_add, epoll_create, epoll_del, epoll_mod, epoll_wait}; -use crate::fd::{AsFd, AsRawFd, BorrowedFd, OwnedFd, RawFd}; -#[cfg(feature = "std")] -use crate::fd::{FromRawFd, IntoRawFd}; +use crate::backend::io::syscalls; +use crate::fd::{AsFd, AsRawFd, OwnedFd}; use crate::io; use alloc::vec::Vec; use bitflags::bitflags; -use core::fmt; -use core::marker::PhantomData; -use core::ops::Deref; -use core::ptr::null; bitflags! { /// `EPOLL_*` for use with [`Epoll::new`]. @@ -99,6 +104,24 @@ bitflags! { /// `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; @@ -113,351 +136,127 @@ bitflags! { } } -/// A reference to a `T`. -pub struct Ref<'a, T> { - t: T, - _phantom: PhantomData<&'a T>, -} - -impl<'a, T> Ref<'a, T> { - #[inline] - fn new(t: T) -> Self { - Self { - t, - _phantom: PhantomData, - } - } - - #[inline] - fn consume(self) -> T { - self.t - } -} - -impl<'a, T> Deref for Ref<'a, T> { - type Target = T; - - #[inline] - fn deref(&self) -> &T { - &self.t - } -} - -impl<'a, T: fmt::Debug> fmt::Debug for Ref<'a, T> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - self.t.fmt(fmt) - } -} - -/// A trait for data stored within an [`Epoll`] instance. -pub trait Context { - /// The type of an element owned by this context. - type Data; - - /// The type of a value used to refer to an element owned by this context. - type Target: AsFd; - - /// Assume ownership of `data`, and returning a `Target`. - fn acquire<'call>(&self, data: Self::Data) -> Ref<'call, Self::Target>; - - /// Encode `target` as a `u64`. The only requirement on this value is that - /// it be decodable by `decode`. - fn encode(&self, target: Ref<'_, Self::Target>) -> u64; - - /// Decode `raw`, which is a value encoded by `encode`, into a `Target`. - /// - /// # Safety - /// - /// `raw` must be a `u64` value returned from `encode`, from the same - /// context, and within the context's lifetime. - unsafe fn decode<'call>(&self, raw: u64) -> Ref<'call, Self::Target>; - - /// Release ownership of the value referred to by `target` and return it. - fn release(&self, target: Ref<'_, Self::Target>) -> Self::Data; -} - -/// A type implementing [`Context`] where the `Data` type is `BorrowedFd<'a>`. -pub struct Borrowing<'a> { - _phantom: PhantomData>, -} - -impl<'a> Context for Borrowing<'a> { - type Data = BorrowedFd<'a>; - type Target = BorrowedFd<'a>; - - #[inline] - fn acquire<'call>(&self, data: Self::Data) -> Ref<'call, Self::Target> { - Ref::new(data) - } - - #[inline] - fn encode(&self, target: Ref<'_, Self::Target>) -> u64 { - target.as_raw_fd() as u64 - } - - #[inline] - unsafe fn decode<'call>(&self, raw: u64) -> Ref<'call, Self::Target> { - Ref::new(BorrowedFd::<'a>::borrow_raw(raw as RawFd)) - } - - #[inline] - fn release(&self, target: Ref<'_, Self::Target>) -> Self::Data { - target.consume() - } -} - -/// A type implementing [`Context`] where the `Data` type is `T`, a type -/// implementing `From` and `From of OwnedFd`. +/// `epoll_create1(flags)`—Creates a new `Epoll`. /// -/// This may be used with [`OwnedFd`], or higher-level types like -/// [`std::fs::File`] or [`std::net::TcpStream`]. -#[cfg(feature = "std")] -pub struct Owning<'context, T: Into + From> { - _phantom: PhantomData<&'context T>, +/// Use the [`CreateFlags::CLOEXEC`] flag to prevent the resulting file +/// descriptor from being implicitly passed across `exec` boundaries. +#[inline] +#[doc(alias = "epoll_create1")] +pub fn epoll_create(flags: CreateFlags) -> io::Result { + syscalls::epoll_create(flags) } -#[cfg(feature = "std")] -impl<'context, T: Into + From> Owning<'context, T> { - /// Creates a new empty `Owning`. - #[allow(clippy::new_without_default)] // This is a specialized type that doesn't need to be generically constructible. - #[inline] - pub fn new() -> Self { - Self { - _phantom: PhantomData, - } - } -} - -#[cfg(feature = "std")] -impl<'context, T: AsFd + Into + From> Context for Owning<'context, T> { - type Data = T; - type Target = BorrowedFd<'context>; - - #[inline] - fn acquire<'call>(&self, data: Self::Data) -> Ref<'call, Self::Target> { - let raw_fd = data.into().into_raw_fd(); - // Safety: `epoll` will assign ownership of the file descriptor to the - // kernel epoll object. We use `Into`+`IntoRawFd` to consume - // the `Data` and extract the raw file descriptor and then "borrow" it - // with `borrow_raw` knowing that the borrow won't outlive the - // kernel epoll object. - unsafe { Ref::new(BorrowedFd::<'context>::borrow_raw(raw_fd)) } - } - - #[inline] - fn encode(&self, target: Ref<'_, Self::Target>) -> u64 { - target.as_fd().as_raw_fd() as u64 - } - - #[inline] - unsafe fn decode<'call>(&self, raw: u64) -> Ref<'call, Self::Target> { - Ref::new(BorrowedFd::<'context>::borrow_raw(raw as RawFd)) - } - - #[inline] - fn release(&self, target: Ref<'_, Self::Target>) -> Self::Data { - let raw_fd = target.consume().as_raw_fd(); - - // Safety: The file descriptor was held by the kernel epoll object and - // is now being released, so we can create a new `OwnedFd` that assumes - // ownership. - unsafe { T::from(io_lifetimes::OwnedFd::from_raw_fd(raw_fd)) } - } -} - -/// An "epoll", an interface to an OS object allowing one to repeatedly wait -/// for events from a set of file descriptors efficiently. -pub struct Epoll { - epoll_fd: OwnedFd, - context: Context, -} - -impl Epoll { - /// `epoll_create1(flags)`—Creates a new `Epoll`. - /// - /// Use the [`CreateFlags::CLOEXEC`] flag to prevent the resulting file - /// descriptor from being implicitly passed across `exec` boundaries. - #[inline] - #[doc(alias = "epoll_create1")] - pub fn new(flags: CreateFlags, context: Context) -> io::Result { - // Safety: We're calling `epoll_create1` via FFI and we know how it - // behaves. - Ok(Self { - epoll_fd: epoll_create(flags)?, - context, - }) - } - - /// `epoll_ctl(self, EPOLL_CTL_ADD, data, event)`—Adds an element to an - /// `Epoll`. - /// - /// This registers interest in any of the events set in `events` occurring - /// on the file descriptor associated with `data`. - #[doc(alias = "epoll_ctl")] - pub fn add( - &self, - data: Context::Data, - event_flags: EventFlags, - ) -> io::Result> { - // Safety: We're calling `epoll_ctl` via FFI and we know how it - // behaves. - unsafe { - let target = self.context.acquire(data); - let raw_fd = target.as_fd().as_raw_fd(); - let encoded = self.context.encode(target); - epoll_add( - self.epoll_fd.as_fd(), - raw_fd, - &linux_raw_sys::general::epoll_event { - events: event_flags.bits(), - data: encoded, - }, - )?; - Ok(self.context.decode(encoded)) - } - } - - /// `epoll_ctl(self, EPOLL_CTL_MOD, target, event)`—Modifies an element in - /// this `Epoll`. - /// - /// This sets the events of interest with `target` to `events`. - #[doc(alias = "epoll_ctl")] - pub fn mod_( - &self, - target: Ref<'_, Context::Target>, - event_flags: EventFlags, - ) -> io::Result<()> { - let raw_fd = target.as_fd().as_raw_fd(); - let encoded = self.context.encode(target); - // Safety: We're calling `epoll_ctl` via FFI and we know how it - // behaves. - unsafe { - epoll_mod( - self.epoll_fd.as_fd(), - raw_fd, - &linux_raw_sys::general::epoll_event { - events: event_flags.bits(), - data: encoded, - }, - ) - } - } - - /// `epoll_ctl(self, EPOLL_CTL_DEL, target, NULL)`—Removes an element in - /// this `Epoll`. - /// - /// This also returns the owning `Data`. - #[doc(alias = "epoll_ctl")] - pub fn del(&self, target: Ref<'_, Context::Target>) -> io::Result { - // Safety: We're calling `epoll_ctl` via FFI and we know how it - // behaves. - unsafe { - let raw_fd = target.as_fd().as_raw_fd(); - epoll_del(self.epoll_fd.as_fd(), raw_fd)?; - } - Ok(self.context.release(target)) - } - - /// `epoll_wait(self, events, timeout)`—Waits for registered events of - /// interest. - /// - /// For each event of interest, an element is written to `events`. On - /// success, this returns the number of written elements. - #[doc(alias = "epoll_wait")] - pub fn wait<'context>( - &'context self, - event_list: &mut EventVec<'context, Context>, - timeout: c::c_int, - ) -> io::Result<()> { - // Safety: We're calling `epoll_wait` via FFI and we know how it - // behaves. - unsafe { - event_list.events.set_len(0); - let nfds = epoll_wait( - self.epoll_fd.as_fd(), - event_list.events[..].as_mut_ptr().cast(), - event_list.events.capacity(), - timeout, - )?; - event_list.events.set_len(nfds); - event_list.context = &self.context; - } - - Ok(()) - } -} - -#[cfg(feature = "std")] -impl<'context, T: AsFd + Into + From> AsRawFd for Epoll> { - fn as_raw_fd(&self) -> RawFd { - self.epoll_fd.as_raw_fd() - } -} - -#[cfg(feature = "std")] -impl<'context, T: AsFd + Into + From> IntoRawFd for Epoll> { - fn into_raw_fd(self) -> RawFd { - self.epoll_fd.into_raw_fd() - } -} - -#[cfg(feature = "std")] -impl<'context, T: AsFd + Into + From> FromRawFd for Epoll> { - unsafe fn from_raw_fd(fd: RawFd) -> Self { - Self { - epoll_fd: OwnedFd::from_raw_fd(fd), - context: Owning::new(), - } +/// `epoll_ctl(self, EPOLL_CTL_ADD, data, event)`—Adds an element to an +/// `Epoll`. +/// +/// This registers interest in any of the events set in `events` occurring +/// on the file descriptor associated with `data`. +/// +/// Note that if `epoll_del` is not called on the I/O source passed into +/// this function before the I/O source is `close`d, then the `epoll` will +/// act as if the I/O source is still registered with it. This can lead to +/// spurious events being returned from `epoll_wait`. If a file descriptor +/// is an `Arc`, then `epoll` can be thought to maintain +/// a `Weak` to the file descriptor. +#[doc(alias = "epoll_ctl")] +pub fn epoll_add( + epoll: impl AsFd, + source: impl AsFd, + data: u64, + event_flags: EventFlags, +) -> io::Result<()> { + // SAFETY: We're calling `epoll_ctl` via FFI and we know how it + // behaves. + unsafe { + syscalls::epoll_add( + epoll.as_fd(), + source.as_fd().as_raw_fd(), + &linux_raw_sys::general::epoll_event { + events: event_flags.bits(), + data, + }, + ) } } -#[cfg(feature = "std")] -impl<'context, T: AsFd + Into + From> AsFd for Epoll> { - fn as_fd(&self) -> BorrowedFd<'_> { - self.epoll_fd.as_fd() +/// `epoll_ctl(self, EPOLL_CTL_MOD, target, event)`—Modifies an element in +/// this `Epoll`. +/// +/// This sets the events of interest with `target` to `events`. +#[doc(alias = "epoll_ctl")] +pub fn epoll_mod( + epoll: impl AsFd, + source: impl AsFd, + data: u64, + event_flags: EventFlags, +) -> io::Result<()> { + // SAFETY: We're calling `epoll_ctl` via FFI and we know how it + // behaves. + unsafe { + let raw_fd = source.as_fd().as_raw_fd(); + syscalls::epoll_mod( + epoll.as_fd(), + raw_fd, + &linux_raw_sys::general::epoll_event { + events: event_flags.bits(), + data, + }, + ) } } -#[cfg(feature = "std")] -impl<'context, T: AsFd + Into + From> From>> - for OwnedFd -{ - fn from(epoll: Epoll>) -> Self { - epoll.epoll_fd +/// `epoll_ctl(self, EPOLL_CTL_DEL, target, NULL)`—Removes an element in +/// this `Epoll`. +/// +/// This also returns the owning `Data`. +#[doc(alias = "epoll_ctl")] +pub fn epoll_del(epoll: impl AsFd, source: impl AsFd) -> io::Result<()> { + // SAFETY: We're calling `epoll_ctl` via FFI and we know how it + // behaves. + unsafe { + let raw_fd = source.as_fd().as_raw_fd(); + syscalls::epoll_del(epoll.as_fd(), raw_fd) } } -#[cfg(feature = "std")] -impl<'context, T: AsFd + Into + From> From - for Epoll> -{ - fn from(fd: OwnedFd) -> Self { - Self { - epoll_fd: fd, - context: Owning::new(), - } - } +/// `epoll_wait(self, events, timeout)`—Waits for registered events of +/// interest. +/// +/// For each event of interest, an element is written to `events`. On +/// success, this returns the number of written elements. +pub fn epoll_wait( + epoll: impl AsFd, + event_list: &mut EventVec, + timeout: c::c_int, +) -> io::Result<()> { + // SAFETY: We're calling `epoll_wait` via FFI and we know how it + // behaves. + unsafe { + event_list.events.set_len(0); + let nfds = syscalls::epoll_wait( + epoll.as_fd(), + event_list.events[..].as_mut_ptr().cast(), + event_list.events.capacity(), + timeout, + )?; + event_list.events.set_len(nfds); + } + + Ok(()) } /// An iterator over the `Event`s in an `EventVec`. -pub struct Iter<'context, Context: self::Context> { - iter: core::slice::Iter<'context, Event>, - context: *const Context, - _phantom: PhantomData<&'context Context>, +pub struct Iter<'a> { + iter: core::slice::Iter<'a, Event>, } -impl<'context, Context: self::Context> Iterator for Iter<'context, Context> { - type Item = (EventFlags, Ref<'context, Context::Target>); +impl<'a> Iterator for Iter<'a> { + type Item = (EventFlags, u64); fn next(&mut self) -> Option { - self.iter.next().map(|event| { - // Safety: `self.context` is guaranteed to be valid because we hold - // `'context` for it. And we know this event is associated with this - // context because `wait` sets both. - let decoded = unsafe { (*self.context).decode(event.encoded) }; - - (event.event_flags, decoded) - }) + self.iter + .next() + .map(|event| (event.event_flags, event.data)) } } @@ -466,28 +265,22 @@ impl<'context, Context: self::Context> Iterator for Iter<'context, Context> { #[cfg_attr(target_arch = "x86_64", repr(packed))] struct Event { // Match the layout of `linux_raw_sys::general::epoll_event`. We just use a - // `u64` instead of the full union; `Context` implementations will simply - // need to deal with casting the value into and out of the `u64` - // themselves. + // `u64` instead of the full union. event_flags: EventFlags, - encoded: u64, + data: u64, } /// A vector of `Event`s, plus context for interpreting them. -pub struct EventVec<'context, Context: self::Context> { +pub struct EventVec { events: Vec, - context: *const Context, - _phantom: PhantomData<&'context Context>, } -impl<'context, Context: self::Context> EventVec<'context, Context> { +impl EventVec { /// Constructs an `EventVec` with memory for `capacity` `Event`s. #[inline] pub fn with_capacity(capacity: usize) -> Self { Self { events: Vec::with_capacity(capacity), - context: null(), - _phantom: PhantomData, } } @@ -523,11 +316,9 @@ impl<'context, Context: self::Context> EventVec<'context, Context> { /// Returns an iterator over the `Event`s in this `EventVec`. #[inline] - pub fn iter(&self) -> Iter<'_, Context> { + pub fn iter(&self) -> Iter<'_> { Iter { iter: self.events.iter(), - context: self.context, - _phantom: PhantomData, } } @@ -544,9 +335,9 @@ impl<'context, Context: self::Context> EventVec<'context, Context> { } } -impl<'context, Context: self::Context> IntoIterator for &'context EventVec<'context, Context> { - type IntoIter = Iter<'context, Context>; - type Item = (EventFlags, Ref<'context, Context::Target>); +impl<'a> IntoIterator for &'a EventVec { + type IntoIter = Iter<'a>; + type Item = (EventFlags, u64); #[inline] fn into_iter(self) -> Self::IntoIter { diff --git a/vendor/rustix/src/backend/linux_raw/io/errno.rs b/vendor/rustix/src/backend/linux_raw/io/errno.rs index 5c7b2fcd5..b01910138 100644 --- a/vendor/rustix/src/backend/linux_raw/io/errno.rs +++ b/vendor/rustix/src/backend/linux_raw/io/errno.rs @@ -69,7 +69,7 @@ impl Errno { // TODO: Use Range::contains, once that's `const`. const_assert!(encoded >= 0xf001); - // Safety: Linux syscalls return negated error values in the range + // SAFETY: Linux syscalls return negated error values in the range // `-4095..0`, which we just asserted. unsafe { Self(encoded) } } @@ -82,7 +82,7 @@ pub(in crate::backend) fn try_decode_c_int( raw: RetReg, ) -> io::Result { if raw.is_in_range(-4095..0) { - // Safety: `raw` must be in `-4095..0`, and we just checked that raw is + // 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()) }); } @@ -97,7 +97,7 @@ pub(in crate::backend) fn try_decode_c_uint( raw: RetReg, ) -> io::Result { if raw.is_in_range(-4095..0) { - // Safety: `raw` must be in `-4095..0`, and we just checked that raw is + // 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()) }); } @@ -110,7 +110,7 @@ pub(in crate::backend) fn try_decode_c_uint( #[inline] pub(in crate::backend) fn try_decode_usize(raw: RetReg) -> io::Result { if raw.is_in_range(-4095..0) { - // Safety: `raw` must be in `-4095..0`, and we just checked that raw is + // 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()) }); } @@ -125,7 +125,7 @@ pub(in crate::backend) fn try_decode_void_star( raw: RetReg, ) -> 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 + // 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()) }); } @@ -139,7 +139,7 @@ pub(in crate::backend) fn try_decode_void_star( #[inline] pub(in crate::backend) fn try_decode_u64(raw: RetReg) -> io::Result { if raw.is_in_range(-4095..0) { - // Safety: `raw` must be in `-4095..0`, and we just checked that raw is + // 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()) }); } @@ -236,6 +236,13 @@ pub(in crate::backend) fn decode_usize_infallible(raw: RetReg(raw: RetReg) -> c::c_uint { + raw.decode_c_uint() +} + impl Errno { /// `EACCES` #[doc(alias = "ACCES")] diff --git a/vendor/rustix/src/backend/linux_raw/io/syscalls.rs b/vendor/rustix/src/backend/linux_raw/io/syscalls.rs index 2cc7898af..3acf9ffdb 100644 --- a/vendor/rustix/src/backend/linux_raw/io/syscalls.rs +++ b/vendor/rustix/src/backend/linux_raw/io/syscalls.rs @@ -32,7 +32,7 @@ use linux_raw_sys::general::{ epoll_event, EPOLL_CTL_ADD, EPOLL_CTL_DEL, EPOLL_CTL_MOD, F_DUPFD_CLOEXEC, F_GETFD, F_SETFD, UIO_MAXIOV, }; -use linux_raw_sys::ioctl::{BLKPBSZGET, BLKSSZGET, FIONBIO, FIONREAD, TIOCEXCL, TIOCNXCL}; +use linux_raw_sys::ioctl::{BLKPBSZGET, BLKSSZGET, FICLONE, FIONBIO, FIONREAD, TIOCEXCL, TIOCNXCL}; #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] use { super::super::conv::{opt_ref, size_of}, @@ -352,6 +352,11 @@ pub(crate) fn ioctl_blkpbszget(fd: BorrowedFd) -> io::Result { } } +#[inline] +pub(crate) fn ioctl_ficlone(fd: BorrowedFd<'_>, src_fd: BorrowedFd<'_>) -> io::Result<()> { + unsafe { ret(syscall_readonly!(__NR_ioctl, fd, c_uint(FICLONE), src_fd)) } +} + #[cfg(all(feature = "fs", feature = "net"))] pub(crate) fn is_read_write(fd: BorrowedFd<'_>) -> io::Result<(bool, bool)> { let (mut read, mut write) = crate::fs::fd::_is_file_read_write(fd)?; diff --git a/vendor/rustix/src/backend/linux_raw/io/types.rs b/vendor/rustix/src/backend/linux_raw/io/types.rs index 51ab61d94..cb6c6acef 100644 --- a/vendor/rustix/src/backend/linux_raw/io/types.rs +++ b/vendor/rustix/src/backend/linux_raw/io/types.rs @@ -94,9 +94,10 @@ pub(crate) const STDOUT_FILENO: c::c_uint = linux_raw_sys::general::STDOUT_FILEN pub(crate) const STDERR_FILENO: c::c_uint = linux_raw_sys::general::STDERR_FILENO; /// A buffer type used with `vmsplice`. -/// It is guaranteed to be ABI compatible with the iovec type on Unix platforms and WSABUF on Windows. -/// Unlike `IoSlice` and `IoSliceMut` it is semantically like a raw pointer, -/// and therefore can be shared or mutated as needed. +/// It is guaranteed to be ABI compatible with the iovec type on Unix platforms +/// and `WSABUF` on Windows. Unlike `IoSlice` and `IoSliceMut` it is +/// semantically like a raw pointer, and therefore can be shared or mutated as +/// needed. #[repr(transparent)] pub struct IoSliceRaw<'a> { _buf: c::iovec, @@ -104,7 +105,7 @@ pub struct IoSliceRaw<'a> { } impl<'a> IoSliceRaw<'a> { - /// Creates a new IoSlice wrapping a byte slice. + /// Creates a new `IoSlice` wrapping a byte slice. pub fn from_slice(buf: &'a [u8]) -> Self { IoSliceRaw { _buf: c::iovec { @@ -115,7 +116,7 @@ impl<'a> IoSliceRaw<'a> { } } - /// Creates a new IoSlice wrapping a mutable byte slice. + /// Creates a new `IoSlice` wrapping a mutable byte slice. pub fn from_slice_mut(buf: &'a mut [u8]) -> Self { IoSliceRaw { _buf: c::iovec { diff --git a/vendor/rustix/src/backend/linux_raw/io_uring/syscalls.rs b/vendor/rustix/src/backend/linux_raw/io_uring/syscalls.rs index 196676985..16655fe77 100644 --- a/vendor/rustix/src/backend/linux_raw/io_uring/syscalls.rs +++ b/vendor/rustix/src/backend/linux_raw/io_uring/syscalls.rs @@ -6,7 +6,7 @@ #![allow(unsafe_code)] #![allow(clippy::undocumented_unsafe_blocks)] -use super::super::conv::{by_mut, c_uint, pass_usize, ret, ret_c_uint, ret_owned_fd}; +use super::super::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, IoringRegisterOp}; @@ -29,8 +29,8 @@ pub(crate) unsafe fn io_uring_register( opcode: IoringRegisterOp, arg: *const c_void, nr_args: u32, -) -> io::Result<()> { - ret(syscall_readonly!( +) -> io::Result { + ret_c_uint(syscall_readonly!( __NR_io_uring_register, fd, c_uint(opcode as u32), diff --git a/vendor/rustix/src/backend/linux_raw/mod.rs b/vendor/rustix/src/backend/linux_raw/mod.rs index e7e073e32..1b91fc3ab 100644 --- a/vendor/rustix/src/backend/linux_raw/mod.rs +++ b/vendor/rustix/src/backend/linux_raw/mod.rs @@ -14,6 +14,11 @@ //! such as which pointers are array slices, out parameters, or in-out //! parameters, which integers are owned or borrowed file descriptors, etc. +// Weak symbols used by the use-libc-auxv feature for glibc 2.15 support. +#[cfg(feature = "use-libc-auxv")] +#[macro_use] +mod weak; + #[macro_use] mod arch; mod conv; diff --git a/vendor/rustix/src/backend/linux_raw/net/addr.rs b/vendor/rustix/src/backend/linux_raw/net/addr.rs index d5683f34e..b69c6deca 100644 --- a/vendor/rustix/src/backend/linux_raw/net/addr.rs +++ b/vendor/rustix/src/backend/linux_raw/net/addr.rs @@ -71,7 +71,7 @@ impl SocketAddrUnix { if len != 0 && self.unix.sun_path[0] != b'\0' as c::c_char { let end = len as usize - offsetof_sun_path(); let bytes = &self.unix.sun_path[..end]; - // Safety: `from_raw_parts` to convert from `&[c_char]` to `&[u8]`. And + // SAFETY: `from_raw_parts` to convert from `&[c_char]` to `&[u8]`. And // `from_bytes_with_nul_unchecked` since the string is NUL-terminated. unsafe { Some(CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts( @@ -91,7 +91,7 @@ impl SocketAddrUnix { if len != 0 && self.unix.sun_path[0] == b'\0' as c::c_char { let end = len as usize - offsetof_sun_path(); let bytes = &self.unix.sun_path[1..end]; - // Safety: `from_raw_parts` to convert from `&[c_char]` to `&[u8]`. + // SAFETY: `from_raw_parts` to convert from `&[c_char]` to `&[u8]`. unsafe { Some(slice::from_raw_parts(bytes.as_ptr().cast(), bytes.len())) } } else { None diff --git a/vendor/rustix/src/backend/linux_raw/net/syscalls.rs b/vendor/rustix/src/backend/linux_raw/net/syscalls.rs index 7b9947a03..6093cd3a5 100644 --- a/vendor/rustix/src/backend/linux_raw/net/syscalls.rs +++ b/vendor/rustix/src/backend/linux_raw/net/syscalls.rs @@ -1065,6 +1065,16 @@ pub(crate) mod sockopt { }) } + #[inline] + pub(crate) fn get_socket_error(fd: BorrowedFd<'_>) -> io::Result> { + let err: c::c_int = getsockopt(fd, c::SOL_SOCKET as _, c::SO_ERROR)?; + Ok(if err == 0 { + Ok(()) + } else { + Err(crate::io::Errno::from_raw_os_error(err)) + }) + } + #[inline] pub(crate) fn set_ip_ttl(fd: BorrowedFd<'_>, ttl: u32) -> io::Result<()> { setsockopt(fd, c::IPPROTO_IP as _, c::IP_TTL, ttl) diff --git a/vendor/rustix/src/backend/linux_raw/param/auxv.rs b/vendor/rustix/src/backend/linux_raw/param/auxv.rs index acdd9d0e7..741a0564f 100644 --- a/vendor/rustix/src/backend/linux_raw/param/auxv.rs +++ b/vendor/rustix/src/backend/linux_raw/param/auxv.rs @@ -77,7 +77,7 @@ pub(crate) fn linux_execfn() -> &'static CStr { execfn = EXECFN.load(Relaxed); } - // Safety: We assume the `AT_EXECFN` value provided by the kernel is a + // 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()) } } @@ -102,7 +102,7 @@ pub(crate) fn exe_phdrs() -> (*const c::c_void, usize) { pub(in super::super) fn exe_phdrs_slice() -> &'static [Elf_Phdr] { let (phdr, phnum) = exe_phdrs(); - // Safety: We assume the `AT_PHDR` and `AT_PHNUM` values provided by the + // SAFETY: We assume the `AT_PHDR` and `AT_PHNUM` values provided by the // kernel form a valid slice. unsafe { slice::from_raw_parts(phdr.cast(), phnum) } } @@ -177,7 +177,7 @@ fn init_from_auxv_file(auxv: OwnedFd) -> Option<()> { buffer.resize(cur + n, 0_u8); } - // Safety: We loaded from an auxv file into the buffer. + // SAFETY: We loaded from an auxv file into the buffer. unsafe { init_from_auxp(buffer.as_ptr().cast()) } } diff --git a/vendor/rustix/src/backend/linux_raw/param/libc_auxv.rs b/vendor/rustix/src/backend/linux_raw/param/libc_auxv.rs index 1597fd727..a8e291ff6 100644 --- a/vendor/rustix/src/backend/linux_raw/param/libc_auxv.rs +++ b/vendor/rustix/src/backend/linux_raw/param/libc_auxv.rs @@ -5,14 +5,15 @@ //! This uses raw pointers to locate and read the kernel-provided auxv array. #![allow(unsafe_code)] -#[cfg(any(feature = "param", feature = "runtime"))] -use super::super::c; use super::super::elf::*; #[cfg(feature = "param")] use crate::ffi::CStr; #[cfg(feature = "runtime")] use core::slice; +// `getauxval` wasn't supported in glibc until 2.16. +weak!(fn getauxval(libc::c_ulong) -> *mut libc::c_void); + #[cfg(feature = "param")] #[inline] pub(crate) fn page_size() -> usize { @@ -22,35 +23,39 @@ pub(crate) fn page_size() -> usize { #[cfg(feature = "param")] #[inline] pub(crate) fn clock_ticks_per_second() -> u64 { - unsafe { libc::getauxval(libc::AT_CLKTCK) as u64 } + unsafe { libc::sysconf(libc::_SC_CLK_TCK) as u64 } } #[cfg(feature = "param")] #[inline] pub(crate) fn linux_hwcap() -> (usize, usize) { - unsafe { - ( - libc::getauxval(libc::AT_HWCAP) as usize, - libc::getauxval(libc::AT_HWCAP2) as usize, - ) + if let Some(libc_getauxval) = getauxval.get() { + unsafe { + let hwcap = libc_getauxval(libc::AT_HWCAP) as usize; + let hwcap2 = libc_getauxval(libc::AT_HWCAP2) as usize; + (hwcap, hwcap2) + } + } else { + (0, 0) } } #[cfg(feature = "param")] #[inline] pub(crate) fn linux_execfn() -> &'static CStr { - unsafe { - let execfn = libc::getauxval(libc::AT_EXECFN) as *const c::c_char; - CStr::from_ptr(execfn.cast()) + if let Some(libc_getauxval) = getauxval.get() { + unsafe { CStr::from_ptr(libc_getauxval(libc::AT_EXECFN).cast()) } + } else { + cstr!("") } } #[cfg(feature = "runtime")] #[inline] -pub(crate) fn exe_phdrs() -> (*const c::c_void, usize) { +pub(crate) fn exe_phdrs() -> (*const libc::c_void, usize) { unsafe { ( - libc::getauxval(libc::AT_PHDR) as *const c::c_void, + libc::getauxval(libc::AT_PHDR) as *const libc::c_void, libc::getauxval(libc::AT_PHNUM) as usize, ) } @@ -61,7 +66,7 @@ pub(crate) fn exe_phdrs() -> (*const c::c_void, usize) { pub(in super::super) fn exe_phdrs_slice() -> &'static [Elf_Phdr] { let (phdr, phnum) = exe_phdrs(); - // Safety: We assume the `AT_PHDR` and `AT_PHNUM` values provided by the + // SAFETY: We assume the `AT_PHDR` and `AT_PHNUM` values provided by the // kernel form a valid slice. unsafe { slice::from_raw_parts(phdr.cast(), phnum) } } @@ -70,5 +75,9 @@ pub(in super::super) fn exe_phdrs_slice() -> &'static [Elf_Phdr] { /// so if we don't see it, this function returns a null pointer. #[inline] pub(in super::super) fn sysinfo_ehdr() -> *const Elf_Ehdr { - unsafe { libc::getauxval(linux_raw_sys::general::AT_SYSINFO_EHDR.into()) as *const Elf_Ehdr } + if let Some(libc_getauxval) = getauxval.get() { + unsafe { libc_getauxval(linux_raw_sys::general::AT_SYSINFO_EHDR.into()) as *const Elf_Ehdr } + } else { + core::ptr::null() + } } diff --git a/vendor/rustix/src/backend/linux_raw/param/mustang_auxv.rs b/vendor/rustix/src/backend/linux_raw/param/mustang_auxv.rs index e9b89b500..49cb1457c 100644 --- a/vendor/rustix/src/backend/linux_raw/param/mustang_auxv.rs +++ b/vendor/rustix/src/backend/linux_raw/param/mustang_auxv.rs @@ -22,28 +22,28 @@ use linux_raw_sys::general::{ #[cfg(feature = "param")] #[inline] pub(crate) fn page_size() -> usize { - // Safety: This is initialized during program startup. + // SAFETY: This is initialized during program startup. unsafe { PAGE_SIZE } } #[cfg(feature = "param")] #[inline] pub(crate) fn clock_ticks_per_second() -> u64 { - // Safety: This is initialized during program startup. + // SAFETY: This is initialized during program startup. unsafe { CLOCK_TICKS_PER_SECOND as u64 } } #[cfg(feature = "param")] #[inline] pub(crate) fn linux_hwcap() -> (usize, usize) { - // Safety: This is initialized during program startup. + // SAFETY: This is initialized during program startup. unsafe { (HWCAP, HWCAP2) } } #[cfg(feature = "param")] #[inline] pub(crate) fn linux_execfn() -> &'static CStr { - // Safety: This is initialized during program startup. And we + // SAFETY: This is initialized during program startup. And we // assume it's a valid pointer to a NUL-terminated string. unsafe { CStr::from_ptr(EXECFN.0.cast()) } } @@ -51,7 +51,7 @@ pub(crate) fn linux_execfn() -> &'static CStr { #[cfg(feature = "runtime")] #[inline] pub(crate) fn exe_phdrs() -> (*const c_void, usize) { - // Safety: This is initialized during program startup. + // SAFETY: This is initialized during program startup. unsafe { (PHDR.0.cast(), PHNUM) } } @@ -60,7 +60,7 @@ pub(crate) fn exe_phdrs() -> (*const c_void, usize) { pub(in super::super) fn exe_phdrs_slice() -> &'static [Elf_Phdr] { let (phdr, phnum) = exe_phdrs(); - // Safety: We assume the `AT_PHDR` and `AT_PHNUM` values provided by the + // SAFETY: We assume the `AT_PHDR` and `AT_PHNUM` values provided by the // kernel form a valid slice. unsafe { slice::from_raw_parts(phdr.cast(), phnum) } } @@ -69,7 +69,7 @@ pub(in super::super) fn exe_phdrs_slice() -> &'static [Elf_Phdr] { /// so if we don't see it, this function returns a null pointer. #[inline] pub(in super::super) fn sysinfo_ehdr() -> *const Elf_Ehdr { - // Safety: This is initialized during program startup. + // SAFETY: This is initialized during program startup. unsafe { SYSINFO_EHDR.0 } } diff --git a/vendor/rustix/src/backend/linux_raw/process/cpu_set.rs b/vendor/rustix/src/backend/linux_raw/process/cpu_set.rs index 10c5f478e..fc81859d8 100644 --- a/vendor/rustix/src/backend/linux_raw/process/cpu_set.rs +++ b/vendor/rustix/src/backend/linux_raw/process/cpu_set.rs @@ -1,3 +1,5 @@ +//! Rust implementation of the `CPU_*` macro API. + #![allow(non_snake_case)] use super::types::RawCpuSet; diff --git a/vendor/rustix/src/backend/linux_raw/process/syscalls.rs b/vendor/rustix/src/backend/linux_raw/process/syscalls.rs index ac62e6944..f86f8e5b9 100644 --- a/vendor/rustix/src/backend/linux_raw/process/syscalls.rs +++ b/vendor/rustix/src/backend/linux_raw/process/syscalls.rs @@ -12,12 +12,13 @@ use super::super::conv::{ ret_infallible, ret_usize, ret_usize_infallible, size_of, slice_just_addr, slice_mut, zero, }; use super::types::{RawCpuSet, RawUname}; -use crate::fd::BorrowedFd; +use crate::backend::conv::ret_owned_fd; +use crate::fd::{AsRawFd, BorrowedFd, OwnedFd}; use crate::ffi::CStr; use crate::io; use crate::process::{ - Cpuid, Gid, MembarrierCommand, MembarrierQuery, Pid, RawNonZeroPid, RawPid, Resource, Rlimit, - Signal, Uid, WaitOptions, WaitStatus, + Cpuid, Gid, MembarrierCommand, MembarrierQuery, Pid, PidfdFlags, RawNonZeroPid, RawPid, + Resource, Rlimit, Signal, Uid, WaitId, WaitOptions, WaitStatus, WaitidOptions, WaitidStatus, }; use core::convert::TryInto; use core::mem::MaybeUninit; @@ -27,6 +28,9 @@ use linux_raw_sys::general::{ __kernel_gid_t, __kernel_pid_t, __kernel_uid_t, membarrier_cmd, membarrier_cmd_flag, rlimit, rlimit64, PRIO_PGRP, PRIO_PROCESS, PRIO_USER, RLIM64_INFINITY, RLIM_INFINITY, }; +#[cfg(not(target_os = "wasi"))] +#[cfg(feature = "fs")] +use {super::super::conv::ret_c_uint_infallible, crate::fs::Mode}; #[inline] pub(crate) fn chdir(filename: &CStr) -> io::Result<()> { @@ -53,7 +57,7 @@ pub(crate) fn membarrier_query() -> MembarrierQuery { c_uint(0) )) { Ok(query) => { - // Safety: The safety of `from_bits_unchecked` is discussed + // SAFETY: The safety of `from_bits_unchecked` is discussed // [here]. Our "source of truth" is Linux, and here, the // `query` value is coming from Linux, so we know it only // contains "source of truth" valid bits. @@ -235,11 +239,20 @@ pub(crate) fn sched_yield() { pub(crate) fn uname() -> RawUname { let mut uname = MaybeUninit::::uninit(); unsafe { - ret(syscall!(__NR_uname, &mut uname)).unwrap(); + ret_infallible(syscall!(__NR_uname, &mut uname)); uname.assume_init() } } +#[cfg(feature = "fs")] +#[inline] +pub(crate) fn umask(mode: Mode) -> Mode { + unsafe { + // TODO: Use `from_bits_retain` when we switch to bitflags 2.0. + Mode::from_bits_truncate(ret_c_uint_infallible(syscall_readonly!(__NR_umask, mode))) + } +} + #[inline] pub(crate) fn nice(inc: i32) -> io::Result { let priority = if inc > -40 && inc < 40 { @@ -516,6 +529,83 @@ pub(crate) fn _waitpid( } } +#[inline] +pub(crate) fn waitid(id: WaitId<'_>, options: WaitidOptions) -> io::Result> { + // Get the id to wait on. + match id { + WaitId::All => _waitid_all(options), + WaitId::Pid(pid) => _waitid_pid(pid, options), + WaitId::PidFd(fd) => _waitid_pidfd(fd, options), + } +} + +#[inline] +fn _waitid_all(options: WaitidOptions) -> io::Result> { + let mut status = MaybeUninit::::uninit(); + unsafe { + ret(syscall!( + __NR_waitid, + c_uint(c::P_ALL), + c_uint(0), + by_mut(&mut status), + c_int(options.bits() as _), + zero() + ))? + }; + + Ok(unsafe { cvt_waitid_status(status) }) +} + +#[inline] +fn _waitid_pid(pid: Pid, options: WaitidOptions) -> io::Result> { + let mut status = MaybeUninit::::uninit(); + unsafe { + ret(syscall!( + __NR_waitid, + c_uint(c::P_PID), + c_uint(Pid::as_raw(Some(pid))), + by_mut(&mut status), + c_int(options.bits() as _), + zero() + ))? + }; + + Ok(unsafe { cvt_waitid_status(status) }) +} + +#[inline] +fn _waitid_pidfd(fd: BorrowedFd<'_>, options: WaitidOptions) -> io::Result> { + let mut status = MaybeUninit::::uninit(); + unsafe { + ret(syscall!( + __NR_waitid, + c_uint(c::P_PIDFD), + c_uint(fd.as_raw_fd() as _), + by_mut(&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) -> Option { + let status = status.assume_init(); + if status.__bindgen_anon_1.__bindgen_anon_1.si_signo == 0 { + None + } else { + Some(WaitidStatus(status)) + } +} + #[cfg(feature = "runtime")] #[inline] pub(crate) fn exit_group(code: c::c_int) -> ! { @@ -558,3 +648,14 @@ pub(crate) unsafe fn prctl( ) -> io::Result { ret_c_int(syscall!(__NR_prctl, c_int(option), arg2, arg3, arg4, arg5)) } + +#[inline] +pub(crate) fn pidfd_open(pid: Pid, flags: PidfdFlags) -> io::Result { + unsafe { + ret_owned_fd(syscall_readonly!( + __NR_pidfd_open, + pid, + c_int(flags.bits() as _) + )) + } +} diff --git a/vendor/rustix/src/backend/linux_raw/process/wait.rs b/vendor/rustix/src/backend/linux_raw/process/wait.rs index 701b4ac0c..edc564a9f 100644 --- a/vendor/rustix/src/backend/linux_raw/process/wait.rs +++ b/vendor/rustix/src/backend/linux_raw/process/wait.rs @@ -1,7 +1,9 @@ // The functions replacing the C macros use the same names as in libc. #![allow(non_snake_case)] -pub(crate) use linux_raw_sys::general::{WCONTINUED, WNOHANG, WUNTRACED}; +pub(crate) use linux_raw_sys::general::{ + WCONTINUED, WEXITED, WNOHANG, WNOWAIT, WSTOPPED, WUNTRACED, +}; #[inline] pub(crate) fn WIFSTOPPED(status: u32) -> bool { diff --git a/vendor/rustix/src/backend/linux_raw/runtime/tls.rs b/vendor/rustix/src/backend/linux_raw/runtime/tls.rs index 43ed25d7d..8cc156a71 100644 --- a/vendor/rustix/src/backend/linux_raw/runtime/tls.rs +++ b/vendor/rustix/src/backend/linux_raw/runtime/tls.rs @@ -1,3 +1,9 @@ +//! TLS utilities. +//! +//! # Safety +//! +//! This file contains code that reads the raw phdr array pointed to by the +//! kernel-provided AUXV values. #![allow(unsafe_code)] use super::super::c; @@ -18,7 +24,7 @@ pub(crate) fn startup_tls_info() -> StartupTlsInfo { let phdrs = exe_phdrs_slice(); - // Safety: We assume the phdr array pointer and length the kernel provided + // SAFETY: We assume the phdr array pointer and length the kernel provided // to the process describe a valid phdr array. unsafe { for phdr in phdrs { diff --git a/vendor/rustix/src/backend/linux_raw/termios/syscalls.rs b/vendor/rustix/src/backend/linux_raw/termios/syscalls.rs index a8dda5f81..f5643f3c3 100644 --- a/vendor/rustix/src/backend/linux_raw/termios/syscalls.rs +++ b/vendor/rustix/src/backend/linux_raw/termios/syscalls.rs @@ -41,6 +41,30 @@ pub(crate) fn tcgetattr(fd: BorrowedFd<'_>) -> io::Result { } } +#[inline] +#[cfg(any( + target_arch = "x86", + target_arch = "x86_64", + target_arch = "x32", + target_arch = "riscv64", + target_arch = "aarch64", + target_arch = "arm", + target_arch = "mips", + target_arch = "mips64", +))] +pub(crate) fn tcgetattr2(fd: BorrowedFd<'_>) -> io::Result { + unsafe { + let mut result = MaybeUninit::::uninit(); + ret(syscall!( + __NR_ioctl, + fd, + c_uint(linux_raw_sys::ioctl::TCGETS2), + &mut result + ))?; + Ok(result.assume_init()) + } +} + #[inline] pub(crate) fn tcgetpgrp(fd: BorrowedFd<'_>) -> io::Result { unsafe { @@ -77,6 +101,32 @@ pub(crate) fn tcsetattr( } } +#[inline] +#[cfg(any( + target_arch = "x86", + target_arch = "x86_64", + target_arch = "x32", + target_arch = "riscv64", + target_arch = "aarch64", + target_arch = "arm", + target_arch = "mips", + target_arch = "mips64", +))] +pub(crate) fn tcsetattr2( + fd: BorrowedFd, + optional_actions: OptionalActions, + termios: &crate::termios::Termios2, +) -> io::Result<()> { + unsafe { + ret(syscall_readonly!( + __NR_ioctl, + fd, + c_uint(linux_raw_sys::ioctl::TCSETS2 + optional_actions as u32), + by_ref(termios) + )) + } +} + #[inline] pub(crate) fn tcsendbreak(fd: BorrowedFd) -> io::Result<()> { unsafe { ret(syscall_readonly!(__NR_ioctl, fd, c_uint(TCSBRK), c_uint(0))) } diff --git a/vendor/rustix/src/backend/linux_raw/termios/types.rs b/vendor/rustix/src/backend/linux_raw/termios/types.rs index a44f1eda5..3fe45af98 100644 --- a/vendor/rustix/src/backend/linux_raw/termios/types.rs +++ b/vendor/rustix/src/backend/linux_raw/termios/types.rs @@ -7,13 +7,16 @@ use super::super::c; #[repr(u32)] pub enum OptionalActions { /// `TCSANOW`—Make the change immediately. + #[doc(alias = "TCSANOW")] Now = linux_raw_sys::general::TCSANOW, /// `TCSADRAIN`—Make the change after all output has been transmitted. + #[doc(alias = "TCSADRAIN")] Drain = linux_raw_sys::general::TCSADRAIN, /// `TCSAFLUSH`—Discard any pending input and then make the change /// after all output has been transmitted. + #[doc(alias = "TCSAFLUSH")] Flush = linux_raw_sys::general::TCSAFLUSH, } @@ -24,12 +27,15 @@ pub enum OptionalActions { #[repr(u32)] pub enum QueueSelector { /// `TCIFLUSH`—Flush data received but not read. + #[doc(alias = "TCIFLUSH")] IFlush = linux_raw_sys::general::TCIFLUSH, /// `TCOFLUSH`—Flush data written but not transmitted. + #[doc(alias = "TCOFLUSH")] OFlush = linux_raw_sys::general::TCOFLUSH, /// `TCIOFLUSH`—`IFlush` and `OFlush` combined. + #[doc(alias = "TCIOFLUSH")] IOFlush = linux_raw_sys::general::TCIOFLUSH, } @@ -40,34 +46,60 @@ pub enum QueueSelector { #[repr(u32)] pub enum Action { /// `TCOOFF`—Suspend output. + #[doc(alias = "TCOOFF")] OOff = linux_raw_sys::general::TCOOFF, /// `TCOON`—Restart suspended output. + #[doc(alias = "TCOON")] OOn = linux_raw_sys::general::TCOON, /// `TCIOFF`—Transmits a STOP byte. + #[doc(alias = "TCIOFF")] IOff = linux_raw_sys::general::TCIOFF, /// `TCION`—Transmits a START byte. + #[doc(alias = "TCION")] IOn = linux_raw_sys::general::TCION, } -/// `struct termios` for use with [`tcgetattr`]. +/// `struct termios` for use with [`tcgetattr`] and [`tcsetattr`]. /// /// [`tcgetattr`]: crate::termios::tcgetattr +/// [`tcsetattr`]: crate::termios::tcsetattr +#[doc(alias = "termios")] pub type Termios = linux_raw_sys::general::termios; +/// `struct termios2` for use with [`tcgetattr2`] and [`tcsetattr2`]. +/// +/// [`tcgetattr2`]: crate::termios::tcgetattr2 +/// [`tcsetattr2`]: crate::termios::tcsetattr2 +#[cfg(any( + target_arch = "x86", + target_arch = "x86_64", + target_arch = "x32", + target_arch = "riscv64", + target_arch = "aarch64", + target_arch = "arm", + target_arch = "mips", + target_arch = "mips64", +))] +#[doc(alias = "termios2")] +pub type Termios2 = linux_raw_sys::general::termios2; + /// `struct winsize` for use with [`tcgetwinsize`]. /// /// [`tcgetwinsize`]: crate::termios::tcgetwinsize +#[doc(alias = "winsize")] pub type Winsize = linux_raw_sys::general::winsize; /// `tcflag_t`—A type for the flags fields of [`Termios`]. +#[doc(alias = "tcflag_t")] pub type Tcflag = linux_raw_sys::general::tcflag_t; /// `speed_t`—A return type for [`cfsetspeed`] and similar. /// /// [`cfsetspeed`]: crate::termios::cfsetspeed +#[doc(alias = "speed_t")] pub type Speed = linux_raw_sys::general::speed_t; /// `VINTR` @@ -353,6 +385,9 @@ pub const B3500000: Speed = linux_raw_sys::general::B3500000; #[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] pub const B4000000: Speed = linux_raw_sys::general::B4000000; +/// `BOTHER` +pub const BOTHER: c::c_uint = linux_raw_sys::general::BOTHER; + /// `CSIZE` pub const CSIZE: c::c_uint = linux_raw_sys::general::CSIZE; diff --git a/vendor/rustix/src/backend/linux_raw/thread/syscalls.rs b/vendor/rustix/src/backend/linux_raw/thread/syscalls.rs index 2ec3e43e8..af2c9ee8a 100644 --- a/vendor/rustix/src/backend/linux_raw/thread/syscalls.rs +++ b/vendor/rustix/src/backend/linux_raw/thread/syscalls.rs @@ -294,3 +294,65 @@ pub(crate) fn setns(fd: BorrowedFd, nstype: c::c_int) -> io::Result { pub(crate) fn unshare(flags: crate::thread::UnshareFlags) -> io::Result<()> { unsafe { ret(syscall_readonly!(__NR_unshare, c_uint(flags.bits()))) } } + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[inline] +pub(crate) fn capget( + header: &mut linux_raw_sys::general::__user_cap_header_struct, + data: &mut [MaybeUninit], +) -> io::Result<()> { + let header: *mut _ = header; + unsafe { ret(syscall!(__NR_capget, header, data.as_mut_ptr())) } +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[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<()> { + let header: *mut _ = header; + unsafe { ret(syscall!(__NR_capset, header, data.as_ptr())) } +} + +#[inline] +pub(crate) fn setuid_thread(uid: crate::process::Uid) -> io::Result<()> { + unsafe { ret(syscall_readonly!(__NR_setuid, uid)) } +} + +#[inline] +pub(crate) fn setresuid_thread( + ruid: crate::process::Uid, + euid: crate::process::Uid, + suid: crate::process::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::process::Gid) -> io::Result<()> { + unsafe { ret(syscall_readonly!(__NR_setgid, gid)) } +} + +#[inline] +pub(crate) fn setresgid_thread( + rgid: crate::process::Gid, + egid: crate::process::Gid, + sgid: crate::process::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)) + } +} diff --git a/vendor/rustix/src/backend/linux_raw/time/syscalls.rs b/vendor/rustix/src/backend/linux_raw/time/syscalls.rs index 6e73a921b..c039393ef 100644 --- a/vendor/rustix/src/backend/linux_raw/time/syscalls.rs +++ b/vendor/rustix/src/backend/linux_raw/time/syscalls.rs @@ -65,6 +65,47 @@ unsafe fn clock_getres_old(which_clock: ClockId, result: &mut MaybeUninit<__kern ); } +#[cfg(feature = "time")] +#[inline] +pub(crate) fn clock_settime(which_clock: ClockId, timespec: __kernel_timespec) -> io::Result<()> { + #[cfg(target_pointer_width = "32")] + unsafe { + match ret(syscall_readonly!( + __NR_clock_settime64, + which_clock, + by_ref(×pec) + )) { + Err(io::Errno::NOSYS) => clock_settime_old(which_clock, timespec), + otherwise => otherwise, + } + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret(syscall_readonly!( + __NR_clock_settime, + which_clock, + by_ref(×pec) + )) + } +} + +#[cfg(feature = "time")] +#[cfg(target_pointer_width = "32")] +unsafe fn clock_settime_old(which_clock: ClockId, timespec: __kernel_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, + which_clock, + by_ref(&old_timespec) + )) +} + #[cfg(feature = "time")] #[inline] pub(crate) fn timerfd_create(clockid: TimerfdClockId, flags: TimerfdFlags) -> io::Result { diff --git a/vendor/rustix/src/backend/linux_raw/vdso.rs b/vendor/rustix/src/backend/linux_raw/vdso.rs index da7910b88..480378b50 100644 --- a/vendor/rustix/src/backend/linux_raw/vdso.rs +++ b/vendor/rustix/src/backend/linux_raw/vdso.rs @@ -55,7 +55,7 @@ fn elf_hash(name: &CStr) -> u32 { /// Create a `Vdso` value by parsing the vDSO at the `sysinfo_ehdr` address. fn init_from_sysinfo_ehdr() -> Option { - // Safety: the auxv initialization code does extensive checks to ensure + // 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 { @@ -255,7 +255,7 @@ impl Vdso { let ver_hash = elf_hash(version); let name_hash = elf_hash(name); - // Safety: The pointers in `self` must be valid. + // SAFETY: The pointers in `self` must be valid. unsafe { let mut chain = *self.bucket.add((name_hash % self.nbucket) as usize); diff --git a/vendor/rustix/src/backend/linux_raw/vdso_wrappers.rs b/vendor/rustix/src/backend/linux_raw/vdso_wrappers.rs index aaa000622..5b2e084ea 100644 --- a/vendor/rustix/src/backend/linux_raw/vdso_wrappers.rs +++ b/vendor/rustix/src/backend/linux_raw/vdso_wrappers.rs @@ -27,7 +27,7 @@ use linux_raw_sys::general::{__kernel_clockid_t, __kernel_timespec}; #[inline] pub(crate) fn clock_gettime(which_clock: ClockId) -> __kernel_timespec { - // Safety: `CLOCK_GETTIME` contains either null or the address of a + // 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 { @@ -64,7 +64,7 @@ pub(crate) fn clock_gettime_dynamic(which_clock: DynamicClockId<'_>) -> io::Resu } }; - // Safety: `CLOCK_GETTIME` contains either null or the address of a + // 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 { @@ -217,7 +217,7 @@ pub(super) type SyscallType = unsafe extern "C" fn(); /// Initialize `CLOCK_GETTIME` and return its value. fn init_clock_gettime() -> ClockGettimeType { init(); - // Safety: Load the function address from static storage that we + // SAFETY: Load the function address from static storage that we // just initialized. unsafe { transmute(CLOCK_GETTIME.load(Relaxed)) } } @@ -226,7 +226,7 @@ fn init_clock_gettime() -> ClockGettimeType { #[cfg(target_arch = "x86")] fn init_syscall() -> SyscallType { init(); - // Safety: Load the function address from static storage that we + // SAFETY: Load the function address from static storage that we // just initialized. unsafe { transmute(SYSCALL.load(Relaxed)) } } @@ -309,7 +309,7 @@ extern "C" { } fn minimal_init() { - // Safety: Store default function addresses in static storage so that if we + // SAFETY: 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. @@ -375,7 +375,7 @@ fn init() { if ok { assert!(!ptr.is_null()); - // Safety: Store the computed function addresses in static storage + // SAFETY: Store the computed function addresses in static storage // so that we don't need to compute it again (but if we do, it doesn't // hurt anything). unsafe { @@ -389,7 +389,7 @@ fn init() { let ptr = vdso.sym(cstr!("LINUX_2.5"), cstr!("__kernel_vsyscall")); assert!(!ptr.is_null()); - // Safety: As above, store the computed function addresses in + // SAFETY: As above, store the computed function addresses in // static storage. unsafe { SYSCALL.store(ptr.cast(), Relaxed); diff --git a/vendor/rustix/src/backend/linux_raw/weak.rs b/vendor/rustix/src/backend/linux_raw/weak.rs new file mode 100644 index 000000000..ae7d6832e --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/weak.rs @@ -0,0 +1,228 @@ +// Implementation derived from `weak` in Rust's +// library/std/src/sys/unix/weak.rs at revision +// fd0cb0cdc21dd9c06025277d772108f8d42cb25f. + +#![allow(unsafe_code)] + +//! Support for "weak linkage" to symbols on Unix +//! +//! Some I/O operations we do in libstd require newer versions of OSes but we +//! need to maintain binary compatibility with older releases for now. In order +//! to use the new functionality when available we use this module for +//! detection. +//! +//! One option to use here is weak linkage, but that is unfortunately only +//! really workable on Linux. Hence, use dlsym to get the symbol value at +//! runtime. This is also done for compatibility with older versions of glibc, +//! and to avoid creating dependencies on `GLIBC_PRIVATE` symbols. It assumes +//! that we've been dynamically linked to the library the symbol comes from, +//! but that is currently always the case for things like libpthread/libc. +//! +//! A long time ago this used weak linkage for the `__pthread_get_minstack` +//! symbol, but that caused Debian to detect an unnecessarily strict versioned +//! dependency on libc6 (#23628). + +// There are a variety of `#[cfg]`s controlling which targets are involved in +// each instance of `weak!` and `syscall!`. Rather than trying to unify all of +// that, we'll just allow that some unix targets don't use this module at all. +#![allow(dead_code, unused_macros)] +#![allow(clippy::doc_markdown)] + +use crate::ffi::CStr; +use core::ffi::c_void; +use core::ptr::null_mut; +use core::sync::atomic::{self, AtomicPtr, Ordering}; +use core::{marker, mem}; + +const NULL: *mut c_void = null_mut(); +const INVALID: *mut c_void = 1 as *mut c_void; + +macro_rules! weak { + ($vis:vis fn $name:ident($($t:ty),*) -> $ret:ty) => ( + #[allow(non_upper_case_globals)] + $vis static $name: $crate::backend::weak::Weak $ret> = + $crate::backend::weak::Weak::new(concat!(stringify!($name), '\0')); + ) +} + +pub(crate) struct Weak { + name: &'static str, + addr: AtomicPtr, + _marker: marker::PhantomData, +} + +impl Weak { + pub(crate) const fn new(name: &'static str) -> Self { + Self { + name, + addr: AtomicPtr::new(INVALID), + _marker: marker::PhantomData, + } + } + + pub(crate) fn get(&self) -> Option { + assert_eq!(mem::size_of::(), mem::size_of::()); + unsafe { + // Relaxed is fine here because we fence before reading through the + // pointer (see the comment below). + match self.addr.load(Ordering::Relaxed) { + INVALID => self.initialize(), + NULL => None, + addr => { + let func = mem::transmute_copy::<*mut c_void, F>(&addr); + // The caller is presumably going to read through this value + // (by calling the function we've dlsymed). This means we'd + // need to have loaded it with at least C11's consume + // ordering in order to be guaranteed that the data we read + // from the pointer isn't from before the pointer was + // stored. Rust has no equivalent to memory_order_consume, + // so we use an acquire fence (sorry, ARM). + // + // Now, in practice this likely isn't needed even on CPUs + // where relaxed and consume mean different things. The + // symbols we're loading are probably present (or not) at + // init, and even if they aren't the runtime dynamic loader + // is extremely likely have sufficient barriers internally + // (possibly implicitly, for example the ones provided by + // invoking `mprotect`). + // + // That said, none of that's *guaranteed*, and so we fence. + atomic::fence(Ordering::Acquire); + Some(func) + } + } + } + } + + // Cold because it should only happen during first-time initialization. + #[cold] + unsafe fn initialize(&self) -> Option { + let val = fetch(self.name); + // This synchronizes with the acquire fence in `get`. + self.addr.store(val, Ordering::Release); + + match val { + NULL => None, + addr => Some(mem::transmute_copy::<*mut c_void, F>(&addr)), + } + } +} + +unsafe fn fetch(name: &str) -> *mut c_void { + let name = match CStr::from_bytes_with_nul(name.as_bytes()) { + Ok(c_str) => c_str, + Err(..) => return null_mut(), + }; + libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) +} + +#[cfg(not(any(target_os = "android", target_os = "linux")))] +macro_rules! syscall { + (fn $name:ident($($arg_name:ident: $t:ty),*) via $_sys_name:ident -> $ret:ty) => ( + unsafe fn $name($($arg_name: $t),*) -> $ret { + weak! { fn $name($($t),*) -> $ret } + + if let Some(fun) = $name.get() { + fun($($arg_name),*) + } else { + libc_errno::set_errno(libc_errno::Errno(libc::ENOSYS)); + -1 + } + } + ) +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +macro_rules! syscall { + (fn $name:ident($($arg_name:ident: $t:ty),*) via $sys_name:ident -> $ret:ty) => ( + unsafe fn $name($($arg_name:$t),*) -> $ret { + // This looks like a hack, but concat_idents only accepts idents + // (not paths). + use libc::*; + + trait AsSyscallArg { + type SyscallArgType; + fn into_syscall_arg(self) -> Self::SyscallArgType; + } + + // Pass pointer types as pointers, to preserve provenance. + impl AsSyscallArg for *mut T { + type SyscallArgType = *mut T; + fn into_syscall_arg(self) -> Self::SyscallArgType { self } + } + impl AsSyscallArg for *const T { + type SyscallArgType = *const T; + fn into_syscall_arg(self) -> Self::SyscallArgType { self } + } + + // Pass `BorrowedFd` values as the integer value. + impl AsSyscallArg for $crate::fd::BorrowedFd<'_> { + type SyscallArgType = c::c_long; + fn into_syscall_arg(self) -> Self::SyscallArgType { + $crate::fd::AsRawFd::as_raw_fd(&self) as _ + } + } + + // Coerce integer values into `c_long`. + impl AsSyscallArg for i32 { + type SyscallArgType = c::c_long; + fn into_syscall_arg(self) -> Self::SyscallArgType { self as _ } + } + impl AsSyscallArg for u32 { + type SyscallArgType = c::c_long; + fn into_syscall_arg(self) -> Self::SyscallArgType { self as _ } + } + impl AsSyscallArg for usize { + type SyscallArgType = c::c_long; + fn into_syscall_arg(self) -> Self::SyscallArgType { self as _ } + } + + // `concat_idents is unstable, so we take an extra `sys_name` + // parameter and have our users do the concat for us for now. + /* + syscall( + concat_idents!(SYS_, $name), + $($arg_name.into_syscall_arg()),* + ) as $ret + */ + + syscall($sys_name, $($arg_name.into_syscall_arg()),*) as $ret + } + ) +} + +macro_rules! weakcall { + ($vis:vis fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => ( + $vis unsafe fn $name($($arg_name: $t),*) -> $ret { + weak! { fn $name($($t),*) -> $ret } + + // Use a weak symbol from libc when possible, allowing `LD_PRELOAD` + // interposition, but if it's not found just fail. + if let Some(fun) = $name.get() { + fun($($arg_name),*) + } else { + libc_errno::set_errno(libc_errno::Errno(libc::ENOSYS)); + -1 + } + } + ) +} + +/// A combination of `weakcall` and `syscall`. Use the libc function if it's +/// available, and fall back to `libc::syscall` otherwise. +macro_rules! weak_or_syscall { + ($vis:vis fn $name:ident($($arg_name:ident: $t:ty),*) via $sys_name:ident -> $ret:ty) => ( + $vis unsafe fn $name($($arg_name: $t),*) -> $ret { + weak! { fn $name($($t),*) -> $ret } + + // Use a weak symbol from libc when possible, allowing `LD_PRELOAD` + // interposition, but if it's not found just fail. + if let Some(fun) = $name.get() { + fun($($arg_name),*) + } else { + syscall! { fn $name($($arg_name: $t),*) via $sys_name -> $ret } + $name($($arg_name),*) + } + } + ) +} -- cgit v1.2.3