summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Lerche <me@carllerche.com>2015-08-21 11:34:02 -0700
committerCarl Lerche <me@carllerche.com>2015-08-21 11:34:02 -0700
commit573e6a5753be415de2bbcfaedd7cfe4cb56d1822 (patch)
treeb2e9aea13b2cb3c24165da8601ef12f18ebd24d9
parentbd265fd8f47142e565294258abb95223f195e96d (diff)
parente9d9a328042b4a247715790a4141a8addf28ddb8 (diff)
downloadnix-573e6a5753be415de2bbcfaedd7cfe4cb56d1822.zip
Merge remote-tracking branch 'posborne/ioctl-rework'
-rw-r--r--Cargo.toml4
-rw-r--r--src/lib.rs3
-rw-r--r--src/sys/epoll.rs36
-rw-r--r--src/sys/event.rs35
-rw-r--r--src/sys/ioctl.rs224
-rw-r--r--src/sys/ioctl/mod.rs115
-rw-r--r--src/sys/ioctl/platform/dragonfly.rs0
-rw-r--r--src/sys/ioctl/platform/freebsd.rs0
-rw-r--r--src/sys/ioctl/platform/ios.rs0
-rw-r--r--src/sys/ioctl/platform/linux.rs200
-rw-r--r--src/sys/ioctl/platform/macos.rs0
-rw-r--r--src/sys/ioctl/platform/openbsd.rs0
-rw-r--r--src/sys/stat.rs8
-rw-r--r--test/sys/test_ioctl.rs36
-rw-r--r--test/test.rs1
15 files changed, 346 insertions, 316 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 7bab2e12..496485c1 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -2,7 +2,7 @@
name = "nix"
description = "Rust friendly bindings to *nix APIs"
-version = "0.3.9"
+version = "0.4.0"
authors = ["Carl Lerche <me@carllerche.com>"]
homepage = "https://github.com/carllerche/nix-rust"
license = "MIT"
@@ -20,7 +20,7 @@ execvpe = []
[dependencies]
libc = "0.1.10"
-bitflags = "0.1.1"
+bitflags = "0.3.2"
[dev-dependencies]
rand = "0.3.8"
diff --git a/src/lib.rs b/src/lib.rs
index b63920bd..f3285762 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -5,6 +5,9 @@
#![crate_name = "nix"]
#![cfg(unix)]
#![allow(non_camel_case_types)]
+// latest bitflags triggers a rustc bug with cross-crate macro expansions causing dead_code
+// warnings even though the macro expands into something with allow(dead_code)
+#![allow(dead_code)]
#![deny(warnings)]
#[macro_use]
diff --git a/src/sys/epoll.rs b/src/sys/epoll.rs
index d510faf3..0e9c5536 100644
--- a/src/sys/epoll.rs
+++ b/src/sys/epoll.rs
@@ -1,7 +1,6 @@
use {Error, Result, from_ffi};
use errno::Errno;
use libc::c_int;
-use std::fmt;
use std::os::unix::io::RawFd;
mod ffi {
@@ -35,41 +34,6 @@ bitflags!(
}
);
-impl fmt::Debug for EpollEventKind {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- let variants = [
- (EPOLLIN, "EPOLLIN"),
- (EPOLLPRI, "EPOLLPRI"),
- (EPOLLOUT, "EPOLLOUT"),
- (EPOLLRDNORM, "EPOLLRDNORM"),
- (EPOLLRDBAND, "EPOLLRDBAND"),
- (EPOLLWRNORM, "EPOLLWRNORM"),
- (EPOLLWRBAND, "EPOLLWRBAND"),
- (EPOLLMSG, "EPOLLMSG"),
- (EPOLLERR, "EPOLLERR"),
- (EPOLLHUP, "EPOLLHUP"),
- (EPOLLRDHUP, "EPOLLRDHUP"),
- (EPOLLWAKEUP, "EPOLLWAKEUP"),
- (EPOLLONESHOT, "EPOLLONESHOT"),
- (EPOLLET, "EPOLLET")];
-
- let mut first = true;
-
- for &(val, name) in variants.iter() {
- if self.contains(val) {
- if first {
- first = false;
- try!(write!(fmt, "{}", name));
- } else {
- try!(write!(fmt, "|{}", name));
- }
- }
- }
-
- Ok(())
- }
-}
-
#[derive(Clone, Copy)]
#[repr(C)]
pub enum EpollOp {
diff --git a/src/sys/event.rs b/src/sys/event.rs
index 62be0af2..e4297c04 100644
--- a/src/sys/event.rs
+++ b/src/sys/event.rs
@@ -4,7 +4,6 @@
use {Error, Result};
use errno::Errno;
use libc::{timespec, time_t, c_int, c_long, uintptr_t};
-use std::fmt;
use std::os::unix::io::RawFd;
pub use self::ffi::kevent as KEvent;
@@ -75,40 +74,6 @@ bitflags!(
}
);
-impl fmt::Debug for EventFlag {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- let mut one = false;
- let flags = [
- (EV_ADD, "EV_ADD"),
- (EV_DELETE, "EV_DELETE"),
- (EV_ENABLE, "EV_ENABLE"),
- (EV_DISABLE, "EV_DISABLE"),
- (EV_RECEIPT, "EV_RECEIPT"),
- (EV_ONESHOT, "EV_ONESHOT"),
- (EV_CLEAR, "EV_CLEAR"),
- (EV_DISPATCH, "EV_DISPATCH"),
- (EV_SYSFLAGS, "EV_SYSFLAGS"),
- (EV_FLAG0, "EV_FLAG0"),
- (EV_FLAG1, "EV_FLAG1"),
- (EV_EOF, "EV_EOF")];
-
- for &(flag, msg) in flags.iter() {
- if self.contains(flag) {
- if one { try!(write!(fmt, " | ")) }
- try!(write!(fmt, "{}", msg));
-
- one = true
- }
- }
-
- if !one {
- try!(write!(fmt, "<None>"));
- }
-
- Ok(())
- }
-}
-
bitflags!(
flags FilterFlag: u32 {
const NOTE_TRIGGER = 0x01000000,
diff --git a/src/sys/ioctl.rs b/src/sys/ioctl.rs
deleted file mode 100644
index 0a2a3451..00000000
--- a/src/sys/ioctl.rs
+++ /dev/null
@@ -1,224 +0,0 @@
-//! Provide helpers for making ioctl system calls
-//!
-//! # Overview of IOCTLs
-//!
-//! The `ioctl` system call is a widely support system
-//! call on *nix systems providing access to functions
-//! and data that do not fit nicely into the standard
-//! read and write operations on a file itself. It is
-//! common to see ioctls used for the following purposes:
-//!
-//! * Provide read/write access to out-of-band data related
-//! to a device such as configuration (for instance, setting
-//! serial port options)
-//! * Provide a mechanism for performing full-duplex data
-//! transfers (for instance, xfer on SPI devices).
-//! * Provide access to control functions on a device (for example,
-//! on Linux you can send commands like pause, resume, and eject
-//! to the CDROM device.
-//! * Do whatever else the device driver creator thought made most sense.
-//!
-//! Ioctls are synchronous system calls and are similar to read and
-//! write calls in that regard.
-//!
-//! The prototype for the ioctl system call in libc is as follows:
-//!
-//! ```c
-//! int ioctl(int fd, unsigned long request, ...);
-//! ```
-//!
-//! Typically, an ioctl takes 3 parameters as arguments:
-//!
-//! 1. An open file descriptor, `fd`.
-//! 2. An device-dependennt request code or operation. This request
-//! code is referred to as `op` in this module.
-//! 3. Either a pointer to a location in memory or an integer. This
-//! number of pointer may either be used by the kernel or written
-//! to by the kernel depending on how the operation is documented
-//! to work.
-//!
-//! The `op` request code is essentially an arbitrary integer having
-//! a device-driver specific meaning. Over time, it proved difficult
-//! for various driver implementors to use this field sanely, so a
-//! convention with macros was introduced to the Linux Kernel that
-//! is used by most newer drivers. See
-//! https://github.com/torvalds/linux/blob/master/Documentation/ioctl/ioctl-number.txt
-//! for additional details. The macros exposed by the kernel for
-//! consumers are implemented in this module and may be used to
-//! instead of calls like `_IOC`, `_IO`, `_IOR`, and `_IOW`.
-//!
-//! # Interface Overview
-//!
-//! This ioctl module seeks to tame the ioctl beast by providing
-//! a set of safer (although not safe) functions
-//! implementing the most common ioctl access patterns.
-//!
-//! The most common access patterns for ioctls are as follows:
-//!
-//! 1. `read`: A pointer is provided to the kernel which is populated
-//! with a value containing the "result" of the operation. The
-//! result may be an integer or structure. The kernel may also
-//! read values from the provided pointer (usually a structure).
-//! 2. `write`: A pointer is provided to the kernel containing values
-//! that the kernel will read in order to perform the operation.
-//! 3. `execute`: The operation is passed to the kernel but no
-//! additional pointer is passed. The operation is enough
-//! and it either succeeds or results in an error.
-//!
-//! Where appropriate, versions of these interface function are provided
-//! taking either refernces or pointers. The pointer versions are
-//! necessary for cases (notably slices) where a reference cannot
-//! be generically cast to a pointer.
-
-use {Error, Result, errno};
-use libc::{c_int, c_ulong};
-use libc::funcs::bsd44::ioctl as libc_ioctl;
-use std::mem;
-use std::os::unix::io::RawFd;
-
-pub type ioctl_op_t = c_ulong;
-
-// the libc definiton of the 'op' type is platform dependent
-#[cfg(any(target_os = "macos",
- target_os = "ios",
- target_os = "freebsd",
- target_os = "openbsd",
- target_os = "dragonfly"))]
-type os_ioctl_op_t = c_ulong;
-
-#[cfg(any(target_os = "linux", target_os = "android"))]
-type os_ioctl_op_t = c_int;
-
-// low-level ioctl functions and definitions matching the
-// macros provided in ioctl.h from the kernel
-const IOC_NRBITS: u32 = 8;
-const IOC_TYPEBITS: u32 = 8;
-const IOC_SIZEBITS: u32 = 14;
-// const IOC_DIRBITS: u32 = 2;
-
-const IOC_NRSHIFT: u32 = 0;
-const IOC_TYPESHIFT: u32 = IOC_NRSHIFT + IOC_NRBITS;
-const IOC_SIZESHIFT: u32 = IOC_TYPESHIFT + IOC_TYPEBITS;
-const IOC_DIRSHIFT: u32 = IOC_SIZESHIFT + IOC_SIZEBITS;
-
-/// Flags indicating the direction of the ioctl operation
-/// for ioctls using modern operation conventions
-bitflags! {
- flags IoctlDirFlags: u8 {
- /// Indicates that the ioctl data pointer is not used
- const IOC_NONE = 0x00,
- /// Indicates that the ioctl data pointer contains data that
- /// will be consumed by the operating system
- const IOC_WRITE = 0x01,
- /// Indicates tha the ioctl data pointer contains data that
- /// will be populated by the operating system to be consumed
- /// by userspace
- const IOC_READ = 0x02,
- }
-}
-
-/// Build an ioctl op with the provide parameters. This is a helper
-/// function for IOCTLs in the Linux kernel using the newer conventions
-/// for IOCTLs operations. Many ioctls do not use this newer convention
-/// and the constants for those should just be used as-is.
-///
-/// This provides the same functionality as the Linux `_IOC` macro.
-pub fn op(dir: IoctlDirFlags, ioctl_type: u8, nr: u8, size: usize) -> ioctl_op_t {
- // actual number will always fit in 32 bits, but ioctl() expects
- // an unsigned long for the op
- let size_to_use: u32 = if size < (1 << IOC_SIZEBITS) { size as u32 } else { 0 };
- (((dir.bits as u32) << IOC_DIRSHIFT) |
- ((ioctl_type as u32) << IOC_TYPESHIFT) |
- ((nr as u32) << IOC_NRSHIFT) |
- ((size_to_use) << IOC_SIZESHIFT)) as ioctl_op_t
-}
-
-/// Build an op indicating that the data pointer is not used.
-/// That is, the command itself is sufficient.
-///
-/// This provides the same functionality the Linux `_IO` macro.
-pub fn op_none(ioctl_type: u8, nr: u8) -> ioctl_op_t {
- op(IOC_NONE, ioctl_type, nr, 0)
-}
-
-/// Build an op indicating that the data pointer will be populated
-/// with data from the kernel
-///
-/// This provides the same functionality as the Linux `_IOR` macro.
-pub fn op_read(ioctl_type: u8, nr: u8, size: usize) -> ioctl_op_t {
- op(IOC_READ, ioctl_type, nr, size)
-}
-
-/// Build an op indicating that the data pointer contains data
-/// to be consumed by the kernel (and not written to).
-///
-/// This provides the same functionality as the Linux `_IOW` macro.
-pub fn op_write(ioctl_type: u8, nr: u8, size: usize) -> ioctl_op_t {
- op(IOC_WRITE, ioctl_type, nr, size)
-}
-
-/// Build an op indicating that the data pointer both contains
-/// data to be consumed by the kernel and contains fields that
-/// will be populated by the kernel.
-///
-/// This provides the same functionality as the Linux `_IOWR` macro.
-pub fn op_read_write(ioctl_type: u8, nr: u8, size: usize) -> ioctl_op_t {
- op(IOC_WRITE | IOC_READ, ioctl_type, nr, size)
-}
-
-fn convert_ioctl_res(res: c_int) -> Result<c_int> {
- if res < 0 {
- return Err(Error::Sys(errno::Errno::last()))
- }
- Ok(res) // res may length or similar useful to caller
-}
-
-/// Ioctl call that is expected to return a result
-/// but which does not take any additional arguments on the input side
-///
-/// This function will allocate allocate space for and returned an owned
-/// reference to the result.
-pub unsafe fn read<T>(fd: RawFd, op: ioctl_op_t) -> Result<T> {
- // allocate memory for the result (should get a value from kernel)
- let mut dst: T = mem::zeroed();
- let dst_ptr: *mut T = &mut dst;
- try!(read_into_ptr(fd, op, dst_ptr));
- Ok(dst)
-}
-
-/// Ioctl where the result from the kernel will be written to the
-/// provided reference
-///
-/// The refernced data may also contain information that will be consumed
-/// by the kernel.
-pub unsafe fn read_into<T>(fd: RawFd, op: ioctl_op_t, data: &mut T) -> Result<c_int> {
- read_into_ptr(fd, op, data as *mut T)
-}
-
-/// Ioctl where the result from the kernel will be written to the
-/// provided pointer
-///
-/// The refernced data may also contain information that will be consumed
-/// by the kernel.
-pub unsafe fn read_into_ptr<T>(fd: RawFd, op: ioctl_op_t, data_ptr: *mut T) -> Result<c_int> {
- convert_ioctl_res(libc_ioctl(fd, op as os_ioctl_op_t, data_ptr))
-}
-
-/// Ioctl call that sends a value to the kernel but
-/// does not return anything (pure side effect).
-pub unsafe fn write<T>(fd: RawFd, op: ioctl_op_t, data: &T) -> Result<c_int> {
- write_ptr(fd, op, data as *const T)
-}
-
-/// Ioctl call that sends a value to the kernel but
-/// does not return anything (pure side effect).
-pub unsafe fn write_ptr<T>(fd: RawFd, op: ioctl_op_t, data: *const T) -> Result<c_int> {
- convert_ioctl_res(libc_ioctl(fd, op as os_ioctl_op_t, data as *const T))
-}
-
-/// Ioctl call for which no data pointer is provided to the kernel.
-/// That is, the kernel has sufficient information about what to
-/// do based on the op alone.
-pub fn execute(fd: RawFd, op: ioctl_op_t) -> Result<c_int> {
- convert_ioctl_res(unsafe { libc_ioctl(fd, op as os_ioctl_op_t) })
-}
diff --git a/src/sys/ioctl/mod.rs b/src/sys/ioctl/mod.rs
new file mode 100644
index 00000000..a4e51cbd
--- /dev/null
+++ b/src/sys/ioctl/mod.rs
@@ -0,0 +1,115 @@
+//! Provide helpers for making ioctl system calls
+//!
+//! Currently supports Linux on all architectures. Other platforms welcome!
+//!
+//! This library is pretty low-level and messy. `ioctl` is not fun.
+//!
+//! What is an `ioctl`?
+//! ===================
+//!
+//! The `ioctl` syscall is the grab-bag syscall on POSIX systems. Don't want
+//! to add a new syscall? Make it an `ioctl`! `ioctl` refers to both the syscall,
+//! and the commands that can be send with it. `ioctl` stands for "IO control",
+//! and the commands are always sent to a file descriptor.
+//!
+//! It is common to see `ioctl`s used for the following purposes:
+//!
+//! * Provide read/write access to out-of-band data related
+//! to a device such as configuration (for instance, setting
+//! serial port options)
+//! * Provide a mechanism for performing full-duplex data
+//! transfers (for instance, xfer on SPI devices).
+//! * Provide access to control functions on a device (for example,
+//! on Linux you can send commands like pause, resume, and eject
+//! to the CDROM device.
+//! * Do whatever else the device driver creator thought made most sense.
+//!
+//! `ioctl`s are synchronous system calls and are similar to read and
+//! write calls in that regard.
+//!
+//! What does this module support?
+//! ===============================
+//!
+//! This library provides the `ioctl!` macro, for binding `ioctl`s. It also tries
+//! to bind every `ioctl` supported by the system with said macro, but
+//! some `ioctl`s requires some amount of manual work (usually by
+//! providing `struct` declaration) that this library does not support yet.
+//!
+//! Additionally, in `etc`, there are scripts for scraping system headers for
+//! `ioctl` definitions, and generating calls to `ioctl!` corresponding to them.
+//!
+//! How do I get the magic numbers?
+//! ===============================
+//!
+//! For Linux, look at your system's headers. For example, `/usr/include/linxu/input.h` has a lot
+//! of lines defining macros which use `_IOR`, `_IOW`, `_IOC`, and `_IORW`. These macros
+//! correspond to the `ior!`, `iow!`, `ioc!`, and `iorw!` macros defined in this crate.
+//! Additionally, there is the `ioctl!` macro for creating a wrapper around `ioctl` that is
+//! somewhat more type-safe.
+//!
+//! Most `ioctl`s have no or little documentation. You'll need to scrounge through
+//! the source to figure out what they do and how they should be used.
+//!
+//! # Interface Overview
+//!
+//! This ioctl module seeks to tame the ioctl beast by providing a set of safer (although not safe)
+//! functions implementing the most common ioctl access patterns.
+//!
+//! The most common access patterns for ioctls are as follows:
+//!
+//! 1. `read`: A pointer is provided to the kernel which is populated
+//! with a value containing the "result" of the operation. The
+//! result may be an integer or structure. The kernel may also
+//! read values from the provided pointer (usually a structure).
+//! 2. `write`: A pointer is provided to the kernel containing values
+//! that the kernel will read in order to perform the operation.
+//! 3. `execute`: The operation is passed to the kernel but no
+//! additional pointer is passed. The operation is enough
+//! and it either succeeds or results in an error.
+//!
+//! Where appropriate, versions of these interface function are provided
+//! taking either refernces or pointers. The pointer versions are
+//! necessary for cases (notably slices) where a reference cannot
+//! be generically cast to a pointer.
+
+#[cfg(any(target_os = "linux", target_os = "android"))]
+#[path = "platform/linux.rs"]
+#[macro_use]
+mod platform;
+
+#[cfg(target_os = "macos")]
+#[path = "platform/macos.rs"]
+#[macro_use]
+mod platform;
+
+#[cfg(target_os = "ios")]
+#[path = "platform/ios.rs"]
+#[macro_use]
+mod platform;
+
+#[cfg(target_os = "freebsd")]
+#[path = "platform/freebsd.rs"]
+#[macro_use]
+mod platform;
+
+#[cfg(target_os = "openbsd")]
+#[path = "platform/openbsd.rs"]
+#[macro_use]
+mod platform;
+
+#[cfg(target_os = "dragonfly")]
+#[path = "platform/dragonfly.rs"]
+#[macro_use]
+mod platform;
+
+pub use self::platform::*;
+
+// liblibc has the wrong decl for linux :| hack until #26809 lands.
+extern "C" {
+ #[doc(hidden)]
+ pub fn ioctl(fd: libc::c_int, req: libc::c_ulong, ...) -> libc::c_int;
+}
+
+/// A hack to get the macros to work nicely.
+#[doc(hidden)]
+pub use ::libc as libc;
diff --git a/src/sys/ioctl/platform/dragonfly.rs b/src/sys/ioctl/platform/dragonfly.rs
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/sys/ioctl/platform/dragonfly.rs
diff --git a/src/sys/ioctl/platform/freebsd.rs b/src/sys/ioctl/platform/freebsd.rs
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/sys/ioctl/platform/freebsd.rs
diff --git a/src/sys/ioctl/platform/ios.rs b/src/sys/ioctl/platform/ios.rs
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/sys/ioctl/platform/ios.rs
diff --git a/src/sys/ioctl/platform/linux.rs b/src/sys/ioctl/platform/linux.rs
new file mode 100644
index 00000000..71b63d3a
--- /dev/null
+++ b/src/sys/ioctl/platform/linux.rs
@@ -0,0 +1,200 @@
+#[doc(hidden)]
+pub const NRBITS: u32 = 8;
+#[doc(hidden)]
+pub const TYPEBITS: u32 = 8;
+
+#[cfg(any(target_arch = "mips", target_arch = "powerpc"))]
+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;
+}
+
+#[cfg(not(any(target_arch = "powerpc", target_arch = "mips", target_arch = "x86", target_arch = "arm", target_arch = "x86_64", target_arch = "aarch64")))]
+use this_arch_not_supported;
+
+// "Generic" ioctl protocol
+#[cfg(any(target_arch = "x86", target_arch = "arm", 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;
+}
+
+#[doc(hidden)]
+pub use self::consts::*;
+
+#[doc(hidden)]
+pub const NRSHIFT: u32 = 0;
+#[doc(hidden)]
+pub const TYPESHIFT: u32 = NRSHIFT + NRBITS as u32;
+#[doc(hidden)]
+pub const SIZESHIFT: u32 = TYPESHIFT + TYPEBITS as u32;
+#[doc(hidden)]
+pub const DIRSHIFT: u32 = SIZESHIFT + SIZEBITS as u32;
+
+#[doc(hidden)]
+pub const NRMASK: u32 = (1 << NRBITS) - 1;
+#[doc(hidden)]
+pub const TYPEMASK: u32 = (1 << TYPEBITS) - 1;
+#[doc(hidden)]
+pub const SIZEMASK: u32 = (1 << SIZEBITS) - 1;
+#[doc(hidden)]
+pub const DIRMASK: u32 = (1 << DIRBITS) - 1;
+
+/// Encode an ioctl command.
+#[macro_export]
+macro_rules! ioc {
+ ($dir:expr, $ty:expr, $nr:expr, $sz:expr) => (
+ (($dir as u32) << $crate::sys::ioctl::DIRSHIFT) |
+ (($ty as u32) << $crate::sys::ioctl::TYPESHIFT) |
+ (($nr as u32) << $crate::sys::ioctl::NRSHIFT) |
+ (($sz as u32) << $crate::sys::ioctl::SIZESHIFT))
+}
+
+/// Encode an ioctl command that has no associated data.
+#[macro_export]
+macro_rules! io {
+ ($ty:expr, $nr:expr) => (ioc!($crate::sys::ioctl::NONE, $ty, $nr, 0))
+}
+
+/// Encode an ioctl command that reads.
+#[macro_export]
+macro_rules! ior {
+ ($ty:expr, $nr:expr, $sz:expr) => (ioc!($crate::sys::ioctl::READ, $ty, $nr, $sz))
+}
+
+/// Encode an ioctl command that writes.
+#[macro_export]
+macro_rules! iow {
+ ($ty:expr, $nr:expr, $sz:expr) => (ioc!($crate::sys::ioctl::WRITE, $ty, $nr, $sz))
+}
+
+/// Encode an ioctl command that both reads and writes.
+#[macro_export]
+macro_rules! iorw {
+ ($ty:expr, $nr:expr, $sz:expr) => (ioc!($crate::sys::ioctl::READ | $crate::sys::ioctl::WRITE, $ty, $nr, $sz))
+}
+
+/// Convert raw ioctl return value to a Nix result
+#[macro_export]
+macro_rules! convert_ioctl_res {
+ ($w:expr) => (
+ {
+ let res = $w;
+ if res < 0 {
+ return Err($crate::Error::Sys($crate::errno::Errno::last()))
+ }
+ Ok(res) // res may contain useful information for user
+ }
+ );
+}
+
+/// Declare a wrapper function around an ioctl.
+#[macro_export]
+macro_rules! ioctl {
+ (bad $name:ident with $nr:expr) => (
+ unsafe fn $name(fd: $crate::sys::ioctl::libc::c_int,
+ data: *mut u8)
+ -> $crate::Result<$crate::sys::ioctl::libc::c_int> {
+ convert_ioctl_res!($crate::sys::ioctl::ioctl(fd, $nr as $crate::sys::ioctl::libc::c_ulong, data))
+ }
+ );
+ (none $name:ident with $ioty:expr, $nr:expr) => (
+ unsafe fn $name(fd: $crate::sys::ioctl::libc::c_int)
+ -> $crate::Result<$crate::sys::ioctl::libc::c_int> {
+ convert_ioctl_res!($crate::sys::ioctl::ioctl(fd, io!($ioty, $nr) as $crate::sys::ioctl::libc::c_ulong))
+ }
+ );
+ (read $name:ident with $ioty:expr, $nr:expr; $ty:ty) => (
+ unsafe fn $name(fd: $crate::sys::ioctl::libc::c_int,
+ val: *mut $ty)
+ -> $crate::Result<$crate::sys::ioctl::libc::c_int> {
+ convert_ioctl_res!($crate::sys::ioctl::ioctl(fd, ior!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::libc::c_ulong, val))
+ }
+ );
+ (write $name:ident with $ioty:expr, $nr:expr; $ty:ty) => (
+ unsafe fn $name(fd: $crate::sys::ioctl::libc::c_int,
+ val: *const $ty)
+ -> $crate::Result<$crate::sys::ioctl::libc::c_int> {
+ convert_ioctl_res!($crate::sys::ioctl::ioctl(fd, iow!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::libc::c_ulong, val))
+ }
+ );
+ (readwrite $name:ident with $ioty:expr, $nr:expr; $ty:ty) => (
+ unsafe fn $name(fd: $crate::sys::ioctl::libc::c_int,
+ val: *mut $ty)
+ -> $crate::Result<$crate::sys::ioctl::libc::c_int> {
+ convert_ioctl_res!($crate::sys::ioctl::ioctl(fd, iorw!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::libc::c_ulong, val))
+ }
+ );
+ (read buf $name:ident with $ioty:expr, $nr:expr; $ty:ty) => (
+ unsafe fn $name(fd: $crate::sys::ioctl::libc::c_int,
+ val: *mut $ty,
+ len: usize)
+ -> $crate::Result<$crate::sys::ioctl::libc::c_int> {
+ convert_ioctl_res!($crate::sys::ioctl::ioctl(fd, ior!($ioty, $nr, len) as $crate::sys::ioctl::libc::c_ulong, val))
+ }
+ );
+ (write buf $name:ident with $ioty:expr, $nr:expr; $ty:ty) => (
+ unsafe fn $name(fd: $crate::sys::ioctl::libc::c_int,
+ val: *const $ty,
+ len: usize) -> $crate::Result<$crate::sys::ioctl::libc::c_int> {
+ convert_ioctl_res!($crate::sys::ioctl::ioctl(fd, iow!($ioty, $nr, len) as $crate::sys::ioctl::libc::c_ulong, val))
+ }
+ );
+ (readwrite buf $name:ident with $ioty:expr, $nr:expr; $ty:ty) => (
+ unsafe fn $name(fd: $crate::sys::ioctl::libc::c_int,
+ val: *const $ty,
+ len: usize)
+ -> $crate::Result<$crate::sys::ioctl::libc::c_int> {
+ convert_ioctl_res!($crate::sys::ioctl::ioctl(fd, iorw!($ioty, $nr, len) as $crate::sys::ioctl::libc::c_ulong, val))
+ }
+ );
+}
+
+/// Extracts the "direction" (read/write/none) from an encoded ioctl command.
+#[inline(always)]
+pub fn ioc_dir(nr: u32) -> u8 {
+ ((nr >> DIRSHIFT) & DIRMASK) as u8
+}
+
+/// Extracts the type from an encoded ioctl command.
+#[inline(always)]
+pub fn ioc_type(nr: u32) -> u32 {
+ (nr >> TYPESHIFT) & TYPEMASK
+}
+
+/// Extracts the ioctl number from an encoded ioctl command.
+#[inline(always)]
+pub fn ioc_nr(nr: u32) -> u32 {
+ (nr >> NRSHIFT) & NRMASK
+}
+
+/// Extracts the size from an encoded ioctl command.
+#[inline(always)]
+pub fn ioc_size(nr: u32) -> u32 {
+ ((nr >> SIZESHIFT) as u32) & SIZEMASK
+}
+
+#[doc(hidden)]
+pub const IN: u32 = (WRITE as u32) << DIRSHIFT;
+#[doc(hidden)]
+pub const OUT: u32 = (READ as u32) << DIRSHIFT;
+#[doc(hidden)]
+pub const INOUT: u32 = ((READ|WRITE) as u32) << DIRSHIFT;
+#[doc(hidden)]
+pub const SIZE_MASK: u32 = SIZEMASK << SIZESHIFT;
diff --git a/src/sys/ioctl/platform/macos.rs b/src/sys/ioctl/platform/macos.rs
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/sys/ioctl/platform/macos.rs
diff --git a/src/sys/ioctl/platform/openbsd.rs b/src/sys/ioctl/platform/openbsd.rs
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/sys/ioctl/platform/openbsd.rs
diff --git a/src/sys/stat.rs b/src/sys/stat.rs
index aee47a67..2a34d282 100644
--- a/src/sys/stat.rs
+++ b/src/sys/stat.rs
@@ -4,7 +4,7 @@ pub use libc::stat as FileStat;
use {Error, Result, NixPath, from_ffi};
use errno::Errno;
use libc::mode_t;
-use std::{fmt, mem};
+use std::mem;
use std::os::unix::io::RawFd;
mod ffi {
@@ -50,12 +50,6 @@ bitflags! {
}
}
-impl fmt::Debug for SFlag {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- write!(fmt, "SFlag {{ bits: {} }}", self.bits())
- }
-}
-
pub fn mknod<P: ?Sized + NixPath>(path: &P, kind: SFlag, perm: Mode, dev: dev_t) -> Result<()> {
let res = try!(path.with_nix_path(|cstr| {
unsafe {
diff --git a/test/sys/test_ioctl.rs b/test/sys/test_ioctl.rs
index 49f49206..94eca447 100644
--- a/test/sys/test_ioctl.rs
+++ b/test/sys/test_ioctl.rs
@@ -1,46 +1,58 @@
-use nix::sys::ioctl::*;
+#![allow(dead_code)]
+
+#![cfg(target_os = "linux")] // no ioctl support for osx yet
+
+// Simple tests to ensure macro generated fns compile
+ioctl!(bad do_bad with 0x1234);
+ioctl!(none do_none with 0, 0);
+ioctl!(read read_test with 0, 0; u32);
+ioctl!(write write_test with 0, 0; u64);
+ioctl!(readwrite readwrite_test with 0, 0; u64);
+ioctl!(read buf readbuf_test with 0, 0; u32);
+ioctl!(write buf writebuf_test with 0, 0; u32);
+ioctl!(readwrite buf readwritebuf_test with 0, 0; u32);
// See C code for source of values for op calculations:
// https://gist.github.com/posborne/83ea6880770a1aef332e
#[test]
fn test_op_none() {
- assert_eq!(op_none('q' as u8, 10), 0x0000710A);
- assert_eq!(op_none('a' as u8, 255), 0x000061FF);
+ assert_eq!(io!(b'q', 10), 0x0000710A);
+ assert_eq!(io!(b'a', 255), 0x000061FF);
}
#[test]
fn test_op_write() {
- assert_eq!(op_write('z' as u8, 10, 1), 0x40017A0A);
- assert_eq!(op_write('z' as u8, 10, 512), 0x42007A0A);
+ assert_eq!(iow!(b'z', 10, 1), 0x40017A0A);
+ assert_eq!(iow!(b'z', 10, 512), 0x42007A0A);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_op_write_64() {
- assert_eq!(op_write('z' as u8, 10, 1 << 32), 0x40007A0A);
+ assert_eq!(iow!(b'z', 10, (1 as u64) << 32), 0x40007A0A);
}
#[test]
fn test_op_read() {
- assert_eq!(op_read('z' as u8, 10, 1), 0x80017A0A);
- assert_eq!(op_read('z' as u8, 10, 512), 0x82007A0A);
+ assert_eq!(ior!(b'z', 10, 1), 0x80017A0A);
+ assert_eq!(ior!(b'z', 10, 512), 0x82007A0A);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_op_read_64() {
- assert_eq!(op_read('z' as u8, 10, 1 << 32), 0x80007A0A);
+ assert_eq!(ior!(b'z', 10, (1 as u64) << 32), 0x80007A0A);
}
#[test]
fn test_op_read_write() {
- assert_eq!(op_read_write('z' as u8, 10, 1), 0xC0017A0A);
- assert_eq!(op_read_write('z' as u8, 10, 512), 0xC2007A0A);
+ assert_eq!(iorw!(b'z', 10, 1), 0xC0017A0A);
+ assert_eq!(iorw!(b'z', 10, 512), 0xC2007A0A);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_op_read_write_64() {
- assert_eq!(op_read_write('z' as u8, 10, 1 << 32), 0xC0007A0A);
+ assert_eq!(iorw!(b'z', 10, (1 as u64) << 32), 0xC0007A0A);
}
diff --git a/test/test.rs b/test/test.rs
index 5a1edf55..cf60dfd7 100644
--- a/test/test.rs
+++ b/test/test.rs
@@ -1,3 +1,4 @@
+#[macro_use]
extern crate nix;
extern crate libc;
extern crate rand;