Skip to content

Commit

Permalink
Merge #833
Browse files Browse the repository at this point in the history
833: Refactor the ioctl API and documentation r=posborne a=Susurrus

I still need to flesh out the docs for the different `ioctl_*!` variants that now exist. I separated them into different macros so they can have their own docs, which should help discoverability. And when macro namespacing comes around this will be a pretty neatly documented API I think (though we'll likely want to rename these macros again at that point).

 * Split `ioctl!` into separate macros. This makes documentation easier to read.
 * Expose `request_code_*!` in the documentation to make the `ioctl_*_bad` macros easier to use.
 * Reorganize the file hierarchy to be simpler

cc @gabrielesvelto @posborne @jethrogb

Co-authored-by: Bryant Mairs <bryantmairs@google.com>
  • Loading branch information
bors[bot] and Bryant Mairs committed Apr 11, 2018
2 parents 31e901b + 5dad660 commit 13f66d0
Show file tree
Hide file tree
Showing 8 changed files with 753 additions and 302 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
([#825](https://github.com/nix-rust/nix/pull/825))
- Added `fchmod`, `fchmodat`.
([#857](https://github.com/nix-rust/nix/pull/857))
- Added `request_code_write_int!` on FreeBSD/DragonFlyBSD
([#833](https://github.com/nix-rust/nix/pull/833))

### Changed
- Display and Debug for SysControlAddr now includes all fields.
Expand All @@ -37,6 +39,10 @@ This project adheres to [Semantic Versioning](http://semver.org/).
### Fixed
- Properly exposed 460800 and 921600 baud rates on NetBSD
([#837](https://github.com/nix-rust/nix/pull/837))
- Fixed `ioctl_write_int!` on FreeBSD/DragonFlyBSD
([#833](https://github.com/nix-rust/nix/pull/833))
- `ioctl_write_int!` now properly supports passing a `c_ulong` as the parameter on Linux non-musl targets
([#833](https://github.com/nix-rust/nix/pull/833))

### Removed
- Removed explicit support for the `bytes` crate from the `sys::aio` module.
Expand Down
102 changes: 102 additions & 0 deletions src/sys/ioctl/bsd.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/// The datatype used for the ioctl number
#[doc(hidden)]
pub type ioctl_num_type = ::libc::c_ulong;
/// The datatype used for the 3rd argument
#[doc(hidden)]
pub type ioctl_param_type = ::libc::c_int;

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 passes an integer
///
/// This is equivalent to the `_IOWINT()` 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_int!()` directly.
#[macro_export]
macro_rules! request_code_write_int {
($g:expr, $n:expr) => (ioc!($crate::sys::ioctl::VOID, $g, $n, ::std::mem::size_of::<$crate::libc::c_int>()))
}

/// 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))
}
71 changes: 48 additions & 23 deletions src/sys/ioctl/platform/linux.rs → src/sys/ioctl/linux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ pub type ioctl_num_type = ::libc::c_int;
#[cfg(not(any(target_os = "android", target_env = "musl")))]
#[doc(hidden)]
pub type ioctl_num_type = ::libc::c_ulong;
/// The datatype used for the 3rd argument
#[doc(hidden)]
pub type ioctl_param_type = ::libc::c_ulong;

#[doc(hidden)]
pub const NRBITS: ioctl_num_type = 8;
Expand All @@ -25,17 +28,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",
Expand Down Expand Up @@ -86,30 +78,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))
}
Loading

0 comments on commit 13f66d0

Please sign in to comment.