1use std::str;
2
3use std::ffi::{CStr, OsStr};
4use std::marker::PhantomData;
5use std::path::Path;
6use std::str::FromStr;
7
8use libc::{c_char, dev_t};
9
10use ::context::Context;
11use ::handle::Handle;
12
13
14pub unsafe fn from_raw(device: *mut ::ffi::udev_device) -> Device {
15 ::ffi::udev_ref(::ffi::udev_device_get_udev(device));
16
17 Device { device: device }
18}
19
20
21pub struct Device {
23 device: *mut ::ffi::udev_device,
24}
25
26impl Drop for Device {
27 fn drop(&mut self) {
28 unsafe {
29 let udev = ::ffi::udev_device_get_udev(self.device);
30
31 ::ffi::udev_device_unref(self.device);
32 ::ffi::udev_unref(udev);
33 }
34 }
35}
36
37#[doc(hidden)]
38impl Handle<::ffi::udev_device> for Device {
39 fn as_ptr(&self) -> *mut ::ffi::udev_device {
40 self.device
41 }
42}
43
44impl Device {
45 pub fn from_syspath(context: &Context, syspath: &Path) -> ::Result<Self> {
50 let syspath = try!(::util::os_str_to_cstring(syspath));
51
52 Ok(unsafe {
53 from_raw(try_alloc!(
54 ::ffi::udev_device_new_from_syspath(context.as_ptr(), syspath.as_ptr())
55 ))
56 })
57 }
58
59 pub fn is_initialized(&self) -> bool {
68 unsafe {
69 ::ffi::udev_device_get_is_initialized(self.device) > 0
70 }
71 }
72
73 pub fn devnum(&self) -> Option<dev_t> {
75 match unsafe { ::ffi::udev_device_get_devnum(self.device) } {
76 0 => None,
77 n => Some(n),
78 }
79 }
80
81 pub fn syspath(&self) -> Option<&Path> {
87 ::util::ptr_to_path(unsafe {
88 ::ffi::udev_device_get_syspath(self.device)
89 })
90 }
91
92 pub fn devpath(&self) -> Option<&OsStr> {
97 ::util::ptr_to_os_str(unsafe {
98 ::ffi::udev_device_get_devpath(self.device)
99 })
100 }
101
102 pub fn devnode(&self) -> Option<&Path> {
107 ::util::ptr_to_path(unsafe {
108 ::ffi::udev_device_get_devnode(self.device)
109 })
110 }
111
112 pub fn parent(&self) -> Option<Device> {
114 let ptr = unsafe { ::ffi::udev_device_get_parent(self.device) };
115
116 if !ptr.is_null() {
117 unsafe {
118 ::ffi::udev_device_ref(ptr);
119
120 Some(from_raw(ptr))
121 }
122 }
123 else {
124 None
125 }
126 }
127
128 pub fn subsystem(&self) -> Option<&OsStr> {
133 ::util::ptr_to_os_str(unsafe {
134 ::ffi::udev_device_get_subsystem(self.device)
135 })
136 }
137
138 pub fn sysname(&self) -> Option<&OsStr> {
144 ::util::ptr_to_os_str(unsafe {
145 ::ffi::udev_device_get_sysname(self.device)
146 })
147 }
148
149 pub fn sysnum(&self) -> Option<usize> {
158 let ptr = unsafe { ::ffi::udev_device_get_sysnum(self.device) };
159
160 if !ptr.is_null() {
161 match str::from_utf8(unsafe { CStr::from_ptr(ptr) }.to_bytes()) {
162 Ok(s) => FromStr::from_str(s).ok(),
163 Err(_) => None,
164 }
165 }
166 else {
167 None
168 }
169 }
170
171 pub fn devtype(&self) -> Option<&OsStr> {
173 ::util::ptr_to_os_str(unsafe { ::ffi::udev_device_get_devtype(self.device) })
174 }
175
176 pub fn driver(&self) -> Option<&OsStr> {
178 ::util::ptr_to_os_str(unsafe { ::ffi::udev_device_get_driver(self.device) })
179 }
180
181 pub fn property_value<T: AsRef<OsStr>>(&self, property: T) -> Option<&OsStr> {
183 match ::util::os_str_to_cstring(property) {
184 Ok(prop) => {
185 ::util::ptr_to_os_str(unsafe {
186 ::ffi::udev_device_get_property_value(self.device, prop.as_ptr())
187 })
188 },
189 Err(_) => None,
190 }
191
192 }
193
194 pub fn attribute_value<T: AsRef<OsStr>>(&self, attribute: T) -> Option<&OsStr> {
196 match ::util::os_str_to_cstring(attribute) {
197 Ok(attr) => {
198 ::util::ptr_to_os_str(unsafe {
199 ::ffi::udev_device_get_sysattr_value(self.device, attr.as_ptr())
200 })
201 },
202 Err(_) => None,
203 }
204 }
205
206 pub fn set_attribute_value<T: AsRef<OsStr>, U: AsRef<OsStr>>(&mut self, attribute: T, value: U) -> ::Result<()> {
208 let attribute = try!(::util::os_str_to_cstring(attribute));
209 let value = try!(::util::os_str_to_cstring(value));
210
211 ::util::errno_to_result(unsafe {
212 ::ffi::udev_device_set_sysattr_value(self.device, attribute.as_ptr(), value.as_ptr() as *mut c_char)
213 })
214 }
215
216 pub fn properties(&self) -> Properties {
231 Properties {
232 _device: PhantomData,
233 entry: unsafe { ::ffi::udev_device_get_properties_list_entry(self.device) },
234 }
235 }
236
237 pub fn attributes(&self) -> Attributes {
252 Attributes {
253 device: self,
254 entry: unsafe { ::ffi::udev_device_get_sysattr_list_entry(self.device) },
255 }
256 }
257}
258
259
260pub struct Properties<'a> {
262 _device: PhantomData<&'a Device>,
263 entry: *mut ::ffi::udev_list_entry,
264}
265
266impl<'a> Iterator for Properties<'a> {
267 type Item = Property<'a>;
268
269 fn next(&mut self) -> Option<Property<'a>> {
270 if !self.entry.is_null() {
271 unsafe {
272 let name = ::util::ptr_to_os_str_unchecked(::ffi::udev_list_entry_get_name(self.entry));
273 let value = ::util::ptr_to_os_str_unchecked(::ffi::udev_list_entry_get_value(self.entry));
274
275 self.entry = ::ffi::udev_list_entry_get_next(self.entry);
276
277 Some(Property {
278 name: name,
279 value: value,
280 })
281 }
282 }
283 else {
284 None
285 }
286 }
287
288 fn size_hint(&self) -> (usize, Option<usize>) {
289 (0, None)
290 }
291}
292
293pub struct Property<'a> {
295 name: &'a OsStr,
296 value: &'a OsStr,
297}
298
299impl<'a> Property<'a> {
300 pub fn name(&self) -> &OsStr {
302 self.name
303 }
304
305 pub fn value(&self) -> &OsStr {
307 self.value
308 }
309}
310
311
312pub struct Attributes<'a> {
314 device: &'a Device,
315 entry: *mut ::ffi::udev_list_entry,
316}
317
318impl<'a> Iterator for Attributes<'a> {
319 type Item = Attribute<'a>;
320
321 fn next(&mut self) -> Option<Attribute<'a>> {
322 if !self.entry.is_null() {
323 let name = unsafe { ::util::ptr_to_os_str_unchecked(::ffi::udev_list_entry_get_name(self.entry)) };
324
325 self.entry = unsafe { ::ffi::udev_list_entry_get_next(self.entry) };
326
327 Some(Attribute {
328 device: self.device,
329 name: name,
330 })
331 }
332 else {
333 None
334 }
335 }
336
337 fn size_hint(&self) -> (usize, Option<usize>) {
338 (0, None)
339 }
340}
341
342pub struct Attribute<'a> {
344 device: &'a Device,
345 name: &'a OsStr,
346}
347
348impl<'a> Attribute<'a> {
349 pub fn name(&self) -> &OsStr {
351 self.name
352 }
353
354 pub fn value(&self) -> Option<&OsStr> {
356 self.device.attribute_value(self.name)
357 }
358}