From 35e032ebb8f2ce1df4b88a0b1294c39d6509462d Mon Sep 17 00:00:00 2001 From: Jean Pierre Dudey Date: Wed, 25 Apr 2018 22:01:48 -0400 Subject: [PATCH] Refactor to use the `udev` library from crates.io. Signed-off-by: Jean Pierre Dudey --- Cargo.toml | 2 +- mio-udev/Cargo.toml | 4 +- mio-udev/src/lib.rs | 114 ++++++++++++++++--- tokio-udev/Cargo.toml | 5 +- tokio-udev/examples/usb_hotplug.rs | 19 ++-- tokio-udev/src/lib.rs | 144 +++++++++++++++++++++++- tokio-udev/src/monitor.rs | 78 ------------- udev-sys/Cargo.toml | 7 -- udev-sys/src/lib.rs | 127 ---------------------- udev/Cargo.toml | 9 -- udev/src/context.rs | 64 ----------- udev/src/device.rs | 82 -------------- udev/src/lib.rs | 15 --- udev/src/monitor.rs | 169 ----------------------------- 14 files changed, 250 insertions(+), 589 deletions(-) delete mode 100644 tokio-udev/src/monitor.rs delete mode 100644 udev-sys/Cargo.toml delete mode 100644 udev-sys/src/lib.rs delete mode 100644 udev/Cargo.toml delete mode 100644 udev/src/context.rs delete mode 100644 udev/src/device.rs delete mode 100644 udev/src/lib.rs delete mode 100644 udev/src/monitor.rs diff --git a/Cargo.toml b/Cargo.toml index 040d893..024f30b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,2 +1,2 @@ [workspace] -members = ["mio-udev", "tokio-udev", "udev-sys", "udev"] +members = ["mio-udev", "tokio-udev"] diff --git a/mio-udev/Cargo.toml b/mio-udev/Cargo.toml index 1506dbf..9e1684e 100644 --- a/mio-udev/Cargo.toml +++ b/mio-udev/Cargo.toml @@ -2,8 +2,10 @@ name = "mio-udev" version = "0.1.0" authors = ["Jean Pierre Dudey "] +license = "Apache-2.0/MIT" +description = "MIO support for udev device events." [dependencies] -udev = { path = "../udev", version = "0.1.0" } +udev = "0.2" mio = "0.6" libc = "0.2" diff --git a/mio-udev/src/lib.rs b/mio-udev/src/lib.rs index c8efc80..6d1fe95 100644 --- a/mio-udev/src/lib.rs +++ b/mio-udev/src/lib.rs @@ -1,31 +1,109 @@ #![cfg(target_os = "linux")] +//! # mio-udev +//! +//! This library implements abstractions around `udev` to make it usable +//! with `mio` event loop. +//! +//! # Usage +//! +//! First put the dependency on your crate's `Cargo.toml`. For example: +//! +//! ```toml +//! [dependencies] +//! mio-udev = "0.1" +//! ``` +//! +//! Then import it in your crate root as: +//! +//! ```rust +//! extern crate mio_udev; +//! ``` + extern crate udev; extern crate mio; extern crate libc; +pub use udev::{Attribute, Attributes, Context, Device, Event, Property, + Properties, Error as UdevError}; + mod util; use std::io; use std::os::unix::io::{AsRawFd, RawFd}; +use std::ffi::OsStr; use mio::{Ready, Poll, PollOpt, Token}; use mio::event::Evented; use mio::unix::EventedFd; -#[derive(Debug)] -pub struct MonitorIo { - monitor: udev::Monitor, +/// Monitors for device events. +/// +/// A monitor communicates with the kernel over a socket. Filtering events is +/// performed efficiently in the kernel, and only events that match the filters +/// are received by the socket. Filters must be setup before listening for +/// events. +pub struct MonitorBuilder { + builder: udev::MonitorBuilder, } -impl MonitorIo { - /// Creates a new monitor io object from an existing udev monitor. - /// - /// # Notes +impl MonitorBuilder { + /// Creates a new `MonitorSocket`. + #[inline(always)] + pub fn new(context: &Context) -> io::Result { + Ok(MonitorBuilder { builder: udev::MonitorBuilder::new(context)? }) + } + + /// Adds a filter that matches events for devices with the given subsystem. + #[inline(always)] + pub fn match_subsystem(&mut self, subsystem: T) -> io::Result<()> + where T: AsRef, + { + Ok(self.builder.match_subsystem::(subsystem)?) + } + + /// Adds a filter that matches events for devices with the given subsystem + /// and device type. + #[inline(always)] + pub fn match_subsystem_devtype(&mut self, + subsystem: T, + devtype: U) -> io::Result<()> + where T: AsRef, + U: AsRef, + { + Ok(self.builder.match_subsystem_devtype::(subsystem, devtype)?) + } + + /// Adds a filter that matches events for devices with the given tag. + #[inline(always)] + pub fn match_tag(&mut self, tag: T) -> io::Result<()> + where T: AsRef, + { + Ok(self.builder.match_tag::(tag)?) + } + + /// Removes all filters currently set on the monitor. + #[inline(always)] + pub fn clear_filters(&mut self) -> io::Result<()> { + Ok(self.builder.clear_filters()?) + } + + /// Listens for events matching the current filters. /// - /// It marks the file descriptor as `FD_CLOEXEC` and sets the `O_NONBLOCK` - /// flag. - pub fn from_monitor(monitor: udev::Monitor) -> io::Result { + /// This method consumes the `MonitorBuilder`. + pub fn listen(self) -> io::Result { + Ok(MonitorSocket::new(self.builder.listen()?)?) + } +} + +/// A wrapper around an `udev::MonitorSocket` that adds the required `mio` +/// functionality. +pub struct MonitorSocket { + monitor: udev::MonitorSocket, +} + +impl MonitorSocket { + fn new(monitor: udev::MonitorSocket) -> io::Result { use libc::{fcntl, F_GETFD, FD_CLOEXEC, F_SETFD, F_GETFL, F_SETFL, O_NONBLOCK}; use util::cvt; @@ -46,11 +124,7 @@ impl MonitorIo { unsafe { cvt(fcntl(fd, F_SETFL, r | O_NONBLOCK))? }; } - Ok(MonitorIo { monitor }) - } - - pub fn receive_device(&self) -> io::Result { - self.monitor.receive_device() + Ok(MonitorSocket { monitor }) } #[inline(always)] @@ -59,7 +133,7 @@ impl MonitorIo { } } -impl Evented for MonitorIo { +impl Evented for MonitorSocket { fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> { @@ -76,3 +150,11 @@ impl Evented for MonitorIo { EventedFd(&self.fd()).deregister(poll) } } + +impl Iterator for MonitorSocket { + type Item = Event; + + fn next(&mut self) -> Option { + self.monitor.next() + } +} diff --git a/tokio-udev/Cargo.toml b/tokio-udev/Cargo.toml index 358f5d5..56bf9c0 100644 --- a/tokio-udev/Cargo.toml +++ b/tokio-udev/Cargo.toml @@ -2,13 +2,14 @@ name = "tokio-udev" version = "0.1.0" authors = ["Jean Pierre Dudey "] +license = "Apache-2.0/MIT" +description = "MIO support for udev device events." [dependencies] libc = "0.2" -mio-udev = { path = "../mio-udev", version = "0.1.0" } mio = "0.6" -udev = { path = "../udev", version = "0.1.0" } +mio-udev = { path = "../mio-udev", version = "0.1" } futures = "0.1" tokio-reactor = "0.1" diff --git a/tokio-udev/examples/usb_hotplug.rs b/tokio-udev/examples/usb_hotplug.rs index 10f2bea..9fe3163 100644 --- a/tokio-udev/examples/usb_hotplug.rs +++ b/tokio-udev/examples/usb_hotplug.rs @@ -4,21 +4,16 @@ extern crate futures; use futures::{Future, stream::Stream}; -use tokio_udev::{USB_SUBSYSTEM, USB_DEVICE, UDEV_MONITOR}; +use tokio_udev::{Context, MonitorBuilder}; fn main() { - let monitor = tokio_udev::Builder::new() - .add_match(USB_SUBSYSTEM, USB_DEVICE) - .build(UDEV_MONITOR) - .expect("couldn't create monitor"); - - let hotplug_stream = monitor.for_each(|device| { - println!("====================="); - println!(" Usb HotPlug Event "); - println!("====================="); - println!("devpath: \"{:?}\"", device.get_devpath()?); - println!("action: \"{}\"", device.get_action()?); + let context = Context::new().unwrap(); + let mut builder = MonitorBuilder::new(&context).unwrap(); + builder.match_subsystem_devtype("usb", "usb_device").unwrap(); + let monitor = builder.listen().unwrap(); + let hotplug_stream = monitor.for_each(|_device| { + println!("Hotplug event!"); Ok(()) }) .map_err(|e| { diff --git a/tokio-udev/src/lib.rs b/tokio-udev/src/lib.rs index f7f3bbe..d006a8f 100644 --- a/tokio-udev/src/lib.rs +++ b/tokio-udev/src/lib.rs @@ -1,18 +1,150 @@ #![cfg(target_os = "linux")] -//! # tokio udev +//! # tokio-udev +//! +//! This library implements an stream of device events from `udev` +//! asynchronously. +//! +//! # Usage +//! +//! First put the dependency on your crate's `Cargo.toml`. For example: +//! +//! ```toml +//! [dependencies] +//! tokio-udev = "0.1" +//! ``` +//! +//! Then import it in your crate root as: +//! +//! ```rust +//! extern crate tokio_udev; +//! ``` extern crate libc; -extern crate udev; -extern crate mio_udev; extern crate mio; +extern crate mio_udev; extern crate futures; extern crate tokio_reactor; -mod monitor; +pub use mio_udev::{Attribute, Attributes, Context, Device, Event, Property, + Properties, UdevError}; + +use std::io; +use std::ffi::OsStr; +use std::sync::Mutex; + +use tokio_reactor::PollEvented; +use futures::{Async, Poll, stream::Stream}; + +/// Monitors for device events. +/// +/// A monitor communicates with the kernel over a socket. Filtering events is +/// performed efficiently in the kernel, and only events that match the filters +/// are received by the socket. Filters must be setup before listening for +/// events. +pub struct MonitorBuilder { + builder: mio_udev::MonitorBuilder, +} + +impl MonitorBuilder { + /// Creates a new `MonitorSocket`. + #[inline(always)] + pub fn new(context: &mio_udev::Context) -> io::Result { + Ok(MonitorBuilder { builder: mio_udev::MonitorBuilder::new(context)? }) + } + + /// Adds a filter that matches events for devices with the given subsystem. + #[inline(always)] + pub fn match_subsystem(&mut self, subsystem: T) -> io::Result<()> + where T: AsRef, + { + Ok(self.builder.match_subsystem::(subsystem)?) + } + + /// Adds a filter that matches events for devices with the given subsystem + /// and device type. + #[inline(always)] + pub fn match_subsystem_devtype(&mut self, + subsystem: T, + devtype: U) -> io::Result<()> + where T: AsRef, + U: AsRef, + { + Ok(self.builder.match_subsystem_devtype::(subsystem, devtype)?) + } + + /// Adds a filter that matches events for devices with the given tag. + #[inline(always)] + pub fn match_tag(&mut self, tag: T) -> io::Result<()> + where T: AsRef, + { + Ok(self.builder.match_tag::(tag)?) + } + + /// Removes all filters currently set on the monitor. + #[inline(always)] + pub fn clear_filters(&mut self) -> io::Result<()> { + Ok(self.builder.clear_filters()?) + } + + /// Listens for events matching the current filters. + /// + /// This method consumes the `MonitorBuilder`. + pub fn listen(self) -> io::Result { + Ok(MonitorSocket::new(self.builder.listen()?)) + } +} + +/// Asynchronous stream of device events. +pub struct MonitorSocket { + inner: Mutex, +} + +impl MonitorSocket { + fn new(monitor: mio_udev::MonitorSocket) -> MonitorSocket { + MonitorSocket { inner: Mutex::new(Inner::new(monitor)), } + } + + fn poll_receive(&mut self) -> Poll, io::Error> { + self.inner.lock().unwrap().poll_receive() + } +} + +unsafe impl Send for MonitorSocket {} +unsafe impl Sync for MonitorSocket {} + +struct Inner { + io: PollEvented, +} + +impl Inner { + fn new(monitor: mio_udev::MonitorSocket) -> Inner { + Inner { io: PollEvented::new(monitor), } + } + + fn poll_receive(&mut self) -> Poll, io::Error> { + if let Async::NotReady = self.io.poll_read_ready(mio::Ready::readable())? { + return Ok(Async::NotReady); + } + + match self.io.get_mut().next() { + Some(device) => Ok(Async::Ready(Some(device))), + None => { + self.io.clear_read_ready(mio::Ready::readable())?; + Ok(Async::NotReady) + }, + } + + } +} -pub use udev::{Subsystem, DeviceType, MonitorName, USB_SUBSYSTEM, USB_DEVICE, UDEV_MONITOR}; +impl Stream for MonitorSocket { + type Item = mio_udev::Event; + type Error = io::Error; -pub use monitor::{Builder, Monitor}; + fn poll(&mut self) -> Poll, Self::Error> { + self.poll_receive() + } +} diff --git a/tokio-udev/src/monitor.rs b/tokio-udev/src/monitor.rs deleted file mode 100644 index 08bb0f0..0000000 --- a/tokio-udev/src/monitor.rs +++ /dev/null @@ -1,78 +0,0 @@ -use std::io; - -use {mio, udev, mio_udev}; -use tokio_reactor::PollEvented; -use futures::{Async, Poll, stream::Stream}; - -#[derive(Debug)] -pub struct Builder { - match_filters: Vec<(udev::Subsystem, udev::DeviceType)>, -} - -impl Builder { - pub fn new() -> Builder { - Builder { - match_filters: Vec::new(), - } - } - - pub fn add_match(mut self, - subsystem: udev::Subsystem, - devtype: udev::DeviceType) -> Builder { - self.match_filters.push((subsystem, devtype)); - self - } - - pub fn build(self, name: udev::MonitorName) -> io::Result { - let context = udev::Context::new(); - let monitor = udev::Monitor::new_from_netlink(&context, name); - - for filter in self.match_filters { - monitor.filter_add_match_subsystem_devtype(filter.0, filter.1)?; - } - - monitor.enable_receiving()?; - - Monitor::new(monitor) - } -} - -#[derive(Debug)] -pub struct Monitor { - io: PollEvented, -} - -impl Monitor { - pub fn new(monitor: udev::Monitor) -> io::Result { - let io = PollEvented::new(mio_udev::MonitorIo::from_monitor(monitor)?); - Ok(Monitor { io }) - } - - pub fn poll_receive(&self) -> Poll, io::Error> { - if let Async::NotReady = self.io.poll_read_ready(mio::Ready::readable())? { - return Ok(Async::NotReady); - } - - match self.io.get_ref().receive_device() { - Ok(device) => Ok(Async::Ready(Some(device))), - Err(e) => { - if e.kind() == io::ErrorKind::WouldBlock { - self.io.clear_read_ready(mio::Ready::readable())?; - Ok(Async::NotReady) - } else { - Err(e) - } - }, - } - - } -} - -impl Stream for Monitor { - type Item = udev::Device; - type Error = io::Error; - - fn poll(&mut self) -> Poll, Self::Error> { - self.poll_receive() - } -} diff --git a/udev-sys/Cargo.toml b/udev-sys/Cargo.toml deleted file mode 100644 index a24aba8..0000000 --- a/udev-sys/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "udev-sys" -version = "0.1.0" -authors = ["Jean Pierre Dudey "] - -[dependencies] -libc = "0.2" diff --git a/udev-sys/src/lib.rs b/udev-sys/src/lib.rs deleted file mode 100644 index bf28f8b..0000000 --- a/udev-sys/src/lib.rs +++ /dev/null @@ -1,127 +0,0 @@ -#![cfg(target_os = "linux")] -#![allow(non_camel_case_types)] - -extern crate libc; - -use libc::{c_void, c_char, c_int, c_ulonglong, dev_t}; - -pub type udev = c_void; - -#[link(name = "udev")] -extern "C" { - pub fn udev_new() -> *mut udev; - pub fn udev_ref(udev: *mut udev) -> *mut udev; - pub fn udev_unref(udev: *mut udev) -> *mut udev; -} - -pub type udev_monitor = c_void; - -#[link(name = "udev")] -extern "C" { - pub fn udev_monitor_new_from_netlink( - udev: *mut udev, - name: *const c_char, - ) -> *mut udev_monitor; - pub fn udev_monitor_ref(udev_monitor: *mut udev_monitor) -> *mut udev_monitor; - pub fn udev_monitor_unref(udev_monitor: *mut udev_monitor) -> *mut udev_monitor; -} - -#[link(name = "udev")] -extern "C" { - pub fn udev_monitor_filter_update(udev_monitor: *mut udev_monitor) -> c_int; - pub fn udev_monitor_filter_remove(udev_monitor: *mut udev_monitor) -> c_int; - pub fn udev_monitor_filter_add_match_subsystem_devtype( - udev_monitor: *mut udev_monitor, - subsytem: *const c_char, - devtype: *const c_char, - ) -> c_int; - pub fn udev_monitor_filter_add_match_tag( - udev_monitor: *mut udev_monitor, - tag: *const c_char - ) -> c_int; -} - -pub type udev_device = c_void; - -#[link(name = "udev")] -extern "C" { - pub fn udev_monitor_receive_device(udev_monitor: *mut udev_monitor) -> *mut udev_device; - pub fn udev_monitor_enable_receiving(udev_monitor: *mut udev_monitor) -> c_int; - pub fn udev_monitor_set_receive_buffer_size( - udev_monitor: *mut udev_monitor, - size: c_int, - ) -> c_int; - pub fn udev_monitor_get_fd(udev_monitor: *mut udev_monitor) -> c_int; -} - -#[link(name = "udev")] -extern "C" { - pub fn udev_device_new_from_syspath( - udev: *mut udev, - syspath: *const c_char, - ) -> *mut udev_device; - pub fn udev_device_new_from_devnum( - udev: *mut udev, - type_: c_char, - devnum: dev_t, - ) -> *mut udev_device; - pub fn udev_device_new_from_subsystem_sysname( - udev: *mut udev, - subsystem: *const c_char, - sysname: *const c_char, - ) -> *mut udev_device; - pub fn udev_device_new_from_device_id( - udev: *mut udev, - id: *const c_char, - ) -> *mut udev_device; - pub fn udev_device_new_from_environment(udev: *mut udev) -> *mut udev_device; - pub fn udev_device_ref(udev_device: *mut udev_device) -> *mut udev_device; - pub fn udev_device_unref(udev_device: *mut udev_device) -> *mut udev_device; -} - -pub type udev_list_entry = c_void; - -#[link(name = "udev")] -extern "C" { - pub fn udev_device_get_devpath(udev_device: *mut udev_device) -> *const c_char; - pub fn udev_device_get_subsystem(udev_device: *mut udev_device) -> *const c_char; - pub fn udev_device_get_devtype(udev_device: *mut udev_device) -> *const c_char; - pub fn udev_device_get_syspath(udev_device: *mut udev_device) -> *const c_char; - pub fn udev_device_get_sysname(udev_device: *mut udev_device) -> *const c_char; - pub fn udev_device_get_sysnum(udev_device: *mut udev_device) -> *const c_char; - pub fn udev_device_get_devnode(udev_device: *mut udev_device) -> *const c_char; - pub fn udev_device_get_is_initialized(udev_device: *mut udev_device) -> c_int; - pub fn udev_device_get_devlinks_list_entry( - udev_device: *mut udev_device - ) -> *mut udev_list_entry; - pub fn udev_device_get_properties_list_entry( - udev_device: *mut udev_device - ) -> *mut udev_list_entry; - pub fn udev_device_get_tags_list_entry( - udev_device: *mut udev_device - ) -> *mut udev_list_entry; - pub fn udev_device_get_sysattr_list_entry( - udev_device: *mut udev_device - ) -> *mut udev_list_entry; - pub fn udev_device_get_property_value( - udev_device: *mut udev_device, - key: *const c_char - ) -> *const c_char; - pub fn udev_device_get_driver(udev_device: *mut udev_device) -> *const c_char; - pub fn udev_device_get_devnum(udev_device: *mut udev_device) -> dev_t; - pub fn udev_device_get_action(udev_device: *mut udev_device) -> *const c_char; - pub fn udev_device_get_seqnum(udev_device: *mut udev_device) -> c_ulonglong; - pub fn udev_device_get_usec_since_initialized( - udev_device: *mut udev_device - ) -> c_ulonglong; - pub fn udev_device_get_sysattr_value( - udev_device: *mut udev_device, - sysattr: *const c_char - ) -> *const c_char; - pub fn udev_device_set_sysattr_value( - udev_device: *mut udev_device, - sysattr: *const c_char, - value: *mut c_char - ) -> c_int; - pub fn udev_device_has_tag(udev_device: *mut udev_device, tag: *const c_char) -> c_int; -} diff --git a/udev/Cargo.toml b/udev/Cargo.toml deleted file mode 100644 index 9011708..0000000 --- a/udev/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "udev" -version = "0.1.0" -authors = ["Jean Pierre Dudey "] - -[dependencies] -udev-sys = { path = "../udev-sys", version = "0.1" } -libc = "0.2" -log = "0.4" diff --git a/udev/src/context.rs b/udev/src/context.rs deleted file mode 100644 index 6850b3e..0000000 --- a/udev/src/context.rs +++ /dev/null @@ -1,64 +0,0 @@ -use {std::ptr, udev_sys}; - -/// Udev context. -/// -/// This is a ptr to the **udev** library context. This context is reference -/// counted internally so a call to `Context::clone` points to the same -/// `Context`. -#[derive(Debug)] -pub struct Context { - ptr: *mut udev_sys::udev, -} - -unsafe impl Send for Context {} -unsafe impl Sync for Context {} - -impl Context { - /// Creates a new udev context. - /// - /// # Panics - /// - /// This function panics if the returned context ptr is invalid. - pub fn new() -> Context { - trace!("creating new udev context, calling `udev_new`"); - let ptr = unsafe { udev_sys::udev_new() }; - if ptr == ptr::null_mut() { - panic!("udev_new returned `std::ptr::null_mut()`."); - } - - Context { - ptr, - } - } - - pub(crate) fn as_ptr(&self) -> *mut udev_sys::udev { - assert!(self.ptr != ptr::null_mut()); - self.ptr - } -} - -impl Clone for Context { - /// Increments the reference count. - fn clone(&self) -> Context { - trace!("incrementing udev context refence count, calling `udev_ref`"); - - assert!(self.ptr != ptr::null_mut()); - let ptr = unsafe { udev_sys::udev_ref(self.ptr) }; - assert!(ptr != ptr::null_mut()); - - Context { - ptr, - } - } -} - -impl Drop for Context { - /// Decrements the reference count, once it reaches 0 it's dropped. - fn drop(&mut self) { - trace!("dropping udev context, calling `udev_unref`"); - - if self.ptr != ptr::null_mut() { - unsafe { udev_sys::udev_unref(self.ptr) }; - } - } -} diff --git a/udev/src/device.rs b/udev/src/device.rs deleted file mode 100644 index e3c28c0..0000000 --- a/udev/src/device.rs +++ /dev/null @@ -1,82 +0,0 @@ -use std::{io, ptr, path::PathBuf, str::FromStr}; - -use udev_sys; - -macro_rules! call_cstring { - ($call:expr) => { - { - let r = unsafe { $call }; - if r == $crate::std::ptr::null_mut() { - Err($crate::std::io::Error::new($crate::std::io::ErrorKind::Other, - concat!("call to `", stringify!($fn), "` failed"))) - } else { - Ok(unsafe { $crate::std::ffi::CStr::from_ptr(r).to_owned() }) - } - } - } -} - -/// An Udev device. -#[derive(Debug)] -pub struct Device { - ptr: *mut udev_sys::udev_device, -} - -unsafe impl Send for Device {} -unsafe impl Sync for Device {} - -impl Device { - #[doc(hidden)] - pub fn from_raw_part(ptr: *mut udev_sys::udev_device) -> Device { - assert!(ptr != ptr::null_mut()); - - Device { ptr } - } - - pub fn get_devpath(&self) -> io::Result { - assert!(self.ptr != ptr::null_mut()); - - call_cstring!(udev_sys::udev_device_get_devpath(self.ptr))? - .to_str() - .map_err(|e| { - io::Error::new(io::ErrorKind::Other, Box::new(e)) - }) - .and_then(|devpath_str| { - PathBuf::from_str(devpath_str) - .map_err(|_| io::Error::new(io::ErrorKind::Other, "couldn't parse path")) - }) - } - - pub fn get_action(&self) -> io::Result { - assert!(self.ptr != ptr::null_mut()); - - call_cstring!(udev_sys::udev_device_get_devpath(self.ptr))? - .to_str() - .map_err(|e| { - io::Error::new(io::ErrorKind::Other, Box::new(e)) - }) - .map(|action| { - action.to_string() - }) - } -} - -impl Clone for Device { - fn clone(&self) -> Device { - assert!(self.ptr != ptr::null_mut()); - let ptr = unsafe { udev_sys::udev_device_ref(self.ptr) }; - assert!(ptr != ptr::null_mut()); - - Device { - ptr, - } - } -} - -impl Drop for Device { - fn drop(&mut self) { - if self.ptr != ptr::null_mut() { - unsafe { udev_sys::udev_device_unref(self.ptr) }; - } - } -} diff --git a/udev/src/lib.rs b/udev/src/lib.rs deleted file mode 100644 index cab6c2a..0000000 --- a/udev/src/lib.rs +++ /dev/null @@ -1,15 +0,0 @@ -#![cfg(target_os = "linux")] - -#[macro_use] -extern crate log; - -extern crate udev_sys; -extern crate libc; - -mod context; -mod device; -mod monitor; - -pub use context::Context; -pub use device::Device; -pub use monitor::{Monitor, MonitorName, Subsystem, DeviceType, UDEV_MONITOR, USB_SUBSYSTEM, USB_DEVICE}; diff --git a/udev/src/monitor.rs b/udev/src/monitor.rs deleted file mode 100644 index c16707c..0000000 --- a/udev/src/monitor.rs +++ /dev/null @@ -1,169 +0,0 @@ -use std::{io, ptr}; -use std::os::unix::io::{AsRawFd, RawFd}; - -use {context::Context, device::Device, udev_sys}; -use libc::c_char; - -/// Name of an udev monitor. -#[derive(Debug)] -pub struct MonitorName(&'static [u8]); - -impl MonitorName { - /// The name as a nul terminated pointer to C string. - fn as_ptr(&self) -> *const u8 { - self.0.as_ptr() - } -} - -/// Udev monitor name (a.k.a `"udev"`). -pub const UDEV_MONITOR: MonitorName = MonitorName(b"udev\0"); - -/// Udev subsystem. -#[derive(Debug)] -pub struct Subsystem(&'static [u8]); - -impl Subsystem { - /// The name as a nul terminated pointer to C string. - fn as_ptr(&self) -> *const u8 { - self.0.as_ptr() - } -} - -/// USB udev subsytem (a.k.a `"usb"`). -pub const USB_SUBSYSTEM: Subsystem = Subsystem(b"usb\0"); - -/// Udev device type. -#[derive(Debug)] -pub struct DeviceType(&'static [u8]); - -impl DeviceType { - /// The name as a nul terminated pointer to C string. - fn as_ptr(&self) -> *const u8 { - self.0.as_ptr() - } -} - -/// USB device type (a.k.a `"usb_device"`) -pub const USB_DEVICE: DeviceType = DeviceType(b"usb_device\0"); - -/// An udev monitor. -#[derive(Debug)] -pub struct Monitor { - ptr: *mut udev_sys::udev_monitor, -} - -unsafe impl Send for Monitor {} -unsafe impl Sync for Monitor {} - -impl Monitor { - /// Create a new monitor. - /// - /// # Notes - /// - /// This is equivalent to the udev C function - /// `udev_monitor_new_from_netlink`. - pub fn new_from_netlink(context: &Context, name: MonitorName) -> Monitor { - trace!("creating new monitor, calling `udev_monitor_new_from_netlink`."); - - let name_ptr = name.as_ptr() as *const c_char; - let ptr = unsafe { - udev_sys::udev_monitor_new_from_netlink(context.as_ptr(), name_ptr) - }; - - if ptr == ptr::null_mut() { - panic!("`udev_monitor_new_from_netlink` returned `std::ptr::null_mut()`."); - } - - Monitor { - ptr, - } - } - - // TODO: documentation. - pub fn filter_add_match_subsystem_devtype(&self, - subsystem: Subsystem, - devtype: DeviceType) -> io::Result<()> { - assert!(self.ptr != ptr::null_mut()); - - let subsystem_ptr = subsystem.as_ptr() as *const c_char; - let devtype_ptr = devtype.as_ptr() as *const c_char; - - let r = unsafe { - udev_sys::udev_monitor_filter_add_match_subsystem_devtype(self.ptr, - subsystem_ptr, - devtype_ptr) - }; - - if r < 0 { - return Err(io::Error::new(io::ErrorKind::Other, - "couldn't add new subsystem-devtype match filter")); - } - - Ok(()) - } - - pub fn enable_receiving(&self) -> io::Result<()> { - assert!(self.ptr != ptr::null_mut()); - - let r = unsafe { - udev_sys::udev_monitor_enable_receiving(self.ptr) - }; - - if r < 0 { - return Err(io::Error::new(io::ErrorKind::Other, - "couldn't enable receiving on udev monitor")); - } - - Ok(()) - } - - pub fn receive_device(&self) -> io::Result { - assert!(self.ptr != ptr::null_mut()); - - let r = unsafe { - udev_sys::udev_monitor_receive_device(self.ptr) - }; - - if r == ptr::null_mut() { - return Err(io::Error::new(io::ErrorKind::WouldBlock, - "couldn't receive device from monitor")); - } - - Ok(Device::from_raw_part(r)) - } -} - -impl Clone for Monitor { - /// Increments the reference count of the `Monitor`. - fn clone(&self) -> Monitor { - trace!("incrementing reference count."); - assert!(self.ptr != ptr::null_mut()); - let ptr = unsafe { udev_sys::udev_monitor_ref(self.ptr) }; - assert!(ptr != ptr::null_mut()); - - Monitor { - ptr, - } - } -} - -impl Drop for Monitor { - /// Decrements the reference count, once it reaches 0 it's dropped. - fn drop(&mut self) { - if self.ptr != ptr::null_mut() { - unsafe { udev_sys::udev_monitor_unref(self.ptr) }; - } else { - trace!("monitor is already null."); - } - } -} - -impl AsRawFd for Monitor { - fn as_raw_fd(&self) -> RawFd { - assert!(self.ptr != ptr::null_mut()); - - unsafe { - udev_sys::udev_monitor_get_fd(self.ptr) as RawFd - } - } -}