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