1 | use std::fmt; |
2 | use std::ptr; |
3 | |
4 | use std::ffi::OsStr; |
5 | use std::io::Result; |
6 | use std::ops::Deref; |
7 | use std::os::unix::io::{AsRawFd, RawFd}; |
8 | |
9 | #[cfg (feature = "mio06" )] |
10 | use mio06::{event::Evented, unix::EventedFd, Poll, PollOpt, Ready, Token}; |
11 | #[cfg (feature = "mio07" )] |
12 | use mio07::{event::Source, unix::SourceFd, Interest, Registry, Token}; |
13 | #[cfg (feature = "mio08" )] |
14 | use mio08::{event::Source, unix::SourceFd, Interest, Registry, Token}; |
15 | |
16 | use Udev; |
17 | use {ffi, util}; |
18 | |
19 | use {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. |
26 | pub struct Builder { |
27 | udev: Udev, |
28 | monitor: *mut ffi::udev_monitor, |
29 | } |
30 | |
31 | impl 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 | |
40 | impl Drop for Builder { |
41 | fn drop(&mut self) { |
42 | unsafe { |
43 | ffi::udev_monitor_unref(self.monitor); |
44 | } |
45 | } |
46 | } |
47 | |
48 | as_ffi_with_context!(Builder, monitor, ffi::udev_monitor, ffi::udev_monitor_ref); |
49 | |
50 | impl 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. |
135 | pub struct Socket { |
136 | inner: Builder, |
137 | } |
138 | |
139 | impl Socket { |
140 | /// Create an iterator of socket event messages |
141 | pub fn iter(&self) -> SocketIter { |
142 | SocketIter::new(self) |
143 | } |
144 | } |
145 | |
146 | impl 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. |
157 | impl 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 | |
164 | pub struct SocketIter { |
165 | udev: Udev, |
166 | monitor: *mut ffi::udev_monitor, |
167 | } |
168 | |
169 | impl 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 | |
179 | impl Drop for SocketIter { |
180 | fn drop(&mut self) { |
181 | unsafe { ffi::udev_monitor_unref(self.monitor) }; |
182 | } |
183 | } |
184 | |
185 | impl 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)] |
202 | pub 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 | |
222 | impl Default for EventType { |
223 | fn default() -> Self { |
224 | EventType::Unknown |
225 | } |
226 | } |
227 | |
228 | impl 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. |
242 | pub struct Event { |
243 | device: Device, |
244 | } |
245 | |
246 | impl 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. |
257 | impl Deref for Event { |
258 | type Target = Device; |
259 | |
260 | fn deref(&self) -> &Device { |
261 | &self.device |
262 | } |
263 | } |
264 | |
265 | impl 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" )] |
295 | impl 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" ))] |
322 | impl 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 | |