summaryrefslogtreecommitdiffstats
path: root/third_party/rust/libudev
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/libudev')
-rw-r--r--third_party/rust/libudev/.cargo-checksum.json1
-rw-r--r--third_party/rust/libudev/Cargo.toml15
-rw-r--r--third_party/rust/libudev/LICENSE20
-rw-r--r--third_party/rust/libudev/README.md67
-rw-r--r--third_party/rust/libudev/examples/list_devices.rs45
-rw-r--r--third_party/rust/libudev/examples/monitor.rs70
-rw-r--r--third_party/rust/libudev/src/context.rs47
-rw-r--r--third_party/rust/libudev/src/device.rs340
-rw-r--r--third_party/rust/libudev/src/enumerator.rs171
-rw-r--r--third_party/rust/libudev/src/error.rs76
-rw-r--r--third_party/rust/libudev/src/handle.rs7
-rw-r--r--third_party/rust/libudev/src/lib.rs29
-rw-r--r--third_party/rust/libudev/src/monitor.rs211
-rw-r--r--third_party/rust/libudev/src/util.rs33
14 files changed, 1132 insertions, 0 deletions
diff --git a/third_party/rust/libudev/.cargo-checksum.json b/third_party/rust/libudev/.cargo-checksum.json
new file mode 100644
index 0000000000..3507f01577
--- /dev/null
+++ b/third_party/rust/libudev/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"Cargo.toml":"a3144a56dea1604c3ad249ff68c7b343c589df72b9de0bde4e1656c7c56edf7e","LICENSE":"871afd9d691846de71e0b83812ba9c7ff00bc7b3ad102dedcaa109f2246d52ad","README.md":"e0585b8675215bc6990055477104786f567dee8ce31a59f0c11421b5ad9529a7","examples/list_devices.rs":"9cb549127f2cad350223646332dc39a674ca765095553cdd2ef47cfd0b108535","examples/monitor.rs":"5631686fe2957f1c8236da9620fea3d3360bb15408827996a1b86d40cf80ba0e","src/context.rs":"26f22d5335aadeb4daa4abfb76363f95651662542c889e2ed5352a1dcebca225","src/device.rs":"01ae029537f8734cfc0e4b33b4f3890595caa707925d339c2914d80f70c8f938","src/enumerator.rs":"1f0a12e2b47fc293aaa5b2a5318aa6a0859772af80ba2195e2d83f465b606988","src/error.rs":"5c219d200b2c6dc0aabb4d916190581922c8ede8361235502eeb1d07b2dcb4a0","src/handle.rs":"86f7cfe4ed8eea20b26322dafb17054b9f42e117ae39725659254808b10b12eb","src/lib.rs":"6556d2be078163881321c27dde73c491b6ecb5fcba4b639942bd111f979fa10f","src/monitor.rs":"f271d92e6e723e0346733c33293119f1df43c46913456e9dcf7a6765d1d3ab78","src/util.rs":"f0e1bc2bdbb68047ed8710ed33d80685e4d3acdb20ccf79b0f45932060ac4bd8"},"package":"ea626d3bdf40a1c5aee3bcd4f40826970cae8d80a8fec934c82a63840094dcfe"} \ No newline at end of file
diff --git a/third_party/rust/libudev/Cargo.toml b/third_party/rust/libudev/Cargo.toml
new file mode 100644
index 0000000000..4e3ff1b8b6
--- /dev/null
+++ b/third_party/rust/libudev/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "libudev"
+version = "0.2.0"
+authors = ["David Cuddeback <david.cuddeback@gmail.com>"]
+description = "Rust wrapper for libudev"
+license = "MIT"
+homepage = "https://github.com/dcuddeback/libudev-rs"
+repository = "https://github.com/dcuddeback/libudev-rs"
+documentation = "http://dcuddeback.github.io/libudev-rs/libudev/"
+keywords = ["udev", "hardware", "bindings", "sysfs", "systemd"]
+readme = "README.md"
+
+[dependencies]
+libudev-sys = "0.1.3"
+libc = "0.2"
diff --git a/third_party/rust/libudev/LICENSE b/third_party/rust/libudev/LICENSE
new file mode 100644
index 0000000000..19f28b12c2
--- /dev/null
+++ b/third_party/rust/libudev/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2015 David Cuddeback
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/third_party/rust/libudev/README.md b/third_party/rust/libudev/README.md
new file mode 100644
index 0000000000..a4e9984352
--- /dev/null
+++ b/third_party/rust/libudev/README.md
@@ -0,0 +1,67 @@
+# Libudev
+This crate provides a safe wrapper around the native `libudev` library. It applies the RAII pattern
+and Rust lifetimes to ensure safe usage of all `libudev` functionality. The RAII pattern ensures
+that all acquired resources are released when they're no longer needed, and Rust lifetimes ensure
+that resources are released in a proper order.
+
+* [Documentation](http://dcuddeback.github.io/libudev-rs/libudev/)
+
+## Dependencies
+In order to use the `libudev` crate, you must have a Linux system with the `libudev` library
+installed where it can be found by `pkg-config`. To install `libudev` on Debian-based Linux
+distributions, execute the following command:
+
+```
+sudo apt-get install libudev-dev
+```
+
+`libudev` is a Linux-specific package. It is not available for Windows, OS X, or other operating
+systems.
+
+### Cross-Compiling
+The `libudev` crate can be used when cross-compiling to a foreign target. Details on how to
+cross-compile `libudev` are explained in the [`libudev-sys` crate's
+README](https://github.com/dcuddeback/libudev-sys#cross-compiling).
+
+## Usage
+Add `libudev` as a dependency in `Cargo.toml`:
+
+```toml
+[dependencies]
+libudev = "0.2"
+```
+
+If you plan to support operating systems other than Linux, you'll need to add `libudev` as a
+target-specific dependency:
+
+```toml
+[target.x86_64-unknown-linux-gnu.dependencies]
+libudev = "0.2"
+```
+
+Import the `libudev` crate. The starting point for nearly all `libudev` functionality is to create a
+context object.
+
+```rust
+extern crate libudev;
+
+fn main() {
+ let context = libudev::Context::new().unwrap();
+ let mut enumerator = libudev::Enumerator::new(&context).unwrap();
+
+ enumerator.match_subsystem("tty").unwrap();
+
+ for device in enumerator.scan_devices().unwrap() {
+ println!("found device: {:?}", device.syspath());
+ }
+}
+```
+
+## Contributors
+* [dcuddeback](https://github.com/dcuddeback)
+* [Susurrus](https://github.com/Susurrus)
+
+## License
+Copyright © 2015 David Cuddeback
+
+Distributed under the [MIT License](LICENSE).
diff --git a/third_party/rust/libudev/examples/list_devices.rs b/third_party/rust/libudev/examples/list_devices.rs
new file mode 100644
index 0000000000..5ef71765de
--- /dev/null
+++ b/third_party/rust/libudev/examples/list_devices.rs
@@ -0,0 +1,45 @@
+extern crate libudev;
+
+use std::io;
+
+fn main() {
+ let context = libudev::Context::new().unwrap();
+ list_devices(&context).unwrap();
+}
+
+fn list_devices(context: &libudev::Context) -> io::Result<()> {
+ let mut enumerator = try!(libudev::Enumerator::new(&context));
+
+ for device in try!(enumerator.scan_devices()) {
+ println!("");
+ println!("initialized: {:?}", device.is_initialized());
+ println!(" devnum: {:?}", device.devnum());
+ println!(" syspath: {:?}", device.syspath());
+ println!(" devpath: {:?}", device.devpath());
+ println!(" subsystem: {:?}", device.subsystem());
+ println!(" sysname: {:?}", device.sysname());
+ println!(" sysnum: {:?}", device.sysnum());
+ println!(" devtype: {:?}", device.devtype());
+ println!(" driver: {:?}", device.driver());
+ println!(" devnode: {:?}", device.devnode());
+
+ if let Some(parent) = device.parent() {
+ println!(" parent: {:?}", parent.syspath());
+ }
+ else {
+ println!(" parent: None");
+ }
+
+ println!(" [properties]");
+ for property in device.properties() {
+ println!(" - {:?} {:?}", property.name(), property.value());
+ }
+
+ println!(" [attributes]");
+ for attribute in device.attributes() {
+ println!(" - {:?} {:?}", attribute.name(), attribute.value());
+ }
+ }
+
+ Ok(())
+}
diff --git a/third_party/rust/libudev/examples/monitor.rs b/third_party/rust/libudev/examples/monitor.rs
new file mode 100644
index 0000000000..ad9dedcbd0
--- /dev/null
+++ b/third_party/rust/libudev/examples/monitor.rs
@@ -0,0 +1,70 @@
+extern crate libudev;
+extern crate libc;
+
+use std::io;
+use std::ptr;
+use std::thread;
+use std::time::Duration;
+
+use std::os::unix::io::{AsRawFd};
+
+use libc::{c_void,c_int,c_short,c_ulong,timespec};
+
+#[repr(C)]
+struct pollfd {
+ fd: c_int,
+ events: c_short,
+ revents: c_short,
+}
+
+#[repr(C)]
+struct sigset_t {
+ __private: c_void
+}
+
+#[allow(non_camel_case_types)]
+type nfds_t = c_ulong;
+
+const POLLIN: c_short = 0x0001;
+
+extern "C" {
+ fn ppoll(fds: *mut pollfd, nfds: nfds_t, timeout_ts: *mut libc::timespec, sigmask: *const sigset_t) -> c_int;
+}
+
+fn main() {
+ let context = libudev::Context::new().unwrap();
+ monitor(&context).unwrap();
+}
+
+fn monitor(context: &libudev::Context) -> io::Result<()> {
+ let mut monitor = try!(libudev::Monitor::new(&context));
+
+ try!(monitor.match_subsystem_devtype("usb", "usb_device"));
+ let mut socket = try!(monitor.listen());
+
+ let mut fds = vec!(pollfd { fd: socket.as_raw_fd(), events: POLLIN, revents: 0 });
+
+ loop {
+ let result = unsafe { ppoll((&mut fds[..]).as_mut_ptr(), fds.len() as nfds_t, ptr::null_mut(), ptr::null()) };
+
+ if result < 0 {
+ return Err(io::Error::last_os_error());
+ }
+
+ let event = match socket.receive_event() {
+ Some(evt) => evt,
+ None => {
+ thread::sleep(Duration::from_millis(10));
+ continue;
+ }
+ };
+
+ println!("{}: {} {} (subsystem={}, sysname={}, devtype={})",
+ event.sequence_number(),
+ event.event_type(),
+ event.syspath().to_str().unwrap_or("---"),
+ event.subsystem().to_str().unwrap_or(""),
+ event.sysname().to_str().unwrap_or(""),
+ event.devtype().map_or("", |s| { s.to_str().unwrap_or("") }));
+ }
+}
diff --git a/third_party/rust/libudev/src/context.rs b/third_party/rust/libudev/src/context.rs
new file mode 100644
index 0000000000..95252611e4
--- /dev/null
+++ b/third_party/rust/libudev/src/context.rs
@@ -0,0 +1,47 @@
+use std::path::Path;
+
+use ::device::{Device};
+use ::handle::{Handle};
+
+/// A libudev context.
+pub struct Context {
+ udev: *mut ::ffi::udev
+}
+
+impl Drop for Context {
+ fn drop(&mut self) {
+ unsafe {
+ ::ffi::udev_unref(self.udev);
+ }
+ }
+}
+
+#[doc(hidden)]
+impl Handle<::ffi::udev> for Context {
+ fn as_ptr(&self) -> *mut ::ffi::udev {
+ self.udev
+ }
+}
+
+impl Context {
+ /// Creates a new context.
+ pub fn new() -> ::Result<Self> {
+ let ptr = try_alloc!(unsafe { ::ffi::udev_new() });
+
+ Ok(Context { udev: ptr })
+ }
+
+ /// Creates a device for a given syspath.
+ ///
+ /// The `syspath` parameter should be a path to the device file within the `sysfs` file system,
+ /// e.g., `/sys/devices/virtual/tty/tty0`.
+ pub fn device_from_syspath(&self, syspath: &Path) -> ::Result<Device> {
+ let syspath = try!(::util::os_str_to_cstring(syspath));
+
+ let ptr = try_alloc!(unsafe {
+ ::ffi::udev_device_new_from_syspath(self.udev, syspath.as_ptr())
+ });
+
+ Ok(::device::new(self, ptr))
+ }
+}
diff --git a/third_party/rust/libudev/src/device.rs b/third_party/rust/libudev/src/device.rs
new file mode 100644
index 0000000000..736e7b58ff
--- /dev/null
+++ b/third_party/rust/libudev/src/device.rs
@@ -0,0 +1,340 @@
+use std::str;
+
+use std::ffi::{CStr,OsStr};
+use std::path::Path;
+use std::str::FromStr;
+
+use libc::{c_char,dev_t};
+
+use ::context::Context;
+use ::handle::*;
+
+pub fn new(context: &Context, device: *mut ::ffi::udev_device) -> Device {
+ Device {
+ _context: context,
+ device: device,
+ }
+}
+
+/// A structure that provides access to sysfs/kernel devices.
+pub struct Device<'a> {
+ _context: &'a Context,
+ device: *mut ::ffi::udev_device,
+}
+
+impl<'a> Drop for Device<'a> {
+ fn drop(&mut self) {
+ unsafe {
+ ::ffi::udev_device_unref(self.device);
+ }
+ }
+}
+
+#[doc(hidden)]
+impl<'a> Handle<::ffi::udev_device> for Device<'a> {
+ fn as_ptr(&self) -> *mut ::ffi::udev_device {
+ self.device
+ }
+}
+
+impl<'a> Device<'a> {
+ /// Checks whether the device has already been handled by udev.
+ ///
+ /// When a new device is connected to the system, udev initializes the device by setting
+ /// permissions, renaming network devices, and possibly other initialization routines. This
+ /// method returns `true` if udev has performed all of its work to initialize this device.
+ ///
+ /// This method only applies to devices with device nodes or network interfaces. All other
+ /// devices return `true` by default.
+ pub fn is_initialized(&self) -> bool {
+ unsafe {
+ ::ffi::udev_device_get_is_initialized(self.device) > 0
+ }
+ }
+
+ /// Gets the device's major/minor number.
+ pub fn devnum(&self) -> Option<dev_t> {
+ match unsafe { ::ffi::udev_device_get_devnum(self.device) } {
+ 0 => None,
+ n => Some(n)
+ }
+ }
+
+ /// Returns the syspath of the device.
+ ///
+ /// The path is an absolute path and includes the sys mount point. For example, the syspath for
+ /// `tty0` could be `/sys/devices/virtual/tty/tty0`, which includes the sys mount point,
+ /// `/sys`.
+ pub fn syspath(&self) -> &Path {
+ Path::new(unsafe {
+ ::util::ptr_to_os_str_unchecked(::ffi::udev_device_get_syspath(self.device))
+ })
+ }
+
+ /// Returns the kernel devpath value of the device.
+ ///
+ /// The path does not contain the sys mount point, but does start with a `/`. For example, the
+ /// devpath for `tty0` could be `/devices/virtual/tty/tty0`.
+ pub fn devpath(&self) -> &OsStr {
+ unsafe {
+ ::util::ptr_to_os_str_unchecked(::ffi::udev_device_get_devpath(self.device))
+ }
+ }
+
+ /// Returns the path to the device node belonging to the device.
+ ///
+ /// The path is an absolute path and starts with the device directory. For example, the device
+ /// node for `tty0` could be `/dev/tty0`.
+ pub fn devnode(&self) -> Option<&Path> {
+ ::util::ptr_to_os_str(unsafe { ::ffi::udev_device_get_devnode(self.device) }).map(|path| {
+ Path::new(path)
+ })
+ }
+
+ /// Returns the parent of the device.
+ pub fn parent(&self) -> Option<Device> {
+ let ptr = unsafe { ::ffi::udev_device_get_parent(self.device) };
+
+ if !ptr.is_null() {
+ unsafe {
+ ::ffi::udev_device_ref(ptr);
+ }
+
+ Some(Device {
+ _context: self._context,
+ device: ptr,
+ })
+ }
+ else {
+ None
+ }
+ }
+
+ /// Returns the subsystem name of the device.
+ ///
+ /// The subsystem name is a string that indicates which kernel subsystem the device belongs to.
+ /// Examples of subsystem names are `tty`, `vtconsole`, `block`, `scsi`, and `net`.
+ pub fn subsystem(&self) -> &OsStr {
+ unsafe {
+ ::util::ptr_to_os_str_unchecked(::ffi::udev_device_get_subsystem(self.device))
+ }
+ }
+
+ /// Returns the kernel device name for the device.
+ ///
+ /// The sysname is a string that differentiates the device from others in the same subsystem.
+ /// For example, `tty0` is the sysname for a TTY device that differentiates it from others,
+ /// such as `tty1`.
+ pub fn sysname(&self) -> &OsStr {
+ unsafe {
+ ::util::ptr_to_os_str_unchecked(::ffi::udev_device_get_sysname(self.device))
+ }
+ }
+
+ /// Returns the instance number of the device.
+ ///
+ /// The instance number is used to differentiate many devices of the same type. For example,
+ /// `/dev/tty0` and `/dev/tty1` are both TTY devices but have instance numbers of 0 and 1,
+ /// respectively.
+ ///
+ /// Some devices don't have instance numbers, such as `/dev/console`, in which case the method
+ /// returns `None`.
+ pub fn sysnum(&self) -> Option<usize> {
+ let ptr = unsafe { ::ffi::udev_device_get_sysnum(self.device) };
+
+ if !ptr.is_null() {
+ match str::from_utf8(unsafe { CStr::from_ptr(ptr) }.to_bytes()) {
+ Err(_) => None,
+ Ok(s) => FromStr::from_str(s).ok()
+ }
+ }
+ else {
+ None
+ }
+ }
+
+ /// Returns the devtype name of the device.
+ pub fn devtype(&self) -> Option<&OsStr> {
+ ::util::ptr_to_os_str(unsafe { ::ffi::udev_device_get_devtype(self.device) })
+ }
+
+ /// Returns the name of the kernel driver attached to the device.
+ pub fn driver(&self) -> Option<&OsStr> {
+ ::util::ptr_to_os_str(unsafe { ::ffi::udev_device_get_driver(self.device) })
+ }
+
+ /// Retreives the value of a device property.
+ pub fn property_value<T: AsRef<OsStr>>(&self, property: T) -> Option<&OsStr> {
+ let prop = match ::util::os_str_to_cstring(property) {
+ Ok(s) => s,
+ Err(_) => return None
+ };
+
+ ::util::ptr_to_os_str(unsafe {
+ ::ffi::udev_device_get_property_value(self.device, prop.as_ptr())
+ })
+ }
+
+ /// Retreives the value of a device attribute.
+ pub fn attribute_value<T: AsRef<OsStr>>(&self, attribute: T) -> Option<&OsStr> {
+ let attr = match ::util::os_str_to_cstring(attribute) {
+ Ok(s) => s,
+ Err(_) => return None
+ };
+
+ ::util::ptr_to_os_str(unsafe {
+ ::ffi::udev_device_get_sysattr_value(self.device, attr.as_ptr())
+ })
+ }
+
+ /// Sets the value of a device attribute.
+ pub fn set_attribute_value<T: AsRef<OsStr>, U: AsRef<OsStr>>(&mut self, attribute: T, value: U) -> ::Result<()> {
+ let attribute = try!(::util::os_str_to_cstring(attribute));
+ let value = try!(::util::os_str_to_cstring(value));
+
+ ::util::errno_to_result(unsafe {
+ ::ffi::udev_device_set_sysattr_value(self.device, attribute.as_ptr(), value.as_ptr() as *mut c_char)
+ })
+ }
+
+ /// Returns an iterator over the device's properties.
+ ///
+ /// ## Example
+ ///
+ /// This example prints out all of a device's properties:
+ ///
+ /// ```no_run
+ /// # use std::path::Path;
+ /// # let mut context = libudev::Context::new().unwrap();
+ /// # let device = context.device_from_syspath(Path::new("/sys/devices/virtual/tty/tty0")).unwrap();
+ /// for property in device.properties() {
+ /// println!("{:?} = {:?}", property.name(), property.value());
+ /// }
+ /// ```
+ pub fn properties(&self) -> Properties {
+ Properties {
+ _device: self,
+ entry: unsafe { ::ffi::udev_device_get_properties_list_entry(self.device) }
+ }
+ }
+
+ /// Returns an iterator over the device's attributes.
+ ///
+ /// ## Example
+ ///
+ /// This example prints out all of a device's attributes:
+ ///
+ /// ```no_run
+ /// # use std::path::Path;
+ /// # let mut context = libudev::Context::new().unwrap();
+ /// # let device = context.device_from_syspath(Path::new("/sys/devices/virtual/tty/tty0")).unwrap();
+ /// for attribute in device.attributes() {
+ /// println!("{:?} = {:?}", attribute.name(), attribute.value());
+ /// }
+ /// ```
+ pub fn attributes(&self) -> Attributes {
+ Attributes {
+ device: self,
+ entry: unsafe { ::ffi::udev_device_get_sysattr_list_entry(self.device) }
+ }
+ }
+}
+
+
+/// Iterator over a device's properties.
+pub struct Properties<'a> {
+ _device: &'a Device<'a>,
+ entry: *mut ::ffi::udev_list_entry
+}
+
+impl<'a> Iterator for Properties<'a> {
+ type Item = Property<'a>;
+
+ fn next(&mut self) -> Option<Property<'a>> {
+ if self.entry.is_null() {
+ None
+ }
+ else {
+ let name = unsafe { ::util::ptr_to_os_str_unchecked(::ffi::udev_list_entry_get_name(self.entry)) };
+ let value = unsafe { ::util::ptr_to_os_str_unchecked(::ffi::udev_list_entry_get_value(self.entry)) };
+
+ self.entry = unsafe { ::ffi::udev_list_entry_get_next(self.entry) };
+
+ Some(Property {
+ name: name,
+ value: value
+ })
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (0, None)
+ }
+}
+
+/// A device property.
+pub struct Property<'a> {
+ name: &'a OsStr,
+ value: &'a OsStr
+}
+
+impl<'a> Property<'a> {
+ /// Returns the property name.
+ pub fn name(&self) -> &OsStr {
+ self.name
+ }
+
+ /// Returns the property value.
+ pub fn value(&self) -> &OsStr {
+ self.value
+ }
+}
+
+
+/// Iterator over a device's attributes.
+pub struct Attributes<'a> {
+ device: &'a Device<'a>,
+ entry: *mut ::ffi::udev_list_entry
+}
+
+impl<'a> Iterator for Attributes<'a> {
+ type Item = Attribute<'a>;
+
+ fn next(&mut self) -> Option<Attribute<'a>> {
+ if !self.entry.is_null() {
+ let name = unsafe { ::util::ptr_to_os_str_unchecked(::ffi::udev_list_entry_get_name(self.entry)) };
+
+ self.entry = unsafe { ::ffi::udev_list_entry_get_next(self.entry) };
+
+ Some(Attribute {
+ device: self.device,
+ name: name
+ })
+ }
+ else {
+ None
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (0, None)
+ }
+}
+
+/// A device attribute.
+pub struct Attribute<'a> {
+ device: &'a Device<'a>,
+ name: &'a OsStr
+}
+
+impl<'a> Attribute<'a> {
+ /// Returns the attribute name.
+ pub fn name(&self) -> &OsStr {
+ self.name
+ }
+
+ /// Returns the attribute value.
+ pub fn value(&self) -> Option<&OsStr> {
+ self.device.attribute_value(self.name)
+ }
+}
diff --git a/third_party/rust/libudev/src/enumerator.rs b/third_party/rust/libudev/src/enumerator.rs
new file mode 100644
index 0000000000..641d68a2c1
--- /dev/null
+++ b/third_party/rust/libudev/src/enumerator.rs
@@ -0,0 +1,171 @@
+use std::ffi::{OsStr};
+use std::path::Path;
+
+use ::handle::prelude::*;
+
+pub use context::{Context};
+pub use device::{Device};
+
+
+/// An enumeration context.
+///
+/// An Enumerator scans `/sys` for devices matching its filters. Filters are added to an Enumerator
+/// by calling its `match_*` and `nomatch_*` methods. After the filters are setup, the
+/// `scan_devices()` method finds devices in `/sys` that match the filters.
+pub struct Enumerator<'a> {
+ context: &'a Context,
+ enumerator: *mut ::ffi::udev_enumerate
+}
+
+impl<'a> Drop for Enumerator<'a> {
+ fn drop(&mut self) {
+ unsafe { ::ffi::udev_enumerate_unref(self.enumerator) };
+ }
+}
+
+impl<'a> Enumerator<'a> {
+ /// Creates a new Enumerator.
+ pub fn new(context: &'a Context) -> ::Result<Self> {
+ let ptr = try_alloc!(unsafe { ::ffi::udev_enumerate_new(context.as_ptr()) });
+
+ Ok(Enumerator {
+ context: context,
+ enumerator: ptr
+ })
+ }
+
+ /// Adds a filter that matches only initialized devices.
+ pub fn match_is_initialized(&mut self) -> ::Result<()> {
+ ::util::errno_to_result(unsafe {
+ ::ffi::udev_enumerate_add_match_is_initialized(self.enumerator)
+ })
+ }
+
+ /// Adds a filter that matches only devices that belong to the given kernel subsystem.
+ pub fn match_subsystem<T: AsRef<OsStr>>(&mut self, subsystem: T) -> ::Result<()> {
+ let subsystem = try!(::util::os_str_to_cstring(subsystem));
+
+ ::util::errno_to_result(unsafe {
+ ::ffi::udev_enumerate_add_match_subsystem(self.enumerator, subsystem.as_ptr())
+ })
+ }
+
+ /// Adds a filter that matches only devices with the given attribute value.
+ pub fn match_attribute<T: AsRef<OsStr>, U: AsRef<OsStr>>(&mut self, attribute: T, value: U) -> ::Result<()> {
+ let attribute = try!(::util::os_str_to_cstring(attribute));
+ let value = try!(::util::os_str_to_cstring(value));
+
+ ::util::errno_to_result(unsafe {
+ ::ffi::udev_enumerate_add_match_sysattr(self.enumerator, attribute.as_ptr(), value.as_ptr())
+ })
+ }
+
+ /// Adds a filter that matches only devices with the given kernel device name.
+ pub fn match_sysname<T: AsRef<OsStr>>(&mut self, sysname: T) -> ::Result<()> {
+ let sysname = try!(::util::os_str_to_cstring(sysname));
+
+ ::util::errno_to_result(unsafe {
+ ::ffi::udev_enumerate_add_match_sysname(self.enumerator, sysname.as_ptr())
+ })
+ }
+
+ /// Adds a filter that matches only devices with the given property value.
+ pub fn match_property<T: AsRef<OsStr>, U: AsRef<OsStr>>(&mut self, property: T, value: U) -> ::Result<()> {
+ let property = try!(::util::os_str_to_cstring(property));
+ let value = try!(::util::os_str_to_cstring(value));
+
+ ::util::errno_to_result(unsafe {
+ ::ffi::udev_enumerate_add_match_property(self.enumerator, property.as_ptr(), value.as_ptr())
+ })
+ }
+
+ /// Adds a filter that matches only devices with the given tag.
+ pub fn match_tag<T: AsRef<OsStr>>(&mut self, tag: T) -> ::Result<()> {
+ let tag = try!(::util::os_str_to_cstring(tag));
+
+ ::util::errno_to_result(unsafe {
+ ::ffi::udev_enumerate_add_match_tag(self.enumerator, tag.as_ptr())
+ })
+ }
+
+ /// Includes the parent device and all devices in the subtree of the parent device.
+ pub fn match_parent(&mut self, parent: &Device) -> ::Result<()> {
+ ::util::errno_to_result(unsafe {
+ ::ffi::udev_enumerate_add_match_parent(self.enumerator, parent.as_ptr())
+ })
+ }
+
+ /// Adds a filter that matches only devices that don't belong to the given kernel subsystem.
+ pub fn nomatch_subsystem<T: AsRef<OsStr>>(&mut self, subsystem: T) -> ::Result<()> {
+ let subsystem = try!(::util::os_str_to_cstring(subsystem));
+
+ ::util::errno_to_result(unsafe {
+ ::ffi::udev_enumerate_add_nomatch_subsystem(self.enumerator, subsystem.as_ptr())
+ })
+ }
+
+ /// Adds a filter that matches only devices that don't have the the given attribute value.
+ pub fn nomatch_attribute<T: AsRef<OsStr>, U: AsRef<OsStr>>(&mut self, attribute: T, value: U) -> ::Result<()> {
+ let attribute = try!(::util::os_str_to_cstring(attribute));
+ let value = try!(::util::os_str_to_cstring(value));
+
+ ::util::errno_to_result(unsafe {
+ ::ffi::udev_enumerate_add_nomatch_sysattr(self.enumerator, attribute.as_ptr(), value.as_ptr())
+ })
+ }
+
+ /// Includes the device with the given syspath.
+ pub fn add_syspath(&mut self, syspath: &Path) -> ::Result<()> {
+ let syspath = try!(::util::os_str_to_cstring(syspath));
+
+ ::util::errno_to_result(unsafe {
+ ::ffi::udev_enumerate_add_syspath(self.enumerator, syspath.as_ptr())
+ })
+ }
+
+ /// Scans `/sys` for devices matching the attached filters.
+ ///
+ /// The devices will be sorted in dependency order.
+ pub fn scan_devices(&mut self) -> ::Result<Devices> {
+ try!(::util::errno_to_result(unsafe {
+ ::ffi::udev_enumerate_scan_devices(self.enumerator)
+ }));
+
+ Ok(Devices {
+ enumerator: self,
+ entry: unsafe { ::ffi::udev_enumerate_get_list_entry(self.enumerator) }
+ })
+ }
+}
+
+
+/// Iterator over devices.
+pub struct Devices<'a> {
+ enumerator: &'a Enumerator<'a>,
+ entry: *mut ::ffi::udev_list_entry
+}
+
+impl<'a> Iterator for Devices<'a> {
+ type Item = Device<'a>;
+
+ fn next(&mut self) -> Option<Device<'a>> {
+ while !self.entry.is_null() {
+ let syspath = Path::new(unsafe {
+ ::util::ptr_to_os_str_unchecked(::ffi::udev_list_entry_get_name(self.entry))
+ });
+
+ self.entry = unsafe { ::ffi::udev_list_entry_get_next(self.entry) };
+
+ match self.enumerator.context.device_from_syspath(syspath) {
+ Ok(d) => return Some(d),
+ Err(_) => continue
+ };
+ }
+
+ None
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (0, None)
+ }
+}
diff --git a/third_party/rust/libudev/src/error.rs b/third_party/rust/libudev/src/error.rs
new file mode 100644
index 0000000000..2c503149c8
--- /dev/null
+++ b/third_party/rust/libudev/src/error.rs
@@ -0,0 +1,76 @@
+use std::ffi::CStr;
+use std::fmt;
+use std::io;
+use std::str;
+
+use std::error::Error as StdError;
+use std::result::Result as StdResult;
+
+use ::libc::c_int;
+
+/// A `Result` type for libudev operations.
+pub type Result<T> = StdResult<T,Error>;
+
+/// Types of errors that occur in libudev.
+#[derive(Debug,Clone,Copy,PartialEq,Eq)]
+pub enum ErrorKind {
+ NoMem,
+ InvalidInput,
+ Io(io::ErrorKind)
+}
+
+/// The error type for libudev operations.
+#[derive(Debug)]
+pub struct Error {
+ errno: c_int,
+}
+
+impl Error {
+ fn strerror(&self) -> &str {
+ unsafe {
+ str::from_utf8_unchecked(CStr::from_ptr(::libc::strerror(self.errno)).to_bytes())
+ }
+ }
+
+ /// Returns the corresponding `ErrorKind` for this error.
+ pub fn kind(&self) -> ErrorKind {
+ match self.errno {
+ ::libc::ENOMEM => ErrorKind::NoMem,
+ ::libc::EINVAL => ErrorKind::InvalidInput,
+ errno => ErrorKind::Io(io::Error::from_raw_os_error(errno).kind()),
+ }
+ }
+
+ /// Returns a description of the error.
+ pub fn description(&self) -> &str {
+ self.strerror()
+ }
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> StdResult<(),fmt::Error> {
+ fmt.write_str(self.strerror())
+ }
+}
+
+impl StdError for Error {
+ fn description(&self) -> &str {
+ self.strerror()
+ }
+}
+
+impl From<Error> for io::Error {
+ fn from(error: Error) -> io::Error {
+ let io_error_kind = match error.kind() {
+ ErrorKind::Io(kind) => kind,
+ ErrorKind::InvalidInput => io::ErrorKind::InvalidInput,
+ ErrorKind::NoMem => io::ErrorKind::Other,
+ };
+
+ io::Error::new(io_error_kind, error.strerror())
+ }
+}
+
+pub fn from_errno(errno: c_int) -> Error {
+ Error { errno: -errno }
+}
diff --git a/third_party/rust/libudev/src/handle.rs b/third_party/rust/libudev/src/handle.rs
new file mode 100644
index 0000000000..3cfd943a00
--- /dev/null
+++ b/third_party/rust/libudev/src/handle.rs
@@ -0,0 +1,7 @@
+pub mod prelude {
+ pub use super::Handle;
+}
+
+pub trait Handle<T> {
+ fn as_ptr(&self) -> *mut T;
+}
diff --git a/third_party/rust/libudev/src/lib.rs b/third_party/rust/libudev/src/lib.rs
new file mode 100644
index 0000000000..ac6be5c169
--- /dev/null
+++ b/third_party/rust/libudev/src/lib.rs
@@ -0,0 +1,29 @@
+extern crate libudev_sys as ffi;
+extern crate libc;
+
+pub use context::{Context};
+pub use device::{Device,Properties,Property,Attributes,Attribute};
+pub use enumerator::{Enumerator,Devices};
+pub use error::{Result,Error,ErrorKind};
+pub use monitor::{Monitor,MonitorSocket,EventType,Event};
+
+macro_rules! try_alloc {
+ ($exp:expr) => {{
+ let ptr = $exp;
+
+ if ptr.is_null() {
+ return Err(::error::from_errno(::libc::ENOMEM));
+ }
+
+ ptr
+ }}
+}
+
+mod context;
+mod device;
+mod enumerator;
+mod error;
+mod monitor;
+
+mod handle;
+mod util;
diff --git a/third_party/rust/libudev/src/monitor.rs b/third_party/rust/libudev/src/monitor.rs
new file mode 100644
index 0000000000..836a8736ce
--- /dev/null
+++ b/third_party/rust/libudev/src/monitor.rs
@@ -0,0 +1,211 @@
+use std::fmt;
+use std::ptr;
+
+use std::ffi::{CString,OsStr};
+use std::ops::Deref;
+use std::os::unix::io::{RawFd,AsRawFd};
+
+use ::context::{Context};
+use ::device::{Device};
+use ::handle::prelude::*;
+
+
+/// Monitors for device events.
+///
+/// A monitor communicates with the kernel over a socket. Filtering events is performed efficiently
+/// in the kernel, and only events that match the filters are received by the socket. Filters must
+/// be setup before listening for events.
+pub struct Monitor<'a> {
+ context: &'a Context,
+ monitor: *mut ::ffi::udev_monitor
+}
+
+impl<'a> Drop for Monitor<'a> {
+ fn drop(&mut self) {
+ unsafe {
+ ::ffi::udev_monitor_unref(self.monitor);
+ }
+ }
+}
+
+impl<'a> Monitor<'a> {
+ /// Creates a new `Monitor`.
+ pub fn new(context: &'a Context) -> ::Result<Self> {
+ let name = CString::new("udev").unwrap();
+
+ let ptr = try_alloc!(unsafe {
+ ::ffi::udev_monitor_new_from_netlink(context.as_ptr(), name.as_ptr())
+ });
+
+ Ok(Monitor {
+ context: context,
+ monitor: ptr
+ })
+ }
+
+ /// Adds a filter that matches events for devices with the given subsystem.
+ pub fn match_subsystem<T: AsRef<OsStr>>(&mut self, subsystem: T) -> ::Result<()> {
+ let subsystem = try!(::util::os_str_to_cstring(subsystem));
+
+ ::util::errno_to_result(unsafe {
+ ::ffi::udev_monitor_filter_add_match_subsystem_devtype(self.monitor, subsystem.as_ptr(), ptr::null())
+ })
+ }
+
+ /// Adds a filter that matches events for devices with the given subsystem and device type.
+ pub fn match_subsystem_devtype<T: AsRef<OsStr>, U: AsRef<OsStr>>(&mut self, subsystem: T, devtype: U) -> ::Result<()> {
+ let subsystem = try!(::util::os_str_to_cstring(subsystem));
+ let devtype = try!(::util::os_str_to_cstring(devtype));
+
+ ::util::errno_to_result(unsafe {
+ ::ffi::udev_monitor_filter_add_match_subsystem_devtype(self.monitor, subsystem.as_ptr(), devtype.as_ptr())
+ })
+ }
+
+ /// Adds a filter that matches events for devices with the given tag.
+ pub fn match_tag<T: AsRef<OsStr>>(&mut self, tag: T) -> ::Result<()> {
+ let tag = try!(::util::os_str_to_cstring(tag));
+
+ ::util::errno_to_result(unsafe {
+ ::ffi::udev_monitor_filter_add_match_tag(self.monitor, tag.as_ptr())
+ })
+ }
+
+ /// Removes all filters currently set on the monitor.
+ pub fn clear_filters(&mut self) -> ::Result<()> {
+ ::util::errno_to_result(unsafe {
+ ::ffi::udev_monitor_filter_remove(self.monitor)
+ })
+ }
+
+ /// Listens for events matching the current filters.
+ ///
+ /// This method consumes the `Monitor`.
+ pub fn listen(self) -> ::Result<MonitorSocket<'a>> {
+ try!(::util::errno_to_result(unsafe {
+ ::ffi::udev_monitor_enable_receiving(self.monitor)
+ }));
+
+ Ok(MonitorSocket { inner: self })
+ }
+}
+
+
+/// An active monitor that can receive events.
+///
+/// The events received by a `MonitorSocket` match the filters setup by the `Monitor` that created
+/// the socket.
+///
+/// Monitors are initially setup to receive events from the kernel via a nonblocking socket. A
+/// variant of `poll()` should be used on the file descriptor returned by the `AsRawFd` trait to
+/// wait for new events.
+pub struct MonitorSocket<'a> {
+ inner: Monitor<'a>
+}
+
+/// Provides raw access to the monitor's socket.
+impl<'a> AsRawFd for MonitorSocket<'a> {
+ /// Returns the file descriptor of the monitor's socket.
+ fn as_raw_fd(&self) -> RawFd {
+ unsafe {
+ ::ffi::udev_monitor_get_fd(self.inner.monitor)
+ }
+ }
+}
+
+impl<'a> MonitorSocket<'a> {
+ /// Receives the next available event from the monitor.
+ ///
+ /// This method does not block. If no events are available, it returns `None` immediately.
+ pub fn receive_event<'b>(&'b mut self) -> Option<Event<'a>> {
+ let device = unsafe {
+ ::ffi::udev_monitor_receive_device(self.inner.monitor)
+ };
+
+ if device.is_null() {
+ None
+ }
+ else {
+ let device = ::device::new(self.inner.context, device);
+
+ Some(Event { device: device })
+ }
+ }
+}
+
+/// Types of events that can be received from udev.
+#[derive(Debug,Clone,Copy,PartialEq,Eq)]
+pub enum EventType {
+ /// A device was added.
+ Add,
+
+ /// A device changed.
+ Change,
+
+ /// A device was removed.
+ Remove,
+
+ /// An unknown event occurred.
+ Unknown,
+}
+
+impl Default for EventType {
+ fn default() -> EventType {
+ EventType::Unknown
+ }
+}
+
+impl fmt::Display for EventType {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.write_str(match self {
+ &EventType::Add => "add",
+ &EventType::Change => "change",
+ &EventType::Remove => "remove",
+ &EventType::Unknown => "unknown",
+ })
+ }
+}
+
+
+/// An event that indicates a change in device state.
+pub struct Event<'a> {
+ device: Device<'a>
+}
+
+/// Provides access to the device associated with the event.
+impl<'a> Deref for Event<'a> {
+ type Target = Device<'a>;
+
+ fn deref(&self) -> &Device<'a> {
+ &self.device
+ }
+}
+
+impl<'a> Event<'a> {
+ /// Returns the `EventType` corresponding to this event.
+ pub fn event_type(&self) -> EventType {
+ let value = match self.device.property_value("ACTION") {
+ Some(s) => s.to_str(),
+ None => None
+ };
+
+ match value {
+ Some("add") => EventType::Add,
+ Some("change") => EventType::Change,
+ Some("remove") => EventType::Remove,
+ _ => EventType::Unknown
+ }
+ }
+
+ /// Returns the event's sequence number.
+ pub fn sequence_number(&self) -> u64 {
+ unsafe {
+ ::ffi::udev_device_get_seqnum(self.device.as_ptr()) as u64
+ }
+ }
+
+ /// Returns the device associated with this event.
+ pub fn device(&self) -> &Device {
+ &self.device
+ }
+}
diff --git a/third_party/rust/libudev/src/util.rs b/third_party/rust/libudev/src/util.rs
new file mode 100644
index 0000000000..6831d2e14a
--- /dev/null
+++ b/third_party/rust/libudev/src/util.rs
@@ -0,0 +1,33 @@
+use std::slice;
+use std::ffi::{CString,OsStr};
+
+use ::libc::{c_int,c_char};
+
+use std::os::unix::prelude::*;
+
+pub fn ptr_to_os_str<'a>(ptr: *const c_char) -> Option<&'a OsStr> {
+ if !ptr.is_null() {
+ Some(unsafe { ptr_to_os_str_unchecked(ptr) })
+ }
+ else {
+ None
+ }
+}
+
+pub unsafe fn ptr_to_os_str_unchecked<'a>(ptr: *const c_char) -> &'a OsStr {
+ OsStr::from_bytes(slice::from_raw_parts(ptr as *const u8, ::libc::strlen(ptr) as usize))
+}
+
+pub fn os_str_to_cstring<T: AsRef<OsStr>>(s: T) -> ::Result<CString> {
+ match CString::new(s.as_ref().as_bytes()) {
+ Ok(s) => Ok(s),
+ Err(_) => return Err(::error::from_errno(::libc::EINVAL))
+ }
+}
+
+pub fn errno_to_result(errno: c_int) -> ::Result<()> {
+ match errno {
+ 0 => Ok(()),
+ e => Err(::error::from_errno(e))
+ }
+}