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