#![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;
#[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();
let output = if I::IS_MUTATING {
_ioctl(fd, request, arg)?
} else {
_ioctl_readonly(fd, request, arg)?
};
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)
}
pub unsafe trait Ioctl {
type Output;
const OPCODE: Opcode;
const IS_MUTATING: bool;
fn as_ptr(&mut self) -> *mut c::c_void;
unsafe fn output_from_ptr(
out: IoctlOutput,
extract_output: *mut c::c_void,
) -> Result<Self::Output>;
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Opcode {
raw: RawOpcode,
}
impl Opcode {
#[inline]
pub const fn old(raw: RawOpcode) -> Self {
Self { raw }
}
#[cfg(any(linux_kernel, bsd))]
#[inline]
pub const fn from_components(
direction: Direction,
group: u8,
number: u8,
data_size: usize,
) -> Self {
assert!(
data_size <= RawOpcode::MAX as usize,
"data size is too large"
);
Self::old(platform::compose_opcode(
direction,
group as RawOpcode,
number as RawOpcode,
data_size as RawOpcode,
))
}
#[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>())
}
#[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>())
}
#[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>())
}
#[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>())
}
#[inline]
pub fn raw(self) -> RawOpcode {
self.raw
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Direction {
None,
Read,
Write,
ReadWrite,
}
pub type IoctlOutput = c::c_int;
pub type RawOpcode = _RawOpcode;
#[cfg(linux_raw)]
type _RawOpcode = c::c_uint;
#[cfg(all(
not(linux_raw),
target_os = "linux",
any(target_env = "gnu", target_env = "uclibc")
))]
type _RawOpcode = c::c_ulong;
#[cfg(all(
not(linux_raw),
target_os = "linux",
not(target_env = "gnu"),
not(target_env = "uclibc")
))]
type _RawOpcode = c::c_int;
#[cfg(all(not(linux_raw), target_os = "android"))]
type _RawOpcode = c::c_int;
#[cfg(any(
bsd,
target_os = "redox",
target_os = "haiku",
target_os = "horizon",
target_os = "hurd",
target_os = "vita"
))]
type _RawOpcode = c::c_ulong;
#[cfg(any(
solarish,
target_os = "aix",
target_os = "fuchsia",
target_os = "emscripten",
target_os = "wasi",
target_os = "nto"
))]
type _RawOpcode = c::c_int;
#[cfg(target_os = "espidf")]
type _RawOpcode = c::c_uint;
#[cfg(windows)]
type _RawOpcode = i32;