1use std::fmt;
2use std::ptr;
3
4use std::ffi::OsStr;
5use std::io::Result;
6use std::ops::Deref;
7use std::os::unix::io::{AsRawFd, RawFd};
8
9#[cfg(feature = "mio06")]
10use mio06::{event::Evented, unix::EventedFd, Poll, PollOpt, Ready, Token};
11#[cfg(feature = "mio07")]
12use mio07::{event::Source, unix::SourceFd, Interest, Registry, Token};
13#[cfg(feature = "mio08")]
14use mio08::{event::Source, unix::SourceFd, Interest, Registry, Token};
15
16use Udev;
17use {ffi, util};
18
19use {AsRaw, AsRawWithContext, Device, FromRaw};
20
21/// Monitors for device events.
22///
23/// A monitor communicates with the kernel over a socket. Filtering events is performed efficiently
24/// in the kernel, and only events that match the filters are received by the socket. Filters must
25/// be setup before listening for events.
26pub struct Builder {
27 udev: Udev,
28 monitor: *mut ffi::udev_monitor,
29}
30
31impl Clone for Builder {
32 fn clone(&self) -> Self {
33 Self {
34 udev: self.udev.clone(),
35 monitor: unsafe { ffi::udev_monitor_ref(self.monitor) },
36 }
37 }
38}
39
40impl Drop for Builder {
41 fn drop(&mut self) {
42 unsafe {
43 ffi::udev_monitor_unref(self.monitor);
44 }
45 }
46}
47
48as_ffi_with_context!(Builder, monitor, ffi::udev_monitor, ffi::udev_monitor_ref);
49
50impl Builder {
51 /// Creates a new `Monitor`.
52 pub fn new() -> Result<Self> {
53 // Create a new Udev context for this monitor
54 // It would be more efficient to allow callers to create just one context and use multiple
55 // monitors, however that would be an API-breaking change.
56 Self::with_udev(Udev::new()?)
57 }
58
59 /// Creates a new `Monitor` using an existing `Udev` instance
60 pub(crate) fn with_udev(udev: Udev) -> Result<Self> {
61 let name = b"udev\0".as_ptr() as *const libc::c_char;
62
63 let ptr = try_alloc!(unsafe { ffi::udev_monitor_new_from_netlink(udev.as_raw(), name) });
64
65 Ok(Self { udev, monitor: ptr })
66 }
67
68 /// Adds a filter that matches events for devices with the given subsystem.
69 pub fn match_subsystem<T: AsRef<OsStr>>(self, subsystem: T) -> Result<Self> {
70 let subsystem = util::os_str_to_cstring(subsystem)?;
71
72 util::errno_to_result(unsafe {
73 ffi::udev_monitor_filter_add_match_subsystem_devtype(
74 self.monitor,
75 subsystem.as_ptr(),
76 ptr::null(),
77 )
78 })
79 .and(Ok(self))
80 }
81
82 /// Adds a filter that matches events for devices with the given subsystem and device type.
83 pub fn match_subsystem_devtype<T: AsRef<OsStr>, U: AsRef<OsStr>>(
84 self,
85 subsystem: T,
86 devtype: U,
87 ) -> Result<Self> {
88 let subsystem = util::os_str_to_cstring(subsystem)?;
89 let devtype = util::os_str_to_cstring(devtype)?;
90
91 util::errno_to_result(unsafe {
92 ffi::udev_monitor_filter_add_match_subsystem_devtype(
93 self.monitor,
94 subsystem.as_ptr(),
95 devtype.as_ptr(),
96 )
97 })
98 .and(Ok(self))
99 }
100
101 /// Adds a filter that matches events for devices with the given tag.
102 pub fn match_tag<T: AsRef<OsStr>>(self, tag: T) -> Result<Self> {
103 let tag = util::os_str_to_cstring(tag)?;
104
105 util::errno_to_result(unsafe {
106 ffi::udev_monitor_filter_add_match_tag(self.monitor, tag.as_ptr())
107 })
108 .and(Ok(self))
109 }
110
111 /// Removes all filters currently set on the monitor.
112 pub fn clear_filters(self) -> Result<Self> {
113 util::errno_to_result(unsafe { ffi::udev_monitor_filter_remove(self.monitor) })
114 .and(Ok(self))
115 }
116
117 /// Listens for events matching the current filters.
118 ///
119 /// This method consumes the `Monitor`.
120 pub fn listen(self) -> Result<Socket> {
121 util::errno_to_result(unsafe { ffi::udev_monitor_enable_receiving(self.monitor) })?;
122
123 Ok(Socket { inner: self })
124 }
125}
126
127/// An active monitor that can receive events.
128///
129/// The events received by a `Socket` match the filters setup by the `Monitor` that created
130/// the socket.
131///
132/// Monitors are initially setup to receive events from the kernel via a nonblocking socket. A
133/// variant of `poll()` should be used on the file descriptor returned by the `AsRawFd` trait to
134/// wait for new events.
135pub struct Socket {
136 inner: Builder,
137}
138
139impl Socket {
140 /// Create an iterator of socket event messages
141 pub fn iter(&self) -> SocketIter {
142 SocketIter::new(self)
143 }
144}
145
146impl AsRaw<ffi::udev_monitor> for Socket {
147 fn as_raw(&self) -> *mut ffi::udev_monitor {
148 self.inner.monitor
149 }
150
151 fn into_raw(self) -> *mut ffi::udev_monitor {
152 self.inner.monitor
153 }
154}
155
156/// Provides raw access to the monitor's socket.
157impl AsRawFd for Socket {
158 /// Returns the file descriptor of the monitor's socket.
159 fn as_raw_fd(&self) -> RawFd {
160 unsafe { ffi::udev_monitor_get_fd(self.inner.monitor) }
161 }
162}
163
164pub struct SocketIter {
165 udev: Udev,
166 monitor: *mut ffi::udev_monitor,
167}
168
169impl SocketIter {
170 /// Create a socket by cloning the underlying udev instance
171 fn new(socket: &Socket) -> SocketIter {
172 SocketIter {
173 udev: socket.inner.udev.clone(),
174 monitor: unsafe { ffi::udev_monitor_ref(udev_monitor:socket.inner.monitor) },
175 }
176 }
177}
178
179impl Drop for SocketIter {
180 fn drop(&mut self) {
181 unsafe { ffi::udev_monitor_unref(self.monitor) };
182 }
183}
184
185impl Iterator for SocketIter {
186 type Item = Event;
187
188 fn next(&mut self) -> Option<Event> {
189 let ptr: *mut udev_device = unsafe { ffi::udev_monitor_receive_device(self.monitor) };
190
191 if ptr.is_null() {
192 None
193 } else {
194 let device: Device = Device::from_raw(self.udev.clone(), ptr);
195 Some(Event { device })
196 }
197 }
198}
199
200/// Types of events that can be received from udev.
201#[derive(Debug, Clone, Copy, PartialEq, Eq)]
202pub enum EventType {
203 /// A device was added.
204 Add,
205
206 /// A device changed.
207 Change,
208
209 /// A device was removed.
210 Remove,
211
212 /// A device was bound to driver.
213 Bind,
214
215 /// A device was unbound to driver.
216 Unbind,
217
218 /// An unknown event occurred.
219 Unknown,
220}
221
222impl Default for EventType {
223 fn default() -> Self {
224 EventType::Unknown
225 }
226}
227
228impl fmt::Display for EventType {
229 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
230 f.write_str(data:match *self {
231 EventType::Add => "add",
232 EventType::Change => "change",
233 EventType::Remove => "remove",
234 EventType::Bind => "bind",
235 EventType::Unbind => "unbind",
236 EventType::Unknown => "unknown",
237 })
238 }
239}
240
241/// An event that indicates a change in device state.
242pub struct Event {
243 device: Device,
244}
245
246impl std::fmt::Debug for Event {
247 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
248 f&mut DebugStruct<'_, '_>.debug_struct("Event")
249 .field("device", &self.device())
250 .field("event_type", &self.event_type())
251 .field(name:"sequence_number", &self.sequence_number())
252 .finish()
253 }
254}
255
256/// Provides access to the device associated with the event.
257impl Deref for Event {
258 type Target = Device;
259
260 fn deref(&self) -> &Device {
261 &self.device
262 }
263}
264
265impl Event {
266 /// Returns the `EventType` corresponding to this event.
267 pub fn event_type(&self) -> EventType {
268 let value = match self.device.property_value("ACTION") {
269 Some(s) => s.to_str(),
270 None => None,
271 };
272
273 match value {
274 Some("add") => EventType::Add,
275 Some("change") => EventType::Change,
276 Some("remove") => EventType::Remove,
277 Some("bind") => EventType::Bind,
278 Some("unbind") => EventType::Unbind,
279 _ => EventType::Unknown,
280 }
281 }
282
283 /// Returns the event's sequence number.
284 pub fn sequence_number(&self) -> u64 {
285 unsafe { ffi::udev_device_get_seqnum(self.device.as_raw()) as u64 }
286 }
287
288 /// Returns the device associated with this event.
289 pub fn device(&self) -> Device {
290 self.device.clone()
291 }
292}
293
294#[cfg(feature = "mio06")]
295impl Evented for Socket {
296 fn register(
297 &self,
298 poll: &Poll,
299 token: Token,
300 interest: Ready,
301 opts: PollOpt,
302 ) -> std::io::Result<()> {
303 EventedFd(&self.as_raw_fd()).register(poll, token, interest, opts)
304 }
305
306 fn reregister(
307 &self,
308 poll: &Poll,
309 token: Token,
310 interest: Ready,
311 opts: PollOpt,
312 ) -> std::io::Result<()> {
313 EventedFd(&self.as_raw_fd()).reregister(poll, token, interest, opts)
314 }
315
316 fn deregister(&self, poll: &Poll) -> std::io::Result<()> {
317 EventedFd(&self.as_raw_fd()).deregister(poll)
318 }
319}
320
321#[cfg(any(feature = "mio07", feature = "mio08"))]
322impl Source for Socket {
323 fn register(
324 &mut self,
325 registry: &Registry,
326 token: Token,
327 interest: Interest,
328 ) -> std::io::Result<()> {
329 SourceFd(&self.as_raw_fd()).register(registry, token, interest)
330 }
331
332 fn reregister(
333 &mut self,
334 registry: &Registry,
335 token: Token,
336 interest: Interest,
337 ) -> std::io::Result<()> {
338 SourceFd(&self.as_raw_fd()).reregister(registry, token, interest)
339 }
340
341 fn deregister(&mut self, registry: &Registry) -> std::io::Result<()> {
342 SourceFd(&self.as_raw_fd()).deregister(registry)
343 }
344}
345