• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 //! Macros and wrapper functions for dealing with ioctls.
6 
7 // Allow missing safety comments because this file provides just thin helper functions for
8 // `libc::ioctl`. Their safety follows `libc::ioctl`'s safety.
9 #![allow(clippy::missing_safety_doc)]
10 
11 use std::os::{raw::*, unix::io::AsRawFd};
12 
13 /// Raw macro to declare the expression that calculates an ioctl number
14 #[macro_export]
15 macro_rules! ioctl_expr {
16     ($dir:expr, $ty:expr, $nr:expr, $size:expr) => {
17         (($dir << $crate::platform::ioctl::_IOC_DIRSHIFT)
18             | ($ty << $crate::platform::ioctl::_IOC_TYPESHIFT)
19             | ($nr << $crate::platform::ioctl::_IOC_NRSHIFT)
20             | ($size << $crate::platform::ioctl::_IOC_SIZESHIFT)) as $crate::platform::IoctlNr
21     };
22 }
23 
24 /// Raw macro to declare a function that returns an ioctl number.
25 #[macro_export]
26 macro_rules! ioctl_ioc_nr {
27     ($name:ident, $dir:expr, $ty:expr, $nr:expr, $size:expr) => {
28         #[allow(non_snake_case)]
29         pub const fn $name() -> $crate::platform::IoctlNr {
30             $crate::ioctl_expr!($dir, $ty, $nr, $size)
31         }
32     };
33     ($name:ident, $dir:expr, $ty:expr, $nr:expr, $size:expr, $($v:ident),+) => {
34         #[allow(non_snake_case)]
35         pub const fn $name($($v: ::std::os::raw::c_uint),+) -> $crate::platform::IoctlNr {
36             $crate::ioctl_expr!($dir, $ty, $nr, $size)
37         }
38     };
39 }
40 
41 /// Declare an ioctl that transfers no data.
42 #[macro_export]
43 macro_rules! ioctl_io_nr {
44     ($name:ident, $ty:expr, $nr:expr) => {
45         $crate::ioctl_ioc_nr!($name, $crate::platform::ioctl::_IOC_NONE, $ty, $nr, 0);
46     };
47     ($name:ident, $ty:expr, $nr:expr, $($v:ident),+) => {
48         $crate::ioctl_ioc_nr!($name, $crate::platform::ioctl::_IOC_NONE, $ty, $nr, 0, $($v),+);
49     };
50 }
51 
52 /// Declare an ioctl that reads data.
53 #[macro_export]
54 macro_rules! ioctl_ior_nr {
55     ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
56         $crate::ioctl_ioc_nr!(
57             $name,
58             $crate::platform::ioctl::_IOC_READ,
59             $ty,
60             $nr,
61             ::std::mem::size_of::<$size>() as u32
62         );
63     };
64     ($name:ident, $ty:expr, $nr:expr, $size:ty, $($v:ident),+) => {
65         $crate::ioctl_ioc_nr!(
66             $name,
67             $crate::platform::ioctl::_IOC_READ,
68             $ty,
69             $nr,
70             ::std::mem::size_of::<$size>() as u32,
71             $($v),+
72         );
73     };
74 }
75 
76 /// Declare an ioctl that writes data.
77 #[macro_export]
78 macro_rules! ioctl_iow_nr {
79     ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
80         $crate::ioctl_ioc_nr!(
81             $name,
82             $crate::platform::ioctl::_IOC_WRITE,
83             $ty,
84             $nr,
85             ::std::mem::size_of::<$size>() as u32
86         );
87     };
88     ($name:ident, $ty:expr, $nr:expr, $size:ty, $($v:ident),+) => {
89         $crate::ioctl_ioc_nr!(
90             $name,
91             $crate::platform::ioctl::_IOC_WRITE,
92             $ty,
93             $nr,
94             ::std::mem::size_of::<$size>() as u32,
95             $($v),+
96         );
97     };
98 }
99 
100 /// Declare an ioctl that reads and writes data.
101 #[macro_export]
102 macro_rules! ioctl_iowr_nr {
103     ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
104         $crate::ioctl_ioc_nr!(
105             $name,
106             $crate::platform::ioctl::_IOC_READ | $crate::platform::ioctl::_IOC_WRITE,
107             $ty,
108             $nr,
109             ::std::mem::size_of::<$size>() as u32
110         );
111     };
112     ($name:ident, $ty:expr, $nr:expr, $size:ty, $($v:ident),+) => {
113         $crate::ioctl_ioc_nr!(
114             $name,
115             $crate::platform::ioctl::_IOC_READ | $crate::platform::ioctl::_IOC_WRITE,
116             $ty,
117             $nr,
118             ::std::mem::size_of::<$size>() as u32,
119             $($v),+
120         );
121     };
122 }
123 
124 pub const _IOC_NRBITS: c_uint = 8;
125 pub const _IOC_TYPEBITS: c_uint = 8;
126 pub const _IOC_SIZEBITS: c_uint = 14;
127 pub const _IOC_DIRBITS: c_uint = 2;
128 pub const _IOC_NRMASK: c_uint = 255;
129 pub const _IOC_TYPEMASK: c_uint = 255;
130 pub const _IOC_SIZEMASK: c_uint = 16383;
131 pub const _IOC_DIRMASK: c_uint = 3;
132 pub const _IOC_NRSHIFT: c_uint = 0;
133 pub const _IOC_TYPESHIFT: c_uint = 8;
134 pub const _IOC_SIZESHIFT: c_uint = 16;
135 pub const _IOC_DIRSHIFT: c_uint = 30;
136 pub const _IOC_NONE: c_uint = 0;
137 pub const _IOC_WRITE: c_uint = 1;
138 pub const _IOC_READ: c_uint = 2;
139 pub const IOC_IN: c_uint = 1_073_741_824;
140 pub const IOC_OUT: c_uint = 2_147_483_648;
141 pub const IOC_INOUT: c_uint = 3_221_225_472;
142 pub const IOCSIZE_MASK: c_uint = 1_073_676_288;
143 pub const IOCSIZE_SHIFT: c_uint = 16;
144 
145 #[cfg(target_os = "android")]
146 pub type IoctlNr = c_int;
147 #[cfg(not(target_os = "android"))]
148 pub type IoctlNr = c_ulong;
149 
150 /// Run an ioctl with no arguments.
ioctl<F: AsRawFd>(fd: &F, nr: IoctlNr) -> c_int151 pub unsafe fn ioctl<F: AsRawFd>(fd: &F, nr: IoctlNr) -> c_int {
152     libc::ioctl(fd.as_raw_fd(), nr, 0)
153 }
154 
155 /// Run an ioctl with a single value argument.
ioctl_with_val<F: AsRawFd>(fd: &F, nr: IoctlNr, arg: c_ulong) -> c_int156 pub unsafe fn ioctl_with_val<F: AsRawFd>(fd: &F, nr: IoctlNr, arg: c_ulong) -> c_int {
157     libc::ioctl(fd.as_raw_fd(), nr, arg)
158 }
159 
160 /// Run an ioctl with an immutable reference.
ioctl_with_ref<F: AsRawFd, T>(fd: &F, nr: IoctlNr, arg: &T) -> c_int161 pub unsafe fn ioctl_with_ref<F: AsRawFd, T>(fd: &F, nr: IoctlNr, arg: &T) -> c_int {
162     libc::ioctl(fd.as_raw_fd(), nr, arg as *const T as *const c_void)
163 }
164 
165 /// Run an ioctl with a mutable reference.
ioctl_with_mut_ref<F: AsRawFd, T>(fd: &F, nr: IoctlNr, arg: &mut T) -> c_int166 pub unsafe fn ioctl_with_mut_ref<F: AsRawFd, T>(fd: &F, nr: IoctlNr, arg: &mut T) -> c_int {
167     libc::ioctl(fd.as_raw_fd(), nr, arg as *mut T as *mut c_void)
168 }
169 
170 /// Run an ioctl with a raw pointer.
ioctl_with_ptr<F: AsRawFd, T>(fd: &F, nr: IoctlNr, arg: *const T) -> c_int171 pub unsafe fn ioctl_with_ptr<F: AsRawFd, T>(fd: &F, nr: IoctlNr, arg: *const T) -> c_int {
172     libc::ioctl(fd.as_raw_fd(), nr, arg as *const c_void)
173 }
174 
175 /// Run an ioctl with a mutable raw pointer.
ioctl_with_mut_ptr<F: AsRawFd, T>(fd: &F, nr: IoctlNr, arg: *mut T) -> c_int176 pub unsafe fn ioctl_with_mut_ptr<F: AsRawFd, T>(fd: &F, nr: IoctlNr, arg: *mut T) -> c_int {
177     libc::ioctl(fd.as_raw_fd(), nr, arg as *mut c_void)
178 }
179 
180 #[cfg(test)]
181 mod tests {
182     const TUNTAP: ::std::os::raw::c_uint = 0x54;
183     const VHOST: ::std::os::raw::c_uint = 0xaf;
184     const EVDEV: ::std::os::raw::c_uint = 0x45;
185 
186     ioctl_io_nr!(VHOST_SET_OWNER, VHOST, 0x01);
187     ioctl_ior_nr!(TUNGETFEATURES, TUNTAP, 0xcf, ::std::os::raw::c_uint);
188     ioctl_iow_nr!(TUNSETQUEUE, TUNTAP, 0xd9, ::std::os::raw::c_int);
189     ioctl_iowr_nr!(VHOST_GET_VRING_BASE, VHOST, 0x12, ::std::os::raw::c_int);
190 
191     ioctl_ior_nr!(EVIOCGBIT, EVDEV, 0x20 + evt, [u8; 128], evt);
192     ioctl_io_nr!(FAKE_IOCTL_2_ARG, EVDEV, 0x01 + x + y, x, y);
193 
194     #[test]
ioctl_macros()195     fn ioctl_macros() {
196         assert_eq!(0x0000af01, VHOST_SET_OWNER());
197         assert_eq!(0x800454cf, TUNGETFEATURES());
198         assert_eq!(0x400454d9, TUNSETQUEUE());
199         assert_eq!(0xc004af12, VHOST_GET_VRING_BASE());
200 
201         assert_eq!(0x80804522, EVIOCGBIT(2));
202         assert_eq!(0x00004509, FAKE_IOCTL_2_ARG(3, 5));
203     }
204 }
205