1#![allow(clippy::missing_safety_doc)]
10
11use std::os::raw::c_int;
12use std::os::raw::c_uint;
13use std::os::raw::c_ulong;
14use std::os::raw::c_void;
15
16use crate::descriptor::AsRawDescriptor;
17
18#[macro_export]
20macro_rules! ioctl_expr {
21 ($dir:expr, $ty:expr, $nr:expr, $size:expr) => {
22 ((($dir as $crate::linux::IoctlNr) << $crate::linux::ioctl::_IOC_DIRSHIFT)
23 | (($ty as $crate::linux::IoctlNr) << $crate::linux::ioctl::_IOC_TYPESHIFT)
24 | (($nr as $crate::linux::IoctlNr) << $crate::linux::ioctl::_IOC_NRSHIFT)
25 | (($size as $crate::linux::IoctlNr) << $crate::linux::ioctl::_IOC_SIZESHIFT))
26 };
27}
28
29#[macro_export]
31macro_rules! ioctl_ioc_nr {
32 ($name:ident, $dir:expr, $ty:expr, $nr:expr, $size:expr) => {
33 #[allow(non_snake_case)]
34 pub const $name: $crate::linux::IoctlNr = $crate::ioctl_expr!($dir, $ty, $nr, $size);
36 };
37 ($name:ident, $dir:expr, $ty:expr, $nr:expr, $size:expr, $($v:ident),+) => {
38 #[allow(non_snake_case)]
39 pub const fn $name($($v: ::std::os::raw::c_uint),+) -> $crate::linux::IoctlNr {
41 $crate::ioctl_expr!($dir, $ty, $nr, $size)
42 }
43 };
44}
45
46#[macro_export]
48macro_rules! ioctl_io_nr {
49 ($name:ident, $ty:expr, $nr:expr) => {
50 $crate::ioctl_ioc_nr!($name, $crate::linux::ioctl::_IOC_NONE, $ty, $nr, 0);
51 };
52 ($name:ident, $ty:expr, $nr:expr, $($v:ident),+) => {
53 $crate::ioctl_ioc_nr!($name, $crate::linux::ioctl::_IOC_NONE, $ty, $nr, 0, $($v),+);
54 };
55}
56
57#[macro_export]
59macro_rules! ioctl_ior_nr {
60 ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
61 $crate::ioctl_ioc_nr!(
62 $name,
63 $crate::linux::ioctl::_IOC_READ,
64 $ty,
65 $nr,
66 ::std::mem::size_of::<$size>() as u32
67 );
68 };
69 ($name:ident, $ty:expr, $nr:expr, $size:ty, $($v:ident),+) => {
70 $crate::ioctl_ioc_nr!(
71 $name,
72 $crate::linux::ioctl::_IOC_READ,
73 $ty,
74 $nr,
75 ::std::mem::size_of::<$size>() as u32,
76 $($v),+
77 );
78 };
79}
80
81#[macro_export]
83macro_rules! ioctl_iow_nr {
84 ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
85 $crate::ioctl_ioc_nr!(
86 $name,
87 $crate::linux::ioctl::_IOC_WRITE,
88 $ty,
89 $nr,
90 ::std::mem::size_of::<$size>() as u32
91 );
92 };
93 ($name:ident, $ty:expr, $nr:expr, $size:ty, $($v:ident),+) => {
94 $crate::ioctl_ioc_nr!(
95 $name,
96 $crate::linux::ioctl::_IOC_WRITE,
97 $ty,
98 $nr,
99 ::std::mem::size_of::<$size>() as u32,
100 $($v),+
101 );
102 };
103}
104
105#[macro_export]
107macro_rules! ioctl_iowr_nr {
108 ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
109 $crate::ioctl_ioc_nr!(
110 $name,
111 $crate::linux::ioctl::_IOC_READ | $crate::linux::ioctl::_IOC_WRITE,
112 $ty,
113 $nr,
114 ::std::mem::size_of::<$size>() as u32
115 );
116 };
117 ($name:ident, $ty:expr, $nr:expr, $size:ty, $($v:ident),+) => {
118 $crate::ioctl_ioc_nr!(
119 $name,
120 $crate::linux::ioctl::_IOC_READ | $crate::linux::ioctl::_IOC_WRITE,
121 $ty,
122 $nr,
123 ::std::mem::size_of::<$size>() as u32,
124 $($v),+
125 );
126 };
127}
128
129pub const _IOC_NRBITS: c_uint = 8;
130pub const _IOC_TYPEBITS: c_uint = 8;
131pub const _IOC_SIZEBITS: c_uint = 14;
132pub const _IOC_DIRBITS: c_uint = 2;
133pub const _IOC_NRMASK: c_uint = 255;
134pub const _IOC_TYPEMASK: c_uint = 255;
135pub const _IOC_SIZEMASK: c_uint = 16383;
136pub const _IOC_DIRMASK: c_uint = 3;
137pub const _IOC_NRSHIFT: c_uint = 0;
138pub const _IOC_TYPESHIFT: c_uint = 8;
139pub const _IOC_SIZESHIFT: c_uint = 16;
140pub const _IOC_DIRSHIFT: c_uint = 30;
141pub const _IOC_NONE: c_uint = 0;
142pub const _IOC_WRITE: c_uint = 1;
143pub const _IOC_READ: c_uint = 2;
144pub const IOC_IN: c_uint = 1_073_741_824;
145pub const IOC_OUT: c_uint = 2_147_483_648;
146pub const IOC_INOUT: c_uint = 3_221_225_472;
147pub const IOCSIZE_MASK: c_uint = 1_073_676_288;
148pub const IOCSIZE_SHIFT: c_uint = 16;
149
150#[cfg(any(target_os = "android", target_env = "musl"))]
151pub type IoctlNr = c_int;
152#[cfg(not(any(target_os = "android", target_env = "musl")))]
153pub type IoctlNr = c_ulong;
154
155pub unsafe fn ioctl<F: AsRawDescriptor>(descriptor: &F, nr: IoctlNr) -> c_int {
159 libc::ioctl(descriptor.as_raw_descriptor(), nr, 0)
160}
161
162pub unsafe fn ioctl_with_val(descriptor: &dyn AsRawDescriptor, nr: IoctlNr, arg: c_ulong) -> c_int {
166 libc::ioctl(descriptor.as_raw_descriptor(), nr, arg)
167}
168
169pub unsafe fn ioctl_with_ref<T: ?Sized>(
174 descriptor: &dyn AsRawDescriptor,
175 nr: IoctlNr,
176 arg: &T,
177) -> c_int {
178 libc::ioctl(
179 descriptor.as_raw_descriptor(),
180 nr,
181 arg as *const T as *const c_void,
182 )
183}
184
185pub unsafe fn ioctl_with_mut_ref<T: ?Sized>(
190 descriptor: &dyn AsRawDescriptor,
191 nr: IoctlNr,
192 arg: &mut T,
193) -> c_int {
194 libc::ioctl(
195 descriptor.as_raw_descriptor(),
196 nr,
197 arg as *mut T as *mut c_void,
198 )
199}
200
201pub unsafe fn ioctl_with_ptr<T: ?Sized>(
205 descriptor: &dyn AsRawDescriptor,
206 nr: IoctlNr,
207 arg: *const T,
208) -> c_int {
209 libc::ioctl(descriptor.as_raw_descriptor(), nr, arg as *const c_void)
210}
211
212pub unsafe fn ioctl_with_mut_ptr<T: ?Sized>(
216 descriptor: &dyn AsRawDescriptor,
217 nr: IoctlNr,
218 arg: *mut T,
219) -> c_int {
220 libc::ioctl(descriptor.as_raw_descriptor(), nr, arg as *mut c_void)
221}
222#[cfg(test)]
223mod tests {
224 const TUNTAP: ::std::os::raw::c_uint = 0x54;
225 const VHOST: ::std::os::raw::c_uint = 0xaf;
226 const EVDEV: ::std::os::raw::c_uint = 0x45;
227
228 ioctl_io_nr!(VHOST_SET_OWNER, VHOST, 0x01);
229 ioctl_ior_nr!(TUNGETFEATURES, TUNTAP, 0xcf, ::std::os::raw::c_uint);
230 ioctl_iow_nr!(TUNSETQUEUE, TUNTAP, 0xd9, ::std::os::raw::c_int);
231 ioctl_iowr_nr!(VHOST_GET_VRING_BASE, VHOST, 0x12, ::std::os::raw::c_int);
232
233 ioctl_ior_nr!(EVIOCGBIT, EVDEV, 0x20 + evt, [u8; 128], evt);
234 ioctl_io_nr!(FAKE_IOCTL_2_ARG, EVDEV, 0x01 + x + y, x, y);
235
236 #[test]
237 fn ioctl_macros() {
238 assert_eq!(0x0000af01, VHOST_SET_OWNER);
239 assert_eq!(0x800454cf, TUNGETFEATURES);
240 assert_eq!(0x400454d9, TUNSETQUEUE);
241 assert_eq!(0xc004af12, VHOST_GET_VRING_BASE);
242
243 assert_eq!(0x80804522, EVIOCGBIT(2));
244 assert_eq!(0x00004509, FAKE_IOCTL_2_ARG(3, 5));
245 }
246}