use std::fmt;
use std::ptr;
use std::ffi::OsStr;
use std::ops::Deref;
use std::os::unix::io::{RawFd, AsRawFd};
use ::context::Context;
use ::device::Device;
use ::handle::Handle;
pub struct Monitor {
monitor: *mut ::ffi::udev_monitor,
}
impl Drop for Monitor {
fn drop(&mut self) {
unsafe {
let udev = ::ffi::udev_monitor_get_udev(self.monitor);
::ffi::udev_monitor_unref(self.monitor);
::ffi::udev_unref(udev);
}
}
}
impl Monitor {
pub fn new(context: &Context) -> ::Result<Self> {
unsafe {
let ptr = try_alloc!(
::ffi::udev_monitor_new_from_netlink(context.as_ptr(), b"udev\0".as_ptr() as *mut _)
);
::ffi::udev_ref(context.as_ptr());
Ok(Monitor { monitor: ptr })
}
}
pub fn match_subsystem<T: AsRef<OsStr>>(&mut self, subsystem: T) -> ::Result<()> {
let subsystem = try!(::util::os_str_to_cstring(subsystem));
::util::errno_to_result(unsafe {
::ffi::udev_monitor_filter_add_match_subsystem_devtype(self.monitor, subsystem.as_ptr(), ptr::null())
})
}
pub fn match_subsystem_devtype<T: AsRef<OsStr>, U: AsRef<OsStr>>(&mut self, subsystem: T, devtype: U) -> ::Result<()> {
let subsystem = try!(::util::os_str_to_cstring(subsystem));
let devtype = try!(::util::os_str_to_cstring(devtype));
::util::errno_to_result(unsafe {
::ffi::udev_monitor_filter_add_match_subsystem_devtype(self.monitor, subsystem.as_ptr(), devtype.as_ptr())
})
}
pub fn match_tag<T: AsRef<OsStr>>(&mut self, tag: T) -> ::Result<()> {
let tag = try!(::util::os_str_to_cstring(tag));
::util::errno_to_result(unsafe {
::ffi::udev_monitor_filter_add_match_tag(self.monitor, tag.as_ptr())
})
}
pub fn clear_filters(&mut self) -> ::Result<()> {
::util::errno_to_result(unsafe {
::ffi::udev_monitor_filter_remove(self.monitor)
})
}
pub fn listen(self) -> ::Result<MonitorSocket> {
try!(::util::errno_to_result(unsafe {
::ffi::udev_monitor_enable_receiving(self.monitor)
}));
Ok(MonitorSocket { inner: self })
}
}
pub struct MonitorSocket {
inner: Monitor,
}
impl AsRawFd for MonitorSocket {
fn as_raw_fd(&self) -> RawFd {
unsafe {
::ffi::udev_monitor_get_fd(self.inner.monitor)
}
}
}
impl MonitorSocket {
pub fn receive_event(&mut self) -> Option<Event> {
let device = unsafe {
::ffi::udev_monitor_receive_device(self.inner.monitor)
};
if !device.is_null() {
Some(Event {
device: unsafe { ::device::from_raw(device) },
})
}
else {
None
}
}
}
#[derive(Debug,Clone,Copy,PartialEq,Eq)]
pub enum EventType {
Add,
Change,
Remove,
Unknown,
}
impl Default for EventType {
fn default() -> EventType {
EventType::Unknown
}
}
impl fmt::Display for EventType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(match self {
&EventType::Add => "add",
&EventType::Change => "change",
&EventType::Remove => "remove",
&EventType::Unknown => "unknown",
})
}
}
pub struct Event {
device: Device,
}
impl Deref for Event {
type Target = Device;
fn deref(&self) -> &Device {
&self.device
}
}
impl Event {
pub fn event_type(&self) -> EventType {
let value = match self.device.property_value("ACTION") {
Some(s) => s.to_str(),
None => None,
};
match value {
Some("add") => EventType::Add,
Some("change") => EventType::Change,
Some("remove") => EventType::Remove,
_ => EventType::Unknown
}
}
pub fn sequence_number(&self) -> u64 {
unsafe {
::ffi::udev_device_get_seqnum(self.device.as_ptr()) as u64
}
}
pub fn device(&self) -> &Device {
&self.device
}
}