summaryrefslogtreecommitdiff
path: root/src/sys/ioctl/linux.rs
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 /src/sys/ioctl/linux.rs
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
Diffstat (limited to 'src/sys/ioctl/linux.rs')
-rw-r--r--src/sys/ioctl/linux.rs137
1 files changed, 137 insertions, 0 deletions
diff --git a/src/sys/ioctl/linux.rs b/src/sys/ioctl/linux.rs
new file mode 100644
index 00000000..e0d02ad4
--- /dev/null
+++ b/src/sys/ioctl/linux.rs
@@ -0,0 +1,137 @@
+/// The datatype used for the ioctl number
+#[cfg(any(target_os = "android", target_env = "musl"))]
+#[doc(hidden)]
+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;
+
+#[doc(hidden)]
+pub const NRBITS: ioctl_num_type = 8;
+#[doc(hidden)]
+pub const TYPEBITS: ioctl_num_type = 8;
+
+#[cfg(any(target_arch = "mips", target_arch = "mips64", target_arch = "powerpc", target_arch = "powerpc64"))]
+mod consts {
+ #[doc(hidden)]
+ pub const NONE: u8 = 1;
+ #[doc(hidden)]
+ pub const READ: u8 = 2;
+ #[doc(hidden)]
+ pub const WRITE: u8 = 4;
+ #[doc(hidden)]
+ pub const SIZEBITS: u8 = 13;
+ #[doc(hidden)]
+ pub const DIRBITS: u8 = 3;
+}
+
+// "Generic" ioctl protocol
+#[cfg(any(target_arch = "x86",
+ target_arch = "arm",
+ target_arch = "s390x",
+ target_arch = "x86_64",
+ target_arch = "aarch64"))]
+mod consts {
+ #[doc(hidden)]
+ pub const NONE: u8 = 0;
+ #[doc(hidden)]
+ pub const READ: u8 = 2;
+ #[doc(hidden)]
+ pub const WRITE: u8 = 1;
+ #[doc(hidden)]
+ pub const SIZEBITS: u8 = 14;
+ #[doc(hidden)]
+ pub const DIRBITS: u8 = 2;
+}
+
+pub use self::consts::*;
+
+#[doc(hidden)]
+pub const NRSHIFT: ioctl_num_type = 0;
+#[doc(hidden)]
+pub const TYPESHIFT: ioctl_num_type = NRSHIFT + NRBITS as ioctl_num_type;
+#[doc(hidden)]
+pub const SIZESHIFT: ioctl_num_type = TYPESHIFT + TYPEBITS as ioctl_num_type;
+#[doc(hidden)]
+pub const DIRSHIFT: ioctl_num_type = SIZESHIFT + SIZEBITS as ioctl_num_type;
+
+#[doc(hidden)]
+pub const NRMASK: ioctl_num_type = (1 << NRBITS) - 1;
+#[doc(hidden)]
+pub const TYPEMASK: ioctl_num_type = (1 << TYPEBITS) - 1;
+#[doc(hidden)]
+pub const SIZEMASK: ioctl_num_type = (1 << SIZEBITS) - 1;
+#[doc(hidden)]
+pub const DIRMASK: ioctl_num_type = (1 << DIRBITS) - 1;
+
+/// Encode an ioctl command.
+#[macro_export]
+#[doc(hidden)]
+macro_rules! ioc {
+ ($dir:expr, $ty:expr, $nr:expr, $sz:expr) => (
+ (($dir as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::DIRMASK) << $crate::sys::ioctl::DIRSHIFT) |
+ (($ty as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::TYPEMASK) << $crate::sys::ioctl::TYPESHIFT) |
+ (($nr as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::NRMASK) << $crate::sys::ioctl::NRSHIFT) |
+ (($sz as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::SIZEMASK) << $crate::sys::ioctl::SIZESHIFT))
+}
+
+/// 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 {
+ ($ty:expr, $nr:expr) => (ioc!($crate::sys::ioctl::NONE, $ty, $nr, 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 {
+ ($ty:expr, $nr:expr, $sz:expr) => (ioc!($crate::sys::ioctl::READ, $ty, $nr, $sz))
+}
+
+/// 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 {
+ ($ty:expr, $nr:expr, $sz:expr) => (ioc!($crate::sys::ioctl::WRITE, $ty, $nr, $sz))
+}
+
+/// 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 {
+ ($ty:expr, $nr:expr, $sz:expr) => (ioc!($crate::sys::ioctl::READ | $crate::sys::ioctl::WRITE, $ty, $nr, $sz))
+}