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) -> Option<&CStr> {
121        unsafe {
122            // Always returns cstring
123            let ptr = ud::udev_device_get_syspath(self.0);
124
125            if ptr.is_null() {
126                None
127            } else {
128                Some(CStr::from_ptr(ptr))
129            }
130        }
131    }
132
133    pub fn devnode(&self) -> Option<&CStr> {
134        unsafe {
135            let s = ud::udev_device_get_devnode(self.0);
136            if s.is_null() {
137                None
138            } else {
139                Some(CStr::from_ptr(s))
140            }
141        }
142    }
143
144    #[allow(dead_code)]
145    pub fn properties(&self) -> PropertyIterator {
146        let prop = unsafe { ud::udev_device_get_properties_list_entry(self.0) };
147        PropertyIterator(prop)
148    }
149
150    pub fn action(&self) -> Option<&CStr> {
151        unsafe {
152            let s = ud::udev_device_get_action(self.0);
153            if s.is_null() {
154                None
155            } else {
156                Some(CStr::from_ptr(s))
157            }
158        }
159    }
160
161    pub fn property_value(&self, key: &CStr) -> Option<&CStr> {
162        unsafe {
163            let s = ud::udev_device_get_property_value(self.0, key.as_ptr());
164            if s.is_null() {
165                None
166            } else {
167                Some(CStr::from_ptr(s))
168            }
169        }
170    }
171}
172
173impl Clone for Device {
174    fn clone(&self) -> Self {
175        unsafe { Device(ud::udev_device_ref(self.0)) }
176    }
177}
178
179impl Drop for Device {
180    fn drop(&mut self) {
181        unsafe {
182            ud::udev_device_unref(self.0);
183        }
184    }
185}
186
187#[allow(dead_code)]
188pub struct PropertyIterator(*mut ud::udev_list_entry);
189
190impl Iterator for PropertyIterator {
191    type Item = (String, String);
192
193    fn next(&mut self) -> Option<(String, String)> {
194        if self.0.is_null() {
195            None
196        } else {
197            let p_name = unsafe { ud::udev_list_entry_get_name(self.0) };
198            let p_val = unsafe { ud::udev_list_entry_get_value(self.0) };
199
200            let name = if p_name.is_null() {
201                return None;
202            } else {
203                unsafe { CStr::from_ptr(p_name).to_string_lossy().into_owned() }
204            };
205
206            let value = if p_val.is_null() {
207                return None;
208            } else {
209                unsafe { CStr::from_ptr(p_val).to_string_lossy().into_owned() }
210            };
211
212            self.0 = unsafe { ud::udev_list_entry_get_next(self.0) };
213            Some((name, value))
214        }
215    }
216}
217
218#[derive(Debug)]
219pub struct Monitor(*mut ud::udev_monitor);
220
221impl Monitor {
222    pub fn new(udev: &Udev) -> Option<Self> {
223        unsafe {
224            let monitor =
225                ud::udev_monitor_new_from_netlink(udev.0, c"udev".as_ptr() as *const c_char);
226            if monitor.is_null() {
227                None
228            } else {
229                ud::udev_monitor_filter_add_match_subsystem_devtype(
230                    monitor,
231                    c"input".as_ptr() as *const c_char,
232                    ptr::null(),
233                );
234                ud::udev_monitor_enable_receiving(monitor);
235                Some(Monitor(monitor))
236            }
237        }
238    }
239
240    pub fn wait_hotplug_available(&self) -> bool {
241        unsafe {
242            let mut fds = c::pollfd {
243                fd: ud::udev_monitor_get_fd(self.0),
244                events: c::POLLIN,
245                revents: 0,
246            };
247            (c::poll(&mut fds, 1, -1) == 1) && (fds.revents & c::POLLIN != 0)
248        }
249    }
250
251    pub fn device(&self) -> Device {
252        Device(unsafe { ud::udev_monitor_receive_device(self.0) })
253    }
254}
255
256impl Drop for Monitor {
257    fn drop(&mut self) {
258        unsafe {
259            ud::udev_monitor_unref(self.0);
260        }
261    }
262}