• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #![allow(dead_code)]
2 
3 // Simple tests to ensure macro generated fns compile
4 ioctl_none_bad!(do_bad, 0x1234);
5 ioctl_read_bad!(do_bad_read, 0x1234, u16);
6 ioctl_write_int_bad!(do_bad_write_int, 0x1234);
7 ioctl_write_ptr_bad!(do_bad_write_ptr, 0x1234, u8);
8 ioctl_readwrite_bad!(do_bad_readwrite, 0x1234, u32);
9 ioctl_none!(do_none, 0, 0);
10 ioctl_read!(read_test, 0, 0, u32);
11 ioctl_write_int!(write_ptr_int, 0, 0);
12 ioctl_write_ptr!(write_ptr_u8, 0, 0, u8);
13 ioctl_write_ptr!(write_ptr_u32, 0, 0, u32);
14 ioctl_write_ptr!(write_ptr_u64, 0, 0, u64);
15 ioctl_readwrite!(readwrite_test, 0, 0, u64);
16 ioctl_read_buf!(readbuf_test, 0, 0, u32);
17 const SPI_IOC_MAGIC: u8 = b'k';
18 const SPI_IOC_MESSAGE: u8 = 0;
19 ioctl_write_buf!(writebuf_test_consts, SPI_IOC_MAGIC, SPI_IOC_MESSAGE, u8);
20 ioctl_write_buf!(writebuf_test_u8, 0, 0, u8);
21 ioctl_write_buf!(writebuf_test_u32, 0, 0, u32);
22 ioctl_write_buf!(writebuf_test_u64, 0, 0, u64);
23 ioctl_readwrite_buf!(readwritebuf_test, 0, 0, u32);
24 
25 // See C code for source of values for op calculations (does NOT work for mips/powerpc):
26 // https://gist.github.com/posborne/83ea6880770a1aef332e
27 //
28 // TODO:  Need a way to compute these constants at test time.  Using precomputed
29 // values is fragile and needs to be maintained.
30 
31 #[cfg(any(target_os = "linux", target_os = "android"))]
32 mod linux {
33     // The cast is not unnecessary on all platforms.
34     #[allow(clippy::unnecessary_cast)]
35     #[test]
test_op_none()36     fn test_op_none() {
37         if cfg!(any(
38             target_arch = "mips",
39             target_arch = "mips64",
40             target_arch = "powerpc",
41             target_arch = "powerpc64"
42         )) {
43             assert_eq!(request_code_none!(b'q', 10) as u32, 0x2000_710A);
44             assert_eq!(request_code_none!(b'a', 255) as u32, 0x2000_61FF);
45         } else {
46             assert_eq!(request_code_none!(b'q', 10) as u32, 0x0000_710A);
47             assert_eq!(request_code_none!(b'a', 255) as u32, 0x0000_61FF);
48         }
49     }
50 
51     // The cast is not unnecessary on all platforms.
52     #[allow(clippy::unnecessary_cast)]
53     #[test]
test_op_write()54     fn test_op_write() {
55         if cfg!(any(
56             target_arch = "mips",
57             target_arch = "mips64",
58             target_arch = "powerpc",
59             target_arch = "powerpc64"
60         )) {
61             assert_eq!(request_code_write!(b'z', 10, 1) as u32, 0x8001_7A0A);
62             assert_eq!(request_code_write!(b'z', 10, 512) as u32, 0x8200_7A0A);
63         } else {
64             assert_eq!(request_code_write!(b'z', 10, 1) as u32, 0x4001_7A0A);
65             assert_eq!(request_code_write!(b'z', 10, 512) as u32, 0x4200_7A0A);
66         }
67     }
68 
69     #[cfg(target_pointer_width = "64")]
70     #[test]
test_op_write_64()71     fn test_op_write_64() {
72         if cfg!(any(target_arch = "mips64", target_arch = "powerpc64")) {
73             assert_eq!(
74                 request_code_write!(b'z', 10, 1u64 << 32) as u32,
75                 0x8000_7A0A
76             );
77         } else {
78             assert_eq!(
79                 request_code_write!(b'z', 10, 1u64 << 32) as u32,
80                 0x4000_7A0A
81             );
82         }
83     }
84 
85     // The cast is not unnecessary on all platforms.
86     #[allow(clippy::unnecessary_cast)]
87     #[test]
test_op_read()88     fn test_op_read() {
89         if cfg!(any(
90             target_arch = "mips",
91             target_arch = "mips64",
92             target_arch = "powerpc",
93             target_arch = "powerpc64"
94         )) {
95             assert_eq!(request_code_read!(b'z', 10, 1) as u32, 0x4001_7A0A);
96             assert_eq!(request_code_read!(b'z', 10, 512) as u32, 0x4200_7A0A);
97         } else {
98             assert_eq!(request_code_read!(b'z', 10, 1) as u32, 0x8001_7A0A);
99             assert_eq!(request_code_read!(b'z', 10, 512) as u32, 0x8200_7A0A);
100         }
101     }
102 
103     #[cfg(target_pointer_width = "64")]
104     #[test]
test_op_read_64()105     fn test_op_read_64() {
106         if cfg!(any(target_arch = "mips64", target_arch = "powerpc64")) {
107             assert_eq!(
108                 request_code_read!(b'z', 10, 1u64 << 32) as u32,
109                 0x4000_7A0A
110             );
111         } else {
112             assert_eq!(
113                 request_code_read!(b'z', 10, 1u64 << 32) as u32,
114                 0x8000_7A0A
115             );
116         }
117     }
118 
119     // The cast is not unnecessary on all platforms.
120     #[allow(clippy::unnecessary_cast)]
121     #[test]
test_op_read_write()122     fn test_op_read_write() {
123         assert_eq!(request_code_readwrite!(b'z', 10, 1) as u32, 0xC001_7A0A);
124         assert_eq!(request_code_readwrite!(b'z', 10, 512) as u32, 0xC200_7A0A);
125     }
126 
127     #[cfg(target_pointer_width = "64")]
128     #[test]
test_op_read_write_64()129     fn test_op_read_write_64() {
130         assert_eq!(
131             request_code_readwrite!(b'z', 10, 1u64 << 32) as u32,
132             0xC000_7A0A
133         );
134     }
135 }
136 
137 #[cfg(any(
138     target_os = "dragonfly",
139     target_os = "freebsd",
140     target_os = "ios",
141     target_os = "macos",
142     target_os = "netbsd",
143     target_os = "openbsd"
144 ))]
145 mod bsd {
146     #[test]
test_op_none()147     fn test_op_none() {
148         assert_eq!(request_code_none!(b'q', 10), 0x2000_710A);
149         assert_eq!(request_code_none!(b'a', 255), 0x2000_61FF);
150     }
151 
152     #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
153     #[test]
test_op_write_int()154     fn test_op_write_int() {
155         assert_eq!(request_code_write_int!(b'v', 4), 0x2004_7604);
156         assert_eq!(request_code_write_int!(b'p', 2), 0x2004_7002);
157     }
158 
159     #[test]
test_op_write()160     fn test_op_write() {
161         assert_eq!(request_code_write!(b'z', 10, 1), 0x8001_7A0A);
162         assert_eq!(request_code_write!(b'z', 10, 512), 0x8200_7A0A);
163     }
164 
165     #[cfg(target_pointer_width = "64")]
166     #[test]
test_op_write_64()167     fn test_op_write_64() {
168         assert_eq!(request_code_write!(b'z', 10, 1u64 << 32), 0x8000_7A0A);
169     }
170 
171     #[test]
test_op_read()172     fn test_op_read() {
173         assert_eq!(request_code_read!(b'z', 10, 1), 0x4001_7A0A);
174         assert_eq!(request_code_read!(b'z', 10, 512), 0x4200_7A0A);
175     }
176 
177     #[cfg(target_pointer_width = "64")]
178     #[test]
test_op_read_64()179     fn test_op_read_64() {
180         assert_eq!(request_code_read!(b'z', 10, 1u64 << 32), 0x4000_7A0A);
181     }
182 
183     #[test]
test_op_read_write()184     fn test_op_read_write() {
185         assert_eq!(request_code_readwrite!(b'z', 10, 1), 0xC001_7A0A);
186         assert_eq!(request_code_readwrite!(b'z', 10, 512), 0xC200_7A0A);
187     }
188 
189     #[cfg(target_pointer_width = "64")]
190     #[test]
test_op_read_write_64()191     fn test_op_read_write_64() {
192         assert_eq!(request_code_readwrite!(b'z', 10, 1u64 << 32), 0xC000_7A0A);
193     }
194 }
195 
196 #[cfg(any(target_os = "android", target_os = "linux"))]
197 mod linux_ioctls {
198     use std::mem;
199     use std::os::unix::io::AsRawFd;
200 
201     use libc::{termios, TCGETS, TCSBRK, TCSETS, TIOCNXCL};
202     use tempfile::tempfile;
203 
204     use nix::errno::Errno;
205 
206     ioctl_none_bad!(tiocnxcl, TIOCNXCL);
207     #[test]
test_ioctl_none_bad()208     fn test_ioctl_none_bad() {
209         let file = tempfile().unwrap();
210         let res = unsafe { tiocnxcl(file.as_raw_fd()) };
211         assert_eq!(res, Err(Errno::ENOTTY));
212     }
213 
214     ioctl_read_bad!(tcgets, TCGETS, termios);
215     #[test]
test_ioctl_read_bad()216     fn test_ioctl_read_bad() {
217         let file = tempfile().unwrap();
218         let mut termios = unsafe { mem::zeroed() };
219         let res = unsafe { tcgets(file.as_raw_fd(), &mut termios) };
220         assert_eq!(res, Err(Errno::ENOTTY));
221     }
222 
223     ioctl_write_int_bad!(tcsbrk, TCSBRK);
224     #[test]
test_ioctl_write_int_bad()225     fn test_ioctl_write_int_bad() {
226         let file = tempfile().unwrap();
227         let res = unsafe { tcsbrk(file.as_raw_fd(), 0) };
228         assert_eq!(res, Err(Errno::ENOTTY));
229     }
230 
231     ioctl_write_ptr_bad!(tcsets, TCSETS, termios);
232     #[test]
test_ioctl_write_ptr_bad()233     fn test_ioctl_write_ptr_bad() {
234         let file = tempfile().unwrap();
235         let termios: termios = unsafe { mem::zeroed() };
236         let res = unsafe { tcsets(file.as_raw_fd(), &termios) };
237         assert_eq!(res, Err(Errno::ENOTTY));
238     }
239 
240     // FIXME: Find a suitable example for `ioctl_readwrite_bad`
241 
242     // From linux/videodev2.h
243     ioctl_none!(log_status, b'V', 70);
244     #[test]
test_ioctl_none()245     fn test_ioctl_none() {
246         let file = tempfile().unwrap();
247         let res = unsafe { log_status(file.as_raw_fd()) };
248         assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS));
249     }
250 
251     #[repr(C)]
252     pub struct v4l2_audio {
253         index: u32,
254         name: [u8; 32],
255         capability: u32,
256         mode: u32,
257         reserved: [u32; 2],
258     }
259 
260     // From linux/videodev2.h
261     ioctl_write_ptr!(s_audio, b'V', 34, v4l2_audio);
262     #[test]
test_ioctl_write_ptr()263     fn test_ioctl_write_ptr() {
264         let file = tempfile().unwrap();
265         let data: v4l2_audio = unsafe { mem::zeroed() };
266         let res = unsafe { s_audio(file.as_raw_fd(), &data) };
267         assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS));
268     }
269 
270     // From linux/net/bluetooth/hci_sock.h
271     const HCI_IOC_MAGIC: u8 = b'H';
272     const HCI_IOC_HCIDEVUP: u8 = 201;
273     ioctl_write_int!(hcidevup, HCI_IOC_MAGIC, HCI_IOC_HCIDEVUP);
274     #[test]
test_ioctl_write_int()275     fn test_ioctl_write_int() {
276         let file = tempfile().unwrap();
277         let res = unsafe { hcidevup(file.as_raw_fd(), 0) };
278         assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS));
279     }
280 
281     // From linux/videodev2.h
282     ioctl_read!(g_audio, b'V', 33, v4l2_audio);
283     #[test]
test_ioctl_read()284     fn test_ioctl_read() {
285         let file = tempfile().unwrap();
286         let mut data: v4l2_audio = unsafe { mem::zeroed() };
287         let res = unsafe { g_audio(file.as_raw_fd(), &mut data) };
288         assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS));
289     }
290 
291     // From linux/videodev2.h
292     ioctl_readwrite!(enum_audio, b'V', 65, v4l2_audio);
293     #[test]
test_ioctl_readwrite()294     fn test_ioctl_readwrite() {
295         let file = tempfile().unwrap();
296         let mut data: v4l2_audio = unsafe { mem::zeroed() };
297         let res = unsafe { enum_audio(file.as_raw_fd(), &mut data) };
298         assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS));
299     }
300 
301     // FIXME: Find a suitable example for `ioctl_read_buf`.
302 
303     #[repr(C)]
304     pub struct spi_ioc_transfer {
305         tx_buf: u64,
306         rx_buf: u64,
307         len: u32,
308         speed_hz: u32,
309         delay_usecs: u16,
310         bits_per_word: u8,
311         cs_change: u8,
312         tx_nbits: u8,
313         rx_nbits: u8,
314         pad: u16,
315     }
316 
317     // From linux/spi/spidev.h
318     ioctl_write_buf!(
319         spi_ioc_message,
320         super::SPI_IOC_MAGIC,
321         super::SPI_IOC_MESSAGE,
322         spi_ioc_transfer
323     );
324     #[test]
test_ioctl_write_buf()325     fn test_ioctl_write_buf() {
326         let file = tempfile().unwrap();
327         let data: [spi_ioc_transfer; 4] = unsafe { mem::zeroed() };
328         let res = unsafe { spi_ioc_message(file.as_raw_fd(), &data[..]) };
329         assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS));
330     }
331 
332     // FIXME: Find a suitable example for `ioctl_readwrite_buf`.
333 }
334 
335 #[cfg(target_os = "freebsd")]
336 mod freebsd_ioctls {
337     use std::mem;
338     use std::os::unix::io::AsRawFd;
339 
340     use libc::termios;
341     use tempfile::tempfile;
342 
343     use nix::errno::Errno;
344 
345     // From sys/sys/ttycom.h
346     const TTY_IOC_MAGIC: u8 = b't';
347     const TTY_IOC_TYPE_NXCL: u8 = 14;
348     const TTY_IOC_TYPE_GETA: u8 = 19;
349     const TTY_IOC_TYPE_SETA: u8 = 20;
350 
351     ioctl_none!(tiocnxcl, TTY_IOC_MAGIC, TTY_IOC_TYPE_NXCL);
352     #[test]
test_ioctl_none()353     fn test_ioctl_none() {
354         let file = tempfile().unwrap();
355         let res = unsafe { tiocnxcl(file.as_raw_fd()) };
356         assert_eq!(res, Err(Errno::ENOTTY));
357     }
358 
359     ioctl_read!(tiocgeta, TTY_IOC_MAGIC, TTY_IOC_TYPE_GETA, termios);
360     #[test]
test_ioctl_read()361     fn test_ioctl_read() {
362         let file = tempfile().unwrap();
363         let mut termios = unsafe { mem::zeroed() };
364         let res = unsafe { tiocgeta(file.as_raw_fd(), &mut termios) };
365         assert_eq!(res, Err(Errno::ENOTTY));
366     }
367 
368     ioctl_write_ptr!(tiocseta, TTY_IOC_MAGIC, TTY_IOC_TYPE_SETA, termios);
369     #[test]
test_ioctl_write_ptr()370     fn test_ioctl_write_ptr() {
371         let file = tempfile().unwrap();
372         let termios: termios = unsafe { mem::zeroed() };
373         let res = unsafe { tiocseta(file.as_raw_fd(), &termios) };
374         assert_eq!(res, Err(Errno::ENOTTY));
375     }
376 }
377