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     #[test]
test_op_none()34     fn test_op_none() {
35         if cfg!(any(target_arch = "mips", target_arch = "mips64", target_arch="powerpc", target_arch="powerpc64")){
36             assert_eq!(request_code_none!(b'q', 10) as u32, 0x2000_710A);
37             assert_eq!(request_code_none!(b'a', 255) as u32, 0x2000_61FF);
38         } else {
39             assert_eq!(request_code_none!(b'q', 10) as u32, 0x0000_710A);
40             assert_eq!(request_code_none!(b'a', 255) as u32, 0x0000_61FF);
41         }
42     }
43 
44     #[test]
test_op_write()45     fn test_op_write() {
46         if cfg!(any(target_arch = "mips", target_arch = "mips64", target_arch="powerpc", target_arch="powerpc64")){
47             assert_eq!(request_code_write!(b'z', 10, 1) as u32, 0x8001_7A0A);
48             assert_eq!(request_code_write!(b'z', 10, 512) as u32, 0x8200_7A0A);
49         } else {
50             assert_eq!(request_code_write!(b'z', 10, 1) as u32, 0x4001_7A0A);
51             assert_eq!(request_code_write!(b'z', 10, 512) as u32, 0x4200_7A0A);
52         }
53     }
54 
55     #[cfg(target_pointer_width = "64")]
56     #[test]
test_op_write_64()57     fn test_op_write_64() {
58         if cfg!(any(target_arch = "mips64", target_arch="powerpc64")){
59             assert_eq!(request_code_write!(b'z', 10, (1 as u64) << 32) as u32,
60                        0x8000_7A0A);
61         } else {
62             assert_eq!(request_code_write!(b'z', 10, (1 as u64) << 32) as u32,
63                        0x4000_7A0A);
64         }
65 
66     }
67 
68     #[test]
test_op_read()69     fn test_op_read() {
70         if cfg!(any(target_arch = "mips", target_arch = "mips64", target_arch="powerpc", target_arch="powerpc64")){
71             assert_eq!(request_code_read!(b'z', 10, 1) as u32, 0x4001_7A0A);
72             assert_eq!(request_code_read!(b'z', 10, 512) as u32, 0x4200_7A0A);
73         } else {
74             assert_eq!(request_code_read!(b'z', 10, 1) as u32, 0x8001_7A0A);
75             assert_eq!(request_code_read!(b'z', 10, 512) as u32, 0x8200_7A0A);
76         }
77     }
78 
79     #[cfg(target_pointer_width = "64")]
80     #[test]
test_op_read_64()81     fn test_op_read_64() {
82         if cfg!(any(target_arch = "mips64", target_arch="powerpc64")){
83             assert_eq!(request_code_read!(b'z', 10, (1 as u64) << 32) as u32,
84                        0x4000_7A0A);
85         } else {
86             assert_eq!(request_code_read!(b'z', 10, (1 as u64) << 32) as u32,
87                        0x8000_7A0A);
88         }
89     }
90 
91     #[test]
test_op_read_write()92     fn test_op_read_write() {
93         assert_eq!(request_code_readwrite!(b'z', 10, 1) as u32, 0xC001_7A0A);
94         assert_eq!(request_code_readwrite!(b'z', 10, 512) as u32, 0xC200_7A0A);
95     }
96 
97     #[cfg(target_pointer_width = "64")]
98     #[test]
test_op_read_write_64()99     fn test_op_read_write_64() {
100         assert_eq!(request_code_readwrite!(b'z', 10, (1 as u64) << 32) as u32,
101                    0xC000_7A0A);
102     }
103 }
104 
105 #[cfg(any(target_os = "dragonfly",
106           target_os = "freebsd",
107           target_os = "ios",
108           target_os = "macos",
109           target_os = "netbsd",
110           target_os = "openbsd"))]
111 mod bsd {
112     #[test]
test_op_none()113     fn test_op_none() {
114         assert_eq!(request_code_none!(b'q', 10), 0x2000_710A);
115         assert_eq!(request_code_none!(b'a', 255), 0x2000_61FF);
116     }
117 
118     #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
119     #[test]
test_op_write_int()120     fn test_op_write_int() {
121         assert_eq!(request_code_write_int!(b'v', 4), 0x2004_7604);
122         assert_eq!(request_code_write_int!(b'p', 2), 0x2004_7002);
123     }
124 
125     #[test]
test_op_write()126     fn test_op_write() {
127         assert_eq!(request_code_write!(b'z', 10, 1), 0x8001_7A0A);
128         assert_eq!(request_code_write!(b'z', 10, 512), 0x8200_7A0A);
129     }
130 
131     #[cfg(target_pointer_width = "64")]
132     #[test]
test_op_write_64()133     fn test_op_write_64() {
134         assert_eq!(request_code_write!(b'z', 10, (1 as u64) << 32), 0x8000_7A0A);
135     }
136 
137     #[test]
test_op_read()138     fn test_op_read() {
139         assert_eq!(request_code_read!(b'z', 10, 1), 0x4001_7A0A);
140         assert_eq!(request_code_read!(b'z', 10, 512), 0x4200_7A0A);
141     }
142 
143     #[cfg(target_pointer_width = "64")]
144     #[test]
test_op_read_64()145     fn test_op_read_64() {
146         assert_eq!(request_code_read!(b'z', 10, (1 as u64) << 32), 0x4000_7A0A);
147     }
148 
149     #[test]
test_op_read_write()150     fn test_op_read_write() {
151         assert_eq!(request_code_readwrite!(b'z', 10, 1), 0xC001_7A0A);
152         assert_eq!(request_code_readwrite!(b'z', 10, 512), 0xC200_7A0A);
153     }
154 
155     #[cfg(target_pointer_width = "64")]
156     #[test]
test_op_read_write_64()157     fn test_op_read_write_64() {
158         assert_eq!(request_code_readwrite!(b'z', 10, (1 as u64) << 32), 0xC000_7A0A);
159     }
160 }
161 
162 #[cfg(any(target_os = "android", target_os = "linux"))]
163 mod linux_ioctls {
164     use std::mem;
165     use std::os::unix::io::AsRawFd;
166 
167     use tempfile::tempfile;
168     use libc::{TCGETS, TCSBRK, TCSETS, TIOCNXCL, termios};
169 
170     use nix::Error::Sys;
171     use nix::errno::Errno::{ENOTTY, ENOSYS};
172 
173     ioctl_none_bad!(tiocnxcl, TIOCNXCL);
174     #[test]
test_ioctl_none_bad()175     fn test_ioctl_none_bad() {
176         let file = tempfile().unwrap();
177         let res = unsafe { tiocnxcl(file.as_raw_fd()) };
178         assert_eq!(res, Err(Sys(ENOTTY)));
179     }
180 
181     ioctl_read_bad!(tcgets, TCGETS, termios);
182     #[test]
test_ioctl_read_bad()183     fn test_ioctl_read_bad() {
184         let file = tempfile().unwrap();
185         let mut termios = unsafe { mem::zeroed() };
186         let res = unsafe { tcgets(file.as_raw_fd(), &mut termios) };
187         assert_eq!(res, Err(Sys(ENOTTY)));
188     }
189 
190     ioctl_write_int_bad!(tcsbrk, TCSBRK);
191     #[test]
test_ioctl_write_int_bad()192     fn test_ioctl_write_int_bad() {
193         let file = tempfile().unwrap();
194         let res = unsafe { tcsbrk(file.as_raw_fd(), 0) };
195         assert_eq!(res, Err(Sys(ENOTTY)));
196     }
197 
198     ioctl_write_ptr_bad!(tcsets, TCSETS, termios);
199     #[test]
test_ioctl_write_ptr_bad()200     fn test_ioctl_write_ptr_bad() {
201         let file = tempfile().unwrap();
202         let termios: termios = unsafe { mem::zeroed() };
203         let res = unsafe { tcsets(file.as_raw_fd(), &termios) };
204         assert_eq!(res, Err(Sys(ENOTTY)));
205     }
206 
207     // FIXME: Find a suitable example for `ioctl_readwrite_bad`
208 
209     // From linux/videodev2.h
210     ioctl_none!(log_status, b'V', 70);
211     #[test]
test_ioctl_none()212     fn test_ioctl_none() {
213         let file = tempfile().unwrap();
214         let res = unsafe { log_status(file.as_raw_fd()) };
215         assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
216     }
217 
218     #[repr(C)]
219     pub struct v4l2_audio {
220         index: u32,
221         name: [u8; 32],
222         capability: u32,
223         mode: u32,
224         reserved: [u32; 2],
225     }
226 
227     // From linux/videodev2.h
228     ioctl_write_ptr!(s_audio, b'V', 34, v4l2_audio);
229     #[test]
test_ioctl_write_ptr()230     fn test_ioctl_write_ptr() {
231         let file = tempfile().unwrap();
232         let data: v4l2_audio = unsafe { mem::zeroed() };
233         let res = unsafe { s_audio(file.as_raw_fd(), &data) };
234         assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
235     }
236 
237     // From linux/net/bluetooth/hci_sock.h
238     const HCI_IOC_MAGIC: u8 = b'H';
239     const HCI_IOC_HCIDEVUP: u8 = 201;
240     ioctl_write_int!(hcidevup, HCI_IOC_MAGIC, HCI_IOC_HCIDEVUP);
241     #[test]
test_ioctl_write_int()242     fn test_ioctl_write_int() {
243         let file = tempfile().unwrap();
244         let res = unsafe { hcidevup(file.as_raw_fd(), 0) };
245         assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
246     }
247 
248     // From linux/videodev2.h
249     ioctl_read!(g_audio, b'V', 33, v4l2_audio);
250     #[test]
test_ioctl_read()251     fn test_ioctl_read() {
252         let file = tempfile().unwrap();
253         let mut data: v4l2_audio = unsafe { mem::zeroed() };
254         let res = unsafe { g_audio(file.as_raw_fd(), &mut data) };
255         assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
256     }
257 
258     // From linux/videodev2.h
259     ioctl_readwrite!(enum_audio,  b'V', 65, v4l2_audio);
260     #[test]
test_ioctl_readwrite()261     fn test_ioctl_readwrite() {
262         let file = tempfile().unwrap();
263         let mut data: v4l2_audio = unsafe { mem::zeroed() };
264         let res = unsafe { enum_audio(file.as_raw_fd(), &mut data) };
265         assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
266     }
267 
268     // FIXME: Find a suitable example for `ioctl_read_buf`.
269 
270     #[repr(C)]
271     pub struct spi_ioc_transfer {
272         tx_buf: u64,
273         rx_buf: u64,
274         len: u32,
275         speed_hz: u32,
276         delay_usecs: u16,
277         bits_per_word: u8,
278         cs_change: u8,
279         tx_nbits: u8,
280         rx_nbits: u8,
281         pad: u16,
282     }
283 
284     // From linux/spi/spidev.h
285     ioctl_write_buf!(spi_ioc_message, super::SPI_IOC_MAGIC, super::SPI_IOC_MESSAGE, spi_ioc_transfer);
286     #[test]
test_ioctl_write_buf()287     fn test_ioctl_write_buf() {
288         let file = tempfile().unwrap();
289         let data: [spi_ioc_transfer; 4] = unsafe { mem::zeroed() };
290         let res = unsafe { spi_ioc_message(file.as_raw_fd(), &data[..]) };
291         assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
292     }
293 
294     // FIXME: Find a suitable example for `ioctl_readwrite_buf`.
295 }
296 
297 #[cfg(target_os = "freebsd")]
298 mod freebsd_ioctls {
299     use std::mem;
300     use std::os::unix::io::AsRawFd;
301 
302     use tempfile::tempfile;
303     use libc::termios;
304 
305     use nix::Error::Sys;
306     use nix::errno::Errno::ENOTTY;
307 
308     // From sys/sys/ttycom.h
309     const TTY_IOC_MAGIC: u8 = b't';
310     const TTY_IOC_TYPE_NXCL: u8 = 14;
311     const TTY_IOC_TYPE_GETA: u8 = 19;
312     const TTY_IOC_TYPE_SETA: u8 = 20;
313 
314     ioctl_none!(tiocnxcl, TTY_IOC_MAGIC, TTY_IOC_TYPE_NXCL);
315     #[test]
test_ioctl_none()316     fn test_ioctl_none() {
317         let file = tempfile().unwrap();
318         let res = unsafe { tiocnxcl(file.as_raw_fd()) };
319         assert_eq!(res, Err(Sys(ENOTTY)));
320     }
321 
322     ioctl_read!(tiocgeta, TTY_IOC_MAGIC, TTY_IOC_TYPE_GETA, termios);
323     #[test]
test_ioctl_read()324     fn test_ioctl_read() {
325         let file = tempfile().unwrap();
326         let mut termios = unsafe { mem::zeroed() };
327         let res = unsafe { tiocgeta(file.as_raw_fd(), &mut termios) };
328         assert_eq!(res, Err(Sys(ENOTTY)));
329     }
330 
331     ioctl_write_ptr!(tiocseta, TTY_IOC_MAGIC, TTY_IOC_TYPE_SETA, termios);
332     #[test]
test_ioctl_write_ptr()333     fn test_ioctl_write_ptr() {
334         let file = tempfile().unwrap();
335         let termios: termios = unsafe { mem::zeroed() };
336         let res = unsafe { tiocseta(file.as_raw_fd(), &termios) };
337         assert_eq!(res, Err(Sys(ENOTTY)));
338     }
339 }
340