gilrs_core/platform/linux/
udev.rs
1use 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 let _ = unsafe { ud::udev_enumerate_scan_devices(self.0) };
58 }
59
60 pub fn add_match_property(&self, key: &CStr, val: &CStr) {
61 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 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 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}