Struct Ioctl

Source
pub struct Ioctl<T: ?Sized = NoArgs> { /* private fields */ }
Expand description

An ioctl.

Ioctl can represent ioctls that take either no arguments or a single argument. If T is NoArgs, the ioctl takes no arguments. For other values of T, the ioctl takes T as its only argument. Often, the argument T is a pointer to a struct that contains the actual arguments.

While Ioctl cannot handle ioctls that require passing more than one argument to the ioctl(2) function, Linux doesn’t have any ioctls that take more than one argument, and is unlikely to gain any in the future.

The Ioctl type is constructed with the free functions _IO, _IOR, _IOW, _IOWR, and _IOC. For legacy ioctls, it can also be created via Ioctl::from_raw.

Implementations§

Source§

impl<T: ?Sized> Ioctl<T>

Source

pub const fn from_raw(request: u32) -> Self

Creates an Ioctl object from a raw request code and an arbitrary argument type.

This can be used for legacy ioctls that were defined before the _IOx macros were introduced.

§Examples

From asm-generic/ioctls.h:

#define FIONREAD	0x541B

From man 2const FIONREAD:

DESCRIPTION
    FIONREAD
        Get the number of bytes in the input buffer.
    ...
SYNOPSIS
    ...
    int ioctl(int fd, FIONREAD, int *argp);
    ...
use std::io;
use std::fs::File;
use std::ffi::c_int;
use linux_ioctl::*;

const FIONREAD: Ioctl<*mut c_int> = Ioctl::from_raw(0x541B);

let file = File::open("/dev/ptmx")
    .map_err(|e| io::Error::new(e.kind(), format!("failed to open `/dev/ptmx`: {e}")))?;

let mut bytes = c_int::MAX;
unsafe { FIONREAD.ioctl(&file, &mut bytes)? };
assert_ne!(bytes, c_int::MAX);

println!("{} bytes in input buffer", bytes);
Source

pub const fn with_arg<T2>(self) -> Ioctl<T2>

Changes the ioctl argument type to T2.

This can be used for ioctls that incorrectly declare their type, or for ioctls that take a by-value argument, rather than _IOW-type ioctls that take their argument indirectly through a pointer.

Returns an Ioctl that passes an argument of type T2 to the kernel, while using the ioctl request code from self.

§Examples

The KVM_CREATE_VM ioctl is declared with _IO, but expects an int argument to be passed to ioctl(2), specifying the VM type (KVM_VM_*).

From linux/kvm.h:

#define KVMIO 0xAE
...
#define KVM_CREATE_VM             _IO(KVMIO,   0x01) /* returns a VM fd */
use std::fs::File;
use std::ffi::c_int;
use linux_ioctl::*;

const KVMIO: u8 = 0xAE;
const KVM_CREATE_VM: Ioctl<c_int> = _IO(KVMIO, 0x01).with_arg::<c_int>();

// The `KVM_CREATE_VM` ioctl takes the VM type as an argument. 0 is a reasonable default on
// most architectures.
let vm_type: c_int = 0;

let file = File::open("/dev/kvm")?;

let vm_fd = unsafe { KVM_CREATE_VM.ioctl(&file, vm_type)? };
println!("created new VM with file descriptor {vm_fd}");

unsafe { libc::close(vm_fd) };
Source

pub fn request(self) -> u32

Returns the ioctl request code.

This is passed to ioctl(2) as its second argument.

Source§

impl<T> Ioctl<*const T>

Source

pub const fn with_direct_arg(self) -> Ioctl<T>

Changes the Ioctl argument type to be passed directly instead of behind a pointer.

Does not change the request code.

Many linux headers define ioctls like _IOW('U', 100, int), but then expect the int argument to be passed as a direct argument to ioctl(2) instead of passing a pointer. This method can be used to bind to these ioctls.

§Example

uinput defines several ioctls where this method is useful:

