/rust/registry/src/index.crates.io-1949cf8c6b5b557f/rustix-0.38.44/src/ioctl/patterns.rs
Line | Count | Source |
1 | | //! Implements typical patterns for `ioctl` usage. |
2 | | |
3 | | use super::{Ioctl, IoctlOutput, Opcode, RawOpcode}; |
4 | | |
5 | | use crate::backend::c; |
6 | | use crate::io::Result; |
7 | | |
8 | | use core::marker::PhantomData; |
9 | | use core::ptr::addr_of_mut; |
10 | | use core::{fmt, mem}; |
11 | | |
12 | | /// Implements an `ioctl` with no real arguments. |
13 | | pub struct NoArg<Opcode> { |
14 | | /// The opcode. |
15 | | _opcode: PhantomData<Opcode>, |
16 | | } |
17 | | |
18 | | impl<Opcode: CompileTimeOpcode> fmt::Debug for NoArg<Opcode> { |
19 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
20 | 0 | f.debug_tuple("NoArg").field(&Opcode::OPCODE).finish() |
21 | 0 | } |
22 | | } |
23 | | |
24 | | impl<Opcode: CompileTimeOpcode> NoArg<Opcode> { |
25 | | /// Create a new no-argument `ioctl` object. |
26 | | /// |
27 | | /// # Safety |
28 | | /// |
29 | | /// - `Opcode` must provide a valid opcode. |
30 | | #[inline] |
31 | 0 | pub unsafe fn new() -> Self { |
32 | 0 | Self { |
33 | 0 | _opcode: PhantomData, |
34 | 0 | } |
35 | 0 | } |
36 | | } |
37 | | |
38 | | unsafe impl<Opcode: CompileTimeOpcode> Ioctl for NoArg<Opcode> { |
39 | | type Output = (); |
40 | | |
41 | | const IS_MUTATING: bool = false; |
42 | | const OPCODE: self::Opcode = Opcode::OPCODE; |
43 | | |
44 | 0 | fn as_ptr(&mut self) -> *mut c::c_void { |
45 | 0 | core::ptr::null_mut() |
46 | 0 | } |
47 | | |
48 | 0 | unsafe fn output_from_ptr(_: IoctlOutput, _: *mut c::c_void) -> Result<Self::Output> { |
49 | 0 | Ok(()) |
50 | 0 | } |
51 | | } |
52 | | |
53 | | /// Implements the traditional “getter” pattern for `ioctl`s. |
54 | | /// |
55 | | /// Some `ioctl`s just read data into the userspace. As this is a popular |
56 | | /// pattern this structure implements it. |
57 | | pub struct Getter<Opcode, Output> { |
58 | | /// The output data. |
59 | | output: mem::MaybeUninit<Output>, |
60 | | |
61 | | /// The opcode. |
62 | | _opcode: PhantomData<Opcode>, |
63 | | } |
64 | | |
65 | | impl<Opcode: CompileTimeOpcode, Output> fmt::Debug for Getter<Opcode, Output> { |
66 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
67 | 0 | f.debug_tuple("Getter").field(&Opcode::OPCODE).finish() |
68 | 0 | } |
69 | | } |
70 | | |
71 | | impl<Opcode: CompileTimeOpcode, Output> Getter<Opcode, Output> { |
72 | | /// Create a new getter-style `ioctl` object. |
73 | | /// |
74 | | /// # Safety |
75 | | /// |
76 | | /// - `Opcode` must provide a valid opcode. |
77 | | /// - For this opcode, `Output` must be the type that the kernel expects to |
78 | | /// write into. |
79 | | #[inline] |
80 | 0 | pub unsafe fn new() -> Self { |
81 | 0 | Self { |
82 | 0 | output: mem::MaybeUninit::uninit(), |
83 | 0 | _opcode: PhantomData, |
84 | 0 | } |
85 | 0 | } |
86 | | } |
87 | | |
88 | | unsafe impl<Opcode: CompileTimeOpcode, Output> Ioctl for Getter<Opcode, Output> { |
89 | | type Output = Output; |
90 | | |
91 | | const IS_MUTATING: bool = true; |
92 | | const OPCODE: self::Opcode = Opcode::OPCODE; |
93 | | |
94 | 0 | fn as_ptr(&mut self) -> *mut c::c_void { |
95 | 0 | self.output.as_mut_ptr().cast() |
96 | 0 | } |
97 | | |
98 | 0 | unsafe fn output_from_ptr(_: IoctlOutput, ptr: *mut c::c_void) -> Result<Self::Output> { |
99 | 0 | Ok(ptr.cast::<Output>().read()) |
100 | 0 | } |
101 | | } |
102 | | |
103 | | /// Implements the pattern for `ioctl`s where a pointer argument is given to |
104 | | /// the `ioctl`. |
105 | | /// |
106 | | /// The opcode must be read-only. |
107 | | pub struct Setter<Opcode, Input> { |
108 | | /// The input data. |
109 | | input: Input, |
110 | | |
111 | | /// The opcode. |
112 | | _opcode: PhantomData<Opcode>, |
113 | | } |
114 | | |
115 | | impl<Opcode: CompileTimeOpcode, Input: fmt::Debug> fmt::Debug for Setter<Opcode, Input> { |
116 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
117 | 0 | f.debug_tuple("Setter") |
118 | 0 | .field(&Opcode::OPCODE) |
119 | 0 | .field(&self.input) |
120 | 0 | .finish() |
121 | 0 | } |
122 | | } |
123 | | |
124 | | impl<Opcode: CompileTimeOpcode, Input> Setter<Opcode, Input> { |
125 | | /// Create a new pointer setter-style `ioctl` object. |
126 | | /// |
127 | | /// # Safety |
128 | | /// |
129 | | /// - `Opcode` must provide a valid opcode. |
130 | | /// - For this opcode, `Input` must be the type that the kernel expects to |
131 | | /// get. |
132 | | #[inline] |
133 | 0 | pub unsafe fn new(input: Input) -> Self { |
134 | 0 | Self { |
135 | 0 | input, |
136 | 0 | _opcode: PhantomData, |
137 | 0 | } |
138 | 0 | } |
139 | | } |
140 | | |
141 | | unsafe impl<Opcode: CompileTimeOpcode, Input> Ioctl for Setter<Opcode, Input> { |
142 | | type Output = (); |
143 | | |
144 | | const IS_MUTATING: bool = false; |
145 | | const OPCODE: self::Opcode = Opcode::OPCODE; |
146 | | |
147 | 0 | fn as_ptr(&mut self) -> *mut c::c_void { |
148 | 0 | addr_of_mut!(self.input).cast::<c::c_void>() |
149 | 0 | } |
150 | | |
151 | 0 | unsafe fn output_from_ptr(_: IoctlOutput, _: *mut c::c_void) -> Result<Self::Output> { |
152 | 0 | Ok(()) |
153 | 0 | } |
154 | | } |
155 | | |
156 | | /// Implements an “updater” pattern for `ioctl`s. |
157 | | /// |
158 | | /// The ioctl takes a reference to a struct that it reads its input from, |
159 | | /// then writes output to the same struct. |
160 | | pub struct Updater<'a, Opcode, Value> { |
161 | | /// Reference to input/output data. |
162 | | value: &'a mut Value, |
163 | | |
164 | | /// The opcode. |
165 | | _opcode: PhantomData<Opcode>, |
166 | | } |
167 | | |
168 | | impl<'a, Opcode: CompileTimeOpcode, Value> Updater<'a, Opcode, Value> { |
169 | | /// Create a new pointer updater-style `ioctl` object. |
170 | | /// |
171 | | /// # Safety |
172 | | /// |
173 | | /// - `Opcode` must provide a valid opcode. |
174 | | /// - For this opcode, `Value` must be the type that the kernel expects to |
175 | | /// get. |
176 | | #[inline] |
177 | 0 | pub unsafe fn new(value: &'a mut Value) -> Self { |
178 | 0 | Self { |
179 | 0 | value, |
180 | 0 | _opcode: PhantomData, |
181 | 0 | } |
182 | 0 | } |
183 | | } |
184 | | |
185 | | unsafe impl<'a, Opcode: CompileTimeOpcode, T> Ioctl for Updater<'a, Opcode, T> { |
186 | | type Output = (); |
187 | | |
188 | | const IS_MUTATING: bool = true; |
189 | | const OPCODE: self::Opcode = Opcode::OPCODE; |
190 | | |
191 | 0 | fn as_ptr(&mut self) -> *mut c::c_void { |
192 | 0 | (self.value as *mut T).cast() |
193 | 0 | } |
194 | | |
195 | 0 | unsafe fn output_from_ptr(_output: IoctlOutput, _ptr: *mut c::c_void) -> Result<()> { |
196 | 0 | Ok(()) |
197 | 0 | } |
198 | | } |
199 | | |
200 | | /// Implements an `ioctl` that passes an integer into the `ioctl`. |
201 | | pub struct IntegerSetter<Opcode> { |
202 | | /// The value to pass in. |
203 | | value: usize, |
204 | | |
205 | | /// The opcode. |
206 | | _opcode: PhantomData<Opcode>, |
207 | | } |
208 | | |
209 | | impl<Opcode: CompileTimeOpcode> IntegerSetter<Opcode> { |
210 | | /// Create a new integer `Ioctl` helper. |
211 | | /// |
212 | | /// # Safety |
213 | | /// |
214 | | /// - `Opcode` must provide a valid opcode. |
215 | | /// - For this opcode, it must expect an integer. |
216 | | /// - The integer is in the valid range for this opcode. |
217 | | #[inline] |
218 | 0 | pub unsafe fn new(value: usize) -> Self { |
219 | 0 | Self { |
220 | 0 | value, |
221 | 0 | _opcode: PhantomData, |
222 | 0 | } |
223 | 0 | } |
224 | | } |
225 | | |
226 | | unsafe impl<Opcode: CompileTimeOpcode> Ioctl for IntegerSetter<Opcode> { |
227 | | type Output = (); |
228 | | |
229 | | const IS_MUTATING: bool = false; |
230 | | const OPCODE: self::Opcode = Opcode::OPCODE; |
231 | | |
232 | 0 | fn as_ptr(&mut self) -> *mut c::c_void { |
233 | | // TODO: strict provenance |
234 | 0 | self.value as *mut c::c_void |
235 | 0 | } |
236 | | |
237 | 0 | unsafe fn output_from_ptr( |
238 | 0 | _out: IoctlOutput, |
239 | 0 | _extract_output: *mut c::c_void, |
240 | 0 | ) -> Result<Self::Output> { |
241 | 0 | Ok(()) |
242 | 0 | } |
243 | | } |
244 | | |
245 | | /// Trait for something that provides an `ioctl` opcode at compile time. |
246 | | pub trait CompileTimeOpcode { |
247 | | /// The opcode. |
248 | | const OPCODE: Opcode; |
249 | | } |
250 | | |
251 | | /// Provides a bad opcode at compile time. |
252 | | pub struct BadOpcode<const OPCODE: RawOpcode>; |
253 | | |
254 | | impl<const OPCODE: RawOpcode> CompileTimeOpcode for BadOpcode<OPCODE> { |
255 | | const OPCODE: Opcode = Opcode::old(OPCODE); |
256 | | } |
257 | | |
258 | | /// Provides a read code at compile time. |
259 | | /// |
260 | | /// This corresponds to the C macro `_IOR(GROUP, NUM, Data)`. |
261 | | #[cfg(any(linux_kernel, bsd))] |
262 | | pub struct ReadOpcode<const GROUP: u8, const NUM: u8, Data>(Data); |
263 | | |
264 | | #[cfg(any(linux_kernel, bsd))] |
265 | | impl<const GROUP: u8, const NUM: u8, Data> CompileTimeOpcode for ReadOpcode<GROUP, NUM, Data> { |
266 | | const OPCODE: Opcode = Opcode::read::<Data>(GROUP, NUM); |
267 | | } |
268 | | |
269 | | /// Provides a write code at compile time. |
270 | | /// |
271 | | /// This corresponds to the C macro `_IOW(GROUP, NUM, Data)`. |
272 | | #[cfg(any(linux_kernel, bsd))] |
273 | | pub struct WriteOpcode<const GROUP: u8, const NUM: u8, Data>(Data); |
274 | | |
275 | | #[cfg(any(linux_kernel, bsd))] |
276 | | impl<const GROUP: u8, const NUM: u8, Data> CompileTimeOpcode for WriteOpcode<GROUP, NUM, Data> { |
277 | | const OPCODE: Opcode = Opcode::write::<Data>(GROUP, NUM); |
278 | | } |
279 | | |
280 | | /// Provides a read/write code at compile time. |
281 | | /// |
282 | | /// This corresponds to the C macro `_IOWR(GROUP, NUM, Data)`. |
283 | | #[cfg(any(linux_kernel, bsd))] |
284 | | pub struct ReadWriteOpcode<const GROUP: u8, const NUM: u8, Data>(Data); |
285 | | |
286 | | #[cfg(any(linux_kernel, bsd))] |
287 | | impl<const GROUP: u8, const NUM: u8, Data> CompileTimeOpcode for ReadWriteOpcode<GROUP, NUM, Data> { |
288 | | const OPCODE: Opcode = Opcode::read_write::<Data>(GROUP, NUM); |
289 | | } |
290 | | |
291 | | /// Provides a `None` code at compile time. |
292 | | /// |
293 | | /// This corresponds to the C macro `_IO(GROUP, NUM)` when `Data` is zero |
294 | | /// sized. |
295 | | #[cfg(any(linux_kernel, bsd))] |
296 | | pub struct NoneOpcode<const GROUP: u8, const NUM: u8, Data>(Data); |
297 | | |
298 | | #[cfg(any(linux_kernel, bsd))] |
299 | | impl<const GROUP: u8, const NUM: u8, Data> CompileTimeOpcode for NoneOpcode<GROUP, NUM, Data> { |
300 | | const OPCODE: Opcode = Opcode::none::<Data>(GROUP, NUM); |
301 | | } |