libudev/
enumerator.rs

1use std::ffi::OsStr;
2use std::marker::PhantomData;
3use std::path::Path;
4
5use ::context::Context;
6use ::device::Device;
7use ::handle::Handle;
8
9
10/// An enumeration context.
11///
12/// An Enumerator scans `/sys` for devices matching its filters. Filters are added to an Enumerator
13/// by calling its `match_*` and `nomatch_*` methods. After the filters are setup, the
14/// `scan_devices()` method finds devices in `/sys` that match the filters.
15pub struct Enumerator {
16    enumerator: *mut ::ffi::udev_enumerate,
17}
18
19impl Drop for Enumerator {
20    fn drop(&mut self) {
21        unsafe {
22            let udev = ::ffi::udev_enumerate_get_udev(self.enumerator);
23
24            ::ffi::udev_enumerate_unref(self.enumerator);
25            ::ffi::udev_unref(udev);
26        };
27    }
28}
29
30impl Enumerator {
31    /// Creates a new Enumerator.
32    pub fn new(context: &Context) -> ::Result<Self> {
33        unsafe {
34            let ptr = try_alloc!(
35                ::ffi::udev_enumerate_new(context.as_ptr())
36            );
37
38            ::ffi::udev_ref(context.as_ptr());
39
40            Ok(Enumerator { enumerator: ptr })
41        }
42    }
43
44    /// Adds a filter that matches only initialized devices.
45    pub fn match_is_initialized(&mut self) -> ::Result<()> {
46        ::util::errno_to_result(unsafe {
47            ::ffi::udev_enumerate_add_match_is_initialized(self.enumerator)
48        })
49    }
50
51    /// Adds a filter that matches only devices that belong to the given kernel subsystem.
52    pub fn match_subsystem<T: AsRef<OsStr>>(&mut self, subsystem: T) -> ::Result<()> {
53        let subsystem = try!(::util::os_str_to_cstring(subsystem));
54
55        ::util::errno_to_result(unsafe {
56            ::ffi::udev_enumerate_add_match_subsystem(self.enumerator, subsystem.as_ptr())
57        })
58    }
59
60    /// Adds a filter that matches only devices with the given attribute value.
61    pub fn match_attribute<T: AsRef<OsStr>, U: AsRef<OsStr>>(&mut self, attribute: T, value: U) -> ::Result<()> {
62        let attribute = try!(::util::os_str_to_cstring(attribute));
63        let value = try!(::util::os_str_to_cstring(value));
64
65        ::util::errno_to_result(unsafe {
66            ::ffi::udev_enumerate_add_match_sysattr(self.enumerator, attribute.as_ptr(), value.as_ptr())
67        })
68    }
69
70    /// Adds a filter that matches only devices with the given kernel device name.
71    pub fn match_sysname<T: AsRef<OsStr>>(&mut self, sysname: T) -> ::Result<()> {
72        let sysname = try!(::util::os_str_to_cstring(sysname));
73
74        ::util::errno_to_result(unsafe {
75            ::ffi::udev_enumerate_add_match_sysname(self.enumerator, sysname.as_ptr())
76        })
77    }
78
79    /// Adds a filter that matches only devices with the given property value.
80    pub fn match_property<T: AsRef<OsStr>, U: AsRef<OsStr>>(&mut self, property: T, value: U) -> ::Result<()> {
81        let property = try!(::util::os_str_to_cstring(property));
82        let value = try!(::util::os_str_to_cstring(value));
83
84        ::util::errno_to_result(unsafe {
85            ::ffi::udev_enumerate_add_match_property(self.enumerator, property.as_ptr(), value.as_ptr())
86        })
87    }
88
89    /// Adds a filter that matches only devices with the given tag.
90    pub fn match_tag<T: AsRef<OsStr>>(&mut self, tag: T) -> ::Result<()> {
91        let tag = try!(::util::os_str_to_cstring(tag));
92
93        ::util::errno_to_result(unsafe {
94            ::ffi::udev_enumerate_add_match_tag(self.enumerator, tag.as_ptr())
95        })
96    }
97
98    /// Includes the parent device and all devices in the subtree of the parent device.
99    pub fn match_parent(&mut self, parent: &Device) -> ::Result<()> {
100        ::util::errno_to_result(unsafe {
101            ::ffi::udev_enumerate_add_match_parent(self.enumerator, parent.as_ptr())
102        })
103    }
104
105    /// Adds a filter that matches only devices that don't belong to the given kernel subsystem.
106    pub fn nomatch_subsystem<T: AsRef<OsStr>>(&mut self, subsystem: T) -> ::Result<()> {
107        let subsystem = try!(::util::os_str_to_cstring(subsystem));
108
109        ::util::errno_to_result(unsafe {
110            ::ffi::udev_enumerate_add_nomatch_subsystem(self.enumerator, subsystem.as_ptr())
111        })
112    }
113
114    /// Adds a filter that matches only devices that don't have the the given attribute value.
115    pub fn nomatch_attribute<T: AsRef<OsStr>, U: AsRef<OsStr>>(&mut self, attribute: T, value: U) -> ::Result<()> {
116        let attribute = try!(::util::os_str_to_cstring(attribute));
117        let value = try!(::util::os_str_to_cstring(value));
118
119        ::util::errno_to_result(unsafe {
120            ::ffi::udev_enumerate_add_nomatch_sysattr(self.enumerator, attribute.as_ptr(), value.as_ptr())
121        })
122    }
123
124    /// Includes the device with the given syspath.
125    pub fn add_syspath(&mut self, syspath: &Path) -> ::Result<()> {
126        let syspath = try!(::util::os_str_to_cstring(syspath));
127
128        ::util::errno_to_result(unsafe {
129            ::ffi::udev_enumerate_add_syspath(self.enumerator, syspath.as_ptr())
130        })
131    }
132
133    /// Scans `/sys` for devices matching the attached filters.
134    ///
135    /// The devices will be sorted in dependency order.
136    pub fn scan_devices(&mut self) -> ::Result<Devices> {
137        try!(::util::errno_to_result(unsafe {
138            ::ffi::udev_enumerate_scan_devices(self.enumerator)
139        }));
140
141        unsafe {
142            Ok(Devices {
143                _enumerator: PhantomData,
144                udev: ::ffi::udev_enumerate_get_udev(self.enumerator),
145                entry: ::ffi::udev_enumerate_get_list_entry(self.enumerator),
146            })
147        }
148    }
149}
150
151
152/// Iterator over devices.
153pub struct Devices<'a> {
154    _enumerator: PhantomData<&'a Enumerator>,
155    udev: *mut ::ffi::udev,
156    entry: *mut ::ffi::udev_list_entry,
157}
158
159impl<'a> Iterator for Devices<'a> {
160    type Item = Device;
161
162    fn next(&mut self) -> Option<Device> {
163        while !self.entry.is_null() {
164            unsafe {
165                let syspath = ::ffi::udev_list_entry_get_name(self.entry);
166
167                self.entry = ::ffi::udev_list_entry_get_next(self.entry);
168
169                let device = ::ffi::udev_device_new_from_syspath(self.udev, syspath);
170
171                if !device.is_null() {
172                    return Some(::device::from_raw(device));
173                }
174                else {
175                    continue;
176                }
177            };
178        }
179
180        None
181    }
182
183    fn size_hint(&self) -> (usize, Option<usize>) {
184        (0, None)
185    }
186}