diff options
author | Carl Lerche <me@carllerche.com> | 2015-08-21 11:34:02 -0700 |
---|---|---|
committer | Carl Lerche <me@carllerche.com> | 2015-08-21 11:34:02 -0700 |
commit | 573e6a5753be415de2bbcfaedd7cfe4cb56d1822 (patch) | |
tree | b2e9aea13b2cb3c24165da8601ef12f18ebd24d9 | |
parent | bd265fd8f47142e565294258abb95223f195e96d (diff) | |
parent | e9d9a328042b4a247715790a4141a8addf28ddb8 (diff) | |
download | nix-573e6a5753be415de2bbcfaedd7cfe4cb56d1822.zip |
Merge remote-tracking branch 'posborne/ioctl-rework'
-rw-r--r-- | Cargo.toml | 4 | ||||
-rw-r--r-- | src/lib.rs | 3 | ||||
-rw-r--r-- | src/sys/epoll.rs | 36 | ||||
-rw-r--r-- | src/sys/event.rs | 35 | ||||
-rw-r--r-- | src/sys/ioctl.rs | 224 | ||||
-rw-r--r-- | src/sys/ioctl/mod.rs | 115 | ||||
-rw-r--r-- | src/sys/ioctl/platform/dragonfly.rs | 0 | ||||
-rw-r--r-- | src/sys/ioctl/platform/freebsd.rs | 0 | ||||
-rw-r--r-- | src/sys/ioctl/platform/ios.rs | 0 | ||||
-rw-r--r-- | src/sys/ioctl/platform/linux.rs | 200 | ||||
-rw-r--r-- | src/sys/ioctl/platform/macos.rs | 0 | ||||
-rw-r--r-- | src/sys/ioctl/platform/openbsd.rs | 0 | ||||
-rw-r--r-- | src/sys/stat.rs | 8 | ||||
-rw-r--r-- | test/sys/test_ioctl.rs | 36 | ||||
-rw-r--r-- | test/test.rs | 1 |
15 files changed, 346 insertions, 316 deletions
@@ -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" @@ -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; |