gilrs_core/platform/linux/
udev.rs1use 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) -> Option<&CStr> {
121 unsafe {
122 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}