Simple porting tools for ioctl(2) driver interfaces on Unix-like systems.
Let's use uinput to create a userspace input device on Linux.
From linux/uinput.h:
/* ioctl */
#define UINPUT_IOCTL_BASE 'U'
#define UI_DEV_CREATE _IO(UINPUT_IOCTL_BASE, 1)
#define UI_DEV_DESTROY _IO(UINPUT_IOCTL_BASE, 2)
...
#define UI_DEV_SETUP _IOW(UINPUT_IOCTL_BASE, 3, struct uinput_setup)use std::{mem, fs::File, ffi::c_char};
use libc::uinput_setup;
use uoctl::*;
const UINPUT_IOCTL_BASE: u8 = b'U';
const UI_DEV_CREATE: Ioctl<NoArgs> = _IO(UINPUT_IOCTL_BASE, 1);
const UI_DEV_DESTROY: Ioctl<NoArgs> = _IO(UINPUT_IOCTL_BASE, 2);
const UI_DEV_SETUP: Ioctl<*const uinput_setup> = _IOW(UINPUT_IOCTL_BASE, 3);
let uinput = File::options().write(true).open("/dev/uinput")?;
let mut setup: libc::uinput_setup = unsafe { mem::zeroed() };
setup.name[0] = b'A' as c_char; // (must not be blank)
unsafe {
UI_DEV_SETUP.ioctl(&uinput, &setup)?;
UI_DEV_CREATE.ioctl(&uinput)?;
// ...use the device...
UI_DEV_DESTROY.ioctl(&uinput)?;
}
# std::io::Result::Ok(())I mainly wrote this crate because I was unhappy with the alternatives:
libc::ioctl- The raw
ioctlfunction provides no built-in error conversion and requires knowing theioctlrequest number. libcdoes provideconst fns that mirror the_IOxmacros, but they are only exposed on Linux and have no type safety.
- The raw
nix::ioctl_X!- Looks nothing like the
ioctldefinitions found in C headers. - Requires very frequent conscious
nixupdates because it publishes A LOT of breaking changes.
- Looks nothing like the
- Other crates for this are either abandoned or also frequently publish breaking changes that I'd have to consciously migrate to.
- Instead, I want a crate that tries to only cover
ioctls, and has a decently designed API that doesn't see much breakage.
- Instead, I want a crate that tries to only cover
- Almost none of these alternatives except
libcmake translation of C headers to Rust very easy.- The Rust code required to do the thing often looks completely different to the equivalent C definitions.
- As
ioctls are a low-level interface often accessed by directly porting a C header, it is beneficial if the result is easy to visually compare to the original C code.
Thus, this library was born in an attempt to address these problems.
This library targets the latest Rust version.
Older Rust versions are supported by equally older versions of this crate. For example, to use a version of Rust that was succeeded 6 months ago, you'd also use an at least 6 month old version of this library.
Compatibility with older Rust versions may be provided on a best-effort basis.