diff options
Diffstat (limited to 'vendor/rustix-0.37.22/src')
242 files changed, 53981 insertions, 0 deletions
diff --git a/vendor/rustix-0.37.22/src/backend/libc/c.rs b/vendor/rustix-0.37.22/src/backend/libc/c.rs new file mode 100644 index 000000000..891710ff9 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/c.rs @@ -0,0 +1,9 @@ +pub(crate) use libc::*; + +/// `PROC_SUPER_MAGIC`—The magic number for the procfs filesystem. +#[cfg(all(linux_kernel, target_env = "musl"))] +pub(crate) const PROC_SUPER_MAGIC: u32 = 0x0000_9fa0; + +/// `NFS_SUPER_MAGIC`—The magic number for the NFS filesystem. +#[cfg(all(linux_kernel, target_env = "musl"))] +pub(crate) const NFS_SUPER_MAGIC: u32 = 0x0000_6969; diff --git a/vendor/rustix-0.37.22/src/backend/libc/conv.rs b/vendor/rustix-0.37.22/src/backend/libc/conv.rs new file mode 100644 index 000000000..8287c4850 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/conv.rs @@ -0,0 +1,282 @@ +//! Libc call arguments and return values are often things like `c_int`, +//! `c_uint`, or libc-specific pointer types. This module provides functions +//! for converting between rustix's types and libc types. + +#![allow(dead_code)] + +use super::c; +use super::fd::{AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, LibcFd, OwnedFd, RawFd}; +#[cfg(not(windows))] +#[cfg(feature = "fs")] +use super::offset::libc_off_t; +#[cfg(not(windows))] +use crate::ffi::CStr; +use crate::io; +#[cfg(windows)] +use core::convert::TryInto; + +#[cfg(not(windows))] +#[inline] +pub(super) fn c_str(c: &CStr) -> *const c::c_char { + c.as_ptr() +} + +#[cfg(not(windows))] +#[inline] +pub(super) fn no_fd() -> LibcFd { + -1 +} + +#[inline] +pub(super) fn borrowed_fd(fd: BorrowedFd<'_>) -> LibcFd { + fd.as_raw_fd() as LibcFd +} + +#[inline] +pub(super) fn owned_fd(fd: OwnedFd) -> LibcFd { + fd.into_raw_fd() as LibcFd +} + +#[inline] +pub(super) fn ret(raw: c::c_int) -> io::Result<()> { + if raw == 0 { + Ok(()) + } else { + Err(io::Errno::last_os_error()) + } +} + +#[inline] +pub(super) fn syscall_ret(raw: c::c_long) -> io::Result<()> { + if raw == 0 { + Ok(()) + } else { + Err(io::Errno::last_os_error()) + } +} + +#[inline] +pub(super) fn nonnegative_ret(raw: c::c_int) -> io::Result<()> { + if raw >= 0 { + Ok(()) + } else { + Err(io::Errno::last_os_error()) + } +} + +#[inline] +pub(super) unsafe fn ret_infallible(raw: c::c_int) { + debug_assert_eq!(raw, 0, "unexpected error: {:?}", io::Errno::last_os_error()); +} + +#[inline] +pub(super) fn ret_c_int(raw: c::c_int) -> io::Result<c::c_int> { + if raw == -1 { + Err(io::Errno::last_os_error()) + } else { + Ok(raw) + } +} + +#[inline] +pub(super) fn ret_u32(raw: c::c_int) -> io::Result<u32> { + if raw == -1 { + Err(io::Errno::last_os_error()) + } else { + Ok(raw as u32) + } +} + +#[inline] +pub(super) fn ret_usize(raw: c::ssize_t) -> io::Result<usize> { + if raw == -1 { + Err(io::Errno::last_os_error()) + } else { + debug_assert!(raw >= 0); + Ok(raw as usize) + } +} + +#[inline] +pub(super) fn syscall_ret_usize(raw: c::c_long) -> io::Result<usize> { + if raw == -1 { + Err(io::Errno::last_os_error()) + } else { + debug_assert!(raw >= 0); + Ok(raw as c::ssize_t as usize) + } +} + +#[cfg(linux_kernel)] +#[inline] +pub(super) fn syscall_ret_u32(raw: c::c_long) -> io::Result<u32> { + if raw == -1 { + Err(io::Errno::last_os_error()) + } else { + let r32 = raw as u32; + + // Converting `raw` to `u32` should be lossless. + debug_assert_eq!(r32 as c::c_long, raw); + + Ok(r32) + } +} + +#[cfg(not(windows))] +#[cfg(feature = "fs")] +#[inline] +pub(super) fn ret_off_t(raw: libc_off_t) -> io::Result<libc_off_t> { + if raw == -1 { + Err(io::Errno::last_os_error()) + } else { + Ok(raw) + } +} + +#[cfg(not(windows))] +#[inline] +pub(super) fn ret_pid_t(raw: c::pid_t) -> io::Result<c::pid_t> { + if raw == -1 { + Err(io::Errno::last_os_error()) + } else { + Ok(raw) + } +} + +/// Convert a `c_int` returned from a libc function to an `OwnedFd`, if valid. +/// +/// # Safety +/// +/// The caller must ensure that this is the return value of a libc function +/// which returns an owned file descriptor. +#[inline] +pub(super) unsafe fn ret_owned_fd(raw: LibcFd) -> io::Result<OwnedFd> { + if raw == !0 { + Err(io::Errno::last_os_error()) + } else { + Ok(OwnedFd::from_raw_fd(raw as RawFd)) + } +} + +#[inline] +pub(super) fn ret_discarded_fd(raw: LibcFd) -> io::Result<()> { + if raw == !0 { + Err(io::Errno::last_os_error()) + } else { + Ok(()) + } +} + +#[inline] +pub(super) fn ret_discarded_char_ptr(raw: *mut c::c_char) -> io::Result<()> { + if raw.is_null() { + Err(io::Errno::last_os_error()) + } else { + Ok(()) + } +} + +/// Convert a `c_long` returned from `syscall` to an `OwnedFd`, if valid. +/// +/// # Safety +/// +/// The caller must ensure that this is the return value of a `syscall` call +/// which returns an owned file descriptor. +#[cfg(not(windows))] +#[inline] +pub(super) unsafe fn syscall_ret_owned_fd(raw: c::c_long) -> io::Result<OwnedFd> { + if raw == -1 { + Err(io::Errno::last_os_error()) + } else { + Ok(OwnedFd::from_raw_fd(raw as RawFd)) + } +} + +/// Convert the buffer-length argument value of a `send` or `recv` call. +#[cfg(not(windows))] +#[inline] +pub(super) fn send_recv_len(len: usize) -> usize { + len +} + +/// Convert the buffer-length argument value of a `send` or `recv` call. +#[cfg(windows)] +#[inline] +pub(super) fn send_recv_len(len: usize) -> i32 { + // On Windows, the length argument has type `i32`; saturate the length, + // since `send` and `recv` are allowed to send and recv less data than + // requested. + len.try_into().unwrap_or(i32::MAX) +} + +/// Convert the return value of a `send` or `recv` call. +#[cfg(not(windows))] +#[inline] +pub(super) fn ret_send_recv(len: isize) -> io::Result<usize> { + ret_usize(len) +} + +/// Convert the return value of a `send` or `recv` call. +#[cfg(windows)] +#[inline] +pub(super) fn ret_send_recv(len: i32) -> io::Result<usize> { + ret_usize(len as isize) +} + +/// Convert the value to the `msg_iovlen` field of a `msghdr` struct. +#[cfg(all( + not(any(windows, target_os = "wasi")), + any( + target_os = "android", + all(target_os = "linux", not(target_env = "musl")) + ) +))] +#[inline] +pub(super) fn msg_iov_len(len: usize) -> c::size_t { + len +} + +/// Convert the value to the `msg_iovlen` field of a `msghdr` struct. +#[cfg(all( + not(any(windows, target_os = "wasi")), + not(any( + target_os = "android", + all(target_os = "linux", not(target_env = "musl")) + )) +))] +#[inline] +pub(crate) fn msg_iov_len(len: usize) -> c::c_int { + use core::convert::TryInto; + len.try_into().unwrap_or(c::c_int::MAX) +} + +/// Convert the value to a `socklen_t`. +#[cfg(any( + bsd, + solarish, + target_env = "musl", + target_os = "emscripten", + target_os = "haiku", + target_os = "fuchsia" +))] +#[inline] +pub(crate) fn msg_control_len(len: usize) -> c::socklen_t { + use core::convert::TryInto; + len.try_into().unwrap_or(c::socklen_t::MAX) +} + +/// Convert the value to a `size_t`. +#[cfg(not(any( + bsd, + solarish, + target_env = "musl", + target_os = "emscripten", + target_os = "haiku", + target_os = "fuchsia", + windows, + target_os = "wasi" +)))] +#[inline] +pub(crate) fn msg_control_len(len: usize) -> c::size_t { + len +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/fs/dir.rs b/vendor/rustix-0.37.22/src/backend/libc/fs/dir.rs new file mode 100644 index 000000000..720f7d01e --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/fs/dir.rs @@ -0,0 +1,284 @@ +use super::super::c; +use super::super::conv::owned_fd; +use super::super::offset::libc_ino_t; +#[cfg(not(any(solarish, target_os = "haiku")))] +use super::types::FileType; +use crate::fd::{AsFd, BorrowedFd}; +use crate::ffi::{CStr, CString}; +use crate::fs::{fcntl_getfl, fstat, openat, Mode, OFlags, Stat}; +#[cfg(not(any( + solarish, + target_os = "haiku", + target_os = "netbsd", + target_os = "redox", + target_os = "wasi", +)))] +use crate::fs::{fstatfs, StatFs}; +#[cfg(not(any(solarish, target_os = "haiku", target_os = "redox", target_os = "wasi")))] +use crate::fs::{fstatvfs, StatVfs}; +use crate::io; +#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))] +use crate::process::fchdir; +use alloc::borrow::ToOwned; +#[cfg(not(linux_like))] +use c::readdir as libc_readdir; +#[cfg(linux_like)] +use c::readdir64 as libc_readdir; +use core::fmt; +use core::ptr::NonNull; +use libc_errno::{errno, set_errno, Errno}; + +/// `DIR*` +#[repr(transparent)] +pub struct Dir(NonNull<c::DIR>); + +impl Dir { + /// Construct a `Dir` that reads entries from the given directory + /// file descriptor. + #[inline] + pub fn read_from<Fd: AsFd>(fd: Fd) -> io::Result<Self> { + Self::_read_from(fd.as_fd()) + } + + #[inline] + fn _read_from(fd: BorrowedFd<'_>) -> io::Result<Self> { + // Given an arbitrary `OwnedFd`, it's impossible to know whether the + // user holds a `dup`'d copy which could continue to modify the + // file description state, which would cause Undefined Behavior after + // our call to `fdopendir`. To prevent this, we obtain an independent + // `OwnedFd`. + let flags = fcntl_getfl(fd)?; + let fd_for_dir = openat(fd, cstr!("."), flags | OFlags::CLOEXEC, Mode::empty())?; + + let raw = owned_fd(fd_for_dir); + unsafe { + let libc_dir = c::fdopendir(raw); + + if let Some(libc_dir) = NonNull::new(libc_dir) { + Ok(Self(libc_dir)) + } else { + let err = io::Errno::last_os_error(); + let _ = c::close(raw); + Err(err) + } + } + } + + /// `rewinddir(self)` + #[inline] + pub fn rewind(&mut self) { + unsafe { c::rewinddir(self.0.as_ptr()) } + } + + /// `readdir(self)`, where `None` means the end of the directory. + pub fn read(&mut self) -> Option<io::Result<DirEntry>> { + set_errno(Errno(0)); + let dirent_ptr = unsafe { libc_readdir(self.0.as_ptr()) }; + if dirent_ptr.is_null() { + let curr_errno = errno().0; + if curr_errno == 0 { + // We successfully reached the end of the stream. + None + } else { + // `errno` is unknown or non-zero, so an error occurred. + Some(Err(io::Errno(curr_errno))) + } + } else { + // We successfully read an entry. + unsafe { + let dirent = &*dirent_ptr; + + // We have our own copy of OpenBSD's dirent; check that the + // layout minimally matches libc's. + #[cfg(target_os = "openbsd")] + check_dirent_layout(dirent); + + let result = DirEntry { + #[cfg(not(any(solarish, target_os = "aix", target_os = "haiku")))] + d_type: dirent.d_type, + + #[cfg(not(any(freebsdlike, netbsdlike)))] + d_ino: dirent.d_ino, + + #[cfg(any(freebsdlike, netbsdlike))] + d_fileno: dirent.d_fileno, + + name: CStr::from_ptr(dirent.d_name.as_ptr()).to_owned(), + }; + + Some(Ok(result)) + } + } + } + + /// `fstat(self)` + #[inline] + pub fn stat(&self) -> io::Result<Stat> { + fstat(unsafe { BorrowedFd::borrow_raw(c::dirfd(self.0.as_ptr())) }) + } + + /// `fstatfs(self)` + #[cfg(not(any( + solarish, + target_os = "haiku", + target_os = "netbsd", + target_os = "redox", + target_os = "wasi", + )))] + #[inline] + pub fn statfs(&self) -> io::Result<StatFs> { + fstatfs(unsafe { BorrowedFd::borrow_raw(c::dirfd(self.0.as_ptr())) }) + } + + /// `fstatvfs(self)` + #[cfg(not(any(solarish, target_os = "haiku", target_os = "redox", target_os = "wasi")))] + #[inline] + pub fn statvfs(&self) -> io::Result<StatVfs> { + fstatvfs(unsafe { BorrowedFd::borrow_raw(c::dirfd(self.0.as_ptr())) }) + } + + /// `fchdir(self)` + #[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))] + #[inline] + pub fn chdir(&self) -> io::Result<()> { + fchdir(unsafe { BorrowedFd::borrow_raw(c::dirfd(self.0.as_ptr())) }) + } +} + +/// `Dir` implements `Send` but not `Sync`, because we use `readdir` which is +/// not guaranteed to be thread-safe. Users can wrap this in a `Mutex` if they +/// need `Sync`, which is effectively what'd need to do to implement `Sync` +/// ourselves. +unsafe impl Send for Dir {} + +impl Drop for Dir { + #[inline] + fn drop(&mut self) { + unsafe { c::closedir(self.0.as_ptr()) }; + } +} + +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", unsafe { &c::dirfd(self.0.as_ptr()) }) + .finish() + } +} + +/// `struct dirent` +#[derive(Debug)] +pub struct DirEntry { + #[cfg(not(any(solarish, target_os = "aix", target_os = "haiku")))] + d_type: u8, + + #[cfg(not(any(freebsdlike, netbsdlike)))] + d_ino: libc_ino_t, + + #[cfg(any(freebsdlike, netbsdlike))] + d_fileno: libc_ino_t, + + name: CString, +} + +impl DirEntry { + /// Returns the file name of this directory entry. + #[inline] + pub fn file_name(&self) -> &CStr { + &self.name + } + + /// Returns the type of this directory entry. + #[cfg(not(any(solarish, target_os = "aix", target_os = "haiku")))] + #[inline] + pub fn file_type(&self) -> FileType { + FileType::from_dirent_d_type(self.d_type) + } + + /// Return the inode number of this directory entry. + #[cfg(not(any(freebsdlike, netbsdlike)))] + #[inline] + pub fn ino(&self) -> u64 { + self.d_ino as u64 + } + + /// Return the inode number of this directory entry. + #[cfg(any(freebsdlike, netbsdlike))] + #[inline] + pub fn ino(&self) -> u64 { + #[allow(clippy::useless_conversion)] + self.d_fileno.into() + } +} + +/// libc's OpenBSD `dirent` has a private field so we can't construct it +/// directly, so we declare it ourselves to make all fields accessible. +#[cfg(target_os = "openbsd")] +#[repr(C)] +#[derive(Debug)] +struct libc_dirent { + d_fileno: c::ino_t, + d_off: c::off_t, + d_reclen: u16, + d_type: u8, + d_namlen: u8, + __d_padding: [u8; 4], + d_name: [c::c_char; 256], +} + +/// We have our own copy of OpenBSD's dirent; check that the layout +/// minimally matches libc's. +#[cfg(target_os = "openbsd")] +fn check_dirent_layout(dirent: &c::dirent) { + use crate::utils::as_ptr; + use core::mem::{align_of, size_of}; + + // Check that the basic layouts match. + assert_eq!(size_of::<libc_dirent>(), size_of::<c::dirent>()); + assert_eq!(align_of::<libc_dirent>(), align_of::<c::dirent>()); + + // Check that the field offsets match. + assert_eq!( + { + let z = libc_dirent { + d_fileno: 0_u64, + d_off: 0_i64, + d_reclen: 0_u16, + d_type: 0_u8, + d_namlen: 0_u8, + __d_padding: [0_u8; 4], + d_name: [0 as c::c_char; 256], + }; + let base = as_ptr(&z) as usize; + ( + (as_ptr(&z.d_fileno) as usize) - base, + (as_ptr(&z.d_off) as usize) - base, + (as_ptr(&z.d_reclen) as usize) - base, + (as_ptr(&z.d_type) as usize) - base, + (as_ptr(&z.d_namlen) as usize) - base, + (as_ptr(&z.d_name) as usize) - base, + ) + }, + { + let z = dirent; + let base = as_ptr(z) as usize; + ( + (as_ptr(&z.d_fileno) as usize) - base, + (as_ptr(&z.d_off) as usize) - base, + (as_ptr(&z.d_reclen) as usize) - base, + (as_ptr(&z.d_type) as usize) - base, + (as_ptr(&z.d_namlen) as usize) - base, + (as_ptr(&z.d_name) as usize) - base, + ) + } + ); +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/fs/inotify.rs b/vendor/rustix-0.37.22/src/backend/libc/fs/inotify.rs new file mode 100644 index 000000000..b2191d7fe --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/fs/inotify.rs @@ -0,0 +1,122 @@ +//! inotify support for working with inotifies + +use super::super::c; +use super::super::conv::{borrowed_fd, c_str, ret, ret_c_int, ret_owned_fd}; +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_int { + /// `IN_CLOEXEC` + const CLOEXEC = c::IN_CLOEXEC; + /// `IN_NONBLOCK` + const NONBLOCK = c::IN_NONBLOCK; + } +} + +bitflags! { + /// `IN*` for use with [`inotify_add_watch`]. + /// + /// [`inotify_add_watch`]: crate::fs::inotify::inotify_add_watch + #[derive(Default)] + pub struct WatchFlags: u32 { + /// `IN_ACCESS` + const ACCESS = c::IN_ACCESS; + /// `IN_ATTRIB` + const ATTRIB = c::IN_ATTRIB; + /// `IN_CLOSE_NOWRITE` + const CLOSE_NOWRITE = c::IN_CLOSE_NOWRITE; + /// `IN_CLOSE_WRITE` + const CLOSE_WRITE = c::IN_CLOSE_WRITE; + /// `IN_CREATE ` + const CREATE = c::IN_CREATE; + /// `IN_DELETE` + const DELETE = c::IN_DELETE; + /// `IN_DELETE_SELF` + const DELETE_SELF = c::IN_DELETE_SELF; + /// `IN_MODIFY` + const MODIFY = c::IN_MODIFY; + /// `IN_MOVE_SELF` + const MOVE_SELF = c::IN_MOVE_SELF; + /// `IN_MOVED_FROM` + const MOVED_FROM = c::IN_MOVED_FROM; + /// `IN_MOVED_TO` + const MOVED_TO = c::IN_MOVED_TO; + /// `IN_OPEN` + const OPEN = c::IN_OPEN; + + /// `IN_CLOSE` + const CLOSE = c::IN_CLOSE; + /// `IN_MOVE` + const MOVE = c::IN_MOVE; + /// `IN_ALL_EVENTS` + const ALL_EVENTS = c::IN_ALL_EVENTS; + + /// `IN_DONT_FOLLOW` + const DONT_FOLLOW = c::IN_DONT_FOLLOW; + /// `IN_EXCL_UNLINK` + const EXCL_UNLINK = 1; + /// `IN_MASK_ADD` + const MASK_ADD = 1; + /// `IN_MASK_CREATE` + const MASK_CREATE = 1; + /// `IN_ONESHOT` + const ONESHOT = c::IN_ONESHOT; + /// `IN_ONLYDIR` + const ONLYDIR = c::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<OwnedFd> { + // SAFETY: `inotify_init1` has no safety preconditions. + unsafe { ret_owned_fd(c::inotify_init1(flags.bits())) } +} + +/// `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<P: crate::path::Arg>( + inot: BorrowedFd<'_>, + path: P, + flags: WatchFlags, +) -> io::Result<i32> { + let path = path.as_cow_c_str().unwrap(); + // SAFETY: The fd and path we are passing is guaranteed valid by the type + // system. + unsafe { + ret_c_int(c::inotify_add_watch( + borrowed_fd(inot), + c_str(&path), + flags.bits(), + )) + } +} + +/// `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<()> { + // Android's `inotify_rm_watch` takes `u32` despite that + // `inotify_add_watch` expects a `i32`. + #[cfg(target_os = "android")] + let wd = wd as u32; + // SAFETY: The fd is valid and closing an arbitrary wd is valid. + unsafe { ret(c::inotify_rm_watch(borrowed_fd(inot), wd)) } +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/fs/makedev.rs b/vendor/rustix-0.37.22/src/backend/libc/fs/makedev.rs new file mode 100644 index 000000000..2db2b218d --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/fs/makedev.rs @@ -0,0 +1,138 @@ +#[cfg(not(all(target_os = "android", target_pointer_width = "32")))] +use super::super::c; +use crate::fs::Dev; + +#[cfg(not(any( + apple, + solarish, + target_os = "aix", + target_os = "android", + target_os = "emscripten", +)))] +#[inline] +pub(crate) fn makedev(maj: u32, min: u32) -> Dev { + c::makedev(maj, min) +} + +#[cfg(solarish)] +pub(crate) fn makedev(maj: u32, min: u32) -> Dev { + // SAFETY: Solarish's `makedev` is marked unsafe but it isn't doing + // anything unsafe. + unsafe { c::makedev(maj, min) } +} + +#[cfg(all(target_os = "android", not(target_pointer_width = "32")))] +#[inline] +pub(crate) fn makedev(maj: u32, min: u32) -> Dev { + c::makedev(maj, min) +} + +#[cfg(all(target_os = "android", target_pointer_width = "32"))] +#[inline] +pub(crate) fn makedev(maj: u32, min: u32) -> Dev { + // 32-bit Android's `dev_t` is 32-bit, but its `st_dev` is 64-bit, + // so we do it ourselves. + ((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) +} + +#[cfg(target_os = "emscripten")] +#[inline] +pub(crate) fn makedev(maj: u32, min: u32) -> Dev { + // Emscripten's `makedev` has a 32-bit return value. + Dev::from(c::makedev(maj, min)) +} + +#[cfg(apple)] +#[inline] +pub(crate) fn makedev(maj: u32, min: u32) -> Dev { + // Apple's `makedev` oddly has signed argument types and is `unsafe`. + unsafe { c::makedev(maj as i32, min as i32) } +} + +#[cfg(target_os = "aix")] +#[inline] +pub(crate) fn makedev(maj: u32, min: u32) -> Dev { + // AIX's `makedev` oddly is `unsafe`. + unsafe { c::makedev(maj, min) } +} + +#[cfg(not(any( + apple, + freebsdlike, + target_os = "android", + target_os = "emscripten", + target_os = "netbsd" +)))] +#[inline] +pub(crate) fn major(dev: Dev) -> u32 { + unsafe { c::major(dev) } +} + +#[cfg(any( + apple, + freebsdlike, + target_os = "netbsd", + all(target_os = "android", not(target_pointer_width = "32")), +))] +#[inline] +pub(crate) fn major(dev: Dev) -> u32 { + // On some platforms `major` oddly has signed return types. + (unsafe { c::major(dev) }) as u32 +} + +#[cfg(all(target_os = "android", target_pointer_width = "32"))] +#[inline] +pub(crate) fn major(dev: Dev) -> u32 { + // 32-bit Android's `dev_t` is 32-bit, but its `st_dev` is 64-bit, + // so we do it ourselves. + (((dev >> 31 >> 1) & 0xffff_f000) | ((dev >> 8) & 0x0000_0fff)) as u32 +} + +#[cfg(target_os = "emscripten")] +#[inline] +pub(crate) fn major(dev: Dev) -> u32 { + // Emscripten's `major` has a 32-bit argument value. + unsafe { c::major(dev as u32) } +} + +#[cfg(not(any( + apple, + freebsdlike, + target_os = "android", + target_os = "emscripten", + target_os = "netbsd" +)))] +#[inline] +pub(crate) fn minor(dev: Dev) -> u32 { + unsafe { c::minor(dev) } +} + +#[cfg(any( + apple, + freebsdlike, + target_os = "netbsd", + all(target_os = "android", not(target_pointer_width = "32")) +))] +#[inline] +pub(crate) fn minor(dev: Dev) -> u32 { + // On some platforms, `minor` oddly has signed return types. + (unsafe { c::minor(dev) }) as u32 +} + +#[cfg(all(target_os = "android", target_pointer_width = "32"))] +#[inline] +pub(crate) fn minor(dev: Dev) -> u32 { + // 32-bit Android's `dev_t` is 32-bit, but its `st_dev` is 64-bit, + // so we do it ourselves. + (((dev >> 12) & 0xffff_ff00) | (dev & 0x0000_00ff)) as u32 +} + +#[cfg(target_os = "emscripten")] +#[inline] +pub(crate) fn minor(dev: Dev) -> u32 { + // Emscripten's `minor` has a 32-bit argument value. + unsafe { c::minor(dev as u32) } +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/fs/mod.rs b/vendor/rustix-0.37.22/src/backend/libc/fs/mod.rs new file mode 100644 index 000000000..28579c993 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/fs/mod.rs @@ -0,0 +1,9 @@ +#[cfg(not(target_os = "redox"))] +pub(crate) mod dir; +#[cfg(linux_kernel)] +pub mod inotify; +#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))] +pub(crate) mod makedev; +#[cfg(not(windows))] +pub(crate) mod syscalls; +pub(crate) mod types; diff --git a/vendor/rustix-0.37.22/src/backend/libc/fs/syscalls.rs b/vendor/rustix-0.37.22/src/backend/libc/fs/syscalls.rs new file mode 100644 index 000000000..2b4e14ac6 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/fs/syscalls.rs @@ -0,0 +1,2152 @@ +//! libc syscalls supporting `rustix::fs`. + +use super::super::c; +use super::super::conv::{borrowed_fd, c_str, ret, ret_c_int, ret_off_t, ret_owned_fd, ret_usize}; +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +use super::super::offset::libc_fallocate; +#[cfg(not(any( + apple, + netbsdlike, + solarish, + target_os = "dragonfly", + target_os = "haiku", + target_os = "redox", +)))] +use super::super::offset::libc_posix_fadvise; +#[cfg(not(any( + apple, + netbsdlike, + solarish, + linux_kernel, + target_os = "aix", + target_os = "dragonfly", + target_os = "fuchsia", + target_os = "redox", +)))] +use super::super::offset::libc_posix_fallocate; +use super::super::offset::{libc_fstat, libc_fstatat, libc_ftruncate, libc_lseek, libc_off_t}; +#[cfg(not(any( + solarish, + target_os = "haiku", + target_os = "netbsd", + target_os = "redox", + target_os = "wasi", +)))] +use super::super::offset::{libc_fstatfs, libc_statfs}; +#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))] +use super::super::offset::{libc_fstatvfs, libc_statvfs}; +#[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +))] +use super::super::time::types::LibcTimespec; +use crate::fd::{BorrowedFd, OwnedFd}; +use crate::ffi::CStr; +#[cfg(apple)] +use crate::ffi::CString; +#[cfg(not(any( + apple, + netbsdlike, + solarish, + target_os = "dragonfly", + target_os = "haiku", + target_os = "redox", +)))] +use crate::fs::Advice; +#[cfg(not(any( + netbsdlike, + solarish, + target_os = "aix", + target_os = "dragonfly", + target_os = "redox", +)))] +use crate::fs::FallocateFlags; +#[cfg(not(target_os = "wasi"))] +use crate::fs::FlockOperation; +#[cfg(any(linux_kernel, target_os = "freebsd"))] +use crate::fs::MemfdFlags; +#[cfg(any(linux_kernel, target_os = "freebsd", target_os = "fuchsia"))] +use crate::fs::SealFlags; +#[cfg(not(any( + solarish, + target_os = "haiku", + target_os = "netbsd", + target_os = "redox", + target_os = "wasi", +)))] +use crate::fs::StatFs; +use crate::fs::{Access, Mode, OFlags, Stat, Timestamps}; +#[cfg(not(any(apple, target_os = "redox", target_os = "wasi")))] +use crate::fs::{Dev, FileType}; +#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))] +use crate::fs::{StatVfs, StatVfsMountFlags}; +use crate::io::{self, SeekFrom}; +#[cfg(not(target_os = "wasi"))] +use crate::process::{Gid, Uid}; +#[cfg(not(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +)))] +use crate::utils::as_ptr; +#[cfg(apple)] +use alloc::vec; +use core::convert::TryInto; +use core::mem::MaybeUninit; +#[cfg(apple)] +use { + super::super::conv::nonnegative_ret, + crate::fs::{copyfile_state_t, CloneFlags, CopyfileFlags}, +}; +#[cfg(linux_kernel)] +use { + super::super::conv::{syscall_ret, syscall_ret_owned_fd, syscall_ret_usize}, + crate::fs::{cwd, RenameFlags, ResolveFlags, Statx, StatxFlags}, + core::ptr::null, +}; +#[cfg(not(target_os = "redox"))] +use {super::super::offset::libc_openat, crate::fs::AtFlags}; +#[cfg(any(apple, linux_kernel))] +use {crate::fs::XattrFlags, core::mem::size_of, core::ptr::null_mut}; + +#[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +))] +weak!(fn __utimensat64(c::c_int, *const c::c_char, *const LibcTimespec, c::c_int) -> c::c_int); +#[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +))] +weak!(fn __futimens64(c::c_int, *const LibcTimespec) -> c::c_int); + +/// Use a direct syscall (via libc) for `openat`. +/// +/// This is only currently necessary as a workaround for old glibc; see below. +#[cfg(all(unix, target_env = "gnu"))] +fn openat_via_syscall( + dirfd: BorrowedFd<'_>, + path: &CStr, + oflags: OFlags, + mode: Mode, +) -> io::Result<OwnedFd> { + unsafe { + let dirfd = borrowed_fd(dirfd); + let path = c_str(path); + let oflags = oflags.bits(); + let mode = c::c_uint::from(mode.bits()); + ret_owned_fd(c::syscall( + c::SYS_openat, + c::c_long::from(dirfd), + path, + c::c_long::from(oflags), + mode as c::c_long, + ) as c::c_int) + } +} + +#[cfg(not(target_os = "redox"))] +pub(crate) fn openat( + dirfd: BorrowedFd<'_>, + path: &CStr, + oflags: OFlags, + mode: Mode, +) -> io::Result<OwnedFd> { + // Work around <https://sourceware.org/bugzilla/show_bug.cgi?id=17523>. + // glibc versions before 2.25 don't handle `O_TMPFILE` correctly. + #[cfg(all(unix, target_env = "gnu"))] + if oflags.contains(OFlags::TMPFILE) && crate::backend::if_glibc_is_less_than_2_25() { + return openat_via_syscall(dirfd, path, oflags, mode); + } + unsafe { + // Pass `mode` as a `c_uint` even if `mode_t` is narrower, since + // `libc_openat` is declared as a variadic function and narrower + // arguments are promoted. + ret_owned_fd(libc_openat( + borrowed_fd(dirfd), + c_str(path), + oflags.bits(), + c::c_uint::from(mode.bits()), + )) + } +} + +#[cfg(not(any( + solarish, + target_os = "haiku", + target_os = "netbsd", + target_os = "redox", + target_os = "wasi", +)))] +#[inline] +pub(crate) fn statfs(filename: &CStr) -> io::Result<StatFs> { + unsafe { + let mut result = MaybeUninit::<StatFs>::uninit(); + ret(libc_statfs(c_str(filename), result.as_mut_ptr()))?; + Ok(result.assume_init()) + } +} + +#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))] +#[inline] +pub(crate) fn statvfs(filename: &CStr) -> io::Result<StatVfs> { + unsafe { + let mut result = MaybeUninit::<libc_statvfs>::uninit(); + ret(libc_statvfs(c_str(filename), result.as_mut_ptr()))?; + Ok(libc_statvfs_to_statvfs(result.assume_init())) + } +} + +#[cfg(not(target_os = "redox"))] +#[inline] +pub(crate) fn readlinkat(dirfd: BorrowedFd<'_>, path: &CStr, buf: &mut [u8]) -> io::Result<usize> { + unsafe { + ret_usize(c::readlinkat( + borrowed_fd(dirfd), + c_str(path), + buf.as_mut_ptr().cast::<c::c_char>(), + buf.len(), + )) + } +} + +#[cfg(not(target_os = "redox"))] +pub(crate) fn mkdirat(dirfd: BorrowedFd<'_>, path: &CStr, mode: Mode) -> io::Result<()> { + unsafe { + ret(c::mkdirat( + borrowed_fd(dirfd), + c_str(path), + mode.bits() as c::mode_t, + )) + } +} + +#[cfg(linux_kernel)] +pub(crate) fn getdents_uninit( + fd: BorrowedFd<'_>, + buf: &mut [MaybeUninit<u8>], +) -> io::Result<usize> { + unsafe { + syscall_ret_usize(c::syscall( + c::SYS_getdents64, + fd, + buf.as_mut_ptr().cast::<c::c_char>(), + buf.len(), + )) + } +} + +#[cfg(not(target_os = "redox"))] +pub(crate) fn linkat( + old_dirfd: BorrowedFd<'_>, + old_path: &CStr, + new_dirfd: BorrowedFd<'_>, + new_path: &CStr, + flags: AtFlags, +) -> io::Result<()> { + // macOS <= 10.9 lacks `linkat`. + #[cfg(target_os = "macos")] + unsafe { + weak! { + fn linkat( + c::c_int, + *const c::c_char, + c::c_int, + *const c::c_char, + c::c_int + ) -> c::c_int + } + // If we have `linkat`, use it. + if let Some(libc_linkat) = linkat.get() { + return ret(libc_linkat( + borrowed_fd(old_dirfd), + c_str(old_path), + borrowed_fd(new_dirfd), + c_str(new_path), + flags.bits(), + )); + } + // Otherwise, see if we can emulate the `AT_FDCWD` case. + if borrowed_fd(old_dirfd) != c::AT_FDCWD || borrowed_fd(new_dirfd) != c::AT_FDCWD { + return Err(io::Errno::NOSYS); + } + if flags.intersects(!AtFlags::SYMLINK_FOLLOW) { + return Err(io::Errno::INVAL); + } + if !flags.is_empty() { + return Err(io::Errno::OPNOTSUPP); + } + ret(c::link(c_str(old_path), c_str(new_path))) + } + + #[cfg(not(target_os = "macos"))] + unsafe { + ret(c::linkat( + borrowed_fd(old_dirfd), + c_str(old_path), + borrowed_fd(new_dirfd), + c_str(new_path), + flags.bits(), + )) + } +} + +#[cfg(not(target_os = "redox"))] +pub(crate) fn unlinkat(dirfd: BorrowedFd<'_>, path: &CStr, flags: AtFlags) -> io::Result<()> { + // macOS <= 10.9 lacks `unlinkat`. + #[cfg(target_os = "macos")] + unsafe { + weak! { + fn unlinkat( + c::c_int, + *const c::c_char, + c::c_int + ) -> c::c_int + } + // If we have `unlinkat`, use it. + if let Some(libc_unlinkat) = unlinkat.get() { + return ret(libc_unlinkat(borrowed_fd(dirfd), c_str(path), flags.bits())); + } + // Otherwise, see if we can emulate the `AT_FDCWD` case. + if borrowed_fd(dirfd) != c::AT_FDCWD { + return Err(io::Errno::NOSYS); + } + if flags.intersects(!AtFlags::REMOVEDIR) { + return Err(io::Errno::INVAL); + } + if flags.contains(AtFlags::REMOVEDIR) { + ret(c::rmdir(c_str(path))) + } else { + ret(c::unlink(c_str(path))) + } + } + + #[cfg(not(target_os = "macos"))] + unsafe { + ret(c::unlinkat(borrowed_fd(dirfd), c_str(path), flags.bits())) + } +} + +#[cfg(not(target_os = "redox"))] +pub(crate) fn renameat( + old_dirfd: BorrowedFd<'_>, + old_path: &CStr, + new_dirfd: BorrowedFd<'_>, + new_path: &CStr, +) -> io::Result<()> { + // macOS <= 10.9 lacks `renameat`. + #[cfg(target_os = "macos")] + unsafe { + weak! { + fn renameat( + c::c_int, + *const c::c_char, + c::c_int, + *const c::c_char + ) -> c::c_int + } + // If we have `renameat`, use it. + if let Some(libc_renameat) = renameat.get() { + return ret(libc_renameat( + borrowed_fd(old_dirfd), + c_str(old_path), + borrowed_fd(new_dirfd), + c_str(new_path), + )); + } + // Otherwise, see if we can emulate the `AT_FDCWD` case. + if borrowed_fd(old_dirfd) != c::AT_FDCWD || borrowed_fd(new_dirfd) != c::AT_FDCWD { + return Err(io::Errno::NOSYS); + } + ret(c::rename(c_str(old_path), c_str(new_path))) + } + + #[cfg(not(target_os = "macos"))] + unsafe { + ret(c::renameat( + borrowed_fd(old_dirfd), + c_str(old_path), + borrowed_fd(new_dirfd), + c_str(new_path), + )) + } +} + +#[cfg(all(target_os = "linux", target_env = "gnu"))] +pub(crate) fn renameat2( + old_dirfd: BorrowedFd<'_>, + old_path: &CStr, + new_dirfd: BorrowedFd<'_>, + new_path: &CStr, + flags: RenameFlags, +) -> io::Result<()> { + // `renameat2` wasn't supported in glibc until 2.28. + weak_or_syscall! { + fn renameat2( + olddirfd: c::c_int, + oldpath: *const c::c_char, + newdirfd: c::c_int, + newpath: *const c::c_char, + flags: c::c_uint + ) via SYS_renameat2 -> c::c_int + } + + unsafe { + ret(renameat2( + borrowed_fd(old_dirfd), + c_str(old_path), + borrowed_fd(new_dirfd), + c_str(new_path), + flags.bits(), + )) + } +} + +/// At present, `libc` only has `renameat2` defined for glibc. On other +/// ABIs, `RenameFlags` has no flags defined, and we use plain `renameat`. +#[cfg(any( + target_os = "android", + all(target_os = "linux", not(target_env = "gnu")), +))] +#[inline] +pub(crate) fn renameat2( + old_dirfd: BorrowedFd<'_>, + old_path: &CStr, + new_dirfd: BorrowedFd<'_>, + new_path: &CStr, + flags: RenameFlags, +) -> io::Result<()> { + assert!(flags.is_empty()); + renameat(old_dirfd, old_path, new_dirfd, new_path) +} + +#[cfg(not(target_os = "redox"))] +pub(crate) fn symlinkat( + old_path: &CStr, + new_dirfd: BorrowedFd<'_>, + new_path: &CStr, +) -> io::Result<()> { + unsafe { + ret(c::symlinkat( + c_str(old_path), + borrowed_fd(new_dirfd), + c_str(new_path), + )) + } +} + +#[cfg(not(target_os = "redox"))] +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(all(linux_kernel, any(target_pointer_width = "32", target_arch = "mips64")))] + { + 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), + } + } + + // Main version: libc is y2038 safe. Or, the platform is not y2038 safe and + // there's nothing practical we can do. + #[cfg(not(all(linux_kernel, any(target_pointer_width = "32", target_arch = "mips64"))))] + unsafe { + let mut stat = MaybeUninit::<Stat>::uninit(); + ret(libc_fstatat( + borrowed_fd(dirfd), + c_str(path), + stat.as_mut_ptr(), + flags.bits(), + ))?; + Ok(stat.assume_init()) + } +} + +#[cfg(all(linux_kernel, any(target_pointer_width = "32", target_arch = "mips64")))] +fn statat_old(dirfd: BorrowedFd<'_>, path: &CStr, flags: AtFlags) -> io::Result<Stat> { + unsafe { + let mut result = MaybeUninit::<c::stat64>::uninit(); + ret(libc_fstatat( + borrowed_fd(dirfd), + c_str(path), + result.as_mut_ptr(), + flags.bits(), + ))?; + stat64_to_stat(result.assume_init()) + } +} + +#[cfg(not(any(target_os = "emscripten", target_os = "redox")))] +pub(crate) fn accessat( + dirfd: BorrowedFd<'_>, + path: &CStr, + access: Access, + flags: AtFlags, +) -> io::Result<()> { + // macOS <= 10.9 lacks `faccessat`. + #[cfg(target_os = "macos")] + unsafe { + weak! { + fn faccessat( + c::c_int, + *const c::c_char, + c::c_int, + c::c_int + ) -> c::c_int + } + // If we have `faccessat`, use it. + if let Some(libc_faccessat) = faccessat.get() { + return ret(libc_faccessat( + borrowed_fd(dirfd), + c_str(path), + access.bits(), + flags.bits(), + )); + } + // Otherwise, see if we can emulate the `AT_FDCWD` case. + if borrowed_fd(dirfd) != c::AT_FDCWD { + return Err(io::Errno::NOSYS); + } + if flags.intersects(!(AtFlags::EACCESS | AtFlags::SYMLINK_NOFOLLOW)) { + return Err(io::Errno::INVAL); + } + if !flags.is_empty() { + return Err(io::Errno::OPNOTSUPP); + } + ret(c::access(c_str(path), access.bits())) + } + + #[cfg(not(target_os = "macos"))] + unsafe { + ret(c::faccessat( + borrowed_fd(dirfd), + c_str(path), + access.bits(), + flags.bits(), + )) + } +} + +#[cfg(target_os = "emscripten")] +pub(crate) fn accessat( + _dirfd: BorrowedFd<'_>, + _path: &CStr, + _access: Access, + _flags: AtFlags, +) -> io::Result<()> { + Ok(()) +} + +#[cfg(not(target_os = "redox"))] +pub(crate) fn utimensat( + dirfd: BorrowedFd<'_>, + path: &CStr, + times: &Timestamps, + flags: AtFlags, +) -> io::Result<()> { + // 32-bit gnu version: libc has `utimensat` but it is not y2038 safe by + // default. + #[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", + ))] + unsafe { + if let Some(libc_utimensat) = __utimensat64.get() { + let libc_times: [LibcTimespec; 2] = [ + times.last_access.clone().into(), + times.last_modification.clone().into(), + ]; + + ret(libc_utimensat( + borrowed_fd(dirfd), + c_str(path), + libc_times.as_ptr(), + flags.bits(), + )) + } else { + utimensat_old(dirfd, path, times, flags) + } + } + + // Main version: libc is y2038 safe and has `utimensat`. Or, the platform + // is not y2038 safe and there's nothing practical we can do. + #[cfg(not(any( + apple, + all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", + ) + )))] + unsafe { + // Assert that `Timestamps` has the expected layout. + let _ = core::mem::transmute::<Timestamps, [c::timespec; 2]>(times.clone()); + + ret(c::utimensat( + borrowed_fd(dirfd), + c_str(path), + as_ptr(times).cast(), + flags.bits(), + )) + } + + // `utimensat` was introduced in macOS 10.13. + #[cfg(apple)] + unsafe { + // ABI details + weak! { + fn utimensat( + c::c_int, + *const c::c_char, + *const c::timespec, + c::c_int + ) -> c::c_int + } + extern "C" { + fn setattrlist( + path: *const c::c_char, + attr_list: *const Attrlist, + attr_buf: *const c::c_void, + attr_buf_size: c::size_t, + options: c::c_ulong, + ) -> c::c_int; + } + const FSOPT_NOFOLLOW: c::c_ulong = 0x0000_0001; + + // If we have `utimensat`, use it. + if let Some(have_utimensat) = utimensat.get() { + // Assert that `Timestamps` has the expected layout. + let _ = core::mem::transmute::<Timestamps, [c::timespec; 2]>(times.clone()); + + return ret(have_utimensat( + borrowed_fd(dirfd), + c_str(path), + as_ptr(times).cast(), + flags.bits(), + )); + } + + // `setattrlistat` was introduced in 10.13 along with `utimensat`, so if + // we don't have `utimensat`, we don't have `setattrlistat` either. + // Emulate it using `fork`, and `fchdir` and [`setattrlist`]. + // + // [`setattrlist`]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setattrlist.2.html + match c::fork() { + -1 => Err(io::Errno::IO), + 0 => { + if c::fchdir(borrowed_fd(dirfd)) != 0 { + let code = match libc_errno::errno().0 { + c::EACCES => 2, + c::ENOTDIR => 3, + _ => 1, + }; + c::_exit(code); + } + + let mut flags_arg = 0; + if flags.contains(AtFlags::SYMLINK_NOFOLLOW) { + flags_arg |= FSOPT_NOFOLLOW; + } + + let (attrbuf_size, times, attrs) = times_to_attrlist(times); + + if setattrlist( + c_str(path), + &attrs, + as_ptr(×).cast(), + attrbuf_size, + flags_arg, + ) != 0 + { + // Translate expected `errno` codes into ad-hoc integer + // values suitable for exit statuses. + let code = match libc_errno::errno().0 { + c::EACCES => 2, + c::ENOTDIR => 3, + c::EPERM => 4, + c::EROFS => 5, + c::ELOOP => 6, + c::ENOENT => 7, + c::ENAMETOOLONG => 8, + c::EINVAL => 9, + c::ESRCH => 10, + c::ENOTSUP => 11, + _ => 1, + }; + c::_exit(code); + } + + c::_exit(0); + } + child_pid => { + let mut wstatus = 0; + let _ = ret_c_int(c::waitpid(child_pid, &mut wstatus, 0))?; + if c::WIFEXITED(wstatus) { + // Translate our ad-hoc exit statuses back to `errno` + // codes. + match c::WEXITSTATUS(wstatus) { + 0 => Ok(()), + 2 => Err(io::Errno::ACCESS), + 3 => Err(io::Errno::NOTDIR), + 4 => Err(io::Errno::PERM), + 5 => Err(io::Errno::ROFS), + 6 => Err(io::Errno::LOOP), + 7 => Err(io::Errno::NOENT), + 8 => Err(io::Errno::NAMETOOLONG), + 9 => Err(io::Errno::INVAL), + 10 => Err(io::Errno::SRCH), + 11 => Err(io::Errno::NOTSUP), + _ => Err(io::Errno::IO), + } + } else { + Err(io::Errno::IO) + } + } + } + } +} + +#[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +))] +unsafe fn utimensat_old( + dirfd: BorrowedFd<'_>, + path: &CStr, + times: &Timestamps, + flags: AtFlags, +) -> io::Result<()> { + let old_times = [ + c::timespec { + tv_sec: times + .last_access + .tv_sec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + tv_nsec: times.last_access.tv_nsec, + }, + c::timespec { + tv_sec: times + .last_modification + .tv_sec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + tv_nsec: times.last_modification.tv_nsec, + }, + ]; + ret(c::utimensat( + borrowed_fd(dirfd), + c_str(path), + old_times.as_ptr(), + flags.bits(), + )) +} + +#[cfg(not(any(linux_kernel, target_os = "redox", target_os = "wasi")))] +pub(crate) fn chmodat( + dirfd: BorrowedFd<'_>, + path: &CStr, + mode: Mode, + flags: AtFlags, +) -> io::Result<()> { + unsafe { + ret(c::fchmodat( + borrowed_fd(dirfd), + c_str(path), + mode.bits() as c::mode_t, + flags.bits(), + )) + } +} + +#[cfg(linux_kernel)] +pub(crate) fn chmodat( + dirfd: BorrowedFd<'_>, + path: &CStr, + mode: Mode, + flags: AtFlags, +) -> io::Result<()> { + // Linux's `fchmodat` does not have a flags argument. + // + // Use `c::syscall` rather than `c::fchmodat` because some libc + // implementations, such as musl, add extra logic to `fchmod` to emulate + // support for `AT_SYMLINK_NOFOLLOW`, which uses `/proc` outside our + // control. + if flags == AtFlags::SYMLINK_NOFOLLOW { + return Err(io::Errno::OPNOTSUPP); + } + if !flags.is_empty() { + return Err(io::Errno::INVAL); + } + unsafe { + // Pass `mode` as a `c_uint` even if `mode_t` is narrower, since + // `libc_openat` is declared as a variadic function and narrower + // arguments are promoted. + syscall_ret(c::syscall( + c::SYS_fchmodat, + borrowed_fd(dirfd), + c_str(path), + c::c_uint::from(mode.bits()), + )) + } +} + +#[cfg(apple)] +pub(crate) fn fclonefileat( + srcfd: BorrowedFd<'_>, + dst_dirfd: BorrowedFd<'_>, + dst: &CStr, + flags: CloneFlags, +) -> io::Result<()> { + syscall! { + fn fclonefileat( + srcfd: BorrowedFd<'_>, + dst_dirfd: BorrowedFd<'_>, + dst: *const c::c_char, + flags: c::c_int + ) via SYS_fclonefileat -> c::c_int + } + + unsafe { ret(fclonefileat(srcfd, dst_dirfd, c_str(dst), flags.bits())) } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn chownat( + dirfd: BorrowedFd<'_>, + path: &CStr, + owner: Option<Uid>, + group: Option<Gid>, + flags: AtFlags, +) -> io::Result<()> { + unsafe { + let (ow, gr) = crate::process::translate_fchown_args(owner, group); + ret(c::fchownat( + borrowed_fd(dirfd), + c_str(path), + ow, + gr, + flags.bits(), + )) + } +} + +#[cfg(not(any(apple, target_os = "redox", target_os = "wasi")))] +pub(crate) fn mknodat( + dirfd: BorrowedFd<'_>, + path: &CStr, + file_type: FileType, + mode: Mode, + dev: Dev, +) -> io::Result<()> { + unsafe { + ret(c::mknodat( + borrowed_fd(dirfd), + c_str(path), + (mode.bits() | file_type.as_raw_mode()) as c::mode_t, + dev.try_into().map_err(|_e| io::Errno::PERM)?, + )) + } +} + +#[cfg(linux_kernel)] +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> { + assert_eq!(size_of::<c::loff_t>(), size_of::<u64>()); + + let mut off_in_val: c::loff_t = 0; + let mut off_out_val: c::loff_t = 0; + // Silently cast; we'll get `EINVAL` if the value is negative. + let off_in_ptr = if let Some(off_in) = &off_in { + off_in_val = (**off_in) as i64; + &mut off_in_val + } else { + null_mut() + }; + let off_out_ptr = if let Some(off_out) = &off_out { + off_out_val = (**off_out) as i64; + &mut off_out_val + } else { + null_mut() + }; + let copied = unsafe { + syscall_ret_usize(c::syscall( + c::SYS_copy_file_range, + borrowed_fd(fd_in), + off_in_ptr, + borrowed_fd(fd_out), + off_out_ptr, + len, + 0, // no flags are defined yet + ))? + }; + if let Some(off_in) = off_in { + *off_in = off_in_val as u64; + } + if let Some(off_out) = off_out { + *off_out = off_out_val as u64; + } + Ok(copied) +} + +#[cfg(not(any( + apple, + netbsdlike, + solarish, + target_os = "dragonfly", + target_os = "haiku", + target_os = "redox", +)))] +pub(crate) fn fadvise(fd: BorrowedFd<'_>, offset: u64, len: u64, advice: Advice) -> io::Result<()> { + let offset = offset as i64; + let len = len as i64; + + // FreeBSD returns `EINVAL` on invalid offsets; emulate the POSIX behavior. + #[cfg(target_os = "freebsd")] + let offset = if (offset as i64) < 0 { + i64::MAX + } else { + offset + }; + + // FreeBSD returns `EINVAL` on overflow; emulate the POSIX behavior. + #[cfg(target_os = "freebsd")] + let len = if len > 0 && offset.checked_add(len).is_none() { + i64::MAX - offset + } else { + len + }; + + let err = unsafe { libc_posix_fadvise(borrowed_fd(fd), offset, len, advice as c::c_int) }; + + // `posix_fadvise` returns its error status rather than using `errno`. + if err == 0 { + Ok(()) + } else { + Err(io::Errno(err)) + } +} + +pub(crate) fn fcntl_getfl(fd: BorrowedFd<'_>) -> io::Result<OFlags> { + unsafe { ret_c_int(c::fcntl(borrowed_fd(fd), c::F_GETFL)).map(OFlags::from_bits_truncate) } +} + +pub(crate) fn fcntl_setfl(fd: BorrowedFd<'_>, flags: OFlags) -> io::Result<()> { + unsafe { ret(c::fcntl(borrowed_fd(fd), c::F_SETFL, flags.bits())) } +} + +#[cfg(any(linux_kernel, target_os = "freebsd", target_os = "fuchsia"))] +pub(crate) fn fcntl_get_seals(fd: BorrowedFd<'_>) -> io::Result<SealFlags> { + unsafe { + ret_c_int(c::fcntl(borrowed_fd(fd), c::F_GET_SEALS)) + .map(|flags| SealFlags::from_bits_unchecked(flags)) + } +} + +#[cfg(any(linux_kernel, target_os = "freebsd", target_os = "fuchsia"))] +pub(crate) fn fcntl_add_seals(fd: BorrowedFd<'_>, seals: SealFlags) -> io::Result<()> { + unsafe { ret(c::fcntl(borrowed_fd(fd), c::F_ADD_SEALS, seals.bits())) } +} + +#[cfg(not(any( + target_os = "emscripten", + target_os = "fuchsia", + target_os = "redox", + target_os = "wasi" +)))] +#[inline] +pub(crate) fn fcntl_lock(fd: BorrowedFd<'_>, operation: FlockOperation) -> io::Result<()> { + use c::{flock, F_RDLCK, F_SETLK, F_SETLKW, F_UNLCK, F_WRLCK, SEEK_SET}; + + 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 mut lock: flock = core::mem::zeroed(); + lock.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. + lock.l_whence = SEEK_SET as _; + lock.l_start = 0; + lock.l_len = 0; + + ret(c::fcntl(borrowed_fd(fd), cmd, &lock)) + } +} + +pub(crate) fn seek(fd: BorrowedFd<'_>, pos: SeekFrom) -> io::Result<u64> { + let (whence, offset): (c::c_int, libc_off_t) = match pos { + SeekFrom::Start(pos) => { + let pos: u64 = pos; + // Silently cast; we'll get `EINVAL` if the value is negative. + (c::SEEK_SET, pos as i64) + } + SeekFrom::End(offset) => (c::SEEK_END, offset), + SeekFrom::Current(offset) => (c::SEEK_CUR, offset), + #[cfg(any(freebsdlike, target_os = "linux", target_os = "solaris"))] + SeekFrom::Data(offset) => (c::SEEK_DATA, offset), + #[cfg(any(freebsdlike, target_os = "linux", target_os = "solaris"))] + SeekFrom::Hole(offset) => (c::SEEK_HOLE, offset), + }; + let offset = unsafe { ret_off_t(libc_lseek(borrowed_fd(fd), offset, whence))? }; + Ok(offset as u64) +} + +pub(crate) fn tell(fd: BorrowedFd<'_>) -> io::Result<u64> { + let offset = unsafe { ret_off_t(libc_lseek(borrowed_fd(fd), 0, c::SEEK_CUR))? }; + Ok(offset as u64) +} + +#[cfg(not(any(linux_kernel, target_os = "wasi")))] +pub(crate) fn fchmod(fd: BorrowedFd<'_>, mode: Mode) -> io::Result<()> { + unsafe { ret(c::fchmod(borrowed_fd(fd), mode.bits())) } +} + +#[cfg(linux_kernel)] +pub(crate) fn fchmod(fd: BorrowedFd<'_>, mode: Mode) -> io::Result<()> { + // Use `c::syscall` rather than `c::fchmod` because some libc + // implementations, such as musl, add extra logic to `fchmod` to emulate + // support for `O_PATH`, which uses `/proc` outside our control and + // interferes with our own use of `O_PATH`. + unsafe { + syscall_ret(c::syscall( + c::SYS_fchmod, + borrowed_fd(fd), + c::c_uint::from(mode.bits()), + )) + } +} + +#[cfg(linux_kernel)] +pub(crate) fn fchown(fd: BorrowedFd<'_>, owner: Option<Uid>, group: Option<Gid>) -> io::Result<()> { + // Use `c::syscall` rather than `c::fchown` because some libc + // implementations, such as musl, add extra logic to `fchown` to emulate + // support for `O_PATH`, which uses `/proc` outside our control and + // interferes with our own use of `O_PATH`. + unsafe { + let (ow, gr) = crate::process::translate_fchown_args(owner, group); + syscall_ret(c::syscall(c::SYS_fchown, borrowed_fd(fd), ow, gr)) + } +} + +#[cfg(not(any(linux_kernel, target_os = "wasi")))] +pub(crate) fn fchown(fd: BorrowedFd<'_>, owner: Option<Uid>, group: Option<Gid>) -> io::Result<()> { + unsafe { + let (ow, gr) = crate::process::translate_fchown_args(owner, group); + ret(c::fchown(borrowed_fd(fd), ow, gr)) + } +} + +#[cfg(not(any(target_os = "solaris", target_os = "wasi")))] +pub(crate) fn flock(fd: BorrowedFd<'_>, operation: FlockOperation) -> io::Result<()> { + unsafe { ret(c::flock(borrowed_fd(fd), operation as c::c_int)) } +} + +#[cfg(linux_kernel)] +pub(crate) fn syncfs(fd: BorrowedFd<'_>) -> io::Result<()> { + // Some versions of Android libc lack a `syncfs` function. + #[cfg(target_os = "android")] + syscall! { + fn syncfs(fd: c::c_int) via SYS_syncfs -> c::c_int + } + + // `syncfs` was added to glibc in 2.20. + #[cfg(not(target_os = "android"))] + weak_or_syscall! { + fn syncfs(fd: c::c_int) via SYS_syncfs -> c::c_int + } + + unsafe { ret(syncfs(borrowed_fd(fd))) } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn sync() { + unsafe { c::sync() } +} + +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(all(linux_kernel, any(target_pointer_width = "32", target_arch = "mips64")))] + { + 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), + } + } + + // Main version: libc is y2038 safe. Or, the platform is not y2038 safe and + // there's nothing practical we can do. + #[cfg(not(all(linux_kernel, any(target_pointer_width = "32", target_arch = "mips64"))))] + unsafe { + let mut stat = MaybeUninit::<Stat>::uninit(); + ret(libc_fstat(borrowed_fd(fd), stat.as_mut_ptr()))?; + Ok(stat.assume_init()) + } +} + +#[cfg(all(linux_kernel, any(target_pointer_width = "32", target_arch = "mips64")))] +fn fstat_old(fd: BorrowedFd<'_>) -> io::Result<Stat> { + unsafe { + let mut result = MaybeUninit::<c::stat64>::uninit(); + ret(libc_fstat(borrowed_fd(fd), result.as_mut_ptr()))?; + stat64_to_stat(result.assume_init()) + } +} + +#[cfg(not(any( + solarish, + target_os = "haiku", + target_os = "netbsd", + target_os = "redox", + target_os = "wasi", +)))] +pub(crate) fn fstatfs(fd: BorrowedFd<'_>) -> io::Result<StatFs> { + let mut statfs = MaybeUninit::<StatFs>::uninit(); + unsafe { + ret(libc_fstatfs(borrowed_fd(fd), statfs.as_mut_ptr()))?; + Ok(statfs.assume_init()) + } +} + +#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))] +pub(crate) fn fstatvfs(fd: BorrowedFd<'_>) -> io::Result<StatVfs> { + let mut statvfs = MaybeUninit::<libc_statvfs>::uninit(); + unsafe { + ret(libc_fstatvfs(borrowed_fd(fd), statvfs.as_mut_ptr()))?; + Ok(libc_statvfs_to_statvfs(statvfs.assume_init())) + } +} + +#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))] +fn libc_statvfs_to_statvfs(from: libc_statvfs) -> StatVfs { + StatVfs { + f_bsize: from.f_bsize as u64, + f_frsize: from.f_frsize as u64, + f_blocks: from.f_blocks as u64, + f_bfree: from.f_bfree as u64, + f_bavail: from.f_bavail as u64, + f_files: from.f_files as u64, + f_ffree: from.f_ffree as u64, + f_favail: from.f_ffree as u64, + f_fsid: from.f_fsid as u64, + f_flag: unsafe { StatVfsMountFlags::from_bits_unchecked(from.f_flag as u64) }, + f_namemax: from.f_namemax as u64, + } +} + +pub(crate) fn futimens(fd: BorrowedFd<'_>, times: &Timestamps) -> io::Result<()> { + // 32-bit gnu version: libc has `futimens` but it is not y2038 safe by default. + #[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", + ))] + unsafe { + if let Some(libc_futimens) = __futimens64.get() { + let libc_times: [LibcTimespec; 2] = [ + times.last_access.clone().into(), + times.last_modification.clone().into(), + ]; + + ret(libc_futimens(borrowed_fd(fd), libc_times.as_ptr())) + } else { + futimens_old(fd, times) + } + } + + // Main version: libc is y2038 safe and has `futimens`. Or, the platform + // is not y2038 safe and there's nothing practical we can do. + #[cfg(not(any( + apple, + all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", + ) + )))] + unsafe { + // Assert that `Timestamps` has the expected layout. + let _ = core::mem::transmute::<Timestamps, [c::timespec; 2]>(times.clone()); + + ret(c::futimens(borrowed_fd(fd), as_ptr(times).cast())) + } + + // `futimens` was introduced in macOS 10.13. + #[cfg(apple)] + unsafe { + // ABI details. + weak! { + fn futimens(c::c_int, *const c::timespec) -> c::c_int + } + extern "C" { + fn fsetattrlist( + fd: c::c_int, + attr_list: *const Attrlist, + attr_buf: *const c::c_void, + attr_buf_size: c::size_t, + options: c::c_ulong, + ) -> c::c_int; + } + + // If we have `futimens`, use it. + if let Some(have_futimens) = futimens.get() { + // Assert that `Timestamps` has the expected layout. + let _ = core::mem::transmute::<Timestamps, [c::timespec; 2]>(times.clone()); + + return ret(have_futimens(borrowed_fd(fd), as_ptr(times).cast())); + } + + // Otherwise use `fsetattrlist`. + let (attrbuf_size, times, attrs) = times_to_attrlist(times); + + ret(fsetattrlist( + borrowed_fd(fd), + &attrs, + as_ptr(×).cast(), + attrbuf_size, + 0, + )) + } +} + +#[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +))] +unsafe fn futimens_old(fd: BorrowedFd<'_>, times: &Timestamps) -> io::Result<()> { + let old_times = [ + c::timespec { + tv_sec: times + .last_access + .tv_sec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + tv_nsec: times.last_access.tv_nsec, + }, + c::timespec { + tv_sec: times + .last_modification + .tv_sec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + tv_nsec: times.last_modification.tv_nsec, + }, + ]; + + ret(c::futimens(borrowed_fd(fd), old_times.as_ptr())) +} + +#[cfg(not(any( + apple, + netbsdlike, + solarish, + target_os = "aix", + target_os = "dragonfly", + target_os = "redox", +)))] +pub(crate) fn fallocate( + fd: BorrowedFd<'_>, + mode: FallocateFlags, + offset: u64, + len: u64, +) -> io::Result<()> { + // Silently cast; we'll get `EINVAL` if the value is negative. + let offset = offset as i64; + let len = len as i64; + + #[cfg(any(linux_kernel, target_os = "fuchsia"))] + unsafe { + ret(libc_fallocate(borrowed_fd(fd), mode.bits(), offset, len)) + } + + #[cfg(not(any(linux_kernel, target_os = "fuchsia")))] + { + assert!(mode.is_empty()); + let err = unsafe { libc_posix_fallocate(borrowed_fd(fd), offset, len) }; + + // `posix_fallocate` returns its error status rather than using `errno`. + if err == 0 { + Ok(()) + } else { + Err(io::Errno(err)) + } + } +} + +#[cfg(apple)] +pub(crate) fn fallocate( + fd: BorrowedFd<'_>, + mode: FallocateFlags, + offset: u64, + len: u64, +) -> io::Result<()> { + let offset: i64 = offset.try_into().map_err(|_e| io::Errno::INVAL)?; + let len = len as i64; + + assert!(mode.is_empty()); + + let new_len = offset.checked_add(len).ok_or(io::Errno::FBIG)?; + let mut store = c::fstore_t { + fst_flags: c::F_ALLOCATECONTIG, + fst_posmode: c::F_PEOFPOSMODE, + fst_offset: 0, + fst_length: new_len, + fst_bytesalloc: 0, + }; + unsafe { + if c::fcntl(borrowed_fd(fd), c::F_PREALLOCATE, &store) == -1 { + // Unable to allocate contiguous disk space; attempt to allocate + // non-contiguously. + store.fst_flags = c::F_ALLOCATEALL; + let _ = ret_c_int(c::fcntl(borrowed_fd(fd), c::F_PREALLOCATE, &store))?; + } + ret(c::ftruncate(borrowed_fd(fd), new_len)) + } +} + +pub(crate) fn fsync(fd: BorrowedFd<'_>) -> io::Result<()> { + unsafe { ret(c::fsync(borrowed_fd(fd))) } +} + +#[cfg(not(any( + apple, + target_os = "dragonfly", + target_os = "haiku", + target_os = "redox", +)))] +pub(crate) fn fdatasync(fd: BorrowedFd<'_>) -> io::Result<()> { + unsafe { ret(c::fdatasync(borrowed_fd(fd))) } +} + +pub(crate) fn ftruncate(fd: BorrowedFd<'_>, length: u64) -> io::Result<()> { + let length = length.try_into().map_err(|_overflow_err| io::Errno::FBIG)?; + unsafe { ret(libc_ftruncate(borrowed_fd(fd), length)) } +} + +#[cfg(any(linux_kernel, target_os = "freebsd"))] +pub(crate) fn memfd_create(path: &CStr, flags: MemfdFlags) -> io::Result<OwnedFd> { + #[cfg(target_os = "freebsd")] + weakcall! { + fn memfd_create( + name: *const c::c_char, + flags: c::c_uint + ) -> c::c_int + } + + #[cfg(linux_kernel)] + weak_or_syscall! { + fn memfd_create( + name: *const c::c_char, + flags: c::c_uint + ) via SYS_memfd_create -> c::c_int + } + + unsafe { ret_owned_fd(memfd_create(c_str(path), flags.bits())) } +} + +#[cfg(linux_kernel)] +pub(crate) fn openat2( + dirfd: BorrowedFd<'_>, + path: &CStr, + oflags: OFlags, + mode: Mode, + resolve: ResolveFlags, +) -> io::Result<OwnedFd> { + let oflags: i32 = oflags.bits(); + let open_how = OpenHow { + oflag: u64::from(oflags as u32), + mode: u64::from(mode.bits()), + resolve: resolve.bits(), + }; + + unsafe { + syscall_ret_owned_fd(c::syscall( + SYS_OPENAT2, + borrowed_fd(dirfd), + c_str(path), + &open_how, + SIZEOF_OPEN_HOW, + )) + } +} +#[cfg(all(linux_kernel, target_pointer_width = "32"))] +const SYS_OPENAT2: i32 = 437; +#[cfg(all(linux_kernel, target_pointer_width = "64"))] +const SYS_OPENAT2: i64 = 437; + +#[cfg(linux_kernel)] +#[repr(C)] +#[derive(Debug)] +struct OpenHow { + oflag: u64, + mode: u64, + resolve: u64, +} +#[cfg(linux_kernel)] +const SIZEOF_OPEN_HOW: usize = size_of::<OpenHow>(); + +#[cfg(target_os = "linux")] +pub(crate) fn sendfile( + out_fd: BorrowedFd<'_>, + in_fd: BorrowedFd<'_>, + offset: Option<&mut u64>, + count: usize, +) -> io::Result<usize> { + unsafe { + ret_usize(c::sendfile64( + borrowed_fd(out_fd), + borrowed_fd(in_fd), + offset.map_or(null_mut(), crate::utils::as_mut_ptr).cast(), + count, + )) + } +} + +/// Convert from a Linux `statx` value to rustix's `Stat`. +#[cfg(all(linux_kernel, target_pointer_width = "32"))] +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).into(), + 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).into(), + st_size: x.stx_size.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_blksize: x.stx_blksize.into(), + st_blocks: x.stx_blocks.into(), + st_atime: x + .stx_atime + .tv_sec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + st_atime_nsec: x.stx_atime.tv_nsec as _, + st_mtime: x + .stx_mtime + .tv_sec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + st_mtime_nsec: x.stx_mtime.tv_nsec as _, + st_ctime: x + .stx_ctime + .tv_sec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + st_ctime_nsec: x.stx_ctime.tv_nsec as _, + st_ino: x.stx_ino.into(), + }) +} + +/// Convert from a Linux `statx` value to rustix's `Stat`. +/// +/// mips64' `struct stat64` in libc has private fields, and `stx_blocks` +#[cfg(all(linux_kernel, target_arch = "mips64"))] +fn statx_to_stat(x: crate::fs::Statx) -> io::Result<Stat> { + let mut result: Stat = unsafe { core::mem::zeroed() }; + + result.st_dev = crate::fs::makedev(x.stx_dev_major, x.stx_dev_minor); + result.st_mode = x.stx_mode.into(); + result.st_nlink = x.stx_nlink.into(); + result.st_uid = x.stx_uid.into(); + result.st_gid = x.stx_gid.into(); + result.st_rdev = crate::fs::makedev(x.stx_rdev_major, x.stx_rdev_minor); + result.st_size = x.stx_size.try_into().map_err(|_| io::Errno::OVERFLOW)?; + result.st_blksize = x.stx_blksize.into(); + result.st_blocks = x.stx_blocks.try_into().map_err(|_e| io::Errno::OVERFLOW)?; + result.st_atime = x + .stx_atime + .tv_sec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?; + result.st_atime_nsec = x.stx_atime.tv_nsec as _; + result.st_mtime = x + .stx_mtime + .tv_sec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?; + result.st_mtime_nsec = x.stx_mtime.tv_nsec as _; + result.st_ctime = x + .stx_ctime + .tv_sec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?; + result.st_ctime_nsec = x.stx_ctime.tv_nsec as _; + result.st_ino = x.stx_ino.into(); + + Ok(result) +} + +/// Convert from a Linux `stat64` value to rustix's `Stat`. +#[cfg(all(linux_kernel, target_pointer_width = "32"))] +fn stat64_to_stat(s64: c::stat64) -> io::Result<Stat> { + Ok(Stat { + st_dev: s64.st_dev.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_mode: s64.st_mode.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_nlink: s64.st_nlink.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_uid: s64.st_uid.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_gid: s64.st_gid.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_rdev: s64.st_rdev.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_size: s64.st_size.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_blksize: s64.st_blksize.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_blocks: s64.st_blocks.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_atime: s64.st_atime.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_atime_nsec: s64 + .st_atime_nsec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + st_mtime: s64.st_mtime.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_mtime_nsec: s64 + .st_mtime_nsec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + st_ctime: s64.st_ctime.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_ctime_nsec: s64 + .st_ctime_nsec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + st_ino: s64.st_ino.try_into().map_err(|_| io::Errno::OVERFLOW)?, + }) +} + +/// Convert from a Linux `stat64` value to rustix's `Stat`. +/// +/// mips64' `struct stat64` in libc has private fields, and `st_blocks` has +/// type `i64`. +#[cfg(all(linux_kernel, target_arch = "mips64"))] +fn stat64_to_stat(s64: c::stat64) -> io::Result<Stat> { + let mut result: Stat = unsafe { core::mem::zeroed() }; + + result.st_dev = s64.st_dev.try_into().map_err(|_| io::Errno::OVERFLOW)?; + result.st_mode = s64.st_mode.try_into().map_err(|_| io::Errno::OVERFLOW)?; + result.st_nlink = s64.st_nlink.try_into().map_err(|_| io::Errno::OVERFLOW)?; + result.st_uid = s64.st_uid.try_into().map_err(|_| io::Errno::OVERFLOW)?; + result.st_gid = s64.st_gid.try_into().map_err(|_| io::Errno::OVERFLOW)?; + result.st_rdev = s64.st_rdev.try_into().map_err(|_| io::Errno::OVERFLOW)?; + result.st_size = s64.st_size.try_into().map_err(|_| io::Errno::OVERFLOW)?; + result.st_blksize = s64.st_blksize.try_into().map_err(|_| io::Errno::OVERFLOW)?; + result.st_blocks = s64.st_blocks.try_into().map_err(|_| io::Errno::OVERFLOW)?; + result.st_atime = s64.st_atime.try_into().map_err(|_| io::Errno::OVERFLOW)?; + result.st_atime_nsec = s64 + .st_atime_nsec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?; + result.st_mtime = s64.st_mtime.try_into().map_err(|_| io::Errno::OVERFLOW)?; + result.st_mtime_nsec = s64 + .st_mtime_nsec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?; + result.st_ctime = s64.st_ctime.try_into().map_err(|_| io::Errno::OVERFLOW)?; + result.st_ctime_nsec = s64 + .st_ctime_nsec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?; + result.st_ino = s64.st_ino.try_into().map_err(|_| io::Errno::OVERFLOW)?; + + Ok(result) +} + +#[cfg(linux_kernel)] +#[allow(non_upper_case_globals)] +mod sys { + use super::{c, BorrowedFd, Statx}; + + weak_or_syscall! { + pub(super) fn statx( + dirfd_: BorrowedFd<'_>, + path: *const c::c_char, + flags: c::c_int, + mask: c::c_uint, + buf: *mut Statx + ) via SYS_statx -> c::c_int + } +} + +#[cfg(linux_kernel)] +#[allow(non_upper_case_globals)] +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/ + #[cfg(not(any(target_os = "android", target_env = "musl")))] + const STATX__RESERVED: u32 = c::STATX__RESERVED as u32; + #[cfg(any(target_os = "android", target_env = "musl"))] + const STATX__RESERVED: u32 = linux_raw_sys::general::STATX__RESERVED; + if (mask.bits() & STATX__RESERVED) == STATX__RESERVED { + return Err(io::Errno::INVAL); + } + let mask = mask & StatxFlags::all(); + + let mut statx_buf = MaybeUninit::<Statx>::uninit(); + unsafe { + ret(sys::statx( + dirfd, + c_str(path), + flags.bits(), + mask.bits(), + statx_buf.as_mut_ptr(), + ))?; + Ok(statx_buf.assume_init()) + } +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn is_statx_available() -> bool { + unsafe { + // Call `statx` with null pointers so that if it fails for any reason + // other than `EFAULT`, we know it's not supported. + matches!( + ret(sys::statx(cwd(), null(), 0, 0, null_mut())), + Err(io::Errno::FAULT) + ) + } +} + +#[cfg(apple)] +pub(crate) unsafe fn fcopyfile( + from: BorrowedFd<'_>, + to: BorrowedFd<'_>, + state: copyfile_state_t, + flags: CopyfileFlags, +) -> io::Result<()> { + extern "C" { + fn fcopyfile( + from: c::c_int, + to: c::c_int, + state: copyfile_state_t, + flags: c::c_uint, + ) -> c::c_int; + } + + nonnegative_ret(fcopyfile( + borrowed_fd(from), + borrowed_fd(to), + state, + flags.bits(), + )) +} + +#[cfg(apple)] +pub(crate) fn copyfile_state_alloc() -> io::Result<copyfile_state_t> { + extern "C" { + fn copyfile_state_alloc() -> copyfile_state_t; + } + + let result = unsafe { copyfile_state_alloc() }; + if result.0.is_null() { + Err(io::Errno::last_os_error()) + } else { + Ok(result) + } +} + +#[cfg(apple)] +pub(crate) unsafe fn copyfile_state_free(state: copyfile_state_t) -> io::Result<()> { + extern "C" { + fn copyfile_state_free(state: copyfile_state_t) -> c::c_int; + } + + nonnegative_ret(copyfile_state_free(state)) +} + +#[cfg(apple)] +const COPYFILE_STATE_COPIED: u32 = 8; + +#[cfg(apple)] +pub(crate) unsafe fn copyfile_state_get_copied(state: copyfile_state_t) -> io::Result<u64> { + let mut copied = MaybeUninit::<u64>::uninit(); + copyfile_state_get(state, COPYFILE_STATE_COPIED, copied.as_mut_ptr().cast())?; + Ok(copied.assume_init()) +} + +#[cfg(apple)] +pub(crate) unsafe fn copyfile_state_get( + state: copyfile_state_t, + flag: u32, + dst: *mut c::c_void, +) -> io::Result<()> { + extern "C" { + fn copyfile_state_get(state: copyfile_state_t, flag: u32, dst: *mut c::c_void) -> c::c_int; + } + + nonnegative_ret(copyfile_state_get(state, flag, dst)) +} + +#[cfg(apple)] +pub(crate) fn getpath(fd: BorrowedFd<'_>) -> io::Result<CString> { + // The use of `PATH_MAX` is generally not encouraged, but it + // is inevitable in this case because macOS defines `fcntl` with + // `F_GETPATH` in terms of `MAXPATHLEN`, and there are no + // alternatives. If a better method is invented, it should be used + // instead. + let mut buf = vec![0; c::PATH_MAX as usize]; + + // From the [macOS `fcntl` manual page]: + // `F_GETPATH` - Get the path of the file descriptor `Fildes`. The argument + // must be a buffer of size `MAXPATHLEN` or greater. + // + // [macOS `fcntl` manual page]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fcntl.2.html + unsafe { + ret(c::fcntl(borrowed_fd(fd), c::F_GETPATH, buf.as_mut_ptr()))?; + } + + let l = buf.iter().position(|&c| c == 0).unwrap(); + buf.truncate(l); + + // TODO: On Rust 1.56, we can use `shrink_to` here. + //buf.shrink_to(l + 1); + buf.shrink_to_fit(); + + Ok(CString::new(buf).unwrap()) +} + +#[cfg(apple)] +pub(crate) fn fcntl_rdadvise(fd: BorrowedFd<'_>, offset: u64, len: u64) -> io::Result<()> { + // From the [macOS `fcntl` manual page]: + // `F_RDADVISE` - Issue an advisory read async with no copy to user. + // + // The `F_RDADVISE` command operates on the following structure which holds + // information passed from the user to the system: + // + // ```c + // struct radvisory { + // off_t ra_offset; /* offset into the file */ + // int ra_count; /* size of the read */ + // }; + // ``` + // + // [macOS `fcntl` manual page]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fcntl.2.html + let ra_offset = match offset.try_into() { + Ok(len) => len, + // If this conversion fails, the user is providing an offset outside + // any possible file extent, so just ignore it. + Err(_) => return Ok(()), + }; + let ra_count = match len.try_into() { + Ok(len) => len, + // If this conversion fails, the user is providing a dubiously large + // hint which is unlikely to improve performance. + Err(_) => return Ok(()), + }; + unsafe { + let radvisory = c::radvisory { + ra_offset, + ra_count, + }; + ret(c::fcntl(borrowed_fd(fd), c::F_RDADVISE, &radvisory)) + } +} + +#[cfg(apple)] +pub(crate) fn fcntl_fullfsync(fd: BorrowedFd<'_>) -> io::Result<()> { + unsafe { ret(c::fcntl(borrowed_fd(fd), c::F_FULLFSYNC)) } +} + +/// Convert `times` from a `futimens`/`utimensat` argument into `setattrlist` +/// arguments. +#[cfg(apple)] +fn times_to_attrlist(times: &Timestamps) -> (c::size_t, [c::timespec; 2], Attrlist) { + // ABI details. + const ATTR_CMN_MODTIME: u32 = 0x0000_0400; + const ATTR_CMN_ACCTIME: u32 = 0x0000_1000; + const ATTR_BIT_MAP_COUNT: u16 = 5; + + let mut times = times.clone(); + + // If we have any `UTIME_NOW` elements, replace them with the current time. + if times.last_access.tv_nsec == c::UTIME_NOW || times.last_modification.tv_nsec == c::UTIME_NOW + { + let now = { + let mut tv = c::timeval { + tv_sec: 0, + tv_usec: 0, + }; + unsafe { + let r = c::gettimeofday(&mut tv, null_mut()); + assert_eq!(r, 0); + } + c::timespec { + tv_sec: tv.tv_sec, + tv_nsec: (tv.tv_usec * 1000) as _, + } + }; + if times.last_access.tv_nsec == c::UTIME_NOW { + times.last_access = now; + } + if times.last_modification.tv_nsec == c::UTIME_NOW { + times.last_modification = now; + } + } + + // Pack the return values following the rules for [`getattrlist`]. + // + // [`getattrlist`]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getattrlist.2.html + let mut times_size = 0; + let mut attrs = Attrlist { + bitmapcount: ATTR_BIT_MAP_COUNT, + reserved: 0, + commonattr: 0, + volattr: 0, + dirattr: 0, + fileattr: 0, + forkattr: 0, + }; + let mut return_times = [c::timespec { + tv_sec: 0, + tv_nsec: 0, + }; 2]; + let mut times_index = 0; + if times.last_modification.tv_nsec != c::UTIME_OMIT { + attrs.commonattr |= ATTR_CMN_MODTIME; + return_times[times_index] = times.last_modification; + times_index += 1; + times_size += size_of::<c::timespec>(); + } + if times.last_access.tv_nsec != c::UTIME_OMIT { + attrs.commonattr |= ATTR_CMN_ACCTIME; + return_times[times_index] = times.last_access; + times_size += size_of::<c::timespec>(); + } + + (times_size, return_times, attrs) +} + +/// Support type for `Attrlist`. +#[cfg(apple)] +type Attrgroup = u32; + +/// Attribute list for use with `setattrlist`. +#[cfg(apple)] +#[repr(C)] +struct Attrlist { + bitmapcount: u16, + reserved: u16, + commonattr: Attrgroup, + volattr: Attrgroup, + dirattr: Attrgroup, + fileattr: Attrgroup, + forkattr: Attrgroup, +} + +#[cfg(linux_kernel)] +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(c::mount( + source.map_or_else(null, CStr::as_ptr), + target.as_ptr(), + file_system_type.map_or_else(null, CStr::as_ptr), + flags.0, + data.map_or_else(null, CStr::as_ptr).cast(), + )) + } +} + +#[cfg(linux_kernel)] +pub(crate) fn unmount(target: &CStr, flags: super::types::UnmountFlags) -> io::Result<()> { + unsafe { ret(c::umount2(target.as_ptr(), flags.bits())) } +} + +#[cfg(any(apple, linux_kernel))] +pub(crate) fn getxattr(path: &CStr, name: &CStr, value: &mut [u8]) -> io::Result<usize> { + let value_ptr = value.as_mut_ptr(); + + #[cfg(not(apple))] + unsafe { + ret_usize(c::getxattr( + path.as_ptr(), + name.as_ptr(), + value_ptr.cast::<c::c_void>(), + value.len(), + )) + } + + #[cfg(apple)] + unsafe { + ret_usize(c::getxattr( + path.as_ptr(), + name.as_ptr(), + value_ptr.cast::<c::c_void>(), + value.len(), + 0, + 0, + )) + } +} + +#[cfg(any(apple, linux_kernel))] +pub(crate) fn lgetxattr(path: &CStr, name: &CStr, value: &mut [u8]) -> io::Result<usize> { + let value_ptr = value.as_mut_ptr(); + + #[cfg(not(apple))] + unsafe { + ret_usize(c::lgetxattr( + path.as_ptr(), + name.as_ptr(), + value_ptr.cast::<c::c_void>(), + value.len(), + )) + } + + #[cfg(apple)] + unsafe { + ret_usize(c::getxattr( + path.as_ptr(), + name.as_ptr(), + value_ptr.cast::<c::c_void>(), + value.len(), + 0, + c::XATTR_NOFOLLOW, + )) + } +} + +#[cfg(any(apple, linux_kernel))] +pub(crate) fn fgetxattr(fd: BorrowedFd<'_>, name: &CStr, value: &mut [u8]) -> io::Result<usize> { + let value_ptr = value.as_mut_ptr(); + + #[cfg(not(apple))] + unsafe { + ret_usize(c::fgetxattr( + borrowed_fd(fd), + name.as_ptr(), + value_ptr.cast::<c::c_void>(), + value.len(), + )) + } + + #[cfg(apple)] + unsafe { + ret_usize(c::fgetxattr( + borrowed_fd(fd), + name.as_ptr(), + value_ptr.cast::<c::c_void>(), + value.len(), + 0, + 0, + )) + } +} + +#[cfg(any(apple, linux_kernel))] +pub(crate) fn setxattr( + path: &CStr, + name: &CStr, + value: &[u8], + flags: XattrFlags, +) -> io::Result<()> { + #[cfg(not(apple))] + unsafe { + ret(c::setxattr( + path.as_ptr(), + name.as_ptr(), + value.as_ptr().cast::<c::c_void>(), + value.len(), + flags.bits() as i32, + )) + } + + #[cfg(apple)] + unsafe { + ret(c::setxattr( + path.as_ptr(), + name.as_ptr(), + value.as_ptr().cast::<c::c_void>(), + value.len(), + 0, + flags.bits() as i32, + )) + } +} + +#[cfg(any(apple, linux_kernel))] +pub(crate) fn lsetxattr( + path: &CStr, + name: &CStr, + value: &[u8], + flags: XattrFlags, +) -> io::Result<()> { + #[cfg(not(apple))] + unsafe { + ret(c::lsetxattr( + path.as_ptr(), + name.as_ptr(), + value.as_ptr().cast::<c::c_void>(), + value.len(), + flags.bits() as i32, + )) + } + + #[cfg(apple)] + unsafe { + ret(c::setxattr( + path.as_ptr(), + name.as_ptr(), + value.as_ptr().cast::<c::c_void>(), + value.len(), + 0, + flags.bits() as i32 | c::XATTR_NOFOLLOW, + )) + } +} + +#[cfg(any(apple, linux_kernel))] +pub(crate) fn fsetxattr( + fd: BorrowedFd<'_>, + name: &CStr, + value: &[u8], + flags: XattrFlags, +) -> io::Result<()> { + #[cfg(not(apple))] + unsafe { + ret(c::fsetxattr( + borrowed_fd(fd), + name.as_ptr(), + value.as_ptr().cast::<c::c_void>(), + value.len(), + flags.bits() as i32, + )) + } + + #[cfg(apple)] + unsafe { + ret(c::fsetxattr( + borrowed_fd(fd), + name.as_ptr(), + value.as_ptr().cast::<c::c_void>(), + value.len(), + 0, + flags.bits() as i32, + )) + } +} + +#[cfg(any(apple, linux_kernel))] +pub(crate) fn listxattr(path: &CStr, list: &mut [c::c_char]) -> io::Result<usize> { + #[cfg(not(apple))] + unsafe { + ret_usize(c::listxattr(path.as_ptr(), list.as_mut_ptr(), list.len())) + } + + #[cfg(apple)] + unsafe { + ret_usize(c::listxattr( + path.as_ptr(), + list.as_mut_ptr(), + list.len(), + 0, + )) + } +} + +#[cfg(any(apple, linux_kernel))] +pub(crate) fn llistxattr(path: &CStr, list: &mut [c::c_char]) -> io::Result<usize> { + #[cfg(not(apple))] + unsafe { + ret_usize(c::llistxattr(path.as_ptr(), list.as_mut_ptr(), list.len())) + } + + #[cfg(apple)] + unsafe { + ret_usize(c::listxattr( + path.as_ptr(), + list.as_mut_ptr(), + list.len(), + c::XATTR_NOFOLLOW, + )) + } +} + +#[cfg(any(apple, linux_kernel))] +pub(crate) fn flistxattr(fd: BorrowedFd<'_>, list: &mut [c::c_char]) -> io::Result<usize> { + let fd = borrowed_fd(fd); + + #[cfg(not(apple))] + unsafe { + ret_usize(c::flistxattr(fd, list.as_mut_ptr(), list.len())) + } + + #[cfg(apple)] + unsafe { + ret_usize(c::flistxattr(fd, list.as_mut_ptr(), list.len(), 0)) + } +} + +#[cfg(any(apple, linux_kernel))] +pub(crate) fn removexattr(path: &CStr, name: &CStr) -> io::Result<()> { + #[cfg(not(apple))] + unsafe { + ret(c::removexattr(path.as_ptr(), name.as_ptr())) + } + + #[cfg(apple)] + unsafe { + ret(c::removexattr(path.as_ptr(), name.as_ptr(), 0)) + } +} + +#[cfg(any(apple, linux_kernel))] +pub(crate) fn lremovexattr(path: &CStr, name: &CStr) -> io::Result<()> { + #[cfg(not(apple))] + unsafe { + ret(c::lremovexattr(path.as_ptr(), name.as_ptr())) + } + + #[cfg(apple)] + unsafe { + ret(c::removexattr( + path.as_ptr(), + name.as_ptr(), + c::XATTR_NOFOLLOW, + )) + } +} + +#[cfg(any(apple, linux_kernel))] +pub(crate) fn fremovexattr(fd: BorrowedFd<'_>, name: &CStr) -> io::Result<()> { + let fd = borrowed_fd(fd); + + #[cfg(not(apple))] + unsafe { + ret(c::fremovexattr(fd, name.as_ptr())) + } + + #[cfg(apple)] + unsafe { + ret(c::fremovexattr(fd, name.as_ptr(), 0)) + } +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/fs/types.rs b/vendor/rustix-0.37.22/src/backend/libc/fs/types.rs new file mode 100644 index 000000000..ffb67cf42 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/fs/types.rs @@ -0,0 +1,1149 @@ +use super::super::c; +use bitflags::bitflags; + +bitflags! { + /// `*_OK` constants for use with [`accessat`]. + /// + /// [`accessat`]: fn.accessat.html + pub struct Access: c::c_int { + /// `R_OK` + const READ_OK = c::R_OK; + + /// `W_OK` + const WRITE_OK = c::W_OK; + + /// `X_OK` + const EXEC_OK = c::X_OK; + + /// `F_OK` + const EXISTS = c::F_OK; + } +} + +#[cfg(not(target_os = "redox"))] +bitflags! { + /// `AT_*` constants for use with [`openat`], [`statat`], and other `*at` + /// functions. + /// + /// [`openat`]: crate::fs::openat + /// [`statat`]: crate::fs::statat + pub struct AtFlags: c::c_int { + /// `AT_REMOVEDIR` + const REMOVEDIR = c::AT_REMOVEDIR; + + /// `AT_SYMLINK_FOLLOW` + const SYMLINK_FOLLOW = c::AT_SYMLINK_FOLLOW; + + /// `AT_SYMLINK_NOFOLLOW` + const SYMLINK_NOFOLLOW = c::AT_SYMLINK_NOFOLLOW; + + /// `AT_EMPTY_PATH` + #[cfg(any( + target_os = "android", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "linux", + ))] + const EMPTY_PATH = c::AT_EMPTY_PATH; + + /// `AT_RESOLVE_BENEATH` + #[cfg(target_os = "freebsd")] + const RESOLVE_BENEATH = c::AT_RESOLVE_BENEATH; + + /// `AT_EACCESS` + #[cfg(not(any(target_os = "emscripten", target_os = "android")))] + const EACCESS = c::AT_EACCESS; + + /// `AT_STATX_SYNC_AS_STAT` + #[cfg(all(target_os = "linux", target_env = "gnu"))] + const STATX_SYNC_AS_STAT = c::AT_STATX_SYNC_AS_STAT; + + /// `AT_STATX_FORCE_SYNC` + #[cfg(all(target_os = "linux", target_env = "gnu"))] + const STATX_FORCE_SYNC = c::AT_STATX_FORCE_SYNC; + + /// `AT_STATX_DONT_SYNC` + #[cfg(all(target_os = "linux", target_env = "gnu"))] + const STATX_DONT_SYNC = c::AT_STATX_DONT_SYNC; + } +} + +bitflags! { + /// `S_I*` constants for use with [`openat`], [`chmodat`], and [`fchmod`]. + /// + /// [`openat`]: crate::fs::openat + /// [`chmodat`]: crate::fs::chmodat + /// [`fchmod`]: crate::fs::fchmod + pub struct Mode: RawMode { + /// `S_IRWXU` + #[cfg(not(target_os = "wasi"))] // WASI doesn't have Unix-style mode flags. + const RWXU = c::S_IRWXU as RawMode; + + /// `S_IRUSR` + #[cfg(not(target_os = "wasi"))] // WASI doesn't have Unix-style mode flags. + const RUSR = c::S_IRUSR as RawMode; + + /// `S_IWUSR` + #[cfg(not(target_os = "wasi"))] // WASI doesn't have Unix-style mode flags. + const WUSR = c::S_IWUSR as RawMode; + + /// `S_IXUSR` + #[cfg(not(target_os = "wasi"))] // WASI doesn't have Unix-style mode flags. + const XUSR = c::S_IXUSR as RawMode; + + /// `S_IRWXG` + #[cfg(not(target_os = "wasi"))] // WASI doesn't have Unix-style mode flags. + const RWXG = c::S_IRWXG as RawMode; + + /// `S_IRGRP` + #[cfg(not(target_os = "wasi"))] // WASI doesn't have Unix-style mode flags. + const RGRP = c::S_IRGRP as RawMode; + + /// `S_IWGRP` + #[cfg(not(target_os = "wasi"))] // WASI doesn't have Unix-style mode flags. + const WGRP = c::S_IWGRP as RawMode; + + /// `S_IXGRP` + #[cfg(not(target_os = "wasi"))] // WASI doesn't have Unix-style mode flags. + const XGRP = c::S_IXGRP as RawMode; + + /// `S_IRWXO` + #[cfg(not(target_os = "wasi"))] // WASI doesn't have Unix-style mode flags. + const RWXO = c::S_IRWXO as RawMode; + + /// `S_IROTH` + #[cfg(not(target_os = "wasi"))] // WASI doesn't have Unix-style mode flags. + const ROTH = c::S_IROTH as RawMode; + + /// `S_IWOTH` + #[cfg(not(target_os = "wasi"))] // WASI doesn't have Unix-style mode flags. + const WOTH = c::S_IWOTH as RawMode; + + /// `S_IXOTH` + #[cfg(not(target_os = "wasi"))] // WASI doesn't have Unix-style mode flags. + const XOTH = c::S_IXOTH as RawMode; + + /// `S_ISUID` + #[cfg(not(target_os = "wasi"))] // WASI doesn't have Unix-style mode flags. + const SUID = c::S_ISUID as RawMode; + + /// `S_ISGID` + #[cfg(not(target_os = "wasi"))] // WASI doesn't have Unix-style mode flags. + const SGID = c::S_ISGID as RawMode; + + /// `S_ISVTX` + #[cfg(not(target_os = "wasi"))] // WASI doesn't have Unix-style mode flags. + const SVTX = c::S_ISVTX as RawMode; + } +} + +impl Mode { + /// Construct a `Mode` from the mode bits of the `st_mode` field of a + /// `Stat`. + #[inline] + pub const fn from_raw_mode(st_mode: RawMode) -> Self { + Self::from_bits_truncate(st_mode) + } + + /// Construct an `st_mode` value from `Stat`. + #[inline] + pub const fn as_raw_mode(self) -> RawMode { + self.bits() + } +} + +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 + pub struct OFlags: c::c_int { + /// `O_ACCMODE` + const ACCMODE = c::O_ACCMODE; + + /// Similar to `ACCMODE`, but just includes the read/write flags, and + /// no other flags. + /// + /// Some implementations include `O_PATH` in `O_ACCMODE`, when + /// sometimes we really just want the read/write bits. Caution is + /// indicated, as the presence of `O_PATH` may mean that the read/write + /// bits don't have their usual meaning. + const RWMODE = c::O_RDONLY | c::O_WRONLY | c::O_RDWR; + + /// `O_APPEND` + const APPEND = c::O_APPEND; + + /// `O_CREAT` + #[doc(alias = "CREAT")] + const CREATE = c::O_CREAT; + + /// `O_DIRECTORY` + const DIRECTORY = c::O_DIRECTORY; + + /// `O_DSYNC` + #[cfg(not(any(target_os = "dragonfly", target_os = "redox")))] + const DSYNC = c::O_DSYNC; + + /// `O_EXCL` + const EXCL = c::O_EXCL; + + /// `O_FSYNC` + #[cfg(any( + bsd, + all(target_os = "linux", not(target_env = "musl")), + ))] + const FSYNC = c::O_FSYNC; + + /// `O_NOFOLLOW` + const NOFOLLOW = c::O_NOFOLLOW; + + /// `O_NONBLOCK` + const NONBLOCK = c::O_NONBLOCK; + + /// `O_RDONLY` + const RDONLY = c::O_RDONLY; + + /// `O_WRONLY` + const WRONLY = c::O_WRONLY; + + /// `O_RDWR` + const RDWR = c::O_RDWR; + + /// `O_NOCTTY` + #[cfg(not(target_os = "redox"))] + const NOCTTY = c::O_NOCTTY; + + /// `O_RSYNC` + #[cfg(any( + netbsdlike, + target_os = "android", + target_os = "emscripten", + target_os = "linux", + target_os = "wasi", + ))] + const RSYNC = c::O_RSYNC; + + /// `O_SYNC` + #[cfg(not(target_os = "redox"))] + const SYNC = c::O_SYNC; + + /// `O_TRUNC` + const TRUNC = c::O_TRUNC; + + /// `O_PATH` + #[cfg(any( + target_os = "android", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "linux", + target_os = "redox", + ))] + const PATH = c::O_PATH; + + /// `O_CLOEXEC` + const CLOEXEC = c::O_CLOEXEC; + + /// `O_TMPFILE` + #[cfg(any( + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "linux", + ))] + const TMPFILE = c::O_TMPFILE; + + /// `O_NOATIME` + #[cfg(any( + target_os = "android", + target_os = "fuchsia", + target_os = "linux", + ))] + const NOATIME = c::O_NOATIME; + + /// `O_DIRECT` + #[cfg(any( + target_os = "android", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "linux", + target_os = "netbsd", + ))] + const DIRECT = c::O_DIRECT; + + /// `O_RESOLVE_BENEATH` + #[cfg(target_os = "freebsd")] + const RESOLVE_BENEATH = c::O_RESOLVE_BENEATH; + + /// `O_EMPTY_PATH` + #[cfg(target_os = "freebsd")] + const EMPTY_PATH = c::O_EMPTY_PATH; + } +} + +#[cfg(apple)] +bitflags! { + /// `CLONE_*` constants for use with [`fclonefileat`]. + /// + /// [`fclonefileat`]: crate::fs::fclonefileat + pub struct CloneFlags: c::c_int { + /// `CLONE_NOFOLLOW` + const NOFOLLOW = 1; + + /// `CLONE_NOOWNERCOPY` + const NOOWNERCOPY = 2; + } +} + +#[cfg(apple)] +mod copyfile { + pub(super) const ACL: u32 = 1 << 0; + pub(super) const STAT: u32 = 1 << 1; + pub(super) const XATTR: u32 = 1 << 2; + pub(super) const DATA: u32 = 1 << 3; + pub(super) const SECURITY: u32 = STAT | ACL; + pub(super) const METADATA: u32 = SECURITY | XATTR; + pub(super) const ALL: u32 = METADATA | DATA; +} + +#[cfg(apple)] +bitflags! { + /// `COPYFILE_*` constants for use with [`fcopyfile`]. + /// + /// [`fcopyfile`]: crate::fs::fcopyfile + pub struct CopyfileFlags: c::c_uint { + /// `COPYFILE_ACL` + const ACL = copyfile::ACL; + + /// `COPYFILE_STAT` + const STAT = copyfile::STAT; + + /// `COPYFILE_XATTR` + const XATTR = copyfile::XATTR; + + /// `COPYFILE_DATA` + const DATA = copyfile::DATA; + + /// `COPYFILE_SECURITY` + const SECURITY = copyfile::SECURITY; + + /// `COPYFILE_METADATA` + const METADATA = copyfile::METADATA; + + /// `COPYFILE_ALL` + const ALL = copyfile::ALL; + } +} + +#[cfg(linux_kernel)] +bitflags! { + /// `RESOLVE_*` constants for use with [`openat2`]. + /// + /// [`openat2`]: crate::fs::openat2 + #[derive(Default)] + pub struct ResolveFlags: u64 { + /// `RESOLVE_NO_XDEV` + const NO_XDEV = 0x01; + + /// `RESOLVE_NO_MAGICLINKS` + const NO_MAGICLINKS = 0x02; + + /// `RESOLVE_NO_SYMLINKS` + const NO_SYMLINKS = 0x04; + + /// `RESOLVE_BENEATH` + const BENEATH = 0x08; + + /// `RESOLVE_IN_ROOT` + const IN_ROOT = 0x10; + + /// `RESOLVE_CACHED` (since Linux 5.12) + const CACHED = 0x20; + } +} + +#[cfg(linux_kernel)] +bitflags! { + /// `RENAME_*` constants for use with [`renameat_with`]. + /// + /// [`renameat_with`]: crate::fs::renameat_with + pub struct RenameFlags: c::c_uint { + /// `RENAME_EXCHANGE` + const EXCHANGE = c::RENAME_EXCHANGE as _; + + /// `RENAME_NOREPLACE` + const NOREPLACE = c::RENAME_NOREPLACE as _; + + /// `RENAME_WHITEOUT` + const WHITEOUT = c::RENAME_WHITEOUT as _; + } +} + +/// `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 = c::S_IFREG as isize, + + /// `S_IFDIR` + Directory = c::S_IFDIR as isize, + + /// `S_IFLNK` + Symlink = c::S_IFLNK as isize, + + /// `S_IFIFO` + #[cfg(not(target_os = "wasi"))] // TODO: Use WASI's `S_IFIFO`. + #[doc(alias = "IFO")] + Fifo = c::S_IFIFO as isize, + + /// `S_IFSOCK` + #[cfg(not(target_os = "wasi"))] // TODO: Use WASI's `S_IFSOCK`. + Socket = c::S_IFSOCK as isize, + + /// `S_IFCHR` + CharacterDevice = c::S_IFCHR as isize, + + /// `S_IFBLK` + BlockDevice = c::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 as c::mode_t) & c::S_IFMT { + c::S_IFREG => Self::RegularFile, + c::S_IFDIR => Self::Directory, + c::S_IFLNK => Self::Symlink, + #[cfg(not(target_os = "wasi"))] // TODO: Use WASI's `S_IFIFO`. + c::S_IFIFO => Self::Fifo, + #[cfg(not(target_os = "wasi"))] // TODO: Use WASI's `S_IFSOCK`. + c::S_IFSOCK => Self::Socket, + c::S_IFCHR => Self::CharacterDevice, + c::S_IFBLK => Self::BlockDevice, + _ => Self::Unknown, + } + } + + /// Construct an `st_mode` value from `Stat`. + #[inline] + pub const fn as_raw_mode(self) -> RawMode { + match self { + Self::RegularFile => c::S_IFREG as RawMode, + Self::Directory => c::S_IFDIR as RawMode, + Self::Symlink => c::S_IFLNK as RawMode, + #[cfg(not(target_os = "wasi"))] // TODO: Use WASI's `S_IFIFO`. + Self::Fifo => c::S_IFIFO as RawMode, + #[cfg(not(target_os = "wasi"))] // TODO: Use WASI's `S_IFSOCK`. + Self::Socket => c::S_IFSOCK as RawMode, + Self::CharacterDevice => c::S_IFCHR as RawMode, + Self::BlockDevice => c::S_IFBLK as RawMode, + Self::Unknown => c::S_IFMT as RawMode, + } + } + + /// Construct a `FileType` from the `d_type` field of a `c::dirent`. + #[cfg(not(any(solarish, target_os = "haiku", target_os = "redox")))] + #[inline] + pub(crate) const fn from_dirent_d_type(d_type: u8) -> Self { + match d_type { + c::DT_REG => Self::RegularFile, + c::DT_DIR => Self::Directory, + c::DT_LNK => Self::Symlink, + #[cfg(not(target_os = "wasi"))] // TODO: Use WASI's `DT_SOCK`. + c::DT_SOCK => Self::Socket, + #[cfg(not(target_os = "wasi"))] // TODO: Use WASI's `DT_FIFO`. + c::DT_FIFO => Self::Fifo, + c::DT_CHR => Self::CharacterDevice, + c::DT_BLK => Self::BlockDevice, + // c::DT_UNKNOWN | + _ => Self::Unknown, + } + } +} + +/// `POSIX_FADV_*` constants for use with [`fadvise`]. +/// +/// [`fadvise`]: crate::fs::fadvise +#[cfg(not(any( + apple, + netbsdlike, + solarish, + target_os = "dragonfly", + target_os = "haiku", + target_os = "redox", +)))] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[repr(u32)] +pub enum Advice { + /// `POSIX_FADV_NORMAL` + Normal = c::POSIX_FADV_NORMAL as c::c_uint, + + /// `POSIX_FADV_SEQUENTIAL` + Sequential = c::POSIX_FADV_SEQUENTIAL as c::c_uint, + + /// `POSIX_FADV_RANDOM` + Random = c::POSIX_FADV_RANDOM as c::c_uint, + + /// `POSIX_FADV_NOREUSE` + NoReuse = c::POSIX_FADV_NOREUSE as c::c_uint, + + /// `POSIX_FADV_WILLNEED` + WillNeed = c::POSIX_FADV_WILLNEED as c::c_uint, + + /// `POSIX_FADV_DONTNEED` + DontNeed = c::POSIX_FADV_DONTNEED as c::c_uint, +} + +#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] +bitflags! { + /// `MFD_*` constants for use with [`memfd_create`]. + /// + /// [`memfd_create`]: crate::fs::memfd_create + pub struct MemfdFlags: c::c_uint { + /// `MFD_CLOEXEC` + const CLOEXEC = c::MFD_CLOEXEC; + + /// `MFD_ALLOW_SEALING` + const ALLOW_SEALING = c::MFD_ALLOW_SEALING; + + /// `MFD_HUGETLB` (since Linux 4.14) + const HUGETLB = c::MFD_HUGETLB; + + /// `MFD_HUGE_64KB` + const HUGE_64KB = c::MFD_HUGE_64KB; + /// `MFD_HUGE_512JB` + const HUGE_512KB = c::MFD_HUGE_512KB; + /// `MFD_HUGE_1MB` + const HUGE_1MB = c::MFD_HUGE_1MB; + /// `MFD_HUGE_2MB` + const HUGE_2MB = c::MFD_HUGE_2MB; + /// `MFD_HUGE_8MB` + const HUGE_8MB = c::MFD_HUGE_8MB; + /// `MFD_HUGE_16MB` + const HUGE_16MB = c::MFD_HUGE_16MB; + /// `MFD_HUGE_32MB` + const HUGE_32MB = c::MFD_HUGE_32MB; + /// `MFD_HUGE_256MB` + const HUGE_256MB = c::MFD_HUGE_256MB; + /// `MFD_HUGE_512MB` + const HUGE_512MB = c::MFD_HUGE_512MB; + /// `MFD_HUGE_1GB` + const HUGE_1GB = c::MFD_HUGE_1GB; + /// `MFD_HUGE_2GB` + const HUGE_2GB = c::MFD_HUGE_2GB; + /// `MFD_HUGE_16GB` + const HUGE_16GB = c::MFD_HUGE_16GB; + } +} + +#[cfg(any( + target_os = "android", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "linux", +))] +bitflags! { + /// `F_SEAL_*` constants for use with [`fcntl_add_seals`] and + /// [`fcntl_get_seals`]. + /// + /// [`fcntl_add_seals`]: crate::fs::fcntl_add_seals + /// [`fcntl_get_seals`]: crate::fs::fcntl_get_seals + pub struct SealFlags: i32 { + /// `F_SEAL_SEAL`. + const SEAL = c::F_SEAL_SEAL; + /// `F_SEAL_SHRINK`. + const SHRINK = c::F_SEAL_SHRINK; + /// `F_SEAL_GROW`. + const GROW = c::F_SEAL_GROW; + /// `F_SEAL_WRITE`. + const WRITE = c::F_SEAL_WRITE; + /// `F_SEAL_FUTURE_WRITE` (since Linux 5.1) + #[cfg(linux_kernel)] + const FUTURE_WRITE = c::F_SEAL_FUTURE_WRITE; + } +} + +#[cfg(all(target_os = "linux", target_env = "gnu"))] +bitflags! { + /// `STATX_*` constants for use with [`statx`]. + /// + /// [`statx`]: crate::fs::statx + pub struct StatxFlags: u32 { + /// `STATX_TYPE` + const TYPE = c::STATX_TYPE; + + /// `STATX_MODE` + const MODE = c::STATX_MODE; + + /// `STATX_NLINK` + const NLINK = c::STATX_NLINK; + + /// `STATX_UID` + const UID = c::STATX_UID; + + /// `STATX_GID` + const GID = c::STATX_GID; + + /// `STATX_ATIME` + const ATIME = c::STATX_ATIME; + + /// `STATX_MTIME` + const MTIME = c::STATX_MTIME; + + /// `STATX_CTIME` + const CTIME = c::STATX_CTIME; + + /// `STATX_INO` + const INO = c::STATX_INO; + + /// `STATX_SIZE` + const SIZE = c::STATX_SIZE; + + /// `STATX_BLOCKS` + const BLOCKS = c::STATX_BLOCKS; + + /// `STATX_BASIC_STATS` + const BASIC_STATS = c::STATX_BASIC_STATS; + + /// `STATX_BTIME` + const BTIME = c::STATX_BTIME; + + /// `STATX_MNT_ID` (since Linux 5.8) + const MNT_ID = c::STATX_MNT_ID; + + /// `STATX_ALL` + const ALL = c::STATX_ALL; + } +} + +#[cfg(any( + target_os = "android", + all(target_os = "linux", not(target_env = "gnu")), +))] +bitflags! { + /// `STATX_*` constants for use with [`statx`]. + /// + /// [`statx`]: crate::fs::statx + pub struct StatxFlags: u32 { + /// `STATX_TYPE` + const TYPE = 0x0001; + + /// `STATX_MODE` + const MODE = 0x0002; + + /// `STATX_NLINK` + const NLINK = 0x0004; + + /// `STATX_UID` + const UID = 0x0008; + + /// `STATX_GID` + const GID = 0x0010; + + /// `STATX_ATIME` + const ATIME = 0x0020; + + /// `STATX_MTIME` + const MTIME = 0x0040; + + /// `STATX_CTIME` + const CTIME = 0x0080; + + /// `STATX_INO` + const INO = 0x0100; + + /// `STATX_SIZE` + const SIZE = 0x0200; + + /// `STATX_BLOCKS` + const BLOCKS = 0x0400; + + /// `STATX_BASIC_STATS` + const BASIC_STATS = 0x07ff; + + /// `STATX_BTIME` + const BTIME = 0x800; + + /// `STATX_MNT_ID` (since Linux 5.8) + const MNT_ID = 0x1000; + + /// `STATX_ALL` + const ALL = 0xfff; + } +} + +#[cfg(not(any(netbsdlike, solarish, target_os = "aix", target_os = "redox")))] +bitflags! { + /// `FALLOC_FL_*` constants for use with [`fallocate`]. + /// + /// [`fallocate`]: crate::fs::fallocate + pub struct FallocateFlags: i32 { + /// `FALLOC_FL_KEEP_SIZE` + #[cfg(not(any( + bsd, + target_os = "aix", + target_os = "haiku", + target_os = "wasi", + )))] + const KEEP_SIZE = c::FALLOC_FL_KEEP_SIZE; + /// `FALLOC_FL_PUNCH_HOLE` + #[cfg(not(any( + bsd, + target_os = "aix", + target_os = "haiku", + target_os = "wasi", + )))] + const PUNCH_HOLE = c::FALLOC_FL_PUNCH_HOLE; + /// `FALLOC_FL_NO_HIDE_STALE` + #[cfg(not(any( + bsd, + target_os = "aix", + target_os = "haiku", + target_os = "linux", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "wasi", + )))] + const NO_HIDE_STALE = c::FALLOC_FL_NO_HIDE_STALE; + /// `FALLOC_FL_COLLAPSE_RANGE` + #[cfg(not(any( + bsd, + target_os = "aix", + target_os = "haiku", + target_os = "emscripten", + target_os = "wasi", + )))] + const COLLAPSE_RANGE = c::FALLOC_FL_COLLAPSE_RANGE; + /// `FALLOC_FL_ZERO_RANGE` + #[cfg(not(any( + bsd, + target_os = "aix", + target_os = "haiku", + target_os = "emscripten", + target_os = "wasi", + )))] + const ZERO_RANGE = c::FALLOC_FL_ZERO_RANGE; + /// `FALLOC_FL_INSERT_RANGE` + #[cfg(not(any( + bsd, + target_os = "aix", + target_os = "haiku", + target_os = "emscripten", + target_os = "wasi", + )))] + const INSERT_RANGE = c::FALLOC_FL_INSERT_RANGE; + /// `FALLOC_FL_UNSHARE_RANGE` + #[cfg(not(any( + bsd, + target_os = "aix", + target_os = "haiku", + target_os = "emscripten", + target_os = "wasi", + )))] + const UNSHARE_RANGE = c::FALLOC_FL_UNSHARE_RANGE; + } +} + +#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))] +bitflags! { + /// `ST_*` constants for use with [`StatVfs`]. + pub struct StatVfsMountFlags: u64 { + /// `ST_MANDLOCK` + #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux"))] + const MANDLOCK = c::ST_MANDLOCK as u64; + + /// `ST_NOATIME` + #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux"))] + const NOATIME = c::ST_NOATIME as u64; + + /// `ST_NODEV` + #[cfg(any(target_os = "aix", target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux"))] + const NODEV = c::ST_NODEV as u64; + + /// `ST_NODIRATIME` + #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux"))] + const NODIRATIME = c::ST_NODIRATIME as u64; + + /// `ST_NOEXEC` + #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux"))] + const NOEXEC = c::ST_NOEXEC as u64; + + /// `ST_NOSUID` + const NOSUID = c::ST_NOSUID as u64; + + /// `ST_RDONLY` + const RDONLY = c::ST_RDONLY as u64; + + /// `ST_RELATIME` + #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] + const RELATIME = c::ST_RELATIME as u64; + + /// `ST_SYNCHRONOUS` + #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux"))] + const SYNCHRONOUS = c::ST_SYNCHRONOUS as u64; + } +} + +/// `LOCK_*` constants for use with [`flock`] and [`fcntl_lock`]. +/// +/// [`flock`]: crate::fs::flock +/// [`fcntl_lock`]: crate::fs::fcntl_lock +#[cfg(not(target_os = "wasi"))] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[repr(i32)] +pub enum FlockOperation { + /// `LOCK_SH` + LockShared = c::LOCK_SH, + /// `LOCK_EX` + LockExclusive = c::LOCK_EX, + /// `LOCK_UN` + Unlock = c::LOCK_UN, + /// `LOCK_SH | LOCK_NB` + NonBlockingLockShared = c::LOCK_SH | c::LOCK_NB, + /// `LOCK_EX | LOCK_NB` + NonBlockingLockExclusive = c::LOCK_EX | c::LOCK_NB, + /// `LOCK_UN | LOCK_NB` + NonBlockingUnlock = c::LOCK_UN | c::LOCK_NB, +} + +/// `struct stat` for use with [`statat`] and [`fstat`]. +/// +/// [`statat`]: crate::fs::statat +/// [`fstat`]: crate::fs::fstat +#[cfg(not(linux_like))] +pub type Stat = c::stat; + +/// `struct stat` for use with [`statat`] and [`fstat`]. +/// +/// [`statat`]: crate::fs::statat +/// [`fstat`]: crate::fs::fstat +#[cfg(any( + all(linux_kernel, target_pointer_width = "64"), + target_os = "emscripten", + target_os = "l4re", +))] +pub type Stat = c::stat64; + +/// `struct stat` for use with [`statat`] and [`fstat`]. +/// +/// [`statat`]: crate::fs::statat +/// [`fstat`]: crate::fs::fstat +// On 32-bit, Linux's `struct stat64` has a 32-bit `st_mtime` and friends, so +// we use our own struct, populated from `statx` where possible, to avoid the +// y2038 bug. +#[cfg(all(linux_kernel, target_pointer_width = "32"))] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +#[allow(missing_docs)] +pub struct Stat { + pub st_dev: u64, + pub st_mode: u32, + pub st_nlink: u32, + pub st_uid: u32, + pub st_gid: u32, + pub st_rdev: u64, + pub st_size: i64, + pub st_blksize: u32, + pub st_blocks: u64, + pub st_atime: u64, + pub st_atime_nsec: u32, + pub st_mtime: u64, + pub st_mtime_nsec: u32, + pub st_ctime: u64, + pub st_ctime_nsec: u32, + pub st_ino: u64, +} + +/// `struct statfs` for use with [`statfs`] and [`fstatfs`]. +/// +/// [`statfs`]: crate::fs::statfs +/// [`fstatfs`]: crate::fs::fstatfs +#[cfg(not(any( + linux_like, + solarish, + target_os = "haiku", + target_os = "netbsd", + target_os = "redox", + target_os = "wasi", +)))] +#[allow(clippy::module_name_repetitions)] +pub type StatFs = c::statfs; + +/// `struct statfs` for use with [`statfs`] and [`fstatfs`]. +/// +/// [`statfs`]: crate::fs::statfs +/// [`fstatfs`]: crate::fs::fstatfs +#[cfg(linux_like)] +pub type StatFs = c::statfs64; + +/// `struct statvfs` for use with [`statvfs`] and [`fstatvfs`]. +/// +/// [`statvfs`]: crate::fs::statvfs +/// [`fstatvfs`]: crate::fs::fstatvfs +#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))] +#[allow(missing_docs)] +pub struct StatVfs { + pub f_bsize: u64, + pub f_frsize: u64, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + pub f_fsid: u64, + pub f_flag: StatVfsMountFlags, + pub f_namemax: u64, +} + +/// `struct statx` for use with [`statx`]. +/// +/// [`statx`]: crate::fs::statx +#[cfg(all(target_os = "linux", target_env = "gnu"))] +// Use the glibc `struct statx`. +pub type Statx = c::statx; + +/// `struct statx_timestamp` for use with [`Statx`]. +#[cfg(all(target_os = "linux", target_env = "gnu"))] +// Use the glibc `struct statx_timestamp`. +pub type StatxTimestamp = c::statx; + +/// `struct statx` for use with [`statx`]. +/// +/// [`statx`]: crate::fs::statx +// Non-glibc ABIs don't currently declare a `struct statx`, so we declare it +// ourselves. +#[cfg(any( + target_os = "android", + all(target_os = "linux", not(target_env = "gnu")), +))] +#[repr(C)] +#[allow(missing_docs)] +pub struct Statx { + pub stx_mask: u32, + pub stx_blksize: u32, + pub stx_attributes: u64, + pub stx_nlink: u32, + pub stx_uid: u32, + pub stx_gid: u32, + pub stx_mode: u16, + __statx_pad1: [u16; 1], + pub stx_ino: u64, + pub stx_size: u64, + pub stx_blocks: u64, + pub stx_attributes_mask: u64, + pub stx_atime: StatxTimestamp, + pub stx_btime: StatxTimestamp, + pub stx_ctime: StatxTimestamp, + pub stx_mtime: StatxTimestamp, + pub stx_rdev_major: u32, + pub stx_rdev_minor: u32, + pub stx_dev_major: u32, + pub stx_dev_minor: u32, + pub stx_mnt_id: u64, + __statx_pad2: u64, + __statx_pad3: [u64; 12], +} + +/// `struct statx_timestamp` for use with [`Statx`]. +// Non-glibc ABIs don't currently declare a `struct statx_timestamp`, so we +// declare it ourselves. +#[cfg(any( + target_os = "android", + all(target_os = "linux", not(target_env = "gnu")), +))] +#[repr(C)] +#[allow(missing_docs)] +pub struct StatxTimestamp { + pub tv_sec: i64, + pub tv_nsec: u32, + pub __statx_timestamp_pad1: [i32; 1], +} + +/// `mode_t` +#[cfg(not(all(target_os = "android", target_pointer_width = "32")))] +pub type RawMode = c::mode_t; + +/// `mode_t` +#[cfg(all(target_os = "android", target_pointer_width = "32"))] +pub type RawMode = c::c_uint; + +/// `dev_t` +#[cfg(not(all(target_os = "android", target_pointer_width = "32")))] +pub type Dev = c::dev_t; + +/// `dev_t` +#[cfg(all(target_os = "android", target_pointer_width = "32"))] +pub type Dev = c::c_ulonglong; + +/// `__fsword_t` +#[cfg(all( + target_os = "linux", + not(target_env = "musl"), + not(target_arch = "s390x"), +))] +pub type FsWord = c::__fsword_t; + +/// `__fsword_t` +#[cfg(all( + any(target_os = "android", all(target_os = "linux", target_env = "musl")), + target_pointer_width = "32", +))] +pub type FsWord = u32; + +/// `__fsword_t` +#[cfg(all( + any(target_os = "android", all(target_os = "linux", target_env = "musl")), + not(target_arch = "s390x"), + target_pointer_width = "64", +))] +pub type FsWord = u64; + +/// `__fsword_t` +// s390x uses `u32` for `statfs` entries, even though `__fsword_t` is `u64`. +#[cfg(all(target_os = "linux", target_arch = "s390x"))] +pub type FsWord = u32; + +/// `copyfile_state_t`—State for use with [`fcopyfile`]. +/// +/// [`fcopyfile`]: crate::fs::fcopyfile +#[cfg(apple)] +#[allow(non_camel_case_types)] +#[repr(transparent)] +#[derive(Copy, Clone)] +pub struct copyfile_state_t(pub(crate) *mut c::c_void); + +#[cfg(linux_kernel)] +bitflags! { + /// `MS_*` constants for use with [`mount`]. + /// + /// [`mount`]: crate::fs::mount + pub struct MountFlags: c::c_ulong { + /// `MS_BIND` + const BIND = c::MS_BIND; + + /// `MS_DIRSYNC` + const DIRSYNC = c::MS_DIRSYNC; + + /// `MS_LAZYTIME` + const LAZYTIME = c::MS_LAZYTIME; + + /// `MS_MANDLOCK` + #[doc(alias = "MANDLOCK")] + const PERMIT_MANDATORY_FILE_LOCKING = c::MS_MANDLOCK; + + /// `MS_NOATIME` + const NOATIME = c::MS_NOATIME; + + /// `MS_NODEV` + const NODEV = c::MS_NODEV; + + /// `MS_NODIRATIME` + const NODIRATIME = c::MS_NODIRATIME; + + /// `MS_NOEXEC` + const NOEXEC = c::MS_NOEXEC; + + /// `MS_NOSUID` + const NOSUID = c::MS_NOSUID; + + /// `MS_RDONLY` + const RDONLY = c::MS_RDONLY; + + /// `MS_REC` + const REC = c::MS_REC; + + /// `MS_RELATIME` + const RELATIME = c::MS_RELATIME; + + /// `MS_SILENT` + const SILENT = c::MS_SILENT; + + /// `MS_STRICTATIME` + const STRICTATIME = c::MS_STRICTATIME; + + /// `MS_SYNCHRONOUS` + const SYNCHRONOUS = c::MS_SYNCHRONOUS; + } +} + +#[cfg(linux_kernel)] +bitflags! { + /// `MS_*` constants for use with [`change_mount`]. + /// + /// [`change_mount`]: crate::fs::mount::change_mount + pub struct MountPropagationFlags: c::c_ulong { + /// `MS_SHARED` + const SHARED = c::MS_SHARED; + /// `MS_PRIVATE` + const PRIVATE = c::MS_PRIVATE; + /// `MS_SLAVE` + const SLAVE = c::MS_SLAVE; + /// `MS_UNBINDABLE` + const UNBINDABLE = c::MS_UNBINDABLE; + /// `MS_REC` + const REC = c::MS_REC; + } +} + +#[cfg(linux_kernel)] +bitflags! { + pub(crate) struct InternalMountFlags: c::c_ulong { + const REMOUNT = c::MS_REMOUNT; + const MOVE = c::MS_MOVE; + } +} + +#[cfg(linux_kernel)] +pub(crate) struct MountFlagsArg(pub(crate) c::c_ulong); + +#[cfg(linux_kernel)] +bitflags! { + /// `MNT_*` constants for use with [`unmount`]. + /// + /// [`unmount`]: crate::fs::mount::unmount + pub struct UnmountFlags: c::c_int { + /// `MNT_FORCE` + const FORCE = c::MNT_FORCE; + /// `MNT_DETACH` + const DETACH = c::MNT_DETACH; + /// `MNT_EXPIRE` + const EXPIRE = c::MNT_EXPIRE; + /// `UMOUNT_NOFOLLOW` + const NOFOLLOW = c::UMOUNT_NOFOLLOW; + } +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/io/epoll.rs b/vendor/rustix-0.37.22/src/backend/libc/io/epoll.rs new file mode 100644 index 000000000..6766aab34 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/io/epoll.rs @@ -0,0 +1,366 @@ +//! epoll support. +//! +//! This is an experiment, and it isn't yet clear whether epoll is the right +//! level of abstraction at which to introduce safety. But it works fairly well +//! in simple examples 🙂. +//! +//! # Examples +//! +//! ```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, 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. +//! let listen_sock = socket(AddressFamily::INET, SocketType::STREAM, Protocol::default())?; +//! bind_v4(&listen_sock, &SocketAddrV4::new(Ipv4Addr::LOCALHOST, 0))?; +//! listen(&listen_sock, 1)?; +//! +//! // Create an epoll object. Using `Owning` here means the epoll object will +//! // take ownership of the file descriptors registered with it. +//! let epoll = epoll::epoll_create(epoll::CreateFlags::CLOEXEC)?; +//! +//! // Register the socket with the epoll object. +//! 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::epoll_wait(&epoll, &mut event_list, -1)?; +//! for (_event_flags, target) in &event_list { +//! 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(&listen_sock)?; +//! ioctl_fionbio(&conn_sock, true)?; +//! 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. +//! let target = sockets.remove(&target).unwrap(); +//! write(&target, b"hello\n")?; +//! let _ = epoll::epoll_del(&epoll, &target)?; +//! } +//! } +//! } +//! # } +//! # #[cfg(not(feature = "net"))] +//! # fn main() {} +//! ``` + +use super::super::c; +use super::super::conv::{ret, ret_owned_fd, ret_u32}; +use crate::fd::{AsFd, AsRawFd, OwnedFd}; +use crate::io; +use alloc::vec::Vec; +use bitflags::bitflags; +use core::convert::TryInto; +use core::ptr::null_mut; + +bitflags! { + /// `EPOLL_*` for use with [`Epoll::new`]. + pub struct CreateFlags: c::c_int { + /// `EPOLL_CLOEXEC` + const CLOEXEC = c::EPOLL_CLOEXEC; + } +} + +bitflags! { + /// `EPOLL*` for use with [`Epoll::add`]. + #[derive(Default)] + pub struct EventFlags: u32 { + /// `EPOLLIN` + const IN = c::EPOLLIN as u32; + + /// `EPOLLOUT` + const OUT = c::EPOLLOUT as u32; + + /// `EPOLLPRI` + const PRI = c::EPOLLPRI as u32; + + /// `EPOLLERR` + const ERR = c::EPOLLERR as u32; + + /// `EPOLLHUP` + const HUP = c::EPOLLHUP as u32; + + /// `EPOLLRDNORM` + const RDNORM = c::EPOLLRDNORM as u32; + + /// `EPOLLRDBAND` + const RDBAND = c::EPOLLRDBAND as u32; + + /// `EPOLLWRNORM` + const WRNORM = c::EPOLLWRNORM as u32; + + /// `EPOLLWRBAND` + const WRBAND = c::EPOLLWRBAND as u32; + + /// `EPOLLMSG` + const MSG = c::EPOLLMSG as u32; + + /// `EPOLLRDHUP` + const RDHUP = c::EPOLLRDHUP as u32; + + /// `EPOLLET` + const ET = c::EPOLLET as u32; + + /// `EPOLLONESHOT` + const ONESHOT = c::EPOLLONESHOT as u32; + + /// `EPOLLWAKEUP` + const WAKEUP = c::EPOLLWAKEUP as u32; + + /// `EPOLLEXCLUSIVE` + #[cfg(not(target_os = "android"))] + const EXCLUSIVE = c::EPOLLEXCLUSIVE as u32; + } +} + +/// `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 epoll_create(flags: CreateFlags) -> io::Result<OwnedFd> { + // SAFETY: We're calling `epoll_create1` via FFI and we know how it + // behaves. + unsafe { ret_owned_fd(c::epoll_create1(flags.bits())) } +} + +/// `epoll_ctl(self, EPOLL_CTL_ADD, data, event)`—Adds an element to an +/// `Epoll`. +/// +/// 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<dyn SystemResource>`, then `epoll` can be thought to maintain a +/// `Weak<dyn SystemResource>` 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 { + let raw_fd = source.as_fd().as_raw_fd(); + ret(c::epoll_ctl( + epoll.as_fd().as_raw_fd(), + c::EPOLL_CTL_ADD, + raw_fd, + &mut c::epoll_event { + events: event_flags.bits(), + r#u64: data, + }, + )) + } +} + +/// `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<()> { + let raw_fd = source.as_fd().as_raw_fd(); + + // SAFETY: We're calling `epoll_ctl` via FFI and we know how it + // behaves. + unsafe { + ret(c::epoll_ctl( + epoll.as_fd().as_raw_fd(), + c::EPOLL_CTL_MOD, + raw_fd, + &mut c::epoll_event { + events: event_flags.bits(), + r#u64: data, + }, + )) + } +} + +/// `epoll_ctl(self, EPOLL_CTL_DEL, target, NULL)`—Removes an element in +/// this `Epoll`. +#[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(); + ret(c::epoll_ctl( + epoll.as_fd().as_raw_fd(), + c::EPOLL_CTL_DEL, + raw_fd, + null_mut(), + )) + } +} + +/// `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 = ret_u32(c::epoll_wait( + epoll.as_fd().as_raw_fd(), + event_list.events.as_mut_ptr().cast::<c::epoll_event>(), + event_list.events.capacity().try_into().unwrap_or(i32::MAX), + timeout, + ))?; + event_list.events.set_len(nfds as usize); + } + + Ok(()) +} + +/// An iterator over the `Event`s in an `EventVec`. +pub struct Iter<'a> { + iter: core::slice::Iter<'a, Event>, +} + +impl<'a> Iterator for Iter<'a> { + type Item = (EventFlags, u64); + + fn next(&mut self) -> Option<Self::Item> { + // 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. + self.iter + .next() + .map(|event| (event.event_flags, event.data)) + } +} + +/// A record of an event that occurred. +#[repr(C)] +#[cfg_attr( + any( + all( + target_arch = "x86", + not(target_env = "musl"), + not(target_os = "android"), + ), + target_arch = "x86_64", + ), + repr(packed) +)] +struct Event { + // Match the layout of `c::epoll_event`. We just use a `u64` instead of + // the full union. + event_flags: EventFlags, + data: u64, +} + +/// A vector of `Event`s, plus context for interpreting them. +pub struct EventVec { + events: Vec<Event>, +} + +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), + } + } + + /// Returns the current `Event` capacity of this `EventVec`. + #[inline] + pub fn capacity(&self) -> usize { + self.events.capacity() + } + + /// Reserves enough memory for at least `additional` more `Event`s. + #[inline] + pub fn reserve(&mut self, additional: usize) { + self.events.reserve(additional); + } + + /// Reserves enough memory for exactly `additional` more `Event`s. + #[inline] + pub fn reserve_exact(&mut self, additional: usize) { + self.events.reserve_exact(additional); + } + + /// Clears all the `Events` out of this `EventVec`. + #[inline] + pub fn clear(&mut self) { + self.events.clear(); + } + + /// Shrinks the capacity of this `EventVec` as much as possible. + #[inline] + pub fn shrink_to_fit(&mut self) { + self.events.shrink_to_fit(); + } + + /// Returns an iterator over the `Event`s in this `EventVec`. + #[inline] + pub fn iter(&self) -> Iter<'_> { + Iter { + iter: self.events.iter(), + } + } + + /// Returns the number of `Event`s logically contained in this `EventVec`. + #[inline] + pub fn len(&mut self) -> usize { + self.events.len() + } + + /// Tests whether this `EventVec` is logically empty. + #[inline] + pub fn is_empty(&mut self) -> bool { + self.events.is_empty() + } +} + +impl<'a> IntoIterator for &'a EventVec { + type IntoIter = Iter<'a>; + type Item = (EventFlags, u64); + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/io/errno.rs b/vendor/rustix-0.37.22/src/backend/libc/io/errno.rs new file mode 100644 index 000000000..9e808c0b4 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/io/errno.rs @@ -0,0 +1,731 @@ +//! The `rustix` `Errno` type. +//! +//! This type holds an OS error code, which conceptually corresponds to an +//! `errno` value. + +use super::super::c; +use libc_errno::errno; + +/// The error type for `rustix` APIs. +/// +/// This is similar to `std::io::Error`, but only holds an OS error code, +/// and no extra error value. +#[repr(transparent)] +#[doc(alias = "errno")] +#[derive(Eq, PartialEq, Hash, Copy, Clone)] +pub struct Errno(pub(crate) c::c_int); + +impl Errno { + /// `EACCES` + #[doc(alias = "ACCES")] + pub const ACCESS: Self = Self(c::EACCES); + /// `EADDRINUSE` + pub const ADDRINUSE: Self = Self(c::EADDRINUSE); + /// `EADDRNOTAVAIL` + pub const ADDRNOTAVAIL: Self = Self(c::EADDRNOTAVAIL); + /// `EADV` + #[cfg(not(any( + bsd, + windows, + target_os = "aix", + target_os = "haiku", + target_os = "wasi", + )))] + pub const ADV: Self = Self(c::EADV); + /// `EAFNOSUPPORT` + pub const AFNOSUPPORT: Self = Self(c::EAFNOSUPPORT); + /// `EAGAIN` + pub const AGAIN: Self = Self(c::EAGAIN); + /// `EALREADY` + pub const ALREADY: Self = Self(c::EALREADY); + /// `EAUTH` + #[cfg(bsd)] + pub const AUTH: Self = Self(c::EAUTH); + /// `EBADE` + #[cfg(not(any( + bsd, + windows, + target_os = "aix", + target_os = "haiku", + target_os = "wasi", + )))] + pub const BADE: Self = Self(c::EBADE); + /// `EBADF` + pub const BADF: Self = Self(c::EBADF); + /// `EBADFD` + #[cfg(not(any( + bsd, + windows, + target_os = "aix", + target_os = "haiku", + target_os = "wasi", + )))] + pub const BADFD: Self = Self(c::EBADFD); + /// `EBADMSG` + #[cfg(not(windows))] + pub const BADMSG: Self = Self(c::EBADMSG); + /// `EBADR` + #[cfg(not(any( + bsd, + windows, + target_os = "aix", + target_os = "haiku", + target_os = "wasi", + )))] + pub const BADR: Self = Self(c::EBADR); + /// `EBADRPC` + #[cfg(bsd)] + pub const BADRPC: Self = Self(c::EBADRPC); + /// `EBADRQC` + #[cfg(not(any( + bsd, + windows, + target_os = "aix", + target_os = "haiku", + target_os = "wasi", + )))] + pub const BADRQC: Self = Self(c::EBADRQC); + /// `EBADSLT` + #[cfg(not(any( + bsd, + windows, + target_os = "aix", + target_os = "haiku", + target_os = "wasi", + )))] + pub const BADSLT: Self = Self(c::EBADSLT); + /// `EBFONT` + #[cfg(not(any( + bsd, + windows, + target_os = "aix", + target_os = "haiku", + target_os = "wasi", + )))] + pub const BFONT: Self = Self(c::EBFONT); + /// `EBUSY` + #[cfg(not(windows))] + pub const BUSY: Self = Self(c::EBUSY); + /// `ECANCELED` + pub const CANCELED: Self = Self(c::ECANCELED); + /// `ECAPMODE` + #[cfg(target_os = "freebsd")] + pub const CAPMODE: Self = Self(c::ECAPMODE); + /// `ECHILD` + #[cfg(not(windows))] + pub const CHILD: Self = Self(c::ECHILD); + /// `ECHRNG` + #[cfg(not(any(bsd, windows, target_os = "haiku", target_os = "wasi")))] + pub const CHRNG: Self = Self(c::ECHRNG); + /// `ECOMM` + #[cfg(not(any( + bsd, + windows, + target_os = "aix", + target_os = "haiku", + target_os = "wasi", + )))] + pub const COMM: Self = Self(c::ECOMM); + /// `ECONNABORTED` + pub const CONNABORTED: Self = Self(c::ECONNABORTED); + /// `ECONNREFUSED` + pub const CONNREFUSED: Self = Self(c::ECONNREFUSED); + /// `ECONNRESET` + pub const CONNRESET: Self = Self(c::ECONNRESET); + /// `EDEADLK` + #[cfg(not(windows))] + pub const DEADLK: Self = Self(c::EDEADLK); + /// `EDEADLOCK` + #[cfg(not(any( + bsd, + windows, + target_os = "aix", + target_os = "android", + target_os = "haiku", + target_os = "wasi", + )))] + pub const DEADLOCK: Self = Self(c::EDEADLOCK); + /// `EDESTADDRREQ` + pub const DESTADDRREQ: Self = Self(c::EDESTADDRREQ); + /// `EDISCON` + #[cfg(windows)] + pub const DISCON: Self = Self(c::EDISCON); + /// `EDOM` + #[cfg(not(windows))] + pub const DOM: Self = Self(c::EDOM); + /// `EDOOFUS` + #[cfg(freebsdlike)] + pub const DOOFUS: Self = Self(c::EDOOFUS); + /// `EDOTDOT` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "haiku", + target_os = "wasi", + )))] + pub const DOTDOT: Self = Self(c::EDOTDOT); + /// `EDQUOT` + pub const DQUOT: Self = Self(c::EDQUOT); + /// `EEXIST` + #[cfg(not(windows))] + pub const EXIST: Self = Self(c::EEXIST); + /// `EFAULT` + pub const FAULT: Self = Self(c::EFAULT); + /// `EFBIG` + #[cfg(not(windows))] + pub const FBIG: Self = Self(c::EFBIG); + /// `EFTYPE` + #[cfg(any(bsd, target_env = "newlib"))] + pub const FTYPE: Self = Self(c::EFTYPE); + /// `EHOSTDOWN` + #[cfg(not(target_os = "wasi"))] + pub const HOSTDOWN: Self = Self(c::EHOSTDOWN); + /// `EHOSTUNREACH` + pub const HOSTUNREACH: Self = Self(c::EHOSTUNREACH); + /// `EHWPOISON` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "android", + target_os = "haiku", + target_os = "redox", + target_os = "wasi", + )))] + pub const HWPOISON: Self = Self(c::EHWPOISON); + /// `EIDRM` + #[cfg(not(windows))] + pub const IDRM: Self = Self(c::EIDRM); + /// `EILSEQ` + #[cfg(not(windows))] + pub const ILSEQ: Self = Self(c::EILSEQ); + /// `EINPROGRESS` + pub const INPROGRESS: Self = Self(c::EINPROGRESS); + /// `EINTR` + /// + /// For a convenient way to retry system calls that exit with `INTR`, use + /// [`retry_on_intr`]. + /// + /// [`retry_on_intr`]: crate::io::retry_on_intr + pub const INTR: Self = Self(c::EINTR); + /// `EINVAL` + pub const INVAL: Self = Self(c::EINVAL); + /// `EINVALIDPROCTABLE` + #[cfg(windows)] + pub const INVALIDPROCTABLE: Self = Self(c::EINVALIDPROCTABLE); + /// `EINVALIDPROVIDER` + #[cfg(windows)] + pub const INVALIDPROVIDER: Self = Self(c::EINVALIDPROVIDER); + /// `EIO` + #[cfg(not(windows))] + pub const IO: Self = Self(c::EIO); + /// `EISCONN` + pub const ISCONN: Self = Self(c::EISCONN); + /// `EISDIR` + #[cfg(not(windows))] + pub const ISDIR: Self = Self(c::EISDIR); + /// `EISNAM` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "haiku", + target_os = "wasi", + )))] + pub const ISNAM: Self = Self(c::EISNAM); + /// `EKEYEXPIRED` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "haiku", + target_os = "wasi", + )))] + pub const KEYEXPIRED: Self = Self(c::EKEYEXPIRED); + /// `EKEYREJECTED` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "haiku", + target_os = "wasi", + )))] + pub const KEYREJECTED: Self = Self(c::EKEYREJECTED); + /// `EKEYREVOKED` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "haiku", + target_os = "wasi", + )))] + pub const KEYREVOKED: Self = Self(c::EKEYREVOKED); + /// `EL2HLT` + #[cfg(not(any(bsd, windows, target_os = "haiku", target_os = "wasi")))] + pub const L2HLT: Self = Self(c::EL2HLT); + /// `EL2NSYNC` + #[cfg(not(any(bsd, windows, target_os = "haiku", target_os = "wasi")))] + pub const L2NSYNC: Self = Self(c::EL2NSYNC); + /// `EL3HLT` + #[cfg(not(any(bsd, windows, target_os = "haiku", target_os = "wasi")))] + pub const L3HLT: Self = Self(c::EL3HLT); + /// `EL3RST` + #[cfg(not(any(bsd, windows, target_os = "haiku", target_os = "wasi")))] + pub const L3RST: Self = Self(c::EL3RST); + /// `ELIBACC` + #[cfg(not(any( + bsd, + windows, + target_os = "aix", + target_os = "haiku", + target_os = "wasi", + )))] + pub const LIBACC: Self = Self(c::ELIBACC); + /// `ELIBBAD` + #[cfg(not(any( + bsd, + windows, + target_os = "aix", + target_os = "haiku", + target_os = "wasi", + )))] + pub const LIBBAD: Self = Self(c::ELIBBAD); + /// `ELIBEXEC` + #[cfg(not(any( + bsd, + windows, + target_os = "aix", + target_os = "haiku", + target_os = "wasi", + )))] + pub const LIBEXEC: Self = Self(c::ELIBEXEC); + /// `ELIBMAX` + #[cfg(not(any( + bsd, + windows, + target_os = "aix", + target_os = "haiku", + target_os = "wasi", + )))] + pub const LIBMAX: Self = Self(c::ELIBMAX); + /// `ELIBSCN` + #[cfg(not(any( + bsd, + windows, + target_os = "aix", + target_os = "haiku", + target_os = "wasi", + )))] + pub const LIBSCN: Self = Self(c::ELIBSCN); + /// `ELNRNG` + #[cfg(not(any(bsd, windows, target_os = "haiku", target_os = "wasi")))] + pub const LNRNG: Self = Self(c::ELNRNG); + /// `ELOOP` + pub const LOOP: Self = Self(c::ELOOP); + /// `EMEDIUMTYPE` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "haiku", + target_os = "wasi", + )))] + pub const MEDIUMTYPE: Self = Self(c::EMEDIUMTYPE); + /// `EMFILE` + pub const MFILE: Self = Self(c::EMFILE); + /// `EMLINK` + #[cfg(not(windows))] + pub const MLINK: Self = Self(c::EMLINK); + /// `EMSGSIZE` + pub const MSGSIZE: Self = Self(c::EMSGSIZE); + /// `EMULTIHOP` + #[cfg(not(any(windows, target_os = "openbsd")))] + pub const MULTIHOP: Self = Self(c::EMULTIHOP); + /// `ENAMETOOLONG` + pub const NAMETOOLONG: Self = Self(c::ENAMETOOLONG); + /// `ENAVAIL` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "haiku", + target_os = "wasi", + )))] + pub const NAVAIL: Self = Self(c::ENAVAIL); + /// `ENEEDAUTH` + #[cfg(bsd)] + pub const NEEDAUTH: Self = Self(c::ENEEDAUTH); + /// `ENETDOWN` + pub const NETDOWN: Self = Self(c::ENETDOWN); + /// `ENETRESET` + pub const NETRESET: Self = Self(c::ENETRESET); + /// `ENETUNREACH` + pub const NETUNREACH: Self = Self(c::ENETUNREACH); + /// `ENFILE` + #[cfg(not(windows))] + pub const NFILE: Self = Self(c::ENFILE); + /// `ENOANO` + #[cfg(not(any( + bsd, + windows, + target_os = "aix", + target_os = "haiku", + target_os = "wasi", + )))] + pub const NOANO: Self = Self(c::ENOANO); + /// `ENOATTR` + #[cfg(any(bsd, target_os = "haiku"))] + pub const NOATTR: Self = Self(c::ENOATTR); + /// `ENOBUFS` + pub const NOBUFS: Self = Self(c::ENOBUFS); + /// `ENOCSI` + #[cfg(not(any(bsd, windows, target_os = "haiku", target_os = "wasi")))] + pub const NOCSI: Self = Self(c::ENOCSI); + /// `ENODATA` + #[cfg(not(any( + freebsdlike, + windows, + target_os = "haiku", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const NODATA: Self = Self(c::ENODATA); + /// `ENODEV` + #[cfg(not(windows))] + pub const NODEV: Self = Self(c::ENODEV); + /// `ENOENT` + #[cfg(not(windows))] + pub const NOENT: Self = Self(c::ENOENT); + /// `ENOEXEC` + #[cfg(not(windows))] + pub const NOEXEC: Self = Self(c::ENOEXEC); + /// `ENOKEY` + #[cfg(not(any( + solarish, + bsd, + windows, + target_os = "aix", + target_os = "haiku", + target_os = "wasi", + )))] + pub const NOKEY: Self = Self(c::ENOKEY); + /// `ENOLCK` + #[cfg(not(windows))] + pub const NOLCK: Self = Self(c::ENOLCK); + /// `ENOLINK` + #[cfg(not(any(windows, target_os = "openbsd")))] + pub const NOLINK: Self = Self(c::ENOLINK); + /// `ENOMEDIUM` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "haiku", + target_os = "wasi", + )))] + pub const NOMEDIUM: Self = Self(c::ENOMEDIUM); + /// `ENOMEM` + #[cfg(not(windows))] + pub const NOMEM: Self = Self(c::ENOMEM); + /// `ENOMORE` + #[cfg(windows)] + pub const NOMORE: Self = Self(c::ENOMORE); + /// `ENOMSG` + #[cfg(not(windows))] + pub const NOMSG: Self = Self(c::ENOMSG); + /// `ENONET` + #[cfg(not(any( + bsd, + windows, + target_os = "aix", + target_os = "haiku", + target_os = "wasi", + )))] + pub const NONET: Self = Self(c::ENONET); + /// `ENOPKG` + #[cfg(not(any( + bsd, + windows, + target_os = "aix", + target_os = "haiku", + target_os = "wasi", + )))] + pub const NOPKG: Self = Self(c::ENOPKG); + /// `ENOPROTOOPT` + pub const NOPROTOOPT: Self = Self(c::ENOPROTOOPT); + /// `ENOSPC` + #[cfg(not(windows))] + pub const NOSPC: Self = Self(c::ENOSPC); + /// `ENOSR` + #[cfg(not(any( + freebsdlike, + windows, + target_os = "haiku", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const NOSR: Self = Self(c::ENOSR); + /// `ENOSTR` + #[cfg(not(any( + freebsdlike, + windows, + target_os = "haiku", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const NOSTR: Self = Self(c::ENOSTR); + /// `ENOSYS` + #[cfg(not(windows))] + pub const NOSYS: Self = Self(c::ENOSYS); + /// `ENOTBLK` + #[cfg(not(any(windows, target_os = "haiku", target_os = "wasi")))] + pub const NOTBLK: Self = Self(c::ENOTBLK); + /// `ENOTCAPABLE` + #[cfg(any(target_os = "freebsd", target_os = "wasi"))] + pub const NOTCAPABLE: Self = Self(c::ENOTCAPABLE); + /// `ENOTCONN` + pub const NOTCONN: Self = Self(c::ENOTCONN); + /// `ENOTDIR` + #[cfg(not(windows))] + pub const NOTDIR: Self = Self(c::ENOTDIR); + /// `ENOTEMPTY` + pub const NOTEMPTY: Self = Self(c::ENOTEMPTY); + /// `ENOTNAM` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "haiku", + target_os = "wasi", + )))] + pub const NOTNAM: Self = Self(c::ENOTNAM); + /// `ENOTRECOVERABLE` + #[cfg(not(any(freebsdlike, netbsdlike, windows, target_os = "haiku")))] + pub const NOTRECOVERABLE: Self = Self(c::ENOTRECOVERABLE); + /// `ENOTSOCK` + pub const NOTSOCK: Self = Self(c::ENOTSOCK); + /// `ENOTSUP` + #[cfg(not(any(windows, target_os = "haiku", target_os = "redox")))] + pub const NOTSUP: Self = Self(c::ENOTSUP); + /// `ENOTTY` + #[cfg(not(windows))] + pub const NOTTY: Self = Self(c::ENOTTY); + /// `ENOTUNIQ` + #[cfg(not(any( + bsd, + windows, + target_os = "aix", + target_os = "haiku", + target_os = "wasi", + )))] + pub const NOTUNIQ: Self = Self(c::ENOTUNIQ); + /// `ENXIO` + #[cfg(not(windows))] + pub const NXIO: Self = Self(c::ENXIO); + /// `EOPNOTSUPP` + pub const OPNOTSUPP: Self = Self(c::EOPNOTSUPP); + /// `EOVERFLOW` + #[cfg(not(windows))] + pub const OVERFLOW: Self = Self(c::EOVERFLOW); + /// `EOWNERDEAD` + #[cfg(not(any(freebsdlike, netbsdlike, windows, target_os = "haiku")))] + pub const OWNERDEAD: Self = Self(c::EOWNERDEAD); + /// `EPERM` + #[cfg(not(windows))] + pub const PERM: Self = Self(c::EPERM); + /// `EPFNOSUPPORT` + #[cfg(not(target_os = "wasi"))] + pub const PFNOSUPPORT: Self = Self(c::EPFNOSUPPORT); + /// `EPIPE` + #[cfg(not(windows))] + pub const PIPE: Self = Self(c::EPIPE); + /// `EPROCLIM` + #[cfg(bsd)] + pub const PROCLIM: Self = Self(c::EPROCLIM); + /// `EPROCUNAVAIL` + #[cfg(bsd)] + pub const PROCUNAVAIL: Self = Self(c::EPROCUNAVAIL); + /// `EPROGMISMATCH` + #[cfg(bsd)] + pub const PROGMISMATCH: Self = Self(c::EPROGMISMATCH); + /// `EPROGUNAVAIL` + #[cfg(bsd)] + pub const PROGUNAVAIL: Self = Self(c::EPROGUNAVAIL); + /// `EPROTO` + #[cfg(not(windows))] + pub const PROTO: Self = Self(c::EPROTO); + /// `EPROTONOSUPPORT` + pub const PROTONOSUPPORT: Self = Self(c::EPROTONOSUPPORT); + /// `EPROTOTYPE` + pub const PROTOTYPE: Self = Self(c::EPROTOTYPE); + /// `EPROVIDERFAILEDINIT` + #[cfg(windows)] + pub const PROVIDERFAILEDINIT: Self = Self(c::EPROVIDERFAILEDINIT); + /// `ERANGE` + #[cfg(not(windows))] + pub const RANGE: Self = Self(c::ERANGE); + /// `EREFUSED` + #[cfg(windows)] + pub const REFUSED: Self = Self(c::EREFUSED); + /// `EREMCHG` + #[cfg(not(any( + bsd, + windows, + target_os = "aix", + target_os = "haiku", + target_os = "wasi", + )))] + pub const REMCHG: Self = Self(c::EREMCHG); + /// `EREMOTE` + #[cfg(not(any(target_os = "haiku", target_os = "wasi")))] + pub const REMOTE: Self = Self(c::EREMOTE); + /// `EREMOTEIO` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "haiku", + target_os = "wasi", + )))] + pub const REMOTEIO: Self = Self(c::EREMOTEIO); + /// `ERESTART` + #[cfg(not(any(bsd, windows, target_os = "haiku", target_os = "wasi")))] + pub const RESTART: Self = Self(c::ERESTART); + /// `ERFKILL` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "android", + target_os = "haiku", + target_os = "redox", + target_os = "wasi", + )))] + pub const RFKILL: Self = Self(c::ERFKILL); + /// `EROFS` + #[cfg(not(windows))] + pub const ROFS: Self = Self(c::EROFS); + /// `ERPCMISMATCH` + #[cfg(bsd)] + pub const RPCMISMATCH: Self = Self(c::ERPCMISMATCH); + /// `ESHUTDOWN` + #[cfg(not(target_os = "wasi"))] + pub const SHUTDOWN: Self = Self(c::ESHUTDOWN); + /// `ESOCKTNOSUPPORT` + #[cfg(not(any(target_os = "haiku", target_os = "wasi")))] + pub const SOCKTNOSUPPORT: Self = Self(c::ESOCKTNOSUPPORT); + /// `ESPIPE` + #[cfg(not(windows))] + pub const SPIPE: Self = Self(c::ESPIPE); + /// `ESRCH` + #[cfg(not(windows))] + pub const SRCH: Self = Self(c::ESRCH); + /// `ESRMNT` + #[cfg(not(any( + bsd, + windows, + target_os = "aix", + target_os = "haiku", + target_os = "wasi", + )))] + pub const SRMNT: Self = Self(c::ESRMNT); + /// `ESTALE` + pub const STALE: Self = Self(c::ESTALE); + /// `ESTRPIPE` + #[cfg(not(any( + bsd, + windows, + target_os = "aix", + target_os = "haiku", + target_os = "wasi", + )))] + pub const STRPIPE: Self = Self(c::ESTRPIPE); + /// `ETIME` + #[cfg(not(any(freebsdlike, windows, target_os = "openbsd", target_os = "wasi")))] + pub const TIME: Self = Self(c::ETIME); + /// `ETIMEDOUT` + pub const TIMEDOUT: Self = Self(c::ETIMEDOUT); + /// `E2BIG` + #[cfg(not(windows))] + #[doc(alias = "2BIG")] + pub const TOOBIG: Self = Self(c::E2BIG); + /// `ETOOMANYREFS` + #[cfg(not(any(target_os = "haiku", target_os = "wasi")))] + pub const TOOMANYREFS: Self = Self(c::ETOOMANYREFS); + /// `ETXTBSY` + #[cfg(not(windows))] + pub const TXTBSY: Self = Self(c::ETXTBSY); + /// `EUCLEAN` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "haiku", + target_os = "wasi", + )))] + pub const UCLEAN: Self = Self(c::EUCLEAN); + /// `EUNATCH` + #[cfg(not(any(bsd, windows, target_os = "haiku", target_os = "wasi")))] + pub const UNATCH: Self = Self(c::EUNATCH); + /// `EUSERS` + #[cfg(not(any(target_os = "haiku", target_os = "wasi")))] + pub const USERS: Self = Self(c::EUSERS); + /// `EWOULDBLOCK` + pub const WOULDBLOCK: Self = Self(c::EWOULDBLOCK); + /// `EXDEV` + #[cfg(not(windows))] + pub const XDEV: Self = Self(c::EXDEV); + /// `EXFULL` + #[cfg(not(any( + bsd, + windows, + target_os = "aix", + target_os = "haiku", + target_os = "wasi", + )))] + pub const XFULL: Self = Self(c::EXFULL); +} + +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| if raw != 0 { Some(Self(raw)) } else { None }) + } + + /// Extract the raw OS error number from this error. + #[inline] + pub const fn raw_os_error(self) -> i32 { + self.0 + } + + /// Construct an `Errno` from a raw OS error number. + #[inline] + pub const fn from_raw_os_error(raw: i32) -> Self { + Self(raw) + } + + pub(crate) fn last_os_error() -> Self { + Self(errno().0) + } +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/io/io_slice.rs b/vendor/rustix-0.37.22/src/backend/libc/io/io_slice.rs new file mode 100644 index 000000000..de1ef434c --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/io/io_slice.rs @@ -0,0 +1,87 @@ +//! The following is derived from Rust's +//! library/std/src/sys/unix/io.rs +//! dca3f1b786efd27be3b325ed1e01e247aa589c3b. + +#![allow(missing_docs)] + +use super::super::c; +use core::marker::PhantomData; +use core::slice; + +#[derive(Copy, Clone)] +#[repr(transparent)] +pub struct IoSlice<'a> { + vec: c::iovec, + _p: PhantomData<&'a [u8]>, +} + +impl<'a> IoSlice<'a> { + #[inline] + pub fn new(buf: &'a [u8]) -> IoSlice<'a> { + IoSlice { + vec: c::iovec { + iov_base: buf.as_ptr() as *mut u8 as *mut c::c_void, + iov_len: buf.len(), + }, + _p: PhantomData, + } + } + + #[inline] + pub fn advance(&mut self, n: usize) { + if self.vec.iov_len < n { + panic!("advancing IoSlice beyond its length"); + } + + unsafe { + self.vec.iov_len -= n; + self.vec.iov_base = self.vec.iov_base.add(n); + } + } + + #[inline] + pub fn as_slice(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) } + } +} + +#[repr(transparent)] +pub struct IoSliceMut<'a> { + vec: c::iovec, + _p: PhantomData<&'a mut [u8]>, +} + +impl<'a> IoSliceMut<'a> { + #[inline] + pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { + IoSliceMut { + vec: c::iovec { + iov_base: buf.as_mut_ptr() as *mut c::c_void, + iov_len: buf.len(), + }, + _p: PhantomData, + } + } + + #[inline] + pub fn advance(&mut self, n: usize) { + if self.vec.iov_len < n { + panic!("advancing IoSliceMut beyond its length"); + } + + unsafe { + self.vec.iov_len -= n; + self.vec.iov_base = self.vec.iov_base.add(n); + } + } + + #[inline] + pub fn as_slice(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) } + } + + #[inline] + pub fn as_mut_slice(&mut self) -> &mut [u8] { + unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) } + } +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/io/mod.rs b/vendor/rustix-0.37.22/src/backend/libc/io/mod.rs new file mode 100644 index 000000000..0876066c4 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/io/mod.rs @@ -0,0 +1,13 @@ +pub(crate) mod errno; +#[cfg(not(windows))] +#[cfg(not(feature = "std"))] +pub(crate) mod io_slice; +pub(crate) mod poll_fd; +#[cfg(not(windows))] +pub(crate) mod types; + +#[cfg_attr(windows, path = "windows_syscalls.rs")] +pub(crate) mod syscalls; + +#[cfg(linux_kernel)] +pub mod epoll; diff --git a/vendor/rustix-0.37.22/src/backend/libc/io/poll_fd.rs b/vendor/rustix-0.37.22/src/backend/libc/io/poll_fd.rs new file mode 100644 index 000000000..97926b269 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/io/poll_fd.rs @@ -0,0 +1,134 @@ +use super::super::c; +use super::super::conv::borrowed_fd; +#[cfg(windows)] +use super::super::fd::RawFd; +use super::super::fd::{AsFd, AsRawFd, BorrowedFd, LibcFd}; +use bitflags::bitflags; +use core::marker::PhantomData; +#[cfg(windows)] +use std::fmt; + +bitflags! { + /// `POLL*` flags for use with [`poll`]. + /// + /// [`poll`]: crate::io::poll + pub struct PollFlags: c::c_short { + /// `POLLIN` + const IN = c::POLLIN; + /// `POLLPRI` + #[cfg(not(target_os = "wasi"))] + const PRI = c::POLLPRI; + /// `POLLOUT` + const OUT = c::POLLOUT; + /// `POLLRDNORM` + const RDNORM = c::POLLRDNORM; + /// `POLLWRNORM` + const WRNORM = c::POLLWRNORM; + /// `POLLRDBAND` + #[cfg(not(target_os = "wasi"))] + const RDBAND = c::POLLRDBAND; + /// `POLLWRBAND` + #[cfg(not(target_os = "wasi"))] + const WRBAND = c::POLLWRBAND; + /// `POLLERR` + const ERR = c::POLLERR; + /// `POLLHUP` + const HUP = c::POLLHUP; + /// `POLLNVAL` + const NVAL = c::POLLNVAL; + /// `POLLRDHUP` + #[cfg(all( + linux_kernel, + not(any(target_arch = "sparc", target_arch = "sparc64"))), + )] + const RDHUP = c::POLLRDHUP; + } +} + +/// `struct pollfd`—File descriptor and flags for use with [`poll`]. +/// +/// [`poll`]: crate::io::poll +#[doc(alias = "pollfd")] +#[derive(Clone)] +#[cfg_attr(not(windows), derive(Debug))] +#[repr(transparent)] +pub struct PollFd<'fd> { + pollfd: c::pollfd, + _phantom: PhantomData<BorrowedFd<'fd>>, +} + +#[cfg(windows)] +impl<'fd> fmt::Debug for PollFd<'fd> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("pollfd") + .field("fd", &self.pollfd.fd) + .field("events", &self.pollfd.events) + .field("revents", &self.pollfd.revents) + .finish() + } +} + +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.pollfd.fd = fd.as_fd().as_raw_fd() as LibcFd; + } + + /// Clears the ready events. + #[inline] + pub fn clear_revents(&mut self) { + self.pollfd.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 { + pollfd: c::pollfd { + fd: borrowed_fd(fd), + events: events.bits(), + revents: 0, + }, + _phantom: PhantomData, + } + } + + /// 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.pollfd.revents).unwrap() + } +} + +#[cfg(not(windows))] +impl<'fd> AsFd for PollFd<'fd> { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + // SAFETY: Our constructors and `set_fd` require `pollfd.fd` to be + // valid for the `fd lifetime. + unsafe { BorrowedFd::borrow_raw(self.pollfd.fd) } + } +} + +#[cfg(windows)] +impl<'fd> io_lifetimes::AsSocket for PollFd<'fd> { + #[inline] + fn as_socket(&self) -> BorrowedFd<'_> { + // SAFETY: Our constructors and `set_fd` require `pollfd.fd` to be + // valid for the `fd lifetime. + unsafe { BorrowedFd::borrow_raw(self.pollfd.fd as RawFd) } + } +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/io/syscalls.rs b/vendor/rustix-0.37.22/src/backend/libc/io/syscalls.rs new file mode 100644 index 000000000..44ae4d221 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/io/syscalls.rs @@ -0,0 +1,681 @@ +//! libc syscalls supporting `rustix::io`. + +use super::super::c; +#[cfg(any( + target_os = "android", + all(target_os = "linux", not(target_env = "gnu")), +))] +use super::super::conv::syscall_ret_usize; +use super::super::conv::{borrowed_fd, ret, ret_c_int, ret_discarded_fd, ret_owned_fd, ret_usize}; +use super::super::offset::{libc_pread, libc_pwrite}; +#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "solaris")))] +use super::super::offset::{libc_preadv, libc_pwritev}; +#[cfg(all(target_os = "linux", target_env = "gnu"))] +use super::super::offset::{libc_preadv2, libc_pwritev2}; +use crate::fd::{AsFd, BorrowedFd, OwnedFd, RawFd}; +#[cfg(not(any(target_os = "aix", target_os = "wasi")))] +use crate::io::DupFlags; +#[cfg(any(linux_kernel, target_os = "freebsd", target_os = "illumos"))] +use crate::io::EventfdFlags; +#[cfg(not(any(apple, target_os = "aix", target_os = "haiku", target_os = "wasi")))] +use crate::io::PipeFlags; +use crate::io::{self, FdFlags, IoSlice, IoSliceMut, PollFd}; +use core::cmp::min; +use core::convert::TryInto; +use core::mem::MaybeUninit; +#[cfg(all(feature = "fs", feature = "net"))] +use libc_errno::errno; +#[cfg(linux_kernel)] +use { + super::super::conv::syscall_ret_owned_fd, + crate::io::{IoSliceRaw, ReadWriteFlags, SpliceFlags}, + crate::utils::optional_as_mut_ptr, +}; +#[cfg(bsd)] +use {crate::io::kqueue::Event, crate::utils::as_ptr, core::ptr::null}; +#[cfg(solarish)] +use {crate::io::port::Event, crate::utils::as_mut_ptr, core::ptr::null_mut}; + +pub(crate) fn read(fd: BorrowedFd<'_>, buf: &mut [u8]) -> io::Result<usize> { + unsafe { + ret_usize(c::read( + borrowed_fd(fd), + buf.as_mut_ptr().cast(), + min(buf.len(), READ_LIMIT), + )) + } +} + +pub(crate) fn write(fd: BorrowedFd<'_>, buf: &[u8]) -> io::Result<usize> { + unsafe { + ret_usize(c::write( + borrowed_fd(fd), + buf.as_ptr().cast(), + min(buf.len(), READ_LIMIT), + )) + } +} + +pub(crate) fn pread(fd: BorrowedFd<'_>, buf: &mut [u8], offset: u64) -> io::Result<usize> { + let len = min(buf.len(), READ_LIMIT); + + // Silently cast; we'll get `EINVAL` if the value is negative. + let offset = offset as i64; + + unsafe { + ret_usize(libc_pread( + borrowed_fd(fd), + buf.as_mut_ptr().cast(), + len, + offset, + )) + } +} + +pub(crate) fn pwrite(fd: BorrowedFd<'_>, buf: &[u8], offset: u64) -> io::Result<usize> { + let len = min(buf.len(), READ_LIMIT); + + // Silently cast; we'll get `EINVAL` if the value is negative. + let offset = offset as i64; + + unsafe { + ret_usize(libc_pwrite( + borrowed_fd(fd), + buf.as_ptr().cast(), + len, + offset, + )) + } +} + +pub(crate) fn readv(fd: BorrowedFd<'_>, bufs: &mut [IoSliceMut]) -> io::Result<usize> { + unsafe { + ret_usize(c::readv( + borrowed_fd(fd), + bufs.as_ptr().cast::<c::iovec>(), + min(bufs.len(), max_iov()) as c::c_int, + )) + } +} + +pub(crate) fn writev(fd: BorrowedFd<'_>, bufs: &[IoSlice]) -> io::Result<usize> { + unsafe { + ret_usize(c::writev( + borrowed_fd(fd), + bufs.as_ptr().cast::<c::iovec>(), + min(bufs.len(), max_iov()) as c::c_int, + )) + } +} + +#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "solaris")))] +pub(crate) fn preadv( + fd: BorrowedFd<'_>, + bufs: &mut [IoSliceMut], + offset: u64, +) -> io::Result<usize> { + // Silently cast; we'll get `EINVAL` if the value is negative. + let offset = offset as i64; + unsafe { + ret_usize(libc_preadv( + borrowed_fd(fd), + bufs.as_ptr().cast::<c::iovec>(), + min(bufs.len(), max_iov()) as c::c_int, + offset, + )) + } +} + +#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "solaris")))] +pub(crate) fn pwritev(fd: BorrowedFd<'_>, bufs: &[IoSlice], offset: u64) -> io::Result<usize> { + // Silently cast; we'll get `EINVAL` if the value is negative. + let offset = offset as i64; + unsafe { + ret_usize(libc_pwritev( + borrowed_fd(fd), + bufs.as_ptr().cast::<c::iovec>(), + min(bufs.len(), max_iov()) as c::c_int, + offset, + )) + } +} + +#[cfg(all(target_os = "linux", target_env = "gnu"))] +pub(crate) fn preadv2( + fd: BorrowedFd<'_>, + bufs: &mut [IoSliceMut], + offset: u64, + flags: ReadWriteFlags, +) -> io::Result<usize> { + // Silently cast; we'll get `EINVAL` if the value is negative. + let offset = offset as i64; + unsafe { + ret_usize(libc_preadv2( + borrowed_fd(fd), + bufs.as_ptr().cast::<c::iovec>(), + min(bufs.len(), max_iov()) as c::c_int, + offset, + flags.bits(), + )) + } +} + +/// At present, `libc` only has `preadv2` defined for glibc. On other +/// ABIs, use `c::syscall`. +#[cfg(any( + target_os = "android", + all(target_os = "linux", not(target_env = "gnu")), +))] +#[inline] +pub(crate) fn preadv2( + fd: BorrowedFd<'_>, + bufs: &mut [IoSliceMut], + offset: u64, + flags: ReadWriteFlags, +) -> io::Result<usize> { + // Silently cast; we'll get `EINVAL` if the value is negative. + let offset = offset as i64; + unsafe { + syscall_ret_usize(c::syscall( + c::SYS_preadv2, + borrowed_fd(fd), + bufs.as_ptr().cast::<c::iovec>(), + min(bufs.len(), max_iov()) as c::c_int, + offset, + flags.bits(), + )) + } +} + +#[cfg(all(target_os = "linux", target_env = "gnu"))] +pub(crate) fn pwritev2( + fd: BorrowedFd<'_>, + bufs: &[IoSlice], + offset: u64, + flags: ReadWriteFlags, +) -> io::Result<usize> { + // Silently cast; we'll get `EINVAL` if the value is negative. + let offset = offset as i64; + unsafe { + ret_usize(libc_pwritev2( + borrowed_fd(fd), + bufs.as_ptr().cast::<c::iovec>(), + min(bufs.len(), max_iov()) as c::c_int, + offset, + flags.bits(), + )) + } +} + +/// At present, `libc` only has `pwritev2` defined for glibc. On other +/// ABIs, use `c::syscall`. +#[cfg(any( + target_os = "android", + all(target_os = "linux", not(target_env = "gnu")), +))] +#[inline] +pub(crate) fn pwritev2( + fd: BorrowedFd<'_>, + bufs: &[IoSlice], + offset: u64, + flags: ReadWriteFlags, +) -> io::Result<usize> { + // Silently cast; we'll get `EINVAL` if the value is negative. + let offset = offset as i64; + unsafe { + syscall_ret_usize(c::syscall( + c::SYS_pwritev2, + borrowed_fd(fd), + bufs.as_ptr().cast::<c::iovec>(), + min(bufs.len(), max_iov()) as c::c_int, + offset, + flags.bits(), + )) + } +} + +// These functions are derived from Rust's library/std/src/sys/unix/fd.rs at +// revision 326ef470a8b379a180d6dc4bbef08990698a737a. + +// The maximum read limit on most POSIX-like systems is `SSIZE_MAX`, with the +// manual page quoting that if the count of bytes to read is greater than +// `SSIZE_MAX` the result is “unspecified”. +// +// On macOS, however, apparently the 64-bit libc is either buggy or +// intentionally showing odd behavior by rejecting any read with a size larger +// than or equal to `INT_MAX`. To handle both of these the read size is capped +// on both platforms. +#[cfg(target_os = "macos")] +const READ_LIMIT: usize = c::c_int::MAX as usize - 1; +#[cfg(not(target_os = "macos"))] +const READ_LIMIT: usize = c::ssize_t::MAX as usize; + +#[cfg(bsd)] +const fn max_iov() -> usize { + c::IOV_MAX as usize +} + +#[cfg(any(linux_kernel, target_os = "emscripten", target_os = "nto"))] +const fn max_iov() -> usize { + c::UIO_MAXIOV as usize +} + +#[cfg(not(any( + bsd, + linux_kernel, + target_os = "emscripten", + target_os = "nto", + target_os = "horizon", +)))] +const fn max_iov() -> usize { + 16 // The minimum value required by POSIX. +} + +pub(crate) unsafe fn close(raw_fd: RawFd) { + let _ = c::close(raw_fd as c::c_int); +} + +#[cfg(linux_kernel)] +pub(crate) fn eventfd(initval: u32, flags: EventfdFlags) -> io::Result<OwnedFd> { + unsafe { syscall_ret_owned_fd(c::syscall(c::SYS_eventfd2, initval, flags.bits())) } +} + +#[cfg(any(target_os = "freebsd", target_os = "illumos"))] +pub(crate) fn eventfd(initval: u32, flags: EventfdFlags) -> io::Result<OwnedFd> { + // `eventfd` was added in FreeBSD 13, so it isn't available on FreeBSD 12. + #[cfg(target_os = "freebsd")] + unsafe { + weakcall! { + fn eventfd( + initval: c::c_uint, + flags: c::c_int + ) -> c::c_int + } + ret_owned_fd(eventfd(initval, flags.bits())) + } + + #[cfg(target_os = "illumos")] + unsafe { + ret_owned_fd(c::eventfd(initval, flags.bits())) + } +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn ioctl_blksszget(fd: BorrowedFd) -> io::Result<u32> { + let mut result = MaybeUninit::<c::c_uint>::uninit(); + unsafe { + ret(c::ioctl(borrowed_fd(fd), c::BLKSSZGET, result.as_mut_ptr()))?; + Ok(result.assume_init() as u32) + } +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn ioctl_blkpbszget(fd: BorrowedFd) -> io::Result<u32> { + let mut result = MaybeUninit::<c::c_uint>::uninit(); + unsafe { + ret(c::ioctl( + borrowed_fd(fd), + c::BLKPBSZGET, + result.as_mut_ptr(), + ))?; + Ok(result.assume_init() as u32) + } +} + +#[cfg(not(target_os = "redox"))] +pub(crate) fn ioctl_fionread(fd: BorrowedFd<'_>) -> io::Result<u64> { + let mut nread = MaybeUninit::<c::c_int>::uninit(); + unsafe { + ret(c::ioctl(borrowed_fd(fd), c::FIONREAD, nread.as_mut_ptr()))?; + // `FIONREAD` returns the number of bytes silently casted to a `c_int`, + // even when this is lossy. The best we can do is convert it back to a + // `u64` without sign-extending it back first. + Ok(u64::from(nread.assume_init() as c::c_uint)) + } +} + +pub(crate) fn ioctl_fionbio(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> { + unsafe { + let data = value as c::c_int; + ret(c::ioctl(borrowed_fd(fd), c::FIONBIO, &data)) + } +} + +// Sparc lacks `FICLONE`. +#[cfg(all(linux_kernel, not(any(target_arch = "sparc", target_arch = "sparc64"))))] +pub(crate) fn ioctl_ficlone(fd: BorrowedFd<'_>, src_fd: BorrowedFd<'_>) -> io::Result<()> { + unsafe { + ret(c::ioctl( + borrowed_fd(fd), + c::FICLONE as _, + borrowed_fd(src_fd), + )) + } +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn ext4_ioc_resize_fs(fd: BorrowedFd<'_>, blocks: u64) -> io::Result<()> { + // TODO: Fix linux-raw-sys to define ioctl codes for sparc. + #[cfg(any(target_arch = "sparc", target_arch = "sparc64"))] + const EXT4_IOC_RESIZE_FS: u32 = 0x8008_6610; + + #[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] + use linux_raw_sys::ioctl::EXT4_IOC_RESIZE_FS; + + unsafe { ret(c::ioctl(borrowed_fd(fd), EXT4_IOC_RESIZE_FS as _, &blocks)) } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +#[cfg(all(feature = "fs", feature = "net"))] +pub(crate) fn is_read_write(fd: BorrowedFd<'_>) -> io::Result<(bool, bool)> { + let (mut read, mut write) = crate::fs::fd::_is_file_read_write(fd)?; + let mut not_socket = false; + if read { + // Do a `recv` with `PEEK` and `DONTWAIT` for 1 byte. A 0 indicates + // the read side is shut down; an `EWOULDBLOCK` indicates the read + // side is still open. + match unsafe { + c::recv( + borrowed_fd(fd), + MaybeUninit::<[u8; 1]>::uninit() + .as_mut_ptr() + .cast::<c::c_void>(), + 1, + c::MSG_PEEK | c::MSG_DONTWAIT, + ) + } { + 0 => read = false, + -1 => { + #[allow(unreachable_patterns)] // `EAGAIN` may equal `EWOULDBLOCK` + match errno().0 { + c::EAGAIN | c::EWOULDBLOCK => (), + c::ENOTSOCK => not_socket = true, + err => return Err(io::Errno(err)), + } + } + _ => (), + } + } + if write && !not_socket { + // Do a `send` with `DONTWAIT` for 0 bytes. An `EPIPE` indicates + // the write side is shut down. + if unsafe { c::send(borrowed_fd(fd), [].as_ptr(), 0, c::MSG_DONTWAIT) } == -1 { + #[allow(unreachable_patterns)] // `EAGAIN` may equal `EWOULDBLOCK` + match errno().0 { + c::EAGAIN | c::EWOULDBLOCK => (), + c::ENOTSOCK => (), + c::EPIPE => write = false, + err => return Err(io::Errno(err)), + } + } + } + Ok((read, write)) +} + +#[cfg(target_os = "wasi")] +#[cfg(all(feature = "fs", feature = "net"))] +pub(crate) fn is_read_write(_fd: BorrowedFd<'_>) -> io::Result<(bool, bool)> { + todo!("Implement is_read_write for WASI in terms of fd_fdstat_get"); +} + +pub(crate) fn fcntl_getfd(fd: BorrowedFd<'_>) -> io::Result<FdFlags> { + unsafe { ret_c_int(c::fcntl(borrowed_fd(fd), c::F_GETFD)).map(FdFlags::from_bits_truncate) } +} + +pub(crate) fn fcntl_setfd(fd: BorrowedFd<'_>, flags: FdFlags) -> io::Result<()> { + unsafe { ret(c::fcntl(borrowed_fd(fd), c::F_SETFD, flags.bits())) } +} + +#[cfg(not(target_os = "wasi"))] +pub(crate) fn fcntl_dupfd_cloexec(fd: BorrowedFd<'_>, min: RawFd) -> io::Result<OwnedFd> { + unsafe { ret_owned_fd(c::fcntl(borrowed_fd(fd), c::F_DUPFD_CLOEXEC, min)) } +} + +#[cfg(not(target_os = "wasi"))] +pub(crate) fn dup(fd: BorrowedFd<'_>) -> io::Result<OwnedFd> { + unsafe { ret_owned_fd(c::dup(borrowed_fd(fd))) } +} + +#[cfg(not(target_os = "wasi"))] +pub(crate) fn dup2(fd: BorrowedFd<'_>, new: &mut OwnedFd) -> io::Result<()> { + unsafe { ret_discarded_fd(c::dup2(borrowed_fd(fd), borrowed_fd(new.as_fd()))) } +} + +#[cfg(not(any( + apple, + target_os = "aix", + target_os = "android", + target_os = "dragonfly", + target_os = "haiku", + target_os = "redox", + target_os = "wasi", +)))] +pub(crate) fn dup3(fd: BorrowedFd<'_>, new: &mut OwnedFd, flags: DupFlags) -> io::Result<()> { + unsafe { + ret_discarded_fd(c::dup3( + borrowed_fd(fd), + borrowed_fd(new.as_fd()), + flags.bits(), + )) + } +} + +#[cfg(any( + apple, + target_os = "android", + target_os = "dragonfly", + target_os = "haiku", + target_os = "redox", +))] +pub(crate) fn dup3(fd: BorrowedFd<'_>, new: &mut OwnedFd, _flags: DupFlags) -> io::Result<()> { + // Android 5.0 has `dup3`, but libc doesn't have bindings. Emulate it + // using `dup2`. 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. + dup2(fd, new) +} + +#[cfg(apple)] +pub(crate) fn ioctl_fioclex(fd: BorrowedFd<'_>) -> io::Result<()> { + unsafe { + ret(c::ioctl( + borrowed_fd(fd), + c::FIOCLEX, + core::ptr::null_mut::<u8>(), + )) + } +} + +#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))] +pub(crate) fn ioctl_tiocexcl(fd: BorrowedFd) -> io::Result<()> { + unsafe { ret(c::ioctl(borrowed_fd(fd), c::TIOCEXCL as _)) } +} + +#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))] +pub(crate) fn ioctl_tiocnxcl(fd: BorrowedFd) -> io::Result<()> { + unsafe { ret(c::ioctl(borrowed_fd(fd), c::TIOCNXCL as _)) } +} + +#[cfg(bsd)] +pub(crate) fn kqueue() -> io::Result<OwnedFd> { + unsafe { ret_owned_fd(c::kqueue()) } +} + +#[cfg(bsd)] +pub(crate) unsafe fn kevent( + kq: BorrowedFd<'_>, + changelist: &[Event], + eventlist: &mut [MaybeUninit<Event>], + timeout: Option<&c::timespec>, +) -> io::Result<c::c_int> { + ret_c_int(c::kevent( + borrowed_fd(kq), + changelist.as_ptr().cast(), + changelist + .len() + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + eventlist.as_mut_ptr().cast(), + eventlist + .len() + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + timeout.map_or(null(), as_ptr), + )) +} + +#[cfg(not(target_os = "wasi"))] +pub(crate) fn pipe() -> io::Result<(OwnedFd, OwnedFd)> { + unsafe { + let mut result = MaybeUninit::<[OwnedFd; 2]>::uninit(); + ret(c::pipe(result.as_mut_ptr().cast::<i32>()))?; + let [p0, p1] = result.assume_init(); + Ok((p0, p1)) + } +} + +#[cfg(not(any(apple, target_os = "aix", target_os = "haiku", target_os = "wasi")))] +pub(crate) fn pipe_with(flags: PipeFlags) -> io::Result<(OwnedFd, OwnedFd)> { + unsafe { + let mut result = MaybeUninit::<[OwnedFd; 2]>::uninit(); + ret(c::pipe2(result.as_mut_ptr().cast::<i32>(), flags.bits()))?; + let [p0, p1] = result.assume_init(); + Ok((p0, p1)) + } +} + +#[inline] +pub(crate) fn poll(fds: &mut [PollFd<'_>], timeout: c::c_int) -> io::Result<usize> { + let nfds = fds + .len() + .try_into() + .map_err(|_convert_err| io::Errno::INVAL)?; + + ret_c_int(unsafe { c::poll(fds.as_mut_ptr().cast(), nfds, timeout) }) + .map(|nready| nready as usize) +} + +#[cfg(linux_kernel)] +#[inline] +pub fn splice( + fd_in: BorrowedFd, + off_in: Option<&mut u64>, + fd_out: BorrowedFd, + off_out: Option<&mut u64>, + len: usize, + flags: SpliceFlags, +) -> io::Result<usize> { + let off_in = optional_as_mut_ptr(off_in).cast(); + let off_out = optional_as_mut_ptr(off_out).cast(); + + unsafe { + ret_usize(c::splice( + borrowed_fd(fd_in), + off_in, + borrowed_fd(fd_out), + off_out, + len, + flags.bits(), + )) + } +} + +#[cfg(linux_kernel)] +#[inline] +pub unsafe fn vmsplice( + fd: BorrowedFd, + bufs: &[IoSliceRaw], + flags: SpliceFlags, +) -> io::Result<usize> { + ret_usize(c::vmsplice( + borrowed_fd(fd), + bufs.as_ptr().cast::<c::iovec>(), + min(bufs.len(), max_iov()), + flags.bits(), + )) +} + +#[cfg(solarish)] +pub(crate) fn port_create() -> io::Result<OwnedFd> { + unsafe { ret_owned_fd(c::port_create()) } +} + +#[cfg(solarish)] +pub(crate) unsafe fn port_associate( + port: BorrowedFd<'_>, + source: c::c_int, + object: c::uintptr_t, + events: c::c_int, + user: *mut c::c_void, +) -> io::Result<()> { + ret(c::port_associate( + borrowed_fd(port), + source, + object, + events, + user, + )) +} + +#[cfg(solarish)] +pub(crate) unsafe fn port_dissociate( + port: BorrowedFd<'_>, + source: c::c_int, + object: c::uintptr_t, +) -> io::Result<()> { + ret(c::port_dissociate(borrowed_fd(port), source, object)) +} + +#[cfg(solarish)] +pub(crate) fn port_get( + port: BorrowedFd<'_>, + timeout: Option<&mut c::timespec>, +) -> io::Result<Event> { + let mut event = MaybeUninit::<c::port_event>::uninit(); + let timeout = timeout.map_or(null_mut(), as_mut_ptr); + + unsafe { + ret(c::port_get(borrowed_fd(port), event.as_mut_ptr(), timeout))?; + } + + // If we're done, initialize the event and return it. + Ok(Event(unsafe { event.assume_init() })) +} + +#[cfg(solarish)] +pub(crate) fn port_getn( + port: BorrowedFd<'_>, + timeout: Option<&mut c::timespec>, + events: &mut Vec<Event>, + mut nget: u32, +) -> io::Result<()> { + let timeout = timeout.map_or(null_mut(), as_mut_ptr); + unsafe { + ret(c::port_getn( + borrowed_fd(port), + events.as_mut_ptr().cast(), + events.len().try_into().unwrap(), + &mut nget, + timeout, + ))?; + } + + // Update the vector length. + unsafe { + events.set_len(nget.try_into().unwrap()); + } + + Ok(()) +} + +#[cfg(solarish)] +pub(crate) fn port_send( + port: BorrowedFd<'_>, + events: c::c_int, + userdata: *mut c::c_void, +) -> io::Result<()> { + unsafe { ret(c::port_send(borrowed_fd(port), events, userdata)) } +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/io/types.rs b/vendor/rustix-0.37.22/src/backend/libc/io/types.rs new file mode 100644 index 000000000..711f0ba75 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/io/types.rs @@ -0,0 +1,153 @@ +use super::super::c; +use bitflags::bitflags; +#[cfg(linux_kernel)] +use core::marker::PhantomData; + +bitflags! { + /// `FD_*` constants for use with [`fcntl_getfd`] and [`fcntl_setfd`]. + /// + /// [`fcntl_getfd`]: crate::io::fcntl_getfd + /// [`fcntl_setfd`]: crate::io::fcntl_setfd + pub struct FdFlags: c::c_int { + /// `FD_CLOEXEC` + const CLOEXEC = c::FD_CLOEXEC; + } +} + +#[cfg(linux_kernel)] +bitflags! { + /// `RWF_*` constants for use with [`preadv2`] and [`pwritev2`]. + /// + /// [`preadv2`]: crate::io::preadv2 + /// [`pwritev2`]: crate::io::pwritev + pub struct ReadWriteFlags: c::c_int { + /// `RWF_DSYNC` (since Linux 4.7) + const DSYNC = linux_raw_sys::general::RWF_DSYNC as c::c_int; + /// `RWF_HIPRI` (since Linux 4.6) + const HIPRI = linux_raw_sys::general::RWF_HIPRI as c::c_int; + /// `RWF_SYNC` (since Linux 4.7) + const SYNC = linux_raw_sys::general::RWF_SYNC as c::c_int; + /// `RWF_NOWAIT` (since Linux 4.14) + const NOWAIT = linux_raw_sys::general::RWF_NOWAIT as c::c_int; + /// `RWF_APPEND` (since Linux 4.16) + const APPEND = linux_raw_sys::general::RWF_APPEND as c::c_int; + } +} + +#[cfg(linux_kernel)] +bitflags! { + /// `SPLICE_F_*` constants for use with [`splice`] and [`vmsplice`]. + pub struct SpliceFlags: c::c_uint { + /// `SPLICE_F_MOVE` + const MOVE = c::SPLICE_F_MOVE; + /// `SPLICE_F_NONBLOCK` + const NONBLOCK = c::SPLICE_F_NONBLOCK; + /// `SPLICE_F_MORE` + const MORE = c::SPLICE_F_MORE; + /// `SPLICE_F_GIFT` + const GIFT = c::SPLICE_F_GIFT; + } +} + +#[cfg(not(target_os = "wasi"))] +bitflags! { + /// `O_*` constants for use with [`dup2`]. + /// + /// [`dup2`]: crate::io::dup2 + pub struct DupFlags: c::c_int { + /// `O_CLOEXEC` + #[cfg(not(any( + apple, + target_os = "aix", + target_os = "android", + target_os = "redox", + )))] // Android 5.0 has dup3, but libc doesn't have bindings + const CLOEXEC = c::O_CLOEXEC; + } +} + +#[cfg(not(any(apple, target_os = "wasi")))] +bitflags! { + /// `O_*` constants for use with [`pipe_with`]. + /// + /// [`pipe_with`]: crate::io::pipe_with + pub struct PipeFlags: c::c_int { + /// `O_CLOEXEC` + const CLOEXEC = c::O_CLOEXEC; + /// `O_DIRECT` + #[cfg(not(any( + solarish, + target_os = "haiku", + target_os = "openbsd", + target_os = "redox", + )))] + const DIRECT = c::O_DIRECT; + /// `O_NONBLOCK` + const NONBLOCK = c::O_NONBLOCK; + } +} + +#[cfg(any(linux_kernel, target_os = "freebsd", target_os = "illumos"))] +bitflags! { + /// `EFD_*` flags for use with [`eventfd`]. + /// + /// [`eventfd`]: crate::io::eventfd + pub struct EventfdFlags: c::c_int { + /// `EFD_CLOEXEC` + const CLOEXEC = c::EFD_CLOEXEC; + /// `EFD_NONBLOCK` + const NONBLOCK = c::EFD_NONBLOCK; + /// `EFD_SEMAPHORE` + const SEMAPHORE = c::EFD_SEMAPHORE; + } +} + +/// `PIPE_BUF`—The maximum size of a write to a pipe guaranteed to be atomic. +#[cfg(not(any(solarish, target_os = "haiku", target_os = "redox", target_os = "wasi")))] +pub const PIPE_BUF: usize = c::PIPE_BUF; + +#[cfg(not(any(windows, target_os = "redox")))] +pub(crate) const AT_FDCWD: c::c_int = c::AT_FDCWD; +#[cfg(not(windows))] +pub(crate) const STDIN_FILENO: c::c_int = c::STDIN_FILENO; +#[cfg(not(windows))] +pub(crate) const STDOUT_FILENO: c::c_int = c::STDOUT_FILENO; +#[cfg(not(windows))] +pub(crate) const STDERR_FILENO: c::c_int = c::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. +#[cfg(linux_kernel)] +#[repr(transparent)] +pub struct IoSliceRaw<'a> { + _buf: c::iovec, + _lifetime: PhantomData<&'a ()>, +} + +#[cfg(linux_kernel)] +impl<'a> IoSliceRaw<'a> { + /// Creates a new `IoSlice` wrapping a byte slice. + pub fn from_slice(buf: &'a [u8]) -> Self { + IoSliceRaw { + _buf: c::iovec { + iov_base: buf.as_ptr() as *mut u8 as *mut c::c_void, + iov_len: buf.len() as _, + }, + _lifetime: PhantomData, + } + } + + /// Creates a new `IoSlice` wrapping a mutable byte slice. + pub fn from_slice_mut(buf: &'a mut [u8]) -> Self { + IoSliceRaw { + _buf: c::iovec { + iov_base: buf.as_mut_ptr() as *mut c::c_void, + iov_len: buf.len() as _, + }, + _lifetime: PhantomData, + } + } +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/io/windows_syscalls.rs b/vendor/rustix-0.37.22/src/backend/libc/io/windows_syscalls.rs new file mode 100644 index 000000000..4c6e86f94 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/io/windows_syscalls.rs @@ -0,0 +1,39 @@ +//! Windows system calls in the `io` module. + +use super::super::c; +use super::super::conv::{borrowed_fd, ret, ret_c_int}; +use super::super::fd::LibcFd; +use crate::fd::{BorrowedFd, RawFd}; +use crate::io; +use crate::io::PollFd; +use core::convert::TryInto; +use core::mem::MaybeUninit; + +pub(crate) unsafe fn close(raw_fd: RawFd) { + let _ = c::close(raw_fd as LibcFd); +} + +pub(crate) fn ioctl_fionread(fd: BorrowedFd<'_>) -> io::Result<u64> { + let mut nread = MaybeUninit::<c::c_ulong>::uninit(); + unsafe { + ret(c::ioctl(borrowed_fd(fd), c::FIONREAD, nread.as_mut_ptr()))?; + Ok(u64::from(nread.assume_init())) + } +} + +pub(crate) fn ioctl_fionbio(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> { + unsafe { + let mut data = value as c::c_uint; + ret(c::ioctl(borrowed_fd(fd), c::FIONBIO, &mut data)) + } +} + +pub(crate) fn poll(fds: &mut [PollFd<'_>], timeout: c::c_int) -> io::Result<usize> { + let nfds = fds + .len() + .try_into() + .map_err(|_convert_err| io::Errno::INVAL)?; + + ret_c_int(unsafe { c::poll(fds.as_mut_ptr().cast(), nfds, timeout) }) + .map(|nready| nready as usize) +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/io_lifetimes.rs b/vendor/rustix-0.37.22/src/backend/libc/io_lifetimes.rs new file mode 100644 index 000000000..993365c0c --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/io_lifetimes.rs @@ -0,0 +1,82 @@ +//! `io_lifetimes` types for Windows assuming that Fd is Socket. +//! +//! We can make this assumption since `rustix` supports only `rustix::net` on +//! Windows. + +pub use io_lifetimes::{BorrowedSocket as BorrowedFd, OwnedSocket as OwnedFd}; +#[cfg(feature = "std")] +pub use std::os::windows::io::RawSocket as RawFd; +pub(crate) use windows_sys::Win32::Networking::WinSock::SOCKET as LibcFd; + +// Re-export the `Socket` traits so that users can implement them. +pub use io_lifetimes::AsSocket; + +/// A version of [`AsRawFd`] for use with Winsock2 API. +/// +/// [`AsRawFd`]: https://doc.rust-lang.org/stable/std/os/fd/trait.AsRawFd.html +pub trait AsRawFd { + /// A version of [`as_raw_fd`] for use with Winsock2 API. + /// + /// [`as_raw_fd`]: https://doc.rust-lang.org/stable/std/os/fd/trait.FromRawFd.html#tymethod.as_raw_fd + fn as_raw_fd(&self) -> RawFd; +} +#[cfg(feature = "std")] +impl<T: std::os::windows::io::AsRawSocket> AsRawFd for T { + #[inline] + fn as_raw_fd(&self) -> RawFd { + self.as_raw_socket() + } +} + +/// A version of [`IntoRawFd`] for use with Winsock2 API. +/// +/// [`IntoRawFd`]: https://doc.rust-lang.org/stable/std/os/fd/trait.IntoRawFd.html +pub trait IntoRawFd { + /// A version of [`into_raw_fd`] for use with Winsock2 API. + /// + /// [`into_raw_fd`]: https://doc.rust-lang.org/stable/std/os/fd/trait.FromRawFd.html#tymethod.into_raw_fd + fn into_raw_fd(self) -> RawFd; +} +#[cfg(feature = "std")] +impl<T: std::os::windows::io::IntoRawSocket> IntoRawFd for T { + #[inline] + fn into_raw_fd(self) -> RawFd { + self.into_raw_socket() + } +} + +/// A version of [`FromRawFd`] for use with Winsock2 API. +/// +/// [`FromRawFd`]: https://doc.rust-lang.org/stable/std/os/fd/trait.FromRawFd.html +pub trait FromRawFd { + /// A version of [`from_raw_fd`] for use with Winsock2 API. + /// + /// # Safety + /// + /// See the [safety requirements] for [`from_raw_fd`]. + /// + /// [`from_raw_fd`]: https://doc.rust-lang.org/stable/std/os/fd/trait.FromRawFd.html#tymethod.from_raw_fd + /// [safety requirements]: https://doc.rust-lang.org/stable/std/os/fd/trait.FromRawFd.html#safety + unsafe fn from_raw_fd(raw_fd: RawFd) -> Self; +} +#[cfg(feature = "std")] +impl<T: std::os::windows::io::FromRawSocket> FromRawFd for T { + #[inline] + unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { + Self::from_raw_socket(raw_fd) + } +} + +/// A version of [`AsFd`] for use with Winsock2 API. +/// +/// [`AsFd`]: https://doc.rust-lang.org/stable/std/os/fd/trait.AsFd.html +pub trait AsFd { + /// An `as_fd` function for Winsock2, where a `Fd` is a `Socket`. + fn as_fd(&self) -> BorrowedFd; +} +impl<T: AsSocket> AsFd for T { + #[inline] + fn as_fd(&self) -> BorrowedFd { + self.as_socket() + } +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/io_uring/mod.rs b/vendor/rustix-0.37.22/src/backend/libc/io_uring/mod.rs new file mode 100644 index 000000000..ef944f04d --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/io_uring/mod.rs @@ -0,0 +1 @@ +pub(crate) mod syscalls; diff --git a/vendor/rustix-0.37.22/src/backend/libc/io_uring/syscalls.rs b/vendor/rustix-0.37.22/src/backend/libc/io_uring/syscalls.rs new file mode 100644 index 000000000..17d3eb10c --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/io_uring/syscalls.rs @@ -0,0 +1,55 @@ +//! libc syscalls supporting `rustix::io_uring`. + +use super::super::c; +use super::super::conv::{borrowed_fd, syscall_ret_owned_fd, syscall_ret_u32}; +use crate::fd::{BorrowedFd, OwnedFd}; +use crate::io; +use crate::io_uring::{io_uring_params, IoringEnterFlags, IoringRegisterOp}; +use linux_raw_sys::general::{__NR_io_uring_enter, __NR_io_uring_register, __NR_io_uring_setup}; + +#[inline] +pub(crate) fn io_uring_setup(entries: u32, params: &mut io_uring_params) -> io::Result<OwnedFd> { + unsafe { + syscall_ret_owned_fd(c::syscall( + __NR_io_uring_setup as _, + entries as usize, + params, + )) + } +} + +#[inline] +pub(crate) unsafe fn io_uring_register( + fd: BorrowedFd<'_>, + opcode: IoringRegisterOp, + arg: *const c::c_void, + nr_args: u32, +) -> io::Result<u32> { + syscall_ret_u32(c::syscall( + __NR_io_uring_register as _, + borrowed_fd(fd), + opcode as u32 as usize, + arg, + nr_args as usize, + )) +} + +#[inline] +pub(crate) unsafe fn io_uring_enter( + fd: BorrowedFd<'_>, + to_submit: u32, + min_complete: u32, + flags: IoringEnterFlags, + arg: *const c::c_void, + size: usize, +) -> io::Result<u32> { + syscall_ret_u32(c::syscall( + __NR_io_uring_enter as _, + borrowed_fd(fd), + to_submit as usize, + min_complete as usize, + flags.bits() as usize, + arg, + size, + )) +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/mm/mod.rs b/vendor/rustix-0.37.22/src/backend/libc/mm/mod.rs new file mode 100644 index 000000000..1e0181a99 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/mm/mod.rs @@ -0,0 +1,2 @@ +pub(crate) mod syscalls; +pub(crate) mod types; diff --git a/vendor/rustix-0.37.22/src/backend/libc/mm/syscalls.rs b/vendor/rustix-0.37.22/src/backend/libc/mm/syscalls.rs new file mode 100644 index 000000000..8d3d0f337 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/mm/syscalls.rs @@ -0,0 +1,218 @@ +//! libc syscalls supporting `rustix::mm`. + +use super::super::c; +#[cfg(linux_kernel)] +use super::super::conv::syscall_ret_owned_fd; +use super::super::conv::{borrowed_fd, no_fd, ret}; +use super::super::offset::libc_mmap; +#[cfg(not(target_os = "redox"))] +use super::types::Advice; +#[cfg(any(target_os = "emscripten", target_os = "linux"))] +use super::types::MremapFlags; +use super::types::{MapFlags, MprotectFlags, MsyncFlags, ProtFlags}; +#[cfg(linux_kernel)] +use super::types::{MlockFlags, UserfaultfdFlags}; +use crate::fd::BorrowedFd; +#[cfg(linux_kernel)] +use crate::fd::OwnedFd; +use crate::io; + +#[cfg(not(target_os = "redox"))] +pub(crate) fn madvise(addr: *mut c::c_void, len: usize, advice: Advice) -> io::Result<()> { + // On Linux platforms, `MADV_DONTNEED` has the same value as + // `POSIX_MADV_DONTNEED` but different behavior. We remap it to a different + // value, and check for it here. + #[cfg(target_os = "linux")] + if let Advice::LinuxDontNeed = advice { + return unsafe { ret(c::madvise(addr, len, c::MADV_DONTNEED)) }; + } + + #[cfg(not(target_os = "android"))] + { + let err = unsafe { c::posix_madvise(addr, len, advice as c::c_int) }; + + // `posix_madvise` returns its error status rather than using `errno`. + if err == 0 { + Ok(()) + } else { + Err(io::Errno(err)) + } + } + + #[cfg(target_os = "android")] + { + if let Advice::DontNeed = advice { + // Do nothing. Linux's `MADV_DONTNEED` isn't the same as + // `POSIX_MADV_DONTNEED`, so just discard `MADV_DONTNEED`. + Ok(()) + } else { + unsafe { ret(c::madvise(addr, len, advice as c::c_int)) } + } + } +} + +pub(crate) unsafe fn msync(addr: *mut c::c_void, len: usize, flags: MsyncFlags) -> io::Result<()> { + let err = c::msync(addr, len, flags.bits()); + + // `msync` returns its error status rather than using `errno`. + if err == 0 { + Ok(()) + } else { + Err(io::Errno(err)) + } +} + +/// # Safety +/// +/// `mmap` is primarily unsafe due to the `addr` parameter, as anything working +/// with memory pointed to by raw pointers is unsafe. +pub(crate) unsafe fn mmap( + ptr: *mut c::c_void, + len: usize, + prot: ProtFlags, + flags: MapFlags, + fd: BorrowedFd<'_>, + offset: u64, +) -> io::Result<*mut c::c_void> { + let res = libc_mmap( + ptr, + len, + prot.bits(), + flags.bits(), + borrowed_fd(fd), + offset as i64, + ); + if res == c::MAP_FAILED { + Err(io::Errno::last_os_error()) + } else { + Ok(res) + } +} + +/// # Safety +/// +/// `mmap` is primarily unsafe due to the `addr` parameter, as anything working +/// with memory pointed to by raw pointers is unsafe. +pub(crate) unsafe fn mmap_anonymous( + ptr: *mut c::c_void, + len: usize, + prot: ProtFlags, + flags: MapFlags, +) -> io::Result<*mut c::c_void> { + let res = libc_mmap( + ptr, + len, + prot.bits(), + flags.bits() | c::MAP_ANONYMOUS, + no_fd(), + 0, + ); + if res == c::MAP_FAILED { + Err(io::Errno::last_os_error()) + } else { + Ok(res) + } +} + +pub(crate) unsafe fn mprotect( + ptr: *mut c::c_void, + len: usize, + flags: MprotectFlags, +) -> io::Result<()> { + ret(c::mprotect(ptr, len, flags.bits())) +} + +pub(crate) unsafe fn munmap(ptr: *mut c::c_void, len: usize) -> io::Result<()> { + ret(c::munmap(ptr, len)) +} + +/// # Safety +/// +/// `mremap` is primarily unsafe due to the `old_address` parameter, as +/// anything working with memory pointed to by raw pointers is unsafe. +#[cfg(any(target_os = "emscripten", target_os = "linux"))] +pub(crate) unsafe fn mremap( + old_address: *mut c::c_void, + old_size: usize, + new_size: usize, + flags: MremapFlags, +) -> io::Result<*mut c::c_void> { + let res = c::mremap(old_address, old_size, new_size, flags.bits()); + if res == c::MAP_FAILED { + Err(io::Errno::last_os_error()) + } else { + Ok(res) + } +} + +/// # 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. +#[cfg(any(target_os = "emscripten", target_os = "linux"))] +pub(crate) unsafe fn mremap_fixed( + old_address: *mut c::c_void, + old_size: usize, + new_size: usize, + flags: MremapFlags, + new_address: *mut c::c_void, +) -> io::Result<*mut c::c_void> { + let res = c::mremap( + old_address, + old_size, + new_size, + flags.bits() | c::MAP_FIXED, + new_address, + ); + if res == c::MAP_FAILED { + Err(io::Errno::last_os_error()) + } else { + Ok(res) + } +} + +/// # Safety +/// +/// `mlock` operates on raw pointers and may round out to the nearest page +/// boundaries. +#[inline] +pub(crate) unsafe fn mlock(addr: *mut c::c_void, length: usize) -> io::Result<()> { + ret(c::mlock(addr, length)) +} + +/// # Safety +/// +/// `mlock_with` operates on raw pointers and may round out to the nearest page +/// boundaries. +#[cfg(linux_kernel)] +#[inline] +pub(crate) unsafe fn mlock_with( + addr: *mut c::c_void, + length: usize, + flags: MlockFlags, +) -> io::Result<()> { + weak_or_syscall! { + fn mlock2( + addr: *const c::c_void, + len: c::size_t, + flags: c::c_int + ) via SYS_mlock2 -> c::c_int + } + + ret(mlock2(addr, length, flags.bits())) +} + +/// # Safety +/// +/// `munlock` operates on raw pointers and may round out to the nearest page +/// boundaries. +#[inline] +pub(crate) unsafe fn munlock(addr: *mut c::c_void, length: usize) -> io::Result<()> { + ret(c::munlock(addr, length)) +} + +#[cfg(linux_kernel)] +pub(crate) unsafe fn userfaultfd(flags: UserfaultfdFlags) -> io::Result<OwnedFd> { + syscall_ret_owned_fd(c::syscall(c::SYS_userfaultfd, flags.bits())) +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/mm/types.rs b/vendor/rustix-0.37.22/src/backend/libc/mm/types.rs new file mode 100644 index 000000000..7c7071bbf --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/mm/types.rs @@ -0,0 +1,360 @@ +use super::super::c; +use bitflags::bitflags; + +bitflags! { + /// `PROT_*` flags for use with [`mmap`]. + /// + /// For `PROT_NONE`, use `ProtFlags::empty()`. + /// + /// [`mmap`]: crate::io::mmap + pub struct ProtFlags: c::c_int { + /// `PROT_READ` + const READ = c::PROT_READ; + /// `PROT_WRITE` + const WRITE = c::PROT_WRITE; + /// `PROT_EXEC` + const EXEC = c::PROT_EXEC; + } +} + +bitflags! { + /// `PROT_*` flags for use with [`mprotect`]. + /// + /// For `PROT_NONE`, use `MprotectFlags::empty()`. + /// + /// [`mprotect`]: crate::io::mprotect + pub struct MprotectFlags: c::c_int { + /// `PROT_READ` + const READ = c::PROT_READ; + /// `PROT_WRITE` + const WRITE = c::PROT_WRITE; + /// `PROT_EXEC` + const EXEC = c::PROT_EXEC; + /// `PROT_GROWSUP` + #[cfg(linux_kernel)] + const GROWSUP = c::PROT_GROWSUP; + /// `PROT_GROWSDOWN` + #[cfg(linux_kernel)] + const GROWSDOWN = c::PROT_GROWSDOWN; + } +} + +bitflags! { + /// `MAP_*` flags for use with [`mmap`]. + /// + /// For `MAP_ANONYMOUS` (aka `MAP_ANON`), see [`mmap_anonymous`]. + /// + /// [`mmap`]: crate::io::mmap + /// [`mmap_anonymous`]: crates::io::mmap_anonymous + pub struct MapFlags: c::c_int { + /// `MAP_SHARED` + const SHARED = c::MAP_SHARED; + /// `MAP_SHARED_VALIDATE` + #[cfg(not(any( + bsd, + solarish, + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "haiku", + target_os = "redox", + )))] + const SHARED_VALIDATE = c::MAP_SHARED_VALIDATE; + /// `MAP_PRIVATE` + const PRIVATE = c::MAP_PRIVATE; + /// `MAP_DENYWRITE` + #[cfg(not(any( + bsd, + solarish, + target_os = "haiku", + target_os = "redox", + )))] + const DENYWRITE = c::MAP_DENYWRITE; + /// `MAP_FIXED` + const FIXED = c::MAP_FIXED; + /// `MAP_FIXED_NOREPLACE` + #[cfg(not(any( + bsd, + solarish, + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "haiku", + target_os = "redox", + )))] + const FIXED_NOREPLACE = c::MAP_FIXED_NOREPLACE; + /// `MAP_GROWSDOWN` + #[cfg(not(any( + bsd, + solarish, + target_os = "haiku", + target_os = "redox", + )))] + const GROWSDOWN = c::MAP_GROWSDOWN; + /// `MAP_HUGETLB` + #[cfg(not(any( + bsd, + solarish, + target_os = "haiku", + target_os = "redox", + )))] + const HUGETLB = c::MAP_HUGETLB; + /// `MAP_HUGE_2MB` + #[cfg(not(any( + bsd, + solarish, + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "haiku", + target_os = "redox", + )))] + const HUGE_2MB = c::MAP_HUGE_2MB; + /// `MAP_HUGE_1GB` + #[cfg(not(any( + bsd, + solarish, + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "haiku", + target_os = "redox", + )))] + const HUGE_1GB = c::MAP_HUGE_1GB; + /// `MAP_LOCKED` + #[cfg(not(any( + bsd, + solarish, + target_os = "haiku", + target_os = "redox", + )))] + const LOCKED = c::MAP_LOCKED; + /// `MAP_NOCORE` + #[cfg(freebsdlike)] + const NOCORE = c::MAP_NOCORE; + /// `MAP_NORESERVE` + #[cfg(not(any(freebsdlike, target_os = "redox")))] + const NORESERVE = c::MAP_NORESERVE; + /// `MAP_NOSYNC` + #[cfg(freebsdlike)] + const NOSYNC = c::MAP_NOSYNC; + /// `MAP_POPULATE` + #[cfg(not(any( + bsd, + solarish, + target_os = "haiku", + target_os = "redox", + )))] + const POPULATE = c::MAP_POPULATE; + /// `MAP_STACK` + #[cfg(not(any( + apple, + solarish, + target_os = "dragonfly", + target_os = "haiku", + target_os = "netbsd", + target_os = "redox", + )))] + const STACK = c::MAP_STACK; + /// `MAP_PREFAULT_READ` + #[cfg(target_os = "freebsd")] + const PREFAULT_READ = c::MAP_PREFAULT_READ; + /// `MAP_SYNC` + #[cfg(not(any( + bsd, + solarish, + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "haiku", + target_os = "redox", + all( + linux_kernel, + any(target_arch = "mips", target_arch = "mips64"), + ) + )))] + const SYNC = c::MAP_SYNC; + /// `MAP_UNINITIALIZED` + #[cfg(any())] + const UNINITIALIZED = c::MAP_UNINITIALIZED; + } +} + +#[cfg(any(target_os = "emscripten", target_os = "linux"))] +bitflags! { + /// `MREMAP_*` flags for use with [`mremap`]. + /// + /// For `MREMAP_FIXED`, see [`mremap_fixed`]. + /// + /// [`mremap`]: crate::io::mremap + /// [`mremap_fixed`]: crate::io::mremap_fixed + pub struct MremapFlags: i32 { + /// `MREMAP_MAYMOVE` + const MAYMOVE = c::MREMAP_MAYMOVE; + } +} + +bitflags! { + /// `MS_*` flags for use with [`msync`]. + /// + /// [`msync`]: crate::io::msync + pub struct MsyncFlags: i32 { + /// `MS_SYNC`—Requests an update and waits for it to complete. + const SYNC = c::MS_SYNC; + /// `MS_ASYNC`—Specifies that an update be scheduled, but the call + /// returns immediately. + const ASYNC = c::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 = c::MS_INVALIDATE; + } +} + +#[cfg(linux_kernel)] +bitflags! { + /// `MLOCK_*` flags for use with [`mlock_with`]. + /// + /// [`mlock_with`]: crate::io::mlock_with + pub struct MlockFlags: i32 { + /// `MLOCK_ONFAULT` + const ONFAULT = c::MLOCK_ONFAULT as _; + } +} + +/// `POSIX_MADV_*` constants for use with [`madvise`]. +/// +/// [`madvise`]: crate::mm::madvise +#[cfg(not(target_os = "redox"))] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[repr(i32)] +#[non_exhaustive] +pub enum Advice { + /// `POSIX_MADV_NORMAL` + #[cfg(not(any(target_os = "android", target_os = "haiku")))] + Normal = c::POSIX_MADV_NORMAL, + + /// `POSIX_MADV_NORMAL` + #[cfg(any(target_os = "android", target_os = "haiku"))] + Normal = c::MADV_NORMAL, + + /// `POSIX_MADV_SEQUENTIAL` + #[cfg(not(any(target_os = "android", target_os = "haiku")))] + Sequential = c::POSIX_MADV_SEQUENTIAL, + + /// `POSIX_MADV_SEQUENTIAL` + #[cfg(any(target_os = "android", target_os = "haiku"))] + Sequential = c::MADV_SEQUENTIAL, + + /// `POSIX_MADV_RANDOM` + #[cfg(not(any(target_os = "android", target_os = "haiku")))] + Random = c::POSIX_MADV_RANDOM, + + /// `POSIX_MADV_RANDOM` + #[cfg(any(target_os = "android", target_os = "haiku"))] + Random = c::MADV_RANDOM, + + /// `POSIX_MADV_WILLNEED` + #[cfg(not(any(target_os = "android", target_os = "haiku")))] + WillNeed = c::POSIX_MADV_WILLNEED, + + /// `POSIX_MADV_WILLNEED` + #[cfg(any(target_os = "android", target_os = "haiku"))] + WillNeed = c::MADV_WILLNEED, + + /// `POSIX_MADV_DONTNEED` + #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "haiku")))] + DontNeed = c::POSIX_MADV_DONTNEED, + + /// `POSIX_MADV_DONTNEED` + #[cfg(any(target_os = "android", target_os = "haiku"))] + DontNeed = i32::MAX - 1, + + /// `MADV_DONTNEED` + // `MADV_DONTNEED` has the same value as `POSIX_MADV_DONTNEED`. We don't + // have a separate `posix_madvise` from `madvise`, so we expose a special + // value which we special-case. + #[cfg(target_os = "linux")] + LinuxDontNeed = i32::MAX, + + /// `MADV_DONTNEED` + #[cfg(target_os = "android")] + LinuxDontNeed = c::MADV_DONTNEED, + /// `MADV_FREE` + #[cfg(linux_kernel)] + LinuxFree = c::MADV_FREE, + /// `MADV_REMOVE` + #[cfg(linux_kernel)] + LinuxRemove = c::MADV_REMOVE, + /// `MADV_DONTFORK` + #[cfg(linux_kernel)] + LinuxDontFork = c::MADV_DONTFORK, + /// `MADV_DOFORK` + #[cfg(linux_kernel)] + LinuxDoFork = c::MADV_DOFORK, + /// `MADV_HWPOISON` + #[cfg(linux_kernel)] + LinuxHwPoison = c::MADV_HWPOISON, + /// `MADV_SOFT_OFFLINE` + #[cfg(all(linux_kernel, not(any(target_arch = "mips", target_arch = "mips64"))))] + LinuxSoftOffline = c::MADV_SOFT_OFFLINE, + /// `MADV_MERGEABLE` + #[cfg(linux_kernel)] + LinuxMergeable = c::MADV_MERGEABLE, + /// `MADV_UNMERGEABLE` + #[cfg(linux_kernel)] + LinuxUnmergeable = c::MADV_UNMERGEABLE, + /// `MADV_HUGEPAGE` (since Linux 2.6.38) + #[cfg(linux_kernel)] + LinuxHugepage = c::MADV_HUGEPAGE, + /// `MADV_NOHUGEPAGE` (since Linux 2.6.38) + #[cfg(linux_kernel)] + LinuxNoHugepage = c::MADV_NOHUGEPAGE, + /// `MADV_DONTDUMP` (since Linux 3.4) + #[cfg(linux_kernel)] + LinuxDontDump = c::MADV_DONTDUMP, + /// `MADV_DODUMP` (since Linux 3.4) + #[cfg(linux_kernel)] + LinuxDoDump = c::MADV_DODUMP, + /// `MADV_WIPEONFORK` (since Linux 4.14) + #[cfg(linux_kernel)] + LinuxWipeOnFork = libc::MADV_WIPEONFORK as i32, + /// `MADV_KEEPONFORK` (since Linux 4.14) + #[cfg(linux_kernel)] + LinuxKeepOnFork = libc::MADV_KEEPONFORK as i32, + /// `MADV_COLD` (since Linux 5.4) + #[cfg(linux_kernel)] + LinuxCold = libc::MADV_COLD as i32, + /// `MADV_PAGEOUT` (since Linux 5.4) + #[cfg(linux_kernel)] + LinuxPageOut = libc::MADV_PAGEOUT as i32, + /// `MADV_POPULATE_READ` (since Linux 5.14) + #[cfg(linux_kernel)] + LinuxPopulateRead = libc::MADV_POPULATE_READ as i32, + /// `MADV_POPULATE_WRITE` (since Linux 5.14) + #[cfg(linux_kernel)] + LinuxPopulateWrite = libc::MADV_POPULATE_WRITE as i32, + /// `MADV_DONTNEED_LOCKED` (since Linux 5.18) + #[cfg(linux_kernel)] + LinuxDontneedLocked = libc::MADV_DONTNEED_LOCKED as i32, +} + +#[cfg(target_os = "emscripten")] +#[allow(non_upper_case_globals)] +impl Advice { + /// `POSIX_MADV_DONTNEED` + pub const DontNeed: Self = Self::Normal; +} + +#[cfg(linux_kernel)] +bitflags! { + /// `O_*` flags for use with [`userfaultfd`]. + /// + /// [`userfaultfd`]: crate::io::userfaultfd + pub struct UserfaultfdFlags: c::c_int { + /// `O_CLOEXEC` + const CLOEXEC = c::O_CLOEXEC; + /// `O_NONBLOCK` + const NONBLOCK = c::O_NONBLOCK; + } +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/mod.rs b/vendor/rustix-0.37.22/src/backend/libc/mod.rs new file mode 100644 index 000000000..cfbf23f39 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/mod.rs @@ -0,0 +1,107 @@ +//! The libc backend. +//! +//! On most platforms, this uses the `libc` crate to make system calls. On +//! Windows, this uses the Winsock2 API in `windows-sys`, which can be adapted +//! to have a very `libc`-like interface. + +// Every FFI call requires an unsafe block, and there are a lot of FFI +// calls. For now, set this to allow for the libc backend. +#![allow(clippy::undocumented_unsafe_blocks)] +// Lots of libc types vary between platforms, so we often need a `.into()` on +// one platform where it's redundant on another. +#![allow(clippy::useless_conversion)] + +mod conv; +mod offset; + +#[cfg(windows)] +mod io_lifetimes; +#[cfg(not(windows))] +#[cfg(not(feature = "std"))] +pub(crate) mod fd { + pub(crate) use super::c::c_int as LibcFd; + pub use crate::io::fd::*; +} +#[cfg(windows)] +pub(crate) mod fd { + pub use super::io_lifetimes::*; +} +#[cfg(not(windows))] +#[cfg(feature = "std")] +pub(crate) mod fd { + pub use io_lifetimes::*; + + #[cfg(target_os = "wasi")] + #[allow(unused_imports)] + pub(crate) use super::c::c_int as LibcFd; + #[cfg(unix)] + #[allow(unused_imports)] + pub(crate) use std::os::unix::io::RawFd as LibcFd; + #[cfg(unix)] + pub use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; + #[cfg(target_os = "wasi")] + pub use std::os::wasi::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +} + +// On Windows we emulate selected libc-compatible interfaces. On non-Windows, +// we just use libc here, since this is the libc backend. +#[cfg_attr(windows, path = "winsock_c.rs")] +pub(crate) mod c; + +#[cfg(not(windows))] +#[cfg(feature = "fs")] +pub(crate) mod fs; +pub(crate) mod io; +#[cfg(linux_kernel)] +#[cfg(feature = "io_uring")] +pub(crate) mod io_uring; +#[cfg(not(any(windows, target_os = "wasi")))] +#[cfg(feature = "mm")] +pub(crate) mod mm; +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +#[cfg(feature = "net")] +pub(crate) mod net; +#[cfg(not(windows))] +#[cfg(any( + feature = "param", + feature = "runtime", + feature = "time", + target_arch = "x86", +))] +pub(crate) mod param; +#[cfg(not(windows))] +pub(crate) mod process; +#[cfg(not(windows))] +#[cfg(not(target_os = "wasi"))] +#[cfg(feature = "pty")] +pub(crate) mod pty; +#[cfg(not(windows))] +#[cfg(feature = "rand")] +pub(crate) mod rand; +#[cfg(not(windows))] +#[cfg(feature = "termios")] +pub(crate) mod termios; +#[cfg(not(windows))] +#[cfg(feature = "thread")] +pub(crate) mod thread; +#[cfg(not(windows))] +pub(crate) mod time; + +/// If the host libc is glibc, return `true` if it is less than version 2.25. +/// +/// To restate and clarify, this function returning true does not mean the libc +/// is glibc just that if it is glibc, it is less than version 2.25. +/// +/// For now, this function is only available on Linux, but if it ends up being +/// used beyond that, this could be changed to e.g. `#[cfg(unix)]`. +#[cfg(all(unix, target_env = "gnu"))] +pub(crate) fn if_glibc_is_less_than_2_25() -> bool { + // This is also defined inside `weak_or_syscall!` in + // backend/libc/rand/syscalls.rs, but it's not convenient to re-export the + // weak symbol from that macro, so we duplicate it at a small cost here. + weak! { fn getrandom(*mut c::c_void, c::size_t, c::c_uint) -> c::ssize_t } + + // glibc 2.25 has `getrandom`, which is how we satisfy the API contract of + // this function. But, there are likely other libc versions which have it. + getrandom.get().is_none() +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/net/addr.rs b/vendor/rustix-0.37.22/src/backend/libc/net/addr.rs new file mode 100644 index 000000000..1731ad24d --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/net/addr.rs @@ -0,0 +1,227 @@ +//! Socket address utilities. + +use super::super::c; +#[cfg(not(windows))] +use core::convert::TryInto; +#[cfg(unix)] +use { + crate::ffi::CStr, + crate::io, + crate::path, + core::cmp::Ordering, + core::fmt, + core::hash::{Hash, Hasher}, + core::slice, +}; + +/// `struct sockaddr_un` +#[cfg(unix)] +#[derive(Clone)] +#[doc(alias = "sockaddr_un")] +pub struct SocketAddrUnix { + pub(crate) unix: c::sockaddr_un, + #[cfg(not(any(bsd, target_os = "haiku")))] + len: c::socklen_t, +} + +#[cfg(unix)] +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 bytes = path.to_bytes_with_nul(); + if bytes.len() > unix.sun_path.len() { + return Err(io::Errno::NAMETOOLONG); + } + for (i, b) in bytes.iter().enumerate() { + unix.sun_path[i] = *b as c::c_char; + } + + #[cfg(any(bsd, target_os = "haiku"))] + { + unix.sun_len = (offsetof_sun_path() + bytes.len()).try_into().unwrap(); + } + + Ok(Self { + unix, + #[cfg(not(any(bsd, target_os = "haiku")))] + len: (offsetof_sun_path() + bytes.len()).try_into().unwrap(), + }) + } + + /// Construct a new abstract Unix-domain address from a byte slice. + #[cfg(linux_kernel)] + #[inline] + pub fn new_abstract_name(name: &[u8]) -> io::Result<Self> { + let mut unix = Self::init(); + if 1 + name.len() > unix.sun_path.len() { + return Err(io::Errno::NAMETOOLONG); + } + unix.sun_path[0] = 0; + for (i, b) in name.iter().enumerate() { + unix.sun_path[1 + i] = *b as c::c_char; + } + let len = offsetof_sun_path() + 1 + name.len(); + let len = len.try_into().unwrap(); + Ok(Self { + unix, + #[cfg(not(any(bsd, target_os = "haiku")))] + len, + }) + } + + fn init() -> c::sockaddr_un { + c::sockaddr_un { + #[cfg(any(bsd, target_os = "haiku"))] + sun_len: 0, + sun_family: c::AF_UNIX as _, + #[cfg(bsd)] + sun_path: [0; 104], + #[cfg(not(any(bsd, target_os = "haiku")))] + sun_path: [0; 108], + #[cfg(target_os = "haiku")] + sun_path: [0; 126], + } + } + + /// For a filesystem path address, return the path. + #[inline] + pub fn path(&self) -> Option<&CStr> { + let len = self.len(); + if len != 0 && self.unix.sun_path[0] != 0 { + 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 `from_bytes_with_nul_unchecked` since the string is + // NUL-terminated. + unsafe { + Some(CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts( + bytes.as_ptr().cast(), + bytes.len(), + ))) + } + } else { + None + } + } + + /// For an abstract address, return the identifier. + #[cfg(linux_kernel)] + #[inline] + pub fn abstract_name(&self) -> Option<&[u8]> { + let len = self.len(); + if len != 0 && self.unix.sun_path[0] == 0 { + 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]`. + unsafe { Some(slice::from_raw_parts(bytes.as_ptr().cast(), bytes.len())) } + } else { + None + } + } + + #[inline] + pub(crate) fn addr_len(&self) -> c::socklen_t { + #[cfg(not(any(bsd, target_os = "haiku")))] + { + self.len + } + #[cfg(any(bsd, target_os = "haiku"))] + { + c::socklen_t::from(self.unix.sun_len) + } + } + + #[inline] + pub(crate) fn len(&self) -> usize { + self.addr_len() as usize + } +} + +#[cfg(unix)] +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]) + } +} + +#[cfg(unix)] +impl Eq for SocketAddrUnix {} + +#[cfg(unix)] +impl PartialOrd for SocketAddrUnix { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + let self_len = self.len() - offsetof_sun_path(); + let other_len = other.len() - offsetof_sun_path(); + self.unix.sun_path[..self_len].partial_cmp(&other.unix.sun_path[..other_len]) + } +} + +#[cfg(unix)] +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]) + } +} + +#[cfg(unix)] +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) + } +} + +#[cfg(unix)] +impl fmt::Debug for SocketAddrUnix { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Some(path) = self.path() { + path.fmt(fmt) + } else { + #[cfg(linux_kernel)] + if let Some(name) = self.abstract_name() { + return name.fmt(fmt); + } + + "(unnamed)".fmt(fmt) + } + } +} + +/// `struct sockaddr_storage` as a raw struct. +pub type SocketAddrStorage = c::sockaddr_storage; + +/// Return the offset of the `sun_path` field of `sockaddr_un`. +#[cfg(not(windows))] +#[inline] +pub(crate) fn offsetof_sun_path() -> usize { + let z = c::sockaddr_un { + #[cfg(any(bsd, target_os = "haiku"))] + sun_len: 0_u8, + #[cfg(any(bsd, target_os = "haiku"))] + sun_family: 0_u8, + #[cfg(not(any(bsd, target_os = "haiku")))] + sun_family: 0_u16, + #[cfg(bsd)] + sun_path: [0; 104], + #[cfg(not(any(bsd, target_os = "haiku")))] + sun_path: [0; 108], + #[cfg(target_os = "haiku")] + sun_path: [0; 126], + }; + (crate::utils::as_ptr(&z.sun_path) as usize) - (crate::utils::as_ptr(&z) as usize) +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/net/ext.rs b/vendor/rustix-0.37.22/src/backend/libc/net/ext.rs new file mode 100644 index 000000000..f53205702 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/net/ext.rs @@ -0,0 +1,193 @@ +use super::super::c; + +/// The windows `sockaddr_in6` type is a union with accessor functions which +/// are not `const fn`. Define our own layout-compatible version so that we +/// can transmute in and out of it. +#[cfg(windows)] +#[repr(C)] +struct sockaddr_in6 { + sin6_family: u16, + sin6_port: u16, + sin6_flowinfo: u32, + sin6_addr: c::in6_addr, + sin6_scope_id: u32, +} + +#[cfg(not(windows))] +#[inline] +pub(crate) const fn in_addr_s_addr(addr: c::in_addr) -> u32 { + addr.s_addr +} + +#[cfg(not(feature = "std"))] +#[cfg(windows)] +#[inline] +pub(crate) const fn in_addr_s_addr(addr: c::in_addr) -> u32 { + // This should be `*addr.S_un.S_addr()`, except that isn't a `const fn`. + unsafe { core::mem::transmute(addr) } +} + +// TODO: With Rust 1.55, we can use the above `in_addr_s_addr` definition that +// uses a const-fn transmute. +#[cfg(feature = "std")] +#[cfg(windows)] +#[inline] +pub(crate) fn in_addr_s_addr(addr: c::in_addr) -> u32 { + // This should be `*addr.S_un.S_addr()`, except that isn't a `const fn`. + unsafe { core::mem::transmute(addr) } +} + +#[cfg(not(windows))] +#[inline] +pub(crate) const fn in_addr_new(s_addr: u32) -> c::in_addr { + c::in_addr { s_addr } +} + +#[cfg(not(feature = "std"))] +#[cfg(windows)] +#[inline] +pub(crate) const fn in_addr_new(s_addr: u32) -> c::in_addr { + unsafe { core::mem::transmute(s_addr) } +} + +// TODO: With Rust 1.55, we can use the above `in_addr_new` definition that +// uses a const-fn transmute. +#[cfg(feature = "std")] +#[cfg(windows)] +#[inline] +pub(crate) fn in_addr_new(s_addr: u32) -> c::in_addr { + unsafe { core::mem::transmute(s_addr) } +} + +#[cfg(not(windows))] +#[inline] +pub(crate) const fn in6_addr_s6_addr(addr: c::in6_addr) -> [u8; 16] { + addr.s6_addr +} + +#[cfg(not(feature = "std"))] +#[cfg(windows)] +#[inline] +pub(crate) const fn in6_addr_s6_addr(addr: c::in6_addr) -> [u8; 16] { + unsafe { core::mem::transmute(addr) } +} + +// TODO: With Rust 1.55, we can use the above `in6_addr_s6_addr` definition +// that uses a const-fn transmute. +#[cfg(feature = "std")] +#[cfg(windows)] +#[inline] +pub(crate) fn in6_addr_s6_addr(addr: c::in6_addr) -> [u8; 16] { + unsafe { core::mem::transmute(addr) } +} + +#[cfg(not(windows))] +#[inline] +pub(crate) const fn in6_addr_new(s6_addr: [u8; 16]) -> c::in6_addr { + c::in6_addr { s6_addr } +} + +#[cfg(not(feature = "std"))] +#[cfg(windows)] +#[inline] +pub(crate) const fn in6_addr_new(s6_addr: [u8; 16]) -> c::in6_addr { + unsafe { core::mem::transmute(s6_addr) } +} + +// TODO: With Rust 1.55, we can use the above `in6_addr_new` definition that +// uses a const-fn transmute. +#[cfg(feature = "std")] +#[cfg(windows)] +#[inline] +pub(crate) fn in6_addr_new(s6_addr: [u8; 16]) -> c::in6_addr { + unsafe { core::mem::transmute(s6_addr) } +} + +#[cfg(not(windows))] +#[inline] +pub(crate) const fn sockaddr_in6_sin6_scope_id(addr: &c::sockaddr_in6) -> u32 { + addr.sin6_scope_id +} + +#[cfg(not(feature = "std"))] +#[cfg(windows)] +#[inline] +pub(crate) const fn sockaddr_in6_sin6_scope_id(addr: &c::sockaddr_in6) -> u32 { + let addr: &sockaddr_in6 = unsafe { core::mem::transmute(addr) }; + addr.sin6_scope_id +} + +// TODO: With Rust 1.55, we can use the above `sockaddr_in6_sin6_scope_id` +// definition that uses a const-fn transmute. +#[cfg(feature = "std")] +#[cfg(windows)] +#[inline] +pub(crate) fn sockaddr_in6_sin6_scope_id(addr: &c::sockaddr_in6) -> u32 { + let addr: &sockaddr_in6 = unsafe { core::mem::transmute(addr) }; + addr.sin6_scope_id +} + +#[cfg(not(windows))] +#[inline] +pub(crate) const fn sockaddr_in6_new( + #[cfg(any(bsd, target_os = "haiku"))] sin6_len: u8, + sin6_family: c::sa_family_t, + sin6_port: u16, + sin6_flowinfo: u32, + sin6_addr: c::in6_addr, + sin6_scope_id: u32, +) -> c::sockaddr_in6 { + c::sockaddr_in6 { + #[cfg(any(bsd, target_os = "haiku"))] + sin6_len, + sin6_family, + sin6_port, + sin6_flowinfo, + sin6_addr, + sin6_scope_id, + #[cfg(solarish)] + __sin6_src_id: 0, + } +} + +#[cfg(not(feature = "std"))] +#[cfg(windows)] +#[inline] +pub(crate) const fn sockaddr_in6_new( + sin6_family: u16, + sin6_port: u16, + sin6_flowinfo: u32, + sin6_addr: c::in6_addr, + sin6_scope_id: u32, +) -> c::sockaddr_in6 { + let addr = sockaddr_in6 { + sin6_family, + sin6_port, + sin6_flowinfo, + sin6_addr, + sin6_scope_id, + }; + unsafe { core::mem::transmute(addr) } +} + +// TODO: With Rust 1.55, we can use the above `sockaddr_in6_new` definition +// that uses a const-fn transmute. +#[cfg(feature = "std")] +#[cfg(windows)] +#[inline] +pub(crate) fn sockaddr_in6_new( + sin6_family: u16, + sin6_port: u16, + sin6_flowinfo: u32, + sin6_addr: c::in6_addr, + sin6_scope_id: u32, +) -> c::sockaddr_in6 { + let addr = sockaddr_in6 { + sin6_family, + sin6_port, + sin6_flowinfo, + sin6_addr, + sin6_scope_id, + }; + unsafe { core::mem::transmute(addr) } +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/net/mod.rs b/vendor/rustix-0.37.22/src/backend/libc/net/mod.rs new file mode 100644 index 000000000..3c3a6ec56 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/net/mod.rs @@ -0,0 +1,9 @@ +pub(crate) mod addr; +pub(crate) mod ext; +#[cfg(not(any(target_os = "redox", target_os = "wasi", windows)))] +pub(crate) mod msghdr; +pub(crate) mod read_sockaddr; +pub(crate) mod send_recv; +pub(crate) mod syscalls; +pub(crate) mod types; +pub(crate) mod write_sockaddr; diff --git a/vendor/rustix-0.37.22/src/backend/libc/net/msghdr.rs b/vendor/rustix-0.37.22/src/backend/libc/net/msghdr.rs new file mode 100644 index 000000000..cb5053982 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/net/msghdr.rs @@ -0,0 +1,126 @@ +//! 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. + +use super::super::c; +use super::super::conv::{msg_control_len, msg_iov_len}; +use super::super::net::write_sockaddr::{encode_sockaddr_v4, encode_sockaddr_v6}; + +use crate::io::{self, IoSlice, IoSliceMut}; +use crate::net::{RecvAncillaryBuffer, SendAncillaryBuffer, SocketAddrV4, SocketAddrV6}; +use crate::utils::as_ptr; + +use core::convert::TryInto; +use core::mem::{size_of, zeroed, MaybeUninit}; + +/// Create a message header intended to receive a datagram. +pub(crate) fn with_recv_msghdr<R>( + name: &mut MaybeUninit<c::sockaddr_storage>, + iov: &mut [IoSliceMut<'_>], + control: &mut RecvAncillaryBuffer<'_>, + f: impl FnOnce(&mut c::msghdr) -> io::Result<R>, +) -> io::Result<R> { + control.clear(); + + let namelen = size_of::<c::sockaddr_storage>() as c::socklen_t; + let mut msghdr = { + let mut h: c::msghdr = unsafe { zeroed() }; + h.msg_name = name.as_mut_ptr().cast(); + h.msg_namelen = namelen; + h.msg_iov = iov.as_mut_ptr().cast(); + h.msg_iovlen = msg_iov_len(iov.len()); + h.msg_control = control.as_control_ptr().cast(); + h.msg_controllen = msg_control_len(control.control_len()); + h + }; + + let res = f(&mut msghdr); + + // Reset the control length. + if res.is_ok() { + unsafe { + control.set_control_len(msghdr.msg_controllen.try_into().unwrap_or(usize::MAX)); + } + } + + res +} + +/// Create a message header intended to send without an address. +pub(crate) fn with_noaddr_msghdr<R>( + iov: &[IoSlice<'_>], + control: &mut SendAncillaryBuffer<'_, '_, '_>, + f: impl FnOnce(c::msghdr) -> R, +) -> R { + f({ + let mut h: c::msghdr = unsafe { zeroed() }; + h.msg_iov = iov.as_ptr() as _; + h.msg_iovlen = msg_iov_len(iov.len()); + h.msg_control = control.as_control_ptr().cast(); + h.msg_controllen = msg_control_len(control.control_len()); + h + }) +} + +/// Create a message header intended to send with an IPv4 address. +pub(crate) fn with_v4_msghdr<R>( + addr: &SocketAddrV4, + iov: &[IoSlice<'_>], + control: &mut SendAncillaryBuffer<'_, '_, '_>, + f: impl FnOnce(c::msghdr) -> R, +) -> R { + let encoded = unsafe { encode_sockaddr_v4(addr) }; + + f({ + let mut h: c::msghdr = unsafe { zeroed() }; + h.msg_name = as_ptr(&encoded) as _; + h.msg_namelen = size_of::<SocketAddrV4>() as _; + h.msg_iov = iov.as_ptr() as _; + h.msg_iovlen = msg_iov_len(iov.len()); + h.msg_control = control.as_control_ptr().cast(); + h.msg_controllen = msg_control_len(control.control_len()); + h + }) +} + +/// Create a message header intended to send with an IPv6 address. +pub(crate) fn with_v6_msghdr<R>( + addr: &SocketAddrV6, + iov: &[IoSlice<'_>], + control: &mut SendAncillaryBuffer<'_, '_, '_>, + f: impl FnOnce(c::msghdr) -> R, +) -> R { + let encoded = unsafe { encode_sockaddr_v6(addr) }; + + f({ + let mut h: c::msghdr = unsafe { zeroed() }; + h.msg_name = as_ptr(&encoded) as _; + h.msg_namelen = size_of::<SocketAddrV6>() as _; + h.msg_iov = iov.as_ptr() as _; + h.msg_iovlen = msg_iov_len(iov.len()); + h.msg_control = control.as_control_ptr().cast(); + h.msg_controllen = msg_control_len(control.control_len()); + h + }) +} + +/// Create a message header intended to send with a Unix address. +#[cfg(all(unix, not(target_os = "redox")))] +pub(crate) fn with_unix_msghdr<R>( + addr: &crate::net::SocketAddrUnix, + iov: &[IoSlice<'_>], + control: &mut SendAncillaryBuffer<'_, '_, '_>, + f: impl FnOnce(c::msghdr) -> R, +) -> R { + f({ + let mut h: c::msghdr = unsafe { zeroed() }; + h.msg_name = as_ptr(addr) as _; + h.msg_namelen = addr.addr_len(); + h.msg_iov = iov.as_ptr() as _; + h.msg_iovlen = msg_iov_len(iov.len()); + h.msg_control = control.as_control_ptr().cast(); + h.msg_controllen = msg_control_len(control.control_len()); + h + }) +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/net/read_sockaddr.rs b/vendor/rustix-0.37.22/src/backend/libc/net/read_sockaddr.rs new file mode 100644 index 000000000..287048b4b --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/net/read_sockaddr.rs @@ -0,0 +1,241 @@ +use super::super::c; +#[cfg(unix)] +use super::addr::SocketAddrUnix; +use super::ext::{in6_addr_s6_addr, in_addr_s_addr, sockaddr_in6_sin6_scope_id}; +#[cfg(not(windows))] +use crate::ffi::CStr; +use crate::io; +use crate::net::{Ipv4Addr, Ipv6Addr, SocketAddrAny, SocketAddrV4, SocketAddrV6}; +use core::mem::size_of; + +// This must match the header of `sockaddr`. +#[repr(C)] +struct sockaddr_header { + #[cfg(any(bsd, target_os = "haiku"))] + sa_len: u8, + #[cfg(any(bsd, target_os = "haiku"))] + ss_family: u8, + #[cfg(not(any(bsd, target_os = "haiku")))] + ss_family: u16, +} + +#[inline] +unsafe fn read_ss_family(storage: *const c::sockaddr_storage) -> u16 { + // Assert that we know the layout of `sockaddr`. + let _ = c::sockaddr { + #[cfg(any(bsd, target_os = "haiku"))] + sa_len: 0_u8, + #[cfg(any(bsd, target_os = "haiku"))] + sa_family: 0_u8, + #[cfg(not(any(bsd, target_os = "haiku")))] + sa_family: 0_u16, + #[cfg(not(target_os = "haiku"))] + sa_data: [0; 14], + #[cfg(target_os = "haiku")] + sa_data: [0; 30], + }; + + (*storage.cast::<sockaddr_header>()).ss_family.into() +} + +/// Set the `ss_family` field of a socket address to `AF_UNSPEC`, so that we +/// can test for `AF_UNSPEC` to test whether it was stored to. +pub(crate) unsafe fn initialize_family_to_unspec(storage: *mut c::sockaddr_storage) { + (*storage.cast::<sockaddr_header>()).ss_family = c::AF_UNSPEC as _; +} + +pub(crate) unsafe fn read_sockaddr( + storage: *const c::sockaddr_storage, + len: usize, +) -> io::Result<SocketAddrAny> { + #[cfg(unix)] + let offsetof_sun_path = super::addr::offsetof_sun_path(); + + if len < size_of::<c::sa_family_t>() { + return Err(io::Errno::INVAL); + } + match read_ss_family(storage).into() { + c::AF_INET => { + if len < size_of::<c::sockaddr_in>() { + return Err(io::Errno::INVAL); + } + let decode = &*storage.cast::<c::sockaddr_in>(); + Ok(SocketAddrAny::V4(SocketAddrV4::new( + Ipv4Addr::from(u32::from_be(in_addr_s_addr(decode.sin_addr))), + u16::from_be(decode.sin_port), + ))) + } + c::AF_INET6 => { + if len < size_of::<c::sockaddr_in6>() { + return Err(io::Errno::INVAL); + } + let decode = &*storage.cast::<c::sockaddr_in6>(); + #[cfg(not(windows))] + let s6_addr = decode.sin6_addr.s6_addr; + #[cfg(windows)] + let s6_addr = decode.sin6_addr.u.Byte; + #[cfg(not(windows))] + let sin6_scope_id = decode.sin6_scope_id; + #[cfg(windows)] + let sin6_scope_id = decode.Anonymous.sin6_scope_id; + Ok(SocketAddrAny::V6(SocketAddrV6::new( + Ipv6Addr::from(s6_addr), + u16::from_be(decode.sin6_port), + u32::from_be(decode.sin6_flowinfo), + sin6_scope_id, + ))) + } + #[cfg(unix)] + c::AF_UNIX => { + if len < offsetof_sun_path { + return Err(io::Errno::INVAL); + } + if len == offsetof_sun_path { + SocketAddrUnix::new(&[][..]).map(SocketAddrAny::Unix) + } else { + let decode = &*storage.cast::<c::sockaddr_un>(); + + // On Linux check for Linux's [abstract namespace]. + // + // [abstract namespace]: https://man7.org/linux/man-pages/man7/unix.7.html + #[cfg(linux_kernel)] + if decode.sun_path[0] == 0 { + return SocketAddrUnix::new_abstract_name(core::mem::transmute::< + &[c::c_char], + &[u8], + >( + &decode.sun_path[1..len - offsetof_sun_path], + )) + .map(SocketAddrAny::Unix); + } + + // Otherwise we expect a NUL-terminated filesystem path. + + // Trim off unused bytes from the end of `path_bytes`. + let path_bytes = if cfg!(target_os = "freebsd") { + // FreeBSD sometimes sets the length to longer than the length + // of the NUL-terminated string. Find the NUL and truncate the + // string accordingly. + &decode.sun_path[..decode + .sun_path + .iter() + .position(|b| *b == 0) + .ok_or(io::Errno::INVAL)?] + } else { + // Otherwise, use the provided length. + let provided_len = len - 1 - offsetof_sun_path; + if decode.sun_path[provided_len] != 0 { + return Err(io::Errno::INVAL); + } + debug_assert_eq!( + CStr::from_ptr(decode.sun_path.as_ptr()).to_bytes().len(), + provided_len + ); + &decode.sun_path[..provided_len] + }; + + SocketAddrUnix::new(core::mem::transmute::<&[c::c_char], &[u8]>(path_bytes)) + .map(SocketAddrAny::Unix) + } + } + _ => Err(io::Errno::INVAL), + } +} + +pub(crate) unsafe fn maybe_read_sockaddr_os( + storage: *const c::sockaddr_storage, + len: usize, +) -> Option<SocketAddrAny> { + if len == 0 { + return None; + } + + assert!(len >= size_of::<c::sa_family_t>()); + let family = read_ss_family(storage).into(); + if family == c::AF_UNSPEC { + None + } else { + Some(inner_read_sockaddr_os(family, storage, len)) + } +} + +pub(crate) unsafe fn read_sockaddr_os( + storage: *const c::sockaddr_storage, + len: usize, +) -> SocketAddrAny { + assert!(len >= size_of::<c::sa_family_t>()); + let family = read_ss_family(storage).into(); + inner_read_sockaddr_os(family, storage, len) +} + +unsafe fn inner_read_sockaddr_os( + family: c::c_int, + storage: *const c::sockaddr_storage, + len: usize, +) -> SocketAddrAny { + #[cfg(unix)] + let offsetof_sun_path = super::addr::offsetof_sun_path(); + + assert!(len >= size_of::<c::sa_family_t>()); + match family { + c::AF_INET => { + assert!(len >= size_of::<c::sockaddr_in>()); + let decode = &*storage.cast::<c::sockaddr_in>(); + SocketAddrAny::V4(SocketAddrV4::new( + Ipv4Addr::from(u32::from_be(in_addr_s_addr(decode.sin_addr))), + u16::from_be(decode.sin_port), + )) + } + c::AF_INET6 => { + assert!(len >= size_of::<c::sockaddr_in6>()); + let decode = &*storage.cast::<c::sockaddr_in6>(); + SocketAddrAny::V6(SocketAddrV6::new( + Ipv6Addr::from(in6_addr_s6_addr(decode.sin6_addr)), + u16::from_be(decode.sin6_port), + u32::from_be(decode.sin6_flowinfo), + sockaddr_in6_sin6_scope_id(decode), + )) + } + #[cfg(unix)] + c::AF_UNIX => { + assert!(len >= offsetof_sun_path); + if len == offsetof_sun_path { + SocketAddrAny::Unix(SocketAddrUnix::new(&[][..]).unwrap()) + } else { + let decode = &*storage.cast::<c::sockaddr_un>(); + + // On Linux check for Linux's [abstract namespace]. + // + // [abstract namespace]: https://man7.org/linux/man-pages/man7/unix.7.html + #[cfg(linux_kernel)] + if decode.sun_path[0] == 0 { + return SocketAddrAny::Unix( + SocketAddrUnix::new_abstract_name(core::mem::transmute::< + &[c::c_char], + &[u8], + >( + &decode.sun_path[1..len - offsetof_sun_path], + )) + .unwrap(), + ); + } + + // Otherwise we expect a NUL-terminated filesystem path. + assert_eq!(decode.sun_path[len - 1 - offsetof_sun_path], 0); + let path_bytes = &decode.sun_path[..len - 1 - offsetof_sun_path]; + + // FreeBSD sometimes sets the length to longer than the length + // of the NUL-terminated string. Find the NUL and truncate the + // string accordingly. + #[cfg(target_os = "freebsd")] + let path_bytes = &path_bytes[..path_bytes.iter().position(|b| *b == 0).unwrap()]; + + SocketAddrAny::Unix( + SocketAddrUnix::new(core::mem::transmute::<&[c::c_char], &[u8]>(path_bytes)) + .unwrap(), + ) + } + } + other => unimplemented!("{:?}", other), + } +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/net/send_recv.rs b/vendor/rustix-0.37.22/src/backend/libc/net/send_recv.rs new file mode 100644 index 000000000..49c6f2c22 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/net/send_recv.rs @@ -0,0 +1,71 @@ +use super::super::c; +use bitflags::bitflags; + +bitflags! { + /// `MSG_* flags for use with [`send`], [`send_to`], and related functions. + /// + /// [`send`]: crate::net::send + /// [`sendto`]: crate::net::sendto + pub struct SendFlags: i32 { + /// `MSG_CONFIRM` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "haiku", + )))] + const CONFIRM = c::MSG_CONFIRM; + /// `MSG_DONTROUTE` + const DONTROUTE = c::MSG_DONTROUTE; + /// `MSG_DONTWAIT` + #[cfg(not(windows))] + const DONTWAIT = c::MSG_DONTWAIT; + /// `MSG_EOR` + #[cfg(not(windows))] + const EOT = c::MSG_EOR; + /// `MSG_MORE` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "haiku", + )))] + const MORE = c::MSG_MORE; + #[cfg(not(any(apple, windows)))] + /// `MSG_NOSIGNAL` + const NOSIGNAL = c::MSG_NOSIGNAL; + /// `MSG_OOB` + const OOB = c::MSG_OOB; + } +} + +bitflags! { + /// `MSG_* flags for use with [`recv`], [`recvfrom`], and related functions. + /// + /// [`recv`]: crate::net::recv + /// [`recvfrom`]: crate::net::recvfrom + pub struct RecvFlags: i32 { + #[cfg(not(any(apple, solarish, windows, target_os = "haiku")))] + /// `MSG_CMSG_CLOEXEC` + const CMSG_CLOEXEC = c::MSG_CMSG_CLOEXEC; + /// `MSG_DONTWAIT` + #[cfg(not(windows))] + const DONTWAIT = c::MSG_DONTWAIT; + /// `MSG_ERRQUEUE` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "haiku", + )))] + 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 as c::c_int; + /// `MSG_WAITALL` + const WAITALL = c::MSG_WAITALL; + } +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/net/syscalls.rs b/vendor/rustix-0.37.22/src/backend/libc/net/syscalls.rs new file mode 100644 index 000000000..54f2fe485 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/net/syscalls.rs @@ -0,0 +1,991 @@ +//! libc syscalls supporting `rustix::net`. + +use super::super::c; +use super::super::conv::{borrowed_fd, ret, ret_owned_fd, ret_send_recv, send_recv_len}; +#[cfg(unix)] +use super::addr::SocketAddrUnix; +use super::ext::{in6_addr_new, in_addr_new}; +use crate::fd::{BorrowedFd, OwnedFd}; +use crate::io; +use crate::net::{SocketAddrAny, SocketAddrV4, SocketAddrV6}; +use crate::utils::as_ptr; +use core::convert::TryInto; +use core::mem::{size_of, MaybeUninit}; +#[cfg(not(any(windows, target_os = "redox", target_os = "wasi")))] +use { + super::msghdr::{with_noaddr_msghdr, with_recv_msghdr, with_v4_msghdr, with_v6_msghdr}, + crate::io::{IoSlice, IoSliceMut}, + crate::net::{RecvAncillaryBuffer, RecvMsgReturn, SendAncillaryBuffer}, +}; +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +use { + super::read_sockaddr::{initialize_family_to_unspec, maybe_read_sockaddr_os, read_sockaddr_os}, + super::send_recv::{RecvFlags, SendFlags}, + super::types::{AddressFamily, Protocol, Shutdown, SocketFlags, SocketType}, + super::write_sockaddr::{encode_sockaddr_v4, encode_sockaddr_v6}, + core::ptr::null_mut, +}; + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn recv(fd: BorrowedFd<'_>, buf: &mut [u8], flags: RecvFlags) -> io::Result<usize> { + unsafe { + ret_send_recv(c::recv( + borrowed_fd(fd), + buf.as_mut_ptr().cast(), + send_recv_len(buf.len()), + flags.bits(), + )) + } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn send(fd: BorrowedFd<'_>, buf: &[u8], flags: SendFlags) -> io::Result<usize> { + unsafe { + ret_send_recv(c::send( + borrowed_fd(fd), + buf.as_ptr().cast(), + send_recv_len(buf.len()), + flags.bits(), + )) + } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn recvfrom( + fd: BorrowedFd<'_>, + buf: &mut [u8], + flags: RecvFlags, +) -> io::Result<(usize, Option<SocketAddrAny>)> { + unsafe { + let mut storage = MaybeUninit::<c::sockaddr_storage>::uninit(); + let mut len = size_of::<c::sockaddr_storage>() as c::socklen_t; + + // `recvfrom` does not write to the storage if the socket is + // connection-oriented sockets, so we initialize the family field to + // `AF_UNSPEC` so that we can detect this case. + initialize_family_to_unspec(storage.as_mut_ptr()); + + ret_send_recv(c::recvfrom( + borrowed_fd(fd), + buf.as_mut_ptr().cast(), + send_recv_len(buf.len()), + flags.bits(), + storage.as_mut_ptr().cast(), + &mut len, + )) + .map(|nread| { + ( + nread, + maybe_read_sockaddr_os(storage.as_ptr(), len.try_into().unwrap()), + ) + }) + } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn sendto_v4( + fd: BorrowedFd<'_>, + buf: &[u8], + flags: SendFlags, + addr: &SocketAddrV4, +) -> io::Result<usize> { + unsafe { + ret_send_recv(c::sendto( + borrowed_fd(fd), + buf.as_ptr().cast(), + send_recv_len(buf.len()), + flags.bits(), + as_ptr(&encode_sockaddr_v4(addr)).cast::<c::sockaddr>(), + size_of::<SocketAddrV4>() as _, + )) + } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn sendto_v6( + fd: BorrowedFd<'_>, + buf: &[u8], + flags: SendFlags, + addr: &SocketAddrV6, +) -> io::Result<usize> { + unsafe { + ret_send_recv(c::sendto( + borrowed_fd(fd), + buf.as_ptr().cast(), + send_recv_len(buf.len()), + flags.bits(), + as_ptr(&encode_sockaddr_v6(addr)).cast::<c::sockaddr>(), + size_of::<SocketAddrV6>() as _, + )) + } +} + +#[cfg(not(any(windows, target_os = "redox", target_os = "wasi")))] +pub(crate) fn sendto_unix( + fd: BorrowedFd<'_>, + buf: &[u8], + flags: SendFlags, + addr: &SocketAddrUnix, +) -> io::Result<usize> { + unsafe { + ret_send_recv(c::sendto( + borrowed_fd(fd), + buf.as_ptr().cast(), + send_recv_len(buf.len()), + flags.bits(), + as_ptr(&addr.unix).cast(), + addr.addr_len(), + )) + } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn socket( + domain: AddressFamily, + type_: SocketType, + protocol: Protocol, +) -> io::Result<OwnedFd> { + unsafe { + ret_owned_fd(c::socket( + domain.0 as c::c_int, + type_.0 as c::c_int, + protocol.0, + )) + } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn socket_with( + domain: AddressFamily, + type_: SocketType, + flags: SocketFlags, + protocol: Protocol, +) -> io::Result<OwnedFd> { + unsafe { + ret_owned_fd(c::socket( + domain.0 as c::c_int, + type_.0 as c::c_int | flags.bits(), + protocol.0, + )) + } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn bind_v4(sockfd: BorrowedFd<'_>, addr: &SocketAddrV4) -> io::Result<()> { + unsafe { + ret(c::bind( + borrowed_fd(sockfd), + as_ptr(&encode_sockaddr_v4(addr)).cast(), + size_of::<c::sockaddr_in>() as c::socklen_t, + )) + } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn bind_v6(sockfd: BorrowedFd<'_>, addr: &SocketAddrV6) -> io::Result<()> { + unsafe { + ret(c::bind( + borrowed_fd(sockfd), + as_ptr(&encode_sockaddr_v6(addr)).cast(), + size_of::<c::sockaddr_in6>() as c::socklen_t, + )) + } +} + +#[cfg(not(any(windows, target_os = "redox", target_os = "wasi")))] +pub(crate) fn bind_unix(sockfd: BorrowedFd<'_>, addr: &SocketAddrUnix) -> io::Result<()> { + unsafe { + ret(c::bind( + borrowed_fd(sockfd), + as_ptr(&addr.unix).cast(), + addr.addr_len(), + )) + } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn connect_v4(sockfd: BorrowedFd<'_>, addr: &SocketAddrV4) -> io::Result<()> { + unsafe { + ret(c::connect( + borrowed_fd(sockfd), + as_ptr(&encode_sockaddr_v4(addr)).cast(), + size_of::<c::sockaddr_in>() as c::socklen_t, + )) + } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn connect_v6(sockfd: BorrowedFd<'_>, addr: &SocketAddrV6) -> io::Result<()> { + unsafe { + ret(c::connect( + borrowed_fd(sockfd), + as_ptr(&encode_sockaddr_v6(addr)).cast(), + size_of::<c::sockaddr_in6>() as c::socklen_t, + )) + } +} + +#[cfg(not(any(windows, target_os = "redox", target_os = "wasi")))] +pub(crate) fn connect_unix(sockfd: BorrowedFd<'_>, addr: &SocketAddrUnix) -> io::Result<()> { + unsafe { + ret(c::connect( + borrowed_fd(sockfd), + as_ptr(&addr.unix).cast(), + addr.addr_len(), + )) + } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn listen(sockfd: BorrowedFd<'_>, backlog: c::c_int) -> io::Result<()> { + unsafe { ret(c::listen(borrowed_fd(sockfd), backlog)) } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn accept(sockfd: BorrowedFd<'_>) -> io::Result<OwnedFd> { + unsafe { + let owned_fd = ret_owned_fd(c::accept(borrowed_fd(sockfd), null_mut(), null_mut()))?; + Ok(owned_fd) + } +} + +#[cfg(not(any(windows, target_os = "redox", target_os = "wasi")))] +pub(crate) fn recvmsg( + sockfd: BorrowedFd<'_>, + iov: &mut [IoSliceMut<'_>], + control: &mut RecvAncillaryBuffer<'_>, + msg_flags: RecvFlags, +) -> io::Result<RecvMsgReturn> { + let mut storage = MaybeUninit::<c::sockaddr_storage>::uninit(); + + with_recv_msghdr(&mut storage, iov, control, |msghdr| { + let result = + unsafe { ret_send_recv(c::recvmsg(borrowed_fd(sockfd), msghdr, msg_flags.bits())) }; + + result.map(|bytes| { + // Get the address of the sender, if any. + let addr = + unsafe { maybe_read_sockaddr_os(msghdr.msg_name as _, msghdr.msg_namelen as _) }; + + RecvMsgReturn { + bytes, + address: addr, + flags: RecvFlags::from_bits_truncate(msghdr.msg_flags), + } + }) + }) +} + +#[cfg(not(any(windows, target_os = "redox", target_os = "wasi")))] +pub(crate) fn sendmsg_noaddr( + sockfd: BorrowedFd<'_>, + iov: &[IoSlice<'_>], + control: &mut SendAncillaryBuffer<'_, '_, '_>, + msg_flags: SendFlags, +) -> io::Result<usize> { + with_noaddr_msghdr(iov, control, |msghdr| unsafe { + ret_send_recv(c::sendmsg(borrowed_fd(sockfd), &msghdr, msg_flags.bits())) + }) +} + +#[cfg(not(any(windows, target_os = "redox", target_os = "wasi")))] +pub(crate) fn sendmsg_v4( + sockfd: BorrowedFd<'_>, + addr: &SocketAddrV4, + iov: &[IoSlice<'_>], + control: &mut SendAncillaryBuffer<'_, '_, '_>, + msg_flags: SendFlags, +) -> io::Result<usize> { + with_v4_msghdr(addr, iov, control, |msghdr| unsafe { + ret_send_recv(c::sendmsg(borrowed_fd(sockfd), &msghdr, msg_flags.bits())) + }) +} + +#[cfg(not(any(windows, target_os = "redox", target_os = "wasi")))] +pub(crate) fn sendmsg_v6( + sockfd: BorrowedFd<'_>, + addr: &SocketAddrV6, + iov: &[IoSlice<'_>], + control: &mut SendAncillaryBuffer<'_, '_, '_>, + msg_flags: SendFlags, +) -> io::Result<usize> { + with_v6_msghdr(addr, iov, control, |msghdr| unsafe { + ret_send_recv(c::sendmsg(borrowed_fd(sockfd), &msghdr, msg_flags.bits())) + }) +} + +#[cfg(all(unix, not(target_os = "redox")))] +pub(crate) fn sendmsg_unix( + sockfd: BorrowedFd<'_>, + addr: &SocketAddrUnix, + iov: &[IoSlice<'_>], + control: &mut SendAncillaryBuffer<'_, '_, '_>, + msg_flags: SendFlags, +) -> io::Result<usize> { + super::msghdr::with_unix_msghdr(addr, iov, control, |msghdr| unsafe { + ret_send_recv(c::sendmsg(borrowed_fd(sockfd), &msghdr, msg_flags.bits())) + }) +} + +#[cfg(not(any( + apple, + windows, + target_os = "haiku", + target_os = "redox", + target_os = "wasi", +)))] +pub(crate) fn accept_with(sockfd: BorrowedFd<'_>, flags: SocketFlags) -> io::Result<OwnedFd> { + unsafe { + let owned_fd = ret_owned_fd(c::accept4( + borrowed_fd(sockfd), + null_mut(), + null_mut(), + flags.bits(), + ))?; + Ok(owned_fd) + } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn acceptfrom(sockfd: BorrowedFd<'_>) -> io::Result<(OwnedFd, Option<SocketAddrAny>)> { + unsafe { + let mut storage = MaybeUninit::<c::sockaddr_storage>::uninit(); + let mut len = size_of::<c::sockaddr_storage>() as c::socklen_t; + let owned_fd = ret_owned_fd(c::accept( + borrowed_fd(sockfd), + storage.as_mut_ptr().cast(), + &mut len, + ))?; + Ok(( + owned_fd, + maybe_read_sockaddr_os(storage.as_ptr(), len.try_into().unwrap()), + )) + } +} + +#[cfg(not(any( + apple, + windows, + target_os = "haiku", + target_os = "redox", + target_os = "wasi", +)))] +pub(crate) fn acceptfrom_with( + sockfd: BorrowedFd<'_>, + flags: SocketFlags, +) -> io::Result<(OwnedFd, Option<SocketAddrAny>)> { + unsafe { + let mut storage = MaybeUninit::<c::sockaddr_storage>::uninit(); + let mut len = size_of::<c::sockaddr_storage>() as c::socklen_t; + let owned_fd = ret_owned_fd(c::accept4( + borrowed_fd(sockfd), + storage.as_mut_ptr().cast(), + &mut len, + flags.bits(), + ))?; + Ok(( + owned_fd, + maybe_read_sockaddr_os(storage.as_ptr(), len.try_into().unwrap()), + )) + } +} + +/// Darwin lacks `accept4`, but does have `accept`. We define +/// `SocketFlags` to have no flags, so we can discard it here. +#[cfg(any(apple, windows, target_os = "haiku"))] +pub(crate) fn accept_with(sockfd: BorrowedFd<'_>, _flags: SocketFlags) -> io::Result<OwnedFd> { + accept(sockfd) +} + +/// Darwin lacks `accept4`, but does have `accept`. We define +/// `SocketFlags` to have no flags, so we can discard it here. +#[cfg(any(apple, windows, target_os = "haiku"))] +pub(crate) fn acceptfrom_with( + sockfd: BorrowedFd<'_>, + _flags: SocketFlags, +) -> io::Result<(OwnedFd, Option<SocketAddrAny>)> { + acceptfrom(sockfd) +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn shutdown(sockfd: BorrowedFd<'_>, how: Shutdown) -> io::Result<()> { + unsafe { ret(c::shutdown(borrowed_fd(sockfd), how as c::c_int)) } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn getsockname(sockfd: BorrowedFd<'_>) -> io::Result<SocketAddrAny> { + unsafe { + let mut storage = MaybeUninit::<c::sockaddr_storage>::uninit(); + let mut len = size_of::<c::sockaddr_storage>() as c::socklen_t; + ret(c::getsockname( + borrowed_fd(sockfd), + storage.as_mut_ptr().cast(), + &mut len, + ))?; + Ok(read_sockaddr_os(storage.as_ptr(), len.try_into().unwrap())) + } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn getpeername(sockfd: BorrowedFd<'_>) -> io::Result<Option<SocketAddrAny>> { + unsafe { + let mut storage = MaybeUninit::<c::sockaddr_storage>::uninit(); + let mut len = size_of::<c::sockaddr_storage>() as c::socklen_t; + ret(c::getpeername( + borrowed_fd(sockfd), + storage.as_mut_ptr().cast(), + &mut len, + ))?; + Ok(maybe_read_sockaddr_os( + storage.as_ptr(), + len.try_into().unwrap(), + )) + } +} + +#[cfg(not(any(windows, target_os = "redox", target_os = "wasi")))] +pub(crate) fn socketpair( + domain: AddressFamily, + type_: SocketType, + flags: SocketFlags, + protocol: Protocol, +) -> io::Result<(OwnedFd, OwnedFd)> { + unsafe { + let mut fds = MaybeUninit::<[OwnedFd; 2]>::uninit(); + ret(c::socketpair( + c::c_int::from(domain.0), + type_.0 as c::c_int | flags.bits(), + protocol.0, + fds.as_mut_ptr().cast::<c::c_int>(), + ))?; + + let [fd0, fd1] = fds.assume_init(); + Ok((fd0, fd1)) + } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) mod sockopt { + use super::{c, in6_addr_new, in_addr_new, BorrowedFd}; + use crate::io; + use crate::net::sockopt::Timeout; + use crate::net::{Ipv4Addr, Ipv6Addr, SocketType}; + use crate::utils::as_mut_ptr; + use core::convert::TryInto; + use core::time::Duration; + #[cfg(windows)] + use windows_sys::Win32::Foundation::BOOL; + + // TODO: With Rust 1.53 we can use `Duration::ZERO` instead. + const DURATION_ZERO: Duration = Duration::from_secs(0); + + #[inline] + fn getsockopt<T: Copy>(fd: BorrowedFd<'_>, level: i32, optname: i32) -> io::Result<T> { + use super::*; + + let mut optlen = core::mem::size_of::<T>().try_into().unwrap(); + debug_assert!( + optlen as usize >= core::mem::size_of::<c::c_int>(), + "Socket APIs don't ever use `bool` directly" + ); + + unsafe { + let mut value = core::mem::zeroed::<T>(); + ret(c::getsockopt( + borrowed_fd(fd), + level, + optname, + as_mut_ptr(&mut value).cast(), + &mut optlen, + ))?; + // On Windows at least, `getsockopt` has been observed writing 1 + // byte on at least (`IPPROTO_TCP`, `TCP_NODELAY`), even though + // Windows' documentation says that should write a 4-byte `BOOL`. + // So, we initialize the memory to zeros above, and just assert + // that `getsockopt` doesn't write too many bytes here. + assert!( + optlen as usize <= size_of::<T>(), + "unexpected getsockopt size" + ); + Ok(value) + } + } + + #[inline] + fn setsockopt<T: Copy>( + fd: BorrowedFd<'_>, + level: i32, + optname: i32, + value: T, + ) -> io::Result<()> { + use super::*; + + let optlen = core::mem::size_of::<T>().try_into().unwrap(); + debug_assert!( + optlen as usize >= core::mem::size_of::<c::c_int>(), + "Socket APIs don't ever use `bool` directly" + ); + + unsafe { + ret(c::setsockopt( + borrowed_fd(fd), + level, + optname, + as_ptr(&value).cast(), + optlen, + )) + } + } + + #[inline] + pub(crate) fn get_socket_type(fd: BorrowedFd<'_>) -> io::Result<SocketType> { + getsockopt(fd, c::SOL_SOCKET as _, c::SO_TYPE) + } + + #[inline] + pub(crate) fn set_socket_reuseaddr(fd: BorrowedFd<'_>, reuseaddr: bool) -> io::Result<()> { + setsockopt( + fd, + c::SOL_SOCKET as _, + c::SO_REUSEADDR, + from_bool(reuseaddr), + ) + } + + #[inline] + pub(crate) fn set_socket_broadcast(fd: BorrowedFd<'_>, broadcast: bool) -> io::Result<()> { + setsockopt( + fd, + c::SOL_SOCKET as _, + c::SO_BROADCAST, + from_bool(broadcast), + ) + } + + #[inline] + pub(crate) fn get_socket_broadcast(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::SOL_SOCKET as _, c::SO_BROADCAST).map(to_bool) + } + + #[inline] + pub(crate) fn set_socket_linger( + fd: BorrowedFd<'_>, + linger: Option<Duration>, + ) -> io::Result<()> { + // Convert `linger` to seconds, rounding up. + let l_linger = if let Some(linger) = linger { + let mut l_linger = linger.as_secs(); + if linger.subsec_nanos() != 0 { + l_linger = l_linger.checked_add(1).ok_or(io::Errno::INVAL)?; + } + l_linger.try_into().map_err(|_e| io::Errno::INVAL)? + } else { + 0 + }; + let linger = c::linger { + l_onoff: linger.is_some() as _, + l_linger, + }; + setsockopt(fd, c::SOL_SOCKET as _, c::SO_LINGER, linger) + } + + #[inline] + pub(crate) fn get_socket_linger(fd: BorrowedFd<'_>) -> io::Result<Option<Duration>> { + let linger: c::linger = getsockopt(fd, c::SOL_SOCKET as _, c::SO_LINGER)?; + // TODO: With Rust 1.50, this could use `.then`. + Ok(if linger.l_onoff != 0 { + Some(Duration::from_secs(linger.l_linger as u64)) + } else { + None + }) + } + + #[cfg(linux_kernel)] + #[inline] + pub(crate) fn set_socket_passcred(fd: BorrowedFd<'_>, passcred: bool) -> io::Result<()> { + setsockopt(fd, c::SOL_SOCKET as _, c::SO_PASSCRED, from_bool(passcred)) + } + + #[cfg(linux_kernel)] + #[inline] + pub(crate) fn get_socket_passcred(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::SOL_SOCKET as _, c::SO_PASSCRED).map(to_bool) + } + + #[inline] + pub(crate) fn set_socket_timeout( + fd: BorrowedFd<'_>, + id: Timeout, + timeout: Option<Duration>, + ) -> io::Result<()> { + let optname = match id { + Timeout::Recv => c::SO_RCVTIMEO, + Timeout::Send => c::SO_SNDTIMEO, + }; + + #[cfg(not(windows))] + let timeout = match timeout { + Some(timeout) => { + if timeout == DURATION_ZERO { + return Err(io::Errno::INVAL); + } + + // Rust's musl libc bindings deprecated `time_t` while they + // transition to 64-bit `time_t`. What we want here is just + // “whatever type `timeval`'s `tv_sec` is”, so we're ok using + // the deprecated type. + #[allow(deprecated)] + let tv_sec = timeout.as_secs().try_into().unwrap_or(c::time_t::MAX); + + // `subsec_micros` rounds down, so we use `subsec_nanos` and + // manually round up. + let mut timeout = c::timeval { + tv_sec, + tv_usec: ((timeout.subsec_nanos() + 999) / 1000) as _, + }; + if timeout.tv_sec == 0 && timeout.tv_usec == 0 { + timeout.tv_usec = 1; + } + timeout + } + None => c::timeval { + tv_sec: 0, + tv_usec: 0, + }, + }; + + #[cfg(windows)] + let timeout: u32 = match timeout { + Some(timeout) => { + if timeout == DURATION_ZERO { + return Err(io::Errno::INVAL); + } + + // `as_millis` rounds down, so we use `as_nanos` and + // manually round up. + let mut timeout: u32 = ((timeout.as_nanos() + 999_999) / 1_000_000) + .try_into() + .map_err(|_convert_err| io::Errno::INVAL)?; + if timeout == 0 { + timeout = 1; + } + timeout + } + None => 0, + }; + + setsockopt(fd, c::SOL_SOCKET, optname, timeout) + } + + #[inline] + pub(crate) fn get_socket_timeout( + fd: BorrowedFd<'_>, + id: Timeout, + ) -> io::Result<Option<Duration>> { + let optname = match id { + Timeout::Recv => c::SO_RCVTIMEO, + Timeout::Send => c::SO_SNDTIMEO, + }; + + #[cfg(not(windows))] + { + let timeout: c::timeval = getsockopt(fd, c::SOL_SOCKET, optname)?; + if timeout.tv_sec == 0 && timeout.tv_usec == 0 { + Ok(None) + } else { + Ok(Some( + Duration::from_secs(timeout.tv_sec as u64) + + Duration::from_micros(timeout.tv_usec as u64), + )) + } + } + + #[cfg(windows)] + { + let timeout: u32 = getsockopt(fd, c::SOL_SOCKET, optname)?; + if timeout == 0 { + Ok(None) + } else { + Ok(Some(Duration::from_millis(timeout as u64))) + } + } + } + + #[cfg(any(apple, target_os = "freebsd"))] + #[inline] + pub(crate) fn getsockopt_nosigpipe(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::SOL_SOCKET, c::SO_NOSIGPIPE).map(to_bool) + } + + #[cfg(any(apple, target_os = "freebsd"))] + #[inline] + pub(crate) fn setsockopt_nosigpipe(fd: BorrowedFd<'_>, val: bool) -> io::Result<()> { + setsockopt(fd, c::SOL_SOCKET, c::SO_NOSIGPIPE, from_bool(val)) + } + + #[inline] + pub(crate) fn get_socket_error(fd: BorrowedFd<'_>) -> io::Result<Result<(), io::Errno>> { + let err: c::c_int = getsockopt(fd, c::SOL_SOCKET as _, 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 as _, + c::SO_KEEPALIVE, + from_bool(keepalive), + ) + } + + #[inline] + pub(crate) fn get_socket_keepalive(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::SOL_SOCKET as _, 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 as _, c::SO_RCVBUF, size) + } + + #[inline] + pub(crate) fn get_socket_recv_buffer_size(fd: BorrowedFd<'_>) -> io::Result<usize> { + getsockopt(fd, c::SOL_SOCKET as _, 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 as _, c::SO_SNDBUF, size) + } + + #[inline] + pub(crate) fn get_socket_send_buffer_size(fd: BorrowedFd<'_>) -> io::Result<usize> { + getsockopt(fd, c::SOL_SOCKET as _, c::SO_SNDBUF).map(|size: u32| size as usize) + } + + #[inline] + pub(crate) fn set_ip_ttl(fd: BorrowedFd<'_>, ttl: u32) -> io::Result<()> { + setsockopt(fd, c::IPPROTO_IP as _, c::IP_TTL, ttl) + } + + #[inline] + pub(crate) fn get_ip_ttl(fd: BorrowedFd<'_>) -> io::Result<u32> { + getsockopt(fd, c::IPPROTO_IP as _, c::IP_TTL) + } + + #[inline] + pub(crate) fn set_ipv6_v6only(fd: BorrowedFd<'_>, only_v6: bool) -> io::Result<()> { + setsockopt(fd, c::IPPROTO_IPV6 as _, c::IPV6_V6ONLY, from_bool(only_v6)) + } + + #[inline] + pub(crate) fn get_ipv6_v6only(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::IPPROTO_IPV6 as _, c::IPV6_V6ONLY).map(to_bool) + } + + #[inline] + pub(crate) fn set_ip_multicast_loop( + fd: BorrowedFd<'_>, + multicast_loop: bool, + ) -> io::Result<()> { + setsockopt( + fd, + c::IPPROTO_IP as _, + c::IP_MULTICAST_LOOP, + from_bool(multicast_loop), + ) + } + + #[inline] + pub(crate) fn get_ip_multicast_loop(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::IPPROTO_IP as _, c::IP_MULTICAST_LOOP).map(to_bool) + } + + #[inline] + pub(crate) fn set_ip_multicast_ttl(fd: BorrowedFd<'_>, multicast_ttl: u32) -> io::Result<()> { + setsockopt(fd, c::IPPROTO_IP as _, c::IP_MULTICAST_TTL, multicast_ttl) + } + + #[inline] + pub(crate) fn get_ip_multicast_ttl(fd: BorrowedFd<'_>) -> io::Result<u32> { + getsockopt(fd, c::IPPROTO_IP as _, c::IP_MULTICAST_TTL) + } + + #[inline] + pub(crate) fn set_ipv6_multicast_loop( + fd: BorrowedFd<'_>, + multicast_loop: bool, + ) -> io::Result<()> { + setsockopt( + fd, + c::IPPROTO_IPV6 as _, + c::IPV6_MULTICAST_LOOP, + from_bool(multicast_loop), + ) + } + + #[inline] + pub(crate) fn get_ipv6_multicast_loop(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::IPPROTO_IPV6 as _, c::IPV6_MULTICAST_LOOP).map(to_bool) + } + + #[inline] + pub(crate) fn set_ipv6_multicast_hops( + fd: BorrowedFd<'_>, + multicast_hops: u32, + ) -> io::Result<()> { + setsockopt( + fd, + c::IPPROTO_IP as _, + c::IPV6_MULTICAST_HOPS, + multicast_hops, + ) + } + + #[inline] + pub(crate) fn get_ipv6_multicast_hops(fd: BorrowedFd<'_>) -> io::Result<u32> { + getsockopt(fd, c::IPPROTO_IP as _, c::IPV6_MULTICAST_HOPS) + } + + #[inline] + pub(crate) fn set_ip_add_membership( + fd: BorrowedFd<'_>, + multiaddr: &Ipv4Addr, + interface: &Ipv4Addr, + ) -> io::Result<()> { + let mreq = to_imr(multiaddr, interface); + setsockopt(fd, c::IPPROTO_IP as _, c::IP_ADD_MEMBERSHIP, mreq) + } + + #[inline] + pub(crate) fn set_ipv6_add_membership( + fd: BorrowedFd<'_>, + multiaddr: &Ipv6Addr, + interface: u32, + ) -> io::Result<()> { + #[cfg(not(any(bsd, solarish, target_os = "haiku", target_os = "l4re")))] + use c::IPV6_ADD_MEMBERSHIP; + #[cfg(any(bsd, solarish, target_os = "haiku", target_os = "l4re"))] + use c::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP; + + let mreq = to_ipv6mr(multiaddr, interface); + setsockopt(fd, c::IPPROTO_IPV6 as _, IPV6_ADD_MEMBERSHIP, mreq) + } + + #[inline] + pub(crate) fn set_ip_drop_membership( + fd: BorrowedFd<'_>, + multiaddr: &Ipv4Addr, + interface: &Ipv4Addr, + ) -> io::Result<()> { + let mreq = to_imr(multiaddr, interface); + setsockopt(fd, c::IPPROTO_IP as _, c::IP_DROP_MEMBERSHIP, mreq) + } + + #[inline] + pub(crate) fn set_ipv6_drop_membership( + fd: BorrowedFd<'_>, + multiaddr: &Ipv6Addr, + interface: u32, + ) -> io::Result<()> { + #[cfg(not(any(bsd, solarish, target_os = "haiku", target_os = "l4re")))] + use c::IPV6_DROP_MEMBERSHIP; + #[cfg(any(bsd, solarish, target_os = "haiku", target_os = "l4re"))] + use c::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP; + + let mreq = to_ipv6mr(multiaddr, interface); + setsockopt(fd, c::IPPROTO_IPV6 as _, IPV6_DROP_MEMBERSHIP, mreq) + } + + #[inline] + pub(crate) fn get_ipv6_unicast_hops(fd: BorrowedFd<'_>) -> io::Result<u8> { + getsockopt(fd, c::IPPROTO_IPV6 as _, 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 as c::c_int, + None => -1, + }; + setsockopt(fd, c::IPPROTO_IPV6 as _, c::IPV6_UNICAST_HOPS, hops) + } + + #[inline] + pub(crate) fn set_tcp_nodelay(fd: BorrowedFd<'_>, nodelay: bool) -> io::Result<()> { + setsockopt(fd, c::IPPROTO_TCP as _, c::TCP_NODELAY, from_bool(nodelay)) + } + + #[inline] + pub(crate) fn get_tcp_nodelay(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::IPPROTO_TCP as _, c::TCP_NODELAY).map(to_bool) + } + + #[inline] + fn to_imr(multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> c::ip_mreq { + c::ip_mreq { + imr_multiaddr: to_imr_addr(multiaddr), + imr_interface: to_imr_addr(interface), + } + } + + #[inline] + fn to_imr_addr(addr: &Ipv4Addr) -> c::in_addr { + in_addr_new(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_interface: to_ipv6mr_interface(interface), + } + } + + #[inline] + fn to_ipv6mr_multiaddr(multiaddr: &Ipv6Addr) -> c::in6_addr { + in6_addr_new(multiaddr.octets()) + } + + #[cfg(target_os = "android")] + #[inline] + fn to_ipv6mr_interface(interface: u32) -> c::c_int { + interface as c::c_int + } + + #[cfg(not(target_os = "android"))] + #[inline] + fn to_ipv6mr_interface(interface: u32) -> c::c_uint { + interface as c::c_uint + } + + // `getsockopt` and `setsockopt` represent boolean values as integers. + #[cfg(not(windows))] + type RawSocketBool = c::c_int; + #[cfg(windows)] + type RawSocketBool = BOOL; + + // Wrap `RawSocketBool` in a newtype to discourage misuse. + #[repr(transparent)] + #[derive(Copy, Clone)] + struct SocketBool(RawSocketBool); + + // Convert from a `bool` to a `SocketBool`. + #[inline] + fn from_bool(value: bool) -> SocketBool { + SocketBool(value as _) + } + + // Convert from a `SocketBool` to a `bool`. + #[inline] + fn to_bool(value: SocketBool) -> bool { + value.0 != 0 + } +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/net/types.rs b/vendor/rustix-0.37.22/src/backend/libc/net/types.rs new file mode 100644 index 000000000..41b5fcf77 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/net/types.rs @@ -0,0 +1,499 @@ +use super::super::c; +use bitflags::bitflags; + +/// A type for holding raw integer socket types. +#[doc(hidden)] +pub type RawSocketType = u32; + +/// `SOCK_*` constants for use with [`socket`]. +/// +/// [`socket`]: crate::net::socket +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[repr(transparent)] +pub struct SocketType(pub(crate) RawSocketType); + +#[rustfmt::skip] +impl SocketType { + /// `SOCK_STREAM` + pub const STREAM: Self = Self(c::SOCK_STREAM as u32); + + /// `SOCK_DGRAM` + pub const DGRAM: Self = Self(c::SOCK_DGRAM as u32); + + /// `SOCK_SEQPACKET` + pub const SEQPACKET: Self = Self(c::SOCK_SEQPACKET as u32); + + /// `SOCK_RAW` + pub const RAW: Self = Self(c::SOCK_RAW as u32); + + /// `SOCK_RDM` + #[cfg(not(target_os = "haiku"))] + pub const RDM: Self = Self(c::SOCK_RDM as u32); + + /// Constructs a `SocketType` from a raw integer. + #[inline] + pub const fn from_raw(raw: RawSocketType) -> Self { + Self(raw) + } + + /// Returns the raw integer for this `SocketType`. + #[inline] + pub const fn as_raw(self) -> RawSocketType { + self.0 + } +} + +/// A type for holding raw integer address families. +#[doc(hidden)] +pub type RawAddressFamily = c::sa_family_t; + +/// `AF_*` constants. +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[repr(transparent)] +pub struct AddressFamily(pub(crate) RawAddressFamily); + +#[rustfmt::skip] +#[allow(non_upper_case_globals)] +impl AddressFamily { + /// `AF_UNSPEC` + pub const UNSPEC: Self = Self(c::AF_UNSPEC as _); + /// `AF_INET` + pub const INET: Self = Self(c::AF_INET as _); + /// `AF_INET6` + pub const INET6: Self = Self(c::AF_INET6 as _); + /// `AF_NETLINK` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "haiku", + )))] + pub const NETLINK: Self = Self(c::AF_NETLINK as _); + /// `AF_UNIX`, aka `AF_LOCAL` + #[doc(alias = "LOCAL")] + pub const UNIX: Self = Self(c::AF_UNIX as _); + /// `AF_AX25` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "haiku", + )))] + pub const AX25: Self = Self(c::AF_AX25 as _); + /// `AF_IPX` + pub const IPX: Self = Self(c::AF_IPX as _); + /// `AF_APPLETALK` + pub const APPLETALK: Self = Self(c::AF_APPLETALK as _); + /// `AF_NETROM` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "haiku", + )))] + pub const NETROM: Self = Self(c::AF_NETROM as _); + /// `AF_BRIDGE` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "haiku", + )))] + pub const BRIDGE: Self = Self(c::AF_BRIDGE as _); + /// `AF_ATMPVC` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "haiku", + )))] + pub const ATMPVC: Self = Self(c::AF_ATMPVC as _); + /// `AF_X25` + #[cfg(not(any( + bsd, + windows, + target_os = "haiku", + )))] + pub const X25: Self = Self(c::AF_X25 as _); + /// `AF_ROSE` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "haiku", + )))] + pub const ROSE: Self = Self(c::AF_ROSE as _); + /// `AF_DECnet` + #[cfg(not(target_os = "haiku"))] + pub const DECnet: Self = Self(c::AF_DECnet as _); + /// `AF_NETBEUI` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "haiku", + )))] + pub const NETBEUI: Self = Self(c::AF_NETBEUI as _); + /// `AF_SECURITY` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "haiku", + )))] + pub const SECURITY: Self = Self(c::AF_SECURITY as _); + /// `AF_KEY` + #[cfg(not(any( + bsd, + windows, + target_os = "haiku", + )))] + pub const KEY: Self = Self(c::AF_KEY as _); + /// `AF_PACKET` + #[cfg(not(any( + bsd, + windows, + target_os = "haiku", + )))] + pub const PACKET: Self = Self(c::AF_PACKET as _); + /// `AF_ASH` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "haiku", + )))] + pub const ASH: Self = Self(c::AF_ASH as _); + /// `AF_ECONET` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "haiku", + )))] + pub const ECONET: Self = Self(c::AF_ECONET as _); + /// `AF_ATMSVC` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "haiku", + )))] + pub const ATMSVC: Self = Self(c::AF_ATMSVC as _); + /// `AF_RDS` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "haiku", + )))] + pub const RDS: Self = Self(c::AF_RDS as _); + /// `AF_SNA` + #[cfg(not(target_os = "haiku"))] + pub const SNA: Self = Self(c::AF_SNA as _); + /// `AF_IRDA` + #[cfg(not(any( + bsd, + solarish, + target_os = "haiku", + )))] + pub const IRDA: Self = Self(c::AF_IRDA as _); + /// `AF_PPPOX` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "haiku", + )))] + pub const PPPOX: Self = Self(c::AF_PPPOX as _); + /// `AF_WANPIPE` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "haiku", + )))] + pub const WANPIPE: Self = Self(c::AF_WANPIPE as _); + /// `AF_LLC` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "haiku", + )))] + pub const LLC: Self = Self(c::AF_LLC as _); + /// `AF_CAN` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "haiku", + )))] + pub const CAN: Self = Self(c::AF_CAN as _); + /// `AF_TIPC` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "haiku", + )))] + pub const TIPC: Self = Self(c::AF_TIPC as _); + /// `AF_BLUETOOTH` + #[cfg(not(any(apple, solarish, windows)))] + pub const BLUETOOTH: Self = Self(c::AF_BLUETOOTH as _); + /// `AF_IUCV` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "haiku", + )))] + pub const IUCV: Self = Self(c::AF_IUCV as _); + /// `AF_RXRPC` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "haiku", + )))] + pub const RXRPC: Self = Self(c::AF_RXRPC as _); + /// `AF_ISDN` + #[cfg(not(any(solarish, windows, target_os = "haiku")))] + pub const ISDN: Self = Self(c::AF_ISDN as _); + /// `AF_PHONET` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "haiku", + )))] + pub const PHONET: Self = Self(c::AF_PHONET as _); + /// `AF_IEEE802154` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "haiku", + )))] + pub const IEEE802154: Self = Self(c::AF_IEEE802154 as _); + + /// Constructs a `AddressFamily` from a raw integer. + #[inline] + pub const fn from_raw(raw: RawAddressFamily) -> Self { + Self(raw) + } + + /// Returns the raw integer for this `AddressFamily`. + #[inline] + pub const fn as_raw(self) -> RawAddressFamily { + self.0 + } +} + +/// A type for holding raw integer protocols. +#[doc(hidden)] +pub type RawProtocol = i32; + +/// `IPPROTO_*` constants for use with [`socket`] and [`socket_with`]. +/// +/// [`socket`]: crate::net::socket +/// [`socket_with`]: crate::net::socket_with +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[repr(transparent)] +pub struct Protocol(pub(crate) RawProtocol); + +#[rustfmt::skip] +impl Protocol { + /// `IPPROTO_IP` + pub const IP: Self = Self(c::IPPROTO_IP as _); + /// `IPPROTO_ICMP` + pub const ICMP: Self = Self(c::IPPROTO_ICMP as _); + /// `IPPROTO_IGMP` + #[cfg(not(any(solarish, target_os = "haiku")))] + pub const IGMP: Self = Self(c::IPPROTO_IGMP as _); + /// `IPPROTO_IPIP` + #[cfg(not(any(solarish, windows, target_os = "haiku")))] + pub const IPIP: Self = Self(c::IPPROTO_IPIP as _); + /// `IPPROTO_TCP` + pub const TCP: Self = Self(c::IPPROTO_TCP as _); + /// `IPPROTO_EGP` + #[cfg(not(any(solarish, target_os = "haiku")))] + pub const EGP: Self = Self(c::IPPROTO_EGP as _); + /// `IPPROTO_PUP` + #[cfg(not(any(solarish, target_os = "haiku")))] + pub const PUP: Self = Self(c::IPPROTO_PUP as _); + /// `IPPROTO_UDP` + pub const UDP: Self = Self(c::IPPROTO_UDP as _); + /// `IPPROTO_IDP` + #[cfg(not(any(solarish, target_os = "haiku")))] + pub const IDP: Self = Self(c::IPPROTO_IDP as _); + /// `IPPROTO_TP` + #[cfg(not(any(solarish, windows, target_os = "haiku")))] + pub const TP: Self = Self(c::IPPROTO_TP as _); + /// `IPPROTO_DCCP` + #[cfg(not(any( + apple, + solarish, + windows, + target_os = "dragonfly", + target_os = "haiku", + target_os = "openbsd", + )))] + pub const DCCP: Self = Self(c::IPPROTO_DCCP as _); + /// `IPPROTO_IPV6` + pub const IPV6: Self = Self(c::IPPROTO_IPV6 as _); + /// `IPPROTO_RSVP` + #[cfg(not(any(solarish, windows, target_os = "haiku")))] + pub const RSVP: Self = Self(c::IPPROTO_RSVP as _); + /// `IPPROTO_GRE` + #[cfg(not(any(solarish, windows, target_os = "haiku")))] + pub const GRE: Self = Self(c::IPPROTO_GRE as _); + /// `IPPROTO_ESP` + #[cfg(not(any(solarish, target_os = "haiku")))] + pub const ESP: Self = Self(c::IPPROTO_ESP as _); + /// `IPPROTO_AH` + #[cfg(not(any(solarish, target_os = "haiku")))] + pub const AH: Self = Self(c::IPPROTO_AH as _); + /// `IPPROTO_MTP` + #[cfg(not(any( + solarish, + netbsdlike, + windows, + target_os = "haiku", + )))] + pub const MTP: Self = Self(c::IPPROTO_MTP as _); + /// `IPPROTO_BEETPH` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "haiku", + )))] + pub const BEETPH: Self = Self(c::IPPROTO_BEETPH as _); + /// `IPPROTO_ENCAP` + #[cfg(not(any(solarish, windows, target_os = "haiku")))] + pub const ENCAP: Self = Self(c::IPPROTO_ENCAP as _); + /// `IPPROTO_PIM` + #[cfg(not(any(solarish, target_os = "haiku")))] + pub const PIM: Self = Self(c::IPPROTO_PIM as _); + /// `IPPROTO_COMP` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "haiku", + )))] + pub const COMP: Self = Self(c::IPPROTO_COMP as _); + /// `IPPROTO_SCTP` + #[cfg(not(any(solarish, target_os = "dragonfly", target_os = "haiku", target_os = "openbsd")))] + pub const SCTP: Self = Self(c::IPPROTO_SCTP as _); + /// `IPPROTO_UDPLITE` + #[cfg(not(any( + apple, + netbsdlike, + solarish, + windows, + target_os = "dragonfly", + target_os = "haiku", + )))] + pub const UDPLITE: Self = Self(c::IPPROTO_UDPLITE as _); + /// `IPPROTO_MPLS` + #[cfg(not(any( + apple, + solarish, + windows, + target_os = "dragonfly", + target_os = "haiku", + target_os = "netbsd", + )))] + pub const MPLS: Self = Self(c::IPPROTO_MPLS as _); + /// `IPPROTO_RAW` + pub const RAW: Self = Self(c::IPPROTO_RAW as _); + /// `IPPROTO_MPTCP` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "emscripten", + target_os = "fuchsia", + target_os = "haiku", + )))] + pub const MPTCP: Self = Self(c::IPPROTO_MPTCP as _); + /// `IPPROTO_FRAGMENT` + #[cfg(not(any(solarish, target_os = "haiku")))] + pub const FRAGMENT: Self = Self(c::IPPROTO_FRAGMENT as _); + /// `IPPROTO_ICMPV6` + pub const ICMPV6: Self = Self(c::IPPROTO_ICMPV6 as _); + /// `IPPROTO_MH` + #[cfg(not(any( + apple, + netbsdlike, + solarish, + windows, + target_os = "dragonfly", + target_os = "haiku", + )))] + pub const MH: Self = Self(c::IPPROTO_MH as _); + /// `IPPROTO_ROUTING` + #[cfg(not(any(solarish, target_os = "haiku")))] + pub const ROUTING: Self = Self(c::IPPROTO_ROUTING as _); + + /// Constructs a `Protocol` from a raw integer. + #[inline] + pub const fn from_raw(raw: RawProtocol) -> Self { + Self(raw) + } + + /// Returns the raw integer for this `Protocol`. + #[inline] + pub const fn as_raw(self) -> RawProtocol { + self.0 + } +} + +/// `SHUT_*` constants for use with [`shutdown`]. +/// +/// [`shutdown`]: crate::net::shutdown +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[repr(i32)] +pub enum Shutdown { + /// `SHUT_RD`—Disable further read operations. + Read = c::SHUT_RD, + /// `SHUT_WR`—Disable further write operations. + Write = c::SHUT_WR, + /// `SHUT_RDWR`—Disable further read and write operations. + ReadWrite = c::SHUT_RDWR, +} + +bitflags! { + /// `SOCK_*` constants for use with [`socket_with`], [`accept_with`] and + /// [`acceptfrom_with`]. + /// + /// [`socket_with`]: crate::net::socket_with + /// [`accept_with`]: crate::net::accept_with + /// [`acceptfrom_with`]: crate::net::acceptfrom_with + pub struct SocketFlags: c::c_int { + /// `SOCK_NONBLOCK` + #[cfg(not(any(apple, windows, target_os = "haiku")))] + const NONBLOCK = c::SOCK_NONBLOCK; + + /// `SOCK_CLOEXEC` + #[cfg(not(any(apple, windows, target_os = "haiku")))] + const CLOEXEC = c::SOCK_CLOEXEC; + } +} + +/// Timeout identifier for use with [`set_socket_timeout`] and +/// [`get_socket_timeout`]. +/// +/// [`set_socket_timeout`]: crate::net::sockopt::set_socket_timeout. +/// [`get_socket_timeout`]: crate::net::sockopt::get_socket_timeout. +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[repr(i32)] +pub enum Timeout { + /// `SO_RCVTIMEO`—Timeout for receiving. + Recv = c::SO_RCVTIMEO, + + /// `SO_SNDTIMEO`—Timeout for sending. + Send = c::SO_SNDTIMEO, +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/net/write_sockaddr.rs b/vendor/rustix-0.37.22/src/backend/libc/net/write_sockaddr.rs new file mode 100644 index 000000000..f8ab62966 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/net/write_sockaddr.rs @@ -0,0 +1,78 @@ +//! The BSD sockets API requires us to read the `ss_family` field before +//! we can interpret the rest of a `sockaddr` produced by the kernel. + +use super::super::c; +use super::addr::SocketAddrStorage; +#[cfg(unix)] +use super::addr::SocketAddrUnix; +use super::ext::{in6_addr_new, in_addr_new, sockaddr_in6_new}; +use crate::net::{SocketAddrAny, SocketAddrV4, SocketAddrV6}; +use core::mem::size_of; + +pub(crate) unsafe fn write_sockaddr( + addr: &SocketAddrAny, + storage: *mut SocketAddrStorage, +) -> usize { + match addr { + SocketAddrAny::V4(v4) => write_sockaddr_v4(v4, storage), + SocketAddrAny::V6(v6) => write_sockaddr_v6(v6, storage), + #[cfg(unix)] + SocketAddrAny::Unix(unix) => write_sockaddr_unix(unix, storage), + } +} + +pub(crate) unsafe fn encode_sockaddr_v4(v4: &SocketAddrV4) -> c::sockaddr_in { + c::sockaddr_in { + #[cfg(any(bsd, target_os = "haiku"))] + sin_len: size_of::<c::sockaddr_in>() as _, + sin_family: c::AF_INET as _, + sin_port: u16::to_be(v4.port()), + sin_addr: in_addr_new(u32::from_ne_bytes(v4.ip().octets())), + #[cfg(not(target_os = "haiku"))] + sin_zero: [0; 8_usize], + #[cfg(target_os = "haiku")] + sin_zero: [0; 24_usize], + } +} + +unsafe fn write_sockaddr_v4(v4: &SocketAddrV4, storage: *mut SocketAddrStorage) -> usize { + let encoded = encode_sockaddr_v4(v4); + core::ptr::write(storage.cast(), encoded); + size_of::<c::sockaddr_in>() +} + +pub(crate) unsafe fn encode_sockaddr_v6(v6: &SocketAddrV6) -> c::sockaddr_in6 { + #[cfg(any(bsd, target_os = "haiku"))] + { + sockaddr_in6_new( + size_of::<c::sockaddr_in6>() as _, + c::AF_INET6 as _, + u16::to_be(v6.port()), + u32::to_be(v6.flowinfo()), + in6_addr_new(v6.ip().octets()), + v6.scope_id(), + ) + } + #[cfg(not(any(bsd, target_os = "haiku")))] + { + sockaddr_in6_new( + c::AF_INET6 as _, + u16::to_be(v6.port()), + u32::to_be(v6.flowinfo()), + in6_addr_new(v6.ip().octets()), + v6.scope_id(), + ) + } +} + +unsafe fn write_sockaddr_v6(v6: &SocketAddrV6, storage: *mut SocketAddrStorage) -> usize { + let encoded = encode_sockaddr_v6(v6); + core::ptr::write(storage.cast(), encoded); + size_of::<c::sockaddr_in6>() +} + +#[cfg(unix)] +unsafe fn write_sockaddr_unix(unix: &SocketAddrUnix, storage: *mut SocketAddrStorage) -> usize { + core::ptr::write(storage.cast(), unix.unix); + unix.len() +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/offset.rs b/vendor/rustix-0.37.22/src/backend/libc/offset.rs new file mode 100644 index 000000000..a046bcea9 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/offset.rs @@ -0,0 +1,403 @@ +//! Automatically enable “large file” support features. + +#[cfg(not(windows))] +use super::c; + +#[cfg(not(any(linux_like, windows)))] +#[cfg(feature = "fs")] +pub(super) use c::{ + fstat as libc_fstat, fstatat as libc_fstatat, ftruncate as libc_ftruncate, ino_t as libc_ino_t, + lseek as libc_lseek, off_t as libc_off_t, +}; + +#[cfg(linux_like)] +#[cfg(feature = "fs")] +pub(super) use c::{ + fstat64 as libc_fstat, fstatat64 as libc_fstatat, ftruncate64 as libc_ftruncate, + ino64_t as libc_ino_t, lseek64 as libc_lseek, off64_t as libc_off_t, +}; + +#[cfg(linux_like)] +pub(super) use c::rlimit64 as libc_rlimit; + +#[cfg(not(any(linux_like, windows, target_os = "wasi")))] +#[cfg(feature = "mm")] +pub(super) use c::mmap as libc_mmap; + +#[cfg(not(any( + linux_like, + windows, + target_os = "fuchsia", + target_os = "redox", + target_os = "wasi", +)))] +pub(super) use c::{rlimit as libc_rlimit, RLIM_INFINITY as LIBC_RLIM_INFINITY}; + +#[cfg(not(any(linux_like, windows, target_os = "fuchsia", target_os = "wasi")))] +pub(super) use c::{getrlimit as libc_getrlimit, setrlimit as libc_setrlimit}; + +#[cfg(linux_like)] +pub(super) use c::{ + getrlimit64 as libc_getrlimit, setrlimit64 as libc_setrlimit, + RLIM64_INFINITY as LIBC_RLIM_INFINITY, +}; + +#[cfg(linux_like)] +#[cfg(feature = "mm")] +pub(super) use c::mmap64 as libc_mmap; + +// `prlimit64` wasn't supported in glibc until 2.13. +#[cfg(all(target_os = "linux", target_env = "gnu"))] +weak_or_syscall! { + fn prlimit64( + pid: c::pid_t, + resource: c::__rlimit_resource_t, + new_limit: *const c::rlimit64, + old_limit: *mut c::rlimit64 + ) via SYS_prlimit64 -> c::c_int +} +#[cfg(all(target_os = "linux", target_env = "musl"))] +weak_or_syscall! { + fn prlimit64( + pid: c::pid_t, + resource: c::c_int, + new_limit: *const c::rlimit64, + old_limit: *mut c::rlimit64 + ) via SYS_prlimit64 -> c::c_int +} +#[cfg(target_os = "android")] +weak_or_syscall! { + fn prlimit64( + pid: c::pid_t, + resource: c::c_int, + new_limit: *const c::rlimit64, + old_limit: *mut c::rlimit64 + ) via SYS_prlimit64 -> c::c_int +} +#[cfg(all(target_os = "linux", target_env = "gnu"))] +pub(super) unsafe fn libc_prlimit( + pid: c::pid_t, + resource: c::__rlimit_resource_t, + new_limit: *const c::rlimit64, + old_limit: *mut c::rlimit64, +) -> c::c_int { + prlimit64(pid, resource, new_limit, old_limit) +} +#[cfg(all(target_os = "linux", target_env = "musl"))] +pub(super) unsafe fn libc_prlimit( + pid: c::pid_t, + resource: c::c_int, + new_limit: *const c::rlimit64, + old_limit: *mut c::rlimit64, +) -> c::c_int { + prlimit64(pid, resource, new_limit, old_limit) +} +#[cfg(target_os = "android")] +pub(super) unsafe fn libc_prlimit( + pid: c::pid_t, + resource: c::c_int, + new_limit: *const c::rlimit64, + old_limit: *mut c::rlimit64, +) -> c::c_int { + prlimit64(pid, resource, new_limit, old_limit) +} + +#[cfg(not(any(linux_like, windows, target_os = "redox")))] +#[cfg(feature = "fs")] +pub(super) use c::openat as libc_openat; +#[cfg(linux_like)] +#[cfg(feature = "fs")] +pub(super) use c::openat64 as libc_openat; + +#[cfg(target_os = "fuchsia")] +#[cfg(feature = "fs")] +pub(super) use c::fallocate as libc_fallocate; +#[cfg(linux_kernel)] +#[cfg(feature = "fs")] +pub(super) use c::fallocate64 as libc_fallocate; +#[cfg(not(any( + apple, + linux_like, + netbsdlike, + solarish, + windows, + target_os = "dragonfly", + target_os = "haiku", + target_os = "redox", +)))] +#[cfg(feature = "fs")] +pub(super) use c::posix_fadvise as libc_posix_fadvise; +#[cfg(linux_like)] +#[cfg(feature = "fs")] +pub(super) use c::posix_fadvise64 as libc_posix_fadvise; + +#[cfg(not(any(linux_kernel, windows, target_os = "emscripten")))] +pub(super) use c::{pread as libc_pread, pwrite as libc_pwrite}; +#[cfg(any(linux_kernel, target_os = "emscripten"))] +pub(super) use c::{pread64 as libc_pread, pwrite64 as libc_pwrite}; +#[cfg(not(any( + apple, + linux_kernel, + windows, + target_os = "emscripten", + target_os = "haiku", + target_os = "redox", + target_os = "solaris", +)))] +pub(super) use c::{preadv as libc_preadv, pwritev as libc_pwritev}; +#[cfg(any(target_os = "linux", target_os = "emscripten"))] +pub(super) use c::{preadv64 as libc_preadv, pwritev64 as libc_pwritev}; + +#[cfg(target_os = "android")] +mod readwrite_pv64 { + use super::c; + + // 64-bit offsets on 32-bit platforms are passed in endianness-specific + // lo/hi pairs. See src/backend/linux_raw/conv.rs for details. + #[cfg(all(target_endian = "little", target_pointer_width = "32"))] + fn lo(x: u64) -> usize { + (x >> 32) as usize + } + #[cfg(all(target_endian = "little", target_pointer_width = "32"))] + fn hi(x: u64) -> usize { + (x & 0xffff_ffff) as usize + } + #[cfg(all(target_endian = "big", target_pointer_width = "32"))] + fn lo(x: u64) -> usize { + (x & 0xffff_ffff) as usize + } + #[cfg(all(target_endian = "big", target_pointer_width = "32"))] + fn hi(x: u64) -> usize { + (x >> 32) as usize + } + + pub(in super::super) unsafe fn preadv64( + fd: c::c_int, + iov: *const c::iovec, + iovcnt: c::c_int, + offset: c::off64_t, + ) -> c::ssize_t { + // Older Android libc lacks `preadv64`, so use the `weak!` mechanism to + // test for it, and call back to `c::syscall`. We don't use + // `weak_or_syscall` here because we need to pass the 64-bit offset + // specially. + weak! { + fn preadv64(c::c_int, *const c::iovec, c::c_int, c::off64_t) -> c::ssize_t + } + if let Some(fun) = preadv64.get() { + fun(fd, iov, iovcnt, offset) + } else { + #[cfg(target_pointer_width = "32")] + { + c::syscall( + c::SYS_preadv, + fd, + iov, + iovcnt, + hi(offset as u64), + lo(offset as u64), + ) as c::ssize_t + } + #[cfg(target_pointer_width = "64")] + { + c::syscall(c::SYS_preadv, fd, iov, iovcnt, offset) as c::ssize_t + } + } + } + pub(in super::super) unsafe fn pwritev64( + fd: c::c_int, + iov: *const c::iovec, + iovcnt: c::c_int, + offset: c::off64_t, + ) -> c::ssize_t { + // See the comments in `preadv64`. + weak! { + fn pwritev64(c::c_int, *const c::iovec, c::c_int, c::off64_t) -> c::ssize_t + } + if let Some(fun) = pwritev64.get() { + fun(fd, iov, iovcnt, offset) + } else { + #[cfg(target_pointer_width = "32")] + { + c::syscall( + c::SYS_pwritev, + fd, + iov, + iovcnt, + hi(offset as u64), + lo(offset as u64), + ) as c::ssize_t + } + #[cfg(target_pointer_width = "64")] + { + c::syscall(c::SYS_pwritev, fd, iov, iovcnt, offset) as c::ssize_t + } + } + } +} +#[cfg(target_os = "android")] +pub(super) use readwrite_pv64::{preadv64 as libc_preadv, pwritev64 as libc_pwritev}; + +// macOS added preadv and pwritev in version 11.0 +#[cfg(apple)] +mod readwrite_pv { + use super::c; + + weakcall! { + pub(in super::super) fn preadv( + fd: c::c_int, + iov: *const c::iovec, + iovcnt: c::c_int, + offset: c::off_t + ) -> c::ssize_t + } + weakcall! { + pub(in super::super) fn pwritev( + fd: c::c_int, + iov: *const c::iovec, + iovcnt: c::c_int, offset: c::off_t + ) -> c::ssize_t + } +} +#[cfg(apple)] +pub(super) use readwrite_pv::{preadv as libc_preadv, pwritev as libc_pwritev}; + +// glibc added `preadv64v2` and `pwritev64v2` in version 2.26. +#[cfg(all(target_os = "linux", target_env = "gnu"))] +mod readwrite_pv64v2 { + use super::c; + + // 64-bit offsets on 32-bit platforms are passed in endianness-specific + // lo/hi pairs. See src/backend/linux_raw/conv.rs for details. + #[cfg(all(target_endian = "little", target_pointer_width = "32"))] + fn lo(x: u64) -> usize { + (x >> 32) as usize + } + #[cfg(all(target_endian = "little", target_pointer_width = "32"))] + fn hi(x: u64) -> usize { + (x & 0xffff_ffff) as usize + } + #[cfg(all(target_endian = "big", target_pointer_width = "32"))] + fn lo(x: u64) -> usize { + (x & 0xffff_ffff) as usize + } + #[cfg(all(target_endian = "big", target_pointer_width = "32"))] + fn hi(x: u64) -> usize { + (x >> 32) as usize + } + + pub(in super::super) unsafe fn preadv64v2( + fd: c::c_int, + iov: *const c::iovec, + iovcnt: c::c_int, + offset: c::off64_t, + flags: c::c_int, + ) -> c::ssize_t { + // Older glibc lacks `preadv64v2`, so use the `weak!` mechanism to + // test for it, and call back to `c::syscall`. We don't use + // `weak_or_syscall` here because we need to pass the 64-bit offset + // specially. + weak! { + fn preadv64v2(c::c_int, *const c::iovec, c::c_int, c::off64_t, c::c_int) -> c::ssize_t + } + if let Some(fun) = preadv64v2.get() { + fun(fd, iov, iovcnt, offset, flags) + } else { + #[cfg(target_pointer_width = "32")] + { + c::syscall( + c::SYS_preadv, + fd, + iov, + iovcnt, + hi(offset as u64), + lo(offset as u64), + flags, + ) as c::ssize_t + } + #[cfg(target_pointer_width = "64")] + { + c::syscall(c::SYS_preadv2, fd, iov, iovcnt, offset, flags) as c::ssize_t + } + } + } + pub(in super::super) unsafe fn pwritev64v2( + fd: c::c_int, + iov: *const c::iovec, + iovcnt: c::c_int, + offset: c::off64_t, + flags: c::c_int, + ) -> c::ssize_t { + // See the comments in `preadv64v2`. + weak! { + fn pwritev64v2(c::c_int, *const c::iovec, c::c_int, c::off64_t, c::c_int) -> c::ssize_t + } + if let Some(fun) = pwritev64v2.get() { + fun(fd, iov, iovcnt, offset, flags) + } else { + #[cfg(target_pointer_width = "32")] + { + c::syscall( + c::SYS_pwritev, + fd, + iov, + iovcnt, + hi(offset as u64), + lo(offset as u64), + flags, + ) as c::ssize_t + } + #[cfg(target_pointer_width = "64")] + { + c::syscall(c::SYS_pwritev2, fd, iov, iovcnt, offset, flags) as c::ssize_t + } + } + } +} +#[cfg(all(target_os = "linux", target_env = "gnu"))] +pub(super) use readwrite_pv64v2::{preadv64v2 as libc_preadv2, pwritev64v2 as libc_pwritev2}; + +#[cfg(not(any( + apple, + linux_kernel, + netbsdlike, + solarish, + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "fuchsia", + target_os = "l4re", + target_os = "redox", +)))] +#[cfg(feature = "fs")] +pub(super) use c::posix_fallocate as libc_posix_fallocate; +#[cfg(target_os = "l4re")] +#[cfg(feature = "fs")] +pub(super) use c::posix_fallocate64 as libc_posix_fallocate; +#[cfg(not(any( + linux_like, + solarish, + windows, + target_os = "haiku", + target_os = "netbsd", + target_os = "redox", + target_os = "wasi", +)))] +#[cfg(feature = "fs")] +pub(super) use {c::fstatfs as libc_fstatfs, c::statfs as libc_statfs}; +#[cfg(not(any( + linux_like, + windows, + target_os = "haiku", + target_os = "redox", + target_os = "wasi", +)))] +#[cfg(feature = "fs")] +pub(super) use {c::fstatvfs as libc_fstatvfs, c::statvfs as libc_statvfs}; + +#[cfg(linux_like)] +#[cfg(feature = "fs")] +pub(super) use { + c::fstatfs64 as libc_fstatfs, c::fstatvfs64 as libc_fstatvfs, c::statfs64 as libc_statfs, + c::statvfs64 as libc_statvfs, +}; diff --git a/vendor/rustix-0.37.22/src/backend/libc/param/auxv.rs b/vendor/rustix-0.37.22/src/backend/libc/param/auxv.rs new file mode 100644 index 000000000..a770c60d8 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/param/auxv.rs @@ -0,0 +1,54 @@ +use super::super::c; +#[cfg(any( + all(target_os = "android", target_pointer_width = "64"), + target_os = "linux", +))] +use crate::ffi::CStr; + +// `getauxval` wasn't supported in glibc until 2.16. +#[cfg(any( + all(target_os = "android", target_pointer_width = "64"), + target_os = "linux", +))] +weak!(fn getauxval(c::c_ulong) -> *mut c::c_void); + +#[inline] +pub(crate) fn page_size() -> usize { + unsafe { c::sysconf(c::_SC_PAGESIZE) as usize } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +pub(crate) fn clock_ticks_per_second() -> u64 { + unsafe { c::sysconf(c::_SC_CLK_TCK) as u64 } +} + +#[cfg(any( + all(target_os = "android", target_pointer_width = "64"), + target_os = "linux", +))] +#[inline] +pub(crate) fn linux_hwcap() -> (usize, usize) { + if let Some(libc_getauxval) = getauxval.get() { + unsafe { + let hwcap = libc_getauxval(c::AT_HWCAP) as usize; + let hwcap2 = libc_getauxval(c::AT_HWCAP2) as usize; + (hwcap, hwcap2) + } + } else { + (0, 0) + } +} + +#[cfg(any( + all(target_os = "android", target_pointer_width = "64"), + target_os = "linux", +))] +#[inline] +pub(crate) fn linux_execfn() -> &'static CStr { + if let Some(libc_getauxval) = getauxval.get() { + unsafe { CStr::from_ptr(libc_getauxval(c::AT_EXECFN).cast()) } + } else { + cstr!("") + } +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/param/mod.rs b/vendor/rustix-0.37.22/src/backend/libc/param/mod.rs new file mode 100644 index 000000000..2cb2fe78a --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/param/mod.rs @@ -0,0 +1 @@ +pub(crate) mod auxv; diff --git a/vendor/rustix-0.37.22/src/backend/libc/process/cpu_set.rs b/vendor/rustix-0.37.22/src/backend/libc/process/cpu_set.rs new file mode 100644 index 000000000..aba21ad44 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/process/cpu_set.rs @@ -0,0 +1,51 @@ +//! Rust implementation of the `CPU_*` macro API. + +#![allow(non_snake_case)] + +use super::super::c; +use super::types::{RawCpuSet, CPU_SETSIZE}; + +#[inline] +pub(crate) fn CPU_SET(cpu: usize, cpuset: &mut RawCpuSet) { + assert!( + cpu < CPU_SETSIZE, + "cpu out of bounds: the cpu max is {} but the cpu is {}", + CPU_SETSIZE, + cpu + ); + unsafe { c::CPU_SET(cpu, cpuset) } +} + +#[inline] +pub(crate) fn CPU_ZERO(cpuset: &mut RawCpuSet) { + unsafe { c::CPU_ZERO(cpuset) } +} + +#[inline] +pub(crate) fn CPU_CLR(cpu: usize, cpuset: &mut RawCpuSet) { + assert!( + cpu < CPU_SETSIZE, + "cpu out of bounds: the cpu max is {} but the cpu is {}", + CPU_SETSIZE, + cpu + ); + unsafe { c::CPU_CLR(cpu, cpuset) } +} + +#[inline] +pub(crate) fn CPU_ISSET(cpu: usize, cpuset: &RawCpuSet) -> bool { + assert!( + cpu < CPU_SETSIZE, + "cpu out of bounds: the cpu max is {} but the cpu is {}", + CPU_SETSIZE, + cpu + ); + unsafe { c::CPU_ISSET(cpu, cpuset) } +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn CPU_COUNT(cpuset: &RawCpuSet) -> u32 { + use core::convert::TryInto; + unsafe { c::CPU_COUNT(cpuset).try_into().unwrap() } +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/process/mod.rs b/vendor/rustix-0.37.22/src/backend/libc/process/mod.rs new file mode 100644 index 000000000..24f43d443 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/process/mod.rs @@ -0,0 +1,7 @@ +#[cfg(any(linux_kernel, target_os = "dragonfly", target_os = "fuchsia"))] +pub(crate) mod cpu_set; +#[cfg(not(windows))] +pub(crate) mod syscalls; +pub(crate) mod types; +#[cfg(not(target_os = "wasi"))] +pub(crate) mod wait; diff --git a/vendor/rustix-0.37.22/src/backend/libc/process/syscalls.rs b/vendor/rustix-0.37.22/src/backend/libc/process/syscalls.rs new file mode 100644 index 000000000..d4faa8d6b --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/process/syscalls.rs @@ -0,0 +1,639 @@ +//! libc syscalls supporting `rustix::process`. + +use super::super::c; +#[cfg(not(target_os = "wasi"))] +use super::super::conv::{borrowed_fd, ret_infallible, ret_pid_t, ret_usize}; +use super::super::conv::{c_str, ret, ret_c_int, ret_discarded_char_ptr}; +#[cfg(linux_kernel)] +use super::super::conv::{syscall_ret, syscall_ret_u32}; +#[cfg(any(linux_kernel, target_os = "dragonfly", target_os = "fuchsia"))] +use super::types::RawCpuSet; +#[cfg(not(target_os = "wasi"))] +use crate::fd::BorrowedFd; +#[cfg(target_os = "linux")] +use crate::fd::{AsRawFd, OwnedFd}; +use crate::ffi::CStr; +#[cfg(feature = "fs")] +use crate::fs::Mode; +use crate::io; +#[cfg(linux_kernel)] +use crate::process::Sysinfo; +#[cfg(not(any(target_os = "wasi", target_os = "redox", target_os = "openbsd")))] +use crate::process::{WaitId, WaitidOptions, WaitidStatus}; +use core::mem::MaybeUninit; +#[cfg(target_os = "linux")] +use {super::super::conv::syscall_ret_owned_fd, crate::process::PidfdFlags}; +#[cfg(linux_kernel)] +use { + super::super::offset::libc_prlimit, + crate::process::{Cpuid, MembarrierCommand, MembarrierQuery}, +}; +#[cfg(not(any(target_os = "fuchsia", target_os = "redox", target_os = "wasi")))] +use { + super::super::offset::{libc_getrlimit, libc_rlimit, libc_setrlimit, LIBC_RLIM_INFINITY}, + crate::process::{Resource, Rlimit}, +}; +#[cfg(not(target_os = "wasi"))] +use { + super::types::RawUname, + crate::process::{Gid, Pid, RawNonZeroPid, RawPid, Signal, Uid, WaitOptions, WaitStatus}, + core::convert::TryInto, +}; + +#[cfg(not(target_os = "wasi"))] +pub(crate) fn chdir(path: &CStr) -> io::Result<()> { + unsafe { ret(c::chdir(c_str(path))) } +} + +#[cfg(not(any(target_os = "wasi", target_os = "fuchsia")))] +pub(crate) fn fchdir(dirfd: BorrowedFd<'_>) -> io::Result<()> { + unsafe { ret(c::fchdir(borrowed_fd(dirfd))) } +} + +#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))] +pub(crate) fn chroot(path: &CStr) -> io::Result<()> { + unsafe { ret(c::chroot(c_str(path))) } +} + +#[cfg(not(target_os = "wasi"))] +pub(crate) fn getcwd(buf: &mut [u8]) -> io::Result<()> { + unsafe { ret_discarded_char_ptr(c::getcwd(buf.as_mut_ptr().cast(), buf.len())) } +} + +#[cfg(linux_kernel)] +pub(crate) fn membarrier_query() -> MembarrierQuery { + // glibc does not have a wrapper for `membarrier`; [the documentation] + // says to use `syscall`. + // + // [the documentation]: https://man7.org/linux/man-pages/man2/membarrier.2.html#NOTES + const MEMBARRIER_CMD_QUERY: u32 = 0; + unsafe { + match syscall_ret_u32(c::syscall(c::SYS_membarrier, MEMBARRIER_CMD_QUERY, 0)) { + Ok(query) => MembarrierQuery::from_bits_unchecked(query), + Err(_) => MembarrierQuery::empty(), + } + } +} + +#[cfg(linux_kernel)] +pub(crate) fn membarrier(cmd: MembarrierCommand) -> io::Result<()> { + unsafe { syscall_ret(c::syscall(c::SYS_membarrier, cmd as u32, 0)) } +} + +#[cfg(linux_kernel)] +pub(crate) fn membarrier_cpu(cmd: MembarrierCommand, cpu: Cpuid) -> io::Result<()> { + const MEMBARRIER_CMD_FLAG_CPU: u32 = 1; + unsafe { + syscall_ret(c::syscall( + c::SYS_membarrier, + cmd as u32, + MEMBARRIER_CMD_FLAG_CPU, + cpu.as_raw(), + )) + } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +#[must_use] +pub(crate) fn getuid() -> Uid { + unsafe { + let uid = c::getuid(); + Uid::from_raw(uid) + } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +#[must_use] +pub(crate) fn geteuid() -> Uid { + unsafe { + let uid = c::geteuid(); + Uid::from_raw(uid) + } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +#[must_use] +pub(crate) fn getgid() -> Gid { + unsafe { + let gid = c::getgid(); + Gid::from_raw(gid) + } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +#[must_use] +pub(crate) fn getegid() -> Gid { + unsafe { + let gid = c::getegid(); + Gid::from_raw(gid) + } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +#[must_use] +pub(crate) fn getpid() -> Pid { + unsafe { + let pid = c::getpid(); + debug_assert_ne!(pid, 0); + Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked(pid)) + } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +#[must_use] +pub(crate) fn getppid() -> Option<Pid> { + unsafe { + let pid: i32 = c::getppid(); + Pid::from_raw(pid) + } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +pub(crate) fn getpgid(pid: Option<Pid>) -> io::Result<Pid> { + unsafe { + let pgid = ret_pid_t(c::getpgid(Pid::as_raw(pid) as _))?; + debug_assert_ne!(pgid, 0); + Ok(Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked(pgid))) + } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +pub(crate) fn setpgid(pid: Option<Pid>, pgid: Option<Pid>) -> io::Result<()> { + unsafe { ret(c::setpgid(Pid::as_raw(pid) as _, Pid::as_raw(pgid) as _)) } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +#[must_use] +pub(crate) fn getpgrp() -> Pid { + unsafe { + let pgid = c::getpgrp(); + debug_assert_ne!(pgid, 0); + Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked(pgid)) + } +} + +#[cfg(any(linux_kernel, target_os = "dragonfly", target_os = "fuchsia"))] +#[inline] +pub(crate) fn sched_getaffinity(pid: Option<Pid>, cpuset: &mut RawCpuSet) -> io::Result<()> { + unsafe { + ret(c::sched_getaffinity( + Pid::as_raw(pid) as _, + core::mem::size_of::<RawCpuSet>(), + cpuset, + )) + } +} + +#[cfg(any(linux_kernel, target_os = "dragonfly", target_os = "fuchsia"))] +#[inline] +pub(crate) fn sched_setaffinity(pid: Option<Pid>, cpuset: &RawCpuSet) -> io::Result<()> { + unsafe { + ret(c::sched_setaffinity( + Pid::as_raw(pid) as _, + core::mem::size_of::<RawCpuSet>(), + cpuset, + )) + } +} + +#[inline] +pub(crate) fn sched_yield() { + unsafe { + let _ = c::sched_yield(); + } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +pub(crate) fn uname() -> RawUname { + let mut uname = MaybeUninit::<RawUname>::uninit(); + unsafe { + ret_infallible(c::uname(uname.as_mut_ptr())); + uname.assume_init() + } +} + +#[cfg(not(target_os = "wasi"))] +#[cfg(feature = "fs")] +#[inline] +pub(crate) fn umask(mask: Mode) -> Mode { + // TODO: Use `from_bits_retain` when we switch to bitflags 2.0. + unsafe { Mode::from_bits_truncate(c::umask(mask.bits() as _) as _) } +} + +#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))] +#[inline] +pub(crate) fn nice(inc: i32) -> io::Result<i32> { + libc_errno::set_errno(libc_errno::Errno(0)); + let r = unsafe { c::nice(inc) }; + if libc_errno::errno().0 != 0 { + ret_c_int(r) + } else { + Ok(r) + } +} + +#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))] +#[inline] +pub(crate) fn getpriority_user(uid: Uid) -> io::Result<i32> { + libc_errno::set_errno(libc_errno::Errno(0)); + let r = unsafe { c::getpriority(c::PRIO_USER, uid.as_raw() as _) }; + if libc_errno::errno().0 != 0 { + ret_c_int(r) + } else { + Ok(r) + } +} + +#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))] +#[inline] +pub(crate) fn getpriority_pgrp(pgid: Option<Pid>) -> io::Result<i32> { + libc_errno::set_errno(libc_errno::Errno(0)); + let r = unsafe { c::getpriority(c::PRIO_PGRP, Pid::as_raw(pgid) as _) }; + if libc_errno::errno().0 != 0 { + ret_c_int(r) + } else { + Ok(r) + } +} + +#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))] +#[inline] +pub(crate) fn getpriority_process(pid: Option<Pid>) -> io::Result<i32> { + libc_errno::set_errno(libc_errno::Errno(0)); + let r = unsafe { c::getpriority(c::PRIO_PROCESS, Pid::as_raw(pid) as _) }; + if libc_errno::errno().0 != 0 { + ret_c_int(r) + } else { + Ok(r) + } +} + +#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))] +#[inline] +pub(crate) fn setpriority_user(uid: Uid, priority: i32) -> io::Result<()> { + unsafe { ret(c::setpriority(c::PRIO_USER, uid.as_raw() as _, priority)) } +} + +#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))] +#[inline] +pub(crate) fn setpriority_pgrp(pgid: Option<Pid>, priority: i32) -> io::Result<()> { + unsafe { + ret(c::setpriority( + c::PRIO_PGRP, + Pid::as_raw(pgid) as _, + priority, + )) + } +} + +#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))] +#[inline] +pub(crate) fn setpriority_process(pid: Option<Pid>, priority: i32) -> io::Result<()> { + unsafe { + ret(c::setpriority( + c::PRIO_PROCESS, + Pid::as_raw(pid) as _, + priority, + )) + } +} + +#[cfg(not(any(target_os = "fuchsia", target_os = "redox", target_os = "wasi")))] +#[inline] +pub(crate) fn getrlimit(limit: Resource) -> Rlimit { + let mut result = MaybeUninit::<libc_rlimit>::uninit(); + unsafe { + ret_infallible(libc_getrlimit(limit as _, result.as_mut_ptr())); + rlimit_from_libc(result.assume_init()) + } +} + +#[cfg(not(any(target_os = "fuchsia", target_os = "redox", target_os = "wasi")))] +#[inline] +pub(crate) fn setrlimit(limit: Resource, new: Rlimit) -> io::Result<()> { + let lim = rlimit_to_libc(new)?; + unsafe { ret(libc_setrlimit(limit as _, &lim)) } +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn prlimit(pid: Option<Pid>, limit: Resource, new: Rlimit) -> io::Result<Rlimit> { + let lim = rlimit_to_libc(new)?; + let mut result = MaybeUninit::<libc_rlimit>::uninit(); + unsafe { + ret(libc_prlimit( + Pid::as_raw(pid), + limit as _, + &lim, + result.as_mut_ptr(), + ))?; + Ok(rlimit_from_libc(result.assume_init())) + } +} + +/// Convert a Rust [`Rlimit`] to a C `libc_rlimit`. +#[cfg(not(any(target_os = "fuchsia", target_os = "redox", target_os = "wasi")))] +fn rlimit_from_libc(lim: libc_rlimit) -> Rlimit { + let current = if lim.rlim_cur == LIBC_RLIM_INFINITY { + None + } else { + Some(lim.rlim_cur.try_into().unwrap()) + }; + let maximum = if lim.rlim_max == LIBC_RLIM_INFINITY { + None + } else { + Some(lim.rlim_max.try_into().unwrap()) + }; + Rlimit { current, maximum } +} + +/// Convert a C `libc_rlimit` to a Rust `Rlimit`. +#[cfg(not(any(target_os = "fuchsia", target_os = "redox", target_os = "wasi")))] +fn rlimit_to_libc(lim: Rlimit) -> io::Result<libc_rlimit> { + let Rlimit { current, maximum } = lim; + let rlim_cur = match current { + Some(r) => r.try_into().map_err(|_e| io::Errno::INVAL)?, + None => LIBC_RLIM_INFINITY as _, + }; + let rlim_max = match maximum { + Some(r) => r.try_into().map_err(|_e| io::Errno::INVAL)?, + None => LIBC_RLIM_INFINITY as _, + }; + Ok(libc_rlimit { rlim_cur, rlim_max }) +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +pub(crate) fn wait(waitopts: WaitOptions) -> io::Result<Option<(Pid, WaitStatus)>> { + _waitpid(!0, waitopts) +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +pub(crate) fn waitpid( + pid: Option<Pid>, + waitopts: WaitOptions, +) -> io::Result<Option<(Pid, WaitStatus)>> { + _waitpid(Pid::as_raw(pid), waitopts) +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +pub(crate) fn _waitpid( + pid: RawPid, + waitopts: WaitOptions, +) -> io::Result<Option<(Pid, WaitStatus)>> { + unsafe { + let mut status: c::c_int = 0; + let pid = ret_c_int(c::waitpid(pid as _, &mut status, waitopts.bits() as _))?; + Ok(RawNonZeroPid::new(pid).map(|non_zero| { + ( + Pid::from_raw_nonzero(non_zero), + WaitStatus::new(status as _), + ) + })) + } +} + +#[cfg(not(any(target_os = "wasi", target_os = "redox", target_os = "openbsd")))] +#[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), + #[cfg(target_os = "linux")] + WaitId::PidFd(fd) => _waitid_pidfd(fd, options), + #[cfg(not(target_os = "linux"))] + WaitId::__EatLifetime(_) => unreachable!(), + } +} + +#[cfg(not(any(target_os = "wasi", target_os = "redox", target_os = "openbsd")))] +#[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(c::waitid( + c::P_ALL, + 0, + status.as_mut_ptr(), + options.bits() as _, + ))? + }; + + Ok(unsafe { cvt_waitid_status(status) }) +} + +#[cfg(not(any(target_os = "wasi", target_os = "redox", target_os = "openbsd")))] +#[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(c::waitid( + c::P_PID, + Pid::as_raw(Some(pid)) as _, + status.as_mut_ptr(), + options.bits() as _, + ))? + }; + + Ok(unsafe { cvt_waitid_status(status) }) +} + +#[cfg(target_os = "linux")] +#[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(c::waitid( + c::P_PIDFD, + fd.as_raw_fd() as _, + status.as_mut_ptr(), + options.bits() as _, + ))? + }; + + 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. +#[cfg(not(any(target_os = "wasi", target_os = "redox", target_os = "openbsd")))] +#[inline] +unsafe fn cvt_waitid_status(status: MaybeUninit<c::siginfo_t>) -> Option<WaitidStatus> { + let status = status.assume_init(); + // `si_pid` is supposedly the better way to check that the struct has been + // filled, e.g. the Linux manpage says about the `WNOHANG` case “zero out + // the si_pid field before the call and check for a nonzero value”. + // But e.g. NetBSD/OpenBSD don't have it exposed in the libc crate for now, + // and some platforms don't have it at all. For simplicity, always check + // `si_signo`. We have zero-initialized the whole struct, and all kernels + // should set `SIGCHLD` here. + if status.si_signo == 0 { + None + } else { + Some(WaitidStatus(status)) + } +} + +#[inline] +pub(crate) fn exit_group(code: c::c_int) -> ! { + // `_exit` and `_Exit` are the same; it's just a matter of which ones + // the libc bindings expose. + #[cfg(any(target_os = "wasi", target_os = "solid"))] + unsafe { + c::_Exit(code) + } + #[cfg(unix)] + unsafe { + c::_exit(code) + } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +#[inline] +pub(crate) fn getsid(pid: Option<Pid>) -> io::Result<Pid> { + unsafe { + let pid = ret_pid_t(c::getsid(Pid::as_raw(pid) as _))?; + debug_assert_ne!(pid, 0); + Ok(Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked(pid))) + } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +pub(crate) fn setsid() -> io::Result<Pid> { + unsafe { + let pid = ret_c_int(c::setsid())?; + debug_assert_ne!(pid, 0); + Ok(Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked(pid))) + } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +pub(crate) fn kill_process(pid: Pid, sig: Signal) -> io::Result<()> { + unsafe { ret(c::kill(pid.as_raw_nonzero().get(), sig as i32)) } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +pub(crate) fn kill_process_group(pid: Pid, sig: Signal) -> io::Result<()> { + unsafe { + ret(c::kill( + pid.as_raw_nonzero().get().wrapping_neg(), + sig as i32, + )) + } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +pub(crate) fn kill_current_process_group(sig: Signal) -> io::Result<()> { + unsafe { ret(c::kill(0, sig as i32)) } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +pub(crate) fn test_kill_process(pid: Pid) -> io::Result<()> { + unsafe { ret(c::kill(pid.as_raw_nonzero().get(), 0)) } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +pub(crate) fn test_kill_process_group(pid: Pid) -> io::Result<()> { + unsafe { ret(c::kill(pid.as_raw_nonzero().get().wrapping_neg(), 0)) } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +pub(crate) fn test_kill_current_process_group() -> io::Result<()> { + unsafe { ret(c::kill(0, 0)) } +} + +#[cfg(linux_kernel)] +#[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(c::prctl(option, arg2, arg3, arg4, arg5)) +} + +#[cfg(freebsdlike)] +#[inline] +pub(crate) unsafe fn procctl( + idtype: c::idtype_t, + id: c::id_t, + option: c::c_int, + data: *mut c::c_void, +) -> io::Result<()> { + ret(c::procctl(idtype, id, option, data)) +} + +#[cfg(target_os = "linux")] +pub(crate) fn pidfd_open(pid: Pid, flags: PidfdFlags) -> io::Result<OwnedFd> { + unsafe { + syscall_ret_owned_fd(c::syscall( + c::SYS_pidfd_open, + pid.as_raw_nonzero().get(), + flags.bits(), + )) + } +} + +#[cfg(not(target_os = "wasi"))] +pub(crate) fn getgroups(buf: &mut [Gid]) -> io::Result<usize> { + let len = buf.len().try_into().map_err(|_| io::Errno::NOMEM)?; + + unsafe { ret_usize(c::getgroups(len, buf.as_mut_ptr().cast()) as isize) } +} + +#[cfg(linux_kernel)] +pub(crate) fn sysinfo() -> Sysinfo { + let mut info = MaybeUninit::<Sysinfo>::uninit(); + unsafe { + ret_infallible(c::sysinfo(info.as_mut_ptr())); + info.assume_init() + } +} + +#[cfg(not(any(target_os = "emscripten", target_os = "redox", target_os = "wasi")))] +pub(crate) fn sethostname(name: &[u8]) -> io::Result<()> { + unsafe { + ret(c::sethostname( + name.as_ptr().cast(), + name.len().try_into().map_err(|_| io::Errno::INVAL)?, + )) + } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +#[inline] +pub(crate) fn ioctl_tiocsctty(fd: BorrowedFd<'_>) -> io::Result<()> { + unsafe { ret(c::ioctl(borrowed_fd(fd), c::TIOCSCTTY as _, &0_u32)) } +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/process/types.rs b/vendor/rustix-0.37.22/src/backend/libc/process/types.rs new file mode 100644 index 000000000..3eb300278 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/process/types.rs @@ -0,0 +1,339 @@ +use super::super::c; + +/// `sysinfo` +#[cfg(linux_kernel)] +pub type Sysinfo = c::sysinfo; + +/// A command for use with [`membarrier`] and [`membarrier_cpu`]. +/// +/// For `MEMBARRIER_CMD_QUERY`, see [`membarrier_query`]. +/// +/// [`membarrier`]: crate::process::membarrier +/// [`membarrier_cpu`]: crate::process::membarrier_cpu +/// [`membarrier_query`]: crate::process::membarrier_query +#[cfg(linux_kernel)] +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +#[repr(u32)] +pub enum MembarrierCommand { + /// `MEMBARRIER_CMD_GLOBAL` + #[doc(alias = "Shared")] + #[doc(alias = "MEMBARRIER_CMD_SHARED")] + Global = c::MEMBARRIER_CMD_GLOBAL as u32, + /// `MEMBARRIER_CMD_GLOBAL_EXPEDITED` + GlobalExpedited = c::MEMBARRIER_CMD_GLOBAL_EXPEDITED as u32, + /// `MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED` + RegisterGlobalExpedited = c::MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED as u32, + /// `MEMBARRIER_CMD_PRIVATE_EXPEDITED` + PrivateExpedited = c::MEMBARRIER_CMD_PRIVATE_EXPEDITED as u32, + /// `MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED` + RegisterPrivateExpedited = c::MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED as u32, + /// `MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE` + PrivateExpeditedSyncCore = c::MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE as u32, + /// `MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE` + RegisterPrivateExpeditedSyncCore = + c::MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE as u32, + /// `MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ` (since Linux 5.10) + PrivateExpeditedRseq = c::MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ as u32, + /// `MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ` (since Linux 5.10) + RegisterPrivateExpeditedRseq = c::MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ as u32, +} + +/// A resource value for use with [`getrlimit`], [`setrlimit`], and +/// [`prlimit`]. +/// +/// [`getrlimit`]: crate::process::getrlimit +/// [`setrlimit`]: crate::process::setrlimit +/// [`prlimit`]: crate::process::prlimit +#[cfg(not(any(target_os = "fuchsia", target_os = "redox", target_os = "wasi")))] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[repr(i32)] +pub enum Resource { + /// `RLIMIT_CPU` + Cpu = c::RLIMIT_CPU as c::c_int, + /// `RLIMIT_FSIZE` + Fsize = c::RLIMIT_FSIZE as c::c_int, + /// `RLIMIT_DATA` + Data = c::RLIMIT_DATA as c::c_int, + /// `RLIMIT_STACK` + Stack = c::RLIMIT_STACK as c::c_int, + /// `RLIMIT_CORE` + #[cfg(not(target_os = "haiku"))] + Core = c::RLIMIT_CORE as c::c_int, + /// `RLIMIT_RSS` + #[cfg(not(any(apple, solarish, target_os = "haiku")))] + Rss = c::RLIMIT_RSS as c::c_int, + /// `RLIMIT_NPROC` + #[cfg(not(any(solarish, target_os = "haiku")))] + Nproc = c::RLIMIT_NPROC as c::c_int, + /// `RLIMIT_NOFILE` + Nofile = c::RLIMIT_NOFILE as c::c_int, + /// `RLIMIT_MEMLOCK` + #[cfg(not(any(solarish, target_os = "aix", target_os = "haiku")))] + Memlock = c::RLIMIT_MEMLOCK as c::c_int, + /// `RLIMIT_AS` + #[cfg(not(target_os = "openbsd"))] + As = c::RLIMIT_AS as c::c_int, + /// `RLIMIT_LOCKS` + #[cfg(not(any(bsd, solarish, target_os = "aix", target_os = "haiku")))] + Locks = c::RLIMIT_LOCKS as c::c_int, + /// `RLIMIT_SIGPENDING` + #[cfg(not(any(bsd, solarish, target_os = "aix", target_os = "haiku")))] + Sigpending = c::RLIMIT_SIGPENDING as c::c_int, + /// `RLIMIT_MSGQUEUE` + #[cfg(not(any(bsd, solarish, target_os = "aix", target_os = "haiku")))] + Msgqueue = c::RLIMIT_MSGQUEUE as c::c_int, + /// `RLIMIT_NICE` + #[cfg(not(any(bsd, solarish, target_os = "aix", target_os = "haiku")))] + Nice = c::RLIMIT_NICE as c::c_int, + /// `RLIMIT_RTPRIO` + #[cfg(not(any(bsd, solarish, target_os = "aix", target_os = "haiku")))] + Rtprio = c::RLIMIT_RTPRIO as c::c_int, + /// `RLIMIT_RTTIME` + #[cfg(not(any( + bsd, + solarish, + target_os = "aix", + target_os = "android", + target_os = "emscripten", + target_os = "haiku", + )))] + Rttime = c::RLIMIT_RTTIME as c::c_int, +} + +#[cfg(apple)] +#[allow(non_upper_case_globals)] +impl Resource { + /// `RLIMIT_RSS` + pub const Rss: Self = Self::As; +} + +/// A signal number for use with [`kill_process`], [`kill_process_group`], +/// and [`kill_current_process_group`]. +/// +/// [`kill_process`]: crate::process::kill_process +/// [`kill_process_group`]: crate::process::kill_process_group +/// [`kill_current_process_group`]: crate::process::kill_current_process_group +#[cfg(not(target_os = "wasi"))] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[repr(i32)] +pub enum Signal { + /// `SIGHUP` + Hup = c::SIGHUP, + /// `SIGINT` + Int = c::SIGINT, + /// `SIGQUIT` + Quit = c::SIGQUIT, + /// `SIGILL` + Ill = c::SIGILL, + /// `SIGTRAP` + Trap = c::SIGTRAP, + /// `SIGABRT`, aka `SIGIOT` + #[doc(alias = "Iot")] + #[doc(alias = "Abrt")] + Abort = c::SIGABRT, + /// `SIGBUS` + Bus = c::SIGBUS, + /// `SIGFPE` + Fpe = c::SIGFPE, + /// `SIGKILL` + Kill = c::SIGKILL, + /// `SIGUSR1` + Usr1 = c::SIGUSR1, + /// `SIGSEGV` + Segv = c::SIGSEGV, + /// `SIGUSR2` + Usr2 = c::SIGUSR2, + /// `SIGPIPE` + Pipe = c::SIGPIPE, + /// `SIGALRM` + #[doc(alias = "Alrm")] + Alarm = c::SIGALRM, + /// `SIGTERM` + Term = c::SIGTERM, + /// `SIGSTKFLT` + #[cfg(not(any( + bsd, + solarish, + target_os = "aix", + target_os = "haiku", + all( + linux_kernel, + any( + target_arch = "mips", + target_arch = "mips64", + target_arch = "sparc", + target_arch = "sparc64" + ), + ) + )))] + Stkflt = c::SIGSTKFLT, + /// `SIGCHLD` + #[doc(alias = "Chld")] + Child = c::SIGCHLD, + /// `SIGCONT` + Cont = c::SIGCONT, + /// `SIGSTOP` + Stop = c::SIGSTOP, + /// `SIGTSTP` + Tstp = c::SIGTSTP, + /// `SIGTTIN` + Ttin = c::SIGTTIN, + /// `SIGTTOU` + Ttou = c::SIGTTOU, + /// `SIGURG` + Urg = c::SIGURG, + /// `SIGXCPU` + Xcpu = c::SIGXCPU, + /// `SIGXFSZ` + Xfsz = c::SIGXFSZ, + /// `SIGVTALRM` + #[doc(alias = "Vtalrm")] + Vtalarm = c::SIGVTALRM, + /// `SIGPROF` + Prof = c::SIGPROF, + /// `SIGWINCH` + Winch = c::SIGWINCH, + /// `SIGIO`, aka `SIGPOLL` + #[doc(alias = "Poll")] + #[cfg(not(target_os = "haiku"))] + Io = c::SIGIO, + /// `SIGPWR` + #[cfg(not(any(bsd, target_os = "haiku")))] + #[doc(alias = "Pwr")] + Power = c::SIGPWR, + /// `SIGSYS`, aka `SIGUNUSED` + #[doc(alias = "Unused")] + Sys = c::SIGSYS, + /// `SIGEMT` + #[cfg(any(bsd, solarish, target_os = "aix", target_os = "hermit"))] + Emt = c::SIGEMT, + /// `SIGEMT` + #[cfg(all( + linux_kernel, + any( + target_arch = "mips", + target_arch = "mips64", + target_arch = "sparc", + target_arch = "sparc64" + ) + ))] + Emt = linux_raw_sys::general::SIGEMT as i32, + /// `SIGINFO` + #[cfg(bsd)] + Info = c::SIGINFO, + /// `SIGTHR` + #[cfg(target_os = "freebsd")] + #[doc(alias = "Lwp")] + Thr = c::SIGTHR, + /// `SIGLIBRT` + #[cfg(target_os = "freebsd")] + Librt = c::SIGLIBRT, +} + +#[cfg(not(target_os = "wasi"))] +impl Signal { + /// Convert a raw signal number into a `Signal`, if possible. + pub fn from_raw(sig: i32) -> Option<Self> { + match sig as _ { + c::SIGHUP => Some(Self::Hup), + c::SIGINT => Some(Self::Int), + c::SIGQUIT => Some(Self::Quit), + c::SIGILL => Some(Self::Ill), + c::SIGTRAP => Some(Self::Trap), + c::SIGABRT => Some(Self::Abort), + c::SIGBUS => Some(Self::Bus), + c::SIGFPE => Some(Self::Fpe), + c::SIGKILL => Some(Self::Kill), + c::SIGUSR1 => Some(Self::Usr1), + c::SIGSEGV => Some(Self::Segv), + c::SIGUSR2 => Some(Self::Usr2), + c::SIGPIPE => Some(Self::Pipe), + c::SIGALRM => Some(Self::Alarm), + c::SIGTERM => Some(Self::Term), + #[cfg(not(any( + bsd, + solarish, + target_os = "aix", + target_os = "haiku", + all( + linux_kernel, + any( + target_arch = "mips", + target_arch = "mips64", + target_arch = "sparc", + target_arch = "sparc64" + ), + ) + )))] + c::SIGSTKFLT => Some(Self::Stkflt), + c::SIGCHLD => Some(Self::Child), + c::SIGCONT => Some(Self::Cont), + c::SIGSTOP => Some(Self::Stop), + c::SIGTSTP => Some(Self::Tstp), + c::SIGTTIN => Some(Self::Ttin), + c::SIGTTOU => Some(Self::Ttou), + c::SIGURG => Some(Self::Urg), + c::SIGXCPU => Some(Self::Xcpu), + c::SIGXFSZ => Some(Self::Xfsz), + c::SIGVTALRM => Some(Self::Vtalarm), + c::SIGPROF => Some(Self::Prof), + c::SIGWINCH => Some(Self::Winch), + #[cfg(not(target_os = "haiku"))] + c::SIGIO => Some(Self::Io), + #[cfg(not(any(bsd, target_os = "haiku")))] + c::SIGPWR => Some(Self::Power), + c::SIGSYS => Some(Self::Sys), + #[cfg(bsd)] + c::SIGEMT => Some(Self::Emt), + #[cfg(bsd)] + c::SIGINFO => Some(Self::Info), + #[cfg(target_os = "freebsd")] + c::SIGTHR => Some(Self::Thr), + #[cfg(target_os = "freebsd")] + c::SIGLIBRT => Some(Self::Librt), + _ => None, + } + } +} + +pub const EXIT_SUCCESS: c::c_int = c::EXIT_SUCCESS; +pub const EXIT_FAILURE: c::c_int = c::EXIT_FAILURE; +#[cfg(not(target_os = "wasi"))] +pub const EXIT_SIGNALED_SIGABRT: c::c_int = 128 + c::SIGABRT; + +/// A process identifier as a raw integer. +#[cfg(not(target_os = "wasi"))] +pub type RawPid = c::pid_t; +/// A non-zero process identifier as a raw non-zero integer. +#[cfg(not(target_os = "wasi"))] +pub type RawNonZeroPid = core::num::NonZeroI32; +/// A group identifier as a raw integer. +#[cfg(not(target_os = "wasi"))] +pub type RawGid = c::gid_t; +/// A user identifier as a raw integer. +#[cfg(not(target_os = "wasi"))] +pub type RawUid = c::uid_t; +/// A CPU identifier as a raw integer. +#[cfg(linux_kernel)] +pub type RawCpuid = u32; +#[cfg(target_os = "freebsd")] +pub type RawId = c::id_t; + +#[cfg(not(target_os = "wasi"))] +pub(crate) type RawUname = c::utsname; + +#[cfg(any(linux_kernel, target_os = "dragonfly", target_os = "fuchsia"))] +pub(crate) type RawCpuSet = c::cpu_set_t; + +#[cfg(any(linux_kernel, target_os = "dragonfly", target_os = "fuchsia"))] +#[inline] +pub(crate) fn raw_cpu_set_new() -> RawCpuSet { + let mut set = unsafe { core::mem::zeroed() }; + super::cpu_set::CPU_ZERO(&mut set); + set +} + +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +pub(crate) const CPU_SETSIZE: usize = c::CPU_SETSIZE as usize; +#[cfg(target_os = "dragonfly")] +pub(crate) const CPU_SETSIZE: usize = 256; diff --git a/vendor/rustix-0.37.22/src/backend/libc/process/wait.rs b/vendor/rustix-0.37.22/src/backend/libc/process/wait.rs new file mode 100644 index 000000000..c09ee1002 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/process/wait.rs @@ -0,0 +1,9 @@ +use super::super::c; + +pub(crate) use c::{ + WCONTINUED, WEXITSTATUS, WIFCONTINUED, WIFEXITED, WIFSIGNALED, WIFSTOPPED, WNOHANG, WSTOPSIG, + WTERMSIG, WUNTRACED, +}; + +#[cfg(not(any(target_os = "openbsd", target_os = "redox", target_os = "wasi")))] +pub(crate) use c::{WEXITED, WNOWAIT, WSTOPPED}; diff --git a/vendor/rustix-0.37.22/src/backend/libc/pty/mod.rs b/vendor/rustix-0.37.22/src/backend/libc/pty/mod.rs new file mode 100644 index 000000000..ef944f04d --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/pty/mod.rs @@ -0,0 +1 @@ +pub(crate) mod syscalls; diff --git a/vendor/rustix-0.37.22/src/backend/libc/pty/syscalls.rs b/vendor/rustix-0.37.22/src/backend/libc/pty/syscalls.rs new file mode 100644 index 000000000..8ed621c38 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/pty/syscalls.rs @@ -0,0 +1,104 @@ +//! libc syscalls supporting `rustix::pty`. + +use super::super::c; +use super::super::conv::{borrowed_fd, ret}; +use crate::fd::BorrowedFd; +use crate::io; +#[cfg(not(target_os = "android"))] +use {super::super::conv::ret_owned_fd, crate::fd::OwnedFd, crate::pty::OpenptFlags}; +#[cfg(any(apple, linux_like, target_os = "freebsd", target_os = "fuchsia"))] +use { + crate::ffi::{CStr, CString}, + crate::path::SMALL_PATH_BUFFER_SIZE, + alloc::borrow::ToOwned, + alloc::vec::Vec, +}; + +#[cfg(not(linux_kernel))] +#[inline] +pub(crate) fn openpt(flags: OpenptFlags) -> io::Result<OwnedFd> { + unsafe { ret_owned_fd(c::posix_openpt(flags.bits() as _)) } +} + +#[cfg(any(apple, linux_like, target_os = "freebsd", target_os = "fuchsia"))] +#[inline] +pub(crate) fn ptsname(fd: BorrowedFd, mut buffer: Vec<u8>) -> io::Result<CString> { + // This code would benefit from having a better way to read into + // uninitialized memory, but that requires `unsafe`. + buffer.clear(); + buffer.reserve(SMALL_PATH_BUFFER_SIZE); + buffer.resize(buffer.capacity(), 0_u8); + + loop { + // On platforms with `ptsname_r`, use it. + #[cfg(any(linux_like, target_os = "fuchsia"))] + let r = + unsafe { libc::ptsname_r(borrowed_fd(fd), buffer.as_mut_ptr().cast(), buffer.len()) }; + + // FreeBSD 12 doesn't have `ptsname_r`. + #[cfg(target_os = "freebsd")] + let r = unsafe { + weak! { + fn ptsname_r( + c::c_int, + *mut c::c_char, + c::size_t + ) -> c::c_int + } + if let Some(func) = ptsname_r.get() { + func(borrowed_fd(fd), buffer.as_mut_ptr().cast(), buffer.len()) + } else { + libc::ENOSYS + } + }; + + // MacOS 10.13.4 has `ptsname_r`; use it if we have it, otherwise fall + // back to calling the underlying ioctl directly. + #[cfg(apple)] + let r = unsafe { + weak! { fn ptsname_r(c::c_int, *mut c::c_char, c::size_t) -> c::c_int } + + if let Some(libc_ptsname_r) = ptsname_r.get() { + libc_ptsname_r(borrowed_fd(fd), buffer.as_mut_ptr().cast(), buffer.len()) + } else { + // The size declared in the `TIOCPTYGNAME` macro in sys/ttycom.h is 128. + let mut name: [u8; 128] = [0_u8; 128]; + match libc::ioctl(borrowed_fd(fd), libc::TIOCPTYGNAME as u64, &mut name) { + 0 => { + let len = CStr::from_ptr(name.as_ptr().cast()).to_bytes().len(); + std::ptr::copy_nonoverlapping(name.as_ptr(), buffer.as_mut_ptr(), len + 1); + 0 + } + _ => libc_errno::errno().0, + } + } + }; + + if r == 0 { + return Ok(unsafe { CStr::from_ptr(buffer.as_ptr().cast()).to_owned() }); + } + if r != libc::ERANGE { + return Err(io::Errno::from_raw_os_error(r)); + } + + buffer.reserve(1); // use `Vec` reallocation strategy to grow capacity exponentially + buffer.resize(buffer.capacity(), 0_u8); + } +} + +#[inline] +pub(crate) fn unlockpt(fd: BorrowedFd) -> io::Result<()> { + unsafe { ret(c::unlockpt(borrowed_fd(fd))) } +} + +#[cfg(not(linux_kernel))] +#[inline] +pub(crate) fn grantpt(fd: BorrowedFd) -> io::Result<()> { + unsafe { ret(c::grantpt(borrowed_fd(fd))) } +} + +#[cfg(target_os = "linux")] +#[inline] +pub(crate) fn ioctl_tiocgptpeer(fd: BorrowedFd, flags: OpenptFlags) -> io::Result<OwnedFd> { + unsafe { ret_owned_fd(c::ioctl(borrowed_fd(fd), c::TIOCGPTPEER, flags.bits())) } +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/rand/mod.rs b/vendor/rustix-0.37.22/src/backend/libc/rand/mod.rs new file mode 100644 index 000000000..1e0181a99 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/rand/mod.rs @@ -0,0 +1,2 @@ +pub(crate) mod syscalls; +pub(crate) mod types; diff --git a/vendor/rustix-0.37.22/src/backend/libc/rand/syscalls.rs b/vendor/rustix-0.37.22/src/backend/libc/rand/syscalls.rs new file mode 100644 index 000000000..dd52ece77 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/rand/syscalls.rs @@ -0,0 +1,14 @@ +//! libc syscalls supporting `rustix::rand`. + +#[cfg(linux_kernel)] +use {super::super::c, super::super::conv::ret_usize, crate::io, crate::rand::GetRandomFlags}; + +#[cfg(linux_kernel)] +pub(crate) fn getrandom(buf: &mut [u8], flags: GetRandomFlags) -> io::Result<usize> { + // `getrandom` wasn't supported in glibc until 2.25. + weak_or_syscall! { + fn getrandom(buf: *mut c::c_void, buflen: c::size_t, flags: c::c_uint) via SYS_getrandom -> c::ssize_t + } + + unsafe { ret_usize(getrandom(buf.as_mut_ptr().cast(), buf.len(), flags.bits())) } +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/rand/types.rs b/vendor/rustix-0.37.22/src/backend/libc/rand/types.rs new file mode 100644 index 000000000..0c7d5f9b5 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/rand/types.rs @@ -0,0 +1,19 @@ +#[cfg(linux_kernel)] +use super::super::c; +#[cfg(linux_kernel)] +use bitflags::bitflags; + +#[cfg(linux_kernel)] +bitflags! { + /// `GRND_*` flags for use with [`getrandom`]. + /// + /// [`getrandom`]: crate::rand::getrandom + pub struct GetRandomFlags: u32 { + /// `GRND_RANDOM` + const RANDOM = c::GRND_RANDOM; + /// `GRND_NONBLOCK` + const NONBLOCK = c::GRND_NONBLOCK; + /// `GRND_INSECURE` + const INSECURE = c::GRND_INSECURE; + } +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/termios/mod.rs b/vendor/rustix-0.37.22/src/backend/libc/termios/mod.rs new file mode 100644 index 000000000..c82c95958 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/termios/mod.rs @@ -0,0 +1,3 @@ +pub(crate) mod syscalls; +#[cfg(not(target_os = "wasi"))] +pub(crate) mod types; diff --git a/vendor/rustix-0.37.22/src/backend/libc/termios/syscalls.rs b/vendor/rustix-0.37.22/src/backend/libc/termios/syscalls.rs new file mode 100644 index 000000000..2a53b8b8c --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/termios/syscalls.rs @@ -0,0 +1,211 @@ +//! libc syscalls supporting `rustix::termios`. +//! +//! # Safety +//! +//! See the `rustix::backend::syscalls` module documentation for details. + +use super::super::c; +use super::super::conv::{borrowed_fd, ret, ret_pid_t}; +use crate::fd::BorrowedFd; +#[cfg(feature = "procfs")] +#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))] +use crate::ffi::CStr; +use core::mem::MaybeUninit; +#[cfg(not(target_os = "wasi"))] +use { + crate::io, + crate::process::{Pid, RawNonZeroPid}, + crate::termios::{Action, OptionalActions, QueueSelector, Speed, Termios, Winsize}, +}; + +#[cfg(not(target_os = "wasi"))] +pub(crate) fn tcgetattr(fd: BorrowedFd<'_>) -> io::Result<Termios> { + let mut result = MaybeUninit::<Termios>::uninit(); + unsafe { + ret(c::tcgetattr(borrowed_fd(fd), result.as_mut_ptr()))?; + Ok(result.assume_init()) + } +} + +#[cfg(all( + linux_kernel, + 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<crate::termios::Termios2> { + let mut result = MaybeUninit::<crate::termios::Termios2>::uninit(); + unsafe { + ret(c::ioctl(borrowed_fd(fd), c::TCGETS2, result.as_mut_ptr()))?; + Ok(result.assume_init()) + } +} + +#[cfg(not(target_os = "wasi"))] +pub(crate) fn tcgetpgrp(fd: BorrowedFd<'_>) -> io::Result<Pid> { + unsafe { + let pid = ret_pid_t(c::tcgetpgrp(borrowed_fd(fd)))?; + debug_assert_ne!(pid, 0); + Ok(Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked(pid))) + } +} + +#[cfg(not(target_os = "wasi"))] +pub(crate) fn tcsetpgrp(fd: BorrowedFd<'_>, pid: Pid) -> io::Result<()> { + unsafe { ret(c::tcsetpgrp(borrowed_fd(fd), pid.as_raw_nonzero().get())) } +} + +#[cfg(not(target_os = "wasi"))] +pub(crate) fn tcsetattr( + fd: BorrowedFd, + optional_actions: OptionalActions, + termios: &Termios, +) -> io::Result<()> { + unsafe { + ret(c::tcsetattr( + borrowed_fd(fd), + optional_actions as _, + termios, + )) + } +} + +#[cfg(all( + linux_kernel, + 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(c::ioctl( + borrowed_fd(fd), + (c::TCSETS2 as u32 + optional_actions as u32) as _, + termios, + )) + } +} + +#[cfg(not(target_os = "wasi"))] +pub(crate) fn tcsendbreak(fd: BorrowedFd) -> io::Result<()> { + unsafe { ret(c::tcsendbreak(borrowed_fd(fd), 0)) } +} + +#[cfg(not(target_os = "wasi"))] +pub(crate) fn tcdrain(fd: BorrowedFd) -> io::Result<()> { + unsafe { ret(c::tcdrain(borrowed_fd(fd))) } +} + +#[cfg(not(target_os = "wasi"))] +pub(crate) fn tcflush(fd: BorrowedFd, queue_selector: QueueSelector) -> io::Result<()> { + unsafe { ret(c::tcflush(borrowed_fd(fd), queue_selector as _)) } +} + +#[cfg(not(target_os = "wasi"))] +pub(crate) fn tcflow(fd: BorrowedFd, action: Action) -> io::Result<()> { + unsafe { ret(c::tcflow(borrowed_fd(fd), action as _)) } +} + +#[cfg(not(target_os = "wasi"))] +pub(crate) fn tcgetsid(fd: BorrowedFd) -> io::Result<Pid> { + unsafe { + let pid = ret_pid_t(c::tcgetsid(borrowed_fd(fd)))?; + debug_assert_ne!(pid, 0); + Ok(Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked(pid))) + } +} + +#[cfg(not(target_os = "wasi"))] +pub(crate) fn tcsetwinsize(fd: BorrowedFd, winsize: Winsize) -> io::Result<()> { + unsafe { ret(c::ioctl(borrowed_fd(fd), c::TIOCSWINSZ, &winsize)) } +} + +#[cfg(not(target_os = "wasi"))] +pub(crate) fn tcgetwinsize(fd: BorrowedFd) -> io::Result<Winsize> { + unsafe { + let mut buf = MaybeUninit::<Winsize>::uninit(); + ret(c::ioctl( + borrowed_fd(fd), + c::TIOCGWINSZ.into(), + buf.as_mut_ptr(), + ))?; + Ok(buf.assume_init()) + } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +#[must_use] +pub(crate) fn cfgetospeed(termios: &Termios) -> Speed { + unsafe { c::cfgetospeed(termios) } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +#[must_use] +pub(crate) fn cfgetispeed(termios: &Termios) -> Speed { + unsafe { c::cfgetispeed(termios) } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +pub(crate) fn cfmakeraw(termios: &mut Termios) { + unsafe { c::cfmakeraw(termios) } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +pub(crate) fn cfsetospeed(termios: &mut Termios, speed: Speed) -> io::Result<()> { + unsafe { ret(c::cfsetospeed(termios, speed)) } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +pub(crate) fn cfsetispeed(termios: &mut Termios, speed: Speed) -> io::Result<()> { + unsafe { ret(c::cfsetispeed(termios, speed)) } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +pub(crate) fn cfsetspeed(termios: &mut Termios, speed: Speed) -> io::Result<()> { + unsafe { ret(c::cfsetspeed(termios, speed)) } +} + +pub(crate) fn isatty(fd: BorrowedFd<'_>) -> bool { + // Use the return value of `isatty` alone. We don't check `errno` because + // we return `bool` rather than `io::Result<bool>`, because we assume + // `BorrrowedFd` protects us from `EBADF`, and any other reasonably + // anticipated `errno` value would end up interpreted as “assume it's not a + // terminal” anyway. + unsafe { c::isatty(borrowed_fd(fd)) != 0 } +} + +#[cfg(feature = "procfs")] +#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))] +pub(crate) fn ttyname(dirfd: BorrowedFd<'_>, buf: &mut [u8]) -> io::Result<usize> { + unsafe { + // `ttyname_r` returns its error status rather than using `errno`. + match c::ttyname_r(borrowed_fd(dirfd), buf.as_mut_ptr().cast(), buf.len()) { + 0 => Ok(CStr::from_ptr(buf.as_ptr().cast()).to_bytes().len()), + err => Err(io::Errno::from_raw_os_error(err)), + } + } +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/termios/types.rs b/vendor/rustix-0.37.22/src/backend/libc/termios/types.rs new file mode 100644 index 000000000..daaf54f4b --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/termios/types.rs @@ -0,0 +1,724 @@ +use super::super::c; + +/// `TCSA*` values for use with [`tcsetattr`]. +/// +/// [`tcsetattr`]: crate::termios::tcsetattr +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[repr(i32)] +pub enum OptionalActions { + /// `TCSANOW`—Make the change immediately. + #[doc(alias = "TCSANOW")] + Now = c::TCSANOW, + + /// `TCSADRAIN`—Make the change after all output has been transmitted. + #[doc(alias = "TCSADRAIN")] + Drain = c::TCSADRAIN, + + /// `TCSAFLUSH`—Discard any pending input and then make the change + /// after all output has been transmitted. + #[doc(alias = "TCSAFLUSH")] + Flush = c::TCSAFLUSH, +} + +/// `TC*` values for use with [`tcflush`]. +/// +/// [`tcflush`]: crate::termios::tcflush +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[repr(i32)] +pub enum QueueSelector { + /// `TCIFLUSH`—Flush data received but not read. + #[doc(alias = "TCIFLUSH")] + IFlush = c::TCIFLUSH, + + /// `TCOFLUSH`—Flush data written but not transmitted. + #[doc(alias = "TCOFLUSH")] + OFlush = c::TCOFLUSH, + + /// `TCIOFLUSH`—`IFlush` and `OFlush` combined. + #[doc(alias = "TCIOFLUSH")] + IOFlush = c::TCIOFLUSH, +} + +/// `TC*` values for use with [`tcflow`]. +/// +/// [`tcflow`]: crate::termios::tcflow +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[repr(i32)] +pub enum Action { + /// `TCOOFF`—Suspend output. + #[doc(alias = "TCOOFF")] + OOff = c::TCOOFF, + + /// `TCOON`—Restart suspended output. + #[doc(alias = "TCOON")] + OOn = c::TCOON, + + /// `TCIOFF`—Transmits a STOP byte. + #[doc(alias = "TCIOFF")] + IOff = c::TCIOFF, + + /// `TCION`—Transmits a START byte. + #[doc(alias = "TCION")] + IOn = c::TCION, +} + +/// `struct termios` for use with [`tcgetattr`] and [`tcsetattr`]. +/// +/// [`tcgetattr`]: crate::termios::tcgetattr +/// [`tcsetattr`]: crate::termios::tcsetattr +#[doc(alias = "termios")] +pub type Termios = c::termios; + +/// `struct termios2` for use with [`tcgetattr2`] and [`tcsetattr2`]. +/// +/// [`tcgetattr2`]: crate::termios::tcgetattr2 +/// [`tcsetattr2`]: crate::termios::tcsetattr2 +#[cfg(all( + linux_kernel, + 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 = c::termios2; + +/// `struct winsize` for use with [`tcgetwinsize`]. +/// +/// [`tcgetwinsize`]: crate::termios::tcgetwinsize +#[doc(alias = "winsize")] +pub type Winsize = c::winsize; + +/// `tcflag_t`—A type for the flags fields of [`Termios`]. +#[doc(alias = "tcflag_t")] +pub type Tcflag = c::tcflag_t; + +/// `speed_t`—A return type for [`cfsetspeed`] and similar. +/// +/// [`cfsetspeed`]: crate::termios::cfsetspeed +#[doc(alias = "speed_t")] +pub type Speed = c::speed_t; + +/// `VINTR` +pub const VINTR: usize = c::VINTR as usize; + +/// `VQUIT` +pub const VQUIT: usize = c::VQUIT as usize; + +/// `VERASE` +pub const VERASE: usize = c::VERASE as usize; + +/// `VKILL` +pub const VKILL: usize = c::VKILL as usize; + +/// `VEOF` +pub const VEOF: usize = c::VEOF as usize; + +/// `VTIME` +pub const VTIME: usize = c::VTIME as usize; + +/// `VMIN` +pub const VMIN: usize = c::VMIN as usize; + +/// `VSWTC` +#[cfg(not(any(bsd, solarish, target_os = "aix", target_os = "haiku")))] +pub const VSWTC: usize = c::VSWTC as usize; + +/// `VSTART` +pub const VSTART: usize = c::VSTART as usize; + +/// `VSTOP` +pub const VSTOP: usize = c::VSTOP as usize; + +/// `VSUSP` +pub const VSUSP: usize = c::VSUSP as usize; + +/// `VEOL` +pub const VEOL: usize = c::VEOL as usize; + +/// `VREPRINT` +#[cfg(not(target_os = "haiku"))] +pub const VREPRINT: usize = c::VREPRINT as usize; + +/// `VDISCARD` +#[cfg(not(any(target_os = "aix", target_os = "haiku")))] +pub const VDISCARD: usize = c::VDISCARD as usize; + +/// `VWERASE` +#[cfg(not(any(target_os = "aix", target_os = "haiku")))] +pub const VWERASE: usize = c::VWERASE as usize; + +/// `VLNEXT` +#[cfg(not(target_os = "haiku"))] +pub const VLNEXT: usize = c::VLNEXT as usize; + +/// `VEOL2` +pub const VEOL2: usize = c::VEOL2 as usize; + +/// `IGNBRK` +pub const IGNBRK: Tcflag = c::IGNBRK; + +/// `BRKINT` +pub const BRKINT: Tcflag = c::BRKINT; + +/// `IGNPAR` +pub const IGNPAR: Tcflag = c::IGNPAR; + +/// `PARMRK` +pub const PARMRK: Tcflag = c::PARMRK; + +/// `INPCK` +pub const INPCK: Tcflag = c::INPCK; + +/// `ISTRIP` +pub const ISTRIP: Tcflag = c::ISTRIP; + +/// `INLCR` +pub const INLCR: Tcflag = c::INLCR; + +/// `IGNCR` +pub const IGNCR: Tcflag = c::IGNCR; + +/// `ICRNL` +pub const ICRNL: Tcflag = c::ICRNL; + +/// `IUCLC` +#[cfg(any(solarish, target_os = "haiku"))] +pub const IUCLC: Tcflag = c::IUCLC; + +/// `IXON` +pub const IXON: Tcflag = c::IXON; + +/// `IXANY` +#[cfg(not(target_os = "redox"))] +pub const IXANY: Tcflag = c::IXANY; + +/// `IXOFF` +pub const IXOFF: Tcflag = c::IXOFF; + +/// `IMAXBEL` +#[cfg(not(any(target_os = "haiku", target_os = "redox")))] +pub const IMAXBEL: Tcflag = c::IMAXBEL; + +/// `IUTF8` +#[cfg(not(any( + freebsdlike, + netbsdlike, + solarish, + target_os = "aix", + target_os = "emscripten", + target_os = "haiku", + target_os = "redox", +)))] +pub const IUTF8: Tcflag = c::IUTF8; + +/// `OPOST` +pub const OPOST: Tcflag = c::OPOST; + +/// `OLCUC` +#[cfg(not(any( + apple, + freebsdlike, + target_os = "aix", + target_os = "netbsd", + target_os = "redox", +)))] +pub const OLCUC: Tcflag = c::OLCUC; + +/// `ONLCR` +pub const ONLCR: Tcflag = c::ONLCR; + +/// `OCRNL` +pub const OCRNL: Tcflag = c::OCRNL; + +/// `ONOCR` +pub const ONOCR: Tcflag = c::ONOCR; + +/// `ONLRET` +pub const ONLRET: Tcflag = c::ONLRET; + +/// `OFILL` +#[cfg(not(bsd))] +pub const OFILL: Tcflag = c::OFILL; + +/// `OFDEL` +#[cfg(not(bsd))] +pub const OFDEL: Tcflag = c::OFDEL; + +/// `NLDLY` +#[cfg(not(any(bsd, solarish, target_os = "redox")))] +pub const NLDLY: Tcflag = c::NLDLY; + +/// `NL0` +#[cfg(not(any(bsd, solarish, target_os = "fuchsia", target_os = "redox")))] +pub const NL0: Tcflag = c::NL0; + +/// `NL1` +#[cfg(not(any(bsd, solarish, target_os = "fuchsia", target_os = "redox")))] +pub const NL1: Tcflag = c::NL1; + +/// `CRDLY` +#[cfg(not(any(bsd, solarish, target_os = "redox")))] +pub const CRDLY: Tcflag = c::CRDLY; + +/// `CR0` +#[cfg(not(any(bsd, solarish, target_os = "fuchsia", target_os = "redox")))] +pub const CR0: Tcflag = c::CR0; + +/// `CR1` +#[cfg(not(any( + target_env = "musl", + bsd, + solarish, + target_os = "emscripten", + target_os = "fuchsia", + target_os = "redox", +)))] +pub const CR1: Tcflag = c::CR1; + +/// `CR2` +#[cfg(not(any( + target_env = "musl", + bsd, + solarish, + target_os = "emscripten", + target_os = "fuchsia", + target_os = "redox", +)))] +pub const CR2: Tcflag = c::CR2; + +/// `CR3` +#[cfg(not(any( + target_env = "musl", + bsd, + solarish, + target_os = "emscripten", + target_os = "fuchsia", + target_os = "redox", +)))] +pub const CR3: Tcflag = c::CR3; + +/// `TABDLY` +#[cfg(not(any(netbsdlike, solarish, target_os = "dragonfly", target_os = "redox")))] +pub const TABDLY: Tcflag = c::TABDLY; + +/// `TAB0` +#[cfg(not(any( + netbsdlike, + solarish, + target_os = "dragonfly", + target_os = "fuchsia", + target_os = "redox", +)))] +pub const TAB0: Tcflag = c::TAB0; + +/// `TAB1` +#[cfg(not(any( + target_env = "musl", + bsd, + solarish, + target_os = "emscripten", + target_os = "fuchsia", + target_os = "redox", +)))] +pub const TAB1: Tcflag = c::TAB1; + +/// `TAB2` +#[cfg(not(any( + target_env = "musl", + bsd, + solarish, + target_os = "emscripten", + target_os = "fuchsia", + target_os = "redox", +)))] +pub const TAB2: Tcflag = c::TAB2; + +/// `TAB3` +#[cfg(not(any( + target_env = "musl", + bsd, + solarish, + target_os = "emscripten", + target_os = "fuchsia", + target_os = "redox", +)))] +pub const TAB3: Tcflag = c::TAB3; + +/// `BSDLY` +#[cfg(not(any(bsd, solarish, target_os = "redox")))] +pub const BSDLY: Tcflag = c::BSDLY; + +/// `BS0` +#[cfg(not(any(bsd, solarish, target_os = "fuchsia", target_os = "redox")))] +pub const BS0: Tcflag = c::BS0; + +/// `BS1` +#[cfg(not(any( + target_env = "musl", + bsd, + solarish, + target_os = "emscripten", + target_os = "fuchsia", + target_os = "redox", +)))] +pub const BS1: Tcflag = c::BS1; + +/// `FFDLY` +#[cfg(not(any(target_env = "musl", bsd, solarish, target_os = "redox")))] +pub const FFDLY: Tcflag = c::FFDLY; + +/// `FF0` +#[cfg(not(any(bsd, solarish, target_os = "fuchsia", target_os = "redox")))] +pub const FF0: Tcflag = c::FF0; + +/// `FF1` +#[cfg(not(any( + target_env = "musl", + bsd, + solarish, + target_os = "emscripten", + target_os = "fuchsia", + target_os = "redox", +)))] +pub const FF1: Tcflag = c::FF1; + +/// `VTDLY` +#[cfg(not(any(target_env = "musl", bsd, solarish, target_os = "redox")))] +pub const VTDLY: Tcflag = c::VTDLY; + +/// `VT0` +#[cfg(not(any(bsd, solarish, target_os = "fuchsia", target_os = "redox")))] +pub const VT0: Tcflag = c::VT0; + +/// `VT1` +#[cfg(not(any( + target_env = "musl", + bsd, + solarish, + target_os = "emscripten", + target_os = "fuchsia", + target_os = "redox", +)))] +pub const VT1: Tcflag = c::VT1; + +/// `B0` +pub const B0: Speed = c::B0; + +/// `B50` +pub const B50: Speed = c::B50; + +/// `B75` +pub const B75: Speed = c::B75; + +/// `B110` +pub const B110: Speed = c::B110; + +/// `B134` +pub const B134: Speed = c::B134; + +/// `B150` +pub const B150: Speed = c::B150; + +/// `B200` +pub const B200: Speed = c::B200; + +/// `B300` +pub const B300: Speed = c::B300; + +/// `B600` +pub const B600: Speed = c::B600; + +/// `B1200` +pub const B1200: Speed = c::B1200; + +/// `B1800` +pub const B1800: Speed = c::B1800; + +/// `B2400` +pub const B2400: Speed = c::B2400; + +/// `B4800` +pub const B4800: Speed = c::B4800; + +/// `B9600` +pub const B9600: Speed = c::B9600; + +/// `B19200` +pub const B19200: Speed = c::B19200; + +/// `B38400` +pub const B38400: Speed = c::B38400; + +/// `B57600` +#[cfg(not(target_os = "aix"))] +pub const B57600: Speed = c::B57600; + +/// `B115200` +#[cfg(not(target_os = "aix"))] +pub const B115200: Speed = c::B115200; + +/// `B230400` +#[cfg(not(target_os = "aix"))] +pub const B230400: Speed = c::B230400; + +/// `B460800` +#[cfg(not(any( + apple, + target_os = "aix", + target_os = "dragonfly", + target_os = "haiku", + target_os = "openbsd" +)))] +pub const B460800: Speed = c::B460800; + +/// `B500000` +#[cfg(not(any(bsd, solarish, target_os = "aix", target_os = "haiku")))] +pub const B500000: Speed = c::B500000; + +/// `B576000` +#[cfg(not(any(bsd, solarish, target_os = "aix", target_os = "haiku")))] +pub const B576000: Speed = c::B576000; + +/// `B921600` +#[cfg(not(any( + apple, + target_os = "aix", + target_os = "dragonfly", + target_os = "haiku", + target_os = "openbsd" +)))] +pub const B921600: Speed = c::B921600; + +/// `B1000000` +#[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "solaris")))] +pub const B1000000: Speed = c::B1000000; + +/// `B1152000` +#[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "solaris")))] +pub const B1152000: Speed = c::B1152000; + +/// `B1500000` +#[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "solaris")))] +pub const B1500000: Speed = c::B1500000; + +/// `B2000000` +#[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "solaris")))] +pub const B2000000: Speed = c::B2000000; + +/// `B2500000` +#[cfg(not(any( + target_arch = "sparc", + target_arch = "sparc64", + bsd, + target_os = "aix", + target_os = "haiku", + target_os = "solaris", +)))] +pub const B2500000: Speed = c::B2500000; + +/// `B3000000` +#[cfg(not(any( + target_arch = "sparc", + target_arch = "sparc64", + bsd, + target_os = "aix", + target_os = "haiku", + target_os = "solaris", +)))] +pub const B3000000: Speed = c::B3000000; + +/// `B3500000` +#[cfg(not(any( + target_arch = "sparc", + target_arch = "sparc64", + bsd, + target_os = "aix", + target_os = "haiku", + target_os = "solaris", +)))] +pub const B3500000: Speed = c::B3500000; + +/// `B4000000` +#[cfg(not(any( + target_arch = "sparc", + target_arch = "sparc64", + bsd, + target_os = "aix", + target_os = "haiku", + target_os = "solaris", +)))] +pub const B4000000: Speed = c::B4000000; + +/// `BOTHER` +#[cfg(linux_kernel)] +pub const BOTHER: Speed = c::BOTHER; + +/// `CSIZE` +pub const CSIZE: Tcflag = c::CSIZE; + +/// `CS5` +pub const CS5: Tcflag = c::CS5; + +/// `CS6` +pub const CS6: Tcflag = c::CS6; + +/// `CS7` +pub const CS7: Tcflag = c::CS7; + +/// `CS8` +pub const CS8: Tcflag = c::CS8; + +/// `CSTOPB` +pub const CSTOPB: Tcflag = c::CSTOPB; + +/// `CREAD` +pub const CREAD: Tcflag = c::CREAD; + +/// `PARENB` +pub const PARENB: Tcflag = c::PARENB; + +/// `PARODD` +pub const PARODD: Tcflag = c::PARODD; + +/// `HUPCL` +pub const HUPCL: Tcflag = c::HUPCL; + +/// `CLOCAL` +pub const CLOCAL: Tcflag = c::CLOCAL; + +/// `ISIG` +pub const ISIG: Tcflag = c::ISIG; + +/// `ICANON`—A flag for the `c_lflag` field of [`Termios`] indicating +/// canonical mode. +pub const ICANON: Tcflag = c::ICANON; + +/// `ECHO` +pub const ECHO: Tcflag = c::ECHO; + +/// `ECHOE` +pub const ECHOE: Tcflag = c::ECHOE; + +/// `ECHOK` +pub const ECHOK: Tcflag = c::ECHOK; + +/// `ECHONL` +pub const ECHONL: Tcflag = c::ECHONL; + +/// `NOFLSH` +pub const NOFLSH: Tcflag = c::NOFLSH; + +/// `TOSTOP` +pub const TOSTOP: Tcflag = c::TOSTOP; + +/// `IEXTEN` +pub const IEXTEN: Tcflag = c::IEXTEN; + +/// `EXTA` +#[cfg(not(any( + solarish, + target_os = "emscripten", + target_os = "haiku", + target_os = "redox", +)))] +pub const EXTA: Speed = c::EXTA; + +/// `EXTB` +#[cfg(not(any( + solarish, + target_os = "emscripten", + target_os = "haiku", + target_os = "redox", +)))] +pub const EXTB: Speed = c::EXTB; + +/// `CBAUD` +#[cfg(not(any(bsd, target_os = "haiku", target_os = "redox")))] +pub const CBAUD: Tcflag = c::CBAUD; + +/// `CBAUDEX` +#[cfg(not(any( + bsd, + solarish, + target_os = "aix", + target_os = "haiku", + target_os = "redox", +)))] +pub const CBAUDEX: Tcflag = c::CBAUDEX; + +/// `CIBAUD` +#[cfg(not(any( + target_arch = "powerpc", + target_arch = "powerpc64", + bsd, + target_os = "emscripten", + target_os = "haiku", + target_os = "redox", +)))] +pub const CIBAUD: Tcflag = c::CIBAUD; + +/// `CIBAUD` +// glibc on powerpc lacks a definition for `CIBAUD`, even though the Linux +// headers and Musl on powerpc both have one. So define it manually. +#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] +pub const CIBAUD: Tcflag = 0o77600000; + +/// `CMSPAR` +#[cfg(not(any( + bsd, + solarish, + target_os = "aix", + target_os = "emscripten", + target_os = "haiku", + target_os = "redox", +)))] +pub const CMSPAR: Tcflag = c::CMSPAR; + +/// `CRTSCTS` +#[cfg(not(any(target_os = "aix", target_os = "redox")))] +pub const CRTSCTS: Tcflag = c::CRTSCTS; + +/// `XCASE` +#[cfg(any(target_arch = "s390x", target_os = "haiku"))] +pub const XCASE: Tcflag = c::XCASE; + +/// `ECHOCTL` +#[cfg(not(any(target_os = "redox")))] +pub const ECHOCTL: Tcflag = c::ECHOCTL; + +/// `ECHOPRT` +#[cfg(not(any(target_os = "redox")))] +pub const ECHOPRT: Tcflag = c::ECHOPRT; + +/// `ECHOKE` +#[cfg(not(any(target_os = "redox")))] +pub const ECHOKE: Tcflag = c::ECHOKE; + +/// `FLUSHO` +#[cfg(not(any(target_os = "redox")))] +pub const FLUSHO: Tcflag = c::FLUSHO; + +/// `PENDIN` +#[cfg(not(any(target_os = "redox")))] +pub const PENDIN: Tcflag = c::PENDIN; + +/// `EXTPROC` +#[cfg(not(any(target_os = "aix", target_os = "haiku", target_os = "redox")))] +pub const EXTPROC: Tcflag = c::EXTPROC; + +/// `XTABS` +#[cfg(not(any( + bsd, + solarish, + target_os = "aix", + target_os = "haiku", + target_os = "redox", +)))] +pub const XTABS: Tcflag = c::XTABS; diff --git a/vendor/rustix-0.37.22/src/backend/libc/thread/mod.rs b/vendor/rustix-0.37.22/src/backend/libc/thread/mod.rs new file mode 100644 index 000000000..40e0d1135 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/thread/mod.rs @@ -0,0 +1,2 @@ +#[cfg(not(windows))] +pub(crate) mod syscalls; diff --git a/vendor/rustix-0.37.22/src/backend/libc/thread/syscalls.rs b/vendor/rustix-0.37.22/src/backend/libc/thread/syscalls.rs new file mode 100644 index 000000000..3c1d09687 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/thread/syscalls.rs @@ -0,0 +1,368 @@ +//! libc syscalls supporting `rustix::thread`. + +use super::super::c; +use super::super::conv::ret; +use super::super::time::types::LibcTimespec; +use crate::io; +#[cfg(not(target_os = "redox"))] +use crate::thread::{NanosleepRelativeResult, Timespec}; +use core::mem::MaybeUninit; +#[cfg(linux_kernel)] +use { + super::super::conv::{borrowed_fd, ret_c_int, syscall_ret}, + crate::fd::BorrowedFd, + crate::process::{Pid, RawNonZeroPid}, + crate::utils::as_mut_ptr, +}; +#[cfg(not(any( + apple, + freebsdlike, + target_os = "emscripten", + target_os = "haiku", + target_os = "openbsd", + target_os = "redox", + target_os = "wasi", +)))] +use {crate::thread::ClockId, core::ptr::null_mut}; + +#[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +))] +weak!(fn __clock_nanosleep_time64(c::clockid_t, c::c_int, *const LibcTimespec, *mut LibcTimespec) -> c::c_int); +#[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +))] +weak!(fn __nanosleep64(*const LibcTimespec, *mut LibcTimespec) -> c::c_int); + +#[cfg(not(any( + apple, + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", // FreeBSD 12 has clock_nanosleep, but libc targets FreeBSD 11. + target_os = "haiku", + target_os = "openbsd", + target_os = "redox", + target_os = "wasi", +)))] +#[inline] +pub(crate) fn clock_nanosleep_relative(id: ClockId, request: &Timespec) -> NanosleepRelativeResult { + let mut remain = MaybeUninit::<LibcTimespec>::uninit(); + let flags = 0; + + // 32-bit gnu version: libc has `clock_nanosleep` but it is not y2038 safe + // by default. + #[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", + ))] + unsafe { + if let Some(libc_clock_nanosleep) = __clock_nanosleep_time64.get() { + match libc_clock_nanosleep( + id as c::clockid_t, + flags, + &request.clone().into(), + remain.as_mut_ptr(), + ) { + 0 => NanosleepRelativeResult::Ok, + err if err == io::Errno::INTR.0 => { + NanosleepRelativeResult::Interrupted(remain.assume_init().into()) + } + err => NanosleepRelativeResult::Err(io::Errno(err)), + } + } else { + clock_nanosleep_relative_old(id, request) + } + } + + // Main version: libc is y2038 safe and has `clock_nanosleep`. + #[cfg(not(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", + )))] + unsafe { + match c::clock_nanosleep(id as c::clockid_t, flags, request, remain.as_mut_ptr()) { + 0 => NanosleepRelativeResult::Ok, + err if err == io::Errno::INTR.0 => { + NanosleepRelativeResult::Interrupted(remain.assume_init()) + } + err => NanosleepRelativeResult::Err(io::Errno(err)), + } + } +} + +#[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +))] +unsafe fn clock_nanosleep_relative_old(id: ClockId, request: &Timespec) -> NanosleepRelativeResult { + use core::convert::TryInto; + let tv_sec = match request.tv_sec.try_into() { + Ok(tv_sec) => tv_sec, + Err(_) => return NanosleepRelativeResult::Err(io::Errno::OVERFLOW), + }; + let tv_nsec = match request.tv_nsec.try_into() { + Ok(tv_nsec) => tv_nsec, + Err(_) => return NanosleepRelativeResult::Err(io::Errno::INVAL), + }; + let old_request = c::timespec { tv_sec, tv_nsec }; + let mut old_remain = MaybeUninit::<c::timespec>::uninit(); + let flags = 0; + + match c::clock_nanosleep( + id as c::clockid_t, + flags, + &old_request, + old_remain.as_mut_ptr(), + ) { + 0 => NanosleepRelativeResult::Ok, + err if err == io::Errno::INTR.0 => { + let old_remain = old_remain.assume_init(); + let remain = Timespec { + tv_sec: old_remain.tv_sec.into(), + tv_nsec: old_remain.tv_nsec.into(), + }; + NanosleepRelativeResult::Interrupted(remain) + } + err => NanosleepRelativeResult::Err(io::Errno(err)), + } +} + +#[cfg(not(any( + apple, + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", // FreeBSD 12 has clock_nanosleep, but libc targets FreeBSD 11. + target_os = "haiku", + target_os = "openbsd", + target_os = "redox", + target_os = "wasi", +)))] +#[inline] +pub(crate) fn clock_nanosleep_absolute(id: ClockId, request: &Timespec) -> io::Result<()> { + let flags = c::TIMER_ABSTIME; + + // 32-bit gnu version: libc has `clock_nanosleep` but it is not y2038 safe + // by default. + #[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", + ))] + { + if let Some(libc_clock_nanosleep) = __clock_nanosleep_time64.get() { + match unsafe { + libc_clock_nanosleep( + id as c::clockid_t, + flags, + &request.clone().into(), + null_mut(), + ) + } { + 0 => Ok(()), + err => Err(io::Errno(err)), + } + } else { + clock_nanosleep_absolute_old(id, request) + } + } + + // Main version: libc is y2038 safe and has `clock_nanosleep`. + #[cfg(not(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", + )))] + match unsafe { c::clock_nanosleep(id as c::clockid_t, flags, request, null_mut()) } { + 0 => Ok(()), + err => Err(io::Errno(err)), + } +} + +#[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +))] +fn clock_nanosleep_absolute_old(id: ClockId, request: &Timespec) -> io::Result<()> { + use core::convert::TryInto; + + let flags = c::TIMER_ABSTIME; + + let old_request = c::timespec { + tv_sec: request.tv_sec.try_into().map_err(|_| io::Errno::OVERFLOW)?, + tv_nsec: request.tv_nsec.try_into().map_err(|_| io::Errno::INVAL)?, + }; + match unsafe { c::clock_nanosleep(id as c::clockid_t, flags, &old_request, null_mut()) } { + 0 => Ok(()), + err => Err(io::Errno(err)), + } +} + +#[cfg(not(target_os = "redox"))] +#[inline] +pub(crate) fn nanosleep(request: &Timespec) -> NanosleepRelativeResult { + let mut remain = MaybeUninit::<LibcTimespec>::uninit(); + + // 32-bit gnu version: libc has `nanosleep` but it is not y2038 safe by + // default. + #[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", + ))] + unsafe { + if let Some(libc_nanosleep) = __nanosleep64.get() { + match ret(libc_nanosleep(&request.clone().into(), remain.as_mut_ptr())) { + Ok(()) => NanosleepRelativeResult::Ok, + Err(io::Errno::INTR) => { + NanosleepRelativeResult::Interrupted(remain.assume_init().into()) + } + Err(err) => NanosleepRelativeResult::Err(err), + } + } else { + nanosleep_old(request) + } + } + + // Main version: libc is y2038 safe and has `nanosleep`. + #[cfg(not(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", + )))] + unsafe { + match ret(c::nanosleep(request, remain.as_mut_ptr())) { + Ok(()) => NanosleepRelativeResult::Ok, + Err(io::Errno::INTR) => NanosleepRelativeResult::Interrupted(remain.assume_init()), + Err(err) => NanosleepRelativeResult::Err(err), + } + } +} + +#[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +))] +unsafe fn nanosleep_old(request: &Timespec) -> NanosleepRelativeResult { + use core::convert::TryInto; + let tv_sec = match request.tv_sec.try_into() { + Ok(tv_sec) => tv_sec, + Err(_) => return NanosleepRelativeResult::Err(io::Errno::OVERFLOW), + }; + let tv_nsec = match request.tv_nsec.try_into() { + Ok(tv_nsec) => tv_nsec, + Err(_) => return NanosleepRelativeResult::Err(io::Errno::INVAL), + }; + let old_request = c::timespec { tv_sec, tv_nsec }; + let mut old_remain = MaybeUninit::<c::timespec>::uninit(); + + match ret(c::nanosleep(&old_request, old_remain.as_mut_ptr())) { + Ok(()) => NanosleepRelativeResult::Ok, + Err(io::Errno::INTR) => { + let old_remain = old_remain.assume_init(); + let remain = Timespec { + tv_sec: old_remain.tv_sec.into(), + tv_nsec: old_remain.tv_nsec.into(), + }; + NanosleepRelativeResult::Interrupted(remain) + } + Err(err) => NanosleepRelativeResult::Err(err), + } +} + +#[cfg(linux_kernel)] +#[inline] +#[must_use] +pub(crate) fn gettid() -> Pid { + // `gettid` wasn't supported in glibc until 2.30, and musl until 1.2.2, + // so use `syscall`. + // <https://sourceware.org/bugzilla/show_bug.cgi?id=6399#c62> + weak_or_syscall! { + fn gettid() via SYS_gettid -> c::pid_t + } + + unsafe { + let tid = gettid(); + debug_assert_ne!(tid, 0); + Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked(tid)) + } +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn setns(fd: BorrowedFd, nstype: c::c_int) -> io::Result<c::c_int> { + // `setns` wasn't supported in glibc until 2.14, and musl until 0.9.5, + // so use `syscall`. + weak_or_syscall! { + fn setns(fd: c::c_int, nstype: c::c_int) via SYS_setns -> c::c_int + } + + unsafe { ret_c_int(setns(borrowed_fd(fd), nstype)) } +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn unshare(flags: crate::thread::UnshareFlags) -> io::Result<()> { + unsafe { ret(c::unshare(flags.bits() as i32)) } +} + +#[cfg(linux_kernel)] +#[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 { + syscall_ret(c::syscall( + c::SYS_capget, + as_mut_ptr(header), + data.as_mut_ptr(), + )) + } +} + +#[cfg(linux_kernel)] +#[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 { syscall_ret(c::syscall(c::SYS_capset, as_mut_ptr(header), data.as_ptr())) } +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn setuid_thread(uid: crate::process::Uid) -> io::Result<()> { + unsafe { syscall_ret(c::syscall(c::SYS_setuid, uid.as_raw())) } +} + +#[cfg(linux_kernel)] +#[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"))] + const SYS: c::c_long = c::SYS_setresuid32 as c::c_long; + #[cfg(not(any(target_arch = "x86", target_arch = "arm", target_arch = "sparc")))] + const SYS: c::c_long = c::SYS_setresuid as c::c_long; + unsafe { syscall_ret(c::syscall(SYS, ruid.as_raw(), euid.as_raw(), suid.as_raw())) } +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn setgid_thread(gid: crate::process::Gid) -> io::Result<()> { + unsafe { syscall_ret(c::syscall(c::SYS_setgid, gid.as_raw())) } +} + +#[cfg(linux_kernel)] +#[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"))] + const SYS: c::c_long = c::SYS_setresgid32 as c::c_long; + #[cfg(not(any(target_arch = "x86", target_arch = "arm", target_arch = "sparc")))] + const SYS: c::c_long = c::SYS_setresgid as c::c_long; + unsafe { syscall_ret(c::syscall(SYS, rgid.as_raw(), egid.as_raw(), sgid.as_raw())) } +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/time/mod.rs b/vendor/rustix-0.37.22/src/backend/libc/time/mod.rs new file mode 100644 index 000000000..bff7fd564 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/time/mod.rs @@ -0,0 +1,3 @@ +#[cfg(not(windows))] +pub(crate) mod syscalls; +pub(crate) mod types; diff --git a/vendor/rustix-0.37.22/src/backend/libc/time/syscalls.rs b/vendor/rustix-0.37.22/src/backend/libc/time/syscalls.rs new file mode 100644 index 000000000..9d03903dc --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/time/syscalls.rs @@ -0,0 +1,471 @@ +//! libc syscalls supporting `rustix::time`. + +use super::super::c; +use super::super::conv::ret; +#[cfg(feature = "time")] +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +use super::super::time::types::LibcItimerspec; +use super::super::time::types::LibcTimespec; +use super::types::Timespec; +#[cfg(not(target_os = "wasi"))] +use super::types::{ClockId, DynamicClockId}; +use crate::io; +use core::mem::MaybeUninit; +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[cfg(feature = "time")] +use { + super::super::conv::{borrowed_fd, ret_owned_fd}, + crate::fd::{BorrowedFd, OwnedFd}, + crate::time::{Itimerspec, TimerfdClockId, TimerfdFlags, TimerfdTimerFlags}, +}; + +#[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +))] +weak!(fn __clock_gettime64(c::clockid_t, *mut LibcTimespec) -> c::c_int); +#[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +))] +weak!(fn __clock_settime64(c::clockid_t, *const LibcTimespec) -> c::c_int); +#[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +))] +weak!(fn __clock_getres64(c::clockid_t, *mut LibcTimespec) -> c::c_int); +#[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +))] +#[cfg(feature = "time")] +weak!(fn __timerfd_gettime64(c::c_int, *mut LibcItimerspec) -> c::c_int); +#[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +))] +#[cfg(feature = "time")] +weak!(fn __timerfd_settime64(c::c_int, c::c_int, *const LibcItimerspec, *mut LibcItimerspec) -> c::c_int); + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +#[inline] +#[must_use] +pub(crate) fn clock_getres(id: ClockId) -> Timespec { + let mut timespec = MaybeUninit::<LibcTimespec>::uninit(); + + // 32-bit gnu version: libc has `clock_getres` but it is not y2038 safe by + // default. + #[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", + ))] + unsafe { + if let Some(libc_clock_getres) = __clock_getres64.get() { + ret(libc_clock_getres(id as c::clockid_t, timespec.as_mut_ptr())).unwrap(); + timespec.assume_init().into() + } else { + clock_getres_old(id) + } + } + + // Main version: libc is y2038 safe and has `clock_getres`. + #[cfg(not(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", + )))] + unsafe { + let _ = c::clock_getres(id as c::clockid_t, timespec.as_mut_ptr()); + timespec.assume_init() + } +} + +#[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +))] +#[must_use] +unsafe fn clock_getres_old(id: ClockId) -> Timespec { + let mut old_timespec = MaybeUninit::<c::timespec>::uninit(); + ret(c::clock_getres( + id as c::clockid_t, + old_timespec.as_mut_ptr(), + )) + .unwrap(); + let old_timespec = old_timespec.assume_init(); + Timespec { + tv_sec: old_timespec.tv_sec.into(), + tv_nsec: old_timespec.tv_nsec.into(), + } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +#[must_use] +pub(crate) fn clock_gettime(id: ClockId) -> Timespec { + let mut timespec = MaybeUninit::<LibcTimespec>::uninit(); + + #[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", + ))] + unsafe { + if let Some(libc_clock_gettime) = __clock_gettime64.get() { + ret(libc_clock_gettime( + id as c::clockid_t, + timespec.as_mut_ptr(), + )) + .unwrap(); + timespec.assume_init().into() + } else { + clock_gettime_old(id) + } + } + + // Use `unwrap()` here because `clock_getres` can fail if the clock itself + // overflows a number of seconds, but if that happens, the monotonic clocks + // can't maintain their invariants, or the realtime clocks aren't properly + // configured. + #[cfg(not(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", + )))] + unsafe { + ret(c::clock_gettime(id as c::clockid_t, timespec.as_mut_ptr())).unwrap(); + timespec.assume_init() + } +} + +#[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +))] +#[must_use] +unsafe fn clock_gettime_old(id: ClockId) -> Timespec { + let mut old_timespec = MaybeUninit::<c::timespec>::uninit(); + ret(c::clock_gettime( + id as c::clockid_t, + old_timespec.as_mut_ptr(), + )) + .unwrap(); + let old_timespec = old_timespec.assume_init(); + Timespec { + tv_sec: old_timespec.tv_sec.into(), + tv_nsec: old_timespec.tv_nsec.into(), + } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +pub(crate) fn clock_gettime_dynamic(id: DynamicClockId<'_>) -> io::Result<Timespec> { + let mut timespec = MaybeUninit::<LibcTimespec>::uninit(); + unsafe { + let id: c::clockid_t = match id { + DynamicClockId::Known(id) => id as c::clockid_t, + + #[cfg(linux_kernel)] + DynamicClockId::Dynamic(fd) => { + use crate::fd::AsRawFd; + const CLOCKFD: i32 = 3; + (!fd.as_raw_fd() << 3) | CLOCKFD + } + + #[cfg(not(linux_kernel))] + DynamicClockId::Dynamic(_fd) => { + // Dynamic clocks are not supported on this platform. + return Err(io::Errno::INVAL); + } + + #[cfg(linux_kernel)] + DynamicClockId::RealtimeAlarm => c::CLOCK_REALTIME_ALARM, + + #[cfg(linux_kernel)] + DynamicClockId::Tai => c::CLOCK_TAI, + + #[cfg(any(linux_kernel, target_os = "openbsd"))] + DynamicClockId::Boottime => c::CLOCK_BOOTTIME, + + #[cfg(linux_kernel)] + DynamicClockId::BoottimeAlarm => c::CLOCK_BOOTTIME_ALARM, + }; + + #[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", + ))] + { + if let Some(libc_clock_gettime) = __clock_gettime64.get() { + ret(libc_clock_gettime( + id as c::clockid_t, + timespec.as_mut_ptr(), + ))?; + + Ok(timespec.assume_init().into()) + } else { + clock_gettime_dynamic_old(id) + } + } + + #[cfg(not(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", + )))] + { + ret(c::clock_gettime(id as c::clockid_t, timespec.as_mut_ptr()))?; + + Ok(timespec.assume_init()) + } + } +} + +#[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +))] +#[inline] +unsafe fn clock_gettime_dynamic_old(id: c::clockid_t) -> io::Result<Timespec> { + let mut old_timespec = MaybeUninit::<c::timespec>::uninit(); + + ret(c::clock_gettime( + id as c::clockid_t, + old_timespec.as_mut_ptr(), + ))?; + + let old_timespec = old_timespec.assume_init(); + Ok(Timespec { + tv_sec: old_timespec.tv_sec.into(), + tv_nsec: old_timespec.tv_nsec.into(), + }) +} + +#[cfg(not(any( + target_os = "redox", + target_os = "wasi", + all(apple, not(target_os = "macos")) +)))] +#[inline] +pub(crate) fn clock_settime(id: ClockId, timespec: Timespec) -> io::Result<()> { + #[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", + ))] + unsafe { + if let Some(libc_clock_settime) = __clock_settime64.get() { + let mut new_timespec = core::mem::zeroed::<LibcTimespec>(); + new_timespec.tv_sec = timespec.tv_sec; + new_timespec.tv_nsec = timespec.tv_nsec as _; + ret(libc_clock_settime(id as c::clockid_t, &new_timespec)) + } else { + clock_settime_old(id, timespec) + } + } + + #[cfg(not(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", + )))] + unsafe { + ret(c::clock_settime(id as c::clockid_t, ×pec)) + } +} + +#[cfg(not(any( + target_os = "redox", + target_os = "wasi", + all(apple, not(target_os = "macos")) +)))] +#[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +))] +unsafe fn clock_settime_old(id: ClockId, timespec: Timespec) -> io::Result<()> { + use core::convert::TryInto; + let old_timespec = c::timespec { + tv_sec: timespec + .tv_sec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + tv_nsec: timespec.tv_nsec as _, + }; + ret(c::clock_settime(id as c::clockid_t, &old_timespec)) +} + +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[cfg(feature = "time")] +pub(crate) fn timerfd_create(id: TimerfdClockId, flags: TimerfdFlags) -> io::Result<OwnedFd> { + unsafe { ret_owned_fd(c::timerfd_create(id as c::clockid_t, flags.bits())) } +} + +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[cfg(feature = "time")] +pub(crate) fn timerfd_settime( + fd: BorrowedFd<'_>, + flags: TimerfdTimerFlags, + new_value: &Itimerspec, +) -> io::Result<Itimerspec> { + let mut result = MaybeUninit::<LibcItimerspec>::uninit(); + + #[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", + ))] + unsafe { + if let Some(libc_timerfd_settime) = __timerfd_settime64.get() { + ret(libc_timerfd_settime( + borrowed_fd(fd), + flags.bits(), + &new_value.clone().into(), + result.as_mut_ptr(), + ))?; + Ok(result.assume_init().into()) + } else { + timerfd_settime_old(fd, flags, new_value) + } + } + + #[cfg(not(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", + )))] + unsafe { + ret(c::timerfd_settime( + borrowed_fd(fd), + flags.bits(), + new_value, + result.as_mut_ptr(), + ))?; + Ok(result.assume_init()) + } +} + +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +))] +#[cfg(feature = "time")] +unsafe fn timerfd_settime_old( + fd: BorrowedFd<'_>, + flags: TimerfdTimerFlags, + new_value: &Itimerspec, +) -> io::Result<Itimerspec> { + use core::convert::TryInto; + + let mut old_result = MaybeUninit::<c::itimerspec>::uninit(); + + // Convert `new_value` to the old `itimerspec` format. + let old_new_value = c::itimerspec { + it_interval: c::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: c::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(c::timerfd_settime( + borrowed_fd(fd), + flags.bits(), + &old_new_value, + old_result.as_mut_ptr(), + ))?; + + let old_result = old_result.assume_init(); + Ok(Itimerspec { + it_interval: Timespec { + tv_sec: old_result + .it_interval + .tv_sec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + tv_nsec: old_result.it_interval.tv_nsec as _, + }, + it_value: Timespec { + tv_sec: old_result + .it_interval + .tv_sec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + tv_nsec: old_result.it_interval.tv_nsec as _, + }, + }) +} + +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[cfg(feature = "time")] +pub(crate) fn timerfd_gettime(fd: BorrowedFd<'_>) -> io::Result<Itimerspec> { + let mut result = MaybeUninit::<LibcItimerspec>::uninit(); + + #[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", + ))] + unsafe { + if let Some(libc_timerfd_gettime) = __timerfd_gettime64.get() { + ret(libc_timerfd_gettime(borrowed_fd(fd), result.as_mut_ptr()))?; + Ok(result.assume_init().into()) + } else { + timerfd_gettime_old(fd) + } + } + + #[cfg(not(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", + )))] + unsafe { + ret(c::timerfd_gettime(borrowed_fd(fd), result.as_mut_ptr()))?; + Ok(result.assume_init()) + } +} + +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +))] +#[cfg(feature = "time")] +unsafe fn timerfd_gettime_old(fd: BorrowedFd<'_>) -> io::Result<Itimerspec> { + use core::convert::TryInto; + + let mut old_result = MaybeUninit::<c::itimerspec>::uninit(); + + ret(c::timerfd_gettime(borrowed_fd(fd), old_result.as_mut_ptr()))?; + + let old_result = old_result.assume_init(); + Ok(Itimerspec { + it_interval: Timespec { + tv_sec: old_result + .it_interval + .tv_sec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + tv_nsec: old_result.it_interval.tv_nsec as _, + }, + it_value: Timespec { + tv_sec: old_result + .it_interval + .tv_sec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + tv_nsec: old_result.it_interval.tv_nsec as _, + }, + }) +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/time/types.rs b/vendor/rustix-0.37.22/src/backend/libc/time/types.rs new file mode 100644 index 000000000..a7310ca2f --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/time/types.rs @@ -0,0 +1,368 @@ +use super::super::c; +#[cfg(not(target_os = "wasi"))] +use crate::fd::BorrowedFd; +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +use bitflags::bitflags; + +/// `struct timespec` +#[cfg(not(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +)))] +pub type Timespec = c::timespec; + +/// `struct timespec` +#[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +))] +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct Timespec { + /// Seconds. + pub tv_sec: Secs, + + /// Nanoseconds. Must be less than 1_000_000_000. + pub tv_nsec: Nsecs, +} + +/// A type for the `tv_sec` field of [`Timespec`]. +#[cfg(not(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +)))] +#[allow(deprecated)] +pub type Secs = c::time_t; + +/// A type for the `tv_sec` field of [`Timespec`]. +#[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +))] +pub type Secs = i64; + +/// A type for the `tv_nsec` field of [`Timespec`]. +#[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] +pub type Nsecs = i64; + +/// A type for the `tv_nsec` field of [`Timespec`]. +#[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] +pub type Nsecs = c::c_long; + +/// On most platforms, `LibcTimespec` is just `Timespec`. +#[cfg(not(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +)))] +pub(crate) type LibcTimespec = Timespec; + +/// On 32-bit glibc platforms, `timespec` has anonymous padding fields, which +/// Rust doesn't support yet (see `unnamed_fields`), so we define our own +/// struct with explicit padding, with bidirectional `From` impls. +#[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +))] +#[repr(C)] +#[derive(Debug, Clone)] +pub(crate) struct LibcTimespec { + pub(crate) tv_sec: Secs, + + #[cfg(target_endian = "big")] + padding: core::mem::MaybeUninit<u32>, + + pub(crate) tv_nsec: Nsecs, + + #[cfg(target_endian = "little")] + padding: core::mem::MaybeUninit<u32>, +} + +#[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +))] +impl From<LibcTimespec> for Timespec { + #[inline] + fn from(t: LibcTimespec) -> Self { + Self { + tv_sec: t.tv_sec, + tv_nsec: t.tv_nsec, + } + } +} + +#[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +))] +impl From<Timespec> for LibcTimespec { + #[inline] + fn from(t: Timespec) -> Self { + Self { + tv_sec: t.tv_sec, + tv_nsec: t.tv_nsec, + padding: core::mem::MaybeUninit::uninit(), + } + } +} + +/// `CLOCK_*` constants for use with [`clock_gettime`]. +/// +/// These constants are always supported at runtime, so `clock_gettime` never +/// has to fail with `INVAL` due to an unsupported clock. See +/// [`DynamicClockId`] for a greater set of clocks, with the caveat that not +/// all of them are always supported. +/// +/// [`clock_gettime`]: crate::time::clock_gettime +#[cfg(not(any(apple, target_os = "wasi")))] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[cfg_attr(not(target_os = "dragonfly"), repr(i32))] +#[cfg_attr(target_os = "dragonfly", repr(u64))] +#[non_exhaustive] +pub enum ClockId { + /// `CLOCK_REALTIME` + Realtime = c::CLOCK_REALTIME, + + /// `CLOCK_MONOTONIC` + Monotonic = c::CLOCK_MONOTONIC, + + /// `CLOCK_UPTIME` + #[cfg(any(freebsdlike, target_os = "openbsd"))] + Uptime = c::CLOCK_UPTIME, + + /// `CLOCK_PROCESS_CPUTIME_ID` + #[cfg(not(any(solarish, target_os = "netbsd", target_os = "redox")))] + ProcessCPUTime = c::CLOCK_PROCESS_CPUTIME_ID, + + /// `CLOCK_THREAD_CPUTIME_ID` + #[cfg(not(any(solarish, target_os = "netbsd", target_os = "redox")))] + ThreadCPUTime = c::CLOCK_THREAD_CPUTIME_ID, + + /// `CLOCK_REALTIME_COARSE` + #[cfg(any(linux_kernel, target_os = "freebsd"))] + RealtimeCoarse = c::CLOCK_REALTIME_COARSE, + + /// `CLOCK_MONOTONIC_COARSE` + #[cfg(any(linux_kernel, target_os = "freebsd"))] + MonotonicCoarse = c::CLOCK_MONOTONIC_COARSE, + + /// `CLOCK_MONOTONIC_RAW` + #[cfg(linux_kernel)] + MonotonicRaw = c::CLOCK_MONOTONIC_RAW, +} + +/// `CLOCK_*` constants for use with [`clock_gettime`]. +/// +/// These constants are always supported at runtime, so `clock_gettime` never +/// has to fail with `INVAL` due to an unsupported clock. See +/// [`DynamicClockId`] for a greater set of clocks, with the caveat that not +/// all of them are always supported. +#[cfg(apple)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[repr(u32)] +#[non_exhaustive] +pub enum ClockId { + /// `CLOCK_REALTIME` + Realtime = c::CLOCK_REALTIME, + + /// `CLOCK_MONOTONIC` + Monotonic = c::CLOCK_MONOTONIC, + + /// `CLOCK_PROCESS_CPUTIME_ID` + ProcessCPUTime = c::CLOCK_PROCESS_CPUTIME_ID, + + /// `CLOCK_THREAD_CPUTIME_ID` + ThreadCPUTime = c::CLOCK_THREAD_CPUTIME_ID, +} + +/// `CLOCK_*` constants for use with [`clock_gettime_dynamic`]. +/// +/// These constants may be unsupported at runtime, depending on the OS version, +/// and `clock_gettime_dynamic` may fail with `INVAL`. See [`ClockId`] for +/// clocks which are always supported at runtime. +/// +/// [`clock_gettime_dynamic`]: crate::time::clock_gettime_dynamic +#[cfg(not(target_os = "wasi"))] +#[derive(Debug, Copy, Clone)] +#[non_exhaustive] +pub enum DynamicClockId<'a> { + /// `ClockId` values that are always supported at runtime. + Known(ClockId), + + /// Linux dynamic clocks. + Dynamic(BorrowedFd<'a>), + + /// `CLOCK_REALTIME_ALARM`, available on Linux >= 3.0 + #[cfg(linux_kernel)] + RealtimeAlarm, + + /// `CLOCK_TAI`, available on Linux >= 3.10 + #[cfg(linux_kernel)] + Tai, + + /// `CLOCK_BOOTTIME`, available on Linux >= 2.6.39 + #[cfg(any(linux_kernel, target_os = "openbsd"))] + Boottime, + + /// `CLOCK_BOOTTIME_ALARM`, available on Linux >= 2.6.39 + #[cfg(linux_kernel)] + BoottimeAlarm, +} + +/// `struct itimerspec` for use with [`timerfd_gettime`] and +/// [`timerfd_settime`]. +/// +/// [`timerfd_gettime`]: crate::time::timerfd_gettime +/// [`timerfd_settime`]: crate::time::timerfd_settime +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[cfg(not(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +)))] +pub type Itimerspec = c::itimerspec; + +/// `struct itimerspec` for use with [`timerfd_gettime`] and +/// [`timerfd_settime`]. +/// +/// [`timerfd_gettime`]: crate::time::timerfd_gettime +/// [`timerfd_settime`]: crate::time::timerfd_settime +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +))] +#[allow(missing_docs)] +#[repr(C)] +#[derive(Debug, Clone)] +pub struct Itimerspec { + pub it_interval: Timespec, + pub it_value: Timespec, +} + +/// On most platforms, `LibcItimerspec` is just `Itimerspec`. +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[cfg(not(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +)))] +pub(crate) type LibcItimerspec = Itimerspec; + +/// On 32-bit glibc platforms, `LibcTimespec` differs from `Timespec`, so we +/// define our own struct, with bidirectional `From` impls. +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +))] +#[repr(C)] +#[derive(Debug, Clone)] +pub(crate) struct LibcItimerspec { + pub it_interval: LibcTimespec, + pub it_value: LibcTimespec, +} + +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +))] +impl From<LibcItimerspec> for Itimerspec { + #[inline] + fn from(t: LibcItimerspec) -> Self { + Self { + it_interval: t.it_interval.into(), + it_value: t.it_value.into(), + } + } +} + +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +))] +impl From<Itimerspec> for LibcItimerspec { + #[inline] + fn from(t: Itimerspec) -> Self { + Self { + it_interval: t.it_interval.into(), + it_value: t.it_value.into(), + } + } +} + +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +bitflags! { + /// `TFD_*` flags for use with [`timerfd_create`]. + /// + /// [`timerfd_create`]: crate::time::timerfd_create + pub struct TimerfdFlags: c::c_int { + /// `TFD_NONBLOCK` + const NONBLOCK = c::TFD_NONBLOCK; + + /// `TFD_CLOEXEC` + const CLOEXEC = c::TFD_CLOEXEC; + } +} + +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +bitflags! { + /// `TFD_TIMER_*` flags for use with [`timerfd_settime`]. + /// + /// [`timerfd_settime`]: crate::time::timerfd_settime + pub struct TimerfdTimerFlags: c::c_int { + /// `TFD_TIMER_ABSTIME` + const ABSTIME = c::TFD_TIMER_ABSTIME; + + /// `TFD_TIMER_CANCEL_ON_SET` + #[cfg(linux_kernel)] + const CANCEL_ON_SET = c::TFD_TIMER_CANCEL_ON_SET; + } +} + +/// `CLOCK_*` constants for use with [`timerfd_create`]. +/// +/// [`timerfd_create`]: crate::time::timerfd_create +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[repr(i32)] +#[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. + Realtime = c::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. + Monotonic = c::CLOCK_MONOTONIC, + + /// `CLOCK_BOOTTIME`—Like `Monotonic`, but advances while suspended. + /// + /// This clock is similar to `Monotonic`, but does advance while the system + /// is suspended. + Boottime = c::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. + RealtimeAlarm = c::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. + BoottimeAlarm = c::CLOCK_BOOTTIME_ALARM, +} diff --git a/vendor/rustix-0.37.22/src/backend/libc/winsock_c.rs b/vendor/rustix-0.37.22/src/backend/libc/winsock_c.rs new file mode 100644 index 000000000..0a1554a86 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/libc/winsock_c.rs @@ -0,0 +1,59 @@ +//! Adapt the Winsock2 API to resemble a POSIX-style libc API. + +#![allow(unused_imports)] +#![allow(non_camel_case_types)] +#![allow(dead_code)] + +use windows_sys::Win32::Networking::WinSock; + +// Define the basic C types. With Rust 1.64, we can use these from `core::ffi`. +pub(crate) type c_schar = i8; +pub(crate) type c_uchar = u8; +pub(crate) type c_short = i16; +pub(crate) type c_ushort = u16; +pub(crate) type c_int = i32; +pub(crate) type c_uint = u32; +pub(crate) type c_longlong = i64; +pub(crate) type c_ulonglong = u64; +pub(crate) type ssize_t = isize; +pub(crate) type c_char = i8; +pub(crate) type c_long = i32; +pub(crate) type c_ulong = u32; +pub(crate) use core::ffi::c_void; + +// windows-sys declares these constants as u16. For better compatibility +// with Unix-family APIs, redeclare them as u32. +pub(crate) const AF_INET: i32 = WinSock::AF_INET as _; +pub(crate) const AF_INET6: i32 = WinSock::AF_INET6 as _; +pub(crate) const AF_UNSPEC: i32 = WinSock::AF_UNSPEC as _; + +// Include the contents of `WinSock`, renaming as needed to match POSIX. +// +// Use `WSA_E_CANCELLED` for `ECANCELED` instead of `WSAECANCELLED`, because +// `WSAECANCELLED` will be removed in the future. +// <https://docs.microsoft.com/en-us/windows/win32/api/ws2spi/nc-ws2spi-lpnsplookupserviceend#remarks> +pub(crate) use WinSock::{ + closesocket as close, ioctlsocket as ioctl, WSAPoll as poll, ADDRESS_FAMILY as sa_family_t, + ADDRINFOA as addrinfo, IN6_ADDR as in6_addr, IN_ADDR as in_addr, IPV6_MREQ as ipv6_mreq, + IP_MREQ as ip_mreq, LINGER as linger, SD_BOTH as SHUT_RDWR, SD_RECEIVE as SHUT_RD, + SD_SEND as SHUT_WR, SOCKADDR as sockaddr, SOCKADDR_IN as sockaddr_in, + SOCKADDR_IN6 as sockaddr_in6, SOCKADDR_STORAGE as sockaddr_storage, WSAEACCES as EACCES, + WSAEADDRINUSE as EADDRINUSE, WSAEADDRNOTAVAIL as EADDRNOTAVAIL, + WSAEAFNOSUPPORT as EAFNOSUPPORT, WSAEALREADY as EALREADY, WSAEBADF as EBADF, + WSAECONNABORTED as ECONNABORTED, WSAECONNREFUSED as ECONNREFUSED, WSAECONNRESET as ECONNRESET, + WSAEDESTADDRREQ as EDESTADDRREQ, WSAEDISCON as EDISCON, WSAEDQUOT as EDQUOT, + WSAEFAULT as EFAULT, WSAEHOSTDOWN as EHOSTDOWN, WSAEHOSTUNREACH as EHOSTUNREACH, + WSAEINPROGRESS as EINPROGRESS, WSAEINTR as EINTR, WSAEINVAL as EINVAL, + WSAEINVALIDPROCTABLE as EINVALIDPROCTABLE, WSAEINVALIDPROVIDER as EINVALIDPROVIDER, + WSAEISCONN as EISCONN, WSAELOOP as ELOOP, WSAEMFILE as EMFILE, WSAEMSGSIZE as EMSGSIZE, + WSAENAMETOOLONG as ENAMETOOLONG, WSAENETDOWN as ENETDOWN, WSAENETRESET as ENETRESET, + WSAENETUNREACH as ENETUNREACH, WSAENOBUFS as ENOBUFS, WSAENOMORE as ENOMORE, + WSAENOPROTOOPT as ENOPROTOOPT, WSAENOTCONN as ENOTCONN, WSAENOTEMPTY as ENOTEMPTY, + WSAENOTSOCK as ENOTSOCK, WSAEOPNOTSUPP as EOPNOTSUPP, WSAEPFNOSUPPORT as EPFNOSUPPORT, + WSAEPROCLIM as EPROCLIM, WSAEPROTONOSUPPORT as EPROTONOSUPPORT, WSAEPROTOTYPE as EPROTOTYPE, + WSAEPROVIDERFAILEDINIT as EPROVIDERFAILEDINIT, WSAEREFUSED as EREFUSED, WSAEREMOTE as EREMOTE, + WSAESHUTDOWN as ESHUTDOWN, WSAESOCKTNOSUPPORT as ESOCKTNOSUPPORT, WSAESTALE as ESTALE, + WSAETIMEDOUT as ETIMEDOUT, WSAETOOMANYREFS as ETOOMANYREFS, WSAEUSERS as EUSERS, + WSAEWOULDBLOCK as EWOULDBLOCK, WSAEWOULDBLOCK as EAGAIN, WSAPOLLFD as pollfd, + WSA_E_CANCELLED as ECANCELED, *, +}; diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/arch/inline/aarch64.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/inline/aarch64.rs new file mode 100644 index 000000000..0f4465d51 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/inline/aarch64.rs @@ -0,0 +1,268 @@ +//! aarch64 Linux system calls. + +use crate::backend::reg::{ + ArgReg, FromAsm, RetReg, SyscallNumber, ToAsm, A0, A1, A2, A3, A4, A5, R0, +}; +use core::arch::asm; + +#[cfg(target_pointer_width = "32")] +compile_error!("arm64-ilp32 is not supported yet"); + +#[inline] +pub(in crate::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", + in("x8") nr.to_asm(), + in("x0") a0.to_asm(), + options(noreturn) + ) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall2( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, +) -> RetReg<R0> { + let r0; + asm!( + "svc 0", + in("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-0.37.22/src/backend/linux_raw/arch/inline/arm.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/inline/arm.rs new file mode 100644 index 000000000..9695c6028 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/inline/arm.rs @@ -0,0 +1,265 @@ +//! arm Linux system calls. + +use crate::backend::reg::{ + ArgReg, FromAsm, RetReg, SyscallNumber, ToAsm, A0, A1, A2, A3, A4, A5, R0, +}; +use core::arch::asm; + +#[inline] +pub(in crate::backend) unsafe fn syscall0_readonly(nr: SyscallNumber<'_>) -> RetReg<R0> { + let r0; + asm!( + "svc 0", + in("r7") nr.to_asm(), + lateout("r0") r0, + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> RetReg<R0> { + let r0; + asm!( + "svc 0", + in("r7") nr.to_asm(), + inlateout("r0") a0.to_asm() => r0, + options(nostack, preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall1_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, +) -> RetReg<R0> { + let r0; + asm!( + "svc 0", + in("r7") nr.to_asm(), + inlateout("r0") a0.to_asm() => r0, + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> ! { + asm!( + "svc 0", + in("r7") nr.to_asm(), + in("r0") a0.to_asm(), + options(noreturn) + ) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall2( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, +) -> RetReg<R0> { + let r0; + asm!( + "svc 0", + in("r7") nr.to_asm(), + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + options(nostack, preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall2_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, +) -> RetReg<R0> { + let r0; + asm!( + "svc 0", + in("r7") nr.to_asm(), + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall3( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, +) -> RetReg<R0> { + let r0; + asm!( + "svc 0", + in("r7") nr.to_asm(), + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + in("r2") a2.to_asm(), + options(nostack, preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall3_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, +) -> RetReg<R0> { + let r0; + asm!( + "svc 0", + in("r7") nr.to_asm(), + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + in("r2") a2.to_asm(), + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall4( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, +) -> RetReg<R0> { + let r0; + asm!( + "svc 0", + in("r7") nr.to_asm(), + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + in("r2") a2.to_asm(), + in("r3") a3.to_asm(), + options(nostack, preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall4_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, +) -> RetReg<R0> { + let r0; + asm!( + "svc 0", + in("r7") nr.to_asm(), + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + in("r2") a2.to_asm(), + in("r3") a3.to_asm(), + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall5( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, +) -> RetReg<R0> { + let r0; + asm!( + "svc 0", + in("r7") nr.to_asm(), + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + in("r2") a2.to_asm(), + in("r3") a3.to_asm(), + in("r4") a4.to_asm(), + options(nostack, preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall5_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, +) -> RetReg<R0> { + let r0; + asm!( + "svc 0", + in("r7") nr.to_asm(), + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + in("r2") a2.to_asm(), + in("r3") a3.to_asm(), + in("r4") a4.to_asm(), + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall6( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, + a5: ArgReg<'_, A5>, +) -> RetReg<R0> { + let r0; + asm!( + "svc 0", + in("r7") nr.to_asm(), + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + in("r2") a2.to_asm(), + in("r3") a3.to_asm(), + in("r4") a4.to_asm(), + in("r5") a5.to_asm(), + options(nostack, preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall6_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, + a5: ArgReg<'_, A5>, +) -> RetReg<R0> { + let r0; + asm!( + "svc 0", + in("r7") nr.to_asm(), + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + in("r2") a2.to_asm(), + in("r3") a3.to_asm(), + in("r4") a4.to_asm(), + in("r5") a5.to_asm(), + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/arch/inline/mips.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/inline/mips.rs new file mode 100644 index 000000000..b39a16847 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/inline/mips.rs @@ -0,0 +1,543 @@ +//! 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, 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", + in("$2" /*$v0*/) nr.to_asm(), + in("$4" /*$a0*/) a0.to_asm(), + options(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-0.37.22/src/backend/linux_raw/arch/inline/mips64.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/inline/mips64.rs new file mode 100644 index 000000000..d3c7d341f --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/inline/mips64.rs @@ -0,0 +1,466 @@ +//! 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, 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", + in("$2" /*$v0*/) nr.to_asm(), + in("$4" /*$a0*/) a0.to_asm(), + options(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-0.37.22/src/backend/linux_raw/arch/inline/mod.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/inline/mod.rs new file mode 100644 index 000000000..4783747ac --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/inline/mod.rs @@ -0,0 +1,22 @@ +//! Inline asm for making system calls. +//! +//! Compilers should really have intrinsics for making system calls. They're +//! much like regular calls, with custom calling conventions, and calling +//! conventions are otherwise the compiler's job. But for now, use inline asm. +//! +//! The calling conventions for Linux syscalls are [documented here]. +//! +//! [documented here]: https://man7.org/linux/man-pages/man2/syscall.2.html + +#[cfg_attr(target_arch = "aarch64", path = "aarch64.rs")] +#[cfg_attr(all(target_arch = "arm", not(thumb_mode)), path = "arm.rs")] +#[cfg_attr(all(target_arch = "arm", thumb_mode), path = "thumb.rs")] +#[cfg_attr(target_arch = "mips", path = "mips.rs")] +#[cfg_attr(target_arch = "mips64", path = "mips64.rs")] +#[cfg_attr(target_arch = "powerpc64", path = "powerpc64.rs")] +#[cfg_attr(target_arch = "riscv64", path = "riscv64.rs")] +#[cfg_attr(target_arch = "x86", path = "x86.rs")] +#[cfg_attr(target_arch = "x86_64", path = "x86_64.rs")] +mod target_arch; + +pub(in crate::backend) use self::target_arch::*; diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/arch/inline/powerpc64.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/inline/powerpc64.rs new file mode 100644 index 000000000..8cca7dca7 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/inline/powerpc64.rs @@ -0,0 +1,413 @@ +//! 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, 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", + in("r0") nr.to_asm(), + in("r3") a0.to_asm(), + options(noreturn) + ) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall2( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, +) -> RetReg<R0> { + let r0; + asm!( + "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-0.37.22/src/backend/linux_raw/arch/inline/riscv64.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/inline/riscv64.rs new file mode 100644 index 000000000..b1e306266 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/inline/riscv64.rs @@ -0,0 +1,265 @@ +//! riscv64 Linux system calls. + +use crate::backend::reg::{ + ArgReg, FromAsm, RetReg, SyscallNumber, ToAsm, A0, A1, A2, A3, A4, A5, R0, +}; +use core::arch::asm; + +#[inline] +pub(in crate::backend) unsafe fn syscall0_readonly(nr: SyscallNumber<'_>) -> RetReg<R0> { + let r0; + asm!( + "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", + in("a7") nr.to_asm(), + in("a0") a0.to_asm(), + options(noreturn) + ); +} + +#[inline] +pub(in crate::backend) unsafe fn syscall2( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, +) -> RetReg<R0> { + let r0; + asm!( + "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-0.37.22/src/backend/linux_raw/arch/inline/thumb.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/inline/thumb.rs new file mode 100644 index 000000000..398a73dfe --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/inline/thumb.rs @@ -0,0 +1,322 @@ +//! arm Linux system calls, using thumb-mode. +//! +//! In thumb-mode, r7 is the frame pointer and is not permitted to be used in +//! an inline asm operand, so we have to use a different register and copy it +//! into r7 inside the inline asm. + +use crate::backend::reg::{ + ArgReg, FromAsm, RetReg, SyscallNumber, ToAsm, A0, A1, A2, A3, A4, A5, R0, +}; +use core::arch::asm; + +#[inline] +pub(in crate::backend) unsafe fn syscall0_readonly(nr: SyscallNumber<'_>) -> RetReg<R0> { + let r0; + asm!( + "mov {tmp}, r7", + "mov r7, {nr}", + "svc 0", + "mov r7, {tmp}", + nr = in(reg) nr.to_asm(), + tmp = out(reg) _, + lateout("r0") r0, + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> RetReg<R0> { + let r0; + asm!( + "mov {tmp}, r7", + "mov r7, {nr}", + "svc 0", + "mov r7, {tmp}", + nr = in(reg) nr.to_asm(), + tmp = out(reg) _, + inlateout("r0") a0.to_asm() => r0, + options(nostack, preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall1_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, +) -> RetReg<R0> { + let r0; + asm!( + "mov {tmp}, r7", + "mov r7, {nr}", + "svc 0", + "mov r7, {tmp}", + nr = in(reg) nr.to_asm(), + tmp = out(reg) _, + inlateout("r0") a0.to_asm() => r0, + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> ! { + asm!( + "mov r7, {nr}", + "svc 0", + nr = in(reg) nr.to_asm(), + in("r0") a0.to_asm(), + options(noreturn) + ) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall2( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, +) -> RetReg<R0> { + let r0; + asm!( + "mov {tmp}, r7", + "mov r7, {nr}", + "svc 0", + "mov r7, {tmp}", + nr = in(reg) nr.to_asm(), + tmp = out(reg) _, + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + options(nostack, preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall2_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, +) -> RetReg<R0> { + let r0; + asm!( + "mov {tmp}, r7", + "mov r7, {nr}", + "svc 0", + "mov r7, {tmp}", + nr = in(reg) nr.to_asm(), + tmp = out(reg) _, + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall3( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, +) -> RetReg<R0> { + let r0; + asm!( + "mov {tmp}, r7", + "mov r7, {nr}", + "svc 0", + "mov r7, {tmp}", + nr = in(reg) nr.to_asm(), + tmp = out(reg) _, + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + in("r2") a2.to_asm(), + options(nostack, preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall3_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, +) -> RetReg<R0> { + let r0; + asm!( + "mov {tmp}, r7", + "mov r7, {nr}", + "svc 0", + "mov r7, {tmp}", + nr = in(reg) nr.to_asm(), + tmp = out(reg) _, + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + in("r2") a2.to_asm(), + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall4( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, +) -> RetReg<R0> { + let r0; + asm!( + "mov {tmp}, r7", + "mov r7, {nr}", + "svc 0", + "mov r7, {tmp}", + nr = in(reg) nr.to_asm(), + tmp = out(reg) _, + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + in("r2") a2.to_asm(), + in("r3") a3.to_asm(), + options(nostack, preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall4_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, +) -> RetReg<R0> { + let r0; + asm!( + "mov {tmp}, r7", + "mov r7, {nr}", + "svc 0", + "mov r7, {tmp}", + nr = in(reg) nr.to_asm(), + tmp = out(reg) _, + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + in("r2") a2.to_asm(), + in("r3") a3.to_asm(), + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall5( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, +) -> RetReg<R0> { + let r0; + asm!( + "mov {tmp}, r7", + "mov r7, {nr}", + "svc 0", + "mov r7, {tmp}", + nr = in(reg) nr.to_asm(), + tmp = out(reg) _, + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + in("r2") a2.to_asm(), + in("r3") a3.to_asm(), + in("r4") a4.to_asm(), + options(nostack, preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall5_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, +) -> RetReg<R0> { + let r0; + asm!( + "mov {tmp}, r7", + "mov r7, {nr}", + "svc 0", + "mov r7, {tmp}", + nr = in(reg) nr.to_asm(), + tmp = out(reg) _, + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + in("r2") a2.to_asm(), + in("r3") a3.to_asm(), + in("r4") a4.to_asm(), + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall6( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, + a5: ArgReg<'_, A5>, +) -> RetReg<R0> { + let r0; + asm!( + "mov {tmp}, r7", + "mov r7, {nr}", + "svc 0", + "mov r7, {tmp}", + nr = in(reg) nr.to_asm(), + tmp = out(reg) _, + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + in("r2") a2.to_asm(), + in("r3") a3.to_asm(), + in("r4") a4.to_asm(), + in("r5") a5.to_asm(), + options(nostack, preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall6_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, + a5: ArgReg<'_, A5>, +) -> RetReg<R0> { + let r0; + asm!( + "mov {tmp}, r7", + "mov r7, {nr}", + "svc 0", + "mov r7, {tmp}", + nr = in(reg) nr.to_asm(), + tmp = out(reg) _, + inlateout("r0") a0.to_asm() => r0, + in("r1") a1.to_asm(), + in("r2") a2.to_asm(), + in("r3") a3.to_asm(), + in("r4") a4.to_asm(), + in("r5") a5.to_asm(), + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/arch/inline/x86.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/inline/x86.rs new file mode 100644 index 000000000..62947cb04 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/inline/x86.rs @@ -0,0 +1,494 @@ +//! 32-bit x86 Linux system calls. +//! +//! There are two forms; `indirect_*` which take a callee, which allow calling +//! through the vDSO when possible, and plain forms, which use the `int 0x80` +//! instruction. +//! +//! Most `rustix` syscalls use the vsyscall mechanism rather than going using +//! `int 0x80` sequences. + +#![allow(dead_code)] + +use crate::backend::reg::{ + ArgReg, FromAsm, RetReg, SyscallNumber, ToAsm, A0, A1, A2, A3, A4, A5, R0, +}; +use crate::backend::vdso_wrappers::SyscallType; +use core::arch::asm; + +#[inline] +pub(in crate::backend) unsafe fn indirect_syscall0( + callee: SyscallType, + nr: SyscallNumber<'_>, +) -> RetReg<R0> { + let r0; + asm!( + "call {callee}", + callee = in(reg) callee, + inlateout("eax") nr.to_asm() => r0, + options(preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn indirect_syscall1( + callee: SyscallType, + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, +) -> RetReg<R0> { + let r0; + asm!( + "call {callee}", + callee = in(reg) callee, + inlateout("eax") nr.to_asm() => r0, + in("ebx") a0.to_asm(), + options(preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn indirect_syscall1_noreturn( + callee: SyscallType, + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, +) -> ! { + asm!( + "call {callee}", + callee = in(reg) callee, + in("eax") nr.to_asm(), + in("ebx") a0.to_asm(), + options(noreturn) + ) +} + +#[inline] +pub(in crate::backend) unsafe fn indirect_syscall2( + callee: SyscallType, + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, +) -> RetReg<R0> { + let r0; + asm!( + "call {callee}", + callee = in(reg) callee, + inlateout("eax") nr.to_asm() => r0, + in("ebx") a0.to_asm(), + in("ecx") a1.to_asm(), + options(preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn indirect_syscall3( + callee: SyscallType, + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, +) -> RetReg<R0> { + let r0; + asm!( + "call {callee}", + callee = in(reg) callee, + inlateout("eax") nr.to_asm() => r0, + in("ebx") a0.to_asm(), + in("ecx") a1.to_asm(), + in("edx") a2.to_asm(), + options(preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn indirect_syscall4( + callee: SyscallType, + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, +) -> RetReg<R0> { + let r0; + // a3 should go in esi, but `asm!` won't let us use it as an operand. + // Temporarily swap it into place, and then swap it back afterward. + // + // We hard-code the callee operand to use edi instead of `in(reg)` because + // even though we can't name esi as an operand, the compiler can use esi to + // satisfy `in(reg)`. + asm!( + "xchg esi, {a3}", + "call edi", + "xchg esi, {a3}", + a3 = in(reg) a3.to_asm(), + in("edi") callee, + inlateout("eax") nr.to_asm() => r0, + in("ebx") a0.to_asm(), + in("ecx") a1.to_asm(), + in("edx") a2.to_asm(), + options(preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn indirect_syscall5( + callee: SyscallType, + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, +) -> RetReg<R0> { + let r0; + // Oof. a3 should go in esi, and `asm!` won't let us use that register as + // an operand. And we can't request stack slots. And there are no other + // registers free. Use eax as a temporary pointer to a slice, since it + // gets clobbered as the return value anyway. + asm!( + "push esi", + "push DWORD PTR [eax + 0]", + "mov esi, DWORD PTR [eax + 4]", + "mov eax, DWORD PTR [eax + 8]", + "call DWORD PTR [esp]", + "pop esi", + "pop esi", + inout("eax") &[callee as _, a3.to_asm(), nr.to_asm()] => r0, + in("ebx") a0.to_asm(), + in("ecx") a1.to_asm(), + in("edx") a2.to_asm(), + in("edi") a4.to_asm(), + options(preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[allow(clippy::too_many_arguments)] +#[inline] +pub(in crate::backend) unsafe fn indirect_syscall6( + callee: SyscallType, + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, + a5: ArgReg<'_, A5>, +) -> RetReg<R0> { + let r0; + // Oof again. a3 should go in esi, and a5 should go in ebp, and `asm!` + // won't let us use either of those registers as operands. And we can't + // request stack slots. And there are no other registers free. Use eax as a + // temporary pointer to a slice, since it gets clobbered as the return + // value anyway. + // + // This is another reason that syscalls should be compiler intrinsics + // rather than inline asm. + asm!( + "push ebp", + "push esi", + "push DWORD PTR [eax + 0]", + "mov esi, DWORD PTR [eax + 4]", + "mov ebp, DWORD PTR [eax + 8]", + "mov eax, DWORD PTR [eax + 12]", + "call DWORD PTR [esp]", + "pop esi", + "pop esi", + "pop ebp", + inout("eax") &[callee as _, a3.to_asm(), a5.to_asm(), nr.to_asm()] => r0, + in("ebx") a0.to_asm(), + in("ecx") a1.to_asm(), + in("edx") a2.to_asm(), + in("edi") a4.to_asm(), + options(preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall0_readonly(nr: SyscallNumber<'_>) -> RetReg<R0> { + let r0; + asm!( + "int $$0x80", + inlateout("eax") nr.to_asm() => r0, + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> RetReg<R0> { + let r0; + asm!( + "int $$0x80", + inlateout("eax") nr.to_asm() => r0, + in("ebx") a0.to_asm(), + options(nostack, preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall1_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, +) -> RetReg<R0> { + let r0; + asm!( + "int $$0x80", + inlateout("eax") nr.to_asm() => r0, + in("ebx") a0.to_asm(), + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> ! { + asm!( + "int $$0x80", + in("eax") nr.to_asm(), + in("ebx") a0.to_asm(), + options(noreturn) + ) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall2( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, +) -> RetReg<R0> { + let r0; + asm!( + "int $$0x80", + inlateout("eax") nr.to_asm() => r0, + in("ebx") a0.to_asm(), + in("ecx") a1.to_asm(), + options(nostack, preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall2_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, +) -> RetReg<R0> { + let r0; + asm!( + "int $$0x80", + inlateout("eax") nr.to_asm() => r0, + in("ebx") a0.to_asm(), + in("ecx") a1.to_asm(), + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall3( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, +) -> RetReg<R0> { + let r0; + asm!( + "int $$0x80", + inlateout("eax") nr.to_asm() => r0, + in("ebx") a0.to_asm(), + in("ecx") a1.to_asm(), + in("edx") a2.to_asm(), + options(nostack, preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall3_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, +) -> RetReg<R0> { + let r0; + asm!( + "int $$0x80", + inlateout("eax") nr.to_asm() => r0, + in("ebx") a0.to_asm(), + in("ecx") a1.to_asm(), + in("edx") a2.to_asm(), + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall4( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, +) -> RetReg<R0> { + let r0; + // a3 should go in esi, but `asm!` won't let us use it as an operand. + // Temporarily swap it into place, and then swap it back afterward. + asm!( + "xchg esi, {a3}", + "int $$0x80", + "xchg esi, {a3}", + a3 = in(reg) a3.to_asm(), + inlateout("eax") nr.to_asm() => r0, + in("ebx") a0.to_asm(), + in("ecx") a1.to_asm(), + in("edx") a2.to_asm(), + options(nostack, preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall4_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, +) -> RetReg<R0> { + let r0; + asm!( + "xchg esi, {a3}", + "int $$0x80", + "xchg esi, {a3}", + a3 = in(reg) a3.to_asm(), + inlateout("eax") nr.to_asm() => r0, + in("ebx") a0.to_asm(), + in("ecx") a1.to_asm(), + in("edx") a2.to_asm(), + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall5( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, +) -> RetReg<R0> { + let r0; + // As in `syscall4`, use xchg to handle a3. a4 should go in edi, and we can + // use that register as an operand. Unlike in `indirect_syscall5`, we don't + // have a `callee` operand taking up a register, so we have enough + // registers and don't need to use a slice. + asm!( + "xchg esi, {a3}", + "int $$0x80", + "xchg esi, {a3}", + a3 = in(reg) a3.to_asm(), + inlateout("eax") nr.to_asm() => r0, + in("ebx") a0.to_asm(), + in("ecx") a1.to_asm(), + in("edx") a2.to_asm(), + in("edi") a4.to_asm(), + options(nostack, preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall5_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, +) -> RetReg<R0> { + let r0; + // See the comments in `syscall5`. + asm!( + "xchg esi, {a3}", + "int $$0x80", + "xchg esi, {a3}", + a3 = in(reg) a3.to_asm(), + inlateout("eax") nr.to_asm() => r0, + in("ebx") a0.to_asm(), + in("ecx") a1.to_asm(), + in("edx") a2.to_asm(), + in("edi") a4.to_asm(), + options(nostack, preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall6( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, + a5: ArgReg<'_, A5>, +) -> RetReg<R0> { + let r0; + // See the comments in `indirect_syscall6`. + asm!( + "push ebp", + "push esi", + "mov esi, DWORD PTR [eax + 0]", + "mov ebp, DWORD PTR [eax + 4]", + "mov eax, DWORD PTR [eax + 8]", + "int $$0x80", + "pop esi", + "pop ebp", + inout("eax") &[a3.to_asm(), a5.to_asm(), nr.to_asm()] => r0, + in("ebx") a0.to_asm(), + in("ecx") a1.to_asm(), + in("edx") a2.to_asm(), + in("edi") a4.to_asm(), + options(preserves_flags) + ); + FromAsm::from_asm(r0) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall6_readonly( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, + a5: ArgReg<'_, A5>, +) -> RetReg<R0> { + let r0; + // See the comments in `indirect_syscall6`. + asm!( + "push ebp", + "push esi", + "mov esi, DWORD PTR [eax + 0]", + "mov ebp, DWORD PTR [eax + 4]", + "mov eax, DWORD PTR [eax + 8]", + "int $$0x80", + "pop esi", + "pop ebp", + inout("eax") &[a3.to_asm(), a5.to_asm(), nr.to_asm()] => r0, + in("ebx") a0.to_asm(), + in("ecx") a1.to_asm(), + in("edx") a2.to_asm(), + in("edi") a4.to_asm(), + options(preserves_flags, readonly) + ); + FromAsm::from_asm(r0) +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/arch/inline/x86_64.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/inline/x86_64.rs new file mode 100644 index 000000000..084f5fee4 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/inline/x86_64.rs @@ -0,0 +1,293 @@ +//! x86-64 Linux system calls. + +use crate::backend::reg::{ + ArgReg, FromAsm, RetReg, SyscallNumber, ToAsm, A0, A1, A2, A3, A4, A5, R0, +}; +use core::arch::asm; + +#[cfg(target_pointer_width = "32")] +compile_error!("x32 is not yet supported"); + +#[inline] +pub(in crate::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", + in("rax") nr.to_asm(), + in("rdi") a0.to_asm(), + options(noreturn) + ) +} + +#[inline] +pub(in crate::backend) unsafe fn syscall2( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, +) -> RetReg<R0> { + let r0; + asm!( + "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-0.37.22/src/backend/linux_raw/arch/mod.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/mod.rs new file mode 100644 index 000000000..678623fcd --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/mod.rs @@ -0,0 +1,225 @@ +//! Architecture-specific syscall code. +//! +//! `rustix` has inline assembly sequences using `asm!`, but that requires +//! Rust 1.59, so it also has out-of-line ("outline") assembly sequences in .s +//! files. And 32-bit x86 is special (see comments below). +//! +//! This module also has a `choose` submodule which chooses a scheme and is +//! what most of the `rustix` syscalls use. +//! +//! # Safety +//! +//! This contains the inline `asm` statements performing the syscall +//! instructions and FFI declarations declaring the out-of-line ("outline") +//! syscall instructions. + +#![allow(unsafe_code)] +#![cfg_attr(not(feature = "all-apis"), allow(unused_imports))] +// We'll use as many arguments as syscalls need. +#![allow(clippy::too_many_arguments)] + +// When inline asm is available, use it. Otherwise, use out-of-line asm. These +// functions always use the machine's syscall instruction, even when it isn't +// the fastest option available. +#[cfg_attr(asm, path = "inline/mod.rs")] +#[cfg_attr(not(asm), path = "outline/mod.rs")] +pub(in crate::backend) mod asm; + +// On most architectures, the architecture syscall instruction is fast, so use +// it directly. +#[cfg(any( + target_arch = "arm", + target_arch = "aarch64", + target_arch = "mips", + target_arch = "mips64", + target_arch = "powerpc64", + target_arch = "riscv64", + target_arch = "x86_64", +))] +pub(in crate::backend) use self::asm as choose; + +// On 32-bit x86, use vDSO wrappers for all syscalls. We could use the +// architecture syscall instruction (`int 0x80`), but the vDSO kernel_vsyscall +// mechanism is much faster. +#[cfg(target_arch = "x86")] +pub(in crate::backend) use super::vdso_wrappers::x86_via_vdso as choose; + +// This would be the code for always using `int 0x80` on 32-bit x86. +//#[cfg(target_arch = "x86")] +//pub(in crate::backend) use self::asm as choose; + +// Macros for invoking system calls. +// +// These factor out: +// - Calling `nr` on the syscall number to convert it into `SyscallNumber`. +// - Calling `.into()` on each of the arguments to convert them into `ArgReg`. +// - Qualifying the `syscall*` and `__NR_*` identifiers. +// - Counting the number of arguments. +macro_rules! syscall { + ($nr:ident) => { + $crate::backend::arch::choose::syscall0($crate::backend::reg::nr( + linux_raw_sys::general::$nr, + )) + }; + + ($nr:ident, $a0:expr) => { + $crate::backend::arch::choose::syscall1( + $crate::backend::reg::nr(linux_raw_sys::general::$nr), + $a0.into(), + ) + }; + + ($nr:ident, $a0:expr, $a1:expr) => { + $crate::backend::arch::choose::syscall2( + $crate::backend::reg::nr(linux_raw_sys::general::$nr), + $a0.into(), + $a1.into(), + ) + }; + + ($nr:ident, $a0:expr, $a1:expr, $a2:expr) => { + $crate::backend::arch::choose::syscall3( + $crate::backend::reg::nr(linux_raw_sys::general::$nr), + $a0.into(), + $a1.into(), + $a2.into(), + ) + }; + + ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr) => { + $crate::backend::arch::choose::syscall4( + $crate::backend::reg::nr(linux_raw_sys::general::$nr), + $a0.into(), + $a1.into(), + $a2.into(), + $a3.into(), + ) + }; + + ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr) => { + $crate::backend::arch::choose::syscall5( + $crate::backend::reg::nr(linux_raw_sys::general::$nr), + $a0.into(), + $a1.into(), + $a2.into(), + $a3.into(), + $a4.into(), + ) + }; + + ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr) => { + $crate::backend::arch::choose::syscall6( + $crate::backend::reg::nr(linux_raw_sys::general::$nr), + $a0.into(), + $a1.into(), + $a2.into(), + $a3.into(), + $a4.into(), + $a5.into(), + ) + }; + + ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr, $a6:expr) => { + $crate::backend::arch::choose::syscall7( + $crate::backend::reg::nr(linux_raw_sys::general::$nr), + $a0.into(), + $a1.into(), + $a2.into(), + $a3.into(), + $a4.into(), + $a5.into(), + $a6.into(), + ) + }; +} + +/// 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-0.37.22/src/backend/linux_raw/arch/outline/aarch64.s b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/outline/aarch64.s new file mode 100644 index 000000000..1fad2fa6d --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/outline/aarch64.s @@ -0,0 +1,119 @@ +// Assembly code for making aarch64 syscalls. +// +// aarch64 syscall argument register ordering is the same as the aarch64 +// userspace argument register ordering except that the syscall number +// (nr) is passed in w8. +// +// outline.rs takes care of reordering the nr argument to the end for us, +// so we only need to move nr into w8. +// +// arm64-ilp32 is not yet supported. + + .file "aarch64.s" + .arch armv8-a + + .section .text.rustix_syscall0_nr_last,"ax",@progbits + .p2align 2 + .weak rustix_syscall0_nr_last + .hidden rustix_syscall0_nr_last + .type rustix_syscall0_nr_last, @function +rustix_syscall0_nr_last: + .cfi_startproc + mov w8, w0 + svc #0 + ret + .cfi_endproc + .size rustix_syscall0_nr_last, .-rustix_syscall0_nr_last + + .section .text.rustix_syscall1_nr_last,"ax",@progbits + .p2align 2 + .weak rustix_syscall1_nr_last + .hidden rustix_syscall1_nr_last + .type rustix_syscall1_nr_last, @function +rustix_syscall1_nr_last: + .cfi_startproc + mov w8, w1 + svc #0 + ret + .cfi_endproc + .size rustix_syscall1_nr_last, .-rustix_syscall1_nr_last + + .section .text.rustix_syscall1_noreturn_nr_last,"ax",@progbits + .p2align 2 + .weak rustix_syscall1_noreturn_nr_last + .hidden rustix_syscall1_noreturn_nr_last + .type rustix_syscall1_noreturn_nr_last, @function +rustix_syscall1_noreturn_nr_last: + .cfi_startproc + mov w8, w1 + svc #0 + brk #0x1 + .cfi_endproc + .size rustix_syscall1_noreturn_nr_last, .-rustix_syscall1_noreturn_nr_last + + .section .text.rustix_syscall2_nr_last,"ax",@progbits + .p2align 2 + .weak rustix_syscall2_nr_last + .hidden rustix_syscall2_nr_last + .type rustix_syscall2_nr_last, @function +rustix_syscall2_nr_last: + .cfi_startproc + mov w8, w2 + svc #0 + ret + .cfi_endproc + .size rustix_syscall2_nr_last, .-rustix_syscall2_nr_last + + .section .text.rustix_syscall3_nr_last,"ax",@progbits + .p2align 2 + .weak rustix_syscall3_nr_last + .hidden rustix_syscall3_nr_last + .type rustix_syscall3_nr_last, @function +rustix_syscall3_nr_last: + .cfi_startproc + mov w8, w3 + svc #0 + ret + .cfi_endproc + .size rustix_syscall3_nr_last, .-rustix_syscall3_nr_last + + .section .text.rustix_syscall4_nr_last,"ax",@progbits + .p2align 2 + .weak rustix_syscall4_nr_last + .hidden rustix_syscall4_nr_last + .type rustix_syscall4_nr_last, @function +rustix_syscall4_nr_last: + .cfi_startproc + mov w8, w4 + svc #0 + ret + .cfi_endproc + .size rustix_syscall4_nr_last, .-rustix_syscall4_nr_last + + .section .text.rustix_syscall5_nr_last,"ax",@progbits + .p2align 2 + .weak rustix_syscall5_nr_last + .hidden rustix_syscall5_nr_last + .type rustix_syscall5_nr_last, @function +rustix_syscall5_nr_last: + .cfi_startproc + mov w8, w5 + svc #0 + ret + .cfi_endproc + .size rustix_syscall5_nr_last, .-rustix_syscall5_nr_last + + .section .text.rustix_syscall6_nr_last,"ax",@progbits + .p2align 2 + .weak rustix_syscall6_nr_last + .hidden rustix_syscall6_nr_last + .type rustix_syscall6_nr_last, @function +rustix_syscall6_nr_last: + .cfi_startproc + mov w8, w6 + svc #0 + ret + .cfi_endproc + .size rustix_syscall6_nr_last, .-rustix_syscall6_nr_last + + .section .note.GNU-stack,"",@progbits diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/arch/outline/arm.s b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/outline/arm.s new file mode 100644 index 000000000..7001686f1 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/outline/arm.s @@ -0,0 +1,135 @@ +// Assembly code for making arm syscalls. +// +// arm syscall argument register ordering is the similar to the arm +// userspace argument register ordering except that the syscall number +// (nr) is passed in r7. +// +// nr_last.rs takes care of reordering the nr argument to the end for us, +// so we only need to move nr into r7 and take care of r4 and r5 if needed. + + .file "arm.s" + .arch armv5t + + .section .text.rustix_syscall0_nr_last,"ax",%progbits + .p2align 4 + .weak rustix_syscall0_nr_last + .hidden rustix_syscall0_nr_last + .type rustix_syscall0_nr_last, %function +rustix_syscall0_nr_last: + .fnstart + .cantunwind + push {r7, lr} + mov r7, r0 + svc #0 + pop {r7, pc} + .fnend + .size rustix_syscall0_nr_last, .-rustix_syscall0_nr_last + + .section .text.rustix_syscall1_nr_last,"ax",%progbits + .p2align 4 + .weak rustix_syscall1_nr_last + .hidden rustix_syscall1_nr_last + .type rustix_syscall1_nr_last, %function +rustix_syscall1_nr_last: + .fnstart + .cantunwind + push {r7, lr} + mov r7, r1 + svc #0 + pop {r7, pc} + .fnend + .size rustix_syscall1_nr_last, .-rustix_syscall1_nr_last + + .section .text.rustix_syscall1_noreturn_nr_last,"ax",%progbits + .p2align 4 + .weak rustix_syscall1_noreturn_nr_last + .hidden rustix_syscall1_noreturn_nr_last + .type rustix_syscall1_noreturn_nr_last, %function +rustix_syscall1_noreturn_nr_last: + .fnstart + .cantunwind + // Don't save r7 and lr; this is noreturn, so we'll never restore them. + mov r7, r1 + svc #0 + udf #16 // Trap instruction + .fnend + .size rustix_syscall1_noreturn_nr_last, .-rustix_syscall1_noreturn_nr_last + + .section .text.rustix_syscall2_nr_last,"ax",%progbits + .p2align 4 + .weak rustix_syscall2_nr_last + .hidden rustix_syscall2_nr_last + .type rustix_syscall2_nr_last, %function +rustix_syscall2_nr_last: + .fnstart + .cantunwind + push {r7, lr} + mov r7, r2 + svc #0 + pop {r7, pc} + .fnend + .size rustix_syscall2_nr_last, .-rustix_syscall2_nr_last + + .section .text.rustix_syscall3_nr_last,"ax",%progbits + .p2align 4 + .weak rustix_syscall3_nr_last + .hidden rustix_syscall3_nr_last + .type rustix_syscall3_nr_last, %function +rustix_syscall3_nr_last: + .fnstart + .cantunwind + push {r7, lr} + mov r7, r3 + svc #0 + pop {r7, pc} + .fnend + .size rustix_syscall3_nr_last, .-rustix_syscall3_nr_last + + .section .text.rustix_syscall4_nr_last,"ax",%progbits + .p2align 4 + .weak rustix_syscall4_nr_last + .hidden rustix_syscall4_nr_last + .type rustix_syscall4_nr_last, %function +rustix_syscall4_nr_last: + .fnstart + .cantunwind + push {r7, lr} + ldr r7, [sp, #8] + svc #0 + pop {r7, pc} + .fnend + .size rustix_syscall4_nr_last, .-rustix_syscall4_nr_last + + .section .text.rustix_syscall5_nr_last,"ax",%progbits + .p2align 4 + .weak rustix_syscall5_nr_last + .hidden rustix_syscall5_nr_last + .type rustix_syscall5_nr_last, %function +rustix_syscall5_nr_last: + .fnstart + .cantunwind + push {r4, r7, r11, lr} + ldr r7, [sp, #20] + ldr r4, [sp, #16] + svc #0 + pop {r4, r7, r11, pc} + .fnend + .size rustix_syscall5_nr_last, .-rustix_syscall5_nr_last + + .section .text.rustix_syscall6_nr_last,"ax",%progbits + .p2align 4 + .weak rustix_syscall6_nr_last + .hidden rustix_syscall6_nr_last + .type rustix_syscall6_nr_last, %function +rustix_syscall6_nr_last: + .fnstart + .cantunwind + push {r4, r5, r7, lr} + add r7, sp, #16 + ldm r7, {r4, r5, r7} + svc #0 + pop {r4, r5, r7, pc} + .fnend + .size rustix_syscall6_nr_last, .-rustix_syscall6_nr_last + + .section .note.GNU-stack,"",%progbits diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/arch/outline/mips.s b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/outline/mips.s new file mode 100644 index 000000000..b016ae124 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/outline/mips.s @@ -0,0 +1,211 @@ +# Assembly code for making mips64 syscalls. +# +# mips64 syscall argument register ordering is the same as the mips64 +# userspace argument register ordering except that the syscall number +# (nr) is passed in v0. +# +# outline.rs takes care of reordering the nr argument to the end for us, +# so we only need to move nr into v0. + + .file "mips.s" + .section .mdebug.abi32 + .previous + .abicalls + + .section .text.rustix_syscall0_nr_last,"ax",@progbits + .p2align 2 + .weak rustix_syscall0_nr_last + .hidden rustix_syscall0_nr_last + .type rustix_syscall0_nr_last, @function + .set nomips16 + .set nomicromips + .ent rustix_syscall0_nr_last +rustix_syscall0_nr_last: + .frame $sp,0,$31 + .mask 0x00000000,0 + .fmask 0x00000000,0 + .set noreorder + .set nomacro + move $2, $4 + syscall + negu $8, $2 + jr $31 + movn $2, $8, $7 + .end rustix_syscall0_nr_last + .size rustix_syscall0_nr_last, .-rustix_syscall0_nr_last + + .section .text.rustix_syscall1_nr_last,"ax",@progbits + .p2align 2 + .weak rustix_syscall1_nr_last + .hidden rustix_syscall1_nr_last + .type rustix_syscall1_nr_last, @function + .set nomips16 + .set nomicromips + .ent rustix_syscall1_nr_last +rustix_syscall1_nr_last: + .frame $sp,0,$31 + .mask 0x00000000,0 + .fmask 0x00000000,0 + .set noreorder + .set nomacro + move $2, $5 + syscall + negu $8, $2 + jr $31 + movn $2, $8, $7 + .end rustix_syscall1_nr_last + .size rustix_syscall1_nr_last, .-rustix_syscall1_nr_last + + .section .text.rustix_syscall1_noreturn_nr_last,"ax",@progbits + .p2align 2 + .weak rustix_syscall1_noreturn_nr_last + .hidden rustix_syscall1_noreturn_nr_last + .type rustix_syscall1_noreturn_nr_last, @function + .set nomips16 + .set nomicromips + .ent rustix_syscall1_noreturn_nr_last +rustix_syscall1_noreturn_nr_last: + .frame $sp,0,$31 + .mask 0x00000000,0 + .fmask 0x00000000,0 + .set noreorder + .set nomacro + move $2, $5 + syscall + teq $zero, $zero + .end rustix_syscall1_noreturn_nr_last + .size rustix_syscall1_noreturn_nr_last, .-rustix_syscall1_noreturn_nr_last + + .section .text.rustix_syscall2_nr_last,"ax",@progbits + .p2align 2 + .weak rustix_syscall2_nr_last + .hidden rustix_syscall2_nr_last + .type rustix_syscall2_nr_last, @function + .set nomips16 + .set nomicromips + .ent rustix_syscall2_nr_last +rustix_syscall2_nr_last: + .frame $sp,0,$31 + .mask 0x00000000,0 + .fmask 0x00000000,0 + .set noreorder + .set nomacro + move $2, $6 + syscall + negu $8, $2 + jr $31 + movn $2, $8, $7 + .end rustix_syscall2_nr_last + .size rustix_syscall2_nr_last, .-rustix_syscall2_nr_last + + .section .text.rustix_syscall3_nr_last,"ax",@progbits + .p2align 2 + .weak rustix_syscall3_nr_last + .hidden rustix_syscall3_nr_last + .type rustix_syscall3_nr_last, @function + .set nomips16 + .set nomicromips + .ent rustix_syscall3_nr_last +rustix_syscall3_nr_last: + .frame $sp,0,$31 + .mask 0x00000000,0 + .fmask 0x00000000,0 + .set noreorder + .set nomacro + move $2, $7 + syscall + negu $8, $2 + jr $31 + movn $2, $8, $7 + .end rustix_syscall3_nr_last + .size rustix_syscall3_nr_last, .-rustix_syscall3_nr_last + + .section .text.rustix_syscall4_nr_last,"ax",@progbits + .p2align 2 + .weak rustix_syscall4_nr_last + .hidden rustix_syscall4_nr_last + .type rustix_syscall4_nr_last, @function + .set nomips16 + .set nomicromips + .ent rustix_syscall4_nr_last +rustix_syscall4_nr_last: + .frame $sp,0,$31 + .mask 0x00000000,0 + .fmask 0x00000000,0 + .set noreorder + .set nomacro + lw $2, 16($sp) + syscall + negu $8, $2 + jr $31 + movn $2, $8, $7 + .end rustix_syscall4_nr_last + .size rustix_syscall4_nr_last, .-rustix_syscall4_nr_last + + .section .text.rustix_syscall5_nr_last,"ax",@progbits + .p2align 2 + .weak rustix_syscall5_nr_last + .hidden rustix_syscall5_nr_last + .type rustix_syscall5_nr_last, @function + .set nomips16 + .set nomicromips + .ent rustix_syscall5_nr_last +rustix_syscall5_nr_last: + .frame $sp,0,$31 + .mask 0x00000000,0 + .fmask 0x00000000,0 + .set noreorder + .set nomacro + lw $2, 20($sp) + syscall + negu $8, $2 + jr $31 + movn $2, $8, $7 + .end rustix_syscall5_nr_last + .size rustix_syscall5_nr_last, .-rustix_syscall5_nr_last + + .section .text.rustix_syscall6_nr_last,"ax",@progbits + .p2align 2 + .weak rustix_syscall6_nr_last + .hidden rustix_syscall6_nr_last + .type rustix_syscall6_nr_last, @function + .set nomips16 + .set nomicromips + .ent rustix_syscall6_nr_last +rustix_syscall6_nr_last: + .frame $sp,0,$31 + .mask 0x00000000,0 + .fmask 0x00000000,0 + .set noreorder + .set nomacro + lw $2, 24($sp) + syscall + negu $8, $2 + jr $31 + movn $2, $8, $7 + .end rustix_syscall6_nr_last + .size rustix_syscall6_nr_last, .-rustix_syscall6_nr_last + + .section .text.rustix_syscall7_nr_last,"ax",@progbits + .p2align 2 + .weak rustix_syscall7_nr_last + .hidden rustix_syscall7_nr_last + .type rustix_syscall7_nr_last, @function + .set nomips16 + .set nomicromips + .ent rustix_syscall7_nr_last +rustix_syscall7_nr_last: + .frame $sp,0,$31 + .mask 0x00000000,0 + .fmask 0x00000000,0 + .set noreorder + .set nomacro + lw $2, 28($sp) + syscall + negu $8, $2 + jr $31 + movn $2, $8, $7 + .end rustix_syscall7_nr_last + .size rustix_syscall7_nr_last, .-rustix_syscall7_nr_last + + .section .note.GNU-stack,"",@progbits diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/arch/outline/mips64.s b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/outline/mips64.s new file mode 100644 index 000000000..a6473990e --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/outline/mips64.s @@ -0,0 +1,189 @@ +# Assembly code for making mips64 syscalls. +# +# mips64 syscall argument register ordering is the same as the mips64 +# userspace argument register ordering except that the syscall number +# (nr) is passed in v0. +# +# outline.rs takes care of reordering the nr argument to the end for us, +# so we only need to move nr into v0. + + .file "mips64.s" + .section .mdebug.abi64 + .previous + .abicalls + + .section .text.rustix_syscall0_nr_last,"ax",@progbits + .p2align 2 + .weak rustix_syscall0_nr_last + .hidden rustix_syscall0_nr_last + .type rustix_syscall0_nr_last, @function + .set nomips16 + .set nomicromips + .ent rustix_syscall0_nr_last +rustix_syscall0_nr_last: + .frame $sp,0,$31 + .mask 0x00000000,0 + .fmask 0x00000000,0 + .set noreorder + .set nomacro + move $2, $4 + syscall + dnegu $12, $2 + jr $31 + movn $2, $12, $7 + .end rustix_syscall0_nr_last + .size rustix_syscall0_nr_last, .-rustix_syscall0_nr_last + + .section .text.rustix_syscall1_nr_last,"ax",@progbits + .p2align 2 + .weak rustix_syscall1_nr_last + .hidden rustix_syscall1_nr_last + .type rustix_syscall1_nr_last, @function + .set nomips16 + .set nomicromips + .ent rustix_syscall1_nr_last +rustix_syscall1_nr_last: + .frame $sp,0,$31 + .mask 0x00000000,0 + .fmask 0x00000000,0 + .set noreorder + .set nomacro + move $2, $5 + syscall + dnegu $12, $2 + jr $31 + movn $2, $12, $7 + .end rustix_syscall1_nr_last + .size rustix_syscall1_nr_last, .-rustix_syscall1_nr_last + + .section .text.rustix_syscall1_noreturn_nr_last,"ax",@progbits + .p2align 2 + .weak rustix_syscall1_noreturn_nr_last + .hidden rustix_syscall1_noreturn_nr_last + .type rustix_syscall1_noreturn_nr_last, @function + .set nomips16 + .set nomicromips + .ent rustix_syscall1_noreturn_nr_last +rustix_syscall1_noreturn_nr_last: + .frame $sp,0,$31 + .mask 0x00000000,0 + .fmask 0x00000000,0 + .set noreorder + .set nomacro + move $2, $5 + syscall + teq $0, $0 + .end rustix_syscall1_noreturn_nr_last + .size rustix_syscall1_noreturn_nr_last, .-rustix_syscall1_noreturn_nr_last + + .section .text.rustix_syscall2_nr_last,"ax",@progbits + .p2align 2 + .weak rustix_syscall2_nr_last + .hidden rustix_syscall2_nr_last + .type rustix_syscall2_nr_last, @function + .set nomips16 + .set nomicromips + .ent rustix_syscall2_nr_last +rustix_syscall2_nr_last: + .frame $sp,0,$31 + .mask 0x00000000,0 + .fmask 0x00000000,0 + .set noreorder + .set nomacro + move $2, $6 + syscall + dnegu $12, $2 + jr $31 + movn $2, $12, $7 + .end rustix_syscall2_nr_last + .size rustix_syscall2_nr_last, .-rustix_syscall2_nr_last + + .section .text.rustix_syscall3_nr_last,"ax",@progbits + .p2align 2 + .weak rustix_syscall3_nr_last + .hidden rustix_syscall3_nr_last + .type rustix_syscall3_nr_last, @function + .set nomips16 + .set nomicromips + .ent rustix_syscall3_nr_last +rustix_syscall3_nr_last: + .frame $sp,0,$31 + .mask 0x00000000,0 + .fmask 0x00000000,0 + .set noreorder + .set nomacro + move $2, $7 + syscall + dnegu $12, $2 + jr $31 + movn $2, $12, $7 + .end rustix_syscall3_nr_last + .size rustix_syscall3_nr_last, .-rustix_syscall3_nr_last + + .section .text.rustix_syscall4_nr_last,"ax",@progbits + .p2align 2 + .weak rustix_syscall4_nr_last + .hidden rustix_syscall4_nr_last + .type rustix_syscall4_nr_last, @function + .set nomips16 + .set nomicromips + .ent rustix_syscall4_nr_last +rustix_syscall4_nr_last: + .frame $sp,0,$31 + .mask 0x00000000,0 + .fmask 0x00000000,0 + .set noreorder + .set nomacro + move $2, $8 + syscall + dnegu $12, $2 + jr $31 + movn $2, $12, $7 + .end rustix_syscall4_nr_last + .size rustix_syscall4_nr_last, .-rustix_syscall4_nr_last + + .section .text.rustix_syscall5_nr_last,"ax",@progbits + .p2align 2 + .weak rustix_syscall5_nr_last + .hidden rustix_syscall5_nr_last + .type rustix_syscall5_nr_last, @function + .set nomips16 + .set nomicromips + .ent rustix_syscall5_nr_last +rustix_syscall5_nr_last: + .frame $sp,0,$31 + .mask 0x00000000,0 + .fmask 0x00000000,0 + .set noreorder + .set nomacro + move $2, $9 + syscall + dnegu $12, $2 + jr $31 + movn $2, $12, $7 + .end rustix_syscall5_nr_last + .size rustix_syscall5_nr_last, .-rustix_syscall5_nr_last + + .section .text.rustix_syscall6_nr_last,"ax",@progbits + .p2align 2 + .weak rustix_syscall6_nr_last + .hidden rustix_syscall6_nr_last + .type rustix_syscall6_nr_last, @function + .set nomips16 + .set nomicromips + .ent rustix_syscall6_nr_last +rustix_syscall6_nr_last: + .frame $sp,0,$31 + .mask 0x00000000,0 + .fmask 0x00000000,0 + .set noreorder + .set nomacro + move $2, $10 + syscall + dnegu $12, $2 + jr $31 + movn $2, $12, $7 + .end rustix_syscall6_nr_last + .size rustix_syscall6_nr_last, .-rustix_syscall6_nr_last + + .section .note.GNU-stack,"",@progbits diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/arch/outline/mod.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/outline/mod.rs new file mode 100644 index 000000000..5e6f5e1f5 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/outline/mod.rs @@ -0,0 +1,37 @@ +//! Declare functions defined in out-of-line ("outline") asm files. +//! +//! Kernel calling conventions differ from userspace calling conventions, so we +//! also define inline function wrappers which reorder the arguments so that +//! they match with the kernel convention as closely as possible, to minimize +//! the amount of out-of-line code we need. +//! +//! This is needed in order to support our MSRV of 1.48, which doesn't support +//! inline asm. When using newer Rust versions, inline asm code is used instead +//! and these outline libraries are unused. + +#[cfg(target_arch = "x86")] +mod x86; +// For these architectures, pass the `nr` argument last. +#[cfg(any( + target_arch = "arm", + target_arch = "aarch64", + target_arch = "mips", + target_arch = "mips64", + target_arch = "powerpc64", + target_arch = "riscv64", + target_arch = "x86_64", +))] +mod nr_last; + +#[cfg(any( + target_arch = "arm", + target_arch = "aarch64", + target_arch = "mips", + target_arch = "mips64", + target_arch = "powerpc64", + target_arch = "riscv64", + target_arch = "x86_64", +))] +pub(in crate::backend) use nr_last::*; +#[cfg(target_arch = "x86")] +pub(in crate::backend) use x86::*; diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/arch/outline/nr_last.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/outline/nr_last.rs new file mode 100644 index 000000000..4af64d6c4 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/outline/nr_last.rs @@ -0,0 +1,166 @@ +//! Syscall wrappers for platforms which pass the syscall number specially. +//! +//! Rustix aims to minimize the amount of assembly code it needs. To that end, +//! this code reorders syscall arguments as close as feasible to the actual +//! syscall convention before calling the assembly functions. +//! +//! Many architectures use a convention where the syscall number is passed in a +//! special register, with the regular syscall arguments passed in either the +//! same or similar registers as the platform C convention. This code +//! approximates that order by passing the regular syscall arguments first, and +//! the syscall number last. That way, the outline assembly code typically just +//! needs to move the syscall number to its special register, and leave the +//! other arguments mostly as they are. + +#[cfg(target_arch = "mips")] +use crate::backend::reg::A6; +use crate::backend::reg::{ArgReg, RetReg, SyscallNumber, A0, A1, A2, A3, A4, A5, R0}; + +// First we declare the actual assembly routines with `*_nr_last` names and +// reordered arguments. If the signatures or calling conventions are ever +// changed, the symbol names should also be updated accordingly, to avoid +// collisions with other versions of this crate. +// +// We don't define `_readonly` versions of these because we have no way to tell +// Rust that calls to our outline assembly are readonly. +extern "C" { + fn rustix_syscall0_nr_last(nr: SyscallNumber<'_>) -> RetReg<R0>; + fn rustix_syscall1_nr_last(a0: ArgReg<'_, A0>, nr: SyscallNumber<'_>) -> RetReg<R0>; + fn rustix_syscall1_noreturn_nr_last(a0: ArgReg<'_, A0>, nr: SyscallNumber<'_>) -> !; + fn rustix_syscall2_nr_last( + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + nr: SyscallNumber<'_>, + ) -> RetReg<R0>; + fn rustix_syscall3_nr_last( + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + nr: SyscallNumber<'_>, + ) -> RetReg<R0>; + fn rustix_syscall4_nr_last( + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + nr: SyscallNumber<'_>, + ) -> RetReg<R0>; + fn rustix_syscall5_nr_last( + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, + nr: SyscallNumber<'_>, + ) -> RetReg<R0>; + fn rustix_syscall6_nr_last( + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, + a5: ArgReg<'_, A5>, + nr: SyscallNumber<'_>, + ) -> RetReg<R0>; + #[cfg(target_arch = "mips")] + fn rustix_syscall7_nr_last( + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, + a5: ArgReg<'_, A5>, + a6: ArgReg<'_, A6>, + nr: SyscallNumber<'_>, + ) -> RetReg<R0>; +} + +// Then we define inline wrapper functions that do the reordering. + +#[inline] +pub(in crate::backend) unsafe fn syscall0(nr: SyscallNumber<'_>) -> RetReg<R0> { + rustix_syscall0_nr_last(nr) +} +#[inline] +pub(in crate::backend) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> RetReg<R0> { + rustix_syscall1_nr_last(a0, nr) +} +#[inline] +pub(in crate::backend) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> ! { + rustix_syscall1_noreturn_nr_last(a0, nr) +} +#[inline] +pub(in crate::backend) unsafe fn syscall2( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, +) -> RetReg<R0> { + rustix_syscall2_nr_last(a0, a1, nr) +} +#[inline] +pub(in crate::backend) unsafe fn syscall3( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, +) -> RetReg<R0> { + rustix_syscall3_nr_last(a0, a1, a2, nr) +} +#[inline] +pub(in crate::backend) unsafe fn syscall4( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, +) -> RetReg<R0> { + rustix_syscall4_nr_last(a0, a1, a2, a3, nr) +} +#[inline] +pub(in crate::backend) unsafe fn syscall5( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, +) -> RetReg<R0> { + rustix_syscall5_nr_last(a0, a1, a2, a3, a4, nr) +} +#[inline] +pub(in crate::backend) unsafe fn syscall6( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, + a5: ArgReg<'_, A5>, +) -> RetReg<R0> { + rustix_syscall6_nr_last(a0, a1, a2, a3, a4, a5, nr) +} +#[cfg(target_arch = "mips")] +#[inline] +pub(in crate::backend) unsafe fn syscall7( + 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> { + rustix_syscall7_nr_last(a0, a1, a2, a3, a4, a5, a6, nr) +} + +// Then we define the `_readonly` versions of the wrappers. We don't have +// separate `_readonly` implementations, so these can just be aliases to +// their non-`_readonly` counterparts. +#[cfg(target_arch = "mips")] +pub(in crate::backend) use syscall7 as syscall7_readonly; +pub(in crate::backend) use { + syscall0 as syscall0_readonly, syscall1 as syscall1_readonly, syscall2 as syscall2_readonly, + syscall3 as syscall3_readonly, syscall4 as syscall4_readonly, syscall5 as syscall5_readonly, + syscall6 as syscall6_readonly, +}; diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/arch/outline/powerpc64.s b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/outline/powerpc64.s new file mode 100644 index 000000000..29d4c0a95 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/outline/powerpc64.s @@ -0,0 +1,132 @@ +# Assembly code for making powerpc64le syscalls. +# +# powerpc64le syscall argument register ordering is the same as the +# powerpc64le userspace argument register ordering except that the syscall +# number (nr) is passed in r0. +# +# outline.rs takes care of reordering the nr argument to the end for us, +# so we only need to move nr into r0. + + .file "powerpc64le.s" + .machine power8 + .abiversion 2 + + .section .text.rustix_syscall0_nr_last,"ax",@progbits + .p2align 2 + .weak rustix_syscall0_nr_last + .hidden rustix_syscall0_nr_last + .type rustix_syscall0_nr_last, @function +rustix_syscall0_nr_last: + .cfi_startproc + mr 0, 3 + sc + bnslr + neg 3, 3 + blr + .cfi_endproc + .size rustix_syscall0_nr_last, .-rustix_syscall0_nr_last + + .section .text.rustix_syscall1_nr_last,"ax",@progbits + .p2align 2 + .weak rustix_syscall1_nr_last + .hidden rustix_syscall1_nr_last + .type rustix_syscall1_nr_last, @function +rustix_syscall1_nr_last: + .cfi_startproc + mr 0, 4 + sc + bnslr + neg 3, 3 + blr + .cfi_endproc + .size rustix_syscall1_nr_last, .-rustix_syscall1_nr_last + + .section .text.rustix_syscall1_noreturn_nr_last,"ax",@progbits + .p2align 2 + .weak rustix_syscall1_noreturn_nr_last + .hidden rustix_syscall1_noreturn_nr_last + .type rustix_syscall1_noreturn_nr_last, @function +rustix_syscall1_noreturn_nr_last: + .cfi_startproc + mr 0, 4 + sc + trap + .cfi_endproc + .size rustix_syscall1_noreturn_nr_last, .-rustix_syscall1_noreturn_nr_last + + .section .text.rustix_syscall2_nr_last,"ax",@progbits + .p2align 2 + .weak rustix_syscall2_nr_last + .hidden rustix_syscall2_nr_last + .type rustix_syscall2_nr_last, @function +rustix_syscall2_nr_last: + .cfi_startproc + mr 0, 5 + sc + bnslr + neg 3, 3 + blr + .cfi_endproc + .size rustix_syscall2_nr_last, .-rustix_syscall2_nr_last + + .section .text.rustix_syscall3_nr_last,"ax",@progbits + .p2align 2 + .weak rustix_syscall3_nr_last + .hidden rustix_syscall3_nr_last + .type rustix_syscall3_nr_last, @function +rustix_syscall3_nr_last: + .cfi_startproc + mr 0, 6 + sc + bnslr + neg 3, 3 + blr + .cfi_endproc + .size rustix_syscall3_nr_last, .-rustix_syscall3_nr_last + + .section .text.rustix_syscall4_nr_last,"ax",@progbits + .p2align 2 + .weak rustix_syscall4_nr_last + .hidden rustix_syscall4_nr_last + .type rustix_syscall4_nr_last, @function +rustix_syscall4_nr_last: + .cfi_startproc + mr 0, 7 + sc + bnslr + neg 3, 3 + blr + .cfi_endproc + .size rustix_syscall4_nr_last, .-rustix_syscall4_nr_last + + .section .text.rustix_syscall5_nr_last,"ax",@progbits + .p2align 2 + .weak rustix_syscall5_nr_last + .hidden rustix_syscall5_nr_last + .type rustix_syscall5_nr_last, @function +rustix_syscall5_nr_last: + .cfi_startproc + mr 0, 8 + sc + bnslr + neg 3, 3 + blr + .cfi_endproc + .size rustix_syscall5_nr_last, .-rustix_syscall5_nr_last + + .section .text.rustix_syscall6_nr_last,"ax",@progbits + .p2align 2 + .weak rustix_syscall6_nr_last + .hidden rustix_syscall6_nr_last + .type rustix_syscall6_nr_last, @function +rustix_syscall6_nr_last: + .cfi_startproc + mr 0, 9 + sc + bnslr + neg 3, 3 + blr + .cfi_endproc + .size rustix_syscall6_nr_last, .-rustix_syscall6_nr_last + + .section .note.GNU-stack,"",@progbits diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/arch/outline/riscv64.s b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/outline/riscv64.s new file mode 100644 index 000000000..28d692f7c --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/outline/riscv64.s @@ -0,0 +1,116 @@ +# Assembly code for making riscv64 syscalls. +# +# riscv64 syscall argument register ordering is the same as the riscv64 +# userspace argument register ordering except that the syscall number +# (nr) is passed in a7. +# +# nr_last.rs takes care of reordering the nr argument to the end for us, +# so we only need to move nr into a7. + + .file "riscv64.s" + + .section .text.rustix_syscall0_nr_last,"ax",@progbits + .p2align 4 + .weak rustix_syscall0_nr_last + .hidden rustix_syscall0_nr_last + .type rustix_syscall0_nr_last, @function +rustix_syscall0_nr_last: + .cfi_startproc + mv a7, a0 + ecall + ret + .cfi_endproc + .size rustix_syscall0_nr_last, .-rustix_syscall0_nr_last + + .section .text.rustix_syscall1_nr_last,"ax",@progbits + .p2align 4 + .weak rustix_syscall1_nr_last + .hidden rustix_syscall1_nr_last + .type rustix_syscall1_nr_last, @function +rustix_syscall1_nr_last: + .cfi_startproc + mv a7, a1 + ecall + ret + .cfi_endproc + .size rustix_syscall1_nr_last, .-rustix_syscall1_nr_last + + .section .text.rustix_syscall1_noreturn_nr_last,"ax",@progbits + .p2align 4 + .weak rustix_syscall1_noreturn_nr_last + .hidden rustix_syscall1_noreturn_nr_last + .type rustix_syscall1_noreturn_nr_last, @function +rustix_syscall1_noreturn_nr_last: + .cfi_startproc + mv a7, a1 + ecall + unimp + .cfi_endproc + .size rustix_syscall1_noreturn_nr_last, .-rustix_syscall1_noreturn_nr_last + + .section .text.rustix_syscall2_nr_last,"ax",@progbits + .p2align 4 + .weak rustix_syscall2_nr_last + .hidden rustix_syscall2_nr_last + .type rustix_syscall2_nr_last, @function +rustix_syscall2_nr_last: + .cfi_startproc + mv a7, a2 + ecall + ret + .cfi_endproc + .size rustix_syscall2_nr_last, .-rustix_syscall2_nr_last + + .section .text.rustix_syscall3_nr_last,"ax",@progbits + .p2align 4 + .weak rustix_syscall3_nr_last + .hidden rustix_syscall3_nr_last + .type rustix_syscall3_nr_last, @function +rustix_syscall3_nr_last: + .cfi_startproc + mv a7, a3 + ecall + ret + .cfi_endproc + .size rustix_syscall3_nr_last, .-rustix_syscall3_nr_last + + .section .text.rustix_syscall4_nr_last,"ax",@progbits + .p2align 4 + .weak rustix_syscall4_nr_last + .hidden rustix_syscall4_nr_last + .type rustix_syscall4_nr_last, @function +rustix_syscall4_nr_last: + .cfi_startproc + mv a7, a4 + ecall + ret + .cfi_endproc + .size rustix_syscall4_nr_last, .-rustix_syscall4_nr_last + + .section .text.rustix_syscall5_nr_last,"ax",@progbits + .p2align 4 + .weak rustix_syscall5_nr_last + .hidden rustix_syscall5_nr_last + .type rustix_syscall5_nr_last, @function +rustix_syscall5_nr_last: + .cfi_startproc + mv a7, a5 + ecall + ret + .cfi_endproc + .size rustix_syscall5_nr_last, .-rustix_syscall5_nr_last + + .section .text.rustix_syscall6_nr_last,"ax",@progbits + .p2align 4 + .weak rustix_syscall6_nr_last + .hidden rustix_syscall6_nr_last + .type rustix_syscall6_nr_last, @function +rustix_syscall6_nr_last: + .cfi_startproc + mv a7, a6 + ecall + ret + .cfi_endproc + .size rustix_syscall6_nr_last, .-rustix_syscall6_nr_last + + .section .note.GNU-stack,"",@progbits diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/arch/outline/x86.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/outline/x86.rs new file mode 100644 index 000000000..e74b8d2aa --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/outline/x86.rs @@ -0,0 +1,285 @@ +//! Syscall wrappers for 32-bit x86. +//! +//! This module is similar to the `nr_last` module, except specialized for +//! 32-bit x86. +//! +//! The syscall convention passes all arguments in registers. The closest we +//! can easily get to that from Rust is to use the fastcall convention which +//! passes the first two arguments in `ecx` and `edx`, which are the second +//! and third Linux syscall arguments. To line them up, this function passes +//! the second and third syscall argument as the first and second argument to +//! the outline assembly, followed by the first syscall argument, and then the +//! rest of the syscall arguments. The assembly code still has to do some work, +//! but at least we can get up to two arguments into the right place for it. + +#![allow(dead_code, unused_imports)] + +use crate::backend::reg::{ArgReg, RetReg, SyscallNumber, A0, A1, A2, A3, A4, A5, R0}; +use crate::backend::vdso_wrappers::SyscallType; + +// First we declare the actual assembly routines with `*_nr_last_fastcall` +// names and reordered arguments. If the signatures or calling conventions are +// ever changed, the symbol names should also be updated accordingly, to avoid +// collisions with other versions of this crate. +// +// We don't define `_readonly` versions of these because we have no way to tell +// Rust that calls to our outline assembly are readonly. +extern "fastcall" { + fn rustix_syscall0_nr_last_fastcall(nr: SyscallNumber<'_>) -> RetReg<R0>; + fn rustix_syscall1_nr_last_fastcall(a0: ArgReg<'_, A0>, nr: SyscallNumber<'_>) -> RetReg<R0>; + fn rustix_syscall1_noreturn_nr_last_fastcall(a0: ArgReg<'_, A0>, nr: SyscallNumber<'_>) -> !; + fn rustix_syscall2_nr_last_fastcall( + a1: ArgReg<'_, A1>, + a0: ArgReg<'_, A0>, + nr: SyscallNumber<'_>, + ) -> RetReg<R0>; + fn rustix_syscall3_nr_last_fastcall( + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a0: ArgReg<'_, A0>, + nr: SyscallNumber<'_>, + ) -> RetReg<R0>; + fn rustix_syscall4_nr_last_fastcall( + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a0: ArgReg<'_, A0>, + a3: ArgReg<'_, A3>, + nr: SyscallNumber<'_>, + ) -> RetReg<R0>; + fn rustix_syscall5_nr_last_fastcall( + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a0: ArgReg<'_, A0>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, + nr: SyscallNumber<'_>, + ) -> RetReg<R0>; + fn rustix_syscall6_nr_last_fastcall( + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a0: ArgReg<'_, A0>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, + a5: ArgReg<'_, A5>, + nr: SyscallNumber<'_>, + ) -> RetReg<R0>; +} + +// Then we define inline wrapper functions that do the reordering. + +#[inline] +pub(in crate::backend) unsafe fn syscall0(nr: SyscallNumber<'_>) -> RetReg<R0> { + rustix_syscall0_nr_last_fastcall(nr) +} +#[inline] +pub(in crate::backend) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> RetReg<R0> { + rustix_syscall1_nr_last_fastcall(a0, nr) +} +#[inline] +pub(in crate::backend) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> ! { + rustix_syscall1_noreturn_nr_last_fastcall(a0, nr) +} +#[inline] +pub(in crate::backend) unsafe fn syscall2( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, +) -> RetReg<R0> { + rustix_syscall2_nr_last_fastcall(a1, a0, nr) +} +#[inline] +pub(in crate::backend) unsafe fn syscall3( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, +) -> RetReg<R0> { + rustix_syscall3_nr_last_fastcall(a1, a2, a0, nr) +} +#[inline] +pub(in crate::backend) unsafe fn syscall4( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, +) -> RetReg<R0> { + rustix_syscall4_nr_last_fastcall(a1, a2, a0, a3, nr) +} +#[inline] +pub(in crate::backend) unsafe fn syscall5( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, +) -> RetReg<R0> { + rustix_syscall5_nr_last_fastcall(a1, a2, a0, a3, a4, nr) +} +#[inline] +pub(in crate::backend) unsafe fn syscall6( + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, + a5: ArgReg<'_, A5>, +) -> RetReg<R0> { + rustix_syscall6_nr_last_fastcall(a1, a2, a0, a3, a4, a5, nr) +} + +// Then we define the `_readonly` versions of the wrappers. We don't have +// separate `_readonly` implementations, so these can just be aliases to +// their non-`_readonly` counterparts. +pub(in crate::backend) use { + syscall0 as syscall0_readonly, syscall1 as syscall1_readonly, syscall2 as syscall2_readonly, + syscall3 as syscall3_readonly, syscall4 as syscall4_readonly, syscall5 as syscall5_readonly, + syscall6 as syscall6_readonly, +}; + +// x86 prefers to route all syscalls through the vDSO, though this isn't +// always possible, so it also has a special form for doing the dispatch. +// +// First we declare the actual assembly routines with `*_nr_last_fastcall` +// names and reordered arguments. If the signatures or calling conventions are +// ever changed, the symbol names should also be updated accordingly, to avoid +// collisions with other versions of this crate. +extern "fastcall" { + fn rustix_indirect_syscall0_nr_last_fastcall( + nr: SyscallNumber<'_>, + callee: SyscallType, + ) -> RetReg<R0>; + fn rustix_indirect_syscall1_nr_last_fastcall( + a0: ArgReg<'_, A0>, + nr: SyscallNumber<'_>, + callee: SyscallType, + ) -> RetReg<R0>; + fn rustix_indirect_syscall1_noreturn_nr_last_fastcall( + a0: ArgReg<'_, A0>, + nr: SyscallNumber<'_>, + callee: SyscallType, + ) -> !; + fn rustix_indirect_syscall2_nr_last_fastcall( + a1: ArgReg<'_, A1>, + a0: ArgReg<'_, A0>, + nr: SyscallNumber<'_>, + callee: SyscallType, + ) -> RetReg<R0>; + fn rustix_indirect_syscall3_nr_last_fastcall( + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a0: ArgReg<'_, A0>, + nr: SyscallNumber<'_>, + callee: SyscallType, + ) -> RetReg<R0>; + fn rustix_indirect_syscall4_nr_last_fastcall( + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a0: ArgReg<'_, A0>, + a3: ArgReg<'_, A3>, + nr: SyscallNumber<'_>, + callee: SyscallType, + ) -> RetReg<R0>; + fn rustix_indirect_syscall5_nr_last_fastcall( + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a0: ArgReg<'_, A0>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, + nr: SyscallNumber<'_>, + callee: SyscallType, + ) -> RetReg<R0>; + fn rustix_indirect_syscall6_nr_last_fastcall( + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a0: ArgReg<'_, A0>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, + a5: ArgReg<'_, A5>, + nr: SyscallNumber<'_>, + callee: SyscallType, + ) -> RetReg<R0>; +} + +// Then we define inline wrapper functions that do the reordering. + +#[inline] +pub(in crate::backend) unsafe fn indirect_syscall0( + callee: SyscallType, + nr: SyscallNumber<'_>, +) -> RetReg<R0> { + rustix_indirect_syscall0_nr_last_fastcall(nr, callee) +} +#[inline] +pub(in crate::backend) unsafe fn indirect_syscall1( + callee: SyscallType, + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, +) -> RetReg<R0> { + rustix_indirect_syscall1_nr_last_fastcall(a0, nr, callee) +} +#[inline] +pub(in crate::backend) unsafe fn indirect_syscall1_noreturn( + callee: SyscallType, + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, +) -> ! { + rustix_indirect_syscall1_noreturn_nr_last_fastcall(a0, nr, callee) +} +#[inline] +pub(in crate::backend) unsafe fn indirect_syscall2( + callee: SyscallType, + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, +) -> RetReg<R0> { + rustix_indirect_syscall2_nr_last_fastcall(a1, a0, nr, callee) +} +#[inline] +pub(in crate::backend) unsafe fn indirect_syscall3( + callee: SyscallType, + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, +) -> RetReg<R0> { + rustix_indirect_syscall3_nr_last_fastcall(a1, a2, a0, nr, callee) +} +#[inline] +pub(in crate::backend) unsafe fn indirect_syscall4( + callee: SyscallType, + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, +) -> RetReg<R0> { + rustix_indirect_syscall4_nr_last_fastcall(a1, a2, a0, a3, nr, callee) +} +#[inline] +pub(in crate::backend) unsafe fn indirect_syscall5( + callee: SyscallType, + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, +) -> RetReg<R0> { + rustix_indirect_syscall5_nr_last_fastcall(a1, a2, a0, a3, a4, nr, callee) +} +#[inline] +pub(in crate::backend) unsafe fn indirect_syscall6( + callee: SyscallType, + nr: SyscallNumber<'_>, + a0: ArgReg<'_, A0>, + a1: ArgReg<'_, A1>, + a2: ArgReg<'_, A2>, + a3: ArgReg<'_, A3>, + a4: ArgReg<'_, A4>, + a5: ArgReg<'_, A5>, +) -> RetReg<R0> { + rustix_indirect_syscall6_nr_last_fastcall(a1, a2, a0, a3, a4, a5, nr, callee) +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/arch/outline/x86.s b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/outline/x86.s new file mode 100644 index 000000000..bda234e1a --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/outline/x86.s @@ -0,0 +1,381 @@ +// Assembly code for making x86 syscalls. +// +// On x86 we use the "fastcall" convention which passes the first two +// arguments in ecx and edx. Outline.rs reorders the arguments to put +// a1 and a2 in those registers so they we don't have to move them to +// set up the kernel convention. +// +// "fastcall" expects callee to pop argument stack space, so we use +// `ret imm` instructions to clean up the stack. We don't need callee +// cleanup per se, it just comes along with using "fastcall". + + .file "x86.s" + .intel_syntax noprefix + + .section .text.rustix_indirect_syscall0_nr_last_fastcall,"ax",@progbits + .p2align 4 + .weak rustix_indirect_syscall0_nr_last_fastcall + .hidden rustix_indirect_syscall0_nr_last_fastcall + .type rustix_indirect_syscall0_nr_last_fastcall, @function +rustix_indirect_syscall0_nr_last_fastcall: + .cfi_startproc + mov eax,ecx + call edx + ret + .cfi_endproc + .size rustix_indirect_syscall0_nr_last_fastcall, .-rustix_indirect_syscall0_nr_last_fastcall + + .section .text.rustix_indirect_syscall1_nr_last_fastcall,"ax",@progbits + .p2align 4 + .weak rustix_indirect_syscall1_nr_last_fastcall + .hidden rustix_indirect_syscall1_nr_last_fastcall + .type rustix_indirect_syscall1_nr_last_fastcall, @function +rustix_indirect_syscall1_nr_last_fastcall: + .cfi_startproc + push ebx + .cfi_def_cfa_offset 8 + .cfi_offset ebx, -8 + mov ebx,ecx + mov eax,edx + call DWORD PTR [esp+0x8] + pop ebx + .cfi_def_cfa_offset 4 + ret 0x4 + .cfi_endproc + .size rustix_indirect_syscall1_nr_last_fastcall, .-rustix_indirect_syscall1_nr_last_fastcall + + .section .text.rustix_indirect_syscall1_noreturn_nr_last_fastcall,"ax",@progbits + .p2align 4 + .weak rustix_indirect_syscall1_noreturn_nr_last_fastcall + .hidden rustix_indirect_syscall1_noreturn_nr_last_fastcall + .type rustix_indirect_syscall1_noreturn_nr_last_fastcall, @function +rustix_indirect_syscall1_noreturn_nr_last_fastcall: + .cfi_startproc + mov ebx,ecx + mov eax,edx + call DWORD PTR [esp+0x4] + ud2 + .cfi_endproc + .size rustix_indirect_syscall1_noreturn_nr_last_fastcall, .-rustix_indirect_syscall1_noreturn_nr_last_fastcall + + .section .text.rustix_indirect_syscall2_nr_last_fastcall,"ax",@progbits + .p2align 4 + .weak rustix_indirect_syscall2_nr_last_fastcall + .hidden rustix_indirect_syscall2_nr_last_fastcall + .type rustix_indirect_syscall2_nr_last_fastcall, @function +rustix_indirect_syscall2_nr_last_fastcall: + .cfi_startproc + push ebx + .cfi_def_cfa_offset 8 + .cfi_offset ebx, -8 + mov ebx,edx + mov eax,DWORD PTR [esp+0x8] + call DWORD PTR [esp+0xc] + pop ebx + .cfi_def_cfa_offset 4 + ret 0x8 + .cfi_endproc + .size rustix_indirect_syscall2_nr_last_fastcall, .-rustix_indirect_syscall2_nr_last_fastcall + + .section .text.rustix_indirect_syscall3_nr_last_fastcall,"ax",@progbits + .p2align 4 + .weak rustix_indirect_syscall3_nr_last_fastcall + .hidden rustix_indirect_syscall3_nr_last_fastcall + .type rustix_indirect_syscall3_nr_last_fastcall, @function +rustix_indirect_syscall3_nr_last_fastcall: + .cfi_startproc + push ebx + .cfi_def_cfa_offset 8 + .cfi_offset ebx, -8 + mov ebx,DWORD PTR [esp+0x8] + mov eax,DWORD PTR [esp+0xc] + call DWORD PTR [esp+0x10] + pop ebx + .cfi_def_cfa_offset 4 + ret 0xc + .cfi_endproc + .size rustix_indirect_syscall3_nr_last_fastcall, .-rustix_indirect_syscall3_nr_last_fastcall + + .section .text.rustix_indirect_syscall4_nr_last_fastcall,"ax",@progbits + .p2align 4 + .weak rustix_indirect_syscall4_nr_last_fastcall + .hidden rustix_indirect_syscall4_nr_last_fastcall + .type rustix_indirect_syscall4_nr_last_fastcall, @function +rustix_indirect_syscall4_nr_last_fastcall: + .cfi_startproc + push ebx + .cfi_def_cfa_offset 8 + push esi + .cfi_def_cfa_offset 12 + .cfi_offset esi, -12 + .cfi_offset ebx, -8 + mov ebx,DWORD PTR [esp+0xc] + mov esi,DWORD PTR [esp+0x10] + mov eax,DWORD PTR [esp+0x14] + call DWORD PTR [esp+0x18] + pop esi + .cfi_def_cfa_offset 8 + pop ebx + .cfi_def_cfa_offset 4 + ret 0x10 + .cfi_endproc + .size rustix_indirect_syscall4_nr_last_fastcall, .-rustix_indirect_syscall4_nr_last_fastcall + + .section .text.rustix_indirect_syscall5_nr_last_fastcall,"ax",@progbits + .p2align 4 + .weak rustix_indirect_syscall5_nr_last_fastcall + .hidden rustix_indirect_syscall5_nr_last_fastcall + .type rustix_indirect_syscall5_nr_last_fastcall, @function +rustix_indirect_syscall5_nr_last_fastcall: + .cfi_startproc + push ebx + .cfi_def_cfa_offset 8 + push esi + .cfi_def_cfa_offset 12 + push edi + .cfi_def_cfa_offset 16 + .cfi_offset edi, -16 + .cfi_offset esi, -12 + .cfi_offset ebx, -8 + mov ebx,DWORD PTR [esp+0x10] + mov esi,DWORD PTR [esp+0x14] + mov edi,DWORD PTR [esp+0x18] + mov eax,DWORD PTR [esp+0x1c] + call DWORD PTR [esp+0x20] + pop edi + .cfi_def_cfa_offset 12 + pop esi + .cfi_def_cfa_offset 8 + pop ebx + .cfi_def_cfa_offset 4 + ret 0x14 + .cfi_endproc + .size rustix_indirect_syscall5_nr_last_fastcall, .-rustix_indirect_syscall5_nr_last_fastcall + + .section .text.rustix_indirect_syscall6_nr_last_fastcall,"ax",@progbits + .p2align 4 + .weak rustix_indirect_syscall6_nr_last_fastcall + .hidden rustix_indirect_syscall6_nr_last_fastcall + .type rustix_indirect_syscall6_nr_last_fastcall, @function +rustix_indirect_syscall6_nr_last_fastcall: + .cfi_startproc + push ebx + .cfi_def_cfa_offset 8 + push esi + .cfi_def_cfa_offset 12 + push edi + .cfi_def_cfa_offset 16 + push ebp + .cfi_def_cfa_offset 20 + .cfi_offset ebp, -20 + .cfi_offset edi, -16 + .cfi_offset esi, -12 + .cfi_offset ebx, -8 + mov ebx,DWORD PTR [esp+0x14] + mov esi,DWORD PTR [esp+0x18] + mov edi,DWORD PTR [esp+0x1c] + mov ebp,DWORD PTR [esp+0x20] + mov eax,DWORD PTR [esp+0x24] + call DWORD PTR [esp+0x28] + pop ebp + .cfi_def_cfa_offset 16 + pop edi + .cfi_def_cfa_offset 12 + pop esi + .cfi_def_cfa_offset 8 + pop ebx + .cfi_def_cfa_offset 4 + ret 0x18 + .cfi_endproc + .size rustix_indirect_syscall6_nr_last_fastcall, .-rustix_indirect_syscall6_nr_last_fastcall + + .section .text.rustix_syscall0_nr_last_fastcall,"ax",@progbits + .p2align 4 + .weak rustix_syscall0_nr_last_fastcall + .hidden rustix_syscall0_nr_last_fastcall + .type rustix_syscall0_nr_last_fastcall, @function +rustix_syscall0_nr_last_fastcall: + .cfi_startproc + mov eax,ecx + int 0x80 + ret + .cfi_endproc + .size rustix_syscall0_nr_last_fastcall, .-rustix_syscall0_nr_last_fastcall + + .section .text.rustix_syscall1_nr_last_fastcall,"ax",@progbits + .p2align 4 + .weak rustix_syscall1_nr_last_fastcall + .hidden rustix_syscall1_nr_last_fastcall + .type rustix_syscall1_nr_last_fastcall, @function +rustix_syscall1_nr_last_fastcall: + .cfi_startproc + push ebx + .cfi_def_cfa_offset 8 + .cfi_offset ebx, -8 + mov eax,edx + mov ebx,ecx + int 0x80 + pop ebx + .cfi_def_cfa_offset 4 + ret + .cfi_endproc + .size rustix_syscall1_nr_last_fastcall, .-rustix_syscall1_nr_last_fastcall + + .section .text.rustix_syscall1_noreturn_nr_last_fastcall,"ax",@progbits + .p2align 4 + .weak rustix_syscall1_noreturn_nr_last_fastcall + .hidden rustix_syscall1_noreturn_nr_last_fastcall + .type rustix_syscall1_noreturn_nr_last_fastcall, @function +rustix_syscall1_noreturn_nr_last_fastcall: + .cfi_startproc + mov eax,edx + mov ebx,ecx + int 0x80 + ud2 + .cfi_endproc + .size rustix_syscall1_noreturn_nr_last_fastcall, .-rustix_syscall1_noreturn_nr_last_fastcall + + .section .text.rustix_syscall2_nr_last_fastcall,"ax",@progbits + .p2align 4 + .weak rustix_syscall2_nr_last_fastcall + .hidden rustix_syscall2_nr_last_fastcall + .type rustix_syscall2_nr_last_fastcall, @function +rustix_syscall2_nr_last_fastcall: + .cfi_startproc + push ebx + .cfi_def_cfa_offset 8 + .cfi_offset ebx, -8 + mov ebx,edx + mov eax,DWORD PTR [esp+0x8] + int 0x80 + pop ebx + .cfi_def_cfa_offset 4 + ret 0x4 + .cfi_endproc + .size rustix_syscall2_nr_last_fastcall, .-rustix_syscall2_nr_last_fastcall + + .section .text.rustix_syscall3_nr_last_fastcall,"ax",@progbits + .p2align 4 + .weak rustix_syscall3_nr_last_fastcall + .hidden rustix_syscall3_nr_last_fastcall + .type rustix_syscall3_nr_last_fastcall, @function +rustix_syscall3_nr_last_fastcall: + .cfi_startproc + push ebx + .cfi_def_cfa_offset 8 + .cfi_offset ebx, -8 + mov ebx,DWORD PTR [esp+0x8] + mov eax,DWORD PTR [esp+0xc] + int 0x80 + pop ebx + .cfi_def_cfa_offset 4 + ret 0x8 + .cfi_endproc + .size rustix_syscall3_nr_last_fastcall, .-rustix_syscall3_nr_last_fastcall + + .section .text.rustix_syscall4_nr_last_fastcall,"ax",@progbits + .p2align 4 + .weak rustix_syscall4_nr_last_fastcall + .hidden rustix_syscall4_nr_last_fastcall + .type rustix_syscall4_nr_last_fastcall, @function +rustix_syscall4_nr_last_fastcall: + .cfi_startproc + push ebx + .cfi_def_cfa_offset 8 + push esi + .cfi_def_cfa_offset 12 + .cfi_offset esi, -12 + .cfi_offset ebx, -8 + mov ebx,DWORD PTR [esp+0xc] + mov esi,DWORD PTR [esp+0x10] + mov eax,DWORD PTR [esp+0x14] + int 0x80 + pop esi + .cfi_def_cfa_offset 8 + pop ebx + .cfi_def_cfa_offset 4 + ret 0xc + .cfi_endproc + .size rustix_syscall4_nr_last_fastcall, .-rustix_syscall4_nr_last_fastcall + + .section .text.rustix_syscall5_nr_last_fastcall,"ax",@progbits + .p2align 4 + .weak rustix_syscall5_nr_last_fastcall + .hidden rustix_syscall5_nr_last_fastcall + .type rustix_syscall5_nr_last_fastcall, @function +rustix_syscall5_nr_last_fastcall: + .cfi_startproc + push ebx + .cfi_def_cfa_offset 8 + push edi + .cfi_def_cfa_offset 12 + push esi + .cfi_def_cfa_offset 16 + .cfi_offset esi, -16 + .cfi_offset edi, -12 + .cfi_offset ebx, -8 + mov ebx,DWORD PTR [esp+0x10] + mov esi,DWORD PTR [esp+0x14] + mov edi,DWORD PTR [esp+0x18] + mov eax,DWORD PTR [esp+0x1c] + int 0x80 + pop esi + .cfi_def_cfa_offset 12 + pop edi + .cfi_def_cfa_offset 8 + pop ebx + .cfi_def_cfa_offset 4 + ret 0x10 + .cfi_endproc + .size rustix_syscall5_nr_last_fastcall, .-rustix_syscall5_nr_last_fastcall + + .section .text.rustix_syscall6_nr_last_fastcall,"ax",@progbits + .p2align 4 + .weak rustix_syscall6_nr_last_fastcall + .hidden rustix_syscall6_nr_last_fastcall + .type rustix_syscall6_nr_last_fastcall, @function +rustix_syscall6_nr_last_fastcall: + .cfi_startproc + push ebp + .cfi_def_cfa_offset 8 + push ebx + .cfi_def_cfa_offset 12 + push edi + .cfi_def_cfa_offset 16 + push esi + .cfi_def_cfa_offset 20 + .cfi_offset esi, -20 + .cfi_offset edi, -16 + .cfi_offset ebx, -12 + .cfi_offset ebp, -8 + mov ebx,DWORD PTR [esp+0x14] + mov esi,DWORD PTR [esp+0x18] + mov edi,DWORD PTR [esp+0x1c] + mov ebp,DWORD PTR [esp+0x20] + mov eax,DWORD PTR [esp+0x24] + int 0x80 + pop esi + .cfi_def_cfa_offset 16 + pop edi + .cfi_def_cfa_offset 12 + pop ebx + .cfi_def_cfa_offset 8 + pop ebp + .cfi_def_cfa_offset 4 + ret 0x14 + .cfi_endproc + .size rustix_syscall6_nr_last_fastcall, .-rustix_syscall6_nr_last_fastcall + + .section .text.rustix_int_0x80,"ax",@progbits + .p2align 4 + .weak rustix_int_0x80 + .hidden rustix_int_0x80 + .type rustix_int_0x80, @function +rustix_int_0x80: + .cfi_startproc + int 0x80 + ret + .cfi_endproc + .size rustix_int_0x80, .-rustix_int_0x80 + + .section .note.GNU-stack,"",@progbits diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/arch/outline/x86_64.s b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/outline/x86_64.s new file mode 100644 index 000000000..2beda323b --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/arch/outline/x86_64.s @@ -0,0 +1,122 @@ +// Assembly code for making x86-64 syscalls. +// +// x86-64 syscall argument register ordering is the same as the x86-64 +// userspace argument register ordering except that a3 is passed in r10 +// instead of rcx, and the syscall number (nr) is passed in eax. +// +// outline.rs takes care of reordering the nr argument to the end for us, +// so we only need to move nr into eax and move rcx into r10 as needed. +// +// x32 is not yet supported. + + .file "x86_64.s" + .intel_syntax noprefix + + .section .text.rustix_syscall0_nr_last,"ax",@progbits + .p2align 4 + .weak rustix_syscall0_nr_last + .hidden rustix_syscall0_nr_last + .type rustix_syscall0_nr_last, @function +rustix_syscall0_nr_last: + .cfi_startproc + mov eax,edi + syscall + ret + .cfi_endproc + .size rustix_syscall0_nr_last, .-rustix_syscall0_nr_last + + .section .text.rustix_syscall1_nr_last,"ax",@progbits + .p2align 4 + .weak rustix_syscall1_nr_last + .hidden rustix_syscall1_nr_last + .type rustix_syscall1_nr_last, @function +rustix_syscall1_nr_last: + .cfi_startproc + mov eax,esi + syscall + ret + .cfi_endproc + .size rustix_syscall1_nr_last, .-rustix_syscall1_nr_last + + .section .text.rustix_syscall1_noreturn_nr_last,"ax",@progbits + .p2align 4 + .weak rustix_syscall1_noreturn_nr_last + .hidden rustix_syscall1_noreturn_nr_last + .type rustix_syscall1_noreturn_nr_last, @function +rustix_syscall1_noreturn_nr_last: + .cfi_startproc + mov eax,esi + syscall + ud2 + .cfi_endproc + .size rustix_syscall1_noreturn_nr_last, .-rustix_syscall1_noreturn_nr_last + + .section .text.rustix_syscall2_nr_last,"ax",@progbits + .p2align 4 + .weak rustix_syscall2_nr_last + .hidden rustix_syscall2_nr_last + .type rustix_syscall2_nr_last, @function +rustix_syscall2_nr_last: + .cfi_startproc + mov eax,edx + syscall + ret + .cfi_endproc + .size rustix_syscall2_nr_last, .-rustix_syscall2_nr_last + + .section .text.rustix_syscall3_nr_last,"ax",@progbits + .p2align 4 + .weak rustix_syscall3_nr_last + .hidden rustix_syscall3_nr_last + .type rustix_syscall3_nr_last, @function +rustix_syscall3_nr_last: + .cfi_startproc + mov eax,ecx + syscall + ret + .cfi_endproc + .size rustix_syscall3_nr_last, .-rustix_syscall3_nr_last + + .section .text.rustix_syscall4_nr_last,"ax",@progbits + .p2align 4 + .weak rustix_syscall4_nr_last + .hidden rustix_syscall4_nr_last + .type rustix_syscall4_nr_last, @function +rustix_syscall4_nr_last: + .cfi_startproc + mov eax,r8d + mov r10,rcx + syscall + ret + .cfi_endproc + .size rustix_syscall4_nr_last, .-rustix_syscall4_nr_last + + .section .text.rustix_syscall5_nr_last,"ax",@progbits + .p2align 4 + .weak rustix_syscall5_nr_last + .hidden rustix_syscall5_nr_last + .type rustix_syscall5_nr_last, @function +rustix_syscall5_nr_last: + .cfi_startproc + mov eax,r9d + mov r10,rcx + syscall + ret + .cfi_endproc + .size rustix_syscall5_nr_last, .-rustix_syscall5_nr_last + + .section .text.rustix_syscall6_nr_last,"ax",@progbits + .p2align 4 + .weak rustix_syscall6_nr_last + .hidden rustix_syscall6_nr_last + .type rustix_syscall6_nr_last, @function +rustix_syscall6_nr_last: + .cfi_startproc + mov eax,DWORD PTR [rsp+0x8] + mov r10,rcx + syscall + ret + .cfi_endproc + .size rustix_syscall6_nr_last, .-rustix_syscall6_nr_last + + .section .note.GNU-stack,"",@progbits diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/c.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/c.rs new file mode 100644 index 000000000..30ce1256c --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/c.rs @@ -0,0 +1,36 @@ +//! 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)] + +pub(crate) use linux_raw_sys::cmsg_macros::*; +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, + cmsghdr, in6_addr, in_addr, iovec, ip_mreq, ipv6_mreq, linger, msghdr, siginfo_t, size_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, CLD_CONTINUED, CLD_DUMPED, CLD_EXITED, CLD_KILLED, + CLD_STOPPED, CLD_TRAPPED, 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_HOPS, + IPV6_MULTICAST_LOOP, IPV6_UNICAST_HOPS, 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, + SCM_CREDENTIALS, SCM_RIGHTS, SHUT_RD, SHUT_RDWR, SHUT_WR, SOCK_DGRAM, SOCK_RAW, SOCK_RDM, + SOCK_SEQPACKET, SOCK_STREAM, SOL_SOCKET, SO_BROADCAST, SO_ERROR, SO_KEEPALIVE, SO_LINGER, + SO_PASSCRED, SO_RCVBUF, SO_RCVTIMEO_NEW, SO_RCVTIMEO_OLD, SO_REUSEADDR, SO_SNDBUF, + 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}; +pub(crate) use linux_raw_sys::general::{O_NOCTTY, O_RDWR}; +pub(crate) use linux_raw_sys::general::{XATTR_CREATE, XATTR_REPLACE}; diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/conv.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/conv.rs new file mode 100644 index 000000000..7635c4e24 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/conv.rs @@ -0,0 +1,879 @@ +//! Convert values to [`ArgReg`] and from [`RetReg`]. +//! +//! System call arguments and return values are all communicated with inline +//! asm and FFI as `*mut Opaque`. To protect these raw pointers from escaping +//! or being accidentally misused as they travel through the code, we wrap +//! them in [`ArgReg`] and [`RetReg`] structs. This file provides `From` +//! implementations and explicit conversion functions for converting values +//! into and out of these wrapper structs. +//! +//! # Safety +//! +//! Some of this code is `unsafe` in order to work with raw file descriptors, +//! and some is `unsafe` to interpret the values in a `RetReg`. +#![allow(unsafe_code)] + +use super::c; +use super::fd::{AsRawFd, BorrowedFd, FromRawFd, RawFd}; +#[cfg(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, +}; +use super::reg::{raw_arg, ArgNumber, ArgReg, RetReg, R0}; +#[cfg(any(feature = "thread", feature = "time", target_arch = "x86"))] +use super::time::types::ClockId; +#[cfg(feature = "time")] +use super::time::types::TimerfdClockId; +use crate::fd::OwnedFd; +use crate::ffi::CStr; +use crate::io; +use crate::process::{Pid, Resource, Signal}; +use crate::utils::{as_mut_ptr, as_ptr}; +use core::mem::MaybeUninit; +use core::ptr::null_mut; +#[cfg(any(feature = "thread", feature = "time", target_arch = "x86"))] +use linux_raw_sys::general::__kernel_clockid_t; +#[cfg(target_pointer_width = "64")] +use linux_raw_sys::general::__kernel_loff_t; +#[cfg(feature = "net")] +use linux_raw_sys::general::socklen_t; + +/// Convert `SYS_*` constants for socketcall. +#[cfg(target_arch = "x86")] +#[inline] +pub(super) fn x86_sys<'a, Num: ArgNumber>(sys: u32) -> ArgReg<'a, Num> { + pass_usize(sys as usize) +} + +/// Pass the "low" half of the endian-specific memory encoding of a `u64`, for +/// 32-bit architectures. +#[cfg(target_pointer_width = "32")] +#[inline] +pub(super) fn lo<'a, Num: ArgNumber>(x: u64) -> ArgReg<'a, Num> { + #[cfg(target_endian = "little")] + let x = x >> 32; + #[cfg(target_endian = "big")] + let x = x & 0xffff_ffff; + + pass_usize(x as usize) +} + +/// Pass the "high" half of the endian-specific memory encoding of a `u64`, for +/// 32-bit architectures. +#[cfg(target_pointer_width = "32")] +#[inline] +pub(super) fn hi<'a, Num: ArgNumber>(x: u64) -> ArgReg<'a, Num> { + #[cfg(target_endian = "little")] + let x = x & 0xffff_ffff; + #[cfg(target_endian = "big")] + let x = x >> 32; + + pass_usize(x as usize) +} + +/// Pass a zero, or null, argument. +#[inline] +pub(super) fn zero<'a, Num: ArgNumber>() -> ArgReg<'a, Num> { + raw_arg(null_mut()) +} + +/// Pass the `mem::size_of` of a type. +#[inline] +pub(super) fn size_of<'a, T: Sized, Num: ArgNumber>() -> ArgReg<'a, Num> { + pass_usize(core::mem::size_of::<T>()) +} + +/// Pass an arbitrary `usize` value. +/// +/// For passing pointers, use `void_star` or other functions which take a raw +/// pointer instead of casting to `usize`, so that provenance is preserved. +#[inline] +pub(super) fn pass_usize<'a, Num: ArgNumber>(t: usize) -> ArgReg<'a, Num> { + raw_arg(t as *mut _) +} + +impl<'a, Num: ArgNumber, T> From<*mut T> for ArgReg<'a, Num> { + #[inline] + fn from(c: *mut T) -> ArgReg<'a, Num> { + raw_arg(c.cast()) + } +} + +impl<'a, Num: ArgNumber, T> From<*const T> for ArgReg<'a, Num> { + #[inline] + fn from(c: *const T) -> ArgReg<'a, Num> { + let mut_ptr = c as *mut T; + raw_arg(mut_ptr.cast()) + } +} + +impl<'a, Num: ArgNumber> From<&'a CStr> for ArgReg<'a, Num> { + #[inline] + fn from(c: &'a CStr) -> Self { + let mut_ptr = c.as_ptr() as *mut u8; + raw_arg(mut_ptr.cast()) + } +} + +impl<'a, Num: ArgNumber> From<Option<&'a CStr>> for ArgReg<'a, Num> { + #[inline] + fn from(t: Option<&'a CStr>) -> Self { + raw_arg(match t { + Some(s) => { + let mut_ptr = s.as_ptr() as *mut u8; + mut_ptr.cast() + } + None => null_mut(), + }) + } +} + +/// Pass a borrowed file-descriptor argument. +impl<'a, Num: ArgNumber> From<BorrowedFd<'a>> for ArgReg<'a, Num> { + #[inline] + fn from(fd: BorrowedFd<'a>) -> Self { + // SAFETY: `BorrowedFd` ensures that the file descriptor is valid, and + // the lifetime parameter on the resulting `ArgReg` ensures that the + // result is bounded by the `BorrowedFd`'s lifetime. + unsafe { raw_fd(fd.as_raw_fd()) } + } +} + +/// Pass a raw file-descriptor argument. Most users should use [`ArgReg::from`] +/// instead, to preserve I/O safety as long as possible. +/// +/// # Safety +/// +/// `fd` must be a valid open file descriptor. +#[inline] +pub(super) unsafe fn raw_fd<'a, Num: ArgNumber>(fd: RawFd) -> ArgReg<'a, Num> { + // Use `no_fd` when passing `-1` is intended. + #[cfg(feature = "fs")] + debug_assert!(fd == crate::fs::cwd().as_raw_fd() || fd >= 0); + + // Don't pass the `io_uring_register_files_skip` sentry value this way. + #[cfg(feature = "io_uring")] + debug_assert_ne!( + fd, + crate::io_uring::io_uring_register_files_skip().as_raw_fd() + ); + + // Linux doesn't look at the high bits beyond the `c_int`, so use + // zero-extension rather than sign-extension because it's a smaller + // instruction. + let fd: c::c_int = fd; + pass_usize(fd as c::c_uint as usize) +} + +/// Deliberately pass `-1` to a file-descriptor argument, for system calls +/// like `mmap` where this indicates the argument is omitted. +#[inline] +pub(super) fn no_fd<'a, Num: ArgNumber>() -> ArgReg<'a, Num> { + pass_usize(!0_usize) +} + +#[inline] +pub(super) fn slice_just_addr<T: Sized, Num: ArgNumber>(v: &[T]) -> ArgReg<Num> { + let mut_ptr = v.as_ptr() as *mut T; + raw_arg(mut_ptr.cast()) +} + +#[inline] +pub(super) fn slice_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. +#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] +#[inline] +pub(super) fn opt_ref<T: Sized, Num: ArgNumber>(t: Option<&T>) -> ArgReg<Num> { + // This optimizes into the equivalent of `transmute(t)`, and has the + // advantage of not requiring `unsafe`. + match t { + Some(t) => by_ref(t), + None => raw_arg(null_mut()), + } +} + +/// Convert a `c_int` into an `ArgReg`. +/// +/// Be sure to use `raw_fd` to pass `RawFd` values. +#[inline] +pub(super) fn c_int<'a, Num: ArgNumber>(i: c::c_int) -> ArgReg<'a, Num> { + pass_usize(i as usize) +} + +/// Convert a `c_uint` into an `ArgReg`. +#[inline] +pub(super) fn c_uint<'a, Num: ArgNumber>(i: c::c_uint) -> ArgReg<'a, Num> { + pass_usize(i as usize) +} + +#[cfg(target_pointer_width = "64")] +#[inline] +pub(super) fn loff_t<'a, Num: ArgNumber>(i: __kernel_loff_t) -> ArgReg<'a, Num> { + pass_usize(i as usize) +} + +#[cfg(target_pointer_width = "64")] +#[inline] +pub(super) fn loff_t_from_u64<'a, Num: ArgNumber>(i: u64) -> ArgReg<'a, Num> { + // `loff_t` is signed, but syscalls which expect `loff_t` return `EINVAL` + // if it's outside the signed `i64` range, so we can silently cast. + pass_usize(i as usize) +} + +#[cfg(any(feature = "thread", feature = "time", target_arch = "x86"))] +impl<'a, Num: ArgNumber> From<ClockId> for ArgReg<'a, Num> { + #[inline] + fn from(i: ClockId) -> Self { + pass_usize(i as __kernel_clockid_t as usize) + } +} + +#[cfg(feature = "time")] +impl<'a, Num: ArgNumber> From<TimerfdClockId> for ArgReg<'a, Num> { + #[inline] + fn from(i: TimerfdClockId) -> Self { + pass_usize(i as __kernel_clockid_t as usize) + } +} + +#[cfg(feature = "net")] +#[inline] +pub(super) fn socklen_t<'a, Num: ArgNumber>(i: socklen_t) -> ArgReg<'a, Num> { + pass_usize(i as usize) +} + +#[cfg(any( + feature = "fs", + all( + not(feature = "use-libc-auxv"), + not(target_vendor = "mustang"), + any( + feature = "param", + feature = "runtime", + 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()) + } + } + + impl<'a, Num: ArgNumber> From<crate::backend::fs::types::MountFlagsArg> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::backend::fs::types::MountFlagsArg) -> Self { + c_uint(flags.0) + } + } + + impl<'a, Num: ArgNumber> From<crate::backend::fs::types::UnmountFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::backend::fs::types::UnmountFlags) -> Self { + c_uint(flags.bits()) + } + } +} + +impl<'a, Num: ArgNumber> From<crate::io::FdFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::io::FdFlags) -> Self { + c_uint(flags.bits()) + } +} + +impl<'a, Num: ArgNumber> From<crate::io::PipeFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::io::PipeFlags) -> Self { + c_uint(flags.bits()) + } +} + +impl<'a, Num: ArgNumber> From<crate::io::DupFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::io::DupFlags) -> Self { + c_uint(flags.bits()) + } +} + +impl<'a, Num: ArgNumber> From<crate::io::ReadWriteFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::io::ReadWriteFlags) -> Self { + c_uint(flags.bits()) + } +} + +impl<'a, Num: ArgNumber> From<crate::io::EventfdFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::io::EventfdFlags) -> Self { + c_uint(flags.bits()) + } +} + +impl<'a, Num: ArgNumber> From<crate::io::epoll::CreateFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::io::epoll::CreateFlags) -> Self { + c_uint(flags.bits()) + } +} + +#[cfg(feature = "mm")] +impl<'a, Num: ArgNumber> From<crate::backend::mm::types::ProtFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::backend::mm::types::ProtFlags) -> Self { + c_uint(flags.bits()) + } +} + +#[cfg(feature = "mm")] +impl<'a, Num: ArgNumber> From<crate::backend::mm::types::MsyncFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::backend::mm::types::MsyncFlags) -> Self { + c_uint(flags.bits()) + } +} + +#[cfg(feature = "mm")] +impl<'a, Num: ArgNumber> From<crate::backend::mm::types::MremapFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::backend::mm::types::MremapFlags) -> Self { + c_uint(flags.bits()) + } +} + +#[cfg(feature = "mm")] +impl<'a, Num: ArgNumber> From<crate::backend::mm::types::MlockFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::backend::mm::types::MlockFlags) -> Self { + c_uint(flags.bits()) + } +} + +#[cfg(feature = "mm")] +impl<'a, Num: ArgNumber> From<crate::backend::mm::types::MapFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::backend::mm::types::MapFlags) -> Self { + c_uint(flags.bits()) + } +} + +#[cfg(feature = "mm")] +impl<'a, Num: ArgNumber> From<crate::backend::mm::types::MprotectFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::backend::mm::types::MprotectFlags) -> Self { + c_uint(flags.bits()) + } +} + +#[cfg(feature = "mm")] +impl<'a, Num: ArgNumber> From<crate::backend::mm::types::UserfaultfdFlags> for ArgReg<'a, Num> { + #[inline] + fn from(flags: crate::backend::mm::types::UserfaultfdFlags) -> Self { + c_uint(flags.bits()) + } +} + +impl<'a, Num: ArgNumber> From<crate::backend::process::types::MembarrierCommand> + for ArgReg<'a, Num> +{ + #[inline] + fn from(cmd: crate::backend::process::types::MembarrierCommand) -> Self { + c_uint(cmd as u32) + } +} + +impl<'a, Num: ArgNumber> From<crate::process::Cpuid> for ArgReg<'a, Num> { + #[inline] + fn from(cpuid: crate::process::Cpuid) -> Self { + c_uint(cpuid.as_raw()) + } +} + +#[cfg(target_pointer_width = "64")] +#[inline] +pub(super) fn dev_t<'a, Num: ArgNumber>(dev: u64) -> ArgReg<'a, Num> { + pass_usize(dev as usize) +} + +#[cfg(target_pointer_width = "32")] +#[inline] +pub(super) fn dev_t<'a, Num: ArgNumber>(dev: u64) -> io::Result<ArgReg<'a, Num>> { + use core::convert::TryInto; + Ok(pass_usize(dev.try_into().map_err(|_err| io::Errno::INVAL)?)) +} + +/// Convert a `Resource` into a syscall argument. +impl<'a, Num: ArgNumber> From<Resource> for ArgReg<'a, Num> { + #[inline] + fn from(resource: Resource) -> Self { + c_uint(resource as c::c_uint) + } +} + +impl<'a, Num: ArgNumber> From<Pid> for ArgReg<'a, Num> { + #[inline] + fn from(pid: Pid) -> Self { + pass_usize(pid.as_raw_nonzero().get() as usize) + } +} + +#[inline] +pub(super) fn negative_pid<'a, Num: ArgNumber>(pid: Pid) -> ArgReg<'a, Num> { + pass_usize(pid.as_raw_nonzero().get().wrapping_neg() as usize) +} + +impl<'a, Num: ArgNumber> From<Signal> for ArgReg<'a, Num> { + #[inline] + fn from(sig: Signal) -> Self { + pass_usize(sig as usize) + } +} + +#[cfg(feature = "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::thread::FutexOperation, crate::thread::FutexFlags)> + for ArgReg<'a, Num> +{ + #[inline] + fn from(pair: (crate::thread::FutexOperation, crate::thread::FutexFlags)) -> Self { + c_uint(pair.0 as u32 | pair.1.bits()) + } +} + +#[cfg(feature = "net")] +impl<'a, Num: ArgNumber> From<crate::net::SocketType> for ArgReg<'a, Num> { + #[inline] + fn from(type_: crate::net::SocketType) -> Self { + c_uint(type_.0) + } +} + +#[cfg(feature = "net")] +impl<'a, Num: ArgNumber> From<crate::net::Protocol> for ArgReg<'a, Num> { + #[inline] + fn from(protocol: crate::net::Protocol) -> Self { + c_uint(protocol.0) + } +} + +impl<'a, Num: ArgNumber, T> From<&'a mut MaybeUninit<T>> for ArgReg<'a, Num> { + #[inline] + fn from(t: &'a mut MaybeUninit<T>) -> Self { + raw_arg(t.as_mut_ptr().cast()) + } +} + +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> From<crate::process::Uid> for ArgReg<'a, Num> { + #[inline] + fn from(t: crate::process::Uid) -> Self { + c_uint(t.as_raw()) + } +} + +impl<'a, Num: ArgNumber> From<crate::process::Gid> for ArgReg<'a, Num> { + #[inline] + fn from(t: crate::process::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(feature = "runtime")] +#[inline] +pub(super) unsafe fn ret_error(raw: RetReg<R0>) -> io::Errno { + try_decode_error(raw) +} + +/// Convert a `usize` returned from a syscall that effectively always returns +/// `()`. +/// +/// # Safety +/// +/// The caller must ensure that this is the return value of a syscall which +/// always returns `()`. +#[inline] +pub(super) unsafe fn ret_infallible(raw: RetReg<R0>) { + #[cfg(debug_assertions)] + { + try_decode_void(raw).unwrap() + } + #[cfg(not(debug_assertions))] + drop(raw); +} + +/// Convert a `usize` returned from a syscall that effectively returns a +/// `c_int` on success. +#[inline] +pub(super) fn ret_c_int(raw: RetReg<R0>) -> io::Result<c::c_int> { + try_decode_c_int(raw) +} + +/// Convert a `usize` returned from a syscall that effectively returns a +/// `c_uint` on success. +#[inline] +pub(super) fn ret_c_uint(raw: RetReg<R0>) -> io::Result<c::c_uint> { + try_decode_c_uint(raw) +} + +/// Convert a `usize` returned from a syscall that effectively returns a `u64` +/// on success. +#[cfg(target_pointer_width = "64")] +#[inline] +pub(super) fn ret_u64(raw: RetReg<R0>) -> io::Result<u64> { + try_decode_u64(raw) +} + +/// Convert a `usize` returned from a syscall that effectively returns a +/// `usize` on success. +#[inline] +pub(super) fn ret_usize(raw: RetReg<R0>) -> io::Result<usize> { + try_decode_usize(raw) +} + +/// Convert a `usize` returned from a syscall that effectively always +/// returns a `usize`. +/// +/// # Safety +/// +/// This function must only be used with return values from infallible +/// syscalls. +#[inline] +pub(super) unsafe fn ret_usize_infallible(raw: RetReg<R0>) -> usize { + #[cfg(debug_assertions)] + { + try_decode_usize(raw).unwrap() + } + #[cfg(not(debug_assertions))] + { + decode_usize_infallible(raw) + } +} + +/// Convert a `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-0.37.22/src/backend/linux_raw/elf.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/elf.rs new file mode 100644 index 000000000..7797f4e21 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/elf.rs @@ -0,0 +1,176 @@ +//! The ELF ABI. 🧝 + +#![allow(non_snake_case)] +#![cfg_attr( + all(not(target_vendor = "mustang"), feature = "use-libc-auxv"), + allow(dead_code) +)] + +pub(super) const SELFMAG: usize = 4; +pub(super) const ELFMAG: [u8; SELFMAG] = [0x7f, b'E', b'L', b'F']; +pub(super) const EI_CLASS: usize = 4; +pub(super) const EI_DATA: usize = 5; +pub(super) const EI_VERSION: usize = 6; +pub(super) const EI_OSABI: usize = 7; +pub(super) const EI_ABIVERSION: usize = 8; +pub(super) const EV_CURRENT: u8 = 1; +#[cfg(target_pointer_width = "32")] +pub(super) const ELFCLASS: u8 = 1; // ELFCLASS32 +#[cfg(target_pointer_width = "64")] +pub(super) const ELFCLASS: u8 = 2; // ELFCLASS64 +#[cfg(target_endian = "little")] +pub(super) const ELFDATA: u8 = 1; // ELFDATA2LSB +#[cfg(target_endian = "big")] +pub(super) const ELFDATA: u8 = 2; // ELFDATA2MSB +pub(super) const ELFOSABI_SYSV: u8 = 0; +pub(super) const ELFOSABI_LINUX: u8 = 3; +// At present all of our supported platforms use 0. +pub(super) const ELFABIVERSION: u8 = 0; +pub(super) const ET_DYN: u16 = 3; +pub(super) const EI_NIDENT: usize = 16; +pub(super) const SHN_UNDEF: u16 = 0; +pub(super) const SHN_ABS: u16 = 0xfff1; +pub(super) const PN_XNUM: u16 = 0xffff; +pub(super) const PT_LOAD: u32 = 1; +pub(super) const PT_DYNAMIC: u32 = 2; +pub(super) const PT_INTERP: u32 = 3; +pub(super) const PT_PHDR: u32 = 6; +pub(super) const PT_TLS: u32 = 7; +pub(super) const PT_GNU_STACK: u32 = 0x6474_e551; +pub(super) const PT_GNU_RELRO: u32 = 0x6474_e552; +pub(super) const PF_X: u32 = 1; +pub(super) const PF_W: u32 = 2; +pub(super) const PF_R: u32 = 4; +pub(super) const DT_NULL: i32 = 0; +pub(super) const DT_HASH: i32 = 4; +pub(super) const DT_STRTAB: i32 = 5; +pub(super) const DT_SYMTAB: i32 = 6; +pub(super) const DT_SYMENT: i32 = 11; +pub(super) const DT_VERSYM: i32 = 0x6fff_fff0; +pub(super) const DT_VERDEF: i32 = 0x6fff_fffc; +pub(super) const STB_WEAK: u8 = 2; +pub(super) const STB_GLOBAL: u8 = 1; +pub(super) const STT_NOTYPE: u8 = 0; +pub(super) const STT_FUNC: u8 = 2; +pub(super) const STN_UNDEF: u32 = 0; +pub(super) const VER_FLG_BASE: u16 = 0x1; +pub(super) const VER_DEF_CURRENT: u16 = 1; +pub(super) const STV_DEFAULT: u8 = 0; +#[cfg(target_arch = "arm")] +pub(super) const EM_CURRENT: u16 = 40; // EM_ARM +#[cfg(target_arch = "x86")] +pub(super) const EM_CURRENT: u16 = 3; // EM_386 +#[cfg(target_arch = "powerpc64")] +pub(super) const EM_CURRENT: u16 = 21; // EM_PPC64 +#[cfg(any(target_arch = "mips", target_arch = "mips64"))] +pub(super) const EM_CURRENT: u16 = 8; // EM_MIPS +#[cfg(target_arch = "x86_64")] +pub(super) const EM_CURRENT: u16 = 62; // EM_X86_64 +#[cfg(target_arch = "aarch64")] +pub(super) const EM_CURRENT: u16 = 183; // EM_AARCH64 +#[cfg(target_arch = "riscv64")] +pub(super) const EM_CURRENT: u16 = 243; // EM_RISCV + +#[inline] +pub(super) const fn ELF_ST_VISIBILITY(o: u8) -> u8 { + o & 0x03 +} + +#[inline] +pub(super) const fn ELF_ST_BIND(val: u8) -> u8 { + val >> 4 +} + +#[inline] +pub(super) const fn ELF_ST_TYPE(val: u8) -> u8 { + val & 0xf +} + +#[repr(C)] +pub(super) struct Elf_Ehdr { + pub(super) e_ident: [u8; EI_NIDENT], + pub(super) e_type: u16, + pub(super) e_machine: u16, + pub(super) e_version: u32, + pub(super) e_entry: usize, + pub(super) e_phoff: usize, + pub(super) e_shoff: usize, + pub(super) e_flags: u32, + pub(super) e_ehsize: u16, + pub(super) e_phentsize: u16, + pub(super) e_phnum: u16, + pub(super) e_shentsize: u16, + pub(super) e_shnum: u16, + pub(super) e_shstrndx: u16, +} + +#[cfg(target_pointer_width = "32")] +#[repr(C)] +pub(super) struct Elf_Phdr { + pub(super) p_type: u32, + pub(super) p_offset: usize, + pub(super) p_vaddr: usize, + pub(super) p_paddr: usize, + pub(super) p_filesz: usize, + pub(super) p_memsz: usize, + pub(super) p_flags: u32, + pub(super) p_align: usize, +} + +#[cfg(target_pointer_width = "64")] +#[repr(C)] +pub(super) struct Elf_Phdr { + pub(super) p_type: u32, + pub(super) p_flags: u32, + pub(super) p_offset: usize, + pub(super) p_vaddr: usize, + pub(super) p_paddr: usize, + pub(super) p_filesz: usize, + pub(super) p_memsz: usize, + pub(super) p_align: usize, +} + +#[cfg(target_pointer_width = "32")] +#[repr(C)] +pub(super) struct Elf_Sym { + pub(super) st_name: u32, + pub(super) st_value: usize, + pub(super) st_size: usize, + pub(super) st_info: u8, + pub(super) st_other: u8, + pub(super) st_shndx: u16, +} + +#[cfg(target_pointer_width = "64")] +#[repr(C)] +pub(super) struct Elf_Sym { + pub(super) st_name: u32, + pub(super) st_info: u8, + pub(super) st_other: u8, + pub(super) st_shndx: u16, + pub(super) st_value: usize, + pub(super) st_size: usize, +} + +#[repr(C)] +pub(super) struct Elf_Dyn { + pub(super) d_tag: i32, + pub(super) d_val: usize, +} + +#[repr(C)] +pub(super) struct Elf_Verdef { + pub(super) vd_version: u16, + pub(super) vd_flags: u16, + pub(super) vd_ndx: u16, + pub(super) vd_cnt: u16, + pub(super) vd_hash: u32, + pub(super) vd_aux: u32, + pub(super) vd_next: u32, +} + +#[repr(C)] +pub(super) struct Elf_Verdaux { + pub(super) vda_name: u32, + pub(super) _vda_next: u32, +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/fs/dir.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/fs/dir.rs new file mode 100644 index 000000000..66b3101b1 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/fs/dir.rs @@ -0,0 +1,224 @@ +use crate::fd::{AsFd, BorrowedFd, OwnedFd}; +use crate::ffi::{CStr, CString}; +use crate::fs::{ + fcntl_getfl, fstat, fstatfs, fstatvfs, openat, FileType, Mode, OFlags, Stat, StatFs, StatVfs, +}; +use crate::io; +use crate::process::fchdir; +use crate::utils::as_ptr; +use alloc::borrow::ToOwned; +use alloc::vec::Vec; +use core::fmt; +use core::mem::size_of; +use linux_raw_sys::general::{linux_dirent64, SEEK_SET}; + +/// `DIR*` +pub struct Dir { + /// The `OwnedFd` that we read directory entries from. + fd: OwnedFd, + + buf: Vec<u8>, + pos: usize, + next: Option<u64>, +} + +impl Dir { + /// Construct a `Dir` that reads entries from the given directory + /// file descriptor. + #[inline] + pub fn read_from<Fd: AsFd>(fd: Fd) -> io::Result<Self> { + Self::_read_from(fd.as_fd()) + } + + #[inline] + fn _read_from(fd: BorrowedFd<'_>) -> io::Result<Self> { + let flags = fcntl_getfl(fd)?; + let fd_for_dir = openat(fd, cstr!("."), flags | OFlags::CLOEXEC, Mode::empty())?; + + Ok(Self { + fd: fd_for_dir, + buf: Vec::new(), + pos: 0, + next: None, + }) + } + + /// `rewinddir(self)` + #[inline] + pub fn rewind(&mut self) { + self.pos = self.buf.len(); + self.next = Some(0); + } + + /// `readdir(self)`, where `None` means the end of the directory. + pub fn read(&mut self) -> Option<io::Result<DirEntry>> { + if let Some(next) = self.next.take() { + match crate::backend::fs::syscalls::_seek(self.fd.as_fd(), next as i64, SEEK_SET) { + Ok(_) => (), + Err(err) => return Some(Err(err)), + } + } + + // Compute linux_dirent64 field offsets. + let z = linux_dirent64 { + d_ino: 0_u64, + d_off: 0_i64, + d_type: 0_u8, + d_reclen: 0_u16, + d_name: Default::default(), + }; + let base = as_ptr(&z) as usize; + let offsetof_d_reclen = (as_ptr(&z.d_reclen) as usize) - base; + let offsetof_d_name = (as_ptr(&z.d_name) as usize) - base; + let offsetof_d_ino = (as_ptr(&z.d_ino) as usize) - base; + let offsetof_d_type = (as_ptr(&z.d_type) as usize) - base; + + // Test if we need more entries, and if so, read more. + if self.buf.len() - self.pos < size_of::<linux_dirent64>() { + match self.read_more()? { + Ok(()) => (), + Err(e) => return Some(Err(e)), + } + } + + // We successfully read an entry. Extract the fields. + let pos = self.pos; + + // Do an unaligned u16 load. + let d_reclen = u16::from_ne_bytes([ + self.buf[pos + offsetof_d_reclen], + self.buf[pos + offsetof_d_reclen + 1], + ]); + assert!(self.buf.len() - pos >= d_reclen as usize); + self.pos += d_reclen as usize; + + // Read the NUL-terminated name from the `d_name` field. Without + // `unsafe`, we need to scan for the NUL twice: once to obtain a size + // for the slice, and then once within `CStr::from_bytes_with_nul`. + let name_start = pos + offsetof_d_name; + let name_len = self.buf[name_start..] + .iter() + .position(|x| *x == b'\0') + .unwrap(); + let name = CStr::from_bytes_with_nul(&self.buf[name_start..][..name_len + 1]).unwrap(); + let name = name.to_owned(); + assert!(name.as_bytes().len() <= self.buf.len() - name_start); + + // Do an unaligned u64 load. + let d_ino = u64::from_ne_bytes([ + self.buf[pos + offsetof_d_ino], + self.buf[pos + offsetof_d_ino + 1], + self.buf[pos + offsetof_d_ino + 2], + self.buf[pos + offsetof_d_ino + 3], + self.buf[pos + offsetof_d_ino + 4], + self.buf[pos + offsetof_d_ino + 5], + self.buf[pos + offsetof_d_ino + 6], + self.buf[pos + offsetof_d_ino + 7], + ]); + + let d_type = self.buf[pos + offsetof_d_type]; + + // Check that our types correspond to the `linux_dirent64` types. + let _ = linux_dirent64 { + d_ino, + d_off: 0, + d_type, + d_reclen, + d_name: Default::default(), + }; + + Some(Ok(DirEntry { + d_ino, + d_type, + name, + })) + } + + fn read_more(&mut self) -> Option<io::Result<()>> { + let og_len = self.buf.len(); + // Capacity increment currently chosen by wild guess. + self.buf + .resize(self.buf.capacity() + 32 * size_of::<linux_dirent64>(), 0); + let nread = match crate::backend::fs::syscalls::getdents(self.fd.as_fd(), &mut self.buf) { + Ok(nread) => nread, + Err(err) => { + self.buf.resize(og_len, 0); + return Some(Err(err)); + } + }; + self.buf.resize(nread, 0); + self.pos = 0; + if nread == 0 { + None + } else { + Some(Ok(())) + } + } + + /// `fstat(self)` + #[inline] + pub fn stat(&self) -> io::Result<Stat> { + fstat(&self.fd) + } + + /// `fstatfs(self)` + #[inline] + pub fn statfs(&self) -> io::Result<StatFs> { + fstatfs(&self.fd) + } + + /// `fstatvfs(self)` + #[inline] + pub fn statvfs(&self) -> io::Result<StatVfs> { + fstatvfs(&self.fd) + } + + /// `fchdir(self)` + #[inline] + pub fn chdir(&self) -> io::Result<()> { + fchdir(&self.fd) + } +} + +impl Iterator for Dir { + type Item = io::Result<DirEntry>; + + #[inline] + fn next(&mut self) -> Option<Self::Item> { + Self::read(self) + } +} + +impl fmt::Debug for Dir { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Dir").field("fd", &self.fd).finish() + } +} + +/// `struct dirent` +#[derive(Debug)] +pub struct DirEntry { + d_ino: u64, + d_type: u8, + name: CString, +} + +impl DirEntry { + /// Returns the file name of this directory entry. + #[inline] + pub fn file_name(&self) -> &CStr { + &self.name + } + + /// Returns the type of this directory entry. + #[inline] + pub fn file_type(&self) -> FileType { + FileType::from_dirent_d_type(self.d_type) + } + + /// Return the inode number of this directory entry. + #[inline] + pub fn ino(&self) -> u64 { + self.d_ino + } +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/fs/inotify.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/fs/inotify.rs new file mode 100644 index 000000000..bfb600ad7 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/fs/inotify.rs @@ -0,0 +1,111 @@ +//! 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")] +#[inline] +pub fn inotify_init(flags: CreateFlags) -> io::Result<OwnedFd> { + 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. +#[inline] +pub fn inotify_add_watch<P: crate::path::Arg>( + inot: BorrowedFd<'_>, + path: P, + flags: WatchFlags, +) -> io::Result<i32> { + 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")] +#[inline] +pub fn inotify_remove_watch(inot: BorrowedFd<'_>, wd: i32) -> io::Result<()> { + syscalls::inotify_rm_watch(inot, wd) +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/fs/makedev.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/fs/makedev.rs new file mode 100644 index 000000000..284ba2f10 --- /dev/null +++ b/vendor/rustix-0.37.22/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-0.37.22/src/backend/linux_raw/fs/mod.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/fs/mod.rs new file mode 100644 index 000000000..acf43ce4f --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/fs/mod.rs @@ -0,0 +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-0.37.22/src/backend/linux_raw/fs/syscalls.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/fs/syscalls.rs new file mode 100644 index 000000000..a096fc6d1 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/fs/syscalls.rs @@ -0,0 +1,1682 @@ +//! linux_raw syscalls supporting `rustix::fs`. +//! +//! # Safety +//! +//! See the `rustix::backend` module documentation for details. +#![allow(unsafe_code)] +#![allow(dead_code)] +#![allow(clippy::undocumented_unsafe_blocks)] + +use super::super::c; +use super::super::conv::fs::oflags_for_open_how; +use super::super::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, zero, +}; +#[cfg(target_pointer_width = "64")] +use super::super::conv::{loff_t, loff_t_from_u64, ret_u64}; +#[cfg(any( + target_arch = "aarch64", + target_arch = "riscv64", + target_arch = "mips64", + target_pointer_width = "32", +))] +use crate::fd::AsFd; +use crate::fd::{BorrowedFd, OwnedFd}; +use crate::ffi::CStr; +use crate::fs::{ + inotify, Access, Advice, AtFlags, FallocateFlags, FileType, FlockOperation, MemfdFlags, Mode, + OFlags, RenameFlags, ResolveFlags, SealFlags, Stat, StatFs, StatVfs, StatVfsMountFlags, + StatxFlags, Timestamps, XattrFlags, +}; +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::{transmute, zeroed, MaybeUninit}; +#[cfg(target_arch = "mips64")] +use linux_raw_sys::general::stat as linux_stat64; +use linux_raw_sys::general::{ + __kernel_fsid_t, __kernel_timespec, open_how, statx, AT_EACCESS, AT_FDCWD, AT_REMOVEDIR, + AT_SYMLINK_NOFOLLOW, F_ADD_SEALS, F_GETFL, F_GETLEASE, F_GETOWN, F_GETPIPE_SZ, F_GETSIG, + F_GET_SEALS, F_SETFL, F_SETPIPE_SZ, SEEK_CUR, SEEK_DATA, SEEK_END, SEEK_HOLE, SEEK_SET, + STATX__RESERVED, +}; +#[cfg(target_pointer_width = "32")] +use { + super::super::conv::{hi, lo, slice_just_addr}, + linux_raw_sys::general::stat64 as linux_stat64, + linux_raw_sys::general::timespec as __kernel_old_timespec, +}; + +#[inline] +pub(crate) fn open(filename: &CStr, flags: OFlags, mode: Mode) -> io::Result<OwnedFd> { + #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + { + openat(crate::fs::cwd().as_fd(), filename, flags, mode) + } + #[cfg(all( + target_pointer_width = "32", + not(any(target_arch = "aarch64", target_arch = "riscv64")), + ))] + unsafe { + ret_owned_fd(syscall_readonly!(__NR_open, filename, flags, mode)) + } + #[cfg(all( + target_pointer_width = "64", + not(any(target_arch = "aarch64", target_arch = "riscv64")), + ))] + unsafe { + ret_owned_fd(syscall_readonly!(__NR_open, filename, flags, mode)) + } +} + +#[inline] +pub(crate) fn openat( + dirfd: BorrowedFd<'_>, + filename: &CStr, + flags: OFlags, + mode: Mode, +) -> io::Result<OwnedFd> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret_owned_fd(syscall_readonly!(__NR_openat, dirfd, filename, flags, mode)) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_owned_fd(syscall_readonly!(__NR_openat, dirfd, filename, flags, mode)) + } +} + +#[inline] +pub(crate) fn openat2( + dirfd: BorrowedFd<'_>, + pathname: &CStr, + flags: OFlags, + mode: Mode, + resolve: ResolveFlags, +) -> io::Result<OwnedFd> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret_owned_fd(syscall_readonly!( + __NR_openat2, + dirfd, + pathname, + by_ref(&open_how { + flags: oflags_for_open_how(flags), + mode: u64::from(mode.bits()), + resolve: resolve.bits(), + }), + size_of::<open_how, _>() + )) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_owned_fd(syscall_readonly!( + __NR_openat2, + dirfd, + pathname, + by_ref(&open_how { + flags: oflags_for_open_how(flags), + mode: u64::from(mode.bits()), + resolve: resolve.bits(), + }), + size_of::<open_how, _>() + )) + } +} + +#[inline] +pub(crate) fn chmod(filename: &CStr, mode: Mode) -> io::Result<()> { + unsafe { + ret(syscall_readonly!( + __NR_fchmodat, + raw_fd(AT_FDCWD), + filename, + mode + )) + } +} + +#[inline] +pub(crate) fn chmodat( + dirfd: BorrowedFd<'_>, + filename: &CStr, + mode: Mode, + 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)) } +} + +#[inline] +pub(crate) fn fchmod(fd: BorrowedFd<'_>, mode: Mode) -> io::Result<()> { + unsafe { ret(syscall_readonly!(__NR_fchmod, fd, mode)) } +} + +#[inline] +pub(crate) fn chownat( + dirfd: BorrowedFd<'_>, + filename: &CStr, + owner: Option<Uid>, + group: Option<Gid>, + flags: AtFlags, +) -> io::Result<()> { + unsafe { + let (ow, gr) = crate::process::translate_fchown_args(owner, group); + ret(syscall_readonly!( + __NR_fchownat, + dirfd, + filename, + c_uint(ow), + c_uint(gr), + flags + )) + } +} + +#[inline] +pub(crate) fn fchown(fd: BorrowedFd<'_>, owner: Option<Uid>, group: Option<Gid>) -> io::Result<()> { + unsafe { + let (ow, gr) = crate::process::translate_fchown_args(owner, group); + ret(syscall_readonly!(__NR_fchown, fd, c_uint(ow), c_uint(gr))) + } +} + +#[inline] +pub(crate) fn mknodat( + dirfd: BorrowedFd<'_>, + filename: &CStr, + file_type: FileType, + mode: Mode, + dev: u64, +) -> io::Result<()> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret(syscall_readonly!( + __NR_mknodat, + dirfd, + filename, + (mode, file_type), + dev_t(dev)? + )) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret(syscall_readonly!( + __NR_mknodat, + dirfd, + filename, + (mode, file_type), + dev_t(dev) + )) + } +} + +#[inline] +pub(crate) fn seek(fd: BorrowedFd<'_>, pos: SeekFrom) -> io::Result<u64> { + let (whence, offset) = match pos { + SeekFrom::Start(pos) => { + let pos: u64 = pos; + // Silently cast; we'll get `EINVAL` if the value is negative. + (SEEK_SET, pos as i64) + } + SeekFrom::End(offset) => (SEEK_END, offset), + SeekFrom::Current(offset) => (SEEK_CUR, offset), + #[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) +} + +#[inline] +pub(crate) fn _seek(fd: BorrowedFd<'_>, offset: i64, whence: c::c_uint) -> io::Result<u64> { + #[cfg(target_pointer_width = "32")] + unsafe { + let mut result = MaybeUninit::<u64>::uninit(); + ret(syscall!( + __NR__llseek, + fd, + // Don't use the hi/lo functions here because Linux's llseek + // takes its 64-bit argument differently from everything else. + pass_usize((offset >> 32) as usize), + pass_usize(offset as usize), + &mut result, + c_uint(whence) + ))?; + Ok(result.assume_init()) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_u64(syscall_readonly!( + __NR_lseek, + fd, + loff_t(offset), + c_uint(whence) + )) + } +} + +#[inline] +pub(crate) fn tell(fd: BorrowedFd<'_>) -> io::Result<u64> { + _seek(fd, 0, SEEK_CUR).map(|x| x as u64) +} + +#[inline] +pub(crate) fn ftruncate(fd: BorrowedFd<'_>, length: u64) -> io::Result<()> { + // <https://github.com/torvalds/linux/blob/fcadab740480e0e0e9fa9bd272acd409884d431a/arch/arm64/kernel/sys32.c#L81-L83> + #[cfg(all( + target_pointer_width = "32", + any(target_arch = "arm", target_arch = "mips", target_arch = "powerpc"), + ))] + unsafe { + ret(syscall_readonly!( + __NR_ftruncate64, + fd, + zero(), + hi(length), + lo(length) + )) + } + #[cfg(all( + target_pointer_width = "32", + not(any(target_arch = "arm", target_arch = "mips", target_arch = "powerpc")), + ))] + unsafe { + ret(syscall_readonly!( + __NR_ftruncate64, + fd, + hi(length), + lo(length) + )) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret(syscall_readonly!( + __NR_ftruncate, + fd, + loff_t_from_u64(length) + )) + } +} + +#[inline] +pub(crate) fn fallocate( + fd: BorrowedFd<'_>, + mode: FallocateFlags, + offset: u64, + len: u64, +) -> io::Result<()> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret(syscall_readonly!( + __NR_fallocate, + fd, + mode, + hi(offset), + lo(offset), + hi(len), + lo(len) + )) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret(syscall_readonly!( + __NR_fallocate, + fd, + mode, + loff_t_from_u64(offset), + loff_t_from_u64(len) + )) + } +} + +#[inline] +pub(crate) fn fadvise(fd: BorrowedFd<'_>, pos: u64, len: u64, advice: Advice) -> io::Result<()> { + // On ARM, the arguments are reordered so that the len and pos argument + // pairs are aligned. And ARM has a custom syscall code for this. + #[cfg(target_arch = "arm")] + unsafe { + ret(syscall_readonly!( + __NR_arm_fadvise64_64, + fd, + advice, + hi(pos), + lo(pos), + hi(len), + lo(len) + )) + } + + // On powerpc, the arguments are reordered as on ARM. + #[cfg(target_arch = "powerpc")] + unsafe { + ret(syscall_readonly!( + __NR_fadvise64_64, + fd, + advice, + hi(pos), + lo(pos), + hi(len), + lo(len) + )) + } + // On mips, the arguments are not reordered, and padding is inserted + // instead to ensure alignment. + #[cfg(target_arch = "mips")] + unsafe { + ret(syscall_readonly!( + __NR_fadvise64, + fd, + zero(), + hi(pos), + lo(pos), + hi(len), + lo(len), + advice + )) + } + #[cfg(all( + target_pointer_width = "32", + not(any(target_arch = "arm", target_arch = "mips", target_arch = "powerpc")), + ))] + unsafe { + ret(syscall_readonly!( + __NR_fadvise64_64, + fd, + hi(pos), + lo(pos), + hi(len), + lo(len), + advice + )) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret(syscall_readonly!( + __NR_fadvise64, + fd, + loff_t_from_u64(pos), + loff_t_from_u64(len), + advice + )) + } +} + +#[inline] +pub(crate) fn fsync(fd: BorrowedFd<'_>) -> io::Result<()> { + unsafe { ret(syscall_readonly!(__NR_fsync, fd)) } +} + +#[inline] +pub(crate) fn fdatasync(fd: BorrowedFd<'_>) -> io::Result<()> { + unsafe { ret(syscall_readonly!(__NR_fdatasync, fd)) } +} + +#[inline] +pub(crate) fn flock(fd: BorrowedFd<'_>, operation: FlockOperation) -> io::Result<()> { + unsafe { + ret(syscall_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"))] + { + 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")))] + unsafe { + let mut result = MaybeUninit::<Stat>::uninit(); + ret(syscall!(__NR_fstat, fd, &mut result))?; + Ok(result.assume_init()) + } +} + +#[cfg(any(target_pointer_width = "32", target_arch = "mips64"))] +fn fstat_old(fd: BorrowedFd<'_>) -> io::Result<Stat> { + let mut result = MaybeUninit::<linux_stat64>::uninit(); + + #[cfg(target_arch = "mips64")] + unsafe { + ret(syscall!(__NR_fstat, fd, &mut result))?; + stat_to_stat(result.assume_init()) + } + + #[cfg(target_pointer_width = "32")] + unsafe { + ret(syscall!(__NR_fstat64, fd, &mut result))?; + stat_to_stat(result.assume_init()) + } +} + +#[inline] +pub(crate) fn stat(filename: &CStr) -> io::Result<Stat> { + // 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().as_fd(), + filename, + AtFlags::empty(), + StatxFlags::BASIC_STATS, + ) { + Ok(x) => statx_to_stat(x), + Err(io::Errno::NOSYS) => stat_old(filename), + Err(err) => Err(err), + } + } + + #[cfg(all(target_pointer_width = "64", not(target_arch = "mips64")))] + unsafe { + let mut result = MaybeUninit::<Stat>::uninit(); + ret(syscall!( + __NR_newfstatat, + raw_fd(AT_FDCWD), + filename, + &mut result, + c_uint(0) + ))?; + Ok(result.assume_init()) + } +} + +#[cfg(any(target_pointer_width = "32", target_arch = "mips64"))] +fn stat_old(filename: &CStr) -> io::Result<Stat> { + let mut result = MaybeUninit::<linux_stat64>::uninit(); + + #[cfg(target_arch = "mips64")] + unsafe { + ret(syscall!( + __NR_newfstatat, + raw_fd(AT_FDCWD), + filename, + &mut result, + c_uint(0) + ))?; + stat_to_stat(result.assume_init()) + } + + #[cfg(target_pointer_width = "32")] + unsafe { + ret(syscall!( + __NR_fstatat64, + raw_fd(AT_FDCWD), + filename, + &mut result, + c_uint(0) + ))?; + stat_to_stat(result.assume_init()) + } +} + +#[inline] +pub(crate) fn statat(dirfd: BorrowedFd<'_>, filename: &CStr, flags: AtFlags) -> io::Result<Stat> { + // See the comments in `fstat` about using `crate::fs::statx` here. + #[cfg(any(target_pointer_width = "32", target_arch = "mips64"))] + { + match crate::fs::statx(dirfd, filename, flags, StatxFlags::BASIC_STATS) { + Ok(x) => statx_to_stat(x), + Err(io::Errno::NOSYS) => statat_old(dirfd, filename, flags), + Err(err) => Err(err), + } + } + + #[cfg(all(target_pointer_width = "64", not(target_arch = "mips64")))] + unsafe { + let mut result = MaybeUninit::<Stat>::uninit(); + ret(syscall!( + __NR_newfstatat, + dirfd, + filename, + &mut result, + flags + ))?; + Ok(result.assume_init()) + } +} + +#[cfg(any(target_pointer_width = "32", target_arch = "mips64"))] +fn statat_old(dirfd: BorrowedFd<'_>, filename: &CStr, flags: AtFlags) -> io::Result<Stat> { + let mut result = MaybeUninit::<linux_stat64>::uninit(); + + #[cfg(target_arch = "mips64")] + unsafe { + ret(syscall!( + __NR_newfstatat, + dirfd, + filename, + &mut result, + flags + ))?; + stat_to_stat(result.assume_init()) + } + + #[cfg(target_pointer_width = "32")] + unsafe { + ret(syscall!( + __NR_fstatat64, + dirfd, + filename, + &mut result, + flags + ))?; + stat_to_stat(result.assume_init()) + } +} + +#[inline] +pub(crate) fn lstat(filename: &CStr) -> io::Result<Stat> { + // 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().as_fd(), + filename, + AtFlags::SYMLINK_NOFOLLOW, + StatxFlags::BASIC_STATS, + ) { + Ok(x) => statx_to_stat(x), + Err(io::Errno::NOSYS) => lstat_old(filename), + Err(err) => Err(err), + } + } + + #[cfg(all(target_pointer_width = "64", not(target_arch = "mips64")))] + unsafe { + let mut result = MaybeUninit::<Stat>::uninit(); + ret(syscall!( + __NR_newfstatat, + raw_fd(AT_FDCWD), + filename, + &mut result, + c_uint(AT_SYMLINK_NOFOLLOW) + ))?; + Ok(result.assume_init()) + } +} + +#[cfg(any(target_pointer_width = "32", target_arch = "mips64"))] +fn lstat_old(filename: &CStr) -> io::Result<Stat> { + let mut result = MaybeUninit::<linux_stat64>::uninit(); + + #[cfg(target_arch = "mips64")] + unsafe { + ret(syscall!( + __NR_newfstatat, + raw_fd(AT_FDCWD), + filename, + &mut result, + c_uint(AT_SYMLINK_NOFOLLOW) + ))?; + stat_to_stat(result.assume_init()) + } + + #[cfg(target_pointer_width = "32")] + unsafe { + ret(syscall!( + __NR_fstatat64, + raw_fd(AT_FDCWD), + filename, + &mut result, + c_uint(AT_SYMLINK_NOFOLLOW) + ))?; + stat_to_stat(result.assume_init()) + } +} + +/// Convert from a Linux `statx` value to rustix's `Stat`. +#[cfg(any(target_pointer_width = "32", target_arch = "mips64"))] +fn statx_to_stat(x: crate::fs::Statx) -> io::Result<Stat> { + Ok(Stat { + st_dev: crate::fs::makedev(x.stx_dev_major, x.stx_dev_minor), + st_mode: x.stx_mode.into(), + st_nlink: x.stx_nlink.into(), + st_uid: x.stx_uid.into(), + st_gid: x.stx_gid.into(), + st_rdev: crate::fs::makedev(x.stx_rdev_major, x.stx_rdev_minor), + st_size: x.stx_size.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_blksize: x.stx_blksize.into(), + st_blocks: x.stx_blocks.into(), + st_atime: x + .stx_atime + .tv_sec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + st_atime_nsec: x.stx_atime.tv_nsec.into(), + st_mtime: x + .stx_mtime + .tv_sec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + st_mtime_nsec: x.stx_mtime.tv_nsec.into(), + st_ctime: x + .stx_ctime + .tv_sec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + st_ctime_nsec: x.stx_ctime.tv_nsec.into(), + st_ino: x.stx_ino.into(), + }) +} + +/// Convert from a Linux `stat64` value to rustix's `Stat`. +#[cfg(target_pointer_width = "32")] +fn stat_to_stat(s64: linux_raw_sys::general::stat64) -> io::Result<Stat> { + Ok(Stat { + st_dev: s64.st_dev.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_mode: s64.st_mode.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_nlink: s64.st_nlink.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_uid: s64.st_uid.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_gid: s64.st_gid.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_rdev: s64.st_rdev.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_size: s64.st_size.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_blksize: s64.st_blksize.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_blocks: s64.st_blocks.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_atime: s64.st_atime.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_atime_nsec: s64 + .st_atime_nsec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + st_mtime: s64.st_mtime.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_mtime_nsec: s64 + .st_mtime_nsec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + st_ctime: s64.st_ctime.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_ctime_nsec: s64 + .st_ctime_nsec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + st_ino: s64.st_ino.try_into().map_err(|_| io::Errno::OVERFLOW)?, + }) +} + +/// Convert from a Linux `stat` value to rustix's `Stat`. +#[cfg(target_arch = "mips64")] +fn stat_to_stat(s: linux_raw_sys::general::stat) -> io::Result<Stat> { + Ok(Stat { + st_dev: s.st_dev.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_mode: s.st_mode.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_nlink: s.st_nlink.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_uid: s.st_uid.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_gid: s.st_gid.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_rdev: s.st_rdev.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_size: s.st_size.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_blksize: s.st_blksize.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_blocks: s.st_blocks.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_atime: s.st_atime.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_atime_nsec: s + .st_atime_nsec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + st_mtime: s.st_mtime.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_mtime_nsec: s + .st_mtime_nsec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + st_ctime: s.st_ctime.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_ctime_nsec: s + .st_ctime_nsec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + st_ino: s.st_ino.try_into().map_err(|_| io::Errno::OVERFLOW)?, + }) +} + +#[inline] +pub(crate) fn statx( + dirfd: BorrowedFd<'_>, + pathname: &CStr, + flags: AtFlags, + mask: StatxFlags, +) -> io::Result<statx> { + // If a future Linux kernel adds more fields to `struct statx` and users + // passing flags unknown to rustix in `StatxFlags`, we could end up + // writing outside of the buffer. To prevent this possibility, we mask off + // any flags that we don't know about. + // + // This includes `STATX__RESERVED`, which has a value that we know, but + // which could take on arbitrary new meaning in the future. Linux currently + // rejects this flag with `EINVAL`, so we do the same. + // + // This doesn't rely on `STATX_ALL` because [it's deprecated] and already + // doesn't represent all the known flags. + // + // [it's deprecated]: https://patchwork.kernel.org/project/linux-fsdevel/patch/20200505095915.11275-7-mszeredi@redhat.com/ + if (mask.bits() & STATX__RESERVED) == STATX__RESERVED { + return Err(io::Errno::INVAL); + } + let mask = mask & StatxFlags::all(); + + unsafe { + let mut statx_buf = MaybeUninit::<statx>::uninit(); + ret(syscall!( + __NR_statx, + dirfd, + pathname, + flags, + mask, + &mut statx_buf + ))?; + Ok(statx_buf.assume_init()) + } +} + +#[inline] +pub(crate) fn is_statx_available() -> bool { + unsafe { + // Call `statx` with null pointers so that if it fails for any reason + // other than `EFAULT`, we know it's not supported. + matches!( + ret(syscall!( + __NR_statx, + raw_fd(AT_FDCWD), + zero(), + zero(), + zero(), + zero() + )), + Err(io::Errno::FAULT) + ) + } +} + +#[inline] +pub(crate) fn fstatfs(fd: BorrowedFd<'_>) -> io::Result<StatFs> { + #[cfg(target_pointer_width = "32")] + unsafe { + let mut result = MaybeUninit::<StatFs>::uninit(); + ret(syscall!( + __NR_fstatfs64, + fd, + size_of::<StatFs, _>(), + &mut result + ))?; + Ok(result.assume_init()) + } + + #[cfg(target_pointer_width = "64")] + unsafe { + let mut result = MaybeUninit::<StatFs>::uninit(); + ret(syscall!(__NR_fstatfs, fd, &mut result))?; + Ok(result.assume_init()) + } +} + +#[inline] +pub(crate) fn fstatvfs(fd: BorrowedFd<'_>) -> io::Result<StatVfs> { + // Linux doesn't have an `fstatvfs` syscall; we have to do `fstatfs` and + // translate the fields as best we can. + let statfs = fstatfs(fd)?; + + Ok(statfs_to_statvfs(statfs)) +} + +#[inline] +pub(crate) fn statfs(filename: &CStr) -> io::Result<StatFs> { + #[cfg(target_pointer_width = "32")] + unsafe { + let mut result = MaybeUninit::<StatFs>::uninit(); + ret(syscall!( + __NR_statfs64, + filename, + size_of::<StatFs, _>(), + &mut result + ))?; + Ok(result.assume_init()) + } + #[cfg(target_pointer_width = "64")] + unsafe { + let mut result = MaybeUninit::<StatFs>::uninit(); + ret(syscall!(__NR_statfs, filename, &mut result))?; + Ok(result.assume_init()) + } +} + +#[inline] +pub(crate) fn statvfs(filename: &CStr) -> io::Result<StatVfs> { + // Linux doesn't have a `statvfs` syscall; we have to do `statfs` and + // translate the fields as best we can. + let statfs = statfs(filename)?; + + Ok(statfs_to_statvfs(statfs)) +} + +fn statfs_to_statvfs(statfs: StatFs) -> StatVfs { + let __kernel_fsid_t { val } = statfs.f_fsid; + let [f_fsid_val0, f_fsid_val1]: [i32; 2] = val; + + StatVfs { + f_bsize: statfs.f_bsize as u64, + f_frsize: if statfs.f_frsize != 0 { + statfs.f_frsize + } else { + statfs.f_bsize + } as u64, + f_blocks: statfs.f_blocks as u64, + f_bfree: statfs.f_bfree as u64, + f_bavail: statfs.f_bavail as u64, + f_files: statfs.f_files as u64, + f_ffree: statfs.f_ffree as u64, + f_favail: statfs.f_ffree as u64, + f_fsid: f_fsid_val0 as u32 as u64 | ((f_fsid_val1 as u32 as u64) << 32), + f_flag: unsafe { StatVfsMountFlags::from_bits_unchecked(statfs.f_flags as u64) }, + f_namemax: statfs.f_namelen as u64, + } +} + +#[inline] +pub(crate) fn readlink(path: &CStr, buf: &mut [u8]) -> io::Result<usize> { + let (buf_addr_mut, buf_len) = slice_mut(buf); + unsafe { + ret_usize(syscall!( + __NR_readlinkat, + raw_fd(AT_FDCWD), + path, + buf_addr_mut, + buf_len + )) + } +} + +#[inline] +pub(crate) fn readlinkat(dirfd: BorrowedFd<'_>, path: &CStr, buf: &mut [u8]) -> io::Result<usize> { + let (buf_addr_mut, buf_len) = slice_mut(buf); + unsafe { + ret_usize(syscall!( + __NR_readlinkat, + dirfd, + path, + buf_addr_mut, + buf_len + )) + } +} + +#[inline] +pub(crate) fn fcntl_getfl(fd: BorrowedFd<'_>) -> io::Result<OFlags> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret_c_uint(syscall_readonly!(__NR_fcntl64, fd, c_uint(F_GETFL))) + .map(OFlags::from_bits_truncate) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_c_uint(syscall_readonly!(__NR_fcntl, fd, c_uint(F_GETFL))) + .map(OFlags::from_bits_truncate) + } +} + +#[inline] +pub(crate) fn fcntl_setfl(fd: BorrowedFd<'_>, flags: OFlags) -> io::Result<()> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret(syscall_readonly!(__NR_fcntl64, fd, c_uint(F_SETFL), flags)) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret(syscall_readonly!(__NR_fcntl, fd, c_uint(F_SETFL), flags)) + } +} + +#[inline] +pub(crate) fn fcntl_getlease(fd: BorrowedFd<'_>) -> io::Result<c::c_int> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret_c_int(syscall_readonly!(__NR_fcntl64, fd, c_uint(F_GETLEASE))) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_c_int(syscall_readonly!(__NR_fcntl, fd, c_uint(F_GETLEASE))) + } +} + +#[inline] +pub(crate) fn fcntl_getown(fd: BorrowedFd<'_>) -> io::Result<c::c_int> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret_c_int(syscall_readonly!(__NR_fcntl64, fd, c_uint(F_GETOWN))) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_c_int(syscall_readonly!(__NR_fcntl, fd, c_uint(F_GETOWN))) + } +} + +#[inline] +pub(crate) fn fcntl_getsig(fd: BorrowedFd<'_>) -> io::Result<c::c_int> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret_c_int(syscall_readonly!(__NR_fcntl64, fd, c_uint(F_GETSIG))) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_c_int(syscall_readonly!(__NR_fcntl, fd, c_uint(F_GETSIG))) + } +} + +#[inline] +pub(crate) fn fcntl_getpipe_sz(fd: BorrowedFd<'_>) -> io::Result<usize> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret_usize(syscall_readonly!(__NR_fcntl64, fd, c_uint(F_GETPIPE_SZ))) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_usize(syscall_readonly!(__NR_fcntl, fd, c_uint(F_GETPIPE_SZ))) + } +} + +#[inline] +pub(crate) fn fcntl_setpipe_sz(fd: BorrowedFd<'_>, size: c::c_int) -> io::Result<usize> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret_usize(syscall_readonly!( + __NR_fcntl64, + fd, + c_uint(F_SETPIPE_SZ), + c_int(size) + )) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_usize(syscall_readonly!( + __NR_fcntl, + fd, + c_uint(F_SETPIPE_SZ), + c_int(size) + )) + } +} + +#[inline] +pub(crate) fn fcntl_get_seals(fd: BorrowedFd<'_>) -> io::Result<SealFlags> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret_c_int(syscall_readonly!(__NR_fcntl64, fd, c_uint(F_GET_SEALS))) + .map(|seals| SealFlags::from_bits_unchecked(seals as u32)) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_c_int(syscall_readonly!(__NR_fcntl, fd, c_uint(F_GET_SEALS))) + .map(|seals| SealFlags::from_bits_unchecked(seals as u32)) + } +} + +#[inline] +pub(crate) fn fcntl_add_seals(fd: BorrowedFd<'_>, seals: SealFlags) -> io::Result<()> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret(syscall_readonly!( + __NR_fcntl64, + fd, + c_uint(F_ADD_SEALS), + seals + )) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret(syscall_readonly!( + __NR_fcntl, + fd, + c_uint(F_ADD_SEALS), + seals + )) + } +} + +#[inline] +pub(crate) fn 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, + + ..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")] + unsafe { + ret(syscall_readonly!( + __NR_renameat2, + raw_fd(AT_FDCWD), + oldname, + raw_fd(AT_FDCWD), + newname, + c_uint(0) + )) + } + #[cfg(not(target_arch = "riscv64"))] + unsafe { + ret(syscall_readonly!( + __NR_renameat, + raw_fd(AT_FDCWD), + oldname, + raw_fd(AT_FDCWD), + newname + )) + } +} + +#[inline] +pub(crate) fn renameat( + old_dirfd: BorrowedFd<'_>, + oldname: &CStr, + new_dirfd: BorrowedFd<'_>, + newname: &CStr, +) -> io::Result<()> { + #[cfg(target_arch = "riscv64")] + unsafe { + ret(syscall_readonly!( + __NR_renameat2, + old_dirfd, + oldname, + new_dirfd, + newname, + c_uint(0) + )) + } + #[cfg(not(target_arch = "riscv64"))] + unsafe { + ret(syscall_readonly!( + __NR_renameat, + old_dirfd, + oldname, + new_dirfd, + newname + )) + } +} + +#[inline] +pub(crate) fn renameat2( + old_dirfd: BorrowedFd<'_>, + oldname: &CStr, + new_dirfd: BorrowedFd<'_>, + newname: &CStr, + flags: RenameFlags, +) -> io::Result<()> { + unsafe { + ret(syscall_readonly!( + __NR_renameat2, + old_dirfd, + oldname, + new_dirfd, + newname, + flags + )) + } +} + +#[inline] +pub(crate) fn unlink(pathname: &CStr) -> io::Result<()> { + unsafe { + ret(syscall_readonly!( + __NR_unlinkat, + raw_fd(AT_FDCWD), + pathname, + c_uint(0) + )) + } +} + +#[inline] +pub(crate) fn unlinkat(dirfd: BorrowedFd<'_>, pathname: &CStr, flags: AtFlags) -> io::Result<()> { + unsafe { ret(syscall_readonly!(__NR_unlinkat, dirfd, pathname, flags)) } +} + +#[inline] +pub(crate) fn rmdir(pathname: &CStr) -> io::Result<()> { + unsafe { + ret(syscall_readonly!( + __NR_unlinkat, + raw_fd(AT_FDCWD), + pathname, + c_uint(AT_REMOVEDIR) + )) + } +} + +#[inline] +pub(crate) fn link(oldname: &CStr, newname: &CStr) -> io::Result<()> { + unsafe { + ret(syscall_readonly!( + __NR_linkat, + raw_fd(AT_FDCWD), + oldname, + raw_fd(AT_FDCWD), + newname, + c_uint(0) + )) + } +} + +#[inline] +pub(crate) fn linkat( + old_dirfd: BorrowedFd<'_>, + oldname: &CStr, + new_dirfd: BorrowedFd<'_>, + newname: &CStr, + flags: AtFlags, +) -> io::Result<()> { + unsafe { + ret(syscall_readonly!( + __NR_linkat, + old_dirfd, + oldname, + new_dirfd, + newname, + flags + )) + } +} + +#[inline] +pub(crate) fn symlink(oldname: &CStr, newname: &CStr) -> io::Result<()> { + unsafe { + ret(syscall_readonly!( + __NR_symlinkat, + oldname, + raw_fd(AT_FDCWD), + newname + )) + } +} + +#[inline] +pub(crate) fn symlinkat(oldname: &CStr, dirfd: BorrowedFd<'_>, newname: &CStr) -> io::Result<()> { + unsafe { ret(syscall_readonly!(__NR_symlinkat, oldname, dirfd, newname)) } +} + +#[inline] +pub(crate) fn mkdir(pathname: &CStr, mode: Mode) -> io::Result<()> { + unsafe { + ret(syscall_readonly!( + __NR_mkdirat, + raw_fd(AT_FDCWD), + pathname, + mode + )) + } +} + +#[inline] +pub(crate) fn mkdirat(dirfd: BorrowedFd<'_>, pathname: &CStr, mode: Mode) -> io::Result<()> { + unsafe { ret(syscall_readonly!(__NR_mkdirat, dirfd, pathname, mode)) } +} + +#[inline] +pub(crate) fn getdents(fd: BorrowedFd<'_>, dirent: &mut [u8]) -> io::Result<usize> { + let (dirent_addr_mut, dirent_len) = slice_mut(dirent); + + unsafe { ret_usize(syscall!(__NR_getdents64, fd, dirent_addr_mut, dirent_len)) } +} + +#[inline] +pub(crate) fn 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<'_>, + pathname: &CStr, + times: &Timestamps, + flags: AtFlags, +) -> io::Result<()> { + _utimensat(dirfd, Some(pathname), times, flags) +} + +#[inline] +fn _utimensat( + dirfd: BorrowedFd<'_>, + pathname: Option<&CStr>, + times: &Timestamps, + flags: AtFlags, +) -> io::Result<()> { + // Assert that `Timestamps` has the expected layout. + let _ = unsafe { transmute::<Timestamps, [__kernel_timespec; 2]>(times.clone()) }; + + // `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, + pathname, + by_ref(times), + flags + )) { + Err(io::Errno::NOSYS) => _utimensat_old(dirfd, pathname, times, flags), + otherwise => otherwise, + } + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret(syscall_readonly!( + __NR_utimensat, + dirfd, + pathname, + by_ref(times), + flags + )) + } +} + +#[cfg(target_pointer_width = "32")] +unsafe fn _utimensat_old( + dirfd: BorrowedFd<'_>, + pathname: Option<&CStr>, + times: &Timestamps, + flags: AtFlags, +) -> io::Result<()> { + // See the comments in `rustix_clock_gettime_via_syscall` about + // emulation. + let old_times = [ + __kernel_old_timespec { + tv_sec: times + .last_access + .tv_sec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + tv_nsec: times + .last_access + .tv_nsec + .try_into() + .map_err(|_| io::Errno::INVAL)?, + }, + __kernel_old_timespec { + tv_sec: times + .last_modification + .tv_sec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + tv_nsec: times + .last_modification + .tv_nsec + .try_into() + .map_err(|_| io::Errno::INVAL)?, + }, + ]; + // The length of the array is fixed and not passed into the syscall. + let old_times_addr = slice_just_addr(&old_times); + ret(syscall_readonly!( + __NR_utimensat, + dirfd, + pathname, + old_times_addr, + flags + )) +} + +#[inline] +pub(crate) fn futimens(fd: BorrowedFd<'_>, times: &Timestamps) -> io::Result<()> { + _utimensat(fd, None, times, AtFlags::empty()) +} + +pub(crate) fn accessat( + dirfd: BorrowedFd<'_>, + path: &CStr, + access: Access, + flags: AtFlags, +) -> io::Result<()> { + 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::process::getuid() == crate::process::geteuid() + && crate::process::getgid() == crate::process::getegid()) + { + return unsafe { ret(syscall_readonly!(__NR_faccessat, dirfd, path, access)) }; + } + + Err(io::Errno::NOSYS) +} + +#[inline] +pub(crate) fn copy_file_range( + fd_in: BorrowedFd<'_>, + off_in: Option<&mut u64>, + fd_out: BorrowedFd<'_>, + off_out: Option<&mut u64>, + len: 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] +#[cfg(linux_kernel)] +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(linux_kernel)] +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<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) fn getxattr(path: &CStr, name: &CStr, value: &mut [u8]) -> io::Result<usize> { + let (value_addr_mut, value_len) = slice_mut(value); + unsafe { + ret_usize(syscall!( + __NR_getxattr, + path, + name, + value_addr_mut, + value_len + )) + } +} + +#[inline] +pub(crate) fn lgetxattr(path: &CStr, name: &CStr, value: &mut [u8]) -> io::Result<usize> { + let (value_addr_mut, value_len) = slice_mut(value); + unsafe { + ret_usize(syscall!( + __NR_lgetxattr, + path, + name, + value_addr_mut, + value_len + )) + } +} + +#[inline] +pub(crate) fn fgetxattr(fd: BorrowedFd<'_>, name: &CStr, value: &mut [u8]) -> io::Result<usize> { + let (value_addr_mut, value_len) = slice_mut(value); + unsafe { + ret_usize(syscall!( + __NR_fgetxattr, + fd, + name, + value_addr_mut, + value_len + )) + } +} + +#[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) fn listxattr(path: &CStr, list: &mut [c::c_char]) -> io::Result<usize> { + let (list_addr_mut, list_len) = slice_mut(list); + unsafe { ret_usize(syscall!(__NR_listxattr, path, list_addr_mut, list_len)) } +} + +#[inline] +pub(crate) fn llistxattr(path: &CStr, list: &mut [c::c_char]) -> io::Result<usize> { + let (list_addr_mut, list_len) = slice_mut(list); + unsafe { ret_usize(syscall!(__NR_llistxattr, path, list_addr_mut, list_len)) } +} + +#[inline] +pub(crate) fn flistxattr(fd: BorrowedFd<'_>, list: &mut [c::c_char]) -> io::Result<usize> { + let (list_addr_mut, list_len) = slice_mut(list); + unsafe { ret_usize(syscall!(__NR_flistxattr, fd, list_addr_mut, list_len)) } +} + +#[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)) } +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/fs/types.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/fs/types.rs new file mode 100644 index 000000000..191cc63d3 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/fs/types.rs @@ -0,0 +1,773 @@ +use super::super::c; +use bitflags::bitflags; + +bitflags! { + /// `*_OK` constants for use with [`accessat`]. + /// + /// [`accessat`]: fn.accessat.html + pub struct Access: c::c_uint { + /// `R_OK` + const READ_OK = linux_raw_sys::general::R_OK; + + /// `W_OK` + const WRITE_OK = linux_raw_sys::general::W_OK; + + /// `X_OK` + const EXEC_OK = linux_raw_sys::general::X_OK; + + /// `F_OK` + const EXISTS = linux_raw_sys::general::F_OK; + } +} + +bitflags! { + /// `AT_*` constants for use with [`openat`], [`statat`], and other `*at` + /// functions. + /// + /// [`openat`]: crate::fs::openat + /// [`statat`]: crate::fs::statat + pub struct AtFlags: c::c_uint { + /// `AT_REMOVEDIR` + const REMOVEDIR = linux_raw_sys::general::AT_REMOVEDIR; + + /// `AT_SYMLINK_FOLLOW` + const SYMLINK_FOLLOW = linux_raw_sys::general::AT_SYMLINK_FOLLOW; + + /// `AT_SYMLINK_NOFOLLOW` + const SYMLINK_NOFOLLOW = linux_raw_sys::general::AT_SYMLINK_NOFOLLOW; + + /// `AT_EMPTY_PATH` + const EMPTY_PATH = linux_raw_sys::general::AT_EMPTY_PATH; + + /// `AT_EACCESS` + const EACCESS = linux_raw_sys::general::AT_EACCESS; + + /// `AT_STATX_SYNC_AS_STAT` + const STATX_SYNC_AS_STAT = linux_raw_sys::general::AT_STATX_SYNC_AS_STAT; + + /// `AT_STATX_FORCE_SYNC` + const STATX_FORCE_SYNC = linux_raw_sys::general::AT_STATX_FORCE_SYNC; + + /// `AT_STATX_DONT_SYNC` + const STATX_DONT_SYNC = linux_raw_sys::general::AT_STATX_DONT_SYNC; + } +} + +bitflags! { + /// `S_I*` constants for use with [`openat`], [`chmodat`], and [`fchmod`]. + /// + /// [`openat`]: crate::fs::openat + /// [`chmodat`]: crate::fs::chmodat + /// [`fchmod`]: crate::fs::fchmod + pub struct Mode: RawMode { + /// `S_IRWXU` + const RWXU = linux_raw_sys::general::S_IRWXU; + + /// `S_IRUSR` + const RUSR = linux_raw_sys::general::S_IRUSR; + + /// `S_IWUSR` + const WUSR = linux_raw_sys::general::S_IWUSR; + + /// `S_IXUSR` + const XUSR = linux_raw_sys::general::S_IXUSR; + + /// `S_IRWXG` + const RWXG = linux_raw_sys::general::S_IRWXG; + + /// `S_IRGRP` + const RGRP = linux_raw_sys::general::S_IRGRP; + + /// `S_IWGRP` + const WGRP = linux_raw_sys::general::S_IWGRP; + + /// `S_IXGRP` + const XGRP = linux_raw_sys::general::S_IXGRP; + + /// `S_IRWXO` + const RWXO = linux_raw_sys::general::S_IRWXO; + + /// `S_IROTH` + const ROTH = linux_raw_sys::general::S_IROTH; + + /// `S_IWOTH` + const WOTH = linux_raw_sys::general::S_IWOTH; + + /// `S_IXOTH` + const XOTH = linux_raw_sys::general::S_IXOTH; + + /// `S_ISUID` + const SUID = linux_raw_sys::general::S_ISUID; + + /// `S_ISGID` + const SGID = linux_raw_sys::general::S_ISGID; + + /// `S_ISVTX` + const SVTX = linux_raw_sys::general::S_ISVTX; + } +} + +impl Mode { + /// Construct a `Mode` from the mode bits of the `st_mode` field of a + /// `Stat`. + #[inline] + pub const fn from_raw_mode(st_mode: RawMode) -> Self { + Self::from_bits_truncate(st_mode) + } + + /// Construct an `st_mode` value from `Stat`. + #[inline] + pub const fn as_raw_mode(self) -> RawMode { + self.bits() + } +} + +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 + pub struct OFlags: c::c_uint { + /// `O_ACCMODE` + const ACCMODE = linux_raw_sys::general::O_ACCMODE; + + /// Similar to `ACCMODE`, but just includes the read/write flags, and + /// no other flags. + /// + /// Some implementations include `O_PATH` in `O_ACCMODE`, when + /// sometimes we really just want the read/write bits. Caution is + /// indicated, as the presence of `O_PATH` may mean that the read/write + /// bits don't have their usual meaning. + const RWMODE = linux_raw_sys::general::O_RDONLY | + linux_raw_sys::general::O_WRONLY | + linux_raw_sys::general::O_RDWR; + + /// `O_APPEND` + const APPEND = linux_raw_sys::general::O_APPEND; + + /// `O_CREAT` + #[doc(alias = "CREAT")] + const CREATE = linux_raw_sys::general::O_CREAT; + + /// `O_DIRECTORY` + const DIRECTORY = linux_raw_sys::general::O_DIRECTORY; + + /// `O_DSYNC`. Linux 2.6.32 only supports `O_SYNC`. + const DSYNC = linux_raw_sys::general::O_SYNC; + + /// `O_EXCL` + const EXCL = linux_raw_sys::general::O_EXCL; + + /// `O_FSYNC`. Linux 2.6.32 only supports `O_SYNC`. + const FSYNC = linux_raw_sys::general::O_SYNC; + + /// `O_NOFOLLOW` + const NOFOLLOW = linux_raw_sys::general::O_NOFOLLOW; + + /// `O_NONBLOCK` + const NONBLOCK = linux_raw_sys::general::O_NONBLOCK; + + /// `O_RDONLY` + const RDONLY = linux_raw_sys::general::O_RDONLY; + + /// `O_WRONLY` + const WRONLY = linux_raw_sys::general::O_WRONLY; + + /// `O_RDWR` + const RDWR = linux_raw_sys::general::O_RDWR; + + /// `O_NOCTTY` + const NOCTTY = linux_raw_sys::general::O_NOCTTY; + + /// `O_RSYNC`. Linux 2.6.32 only supports `O_SYNC`. + const RSYNC = linux_raw_sys::general::O_SYNC; + + /// `O_SYNC` + const SYNC = linux_raw_sys::general::O_SYNC; + + /// `O_TRUNC` + const TRUNC = linux_raw_sys::general::O_TRUNC; + + /// `O_PATH` + const PATH = linux_raw_sys::general::O_PATH; + + /// `O_CLOEXEC` + const CLOEXEC = linux_raw_sys::general::O_CLOEXEC; + + /// `O_TMPFILE` + const TMPFILE = linux_raw_sys::general::O_TMPFILE; + + /// `O_NOATIME` + const NOATIME = linux_raw_sys::general::O_NOATIME; + + /// `O_DIRECT` + const DIRECT = linux_raw_sys::general::O_DIRECT; + } +} + +bitflags! { + /// `RESOLVE_*` constants for use with [`openat2`]. + /// + /// [`openat2`]: crate::fs::openat2 + #[derive(Default)] + pub struct ResolveFlags: u64 { + /// `RESOLVE_NO_XDEV` + const NO_XDEV = linux_raw_sys::general::RESOLVE_NO_XDEV as u64; + + /// `RESOLVE_NO_MAGICLINKS` + const NO_MAGICLINKS = linux_raw_sys::general::RESOLVE_NO_MAGICLINKS as u64; + + /// `RESOLVE_NO_SYMLINKS` + const NO_SYMLINKS = linux_raw_sys::general::RESOLVE_NO_SYMLINKS as u64; + + /// `RESOLVE_BENEATH` + const BENEATH = linux_raw_sys::general::RESOLVE_BENEATH as u64; + + /// `RESOLVE_IN_ROOT` + const IN_ROOT = linux_raw_sys::general::RESOLVE_IN_ROOT as u64; + + /// `RESOLVE_CACHED` (since Linux 5.12) + const CACHED = linux_raw_sys::general::RESOLVE_CACHED as u64; + } +} + +bitflags! { + /// `RENAME_*` constants for use with [`renameat_with`]. + /// + /// [`renameat_with`]: crate::fs::renameat_with + pub struct RenameFlags: c::c_uint { + /// `RENAME_EXCHANGE` + const EXCHANGE = linux_raw_sys::general::RENAME_EXCHANGE; + + /// `RENAME_NOREPLACE` + const NOREPLACE = linux_raw_sys::general::RENAME_NOREPLACE; + + /// `RENAME_WHITEOUT` + const WHITEOUT = linux_raw_sys::general::RENAME_WHITEOUT; + } +} + +/// `S_IF*` constants for use with [`mknodat`] and [`Stat`]'s `st_mode` field. +/// +/// [`mknodat`]: crate::fs::mknodat +/// [`Stat`]: crate::fs::Stat +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum FileType { + /// `S_IFREG` + RegularFile = linux_raw_sys::general::S_IFREG as isize, + + /// `S_IFDIR` + Directory = linux_raw_sys::general::S_IFDIR as isize, + + /// `S_IFLNK` + Symlink = linux_raw_sys::general::S_IFLNK as isize, + + /// `S_IFIFO` + #[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 `Stat`. + #[inline] + pub const fn as_raw_mode(self) -> RawMode { + match self { + Self::RegularFile => linux_raw_sys::general::S_IFREG, + Self::Directory => linux_raw_sys::general::S_IFDIR, + Self::Symlink => linux_raw_sys::general::S_IFLNK, + Self::Fifo => linux_raw_sys::general::S_IFIFO, + Self::Socket => linux_raw_sys::general::S_IFSOCK, + Self::CharacterDevice => linux_raw_sys::general::S_IFCHR, + Self::BlockDevice => linux_raw_sys::general::S_IFBLK, + Self::Unknown => linux_raw_sys::general::S_IFMT, + } + } + + /// Construct a `FileType` from the `d_type` field of a `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 + pub struct MemfdFlags: c::c_uint { + /// `MFD_CLOEXEC` + const CLOEXEC = linux_raw_sys::general::MFD_CLOEXEC; + + /// `MFD_ALLOW_SEALING` + const ALLOW_SEALING = linux_raw_sys::general::MFD_ALLOW_SEALING; + + /// `MFD_HUGETLB` (since Linux 4.14) + const HUGETLB = linux_raw_sys::general::MFD_HUGETLB; + + /// `MFD_HUGE_64KB` + const HUGE_64KB = linux_raw_sys::general::MFD_HUGE_64KB; + /// `MFD_HUGE_512JB` + const HUGE_512KB = linux_raw_sys::general::MFD_HUGE_512KB; + /// `MFD_HUGE_1MB` + const HUGE_1MB = linux_raw_sys::general::MFD_HUGE_1MB; + /// `MFD_HUGE_2MB` + const HUGE_2MB = linux_raw_sys::general::MFD_HUGE_2MB; + /// `MFD_HUGE_8MB` + const HUGE_8MB = linux_raw_sys::general::MFD_HUGE_8MB; + /// `MFD_HUGE_16MB` + const HUGE_16MB = linux_raw_sys::general::MFD_HUGE_16MB; + /// `MFD_HUGE_32MB` + const HUGE_32MB = linux_raw_sys::general::MFD_HUGE_32MB; + /// `MFD_HUGE_256MB` + const HUGE_256MB = linux_raw_sys::general::MFD_HUGE_256MB; + /// `MFD_HUGE_512MB` + const HUGE_512MB = linux_raw_sys::general::MFD_HUGE_512MB; + /// `MFD_HUGE_1GB` + const HUGE_1GB = linux_raw_sys::general::MFD_HUGE_1GB; + /// `MFD_HUGE_2GB` + const HUGE_2GB = linux_raw_sys::general::MFD_HUGE_2GB; + /// `MFD_HUGE_16GB` + const HUGE_16GB = linux_raw_sys::general::MFD_HUGE_16GB; + } +} + +bitflags! { + /// `F_SEAL_*` constants for use with [`fcntl_add_seals`] and + /// [`fcntl_get_seals`]. + /// + /// [`fcntl_add_seals`]: crate::fs::fcntl_add_seals + /// [`fcntl_get_seals`]: crate::fs::fcntl_get_seals + pub struct SealFlags: u32 { + /// `F_SEAL_SEAL`. + const SEAL = linux_raw_sys::general::F_SEAL_SEAL; + /// `F_SEAL_SHRINK`. + const SHRINK = linux_raw_sys::general::F_SEAL_SHRINK; + /// `F_SEAL_GROW`. + const GROW = linux_raw_sys::general::F_SEAL_GROW; + /// `F_SEAL_WRITE`. + const WRITE = linux_raw_sys::general::F_SEAL_WRITE; + /// `F_SEAL_FUTURE_WRITE` (since Linux 5.1) + const FUTURE_WRITE = linux_raw_sys::general::F_SEAL_FUTURE_WRITE; + } +} + +bitflags! { + /// `STATX_*` constants for use with [`statx`]. + /// + /// [`statx`]: crate::fs::statx + pub struct StatxFlags: u32 { + /// `STATX_TYPE` + const TYPE = linux_raw_sys::general::STATX_TYPE; + + /// `STATX_MODE` + const MODE = linux_raw_sys::general::STATX_MODE; + + /// `STATX_NLINK` + const NLINK = linux_raw_sys::general::STATX_NLINK; + + /// `STATX_UID` + const UID = linux_raw_sys::general::STATX_UID; + + /// `STATX_GID` + const GID = linux_raw_sys::general::STATX_GID; + + /// `STATX_ATIME` + const ATIME = linux_raw_sys::general::STATX_ATIME; + + /// `STATX_MTIME` + const MTIME = linux_raw_sys::general::STATX_MTIME; + + /// `STATX_CTIME` + const CTIME = linux_raw_sys::general::STATX_CTIME; + + /// `STATX_INO` + const INO = linux_raw_sys::general::STATX_INO; + + /// `STATX_SIZE` + const SIZE = linux_raw_sys::general::STATX_SIZE; + + /// `STATX_BLOCKS` + const BLOCKS = linux_raw_sys::general::STATX_BLOCKS; + + /// `STATX_BASIC_STATS` + const BASIC_STATS = linux_raw_sys::general::STATX_BASIC_STATS; + + /// `STATX_BTIME` + const BTIME = linux_raw_sys::general::STATX_BTIME; + + /// `STATX_MNT_ID` (since Linux 5.8) + const MNT_ID = linux_raw_sys::general::STATX_MNT_ID; + + /// `STATX_ALL` + const ALL = linux_raw_sys::general::STATX_ALL; + } +} + +bitflags! { + /// `FALLOC_FL_*` constants for use with [`fallocate`]. + /// + /// [`fallocate`]: crate::fs::fallocate + pub struct FallocateFlags: u32 { + /// `FALLOC_FL_KEEP_SIZE` + const KEEP_SIZE = linux_raw_sys::general::FALLOC_FL_KEEP_SIZE; + /// `FALLOC_FL_PUNCH_HOLE` + const PUNCH_HOLE = linux_raw_sys::general::FALLOC_FL_PUNCH_HOLE; + /// `FALLOC_FL_NO_HIDE_STALE` + const NO_HIDE_STALE = linux_raw_sys::general::FALLOC_FL_NO_HIDE_STALE; + /// `FALLOC_FL_COLLAPSE_RANGE` + const COLLAPSE_RANGE = linux_raw_sys::general::FALLOC_FL_COLLAPSE_RANGE; + /// `FALLOC_FL_ZERO_RANGE` + const ZERO_RANGE = linux_raw_sys::general::FALLOC_FL_ZERO_RANGE; + /// `FALLOC_FL_INSERT_RANGE` + const INSERT_RANGE = linux_raw_sys::general::FALLOC_FL_INSERT_RANGE; + /// `FALLOC_FL_UNSHARE_RANGE` + const UNSHARE_RANGE = linux_raw_sys::general::FALLOC_FL_UNSHARE_RANGE; + } +} + +bitflags! { + /// `ST_*` constants for use with [`StatVfs`]. + pub struct StatVfsMountFlags: u64 { + /// `ST_MANDLOCK` + const MANDLOCK = linux_raw_sys::general::MS_MANDLOCK as u64; + + /// `ST_NOATIME` + const NOATIME = linux_raw_sys::general::MS_NOATIME as u64; + + /// `ST_NODEV` + const NODEV = linux_raw_sys::general::MS_NODEV as u64; + + /// `ST_NODIRATIME` + const NODIRATIME = linux_raw_sys::general::MS_NODIRATIME as u64; + + /// `ST_NOEXEC` + const NOEXEC = linux_raw_sys::general::MS_NOEXEC as u64; + + /// `ST_NOSUID` + const NOSUID = linux_raw_sys::general::MS_NOSUID as u64; + + /// `ST_RDONLY` + const RDONLY = linux_raw_sys::general::MS_RDONLY as u64; + + /// `ST_RELATIME` + const RELATIME = linux_raw_sys::general::MS_RELATIME as u64; + + /// `ST_SYNCHRONOUS` + const SYNCHRONOUS = linux_raw_sys::general::MS_SYNCHRONOUS as u64; + } +} + +/// `LOCK_*` constants for use with [`flock`] 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, and mips64, Linux's `struct stat64` has a 32-bit `st_mtime` and +// friends, so we use our own struct, populated from `statx` where possible, to +// avoid the y2038 bug. +#[cfg(any(target_pointer_width = "32", target_arch = "mips64"))] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +#[allow(missing_docs)] +pub struct Stat { + pub st_dev: u64, + pub st_mode: u32, + pub st_nlink: u32, + pub st_uid: u32, + pub st_gid: u32, + pub st_rdev: u64, + pub st_size: i64, + pub st_blksize: u32, + pub st_blocks: u64, + pub st_atime: u64, + pub st_atime_nsec: u32, + pub st_mtime: u64, + pub st_mtime_nsec: u32, + pub st_ctime: u64, + pub st_ctime_nsec: u32, + pub st_ino: u64, +} + +/// `struct stat` for use with [`statat`] and [`fstat`]. +/// +/// [`statat`]: crate::fs::statat +/// [`fstat`]: crate::fs::fstat +#[cfg(all(target_pointer_width = "64", not(target_arch = "mips64")))] +pub type Stat = linux_raw_sys::general::stat; + +/// `struct statfs` for use with [`statfs`] and [`fstatfs`]. +/// +/// [`statfs`]: crate::fs::statfs +/// [`fstatfs`]: crate::fs::fstatfs +#[allow(clippy::module_name_repetitions)] +pub type StatFs = linux_raw_sys::general::statfs64; + +/// `struct statvfs` for use with [`statvfs`] and [`fstatvfs`]. +/// +/// [`statvfs`]: crate::fs::statvfs +/// [`fstatvfs`]: crate::fs::fstatvfs +#[allow(missing_docs)] +pub struct StatVfs { + pub f_bsize: u64, + pub f_frsize: u64, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + pub f_fsid: u64, + pub f_flag: StatVfsMountFlags, + pub f_namemax: u64, +} + +/// `struct statx` for use with [`statx`]. +/// +/// [`statx`]: crate::fs::statx +pub type Statx = linux_raw_sys::general::statx; + +/// `struct statx_timestamp` for use with [`Statx`]. +pub type StatxTimestamp = linux_raw_sys::general::statx_timestamp; + +/// `mode_t` +#[cfg(not(any( + target_arch = "x86", + target_arch = "sparc", + target_arch = "avr", + target_arch = "arm", +)))] +pub type RawMode = linux_raw_sys::general::__kernel_mode_t; + +/// `mode_t` +#[cfg(any( + target_arch = "x86", + target_arch = "sparc", + target_arch = "avr", + target_arch = "arm", +))] +// Don't use `__kernel_mode_t` since it's `u16` which differs from `st_size`. +pub type RawMode = c::c_uint; + +/// `dev_t` +// Within the kernel the dev_t is 32-bit, but userspace uses a 64-bit field. +pub type Dev = u64; + +/// `__fsword_t` +#[cfg(not(target_arch = "mips64"))] +pub type FsWord = linux_raw_sys::general::__fsword_t; + +/// `__fsword_t` +#[cfg(target_arch = "mips64")] +pub type FsWord = i64; + +#[cfg(linux_kernel)] +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; + + /// `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; + } +} + +#[cfg(linux_kernel)] +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(linux_kernel)] +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(linux_kernel)] +pub(crate) struct MountFlagsArg(pub(crate) c::c_uint); + +#[cfg(linux_kernel)] +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-0.37.22/src/backend/linux_raw/io/epoll.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/io/epoll.rs new file mode 100644 index 000000000..ac085db4a --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/io/epoll.rs @@ -0,0 +1,352 @@ +//! epoll support. +//! +//! This is an experiment, and it isn't yet clear whether epoll is the right +//! level of abstraction at which to introduce safety. But it works fairly well +//! in simple examples 🙂. +//! +//! # Examples +//! +//! ```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, 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. +//! let listen_sock = socket(AddressFamily::INET, SocketType::STREAM, Protocol::default())?; +//! bind_v4(&listen_sock, &SocketAddrV4::new(Ipv4Addr::LOCALHOST, 0))?; +//! listen(&listen_sock, 1)?; +//! +//! // Create an epoll object. Using `Owning` here means the epoll object will +//! // take ownership of the file descriptors registered with it. +//! let epoll = epoll::epoll_create(epoll::CreateFlags::CLOEXEC)?; +//! +//! // Register the socket with the epoll object. +//! 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::epoll_wait(&epoll, &mut event_list, -1)?; +//! for (_event_flags, target) in &event_list { +//! 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(&listen_sock)?; +//! ioctl_fionbio(&conn_sock, true)?; +//! 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. +//! let target = sockets.remove(&target).unwrap(); +//! write(&target, b"hello\n")?; +//! let _ = epoll::epoll_del(&epoll, &target)?; +//! } +//! } +//! } +//! # } +//! # #[cfg(not(feature = "net"))] +//! # fn main() {} +//! ``` + +#![allow(unsafe_code)] + +use super::super::c; +use crate::backend::io::syscalls; +use crate::fd::{AsFd, AsRawFd, OwnedFd}; +use crate::io; +use alloc::vec::Vec; +use bitflags::bitflags; +use core::slice; + +bitflags! { + /// `EPOLL_*` for use with [`Epoll::new`]. + pub struct CreateFlags: c::c_uint { + /// `EPOLL_CLOEXEC` + const CLOEXEC = linux_raw_sys::general::EPOLL_CLOEXEC; + } +} + +bitflags! { + /// `EPOLL*` for use with [`Epoll::add`]. + #[derive(Default)] + pub struct EventFlags: u32 { + /// `EPOLLIN` + const IN = linux_raw_sys::general::EPOLLIN as u32; + + /// `EPOLLOUT` + const OUT = linux_raw_sys::general::EPOLLOUT as u32; + + /// `EPOLLPRI` + const PRI = linux_raw_sys::general::EPOLLPRI as u32; + + /// `EPOLLERR` + const ERR = linux_raw_sys::general::EPOLLERR as u32; + + /// `EPOLLHUP` + const HUP = linux_raw_sys::general::EPOLLHUP as u32; + + /// `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; + } +} + +/// `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 epoll_create(flags: CreateFlags) -> io::Result<OwnedFd> { + syscalls::epoll_create(flags) +} + +/// `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`. +/// +/// 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<dyn SystemResource>`, then `epoll` can be thought to maintain a +/// `Weak<dyn SystemResource>` to the file descriptor. +#[doc(alias = "epoll_ctl")] +#[inline] +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, + }, + ) + } +} + +/// `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")] +#[inline] +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, + }, + ) + } +} + +/// `epoll_ctl(self, EPOLL_CTL_DEL, target, NULL)`—Removes an element in +/// this `Epoll`. +/// +/// This also returns the owning `Data`. +#[doc(alias = "epoll_ctl")] +#[inline] +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) + } +} + +/// `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. +#[inline] +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<'a> { + iter: slice::Iter<'a, Event>, +} + +impl<'a> Iterator for Iter<'a> { + type Item = (EventFlags, u64); + + #[inline] + fn next(&mut self) -> Option<Self::Item> { + self.iter + .next() + .map(|event| (event.event_flags, event.data)) + } +} + +/// A record of an event that occurred. +#[repr(C)] +#[cfg_attr(target_arch = "x86_64", repr(packed))] +struct Event { + // Match the layout of `linux_raw_sys::general::epoll_event`. We just use a + // `u64` instead of the full union. + event_flags: EventFlags, + data: u64, +} + +/// A vector of `Event`s, plus context for interpreting them. +pub struct EventVec { + events: Vec<Event>, +} + +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), + } + } + + /// Returns the current `Event` capacity of this `EventVec`. + #[inline] + pub fn capacity(&self) -> usize { + self.events.capacity() + } + + /// Reserves enough memory for at least `additional` more `Event`s. + #[inline] + pub fn reserve(&mut self, additional: usize) { + self.events.reserve(additional); + } + + /// Reserves enough memory for exactly `additional` more `Event`s. + #[inline] + pub fn reserve_exact(&mut self, additional: usize) { + self.events.reserve_exact(additional); + } + + /// Clears all the `Events` out of this `EventVec`. + #[inline] + pub fn clear(&mut self) { + self.events.clear(); + } + + /// Shrinks the capacity of this `EventVec` as much as possible. + #[inline] + pub fn shrink_to_fit(&mut self) { + self.events.shrink_to_fit(); + } + + /// Returns an iterator over the `Event`s in this `EventVec`. + #[inline] + pub fn iter(&self) -> Iter<'_> { + Iter { + iter: self.events.iter(), + } + } + + /// Returns the number of `Event`s logically contained in this `EventVec`. + #[inline] + pub fn len(&mut self) -> usize { + self.events.len() + } + + /// Tests whether this `EventVec` is logically empty. + #[inline] + pub fn is_empty(&mut self) -> bool { + self.events.is_empty() + } +} + +impl<'a> IntoIterator for &'a EventVec { + type IntoIter = Iter<'a>; + type Item = (EventFlags, u64); + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/io/errno.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/io/errno.rs new file mode 100644 index 000000000..a6d30ca3e --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/io/errno.rs @@ -0,0 +1,524 @@ +//! The `rustix` `Errno` type. +//! +//! This type holds an OS error code, which conceptually corresponds to an +//! `errno` value. +//! +//! # Safety +//! +//! Linux uses error codes in `-4095..0`; we use rustc attributes to describe +//! this restricted range of values. +#![allow(unsafe_code)] +#![cfg_attr(not(rustc_attrs), allow(unused_unsafe))] + +use super::super::c; +use crate::backend::fd::RawFd; +use crate::backend::reg::{RetNumber, RetReg}; +use crate::io; +use linux_raw_sys::errno; + +/// The error type for `rustix` APIs. +/// +/// This is similar to `std::io::Error`, but only holds an OS error code, +/// and no extra error value. +#[repr(transparent)] +#[doc(alias = "errno")] +#[derive(Eq, PartialEq, Hash, Copy, Clone)] +// Linux returns negated error codes, and we leave them in negated form, so +// error codes are in `-4095..0`. +#[cfg_attr(rustc_attrs, rustc_layout_scalar_valid_range_start(0xf001))] +#[cfg_attr(rustc_attrs, rustc_layout_scalar_valid_range_end(0xffff))] +pub struct Errno(u16); + +impl Errno { + /// Extract an `Errno` value from a `std::io::Error`. + /// + /// This isn't a `From` conversion because it's expected to be relatively + /// uncommon. + #[cfg(feature = "std")] + #[inline] + pub fn from_io_error(io_err: &std::io::Error) -> Option<Self> { + io_err.raw_os_error().and_then(|raw| { + // `std::io::Error` could theoretically have arbitrary "OS error" + // values, so check that they're in Linux's range. + if (1..4096).contains(&raw) { + Some(Self::from_errno(raw as u32)) + } else { + None + } + }) + } + + /// Extract the raw OS error number from this error. + #[inline] + pub const fn raw_os_error(self) -> i32 { + (self.0 as i16 as i32).wrapping_neg() + } + + /// Construct an `Errno` from a raw OS error number. + #[inline] + pub const fn from_raw_os_error(raw: i32) -> Self { + Self::from_errno(raw as u32) + } + + /// Convert from a C `errno` value (which is positive) to an `Errno`. + const fn from_errno(raw: u32) -> Self { + // We store error values in negated form, so that we don't have to + // negate them after every syscall. + let encoded = raw.wrapping_neg() as u16; + + // TODO: Use Range::contains, once that's `const`. + const_assert!(encoded >= 0xf001); + + // SAFETY: Linux syscalls return negated error values in the range + // `-4095..0`, which we just asserted. + unsafe { Self(encoded) } + } +} + +/// Check for an error from the result of a syscall which encodes a +/// `c::c_int` on success. +#[inline] +pub(in crate::backend) fn try_decode_c_int<Num: RetNumber>( + raw: RetReg<Num>, +) -> io::Result<c::c_int> { + if raw.is_in_range(-4095..0) { + // SAFETY: `raw` must be in `-4095..0`, and we just checked that raw is + // in that range. + return Err(unsafe { Errno(raw.decode_error_code()) }); + } + + Ok(raw.decode_c_int()) +} + +/// Check for an error from the result of a syscall which encodes a +/// `c::c_uint` on success. +#[inline] +pub(in crate::backend) fn try_decode_c_uint<Num: RetNumber>( + raw: RetReg<Num>, +) -> io::Result<c::c_uint> { + if raw.is_in_range(-4095..0) { + // SAFETY: `raw` must be in `-4095..0`, and we just checked that raw is + // in that range. + return Err(unsafe { Errno(raw.decode_error_code()) }); + } + + Ok(raw.decode_c_uint()) +} + +/// Check for an error from the result of a syscall which encodes a `usize` on +/// success. +#[inline] +pub(in crate::backend) fn try_decode_usize<Num: RetNumber>(raw: RetReg<Num>) -> io::Result<usize> { + if raw.is_in_range(-4095..0) { + // SAFETY: `raw` must be in `-4095..0`, and we just checked that raw is + // in that range. + return Err(unsafe { Errno(raw.decode_error_code()) }); + } + + Ok(raw.decode_usize()) +} + +/// Check for an error from the result of a syscall which encodes a +/// `*mut c_void` on success. +#[inline] +pub(in crate::backend) fn try_decode_void_star<Num: RetNumber>( + raw: RetReg<Num>, +) -> io::Result<*mut c::c_void> { + if raw.is_in_range(-4095..0) { + // SAFETY: `raw` must be in `-4095..0`, and we just checked that raw is + // in that range. + return Err(unsafe { Errno(raw.decode_error_code()) }); + } + + Ok(raw.decode_void_star()) +} + +/// Check for an error from the result of a syscall which encodes a +/// `u64` on success. +#[cfg(target_pointer_width = "64")] +#[inline] +pub(in crate::backend) fn try_decode_u64<Num: RetNumber>(raw: RetReg<Num>) -> io::Result<u64> { + if raw.is_in_range(-4095..0) { + // SAFETY: `raw` must be in `-4095..0`, and we just checked that raw is + // in that range. + return Err(unsafe { Errno(raw.decode_error_code()) }); + } + + Ok(raw.decode_u64()) +} + +/// Check for an error from the result of a syscall which encodes a file +/// descriptor on success. +/// +/// # Safety +/// +/// This must only be used with syscalls which return file descriptors on +/// success. +#[inline] +pub(in crate::backend) unsafe fn try_decode_raw_fd<Num: RetNumber>( + raw: RetReg<Num>, +) -> io::Result<RawFd> { + // Instead of using `check_result` here, we just check for negative, since + // this function is only used for system calls which return file + // descriptors, and this produces smaller code. + if raw.is_negative() { + debug_assert!(raw.is_in_range(-4095..0)); + + // Tell the optimizer that we know the value is in the error range. + // This helps it avoid unnecessary integer conversions. + #[cfg(core_intrinsics)] + { + core::intrinsics::assume(raw.is_in_range(-4095..0)); + } + + return Err(Errno(raw.decode_error_code())); + } + + Ok(raw.decode_raw_fd()) +} + +/// Check for an error from the result of a syscall which encodes no value on +/// success. On success, return the unconsumed `raw` value. +/// +/// # Safety +/// +/// This must only be used with syscalls which return no value on success. +#[inline] +pub(in crate::backend) unsafe fn try_decode_void<Num: RetNumber>( + raw: RetReg<Num>, +) -> io::Result<()> { + // Instead of using `check_result` here, we just check for zero, since this + // function is only used for system calls which have no other return value, + // and this produces smaller code. + if raw.is_nonzero() { + debug_assert!(raw.is_in_range(-4095..0)); + + // Tell the optimizer that we know the value is in the error range. + // This helps it avoid unnecessary integer conversions. + #[cfg(core_intrinsics)] + { + core::intrinsics::assume(raw.is_in_range(-4095..0)); + } + + return Err(Errno(raw.decode_error_code())); + } + + raw.decode_void(); + + Ok(()) +} + +/// Check for an error from the result of a syscall which does not return on +/// success. On success, return the unconsumed `raw` value. +/// +/// # Safety +/// +/// This must only be used with syscalls which do not return on success. +#[cfg(feature = "runtime")] +#[inline] +pub(in crate::backend) unsafe fn try_decode_error<Num: RetNumber>(raw: RetReg<Num>) -> io::Errno { + debug_assert!(raw.is_in_range(-4095..0)); + + // Tell the optimizer that we know the value is in the error range. + // This helps it avoid unnecessary integer conversions. + #[cfg(core_intrinsics)] + { + core::intrinsics::assume(raw.is_in_range(-4095..0)); + } + + Errno(raw.decode_error_code()) +} + +/// Return the contained `usize` value. +#[cfg(not(debug_assertions))] +#[inline] +pub(in crate::backend) fn decode_usize_infallible<Num: RetNumber>(raw: RetReg<Num>) -> usize { + raw.decode_usize() +} + +/// Return the contained `c_int` 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-0.37.22/src/backend/linux_raw/io/io_slice.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/io/io_slice.rs new file mode 100644 index 000000000..a59a1cc34 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/io/io_slice.rs @@ -0,0 +1,98 @@ +//! The following is derived from Rust's +//! library/std/src/sys/unix/io.rs +//! dca3f1b786efd27be3b325ed1e01e247aa589c3b. + +#![allow(unsafe_code)] +use super::super::c; +use core::marker::PhantomData; +use core::slice; +use linux_raw_sys::general::__kernel_size_t; + +/// <https://doc.rust-lang.org/stable/std/io/struct.IoSlice.html> +#[derive(Copy, Clone)] +#[repr(transparent)] +pub struct IoSlice<'a> { + vec: c::iovec, + _p: PhantomData<&'a [u8]>, +} + +impl<'a> IoSlice<'a> { + /// <https://doc.rust-lang.org/stable/std/io/struct.IoSlice.html#method.new> + #[inline] + pub fn new(buf: &'a [u8]) -> IoSlice<'a> { + IoSlice { + vec: c::iovec { + iov_base: buf.as_ptr() as *mut u8 as *mut c::c_void, + iov_len: buf.len() as _, + }, + _p: PhantomData, + } + } + + /// <https://doc.rust-lang.org/stable/std/io/struct.IoSlice.html#method.advance> + #[inline] + pub fn advance(&mut self, n: usize) { + if self.vec.iov_len < n as _ { + panic!("advancing IoSlice beyond its length"); + } + + unsafe { + self.vec.iov_len -= n as __kernel_size_t; + self.vec.iov_base = self.vec.iov_base.add(n); + } + } + + /// <https://doc.rust-lang.org/stable/std/io/struct.IoSlice.html#method.as_slice> + #[inline] + pub fn as_slice(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len as usize) } + } +} + +/// <https://doc.rust-lang.org/stable/std/io/struct.IoSliceMut.html> +#[repr(transparent)] +pub struct IoSliceMut<'a> { + vec: c::iovec, + _p: PhantomData<&'a mut [u8]>, +} + +impl<'a> IoSliceMut<'a> { + /// <https://doc.rust-lang.org/stable/std/io/struct.IoSliceMut.html#method.new> + #[inline] + pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { + IoSliceMut { + vec: c::iovec { + iov_base: buf.as_mut_ptr() as *mut c::c_void, + iov_len: buf.len() as _, + }, + _p: PhantomData, + } + } + + /// <https://doc.rust-lang.org/stable/std/io/struct.IoSliceMut.html#method.advance> + #[inline] + pub fn advance(&mut self, n: usize) { + if self.vec.iov_len < n as _ { + panic!("advancing IoSliceMut beyond its length"); + } + + unsafe { + self.vec.iov_len -= n as __kernel_size_t; + self.vec.iov_base = self.vec.iov_base.add(n); + } + } + + /// <https://doc.rust-lang.org/stable/std/io/struct.IoSliceMut.html#method.as_slice> + #[inline] + pub fn as_slice(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len as usize) } + } + + /// <https://doc.rust-lang.org/stable/std/io/struct.IoSliceMut.html#method.as_slice_mut> + #[inline] + pub fn as_mut_slice(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len as usize) + } + } +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/io/mod.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/io/mod.rs new file mode 100644 index 000000000..f5c2bf3c0 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/io/mod.rs @@ -0,0 +1,7 @@ +pub mod epoll; +pub(crate) mod errno; +#[cfg(not(feature = "std"))] +pub(crate) mod io_slice; +pub(crate) mod poll_fd; +pub(crate) mod syscalls; +pub(crate) mod types; diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/io/poll_fd.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/io/poll_fd.rs new file mode 100644 index 000000000..252358331 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/io/poll_fd.rs @@ -0,0 +1,93 @@ +use crate::fd::{AsFd, BorrowedFd}; +use bitflags::bitflags; + +bitflags! { + /// `POLL*` flags for use with [`poll`]. + /// + /// [`poll`]: crate::io::poll + 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; + } +} + +/// `struct pollfd`—File descriptor and flags for use with [`poll`]. +/// +/// [`poll`]: crate::io::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-0.37.22/src/backend/linux_raw/io/syscalls.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/io/syscalls.rs new file mode 100644 index 000000000..86ff6fbbd --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/io/syscalls.rs @@ -0,0 +1,695 @@ +//! linux_raw syscalls supporting `rustix::io`. +//! +//! # Safety +//! +//! See the `rustix::backend` module documentation for details. +#![allow(unsafe_code)] +#![allow(clippy::undocumented_unsafe_blocks)] + +use super::super::c; +#[cfg(target_pointer_width = "64")] +use super::super::conv::loff_t_from_u64; +use super::super::conv::{ + by_ref, c_int, c_uint, opt_mut, pass_usize, raw_fd, ret, ret_c_uint, ret_discarded_fd, + ret_owned_fd, ret_usize, slice, slice_mut, zero, +}; +#[cfg(target_pointer_width = "32")] +use super::super::conv::{hi, lo}; +use crate::fd::{AsFd, BorrowedFd, OwnedFd, RawFd}; +#[cfg(linux_kernel)] +use crate::io::SpliceFlags; +use crate::io::{ + self, epoll, DupFlags, EventfdFlags, FdFlags, IoSlice, IoSliceMut, IoSliceRaw, PipeFlags, + PollFd, ReadWriteFlags, +}; +#[cfg(all(feature = "fs", feature = "net"))] +use crate::net::{RecvFlags, SendFlags}; +use core::cmp; +use core::mem::MaybeUninit; +#[cfg(target_os = "espidf")] +use linux_raw_sys::general::F_DUPFD; +use linux_raw_sys::general::{ + epoll_event, EPOLL_CTL_ADD, EPOLL_CTL_DEL, EPOLL_CTL_MOD, F_DUPFD_CLOEXEC, F_GETFD, F_SETFD, + UIO_MAXIOV, +}; +use linux_raw_sys::ioctl::{ + BLKPBSZGET, BLKSSZGET, EXT4_IOC_RESIZE_FS, FICLONE, FIONBIO, FIONREAD, TIOCEXCL, TIOCNXCL, +}; +#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] +use { + super::super::conv::{opt_ref, size_of}, + linux_raw_sys::general::{__kernel_timespec, kernel_sigset_t}, +}; + +#[inline] +pub(crate) fn read(fd: BorrowedFd<'_>, buf: &mut [u8]) -> io::Result<usize> { + let (buf_addr_mut, buf_len) = slice_mut(buf); + + unsafe { ret_usize(syscall!(__NR_read, fd, buf_addr_mut, buf_len)) } +} + +#[inline] +pub(crate) fn pread(fd: BorrowedFd<'_>, buf: &mut [u8], pos: u64) -> io::Result<usize> { + let (buf_addr_mut, buf_len) = slice_mut(buf); + + // <https://github.com/torvalds/linux/blob/fcadab740480e0e0e9fa9bd272acd409884d431a/arch/arm64/kernel/sys32.c#L75> + #[cfg(all( + target_pointer_width = "32", + any(target_arch = "arm", target_arch = "mips", target_arch = "power"), + ))] + unsafe { + ret_usize(syscall!( + __NR_pread64, + fd, + buf_addr_mut, + buf_len, + zero(), + hi(pos), + lo(pos) + )) + } + #[cfg(all( + target_pointer_width = "32", + not(any(target_arch = "arm", target_arch = "mips", target_arch = "power")), + ))] + unsafe { + ret_usize(syscall!( + __NR_pread64, + fd, + buf_addr_mut, + buf_len, + hi(pos), + lo(pos) + )) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_usize(syscall!( + __NR_pread64, + fd, + buf_addr_mut, + buf_len, + loff_t_from_u64(pos) + )) + } +} + +#[inline] +pub(crate) fn readv(fd: BorrowedFd<'_>, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { + let (bufs_addr, bufs_len) = slice(&bufs[..cmp::min(bufs.len(), max_iov())]); + + unsafe { ret_usize(syscall!(__NR_readv, fd, bufs_addr, bufs_len)) } +} + +#[inline] +pub(crate) fn preadv( + fd: BorrowedFd<'_>, + bufs: &mut [IoSliceMut<'_>], + pos: u64, +) -> io::Result<usize> { + let (bufs_addr, bufs_len) = slice(&bufs[..cmp::min(bufs.len(), max_iov())]); + + #[cfg(target_pointer_width = "32")] + unsafe { + ret_usize(syscall!( + __NR_preadv, + fd, + bufs_addr, + bufs_len, + hi(pos), + lo(pos) + )) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_usize(syscall!( + __NR_preadv, + fd, + bufs_addr, + bufs_len, + loff_t_from_u64(pos) + )) + } +} + +#[inline] +pub(crate) fn preadv2( + fd: BorrowedFd<'_>, + bufs: &mut [IoSliceMut<'_>], + pos: u64, + flags: ReadWriteFlags, +) -> io::Result<usize> { + let (bufs_addr, bufs_len) = slice(&bufs[..cmp::min(bufs.len(), max_iov())]); + + #[cfg(target_pointer_width = "32")] + unsafe { + ret_usize(syscall!( + __NR_preadv2, + fd, + bufs_addr, + bufs_len, + hi(pos), + lo(pos), + flags + )) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_usize(syscall!( + __NR_preadv2, + fd, + bufs_addr, + bufs_len, + loff_t_from_u64(pos), + flags + )) + } +} + +#[inline] +pub(crate) fn write(fd: BorrowedFd<'_>, buf: &[u8]) -> io::Result<usize> { + let (buf_addr, buf_len) = slice(buf); + + unsafe { ret_usize(syscall_readonly!(__NR_write, fd, buf_addr, buf_len)) } +} + +#[inline] +pub(crate) fn pwrite(fd: BorrowedFd<'_>, buf: &[u8], pos: u64) -> io::Result<usize> { + let (buf_addr, buf_len) = slice(buf); + + // <https://github.com/torvalds/linux/blob/fcadab740480e0e0e9fa9bd272acd409884d431a/arch/arm64/kernel/sys32.c#L81-L83> + #[cfg(all( + target_pointer_width = "32", + any(target_arch = "arm", target_arch = "mips", target_arch = "power"), + ))] + unsafe { + ret_usize(syscall_readonly!( + __NR_pwrite64, + fd, + buf_addr, + buf_len, + zero(), + hi(pos), + lo(pos) + )) + } + #[cfg(all( + target_pointer_width = "32", + not(any(target_arch = "arm", target_arch = "mips", target_arch = "power")), + ))] + unsafe { + ret_usize(syscall_readonly!( + __NR_pwrite64, + fd, + buf_addr, + buf_len, + hi(pos), + lo(pos) + )) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_usize(syscall_readonly!( + __NR_pwrite64, + fd, + buf_addr, + buf_len, + loff_t_from_u64(pos) + )) + } +} + +#[inline] +pub(crate) fn writev(fd: BorrowedFd<'_>, bufs: &[IoSlice<'_>]) -> io::Result<usize> { + let (bufs_addr, bufs_len) = slice(&bufs[..cmp::min(bufs.len(), max_iov())]); + + unsafe { ret_usize(syscall_readonly!(__NR_writev, fd, bufs_addr, bufs_len)) } +} + +#[inline] +pub(crate) fn pwritev(fd: BorrowedFd<'_>, bufs: &[IoSlice<'_>], pos: u64) -> io::Result<usize> { + let (bufs_addr, bufs_len) = slice(&bufs[..cmp::min(bufs.len(), max_iov())]); + + #[cfg(target_pointer_width = "32")] + unsafe { + ret_usize(syscall_readonly!( + __NR_pwritev, + fd, + bufs_addr, + bufs_len, + hi(pos), + lo(pos) + )) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_usize(syscall_readonly!( + __NR_pwritev, + fd, + bufs_addr, + bufs_len, + loff_t_from_u64(pos) + )) + } +} + +#[inline] +pub(crate) fn pwritev2( + fd: BorrowedFd<'_>, + bufs: &[IoSlice<'_>], + pos: u64, + flags: ReadWriteFlags, +) -> io::Result<usize> { + let (bufs_addr, bufs_len) = slice(&bufs[..cmp::min(bufs.len(), max_iov())]); + + #[cfg(target_pointer_width = "32")] + unsafe { + ret_usize(syscall_readonly!( + __NR_pwritev2, + fd, + bufs_addr, + bufs_len, + hi(pos), + lo(pos), + flags + )) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_usize(syscall_readonly!( + __NR_pwritev2, + fd, + bufs_addr, + bufs_len, + loff_t_from_u64(pos), + flags + )) + } +} + +/// The maximum number of buffers that can be passed into a vectored I/O system +/// call on the current platform. +const fn max_iov() -> usize { + UIO_MAXIOV as usize +} + +#[inline] +pub(crate) unsafe fn close(fd: RawFd) { + // See the documentation for [`io::close`] for why errors are ignored. + syscall_readonly!(__NR_close, raw_fd(fd)).decode_void(); +} + +#[inline] +pub(crate) fn eventfd(initval: u32, flags: EventfdFlags) -> io::Result<OwnedFd> { + unsafe { ret_owned_fd(syscall_readonly!(__NR_eventfd2, c_uint(initval), flags)) } +} + +#[inline] +pub(crate) fn ioctl_fionread(fd: BorrowedFd<'_>) -> io::Result<u64> { + unsafe { + let mut result = MaybeUninit::<c::c_int>::uninit(); + ret(syscall!(__NR_ioctl, fd, c_uint(FIONREAD), &mut result))?; + Ok(result.assume_init() as u64) + } +} + +#[inline] +pub(crate) fn ioctl_fionbio(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> { + unsafe { + let data = c::c_int::from(value); + ret(syscall_readonly!( + __NR_ioctl, + fd, + c_uint(FIONBIO), + by_ref(&data) + )) + } +} + +#[inline] +pub(crate) fn ioctl_tiocexcl(fd: BorrowedFd<'_>) -> io::Result<()> { + unsafe { ret(syscall_readonly!(__NR_ioctl, fd, c_uint(TIOCEXCL))) } +} + +#[inline] +pub(crate) fn ioctl_tiocnxcl(fd: BorrowedFd<'_>) -> io::Result<()> { + unsafe { ret(syscall_readonly!(__NR_ioctl, fd, c_uint(TIOCNXCL))) } +} + +#[inline] +pub(crate) fn ioctl_blksszget(fd: BorrowedFd) -> io::Result<u32> { + let mut result = MaybeUninit::<c::c_uint>::uninit(); + unsafe { + ret(syscall!(__NR_ioctl, fd, c_uint(BLKSSZGET), &mut result))?; + Ok(result.assume_init() as u32) + } +} + +#[inline] +pub(crate) fn ioctl_blkpbszget(fd: BorrowedFd) -> io::Result<u32> { + let mut result = MaybeUninit::<c::c_uint>::uninit(); + unsafe { + ret(syscall!(__NR_ioctl, fd, c_uint(BLKPBSZGET), &mut result))?; + Ok(result.assume_init() as u32) + } +} + +#[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)) } +} + +#[inline] +pub(crate) fn ext4_ioc_resize_fs(fd: BorrowedFd<'_>, blocks: u64) -> io::Result<()> { + unsafe { + ret(syscall_readonly!( + __NR_ioctl, + fd, + c_uint(EXT4_IOC_RESIZE_FS), + by_ref(&blocks) + )) + } +} + +#[cfg(all(feature = "fs", feature = "net"))] +pub(crate) fn is_read_write(fd: BorrowedFd<'_>) -> io::Result<(bool, bool)> { + let (mut read, mut write) = crate::fs::fd::_is_file_read_write(fd)?; + let mut not_socket = false; + if read { + // Do a `recv` with `PEEK` and `DONTWAIT` for 1 byte. A 0 indicates + // the read side is shut down; an `EWOULDBLOCK` indicates the read + // side is still open. + // + // TODO: This code would benefit from having a better way to read into + // uninitialized memory. + let mut buf = [0]; + match super::super::net::syscalls::recv(fd, &mut buf, RecvFlags::PEEK | RecvFlags::DONTWAIT) + { + Ok(0) => read = false, + Err(err) => { + #[allow(unreachable_patterns)] // `EAGAIN` may equal `EWOULDBLOCK` + match err { + io::Errno::AGAIN | io::Errno::WOULDBLOCK => (), + io::Errno::NOTSOCK => not_socket = true, + _ => return Err(err), + } + } + Ok(_) => (), + } + } + if write && !not_socket { + // Do a `send` with `DONTWAIT` for 0 bytes. An `EPIPE` indicates + // the write side is shut down. + #[allow(unreachable_patterns)] // `EAGAIN` equals `EWOULDBLOCK` + match super::super::net::syscalls::send(fd, &[], SendFlags::DONTWAIT) { + // TODO or-patterns when we don't need 1.51 + Err(io::Errno::AGAIN) => (), + Err(io::Errno::WOULDBLOCK) => (), + Err(io::Errno::NOTSOCK) => (), + Err(io::Errno::PIPE) => write = false, + Err(err) => return Err(err), + Ok(_) => (), + } + } + Ok((read, write)) +} + +#[inline] +pub(crate) fn dup(fd: BorrowedFd<'_>) -> io::Result<OwnedFd> { + unsafe { ret_owned_fd(syscall_readonly!(__NR_dup, fd)) } +} + +#[inline] +pub(crate) fn dup2(fd: BorrowedFd<'_>, new: &mut OwnedFd) -> io::Result<()> { + #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + { + // We don't need to worry about the difference between `dup2` and + // `dup3` when the file descriptors are equal because we have an + // `&mut OwnedFd` which means `fd` doesn't alias it. + dup3(fd, new, DupFlags::empty()) + } + + #[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))] + unsafe { + ret_discarded_fd(syscall_readonly!(__NR_dup2, fd, new.as_fd())) + } +} + +#[inline] +pub(crate) fn dup3(fd: BorrowedFd<'_>, new: &mut OwnedFd, flags: DupFlags) -> io::Result<()> { + unsafe { ret_discarded_fd(syscall_readonly!(__NR_dup3, fd, new.as_fd(), flags)) } +} + +#[inline] +pub(crate) fn fcntl_getfd(fd: BorrowedFd<'_>) -> io::Result<FdFlags> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret_c_uint(syscall_readonly!(__NR_fcntl64, fd, c_uint(F_GETFD))) + .map(FdFlags::from_bits_truncate) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_c_uint(syscall_readonly!(__NR_fcntl, fd, c_uint(F_GETFD))) + .map(FdFlags::from_bits_truncate) + } +} + +#[inline] +pub(crate) fn fcntl_setfd(fd: BorrowedFd<'_>, flags: FdFlags) -> io::Result<()> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret(syscall_readonly!(__NR_fcntl64, fd, c_uint(F_SETFD), flags)) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret(syscall_readonly!(__NR_fcntl, fd, c_uint(F_SETFD), flags)) + } +} + +#[cfg(target_os = "espidf")] +#[inline] +pub(crate) fn fcntl_dupfd(fd: BorrowedFd<'_>, min: RawFd) -> io::Result<OwnedFd> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret_owned_fd(syscall_readonly!( + __NR_fcntl64, + fd, + c_uint(F_DUPFD), + raw_fd(min) + )) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_owned_fd(syscall_readonly!( + __NR_fcntl, + fd, + c_uint(F_DUPFD), + raw_fd(min) + )) + } +} + +#[inline] +pub(crate) fn fcntl_dupfd_cloexec(fd: BorrowedFd<'_>, min: RawFd) -> io::Result<OwnedFd> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret_owned_fd(syscall_readonly!( + __NR_fcntl64, + fd, + c_uint(F_DUPFD_CLOEXEC), + raw_fd(min) + )) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret_owned_fd(syscall_readonly!( + __NR_fcntl, + fd, + c_uint(F_DUPFD_CLOEXEC), + raw_fd(min) + )) + } +} + +#[inline] +pub(crate) fn pipe_with(flags: PipeFlags) -> io::Result<(OwnedFd, OwnedFd)> { + unsafe { + let mut result = MaybeUninit::<[OwnedFd; 2]>::uninit(); + ret(syscall!(__NR_pipe2, &mut result, flags))?; + let [p0, p1] = result.assume_init(); + Ok((p0, p1)) + } +} + +#[inline] +pub(crate) fn pipe() -> io::Result<(OwnedFd, OwnedFd)> { + // aarch64 and risc64 omit `__NR_pipe`. On mips, `__NR_pipe` uses a special + // calling convention, but using it is not worth complicating our syscall + // wrapping infrastructure at this time. + #[cfg(any( + target_arch = "aarch64", + target_arch = "mips", + target_arch = "mips64", + target_arch = "riscv64", + ))] + { + pipe_with(PipeFlags::empty()) + } + #[cfg(not(any( + target_arch = "aarch64", + target_arch = "mips", + target_arch = "mips64", + target_arch = "riscv64", + )))] + unsafe { + let mut result = MaybeUninit::<[OwnedFd; 2]>::uninit(); + ret(syscall!(__NR_pipe, &mut result))?; + let [p0, p1] = result.assume_init(); + Ok((p0, p1)) + } +} + +#[inline] +pub(crate) fn poll(fds: &mut [PollFd<'_>], timeout: c::c_int) -> io::Result<usize> { + let (fds_addr_mut, fds_len) = slice_mut(fds); + + #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + unsafe { + let timeout = if timeout >= 0 { + Some(__kernel_timespec { + tv_sec: (timeout as i64) / 1000, + tv_nsec: (timeout as i64) % 1000 * 1_000_000, + }) + } else { + None + }; + ret_usize(syscall!( + __NR_ppoll, + fds_addr_mut, + fds_len, + opt_ref(timeout.as_ref()), + zero(), + size_of::<kernel_sigset_t, _>() + )) + } + #[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))] + unsafe { + ret_usize(syscall!(__NR_poll, fds_addr_mut, fds_len, c_int(timeout))) + } +} + +#[inline] +pub(crate) fn epoll_create(flags: epoll::CreateFlags) -> io::Result<OwnedFd> { + unsafe { ret_owned_fd(syscall_readonly!(__NR_epoll_create1, flags)) } +} + +#[inline] +pub(crate) unsafe fn epoll_add( + epfd: BorrowedFd<'_>, + fd: c::c_int, + event: &epoll_event, +) -> io::Result<()> { + ret(syscall_readonly!( + __NR_epoll_ctl, + epfd, + c_uint(EPOLL_CTL_ADD), + raw_fd(fd), + by_ref(event) + )) +} + +#[inline] +pub(crate) unsafe fn epoll_mod( + epfd: BorrowedFd<'_>, + fd: c::c_int, + event: &epoll_event, +) -> io::Result<()> { + ret(syscall_readonly!( + __NR_epoll_ctl, + epfd, + c_uint(EPOLL_CTL_MOD), + raw_fd(fd), + by_ref(event) + )) +} + +#[inline] +pub(crate) unsafe fn epoll_del(epfd: BorrowedFd<'_>, fd: c::c_int) -> io::Result<()> { + ret(syscall_readonly!( + __NR_epoll_ctl, + epfd, + c_uint(EPOLL_CTL_DEL), + raw_fd(fd), + zero() + )) +} + +#[inline] +pub(crate) fn epoll_wait( + epfd: BorrowedFd<'_>, + events: *mut epoll_event, + num_events: usize, + timeout: c::c_int, +) -> io::Result<usize> { + #[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))] + unsafe { + ret_usize(syscall!( + __NR_epoll_wait, + epfd, + events, + pass_usize(num_events), + c_int(timeout) + )) + } + #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + unsafe { + ret_usize(syscall!( + __NR_epoll_pwait, + epfd, + events, + pass_usize(num_events), + c_int(timeout), + zero() + )) + } +} + +#[cfg(linux_kernel)] +#[inline] +pub fn splice( + fd_in: BorrowedFd, + off_in: Option<&mut u64>, + fd_out: BorrowedFd, + off_out: Option<&mut u64>, + len: usize, + flags: SpliceFlags, +) -> io::Result<usize> { + unsafe { + ret_usize(syscall!( + __NR_splice, + fd_in, + opt_mut(off_in), + fd_out, + opt_mut(off_out), + pass_usize(len), + c_uint(flags.bits()) + )) + } +} + +#[cfg(linux_kernel)] +#[inline] +pub unsafe fn vmsplice( + fd: BorrowedFd, + bufs: &[IoSliceRaw], + flags: SpliceFlags, +) -> io::Result<usize> { + let (bufs_addr, bufs_len) = slice(&bufs[..cmp::min(bufs.len(), max_iov())]); + ret_usize(syscall!( + __NR_vmsplice, + fd, + bufs_addr, + bufs_len, + c_uint(flags.bits()) + )) +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/io/types.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/io/types.rs new file mode 100644 index 000000000..00f15bec4 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/io/types.rs @@ -0,0 +1,129 @@ +use super::super::c; +use bitflags::bitflags; +use core::marker::PhantomData; + +bitflags! { + /// `FD_*` constants for use with [`fcntl_getfd`] and [`fcntl_setfd`]. + /// + /// [`fcntl_getfd`]: crate::io::fcntl_getfd + /// [`fcntl_setfd`]: crate::io::fcntl_setfd + pub struct FdFlags: c::c_uint { + /// `FD_CLOEXEC` + const CLOEXEC = linux_raw_sys::general::FD_CLOEXEC; + } +} + +bitflags! { + /// `RWF_*` constants for use with [`preadv2`] and [`pwritev2`]. + /// + /// [`preadv2`]: crate::io::preadv2 + /// [`pwritev2`]: crate::io::pwritev + pub struct ReadWriteFlags: c::c_uint { + /// `RWF_DSYNC` (since Linux 4.7) + const DSYNC = linux_raw_sys::general::RWF_DSYNC; + /// `RWF_HIPRI` (since Linux 4.6) + const HIPRI = linux_raw_sys::general::RWF_HIPRI; + /// `RWF_SYNC` (since Linux 4.7) + const SYNC = linux_raw_sys::general::RWF_SYNC; + /// `RWF_NOWAIT` (since Linux 4.14) + const NOWAIT = linux_raw_sys::general::RWF_NOWAIT; + /// `RWF_APPEND` (since Linux 4.16) + const APPEND = linux_raw_sys::general::RWF_APPEND; + } +} + +#[cfg(linux_kernel)] +bitflags! { + /// `SPLICE_F_*` constants for use with [`splice`] and [`vmsplice`]. + pub struct SpliceFlags: c::c_uint { + /// `SPLICE_F_MOVE` + const MOVE = linux_raw_sys::general::SPLICE_F_MOVE; + /// `SPLICE_F_NONBLOCK` + const NONBLOCK = linux_raw_sys::general::SPLICE_F_NONBLOCK; + /// `SPLICE_F_MORE` + const MORE = linux_raw_sys::general::SPLICE_F_MORE; + /// `SPLICE_F_GIFT` + const GIFT = linux_raw_sys::general::SPLICE_F_GIFT; + } +} + +bitflags! { + /// `O_*` constants for use with [`dup2`]. + /// + /// [`dup2`]: crate::io::dup2 + pub struct DupFlags: c::c_uint { + /// `O_CLOEXEC` + const CLOEXEC = linux_raw_sys::general::O_CLOEXEC; + } +} + +bitflags! { + /// `O_*` constants for use with [`pipe_with`]. + /// + /// [`pipe_with`]: crate::io::pipe_with + pub struct PipeFlags: c::c_uint { + /// `O_CLOEXEC` + const CLOEXEC = linux_raw_sys::general::O_CLOEXEC; + /// `O_DIRECT` + const DIRECT = linux_raw_sys::general::O_DIRECT; + /// `O_NONBLOCK` + const NONBLOCK = linux_raw_sys::general::O_NONBLOCK; + } +} + +bitflags! { + /// `EFD_*` flags for use with [`eventfd`]. + /// + /// [`eventfd`]: crate::io::eventfd + pub struct EventfdFlags: c::c_uint { + /// `EFD_CLOEXEC` + const CLOEXEC = linux_raw_sys::general::EFD_CLOEXEC; + /// `EFD_NONBLOCK` + const NONBLOCK = linux_raw_sys::general::EFD_NONBLOCK; + /// `EFD_SEMAPHORE` + const SEMAPHORE = linux_raw_sys::general::EFD_SEMAPHORE; + } +} + +/// `PIPE_BUF`—The maximum size of a write to a pipe guaranteed to be atomic. +pub const PIPE_BUF: usize = linux_raw_sys::general::PIPE_BUF as usize; + +pub(crate) const AT_FDCWD: c::c_int = linux_raw_sys::general::AT_FDCWD; +pub(crate) const STDIN_FILENO: c::c_uint = linux_raw_sys::general::STDIN_FILENO; +pub(crate) const STDOUT_FILENO: c::c_uint = linux_raw_sys::general::STDOUT_FILENO; +pub(crate) const STDERR_FILENO: c::c_uint = linux_raw_sys::general::STDERR_FILENO; + +/// A buffer type used with `vmsplice`. +/// It is guaranteed to be ABI compatible with the iovec type on Unix platforms +/// and `WSABUF` on Windows. Unlike `IoSlice` and `IoSliceMut` it is +/// semantically like a raw pointer, and therefore can be shared or mutated as +/// needed. +#[repr(transparent)] +pub struct IoSliceRaw<'a> { + _buf: c::iovec, + _lifetime: PhantomData<&'a ()>, +} + +impl<'a> IoSliceRaw<'a> { + /// Creates a new `IoSlice` wrapping a byte slice. + pub fn from_slice(buf: &'a [u8]) -> Self { + IoSliceRaw { + _buf: c::iovec { + iov_base: (buf.as_ptr() as *mut u8).cast::<c::c_void>(), + iov_len: buf.len() as _, + }, + _lifetime: PhantomData, + } + } + + /// Creates a new `IoSlice` wrapping a mutable byte slice. + pub fn from_slice_mut(buf: &'a mut [u8]) -> Self { + IoSliceRaw { + _buf: c::iovec { + iov_base: buf.as_mut_ptr().cast::<c::c_void>(), + iov_len: buf.len() as _, + }, + _lifetime: PhantomData, + } + } +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/io_uring/mod.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/io_uring/mod.rs new file mode 100644 index 000000000..ef944f04d --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/io_uring/mod.rs @@ -0,0 +1 @@ +pub(crate) mod syscalls; diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/io_uring/syscalls.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/io_uring/syscalls.rs new file mode 100644 index 000000000..16655fe77 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/io_uring/syscalls.rs @@ -0,0 +1,63 @@ +//! linux_raw syscalls supporting `rustix::io_uring`. +//! +//! # Safety +//! +//! See the `rustix::backend::syscalls` module documentation for details. +#![allow(unsafe_code)] +#![allow(clippy::undocumented_unsafe_blocks)] + +use super::super::conv::{by_mut, c_uint, pass_usize, ret_c_uint, ret_owned_fd}; +use crate::fd::{BorrowedFd, OwnedFd}; +use crate::io; +use crate::io_uring::{io_uring_params, IoringEnterFlags, IoringRegisterOp}; +use core::ffi::c_void; + +#[inline] +pub(crate) fn io_uring_setup(entries: u32, params: &mut io_uring_params) -> io::Result<OwnedFd> { + unsafe { + ret_owned_fd(syscall!( + __NR_io_uring_setup, + c_uint(entries), + by_mut(params) + )) + } +} + +#[inline] +pub(crate) unsafe fn io_uring_register( + fd: BorrowedFd<'_>, + opcode: IoringRegisterOp, + arg: *const c_void, + nr_args: u32, +) -> io::Result<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_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-0.37.22/src/backend/linux_raw/mm/mod.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/mm/mod.rs new file mode 100644 index 000000000..1e0181a99 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/mm/mod.rs @@ -0,0 +1,2 @@ +pub(crate) mod syscalls; +pub(crate) mod types; diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/mm/syscalls.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/mm/syscalls.rs new file mode 100644 index 000000000..8fa6a3ec3 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/mm/syscalls.rs @@ -0,0 +1,214 @@ +//! linux_raw syscalls supporting `rustix::io`. +//! +//! # Safety +//! +//! See the `rustix::backend` module documentation for details. +#![allow(unsafe_code)] +#![allow(clippy::undocumented_unsafe_blocks)] + +use super::super::c; +#[cfg(target_pointer_width = "64")] +use super::super::conv::loff_t_from_u64; +use super::super::conv::{c_uint, no_fd, pass_usize, ret, ret_owned_fd, ret_void_star}; +use super::types::{ + Advice, MapFlags, MlockFlags, MprotectFlags, MremapFlags, MsyncFlags, ProtFlags, + UserfaultfdFlags, +}; +use crate::fd::{BorrowedFd, OwnedFd}; +use crate::io; +#[cfg(target_pointer_width = "32")] +use core::convert::TryInto; +use linux_raw_sys::general::MAP_ANONYMOUS; + +#[inline] +pub(crate) fn madvise(addr: *mut c::c_void, len: usize, advice: Advice) -> io::Result<()> { + unsafe { + ret(syscall!( + __NR_madvise, + addr, + pass_usize(len), + c_uint(advice as c::c_uint) + )) + } +} + +#[inline] +pub(crate) unsafe fn msync(addr: *mut c::c_void, len: usize, flags: MsyncFlags) -> io::Result<()> { + ret(syscall!(__NR_msync, addr, pass_usize(len), flags)) +} + +/// # Safety +/// +/// `mmap` is primarily unsafe due to the `addr` parameter, as anything working +/// with memory pointed to by raw pointers is unsafe. +#[inline] +pub(crate) unsafe fn mmap( + addr: *mut c::c_void, + length: usize, + prot: ProtFlags, + flags: MapFlags, + fd: BorrowedFd<'_>, + offset: u64, +) -> io::Result<*mut c::c_void> { + #[cfg(target_pointer_width = "32")] + { + ret_void_star(syscall!( + __NR_mmap2, + addr, + pass_usize(length), + prot, + flags, + fd, + (offset / 4096) + .try_into() + .map(pass_usize) + .map_err(|_| io::Errno::INVAL)? + )) + } + #[cfg(target_pointer_width = "64")] + { + ret_void_star(syscall!( + __NR_mmap, + addr, + pass_usize(length), + prot, + flags, + fd, + loff_t_from_u64(offset) + )) + } +} + +/// # Safety +/// +/// `mmap` is primarily unsafe due to the `addr` parameter, as anything working +/// with memory pointed to by raw pointers is unsafe. +#[inline] +pub(crate) unsafe fn mmap_anonymous( + addr: *mut c::c_void, + length: usize, + prot: ProtFlags, + flags: MapFlags, +) -> io::Result<*mut c::c_void> { + #[cfg(target_pointer_width = "32")] + { + ret_void_star(syscall!( + __NR_mmap2, + addr, + pass_usize(length), + prot, + c_uint(flags.bits() | MAP_ANONYMOUS), + no_fd(), + pass_usize(0) + )) + } + #[cfg(target_pointer_width = "64")] + { + ret_void_star(syscall!( + __NR_mmap, + addr, + pass_usize(length), + prot, + c_uint(flags.bits() | MAP_ANONYMOUS), + no_fd(), + loff_t_from_u64(0) + )) + } +} + +#[inline] +pub(crate) unsafe fn mprotect( + ptr: *mut c::c_void, + len: usize, + flags: MprotectFlags, +) -> io::Result<()> { + ret(syscall!(__NR_mprotect, ptr, pass_usize(len), flags)) +} + +/// # Safety +/// +/// `munmap` is primarily unsafe due to the `addr` parameter, as anything +/// working with memory pointed to by raw pointers is unsafe. +#[inline] +pub(crate) unsafe fn munmap(addr: *mut c::c_void, length: usize) -> io::Result<()> { + ret(syscall!(__NR_munmap, addr, pass_usize(length))) +} + +/// # Safety +/// +/// `mremap` is primarily unsafe due to the `old_address` parameter, as +/// anything working with memory pointed to by raw pointers is unsafe. +#[inline] +pub(crate) unsafe fn mremap( + old_address: *mut c::c_void, + old_size: usize, + new_size: usize, + flags: MremapFlags, +) -> io::Result<*mut c::c_void> { + ret_void_star(syscall!( + __NR_mremap, + old_address, + pass_usize(old_size), + pass_usize(new_size), + flags + )) +} + +/// # Safety +/// +/// `mremap_fixed` is primarily unsafe due to the `old_address` and +/// `new_address` parameters, as anything working with memory pointed to by raw +/// pointers is unsafe. +#[inline] +pub(crate) unsafe fn mremap_fixed( + old_address: *mut c::c_void, + old_size: usize, + new_size: usize, + flags: MremapFlags, + new_address: *mut c::c_void, +) -> io::Result<*mut c::c_void> { + ret_void_star(syscall!( + __NR_mremap, + old_address, + pass_usize(old_size), + pass_usize(new_size), + flags, + new_address + )) +} + +/// # Safety +/// +/// `mlock` operates on raw pointers and may round out to the nearest page +/// boundaries. +#[inline] +pub(crate) unsafe fn mlock(addr: *mut c::c_void, length: usize) -> io::Result<()> { + ret(syscall!(__NR_mlock, addr, pass_usize(length))) +} + +/// # Safety +/// +/// `mlock_with` operates on raw pointers and may round out to the nearest page +/// boundaries. +#[inline] +pub(crate) unsafe fn mlock_with( + addr: *mut c::c_void, + length: usize, + flags: MlockFlags, +) -> io::Result<()> { + ret(syscall!(__NR_mlock2, addr, pass_usize(length), flags)) +} + +/// # Safety +/// +/// `munlock` operates on raw pointers and may round out to the nearest page +/// boundaries. +#[inline] +pub(crate) unsafe fn munlock(addr: *mut c::c_void, length: usize) -> io::Result<()> { + ret(syscall!(__NR_munlock, addr, pass_usize(length))) +} + +#[inline] +pub(crate) unsafe fn userfaultfd(flags: UserfaultfdFlags) -> io::Result<OwnedFd> { + ret_owned_fd(syscall_readonly!(__NR_userfaultfd, flags)) +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/mm/types.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/mm/types.rs new file mode 100644 index 000000000..1adca1ef7 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/mm/types.rs @@ -0,0 +1,210 @@ +use super::super::c; +use bitflags::bitflags; + +bitflags! { + /// `PROT_*` flags for use with [`mmap`]. + /// + /// For `PROT_NONE`, use `ProtFlags::empty()`. + /// + /// [`mmap`]: crate::io::mmap + 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; + } +} + +bitflags! { + /// `PROT_*` flags for use with [`mprotect`]. + /// + /// For `PROT_NONE`, use `MprotectFlags::empty()`. + /// + /// [`mprotect`]: crate::io::mprotect + 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; + } +} + +bitflags! { + /// `MAP_*` flags for use with [`mmap`]. + /// + /// For `MAP_ANONYMOUS` (aka `MAP_ANON`), see [`mmap_anonymous`]. + /// + /// [`mmap`]: crate::io::mmap + /// [`mmap_anonymous`]: crates::io::mmap_anonymous + 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 = "mips64")))] + const SYNC = linux_raw_sys::general::MAP_SYNC; + /// `MAP_UNINITIALIZED` + #[cfg(not(any(target_arch = "mips", target_arch = "mips64")))] + const UNINITIALIZED = linux_raw_sys::general::MAP_UNINITIALIZED; + } +} + +bitflags! { + /// `MREMAP_*` flags for use with [`mremap`]. + /// + /// For `MREMAP_FIXED`, see [`mremap_fixed`]. + /// + /// [`mremap`]: crate::io::mremap + /// [`mremap_fixed`]: crate::io::mremap_fixed + 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; + } +} + +bitflags! { + /// `MLOCK_*` flags for use with [`mlock_with`]. + /// + /// [`mlock_with`]: crate::io::mlock_with + pub struct MlockFlags: u32 { + /// `MLOCK_ONFAULT` + const ONFAULT = linux_raw_sys::general::MLOCK_ONFAULT; + } +} + +bitflags! { + /// `MS_*` flags for use with [`msync`]. + /// + /// [`msync`]: crate::io::msync + 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; + } +} + +bitflags! { + /// `O_*` flags for use with [`userfaultfd`]. + /// + /// [`userfaultfd`]: crate::io::userfaultfd + pub struct UserfaultfdFlags: c::c_uint { + /// `O_CLOEXEC` + const CLOEXEC = linux_raw_sys::general::O_CLOEXEC; + /// `O_NONBLOCK` + const NONBLOCK = linux_raw_sys::general::O_NONBLOCK; + } +} + +/// `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 = "mips64")))] + 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` (since Linux 2.6.38) + LinuxHugepage = linux_raw_sys::general::MADV_HUGEPAGE, + /// `MADV_NOHUGEPAGE` (since Linux 2.6.38) + 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; +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/mod.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/mod.rs new file mode 100644 index 000000000..bf67268f7 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/mod.rs @@ -0,0 +1,81 @@ +//! The linux_raw backend. +//! +//! This makes Linux syscalls directly, without going through libc. +//! +//! # Safety +//! +//! These files performs raw system calls, and sometimes passes them +//! uninitialized memory buffers. The signatures in this file are currently +//! manually maintained and must correspond with the signatures of the actual +//! Linux syscalls. +//! +//! Some of this could be auto-generated from the Linux header file +//! <linux/syscalls.h>, but we often need more information than it provides, +//! such as which pointers are array slices, out parameters, or in-out +//! parameters, which integers are owned or borrowed file descriptors, etc. + +#[macro_use] +mod arch; +mod conv; +mod elf; +mod reg; +#[cfg(any(feature = "time", target_arch = "x86"))] +mod vdso; +#[cfg(any(feature = "time", target_arch = "x86"))] +mod vdso_wrappers; + +#[cfg(any( + feature = "fs", + all( + not(feature = "use-libc-auxv"), + not(target_vendor = "mustang"), + any( + feature = "param", + feature = "runtime", + 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 = "net")] +pub(crate) mod net; +#[cfg(any( + feature = "param", + feature = "runtime", + feature = "time", + target_arch = "x86", +))] +pub(crate) mod param; +pub(crate) mod process; +#[cfg(feature = "pty")] +pub(crate) mod pty; +#[cfg(feature = "rand")] +pub(crate) mod rand; +#[cfg(feature = "runtime")] +pub(crate) mod runtime; +#[cfg(feature = "termios")] +pub(crate) mod termios; +#[cfg(feature = "thread")] +pub(crate) mod thread; +pub(crate) mod time; + +#[cfg(feature = "std")] +pub(crate) mod fd { + pub use io_lifetimes::*; + #[allow(unused_imports)] + pub(crate) use std::os::unix::io::RawFd as LibcFd; + pub use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +} + +#[cfg(not(feature = "std"))] +pub(crate) use crate::io::fd; + +// The linux_raw backend doesn't use actual libc, so we define selected +// libc-like definitions in a module called `c`. +pub(crate) mod c; diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/net/addr.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/net/addr.rs new file mode 100644 index 000000000..c53ba7673 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/net/addr.rs @@ -0,0 +1,167 @@ +//! 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 super::super::c; +use crate::ffi::CStr; +use crate::{io, path}; +use core::cmp::Ordering; +use core::convert::TryInto; +use core::fmt; +use core::hash::{Hash, Hasher}; + +/// `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 bytes = path.to_bytes_with_nul(); + if bytes.len() > unix.sun_path.len() { + return Err(io::Errno::NAMETOOLONG); + } + for (i, b) in bytes.iter().enumerate() { + unix.sun_path[i] = *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..]; + 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) + } + } + + 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] + pub fn path(&self) -> Option<&CStr> { + let len = self.len(); + if len != 0 && self.unix.sun_path[0] != b'\0' { + let end = len as usize - offsetof_sun_path(); + let bytes = &self.unix.sun_path[..end]; + // SAFETY: `from_bytes_with_nul_unchecked` since the string is + // NUL-terminated. + unsafe { Some(CStr::from_bytes_with_nul_unchecked(bytes)) } + } else { + None + } + } + + /// For an abstract address, return the identifier. + #[inline] + pub fn abstract_name(&self) -> Option<&[u8]> { + let len = self.len(); + if len != 0 && self.unix.sun_path[0] == b'\0' { + let end = len as usize - offsetof_sun_path(); + Some(&self.unix.sun_path[1..end]) + } else { + None + } + } + + #[inline] + pub(crate) fn addr_len(&self) -> c::socklen_t { + self.len + } + + #[inline] + pub(crate) fn len(&self) -> usize { + self.addr_len() as usize + } +} + +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> { + let self_len = self.len() - offsetof_sun_path(); + let other_len = other.len() - offsetof_sun_path(); + self.unix.sun_path[..self_len].partial_cmp(&other.unix.sun_path[..other_len]) + } +} + +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, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Some(path) = self.path() { + path.fmt(fmt) + } else if let Some(name) = self.abstract_name() { + name.fmt(fmt) + } else { + "(unnamed)".fmt(fmt) + } + } +} + +/// `struct sockaddr_storage` as a raw struct. +pub type SocketAddrStorage = 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-0.37.22/src/backend/linux_raw/net/mod.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/net/mod.rs new file mode 100644 index 000000000..77956c646 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/net/mod.rs @@ -0,0 +1,7 @@ +pub(crate) mod addr; +pub(crate) mod msghdr; +pub(crate) mod read_sockaddr; +pub(crate) mod send_recv; +pub(crate) mod syscalls; +pub(crate) mod types; +pub(crate) mod write_sockaddr; diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/net/msghdr.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/net/msghdr.rs new file mode 100644 index 000000000..06bcd594d --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/net/msghdr.rs @@ -0,0 +1,144 @@ +//! 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 super::super::c; +use super::super::net::write_sockaddr::{encode_sockaddr_v4, encode_sockaddr_v6}; + +use crate::io::{self, IoSlice, IoSliceMut}; +use crate::net::{RecvAncillaryBuffer, SendAncillaryBuffer, SocketAddrV4, SocketAddrV6}; +use crate::utils::as_ptr; + +use core::convert::TryInto; +use core::mem::{size_of, zeroed, MaybeUninit}; +use core::ptr::null_mut; + +fn msg_iov_len(len: usize) -> c::size_t { + // This cast cannot overflow. + len as c::size_t +} + +pub(crate) 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. +pub(crate) fn with_recv_msghdr<R>( + name: &mut MaybeUninit<c::sockaddr_storage>, + iov: &mut [IoSliceMut<'_>], + control: &mut RecvAncillaryBuffer<'_>, + f: impl FnOnce(&mut c::msghdr) -> io::Result<R>, +) -> io::Result<R> { + control.clear(); + + let namelen = size_of::<c::sockaddr_storage>() as c::c_int; + let mut msghdr = c::msghdr { + msg_name: name.as_mut_ptr().cast(), + msg_namelen: namelen, + 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()), + + // Zero-initialize any padding bytes. + ..unsafe { zeroed() } + }; + + let res = f(&mut msghdr); + + // Reset the control length. + if res.is_ok() { + unsafe { + control.set_control_len(msghdr.msg_controllen.try_into().unwrap_or(usize::MAX)); + } + } + + res +} + +/// Create a message header intended to send without an address. +pub(crate) fn with_noaddr_msghdr<R>( + iov: &[IoSlice<'_>], + control: &mut SendAncillaryBuffer<'_, '_, '_>, + f: impl FnOnce(c::msghdr) -> R, +) -> R { + f(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()), + + // Zero-initialize any padding bytes. + ..unsafe { zeroed() } + }) +} + +/// Create a message header intended to send with an IPv4 address. +pub(crate) fn with_v4_msghdr<R>( + addr: &SocketAddrV4, + iov: &[IoSlice<'_>], + control: &mut SendAncillaryBuffer<'_, '_, '_>, + f: impl FnOnce(c::msghdr) -> R, +) -> R { + let encoded = unsafe { encode_sockaddr_v4(addr) }; + + f(c::msghdr { + msg_name: as_ptr(&encoded) as _, + msg_namelen: size_of::<SocketAddrV4>() as _, + 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()), + + // Zero-initialize any padding bytes. + ..unsafe { zeroed() } + }) +} + +/// Create a message header intended to send with an IPv6 address. +pub(crate) fn with_v6_msghdr<R>( + addr: &SocketAddrV6, + iov: &[IoSlice<'_>], + control: &mut SendAncillaryBuffer<'_, '_, '_>, + f: impl FnOnce(c::msghdr) -> R, +) -> R { + let encoded = unsafe { encode_sockaddr_v6(addr) }; + + f(c::msghdr { + msg_name: as_ptr(&encoded) as _, + msg_namelen: size_of::<SocketAddrV6>() as _, + 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()), + + // Zero-initialize any padding bytes. + ..unsafe { zeroed() } + }) +} + +/// Create a message header intended to send with a Unix address. +pub(crate) fn with_unix_msghdr<R>( + addr: &crate::net::SocketAddrUnix, + iov: &[IoSlice<'_>], + control: &mut SendAncillaryBuffer<'_, '_, '_>, + f: impl FnOnce(c::msghdr) -> R, +) -> R { + f(c::msghdr { + msg_name: as_ptr(addr) as _, + msg_namelen: addr.addr_len() as _, + 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()), + + // Zero-initialize any padding bytes. + ..unsafe { zeroed() } + }) +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/net/read_sockaddr.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/net/read_sockaddr.rs new file mode 100644 index 000000000..c58c3cced --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/net/read_sockaddr.rs @@ -0,0 +1,187 @@ +//! The BSD sockets API requires us to read the `ss_family` field before +//! we can interpret the rest of a `sockaddr` produced by the kernel. +#![allow(unsafe_code)] + +use super::super::c; +use crate::io; +use crate::net::{Ipv4Addr, Ipv6Addr, SocketAddrAny, SocketAddrUnix, SocketAddrV4, SocketAddrV6}; +use core::mem::size_of; + +// This must match the header of `sockaddr`. +#[repr(C)] +struct sockaddr_header { + ss_family: u16, +} + +/// Read the `ss_family` field from a socket address returned from the OS. +/// +/// # Safety +/// +/// `storage` must point to a valid socket address returned from the OS. +#[inline] +unsafe fn read_ss_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::general::__kernel_sockaddr_storage__bindgen_ty_1 { + __bindgen_anon_1: + linux_raw_sys::general::__kernel_sockaddr_storage__bindgen_ty_1__bindgen_ty_1 { + ss_family: 0_u16, + __data: [0; 126_usize], + }, + }, + }, + }; + + (*storage.cast::<sockaddr_header>()).ss_family +} + +/// Set the `ss_family` field of a socket address to `AF_UNSPEC`, so that we +/// can test for `AF_UNSPEC` to test whether it was stored to. +#[inline] +pub(crate) unsafe fn initialize_family_to_unspec(storage: *mut c::sockaddr) { + (*storage.cast::<sockaddr_header>()).ss_family = c::AF_UNSPEC as _; +} + +/// Read a socket address encoded in a platform-specific format. +/// +/// # Safety +/// +/// `storage` must point to valid socket address storage. +pub(crate) unsafe fn read_sockaddr( + storage: *const c::sockaddr, + len: usize, +) -> io::Result<SocketAddrAny> { + let offsetof_sun_path = super::addr::offsetof_sun_path(); + + if len < size_of::<c::sa_family_t>() { + return Err(io::Errno::INVAL); + } + match read_ss_family(storage).into() { + c::AF_INET => { + if len < size_of::<c::sockaddr_in>() { + return Err(io::Errno::INVAL); + } + let decode = *storage.cast::<c::sockaddr_in>(); + Ok(SocketAddrAny::V4(SocketAddrV4::new( + Ipv4Addr::from(u32::from_be(decode.sin_addr.s_addr)), + u16::from_be(decode.sin_port), + ))) + } + c::AF_INET6 => { + if len < size_of::<c::sockaddr_in6>() { + return Err(io::Errno::INVAL); + } + let decode = *storage.cast::<c::sockaddr_in6>(); + Ok(SocketAddrAny::V6(SocketAddrV6::new( + Ipv6Addr::from(decode.sin6_addr.in6_u.u6_addr8), + u16::from_be(decode.sin6_port), + u32::from_be(decode.sin6_flowinfo), + decode.sin6_scope_id, + ))) + } + c::AF_UNIX => { + if len < offsetof_sun_path { + return Err(io::Errno::INVAL); + } + if len == offsetof_sun_path { + Ok(SocketAddrAny::Unix(SocketAddrUnix::new(&[][..])?)) + } else { + let decode = *storage.cast::<c::sockaddr_un>(); + + // On Linux check for Linux's [abstract namespace]. + // + // [abstract namespace]: https://man7.org/linux/man-pages/man7/unix.7.html + #[cfg(linux_kernel)] + if decode.sun_path[0] == 0 { + return SocketAddrUnix::new_abstract_name( + &decode.sun_path[1..len - offsetof_sun_path], + ) + .map(SocketAddrAny::Unix); + } + + // Otherwise we expect a NUL-terminated filesystem path. + assert_eq!(decode.sun_path[len - 1 - offsetof_sun_path], 0); + Ok(SocketAddrAny::Unix(SocketAddrUnix::new( + &decode.sun_path[..len - 1 - offsetof_sun_path], + )?)) + } + } + _ => Err(io::Errno::NOTSUP), + } +} + +/// Read a socket address returned from the OS. +/// +/// # Safety +/// +/// `storage` must point to a valid socket address returned from the OS. +pub(crate) unsafe fn maybe_read_sockaddr_os( + storage: *const c::sockaddr, + len: usize, +) -> Option<SocketAddrAny> { + if len == 0 { + None + } else { + Some(read_sockaddr_os(storage, len)) + } +} + +/// Read a socket address returned from the OS. +/// +/// # Safety +/// +/// `storage` must point to a valid socket address returned from the OS. +pub(crate) unsafe fn read_sockaddr_os(storage: *const c::sockaddr, len: usize) -> SocketAddrAny { + let offsetof_sun_path = super::addr::offsetof_sun_path(); + + assert!(len >= size_of::<c::sa_family_t>()); + match read_ss_family(storage).into() { + c::AF_INET => { + assert!(len >= size_of::<c::sockaddr_in>()); + let decode = *storage.cast::<c::sockaddr_in>(); + SocketAddrAny::V4(SocketAddrV4::new( + Ipv4Addr::from(u32::from_be(decode.sin_addr.s_addr)), + u16::from_be(decode.sin_port), + )) + } + c::AF_INET6 => { + assert!(len >= size_of::<c::sockaddr_in6>()); + let decode = *storage.cast::<c::sockaddr_in6>(); + SocketAddrAny::V6(SocketAddrV6::new( + Ipv6Addr::from(decode.sin6_addr.in6_u.u6_addr8), + u16::from_be(decode.sin6_port), + u32::from_be(decode.sin6_flowinfo), + decode.sin6_scope_id, + )) + } + c::AF_UNIX => { + assert!(len >= offsetof_sun_path); + if len == offsetof_sun_path { + SocketAddrAny::Unix(SocketAddrUnix::new(&[][..]).unwrap()) + } else { + let decode = *storage.cast::<c::sockaddr_un>(); + + // On Linux check for Linux's [abstract namespace]. + // + // [abstract namespace]: https://man7.org/linux/man-pages/man7/unix.7.html + #[cfg(linux_kernel)] + if decode.sun_path[0] == 0 { + return SocketAddrAny::Unix( + SocketAddrUnix::new_abstract_name( + &decode.sun_path[1..len - offsetof_sun_path], + ) + .unwrap(), + ); + } + + // Otherwise we expect a NUL-terminated filesystem path. + assert_eq!(decode.sun_path[len - 1 - offsetof_sun_path], 0); + SocketAddrAny::Unix( + SocketAddrUnix::new(&decode.sun_path[..len - 1 - offsetof_sun_path]).unwrap(), + ) + } + } + other => unimplemented!("{:?}", other), + } +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/net/send_recv.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/net/send_recv.rs new file mode 100644 index 000000000..fb82eaef3 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/net/send_recv.rs @@ -0,0 +1,48 @@ +use super::super::c; +use bitflags::bitflags; + +bitflags! { + /// `MSG_* flags for use with [`send`], [`send_to`], and related functions. + /// + /// [`send`]: crate::net::send + /// [`sendto`]: crate::net::sendto + 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_EOT` + const EOT = c::MSG_EOR; + /// `MSG_MORE` + const MORE = c::MSG_MORE; + /// `MSG_NOSIGNAL` + const NOSIGNAL = c::MSG_NOSIGNAL; + /// `MSG_OOB` + const OOB = c::MSG_OOB; + } +} + +bitflags! { + /// `MSG_* flags for use with [`recv`], [`recvfrom`], and related functions. + /// + /// [`recv`]: crate::net::recv + /// [`recvfrom`]: crate::net::recvfrom + 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; + } +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/net/syscalls.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/net/syscalls.rs new file mode 100644 index 000000000..a9b2d2cd8 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/net/syscalls.rs @@ -0,0 +1,1505 @@ +//! linux_raw syscalls supporting `rustix::net`. +//! +//! # Safety +//! +//! See the `rustix::backend` module documentation for details. +#![allow(unsafe_code)] +#![allow(clippy::undocumented_unsafe_blocks)] + +use super::super::c; +use super::super::conv::{ + by_mut, by_ref, c_int, c_uint, ret, ret_owned_fd, ret_usize, size_of, slice, slice_mut, + socklen_t, zero, +}; +use super::msghdr::{ + with_noaddr_msghdr, with_recv_msghdr, with_unix_msghdr, with_v4_msghdr, with_v6_msghdr, +}; +use super::read_sockaddr::{initialize_family_to_unspec, maybe_read_sockaddr_os, read_sockaddr_os}; +use super::send_recv::{RecvFlags, SendFlags}; +use super::types::{AddressFamily, Protocol, Shutdown, SocketFlags, SocketType}; +use super::write_sockaddr::{encode_sockaddr_v4, encode_sockaddr_v6}; +use crate::fd::{BorrowedFd, OwnedFd}; +use crate::io::{self, IoSlice, IoSliceMut}; +use crate::net::{ + RecvAncillaryBuffer, RecvMsgReturn, SendAncillaryBuffer, SocketAddrAny, SocketAddrUnix, + SocketAddrV4, SocketAddrV6, +}; +use c::{sockaddr, sockaddr_in, sockaddr_in6, socklen_t}; +use core::convert::TryInto; +use core::mem::MaybeUninit; +#[cfg(target_arch = "x86")] +use { + super::super::conv::{slice_just_addr, x86_sys}, + super::super::reg::{ArgReg, SocketArg}, + linux_raw_sys::general::{ + SYS_ACCEPT, SYS_ACCEPT4, SYS_BIND, SYS_CONNECT, SYS_GETPEERNAME, SYS_GETSOCKNAME, + SYS_GETSOCKOPT, SYS_LISTEN, SYS_RECV, SYS_RECVFROM, SYS_RECVMSG, SYS_SEND, SYS_SENDMSG, + SYS_SENDTO, SYS_SETSOCKOPT, SYS_SHUTDOWN, SYS_SOCKET, SYS_SOCKETPAIR, + }, +}; + +#[inline] +pub(crate) fn socket( + family: AddressFamily, + type_: SocketType, + protocol: Protocol, +) -> io::Result<OwnedFd> { + #[cfg(not(target_arch = "x86"))] + unsafe { + ret_owned_fd(syscall_readonly!(__NR_socket, family, type_, protocol)) + } + #[cfg(target_arch = "x86")] + unsafe { + ret_owned_fd(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_SOCKET), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + family.into(), + type_.into(), + protocol.into(), + ]) + )) + } +} + +#[inline] +pub(crate) fn socket_with( + family: AddressFamily, + type_: SocketType, + flags: SocketFlags, + protocol: Protocol, +) -> io::Result<OwnedFd> { + #[cfg(not(target_arch = "x86"))] + unsafe { + ret_owned_fd(syscall_readonly!( + __NR_socket, + family, + (type_, flags), + protocol + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret_owned_fd(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_SOCKET), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + family.into(), + (type_, flags).into(), + protocol.into(), + ]) + )) + } +} + +#[inline] +pub(crate) fn socketpair( + family: AddressFamily, + type_: SocketType, + flags: SocketFlags, + protocol: Protocol, +) -> io::Result<(OwnedFd, OwnedFd)> { + #[cfg(not(target_arch = "x86"))] + unsafe { + let mut result = MaybeUninit::<[OwnedFd; 2]>::uninit(); + ret(syscall!( + __NR_socketpair, + family, + (type_, flags), + protocol, + &mut result + ))?; + let [fd0, fd1] = result.assume_init(); + Ok((fd0, fd1)) + } + #[cfg(target_arch = "x86")] + unsafe { + let mut result = MaybeUninit::<[OwnedFd; 2]>::uninit(); + ret(syscall!( + __NR_socketcall, + x86_sys(SYS_SOCKETPAIR), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + family.into(), + (type_, flags).into(), + protocol.into(), + (&mut result).into(), + ]) + ))?; + let [fd0, fd1] = result.assume_init(); + Ok((fd0, fd1)) + } +} + +#[inline] +pub(crate) fn accept(fd: BorrowedFd<'_>) -> io::Result<OwnedFd> { + #[cfg(not(target_arch = "x86"))] + unsafe { + let fd = ret_owned_fd(syscall_readonly!(__NR_accept, fd, zero(), zero()))?; + Ok(fd) + } + #[cfg(target_arch = "x86")] + unsafe { + let fd = ret_owned_fd(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_ACCEPT), + slice_just_addr::<ArgReg<SocketArg>, _>(&[fd.into(), zero(), zero()]) + ))?; + Ok(fd) + } +} + +#[inline] +pub(crate) fn accept_with(fd: BorrowedFd<'_>, flags: 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(target_arch = "x86"))] + unsafe { + let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t; + let mut storage = MaybeUninit::<sockaddr>::uninit(); + let fd = ret_owned_fd(syscall!( + __NR_accept, + fd, + &mut storage, + by_mut(&mut addrlen) + ))?; + Ok(( + fd, + maybe_read_sockaddr_os(&storage.assume_init(), addrlen.try_into().unwrap()), + )) + } + #[cfg(target_arch = "x86")] + unsafe { + let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t; + let mut storage = MaybeUninit::<sockaddr>::uninit(); + let fd = ret_owned_fd(syscall!( + __NR_socketcall, + x86_sys(SYS_ACCEPT), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + (&mut storage).into(), + by_mut(&mut addrlen), + ]) + ))?; + Ok(( + fd, + maybe_read_sockaddr_os(&storage.assume_init(), addrlen.try_into().unwrap()), + )) + } +} + +#[inline] +pub(crate) fn acceptfrom_with( + fd: BorrowedFd<'_>, + flags: SocketFlags, +) -> io::Result<(OwnedFd, Option<SocketAddrAny>)> { + #[cfg(not(target_arch = "x86"))] + unsafe { + let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t; + let mut storage = MaybeUninit::<sockaddr>::uninit(); + let fd = ret_owned_fd(syscall!( + __NR_accept4, + fd, + &mut storage, + by_mut(&mut addrlen), + flags + ))?; + Ok(( + fd, + maybe_read_sockaddr_os(&storage.assume_init(), addrlen.try_into().unwrap()), + )) + } + #[cfg(target_arch = "x86")] + unsafe { + let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t; + let mut storage = MaybeUninit::<sockaddr>::uninit(); + let fd = ret_owned_fd(syscall!( + __NR_socketcall, + x86_sys(SYS_ACCEPT4), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + (&mut storage).into(), + by_mut(&mut addrlen), + flags.into(), + ]) + ))?; + Ok(( + fd, + maybe_read_sockaddr_os(&storage.assume_init(), addrlen.try_into().unwrap()), + )) + } +} + +#[inline] +pub(crate) fn recvmsg( + sockfd: BorrowedFd<'_>, + iov: &mut [IoSliceMut<'_>], + control: &mut RecvAncillaryBuffer<'_>, + msg_flags: RecvFlags, +) -> io::Result<RecvMsgReturn> { + let mut storage = MaybeUninit::<c::sockaddr_storage>::uninit(); + + with_recv_msghdr(&mut storage, iov, control, |msghdr| { + #[cfg(not(target_arch = "x86"))] + let result = unsafe { + ret_usize(syscall!( + __NR_recvmsg, + sockfd, + by_mut(msghdr), + c_uint(msg_flags.bits()) + )) + }; + + #[cfg(target_arch = "x86")] + let result = unsafe { + ret_usize(syscall!( + __NR_socketcall, + x86_sys(SYS_RECVMSG), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + sockfd.into(), + by_mut(msghdr), + c_uint(msg_flags.bits()).into(), + ]) + )) + }; + + result.map(|bytes| { + // Get the address of the sender, if any. + let addr = + unsafe { maybe_read_sockaddr_os(msghdr.msg_name as _, msghdr.msg_namelen as _) }; + + RecvMsgReturn { + bytes, + address: addr, + flags: RecvFlags::from_bits_truncate(msghdr.msg_flags), + } + }) + }) +} + +#[inline] +pub(crate) fn sendmsg_noaddr( + sockfd: BorrowedFd<'_>, + iov: &[IoSlice<'_>], + control: &mut SendAncillaryBuffer<'_, '_, '_>, + msg_flags: SendFlags, +) -> io::Result<usize> { + with_noaddr_msghdr(iov, control, |msghdr| { + #[cfg(not(target_arch = "x86"))] + let result = unsafe { + ret_usize(syscall!( + __NR_sendmsg, + sockfd, + by_ref(&msghdr), + c_uint(msg_flags.bits()) + )) + }; + + #[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), + c_uint(msg_flags.bits()) + ]) + )) + }; + + result + }) +} + +#[inline] +pub(crate) fn sendmsg_v4( + sockfd: BorrowedFd<'_>, + addr: &SocketAddrV4, + iov: &[IoSlice<'_>], + control: &mut SendAncillaryBuffer<'_, '_, '_>, + msg_flags: SendFlags, +) -> io::Result<usize> { + with_v4_msghdr(addr, iov, control, |msghdr| { + #[cfg(not(target_arch = "x86"))] + let result = unsafe { + ret_usize(syscall!( + __NR_sendmsg, + sockfd, + by_ref(&msghdr), + c_uint(msg_flags.bits()) + )) + }; + + #[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), + c_uint(msg_flags.bits()) + ]) + )) + }; + + result + }) +} + +#[inline] +pub(crate) fn sendmsg_v6( + sockfd: BorrowedFd<'_>, + addr: &SocketAddrV6, + iov: &[IoSlice<'_>], + control: &mut SendAncillaryBuffer<'_, '_, '_>, + msg_flags: SendFlags, +) -> io::Result<usize> { + with_v6_msghdr(addr, iov, control, |msghdr| { + #[cfg(not(target_arch = "x86"))] + let result = unsafe { + ret_usize(syscall!( + __NR_sendmsg, + sockfd, + by_ref(&msghdr), + c_uint(msg_flags.bits()) + )) + }; + + #[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), + c_uint(msg_flags.bits()) + ]) + )) + }; + + result + }) +} + +#[inline] +pub(crate) fn sendmsg_unix( + sockfd: BorrowedFd<'_>, + addr: &SocketAddrUnix, + iov: &[IoSlice<'_>], + control: &mut SendAncillaryBuffer<'_, '_, '_>, + msg_flags: SendFlags, +) -> io::Result<usize> { + with_unix_msghdr(addr, iov, control, |msghdr| { + #[cfg(not(target_arch = "x86"))] + let result = unsafe { + ret_usize(syscall!( + __NR_sendmsg, + sockfd, + by_ref(&msghdr), + c_uint(msg_flags.bits()) + )) + }; + + #[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), + c_uint(msg_flags.bits()) + ]) + )) + }; + + 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 = "riscv64", + target_arch = "x86", + target_arch = "x86_64", + )))] + unsafe { + ret_usize(syscall_readonly!(__NR_send, fd, buf_addr, buf_len, flags)) + } + #[cfg(any( + target_arch = "aarch64", + target_arch = "mips64", + target_arch = "riscv64", + target_arch = "x86_64", + ))] + unsafe { + ret_usize(syscall_readonly!( + __NR_sendto, + fd, + buf_addr, + buf_len, + flags, + zero(), + zero() + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret_usize(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_SEND), + slice_just_addr::<ArgReg<SocketArg>, _>(&[fd.into(), buf_addr, buf_len, flags.into()]) + )) + } +} + +#[inline] +pub(crate) fn sendto_v4( + fd: BorrowedFd<'_>, + buf: &[u8], + flags: SendFlags, + addr: &SocketAddrV4, +) -> io::Result<usize> { + let (buf_addr, buf_len) = slice(buf); + + #[cfg(not(target_arch = "x86"))] + unsafe { + ret_usize(syscall_readonly!( + __NR_sendto, + fd, + buf_addr, + buf_len, + flags, + by_ref(&encode_sockaddr_v4(addr)), + size_of::<sockaddr_in, _>() + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret_usize(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_SENDTO), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + buf_addr, + buf_len, + flags.into(), + by_ref(&encode_sockaddr_v4(addr)), + size_of::<sockaddr_in, _>(), + ]) + )) + } +} + +#[inline] +pub(crate) fn sendto_v6( + fd: BorrowedFd<'_>, + buf: &[u8], + flags: SendFlags, + addr: &SocketAddrV6, +) -> io::Result<usize> { + let (buf_addr, buf_len) = slice(buf); + + #[cfg(not(target_arch = "x86"))] + unsafe { + ret_usize(syscall_readonly!( + __NR_sendto, + fd, + buf_addr, + buf_len, + flags, + by_ref(&encode_sockaddr_v6(addr)), + size_of::<sockaddr_in6, _>() + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret_usize(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_SENDTO), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + buf_addr, + buf_len, + flags.into(), + by_ref(&encode_sockaddr_v6(addr)), + size_of::<sockaddr_in6, _>(), + ]) + )) + } +} + +#[inline] +pub(crate) fn sendto_unix( + fd: BorrowedFd<'_>, + buf: &[u8], + flags: SendFlags, + addr: &SocketAddrUnix, +) -> io::Result<usize> { + let (buf_addr, buf_len) = slice(buf); + + #[cfg(not(target_arch = "x86"))] + unsafe { + ret_usize(syscall_readonly!( + __NR_sendto, + fd, + buf_addr, + buf_len, + flags, + by_ref(&addr.unix), + socklen_t(addr.addr_len()) + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret_usize(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_SENDTO), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + buf_addr, + buf_len, + flags.into(), + by_ref(&addr.unix), + socklen_t(addr.addr_len()), + ]) + )) + } +} + +#[inline] +pub(crate) fn recv(fd: BorrowedFd<'_>, buf: &mut [u8], flags: RecvFlags) -> io::Result<usize> { + let (buf_addr_mut, buf_len) = slice_mut(buf); + + #[cfg(not(any( + target_arch = "aarch64", + target_arch = "mips64", + target_arch = "riscv64", + target_arch = "x86", + target_arch = "x86_64", + )))] + unsafe { + ret_usize(syscall!(__NR_recv, fd, buf_addr_mut, buf_len, flags)) + } + #[cfg(any( + target_arch = "aarch64", + target_arch = "mips64", + target_arch = "riscv64", + target_arch = "x86_64", + ))] + unsafe { + ret_usize(syscall!( + __NR_recvfrom, + fd, + buf_addr_mut, + buf_len, + flags, + zero(), + zero() + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret_usize(syscall!( + __NR_socketcall, + x86_sys(SYS_RECV), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + buf_addr_mut, + buf_len, + flags.into(), + ]) + )) + } +} + +#[inline] +pub(crate) fn recvfrom( + fd: BorrowedFd<'_>, + buf: &mut [u8], + flags: RecvFlags, +) -> io::Result<(usize, Option<SocketAddrAny>)> { + let (buf_addr_mut, buf_len) = slice_mut(buf); + + let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t; + let mut storage = MaybeUninit::<sockaddr>::uninit(); + + unsafe { + // `recvfrom` does not write to the storage if the socket is + // connection-oriented sockets, so we initialize the family field to + // `AF_UNSPEC` so that we can detect this case. + initialize_family_to_unspec(storage.as_mut_ptr()); + + #[cfg(not(target_arch = "x86"))] + let nread = ret_usize(syscall!( + __NR_recvfrom, + fd, + buf_addr_mut, + buf_len, + flags, + &mut storage, + by_mut(&mut addrlen) + ))?; + #[cfg(target_arch = "x86")] + let nread = ret_usize(syscall!( + __NR_socketcall, + x86_sys(SYS_RECVFROM), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + buf_addr_mut, + buf_len, + flags.into(), + (&mut storage).into(), + by_mut(&mut addrlen), + ]) + ))?; + + Ok(( + nread, + maybe_read_sockaddr_os(&storage.assume_init(), addrlen.try_into().unwrap()), + )) + } +} + +#[inline] +pub(crate) fn getpeername(fd: BorrowedFd<'_>) -> io::Result<Option<SocketAddrAny>> { + #[cfg(not(target_arch = "x86"))] + unsafe { + let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t; + let mut storage = MaybeUninit::<sockaddr>::uninit(); + ret(syscall!( + __NR_getpeername, + fd, + &mut storage, + by_mut(&mut addrlen) + ))?; + Ok(maybe_read_sockaddr_os( + &storage.assume_init(), + addrlen.try_into().unwrap(), + )) + } + #[cfg(target_arch = "x86")] + unsafe { + let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t; + let mut storage = MaybeUninit::<sockaddr>::uninit(); + ret(syscall!( + __NR_socketcall, + x86_sys(SYS_GETPEERNAME), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + (&mut storage).into(), + by_mut(&mut addrlen), + ]) + ))?; + Ok(maybe_read_sockaddr_os( + &storage.assume_init(), + addrlen.try_into().unwrap(), + )) + } +} + +#[inline] +pub(crate) fn getsockname(fd: BorrowedFd<'_>) -> io::Result<SocketAddrAny> { + #[cfg(not(target_arch = "x86"))] + unsafe { + let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t; + let mut storage = MaybeUninit::<sockaddr>::uninit(); + ret(syscall!( + __NR_getsockname, + fd, + &mut storage, + by_mut(&mut addrlen) + ))?; + Ok(read_sockaddr_os( + &storage.assume_init(), + addrlen.try_into().unwrap(), + )) + } + #[cfg(target_arch = "x86")] + unsafe { + let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t; + let mut storage = MaybeUninit::<sockaddr>::uninit(); + ret(syscall!( + __NR_socketcall, + x86_sys(SYS_GETSOCKNAME), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + (&mut storage).into(), + by_mut(&mut addrlen), + ]) + ))?; + Ok(read_sockaddr_os( + &storage.assume_init(), + addrlen.try_into().unwrap(), + )) + } +} + +#[inline] +pub(crate) fn bind_v4(fd: BorrowedFd<'_>, addr: &SocketAddrV4) -> io::Result<()> { + #[cfg(not(target_arch = "x86"))] + unsafe { + ret(syscall_readonly!( + __NR_bind, + fd, + by_ref(&encode_sockaddr_v4(addr)), + size_of::<sockaddr_in, _>() + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_BIND), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + by_ref(&encode_sockaddr_v4(addr)), + size_of::<sockaddr_in, _>(), + ]) + )) + } +} + +#[inline] +pub(crate) fn bind_v6(fd: BorrowedFd<'_>, addr: &SocketAddrV6) -> io::Result<()> { + #[cfg(not(target_arch = "x86"))] + unsafe { + ret(syscall_readonly!( + __NR_bind, + fd, + by_ref(&encode_sockaddr_v6(addr)), + size_of::<sockaddr_in6, _>() + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_BIND), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + by_ref(&encode_sockaddr_v6(addr)), + size_of::<sockaddr_in6, _>(), + ]) + )) + } +} + +#[inline] +pub(crate) fn bind_unix(fd: BorrowedFd<'_>, addr: &SocketAddrUnix) -> io::Result<()> { + #[cfg(not(target_arch = "x86"))] + unsafe { + ret(syscall_readonly!( + __NR_bind, + fd, + by_ref(&addr.unix), + socklen_t(addr.addr_len()) + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_BIND), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + by_ref(&addr.unix), + socklen_t(addr.addr_len()), + ]) + )) + } +} + +#[inline] +pub(crate) fn connect_v4(fd: BorrowedFd<'_>, addr: &SocketAddrV4) -> io::Result<()> { + #[cfg(not(target_arch = "x86"))] + unsafe { + ret(syscall_readonly!( + __NR_connect, + fd, + by_ref(&encode_sockaddr_v4(addr)), + size_of::<sockaddr_in, _>() + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_CONNECT), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + by_ref(&encode_sockaddr_v4(addr)), + size_of::<sockaddr_in, _>(), + ]) + )) + } +} + +#[inline] +pub(crate) fn connect_v6(fd: BorrowedFd<'_>, addr: &SocketAddrV6) -> io::Result<()> { + #[cfg(not(target_arch = "x86"))] + unsafe { + ret(syscall_readonly!( + __NR_connect, + fd, + by_ref(&encode_sockaddr_v6(addr)), + size_of::<sockaddr_in6, _>() + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_CONNECT), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + by_ref(&encode_sockaddr_v6(addr)), + size_of::<sockaddr_in6, _>(), + ]) + )) + } +} + +#[inline] +pub(crate) fn connect_unix(fd: BorrowedFd<'_>, addr: &SocketAddrUnix) -> io::Result<()> { + #[cfg(not(target_arch = "x86"))] + unsafe { + ret(syscall_readonly!( + __NR_connect, + fd, + by_ref(&addr.unix), + socklen_t(addr.addr_len()) + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_CONNECT), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + by_ref(&addr.unix), + socklen_t(addr.addr_len()), + ]) + )) + } +} + +#[inline] +pub(crate) fn listen(fd: BorrowedFd<'_>, backlog: c::c_int) -> io::Result<()> { + #[cfg(not(target_arch = "x86"))] + unsafe { + ret(syscall_readonly!(__NR_listen, fd, c_int(backlog))) + } + #[cfg(target_arch = "x86")] + unsafe { + ret(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_LISTEN), + slice_just_addr::<ArgReg<SocketArg>, _>(&[fd.into(), c_int(backlog)]) + )) + } +} + +pub(crate) mod sockopt { + use super::{c, BorrowedFd}; + use crate::io; + use crate::net::sockopt::Timeout; + use crate::net::{Ipv4Addr, Ipv6Addr, SocketType}; + use c::{SO_RCVTIMEO_NEW, SO_RCVTIMEO_OLD, SO_SNDTIMEO_NEW, SO_SNDTIMEO_OLD}; + use core::convert::TryInto; + use core::time::Duration; + use linux_raw_sys::general::{__kernel_timespec, timeval}; + + // TODO: With Rust 1.53 we can use `Duration::ZERO` instead. + const DURATION_ZERO: Duration = Duration::from_secs(0); + + #[inline] + fn getsockopt<T: Copy>(fd: BorrowedFd<'_>, level: u32, optname: u32) -> io::Result<T> { + use super::*; + + let mut optlen = core::mem::size_of::<T>(); + debug_assert!( + optlen as usize >= core::mem::size_of::<c::c_int>(), + "Socket APIs don't ever use `bool` directly" + ); + + #[cfg(not(target_arch = "x86"))] + unsafe { + let mut value = MaybeUninit::<T>::uninit(); + ret(syscall!( + __NR_getsockopt, + fd, + c_uint(level), + c_uint(optname), + &mut value, + by_mut(&mut optlen) + ))?; + + assert_eq!( + optlen as usize, + core::mem::size_of::<T>(), + "unexpected getsockopt size" + ); + Ok(value.assume_init()) + } + #[cfg(target_arch = "x86")] + unsafe { + let mut value = MaybeUninit::<T>::uninit(); + ret(syscall!( + __NR_socketcall, + x86_sys(SYS_GETSOCKOPT), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + c_uint(level), + c_uint(optname), + (&mut value).into(), + by_mut(&mut optlen), + ]) + ))?; + assert_eq!( + optlen as usize, + core::mem::size_of::<T>(), + "unexpected getsockopt size" + ); + Ok(value.assume_init()) + } + } + + #[inline] + fn setsockopt<T: Copy>( + fd: BorrowedFd<'_>, + level: u32, + optname: u32, + value: T, + ) -> io::Result<()> { + use super::*; + + let optlen = core::mem::size_of::<T>().try_into().unwrap(); + debug_assert!( + optlen as usize >= core::mem::size_of::<c::c_int>(), + "Socket APIs don't ever use `bool` directly" + ); + + #[cfg(not(target_arch = "x86"))] + unsafe { + ret(syscall_readonly!( + __NR_setsockopt, + fd, + c_uint(level), + c_uint(optname), + by_ref(&value), + socklen_t(optlen) + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_SETSOCKOPT), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + c_uint(level), + c_uint(optname), + by_ref(&value), + socklen_t(optlen), + ]) + )) + } + } + + #[inline] + pub(crate) fn get_socket_type(fd: BorrowedFd<'_>) -> io::Result<SocketType> { + getsockopt(fd, c::SOL_SOCKET as _, c::SO_TYPE) + } + + #[inline] + pub(crate) fn set_socket_reuseaddr(fd: BorrowedFd<'_>, reuseaddr: bool) -> io::Result<()> { + setsockopt( + fd, + c::SOL_SOCKET as _, + c::SO_REUSEADDR, + from_bool(reuseaddr), + ) + } + + #[inline] + pub(crate) fn set_socket_broadcast(fd: BorrowedFd<'_>, broadcast: bool) -> io::Result<()> { + setsockopt( + fd, + c::SOL_SOCKET as _, + c::SO_BROADCAST, + from_bool(broadcast), + ) + } + + #[inline] + pub(crate) fn get_socket_broadcast(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::SOL_SOCKET as _, c::SO_BROADCAST).map(to_bool) + } + + #[inline] + pub(crate) fn set_socket_linger( + fd: BorrowedFd<'_>, + linger: Option<Duration>, + ) -> io::Result<()> { + // Convert `linger` to seconds, rounding up. + let l_linger = if let Some(linger) = linger { + let mut l_linger = linger.as_secs(); + if linger.subsec_nanos() != 0 { + l_linger = l_linger.checked_add(1).ok_or(io::Errno::INVAL)?; + } + l_linger.try_into().map_err(|_e| io::Errno::INVAL)? + } else { + 0 + }; + let linger = c::linger { + l_onoff: c::c_int::from(linger.is_some()), + l_linger, + }; + setsockopt(fd, c::SOL_SOCKET as _, c::SO_LINGER, linger) + } + + #[inline] + pub(crate) fn get_socket_linger(fd: BorrowedFd<'_>) -> io::Result<Option<Duration>> { + let linger: c::linger = getsockopt(fd, c::SOL_SOCKET as _, c::SO_LINGER)?; + // TODO: With Rust 1.50, this could use `.then`. + Ok(if linger.l_onoff != 0 { + Some(Duration::from_secs(linger.l_linger as u64)) + } else { + None + }) + } + + #[inline] + pub(crate) fn set_socket_passcred(fd: BorrowedFd<'_>, passcred: bool) -> io::Result<()> { + setsockopt(fd, c::SOL_SOCKET as _, c::SO_PASSCRED, from_bool(passcred)) + } + + #[inline] + pub(crate) fn get_socket_passcred(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::SOL_SOCKET as _, c::SO_PASSCRED).map(to_bool) + } + + #[inline] + pub(crate) fn set_socket_timeout( + fd: BorrowedFd<'_>, + id: Timeout, + timeout: Option<Duration>, + ) -> io::Result<()> { + let time = duration_to_linux(timeout)?; + let optname = match id { + Timeout::Recv => SO_RCVTIMEO_NEW, + Timeout::Send => SO_SNDTIMEO_NEW, + }; + match setsockopt(fd, c::SOL_SOCKET, optname, time) { + Err(io::Errno::NOPROTOOPT) if SO_RCVTIMEO_NEW != SO_RCVTIMEO_OLD => { + set_socket_timeout_old(fd, id, timeout) + } + otherwise => otherwise, + } + } + + /// Same as `set_socket_timeout` but uses `timeval` instead of + /// `__kernel_timespec` and `_OLD` constants instead of `_NEW`. + fn set_socket_timeout_old( + fd: BorrowedFd<'_>, + id: Timeout, + timeout: Option<Duration>, + ) -> io::Result<()> { + let time = duration_to_linux_old(timeout)?; + let optname = match id { + Timeout::Recv => SO_RCVTIMEO_OLD, + Timeout::Send => SO_SNDTIMEO_OLD, + }; + setsockopt(fd, c::SOL_SOCKET, optname, time) + } + + #[inline] + pub(crate) fn get_socket_timeout( + fd: BorrowedFd<'_>, + id: Timeout, + ) -> io::Result<Option<Duration>> { + let optname = match id { + Timeout::Recv => SO_RCVTIMEO_NEW, + Timeout::Send => SO_SNDTIMEO_NEW, + }; + let time: __kernel_timespec = match getsockopt(fd, c::SOL_SOCKET, optname) { + Err(io::Errno::NOPROTOOPT) if SO_RCVTIMEO_NEW != SO_RCVTIMEO_OLD => { + return get_socket_timeout_old(fd, id) + } + otherwise => otherwise?, + }; + Ok(duration_from_linux(time)) + } + + /// Same as `get_socket_timeout` but uses `timeval` instead of + /// `__kernel_timespec` and `_OLD` constants instead of `_NEW`. + fn get_socket_timeout_old(fd: BorrowedFd<'_>, id: Timeout) -> io::Result<Option<Duration>> { + let optname = match id { + Timeout::Recv => SO_RCVTIMEO_OLD, + Timeout::Send => SO_SNDTIMEO_OLD, + }; + let time: timeval = getsockopt(fd, c::SOL_SOCKET, optname)?; + Ok(duration_from_linux_old(time)) + } + + /// Convert a C `timespec` to a Rust `Option<Duration>`. + #[inline] + fn duration_from_linux(time: __kernel_timespec) -> Option<Duration> { + if time.tv_sec == 0 && time.tv_nsec == 0 { + None + } else { + Some( + Duration::from_secs(time.tv_sec as u64) + Duration::from_nanos(time.tv_nsec as u64), + ) + } + } + + /// Like `duration_from_linux` but uses Linux's old 32-bit `timeval`. + fn duration_from_linux_old(time: timeval) -> Option<Duration> { + if time.tv_sec == 0 && time.tv_usec == 0 { + None + } else { + Some( + Duration::from_secs(time.tv_sec as u64) + + Duration::from_micros(time.tv_usec as u64), + ) + } + } + + /// Convert a Rust `Option<Duration>` to a C `timespec`. + #[inline] + fn duration_to_linux(timeout: Option<Duration>) -> io::Result<__kernel_timespec> { + Ok(match timeout { + Some(timeout) => { + if timeout == DURATION_ZERO { + return Err(io::Errno::INVAL); + } + let mut timeout = __kernel_timespec { + tv_sec: timeout.as_secs().try_into().unwrap_or(i64::MAX), + tv_nsec: timeout.subsec_nanos().into(), + }; + if timeout.tv_sec == 0 && timeout.tv_nsec == 0 { + timeout.tv_nsec = 1; + } + timeout + } + None => __kernel_timespec { + tv_sec: 0, + tv_nsec: 0, + }, + }) + } + + /// Like `duration_to_linux` but uses Linux's old 32-bit `timeval`. + fn duration_to_linux_old(timeout: Option<Duration>) -> io::Result<timeval> { + Ok(match timeout { + Some(timeout) => { + if timeout == DURATION_ZERO { + return Err(io::Errno::INVAL); + } + + // `subsec_micros` rounds down, so we use `subsec_nanos` and + // manually round up. + let mut timeout = timeval { + tv_sec: timeout.as_secs().try_into().unwrap_or(c::c_long::MAX), + tv_usec: ((timeout.subsec_nanos() + 999) / 1000) as _, + }; + if timeout.tv_sec == 0 && timeout.tv_usec == 0 { + timeout.tv_usec = 1; + } + timeout + } + None => timeval { + tv_sec: 0, + tv_usec: 0, + }, + }) + } + + #[inline] + pub(crate) fn get_socket_error(fd: BorrowedFd<'_>) -> io::Result<Result<(), io::Errno>> { + let err: c::c_int = getsockopt(fd, c::SOL_SOCKET as _, 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 as _, + c::SO_KEEPALIVE, + from_bool(keepalive), + ) + } + + #[inline] + pub(crate) fn get_socket_keepalive(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::SOL_SOCKET as _, 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::OVERFLOW)?; + setsockopt(fd, c::SOL_SOCKET as _, c::SO_RCVBUF, size) + } + + #[inline] + pub(crate) fn get_socket_recv_buffer_size(fd: BorrowedFd<'_>) -> io::Result<usize> { + getsockopt(fd, c::SOL_SOCKET as _, 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::OVERFLOW)?; + setsockopt(fd, c::SOL_SOCKET as _, c::SO_SNDBUF, size) + } + + #[inline] + pub(crate) fn get_socket_send_buffer_size(fd: BorrowedFd<'_>) -> io::Result<usize> { + getsockopt(fd, c::SOL_SOCKET as _, c::SO_SNDBUF).map(|size: u32| size as usize) + } + + #[inline] + pub(crate) fn set_ip_ttl(fd: BorrowedFd<'_>, ttl: u32) -> io::Result<()> { + setsockopt(fd, c::IPPROTO_IP as _, c::IP_TTL, ttl) + } + + #[inline] + pub(crate) fn get_ip_ttl(fd: BorrowedFd<'_>) -> io::Result<u32> { + getsockopt(fd, c::IPPROTO_IP as _, c::IP_TTL) + } + + #[inline] + pub(crate) fn set_ipv6_v6only(fd: BorrowedFd<'_>, only_v6: bool) -> io::Result<()> { + setsockopt(fd, c::IPPROTO_IPV6 as _, c::IPV6_V6ONLY, from_bool(only_v6)) + } + + #[inline] + pub(crate) fn get_ipv6_v6only(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::IPPROTO_IPV6 as _, c::IPV6_V6ONLY).map(to_bool) + } + + #[inline] + pub(crate) fn set_ip_multicast_loop( + fd: BorrowedFd<'_>, + multicast_loop: bool, + ) -> io::Result<()> { + setsockopt( + fd, + c::IPPROTO_IP as _, + c::IP_MULTICAST_LOOP, + from_bool(multicast_loop), + ) + } + + #[inline] + pub(crate) fn get_ip_multicast_loop(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::IPPROTO_IP as _, c::IP_MULTICAST_LOOP).map(to_bool) + } + + #[inline] + pub(crate) fn set_ip_multicast_ttl(fd: BorrowedFd<'_>, multicast_ttl: u32) -> io::Result<()> { + setsockopt(fd, c::IPPROTO_IP as _, c::IP_MULTICAST_TTL, multicast_ttl) + } + + #[inline] + pub(crate) fn get_ip_multicast_ttl(fd: BorrowedFd<'_>) -> io::Result<u32> { + getsockopt(fd, c::IPPROTO_IP as _, c::IP_MULTICAST_TTL) + } + + #[inline] + pub(crate) fn set_ipv6_multicast_loop( + fd: BorrowedFd<'_>, + multicast_loop: bool, + ) -> io::Result<()> { + setsockopt( + fd, + c::IPPROTO_IPV6 as _, + c::IPV6_MULTICAST_LOOP, + from_bool(multicast_loop), + ) + } + + #[inline] + pub(crate) fn get_ipv6_multicast_loop(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::IPPROTO_IPV6 as _, c::IPV6_MULTICAST_LOOP).map(to_bool) + } + + #[inline] + pub(crate) fn set_ipv6_multicast_hops( + fd: BorrowedFd<'_>, + multicast_hops: u32, + ) -> io::Result<()> { + setsockopt( + fd, + c::IPPROTO_IP as _, + c::IPV6_MULTICAST_HOPS, + multicast_hops, + ) + } + + #[inline] + pub(crate) fn get_ipv6_multicast_hops(fd: BorrowedFd<'_>) -> io::Result<u32> { + getsockopt(fd, c::IPPROTO_IP as _, c::IPV6_MULTICAST_HOPS) + } + + #[inline] + pub(crate) fn set_ip_add_membership( + fd: BorrowedFd<'_>, + multiaddr: &Ipv4Addr, + interface: &Ipv4Addr, + ) -> io::Result<()> { + let mreq = to_imr(multiaddr, interface); + setsockopt(fd, c::IPPROTO_IP as _, c::IP_ADD_MEMBERSHIP, mreq) + } + + #[inline] + pub(crate) fn set_ipv6_add_membership( + fd: BorrowedFd<'_>, + multiaddr: &Ipv6Addr, + interface: u32, + ) -> io::Result<()> { + let mreq = to_ipv6mr(multiaddr, interface); + setsockopt(fd, c::IPPROTO_IPV6 as _, c::IPV6_ADD_MEMBERSHIP, mreq) + } + + #[inline] + pub(crate) fn set_ip_drop_membership( + fd: BorrowedFd<'_>, + multiaddr: &Ipv4Addr, + interface: &Ipv4Addr, + ) -> io::Result<()> { + let mreq = to_imr(multiaddr, interface); + setsockopt(fd, c::IPPROTO_IP as _, c::IP_DROP_MEMBERSHIP, mreq) + } + + #[inline] + pub(crate) fn set_ipv6_drop_membership( + fd: BorrowedFd<'_>, + multiaddr: &Ipv6Addr, + interface: u32, + ) -> io::Result<()> { + let mreq = to_ipv6mr(multiaddr, interface); + setsockopt(fd, c::IPPROTO_IPV6 as _, c::IPV6_DROP_MEMBERSHIP, mreq) + } + + #[inline] + pub(crate) fn get_ipv6_unicast_hops(fd: BorrowedFd<'_>) -> io::Result<u8> { + getsockopt(fd, c::IPPROTO_IPV6 as _, 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 as _, c::IPV6_UNICAST_HOPS, hops) + } + + #[inline] + pub(crate) fn set_tcp_nodelay(fd: BorrowedFd<'_>, nodelay: bool) -> io::Result<()> { + setsockopt(fd, c::IPPROTO_TCP as _, c::TCP_NODELAY, from_bool(nodelay)) + } + + #[inline] + pub(crate) fn get_tcp_nodelay(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::IPPROTO_TCP as _, c::TCP_NODELAY).map(to_bool) + } + + #[inline] + fn to_imr(multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> c::ip_mreq { + c::ip_mreq { + imr_multiaddr: to_imr_addr(multiaddr), + imr_interface: to_imr_addr(interface), + } + } + + #[inline] + fn to_imr_addr(addr: &Ipv4Addr) -> c::in_addr { + c::in_addr { + s_addr: u32::from_ne_bytes(addr.octets()), + } + } + + #[inline] + fn to_ipv6mr(multiaddr: &Ipv6Addr, interface: u32) -> c::ipv6_mreq { + c::ipv6_mreq { + ipv6mr_multiaddr: to_ipv6mr_multiaddr(multiaddr), + ipv6mr_ifindex: to_ipv6mr_interface(interface), + } + } + + #[inline] + fn to_ipv6mr_multiaddr(multiaddr: &Ipv6Addr) -> c::in6_addr { + c::in6_addr { + in6_u: linux_raw_sys::general::in6_addr__bindgen_ty_1 { + u6_addr8: multiaddr.octets(), + }, + } + } + + #[inline] + fn to_ipv6mr_interface(interface: u32) -> c::c_int { + interface as c::c_int + } + + #[inline] + fn from_bool(value: bool) -> c::c_uint { + c::c_uint::from(value) + } + + #[inline] + fn to_bool(value: c::c_uint) -> bool { + value != 0 + } +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/net/types.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/net/types.rs new file mode 100644 index 000000000..3f0b571a5 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/net/types.rs @@ -0,0 +1,275 @@ +use super::super::c; +use bitflags::bitflags; + +/// A type for holding raw integer socket types. +#[doc(hidden)] +pub type RawSocketType = u32; + +/// `SOCK_*` constants for use with [`socket`]. +/// +/// [`socket`]: crate::net::socket +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[repr(transparent)] +pub struct SocketType(pub(crate) RawSocketType); + +#[rustfmt::skip] +impl SocketType { + /// `SOCK_STREAM` + pub const STREAM: Self = Self(c::SOCK_STREAM); + + /// `SOCK_DGRAM` + pub const DGRAM: Self = Self(c::SOCK_DGRAM); + + /// `SOCK_SEQPACKET` + pub const SEQPACKET: Self = Self(c::SOCK_SEQPACKET); + + /// `SOCK_RAW` + pub const RAW: Self = Self(c::SOCK_RAW); + + /// `SOCK_RDM` + pub const RDM: Self = Self(c::SOCK_RDM); + + /// Constructs a `SocketType` from a raw integer. + #[inline] + pub const fn from_raw(raw: RawSocketType) -> Self { + Self(raw) + } + + /// Returns the raw integer for this `SocketType`. + #[inline] + pub const fn as_raw(self) -> RawSocketType { + self.0 + } +} + +/// A type for holding raw integer address families. +#[doc(hidden)] +pub type RawAddressFamily = c::sa_family_t; + +/// `AF_*` constants. +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[repr(transparent)] +pub struct AddressFamily(pub(crate) RawAddressFamily); + +#[rustfmt::skip] +#[allow(non_upper_case_globals)] +impl AddressFamily { + /// `AF_UNSPEC` + pub const UNSPEC: Self = Self(c::AF_UNSPEC as _); + /// `AF_INET` + pub const INET: Self = Self(c::AF_INET as _); + /// `AF_INET6` + pub const INET6: Self = Self(c::AF_INET6 as _); + /// `AF_NETLINK` + pub const NETLINK: Self = Self(c::AF_NETLINK as _); + /// `AF_UNIX`, aka `AF_LOCAL` + #[doc(alias = "LOCAL")] + pub const UNIX: Self = Self(c::AF_UNIX as _); + /// `AF_AX25` + pub const AX25: Self = Self(c::AF_AX25 as _); + /// `AF_IPX` + pub const IPX: Self = Self(c::AF_IPX as _); + /// `AF_APPLETALK` + pub const APPLETALK: Self = Self(c::AF_APPLETALK as _); + /// `AF_NETROM` + pub const NETROM: Self = Self(c::AF_NETROM as _); + /// `AF_BRIDGE` + pub const BRIDGE: Self = Self(c::AF_BRIDGE as _); + /// `AF_ATMPVC` + pub const ATMPVC: Self = Self(c::AF_ATMPVC as _); + /// `AF_X25` + pub const X25: Self = Self(c::AF_X25 as _); + /// `AF_ROSE` + pub const ROSE: Self = Self(c::AF_ROSE as _); + /// `AF_DECnet` + pub const DECnet: Self = Self(c::AF_DECnet as _); + /// `AF_NETBEUI` + pub const NETBEUI: Self = Self(c::AF_NETBEUI as _); + /// `AF_SECURITY` + pub const SECURITY: Self = Self(c::AF_SECURITY as _); + /// `AF_KEY` + pub const KEY: Self = Self(c::AF_KEY as _); + /// `AF_PACKET` + pub const PACKET: Self = Self(c::AF_PACKET as _); + /// `AF_ASH` + pub const ASH: Self = Self(c::AF_ASH as _); + /// `AF_ECONET` + pub const ECONET: Self = Self(c::AF_ECONET as _); + /// `AF_ATMSVC` + pub const ATMSVC: Self = Self(c::AF_ATMSVC as _); + /// `AF_RDS` + pub const RDS: Self = Self(c::AF_RDS as _); + /// `AF_SNA` + pub const SNA: Self = Self(c::AF_SNA as _); + /// `AF_IRDA` + pub const IRDA: Self = Self(c::AF_IRDA as _); + /// `AF_PPPOX` + pub const PPPOX: Self = Self(c::AF_PPPOX as _); + /// `AF_WANPIPE` + pub const WANPIPE: Self = Self(c::AF_WANPIPE as _); + /// `AF_LLC` + pub const LLC: Self = Self(c::AF_LLC as _); + /// `AF_CAN` + pub const CAN: Self = Self(c::AF_CAN as _); + /// `AF_TIPC` + pub const TIPC: Self = Self(c::AF_TIPC as _); + /// `AF_BLUETOOTH` + pub const BLUETOOTH: Self = Self(c::AF_BLUETOOTH as _); + /// `AF_IUCV` + pub const IUCV: Self = Self(c::AF_IUCV as _); + /// `AF_RXRPC` + pub const RXRPC: Self = Self(c::AF_RXRPC as _); + /// `AF_ISDN` + pub const ISDN: Self = Self(c::AF_ISDN as _); + /// `AF_PHONET` + pub const PHONET: Self = Self(c::AF_PHONET as _); + /// `AF_IEEE802154` + pub const IEEE802154: Self = Self(c::AF_IEEE802154 as _); + + /// Constructs a `AddressFamily` from a raw integer. + #[inline] + pub const fn from_raw(raw: RawAddressFamily) -> Self { + Self(raw) + } + + /// Returns the raw integer for this `AddressFamily`. + #[inline] + pub const fn as_raw(self) -> RawAddressFamily { + self.0 + } +} + +/// A type for holding raw integer protocols. +#[doc(hidden)] +pub type RawProtocol = u32; + +/// `IPPROTO_*` constants for use with [`socket`] and [`socket_with`]. +/// +/// [`socket`]: crate::net::socket +/// [`socket_with`]: crate::net::socket_with +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[repr(transparent)] +pub struct Protocol(pub(crate) RawProtocol); + +#[rustfmt::skip] +impl Protocol { + /// `IPPROTO_IP` + pub const IP: Self = Self(c::IPPROTO_IP as _); + /// `IPPROTO_ICMP` + pub const ICMP: Self = Self(c::IPPROTO_ICMP as _); + /// `IPPROTO_IGMP` + pub const IGMP: Self = Self(c::IPPROTO_IGMP as _); + /// `IPPROTO_IPIP` + pub const IPIP: Self = Self(c::IPPROTO_IPIP as _); + /// `IPPROTO_TCP` + pub const TCP: Self = Self(c::IPPROTO_TCP as _); + /// `IPPROTO_EGP` + pub const EGP: Self = Self(c::IPPROTO_EGP as _); + /// `IPPROTO_PUP` + pub const PUP: Self = Self(c::IPPROTO_PUP as _); + /// `IPPROTO_UDP` + pub const UDP: Self = Self(c::IPPROTO_UDP as _); + /// `IPPROTO_IDP` + pub const IDP: Self = Self(c::IPPROTO_IDP as _); + /// `IPPROTO_TP` + pub const TP: Self = Self(c::IPPROTO_TP as _); + /// `IPPROTO_DCCP` + pub const DCCP: Self = Self(c::IPPROTO_DCCP as _); + /// `IPPROTO_IPV6` + pub const IPV6: Self = Self(c::IPPROTO_IPV6 as _); + /// `IPPROTO_RSVP` + pub const RSVP: Self = Self(c::IPPROTO_RSVP as _); + /// `IPPROTO_GRE` + pub const GRE: Self = Self(c::IPPROTO_GRE as _); + /// `IPPROTO_ESP` + pub const ESP: Self = Self(c::IPPROTO_ESP as _); + /// `IPPROTO_AH` + pub const AH: Self = Self(c::IPPROTO_AH as _); + /// `IPPROTO_MTP` + pub const MTP: Self = Self(c::IPPROTO_MTP as _); + /// `IPPROTO_BEETPH` + pub const BEETPH: Self = Self(c::IPPROTO_BEETPH as _); + /// `IPPROTO_ENCAP` + pub const ENCAP: Self = Self(c::IPPROTO_ENCAP as _); + /// `IPPROTO_PIM` + pub const PIM: Self = Self(c::IPPROTO_PIM as _); + /// `IPPROTO_COMP` + pub const COMP: Self = Self(c::IPPROTO_COMP as _); + /// `IPPROTO_SCTP` + pub const SCTP: Self = Self(c::IPPROTO_SCTP as _); + /// `IPPROTO_UDPLITE` + pub const UDPLITE: Self = Self(c::IPPROTO_UDPLITE as _); + /// `IPPROTO_MPLS` + pub const MPLS: Self = Self(c::IPPROTO_MPLS as _); + /// `IPPROTO_ETHERNET` + pub const ETHERNET: Self = Self(c::IPPROTO_ETHERNET as _); + /// `IPPROTO_RAW` + pub const RAW: Self = Self(c::IPPROTO_RAW as _); + /// `IPPROTO_MPTCP` + pub const MPTCP: Self = Self(c::IPPROTO_MPTCP as _); + /// `IPPROTO_FRAGMENT` + pub const FRAGMENT: Self = Self(c::IPPROTO_FRAGMENT as _); + /// `IPPROTO_ICMPV6` + pub const ICMPV6: Self = Self(c::IPPROTO_ICMPV6 as _); + /// `IPPROTO_MH` + pub const MH: Self = Self(c::IPPROTO_MH as _); + /// `IPPROTO_ROUTING` + pub const ROUTING: Self = Self(c::IPPROTO_ROUTING as _); + + /// Constructs a `Protocol` from a raw integer. + #[inline] + pub const fn from_raw(raw: RawProtocol) -> Self { + Self(raw) + } + + /// Returns the raw integer for this `Protocol`. + #[inline] + pub const fn as_raw(self) -> RawProtocol { + self.0 + } +} + +/// `SHUT_*` constants for use with [`shutdown`]. +/// +/// [`shutdown`]: crate::net::shutdown +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[repr(u32)] +pub enum Shutdown { + /// `SHUT_RD`—Disable further read operations. + Read = c::SHUT_RD, + /// `SHUT_WR`—Disable further write operations. + Write = c::SHUT_WR, + /// `SHUT_RDWR`—Disable further read and write operations. + ReadWrite = c::SHUT_RDWR, +} + +bitflags! { + /// `SOCK_*` constants for use with [`socket_with`], [`accept_with`] and + /// [`acceptfrom_with`]. + /// + /// [`socket_with`]: crate::net::socket_with + /// [`accept_with`]: crate::net::accept_with + /// [`acceptfrom_with`]: crate::net::acceptfrom_with + pub struct SocketFlags: c::c_uint { + /// `SOCK_NONBLOCK` + const NONBLOCK = c::O_NONBLOCK; + + /// `SOCK_CLOEXEC` + const CLOEXEC = c::O_CLOEXEC; + } +} + +/// Timeout identifier for use with [`set_socket_timeout`] and +/// [`get_socket_timeout`]. +/// +/// [`set_socket_timeout`]: crate::net::sockopt::set_socket_timeout. +/// [`get_socket_timeout`]: crate::net::sockopt::get_socket_timeout. +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[repr(u32)] +pub enum Timeout { + /// `SO_RCVTIMEO`—Timeout for receiving. + Recv = c::SO_RCVTIMEO_NEW, + + /// `SO_SNDTIMEO`—Timeout for sending. + Send = c::SO_SNDTIMEO_NEW, +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/net/write_sockaddr.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/net/write_sockaddr.rs new file mode 100644 index 000000000..17abd96a0 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/net/write_sockaddr.rs @@ -0,0 +1,60 @@ +//! The BSD sockets API requires us to read the `ss_family` field before +//! we can interpret the rest of a `sockaddr` produced by the kernel. +#![allow(unsafe_code)] + +use super::super::c; +use crate::net::{SocketAddrAny, SocketAddrStorage, SocketAddrUnix, SocketAddrV4, SocketAddrV6}; +use core::mem::size_of; + +pub(crate) unsafe fn write_sockaddr( + addr: &SocketAddrAny, + storage: *mut SocketAddrStorage, +) -> usize { + match addr { + SocketAddrAny::V4(v4) => write_sockaddr_v4(v4, storage), + SocketAddrAny::V6(v6) => write_sockaddr_v6(v6, storage), + SocketAddrAny::Unix(unix) => write_sockaddr_unix(unix, storage), + } +} + +pub(crate) unsafe 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], + } +} + +unsafe fn write_sockaddr_v4(v4: &SocketAddrV4, storage: *mut SocketAddrStorage) -> usize { + let encoded = encode_sockaddr_v4(v4); + core::ptr::write(storage.cast(), encoded); + size_of::<c::sockaddr_in>() +} + +pub(crate) unsafe 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::general::in6_addr__bindgen_ty_1 { + u6_addr8: v6.ip().octets(), + }, + }, + sin6_scope_id: v6.scope_id(), + } +} + +unsafe fn write_sockaddr_v6(v6: &SocketAddrV6, storage: *mut SocketAddrStorage) -> usize { + let encoded = encode_sockaddr_v6(v6); + core::ptr::write(storage.cast(), encoded); + size_of::<c::sockaddr_in6>() +} + +unsafe fn write_sockaddr_unix(unix: &SocketAddrUnix, storage: *mut SocketAddrStorage) -> usize { + core::ptr::write(storage.cast(), unix.unix); + unix.len() +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/param/auxv.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/param/auxv.rs new file mode 100644 index 000000000..c234b4f9f --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/param/auxv.rs @@ -0,0 +1,377 @@ +//! Linux auxv support. +//! +//! # Safety +//! +//! This uses raw pointers to locate and read the kernel-provided auxv array. +#![allow(unsafe_code)] + +use super::super::c; +use super::super::elf::*; +use crate::fd::OwnedFd; +#[cfg(feature = "param")] +use crate::ffi::CStr; +#[cfg(not(target_vendor = "mustang"))] +use crate::fs::{Mode, OFlags}; +use crate::utils::{as_ptr, check_raw_pointer}; +use alloc::vec::Vec; +use core::ffi::c_void; +use core::mem::size_of; +use core::ptr::{null_mut, read_unaligned, NonNull}; +#[cfg(feature = "runtime")] +use core::slice; +use core::sync::atomic::Ordering::Relaxed; +use core::sync::atomic::{AtomicPtr, AtomicUsize}; +use linux_raw_sys::general::{ + AT_BASE, AT_CLKTCK, AT_EXECFN, AT_HWCAP, AT_HWCAP2, AT_NULL, AT_PAGESZ, AT_PHDR, AT_PHENT, + AT_PHNUM, AT_SYSINFO_EHDR, +}; + +#[cfg(feature = "param")] +#[inline] +pub(crate) fn page_size() -> usize { + let mut page_size = PAGE_SIZE.load(Relaxed); + + if page_size == 0 { + init_from_proc_self_auxv(); + page_size = PAGE_SIZE.load(Relaxed); + } + + page_size +} + +#[cfg(feature = "param")] +#[inline] +pub(crate) fn clock_ticks_per_second() -> u64 { + let mut ticks = CLOCK_TICKS_PER_SECOND.load(Relaxed); + + if ticks == 0 { + init_from_proc_self_auxv(); + ticks = CLOCK_TICKS_PER_SECOND.load(Relaxed); + } + + ticks as u64 +} + +#[cfg(feature = "param")] +#[inline] +pub(crate) fn linux_hwcap() -> (usize, usize) { + let mut hwcap = HWCAP.load(Relaxed); + let mut hwcap2 = HWCAP2.load(Relaxed); + + if hwcap == 0 || hwcap2 == 0 { + init_from_proc_self_auxv(); + hwcap = HWCAP.load(Relaxed); + hwcap2 = HWCAP2.load(Relaxed); + } + + (hwcap, hwcap2) +} + +#[cfg(feature = "param")] +#[inline] +pub(crate) fn linux_execfn() -> &'static CStr { + let mut execfn = EXECFN.load(Relaxed); + + if execfn.is_null() { + init_from_proc_self_auxv(); + execfn = EXECFN.load(Relaxed); + } + + // SAFETY: We assume the `AT_EXECFN` value provided by the kernel is a + // valid pointer to a valid NUL-terminated array of bytes. + unsafe { CStr::from_ptr(execfn.cast()) } +} + +#[cfg(feature = "runtime")] +#[inline] +pub(crate) fn exe_phdrs() -> (*const c::c_void, usize) { + let mut phdr = PHDR.load(Relaxed); + let mut phnum = PHNUM.load(Relaxed); + + if phdr.is_null() || phnum == 0 { + init_from_proc_self_auxv(); + phdr = PHDR.load(Relaxed); + phnum = PHNUM.load(Relaxed); + } + + (phdr.cast(), phnum) +} + +#[cfg(feature = "runtime")] +#[inline] +pub(in super::super) fn exe_phdrs_slice() -> &'static [Elf_Phdr] { + let (phdr, phnum) = exe_phdrs(); + + // SAFETY: We assume the `AT_PHDR` and `AT_PHNUM` values provided by the + // kernel form a valid slice. + unsafe { slice::from_raw_parts(phdr.cast(), phnum) } +} + +/// `AT_SYSINFO_EHDR` isn't present on all platforms in all configurations, +/// so if we don't see it, this function returns a null pointer. +#[inline] +pub(in super::super) fn sysinfo_ehdr() -> *const Elf_Ehdr { + let mut ehdr = SYSINFO_EHDR.load(Relaxed); + + if ehdr.is_null() { + init_from_proc_self_auxv(); + ehdr = SYSINFO_EHDR.load(Relaxed); + } + + ehdr +} + +static PAGE_SIZE: AtomicUsize = AtomicUsize::new(0); +static CLOCK_TICKS_PER_SECOND: AtomicUsize = AtomicUsize::new(0); +static HWCAP: AtomicUsize = AtomicUsize::new(0); +static HWCAP2: AtomicUsize = AtomicUsize::new(0); +static SYSINFO_EHDR: AtomicPtr<Elf_Ehdr> = AtomicPtr::new(null_mut()); +static PHDR: AtomicPtr<Elf_Phdr> = AtomicPtr::new(null_mut()); +static PHNUM: AtomicUsize = AtomicUsize::new(0); +static EXECFN: AtomicPtr<c::c_char> = AtomicPtr::new(null_mut()); + +/// On non-Mustang platforms, we read the aux vector from /proc/self/auxv. +#[cfg(not(target_vendor = "mustang"))] +fn init_from_proc_self_auxv() { + // Open "/proc/self/auxv", either because we trust "/proc", or because + // we're running inside QEMU and `proc_self_auxv`'s extra checking foils + // QEMU's emulation so we need to do a plain open to get the right + // auxv records. + let file = crate::fs::openat( + crate::fs::cwd(), + "/proc/self/auxv", + OFlags::RDONLY, + Mode::empty(), + ) + .unwrap(); + + let _ = init_from_auxv_file(file); +} + +#[cfg(target_vendor = "mustang")] +fn init_from_proc_self_auxv() { + panic!("mustang should have initialized the auxv values"); +} + +/// Process auxv entries from the open file `auxv`. +fn init_from_auxv_file(auxv: OwnedFd) -> Option<()> { + let mut buffer = Vec::<u8>::with_capacity(512); + loop { + let cur = buffer.len(); + + // Request one extra byte; `Vec` will often allocate more. + buffer.reserve(1); + + // Use all the space it allocated. + buffer.resize(buffer.capacity(), 0); + + // Read up to that many bytes. + let n = match crate::io::read(&auxv, &mut buffer[cur..]) { + Err(crate::io::Errno::INTR) => 0, + Err(_err) => panic!(), + Ok(0) => break, + Ok(n) => n, + }; + + // Account for the number of bytes actually read. + buffer.resize(cur + n, 0_u8); + } + + // SAFETY: We loaded from an auxv file into the buffer. + unsafe { init_from_auxp(buffer.as_ptr().cast()) } +} + +/// Process auxv entries from the auxv array pointed to by `auxp`. +/// +/// # Safety +/// +/// This must be passed a pointer to an auxv array. +/// +/// The buffer contains `Elf_aux_t` elements, though it need not be aligned; +/// function uses `read_unaligned` to read from it. +unsafe fn init_from_auxp(mut auxp: *const Elf_auxv_t) -> Option<()> { + let mut pagesz = 0; + let mut clktck = 0; + let mut hwcap = 0; + let mut hwcap2 = 0; + let mut phdr = null_mut(); + let mut phnum = 0; + let mut execfn = null_mut(); + let mut sysinfo_ehdr = null_mut(); + let mut phent = 0; + + loop { + let Elf_auxv_t { a_type, a_val } = read_unaligned(auxp); + + match a_type as _ { + AT_PAGESZ => pagesz = a_val as usize, + AT_CLKTCK => clktck = a_val as usize, + AT_HWCAP => hwcap = a_val as usize, + AT_HWCAP2 => hwcap2 = a_val as usize, + AT_PHDR => phdr = check_raw_pointer::<Elf_Phdr>(a_val as *mut _)?.as_ptr(), + AT_PHNUM => phnum = a_val as usize, + AT_PHENT => phent = a_val as usize, + AT_EXECFN => execfn = check_raw_pointer::<c::c_char>(a_val as *mut _)?.as_ptr(), + AT_BASE => check_interpreter_base(a_val.cast())?, + AT_SYSINFO_EHDR => sysinfo_ehdr = check_vdso_base(a_val as *mut _)?.as_ptr(), + AT_NULL => break, + _ => (), + } + auxp = auxp.add(1); + } + + assert_eq!(phent, size_of::<Elf_Phdr>()); + + // The base and sysinfo_ehdr (if present) matches our platform. Accept + // the aux values. + PAGE_SIZE.store(pagesz, Relaxed); + CLOCK_TICKS_PER_SECOND.store(clktck, Relaxed); + HWCAP.store(hwcap, Relaxed); + HWCAP2.store(hwcap2, Relaxed); + PHDR.store(phdr, Relaxed); + PHNUM.store(phnum, Relaxed); + EXECFN.store(execfn, Relaxed); + SYSINFO_EHDR.store(sysinfo_ehdr, Relaxed); + + Some(()) +} + +/// Check that `base` is a valid pointer to the program interpreter. +/// +/// `base` is some value we got from a `AT_BASE` aux record somewhere, +/// which hopefully holds the value of the program interpreter in memory. Do a +/// series of checks to be as sure as we can that it's safe to use. +unsafe fn check_interpreter_base(base: *const Elf_Ehdr) -> Option<()> { + check_elf_base(base)?; + Some(()) +} + +/// Check that `base` is a valid pointer to the kernel-provided vDSO. +/// +/// `base` is some value we got from a `AT_SYSINFO_EHDR` aux record somewhere, +/// which hopefully holds the value of the kernel-provided vDSO in memory. Do a +/// series of checks to be as sure as we can that it's safe to use. +unsafe fn check_vdso_base(base: *const Elf_Ehdr) -> Option<NonNull<Elf_Ehdr>> { + // In theory, we could check that we're not attempting to parse our own ELF + // image, as an additional check. However, older Linux toolchains don't + // support this, and Rust's `#[linkage = "extern_weak"]` isn't stable yet, + // so just disable this for now. + /* + { + extern "C" { + static __ehdr_start: c::c_void; + } + + let ehdr_start: *const c::c_void = &__ehdr_start; + if base == ehdr_start { + return None; + } + } + */ + + let hdr = check_elf_base(base)?; + + // Check that the ELF is not writable, since that would indicate that this + // isn't the ELF we think it is. Here we're just using `clock_getres` just + // as an arbitrary system call which writes to a buffer and fails with + // `EFAULT` if the buffer is not writable. + { + use super::super::conv::{c_uint, ret}; + if ret(syscall!( + __NR_clock_getres, + c_uint(linux_raw_sys::general::CLOCK_MONOTONIC), + base + )) != Err(crate::io::Errno::FAULT) + { + // We can't gracefully fail here because we would seem to have just + // mutated some unknown memory. + #[cfg(feature = "std")] + { + std::process::abort(); + } + #[cfg(all(not(feature = "std"), feature = "rustc-dep-of-std"))] + { + core::intrinsics::abort(); + } + } + } + + Some(hdr) +} + +/// Check that `base` is a valid pointer to an ELF image. +unsafe fn check_elf_base(base: *const Elf_Ehdr) -> Option<NonNull<Elf_Ehdr>> { + // If we're reading a 64-bit auxv on a 32-bit platform, we'll see + // a zero `a_val` because `AT_*` values are never greater than + // `u32::MAX`. Zero is used by libc's `getauxval` to indicate + // errors, so it should never be a valid value. + if base.is_null() { + return None; + } + + let hdr = match check_raw_pointer::<Elf_Ehdr>(base as *mut _) { + Some(hdr) => hdr, + None => return None, + }; + + let hdr = hdr.as_ref(); + if hdr.e_ident[..SELFMAG] != ELFMAG { + return None; // Wrong ELF magic + } + if !matches!(hdr.e_ident[EI_OSABI], ELFOSABI_SYSV | ELFOSABI_LINUX) { + return None; // Unrecognized ELF OS ABI + } + if hdr.e_ident[EI_ABIVERSION] != ELFABIVERSION { + return None; // Unrecognized ELF ABI version + } + if hdr.e_type != ET_DYN { + return None; // Wrong ELF type + } + + // If ELF is extended, we'll need to adjust. + if hdr.e_ident[EI_VERSION] != EV_CURRENT + || hdr.e_ehsize as usize != size_of::<Elf_Ehdr>() + || hdr.e_phentsize as usize != size_of::<Elf_Phdr>() + { + return None; + } + // We don't currently support extra-large numbers of segments. + if hdr.e_phnum == PN_XNUM { + return None; + } + + // If `e_phoff` is zero, it's more likely that we're looking at memory that + // has been zeroed than that the kernel has somehow aliased the `Ehdr` and + // the `Phdr`. + if hdr.e_phoff < size_of::<Elf_Ehdr>() { + return None; + } + + // Verify that the `EI_CLASS`/`EI_DATA`/`e_machine` fields match the + // architecture we're running as. This helps catch cases where we're + // running under QEMU. + if hdr.e_ident[EI_CLASS] != ELFCLASS { + return None; // Wrong ELF class + } + if hdr.e_ident[EI_DATA] != ELFDATA { + return None; // Wrong ELF data + } + if hdr.e_machine != EM_CURRENT { + return None; // Wrong machine type + } + + Some(NonNull::new_unchecked(as_ptr(hdr) as *mut _)) +} + +// ELF ABI + +#[repr(C)] +#[derive(Copy, Clone)] +struct Elf_auxv_t { + a_type: usize, + + // Some of the values in the auxv array are pointers, so we make `a_val` a + // pointer, in order to preserve their provenance. For the values which are + // integers, we cast this to `usize`. + a_val: *const c_void, +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/param/libc_auxv.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/param/libc_auxv.rs new file mode 100644 index 000000000..b8f2c06c8 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/param/libc_auxv.rs @@ -0,0 +1,84 @@ +//! Linux auxv support, using libc. +//! +//! # Safety +//! +//! This uses raw pointers to locate and read the kernel-provided auxv array. +#![allow(unsafe_code)] + +use super::super::elf::*; +#[cfg(feature = "param")] +use crate::ffi::CStr; +use core::ptr::null; +#[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 { + unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize } +} + +#[cfg(feature = "param")] +#[inline] +pub(crate) fn clock_ticks_per_second() -> u64 { + unsafe { libc::sysconf(libc::_SC_CLK_TCK) as u64 } +} + +#[cfg(feature = "param")] +#[inline] +pub(crate) fn linux_hwcap() -> (usize, 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 { + 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 libc::c_void, usize) { + unsafe { + ( + libc::getauxval(libc::AT_PHDR) as *const libc::c_void, + libc::getauxval(libc::AT_PHNUM) as usize, + ) + } +} + +#[cfg(feature = "runtime")] +#[inline] +pub(in super::super) fn exe_phdrs_slice() -> &'static [Elf_Phdr] { + let (phdr, phnum) = exe_phdrs(); + + // SAFETY: We assume the `AT_PHDR` and `AT_PHNUM` values provided by the + // kernel form a valid slice. + unsafe { slice::from_raw_parts(phdr.cast(), phnum) } +} + +/// `AT_SYSINFO_EHDR` isn't present on all platforms in all configurations, +/// so if we don't see it, this function returns a null pointer. +#[inline] +pub(in super::super) fn sysinfo_ehdr() -> *const Elf_Ehdr { + if let Some(libc_getauxval) = getauxval.get() { + unsafe { libc_getauxval(linux_raw_sys::general::AT_SYSINFO_EHDR.into()) as *const Elf_Ehdr } + } else { + null() + } +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/param/mod.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/param/mod.rs new file mode 100644 index 000000000..956282074 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/param/mod.rs @@ -0,0 +1,12 @@ +// On Mustang, origin is in control of program startup and can access the +// incoming aux values on the stack. +// +// With "use-libc-auxv" enabled, use libc's `getauxval`. +// +// Otherwise, we read aux values from /proc/self/auxv. +#[cfg_attr(target_vendor = "mustang", path = "mustang_auxv.rs")] +#[cfg_attr( + all(not(target_vendor = "mustang"), feature = "use-libc-auxv"), + path = "libc_auxv.rs" +)] +pub(crate) mod auxv; diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/param/mustang_auxv.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/param/mustang_auxv.rs new file mode 100644 index 000000000..49cb1457c --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/param/mustang_auxv.rs @@ -0,0 +1,159 @@ +//! Linux auxv support, for Mustang. +//! +//! # Safety +//! +//! This uses raw pointers to locate and read the kernel-provided auxv array. +#![allow(unsafe_code)] + +use super::super::c; +use super::super::elf::*; +#[cfg(feature = "param")] +use crate::ffi::CStr; +use core::ffi::c_void; +use core::mem::size_of; +use core::ptr::{null, read}; +#[cfg(feature = "runtime")] +use core::slice; +use linux_raw_sys::general::{ + AT_CLKTCK, AT_EXECFN, AT_HWCAP, AT_HWCAP2, AT_NULL, AT_PAGESZ, AT_PHDR, AT_PHENT, AT_PHNUM, + AT_SYSINFO_EHDR, +}; + +#[cfg(feature = "param")] +#[inline] +pub(crate) fn page_size() -> usize { + // SAFETY: This is initialized during program startup. + unsafe { PAGE_SIZE } +} + +#[cfg(feature = "param")] +#[inline] +pub(crate) fn clock_ticks_per_second() -> u64 { + // SAFETY: This is initialized during program startup. + unsafe { CLOCK_TICKS_PER_SECOND as u64 } +} + +#[cfg(feature = "param")] +#[inline] +pub(crate) fn linux_hwcap() -> (usize, usize) { + // SAFETY: This is initialized during program startup. + unsafe { (HWCAP, HWCAP2) } +} + +#[cfg(feature = "param")] +#[inline] +pub(crate) fn linux_execfn() -> &'static CStr { + // SAFETY: This is initialized during program startup. And we + // assume it's a valid pointer to a NUL-terminated string. + unsafe { CStr::from_ptr(EXECFN.0.cast()) } +} + +#[cfg(feature = "runtime")] +#[inline] +pub(crate) fn exe_phdrs() -> (*const c_void, usize) { + // SAFETY: This is initialized during program startup. + unsafe { (PHDR.0.cast(), PHNUM) } +} + +#[cfg(feature = "runtime")] +#[inline] +pub(in super::super) fn exe_phdrs_slice() -> &'static [Elf_Phdr] { + let (phdr, phnum) = exe_phdrs(); + + // SAFETY: We assume the `AT_PHDR` and `AT_PHNUM` values provided by the + // kernel form a valid slice. + unsafe { slice::from_raw_parts(phdr.cast(), phnum) } +} + +/// `AT_SYSINFO_EHDR` isn't present on all platforms in all configurations, +/// so if we don't see it, this function returns a null pointer. +#[inline] +pub(in super::super) fn sysinfo_ehdr() -> *const Elf_Ehdr { + // SAFETY: This is initialized during program startup. + unsafe { SYSINFO_EHDR.0 } +} + +/// A const pointer to `T` that implements [`Sync`]. +#[repr(transparent)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct SyncConstPtr<T>(*const T); +unsafe impl<T> Sync for SyncConstPtr<T> {} + +impl<T> SyncConstPtr<T> { + /// Creates a `SyncConstPointer` from a raw pointer. + /// + /// Behavior is undefined if `ptr` is actually not + /// safe to share across threads. + pub const unsafe fn new(ptr: *const T) -> Self { + Self(ptr) + } +} + +static mut PAGE_SIZE: usize = 0; +static mut CLOCK_TICKS_PER_SECOND: usize = 0; +static mut HWCAP: usize = 0; +static mut HWCAP2: usize = 0; +static mut SYSINFO_EHDR: SyncConstPtr<Elf_Ehdr> = unsafe { SyncConstPtr::new(null()) }; +static mut PHDR: SyncConstPtr<Elf_Phdr> = unsafe { SyncConstPtr::new(null()) }; +static mut PHNUM: usize = 0; +static mut EXECFN: SyncConstPtr<c::c_char> = unsafe { SyncConstPtr::new(null()) }; + +/// On mustang, we export a function to be called during initialization, and +/// passed a pointer to the original environment variable block set up by the +/// OS. +pub(crate) unsafe fn init(envp: *mut *mut u8) { + init_from_envp(envp); +} + +/// # Safety +/// +/// This must be passed a pointer to the environment variable buffer +/// provided by the kernel, which is followed in memory by the auxv array. +unsafe fn init_from_envp(mut envp: *mut *mut u8) { + while !(*envp).is_null() { + envp = envp.add(1); + } + init_from_auxp(envp.add(1).cast()) +} + +/// Process auxv entries from the auxv array pointed to by `auxp`. +/// +/// # Safety +/// +/// This must be passed a pointer to an auxv array. +/// +/// The buffer contains `Elf_aux_t` elements, though it need not be aligned; +/// function uses `read_unaligned` to read from it. +unsafe fn init_from_auxp(mut auxp: *const Elf_auxv_t) { + loop { + let Elf_auxv_t { a_type, a_val } = read(auxp); + + match a_type as _ { + AT_PAGESZ => PAGE_SIZE = a_val as usize, + AT_CLKTCK => CLOCK_TICKS_PER_SECOND = a_val as usize, + AT_HWCAP => HWCAP = a_val as usize, + AT_HWCAP2 => HWCAP2 = a_val as usize, + AT_PHDR => PHDR = SyncConstPtr::new(a_val.cast::<Elf_Phdr>()), + AT_PHNUM => PHNUM = a_val as usize, + AT_PHENT => assert_eq!(a_val as usize, size_of::<Elf_Phdr>()), + AT_EXECFN => EXECFN = SyncConstPtr::new(a_val.cast::<c::c_char>()), + AT_SYSINFO_EHDR => SYSINFO_EHDR = SyncConstPtr::new(a_val.cast::<Elf_Ehdr>()), + AT_NULL => break, + _ => (), + } + auxp = auxp.add(1); + } +} + +// ELF ABI + +#[repr(C)] +#[derive(Copy, Clone)] +struct Elf_auxv_t { + a_type: usize, + + // Some of the values in the auxv array are pointers, so we make `a_val` a + // pointer, in order to preserve their provenance. For the values which are + // integers, we cast this to `usize`. + a_val: *const c_void, +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/process/cpu_set.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/process/cpu_set.rs new file mode 100644 index 000000000..fc81859d8 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/process/cpu_set.rs @@ -0,0 +1,49 @@ +//! Rust implementation of the `CPU_*` macro API. + +#![allow(non_snake_case)] + +use super::types::RawCpuSet; +use core::mem::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) { + // TODO: With, Rust 1.50, use `cpuset.bits.fill(0)` instead. + for element in &mut cpuset.bits { + *element = 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(core::mem::size_of::<RawCpuSet>(), cpuset) +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/process/mod.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/process/mod.rs new file mode 100644 index 000000000..9b2c25f91 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/process/mod.rs @@ -0,0 +1,4 @@ +pub(crate) mod cpu_set; +pub(crate) mod syscalls; +pub(crate) mod types; +pub(crate) mod wait; diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/process/syscalls.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/process/syscalls.rs new file mode 100644 index 000000000..97215e369 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/process/syscalls.rs @@ -0,0 +1,760 @@ +//! linux_raw syscalls supporting `rustix::process`. +//! +//! # Safety +//! +//! See the `rustix::backend` module documentation for details. +#![allow(unsafe_code)] +#![allow(clippy::undocumented_unsafe_blocks)] + +use super::super::c; +use super::super::conv::{ + by_mut, by_ref, c_int, c_uint, negative_pid, pass_usize, ret, ret_c_int, ret_c_uint, + ret_infallible, ret_usize, ret_usize_infallible, size_of, slice, slice_just_addr, + slice_just_addr_mut, slice_mut, zero, +}; +use super::types::{RawCpuSet, RawUname}; +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, PidfdFlags, RawNonZeroPid, RawPid, + Resource, Rlimit, Signal, Sysinfo, Uid, WaitId, WaitOptions, WaitStatus, WaitidOptions, + WaitidStatus, +}; +use crate::utils::as_mut_ptr; +use core::convert::TryInto; +use core::mem::MaybeUninit; +use core::num::NonZeroU32; +use core::ptr::{null, null_mut}; +use linux_raw_sys::general::{ + __kernel_gid_t, __kernel_pid_t, __kernel_uid_t, membarrier_cmd, membarrier_cmd_flag, rlimit, + rlimit64, PRIO_PGRP, PRIO_PROCESS, PRIO_USER, RLIM64_INFINITY, RLIM_INFINITY, +}; +use linux_raw_sys::ioctl::TIOCSCTTY; +#[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<()> { + unsafe { ret(syscall_readonly!(__NR_chdir, filename)) } +} + +#[inline] +pub(crate) fn fchdir(fd: BorrowedFd<'_>) -> io::Result<()> { + unsafe { ret(syscall_readonly!(__NR_fchdir, fd)) } +} + +#[inline] +pub(crate) fn chroot(filename: &CStr) -> io::Result<()> { + unsafe { ret(syscall_readonly!(__NR_chroot, filename)) } +} + +#[inline] +pub(crate) fn getcwd(buf: &mut [u8]) -> io::Result<usize> { + let (buf_addr_mut, buf_len) = slice_mut(buf); + unsafe { ret_usize(syscall!(__NR_getcwd, buf_addr_mut, buf_len)) } +} + +#[inline] +pub(crate) fn membarrier_query() -> MembarrierQuery { + unsafe { + match ret_c_uint(syscall!( + __NR_membarrier, + c_int(membarrier_cmd::MEMBARRIER_CMD_QUERY as _), + c_uint(0) + )) { + Ok(query) => { + // SAFETY: The safety of `from_bits_unchecked` is discussed + // [here]. Our "source of truth" is Linux, and here, the + // `query` value is coming from Linux, so we know it only + // contains "source of truth" valid bits. + // + // [here]: https://github.com/bitflags/bitflags/pull/207#issuecomment-671668662 + MembarrierQuery::from_bits_unchecked(query) + } + Err(_) => MembarrierQuery::empty(), + } + } +} + +#[inline] +pub(crate) fn membarrier(cmd: MembarrierCommand) -> io::Result<()> { + unsafe { ret(syscall!(__NR_membarrier, cmd, c_uint(0))) } +} + +#[inline] +pub(crate) fn membarrier_cpu(cmd: MembarrierCommand, cpu: Cpuid) -> io::Result<()> { + unsafe { + ret(syscall!( + __NR_membarrier, + cmd, + c_uint(membarrier_cmd_flag::MEMBARRIER_CMD_FLAG_CPU as _), + cpu + )) + } +} + +#[inline] +pub(crate) fn getpid() -> Pid { + unsafe { + let pid: i32 = ret_usize_infallible(syscall_readonly!(__NR_getpid)) as __kernel_pid_t; + debug_assert!(pid > 0); + Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked(pid as u32)) + } +} + +#[inline] +pub(crate) fn getppid() -> Option<Pid> { + unsafe { + let ppid: i32 = ret_usize_infallible(syscall_readonly!(__NR_getppid)) as __kernel_pid_t; + Pid::from_raw(ppid as u32) + } +} + +#[inline] +pub(crate) fn getpgid(pid: Option<Pid>) -> io::Result<Pid> { + unsafe { + let pgid: i32 = + ret_usize(syscall_readonly!(__NR_getpgid, c_uint(Pid::as_raw(pid))))? as __kernel_pid_t; + Ok(Pid::from_raw_nonzero(NonZeroU32::new_unchecked( + pgid as u32, + ))) + } +} + +#[inline] +pub(crate) fn setpgid(pid: Option<Pid>, pgid: Option<Pid>) -> io::Result<()> { + unsafe { + ret(syscall_readonly!( + __NR_setpgid, + c_uint(Pid::as_raw(pid)), + c_uint(Pid::as_raw(pgid)) + )) + } +} + +#[inline] +pub(crate) fn getpgrp() -> Pid { + // Use the `getpgrp` syscall if available. + #[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))] + unsafe { + let pgid: i32 = ret_usize_infallible(syscall_readonly!(__NR_getpgrp)) as __kernel_pid_t; + debug_assert!(pgid > 0); + Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked(pgid as u32)) + } + + // Otherwise use `getpgrp` and pass it zero. + #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + unsafe { + let pgid: i32 = + ret_usize_infallible(syscall_readonly!(__NR_getpgid, c_uint(0))) as __kernel_pid_t; + debug_assert!(pgid > 0); + Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked(pgid as u32)) + } +} + +#[inline] +pub(crate) fn getgid() -> Gid { + #[cfg(any(target_arch = "x86", target_arch = "sparc", target_arch = "arm"))] + unsafe { + let gid: i32 = + (ret_usize_infallible(syscall_readonly!(__NR_getgid32)) as __kernel_gid_t).into(); + Gid::from_raw(gid as u32) + } + #[cfg(not(any(target_arch = "x86", target_arch = "sparc", target_arch = "arm")))] + unsafe { + let gid = ret_usize_infallible(syscall_readonly!(__NR_getgid)) as __kernel_gid_t; + Gid::from_raw(gid as u32) + } +} + +#[inline] +pub(crate) fn getegid() -> Gid { + #[cfg(any(target_arch = "x86", target_arch = "sparc", target_arch = "arm"))] + unsafe { + let gid: i32 = + (ret_usize_infallible(syscall_readonly!(__NR_getegid32)) as __kernel_gid_t).into(); + Gid::from_raw(gid as u32) + } + #[cfg(not(any(target_arch = "x86", target_arch = "sparc", target_arch = "arm")))] + unsafe { + let gid = ret_usize_infallible(syscall_readonly!(__NR_getegid)) as __kernel_gid_t; + Gid::from_raw(gid as u32) + } +} + +#[inline] +pub(crate) fn getuid() -> Uid { + #[cfg(any(target_arch = "x86", target_arch = "sparc", target_arch = "arm"))] + unsafe { + let uid = (ret_usize_infallible(syscall_readonly!(__NR_getuid32)) as __kernel_uid_t).into(); + Uid::from_raw(uid) + } + #[cfg(not(any(target_arch = "x86", target_arch = "sparc", target_arch = "arm")))] + unsafe { + let uid = ret_usize_infallible(syscall_readonly!(__NR_getuid)) as __kernel_uid_t; + Uid::from_raw(uid as u32) + } +} + +#[inline] +pub(crate) fn geteuid() -> Uid { + #[cfg(any(target_arch = "x86", target_arch = "sparc", target_arch = "arm"))] + unsafe { + let uid: i32 = + (ret_usize_infallible(syscall_readonly!(__NR_geteuid32)) as __kernel_uid_t).into(); + Uid::from_raw(uid as u32) + } + #[cfg(not(any(target_arch = "x86", target_arch = "sparc", target_arch = "arm")))] + unsafe { + let uid = ret_usize_infallible(syscall_readonly!(__NR_geteuid)) as __kernel_uid_t; + Uid::from_raw(uid as u32) + } +} + +#[inline] +pub(crate) fn sched_getaffinity(pid: Option<Pid>, cpuset: &mut RawCpuSet) -> io::Result<()> { + unsafe { + // The raw linux syscall returns the size (in bytes) of the `cpumask_t` + // data type that is used internally by the kernel to represent the CPU + // set bit mask. + let size = ret_usize(syscall!( + __NR_sched_getaffinity, + c_uint(Pid::as_raw(pid)), + size_of::<RawCpuSet, _>(), + by_mut(&mut cpuset.bits) + ))?; + let bytes = 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_uint(Pid::as_raw(pid)), + size_of::<RawCpuSet, _>(), + slice_just_addr(&cpuset.bits) + )) + } +} + +#[inline] +pub(crate) fn sched_yield() { + unsafe { + // See the documentation for [`crate::process::sched_yield`] for why + // errors are ignored. + syscall_readonly!(__NR_sched_yield).decode_void(); + } +} + +#[inline] +pub(crate) fn uname() -> RawUname { + let mut uname = MaybeUninit::<RawUname>::uninit(); + unsafe { + ret_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<i32> { + let priority = if inc > -40 && inc < 40 { + inc + getpriority_process(None)? + } else { + inc + } + // TODO: With Rust 1.50, use `.clamp` instead of `.min` and `.max`. + //.clamp(-20, 19); + .min(19) + .max(-20); + setpriority_process(None, priority)?; + Ok(priority) +} + +#[inline] +pub(crate) fn getpriority_user(uid: Uid) -> io::Result<i32> { + unsafe { + Ok(20 + - ret_c_int(syscall_readonly!( + __NR_getpriority, + c_uint(PRIO_USER), + c_uint(uid.as_raw()) + ))?) + } +} + +#[inline] +pub(crate) fn getpriority_pgrp(pgid: Option<Pid>) -> io::Result<i32> { + unsafe { + Ok(20 + - ret_c_int(syscall_readonly!( + __NR_getpriority, + c_uint(PRIO_PGRP), + c_uint(Pid::as_raw(pgid)) + ))?) + } +} + +#[inline] +pub(crate) fn getpriority_process(pid: Option<Pid>) -> io::Result<i32> { + unsafe { + Ok(20 + - ret_c_int(syscall_readonly!( + __NR_getpriority, + c_uint(PRIO_PROCESS), + c_uint(Pid::as_raw(pid)) + ))?) + } +} + +#[inline] +pub(crate) fn setpriority_user(uid: Uid, priority: i32) -> io::Result<()> { + unsafe { + ret(syscall_readonly!( + __NR_setpriority, + c_uint(PRIO_USER), + c_uint(uid.as_raw()), + c_int(priority) + )) + } +} + +#[inline] +pub(crate) fn setpriority_pgrp(pgid: Option<Pid>, priority: i32) -> io::Result<()> { + unsafe { + ret(syscall_readonly!( + __NR_setpriority, + c_uint(PRIO_PGRP), + c_uint(Pid::as_raw(pgid)), + c_int(priority) + )) + } +} + +#[inline] +pub(crate) fn setpriority_process(pid: Option<Pid>, priority: i32) -> io::Result<()> { + unsafe { + ret(syscall_readonly!( + __NR_setpriority, + c_uint(PRIO_PROCESS), + c_uint(Pid::as_raw(pid)), + c_int(priority) + )) + } +} + +#[inline] +pub(crate) fn getrlimit(limit: Resource) -> Rlimit { + let mut result = MaybeUninit::<rlimit64>::uninit(); + unsafe { + match ret(syscall!( + __NR_prlimit64, + c_uint(0), + limit, + null::<c::c_void>(), + &mut result + )) { + Ok(()) => rlimit_from_linux(result.assume_init()), + Err(err) => { + debug_assert_eq!(err, io::Errno::NOSYS); + getrlimit_old(limit) + } + } + } +} + +/// The old 32-bit-only `getrlimit` syscall, for when we lack the new +/// `prlimit64`. +unsafe fn getrlimit_old(limit: Resource) -> Rlimit { + let mut result = MaybeUninit::<rlimit>::uninit(); + + // On these platforms, `__NR_getrlimit` is called `__NR_ugetrlimit`. + #[cfg(any( + target_arch = "arm", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "x86", + ))] + { + ret_infallible(syscall!(__NR_ugetrlimit, limit, &mut result)); + } + + // On these platforms, it's just `__NR_getrlimit`. + #[cfg(not(any( + target_arch = "arm", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "x86", + )))] + { + ret_infallible(syscall!(__NR_getrlimit, limit, &mut result)); + } + + rlimit_from_linux_old(result.assume_init()) +} + +#[inline] +pub(crate) fn setrlimit(limit: Resource, new: Rlimit) -> io::Result<()> { + unsafe { + let lim = rlimit_to_linux(new.clone()); + match ret(syscall_readonly!( + __NR_prlimit64, + c_uint(0), + limit, + by_ref(&lim), + null_mut::<c::c_void>() + )) { + Ok(()) => Ok(()), + Err(io::Errno::NOSYS) => setrlimit_old(limit, new), + Err(err) => Err(err), + } + } +} + +/// The old 32-bit-only `setrlimit` syscall, for when we lack the new +/// `prlimit64`. +unsafe fn setrlimit_old(limit: Resource, new: Rlimit) -> io::Result<()> { + let lim = rlimit_to_linux_old(new)?; + ret(syscall_readonly!(__NR_setrlimit, limit, by_ref(&lim))) +} + +#[inline] +pub(crate) fn prlimit(pid: Option<Pid>, limit: Resource, new: Rlimit) -> io::Result<Rlimit> { + let lim = rlimit_to_linux(new); + let mut result = MaybeUninit::<rlimit64>::uninit(); + unsafe { + match ret(syscall!( + __NR_prlimit64, + c_uint(Pid::as_raw(pid)), + limit, + by_ref(&lim), + &mut result + )) { + Ok(()) => Ok(rlimit_from_linux(result.assume_init())), + Err(err) => Err(err), + } + } +} + +/// Convert a Rust [`Rlimit`] to a C `rlimit64`. +#[inline] +fn rlimit_from_linux(lim: rlimit64) -> Rlimit { + let current = if lim.rlim_cur == RLIM64_INFINITY as _ { + None + } else { + Some(lim.rlim_cur) + }; + let maximum = if lim.rlim_max == RLIM64_INFINITY as _ { + None + } else { + Some(lim.rlim_max) + }; + Rlimit { current, maximum } +} + +/// Convert a C `rlimit64` to a Rust `Rlimit`. +#[inline] +fn rlimit_to_linux(lim: Rlimit) -> rlimit64 { + let rlim_cur = match lim.current { + Some(r) => r, + None => RLIM64_INFINITY as _, + }; + let rlim_max = match lim.maximum { + Some(r) => r, + None => RLIM64_INFINITY as _, + }; + rlimit64 { rlim_cur, rlim_max } +} + +/// Like `rlimit_from_linux` but uses Linux's old 32-bit `rlimit`. +#[allow(clippy::useless_conversion)] +fn rlimit_from_linux_old(lim: rlimit) -> Rlimit { + let current = if lim.rlim_cur == RLIM_INFINITY as _ { + None + } else { + Some(lim.rlim_cur.into()) + }; + let maximum = if lim.rlim_max == RLIM_INFINITY as _ { + None + } else { + Some(lim.rlim_max.into()) + }; + Rlimit { current, maximum } +} + +/// Like `rlimit_to_linux` but uses Linux's old 32-bit `rlimit`. +#[allow(clippy::useless_conversion)] +fn rlimit_to_linux_old(lim: Rlimit) -> io::Result<rlimit> { + let rlim_cur = match lim.current { + Some(r) => r.try_into().map_err(|_e| io::Errno::INVAL)?, + None => RLIM_INFINITY as _, + }; + let rlim_max = match lim.maximum { + Some(r) => r.try_into().map_err(|_e| io::Errno::INVAL)?, + None => RLIM_INFINITY as _, + }; + Ok(rlimit { rlim_cur, rlim_max }) +} + +#[inline] +pub(crate) fn wait(waitopts: WaitOptions) -> io::Result<Option<(Pid, WaitStatus)>> { + _waitpid(!0, waitopts) +} + +#[inline] +pub(crate) fn waitpid( + pid: Option<Pid>, + waitopts: WaitOptions, +) -> io::Result<Option<(Pid, WaitStatus)>> { + _waitpid(Pid::as_raw(pid), waitopts) +} + +#[inline] +pub(crate) fn _waitpid( + pid: RawPid, + waitopts: WaitOptions, +) -> io::Result<Option<(Pid, WaitStatus)>> { + unsafe { + let mut status = MaybeUninit::<u32>::uninit(); + let pid = ret_c_uint(syscall!( + __NR_wait4, + c_int(pid as _), + &mut status, + c_int(waitopts.bits() as _), + zero() + ))?; + Ok(RawNonZeroPid::new(pid).map(|non_zero| { + ( + Pid::from_raw_nonzero(non_zero), + WaitStatus::new(status.assume_init()), + ) + })) + } +} + +#[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::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), + 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<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_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<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 _), + 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] +#[rustfmt::skip] +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)) + } +} + +#[cfg(feature = "runtime")] +#[inline] +pub(crate) fn exit_group(code: c::c_int) -> ! { + unsafe { syscall_noreturn!(__NR_exit_group, c_int(code)) } +} + +#[inline] +pub(crate) fn getsid(pid: Option<Pid>) -> io::Result<Pid> { + unsafe { + let pid = ret_usize(syscall_readonly!(__NR_getsid, c_uint(Pid::as_raw(pid))))?; + debug_assert!(pid > 0); + Ok(Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked( + pid as u32, + ))) + } +} + +#[inline] +pub(crate) fn setsid() -> io::Result<Pid> { + unsafe { + let pid = ret_usize(syscall_readonly!(__NR_setsid))?; + debug_assert!(pid > 0); + Ok(Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked( + pid as u32, + ))) + } +} + +#[inline] +pub(crate) fn kill_process(pid: Pid, sig: Signal) -> io::Result<()> { + unsafe { ret(syscall_readonly!(__NR_kill, pid, sig)) } +} + +#[inline] +pub(crate) fn kill_process_group(pid: Pid, sig: Signal) -> io::Result<()> { + unsafe { ret(syscall_readonly!(__NR_kill, negative_pid(pid), sig)) } +} + +#[inline] +pub(crate) fn kill_current_process_group(sig: Signal) -> io::Result<()> { + unsafe { ret(syscall_readonly!(__NR_kill, pass_usize(0), sig)) } +} + +#[inline] +pub(crate) 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) 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)) +} + +#[inline] +pub(crate) fn pidfd_open(pid: Pid, flags: PidfdFlags) -> io::Result<OwnedFd> { + unsafe { + ret_owned_fd(syscall_readonly!( + __NR_pidfd_open, + pid, + c_int(flags.bits() as _) + )) + } +} + +#[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 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 ioctl_tiocsctty(fd: BorrowedFd<'_>) -> io::Result<()> { + unsafe { + ret(syscall_readonly!( + __NR_ioctl, + fd, + c_uint(TIOCSCTTY), + by_ref(&0_u32) + )) + } +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/process/types.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/process/types.rs new file mode 100644 index 000000000..ff85106ea --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/process/types.rs @@ -0,0 +1,259 @@ +use super::super::c; +use linux_raw_sys::general::membarrier_cmd; + +/// `sysinfo` +pub type Sysinfo = linux_raw_sys::general::sysinfo; + +/// A command for use with [`membarrier`] and [`membarrier_cpu`]. +/// +/// For `MEMBARRIER_CMD_QUERY`, see [`membarrier_query`]. +/// +/// [`membarrier`]: crate::process::membarrier +/// [`membarrier_cpu`]: crate::process::membarrier_cpu +/// [`membarrier_query`]: crate::process::membarrier_query +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +#[repr(u32)] +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 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)] +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, +} + +/// A signal number for use with [`kill_process`], [`kill_process_group`], +/// and [`kill_current_process_group`]. +/// +/// [`kill_process`]: crate::process::kill_process +/// [`kill_process_group`]: crate::process::kill_process_group +/// [`kill_current_process_group`]: crate::process::kill_current_process_group +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[repr(u32)] +pub enum Signal { + /// `SIGHUP` + Hup = linux_raw_sys::general::SIGHUP, + /// `SIGINT` + Int = linux_raw_sys::general::SIGINT, + /// `SIGQUIT` + Quit = linux_raw_sys::general::SIGQUIT, + /// `SIGILL` + Ill = linux_raw_sys::general::SIGILL, + /// `SIGTRAP` + Trap = linux_raw_sys::general::SIGTRAP, + /// `SIGABRT`, aka `SIGIOT` + #[doc(alias = "Iot")] + #[doc(alias = "Abrt")] + Abort = linux_raw_sys::general::SIGABRT, + /// `SIGEMT` + #[cfg(any( + target_arch = "mips", + target_arch = "mips64", + target_arch = "sparc", + target_arch = "sparc64" + ))] + Emt = linux_raw_sys::general::SIGEMT, + /// `SIGBUS` + Bus = linux_raw_sys::general::SIGBUS, + /// `SIGFPE` + Fpe = linux_raw_sys::general::SIGFPE, + /// `SIGKILL` + Kill = linux_raw_sys::general::SIGKILL, + /// `SIGUSR1` + Usr1 = linux_raw_sys::general::SIGUSR1, + /// `SIGSEGV` + Segv = linux_raw_sys::general::SIGSEGV, + /// `SIGUSR2` + Usr2 = linux_raw_sys::general::SIGUSR2, + /// `SIGPIPE` + Pipe = linux_raw_sys::general::SIGPIPE, + /// `SIGALRM` + #[doc(alias = "Alrm")] + Alarm = linux_raw_sys::general::SIGALRM, + /// `SIGTERM` + Term = linux_raw_sys::general::SIGTERM, + /// `SIGSTKFLT` + #[cfg(not(any(target_arch = "mips", target_arch = "mips64")))] + Stkflt = linux_raw_sys::general::SIGSTKFLT, + /// `SIGCHLD` + #[doc(alias = "Chld")] + Child = linux_raw_sys::general::SIGCHLD, + /// `SIGCONT` + Cont = linux_raw_sys::general::SIGCONT, + /// `SIGSTOP` + Stop = linux_raw_sys::general::SIGSTOP, + /// `SIGTSTP` + Tstp = linux_raw_sys::general::SIGTSTP, + /// `SIGTTIN` + Ttin = linux_raw_sys::general::SIGTTIN, + /// `SIGTTOU` + Ttou = linux_raw_sys::general::SIGTTOU, + /// `SIGURG` + Urg = linux_raw_sys::general::SIGURG, + /// `SIGXCPU` + Xcpu = linux_raw_sys::general::SIGXCPU, + /// `SIGXFSZ` + Xfsz = linux_raw_sys::general::SIGXFSZ, + /// `SIGVTALRM` + #[doc(alias = "Vtalrm")] + Vtalarm = linux_raw_sys::general::SIGVTALRM, + /// `SIGPROF` + Prof = linux_raw_sys::general::SIGPROF, + /// `SIGWINCH` + Winch = linux_raw_sys::general::SIGWINCH, + /// `SIGIO`, aka `SIGPOLL` + #[doc(alias = "Poll")] + Io = linux_raw_sys::general::SIGIO, + /// `SIGPWR` + #[doc(alias = "Pwr")] + Power = linux_raw_sys::general::SIGPWR, + /// `SIGSYS`, aka `SIGUNUSED` + #[doc(alias = "Unused")] + Sys = linux_raw_sys::general::SIGSYS, + /// `SIGRTMIN` + Rtmin = linux_raw_sys::general::SIGRTMIN, +} + +impl Signal { + /// Convert a raw signal number into a `Signal`, if possible. + pub fn from_raw(sig: i32) -> Option<Self> { + match sig as _ { + linux_raw_sys::general::SIGHUP => Some(Self::Hup), + linux_raw_sys::general::SIGINT => Some(Self::Int), + linux_raw_sys::general::SIGQUIT => Some(Self::Quit), + linux_raw_sys::general::SIGILL => Some(Self::Ill), + linux_raw_sys::general::SIGTRAP => Some(Self::Trap), + linux_raw_sys::general::SIGABRT => Some(Self::Abort), + linux_raw_sys::general::SIGBUS => Some(Self::Bus), + linux_raw_sys::general::SIGFPE => Some(Self::Fpe), + linux_raw_sys::general::SIGKILL => Some(Self::Kill), + linux_raw_sys::general::SIGUSR1 => Some(Self::Usr1), + linux_raw_sys::general::SIGSEGV => Some(Self::Segv), + linux_raw_sys::general::SIGUSR2 => Some(Self::Usr2), + linux_raw_sys::general::SIGPIPE => Some(Self::Pipe), + linux_raw_sys::general::SIGALRM => Some(Self::Alarm), + linux_raw_sys::general::SIGTERM => Some(Self::Term), + #[cfg(not(any(target_arch = "mips", target_arch = "mips64")))] + linux_raw_sys::general::SIGSTKFLT => Some(Self::Stkflt), + linux_raw_sys::general::SIGCHLD => Some(Self::Child), + linux_raw_sys::general::SIGCONT => Some(Self::Cont), + linux_raw_sys::general::SIGSTOP => Some(Self::Stop), + linux_raw_sys::general::SIGTSTP => Some(Self::Tstp), + linux_raw_sys::general::SIGTTIN => Some(Self::Ttin), + linux_raw_sys::general::SIGTTOU => Some(Self::Ttou), + linux_raw_sys::general::SIGURG => Some(Self::Urg), + linux_raw_sys::general::SIGXCPU => Some(Self::Xcpu), + linux_raw_sys::general::SIGXFSZ => Some(Self::Xfsz), + linux_raw_sys::general::SIGVTALRM => Some(Self::Vtalarm), + linux_raw_sys::general::SIGPROF => Some(Self::Prof), + linux_raw_sys::general::SIGWINCH => Some(Self::Winch), + linux_raw_sys::general::SIGIO => Some(Self::Io), + linux_raw_sys::general::SIGPWR => Some(Self::Power), + linux_raw_sys::general::SIGSYS => Some(Self::Sys), + linux_raw_sys::general::SIGRTMIN => Some(Self::Rtmin), + _ => None, + } + } +} + +/// `EXIT_SUCCESS` +pub const EXIT_SUCCESS: c::c_int = 0; +/// `EXIT_FAILURE` +pub const EXIT_FAILURE: c::c_int = 1; +/// The status value of a child terminated with a [`Signal::Abort`] signal. +pub const EXIT_SIGNALED_SIGABRT: c::c_int = 128 + linux_raw_sys::general::SIGABRT as i32; + +/// A process identifier as a raw integer. +pub type RawPid = u32; +/// A non-zero process identifier as a raw non-zero integer. +pub type RawNonZeroPid = core::num::NonZeroU32; +/// A group identifier as a raw integer. +pub type RawGid = u32; +/// A user identifier as a raw integer. +pub type RawUid = u32; +/// A CPU identifier as a raw integer. +pub type RawCpuid = u32; + +pub(crate) type RawUname = linux_raw_sys::general::new_utsname; + +#[repr(C)] +#[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-0.37.22/src/backend/linux_raw/process/wait.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/process/wait.rs new file mode 100644 index 000000000..9af7f2b5e --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/process/wait.rs @@ -0,0 +1,68 @@ +// The functions replacing the C macros use the same names as in libc. +#![allow(non_snake_case, unsafe_code)] + +use linux_raw_sys::ctypes::c_int; +pub(crate) use linux_raw_sys::general::{ + siginfo_t, WCONTINUED, WEXITED, WNOHANG, WNOWAIT, WSTOPPED, WUNTRACED, +}; + +#[inline] +pub(crate) fn WIFSTOPPED(status: u32) -> bool { + (status & 0xff) == 0x7f +} + +#[inline] +pub(crate) fn WSTOPSIG(status: u32) -> u32 { + (status >> 8) & 0xff +} + +#[inline] +pub(crate) fn WIFCONTINUED(status: u32) -> bool { + status == 0xffff +} + +#[inline] +pub(crate) fn WIFSIGNALED(status: u32) -> bool { + ((status & 0x7f) + 1) as i8 >= 2 +} + +#[inline] +pub(crate) fn WTERMSIG(status: u32) -> u32 { + status & 0x7f +} + +#[inline] +pub(crate) fn WIFEXITED(status: u32) -> bool { + (status & 0x7f) == 0 +} + +#[inline] +pub(crate) fn WEXITSTATUS(status: u32) -> u32 { + (status >> 8) & 0xff +} + +pub(crate) trait SiginfoExt { + fn si_code(&self) -> c_int; + unsafe fn si_status(&self) -> c_int; +} + +impl SiginfoExt for siginfo_t { + #[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] + #[rustfmt::skip] + unsafe fn si_status(&self) -> c_int { + self.__bindgen_anon_1.__bindgen_anon_1._sifields._sigchld._status + } +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/pty/mod.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/pty/mod.rs new file mode 100644 index 000000000..ef944f04d --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/pty/mod.rs @@ -0,0 +1 @@ +pub(crate) mod syscalls; diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/pty/syscalls.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/pty/syscalls.rs new file mode 100644 index 000000000..936c97f67 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/pty/syscalls.rs @@ -0,0 +1,60 @@ +//! linux_raw syscalls supporting `rustix::pty`. +//! +//! # Safety +//! +//! See the `rustix::backend` module documentation for details. +#![allow(unsafe_code)] +#![allow(clippy::undocumented_unsafe_blocks)] + +use super::super::c; +use super::super::conv::{by_ref, c_uint, ret, ret_owned_fd}; +use crate::fd::{BorrowedFd, OwnedFd}; +use crate::ffi::CString; +use crate::io; +use crate::path::DecInt; +use crate::pty::OpenptFlags; +#[cfg(any(apple, freebsdlike, linux_like, target_os = "fuchsia"))] +use alloc::vec::Vec; +use core::mem::MaybeUninit; +use linux_raw_sys::ioctl::{TIOCGPTN, TIOCGPTPEER, TIOCSPTLCK}; + +#[cfg(any(apple, freebsdlike, linux_like, target_os = "fuchsia"))] +#[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()); + // With Rust 1.58 we can append a '\0' ourselves and use + // `from_vec_with_nul_unchecked`. + Ok(CString::from_vec_unchecked(buffer)) + } +} + +#[inline] +pub(crate) fn unlockpt(fd: BorrowedFd) -> io::Result<()> { + unsafe { + ret(syscall_readonly!( + __NR_ioctl, + fd, + c_uint(TIOCSPTLCK), + by_ref(&0) + )) + } +} + +#[cfg(target_os = "linux")] +#[inline] +pub(crate) fn ioctl_tiocgptpeer(fd: BorrowedFd, flags: OpenptFlags) -> io::Result<OwnedFd> { + unsafe { + ret_owned_fd(syscall_readonly!( + __NR_ioctl, + fd, + c_uint(TIOCGPTPEER), + c_uint(flags.bits()) + )) + } +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/rand/mod.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/rand/mod.rs new file mode 100644 index 000000000..1e0181a99 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/rand/mod.rs @@ -0,0 +1,2 @@ +pub(crate) mod syscalls; +pub(crate) mod types; diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/rand/syscalls.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/rand/syscalls.rs new file mode 100644 index 000000000..5533f75e0 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/rand/syscalls.rs @@ -0,0 +1,17 @@ +//! linux_raw syscalls supporting `rustix::rand`. +//! +//! # Safety +//! +//! See the `rustix::backend` module documentation for details. +#![allow(unsafe_code)] +#![allow(clippy::undocumented_unsafe_blocks)] + +use super::super::conv::{ret_usize, slice_mut}; +use crate::io; +use crate::rand::GetRandomFlags; + +#[inline] +pub(crate) fn getrandom(buf: &mut [u8], flags: GetRandomFlags) -> io::Result<usize> { + let (buf_addr_mut, buf_len) = slice_mut(buf); + unsafe { ret_usize(syscall!(__NR_getrandom, buf_addr_mut, buf_len, flags)) } +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/rand/types.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/rand/types.rs new file mode 100644 index 000000000..75f17443e --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/rand/types.rs @@ -0,0 +1,15 @@ +use bitflags::bitflags; + +bitflags! { + /// `GRND_*` flags for use with [`getrandom`]. + /// + /// [`getrandom`]: crate::rand::getrandom + 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; + } +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/reg.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/reg.rs new file mode 100644 index 000000000..206031dde --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/reg.rs @@ -0,0 +1,259 @@ +//! Encapsulation for system call arguments and return values. +//! +//! The inline-asm and outline-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)] +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(target_arch = "mips")] +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(target_arch = "mips")] +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> { + 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(target_arch = "mips")] + impl Sealed for super::A6 {} + #[cfg(target_arch = "x86")] + impl Sealed for super::SocketArg {} + impl Sealed for super::R0 {} +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/runtime/mod.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/runtime/mod.rs new file mode 100644 index 000000000..0b48649ce --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/runtime/mod.rs @@ -0,0 +1,2 @@ +pub(crate) mod syscalls; +pub(crate) mod tls; diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/runtime/syscalls.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/runtime/syscalls.rs new file mode 100644 index 000000000..8f92085ef --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/runtime/syscalls.rs @@ -0,0 +1,253 @@ +//! linux_raw syscalls supporting `rustix::runtime`. +//! +//! # Safety +//! +//! See the `rustix::backend` module documentation for details. +#![allow(unsafe_code)] +#![allow(clippy::undocumented_unsafe_blocks)] + +use super::super::c; +#[cfg(target_arch = "x86")] +use super::super::conv::by_mut; +use super::super::conv::{ + by_ref, c_int, c_uint, ret, ret_c_int, ret_c_uint, ret_error, ret_usize_infallible, 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::process::{Pid, RawNonZeroPid, Signal}; +use crate::runtime::{How, Sigaction, Siginfo, Sigset, Stack, Timespec}; +use crate::utils::optional_as_ptr; +#[cfg(target_pointer_width = "32")] +use core::convert::TryInto; +use core::mem::MaybeUninit; +#[cfg(target_pointer_width = "32")] +use linux_raw_sys::general::__kernel_old_timespec; +use linux_raw_sys::general::{__kernel_pid_t, kernel_sigset_t, PR_SET_NAME, SIGCHLD}; +#[cfg(target_arch = "x86_64")] +use {super::super::conv::ret_infallible, linux_raw_sys::general::ARCH_SET_FS}; + +#[inline] +pub(crate) unsafe fn fork() -> io::Result<Option<Pid>> { + let pid = ret_c_uint(syscall_readonly!( + __NR_clone, + c_uint(SIGCHLD), + zero(), + zero(), + zero(), + zero() + ))?; + Ok(Pid::from_raw(pid)) +} + +#[cfg(feature = "fs")] +pub(crate) unsafe fn execveat( + dirfd: BorrowedFd<'_>, + path: &CStr, + args: *const *const u8, + env_vars: *const *const u8, + flags: AtFlags, +) -> io::Errno { + ret_error(syscall_readonly!( + __NR_execveat, + dirfd, + path, + args, + env_vars, + flags + )) +} + +pub(crate) unsafe fn execve( + path: &CStr, + args: *const *const u8, + env_vars: *const *const u8, +) -> io::Errno { + ret_error(syscall_readonly!(__NR_execve, path, args, env_vars)) +} + +pub(crate) mod tls { + #[cfg(target_arch = "x86")] + use super::super::tls::UserDesc; + use super::*; + + #[cfg(target_arch = "x86")] + #[inline] + pub(crate) unsafe fn set_thread_area(u_info: &mut UserDesc) -> io::Result<()> { + ret(syscall!(__NR_set_thread_area, by_mut(u_info))) + } + + #[cfg(target_arch = "arm")] + #[inline] + pub(crate) unsafe fn arm_set_tls(data: *mut c::c_void) -> io::Result<()> { + ret(syscall_readonly!(__ARM_NR_set_tls, data)) + } + + #[cfg(target_arch = "x86_64")] + #[inline] + pub(crate) unsafe fn set_fs(data: *mut c::c_void) { + ret_infallible(syscall_readonly!( + __NR_arch_prctl, + c_uint(ARCH_SET_FS), + data + )) + } + + #[inline] + pub(crate) unsafe fn set_tid_address(data: *mut c::c_void) -> Pid { + let tid: i32 = + ret_usize_infallible(syscall_readonly!(__NR_set_tid_address, data)) as __kernel_pid_t; + debug_assert_ne!(tid, 0); + Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked(tid as u32)) + } + + #[inline] + pub(crate) unsafe fn set_thread_name(name: &CStr) -> io::Result<()> { + ret(syscall_readonly!(__NR_prctl, c_uint(PR_SET_NAME), name)) + } + + #[inline] + pub(crate) fn exit_thread(code: c::c_int) -> ! { + unsafe { syscall_noreturn!(__NR_exit, c_int(code)) } + } +} + +#[inline] +pub(crate) unsafe fn sigaction(signal: Signal, new: Option<Sigaction>) -> io::Result<Sigaction> { + let mut old = MaybeUninit::<Sigaction>::uninit(); + let new = optional_as_ptr(new.as_ref()); + ret(syscall!( + __NR_rt_sigaction, + signal, + new, + &mut old, + size_of::<kernel_sigset_t, _>() + ))?; + Ok(old.assume_init()) +} + +#[inline] +pub(crate) unsafe fn sigaltstack(new: Option<Stack>) -> io::Result<Stack> { + let mut old = MaybeUninit::<Stack>::uninit(); + let new = optional_as_ptr(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 sigprocmask(how: How, new: Option<&Sigset>) -> io::Result<Sigset> { + let mut old = MaybeUninit::<Sigset>::uninit(); + let new = optional_as_ptr(new); + ret(syscall!( + __NR_rt_sigprocmask, + how, + new, + &mut old, + size_of::<kernel_sigset_t, _>() + ))?; + Ok(old.assume_init()) +} + +#[inline] +pub(crate) fn sigwait(set: &Sigset) -> io::Result<Signal> { + unsafe { + match Signal::from_raw(ret_c_int(syscall_readonly!( + __NR_rt_sigtimedwait, + by_ref(set), + zero(), + zero(), + size_of::<kernel_sigset_t, _>() + ))?) { + Some(signum) => Ok(signum), + None => Err(io::Errno::NOTSUP), + } + } +} + +#[inline] +pub(crate) fn sigwaitinfo(set: &Sigset) -> io::Result<Siginfo> { + let mut info = MaybeUninit::<Siginfo>::uninit(); + unsafe { + let _signum = ret_c_int(syscall!( + __NR_rt_sigtimedwait, + by_ref(set), + &mut info, + zero(), + size_of::<kernel_sigset_t, _>() + ))?; + Ok(info.assume_init()) + } +} + +#[inline] +pub(crate) fn sigtimedwait(set: &Sigset, timeout: Option<Timespec>) -> io::Result<Siginfo> { + let mut info = MaybeUninit::<Siginfo>::uninit(); + let timeout_ptr = optional_as_ptr(timeout.as_ref()); + + // `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")] + unsafe { + match ret_c_int(syscall!( + __NR_rt_sigtimedwait_time64, + by_ref(set), + &mut info, + timeout_ptr, + size_of::<kernel_sigset_t, _>() + )) { + Ok(_signum) => (), + Err(io::Errno::NOSYS) => sigtimedwait_old(set, timeout, &mut info)?, + Err(err) => return Err(err), + } + Ok(info.assume_init()) + } + + #[cfg(target_pointer_width = "64")] + unsafe { + let _signum = ret_c_int(syscall!( + __NR_rt_sigtimedwait, + by_ref(set), + &mut info, + timeout_ptr, + size_of::<kernel_sigset_t, _>() + ))?; + Ok(info.assume_init()) + } +} + +#[cfg(target_pointer_width = "32")] +unsafe fn sigtimedwait_old( + set: &Sigset, + timeout: Option<Timespec>, + info: &mut MaybeUninit<Siginfo>, +) -> io::Result<()> { + let old_timeout = match timeout { + Some(timeout) => Some(__kernel_old_timespec { + tv_sec: timeout.tv_sec.try_into().map_err(|_| io::Errno::OVERFLOW)?, + tv_nsec: timeout.tv_nsec as _, + }), + None => None, + }; + + let old_timeout_ptr = optional_as_ptr(old_timeout.as_ref()); + + let _signum = ret_c_int(syscall!( + __NR_rt_sigtimedwait, + by_ref(set), + info, + old_timeout_ptr, + size_of::<kernel_sigset_t, _>() + ))?; + + Ok(()) +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/runtime/tls.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/runtime/tls.rs new file mode 100644 index 000000000..160c5e592 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/runtime/tls.rs @@ -0,0 +1,63 @@ +//! 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; +use super::super::elf::*; +use super::super::param::auxv::exe_phdrs_slice; +use core::ptr::null; + +/// For use with [`set_thread_area`]. +/// +/// [`set_thread_area`]: crate::runtime::set_thread_area +#[cfg(target_arch = "x86")] +pub type UserDesc = linux_raw_sys::general::user_desc; + +pub(crate) fn startup_tls_info() -> StartupTlsInfo { + let mut base = null(); + let mut tls_phdr = null(); + let mut stack_size = 0; + + let phdrs = exe_phdrs_slice(); + + // SAFETY: We assume the phdr array pointer and length the kernel provided + // to the process describe a valid phdr array. + unsafe { + for phdr in phdrs { + match phdr.p_type { + PT_PHDR => base = phdrs.as_ptr().cast::<u8>().sub(phdr.p_vaddr), + PT_TLS => tls_phdr = phdr, + PT_GNU_STACK => stack_size = phdr.p_memsz, + _ => {} + } + } + + StartupTlsInfo { + addr: base.cast::<u8>().add((*tls_phdr).p_vaddr).cast(), + mem_size: (*tls_phdr).p_memsz, + file_size: (*tls_phdr).p_filesz, + align: (*tls_phdr).p_align, + stack_size, + } + } +} + +/// The values returned from [`startup_tls_info`]. +/// +/// [`startup_tls_info`]: crate::runtime::startup_tls_info +pub struct StartupTlsInfo { + /// The base address of the TLS segment. + pub addr: *const c::c_void, + /// The size of the memory region. + pub mem_size: usize, + /// The size beyond which all memory is zero-initialized. + pub file_size: usize, + /// The required alignment for the TLS segment. + pub align: usize, + /// The requested minimum size for stacks. + pub stack_size: usize, +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/termios/mod.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/termios/mod.rs new file mode 100644 index 000000000..1e0181a99 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/termios/mod.rs @@ -0,0 +1,2 @@ +pub(crate) mod syscalls; +pub(crate) mod types; diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/termios/syscalls.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/termios/syscalls.rs new file mode 100644 index 000000000..3c8cbb0c9 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/termios/syscalls.rs @@ -0,0 +1,302 @@ +//! linux_raw syscalls supporting `rustix::termios`. +//! +//! # Safety +//! +//! See the `rustix::backend` module documentation for details. +#![allow(unsafe_code)] +#![allow(clippy::undocumented_unsafe_blocks)] + +use super::super::conv::{by_ref, c_uint, ret}; +use crate::fd::BorrowedFd; +use crate::io; +use crate::process::{Pid, RawNonZeroPid}; +use crate::termios::{ + Action, OptionalActions, QueueSelector, Termios, Winsize, BRKINT, CBAUD, CS8, CSIZE, ECHO, + ECHONL, ICANON, ICRNL, IEXTEN, IGNBRK, IGNCR, INLCR, ISIG, ISTRIP, IXON, OPOST, PARENB, PARMRK, + VMIN, VTIME, +}; +#[cfg(feature = "procfs")] +use crate::{ffi::CStr, fs::FileType, path::DecInt}; +use core::mem::MaybeUninit; +use linux_raw_sys::general::__kernel_pid_t; +use linux_raw_sys::ioctl::{ + TCFLSH, TCGETS, TCSBRK, TCSETS, TCXONC, TIOCGPGRP, TIOCGSID, TIOCGWINSZ, TIOCSPGRP, TIOCSWINSZ, +}; + +#[inline] +pub(crate) fn tcgetwinsize(fd: BorrowedFd<'_>) -> io::Result<Winsize> { + unsafe { + let mut result = MaybeUninit::<Winsize>::uninit(); + ret(syscall!(__NR_ioctl, fd, c_uint(TIOCGWINSZ), &mut result))?; + Ok(result.assume_init()) + } +} + +#[inline] +pub(crate) fn tcgetattr(fd: BorrowedFd<'_>) -> io::Result<Termios> { + unsafe { + let mut result = MaybeUninit::<Termios>::uninit(); + ret(syscall!(__NR_ioctl, fd, c_uint(TCGETS), &mut result))?; + Ok(result.assume_init()) + } +} + +#[inline] +#[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<crate::termios::Termios2> { + unsafe { + let mut result = MaybeUninit::<crate::termios::Termios2>::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<Pid> { + unsafe { + let mut result = MaybeUninit::<__kernel_pid_t>::uninit(); + ret(syscall!(__NR_ioctl, fd, c_uint(TIOCGPGRP), &mut result))?; + let pid = result.assume_init(); + debug_assert!(pid > 0); + Ok(Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked( + pid as u32, + ))) + } +} + +#[inline] +pub(crate) fn tcsetattr( + fd: BorrowedFd, + optional_actions: OptionalActions, + termios: &Termios, +) -> io::Result<()> { + // Translate from `optional_actions` into an ioctl request code. On MIPS, + // `optional_actions` already has `TCGETS` added to it. + let request = if cfg!(any(target_arch = "mips", target_arch = "mips64")) { + optional_actions as u32 + } else { + TCSETS + optional_actions as u32 + }; + unsafe { + ret(syscall_readonly!( + __NR_ioctl, + fd, + c_uint(request as u32), + by_ref(termios) + )) + } +} + +#[inline] +#[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))) } +} + +#[inline] +pub(crate) fn tcdrain(fd: BorrowedFd) -> io::Result<()> { + unsafe { ret(syscall_readonly!(__NR_ioctl, fd, c_uint(TCSBRK), c_uint(1))) } +} + +#[inline] +pub(crate) fn tcflush(fd: BorrowedFd, queue_selector: QueueSelector) -> io::Result<()> { + unsafe { + ret(syscall_readonly!( + __NR_ioctl, + fd, + c_uint(TCFLSH), + c_uint(queue_selector as u32) + )) + } +} + +#[inline] +pub(crate) fn tcflow(fd: BorrowedFd, action: Action) -> io::Result<()> { + unsafe { + ret(syscall_readonly!( + __NR_ioctl, + fd, + c_uint(TCXONC), + c_uint(action as u32) + )) + } +} + +#[inline] +pub(crate) fn tcgetsid(fd: BorrowedFd) -> io::Result<Pid> { + unsafe { + let mut result = MaybeUninit::<__kernel_pid_t>::uninit(); + ret(syscall!(__NR_ioctl, fd, c_uint(TIOCGSID), &mut result))?; + let pid = result.assume_init(); + debug_assert!(pid > 0); + Ok(Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked( + pid as u32, + ))) + } +} + +#[inline] +pub(crate) fn tcsetwinsize(fd: BorrowedFd, winsize: Winsize) -> io::Result<()> { + unsafe { + ret(syscall!( + __NR_ioctl, + fd, + c_uint(TIOCSWINSZ), + by_ref(&winsize) + )) + } +} + +#[inline] +pub(crate) fn tcsetpgrp(fd: BorrowedFd<'_>, pid: Pid) -> io::Result<()> { + unsafe { ret(syscall!(__NR_ioctl, fd, c_uint(TIOCSPGRP), pid)) } +} + +#[inline] +#[must_use] +#[allow(clippy::missing_const_for_fn)] +pub(crate) fn cfgetospeed(termios: &Termios) -> u32 { + termios.c_cflag & CBAUD +} + +#[inline] +#[must_use] +#[allow(clippy::missing_const_for_fn)] +pub(crate) fn cfgetispeed(termios: &Termios) -> u32 { + termios.c_cflag & CBAUD +} + +#[inline] +pub(crate) fn cfmakeraw(termios: &mut Termios) { + // From the Linux [`cfmakeraw` manual page]: + // + // [`cfmakeraw` manual page]: https://man7.org/linux/man-pages/man3/cfmakeraw.3.html + termios.c_iflag &= !(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); + termios.c_oflag &= !OPOST; + termios.c_lflag &= !(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + termios.c_cflag &= !(CSIZE | PARENB); + termios.c_cflag |= CS8; + + // Musl and glibc also do these: + termios.c_cc[VMIN] = 1; + termios.c_cc[VTIME] = 0; +} + +#[inline] +pub(crate) fn cfsetospeed(termios: &mut Termios, speed: u32) -> io::Result<()> { + if (speed & !CBAUD) != 0 { + return Err(io::Errno::INVAL); + } + termios.c_cflag &= !CBAUD; + termios.c_cflag |= speed; + Ok(()) +} + +#[inline] +pub(crate) fn cfsetispeed(termios: &mut Termios, speed: u32) -> io::Result<()> { + if speed == 0 { + return Ok(()); + } + if (speed & !CBAUD) != 0 { + return Err(io::Errno::INVAL); + } + termios.c_cflag &= !CBAUD; + termios.c_cflag |= speed; + Ok(()) +} + +#[inline] +pub(crate) fn cfsetspeed(termios: &mut Termios, speed: u32) -> io::Result<()> { + if (speed & !CBAUD) != 0 { + return Err(io::Errno::INVAL); + } + termios.c_cflag &= !CBAUD; + termios.c_cflag |= speed; + Ok(()) +} + +#[inline] +pub(crate) fn isatty(fd: BorrowedFd<'_>) -> bool { + // On error, Linux will return either `EINVAL` (2.6.32) or `ENOTTY` + // (otherwise), because we assume we're never passing an invalid + // file descriptor (which would get `EBADF`). Either way, an error + // means we don't have a tty. + tcgetwinsize(fd).is_ok() +} + +#[cfg(feature = "procfs")] +pub(crate) fn ttyname(fd: BorrowedFd<'_>, buf: &mut [u8]) -> io::Result<usize> { + let fd_stat = super::super::fs::syscalls::fstat(fd)?; + + // Quick check: if `fd` isn't a character device, it's not a tty. + if FileType::from_raw_mode(fd_stat.st_mode) != FileType::CharacterDevice { + return Err(io::Errno::NOTTY); + } + + // Check that `fd` is really a tty. + tcgetwinsize(fd)?; + + // Get a fd to '/proc/self/fd'. + let proc_self_fd = io::proc_self_fd()?; + + // Gather the ttyname by reading the 'fd' file inside 'proc_self_fd'. + let r = + super::super::fs::syscalls::readlinkat(proc_self_fd, DecInt::from_fd(fd).as_c_str(), buf)?; + + // If the number of bytes is equal to the buffer length, truncation may + // have occurred. This check also ensures that we have enough space for + // adding a NUL terminator. + if r == buf.len() { + return Err(io::Errno::RANGE); + } + buf[r] = b'\0'; + + // Check that the path we read refers to the same file as `fd`. + let path = CStr::from_bytes_with_nul(&buf[..=r]).unwrap(); + + let path_stat = super::super::fs::syscalls::stat(path)?; + if path_stat.st_dev != fd_stat.st_dev || path_stat.st_ino != fd_stat.st_ino { + return Err(io::Errno::NODEV); + } + + Ok(r) +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/termios/types.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/termios/types.rs new file mode 100644 index 000000000..3fe45af98 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/termios/types.rs @@ -0,0 +1,495 @@ +use super::super::c; + +/// `TCSA*` values for use with [`tcsetattr`]. +/// +/// [`tcsetattr`]: crate::termios::tcsetattr +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[repr(u32)] +pub enum OptionalActions { + /// `TCSANOW`—Make the change immediately. + #[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, +} + +/// `TC*` values for use with [`tcflush`]. +/// +/// [`tcflush`]: crate::termios::tcflush +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[repr(u32)] +pub enum QueueSelector { + /// `TCIFLUSH`—Flush data received but not read. + #[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, +} + +/// `TC*` values for use with [`tcflow`]. +/// +/// [`tcflow`]: crate::termios::tcflow +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[repr(u32)] +pub enum Action { + /// `TCOOFF`—Suspend output. + #[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`] 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` +pub const VINTR: usize = linux_raw_sys::general::VINTR as usize; + +/// `VQUIT` +pub const VQUIT: usize = linux_raw_sys::general::VQUIT as usize; + +/// `VERASE` +pub const VERASE: usize = linux_raw_sys::general::VERASE as usize; + +/// `VKILL` +pub const VKILL: usize = linux_raw_sys::general::VKILL as usize; + +/// `VEOF` +pub const VEOF: usize = linux_raw_sys::general::VEOF as usize; + +/// `VTIME` +pub const VTIME: usize = linux_raw_sys::general::VTIME as usize; + +/// `VMIN` +pub const VMIN: usize = linux_raw_sys::general::VMIN as usize; + +/// `VSWTC` +pub const VSWTC: usize = linux_raw_sys::general::VSWTC as usize; + +/// `VSTART` +pub const VSTART: usize = linux_raw_sys::general::VSTART as usize; + +/// `VSTOP` +pub const VSTOP: usize = linux_raw_sys::general::VSTOP as usize; + +/// `VSUSP` +pub const VSUSP: usize = linux_raw_sys::general::VSUSP as usize; + +/// `VEOL` +pub const VEOL: usize = linux_raw_sys::general::VEOL as usize; + +/// `VREPRINT` +pub const VREPRINT: usize = linux_raw_sys::general::VREPRINT as usize; + +/// `VDISCARD` +pub const VDISCARD: usize = linux_raw_sys::general::VDISCARD as usize; + +/// `VWERASE` +pub const VWERASE: usize = linux_raw_sys::general::VWERASE as usize; + +/// `VLNEXT` +pub const VLNEXT: usize = linux_raw_sys::general::VLNEXT as usize; + +/// `VEOL2` +pub const VEOL2: usize = linux_raw_sys::general::VEOL2 as usize; + +/// `IGNBRK` +pub const IGNBRK: c::c_uint = linux_raw_sys::general::IGNBRK; + +/// `BRKINT` +pub const BRKINT: c::c_uint = linux_raw_sys::general::BRKINT; + +/// `IGNPAR` +pub const IGNPAR: c::c_uint = linux_raw_sys::general::IGNPAR; + +/// `PARMRK` +pub const PARMRK: c::c_uint = linux_raw_sys::general::PARMRK; + +/// `INPCK` +pub const INPCK: c::c_uint = linux_raw_sys::general::INPCK; + +/// `ISTRIP` +pub const ISTRIP: c::c_uint = linux_raw_sys::general::ISTRIP; + +/// `INLCR` +pub const INLCR: c::c_uint = linux_raw_sys::general::INLCR; + +/// `IGNCR` +pub const IGNCR: c::c_uint = linux_raw_sys::general::IGNCR; + +/// `ICRNL` +pub const ICRNL: c::c_uint = linux_raw_sys::general::ICRNL; + +/// `IUCLC` +pub const IUCLC: c::c_uint = linux_raw_sys::general::IUCLC; + +/// `IXON` +pub const IXON: c::c_uint = linux_raw_sys::general::IXON; + +/// `IXANY` +pub const IXANY: c::c_uint = linux_raw_sys::general::IXANY; + +/// `IXOFF` +pub const IXOFF: c::c_uint = linux_raw_sys::general::IXOFF; + +/// `IMAXBEL` +pub const IMAXBEL: c::c_uint = linux_raw_sys::general::IMAXBEL; + +/// `IUTF8` +pub const IUTF8: c::c_uint = linux_raw_sys::general::IUTF8; + +/// `OPOST` +pub const OPOST: c::c_uint = linux_raw_sys::general::OPOST; + +/// `OLCUC` +pub const OLCUC: c::c_uint = linux_raw_sys::general::OLCUC; + +/// `ONLCR` +pub const ONLCR: c::c_uint = linux_raw_sys::general::ONLCR; + +/// `OCRNL` +pub const OCRNL: c::c_uint = linux_raw_sys::general::OCRNL; + +/// `ONOCR` +pub const ONOCR: c::c_uint = linux_raw_sys::general::ONOCR; + +/// `ONLRET` +pub const ONLRET: c::c_uint = linux_raw_sys::general::ONLRET; + +/// `OFILL` +pub const OFILL: c::c_uint = linux_raw_sys::general::OFILL; + +/// `OFDEL` +pub const OFDEL: c::c_uint = linux_raw_sys::general::OFDEL; + +/// `NLDLY` +pub const NLDLY: c::c_uint = linux_raw_sys::general::NLDLY; + +/// `NL0` +pub const NL0: c::c_uint = linux_raw_sys::general::NL0; + +/// `NL1` +pub const NL1: c::c_uint = linux_raw_sys::general::NL1; + +/// `CRDLY` +pub const CRDLY: c::c_uint = linux_raw_sys::general::CRDLY; + +/// `CR0` +pub const CR0: c::c_uint = linux_raw_sys::general::CR0; + +/// `CR1` +pub const CR1: c::c_uint = linux_raw_sys::general::CR1; + +/// `CR2` +pub const CR2: c::c_uint = linux_raw_sys::general::CR2; + +/// `CR3` +pub const CR3: c::c_uint = linux_raw_sys::general::CR3; + +/// `TABDLY` +pub const TABDLY: c::c_uint = linux_raw_sys::general::TABDLY; + +/// `TAB0` +pub const TAB0: c::c_uint = linux_raw_sys::general::TAB0; + +/// `TAB1` +pub const TAB1: c::c_uint = linux_raw_sys::general::TAB1; + +/// `TAB2` +pub const TAB2: c::c_uint = linux_raw_sys::general::TAB2; + +/// `TAB3` +pub const TAB3: c::c_uint = linux_raw_sys::general::TAB3; + +/// `BSDLY` +pub const BSDLY: c::c_uint = linux_raw_sys::general::BSDLY; + +/// `BS0` +pub const BS0: c::c_uint = linux_raw_sys::general::BS0; + +/// `BS1` +pub const BS1: c::c_uint = linux_raw_sys::general::BS1; + +/// `FFDLY` +pub const FFDLY: c::c_uint = linux_raw_sys::general::FFDLY; + +/// `FF0` +pub const FF0: c::c_uint = linux_raw_sys::general::FF0; + +/// `FF1` +pub const FF1: c::c_uint = linux_raw_sys::general::FF1; + +/// `VTDLY` +pub const VTDLY: c::c_uint = linux_raw_sys::general::VTDLY; + +/// `VT0` +pub const VT0: c::c_uint = linux_raw_sys::general::VT0; + +/// `VT1` +pub const VT1: c::c_uint = linux_raw_sys::general::VT1; + +/// `B0` +pub const B0: Speed = linux_raw_sys::general::B0; + +/// `B50` +pub const B50: Speed = linux_raw_sys::general::B50; + +/// `B75` +pub const B75: Speed = linux_raw_sys::general::B75; + +/// `B110` +pub const B110: Speed = linux_raw_sys::general::B110; + +/// `B134` +pub const B134: Speed = linux_raw_sys::general::B134; + +/// `B150` +pub const B150: Speed = linux_raw_sys::general::B150; + +/// `B200` +pub const B200: Speed = linux_raw_sys::general::B200; + +/// `B300` +pub const B300: Speed = linux_raw_sys::general::B300; + +/// `B600` +pub const B600: Speed = linux_raw_sys::general::B600; + +/// `B1200` +pub const B1200: Speed = linux_raw_sys::general::B1200; + +/// `B1800` +pub const B1800: Speed = linux_raw_sys::general::B1800; + +/// `B2400` +pub const B2400: Speed = linux_raw_sys::general::B2400; + +/// `B4800` +pub const B4800: Speed = linux_raw_sys::general::B4800; + +/// `B9600` +pub const B9600: Speed = linux_raw_sys::general::B9600; + +/// `B19200` +pub const B19200: Speed = linux_raw_sys::general::B19200; + +/// `B38400` +pub const B38400: Speed = linux_raw_sys::general::B38400; + +/// `B57600` +pub const B57600: Speed = linux_raw_sys::general::B57600; + +/// `B115200` +pub const B115200: Speed = linux_raw_sys::general::B115200; + +/// `B230400` +pub const B230400: Speed = linux_raw_sys::general::B230400; + +/// `B460800` +pub const B460800: Speed = linux_raw_sys::general::B460800; + +/// `B500000` +pub const B500000: Speed = linux_raw_sys::general::B500000; + +/// `B576000` +pub const B576000: Speed = linux_raw_sys::general::B576000; + +/// `B921600` +pub const B921600: Speed = linux_raw_sys::general::B921600; + +/// `B1000000` +pub const B1000000: Speed = linux_raw_sys::general::B1000000; + +/// `B1152000` +pub const B1152000: Speed = linux_raw_sys::general::B1152000; + +/// `B1500000` +pub const B1500000: Speed = linux_raw_sys::general::B1500000; + +/// `B2000000` +pub const B2000000: Speed = linux_raw_sys::general::B2000000; + +/// `B2500000` +#[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] +pub const B2500000: Speed = linux_raw_sys::general::B2500000; + +/// `B3000000` +#[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] +pub const B3000000: Speed = linux_raw_sys::general::B3000000; + +/// `B3500000` +#[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] +pub const B3500000: Speed = linux_raw_sys::general::B3500000; + +/// `B4000000` +#[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] +pub const B4000000: Speed = linux_raw_sys::general::B4000000; + +/// `BOTHER` +pub const BOTHER: c::c_uint = linux_raw_sys::general::BOTHER; + +/// `CSIZE` +pub const CSIZE: c::c_uint = linux_raw_sys::general::CSIZE; + +/// `CS5` +pub const CS5: c::c_uint = linux_raw_sys::general::CS5; + +/// `CS6` +pub const CS6: c::c_uint = linux_raw_sys::general::CS6; + +/// `CS7` +pub const CS7: c::c_uint = linux_raw_sys::general::CS7; + +/// `CS8` +pub const CS8: c::c_uint = linux_raw_sys::general::CS8; + +/// `CSTOPB` +pub const CSTOPB: c::c_uint = linux_raw_sys::general::CSTOPB; + +/// `CREAD` +pub const CREAD: c::c_uint = linux_raw_sys::general::CREAD; + +/// `PARENB` +pub const PARENB: c::c_uint = linux_raw_sys::general::PARENB; + +/// `PARODD` +pub const PARODD: c::c_uint = linux_raw_sys::general::PARODD; + +/// `HUPCL` +pub const HUPCL: c::c_uint = linux_raw_sys::general::HUPCL; + +/// `CLOCAL` +pub const CLOCAL: c::c_uint = linux_raw_sys::general::CLOCAL; + +/// `ISIG` +pub const ISIG: c::c_uint = linux_raw_sys::general::ISIG; + +/// `ICANON`—A flag for the `c_lflag` field of [`Termios`] indicating +/// canonical mode. +pub const ICANON: Tcflag = linux_raw_sys::general::ICANON; + +/// `ECHO` +pub const ECHO: c::c_uint = linux_raw_sys::general::ECHO; + +/// `ECHOE` +pub const ECHOE: c::c_uint = linux_raw_sys::general::ECHOE; + +/// `ECHOK` +pub const ECHOK: c::c_uint = linux_raw_sys::general::ECHOK; + +/// `ECHONL` +pub const ECHONL: c::c_uint = linux_raw_sys::general::ECHONL; + +/// `NOFLSH` +pub const NOFLSH: c::c_uint = linux_raw_sys::general::NOFLSH; + +/// `TOSTOP` +pub const TOSTOP: c::c_uint = linux_raw_sys::general::TOSTOP; + +/// `IEXTEN` +pub const IEXTEN: c::c_uint = linux_raw_sys::general::IEXTEN; + +/// `EXTA` +pub const EXTA: c::c_uint = linux_raw_sys::general::EXTA; + +/// `EXTB` +pub const EXTB: c::c_uint = linux_raw_sys::general::EXTB; + +/// `CBAUD` +pub const CBAUD: c::c_uint = linux_raw_sys::general::CBAUD; + +/// `CBAUDEX` +pub const CBAUDEX: c::c_uint = linux_raw_sys::general::CBAUDEX; + +/// `CIBAUD` +pub const CIBAUD: c::c_uint = linux_raw_sys::general::CIBAUD; + +/// `CMSPAR` +pub const CMSPAR: c::c_uint = linux_raw_sys::general::CMSPAR; + +/// `CRTSCTS` +pub const CRTSCTS: c::c_uint = linux_raw_sys::general::CRTSCTS; + +/// `XCASE` +pub const XCASE: c::c_uint = linux_raw_sys::general::XCASE; + +/// `ECHOCTL` +pub const ECHOCTL: c::c_uint = linux_raw_sys::general::ECHOCTL; + +/// `ECHOPRT` +pub const ECHOPRT: c::c_uint = linux_raw_sys::general::ECHOPRT; + +/// `ECHOKE` +pub const ECHOKE: c::c_uint = linux_raw_sys::general::ECHOKE; + +/// `FLUSHO` +pub const FLUSHO: c::c_uint = linux_raw_sys::general::FLUSHO; + +/// `PENDIN` +pub const PENDIN: c::c_uint = linux_raw_sys::general::PENDIN; + +/// `EXTPROC` +pub const EXTPROC: c::c_uint = linux_raw_sys::general::EXTPROC; + +/// `XTABS` +pub const XTABS: c::c_uint = linux_raw_sys::general::XTABS; diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/thread/futex.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/thread/futex.rs new file mode 100644 index 000000000..4bb24cd61 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/thread/futex.rs @@ -0,0 +1,39 @@ +bitflags::bitflags! { + /// `FUTEX_*` flags for use with [`futex`]. + /// + /// [`futex`]: crate::thread::futex + pub struct FutexFlags: 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; + } +} + +/// `FUTEX_*` operations for use with [`futex`]. +/// +/// [`futex`]: crate::thread::futex +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[repr(u32)] +pub enum FutexOperation { + /// `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, +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/thread/mod.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/thread/mod.rs new file mode 100644 index 000000000..8bb80c33a --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/thread/mod.rs @@ -0,0 +1,4 @@ +mod futex; +pub(crate) mod syscalls; + +pub use futex::{FutexFlags, FutexOperation}; diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/thread/syscalls.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/thread/syscalls.rs new file mode 100644 index 000000000..ab1d23d54 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/thread/syscalls.rs @@ -0,0 +1,355 @@ +//! linux_raw syscalls supporting `rustix::thread`. +//! +//! # Safety +//! +//! See the `rustix::backend` module documentation for details. +#![allow(unsafe_code)] +#![allow(clippy::undocumented_unsafe_blocks)] + +use super::super::c; +use super::super::conv::{ + by_mut, by_ref, c_int, c_uint, ret, ret_c_int, ret_usize, ret_usize_infallible, + slice_just_addr, slice_just_addr_mut, zero, +}; +use crate::fd::BorrowedFd; +use crate::io; +use crate::process::{Pid, RawNonZeroPid}; +use crate::thread::{ClockId, FutexFlags, FutexOperation, NanosleepRelativeResult, Timespec}; +use core::mem::MaybeUninit; +use linux_raw_sys::general::{__kernel_pid_t, __kernel_timespec, TIMER_ABSTIME}; +#[cfg(target_pointer_width = "32")] +use {core::convert::TryInto, linux_raw_sys::general::timespec as __kernel_old_timespec}; + +#[inline] +pub(crate) fn clock_nanosleep_relative( + id: ClockId, + req: &__kernel_timespec, +) -> NanosleepRelativeResult { + #[cfg(target_pointer_width = "32")] + unsafe { + let mut rem = MaybeUninit::<__kernel_timespec>::uninit(); + match ret(syscall!( + __NR_clock_nanosleep_time64, + id, + c_int(0), + by_ref(req), + &mut rem + )) + .or_else(|err| { + // See the comments in `rustix_clock_gettime_via_syscall` about + // emulation. + if err == io::Errno::NOSYS { + clock_nanosleep_relative_old(id, req, &mut rem) + } else { + Err(err) + } + }) { + Ok(()) => NanosleepRelativeResult::Ok, + Err(io::Errno::INTR) => NanosleepRelativeResult::Interrupted(rem.assume_init()), + Err(err) => NanosleepRelativeResult::Err(err), + } + } + #[cfg(target_pointer_width = "64")] + unsafe { + let mut rem = MaybeUninit::<__kernel_timespec>::uninit(); + match ret(syscall!( + __NR_clock_nanosleep, + id, + c_int(0), + by_ref(req), + &mut rem + )) { + Ok(()) => NanosleepRelativeResult::Ok, + Err(io::Errno::INTR) => NanosleepRelativeResult::Interrupted(rem.assume_init()), + Err(err) => NanosleepRelativeResult::Err(err), + } + } +} + +#[cfg(target_pointer_width = "32")] +unsafe fn clock_nanosleep_relative_old( + id: ClockId, + req: &__kernel_timespec, + rem: &mut MaybeUninit<__kernel_timespec>, +) -> io::Result<()> { + let old_req = __kernel_old_timespec { + tv_sec: req.tv_sec.try_into().map_err(|_| io::Errno::INVAL)?, + tv_nsec: req.tv_nsec.try_into().map_err(|_| io::Errno::INVAL)?, + }; + let mut old_rem = MaybeUninit::<__kernel_old_timespec>::uninit(); + ret(syscall!( + __NR_clock_nanosleep, + id, + c_int(0), + by_ref(&old_req), + &mut old_rem + ))?; + let old_rem = old_rem.assume_init(); + // TODO: With Rust 1.55, we can use MaybeUninit::write here. + rem.as_mut_ptr().write(__kernel_timespec { + tv_sec: old_rem.tv_sec.into(), + tv_nsec: old_rem.tv_nsec.into(), + }); + Ok(()) +} + +#[inline] +pub(crate) fn clock_nanosleep_absolute(id: ClockId, req: &__kernel_timespec) -> io::Result<()> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret(syscall_readonly!( + __NR_clock_nanosleep_time64, + id, + c_uint(TIMER_ABSTIME), + by_ref(req), + zero() + )) + .or_else(|err| { + // See the comments in `rustix_clock_gettime_via_syscall` about + // emulation. + if err == io::Errno::NOSYS { + clock_nanosleep_absolute_old(id, req) + } else { + Err(err) + } + }) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret(syscall_readonly!( + __NR_clock_nanosleep, + id, + c_uint(TIMER_ABSTIME), + by_ref(req), + zero() + )) + } +} + +#[cfg(target_pointer_width = "32")] +unsafe fn clock_nanosleep_absolute_old(id: ClockId, req: &__kernel_timespec) -> io::Result<()> { + let old_req = __kernel_old_timespec { + tv_sec: req.tv_sec.try_into().map_err(|_| io::Errno::INVAL)?, + tv_nsec: req.tv_nsec.try_into().map_err(|_| io::Errno::INVAL)?, + }; + ret(syscall_readonly!( + __NR_clock_nanosleep, + id, + c_int(0), + by_ref(&old_req), + zero() + )) +} + +#[inline] +pub(crate) fn nanosleep(req: &__kernel_timespec) -> NanosleepRelativeResult { + #[cfg(target_pointer_width = "32")] + unsafe { + let mut rem = MaybeUninit::<__kernel_timespec>::uninit(); + match ret(syscall!( + __NR_clock_nanosleep_time64, + ClockId::Realtime, + c_int(0), + by_ref(req), + &mut rem + )) + .or_else(|err| { + // See the comments in `rustix_clock_gettime_via_syscall` about + // emulation. + if err == io::Errno::NOSYS { + nanosleep_old(req, &mut rem) + } else { + Err(err) + } + }) { + Ok(()) => NanosleepRelativeResult::Ok, + Err(io::Errno::INTR) => NanosleepRelativeResult::Interrupted(rem.assume_init()), + Err(err) => NanosleepRelativeResult::Err(err), + } + } + #[cfg(target_pointer_width = "64")] + unsafe { + let mut rem = MaybeUninit::<__kernel_timespec>::uninit(); + match ret(syscall!(__NR_nanosleep, by_ref(req), &mut rem)) { + Ok(()) => NanosleepRelativeResult::Ok, + Err(io::Errno::INTR) => NanosleepRelativeResult::Interrupted(rem.assume_init()), + Err(err) => NanosleepRelativeResult::Err(err), + } + } +} + +#[cfg(target_pointer_width = "32")] +unsafe fn nanosleep_old( + req: &__kernel_timespec, + rem: &mut MaybeUninit<__kernel_timespec>, +) -> io::Result<()> { + let old_req = __kernel_old_timespec { + tv_sec: req.tv_sec.try_into().map_err(|_| io::Errno::INVAL)?, + tv_nsec: req.tv_nsec.try_into().map_err(|_| io::Errno::INVAL)?, + }; + let mut old_rem = MaybeUninit::<__kernel_old_timespec>::uninit(); + ret(syscall!(__NR_nanosleep, by_ref(&old_req), &mut old_rem))?; + let old_rem = old_rem.assume_init(); + // TODO: With Rust 1.55, we can use MaybeUninit::write here. + rem.as_mut_ptr().write(__kernel_timespec { + tv_sec: old_rem.tv_sec.into(), + tv_nsec: old_rem.tv_nsec.into(), + }); + Ok(()) +} + +#[inline] +pub(crate) fn gettid() -> Pid { + unsafe { + let tid: i32 = ret_usize_infallible(syscall_readonly!(__NR_gettid)) as __kernel_pid_t; + debug_assert_ne!(tid, 0); + Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked(tid as u32)) + } +} + +// TODO: This could be de-multiplexed. +#[inline] +pub(crate) unsafe fn futex( + uaddr: *mut u32, + op: FutexOperation, + flags: FutexFlags, + val: u32, + utime: *const Timespec, + uaddr2: *mut u32, + val3: u32, +) -> io::Result<usize> { + #[cfg(target_pointer_width = "32")] + { + ret_usize(syscall!( + __NR_futex_time64, + uaddr, + (op, flags), + c_uint(val), + utime, + uaddr2, + c_uint(val3) + )) + .or_else(|err| { + // See the comments in `rustix_clock_gettime_via_syscall` about + // emulation. + if err == io::Errno::NOSYS { + futex_old(uaddr, op, flags, val, utime, uaddr2, val3) + } else { + Err(err) + } + }) + } + #[cfg(target_pointer_width = "64")] + ret_usize(syscall!( + __NR_futex, + uaddr, + (op, flags), + c_uint(val), + utime, + uaddr2, + c_uint(val3) + )) +} + +#[cfg(target_pointer_width = "32")] +unsafe fn futex_old( + uaddr: *mut u32, + op: FutexOperation, + flags: FutexFlags, + val: u32, + utime: *const Timespec, + uaddr2: *mut u32, + val3: u32, +) -> io::Result<usize> { + let old_utime = __kernel_old_timespec { + tv_sec: (*utime).tv_sec.try_into().map_err(|_| io::Errno::INVAL)?, + tv_nsec: (*utime).tv_nsec.try_into().map_err(|_| io::Errno::INVAL)?, + }; + ret_usize(syscall!( + __NR_futex, + uaddr, + (op, flags), + c_uint(val), + by_ref(&old_utime), + uaddr2, + c_uint(val3) + )) +} + +#[cfg(linux_kernel)] +#[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))) } +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn unshare(flags: crate::thread::UnshareFlags) -> io::Result<()> { + unsafe { ret(syscall_readonly!(__NR_unshare, c_uint(flags.bits()))) } +} + +#[cfg(linux_kernel)] +#[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) + )) + } +} + +#[cfg(linux_kernel)] +#[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::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-0.37.22/src/backend/linux_raw/time/mod.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/time/mod.rs new file mode 100644 index 000000000..c42592c4f --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/time/mod.rs @@ -0,0 +1,3 @@ +#[cfg(any(feature = "time", target_arch = "x86"))] +pub(crate) mod syscalls; +pub(crate) mod types; diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/time/syscalls.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/time/syscalls.rs new file mode 100644 index 000000000..98b5dcc2c --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/time/syscalls.rs @@ -0,0 +1,261 @@ +//! linux_raw syscalls supporting `rustix::time`. +//! +//! # Safety +//! +//! See the `rustix::backend` module documentation for details. +#![allow(unsafe_code)] +#![allow(clippy::undocumented_unsafe_blocks)] + +use super::super::conv::{ret, ret_infallible}; +use super::types::ClockId; +use crate::io; +use core::mem::MaybeUninit; +use linux_raw_sys::general::__kernel_timespec; +#[cfg(target_pointer_width = "32")] +use linux_raw_sys::general::timespec as __kernel_old_timespec; +#[cfg(feature = "time")] +use { + super::super::conv::{by_ref, ret_owned_fd}, + crate::fd::BorrowedFd, + crate::fd::OwnedFd, + crate::time::{Itimerspec, TimerfdClockId, TimerfdFlags, TimerfdTimerFlags}, +}; +#[cfg(all(feature = "time", target_pointer_width = "32"))] +use {core::convert::TryInto, linux_raw_sys::general::itimerspec as __kernel_old_itimerspec}; + +// `clock_gettime` has special optimizations via the vDSO. +#[cfg(feature = "time")] +pub(crate) use super::super::vdso_wrappers::{clock_gettime, clock_gettime_dynamic}; + +#[inline] +pub(crate) fn clock_getres(which_clock: ClockId) -> __kernel_timespec { + #[cfg(target_pointer_width = "32")] + unsafe { + let mut result = MaybeUninit::<__kernel_timespec>::uninit(); + if let Err(err) = ret(syscall!(__NR_clock_getres_time64, which_clock, &mut result)) { + // See the comments in `rustix_clock_gettime_via_syscall` about + // emulation. + debug_assert_eq!(err, io::Errno::NOSYS); + clock_getres_old(which_clock, &mut result); + } + result.assume_init() + } + #[cfg(target_pointer_width = "64")] + unsafe { + let mut result = MaybeUninit::<__kernel_timespec>::uninit(); + ret_infallible(syscall!(__NR_clock_getres, which_clock, &mut result)); + result.assume_init() + } +} + +#[cfg(target_pointer_width = "32")] +unsafe fn clock_getres_old(which_clock: ClockId, result: &mut MaybeUninit<__kernel_timespec>) { + let mut old_result = MaybeUninit::<__kernel_old_timespec>::uninit(); + ret_infallible(syscall!(__NR_clock_getres, which_clock, &mut old_result)); + let old_result = old_result.assume_init(); + // TODO: With Rust 1.55, we can use MaybeUninit::write here. + result.as_mut_ptr().write(__kernel_timespec { + tv_sec: old_result.tv_sec.into(), + tv_nsec: old_result.tv_nsec.into(), + }); +} + +#[cfg(feature = "time")] +#[inline] +pub(crate) fn clock_settime(which_clock: ClockId, timespec: __kernel_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, + 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<OwnedFd> { + unsafe { ret_owned_fd(syscall!(__NR_timerfd_create, clockid, flags)) } +} + +#[cfg(feature = "time")] +#[inline] +pub(crate) fn timerfd_settime( + fd: BorrowedFd<'_>, + flags: TimerfdTimerFlags, + new_value: &Itimerspec, +) -> io::Result<Itimerspec> { + let mut result = MaybeUninit::<Itimerspec>::uninit(); + + #[cfg(target_pointer_width = "64")] + unsafe { + ret(syscall!( + __NR_timerfd_settime, + fd, + flags, + by_ref(new_value), + &mut result + ))?; + Ok(result.assume_init()) + } + + #[cfg(target_pointer_width = "32")] + unsafe { + ret(syscall!( + __NR_timerfd_settime64, + fd, + flags, + by_ref(new_value), + &mut result + )) + .or_else(|err| { + // See the comments in `rustix_clock_gettime_via_syscall` about + // emulation. + if err == io::Errno::NOSYS { + timerfd_settime_old(fd, flags, new_value, &mut result) + } else { + Err(err) + } + })?; + Ok(result.assume_init()) + } +} + +#[cfg(feature = "time")] +#[cfg(target_pointer_width = "32")] +unsafe fn timerfd_settime_old( + fd: BorrowedFd<'_>, + flags: TimerfdTimerFlags, + new_value: &Itimerspec, + result: &mut MaybeUninit<Itimerspec>, +) -> io::Result<()> { + let mut old_result = MaybeUninit::<__kernel_old_itimerspec>::uninit(); + + // Convert `new_value` to the old `__kernel_old_itimerspec` format. + let old_new_value = __kernel_old_itimerspec { + it_interval: __kernel_old_timespec { + tv_sec: new_value + .it_interval + .tv_sec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + tv_nsec: new_value + .it_interval + .tv_nsec + .try_into() + .map_err(|_| io::Errno::INVAL)?, + }, + it_value: __kernel_old_timespec { + tv_sec: new_value + .it_value + .tv_sec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + tv_nsec: new_value + .it_value + .tv_nsec + .try_into() + .map_err(|_| io::Errno::INVAL)?, + }, + }; + ret(syscall!( + __NR_timerfd_settime, + fd, + flags, + by_ref(&old_new_value), + &mut old_result + ))?; + let old_result = old_result.assume_init(); + // TODO: With Rust 1.55, we can use MaybeUninit::write here. + result.as_mut_ptr().write(Itimerspec { + it_interval: __kernel_timespec { + tv_sec: old_result.it_interval.tv_sec.into(), + tv_nsec: old_result.it_interval.tv_nsec.into(), + }, + it_value: __kernel_timespec { + tv_sec: old_result.it_value.tv_sec.into(), + tv_nsec: old_result.it_value.tv_nsec.into(), + }, + }); + Ok(()) +} + +#[cfg(feature = "time")] +#[inline] +pub(crate) fn timerfd_gettime(fd: BorrowedFd<'_>) -> io::Result<Itimerspec> { + let mut result = MaybeUninit::<Itimerspec>::uninit(); + + #[cfg(target_pointer_width = "64")] + unsafe { + ret(syscall!(__NR_timerfd_gettime, fd, &mut result))?; + Ok(result.assume_init()) + } + + #[cfg(target_pointer_width = "32")] + unsafe { + ret(syscall!(__NR_timerfd_gettime64, fd, &mut result)).or_else(|err| { + // See the comments in `rustix_clock_gettime_via_syscall` about + // emulation. + if err == io::Errno::NOSYS { + timerfd_gettime_old(fd, &mut result) + } else { + Err(err) + } + })?; + Ok(result.assume_init()) + } +} + +#[cfg(feature = "time")] +#[cfg(target_pointer_width = "32")] +unsafe fn timerfd_gettime_old( + fd: BorrowedFd<'_>, + result: &mut MaybeUninit<Itimerspec>, +) -> io::Result<()> { + let mut old_result = MaybeUninit::<__kernel_old_itimerspec>::uninit(); + ret(syscall!(__NR_timerfd_gettime, fd, &mut old_result))?; + let old_result = old_result.assume_init(); + // TODO: With Rust 1.55, we can use MaybeUninit::write here. + result.as_mut_ptr().write(Itimerspec { + it_interval: __kernel_timespec { + tv_sec: old_result.it_interval.tv_sec.into(), + tv_nsec: old_result.it_interval.tv_nsec.into(), + }, + it_value: __kernel_timespec { + tv_sec: old_result.it_value.tv_sec.into(), + tv_nsec: old_result.it_value.tv_nsec.into(), + }, + }); + Ok(()) +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/time/types.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/time/types.rs new file mode 100644 index 000000000..fcdd7f6d6 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/time/types.rs @@ -0,0 +1,154 @@ +use super::super::c; +use crate::fd::BorrowedFd; +use bitflags::bitflags; + +/// `struct timespec` +pub type Timespec = linux_raw_sys::general::__kernel_timespec; + +/// A type for the `tv_sec` field of [`Timespec`]. +pub type Secs = linux_raw_sys::general::__kernel_time64_t; + +/// A type for the `tv_nsec` field of [`Timespec`]. +pub type Nsecs = i64; + +/// `struct itimerspec` for use with [`timerfd_gettime`] and +/// [`timerfd_settime`]. +/// +/// [`timerfd_gettime`]: crate::time::timerfd_gettime +/// [`timerfd_settime`]: crate::time::timerfd_settime +pub type Itimerspec = linux_raw_sys::general::__kernel_itimerspec; + +/// `CLOCK_*` constants for use with [`clock_gettime`]. +/// +/// These constants are always supported at runtime, so `clock_gettime` never +/// has to fail with `INVAL` due to an unsupported clock. See +/// [`DynamicClockId`] for a greater set of clocks, with the caveat that not +/// all of them are always supported. +/// +/// [`clock_gettime`]: crate::time::clock_gettime +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[repr(u32)] +#[non_exhaustive] +pub enum ClockId { + /// `CLOCK_REALTIME` + Realtime = linux_raw_sys::general::CLOCK_REALTIME, + + /// `CLOCK_MONOTONIC` + Monotonic = linux_raw_sys::general::CLOCK_MONOTONIC, + + /// `CLOCK_PROCESS_CPUTIME_ID` + ProcessCPUTime = linux_raw_sys::general::CLOCK_PROCESS_CPUTIME_ID, + + /// `CLOCK_THREAD_CPUTIME_ID` + ThreadCPUTime = linux_raw_sys::general::CLOCK_THREAD_CPUTIME_ID, + + /// `CLOCK_REALTIME_COARSE` + RealtimeCoarse = linux_raw_sys::general::CLOCK_REALTIME_COARSE, + + /// `CLOCK_MONOTONIC_COARSE` + MonotonicCoarse = linux_raw_sys::general::CLOCK_MONOTONIC_COARSE, + + /// `CLOCK_MONOTONIC_RAW` + MonotonicRaw = linux_raw_sys::general::CLOCK_MONOTONIC_RAW, +} + +/// `CLOCK_*` constants for use with [`clock_gettime_dynamic`]. +/// +/// These constants may be unsupported at runtime, depending on the OS version, +/// and `clock_gettime_dynamic` may fail with `INVAL`. See [`ClockId`] for +/// clocks which are always supported at runtime. +/// +/// [`clock_gettime_dynamic`]: crate::time::clock_gettime_dynamic +#[derive(Debug, Copy, Clone)] +#[non_exhaustive] +pub enum DynamicClockId<'a> { + /// `ClockId` values that are always supported at runtime. + Known(ClockId), + + /// Linux dynamic clocks. + Dynamic(BorrowedFd<'a>), + + /// `CLOCK_REALTIME_ALARM`, available on Linux >= 3.0 + RealtimeAlarm, + + /// `CLOCK_TAI`, available on Linux >= 3.10 + Tai, + + /// `CLOCK_BOOTTIME`, available on Linux >= 2.6.39 + Boottime, + + /// `CLOCK_BOOTTIME_ALARM`, available on Linux >= 2.6.39 + BoottimeAlarm, +} + +bitflags! { + /// `TFD_*` flags for use with [`timerfd_create`]. + /// + /// [`timerfd_create`]: crate::time::timerfd_create + pub struct TimerfdFlags: c::c_uint { + /// `TFD_NONBLOCK` + const NONBLOCK = linux_raw_sys::general::TFD_NONBLOCK; + + /// `TFD_CLOEXEC` + const CLOEXEC = linux_raw_sys::general::TFD_CLOEXEC; + } +} + +bitflags! { + /// `TFD_TIMER_*` flags for use with [`timerfd_settime`]. + /// + /// [`timerfd_settime`]: crate::time::timerfd_settime + pub struct TimerfdTimerFlags: c::c_uint { + /// `TFD_TIMER_ABSTIME` + const ABSTIME = linux_raw_sys::general::TFD_TIMER_ABSTIME; + + /// `TFD_TIMER_CANCEL_ON_SET` + const CANCEL_ON_SET = linux_raw_sys::general::TFD_TIMER_CANCEL_ON_SET; + } +} + +/// `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. + 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. + 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. + 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. + 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. + BoottimeAlarm = linux_raw_sys::general::CLOCK_BOOTTIME_ALARM, +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/vdso.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/vdso.rs new file mode 100644 index 000000000..606aee7d1 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/vdso.rs @@ -0,0 +1,310 @@ +//! Parse the Linux vDSO. +//! +//! The following code is transliterated from +//! tools/testing/selftests/vDSO/parse_vdso.c in Linux 5.11, which is licensed +//! with Creative Commons Zero License, version 1.0, +//! available at <https://creativecommons.org/publicdomain/zero/1.0/legalcode> +//! +//! # Safety +//! +//! Parsing the vDSO involves a lot of raw pointer manipulation. This +//! implementation follows Linux's reference implementation, and adds several +//! additional safety checks. +#![allow(unsafe_code)] + +use super::c; +use super::elf::*; +use crate::ffi::CStr; +use crate::utils::check_raw_pointer; +use core::ffi::c_void; +use core::mem::size_of; +use core::ptr::{null, null_mut}; + +pub(super) struct Vdso { + // Load information + load_addr: *const Elf_Ehdr, + load_end: *const c_void, // the end of the `PT_LOAD` segment + pv_offset: usize, // recorded paddr - recorded vaddr + + // Symbol table + symtab: *const Elf_Sym, + symstrings: *const u8, + bucket: *const u32, + chain: *const u32, + nbucket: u32, + //nchain: u32, + + // Version table + versym: *const u16, + verdef: *const Elf_Verdef, +} + +// Straight from the ELF specification. +fn elf_hash(name: &CStr) -> u32 { + let mut h: u32 = 0; + for b in name.to_bytes() { + h = (h << 4).wrapping_add(u32::from(*b)); + let g = h & 0xf000_0000; + if g != 0 { + h ^= g >> 24; + } + h &= !g; + } + h +} + +/// Create a `Vdso` value by parsing the vDSO at the `sysinfo_ehdr` address. +fn init_from_sysinfo_ehdr() -> Option<Vdso> { + // SAFETY: the auxv initialization code does extensive checks to ensure + // that the value we get really is an `AT_SYSINFO_EHDR` value from the + // kernel. + unsafe { + let hdr = super::param::auxv::sysinfo_ehdr(); + + // If the platform doesn't provide a `AT_SYSINFO_EHDR`, we can't locate + // the vDSO. + if hdr.is_null() { + return None; + } + + let mut vdso = Vdso { + load_addr: hdr, + load_end: hdr.cast(), + pv_offset: 0, + symtab: null(), + symstrings: null(), + bucket: null(), + chain: null(), + nbucket: 0, + //nchain: 0, + versym: null(), + verdef: null(), + }; + + let hdr = &*hdr; + let pt = check_raw_pointer::<Elf_Phdr>(vdso.base_plus(hdr.e_phoff)? as *mut _)?.as_ptr(); + let mut dyn_: *const Elf_Dyn = null(); + let mut num_dyn = 0; + + // We need two things from the segment table: the load offset + // and the dynamic table. + let mut found_vaddr = false; + for i in 0..hdr.e_phnum { + let phdr = &*pt.add(i as usize); + if phdr.p_flags & PF_W != 0 { + // Don't trust any vDSO that claims to be loading writable + // segments into memory. + return None; + } + if phdr.p_type == PT_LOAD && !found_vaddr { + // The segment should be readable and executable, because it + // contains the symbol table and the function bodies. + if phdr.p_flags & (PF_R | PF_X) != (PF_R | PF_X) { + return None; + } + found_vaddr = true; + vdso.load_end = vdso.base_plus(phdr.p_offset.checked_add(phdr.p_memsz)?)?; + vdso.pv_offset = phdr.p_offset.wrapping_sub(phdr.p_vaddr); + } else if phdr.p_type == PT_DYNAMIC { + // If `p_offset` is zero, it's more likely that we're looking at memory + // that has been zeroed than that the kernel has somehow aliased the + // `Ehdr` and the `Elf_Dyn` array. + if phdr.p_offset < size_of::<Elf_Ehdr>() { + return None; + } + + dyn_ = check_raw_pointer::<Elf_Dyn>(vdso.base_plus(phdr.p_offset)? as *mut _)? + .as_ptr(); + num_dyn = phdr.p_memsz / size_of::<Elf_Dyn>(); + } else if phdr.p_type == PT_INTERP || phdr.p_type == PT_GNU_RELRO { + // Don't trust any ELF image that has an “interpreter” or that uses + // RELRO, which is likely to be a user ELF image rather and not the + // kernel vDSO. + return None; + } + } + + if !found_vaddr || dyn_.is_null() { + return None; // Failed + } + + // Fish out the useful bits of the dynamic table. + let mut hash: *const u32 = null(); + vdso.symstrings = null(); + vdso.symtab = null(); + vdso.versym = null(); + vdso.verdef = null(); + let mut i = 0; + loop { + if i == num_dyn { + return None; + } + let d = &*dyn_.add(i); + match d.d_tag { + DT_STRTAB => { + vdso.symstrings = + check_raw_pointer::<u8>(vdso.addr_from_elf(d.d_val)? as *mut _)?.as_ptr(); + } + DT_SYMTAB => { + vdso.symtab = + check_raw_pointer::<Elf_Sym>(vdso.addr_from_elf(d.d_val)? as *mut _)? + .as_ptr(); + } + DT_HASH => { + hash = + check_raw_pointer::<u32>(vdso.addr_from_elf(d.d_val)? as *mut _)?.as_ptr(); + } + DT_VERSYM => { + vdso.versym = + check_raw_pointer::<u16>(vdso.addr_from_elf(d.d_val)? as *mut _)?.as_ptr(); + } + DT_VERDEF => { + vdso.verdef = + check_raw_pointer::<Elf_Verdef>(vdso.addr_from_elf(d.d_val)? as *mut _)? + .as_ptr(); + } + DT_SYMENT => { + if d.d_val != size_of::<Elf_Sym>() { + return None; // Failed + } + } + DT_NULL => break, + _ => {} + } + i = i.checked_add(1)?; + } + // The upstream code checks `symstrings`, `symtab`, and `hash` for null; + // here, `check_raw_pointer` has already done that. + + if vdso.verdef.is_null() { + vdso.versym = null(); + } + + // Parse the hash table header. + vdso.nbucket = *hash.add(0); + //vdso.nchain = *hash.add(1); + vdso.bucket = hash.add(2); + vdso.chain = hash.add(vdso.nbucket as usize + 2); + + // That's all we need. + Some(vdso) + } +} + +impl Vdso { + /// Parse the vDSO. + /// + /// Returns `None` if the vDSO can't be located or if it doesn't conform + /// to our expectations. + #[inline] + pub(super) fn new() -> Option<Self> { + init_from_sysinfo_ehdr() + } + + /// Check the version for a symbol. + /// + /// # Safety + /// + /// The raw pointers inside `self` must be valid. + unsafe fn match_version(&self, mut ver: u16, name: &CStr, hash: u32) -> bool { + // This is a helper function to check if the version indexed by + // ver matches name (which hashes to hash). + // + // The version definition table is a mess, and I don't know how + // to do this in better than linear time without allocating memory + // to build an index. I also don't know why the table has + // variable size entries in the first place. + // + // For added fun, I can't find a comprehensible specification of how + // to parse all the weird flags in the table. + // + // So I just parse the whole table every time. + + // First step: find the version definition + ver &= 0x7fff; // Apparently bit 15 means "hidden" + let mut def = self.verdef; + loop { + if (*def).vd_version != VER_DEF_CURRENT { + return false; // Failed + } + + if ((*def).vd_flags & VER_FLG_BASE) == 0 && ((*def).vd_ndx & 0x7fff) == ver { + break; + } + + if (*def).vd_next == 0 { + return false; // No definition. + } + + def = def + .cast::<u8>() + .add((*def).vd_next as usize) + .cast::<Elf_Verdef>(); + } + + // Now figure out whether it matches. + let aux = &*(def.cast::<u8>()) + .add((*def).vd_aux as usize) + .cast::<Elf_Verdaux>(); + (*def).vd_hash == hash + && (name == CStr::from_ptr(self.symstrings.add(aux.vda_name as usize).cast())) + } + + /// Look up a symbol in the vDSO. + pub(super) fn sym(&self, version: &CStr, name: &CStr) -> *mut c::c_void { + let ver_hash = elf_hash(version); + let name_hash = elf_hash(name); + + // SAFETY: The pointers in `self` must be valid. + unsafe { + let mut chain = *self.bucket.add((name_hash % self.nbucket) as usize); + + while chain != STN_UNDEF { + let sym = &*self.symtab.add(chain as usize); + + // Check for a defined global or weak function w/ right name. + // + // The reference parser in Linux's parse_vdso.c requires + // symbols to have type `STT_FUNC`, but on powerpc64, the vDSO + // uses `STT_NOTYPE`, so allow that too. + if (ELF_ST_TYPE(sym.st_info) != STT_FUNC && + ELF_ST_TYPE(sym.st_info) != STT_NOTYPE) + || (ELF_ST_BIND(sym.st_info) != STB_GLOBAL + && ELF_ST_BIND(sym.st_info) != STB_WEAK) + || sym.st_shndx == SHN_UNDEF + || sym.st_shndx == SHN_ABS + || ELF_ST_VISIBILITY(sym.st_other) != STV_DEFAULT + || (name != CStr::from_ptr(self.symstrings.add(sym.st_name as usize).cast())) + // Check symbol version. + || (!self.versym.is_null() + && !self.match_version(*self.versym.add(chain as usize), version, ver_hash)) + { + chain = *self.chain.add(chain as usize); + continue; + } + + let sum = self.addr_from_elf(sym.st_value).unwrap(); + assert!( + sum as usize >= self.load_addr as usize + && sum as usize <= self.load_end as usize + ); + return sum as *mut c::c_void; + } + } + + null_mut() + } + + /// Add the given address to the vDSO base address. + unsafe fn base_plus(&self, offset: usize) -> Option<*const c_void> { + // Check for overflow. + let _ = (self.load_addr as usize).checked_add(offset)?; + // Add the offset to the base. + Some(self.load_addr.cast::<u8>().add(offset).cast()) + } + + /// Translate an ELF-address-space address into a usable virtual address. + unsafe fn addr_from_elf(&self, elf_addr: usize) -> Option<*const c_void> { + self.base_plus(elf_addr.wrapping_add(self.pv_offset)) + } +} diff --git a/vendor/rustix-0.37.22/src/backend/linux_raw/vdso_wrappers.rs b/vendor/rustix-0.37.22/src/backend/linux_raw/vdso_wrappers.rs new file mode 100644 index 000000000..51b98e643 --- /dev/null +++ b/vendor/rustix-0.37.22/src/backend/linux_raw/vdso_wrappers.rs @@ -0,0 +1,399 @@ +//! 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)] + +use super::conv::{c_int, ret}; +#[cfg(target_arch = "x86")] +use super::reg::{ArgReg, RetReg, SyscallNumber, A0, A1, A2, A3, A4, A5, R0}; +use super::time::types::{ClockId, DynamicClockId, Timespec}; +use super::{c, vdso}; +use crate::io; +#[cfg(all(asm, target_arch = "x86"))] +use core::arch::asm; +use core::mem::{transmute, MaybeUninit}; +use core::ptr::null_mut; +use core::sync::atomic::AtomicPtr; +use core::sync::atomic::Ordering::Relaxed; +#[cfg(target_pointer_width = "32")] +use linux_raw_sys::general::timespec as __kernel_old_timespec; +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 + // 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::<__kernel_timespec>::uninit(); + let callee = match transmute(CLOCK_GETTIME.load(Relaxed)) { + Some(callee) => callee, + None => init_clock_gettime(), + }; + let r0 = callee(which_clock as c::c_int, result.as_mut_ptr()); + assert_eq!(r0, 0); + result.assume_init() + } +} + +#[inline] +pub(crate) fn clock_gettime_dynamic(which_clock: DynamicClockId<'_>) -> io::Result<Timespec> { + let id = match which_clock { + 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; + const CLOCKFD: i32 = 3; + ((!fd.as_raw_fd() << 3) | CLOCKFD) as __kernel_clockid_t + } + + DynamicClockId::RealtimeAlarm => { + linux_raw_sys::general::CLOCK_REALTIME_ALARM as __kernel_clockid_t + } + DynamicClockId::Tai => linux_raw_sys::general::CLOCK_TAI as __kernel_clockid_t, + DynamicClockId::Boottime => linux_raw_sys::general::CLOCK_BOOTTIME as __kernel_clockid_t, + DynamicClockId::BoottimeAlarm => { + linux_raw_sys::general::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), + _ => _rustix_clock_gettime_via_syscall(id, timespec.as_mut_ptr())?, + } + Ok(timespec.assume_init()) + } +} + +#[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. + 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, + }; +} + +type ClockGettimeType = unsafe extern "C" fn(c::c_int, *mut Timespec) -> 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. +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 `SYSCALL` and return its value. +#[cfg(target_arch = "x86")] +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; +static mut CLOCK_GETTIME: AtomicPtr<Function> = AtomicPtr::new(null_mut()); +#[cfg(target_arch = "x86")] +static mut SYSCALL: AtomicPtr<Function> = AtomicPtr::new(null_mut()); + +unsafe extern "C" fn rustix_clock_gettime_via_syscall( + clockid: c::c_int, + res: *mut Timespec, +) -> c::c_int { + match _rustix_clock_gettime_via_syscall(clockid, res) { + Ok(()) => 0, + Err(err) => err.raw_os_error().wrapping_neg(), + } +} + +#[cfg(target_pointer_width = "32")] +unsafe fn _rustix_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) => _rustix_clock_gettime_via_syscall_old(clockid, res), + otherwise => otherwise, + } +} + +#[cfg(target_pointer_width = "32")] +unsafe fn _rustix_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(target_pointer_width = "64")] +unsafe fn _rustix_clock_gettime_via_syscall( + clockid: c::c_int, + res: *mut Timespec, +) -> io::Result<()> { + ret(syscall!(__NR_clock_gettime, c_int(clockid), res)) +} + +/// A symbol pointing to an `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. +#[cfg(all(asm, target_arch = "x86"))] +#[naked] +unsafe extern "C" fn rustix_int_0x80() { + asm!("int $$0x80", "ret", options(noreturn)) +} + +// The outline version of the `rustix_int_0x80` above. +#[cfg(all(not(asm), target_arch = "x86"))] +extern "C" { + fn rustix_int_0x80(); +} + +fn minimal_init() { + // 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. + unsafe { + CLOCK_GETTIME + .compare_exchange( + null_mut(), + rustix_clock_gettime_via_syscall as *mut Function, + Relaxed, + Relaxed, + ) + .ok(); + #[cfg(target_arch = "x86")] + { + SYSCALL + .compare_exchange( + null_mut(), + rustix_int_0x80 as *mut Function, + Relaxed, + Relaxed, + ) + .ok(); + } + } +} + +fn init() { + minimal_init(); + + if let Some(vdso) = vdso::Vdso::new() { + // 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 = "powerpc64")] + let ptr = vdso.sym(cstr!("LINUX_2.6.15"), cstr!("__kernel_clock_gettime")); + #[cfg(target_arch = "mips")] + let ptr = vdso.sym(cstr!("LINUX_2.6"), cstr!("__vdso_clock_gettime64")); + #[cfg(target_arch = "mips64")] + 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 = "x86"))] + let ok = !ptr.is_null(); + + if ok { + assert!(!ptr.is_null()); + + // 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 { + CLOCK_GETTIME.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()); + + // SAFETY: As above, store the computed function addresses in + // static storage. + unsafe { + SYSCALL.store(ptr.cast(), Relaxed); + } + } + } +} diff --git a/vendor/rustix-0.37.22/src/const_assert.rs b/vendor/rustix-0.37.22/src/const_assert.rs new file mode 100644 index 000000000..99698cecb --- /dev/null +++ b/vendor/rustix-0.37.22/src/const_assert.rs @@ -0,0 +1,22 @@ +/// A simple `assert` macro that works in `const fn`, for use until the +/// standard `assert` macro works in `const fn`. +/// +/// TODO: With Rust 1.58 we can replace this with just `assert!`. +#[allow(unused_macros)] +macro_rules! const_assert { + ($x:expr) => { + let b: bool = $x; + let _ = [()][!b as usize]; + }; +} + +#[test] +#[allow(clippy::missing_const_for_fn)] +fn test_const_assert() { + const_assert!(true); +} + +#[test] +const fn test_const_assert_in_const_fn() { + const_assert!(true); +} diff --git a/vendor/rustix-0.37.22/src/cstr.rs b/vendor/rustix-0.37.22/src/cstr.rs new file mode 100644 index 000000000..b2a72ae73 --- /dev/null +++ b/vendor/rustix-0.37.22/src/cstr.rs @@ -0,0 +1,76 @@ +/// A macro for [`CStr`] literals. +/// +/// This can make passing string literals to rustix APIs more efficient, since +/// most underlying system calls with string arguments expect NUL-terminated +/// strings, and passing strings to rustix as `CStr`s means that rustix doesn't +/// need to copy them into a separate buffer to NUL-terminate them. +/// +/// [`CStr`]: crate::ffi::CStr +/// +/// # Examples +/// +/// ```no_run +/// # #[cfg(feature = "fs")] +/// # fn main() -> rustix::io::Result<()> { +/// use rustix::cstr; +/// use rustix::fs::{cwd, statat, AtFlags}; +/// +/// let metadata = statat(cwd(), cstr!("test.txt"), AtFlags::empty())?; +/// # Ok(()) +/// # } +/// # #[cfg(not(feature = "fs"))] +/// # fn main() {} +/// ``` +#[allow(unused_macros)] +#[macro_export] +macro_rules! cstr { + ($str:literal) => {{ + // Check for NUL manually, to ensure safety. + // + // In release builds, with strings that don't contain NULs, this + // constant-folds away. + // + // We don't use std's `CStr::from_bytes_with_nul`; as of this writing, + // that function isn't defined as `#[inline]` in std and doesn't + // constant-fold away. + assert!( + !$str.bytes().any(|b| b == b'\0'), + "cstr argument contains embedded NUL bytes", + ); + + #[allow(unsafe_code, unused_unsafe)] + { + // Now that we know the string doesn't have embedded NULs, we can + // call `from_bytes_with_nul_unchecked`, which as of this writing + // is defined as `#[inline]` and completely optimizes away. + // + // SAFETY: We have manually checked that the string does not contain + // embedded NULs above, and we append or own NUL terminator here. + unsafe { + $crate::ffi::CStr::from_bytes_with_nul_unchecked(concat!($str, "\0").as_bytes()) + } + } + }}; +} + +#[test] +fn test_cstr() { + use crate::ffi::CString; + use alloc::borrow::ToOwned; + assert_eq!(cstr!(""), &*CString::new("").unwrap()); + assert_eq!(cstr!("").to_owned(), CString::new("").unwrap()); + assert_eq!(cstr!("hello"), &*CString::new("hello").unwrap()); + assert_eq!(cstr!("hello").to_owned(), CString::new("hello").unwrap()); +} + +#[test] +#[should_panic] +fn test_invalid_cstr() { + let _ = cstr!("hello\0world"); +} + +#[test] +#[should_panic] +fn test_invalid_empty_cstr() { + let _ = cstr!("\0"); +} diff --git a/vendor/rustix-0.37.22/src/ffi/mod.rs b/vendor/rustix-0.37.22/src/ffi/mod.rs new file mode 100644 index 000000000..eb9983610 --- /dev/null +++ b/vendor/rustix-0.37.22/src/ffi/mod.rs @@ -0,0 +1,16 @@ +//! Utilities related to FFI bindings. + +// If we have std, use it. +#[cfg(feature = "std")] +pub use { + std::ffi::{CStr, CString, FromBytesWithNulError, NulError}, + std::os::raw::c_char, +}; + +// If we don't have std, we can depend on core and alloc having these features +// in new versions of Rust. +#[cfg(not(feature = "std"))] +pub use { + alloc::ffi::{CString, NulError}, + core::ffi::{c_char, CStr, FromBytesWithNulError}, +}; diff --git a/vendor/rustix-0.37.22/src/fs/abs.rs b/vendor/rustix-0.37.22/src/fs/abs.rs new file mode 100644 index 000000000..314895006 --- /dev/null +++ b/vendor/rustix-0.37.22/src/fs/abs.rs @@ -0,0 +1,55 @@ +//! POSIX-style filesystem functions which operate on bare paths. + +#[cfg(not(any( + solarish, + target_os = "haiku", + target_os = "netbsd", + target_os = "redox", + target_os = "wasi", +)))] +use crate::fs::StatFs; +#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))] +use { + crate::fs::StatVfs, + crate::{backend, io, path}, +}; + +/// `statfs`—Queries filesystem metadata. +/// +/// Compared to [`statvfs`], this function often provides more information, +/// though it's less portable. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/statfs.2.html +#[cfg(not(any( + solarish, + target_os = "haiku", + target_os = "netbsd", + target_os = "redox", + target_os = "wasi", +)))] +#[inline] +pub fn statfs<P: path::Arg>(path: P) -> io::Result<StatFs> { + path.into_with_c_str(backend::fs::syscalls::statfs) +} + +/// `statvfs`—Queries filesystem metadata, POSIX version. +/// +/// Compared to [`statfs`], this function often provides less information, +/// but it is more portable. But even so, filesystems are very diverse and not +/// all the fields are meaningful for every filesystem. And `f_fsid` doesn't +/// seem to have a clear meaning anywhere. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/statvfs.html +/// [Linux]: https://man7.org/linux/man-pages/man2/statvfs.2.html +#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))] +#[inline] +pub fn statvfs<P: path::Arg>(path: P) -> io::Result<StatVfs> { + path.into_with_c_str(backend::fs::syscalls::statvfs) +} diff --git a/vendor/rustix-0.37.22/src/fs/at.rs b/vendor/rustix-0.37.22/src/fs/at.rs new file mode 100644 index 000000000..73f836396 --- /dev/null +++ b/vendor/rustix-0.37.22/src/fs/at.rs @@ -0,0 +1,412 @@ +//! POSIX-style `*at` functions. +//! +//! The `dirfd` argument to these functions may be a file descriptor for a +//! directory, or the special value returned by [`cwd`]. +//! +//! [`cwd`]: crate::fs::cwd::cwd + +use crate::fd::OwnedFd; +use crate::ffi::{CStr, CString}; +#[cfg(apple)] +use crate::fs::CloneFlags; +#[cfg(not(any(apple, target_os = "wasi")))] +use crate::fs::FileType; +#[cfg(linux_kernel)] +use crate::fs::RenameFlags; +use crate::fs::{Access, AtFlags, Mode, OFlags, Stat, Timestamps}; +use crate::path::SMALL_PATH_BUFFER_SIZE; +#[cfg(not(target_os = "wasi"))] +use crate::process::{Gid, Uid}; +use crate::{backend, io, path}; +use alloc::vec::Vec; +use backend::fd::{AsFd, BorrowedFd}; +use backend::time::types::Nsecs; + +pub use backend::fs::types::{Dev, RawMode}; + +/// `UTIME_NOW` for use with [`utimensat`]. +/// +/// [`utimensat`]: crate::fs::utimensat +#[cfg(not(target_os = "redox"))] +pub const UTIME_NOW: Nsecs = backend::c::UTIME_NOW as Nsecs; + +/// `UTIME_OMIT` for use with [`utimensat`]. +/// +/// [`utimensat`]: crate::fs::utimensat +#[cfg(not(target_os = "redox"))] +pub const UTIME_OMIT: Nsecs = backend::c::UTIME_OMIT as Nsecs; + +/// `openat(dirfd, path, oflags, mode)`—Opens a file. +/// +/// POSIX guarantees that `openat` will use the lowest unused file descriptor, +/// however it is not safe in general to rely on this, as file descriptors may +/// be unexpectedly allocated on other threads or in libraries. +/// +/// The `Mode` argument is only significant when creating a file. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/openat.html +/// [Linux]: https://man7.org/linux/man-pages/man2/openat.2.html +#[inline] +pub fn openat<P: path::Arg, Fd: AsFd>( + dirfd: Fd, + path: P, + oflags: OFlags, + create_mode: Mode, +) -> io::Result<OwnedFd> { + path.into_with_c_str(|path| { + backend::fs::syscalls::openat(dirfd.as_fd(), path, oflags, create_mode) + }) +} + +/// `readlinkat(fd, path)`—Reads the contents of a symlink. +/// +/// If `reuse` is non-empty, reuse its buffer to store the result if possible. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/readlinkat.html +/// [Linux]: https://man7.org/linux/man-pages/man2/readlinkat.2.html +#[inline] +pub fn readlinkat<P: path::Arg, Fd: AsFd, B: Into<Vec<u8>>>( + dirfd: Fd, + path: P, + reuse: B, +) -> io::Result<CString> { + path.into_with_c_str(|path| _readlinkat(dirfd.as_fd(), path, reuse.into())) +} + +fn _readlinkat(dirfd: BorrowedFd<'_>, path: &CStr, mut buffer: Vec<u8>) -> io::Result<CString> { + // This code would benefit from having a better way to read into + // uninitialized memory, but that requires `unsafe`. + buffer.clear(); + buffer.reserve(SMALL_PATH_BUFFER_SIZE); + buffer.resize(buffer.capacity(), 0_u8); + + loop { + let nread = backend::fs::syscalls::readlinkat(dirfd.as_fd(), path, &mut buffer)?; + + let nread = nread as usize; + assert!(nread <= buffer.len()); + if nread < buffer.len() { + buffer.resize(nread, 0_u8); + return Ok(CString::new(buffer).unwrap()); + } + buffer.reserve(1); // use `Vec` reallocation strategy to grow capacity exponentially + buffer.resize(buffer.capacity(), 0_u8); + } +} + +/// `mkdirat(fd, path, mode)`—Creates a directory. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdirat.html +/// [Linux]: https://man7.org/linux/man-pages/man2/mkdirat.2.html +#[inline] +pub fn mkdirat<P: path::Arg, Fd: AsFd>(dirfd: Fd, path: P, mode: Mode) -> io::Result<()> { + path.into_with_c_str(|path| backend::fs::syscalls::mkdirat(dirfd.as_fd(), path, mode)) +} + +/// `linkat(old_dirfd, old_path, new_dirfd, new_path, flags)`—Creates a hard +/// link. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/linkat.html +/// [Linux]: https://man7.org/linux/man-pages/man2/linkat.2.html +#[inline] +pub fn linkat<P: path::Arg, Q: path::Arg, PFd: AsFd, QFd: AsFd>( + old_dirfd: PFd, + old_path: P, + new_dirfd: QFd, + new_path: Q, + flags: AtFlags, +) -> io::Result<()> { + old_path.into_with_c_str(|old_path| { + new_path.into_with_c_str(|new_path| { + backend::fs::syscalls::linkat( + old_dirfd.as_fd(), + old_path, + new_dirfd.as_fd(), + new_path, + flags, + ) + }) + }) +} + +/// `unlinkat(fd, path, flags)`—Unlinks a file or remove a directory. +/// +/// With the [`REMOVEDIR`] flag, this removes a directory. This is in place +/// of a `rmdirat` function. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [`REMOVEDIR`]: AtFlags::REMOVEDIR +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlinkat.html +/// [Linux]: https://man7.org/linux/man-pages/man2/unlinkat.2.html +#[inline] +pub fn unlinkat<P: path::Arg, Fd: AsFd>(dirfd: Fd, path: P, flags: AtFlags) -> io::Result<()> { + path.into_with_c_str(|path| backend::fs::syscalls::unlinkat(dirfd.as_fd(), path, flags)) +} + +/// `renameat(old_dirfd, old_path, new_dirfd, new_path)`—Renames a file or +/// directory. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/renameat.html +/// [Linux]: https://man7.org/linux/man-pages/man2/renameat.2.html +#[inline] +pub fn renameat<P: path::Arg, Q: path::Arg, PFd: AsFd, QFd: AsFd>( + old_dirfd: PFd, + old_path: P, + new_dirfd: QFd, + new_path: Q, +) -> io::Result<()> { + old_path.into_with_c_str(|old_path| { + new_path.into_with_c_str(|new_path| { + backend::fs::syscalls::renameat( + old_dirfd.as_fd(), + old_path, + new_dirfd.as_fd(), + new_path, + ) + }) + }) +} + +/// `renameat2(old_dirfd, old_path, new_dirfd, new_path, flags)`—Renames a +/// file or directory. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/renameat2.2.html +#[cfg(linux_kernel)] +#[inline] +#[doc(alias = "renameat2")] +pub fn renameat_with<P: path::Arg, Q: path::Arg, PFd: AsFd, QFd: AsFd>( + old_dirfd: PFd, + old_path: P, + new_dirfd: QFd, + new_path: Q, + flags: RenameFlags, +) -> io::Result<()> { + old_path.into_with_c_str(|old_path| { + new_path.into_with_c_str(|new_path| { + backend::fs::syscalls::renameat2( + old_dirfd.as_fd(), + old_path, + new_dirfd.as_fd(), + new_path, + flags, + ) + }) + }) +} + +/// `symlinkat(old_path, new_dirfd, new_path)`—Creates a symlink. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/symlinkat.html +/// [Linux]: https://man7.org/linux/man-pages/man2/symlinkat.2.html +#[inline] +pub fn symlinkat<P: path::Arg, Q: path::Arg, Fd: AsFd>( + old_path: P, + new_dirfd: Fd, + new_path: Q, +) -> io::Result<()> { + old_path.into_with_c_str(|old_path| { + new_path.into_with_c_str(|new_path| { + backend::fs::syscalls::symlinkat(old_path, new_dirfd.as_fd(), new_path) + }) + }) +} + +/// `fstatat(dirfd, path, flags)`—Queries metadata for a file or directory. +/// +/// [`Mode::from_raw_mode`] and [`FileType::from_raw_mode`] may be used to +/// interpret the `st_mode` field. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fstatat.html +/// [Linux]: https://man7.org/linux/man-pages/man2/fstatat.2.html +/// [`Mode::from_raw_mode`]: crate::fs::Mode::from_raw_mode +/// [`FileType::from_raw_mode`]: crate::fs::FileType::from_raw_mode +#[inline] +#[doc(alias = "fstatat")] +pub fn statat<P: path::Arg, Fd: AsFd>(dirfd: Fd, path: P, flags: AtFlags) -> io::Result<Stat> { + path.into_with_c_str(|path| backend::fs::syscalls::statat(dirfd.as_fd(), path, flags)) +} + +/// `faccessat(dirfd, path, access, flags)`—Tests permissions for a file or +/// directory. +/// +/// On Linux before 5.8, this function uses the `faccessat` system call which +/// doesn't support any flags. This function emulates support for the +/// [`AtFlags::EACCESS`] flag by checking whether the uid and gid of the +/// process match the effective uid and gid, in which case the `EACCESS` flag +/// can be ignored. In Linux 5.8 and beyond `faccessat2` is used, which +/// supports flags. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/faccessat.html +/// [Linux]: https://man7.org/linux/man-pages/man2/faccessat.2.html +#[inline] +#[doc(alias = "faccessat")] +pub fn accessat<P: path::Arg, Fd: AsFd>( + dirfd: Fd, + path: P, + access: Access, + flags: AtFlags, +) -> io::Result<()> { + path.into_with_c_str(|path| backend::fs::syscalls::accessat(dirfd.as_fd(), path, access, flags)) +} + +/// `utimensat(dirfd, path, times, flags)`—Sets file or directory timestamps. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimensat.html +/// [Linux]: https://man7.org/linux/man-pages/man2/utimensat.2.html +#[inline] +pub fn utimensat<P: path::Arg, Fd: AsFd>( + dirfd: Fd, + path: P, + times: &Timestamps, + flags: AtFlags, +) -> io::Result<()> { + path.into_with_c_str(|path| backend::fs::syscalls::utimensat(dirfd.as_fd(), path, times, flags)) +} + +/// `fchmodat(dirfd, path, mode, 0)`—Sets file or directory permissions. +/// +/// See `fchmodat_with` for a version that does take flags. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmodat.html +/// [Linux]: https://man7.org/linux/man-pages/man2/fchmodat.2.html +#[cfg(not(target_os = "wasi"))] +#[inline] +#[doc(alias = "fchmodat")] +pub fn chmodat<P: path::Arg, Fd: AsFd>(dirfd: Fd, path: P, mode: Mode) -> io::Result<()> { + chmodat_with(dirfd, path, mode, AtFlags::empty()) +} + +/// `fchmodat(dirfd, path, mode, flags)`—Sets file or directory permissions. +/// +/// Platform support for flags varies widely, for example on Linux +/// [`AtFlags::SYMLINK_NOFOLLOW`] is not implemented and therefore +/// [`io::Errno::OPNOTSUPP`] will be returned. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmodat.html +/// [Linux]: https://man7.org/linux/man-pages/man2/fchmodat.2.html +#[cfg(not(target_os = "wasi"))] +#[inline] +#[doc(alias = "fchmodat_with")] +pub fn chmodat_with<P: path::Arg, Fd: AsFd>( + dirfd: Fd, + path: P, + mode: Mode, + flags: AtFlags, +) -> io::Result<()> { + path.into_with_c_str(|path| backend::fs::syscalls::chmodat(dirfd.as_fd(), path, mode, flags)) +} + +/// `fclonefileat(src, dst_dir, dst, flags)`—Efficiently copies between files. +/// +/// # References +/// - [Apple] +/// +/// [Apple]: https://opensource.apple.com/source/xnu/xnu-3789.21.4/bsd/man/man2/clonefile.2.auto.html +#[cfg(apple)] +#[inline] +pub fn fclonefileat<Fd: AsFd, DstFd: AsFd, P: path::Arg>( + src: Fd, + dst_dir: DstFd, + dst: P, + flags: CloneFlags, +) -> io::Result<()> { + dst.into_with_c_str(|dst| { + backend::fs::syscalls::fclonefileat(src.as_fd(), dst_dir.as_fd(), dst, flags) + }) +} + +/// `mknodat(dirfd, path, mode, dev)`—Creates special or normal files. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/mknodat.html +/// [Linux]: https://man7.org/linux/man-pages/man2/mknodat.2.html +#[cfg(not(any(apple, target_os = "wasi")))] +#[inline] +pub fn mknodat<P: path::Arg, Fd: AsFd>( + dirfd: Fd, + path: P, + file_type: FileType, + mode: Mode, + dev: Dev, +) -> io::Result<()> { + path.into_with_c_str(|path| { + backend::fs::syscalls::mknodat(dirfd.as_fd(), path, file_type, mode, dev) + }) +} + +/// `fchownat(dirfd, path, owner, group, flags)`—Sets file or directory +/// ownership. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchownat.html +/// [Linux]: https://man7.org/linux/man-pages/man2/fchownat.2.html +#[cfg(not(target_os = "wasi"))] +#[inline] +#[doc(alias = "fchownat")] +pub fn chownat<P: path::Arg, Fd: AsFd>( + dirfd: Fd, + path: P, + owner: Option<Uid>, + group: Option<Gid>, + flags: AtFlags, +) -> io::Result<()> { + path.into_with_c_str(|path| { + backend::fs::syscalls::chownat(dirfd.as_fd(), path, owner, group, flags) + }) +} diff --git a/vendor/rustix-0.37.22/src/fs/constants.rs b/vendor/rustix-0.37.22/src/fs/constants.rs new file mode 100644 index 000000000..3e75879f1 --- /dev/null +++ b/vendor/rustix-0.37.22/src/fs/constants.rs @@ -0,0 +1,17 @@ +//! Filesystem API constants, translated into `bitflags` constants. + +use crate::backend; + +pub use crate::io::FdFlags; +pub use backend::fs::types::{Access, Dev, Mode, OFlags}; + +#[cfg(not(target_os = "redox"))] +pub use backend::fs::types::AtFlags; + +#[cfg(apple)] +pub use backend::fs::types::{CloneFlags, CopyfileFlags}; + +#[cfg(linux_kernel)] +pub use backend::fs::types::*; + +pub use backend::time::types::{Nsecs, Secs, Timespec}; diff --git a/vendor/rustix-0.37.22/src/fs/copy_file_range.rs b/vendor/rustix-0.37.22/src/fs/copy_file_range.rs new file mode 100644 index 000000000..b927d572b --- /dev/null +++ b/vendor/rustix-0.37.22/src/fs/copy_file_range.rs @@ -0,0 +1,20 @@ +use crate::{backend, io}; +use backend::fd::AsFd; + +/// `copy_file_range(fd_in, off_in, fd_out, off_out, len, 0)`—Copies data +/// from one file to another. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/copy_file_range.2.html +#[inline] +pub fn copy_file_range<InFd: AsFd, OutFd: AsFd>( + fd_in: InFd, + off_in: Option<&mut u64>, + fd_out: OutFd, + off_out: Option<&mut u64>, + len: usize, +) -> io::Result<usize> { + backend::fs::syscalls::copy_file_range(fd_in.as_fd(), off_in, fd_out.as_fd(), off_out, len) +} diff --git a/vendor/rustix-0.37.22/src/fs/cwd.rs b/vendor/rustix-0.37.22/src/fs/cwd.rs new file mode 100644 index 000000000..0abd75df6 --- /dev/null +++ b/vendor/rustix-0.37.22/src/fs/cwd.rs @@ -0,0 +1,32 @@ +//! The `cwd` function, representing the current working directory. +//! +//! # Safety +//! +//! This file uses `AT_FDCWD`, which is a raw file descriptor, but which is +//! always valid. + +#![allow(unsafe_code)] + +use crate::backend; +use backend::fd::{BorrowedFd, RawFd}; + +/// `AT_FDCWD`—Returns a handle representing the current working directory. +/// +/// This returns a file descriptor which refers to the process current +/// directory which can be used as the directory argument in `*at` +/// functions such as [`openat`]. +/// +/// # References +/// - [POSIX] +/// +/// [`openat`]: crate::fs::openat +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/fcntl.h.html +#[inline] +#[doc(alias = "AT_FDCWD")] +pub const fn cwd() -> BorrowedFd<'static> { + let at_fdcwd = backend::io::types::AT_FDCWD as RawFd; + + // SAFETY: `AT_FDCWD` is a reserved value that is never dynamically + // allocated, so it'll remain valid for the duration of `'static`. + unsafe { BorrowedFd::<'static>::borrow_raw(at_fdcwd) } +} diff --git a/vendor/rustix-0.37.22/src/fs/dir.rs b/vendor/rustix-0.37.22/src/fs/dir.rs new file mode 100644 index 000000000..b3e1e3b99 --- /dev/null +++ b/vendor/rustix-0.37.22/src/fs/dir.rs @@ -0,0 +1,5 @@ +//! `Dir` and `DirEntry`. + +use crate::backend; + +pub use backend::fs::dir::{Dir, DirEntry}; diff --git a/vendor/rustix-0.37.22/src/fs/fadvise.rs b/vendor/rustix-0.37.22/src/fs/fadvise.rs new file mode 100644 index 000000000..5bc3a588a --- /dev/null +++ b/vendor/rustix-0.37.22/src/fs/fadvise.rs @@ -0,0 +1,19 @@ +use crate::{backend, io}; +use backend::fd::AsFd; + +pub use backend::fs::types::Advice; + +/// `posix_fadvise(fd, offset, len, advice)`—Declares an expected access +/// pattern for a file. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_fadvise.html +/// [Linux]: https://man7.org/linux/man-pages/man2/posix_fadvise.2.html +#[inline] +#[doc(alias = "posix_fadvise")] +pub fn fadvise<Fd: AsFd>(fd: Fd, offset: u64, len: u64, advice: Advice) -> io::Result<()> { + backend::fs::syscalls::fadvise(fd.as_fd(), offset, len, advice) +} diff --git a/vendor/rustix-0.37.22/src/fs/fcntl.rs b/vendor/rustix-0.37.22/src/fs/fcntl.rs new file mode 100644 index 000000000..91816aaa2 --- /dev/null +++ b/vendor/rustix-0.37.22/src/fs/fcntl.rs @@ -0,0 +1,108 @@ +//! The Unix `fcntl` function is effectively lots of different functions +//! hidden behind a single dynamic dispatch interface. In order to provide +//! a type-safe API, rustix makes them all separate functions so that they +//! can have dedicated static type signatures. + +#[cfg(not(any( + target_os = "emscripten", + target_os = "fuchsia", + target_os = "redox", + target_os = "wasi" +)))] +use crate::fs::FlockOperation; +use crate::{backend, io}; +use backend::fd::AsFd; +use backend::fs::types::OFlags; + +// These `fcntl` functions like in the `io` module because they're not specific +// to files, directories, or memfd objects. We re-export them here in the `fs` +// module because the other the `fcntl` functions are here. +#[cfg(not(target_os = "wasi"))] +pub use crate::io::fcntl_dupfd_cloexec; +pub use crate::io::{fcntl_getfd, fcntl_setfd}; + +/// `fcntl(fd, F_GETFL)`—Returns a file descriptor's access mode and status. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fcntl.html +/// [Linux]: https://man7.org/linux/man-pages/man2/fcntl.2.html +#[inline] +#[doc(alias = "F_GETFL")] +pub fn fcntl_getfl<Fd: AsFd>(fd: Fd) -> io::Result<OFlags> { + backend::fs::syscalls::fcntl_getfl(fd.as_fd()) +} + +/// `fcntl(fd, F_SETFL, flags)`—Sets a file descriptor's status. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fcntl.html +/// [Linux]: https://man7.org/linux/man-pages/man2/fcntl.2.html +#[inline] +#[doc(alias = "F_SETFL")] +pub fn fcntl_setfl<Fd: AsFd>(fd: Fd, flags: OFlags) -> io::Result<()> { + backend::fs::syscalls::fcntl_setfl(fd.as_fd(), flags) +} + +/// `fcntl(fd, F_GET_SEALS)` +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/fcntl.2.html +#[cfg(any(linux_kernel, target_os = "freebsd", target_os = "fuchsia"))] +#[inline] +#[doc(alias = "F_GET_SEALS")] +pub fn fcntl_get_seals<Fd: AsFd>(fd: Fd) -> io::Result<SealFlags> { + backend::fs::syscalls::fcntl_get_seals(fd.as_fd()) +} + +#[cfg(any(linux_kernel, target_os = "freebsd", target_os = "fuchsia"))] +pub use backend::fs::types::SealFlags; + +/// `fcntl(fd, F_ADD_SEALS)` +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/fcntl.2.html +#[cfg(any(linux_kernel, target_os = "freebsd", target_os = "fuchsia"))] +#[inline] +#[doc(alias = "F_ADD_SEALS")] +pub fn fcntl_add_seals<Fd: AsFd>(fd: Fd, seals: SealFlags) -> io::Result<()> { + backend::fs::syscalls::fcntl_add_seals(fd.as_fd(), seals) +} + +/// `fcntl(fd, F_SETLK)`—Acquire or release an `fcntl`-style lock. +/// +/// This function doesn't currently have an offset or len; it currently always +/// sets the `l_len` field to 0, which is a special case that means the entire +/// file should be locked. +/// +/// Unlike `flock`-style locks, `fcntl`-style locks are process-associated, +/// meaning that they don't guard against being acquired by two threads in +/// the same process. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fcntl.html +/// [Linux]: https://man7.org/linux/man-pages/man2/fcntl.2.html +#[cfg(not(any( + target_os = "emscripten", + target_os = "fuchsia", + target_os = "redox", + target_os = "wasi" +)))] +#[inline] +#[doc(alias = "F_SETLK")] +#[doc(alias = "F_SETLKW")] +pub fn fcntl_lock<Fd: AsFd>(fd: Fd, operation: FlockOperation) -> io::Result<()> { + backend::fs::syscalls::fcntl_lock(fd.as_fd(), operation) +} diff --git a/vendor/rustix-0.37.22/src/fs/fcntl_apple.rs b/vendor/rustix-0.37.22/src/fs/fcntl_apple.rs new file mode 100644 index 000000000..6d624ee47 --- /dev/null +++ b/vendor/rustix-0.37.22/src/fs/fcntl_apple.rs @@ -0,0 +1,24 @@ +use crate::{backend, io}; +use backend::fd::AsFd; + +/// `fcntl(fd, F_RDADVISE, radvisory { offset, len })` +/// +/// # References +/// - [Apple] +/// +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fcntl.2.html +#[inline] +pub fn fcntl_rdadvise<Fd: AsFd>(fd: Fd, offset: u64, len: u64) -> io::Result<()> { + backend::fs::syscalls::fcntl_rdadvise(fd.as_fd(), offset, len) +} + +/// `fcntl(fd, F_FULLFSYNC)` +/// +/// # References +/// - [Apple] +/// +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fcntl.2.html +#[inline] +pub fn fcntl_fullfsync<Fd: AsFd>(fd: Fd) -> io::Result<()> { + backend::fs::syscalls::fcntl_fullfsync(fd.as_fd()) +} diff --git a/vendor/rustix-0.37.22/src/fs/fcopyfile.rs b/vendor/rustix-0.37.22/src/fs/fcopyfile.rs new file mode 100644 index 000000000..d8931733f --- /dev/null +++ b/vendor/rustix-0.37.22/src/fs/fcopyfile.rs @@ -0,0 +1,90 @@ +use crate::fs::CopyfileFlags; +use crate::{backend, io}; +use backend::fd::AsFd; + +/// `copyfile_state_t` +pub use backend::fs::types::copyfile_state_t; + +/// `fcopyfile(from, to, state, flags)` +/// +/// # Safety +/// +/// The `state` operand must be allocated with `copyfile_state_alloc` and not +/// yet freed with `copyfile_state_free`. +/// +/// # References +/// - [Apple] +/// +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/fcopyfile.3.html +#[inline] +pub unsafe fn fcopyfile<FromFd: AsFd, ToFd: AsFd>( + from: FromFd, + to: ToFd, + state: copyfile_state_t, + flags: CopyfileFlags, +) -> io::Result<()> { + backend::fs::syscalls::fcopyfile(from.as_fd(), to.as_fd(), state, flags) +} + +/// `copyfile_state_alloc()` +/// +/// # References +/// - [Apple] +/// +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/fcopyfile.3.html +#[inline] +pub fn copyfile_state_alloc() -> io::Result<copyfile_state_t> { + backend::fs::syscalls::copyfile_state_alloc() +} + +/// `copyfile_state_free(state)` +/// +/// # Safety +/// +/// The `state` operand must be allocated with `copyfile_state_alloc` and not +/// yet freed with `copyfile_state_free`. +/// +/// # References +/// - [Apple] +/// +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/fcopyfile.3.html +#[inline] +pub unsafe fn copyfile_state_free(state: copyfile_state_t) -> io::Result<()> { + backend::fs::syscalls::copyfile_state_free(state) +} + +/// `copyfile_state_get(state, COPYFILE_STATE_COPIED)` +/// +/// # Safety +/// +/// The `state` operand must be allocated with `copyfile_state_alloc` and not +/// yet freed with `copyfile_state_free`. +/// +/// # References +/// - [Apple] +/// +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/fcopyfile.3.html +#[inline] +pub unsafe fn copyfile_state_get_copied(state: copyfile_state_t) -> io::Result<u64> { + backend::fs::syscalls::copyfile_state_get_copied(state) +} + +/// `copyfile_state_get(state, flags, dst)` +/// +/// # Safety +/// +/// The `state` operand must be allocated with `copyfile_state_alloc` and not +/// yet freed with `copyfile_state_free`. +/// +/// # References +/// - [Apple] +/// +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/fcopyfile.3.html +#[inline] +pub unsafe fn copyfile_state_get( + state: copyfile_state_t, + flag: u32, + dst: *mut core::ffi::c_void, +) -> io::Result<()> { + backend::fs::syscalls::copyfile_state_get(state, flag, dst) +} diff --git a/vendor/rustix-0.37.22/src/fs/fd.rs b/vendor/rustix-0.37.22/src/fs/fd.rs new file mode 100644 index 000000000..743c1fafc --- /dev/null +++ b/vendor/rustix-0.37.22/src/fs/fd.rs @@ -0,0 +1,339 @@ +//! Functions which operate on file descriptors. + +#[cfg(not(target_os = "wasi"))] +use crate::fs::Mode; +use crate::fs::{OFlags, Timespec}; +use crate::io::SeekFrom; +#[cfg(not(target_os = "wasi"))] +use crate::process::{Gid, Uid}; +use crate::{backend, io}; +use backend::fd::{AsFd, BorrowedFd}; + +#[cfg(not(target_os = "wasi"))] +pub use backend::fs::types::FlockOperation; + +#[cfg(not(any( + netbsdlike, + solarish, + target_os = "aix", + target_os = "dragonfly", + target_os = "redox", +)))] +pub use backend::fs::types::FallocateFlags; + +pub use backend::fs::types::Stat; + +#[cfg(not(any( + solarish, + target_os = "haiku", + target_os = "netbsd", + target_os = "redox", + target_os = "wasi", +)))] +pub use backend::fs::types::StatFs; + +#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))] +pub use backend::fs::types::{StatVfs, StatVfsMountFlags}; + +#[cfg(linux_kernel)] +pub use backend::fs::types::FsWord; + +/// Timestamps used by [`utimensat`] and [`futimens`]. +/// +/// [`utimensat`]: crate::fs::utimensat +/// [`futimens`]: crate::fs::futimens +// This is `repr(C)` and specifically laid out to match the representation used +// by `utimensat` and `futimens`, which expect 2-element arrays of timestamps. +#[repr(C)] +#[derive(Clone, Debug)] +pub struct Timestamps { + /// The timestamp of the last access to a filesystem object. + pub last_access: Timespec, + + /// The timestamp of the last modification of a filesystem object. + pub last_modification: Timespec, +} + +/// The filesystem magic number for procfs. +/// +/// See [the `fstatfs` manual page] for more information. +/// +/// [the `fstatfs` manual page]: https://man7.org/linux/man-pages/man2/fstatfs.2.html#DESCRIPTION +#[cfg(linux_kernel)] +pub const PROC_SUPER_MAGIC: FsWord = backend::c::PROC_SUPER_MAGIC as FsWord; + +/// The filesystem magic number for NFS. +/// +/// See [the `fstatfs` manual page] for more information. +/// +/// [the `fstatfs` manual page]: https://man7.org/linux/man-pages/man2/fstatfs.2.html#DESCRIPTION +#[cfg(linux_kernel)] +pub const NFS_SUPER_MAGIC: FsWord = backend::c::NFS_SUPER_MAGIC as FsWord; + +/// `lseek(fd, offset, whence)`—Repositions a file descriptor within a file. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/lseek.html +/// [Linux]: https://man7.org/linux/man-pages/man2/lseek.2.html +#[inline] +#[doc(alias = "lseek")] +pub fn seek<Fd: AsFd>(fd: Fd, pos: SeekFrom) -> io::Result<u64> { + backend::fs::syscalls::seek(fd.as_fd(), pos) +} + +/// `lseek(fd, 0, SEEK_CUR)`—Returns the current position within a file. +/// +/// Return the current position of the file descriptor. This is a subset of +/// the functionality of `seek`, but this interface makes it easier for users +/// to declare their intent not to mutate any state. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/lseek.html +/// [Linux]: https://man7.org/linux/man-pages/man2/lseek.2.html +#[inline] +#[doc(alias = "lseek")] +pub fn tell<Fd: AsFd>(fd: Fd) -> io::Result<u64> { + backend::fs::syscalls::tell(fd.as_fd()) +} + +/// `fchmod(fd)`—Sets open file or directory permissions. +/// +/// This implementation does not support `O_PATH` file descriptors, even on +/// platforms where the host libc emulates it. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmod.html +/// [Linux]: https://man7.org/linux/man-pages/man2/fchmod.2.html +#[cfg(not(target_os = "wasi"))] +#[inline] +pub fn fchmod<Fd: AsFd>(fd: Fd, mode: Mode) -> io::Result<()> { + backend::fs::syscalls::fchmod(fd.as_fd(), mode) +} + +/// `fchown(fd)`—Sets open file or directory ownership. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchown.html +/// [Linux]: https://man7.org/linux/man-pages/man2/fchown.2.html +#[cfg(not(target_os = "wasi"))] +#[inline] +pub fn fchown<Fd: AsFd>(fd: Fd, owner: Option<Uid>, group: Option<Gid>) -> io::Result<()> { + backend::fs::syscalls::fchown(fd.as_fd(), owner, group) +} + +/// `fstat(fd)`—Queries metadata for an open file or directory. +/// +/// [`Mode::from_raw_mode`] and [`FileType::from_raw_mode`] may be used to +/// interpret the `st_mode` field. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fstat.html +/// [Linux]: https://man7.org/linux/man-pages/man2/fstat.2.html +/// [`Mode::from_raw_mode`]: Mode::from_raw_mode +/// [`FileType::from_raw_mode`]: crate::fs::FileType::from_raw_mode +#[inline] +pub fn fstat<Fd: AsFd>(fd: Fd) -> io::Result<Stat> { + backend::fs::syscalls::fstat(fd.as_fd()) +} + +/// `fstatfs(fd)`—Queries filesystem statistics for an open file or directory. +/// +/// Compared to [`fstatvfs`], this function often provides more information, +/// though it's less portable. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/fstatfs.2.html +#[cfg(not(any( + solarish, + target_os = "haiku", + target_os = "netbsd", + target_os = "redox", + target_os = "wasi", +)))] +#[inline] +pub fn fstatfs<Fd: AsFd>(fd: Fd) -> io::Result<StatFs> { + backend::fs::syscalls::fstatfs(fd.as_fd()) +} + +/// `fstatvfs(fd)`—Queries filesystem statistics for an open file or +/// directory, POSIX version. +/// +/// Compared to [`fstatfs`], this function often provides less information, +/// but it is more portable. But even so, filesystems are very diverse and not +/// all the fields are meaningful for every filesystem. And `f_fsid` doesn't +/// seem to have a clear meaning anywhere. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fstatvfs.html +/// [Linux]: https://man7.org/linux/man-pages/man2/fstatvfs.2.html +#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))] +#[inline] +pub fn fstatvfs<Fd: AsFd>(fd: Fd) -> io::Result<StatVfs> { + backend::fs::syscalls::fstatvfs(fd.as_fd()) +} + +/// `futimens(fd, times)`—Sets timestamps for an open file or directory. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html +/// [Linux]: https://man7.org/linux/man-pages/man2/utimensat.2.html +#[inline] +pub fn futimens<Fd: AsFd>(fd: Fd, times: &Timestamps) -> io::Result<()> { + backend::fs::syscalls::futimens(fd.as_fd(), times) +} + +/// `fallocate(fd, mode, offset, len)`—Adjusts file allocation. +/// +/// This is a more general form of `posix_fallocate`, adding a `mode` argument +/// which modifies the behavior. On platforms which only support +/// `posix_fallocate` and not the more general form, no `FallocateFlags` values +/// are defined so it will always be empty. +/// +/// # References +/// - [POSIX] +/// - [Linux `fallocate`] +/// - [Linux `posix_fallocate`] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_fallocate.html +/// [Linux `fallocate`]: https://man7.org/linux/man-pages/man2/fallocate.2.html +/// [Linux `posix_fallocate`]: https://man7.org/linux/man-pages/man3/posix_fallocate.3.html +#[cfg(not(any( + netbsdlike, + solarish, + target_os = "aix", + target_os = "dragonfly", + target_os = "redox", +)))] // not implemented in libc for netbsd yet +#[inline] +#[doc(alias = "posix_fallocate")] +pub fn fallocate<Fd: AsFd>(fd: Fd, mode: FallocateFlags, offset: u64, len: u64) -> io::Result<()> { + backend::fs::syscalls::fallocate(fd.as_fd(), mode, offset, len) +} + +/// `fcntl(fd, F_GETFL) & O_ACCMODE` +/// +/// Returns a pair of booleans indicating whether the file descriptor is +/// readable and/or writable, respectively. This is only reliable on files; for +/// example, it doesn't reflect whether sockets have been shut down; for +/// general I/O handle support, use [`io::is_read_write`]. +#[inline] +pub fn is_file_read_write<Fd: AsFd>(fd: Fd) -> io::Result<(bool, bool)> { + _is_file_read_write(fd.as_fd()) +} + +pub(crate) fn _is_file_read_write(fd: BorrowedFd<'_>) -> io::Result<(bool, bool)> { + let mode = backend::fs::syscalls::fcntl_getfl(fd)?; + + // Check for `O_PATH`. + #[cfg(any(linux_kernel, target_os = "fuchsia", target_os = "emscripten"))] + if mode.contains(OFlags::PATH) { + return Ok((false, false)); + } + + // Use `RWMODE` rather than `ACCMODE` as `ACCMODE` may include `O_PATH`. + // We handled `O_PATH` above. + match mode & OFlags::RWMODE { + OFlags::RDONLY => Ok((true, false)), + OFlags::RDWR => Ok((true, true)), + OFlags::WRONLY => Ok((false, true)), + _ => unreachable!(), + } +} + +/// `fsync(fd)`—Ensures that file data and metadata is written to the +/// underlying storage device. +/// +/// On iOS and macOS this isn't sufficient to ensure that data has reached +/// persistent storage; use [`fcntl_fullfsync`] to ensure that. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html +/// [Linux]: https://man7.org/linux/man-pages/man2/fsync.2.html +/// [`fcntl_fullfsync`]: https://docs.rs/rustix/*/x86_64-apple-darwin/rustix/fs/fn.fcntl_fullfsync.html +#[inline] +pub fn fsync<Fd: AsFd>(fd: Fd) -> io::Result<()> { + backend::fs::syscalls::fsync(fd.as_fd()) +} + +/// `fdatasync(fd)`—Ensures that file data is written to the underlying +/// storage device. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdatasync.html +/// [Linux]: https://man7.org/linux/man-pages/man2/fdatasync.2.html +#[cfg(not(any( + apple, + target_os = "dragonfly", + target_os = "haiku", + target_os = "redox", +)))] +#[inline] +pub fn fdatasync<Fd: AsFd>(fd: Fd) -> io::Result<()> { + backend::fs::syscalls::fdatasync(fd.as_fd()) +} + +/// `ftruncate(fd, length)`—Sets the length of a file. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html +/// [Linux]: https://man7.org/linux/man-pages/man2/ftruncate.2.html +#[inline] +pub fn ftruncate<Fd: AsFd>(fd: Fd, length: u64) -> io::Result<()> { + backend::fs::syscalls::ftruncate(fd.as_fd(), length) +} + +/// `flock(fd, operation)`—Acquire or release an advisory lock on an open file. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/flock.2.html +#[cfg(not(any(target_os = "solaris", target_os = "wasi")))] +#[inline] +pub fn flock<Fd: AsFd>(fd: Fd, operation: FlockOperation) -> io::Result<()> { + backend::fs::syscalls::flock(fd.as_fd(), operation) +} + +/// `syncfs(fd)`—Flush cached filesystem data. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/syncfs.2.html +#[cfg(linux_kernel)] +#[inline] +pub fn syncfs<Fd: AsFd>(fd: Fd) -> io::Result<()> { + backend::fs::syscalls::syncfs(fd.as_fd()) +} diff --git a/vendor/rustix-0.37.22/src/fs/file_type.rs b/vendor/rustix-0.37.22/src/fs/file_type.rs new file mode 100644 index 000000000..cf8fc1d38 --- /dev/null +++ b/vendor/rustix-0.37.22/src/fs/file_type.rs @@ -0,0 +1,4 @@ +use crate::backend; + +/// `S_IF*` constants. +pub use backend::fs::types::FileType; diff --git a/vendor/rustix-0.37.22/src/fs/getpath.rs b/vendor/rustix-0.37.22/src/fs/getpath.rs new file mode 100644 index 000000000..8e14ff2f2 --- /dev/null +++ b/vendor/rustix-0.37.22/src/fs/getpath.rs @@ -0,0 +1,14 @@ +use crate::ffi::CString; +use crate::{backend, io}; +use backend::fd::AsFd; + +/// `fcntl(fd, F_GETPATH)` +/// +/// # References +/// - [Apple] +/// +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fcntl.2.html +#[inline] +pub fn getpath<Fd: AsFd>(fd: Fd) -> io::Result<CString> { + backend::fs::syscalls::getpath(fd.as_fd()) +} diff --git a/vendor/rustix-0.37.22/src/fs/makedev.rs b/vendor/rustix-0.37.22/src/fs/makedev.rs new file mode 100644 index 000000000..5793058ff --- /dev/null +++ b/vendor/rustix-0.37.22/src/fs/makedev.rs @@ -0,0 +1,35 @@ +use crate::backend; +use crate::fs::Dev; + +/// `makedev(maj, min)` +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man3/makedev.3.html +#[inline] +pub fn makedev(maj: u32, min: u32) -> Dev { + backend::fs::makedev::makedev(maj, min) +} + +/// `minor(dev)` +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man3/minor.3.html +#[inline] +pub fn minor(dev: Dev) -> u32 { + backend::fs::makedev::minor(dev) +} + +/// `major(dev)` +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man3/major.3.html +#[inline] +pub fn major(dev: Dev) -> u32 { + backend::fs::makedev::major(dev) +} diff --git a/vendor/rustix-0.37.22/src/fs/memfd_create.rs b/vendor/rustix-0.37.22/src/fs/memfd_create.rs new file mode 100644 index 000000000..bbcbab258 --- /dev/null +++ b/vendor/rustix-0.37.22/src/fs/memfd_create.rs @@ -0,0 +1,19 @@ +use crate::fd::OwnedFd; +use crate::{backend, io, path}; + +pub use backend::fs::types::MemfdFlags; + +/// `memfd_create(path, flags)` +/// +/// # References +/// - [Linux] +/// - [glibc] +/// - [FreeBSD] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/memfd_create.2.html +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Memory_002dmapped-I_002fO.html#index-memfd_005fcreate +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?memfd_create +#[inline] +pub fn memfd_create<P: path::Arg>(path: P, flags: MemfdFlags) -> io::Result<OwnedFd> { + path.into_with_c_str(|path| backend::fs::syscalls::memfd_create(path, flags)) +} diff --git a/vendor/rustix-0.37.22/src/fs/mod.rs b/vendor/rustix-0.37.22/src/fs/mod.rs new file mode 100644 index 000000000..004bff06c --- /dev/null +++ b/vendor/rustix-0.37.22/src/fs/mod.rs @@ -0,0 +1,105 @@ +//! Filesystem operations. + +mod abs; +#[cfg(not(target_os = "redox"))] +mod at; +mod constants; +#[cfg(linux_kernel)] +mod copy_file_range; +#[cfg(not(target_os = "redox"))] +mod cwd; +#[cfg(not(target_os = "redox"))] +mod dir; +#[cfg(not(any( + apple, + netbsdlike, + solarish, + target_os = "dragonfly", + target_os = "haiku", + target_os = "redox", +)))] +mod fadvise; +pub(crate) mod fcntl; +#[cfg(apple)] +mod fcntl_apple; +#[cfg(apple)] +mod fcopyfile; +pub(crate) mod fd; +mod file_type; +#[cfg(apple)] +mod getpath; +#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))] +mod makedev; +#[cfg(any(linux_kernel, target_os = "freebsd"))] +mod memfd_create; +#[cfg(linux_kernel)] +mod mount; +#[cfg(linux_kernel)] +mod openat2; +#[cfg(linux_kernel)] +mod raw_dir; +#[cfg(target_os = "linux")] +mod sendfile; +#[cfg(linux_kernel)] +mod statx; +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +mod sync; +#[cfg(any(apple, linux_kernel))] +mod xattr; + +#[cfg(linux_kernel)] +pub use crate::backend::fs::inotify; +pub use abs::*; +#[cfg(not(target_os = "redox"))] +pub use at::*; +pub use constants::*; +#[cfg(linux_kernel)] +pub use copy_file_range::copy_file_range; +#[cfg(not(target_os = "redox"))] +pub use cwd::cwd; +#[cfg(not(target_os = "redox"))] +pub use dir::{Dir, DirEntry}; +#[cfg(not(any( + apple, + netbsdlike, + solarish, + target_os = "dragonfly", + target_os = "haiku", + target_os = "redox", +)))] +pub use fadvise::{fadvise, Advice}; +pub use fcntl::*; +#[cfg(apple)] +pub use fcntl_apple::{fcntl_fullfsync, fcntl_rdadvise}; +#[cfg(apple)] +pub use fcopyfile::*; +pub use fd::*; +pub use file_type::FileType; +#[cfg(apple)] +pub use getpath::getpath; +#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))] +pub use makedev::*; +#[cfg(any(linux_kernel, target_os = "freebsd"))] +pub use memfd_create::{memfd_create, MemfdFlags}; +#[cfg(linux_kernel)] +pub use mount::*; +#[cfg(linux_kernel)] +pub use openat2::openat2; +#[cfg(linux_kernel)] +pub use raw_dir::{RawDir, RawDirEntry}; +#[cfg(target_os = "linux")] +pub use sendfile::sendfile; +#[cfg(linux_kernel)] +pub use statx::{statx, Statx, StatxFlags, StatxTimestamp}; +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub use sync::sync; +#[cfg(any(apple, linux_kernel))] +pub use xattr::*; + +/// Re-export types common to POSIX-ish platforms. +#[cfg(feature = "std")] +#[cfg(unix)] +pub use std::os::unix::fs::{DirEntryExt, FileExt, FileTypeExt, MetadataExt, OpenOptionsExt}; +#[cfg(feature = "std")] +#[cfg(all(wasi_ext, target_os = "wasi"))] +pub use std::os::wasi::fs::{DirEntryExt, FileExt, FileTypeExt, MetadataExt, OpenOptionsExt}; diff --git a/vendor/rustix-0.37.22/src/fs/mount.rs b/vendor/rustix-0.37.22/src/fs/mount.rs new file mode 100644 index 000000000..1439b1f32 --- /dev/null +++ b/vendor/rustix-0.37.22/src/fs/mount.rs @@ -0,0 +1,166 @@ +//! Linux `mount`. + +use crate::backend::fs::types::{ + InternalMountFlags, MountFlags, MountFlagsArg, MountPropagationFlags, UnmountFlags, +}; +use crate::{backend, io, path}; + +/// `mount(source, target, filesystemtype, mountflags, data)` +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/mount.2.html +#[inline] +pub fn mount<Source: path::Arg, Target: path::Arg, Fs: path::Arg, Data: path::Arg>( + source: Source, + target: Target, + file_system_type: Fs, + flags: MountFlags, + data: Data, +) -> io::Result<()> { + source.into_with_c_str(|source| { + target.into_with_c_str(|target| { + file_system_type.into_with_c_str(|file_system_type| { + data.into_with_c_str(|data| { + backend::fs::syscalls::mount( + Some(source), + target, + Some(file_system_type), + MountFlagsArg(flags.bits()), + Some(data), + ) + }) + }) + }) + }) +} + +/// `mount(NULL, target, NULL, MS_REMOUNT | mountflags, data)` +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/mount.2.html +#[inline] +#[doc(alias = "mount")] +pub fn remount<Target: path::Arg, Data: path::Arg>( + target: Target, + flags: MountFlags, + data: Data, +) -> io::Result<()> { + target.into_with_c_str(|target| { + data.into_with_c_str(|data| { + backend::fs::syscalls::mount( + None, + target, + None, + MountFlagsArg(InternalMountFlags::REMOUNT.bits() | flags.bits()), + Some(data), + ) + }) + }) +} + +/// `mount(source, target, NULL, MS_BIND, NULL)` +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/mount.2.html +#[inline] +#[doc(alias = "mount")] +pub fn bind_mount<Source: path::Arg, Target: path::Arg>( + source: Source, + target: Target, +) -> io::Result<()> { + source.into_with_c_str(|source| { + target.into_with_c_str(|target| { + backend::fs::syscalls::mount( + Some(source), + target, + None, + MountFlagsArg(MountFlags::BIND.bits()), + None, + ) + }) + }) +} + +/// `mount(source, target, NULL, MS_BIND | MS_REC, NULL)` +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/mount.2.html +#[inline] +#[doc(alias = "mount")] +pub fn recursive_bind_mount<Source: path::Arg, Target: path::Arg>( + source: Source, + target: Target, +) -> io::Result<()> { + source.into_with_c_str(|source| { + target.into_with_c_str(|target| { + backend::fs::syscalls::mount( + Some(source), + target, + None, + MountFlagsArg(MountFlags::BIND.bits() | MountPropagationFlags::REC.bits()), + None, + ) + }) + }) +} + +/// `mount(NULL, target, NULL, mountflags, NULL)` +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/mount.2.html +#[inline] +#[doc(alias = "mount")] +pub fn change_mount<Target: path::Arg>( + target: Target, + flags: MountPropagationFlags, +) -> io::Result<()> { + target.into_with_c_str(|target| { + backend::fs::syscalls::mount(None, target, None, MountFlagsArg(flags.bits()), None) + }) +} + +/// `mount(source, target, NULL, MS_MOVE, NULL)` +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/mount.2.html +#[inline] +#[doc(alias = "mount")] +pub fn move_mount<Source: path::Arg, Target: path::Arg>( + source: Source, + target: Target, +) -> io::Result<()> { + source.into_with_c_str(|source| { + target.into_with_c_str(|target| { + backend::fs::syscalls::mount( + Some(source), + target, + None, + MountFlagsArg(InternalMountFlags::MOVE.bits()), + None, + ) + }) + }) +} + +/// `umount2(target, flags)` +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/umount.2.html +#[doc(alias = "umount", alias = "umount2")] +pub fn unmount<Target: path::Arg>(target: Target, flags: UnmountFlags) -> io::Result<()> { + target.into_with_c_str(|target| backend::fs::syscalls::unmount(target, flags)) +} diff --git a/vendor/rustix-0.37.22/src/fs/openat2.rs b/vendor/rustix-0.37.22/src/fs/openat2.rs new file mode 100644 index 000000000..4918e0034 --- /dev/null +++ b/vendor/rustix-0.37.22/src/fs/openat2.rs @@ -0,0 +1,23 @@ +use crate::fd::OwnedFd; +use crate::{backend, io, path}; +use backend::fd::AsFd; +use backend::fs::types::{Mode, OFlags, ResolveFlags}; + +/// `openat2(dirfd, path, OpenHow { oflags, mode, resolve }, sizeof(OpenHow))` +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/openat2.2.html +#[inline] +pub fn openat2<Fd: AsFd, P: path::Arg>( + dirfd: Fd, + path: P, + oflags: OFlags, + mode: Mode, + resolve: ResolveFlags, +) -> io::Result<OwnedFd> { + path.into_with_c_str(|path| { + backend::fs::syscalls::openat2(dirfd.as_fd(), path, oflags, mode, resolve) + }) +} diff --git a/vendor/rustix-0.37.22/src/fs/raw_dir.rs b/vendor/rustix-0.37.22/src/fs/raw_dir.rs new file mode 100644 index 000000000..fdf560215 --- /dev/null +++ b/vendor/rustix-0.37.22/src/fs/raw_dir.rs @@ -0,0 +1,235 @@ +//! `RawDir` and `RawDirEntry`. + +use core::fmt; +use core::mem::{align_of, MaybeUninit}; +use linux_raw_sys::general::linux_dirent64; + +use crate::backend::fs::syscalls::getdents_uninit; +use crate::fd::AsFd; +use crate::ffi::CStr; +use crate::fs::FileType; +use crate::io; + +/// A directory iterator implemented with getdents. +/// +/// Note: This implementation does not handle growing the buffer. If this +/// functionality is necessary, you'll need to drop the current iterator, +/// resize the buffer, and then re-create the iterator. The iterator is +/// guaranteed to continue where it left off provided the file descriptor isn't +/// changed. See the example in [`RawDir::new`]. +pub struct RawDir<'buf, Fd: AsFd> { + fd: Fd, + buf: &'buf mut [MaybeUninit<u8>], + initialized: usize, + offset: usize, +} + +impl<'buf, Fd: AsFd> RawDir<'buf, Fd> { + /// Create a new iterator from the given file descriptor and buffer. + /// + /// Note: the buffer size may be trimmed to accommodate alignment + /// requirements. + /// + /// # Examples + /// + /// ## Simple but non-portable + /// + /// These examples are non-portable, because file systems may not have a + /// maximum file name length. If you can make assumptions that bound + /// this length, then these examples may suffice. + /// + /// Using the heap: + /// + /// ```notrust + /// # // The `notrust` above can be removed when we can depend on Rust 1.60. + /// # use std::mem::MaybeUninit; + /// # use rustix::fs::{cwd, Mode, OFlags, openat, RawDir}; + /// + /// let fd = openat( + /// cwd(), + /// ".", + /// OFlags::RDONLY | OFlags::DIRECTORY | OFlags::CLOEXEC, + /// Mode::empty(), + /// ) + /// .unwrap(); + /// + /// let mut buf = Vec::with_capacity(8192); + /// let mut iter = RawDir::new(fd, buf.spare_capacity_mut()); + /// while let Some(entry) = iter.next() { + /// let entry = entry.unwrap(); + /// dbg!(&entry); + /// } + /// ``` + /// + /// Using the stack: + /// + /// ``` + /// # use std::mem::MaybeUninit; + /// # use rustix::fs::{cwd, Mode, OFlags, openat, RawDir}; + /// + /// let fd = openat( + /// cwd(), + /// ".", + /// OFlags::RDONLY | OFlags::DIRECTORY | OFlags::CLOEXEC, + /// Mode::empty(), + /// ) + /// .unwrap(); + /// + /// let mut buf = [MaybeUninit::uninit(); 2048]; + /// let mut iter = RawDir::new(fd, &mut buf); + /// while let Some(entry) = iter.next() { + /// let entry = entry.unwrap(); + /// dbg!(&entry); + /// } + /// ``` + /// + /// ## Portable + /// + /// Heap allocated growing buffer for supporting directory entries with + /// arbitrarily large file names: + /// + /// ```notrust + /// # // The `notrust` above can be removed when we can depend on Rust 1.60. + /// # use std::mem::MaybeUninit; + /// # use rustix::fs::{cwd, Mode, OFlags, openat, RawDir}; + /// # use rustix::io::Errno; + /// + /// let fd = openat( + /// cwd(), + /// ".", + /// OFlags::RDONLY | OFlags::DIRECTORY | OFlags::CLOEXEC, + /// Mode::empty(), + /// ) + /// .unwrap(); + /// + /// let mut buf = Vec::with_capacity(8192); + /// 'read: loop { + /// 'resize: { + /// let mut iter = RawDir::new(&fd, buf.spare_capacity_mut()); + /// while let Some(entry) = iter.next() { + /// let entry = match entry { + /// Err(Errno::INVAL) => break 'resize, + /// r => r.unwrap(), + /// }; + /// dbg!(&entry); + /// } + /// break 'read; + /// } + /// + /// let new_capacity = buf.capacity() * 2; + /// buf.reserve(new_capacity); + /// } + /// ``` + pub fn new(fd: Fd, buf: &'buf mut [MaybeUninit<u8>]) -> Self { + Self { + fd, + buf: { + let offset = buf.as_ptr().align_offset(align_of::<linux_dirent64>()); + if offset < buf.len() { + &mut buf[offset..] + } else { + &mut [] + } + }, + initialized: 0, + offset: 0, + } + } +} + +/// A raw directory entry, similar to `std::fs::DirEntry`. +/// +/// Unlike the std version, this may represent the `.` or `..` entries. +pub struct RawDirEntry<'a> { + file_name: &'a CStr, + file_type: u8, + inode_number: u64, + next_entry_cookie: i64, +} + +impl<'a> fmt::Debug for RawDirEntry<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut f = f.debug_struct("RawDirEntry"); + f.field("file_name", &self.file_name()); + f.field("file_type", &self.file_type()); + f.field("ino", &self.ino()); + f.field("next_entry_cookie", &self.next_entry_cookie()); + f.finish() + } +} + +impl<'a> RawDirEntry<'a> { + /// Returns the file name of this directory entry. + #[inline] + pub fn file_name(&self) -> &CStr { + self.file_name + } + + /// Returns the type of this directory entry. + #[inline] + pub fn file_type(&self) -> FileType { + FileType::from_dirent_d_type(self.file_type) + } + + /// Returns the inode number of this directory entry. + #[inline] + #[doc(alias = "inode_number")] + pub fn ino(&self) -> u64 { + self.inode_number + } + + /// Returns the seek cookie to the next directory entry. + #[inline] + #[doc(alias = "off")] + pub fn next_entry_cookie(&self) -> u64 { + self.next_entry_cookie as u64 + } +} + +impl<'buf, Fd: AsFd> RawDir<'buf, Fd> { + /// Identical to [`Iterator::next`] except that [`Iterator::Item`] borrows + /// from self. + /// + /// Note: this interface will be broken to implement a stdlib iterator API + /// with GAT support once one becomes available. + #[allow(unsafe_code)] + #[allow(clippy::should_implement_trait)] + pub fn next(&mut self) -> Option<io::Result<RawDirEntry>> { + if self.is_buffer_empty() { + match getdents_uninit(self.fd.as_fd(), self.buf) { + Ok(bytes_read) if bytes_read == 0 => return None, + Ok(bytes_read) => { + self.initialized = bytes_read; + self.offset = 0; + } + Err(e) => return Some(Err(e)), + } + } + + let dirent_ptr = self.buf[self.offset..].as_ptr(); + // SAFETY: + // - This data is initialized by the check above. + // - Assumption: the kernel will not give us partial structs. + // - Assumption: the kernel uses proper alignment between structs. + // - The starting pointer is aligned (performed in RawDir::new) + let dirent = unsafe { &*dirent_ptr.cast::<linux_dirent64>() }; + + self.offset += usize::from(dirent.d_reclen); + + Some(Ok(RawDirEntry { + file_type: dirent.d_type, + inode_number: dirent.d_ino.into(), + next_entry_cookie: dirent.d_off.into(), + // SAFETY: The kernel guarantees a NUL-terminated string. + file_name: unsafe { CStr::from_ptr(dirent.d_name.as_ptr().cast()) }, + })) + } + + /// Returns true if the internal buffer is empty and will be refilled when + /// calling [`next`]. + /// + /// [`next`]: Self::next + pub fn is_buffer_empty(&self) -> bool { + self.offset >= self.initialized + } +} diff --git a/vendor/rustix-0.37.22/src/fs/sendfile.rs b/vendor/rustix-0.37.22/src/fs/sendfile.rs new file mode 100644 index 000000000..7f5c8482d --- /dev/null +++ b/vendor/rustix-0.37.22/src/fs/sendfile.rs @@ -0,0 +1,19 @@ +use crate::{backend, io}; +use backend::fd::AsFd; + +/// `sendfile(out_fd, in_fd, offset, count)` +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/sendfile.2.html +#[cfg(linux_kernel)] +#[inline] +pub fn sendfile<OutFd: AsFd, InFd: AsFd>( + out_fd: OutFd, + in_fd: InFd, + offset: Option<&mut u64>, + count: usize, +) -> io::Result<usize> { + backend::fs::syscalls::sendfile(out_fd.as_fd(), in_fd.as_fd(), offset, count) +} diff --git a/vendor/rustix-0.37.22/src/fs/statx.rs b/vendor/rustix-0.37.22/src/fs/statx.rs new file mode 100644 index 000000000..32ae84ed3 --- /dev/null +++ b/vendor/rustix-0.37.22/src/fs/statx.rs @@ -0,0 +1,105 @@ +//! Linux `statx`. + +use crate::fd::AsFd; +use crate::fs::AtFlags; +use crate::{backend, io, path}; + +pub use backend::fs::types::{Statx, StatxFlags, StatxTimestamp}; + +#[cfg(feature = "linux_4_11")] +use backend::fs::syscalls::statx as _statx; +#[cfg(not(feature = "linux_4_11"))] +use compat::statx as _statx; + +/// `statx(dirfd, path, flags, mask, statxbuf)` +/// +/// This function returns [`io::Errno::NOSYS`] if `statx` is not available on +/// the platform, such as Linux before 4.11. This also includes older Docker +/// versions where the actual syscall fails with different error codes; rustix +/// handles this and translates them into `NOSYS`. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/statx.2.html +#[inline] +pub fn statx<P: path::Arg, Fd: AsFd>( + dirfd: Fd, + path: P, + flags: AtFlags, + mask: StatxFlags, +) -> io::Result<Statx> { + path.into_with_c_str(|path| _statx(dirfd.as_fd(), path, flags, mask)) +} + +#[cfg(not(feature = "linux_4_11"))] +mod compat { + use crate::fd::BorrowedFd; + use crate::ffi::CStr; + use crate::fs::AtFlags; + use crate::{backend, io}; + use core::sync::atomic::{AtomicU8, Ordering}; + + use backend::fs::types::{Statx, StatxFlags}; + + // Linux kernel prior to 4.11 old versions of Docker don't support `statx`. + // We store the availability in a global to avoid unnecessary syscalls. + // + // 0: Unknown + // 1: Not available + // 2: Available + static STATX_STATE: AtomicU8 = AtomicU8::new(0); + + #[inline] + pub fn statx( + dirfd: BorrowedFd<'_>, + path: &CStr, + flags: AtFlags, + mask: StatxFlags, + ) -> io::Result<Statx> { + match STATX_STATE.load(Ordering::Relaxed) { + 0 => statx_init(dirfd, path, flags, mask), + 1 => Err(io::Errno::NOSYS), + _ => backend::fs::syscalls::statx(dirfd, path, flags, mask), + } + } + + /// The first `statx` call. We don't know if `statx` is available yet. + fn statx_init( + dirfd: BorrowedFd<'_>, + path: &CStr, + flags: AtFlags, + mask: StatxFlags, + ) -> io::Result<Statx> { + match backend::fs::syscalls::statx(dirfd, path, flags, mask) { + Err(io::Errno::NOSYS) => statx_error_nosys(), + Err(io::Errno::PERM) => statx_error_perm(), + result => { + STATX_STATE.store(2, Ordering::Relaxed); + result + } + } + } + + /// The first `statx` call failed with `NOSYS` (or something we're treating + /// like `NOSYS`). + #[cold] + fn statx_error_nosys() -> io::Result<Statx> { + STATX_STATE.store(1, Ordering::Relaxed); + Err(io::Errno::NOSYS) + } + + /// The first `statx` call failed with `PERM`. + #[cold] + fn statx_error_perm() -> io::Result<Statx> { + // Some old versions of Docker have `statx` fail with `PERM` when it + // isn't recognized. Check whether `statx` really is available, and if + // so, fail with `PERM`, and if not, treat it like `NOSYS`. + if backend::fs::syscalls::is_statx_available() { + STATX_STATE.store(2, Ordering::Relaxed); + Err(io::Errno::PERM) + } else { + statx_error_nosys() + } + } +} diff --git a/vendor/rustix-0.37.22/src/fs/sync.rs b/vendor/rustix-0.37.22/src/fs/sync.rs new file mode 100644 index 000000000..3d2d08920 --- /dev/null +++ b/vendor/rustix-0.37.22/src/fs/sync.rs @@ -0,0 +1,14 @@ +use crate::backend; + +/// `sync`—Flush cached filesystem data for all filesystems. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sync.html +/// [Linux]: https://man7.org/linux/man-pages/man2/sync.2.html +#[inline] +pub fn sync() { + backend::fs::syscalls::sync(); +} diff --git a/vendor/rustix-0.37.22/src/fs/xattr.rs b/vendor/rustix-0.37.22/src/fs/xattr.rs new file mode 100644 index 000000000..e50841b49 --- /dev/null +++ b/vendor/rustix-0.37.22/src/fs/xattr.rs @@ -0,0 +1,197 @@ +use crate::{backend, io, path}; +use backend::c; +use backend::fd::AsFd; +use bitflags::bitflags; + +bitflags! { + /// `XATTR_*` constants for use with [`setxattr`], and other `*setxattr` + /// functions. + pub struct XattrFlags: c::c_uint { + /// `XATTR_CREATE` + const CREATE = c::XATTR_CREATE as c::c_uint; + + /// `XATTR_REPLACE` + const REPLACE = c::XATTR_REPLACE as c::c_uint; + } +} + +/// `getxattr(path, name, value.as_ptr(), value.len())`—Get extended +/// filesystem attributes. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/getxattr.2.html +#[inline] +pub fn getxattr<P: path::Arg, Name: path::Arg>( + path: P, + name: Name, + value: &mut [u8], +) -> io::Result<usize> { + path.into_with_c_str(|path| { + name.into_with_c_str(|name| backend::fs::syscalls::getxattr(path, name, value)) + }) +} + +/// `lgetxattr(path, name, value.as_ptr(), value.len())`—Get extended +/// filesystem attributes, without following symlinks in the last path +/// component. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/lgetxattr.2.html +#[inline] +pub fn lgetxattr<P: path::Arg, Name: path::Arg>( + path: P, + name: Name, + value: &mut [u8], +) -> io::Result<usize> { + path.into_with_c_str(|path| { + name.into_with_c_str(|name| backend::fs::syscalls::lgetxattr(path, name, value)) + }) +} + +/// `fgetxattr(fd, name, value.as_ptr(), value.len())`—Get extended +/// filesystem attributes on an open file descriptor. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/fgetxattr.2.html +#[inline] +pub fn fgetxattr<Fd: AsFd, Name: path::Arg>( + fd: Fd, + name: Name, + value: &mut [u8], +) -> io::Result<usize> { + name.into_with_c_str(|name| backend::fs::syscalls::fgetxattr(fd.as_fd(), name, value)) +} + +/// `setxattr(path, name, value.as_ptr(), value.len(), flags)`—Set extended +/// filesystem attributes. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/setxattr.2.html +#[inline] +pub fn setxattr<P: path::Arg, Name: path::Arg>( + path: P, + name: Name, + value: &[u8], + flags: XattrFlags, +) -> io::Result<()> { + path.into_with_c_str(|path| { + name.into_with_c_str(|name| backend::fs::syscalls::setxattr(path, name, value, flags)) + }) +} + +/// `setxattr(path, name, value.as_ptr(), value.len(), flags)`—Set extended +/// filesystem attributes, without following symlinks in the last path +/// component. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/lsetxattr.2.html +#[inline] +pub fn lsetxattr<P: path::Arg, Name: path::Arg>( + path: P, + name: Name, + value: &[u8], + flags: XattrFlags, +) -> io::Result<()> { + path.into_with_c_str(|path| { + name.into_with_c_str(|name| backend::fs::syscalls::lsetxattr(path, name, value, flags)) + }) +} + +/// `fsetxattr(fd, name, value.as_ptr(), value.len(), flags)`—Set extended +/// filesystem attributes on an open file descriptor. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/fsetxattr.2.html +#[inline] +pub fn fsetxattr<Fd: AsFd, Name: path::Arg>( + fd: Fd, + name: Name, + value: &[u8], + flags: XattrFlags, +) -> io::Result<()> { + name.into_with_c_str(|name| backend::fs::syscalls::fsetxattr(fd.as_fd(), name, value, flags)) +} + +/// `listxattr(path, list.as_ptr(), list.len())`—List extended filesystem +/// attributes. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/listxattr.2.html +#[inline] +pub fn listxattr<P: path::Arg>(path: P, list: &mut [c::c_char]) -> io::Result<usize> { + path.into_with_c_str(|path| backend::fs::syscalls::listxattr(path, list)) +} + +/// `llistxattr(path, list.as_ptr(), list.len())`—List extended filesystem +/// attributes, without following symlinks in the last path component. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/llistxattr.2.html +#[inline] +pub fn llistxattr<P: path::Arg>(path: P, list: &mut [c::c_char]) -> io::Result<usize> { + path.into_with_c_str(|path| backend::fs::syscalls::llistxattr(path, list)) +} + +/// `flistxattr(fd, list.as_ptr(), list.len())`—List extended filesystem +/// attributes on an open file descriptor. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/flistxattr.2.html +#[inline] +pub fn flistxattr<Fd: AsFd>(fd: Fd, list: &mut [c::c_char]) -> io::Result<usize> { + backend::fs::syscalls::flistxattr(fd.as_fd(), list) +} + +/// `removexattr(path, name)`—Remove an extended filesystem attribute. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/removexattr.2.html +pub fn removexattr<P: path::Arg, Name: path::Arg>(path: P, name: Name) -> io::Result<()> { + path.into_with_c_str(|path| { + name.into_with_c_str(|name| backend::fs::syscalls::removexattr(path, name)) + }) +} + +/// `lremovexattr(path, name)`—Remove an extended filesystem attribute, +/// without following symlinks in the last path component. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/lremovexattr.2.html +pub fn lremovexattr<P: path::Arg, Name: path::Arg>(path: P, name: Name) -> io::Result<()> { + path.into_with_c_str(|path| { + name.into_with_c_str(|name| backend::fs::syscalls::lremovexattr(path, name)) + }) +} + +/// `fremovexattr(fd, name)`—Remove an extended filesystem attribute on an +/// open file descriptor. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/fremovexattr.2.html +pub fn fremovexattr<Fd: AsFd, Name: path::Arg>(fd: Fd, name: Name) -> io::Result<()> { + name.into_with_c_str(|name| backend::fs::syscalls::fremovexattr(fd.as_fd(), name)) +} diff --git a/vendor/rustix-0.37.22/src/io/close.rs b/vendor/rustix-0.37.22/src/io/close.rs new file mode 100644 index 000000000..aad2c20a3 --- /dev/null +++ b/vendor/rustix-0.37.22/src/io/close.rs @@ -0,0 +1,55 @@ +//! The unsafe `close` for raw file descriptors. +//! +//! # Safety +//! +//! Operating on raw file descriptors is unsafe. +#![allow(unsafe_code)] + +use crate::backend; +use backend::fd::RawFd; + +/// `close(raw_fd)`—Closes a `RawFd` directly. +/// +/// Most users won't need to use this, as `OwnedFd` automatically closes its +/// file descriptor on `Drop`. +/// +/// This function does not return a `Result`, as it is the [responsibility] of +/// filesystem designers to not return errors from `close`. Users who chose to +/// use NFS or similar filesystems should take care to monitor for problems +/// externally. +/// +/// [responsibility]: https://lwn.net/Articles/576518/ +/// +/// # References +/// - [Beej's Guide to Network Programming] +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [Winsock2] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#close-and-shutdownget-outta-my-face +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html +/// [Linux]: https://man7.org/linux/man-pages/man2/close.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/close.2.html#//apple_ref/doc/man/2/close +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-closesocket +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=close&sektion=2 +/// [NetBSD]: https://man.netbsd.org/close.2 +/// [OpenBSD]: https://man.openbsd.org/close.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=close§ion=2 +/// [illumos]: https://illumos.org/man/2/close +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Opening-and-Closing-Files.html#index-close +/// +/// # Safety +/// +/// This function takes a `RawFd`, which must be valid before the call, and is +/// not valid after the call. +#[inline] +pub unsafe fn close(raw_fd: RawFd) { + backend::io::syscalls::close(raw_fd) +} diff --git a/vendor/rustix-0.37.22/src/io/dup.rs b/vendor/rustix-0.37.22/src/io/dup.rs new file mode 100644 index 000000000..0ac99f3f3 --- /dev/null +++ b/vendor/rustix-0.37.22/src/io/dup.rs @@ -0,0 +1,115 @@ +//! Functions which duplicate file descriptors. + +use crate::fd::OwnedFd; +use crate::{backend, io}; +use backend::fd::AsFd; + +#[cfg(not(target_os = "wasi"))] +pub use backend::io::types::DupFlags; + +/// `dup(fd)`—Creates a new `OwnedFd` instance that shares the same +/// underlying [file description] as `fd`. +/// +/// This function does not set the `O_CLOEXEC` flag. To do a `dup` that does +/// set `O_CLOEXEC`, use [`fcntl_dupfd_cloexec`]. +/// +/// POSIX guarantees that `dup` will use the lowest unused file descriptor, +/// however it is not safe in general to rely on this, as file descriptors may +/// be unexpectedly allocated on other threads or in libraries. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [file description]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_258 +/// [`fcntl_dupfd_cloexec`]: crate::io::fcntl_dupfd_cloexec +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html +/// [Linux]: https://man7.org/linux/man-pages/man2/dup.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/dup.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=dup&sektion=2 +/// [NetBSD]: https://man.netbsd.org/dup.2 +/// [OpenBSD]: https://man.openbsd.org/dup.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=dup§ion=2 +/// [illumos]: https://illumos.org/man/2/dup +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Duplicating-Descriptors.html +#[cfg(not(target_os = "wasi"))] +#[inline] +pub fn dup<Fd: AsFd>(fd: Fd) -> io::Result<OwnedFd> { + backend::io::syscalls::dup(fd.as_fd()) +} + +/// `dup2(fd, new)`—Changes the [file description] of a file descriptor. +/// +/// `dup2` conceptually closes `new` and then sets the file description for +/// `new` to be the same as the one for `fd`. This is a very unusual operation, +/// and should only be used on file descriptors where you know how `new` will +/// be subsequently used. +/// +/// This function does not set the `O_CLOEXEC` flag. To do a `dup2` that does +/// set `O_CLOEXEC`, use [`dup3`] with [`DupFlags::CLOEXEC`] on platforms which +/// support it, or [`fcntl_dupfd_cloexec`] +/// +/// For `dup2` to stdin, stdout, and stderr, see [`io::dup2_stdin`], +/// [`io::dup2_stdout`], and [`io::dup2_stderr`]. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [file description]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_258 +/// [`fcntl_dupfd_cloexec`]: crate::io::fcntl_dupfd_cloexec +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/dup2.html +/// [Linux]: https://man7.org/linux/man-pages/man2/dup2.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/dup2.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=dup2&sektion=2 +/// [NetBSD]: https://man.netbsd.org/dup2.2 +/// [OpenBSD]: https://man.openbsd.org/dup2.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=dup2§ion=2 +/// [illumos]: https://illumos.org/man/2/dup +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Duplicating-Descriptors.html +#[cfg(not(target_os = "wasi"))] +#[inline] +pub fn dup2<Fd: AsFd>(fd: Fd, new: &mut OwnedFd) -> io::Result<()> { + backend::io::syscalls::dup2(fd.as_fd(), new) +} + +/// `dup3(fd, new, flags)`—Changes the [file description] of a file +/// descriptor, with flags. +/// +/// `dup3` is the same as [`dup2`] but adds an additional flags operand, and it +/// fails in the case that `fd` and `new` have the same file descriptor value. +/// This additional difference is the reason this function isn't named +/// `dup2_with`. +/// +/// # References +/// - [Linux] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// +/// [file description]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_258 +/// [Linux]: https://man7.org/linux/man-pages/man2/dup3.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=dup3&sektion=3 +/// [NetBSD]: https://man.netbsd.org/dup3.2 +/// [OpenBSD]: https://man.openbsd.org/dup3.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=dup3§ion=3 +#[cfg(not(any(target_os = "aix", target_os = "wasi")))] +#[inline] +pub fn dup3<Fd: AsFd>(fd: Fd, new: &mut OwnedFd, flags: DupFlags) -> io::Result<()> { + backend::io::syscalls::dup3(fd.as_fd(), new, flags) +} diff --git a/vendor/rustix-0.37.22/src/io/errno.rs b/vendor/rustix-0.37.22/src/io/errno.rs new file mode 100644 index 000000000..7cb50f229 --- /dev/null +++ b/vendor/rustix-0.37.22/src/io/errno.rs @@ -0,0 +1,97 @@ +//! The `Errno` type, which is a minimal wrapper around an error code. +//! +//! We define the error constants as individual `const`s instead of an +//! enum because we may not know about all of the host's error values +//! and we don't want unrecognized values to create UB. + +use crate::backend; +use core::{fmt, result}; +#[cfg(feature = "std")] +use std::error; + +/// A specialized [`Result`] type for `rustix` APIs. +pub type Result<T> = result::Result<T, 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] +/// - [Winsock2] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/errno.html +/// [Linux]: https://man7.org/linux/man-pages/man3/errno.3.html +/// [Winsock2]: 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§ion=2 +/// [illumos]: https://illumos.org/man/3C/errno +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Error-Codes.html +pub use backend::io::errno::Errno; + +impl Errno { + /// Shorthand for `std::io::Error::from(self).kind()`. + #[cfg(feature = "std")] + #[inline] + pub fn kind(self) -> std::io::ErrorKind { + std::io::Error::from(self).kind() + } +} + +impl fmt::Display for Errno { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + #[cfg(feature = "std")] + { + std::io::Error::from(*self).fmt(fmt) + } + #[cfg(not(feature = "std"))] + { + write!(fmt, "os error {}", self.raw_os_error()) + } + } +} + +impl fmt::Debug for Errno { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + #[cfg(feature = "std")] + { + std::io::Error::from(*self).fmt(fmt) + } + #[cfg(not(feature = "std"))] + { + write!(fmt, "os error {}", self.raw_os_error()) + } + } +} + +#[cfg(feature = "std")] +impl error::Error for Errno {} + +#[cfg(feature = "std")] +impl From<Errno> for std::io::Error { + #[inline] + fn from(err: Errno) -> Self { + Self::from_raw_os_error(err.raw_os_error() as _) + } +} + +/// Call `f` until it either succeeds or fails other than [`Errno::INTR`]. +#[inline] +pub fn retry_on_intr<T, F: FnMut() -> Result<T>>(mut f: F) -> Result<T> { + loop { + match f() { + Err(Errno::INTR) => (), + result => return result, + } + } +} diff --git a/vendor/rustix-0.37.22/src/io/eventfd.rs b/vendor/rustix-0.37.22/src/io/eventfd.rs new file mode 100644 index 000000000..1f71c96b1 --- /dev/null +++ b/vendor/rustix-0.37.22/src/io/eventfd.rs @@ -0,0 +1,20 @@ +use crate::fd::OwnedFd; +use crate::{backend, io}; + +pub use backend::io::types::EventfdFlags; + +/// `eventfd(initval, flags)`—Creates a file descriptor for event +/// notification. +/// +/// # References +/// - [Linux] +/// - [FreeBSD] +/// - [illumos] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/eventfd.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?eventfd +/// [illumos]: https://illumos.org/man/3C/eventfd +#[inline] +pub fn eventfd(initval: u32, flags: EventfdFlags) -> io::Result<OwnedFd> { + backend::io::syscalls::eventfd(initval, flags) +} diff --git a/vendor/rustix-0.37.22/src/io/fcntl.rs b/vendor/rustix-0.37.22/src/io/fcntl.rs new file mode 100644 index 000000000..0454821ff --- /dev/null +++ b/vendor/rustix-0.37.22/src/io/fcntl.rs @@ -0,0 +1,141 @@ +//! The Unix `fcntl` function is effectively lots of different functions +//! hidden behind a single dynamic dispatch interface. In order to provide +//! a type-safe API, rustix makes them all separate functions so that they +//! can have dedicated static type signatures. +//! +//! `fcntl` functions which are not specific to files or directories live +//! in the [`io`] module instead. +//! +//! [`io`]: crate::io + +use crate::{backend, io}; +use backend::fd::{AsFd, OwnedFd, RawFd}; + +pub use backend::io::types::FdFlags; + +/// `fcntl(fd, F_GETFD)`—Returns a file descriptor's flags. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fcntl.html +/// [Linux]: https://man7.org/linux/man-pages/man2/fcntl.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fcntl.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=fcntl&sektion=2 +/// [NetBSD]: https://man.netbsd.org/fcntl.2 +/// [OpenBSD]: https://man.openbsd.org/fcntl.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=fcntl§ion=2 +/// [illumos]: https://illumos.org/man/2/fcntl +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Control-Operations.html#index-fcntl-function +#[inline] +#[doc(alias = "F_GETFD")] +pub fn fcntl_getfd<Fd: AsFd>(fd: Fd) -> io::Result<FdFlags> { + backend::io::syscalls::fcntl_getfd(fd.as_fd()) +} + +/// `fcntl(fd, F_SETFD, flags)`—Sets a file descriptor's flags. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fcntl.html +/// [Linux]: https://man7.org/linux/man-pages/man2/fcntl.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fcntl.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=fcntl&sektion=2 +/// [NetBSD]: https://man.netbsd.org/fcntl.2 +/// [OpenBSD]: https://man.openbsd.org/fcntl.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=fcntl§ion=2 +/// [illumos]: https://illumos.org/man/2/fcntl +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Control-Operations.html#index-fcntl-function +#[inline] +#[doc(alias = "F_SETFD")] +pub fn fcntl_setfd<Fd: AsFd>(fd: Fd, flags: FdFlags) -> io::Result<()> { + backend::io::syscalls::fcntl_setfd(fd.as_fd(), flags) +} + +/// `fcntl(fd, F_DUPFD_CLOEXEC)`—Creates a new `OwnedFd` instance, with value +/// at least `min`, that has `O_CLOEXEC` set and that shares the same +/// underlying [file description] as `fd`. +/// +/// POSIX guarantees that `F_DUPFD_CLOEXEC` will use the lowest unused file +/// descriptor which is at least `min`, however it is not safe in general to +/// rely on this, as file descriptors may be unexpectedly allocated on other +/// threads or in libraries. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fcntl.html +/// [Linux]: https://man7.org/linux/man-pages/man2/fcntl.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fcntl.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=fcntl&sektion=2 +/// [NetBSD]: https://man.netbsd.org/fcntl.2 +/// [OpenBSD]: https://man.openbsd.org/fcntl.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=fcntl§ion=2 +/// [illumos]: https://illumos.org/man/2/fcntl +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Control-Operations.html#index-fcntl-function +#[cfg(not(any(target_os = "wasi", target_os = "espidf")))] +#[inline] +#[doc(alias = "F_DUPFD_CLOEXEC")] +pub fn fcntl_dupfd_cloexec<Fd: AsFd>(fd: Fd, min: RawFd) -> io::Result<OwnedFd> { + backend::io::syscalls::fcntl_dupfd_cloexec(fd.as_fd(), min) +} + +/// `fcntl(fd, F_DUPFD)`—Creates a new `OwnedFd` instance, with value at least +/// `min`, that shares the same underlying [file description] as `fd`. +/// +/// POSIX guarantees that `F_DUPFD` will use the lowest unused file descriptor +/// which is at least `min`, however it is not safe in general to rely on this, +/// as file descriptors may be unexpectedly allocated on other threads or in +/// libraries. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fcntl.html +/// [Linux]: https://man7.org/linux/man-pages/man2/fcntl.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fcntl.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=fcntl&sektion=2 +/// [NetBSD]: https://man.netbsd.org/fcntl.2 +/// [OpenBSD]: https://man.openbsd.org/fcntl.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=fcntl§ion=2 +/// [illumos]: https://illumos.org/man/2/fcntl +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Control-Operations.html#index-fcntl-function +#[cfg(target_os = "espidf")] +#[inline] +#[doc(alias = "F_DUPFD")] +pub fn fcntl_dupfd<Fd: AsFd>(fd: Fd, min: RawFd) -> io::Result<OwnedFd> { + backend::io::syscalls::fcntl_dupfd(fd.as_fd(), min) +} diff --git a/vendor/rustix-0.37.22/src/io/fd/mod.rs b/vendor/rustix-0.37.22/src/io/fd/mod.rs new file mode 100644 index 000000000..0978b5421 --- /dev/null +++ b/vendor/rustix-0.37.22/src/io/fd/mod.rs @@ -0,0 +1,17 @@ +//! The following is derived from Rust's +//! library/std/src/os/fd/mod.rs at revision +//! fa68e73e9947be8ffc5b3b46d899e4953a44e7e9. +//! +//! Owned and borrowed Unix-like file descriptors. + +#![cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))] +#![deny(unsafe_op_in_unsafe_fn)] + +// `RawFd`, `AsRawFd`, etc. +mod raw; + +// `OwnedFd`, `AsFd`, etc. +mod owned; + +pub use owned::*; +pub use raw::*; diff --git a/vendor/rustix-0.37.22/src/io/fd/owned.rs b/vendor/rustix-0.37.22/src/io/fd/owned.rs new file mode 100644 index 000000000..2b9238ca7 --- /dev/null +++ b/vendor/rustix-0.37.22/src/io/fd/owned.rs @@ -0,0 +1,252 @@ +//! The following is derived from Rust's +//! library/std/src/os/fd/owned.rs at revision +//! fa68e73e9947be8ffc5b3b46d899e4953a44e7e9. +//! +//! Owned and borrowed Unix-like file descriptors. + +#![cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))] +#![deny(unsafe_op_in_unsafe_fn)] +#![allow(unsafe_code)] + +use super::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use crate::io::close; +use core::fmt; +use core::marker::PhantomData; +use core::mem::forget; + +/// A borrowed file descriptor. +/// +/// This has a lifetime parameter to tie it to the lifetime of something that +/// owns the file descriptor. +/// +/// This uses `repr(transparent)` and has the representation of a host file +/// descriptor, so it can be used in FFI in places where a file descriptor is +/// passed as an argument, it is not captured or consumed, and it never has the +/// value `-1`. +/// +/// This type's `.to_owned()` implementation returns another `BorrowedFd` +/// rather than an `OwnedFd`. It just makes a trivial copy of the raw file +/// descriptor, which is then borrowed under the same lifetime. +#[derive(Copy, Clone)] +#[repr(transparent)] +#[cfg_attr(rustc_attrs, rustc_layout_scalar_valid_range_start(0))] +// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a +// 32-bit c_int. Below is -2, in two's complement, but that only works out +// because c_int is 32 bits. +#[cfg_attr(rustc_attrs, rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE))] +#[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))] +#[cfg_attr(rustc_attrs, rustc_nonnull_optimization_guaranteed)] +pub struct BorrowedFd<'fd> { + fd: RawFd, + _phantom: PhantomData<&'fd OwnedFd>, +} + +/// An owned file descriptor. +/// +/// This closes the file descriptor on drop. +/// +/// This uses `repr(transparent)` and has the representation of a host file +/// descriptor, so it can be used in FFI in places where a file descriptor is +/// passed as a consumed argument or returned as an owned value, and it never +/// has the value `-1`. +#[repr(transparent)] +#[cfg_attr(rustc_attrs, rustc_layout_scalar_valid_range_start(0))] +// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a +// 32-bit c_int. Below is -2, in two's complement, but that only works out +// because c_int is 32 bits. +#[cfg_attr(rustc_attrs, rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE))] +#[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))] +#[cfg_attr(rustc_attrs, rustc_nonnull_optimization_guaranteed)] +pub struct OwnedFd { + fd: RawFd, +} + +impl BorrowedFd<'_> { + /// Return a `BorrowedFd` holding the given raw file descriptor. + /// + /// # Safety + /// + /// The resource pointed to by `fd` must remain open for the duration of + /// the returned `BorrowedFd`, and it must not have the value `-1`. + #[inline] + #[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))] + pub const unsafe fn borrow_raw(fd: RawFd) -> Self { + assert!(fd != u32::MAX as RawFd); + // SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) + #[allow(unused_unsafe)] + unsafe { + Self { + fd, + _phantom: PhantomData, + } + } + } +} + +impl OwnedFd { + /// Creates a new `OwnedFd` instance that shares the same underlying file handle + /// as the existing `OwnedFd` instance. + #[cfg(not(target_arch = "wasm32"))] + pub fn try_clone(&self) -> crate::io::Result<Self> { + // We want to atomically duplicate this file descriptor and set the + // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This + // is a POSIX flag that was added to Linux in 2.6.24. + #[cfg(not(target_os = "espidf"))] + let fd = crate::io::fcntl_dupfd_cloexec(self, 0)?; + + // For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics + // will never be supported, as this is a bare metal framework with + // no capabilities for multi-process execution. While F_DUPFD is also + // not supported yet, it might be (currently it returns ENOSYS). + #[cfg(target_os = "espidf")] + let fd = crate::io::fcntl_dupfd(self)?; + + Ok(fd.into()) + } + + #[cfg(target_arch = "wasm32")] + pub fn try_clone(&self) -> crate::io::Result<Self> { + Err(crate::io::const_io_error!( + crate::io::ErrorKind::Unsupported, + "operation not supported on WASI yet", + )) + } +} + +#[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))] +impl AsRawFd for BorrowedFd<'_> { + #[inline] + fn as_raw_fd(&self) -> RawFd { + self.fd + } +} + +#[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))] +impl AsRawFd for OwnedFd { + #[inline] + fn as_raw_fd(&self) -> RawFd { + self.fd + } +} + +#[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))] +impl IntoRawFd for OwnedFd { + #[inline] + fn into_raw_fd(self) -> RawFd { + let fd = self.fd; + forget(self); + fd + } +} + +#[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))] +impl FromRawFd for OwnedFd { + /// Constructs a new instance of `Self` from the given raw file descriptor. + /// + /// # Safety + /// + /// The resource pointed to by `fd` must be open and suitable for assuming + /// ownership. The resource must not require any cleanup other than `close`. + #[inline] + unsafe fn from_raw_fd(fd: RawFd) -> Self { + assert_ne!(fd, u32::MAX as RawFd); + // SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) + #[allow(unused_unsafe)] + unsafe { + Self { fd } + } + } +} + +#[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))] +impl Drop for OwnedFd { + #[inline] + fn drop(&mut self) { + unsafe { + // Errors are ignored when closing a file descriptor. The reason + // for this is that if an error occurs we don't actually know if + // the file descriptor was closed or not, and if we retried (for + // something like EINTR), we might close another valid file + // descriptor opened after we closed ours. + close(self.fd as _); + } + } +} + +#[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))] +impl fmt::Debug for BorrowedFd<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("BorrowedFd").field("fd", &self.fd).finish() + } +} + +#[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))] +impl fmt::Debug for OwnedFd { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OwnedFd").field("fd", &self.fd).finish() + } +} + +/// A trait to borrow the file descriptor from an underlying object. +/// +/// This is only available on unix platforms and must be imported in order to +/// call the method. Windows platforms have a corresponding `AsHandle` and +/// `AsSocket` set of traits. +#[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))] +pub trait AsFd { + /// Borrows the file descriptor. + /// + /// # Example + /// + /// ```no_run + /// # #![feature(io_safety)] + /// use std::fs::File; + /// # use std::io; + /// # #[cfg(target_os = "wasi")] + /// # use std::os::wasi::io::{AsFd, BorrowedFd}; + /// # #[cfg(unix)] + /// # use std::os::unix::io::{AsFd, BorrowedFd}; + /// + /// let mut f = File::open("foo.txt")?; + /// # #[cfg(any(unix, target_os = "wasi"))] + /// let borrowed_fd: BorrowedFd<'_> = f.as_fd(); + /// # Ok::<(), io::Error>(()) + /// ``` + #[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))] + fn as_fd(&self) -> BorrowedFd<'_>; +} + +#[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))] +impl<T: AsFd> AsFd for &T { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + T::as_fd(self) + } +} + +#[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))] +impl<T: AsFd> AsFd for &mut T { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + T::as_fd(self) + } +} + +#[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))] +impl AsFd for BorrowedFd<'_> { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + *self + } +} + +#[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))] +impl AsFd for OwnedFd { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + // SAFETY: `OwnedFd` and `BorrowedFd` have the same validity + // invariants, and the `BorrowedFd` is bounded by the lifetime + // of `&self`. + unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) } + } +} diff --git a/vendor/rustix-0.37.22/src/io/fd/raw.rs b/vendor/rustix-0.37.22/src/io/fd/raw.rs new file mode 100644 index 000000000..a522c9794 --- /dev/null +++ b/vendor/rustix-0.37.22/src/io/fd/raw.rs @@ -0,0 +1,159 @@ +//! The following is derived from Rust's +//! library/std/src/os/fd/raw.rs at revision +//! fa68e73e9947be8ffc5b3b46d899e4953a44e7e9. +//! +//! Raw Unix-like file descriptors. + +#![cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] +#![allow(unsafe_code)] + +use crate::backend::c; + +/// Raw file descriptors. +#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] +pub type RawFd = c::c_int; + +/// A trait to extract the raw file descriptor from an underlying object. +/// +/// This is only available on unix and WASI platforms and must be imported in +/// order to call the method. Windows platforms have a corresponding +/// `AsRawHandle` and `AsRawSocket` set of traits. +#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] +pub trait AsRawFd { + /// Extracts the raw file descriptor. + /// + /// This function is typically used to **borrow** an owned file descriptor. + /// When used in this way, this method does **not** pass ownership of the + /// raw file descriptor to the caller, and the file descriptor is only + /// guaranteed to be valid while the original object has not yet been + /// destroyed. + /// + /// However, borrowing is not strictly required. See [`AsFd::as_fd`] + /// for an API which strictly borrows a file descriptor. + /// + /// # Example + /// + /// ```no_run + /// use std::fs::File; + /// # use std::io; + /// #[cfg(unix)] + /// use std::os::unix::io::{AsRawFd, RawFd}; + /// #[cfg(target_os = "wasi")] + /// use std::os::wasi::io::{AsRawFd, RawFd}; + /// + /// let mut f = File::open("foo.txt")?; + /// // `raw_fd` is only valid as long as `f` exists. + /// #[cfg(any(unix, target_os = "wasi"))] + /// let raw_fd: RawFd = f.as_raw_fd(); + /// # Ok::<(), io::Error>(()) + /// ``` + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + fn as_raw_fd(&self) -> RawFd; +} + +/// A trait to express the ability to construct an object from a raw file +/// descriptor. +#[cfg_attr(staged_api, stable(feature = "from_raw_os", since = "1.1.0"))] +pub trait FromRawFd { + /// Constructs a new instance of `Self` from the given raw file + /// descriptor. + /// + /// This function is typically used to **consume ownership** of the + /// specified file descriptor. When used in this way, the returned object + /// will take responsibility for closing it when the object goes out of + /// scope. + /// + /// However, consuming ownership is not strictly required. Use a + /// [`From<OwnedFd>::from`] implementation for an API which strictly + /// consumes ownership. + /// + /// # Safety + /// + /// The `fd` passed in must be a valid an open file descriptor. + /// + /// # Example + /// + /// ```no_run + /// use std::fs::File; + /// # use std::io; + /// #[cfg(unix)] + /// use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd}; + /// #[cfg(target_os = "wasi")] + /// use std::os::wasi::io::{FromRawFd, IntoRawFd, RawFd}; + /// + /// let f = File::open("foo.txt")?; + /// # #[cfg(any(unix, target_os = "wasi"))] + /// let raw_fd: RawFd = f.into_raw_fd(); + /// // SAFETY: no other functions should call `from_raw_fd`, so there + /// // is only one owner for the file descriptor. + /// # #[cfg(any(unix, target_os = "wasi"))] + /// let f = unsafe { File::from_raw_fd(raw_fd) }; + /// # Ok::<(), io::Error>(()) + /// ``` + #[cfg_attr(staged_api, stable(feature = "from_raw_os", since = "1.1.0"))] + unsafe fn from_raw_fd(fd: RawFd) -> Self; +} + +/// A trait to express the ability to consume an object and acquire ownership of +/// its raw file descriptor. +#[cfg_attr(staged_api, stable(feature = "into_raw_os", since = "1.4.0"))] +pub trait IntoRawFd { + /// Consumes this object, returning the raw underlying file descriptor. + /// + /// This function is typically used to **transfer ownership** of the underlying + /// file descriptor to the caller. When used in this way, callers are then the unique + /// owners of the file descriptor and must close it once it's no longer needed. + /// + /// However, transferring ownership is not strictly required. Use a + /// [`Into<OwnedFd>::into`] implementation for an API which strictly + /// transfers ownership. + /// + /// # Example + /// + /// ```no_run + /// use std::fs::File; + /// # use std::io; + /// #[cfg(unix)] + /// use std::os::unix::io::{IntoRawFd, RawFd}; + /// #[cfg(target_os = "wasi")] + /// use std::os::wasi::io::{IntoRawFd, RawFd}; + /// + /// let f = File::open("foo.txt")?; + /// #[cfg(any(unix, target_os = "wasi"))] + /// let raw_fd: RawFd = f.into_raw_fd(); + /// # Ok::<(), io::Error>(()) + /// ``` + #[cfg_attr(staged_api, stable(feature = "into_raw_os", since = "1.4.0"))] + fn into_raw_fd(self) -> RawFd; +} + +#[cfg_attr( + staged_api, + stable(feature = "raw_fd_reflexive_traits", since = "1.48.0") +)] +impl AsRawFd for RawFd { + #[inline] + fn as_raw_fd(&self) -> RawFd { + *self + } +} +#[cfg_attr( + staged_api, + stable(feature = "raw_fd_reflexive_traits", since = "1.48.0") +)] +impl IntoRawFd for RawFd { + #[inline] + fn into_raw_fd(self) -> RawFd { + self + } +} +#[cfg_attr( + staged_api, + stable(feature = "raw_fd_reflexive_traits", since = "1.48.0") +)] +impl FromRawFd for RawFd { + #[inline] + unsafe fn from_raw_fd(fd: RawFd) -> RawFd { + fd + } +} diff --git a/vendor/rustix-0.37.22/src/io/ioctl.rs b/vendor/rustix-0.37.22/src/io/ioctl.rs new file mode 100644 index 000000000..73e955161 --- /dev/null +++ b/vendor/rustix-0.37.22/src/io/ioctl.rs @@ -0,0 +1,148 @@ +//! The Unix `ioctl` function is effectively lots of different functions +//! hidden behind a single dynamic dispatch interface. In order to provide +//! a type-safe API, rustix makes them all separate functions so that they +//! can have dedicated static type signatures. + +use crate::{backend, io}; +use backend::fd::AsFd; + +/// `ioctl(fd, TIOCEXCL)`—Enables exclusive mode on a terminal. +/// +/// # References +/// - [Linux] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// +/// [Linux]: https://man7.org/linux/man-pages/man4/tty_ioctl.4.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=tty&sektion=4 +/// [NetBSD]: https://man.netbsd.org/tty.4 +/// [OpenBSD]: https://man.openbsd.org/tty.4 +#[cfg(not(any(windows, target_os = "haiku", target_os = "redox", target_os = "wasi")))] +#[inline] +#[doc(alias = "TIOCEXCL")] +pub fn ioctl_tiocexcl<Fd: AsFd>(fd: Fd) -> io::Result<()> { + backend::io::syscalls::ioctl_tiocexcl(fd.as_fd()) +} + +/// `ioctl(fd, TIOCNXCL)`—Disables exclusive mode on a terminal. +/// +/// # References +/// - [Linux] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// +/// [Linux]: https://man7.org/linux/man-pages/man4/tty_ioctl.4.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=tty&sektion=4 +/// [NetBSD]: https://man.netbsd.org/tty.4 +/// [OpenBSD]: https://man.openbsd.org/tty.4 +#[cfg(not(any(windows, target_os = "haiku", target_os = "redox", target_os = "wasi")))] +#[inline] +#[doc(alias = "TIOCNXCL")] +pub fn ioctl_tiocnxcl<Fd: AsFd>(fd: Fd) -> io::Result<()> { + backend::io::syscalls::ioctl_tiocnxcl(fd.as_fd()) +} + +/// `ioctl(fd, FIOCLEX, NULL)`—Set the close-on-exec flag. +/// +/// Also known as `fcntl(fd, F_SETFD, FD_CLOEXEC)`. +/// +/// # References +/// - [Winsock2] +/// - [NetBSD] +/// - [OpenBSD] +/// +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-ioctlsocket +/// [NetBSD]: https://man.netbsd.org/ioctl.2#GENERIC%20IOCTLS +/// [OpenBSD]: https://man.openbsd.org/ioctl.2#GENERIC_IOCTLS +#[cfg(apple)] +#[inline] +#[doc(alias = "FIOCLEX")] +#[doc(alias = "FD_CLOEXEC")] +pub fn ioctl_fioclex<Fd: AsFd>(fd: Fd) -> io::Result<()> { + backend::io::syscalls::ioctl_fioclex(fd.as_fd()) +} + +/// `ioctl(fd, FIONBIO, &value)`—Enables or disables non-blocking mode. +/// +/// # References +/// - [Winsock2] +/// - [NetBSD] +/// - [OpenBSD] +/// +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/winsock/winsock-ioctls#unix-ioctl-codes +/// [NetBSD]: https://man.netbsd.org/ioctl.2#GENERIC%20IOCTLS +/// [OpenBSD]: https://man.openbsd.org/ioctl.2#GENERIC_IOCTLS +#[inline] +#[doc(alias = "FIONBIO")] +pub fn ioctl_fionbio<Fd: AsFd>(fd: Fd, value: bool) -> io::Result<()> { + backend::io::syscalls::ioctl_fionbio(fd.as_fd(), value) +} + +/// `ioctl(fd, FIONREAD)`—Returns the number of bytes ready to be read. +/// +/// The result of this function gets silently coerced into a C `int` +/// by the OS, so it may contain a wrapped value. +/// +/// # References +/// - [Linux] +/// - [Winsock2] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/ioctl_tty.2.html +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/winsock/winsock-ioctls#unix-ioctl-codes +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=ioctl&sektion=2#GENERIC%09IOCTLS +/// [NetBSD]: https://man.netbsd.org/ioctl.2#GENERIC%20IOCTLS +/// [OpenBSD]: https://man.openbsd.org/ioctl.2#GENERIC_IOCTLS +#[cfg(not(target_os = "redox"))] +#[inline] +#[doc(alias = "FIONREAD")] +pub fn ioctl_fionread<Fd: AsFd>(fd: Fd) -> io::Result<u64> { + backend::io::syscalls::ioctl_fionread(fd.as_fd()) +} + +/// `ioctl(fd, BLKSSZGET)`—Returns the logical block size of a block device. +/// +/// This is mentioned in the [Linux `openat` manual page]. +/// +/// [Linux `openat` manual page]: https://man7.org/linux/man-pages/man2/openat.2.html +#[cfg(linux_kernel)] +#[inline] +#[doc(alias = "BLKSSZGET")] +pub fn ioctl_blksszget<Fd: AsFd>(fd: Fd) -> io::Result<u32> { + backend::io::syscalls::ioctl_blksszget(fd.as_fd()) +} + +/// `ioctl(fd, BLKPBSZGET)`—Returns the physical block size of a block device. +#[cfg(linux_kernel)] +#[inline] +#[doc(alias = "BLKPBSZGET")] +pub fn ioctl_blkpbszget<Fd: AsFd>(fd: Fd) -> io::Result<u32> { + backend::io::syscalls::ioctl_blkpbszget(fd.as_fd()) +} + +/// `ioctl(fd, FICLONE, src_fd)`—Share data between open files. +/// +/// This ioctl is not available on Sparc platforms +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/ioctl_ficlone.2.html +#[cfg(all(linux_kernel, not(any(target_arch = "sparc", target_arch = "sparc64"))))] +#[inline] +#[doc(alias = "FICLONE")] +pub fn ioctl_ficlone<Fd: AsFd, SrcFd: AsFd>(fd: Fd, src_fd: SrcFd) -> io::Result<()> { + backend::io::syscalls::ioctl_ficlone(fd.as_fd(), src_fd.as_fd()) +} + +/// `ioctl(fd, EXT4_IOC_RESIZE_FS, blocks)`—Resize ext4 filesystem on fd. +#[cfg(linux_kernel)] +#[inline] +#[doc(alias = "EXT4_IOC_RESIZE_FS")] +pub fn ext4_ioc_resize_fs<Fd: AsFd>(fd: Fd, blocks: u64) -> io::Result<()> { + backend::io::syscalls::ext4_ioc_resize_fs(fd.as_fd(), blocks) +} diff --git a/vendor/rustix-0.37.22/src/io/is_read_write.rs b/vendor/rustix-0.37.22/src/io/is_read_write.rs new file mode 100644 index 000000000..af33806cb --- /dev/null +++ b/vendor/rustix-0.37.22/src/io/is_read_write.rs @@ -0,0 +1,19 @@ +//! The [`is_read_write`] function. +//! +//! [`is_read_write`]: https://docs.rs/rustix/*/rustix/io/fn.is_read_write.html + +use crate::{backend, io}; +use backend::fd::AsFd; + +/// Returns a pair of booleans indicating whether the file descriptor is +/// readable and/or writable, respectively. +/// +/// Unlike [`is_file_read_write`], this correctly detects whether sockets +/// have been shutdown, partially or completely. +/// +/// [`is_file_read_write`]: crate::fs::is_file_read_write +#[inline] +#[cfg_attr(doc_cfg, doc(cfg(all(feature = "fs", feature = "net"))))] +pub fn is_read_write<Fd: AsFd>(fd: Fd) -> io::Result<(bool, bool)> { + backend::io::syscalls::is_read_write(fd.as_fd()) +} diff --git a/vendor/rustix-0.37.22/src/io/kqueue.rs b/vendor/rustix-0.37.22/src/io/kqueue.rs new file mode 100644 index 000000000..d6ff60933 --- /dev/null +++ b/vendor/rustix-0.37.22/src/io/kqueue.rs @@ -0,0 +1,430 @@ +//! An API for interfacing with `kqueue`. + +use crate::fd::{AsFd, AsRawFd, OwnedFd, RawFd}; +#[cfg(feature = "process")] +use crate::process::{Pid, Signal}; +use crate::{backend, io}; + +use backend::c::{self, intptr_t, kevent as kevent_t, uintptr_t}; +use backend::io::syscalls; + +use alloc::vec::Vec; +use core::mem::zeroed; +use core::ptr::slice_from_raw_parts_mut; +use core::time::Duration; + +/// A `kqueue` event. +#[repr(transparent)] +#[derive(Copy, Clone)] +pub struct Event { + // The layout varies between BSDs and macOS. + inner: kevent_t, +} + +impl Event { + /// Create a new `Event`. + #[allow(clippy::needless_update)] + pub fn new(filter: EventFilter, flags: EventFlags, udata: isize) -> Event { + let (ident, data, filter, fflags) = match filter { + EventFilter::Read(fd) => (fd.as_raw_fd() as uintptr_t, 0, c::EVFILT_READ, 0), + EventFilter::Write(fd) => (fd.as_raw_fd() as _, 0, c::EVFILT_WRITE, 0), + #[cfg(target_os = "freebsd")] + EventFilter::Empty(fd) => (fd.as_raw_fd() as _, 0, c::EVFILT_EMPTY, 0), + EventFilter::Vnode { vnode, flags } => { + (vnode.as_raw_fd() as _, 0, c::EVFILT_VNODE, flags.bits()) + } + #[cfg(feature = "process")] + EventFilter::Proc { pid, flags } => { + (Pid::as_raw(Some(pid)) as _, 0, c::EVFILT_PROC, flags.bits()) + } + #[cfg(feature = "process")] + EventFilter::Signal { signal, times: _ } => (signal as _, 0, c::EVFILT_SIGNAL, 0), + EventFilter::Timer { ident, timer } => { + #[cfg(any(apple, target_os = "freebsd", target_os = "netbsd"))] + let (data, fflags) = match timer { + Some(timer) => { + if timer.subsec_millis() == 0 { + (timer.as_secs() as _, c::NOTE_SECONDS) + } else if timer.subsec_nanos() == 0 { + (timer.as_micros() as _, c::NOTE_USECONDS) + } else { + (timer.as_nanos() as _, c::NOTE_NSECONDS) + } + } + None => (intptr_t::MAX, c::NOTE_SECONDS), + }; + #[cfg(any(target_os = "dragonfly", target_os = "openbsd"))] + let (data, fflags) = match timer { + Some(timer) => (timer.as_millis() as _, 0), + None => (intptr_t::MAX, 0), + }; + + (ident as _, data, c::EVFILT_TIMER, fflags) + } + #[cfg(any(apple, freebsdlike))] + EventFilter::User { + ident, + flags, + user_flags, + } => (ident as _, 0, c::EVFILT_USER, flags.bits() | user_flags.0), + EventFilter::Unknown => panic!("unknown filter"), + }; + + Event { + inner: kevent_t { + ident, + filter: filter as _, + flags: flags.bits() as _, + fflags, + data: { + // On openbsd, data is an i64 and not an isize + data as _ + }, + udata: { + // On netbsd, udata is an isize and not a pointer. + // TODO: Strict provenance, prevent int-to-ptr cast. + udata as _ + }, + ..unsafe { zeroed() } + }, + } + } + + /// Get the event flags for this event. + pub fn flags(&self) -> EventFlags { + EventFlags::from_bits_truncate(self.inner.flags as _) + } + + /// Get the user data for this event. + pub fn udata(&self) -> isize { + // On netbsd, udata is an isize and not a pointer. + // TODO: Strict provenance, prevent ptr-to-int cast. + + self.inner.udata as _ + } + + /// Get the filter of this event. + pub fn filter(&self) -> EventFilter { + match self.inner.filter as _ { + c::EVFILT_READ => EventFilter::Read(self.inner.ident as _), + c::EVFILT_WRITE => EventFilter::Write(self.inner.ident as _), + #[cfg(target_os = "freebsd")] + c::EVFILT_EMPTY => EventFilter::Empty(self.inner.ident as _), + c::EVFILT_VNODE => EventFilter::Vnode { + vnode: self.inner.ident as _, + flags: VnodeEvents::from_bits_truncate(self.inner.fflags), + }, + #[cfg(feature = "process")] + c::EVFILT_PROC => EventFilter::Proc { + pid: unsafe { Pid::from_raw(self.inner.ident as _) }.unwrap(), + flags: ProcessEvents::from_bits_truncate(self.inner.fflags), + }, + #[cfg(feature = "process")] + c::EVFILT_SIGNAL => EventFilter::Signal { + signal: Signal::from_raw(self.inner.ident as _).unwrap(), + times: self.inner.data as _, + }, + c::EVFILT_TIMER => EventFilter::Timer { + ident: self.inner.ident as _, + timer: { + let (data, fflags) = (self.inner.data, self.inner.fflags); + #[cfg(any(apple, target_os = "freebsd", target_os = "netbsd"))] + match fflags as _ { + c::NOTE_SECONDS => Some(Duration::from_secs(data as _)), + c::NOTE_USECONDS => Some(Duration::from_micros(data as _)), + c::NOTE_NSECONDS => Some(Duration::from_nanos(data as _)), + _ => { + // Unknown timer flags. + None + } + } + #[cfg(any(target_os = "dragonfly", target_os = "openbsd"))] + Some(Duration::from_millis(data as _)) + }, + }, + #[cfg(any(apple, freebsdlike))] + c::EVFILT_USER => EventFilter::User { + ident: self.inner.ident as _, + flags: UserFlags::from_bits_truncate(self.inner.fflags), + user_flags: UserDefinedFlags(self.inner.fflags & EVFILT_USER_FLAGS), + }, + _ => EventFilter::Unknown, + } + } +} + +/// Bottom 24 bits of a u32. +#[cfg(any(apple, freebsdlike))] +const EVFILT_USER_FLAGS: u32 = 0x00ff_ffff; + +/// The possible filters for a `kqueue`. +#[repr(i16)] +#[non_exhaustive] +pub enum EventFilter { + /// A read filter. + Read(RawFd), + + /// A write filter. + Write(RawFd), + + /// An empty filter. + #[cfg(target_os = "freebsd")] + Empty(RawFd), + + /// A VNode filter. + Vnode { + /// The file descriptor we looked for events in. + vnode: RawFd, + + /// The flags for this event. + flags: VnodeEvents, + }, + + /// A process filter. + #[cfg(feature = "process")] + Proc { + /// The process ID we waited on. + pid: Pid, + + /// The flags for this event. + flags: ProcessEvents, + }, + + /// A signal filter. + #[cfg(feature = "process")] + Signal { + /// The signal number we waited on. + signal: Signal, + + /// The number of times the signal has been + /// received since the last call to kevent. + times: usize, + }, + + /// A timer filter. + Timer { + /// The identifier for this event. + ident: intptr_t, + + /// The duration for this event. + timer: Option<Duration>, + }, + + /// A user filter. + #[cfg(any(apple, freebsdlike))] + User { + /// The identifier for this event. + ident: intptr_t, + + /// The flags for this event. + flags: UserFlags, + + /// The user-defined flags for this event. + user_flags: UserDefinedFlags, + }, + + /// This filter is unknown. + /// + /// # Panics + /// + /// Passing this into `Event::new()` will result in a panic. + Unknown, +} + +bitflags::bitflags! { + /// The flags for a `kqueue` event. + pub struct EventFlags: u16 { + /// Add the event to the `kqueue`. + const ADD = c::EV_ADD as _; + + /// Enable the event. + const ENABLE = c::EV_ENABLE as _; + + /// Disable the event. + const DISABLE = c::EV_DISABLE as _; + + /// Delete the event from the `kqueue`. + const DELETE = c::EV_DELETE as _; + + /// TODO + const RECEIPT = c::EV_RECEIPT as _; + + /// Clear the event after it is triggered. + const ONESHOT = c::EV_ONESHOT as _; + + /// TODO + const CLEAR = c::EV_CLEAR as _; + + /// TODO + const EOF = c::EV_EOF as _; + + /// TODO + const ERROR = c::EV_ERROR as _; + } +} + +bitflags::bitflags! { + /// The flags for a virtual node event. + pub struct VnodeEvents: u32 { + /// The file was deleted. + const DELETE = c::NOTE_DELETE; + + /// The file was written to. + const WRITE = c::NOTE_WRITE; + + /// The file was extended. + const EXTEND = c::NOTE_EXTEND; + + /// The file had its attributes changed. + const ATTRIBUTES = c::NOTE_ATTRIB; + + /// The file was renamed. + const RENAME = c::NOTE_RENAME; + + /// Access to the file was revoked. + const REVOKE = c::NOTE_REVOKE; + + /// The link count of the file has changed. + const LINK = c::NOTE_LINK; + } +} + +#[cfg(feature = "process")] +bitflags::bitflags! { + /// The flags for a process event. + pub struct ProcessEvents: u32 { + /// The process exited. + const EXIT = c::NOTE_EXIT; + + /// The process forked itself. + const FORK = c::NOTE_FORK; + + /// The process executed a new process. + const EXEC = c::NOTE_EXEC; + + /// Follow the process through `fork()` calls (write only). + const TRACK = c::NOTE_TRACK; + + /// An error has occurred with following the process. + const TRACKERR = c::NOTE_TRACKERR; + } +} + +#[cfg(any(apple, freebsdlike))] +bitflags::bitflags! { + /// The flags for a user event. + pub struct UserFlags: u32 { + /// Ignore the user input flags. + const NOINPUT = c::NOTE_FFNOP; + + /// Bitwise AND `fflags`. + const AND = c::NOTE_FFAND; + + /// Bitwise OR `fflags`. + const OR = c::NOTE_FFOR; + + /// Copy `fflags`. + const COPY = c::NOTE_FFCOPY; + + /// Control mask for operations. + const CTRLMASK = c::NOTE_FFCTRLMASK; + + /// User defined flags for masks. + const UDFMASK = c::NOTE_FFLAGSMASK; + + /// Trigger the event. + const TRIGGER = c::NOTE_TRIGGER; + } +} + +/// User-defined flags. +/// +/// Only the lower 24 bits are used in this struct. +#[repr(transparent)] +#[cfg(any(apple, freebsdlike))] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct UserDefinedFlags(u32); + +#[cfg(any(apple, freebsdlike))] +impl UserDefinedFlags { + /// Create a new `UserDefinedFlags` from a `u32`. + pub fn new(flags: u32) -> Self { + Self(flags & EVFILT_USER_FLAGS) + } + + /// Get the underlying `u32`. + pub fn get(self) -> u32 { + self.0 + } +} + +/// `kqueue()`—Create a new `kqueue` file descriptor. +/// +/// # References +/// - [Apple] +/// - [FreeBSD] +/// - [OpenBSD] +/// - [NetBSD] +/// - [DragonFly BSD] +/// +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/kqueue.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2 +/// [OpenBSD]: https://man.openbsd.org/kqueue.2 +/// [NetBSD]: https://man.netbsd.org/kqueue.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=kqueue§ion=2 +pub fn kqueue() -> io::Result<OwnedFd> { + syscalls::kqueue() +} + +/// `kevent(kqueue, changelist, eventlist, timeout)`—Wait for events on a +/// `kqueue`. +/// +/// Note: in order to receive events, make sure to allocate capacity in the +/// eventlist! Otherwise, the function will return immediately. +/// +/// # Safety +/// +/// The file descriptors referred to by the `Event` structs must be valid for +/// the lifetime of the `kqueue` file descriptor. +/// +/// # References +/// - [Apple] +/// - [FreeBSD] +/// - [OpenBSD] +/// - [NetBSD] +/// - [DragonFly BSD] +/// +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/kevent.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=kevent&sektion=2 +/// [OpenBSD]: https://man.openbsd.org/kevent.2 +/// [NetBSD]: https://man.netbsd.org/kevent.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=kevent§ion=2 +pub unsafe fn kevent( + kqueue: impl AsFd, + changelist: &[Event], + eventlist: &mut Vec<Event>, + timeout: Option<Duration>, +) -> io::Result<usize> { + let timeout = timeout.map(|timeout| backend::c::timespec { + tv_sec: timeout.as_secs() as _, + tv_nsec: timeout.subsec_nanos() as _, + }); + + // Populate the event list with events. + eventlist.set_len(0); + let out_slice = slice_from_raw_parts_mut(eventlist.as_mut_ptr().cast(), eventlist.capacity()); + let res = syscalls::kevent( + kqueue.as_fd(), + changelist, + &mut *out_slice, + timeout.as_ref(), + ) + .map(|res| res as _); + + // Update the event list. + if let Ok(len) = res { + eventlist.set_len(len); + } + + res +} diff --git a/vendor/rustix-0.37.22/src/io/mod.rs b/vendor/rustix-0.37.22/src/io/mod.rs new file mode 100644 index 000000000..e7553c9ff --- /dev/null +++ b/vendor/rustix-0.37.22/src/io/mod.rs @@ -0,0 +1,55 @@ +//! I/O operations. + +mod close; +#[cfg(not(windows))] +mod dup; +mod errno; +#[cfg(any(linux_kernel, target_os = "freebsd", target_os = "illumos"))] +mod eventfd; +#[cfg(not(windows))] +mod fcntl; +#[cfg(not(feature = "std"))] +pub(crate) mod fd; +mod ioctl; +#[cfg(not(any(windows, target_os = "redox")))] +#[cfg(all(feature = "fs", feature = "net"))] +mod is_read_write; +#[cfg(bsd)] +pub mod kqueue; +#[cfg(not(any(windows, target_os = "wasi")))] +mod pipe; +mod poll; +#[cfg(solarish)] +pub mod port; +#[cfg(all(feature = "procfs", linux_kernel))] +mod procfs; +#[cfg(not(windows))] +mod read_write; +mod seek_from; +#[cfg(not(windows))] +mod stdio; + +#[cfg(linux_kernel)] +pub use crate::backend::io::epoll; +pub use close::close; +#[cfg(not(windows))] +pub use dup::*; +pub use errno::{retry_on_intr, Errno, Result}; +#[cfg(any(linux_kernel, target_os = "freebsd", target_os = "illumos"))] +pub use eventfd::{eventfd, EventfdFlags}; +#[cfg(not(windows))] +pub use fcntl::*; +pub use ioctl::*; +#[cfg(not(any(windows, target_os = "redox")))] +#[cfg(all(feature = "fs", feature = "net"))] +pub use is_read_write::*; +#[cfg(not(any(windows, target_os = "wasi")))] +pub use pipe::*; +pub use poll::{poll, PollFd, PollFlags}; +#[cfg(all(feature = "procfs", linux_kernel))] +pub use procfs::*; +#[cfg(not(windows))] +pub use read_write::*; +pub use seek_from::SeekFrom; +#[cfg(not(windows))] +pub use stdio::*; diff --git a/vendor/rustix-0.37.22/src/io/pipe.rs b/vendor/rustix-0.37.22/src/io/pipe.rs new file mode 100644 index 000000000..b54abe8e8 --- /dev/null +++ b/vendor/rustix-0.37.22/src/io/pipe.rs @@ -0,0 +1,156 @@ +//! `pipe` and related APIs. +//! +//! # Safety +//! +//! `vmsplice` is an unsafe function. + +#![allow(unsafe_code)] + +use crate::fd::OwnedFd; +use crate::{backend, io}; +#[cfg(linux_kernel)] +use backend::fd::AsFd; + +#[cfg(not(apple))] +pub use backend::io::types::PipeFlags; + +#[cfg(linux_kernel)] +pub use backend::io::types::{IoSliceRaw, SpliceFlags}; + +/// `PIPE_BUF`—The maximum length at which writes to a pipe are atomic. +/// +/// # References +/// - [Linux] +/// - [POSIX] +/// +/// [Linux]: https://man7.org/linux/man-pages/man7/pipe.7.html +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html +#[cfg(not(any( + solarish, + windows, + target_os = "haiku", + target_os = "redox", + target_os = "wasi", +)))] +pub const PIPE_BUF: usize = backend::io::types::PIPE_BUF; + +/// `pipe()`—Creates a pipe. +/// +/// This function creates a pipe and returns two file descriptors, for the +/// reading and writing ends of the pipe, respectively. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/pipe.html +/// [Linux]: https://man7.org/linux/man-pages/man2/pipe.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/pipe.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=pipe&sektion=2 +/// [NetBSD]: https://man.netbsd.org/pipe.2 +/// [OpenBSD]: https://man.openbsd.org/pipe.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=pipe§ion=2 +/// [illumos]: https://illumos.org/man/2/pipe +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Creating-a-Pipe.html +#[inline] +pub fn pipe() -> io::Result<(OwnedFd, OwnedFd)> { + backend::io::syscalls::pipe() +} + +/// `pipe2(flags)`—Creates a pipe, with flags. +/// +/// This function creates a pipe and returns two file descriptors, for the +/// reading and writing ends of the pipe, respectively. +/// +/// # References +/// - [Linux] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/pipe2.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=pipe2&sektion=2 +/// [NetBSD]: https://man.netbsd.org/pipe2.2 +/// [OpenBSD]: https://man.openbsd.org/pipe2.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=pipe2§ion=2 +/// [illumos]: https://illumos.org/man/2/pipe2 +#[cfg(not(any(apple, target_os = "aix", target_os = "haiku")))] +#[inline] +#[doc(alias = "pipe2")] +pub fn pipe_with(flags: PipeFlags) -> io::Result<(OwnedFd, OwnedFd)> { + backend::io::syscalls::pipe_with(flags) +} + +/// `splice(fd_in, off_in, fd_out, off_out, len, flags)`—Transfer data between +/// a file and a pipe. +/// +/// This function transfers up to `len` bytes of data from the file descriptor +/// `fd_in` to the file descriptor `fd_out`, where one of the file descriptors +/// must refer to a pipe. +/// +/// `off_*` must be `None` if the corresponding fd refers to a pipe. +/// Otherwise its value points to the starting offset to the file, +/// from which the data is read/written. +/// on success the number of bytes read/written is added to the offset. +/// +/// passing `None` causes the read/write to start from the file offset, +/// and the file offset is adjusted appropriately. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/splice.2.html +#[cfg(linux_kernel)] +#[inline] +pub fn splice<FdIn: AsFd, FdOut: AsFd>( + fd_in: FdIn, + off_in: Option<&mut u64>, + fd_out: FdOut, + off_out: Option<&mut u64>, + len: usize, + flags: SpliceFlags, +) -> io::Result<usize> { + backend::io::syscalls::splice(fd_in.as_fd(), off_in, fd_out.as_fd(), off_out, len, flags) +} + +/// `vmsplice(fd, bufs, flags)`—Transfer data between memory and a pipe. +/// +/// If `fd` is the write end of the pipe, +/// the function maps the memory pointer at by `bufs` to the pipe. +/// +/// If `fd` is the read end of the pipe, +/// the function writes data from the pipe to said memory. +/// +/// # Safety +/// +/// If the memory must not be mutated (such as when `bufs` were originally +/// immutable slices), it is up to the caller to ensure that the write end of +/// the pipe is placed in `fd`. +/// +/// Additionally if `SpliceFlags::GIFT` is set, the caller must also ensure +/// that the contents of `bufs` in never modified following the call, +/// and that all of the pointers in `bufs` are page aligned, +/// and the lengths are multiples of a page size in bytes. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/vmsplice.2.html +#[cfg(linux_kernel)] +#[inline] +pub unsafe fn vmsplice<PipeFd: AsFd>( + fd: PipeFd, + bufs: &[IoSliceRaw], + flags: SpliceFlags, +) -> io::Result<usize> { + backend::io::syscalls::vmsplice(fd.as_fd(), bufs, flags) +} diff --git a/vendor/rustix-0.37.22/src/io/poll.rs b/vendor/rustix-0.37.22/src/io/poll.rs new file mode 100644 index 000000000..3f25d5ec3 --- /dev/null +++ b/vendor/rustix-0.37.22/src/io/poll.rs @@ -0,0 +1,32 @@ +use crate::{backend, io}; + +pub use backend::io::poll_fd::{PollFd, PollFlags}; + +/// `poll(self.fds, timeout)` +/// +/// # References +/// - [Beej's Guide to Network Programming] +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [Winsock2] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// +/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/slightly-advanced-techniques.html#poll +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html +/// [Linux]: https://man7.org/linux/man-pages/man2/poll.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/poll.2.html +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsapoll +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=poll&sektion=2 +/// [NetBSD]: https://man.netbsd.org/poll.2 +/// [OpenBSD]: https://man.openbsd.org/poll.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=poll§ion=2 +/// [illumos]: https://illumos.org/man/2/poll +#[inline] +pub fn poll(fds: &mut [PollFd<'_>], timeout: i32) -> io::Result<usize> { + backend::io::syscalls::poll(fds, timeout) +} diff --git a/vendor/rustix-0.37.22/src/io/port.rs b/vendor/rustix-0.37.22/src/io/port.rs new file mode 100644 index 000000000..4eb0bcd9e --- /dev/null +++ b/vendor/rustix-0.37.22/src/io/port.rs @@ -0,0 +1,151 @@ +//! Solaris/illumos event ports. + +use crate::backend::c; +use crate::backend::io::syscalls; +use crate::fd::{AsFd, AsRawFd, OwnedFd}; +use crate::io; + +use super::PollFlags; + +use core::convert::TryInto; +use core::time::Duration; + +/// The structure representing a port event. +#[repr(transparent)] +pub struct Event(pub(crate) c::port_event); + +impl Event { + /// Get the events associated with this event. + pub fn events(&self) -> i32 { + self.0.portev_events + } + + /// Get the event source associated with this event. + pub fn object(&self) -> usize { + self.0.portev_object + } + + /// Get the userdata associated with this event. + pub fn userdata(&self) -> *mut c::c_void { + self.0.portev_user + } +} + +/// `port_create()`—Creates a new port. +/// +/// # References +/// - [OpenSolaris] +/// - [illumos] +/// +/// [OpenSolaris]: https://www.unix.com/man-page/opensolaris/3C/port_create/ +/// [illumos]: https://illumos.org/man/3C/port_create +pub fn port_create() -> io::Result<OwnedFd> { + syscalls::port_create() +} + +/// `port_associate(_, PORT_SOURCE_FD, _, _, _)`—Associates a file descriptor +/// with a port. +/// +/// # Safety +/// +/// Any `object`s passed into the `port` must be valid for the lifetime of the +/// `port`. Logically, `port` keeps a borrowed reference to the `object` until +/// it is removed via `port_dissociate_fd`. +/// +/// # References +/// - [OpenSolaris] +/// - [illumos] +/// +/// [OpenSolaris]: https://www.unix.com/man-page/opensolaris/3C/port_associate/ +/// [illumos]: https://illumos.org/man/3C/port_associate +pub unsafe fn port_associate_fd( + port: impl AsFd, + object: impl AsRawFd, + events: PollFlags, + userdata: *mut c::c_void, +) -> io::Result<()> { + syscalls::port_associate( + port.as_fd(), + c::PORT_SOURCE_FD, + object.as_raw_fd() as _, + events.bits() as _, + userdata.cast(), + ) +} + +/// `port_dissociate(_, PORT_SOURCE_FD, _)`—Dissociates a file descriptor from +/// a port. +/// +/// # Safety +/// +/// The file descriptor passed into this function must have been previously +/// associated with the port via [`port_associate_fd`]. +/// +/// # References +/// - [OpenSolaris] +/// - [illumos] +/// +/// [OpenSolaris]: https://www.unix.com/man-page/opensolaris/3C/port_dissociate +/// [illumos]: https://illumos.org/man/3C/port_dissociate +pub unsafe fn port_dissociate_fd(port: impl AsFd, object: impl AsRawFd) -> io::Result<()> { + syscalls::port_dissociate(port.as_fd(), c::PORT_SOURCE_FD, object.as_raw_fd() as _) +} + +/// `port_get(port, timeout)`—Gets an event from a port. +/// +/// # References +/// - [OpenSolaris] +/// - [illumos] +/// +/// [OpenSolaris]: https://www.unix.com/man-page/opensolaris/3C/port_get/ +/// [illumos]: https://illumos.org/man/3C/port_get +pub fn port_get(port: impl AsFd, timeout: Option<Duration>) -> io::Result<Event> { + let mut timeout = timeout.map(|timeout| c::timespec { + tv_sec: timeout.as_secs().try_into().unwrap(), + tv_nsec: timeout.subsec_nanos() as _, + }); + + syscalls::port_get(port.as_fd(), timeout.as_mut()) +} + +/// `port_getn(port, events, min_events, timeout)`—Gets multiple events from a +/// port. +/// +/// # References +/// - [OpenSolaris] +/// - [illumos] +/// +/// [OpenSolaris]: https://www.unix.com/man-page/opensolaris/3C/port_getn/ +/// [illumos]: https://illumos.org/man/3C/port_getn +pub fn port_getn( + port: impl AsFd, + events: &mut Vec<Event>, + min_events: usize, + timeout: Option<Duration>, +) -> io::Result<()> { + events.clear(); + + let mut timeout = timeout.map(|timeout| c::timespec { + tv_sec: timeout.as_secs().try_into().unwrap(), + tv_nsec: timeout.subsec_nanos() as _, + }); + + syscalls::port_getn( + port.as_fd(), + timeout.as_mut(), + events, + min_events.try_into().unwrap(), + ) +} + +/// `port_send(port, events, userdata)`—Sends an event to a port. +/// +/// # References +/// - [OpenSolaris] +/// - [illumos] +/// +/// [OpenSolaris]: https://www.unix.com/man-page/opensolaris/3C/port_send/ +/// [illumos]: https://illumos.org/man/3C/port_send +pub fn port_send(port: impl AsFd, events: i32, userdata: *mut c::c_void) -> io::Result<()> { + syscalls::port_send(port.as_fd(), events, userdata.cast()) +} diff --git a/vendor/rustix-0.37.22/src/io/procfs.rs b/vendor/rustix-0.37.22/src/io/procfs.rs new file mode 100644 index 000000000..e616473c7 --- /dev/null +++ b/vendor/rustix-0.37.22/src/io/procfs.rs @@ -0,0 +1,466 @@ +//! Utilities for working with `/proc`, where Linux's `procfs` is typically +//! mounted. `/proc` serves as an adjunct to Linux's main syscall surface area, +//! providing additional features with an awkward interface. +//! +//! This module does a considerable amount of work to determine whether `/proc` +//! is mounted, with actual `procfs`, and without any additional mount points +//! on top of the paths we open. +//! +//! Why all the effort to detect bind mount points? People are doing all kinds +//! of things with Linux containers these days, with many different privilege +//! schemes, and we want to avoid making any unnecessary assumptions. Rustix +//! and its users will sometimes use procfs *implicitly* (when Linux gives them +//! no better options), in ways that aren't obvious from their public APIs. +//! These filesystem accesses might not be visible to someone auditing the main +//! code of an application for places which may be influenced by the filesystem +//! namespace. So with the checking here, they may fail, but they won't be able +//! to succeed with bogus results. + +use crate::fd::{AsFd, BorrowedFd, OwnedFd}; +use crate::ffi::CStr; +use crate::fs::{ + cwd, fstat, fstatfs, major, openat, renameat, Dir, FileType, Mode, OFlags, Stat, + PROC_SUPER_MAGIC, +}; +use crate::io; +use crate::path::DecInt; +use crate::process::getpid; +#[cfg(feature = "rustc-dep-of-std")] +use core::lazy::OnceCell; +#[cfg(not(feature = "rustc-dep-of-std"))] +use once_cell::sync::OnceCell; + +/// Linux's procfs always uses inode 1 for its root directory. +const PROC_ROOT_INO: u64 = 1; + +// Identify an entry within "/proc", to determine which anomalies to check for. +#[derive(Copy, Clone, Debug)] +enum Kind { + Proc, + Pid, + Fd, + File, +} + +/// Check a subdirectory of "/proc" for anomalies. +fn check_proc_entry( + kind: Kind, + entry: BorrowedFd<'_>, + proc_stat: Option<&Stat>, +) -> io::Result<Stat> { + let entry_stat = fstat(entry)?; + check_proc_entry_with_stat(kind, entry, entry_stat, proc_stat) +} + +/// Check a subdirectory of "/proc" for anomalies, using the provided `Stat`. +fn check_proc_entry_with_stat( + kind: Kind, + entry: BorrowedFd<'_>, + entry_stat: Stat, + proc_stat: Option<&Stat>, +) -> io::Result<Stat> { + // Check the filesystem magic. + check_procfs(entry)?; + + match kind { + Kind::Proc => check_proc_root(entry, &entry_stat)?, + Kind::Pid | Kind::Fd => check_proc_subdir(entry, &entry_stat, proc_stat)?, + Kind::File => check_proc_file(&entry_stat, proc_stat)?, + } + + // "/proc" directories are typically mounted r-xr-xr-x. + // "/proc/self/fd" is r-x------. Allow them to have fewer permissions, but + // not more. + let expected_mode = if let Kind::Fd = kind { 0o500 } else { 0o555 }; + if entry_stat.st_mode & 0o777 & !expected_mode != 0 { + return Err(io::Errno::NOTSUP); + } + + match kind { + Kind::Fd => { + // Check that the "/proc/self/fd" directory doesn't have any + // extraneous links into it (which might include unexpected + // subdirectories). + if entry_stat.st_nlink != 2 { + return Err(io::Errno::NOTSUP); + } + } + Kind::Pid | Kind::Proc => { + // Check that the "/proc" and "/proc/self" directories aren't + // empty. + if entry_stat.st_nlink <= 2 { + return Err(io::Errno::NOTSUP); + } + } + Kind::File => { + // Check that files in procfs don't have extraneous hard links to + // them (which might indicate hard links to other things). + if entry_stat.st_nlink != 1 { + return Err(io::Errno::NOTSUP); + } + } + } + + Ok(entry_stat) +} + +fn check_proc_root(entry: BorrowedFd<'_>, stat: &Stat) -> io::Result<()> { + // We use `O_DIRECTORY` for proc directories, so open should fail if we + // don't get a directory when we expect one. + assert_eq!(FileType::from_raw_mode(stat.st_mode), FileType::Directory); + + // Check the root inode number. + if stat.st_ino != PROC_ROOT_INO { + return Err(io::Errno::NOTSUP); + } + + // Proc is a non-device filesystem, so check for major number 0. + // <https://www.kernel.org/doc/Documentation/admin-guide/devices.txt> + if major(stat.st_dev) != 0 { + return Err(io::Errno::NOTSUP); + } + + // Check that "/proc" is a mountpoint. + if !is_mountpoint(entry) { + return Err(io::Errno::NOTSUP); + } + + Ok(()) +} + +fn check_proc_subdir( + entry: BorrowedFd<'_>, + stat: &Stat, + proc_stat: Option<&Stat>, +) -> io::Result<()> { + // We use `O_DIRECTORY` for proc directories, so open should fail if we + // don't get a directory when we expect one. + assert_eq!(FileType::from_raw_mode(stat.st_mode), FileType::Directory); + + check_proc_nonroot(stat, proc_stat)?; + + // Check that subdirectories of "/proc" are not mount points. + if is_mountpoint(entry) { + return Err(io::Errno::NOTSUP); + } + + Ok(()) +} + +fn check_proc_file(stat: &Stat, proc_stat: Option<&Stat>) -> io::Result<()> { + // Check that we have a regular file. + if FileType::from_raw_mode(stat.st_mode) != FileType::RegularFile { + return Err(io::Errno::NOTSUP); + } + + check_proc_nonroot(stat, proc_stat)?; + + Ok(()) +} + +fn check_proc_nonroot(stat: &Stat, proc_stat: Option<&Stat>) -> io::Result<()> { + // Check that we haven't been linked back to the root of "/proc". + if stat.st_ino == PROC_ROOT_INO { + return Err(io::Errno::NOTSUP); + } + + // Check that we're still in procfs. + if stat.st_dev != proc_stat.unwrap().st_dev { + return Err(io::Errno::NOTSUP); + } + + Ok(()) +} + +/// Check that `file` is opened on a `procfs` filesystem. +fn check_procfs(file: BorrowedFd<'_>) -> io::Result<()> { + let statfs = fstatfs(file)?; + let f_type = statfs.f_type; + if f_type != PROC_SUPER_MAGIC { + return Err(io::Errno::NOTSUP); + } + + Ok(()) +} + +/// Check whether the given directory handle is a mount point. +fn is_mountpoint(file: BorrowedFd<'_>) -> bool { + // We use a `renameat` call that would otherwise fail, but which fails with + // `XDEV` first if it would cross a mount point. + let err = renameat(file, cstr!("../."), file, cstr!(".")).unwrap_err(); + match err { + io::Errno::XDEV => true, // the rename failed due to crossing a mount point + io::Errno::BUSY => false, // the rename failed normally + _ => panic!("Unexpected error from `renameat`: {:?}", err), + } +} + +/// Open a directory in `/proc`, mapping all errors to `io::Errno::NOTSUP`. +fn proc_opendirat<P: crate::path::Arg, Fd: AsFd>(dirfd: Fd, path: P) -> io::Result<OwnedFd> { + // We could add `PATH`|`NOATIME` here but Linux 2.6.32 doesn't support it. + // Also for `NOATIME` see the comment in `open_and_check_file`. + let oflags = OFlags::NOFOLLOW | OFlags::DIRECTORY | OFlags::CLOEXEC | OFlags::NOCTTY; + openat(dirfd, path, oflags, Mode::empty()).map_err(|_err| io::Errno::NOTSUP) +} + +/// Returns a handle to Linux's `/proc` directory. +/// +/// This ensures that `/proc` is procfs, that nothing is mounted on top of it, +/// and that it looks normal. It also returns the `Stat` of `/proc`. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man5/proc.5.html +fn proc() -> io::Result<(BorrowedFd<'static>, &'static Stat)> { + static PROC: StaticFd = StaticFd::new(); + + // `OnceBox` is "racey" in that the initialization function may run + // multiple times. We're ok with that, since the initialization function + // has no side effects. + PROC.get_or_try_init(|| { + // Open "/proc". + let proc = proc_opendirat(cwd(), cstr!("/proc"))?; + let proc_stat = + check_proc_entry(Kind::Proc, proc.as_fd(), None).map_err(|_err| io::Errno::NOTSUP)?; + + Ok(new_static_fd(proc, proc_stat)) + }) + .map(|(fd, stat)| (fd.as_fd(), stat)) +} + +/// Returns a handle to Linux's `/proc/self` directory. +/// +/// This ensures that `/proc/self` is procfs, that nothing is mounted on top of +/// it, and that it looks normal. It also returns the `Stat` of `/proc/self`. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man5/proc.5.html +fn proc_self() -> io::Result<(BorrowedFd<'static>, &'static Stat)> { + static PROC_SELF: StaticFd = StaticFd::new(); + + // The init function here may run multiple times; see above. + PROC_SELF + .get_or_try_init(|| { + let (proc, proc_stat) = proc()?; + + let pid = getpid(); + + // Open "/proc/self". Use our pid to compute the name rather than + // literally using "self", as "self" is a symlink. + let proc_self = proc_opendirat(proc, DecInt::new(pid.as_raw_nonzero().get()))?; + let proc_self_stat = check_proc_entry(Kind::Pid, proc_self.as_fd(), Some(proc_stat)) + .map_err(|_err| io::Errno::NOTSUP)?; + + Ok(new_static_fd(proc_self, proc_self_stat)) + }) + .map(|(owned, stat)| (owned.as_fd(), stat)) +} + +/// Returns a handle to Linux's `/proc/self/fd` directory. +/// +/// This ensures that `/proc/self/fd` is `procfs`, that nothing is mounted on +/// top of it, and that it looks normal. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man5/proc.5.html +#[cfg_attr(doc_cfg, doc(cfg(feature = "procfs")))] +pub fn proc_self_fd() -> io::Result<BorrowedFd<'static>> { + static PROC_SELF_FD: StaticFd = StaticFd::new(); + + // The init function here may run multiple times; see above. + PROC_SELF_FD + .get_or_try_init(|| { + let (_, proc_stat) = proc()?; + + let (proc_self, _proc_self_stat) = proc_self()?; + + // Open "/proc/self/fd". + let proc_self_fd = proc_opendirat(proc_self, cstr!("fd"))?; + let proc_self_fd_stat = + check_proc_entry(Kind::Fd, proc_self_fd.as_fd(), Some(proc_stat)) + .map_err(|_err| io::Errno::NOTSUP)?; + + Ok(new_static_fd(proc_self_fd, proc_self_fd_stat)) + }) + .map(|(owned, _stat)| owned.as_fd()) +} + +type StaticFd = OnceCell<(OwnedFd, Stat)>; + +#[inline] +fn new_static_fd(fd: OwnedFd, stat: Stat) -> (OwnedFd, Stat) { + (fd, stat) +} + +/// Returns a handle to Linux's `/proc/self/fdinfo` directory. +/// +/// This ensures that `/proc/self/fdinfo` is `procfs`, that nothing is mounted +/// on top of it, and that it looks normal. It also returns the `Stat` of +/// `/proc/self/fd`. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man5/proc.5.html +fn proc_self_fdinfo() -> io::Result<(BorrowedFd<'static>, &'static Stat)> { + static PROC_SELF_FDINFO: StaticFd = StaticFd::new(); + + PROC_SELF_FDINFO + .get_or_try_init(|| { + let (_, proc_stat) = proc()?; + + let (proc_self, _proc_self_stat) = proc_self()?; + + // Open "/proc/self/fdinfo". + let proc_self_fdinfo = proc_opendirat(proc_self, cstr!("fdinfo"))?; + let proc_self_fdinfo_stat = + check_proc_entry(Kind::Fd, proc_self_fdinfo.as_fd(), Some(proc_stat)) + .map_err(|_err| io::Errno::NOTSUP)?; + + Ok((proc_self_fdinfo, proc_self_fdinfo_stat)) + }) + .map(|(owned, stat)| (owned.as_fd(), stat)) +} + +/// Returns a handle to a Linux `/proc/self/fdinfo/<fd>` file. +/// +/// This ensures that `/proc/self/fdinfo/<fd>` is `procfs`, that nothing is +/// mounted on top of it, and that it looks normal. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man5/proc.5.html +#[inline] +#[cfg_attr(doc_cfg, doc(cfg(feature = "procfs")))] +pub fn proc_self_fdinfo_fd<Fd: AsFd>(fd: Fd) -> io::Result<OwnedFd> { + _proc_self_fdinfo(fd.as_fd()) +} + +fn _proc_self_fdinfo(fd: BorrowedFd<'_>) -> io::Result<OwnedFd> { + let (proc_self_fdinfo, proc_self_fdinfo_stat) = proc_self_fdinfo()?; + let fd_str = DecInt::from_fd(fd); + open_and_check_file(proc_self_fdinfo, proc_self_fdinfo_stat, fd_str.as_c_str()) +} + +/// Returns a handle to a Linux `/proc/self/pagemap` file. +/// +/// This ensures that `/proc/self/pagemap` is `procfs`, that nothing is +/// mounted on top of it, and that it looks normal. +/// +/// # References +/// - [Linux] +/// - [Linux pagemap] +/// +/// [Linux]: https://man7.org/linux/man-pages/man5/proc.5.html +/// [Linux pagemap]: https://www.kernel.org/doc/Documentation/vm/pagemap.txt +#[inline] +#[cfg_attr(doc_cfg, doc(cfg(feature = "procfs")))] +pub fn proc_self_pagemap() -> io::Result<OwnedFd> { + proc_self_file(cstr!("pagemap")) +} + +/// Returns a handle to a Linux `/proc/self/maps` file. +/// +/// This ensures that `/proc/self/maps` is `procfs`, that nothing is +/// mounted on top of it, and that it looks normal. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man5/proc.5.html +#[inline] +#[cfg_attr(doc_cfg, doc(cfg(feature = "procfs")))] +pub fn proc_self_maps() -> io::Result<OwnedFd> { + proc_self_file(cstr!("maps")) +} + +/// Returns a handle to a Linux `/proc/self/status` file. +/// +/// This ensures that `/proc/self/status` is `procfs`, that nothing is +/// mounted on top of it, and that it looks normal. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man5/proc.5.html +#[inline] +#[cfg_attr(doc_cfg, doc(cfg(feature = "procfs")))] +pub fn proc_self_status() -> io::Result<OwnedFd> { + proc_self_file(cstr!("status")) +} + +/// Open a file under `/proc/self`. +fn proc_self_file(name: &CStr) -> io::Result<OwnedFd> { + let (proc_self, proc_self_stat) = proc_self()?; + open_and_check_file(proc_self, proc_self_stat, name) +} + +/// Open a procfs file within in `dir` and check it for bind mounts. +fn open_and_check_file(dir: BorrowedFd, dir_stat: &Stat, name: &CStr) -> io::Result<OwnedFd> { + let (_, proc_stat) = proc()?; + + // Don't use `NOATIME`, because it [requires us to own the file], and when + // a process sets itself non-dumpable Linux changes the user:group of its + // `/proc/<pid>` files [to root:root]. + // + // [requires us to own the file]: https://man7.org/linux/man-pages/man2/openat.2.html + // [to root:root]: https://man7.org/linux/man-pages/man5/proc.5.html + let oflags = OFlags::RDONLY | OFlags::CLOEXEC | OFlags::NOFOLLOW | OFlags::NOCTTY; + let file = openat(dir, name, oflags, Mode::empty()).map_err(|_err| io::Errno::NOTSUP)?; + let file_stat = fstat(&file)?; + + // `is_mountpoint` only works on directory mount points, not file mount + // points. To detect file mount points, scan the parent directory to see + // if we can find a regular file with an inode and name that matches the + // file we just opened. If we can't find it, there could be a file bind + // mount on top of the file we want. + // + // As we scan, we also check for ".", to make sure it's the same directory + // as our original directory, to detect mount points, since + // `Dir::read_from` reopens ".". + // + // TODO: With Linux 5.8 we might be able to use `statx` and + // `STATX_ATTR_MOUNT_ROOT` to detect mountpoints directly instead of doing + // this scanning. + let dir = Dir::read_from(dir).map_err(|_err| io::Errno::NOTSUP)?; + + // Confirm that we got the same inode. + let dot_stat = dir.stat().map_err(|_err| io::Errno::NOTSUP)?; + if (dot_stat.st_dev, dot_stat.st_ino) != (dir_stat.st_dev, dir_stat.st_ino) { + return Err(io::Errno::NOTSUP); + } + + let mut found_file = false; + let mut found_dot = false; + for entry in dir { + let entry = entry.map_err(|_err| io::Errno::NOTSUP)?; + if entry.ino() == file_stat.st_ino + && entry.file_type() == FileType::RegularFile + && entry.file_name() == name + { + // We found the file. Proceed to check the file handle. + let _ = + check_proc_entry_with_stat(Kind::File, file.as_fd(), file_stat, Some(proc_stat))?; + + found_file = true; + } else if entry.ino() == dir_stat.st_ino + && entry.file_type() == FileType::Directory + && entry.file_name() == cstr!(".") + { + // We found ".", and it's the right ".". + found_dot = true; + } + } + + if found_file && found_dot { + Ok(file) + } else { + Err(io::Errno::NOTSUP) + } +} diff --git a/vendor/rustix-0.37.22/src/io/read_write.rs b/vendor/rustix-0.37.22/src/io/read_write.rs new file mode 100644 index 000000000..1d7474706 --- /dev/null +++ b/vendor/rustix-0.37.22/src/io/read_write.rs @@ -0,0 +1,261 @@ +//! `read` and `write`, optionally positioned, optionally vectored + +use crate::{backend, io}; +use backend::fd::AsFd; + +// Declare `IoSlice` and `IoSliceMut`. +#[cfg(not(windows))] +#[cfg(not(feature = "std"))] +pub use backend::io::io_slice::{IoSlice, IoSliceMut}; +#[cfg(not(windows))] +#[cfg(feature = "std")] +pub use std::io::{IoSlice, IoSliceMut}; + +#[cfg(linux_kernel)] +pub use backend::io::types::ReadWriteFlags; + +/// `read(fd, buf)`—Reads from a stream. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html +/// [Linux]: https://man7.org/linux/man-pages/man2/read.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/read.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=read&sektion=2 +/// [NetBSD]: https://man.netbsd.org/read.2 +/// [OpenBSD]: https://man.openbsd.org/read.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=read§ion=2 +/// [illumos]: https://illumos.org/man/2/read +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/I_002fO-Primitives.html#index-reading-from-a-file-descriptor +#[inline] +pub fn read<Fd: AsFd>(fd: Fd, buf: &mut [u8]) -> io::Result<usize> { + backend::io::syscalls::read(fd.as_fd(), buf) +} + +/// `write(fd, buf)`—Writes to a stream. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html +/// [Linux]: https://man7.org/linux/man-pages/man2/write.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/write.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=write&sektion=2 +/// [NetBSD]: https://man.netbsd.org/write.2 +/// [OpenBSD]: https://man.openbsd.org/write.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=write§ion=2 +/// [illumos]: https://illumos.org/man/2/write +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/I_002fO-Primitives.html#index-writing-to-a-file-descriptor +#[inline] +pub fn write<Fd: AsFd>(fd: Fd, buf: &[u8]) -> io::Result<usize> { + backend::io::syscalls::write(fd.as_fd(), buf) +} + +/// `pread(fd, buf, offset)`—Reads from a file at a given position. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/pread.html +/// [Linux]: https://man7.org/linux/man-pages/man2/pread.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/pread.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=pread&sektion=2 +/// [NetBSD]: https://man.netbsd.org/pread.2 +/// [OpenBSD]: https://man.openbsd.org/pread.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=pread§ion=2 +/// [illumos]: https://illumos.org/man/2/pread +#[inline] +pub fn pread<Fd: AsFd>(fd: Fd, buf: &mut [u8], offset: u64) -> io::Result<usize> { + backend::io::syscalls::pread(fd.as_fd(), buf, offset) +} + +/// `pwrite(fd, bufs)`—Writes to a file at a given position. +/// +/// Contrary to POSIX, on many popular platforms including Linux and FreeBSD, +/// if the file is opened in append mode, this ignores the offset appends the +/// data to the end of the file. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/pwrite.html +/// [Linux]: https://man7.org/linux/man-pages/man2/pwrite.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/pwrite.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=pwrite&sektion=2 +/// [NetBSD]: https://man.netbsd.org/pwrite.2 +/// [OpenBSD]: https://man.openbsd.org/pwrite.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=pwrite§ion=2 +/// [illumos]: https://illumos.org/man/2/pwrite +#[inline] +pub fn pwrite<Fd: AsFd>(fd: Fd, buf: &[u8], offset: u64) -> io::Result<usize> { + backend::io::syscalls::pwrite(fd.as_fd(), buf, offset) +} + +/// `readv(fd, bufs)`—Reads from a stream into multiple buffers. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/readv.html +/// [Linux]: https://man7.org/linux/man-pages/man2/readv.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/readv.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=readv&sektion=2 +/// [NetBSD]: https://man.netbsd.org/readv.2 +/// [OpenBSD]: https://man.openbsd.org/readv.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=readv§ion=2 +/// [illumos]: https://illumos.org/man/2/readv +#[inline] +pub fn readv<Fd: AsFd>(fd: Fd, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { + backend::io::syscalls::readv(fd.as_fd(), bufs) +} + +/// `writev(fd, bufs)`—Writes to a stream from multiple buffers. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/writev.html +/// [Linux]: https://man7.org/linux/man-pages/man2/writev.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/writev.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=writev&sektion=2 +/// [NetBSD]: https://man.netbsd.org/writev.2 +/// [OpenBSD]: https://man.openbsd.org/writev.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=writev§ion=2 +/// [illumos]: https://illumos.org/man/2/writev +#[inline] +pub fn writev<Fd: AsFd>(fd: Fd, bufs: &[IoSlice<'_>]) -> io::Result<usize> { + backend::io::syscalls::writev(fd.as_fd(), bufs) +} + +/// `preadv(fd, bufs, offset)`—Reads from a file at a given position into +/// multiple buffers. +/// +/// # References +/// - [Linux] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/preadv.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=preadv&sektion=2 +/// [NetBSD]: https://man.netbsd.org/preadv.2 +/// [OpenBSD]: https://man.openbsd.org/preadv.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=preadv§ion=2 +/// [illumos]: https://illumos.org/man/2/preadv +#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "solaris")))] +#[inline] +pub fn preadv<Fd: AsFd>(fd: Fd, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> { + backend::io::syscalls::preadv(fd.as_fd(), bufs, offset) +} + +/// `pwritev(fd, bufs, offset)`—Writes to a file at a given position from +/// multiple buffers. +/// +/// Contrary to POSIX, on many popular platforms including Linux and FreeBSD, +/// if the file is opened in append mode, this ignores the offset appends the +/// data to the end of the file. +/// +/// # References +/// - [Linux] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/pwritev.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=pwritev&sektion=2 +/// [NetBSD]: https://man.netbsd.org/pwritev.2 +/// [OpenBSD]: https://man.openbsd.org/pwritev.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=pwritev§ion=2 +/// [illumos]: https://illumos.org/man/2/pwritev +#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "solaris")))] +#[inline] +pub fn pwritev<Fd: AsFd>(fd: Fd, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> { + backend::io::syscalls::pwritev(fd.as_fd(), bufs, offset) +} + +/// `preadv2(fd, bufs, offset, flags)`—Reads data, with several options. +/// +/// An `offset` of `u64::MAX` means to use and update the current file offset. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/preadv2.2.html +#[cfg(linux_kernel)] +#[inline] +pub fn preadv2<Fd: AsFd>( + fd: Fd, + bufs: &mut [IoSliceMut<'_>], + offset: u64, + flags: ReadWriteFlags, +) -> io::Result<usize> { + backend::io::syscalls::preadv2(fd.as_fd(), bufs, offset, flags) +} + +/// `pwritev2(fd, bufs, offset, flags)`—Writes data, with several options. +/// +/// An `offset` of `u64::MAX` means to use and update the current file offset. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/pwritev2.2.html +#[cfg(linux_kernel)] +#[inline] +pub fn pwritev2<Fd: AsFd>( + fd: Fd, + bufs: &[IoSlice<'_>], + offset: u64, + flags: ReadWriteFlags, +) -> io::Result<usize> { + backend::io::syscalls::pwritev2(fd.as_fd(), bufs, offset, flags) +} diff --git a/vendor/rustix-0.37.22/src/io/seek_from.rs b/vendor/rustix-0.37.22/src/io/seek_from.rs new file mode 100644 index 000000000..cca23ed62 --- /dev/null +++ b/vendor/rustix-0.37.22/src/io/seek_from.rs @@ -0,0 +1,48 @@ +//! The following is derived from Rust's +//! library/std/src/io/mod.rs at revision +//! dca3f1b786efd27be3b325ed1e01e247aa589c3b. + +/// Enumeration of possible methods to seek within an I/O object. +/// +/// It is used by the [`Seek`] trait. +/// +/// [`Seek`]: std::io::Seek +#[derive(Copy, PartialEq, Eq, Clone, Debug)] +#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] +pub enum SeekFrom { + /// Sets the offset to the provided number of bytes. + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + Start(#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] u64), + + /// Sets the offset to the size of this object plus the specified number of + /// bytes. + /// + /// It is possible to seek beyond the end of an object, but it's an error + /// to seek before byte 0. + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + End(#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] i64), + + /// Sets the offset to the current position plus the specified number of + /// bytes. + /// + /// It is possible to seek beyond the end of an object, but it's an error + /// to seek before byte 0. + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + Current(#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] i64), + + /// Sets the offset to the current position plus the specified number of bytes, + /// plus the distance to the next byte which is not in a hole. + /// + /// If the offset is in a hole at the end of the file, the seek will produce + /// an `NXIO` error. + #[cfg(any(freebsdlike, target_os = "linux", target_os = "solaris"))] + Data(i64), + + /// Sets the offset to the current position plus the specified number of bytes, + /// plus the distance to the next byte which is in a hole. + /// + /// If there is no hole past the offset, it will be set to the end of the file + /// i.e. there is an implicit hole at the end of any file. + #[cfg(any(freebsdlike, target_os = "linux", target_os = "solaris"))] + Hole(i64), +} diff --git a/vendor/rustix-0.37.22/src/io/stdio.rs b/vendor/rustix-0.37.22/src/io/stdio.rs new file mode 100644 index 000000000..2c4de8ddf --- /dev/null +++ b/vendor/rustix-0.37.22/src/io/stdio.rs @@ -0,0 +1,507 @@ +//! Functions returning the stdio file descriptors. +//! +//! # Safety +//! +//! These access the file descriptors by absolute index value, and nothing +//! prevents them from being closed and reused. They should only be used in +//! `main` or other situations where one is in control of the process' +//! stdio streams. +#![allow(unsafe_code)] + +use crate::backend; +use crate::fd::OwnedFd; +use backend::fd::{BorrowedFd, FromRawFd, RawFd}; + +#[cfg(not(any(windows, target_os = "wasi")))] +use {crate::io, backend::fd::AsFd, core::mem::forget}; + +/// `STDIN_FILENO`—Standard input, borrowed. +/// +/// In `std`-using configurations, this is a safe function, because the +/// standard library already assumes that the stdin file descriptor is always +/// valid. In `no_std` configurations, it is `unsafe`. +/// +/// # Warning +/// +/// This function allows reading directly from stdin without coordinating +/// with the buffering performed by [`std::io::Stdin`], so it could cause +/// corrupted input. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/stdin.html +/// [Linux]: https://man7.org/linux/man-pages/man3/stdin.3.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=stdin&sektion=4 +/// [NetBSD]: https://man.netbsd.org/stdin.4 +/// [OpenBSD]: https://man.openbsd.org/stdin.4 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=stdin§ion=4 +/// [illumos]: https://illumos.org/man/4FS/stdin +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Standard-Streams.html#index-stdin +#[cfg(feature = "std")] +#[doc(alias = "STDIN_FILENO")] +#[inline] +pub const fn stdin() -> BorrowedFd<'static> { + // SAFETY: When "std" is enabled, the standard library assumes that the + // stdio file descriptors are all valid. + unsafe { BorrowedFd::borrow_raw(backend::io::types::STDIN_FILENO as RawFd) } +} + +/// `STDIN_FILENO`—Standard input, borrowed. +/// +/// In `std`-using configurations, this is a safe function, because the +/// standard library already assumes that the stdin file descriptor is always +/// valid. In `no_std` configurations, it is `unsafe`. +/// +/// # Safety +/// +/// In `no_std` configurations, the stdin file descriptor can be closed, +/// potentially on other threads, in which case the file descriptor index +/// value could be dynamically reused for other purposes, potentially on +/// different threads. +/// +/// # Warning +/// +/// This function allows reading directly from stdin without coordinating +/// with the buffering performed by [`std::io::Stdin`], so it could cause +/// corrupted input. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/stdin.html +/// [Linux]: https://man7.org/linux/man-pages/man3/stdin.3.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=stdin&sektion=4 +/// [NetBSD]: https://man.netbsd.org/stdin.4 +/// [OpenBSD]: https://man.openbsd.org/stdin.4 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=stdin§ion=4 +/// [illumos]: https://illumos.org/man/4FS/stdin +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Standard-Streams.html#index-stdin +#[cfg(not(feature = "std"))] +#[doc(alias = "STDIN_FILENO")] +#[inline] +pub const unsafe fn stdin() -> BorrowedFd<'static> { + BorrowedFd::borrow_raw(backend::io::types::STDIN_FILENO as RawFd) +} + +/// `STDIN_FILENO`—Standard input, owned. +/// +/// This is similar to [`stdin`], however it returns an `OwnedFd` which closes +/// standard input when it is dropped. +/// +/// # Safety +/// +/// Safe `std`-using Rust code is permitted to assume that the stdin file +/// descriptor is always valid. This function returns an `OwnedFd` which will +/// close the stdin file descriptor when dropped. +/// +/// # Warning +/// +/// This has the same hazards as [`stdin`]. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/stdin.html +/// [Linux]: https://man7.org/linux/man-pages/man3/stdin.3.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=stdin&sektion=4 +/// [NetBSD]: https://man.netbsd.org/stdin.4 +/// [OpenBSD]: https://man.openbsd.org/stdin.4 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=stdin§ion=4 +/// [illumos]: https://illumos.org/man/4FS/stdin +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Standard-Streams.html#index-stdin +#[doc(alias = "STDIN_FILENO")] +#[inline] +pub unsafe fn take_stdin() -> OwnedFd { + backend::fd::OwnedFd::from_raw_fd(backend::io::types::STDIN_FILENO as RawFd) +} + +/// `STDOUT_FILENO`—Standard output, borrowed. +/// +/// In `std`-using configurations, this is a safe function, because the +/// standard library already assumes that the stdout file descriptor is always +/// valid. In `no_std` configurations, it is `unsafe`. +/// +/// # Warning +/// +/// This function allows reading directly from stdout without coordinating +/// with the buffering performed by [`std::io::Stdout`], so it could cause +/// corrupted input. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/stdout.html +/// [Linux]: https://man7.org/linux/man-pages/man3/stdout.3.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=stdout&sektion=4 +/// [NetBSD]: https://man.netbsd.org/stdout.4 +/// [OpenBSD]: https://man.openbsd.org/stdout.4 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=stdout§ion=4 +/// [illumos]: https://illumos.org/man/4FS/stdout +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Standard-Streams.html#index-stdout +#[cfg(feature = "std")] +#[doc(alias = "STDOUT_FILENO")] +#[inline] +pub const fn stdout() -> BorrowedFd<'static> { + // SAFETY: When "std" is enabled, the standard library assumes that the + // stdio file descriptors are all valid. + unsafe { BorrowedFd::borrow_raw(backend::io::types::STDOUT_FILENO as RawFd) } +} + +/// `STDOUT_FILENO`—Standard output, borrowed. +/// +/// In `std`-using configurations, this is a safe function, because the +/// standard library already assumes that the stdout file descriptor is always +/// valid. In `no_std` configurations, it is `unsafe`. +/// +/// # Safety +/// +/// In `no_std` configurations, the stdout file descriptor can be closed, +/// potentially on other threads, in which case the file descriptor index +/// value could be dynamically reused for other purposes, potentially on +/// different threads. +/// +/// # Warning +/// +/// This function allows reading directly from stdout without coordinating +/// with the buffering performed by [`std::io::Stdout`], so it could cause +/// corrupted input. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/stdout.html +/// [Linux]: https://man7.org/linux/man-pages/man3/stdout.3.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=stdout&sektion=4 +/// [NetBSD]: https://man.netbsd.org/stdout.4 +/// [OpenBSD]: https://man.openbsd.org/stdout.4 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=stdout§ion=4 +/// [illumos]: https://illumos.org/man/4FS/stdout +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Standard-Streams.html#index-stdout +#[cfg(not(feature = "std"))] +#[doc(alias = "STDOUT_FILENO")] +#[inline] +pub const unsafe fn stdout() -> BorrowedFd<'static> { + BorrowedFd::borrow_raw(backend::io::types::STDOUT_FILENO as RawFd) +} + +/// `STDOUT_FILENO`—Standard output, owned. +/// +/// This is similar to [`stdout`], however it returns an `OwnedFd` which closes +/// standard output when it is dropped. +/// +/// # Safety +/// +/// Safe `std`-using Rust code is permitted to assume that the stdout file +/// descriptor is always valid. This function returns an `OwnedFd` which will +/// close the stdout file descriptor when dropped. +/// +/// # Warning +/// +/// This has the same hazards as [`stdout`]. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/stdout.html +/// [Linux]: https://man7.org/linux/man-pages/man3/stdout.3.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=stdout&sektion=4 +/// [NetBSD]: https://man.netbsd.org/stdout.4 +/// [OpenBSD]: https://man.openbsd.org/stdout.4 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=stdout§ion=4 +/// [illumos]: https://illumos.org/man/4FS/stdout +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Standard-Streams.html#index-stdout +#[doc(alias = "STDOUT_FILENO")] +#[inline] +pub unsafe fn take_stdout() -> OwnedFd { + backend::fd::OwnedFd::from_raw_fd(backend::io::types::STDOUT_FILENO as RawFd) +} + +/// `STDERR_FILENO`—Standard error, borrowed. +/// +/// In `std`-using configurations, this is a safe function, because the +/// standard library already assumes that the stderr file descriptor is always +/// valid. In `no_std` configurations, it is `unsafe`. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/stderr.html +/// [Linux]: https://man7.org/linux/man-pages/man3/stderr.3.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=stderr&sektion=4 +/// [NetBSD]: https://man.netbsd.org/stderr.4 +/// [OpenBSD]: https://man.openbsd.org/stderr.4 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=stderr§ion=4 +/// [illumos]: https://illumos.org/man/4FS/stderr +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Standard-Streams.html#index-stderr +#[cfg(feature = "std")] +#[doc(alias = "STDERR_FILENO")] +#[inline] +pub const fn stderr() -> BorrowedFd<'static> { + // SAFETY: When "std" is enabled, the standard library assumes that the + // stdio file descriptors are all valid. + unsafe { BorrowedFd::borrow_raw(backend::io::types::STDERR_FILENO as RawFd) } +} + +/// `STDERR_FILENO`—Standard error, borrowed. +/// +/// In `std`-using configurations, this is a safe function, because the +/// standard library already assumes that the stderr file descriptor is always +/// valid. In `no_std` configurations, it is `unsafe`. +/// +/// # Safety +/// +/// In `no_std` configurations, the stderr file descriptor can be closed, +/// potentially on other threads, in which case the file descriptor index +/// value could be dynamically reused for other purposes, potentially on +/// different threads. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/stderr.html +/// [Linux]: https://man7.org/linux/man-pages/man3/stderr.3.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=stderr&sektion=4 +/// [NetBSD]: https://man.netbsd.org/stderr.4 +/// [OpenBSD]: https://man.openbsd.org/stderr.4 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=stderr§ion=4 +/// [illumos]: https://illumos.org/man/4FS/stderr +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Standard-Streams.html#index-stderr +#[cfg(not(feature = "std"))] +#[doc(alias = "STDERR_FILENO")] +#[inline] +pub const unsafe fn stderr() -> BorrowedFd<'static> { + BorrowedFd::borrow_raw(backend::io::types::STDERR_FILENO as RawFd) +} + +/// `STDERR_FILENO`—Standard error, owned. +/// +/// This is similar to [`stderr`], however it returns an `OwnedFd` which closes +/// standard output when it is dropped. +/// +/// # Safety +/// +/// Safe std-using Rust code is permitted to assume that the stderr file +/// descriptor is always valid. This function returns an `OwnedFd` which will +/// close the stderr file descriptor when dropped. +/// +/// # Other hazards +/// +/// This has the same hazards as [`stderr`]. +/// +/// And, when the `OwnedFd` is dropped, subsequent newly created file +/// descriptors may unknowingly reuse the stderr file descriptor number, which +/// may break common assumptions, so it should typically only be dropped at the +/// end of a program when no more file descriptors will be created. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/stderr.html +/// [Linux]: https://man7.org/linux/man-pages/man3/stderr.3.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=stderr&sektion=4 +/// [NetBSD]: https://man.netbsd.org/stderr.4 +/// [OpenBSD]: https://man.openbsd.org/stderr.4 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=stderr§ion=4 +/// [illumos]: https://illumos.org/man/4FS/stderr +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Standard-Streams.html#index-stderr +#[doc(alias = "STDERR_FILENO")] +#[inline] +pub unsafe fn take_stderr() -> OwnedFd { + backend::fd::OwnedFd::from_raw_fd(backend::io::types::STDERR_FILENO as RawFd) +} + +/// `STDIN_FILENO`—Standard input, raw. +/// +/// This is similar to [`stdin`], however it returns a `RawFd`. +/// +/// # Other hazards +/// +/// This has the same hazards as [`stdin`]. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/stdin.html +/// [Linux]: https://man7.org/linux/man-pages/man3/stdin.3.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=stdin&sektion=4 +/// [NetBSD]: https://man.netbsd.org/stdin.4 +/// [OpenBSD]: https://man.openbsd.org/stdin.4 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=stdin§ion=4 +/// [illumos]: https://illumos.org/man/4FS/stdin +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Standard-Streams.html#index-stdin +#[doc(alias = "STDIN_FILENO")] +#[inline] +pub const fn raw_stdin() -> RawFd { + backend::io::types::STDIN_FILENO as RawFd +} + +/// `STDOUT_FILENO`—Standard output, raw. +/// +/// This is similar to [`stdout`], however it returns a `RawFd`. +/// +/// # Other hazards +/// +/// This has the same hazards as [`stdout`]. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/stdout.html +/// [Linux]: https://man7.org/linux/man-pages/man3/stdout.3.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=stdout&sektion=4 +/// [NetBSD]: https://man.netbsd.org/stdout.4 +/// [OpenBSD]: https://man.openbsd.org/stdout.4 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=stdout§ion=4 +/// [illumos]: https://illumos.org/man/4FS/stdout +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Standard-Streams.html#index-stdout +#[doc(alias = "STDOUT_FILENO")] +#[inline] +pub const fn raw_stdout() -> RawFd { + backend::io::types::STDOUT_FILENO as RawFd +} + +/// `STDERR_FILENO`—Standard error, raw. +/// +/// This is similar to [`stderr`], however it returns a `RawFd`. +/// +/// # Other hazards +/// +/// This has the same hazards as [`stderr`]. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/stderr.html +/// [Linux]: https://man7.org/linux/man-pages/man3/stderr.3.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=stderr&sektion=4 +/// [NetBSD]: https://man.netbsd.org/stderr.4 +/// [OpenBSD]: https://man.openbsd.org/stderr.4 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=stderr§ion=4 +/// [illumos]: https://illumos.org/man/4FS/stderr +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Standard-Streams.html#index-stderr +#[doc(alias = "STDERR_FILENO")] +#[inline] +pub const fn raw_stderr() -> RawFd { + backend::io::types::STDERR_FILENO as RawFd +} + +/// Utility function to safely `dup2` over stdin (fd 0). +#[cfg(not(any(windows, target_os = "wasi")))] +#[inline] +pub fn dup2_stdin<Fd: AsFd>(fd: Fd) -> io::Result<()> { + // SAFETY: We pass the returned `OwnedFd` to `forget` so that it isn't + // dropped. + let mut target = unsafe { io::take_stdin() }; + backend::io::syscalls::dup2(fd.as_fd(), &mut target)?; + forget(target); + Ok(()) +} + +/// Utility function to safely `dup2` over stdout (fd 1). +#[cfg(not(any(windows, target_os = "wasi")))] +#[inline] +pub fn dup2_stdout<Fd: AsFd>(fd: Fd) -> io::Result<()> { + // SAFETY: We pass the returned `OwnedFd` to `forget` so that it isn't + // dropped. + let mut target = unsafe { io::take_stdout() }; + backend::io::syscalls::dup2(fd.as_fd(), &mut target)?; + forget(target); + Ok(()) +} + +/// Utility function to safely `dup2` over stderr (fd 2). +#[cfg(not(any(windows, target_os = "wasi")))] +#[inline] +pub fn dup2_stderr<Fd: AsFd>(fd: Fd) -> io::Result<()> { + // SAFETY: We pass the returned `OwnedFd` to `forget` so that it isn't + // dropped. + let mut target = unsafe { io::take_stderr() }; + backend::io::syscalls::dup2(fd.as_fd(), &mut target)?; + forget(target); + Ok(()) +} diff --git a/vendor/rustix-0.37.22/src/io_uring.rs b/vendor/rustix-0.37.22/src/io_uring.rs new file mode 100644 index 000000000..629e4d175 --- /dev/null +++ b/vendor/rustix-0.37.22/src/io_uring.rs @@ -0,0 +1,1443 @@ +//! Linux [io_uring]. +//! +//! This API is very low-level. The main adaptations it makes from the raw +//! Linux io_uring API are the use of appropriately-sized `bitflags`, `enum`, +//! `Result`, `OwnedFd`, `AsFd`, `RawFd`, and `*mut c_void` in place of plain +//! integers. +//! +//! For a higher-level API built on top of this, see the [rustix-uring] crate. +//! +//! # Safety +//! +//! io_uring operates on raw pointers and raw file descriptors. Rustix does not +//! attempt to provide a safe API for these, because the abstraction level is +//! too low for this to be practical. Safety should be introduced in +//! higher-level abstraction layers. +//! +//! # References +//! - [Linux] +//! - [io_uring header] +//! +//! [Linux]: https://man.archlinux.org/man/io_uring.7.en +//! [io_uring]: https://en.wikipedia.org/wiki/Io_uring +//! [io_uring header]: https://github.com/torvalds/linux/blob/master/include/uapi/linux/io_uring.h +//! [rustix-uring]: https://crates.io/crates/rustix-uring +#![allow(unsafe_code)] + +use crate::fd::{AsFd, BorrowedFd, OwnedFd, RawFd}; +use crate::{backend, io}; +use core::ffi::c_void; +use core::mem::{zeroed, MaybeUninit}; +use core::ptr::{null_mut, write_bytes}; +use linux_raw_sys::general as sys; + +/// `io_uring_setup(entries, params)`—Setup a context for performing +/// asynchronous I/O. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man.archlinux.org/man/io_uring_setup.2.en +#[inline] +pub fn io_uring_setup(entries: u32, params: &mut io_uring_params) -> io::Result<OwnedFd> { + backend::io_uring::syscalls::io_uring_setup(entries, params) +} + +/// `io_uring_register(fd, opcode, arg, nr_args)`—Register files or user +/// buffers for asynchronous I/O. +/// +/// # Safety +/// +/// io_uring operates on raw pointers and raw file descriptors. Users are +/// responsible for ensuring that memory and resources are only accessed in +/// valid ways. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man.archlinux.org/man/io_uring_register.2.en +#[inline] +pub unsafe fn io_uring_register<Fd: AsFd>( + fd: Fd, + opcode: IoringRegisterOp, + arg: *const c_void, + nr_args: u32, +) -> io::Result<u32> { + backend::io_uring::syscalls::io_uring_register(fd.as_fd(), opcode, arg, nr_args) +} + +/// `io_uring_enter(fd, to_submit, min_complete, flags, arg, size)`—Initiate +/// and/or complete asynchronous I/O. +/// +/// # Safety +/// +/// io_uring operates on raw pointers and raw file descriptors. Users are +/// responsible for ensuring that memory and resources are only accessed in +/// valid ways. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man.archlinux.org/man/io_uring_enter.2.en +#[inline] +pub unsafe fn io_uring_enter<Fd: AsFd>( + fd: Fd, + to_submit: u32, + min_complete: u32, + flags: IoringEnterFlags, + arg: *const c_void, + size: usize, +) -> io::Result<u32> { + backend::io_uring::syscalls::io_uring_enter( + fd.as_fd(), + to_submit, + min_complete, + flags, + arg, + size, + ) +} + +bitflags::bitflags! { + /// `IORING_ENTER_*` flags for use with [`io_uring_enter`]. + #[derive(Default)] + pub struct IoringEnterFlags: u32 { + /// `IORING_ENTER_GETEVENTS` + const GETEVENTS = sys::IORING_ENTER_GETEVENTS; + + /// `IORING_ENTER_SQ_WAKEUP` + const SQ_WAKEUP = sys::IORING_ENTER_SQ_WAKEUP; + + /// `IORING_ENTER_SQ_WAIT` + const SQ_WAIT = sys::IORING_ENTER_SQ_WAIT; + + /// `IORING_ENTER_EXT_ARG` + const EXT_ARG = sys::IORING_ENTER_EXT_ARG; + } +} + +/// `IORING_REGISTER_*` and `IORING_UNREGISTER_*` constants for use with +/// [`io_uring_register`]. +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[repr(u8)] +#[non_exhaustive] +pub enum IoringRegisterOp { + /// `IORING_REGISTER_BUFFERS` + RegisterBuffers = sys::IORING_REGISTER_BUFFERS as _, + + /// `IORING_UNREGISTER_BUFFERS` + UnregisterBuffers = sys::IORING_UNREGISTER_BUFFERS as _, + + /// `IORING_REGISTER_FILES` + RegisterFiles = sys::IORING_REGISTER_FILES as _, + + /// `IORING_UNREGISTER_FILES` + UnregisterFiles = sys::IORING_UNREGISTER_FILES as _, + + /// `IORING_REGISTER_EVENTFD` + RegisterEventfd = sys::IORING_REGISTER_EVENTFD as _, + + /// `IORING_UNREGISTER_EVENTFD` + UnregisterEventfd = sys::IORING_UNREGISTER_EVENTFD as _, + + /// `IORING_REGISTER_FILES_UPDATE` + RegisterFilesUpdate = sys::IORING_REGISTER_FILES_UPDATE as _, + + /// `IORING_REGISTER_EVENTFD_ASYNC` + RegisterEventfdAsync = sys::IORING_REGISTER_EVENTFD_ASYNC as _, + + /// `IORING_REGISTER_PROBE` + RegisterProbe = sys::IORING_REGISTER_PROBE as _, + + /// `IORING_REGISTER_PERSONALITY` + RegisterPersonality = sys::IORING_REGISTER_PERSONALITY as _, + + /// `IORING_UNREGISTER_PERSONALITY` + UnregisterPersonality = sys::IORING_UNREGISTER_PERSONALITY as _, + + /// `IORING_REGISTER_RESTRICTIONS` + RegisterRestrictions = sys::IORING_REGISTER_RESTRICTIONS as _, + + /// `IORING_REGISTER_ENABLE_RINGS` + RegisterEnableRings = sys::IORING_REGISTER_ENABLE_RINGS as _, + + /// `IORING_REGISTER_BUFFERS2` + RegisterBuffers2 = sys::IORING_REGISTER_BUFFERS2 as _, + + /// `IORING_REGISTER_BUFFERS_UPDATE` + RegisterBuffersUpdate = sys::IORING_REGISTER_BUFFERS_UPDATE as _, + + /// `IORING_REGISTER_FILES2` + RegisterFiles2 = sys::IORING_REGISTER_FILES2 as _, + + /// `IORING_REGISTER_FILES_SKIP` + RegisterFilesSkip = sys::IORING_REGISTER_FILES_SKIP as _, + + /// `IORING_REGISTER_FILES_UPDATE2` + RegisterFilesUpdate2 = sys::IORING_REGISTER_FILES_UPDATE2 as _, + + /// `IORING_REGISTER_IOWQ_AFF` + RegisterIowqAff = sys::IORING_REGISTER_IOWQ_AFF as _, + + /// `IORING_UNREGISTER_IOWQ_AFF` + UnregisterIowqAff = sys::IORING_UNREGISTER_IOWQ_AFF as _, + + /// `IORING_REGISTER_IOWQ_MAX_WORKERS` + RegisterIowqMaxWorkers = sys::IORING_REGISTER_IOWQ_MAX_WORKERS as _, + + /// `IORING_REGISTER_RING_FDS` + RegisterRingFds = sys::IORING_REGISTER_RING_FDS as _, + + /// `IORING_UNREGISTER_RING_FDS` + UnregisterRingFds = sys::IORING_UNREGISTER_RING_FDS as _, + + /// `IORING_REGISTER_PBUF_RING` + RegisterPbufRing = sys::IORING_REGISTER_PBUF_RING as _, + + /// `IORING_UNREGISTER_PBUF_RING` + UnregisterPbufRing = sys::IORING_UNREGISTER_PBUF_RING as _, + + /// `IORING_REGISTER_SYNC_CANCEL` + RegisterSyncCancel = sys::IORING_REGISTER_SYNC_CANCEL as _, + + /// `IORING_REGISTER_FILE_ALLOC_RANGE` + RegisterFileAllocRange = sys::IORING_REGISTER_FILE_ALLOC_RANGE as _, +} + +/// `IORING_OP_*` constants for use with [`io_uring_sqe`]. +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[repr(u8)] +#[non_exhaustive] +pub enum IoringOp { + /// `IORING_OP_NOP` + Nop = sys::io_uring_op::IORING_OP_NOP as _, + + /// `IORING_OP_ACCEPT` + Accept = sys::io_uring_op::IORING_OP_ACCEPT as _, + + /// `IORING_OP_ASYNC_CANCEL` + AsyncCancel = sys::io_uring_op::IORING_OP_ASYNC_CANCEL as _, + + /// `IORING_OP_CLOSE` + Close = sys::io_uring_op::IORING_OP_CLOSE as _, + + /// `IORING_OP_CONNECT` + Connect = sys::io_uring_op::IORING_OP_CONNECT as _, + + /// `IORING_OP_EPOLL_CTL` + EpollCtl = sys::io_uring_op::IORING_OP_EPOLL_CTL as _, + + /// `IORING_OP_FADVISE` + Fadvise = sys::io_uring_op::IORING_OP_FADVISE as _, + + /// `IORING_OP_FALLOCATE` + Fallocate = sys::io_uring_op::IORING_OP_FALLOCATE as _, + + /// `IORING_OP_FILES_UPDATE` + FilesUpdate = sys::io_uring_op::IORING_OP_FILES_UPDATE as _, + + /// `IORING_OP_FSYNC` + Fsync = sys::io_uring_op::IORING_OP_FSYNC as _, + + /// `IORING_OP_LINKAT` + Linkat = sys::io_uring_op::IORING_OP_LINKAT as _, + + /// `IORING_OP_LINK_TIMEOUT` + LinkTimeout = sys::io_uring_op::IORING_OP_LINK_TIMEOUT as _, + + /// `IORING_OP_MADVISE` + Madvise = sys::io_uring_op::IORING_OP_MADVISE as _, + + /// `IORING_OP_MKDIRAT` + Mkdirat = sys::io_uring_op::IORING_OP_MKDIRAT as _, + + /// `IORING_OP_OPENAT` + Openat = sys::io_uring_op::IORING_OP_OPENAT as _, + + /// `IORING_OP_OPENAT2` + Openat2 = sys::io_uring_op::IORING_OP_OPENAT2 as _, + + /// `IORING_OP_POLL_ADD` + PollAdd = sys::io_uring_op::IORING_OP_POLL_ADD as _, + + /// `IORING_OP_POLL_REMOVE` + PollRemove = sys::io_uring_op::IORING_OP_POLL_REMOVE as _, + + /// `IORING_OP_PROVIDE_BUFFERS` + ProvideBuffers = sys::io_uring_op::IORING_OP_PROVIDE_BUFFERS as _, + + /// `IORING_OP_READ` + Read = sys::io_uring_op::IORING_OP_READ as _, + + /// `IORING_OP_READV` + Readv = sys::io_uring_op::IORING_OP_READV as _, + + /// `IORING_OP_READ_FIXED` + ReadFixed = sys::io_uring_op::IORING_OP_READ_FIXED as _, + + /// `IORING_OP_RECV` + Recv = sys::io_uring_op::IORING_OP_RECV as _, + + /// `IORING_OP_RECVMSG` + Recvmsg = sys::io_uring_op::IORING_OP_RECVMSG as _, + + /// `IORING_OP_REMOVE_BUFFERS` + RemoveBuffers = sys::io_uring_op::IORING_OP_REMOVE_BUFFERS as _, + + /// `IORING_OP_RENAMEAT` + Renameat = sys::io_uring_op::IORING_OP_RENAMEAT as _, + + /// `IORING_OP_SEND` + Send = sys::io_uring_op::IORING_OP_SEND as _, + + /// `IORING_OP_SENDMSG` + Sendmsg = sys::io_uring_op::IORING_OP_SENDMSG as _, + + /// `IORING_OP_SHUTDOWN` + Shutdown = sys::io_uring_op::IORING_OP_SHUTDOWN as _, + + /// `IORING_OP_SPLICE` + Splice = sys::io_uring_op::IORING_OP_SPLICE as _, + + /// `IORING_OP_STATX` + Statx = sys::io_uring_op::IORING_OP_STATX as _, + + /// `IORING_OP_SYMLINKAT` + Symlinkat = sys::io_uring_op::IORING_OP_SYMLINKAT as _, + + /// `IORING_OP_SYNC_FILE_RANGE` + SyncFileRange = sys::io_uring_op::IORING_OP_SYNC_FILE_RANGE as _, + + /// `IORING_OP_TEE` + Tee = sys::io_uring_op::IORING_OP_TEE as _, + + /// `IORING_OP_TIMEOUT` + Timeout = sys::io_uring_op::IORING_OP_TIMEOUT as _, + + /// `IORING_OP_TIMEOUT_REMOVE` + TimeoutRemove = sys::io_uring_op::IORING_OP_TIMEOUT_REMOVE as _, + + /// `IORING_OP_UNLINKAT` + Unlinkat = sys::io_uring_op::IORING_OP_UNLINKAT as _, + + /// `IORING_OP_WRITE` + Write = sys::io_uring_op::IORING_OP_WRITE as _, + + /// `IORING_OP_WRITEV` + Writev = sys::io_uring_op::IORING_OP_WRITEV as _, + + /// `IORING_OP_WRITE_FIXED` + WriteFixed = sys::io_uring_op::IORING_OP_WRITE_FIXED as _, + + /// `IORING_OP_MSG_RING` + MsgRing = sys::io_uring_op::IORING_OP_MSG_RING as _, + + /// `IORING_OP_FSETXATTR` + Fsetxattr = sys::io_uring_op::IORING_OP_FSETXATTR as _, + + /// `IORING_OP_SETXATTR` + Setxattr = sys::io_uring_op::IORING_OP_SETXATTR as _, + + /// `IORING_OP_FGETXATTR` + Fgetxattr = sys::io_uring_op::IORING_OP_FGETXATTR as _, + + /// `IORING_OP_GETXATTR` + Getxattr = sys::io_uring_op::IORING_OP_GETXATTR as _, + + /// `IORING_OP_SOCKET` + Socket = sys::io_uring_op::IORING_OP_SOCKET as _, + + /// `IORING_OP_URING_CMD` + UringCmd = sys::io_uring_op::IORING_OP_URING_CMD as _, + + /// `IORING_OP_SEND_ZC` + SendZc = sys::io_uring_op::IORING_OP_SEND_ZC as _, + + /// `IORING_OP_SENDMSG_ZC` + SendmsgZc = sys::io_uring_op::IORING_OP_SENDMSG_ZC as _, +} + +impl Default for IoringOp { + #[inline] + fn default() -> Self { + Self::Nop + } +} + +/// `IORING_RESTRICTION_*` constants for use with [`io_uring_restriction`]. +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[repr(u16)] +#[non_exhaustive] +pub enum IoringRestrictionOp { + /// `IORING_RESTRICTION_REGISTER_OP` + RegisterOp = sys::IORING_RESTRICTION_REGISTER_OP as _, + + /// `IORING_RESTRICTION_SQE_FLAGS_ALLOWED` + SqeFlagsAllowed = sys::IORING_RESTRICTION_SQE_FLAGS_ALLOWED as _, + + /// `IORING_RESTRICTION_SQE_FLAGS_REQUIRED` + SqeFlagsRequired = sys::IORING_RESTRICTION_SQE_FLAGS_REQUIRED as _, + + /// `IORING_RESTRICTION_SQE_OP` + SqeOp = sys::IORING_RESTRICTION_SQE_OP as _, +} + +impl Default for IoringRestrictionOp { + #[inline] + fn default() -> Self { + Self::RegisterOp + } +} + +/// `IORING_MSG_*` constants which represent commands for use with +/// [`IoringOp::MsgRing`], (`seq.addr`) +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[repr(u64)] +#[non_exhaustive] +pub enum IoringMsgringCmds { + /// `IORING_MSG_DATA` + Data = sys::IORING_MSG_DATA as _, + + /// `IORING_MSG_SEND_FD` + SendFd = sys::IORING_MSG_SEND_FD as _, +} + +bitflags::bitflags! { + /// `IORING_SETUP_*` flags for use with [`io_uring_params`]. + #[derive(Default)] + pub struct IoringSetupFlags: u32 { + /// `IORING_SETUP_ATTACH_WQ` + const ATTACH_WQ = sys::IORING_SETUP_ATTACH_WQ; + + /// `IORING_SETUP_CLAMP` + const CLAMP = sys::IORING_SETUP_CLAMP; + + /// `IORING_SETUP_CQSIZE` + const CQSIZE = sys::IORING_SETUP_CQSIZE; + + /// `IORING_SETUP_IOPOLL` + const IOPOLL = sys::IORING_SETUP_IOPOLL; + + /// `IORING_SETUP_R_DISABLED` + const R_DISABLED = sys::IORING_SETUP_R_DISABLED; + + /// `IORING_SETUP_SQPOLL` + const SQPOLL = sys::IORING_SETUP_SQPOLL; + + /// `IORING_SETUP_SQ_AFF` + const SQ_AFF = sys::IORING_SETUP_SQ_AFF; + + /// `IORING_SETUP_SQE128` + const SQE128 = sys::IORING_SETUP_SQE128; + + /// `IORING_SETUP_CQE32` + const CQE32 = sys::IORING_SETUP_CQE32; + + /// `IORING_SETUP_SUBMIT_ALL` + const SUBMIT_ALL = sys::IORING_SETUP_SUBMIT_ALL; + + /// `IORING_SETUP_COOP_TRASKRUN` + const COOP_TASKRUN = sys::IORING_SETUP_COOP_TASKRUN; + + /// `IORING_SETUP_TASKRUN_FLAG` + const TASKRUN_FLAG = sys::IORING_SETUP_TASKRUN_FLAG; + + /// `IORING_SETUP_SINGLE_ISSUER` + const SINGLE_ISSUER = sys::IORING_SETUP_SINGLE_ISSUER; + + /// `IORING_SETUP_DEFER_TASKRUN` + const DEFER_TASKRUN = sys::IORING_SETUP_DEFER_TASKRUN; + } +} + +bitflags::bitflags! { + /// `IOSQE_*` flags for use with [`io_uring_sqe`]. + #[derive(Default)] + pub struct IoringSqeFlags: u8 { + /// `1 << IOSQE_ASYNC_BIT` + const ASYNC = 1 << sys::IOSQE_ASYNC_BIT as u8; + + /// `1 << IOSQE_BUFFER_SELECT_BIT` + const BUFFER_SELECT = 1 << sys::IOSQE_BUFFER_SELECT_BIT as u8; + + /// `1 << IOSQE_FIXED_FILE_BIT` + const FIXED_FILE = 1 << sys::IOSQE_FIXED_FILE_BIT as u8; + + /// 1 << `IOSQE_IO_DRAIN_BIT` + const IO_DRAIN = 1 << sys::IOSQE_IO_DRAIN_BIT as u8; + + /// `1 << IOSQE_IO_HARDLINK_BIT` + const IO_HARDLINK = 1 << sys::IOSQE_IO_HARDLINK_BIT as u8; + + /// `1 << IOSQE_IO_LINK_BIT` + const IO_LINK = 1 << sys::IOSQE_IO_LINK_BIT as u8; + + /// `1 << IOSQE_CQE_SKIP_SUCCESS_BIT` + const CQE_SKIP_SUCCESS = 1 << sys::IOSQE_CQE_SKIP_SUCCESS_BIT as u8; + } +} + +bitflags::bitflags! { + /// `IORING_CQE_F_*` flags for use with [`io_uring_cqe`]. + #[derive(Default)] + pub struct IoringCqeFlags: u32 { + /// `IORING_CQE_F_BUFFER` + const BUFFER = sys::IORING_CQE_F_BUFFER as _; + + /// `IORING_CQE_F_MORE` + const MORE = sys::IORING_CQE_F_MORE as _; + + /// `IORING_CQE_F_SOCK_NONEMPTY` + const SOCK_NONEMPTY = sys::IORING_CQE_F_SOCK_NONEMPTY as _; + + /// `IORING_CQE_F_NOTIF` + const NOTIF = sys::IORING_CQE_F_NOTIF as _; + } +} + +bitflags::bitflags! { + /// `IORING_FSYNC_*` flags for use with [`io_uring_sqe`]. + #[derive(Default)] + pub struct IoringFsyncFlags: u32 { + /// `IORING_FSYNC_DATASYNC` + const DATASYNC = sys::IORING_FSYNC_DATASYNC; + } +} + +bitflags::bitflags! { + /// `IORING_TIMEOUT_*` and `IORING_LINK_TIMEOUT_UPDATE` flags for use with + /// [`io_uring_sqe`]. + #[derive(Default)] + pub struct IoringTimeoutFlags: u32 { + /// `IORING_TIMEOUT_ABS` + const ABS = sys::IORING_TIMEOUT_ABS; + + /// `IORING_TIMEOUT_UPDATE` + const UPDATE = sys::IORING_TIMEOUT_UPDATE; + + /// `IORING_TIMEOUT_BOOTTIME` + const BOOTTIME = sys::IORING_TIMEOUT_BOOTTIME; + + /// `IORING_TIMEOUT_ETIME_SUCCESS` + const ETIME_SUCCESS = sys::IORING_TIMEOUT_ETIME_SUCCESS; + + /// `IORING_TIMEOUT_REALTIME` + const REALTIME = sys::IORING_TIMEOUT_REALTIME; + + /// `IORING_TIMEOUT_CLOCK_MASK` + const CLOCK_MASK = sys::IORING_TIMEOUT_CLOCK_MASK; + + /// `IORING_TIMEOUT_UPDATE_MASK` + const UPDATE_MASK = sys::IORING_TIMEOUT_UPDATE_MASK; + + /// `IORING_LINK_TIMEOUT_UPDATE` + const LINK_TIMEOUT_UPDATE = sys::IORING_LINK_TIMEOUT_UPDATE; + } +} + +bitflags::bitflags! { + /// `SPLICE_F_*` flags for use with [`io_uring_sqe`]. + #[derive(Default)] + pub struct SpliceFlags: u32 { + /// `SPLICE_F_FD_IN_FIXED` + const FD_IN_FIXED = sys::SPLICE_F_FD_IN_FIXED; + } +} + +bitflags::bitflags! { + /// `IORING_MSG_RING_*` flags for use with [`io_uring_sqe`]. + #[derive(Default)] + pub struct IoringMsgringFlags: u32 { + /// `IORING_MSG_RING_CQE_SKIP` + const CQE_SKIP = sys::IORING_MSG_RING_CQE_SKIP; + } +} + +bitflags::bitflags! { + /// `IORING_ASYNC_CANCEL_*` flags for use with [`io_uring_sqe`]. + #[derive(Default)] + pub struct IoringAsyncCancelFlags: u32 { + /// `IORING_ASYNC_CANCEL_ALL` + const ALL = sys::IORING_ASYNC_CANCEL_ALL; + + /// `IORING_ASYNC_CANCEL_FD` + const FD = sys::IORING_ASYNC_CANCEL_FD; + + /// `IORING_ASYNC_CANCEL_FD` + const ANY = sys::IORING_ASYNC_CANCEL_ANY; + + /// `IORING_ASYNC_CANCEL_FD` + const FD_FIXED = sys::IORING_ASYNC_CANCEL_FD_FIXED; + } +} + +bitflags::bitflags! { + /// `IORING_FEAT_*` flags for use with [`io_uring_params`]. + #[derive(Default)] + pub struct IoringFeatureFlags: u32 { + /// `IORING_FEAT_CQE_SKIP` + const CQE_SKIP = sys::IORING_FEAT_CQE_SKIP; + + /// `IORING_FEAT_CUR_PERSONALITY` + const CUR_PERSONALITY = sys::IORING_FEAT_CUR_PERSONALITY; + + /// `IORING_FEAT_EXT_ARG` + const EXT_ARG = sys::IORING_FEAT_EXT_ARG; + + /// `IORING_FEAT_FAST_POLL` + const FAST_POLL = sys::IORING_FEAT_FAST_POLL; + + /// `IORING_FEAT_NATIVE_WORKERS` + const NATIVE_WORKERS = sys::IORING_FEAT_NATIVE_WORKERS; + + /// `IORING_FEAT_NODROP` + const NODROP = sys::IORING_FEAT_NODROP; + + /// `IORING_FEAT_POLL_32BITS` + const POLL_32BITS = sys::IORING_FEAT_POLL_32BITS; + + /// `IORING_FEAT_RSRC_TAGS` + const RSRC_TAGS = sys::IORING_FEAT_RSRC_TAGS; + + /// `IORING_FEAT_RW_CUR_POS` + const RW_CUR_POS = sys::IORING_FEAT_RW_CUR_POS; + + /// `IORING_FEAT_SINGLE_MMAP` + const SINGLE_MMAP = sys::IORING_FEAT_SINGLE_MMAP; + + /// `IORING_FEAT_SQPOLL_NONFIXED` + const SQPOLL_NONFIXED = sys::IORING_FEAT_SQPOLL_NONFIXED; + + /// `IORING_FEAT_SUBMIT_STABLE` + const SUBMIT_STABLE = sys::IORING_FEAT_SUBMIT_STABLE; + + /// `IORING_FEAT_LINKED_FILE` + const LINKED_FILE = sys::IORING_FEAT_LINKED_FILE; + } +} + +bitflags::bitflags! { + /// `IO_URING_OP_*` flags for use with [`io_uring_probe_op`]. + #[derive(Default)] + pub struct IoringOpFlags: u16 { + /// `IO_URING_OP_SUPPORTED` + const SUPPORTED = sys::IO_URING_OP_SUPPORTED as _; + } +} + +bitflags::bitflags! { + /// `IORING_RSRC_*` flags for use with [`io_uring_rsrc_register`]. + #[derive(Default)] + pub struct IoringRsrcFlags: u32 { + /// `IORING_RSRC_REGISTER_SPARSE` + const REGISTER_SPARSE = sys::IORING_RSRC_REGISTER_SPARSE as _; + } +} + +bitflags::bitflags! { + /// `IORING_SQ_*` flags. + #[derive(Default)] + pub struct IoringSqFlags: u32 { + /// `IORING_SQ_NEED_WAKEUP` + const NEED_WAKEUP = sys::IORING_SQ_NEED_WAKEUP; + + /// `IORING_SQ_CQ_OVERFLOW` + const CQ_OVERFLOW = sys::IORING_SQ_CQ_OVERFLOW; + + /// `IORING_SQ_TASKRUN` + const TASKRUN = sys::IORING_SQ_TASKRUN; + } +} + +bitflags::bitflags! { + /// `IORING_CQ_*` flags. + #[derive(Default)] + pub struct IoringCqFlags: u32 { + /// `IORING_CQ_EVENTFD_DISABLED` + const EVENTFD_DISABLED = sys::IORING_CQ_EVENTFD_DISABLED; + } +} + +bitflags::bitflags! { + /// `IORING_POLL_*` flags. + #[derive(Default)] + pub struct IoringPollFlags: u32 { + /// `IORING_POLL_ADD_MULTI` + const ADD_MULTI = sys::IORING_POLL_ADD_MULTI; + + /// `IORING_POLL_UPDATE_EVENTS` + const UPDATE_EVENTS = sys::IORING_POLL_UPDATE_EVENTS; + + /// `IORING_POLL_UPDATE_USER_DATA` + const UPDATE_USER_DATA = sys::IORING_POLL_UPDATE_USER_DATA; + + /// `IORING_POLL_ADD_LEVEL` + const ADD_LEVEL = sys::IORING_POLL_ADD_LEVEL; + } +} + +bitflags::bitflags! { + /// send/sendmsg flags (`sqe.ioprio`) + #[derive(Default)] + pub struct IoringSendFlags: u16 { + /// `IORING_RECVSEND_POLL_FIRST`. + /// + /// See also [`IoringRecvFlags::POLL_FIRST`]. + const POLL_FIRST = sys::IORING_RECVSEND_POLL_FIRST as _; + + /// `IORING_RECVSEND_FIXED_BUF` + /// + /// See also [`IoringRecvFlags::FIXED_BUF`]. + const FIXED_BUF = sys::IORING_RECVSEND_FIXED_BUF as _; + + /// `IORING_SEND_ZC_REPORT_USAGE` (since Linux 6.2) + const ZC_REPORT_USAGE = sys::IORING_SEND_ZC_REPORT_USAGE as _; + } +} + +bitflags::bitflags! { + /// recv/recvmsg flags (`sqe.ioprio`) + #[derive(Default)] + pub struct IoringRecvFlags: u16 { + /// `IORING_RECVSEND_POLL_FIRST` + /// + /// See also [`IoringSendFlags::POLL_FIRST`]. + const POLL_FIRST = sys::IORING_RECVSEND_POLL_FIRST as _; + + /// `IORING_RECV_MULTISHOT` + const MULTISHOT = sys::IORING_RECV_MULTISHOT as _; + + /// `IORING_RECVSEND_FIXED_BUF` + /// + /// See also [`IoringSendFlags::FIXED_BUF`]. + const FIXED_BUF = sys::IORING_RECVSEND_FIXED_BUF as _; + } +} + +bitflags::bitflags! { + /// accept flags (`sqe.ioprio`) + #[derive(Default)] + pub struct IoringAcceptFlags: u16 { + /// `IORING_ACCEPT_MULTISHOT` + const MULTISHOT = sys::IORING_ACCEPT_MULTISHOT as _; + } +} + +bitflags::bitflags! { + /// recvmsg out flags + #[derive(Default)] + pub struct RecvmsgOutFlags: u32 { + /// `MSG_EOR` + const EOR = sys::MSG_EOR; + + /// `MSG_TRUNC` + const TRUNC = sys::MSG_TRUNC; + + /// `MSG_CTRUNC` + const CTRUNC = sys::MSG_CTRUNC; + + /// `MSG_OOB` + const OOB = sys::MSG_OOB; + + /// `MSG_ERRQUEUE` + const ERRQUEUE = sys::MSG_ERRQUEUE; + } +} + +#[allow(missing_docs)] +pub const IORING_CQE_BUFFER_SHIFT: u32 = sys::IORING_CQE_BUFFER_SHIFT as _; +#[allow(missing_docs)] +pub const IORING_FILE_INDEX_ALLOC: i32 = sys::IORING_FILE_INDEX_ALLOC as _; + +// Re-export these as `u64`, which is the `offset` type in `rustix::io::mmap`. +#[allow(missing_docs)] +pub const IORING_OFF_SQ_RING: u64 = sys::IORING_OFF_SQ_RING as _; +#[allow(missing_docs)] +pub const IORING_OFF_CQ_RING: u64 = sys::IORING_OFF_CQ_RING as _; +#[allow(missing_docs)] +pub const IORING_OFF_SQES: u64 = sys::IORING_OFF_SQES as _; + +/// `IORING_REGISTER_FILES_SKIP` +#[inline] +#[doc(alias = "IORING_REGISTER_FILES_SKIP")] +pub const fn io_uring_register_files_skip() -> BorrowedFd<'static> { + let files_skip = sys::IORING_REGISTER_FILES_SKIP as RawFd; + + // SAFETY: `IORING_REGISTER_FILES_SKIP` is a reserved value that is never + // dynamically allocated, so it'll remain valid for the duration of + // `'static`. + unsafe { BorrowedFd::<'static>::borrow_raw(files_skip) } +} + +/// `IORING_NOTIF_USAGE_ZC_COPIED` (since Linux 6.2) +pub const IORING_NOTIF_USAGE_ZC_COPIED: i32 = sys::IORING_NOTIF_USAGE_ZC_COPIED as _; + +/// A pointer in the io_uring API. +/// +/// `io_uring`'s native API represents pointers as `u64` values. In order to +/// preserve strict-provenance, use a `*mut c_void`. On platforms where +/// pointers are narrower than 64 bits, this requires additional padding. +#[repr(C)] +#[derive(Copy, Clone)] +pub struct io_uring_ptr { + #[cfg(all(target_pointer_width = "32", target_endian = "big"))] + #[doc(hidden)] + pub __pad32: u32, + #[cfg(all(target_pointer_width = "16", target_endian = "big"))] + #[doc(hidden)] + pub __pad16: u16, + + /// The pointer value. + pub ptr: *mut c_void, + + #[cfg(all(target_pointer_width = "16", target_endian = "little"))] + #[doc(hidden)] + pub __pad16: u16, + #[cfg(all(target_pointer_width = "32", target_endian = "little"))] + #[doc(hidden)] + pub __pad32: u32, +} + +impl From<*mut c_void> for io_uring_ptr { + #[inline] + fn from(ptr: *mut c_void) -> Self { + Self { + ptr, + + #[cfg(target_pointer_width = "16")] + __pad16: Default::default(), + #[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))] + __pad32: Default::default(), + } + } +} + +impl Default for io_uring_ptr { + #[inline] + fn default() -> Self { + Self::from(null_mut()) + } +} + +/// User data in the io_uring API. +/// +/// `io_uring`'s native API represents `user_data` fields as `u64` values. In +/// order to preserve strict-provenance, use a union which allows users to +/// optionally store pointers. +#[repr(C)] +#[derive(Copy, Clone)] +pub union io_uring_user_data { + /// An arbitrary `u64`. + pub u64_: u64, + + /// A pointer. + pub ptr: io_uring_ptr, +} + +impl io_uring_user_data { + /// Return the `u64` value. + #[inline] + pub fn u64_(self) -> u64 { + // SAFETY: All the fields have the same underlying representation. + unsafe { self.u64_ } + } + + /// Create a `Self` from a `u64` value. + #[inline] + pub fn from_u64(u64_: u64) -> Self { + Self { u64_ } + } + + /// Return the `ptr` pointer value. + #[inline] + pub fn ptr(self) -> *mut c_void { + // SAFETY: All the fields have the same underlying representation. + unsafe { self.ptr }.ptr + } + + /// Create a `Self` from a pointer value. + #[inline] + pub fn from_ptr(ptr: *mut c_void) -> Self { + Self { + ptr: io_uring_ptr::from(ptr), + } + } +} + +impl Default for io_uring_user_data { + #[inline] + fn default() -> Self { + let mut s = MaybeUninit::<Self>::uninit(); + // SAFETY: All of Linux's io_uring structs may be zero-initialized. + unsafe { + write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} + +impl core::fmt::Debug for io_uring_user_data { + fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + // SAFETY: Just format as a `u64`, since formatting doesn't preserve + // provenance, and we don't have a discriminant. + unsafe { self.u64_.fmt(fmt) } + } +} + +/// An io_uring Submission Queue Entry. +#[allow(missing_docs)] +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct io_uring_sqe { + pub opcode: IoringOp, + pub flags: IoringSqeFlags, + pub ioprio: ioprio_union, + pub fd: RawFd, + pub off_or_addr2: off_or_addr2_union, + pub addr_or_splice_off_in: addr_or_splice_off_in_union, + pub len: len_union, + pub op_flags: op_flags_union, + pub user_data: io_uring_user_data, + pub buf: buf_union, + pub personality: u16, + pub splice_fd_in_or_file_index: splice_fd_in_or_file_index_union, + pub addr3_or_cmd: addr3_or_cmd_union, +} + +#[allow(missing_docs)] +#[repr(C)] +#[derive(Copy, Clone)] +pub union ioprio_union { + pub recv_flags: IoringRecvFlags, + pub send_flags: IoringSendFlags, + pub accept_flags: IoringAcceptFlags, + pub ioprio: u16, +} + +#[allow(missing_docs)] +#[repr(C)] +#[derive(Copy, Clone)] +pub union len_union { + pub poll_flags: IoringPollFlags, + pub len: u32, +} + +#[allow(missing_docs)] +#[repr(C)] +#[derive(Copy, Clone)] +pub union addr3_or_cmd_union { + pub addr3: addr3_struct, + pub cmd: [u8; 0], +} + +#[allow(missing_docs)] +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct addr3_struct { + pub addr3: u64, + pub __pad2: [u64; 1], +} + +#[allow(missing_docs)] +#[repr(C)] +#[derive(Copy, Clone)] +pub union off_or_addr2_union { + pub off: u64, + pub addr2: io_uring_ptr, + pub cmd_op: cmd_op_struct, + pub user_data: io_uring_user_data, +} + +#[allow(missing_docs)] +#[repr(C)] +#[derive(Copy, Clone)] +pub struct cmd_op_struct { + pub cmd_op: u32, + pub __pad1: u32, +} + +#[allow(missing_docs)] +#[repr(C)] +#[derive(Copy, Clone)] +pub union addr_or_splice_off_in_union { + pub addr: io_uring_ptr, + pub splice_off_in: u64, + pub msgring_cmd: IoringMsgringCmds, + pub user_data: io_uring_user_data, +} + +#[allow(missing_docs)] +#[repr(C)] +#[derive(Copy, Clone)] +pub union op_flags_union { + pub rw_flags: crate::io::ReadWriteFlags, + pub fsync_flags: IoringFsyncFlags, + pub poll_events: u16, + pub poll32_events: u32, + pub sync_range_flags: u32, + /// `msg_flags` is split into `send_flags` and `recv_flags`. + #[doc(alias = "msg_flags")] + pub send_flags: crate::net::SendFlags, + /// `msg_flags` is split into `send_flags` and `recv_flags`. + #[doc(alias = "msg_flags")] + pub recv_flags: crate::net::RecvFlags, + pub timeout_flags: IoringTimeoutFlags, + pub accept_flags: crate::net::SocketFlags, + pub cancel_flags: IoringAsyncCancelFlags, + pub open_flags: crate::fs::OFlags, + pub statx_flags: crate::fs::AtFlags, + pub fadvise_advice: crate::fs::Advice, + pub splice_flags: SpliceFlags, + pub rename_flags: crate::fs::RenameFlags, + pub unlink_flags: crate::fs::AtFlags, + pub hardlink_flags: crate::fs::AtFlags, + pub msg_ring_flags: IoringMsgringFlags, +} + +#[allow(missing_docs)] +#[repr(C, packed)] +#[derive(Copy, Clone)] +pub union buf_union { + pub buf_index: u16, + pub buf_group: u16, +} + +#[allow(missing_docs)] +#[repr(C)] +#[derive(Copy, Clone)] +pub union splice_fd_in_or_file_index_union { + pub splice_fd_in: i32, + pub file_index: u32, +} + +/// An io_uring Completion Queue Entry. +#[allow(missing_docs)] +#[repr(C)] +#[derive(Debug, Copy, Clone, Default)] +pub struct io_uring_cqe { + pub user_data: io_uring_user_data, + pub res: i32, + pub flags: IoringCqeFlags, +} + +#[allow(missing_docs)] +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct io_uring_restriction { + pub opcode: IoringRestrictionOp, + pub register_or_sqe_op_or_sqe_flags: register_or_sqe_op_or_sqe_flags_union, + pub resv: u8, + pub resv2: [u32; 3], +} + +#[allow(missing_docs)] +#[repr(C)] +#[derive(Copy, Clone)] +pub union register_or_sqe_op_or_sqe_flags_union { + pub register_op: IoringRegisterOp, + pub sqe_op: IoringOp, + pub sqe_flags: IoringSqeFlags, +} + +#[allow(missing_docs)] +#[repr(C)] +#[derive(Debug, Copy, Clone, Default)] +pub struct io_uring_params { + pub sq_entries: u32, + pub cq_entries: u32, + pub flags: IoringSetupFlags, + pub sq_thread_cpu: u32, + pub sq_thread_idle: u32, + pub features: IoringFeatureFlags, + pub wq_fd: u32, + pub resv: [u32; 3], + pub sq_off: io_sqring_offsets, + pub cq_off: io_cqring_offsets, +} + +#[allow(missing_docs)] +#[repr(C)] +#[derive(Debug, Copy, Clone, Default)] +pub struct io_sqring_offsets { + pub head: u32, + pub tail: u32, + pub ring_mask: u32, + pub ring_entries: u32, + pub flags: u32, + pub dropped: u32, + pub array: u32, + pub resv1: u32, + pub resv2: u64, +} + +#[allow(missing_docs)] +#[repr(C)] +#[derive(Debug, Copy, Clone, Default)] +pub struct io_cqring_offsets { + pub head: u32, + pub tail: u32, + pub ring_mask: u32, + pub ring_entries: u32, + pub overflow: u32, + pub cqes: u32, + pub flags: u32, + pub resv1: u32, + pub resv2: u64, +} + +#[allow(missing_docs)] +#[repr(C)] +#[derive(Debug, Default)] +pub struct io_uring_probe { + pub last_op: IoringOp, + pub ops_len: u8, + pub resv: u16, + pub resv2: [u32; 3], + pub ops: sys::__IncompleteArrayField<io_uring_probe_op>, +} + +#[allow(missing_docs)] +#[repr(C)] +#[derive(Debug, Copy, Clone, Default)] +pub struct io_uring_probe_op { + pub op: IoringOp, + pub resv: u8, + pub flags: IoringOpFlags, + pub resv2: u32, +} + +#[allow(missing_docs)] +#[repr(C, align(8))] +#[derive(Debug, Copy, Clone, Default)] +pub struct io_uring_files_update { + pub offset: u32, + pub resv: u32, + pub fds: u64, +} + +#[allow(missing_docs)] +#[repr(C, align(8))] +#[derive(Debug, Copy, Clone, Default)] +pub struct io_uring_rsrc_register { + pub nr: u32, + pub flags: IoringRsrcFlags, + pub resv2: u64, + pub data: u64, + pub tags: u64, +} + +#[allow(missing_docs)] +#[repr(C, align(8))] +#[derive(Debug, Copy, Clone, Default)] +pub struct io_uring_rsrc_update { + pub offset: u32, + pub resv: u32, + pub data: u64, +} + +#[allow(missing_docs)] +#[repr(C, align(8))] +#[derive(Debug, Copy, Clone, Default)] +pub struct io_uring_rsrc_update2 { + pub offset: u32, + pub resv: u32, + pub data: u64, + pub tags: u64, + pub nr: u32, + pub resv2: u32, +} + +#[allow(missing_docs)] +#[repr(C)] +#[derive(Debug, Copy, Clone, Default)] +pub struct io_uring_getevents_arg { + pub sigmask: u64, + pub sigmask_sz: u32, + pub pad: u32, + pub ts: u64, +} + +#[allow(missing_docs)] +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct io_uring_recvmsg_out { + pub namelen: u32, + pub controllen: u32, + pub payloadlen: u32, + pub flags: RecvmsgOutFlags, +} + +#[allow(missing_docs)] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct iovec { + pub iov_base: *mut c_void, + pub iov_len: usize, +} + +#[allow(missing_docs)] +#[repr(C)] +#[derive(Debug, Copy, Clone, Default)] +pub struct open_how { + /// An [`OFlags`] value represented as a `u64`. + /// + /// [`OFlags`]: crate::fs::OFlags + pub flags: u64, + + /// A [`Mode`] value represented as a `u64`. + /// + /// [`Mode`]: crate::fs::Mode + pub mode: u64, + + pub resolve: crate::fs::ResolveFlags, +} + +#[allow(missing_docs)] +#[repr(C)] +#[derive(Debug, Copy, Clone, Default)] +pub struct io_uring_buf_reg { + pub ring_addr: u64, + pub ring_entries: u32, + pub bgid: u16, + pub pad: u16, + pub resv: [u64; 3_usize], +} + +#[allow(missing_docs)] +#[repr(C)] +#[derive(Debug, Copy, Clone, Default)] +pub struct io_uring_buf { + pub addr: u64, + pub len: u32, + pub bid: u16, + pub resv: u16, +} + +impl Default for ioprio_union { + #[inline] + fn default() -> Self { + // SAFETY: All of Linux's io_uring structs may be zero-initialized. + unsafe { zeroed::<Self>() } + } +} + +impl Default for len_union { + #[inline] + fn default() -> Self { + // SAFETY: All of Linux's io_uring structs may be zero-initialized. + unsafe { zeroed::<Self>() } + } +} + +impl Default for off_or_addr2_union { + #[inline] + fn default() -> Self { + // SAFETY: All of Linux's io_uring structs may be zero-initialized. + unsafe { zeroed::<Self>() } + } +} + +impl Default for addr_or_splice_off_in_union { + #[inline] + fn default() -> Self { + // SAFETY: All of Linux's io_uring structs may be zero-initialized. + unsafe { zeroed::<Self>() } + } +} + +impl Default for addr3_or_cmd_union { + #[inline] + fn default() -> Self { + // SAFETY: All of Linux's io_uring structs may be zero-initialized. + unsafe { zeroed::<Self>() } + } +} + +impl Default for op_flags_union { + #[inline] + fn default() -> Self { + // SAFETY: All of Linux's io_uring structs may be zero-initialized. + unsafe { zeroed::<Self>() } + } +} + +impl Default for buf_union { + #[inline] + fn default() -> Self { + // SAFETY: All of Linux's io_uring structs may be zero-initialized. + unsafe { zeroed::<Self>() } + } +} + +impl Default for splice_fd_in_or_file_index_union { + #[inline] + fn default() -> Self { + // SAFETY: All of Linux's io_uring structs may be zero-initialized. + unsafe { zeroed::<Self>() } + } +} + +impl Default for register_or_sqe_op_or_sqe_flags_union { + #[inline] + fn default() -> Self { + // SAFETY: All of Linux's io_uring structs may be zero-initialized. + unsafe { zeroed::<Self>() } + } +} + +/// Check that our custom structs and unions have the same layout as the +/// kernel's versions. +#[test] +fn io_uring_layouts() { + use core::mem::{align_of, size_of}; + use memoffset::{offset_of, span_of}; + + // Check that the size and alignment of a type match the `sys` bindings. + macro_rules! check_type { + ($struct:ident) => { + assert_eq!( + (size_of::<$struct>(), align_of::<$struct>()), + (size_of::<sys::$struct>(), align_of::<sys::$struct>()) + ); + }; + } + + // The same as `check_type`, but for unions and anonymous structs we've + // renamed to avoid having types like "bindgen_ty_1" in the API. + macro_rules! check_renamed_type { + ($to:ident, $from:ident) => { + assert_eq!( + (size_of::<$to>(), align_of::<$to>()), + (size_of::<sys::$from>(), align_of::<sys::$from>()) + ); + }; + } + + // Check that the field of a struct has the same offset as the + // corresponding field in the `sys` bindings. + macro_rules! check_struct_field { + ($struct:ident, $field:ident) => { + assert_eq!( + offset_of!($struct, $field), + offset_of!(sys::$struct, $field) + ); + assert_eq!(span_of!($struct, $field), span_of!(sys::$struct, $field)); + }; + } + + // The same as `check_struct_field`, but for unions and anonymous structs + // we've renamed to avoid having types like "bindgen_ty_1" in the API. + macro_rules! check_struct_renamed_field { + ($struct:ident, $to:ident, $from:ident) => { + assert_eq!(offset_of!($struct, $to), offset_of!(sys::$struct, $from)); + assert_eq!(span_of!($struct, $to), span_of!(sys::$struct, $from)); + }; + } + + // For the common case of no renaming, check all fields of a struct. + macro_rules! check_struct { + ($name:ident, $($field:ident),*) => { + // Check the size and alignment. + check_type!($name); + + // Check that we have all the fields. + let _test = $name { + // SAFETY: All of io_uring's types can be zero-initialized. + $($field: unsafe { core::mem::zeroed() }),* + }; + + // Check that the fields have the right sizes and offsets. + $(check_struct_field!($name, $field));* + }; + } + + check_renamed_type!(off_or_addr2_union, io_uring_sqe__bindgen_ty_1); + check_renamed_type!(addr_or_splice_off_in_union, io_uring_sqe__bindgen_ty_2); + check_renamed_type!(addr3_or_cmd_union, io_uring_sqe__bindgen_ty_6); + check_renamed_type!(op_flags_union, io_uring_sqe__bindgen_ty_3); + check_renamed_type!(buf_union, io_uring_sqe__bindgen_ty_4); + check_renamed_type!(splice_fd_in_or_file_index_union, io_uring_sqe__bindgen_ty_5); + check_renamed_type!( + register_or_sqe_op_or_sqe_flags_union, + io_uring_restriction__bindgen_ty_1 + ); + + check_renamed_type!(addr3_struct, io_uring_sqe__bindgen_ty_6__bindgen_ty_1); + check_renamed_type!(cmd_op_struct, io_uring_sqe__bindgen_ty_1__bindgen_ty_1); + + check_type!(io_uring_sqe); + check_struct_field!(io_uring_sqe, opcode); + check_struct_field!(io_uring_sqe, flags); + check_struct_field!(io_uring_sqe, ioprio); + check_struct_field!(io_uring_sqe, fd); + check_struct_renamed_field!(io_uring_sqe, off_or_addr2, __bindgen_anon_1); + check_struct_renamed_field!(io_uring_sqe, addr_or_splice_off_in, __bindgen_anon_2); + check_struct_field!(io_uring_sqe, len); + check_struct_renamed_field!(io_uring_sqe, op_flags, __bindgen_anon_3); + check_struct_field!(io_uring_sqe, user_data); + check_struct_renamed_field!(io_uring_sqe, buf, __bindgen_anon_4); + check_struct_field!(io_uring_sqe, personality); + check_struct_renamed_field!(io_uring_sqe, splice_fd_in_or_file_index, __bindgen_anon_5); + check_struct_renamed_field!(io_uring_sqe, addr3_or_cmd, __bindgen_anon_6); + + check_type!(io_uring_restriction); + check_struct_field!(io_uring_restriction, opcode); + check_struct_renamed_field!( + io_uring_restriction, + register_or_sqe_op_or_sqe_flags, + __bindgen_anon_1 + ); + check_struct_field!(io_uring_restriction, resv); + check_struct_field!(io_uring_restriction, resv2); + + check_struct!(io_uring_cqe, user_data, res, flags); + check_struct!( + io_uring_params, + sq_entries, + cq_entries, + flags, + sq_thread_cpu, + sq_thread_idle, + features, + wq_fd, + resv, + sq_off, + cq_off + ); + check_struct!( + io_sqring_offsets, + head, + tail, + ring_mask, + ring_entries, + flags, + dropped, + array, + resv1, + resv2 + ); + check_struct!( + io_cqring_offsets, + head, + tail, + ring_mask, + ring_entries, + overflow, + cqes, + flags, + resv1, + resv2 + ); + check_struct!(io_uring_recvmsg_out, namelen, controllen, payloadlen, flags); + check_struct!(io_uring_probe, last_op, ops_len, resv, resv2, ops); + check_struct!(io_uring_probe_op, op, resv, flags, resv2); + check_struct!(io_uring_files_update, offset, resv, fds); + check_struct!(io_uring_rsrc_register, nr, flags, resv2, data, tags); + check_struct!(io_uring_rsrc_update, offset, resv, data); + check_struct!(io_uring_rsrc_update2, offset, resv, data, tags, nr, resv2); + check_struct!(io_uring_getevents_arg, sigmask, sigmask_sz, pad, ts); + check_struct!(iovec, iov_base, iov_len); + check_struct!(open_how, flags, mode, resolve); + check_struct!(io_uring_buf_reg, ring_addr, ring_entries, bgid, pad, resv); + check_struct!(io_uring_buf, addr, len, bid, resv); +} diff --git a/vendor/rustix-0.37.22/src/lib.rs b/vendor/rustix-0.37.22/src/lib.rs new file mode 100644 index 000000000..e2f1e0738 --- /dev/null +++ b/vendor/rustix-0.37.22/src/lib.rs @@ -0,0 +1,261 @@ +//! `rustix` provides efficient memory-safe and [I/O-safe] wrappers to +//! POSIX-like, Unix-like, Linux, and Winsock2 syscall-like APIs, with +//! configurable backends. +//! +//! With rustix, you can write code like this: +//! +//! ``` +//! # #[cfg(feature = "net")] +//! # fn read(sock: std::net::TcpStream, buf: &mut [u8]) -> std::io::Result<()> { +//! # use rustix::net::RecvFlags; +//! let nread: usize = rustix::net::recv(&sock, buf, RecvFlags::PEEK)?; +//! # let _ = nread; +//! # Ok(()) +//! # } +//! ``` +//! +//! instead of like this: +//! +//! ``` +//! # #[cfg(feature = "net")] +//! # fn read(sock: std::net::TcpStream, buf: &mut [u8]) -> std::io::Result<()> { +//! # use std::convert::TryInto; +//! # #[cfg(unix)] +//! # use std::os::unix::io::AsRawFd; +//! # #[cfg(target_os = "wasi")] +//! # use std::os::wasi::io::AsRawFd; +//! # #[cfg(windows)] +//! # use windows_sys::Win32::Networking::WinSock as libc; +//! # #[cfg(windows)] +//! # use std::os::windows::io::AsRawSocket; +//! # const MSG_PEEK: i32 = libc::MSG_PEEK; +//! let nread: usize = unsafe { +//! #[cfg(any(unix, target_os = "wasi"))] +//! let raw = sock.as_raw_fd(); +//! #[cfg(windows)] +//! let raw = sock.as_raw_socket(); +//! match libc::recv( +//! raw as _, +//! buf.as_mut_ptr().cast(), +//! buf.len().try_into().unwrap_or(i32::MAX as _), +//! MSG_PEEK, +//! ) { +//! -1 => return Err(std::io::Error::last_os_error()), +//! nread => nread as usize, +//! } +//! }; +//! # let _ = nread; +//! # Ok(()) +//! # } +//! ``` +//! +//! rustix's APIs perform the following tasks: +//! - Error values are translated to [`Result`]s. +//! - Buffers are passed as Rust slices. +//! - Out-parameters are presented as return values. +//! - Path arguments use [`Arg`], so they accept any string type. +//! - File descriptors are passed and returned via [`AsFd`] and [`OwnedFd`] +//! instead of bare integers, ensuring I/O safety. +//! - Constants use `enum`s and [`bitflags`] types. +//! - Multiplexed functions (eg. `fcntl`, `ioctl`, etc.) are de-multiplexed. +//! - Variadic functions (eg. `openat`, etc.) are presented as non-variadic. +//! - Functions that return strings automatically allocate sufficient memory +//! and retry the syscall as needed to determine the needed length. +//! - Functions and types which need `l` prefixes or `64` suffixes to enable +//! large-file support (LFS) are used automatically. File sizes and offsets +//! are always presented as `u64` and `i64`. +//! - Behaviors that depend on the sizes of C types like `long` are hidden. +//! - In some places, more human-friendly and less historical-accident names +//! are used (and documentation aliases are used so that the original names +//! can still be searched for). +//! - Provide y2038 compatibility, on platforms which support this. +//! - Correct selected platform bugs, such as behavioral differences when +//! running under seccomp. +//! +//! Things they don't do include: +//! - Detecting whether functions are supported at runtime, except in specific +//! cases where new interfaces need to be detected to support y2038 and LFS. +//! - Hiding significant differences between platforms. +//! - Restricting ambient authorities. +//! - Imposing sandboxing features such as filesystem path or network address +//! sandboxing. +//! +//! See [`cap-std`], [`system-interface`], and [`io-streams`] for libraries +//! which do hide significant differences between platforms, and [`cap-std`] +//! which does perform sandboxing and restricts ambient authorities. +//! +//! [`cap-std`]: https://crates.io/crates/cap-std +//! [`system-interface`]: https://crates.io/crates/system-interface +//! [`io-streams`]: https://crates.io/crates/io-streams +//! [`getrandom`]: https://crates.io/crates/getrandom +//! [`bitflags`]: https://crates.io/crates/bitflags +//! [`AsFd`]: https://doc.rust-lang.org/stable/std/os/fd/trait.AsFd.html +//! [`OwnedFd`]: https://doc.rust-lang.org/stable/std/os/fd/struct.OwnedFd.html +//! [I/O-safe]: https://github.com/rust-lang/rfcs/blob/master/text/3128-io-safety.md +//! [`Result`]: https://doc.rust-lang.org/stable/std/result/enum.Result.html +//! [`Arg`]: https://docs.rs/rustix/*/rustix/path/trait.Arg.html + +#![deny(missing_docs)] +#![allow(stable_features)] +#![cfg_attr(linux_raw, deny(unsafe_code))] +#![cfg_attr(rustc_attrs, feature(rustc_attrs))] +#![cfg_attr(doc_cfg, feature(doc_cfg))] +#![cfg_attr(all(wasi_ext, target_os = "wasi", feature = "std"), feature(wasi_ext))] +#![cfg_attr( + all(linux_raw, naked_functions, target_arch = "x86"), + feature(naked_functions) +)] +#![cfg_attr(io_lifetimes_use_std, feature(io_safety))] +#![cfg_attr(core_ffi_c, feature(core_ffi_c))] +#![cfg_attr(core_c_str, feature(core_c_str))] +#![cfg_attr(alloc_c_string, feature(alloc_ffi))] +#![cfg_attr(alloc_c_string, feature(alloc_c_string))] +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr(feature = "rustc-dep-of-std", feature(ip))] +#![cfg_attr( + any(feature = "rustc-dep-of-std", core_intrinsics), + feature(core_intrinsics) +)] +#![cfg_attr(asm_experimental_arch, feature(asm_experimental_arch))] +#![cfg_attr(not(feature = "all-apis"), allow(dead_code))] +// Clamp depends on Rust 1.50 which is newer than our MSRV. +#![allow(clippy::manual_clamp)] +// It is common in linux and libc APIs for types to vary between platforms. +#![allow(clippy::unnecessary_cast)] +// It is common in linux and libc APIs for types to vary between platforms. +#![allow(clippy::useless_conversion)] +// Redox and WASI have enough differences that it isn't worth +// precisely conditionallizing all the `use`s for them. +#![cfg_attr(any(target_os = "redox", target_os = "wasi"), allow(unused_imports))] + +#[cfg(not(feature = "rustc-dep-of-std"))] +extern crate alloc; + +// Internal utilities. +#[cfg(not(windows))] +#[macro_use] +pub(crate) mod cstr; +#[macro_use] +pub(crate) mod const_assert; +pub(crate) mod utils; + +// linux_raw: Weak symbols are used by the use-libc-auxv feature for +// glibc 2.15 support. +// +// libc: Weak symbols are used to call various functions available in some +// versions of libc and not others. +#[cfg(any( + all(linux_raw, feature = "use-libc-auxv"), + all(libc, not(any(windows, target_os = "wasi"))) +))] +#[macro_use] +mod weak; + +// Pick the backend implementation to use. +#[cfg_attr(libc, path = "backend/libc/mod.rs")] +#[cfg_attr(linux_raw, path = "backend/linux_raw/mod.rs")] +#[cfg_attr(wasi, path = "backend/wasi/mod.rs")] +mod backend; + +/// Export the `*Fd` types and traits that are used in rustix's public API. +/// +/// Users can use this to avoid needing to import anything else to use the same +/// versions of these types and traits. +pub mod fd { + use super::backend; + #[cfg(windows)] + pub use backend::fd::AsSocket; + pub use backend::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; +} + +// The public API modules. +#[cfg(not(windows))] +pub mod ffi; +#[cfg(not(windows))] +#[cfg(feature = "fs")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "fs")))] +pub mod fs; +pub mod io; +#[cfg(linux_kernel)] +#[cfg(feature = "io_uring")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "io_uring")))] +pub mod io_uring; +#[cfg(not(any(windows, target_os = "wasi")))] +#[cfg(feature = "mm")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "mm")))] +pub mod mm; +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +#[cfg(feature = "net")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "net")))] +pub mod net; +#[cfg(not(windows))] +#[cfg(feature = "param")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "param")))] +pub mod param; +#[cfg(not(windows))] +#[cfg(any(feature = "fs", feature = "net"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "fs", feature = "net"))))] +pub mod path; +#[cfg(not(windows))] +#[cfg(feature = "process")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "process")))] +pub mod process; +#[cfg(not(windows))] +#[cfg(not(target_os = "wasi"))] +#[cfg(feature = "pty")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "pty")))] +pub mod pty; +#[cfg(not(windows))] +#[cfg(feature = "rand")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "rand")))] +pub mod rand; +#[cfg(not(windows))] +#[cfg(feature = "termios")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "termios")))] +pub mod termios; +#[cfg(not(windows))] +#[cfg(feature = "thread")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "thread")))] +pub mod thread; +#[cfg(not(windows))] +#[cfg(feature = "time")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "time")))] +pub mod time; + +// "runtime" is also a public API module, but it's only for libc-like users. +#[cfg(not(windows))] +#[cfg(feature = "runtime")] +#[doc(hidden)] +#[cfg_attr(doc_cfg, doc(cfg(feature = "runtime")))] +pub mod runtime; + +// We have some internal interdependencies in the API features, so for now, +// for API features that aren't enabled, declare them as `pub(crate)` so +// that they're not public, but still available for internal use. + +#[cfg(all( + linux_raw, + not(windows), + not(feature = "fs"), + not(feature = "use-libc-auxv"), + not(target_vendor = "mustang"), + any( + feature = "param", + feature = "runtime", + feature = "time", + target_arch = "x86", + ) +))] +pub(crate) mod fs; +#[cfg(not(windows))] +#[cfg(all( + not(feature = "param"), + any(feature = "runtime", feature = "time", target_arch = "x86"), +))] +pub(crate) mod param; +#[cfg(not(windows))] +#[cfg(not(any(feature = "fs", feature = "net")))] +pub(crate) mod path; +#[cfg(not(windows))] +#[cfg(not(feature = "process"))] +pub(crate) mod process; diff --git a/vendor/rustix-0.37.22/src/mm/madvise.rs b/vendor/rustix-0.37.22/src/mm/madvise.rs new file mode 100644 index 000000000..868a31a5e --- /dev/null +++ b/vendor/rustix-0.37.22/src/mm/madvise.rs @@ -0,0 +1,49 @@ +//! The `madvise` function. +//! +//! # Safety +//! +//! `madvise` operates on a raw pointer. Some forms of `madvise` may +//! mutate the memory or have other side effects. +#![allow(unsafe_code)] + +use crate::{backend, io}; +use core::ffi::c_void; + +pub use backend::mm::types::Advice; + +/// `posix_madvise(addr, len, advice)`—Declares an expected access pattern +/// for a memory-mapped file. +/// +/// # Safety +/// +/// `addr` must be a valid pointer to memory that is appropriate to +/// call `posix_madvise` on. Some forms of `advice` may mutate the memory +/// or evoke a variety of side-effects on the mapping and/or the file. +/// +/// # References +/// - [POSIX] +/// - [Linux `madvise`] +/// - [Linux `posix_madvise`] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_madvise.html +/// [Linux `madvise`]: https://man7.org/linux/man-pages/man2/madvise.2.html +/// [Linux `posix_madvise`]: https://man7.org/linux/man-pages/man3/posix_madvise.3.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/madvise.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=madvise&sektion=2 +/// [NetBSD]: https://man.netbsd.org/madvise.2 +/// [OpenBSD]: https://man.openbsd.org/madvise.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=madvise§ion=2 +/// [illumos]: https://illumos.org/man/3C/madvise +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Memory_002dmapped-I_002fO.html#index-madvise +#[inline] +#[doc(alias = "posix_madvise")] +pub unsafe fn madvise(addr: *mut c_void, len: usize, advice: Advice) -> io::Result<()> { + backend::mm::syscalls::madvise(addr, len, advice) +} diff --git a/vendor/rustix-0.37.22/src/mm/mmap.rs b/vendor/rustix-0.37.22/src/mm/mmap.rs new file mode 100644 index 000000000..bec15f0ad --- /dev/null +++ b/vendor/rustix-0.37.22/src/mm/mmap.rs @@ -0,0 +1,315 @@ +//! The `mmap` API. +//! +//! # Safety +//! +//! `mmap` and related functions manipulate raw pointers and have special +//! semantics and are wildly unsafe. +#![allow(unsafe_code)] + +use crate::{backend, io}; +use backend::fd::AsFd; +use core::ffi::c_void; + +#[cfg(linux_kernel)] +pub use backend::mm::types::MlockFlags; +#[cfg(any(target_os = "emscripten", target_os = "linux"))] +pub use backend::mm::types::MremapFlags; +pub use backend::mm::types::{MapFlags, MprotectFlags, ProtFlags}; + +/// `mmap(ptr, len, prot, flags, fd, offset)`—Create a file-backed memory +/// mapping. +/// +/// For anonymous mappings (`MAP_ANON`/`MAP_ANONYMOUS`), see +/// [`mmap_anonymous`]. +/// +/// # Safety +/// +/// Raw pointers and lots of special semantics. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html +/// [Linux]: https://man7.org/linux/man-pages/man2/mmap.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/mmap.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=mmap&sektion=2 +/// [NetBSD]: https://man.netbsd.org/mmap.2 +/// [OpenBSD]: https://man.openbsd.org/mmap.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=mmap§ion=2 +/// [illumos]: https://illumos.org/man/2/mmap +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Memory_002dmapped-I_002fO.html#index-mmap +#[inline] +pub unsafe fn mmap<Fd: AsFd>( + ptr: *mut c_void, + len: usize, + prot: ProtFlags, + flags: MapFlags, + fd: Fd, + offset: u64, +) -> io::Result<*mut c_void> { + backend::mm::syscalls::mmap(ptr, len, prot, flags, fd.as_fd(), offset) +} + +/// `mmap(ptr, len, prot, MAP_ANONYMOUS | flags, -1, 0)`—Create an anonymous +/// memory mapping. +/// +/// For file-backed mappings, see [`mmap`]. +/// +/// # Safety +/// +/// Raw pointers and lots of special semantics. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html +/// [Linux]: https://man7.org/linux/man-pages/man2/mmap.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/mmap.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=mmap&sektion=2 +/// [NetBSD]: https://man.netbsd.org/mmap.2 +/// [OpenBSD]: https://man.openbsd.org/mmap.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=mmap§ion=2 +/// [illumos]: https://illumos.org/man/2/mmap +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Memory_002dmapped-I_002fO.html#index-mmap +#[inline] +#[doc(alias = "mmap")] +pub unsafe fn mmap_anonymous( + ptr: *mut c_void, + len: usize, + prot: ProtFlags, + flags: MapFlags, +) -> io::Result<*mut c_void> { + backend::mm::syscalls::mmap_anonymous(ptr, len, prot, flags) +} + +/// `munmap(ptr, len)`—Remove a memory mapping. +/// +/// # Safety +/// +/// Raw pointers and lots of special semantics. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/munmap.html +/// [Linux]: https://man7.org/linux/man-pages/man2/munmap.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/munmap.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=munmap&sektion=2 +/// [NetBSD]: https://man.netbsd.org/munmap.2 +/// [OpenBSD]: https://man.openbsd.org/munmap.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=munmap§ion=2 +/// [illumos]: https://illumos.org/man/2/munmap +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Memory_002dmapped-I_002fO.html#index-munmap +#[inline] +pub unsafe fn munmap(ptr: *mut c_void, len: usize) -> io::Result<()> { + backend::mm::syscalls::munmap(ptr, len) +} + +/// `mremap(old_address, old_size, new_size, flags)`—Resize, modify, +/// and/or move a memory mapping. +/// +/// For moving a mapping to a fixed address (`MREMAP_FIXED`), see +/// [`mremap_fixed`]. +/// +/// # Safety +/// +/// Raw pointers and lots of special semantics. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/mremap.2.html +#[cfg(any(target_os = "emscripten", target_os = "linux"))] +#[inline] +pub unsafe fn mremap( + old_address: *mut c_void, + old_size: usize, + new_size: usize, + flags: MremapFlags, +) -> io::Result<*mut c_void> { + backend::mm::syscalls::mremap(old_address, old_size, new_size, flags) +} + +/// `mremap(old_address, old_size, new_size, MREMAP_FIXED | flags)`—Resize, +/// modify, and/or move a memory mapping to a specific address. +/// +/// For `mremap` without moving to a specific address, see [`mremap`]. +/// [`mremap_fixed`]. +/// +/// # Safety +/// +/// Raw pointers and lots of special semantics. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/mremap.2.html +#[cfg(any(target_os = "emscripten", target_os = "linux"))] +#[inline] +#[doc(alias = "mremap")] +pub 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> { + backend::mm::syscalls::mremap_fixed(old_address, old_size, new_size, flags, new_address) +} + +/// `mprotect(ptr, len, flags)`—Change the protection flags of a region of +/// memory. +/// +/// # Safety +/// +/// Raw pointers and lots of special semantics. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/mprotect.html +/// [Linux]: https://man7.org/linux/man-pages/man2/mprotect.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/mprotect.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=mprotect&sektion=2 +/// [NetBSD]: https://man.netbsd.org/mprotect.2 +/// [OpenBSD]: https://man.openbsd.org/mprotect.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=mprotect§ion=2 +/// [illumos]: https://illumos.org/man/2/mprotect +#[inline] +pub unsafe fn mprotect(ptr: *mut c_void, len: usize, flags: MprotectFlags) -> io::Result<()> { + backend::mm::syscalls::mprotect(ptr, len, flags) +} + +/// `mlock(ptr, len)`—Lock memory into RAM. +/// +/// # Safety +/// +/// This function operates on raw pointers, but it should only be used on +/// memory which the caller owns. Technically, locking memory shouldn't violate +/// any invariants, but since unlocking it can violate invariants, this +/// function is also unsafe for symmetry. +/// +/// Some implementations implicitly round the memory region out to the nearest +/// page boundaries, so this function may lock more memory than explicitly +/// requested if the memory isn't page-aligned. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/mlock.html +/// [Linux]: https://man7.org/linux/man-pages/man2/mlock.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/mlock.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=mlock&sektion=2 +/// [NetBSD]: https://man.netbsd.org/mlock.2 +/// [OpenBSD]: https://man.openbsd.org/mlock.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=mlock§ion=2 +/// [illumos]: https://illumos.org/man/3C/mlock +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Page-Lock-Functions.html#index-mlock +#[inline] +pub unsafe fn mlock(ptr: *mut c_void, len: usize) -> io::Result<()> { + backend::mm::syscalls::mlock(ptr, len) +} + +/// `mlock2(ptr, len, flags)`—Lock memory into RAM, with flags. +/// +/// `mlock_with` is the same as [`mlock`] but adds an additional flags operand. +/// +/// # Safety +/// +/// This function operates on raw pointers, but it should only be used on +/// memory which the caller owns. Technically, locking memory shouldn't violate +/// any invariants, but since unlocking it can violate invariants, this +/// function is also unsafe for symmetry. +/// +/// Some implementations implicitly round the memory region out to the nearest +/// page boundaries, so this function may lock more memory than explicitly +/// requested if the memory isn't page-aligned. +/// +/// # References +/// - [Linux] +/// - [glibc] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/mlock2.2.html +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Page-Lock-Functions.html#index-mlock2 +#[cfg(linux_kernel)] +#[inline] +#[doc(alias = "mlock2")] +pub unsafe fn mlock_with(ptr: *mut c_void, len: usize, flags: MlockFlags) -> io::Result<()> { + backend::mm::syscalls::mlock_with(ptr, len, flags) +} + +/// `munlock(ptr, len)`—Unlock memory. +/// +/// # Safety +/// +/// This function operates on raw pointers, but it should only be used on +/// memory which the caller owns, to avoid compromising the `mlock` invariants +/// of other unrelated code in the process. +/// +/// Some implementations implicitly round the memory region out to the nearest +/// page boundaries, so this function may unlock more memory than explicitly +/// requested if the memory isn't page-aligned. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/munlock.html +/// [Linux]: https://man7.org/linux/man-pages/man2/munlock.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/munlock.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=munlock&sektion=2 +/// [NetBSD]: https://man.netbsd.org/munlock.2 +/// [OpenBSD]: https://man.openbsd.org/munlock.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=munlock§ion=2 +/// [illumos]: https://illumos.org/man/3C/munlock +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Page-Lock-Functions.html#index-munlock +#[inline] +pub unsafe fn munlock(ptr: *mut c_void, len: usize) -> io::Result<()> { + backend::mm::syscalls::munlock(ptr, len) +} diff --git a/vendor/rustix-0.37.22/src/mm/mod.rs b/vendor/rustix-0.37.22/src/mm/mod.rs new file mode 100644 index 000000000..7505cac0a --- /dev/null +++ b/vendor/rustix-0.37.22/src/mm/mod.rs @@ -0,0 +1,15 @@ +//! Memory map operations. + +#[cfg(not(target_os = "redox"))] +mod madvise; +mod mmap; +mod msync; +#[cfg(linux_kernel)] +mod userfaultfd; + +#[cfg(not(target_os = "redox"))] +pub use madvise::{madvise, Advice}; +pub use mmap::*; +pub use msync::{msync, MsyncFlags}; +#[cfg(linux_kernel)] +pub use userfaultfd::{userfaultfd, UserfaultfdFlags}; diff --git a/vendor/rustix-0.37.22/src/mm/msync.rs b/vendor/rustix-0.37.22/src/mm/msync.rs new file mode 100644 index 000000000..0306e36b9 --- /dev/null +++ b/vendor/rustix-0.37.22/src/mm/msync.rs @@ -0,0 +1,46 @@ +//! The `msync` function. +//! +//! # Safety +//! +//! `msync` operates on a raw pointer. Some forms of `msync` may mutate the +//! memory or have other side effects. +#![allow(unsafe_code)] + +use crate::{backend, io}; +use core::ffi::c_void; + +pub use backend::mm::types::MsyncFlags; + +/// `msync(addr, len, flags)`—Synchronizes a memory-mapping with its backing +/// storage. +/// +/// # Safety +/// +/// `addr` must be a valid pointer to memory that is appropriate to +/// call `msync` on. Some forms of `msync` may mutate the memory +/// or evoke a variety of side-effects on the mapping and/or the file. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/msync.html +/// [Linux]: https://man7.org/linux/man-pages/man2/msync.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/msync.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=msync&sektion=2 +/// [NetBSD]: https://man.netbsd.org/msync.2 +/// [OpenBSD]: https://man.openbsd.org/msync.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=msync§ion=2 +/// [illumos]: https://illumos.org/man/3C/msync +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Memory_002dmapped-I_002fO.html#index-msync +#[inline] +pub unsafe fn msync(addr: *mut c_void, len: usize, flags: MsyncFlags) -> io::Result<()> { + backend::mm::syscalls::msync(addr, len, flags) +} diff --git a/vendor/rustix-0.37.22/src/mm/userfaultfd.rs b/vendor/rustix-0.37.22/src/mm/userfaultfd.rs new file mode 100644 index 000000000..201d54772 --- /dev/null +++ b/vendor/rustix-0.37.22/src/mm/userfaultfd.rs @@ -0,0 +1,30 @@ +//! The Linux `userfaultfd` API. +//! +//! # Safety +//! +//! Calling `userfaultfd` is safe, but the returned file descriptor lets users +//! observe and manipulate process memory in magical ways. +#![allow(unsafe_code)] + +use crate::fd::OwnedFd; +use crate::{backend, io}; + +pub use backend::mm::types::UserfaultfdFlags; + +/// `userfaultfd(flags)` +/// +/// # Safety +/// +/// The call itself is safe, but the returned file descriptor lets users +/// observe and manipulate process memory in magical ways. +/// +/// # References +/// - [Linux] +/// - [Linux userfaultfd] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/userfaultfd.2.html +/// [Linux userfaultfd]: https://www.kernel.org/doc/Documentation/vm/userfaultfd.txt +#[inline] +pub unsafe fn userfaultfd(flags: UserfaultfdFlags) -> io::Result<OwnedFd> { + backend::mm::syscalls::userfaultfd(flags) +} diff --git a/vendor/rustix-0.37.22/src/net/addr.rs b/vendor/rustix-0.37.22/src/net/addr.rs new file mode 100644 index 000000000..ca87298e9 --- /dev/null +++ b/vendor/rustix-0.37.22/src/net/addr.rs @@ -0,0 +1,641 @@ +//! The following is derived from Rust's +//! library/std/src/net/socket_addr.rs at revision +//! bd20fc1fd657b32f7aa1d70d8723f04c87f21606. +//! +//! All code in this file is licensed MIT or Apache 2.0 at your option. +//! +//! This defines `SocketAddr`, `SocketAddrV4`, and `SocketAddrV6` in a +//! platform-independent way. It is not the native representation. + +use crate::net::ip::{IpAddr, Ipv4Addr, Ipv6Addr}; +use core::cmp::Ordering; +use core::hash; + +/// An internet socket address, either IPv4 or IPv6. +/// +/// Internet socket addresses consist of an [IP address], a 16-bit port number, as well +/// as possibly some version-dependent additional information. See [`SocketAddrV4`]'s and +/// [`SocketAddrV6`]'s respective documentation for more details. +/// +/// The size of a `SocketAddr` instance may vary depending on the target operating +/// system. +/// +/// [IP address]: IpAddr +/// +/// # Examples +/// +/// ``` +/// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; +/// +/// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); +/// +/// assert_eq!("127.0.0.1:8080".parse(), Ok(socket)); +/// assert_eq!(socket.port(), 8080); +/// assert_eq!(socket.is_ipv4(), true); +/// ``` +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] +pub enum SocketAddr { + /// An IPv4 socket address. + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + V4(#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] SocketAddrV4), + /// An IPv6 socket address. + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + V6(#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] SocketAddrV6), +} + +/// An IPv4 socket address. +/// +/// IPv4 socket addresses consist of an [`IPv4` address] and a 16-bit port number, as +/// stated in [IETF RFC 793]. +/// +/// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses. +/// +/// The size of a `SocketAddrV4` struct may vary depending on the target operating +/// system. Do not assume that this type has the same memory layout as the underlying +/// system representation. +/// +/// [IETF RFC 793]: https://tools.ietf.org/html/rfc793 +/// [`IPv4` address]: Ipv4Addr +/// +/// # Examples +/// +/// ``` +/// use std::net::{Ipv4Addr, SocketAddrV4}; +/// +/// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); +/// +/// assert_eq!("127.0.0.1:8080".parse(), Ok(socket)); +/// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1)); +/// assert_eq!(socket.port(), 8080); +/// ``` +#[derive(Copy, Clone, Eq, PartialEq)] +#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] +pub struct SocketAddrV4 { + ip: Ipv4Addr, + port: u16, +} + +/// An IPv6 socket address. +/// +/// IPv6 socket addresses consist of an [`IPv6` address], a 16-bit port number, as well +/// as fields containing the traffic class, the flow label, and a scope identifier +/// (see [IETF RFC 2553, Section 3.3] for more details). +/// +/// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses. +/// +/// The size of a `SocketAddrV6` struct may vary depending on the target operating +/// system. Do not assume that this type has the same memory layout as the underlying +/// system representation. +/// +/// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 +/// [`IPv6` address]: Ipv6Addr +/// +/// # Examples +/// +/// ``` +/// use std::net::{Ipv6Addr, SocketAddrV6}; +/// +/// let socket = SocketAddrV6::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1), 8080, 0, 0); +/// +/// assert_eq!("[2001:db8::1]:8080".parse(), Ok(socket)); +/// assert_eq!(socket.ip(), &Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1)); +/// assert_eq!(socket.port(), 8080); +/// ``` +#[derive(Copy, Clone, Eq, PartialEq)] +#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] +pub struct SocketAddrV6 { + ip: Ipv6Addr, + port: u16, + flowinfo: u32, + scope_id: u32, +} + +impl SocketAddr { + /// Creates a new socket address from an [IP address] and a port number. + /// + /// [IP address]: IpAddr + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; + /// + /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); + /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))); + /// assert_eq!(socket.port(), 8080); + /// ``` + #[cfg_attr(staged_api, stable(feature = "ip_addr", since = "1.7.0"))] + #[must_use] + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_socketaddr", issue = "82485") + )] + pub const fn new(ip: IpAddr, port: u16) -> SocketAddr { + match ip { + IpAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a, port)), + IpAddr::V6(a) => SocketAddr::V6(SocketAddrV6::new(a, port, 0, 0)), + } + } + + /// Returns the IP address associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; + /// + /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); + /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))); + /// ``` + #[must_use] + #[cfg_attr(staged_api, stable(feature = "ip_addr", since = "1.7.0"))] + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_socketaddr", issue = "82485") + )] + pub const fn ip(&self) -> IpAddr { + match *self { + SocketAddr::V4(ref a) => IpAddr::V4(*a.ip()), + SocketAddr::V6(ref a) => IpAddr::V6(*a.ip()), + } + } + + /// Changes the IP address associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; + /// + /// let mut socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); + /// socket.set_ip(IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1))); + /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1))); + /// ``` + #[cfg_attr(staged_api, stable(feature = "sockaddr_setters", since = "1.9.0"))] + pub fn set_ip(&mut self, new_ip: IpAddr) { + // `match (*self, new_ip)` would have us mutate a copy of self only to throw it away. + match (self, new_ip) { + (&mut SocketAddr::V4(ref mut a), IpAddr::V4(new_ip)) => a.set_ip(new_ip), + (&mut SocketAddr::V6(ref mut a), IpAddr::V6(new_ip)) => a.set_ip(new_ip), + (self_, new_ip) => *self_ = Self::new(new_ip, self_.port()), + } + } + + /// Returns the port number associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; + /// + /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); + /// assert_eq!(socket.port(), 8080); + /// ``` + #[must_use] + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_socketaddr", issue = "82485") + )] + pub const fn port(&self) -> u16 { + match *self { + SocketAddr::V4(ref a) => a.port(), + SocketAddr::V6(ref a) => a.port(), + } + } + + /// Changes the port number associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; + /// + /// let mut socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); + /// socket.set_port(1025); + /// assert_eq!(socket.port(), 1025); + /// ``` + #[cfg_attr(staged_api, stable(feature = "sockaddr_setters", since = "1.9.0"))] + pub fn set_port(&mut self, new_port: u16) { + match *self { + SocketAddr::V4(ref mut a) => a.set_port(new_port), + SocketAddr::V6(ref mut a) => a.set_port(new_port), + } + } + + /// Returns [`true`] if the [IP address] in this `SocketAddr` is an + /// [`IPv4` address], and [`false`] otherwise. + /// + /// [IP address]: IpAddr + /// [`IPv4` address]: IpAddr::V4 + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; + /// + /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); + /// assert_eq!(socket.is_ipv4(), true); + /// assert_eq!(socket.is_ipv6(), false); + /// ``` + #[must_use] + #[cfg_attr(staged_api, stable(feature = "sockaddr_checker", since = "1.16.0"))] + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_socketaddr", issue = "82485") + )] + pub const fn is_ipv4(&self) -> bool { + matches!(*self, SocketAddr::V4(_)) + } + + /// Returns [`true`] if the [IP address] in this `SocketAddr` is an + /// [`IPv6` address], and [`false`] otherwise. + /// + /// [IP address]: IpAddr + /// [`IPv6` address]: IpAddr::V6 + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv6Addr, SocketAddr}; + /// + /// let socket = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 0, 1)), 8080); + /// assert_eq!(socket.is_ipv4(), false); + /// assert_eq!(socket.is_ipv6(), true); + /// ``` + #[must_use] + #[cfg_attr(staged_api, stable(feature = "sockaddr_checker", since = "1.16.0"))] + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_socketaddr", issue = "82485") + )] + pub const fn is_ipv6(&self) -> bool { + matches!(*self, SocketAddr::V6(_)) + } +} + +impl SocketAddrV4 { + /// Creates a new socket address from an [`IPv4` address] and a port number. + /// + /// [`IPv4` address]: Ipv4Addr + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV4, Ipv4Addr}; + /// + /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); + /// ``` + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + #[must_use] + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_socketaddr", issue = "82485") + )] + pub const fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 { + SocketAddrV4 { ip, port } + } + + /// Returns the IP address associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV4, Ipv4Addr}; + /// + /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); + /// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1)); + /// ``` + #[must_use] + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_socketaddr", issue = "82485") + )] + pub const fn ip(&self) -> &Ipv4Addr { + &self.ip + } + + /// Changes the IP address associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV4, Ipv4Addr}; + /// + /// let mut socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); + /// socket.set_ip(Ipv4Addr::new(192, 168, 0, 1)); + /// assert_eq!(socket.ip(), &Ipv4Addr::new(192, 168, 0, 1)); + /// ``` + #[cfg_attr(staged_api, stable(feature = "sockaddr_setters", since = "1.9.0"))] + pub fn set_ip(&mut self, new_ip: Ipv4Addr) { + self.ip = new_ip; + } + + /// Returns the port number associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV4, Ipv4Addr}; + /// + /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); + /// assert_eq!(socket.port(), 8080); + /// ``` + #[must_use] + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_socketaddr", issue = "82485") + )] + pub const fn port(&self) -> u16 { + self.port + } + + /// Changes the port number associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV4, Ipv4Addr}; + /// + /// let mut socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); + /// socket.set_port(4242); + /// assert_eq!(socket.port(), 4242); + /// ``` + #[cfg_attr(staged_api, stable(feature = "sockaddr_setters", since = "1.9.0"))] + pub fn set_port(&mut self, new_port: u16) { + self.port = new_port; + } +} + +impl SocketAddrV6 { + /// Creates a new socket address from an [`IPv6` address], a 16-bit port number, + /// and the `flowinfo` and `scope_id` fields. + /// + /// For more information on the meaning and layout of the `flowinfo` and `scope_id` + /// parameters, see [IETF RFC 2553, Section 3.3]. + /// + /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 + /// [`IPv6` address]: Ipv6Addr + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); + /// ``` + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + #[must_use] + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_socketaddr", issue = "82485") + )] + pub const fn new(ip: Ipv6Addr, port: u16, flowinfo: u32, scope_id: u32) -> SocketAddrV6 { + SocketAddrV6 { + ip, + port, + flowinfo, + scope_id, + } + } + + /// Returns the IP address associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); + /// assert_eq!(socket.ip(), &Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); + /// ``` + #[must_use] + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_socketaddr", issue = "82485") + )] + pub const fn ip(&self) -> &Ipv6Addr { + &self.ip + } + + /// Changes the IP address associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); + /// socket.set_ip(Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0)); + /// assert_eq!(socket.ip(), &Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0)); + /// ``` + #[cfg_attr(staged_api, stable(feature = "sockaddr_setters", since = "1.9.0"))] + pub fn set_ip(&mut self, new_ip: Ipv6Addr) { + self.ip = new_ip; + } + + /// Returns the port number associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); + /// assert_eq!(socket.port(), 8080); + /// ``` + #[must_use] + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_socketaddr", issue = "82485") + )] + pub const fn port(&self) -> u16 { + self.port + } + + /// Changes the port number associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); + /// socket.set_port(4242); + /// assert_eq!(socket.port(), 4242); + /// ``` + #[cfg_attr(staged_api, stable(feature = "sockaddr_setters", since = "1.9.0"))] + pub fn set_port(&mut self, new_port: u16) { + self.port = new_port; + } + + /// Returns the flow information associated with this address. + /// + /// This information corresponds to the `sin6_flowinfo` field in C's `netinet/in.h`, + /// as specified in [IETF RFC 2553, Section 3.3]. + /// It combines information about the flow label and the traffic class as specified + /// in [IETF RFC 2460], respectively [Section 6] and [Section 7]. + /// + /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 + /// [IETF RFC 2460]: https://tools.ietf.org/html/rfc2460 + /// [Section 6]: https://tools.ietf.org/html/rfc2460#section-6 + /// [Section 7]: https://tools.ietf.org/html/rfc2460#section-7 + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 10, 0); + /// assert_eq!(socket.flowinfo(), 10); + /// ``` + #[must_use] + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_socketaddr", issue = "82485") + )] + pub const fn flowinfo(&self) -> u32 { + self.flowinfo + } + + /// Changes the flow information associated with this socket address. + /// + /// See [`SocketAddrV6::flowinfo`]'s documentation for more details. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 10, 0); + /// socket.set_flowinfo(56); + /// assert_eq!(socket.flowinfo(), 56); + /// ``` + #[cfg_attr(staged_api, stable(feature = "sockaddr_setters", since = "1.9.0"))] + pub fn set_flowinfo(&mut self, new_flowinfo: u32) { + self.flowinfo = new_flowinfo; + } + + /// Returns the scope ID associated with this address. + /// + /// This information corresponds to the `sin6_scope_id` field in C's `netinet/in.h`, + /// as specified in [IETF RFC 2553, Section 3.3]. + /// + /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 78); + /// assert_eq!(socket.scope_id(), 78); + /// ``` + #[must_use] + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_socketaddr", issue = "82485") + )] + pub const fn scope_id(&self) -> u32 { + self.scope_id + } + + /// Changes the scope ID associated with this socket address. + /// + /// See [`SocketAddrV6::scope_id`]'s documentation for more details. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 78); + /// socket.set_scope_id(42); + /// assert_eq!(socket.scope_id(), 42); + /// ``` + #[cfg_attr(staged_api, stable(feature = "sockaddr_setters", since = "1.9.0"))] + pub fn set_scope_id(&mut self, new_scope_id: u32) { + self.scope_id = new_scope_id; + } +} + +#[cfg_attr(staged_api, stable(feature = "ip_from_ip", since = "1.16.0"))] +impl From<SocketAddrV4> for SocketAddr { + /// Converts a [`SocketAddrV4`] into a [`SocketAddr::V4`]. + fn from(sock4: SocketAddrV4) -> SocketAddr { + SocketAddr::V4(sock4) + } +} + +#[cfg_attr(staged_api, stable(feature = "ip_from_ip", since = "1.16.0"))] +impl From<SocketAddrV6> for SocketAddr { + /// Converts a [`SocketAddrV6`] into a [`SocketAddr::V6`]. + fn from(sock6: SocketAddrV6) -> SocketAddr { + SocketAddr::V6(sock6) + } +} + +#[cfg_attr(staged_api, stable(feature = "addr_from_into_ip", since = "1.17.0"))] +impl<I: Into<IpAddr>> From<(I, u16)> for SocketAddr { + /// Converts a tuple struct (Into<[`IpAddr`]>, `u16`) into a [`SocketAddr`]. + /// + /// This conversion creates a [`SocketAddr::V4`] for an [`IpAddr::V4`] + /// and creates a [`SocketAddr::V6`] for an [`IpAddr::V6`]. + /// + /// `u16` is treated as port of the newly created [`SocketAddr`]. + fn from(pieces: (I, u16)) -> SocketAddr { + SocketAddr::new(pieces.0.into(), pieces.1) + } +} + +#[cfg_attr(staged_api, stable(feature = "socketaddr_ordering", since = "1.45.0"))] +impl PartialOrd for SocketAddrV4 { + fn partial_cmp(&self, other: &SocketAddrV4) -> Option<Ordering> { + Some(self.cmp(other)) + } +} + +#[cfg_attr(staged_api, stable(feature = "socketaddr_ordering", since = "1.45.0"))] +impl PartialOrd for SocketAddrV6 { + fn partial_cmp(&self, other: &SocketAddrV6) -> Option<Ordering> { + Some(self.cmp(other)) + } +} + +#[cfg_attr(staged_api, stable(feature = "socketaddr_ordering", since = "1.45.0"))] +impl Ord for SocketAddrV4 { + fn cmp(&self, other: &SocketAddrV4) -> Ordering { + self.ip() + .cmp(other.ip()) + .then(self.port().cmp(&other.port())) + } +} + +#[cfg_attr(staged_api, stable(feature = "socketaddr_ordering", since = "1.45.0"))] +impl Ord for SocketAddrV6 { + fn cmp(&self, other: &SocketAddrV6) -> Ordering { + self.ip() + .cmp(other.ip()) + .then(self.port().cmp(&other.port())) + } +} + +#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] +impl hash::Hash for SocketAddrV4 { + fn hash<H: hash::Hasher>(&self, s: &mut H) { + (self.port, self.ip).hash(s) + } +} +#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] +impl hash::Hash for SocketAddrV6 { + fn hash<H: hash::Hasher>(&self, s: &mut H) { + (self.port, &self.ip, self.flowinfo, self.scope_id).hash(s) + } +} diff --git a/vendor/rustix-0.37.22/src/net/ip.rs b/vendor/rustix-0.37.22/src/net/ip.rs new file mode 100644 index 000000000..ffa5302e3 --- /dev/null +++ b/vendor/rustix-0.37.22/src/net/ip.rs @@ -0,0 +1,2068 @@ +//! The following is derived from Rust's +//! library/std/src/net/ip_addr.rs at revision +//! bd20fc1fd657b32f7aa1d70d8723f04c87f21606. +//! +//! All code in this file is licensed MIT or Apache 2.0 at your option. +//! +//! This defines `IpAddr`, `Ipv4Addr`, and `Ipv6Addr`. Ideally, these should be +//! defined in `core`. See [RFC 2832]. +//! +//! [RFC 2832]: https://github.com/rust-lang/rfcs/pull/2832 + +#![allow(unsafe_code)] + +use core::cmp::Ordering; +use core::mem::transmute; + +/// An IP address, either IPv4 or IPv6. +/// +/// This enum can contain either an [`Ipv4Addr`] or an [`Ipv6Addr`], see their +/// respective documentation for more details. +/// +/// # Examples +/// +/// ``` +/// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; +/// +/// let localhost_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)); +/// let localhost_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); +/// +/// assert_eq!("127.0.0.1".parse(), Ok(localhost_v4)); +/// assert_eq!("::1".parse(), Ok(localhost_v6)); +/// +/// assert_eq!(localhost_v4.is_ipv6(), false); +/// assert_eq!(localhost_v4.is_ipv4(), true); +/// ``` +#[cfg_attr(staged_api, stable(feature = "ip_addr", since = "1.7.0"))] +#[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)] +pub enum IpAddr { + /// An IPv4 address. + #[cfg_attr(staged_api, stable(feature = "ip_addr", since = "1.7.0"))] + V4(#[cfg_attr(staged_api, stable(feature = "ip_addr", since = "1.7.0"))] Ipv4Addr), + /// An IPv6 address. + #[cfg_attr(staged_api, stable(feature = "ip_addr", since = "1.7.0"))] + V6(#[cfg_attr(staged_api, stable(feature = "ip_addr", since = "1.7.0"))] Ipv6Addr), +} + +/// An IPv4 address. +/// +/// IPv4 addresses are defined as 32-bit integers in [IETF RFC 791]. +/// They are usually represented as four octets. +/// +/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. +/// +/// [IETF RFC 791]: https://tools.ietf.org/html/rfc791 +/// +/// # Textual representation +/// +/// `Ipv4Addr` provides a [`FromStr`] implementation. The four octets are in decimal +/// notation, divided by `.` (this is called "dot-decimal notation"). +/// Notably, octal numbers (which are indicated with a leading `0`) and hexadecimal numbers (which +/// are indicated with a leading `0x`) are not allowed per [IETF RFC 6943]. +/// +/// [IETF RFC 6943]: https://tools.ietf.org/html/rfc6943#section-3.1.1 +/// [`FromStr`]: core::str::FromStr +/// +/// # Examples +/// +/// ``` +/// use std::net::Ipv4Addr; +/// +/// let localhost = Ipv4Addr::new(127, 0, 0, 1); +/// assert_eq!("127.0.0.1".parse(), Ok(localhost)); +/// assert_eq!(localhost.is_loopback(), true); +/// assert!("012.004.002.000".parse::<Ipv4Addr>().is_err()); // all octets are in octal +/// assert!("0000000.0.0.0".parse::<Ipv4Addr>().is_err()); // first octet is a zero in octal +/// assert!("0xcb.0x0.0x71.0x00".parse::<Ipv4Addr>().is_err()); // all octets are in hex +/// ``` +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] +pub struct Ipv4Addr { + octets: [u8; 4], +} + +/// An IPv6 address. +/// +/// IPv6 addresses are defined as 128-bit integers in [IETF RFC 4291]. +/// They are usually represented as eight 16-bit segments. +/// +/// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 +/// +/// # Embedding IPv4 Addresses +/// +/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. +/// +/// To assist in the transition from IPv4 to IPv6 two types of IPv6 addresses that embed an IPv4 address were defined: +/// IPv4-compatible and IPv4-mapped addresses. Of these IPv4-compatible addresses have been officially deprecated. +/// +/// Both types of addresses are not assigned any special meaning by this implementation, +/// other than what the relevant standards prescribe. This means that an address like `::ffff:127.0.0.1`, +/// while representing an IPv4 loopback address, is not itself an IPv6 loopback address; only `::1` is. +/// To handle these so called "IPv4-in-IPv6" addresses, they have to first be converted to their canonical IPv4 address. +/// +/// ### IPv4-Compatible IPv6 Addresses +/// +/// IPv4-compatible IPv6 addresses are defined in [IETF RFC 4291 Section 2.5.5.1], and have been officially deprecated. +/// The RFC describes the format of an "IPv4-Compatible IPv6 address" as follows: +/// +/// ```text +/// | 80 bits | 16 | 32 bits | +/// +--------------------------------------+--------------------------+ +/// |0000..............................0000|0000| IPv4 address | +/// +--------------------------------------+----+---------------------+ +/// ``` +/// So `::a.b.c.d` would be an IPv4-compatible IPv6 address representing the IPv4 address `a.b.c.d`. +/// +/// To convert from an IPv4 address to an IPv4-compatible IPv6 address, use [`Ipv4Addr::to_ipv6_compatible`]. +/// Use [`Ipv6Addr::to_ipv4`] to convert an IPv4-compatible IPv6 address to the canonical IPv4 address. +/// +/// [IETF RFC 4291 Section 2.5.5.1]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.1 +/// +/// ### IPv4-Mapped IPv6 Addresses +/// +/// IPv4-mapped IPv6 addresses are defined in [IETF RFC 4291 Section 2.5.5.2]. +/// The RFC describes the format of an "IPv4-Mapped IPv6 address" as follows: +/// +/// ```text +/// | 80 bits | 16 | 32 bits | +/// +--------------------------------------+--------------------------+ +/// |0000..............................0000|FFFF| IPv4 address | +/// +--------------------------------------+----+---------------------+ +/// ``` +/// So `::ffff:a.b.c.d` would be an IPv4-mapped IPv6 address representing the IPv4 address `a.b.c.d`. +/// +/// To convert from an IPv4 address to an IPv4-mapped IPv6 address, use [`Ipv4Addr::to_ipv6_mapped`]. +/// Use [`Ipv6Addr::to_ipv4`] to convert an IPv4-mapped IPv6 address to the canonical IPv4 address. +/// Note that this will also convert the IPv6 loopback address `::1` to `0.0.0.1`. Use +/// [`Ipv6Addr::to_ipv4_mapped`] to avoid this. +/// +/// [IETF RFC 4291 Section 2.5.5.2]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2 +/// +/// # Textual representation +/// +/// `Ipv6Addr` provides a [`FromStr`] implementation. There are many ways to represent +/// an IPv6 address in text, but in general, each segments is written in hexadecimal +/// notation, and segments are separated by `:`. For more information, see +/// [IETF RFC 5952]. +/// +/// [`FromStr`]: core::str::FromStr +/// [IETF RFC 5952]: https://tools.ietf.org/html/rfc5952 +/// +/// # Examples +/// +/// ``` +/// use std::net::Ipv6Addr; +/// +/// let localhost = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); +/// assert_eq!("::1".parse(), Ok(localhost)); +/// assert_eq!(localhost.is_loopback(), true); +/// ``` +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] +pub struct Ipv6Addr { + octets: [u8; 16], +} + +/// Scope of an [IPv6 multicast address] as defined in [IETF RFC 7346 section 2]. +/// +/// # Stability Guarantees +/// +/// Not all possible values for a multicast scope have been assigned. +/// Future RFCs may introduce new scopes, which will be added as variants to this enum; +/// because of this the enum is marked as `#[non_exhaustive]`. +/// +/// # Examples +/// ``` +/// #![feature(ip)] +/// +/// use std::net::Ipv6Addr; +/// use std::net::Ipv6MulticastScope::*; +/// +/// // An IPv6 multicast address with global scope (`ff0e::`). +/// let address = Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0); +/// +/// // Will print "Global scope". +/// match address.multicast_scope() { +/// Some(InterfaceLocal) => println!("Interface-Local scope"), +/// Some(LinkLocal) => println!("Link-Local scope"), +/// Some(RealmLocal) => println!("Realm-Local scope"), +/// Some(AdminLocal) => println!("Admin-Local scope"), +/// Some(SiteLocal) => println!("Site-Local scope"), +/// Some(OrganizationLocal) => println!("Organization-Local scope"), +/// Some(Global) => println!("Global scope"), +/// Some(_) => println!("Unknown scope"), +/// None => println!("Not a multicast address!") +/// } +/// +/// ``` +/// +/// [IPv6 multicast address]: Ipv6Addr +/// [IETF RFC 7346 section 2]: https://tools.ietf.org/html/rfc7346#section-2 +#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)] +#[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] +#[non_exhaustive] +pub enum Ipv6MulticastScope { + /// Interface-Local scope. + InterfaceLocal, + /// Link-Local scope. + LinkLocal, + /// Realm-Local scope. + RealmLocal, + /// Admin-Local scope. + AdminLocal, + /// Site-Local scope. + SiteLocal, + /// Organization-Local scope. + OrganizationLocal, + /// Global scope. + Global, +} + +impl IpAddr { + /// Returns [`true`] for the special 'unspecified' address. + /// + /// See the documentation for [`Ipv4Addr::is_unspecified()`] and + /// [`Ipv6Addr::is_unspecified()`] for more details. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)).is_unspecified(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)).is_unspecified(), true); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(feature = "ip_shared", since = "1.12.0"))] + #[must_use] + #[inline] + pub const fn is_unspecified(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_unspecified(), + IpAddr::V6(ip) => ip.is_unspecified(), + } + } + + /// Returns [`true`] if this is a loopback address. + /// + /// See the documentation for [`Ipv4Addr::is_loopback()`] and + /// [`Ipv6Addr::is_loopback()`] for more details. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).is_loopback(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1)).is_loopback(), true); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(feature = "ip_shared", since = "1.12.0"))] + #[must_use] + #[inline] + pub const fn is_loopback(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_loopback(), + IpAddr::V6(ip) => ip.is_loopback(), + } + } + + /// Returns [`true`] if the address appears to be globally routable. + /// + /// See the documentation for [`Ipv4Addr::is_global()`] and + /// [`Ipv6Addr::is_global()`] for more details. + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(80, 9, 12, 3)).is_global(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1)).is_global(), true); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_ip", issue = "76205") + )] + #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] + #[must_use] + #[inline] + pub const fn is_global(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_global(), + IpAddr::V6(ip) => ip.is_global(), + } + } + + /// Returns [`true`] if this is a multicast address. + /// + /// See the documentation for [`Ipv4Addr::is_multicast()`] and + /// [`Ipv6Addr::is_multicast()`] for more details. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(224, 254, 0, 0)).is_multicast(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0)).is_multicast(), true); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(feature = "ip_shared", since = "1.12.0"))] + #[must_use] + #[inline] + pub const fn is_multicast(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_multicast(), + IpAddr::V6(ip) => ip.is_multicast(), + } + } + + /// Returns [`true`] if this address is in a range designated for documentation. + /// + /// See the documentation for [`Ipv4Addr::is_documentation()`] and + /// [`Ipv6Addr::is_documentation()`] for more details. + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_documentation(), true); + /// assert_eq!( + /// IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_documentation(), + /// true + /// ); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_ip", issue = "76205") + )] + #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] + #[must_use] + #[inline] + pub const fn is_documentation(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_documentation(), + IpAddr::V6(ip) => ip.is_documentation(), + } + } + + /// Returns [`true`] if this address is in a range designated for benchmarking. + /// + /// See the documentation for [`Ipv4Addr::is_benchmarking()`] and + /// [`Ipv6Addr::is_benchmarking()`] for more details. + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(198, 19, 255, 255)).is_benchmarking(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0x2, 0, 0, 0, 0, 0, 0)).is_benchmarking(), true); + /// ``` + #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] + #[must_use] + #[inline] + pub const fn is_benchmarking(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_benchmarking(), + IpAddr::V6(ip) => ip.is_benchmarking(), + } + } + + /// Returns [`true`] if this address is an [`IPv4` address], and [`false`] + /// otherwise. + /// + /// [`IPv4` address]: IpAddr::V4 + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv4(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv4(), false); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(feature = "ipaddr_checker", since = "1.16.0"))] + #[must_use] + #[inline] + pub const fn is_ipv4(&self) -> bool { + matches!(self, IpAddr::V4(_)) + } + + /// Returns [`true`] if this address is an [`IPv6` address], and [`false`] + /// otherwise. + /// + /// [`IPv6` address]: IpAddr::V6 + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv6(), false); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv6(), true); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(feature = "ipaddr_checker", since = "1.16.0"))] + #[must_use] + #[inline] + pub const fn is_ipv6(&self) -> bool { + matches!(self, IpAddr::V6(_)) + } + + /// Converts this address to an `IpAddr::V4` if it is an IPv4-mapped IPv6 addresses, otherwise it + /// return `self` as-is. + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).to_canonical().is_loopback(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1)).is_loopback(), false); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1)).to_canonical().is_loopback(), true); + /// ``` + #[inline] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_ip", issue = "76205") + )] + #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] + pub const fn to_canonical(&self) -> IpAddr { + match self { + &v4 @ IpAddr::V4(_) => v4, + IpAddr::V6(v6) => v6.to_canonical(), + } + } +} + +impl Ipv4Addr { + /// Creates a new IPv4 address from four eight-bit octets. + /// + /// The result will represent the IP address `a`.`b`.`c`.`d`. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::new(127, 0, 0, 1); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_32", since = "1.32.0") + )] + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + #[must_use] + #[inline] + pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { + Ipv4Addr { + octets: [a, b, c, d], + } + } + + /// An IPv4 address with the address pointing to localhost: `127.0.0.1` + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::LOCALHOST; + /// assert_eq!(addr, Ipv4Addr::new(127, 0, 0, 1)); + /// ``` + #[cfg_attr(staged_api, stable(feature = "ip_constructors", since = "1.30.0"))] + pub const LOCALHOST: Self = Ipv4Addr::new(127, 0, 0, 1); + + /// An IPv4 address representing an unspecified address: `0.0.0.0` + /// + /// This corresponds to the constant `INADDR_ANY` in other languages. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::UNSPECIFIED; + /// assert_eq!(addr, Ipv4Addr::new(0, 0, 0, 0)); + /// ``` + #[doc(alias = "INADDR_ANY")] + #[cfg_attr(staged_api, stable(feature = "ip_constructors", since = "1.30.0"))] + pub const UNSPECIFIED: Self = Ipv4Addr::new(0, 0, 0, 0); + + /// An IPv4 address representing the broadcast address: `255.255.255.255` + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::BROADCAST; + /// assert_eq!(addr, Ipv4Addr::new(255, 255, 255, 255)); + /// ``` + #[cfg_attr(staged_api, stable(feature = "ip_constructors", since = "1.30.0"))] + pub const BROADCAST: Self = Ipv4Addr::new(255, 255, 255, 255); + + /// Returns the four eight-bit integers that make up this address. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::new(127, 0, 0, 1); + /// assert_eq!(addr.octets(), [127, 0, 0, 1]); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + #[must_use] + #[inline] + pub const fn octets(&self) -> [u8; 4] { + self.octets + } + + /// Returns [`true`] for the special 'unspecified' address (`0.0.0.0`). + /// + /// This property is defined in _UNIX Network Programming, Second Edition_, + /// W. Richard Stevens, p. 891; see also [ip7]. + /// + /// [ip7]: https://man7.org/linux/man-pages/man7/ip.7.html + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_unspecified(), true); + /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_unspecified(), false); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_32", since = "1.32.0") + )] + #[cfg_attr(staged_api, stable(feature = "ip_shared", since = "1.12.0"))] + #[must_use] + #[inline] + pub const fn is_unspecified(&self) -> bool { + u32::from_be_bytes(self.octets) == 0 + } + + /// Returns [`true`] if this is a loopback address (`127.0.0.0/8`). + /// + /// This property is defined by [IETF RFC 1122]. + /// + /// [IETF RFC 1122]: https://tools.ietf.org/html/rfc1122 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_loopback(), true); + /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_loopback(), false); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] + #[must_use] + #[inline] + pub const fn is_loopback(&self) -> bool { + self.octets()[0] == 127 + } + + /// Returns [`true`] if this is a private address. + /// + /// The private address ranges are defined in [IETF RFC 1918] and include: + /// + /// - `10.0.0.0/8` + /// - `172.16.0.0/12` + /// - `192.168.0.0/16` + /// + /// [IETF RFC 1918]: https://tools.ietf.org/html/rfc1918 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(10, 0, 0, 1).is_private(), true); + /// assert_eq!(Ipv4Addr::new(10, 10, 10, 10).is_private(), true); + /// assert_eq!(Ipv4Addr::new(172, 16, 10, 10).is_private(), true); + /// assert_eq!(Ipv4Addr::new(172, 29, 45, 14).is_private(), true); + /// assert_eq!(Ipv4Addr::new(172, 32, 0, 2).is_private(), false); + /// assert_eq!(Ipv4Addr::new(192, 168, 0, 2).is_private(), true); + /// assert_eq!(Ipv4Addr::new(192, 169, 0, 2).is_private(), false); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] + #[must_use] + #[inline] + pub const fn is_private(&self) -> bool { + match self.octets() { + [10, ..] => true, + [172, b, ..] if b >= 16 && b <= 31 => true, + [192, 168, ..] => true, + _ => false, + } + } + + /// Returns [`true`] if the address is link-local (`169.254.0.0/16`). + /// + /// This property is defined by [IETF RFC 3927]. + /// + /// [IETF RFC 3927]: https://tools.ietf.org/html/rfc3927 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(169, 254, 0, 0).is_link_local(), true); + /// assert_eq!(Ipv4Addr::new(169, 254, 10, 65).is_link_local(), true); + /// assert_eq!(Ipv4Addr::new(16, 89, 10, 65).is_link_local(), false); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] + #[must_use] + #[inline] + pub const fn is_link_local(&self) -> bool { + matches!(self.octets(), [169, 254, ..]) + } + + /// Returns [`true`] if the address appears to be globally reachable + /// as specified by the [IANA IPv4 Special-Purpose Address Registry]. + /// Whether or not an address is practically reachable will depend on your network configuration. + /// + /// Most IPv4 addresses are globally reachable; + /// unless they are specifically defined as *not* globally reachable. + /// + /// Non-exhaustive list of notable addresses that are not globally reachable: + /// + /// - The [unspecified address] ([`is_unspecified`](Ipv4Addr::is_unspecified)) + /// - Addresses reserved for private use ([`is_private`](Ipv4Addr::is_private)) + /// - Addresses in the shared address space ([`is_shared`](Ipv4Addr::is_shared)) + /// - Loopback addresses ([`is_loopback`](Ipv4Addr::is_loopback)) + /// - Link-local addresses ([`is_link_local`](Ipv4Addr::is_link_local)) + /// - Addresses reserved for documentation ([`is_documentation`](Ipv4Addr::is_documentation)) + /// - Addresses reserved for benchmarking ([`is_benchmarking`](Ipv4Addr::is_benchmarking)) + /// - Reserved addresses ([`is_reserved`](Ipv4Addr::is_reserved)) + /// - The [broadcast address] ([`is_broadcast`](Ipv4Addr::is_broadcast)) + /// + /// For the complete overview of which addresses are globally reachable, see the table at the [IANA IPv4 Special-Purpose Address Registry]. + /// + /// [IANA IPv4 Special-Purpose Address Registry]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml + /// [unspecified address]: Ipv4Addr::UNSPECIFIED + /// [broadcast address]: Ipv4Addr::BROADCAST + + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv4Addr; + /// + /// // Most IPv4 addresses are globally reachable: + /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true); + /// + /// // However some addresses have been assigned a special meaning + /// // that makes them not globally reachable. Some examples are: + /// + /// // The unspecified address (`0.0.0.0`) + /// assert_eq!(Ipv4Addr::UNSPECIFIED.is_global(), false); + /// + /// // Addresses reserved for private use (`10.0.0.0/8`, `172.16.0.0/12`, 192.168.0.0/16) + /// assert_eq!(Ipv4Addr::new(10, 254, 0, 0).is_global(), false); + /// assert_eq!(Ipv4Addr::new(192, 168, 10, 65).is_global(), false); + /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_global(), false); + /// + /// // Addresses in the shared address space (`100.64.0.0/10`) + /// assert_eq!(Ipv4Addr::new(100, 100, 0, 0).is_global(), false); + /// + /// // The loopback addresses (`127.0.0.0/8`) + /// assert_eq!(Ipv4Addr::LOCALHOST.is_global(), false); + /// + /// // Link-local addresses (`169.254.0.0/16`) + /// assert_eq!(Ipv4Addr::new(169, 254, 45, 1).is_global(), false); + /// + /// // Addresses reserved for documentation (`192.0.2.0/24`, `198.51.100.0/24`, `203.0.113.0/24`) + /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_global(), false); + /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_global(), false); + /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_global(), false); + /// + /// // Addresses reserved for benchmarking (`198.18.0.0/15`) + /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_global(), false); + /// + /// // Reserved addresses (`240.0.0.0/4`) + /// assert_eq!(Ipv4Addr::new(250, 10, 20, 30).is_global(), false); + /// + /// // The broadcast address (`255.255.255.255`) + /// assert_eq!(Ipv4Addr::BROADCAST.is_global(), false); + /// + /// // For a complete overview see the IANA IPv4 Special-Purpose Address Registry. + /// ``` + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_ipv4", issue = "76205") + )] + #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] + #[must_use] + #[inline] + pub const fn is_global(&self) -> bool { + !(self.octets()[0] == 0 // "This network" + || self.is_private() + || self.is_shared() + || self.is_loopback() + || self.is_link_local() + // addresses reserved for future protocols (`192.0.0.0/24`) + ||(self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0) + || self.is_documentation() + || self.is_benchmarking() + || self.is_reserved() + || self.is_broadcast()) + } + + /// Returns [`true`] if this address is part of the Shared Address Space defined in + /// [IETF RFC 6598] (`100.64.0.0/10`). + /// + /// [IETF RFC 6598]: https://tools.ietf.org/html/rfc6598 + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(100, 64, 0, 0).is_shared(), true); + /// assert_eq!(Ipv4Addr::new(100, 127, 255, 255).is_shared(), true); + /// assert_eq!(Ipv4Addr::new(100, 128, 0, 0).is_shared(), false); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_ipv4", issue = "76205") + )] + #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] + #[must_use] + #[inline] + pub const fn is_shared(&self) -> bool { + self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000) + } + + /// Returns [`true`] if this address part of the `198.18.0.0/15` range, which is reserved for + /// network devices benchmarking. This range is defined in [IETF RFC 2544] as `192.18.0.0` + /// through `198.19.255.255` but [errata 423] corrects it to `198.18.0.0/15`. + /// + /// [IETF RFC 2544]: https://tools.ietf.org/html/rfc2544 + /// [errata 423]: https://www.rfc-editor.org/errata/eid423 + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(198, 17, 255, 255).is_benchmarking(), false); + /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_benchmarking(), true); + /// assert_eq!(Ipv4Addr::new(198, 19, 255, 255).is_benchmarking(), true); + /// assert_eq!(Ipv4Addr::new(198, 20, 0, 0).is_benchmarking(), false); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_ipv4", issue = "76205") + )] + #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] + #[must_use] + #[inline] + pub const fn is_benchmarking(&self) -> bool { + self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18 + } + + /// Returns [`true`] if this address is reserved by IANA for future use. [IETF RFC 1112] + /// defines the block of reserved addresses as `240.0.0.0/4`. This range normally includes the + /// broadcast address `255.255.255.255`, but this implementation explicitly excludes it, since + /// it is obviously not reserved for future use. + /// + /// [IETF RFC 1112]: https://tools.ietf.org/html/rfc1112 + /// + /// # Warning + /// + /// As IANA assigns new addresses, this method will be + /// updated. This may result in non-reserved addresses being + /// treated as reserved in code that relies on an outdated version + /// of this method. + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(240, 0, 0, 0).is_reserved(), true); + /// assert_eq!(Ipv4Addr::new(255, 255, 255, 254).is_reserved(), true); + /// + /// assert_eq!(Ipv4Addr::new(239, 255, 255, 255).is_reserved(), false); + /// // The broadcast address is not considered as reserved for future use by this implementation + /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_reserved(), false); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_ipv4", issue = "76205") + )] + #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] + #[must_use] + #[inline] + pub const fn is_reserved(&self) -> bool { + self.octets()[0] & 240 == 240 && !self.is_broadcast() + } + + /// Returns [`true`] if this is a multicast address (`224.0.0.0/4`). + /// + /// Multicast addresses have a most significant octet between `224` and `239`, + /// and is defined by [IETF RFC 5771]. + /// + /// [IETF RFC 5771]: https://tools.ietf.org/html/rfc5771 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(224, 254, 0, 0).is_multicast(), true); + /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_multicast(), true); + /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_multicast(), false); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] + #[must_use] + #[inline] + pub const fn is_multicast(&self) -> bool { + self.octets()[0] >= 224 && self.octets()[0] <= 239 + } + + /// Returns [`true`] if this is a broadcast address (`255.255.255.255`). + /// + /// A broadcast address has all octets set to `255` as defined in [IETF RFC 919]. + /// + /// [IETF RFC 919]: https://tools.ietf.org/html/rfc919 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_broadcast(), true); + /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_broadcast(), false); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] + #[must_use] + #[inline] + pub const fn is_broadcast(&self) -> bool { + u32::from_be_bytes(self.octets()) == u32::from_be_bytes(Self::BROADCAST.octets()) + } + + /// Returns [`true`] if this address is in a range designated for documentation. + /// + /// This is defined in [IETF RFC 5737]: + /// + /// - `192.0.2.0/24` (TEST-NET-1) + /// - `198.51.100.0/24` (TEST-NET-2) + /// - `203.0.113.0/24` (TEST-NET-3) + /// + /// [IETF RFC 5737]: https://tools.ietf.org/html/rfc5737 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_documentation(), true); + /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_documentation(), true); + /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_documentation(), true); + /// assert_eq!(Ipv4Addr::new(193, 34, 17, 19).is_documentation(), false); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] + #[must_use] + #[inline] + pub const fn is_documentation(&self) -> bool { + matches!( + self.octets(), + [192, 0, 2, _] | [198, 51, 100, _] | [203, 0, 113, _] + ) + } + + /// Converts this address to an [IPv4-compatible] [`IPv6` address]. + /// + /// `a.b.c.d` becomes `::a.b.c.d` + /// + /// Note that IPv4-compatible addresses have been officially deprecated. + /// If you don't explicitly need an IPv4-compatible address for legacy reasons, consider using `to_ipv6_mapped` instead. + /// + /// [IPv4-compatible]: Ipv6Addr#ipv4-compatible-ipv6-addresses + /// [`IPv6` address]: Ipv6Addr + /// + /// # Examples + /// + /// ``` + /// use std::net::{Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!( + /// Ipv4Addr::new(192, 0, 2, 255).to_ipv6_compatible(), + /// Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x2ff) + /// ); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn to_ipv6_compatible(&self) -> Ipv6Addr { + let [a, b, c, d] = self.octets(); + Ipv6Addr { + octets: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d], + } + } + + /// Converts this address to an [IPv4-mapped] [`IPv6` address]. + /// + /// `a.b.c.d` becomes `::ffff:a.b.c.d` + /// + /// [IPv4-mapped]: Ipv6Addr#ipv4-mapped-ipv6-addresses + /// [`IPv6` address]: Ipv6Addr + /// + /// # Examples + /// + /// ``` + /// use std::net::{Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_mapped(), + /// Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x2ff)); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn to_ipv6_mapped(&self) -> Ipv6Addr { + let [a, b, c, d] = self.octets(); + Ipv6Addr { + octets: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, a, b, c, d], + } + } +} + +#[cfg_attr(staged_api, stable(feature = "ip_from_ip", since = "1.16.0"))] +impl From<Ipv4Addr> for IpAddr { + /// Copies this address to a new `IpAddr::V4`. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr}; + /// + /// let addr = Ipv4Addr::new(127, 0, 0, 1); + /// + /// assert_eq!( + /// IpAddr::V4(addr), + /// IpAddr::from(addr) + /// ) + /// ``` + #[inline] + fn from(ipv4: Ipv4Addr) -> IpAddr { + IpAddr::V4(ipv4) + } +} + +#[cfg_attr(staged_api, stable(feature = "ip_from_ip", since = "1.16.0"))] +impl From<Ipv6Addr> for IpAddr { + /// Copies this address to a new `IpAddr::V6`. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv6Addr}; + /// + /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff); + /// + /// assert_eq!( + /// IpAddr::V6(addr), + /// IpAddr::from(addr) + /// ); + /// ``` + #[inline] + fn from(ipv6: Ipv6Addr) -> IpAddr { + IpAddr::V6(ipv6) + } +} + +#[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))] +impl PartialEq<Ipv4Addr> for IpAddr { + #[inline] + fn eq(&self, other: &Ipv4Addr) -> bool { + match self { + IpAddr::V4(v4) => v4 == other, + IpAddr::V6(_) => false, + } + } +} + +#[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))] +impl PartialEq<IpAddr> for Ipv4Addr { + #[inline] + fn eq(&self, other: &IpAddr) -> bool { + match other { + IpAddr::V4(v4) => self == v4, + IpAddr::V6(_) => false, + } + } +} + +#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] +impl PartialOrd for Ipv4Addr { + #[inline] + fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> { + Some(self.cmp(other)) + } +} + +#[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))] +impl PartialOrd<Ipv4Addr> for IpAddr { + #[inline] + fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> { + match self { + IpAddr::V4(v4) => v4.partial_cmp(other), + IpAddr::V6(_) => Some(Ordering::Greater), + } + } +} + +#[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))] +impl PartialOrd<IpAddr> for Ipv4Addr { + #[inline] + fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> { + match other { + IpAddr::V4(v4) => self.partial_cmp(v4), + IpAddr::V6(_) => Some(Ordering::Less), + } + } +} + +#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] +impl Ord for Ipv4Addr { + #[inline] + fn cmp(&self, other: &Ipv4Addr) -> Ordering { + self.octets.cmp(&other.octets) + } +} + +#[cfg_attr(staged_api, stable(feature = "ip_u32", since = "1.1.0"))] +impl From<Ipv4Addr> for u32 { + /// Converts an `Ipv4Addr` into a host byte order `u32`. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::new(0x12, 0x34, 0x56, 0x78); + /// assert_eq!(0x12345678, u32::from(addr)); + /// ``` + #[inline] + fn from(ip: Ipv4Addr) -> u32 { + u32::from_be_bytes(ip.octets) + } +} + +#[cfg_attr(staged_api, stable(feature = "ip_u32", since = "1.1.0"))] +impl From<u32> for Ipv4Addr { + /// Converts a host byte order `u32` into an `Ipv4Addr`. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::from(0x12345678); + /// assert_eq!(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78), addr); + /// ``` + #[inline] + fn from(ip: u32) -> Ipv4Addr { + Ipv4Addr { + octets: ip.to_be_bytes(), + } + } +} + +#[cfg_attr(staged_api, stable(feature = "from_slice_v4", since = "1.9.0"))] +impl From<[u8; 4]> for Ipv4Addr { + /// Creates an `Ipv4Addr` from a four element byte array. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::from([13u8, 12u8, 11u8, 10u8]); + /// assert_eq!(Ipv4Addr::new(13, 12, 11, 10), addr); + /// ``` + #[inline] + fn from(octets: [u8; 4]) -> Ipv4Addr { + Ipv4Addr { octets } + } +} + +#[cfg_attr(staged_api, stable(feature = "ip_from_slice", since = "1.17.0"))] +impl From<[u8; 4]> for IpAddr { + /// Creates an `IpAddr::V4` from a four element byte array. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr}; + /// + /// let addr = IpAddr::from([13u8, 12u8, 11u8, 10u8]); + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(13, 12, 11, 10)), addr); + /// ``` + #[inline] + fn from(octets: [u8; 4]) -> IpAddr { + IpAddr::V4(Ipv4Addr::from(octets)) + } +} + +impl Ipv6Addr { + /// Creates a new IPv6 address from eight 16-bit segments. + /// + /// The result will represent the IP address `a:b:c:d:e:f:g:h`. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_32", since = "1.32.0") + )] + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + #[allow(clippy::too_many_arguments)] + #[must_use] + #[inline] + pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr { + let addr16 = [ + a.to_be(), + b.to_be(), + c.to_be(), + d.to_be(), + e.to_be(), + f.to_be(), + g.to_be(), + h.to_be(), + ]; + Ipv6Addr { + // All elements in `addr16` are big endian. + // SAFETY: `[u16; 8]` is always safe to transmute to `[u8; 16]`. + octets: unsafe { transmute::<_, [u8; 16]>(addr16) }, + } + } + + /// An IPv6 address representing localhost: `::1`. + /// + /// This corresponds to constant `IN6ADDR_LOOPBACK_INIT` or `in6addr_loopback` in other + /// languages. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// let addr = Ipv6Addr::LOCALHOST; + /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); + /// ``` + #[doc(alias = "IN6ADDR_LOOPBACK_INIT")] + #[doc(alias = "in6addr_loopback")] + #[cfg_attr(staged_api, stable(feature = "ip_constructors", since = "1.30.0"))] + pub const LOCALHOST: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); + + /// An IPv6 address representing the unspecified address: `::` + /// + /// This corresponds to constant `IN6ADDR_ANY_INIT` or `in6addr_any` in other languages. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// let addr = Ipv6Addr::UNSPECIFIED; + /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); + /// ``` + #[doc(alias = "IN6ADDR_ANY_INIT")] + #[doc(alias = "in6addr_any")] + #[cfg_attr(staged_api, stable(feature = "ip_constructors", since = "1.30.0"))] + pub const UNSPECIFIED: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); + + /// Returns the eight 16-bit segments that make up this address. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).segments(), + /// [0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff]); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + #[must_use] + #[inline] + pub const fn segments(&self) -> [u16; 8] { + // All elements in `self.octets` must be big endian. + // SAFETY: `[u8; 16]` is always safe to transmute to `[u16; 8]`. + let [a, b, c, d, e, f, g, h] = unsafe { transmute::<_, [u16; 8]>(self.octets) }; + // We want native endian u16 + [ + u16::from_be(a), + u16::from_be(b), + u16::from_be(c), + u16::from_be(d), + u16::from_be(e), + u16::from_be(f), + u16::from_be(g), + u16::from_be(h), + ] + } + + /// Returns [`true`] for the special 'unspecified' address (`::`). + /// + /// This property is defined in [IETF RFC 4291]. + /// + /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unspecified(), false); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).is_unspecified(), true); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] + #[must_use] + #[inline] + pub const fn is_unspecified(&self) -> bool { + u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::UNSPECIFIED.octets()) + } + + /// Returns [`true`] if this is the [loopback address] (`::1`), + /// as defined in [IETF RFC 4291 section 2.5.3]. + /// + /// Contrary to IPv4, in IPv6 there is only one loopback address. + /// + /// [loopback address]: Ipv6Addr::LOCALHOST + /// [IETF RFC 4291 section 2.5.3]: https://tools.ietf.org/html/rfc4291#section-2.5.3 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_loopback(), false); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_loopback(), true); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] + #[must_use] + #[inline] + pub const fn is_loopback(&self) -> bool { + u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets()) + } + + /// Returns [`true`] if the address appears to be globally reachable + /// as specified by the [IANA IPv6 Special-Purpose Address Registry]. + /// Whether or not an address is practically reachable will depend on your network configuration. + /// + /// Most IPv6 addresses are globally reachable; + /// unless they are specifically defined as *not* globally reachable. + /// + /// Non-exhaustive list of notable addresses that are not globally reachable: + /// - The [unspecified address] ([`is_unspecified`](Ipv6Addr::is_unspecified)) + /// - The [loopback address] ([`is_loopback`](Ipv6Addr::is_loopback)) + /// - IPv4-mapped addresses + /// - Addresses reserved for benchmarking + /// - Addresses reserved for documentation ([`is_documentation`](Ipv6Addr::is_documentation)) + /// - Unique local addresses ([`is_unique_local`](Ipv6Addr::is_unique_local)) + /// - Unicast addresses with link-local scope ([`is_unicast_link_local`](Ipv6Addr::is_unicast_link_local)) + /// + /// For the complete overview of which addresses are globally reachable, see the table at the [IANA IPv6 Special-Purpose Address Registry]. + /// + /// Note that an address having global scope is not the same as being globally reachable, + /// and there is no direct relation between the two concepts: There exist addresses with global scope + /// that are not globally reachable (for example unique local addresses), + /// and addresses that are globally reachable without having global scope + /// (multicast addresses with non-global scope). + /// + /// [IANA IPv6 Special-Purpose Address Registry]: https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml + /// [unspecified address]: Ipv6Addr::UNSPECIFIED + /// [loopback address]: Ipv6Addr::LOCALHOST + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv6Addr; + /// + /// // Most IPv6 addresses are globally reachable: + /// assert_eq!(Ipv6Addr::new(0x26, 0, 0x1c9, 0, 0, 0xafc8, 0x10, 0x1).is_global(), true); + /// + /// // However some addresses have been assigned a special meaning + /// // that makes them not globally reachable. Some examples are: + /// + /// // The unspecified address (`::`) + /// assert_eq!(Ipv6Addr::UNSPECIFIED.is_global(), false); + /// + /// // The loopback address (`::1`) + /// assert_eq!(Ipv6Addr::LOCALHOST.is_global(), false); + /// + /// // IPv4-mapped addresses (`::ffff:0:0/96`) + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), false); + /// + /// // Addresses reserved for benchmarking (`2001:2::/48`) + /// assert_eq!(Ipv6Addr::new(0x2001, 2, 0, 0, 0, 0, 0, 1,).is_global(), false); + /// + /// // Addresses reserved for documentation (`2001:db8::/32`) + /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1).is_global(), false); + /// + /// // Unique local addresses (`fc00::/7`) + /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 1).is_global(), false); + /// + /// // Unicast addresses with link-local scope (`fe80::/10`) + /// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 1).is_global(), false); + /// + /// // For a complete overview see the IANA IPv6 Special-Purpose Address Registry. + /// ``` + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_ipv6", issue = "76205") + )] + #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] + #[must_use] + #[inline] + pub const fn is_global(&self) -> bool { + !(self.is_unspecified() + || self.is_loopback() + // IPv4-mapped Address (`::ffff:0:0/96`) + || matches!(self.segments(), [0, 0, 0, 0, 0, 0xffff, _, _]) + // IPv4-IPv6 Translat. (`64:ff9b:1::/48`) + || matches!(self.segments(), [0x64, 0xff9b, 1, _, _, _, _, _]) + // Discard-Only Address Block (`100::/64`) + || matches!(self.segments(), [0x100, 0, 0, 0, _, _, _, _]) + // IETF Protocol Assignments (`2001::/23`) + || (matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b < 0x200) + && !( + // Port Control Protocol Anycast (`2001:1::1`) + u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0001 + // Traversal Using Relays around NAT Anycast (`2001:1::2`) + || u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0002 + // AMT (`2001:3::/32`) + || matches!(self.segments(), [0x2001, 3, _, _, _, _, _, _]) + // AS112-v6 (`2001:4:112::/48`) + || matches!(self.segments(), [0x2001, 4, 0x112, _, _, _, _, _]) + // ORCHIDv2 (`2001:20::/28`) + || matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x2F) + )) + || self.is_documentation() + || self.is_unique_local() + || self.is_unicast_link_local()) + } + + /// Returns [`true`] if this is a unique local address (`fc00::/7`). + /// + /// This property is defined in [IETF RFC 4193]. + /// + /// [IETF RFC 4193]: https://tools.ietf.org/html/rfc4193 + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unique_local(), false); + /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_ipv6", issue = "76205") + )] + #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] + #[must_use] + #[inline] + pub const fn is_unique_local(&self) -> bool { + (self.segments()[0] & 0xfe00) == 0xfc00 + } + + /// Returns [`true`] if this is a unicast address, as defined by [IETF RFC 4291]. + /// Any address that is not a [multicast address] (`ff00::/8`) is unicast. + /// + /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [multicast address]: Ipv6Addr::is_multicast + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv6Addr; + /// + /// // The unspecified and loopback addresses are unicast. + /// assert_eq!(Ipv6Addr::UNSPECIFIED.is_unicast(), true); + /// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast(), true); + /// + /// // Any address that is not a multicast address (`ff00::/8`) is unicast. + /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast(), true); + /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_unicast(), false); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_ipv6", issue = "76205") + )] + #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] + #[must_use] + #[inline] + pub const fn is_unicast(&self) -> bool { + !self.is_multicast() + } + + /// Returns `true` if the address is a unicast address with link-local scope, + /// as defined in [RFC 4291]. + /// + /// A unicast address has link-local scope if it has the prefix `fe80::/10`, as per [RFC 4291 section 2.4]. + /// Note that this encompasses more addresses than those defined in [RFC 4291 section 2.5.6], + /// which describes "Link-Local IPv6 Unicast Addresses" as having the following stricter format: + /// + /// ```text + /// | 10 bits | 54 bits | 64 bits | + /// +----------+-------------------------+----------------------------+ + /// |1111111010| 0 | interface ID | + /// +----------+-------------------------+----------------------------+ + /// ``` + /// So while currently the only addresses with link-local scope an application will encounter are all in `fe80::/64`, + /// this might change in the future with the publication of new standards. More addresses in `fe80::/10` could be allocated, + /// and those addresses will have link-local scope. + /// + /// Also note that while [RFC 4291 section 2.5.3] mentions about the [loopback address] (`::1`) that "it is treated as having Link-Local scope", + /// this does not mean that the loopback address actually has link-local scope and this method will return `false` on it. + /// + /// [RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4 + /// [RFC 4291 section 2.5.3]: https://tools.ietf.org/html/rfc4291#section-2.5.3 + /// [RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6 + /// [loopback address]: Ipv6Addr::LOCALHOST + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv6Addr; + /// + /// // The loopback address (`::1`) does not actually have link-local scope. + /// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast_link_local(), false); + /// + /// // Only addresses in `fe80::/10` have link-local scope. + /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), false); + /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true); + /// + /// // Addresses outside the stricter `fe80::/64` also have link-local scope. + /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0).is_unicast_link_local(), true); + /// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_ipv6", issue = "76205") + )] + #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] + #[must_use] + #[inline] + pub const fn is_unicast_link_local(&self) -> bool { + (self.segments()[0] & 0xffc0) == 0xfe80 + } + + /// Returns [`true`] if this is an address reserved for documentation + /// (`2001:db8::/32`). + /// + /// This property is defined in [IETF RFC 3849]. + /// + /// [IETF RFC 3849]: https://tools.ietf.org/html/rfc3849 + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_documentation(), false); + /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_ipv6", issue = "76205") + )] + #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] + #[must_use] + #[inline] + pub const fn is_documentation(&self) -> bool { + (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) + } + + /// Returns [`true`] if this is an address reserved for benchmarking (`2001:2::/48`). + /// + /// This property is defined in [IETF RFC 5180], where it is mistakenly specified as covering the range `2001:0200::/48`. + /// This is corrected in [IETF RFC Errata 1752] to `2001:0002::/48`. + /// + /// [IETF RFC 5180]: https://tools.ietf.org/html/rfc5180 + /// [IETF RFC Errata 1752]: https://www.rfc-editor.org/errata_search.php?eid=1752 + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc613, 0x0).is_benchmarking(), false); + /// assert_eq!(Ipv6Addr::new(0x2001, 0x2, 0, 0, 0, 0, 0, 0).is_benchmarking(), true); + /// ``` + #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] + #[must_use] + #[inline] + pub const fn is_benchmarking(&self) -> bool { + (self.segments()[0] == 0x2001) && (self.segments()[1] == 0x2) && (self.segments()[2] == 0) + } + + /// Returns [`true`] if the address is a globally routable unicast address. + /// + /// The following return false: + /// + /// - the loopback address + /// - the link-local addresses + /// - unique local addresses + /// - the unspecified address + /// - the address range reserved for documentation + /// + /// This method returns [`true`] for site-local addresses as per [RFC 4291 section 2.5.7] + /// + /// ```no_rust + /// The special behavior of [the site-local unicast] prefix defined in [RFC3513] must no longer + /// be supported in new implementations (i.e., new implementations must treat this prefix as + /// Global Unicast). + /// ``` + /// + /// [RFC 4291 section 2.5.7]: https://tools.ietf.org/html/rfc4291#section-2.5.7 + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_global(), false); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_global(), true); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_ipv6", issue = "76205") + )] + #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] + #[must_use] + #[inline] + pub const fn is_unicast_global(&self) -> bool { + self.is_unicast() + && !self.is_loopback() + && !self.is_unicast_link_local() + && !self.is_unique_local() + && !self.is_unspecified() + && !self.is_documentation() + && !self.is_benchmarking() + } + + /// Returns the address's multicast scope if the address is multicast. + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::{Ipv6Addr, Ipv6MulticastScope}; + /// + /// assert_eq!( + /// Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0).multicast_scope(), + /// Some(Ipv6MulticastScope::Global) + /// ); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_ipv6", issue = "76205") + )] + #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] + #[must_use] + #[inline] + pub const fn multicast_scope(&self) -> Option<Ipv6MulticastScope> { + if self.is_multicast() { + match self.segments()[0] & 0x000f { + 1 => Some(Ipv6MulticastScope::InterfaceLocal), + 2 => Some(Ipv6MulticastScope::LinkLocal), + 3 => Some(Ipv6MulticastScope::RealmLocal), + 4 => Some(Ipv6MulticastScope::AdminLocal), + 5 => Some(Ipv6MulticastScope::SiteLocal), + 8 => Some(Ipv6MulticastScope::OrganizationLocal), + 14 => Some(Ipv6MulticastScope::Global), + _ => None, + } + } else { + None + } + } + + /// Returns [`true`] if this is a multicast address (`ff00::/8`). + /// + /// This property is defined by [IETF RFC 4291]. + /// + /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_multicast(), true); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_multicast(), false); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] + #[must_use] + #[inline] + pub const fn is_multicast(&self) -> bool { + (self.segments()[0] & 0xff00) == 0xff00 + } + + /// Converts this address to an [`IPv4` address] if it's an [IPv4-mapped] address, + /// as defined in [IETF RFC 4291 section 2.5.5.2], otherwise returns [`None`]. + /// + /// `::ffff:a.b.c.d` becomes `a.b.c.d`. + /// All addresses *not* starting with `::ffff` will return `None`. + /// + /// [`IPv4` address]: Ipv4Addr + /// [IPv4-mapped]: Ipv6Addr + /// [IETF RFC 4291 section 2.5.5.2]: https://tools.ietf.org/html/rfc4291#section-2.5.5.2 + /// + /// # Examples + /// + /// ``` + /// use std::net::{Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4_mapped(), None); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4_mapped(), + /// Some(Ipv4Addr::new(192, 10, 2, 255))); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4_mapped(), None); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_ipv6", issue = "76205") + )] + #[cfg_attr(staged_api, stable(feature = "ipv6_to_ipv4_mapped", since = "1.63.0"))] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn to_ipv4_mapped(&self) -> Option<Ipv4Addr> { + match self.octets() { + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, a, b, c, d] => { + Some(Ipv4Addr::new(a, b, c, d)) + } + _ => None, + } + } + + /// Converts this address to an [`IPv4` address] if it is either + /// an [IPv4-compatible] address as defined in [IETF RFC 4291 section 2.5.5.1], + /// or an [IPv4-mapped] address as defined in [IETF RFC 4291 section 2.5.5.2], + /// otherwise returns [`None`]. + /// + /// Note that this will return an [`IPv4` address] for the IPv6 loopback address `::1`. Use + /// [`Ipv6Addr::to_ipv4_mapped`] to avoid this. + /// + /// `::a.b.c.d` and `::ffff:a.b.c.d` become `a.b.c.d`. `::1` becomes `0.0.0.1`. + /// All addresses *not* starting with either all zeroes or `::ffff` will return `None`. + /// + /// [`IPv4` address]: Ipv4Addr + /// [IPv4-compatible]: Ipv6Addr#ipv4-compatible-ipv6-addresses + /// [IPv4-mapped]: Ipv6Addr#ipv4-mapped-ipv6-addresses + /// [IETF RFC 4291 section 2.5.5.1]: https://tools.ietf.org/html/rfc4291#section-2.5.5.1 + /// [IETF RFC 4291 section 2.5.5.2]: https://tools.ietf.org/html/rfc4291#section-2.5.5.2 + /// + /// # Examples + /// + /// ``` + /// use std::net::{Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4(), None); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4(), + /// Some(Ipv4Addr::new(192, 10, 2, 255))); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4(), + /// Some(Ipv4Addr::new(0, 0, 0, 1))); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn to_ipv4(&self) -> Option<Ipv4Addr> { + if let [0, 0, 0, 0, 0, 0 | 0xffff, ab, cd] = self.segments() { + let [a, b] = ab.to_be_bytes(); + let [c, d] = cd.to_be_bytes(); + Some(Ipv4Addr::new(a, b, c, d)) + } else { + None + } + } + + /// Converts this address to an `IpAddr::V4` if it is an IPv4-mapped addresses, otherwise it + /// returns self wrapped in an `IpAddr::V6`. + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).is_loopback(), false); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).to_canonical().is_loopback(), true); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_ipv6", issue = "76205") + )] + #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn to_canonical(&self) -> IpAddr { + if let Some(mapped) = self.to_ipv4_mapped() { + return IpAddr::V4(mapped); + } + IpAddr::V6(*self) + } + + /// Returns the sixteen eight-bit integers the IPv6 address consists of. + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).octets(), + /// [255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_32", since = "1.32.0") + )] + #[cfg_attr(staged_api, stable(feature = "ipv6_to_octets", since = "1.12.0"))] + #[must_use] + #[inline] + pub const fn octets(&self) -> [u8; 16] { + self.octets + } +} + +#[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))] +impl PartialEq<IpAddr> for Ipv6Addr { + #[inline] + fn eq(&self, other: &IpAddr) -> bool { + match other { + IpAddr::V4(_) => false, + IpAddr::V6(v6) => self == v6, + } + } +} + +#[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))] +impl PartialEq<Ipv6Addr> for IpAddr { + #[inline] + fn eq(&self, other: &Ipv6Addr) -> bool { + match self { + IpAddr::V4(_) => false, + IpAddr::V6(v6) => v6 == other, + } + } +} + +#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] +impl PartialOrd for Ipv6Addr { + #[inline] + fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> { + Some(self.cmp(other)) + } +} + +#[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))] +impl PartialOrd<Ipv6Addr> for IpAddr { + #[inline] + fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> { + match self { + IpAddr::V4(_) => Some(Ordering::Less), + IpAddr::V6(v6) => v6.partial_cmp(other), + } + } +} + +#[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))] +impl PartialOrd<IpAddr> for Ipv6Addr { + #[inline] + fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> { + match other { + IpAddr::V4(_) => Some(Ordering::Greater), + IpAddr::V6(v6) => self.partial_cmp(v6), + } + } +} + +#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] +impl Ord for Ipv6Addr { + #[inline] + fn cmp(&self, other: &Ipv6Addr) -> Ordering { + self.segments().cmp(&other.segments()) + } +} + +#[cfg_attr(staged_api, stable(feature = "i128", since = "1.26.0"))] +impl From<Ipv6Addr> for u128 { + /// Convert an `Ipv6Addr` into a host byte order `u128`. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// let addr = Ipv6Addr::new( + /// 0x1020, 0x3040, 0x5060, 0x7080, + /// 0x90A0, 0xB0C0, 0xD0E0, 0xF00D, + /// ); + /// assert_eq!(0x102030405060708090A0B0C0D0E0F00D_u128, u128::from(addr)); + /// ``` + #[inline] + fn from(ip: Ipv6Addr) -> u128 { + u128::from_be_bytes(ip.octets) + } +} +#[cfg_attr(staged_api, stable(feature = "i128", since = "1.26.0"))] +impl From<u128> for Ipv6Addr { + /// Convert a host byte order `u128` into an `Ipv6Addr`. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// let addr = Ipv6Addr::from(0x102030405060708090A0B0C0D0E0F00D_u128); + /// assert_eq!( + /// Ipv6Addr::new( + /// 0x1020, 0x3040, 0x5060, 0x7080, + /// 0x90A0, 0xB0C0, 0xD0E0, 0xF00D, + /// ), + /// addr); + /// ``` + #[inline] + fn from(ip: u128) -> Ipv6Addr { + Ipv6Addr::from(ip.to_be_bytes()) + } +} + +#[cfg_attr(staged_api, stable(feature = "ipv6_from_octets", since = "1.9.0"))] +impl From<[u8; 16]> for Ipv6Addr { + /// Creates an `Ipv6Addr` from a sixteen element byte array. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// let addr = Ipv6Addr::from([ + /// 25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8, + /// 17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8, + /// ]); + /// assert_eq!( + /// Ipv6Addr::new( + /// 0x1918, 0x1716, + /// 0x1514, 0x1312, + /// 0x1110, 0x0f0e, + /// 0x0d0c, 0x0b0a + /// ), + /// addr + /// ); + /// ``` + #[inline] + fn from(octets: [u8; 16]) -> Ipv6Addr { + Ipv6Addr { octets } + } +} + +#[cfg_attr(staged_api, stable(feature = "ipv6_from_segments", since = "1.16.0"))] +impl From<[u16; 8]> for Ipv6Addr { + /// Creates an `Ipv6Addr` from an eight element 16-bit array. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// let addr = Ipv6Addr::from([ + /// 525u16, 524u16, 523u16, 522u16, + /// 521u16, 520u16, 519u16, 518u16, + /// ]); + /// assert_eq!( + /// Ipv6Addr::new( + /// 0x20d, 0x20c, + /// 0x20b, 0x20a, + /// 0x209, 0x208, + /// 0x207, 0x206 + /// ), + /// addr + /// ); + /// ``` + #[inline] + fn from(segments: [u16; 8]) -> Ipv6Addr { + let [a, b, c, d, e, f, g, h] = segments; + Ipv6Addr::new(a, b, c, d, e, f, g, h) + } +} + +#[cfg_attr(staged_api, stable(feature = "ip_from_slice", since = "1.17.0"))] +impl From<[u8; 16]> for IpAddr { + /// Creates an `IpAddr::V6` from a sixteen element byte array. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv6Addr}; + /// + /// let addr = IpAddr::from([ + /// 25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8, + /// 17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8, + /// ]); + /// assert_eq!( + /// IpAddr::V6(Ipv6Addr::new( + /// 0x1918, 0x1716, + /// 0x1514, 0x1312, + /// 0x1110, 0x0f0e, + /// 0x0d0c, 0x0b0a + /// )), + /// addr + /// ); + /// ``` + #[inline] + fn from(octets: [u8; 16]) -> IpAddr { + IpAddr::V6(Ipv6Addr::from(octets)) + } +} + +#[cfg_attr(staged_api, stable(feature = "ip_from_slice", since = "1.17.0"))] +impl From<[u16; 8]> for IpAddr { + /// Creates an `IpAddr::V6` from an eight element 16-bit array. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv6Addr}; + /// + /// let addr = IpAddr::from([ + /// 525u16, 524u16, 523u16, 522u16, + /// 521u16, 520u16, 519u16, 518u16, + /// ]); + /// assert_eq!( + /// IpAddr::V6(Ipv6Addr::new( + /// 0x20d, 0x20c, + /// 0x20b, 0x20a, + /// 0x209, 0x208, + /// 0x207, 0x206 + /// )), + /// addr + /// ); + /// ``` + #[inline] + fn from(segments: [u16; 8]) -> IpAddr { + IpAddr::V6(Ipv6Addr::from(segments)) + } +} diff --git a/vendor/rustix-0.37.22/src/net/mod.rs b/vendor/rustix-0.37.22/src/net/mod.rs new file mode 100644 index 000000000..7b5216e15 --- /dev/null +++ b/vendor/rustix-0.37.22/src/net/mod.rs @@ -0,0 +1,37 @@ +//! Network-related operations. +//! +//! On Windows, one must call [`wsa_startup`] in the process before calling any +//! of these APIs. [`wsa_cleanup`] may be used in the process if these APIs are +//! no longer needed. +//! +//! [`wsa_startup`]: https://docs.rs/rustix/*/x86_64-pc-windows-msvc/rustix/net/fn.wsa_startup.html +//! [`wsa_cleanup`]: https://docs.rs/rustix/*/x86_64-pc-windows-msvc/rustix/net/fn.wsa_cleanup.html + +#[cfg(not(feature = "std"))] +mod addr; +#[cfg(not(feature = "std"))] +mod ip; +mod send_recv; +mod socket; +mod socket_addr_any; +#[cfg(not(any(windows, target_os = "wasi")))] +mod socketpair; +#[cfg(windows)] +mod wsa; + +pub mod sockopt; + +pub use send_recv::*; +pub use socket::*; +pub use socket_addr_any::{SocketAddrAny, SocketAddrStorage}; +#[cfg(not(any(windows, target_os = "wasi")))] +pub use socketpair::socketpair; +#[cfg(feature = "std")] +pub use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; +#[cfg(windows)] +pub use wsa::{wsa_cleanup, wsa_startup}; +#[cfg(not(feature = "std"))] +pub use { + addr::{SocketAddr, SocketAddrV4, SocketAddrV6}, + ip::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope}, +}; diff --git a/vendor/rustix-0.37.22/src/net/send_recv/mod.rs b/vendor/rustix-0.37.22/src/net/send_recv/mod.rs new file mode 100644 index 000000000..a2bb520a0 --- /dev/null +++ b/vendor/rustix-0.37.22/src/net/send_recv/mod.rs @@ -0,0 +1,326 @@ +//! `recv` and `send`, and variants. + +#[cfg(unix)] +use crate::net::SocketAddrUnix; +use crate::net::{SocketAddr, SocketAddrAny, SocketAddrV4, SocketAddrV6}; +use crate::{backend, io}; +use backend::fd::{AsFd, BorrowedFd}; + +pub use backend::net::send_recv::{RecvFlags, SendFlags}; + +#[cfg(not(any(windows, target_os = "redox", target_os = "wasi")))] +mod msg; + +#[cfg(not(any(windows, target_os = "redox", target_os = "wasi")))] +pub use msg::*; + +/// `recv(fd, buf, flags)`—Reads data from a socket. +/// +/// # References +/// - [Beej's Guide to Network Programming] +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [Winsock2] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#sendrecv +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/recv.html +/// [Linux]: https://man7.org/linux/man-pages/man2/recv.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/recv.2.html +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-recv +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=recv&sektion=2 +/// [NetBSD]: https://man.netbsd.org/recv.2 +/// [OpenBSD]: https://man.openbsd.org/recv.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=recv§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/recv +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Receiving-Data.html +#[inline] +pub fn recv<Fd: AsFd>(fd: Fd, buf: &mut [u8], flags: RecvFlags) -> io::Result<usize> { + backend::net::syscalls::recv(fd.as_fd(), buf, flags) +} + +/// `send(fd, buf, flags)`—Writes data to a socket. +/// +/// # References +/// - [Beej's Guide to Network Programming] +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [Winsock2] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#sendrecv +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html +/// [Linux]: https://man7.org/linux/man-pages/man2/send.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/send.2.html +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-send +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=send&sektion=2 +/// [NetBSD]: https://man.netbsd.org/send.2 +/// [OpenBSD]: https://man.openbsd.org/send.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=send§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/send +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Sending-Data.html +#[inline] +pub fn send<Fd: AsFd>(fd: Fd, buf: &[u8], flags: SendFlags) -> io::Result<usize> { + backend::net::syscalls::send(fd.as_fd(), buf, flags) +} + +/// `recvfrom(fd, buf, flags, addr, len)`—Reads data from a socket and +/// returns the sender address. +/// +/// # References +/// - [Beej's Guide to Network Programming] +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [Winsock2] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#sendtorecv +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html +/// [Linux]: https://man7.org/linux/man-pages/man2/recvfrom.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/recvfrom.2.html +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-recvfrom +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=recvfrom&sektion=2 +/// [NetBSD]: https://man.netbsd.org/recvfrom.2 +/// [OpenBSD]: https://man.openbsd.org/recvfrom.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=recvfrom§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/recvfrom +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Receiving-Datagrams.html +#[inline] +pub fn recvfrom<Fd: AsFd>( + fd: Fd, + buf: &mut [u8], + flags: RecvFlags, +) -> io::Result<(usize, Option<SocketAddrAny>)> { + backend::net::syscalls::recvfrom(fd.as_fd(), buf, flags) +} + +/// `sendto(fd, buf, flags, addr)`—Writes data to a socket to a specific IP +/// address. +/// +/// # References +/// - [Beej's Guide to Network Programming] +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [Winsock2] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#sendtorecv +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html +/// [Linux]: https://man7.org/linux/man-pages/man2/sendto.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendto.2.html +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-sendto +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendto&sektion=2 +/// [NetBSD]: https://man.netbsd.org/sendto.2 +/// [OpenBSD]: https://man.openbsd.org/sendto.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendto§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/sendto +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Sending-Datagrams.html +pub fn sendto<Fd: AsFd>( + fd: Fd, + buf: &[u8], + flags: SendFlags, + addr: &SocketAddr, +) -> io::Result<usize> { + _sendto(fd.as_fd(), buf, flags, addr) +} + +fn _sendto( + fd: BorrowedFd<'_>, + buf: &[u8], + flags: SendFlags, + addr: &SocketAddr, +) -> io::Result<usize> { + match addr { + SocketAddr::V4(v4) => backend::net::syscalls::sendto_v4(fd, buf, flags, v4), + SocketAddr::V6(v6) => backend::net::syscalls::sendto_v6(fd, buf, flags, v6), + } +} + +/// `sendto(fd, buf, flags, addr)`—Writes data to a socket to a specific +/// address. +/// +/// # References +/// - [Beej's Guide to Network Programming] +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [Winsock2] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#sendtorecv +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html +/// [Linux]: https://man7.org/linux/man-pages/man2/sendto.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendto.2.html +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-sendto +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendto&sektion=2 +/// [NetBSD]: https://man.netbsd.org/sendto.2 +/// [OpenBSD]: https://man.openbsd.org/sendto.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendto§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/sendto +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Sending-Datagrams.html +pub fn sendto_any<Fd: AsFd>( + fd: Fd, + buf: &[u8], + flags: SendFlags, + addr: &SocketAddrAny, +) -> io::Result<usize> { + _sendto_any(fd.as_fd(), buf, flags, addr) +} + +fn _sendto_any( + fd: BorrowedFd<'_>, + buf: &[u8], + flags: SendFlags, + addr: &SocketAddrAny, +) -> io::Result<usize> { + match addr { + SocketAddrAny::V4(v4) => backend::net::syscalls::sendto_v4(fd, buf, flags, v4), + SocketAddrAny::V6(v6) => backend::net::syscalls::sendto_v6(fd, buf, flags, v6), + #[cfg(unix)] + SocketAddrAny::Unix(unix) => backend::net::syscalls::sendto_unix(fd, buf, flags, unix), + } +} + +/// `sendto(fd, buf, flags, addr, sizeof(struct sockaddr_in))`—Writes data to +/// a socket to a specific IPv4 address. +/// +/// # References +/// - [Beej's Guide to Network Programming] +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [Winsock2] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#sendtorecv +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html +/// [Linux]: https://man7.org/linux/man-pages/man2/sendto.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendto.2.html +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-sendto +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendto&sektion=2 +/// [NetBSD]: https://man.netbsd.org/sendto.2 +/// [OpenBSD]: https://man.openbsd.org/sendto.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendto§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/sendto +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Sending-Datagrams.html +#[inline] +#[doc(alias = "sendto")] +pub fn sendto_v4<Fd: AsFd>( + fd: Fd, + buf: &[u8], + flags: SendFlags, + addr: &SocketAddrV4, +) -> io::Result<usize> { + backend::net::syscalls::sendto_v4(fd.as_fd(), buf, flags, addr) +} + +/// `sendto(fd, buf, flags, addr, sizeof(struct sockaddr_in6))`—Writes data +/// to a socket to a specific IPv6 address. +/// +/// # References +/// - [Beej's Guide to Network Programming] +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [Winsock2] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#sendtorecv +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html +/// [Linux]: https://man7.org/linux/man-pages/man2/sendto.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendto.2.html +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-sendto +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendto&sektion=2 +/// [NetBSD]: https://man.netbsd.org/sendto.2 +/// [OpenBSD]: https://man.openbsd.org/sendto.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendto§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/sendto +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Sending-Datagrams.html +#[inline] +#[doc(alias = "sendto")] +pub fn sendto_v6<Fd: AsFd>( + fd: Fd, + buf: &[u8], + flags: SendFlags, + addr: &SocketAddrV6, +) -> io::Result<usize> { + backend::net::syscalls::sendto_v6(fd.as_fd(), buf, flags, addr) +} + +/// `sendto(fd, buf, flags, addr, sizeof(struct sockaddr_un))`—Writes data to +/// a socket to a specific Unix-domain socket address. +/// +/// # References +/// - [Beej's Guide to Network Programming] +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [Winsock2] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#sendtorecv +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html +/// [Linux]: https://man7.org/linux/man-pages/man2/sendto.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendto.2.html +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-sendto +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendto&sektion=2 +/// [NetBSD]: https://man.netbsd.org/sendto.2 +/// [OpenBSD]: https://man.openbsd.org/sendto.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendto§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/sendto +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Sending-Datagrams.html +#[cfg(unix)] +#[inline] +#[doc(alias = "sendto")] +pub fn sendto_unix<Fd: AsFd>( + fd: Fd, + buf: &[u8], + flags: SendFlags, + addr: &SocketAddrUnix, +) -> io::Result<usize> { + backend::net::syscalls::sendto_unix(fd.as_fd(), buf, flags, addr) +} diff --git a/vendor/rustix-0.37.22/src/net/send_recv/msg.rs b/vendor/rustix-0.37.22/src/net/send_recv/msg.rs new file mode 100644 index 000000000..759b1b61d --- /dev/null +++ b/vendor/rustix-0.37.22/src/net/send_recv/msg.rs @@ -0,0 +1,759 @@ +//! [`recvmsg`], [`sendmsg_noaddr`], and related functions. + +#![allow(unsafe_code)] + +use crate::backend::{self, c}; +use crate::fd::{AsFd, BorrowedFd, OwnedFd}; +use crate::io::{self, IoSlice, IoSliceMut}; + +use core::convert::{TryFrom, TryInto}; +use core::iter::{FromIterator, FusedIterator}; +use core::marker::PhantomData; +use core::mem::{size_of, size_of_val, take}; +use core::{ptr, slice}; + +use super::{RecvFlags, SendFlags, SocketAddrAny, SocketAddrV4, SocketAddrV6}; + +/// Macro for defining the amount of space used by CMSGs. +#[macro_export] +macro_rules! cmsg_space { + // Base Rules + (ScmRights($len:expr)) => { + $crate::net::__cmsg_space( + $len * ::core::mem::size_of::<$crate::fd::BorrowedFd<'static>>(), + ) + }; + + // Combo Rules + (($($($x:tt)*),+)) => { + $( + cmsg_space!($($x)*) + + )+ + 0 + }; +} + +#[doc(hidden)] +pub fn __cmsg_space(len: usize) -> usize { + unsafe { c::CMSG_SPACE(len.try_into().expect("CMSG_SPACE size overflow")) as usize } +} + +/// Ancillary message for [`sendmsg_noaddr`], [`sendmsg_v4`], [`sendmsg_v6`], +/// [`sendmsg_unix`], and [`sendmsg_any`]. +#[non_exhaustive] +pub enum SendAncillaryMessage<'slice, 'fd> { + /// Send file descriptors. + ScmRights(&'slice [BorrowedFd<'fd>]), +} + +impl SendAncillaryMessage<'_, '_> { + /// Get the maximum size of an ancillary message. + /// + /// This can be helpful in determining the size of the buffer you allocate. + pub fn size(&self) -> usize { + let total_bytes = match self { + Self::ScmRights(slice) => size_of_val(*slice), + }; + + unsafe { + c::CMSG_SPACE( + total_bytes + .try_into() + .expect("size too large for CMSG_SPACE"), + ) as usize + } + } +} + +/// Ancillary message for [`recvmsg`]. +#[non_exhaustive] +pub enum RecvAncillaryMessage<'a> { + /// Received file descriptors. + ScmRights(AncillaryIter<'a, OwnedFd>), +} + +/// Buffer for sending ancillary messages. +pub struct SendAncillaryBuffer<'buf, 'slice, 'fd> { + /// Raw byte buffer for messages. + buffer: &'buf mut [u8], + + /// The amount of the buffer that is used. + length: usize, + + /// Phantom data for lifetime of `&'slice [BorrowedFd<'fd>]`. + _phantom: PhantomData<&'slice [BorrowedFd<'fd>]>, +} + +impl<'buf> From<&'buf mut [u8]> for SendAncillaryBuffer<'buf, '_, '_> { + fn from(buffer: &'buf mut [u8]) -> Self { + Self::new(buffer) + } +} + +impl Default for SendAncillaryBuffer<'_, '_, '_> { + fn default() -> Self { + Self::new(&mut []) + } +} + +impl<'buf, 'slice, 'fd> SendAncillaryBuffer<'buf, 'slice, 'fd> { + /// Create a new, empty `SendAncillaryBuffer` from a raw byte buffer. + pub fn new(buffer: &'buf mut [u8]) -> Self { + Self { + buffer, + length: 0, + _phantom: PhantomData, + } + } + + /// Returns a pointer to the message data. + pub(crate) fn as_control_ptr(&mut self) -> *mut u8 { + if self.length > 0 { + self.buffer.as_mut_ptr() + } else { + ptr::null_mut() + } + } + + /// Returns the length of the message data. + pub(crate) fn control_len(&self) -> usize { + self.length + } + + /// Delete all messages from the buffer. + pub fn clear(&mut self) { + self.length = 0; + } + + /// Add an ancillary message to the buffer. + /// + /// Returns `true` if the message was added successfully. + pub fn push(&mut self, msg: SendAncillaryMessage<'slice, 'fd>) -> bool { + match msg { + SendAncillaryMessage::ScmRights(fds) => { + let fds_bytes = + unsafe { slice::from_raw_parts(fds.as_ptr().cast::<u8>(), size_of_val(fds)) }; + self.push_ancillary(fds_bytes, c::SOL_SOCKET as _, c::SCM_RIGHTS as _) + } + } + } + + /// Pushes an ancillary message to the buffer. + fn push_ancillary(&mut self, source: &[u8], cmsg_level: c::c_int, cmsg_type: c::c_int) -> bool { + macro_rules! leap { + ($e:expr) => {{ + match ($e) { + Some(x) => x, + None => return false, + } + }}; + } + + // Calculate the length of the message. + let source_len = leap!(u32::try_from(source.len()).ok()); + + // Calculate the new length of the buffer. + let additional_space = unsafe { c::CMSG_SPACE(source_len) }; + let new_length = leap!(self.length.checked_add(additional_space as usize)); + let buffer = leap!(self.buffer.get_mut(..new_length)); + + // Fill the new part of the buffer with zeroes. + // TODO: In Rust 1.50 we can use `fill` here. + unsafe { + buffer + .as_mut_ptr() + .add(self.length) + .write_bytes(0, new_length - self.length); + } + self.length = new_length; + + // Get the last header in the buffer. + let last_header = leap!(messages::Messages::new(buffer).last()); + + // Set the header fields. + last_header.cmsg_len = unsafe { c::CMSG_LEN(source_len) } as _; + last_header.cmsg_level = cmsg_level; + last_header.cmsg_type = cmsg_type; + + // Get the pointer to the payload and copy the data. + unsafe { + let payload = c::CMSG_DATA(last_header); + ptr::copy_nonoverlapping(source.as_ptr(), payload, source_len as _); + } + + true + } +} + +impl<'slice, 'fd> Extend<SendAncillaryMessage<'slice, 'fd>> + for SendAncillaryBuffer<'_, 'slice, 'fd> +{ + fn extend<T: IntoIterator<Item = SendAncillaryMessage<'slice, 'fd>>>(&mut self, iter: T) { + // TODO: This could be optimized to add every message in one go. + iter.into_iter().all(|msg| self.push(msg)); + } +} + +/// Buffer for receiving ancillary messages. +pub struct RecvAncillaryBuffer<'buf> { + /// Raw byte buffer for messages. + buffer: &'buf mut [u8], + + /// The portion of the buffer we've read from already. + read: usize, + + /// The amount of the buffer that is used. + length: usize, +} + +impl<'buf> From<&'buf mut [u8]> for RecvAncillaryBuffer<'buf> { + fn from(buffer: &'buf mut [u8]) -> Self { + Self::new(buffer) + } +} + +impl Default for RecvAncillaryBuffer<'_> { + fn default() -> Self { + Self::new(&mut []) + } +} + +impl<'buf> RecvAncillaryBuffer<'buf> { + /// Create a new, empty `RecvAncillaryBuffer` from a raw byte buffer. + pub fn new(buffer: &'buf mut [u8]) -> Self { + Self { + buffer, + read: 0, + length: 0, + } + } + + /// Returns a pointer to the message data. + pub(crate) fn as_control_ptr(&mut self) -> *mut u8 { + self.buffer.as_mut_ptr() + } + + /// Returns the length of the message data. + pub(crate) fn control_len(&self) -> usize { + self.buffer.len() + } + + /// Set the length of the message data. + /// + /// # Safety + /// + /// The buffer must be filled with valid message data. + pub(crate) unsafe fn set_control_len(&mut self, len: usize) { + self.length = len; + self.read = 0; + } + + /// Delete all messages from the buffer. + pub(crate) fn clear(&mut self) { + self.drain().for_each(drop); + } + + /// Drain all messages from the buffer. + pub fn drain(&mut self) -> AncillaryDrain<'_> { + AncillaryDrain { + messages: messages::Messages::new(&mut self.buffer[self.read..][..self.length]), + read: &mut self.read, + length: &mut self.length, + } + } +} + +impl Drop for RecvAncillaryBuffer<'_> { + fn drop(&mut self) { + self.clear(); + } +} + +/// An iterator that drains messages from a `RecvAncillaryBuffer`. +pub struct AncillaryDrain<'buf> { + /// Inner iterator over messages. + messages: messages::Messages<'buf>, + + /// Increment the number of messages we've read. + read: &'buf mut usize, + + /// Decrement the total length. + length: &'buf mut usize, +} + +impl<'buf> AncillaryDrain<'buf> { + /// A closure that converts a message into a `RecvAncillaryMessage`. + fn cvt_msg( + read: &mut usize, + length: &mut usize, + msg: &c::cmsghdr, + ) -> Option<RecvAncillaryMessage<'buf>> { + unsafe { + // Advance the "read" pointer. + let msg_len = msg.cmsg_len as usize; + *read += msg_len; + *length -= msg_len; + + // Get a pointer to the payload. + let payload = c::CMSG_DATA(msg); + let payload_len = msg.cmsg_len as usize - c::CMSG_LEN(0) as usize; + + // Get a mutable slice of the payload. + let payload: &'buf mut [u8] = slice::from_raw_parts_mut(payload, payload_len); + + // Determine what type it is. + let (level, msg_type) = (msg.cmsg_level, msg.cmsg_type); + match (level as _, msg_type as _) { + (c::SOL_SOCKET, c::SCM_RIGHTS) => { + // Create an iterator that reads out the file descriptors. + let fds = AncillaryIter::new(payload); + + Some(RecvAncillaryMessage::ScmRights(fds)) + } + _ => None, + } + } + } +} + +impl<'buf> Iterator for AncillaryDrain<'buf> { + type Item = RecvAncillaryMessage<'buf>; + + fn next(&mut self) -> Option<Self::Item> { + let read = &mut self.read; + let length = &mut self.length; + self.messages.find_map(|ev| Self::cvt_msg(read, length, ev)) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + let (_, max) = self.messages.size_hint(); + (0, max) + } + + fn fold<B, F>(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + let read = self.read; + let length = self.length; + self.messages + .filter_map(|ev| Self::cvt_msg(read, length, ev)) + .fold(init, f) + } + + fn count(self) -> usize { + let read = self.read; + let length = self.length; + self.messages + .filter_map(|ev| Self::cvt_msg(read, length, ev)) + .count() + } + + fn last(self) -> Option<Self::Item> + where + Self: Sized, + { + let read = self.read; + let length = self.length; + self.messages + .filter_map(|ev| Self::cvt_msg(read, length, ev)) + .last() + } + + fn collect<B: FromIterator<Self::Item>>(self) -> B + where + Self: Sized, + { + let read = self.read; + let length = self.length; + self.messages + .filter_map(|ev| Self::cvt_msg(read, length, ev)) + .collect() + } +} + +impl FusedIterator for AncillaryDrain<'_> {} + +/// `sendmsg(msghdr)`—Sends a message on a socket. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendmsg.html +/// [Linux]: https://man7.org/linux/man-pages/man2/sendmsg.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendmsg.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendmsg&sektion=2 +/// [NetBSD]: https://man.netbsd.org/sendmsg.2 +/// [OpenBSD]: https://man.openbsd.org/sendmsg.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendmsg§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/sendmsg +#[inline] +pub fn sendmsg_noaddr( + socket: impl AsFd, + iov: &[IoSlice<'_>], + control: &mut SendAncillaryBuffer<'_, '_, '_>, + flags: SendFlags, +) -> io::Result<usize> { + backend::net::syscalls::sendmsg_noaddr(socket.as_fd(), iov, control, flags) +} + +/// `sendmsg(msghdr)`—Sends a message on a socket to a specific IPv4 address. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendmsg.html +/// [Linux]: https://man7.org/linux/man-pages/man2/sendmsg.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendmsg.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendmsg&sektion=2 +/// [NetBSD]: https://man.netbsd.org/sendmsg.2 +/// [OpenBSD]: https://man.openbsd.org/sendmsg.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendmsg§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/sendmsg +#[inline] +pub fn sendmsg_v4( + socket: impl AsFd, + addr: &SocketAddrV4, + iov: &[IoSlice<'_>], + control: &mut SendAncillaryBuffer<'_, '_, '_>, + flags: SendFlags, +) -> io::Result<usize> { + backend::net::syscalls::sendmsg_v4(socket.as_fd(), addr, iov, control, flags) +} + +/// `sendmsg(msghdr)`—Sends a message on a socket to a specific IPv6 address. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendmsg.html +/// [Linux]: https://man7.org/linux/man-pages/man2/sendmsg.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendmsg.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendmsg&sektion=2 +/// [NetBSD]: https://man.netbsd.org/sendmsg.2 +/// [OpenBSD]: https://man.openbsd.org/sendmsg.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendmsg§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/sendmsg +#[inline] +pub fn sendmsg_v6( + socket: impl AsFd, + addr: &SocketAddrV6, + iov: &[IoSlice<'_>], + control: &mut SendAncillaryBuffer<'_, '_, '_>, + flags: SendFlags, +) -> io::Result<usize> { + backend::net::syscalls::sendmsg_v6(socket.as_fd(), addr, iov, control, flags) +} + +/// `sendmsg(msghdr)`—Sends a message on a socket to a specific Unix-domain +/// address. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendmsg.html +/// [Linux]: https://man7.org/linux/man-pages/man2/sendmsg.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendmsg.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendmsg&sektion=2 +/// [NetBSD]: https://man.netbsd.org/sendmsg.2 +/// [OpenBSD]: https://man.openbsd.org/sendmsg.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendmsg§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/sendmsg +#[inline] +#[cfg(unix)] +pub fn sendmsg_unix( + socket: impl AsFd, + addr: &super::SocketAddrUnix, + iov: &[IoSlice<'_>], + control: &mut SendAncillaryBuffer<'_, '_, '_>, + flags: SendFlags, +) -> io::Result<usize> { + backend::net::syscalls::sendmsg_unix(socket.as_fd(), addr, iov, control, flags) +} + +/// `sendmsg(msghdr)`—Sends a message on a socket to a specific address. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendmsg.html +/// [Linux]: https://man7.org/linux/man-pages/man2/sendmsg.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendmsg.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendmsg&sektion=2 +/// [NetBSD]: https://man.netbsd.org/sendmsg.2 +/// [OpenBSD]: https://man.openbsd.org/sendmsg.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendmsg§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/sendmsg +#[inline] +pub fn sendmsg_any( + socket: impl AsFd, + addr: Option<&SocketAddrAny>, + iov: &[IoSlice<'_>], + control: &mut SendAncillaryBuffer<'_, '_, '_>, + flags: SendFlags, +) -> io::Result<usize> { + match addr { + None => backend::net::syscalls::sendmsg_noaddr(socket.as_fd(), iov, control, flags), + Some(SocketAddrAny::V4(addr)) => { + backend::net::syscalls::sendmsg_v4(socket.as_fd(), addr, iov, control, flags) + } + Some(SocketAddrAny::V6(addr)) => { + backend::net::syscalls::sendmsg_v6(socket.as_fd(), addr, iov, control, flags) + } + #[cfg(unix)] + Some(SocketAddrAny::Unix(addr)) => { + backend::net::syscalls::sendmsg_unix(socket.as_fd(), addr, iov, control, flags) + } + } +} + +/// `recvmsg(msghdr)`—Receives a message from a socket. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html +/// [Linux]: https://man7.org/linux/man-pages/man2/recvmsg.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/recvmsg.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=recvmsg&sektion=2 +/// [NetBSD]: https://man.netbsd.org/recvmsg.2 +/// [OpenBSD]: https://man.openbsd.org/recvmsg.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=recvmsg§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/recvmsg +#[inline] +pub fn recvmsg( + socket: impl AsFd, + iov: &mut [IoSliceMut<'_>], + control: &mut RecvAncillaryBuffer<'_>, + flags: RecvFlags, +) -> io::Result<RecvMsgReturn> { + backend::net::syscalls::recvmsg(socket.as_fd(), iov, control, flags) +} + +/// The result of a successful [`recvmsg`] call. +pub struct RecvMsgReturn { + /// The number of bytes received. + pub bytes: usize, + + /// The flags received. + pub flags: RecvFlags, + + /// The address of the socket we received from, if any. + pub address: Option<SocketAddrAny>, +} + +/// An iterator over data in an ancillary buffer. +pub struct AncillaryIter<'data, T> { + /// The data we're iterating over. + data: &'data mut [u8], + + /// The raw data we're removing. + _marker: PhantomData<T>, +} + +impl<'data, T> AncillaryIter<'data, T> { + /// Create a new iterator over data in an ancillary buffer. + /// + /// # Safety + /// + /// The buffer must contain valid ancillary data. + unsafe fn new(data: &'data mut [u8]) -> Self { + assert_eq!(data.len() % size_of::<T>(), 0); + + Self { + data, + _marker: PhantomData, + } + } +} + +impl<'data, T> Drop for AncillaryIter<'data, T> { + fn drop(&mut self) { + self.for_each(drop); + } +} + +impl<T> Iterator for AncillaryIter<'_, T> { + type Item = T; + + fn next(&mut self) -> Option<Self::Item> { + // See if there is a next item. + if self.data.len() < size_of::<T>() { + return None; + } + + // Get the next item. + let item = unsafe { self.data.as_ptr().cast::<T>().read_unaligned() }; + + // Move forward. + let data = take(&mut self.data); + self.data = &mut data[size_of::<T>()..]; + + Some(item) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + let len = self.len(); + (len, Some(len)) + } + + fn count(self) -> usize { + self.len() + } + + fn last(mut self) -> Option<Self::Item> { + self.next_back() + } +} + +impl<T> FusedIterator for AncillaryIter<'_, T> {} + +impl<T> ExactSizeIterator for AncillaryIter<'_, T> { + fn len(&self) -> usize { + self.data.len() / size_of::<T>() + } +} + +impl<T> DoubleEndedIterator for AncillaryIter<'_, T> { + fn next_back(&mut self) -> Option<Self::Item> { + // See if there is a next item. + if self.data.len() < size_of::<T>() { + return None; + } + + // Get the next item. + let item = unsafe { + let ptr = self.data.as_ptr().add(self.data.len() - size_of::<T>()); + ptr.cast::<T>().read_unaligned() + }; + + // Move forward. + let len = self.data.len(); + let data = take(&mut self.data); + self.data = &mut data[..len - size_of::<T>()]; + + Some(item) + } +} + +mod messages { + use crate::backend::c; + use core::convert::TryInto; + use core::iter::FusedIterator; + use core::marker::PhantomData; + use core::mem::zeroed; + use core::ptr::NonNull; + + /// An iterator over the messages in an ancillary buffer. + pub(super) struct Messages<'buf> { + /// The message header we're using to iterator over the messages. + msghdr: c::msghdr, + + /// The current pointer to the next message header to return. + /// + /// This has a lifetime of `'buf`. + header: Option<NonNull<c::cmsghdr>>, + + /// Capture the original lifetime of the buffer. + _buffer: PhantomData<&'buf mut [u8]>, + } + + impl<'buf> Messages<'buf> { + /// Create a new iterator over messages from a byte buffer. + pub(super) fn new(buf: &'buf mut [u8]) -> Self { + let msghdr = { + let mut h: c::msghdr = unsafe { zeroed() }; + h.msg_control = buf.as_mut_ptr().cast(); + h.msg_controllen = buf.len().try_into().expect("buffer too large for msghdr"); + h + }; + + // Get the first header. + let header = NonNull::new(unsafe { c::CMSG_FIRSTHDR(&msghdr) }); + + Self { + msghdr, + header, + _buffer: PhantomData, + } + } + } + + impl<'a> Iterator for Messages<'a> { + type Item = &'a mut c::cmsghdr; + + #[inline] + fn next(&mut self) -> Option<Self::Item> { + // Get the current header. + let header = self.header?; + + // Get the next header. + self.header = NonNull::new(unsafe { c::CMSG_NXTHDR(&self.msghdr, header.as_ptr()) }); + + // If the headers are equal, we're done. + if Some(header) == self.header { + self.header = None; + } + + // SAFETY: The lifetime of `header` is tied to this. + Some(unsafe { &mut *header.as_ptr() }) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + if self.header.is_some() { + // The remaining buffer *could* be filled with zero-length + // messages. + let max_size = unsafe { c::CMSG_LEN(0) } as usize; + let remaining_count = self.msghdr.msg_controllen as usize / max_size; + (1, Some(remaining_count)) + } else { + (0, Some(0)) + } + } + } + + impl FusedIterator for Messages<'_> {} +} diff --git a/vendor/rustix-0.37.22/src/net/socket.rs b/vendor/rustix-0.37.22/src/net/socket.rs new file mode 100644 index 000000000..dbfb391ba --- /dev/null +++ b/vendor/rustix-0.37.22/src/net/socket.rs @@ -0,0 +1,711 @@ +use crate::fd::OwnedFd; +use crate::net::{SocketAddr, SocketAddrAny, SocketAddrV4, SocketAddrV6}; +use crate::{backend, io}; +use backend::fd::{AsFd, BorrowedFd}; + +#[cfg(unix)] +pub use backend::net::addr::SocketAddrUnix; +pub use backend::net::types::{AddressFamily, Protocol, Shutdown, SocketFlags, SocketType}; + +/// Compatibility alias for `SocketFlags`. Use `SocketFlags` instead of this. +pub type AcceptFlags = SocketFlags; + +impl Default for Protocol { + #[inline] + fn default() -> Self { + Self::IP + } +} + +/// `socket(domain, type_, protocol)`—Creates a socket. +/// +/// POSIX guarantees that `socket` will use the lowest unused file descriptor, +/// however it is not safe in general to rely on this, as file descriptors may +/// be unexpectedly allocated on other threads or in libraries. +/// +/// To pass extra flags such as [`SocketFlags::CLOEXEC`], use [`socket_with`]. +/// +/// # References +/// - [Beej's Guide to Network Programming] +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [Winsock2] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#socket +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html +/// [Linux]: https://man7.org/linux/man-pages/man2/socket.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/socket.2.html +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-socket +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=socket&sektion=2 +/// [NetBSD]: https://man.netbsd.org/socket.2 +/// [OpenBSD]: https://man.openbsd.org/socket.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=socket§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/socket +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Creating-a-Socket.html +#[inline] +pub fn socket(domain: AddressFamily, type_: SocketType, protocol: Protocol) -> io::Result<OwnedFd> { + backend::net::syscalls::socket(domain, type_, protocol) +} + +/// `socket_with(domain, type_ | flags, protocol)`—Creates a socket, with +/// flags. +/// +/// POSIX guarantees that `socket` will use the lowest unused file descriptor, +/// however it is not safe in general to rely on this, as file descriptors may +/// be unexpectedly allocated on other threads or in libraries. +/// +/// `socket_with` is the same as [`socket`] but adds an additional flags +/// operand. +/// +/// # References +/// - [Beej's Guide to Network Programming] +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [Winsock2] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#socket +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html +/// [Linux]: https://man7.org/linux/man-pages/man2/socket.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/socket.2.html +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-socket +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=socket&sektion=2 +/// [NetBSD]: https://man.netbsd.org/socket.2 +/// [OpenBSD]: https://man.openbsd.org/socket.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=socket§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/socket +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Creating-a-Socket.html +#[inline] +pub fn socket_with( + domain: AddressFamily, + type_: SocketType, + flags: SocketFlags, + protocol: Protocol, +) -> io::Result<OwnedFd> { + backend::net::syscalls::socket_with(domain, type_, flags, protocol) +} + +/// `bind(sockfd, addr)`—Binds a socket to an IP address. +/// +/// # References +/// - [Beej's Guide to Network Programming] +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [Winsock2] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#bind +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html +/// [Linux]: https://man7.org/linux/man-pages/man2/bind.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/bind.2.html +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-bind +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=bind&sektion=2 +/// [NetBSD]: https://man.netbsd.org/bind.2 +/// [OpenBSD]: https://man.openbsd.org/bind.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=bind§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/bind +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Setting-Address.html +pub fn bind<Fd: AsFd>(sockfd: Fd, addr: &SocketAddr) -> io::Result<()> { + _bind(sockfd.as_fd(), addr) +} + +fn _bind(sockfd: BorrowedFd<'_>, addr: &SocketAddr) -> io::Result<()> { + match addr { + SocketAddr::V4(v4) => backend::net::syscalls::bind_v4(sockfd, v4), + SocketAddr::V6(v6) => backend::net::syscalls::bind_v6(sockfd, v6), + } +} + +/// `bind(sockfd, addr)`—Binds a socket to an address. +/// +/// # References +/// - [Beej's Guide to Network Programming] +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [Winsock2] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#bind +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html +/// [Linux]: https://man7.org/linux/man-pages/man2/bind.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/bind.2.html +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-bind +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=bind&sektion=2 +/// [NetBSD]: https://man.netbsd.org/bind.2 +/// [OpenBSD]: https://man.openbsd.org/bind.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=bind§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/bind +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Setting-Address.html +#[doc(alias = "bind")] +pub fn bind_any<Fd: AsFd>(sockfd: Fd, addr: &SocketAddrAny) -> io::Result<()> { + _bind_any(sockfd.as_fd(), addr) +} + +fn _bind_any(sockfd: BorrowedFd<'_>, addr: &SocketAddrAny) -> io::Result<()> { + match addr { + SocketAddrAny::V4(v4) => backend::net::syscalls::bind_v4(sockfd, v4), + SocketAddrAny::V6(v6) => backend::net::syscalls::bind_v6(sockfd, v6), + #[cfg(unix)] + SocketAddrAny::Unix(unix) => backend::net::syscalls::bind_unix(sockfd, unix), + } +} + +/// `bind(sockfd, addr, sizeof(struct sockaddr_in))`—Binds a socket to an +/// IPv4 address. +/// +/// # References +/// - [Beej's Guide to Network Programming] +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [Winsock2] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#bind +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html +/// [Linux]: https://man7.org/linux/man-pages/man2/bind.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/bind.2.html +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-bind +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=bind&sektion=2 +/// [NetBSD]: https://man.netbsd.org/bind.2 +/// [OpenBSD]: https://man.openbsd.org/bind.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=bind§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/bind +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Setting-Address.html +#[inline] +#[doc(alias = "bind")] +pub fn bind_v4<Fd: AsFd>(sockfd: Fd, addr: &SocketAddrV4) -> io::Result<()> { + backend::net::syscalls::bind_v4(sockfd.as_fd(), addr) +} + +/// `bind(sockfd, addr, sizeof(struct sockaddr_in6))`—Binds a socket to an +/// IPv6 address. +/// +/// # References +/// - [Beej's Guide to Network Programming] +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [Winsock2] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#bind +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html +/// [Linux]: https://man7.org/linux/man-pages/man2/bind.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/bind.2.html +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-bind +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=bind&sektion=2 +/// [NetBSD]: https://man.netbsd.org/bind.2 +/// [OpenBSD]: https://man.openbsd.org/bind.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=bind§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/bind +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Setting-Address.html +#[inline] +#[doc(alias = "bind")] +pub fn bind_v6<Fd: AsFd>(sockfd: Fd, addr: &SocketAddrV6) -> io::Result<()> { + backend::net::syscalls::bind_v6(sockfd.as_fd(), addr) +} + +/// `bind(sockfd, addr, sizeof(struct sockaddr_un))`—Binds a socket to a +/// Unix-domain address. +/// +/// # References +/// - [Beej's Guide to Network Programming] +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [Winsock2] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#bind +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html +/// [Linux]: https://man7.org/linux/man-pages/man2/bind.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/bind.2.html +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-bind +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=bind&sektion=2 +/// [NetBSD]: https://man.netbsd.org/bind.2 +/// [OpenBSD]: https://man.openbsd.org/bind.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=bind§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/bind +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Setting-Address.html +#[cfg(unix)] +#[inline] +#[doc(alias = "bind")] +pub fn bind_unix<Fd: AsFd>(sockfd: Fd, addr: &SocketAddrUnix) -> io::Result<()> { + backend::net::syscalls::bind_unix(sockfd.as_fd(), addr) +} + +/// `connect(sockfd, addr)`—Initiates a connection to an IP address. +/// +/// # References +/// - [Beej's Guide to Network Programming] +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [Winsock2] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#connect +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html +/// [Linux]: https://man7.org/linux/man-pages/man2/connect.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/connect.2.html +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-connect +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=connect&sektion=2 +/// [NetBSD]: https://man.netbsd.org/connect.2 +/// [OpenBSD]: https://man.openbsd.org/connect.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=connect§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/connect +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Connecting.html +pub fn connect<Fd: AsFd>(sockfd: Fd, addr: &SocketAddr) -> io::Result<()> { + _connect(sockfd.as_fd(), addr) +} + +fn _connect(sockfd: BorrowedFd<'_>, addr: &SocketAddr) -> io::Result<()> { + match addr { + SocketAddr::V4(v4) => backend::net::syscalls::connect_v4(sockfd, v4), + SocketAddr::V6(v6) => backend::net::syscalls::connect_v6(sockfd, v6), + } +} + +/// `connect(sockfd, addr)`—Initiates a connection. +/// +/// # References +/// - [Beej's Guide to Network Programming] +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [Winsock2] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#connect +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html +/// [Linux]: https://man7.org/linux/man-pages/man2/connect.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/connect.2.html +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-connect +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=connect&sektion=2 +/// [NetBSD]: https://man.netbsd.org/connect.2 +/// [OpenBSD]: https://man.openbsd.org/connect.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=connect§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/connect +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Connecting.html +#[doc(alias = "connect")] +pub fn connect_any<Fd: AsFd>(sockfd: Fd, addr: &SocketAddrAny) -> io::Result<()> { + _connect_any(sockfd.as_fd(), addr) +} + +fn _connect_any(sockfd: BorrowedFd<'_>, addr: &SocketAddrAny) -> io::Result<()> { + match addr { + SocketAddrAny::V4(v4) => backend::net::syscalls::connect_v4(sockfd, v4), + SocketAddrAny::V6(v6) => backend::net::syscalls::connect_v6(sockfd, v6), + #[cfg(unix)] + SocketAddrAny::Unix(unix) => backend::net::syscalls::connect_unix(sockfd, unix), + } +} + +/// `connect(sockfd, addr, sizeof(struct sockaddr_in))`—Initiates a +/// connection to an IPv4 address. +/// +/// # References +/// - [Beej's Guide to Network Programming] +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [Winsock2] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#connect +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html +/// [Linux]: https://man7.org/linux/man-pages/man2/connect.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/connect.2.html +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-connect +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=connect&sektion=2 +/// [NetBSD]: https://man.netbsd.org/connect.2 +/// [OpenBSD]: https://man.openbsd.org/connect.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=connect§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/connect +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Connecting.html +#[inline] +#[doc(alias = "connect")] +pub fn connect_v4<Fd: AsFd>(sockfd: Fd, addr: &SocketAddrV4) -> io::Result<()> { + backend::net::syscalls::connect_v4(sockfd.as_fd(), addr) +} + +/// `connect(sockfd, addr, sizeof(struct sockaddr_in6))`—Initiates a +/// connection to an IPv6 address. +/// +/// # References +/// - [Beej's Guide to Network Programming] +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [Winsock2] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#connect +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html +/// [Linux]: https://man7.org/linux/man-pages/man2/connect.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/connect.2.html +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-connect +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=connect&sektion=2 +/// [NetBSD]: https://man.netbsd.org/connect.2 +/// [OpenBSD]: https://man.openbsd.org/connect.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=connect§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/connect +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Connecting.html +#[inline] +#[doc(alias = "connect")] +pub fn connect_v6<Fd: AsFd>(sockfd: Fd, addr: &SocketAddrV6) -> io::Result<()> { + backend::net::syscalls::connect_v6(sockfd.as_fd(), addr) +} + +/// `connect(sockfd, addr, sizeof(struct sockaddr_un))`—Initiates a +/// connection to a Unix-domain address. +/// +/// # References +/// - [Beej's Guide to Network Programming] +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [Winsock2] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#connect +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html +/// [Linux]: https://man7.org/linux/man-pages/man2/connect.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/connect.2.html +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-connect +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=connect&sektion=2 +/// [NetBSD]: https://man.netbsd.org/connect.2 +/// [OpenBSD]: https://man.openbsd.org/connect.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=connect§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/connect +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Connecting.html +#[cfg(unix)] +#[inline] +#[doc(alias = "connect")] +pub fn connect_unix<Fd: AsFd>(sockfd: Fd, addr: &SocketAddrUnix) -> io::Result<()> { + backend::net::syscalls::connect_unix(sockfd.as_fd(), addr) +} + +/// `listen(fd, backlog)`—Enables listening for incoming connections. +/// +/// # References +/// - [Beej's Guide to Network Programming] +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [Winsock2] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#listen +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html +/// [Linux]: https://man7.org/linux/man-pages/man2/listen.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/listen.2.html +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-listen +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=listen&sektion=2 +/// [NetBSD]: https://man.netbsd.org/listen.2 +/// [OpenBSD]: https://man.openbsd.org/listen.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=listen§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/listen +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Listening.html +#[inline] +pub fn listen<Fd: AsFd>(sockfd: Fd, backlog: i32) -> io::Result<()> { + backend::net::syscalls::listen(sockfd.as_fd(), backlog) +} + +/// `accept(fd, NULL, NULL)`—Accepts an incoming connection. +/// +/// Use [`acceptfrom`] to retrieve the peer address. +/// +/// POSIX guarantees that `accept` will use the lowest unused file descriptor, +/// however it is not safe in general to rely on this, as file descriptors may +/// be unexpectedly allocated on other threads or in libraries. +/// +/// # References +/// - [Beej's Guide to Network Programming] +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [Winsock2] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#acceptthank-you-for-calling-port-3490. +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.html +/// [Linux]: https://man7.org/linux/man-pages/man2/accept.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/accept.2.html +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-accept +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=accept&sektion=2 +/// [NetBSD]: https://man.netbsd.org/accept.2 +/// [OpenBSD]: https://man.openbsd.org/accept.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=accept§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/accept +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Accepting-Connections.html +#[inline] +pub fn accept<Fd: AsFd>(sockfd: Fd) -> io::Result<OwnedFd> { + backend::net::syscalls::accept(sockfd.as_fd()) +} + +/// `accept4(fd, NULL, NULL, flags)`—Accepts an incoming connection, with +/// flags. +/// +/// Use [`acceptfrom_with`] to retrieve the peer address. +/// +/// Even though POSIX guarantees that this will use the lowest unused file +/// descriptor, it is not safe in general to rely on this, as file descriptors +/// may be unexpectedly allocated on other threads or in libraries. +/// +/// `accept_with` is the same as [`accept`] but adds an additional flags +/// operand. +/// +/// # References +/// - [Linux] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/accept4.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=accept4&sektion=2 +/// [NetBSD]: https://man.netbsd.org/accept4.2 +/// [OpenBSD]: https://man.openbsd.org/accept4.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=accept4§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/accept4 +#[inline] +#[doc(alias = "accept4")] +pub fn accept_with<Fd: AsFd>(sockfd: Fd, flags: SocketFlags) -> io::Result<OwnedFd> { + backend::net::syscalls::accept_with(sockfd.as_fd(), flags) +} + +/// `accept(fd, &addr, &len)`—Accepts an incoming connection and returns the +/// peer address. +/// +/// Use [`accept`] if the peer address isn't needed. +/// +/// # References +/// - [Beej's Guide to Network Programming] +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [Winsock2] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#acceptthank-you-for-calling-port-3490. +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.html +/// [Linux]: https://man7.org/linux/man-pages/man2/accept.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/accept.2.html +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-accept +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=accept&sektion=2 +/// [NetBSD]: https://man.netbsd.org/accept.2 +/// [OpenBSD]: https://man.openbsd.org/accept.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=accept§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/accept +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Accepting-Connections.html +#[inline] +#[doc(alias = "accept")] +pub fn acceptfrom<Fd: AsFd>(sockfd: Fd) -> io::Result<(OwnedFd, Option<SocketAddrAny>)> { + backend::net::syscalls::acceptfrom(sockfd.as_fd()) +} + +/// `accept4(fd, &addr, &len, flags)`—Accepts an incoming connection and +/// returns the peer address, with flags. +/// +/// Use [`accept_with`] if the peer address isn't needed. +/// +/// `acceptfrom_with` is the same as [`acceptfrom`] but adds an additional +/// flags operand. +/// +/// # References +/// - [Linux] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/accept4.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=accept4&sektion=2 +/// [NetBSD]: https://man.netbsd.org/accept4.2 +/// [OpenBSD]: https://man.openbsd.org/accept4.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=accept4§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/accept4 +#[inline] +#[doc(alias = "accept4")] +pub fn acceptfrom_with<Fd: AsFd>( + sockfd: Fd, + flags: SocketFlags, +) -> io::Result<(OwnedFd, Option<SocketAddrAny>)> { + backend::net::syscalls::acceptfrom_with(sockfd.as_fd(), flags) +} + +/// `shutdown(fd, how)`—Closes the read and/or write sides of a stream. +/// +/// # References +/// - [Beej's Guide to Network Programming] +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [Winsock2] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#close-and-shutdownget-outta-my-face +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/shutdown.html +/// [Linux]: https://man7.org/linux/man-pages/man2/shutdown.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/shutdown.2.html +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-shutdown +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=shutdown&sektion=2 +/// [NetBSD]: https://man.netbsd.org/shutdown.2 +/// [OpenBSD]: https://man.openbsd.org/shutdown.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=shutdown§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/shutdown +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Closing-a-Socket.html +#[inline] +pub fn shutdown<Fd: AsFd>(sockfd: Fd, how: Shutdown) -> io::Result<()> { + backend::net::syscalls::shutdown(sockfd.as_fd(), how) +} + +/// `getsockname(fd, addr, len)`—Returns the address a socket is bound to. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [Winsock2] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html +/// [Linux]: https://man7.org/linux/man-pages/man2/getsockname.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getsockname.2.html +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-getsockname +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=getsockname&sektion=2 +/// [NetBSD]: https://man.netbsd.org/getsockname.2 +/// [OpenBSD]: https://man.openbsd.org/getsockname.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=getsockname§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/getsockname +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Reading-Address.html +#[inline] +pub fn getsockname<Fd: AsFd>(sockfd: Fd) -> io::Result<SocketAddrAny> { + backend::net::syscalls::getsockname(sockfd.as_fd()) +} + +/// `getpeername(fd, addr, len)`—Returns the address a socket is connected +/// to. +/// +/// # References +/// - [Beej's Guide to Network Programming] +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [Winsock2] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#getpeernamewho-are-you +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpeername.html +/// [Linux]: https://man7.org/linux/man-pages/man2/getpeername.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getpeername.2.html +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-getpeername +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=getpeername&sektion=2 +/// [NetBSD]: https://man.netbsd.org/getpeername.2 +/// [OpenBSD]: https://man.openbsd.org/getpeername.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=getpeername§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/getpeername +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Who-is-Connected.html +#[inline] +pub fn getpeername<Fd: AsFd>(sockfd: Fd) -> io::Result<Option<SocketAddrAny>> { + backend::net::syscalls::getpeername(sockfd.as_fd()) +} diff --git a/vendor/rustix-0.37.22/src/net/socket_addr_any.rs b/vendor/rustix-0.37.22/src/net/socket_addr_any.rs new file mode 100644 index 000000000..403ad11c2 --- /dev/null +++ b/vendor/rustix-0.37.22/src/net/socket_addr_any.rs @@ -0,0 +1,103 @@ +//! A socket address for any kind of socket. +//! +//! This is similar to [`std::net::SocketAddr`], but also supports Unix-domain +//! socket addresses. +//! +//! # Safety +//! +//! The `read` and `write` functions allow decoding and encoding from and to +//! OS-specific socket address representations in memory. +#![allow(unsafe_code)] + +#[cfg(unix)] +use crate::net::SocketAddrUnix; +use crate::net::{AddressFamily, SocketAddrV4, SocketAddrV6}; +use crate::{backend, io}; +#[cfg(feature = "std")] +use core::fmt; + +pub use backend::net::addr::SocketAddrStorage; + +/// `struct sockaddr_storage` as a Rust enum. +#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[doc(alias = "sockaddr")] +#[non_exhaustive] +pub enum SocketAddrAny { + /// `struct sockaddr_in` + V4(SocketAddrV4), + /// `struct sockaddr_in6` + V6(SocketAddrV6), + /// `struct sockaddr_un` + #[cfg(unix)] + Unix(SocketAddrUnix), +} + +impl From<SocketAddrV4> for SocketAddrAny { + #[inline] + fn from(from: SocketAddrV4) -> Self { + Self::V4(from) + } +} + +impl From<SocketAddrV6> for SocketAddrAny { + #[inline] + fn from(from: SocketAddrV6) -> Self { + Self::V6(from) + } +} + +#[cfg(unix)] +impl From<SocketAddrUnix> for SocketAddrAny { + #[inline] + fn from(from: SocketAddrUnix) -> Self { + Self::Unix(from) + } +} + +impl SocketAddrAny { + /// Return the address family of this socket address. + #[inline] + pub const fn address_family(&self) -> AddressFamily { + match self { + Self::V4(_) => AddressFamily::INET, + Self::V6(_) => AddressFamily::INET6, + #[cfg(unix)] + Self::Unix(_) => AddressFamily::UNIX, + } + } + + /// Writes a platform-specific encoding of this socket address to + /// the memory pointed to by `storage`, and returns the number of + /// bytes used. + /// + /// # Safety + /// + /// `storage` must point to valid memory for encoding the socket + /// address. + pub unsafe fn write(&self, storage: *mut SocketAddrStorage) -> usize { + backend::net::write_sockaddr::write_sockaddr(self, storage) + } + + /// Reads a platform-specific encoding of a socket address from + /// the memory pointed to by `storage`, which uses `len` bytes. + /// + /// # Safety + /// + /// `storage` must point to valid memory for decoding a socket + /// address. + pub unsafe fn read(storage: *const SocketAddrStorage, len: usize) -> io::Result<Self> { + backend::net::read_sockaddr::read_sockaddr(storage, len) + } +} + +#[cfg(feature = "std")] +impl fmt::Debug for SocketAddrAny { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::V4(v4) => v4.fmt(fmt), + Self::V6(v6) => v6.fmt(fmt), + #[cfg(unix)] + Self::Unix(unix) => unix.fmt(fmt), + } + } +} diff --git a/vendor/rustix-0.37.22/src/net/socketpair.rs b/vendor/rustix-0.37.22/src/net/socketpair.rs new file mode 100644 index 000000000..b2d46060e --- /dev/null +++ b/vendor/rustix-0.37.22/src/net/socketpair.rs @@ -0,0 +1,35 @@ +use crate::fd::OwnedFd; +use crate::net::{AddressFamily, Protocol, SocketFlags, SocketType}; +use crate::{backend, io}; + +/// `socketpair(domain, type_ | accept_flags, protocol)` +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/socketpair.html +/// [Linux]: https://man7.org/linux/man-pages/man2/socketpair.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/socketpair.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=socketpair&sektion=2 +/// [NetBSD]: https://man.netbsd.org/socketpair.2 +/// [OpenBSD]: https://man.openbsd.org/socketpair.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=socketpair§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/socketpair +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Socket-Pairs.html +#[inline] +pub fn socketpair( + domain: AddressFamily, + type_: SocketType, + flags: SocketFlags, + protocol: Protocol, +) -> io::Result<(OwnedFd, OwnedFd)> { + backend::net::syscalls::socketpair(domain, type_, flags, protocol) +} diff --git a/vendor/rustix-0.37.22/src/net/sockopt.rs b/vendor/rustix-0.37.22/src/net/sockopt.rs new file mode 100644 index 000000000..ec8e49723 --- /dev/null +++ b/vendor/rustix-0.37.22/src/net/sockopt.rs @@ -0,0 +1,1616 @@ +//! `getsockopt` and `setsockopt` functions. +//! +//! In the rustix API, there is a separate function for each option, so that +//! it can be given an option-specific type signature. + +#![doc(alias = "getsockopt")] +#![doc(alias = "setsockopt")] + +use crate::net::{Ipv4Addr, Ipv6Addr, SocketType}; +use crate::{backend, io}; +use backend::fd::AsFd; +use core::time::Duration; + +pub use backend::net::types::Timeout; + +/// `getsockopt(fd, SOL_SOCKET, SO_TYPE)`—Returns the type of a socket. +/// +/// # References +/// - [POSIX `getsockopt`] +/// - [POSIX `sys/socket.h`] +/// - [Linux `getsockopt`] +/// - [Linux `socket`] +/// - [Winsock2 `getsockopt`] +/// - [Winsock2 `SOL_SOCKET` options] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc `getsockopt`] +/// - [glibc `SOL_SOCKET` Options] +/// +/// [POSIX `getsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html +/// [POSIX `sys/socket.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_socket.h.html +/// [Linux `getsockopt`]: https://man7.org/linux/man-pages/man2/getsockopt.2.html +/// [Linux `socket`]: https://man7.org/linux/man-pages/man7/socket.7.html +/// [Winsock2 `getsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-getsockopt +/// [Winsock2 `SOL_SOCKET` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/sol-socket-socket-options +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getsockopt.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=getsockopt&sektion=2 +/// [NetBSD]: https://man.netbsd.org/getsockopt.2 +/// [OpenBSD]: https://man.openbsd.org/getsockopt.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=getsockopt§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/getsockopt +/// [glibc `getsockopt`]: https://www.gnu.org/software/libc/manual/html_node/Socket-Option-Functions.html +/// [glibc `SOL_SOCKET` options]: https://www.gnu.org/software/libc/manual/html_node/Socket_002dLevel-Options.html +#[inline] +#[doc(alias = "SO_TYPE")] +pub fn get_socket_type<Fd: AsFd>(fd: Fd) -> io::Result<SocketType> { + backend::net::syscalls::sockopt::get_socket_type(fd.as_fd()) +} + +/// `setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, value)` +/// +/// # References +/// - [POSIX `setsockopt`] +/// - [POSIX `sys/socket.h`] +/// - [Linux `setsockopt`] +/// - [Linux `socket`] +/// - [Winsock2 `setsockopt`] +/// - [Winsock2 `SOL_SOCKET` options] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc `setsockopt`] +/// - [glibc `SOL_SOCKET` Options] +/// +/// [POSIX `setsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html +/// [POSIX `sys/socket.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_socket.h.html +/// [Linux `setsockopt`]: https://man7.org/linux/man-pages/man2/setsockopt.2.html +/// [Linux `socket`]: https://man7.org/linux/man-pages/man7/socket.7.html +/// [Winsock2 `setsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-setsockopt +/// [Winsock2 `SOL_SOCKET` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/sol-socket-socket-options +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setsockopt.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=setsockopt&sektion=2 +/// [NetBSD]: https://man.netbsd.org/setsockopt.2 +/// [OpenBSD]: https://man.openbsd.org/setsockopt.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=setsockopt§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/setsockopt +/// [glibc `setsockopt`]: https://www.gnu.org/software/libc/manual/html_node/Socket-Option-Functions.html +/// [glibc `SOL_SOCKET` options]: https://www.gnu.org/software/libc/manual/html_node/Socket_002dLevel-Options.html +#[inline] +#[doc(alias = "SO_REUSEADDR")] +pub fn set_socket_reuseaddr<Fd: AsFd>(fd: Fd, value: bool) -> io::Result<()> { + backend::net::syscalls::sockopt::set_socket_reuseaddr(fd.as_fd(), value) +} + +/// `setsockopt(fd, SOL_SOCKET, SO_BROADCAST, broadcast)` +/// +/// # References +/// - [POSIX `setsockopt`] +/// - [POSIX `sys/socket.h`] +/// - [Linux `setsockopt`] +/// - [Linux `socket`] +/// - [Winsock2 `setsockopt`] +/// - [Winsock2 `SOL_SOCKET` options] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc `setsockopt`] +/// - [glibc `SOL_SOCKET` Options] +/// +/// [POSIX `setsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html +/// [POSIX `sys/socket.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_socket.h.html +/// [Linux `setsockopt`]: https://man7.org/linux/man-pages/man2/setsockopt.2.html +/// [Linux `socket`]: https://man7.org/linux/man-pages/man7/socket.7.html +/// [Winsock2 `setsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-setsockopt +/// [Winsock2 `SOL_SOCKET` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/sol-socket-socket-options +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setsockopt.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=setsockopt&sektion=2 +/// [NetBSD]: https://man.netbsd.org/setsockopt.2 +/// [OpenBSD]: https://man.openbsd.org/setsockopt.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=setsockopt§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/setsockopt +/// [glibc `setsockopt`]: https://www.gnu.org/software/libc/manual/html_node/Socket-Option-Functions.html +/// [glibc `SOL_SOCKET` options]: https://www.gnu.org/software/libc/manual/html_node/Socket_002dLevel-Options.html +#[inline] +#[doc(alias = "SO_BROADCAST")] +pub fn set_socket_broadcast<Fd: AsFd>(fd: Fd, broadcast: bool) -> io::Result<()> { + backend::net::syscalls::sockopt::set_socket_broadcast(fd.as_fd(), broadcast) +} + +/// `getsockopt(fd, SOL_SOCKET, SO_BROADCAST)` +/// +/// # References +/// - [POSIX `getsockopt`] +/// - [POSIX `sys/socket.h`] +/// - [Linux `getsockopt`] +/// - [Linux `socket`] +/// - [Winsock2 `getsockopt`] +/// - [Winsock2 `SOL_SOCKET` options] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc `getsockopt`] +/// - [glibc `SOL_SOCKET` Options] +/// +/// [POSIX `getsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html +/// [POSIX `sys/socket.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_socket.h.html +/// [Linux `getsockopt`]: https://man7.org/linux/man-pages/man2/getsockopt.2.html +/// [Linux `socket`]: https://man7.org/linux/man-pages/man7/socket.7.html +/// [Winsock2 `getsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-getsockopt +/// [Winsock2 `SOL_SOCKET` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/sol-socket-socket-options +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getsockopt.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=getsockopt&sektion=2 +/// [NetBSD]: https://man.netbsd.org/getsockopt.2 +/// [OpenBSD]: https://man.openbsd.org/getsockopt.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=getsockopt§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/getsockopt +/// [glibc `getsockopt`]: https://www.gnu.org/software/libc/manual/html_node/Socket-Option-Functions.html +/// [glibc `SOL_SOCKET` options]: https://www.gnu.org/software/libc/manual/html_node/Socket_002dLevel-Options.html +#[inline] +#[doc(alias = "SO_BROADCAST")] +pub fn get_socket_broadcast<Fd: AsFd>(fd: Fd) -> io::Result<bool> { + backend::net::syscalls::sockopt::get_socket_broadcast(fd.as_fd()) +} + +/// `setsockopt(fd, SOL_SOCKET, SO_LINGER, linger)` +/// +/// # References +/// - [POSIX `setsockopt`] +/// - [POSIX `sys/socket.h`] +/// - [Linux `setsockopt`] +/// - [Linux `socket`] +/// - [Winsock2 `setsockopt`] +/// - [Winsock2 `SOL_SOCKET` options] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc `setsockopt`] +/// - [glibc `SOL_SOCKET` Options] +/// +/// [POSIX `setsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html +/// [POSIX `sys/socket.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_socket.h.html +/// [Linux `setsockopt`]: https://man7.org/linux/man-pages/man2/setsockopt.2.html +/// [Linux `socket`]: https://man7.org/linux/man-pages/man7/socket.7.html +/// [Winsock2 `setsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-setsockopt +/// [Winsock2 `SOL_SOCKET` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/sol-socket-socket-options +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setsockopt.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=setsockopt&sektion=2 +/// [NetBSD]: https://man.netbsd.org/setsockopt.2 +/// [OpenBSD]: https://man.openbsd.org/setsockopt.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=setsockopt§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/setsockopt +/// [glibc `setsockopt`]: https://www.gnu.org/software/libc/manual/html_node/Socket-Option-Functions.html +/// [glibc `SOL_SOCKET` options]: https://www.gnu.org/software/libc/manual/html_node/Socket_002dLevel-Options.html +#[inline] +#[doc(alias = "SO_LINGER")] +pub fn set_socket_linger<Fd: AsFd>(fd: Fd, linger: Option<Duration>) -> io::Result<()> { + backend::net::syscalls::sockopt::set_socket_linger(fd.as_fd(), linger) +} + +/// `getsockopt(fd, SOL_SOCKET, SO_LINGER)` +/// +/// # References +/// - [POSIX `getsockopt`] +/// - [POSIX `sys/socket.h`] +/// - [Linux `getsockopt`] +/// - [Linux `socket`] +/// - [Winsock2 `getsockopt`] +/// - [Winsock2 `SOL_SOCKET` options] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc `getsockopt`] +/// - [glibc `SOL_SOCKET` Options] +/// +/// [POSIX `getsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html +/// [POSIX `sys/socket.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_socket.h.html +/// [Linux `getsockopt`]: https://man7.org/linux/man-pages/man2/getsockopt.2.html +/// [Linux `socket`]: https://man7.org/linux/man-pages/man7/socket.7.html +/// [Winsock2 `getsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-getsockopt +/// [Winsock2 `SOL_SOCKET` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/sol-socket-socket-options +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getsockopt.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=getsockopt&sektion=2 +/// [NetBSD]: https://man.netbsd.org/getsockopt.2 +/// [OpenBSD]: https://man.openbsd.org/getsockopt.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=getsockopt§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/getsockopt +/// [glibc `getsockopt`]: https://www.gnu.org/software/libc/manual/html_node/Socket-Option-Functions.html +/// [glibc `SOL_SOCKET` options]: https://www.gnu.org/software/libc/manual/html_node/Socket_002dLevel-Options.html +#[inline] +#[doc(alias = "SO_LINGER")] +pub fn get_socket_linger<Fd: AsFd>(fd: Fd) -> io::Result<Option<Duration>> { + backend::net::syscalls::sockopt::get_socket_linger(fd.as_fd()) +} + +/// `setsockopt(fd, SOL_SOCKET, SO_PASSCRED, passcred)` +/// +/// # References +/// - [Linux `setsockopt`] +/// - [Linux `socket`] +/// +/// [Linux `setsockopt`]: https://man7.org/linux/man-pages/man2/setsockopt.2.html +/// [Linux `socket`]: https://man7.org/linux/man-pages/man7/socket.7.html +#[cfg(linux_kernel)] +#[inline] +#[doc(alias = "SO_PASSCRED")] +pub fn set_socket_passcred<Fd: AsFd>(fd: Fd, passcred: bool) -> io::Result<()> { + backend::net::syscalls::sockopt::set_socket_passcred(fd.as_fd(), passcred) +} + +/// `getsockopt(fd, SOL_SOCKET, SO_PASSCRED)` +/// +/// # References +/// - [Linux `getsockopt`] +/// - [Linux `socket`] +/// +/// [Linux `getsockopt`]: https://man7.org/linux/man-pages/man2/getsockopt.2.html +/// [Linux `socket`]: https://man7.org/linux/man-pages/man7/socket.7.html +#[cfg(linux_kernel)] +#[inline] +#[doc(alias = "SO_PASSCRED")] +pub fn get_socket_passcred<Fd: AsFd>(fd: Fd) -> io::Result<bool> { + backend::net::syscalls::sockopt::get_socket_passcred(fd.as_fd()) +} + +/// `setsockopt(fd, SOL_SOCKET, id, timeout)`—Set the sending or receiving +/// timeout. +/// +/// # References +/// - [POSIX `setsockopt`] +/// - [POSIX `sys/socket.h`] +/// - [Linux `setsockopt`] +/// - [Linux `socket`] +/// - [Winsock2 `setsockopt`] +/// - [Winsock2 `SOL_SOCKET` options] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc `setsockopt`] +/// - [glibc `SOL_SOCKET` Options] +/// +/// [POSIX `setsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html +/// [POSIX `sys/socket.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_socket.h.html +/// [Linux `setsockopt`]: https://man7.org/linux/man-pages/man2/setsockopt.2.html +/// [Linux `socket`]: https://man7.org/linux/man-pages/man7/socket.7.html +/// [Winsock2 `setsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-setsockopt +/// [Winsock2 `SOL_SOCKET` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/sol-socket-socket-options +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setsockopt.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=setsockopt&sektion=2 +/// [NetBSD]: https://man.netbsd.org/setsockopt.2 +/// [OpenBSD]: https://man.openbsd.org/setsockopt.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=setsockopt§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/setsockopt +/// [glibc `setsockopt`]: https://www.gnu.org/software/libc/manual/html_node/Socket-Option-Functions.html +/// [glibc `SOL_SOCKET` options]: https://www.gnu.org/software/libc/manual/html_node/Socket_002dLevel-Options.html +#[inline] +#[doc(alias = "SO_RCVTIMEO")] +#[doc(alias = "SO_SNDTIMEO")] +pub fn set_socket_timeout<Fd: AsFd>( + fd: Fd, + id: Timeout, + timeout: Option<Duration>, +) -> io::Result<()> { + backend::net::syscalls::sockopt::set_socket_timeout(fd.as_fd(), id, timeout) +} + +/// `getsockopt(fd, SOL_SOCKET, id)`—Get the sending or receiving timeout. +/// +/// # References +/// - [POSIX `getsockopt`] +/// - [POSIX `sys/socket.h`] +/// - [Linux `getsockopt`] +/// - [Linux `socket`] +/// - [Winsock2 `getsockopt`] +/// - [Winsock2 `SOL_SOCKET` options] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc `getsockopt`] +/// - [glibc `SOL_SOCKET` Options] +/// +/// [POSIX `getsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html +/// [POSIX `sys/socket.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_socket.h.html +/// [Linux `getsockopt`]: https://man7.org/linux/man-pages/man2/getsockopt.2.html +/// [Linux `socket`]: https://man7.org/linux/man-pages/man7/socket.7.html +/// [Winsock2 `getsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-getsockopt +/// [Winsock2 `SOL_SOCKET` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/sol-socket-socket-options +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getsockopt.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=getsockopt&sektion=2 +/// [NetBSD]: https://man.netbsd.org/getsockopt.2 +/// [OpenBSD]: https://man.openbsd.org/getsockopt.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=getsockopt§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/getsockopt +/// [glibc `getsockopt`]: https://www.gnu.org/software/libc/manual/html_node/Socket-Option-Functions.html +/// [glibc `SOL_SOCKET` options]: https://www.gnu.org/software/libc/manual/html_node/Socket_002dLevel-Options.html +#[inline] +#[doc(alias = "SO_RCVTIMEO")] +#[doc(alias = "SO_SNDTIMEO")] +pub fn get_socket_timeout<Fd: AsFd>(fd: Fd, id: Timeout) -> io::Result<Option<Duration>> { + backend::net::syscalls::sockopt::get_socket_timeout(fd.as_fd(), id) +} + +/// `getsockopt(fd, SOL_SOCKET, SO_ERROR)` +/// +/// # References +/// - [POSIX `getsockopt`] +/// - [POSIX `sys/socket.h`] +/// - [Linux `getsockopt`] +/// - [Linux `socket`] +/// - [Winsock2 `getsockopt`] +/// - [Winsock2 `SOL_SOCKET` options] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc `getsockopt`] +/// - [glibc `SOL_SOCKET` Options] +/// +/// [POSIX `getsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html +/// [POSIX `sys/socket.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_socket.h.html +/// [Linux `getsockopt`]: https://man7.org/linux/man-pages/man2/getsockopt.2.html +/// [Linux `socket`]: https://man7.org/linux/man-pages/man7/socket.7.html +/// [Winsock2 `getsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-getsockopt +/// [Winsock2 `SOL_SOCKET` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/sol-socket-socket-options +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getsockopt.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=getsockopt&sektion=2 +/// [NetBSD]: https://man.netbsd.org/getsockopt.2 +/// [OpenBSD]: https://man.openbsd.org/getsockopt.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=getsockopt§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/getsockopt +/// [glibc `getsockopt`]: https://www.gnu.org/software/libc/manual/html_node/Socket-Option-Functions.html +/// [glibc `SOL_SOCKET` options]: https://www.gnu.org/software/libc/manual/html_node/Socket_002dLevel-Options.html +#[inline] +#[doc(alias = "SO_ERROR")] +pub fn get_socket_error<Fd: AsFd>(fd: Fd) -> io::Result<Result<(), io::Errno>> { + backend::net::syscalls::sockopt::get_socket_error(fd.as_fd()) +} + +/// `getsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE)` +/// +/// # References +/// - [POSIX `getsockopt`] +/// - [POSIX `sys/socket.h`] +/// - [Linux `getsockopt`] +/// - [Linux `socket`] +/// - [Winsock2 `getsockopt`] +/// - [Winsock2 `SOL_SOCKET` options] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc `getsockopt`] +/// - [glibc `SOL_SOCKET` Options] +/// +/// [POSIX `getsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html +/// [POSIX `sys/socket.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_socket.h.html +/// [Linux `getsockopt`]: https://man7.org/linux/man-pages/man2/getsockopt.2.html +/// [Linux `socket`]: https://man7.org/linux/man-pages/man7/socket.7.html +/// [Winsock2 `getsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-getsockopt +/// [Winsock2 `SOL_SOCKET` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/sol-socket-socket-options +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getsockopt.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=getsockopt&sektion=2 +/// [NetBSD]: https://man.netbsd.org/getsockopt.2 +/// [OpenBSD]: https://man.openbsd.org/getsockopt.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=getsockopt§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/getsockopt +/// [glibc `getsockopt`]: https://www.gnu.org/software/libc/manual/html_node/Socket-Option-Functions.html +/// [glibc `SOL_SOCKET` options]: https://www.gnu.org/software/libc/manual/html_node/Socket_002dLevel-Options.html +#[cfg(any(apple, target_os = "freebsd"))] +#[doc(alias = "SO_NOSIGPIPE")] +#[inline] +pub fn getsockopt_nosigpipe<Fd: AsFd>(fd: Fd) -> io::Result<bool> { + backend::net::syscalls::sockopt::getsockopt_nosigpipe(fd.as_fd()) +} + +/// `setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, val)` +/// +/// # References +/// - [POSIX `setsockopt`] +/// - [POSIX `sys/socket.h`] +/// - [Linux `setsockopt`] +/// - [Linux `socket`] +/// - [Winsock2 `setsockopt`] +/// - [Winsock2 `SOL_SOCKET` options] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc `setsockopt`] +/// - [glibc `SOL_SOCKET` Options] +/// +/// [POSIX `setsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html +/// [POSIX `sys/socket.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_socket.h.html +/// [Linux `setsockopt`]: https://man7.org/linux/man-pages/man2/setsockopt.2.html +/// [Linux `socket`]: https://man7.org/linux/man-pages/man7/socket.7.html +/// [Winsock2 `setsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-setsockopt +/// [Winsock2 `SOL_SOCKET` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/sol-socket-socket-options +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setsockopt.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=setsockopt&sektion=2 +/// [NetBSD]: https://man.netbsd.org/setsockopt.2 +/// [OpenBSD]: https://man.openbsd.org/setsockopt.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=setsockopt§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/setsockopt +/// [glibc `setsockopt`]: https://www.gnu.org/software/libc/manual/html_node/Socket-Option-Functions.html +/// [glibc `SOL_SOCKET` options]: https://www.gnu.org/software/libc/manual/html_node/Socket_002dLevel-Options.html +#[cfg(any(apple, target_os = "freebsd"))] +#[doc(alias = "SO_NOSIGPIPE")] +#[inline] +pub fn setsockopt_nosigpipe<Fd: AsFd>(fd: Fd, val: bool) -> io::Result<()> { + backend::net::syscalls::sockopt::setsockopt_nosigpipe(fd.as_fd(), val) +} + +/// `setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, keepalive)` +/// +/// # References +/// - [POSIX `setsockopt`] +/// - [POSIX `sys/socket.h`] +/// - [Linux `setsockopt`] +/// - [Linux `socket`] +/// - [Winsock2 `setsockopt`] +/// - [Winsock2 `SOL_SOCKET` options] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc `setsockopt`] +/// - [glibc `SOL_SOCKET` Options] +/// +/// [POSIX `setsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html +/// [POSIX `sys/socket.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_socket.h.html +/// [Linux `setsockopt`]: https://man7.org/linux/man-pages/man2/setsockopt.2.html +/// [Linux `socket`]: https://man7.org/linux/man-pages/man7/socket.7.html +/// [Winsock2 `setsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-setsockopt +/// [Winsock2 `SOL_SOCKET` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/sol-socket-socket-options +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setsockopt.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=setsockopt&sektion=2 +/// [NetBSD]: https://man.netbsd.org/setsockopt.2 +/// [OpenBSD]: https://man.openbsd.org/setsockopt.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=setsockopt§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/setsockopt +/// [glibc `setsockopt`]: https://www.gnu.org/software/libc/manual/html_node/Socket-Option-Functions.html +/// [glibc `SOL_SOCKET` options]: https://www.gnu.org/software/libc/manual/html_node/Socket_002dLevel-Options.html +#[inline] +#[doc(alias = "SO_KEEPALIVE")] +pub fn set_socket_keepalive<Fd: AsFd>(fd: Fd, keepalive: bool) -> io::Result<()> { + backend::net::syscalls::sockopt::set_socket_keepalive(fd.as_fd(), keepalive) +} + +/// `getsockopt(fd, SOL_SOCKET, SO_KEEPALIVE)` +/// +/// # References +/// - [POSIX `getsockopt`] +/// - [POSIX `sys/socket.h`] +/// - [Linux `getsockopt`] +/// - [Linux `socket`] +/// - [Winsock2 `getsockopt`] +/// - [Winsock2 `SOL_SOCKET` options] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc `getsockopt`] +/// - [glibc `SOL_SOCKET` Options] +/// +/// [POSIX `getsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html +/// [POSIX `sys/socket.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_socket.h.html +/// [Linux `getsockopt`]: https://man7.org/linux/man-pages/man2/getsockopt.2.html +/// [Linux `socket`]: https://man7.org/linux/man-pages/man7/socket.7.html +/// [Winsock2 `getsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-getsockopt +/// [Winsock2 `SOL_SOCKET` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/sol-socket-socket-options +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getsockopt.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=getsockopt&sektion=2 +/// [NetBSD]: https://man.netbsd.org/getsockopt.2 +/// [OpenBSD]: https://man.openbsd.org/getsockopt.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=getsockopt§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/getsockopt +/// [glibc `getsockopt`]: https://www.gnu.org/software/libc/manual/html_node/Socket-Option-Functions.html +/// [glibc `SOL_SOCKET` options]: https://www.gnu.org/software/libc/manual/html_node/Socket_002dLevel-Options.html +#[inline] +#[doc(alias = "SO_KEEPALIVE")] +pub fn get_socket_keepalive<Fd: AsFd>(fd: Fd) -> io::Result<bool> { + backend::net::syscalls::sockopt::get_socket_keepalive(fd.as_fd()) +} + +/// `setsockopt(fd, SOL_SOCKET, SO_RCVBUF, size)` +/// +/// # References +/// - [POSIX `setsockopt`] +/// - [POSIX `sys/socket.h`] +/// - [Linux `setsockopt`] +/// - [Linux `socket`] +/// - [Winsock2 `setsockopt`] +/// - [Winsock2 `SOL_SOCKET` options] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc `setsockopt`] +/// - [glibc `SOL_SOCKET` Options] +/// +/// [POSIX `setsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html +/// [POSIX `sys/socket.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_socket.h.html +/// [Linux `setsockopt`]: https://man7.org/linux/man-pages/man2/setsockopt.2.html +/// [Linux `socket`]: https://man7.org/linux/man-pages/man7/socket.7.html +/// [Winsock2 `setsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-setsockopt +/// [Winsock2 `SOL_SOCKET` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/sol-socket-socket-options +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setsockopt.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=setsockopt&sektion=2 +/// [NetBSD]: https://man.netbsd.org/setsockopt.2 +/// [OpenBSD]: https://man.openbsd.org/setsockopt.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=setsockopt§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/setsockopt +/// [glibc `setsockopt`]: https://www.gnu.org/software/libc/manual/html_node/Socket-Option-Functions.html +/// [glibc `SOL_SOCKET` options]: https://www.gnu.org/software/libc/manual/html_node/Socket_002dLevel-Options.html +#[inline] +#[doc(alias = "SO_RCVBUF")] +pub fn set_socket_recv_buffer_size<Fd: AsFd>(fd: Fd, size: usize) -> io::Result<()> { + backend::net::syscalls::sockopt::set_socket_recv_buffer_size(fd.as_fd(), size) +} + +/// `getsockopt(fd, SOL_SOCKET, SO_RCVBUF)` +/// +/// # References +/// - [POSIX `getsockopt`] +/// - [POSIX `sys/socket.h`] +/// - [Linux `getsockopt`] +/// - [Linux `socket`] +/// - [Winsock2 `getsockopt`] +/// - [Winsock2 `SOL_SOCKET` options] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc `getsockopt`] +/// - [glibc `SOL_SOCKET` Options] +/// +/// [POSIX `getsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html +/// [POSIX `sys/socket.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_socket.h.html +/// [Linux `getsockopt`]: https://man7.org/linux/man-pages/man2/getsockopt.2.html +/// [Linux `socket`]: https://man7.org/linux/man-pages/man7/socket.7.html +/// [Winsock2 `getsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-getsockopt +/// [Winsock2 `SOL_SOCKET` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/sol-socket-socket-options +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getsockopt.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=getsockopt&sektion=2 +/// [NetBSD]: https://man.netbsd.org/getsockopt.2 +/// [OpenBSD]: https://man.openbsd.org/getsockopt.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=getsockopt§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/getsockopt +/// [glibc `getsockopt`]: https://www.gnu.org/software/libc/manual/html_node/Socket-Option-Functions.html +/// [glibc `SOL_SOCKET` options]: https://www.gnu.org/software/libc/manual/html_node/Socket_002dLevel-Options.html +#[inline] +#[doc(alias = "SO_RCVBUF")] +pub fn get_socket_recv_buffer_size<Fd: AsFd>(fd: Fd) -> io::Result<usize> { + backend::net::syscalls::sockopt::get_socket_recv_buffer_size(fd.as_fd()) +} + +/// `setsockopt(fd, SOL_SOCKET, SO_SNDBUF, size)` +/// +/// # References +/// - [POSIX `setsockopt`] +/// - [POSIX `sys/socket.h`] +/// - [Linux `setsockopt`] +/// - [Linux `socket`] +/// - [Winsock2 `setsockopt`] +/// - [Winsock2 `SOL_SOCKET` options] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc `setsockopt`] +/// - [glibc `SOL_SOCKET` Options] +/// +/// [POSIX `setsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html +/// [POSIX `sys/socket.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_socket.h.html +/// [Linux `setsockopt`]: https://man7.org/linux/man-pages/man2/setsockopt.2.html +/// [Linux `socket`]: https://man7.org/linux/man-pages/man7/socket.7.html +/// [Winsock2 `setsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-setsockopt +/// [Winsock2 `SOL_SOCKET` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/sol-socket-socket-options +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setsockopt.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=setsockopt&sektion=2 +/// [NetBSD]: https://man.netbsd.org/setsockopt.2 +/// [OpenBSD]: https://man.openbsd.org/setsockopt.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=setsockopt§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/setsockopt +/// [glibc `setsockopt`]: https://www.gnu.org/software/libc/manual/html_node/Socket-Option-Functions.html +/// [glibc `SOL_SOCKET` options]: https://www.gnu.org/software/libc/manual/html_node/Socket_002dLevel-Options.html +#[inline] +#[doc(alias = "SO_SNDBUF")] +pub fn set_socket_send_buffer_size<Fd: AsFd>(fd: Fd, size: usize) -> io::Result<()> { + backend::net::syscalls::sockopt::set_socket_send_buffer_size(fd.as_fd(), size) +} + +/// `getsockopt(fd, SOL_SOCKET, SO_SNDBUF)` +/// +/// # References +/// - [POSIX `getsockopt`] +/// - [POSIX `sys/socket.h`] +/// - [Linux `getsockopt`] +/// - [Linux `socket`] +/// - [Winsock2 `getsockopt`] +/// - [Winsock2 `SOL_SOCKET` options] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc `getsockopt`] +/// - [glibc `SOL_SOCKET` Options] +/// +/// [POSIX `getsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html +/// [POSIX `sys/socket.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_socket.h.html +/// [Linux `getsockopt`]: https://man7.org/linux/man-pages/man2/getsockopt.2.html +/// [Linux `socket`]: https://man7.org/linux/man-pages/man7/socket.7.html +/// [Winsock2 `getsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-getsockopt +/// [Winsock2 `SOL_SOCKET` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/sol-socket-socket-options +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getsockopt.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=getsockopt&sektion=2 +/// [NetBSD]: https://man.netbsd.org/getsockopt.2 +/// [OpenBSD]: https://man.openbsd.org/getsockopt.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=getsockopt§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/getsockopt +/// [glibc `getsockopt`]: https://www.gnu.org/software/libc/manual/html_node/Socket-Option-Functions.html +/// [glibc `SOL_SOCKET` options]: https://www.gnu.org/software/libc/manual/html_node/Socket_002dLevel-Options.html +#[inline] +#[doc(alias = "SO_SNDBUF")] +pub fn get_socket_send_buffer_size<Fd: AsFd>(fd: Fd) -> io::Result<usize> { + backend::net::syscalls::sockopt::get_socket_send_buffer_size(fd.as_fd()) +} + +/// `setsockopt(fd, IPPROTO_IP, IP_TTL, ttl)` +/// +/// # References +/// - [POSIX `setsockopt`] +/// - [POSIX `netinet/in.h`] +/// - [Linux `setsockopt`] +/// - [Linux `ip`] +/// - [Winsock2 `setsockopt`] +/// - [Winsock2 `IPPROTO_IP` options] +/// - [Apple `setsockopt`] +/// - [Apple `ip`] +/// - [FreeBSD `setsockopt`] +/// - [FreeBSD `ip`] +/// - [NetBSD `setsockopt`] +/// - [NetBSD `ip`] +/// - [OpenBSD `setsockopt`] +/// - [OpenBSD `ip`] +/// - [DragonFly BSD `setsockopt`] +/// - [DragonFly BSD `ip`] +/// - [illumos `setsockopt`] +/// - [illumos `ip`] +/// +/// [POSIX `setsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html +/// [Linux `setsockopt`]: https://man7.org/linux/man-pages/man2/setsockopt.2.html +/// [Linux `ip`]: https://man7.org/linux/man-pages/man7/ip.7.html +/// [Winsock2 `setsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-setsockopt +/// [Winsock2 `IPPROTO_IP` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options +/// [Apple `setsockopt`]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setsockopt.2.html +/// [Apple `ip`]: https://opensource.apple.com/source/xnu/xnu-7195.81.3/bsd/man/man4/ip.4.auto.html +/// [FreeBSD `setsockopt`]: https://man.freebsd.org/cgi/man.cgi?query=setsockopt&sektion=2 +/// [FreeBSD `ip`]: https://man.freebsd.org/cgi/man.cgi?query=ip&sektion=4 +/// [NetBSD `setsockopt`]: https://man.netbsd.org/setsockopt.2 +/// [NetBSD `ip`]: https://man.netbsd.org/ip.4 +/// [OpenBSD `setsockopt`]: https://man.openbsd.org/setsockopt.2 +/// [OpenBSD `ip`]: https://man.openbsd.org/ip.4 +/// [DragonFly BSD `setsockopt`]: https://man.dragonflybsd.org/?command=setsockopt§ion=2 +/// [DragonFly BSD `ip`]: https://man.dragonflybsd.org/?command=ip§ion=4 +/// [illumos `setsockopt`]: https://illumos.org/man/3SOCKET/setsockopt +/// [illumos `ip`]: https://illumos.org/man/4P/ip +#[inline] +#[doc(alias = "IP_TTL")] +pub fn set_ip_ttl<Fd: AsFd>(fd: Fd, ttl: u32) -> io::Result<()> { + backend::net::syscalls::sockopt::set_ip_ttl(fd.as_fd(), ttl) +} + +/// `getsockopt(fd, IPPROTO_IP, IP_TTL)` +/// +/// # References +/// - [POSIX `getsockopt`] +/// - [POSIX `netinet/in.h`] +/// - [Linux `getsockopt`] +/// - [Linux `ip`] +/// - [Winsock2 `getsockopt`] +/// - [Winsock2 `IPPROTO_IP` options] +/// - [Apple `getsockopt`] +/// - [Apple `ip`] +/// - [FreeBSD `getsockopt`] +/// - [FreeBSD `ip`] +/// - [NetBSD `getsockopt`] +/// - [NetBSD `ip`] +/// - [OpenBSD `getsockopt`] +/// - [OpenBSD `ip`] +/// - [DragonFly BSD `getsockopt`] +/// - [DragonFly BSD `ip`] +/// - [illumos `getsockopt`] +/// - [illumos `ip`] +/// +/// [POSIX `getsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html +/// [POSIX `netinet/in.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netinet_in.h.html +/// [Linux `getsockopt`]: https://man7.org/linux/man-pages/man2/getsockopt.2.html +/// [Linux `ip`]: https://man7.org/linux/man-pages/man7/ip.7.html +/// [Winsock2 `getsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-getsockopt +/// [Winsock2 `IPPROTO_IP` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options +/// [Apple `setsockopt`]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setsockopt.2.html +/// [Apple `ip`]: https://opensource.apple.com/source/xnu/xnu-7195.81.3/bsd/man/man4/ip.4.auto.html +/// [FreeBSD `setsockopt`]: https://man.freebsd.org/cgi/man.cgi?query=setsockopt&sektion=2 +/// [FreeBSD `ip`]: https://man.freebsd.org/cgi/man.cgi?query=ip&sektion=4 +/// [NetBSD `setsockopt`]: https://man.netbsd.org/setsockopt.2 +/// [NetBSD `ip`]: https://man.netbsd.org/ip.4 +/// [OpenBSD `setsockopt`]: https://man.openbsd.org/setsockopt.2 +/// [OpenBSD `ip`]: https://man.openbsd.org/ip.4 +/// [DragonFly BSD `setsockopt`]: https://man.dragonflybsd.org/?command=setsockopt§ion=2 +/// [DragonFly BSD `ip`]: https://man.dragonflybsd.org/?command=ip§ion=4 +/// [illumos `setsockopt`]: https://illumos.org/man/3SOCKET/setsockopt +/// [illumos `ip`]: https://illumos.org/man/4P/ip +#[inline] +#[doc(alias = "IP_TTL")] +pub fn get_ip_ttl<Fd: AsFd>(fd: Fd) -> io::Result<u32> { + backend::net::syscalls::sockopt::get_ip_ttl(fd.as_fd()) +} + +/// `setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, only_v6)` +/// +/// # References +/// - [POSIX `setsockopt`] +/// - [POSIX `netinet/in.h`] +/// - [Linux `setsockopt`] +/// - [Linux `ipv6`] +/// - [Winsock2 `setsockopt`] +/// - [Winsock2 `IPPROTO_IPV6` options] +/// - [Apple `setsockopt`] +/// - [Apple `ip6`] +/// - [FreeBSD `setsockopt`] +/// - [FreeBSD `ip6`] +/// - [NetBSD `setsockopt`] +/// - [NetBSD `ip6`] +/// - [OpenBSD `setsockopt`] +/// - [OpenBSD `ip6`] +/// - [DragonFly BSD `setsockopt`] +/// - [DragonFly BSD `ip6`] +/// - [illumos `setsockopt`] +/// - [illumos `ip6`] +/// +/// [POSIX `setsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html +/// [POSIX `netinet/in.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netinet_in.h.html +/// [Linux `setsockopt`]: https://man7.org/linux/man-pages/man2/setsockopt.2.html +/// [Linux `ipv6`]: https://man7.org/linux/man-pages/man7/ipv6.7.html +/// [Winsock2 `setsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-setsockopt +/// [Winsock2 `IPPROTO_IPV6` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ipv6-socket-options +/// [Apple `setsockopt`]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setsockopt.2.html +/// [Apple `ip6`]: https://opensource.apple.com/source/xnu/xnu-7195.81.3/bsd/man/man4/ip6.4.auto.html +/// [FreeBSD `setsockopt`]: https://man.freebsd.org/cgi/man.cgi?query=setsockopt&sektion=2 +/// [FreeBSD `ip6`]: https://man.freebsd.org/cgi/man.cgi?query=ip6&sektion=4 +/// [NetBSD `setsockopt`]: https://man.netbsd.org/setsockopt.2 +/// [NetBSD `ip6`]: https://man.netbsd.org/ip6.4 +/// [OpenBSD `setsockopt`]: https://man.openbsd.org/setsockopt.2 +/// [OpenBSD `ip6`]: https://man.openbsd.org/ip6.4 +/// [DragonFly BSD `setsockopt`]: https://man.dragonflybsd.org/?command=setsockopt§ion=2 +/// [DragonFly BSD `ip6`]: https://man.dragonflybsd.org/?command=ip6§ion=4 +/// [illumos `setsockopt`]: https://illumos.org/man/3SOCKET/setsockopt +/// [illumos `ip6`]: https://illumos.org/man/4P/ip6 +#[inline] +#[doc(alias = "IPV6_V6ONLY")] +pub fn set_ipv6_v6only<Fd: AsFd>(fd: Fd, only_v6: bool) -> io::Result<()> { + backend::net::syscalls::sockopt::set_ipv6_v6only(fd.as_fd(), only_v6) +} + +/// `getsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY)` +/// +/// # References +/// - [POSIX `getsockopt`] +/// - [POSIX `netinet/in.h`] +/// - [Linux `getsockopt`] +/// - [Linux `ipv6`] +/// - [Winsock2 `getsockopt`] +/// - [Winsock2 `IPPROTO_IPV6` options] +/// - [Apple `getsockopt`] +/// - [Apple `ip6`] +/// - [FreeBSD `getsockopt`] +/// - [FreeBSD `ip6`] +/// - [NetBSD `getsockopt`] +/// - [NetBSD `ip6`] +/// - [OpenBSD `getsockopt`] +/// - [OpenBSD `ip6`] +/// - [DragonFly BSD `getsockopt`] +/// - [DragonFly BSD `ip6`] +/// - [illumos `getsockopt`] +/// - [illumos `ip6`] +/// +/// [POSIX `getsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html +/// [POSIX `netinet/in.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netinet_in.h.html +/// [Linux `getsockopt`]: https://man7.org/linux/man-pages/man2/getsockopt.2.html +/// [Linux `ipv6`]: https://man7.org/linux/man-pages/man7/ipv6.7.html +/// [Winsock2 `getsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-getsockopt +/// [Winsock2 `IPPROTO_IPV6` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ipv6-socket-options +/// [Apple `getsockopt`]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getsockopt.2.html +/// [Apple `ip6`]: https://opensource.apple.com/source/xnu/xnu-7195.81.3/bsd/man/man4/ip6.4.auto.html +/// [FreeBSD `getsockopt`]: https://man.freebsd.org/cgi/man.cgi?query=getsockopt&sektion=2 +/// [FreeBSD `ip6`]: https://man.freebsd.org/cgi/man.cgi?query=ip6&sektion=4 +/// [NetBSD `getsockopt`]: https://man.netbsd.org/getsockopt.2 +/// [NetBSD `ip6`]: https://man.netbsd.org/ip6.4 +/// [OpenBSD `getsockopt`]: https://man.openbsd.org/getsockopt.2 +/// [OpenBSD `ip6`]: https://man.openbsd.org/ip6.4 +/// [DragonFly BSD `getsockopt`]: https://man.dragonflybsd.org/?command=getsockopt§ion=2 +/// [DragonFly BSD `ip6`]: https://man.dragonflybsd.org/?command=ip6§ion=4 +/// [illumos `getsockopt`]: https://illumos.org/man/3SOCKET/getsockopt +/// [illumos `ip6`]: https://illumos.org/man/4P/ip6 +#[inline] +#[doc(alias = "IPV6_V6ONLY")] +pub fn get_ipv6_v6only<Fd: AsFd>(fd: Fd) -> io::Result<bool> { + backend::net::syscalls::sockopt::get_ipv6_v6only(fd.as_fd()) +} + +/// `setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, multicast_loop)` +/// +/// # References +/// - [POSIX `setsockopt`] +/// - [POSIX `netinet/in.h`] +/// - [Linux `setsockopt`] +/// - [Linux `ip`] +/// - [Winsock2 `setsockopt`] +/// - [Winsock2 `IPPROTO_IP` options] +/// - [Apple `setsockopt`] +/// - [Apple `ip`] +/// - [FreeBSD `setsockopt`] +/// - [FreeBSD `ip`] +/// - [NetBSD `setsockopt`] +/// - [NetBSD `ip`] +/// - [OpenBSD `setsockopt`] +/// - [OpenBSD `ip`] +/// - [DragonFly BSD `setsockopt`] +/// - [DragonFly BSD `ip`] +/// - [illumos `setsockopt`] +/// - [illumos `ip`] +/// +/// [POSIX `setsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html +/// [POSIX `netinet/in.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netinet_in.h.html +/// [Linux `setsockopt`]: https://man7.org/linux/man-pages/man2/setsockopt.2.html +/// [Linux `ip`]: https://man7.org/linux/man-pages/man7/ip.7.html +/// [Winsock2 `setsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-setsockopt +/// [Winsock2 `IPPROTO_IP` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options +/// [Apple `setsockopt`]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setsockopt.2.html +/// [Apple `ip`]: https://opensource.apple.com/source/xnu/xnu-7195.81.3/bsd/man/man4/ip.4.auto.html +/// [FreeBSD `setsockopt`]: https://man.freebsd.org/cgi/man.cgi?query=setsockopt&sektion=2 +/// [FreeBSD `ip`]: https://man.freebsd.org/cgi/man.cgi?query=ip&sektion=4 +/// [NetBSD `setsockopt`]: https://man.netbsd.org/setsockopt.2 +/// [NetBSD `ip`]: https://man.netbsd.org/ip.4 +/// [OpenBSD `setsockopt`]: https://man.openbsd.org/setsockopt.2 +/// [OpenBSD `ip`]: https://man.openbsd.org/ip.4 +/// [DragonFly BSD `setsockopt`]: https://man.dragonflybsd.org/?command=setsockopt§ion=2 +/// [DragonFly BSD `ip`]: https://man.dragonflybsd.org/?command=ip§ion=4 +/// [illumos `setsockopt`]: https://illumos.org/man/3SOCKET/setsockopt +/// [illumos `ip`]: https://illumos.org/man/4P/ip +#[inline] +#[doc(alias = "IP_MULTICAST_LOOP")] +pub fn set_ip_multicast_loop<Fd: AsFd>(fd: Fd, multicast_loop: bool) -> io::Result<()> { + backend::net::syscalls::sockopt::set_ip_multicast_loop(fd.as_fd(), multicast_loop) +} + +/// `getsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP)` +/// +/// # References +/// - [POSIX `getsockopt`] +/// - [POSIX `netinet/in.h`] +/// - [Linux `getsockopt`] +/// - [Linux `ip`] +/// - [Winsock2 `getsockopt`] +/// - [Winsock2 `IPPROTO_IP` options] +/// - [Apple `getsockopt`] +/// - [Apple `ip`] +/// - [FreeBSD `getsockopt`] +/// - [FreeBSD `ip`] +/// - [NetBSD `getsockopt`] +/// - [NetBSD `ip`] +/// - [OpenBSD `getsockopt`] +/// - [OpenBSD `ip`] +/// - [DragonFly BSD `getsockopt`] +/// - [DragonFly BSD `ip`] +/// - [illumos `getsockopt`] +/// - [illumos `ip`] +/// +/// [POSIX `getsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html +/// [POSIX `netinet/in.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netinet_in.h.html +/// [Linux `getsockopt`]: https://man7.org/linux/man-pages/man2/getsockopt.2.html +/// [Linux `ip`]: https://man7.org/linux/man-pages/man7/ip.7.html +/// [Winsock2 `getsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-getsockopt +/// [Winsock2 `IPPROTO_IP` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options +#[inline] +#[doc(alias = "IP_MULTICAST_LOOP")] +pub fn get_ip_multicast_loop<Fd: AsFd>(fd: Fd) -> io::Result<bool> { + backend::net::syscalls::sockopt::get_ip_multicast_loop(fd.as_fd()) +} + +/// `setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, multicast_ttl)` +/// +/// # References +/// - [POSIX `setsockopt`] +/// - [POSIX `netinet/in.h`] +/// - [Linux `setsockopt`] +/// - [Linux `ip`] +/// - [Winsock2 `setsockopt`] +/// - [Winsock2 `IPPROTO_IP` options] +/// - [Apple `setsockopt`] +/// - [Apple `ip`] +/// - [FreeBSD `setsockopt`] +/// - [FreeBSD `ip`] +/// - [NetBSD `setsockopt`] +/// - [NetBSD `ip`] +/// - [OpenBSD `setsockopt`] +/// - [OpenBSD `ip`] +/// - [DragonFly BSD `setsockopt`] +/// - [DragonFly BSD `ip`] +/// - [illumos `setsockopt`] +/// - [illumos `ip`] +/// +/// [POSIX `setsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html +/// [POSIX `netinet/in.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netinet_in.h.html +/// [Linux `setsockopt`]: https://man7.org/linux/man-pages/man2/setsockopt.2.html +/// [Linux `ip`]: https://man7.org/linux/man-pages/man7/ip.7.html +/// [Winsock2 `setsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-setsockopt +/// [Winsock2 `IPPROTO_IP` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options +/// [Apple `setsockopt`]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setsockopt.2.html +/// [Apple `ip`]: https://opensource.apple.com/source/xnu/xnu-7195.81.3/bsd/man/man4/ip.4.auto.html +/// [FreeBSD `setsockopt`]: https://man.freebsd.org/cgi/man.cgi?query=setsockopt&sektion=2 +/// [FreeBSD `ip`]: https://man.freebsd.org/cgi/man.cgi?query=ip&sektion=4 +/// [NetBSD `setsockopt`]: https://man.netbsd.org/setsockopt.2 +/// [NetBSD `ip`]: https://man.netbsd.org/ip.4 +/// [OpenBSD `setsockopt`]: https://man.openbsd.org/setsockopt.2 +/// [OpenBSD `ip`]: https://man.openbsd.org/ip.4 +/// [DragonFly BSD `setsockopt`]: https://man.dragonflybsd.org/?command=setsockopt§ion=2 +/// [DragonFly BSD `ip`]: https://man.dragonflybsd.org/?command=ip§ion=4 +/// [illumos `setsockopt`]: https://illumos.org/man/3SOCKET/setsockopt +/// [illumos `ip`]: https://illumos.org/man/4P/ip +#[inline] +#[doc(alias = "IP_MULTICAST_TTL")] +pub fn set_ip_multicast_ttl<Fd: AsFd>(fd: Fd, multicast_ttl: u32) -> io::Result<()> { + backend::net::syscalls::sockopt::set_ip_multicast_ttl(fd.as_fd(), multicast_ttl) +} + +/// `getsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL)` +/// +/// # References +/// - [POSIX `getsockopt`] +/// - [POSIX `netinet/in.h`] +/// - [Linux `getsockopt`] +/// - [Linux `ip`] +/// - [Winsock2 `getsockopt`] +/// - [Winsock2 `IPPROTO_IP` options] +/// - [Apple `getsockopt`] +/// - [Apple `ip`] +/// - [FreeBSD `getsockopt`] +/// - [FreeBSD `ip`] +/// - [NetBSD `getsockopt`] +/// - [NetBSD `ip`] +/// - [OpenBSD `getsockopt`] +/// - [OpenBSD `ip`] +/// - [DragonFly BSD `getsockopt`] +/// - [DragonFly BSD `ip`] +/// - [illumos `getsockopt`] +/// - [illumos `ip`] +/// +/// [POSIX `getsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html +/// [POSIX `netinet/in.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netinet_in.h.html +/// [Linux `getsockopt`]: https://man7.org/linux/man-pages/man2/getsockopt.2.html +/// [Linux `ip`]: https://man7.org/linux/man-pages/man7/ip.7.html +/// [Winsock2 `getsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-getsockopt +/// [Winsock2 `IPPROTO_IP` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options +#[inline] +#[doc(alias = "IP_MULTICAST_TTL")] +pub fn get_ip_multicast_ttl<Fd: AsFd>(fd: Fd) -> io::Result<u32> { + backend::net::syscalls::sockopt::get_ip_multicast_ttl(fd.as_fd()) +} + +/// `setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, multicast_loop)` +/// +/// # References +/// - [POSIX `setsockopt`] +/// - [POSIX `netinet/in.h`] +/// - [Linux `setsockopt`] +/// - [Linux `ipv6`] +/// - [Winsock2 `setsockopt`] +/// - [Winsock2 `IPPROTO_IPV6` options] +/// - [Apple `setsockopt`] +/// - [Apple `ip6`] +/// - [FreeBSD `setsockopt`] +/// - [FreeBSD `ip6`] +/// - [NetBSD `setsockopt`] +/// - [NetBSD `ip6`] +/// - [OpenBSD `setsockopt`] +/// - [OpenBSD `ip6`] +/// - [DragonFly BSD `setsockopt`] +/// - [DragonFly BSD `ip6`] +/// - [illumos `setsockopt`] +/// - [illumos `ip6`] +/// +/// [POSIX `setsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html +/// [POSIX `netinet/in.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netinet_in.h.html +/// [Linux `setsockopt`]: https://man7.org/linux/man-pages/man2/setsockopt.2.html +/// [Linux `ipv6`]: https://man7.org/linux/man-pages/man7/ipv6.7.html +/// [Winsock2 `setsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-setsockopt +/// [Winsock2 `IPPROTO_IPV6` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ipv6-socket-options +/// [Apple `setsockopt`]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setsockopt.2.html +/// [Apple `ip6`]: https://opensource.apple.com/source/xnu/xnu-7195.81.3/bsd/man/man4/ip6.4.auto.html +/// [FreeBSD `setsockopt`]: https://man.freebsd.org/cgi/man.cgi?query=setsockopt&sektion=2 +/// [FreeBSD `ip6`]: https://man.freebsd.org/cgi/man.cgi?query=ip6&sektion=4 +/// [NetBSD `setsockopt`]: https://man.netbsd.org/setsockopt.2 +/// [NetBSD `ip6`]: https://man.netbsd.org/ip6.4 +/// [OpenBSD `setsockopt`]: https://man.openbsd.org/setsockopt.2 +/// [OpenBSD `ip6`]: https://man.openbsd.org/ip6.4 +/// [DragonFly BSD `setsockopt`]: https://man.dragonflybsd.org/?command=setsockopt§ion=2 +/// [DragonFly BSD `ip6`]: https://man.dragonflybsd.org/?command=ip6§ion=4 +/// [illumos `setsockopt`]: https://illumos.org/man/3SOCKET/setsockopt +/// [illumos `ip6`]: https://illumos.org/man/4P/ip6 +#[inline] +#[doc(alias = "IPV6_MULTICAST_LOOP")] +pub fn set_ipv6_multicast_loop<Fd: AsFd>(fd: Fd, multicast_loop: bool) -> io::Result<()> { + backend::net::syscalls::sockopt::set_ipv6_multicast_loop(fd.as_fd(), multicast_loop) +} + +/// `getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP)` +/// +/// # References +/// - [POSIX `getsockopt`] +/// - [POSIX `netinet/in.h`] +/// - [Linux `getsockopt`] +/// - [Linux `ipv6`] +/// - [Winsock2 `getsockopt`] +/// - [Winsock2 `IPPROTO_IPV6` options] +/// - [Apple `getsockopt`] +/// - [Apple `ip6`] +/// - [FreeBSD `getsockopt`] +/// - [FreeBSD `ip6`] +/// - [NetBSD `getsockopt`] +/// - [NetBSD `ip6`] +/// - [OpenBSD `getsockopt`] +/// - [OpenBSD `ip6`] +/// - [DragonFly BSD `getsockopt`] +/// - [DragonFly BSD `ip6`] +/// - [illumos `getsockopt`] +/// - [illumos `ip6`] +/// +/// [POSIX `getsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html +/// [POSIX `netinet/in.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netinet_in.h.html +/// [Linux `getsockopt`]: https://man7.org/linux/man-pages/man2/getsockopt.2.html +/// [Linux `ipv6`]: https://man7.org/linux/man-pages/man7/ipv6.7.html +/// [Winsock2 `getsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-getsockopt +/// [Winsock2 `IPPROTO_IPV6` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ipv6-socket-options +/// [Apple `getsockopt`]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getsockopt.2.html +/// [Apple `ip6`]: https://opensource.apple.com/source/xnu/xnu-7195.81.3/bsd/man/man4/ip6.4.auto.html +/// [FreeBSD `getsockopt`]: https://man.freebsd.org/cgi/man.cgi?query=getsockopt&sektion=2 +/// [FreeBSD `ip6`]: https://man.freebsd.org/cgi/man.cgi?query=ip6&sektion=4 +/// [NetBSD `getsockopt`]: https://man.netbsd.org/getsockopt.2 +/// [NetBSD `ip6`]: https://man.netbsd.org/ip6.4 +/// [OpenBSD `getsockopt`]: https://man.openbsd.org/getsockopt.2 +/// [OpenBSD `ip6`]: https://man.openbsd.org/ip6.4 +/// [DragonFly BSD `getsockopt`]: https://man.dragonflybsd.org/?command=getsockopt§ion=2 +/// [DragonFly BSD `ip6`]: https://man.dragonflybsd.org/?command=ip6§ion=4 +/// [illumos `getsockopt`]: https://illumos.org/man/3SOCKET/getsockopt +/// [illumos `ip6`]: https://illumos.org/man/4P/ip6 +#[inline] +#[doc(alias = "IPV6_MULTICAST_LOOP")] +pub fn get_ipv6_multicast_loop<Fd: AsFd>(fd: Fd) -> io::Result<bool> { + backend::net::syscalls::sockopt::get_ipv6_multicast_loop(fd.as_fd()) +} + +/// `setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, multicast_hops)` +/// +/// # References +/// - [POSIX `setsockopt`] +/// - [POSIX `netinet/in.h`] +/// - [Linux `setsockopt`] +/// - [Linux `ipv6`] +/// - [Winsock2 `setsockopt`] +/// - [Winsock2 `IPPROTO_IPV6` options] +/// - [Apple `setsockopt`] +/// - [Apple `ip6`] +/// - [FreeBSD `setsockopt`] +/// - [FreeBSD `ip6`] +/// - [NetBSD `setsockopt`] +/// - [NetBSD `ip6`] +/// - [OpenBSD `setsockopt`] +/// - [OpenBSD `ip6`] +/// - [DragonFly BSD `setsockopt`] +/// - [DragonFly BSD `ip6`] +/// - [illumos `setsockopt`] +/// - [illumos `ip6`] +/// +/// [POSIX `setsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html +/// [POSIX `netinet/in.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netinet_in.h.html +/// [Linux `setsockopt`]: https://man7.org/linux/man-pages/man2/setsockopt.2.html +/// [Linux `ipv6`]: https://man7.org/linux/man-pages/man7/ipv6.7.html +/// [Winsock2 `setsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-setsockopt +/// [Winsock2 `IPPROTO_IPV6` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ipv6-socket-options +/// [Apple `setsockopt`]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setsockopt.2.html +/// [Apple `ip6`]: https://opensource.apple.com/source/xnu/xnu-7195.81.3/bsd/man/man4/ip6.4.auto.html +/// [FreeBSD `setsockopt`]: https://man.freebsd.org/cgi/man.cgi?query=setsockopt&sektion=2 +/// [FreeBSD `ip6`]: https://man.freebsd.org/cgi/man.cgi?query=ip6&sektion=4 +/// [NetBSD `setsockopt`]: https://man.netbsd.org/setsockopt.2 +/// [NetBSD `ip6`]: https://man.netbsd.org/ip6.4 +/// [OpenBSD `setsockopt`]: https://man.openbsd.org/setsockopt.2 +/// [OpenBSD `ip6`]: https://man.openbsd.org/ip6.4 +/// [DragonFly BSD `setsockopt`]: https://man.dragonflybsd.org/?command=setsockopt§ion=2 +/// [DragonFly BSD `ip6`]: https://man.dragonflybsd.org/?command=ip6§ion=4 +/// [illumos `setsockopt`]: https://illumos.org/man/3SOCKET/setsockopt +/// [illumos `ip6`]: https://illumos.org/man/4P/ip6 +#[inline] +#[doc(alias = "IP_MULTICAST_TTL")] +pub fn set_ipv6_multicast_hops<Fd: AsFd>(fd: Fd, multicast_hops: u32) -> io::Result<()> { + backend::net::syscalls::sockopt::set_ipv6_multicast_hops(fd.as_fd(), multicast_hops) +} + +/// `getsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS)` +/// +/// # References +/// - [POSIX `getsockopt`] +/// - [POSIX `netinet/in.h`] +/// - [Linux `getsockopt`] +/// - [Linux `ipv6`] +/// - [Winsock2 `getsockopt`] +/// - [Winsock2 `IPPROTO_IPV6` options] +/// - [Apple `getsockopt`] +/// - [Apple `ip6`] +/// - [FreeBSD `getsockopt`] +/// - [FreeBSD `ip6`] +/// - [NetBSD `getsockopt`] +/// - [NetBSD `ip6`] +/// - [OpenBSD `getsockopt`] +/// - [OpenBSD `ip6`] +/// - [DragonFly BSD `getsockopt`] +/// - [DragonFly BSD `ip6`] +/// - [illumos `getsockopt`] +/// - [illumos `ip6`] +/// +/// [POSIX `getsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html +/// [POSIX `netinet/in.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netinet_in.h.html +/// [Linux `getsockopt`]: https://man7.org/linux/man-pages/man2/getsockopt.2.html +/// [Linux `ipv6`]: https://man7.org/linux/man-pages/man7/ipv6.7.html +/// [Winsock2 `getsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-getsockopt +/// [Winsock2 `IPPROTO_IPV6` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ipv6-socket-options +/// [Apple `getsockopt`]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getsockopt.2.html +/// [Apple `ip6`]: https://opensource.apple.com/source/xnu/xnu-7195.81.3/bsd/man/man4/ip6.4.auto.html +/// [FreeBSD `getsockopt`]: https://man.freebsd.org/cgi/man.cgi?query=getsockopt&sektion=2 +/// [FreeBSD `ip6`]: https://man.freebsd.org/cgi/man.cgi?query=ip6&sektion=4 +/// [NetBSD `getsockopt`]: https://man.netbsd.org/getsockopt.2 +/// [NetBSD `ip6`]: https://man.netbsd.org/ip6.4 +/// [OpenBSD `getsockopt`]: https://man.openbsd.org/getsockopt.2 +/// [OpenBSD `ip6`]: https://man.openbsd.org/ip6.4 +/// [DragonFly BSD `getsockopt`]: https://man.dragonflybsd.org/?command=getsockopt§ion=2 +/// [DragonFly BSD `ip6`]: https://man.dragonflybsd.org/?command=ip6§ion=4 +/// [illumos `getsockopt`]: https://illumos.org/man/3SOCKET/getsockopt +/// [illumos `ip6`]: https://illumos.org/man/4P/ip6 +#[inline] +#[doc(alias = "IPV6_UNICAST_HOPS")] +pub fn get_ipv6_unicast_hops<Fd: AsFd>(fd: Fd) -> io::Result<u8> { + backend::net::syscalls::sockopt::get_ipv6_unicast_hops(fd.as_fd()) +} + +/// `setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, unicast_hops)` +/// +/// # References +/// - [POSIX `setsockopt`] +/// - [POSIX `netinet/in.h`] +/// - [Linux `setsockopt`] +/// - [Linux `ipv6`] +/// - [Winsock2 `setsockopt`] +/// - [Winsock2 `IPPROTO_IPV6` options] +/// - [Apple `setsockopt`] +/// - [Apple `ip6`] +/// - [FreeBSD `setsockopt`] +/// - [FreeBSD `ip6`] +/// - [NetBSD `setsockopt`] +/// - [NetBSD `ip6`] +/// - [OpenBSD `setsockopt`] +/// - [OpenBSD `ip6`] +/// - [DragonFly BSD `setsockopt`] +/// - [DragonFly BSD `ip6`] +/// - [illumos `setsockopt`] +/// - [illumos `ip6`] +/// +/// [POSIX `setsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html +/// [POSIX `netinet/in.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netinet_in.h.html +/// [Linux `setsockopt`]: https://man7.org/linux/man-pages/man2/setsockopt.2.html +/// [Linux `ipv6`]: https://man7.org/linux/man-pages/man7/ipv6.7.html +/// [Winsock2 `setsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-setsockopt +/// [Winsock2 `IPPROTO_IPV6` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ipv6-socket-options +/// [Apple `setsockopt`]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setsockopt.2.html +/// [Apple `ip6`]: https://opensource.apple.com/source/xnu/xnu-7195.81.3/bsd/man/man4/ip6.4.auto.html +/// [FreeBSD `setsockopt`]: https://man.freebsd.org/cgi/man.cgi?query=setsockopt&sektion=2 +/// [FreeBSD `ip6`]: https://man.freebsd.org/cgi/man.cgi?query=ip6&sektion=4 +/// [NetBSD `setsockopt`]: https://man.netbsd.org/setsockopt.2 +/// [NetBSD `ip6`]: https://man.netbsd.org/ip6.4 +/// [OpenBSD `setsockopt`]: https://man.openbsd.org/setsockopt.2 +/// [OpenBSD `ip6`]: https://man.openbsd.org/ip6.4 +/// [DragonFly BSD `setsockopt`]: https://man.dragonflybsd.org/?command=setsockopt§ion=2 +/// [DragonFly BSD `ip6`]: https://man.dragonflybsd.org/?command=ip6§ion=4 +/// [illumos `setsockopt`]: https://illumos.org/man/3SOCKET/setsockopt +/// [illumos `ip6`]: https://illumos.org/man/4P/ip6 +#[inline] +#[doc(alias = "IPV6_UNICAST_HOPS")] +pub fn set_ipv6_unicast_hops<Fd: AsFd>(fd: Fd, unicast_hops: Option<u8>) -> io::Result<()> { + backend::net::syscalls::sockopt::set_ipv6_unicast_hops(fd.as_fd(), unicast_hops) +} + +/// `getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS)` +/// +/// # References +/// - [POSIX `getsockopt`] +/// - [POSIX `netinet/in.h`] +/// - [Linux `getsockopt`] +/// - [Linux `ipv6`] +/// - [Winsock2 `getsockopt`] +/// - [Winsock2 `IPPROTO_IPV6` options] +/// - [Apple `getsockopt`] +/// - [Apple `ip6`] +/// - [FreeBSD `getsockopt`] +/// - [FreeBSD `ip6`] +/// - [NetBSD `getsockopt`] +/// - [NetBSD `ip6`] +/// - [OpenBSD `getsockopt`] +/// - [OpenBSD `ip6`] +/// - [DragonFly BSD `getsockopt`] +/// - [DragonFly BSD `ip6`] +/// - [illumos `getsockopt`] +/// - [illumos `ip6`] +/// +/// [POSIX `getsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html +/// [POSIX `netinet/in.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netinet_in.h.html +/// [Linux `getsockopt`]: https://man7.org/linux/man-pages/man2/getsockopt.2.html +/// [Linux `ipv6`]: https://man7.org/linux/man-pages/man7/ipv6.7.html +/// [Winsock2 `getsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-getsockopt +/// [Winsock2 `IPPROTO_IPV6` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ipv6-socket-options +/// [Apple `getsockopt`]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getsockopt.2.html +/// [Apple `ip6`]: https://opensource.apple.com/source/xnu/xnu-7195.81.3/bsd/man/man4/ip6.4.auto.html +/// [FreeBSD `getsockopt`]: https://man.freebsd.org/cgi/man.cgi?query=getsockopt&sektion=2 +/// [FreeBSD `ip6`]: https://man.freebsd.org/cgi/man.cgi?query=ip6&sektion=4 +/// [NetBSD `getsockopt`]: https://man.netbsd.org/getsockopt.2 +/// [NetBSD `ip6`]: https://man.netbsd.org/ip6.4 +/// [OpenBSD `getsockopt`]: https://man.openbsd.org/getsockopt.2 +/// [OpenBSD `ip6`]: https://man.openbsd.org/ip6.4 +/// [DragonFly BSD `getsockopt`]: https://man.dragonflybsd.org/?command=getsockopt§ion=2 +/// [DragonFly BSD `ip6`]: https://man.dragonflybsd.org/?command=ip6§ion=4 +/// [illumos `getsockopt`]: https://illumos.org/man/3SOCKET/getsockopt +/// [illumos `ip6`]: https://illumos.org/man/4P/ip6 +#[inline] +#[doc(alias = "IP_MULTICAST_TTL")] +pub fn get_ipv6_multicast_hops<Fd: AsFd>(fd: Fd) -> io::Result<u32> { + backend::net::syscalls::sockopt::get_ipv6_multicast_hops(fd.as_fd()) +} + +/// `setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, multiaddr, interface)` +/// +/// # References +/// - [POSIX `setsockopt`] +/// - [POSIX `netinet/in.h`] +/// - [Linux `setsockopt`] +/// - [Linux `ip`] +/// - [Winsock2 `setsockopt`] +/// - [Winsock2 `IPPROTO_IP` options] +/// - [Apple `setsockopt`] +/// - [Apple `ip`] +/// - [FreeBSD `setsockopt`] +/// - [FreeBSD `ip`] +/// - [NetBSD `setsockopt`] +/// - [NetBSD `ip`] +/// - [OpenBSD `setsockopt`] +/// - [OpenBSD `ip`] +/// - [DragonFly BSD `setsockopt`] +/// - [DragonFly BSD `ip`] +/// - [illumos `setsockopt`] +/// - [illumos `ip`] +/// +/// [POSIX `setsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html +/// [POSIX `netinet/in.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netinet_in.h.html +/// [Linux `setsockopt`]: https://man7.org/linux/man-pages/man2/setsockopt.2.html +/// [Linux `ip`]: https://man7.org/linux/man-pages/man7/ip.7.html +/// [Winsock2 `setsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-setsockopt +/// [Winsock2 `IPPROTO_IP` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options +/// [Apple `setsockopt`]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setsockopt.2.html +/// [Apple `ip`]: https://opensource.apple.com/source/xnu/xnu-7195.81.3/bsd/man/man4/ip.4.auto.html +/// [FreeBSD `setsockopt`]: https://man.freebsd.org/cgi/man.cgi?query=setsockopt&sektion=2 +/// [FreeBSD `ip`]: https://man.freebsd.org/cgi/man.cgi?query=ip&sektion=4 +/// [NetBSD `setsockopt`]: https://man.netbsd.org/setsockopt.2 +/// [NetBSD `ip`]: https://man.netbsd.org/ip.4 +/// [OpenBSD `setsockopt`]: https://man.openbsd.org/setsockopt.2 +/// [OpenBSD `ip`]: https://man.openbsd.org/ip.4 +/// [DragonFly BSD `setsockopt`]: https://man.dragonflybsd.org/?command=setsockopt§ion=2 +/// [DragonFly BSD `ip`]: https://man.dragonflybsd.org/?command=ip§ion=4 +/// [illumos `setsockopt`]: https://illumos.org/man/3SOCKET/setsockopt +/// [illumos `ip`]: https://illumos.org/man/4P/ip +#[inline] +#[doc(alias = "IP_ADD_MEMBERSHIP")] +pub fn set_ip_add_membership<Fd: AsFd>( + fd: Fd, + multiaddr: &Ipv4Addr, + interface: &Ipv4Addr, +) -> io::Result<()> { + backend::net::syscalls::sockopt::set_ip_add_membership(fd.as_fd(), multiaddr, interface) +} + +/// `setsockopt(fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, multiaddr, interface)` +/// +/// `IPV6_ADD_MEMBERSHIP` is the same as `IPV6_JOIN_GROUP` in POSIX. +/// +/// # References +/// - [POSIX `setsockopt`] +/// - [POSIX `netinet/in.h`] +/// - [Linux `setsockopt`] +/// - [Linux `ipv6`] +/// - [Winsock2 `setsockopt`] +/// - [Winsock2 `IPPROTO_IPV6` options] +/// - [Apple `setsockopt`] +/// - [Apple `ip6`] +/// - [FreeBSD `setsockopt`] +/// - [FreeBSD `ip6`] +/// - [NetBSD `setsockopt`] +/// - [NetBSD `ip6`] +/// - [OpenBSD `setsockopt`] +/// - [OpenBSD `ip6`] +/// - [DragonFly BSD `setsockopt`] +/// - [DragonFly BSD `ip6`] +/// - [illumos `setsockopt`] +/// - [illumos `ip6`] +/// +/// [POSIX `setsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html +/// [POSIX `netinet/in.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netinet_in.h.html +/// [Linux `setsockopt`]: https://man7.org/linux/man-pages/man2/setsockopt.2.html +/// [Linux `ipv6`]: https://man7.org/linux/man-pages/man7/ipv6.7.html +/// [Winsock2 `setsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-setsockopt +/// [Winsock2 `IPPROTO_IPV6` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ipv6-socket-options +/// [Apple `setsockopt`]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setsockopt.2.html +/// [Apple `ip6`]: https://opensource.apple.com/source/xnu/xnu-7195.81.3/bsd/man/man4/ip6.4.auto.html +/// [FreeBSD `setsockopt`]: https://man.freebsd.org/cgi/man.cgi?query=setsockopt&sektion=2 +/// [FreeBSD `ip6`]: https://man.freebsd.org/cgi/man.cgi?query=ip6&sektion=4 +/// [NetBSD `setsockopt`]: https://man.netbsd.org/setsockopt.2 +/// [NetBSD `ip6`]: https://man.netbsd.org/ip6.4 +/// [OpenBSD `setsockopt`]: https://man.openbsd.org/setsockopt.2 +/// [OpenBSD `ip6`]: https://man.openbsd.org/ip6.4 +/// [DragonFly BSD `setsockopt`]: https://man.dragonflybsd.org/?command=setsockopt§ion=2 +/// [DragonFly BSD `ip6`]: https://man.dragonflybsd.org/?command=ip6§ion=4 +/// [illumos `setsockopt`]: https://illumos.org/man/3SOCKET/setsockopt +/// [illumos `ip6`]: https://illumos.org/man/4P/ip6 +#[inline] +#[doc(alias = "IPV6_JOIN_GROUP")] +#[doc(alias = "IPV6_ADD_MEMBERSHIP")] +pub fn set_ipv6_add_membership<Fd: AsFd>( + fd: Fd, + multiaddr: &Ipv6Addr, + interface: u32, +) -> io::Result<()> { + backend::net::syscalls::sockopt::set_ipv6_add_membership(fd.as_fd(), multiaddr, interface) +} + +/// `setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, multiaddr, interface)` +/// +/// # References +/// - [POSIX `setsockopt`] +/// - [POSIX `netinet/in.h`] +/// - [Linux `setsockopt`] +/// - [Linux `ip`] +/// - [Winsock2 `setsockopt`] +/// - [Winsock2 `IPPROTO_IP` options] +/// - [Apple `setsockopt`] +/// - [Apple `ip`] +/// - [FreeBSD `setsockopt`] +/// - [FreeBSD `ip`] +/// - [NetBSD `setsockopt`] +/// - [NetBSD `ip`] +/// - [OpenBSD `setsockopt`] +/// - [OpenBSD `ip`] +/// - [DragonFly BSD `setsockopt`] +/// - [DragonFly BSD `ip`] +/// - [illumos `setsockopt`] +/// - [illumos `ip`] +/// +/// [POSIX `setsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html +/// [POSIX `netinet/in.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netinet_in.h.html +/// [Linux `setsockopt`]: https://man7.org/linux/man-pages/man2/setsockopt.2.html +/// [Linux `ip`]: https://man7.org/linux/man-pages/man7/ip.7.html +/// [Winsock2 `setsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-setsockopt +/// [Winsock2 `IPPROTO_IP` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options +/// [Apple `setsockopt`]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setsockopt.2.html +/// [Apple `ip`]: https://opensource.apple.com/source/xnu/xnu-7195.81.3/bsd/man/man4/ip.4.auto.html +/// [FreeBSD `setsockopt`]: https://man.freebsd.org/cgi/man.cgi?query=setsockopt&sektion=2 +/// [FreeBSD `ip`]: https://man.freebsd.org/cgi/man.cgi?query=ip&sektion=4 +/// [NetBSD `setsockopt`]: https://man.netbsd.org/setsockopt.2 +/// [NetBSD `ip`]: https://man.netbsd.org/ip.4 +/// [OpenBSD `setsockopt`]: https://man.openbsd.org/setsockopt.2 +/// [OpenBSD `ip`]: https://man.openbsd.org/ip.4 +/// [DragonFly BSD `setsockopt`]: https://man.dragonflybsd.org/?command=setsockopt§ion=2 +/// [DragonFly BSD `ip`]: https://man.dragonflybsd.org/?command=ip§ion=4 +/// [illumos `setsockopt`]: https://illumos.org/man/3SOCKET/setsockopt +/// [illumos `ip`]: https://illumos.org/man/4P/ip +#[inline] +#[doc(alias = "IP_DROP_MEMBERSHIP")] +pub fn set_ip_drop_membership<Fd: AsFd>( + fd: Fd, + multiaddr: &Ipv4Addr, + interface: &Ipv4Addr, +) -> io::Result<()> { + backend::net::syscalls::sockopt::set_ip_drop_membership(fd.as_fd(), multiaddr, interface) +} + +/// `setsockopt(fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, multiaddr, interface)` +/// +/// `IPV6_DROP_MEMBERSHIP` is the same as `IPV6_LEAVE_GROUP` in POSIX. +/// +/// # References +/// - [POSIX `setsockopt`] +/// - [POSIX `netinet/in.h`] +/// - [Linux `setsockopt`] +/// - [Linux `ipv6`] +/// - [Winsock2 `setsockopt`] +/// - [Winsock2 `IPPROTO_IPV6` options] +/// - [Apple `setsockopt`] +/// - [Apple `ip6`] +/// - [FreeBSD `setsockopt`] +/// - [FreeBSD `ip6`] +/// - [NetBSD `setsockopt`] +/// - [NetBSD `ip6`] +/// - [OpenBSD `setsockopt`] +/// - [OpenBSD `ip6`] +/// - [DragonFly BSD `setsockopt`] +/// - [DragonFly BSD `ip6`] +/// - [illumos `setsockopt`] +/// - [illumos `ip6`] +/// +/// [POSIX `setsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html +/// [POSIX `netinet/in.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netinet_in.h.html +/// [Linux `setsockopt`]: https://man7.org/linux/man-pages/man2/setsockopt.2.html +/// [Linux `ipv6`]: https://man7.org/linux/man-pages/man7/ipv6.7.html +/// [Winsock2 `setsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-setsockopt +/// [Winsock2 `IPPROTO_IPV6` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ipv6-socket-options +/// [Apple `setsockopt`]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setsockopt.2.html +/// [Apple `ip6`]: https://opensource.apple.com/source/xnu/xnu-7195.81.3/bsd/man/man4/ip6.4.auto.html +/// [FreeBSD `setsockopt`]: https://man.freebsd.org/cgi/man.cgi?query=setsockopt&sektion=2 +/// [FreeBSD `ip6`]: https://man.freebsd.org/cgi/man.cgi?query=ip6&sektion=4 +/// [NetBSD `setsockopt`]: https://man.netbsd.org/setsockopt.2 +/// [NetBSD `ip6`]: https://man.netbsd.org/ip6.4 +/// [OpenBSD `setsockopt`]: https://man.openbsd.org/setsockopt.2 +/// [OpenBSD `ip6`]: https://man.openbsd.org/ip6.4 +/// [DragonFly BSD `setsockopt`]: https://man.dragonflybsd.org/?command=setsockopt§ion=2 +/// [DragonFly BSD `ip6`]: https://man.dragonflybsd.org/?command=ip6§ion=4 +/// [illumos `setsockopt`]: https://illumos.org/man/3SOCKET/setsockopt +/// [illumos `ip6`]: https://illumos.org/man/4P/ip6 +#[inline] +#[doc(alias = "IPV6_LEAVE_GROUP")] +#[doc(alias = "IPV6_DROP_MEMBERSHIP")] +pub fn set_ipv6_drop_membership<Fd: AsFd>( + fd: Fd, + multiaddr: &Ipv6Addr, + interface: u32, +) -> io::Result<()> { + backend::net::syscalls::sockopt::set_ipv6_drop_membership(fd.as_fd(), multiaddr, interface) +} + +/// `setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, nodelay)` +/// +/// # References +/// - [POSIX `setsockopt`] +/// - [POSIX `netinet/tcp.h`] +/// - [Linux `setsockopt`] +/// - [Linux `tcp`] +/// - [Winsock2 `setsockopt`] +/// - [Winsock2 `IPPROTO_TCP` options] +/// - [Apple `setsockopt`] +/// - [Apple `tcp`] +/// - [FreeBSD `setsockopt`] +/// - [FreeBSD `tcp`] +/// - [NetBSD `setsockopt`] +/// - [NetBSD `tcp`] +/// - [OpenBSD `setsockopt`] +/// - [OpenBSD `tcp`] +/// - [DragonFly BSD `setsockopt`] +/// - [DragonFly BSD `tcp`] +/// - [illumos `setsockopt`] +/// - [illumos `tcp`] +/// +/// [POSIX `setsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html +/// [POSIX `netinet/tcp.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netinet_tcp.h.html +/// [Linux `setsockopt`]: https://man7.org/linux/man-pages/man2/setsockopt.2.html +/// [Linux `tcp`]: https://man7.org/linux/man-pages/man7/tcp.7.html +/// [Winsock2 `setsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-setsockopt +/// [Winsock2 `IPPROTO_TCP` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-tcp-socket-options +/// [Apple `setsockopt`]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setsockopt.2.html +/// [Apple `tcp`]: https://opensource.apple.com/source/xnu/xnu-7195.81.3/bsd/man/man4/tcp.4.auto.html +/// [FreeBSD `setsockopt`]: https://man.freebsd.org/cgi/man.cgi?query=setsockopt&sektion=2 +/// [FreeBSD `tcp`]: https://man.freebsd.org/cgi/man.cgi?query=tcp&sektion=4 +/// [NetBSD `setsockopt`]: https://man.netbsd.org/setsockopt.2 +/// [NetBSD `tcp`]: https://man.netbsd.org/tcp.4 +/// [OpenBSD `setsockopt`]: https://man.openbsd.org/setsockopt.2 +/// [OpenBSD `tcp`]: https://man.openbsd.org/tcp.4 +/// [DragonFly BSD `setsockopt`]: https://man.dragonflybsd.org/?command=setsockopt§ion=2 +/// [DragonFly BSD `tcp`]: https://man.dragonflybsd.org/?command=tcp§ion=4 +/// [illumos `setsockopt`]: https://illumos.org/man/3SOCKET/setsockopt +/// [illumos `tcp`]: https://illumos.org/man/4P/tcp +#[inline] +#[doc(alias = "TCP_NODELAY")] +pub fn set_tcp_nodelay<Fd: AsFd>(fd: Fd, nodelay: bool) -> io::Result<()> { + backend::net::syscalls::sockopt::set_tcp_nodelay(fd.as_fd(), nodelay) +} + +/// `getsockopt(fd, IPPROTO_TCP, TCP_NODELAY)` +/// +/// # References +/// - [POSIX `getsockopt`] +/// - [POSIX `netinet/tcp.h`] +/// - [Linux `getsockopt`] +/// - [Linux `tcp`] +/// - [Winsock2 `getsockopt`] +/// - [Winsock2 `IPPROTO_TCP` options] +/// - [Apple `getsockopt`] +/// - [Apple `tcp`] +/// - [FreeBSD `getsockopt`] +/// - [FreeBSD `tcp`] +/// - [NetBSD `getsockopt`] +/// - [NetBSD `tcp`] +/// - [OpenBSD `getsockopt`] +/// - [OpenBSD `tcp`] +/// - [DragonFly BSD `getsockopt`] +/// - [DragonFly BSD `tcp`] +/// - [illumos `getsockopt`] +/// - [illumos `tcp`] +/// +/// [POSIX `getsockopt`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html +/// [POSIX `netinet/tcp.h`]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netinet_tcp.h.html +/// [Linux `getsockopt`]: https://man7.org/linux/man-pages/man2/getsockopt.2.html +/// [Linux `tcp`]: https://man7.org/linux/man-pages/man7/tcp.7.html +/// [Winsock2 `getsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-getsockopt +/// [Winsock2 `IPPROTO_TCP` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-tcp-socket-options +/// [Apple `getsockopt`]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getsockopt.2.html +/// [Apple `tcp`]: https://opensource.apple.com/source/xnu/xnu-7195.81.3/bsd/man/man4/tcp.4.auto.html +/// [FreeBSD `getsockopt`]: https://man.freebsd.org/cgi/man.cgi?query=getsockopt&sektion=2 +/// [FreeBSD `tcp`]: https://man.freebsd.org/cgi/man.cgi?query=tcp&sektion=4 +/// [NetBSD `getsockopt`]: https://man.netbsd.org/getsockopt.2 +/// [NetBSD `tcp`]: https://man.netbsd.org/tcp.4 +/// [OpenBSD `getsockopt`]: https://man.openbsd.org/getsockopt.2 +/// [OpenBSD `tcp`]: https://man.openbsd.org/tcp.4 +/// [DragonFly BSD `getsockopt`]: https://man.dragonflybsd.org/?command=getsockopt§ion=2 +/// [DragonFly BSD `tcp`]: https://man.dragonflybsd.org/?command=tcp§ion=4 +/// [illumos `getsockopt`]: https://illumos.org/man/3SOCKET/getsockopt +/// [illumos `tcp`]: https://illumos.org/man/4P/tcp +#[inline] +#[doc(alias = "TCP_NODELAY")] +pub fn get_tcp_nodelay<Fd: AsFd>(fd: Fd) -> io::Result<bool> { + backend::net::syscalls::sockopt::get_tcp_nodelay(fd.as_fd()) +} diff --git a/vendor/rustix-0.37.22/src/net/wsa.rs b/vendor/rustix-0.37.22/src/net/wsa.rs new file mode 100644 index 000000000..3367ca95c --- /dev/null +++ b/vendor/rustix-0.37.22/src/net/wsa.rs @@ -0,0 +1,49 @@ +use crate::io; +use core::mem::MaybeUninit; +use windows_sys::Win32::Networking::WinSock::{WSACleanup, WSAGetLastError, WSAStartup, WSADATA}; + +/// `WSAStartup()`—Initialize process-wide Windows support for sockets. +/// +/// On Windows, it's necessary to initialize the sockets subsystem before +/// using sockets APIs. The function performs the necessary initialization. +/// +/// # References +/// - [Winsock2] +/// +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsastartup +pub fn wsa_startup() -> io::Result<WSADATA> { + // Request version 2.2, which has been the latest version since far older + // versions of Windows than we support here. For more information about + // the version, see [here]. + // + // [here]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsastartup#remarks + let version = 0x202; + let mut data = MaybeUninit::uninit(); + unsafe { + let ret = WSAStartup(version, data.as_mut_ptr()); + if ret == 0 { + Ok(data.assume_init()) + } else { + Err(io::Errno::from_raw_os_error(WSAGetLastError())) + } + } +} + +/// `WSACleanup()`—Clean up process-wide Windows support for sockets. +/// +/// In a program where `init` is called, if sockets are no longer necessary, +/// this function releases associated resources. +/// +/// # References +/// - [Winsock2] +/// +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsacleanup +pub fn wsa_cleanup() -> io::Result<()> { + unsafe { + if WSACleanup() == 0 { + Ok(()) + } else { + Err(io::Errno::from_raw_os_error(WSAGetLastError())) + } + } +} diff --git a/vendor/rustix-0.37.22/src/param/auxv.rs b/vendor/rustix-0.37.22/src/param/auxv.rs new file mode 100644 index 000000000..03be2a29d --- /dev/null +++ b/vendor/rustix-0.37.22/src/param/auxv.rs @@ -0,0 +1,96 @@ +use crate::backend; +#[cfg(any( + linux_raw, + all( + libc, + any( + all(target_os = "android", target_pointer_width = "64"), + target_os = "linux", + ) + ) +))] +use crate::ffi::CStr; + +/// `sysconf(_SC_PAGESIZE)`—Returns the process' page size. +/// +/// Also known as `getpagesize`. +/// +/// # References +/// - [POSIX] +/// - [Linux `sysconf`] +/// - [Linux `getpagesize`] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sysconf.html +/// [Linux `sysconf`]: https://man7.org/linux/man-pages/man3/sysconf.3.html +/// [Linux `getpagesize`]: https://man7.org/linux/man-pages/man2/getpagesize.2.html +#[inline] +#[doc(alias = "_SC_PAGESIZE")] +#[doc(alias = "_SC_PAGE_SIZE")] +#[doc(alias = "getpagesize")] +pub fn page_size() -> usize { + backend::param::auxv::page_size() +} + +/// `sysconf(_SC_CLK_TCK)`—Returns the process' clock ticks per second. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sysconf.html +/// [Linux]: https://man7.org/linux/man-pages/man3/sysconf.3.html +#[cfg(not(target_os = "wasi"))] +#[inline] +#[doc(alias = "_SC_CLK_TCK")] +pub fn clock_ticks_per_second() -> u64 { + backend::param::auxv::clock_ticks_per_second() +} + +/// `(getauxval(AT_HWCAP), getauxval(AT_HWCAP2)`—Returns the Linux "hwcap" +/// data. +/// +/// Return the Linux `AT_HWCAP` and `AT_HWCAP2` values passed to the +/// current process. Returns 0 for each value if it is not available. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man3/getauxval.3.html +#[cfg(any( + linux_raw, + all( + libc, + any( + all(target_os = "android", target_pointer_width = "64"), + target_os = "linux", + ) + ) +))] +#[inline] +pub fn linux_hwcap() -> (usize, usize) { + backend::param::auxv::linux_hwcap() +} + +/// `getauxval(AT_EXECFN)`—Returns the Linux "execfn" string. +/// +/// Return the string that Linux has recorded as the filesystem path to the +/// executable. Returns an empty string if the string is not available. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man3/getauxval.3.html +#[cfg(any( + linux_raw, + all( + libc, + any( + all(target_os = "android", target_pointer_width = "64"), + target_os = "linux", + ) + ) +))] +#[inline] +pub fn linux_execfn() -> &'static CStr { + backend::param::auxv::linux_execfn() +} diff --git a/vendor/rustix-0.37.22/src/param/init.rs b/vendor/rustix-0.37.22/src/param/init.rs new file mode 100644 index 000000000..d261fabd2 --- /dev/null +++ b/vendor/rustix-0.37.22/src/param/init.rs @@ -0,0 +1,23 @@ +//! rustix's `init` function. +//! +//! # Safety +//! +//! On mustang, or on any non-glibc non-musl platform, the `init` function must +//! be called before any other function in this module. It is unsafe because it +//! operates on raw pointers. +#![allow(unsafe_code)] + +use crate::backend; + +/// Initialize process-wide state. +/// +/// # Safety +/// +/// This must be passed a pointer to the original environment variable block +/// set up by the OS at process startup, and it must be called before any +/// other rustix functions are called. +#[inline] +#[doc(hidden)] +pub unsafe fn init(envp: *mut *mut u8) { + backend::param::auxv::init(envp) +} diff --git a/vendor/rustix-0.37.22/src/param/mod.rs b/vendor/rustix-0.37.22/src/param/mod.rs new file mode 100644 index 000000000..c3838b62e --- /dev/null +++ b/vendor/rustix-0.37.22/src/param/mod.rs @@ -0,0 +1,16 @@ +//! Process parameters. +//! +//! These values correspond to `sysconf` in POSIX, and the auxv array in Linux. +//! Despite the POSIX name “sysconf”, these aren't *system* configuration +//! parameters; they're *process* configuration parameters, as they may differ +//! between different processes on the same system. + +#[cfg(feature = "param")] +mod auxv; +#[cfg(target_vendor = "mustang")] +mod init; + +#[cfg(feature = "param")] +pub use auxv::*; +#[cfg(target_vendor = "mustang")] +pub use init::init; diff --git a/vendor/rustix-0.37.22/src/path/arg.rs b/vendor/rustix-0.37.22/src/path/arg.rs new file mode 100644 index 000000000..64091611c --- /dev/null +++ b/vendor/rustix-0.37.22/src/path/arg.rs @@ -0,0 +1,979 @@ +//! Convenient and efficient string argument passing. +//! +//! This module defines the `Arg` trait and implements it for several common +//! string types. This allows users to pass any of these string types directly +//! to rustix APIs with string arguments, and it allows rustix to implement +//! NUL-termination without the need for copying where possible. + +use crate::ffi::{CStr, CString}; +use crate::io; +#[cfg(feature = "itoa")] +use crate::path::DecInt; +use crate::path::SMALL_PATH_BUFFER_SIZE; +use alloc::borrow::Cow; +#[cfg(feature = "itoa")] +use alloc::borrow::ToOwned; +use alloc::string::String; +use alloc::vec::Vec; +use core::mem::MaybeUninit; +use core::{ptr, slice, str}; +#[cfg(feature = "std")] +use std::ffi::{OsStr, OsString}; +#[cfg(all(feature = "std", target_os = "hermit"))] +use std::os::hermit::ext::ffi::{OsStrExt, OsStringExt}; +#[cfg(all(feature = "std", unix))] +use std::os::unix::ffi::{OsStrExt, OsStringExt}; +#[cfg(all(feature = "std", target_os = "vxworks"))] +use std::os::vxworks::ext::ffi::{OsStrExt, OsStringExt}; +#[cfg(all(feature = "std", target_os = "wasi"))] +use std::os::wasi::ffi::{OsStrExt, OsStringExt}; +#[cfg(feature = "std")] +use std::path::{Component, Components, Iter, Path, PathBuf}; + +/// A trait for passing path arguments. +/// +/// This is similar to [`AsRef`]`<`[`Path`]`>`, but is implemented for more +/// kinds of strings and can convert into more kinds of strings. +/// +/// # Example +/// +/// ``` +/// # #[cfg(any(feature = "fs", feature = "net"))] +/// use rustix::ffi::CStr; +/// use rustix::io; +/// # #[cfg(any(feature = "fs", feature = "net"))] +/// use rustix::path::Arg; +/// +/// # #[cfg(any(feature = "fs", feature = "net"))] +/// pub fn touch<P: Arg>(path: P) -> io::Result<()> { +/// let path = path.into_c_str()?; +/// _touch(&path) +/// } +/// +/// # #[cfg(any(feature = "fs", feature = "net"))] +/// fn _touch(path: &CStr) -> io::Result<()> { +/// // implementation goes here +/// Ok(()) +/// } +/// ``` +/// +/// Users can then call `touch("foo")`, `touch(cstr!("foo"))`, +/// `touch(Path::new("foo"))`, or many other things. +/// +/// [`AsRef`]: std::convert::AsRef +pub trait Arg { + /// Returns a view of this string as a string slice. + fn as_str(&self) -> io::Result<&str>; + + /// Returns a potentially-lossy rendering of this string as a `Cow<'_, + /// str>`. + fn to_string_lossy(&self) -> Cow<'_, str>; + + /// Returns a view of this string as a maybe-owned [`CStr`]. + fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>>; + + /// Consumes `self` and returns a view of this string as a maybe-owned + /// [`CStr`]. + fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>> + where + Self: 'b; + + /// Runs a closure with `self` passed in as a `&CStr`. + fn into_with_c_str<T, F>(self, f: F) -> io::Result<T> + where + Self: Sized, + F: FnOnce(&CStr) -> io::Result<T>; +} + +impl Arg for &str { + #[inline] + fn as_str(&self) -> io::Result<&str> { + Ok(self) + } + + #[inline] + fn to_string_lossy(&self) -> Cow<'_, str> { + Cow::Borrowed(self) + } + + #[inline] + fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> { + Ok(Cow::Owned( + CString::new(*self).map_err(|_cstr_err| io::Errno::INVAL)?, + )) + } + + #[inline] + fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>> + where + Self: 'b, + { + Ok(Cow::Owned( + CString::new(self).map_err(|_cstr_err| io::Errno::INVAL)?, + )) + } + + #[inline] + fn into_with_c_str<T, F>(self, f: F) -> io::Result<T> + where + Self: Sized, + F: FnOnce(&CStr) -> io::Result<T>, + { + with_c_str(self.as_bytes(), f) + } +} + +impl Arg for &String { + #[inline] + fn as_str(&self) -> io::Result<&str> { + Ok(self) + } + + #[inline] + fn to_string_lossy(&self) -> Cow<'_, str> { + Cow::Borrowed(self) + } + + #[inline] + fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> { + Ok(Cow::Owned( + CString::new(String::as_str(self)).map_err(|_cstr_err| io::Errno::INVAL)?, + )) + } + + #[inline] + fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>> + where + Self: 'b, + { + self.as_str().into_c_str() + } + + #[inline] + fn into_with_c_str<T, F>(self, f: F) -> io::Result<T> + where + Self: Sized, + F: FnOnce(&CStr) -> io::Result<T>, + { + with_c_str(self.as_bytes(), f) + } +} + +impl Arg for String { + #[inline] + fn as_str(&self) -> io::Result<&str> { + Ok(self) + } + + #[inline] + fn to_string_lossy(&self) -> Cow<'_, str> { + Cow::Borrowed(self) + } + + #[inline] + fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> { + Ok(Cow::Owned( + CString::new(self.as_str()).map_err(|_cstr_err| io::Errno::INVAL)?, + )) + } + + #[inline] + fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>> + where + Self: 'b, + { + Ok(Cow::Owned( + CString::new(self).map_err(|_cstr_err| io::Errno::INVAL)?, + )) + } + + #[inline] + fn into_with_c_str<T, F>(self, f: F) -> io::Result<T> + where + Self: Sized, + F: FnOnce(&CStr) -> io::Result<T>, + { + f(&CString::new(self).map_err(|_cstr_err| io::Errno::INVAL)?) + } +} + +#[cfg(feature = "std")] +impl Arg for &OsStr { + #[inline] + fn as_str(&self) -> io::Result<&str> { + self.to_str().ok_or(io::Errno::INVAL) + } + + #[inline] + fn to_string_lossy(&self) -> Cow<'_, str> { + OsStr::to_string_lossy(self) + } + + #[inline] + fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> { + Ok(Cow::Owned( + CString::new(self.as_bytes()).map_err(|_cstr_err| io::Errno::INVAL)?, + )) + } + + #[inline] + fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>> + where + Self: 'b, + { + Ok(Cow::Owned( + CString::new(self.as_bytes()).map_err(|_cstr_err| io::Errno::INVAL)?, + )) + } + + #[inline] + fn into_with_c_str<T, F>(self, f: F) -> io::Result<T> + where + Self: Sized, + F: FnOnce(&CStr) -> io::Result<T>, + { + with_c_str(self.as_bytes(), f) + } +} + +#[cfg(feature = "std")] +impl Arg for &OsString { + #[inline] + fn as_str(&self) -> io::Result<&str> { + OsString::as_os_str(self).to_str().ok_or(io::Errno::INVAL) + } + + #[inline] + fn to_string_lossy(&self) -> Cow<'_, str> { + self.as_os_str().to_string_lossy() + } + + #[inline] + fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> { + Ok(Cow::Owned( + CString::new(OsString::as_os_str(self).as_bytes()) + .map_err(|_cstr_err| io::Errno::INVAL)?, + )) + } + + #[inline] + fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>> + where + Self: 'b, + { + self.as_os_str().into_c_str() + } + + #[inline] + fn into_with_c_str<T, F>(self, f: F) -> io::Result<T> + where + Self: Sized, + F: FnOnce(&CStr) -> io::Result<T>, + { + with_c_str(self.as_bytes(), f) + } +} + +#[cfg(feature = "std")] +impl Arg for OsString { + #[inline] + fn as_str(&self) -> io::Result<&str> { + self.as_os_str().to_str().ok_or(io::Errno::INVAL) + } + + #[inline] + fn to_string_lossy(&self) -> Cow<'_, str> { + self.as_os_str().to_string_lossy() + } + + #[inline] + fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> { + Ok(Cow::Owned( + CString::new(self.as_bytes()).map_err(|_cstr_err| io::Errno::INVAL)?, + )) + } + + #[inline] + fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>> + where + Self: 'b, + { + Ok(Cow::Owned( + CString::new(self.into_vec()).map_err(|_cstr_err| io::Errno::INVAL)?, + )) + } + + #[inline] + fn into_with_c_str<T, F>(self, f: F) -> io::Result<T> + where + Self: Sized, + F: FnOnce(&CStr) -> io::Result<T>, + { + f(&CString::new(self.into_vec()).map_err(|_cstr_err| io::Errno::INVAL)?) + } +} + +#[cfg(feature = "std")] +impl Arg for &Path { + #[inline] + fn as_str(&self) -> io::Result<&str> { + self.as_os_str().to_str().ok_or(io::Errno::INVAL) + } + + #[inline] + fn to_string_lossy(&self) -> Cow<'_, str> { + Path::to_string_lossy(self) + } + + #[inline] + fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> { + Ok(Cow::Owned( + CString::new(self.as_os_str().as_bytes()).map_err(|_cstr_err| io::Errno::INVAL)?, + )) + } + + #[inline] + fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>> + where + Self: 'b, + { + Ok(Cow::Owned( + CString::new(self.as_os_str().as_bytes()).map_err(|_cstr_err| io::Errno::INVAL)?, + )) + } + + #[inline] + fn into_with_c_str<T, F>(self, f: F) -> io::Result<T> + where + Self: Sized, + F: FnOnce(&CStr) -> io::Result<T>, + { + with_c_str(self.as_os_str().as_bytes(), f) + } +} + +#[cfg(feature = "std")] +impl Arg for &PathBuf { + #[inline] + fn as_str(&self) -> io::Result<&str> { + PathBuf::as_path(self) + .as_os_str() + .to_str() + .ok_or(io::Errno::INVAL) + } + + #[inline] + fn to_string_lossy(&self) -> Cow<'_, str> { + self.as_path().to_string_lossy() + } + + #[inline] + fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> { + Ok(Cow::Owned( + CString::new(PathBuf::as_path(self).as_os_str().as_bytes()) + .map_err(|_cstr_err| io::Errno::INVAL)?, + )) + } + + #[inline] + fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>> + where + Self: 'b, + { + self.as_path().into_c_str() + } + + #[inline] + fn into_with_c_str<T, F>(self, f: F) -> io::Result<T> + where + Self: Sized, + F: FnOnce(&CStr) -> io::Result<T>, + { + with_c_str(self.as_os_str().as_bytes(), f) + } +} + +#[cfg(feature = "std")] +impl Arg for PathBuf { + #[inline] + fn as_str(&self) -> io::Result<&str> { + self.as_os_str().to_str().ok_or(io::Errno::INVAL) + } + + #[inline] + fn to_string_lossy(&self) -> Cow<'_, str> { + self.as_os_str().to_string_lossy() + } + + #[inline] + fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> { + Ok(Cow::Owned( + CString::new(self.as_os_str().as_bytes()).map_err(|_cstr_err| io::Errno::INVAL)?, + )) + } + + #[inline] + fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>> + where + Self: 'b, + { + Ok(Cow::Owned( + CString::new(self.into_os_string().into_vec()).map_err(|_cstr_err| io::Errno::INVAL)?, + )) + } + + #[inline] + fn into_with_c_str<T, F>(self, f: F) -> io::Result<T> + where + Self: Sized, + F: FnOnce(&CStr) -> io::Result<T>, + { + f( + &CString::new(self.into_os_string().into_vec()) + .map_err(|_cstr_err| io::Errno::INVAL)?, + ) + } +} + +impl Arg for &CStr { + #[inline] + fn as_str(&self) -> io::Result<&str> { + self.to_str().map_err(|_utf8_err| io::Errno::INVAL) + } + + #[inline] + fn to_string_lossy(&self) -> Cow<'_, str> { + CStr::to_string_lossy(self) + } + + #[inline] + fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> { + Ok(Cow::Borrowed(self)) + } + + #[inline] + fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>> + where + Self: 'b, + { + Ok(Cow::Borrowed(self)) + } + + #[inline] + fn into_with_c_str<T, F>(self, f: F) -> io::Result<T> + where + Self: Sized, + F: FnOnce(&CStr) -> io::Result<T>, + { + f(self) + } +} + +impl Arg for &CString { + #[inline] + fn as_str(&self) -> io::Result<&str> { + unimplemented!() + } + + #[inline] + fn to_string_lossy(&self) -> Cow<'_, str> { + unimplemented!() + } + + #[inline] + fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> { + Ok(Cow::Borrowed(self)) + } + + #[inline] + fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>> + where + Self: 'b, + { + Ok(Cow::Borrowed(self)) + } + + #[inline] + fn into_with_c_str<T, F>(self, f: F) -> io::Result<T> + where + Self: Sized, + F: FnOnce(&CStr) -> io::Result<T>, + { + f(self) + } +} + +impl Arg for CString { + #[inline] + fn as_str(&self) -> io::Result<&str> { + self.to_str().map_err(|_utf8_err| io::Errno::INVAL) + } + + #[inline] + fn to_string_lossy(&self) -> Cow<'_, str> { + CStr::to_string_lossy(self) + } + + #[inline] + fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> { + Ok(Cow::Borrowed(self)) + } + + #[inline] + fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>> + where + Self: 'b, + { + Ok(Cow::Owned(self)) + } + + #[inline] + fn into_with_c_str<T, F>(self, f: F) -> io::Result<T> + where + Self: Sized, + F: FnOnce(&CStr) -> io::Result<T>, + { + f(&self) + } +} + +impl<'a> Arg for Cow<'a, str> { + #[inline] + fn as_str(&self) -> io::Result<&str> { + Ok(self) + } + + #[inline] + fn to_string_lossy(&self) -> Cow<'_, str> { + Cow::Borrowed(self) + } + + #[inline] + fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> { + Ok(Cow::Owned( + CString::new(self.as_ref()).map_err(|_cstr_err| io::Errno::INVAL)?, + )) + } + + #[inline] + fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>> + where + Self: 'b, + { + Ok(Cow::Owned( + match self { + Cow::Owned(s) => CString::new(s), + Cow::Borrowed(s) => CString::new(s), + } + .map_err(|_cstr_err| io::Errno::INVAL)?, + )) + } + + #[inline] + fn into_with_c_str<T, F>(self, f: F) -> io::Result<T> + where + Self: Sized, + F: FnOnce(&CStr) -> io::Result<T>, + { + with_c_str(self.as_bytes(), f) + } +} + +#[cfg(feature = "std")] +impl<'a> Arg for Cow<'a, OsStr> { + #[inline] + fn as_str(&self) -> io::Result<&str> { + (**self).to_str().ok_or(io::Errno::INVAL) + } + + #[inline] + fn to_string_lossy(&self) -> Cow<'_, str> { + (**self).to_string_lossy() + } + + #[inline] + fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> { + Ok(Cow::Owned( + CString::new(self.as_bytes()).map_err(|_cstr_err| io::Errno::INVAL)?, + )) + } + + #[inline] + fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>> + where + Self: 'b, + { + Ok(Cow::Owned( + match self { + Cow::Owned(os) => CString::new(os.into_vec()), + Cow::Borrowed(os) => CString::new(os.as_bytes()), + } + .map_err(|_cstr_err| io::Errno::INVAL)?, + )) + } + + #[inline] + fn into_with_c_str<T, F>(self, f: F) -> io::Result<T> + where + Self: Sized, + F: FnOnce(&CStr) -> io::Result<T>, + { + with_c_str(self.as_bytes(), f) + } +} + +impl<'a> Arg for Cow<'a, CStr> { + #[inline] + fn as_str(&self) -> io::Result<&str> { + self.to_str().map_err(|_utf8_err| io::Errno::INVAL) + } + + #[inline] + fn to_string_lossy(&self) -> Cow<'_, str> { + let borrow: &CStr = core::borrow::Borrow::borrow(self); + borrow.to_string_lossy() + } + + #[inline] + fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> { + Ok(Cow::Borrowed(self)) + } + + #[inline] + fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>> + where + Self: 'b, + { + Ok(self) + } + + #[inline] + fn into_with_c_str<T, F>(self, f: F) -> io::Result<T> + where + Self: Sized, + F: FnOnce(&CStr) -> io::Result<T>, + { + f(&self) + } +} + +#[cfg(feature = "std")] +impl<'a> Arg for Component<'a> { + #[inline] + fn as_str(&self) -> io::Result<&str> { + self.as_os_str().to_str().ok_or(io::Errno::INVAL) + } + + #[inline] + fn to_string_lossy(&self) -> Cow<'_, str> { + self.as_os_str().to_string_lossy() + } + + #[inline] + fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> { + Ok(Cow::Owned( + CString::new(self.as_os_str().as_bytes()).map_err(|_cstr_err| io::Errno::INVAL)?, + )) + } + + #[inline] + fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>> + where + Self: 'b, + { + Ok(Cow::Owned( + CString::new(self.as_os_str().as_bytes()).map_err(|_cstr_err| io::Errno::INVAL)?, + )) + } + + #[inline] + fn into_with_c_str<T, F>(self, f: F) -> io::Result<T> + where + Self: Sized, + F: FnOnce(&CStr) -> io::Result<T>, + { + with_c_str(self.as_os_str().as_bytes(), f) + } +} + +#[cfg(feature = "std")] +impl<'a> Arg for Components<'a> { + #[inline] + fn as_str(&self) -> io::Result<&str> { + self.as_path().to_str().ok_or(io::Errno::INVAL) + } + + #[inline] + fn to_string_lossy(&self) -> Cow<'_, str> { + self.as_path().to_string_lossy() + } + + #[inline] + fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> { + Ok(Cow::Owned( + CString::new(self.as_path().as_os_str().as_bytes()) + .map_err(|_cstr_err| io::Errno::INVAL)?, + )) + } + + #[inline] + fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>> + where + Self: 'b, + { + Ok(Cow::Owned( + CString::new(self.as_path().as_os_str().as_bytes()) + .map_err(|_cstr_err| io::Errno::INVAL)?, + )) + } + + #[inline] + fn into_with_c_str<T, F>(self, f: F) -> io::Result<T> + where + Self: Sized, + F: FnOnce(&CStr) -> io::Result<T>, + { + with_c_str(self.as_path().as_os_str().as_bytes(), f) + } +} + +#[cfg(feature = "std")] +impl<'a> Arg for Iter<'a> { + #[inline] + fn as_str(&self) -> io::Result<&str> { + self.as_path().to_str().ok_or(io::Errno::INVAL) + } + + #[inline] + fn to_string_lossy(&self) -> Cow<'_, str> { + self.as_path().to_string_lossy() + } + + #[inline] + fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> { + Ok(Cow::Owned( + CString::new(self.as_path().as_os_str().as_bytes()) + .map_err(|_cstr_err| io::Errno::INVAL)?, + )) + } + + #[inline] + fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>> + where + Self: 'b, + { + Ok(Cow::Owned( + CString::new(self.as_path().as_os_str().as_bytes()) + .map_err(|_cstr_err| io::Errno::INVAL)?, + )) + } + + #[inline] + fn into_with_c_str<T, F>(self, f: F) -> io::Result<T> + where + Self: Sized, + F: FnOnce(&CStr) -> io::Result<T>, + { + with_c_str(self.as_path().as_os_str().as_bytes(), f) + } +} + +impl Arg for &[u8] { + #[inline] + fn as_str(&self) -> io::Result<&str> { + str::from_utf8(self).map_err(|_utf8_err| io::Errno::INVAL) + } + + #[inline] + fn to_string_lossy(&self) -> Cow<'_, str> { + String::from_utf8_lossy(self) + } + + #[inline] + fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> { + Ok(Cow::Owned( + CString::new(*self).map_err(|_cstr_err| io::Errno::INVAL)?, + )) + } + + #[inline] + fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>> + where + Self: 'b, + { + Ok(Cow::Owned( + CString::new(self).map_err(|_cstr_err| io::Errno::INVAL)?, + )) + } + + #[inline] + fn into_with_c_str<T, F>(self, f: F) -> io::Result<T> + where + Self: Sized, + F: FnOnce(&CStr) -> io::Result<T>, + { + with_c_str(self, f) + } +} + +impl Arg for &Vec<u8> { + #[inline] + fn as_str(&self) -> io::Result<&str> { + str::from_utf8(self).map_err(|_utf8_err| io::Errno::INVAL) + } + + #[inline] + fn to_string_lossy(&self) -> Cow<'_, str> { + String::from_utf8_lossy(self) + } + + #[inline] + fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> { + Ok(Cow::Owned( + CString::new(self.as_slice()).map_err(|_cstr_err| io::Errno::INVAL)?, + )) + } + + #[inline] + fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>> + where + Self: 'b, + { + Ok(Cow::Owned( + CString::new(self.as_slice()).map_err(|_cstr_err| io::Errno::INVAL)?, + )) + } + + #[inline] + fn into_with_c_str<T, F>(self, f: F) -> io::Result<T> + where + Self: Sized, + F: FnOnce(&CStr) -> io::Result<T>, + { + with_c_str(self, f) + } +} + +impl Arg for Vec<u8> { + #[inline] + fn as_str(&self) -> io::Result<&str> { + str::from_utf8(self).map_err(|_utf8_err| io::Errno::INVAL) + } + + #[inline] + fn to_string_lossy(&self) -> Cow<'_, str> { + String::from_utf8_lossy(self) + } + + #[inline] + fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> { + Ok(Cow::Owned( + CString::new(self.as_slice()).map_err(|_cstr_err| io::Errno::INVAL)?, + )) + } + + #[inline] + fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>> + where + Self: 'b, + { + Ok(Cow::Owned( + CString::new(self).map_err(|_cstr_err| io::Errno::INVAL)?, + )) + } + + #[inline] + fn into_with_c_str<T, F>(self, f: F) -> io::Result<T> + where + Self: Sized, + F: FnOnce(&CStr) -> io::Result<T>, + { + f(&CString::new(self).map_err(|_cstr_err| io::Errno::INVAL)?) + } +} + +#[cfg(feature = "itoa")] +impl Arg for DecInt { + #[inline] + fn as_str(&self) -> io::Result<&str> { + Ok(self.as_str()) + } + + #[inline] + fn to_string_lossy(&self) -> Cow<'_, str> { + Cow::Borrowed(self.as_str()) + } + + #[inline] + fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> { + Ok(Cow::Borrowed(self.as_c_str())) + } + + #[inline] + fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>> + where + Self: 'b, + { + Ok(Cow::Owned(self.as_c_str().to_owned())) + } + + #[inline] + fn into_with_c_str<T, F>(self, f: F) -> io::Result<T> + where + Self: Sized, + F: FnOnce(&CStr) -> io::Result<T>, + { + f(self.as_c_str()) + } +} + +/// Runs a closure with `bytes` passed in as a `&CStr`. +#[allow(unsafe_code, clippy::int_plus_one)] +#[inline] +fn with_c_str<T, F>(bytes: &[u8], f: F) -> io::Result<T> +where + F: FnOnce(&CStr) -> io::Result<T>, +{ + // Most paths are less than `SMALL_PATH_BUFFER_SIZE` long. The rest can go + // through the dynamic allocation path. If you're opening many files in a + // directory with a long path, consider opening the directory and using + // `openat` to open the files under it, which will avoid this, and is often + // faster in the OS as well. + + // Test with >= so that we have room for the trailing NUL. + if bytes.len() >= SMALL_PATH_BUFFER_SIZE { + return with_c_str_slow_path(bytes, f); + } + + // Taken from + // <https://github.com/rust-lang/rust/blob/a00f8ba7fcac1b27341679c51bf5a3271fa82df3/library/std/src/sys/common/small_c_string.rs> + let mut buf = MaybeUninit::<[u8; SMALL_PATH_BUFFER_SIZE]>::uninit(); + let buf_ptr = buf.as_mut_ptr().cast::<u8>(); + + // This helps test our safety condition below. + debug_assert!(bytes.len() + 1 <= SMALL_PATH_BUFFER_SIZE); + + // SAFETY: `bytes.len() < SMALL_PATH_BUFFER_SIZE` which means we have space + // for `bytes.len() + 1` u8s: + unsafe { + ptr::copy_nonoverlapping(bytes.as_ptr(), buf_ptr, bytes.len()); + buf_ptr.add(bytes.len()).write(0); + } + + // SAFETY: we just wrote the bytes above and they will remain valid for the + // duration of f b/c buf doesn't get dropped until the end of the function. + match CStr::from_bytes_with_nul(unsafe { slice::from_raw_parts(buf_ptr, bytes.len() + 1) }) { + Ok(s) => f(s), + Err(_) => Err(io::Errno::INVAL), + } +} + +/// The slow path which handles any length. In theory OS's only support up +/// to `PATH_MAX`, but we let the OS enforce that. +#[cold] +fn with_c_str_slow_path<T, F>(bytes: &[u8], f: F) -> io::Result<T> +where + F: FnOnce(&CStr) -> io::Result<T>, +{ + f(&CString::new(bytes).map_err(|_cstr_err| io::Errno::INVAL)?) +} diff --git a/vendor/rustix-0.37.22/src/path/dec_int.rs b/vendor/rustix-0.37.22/src/path/dec_int.rs new file mode 100644 index 000000000..04c97d406 --- /dev/null +++ b/vendor/rustix-0.37.22/src/path/dec_int.rs @@ -0,0 +1,120 @@ +//! Efficient decimal integer formatting. +//! +//! # Safety +//! +//! This uses `CStr::from_bytes_with_nul_unchecked` and +//! `str::from_utf8_unchecked`on the buffer that it filled itself. +#![allow(unsafe_code)] + +use crate::backend::fd::{AsFd, AsRawFd}; +use crate::ffi::CStr; +use core::fmt::Write; +use itoa::{Buffer, Integer}; +#[cfg(all(feature = "std", unix))] +use std::os::unix::ffi::OsStrExt; +#[cfg(all(feature = "std", target_os = "wasi"))] +use std::os::wasi::ffi::OsStrExt; +#[cfg(feature = "std")] +use {core::fmt, std::ffi::OsStr, std::path::Path}; + +/// Format an integer into a decimal `Path` component, without constructing a +/// temporary `PathBuf` or `String`. +/// +/// This is used for opening paths such as `/proc/self/fd/<fd>` on Linux. +/// +/// # Example +/// +/// ``` +/// # #[cfg(any(feature = "fs", feature = "net"))] +/// use rustix::path::DecInt; +/// +/// # #[cfg(any(feature = "fs", feature = "net"))] +/// assert_eq!( +/// format!("hello {}", DecInt::new(9876).as_ref().display()), +/// "hello 9876" +/// ); +/// ``` +#[derive(Clone)] +pub struct DecInt { + // 20 `u8`s is enough to hold the decimal ASCII representation of any + // `u64`, and we add one for a NUL terminator for `as_c_str`. + buf: [u8; 20 + 1], + len: usize, +} + +impl DecInt { + /// Construct a new path component from an integer. + #[inline] + pub fn new<Int: Integer>(i: Int) -> Self { + let mut me = DecIntWriter(Self { + buf: [0; 20 + 1], + len: 0, + }); + let mut buf = Buffer::new(); + me.write_str(buf.format(i)).unwrap(); + me.0 + } + + /// Construct a new path component from a file descriptor. + #[inline] + pub fn from_fd<Fd: AsFd>(fd: Fd) -> Self { + Self::new(fd.as_fd().as_raw_fd()) + } + + /// Return the raw byte buffer as a `&str`. + #[inline] + pub fn as_str(&self) -> &str { + // SAFETY: `DecInt` always holds a formatted decimal number, so it's + // always valid UTF-8. + unsafe { core::str::from_utf8_unchecked(self.as_bytes()) } + } + + /// Return the raw byte buffer as a `&CStr`. + #[inline] + pub fn as_c_str(&self) -> &CStr { + let bytes_with_nul = &self.buf[..=self.len]; + debug_assert!(CStr::from_bytes_with_nul(bytes_with_nul).is_ok()); + + // SAFETY: `self.buf` holds a single decimal ASCII representation and + // at least one extra NUL byte. + unsafe { CStr::from_bytes_with_nul_unchecked(bytes_with_nul) } + } + + /// Return the raw byte buffer. + #[inline] + pub fn as_bytes(&self) -> &[u8] { + &self.buf[..self.len] + } +} + +struct DecIntWriter(DecInt); + +impl core::fmt::Write for DecIntWriter { + #[inline] + fn write_str(&mut self, s: &str) -> core::fmt::Result { + match self.0.buf.get_mut(self.0.len..self.0.len + s.len()) { + Some(slice) => { + slice.copy_from_slice(s.as_bytes()); + self.0.len += s.len(); + Ok(()) + } + None => Err(core::fmt::Error), + } + } +} + +#[cfg(feature = "std")] +impl AsRef<Path> for DecInt { + #[inline] + fn as_ref(&self) -> &Path { + let as_os_str: &OsStr = OsStrExt::from_bytes(&self.buf[..self.len]); + Path::new(as_os_str) + } +} + +#[cfg(feature = "std")] +impl fmt::Debug for DecInt { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + self.as_str().fmt(fmt) + } +} diff --git a/vendor/rustix-0.37.22/src/path/mod.rs b/vendor/rustix-0.37.22/src/path/mod.rs new file mode 100644 index 000000000..19bf2c7f0 --- /dev/null +++ b/vendor/rustix-0.37.22/src/path/mod.rs @@ -0,0 +1,12 @@ +//! Filesystem path operations. + +mod arg; +#[cfg(feature = "itoa")] +mod dec_int; + +pub use arg::Arg; +#[cfg(feature = "itoa")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "itoa")))] +pub use dec_int::DecInt; + +pub(crate) const SMALL_PATH_BUFFER_SIZE: usize = 256; diff --git a/vendor/rustix-0.37.22/src/process/chdir.rs b/vendor/rustix-0.37.22/src/process/chdir.rs new file mode 100644 index 000000000..4951e5670 --- /dev/null +++ b/vendor/rustix-0.37.22/src/process/chdir.rs @@ -0,0 +1,72 @@ +use crate::ffi::CString; +use crate::path::SMALL_PATH_BUFFER_SIZE; +use crate::{backend, io, path}; +use alloc::vec::Vec; +#[cfg(not(target_os = "fuchsia"))] +use backend::fd::AsFd; + +/// `chdir(path)`—Change the current working directory. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/chdir.html +/// [Linux]: https://man7.org/linux/man-pages/man2/chdir.2.html +#[inline] +pub fn chdir<P: path::Arg>(path: P) -> io::Result<()> { + path.into_with_c_str(backend::process::syscalls::chdir) +} + +/// `fchdir(fd)`—Change the current working directory. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchdir.html +/// [Linux]: https://man7.org/linux/man-pages/man2/fchdir.2.html +#[cfg(not(target_os = "fuchsia"))] +#[inline] +pub fn fchdir<Fd: AsFd>(fd: Fd) -> io::Result<()> { + backend::process::syscalls::fchdir(fd.as_fd()) +} + +/// `getcwd()`—Return the current working directory. +/// +/// If `reuse` is non-empty, reuse its buffer to store the result if possible. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getcwd.html +/// [Linux]: https://man7.org/linux/man-pages/man3/getcwd.3.html +#[cfg(not(target_os = "wasi"))] +#[inline] +pub fn getcwd<B: Into<Vec<u8>>>(reuse: B) -> io::Result<CString> { + _getcwd(reuse.into()) +} + +fn _getcwd(mut buffer: Vec<u8>) -> io::Result<CString> { + // This code would benefit from having a better way to read into + // uninitialized memory, but that requires `unsafe`. + buffer.clear(); + buffer.reserve(SMALL_PATH_BUFFER_SIZE); + buffer.resize(buffer.capacity(), 0_u8); + + loop { + match backend::process::syscalls::getcwd(&mut buffer) { + Err(io::Errno::RANGE) => { + buffer.reserve(1); // use `Vec` reallocation strategy to grow capacity exponentially + buffer.resize(buffer.capacity(), 0_u8); + } + Ok(_) => { + let len = buffer.iter().position(|x| *x == b'\0').unwrap(); + buffer.resize(len, 0_u8); + return Ok(CString::new(buffer).unwrap()); + } + Err(errno) => return Err(errno), + } + } +} diff --git a/vendor/rustix-0.37.22/src/process/chroot.rs b/vendor/rustix-0.37.22/src/process/chroot.rs new file mode 100644 index 000000000..d68a8b081 --- /dev/null +++ b/vendor/rustix-0.37.22/src/process/chroot.rs @@ -0,0 +1,12 @@ +use crate::{backend, io, path}; + +/// `chroot(path)`—Change the process root directory. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/chroot.2.html +#[inline] +pub fn chroot<P: path::Arg>(path: P) -> io::Result<()> { + path.into_with_c_str(backend::process::syscalls::chroot) +} diff --git a/vendor/rustix-0.37.22/src/process/exit.rs b/vendor/rustix-0.37.22/src/process/exit.rs new file mode 100644 index 000000000..2bbbcf538 --- /dev/null +++ b/vendor/rustix-0.37.22/src/process/exit.rs @@ -0,0 +1,36 @@ +use crate::backend; + +/// `EXIT_SUCCESS` for use with [`exit`]. +/// +/// [`exit`]: std::process::exit +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/stdlib.h.html +/// [Linux]: https://man7.org/linux/man-pages/man3/exit.3.html +pub const EXIT_SUCCESS: i32 = backend::process::types::EXIT_SUCCESS; + +/// `EXIT_FAILURE` for use with [`exit`]. +/// +/// [`exit`]: std::process::exit +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/stdlib.h.html +/// [Linux]: https://man7.org/linux/man-pages/man3/exit.3.html +pub const EXIT_FAILURE: i32 = backend::process::types::EXIT_FAILURE; + +/// The exit status used by a process terminated with a [`Signal::Abort`] +/// signal. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://tldp.org/LDP/abs/html/exitcodes.html +/// [`Signal::Abort`]: crate::process::Signal::Abort +#[cfg(not(target_os = "wasi"))] +pub const EXIT_SIGNALED_SIGABRT: i32 = backend::process::types::EXIT_SIGNALED_SIGABRT; diff --git a/vendor/rustix-0.37.22/src/process/id.rs b/vendor/rustix-0.37.22/src/process/id.rs new file mode 100644 index 000000000..9058cf595 --- /dev/null +++ b/vendor/rustix-0.37.22/src/process/id.rs @@ -0,0 +1,383 @@ +//! Unix user, group, and process identifiers. +//! +//! # Safety +//! +//! The `Uid`, `Gid`, and `Pid` types can be constructed from raw integers, +//! which is marked unsafe because actual OS's assign special meaning to some +//! integer values. +#![allow(unsafe_code)] + +use crate::{backend, io}; +use alloc::vec::Vec; +#[cfg(linux_kernel)] +use backend::process::types::RawCpuid; + +/// The raw integer value of a Unix user ID. +pub use backend::process::types::RawUid; + +/// The raw integer value of a Unix group ID. +pub use backend::process::types::RawGid; + +/// The raw integer value of a Unix process ID. +pub use backend::process::types::RawPid; + +/// The raw integer value of a Unix process ID. +pub use backend::process::types::RawNonZeroPid; + +/// `uid_t`—A Unix user ID. +#[repr(transparent)] +#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)] +pub struct Uid(RawUid); + +/// `gid_t`—A Unix group ID. +#[repr(transparent)] +#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)] +pub struct Gid(RawGid); + +/// `pid_t`—A non-zero Unix process ID. +/// +/// This is a pid, and not a pidfd. It is not a file descriptor, and the +/// process it refers to could disappear at any time and be replaced by +/// another, unrelated, process. +#[repr(transparent)] +#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)] +pub struct Pid(RawNonZeroPid); + +/// A Linux CPU ID. +#[cfg(linux_kernel)] +#[repr(transparent)] +#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)] +pub struct Cpuid(RawCpuid); + +impl Uid { + /// A `Uid` corresponding to the root user (uid 0). + pub const ROOT: Self = Self(0); + + /// Converts a `RawUid` into a `Uid`. + /// + /// # Safety + /// + /// `raw` must be the value of a valid Unix user ID. + #[inline] + pub const unsafe fn from_raw(raw: RawUid) -> Self { + Self(raw) + } + + /// Converts a `Uid` into a `RawUid`. + #[inline] + pub const fn as_raw(self) -> RawUid { + self.0 + } + + /// Test whether this uid represents the root user (uid 0). + #[inline] + pub const fn is_root(self) -> bool { + self.0 == Self::ROOT.0 + } +} + +impl Gid { + /// A `Gid` corresponding to the root group (gid 0). + pub const ROOT: Self = Self(0); + + /// Converts a `RawGid` into a `Gid`. + /// + /// # Safety + /// + /// `raw` must be the value of a valid Unix group ID. + #[inline] + pub const unsafe fn from_raw(raw: RawGid) -> Self { + Self(raw) + } + + /// Converts a `Gid` into a `RawGid`. + #[inline] + pub const fn as_raw(self) -> RawGid { + self.0 + } + + /// Test whether this gid represents the root group (gid 0). + #[inline] + pub const fn is_root(self) -> bool { + self.0 == Self::ROOT.0 + } +} + +impl Pid { + /// A `Pid` corresponding to the init process (pid 1). + pub const INIT: Self = Self( + // SAFETY: The init process' pid is always valid. + unsafe { RawNonZeroPid::new_unchecked(1) }, + ); + + /// Converts a `RawPid` into a `Pid`. + /// + /// # Safety + /// + /// `raw` must be the value of a valid Unix process ID, or zero. + #[inline] + pub const unsafe fn from_raw(raw: RawPid) -> Option<Self> { + match RawNonZeroPid::new(raw) { + Some(pid) => Some(Self(pid)), + None => None, + } + } + + /// Converts a known non-zero `RawPid` into a `Pid`. + /// + /// # Safety + /// + /// `raw` must be the value of a valid Unix process ID. It must not be + /// zero. + #[inline] + pub const unsafe fn from_raw_nonzero(raw: RawNonZeroPid) -> Self { + Self(raw) + } + + /// Creates a `Pid` holding the ID of the given child process. + #[cfg(feature = "std")] + #[inline] + pub fn from_child(child: &std::process::Child) -> Self { + let id = child.id(); + debug_assert_ne!(id, 0); + + // SAFETY: We know the returned ID is valid because it came directly + // from an OS API. + unsafe { Self::from_raw_nonzero(RawNonZeroPid::new_unchecked(id as _)) } + } + + /// Converts a `Pid` into a `RawNonZeroPid`. + #[inline] + pub const fn as_raw_nonzero(self) -> RawNonZeroPid { + self.0 + } + + /// Converts an `Option<Pid>` into a `RawPid`. + #[inline] + pub fn as_raw(pid: Option<Self>) -> RawPid { + pid.map_or(0, |pid| pid.0.get()) + } + + /// Test whether this pid represents the init process (pid 0). + #[inline] + pub const fn is_init(self) -> bool { + self.0.get() == Self::INIT.0.get() + } +} + +#[cfg(linux_kernel)] +impl Cpuid { + /// Converts a `RawCpuid` into a `Cpuid`. + /// + /// # Safety + /// + /// `raw` must be the value of a valid Linux CPU ID. + #[inline] + pub const unsafe fn from_raw(raw: RawCpuid) -> Self { + Self(raw) + } + + /// Converts a `Cpuid` into a `RawCpuid`. + #[inline] + pub const fn as_raw(self) -> RawCpuid { + self.0 + } +} + +/// `getuid()`—Returns the process' real user ID. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getuid.html +/// [Linux]: https://man7.org/linux/man-pages/man2/getuid.2.html +#[inline] +#[must_use] +pub fn getuid() -> Uid { + backend::process::syscalls::getuid() +} + +/// `geteuid()`—Returns the process' effective user ID. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/geteuid.html +/// [Linux]: https://man7.org/linux/man-pages/man2/geteuid.2.html +#[inline] +#[must_use] +pub fn geteuid() -> Uid { + backend::process::syscalls::geteuid() +} + +/// `getgid()`—Returns the process' real group ID. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getgid.html +/// [Linux]: https://man7.org/linux/man-pages/man2/getgid.2.html +#[inline] +#[must_use] +pub fn getgid() -> Gid { + backend::process::syscalls::getgid() +} + +/// `getegid()`—Returns the process' effective group ID. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getegid.html +/// [Linux]: https://man7.org/linux/man-pages/man2/getegid.2.html +#[inline] +#[must_use] +pub fn getegid() -> Gid { + backend::process::syscalls::getegid() +} + +/// `getpid()`—Returns the process' ID. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpid.html +/// [Linux]: https://man7.org/linux/man-pages/man2/getpid.2.html +#[inline] +#[must_use] +pub fn getpid() -> Pid { + backend::process::syscalls::getpid() +} + +/// `getppid()`—Returns the parent process' ID. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getppid.html +/// [Linux]: https://man7.org/linux/man-pages/man2/getppid.2.html +#[inline] +#[must_use] +pub fn getppid() -> Option<Pid> { + backend::process::syscalls::getppid() +} + +/// `getpgid(pid)`—Returns the process group ID of the given process. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpgid.html +/// [Linux]: https://man7.org/linux/man-pages/man2/getpgid.2.html +#[inline] +pub fn getpgid(pid: Option<Pid>) -> io::Result<Pid> { + backend::process::syscalls::getpgid(pid) +} + +/// `setpgid(pid, pgid)`—Sets the process group ID of the given process. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setpgid.html +/// [Linux]: https://man7.org/linux/man-pages/man2/setpgid.2.html +#[inline] +pub fn setpgid(pid: Option<Pid>, pgid: Option<Pid>) -> io::Result<()> { + backend::process::syscalls::setpgid(pid, pgid) +} + +/// `getpgrp()`—Returns the process' group ID. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpgrp.html +/// [Linux]: https://man7.org/linux/man-pages/man2/getpgrp.2.html +#[inline] +#[must_use] +pub fn getpgrp() -> Pid { + backend::process::syscalls::getpgrp() +} + +/// `getsid(pid)`—Get the session ID of the given process. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsid.html +/// [Linux]: https://man7.org/linux/man-pages/man2/getsid.2.html +#[cfg(not(target_os = "redox"))] +#[inline] +pub fn getsid(pid: Option<Pid>) -> io::Result<Pid> { + backend::process::syscalls::getsid(pid) +} + +/// `setsid()`—Create a new session. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsid.html +/// [Linux]: https://man7.org/linux/man-pages/man2/setsid.2.html +#[inline] +pub fn setsid() -> io::Result<Pid> { + backend::process::syscalls::setsid() +} + +/// `getgroups()`—Return a list of the current user's groups. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getgroups.html +/// [Linux]: https://man7.org/linux/man-pages/man2/getgroups.2.html +pub fn getgroups() -> io::Result<Vec<Gid>> { + let mut buffer = Vec::new(); + + // This code would benefit from having a better way to read into + // uninitialized memory, but that requires `unsafe`. + buffer.reserve(8); + buffer.resize(buffer.capacity(), Gid::ROOT); + + loop { + let ngroups = backend::process::syscalls::getgroups(&mut buffer)?; + + let ngroups = ngroups as usize; + assert!(ngroups <= buffer.len()); + if ngroups < buffer.len() { + buffer.resize(ngroups, Gid::ROOT); + return Ok(buffer); + } + buffer.reserve(1); // use `Vec` reallocation strategy to grow capacity exponentially + buffer.resize(buffer.capacity(), Gid::ROOT); + } +} + +// Return the raw value of the IDs. In case of `None` it returns `u32::MAX` +// since it has the same bit pattern as `-1` indicating no change to the +// owner/group ID. +pub(crate) fn translate_fchown_args(owner: Option<Uid>, group: Option<Gid>) -> (u32, u32) { + let ow = match owner { + Some(o) => o.as_raw(), + None => u32::MAX, + }; + + let gr = match group { + Some(g) => g.as_raw(), + None => u32::MAX, + }; + + (ow, gr) +} diff --git a/vendor/rustix-0.37.22/src/process/ioctl.rs b/vendor/rustix-0.37.22/src/process/ioctl.rs new file mode 100644 index 000000000..46dbbc59b --- /dev/null +++ b/vendor/rustix-0.37.22/src/process/ioctl.rs @@ -0,0 +1,21 @@ +use crate::{backend, io}; +use backend::fd::AsFd; + +/// `ioctl(fd, TIOCSCTTY, 0)`—Sets the controlling terminal for the processs. +/// +/// # References +/// - [Linux] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// +/// [Linux]: https://man7.org/linux/man-pages/man4/tty_ioctl.4.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=tty&sektion=4 +/// [NetBSD]: https://man.netbsd.org/tty.4 +/// [OpenBSD]: https://man.openbsd.org/tty.4 +#[cfg(not(any(windows, target_os = "haiku", target_os = "redox", target_os = "wasi")))] +#[inline] +#[doc(alias = "TIOCSCTTY")] +pub fn ioctl_tiocsctty<Fd: AsFd>(fd: Fd) -> io::Result<()> { + backend::process::syscalls::ioctl_tiocsctty(fd.as_fd()) +} diff --git a/vendor/rustix-0.37.22/src/process/kill.rs b/vendor/rustix-0.37.22/src/process/kill.rs new file mode 100644 index 000000000..807cc1028 --- /dev/null +++ b/vendor/rustix-0.37.22/src/process/kill.rs @@ -0,0 +1,97 @@ +use crate::process::Pid; +use crate::{backend, io}; + +pub use backend::process::types::Signal; + +/// `kill(pid, sig)`—Sends a signal to a process. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/kill.html +/// [Linux]: https://man7.org/linux/man-pages/man2/kill.2.html +#[inline] +#[doc(alias = "kill")] +pub fn kill_process(pid: Pid, sig: Signal) -> io::Result<()> { + backend::process::syscalls::kill_process(pid, sig) +} + +/// `kill(-pid, sig)`—Sends a signal to all processes in a process group. +/// +/// If `pid` is 1, this sends a signal to all processes the current process +/// has permission to send signals to, except process `1`, possibly other +/// system-specific processes, and on some systems, the current process. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/kill.html +/// [Linux]: https://man7.org/linux/man-pages/man2/kill.2.html +#[inline] +#[doc(alias = "kill")] +pub fn kill_process_group(pid: Pid, sig: Signal) -> io::Result<()> { + backend::process::syscalls::kill_process_group(pid, sig) +} + +/// `kill(0, sig)`—Sends a signal to all processes in the current process +/// group. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/kill.html +/// [Linux]: https://man7.org/linux/man-pages/man2/kill.2.html +#[inline] +#[doc(alias = "kill")] +pub fn kill_current_process_group(sig: Signal) -> io::Result<()> { + backend::process::syscalls::kill_current_process_group(sig) +} + +/// `kill(pid, 0)`—Check validity of pid and permissions to send signals to +/// the process, without actually sending any signals. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/kill.html +/// [Linux]: https://man7.org/linux/man-pages/man2/kill.2.html +#[inline] +#[doc(alias = "kill")] +pub fn test_kill_process(pid: Pid) -> io::Result<()> { + backend::process::syscalls::test_kill_process(pid) +} + +/// `kill(-pid, 0)`—Check validity of pid and permissions to send signals to +/// all processes in the process group, without actually sending any signals. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/kill.html +/// [Linux]: https://man7.org/linux/man-pages/man2/kill.2.html +#[inline] +#[doc(alias = "kill")] +pub fn test_kill_process_group(pid: Pid) -> io::Result<()> { + backend::process::syscalls::test_kill_process_group(pid) +} + +/// `kill(0, 0)`—Check validity of pid and permissions to send signals to the +/// all processes in the current process group, without actually sending any +/// signals. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/kill.html +/// [Linux]: https://man7.org/linux/man-pages/man2/kill.2.html +#[inline] +#[doc(alias = "kill")] +pub fn test_kill_current_process_group() -> io::Result<()> { + backend::process::syscalls::test_kill_current_process_group() +} diff --git a/vendor/rustix-0.37.22/src/process/membarrier.rs b/vendor/rustix-0.37.22/src/process/membarrier.rs new file mode 100644 index 000000000..1594ba1c2 --- /dev/null +++ b/vendor/rustix-0.37.22/src/process/membarrier.rs @@ -0,0 +1,93 @@ +//! The Linux `membarrier` syscall. +//! +//! # Safety +//! +//! This file defines an enum and a bitflags type that represent the same +//! set of values and are kept in sync. +#![allow(unsafe_code)] + +use crate::process::Cpuid; +use crate::{backend, io}; + +pub use backend::process::types::MembarrierCommand; + +#[cfg(linux_kernel)] +bitflags::bitflags! { + /// A result from [`membarrier_query`]. + /// + /// These flags correspond to values of [`MembarrierCommand`] which are + /// supported in the OS. + pub struct MembarrierQuery: u32 { + /// `MEMBARRIER_CMD_GLOBAL` (also known as `MEMBARRIER_CMD_SHARED`) + #[doc(alias = "SHARED")] + #[doc(alias = "MEMBARRIER_CMD_SHARED")] + const GLOBAL = MembarrierCommand::Global as _; + /// `MEMBARRIER_CMD_GLOBAL_EXPEDITED` + const GLOBAL_EXPEDITED = MembarrierCommand::GlobalExpedited as _; + /// `MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED` + const REGISTER_GLOBAL_EXPEDITED = MembarrierCommand::RegisterGlobalExpedited as _; + /// `MEMBARRIER_CMD_PRIVATE_EXPEDITED` + const PRIVATE_EXPEDITED = MembarrierCommand::PrivateExpedited as _; + /// `MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED` + const REGISTER_PRIVATE_EXPEDITED = MembarrierCommand::RegisterPrivateExpedited as _; + /// `MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE` + const PRIVATE_EXPEDITED_SYNC_CORE = MembarrierCommand::PrivateExpeditedSyncCore as _; + /// `MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE` + const REGISTER_PRIVATE_EXPEDITED_SYNC_CORE = MembarrierCommand::RegisterPrivateExpeditedSyncCore as _; + /// `MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ` (since Linux 5.10) + const PRIVATE_EXPEDITED_RSEQ = MembarrierCommand::PrivateExpeditedRseq as _; + /// `MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ` (since Linux 5.10) + const REGISTER_PRIVATE_EXPEDITED_RSEQ = MembarrierCommand::RegisterPrivateExpeditedRseq as _; + } +} + +#[cfg(linux_kernel)] +impl MembarrierQuery { + /// Test whether this query result contains the given command. + #[inline] + pub fn contains_command(self, cmd: MembarrierCommand) -> bool { + // SAFETY: `MembarrierCommand` is an enum that only contains values + // also valid in `MembarrierQuery`. + self.contains(unsafe { Self::from_bits_unchecked(cmd as _) }) + } +} + +/// `membarrier(MEMBARRIER_CMD_QUERY, 0, 0)`—Query the supported `membarrier` +/// commands. +/// +/// This function doesn't return a `Result` because it always succeeds; if +/// the underlying OS doesn't support the `membarrier` syscall, it returns +/// an empty `MembarrierQuery` value. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/membarrier.2.html +#[inline] +#[doc(alias = "MEMBARRIER_CMD_QUERY")] +pub fn membarrier_query() -> MembarrierQuery { + backend::process::syscalls::membarrier_query() +} + +/// `membarrier(cmd, 0, 0)`—Perform a memory barrier. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/membarrier.2.html +#[inline] +pub fn membarrier(cmd: MembarrierCommand) -> io::Result<()> { + backend::process::syscalls::membarrier(cmd) +} + +/// `membarrier(cmd, MEMBARRIER_CMD_FLAG_CPU, cpu)`—Perform a memory barrier +/// with a specific CPU. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/membarrier.2.html +#[inline] +pub fn membarrier_cpu(cmd: MembarrierCommand, cpu: Cpuid) -> io::Result<()> { + backend::process::syscalls::membarrier_cpu(cmd, cpu) +} diff --git a/vendor/rustix-0.37.22/src/process/mod.rs b/vendor/rustix-0.37.22/src/process/mod.rs new file mode 100644 index 000000000..35999b454 --- /dev/null +++ b/vendor/rustix-0.37.22/src/process/mod.rs @@ -0,0 +1,69 @@ +//! Process-associated operations. + +#[cfg(not(target_os = "wasi"))] +mod chdir; +#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))] +mod chroot; +mod exit; +#[cfg(not(target_os = "wasi"))] // WASI doesn't have get[gpu]id. +mod id; +mod ioctl; +#[cfg(not(target_os = "wasi"))] +mod kill; +#[cfg(linux_kernel)] +mod membarrier; +#[cfg(target_os = "linux")] +mod pidfd; +#[cfg(linux_kernel)] +mod prctl; +#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))] // WASI doesn't have [gs]etpriority. +mod priority; +#[cfg(target_os = "freebsd")] +mod procctl; +#[cfg(not(any(target_os = "fuchsia", target_os = "redox", target_os = "wasi")))] +mod rlimit; +#[cfg(any(linux_kernel, target_os = "dragonfly", target_os = "fuchsia"))] +mod sched; +mod sched_yield; +#[cfg(not(target_os = "wasi"))] // WASI doesn't have uname. +mod system; +#[cfg(not(target_os = "wasi"))] // WASI doesn't have umask. +mod umask; +#[cfg(not(target_os = "wasi"))] +mod wait; + +#[cfg(not(target_os = "wasi"))] +pub use chdir::*; +#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))] +pub use chroot::*; +pub use exit::*; +#[cfg(not(target_os = "wasi"))] +pub use id::*; +pub use ioctl::*; +#[cfg(not(target_os = "wasi"))] +pub use kill::*; +#[cfg(linux_kernel)] +pub use membarrier::*; +#[cfg(target_os = "linux")] +pub use pidfd::*; +#[cfg(linux_kernel)] +pub use prctl::*; +#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))] +pub use priority::*; +#[cfg(target_os = "freebsd")] +pub use procctl::*; +#[cfg(not(any(target_os = "fuchsia", target_os = "redox", target_os = "wasi")))] +pub use rlimit::*; +#[cfg(any(linux_kernel, target_os = "dragonfly", target_os = "fuchsia"))] +pub use sched::*; +pub use sched_yield::sched_yield; +#[cfg(not(target_os = "wasi"))] +pub use system::*; +#[cfg(not(target_os = "wasi"))] +pub use umask::*; +#[cfg(not(target_os = "wasi"))] +pub use wait::*; + +#[cfg(not(target_os = "wasi"))] +#[cfg(feature = "fs")] +pub(crate) use id::translate_fchown_args; diff --git a/vendor/rustix-0.37.22/src/process/pidfd.rs b/vendor/rustix-0.37.22/src/process/pidfd.rs new file mode 100644 index 000000000..c9ddb591f --- /dev/null +++ b/vendor/rustix-0.37.22/src/process/pidfd.rs @@ -0,0 +1,25 @@ +use crate::fd::OwnedFd; +use crate::process::Pid; +use crate::{backend, io}; + +bitflags::bitflags! { + /// `PIDFD_*` flags for use with [`pidfd_open`]. + /// + /// [`pidfd_open`]: crate::process::pidfd_open + pub struct PidfdFlags: backend::c::c_uint { + /// `PIDFD_NONBLOCK`. + const NONBLOCK = backend::c::PIDFD_NONBLOCK; + } +} + +/// `syscall(SYS_pidfd_open, pid, flags)`—Creates a file descriptor for +/// a process. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/pidfd_open.2.html +#[inline] +pub fn pidfd_open(pid: Pid, flags: PidfdFlags) -> io::Result<OwnedFd> { + backend::process::syscalls::pidfd_open(pid, flags) +} diff --git a/vendor/rustix-0.37.22/src/process/prctl.rs b/vendor/rustix-0.37.22/src/process/prctl.rs new file mode 100644 index 000000000..14674b9e3 --- /dev/null +++ b/vendor/rustix-0.37.22/src/process/prctl.rs @@ -0,0 +1,1191 @@ +//! Bindings for the Linux `prctl` system call. +//! +//! There are similarities (but also differences) with FreeBSD's `procctl` +//! system call, whose interface is located in the `procctl.rs` file. + +#![allow(unsafe_code)] + +use core::convert::{TryFrom, TryInto}; +use core::mem::{size_of, MaybeUninit}; +use core::ptr::{null, null_mut, NonNull}; + +use bitflags::bitflags; + +use crate::backend::c::{c_int, c_uint, c_void}; +use crate::backend::process::syscalls; +use crate::backend::process::types::Signal; +use crate::fd::{AsRawFd, BorrowedFd}; +use crate::ffi::CStr; +use crate::io; +use crate::process::{Pid, RawPid}; +use crate::utils::{as_mut_ptr, as_ptr}; + +// +// Helper functions. +// + +#[inline] +pub(crate) unsafe fn prctl_1arg(option: c_int) -> io::Result<c_int> { + const NULL: *mut c_void = null_mut(); + syscalls::prctl(option, NULL, NULL, NULL, NULL) +} + +#[inline] +pub(crate) unsafe fn prctl_2args(option: c_int, arg2: *mut c_void) -> io::Result<c_int> { + const NULL: *mut c_void = null_mut(); + syscalls::prctl(option, arg2, NULL, NULL, NULL) +} + +#[inline] +pub(crate) unsafe fn prctl_3args( + option: c_int, + arg2: *mut c_void, + arg3: *mut c_void, +) -> io::Result<c_int> { + syscalls::prctl(option, arg2, arg3, null_mut(), null_mut()) +} + +#[inline] +pub(crate) unsafe fn prctl_get_at_arg2_optional<P>(option: i32) -> io::Result<P> { + let mut value: MaybeUninit<P> = MaybeUninit::uninit(); + prctl_2args(option, value.as_mut_ptr().cast())?; + Ok(value.assume_init()) +} + +#[inline] +pub(crate) unsafe fn prctl_get_at_arg2<P, T>(option: i32) -> io::Result<T> +where + P: Default, + T: TryFrom<P, Error = io::Errno>, +{ + let mut value: P = Default::default(); + prctl_2args(option, as_mut_ptr(&mut value).cast())?; + TryFrom::try_from(value) +} + +// +// PR_GET_PDEATHSIG/PR_SET_PDEATHSIG +// + +const PR_GET_PDEATHSIG: c_int = 2; + +/// Get the current value of the parent process death signal. +/// +/// # References +/// - [Linux: `prctl(PR_GET_PDEATHSIG,...)`] +/// - [FreeBSD: `procctl(PROC_PDEATHSIG_STATUS,...)`] +/// +/// [Linux: `prctl(PR_GET_PDEATHSIG,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +/// [FreeBSD: `procctl(PROC_PDEATHSIG_STATUS,...)`]: https://man.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 +#[inline] +#[doc(alias = "PR_GET_PDEATHSIG")] +pub fn parent_process_death_signal() -> io::Result<Option<Signal>> { + unsafe { prctl_get_at_arg2_optional::<c_int>(PR_GET_PDEATHSIG) }.map(Signal::from_raw) +} + +const PR_SET_PDEATHSIG: c_int = 1; + +/// Set the parent-death signal of the calling process. +/// +/// # References +/// - [Linux: `prctl(PR_SET_PDEATHSIG,...)`] +/// - [FreeBSD: `procctl(PROC_PDEATHSIG_CTL,...)`] +/// +/// [Linux: `prctl(PR_SET_PDEATHSIG,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +/// [FreeBSD: `procctl(PROC_PDEATHSIG_CTL,...)`]: https://man.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 +#[inline] +#[doc(alias = "PR_SET_PDEATHSIG")] +pub fn set_parent_process_death_signal(signal: Option<Signal>) -> io::Result<()> { + let signal = signal.map_or(0_usize, |signal| signal as usize); + unsafe { prctl_2args(PR_SET_PDEATHSIG, signal as *mut _) }.map(|_r| ()) +} + +// +// PR_GET_DUMPABLE/PR_SET_DUMPABLE +// + +const PR_GET_DUMPABLE: c_int = 3; + +const SUID_DUMP_DISABLE: i32 = 0; +const SUID_DUMP_USER: i32 = 1; +const SUID_DUMP_ROOT: i32 = 2; + +/// `SUID_DUMP_*` values for use with [`dumpable_behavior`] and +/// [`set_dumpable_behavior`]. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[repr(i32)] +pub enum DumpableBehavior { + /// Not dumpable. + #[doc(alias = "SUID_DUMP_DISABLE")] + NotDumpable = SUID_DUMP_DISABLE, + /// Dumpable. + #[doc(alias = "SUID_DUMP_USER")] + Dumpable = SUID_DUMP_USER, + /// Dumpable but only readable by root. + #[doc(alias = "SUID_DUMP_ROOT")] + DumpableReadableOnlyByRoot = SUID_DUMP_ROOT, +} + +impl TryFrom<i32> for DumpableBehavior { + type Error = io::Errno; + + fn try_from(value: i32) -> Result<Self, Self::Error> { + match value { + SUID_DUMP_DISABLE => Ok(Self::NotDumpable), + SUID_DUMP_USER => Ok(Self::Dumpable), + SUID_DUMP_ROOT => Ok(Self::DumpableReadableOnlyByRoot), + _ => Err(io::Errno::RANGE), + } + } +} + +/// Get the current state of the calling process's `dumpable` attribute. +/// +/// # References +/// - [`prctl(PR_GET_DUMPABLE,...)`] +/// +/// [`prctl(PR_GET_DUMPABLE,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +#[doc(alias = "PR_GET_DUMPABLE")] +pub fn dumpable_behavior() -> io::Result<DumpableBehavior> { + unsafe { prctl_1arg(PR_GET_DUMPABLE) }.and_then(TryInto::try_into) +} + +const PR_SET_DUMPABLE: c_int = 4; + +/// Set the state of the `dumpable` attribute, which determines whether the +/// process can be traced and whether core dumps are produced for the calling +/// process upon delivery of a signal whose default behavior is to produce a +/// core dump. +/// +/// A similar function with the same name is available on FreeBSD (as part of +/// the `procctl` interface), but it has an extra argument which allows to +/// select a process other then the current process. +/// +/// # References +/// - [`prctl(PR_SET_DUMPABLE,...)`] +/// +/// [`prctl(PR_SET_DUMPABLE,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +#[doc(alias = "PR_SET_DUMPABLE")] +pub fn set_dumpable_behavior(config: DumpableBehavior) -> io::Result<()> { + unsafe { prctl_2args(PR_SET_DUMPABLE, config as usize as *mut _) }.map(|_r| ()) +} + +// +// PR_GET_UNALIGN/PR_SET_UNALIGN +// + +const PR_GET_UNALIGN: c_int = 5; + +bitflags! { + /// `PR_UNALIGN_*` flags for use with [`unaligned_access_control`] and + pub struct UnalignedAccessControl: u32 { + /// Silently fix up unaligned user accesses. + #[doc(alias = "NOPRINT")] + #[doc(alias = "PR_UNALIGN_NOPRINT")] + const NO_PRINT = 1; + /// Generate a [`Signal::Bus`] signal on unaligned user access. + #[doc(alias = "PR_UNALIGN_SIGBUS")] + const SIGBUS = 2; + } +} + +/// Get unaligned access control bits. +/// +/// # References +/// - [`prctl(PR_GET_UNALIGN,...)`] +/// +/// [`prctl(PR_GET_UNALIGN,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +#[doc(alias = "PR_GET_UNALIGN")] +pub fn unaligned_access_control() -> io::Result<UnalignedAccessControl> { + let r = unsafe { prctl_get_at_arg2_optional::<c_uint>(PR_GET_UNALIGN)? }; + UnalignedAccessControl::from_bits(r).ok_or(io::Errno::RANGE) +} + +const PR_SET_UNALIGN: c_int = 6; + +/// Set unaligned access control bits. +/// +/// # References +/// - [`prctl(PR_SET_UNALIGN,...)`] +/// +/// [`prctl(PR_SET_UNALIGN,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +#[doc(alias = "PR_SET_UNALIGN")] +pub fn set_unaligned_access_control(config: UnalignedAccessControl) -> io::Result<()> { + unsafe { prctl_2args(PR_SET_UNALIGN, config.bits() as usize as *mut _) }.map(|_r| ()) +} + +// +// PR_GET_FPEMU/PR_SET_FPEMU +// + +const PR_GET_FPEMU: c_int = 9; + +bitflags! { + /// `PR_FPEMU_*` flags for use with [`floating_point_emulation_control`] + /// and [`set_floating_point_emulation_control`]. + pub struct FloatingPointEmulationControl: u32 { + /// Silently emulate floating point operations accesses. + #[doc(alias = "PR_UNALIGN_NOPRINT")] + const NO_PRINT = 1; + /// Don't emulate floating point operations, send a [`Signal::Fpe`] + /// signal instead. + #[doc(alias = "PR_UNALIGN_SIGFPE")] + const SIGFPE = 2; + } +} + +/// Get floating point emulation control bits. +/// +/// # References +/// - [`prctl(PR_GET_FPEMU,...)`] +/// +/// [`prctl(PR_GET_FPEMU,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +#[doc(alias = "PR_GET_FPEMU")] +pub fn floating_point_emulation_control() -> io::Result<FloatingPointEmulationControl> { + let r = unsafe { prctl_get_at_arg2_optional::<c_uint>(PR_GET_FPEMU)? }; + FloatingPointEmulationControl::from_bits(r).ok_or(io::Errno::RANGE) +} + +const PR_SET_FPEMU: c_int = 10; + +/// Set floating point emulation control bits. +/// +/// # References +/// - [`prctl(PR_SET_FPEMU,...)`] +/// +/// [`prctl(PR_SET_FPEMU,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +#[doc(alias = "PR_SET_FPEMU")] +pub fn set_floating_point_emulation_control( + config: FloatingPointEmulationControl, +) -> io::Result<()> { + unsafe { prctl_2args(PR_SET_FPEMU, config.bits() as usize as *mut _) }.map(|_r| ()) +} + +// +// PR_GET_FPEXC/PR_SET_FPEXC +// + +const PR_GET_FPEXC: c_int = 11; + +bitflags! { + /// Zero means floating point exceptions are disabled. + pub struct FloatingPointExceptionMode: u32 { + /// Async non-recoverable exception mode. + const NONRECOV = 1; + /// Async recoverable exception mode. + const ASYNC = 2; + /// Precise exception mode. + const PRECISE = 3; + + /// Use FPEXC for floating point exception enables. + const SW_ENABLE = 0x80; + /// Floating point divide by zero. + const DIV = 0x01_0000; + /// Floating point overflow. + const OVF = 0x02_0000; + /// Floating point underflow. + const UND = 0x04_0000; + /// Floating point inexact result. + const RES = 0x08_0000; + /// Floating point invalid operation. + const INV = 0x10_0000; + } +} + +/// Get floating point exception mode. +/// +/// # References +/// - [`prctl(PR_GET_FPEXC,...)`] +/// +/// [`prctl(PR_GET_FPEXC,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +#[doc(alias = "PR_GET_FPEXEC")] +pub fn floating_point_exception_mode() -> io::Result<Option<FloatingPointExceptionMode>> { + unsafe { prctl_get_at_arg2_optional::<c_uint>(PR_GET_FPEXC) } + .map(FloatingPointExceptionMode::from_bits) +} + +const PR_SET_FPEXC: c_int = 12; + +/// Set floating point exception mode. +/// +/// # References +/// - [`prctl(PR_SET_FPEXC,...)`] +/// +/// [`prctl(PR_SET_FPEXC,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +#[doc(alias = "PR_SET_FPEXEC")] +pub fn set_floating_point_exception_mode( + config: Option<FloatingPointExceptionMode>, +) -> io::Result<()> { + let config = config.as_ref().map_or(0, FloatingPointExceptionMode::bits); + unsafe { prctl_2args(PR_SET_FPEXC, config as usize as *mut _) }.map(|_r| ()) +} + +// +// PR_GET_TIMING/PR_SET_TIMING +// + +const PR_GET_TIMING: c_int = 13; + +const PR_TIMING_STATISTICAL: i32 = 0; +const PR_TIMING_TIMESTAMP: i32 = 1; + +/// `PR_TIMING_*` values for use with [`timing_method`] and +/// [`set_timing_method`]. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[repr(i32)] +pub enum TimingMethod { + /// Normal, traditional, statistical process timing. + Statistical = PR_TIMING_STATISTICAL, + /// Accurate timestamp based process timing. + TimeStamp = PR_TIMING_TIMESTAMP, +} + +impl TryFrom<i32> for TimingMethod { + type Error = io::Errno; + + fn try_from(value: i32) -> Result<Self, Self::Error> { + match value { + PR_TIMING_STATISTICAL => Ok(Self::Statistical), + PR_TIMING_TIMESTAMP => Ok(Self::TimeStamp), + _ => Err(io::Errno::RANGE), + } + } +} + +/// Get which process timing method is currently in use. +/// +/// # References +/// - [`prctl(PR_GET_TIMING,...)`] +/// +/// [`prctl(PR_GET_TIMING,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +#[doc(alias = "PR_GET_TIMING")] +pub fn timing_method() -> io::Result<TimingMethod> { + unsafe { prctl_1arg(PR_GET_TIMING) }.and_then(TryInto::try_into) +} + +const PR_SET_TIMING: c_int = 14; + +/// Set whether to use (normal, traditional) statistical process timing or +/// accurate timestamp-based process timing. +/// +/// # References +/// - [`prctl(PR_SET_TIMING,...)`] +/// +/// [`prctl(PR_SET_TIMING,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +#[doc(alias = "PR_SET_TIMING")] +pub fn set_timing_method(method: TimingMethod) -> io::Result<()> { + unsafe { prctl_2args(PR_SET_TIMING, method as usize as *mut _) }.map(|_r| ()) +} + +// +// PR_GET_ENDIAN/PR_SET_ENDIAN +// + +const PR_GET_ENDIAN: c_int = 19; + +const PR_ENDIAN_BIG: u32 = 0; +const PR_ENDIAN_LITTLE: u32 = 1; +const PR_ENDIAN_PPC_LITTLE: u32 = 2; + +/// `PR_ENDIAN_*` values for use with [`endian_mode`]. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[repr(u32)] +pub enum EndianMode { + /// Big endian mode. + Big = PR_ENDIAN_BIG, + /// True little endian mode. + Little = PR_ENDIAN_LITTLE, + /// `PowerPC` pseudo little endian. + PowerPCLittle = PR_ENDIAN_PPC_LITTLE, +} + +impl TryFrom<u32> for EndianMode { + type Error = io::Errno; + + fn try_from(value: u32) -> Result<Self, Self::Error> { + match value { + PR_ENDIAN_BIG => Ok(Self::Big), + PR_ENDIAN_LITTLE => Ok(Self::Little), + PR_ENDIAN_PPC_LITTLE => Ok(Self::PowerPCLittle), + _ => Err(io::Errno::RANGE), + } + } +} + +/// Get the endianness of the calling process. +/// +/// # References +/// - [`prctl(PR_GET_ENDIAN,...)`] +/// +/// [`prctl(PR_GET_ENDIAN,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +#[doc(alias = "PR_GET_ENDIAN")] +pub fn endian_mode() -> io::Result<EndianMode> { + unsafe { prctl_get_at_arg2::<c_uint, _>(PR_GET_ENDIAN) } +} + +const PR_SET_ENDIAN: c_int = 20; + +/// Set the endianness of the calling process. +/// +/// # References +/// - [`prctl(PR_SET_ENDIAN,...)`] +/// +/// # Safety +/// +/// Please ensure the conditions necessary to safely call this function, +/// as detailed in the references above. +/// +/// [`prctl(PR_SET_ENDIAN,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +#[doc(alias = "PR_SET_ENDIAN")] +pub unsafe fn set_endian_mode(mode: EndianMode) -> io::Result<()> { + prctl_2args(PR_SET_ENDIAN, mode as usize as *mut _).map(|_r| ()) +} + +// +// PR_GET_TSC/PR_SET_TSC +// + +const PR_GET_TSC: c_int = 25; + +const PR_TSC_ENABLE: u32 = 1; +const PR_TSC_SIGSEGV: u32 = 2; + +/// `PR_TSC_*` values for use with [`time_stamp_counter_readability`] and +/// [`set_time_stamp_counter_readability`]. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[repr(u32)] +pub enum TimeStampCounterReadability { + /// Allow the use of the timestamp counter. + Readable = PR_TSC_ENABLE, + /// Throw a [`Signal::Segv`] signal instead of reading the TSC. + RaiseSIGSEGV = PR_TSC_SIGSEGV, +} + +impl TryFrom<u32> for TimeStampCounterReadability { + type Error = io::Errno; + + fn try_from(value: u32) -> Result<Self, Self::Error> { + match value { + PR_TSC_ENABLE => Ok(Self::Readable), + PR_TSC_SIGSEGV => Ok(Self::RaiseSIGSEGV), + _ => Err(io::Errno::RANGE), + } + } +} + +/// Get the state of the flag determining if the timestamp counter can be read. +/// +/// # References +/// - [`prctl(PR_GET_TSC,...)`] +/// +/// [`prctl(PR_GET_TSC,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +#[doc(alias = "PR_GET_TSC")] +pub fn time_stamp_counter_readability() -> io::Result<TimeStampCounterReadability> { + unsafe { prctl_get_at_arg2::<c_uint, _>(PR_GET_TSC) } +} + +const PR_SET_TSC: c_int = 26; + +/// Set the state of the flag determining if the timestamp counter can be read +/// by the process. +/// +/// # References +/// - [`prctl(PR_SET_TSC,...)`] +/// +/// [`prctl(PR_SET_TSC,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +#[doc(alias = "PR_SET_TSC")] +pub fn set_time_stamp_counter_readability( + readability: TimeStampCounterReadability, +) -> io::Result<()> { + unsafe { prctl_2args(PR_SET_TSC, readability as usize as *mut _) }.map(|_r| ()) +} + +// +// PR_TASK_PERF_EVENTS_DISABLE/PR_TASK_PERF_EVENTS_ENABLE +// + +const PR_TASK_PERF_EVENTS_DISABLE: c_int = 31; +const PR_TASK_PERF_EVENTS_ENABLE: c_int = 32; + +/// Enable or disable all performance counters attached to the calling process. +/// +/// # References +/// - [`prctl(PR_TASK_PERF_EVENTS_ENABLE,...)`] +/// - [`prctl(PR_TASK_PERF_EVENTS_DISABLE,...)`] +/// +/// [`prctl(PR_TASK_PERF_EVENTS_ENABLE,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +/// [`prctl(PR_TASK_PERF_EVENTS_DISABLE,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +#[doc(alias = "PR_TASK_PERF_EVENTS_ENABLE")] +#[doc(alias = "PR_TASK_PERF_EVENTS_DISABLE")] +pub fn configure_performance_counters(enable: bool) -> io::Result<()> { + let option = if enable { + PR_TASK_PERF_EVENTS_ENABLE + } else { + PR_TASK_PERF_EVENTS_DISABLE + }; + + unsafe { prctl_1arg(option) }.map(|_r| ()) +} + +// +// PR_MCE_KILL_GET/PR_MCE_KILL +// + +const PR_MCE_KILL_GET: c_int = 34; + +const PR_MCE_KILL_LATE: u32 = 0; +const PR_MCE_KILL_EARLY: u32 = 1; +const PR_MCE_KILL_DEFAULT: u32 = 2; + +/// `PR_MCE_KILL_*` values for use with +/// [`machine_check_memory_corruption_kill_policy`] and +/// [`set_machine_check_memory_corruption_kill_policy`]. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[repr(u32)] +pub enum MachineCheckMemoryCorruptionKillPolicy { + /// Late kill policy. + #[doc(alias = "PR_MCE_KILL_LATE")] + Late = PR_MCE_KILL_LATE, + /// Early kill policy. + #[doc(alias = "PR_MCE_KILL_EARLY")] + Early = PR_MCE_KILL_EARLY, + /// System-wide default policy. + #[doc(alias = "PR_MCE_KILL_DEFAULT")] + Default = PR_MCE_KILL_DEFAULT, +} + +impl TryFrom<u32> for MachineCheckMemoryCorruptionKillPolicy { + type Error = io::Errno; + + fn try_from(value: u32) -> Result<Self, Self::Error> { + match value { + PR_MCE_KILL_LATE => Ok(Self::Late), + PR_MCE_KILL_EARLY => Ok(Self::Early), + PR_MCE_KILL_DEFAULT => Ok(Self::Default), + _ => Err(io::Errno::RANGE), + } + } +} + +/// Get the current per-process machine check kill policy. +/// +/// # References +/// - [`prctl(PR_MCE_KILL_GET,...)`] +/// +/// [`prctl(PR_MCE_KILL_GET,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +#[doc(alias = "PR_MCE_KILL_GET")] +pub fn machine_check_memory_corruption_kill_policy( +) -> io::Result<MachineCheckMemoryCorruptionKillPolicy> { + let r = unsafe { prctl_1arg(PR_MCE_KILL_GET)? } as c_uint; + MachineCheckMemoryCorruptionKillPolicy::try_from(r) +} + +const PR_MCE_KILL: c_int = 33; + +const PR_MCE_KILL_CLEAR: usize = 0; +const PR_MCE_KILL_SET: usize = 1; + +/// Set the machine check memory corruption kill policy for the calling thread. +/// +/// # References +/// - [`prctl(PR_MCE_KILL,...)`] +/// +/// [`prctl(PR_MCE_KILL,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +#[doc(alias = "PR_MCE_KILL")] +pub fn set_machine_check_memory_corruption_kill_policy( + policy: Option<MachineCheckMemoryCorruptionKillPolicy>, +) -> io::Result<()> { + let (sub_operation, policy) = if let Some(policy) = policy { + (PR_MCE_KILL_SET, policy as usize as *mut _) + } else { + (PR_MCE_KILL_CLEAR, null_mut()) + }; + + unsafe { prctl_3args(PR_MCE_KILL, sub_operation as *mut _, policy) }.map(|_r| ()) +} + +// +// PR_SET_MM +// + +const PR_SET_MM: c_int = 35; + +const PR_SET_MM_START_CODE: u32 = 1; +const PR_SET_MM_END_CODE: u32 = 2; +const PR_SET_MM_START_DATA: u32 = 3; +const PR_SET_MM_END_DATA: u32 = 4; +const PR_SET_MM_START_STACK: u32 = 5; +const PR_SET_MM_START_BRK: u32 = 6; +const PR_SET_MM_BRK: u32 = 7; +const PR_SET_MM_ARG_START: u32 = 8; +const PR_SET_MM_ARG_END: u32 = 9; +const PR_SET_MM_ENV_START: u32 = 10; +const PR_SET_MM_ENV_END: u32 = 11; +const PR_SET_MM_AUXV: usize = 12; +const PR_SET_MM_EXE_FILE: usize = 13; +const PR_SET_MM_MAP: usize = 14; +const PR_SET_MM_MAP_SIZE: usize = 15; + +/// `PR_SET_MM_*` values for use with [`set_virtual_memory_map_address`]. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[repr(u32)] +pub enum VirtualMemoryMapAddress { + /// Set the address above which the program text can run. + CodeStart = PR_SET_MM_START_CODE, + /// Set the address below which the program text can run. + CodeEnd = PR_SET_MM_END_CODE, + /// Set the address above which initialized and uninitialized (bss) data + /// are placed. + DataStart = PR_SET_MM_START_DATA, + /// Set the address below which initialized and uninitialized (bss) data + /// are placed. + DataEnd = PR_SET_MM_END_DATA, + /// Set the start address of the stack. + StackStart = PR_SET_MM_START_STACK, + /// Set the address above which the program heap can be expanded with `brk` + /// call. + BrkStart = PR_SET_MM_START_BRK, + /// Set the current `brk` value. + BrkCurrent = PR_SET_MM_BRK, + /// Set the address above which the program command line is placed. + ArgStart = PR_SET_MM_ARG_START, + /// Set the address below which the program command line is placed. + ArgEnd = PR_SET_MM_ARG_END, + /// Set the address above which the program environment is placed. + EnvironmentStart = PR_SET_MM_ENV_START, + /// Set the address below which the program environment is placed. + EnvironmentEnd = PR_SET_MM_ENV_END, +} + +/// Modify certain kernel memory map descriptor addresses of the calling +/// process. +/// +/// # References +/// - [`prctl(PR_SET_MM,...)`] +/// +/// # Safety +/// +/// Please ensure the conditions necessary to safely call this function, +/// as detailed in the references above. +/// +/// [`prctl(PR_SET_MM,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +#[doc(alias = "PR_SET_MM")] +pub unsafe fn set_virtual_memory_map_address( + option: VirtualMemoryMapAddress, + address: Option<NonNull<c_void>>, +) -> io::Result<()> { + let address = address.map_or_else(null_mut, NonNull::as_ptr); + prctl_3args(PR_SET_MM, option as usize as *mut _, address).map(|_r| ()) +} + +/// Supersede the `/proc/pid/exe` symbolic link with a new one pointing to a +/// new executable file. +/// +/// # References +/// - [`prctl(PR_SET_MM,PR_SET_MM_EXE_FILE,...)`] +/// +/// [`prctl(PR_SET_MM,PR_SET_MM_EXE_FILE,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +#[doc(alias = "PR_SET_MM")] +#[doc(alias = "PR_SET_MM_EXE_FILE")] +pub fn set_executable_file(fd: BorrowedFd) -> io::Result<()> { + let fd = usize::try_from(fd.as_raw_fd()).map_err(|_r| io::Errno::RANGE)?; + unsafe { prctl_3args(PR_SET_MM, PR_SET_MM_EXE_FILE as *mut _, fd as *mut _) }.map(|_r| ()) +} + +/// Set a new auxiliary vector. +/// +/// # References +/// - [`prctl(PR_SET_MM,PR_SET_MM_AUXV,...)`] +/// +/// # Safety +/// +/// Please ensure the conditions necessary to safely call this function, +/// as detailed in the references above. +/// +/// [`prctl(PR_SET_MM,PR_SET_MM_AUXV,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +#[doc(alias = "PR_SET_MM")] +#[doc(alias = "PR_SET_MM_AUXV")] +pub unsafe fn set_auxiliary_vector(auxv: &[*const c_void]) -> io::Result<()> { + syscalls::prctl( + PR_SET_MM, + PR_SET_MM_AUXV as *mut _, + auxv.as_ptr() as *mut _, + auxv.len() as *mut _, + null_mut(), + ) + .map(|_r| ()) +} + +/// Get the size of the [`PrctlMmMap`] the kernel expects. +/// +/// # References +/// - [`prctl(PR_SET_MM,PR_SET_MM_MAP_SIZE,...)`] +/// +/// [`prctl(PR_SET_MM,PR_SET_MM_MAP_SIZE,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +#[doc(alias = "PR_SET_MM")] +#[doc(alias = "PR_SET_MM_MAP_SIZE")] +pub fn virtual_memory_map_config_struct_size() -> io::Result<usize> { + let mut value: c_uint = 0; + let value_ptr = as_mut_ptr(&mut value); + unsafe { prctl_3args(PR_SET_MM, PR_SET_MM_MAP_SIZE as *mut _, value_ptr.cast())? }; + Ok(value as usize) +} + +/// This structure provides new memory descriptor map which mostly modifies +/// `/proc/pid/stat[m]` output for a task. +/// This mostly done in a sake of checkpoint/restore functionality. +#[repr(C)] +#[derive(Debug, Clone)] +pub struct PrctlMmMap { + /// Code section start address. + pub start_code: u64, + /// Code section end address. + pub end_code: u64, + /// Data section start address. + pub start_data: u64, + /// Data section end address. + pub end_data: u64, + /// `brk` start address. + pub start_brk: u64, + /// `brk` current address. + pub brk: u64, + /// Stack start address. + pub start_stack: u64, + /// Program command line start address. + pub arg_start: u64, + /// Program command line end address. + pub arg_end: u64, + /// Program environment start address. + pub env_start: u64, + /// Program environment end address. + pub env_end: u64, + /// Auxiliary vector start address. + pub auxv: *mut u64, + /// Auxiliary vector size. + pub auxv_size: u32, + /// File descriptor of executable file that was used to create this + /// process. + pub exe_fd: u32, +} + +/// Provides one-shot access to all the addresses by passing in a +/// [`PrctlMmMap`]. +/// +/// # References +/// - [`prctl(PR_SET_MM,PR_SET_MM_MAP,...)`] +/// +/// # Safety +/// +/// Please ensure the conditions necessary to safely call this function, +/// as detailed in the references above. +/// +/// [`prctl(PR_SET_MM,PR_SET_MM_MAP,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +#[doc(alias = "PR_SET_MM")] +#[doc(alias = "PR_SET_MM_MAP")] +pub unsafe fn configure_virtual_memory_map(config: &PrctlMmMap) -> io::Result<()> { + syscalls::prctl( + PR_SET_MM, + PR_SET_MM_MAP as *mut _, + as_ptr(config) as *mut _, + size_of::<PrctlMmMap>() as *mut _, + null_mut(), + ) + .map(|_r| ()) +} + +// +// PR_SET_PTRACER +// + +const PR_SET_PTRACER: c_int = 0x59_61_6d_61; + +const PR_SET_PTRACER_ANY: usize = usize::MAX; + +/// Process ptracer. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum PTracer { + /// None. + None, + /// Disable `ptrace` restrictions for the calling process. + Any, + /// Specific process. + ProcessID(Pid), +} + +/// Declare that the ptracer process can `ptrace` the calling process as if it +/// were a direct process ancestor. +/// +/// # References +/// - [`prctl(PR_SET_PTRACER,...)`] +/// +/// [`prctl(PR_SET_PTRACER,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +#[doc(alias = "PR_SET_PTRACER")] +pub fn set_ptracer(tracer: PTracer) -> io::Result<()> { + let pid = match tracer { + PTracer::None => null_mut(), + PTracer::Any => PR_SET_PTRACER_ANY as *mut _, + PTracer::ProcessID(pid) => pid.as_raw_nonzero().get() as usize as *mut _, + }; + + unsafe { prctl_2args(PR_SET_PTRACER, pid) }.map(|_r| ()) +} + +// +// PR_GET_CHILD_SUBREAPER/PR_SET_CHILD_SUBREAPER +// + +const PR_GET_CHILD_SUBREAPER: c_int = 37; + +/// Get the `child subreaper` setting of the calling process. +/// +/// # References +/// - [`prctl(PR_GET_CHILD_SUBREAPER,...)`] +/// +/// [`prctl(PR_GET_CHILD_SUBREAPER,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +#[doc(alias = "PR_GET_CHILD_SUBREAPER")] +pub fn child_subreaper() -> io::Result<Option<Pid>> { + unsafe { + let r = prctl_get_at_arg2_optional::<c_uint>(PR_GET_CHILD_SUBREAPER)?; + Ok(Pid::from_raw(r as RawPid)) + } +} + +const PR_SET_CHILD_SUBREAPER: c_int = 36; + +/// Set the `child subreaper` attribute of the calling process. +/// +/// # References +/// - [`prctl(PR_SET_CHILD_SUBREAPER,...)`] +/// +/// [`prctl(PR_SET_CHILD_SUBREAPER,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +#[doc(alias = "PR_SET_CHILD_SUBREAPER")] +pub fn set_child_subreaper(pid: Option<Pid>) -> io::Result<()> { + let pid = pid.map_or(0_usize, |pid| pid.as_raw_nonzero().get() as usize); + unsafe { prctl_2args(PR_SET_CHILD_SUBREAPER, pid as *mut _) }.map(|_r| ()) +} + +// +// PR_GET_FP_MODE/PR_SET_FP_MODE +// + +const PR_GET_FP_MODE: c_int = 46; + +const PR_FP_MODE_FR: u32 = 1_u32 << 0; +const PR_FP_MODE_FRE: u32 = 1_u32 << 1; + +/// `PR_FP_MODE_*` values for use with [`floating_point_mode`] and +/// [`set_floating_point_mode`]. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[repr(u32)] +pub enum FloatingPointMode { + /// 64-bit floating point registers. + FloatingPointRegisters = PR_FP_MODE_FR, + /// Enable emulation of 32-bit floating-point mode. + FloatingPointEmulation = PR_FP_MODE_FRE, +} + +impl TryFrom<u32> for FloatingPointMode { + type Error = io::Errno; + + fn try_from(value: u32) -> Result<Self, Self::Error> { + match value { + PR_FP_MODE_FR => Ok(Self::FloatingPointRegisters), + PR_FP_MODE_FRE => Ok(Self::FloatingPointEmulation), + _ => Err(io::Errno::RANGE), + } + } +} + +/// Get the current floating point mode. +/// +/// # References +/// - [`prctl(PR_GET_FP_MODE,...)`] +/// +/// [`prctl(PR_GET_FP_MODE,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +#[doc(alias = "PR_GET_FP_MODE")] +pub fn floating_point_mode() -> io::Result<FloatingPointMode> { + let r = unsafe { prctl_1arg(PR_GET_FP_MODE)? } as c_uint; + FloatingPointMode::try_from(r) +} + +const PR_SET_FP_MODE: c_int = 45; + +/// Allow control of the floating point mode from user space. +/// +/// # References +/// - [`prctl(PR_SET_FP_MODE,...)`] +/// +/// [`prctl(PR_SET_FP_MODE,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +#[doc(alias = "PR_SET_FP_MODE")] +pub fn set_floating_point_mode(mode: FloatingPointMode) -> io::Result<()> { + unsafe { prctl_2args(PR_SET_FP_MODE, mode as usize as *mut _) }.map(|_r| ()) +} + +// +// PR_GET_SPECULATION_CTRL/PR_SET_SPECULATION_CTRL +// + +const PR_GET_SPECULATION_CTRL: c_int = 52; + +const PR_SPEC_STORE_BYPASS: u32 = 0; +const PR_SPEC_INDIRECT_BRANCH: u32 = 1; +const PR_SPEC_L1D_FLUSH: u32 = 2; + +/// `PR_SPEC_*` values for use with [`speculative_feature_state`] and +/// [`control_speculative_feature`]. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[repr(u32)] +pub enum SpeculationFeature { + /// Set the state of the speculative store bypass misfeature. + SpeculativeStoreBypass = PR_SPEC_STORE_BYPASS, + /// Set the state of the indirect branch speculation misfeature. + IndirectBranchSpeculation = PR_SPEC_INDIRECT_BRANCH, + /// Flush L1D Cache on context switch out of the task. + FlushL1DCacheOnContextSwitchOutOfTask = PR_SPEC_L1D_FLUSH, +} + +impl TryFrom<u32> for SpeculationFeature { + type Error = io::Errno; + + fn try_from(value: u32) -> Result<Self, Self::Error> { + match value { + PR_SPEC_STORE_BYPASS => Ok(Self::SpeculativeStoreBypass), + PR_SPEC_INDIRECT_BRANCH => Ok(Self::IndirectBranchSpeculation), + PR_SPEC_L1D_FLUSH => Ok(Self::FlushL1DCacheOnContextSwitchOutOfTask), + _ => Err(io::Errno::RANGE), + } + } +} + +bitflags! { + /// `PR_SPEC_*` flags for use with [`control_speculative_feature`]. + pub struct SpeculationFeatureControl: u32 { + /// The speculation feature is enabled, mitigation is disabled. + const ENABLE = 1_u32 << 1; + /// The speculation feature is disabled, mitigation is enabled. + const DISABLE = 1_u32 << 2; + /// The speculation feature is disabled, mitigation is enabled, and it cannot be undone. + const FORCE_DISABLE = 1_u32 << 3; + /// The speculation feature is disabled, mitigation is enabled, and the state will be cleared on `execve`. + const DISABLE_NOEXEC = 1_u32 << 4; + } +} + +bitflags! { + /// Zero means the processors are not vulnerable. + pub struct SpeculationFeatureState: u32 { + /// Mitigation can be controlled per thread by `PR_SET_SPECULATION_CTRL`. + const PRCTL = 1_u32 << 0; + /// The speculation feature is enabled, mitigation is disabled. + const ENABLE = 1_u32 << 1; + /// The speculation feature is disabled, mitigation is enabled. + const DISABLE = 1_u32 << 2; + /// The speculation feature is disabled, mitigation is enabled, and it cannot be undone. + const FORCE_DISABLE = 1_u32 << 3; + /// The speculation feature is disabled, mitigation is enabled, and the state will be cleared on `execve`. + const DISABLE_NOEXEC = 1_u32 << 4; + } +} + +/// Get the state of the speculation misfeature. +/// +/// # References +/// - [`prctl(PR_GET_SPECULATION_CTRL,...)`] +/// +/// [`prctl(PR_GET_SPECULATION_CTRL,...)`]: https://www.kernel.org/doc/html/v5.18/userspace-api/spec_ctrl.html +#[inline] +#[doc(alias = "PR_GET_SPECULATION_CTRL")] +pub fn speculative_feature_state( + feature: SpeculationFeature, +) -> io::Result<Option<SpeculationFeatureState>> { + let r = unsafe { prctl_2args(PR_GET_SPECULATION_CTRL, feature as usize as *mut _)? } as c_uint; + Ok(SpeculationFeatureState::from_bits(r)) +} + +const PR_SET_SPECULATION_CTRL: c_int = 53; + +/// Sets the state of the speculation misfeature. +/// +/// # References +/// - [`prctl(PR_SET_SPECULATION_CTRL,...)`] +/// +/// [`prctl(PR_SET_SPECULATION_CTRL,...)`]: https://www.kernel.org/doc/html/v5.18/userspace-api/spec_ctrl.html +#[inline] +#[doc(alias = "PR_SET_SPECULATION_CTRL")] +pub fn control_speculative_feature( + feature: SpeculationFeature, + config: SpeculationFeatureControl, +) -> io::Result<()> { + let feature = feature as usize as *mut _; + let config = config.bits() as usize as *mut _; + unsafe { prctl_3args(PR_SET_SPECULATION_CTRL, feature, config) }.map(|_r| ()) +} + +// +// PR_GET_IO_FLUSHER/PR_SET_IO_FLUSHER +// + +const PR_GET_IO_FLUSHER: c_int = 58; + +/// Get the `IO_FLUSHER` state of the caller. +/// +/// # References +/// - [`prctl(PR_GET_IO_FLUSHER,...)`] +/// +/// [`prctl(PR_GET_IO_FLUSHER,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +#[doc(alias = "PR_GET_IO_FLUSHER")] +pub fn is_io_flusher() -> io::Result<bool> { + unsafe { prctl_1arg(PR_GET_IO_FLUSHER) }.map(|r| r != 0) +} + +const PR_SET_IO_FLUSHER: c_int = 57; + +/// Put the process in the `IO_FLUSHER` state, allowing it to make progress +/// when allocating memory. +/// +/// # References +/// - [`prctl(PR_SET_IO_FLUSHER,...)`] +/// +/// [`prctl(PR_SET_IO_FLUSHER,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +#[doc(alias = "PR_SET_IO_FLUSHER")] +pub fn configure_io_flusher_behavior(enable: bool) -> io::Result<()> { + unsafe { prctl_2args(PR_SET_IO_FLUSHER, usize::from(enable) as *mut _) }.map(|_r| ()) +} + +// +// PR_PAC_GET_ENABLED_KEYS/PR_PAC_SET_ENABLED_KEYS +// + +const PR_PAC_GET_ENABLED_KEYS: c_int = 61; + +bitflags! { + /// `PR_PAC_AP*`. + pub struct PointerAuthenticationKeys: u32 { + /// Instruction authentication key `A`. + const INSTRUCTION_AUTHENTICATION_KEY_A = 1_u32 << 0; + /// Instruction authentication key `B`. + const INSTRUCTION_AUTHENTICATION_KEY_B = 1_u32 << 1; + /// Data authentication key `A`. + const DATA_AUTHENTICATION_KEY_A = 1_u32 << 2; + /// Data authentication key `B`. + const DATA_AUTHENTICATION_KEY_B = 1_u32 << 3; + /// Generic authentication `A` key. + const GENERIC_AUTHENTICATION_KEY_A = 1_u32 << 4; + } +} + +/// Get enabled pointer authentication keys. +/// +/// # References +/// - [`prctl(PR_PAC_GET_ENABLED_KEYS,...)`] +/// +/// [`prctl(PR_PAC_GET_ENABLED_KEYS,...)`]: https://www.kernel.org/doc/html/v5.18/arm64/pointer-authentication.html +#[inline] +#[doc(alias = "PR_PAC_GET_ENABLED_KEYS")] +pub fn enabled_pointer_authentication_keys() -> io::Result<PointerAuthenticationKeys> { + let r = unsafe { prctl_1arg(PR_PAC_GET_ENABLED_KEYS)? } as c_uint; + PointerAuthenticationKeys::from_bits(r).ok_or(io::Errno::RANGE) +} + +const PR_PAC_SET_ENABLED_KEYS: c_int = 60; + +/// Set enabled pointer authentication keys. +/// +/// # References +/// - [`prctl(PR_PAC_SET_ENABLED_KEYS,...)`] +/// +/// # Safety +/// +/// Please ensure the conditions necessary to safely call this function, +/// as detailed in the references above. +/// +/// [`prctl(PR_PAC_SET_ENABLED_KEYS,...)`]: https://www.kernel.org/doc/html/v5.18/arm64/pointer-authentication.html +#[inline] +#[doc(alias = "PR_PAC_SET_ENABLED_KEYS")] +pub unsafe fn configure_pointer_authentication_keys( + config: impl Iterator<Item = (PointerAuthenticationKeys, bool)>, +) -> io::Result<()> { + let mut affected_keys: u32 = 0; + let mut enabled_keys: u32 = 0; + + for (key, enable) in config { + let key = key.bits(); + affected_keys |= key; + + if enable { + enabled_keys |= key; + } else { + enabled_keys &= !key; + } + } + + if affected_keys == 0 { + return Ok(()); // Nothing to do. + } + + prctl_3args( + PR_PAC_SET_ENABLED_KEYS, + affected_keys as usize as *mut _, + enabled_keys as usize as *mut _, + ) + .map(|_r| ()) +} + +// +// PR_SET_VMA +// + +const PR_SET_VMA: c_int = 0x53_56_4d_41; + +const PR_SET_VMA_ANON_NAME: usize = 0; + +/// Set the name for a virtual memory region. +/// +/// # References +/// - [`prctl(PR_SET_VMA,PR_SET_VMA_ANON_NAME,...)`] +/// +/// [`prctl(PR_SET_VMA,PR_SET_VMA_ANON_NAME,...)`]: https://lwn.net/Articles/867818/ +#[inline] +#[doc(alias = "PR_SET_VMA")] +#[doc(alias = "PR_SET_VMA_ANON_NAME")] +pub fn set_virtual_memory_region_name(region: &[u8], name: Option<&CStr>) -> io::Result<()> { + unsafe { + syscalls::prctl( + PR_SET_VMA, + PR_SET_VMA_ANON_NAME as *mut _, + region.as_ptr() as *mut _, + region.len() as *mut _, + name.map_or_else(null, CStr::as_ptr) as *mut _, + ) + .map(|_r| ()) + } +} diff --git a/vendor/rustix-0.37.22/src/process/priority.rs b/vendor/rustix-0.37.22/src/process/priority.rs new file mode 100644 index 000000000..604614ef0 --- /dev/null +++ b/vendor/rustix-0.37.22/src/process/priority.rs @@ -0,0 +1,125 @@ +use crate::process::{Pid, Uid}; +use crate::{backend, io}; + +/// `nice(inc)`—Adjust the scheduling priority of the current process. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/nice.html +/// [Linux]: https://man7.org/linux/man-pages/man2/nice.2.html +#[inline] +pub fn nice(inc: i32) -> io::Result<i32> { + backend::process::syscalls::nice(inc) +} + +/// `getpriority(PRIO_USER, uid)`—Get the scheduling priority of the given +/// user. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpriority.html +/// [Linux]: https://man7.org/linux/man-pages/man2/getpriority.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setpriority.2.html +#[inline] +#[doc(alias = "getpriority")] +pub fn getpriority_user(uid: Uid) -> io::Result<i32> { + backend::process::syscalls::getpriority_user(uid) +} + +/// `getpriority(PRIO_PGRP, gid)`—Get the scheduling priority of the given +/// process group. +/// +/// A `pgid` of `None` means the process group of the calling process. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpriority.html +/// [Linux]: https://man7.org/linux/man-pages/man2/getpriority.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setpriority.2.html +#[inline] +#[doc(alias = "getpriority")] +pub fn getpriority_pgrp(pgid: Option<Pid>) -> io::Result<i32> { + backend::process::syscalls::getpriority_pgrp(pgid) +} + +/// `getpriority(PRIO_PROCESS, pid)`—Get the scheduling priority of the given +/// process. +/// +/// A `pid` of `None` means the calling process. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpriority.html +/// [Linux]: https://man7.org/linux/man-pages/man2/getpriority.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setpriority.2.html +#[inline] +#[doc(alias = "getpriority")] +pub fn getpriority_process(pid: Option<Pid>) -> io::Result<i32> { + backend::process::syscalls::getpriority_process(pid) +} + +/// `setpriority(PRIO_USER, uid)`—Get the scheduling priority of the given +/// user. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setpriority.html +/// [Linux]: https://man7.org/linux/man-pages/man2/setpriority.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setpriority.2.html +#[inline] +#[doc(alias = "setpriority")] +pub fn setpriority_user(uid: Uid, priority: i32) -> io::Result<()> { + backend::process::syscalls::setpriority_user(uid, priority) +} + +/// `setpriority(PRIO_PGRP, pgid)`—Get the scheduling priority of the given +/// process group. +/// +/// A `pgid` of `None` means the process group of the calling process. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setpriority.html +/// [Linux]: https://man7.org/linux/man-pages/man2/setpriority.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setpriority.2.html +#[inline] +#[doc(alias = "setpriority")] +pub fn setpriority_pgrp(pgid: Option<Pid>, priority: i32) -> io::Result<()> { + backend::process::syscalls::setpriority_pgrp(pgid, priority) +} + +/// `setpriority(PRIO_PROCESS, pid)`—Get the scheduling priority of the given +/// process. +/// +/// A `pid` of `None` means the calling process. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setpriority.html +/// [Linux]: https://man7.org/linux/man-pages/man2/setpriority.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setpriority.2.html +#[inline] +#[doc(alias = "setpriority")] +pub fn setpriority_process(pid: Option<Pid>, priority: i32) -> io::Result<()> { + backend::process::syscalls::setpriority_process(pid, priority) +} diff --git a/vendor/rustix-0.37.22/src/process/procctl.rs b/vendor/rustix-0.37.22/src/process/procctl.rs new file mode 100644 index 000000000..59fe5ebc8 --- /dev/null +++ b/vendor/rustix-0.37.22/src/process/procctl.rs @@ -0,0 +1,518 @@ +//! Bindings for the FreeBSD `procctl` system call. +//! +//! There are similarities (but also differences) with Linux's `prctl` system +//! call, whose interface is located in the `prctl.rs` file. + +#![allow(unsafe_code)] + +use alloc::vec; +use alloc::vec::Vec; +use core::mem::MaybeUninit; +use core::ptr; + +use bitflags::bitflags; + +use crate::backend::c::{c_int, c_uint, c_void}; +use crate::backend::process::syscalls; +use crate::backend::process::types::{RawId, Signal}; +use crate::io; +use crate::process::{Pid, RawPid}; +use crate::utils::{as_mut_ptr, as_ptr}; + +// +// Helper functions. +// + +/// Subset of `idtype_t` C enum, with only the values allowed by `procctl`. +#[repr(i32)] +pub enum IdType { + /// Process id. + Pid = 0, + /// Process group id. + Pgid = 2, +} + +/// A process selector for use with the `procctl` interface. +/// +/// `None` represents the current process. `Some((IdType::Pid, pid))` +/// represents the process with pid `pid`. `Some((IdType::Pgid, pgid))` +/// represents the control processes belonging to the process group with id +/// `pgid`. +pub type ProcSelector = Option<(IdType, Pid)>; +fn proc_selector_to_raw(selector: ProcSelector) -> (IdType, RawPid) { + match selector { + Some((idtype, id)) => (idtype, id.as_raw_nonzero().get()), + None => (IdType::Pid, 0), + } +} + +#[inline] +pub(crate) unsafe fn procctl( + option: c_int, + process: ProcSelector, + data: *mut c_void, +) -> io::Result<()> { + let (idtype, id) = proc_selector_to_raw(process); + syscalls::procctl(idtype as c_uint, id as RawId, option, data) +} + +#[inline] +pub(crate) unsafe fn procctl_set<P>( + option: c_int, + process: ProcSelector, + data: &P, +) -> io::Result<()> { + procctl(option, process, (as_ptr(data) as *mut P).cast()) +} + +#[inline] +pub(crate) unsafe fn procctl_get_optional<P>( + option: c_int, + process: ProcSelector, +) -> io::Result<P> { + let mut value: MaybeUninit<P> = MaybeUninit::uninit(); + procctl(option, process, value.as_mut_ptr().cast())?; + Ok(value.assume_init()) +} + +// +// PROC_PDEATHSIG_STATUS/PROC_PDEATHSIG_CTL +// + +const PROC_PDEATHSIG_STATUS: c_int = 12; + +/// Get the current value of the parent process death signal. +/// +/// # References +/// - [Linux: `prctl(PR_GET_PDEATHSIG,...)`] +/// - [FreeBSD: `procctl(PROC_PDEATHSIG_STATUS,...)`] +/// +/// [Linux: `prctl(PR_GET_PDEATHSIG,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +/// [FreeBSD: `procctl(PROC_PDEATHSIG_STATUS,...)`]: https://man.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 +#[inline] +pub fn parent_process_death_signal() -> io::Result<Option<Signal>> { + unsafe { procctl_get_optional::<c_int>(PROC_PDEATHSIG_STATUS, None) }.map(Signal::from_raw) +} + +const PROC_PDEATHSIG_CTL: c_int = 11; + +/// Set the parent-death signal of the calling process. +/// +/// # References +/// - [Linux: `prctl(PR_SET_PDEATHSIG,...)`] +/// - [FreeBSD: `procctl(PROC_PDEATHSIG_CTL,...)`] +/// +/// [Linux: `prctl(PR_SET_PDEATHSIG,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +/// [FreeBSD: `procctl(PROC_PDEATHSIG_CTL,...)`]: https://man.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 +#[inline] +pub fn set_parent_process_death_signal(signal: Option<Signal>) -> io::Result<()> { + let signal = signal.map_or(0, |signal| signal as c_int); + unsafe { procctl_set::<c_int>(PROC_PDEATHSIG_CTL, None, &signal) } +} + +// +// PROC_TRACE_CTL +// + +const PROC_TRACE_CTL: c_int = 7; + +const PROC_TRACE_CTL_ENABLE: i32 = 1; +const PROC_TRACE_CTL_DISABLE: i32 = 2; +const PROC_TRACE_CTL_DISABLE_EXEC: i32 = 3; + +/// `PROC_TRACE_CTL_*`. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[repr(i32)] +pub enum DumpableBehavior { + /// Not dumpable. + NotDumpable = PROC_TRACE_CTL_DISABLE, + /// Dumpable. + Dumpable = PROC_TRACE_CTL_ENABLE, + /// Not dumpable, and this behaviour is preserved across `execve` calls. + NotDumpableExecPreserved = PROC_TRACE_CTL_DISABLE_EXEC, +} + +/// Set the state of the `dumpable` attribute for the process indicated by +/// `idtype` and `id`. This determines whether the process can be traced and +/// whether core dumps are produced for the process upon delivery of a signal +/// whose default behavior is to produce a core dump. +/// +/// This is similar to `set_dumpable_behavior` on Linux, with the exception +/// that on FreeBSD there is an extra argument `process`. When `process` is set +/// to `None`, the operation is performed for the current process, like on +/// Linux. +/// +/// # References +/// - [FreeBSD `procctl(PROC_TRACE_CTL,...)`] +/// +/// [FreeBSD `procctl(PROC_TRACE_CTL,...)`]: https://man.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 +#[inline] +pub fn set_dumpable_behavior(process: ProcSelector, config: DumpableBehavior) -> io::Result<()> { + unsafe { procctl(PROC_TRACE_CTL, process, config as usize as *mut _) } +} + +// +// PROC_TRACE_STATUS +// + +const PROC_TRACE_STATUS: c_int = 8; + +/// Tracing status as returned by [`trace_status`]. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum TracingStatus { + /// Tracing is disabled for the process. + NotTraceble, + /// Tracing is not disabled for the process, but not debugger/tracer is + /// attached. + Tracable, + /// The process is being traced by the process whose pid is stored in the + /// first component of this variant. + BeingTraced(Pid), +} + +/// Get the tracing status of the process indicated by `idtype` and `id`. +/// +/// # References +/// - [FreeBSD `procctl(PROC_TRACE_STATUS,...)`] +/// +/// [FreeBSD `procctl(PROC_TRACE_STATUS,...)`]: https://man.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 +#[inline] +pub fn trace_status(process: ProcSelector) -> io::Result<TracingStatus> { + let val = unsafe { procctl_get_optional::<c_int>(PROC_TRACE_STATUS, process) }?; + match val { + -1 => Ok(TracingStatus::NotTraceble), + 0 => Ok(TracingStatus::Tracable), + pid => { + let pid = unsafe { Pid::from_raw(pid as RawPid) }.ok_or(io::Errno::RANGE)?; + Ok(TracingStatus::BeingTraced(pid)) + } + } +} + +// +// PROC_REAP_* +// + +const PROC_REAP_ACQUIRE: c_int = 2; +const PROC_REAP_RELEASE: c_int = 3; + +/// Acquire or release the reaper status of the calling process. +/// +/// # References +/// - [FreeBSD: `procctl(PROC_REAP_ACQUIRE/RELEASE,...)`] +/// +/// [FreeBSD: `procctl(PROC_REAP_ACQUIRE/RELEASE,...)`]: https://man.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 +#[inline] +pub fn set_reaper_status(reaper: bool) -> io::Result<()> { + unsafe { + procctl( + if reaper { + PROC_REAP_ACQUIRE + } else { + PROC_REAP_RELEASE + }, + None, + ptr::null_mut(), + ) + } +} + +const PROC_REAP_STATUS: c_int = 4; + +bitflags! { + /// `REAPER_STATUS_*`. + pub struct ReaperStatusFlags: c_uint { + /// The process has acquired reaper status. + const OWNED = 1; + /// The process is the root of the reaper tree (pid 1). + const REALINIT = 2; + } +} + +#[repr(C)] +struct procctl_reaper_status { + rs_flags: c_uint, + rs_children: c_uint, + rs_descendants: c_uint, + rs_reaper: RawPid, + rs_pid: RawPid, + rs_pad0: [c_uint; 15], +} + +/// Reaper status as returned by [`get_reaper_status`]. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct ReaperStatus { + /// The flags. + pub flags: ReaperStatusFlags, + /// The number of children of the reaper among the descendants. + pub children: usize, + /// The total number of descendants of the reaper(s), not counting + /// descendants of the reaper in the subtree. + pub descendants: usize, + /// The pid of the reaper for the specified process id. + pub reaper: Pid, + /// The pid of one reaper child if there are any descendants. + pub pid: Pid, +} + +/// Get information about the reaper of the specified process (or the process +/// itself if it is a reaper). +/// +/// # References +/// - [FreeBSD: `procctl(PROC_REAP_STATUS,...)`] +/// +/// [FreeBSD: `procctl(PROC_REAP_STATUS,...)`]: https://man.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 +#[inline] +pub fn get_reaper_status(process: ProcSelector) -> io::Result<ReaperStatus> { + let raw = unsafe { procctl_get_optional::<procctl_reaper_status>(PROC_REAP_STATUS, process) }?; + Ok(ReaperStatus { + flags: ReaperStatusFlags::from_bits_truncate(raw.rs_flags), + children: raw.rs_children as _, + descendants: raw.rs_descendants as _, + reaper: unsafe { Pid::from_raw(raw.rs_reaper) }.ok_or(io::Errno::RANGE)?, + pid: unsafe { Pid::from_raw(raw.rs_pid) }.ok_or(io::Errno::RANGE)?, + }) +} + +const PROC_REAP_GETPIDS: c_int = 5; + +bitflags! { + /// `REAPER_PIDINFO_*`. + pub struct PidInfoFlags: c_uint { + /// This structure was filled by the kernel. + const VALID = 1; + /// The pid field identifies a direct child of the reaper. + const CHILD = 2; + /// The reported process is itself a reaper. Descendants of a + /// subordinate reaper are not reported. + const REAPER = 4; + /// The reported process is in the zombie state. + const ZOMBIE = 8; + /// The reported process is stopped by SIGSTOP/SIGTSTP. + const STOPPED = 16; + /// The reported process is in the process of exiting. + const EXITING = 32; + } +} + +#[repr(C)] +#[derive(Default, Clone)] +struct procctl_reaper_pidinfo { + pi_pid: RawPid, + pi_subtree: RawPid, + pi_flags: c_uint, + pi_pad0: [c_uint; 15], +} + +#[repr(C)] +struct procctl_reaper_pids { + rp_count: c_uint, + rp_pad0: [c_uint; 15], + rp_pids: *mut procctl_reaper_pidinfo, +} + +/// A child process of a reaper. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct PidInfo { + /// The flags of the process. + pub flags: PidInfoFlags, + /// The pid of the process. + pub pid: Pid, + /// The pid of the child of the reaper which is the (grand-..)parent of the + /// process. + pub subtree: Pid, +} + +/// Get the list of descendants of the specified reaper process. +/// +/// # References +/// - [FreeBSD: `procctl(PROC_REAP_GETPIDS,...)`] +/// +/// [FreeBSD: `procctl(PROC_REAP_GETPIDS,...)`]: https://man.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 +pub fn get_reaper_pids(process: ProcSelector) -> io::Result<Vec<PidInfo>> { + // Sadly no better way to guarantee that we get all the results than to + // allocate ~8MB of memory.. + const PID_MAX: usize = 99999; + let mut pids: Vec<procctl_reaper_pidinfo> = vec![Default::default(); PID_MAX]; + let mut pinfo = procctl_reaper_pids { + rp_count: PID_MAX as _, + rp_pad0: [0; 15], + rp_pids: pids.as_mut_slice().as_mut_ptr(), + }; + unsafe { procctl(PROC_REAP_GETPIDS, process, as_mut_ptr(&mut pinfo).cast())? }; + let mut result = Vec::new(); + for raw in pids.into_iter() { + let flags = PidInfoFlags::from_bits_truncate(raw.pi_flags); + if !flags.contains(PidInfoFlags::VALID) { + break; + } + result.push(PidInfo { + flags, + subtree: unsafe { Pid::from_raw(raw.pi_subtree) }.ok_or(io::Errno::RANGE)?, + pid: unsafe { Pid::from_raw(raw.pi_pid) }.ok_or(io::Errno::RANGE)?, + }); + } + Ok(result) +} + +const PROC_REAP_KILL: c_int = 6; + +bitflags! { + /// `REAPER_KILL_*`. + struct KillFlags: c_uint { + const CHILDREN = 1; + const SUBTREE = 2; + } +} + +#[repr(C)] +struct procctl_reaper_kill { + rk_sig: c_int, + rk_flags: c_uint, + rk_subtree: RawPid, + rk_killed: c_uint, + rk_fpid: RawPid, + rk_pad0: [c_uint; 15], +} + +/// Reaper status as returned by [`get_reaper_status`]. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct KillResult { + /// The number of processes that were signalled. + pub killed: usize, + /// The pid of the first process that wasn't successfully signalled. + pub first_failed: Option<Pid>, +} + +/// Deliver a signal to some subset of +/// +/// # References +/// - [FreeBSD: `procctl(PROC_REAP_KILL,...)`] +/// +/// [FreeBSD: `procctl(PROC_REAP_KILL,...)`]: https://man.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 +pub fn reaper_kill( + process: ProcSelector, + signal: Signal, + direct_children: bool, + subtree: Option<Pid>, +) -> io::Result<KillResult> { + let mut flags = KillFlags::empty(); + flags.set(KillFlags::CHILDREN, direct_children); + flags.set(KillFlags::SUBTREE, subtree.is_some()); + let mut req = procctl_reaper_kill { + rk_sig: signal as c_int, + rk_flags: flags.bits(), + rk_subtree: subtree.map(|p| p.as_raw_nonzero().into()).unwrap_or(0), + rk_killed: 0, + rk_fpid: 0, + rk_pad0: [0; 15], + }; + unsafe { procctl(PROC_REAP_KILL, process, as_mut_ptr(&mut req).cast())? }; + Ok(KillResult { + killed: req.rk_killed as _, + first_failed: if req.rk_fpid == -1 { + None + } else { + unsafe { Pid::from_raw(req.rk_fpid) } + }, + }) +} + +// +// PROC_TRAPCAP_STATUS/PROC_TRAPCAP_CTL +// + +const PROC_TRAPCAP_CTL: c_int = 9; + +const PROC_TRAPCAP_CTL_ENABLE: i32 = 1; +const PROC_TRAPCAP_CTL_DISABLE: i32 = 2; + +/// `PROC_TRAPCAP_CTL_*`. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[repr(i32)] +pub enum TrapCapBehavior { + /// Disable the [`Signal::Trap`] signal delivery on capability mode access + /// violations. + Disable = PROC_TRAPCAP_CTL_DISABLE, + /// Enable the [`Signal::Trap`] signal delivery on capability mode access + /// violations. + Enable = PROC_TRAPCAP_CTL_ENABLE, +} + +/// Set the current value of the capability mode violation trapping behavior. +/// If this behavior is enabled, the kernel would deliver a [`Signal::Trap`] +/// signal on any return from a system call that would result in a +/// [`io::Errno::NOTCAPABLE`]` or [`io::Errno::CAPMODE`] error. +/// +/// This behavior is inherited by the children of the process and is kept +/// across `execve` calls. +/// +/// # References +/// - [FreeBSD: `procctl(PROC_TRAPCAP_CTL,...)`] +/// +/// [FreeBSD: `procctl(PROC_TRAPCAP_CTL,...)`]: https://man.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 +#[inline] +pub fn set_trap_cap_behavior(process: ProcSelector, config: TrapCapBehavior) -> io::Result<()> { + let config = config as c_int; + unsafe { procctl_set::<c_int>(PROC_TRAPCAP_CTL, process, &config) } +} + +const PROC_TRAPCAP_STATUS: c_int = 10; + +/// Get the current value of the capability mode violation trapping behavior. +/// +/// # References +/// - [FreeBSD: `procctl(PROC_TRAPCAP_STATUS,...)`] +/// +/// [FreeBSD: `procctl(PROC_TRAPCAP_STATUS,...)`]: https://man.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 +#[inline] +pub fn trap_cap_behavior(process: ProcSelector) -> io::Result<TrapCapBehavior> { + let val = unsafe { procctl_get_optional::<c_int>(PROC_TRAPCAP_STATUS, process) }?; + match val { + PROC_TRAPCAP_CTL_DISABLE => Ok(TrapCapBehavior::Disable), + PROC_TRAPCAP_CTL_ENABLE => Ok(TrapCapBehavior::Enable), + _ => Err(io::Errno::RANGE), + } +} + +// +// PROC_NO_NEW_PRIVS_STATUS/PROC_NO_NEW_PRIVS_CTL +// + +const PROC_NO_NEW_PRIVS_CTL: c_int = 19; + +const PROC_NO_NEW_PRIVS_ENABLE: c_int = 1; + +/// Enable the `no_new_privs` mode that ignores SUID and SGID bits +/// on `execve` in the specified process and its future descendants. +/// +/// This is similar to `set_no_new_privs` on Linux, with the exception +/// that on FreeBSD there is no argument `no_new_privs` argument as it's +/// only possible to enable this mode and there's no going back. +/// +/// # References +/// - [Linux: `prctl(PR_SET_NO_NEW_PRIVS,...)`] +/// - [FreeBSD: `procctl(PROC_NO_NEW_PRIVS_CTL,...)`] +/// +/// [Linux: `prctl(PR_SET_NO_NEW_PRIVS,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +/// [FreeBSD: `procctl(PROC_NO_NEW_PRIVS_CTL,...)`]: https://man.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 +#[inline] +pub fn set_no_new_privs(process: ProcSelector) -> io::Result<()> { + unsafe { procctl_set::<c_int>(PROC_NO_NEW_PRIVS_CTL, process, &PROC_NO_NEW_PRIVS_ENABLE) } +} + +const PROC_NO_NEW_PRIVS_STATUS: c_int = 20; + +/// Check the `no_new_privs` mode of the specified process. +/// +/// # References +/// - [Linux: `prctl(PR_GET_NO_NEW_PRIVS,...)`] +/// - [FreeBSD: `procctl(PROC_NO_NEW_PRIVS_STATUS,...)`] +/// +/// [Linux: `prctl(PR_GET_NO_NEW_PRIVS,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +/// [FreeBSD: `procctl(PROC_NO_NEW_PRIVS_STATUS,...)`]: https://man.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 +#[inline] +pub fn no_new_privs(process: ProcSelector) -> io::Result<bool> { + unsafe { procctl_get_optional::<c_int>(PROC_NO_NEW_PRIVS_STATUS, process) } + .map(|x| x == PROC_NO_NEW_PRIVS_ENABLE) +} diff --git a/vendor/rustix-0.37.22/src/process/rlimit.rs b/vendor/rustix-0.37.22/src/process/rlimit.rs new file mode 100644 index 000000000..ea760c22f --- /dev/null +++ b/vendor/rustix-0.37.22/src/process/rlimit.rs @@ -0,0 +1,53 @@ +#[cfg(linux_kernel)] +use crate::process::Pid; +use crate::{backend, io}; + +pub use backend::process::types::Resource; + +/// `struct rlimit`—Current and maximum values used in [`getrlimit`], +/// [`setrlimit`], and [`prlimit`]. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Rlimit { + /// Current effective, “soft”, limit. + pub current: Option<u64>, + /// Maximum, “hard”, value that `current` may be dynamically increased to. + pub maximum: Option<u64>, +} + +/// `getrlimit(resource)`—Get a process resource limit value. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getrlimit.html +/// [Linux]: https://man7.org/linux/man-pages/man2/getrlimit.2.html +#[inline] +pub fn getrlimit(resource: Resource) -> Rlimit { + backend::process::syscalls::getrlimit(resource) +} + +/// `setrlimit(resource, new)`—Set a process resource limit value. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setrlimit.html +/// [Linux]: https://man7.org/linux/man-pages/man2/setrlimit.2.html +#[inline] +pub fn setrlimit(resource: Resource, new: Rlimit) -> io::Result<()> { + backend::process::syscalls::setrlimit(resource, new) +} + +/// `prlimit(pid, resource, new)`—Get and set a process resource limit value. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/prlimit.2.html +#[cfg(linux_kernel)] +#[inline] +pub fn prlimit(pid: Option<Pid>, resource: Resource, new: Rlimit) -> io::Result<Rlimit> { + backend::process::syscalls::prlimit(pid, resource, new) +} diff --git a/vendor/rustix-0.37.22/src/process/sched.rs b/vendor/rustix-0.37.22/src/process/sched.rs new file mode 100644 index 000000000..239b7df82 --- /dev/null +++ b/vendor/rustix-0.37.22/src/process/sched.rs @@ -0,0 +1,110 @@ +use crate::process::Pid; +use crate::{backend, io}; + +/// `CpuSet` represents a bit-mask of CPUs. +/// +/// `CpuSet`s are used by [`sched_setaffinity`] and [`sched_getaffinity`], for +/// example. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man3/CPU_SET.3.html +/// [`sched_setaffinity`]: crate::process::sched_setaffinity +/// [`sched_getaffinity`]: crate::process::sched_getaffinity +#[repr(C)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct CpuSet { + cpu_set: backend::process::types::RawCpuSet, +} + +impl CpuSet { + /// The maximum number of CPU in `CpuSet`. + pub const MAX_CPU: usize = backend::process::types::CPU_SETSIZE; + + /// Create a new and empty `CpuSet`. + #[inline] + pub fn new() -> Self { + Self { + cpu_set: backend::process::types::raw_cpu_set_new(), + } + } + + /// Test to see if a CPU is in the `CpuSet`. + /// + /// `field` is the CPU id to test. + #[inline] + pub fn is_set(&self, field: usize) -> bool { + backend::process::cpu_set::CPU_ISSET(field, &self.cpu_set) + } + + /// Add a CPU to `CpuSet`. + /// + /// `field` is the CPU id to add. + #[inline] + pub fn set(&mut self, field: usize) { + backend::process::cpu_set::CPU_SET(field, &mut self.cpu_set) + } + + /// Remove a CPU from `CpuSet`. + /// + /// `field` is the CPU id to remove. + #[inline] + pub fn unset(&mut self, field: usize) { + backend::process::cpu_set::CPU_CLR(field, &mut self.cpu_set) + } + + /// Count the number of CPUs set in the `CpuSet`. + #[cfg(linux_kernel)] + #[inline] + pub fn count(&self) -> u32 { + backend::process::cpu_set::CPU_COUNT(&self.cpu_set) + } + + /// Zeroes the `CpuSet`. + #[inline] + pub fn clear(&mut self) { + backend::process::cpu_set::CPU_ZERO(&mut self.cpu_set) + } +} + +impl Default for CpuSet { + #[inline] + fn default() -> Self { + Self::new() + } +} + +/// `sched_setaffinity(pid, cpuset)`—Set a thread's CPU affinity mask. +/// +/// `pid` is the thread ID to update. If pid is `None`, then the current thread +/// is updated. +/// +/// The `CpuSet` argument specifies the set of CPUs on which the thread will +/// be eligible to run. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/sched_setaffinity.2.html +#[inline] +pub fn sched_setaffinity(pid: Option<Pid>, cpuset: &CpuSet) -> io::Result<()> { + backend::process::syscalls::sched_setaffinity(pid, &cpuset.cpu_set) +} + +/// `sched_getaffinity(pid)`—Get a thread's CPU affinity mask. +/// +/// `pid` is the thread ID to check. If pid is `None`, then the current thread +/// is checked. +/// +/// Returns the set of CPUs on which the thread is eligible to run. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/sched_getaffinity.2.html +#[inline] +pub fn sched_getaffinity(pid: Option<Pid>) -> io::Result<CpuSet> { + let mut cpuset = CpuSet::new(); + backend::process::syscalls::sched_getaffinity(pid, &mut cpuset.cpu_set).and(Ok(cpuset)) +} diff --git a/vendor/rustix-0.37.22/src/process/sched_yield.rs b/vendor/rustix-0.37.22/src/process/sched_yield.rs new file mode 100644 index 000000000..0324f67cb --- /dev/null +++ b/vendor/rustix-0.37.22/src/process/sched_yield.rs @@ -0,0 +1,16 @@ +use crate::backend; + +/// `sched_yield()`—Hints to the OS that other processes should run. +/// +/// This function always succeeds. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sched_yield.html +/// [Linux]: https://man7.org/linux/man-pages/man2/sched_yield.2.html +#[inline] +pub fn sched_yield() { + backend::process::syscalls::sched_yield() +} diff --git a/vendor/rustix-0.37.22/src/process/system.rs b/vendor/rustix-0.37.22/src/process/system.rs new file mode 100644 index 000000000..ab7e8237a --- /dev/null +++ b/vendor/rustix-0.37.22/src/process/system.rs @@ -0,0 +1,137 @@ +//! Uname and other system-level functions. +//! +//! # Safety +//! +//! This function converts from `struct utsname` fields provided from the +//! kernel into `&str` references, which assumes that they're NUL-terminated. +#![allow(unsafe_code)] + +use crate::backend; +use crate::ffi::CStr; +#[cfg(not(target_os = "emscripten"))] +use crate::io; +use core::fmt; + +#[cfg(linux_kernel)] +pub use backend::process::types::Sysinfo; + +/// `uname()`—Returns high-level information about the runtime OS and +/// hardware. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/uname.html +/// [Linux]: https://man7.org/linux/man-pages/man2/uname.2.html +#[inline] +pub fn uname() -> Uname { + Uname(backend::process::syscalls::uname()) +} + +/// `struct utsname`—Return type for [`uname`]. +#[doc(alias = "utsname")] +pub struct Uname(backend::process::types::RawUname); + +impl Uname { + /// `sysname`—Operating system release name + #[inline] + pub fn sysname(&self) -> &CStr { + Self::to_cstr(self.0.sysname.as_ptr().cast()) + } + + /// `nodename`—Name with vague meaning + /// + /// This is intended to be a network name, however it's unable to convey + /// information about hosts that have multiple names, or any information + /// about where the names are visible. + #[inline] + pub fn nodename(&self) -> &CStr { + Self::to_cstr(self.0.nodename.as_ptr().cast()) + } + + /// `release`—Operating system release version string + #[inline] + pub fn release(&self) -> &CStr { + Self::to_cstr(self.0.release.as_ptr().cast()) + } + + /// `version`—Operating system build identifiers + #[inline] + pub fn version(&self) -> &CStr { + Self::to_cstr(self.0.version.as_ptr().cast()) + } + + /// `machine`—Hardware architecture identifier + #[inline] + pub fn machine(&self) -> &CStr { + Self::to_cstr(self.0.machine.as_ptr().cast()) + } + + /// `domainname`—NIS or YP domain identifier + #[cfg(linux_kernel)] + #[inline] + pub fn domainname(&self) -> &CStr { + Self::to_cstr(self.0.domainname.as_ptr().cast()) + } + + #[inline] + fn to_cstr<'a>(ptr: *const u8) -> &'a CStr { + // SAFETY: Strings returned from the kernel are always NUL-terminated. + unsafe { CStr::from_ptr(ptr.cast()) } + } +} + +impl fmt::Debug for Uname { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + #[cfg(not(linux_kernel))] + { + write!( + fmt, + "{} {} {} {} {}", + self.sysname().to_string_lossy(), + self.nodename().to_string_lossy(), + self.release().to_string_lossy(), + self.version().to_string_lossy(), + self.machine().to_string_lossy(), + ) + } + #[cfg(linux_kernel)] + { + write!( + fmt, + "{} {} {} {} {} {}", + self.sysname().to_string_lossy(), + self.nodename().to_string_lossy(), + self.release().to_string_lossy(), + self.version().to_string_lossy(), + self.machine().to_string_lossy(), + self.domainname().to_string_lossy(), + ) + } + } +} + +/// `sysinfo()`—Returns status information about the runtime OS. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/uname.2.html +#[cfg(linux_kernel)] +#[inline] +pub fn sysinfo() -> Sysinfo { + backend::process::syscalls::sysinfo() +} + +/// `sethostname(name)`—Sets the system host name. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/sethostname.2.html +#[cfg(not(any(target_os = "emscripten", target_os = "redox", target_os = "wasi")))] +#[inline] +pub fn sethostname(name: &[u8]) -> io::Result<()> { + backend::process::syscalls::sethostname(name) +} diff --git a/vendor/rustix-0.37.22/src/process/umask.rs b/vendor/rustix-0.37.22/src/process/umask.rs new file mode 100644 index 000000000..01779d7ed --- /dev/null +++ b/vendor/rustix-0.37.22/src/process/umask.rs @@ -0,0 +1,21 @@ +//! Umask support. + +#[cfg(feature = "fs")] +use crate::backend; +#[cfg(feature = "fs")] +use crate::fs::Mode; + +/// `umask(mask)`—Set the process file creation mask. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/umask.html +/// [Linux]: https://man7.org/linux/man-pages/man2/umask.2.html +#[cfg(feature = "fs")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "fs")))] +#[inline] +pub fn umask(mask: Mode) -> Mode { + backend::process::syscalls::umask(mask) +} diff --git a/vendor/rustix-0.37.22/src/process/wait.rs b/vendor/rustix-0.37.22/src/process/wait.rs new file mode 100644 index 000000000..ac19e71fd --- /dev/null +++ b/vendor/rustix-0.37.22/src/process/wait.rs @@ -0,0 +1,323 @@ +use crate::process::Pid; +use crate::{backend, io}; +use bitflags::bitflags; + +#[cfg(target_os = "linux")] +use crate::fd::BorrowedFd; + +#[cfg(linux_raw)] +use crate::backend::process::wait::SiginfoExt; + +bitflags! { + /// Options for modifying the behavior of wait/waitpid + pub struct WaitOptions: u32 { + /// Return immediately if no child has exited. + const NOHANG = backend::process::wait::WNOHANG as _; + /// Return if a child has stopped (but not traced via [`ptrace`]) + /// + /// [`ptrace`]: https://man7.org/linux/man-pages/man2/ptrace.2.html + const UNTRACED = backend::process::wait::WUNTRACED as _; + /// Return if a stopped child has been resumed by delivery of + /// [`Signal::Cont`]. + const CONTINUED = backend::process::wait::WCONTINUED as _; + } +} + +#[cfg(not(any(target_os = "wasi", target_os = "redox", target_os = "openbsd")))] +bitflags! { + /// Options for modifying the behavior of waitid + pub struct WaitidOptions: u32 { + /// Return immediately if no child has exited. + const NOHANG = backend::process::wait::WNOHANG as _; + /// Return if a stopped child has been resumed by delivery of + /// [`Signal::Cont`] + const CONTINUED = backend::process::wait::WCONTINUED as _; + /// Wait for processed that have exited. + const EXITED = backend::process::wait::WEXITED as _; + /// Keep processed in a waitable state. + const NOWAIT = backend::process::wait::WNOWAIT as _; + /// Wait for processes that have been stopped. + const STOPPED = backend::process::wait::WSTOPPED as _; + } +} + +/// The status of a child process after calling [`wait`]/[`waitpid`]. +#[derive(Debug, Clone, Copy)] +#[repr(transparent)] +pub struct WaitStatus(u32); + +impl WaitStatus { + /// Creates a `WaitStatus` out of an integer. + #[inline] + pub(crate) fn new(status: u32) -> Self { + Self(status) + } + + /// Converts a `WaitStatus` into its raw representation as an integer. + #[inline] + pub const fn as_raw(self) -> u32 { + self.0 + } + + /// Returns whether the process is currently stopped. + #[inline] + pub fn stopped(self) -> bool { + backend::process::wait::WIFSTOPPED(self.0 as _) + } + + /// Returns whether the process has exited normally. + #[inline] + pub fn exited(self) -> bool { + backend::process::wait::WIFEXITED(self.0 as _) + } + + /// Returns whether the process was terminated by a signal. + #[inline] + pub fn signaled(self) -> bool { + backend::process::wait::WIFSIGNALED(self.0 as _) + } + + /// Returns whether the process has continued from a job control stop. + #[inline] + pub fn continued(self) -> bool { + backend::process::wait::WIFCONTINUED(self.0 as _) + } + + /// Returns the number of the signal that stopped the process, + /// if the process was stopped by a signal. + #[inline] + pub fn stopping_signal(self) -> Option<u32> { + if self.stopped() { + Some(backend::process::wait::WSTOPSIG(self.0 as _) as _) + } else { + None + } + } + + /// Returns the exit status number returned by the process, + /// if it exited normally. + #[inline] + pub fn exit_status(self) -> Option<u32> { + if self.exited() { + Some(backend::process::wait::WEXITSTATUS(self.0 as _) as _) + } else { + None + } + } + + /// Returns the number of the signal that terminated the process, + /// if the process was terminated by a signal. + #[inline] + pub fn terminating_signal(self) -> Option<u32> { + if self.signaled() { + Some(backend::process::wait::WTERMSIG(self.0 as _) as _) + } else { + None + } + } +} + +/// The status of a process after calling [`waitid`]. +#[derive(Clone, Copy)] +#[repr(transparent)] +#[cfg(not(any(target_os = "wasi", target_os = "redox", target_os = "openbsd")))] +pub struct WaitidStatus(pub(crate) backend::c::siginfo_t); + +#[cfg(not(any(target_os = "wasi", target_os = "redox", target_os = "openbsd")))] +impl WaitidStatus { + /// Returns whether the process is currently stopped. + #[inline] + pub fn stopped(&self) -> bool { + self.si_code() == backend::c::CLD_STOPPED + } + + /// Returns whether the process is currently trapped. + #[inline] + pub fn trapped(&self) -> bool { + self.si_code() == backend::c::CLD_TRAPPED + } + + /// Returns whether the process has exited normally. + #[inline] + pub fn exited(&self) -> bool { + self.si_code() == backend::c::CLD_EXITED + } + + /// Returns whether the process was terminated by a signal + /// and did not create a core file. + #[inline] + pub fn killed(&self) -> bool { + self.si_code() == backend::c::CLD_KILLED + } + + /// Returns whether the process was terminated by a signal + /// and did create a core file. + #[inline] + pub fn dumped(&self) -> bool { + self.si_code() == backend::c::CLD_DUMPED + } + + /// Returns whether the process has continued from a job control stop. + #[inline] + pub fn continued(&self) -> bool { + self.si_code() == backend::c::CLD_CONTINUED + } + + /// Returns the number of the signal that stopped the process, + /// if the process was stopped by a signal. + #[inline] + #[cfg(not(any(target_os = "netbsd", target_os = "fuchsia", target_os = "emscripten")))] + pub fn stopping_signal(&self) -> Option<u32> { + if self.stopped() { + Some(self.si_status() as _) + } else { + None + } + } + + /// Returns the number of the signal that trapped the process, + /// if the process was trapped by a signal. + #[inline] + #[cfg(not(any(target_os = "netbsd", target_os = "fuchsia", target_os = "emscripten")))] + pub fn trapping_signal(&self) -> Option<u32> { + if self.trapped() { + Some(self.si_status() as _) + } else { + None + } + } + + /// Returns the exit status number returned by the process, + /// if it exited normally. + #[inline] + #[cfg(not(any(target_os = "netbsd", target_os = "fuchsia", target_os = "emscripten")))] + pub fn exit_status(&self) -> Option<u32> { + if self.exited() { + Some(self.si_status() as _) + } else { + None + } + } + + /// Returns the number of the signal that terminated the process, + /// if the process was terminated by a signal. + #[inline] + #[cfg(not(any(target_os = "netbsd", target_os = "fuchsia", target_os = "emscripten")))] + pub fn terminating_signal(&self) -> Option<u32> { + if self.killed() || self.dumped() { + Some(self.si_status() as _) + } else { + None + } + } + + /// Returns a reference to the raw platform-specific `siginfo_t` struct. + #[inline] + pub const fn as_raw(&self) -> &backend::c::siginfo_t { + &self.0 + } + + #[cfg(linux_raw)] + fn si_code(&self) -> u32 { + self.0.si_code() as u32 // CLD_ consts are unsigned + } + + #[cfg(not(linux_raw))] + fn si_code(&self) -> backend::c::c_int { + self.0.si_code + } + + #[cfg(not(any(target_os = "netbsd", target_os = "fuchsia", target_os = "emscripten")))] + #[allow(unsafe_code)] + fn si_status(&self) -> backend::c::c_int { + // SAFETY: POSIX [specifies] that the `siginfo_t` returned by a + // `waitid` call always has a valid `si_status` value. + // + // [specifies]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html + unsafe { self.0.si_status() } + } +} + +/// The identifier to wait on in a call to [`waitid`]. +#[cfg(not(any(target_os = "wasi", target_os = "redox", target_os = "openbsd")))] +#[derive(Debug, Clone)] +#[non_exhaustive] +pub enum WaitId<'a> { + /// Wait on all processes. + All, + + /// Wait for a specific process ID. + Pid(Pid), + + /// Wait for a specific process file descriptor. + #[cfg(target_os = "linux")] + PidFd(BorrowedFd<'a>), + + /// Eat the lifetime for non-Linux platforms. + #[doc(hidden)] + #[cfg(not(target_os = "linux"))] + __EatLifetime(core::marker::PhantomData<&'a ()>), + // TODO(notgull): Once this crate has the concept of PGIDs, add a WaitId::Pgid +} + +/// `waitpid(pid, waitopts)`—Wait for a specific process to change state. +/// +/// If the pid is `None`, the call will wait for any child process whose +/// process group id matches that of the calling process. +/// +/// If the pid is equal to `RawPid::MAX`, the call will wait for any child +/// process. +/// +/// Otherwise if the `wrapping_neg` of pid is less than pid, the call will wait +/// for any child process with a group ID equal to the `wrapping_neg` of `pid`. +/// +/// Otherwise, the call will wait for the child process with the given pid. +/// +/// On Success, returns the status of the selected process. +/// +/// If `NOHANG` was specified in the options, and the selected child process +/// didn't change state, returns `None`. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html +/// [Linux]: https://man7.org/linux/man-pages/man2/waitpid.2.html +#[cfg(not(target_os = "wasi"))] +#[inline] +pub fn waitpid(pid: Option<Pid>, waitopts: WaitOptions) -> io::Result<Option<WaitStatus>> { + Ok(backend::process::syscalls::waitpid(pid, waitopts)?.map(|(_, status)| status)) +} + +/// `wait(waitopts)`—Wait for any of the children of calling process to +/// change state. +/// +/// On success, returns the pid of the child process whose state changed, and +/// the status of said process. +/// +/// If `NOHANG` was specified in the options, and the selected child process +/// didn't change state, returns `None`. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html +/// [Linux]: https://man7.org/linux/man-pages/man2/waitpid.2.html +#[cfg(not(target_os = "wasi"))] +#[inline] +pub fn wait(waitopts: WaitOptions) -> io::Result<Option<(Pid, WaitStatus)>> { + backend::process::syscalls::wait(waitopts) +} + +/// `waitid(_, _, _, opts)`—Wait for the specified child process to change +/// state. +#[cfg(not(any(target_os = "wasi", target_os = "redox", target_os = "openbsd")))] +#[inline] +pub fn waitid<'a>( + id: impl Into<WaitId<'a>>, + options: WaitidOptions, +) -> io::Result<Option<WaitidStatus>> { + backend::process::syscalls::waitid(id.into(), options) +} diff --git a/vendor/rustix-0.37.22/src/pty.rs b/vendor/rustix-0.37.22/src/pty.rs new file mode 100644 index 000000000..b7418b5d9 --- /dev/null +++ b/vendor/rustix-0.37.22/src/pty.rs @@ -0,0 +1,171 @@ +//! Pseudoterminal operations. +//! +//! For the `openpty` and `login_tty` functions, see the +//! [rustix-openpty crate]. +//! +//! [rustix-openpty crate]: https://crates.io/crates/rustix-openpty + +use crate::backend::c; +use crate::fd::{AsFd, OwnedFd}; +use crate::fs::OFlags; +use crate::{backend, io}; +#[cfg(any(apple, linux_like, target_os = "freebsd", target_os = "fuchsia"))] +use {crate::ffi::CString, alloc::vec::Vec}; + +bitflags::bitflags! { + /// `O_*` flags for use with [`openpt`] and [`ioctl_tiocgptpeer`]. + /// + /// [`ioctl_tiocgtpeer`]: https://docs.rs/rustix/*/x86_64-unknown-linux-gnu/rustix/pty/fn.ioctl_tiocgtpeer.html + pub struct OpenptFlags: u32 { + /// `O_RDWR` + const RDWR = c::O_RDWR as c::c_uint; + + /// `O_NOCTTY` + #[cfg(not(target_os = "redox"))] + const NOCTTY = c::O_NOCTTY as c::c_uint; + + /// `O_CLOEXEC` + /// + /// The standard `posix_openpt` function doesn't support `CLOEXEC`, but + /// rustix supports it on Linux, and FreeBSD and NetBSD support it. + #[cfg(any(linux_kernel, target_os = "freebsd", target_os = "netbsd"))] + const CLOEXEC = c::O_CLOEXEC as c::c_uint; + } +} + +impl From<OpenptFlags> for OFlags { + #[inline] + fn from(flags: OpenptFlags) -> Self { + // SAFETY: `OpenptFlags` is a subset of `OFlags`. + #[allow(unsafe_code)] + unsafe { + Self::from_bits_unchecked(flags.bits() as _) + } + } +} + +/// `posix_openpt(flags)`—Open a pseudoterminal device. +/// +/// On Linux, an additional `CLOEXEC` flag value may be passed to request the +/// close-on-exec flag be set. +/// +/// On Linux, if the system has no free pseudoterminals available, the +/// underlying system call fails with [`io::Errno::NOSPC`], however this rustix +/// function translates that to [`io::Errno::AGAIN`], so that the linux_raw and +/// libc backends have the same behavior. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [FreeBSD] +/// - [DragonFly BSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [illumos] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_openpt.html +/// [Linux]: https://man7.org/linux/man-pages/man3/posix_openpt.3.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/posix_openpt.3.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=posix_openpt&sektion=2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=posix_openpt§ion=3 +/// [NetBSD]: https://man.netbsd.org/posix_openpt.3 +/// [OpenBSD]: https://man.openbsd.org/posix_openpt +/// [illumos]: https://illumos.org/man/3C/posix_openpt +#[inline] +#[doc(alias = "posix_openpt")] +pub fn openpt(flags: OpenptFlags) -> io::Result<OwnedFd> { + // On Linux, open the device ourselves so that we can support `CLOEXEC`. + #[cfg(linux_kernel)] + { + use crate::fs::{cwd, openat, Mode}; + match openat(cwd(), cstr!("/dev/ptmx"), flags.into(), Mode::empty()) { + // Match libc `openat` behavior with `ENOSPC`. + Err(io::Errno::NOSPC) => Err(io::Errno::AGAIN), + otherwise => otherwise, + } + } + + // On all other platforms, use `openpt`. + #[cfg(not(linux_kernel))] + { + backend::pty::syscalls::openpt(flags) + } +} + +/// `ptsname(fd)`—Return the name of a pseudoterminal. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/ptsname.html +/// [Linux]: https://man7.org/linux/man-pages/man3/ptsname.3.html +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Allocation.html#index-ptsname +#[inline] +#[doc(alias = "ptsname_r")] +#[cfg(any(apple, linux_like, target_os = "freebsd", target_os = "fuchsia"))] +pub fn ptsname<Fd: AsFd, B: Into<Vec<u8>>>(fd: Fd, reuse: B) -> io::Result<CString> { + backend::pty::syscalls::ptsname(fd.as_fd(), reuse.into()) +} + +/// `unlockpt(fd)`—Unlock a pseudoterminal. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlockpt.html +/// [Linux]: https://man7.org/linux/man-pages/man3/unlockpt.3.html +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Allocation.html#index-unlockpt +#[inline] +pub fn unlockpt<Fd: AsFd>(fd: Fd) -> io::Result<()> { + backend::pty::syscalls::unlockpt(fd.as_fd()) +} + +/// `grantpt(fd)`—Grant access to the user side of a pseudoterminal. +/// +/// On Linux, calling this function has no effect, as the kernel is expected to +/// grant the appropriate access. On all other platorms, this function has +/// unspecified behavior if the calling process has a `SIGCHLD` signal handler +/// installed. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/grantpt.html +/// [Linux]: https://man7.org/linux/man-pages/man3/grantpt.3.html +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Allocation.html#index-grantpt +#[inline] +pub fn grantpt<Fd: AsFd>(fd: Fd) -> io::Result<()> { + #[cfg(not(linux_kernel))] + { + backend::pty::syscalls::grantpt(fd.as_fd()) + } + + // On Linux, we assume the kernel has already granted the needed + // permissions to the user side of the pseudoterminal. + #[cfg(linux_kernel)] + { + let _ = fd; + Ok(()) + } +} + +/// `ioctl(fd, TIOCGPTPEER)`—Open the user side of a pseduoterminal. +/// +/// This function is currently only implemented on Linux. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/ioctl_tty.2.html +#[cfg(target_os = "linux")] +#[inline] +pub fn ioctl_tiocgptpeer<Fd: AsFd>(fd: Fd, flags: OpenptFlags) -> io::Result<OwnedFd> { + backend::pty::syscalls::ioctl_tiocgptpeer(fd.as_fd(), flags) +} diff --git a/vendor/rustix-0.37.22/src/rand/getrandom.rs b/vendor/rustix-0.37.22/src/rand/getrandom.rs new file mode 100644 index 000000000..79d5319d5 --- /dev/null +++ b/vendor/rustix-0.37.22/src/rand/getrandom.rs @@ -0,0 +1,21 @@ +use crate::{backend, io}; + +/// `GRND_*` constants for use with `getrandom`. +pub use backend::rand::types::GetRandomFlags; + +/// `getrandom(buf, flags)`—Reads a sequence of random bytes. +/// +/// This is a very low-level API which may be difficult to use correctly. Most +/// users should prefer to use [`getrandom`] or [`rand`] APIs instead. +/// +/// [`getrandom`]: https://crates.io/crates/getrandom +/// [`rand`]: https://crates.io/crates/rand +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/getrandom.2.html +#[inline] +pub fn getrandom(buf: &mut [u8], flags: GetRandomFlags) -> io::Result<usize> { + backend::rand::syscalls::getrandom(buf, flags) +} diff --git a/vendor/rustix-0.37.22/src/rand/mod.rs b/vendor/rustix-0.37.22/src/rand/mod.rs new file mode 100644 index 000000000..e767c590d --- /dev/null +++ b/vendor/rustix-0.37.22/src/rand/mod.rs @@ -0,0 +1,7 @@ +//! Random-related operations. + +#[cfg(linux_kernel)] +mod getrandom; + +#[cfg(linux_kernel)] +pub use getrandom::{getrandom, GetRandomFlags}; diff --git a/vendor/rustix-0.37.22/src/runtime.rs b/vendor/rustix-0.37.22/src/runtime.rs new file mode 100644 index 000000000..9db32776b --- /dev/null +++ b/vendor/rustix-0.37.22/src/runtime.rs @@ -0,0 +1,449 @@ +//! Low-level implementation details for libc-like runtime libraries such as +//! [origin]. +//! +//! Do not use the functions in this module unless you've read all of their +//! code, *and* you know all the relevant internal implementation details of +//! any libc in the process they'll be used. +//! +//! These functions are for implementing thread-local storage (TLS), managing +//! threads, loaded libraries, and other process-wide resources. Most of +//! `rustix` doesn't care about what other libraries are linked into the +//! program or what they're doing, but the features in this module generally +//! can only be used by one entity within a process. +//! +//! The API for these functions is not stable, and this module is +//! `doc(hidden)`. +//! +//! [origin]: https://github.com/sunfishcode/mustang/tree/main/origin +//! +//! # Safety +//! +//! This module is intended to be used for implementing a runtime library such +//! as libc. Use of these features for any other purpose is likely to create +//! serious problems. +#![allow(unsafe_code)] + +use crate::backend; +#[cfg(linux_raw)] +use crate::ffi::CStr; +#[cfg(linux_raw)] +#[cfg(feature = "fs")] +use crate::fs::AtFlags; +#[cfg(linux_raw)] +use crate::io; +#[cfg(linux_raw)] +use crate::process::{Pid, Signal}; +#[cfg(linux_raw)] +#[cfg(feature = "fs")] +use backend::fd::AsFd; +#[cfg(linux_raw)] +use core::ffi::c_void; + +/// `sigaction` +#[cfg(linux_raw)] +pub type Sigaction = linux_raw_sys::general::kernel_sigaction; + +/// `stack_t` +#[cfg(linux_raw)] +pub type Stack = linux_raw_sys::general::stack_t; + +/// `sigset_t` +#[cfg(linux_raw)] +pub type Sigset = linux_raw_sys::general::kernel_sigset_t; + +/// `siginfo_t` +#[cfg(linux_raw)] +pub type Siginfo = linux_raw_sys::general::siginfo_t; + +pub use backend::time::types::{Nsecs, Secs, Timespec}; + +/// `SIG_*` constants for use with [`sigprocmask`]. +#[cfg(linux_raw)] +#[repr(u32)] +pub enum How { + /// `SIG_BLOCK` + BLOCK = linux_raw_sys::general::SIG_BLOCK, + + /// `SIG_UNBLOCK` + UNBLOCK = linux_raw_sys::general::SIG_UNBLOCK, + + /// `SIG_SETMASK` + SETMASK = linux_raw_sys::general::SIG_SETMASK, +} + +#[cfg(linux_raw)] +#[cfg(target_arch = "x86")] +#[inline] +pub unsafe fn set_thread_area(u_info: &mut UserDesc) -> io::Result<()> { + backend::runtime::syscalls::tls::set_thread_area(u_info) +} + +#[cfg(linux_raw)] +#[cfg(target_arch = "arm")] +#[inline] +pub unsafe fn arm_set_tls(data: *mut c_void) -> io::Result<()> { + backend::runtime::syscalls::tls::arm_set_tls(data) +} + +/// `prctl(PR_SET_FS, data)`—Set the x86_64 `fs` register. +/// +/// # Safety +/// +/// This is a very low-level feature for implementing threading libraries. +/// See the references links above. +#[cfg(linux_raw)] +#[cfg(target_arch = "x86_64")] +#[inline] +pub unsafe fn set_fs(data: *mut c_void) { + backend::runtime::syscalls::tls::set_fs(data) +} + +/// Set the x86_64 thread ID address. +/// +/// # Safety +/// +/// This is a very low-level feature for implementing threading libraries. +/// See the references links above. +#[cfg(linux_raw)] +#[inline] +pub unsafe fn set_tid_address(data: *mut c_void) -> Pid { + backend::runtime::syscalls::tls::set_tid_address(data) +} + +/// `prctl(PR_SET_NAME, name)` +/// +/// # References +/// - [Linux] +/// +/// # Safety +/// +/// This is a very low-level feature for implementing threading libraries. +/// See the references links above. +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[cfg(linux_raw)] +#[inline] +pub unsafe fn set_thread_name(name: &CStr) -> io::Result<()> { + backend::runtime::syscalls::tls::set_thread_name(name) +} + +#[cfg(linux_raw)] +#[cfg(target_arch = "x86")] +pub use backend::runtime::tls::UserDesc; + +/// `syscall(SYS_exit, status)`—Exit the current thread. +/// +/// # Safety +/// +/// This is a very low-level feature for implementing threading libraries. +#[cfg(linux_raw)] +#[inline] +pub unsafe fn exit_thread(status: i32) -> ! { + backend::runtime::syscalls::tls::exit_thread(status) +} + +/// Exit all the threads in the current process' thread group. +/// +/// This is equivalent to `_exit` and `_Exit` in libc. +/// +/// This does not all any `__cxa_atexit`, `atexit`, or any other destructors. +/// Most programs should use [`std::process::exit`] instead of calling this +/// directly. +/// +/// # References +/// - [POSIX `_Exit`] +/// - [Linux `exit_group`] +/// - [Linux `_Exit`] +/// +/// [POSIX `_Exit`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/_Exit.html +/// [Linux `exit_group`]: https://man7.org/linux/man-pages/man2/exit_group.2.html +/// [Linux `_Exit`]: https://man7.org/linux/man-pages/man2/_Exit.2.html +#[doc(alias = "_exit")] +#[doc(alias = "_Exit")] +#[inline] +pub fn exit_group(status: i32) -> ! { + backend::process::syscalls::exit_group(status) +} + +/// Return fields from the main executable segment headers ("phdrs") relevant +/// to initializing TLS provided to the program at startup. +#[cfg(linux_raw)] +#[inline] +pub fn startup_tls_info() -> StartupTlsInfo { + backend::runtime::tls::startup_tls_info() +} + +/// `(getauxval(AT_PHDR), getauxval(AT_PHNUM))`—Returns the address and +/// number of ELF segment headers for the main executable. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man3/getauxval.3.html +#[cfg(linux_raw)] +#[cfg(linux_kernel)] +#[inline] +pub fn exe_phdrs() -> (*const c_void, usize) { + backend::param::auxv::exe_phdrs() +} + +#[cfg(linux_raw)] +pub use backend::runtime::tls::StartupTlsInfo; + +/// `fork()`—Creates a new process by duplicating the calling process. +/// +/// On success, the pid of the child process is returned in the parent, and +/// `None` is returned in the child. +/// +/// Unlike its POSIX and libc counterparts, this `fork` does not invoke any +/// handlers (such as those registered with `pthread_atfork`). +/// +/// The program environment in the child after a `fork` and before an `execve` +/// is very special. All code that executes in this environment must avoid: +/// +/// - Acquiring any other locks that are held in other threads on the parent +/// at the time of the `fork`, as the child only contains one thread, and +/// attempting to acquire such locks will deadlock (though this is [not +/// considered unsafe]). +/// +/// - Performing any dynamic allocation using the global allocator, since +/// global allocators may use locks to ensure thread safety, and their locks +/// may not be released in the child process, so attempts to allocate may +/// deadlock (as described in the previous point). +/// +/// - Accessing any external state which the parent assumes it has exclusive +/// access to, such as a file protected by a file lock, as this could +/// corrupt the external state. +/// +/// - Accessing any random-number-generator state inherited from the parent, +/// as the parent may have the same state and generate the same random +/// numbers, which may violate security invariants. +/// +/// - Accessing any thread runtime state, since this function does not update +/// the thread id in the thread runtime, so thread runtime functions could +/// cause undefined behavior. +/// +/// - Accessing any memory shared with the parent, such as a [`MAP_SHARED`] +/// mapping, even with anonymous or [`memfd_create`] mappings, as this could +/// cause undefined behavior. +/// +/// - Calling any C function which isn't known to be [async-signal-safe], as +/// that could cause undefined behavior. The extent to which this also +/// applies to Rust functions is unclear at this time. +/// +/// # Safety +/// +/// The child must avoid accessing any memory shared with the parent in a +/// way that invokes undefined behavior. It must avoid accessing any threading +/// runtime functions in a way that invokes undefined behavior. And it must +/// avoid invoking any undefined behavior through any function that is not +/// guaranteed to be async-signal-safe. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// # Literary interlude +/// +/// > Do not jump on ancient uncles. +/// > Do not yell at average mice. +/// > Do not wear a broom to breakfast. +/// > Do not ask a snake’s advice. +/// > Do not bathe in chocolate pudding. +/// > Do not talk to bearded bears. +/// > Do not smoke cigars on sofas. +/// > Do not dance on velvet chairs. +/// > Do not take a whale to visit +/// > Russell’s mother’s cousin’s yacht. +/// > And whatever else you do do +/// > It is better you +/// > Do not. +/// +/// - “Rules”, by Karla Kuskin +/// +/// [`MAP_SHARED`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html +/// [not considered unsafe]: https://doc.rust-lang.org/reference/behavior-not-considered-unsafe.html#deadlocks +/// [`memfd_create`]: https://man7.org/linux/man-pages/man2/memfd_create.2.html +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html +/// [Linux]: https://man7.org/linux/man-pages/man2/fork.2.html +/// [async-signal-safe]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04_03 +#[cfg(linux_raw)] +pub unsafe fn fork() -> io::Result<Option<Pid>> { + backend::runtime::syscalls::fork() +} + +/// `execveat(dirfd, path.as_c_str(), argv, envp, flags)`—Execute a new +/// command using the current process. +/// +/// # Safety +/// +/// The `argv` and `envp` pointers must point to NUL-terminated arrays, and +/// their contents must be pointers to NUL-terminated byte arrays. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/execveat.2.html +#[cfg(linux_raw)] +#[inline] +#[cfg(feature = "fs")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "fs")))] +pub unsafe fn execveat<Fd: AsFd>( + dirfd: Fd, + path: &CStr, + argv: *const *const u8, + envp: *const *const u8, + flags: AtFlags, +) -> io::Errno { + backend::runtime::syscalls::execveat(dirfd.as_fd(), path, argv, envp, flags) +} + +/// `execve(path.as_c_str(), argv, envp)`—Execute a new command using the +/// current process. +/// +/// # Safety +/// +/// The `argv` and `envp` pointers must point to NUL-terminated arrays, and +/// their contents must be pointers to NUL-terminated byte arrays. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/execve.2.html +#[cfg(linux_raw)] +#[inline] +pub unsafe fn execve(path: &CStr, argv: *const *const u8, envp: *const *const u8) -> io::Errno { + backend::runtime::syscalls::execve(path, argv, envp) +} + +/// `sigaction(signal, &new, &old)`—Modify or query a signal handler. +/// +/// # Safety +/// +/// You're on your own. And on top of all the troubles with signal handlers, +/// this implementation is highly experimental. Even further, it differs from +/// the libc `sigaction` in several non-obvious and unsafe ways. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigaction.html +/// [Linux]: https://man7.org/linux/man-pages/man2/sigaction.2.html +#[cfg(linux_raw)] +#[inline] +pub unsafe fn sigaction(signal: Signal, new: Option<Sigaction>) -> io::Result<Sigaction> { + backend::runtime::syscalls::sigaction(signal, new) +} + +/// `sigaltstack(new, old)`—Modify or query a signal stack. +/// +/// # Safety +/// +/// You're on your own. And on top of all the troubles with signal handlers, +/// this implementation is highly experimental. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigaltstack.html +/// [Linux]: https://man7.org/linux/man-pages/man2/sigaltstack.2.html +#[cfg(linux_raw)] +#[inline] +pub unsafe fn sigaltstack(new: Option<Stack>) -> io::Result<Stack> { + backend::runtime::syscalls::sigaltstack(new) +} + +/// `tkill(tid, sig)`—Send a signal to a thread. +/// +/// # Safety +/// +/// You're on your own. And on top of all the troubles with signal handlers, +/// this implementation is highly experimental. The warning about the hazard +/// of recycled thread ID's applies. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/tkill.2.html +#[cfg(linux_raw)] +#[inline] +pub unsafe fn tkill(tid: Pid, sig: Signal) -> io::Result<()> { + backend::runtime::syscalls::tkill(tid, sig) +} + +/// `sigprocmask(how, set, oldset)`—Adjust the process signal mask. +/// +/// # Safety +/// +/// You're on your own. And on top of all the troubles with signal handlers, +/// this implementation is highly experimental. Even further, it differs from +/// the libc `sigprocmask` in several non-obvious and unsafe ways. +/// +/// # References +/// - [Linux `sigprocmask`] +/// - [Linux `pthread_sigmask`] +/// +/// [Linux `sigprocmask`]: https://man7.org/linux/man-pages/man2/sigprocmask.2.html +/// [Linux `pthread_sigmask`]: https://man7.org/linux/man-pages/man3/pthread_sigmask.3.html +#[cfg(linux_raw)] +#[inline] +#[doc(alias = "pthread_sigmask")] +pub unsafe fn sigprocmask(how: How, set: Option<&Sigset>) -> io::Result<Sigset> { + backend::runtime::syscalls::sigprocmask(how, set) +} + +/// `sigwait(set)`—Wait for signals. +/// +/// # Safety +/// +/// If code elsewhere in the process is depending on delivery of a signal to +/// prevent it from executing some code, this could cause it to miss that +/// signal and execute that code. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man3/sigwait.3.html +#[cfg(linux_raw)] +#[inline] +pub unsafe fn sigwait(set: &Sigset) -> io::Result<Signal> { + backend::runtime::syscalls::sigwait(set) +} + +/// `sigwait(set)`—Wait for signals, returning a [`Siginfo`]. +/// +/// # Safety +/// +/// If code elsewhere in the process is depending on delivery of a signal to +/// prevent it from executing some code, this could cause it to miss that +/// signal and execute that code. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/sigwaitinfo.2.html +#[cfg(linux_raw)] +#[inline] +pub unsafe fn sigwaitinfo(set: &Sigset) -> io::Result<Siginfo> { + backend::runtime::syscalls::sigwaitinfo(set) +} + +/// `sigtimedwait(set)`—Wait for signals, optionally with a timeout. +/// +/// # Safety +/// +/// If code elsewhere in the process is depending on delivery of a signal to +/// prevent it from executing some code, this could cause it to miss that +/// signal and execute that code. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/sigtimedwait.2.html +#[cfg(linux_raw)] +#[inline] +pub unsafe fn sigtimedwait(set: &Sigset, timeout: Option<Timespec>) -> io::Result<Siginfo> { + backend::runtime::syscalls::sigtimedwait(set, timeout) +} diff --git a/vendor/rustix-0.37.22/src/termios/cf.rs b/vendor/rustix-0.37.22/src/termios/cf.rs new file mode 100644 index 000000000..d79eab5c8 --- /dev/null +++ b/vendor/rustix-0.37.22/src/termios/cf.rs @@ -0,0 +1,40 @@ +use crate::termios::{Speed, Termios}; +use crate::{backend, io}; + +/// `cfgetospeed(termios)` +#[inline] +#[must_use] +pub fn cfgetospeed(termios: &Termios) -> Speed { + backend::termios::syscalls::cfgetospeed(termios) +} + +/// `cfgetispeed(termios)` +#[inline] +#[must_use] +pub fn cfgetispeed(termios: &Termios) -> Speed { + backend::termios::syscalls::cfgetispeed(termios) +} + +/// `cfmakeraw(termios)` +#[inline] +pub fn cfmakeraw(termios: &mut Termios) { + backend::termios::syscalls::cfmakeraw(termios) +} + +/// `cfsetospeed(termios, speed)` +#[inline] +pub fn cfsetospeed(termios: &mut Termios, speed: Speed) -> io::Result<()> { + backend::termios::syscalls::cfsetospeed(termios, speed) +} + +/// `cfsetispeed(termios, speed)` +#[inline] +pub fn cfsetispeed(termios: &mut Termios, speed: Speed) -> io::Result<()> { + backend::termios::syscalls::cfsetispeed(termios, speed) +} + +/// `cfsetspeed(termios, speed)` +#[inline] +pub fn cfsetspeed(termios: &mut Termios, speed: Speed) -> io::Result<()> { + backend::termios::syscalls::cfsetspeed(termios, speed) +} diff --git a/vendor/rustix-0.37.22/src/termios/constants.rs b/vendor/rustix-0.37.22/src/termios/constants.rs new file mode 100644 index 000000000..99b75c06e --- /dev/null +++ b/vendor/rustix-0.37.22/src/termios/constants.rs @@ -0,0 +1,101 @@ +use crate::backend; + +pub use backend::termios::types::*; + +/// Translate from a `Speed` code to a speed value `u32`. +/// +/// ``` +/// let speed = rustix::termios::speed_value(rustix::termios::B57600); +/// assert_eq!(speed, Some(57600)); +/// ``` +pub fn speed_value(speed: backend::termios::types::Speed) -> Option<u32> { + match speed { + backend::termios::types::B0 => Some(0), + backend::termios::types::B50 => Some(50), + backend::termios::types::B75 => Some(75), + backend::termios::types::B110 => Some(110), + backend::termios::types::B134 => Some(134), + backend::termios::types::B150 => Some(150), + backend::termios::types::B200 => Some(200), + backend::termios::types::B300 => Some(300), + backend::termios::types::B600 => Some(600), + backend::termios::types::B1200 => Some(1200), + backend::termios::types::B1800 => Some(1800), + backend::termios::types::B2400 => Some(2400), + backend::termios::types::B4800 => Some(4800), + backend::termios::types::B9600 => Some(9600), + backend::termios::types::B19200 => Some(19200), + backend::termios::types::B38400 => Some(38400), + #[cfg(not(target_os = "aix"))] + backend::termios::types::B57600 => Some(57600), + #[cfg(not(target_os = "aix"))] + backend::termios::types::B115200 => Some(115_200), + #[cfg(not(target_os = "aix"))] + backend::termios::types::B230400 => Some(230_400), + #[cfg(not(any( + apple, + target_os = "aix", + target_os = "dragonfly", + target_os = "haiku", + target_os = "openbsd" + )))] + backend::termios::types::B460800 => Some(460_800), + #[cfg(not(any(bsd, solarish, target_os = "aix", target_os = "haiku")))] + backend::termios::types::B500000 => Some(500_000), + #[cfg(not(any(bsd, solarish, target_os = "aix", target_os = "haiku")))] + backend::termios::types::B576000 => Some(576_000), + #[cfg(not(any( + apple, + target_os = "aix", + target_os = "dragonfly", + target_os = "haiku", + target_os = "openbsd" + )))] + backend::termios::types::B921600 => Some(921_600), + #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "solaris")))] + backend::termios::types::B1000000 => Some(1_000_000), + #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "solaris")))] + backend::termios::types::B1152000 => Some(1_152_000), + #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "solaris")))] + backend::termios::types::B1500000 => Some(1_500_000), + #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "solaris")))] + backend::termios::types::B2000000 => Some(2_000_000), + #[cfg(not(any( + target_arch = "sparc", + target_arch = "sparc64", + bsd, + target_os = "aix", + target_os = "haiku", + target_os = "solaris", + )))] + backend::termios::types::B2500000 => Some(2_500_000), + #[cfg(not(any( + target_arch = "sparc", + target_arch = "sparc64", + bsd, + target_os = "aix", + target_os = "haiku", + target_os = "solaris", + )))] + backend::termios::types::B3000000 => Some(3_000_000), + #[cfg(not(any( + target_arch = "sparc", + target_arch = "sparc64", + bsd, + target_os = "aix", + target_os = "haiku", + target_os = "solaris", + )))] + backend::termios::types::B3500000 => Some(3_500_000), + #[cfg(not(any( + target_arch = "sparc", + target_arch = "sparc64", + bsd, + target_os = "aix", + target_os = "haiku", + target_os = "solaris", + )))] + backend::termios::types::B4000000 => Some(4_000_000), + _ => None, + } +} diff --git a/vendor/rustix-0.37.22/src/termios/mod.rs b/vendor/rustix-0.37.22/src/termios/mod.rs new file mode 100644 index 000000000..ffbb1b663 --- /dev/null +++ b/vendor/rustix-0.37.22/src/termios/mod.rs @@ -0,0 +1,19 @@ +//! Terminal I/O stream operations. + +#[cfg(not(target_os = "wasi"))] +mod cf; +#[cfg(not(target_os = "wasi"))] +mod constants; +#[cfg(not(target_os = "wasi"))] +mod tc; +#[cfg(not(windows))] +mod tty; + +#[cfg(not(target_os = "wasi"))] +pub use cf::*; +#[cfg(not(target_os = "wasi"))] +pub use constants::*; +#[cfg(not(target_os = "wasi"))] +pub use tc::*; +#[cfg(not(windows))] +pub use tty::*; diff --git a/vendor/rustix-0.37.22/src/termios/tc.rs b/vendor/rustix-0.37.22/src/termios/tc.rs new file mode 100644 index 000000000..64a7845b9 --- /dev/null +++ b/vendor/rustix-0.37.22/src/termios/tc.rs @@ -0,0 +1,276 @@ +use crate::fd::AsFd; +use crate::process::Pid; +use crate::{backend, io}; + +#[cfg(all( + linux_kernel, + 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 use backend::termios::types::Termios2; +pub use backend::termios::types::{ + Action, OptionalActions, QueueSelector, Speed, Tcflag, Termios, Winsize, +}; + +/// `tcgetattr(fd)`—Get terminal attributes. +/// +/// Also known as the `TCGETS` operation with `ioctl`. +/// +/// # References +/// - [POSIX `tcgetattr`] +/// - [Linux `ioctl_tty`] +/// - [Linux `termios`] +/// +/// [POSIX `tcgetattr`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetattr.html +/// [Linux `ioctl_tty`]: https://man7.org/linux/man-pages/man4/tty_ioctl.4.html +/// [Linux `termios`]: https://man7.org/linux/man-pages/man3/termios.3.html +#[cfg(not(any(windows, target_os = "wasi")))] +#[inline] +#[doc(alias = "TCGETS")] +pub fn tcgetattr<Fd: AsFd>(fd: Fd) -> io::Result<Termios> { + backend::termios::syscalls::tcgetattr(fd.as_fd()) +} + +/// `tcgetattr2(fd)`—Get terminal attributes. +/// +/// Also known as the `TCGETS2` operation with `ioctl`. +/// +/// # References +/// - [POSIX `tcgetattr`] +/// - [Linux `ioctl_tty`] +/// - [Linux `termios`] +/// +/// [POSIX `tcgetattr`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetattr.html +/// [Linux `ioctl_tty`]: https://man7.org/linux/man-pages/man4/tty_ioctl.4.html +/// [Linux `termios`]: https://man7.org/linux/man-pages/man3/termios.3.html +#[inline] +#[doc(alias = "TCGETS2")] +#[cfg(all( + linux_kernel, + 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 fn tcgetattr2<Fd: AsFd>(fd: Fd) -> io::Result<Termios2> { + backend::termios::syscalls::tcgetattr2(fd.as_fd()) +} + +/// `tcgetwinsize(fd)`—Get the current terminal window size. +/// +/// Also known as the `TIOCGWINSZ` operation with `ioctl`. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man4/tty_ioctl.4.html +#[cfg(not(any(windows, target_os = "wasi")))] +#[inline] +#[doc(alias = "TIOCGWINSZ")] +pub fn tcgetwinsize<Fd: AsFd>(fd: Fd) -> io::Result<Winsize> { + backend::termios::syscalls::tcgetwinsize(fd.as_fd()) +} + +/// `tcgetpgrp(fd)`—Get the terminal foreground process group. +/// +/// Also known as the `TIOCGPGRP` operation with `ioctl`. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetpgrp.html +/// [Linux]: https://man7.org/linux/man-pages/man3/tcgetpgrp.3.html +#[cfg(not(any(windows, target_os = "wasi")))] +#[inline] +#[doc(alias = "TIOCGPGRP")] +pub fn tcgetpgrp<Fd: AsFd>(fd: Fd) -> io::Result<Pid> { + backend::termios::syscalls::tcgetpgrp(fd.as_fd()) +} + +/// `tcsetpgrp(fd, pid)`—Set the terminal foreground process group. +/// +/// Also known as the `TIOCSPGRP` operation with `ioctl`. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetpgrp.html +/// [Linux]: https://man7.org/linux/man-pages/man3/tcsetpgrp.3.html +#[cfg(not(any(windows, target_os = "wasi")))] +#[inline] +#[doc(alias = "TIOCSPGRP")] +pub fn tcsetpgrp<Fd: AsFd>(fd: Fd, pid: Pid) -> io::Result<()> { + backend::termios::syscalls::tcsetpgrp(fd.as_fd(), pid) +} + +/// `tcsetattr(fd)`—Set terminal attributes. +/// +/// Also known as the `TCSETS` operation with `ioctl`. +/// +/// # References +/// - [POSIX `tcsetattr`] +/// - [Linux `ioctl_tty`] +/// - [Linux `termios`] +/// +/// [POSIX `tcsetattr`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetattr.html +/// [Linux `ioctl_tty`]: https://man7.org/linux/man-pages/man4/tty_ioctl.4.html +/// [Linux `termios`]: https://man7.org/linux/man-pages/man3/termios.3.html +#[inline] +#[doc(alias = "TCSETS")] +pub fn tcsetattr<Fd: AsFd>( + fd: Fd, + optional_actions: OptionalActions, + termios: &Termios, +) -> io::Result<()> { + backend::termios::syscalls::tcsetattr(fd.as_fd(), optional_actions, termios) +} + +/// `tcsetattr2(fd)`—Set terminal attributes. +/// +/// Also known as the `TCSETS2` operation with `ioctl`. +/// +/// # References +/// - [POSIX `tcsetattr`] +/// - [Linux `ioctl_tty`] +/// - [Linux `termios`] +/// +/// [POSIX `tcsetattr`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetattr.html +/// [Linux `ioctl_tty`]: https://man7.org/linux/man-pages/man4/tty_ioctl.4.html +/// [Linux `termios`]: https://man7.org/linux/man-pages/man3/termios.3.html +#[inline] +#[doc(alias = "TCSETS2")] +#[cfg(all( + linux_kernel, + 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 fn tcsetattr2<Fd: AsFd>( + fd: Fd, + optional_actions: OptionalActions, + termios: &Termios2, +) -> io::Result<()> { + backend::termios::syscalls::tcsetattr2(fd.as_fd(), optional_actions, termios) +} + +/// `tcsendbreak(fd, 0)`—Transmit zero-valued bits. +/// +/// Also known as the `TCSBRK` operation with `ioctl`, with a duration of 0. +/// +/// This function always uses an effective duration parameter of zero. For the +/// equivalent of a `tcsendbreak` with a non-zero duration parameter, use +/// `tcdrain`. +/// +/// # References +/// - [POSIX `tcsendbreak`] +/// - [Linux `ioctl_tty`] +/// - [Linux `termios`] +/// +/// [POSIX `tcsendbreak`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsendbreak.html +/// [Linux `ioctl_tty`]: https://man7.org/linux/man-pages/man4/tty_ioctl.4.html +/// [Linux `termios`]: https://man7.org/linux/man-pages/man3/termios.3.html +#[inline] +#[doc(alias = "TCSBRK")] +pub fn tcsendbreak<Fd: AsFd>(fd: Fd) -> io::Result<()> { + backend::termios::syscalls::tcsendbreak(fd.as_fd()) +} + +/// `tcdrain(fd, duration)`—Wait until all pending output has been written. +/// +/// # References +/// - [POSIX `tcdrain`] +/// - [Linux `ioctl_tty`] +/// - [Linux `termios`] +/// +/// [POSIX `tcsetattr`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcdrain.html +/// [Linux `ioctl_tty`]: https://man7.org/linux/man-pages/man4/tty_ioctl.4.html +/// [Linux `termios`]: https://man7.org/linux/man-pages/man3/termios.3.html +#[inline] +pub fn tcdrain<Fd: AsFd>(fd: Fd) -> io::Result<()> { + backend::termios::syscalls::tcdrain(fd.as_fd()) +} + +/// `tcflush(fd, queue_selector)`—Wait until all pending output has been +/// written. +/// +/// # References +/// - [POSIX `tcflush`] +/// - [Linux `ioctl_tty`] +/// - [Linux `termios`] +/// +/// [POSIX `tcflush`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcflush.html +/// [Linux `ioctl_tty`]: https://man7.org/linux/man-pages/man4/tty_ioctl.4.html +/// [Linux `termios`]: https://man7.org/linux/man-pages/man3/termios.3.html +#[inline] +#[doc(alias = "TCFLSH")] +pub fn tcflush<Fd: AsFd>(fd: Fd, queue_selector: QueueSelector) -> io::Result<()> { + backend::termios::syscalls::tcflush(fd.as_fd(), queue_selector) +} + +/// `tcflow(fd, action)`—Suspend or resume transmission or reception. +/// +/// # References +/// - [POSIX `tcflow`] +/// - [Linux `ioctl_tty`] +/// - [Linux `termios`] +/// +/// [POSIX `tcflow`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcflow.html +/// [Linux `ioctl_tty`]: https://man7.org/linux/man-pages/man4/tty_ioctl.4.html +/// [Linux `termios`]: https://man7.org/linux/man-pages/man3/termios.3.html +#[inline] +#[doc(alias = "TCXONC")] +pub fn tcflow<Fd: AsFd>(fd: Fd, action: Action) -> io::Result<()> { + backend::termios::syscalls::tcflow(fd.as_fd(), action) +} + +/// `tcgetsid(fd)`—Return the session ID of the current session with `fd` as +/// its controlling terminal. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetsid.html +/// [Linux]: https://man7.org/linux/man-pages/man3/tcgetsid.3.html +#[inline] +#[doc(alias = "TIOCGSID")] +pub fn tcgetsid<Fd: AsFd>(fd: Fd) -> io::Result<Pid> { + backend::termios::syscalls::tcgetsid(fd.as_fd()) +} + +/// `tcsetwinsize(fd)`—Set the current terminal window size. +/// +/// Also known as the `TIOCSWINSZ` operation with `ioctl`. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man4/tty_ioctl.4.html +#[inline] +#[doc(alias = "TIOCSWINSZ")] +pub fn tcsetwinsize<Fd: AsFd>(fd: Fd, winsize: Winsize) -> io::Result<()> { + backend::termios::syscalls::tcsetwinsize(fd.as_fd(), winsize) +} diff --git a/vendor/rustix-0.37.22/src/termios/tty.rs b/vendor/rustix-0.37.22/src/termios/tty.rs new file mode 100644 index 000000000..0fcf1d5f2 --- /dev/null +++ b/vendor/rustix-0.37.22/src/termios/tty.rs @@ -0,0 +1,66 @@ +//! Functions which operate on file descriptors which might be terminals. + +use crate::backend; +use backend::fd::AsFd; +#[cfg(feature = "procfs")] +#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))] +use { + crate::ffi::CString, crate::io, crate::path::SMALL_PATH_BUFFER_SIZE, alloc::vec::Vec, + backend::fd::BorrowedFd, +}; + +/// `isatty(fd)`—Tests whether a file descriptor refers to a terminal. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/isatty.html +/// [Linux]: https://man7.org/linux/man-pages/man3/isatty.3.html +#[inline] +pub fn isatty<Fd: AsFd>(fd: Fd) -> bool { + backend::termios::syscalls::isatty(fd.as_fd()) +} + +/// `ttyname_r(fd)` +/// +/// If `reuse` is non-empty, reuse its buffer to store the result if possible. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/ttyname.html +/// [Linux]: https://man7.org/linux/man-pages/man3/ttyname.3.html +#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))] +#[cfg(feature = "procfs")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "procfs")))] +#[doc(alias = "ttyname_r")] +#[inline] +pub fn ttyname<Fd: AsFd, B: Into<Vec<u8>>>(dirfd: Fd, reuse: B) -> io::Result<CString> { + _ttyname(dirfd.as_fd(), reuse.into()) +} + +#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))] +#[cfg(feature = "procfs")] +fn _ttyname(dirfd: BorrowedFd<'_>, mut buffer: Vec<u8>) -> io::Result<CString> { + // This code would benefit from having a better way to read into + // uninitialized memory, but that requires `unsafe`. + buffer.clear(); + buffer.reserve(SMALL_PATH_BUFFER_SIZE); + buffer.resize(buffer.capacity(), 0_u8); + + loop { + match backend::termios::syscalls::ttyname(dirfd, &mut buffer) { + Err(io::Errno::RANGE) => { + buffer.reserve(1); // use `Vec` reallocation strategy to grow capacity exponentially + buffer.resize(buffer.capacity(), 0_u8); + } + Ok(len) => { + buffer.resize(len, 0_u8); + return Ok(CString::new(buffer).unwrap()); + } + Err(errno) => return Err(errno), + } + } +} diff --git a/vendor/rustix-0.37.22/src/thread/clock.rs b/vendor/rustix-0.37.22/src/thread/clock.rs new file mode 100644 index 000000000..620cb4ec0 --- /dev/null +++ b/vendor/rustix-0.37.22/src/thread/clock.rs @@ -0,0 +1,95 @@ +use crate::{backend, io}; + +pub use backend::time::types::Timespec; + +#[cfg(not(any( + apple, + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", // FreeBSD 12 has clock_nanosleep, but libc targets FreeBSD 11. + target_os = "openbsd", + target_os = "redox", + target_os = "wasi", +)))] +pub use backend::time::types::ClockId; + +/// `clock_nanosleep(id, 0, request, remain)`—Sleeps for a duration on a +/// given clock. +/// +/// This is `clock_nanosleep` specialized for the case of a relative sleep +/// interval. See [`clock_nanosleep_absolute`] for absolute intervals. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_nanosleep.html +/// [Linux]: https://man7.org/linux/man-pages/man2/clock_nanosleep.2.html +#[cfg(not(any( + apple, + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", // FreeBSD 12 has clock_nanosleep, but libc targets FreeBSD 11. + target_os = "haiku", + target_os = "openbsd", + target_os = "redox", + target_os = "wasi", +)))] +#[inline] +pub fn clock_nanosleep_relative(id: ClockId, request: &Timespec) -> NanosleepRelativeResult { + backend::thread::syscalls::clock_nanosleep_relative(id, request) +} + +/// `clock_nanosleep(id, TIMER_ABSTIME, request, NULL)`—Sleeps until an +/// absolute time on a given clock. +/// +/// This is `clock_nanosleep` specialized for the case of an absolute sleep +/// interval. See [`clock_nanosleep_relative`] for relative intervals. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_nanosleep.html +/// [Linux]: https://man7.org/linux/man-pages/man2/clock_nanosleep.2.html +#[cfg(not(any( + apple, + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", // FreeBSD 12 has clock_nanosleep, but libc targets FreeBSD 11. + target_os = "haiku", + target_os = "openbsd", + target_os = "redox", + target_os = "wasi", +)))] +#[inline] +pub fn clock_nanosleep_absolute(id: ClockId, request: &Timespec) -> io::Result<()> { + backend::thread::syscalls::clock_nanosleep_absolute(id, request) +} + +/// `nanosleep(request, remain)`—Sleeps for a duration. +/// +/// This effectively uses the system monotonic clock. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/nanosleep.html +/// [Linux]: https://man7.org/linux/man-pages/man2/nanosleep.2.html +#[inline] +pub fn nanosleep(request: &Timespec) -> NanosleepRelativeResult { + backend::thread::syscalls::nanosleep(request) +} + +/// A return type for `nanosleep` and `clock_nanosleep_relative`. +#[derive(Debug, Clone)] +#[must_use] +pub enum NanosleepRelativeResult { + /// The sleep completed normally. + Ok, + /// The sleep was interrupted, the remaining time is returned. + Interrupted(Timespec), + /// An invalid time value was provided. + Err(io::Errno), +} diff --git a/vendor/rustix-0.37.22/src/thread/futex.rs b/vendor/rustix-0.37.22/src/thread/futex.rs new file mode 100644 index 000000000..7c4399f7a --- /dev/null +++ b/vendor/rustix-0.37.22/src/thread/futex.rs @@ -0,0 +1,38 @@ +//! Linux `futex`. +//! +//! # Safety +//! +//! Futex is a very low-level mechanism for implementing concurrency +//! primitives. +#![allow(unsafe_code)] + +use crate::thread::Timespec; +use crate::{backend, io}; + +pub use backend::thread::{FutexFlags, FutexOperation}; + +/// `futex(uaddr, op, val, utime, uaddr2, val3)` +/// +/// # References +/// - [Linux `futex` system call] +/// - [Linux `futex` feature] +/// +/// # Safety +/// +/// This is a very low-level feature for implementing synchronization +/// primitives. See the references links above. +/// +/// [Linux `futex` system call]: https://man7.org/linux/man-pages/man2/futex.2.html +/// [Linux `futex` feature]: https://man7.org/linux/man-pages/man7/futex.7.html +#[inline] +pub unsafe fn futex( + uaddr: *mut u32, + op: FutexOperation, + flags: FutexFlags, + val: u32, + utime: *const Timespec, + uaddr2: *mut u32, + val3: u32, +) -> io::Result<usize> { + backend::thread::syscalls::futex(uaddr, op, flags, val, utime, uaddr2, val3) +} diff --git a/vendor/rustix-0.37.22/src/thread/id.rs b/vendor/rustix-0.37.22/src/thread/id.rs new file mode 100644 index 000000000..3143b068b --- /dev/null +++ b/vendor/rustix-0.37.22/src/thread/id.rs @@ -0,0 +1,113 @@ +use crate::process::{Gid, Pid, Uid}; +use crate::{backend, io}; + +/// `gettid()`—Returns the thread ID. +/// +/// This returns the OS thread ID, which is not necessarily the same as the +/// `rust::thread::Thread::id` or the pthread ID. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/gettid.2.html +#[inline] +#[must_use] +pub fn gettid() -> Pid { + backend::thread::syscalls::gettid() +} + +/// `setuid(uid)` +/// +/// # Warning +/// +/// This is not the setxid you are looking for... POSIX requires xids to be +/// process granular, but on Linux they are per-thread. Thus, this call only +/// changes the xid for the current *thread*, not the entire process even +/// though that is in violation of the POSIX standard. +/// +/// For details on this distinction, see the C library vs. kernel differences +/// in the [manual page][linux_notes]. This call implements the kernel +/// behavior. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setuid.html +/// [Linux]: https://man7.org/linux/man-pages/man2/setuid.2.html +/// [linux_notes]: https://man7.org/linux/man-pages/man2/setuid.2.html#NOTES +#[inline] +pub fn set_thread_uid(uid: Uid) -> io::Result<()> { + backend::thread::syscalls::setuid_thread(uid) +} + +/// `setresuid(ruid, euid, suid)` +/// +/// # Warning +/// +/// This is not the setresxid you are looking for... POSIX requires xids to be +/// process granular, but on Linux they are per-thread. Thus, this call only +/// changes the xid for the current *thread*, not the entire process even +/// though that is in violation of the POSIX standard. +/// +/// For details on this distinction, see the C library vs. kernel differences +/// in the [manual page][linux_notes] and the notes in [`set_thread_uid`]. This +/// call implements the kernel behavior. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/setresuid.2.html +/// [linux_notes]: https://man7.org/linux/man-pages/man2/setresuid.2.html#NOTES +#[inline] +pub fn set_thread_res_uid(ruid: Uid, euid: Uid, suid: Uid) -> io::Result<()> { + backend::thread::syscalls::setresuid_thread(ruid, euid, suid) +} + +/// `setgid(gid)` +/// +/// # Warning +/// +/// This is not the setxid you are looking for... POSIX requires xids to be +/// process granular, but on Linux they are per-thread. Thus, this call only +/// changes the xid for the current *thread*, not the entire process even +/// though that is in violation of the POSIX standard. +/// +/// For details on this distinction, see the C library vs. kernel differences +/// in the [manual page][linux_notes]. This call implements the kernel +/// behavior. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setgid.html +/// [Linux]: https://man7.org/linux/man-pages/man2/setgid.2.html +/// [linux_notes]: https://man7.org/linux/man-pages/man2/setgid.2.html#NOTES +#[inline] +pub fn set_thread_gid(gid: Gid) -> io::Result<()> { + backend::thread::syscalls::setgid_thread(gid) +} + +/// `setresgid(rgid, egid, sgid)` +/// +/// # Warning +/// +/// This is not the setresxid you are looking for... POSIX requires xids to be +/// process granular, but on Linux they are per-thread. Thus, this call only +/// changes the xid for the current *thread*, not the entire process even +/// though that is in violation of the POSIX standard. +/// +/// For details on this distinction, see the C library vs. kernel differences +/// in the [manual page][linux_notes] and the notes in [`set_thread_gid`]. This +/// call implements the kernel behavior. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/setresgid.2.html +/// [linux_notes]: https://man7.org/linux/man-pages/man2/setresgid.2.html#NOTES +#[inline] +pub fn set_thread_res_gid(rgid: Gid, egid: Gid, sgid: Gid) -> io::Result<()> { + backend::thread::syscalls::setresgid_thread(rgid, egid, sgid) +} diff --git a/vendor/rustix-0.37.22/src/thread/libcap.rs b/vendor/rustix-0.37.22/src/thread/libcap.rs new file mode 100644 index 000000000..711106d4c --- /dev/null +++ b/vendor/rustix-0.37.22/src/thread/libcap.rs @@ -0,0 +1,188 @@ +use bitflags::bitflags; +use core::mem::MaybeUninit; + +use crate::process::Pid; +use crate::{backend, io}; + +/// `__user_cap_data_struct` +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct CapabilitySets { + /// `__user_cap_data_struct.effective` + pub effective: CapabilityFlags, + /// `__user_cap_data_struct.permitted` + pub permitted: CapabilityFlags, + /// `__user_cap_data_struct.inheritable` + pub inheritable: CapabilityFlags, +} + +bitflags! { + /// `CAP_*` constants. + pub struct CapabilityFlags: u64 { + /// `CAP_CHOWN` + const CHOWN = 1 << linux_raw_sys::general::CAP_CHOWN; + /// `CAP_DAC_OVERRIDE` + const DAC_OVERRIDE = 1 << linux_raw_sys::general::CAP_DAC_OVERRIDE; + /// `CAP_DAC_READ_SEARCH` + const DAC_READ_SEARCH = 1 << linux_raw_sys::general::CAP_DAC_READ_SEARCH; + /// `CAP_FOWNER` + const FOWNER = 1 << linux_raw_sys::general::CAP_FOWNER; + /// `CAP_FSETID` + const FSETID = 1 << linux_raw_sys::general::CAP_FSETID; + /// `CAP_KILL` + const KILL = 1 << linux_raw_sys::general::CAP_KILL; + /// `CAP_SETGID` + const SETGID = 1 << linux_raw_sys::general::CAP_SETGID; + /// `CAP_SETUID` + const SETUID = 1 << linux_raw_sys::general::CAP_SETUID; + /// `CAP_SETPCAP` + const SETPCAP = 1 << linux_raw_sys::general::CAP_SETPCAP; + /// `CAP_LINUX_IMMUTABLE` + const LINUX_IMMUTABLE = 1 << linux_raw_sys::general::CAP_LINUX_IMMUTABLE; + /// `CAP_NET_BIND_SERVICE` + const NET_BIND_SERVICE = 1 << linux_raw_sys::general::CAP_NET_BIND_SERVICE; + /// `CAP_NET_BROADCAST` + const NET_BROADCAST = 1 << linux_raw_sys::general::CAP_NET_BROADCAST; + /// `CAP_NET_ADMIN` + const NET_ADMIN = 1 << linux_raw_sys::general::CAP_NET_ADMIN; + /// `CAP_NET_RAW` + const NET_RAW = 1 << linux_raw_sys::general::CAP_NET_RAW; + /// `CAP_IPC_LOCK` + const IPC_LOCK = 1 << linux_raw_sys::general::CAP_IPC_LOCK; + /// `CAP_IPC_OWNER` + const IPC_OWNER = 1 << linux_raw_sys::general::CAP_IPC_OWNER; + /// `CAP_SYS_MODULE` + const SYS_MODULE = 1 << linux_raw_sys::general::CAP_SYS_MODULE; + /// `CAP_SYS_RAWIO` + const SYS_RAWIO = 1 << linux_raw_sys::general::CAP_SYS_RAWIO; + /// `CAP_SYS_CHROOT` + const SYS_CHROOT = 1 << linux_raw_sys::general::CAP_SYS_CHROOT; + /// `CAP_SYS_PTRACE` + const SYS_PTRACE = 1 << linux_raw_sys::general::CAP_SYS_PTRACE; + /// `CAP_SYS_PACCT` + const SYS_PACCT = 1 << linux_raw_sys::general::CAP_SYS_PACCT; + /// `CAP_SYS_ADMIN` + const SYS_ADMIN = 1 << linux_raw_sys::general::CAP_SYS_ADMIN; + /// `CAP_SYS_BOOT` + const SYS_BOOT = 1 << linux_raw_sys::general::CAP_SYS_BOOT; + /// `CAP_SYS_NICE` + const SYS_NICE = 1 << linux_raw_sys::general::CAP_SYS_NICE; + /// `CAP_SYS_RESOURCE` + const SYS_RESOURCE = 1 << linux_raw_sys::general::CAP_SYS_RESOURCE; + /// `CAP_SYS_TIME` + const SYS_TIME = 1 << linux_raw_sys::general::CAP_SYS_TIME; + /// `CAP_SYS_TTY_CONFIG` + const SYS_TTY_CONFIG = 1 << linux_raw_sys::general::CAP_SYS_TTY_CONFIG; + /// `CAP_MKNOD` + const MKNOD = 1 << linux_raw_sys::general::CAP_MKNOD; + /// `CAP_LEASE` + const LEASE = 1 << linux_raw_sys::general::CAP_LEASE; + /// `CAP_AUDIT_WRITE` + const AUDIT_WRITE = 1 << linux_raw_sys::general::CAP_AUDIT_WRITE; + /// `CAP_AUDIT_CONTROL` + const AUDIT_CONTROL = 1 << linux_raw_sys::general::CAP_AUDIT_CONTROL; + /// `CAP_SETFCAP` + const SETFCAP = 1 << linux_raw_sys::general::CAP_SETFCAP; + /// `CAP_MAC_OVERRIDE` + const MAC_OVERRIDE = 1 << linux_raw_sys::general::CAP_MAC_OVERRIDE; + /// `CAP_MAC_ADMIN` + const MAC_ADMIN = 1 << linux_raw_sys::general::CAP_MAC_ADMIN; + /// `CAP_SYSLOG` + const SYSLOG = 1 << linux_raw_sys::general::CAP_SYSLOG; + /// `CAP_WAKE_ALARM` + const WAKE_ALARM = 1 << linux_raw_sys::general::CAP_WAKE_ALARM; + /// `CAP_BLOCK_SUSPEND` + const BLOCK_SUSPEND = 1 << linux_raw_sys::general::CAP_BLOCK_SUSPEND; + /// `CAP_AUDIT_READ` + const AUDIT_READ = 1 << linux_raw_sys::general::CAP_AUDIT_READ; + /// `CAP_PERFMON` + const PERFMON = 1 << linux_raw_sys::general::CAP_PERFMON; + /// `CAP_BPF` + const BPF = 1 << linux_raw_sys::general::CAP_BPF; + /// `CAP_CHECKPOINT_RESTORE` + const CHECKPOINT_RESTORE = 1 << linux_raw_sys::general::CAP_CHECKPOINT_RESTORE; + } +} + +/// `capget(_LINUX_CAPABILITY_VERSION_3, pid)` +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/capget.2.html +#[inline] +#[doc(alias = "capget")] +pub fn capabilities(pid: Option<Pid>) -> io::Result<CapabilitySets> { + capget(pid) +} + +/// `capset(_LINUX_CAPABILITY_VERSION_3, pid, effective, permitted, +/// inheritable)` +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/capget.2.html +#[inline] +#[doc(alias = "capset")] +pub fn set_capabilities(pid: Option<Pid>, sets: CapabilitySets) -> io::Result<()> { + capset(pid, sets) +} + +#[inline] +#[allow(unsafe_code)] +fn capget(pid: Option<Pid>) -> io::Result<CapabilitySets> { + let mut data = [MaybeUninit::<linux_raw_sys::general::__user_cap_data_struct>::uninit(); 2]; + + let data = { + let mut header = linux_raw_sys::general::__user_cap_header_struct { + version: linux_raw_sys::general::_LINUX_CAPABILITY_VERSION_3, + pid: Pid::as_raw(pid) as backend::c::c_int, + }; + + backend::thread::syscalls::capget(&mut header, &mut data)?; + // SAFETY: v3 is a 64-bit implementation, so the kernel filled in both + // data structs. + unsafe { (data[0].assume_init(), data[1].assume_init()) } + }; + + { + // TODO: With Rust 1.53, we can use u32::BITS in the shifts. + const BITS: u32 = 32; + let effective = u64::from(data.0.effective) | (u64::from(data.1.effective) << BITS); + let permitted = u64::from(data.0.permitted) | (u64::from(data.1.permitted) << BITS); + let inheritable = u64::from(data.0.inheritable) | (u64::from(data.1.inheritable) << BITS); + + // SAFETY: The kernel returns a partitioned bitset that we just + // combined above. + Ok(CapabilitySets { + effective: unsafe { CapabilityFlags::from_bits_unchecked(effective) }, + permitted: unsafe { CapabilityFlags::from_bits_unchecked(permitted) }, + inheritable: unsafe { CapabilityFlags::from_bits_unchecked(inheritable) }, + }) + } +} + +#[inline] +fn capset(pid: Option<Pid>, sets: CapabilitySets) -> io::Result<()> { + // TODO: With Rust 1.53, we can use u32::BITS in the shifts. + const BITS: u32 = 32; + + let mut header = linux_raw_sys::general::__user_cap_header_struct { + version: linux_raw_sys::general::_LINUX_CAPABILITY_VERSION_3, + pid: Pid::as_raw(pid) as backend::c::c_int, + }; + let data = [ + linux_raw_sys::general::__user_cap_data_struct { + effective: sets.effective.bits() as u32, + permitted: sets.permitted.bits() as u32, + inheritable: sets.inheritable.bits() as u32, + }, + linux_raw_sys::general::__user_cap_data_struct { + effective: (sets.effective.bits() >> BITS) as u32, + permitted: (sets.permitted.bits() >> BITS) as u32, + inheritable: (sets.inheritable.bits() >> BITS) as u32, + }, + ]; + + backend::thread::syscalls::capset(&mut header, &data) +} diff --git a/vendor/rustix-0.37.22/src/thread/mod.rs b/vendor/rustix-0.37.22/src/thread/mod.rs new file mode 100644 index 000000000..fa4897025 --- /dev/null +++ b/vendor/rustix-0.37.22/src/thread/mod.rs @@ -0,0 +1,27 @@ +//! Thread-associated operations. + +#[cfg(not(target_os = "redox"))] +mod clock; +#[cfg(linux_raw)] +mod futex; +#[cfg(linux_kernel)] +mod id; +#[cfg(linux_kernel)] +mod libcap; +#[cfg(linux_kernel)] +mod prctl; +#[cfg(linux_kernel)] +mod setns; + +#[cfg(not(target_os = "redox"))] +pub use clock::*; +#[cfg(linux_raw)] +pub use futex::{futex, FutexFlags, FutexOperation}; +#[cfg(linux_kernel)] +pub use id::{gettid, set_thread_gid, set_thread_res_gid, set_thread_res_uid, set_thread_uid}; +#[cfg(linux_kernel)] +pub use libcap::{capabilities, set_capabilities, CapabilityFlags, CapabilitySets}; +#[cfg(linux_kernel)] +pub use prctl::*; +#[cfg(linux_kernel)] +pub use setns::*; diff --git a/vendor/rustix-0.37.22/src/thread/prctl.rs b/vendor/rustix-0.37.22/src/thread/prctl.rs new file mode 100644 index 000000000..621e690cf --- /dev/null +++ b/vendor/rustix-0.37.22/src/thread/prctl.rs @@ -0,0 +1,986 @@ +//! Linux `prctl` wrappers. +//! +//! Rustix wraps variadic/dynamic-dispatch functions like `prctl` in +//! type-safe wrappers. +//! +//! # Safety +//! +//! The inner `prctl` calls are dynamically typed and must be called +//! correctly. +#![allow(unsafe_code)] + +use core::convert::TryFrom; +use core::mem::MaybeUninit; +use core::num::NonZeroU64; +use core::ptr; +use core::ptr::NonNull; +use core::sync::atomic::AtomicU8; + +use bitflags::bitflags; + +use crate::backend::c::{c_int, c_uint, c_void}; +use crate::backend::process::syscalls; +use crate::ffi::{CStr, CString}; +use crate::io; +use crate::process::{ + prctl_1arg, prctl_2args, prctl_3args, prctl_get_at_arg2_optional, Pid, + PointerAuthenticationKeys, +}; +use crate::utils::as_ptr; + +// +// PR_GET_KEEPCAPS/PR_SET_KEEPCAPS +// + +const PR_GET_KEEPCAPS: c_int = 7; + +/// Get the current state of the calling thread's `keep capabilities` flag. +/// +/// # References +/// - [`prctl(PR_GET_KEEPCAPS,...)`] +/// +/// [`prctl(PR_GET_KEEPCAPS,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +pub fn get_keep_capabilities() -> io::Result<bool> { + unsafe { prctl_1arg(PR_GET_KEEPCAPS) }.map(|r| r != 0) +} + +const PR_SET_KEEPCAPS: c_int = 8; + +/// Set the state of the calling thread's `keep capabilities` flag. +/// +/// # References +/// - [`prctl(PR_SET_KEEPCAPS,...)`] +/// +/// [`prctl(PR_SET_KEEPCAPS,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +pub fn set_keep_capabilities(enable: bool) -> io::Result<()> { + unsafe { prctl_2args(PR_SET_KEEPCAPS, usize::from(enable) as *mut _) }.map(|_r| ()) +} + +// +// PR_GET_NAME/PR_SET_NAME +// + +const PR_GET_NAME: c_int = 16; + +/// Get the name of the calling thread. +/// +/// # References +/// - [`prctl(PR_GET_NAME,...)`] +/// +/// [`prctl(PR_GET_NAME,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +pub fn name() -> io::Result<CString> { + let mut buffer = [0_u8; 16]; + unsafe { prctl_2args(PR_GET_NAME, buffer.as_mut_ptr().cast())? }; + + let len = buffer.iter().position(|&x| x == 0_u8).unwrap_or(0); + CString::new(&buffer[..len]).map_err(|_r| io::Errno::ILSEQ) +} + +const PR_SET_NAME: c_int = 15; + +/// Set the name of the calling thread. +/// +/// # References +/// - [`prctl(PR_SET_NAME,...)`] +/// +/// [`prctl(PR_SET_NAME,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +pub fn set_name(name: &CStr) -> io::Result<()> { + unsafe { prctl_2args(PR_SET_NAME, name.as_ptr() as *mut _) }.map(|_r| ()) +} + +// +// PR_GET_SECCOMP/PR_SET_SECCOMP +// + +//const PR_GET_SECCOMP: c_int = 21; + +const SECCOMP_MODE_DISABLED: i32 = 0; +const SECCOMP_MODE_STRICT: i32 = 1; +const SECCOMP_MODE_FILTER: i32 = 2; + +/// `SECCOMP_MODE_*`. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[repr(i32)] +pub enum SecureComputingMode { + /// Secure computing is not in use. + Disabled = SECCOMP_MODE_DISABLED, + /// Use hard-coded filter. + Strict = SECCOMP_MODE_STRICT, + /// Use user-supplied filter. + Filter = SECCOMP_MODE_FILTER, +} + +impl TryFrom<i32> for SecureComputingMode { + type Error = io::Errno; + + fn try_from(value: i32) -> Result<Self, Self::Error> { + match value { + SECCOMP_MODE_DISABLED => Ok(Self::Disabled), + SECCOMP_MODE_STRICT => Ok(Self::Strict), + SECCOMP_MODE_FILTER => Ok(Self::Filter), + _ => Err(io::Errno::RANGE), + } + } +} + +/* +/// Get the secure computing mode of the calling thread. +/// +/// If the caller is not in secure computing mode, this returns +/// [`SecureComputingMode::Disabled`]. If the caller is in strict secure +/// computing mode, then this call will cause a [`Signal::Kill`] signal to be +/// sent to the process. If the caller is in filter mode, and this system call +/// is allowed by the seccomp filters, it returns +/// [`SecureComputingMode::Filter`]; otherwise, the process is killed with +/// a [`Signal::Kill`] signal. +/// +/// Since Linux 3.8, the Seccomp field of the `/proc/[pid]/status` file +/// provides a method of obtaining the same information, without the risk that +/// the process is killed; see [the `proc` manual page]. +/// +/// # References +/// - [`prctl(PR_GET_SECCOMP,...)`] +/// +/// [`prctl(PR_GET_SECCOMP,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +/// [the `proc` manual page]: https://man7.org/linux/man-pages/man5/proc.5.html +#[inline] +pub fn secure_computing_mode() -> io::Result<SecureComputingMode> { + unsafe { prctl_1arg(PR_GET_SECCOMP) }.and_then(TryInto::try_into) +} +*/ + +const PR_SET_SECCOMP: c_int = 22; + +/// Set the secure computing mode for the calling thread, to limit the +/// available system calls. +/// +/// # References +/// - [`prctl(PR_SET_SECCOMP,...)`] +/// +/// [`prctl(PR_SET_SECCOMP,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +pub fn set_secure_computing_mode(mode: SecureComputingMode) -> io::Result<()> { + unsafe { prctl_2args(PR_SET_SECCOMP, mode as usize as *mut _) }.map(|_r| ()) +} + +// +// PR_CAPBSET_READ/PR_CAPBSET_DROP +// + +const PR_CAPBSET_READ: c_int = 23; + +/// Linux per-thread capability. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[repr(u32)] +pub enum Capability { + /// In a system with the `_POSIX_CHOWN_RESTRICTED` option defined, this + /// overrides the restriction of changing file ownership and group + /// ownership. + ChangeOwnership = linux_raw_sys::general::CAP_CHOWN, + /// Override all DAC access, including ACL execute access if `_POSIX_ACL` + /// is defined. Excluding DAC access covered by + /// [`Capability::LinuxImmutable`]. + DACOverride = linux_raw_sys::general::CAP_DAC_OVERRIDE, + /// Overrides all DAC restrictions regarding read and search on files and + /// directories, including ACL restrictions if `_POSIX_ACL` is defined. + /// Excluding DAC access covered by [`Capability::LinuxImmutable`]. + DACReadSearch = linux_raw_sys::general::CAP_DAC_READ_SEARCH, + /// Overrides all restrictions about allowed operations on files, where + /// file owner ID must be equal to the user ID, except where + /// [`Capability::FileSetID`] is applicable. It doesn't override MAC + /// and DAC restrictions. + FileOwner = linux_raw_sys::general::CAP_FOWNER, + /// Overrides the following restrictions that the effective user ID shall + /// match the file owner ID when setting the `S_ISUID` and `S_ISGID` + /// bits on that file; that the effective group ID (or one of the + /// supplementary group IDs) shall match the file owner ID when setting the + /// `S_ISGID` bit on that file; that the `S_ISUID` and `S_ISGID` bits are + /// cleared on successful return from `chown` (not implemented). + FileSetID = linux_raw_sys::general::CAP_FSETID, + /// Overrides the restriction that the real or effective user ID of a + /// process sending a signal must match the real or effective user ID + /// of the process receiving the signal. + Kill = linux_raw_sys::general::CAP_KILL, + /// Allows `setgid` manipulation. Allows `setgroups`. Allows forged gids on + /// socket credentials passing. + SetGroupID = linux_raw_sys::general::CAP_SETGID, + /// Allows `set*uid` manipulation (including fsuid). Allows forged pids on + /// socket credentials passing. + SetUserID = linux_raw_sys::general::CAP_SETUID, + /// Without VFS support for capabilities: + /// - Transfer any capability in your permitted set to any pid. + /// - remove any capability in your permitted set from any pid. With VFS + /// support for capabilities (neither of above, but) + /// - Add any capability from current's capability bounding set to the + /// current process' inheritable set. + /// - Allow taking bits out of capability bounding set. + /// - Allow modification of the securebits for a process. + SetPermittedCapabilities = linux_raw_sys::general::CAP_SETPCAP, + /// Allow modification of `S_IMMUTABLE` and `S_APPEND` file attributes. + LinuxImmutable = linux_raw_sys::general::CAP_LINUX_IMMUTABLE, + /// Allows binding to TCP/UDP sockets below 1024. Allows binding to ATM + /// VCIs below 32. + NetBindService = linux_raw_sys::general::CAP_NET_BIND_SERVICE, + /// Allow broadcasting, listen to multicast. + NetBroadcast = linux_raw_sys::general::CAP_NET_BROADCAST, + /// Allow interface configuration. Allow administration of IP firewall, + /// masquerading and accounting. Allow setting debug option on sockets. + /// Allow modification of routing tables. Allow setting arbitrary + /// process / process group ownership on sockets. Allow binding to any + /// address for transparent proxying (also via [`Capability::NetRaw`]). + /// Allow setting TOS (type of service). Allow setting promiscuous + /// mode. Allow clearing driver statistics. Allow multicasting. Allow + /// read/write of device-specific registers. Allow activation of ATM + /// control sockets. + NetAdmin = linux_raw_sys::general::CAP_NET_ADMIN, + /// Allow use of `RAW` sockets. Allow use of `PACKET` sockets. Allow + /// binding to any address for transparent proxying (also via + /// [`Capability::NetAdmin`]). + NetRaw = linux_raw_sys::general::CAP_NET_RAW, + /// Allow locking of shared memory segments. Allow mlock and mlockall + /// (which doesn't really have anything to do with IPC). + IPCLock = linux_raw_sys::general::CAP_IPC_LOCK, + /// Override IPC ownership checks. + IPCOwner = linux_raw_sys::general::CAP_IPC_OWNER, + /// Insert and remove kernel modules - modify kernel without limit. + SystemModule = linux_raw_sys::general::CAP_SYS_MODULE, + /// Allow ioperm/iopl access. Allow sending USB messages to any device via + /// `/dev/bus/usb`. + SystemRawIO = linux_raw_sys::general::CAP_SYS_RAWIO, + /// Allow use of `chroot`. + SystemChangeRoot = linux_raw_sys::general::CAP_SYS_CHROOT, + /// Allow `ptrace` of any process. + SystemProcessTrace = linux_raw_sys::general::CAP_SYS_PTRACE, + /// Allow configuration of process accounting. + SystemProcessAccounting = linux_raw_sys::general::CAP_SYS_PACCT, + /// Allow configuration of the secure attention key. Allow administration + /// of the random device. Allow examination and configuration of disk + /// quotas. Allow setting the domainname. Allow setting the hostname. + /// Allow `mount` and `umount`, setting up new smb connection. + /// Allow some autofs root ioctls. Allow nfsservctl. Allow + /// `VM86_REQUEST_IRQ`. Allow to read/write pci config on alpha. Allow + /// `irix_prctl` on mips (setstacksize). Allow flushing all cache on + /// m68k (`sys_cacheflush`). Allow removing semaphores. Used instead of + /// [`Capability::ChangeOwnership`] to "chown" IPC message queues, + /// semaphores and shared memory. Allow locking/unlocking of shared + /// memory segment. Allow turning swap on/off. Allow forged pids on + /// socket credentials passing. Allow setting readahead and + /// flushing buffers on block devices. Allow setting geometry in floppy + /// driver. Allow turning DMA on/off in `xd` driver. Allow + /// administration of md devices (mostly the above, but some + /// extra ioctls). Allow tuning the ide driver. Allow access to the nvram + /// device. Allow administration of `apm_bios`, serial and bttv (TV) + /// device. Allow manufacturer commands in isdn CAPI support driver. + /// Allow reading non-standardized portions of pci configuration space. + /// Allow DDI debug ioctl on sbpcd driver. Allow setting up serial ports. + /// Allow sending raw qic-117 commands. Allow enabling/disabling tagged + /// queuing on SCSI controllers and sending arbitrary SCSI commands. + /// Allow setting encryption key on loopback filesystem. Allow setting + /// zone reclaim policy. Allow everything under + /// [`Capability::BerkeleyPacketFilters`] and + /// [`Capability::PerformanceMonitoring`] for backward compatibility. + SystemAdmin = linux_raw_sys::general::CAP_SYS_ADMIN, + /// Allow use of `reboot`. + SystemBoot = linux_raw_sys::general::CAP_SYS_BOOT, + /// Allow raising priority and setting priority on other (different UID) + /// processes. Allow use of FIFO and round-robin (realtime) scheduling + /// on own processes and setting the scheduling algorithm used by + /// another process. Allow setting cpu affinity on other processes. + /// Allow setting realtime ioprio class. Allow setting ioprio class on + /// other processes. + SystemNice = linux_raw_sys::general::CAP_SYS_NICE, + /// Override resource limits. Set resource limits. Override quota limits. + /// Override reserved space on ext2 filesystem. Modify data journaling + /// mode on ext3 filesystem (uses journaling resources). NOTE: ext2 + /// honors fsuid when checking for resource overrides, so you can + /// override using fsuid too. Override size restrictions on IPC message + /// queues. Allow more than 64hz interrupts from the real-time clock. + /// Override max number of consoles on console allocation. Override max + /// number of keymaps. Control memory reclaim behavior. + SystemResource = linux_raw_sys::general::CAP_SYS_RESOURCE, + /// Allow manipulation of system clock. Allow `irix_stime` on mips. Allow + /// setting the real-time clock. + SystemTime = linux_raw_sys::general::CAP_SYS_TIME, + /// Allow configuration of tty devices. Allow `vhangup` of tty. + SystemTTYConfig = linux_raw_sys::general::CAP_SYS_TTY_CONFIG, + /// Allow the privileged aspects of `mknod`. + MakeNode = linux_raw_sys::general::CAP_MKNOD, + /// Allow taking of leases on files. + Lease = linux_raw_sys::general::CAP_LEASE, + /// Allow writing the audit log via unicast netlink socket. + AuditWrite = linux_raw_sys::general::CAP_AUDIT_WRITE, + /// Allow configuration of audit via unicast netlink socket. + AuditControl = linux_raw_sys::general::CAP_AUDIT_CONTROL, + /// Set or remove capabilities on files. Map `uid=0` into a child user + /// namespace. + SetFileCapabilities = linux_raw_sys::general::CAP_SETFCAP, + /// Override MAC access. The base kernel enforces no MAC policy. An LSM may + /// enforce a MAC policy, and if it does and it chooses to implement + /// capability based overrides of that policy, this is the capability + /// it should use to do so. + MACOverride = linux_raw_sys::general::CAP_MAC_OVERRIDE, + /// Allow MAC configuration or state changes. The base kernel requires no + /// MAC configuration. An LSM may enforce a MAC policy, and if it does + /// and it chooses to implement capability based + /// checks on modifications to that policy or the data required to maintain + /// it, this is the capability it should use to do so. + MACAdmin = linux_raw_sys::general::CAP_MAC_ADMIN, + /// Allow configuring the kernel's `syslog` (`printk` behaviour). + SystemLog = linux_raw_sys::general::CAP_SYSLOG, + /// Allow triggering something that will wake the system. + WakeAlarm = linux_raw_sys::general::CAP_WAKE_ALARM, + /// Allow preventing system suspends. + BlockSuspend = linux_raw_sys::general::CAP_BLOCK_SUSPEND, + /// Allow reading the audit log via multicast netlink socket. + AuditRead = linux_raw_sys::general::CAP_AUDIT_READ, + /// Allow system performance and observability privileged operations using + /// `perf_events`, `i915_perf` and other kernel subsystems. + PerformanceMonitoring = linux_raw_sys::general::CAP_PERFMON, + /// This capability allows the following BPF operations: + /// - Creating all types of BPF maps + /// - Advanced verifier features + /// - Indirect variable access + /// - Bounded loops + /// - BPF to BPF function calls + /// - Scalar precision tracking + /// - Larger complexity limits + /// - Dead code elimination + /// - And potentially other features + /// - Loading BPF Type Format (BTF) data + /// - Retrieve `xlated` and JITed code of BPF programs + /// - Use `bpf_spin_lock` helper + /// + /// [`Capability::PerformanceMonitoring`] relaxes the verifier checks + /// further: + /// - BPF progs can use of pointer-to-integer conversions + /// - speculation attack hardening measures are bypassed + /// - `bpf_probe_read` to read arbitrary kernel memory is allowed + /// - `bpf_trace_printk` to print kernel memory is allowed + /// + /// [`Capability::SystemAdmin`] is required to use bpf_probe_write_user. + /// + /// [`Capability::SystemAdmin`] is required to iterate system wide loaded + /// programs, maps, links, BTFs and convert their IDs to file descriptors. + /// + /// [`Capability::PerformanceMonitoring`] and + /// [`Capability::BerkeleyPacketFilters`] are required to load tracing + /// programs. [`Capability::NetAdmin`] and + /// [`Capability::BerkeleyPacketFilters`] are required to load + /// networking programs. + BerkeleyPacketFilters = linux_raw_sys::general::CAP_BPF, + /// Allow checkpoint/restore related operations. Allow PID selection during + /// `clone3`. Allow writing to `ns_last_pid`. + CheckpointRestore = linux_raw_sys::general::CAP_CHECKPOINT_RESTORE, +} + +/// Check if the specified capability is in the calling thread's capability +/// bounding set. +/// +/// # References +/// - [`prctl(PR_CAPBSET_READ,...)`] +/// +/// [`prctl(PR_CAPBSET_READ,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +pub fn capability_is_in_bounding_set(capability: Capability) -> io::Result<bool> { + unsafe { prctl_2args(PR_CAPBSET_READ, capability as usize as *mut _) }.map(|r| r != 0) +} + +const PR_CAPBSET_DROP: c_int = 24; + +/// If the calling thread has the [`Capability::SetPermittedCapabilities`] +/// capability within its user namespace, then drop the specified capability +/// from the thread's capability bounding set. +/// +/// # References +/// - [`prctl(PR_CAPBSET_DROP,...)`] +/// +/// [`prctl(PR_CAPBSET_DROP,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +pub fn remove_capability_from_bounding_set(capability: Capability) -> io::Result<()> { + unsafe { prctl_2args(PR_CAPBSET_DROP, capability as usize as *mut _) }.map(|_r| ()) +} + +// +// PR_GET_SECUREBITS/PR_SET_SECUREBITS +// + +const PR_GET_SECUREBITS: c_int = 27; + +bitflags! { + /// `SECBIT_*`. + pub struct CapabilitiesSecureBits: u32 { + /// If this bit is set, then the kernel does not grant capabilities when + /// a `set-user-ID-root` program is executed, or when a process with an effective or real + /// UID of 0 calls `execve`. + const NO_ROOT = 1_u32 << 0; + /// Set [`NO_ROOT`] irreversibly. + const NO_ROOT_LOCKED = 1_u32 << 1; + /// Setting this flag stops the kernel from adjusting the process's permitted, effective, + /// and ambient capability sets when the thread's effective and filesystem UIDs are switched + /// between zero and nonzero values. + const NO_SETUID_FIXUP = 1_u32 << 2; + /// Set [`NO_SETUID_FIXUP`] irreversibly. + const NO_SETUID_FIXUP_LOCKED = 1_u32 << 3; + /// Setting this flag allows a thread that has one or more 0 UIDs to retain capabilities in + /// its permitted set when it switches all of its UIDs to nonzero values. + const KEEP_CAPS = 1_u32 << 4; + /// Set [`KEEP_CAPS`] irreversibly. + const KEEP_CAPS_LOCKED = 1_u32 << 5; + /// Setting this flag disallows raising ambient capabilities via the `prctl`'s + /// `PR_CAP_AMBIENT_RAISE` operation. + const NO_CAP_AMBIENT_RAISE = 1_u32 << 6; + /// Set [`NO_CAP_AMBIENT_RAISE`] irreversibly. + const NO_CAP_AMBIENT_RAISE_LOCKED = 1_u32 << 7; + } +} + +/// Get the `securebits` flags of the calling thread. +/// +/// # References +/// - [`prctl(PR_GET_SECUREBITS,...)`] +/// +/// [`prctl(PR_GET_SECUREBITS,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +pub fn capabilities_secure_bits() -> io::Result<CapabilitiesSecureBits> { + let r = unsafe { prctl_1arg(PR_GET_SECUREBITS)? } as c_uint; + CapabilitiesSecureBits::from_bits(r).ok_or(io::Errno::RANGE) +} + +const PR_SET_SECUREBITS: c_int = 28; + +/// Set the `securebits` flags of the calling thread. +/// +/// # References +/// - [`prctl(PR_SET_SECUREBITS,...)`] +/// +/// [`prctl(PR_SET_SECUREBITS,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +pub fn set_capabilities_secure_bits(bits: CapabilitiesSecureBits) -> io::Result<()> { + unsafe { prctl_2args(PR_SET_SECUREBITS, bits.bits() as usize as *mut _) }.map(|_r| ()) +} + +// +// PR_GET_TIMERSLACK/PR_SET_TIMERSLACK +// + +const PR_GET_TIMERSLACK: c_int = 30; + +/// Get the `current` timer slack value of the calling thread. +/// +/// # References +/// - [`prctl(PR_GET_TIMERSLACK,...)`] +/// +/// [`prctl(PR_GET_TIMERSLACK,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +pub fn current_timer_slack() -> io::Result<u64> { + unsafe { prctl_1arg(PR_GET_TIMERSLACK) }.map(|r| r as u64) +} + +const PR_SET_TIMERSLACK: c_int = 29; + +/// Sets the `current` timer slack value for the calling thread. +/// +/// # References +/// - [`prctl(PR_SET_TIMERSLACK,...)`] +/// +/// [`prctl(PR_SET_TIMERSLACK,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +pub fn set_current_timer_slack(value: Option<NonZeroU64>) -> io::Result<()> { + let value = usize::try_from(value.map_or(0, NonZeroU64::get)).map_err(|_r| io::Errno::RANGE)?; + unsafe { prctl_2args(PR_SET_TIMERSLACK, value as *mut _) }.map(|_r| ()) +} + +// +// PR_GET_NO_NEW_PRIVS/PR_SET_NO_NEW_PRIVS +// + +const PR_GET_NO_NEW_PRIVS: c_int = 39; + +/// Get the value of the `no_new_privs` attribute for the calling thread. +/// +/// # References +/// - [`prctl(PR_GET_NO_NEW_PRIVS,...)`] +/// +/// [`prctl(PR_GET_NO_NEW_PRIVS,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +pub fn no_new_privs() -> io::Result<bool> { + unsafe { prctl_1arg(PR_GET_NO_NEW_PRIVS) }.map(|r| r != 0) +} + +const PR_SET_NO_NEW_PRIVS: c_int = 38; + +/// Set the calling thread's `no_new_privs` attribute. +/// +/// # References +/// - [`prctl(PR_SET_NO_NEW_PRIVS,...)`] +/// +/// [`prctl(PR_SET_NO_NEW_PRIVS,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +pub fn set_no_new_privs(no_new_privs: bool) -> io::Result<()> { + unsafe { prctl_2args(PR_SET_NO_NEW_PRIVS, usize::from(no_new_privs) as *mut _) }.map(|_r| ()) +} + +// +// PR_GET_TID_ADDRESS +// + +const PR_GET_TID_ADDRESS: c_int = 40; + +/// Get the `clear_child_tid` address set by `set_tid_address` +/// and `clone`'s `CLONE_CHILD_CLEARTID` flag. +/// +/// # References +/// - [`prctl(PR_GET_TID_ADDRESS,...)`] +/// +/// [`prctl(PR_GET_TID_ADDRESS,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +pub fn get_clear_child_tid_address() -> io::Result<Option<NonNull<c_void>>> { + unsafe { prctl_get_at_arg2_optional::<*mut c_void>(PR_GET_TID_ADDRESS) }.map(NonNull::new) +} + +// +// PR_GET_THP_DISABLE/PR_SET_THP_DISABLE +// + +const PR_GET_THP_DISABLE: c_int = 42; + +/// Get the current setting of the `THP disable` flag for the calling thread. +/// +/// # References +/// - [`prctl(PR_GET_THP_DISABLE,...)`] +/// +/// [`prctl(PR_GET_THP_DISABLE,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +pub fn transparent_huge_pages_are_disabled() -> io::Result<bool> { + unsafe { prctl_1arg(PR_GET_THP_DISABLE) }.map(|r| r != 0) +} + +const PR_SET_THP_DISABLE: c_int = 41; + +/// Set the state of the `THP disable` flag for the calling thread. +/// +/// # References +/// - [`prctl(PR_SET_THP_DISABLE,...)`] +/// +/// [`prctl(PR_SET_THP_DISABLE,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +pub fn disable_transparent_huge_pages(thp_disable: bool) -> io::Result<()> { + unsafe { prctl_2args(PR_SET_THP_DISABLE, usize::from(thp_disable) as *mut _) }.map(|_r| ()) +} + +// +// PR_CAP_AMBIENT +// + +const PR_CAP_AMBIENT: c_int = 47; + +const PR_CAP_AMBIENT_IS_SET: usize = 1; + +/// Check if the specified capability is in the ambient set. +/// +/// # References +/// - [`prctl(PR_CAP_AMBIENT,PR_CAP_AMBIENT_IS_SET,...)`] +/// +/// [`prctl(PR_CAP_AMBIENT,PR_CAP_AMBIENT_IS_SET,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +pub fn capability_is_in_ambient_set(capability: Capability) -> io::Result<bool> { + let cap = capability as usize as *mut _; + unsafe { prctl_3args(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET as *mut _, cap) }.map(|r| r != 0) +} + +const PR_CAP_AMBIENT_CLEAR_ALL: usize = 4; + +/// Remove all capabilities from the ambient set. +/// +/// # References +/// - [`prctl(PR_CAP_AMBIENT,PR_CAP_AMBIENT_CLEAR_ALL,...)`] +/// +/// [`prctl(PR_CAP_AMBIENT,PR_CAP_AMBIENT_CLEAR_ALL,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +pub fn clear_ambient_capability_set() -> io::Result<()> { + unsafe { prctl_2args(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL as *mut _) }.map(|_r| ()) +} + +const PR_CAP_AMBIENT_RAISE: usize = 2; +const PR_CAP_AMBIENT_LOWER: usize = 3; + +/// Add or remove the specified capability to the ambient set. +/// +/// # References +/// - [`prctl(PR_CAP_AMBIENT,...)`] +/// +/// [`prctl(PR_CAP_AMBIENT,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +pub fn configure_capability_in_ambient_set(capability: Capability, enable: bool) -> io::Result<()> { + let sub_operation = if enable { + PR_CAP_AMBIENT_RAISE + } else { + PR_CAP_AMBIENT_LOWER + }; + let cap = capability as usize as *mut _; + + unsafe { prctl_3args(PR_CAP_AMBIENT, sub_operation as *mut _, cap) }.map(|_r| ()) +} + +// +// PR_SVE_GET_VL/PR_SVE_SET_VL +// + +const PR_SVE_GET_VL: c_int = 51; + +const PR_SVE_VL_LEN_MASK: u32 = 0xffff; +const PR_SVE_VL_INHERIT: u32 = 1_u32 << 17; + +/// Scalable Vector Extension vector length configuration. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct SVEVectorLengthConfig { + /// Vector length in bytes. + pub vector_length_in_bytes: u32, + /// Vector length inherited across `execve`. + pub vector_length_inherited_across_execve: bool, +} + +/// Get the thread's current SVE vector length configuration. +/// +/// # References +/// - [`prctl(PR_SVE_GET_VL,...)`] +/// +/// [`prctl(PR_SVE_GET_VL,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +pub fn sve_vector_length_configuration() -> io::Result<SVEVectorLengthConfig> { + let bits = unsafe { prctl_1arg(PR_SVE_GET_VL)? } as c_uint; + Ok(SVEVectorLengthConfig { + vector_length_in_bytes: bits & PR_SVE_VL_LEN_MASK, + vector_length_inherited_across_execve: (bits & PR_SVE_VL_INHERIT) != 0, + }) +} + +const PR_SVE_SET_VL: c_int = 50; + +const PR_SVE_SET_VL_ONEXEC: u32 = 1_u32 << 18; + +/// Configure the thread's vector length of Scalable Vector Extension. +/// +/// # References +/// - [`prctl(PR_SVE_SET_VL,...)`] +/// +/// # Safety +/// +/// Please ensure the conditions necessary to safely call this function, +/// as detailed in the references above. +/// +/// [`prctl(PR_SVE_SET_VL,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +pub unsafe fn set_sve_vector_length_configuration( + vector_length_in_bytes: usize, + vector_length_inherited_across_execve: bool, + defer_change_to_next_execve: bool, +) -> io::Result<()> { + let vector_length_in_bytes = + u32::try_from(vector_length_in_bytes).map_err(|_r| io::Errno::RANGE)?; + + let mut bits = vector_length_in_bytes & PR_SVE_VL_LEN_MASK; + + if vector_length_inherited_across_execve { + bits |= PR_SVE_VL_INHERIT; + } + + if defer_change_to_next_execve { + bits |= PR_SVE_SET_VL_ONEXEC; + } + + prctl_2args(PR_SVE_SET_VL, bits as usize as *mut _).map(|_r| ()) +} + +// +// PR_PAC_RESET_KEYS +// + +const PR_PAC_RESET_KEYS: c_int = 54; + +/// Securely reset the thread's pointer authentication keys to fresh random +/// values generated by the kernel. +/// +/// # References +/// - [`prctl(PR_PAC_RESET_KEYS,...)`] +/// +/// # Safety +/// +/// Please ensure the conditions necessary to safely call this function, +/// as detailed in the references above. +/// +/// [`prctl(PR_PAC_RESET_KEYS,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +pub unsafe fn reset_pointer_authentication_keys( + keys: Option<PointerAuthenticationKeys>, +) -> io::Result<()> { + let keys = keys.as_ref().map_or(0_u32, PointerAuthenticationKeys::bits); + prctl_2args(PR_PAC_RESET_KEYS, keys as usize as *mut _).map(|_r| ()) +} + +// +// PR_GET_TAGGED_ADDR_CTRL/PR_SET_TAGGED_ADDR_CTRL +// + +const PR_GET_TAGGED_ADDR_CTRL: c_int = 56; + +const PR_MTE_TAG_SHIFT: u32 = 3; +const PR_MTE_TAG_MASK: u32 = 0xffff_u32 << PR_MTE_TAG_SHIFT; + +bitflags! { + /// Zero means addresses that are passed for the purpose of being dereferenced by the kernel must be untagged. + pub struct TaggedAddressMode: u32 { + /// Addresses that are passed for the purpose of being dereferenced by the kernel may be tagged. + const ENABLED = 1_u32 << 0; + /// Synchronous tag check fault mode. + const TCF_SYNC = 1_u32 << 1; + /// Asynchronous tag check fault mode. + const TCF_ASYNC = 1_u32 << 2; + } +} + +/// Get the current tagged address mode for the calling thread. +/// +/// # References +/// - [`prctl(PR_GET_TAGGED_ADDR_CTRL,...)`] +/// +/// [`prctl(PR_GET_TAGGED_ADDR_CTRL,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +pub fn current_tagged_address_mode() -> io::Result<(Option<TaggedAddressMode>, u32)> { + let r = unsafe { prctl_1arg(PR_GET_TAGGED_ADDR_CTRL)? } as c_uint; + let mode = r & 0b111_u32; + let mte_tag = (r & PR_MTE_TAG_MASK) >> PR_MTE_TAG_SHIFT; + Ok((TaggedAddressMode::from_bits(mode), mte_tag)) +} + +const PR_SET_TAGGED_ADDR_CTRL: c_int = 55; + +/// Controls support for passing tagged user-space addresses to the kernel. +/// +/// # References +/// - [`prctl(PR_SET_TAGGED_ADDR_CTRL,...)`] +/// +/// # Safety +/// +/// Please ensure the conditions necessary to safely call this function, +/// as detailed in the references above. +/// +/// [`prctl(PR_SET_TAGGED_ADDR_CTRL,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +pub unsafe fn set_current_tagged_address_mode( + mode: Option<TaggedAddressMode>, + mte_tag: u32, +) -> io::Result<()> { + let config = mode.as_ref().map_or(0_u32, TaggedAddressMode::bits) + | ((mte_tag << PR_MTE_TAG_SHIFT) & PR_MTE_TAG_MASK); + prctl_2args(PR_SET_TAGGED_ADDR_CTRL, config as usize as *mut _).map(|_r| ()) +} + +// +// PR_SET_SYSCALL_USER_DISPATCH +// + +const PR_SET_SYSCALL_USER_DISPATCH: c_int = 59; + +const PR_SYS_DISPATCH_OFF: usize = 0; + +/// Disable Syscall User Dispatch mechanism. +/// +/// # References +/// - [`prctl(PR_SET_SYSCALL_USER_DISPATCH,PR_SYS_DISPATCH_OFF,...)`] +/// +/// # Safety +/// +/// Please ensure the conditions necessary to safely call this function, +/// as detailed in the references above. +/// +/// [`prctl(PR_SET_SYSCALL_USER_DISPATCH,PR_SYS_DISPATCH_OFF,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +pub unsafe fn disable_syscall_user_dispatch() -> io::Result<()> { + prctl_2args(PR_SET_SYSCALL_USER_DISPATCH, PR_SYS_DISPATCH_OFF as *mut _).map(|_r| ()) +} + +const PR_SYS_DISPATCH_ON: usize = 1; + +/// Allow system calls to be executed. +const SYSCALL_DISPATCH_FILTER_ALLOW: u8 = 0; +/// Block system calls from executing. +const SYSCALL_DISPATCH_FILTER_BLOCK: u8 = 1; + +/// Value of the fast switch flag controlling system calls user dispatch +/// mechanism without the need to issue a syscall. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[repr(u8)] +pub enum SysCallUserDispatchFastSwitch { + /// System calls are allowed to execute. + Allow = SYSCALL_DISPATCH_FILTER_ALLOW, + /// System calls are blocked from executing. + Block = SYSCALL_DISPATCH_FILTER_BLOCK, +} + +impl TryFrom<u8> for SysCallUserDispatchFastSwitch { + type Error = io::Errno; + + fn try_from(value: u8) -> Result<Self, Self::Error> { + match value { + SYSCALL_DISPATCH_FILTER_ALLOW => Ok(Self::Allow), + SYSCALL_DISPATCH_FILTER_BLOCK => Ok(Self::Block), + _ => Err(io::Errno::RANGE), + } + } +} + +/// Enable Syscall User Dispatch mechanism. +/// +/// # References +/// - [`prctl(PR_SET_SYSCALL_USER_DISPATCH,PR_SYS_DISPATCH_ON,...)`] +/// +/// # Safety +/// +/// Please ensure the conditions necessary to safely call this function, +/// as detailed in the references above. +/// +/// [`prctl(PR_SET_SYSCALL_USER_DISPATCH,PR_SYS_DISPATCH_ON,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[inline] +pub unsafe fn enable_syscall_user_dispatch( + always_allowed_region: &[u8], + fast_switch_flag: &AtomicU8, +) -> io::Result<()> { + syscalls::prctl( + PR_SET_SYSCALL_USER_DISPATCH, + PR_SYS_DISPATCH_ON as *mut _, + always_allowed_region.as_ptr() as *mut _, + always_allowed_region.len() as *mut _, + as_ptr(fast_switch_flag) as *mut _, + ) + .map(|_r| ()) +} + +// +// PR_SCHED_CORE +// + +const PR_SCHED_CORE: c_int = 62; + +const PR_SCHED_CORE_GET: usize = 0; + +const PR_SCHED_CORE_SCOPE_THREAD: u32 = 0; +const PR_SCHED_CORE_SCOPE_THREAD_GROUP: u32 = 1; +const PR_SCHED_CORE_SCOPE_PROCESS_GROUP: u32 = 2; + +/// `PR_SCHED_CORE_SCOPE_*`. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[repr(u32)] +pub enum CoreSchedulingScope { + /// Operation will be performed for the thread. + Thread = PR_SCHED_CORE_SCOPE_THREAD, + /// Operation will be performed for all tasks in the task group of the + /// process. + ThreadGroup = PR_SCHED_CORE_SCOPE_THREAD_GROUP, + /// Operation will be performed for all processes in the process group. + ProcessGroup = PR_SCHED_CORE_SCOPE_PROCESS_GROUP, +} + +impl TryFrom<u32> for CoreSchedulingScope { + type Error = io::Errno; + + fn try_from(value: u32) -> Result<Self, Self::Error> { + match value { + PR_SCHED_CORE_SCOPE_THREAD => Ok(Self::Thread), + PR_SCHED_CORE_SCOPE_THREAD_GROUP => Ok(Self::ThreadGroup), + PR_SCHED_CORE_SCOPE_PROCESS_GROUP => Ok(Self::ProcessGroup), + _ => Err(io::Errno::RANGE), + } + } +} + +/// Get core scheduling cookie of a process. +/// +/// # References +/// - [`prctl(PR_SCHED_CORE,PR_SCHED_CORE_GET,...)`] +/// +/// [`prctl(PR_SCHED_CORE,PR_SCHED_CORE_GET,...)`]: https://www.kernel.org/doc/html/v5.18/admin-guide/hw-vuln/core-scheduling.html +#[inline] +pub fn core_scheduling_cookie(pid: Pid, scope: CoreSchedulingScope) -> io::Result<u64> { + let mut value: MaybeUninit<u64> = MaybeUninit::uninit(); + unsafe { + syscalls::prctl( + PR_SCHED_CORE, + PR_SCHED_CORE_GET as *mut _, + pid.as_raw_nonzero().get() as usize as *mut _, + scope as usize as *mut _, + value.as_mut_ptr().cast(), + )?; + Ok(value.assume_init()) + } +} + +const PR_SCHED_CORE_CREATE: usize = 1; + +/// Create unique core scheduling cookie. +/// +/// # References +/// - [`prctl(PR_SCHED_CORE,PR_SCHED_CORE_CREATE,...)`] +/// +/// [`prctl(PR_SCHED_CORE,PR_SCHED_CORE_CREATE,...)`]: https://www.kernel.org/doc/html/v5.18/admin-guide/hw-vuln/core-scheduling.html +#[inline] +pub fn create_core_scheduling_cookie(pid: Pid, scope: CoreSchedulingScope) -> io::Result<()> { + unsafe { + syscalls::prctl( + PR_SCHED_CORE, + PR_SCHED_CORE_CREATE as *mut _, + pid.as_raw_nonzero().get() as usize as *mut _, + scope as usize as *mut _, + ptr::null_mut(), + ) + .map(|_r| ()) + } +} + +const PR_SCHED_CORE_SHARE_TO: usize = 2; + +/// Push core scheduling cookie to a process. +/// +/// # References +/// - [`prctl(PR_SCHED_CORE,PR_SCHED_CORE_SHARE_TO,...)`] +/// +/// [`prctl(PR_SCHED_CORE,PR_SCHED_CORE_SHARE_TO,...)`]: https://www.kernel.org/doc/html/v5.18/admin-guide/hw-vuln/core-scheduling.html +#[inline] +pub fn push_core_scheduling_cookie(pid: Pid, scope: CoreSchedulingScope) -> io::Result<()> { + unsafe { + syscalls::prctl( + PR_SCHED_CORE, + PR_SCHED_CORE_SHARE_TO as *mut _, + pid.as_raw_nonzero().get() as usize as *mut _, + scope as usize as *mut _, + ptr::null_mut(), + ) + .map(|_r| ()) + } +} + +const PR_SCHED_CORE_SHARE_FROM: usize = 3; + +/// Pull core scheduling cookie from a process. +/// +/// # References +/// - [`prctl(PR_SCHED_CORE,PR_SCHED_CORE_SHARE_FROM,...)`] +/// +/// [`prctl(PR_SCHED_CORE,PR_SCHED_CORE_SHARE_FROM,...)`]: https://www.kernel.org/doc/html/v5.18/admin-guide/hw-vuln/core-scheduling.html +#[inline] +pub fn pull_core_scheduling_cookie(pid: Pid, scope: CoreSchedulingScope) -> io::Result<()> { + unsafe { + syscalls::prctl( + PR_SCHED_CORE, + PR_SCHED_CORE_SHARE_FROM as *mut _, + pid.as_raw_nonzero().get() as usize as *mut _, + scope as usize as *mut _, + ptr::null_mut(), + ) + .map(|_r| ()) + } +} diff --git a/vendor/rustix-0.37.22/src/thread/setns.rs b/vendor/rustix-0.37.22/src/thread/setns.rs new file mode 100644 index 000000000..81c9225e3 --- /dev/null +++ b/vendor/rustix-0.37.22/src/thread/setns.rs @@ -0,0 +1,125 @@ +use bitflags::bitflags; +use linux_raw_sys::general::{ + CLONE_FILES, CLONE_FS, CLONE_NEWCGROUP, CLONE_NEWIPC, CLONE_NEWNET, CLONE_NEWNS, CLONE_NEWPID, + CLONE_NEWTIME, CLONE_NEWUSER, CLONE_NEWUTS, CLONE_SYSVSEM, +}; + +use crate::backend::c::c_int; +use crate::backend::thread::syscalls; +use crate::fd::BorrowedFd; +use crate::io; + +bitflags! { + /// Thread name space type. + pub struct ThreadNameSpaceType: u32 { + /// Time name space. + const TIME = CLONE_NEWTIME; + /// Mount name space. + const MOUNT = CLONE_NEWNS; + /// Control group (CGroup) name space. + const CONTROL_GROUP = CLONE_NEWCGROUP; + /// `Host name` and `NIS domain name` (UTS) name space. + const HOST_NAME_AND_NIS_DOMAIN_NAME = CLONE_NEWUTS; + /// Inter-process communication (IPC) name space. + const INTER_PROCESS_COMMUNICATION = CLONE_NEWIPC; + /// User name space. + const USER = CLONE_NEWUSER; + /// Process ID name space. + const PROCESS_ID = CLONE_NEWPID; + /// Network name space. + const NETWORK = CLONE_NEWNET; + } +} + +/// Type of name space referred to by a link. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[repr(u32)] +pub enum LinkNameSpaceType { + /// Time name space. + Time = CLONE_NEWTIME, + /// Mount name space. + Mount = CLONE_NEWNS, + /// Control group (CGroup) name space. + ControlGroup = CLONE_NEWCGROUP, + /// `Host name` and `NIS domain name` (UTS) name space. + HostNameAndNISDomainName = CLONE_NEWUTS, + /// Inter-process communication (IPC) name space. + InterProcessCommunication = CLONE_NEWIPC, + /// User name space. + User = CLONE_NEWUSER, + /// Process ID name space. + ProcessID = CLONE_NEWPID, + /// Network name space. + Network = CLONE_NEWNET, +} + +bitflags! { + /// `CLONE_*` for use with [`unshare`]. + pub struct UnshareFlags: u32 { + /// `CLONE_FILES`. + const FILES = CLONE_FILES; + /// `CLONE_FS`. + const FS = CLONE_FS; + /// `CLONE_NEWCGROUP`. + const NWCGROUP = CLONE_NEWCGROUP; + /// `CLONE_NEWIPC`. + const NEWIPC = CLONE_NEWIPC; + /// `CLONE_NEWNET`. + const NEWNET = CLONE_NEWNET; + /// `CLONE_NEWNS`. + const NEWNS = CLONE_NEWNS; + /// `CLONE_NEWPID`. + const NEWPID = CLONE_NEWPID; + /// `CLONE_NEWTIME`. + const NEWTIME = CLONE_NEWTIME; + /// `CLONE_NEWUSER`. + const NEWUSER = CLONE_NEWUSER; + /// `CLONE_SYSVSEM`. + const SYSVSEM = CLONE_SYSVSEM; + } +} + +/// Reassociate the calling thread with the namespace associated with link +/// referred to by `fd`. +/// +/// `fd` must refer to one of the magic links in a `/proc/[pid]/ns/` directory, +/// or a bind mount to such a link. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/setns.2.html +pub fn move_into_link_name_space( + fd: BorrowedFd, + allowed_type: Option<LinkNameSpaceType>, +) -> io::Result<()> { + let allowed_type = allowed_type.map_or(0, |t| t as c_int); + syscalls::setns(fd, allowed_type).map(|_r| ()) +} + +/// Atomically move the calling thread into one or more of the same namespaces +/// as the thread referred to by `fd`. +/// +/// `fd` must refer to a thread ID. See: `pidfd_open` and `clone`. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/setns.2.html +pub fn move_into_thread_name_spaces( + fd: BorrowedFd, + allowed_types: ThreadNameSpaceType, +) -> io::Result<()> { + syscalls::setns(fd, allowed_types.bits() as c_int).map(|_r| ()) +} + +/// `unshare(flags)`—Disassociate parts of the current thread's execution +/// context with other threads. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/unshare.2.html +pub fn unshare(flags: UnshareFlags) -> io::Result<()> { + syscalls::unshare(flags) +} diff --git a/vendor/rustix-0.37.22/src/time/clock.rs b/vendor/rustix-0.37.22/src/time/clock.rs new file mode 100644 index 000000000..2aa38b213 --- /dev/null +++ b/vendor/rustix-0.37.22/src/time/clock.rs @@ -0,0 +1,108 @@ +use crate::{backend, io}; + +pub use backend::time::types::{Nsecs, Secs, Timespec}; + +/// `clockid_t` +#[cfg(not(target_os = "wasi"))] +pub use backend::time::types::{ClockId, DynamicClockId}; + +/// `clock_getres(id)`—Returns the resolution of a clock. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html +/// [Linux]: https://man7.org/linux/man-pages/man2/clock_getres.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=clock_getres&sektion=2 +/// [NetBSD]: https://man.netbsd.org/clock_getres.2 +/// [OpenBSD]: https://man.openbsd.org/clock_getres.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=clock_getres§ion=2 +/// [illumos]: https://illumos.org/man/3C/clock_getres +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +#[inline] +#[must_use] +pub fn clock_getres(id: ClockId) -> Timespec { + backend::time::syscalls::clock_getres(id) +} + +/// `clock_gettime(id)`—Returns the current value of a clock. +/// +/// This function uses `ClockId` which only contains clocks which are known to +/// always be supported at runtime, allowing this function to be infallible. +/// For a greater set of clocks and dynamic clock support, see +/// [`clock_gettime_dynamic`]. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_gettime.html +/// [Linux]: https://man7.org/linux/man-pages/man2/clock_gettime.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=clock_getres&sektion=2 +/// [NetBSD]: https://man.netbsd.org/clock_getres.2 +/// [OpenBSD]: https://man.openbsd.org/clock_getres.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=clock_getres§ion=2 +/// [illumos]: https://illumos.org/man/3C/clock_gettime +#[cfg(not(target_os = "wasi"))] +#[inline] +#[must_use] +pub fn clock_gettime(id: ClockId) -> Timespec { + backend::time::syscalls::clock_gettime(id) +} + +/// Like [`clock_gettime`] but with support for dynamic clocks. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_gettime.html +/// [Linux]: https://man7.org/linux/man-pages/man2/clock_gettime.2.html +#[cfg(not(target_os = "wasi"))] +#[inline] +pub fn clock_gettime_dynamic(id: DynamicClockId<'_>) -> io::Result<Timespec> { + backend::time::syscalls::clock_gettime_dynamic(id) +} + +/// `clock_settime(id, timespec)`—Sets the current value of a settable clock. +/// +/// This fails with [`io::Errno::INVAL`] if the clock is not settable, and +/// [`io::Errno::ACCESS`] if the current process does not have permission to +/// set it. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_settime.html +/// [Linux]: https://man7.org/linux/man-pages/man2/clock_settime.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=clock_settime&sektion=2 +/// [NetBSD]: https://man.netbsd.org/clock_settime.2 +/// [OpenBSD]: https://man.openbsd.org/clock_settime.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=clock_settime§ion=2 +/// [illumos]: https://illumos.org/man/3C/clock_settime +#[cfg(not(any( + target_os = "redox", + target_os = "wasi", + all(apple, not(target_os = "macos")) +)))] +#[inline] +pub fn clock_settime(id: ClockId, timespec: Timespec) -> io::Result<()> { + backend::time::syscalls::clock_settime(id, timespec) +} diff --git a/vendor/rustix-0.37.22/src/time/mod.rs b/vendor/rustix-0.37.22/src/time/mod.rs new file mode 100644 index 000000000..c633e767f --- /dev/null +++ b/vendor/rustix-0.37.22/src/time/mod.rs @@ -0,0 +1,11 @@ +//! Time-related operations. + +mod clock; +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +mod timerfd; + +// TODO: Convert WASI'S clock APIs to use handles rather than ambient clock +// identifiers, update `wasi-libc`, and then add support in `rustix`. +pub use clock::*; +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +pub use timerfd::*; diff --git a/vendor/rustix-0.37.22/src/time/timerfd.rs b/vendor/rustix-0.37.22/src/time/timerfd.rs new file mode 100644 index 000000000..7f661f7d9 --- /dev/null +++ b/vendor/rustix-0.37.22/src/time/timerfd.rs @@ -0,0 +1,41 @@ +use crate::fd::{AsFd, OwnedFd}; +use crate::{backend, io}; + +pub use backend::time::types::{Itimerspec, TimerfdClockId, TimerfdFlags, TimerfdTimerFlags}; + +/// `timerfd_create(clockid, flags)`—Create a timer. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/timerfd_create.2.html +#[inline] +pub fn timerfd_create(clockid: TimerfdClockId, flags: TimerfdFlags) -> io::Result<OwnedFd> { + backend::time::syscalls::timerfd_create(clockid, flags) +} + +/// `timerfd_settime(clockid, flags, new_value)`—Set the time on a timer. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/timerfd_settime.2.html +#[inline] +pub fn timerfd_settime<Fd: AsFd>( + fd: Fd, + flags: TimerfdTimerFlags, + new_value: &Itimerspec, +) -> io::Result<Itimerspec> { + backend::time::syscalls::timerfd_settime(fd.as_fd(), flags, new_value) +} + +/// `timerfd_gettime(clockid, flags)`—Query a timer. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/timerfd_gettime.2.html +#[inline] +pub fn timerfd_gettime<Fd: AsFd>(fd: Fd) -> io::Result<Itimerspec> { + backend::time::syscalls::timerfd_gettime(fd.as_fd()) +} diff --git a/vendor/rustix-0.37.22/src/utils.rs b/vendor/rustix-0.37.22/src/utils.rs new file mode 100644 index 000000000..df2ac315b --- /dev/null +++ b/vendor/rustix-0.37.22/src/utils.rs @@ -0,0 +1,48 @@ +#![allow(dead_code)] + +use core::ffi::c_void; +use core::mem::{align_of, size_of}; +use core::ptr::{null, null_mut, NonNull}; + +/// Convert a `&T` into a `*const T` without using an `as`. +#[inline] +pub(crate) const fn as_ptr<T>(t: &T) -> *const T { + t +} + +/// Convert a `&mut T` into a `*mut T` without using an `as`. +#[inline] +pub(crate) fn as_mut_ptr<T>(t: &mut T) -> *mut T { + t +} + +/// Convert an `Option<&T>` into a possibly-null `*const T`. +#[inline] +pub(crate) const fn optional_as_ptr<T>(t: Option<&T>) -> *const T { + match t { + Some(t) => t, + None => null(), + } +} + +/// Convert an `Option<&mut T>` into a possibly-null `*mut T`. +#[inline] +pub(crate) fn optional_as_mut_ptr<T>(t: Option<&mut T>) -> *mut T { + match t { + Some(t) => t, + None => null_mut(), + } +} + +/// Convert a `*mut c_void` to a `*mut T`, checking that it is not null, +/// misaligned, or pointing to a region of memory that wraps around the address +/// space. +pub(crate) fn check_raw_pointer<T>(value: *mut c_void) -> Option<NonNull<T>> { + if (value as usize).checked_add(size_of::<T>()).is_none() + || (value as usize) % align_of::<T>() != 0 + { + return None; + } + + NonNull::new(value.cast()) +} diff --git a/vendor/rustix-0.37.22/src/weak.rs b/vendor/rustix-0.37.22/src/weak.rs new file mode 100644 index 000000000..94bcfd375 --- /dev/null +++ b/vendor/rustix-0.37.22/src/weak.rs @@ -0,0 +1,234 @@ +// Implementation derived from `weak` in Rust's +// library/std/src/sys/unix/weak.rs at revision +// fd0cb0cdc21dd9c06025277d772108f8d42cb25f. +// +// Ideally we should update to a newer version which doesn't need `dlsym`, +// however that depends on the `extern_weak` feature which is currrently +// unstable. + +#![cfg_attr(linux_raw, 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::weak::Weak<unsafe extern fn($($t),*) -> $ret> = + $crate::weak::Weak::new(concat!(stringify!($name), '\0')); + ) +} + +pub(crate) struct Weak<F> { + name: &'static str, + addr: AtomicPtr<c_void>, + _marker: marker::PhantomData<F>, +} + +impl<F> Weak<F> { + pub(crate) const fn new(name: &'static str) -> Self { + Self { + name, + addr: AtomicPtr::new(INVALID), + _marker: marker::PhantomData, + } + } + + pub(crate) fn get(&self) -> Option<F> { + assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>()); + 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<F> { + 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(linux_kernel))] +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(linux_kernel)] +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<T> AsSyscallArg for *mut T { + type SyscallArgType = *mut T; + fn into_syscall_arg(self) -> Self::SyscallArgType { self } + } + impl<T> 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. + // + // [unstable]: https://github.com/rust-lang/rust/issues/29599 + /* + 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),*) + } + } + ) +} |