diff --git a/src/ioctl/patterns.rs b/src/ioctl/patterns.rs index 6cf7ebd61..0fb600556 100644 --- a/src/ioctl/patterns.rs +++ b/src/ioctl/patterns.rs @@ -197,6 +197,51 @@ unsafe impl<'a, Opcode: CompileTimeOpcode, T> Ioctl for Updater<'a, Opcode, T> { } } +/// Implements an `ioctl` that passes an integer into the `ioctl`. +pub struct IntegerSetter { + /// The value to pass in. + value: usize, + + /// The opcode. + _opcode: PhantomData, +} + +impl IntegerSetter { + /// Create a new integer `Ioctl` helper. + /// + /// # 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 unsafe fn new(value: usize) -> Self { + Self { + value, + _opcode: PhantomData, + } + } +} + +unsafe impl Ioctl for IntegerSetter { + type Output = (); + + const IS_MUTATING: bool = false; + const OPCODE: self::Opcode = Opcode::OPCODE; + + fn as_ptr(&mut self) -> *mut c::c_void { + // TODO: strict provenance + self.value as *mut c::c_void + } + + unsafe fn output_from_ptr( + _out: IoctlOutput, + _extract_output: *mut c::c_void, + ) -> Result { + Ok(()) + } +} + /// Trait for something that provides an `ioctl` opcode at compile time. pub trait CompileTimeOpcode { /// The opcode. diff --git a/tests/io/ioctl.rs b/tests/io/ioctl.rs index cb5bc6715..cc8cd987c 100644 --- a/tests/io/ioctl.rs +++ b/tests/io/ioctl.rs @@ -13,3 +13,20 @@ fn test_ioctls() { file.metadata().unwrap().len() ); } + +#[cfg(all(target_os = "linux", feature = "fs"))] +#[test] +fn test_int_setter() { + use rustix::fs::{open, Mode, OFlags}; + use rustix::ioctl::{ioctl, BadOpcode, IntegerSetter, RawOpcode}; + + const TUNSETOFFLOAD: RawOpcode = 0x400454D0; + + let tun = open("/dev/net/tun", OFlags::RDWR, Mode::empty()).unwrap(); + + // SAFETY: TUNSETOFFLOAD is defined for TUN. + unsafe { + let code = IntegerSetter::>::new(0); + assert!(ioctl(&tun, code).is_err()); + } +}