diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/sys/ioctl/bsd.rs | 88 | ||||
-rw-r--r-- | src/sys/ioctl/linux.rs (renamed from src/sys/ioctl/platform/linux.rs) | 68 | ||||
-rw-r--r-- | src/sys/ioctl/mod.rs | 567 | ||||
-rw-r--r-- | src/sys/ioctl/platform/bsd.rs | 51 | ||||
-rw-r--r-- | src/sys/mod.rs | 8 | ||||
-rw-r--r-- | src/sys/socket/addr.rs | 2 |
6 files changed, 610 insertions, 174 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)] |