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