libudev/
monitor.rs

1use std::fmt;
2use std::ptr;
3
4use std::ffi::OsStr;
5use std::ops::Deref;
6use std::os::unix::io::{RawFd, AsRawFd};
7
8use ::context::Context;
9use ::device::Device;
10use ::handle::Handle;
11
12
13/// Monitors for device events.
14///
15/// A monitor communicates with the kernel over a socket. Filtering events is performed efficiently
16/// in the kernel, and only events that match the filters are received by the socket. Filters must
17/// be setup before listening for events.
18pub struct Monitor {
19    monitor: *mut ::ffi::udev_monitor,
20}
21
22impl Drop for Monitor {
23    fn drop(&mut self) {
24        unsafe {
25            let udev = ::ffi::udev_monitor_get_udev(self.monitor);
26
27            ::ffi::udev_monitor_unref(self.monitor);
28            ::ffi::udev_unref(udev);
29        }
30    }
31}
32
33impl Monitor {
34    /// Creates a new `Monitor`.
35    pub fn new(context: &Context) -> ::Result<Self> {
36        unsafe {
37            let ptr = try_alloc!(
38                ::ffi::udev_monitor_new_from_netlink(context.as_ptr(), b"udev\0".as_ptr() as *mut _)
39            );
40
41            ::ffi::udev_ref(context.as_ptr());
42
43            Ok(Monitor { monitor: ptr })
44        }
45    }
46
47    /// Adds a filter that matches events for devices with the given subsystem.
48    pub fn match_subsystem<T: AsRef<OsStr>>(&mut self, subsystem: T) -> ::Result<()> {
49        let subsystem = try!(::util::os_str_to_cstring(subsystem));
50
51        ::util::errno_to_result(unsafe {
52            ::ffi::udev_monitor_filter_add_match_subsystem_devtype(self.monitor, subsystem.as_ptr(), ptr::null())
53        })
54    }
55
56    /// Adds a filter that matches events for devices with the given subsystem and device type.
57    pub fn match_subsystem_devtype<T: AsRef<OsStr>, U: AsRef<OsStr>>(&mut self, subsystem: T, devtype: U) -> ::Result<()> {
58        let subsystem = try!(::util::os_str_to_cstring(subsystem));
59        let devtype = try!(::util::os_str_to_cstring(devtype));
60
61        ::util::errno_to_result(unsafe {
62            ::ffi::udev_monitor_filter_add_match_subsystem_devtype(self.monitor, subsystem.as_ptr(), devtype.as_ptr())
63        })
64    }
65
66    /// Adds a filter that matches events for devices with the given tag.
67    pub fn match_tag<T: AsRef<OsStr>>(&mut self, tag: T) -> ::Result<()> {
68        let tag = try!(::util::os_str_to_cstring(tag));
69
70        ::util::errno_to_result(unsafe {
71            ::ffi::udev_monitor_filter_add_match_tag(self.monitor, tag.as_ptr())
72        })
73    }
74
75    /// Removes all filters currently set on the monitor.
76    pub fn clear_filters(&mut self) -> ::Result<()> {
77        ::util::errno_to_result(unsafe {
78            ::ffi::udev_monitor_filter_remove(self.monitor)
79        })
80    }
81
82    /// Listens for events matching the current filters.
83    ///
84    /// This method consumes the `Monitor`.
85    pub fn listen(self) -> ::Result<MonitorSocket> {
86        try!(::util::errno_to_result(unsafe {
87            ::ffi::udev_monitor_enable_receiving(self.monitor)
88        }));
89
90        Ok(MonitorSocket { inner: self })
91    }
92}
93
94
95/// An active monitor that can receive events.
96///
97/// The events received by a `MonitorSocket` match the filters setup by the `Monitor` that created
98/// the socket.
99///
100/// Monitors are initially setup to receive events from the kernel via a nonblocking socket. A
101/// variant of `poll()` should be used on the file descriptor returned by the `AsRawFd` trait to
102/// wait for new events.
103pub struct MonitorSocket {
104    inner: Monitor,
105}
106
107/// Provides raw access to the monitor's socket.
108impl AsRawFd for MonitorSocket {
109    /// Returns the file descriptor of the monitor's socket.
110    fn as_raw_fd(&self) -> RawFd {
111        unsafe {
112            ::ffi::udev_monitor_get_fd(self.inner.monitor)
113        }
114    }
115}
116
117impl MonitorSocket {
118    /// Receives the next available event from the monitor.
119    ///
120    /// This method does not block. If no events are available, it returns `None` immediately.
121    pub fn receive_event(&mut self) -> Option<Event> {
122        let device = unsafe {
123            ::ffi::udev_monitor_receive_device(self.inner.monitor)
124        };
125
126        if !device.is_null() {
127            Some(Event {
128                device: unsafe { ::device::from_raw(device) },
129            })
130        }
131        else {
132            None
133        }
134    }
135}
136
137/// Types of events that can be received from udev.
138#[derive(Debug,Clone,Copy,PartialEq,Eq)]
139pub enum EventType {
140    /// A device was added.
141    Add,
142
143    /// A device changed.
144    Change,
145
146    /// A device was removed.
147    Remove,
148
149    /// An unknown event occurred.
150    Unknown,
151}
152
153impl Default for EventType {
154    fn default() -> EventType {
155        EventType::Unknown
156    }
157}
158
159impl fmt::Display for EventType {
160    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
161        f.write_str(match self {
162            &EventType::Add => "add",
163            &EventType::Change => "change",
164            &EventType::Remove => "remove",
165            &EventType::Unknown => "unknown",
166        })
167    }
168}
169
170
171/// An event that indicates a change in device state.
172pub struct Event {
173    device: Device,
174}
175
176/// Provides access to the device associated with the event.
177impl Deref for Event {
178    type Target = Device;
179
180    fn deref(&self) -> &Device {
181        &self.device
182    }
183}
184
185impl Event {
186    /// Returns the `EventType` corresponding to this event.
187    pub fn event_type(&self) -> EventType {
188        let value = match self.device.property_value("ACTION") {
189            Some(s) => s.to_str(),
190            None => None,
191        };
192
193        match value {
194            Some("add") => EventType::Add,
195            Some("change") => EventType::Change,
196            Some("remove") => EventType::Remove,
197            _ => EventType::Unknown
198        }
199    }
200
201    /// Returns the event's sequence number.
202    pub fn sequence_number(&self) -> u64 {
203        unsafe {
204            ::ffi::udev_device_get_seqnum(self.device.as_ptr()) as u64
205        }
206    }
207
208    /// Returns the device associated with this event.
209    pub fn device(&self) -> &Device {
210        &self.device
211    }
212}