summaryrefslogtreecommitdiffstats
path: root/third_party/rust/nix/test/sys/test_ioctl.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/nix/test/sys/test_ioctl.rs')
-rw-r--r--third_party/rust/nix/test/sys/test_ioctl.rs376
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));
+ }
+}