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