Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
27
third-party/vendor/rustix/src/ioctl/bsd.rs
vendored
Normal file
27
third-party/vendor/rustix/src/ioctl/bsd.rs
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
//! `ioctl` opcode behavior for BSD platforms.
|
||||
|
||||
use super::{Direction, RawOpcode};
|
||||
|
||||
pub(super) const fn compose_opcode(
|
||||
dir: Direction,
|
||||
group: RawOpcode,
|
||||
num: RawOpcode,
|
||||
size: RawOpcode,
|
||||
) -> RawOpcode {
|
||||
let dir = match dir {
|
||||
Direction::None => NONE,
|
||||
Direction::Read => READ,
|
||||
Direction::Write => WRITE,
|
||||
Direction::ReadWrite => READ | WRITE,
|
||||
};
|
||||
|
||||
dir | num | (group << 8) | ((size & IOCPARAM_MASK) << 16)
|
||||
}
|
||||
|
||||
// `IOC_VOID`
|
||||
pub const NONE: RawOpcode = 0x2000_0000;
|
||||
// `IOC_OUT` ("out" is from the perspective of the kernel)
|
||||
pub const READ: RawOpcode = 0x4000_0000;
|
||||
// `IOC_IN`
|
||||
pub const WRITE: RawOpcode = 0x8000_0000;
|
||||
pub const IOCPARAM_MASK: RawOpcode = 0x1FFF;
|
||||
118
third-party/vendor/rustix/src/ioctl/linux.rs
vendored
Normal file
118
third-party/vendor/rustix/src/ioctl/linux.rs
vendored
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
//! `ioctl` opcode behavior for Linux platforms.
|
||||
|
||||
use super::{Direction, RawOpcode};
|
||||
use consts::*;
|
||||
|
||||
/// Compose an opcode from its component parts.
|
||||
pub(super) const fn compose_opcode(
|
||||
dir: Direction,
|
||||
group: RawOpcode,
|
||||
num: RawOpcode,
|
||||
size: RawOpcode,
|
||||
) -> RawOpcode {
|
||||
macro_rules! mask_and_shift {
|
||||
($val:expr, $shift:expr, $mask:expr) => {{
|
||||
($val & $mask) << $shift
|
||||
}};
|
||||
}
|
||||
|
||||
let dir = match dir {
|
||||
Direction::None => NONE,
|
||||
Direction::Read => READ,
|
||||
Direction::Write => WRITE,
|
||||
Direction::ReadWrite => READ | WRITE,
|
||||
};
|
||||
|
||||
mask_and_shift!(group, GROUP_SHIFT, GROUP_MASK)
|
||||
| mask_and_shift!(num, NUM_SHIFT, NUM_MASK)
|
||||
| mask_and_shift!(size, SIZE_SHIFT, SIZE_MASK)
|
||||
| mask_and_shift!(dir, DIR_SHIFT, DIR_MASK)
|
||||
}
|
||||
|
||||
const NUM_BITS: RawOpcode = 8;
|
||||
const GROUP_BITS: RawOpcode = 8;
|
||||
|
||||
const NUM_SHIFT: RawOpcode = 0;
|
||||
const GROUP_SHIFT: RawOpcode = NUM_SHIFT + NUM_BITS;
|
||||
const SIZE_SHIFT: RawOpcode = GROUP_SHIFT + GROUP_BITS;
|
||||
const DIR_SHIFT: RawOpcode = SIZE_SHIFT + SIZE_BITS;
|
||||
|
||||
const NUM_MASK: RawOpcode = (1 << NUM_BITS) - 1;
|
||||
const GROUP_MASK: RawOpcode = (1 << GROUP_BITS) - 1;
|
||||
const SIZE_MASK: RawOpcode = (1 << SIZE_BITS) - 1;
|
||||
const DIR_MASK: RawOpcode = (1 << DIR_BITS) - 1;
|
||||
|
||||
#[cfg(any(
|
||||
target_arch = "x86",
|
||||
target_arch = "arm",
|
||||
target_arch = "s390x",
|
||||
target_arch = "x86_64",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "riscv32",
|
||||
target_arch = "riscv64",
|
||||
target_arch = "loongarch64",
|
||||
target_arch = "csky"
|
||||
))]
|
||||
mod consts {
|
||||
use super::RawOpcode;
|
||||
|
||||
pub(super) const NONE: RawOpcode = 0;
|
||||
pub(super) const READ: RawOpcode = 2;
|
||||
pub(super) const WRITE: RawOpcode = 1;
|
||||
pub(super) const SIZE_BITS: RawOpcode = 14;
|
||||
pub(super) const DIR_BITS: RawOpcode = 2;
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_arch = "mips",
|
||||
target_arch = "mips32r6",
|
||||
target_arch = "mips64",
|
||||
target_arch = "mips64r6",
|
||||
target_arch = "powerpc",
|
||||
target_arch = "powerpc64",
|
||||
target_arch = "sparc",
|
||||
target_arch = "sparc64"
|
||||
))]
|
||||
mod consts {
|
||||
use super::RawOpcode;
|
||||
|
||||
pub(super) const NONE: RawOpcode = 1;
|
||||
pub(super) const READ: RawOpcode = 2;
|
||||
pub(super) const WRITE: RawOpcode = 4;
|
||||
pub(super) const SIZE_BITS: RawOpcode = 13;
|
||||
pub(super) const DIR_BITS: RawOpcode = 3;
|
||||
}
|
||||
|
||||
#[cfg(not(any(
|
||||
// These have no ioctl opcodes defined in linux_raw_sys
|
||||
// so can't use that as a known-good value for this test.
|
||||
target_arch = "sparc",
|
||||
target_arch = "sparc64"
|
||||
)))]
|
||||
#[test]
|
||||
fn check_known_opcodes() {
|
||||
use crate::backend::c::{c_long, c_uint};
|
||||
use core::mem::size_of;
|
||||
|
||||
// _IOR('U', 15, unsigned int)
|
||||
assert_eq!(
|
||||
compose_opcode(
|
||||
Direction::Read,
|
||||
b'U' as RawOpcode,
|
||||
15,
|
||||
size_of::<c_uint>() as RawOpcode
|
||||
),
|
||||
linux_raw_sys::ioctl::USBDEVFS_CLAIMINTERFACE as RawOpcode
|
||||
);
|
||||
|
||||
// _IOW('v', 2, long)
|
||||
assert_eq!(
|
||||
compose_opcode(
|
||||
Direction::Write,
|
||||
b'v' as RawOpcode,
|
||||
2,
|
||||
size_of::<c_long>() as RawOpcode
|
||||
),
|
||||
linux_raw_sys::ioctl::FS_IOC_SETVERSION as RawOpcode
|
||||
);
|
||||
}
|
||||
357
third-party/vendor/rustix/src/ioctl/mod.rs
vendored
Normal file
357
third-party/vendor/rustix/src/ioctl/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,357 @@
|
|||
//! Unsafe `ioctl` API.
|
||||
//!
|
||||
//! Unix systems expose a number of `ioctl`'s. `ioctl`s have been adopted as a
|
||||
//! general purpose system call for making calls into the kernel. In addition
|
||||
//! to the wide variety of system calls that are included by default in the
|
||||
//! kernel, many drivers expose their own `ioctl`'s for controlling their
|
||||
//! behavior, some of which are proprietary. Therefore it is impossible to make
|
||||
//! a safe interface for every `ioctl` call, as they all have wildly varying
|
||||
//! semantics.
|
||||
//!
|
||||
//! This module provides an unsafe interface to write your own `ioctl` API. To
|
||||
//! start, create a type that implements [`Ioctl`]. Then, pass it to [`ioctl`]
|
||||
//! to make the `ioctl` call.
|
||||
|
||||
#![allow(unsafe_code)]
|
||||
|
||||
use crate::backend::c;
|
||||
use crate::fd::{AsFd, BorrowedFd};
|
||||
use crate::io::Result;
|
||||
|
||||
#[cfg(any(linux_kernel, bsd))]
|
||||
use core::mem;
|
||||
|
||||
pub use patterns::*;
|
||||
|
||||
mod patterns;
|
||||
|
||||
#[cfg(linux_kernel)]
|
||||
mod linux;
|
||||
|
||||
#[cfg(bsd)]
|
||||
mod bsd;
|
||||
|
||||
#[cfg(linux_kernel)]
|
||||
use linux as platform;
|
||||
|
||||
#[cfg(bsd)]
|
||||
use bsd as platform;
|
||||
|
||||
/// Perform an `ioctl` call.
|
||||
///
|
||||
/// `ioctl` was originally intended to act as a way of modifying the behavior
|
||||
/// of files, but has since been adopted as a general purpose system call for
|
||||
/// making calls into the kernel. In addition to the default calls exposed by
|
||||
/// generic file descriptors, many drivers expose their own `ioctl` calls for
|
||||
/// controlling their behavior, some of which are proprietary.
|
||||
///
|
||||
/// This crate exposes many other `ioctl` interfaces with safe and idiomatic
|
||||
/// wrappers, like [`ioctl_fionbio`] and [`ioctl_fionread`]. It is recommended
|
||||
/// to use those instead of this function, as they are safer and more
|
||||
/// idiomatic. For other cases, implement the [`Ioctl`] API and pass it to this
|
||||
/// function.
|
||||
///
|
||||
/// See documentation for [`Ioctl`] for more information.
|
||||
///
|
||||
/// [`ioctl_fionbio`]: crate::io::ioctl_fionbio
|
||||
/// [`ioctl_fionread`]: crate::io::ioctl_fionread
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// While [`Ioctl`] takes much of the unsafety out of `ioctl` calls, it is
|
||||
/// still unsafe to call this code with arbitrary device drivers, as it is up
|
||||
/// to the device driver to implement the `ioctl` call correctly. It is on the
|
||||
/// onus of the protocol between the user and the driver to ensure that the
|
||||
/// `ioctl` call is safe to make.
|
||||
///
|
||||
/// # References
|
||||
/// - [Linux]
|
||||
/// - [Winsock]
|
||||
/// - [FreeBSD]
|
||||
/// - [NetBSD]
|
||||
/// - [OpenBSD]
|
||||
/// - [Apple]
|
||||
/// - [Solaris]
|
||||
/// - [illumos]
|
||||
///
|
||||
/// [Linux]: https://man7.org/linux/man-pages/man2/ioctl.2.html
|
||||
/// [Winsock]: https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-ioctlsocket
|
||||
/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=ioctl&sektion=2
|
||||
/// [NetBSD]: https://man.netbsd.org/ioctl.2
|
||||
/// [OpenBSD]: https://man.openbsd.org/ioctl.2
|
||||
/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/ioctl.2.html
|
||||
/// [Solaris]: https://docs.oracle.com/cd/E23824_01/html/821-1463/ioctl-2.html
|
||||
/// [illumos]: https://illumos.org/man/2/ioctl
|
||||
#[inline]
|
||||
pub unsafe fn ioctl<F: AsFd, I: Ioctl>(fd: F, mut ioctl: I) -> Result<I::Output> {
|
||||
let fd = fd.as_fd();
|
||||
let request = I::OPCODE.raw();
|
||||
let arg = ioctl.as_ptr();
|
||||
|
||||
// SAFETY: The variant of `Ioctl` asserts that this is a valid IOCTL call
|
||||
// to make.
|
||||
let output = if I::IS_MUTATING {
|
||||
_ioctl(fd, request, arg)?
|
||||
} else {
|
||||
_ioctl_readonly(fd, request, arg)?
|
||||
};
|
||||
|
||||
// SAFETY: The variant of `Ioctl` asserts that this is a valid pointer to
|
||||
// the output data.
|
||||
I::output_from_ptr(output, arg)
|
||||
}
|
||||
|
||||
unsafe fn _ioctl(
|
||||
fd: BorrowedFd<'_>,
|
||||
request: RawOpcode,
|
||||
arg: *mut c::c_void,
|
||||
) -> Result<IoctlOutput> {
|
||||
crate::backend::io::syscalls::ioctl(fd, request, arg)
|
||||
}
|
||||
|
||||
unsafe fn _ioctl_readonly(
|
||||
fd: BorrowedFd<'_>,
|
||||
request: RawOpcode,
|
||||
arg: *mut c::c_void,
|
||||
) -> Result<IoctlOutput> {
|
||||
crate::backend::io::syscalls::ioctl_readonly(fd, request, arg)
|
||||
}
|
||||
|
||||
/// A trait defining the properties of an `ioctl` command.
|
||||
///
|
||||
/// Objects implementing this trait can be passed to [`ioctl`] to make an
|
||||
/// `ioctl` call. The contents of the object represent the inputs to the
|
||||
/// `ioctl` call. The inputs must be convertible to a pointer through the
|
||||
/// `as_ptr` method. In most cases, this involves either casting a number to a
|
||||
/// pointer, or creating a pointer to the actual data. The latter case is
|
||||
/// necessary for `ioctl` calls that modify userspace data.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This trait is unsafe to implement because it is impossible to guarantee
|
||||
/// that the `ioctl` call is safe. The `ioctl` call may be proprietary, or it
|
||||
/// may be unsafe to call in certain circumstances.
|
||||
///
|
||||
/// By implementing this trait, you guarantee that:
|
||||
///
|
||||
/// - The `ioctl` call expects the input provided by `as_ptr` and produces the
|
||||
/// output as indicated by `output`.
|
||||
/// - That `output_from_ptr` can safely take the pointer from `as_ptr` and cast
|
||||
/// it to the correct type, *only* after the `ioctl` call.
|
||||
/// - That `OPCODE` uniquely identifies the `ioctl` call.
|
||||
/// - That, for whatever platforms you are targeting, the `ioctl` call is safe
|
||||
/// to make.
|
||||
/// - If `IS_MUTATING` is false, that no userspace data will be modified by the
|
||||
/// `ioctl` call.
|
||||
pub unsafe trait Ioctl {
|
||||
/// The type of the output data.
|
||||
///
|
||||
/// Given a pointer, one should be able to construct an instance of this
|
||||
/// type.
|
||||
type Output;
|
||||
|
||||
/// The opcode used by this `ioctl` command.
|
||||
///
|
||||
/// There are different types of opcode depending on the operation. See
|
||||
/// documentation for the [`Opcode`] struct for more information.
|
||||
const OPCODE: Opcode;
|
||||
|
||||
/// Does the `ioctl` mutate any data in the userspace?
|
||||
///
|
||||
/// If the `ioctl` call does not mutate any data in the userspace, then
|
||||
/// making this `false` enables optimizations that can make the call
|
||||
/// faster. When in doubt, set this to `true`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This should only be set to `false` if the `ioctl` call does not mutate
|
||||
/// any data in the userspace. Undefined behavior may occur if this is set
|
||||
/// to `false` when it should be `true`.
|
||||
const IS_MUTATING: bool;
|
||||
|
||||
/// Get a pointer to the data to be passed to the `ioctl` command.
|
||||
///
|
||||
/// See trait-level documentation for more information.
|
||||
fn as_ptr(&mut self) -> *mut c::c_void;
|
||||
|
||||
/// Cast the output data to the correct type.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The `extract_output` value must be the resulting value after a
|
||||
/// successful `ioctl` call, and `out` is the direct return value of an
|
||||
/// `ioctl` call that did not fail. In this case `extract_output` is the
|
||||
/// pointer that was passed to the `ioctl` call.
|
||||
unsafe fn output_from_ptr(
|
||||
out: IoctlOutput,
|
||||
extract_output: *mut c::c_void,
|
||||
) -> Result<Self::Output>;
|
||||
}
|
||||
|
||||
/// The opcode used by an `Ioctl`.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct Opcode {
|
||||
/// The raw opcode.
|
||||
raw: RawOpcode,
|
||||
}
|
||||
|
||||
impl Opcode {
|
||||
/// Create a new old `Opcode` from a raw opcode.
|
||||
///
|
||||
/// Rather than being a composition of several attributes, old opcodes are
|
||||
/// just numbers. In general most drivers follow stricter conventions, but
|
||||
/// older drivers may still use this strategy.
|
||||
#[inline]
|
||||
pub const fn old(raw: RawOpcode) -> Self {
|
||||
Self { raw }
|
||||
}
|
||||
|
||||
/// Create a new opcode from a direction, group, number, and size.
|
||||
///
|
||||
/// This corresponds to the C macro `_IOC(direction, group, number, size)`
|
||||
#[cfg(any(linux_kernel, bsd))]
|
||||
#[inline]
|
||||
pub const fn from_components(
|
||||
direction: Direction,
|
||||
group: u8,
|
||||
number: u8,
|
||||
data_size: usize,
|
||||
) -> Self {
|
||||
if data_size > RawOpcode::MAX as usize {
|
||||
panic!("data size is too large");
|
||||
}
|
||||
|
||||
Self::old(platform::compose_opcode(
|
||||
direction,
|
||||
group as RawOpcode,
|
||||
number as RawOpcode,
|
||||
data_size as RawOpcode,
|
||||
))
|
||||
}
|
||||
|
||||
/// Create a new non-mutating opcode from a group, a number, and the type
|
||||
/// of data.
|
||||
///
|
||||
/// This corresponds to the C macro `_IO(group, number)` when `T` is zero
|
||||
/// sized.
|
||||
#[cfg(any(linux_kernel, bsd))]
|
||||
#[inline]
|
||||
pub const fn none<T>(group: u8, number: u8) -> Self {
|
||||
Self::from_components(Direction::None, group, number, mem::size_of::<T>())
|
||||
}
|
||||
|
||||
/// Create a new reading opcode from a group, a number and the type of
|
||||
/// data.
|
||||
///
|
||||
/// This corresponds to the C macro `_IOR(group, number, T)`.
|
||||
#[cfg(any(linux_kernel, bsd))]
|
||||
#[inline]
|
||||
pub const fn read<T>(group: u8, number: u8) -> Self {
|
||||
Self::from_components(Direction::Read, group, number, mem::size_of::<T>())
|
||||
}
|
||||
|
||||
/// Create a new writing opcode from a group, a number and the type of
|
||||
/// data.
|
||||
///
|
||||
/// This corresponds to the C macro `_IOW(group, number, T)`.
|
||||
#[cfg(any(linux_kernel, bsd))]
|
||||
#[inline]
|
||||
pub const fn write<T>(group: u8, number: u8) -> Self {
|
||||
Self::from_components(Direction::Write, group, number, mem::size_of::<T>())
|
||||
}
|
||||
|
||||
/// Create a new reading and writing opcode from a group, a number and the
|
||||
/// type of data.
|
||||
///
|
||||
/// This corresponds to the C macro `_IOWR(group, number, T)`.
|
||||
#[cfg(any(linux_kernel, bsd))]
|
||||
#[inline]
|
||||
pub const fn read_write<T>(group: u8, number: u8) -> Self {
|
||||
Self::from_components(Direction::ReadWrite, group, number, mem::size_of::<T>())
|
||||
}
|
||||
|
||||
/// Get the raw opcode.
|
||||
#[inline]
|
||||
pub fn raw(self) -> RawOpcode {
|
||||
self.raw
|
||||
}
|
||||
}
|
||||
|
||||
/// The direction that an `ioctl` is going.
|
||||
///
|
||||
/// Note that this is relative to userspace. `Read` means reading data from the
|
||||
/// kernel, and write means the kernel writing data to userspace.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub enum Direction {
|
||||
/// None of the above.
|
||||
None,
|
||||
|
||||
/// Read data from the kernel.
|
||||
Read,
|
||||
|
||||
/// Write data to the kernel.
|
||||
Write,
|
||||
|
||||
/// Read and write data to the kernel.
|
||||
ReadWrite,
|
||||
}
|
||||
|
||||
/// The type used by the `ioctl` to signify the output.
|
||||
pub type IoctlOutput = c::c_int;
|
||||
|
||||
/// The type used by the `ioctl` to signify the command.
|
||||
pub type RawOpcode = _RawOpcode;
|
||||
|
||||
// Under raw Linux, this is an `unsigned int`.
|
||||
#[cfg(linux_raw)]
|
||||
type _RawOpcode = c::c_uint;
|
||||
|
||||
// On libc Linux with GNU libc or uclibc, this is an `unsigned long`.
|
||||
#[cfg(all(
|
||||
not(linux_raw),
|
||||
target_os = "linux",
|
||||
any(target_env = "gnu", target_env = "uclibc")
|
||||
))]
|
||||
type _RawOpcode = c::c_ulong;
|
||||
|
||||
// Musl uses `c_int`.
|
||||
#[cfg(all(
|
||||
not(linux_raw),
|
||||
target_os = "linux",
|
||||
not(target_env = "gnu"),
|
||||
not(target_env = "uclibc")
|
||||
))]
|
||||
type _RawOpcode = c::c_int;
|
||||
|
||||
// Android uses `c_int`.
|
||||
#[cfg(all(not(linux_raw), target_os = "android"))]
|
||||
type _RawOpcode = c::c_int;
|
||||
|
||||
// BSD, Haiku, Hurd, Redox, and Vita use `unsigned long`.
|
||||
#[cfg(any(
|
||||
bsd,
|
||||
target_os = "redox",
|
||||
target_os = "haiku",
|
||||
target_os = "hurd",
|
||||
target_os = "vita"
|
||||
))]
|
||||
type _RawOpcode = c::c_ulong;
|
||||
|
||||
// AIX, Emscripten, Fuchsia, Solaris, and WASI use a `int`.
|
||||
#[cfg(any(
|
||||
solarish,
|
||||
target_os = "aix",
|
||||
target_os = "fuchsia",
|
||||
target_os = "emscripten",
|
||||
target_os = "wasi",
|
||||
target_os = "nto"
|
||||
))]
|
||||
type _RawOpcode = c::c_int;
|
||||
|
||||
// ESP-IDF uses a `c_uint`.
|
||||
#[cfg(target_os = "espidf")]
|
||||
type _RawOpcode = c::c_uint;
|
||||
|
||||
// Windows has `ioctlsocket`, which uses `i32`.
|
||||
#[cfg(windows)]
|
||||
type _RawOpcode = i32;
|
||||
256
third-party/vendor/rustix/src/ioctl/patterns.rs
vendored
Normal file
256
third-party/vendor/rustix/src/ioctl/patterns.rs
vendored
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
//! Implements typical patterns for `ioctl` usage.
|
||||
|
||||
use super::{Ioctl, IoctlOutput, Opcode, RawOpcode};
|
||||
|
||||
use crate::backend::c;
|
||||
use crate::io::Result;
|
||||
|
||||
use core::marker::PhantomData;
|
||||
use core::ptr::addr_of_mut;
|
||||
use core::{fmt, mem};
|
||||
|
||||
/// Implements an `ioctl` with no real arguments.
|
||||
pub struct NoArg<Opcode> {
|
||||
/// The opcode.
|
||||
_opcode: PhantomData<Opcode>,
|
||||
}
|
||||
|
||||
impl<Opcode: CompileTimeOpcode> fmt::Debug for NoArg<Opcode> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_tuple("NoArg").field(&Opcode::OPCODE).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Opcode: CompileTimeOpcode> NoArg<Opcode> {
|
||||
/// Create a new no-argument `ioctl` object.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// - `Opcode` must provide a valid opcode.
|
||||
#[inline]
|
||||
pub unsafe fn new() -> Self {
|
||||
Self {
|
||||
_opcode: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<Opcode: CompileTimeOpcode> Ioctl for NoArg<Opcode> {
|
||||
type Output = ();
|
||||
|
||||
const IS_MUTATING: bool = false;
|
||||
const OPCODE: self::Opcode = Opcode::OPCODE;
|
||||
|
||||
fn as_ptr(&mut self) -> *mut c::c_void {
|
||||
core::ptr::null_mut()
|
||||
}
|
||||
|
||||
unsafe fn output_from_ptr(_: IoctlOutput, _: *mut c::c_void) -> Result<Self::Output> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Implements the traditional “getter” pattern for `ioctl`s.
|
||||
///
|
||||
/// Some `ioctl`s just read data into the userspace. As this is a popular
|
||||
/// pattern this structure implements it.
|
||||
pub struct Getter<Opcode, Output> {
|
||||
/// The output data.
|
||||
output: mem::MaybeUninit<Output>,
|
||||
|
||||
/// The opcode.
|
||||
_opcode: PhantomData<Opcode>,
|
||||
}
|
||||
|
||||
impl<Opcode: CompileTimeOpcode, Output> fmt::Debug for Getter<Opcode, Output> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_tuple("Getter").field(&Opcode::OPCODE).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Opcode: CompileTimeOpcode, Output> Getter<Opcode, Output> {
|
||||
/// Create a new getter-style `ioctl` object.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// - `Opcode` must provide a valid opcode.
|
||||
/// - For this opcode, `Output` must be the type that the kernel expects to
|
||||
/// write into.
|
||||
#[inline]
|
||||
pub unsafe fn new() -> Self {
|
||||
Self {
|
||||
output: mem::MaybeUninit::uninit(),
|
||||
_opcode: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<Opcode: CompileTimeOpcode, Output> Ioctl for Getter<Opcode, Output> {
|
||||
type Output = Output;
|
||||
|
||||
const IS_MUTATING: bool = true;
|
||||
const OPCODE: self::Opcode = Opcode::OPCODE;
|
||||
|
||||
fn as_ptr(&mut self) -> *mut c::c_void {
|
||||
self.output.as_mut_ptr().cast()
|
||||
}
|
||||
|
||||
unsafe fn output_from_ptr(_: IoctlOutput, ptr: *mut c::c_void) -> Result<Self::Output> {
|
||||
Ok(ptr.cast::<Output>().read())
|
||||
}
|
||||
}
|
||||
|
||||
/// Implements the pattern for `ioctl`s where a pointer argument is given to
|
||||
/// the `ioctl`.
|
||||
///
|
||||
/// The opcode must be read-only.
|
||||
pub struct Setter<Opcode, Input> {
|
||||
/// The input data.
|
||||
input: Input,
|
||||
|
||||
/// The opcode.
|
||||
_opcode: PhantomData<Opcode>,
|
||||
}
|
||||
|
||||
impl<Opcode: CompileTimeOpcode, Input: fmt::Debug> fmt::Debug for Setter<Opcode, Input> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_tuple("Setter")
|
||||
.field(&Opcode::OPCODE)
|
||||
.field(&self.input)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Opcode: CompileTimeOpcode, Input> Setter<Opcode, Input> {
|
||||
/// Create a new pointer setter-style `ioctl` object.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// - `Opcode` must provide a valid opcode.
|
||||
/// - For this opcode, `Input` must be the type that the kernel expects to
|
||||
/// get.
|
||||
#[inline]
|
||||
pub unsafe fn new(input: Input) -> Self {
|
||||
Self {
|
||||
input,
|
||||
_opcode: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<Opcode: CompileTimeOpcode, Input> Ioctl for Setter<Opcode, Input> {
|
||||
type Output = ();
|
||||
|
||||
const IS_MUTATING: bool = false;
|
||||
const OPCODE: self::Opcode = Opcode::OPCODE;
|
||||
|
||||
fn as_ptr(&mut self) -> *mut c::c_void {
|
||||
addr_of_mut!(self.input).cast::<c::c_void>()
|
||||
}
|
||||
|
||||
unsafe fn output_from_ptr(_: IoctlOutput, _: *mut c::c_void) -> Result<Self::Output> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Implements an “updater” pattern for `ioctl`s.
|
||||
///
|
||||
/// The ioctl takes a reference to a struct that it reads its input from,
|
||||
/// then writes output to the same struct.
|
||||
pub struct Updater<'a, Opcode, Value> {
|
||||
/// Reference to input/output data.
|
||||
value: &'a mut Value,
|
||||
|
||||
/// The opcode.
|
||||
_opcode: PhantomData<Opcode>,
|
||||
}
|
||||
|
||||
impl<'a, Opcode: CompileTimeOpcode, Value> Updater<'a, Opcode, Value> {
|
||||
/// Create a new pointer updater-style `ioctl` object.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// - `Opcode` must provide a valid opcode.
|
||||
/// - For this opcode, `Value` must be the type that the kernel expects to
|
||||
/// get.
|
||||
#[inline]
|
||||
pub unsafe fn new(value: &'a mut Value) -> Self {
|
||||
Self {
|
||||
value,
|
||||
_opcode: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<'a, Opcode: CompileTimeOpcode, T> Ioctl for Updater<'a, Opcode, T> {
|
||||
type Output = ();
|
||||
|
||||
const IS_MUTATING: bool = true;
|
||||
const OPCODE: self::Opcode = Opcode::OPCODE;
|
||||
|
||||
fn as_ptr(&mut self) -> *mut c::c_void {
|
||||
(self.value as *mut T).cast()
|
||||
}
|
||||
|
||||
unsafe fn output_from_ptr(_output: IoctlOutput, _ptr: *mut c::c_void) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait for something that provides an `ioctl` opcode at compile time.
|
||||
pub trait CompileTimeOpcode {
|
||||
/// The opcode.
|
||||
const OPCODE: Opcode;
|
||||
}
|
||||
|
||||
/// Provides a bad opcode at compile time.
|
||||
pub struct BadOpcode<const OPCODE: RawOpcode>;
|
||||
|
||||
impl<const OPCODE: RawOpcode> CompileTimeOpcode for BadOpcode<OPCODE> {
|
||||
const OPCODE: Opcode = Opcode::old(OPCODE);
|
||||
}
|
||||
|
||||
/// Provides a read code at compile time.
|
||||
///
|
||||
/// This corresponds to the C macro `_IOR(GROUP, NUM, Data)`.
|
||||
#[cfg(any(linux_kernel, bsd))]
|
||||
pub struct ReadOpcode<const GROUP: u8, const NUM: u8, Data>(Data);
|
||||
|
||||
#[cfg(any(linux_kernel, bsd))]
|
||||
impl<const GROUP: u8, const NUM: u8, Data> CompileTimeOpcode for ReadOpcode<GROUP, NUM, Data> {
|
||||
const OPCODE: Opcode = Opcode::read::<Data>(GROUP, NUM);
|
||||
}
|
||||
|
||||
/// Provides a write code at compile time.
|
||||
///
|
||||
/// This corresponds to the C macro `_IOW(GROUP, NUM, Data)`.
|
||||
#[cfg(any(linux_kernel, bsd))]
|
||||
pub struct WriteOpcode<const GROUP: u8, const NUM: u8, Data>(Data);
|
||||
|
||||
#[cfg(any(linux_kernel, bsd))]
|
||||
impl<const GROUP: u8, const NUM: u8, Data> CompileTimeOpcode for WriteOpcode<GROUP, NUM, Data> {
|
||||
const OPCODE: Opcode = Opcode::write::<Data>(GROUP, NUM);
|
||||
}
|
||||
|
||||
/// Provides a read/write code at compile time.
|
||||
///
|
||||
/// This corresponds to the C macro `_IOWR(GROUP, NUM, Data)`.
|
||||
#[cfg(any(linux_kernel, bsd))]
|
||||
pub struct ReadWriteOpcode<const GROUP: u8, const NUM: u8, Data>(Data);
|
||||
|
||||
#[cfg(any(linux_kernel, bsd))]
|
||||
impl<const GROUP: u8, const NUM: u8, Data> CompileTimeOpcode for ReadWriteOpcode<GROUP, NUM, Data> {
|
||||
const OPCODE: Opcode = Opcode::read_write::<Data>(GROUP, NUM);
|
||||
}
|
||||
|
||||
/// Provides a `None` code at compile time.
|
||||
///
|
||||
/// This corresponds to the C macro `_IO(GROUP, NUM)` when `Data` is zero
|
||||
/// sized.
|
||||
#[cfg(any(linux_kernel, bsd))]
|
||||
pub struct NoneOpcode<const GROUP: u8, const NUM: u8, Data>(Data);
|
||||
|
||||
#[cfg(any(linux_kernel, bsd))]
|
||||
impl<const GROUP: u8, const NUM: u8, Data> CompileTimeOpcode for NoneOpcode<GROUP, NUM, Data> {
|
||||
const OPCODE: Opcode = Opcode::none::<Data>(GROUP, NUM);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue