diff options
Diffstat (limited to 'third_party/rust/nix/test/sys/test_ioctl.rs')
-rw-r--r-- | third_party/rust/nix/test/sys/test_ioctl.rs | 376 |
1 files changed, 376 insertions, 0 deletions
diff --git a/third_party/rust/nix/test/sys/test_ioctl.rs b/third_party/rust/nix/test/sys/test_ioctl.rs new file mode 100644 index 0000000000..40f60cfdbc --- /dev/null +++ b/third_party/rust/nix/test/sys/test_ioctl.rs @@ -0,0 +1,376 @@ +#![allow(dead_code)] + +// Simple tests to ensure macro generated fns compile +ioctl_none_bad!(do_bad, 0x1234); +ioctl_read_bad!(do_bad_read, 0x1234, u16); +ioctl_write_int_bad!(do_bad_write_int, 0x1234); +ioctl_write_ptr_bad!(do_bad_write_ptr, 0x1234, u8); +ioctl_readwrite_bad!(do_bad_readwrite, 0x1234, u32); +ioctl_none!(do_none, 0, 0); +ioctl_read!(read_test, 0, 0, u32); +ioctl_write_int!(write_ptr_int, 0, 0); +ioctl_write_ptr!(write_ptr_u8, 0, 0, u8); +ioctl_write_ptr!(write_ptr_u32, 0, 0, u32); +ioctl_write_ptr!(write_ptr_u64, 0, 0, u64); +ioctl_readwrite!(readwrite_test, 0, 0, u64); +ioctl_read_buf!(readbuf_test, 0, 0, u32); +const SPI_IOC_MAGIC: u8 = b'k'; +const SPI_IOC_MESSAGE: u8 = 0; +ioctl_write_buf!(writebuf_test_consts, SPI_IOC_MAGIC, SPI_IOC_MESSAGE, u8); +ioctl_write_buf!(writebuf_test_u8, 0, 0, u8); +ioctl_write_buf!(writebuf_test_u32, 0, 0, u32); +ioctl_write_buf!(writebuf_test_u64, 0, 0, u64); +ioctl_readwrite_buf!(readwritebuf_test, 0, 0, u32); + +// See C code for source of values for op calculations (does NOT work for mips/powerpc): +// https://gist.github.com/posborne/83ea6880770a1aef332e +// +// TODO: Need a way to compute these constants at test time. Using precomputed +// values is fragile and needs to be maintained. + +#[cfg(any(target_os = "linux", target_os = "android"))] +mod linux { + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] + #[test] + fn test_op_none() { + if cfg!(any( + target_arch = "mips", + target_arch = "mips64", + target_arch = "powerpc", + target_arch = "powerpc64" + )) { + assert_eq!(request_code_none!(b'q', 10) as u32, 0x2000_710A); + assert_eq!(request_code_none!(b'a', 255) as u32, 0x2000_61FF); + } else { + assert_eq!(request_code_none!(b'q', 10) as u32, 0x0000_710A); + assert_eq!(request_code_none!(b'a', 255) as u32, 0x0000_61FF); + } + } + + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] + #[test] + fn test_op_write() { + if cfg!(any( + target_arch = "mips", + target_arch = "mips64", + target_arch = "powerpc", + target_arch = "powerpc64" + )) { + assert_eq!(request_code_write!(b'z', 10, 1) as u32, 0x8001_7A0A); + assert_eq!(request_code_write!(b'z', 10, 512) as u32, 0x8200_7A0A); + } else { + assert_eq!(request_code_write!(b'z', 10, 1) as u32, 0x4001_7A0A); + assert_eq!(request_code_write!(b'z', 10, 512) as u32, 0x4200_7A0A); + } + } + + #[cfg(target_pointer_width = "64")] + #[test] + fn test_op_write_64() { + if cfg!(any(target_arch = "mips64", target_arch = "powerpc64")) { + assert_eq!( + request_code_write!(b'z', 10, 1u64 << 32) as u32, + 0x8000_7A0A + ); + } else { + assert_eq!( + request_code_write!(b'z', 10, 1u64 << 32) as u32, + 0x4000_7A0A + ); + } + } + + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] + #[test] + fn test_op_read() { + if cfg!(any( + target_arch = "mips", + target_arch = "mips64", + target_arch = "powerpc", + target_arch = "powerpc64" + )) { + assert_eq!(request_code_read!(b'z', 10, 1) as u32, 0x4001_7A0A); + assert_eq!(request_code_read!(b'z', 10, 512) as u32, 0x4200_7A0A); + } else { + assert_eq!(request_code_read!(b'z', 10, 1) as u32, 0x8001_7A0A); + assert_eq!(request_code_read!(b'z', 10, 512) as u32, 0x8200_7A0A); + } + } + + #[cfg(target_pointer_width = "64")] + #[test] + fn test_op_read_64() { + if cfg!(any(target_arch = "mips64", target_arch = "powerpc64")) { + assert_eq!( + request_code_read!(b'z', 10, 1u64 << 32) as u32, + 0x4000_7A0A + ); + } else { + assert_eq!( + request_code_read!(b'z', 10, 1u64 << 32) as u32, + 0x8000_7A0A + ); + } + } + + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] + #[test] + fn test_op_read_write() { + assert_eq!(request_code_readwrite!(b'z', 10, 1) as u32, 0xC001_7A0A); + assert_eq!(request_code_readwrite!(b'z', 10, 512) as u32, 0xC200_7A0A); + } + + #[cfg(target_pointer_width = "64")] + #[test] + fn test_op_read_write_64() { + assert_eq!( + request_code_readwrite!(b'z', 10, 1u64 << 32) as u32, + 0xC000_7A0A + ); + } +} + +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" +))] +mod bsd { + #[test] + fn test_op_none() { + assert_eq!(request_code_none!(b'q', 10), 0x2000_710A); + assert_eq!(request_code_none!(b'a', 255), 0x2000_61FF); + } + + #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[test] + fn test_op_write_int() { + assert_eq!(request_code_write_int!(b'v', 4), 0x2004_7604); + assert_eq!(request_code_write_int!(b'p', 2), 0x2004_7002); + } + + #[test] + fn test_op_write() { + assert_eq!(request_code_write!(b'z', 10, 1), 0x8001_7A0A); + assert_eq!(request_code_write!(b'z', 10, 512), 0x8200_7A0A); + } + + #[cfg(target_pointer_width = "64")] + #[test] + fn test_op_write_64() { + assert_eq!(request_code_write!(b'z', 10, 1u64 << 32), 0x8000_7A0A); + } + + #[test] + fn test_op_read() { + assert_eq!(request_code_read!(b'z', 10, 1), 0x4001_7A0A); + assert_eq!(request_code_read!(b'z', 10, 512), 0x4200_7A0A); + } + + #[cfg(target_pointer_width = "64")] + #[test] + fn test_op_read_64() { + assert_eq!(request_code_read!(b'z', 10, 1u64 << 32), 0x4000_7A0A); + } + + #[test] + fn test_op_read_write() { + assert_eq!(request_code_readwrite!(b'z', 10, 1), 0xC001_7A0A); + assert_eq!(request_code_readwrite!(b'z', 10, 512), 0xC200_7A0A); + } + + #[cfg(target_pointer_width = "64")] + #[test] + fn test_op_read_write_64() { + assert_eq!(request_code_readwrite!(b'z', 10, 1u64 << 32), 0xC000_7A0A); + } +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +mod linux_ioctls { + use std::mem; + use std::os::unix::io::AsRawFd; + + use libc::{termios, TCGETS, TCSBRK, TCSETS, TIOCNXCL}; + use tempfile::tempfile; + + use nix::errno::Errno; + + ioctl_none_bad!(tiocnxcl, TIOCNXCL); + #[test] + fn test_ioctl_none_bad() { + let file = tempfile().unwrap(); + let res = unsafe { tiocnxcl(file.as_raw_fd()) }; + assert_eq!(res, Err(Errno::ENOTTY)); + } + + ioctl_read_bad!(tcgets, TCGETS, termios); + #[test] + fn test_ioctl_read_bad() { + let file = tempfile().unwrap(); + let mut termios = unsafe { mem::zeroed() }; + let res = unsafe { tcgets(file.as_raw_fd(), &mut termios) }; + assert_eq!(res, Err(Errno::ENOTTY)); + } + + ioctl_write_int_bad!(tcsbrk, TCSBRK); + #[test] + fn test_ioctl_write_int_bad() { + let file = tempfile().unwrap(); + let res = unsafe { tcsbrk(file.as_raw_fd(), 0) }; + assert_eq!(res, Err(Errno::ENOTTY)); + } + + ioctl_write_ptr_bad!(tcsets, TCSETS, termios); + #[test] + fn test_ioctl_write_ptr_bad() { + let file = tempfile().unwrap(); + let termios: termios = unsafe { mem::zeroed() }; + let res = unsafe { tcsets(file.as_raw_fd(), &termios) }; + assert_eq!(res, Err(Errno::ENOTTY)); + } + + // FIXME: Find a suitable example for `ioctl_readwrite_bad` + + // From linux/videodev2.h + ioctl_none!(log_status, b'V', 70); + #[test] + fn test_ioctl_none() { + let file = tempfile().unwrap(); + let res = unsafe { log_status(file.as_raw_fd()) }; + assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS)); + } + + #[repr(C)] + pub struct v4l2_audio { + index: u32, + name: [u8; 32], + capability: u32, + mode: u32, + reserved: [u32; 2], + } + + // From linux/videodev2.h + ioctl_write_ptr!(s_audio, b'V', 34, v4l2_audio); + #[test] + fn test_ioctl_write_ptr() { + let file = tempfile().unwrap(); + let data: v4l2_audio = unsafe { mem::zeroed() }; + let res = unsafe { s_audio(file.as_raw_fd(), &data) }; + assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS)); + } + + // From linux/net/bluetooth/hci_sock.h + const HCI_IOC_MAGIC: u8 = b'H'; + const HCI_IOC_HCIDEVUP: u8 = 201; + ioctl_write_int!(hcidevup, HCI_IOC_MAGIC, HCI_IOC_HCIDEVUP); + #[test] + fn test_ioctl_write_int() { + let file = tempfile().unwrap(); + let res = unsafe { hcidevup(file.as_raw_fd(), 0) }; + assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS)); + } + + // From linux/videodev2.h + ioctl_read!(g_audio, b'V', 33, v4l2_audio); + #[test] + fn test_ioctl_read() { + let file = tempfile().unwrap(); + let mut data: v4l2_audio = unsafe { mem::zeroed() }; + let res = unsafe { g_audio(file.as_raw_fd(), &mut data) }; + assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS)); + } + + // From linux/videodev2.h + ioctl_readwrite!(enum_audio, b'V', 65, v4l2_audio); + #[test] + fn test_ioctl_readwrite() { + let file = tempfile().unwrap(); + let mut data: v4l2_audio = unsafe { mem::zeroed() }; + let res = unsafe { enum_audio(file.as_raw_fd(), &mut data) }; + assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS)); + } + + // FIXME: Find a suitable example for `ioctl_read_buf`. + + #[repr(C)] + pub struct spi_ioc_transfer { + tx_buf: u64, + rx_buf: u64, + len: u32, + speed_hz: u32, + delay_usecs: u16, + bits_per_word: u8, + cs_change: u8, + tx_nbits: u8, + rx_nbits: u8, + pad: u16, + } + + // From linux/spi/spidev.h + ioctl_write_buf!( + spi_ioc_message, + super::SPI_IOC_MAGIC, + super::SPI_IOC_MESSAGE, + spi_ioc_transfer + ); + #[test] + fn test_ioctl_write_buf() { + let file = tempfile().unwrap(); + let data: [spi_ioc_transfer; 4] = unsafe { mem::zeroed() }; + let res = unsafe { spi_ioc_message(file.as_raw_fd(), &data[..]) }; + assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS)); + } + + // FIXME: Find a suitable example for `ioctl_readwrite_buf`. +} + +#[cfg(target_os = "freebsd")] +mod freebsd_ioctls { + use std::mem; + use std::os::unix::io::AsRawFd; + + use libc::termios; + use tempfile::tempfile; + + use nix::errno::Errno; + + // From sys/sys/ttycom.h + const TTY_IOC_MAGIC: u8 = b't'; + const TTY_IOC_TYPE_NXCL: u8 = 14; + const TTY_IOC_TYPE_GETA: u8 = 19; + const TTY_IOC_TYPE_SETA: u8 = 20; + + ioctl_none!(tiocnxcl, TTY_IOC_MAGIC, TTY_IOC_TYPE_NXCL); + #[test] + fn test_ioctl_none() { + let file = tempfile().unwrap(); + let res = unsafe { tiocnxcl(file.as_raw_fd()) }; + assert_eq!(res, Err(Errno::ENOTTY)); + } + + ioctl_read!(tiocgeta, TTY_IOC_MAGIC, TTY_IOC_TYPE_GETA, termios); + #[test] + fn test_ioctl_read() { + let file = tempfile().unwrap(); + let mut termios = unsafe { mem::zeroed() }; + let res = unsafe { tiocgeta(file.as_raw_fd(), &mut termios) }; + assert_eq!(res, Err(Errno::ENOTTY)); + } + + ioctl_write_ptr!(tiocseta, TTY_IOC_MAGIC, TTY_IOC_TYPE_SETA, termios); + #[test] + fn test_ioctl_write_ptr() { + let file = tempfile().unwrap(); + let termios: termios = unsafe { mem::zeroed() }; + let res = unsafe { tiocseta(file.as_raw_fd(), &termios) }; + assert_eq!(res, Err(Errno::ENOTTY)); + } +} |