#define UI_SET_EVBIT		_IOW(UINPUT_IOCTL_BASE, 100, int)
use std::ffi::c_int;
use linux_ioctl::{Ioctl, _IOW};

const UI_SET_EVBIT: Ioctl<c_int> = _IOW(b'U', 100).with_direct_arg();
Source

pub const fn cast_mut(self) -> Ioctl<*mut T>

Casts the Ioctl so that it takes a *mut pointer instead of a *const pointer.

This can be used to fix an ioctl that is incorrectly declared as only reading its argument through the pointer (with _IOW), when in reality the kernel can write through the pointer as well.

An ioctl that writes through its pointer argument, but is incorrectly declared as Ioctl<*const T> will generally cause UB when invoked with an immutable reference.

Also see Ioctl::cast_const for the opposite direction.

§Example

The EVIOCSFF ioctl from evdev is incorrectly declared with _IOW, but may write to the data, as documented here:

“request” must be EVIOCSFF.

“effect” points to a structure describing the effect to upload. The effect is uploaded, but not played. The content of effect may be modified.

https://www.kernel.org/doc/html/latest/input/ff.html

use std::ffi::c_void as ff_effect;
use linux_ioctl::{Ioctl, _IOW};

pub const EVIOCSFF: Ioctl<*mut ff_effect> = _IOW(b'E', 0x80).cast_mut();
Source§

impl<T> Ioctl<*mut T>

Source

pub const fn cast_const(self) -> Ioctl<*const T>

Casts the Ioctl so that it takes a *const pointer instead of a *mut pointer.

This performs the opposite operation of Ioctl::cast_mut, and can be used when an ioctl is incorrectly declared as writing to its argument (yielding an Ioctl<*mut T>) when it actually only reads from it.

Only use this method if you are sure it is correct! If the ioctl does write through the pointer, the result is likely UB!

Source§

impl Ioctl<NoArgs>

Source

pub unsafe fn ioctl(self, fd: &impl AsRawFd) -> Result<c_int>

Performs an ioctl that doesn’t take an argument.

On success, returns the value returned by the ioctl syscall. On error (when ioctl returns -1), returns the error from errno.

Note that the actual ioctl(2) call performed will pass 0 as a dummy argument to the ioctl. This is because some Linux ioctls are declared without an argument, but will fail unless they receive 0 as their argument (eg. KVM_GET_API_VERSION). There should be no harm in passing this argument unconditionally, as the kernel will typically just ignore excess arguments.

§Safety

This method performs an arbitrary ioctl on an arbitrary file descriptor. The caller has to ensure that any safety requirements of the ioctl are met, and that fd belongs to the driver it expects.

Source§

impl<T> Ioctl<T>

Source

pub unsafe fn ioctl(self, fd: &impl AsRawFd, arg: T) -> Result<c_int>

Performs an ioctl that takes an argument of type T.

Returns the value returned by the ioctl(2) invocation, or an I/O error if the call failed.

For many ioctls, T will be a pointer to the actual argument. The caller must ensure that it points to valid data that conforms to the requirements of the ioctl.

§Safety

This method performs an arbitrary ioctl on an arbitrary file descriptor. The caller has to ensure that any safety requirements of the ioctl are met, and that fd belongs to the driver it expects.

Trait Implementations§

Source§

impl<T: ?Sized> Clone for Ioctl<T>

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<T: ?Sized> Copy for Ioctl<T>

Auto Trait Implementations§

§

impl<T> Freeze for Ioctl<T>
where T: ?Sized,

§

impl<T> RefUnwindSafe for Ioctl<T>
where T: RefUnwindSafe + ?Sized,

§

impl<T> Send for Ioctl<T>
where T: Send + ?Sized,

§

impl<T> Sync for Ioctl<T>
where T: Sync + ?Sized,

§

impl<T> Unpin for Ioctl<T>
where T: Unpin + ?Sized,

§

impl<T> UnwindSafe for Ioctl<T>
where T: UnwindSafe + ?Sized,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.