gilrs_core/platform/linux/
udev.rs

1// Copyright 2016-2018 Mateusz Sieczko and other GilRs Developers
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// http://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8use libc as c;
9use libudev_sys as ud;
10use std::ffi::{CStr, CString};
11use std::os::raw::c_char;
12use std::ptr;
13
14#[derive(Debug)]
15pub struct Udev(*mut ud::udev);
16
17impl Udev {
18    pub fn new() -> Option<Self> {
19        let u = unsafe { ud::udev_new() };
20        if u.is_null() {
21            None
22        } else {
23            Some(Udev(u))
24        }
25    }
26
27    pub fn enumerate(&self) -> Option<Enumerate> {
28        let en = unsafe { ud::udev_enumerate_new(self.0) };
29        if en.is_null() {
30            None
31        } else {
32            let en = Enumerate(en);
33            Some(en)
34        }
35    }
36}
37
38impl Drop for Udev {
39    fn drop(&mut self) {
40        unsafe {
41            ud::udev_unref(self.0);
42        }
43    }
44}
45
46impl Clone for Udev {
47    fn clone(&self) -> Self {
48        Udev(unsafe { ud::udev_ref(self.0) })
49    }
50}
51
52pub struct Enumerate(*mut ud::udev_enumerate);
53
54impl Enumerate {
55    pub fn scan_devices(&self) {
56        // TODO: Check for error
57        let _ = unsafe { ud::udev_enumerate_scan_devices(self.0) };
58    }
59
60    pub fn add_match_property(&self, key: &CStr, val: &CStr) {
61        // TODO: Check for error
62        unsafe {
63            ud::udev_enumerate_add_match_property(self.0, key.as_ptr(), val.as_ptr());
64        }
65    }
66
67    pub fn add_match_subsystem(&self, subsystem: &CStr) {
68        // TODO: Check for error
69        unsafe {
70            ud::udev_enumerate_add_match_subsystem(self.0, subsystem.as_ptr());
71        }
72    }
73
74    pub fn iter(&self) -> DeviceIterator {
75        DeviceIterator(unsafe { ud::udev_enumerate_get_list_entry(self.0) })
76    }
77}
78
79impl Drop for Enumerate {
80    fn drop(&mut self) {
81        unsafe {
82            ud::udev_enumerate_unref(self.0);
83        }
84    }
85}
86
87pub struct DeviceIterator(*mut ud::udev_list_entry);
88
89impl Iterator for DeviceIterator {
90    type Item = CString;
91
92    fn next(&mut self) -> Option<CString> {
93        if self.0.is_null() {
94            None
95        } else {
96            let p_name = unsafe { ud::udev_list_entry_get_name(self.0) };
97            let name = if p_name.is_null() {
98                return None;
99            } else {
100                unsafe { CStr::from_ptr(p_name).to_owned() }
101            };
102            self.0 = unsafe { ud::udev_list_entry_get_next(self.0) };
103            Some(name)
104        }
105    }
106}
107
108pub struct Device(*mut ud::udev_device);
109
110impl Device {
111    pub fn from_syspath(udev: &Udev, path: &CStr) -> Option<Self> {
112        let dev = unsafe { ud::udev_device_new_from_syspath(udev.0, path.as_ptr()) };
113        if dev.is_null() {
114            None
115        } else {
116            Some(Device(dev))
117        }
118    }
119
120    pub fn syspath(&self) -> &CStr {
121        // Always returns cstring
122        unsafe { CStr::from_ptr(ud::udev_device_get_syspath(self.0)) }
123    }
124
125    pub fn devnode(&self) -> Option<&CStr> {
126        unsafe {
127            let s = ud::udev_device_get_devnode(self.0);
128            if s.is_null() {
129                None
130            } else {
131                Some(CStr::from_ptr(s))
132            }
133        }
134    }
135
136    #[allow(dead_code)]
137    pub fn properties(&self) -> PropertyIterator {
138        let prop = unsafe { ud::udev_device_get_properties_list_entry(self.0) };
139        PropertyIterator(prop)
140    }
141
142    pub fn action(&self) -> Option<&CStr> {
143        unsafe {
144            let s = ud::udev_device_get_action(self.0);
145            if s.is_null() {
146                None
147            } else {
148                Some(CStr::from_ptr(s))
149            }
150        }
151    }
152
153    pub fn property_value(&self, key: &CStr) -> Option<&CStr> {
154        unsafe {
155            let s = ud::udev_device_get_property_value(self.0, key.as_ptr());
156            if s.is_null() {
157                None
158            } else {
159                Some(CStr::from_ptr(s))
160            }
161        }
162    }
163}
164
165impl Clone for Device {
166    fn clone(&self) -> Self {
167        unsafe { Device(ud::udev_device_ref(self.0)) }
168    }
169}
170
171impl Drop for Device {
172    fn drop(&mut self) {
173        unsafe {
174            ud::udev_device_unref(self.0);
175        }
176    }
177}
178
179#[allow(dead_code)]
180pub struct PropertyIterator(*mut ud::udev_list_entry);
181
182impl Iterator for PropertyIterator {
183    type Item = (String, String);
184
185    fn next(&mut self) -> Option<(String, String)> {
186        if self.0.is_null() {
187            None
188        } else {
189            let p_name = unsafe { ud::udev_list_entry_get_name(self.0) };
190            let p_val = unsafe { ud::udev_list_entry_get_value(self.0) };
191
192            let name = if p_name.is_null() {
193                return None;
194            } else {
195                unsafe { CStr::from_ptr(p_name).to_string_lossy().into_owned() }
196            };
197
198            let value = if p_val.is_null() {
199                return None;
200            } else {
201                unsafe { CStr::from_ptr(p_val).to_string_lossy().into_owned() }
202            };
203
204            self.0 = unsafe { ud::udev_list_entry_get_next(self.0) };
205            Some((name, value))
206        }
207    }
208}
209
210#[derive(Debug)]
211pub struct Monitor(*mut ud::udev_monitor);
212
213impl Monitor {
214    pub fn new(udev: &Udev) -> Option<Self> {
215        unsafe {
216            let monitor =
217                ud::udev_monitor_new_from_netlink(udev.0, c"udev".as_ptr() as *const c_char);
218            if monitor.is_null() {
219                None
220            } else {
221                ud::udev_monitor_filter_add_match_subsystem_devtype(
222                    monitor,
223                    c"input".as_ptr() as *const c_char,
224                    ptr::null(),
225                );
226                ud::udev_monitor_enable_receiving(monitor);
227                Some(Monitor(monitor))
228            }
229        }
230    }
231
232    pub fn wait_hotplug_available(&self) -> bool {
233        unsafe {
234            let mut fds = c::pollfd {
235                fd: ud::udev_monitor_get_fd(self.0),
236                events: c::POLLIN,
237                revents: 0,
238            };
239            (c::poll(&mut fds, 1, -1) == 1) && (fds.revents & c::POLLIN != 0)
240        }
241    }
242
243    pub fn device(&self) -> Device {
244        Device(unsafe { ud::udev_monitor_receive_device(self.0) })
245    }
246}
247
248impl Drop for Monitor {
249    fn drop(&mut self) {
250        unsafe {
251            ud::udev_monitor_unref(self.0);
252        }
253    }
254}