summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBryant Mairs <bryantmairs@google.com>2018-01-07 18:30:34 -0800
committerBryant Mairs <bryantmairs@google.com>2018-04-10 08:28:39 -0700
commitdb7574f676c2c0f90a48dde0c34a73e9549d955f (patch)
treeac10b3b6704a736115093fcb2e5fa444b497dcb1
parent31e901b4bf36be5a4b27f28ae43105913c5d6245 (diff)
downloadnix-db7574f676c2c0f90a48dde0c34a73e9549d955f.zip
Refactor the ioctl API and documentation
* Split `ioctl!` into separate macros. This makes documentation easier to read. * For every `ioctl_*!` macro include a description of the macro arguments as, the function prototype for the generated wrapper function, and an example if we have one. * Expose `request_code_*!` in the documentation to make the `ioctl_*_bad` macros easier to use. * Reorganize the file hierarchy to be simpler
-rw-r--r--src/sys/ioctl/bsd.rs88
-rw-r--r--src/sys/ioctl/linux.rs (renamed from src/sys/ioctl/platform/linux.rs)68
-rw-r--r--src/sys/ioctl/mod.rs567
-rw-r--r--src/sys/ioctl/platform/bsd.rs51
-rw-r--r--src/sys/mod.rs8
-rw-r--r--src/sys/socket/addr.rs2
-rw-r--r--test/sys/test_ioctl.rs198
7 files changed, 682 insertions, 300 deletions
diff --git a/src/sys/ioctl/bsd.rs b/src/sys/ioctl/bsd.rs
new file mode 100644
index 00000000..922d32e8
--- /dev/null
+++ b/src/sys/ioctl/bsd.rs
@@ -0,0 +1,88 @@
+/// The datatype used for the ioctl number
+#[doc(hidden)]
+pub type ioctl_num_type = ::libc::c_ulong;
+
+mod consts {
+ use ::sys::ioctl::ioctl_num_type;
+ #[doc(hidden)]
+ pub const VOID: ioctl_num_type = 0x2000_0000;
+ #[doc(hidden)]
+ pub const OUT: ioctl_num_type = 0x4000_0000;
+ #[doc(hidden)]
+ pub const IN: ioctl_num_type = 0x8000_0000;
+ #[doc(hidden)]
+ pub const INOUT: ioctl_num_type = (IN|OUT);
+ #[doc(hidden)]
+ pub const IOCPARM_MASK: ioctl_num_type = 0x1fff;
+}
+
+pub use self::consts::*;
+
+#[macro_export]
+#[doc(hidden)]
+macro_rules! ioc {
+ ($inout:expr, $group:expr, $num:expr, $len:expr) => (
+ $inout | (($len as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::IOCPARM_MASK) << 16) | (($group as $crate::sys::ioctl::ioctl_num_type) << 8) | ($num as $crate::sys::ioctl::ioctl_num_type)
+ )
+}
+
+/// Generate an ioctl request code for a command that passes no data.
+///
+/// This is equivalent to the `_IO()` macro exposed by the C ioctl API.
+///
+/// You should only use this macro directly if the `ioctl` you're working
+/// with is "bad" and you cannot use `ioctl_none!()` directly.
+///
+/// # Example
+///
+/// ```
+/// # #[macro_use] extern crate nix;
+/// const KVMIO: u8 = 0xAE;
+/// ioctl_write_int_bad!(kvm_create_vm, request_code_none!(KVMIO, 0x03));
+/// # fn main() {}
+/// ```
+#[macro_export]
+macro_rules! request_code_none {
+ ($g:expr, $n:expr) => (ioc!($crate::sys::ioctl::VOID, $g, $n, 0))
+}
+
+/// Generate an ioctl request code for a command that reads.
+///
+/// This is equivalent to the `_IOR()` macro exposed by the C ioctl API.
+///
+/// You should only use this macro directly if the `ioctl` you're working
+/// with is "bad" and you cannot use `ioctl_read!()` directly.
+///
+/// The read/write direction is relative to userland, so this
+/// command would be userland is reading and the kernel is
+/// writing.
+#[macro_export]
+macro_rules! request_code_read {
+ ($g:expr, $n:expr, $len:expr) => (ioc!($crate::sys::ioctl::OUT, $g, $n, $len))
+}
+
+/// Generate an ioctl request code for a command that writes.
+///
+/// This is equivalent to the `_IOW()` macro exposed by the C ioctl API.
+///
+/// You should only use this macro directly if the `ioctl` you're working
+/// with is "bad" and you cannot use `ioctl_write!()` directly.
+///
+/// The read/write direction is relative to userland, so this
+/// command would be userland is writing and the kernel is
+/// reading.
+#[macro_export]
+macro_rules! request_code_write {
+ ($g:expr, $n:expr, $len:expr) => (ioc!($crate::sys::ioctl::IN, $g, $n, $len))
+}
+
+/// Generate an ioctl request code for a command that reads and writes.
+///
+/// This is equivalent to the `_IOWR()` macro exposed by the C ioctl API.
+///
+/// You should only use this macro directly if the `ioctl` you're working
+/// with is "bad" and you cannot use `ioctl_readwrite!()` directly.
+#[macro_export]
+macro_rules! request_code_readwrite {
+ ($g:expr, $n:expr, $len:expr) => (ioc!($crate::sys::ioctl::INOUT, $g, $n, $len))
+}
diff --git a/src/sys/ioctl/platform/linux.rs b/src/sys/ioctl/linux.rs
index 117085d2..e0d02ad4 100644
--- a/src/sys/ioctl/platform/linux.rs
+++ b/src/sys/ioctl/linux.rs
@@ -25,17 +25,6 @@ mod consts {
pub const DIRBITS: u8 = 3;
}
-#[cfg(not(any(target_arch = "powerpc",
- target_arch = "mips",
- target_arch = "mips64",
- target_arch = "x86",
- target_arch = "arm",
- target_arch = "x86_64",
- target_arch = "powerpc64",
- target_arch = "s390x",
- target_arch = "aarch64")))]
-use this_arch_not_supported;
-
// "Generic" ioctl protocol
#[cfg(any(target_arch = "x86",
target_arch = "arm",
@@ -86,30 +75,63 @@ macro_rules! ioc {
(($sz as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::SIZEMASK) << $crate::sys::ioctl::SIZESHIFT))
}
-/// Encode an ioctl command that has no associated data.
+/// Generate an ioctl request code for a command that passes no data.
+///
+/// This is equivalent to the `_IO()` macro exposed by the C ioctl API.
+///
+/// You should only use this macro directly if the `ioctl` you're working
+/// with is "bad" and you cannot use `ioctl_none!()` directly.
+///
+/// # Example
+///
+/// ```
+/// # #[macro_use] extern crate nix;
+/// const KVMIO: u8 = 0xAE;
+/// ioctl_write_int_bad!(kvm_create_vm, request_code_none!(KVMIO, 0x03));
+/// # fn main() {}
+/// ```
#[macro_export]
-#[doc(hidden)]
-macro_rules! io {
+macro_rules! request_code_none {
($ty:expr, $nr:expr) => (ioc!($crate::sys::ioctl::NONE, $ty, $nr, 0))
}
-/// Encode an ioctl command that reads.
+/// Generate an ioctl request code for a command that reads.
+///
+/// This is equivalent to the `_IOR()` macro exposed by the C ioctl API.
+///
+/// You should only use this macro directly if the `ioctl` you're working
+/// with is "bad" and you cannot use `ioctl_read!()` directly.
+///
+/// The read/write direction is relative to userland, so this
+/// command would be userland is reading and the kernel is
+/// writing.
#[macro_export]
-#[doc(hidden)]
-macro_rules! ior {
+macro_rules! request_code_read {
($ty:expr, $nr:expr, $sz:expr) => (ioc!($crate::sys::ioctl::READ, $ty, $nr, $sz))
}
-/// Encode an ioctl command that writes.
+/// Generate an ioctl request code for a command that writes.
+///
+/// This is equivalent to the `_IOW()` macro exposed by the C ioctl API.
+///
+/// You should only use this macro directly if the `ioctl` you're working
+/// with is "bad" and you cannot use `ioctl_write!()` directly.
+///
+/// The read/write direction is relative to userland, so this
+/// command would be userland is writing and the kernel is
+/// reading.
#[macro_export]
-#[doc(hidden)]
-macro_rules! iow {
+macro_rules! request_code_write {
($ty:expr, $nr:expr, $sz:expr) => (ioc!($crate::sys::ioctl::WRITE, $ty, $nr, $sz))
}
-/// Encode an ioctl command that both reads and writes.
+/// Generate an ioctl request code for a command that reads and writes.
+///
+/// This is equivalent to the `_IOWR()` macro exposed by the C ioctl API.
+///
+/// You should only use this macro directly if the `ioctl` you're working
+/// with is "bad" and you cannot use `ioctl_readwrite!()` directly.
#[macro_export]
-#[doc(hidden)]
-macro_rules! iorw {
+macro_rules! request_code_readwrite {
($ty:expr, $nr:expr, $sz:expr) => (ioc!($crate::sys::ioctl::READ | $crate::sys::ioctl::WRITE, $ty, $nr, $sz))
}
diff --git a/src/sys/ioctl/mod.rs b/src/sys/ioctl/mod.rs
index 44822e4f..c4ba39c8 100644
--- a/src/sys/ioctl/mod.rs
+++ b/src/sys/ioctl/mod.rs
@@ -41,23 +41,23 @@
//! how old `ioctl`s are, however, there are many hard-coded `ioctl` identifiers. These are
//! commonly referred to as "bad" in `ioctl` documentation.
//!
-//! Defining ioctls
-//! ===============
+//! Defining `ioctl`s
+//! =================
//!
-//! This library provides the `ioctl!` macro, for binding `ioctl`s. This macro generates public
+//! This library provides several `ioctl_*!` macros for binding `ioctl`s. These generate public
//! unsafe functions that can then be used for calling the ioctl. This macro has a few different
//! ways it can be used depending on the specific ioctl you're working with.
//!
//! A simple `ioctl` is `SPI_IOC_RD_MODE`. This ioctl works with the SPI interface on Linux. This
//! specific `ioctl` reads the mode of the SPI device as a `u8`. It's declared in
//! `/include/uapi/linux/spi/spidev.h` as `_IOR(SPI_IOC_MAGIC, 1, __u8)`. Since it uses the `_IOR`
-//! macro, we know it's a `read` ioctl and can use the `ioctl!` macro as follows:
+//! macro, we know it's a `read` ioctl and can use the `ioctl_read!` macro as follows:
//!
//! ```
//! # #[macro_use] extern crate nix;
//! const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h
//! const SPI_IOC_TYPE_MODE: u8 = 1;
-//! ioctl!(read spi_read_mode with SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE; u8);
+//! ioctl_read!(spi_read_mode, SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE, u8);
//! # fn main() {}
//! ```
//!
@@ -72,49 +72,47 @@
//! # const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h
//! # const SPI_IOC_TYPE_MODE: u8 = 1;
//! pub unsafe fn spi_read_mode(fd: c_int, data: *mut u8) -> Result<c_int> {
-//! let res = libc::ioctl(fd, ior!(SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE, mem::size_of::<u8>()), data);
+//! let res = libc::ioctl(fd, request_code_read!(SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE, mem::size_of::<u8>()), data);
//! Errno::result(res)
//! }
//! # fn main() {}
//! ```
//!
-//! The return value for `ioctl` functions generated by the `ioctl!` macro are `nix::Error`s.
+//! The return value for the wrapper functions generated by the `ioctl_*!` macros are `nix::Error`s.
//! These are generated by assuming the return value of the ioctl is `-1` on error and everything
//! else is a valid return value. If this is not the case, `Result::map` can be used to map some
//! of the range of "good" values (-Inf..-2, 0..Inf) into a smaller range in a helper function.
//!
//! Writing `ioctl`s generally use pointers as their data source and these should use the
-//! `write_ptr` variant. But in some cases an `int` is passed directly. For these `ioctl`s use the
-//! `write_int` variant of the `ioctl!` macro. This variant does not take a type as the last argument:
+//! `ioctl_write_ptr!`. But in some cases an `int` is passed directly. For these `ioctl`s use the
+//! `ioctl_write_int!` macro. This variant does not take a type as the last argument:
//!
//! ```
//! # #[macro_use] extern crate nix;
//! const HCI_IOC_MAGIC: u8 = b'k';
//! const HCI_IOC_HCIDEVUP: u8 = 1;
-//! ioctl!(write_int hci_dev_up with HCI_IOC_MAGIC, HCI_IOC_HCIDEVUP);
+//! ioctl_write_int!(hci_dev_up, HCI_IOC_MAGIC, HCI_IOC_HCIDEVUP);
//! # fn main() {}
//! ```
//!
-//! Some `ioctl`s don't transfer any data, and those should use the `none` variant. This variant
+//! Some `ioctl`s don't transfer any data, and those should use `ioctl_none!`. This macro
//! doesn't take a type and so it is declared similar to the `write_int` variant shown above.
//!
//! The mode for a given `ioctl` should be clear from the documentation if it has good
//! documentation. Otherwise it will be clear based on the macro used to generate the `ioctl`
-//! number where `_IO`, `_IOR`, `_IOW`, and `_IORW` map to "none", "read", "write_*", and "readwrite"
+//! number where `_IO`, `_IOR`, `_IOW`, and `_IOWR` map to "none", "read", "write_*", and "readwrite"
//! respectively. To determine the specific `write_` variant to use you'll need to find
//! what the argument type is supposed to be. If it's an `int`, then `write_int` should be used,
//! otherwise it should be a pointer and `write_ptr` should be used. On Linux the
//! [`ioctl_list` man page](http://man7.org/linux/man-pages/man2/ioctl_list.2.html) describes a
//! large number of `ioctl`s and describes their argument data type.
//!
-//! More examples on using `ioctl!` can be found in the [rust-spidev crate](https://github.com/rust-embedded/rust-spidev).
-//!
-//! Using hard-coded ioctl numbers
-//! ------------------------------
+//! Using "bad" `ioctl`s
+//! --------------------
//!
//! As mentioned earlier, there are many old `ioctl`s that do not use the newer method of
-//! generating `ioctl` numbers and instead use hardcoded values. These can be used with the `bad *`
-//! variants of the `ioctl!` macro. This naming comes from the Linux kernel which refers to these
+//! generating `ioctl` numbers and instead use hardcoded values. These can be used with the
+//! `ioctl_*_bad!` macros. This naming comes from the Linux kernel which refers to these
//! `ioctl`s as "bad". These are a different variant as they bypass calling the macro that generates
//! the ioctl number and instead use the defined value directly.
//!
@@ -128,27 +126,24 @@
//! # #[cfg(any(target_os = "android", target_os = "linux"))]
//! # use nix::libc::termios as termios;
//! # #[cfg(any(target_os = "android", target_os = "linux"))]
-//! ioctl!(bad read tcgets with TCGETS; termios);
+//! ioctl_read_bad!(tcgets, TCGETS, termios);
//! # fn main() {}
//! ```
//!
-//! The generated function has the same form as that generated by `read`:
+//! The generated function has the same form as that generated by `ioctl_read!`:
//!
//! ```text
//! pub unsafe fn tcgets(fd: c_int, data: *mut termios) -> Result<c_int>;
//! ```
//!
-//! There is also a `bad none`, `bad write_int`/`bad write_ptr`, and `bad readwrite` variant that work
-//! similar to the standard `none`, `write_int`/`write_ptr`, and `readwrite` variants.
+//! Working with Arrays
+//! -------------------
//!
-//! Working with arrays
-//! --------------------
-//!
-//! Some `ioctl`s work with entire arrays of elements. These are supported by the `*_buf` variants in
-//! the `ioctl!` macro which can be used by specifying `read_buf`, `write_buf`, and
-//! `readwrite_buf`. Note that there are no "bad" versions for working with buffers. The generated
-//! functions include a `len` argument to specify the number of elements (where the type of each
-//! element is specified in the macro).
+//! Some `ioctl`s work with entire arrays of elements. These are supported by the `ioctl_*_buf`
+//! family of macros: `ioctl_read_buf`, `ioctl_write_buf`, and `ioctl_readwrite_buf`. Note that
+//! there are no "bad" versions for working with buffers. The generated functions include a `len`
+//! argument to specify the number of elements (where the type of each element is specified in the
+//! macro).
//!
//! Again looking to the SPI `ioctl`s on Linux for an example, there is a `SPI_IOC_MESSAGE` `ioctl`
//! that queues up multiple SPI messages by writing an entire array of `spi_ioc_transfer` structs.
@@ -160,7 +155,7 @@
//! #define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)])
//! ```
//!
-//! The `SPI_MSGSIZE(N)` calculation is already handled by the `ioctl!` macro, so all that's
+//! The `SPI_MSGSIZE(N)` calculation is already handled by the `ioctl_*!` macros, so all that's
//! needed to define this `ioctl` is:
//!
//! ```
@@ -168,7 +163,7 @@
//! const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h
//! const SPI_IOC_TYPE_MESSAGE: u8 = 0;
//! # pub struct spi_ioc_transfer(u64);
-//! ioctl!(write_buf spi_transfer with SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE; spi_ioc_transfer);
+//! ioctl_write_buf!(spi_transfer, SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, spi_ioc_transfer);
//! # fn main() {}
//! ```
//!
@@ -185,22 +180,22 @@
//! # pub struct spi_ioc_transfer(u64);
//! pub unsafe fn spi_message(fd: c_int, data: &mut [spi_ioc_transfer]) -> Result<c_int> {
//! let res = libc::ioctl(fd,
-//! iow!(SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, data.len() * mem::size_of::<spi_ioc_transfer>()),
+//! request_code_write!(SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, data.len() * mem::size_of::<spi_ioc_transfer>()),
//! data);
//! Errno::result(res)
//! }
//! # fn main() {}
//! ```
//!
-//! Finding ioctl documentation
-//! ---------------------------
+//! Finding `ioctl` Documentation
+//! -----------------------------
//!
//! For Linux, look at your system's headers. For example, `/usr/include/linux/input.h` has a lot
-//! of lines defining macros which use `_IO`, `_IOR`, `_IOW`, `_IOC`, and `_IORW`. Some `ioctl`s are
+//! of lines defining macros which use `_IO`, `_IOR`, `_IOW`, `_IOC`, and `_IOWR`. Some `ioctl`s are
//! documented directly in the headers defining their constants, but others have more extensive
//! documentation in man pages (like termios' `ioctl`s which are in `tty_ioctl(4)`).
//!
-//! Documenting the generated functions
+//! Documenting the Generated Functions
//! ===================================
//!
//! In many cases, users will wish for the functions generated by the `ioctl`
@@ -208,41 +203,48 @@
//! are public by default. If you wish to hide the ioctl, you will need to put
//! them in a private module.
//!
-//! For documentation, it is possible to use doc comments inside the `ioctl!`
-//! macro. Here is an example :
+//! For documentation, it is possible to use doc comments inside the `ioctl_*!` macros. Here is an
+//! example :
//!
//! ```
//! # #[macro_use] extern crate nix;
//! # use nix::libc::c_int;
-//! ioctl! {
+//! ioctl_read! {
//! /// Make the given terminal the controlling terminal of the calling process. The calling
//! /// process must be a session leader and not have a controlling terminal already. If the
//! /// terminal is already the controlling terminal of a different session group then the
//! /// ioctl will fail with **EPERM**, unless the caller is root (more precisely: has the
//! /// **CAP_SYS_ADMIN** capability) and arg equals 1, in which case the terminal is stolen
//! /// and all processes that had it as controlling terminal lose it.
-//! read tiocsctty with b't', 19; c_int
+//! tiocsctty, b't', 19, c_int
//! }
//!
//! # fn main() {}
//! ```
//!
-#[cfg(any(target_os = "linux", target_os = "android"))]
-#[path = "platform/linux.rs"]
+#[cfg(any(target_os = "android", target_os = "linux"))]
#[macro_use]
-mod platform;
+mod linux;
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+pub use self::linux::*;
-#[cfg(any(target_os = "macos",
+#[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
target_os = "ios",
+ target_os = "macos",
target_os = "netbsd",
- target_os = "openbsd",
- target_os = "freebsd",
- target_os = "dragonfly"))]
-#[path = "platform/bsd.rs"]
+ target_os = "openbsd"))]
#[macro_use]
-mod platform;
+mod bsd;
-pub use self::platform::*;
+#[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+pub use self::bsd::*;
/// Convert raw ioctl return value to a Nix result
#[macro_export]
@@ -255,109 +257,476 @@ macro_rules! convert_ioctl_res {
);
}
-/// Generates ioctl functions. See [`::sys::ioctl`](sys/ioctl/index.html).
+/// Generates a wrapper function for an ioctl that passes no data to the kernel.
+///
+/// The arguments to this macro are:
+///
+/// * The function name
+/// * The ioctl identifier
+/// * The ioctl sequence number
+///
+/// The generated function has the following signature:
+///
+/// ```rust,ignore
+/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int) -> Result<libc::c_int>
+/// ```
+///
+/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
+///
+/// # Example
+///
+/// The `videodev2` driver on Linux defines the `log_status` `ioctl` as:
+///
+/// ```C
+/// #define VIDIOC_LOG_STATUS _IO('V', 70)
+/// ```
+///
+/// This can be implemented in Rust like:
+///
+/// ```no_run
+/// # #[macro_use] extern crate nix;
+/// ioctl_none!(log_status, b'V', 70);
+/// fn main() {}
+/// ```
#[macro_export]
-macro_rules! ioctl {
- ($(#[$attr:meta])* bad none $name:ident with $nr:expr) => (
+macro_rules! ioctl_none {
+ ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr) => (
+ $(#[$attr])*
+ pub unsafe fn $name(fd: $crate::libc::c_int)
+ -> $crate::Result<$crate::libc::c_int> {
+ convert_ioctl_res!($crate::libc::ioctl(fd, request_code_none!($ioty, $nr) as $crate::sys::ioctl::ioctl_num_type))
+ }
+ )
+}
+
+/// Generates a wrapper function for a "bad" ioctl that passes no data to the kernel.
+///
+/// The arguments to this macro are:
+///
+/// * The function name
+/// * The ioctl request code
+///
+/// The generated function has the following signature:
+///
+/// ```rust,ignore
+/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int) -> Result<libc::c_int>
+/// ```
+///
+/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
+///
+/// # Example
+///
+/// ```no_run
+/// # #[macro_use] extern crate nix;
+/// # extern crate libc;
+/// # use libc::TIOCNXCL;
+/// # use std::fs::File;
+/// # use std::os::unix::io::AsRawFd;
+/// ioctl_none_bad!(tiocnxcl, TIOCNXCL);
+/// fn main() {
+/// let file = File::open("/dev/ttyUSB0").unwrap();
+/// unsafe { tiocnxcl(file.as_raw_fd()) }.unwrap();
+/// }
+/// ```
+// TODO: add an example using request_code_*!()
+#[macro_export]
+macro_rules! ioctl_none_bad {
+ ($(#[$attr:meta])* $name:ident, $nr:expr) => (
$(#[$attr])*
pub unsafe fn $name(fd: $crate::libc::c_int)
-> $crate::Result<$crate::libc::c_int> {
convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type))
}
- );
- ($(#[$attr:meta])* bad read $name:ident with $nr:expr; $ty:ty) => (
+ )
+}
+
+/// Generates a wrapper function for an ioctl that reads data from the kernel.
+///
+/// The arguments to this macro are:
+///
+/// * The function name
+/// * The ioctl identifier
+/// * The ioctl sequence number
+/// * The data type passed by this ioctl
+///
+/// The generated function has the following signature:
+///
+/// ```rust,ignore
+/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result<libc::c_int>
+/// ```
+///
+/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
+///
+/// # Example
+///
+/// ```
+/// # #[macro_use] extern crate nix;
+/// const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h
+/// const SPI_IOC_TYPE_MODE: u8 = 1;
+/// ioctl_read!(spi_read_mode, SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE, u8);
+/// # fn main() {}
+/// ```
+#[macro_export]
+macro_rules! ioctl_read {
+ ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => (
$(#[$attr])*
pub unsafe fn $name(fd: $crate::libc::c_int,
data: *mut $ty)
-> $crate::Result<$crate::libc::c_int> {
- convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
+ convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
}
- );
- ($(#[$attr:meta])* bad write_ptr $name:ident with $nr:expr; $ty:ty) => (
+ )
+}
+
+/// Generates a wrapper function for a "bad" ioctl that reads data from the kernel.
+///
+/// The arguments to this macro are:
+///
+/// * The function name
+/// * The ioctl request code
+/// * The data type passed by this ioctl
+///
+/// The generated function has the following signature:
+///
+/// ```rust,ignore
+/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result<libc::c_int>
+/// ```
+///
+/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
+///
+/// # Example
+///
+/// ```
+/// # extern crate libc;
+/// # #[macro_use] extern crate nix;
+/// # #[cfg(any(target_os = "android", target_os = "linux"))]
+/// ioctl_read_bad!(tcgets, libc::TCGETS, libc::termios);
+/// # fn main() {}
+/// ```
+#[macro_export]
+macro_rules! ioctl_read_bad {
+ ($(#[$attr:meta])* $name:ident, $nr:expr, $ty:ty) => (
$(#[$attr])*
pub unsafe fn $name(fd: $crate::libc::c_int,
- data: *const $ty)
+ data: *mut $ty)
-> $crate::Result<$crate::libc::c_int> {
convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
}
- );
- ($(#[$attr:meta])* bad write_int $name:ident with $nr:expr) => (
+ )
+}
+
+/// Generates a wrapper function for an ioctl that writes data through a pointer to the kernel.
+///
+/// The arguments to this macro are:
+///
+/// * The function name
+/// * The ioctl identifier
+/// * The ioctl sequence number
+/// * The data type passed by this ioctl
+///
+/// The generated function has the following signature:
+///
+/// ```rust,ignore
+/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *const DATA_TYPE) -> Result<libc::c_int>
+/// ```
+///
+/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
+///
+/// # Example
+///
+/// ```
+/// # #[macro_use] extern crate nix;
+/// # pub struct v4l2_audio {}
+/// ioctl_write_ptr!(s_audio, b'V', 34, v4l2_audio);
+/// # fn main() {}
+/// ```
+#[macro_export]
+macro_rules! ioctl_write_ptr {
+ ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => (
$(#[$attr])*
pub unsafe fn $name(fd: $crate::libc::c_int,
- data: $crate::libc::c_int)
+ data: *const $ty)
-> $crate::Result<$crate::libc::c_int> {
- convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
+ convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
}
- );
- ($(#[$attr:meta])* bad readwrite $name:ident with $nr:expr; $ty:ty) => (
+ )
+}
+
+/// Generates a wrapper function for a "bad" ioctl that writes data through a pointer to the kernel.
+///
+/// The arguments to this macro are:
+///
+/// * The function name
+/// * The ioctl request code
+/// * The data type passed by this ioctl
+///
+/// The generated function has the following signature:
+///
+/// ```rust,ignore
+/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *const DATA_TYPE) -> Result<libc::c_int>
+/// ```
+///
+/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
+///
+/// # Example
+///
+/// ```
+/// # extern crate libc;
+/// # #[macro_use] extern crate nix;
+/// # #[cfg(any(target_os = "android", target_os = "linux"))]
+/// ioctl_write_ptr_bad!(tcsets, libc::TCSETS, libc::termios);
+/// # fn main() {}
+/// ```
+#[macro_export]
+macro_rules! ioctl_write_ptr_bad {
+ ($(#[$attr:meta])* $name:ident, $nr:expr, $ty:ty) => (
$(#[$attr])*
pub unsafe fn $name(fd: $crate::libc::c_int,
- data: *mut $ty)
+ data: *const $ty)
-> $crate::Result<$crate::libc::c_int> {
convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
}
- );
- ($(#[$attr:meta])* none $name:ident with $ioty:expr, $nr:expr) => (
- $(#[$attr])*
- pub unsafe fn $name(fd: $crate::libc::c_int)
- -> $crate::Result<$crate::libc::c_int> {
- convert_ioctl_res!($crate::libc::ioctl(fd, io!($ioty, $nr) as $crate::sys::ioctl::ioctl_num_type))
- }
- );
- ($(#[$attr:meta])* read $name:ident with $ioty:expr, $nr:expr; $ty:ty) => (
+ )
+}
+
+/// Generates a wrapper function for a ioctl that writes an integer to the kernel.
+///
+/// The arguments to this macro are:
+///
+/// * The function name
+/// * The ioctl identifier
+/// * The ioctl sequence number
+///
+/// The generated function has the following signature:
+///
+/// ```rust,ignore
+/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: libc::c_int) -> Result<libc::c_int>
+/// ```
+///
+/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
+///
+/// # Example
+///
+/// ```
+/// # #[macro_use] extern crate nix;
+/// const HCI_IOC_MAGIC: u8 = b'k';
+/// const HCI_IOC_HCIDEVUP: u8 = 1;
+/// ioctl_write_int!(hci_dev_up, HCI_IOC_MAGIC, HCI_IOC_HCIDEVUP);
+/// # fn main() {}
+/// ```
+#[macro_export]
+macro_rules! ioctl_write_int {
+ ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr) => (
$(#[$attr])*
pub unsafe fn $name(fd: $crate::libc::c_int,
- data: *mut $ty)
+ data: $crate::libc::c_int)
-> $crate::Result<$crate::libc::c_int> {
- convert_ioctl_res!($crate::libc::ioctl(fd, ior!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
+ convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of::<$crate::libc::c_int>()) as $crate::sys::ioctl::ioctl_num_type, data))
}
- );
- ($(#[$attr:meta])* write_ptr $name:ident with $ioty:expr, $nr:expr; $ty:ty) => (
+ )
+}
+
+/// Generates a wrapper function for a "bad" ioctl that writes an integer to the kernel.
+///
+/// The arguments to this macro are:
+///
+/// * The function name
+/// * The ioctl request code
+///
+/// The generated function has the following signature:
+///
+/// ```rust,ignore
+/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: libc::c_int) -> Result<libc::c_int>
+/// ```
+///
+/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
+///
+/// # Examples
+///
+/// ```
+/// # extern crate libc;
+/// # #[macro_use] extern crate nix;
+/// # #[cfg(any(target_os = "android", target_os = "linux"))]
+/// ioctl_write_int_bad!(tcsbrk, libc::TCSBRK);
+/// # fn main() {}
+/// ```
+///
+/// ```rust
+/// # #[macro_use] extern crate nix;
+/// const KVMIO: u8 = 0xAE;
+/// ioctl_write_int_bad!(kvm_create_vm, request_code_none!(KVMIO, 0x03));
+/// # fn main() {}
+/// ```
+#[macro_export]
+macro_rules! ioctl_write_int_bad {
+ ($(#[$attr:meta])* $name:ident, $nr:expr) => (
$(#[$attr])*
pub unsafe fn $name(fd: $crate::libc::c_int,
- data: *const $ty)
+ data: $crate::libc::c_int)
-> $crate::Result<$crate::libc::c_int> {
- convert_ioctl_res!($crate::libc::ioctl(fd, iow!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
+ convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
}
- );
- ($(#[$attr:meta])* write_int $name:ident with $ioty:expr, $nr:expr) => (
+ )
+}
+
+/// Generates a wrapper function for an ioctl that reads and writes data to the kernel.
+///
+/// The arguments to this macro are:
+///
+/// * The function name
+/// * The ioctl identifier
+/// * The ioctl sequence number
+/// * The data type passed by this ioctl
+///
+/// The generated function has the following signature:
+///
+/// ```rust,ignore
+/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result<libc::c_int>
+/// ```
+///
+/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
+///
+/// # Example
+///
+/// ```
+/// # #[macro_use] extern crate nix;
+/// # pub struct v4l2_audio {}
+/// ioctl_readwrite!(enum_audio, b'V', 65, v4l2_audio);
+/// # fn main() {}
+/// ```
+#[macro_export]
+macro_rules! ioctl_readwrite {
+ ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => (
$(#[$attr])*
pub unsafe fn $name(fd: $crate::libc::c_int,
- data: $crate::libc::c_int)
+ data: *mut $ty)
-> $crate::Result<$crate::libc::c_int> {
- convert_ioctl_res!($crate::libc::ioctl(fd, iow!($ioty, $nr, ::std::mem::size_of::<$crate::libc::c_int>()) as $crate::sys::ioctl::ioctl_num_type, data))
+ convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
}
- );
- ($(#[$attr:meta])* readwrite $name:ident with $ioty:expr, $nr:expr; $ty:ty) => (
+ )
+}
+
+/// Generates a wrapper function for a "bad" ioctl that reads and writes data to the kernel.
+///
+/// The arguments to this macro are:
+///
+/// * The function name
+/// * The ioctl request code
+/// * The data type passed by this ioctl
+///
+/// The generated function has the following signature:
+///
+/// ```rust,ignorerust,ignore
+/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result<libc::c_int>
+/// ```
+///
+/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
+// TODO: Find an example for ioctl_readwrite_bad
+#[macro_export]
+macro_rules! ioctl_readwrite_bad {
+ ($(#[$attr:meta])* $name:ident, $nr:expr, $ty:ty) => (
$(#[$attr])*
pub unsafe fn $name(fd: $crate::libc::c_int,
data: *mut $ty)
-> $crate::Result<$crate::libc::c_int> {
- convert_ioctl_res!($crate::libc::ioctl(fd, iorw!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
+ convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
}
- );
- ($(#[$attr:meta])* read_buf $name:ident with $ioty:expr, $nr:expr; $ty:ty) => (
+ )
+}
+
+/// Generates a wrapper function for an ioctl that reads an array of elements from the kernel.
+///
+/// The arguments to this macro are:
+///
+/// * The function name
+/// * The ioctl identifier
+/// * The ioctl sequence number
+/// * The data type passed by this ioctl
+///
+/// The generated function has the following signature:
+///
+/// ```rust,ignore
+/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: &mut [DATA_TYPE]) -> Result<libc::c_int>
+/// ```
+///
+/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
+// TODO: Find an example for ioctl_read_buf
+#[macro_export]
+macro_rules! ioctl_read_buf {
+ ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => (
$(#[$attr])*
pub unsafe fn $name(fd: $crate::libc::c_int,
data: &mut [$ty])
-> $crate::Result<$crate::libc::c_int> {
- convert_ioctl_res!($crate::libc::ioctl(fd, ior!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
+ convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
}
- );
- ($(#[$attr:meta])* write_buf $name:ident with $ioty:expr, $nr:expr; $ty:ty) => (
+ )
+}
+
+/// Generates a wrapper function for an ioctl that writes an array of elements to the kernel.
+///
+/// The arguments to this macro are:
+///
+/// * The function name
+/// * The ioctl identifier
+/// * The ioctl sequence number
+/// * The data type passed by this ioctl
+///
+/// The generated function has the following signature:
+///
+/// ```rust,ignore
+/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: &[DATA_TYPE]) -> Result<libc::c_int>
+/// ```
+///
+/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
+///
+/// # Examples
+///
+/// ```
+/// # #[macro_use] extern crate nix;
+/// const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h
+/// const SPI_IOC_TYPE_MESSAGE: u8 = 0;
+/// # pub struct spi_ioc_transfer(u64);
+/// ioctl_write_buf!(spi_transfer, SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, spi_ioc_transfer);
+/// # fn main() {}
+/// ```
+#[macro_export]
+macro_rules! ioctl_write_buf {
+ ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => (
$(#[$attr])*
pub unsafe fn $name(fd: $crate::libc::c_int,
data: &[$ty])
-> $crate::Result<$crate::libc::c_int> {
- convert_ioctl_res!($crate::libc::ioctl(fd, iow!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
+ convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
}
- );
- ($(#[$attr:meta])* readwrite_buf $name:ident with $ioty:expr, $nr:expr; $ty:ty) => (
+ )
+}
+
+/// Generates a wrapper function for an ioctl that reads and writes an array of elements to the kernel.
+///
+/// The arguments to this macro are:
+///
+/// * The function name
+/// * The ioctl identifier
+/// * The ioctl sequence number
+/// * The data type passed by this ioctl
+///
+/// The generated function has the following signature:
+///
+/// ```rust,ignore
+/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: &mut [DATA_TYPE]) -> Result<libc::c_int>
+/// ```
+///
+/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
+// TODO: Find an example for readwrite_buf
+#[macro_export]
+macro_rules! ioctl_readwrite_buf {
+ ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => (
$(#[$attr])*
pub unsafe fn $name(fd: $crate::libc::c_int,
data: &mut [$ty])
-> $crate::Result<$crate::libc::c_int> {
- convert_ioctl_res!($crate::libc::ioctl(fd, iorw!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
+ convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
}
- );
+ )
}
diff --git a/src/sys/ioctl/platform/bsd.rs b/src/sys/ioctl/platform/bsd.rs
deleted file mode 100644
index a36808d7..00000000
--- a/src/sys/ioctl/platform/bsd.rs
+++ /dev/null
@@ -1,51 +0,0 @@
-/// The datatype used for the ioctl number
-#[doc(hidden)]
-pub type ioctl_num_type = ::libc::c_ulong;
-
-mod consts {
- use ::sys::ioctl::platform::ioctl_num_type;
- #[doc(hidden)]
- pub const VOID: ioctl_num_type = 0x2000_0000;
- #[doc(hidden)]
- pub const OUT: ioctl_num_type = 0x4000_0000;
- #[doc(hidden)]
- pub const IN: ioctl_num_type = 0x8000_0000;
- #[doc(hidden)]
- pub const INOUT: ioctl_num_type = (IN|OUT);
- #[doc(hidden)]
- pub const IOCPARM_MASK: ioctl_num_type = 0x1fff;
-}
-
-pub use self::consts::*;
-
-#[macro_export]
-#[doc(hidden)]
-macro_rules! ioc {
- ($inout:expr, $group:expr, $num:expr, $len:expr) => (
- $inout | (($len as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::IOCPARM_MASK) << 16) | (($group as $crate::sys::ioctl::ioctl_num_type) << 8) | ($num as $crate::sys::ioctl::ioctl_num_type)
- )
-}
-
-#[macro_export]
-#[doc(hidden)]
-macro_rules! io {
- ($g:expr, $n:expr) => (ioc!($crate::sys::ioctl::VOID, $g, $n, 0))
-}
-
-#[macro_export]
-#[doc(hidden)]
-macro_rules! ior {
- ($g:expr, $n:expr, $len:expr) => (ioc!($crate::sys::ioctl::OUT, $g, $n, $len))
-}
-
-#[macro_export]
-#[doc(hidden)]
-macro_rules! iow {
- ($g:expr, $n:expr, $len:expr) => (ioc!($crate::sys::ioctl::IN, $g, $n, $len))
-}
-
-#[macro_export]
-#[doc(hidden)]
-macro_rules! iorw {
- ($g:expr, $n:expr, $len:expr) => (ioc!($crate::sys::ioctl::INOUT, $g, $n, $len))
-}
diff --git a/src/sys/mod.rs b/src/sys/mod.rs
index 972a1b5e..db03dece 100644
--- a/src/sys/mod.rs
+++ b/src/sys/mod.rs
@@ -20,6 +20,14 @@ pub mod event;
#[cfg(target_os = "linux")]
pub mod eventfd;
+#[cfg(any(target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
#[macro_use]
pub mod ioctl;
diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs
index 25114dd2..93014f1c 100644
--- a/src/sys/socket/addr.rs
+++ b/src/sys/socket/addr.rs
@@ -1029,7 +1029,7 @@ pub mod sys_control {
const CTL_IOC_INFO: u8 = 3;
const MAX_KCTL_NAME: usize = 96;
- ioctl!(readwrite ctl_info with CTL_IOC_MAGIC, CTL_IOC_INFO; ctl_ioc_info);
+ ioctl_readwrite!(ctl_info, CTL_IOC_MAGIC, CTL_IOC_INFO, ctl_ioc_info);
#[derive(Copy, Clone)]
#[repr(C)]
diff --git a/test/sys/test_ioctl.rs b/test/sys/test_ioctl.rs
index 9a7a4819..ec9d26a3 100644
--- a/test/sys/test_ioctl.rs
+++ b/test/sys/test_ioctl.rs
@@ -1,80 +1,26 @@
#![allow(dead_code)]
// Simple tests to ensure macro generated fns compile
-ioctl!(bad none do_bad with 0x1234);
-ioctl!(bad read do_bad_read with 0x1234; u16);
-ioctl!(bad write_int do_bad_write_int with 0x1234);
-ioctl!(bad write_ptr do_bad_write_ptr with 0x1234; u8);
-ioctl!(bad readwrite do_bad_readwrite with 0x1234; u32);
-ioctl!(none do_none with 0, 0);
-ioctl!(read read_test with 0, 0; u32);
-ioctl!(write_int write_ptr_int with 0, 0);
-ioctl!(write_ptr write_ptr_u8 with 0, 0; u8);
-ioctl!(write_ptr write_ptr_u32 with 0, 0; u32);
-ioctl!(write_ptr write_ptr_u64 with 0, 0; u64);
-ioctl!(readwrite readwrite_test with 0, 0; u64);
-ioctl!(read_buf readbuf_test with 0, 0; u32);
+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 with SPI_IOC_MAGIC, SPI_IOC_MESSAGE; u8);
-ioctl!(write_buf writebuf_test_u8 with 0, 0; u8);
-ioctl!(write_buf writebuf_test_u32 with 0, 0; u32);
-ioctl!(write_buf writebuf_test_u64 with 0, 0; u64);
-ioctl!(readwrite_buf readwritebuf_test with 0, 0; u32);
-
-// Make sure documentation works
-ioctl! {
- /// This documents the ioctl function
- bad none do_bad_docs with 0x1234
-}
-ioctl! {
- /// This documents the ioctl function
- bad read do_bad_read_docs with 0x1234; u16
-}
-ioctl! {
- /// This documents the ioctl function
- bad write_int do_bad_write_int_docs with 0x1234
-}
-ioctl! {
- /// This documents the ioctl function
- bad write_ptr do_bad_write_ptr_docs with 0x1234; u8
-}
-ioctl! {
- /// This documents the ioctl function
- bad readwrite do_bad_readwrite_docs with 0x1234; u32
-}
-ioctl! {
- /// This documents the ioctl function
- none do_none_docs with 0, 0
-}
-ioctl! {
- /// This documents the ioctl function
- read do_read_docs with 0, 0; u32
-}
-ioctl! {
- /// This documents the ioctl function
- write_int do_write_int_docs with 0, 0
-}
-ioctl! {
- /// This documents the ioctl function
- write_ptr do_write_ptr_docs with 0, 0; u32
-}
-ioctl! {
- /// This documents the ioctl function
- readwrite do_readwrite_docs with 0, 0; u32
-}
-ioctl! {
- /// This documents the ioctl function
- read_buf do_read_buf_docs with 0, 0; u32
-}
-ioctl! {
- /// This documents the ioctl function
- write_buf do_write_buf_docs with 0, 0; u32
-}
-ioctl! {
- /// This documents the ioctl function
- readwrite_buf do_readwrite_buf_docs with 0, 0; u32
-}
+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
@@ -87,22 +33,22 @@ mod linux {
#[test]
fn test_op_none() {
if cfg!(any(target_arch = "mips", target_arch = "mips64", target_arch="powerpc", target_arch="powerpc64")){
- assert_eq!(io!(b'q', 10), 0x2000_710A);
- assert_eq!(io!(b'a', 255), 0x2000_61FF);
+ assert_eq!(request_code_none!(b'q', 10), 0x2000_710A);
+ assert_eq!(request_code_none!(b'a', 255), 0x2000_61FF);
} else {
- assert_eq!(io!(b'q', 10), 0x0000_710A);
- assert_eq!(io!(b'a', 255), 0x0000_61FF);
+ assert_eq!(request_code_none!(b'q', 10), 0x0000_710A);
+ assert_eq!(request_code_none!(b'a', 255), 0x0000_61FF);
}
}
#[test]
fn test_op_write() {
if cfg!(any(target_arch = "mips", target_arch = "mips64", target_arch="powerpc", target_arch="powerpc64")){
- assert_eq!(iow!(b'z', 10, 1), 0x8001_7A0A);
- assert_eq!(iow!(b'z', 10, 512), 0x8200_7A0A);
+ assert_eq!(request_code_write!(b'z', 10, 1), 0x8001_7A0A);
+ assert_eq!(request_code_write!(b'z', 10, 512), 0x8200_7A0A);
} else {
- assert_eq!(iow!(b'z', 10, 1), 0x4001_7A0A);
- assert_eq!(iow!(b'z', 10, 512), 0x4200_7A0A);
+ assert_eq!(request_code_write!(b'z', 10, 1), 0x4001_7A0A);
+ assert_eq!(request_code_write!(b'z', 10, 512), 0x4200_7A0A);
}
}
@@ -110,9 +56,9 @@ mod linux {
#[test]
fn test_op_write_64() {
if cfg!(any(target_arch = "mips64", target_arch="powerpc64")){
- assert_eq!(iow!(b'z', 10, (1 as u64) << 32), 0x8000_7A0A);
+ assert_eq!(request_code_write!(b'z', 10, (1 as u64) << 32), 0x8000_7A0A);
} else {
- assert_eq!(iow!(b'z', 10, (1 as u64) << 32), 0x4000_7A0A);
+ assert_eq!(request_code_write!(b'z', 10, (1 as u64) << 32), 0x4000_7A0A);
}
}
@@ -120,11 +66,11 @@ mod linux {
#[test]
fn test_op_read() {
if cfg!(any(target_arch = "mips", target_arch = "mips64", target_arch="powerpc", target_arch="powerpc64")){
- assert_eq!(ior!(b'z', 10, 1), 0x4001_7A0A);
- assert_eq!(ior!(b'z', 10, 512), 0x4200_7A0A);
+ assert_eq!(request_code_read!(b'z', 10, 1), 0x4001_7A0A);
+ assert_eq!(request_code_read!(b'z', 10, 512), 0x4200_7A0A);
} else {
- assert_eq!(ior!(b'z', 10, 1), 0x8001_7A0A);
- assert_eq!(ior!(b'z', 10, 512), 0x8200_7A0A);
+ assert_eq!(request_code_read!(b'z', 10, 1), 0x8001_7A0A);
+ assert_eq!(request_code_read!(b'z', 10, 512), 0x8200_7A0A);
}
}
@@ -132,72 +78,72 @@ mod linux {
#[test]
fn test_op_read_64() {
if cfg!(any(target_arch = "mips64", target_arch="powerpc64")){
- assert_eq!(ior!(b'z', 10, (1 as u64) << 32), 0x4000_7A0A);
+ assert_eq!(request_code_read!(b'z', 10, (1 as u64) << 32), 0x4000_7A0A);
} else {
- assert_eq!(ior!(b'z', 10, (1 as u64) << 32), 0x8000_7A0A);
+ assert_eq!(request_code_read!(b'z', 10, (1 as u64) << 32), 0x8000_7A0A);
}
}
#[test]
fn test_op_read_write() {
- assert_eq!(iorw!(b'z', 10, 1), 0xC001_7A0A);
- assert_eq!(iorw!(b'z', 10, 512), 0xC200_7A0A);
+ 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!(iorw!(b'z', 10, (1 as u64) << 32), 0xC000_7A0A);
+ assert_eq!(request_code_readwrite!(b'z', 10, (1 as u64) << 32), 0xC000_7A0A);
}
}
-#[cfg(any(target_os = "macos",
+#[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
target_os = "ios",
+ target_os = "macos",
target_os = "netbsd",
- target_os = "openbsd",
- target_os = "freebsd",
- target_os = "dragonfly"))]
+ target_os = "openbsd"))]
mod bsd {
#[test]
fn test_op_none() {
- assert_eq!(io!(b'q', 10), 0x2000_710A);
- assert_eq!(io!(b'a', 255), 0x2000_61FF);
+ assert_eq!(request_code_none!(b'q', 10), 0x2000_710A);
+ assert_eq!(request_code_none!(b'a', 255), 0x2000_61FF);
}
#[test]
fn test_op_write() {
- assert_eq!(iow!(b'z', 10, 1), 0x8001_7A0A);
- assert_eq!(iow!(b'z', 10, 512), 0x8200_7A0A);
+ 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!(iow!(b'z', 10, (1 as u64) << 32), 0x8000_7A0A);
+ assert_eq!(request_code_write!(b'z', 10, (1 as u64) << 32), 0x8000_7A0A);
}
#[test]
fn test_op_read() {
- assert_eq!(ior!(b'z', 10, 1), 0x4001_7A0A);
- assert_eq!(ior!(b'z', 10, 512), 0x4200_7A0A);
+ 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!(ior!(b'z', 10, (1 as u64) << 32), 0x4000_7A0A);
+ assert_eq!(request_code_read!(b'z', 10, (1 as u64) << 32), 0x4000_7A0A);
}
#[test]
fn test_op_read_write() {
- assert_eq!(iorw!(b'z', 10, 1), 0xC001_7A0A);
- assert_eq!(iorw!(b'z', 10, 512), 0xC200_7A0A);
+ 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!(iorw!(b'z', 10, (1 as u64) << 32), 0xC000_7A0A);
+ assert_eq!(request_code_readwrite!(b'z', 10, (1 as u64) << 32), 0xC000_7A0A);
}
}
@@ -212,44 +158,44 @@ mod linux_ioctls {
use nix::Error::Sys;
use nix::errno::Errno::{ENOTTY, ENOSYS};
- ioctl!(bad none tiocnxcl with TIOCNXCL);
+ ioctl_none_bad!(tiocnxcl, TIOCNXCL);
#[test]
- fn test_ioctl_bad_none() {
+ fn test_ioctl_none_bad() {
let file = tempfile().unwrap();
let res = unsafe { tiocnxcl(file.as_raw_fd()) };
assert_eq!(res, Err(Sys(ENOTTY)));
}
- ioctl!(bad read tcgets with TCGETS; termios);
+ ioctl_read_bad!(tcgets, TCGETS, termios);
#[test]
- fn test_ioctl_bad_read() {
+ fn test_ioctl_read_bad() {
let file = tempfile().unwrap();
let mut termios = unsafe { mem::uninitialized() };
let res = unsafe { tcgets(file.as_raw_fd(), &mut termios) };
assert_eq!(res, Err(Sys(ENOTTY)));
}
- ioctl!(bad write_int tcsbrk with TCSBRK);
+ ioctl_write_int_bad!(tcsbrk, TCSBRK);
#[test]
- fn test_ioctl_bad_write_int() {
+ fn test_ioctl_write_int_bad() {
let file = tempfile().unwrap();
let res = unsafe { tcsbrk(file.as_raw_fd(), 0) };
assert_eq!(res, Err(Sys(ENOTTY)));
}
- ioctl!(bad write_ptr tcsets with TCSETS; termios);
+ ioctl_write_ptr_bad!(tcsets, TCSETS, termios);
#[test]
- fn test_ioctl_bad_write_ptr() {
+ fn test_ioctl_write_ptr_bad() {
let file = tempfile().unwrap();
let termios: termios = unsafe { mem::uninitialized() };
let res = unsafe { tcsets(file.as_raw_fd(), &termios) };
assert_eq!(res, Err(Sys(ENOTTY)));
}
- // FIXME: Find a suitable example for "bad readwrite".
+ // FIXME: Find a suitable example for `ioctl_readwrite_bad`
// From linux/videodev2.h
- ioctl!(none log_status with b'V', 70);
+ ioctl_none!(log_status, b'V', 70);
#[test]
fn test_ioctl_none() {
let file = tempfile().unwrap();
@@ -267,7 +213,7 @@ mod linux_ioctls {
}
// From linux/videodev2.h
- ioctl!(write_ptr s_audio with b'V', 34; v4l2_audio);
+ ioctl_write_ptr!(s_audio, b'V', 34, v4l2_audio);
#[test]
fn test_ioctl_write_ptr() {
let file = tempfile().unwrap();
@@ -279,7 +225,7 @@ mod linux_ioctls {
// From linux/net/bluetooth/hci_sock.h
const HCI_IOC_MAGIC: u8 = b'H';
const HCI_IOC_HCIDEVUP: u8 = 201;
- ioctl!(write_int hcidevup with HCI_IOC_MAGIC, HCI_IOC_HCIDEVUP);
+ ioctl_write_int!(hcidevup, HCI_IOC_MAGIC, HCI_IOC_HCIDEVUP);
#[test]
fn test_ioctl_write_int() {
let file = tempfile().unwrap();
@@ -288,7 +234,7 @@ mod linux_ioctls {
}
// From linux/videodev2.h
- ioctl!(read g_audio with b'V', 33; v4l2_audio);
+ ioctl_read!(g_audio, b'V', 33, v4l2_audio);
#[test]
fn test_ioctl_read() {
let file = tempfile().unwrap();
@@ -298,7 +244,7 @@ mod linux_ioctls {
}
// From linux/videodev2.h
- ioctl!(readwrite enum_audio with b'V', 65; v4l2_audio);
+ ioctl_readwrite!(enum_audio, b'V', 65, v4l2_audio);
#[test]
fn test_ioctl_readwrite() {
let file = tempfile().unwrap();
@@ -307,7 +253,7 @@ mod linux_ioctls {
assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
}
- // FIXME: Find a suitable example for read_buf.
+ // FIXME: Find a suitable example for `ioctl_read_buf`.
#[repr(C)]
pub struct spi_ioc_transfer {
@@ -324,7 +270,7 @@ mod linux_ioctls {
}
// From linux/spi/spidev.h
- ioctl!(write_buf spi_ioc_message with super::SPI_IOC_MAGIC, super::SPI_IOC_MESSAGE; spi_ioc_transfer);
+ 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();
@@ -333,7 +279,7 @@ mod linux_ioctls {
assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
}
- // FIXME: Find a suitable example for readwrite_buf.
+ // FIXME: Find a suitable example for `ioctl_readwrite_buf`.
}
#[cfg(target_os = "freebsd")]
@@ -353,7 +299,7 @@ mod freebsd_ioctls {
const TTY_IOC_TYPE_GETA: u8 = 19;
const TTY_IOC_TYPE_SETA: u8 = 20;
- ioctl!(none tiocnxcl with TTY_IOC_MAGIC, TTY_IOC_TYPE_NXCL);
+ ioctl_none!(tiocnxcl, TTY_IOC_MAGIC, TTY_IOC_TYPE_NXCL);
#[test]
fn test_ioctl_none() {
let file = tempfile().unwrap();
@@ -361,7 +307,7 @@ mod freebsd_ioctls {
assert_eq!(res, Err(Sys(ENOTTY)));
}
- ioctl!(read tiocgeta with TTY_IOC_MAGIC, TTY_IOC_TYPE_GETA; termios);
+ ioctl_read!(tiocgeta, TTY_IOC_MAGIC, TTY_IOC_TYPE_GETA, termios);
#[test]
fn test_ioctl_read() {
let file = tempfile().unwrap();
@@ -370,7 +316,7 @@ mod freebsd_ioctls {
assert_eq!(res, Err(Sys(ENOTTY)));
}
- ioctl!(write_ptr tiocseta with TTY_IOC_MAGIC, TTY_IOC_TYPE_SETA; termios);
+ ioctl_write_ptr!(tiocseta, TTY_IOC_MAGIC, TTY_IOC_TYPE_SETA, termios);
#[test]
fn test_ioctl_write_ptr() {
let file = tempfile().unwrap();