udev/
monitor.rs

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