summaryrefslogtreecommitdiff
path: root/vendor/rustix/src/ioctl/patterns.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/rustix/src/ioctl/patterns.rs')
-rw-r--r--vendor/rustix/src/ioctl/patterns.rs268
1 files changed, 268 insertions, 0 deletions
diff --git a/vendor/rustix/src/ioctl/patterns.rs b/vendor/rustix/src/ioctl/patterns.rs
new file mode 100644
index 00000000..a08aae74
--- /dev/null
+++ b/vendor/rustix/src/ioctl/patterns.rs
@@ -0,0 +1,268 @@
+//! Implements typical patterns for `ioctl` usage.
+
+use super::{Ioctl, IoctlOutput, Opcode};
+
+use crate::backend::c;
+use crate::io::Result;
+
+use core::ptr::addr_of_mut;
+use core::{fmt, mem};
+
+/// Implements an `ioctl` with no real arguments.
+///
+/// To compute a value for the `OPCODE` argument, see the functions in the
+/// [`opcode`] module.
+///
+/// [`opcode`]: crate::ioctl::opcode
+pub struct NoArg<const OPCODE: Opcode> {}
+
+impl<const OPCODE: Opcode> fmt::Debug for NoArg<OPCODE> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_tuple("NoArg").field(&OPCODE).finish()
+ }
+}
+
+impl<const OPCODE: Opcode> NoArg<OPCODE> {
+ /// Create a new no-argument `ioctl` object.
+ ///
+ /// # Safety
+ ///
+ /// - `OPCODE` must provide a valid opcode.
+ #[inline]
+ pub const unsafe fn new() -> Self {
+ Self {}
+ }
+}
+
+unsafe impl<const OPCODE: Opcode> Ioctl for NoArg<OPCODE> {
+ type Output = ();
+
+ const IS_MUTATING: bool = false;
+
+ fn opcode(&self) -> self::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.
+///
+/// To compute a value for the `OPCODE` argument, see the functions in the
+/// [`opcode`] module.
+///
+/// [`opcode`]: crate::ioctl::opcode
+pub struct Getter<const OPCODE: Opcode, Output> {
+ /// The output data.
+ output: mem::MaybeUninit<Output>,
+}
+
+impl<const OPCODE: Opcode, Output> fmt::Debug for Getter<OPCODE, Output> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_tuple("Getter").field(&OPCODE).finish()
+ }
+}
+
+impl<const OPCODE: Opcode, 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 const unsafe fn new() -> Self {
+ Self {
+ output: mem::MaybeUninit::uninit(),
+ }
+ }
+}
+
+unsafe impl<const OPCODE: Opcode, Output> Ioctl for Getter<OPCODE, Output> {
+ type Output = Output;
+
+ const IS_MUTATING: bool = true;
+
+ fn opcode(&self) -> self::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.
+///
+/// To compute a value for the `OPCODE` argument, see the functions in the
+/// [`opcode`] module.
+///
+/// [`opcode`]: crate::ioctl::opcode
+pub struct Setter<const OPCODE: Opcode, Input> {
+ /// The input data.
+ input: Input,
+}
+
+impl<const OPCODE: Opcode, Input: fmt::Debug> fmt::Debug for Setter<OPCODE, Input> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_tuple("Setter")
+ .field(&OPCODE)
+ .field(&self.input)
+ .finish()
+ }
+}
+
+impl<const OPCODE: Opcode, 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 const unsafe fn new(input: Input) -> Self {
+ Self { input }
+ }
+}
+
+unsafe impl<const OPCODE: Opcode, Input> Ioctl for Setter<OPCODE, Input> {
+ type Output = ();
+
+ const IS_MUTATING: bool = false;
+
+ fn opcode(&self) -> self::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.
+///
+/// To compute a value for the `OPCODE` argument, see the functions in the
+/// [`opcode`] module.
+///
+/// [`opcode`]: crate::ioctl::opcode
+pub struct Updater<'a, const OPCODE: Opcode, Value> {
+ /// Reference to input/output data.
+ value: &'a mut Value,
+}
+
+impl<'a, const OPCODE: Opcode, 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 }
+ }
+}
+
+unsafe impl<'a, const OPCODE: Opcode, T> Ioctl for Updater<'a, OPCODE, T> {
+ type Output = ();
+
+ const IS_MUTATING: bool = true;
+
+ fn opcode(&self) -> self::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(())
+ }
+}
+
+/// Implements an `ioctl` that passes an integer into the `ioctl`.
+///
+/// To compute a value for the `OPCODE` argument, see the functions in the
+/// [`opcode`] module.
+///
+/// [`opcode`]: crate::ioctl::opcode
+pub struct IntegerSetter<const OPCODE: Opcode> {
+ /// The value to pass in.
+ ///
+ /// For strict provenance preservation, this is a pointer.
+ value: *mut c::c_void,
+}
+
+impl<const OPCODE: Opcode> IntegerSetter<OPCODE> {
+ /// Create a new integer `Ioctl` helper containing a `usize`.
+ ///
+ /// # Safety
+ ///
+ /// - `OPCODE` must provide a valid opcode.
+ /// - For this opcode, it must expect an integer.
+ /// - The integer is in the valid range for this opcode.
+ #[inline]
+ pub const unsafe fn new_usize(value: usize) -> Self {
+ Self { value: value as _ }
+ }
+
+ /// Create a new integer `Ioctl` helper containing a `*mut c_void`.
+ ///
+ /// # Safety
+ ///
+ /// - `OPCODE` must provide a valid opcode.
+ /// - For this opcode, it must expect an integer.
+ /// - The integer is in the valid range for this opcode.
+ #[inline]
+ pub const unsafe fn new_pointer(value: *mut c::c_void) -> Self {
+ Self { value }
+ }
+}
+
+unsafe impl<const OPCODE: Opcode> Ioctl for IntegerSetter<OPCODE> {
+ type Output = ();
+
+ const IS_MUTATING: bool = false;
+
+ fn opcode(&self) -> self::Opcode {
+ OPCODE
+ }
+
+ fn as_ptr(&mut self) -> *mut c::c_void {
+ self.value
+ }
+
+ unsafe fn output_from_ptr(
+ _out: IoctlOutput,
+ _extract_output: *mut c::c_void,
+ ) -> Result<Self::Output> {
+ Ok(())
+ }
+}