Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/base/src/sys/linux/ioctl.rs
5394 views
1
// Copyright 2017 The ChromiumOS Authors
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::c_int;
12
use std::os::raw::c_uint;
13
use std::os::raw::c_ulong;
14
use std::os::raw::c_void;
15
16
use crate::descriptor::AsRawDescriptor;
17
18
/// Raw macro to declare the expression that calculates an ioctl number
19
#[macro_export]
20
macro_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
/// Raw macro to declare a constant or a function that returns an ioctl number.
30
#[macro_export]
31
macro_rules! ioctl_ioc_nr {
32
($name:ident, $dir:expr, $ty:expr, $nr:expr, $size:expr) => {
33
#[allow(non_snake_case)]
34
/// Constant ioctl request number.
35
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
/// Generates ioctl request number.
40
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
/// Declare an ioctl that transfers no data.
47
#[macro_export]
48
macro_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
/// Declare an ioctl that reads data.
58
#[macro_export]
59
macro_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
/// Declare an ioctl that writes data.
82
#[macro_export]
83
macro_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
/// Declare an ioctl that reads and writes data.
106
#[macro_export]
107
macro_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
129
pub const _IOC_NRBITS: c_uint = 8;
130
pub const _IOC_TYPEBITS: c_uint = 8;
131
pub const _IOC_SIZEBITS: c_uint = 14;
132
pub const _IOC_DIRBITS: c_uint = 2;
133
pub const _IOC_NRMASK: c_uint = 255;
134
pub const _IOC_TYPEMASK: c_uint = 255;
135
pub const _IOC_SIZEMASK: c_uint = 16383;
136
pub const _IOC_DIRMASK: c_uint = 3;
137
pub const _IOC_NRSHIFT: c_uint = 0;
138
pub const _IOC_TYPESHIFT: c_uint = 8;
139
pub const _IOC_SIZESHIFT: c_uint = 16;
140
pub const _IOC_DIRSHIFT: c_uint = 30;
141
pub const _IOC_NONE: c_uint = 0;
142
pub const _IOC_WRITE: c_uint = 1;
143
pub const _IOC_READ: c_uint = 2;
144
pub const IOC_IN: c_uint = 1_073_741_824;
145
pub const IOC_OUT: c_uint = 2_147_483_648;
146
pub const IOC_INOUT: c_uint = 3_221_225_472;
147
pub const IOCSIZE_MASK: c_uint = 1_073_676_288;
148
pub const IOCSIZE_SHIFT: c_uint = 16;
149
150
#[cfg(any(target_os = "android", target_env = "musl"))]
151
pub type IoctlNr = c_int;
152
#[cfg(not(any(target_os = "android", target_env = "musl")))]
153
pub type IoctlNr = c_ulong;
154
155
/// Run an ioctl with no arguments.
156
/// # Safety
157
/// The caller is responsible for determining the safety of the particular ioctl.
158
pub unsafe fn ioctl<F: AsRawDescriptor>(descriptor: &F, nr: IoctlNr) -> c_int {
159
libc::ioctl(descriptor.as_raw_descriptor(), nr, 0)
160
}
161
162
/// Run an ioctl with a single value argument.
163
/// # Safety
164
/// The caller is responsible for determining the safety of the particular ioctl.
165
pub 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
169
/// Run an ioctl with an immutable reference.
170
/// # Safety
171
///
172
/// The caller is responsible for determining the safety of the particular ioctl.
173
pub 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
185
/// Run an ioctl with a mutable reference.
186
/// # Safety
187
///
188
/// The caller is responsible for determining the safety of the particular ioctl.
189
pub 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
201
/// Run an ioctl with a raw pointer.
202
/// # Safety
203
/// The caller is responsible for determining the safety of the particular ioctl.
204
pub 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
212
/// Run an ioctl with a mutable raw pointer.
213
/// # Safety
214
/// The caller is responsible for determining the safety of the particular ioctl.
215
pub 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)]
223
mod 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
}
247
248