Skip to content

Commit

Permalink
Initial commit.
Browse files Browse the repository at this point in the history
Signed-off-by: Jean Pierre Dudey <[email protected]>
  • Loading branch information
jeandudey committed Apr 23, 2018
0 parents commit fe36f28
Show file tree
Hide file tree
Showing 16 changed files with 731 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

/target
**/*.rs.bk
Cargo.lock
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[workspace]
members = ["mio-udev", "tokio-udev", "udev-sys", "udev"]
9 changes: 9 additions & 0 deletions mio-udev/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "mio-udev"
version = "0.1.0"
authors = ["Jean Pierre Dudey <[email protected]>"]

[dependencies]
udev = { path = "../udev", version = "0.1.0" }
mio = "0.6"
libc = "0.2"
78 changes: 78 additions & 0 deletions mio-udev/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#![cfg(target_os = "linux")]

extern crate udev;
extern crate mio;
extern crate libc;

mod util;

use std::io;
use std::os::unix::io::{AsRawFd, RawFd};

use mio::{Ready, Poll, PollOpt, Token};
use mio::event::Evented;
use mio::unix::EventedFd;

#[derive(Debug)]
pub struct MonitorIo {
monitor: udev::Monitor,
}

impl MonitorIo {
/// Creates a new monitor io object from an existing udev monitor.
///
/// # Notes
///
/// It marks the file descriptor as `FD_CLOEXEC` and sets the `O_NONBLOCK`
/// flag.
pub fn from_monitor(monitor: udev::Monitor) -> io::Result<MonitorIo> {
use libc::{fcntl, F_GETFD, FD_CLOEXEC, F_SETFD, F_GETFL, F_SETFL, O_NONBLOCK};
use util::cvt;

let fd = monitor.as_raw_fd();

// Make sure the udev file descriptor is marked as CLOEXEC.
let r = unsafe { cvt(fcntl(fd, F_GETFD))? };

if !((r & FD_CLOEXEC) == FD_CLOEXEC) {
unsafe { cvt(fcntl(fd, F_SETFD, r | FD_CLOEXEC))? };
}

// Some older versions of udev are not non-blocking by default,
// so make sure this is set
let r = unsafe { cvt(fcntl(fd, F_GETFL))? };

if !((r & O_NONBLOCK) == O_NONBLOCK) {
unsafe { cvt(fcntl(fd, F_SETFL, r | O_NONBLOCK))? };
}

Ok(MonitorIo { monitor })
}

pub fn receive_device(&self) -> io::Result<udev::Device> {
self.monitor.receive_device()
}

#[inline(always)]
fn fd(&self) -> RawFd {
self.monitor.as_raw_fd()
}
}

impl Evented for MonitorIo {
fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt)
-> io::Result<()>
{
EventedFd(&self.fd()).register(poll, token, interest, opts)
}

fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt)
-> io::Result<()>
{
EventedFd(&self.fd()).reregister(poll, token, interest, opts)
}

fn deregister(&self, poll: &Poll) -> io::Result<()> {
EventedFd(&self.fd()).deregister(poll)
}
}
23 changes: 23 additions & 0 deletions mio-udev/src/util.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use std::{io, ops::Neg};

#[doc(hidden)]
pub trait One {
fn one() -> Self;
}

macro_rules! one {
($($t:ident)*) => ($(
impl One for $t { fn one() -> $t { 1 } }
)*)
}

one! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }

pub fn cvt<T: One + PartialEq + Neg<Output=T>>(t: T) -> io::Result<T> {
let one: T = T::one();
if t == -one {
Err(io::Error::last_os_error())
} else {
Ok(t)
}
}
17 changes: 17 additions & 0 deletions tokio-udev/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "tokio-udev"
version = "0.1.0"
authors = ["Jean Pierre Dudey <[email protected]>"]

[dependencies]
libc = "0.2"

mio-udev = { path = "../mio-udev", version = "0.1.0" }
mio = "0.6"
udev = { path = "../udev", version = "0.1.0" }

futures = "0.1"
tokio-reactor = "0.1"

[dev-dependencies]
tokio = "0.1"
29 changes: 29 additions & 0 deletions tokio-udev/examples/usb_hotplug.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
extern crate tokio_udev;
extern crate tokio;
extern crate futures;

use futures::{Future, stream::Stream};

use tokio_udev::{USB_SUBSYSTEM, USB_DEVICE, UDEV_MONITOR};

fn main() {
let monitor = tokio_udev::Builder::new()
.add_match(USB_SUBSYSTEM, USB_DEVICE)
.build(UDEV_MONITOR)
.expect("couldn't create monitor");

let hotplug_stream = monitor.for_each(|device| {
println!("=====================");
println!(" Usb HotPlug Event ");
println!("=====================");
println!("devpath: \"{:?}\"", device.get_devpath()?);
println!("action: \"{}\"", device.get_action()?);

Ok(())
})
.map_err(|e| {
println!("error: {}", e);
});

tokio::run(hotplug_stream);
}
18 changes: 18 additions & 0 deletions tokio-udev/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#![cfg(target_os = "linux")]

//! # tokio udev
extern crate libc;

extern crate udev;
extern crate mio_udev;
extern crate mio;

extern crate futures;
extern crate tokio_reactor;

mod monitor;

pub use udev::{Subsystem, DeviceType, MonitorName, USB_SUBSYSTEM, USB_DEVICE, UDEV_MONITOR};

pub use monitor::{Builder, Monitor};
78 changes: 78 additions & 0 deletions tokio-udev/src/monitor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
use std::io;

use {mio, udev, mio_udev};
use tokio_reactor::PollEvented;
use futures::{Async, Poll, stream::Stream};

#[derive(Debug)]
pub struct Builder {
match_filters: Vec<(udev::Subsystem, udev::DeviceType)>,
}

impl Builder {
pub fn new() -> Builder {
Builder {
match_filters: Vec::new(),
}
}

pub fn add_match(mut self,
subsystem: udev::Subsystem,
devtype: udev::DeviceType) -> Builder {
self.match_filters.push((subsystem, devtype));
self
}

pub fn build(self, name: udev::MonitorName) -> io::Result<Monitor> {
let context = udev::Context::new();
let monitor = udev::Monitor::new_from_netlink(&context, name);

for filter in self.match_filters {
monitor.filter_add_match_subsystem_devtype(filter.0, filter.1)?;
}

monitor.enable_receiving()?;

Monitor::new(monitor)
}
}

#[derive(Debug)]
pub struct Monitor {
io: PollEvented<mio_udev::MonitorIo>,
}

impl Monitor {
pub fn new(monitor: udev::Monitor) -> io::Result<Monitor> {
let io = PollEvented::new(mio_udev::MonitorIo::from_monitor(monitor)?);
Ok(Monitor { io })
}

pub fn poll_receive(&self) -> Poll<Option<udev::Device>, io::Error> {
if let Async::NotReady = self.io.poll_read_ready(mio::Ready::readable())? {
return Ok(Async::NotReady);
}

match self.io.get_ref().receive_device() {
Ok(device) => Ok(Async::Ready(Some(device))),
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
self.io.clear_read_ready(mio::Ready::readable())?;
Ok(Async::NotReady)
} else {
Err(e)
}
},
}

}
}

impl Stream for Monitor {
type Item = udev::Device;
type Error = io::Error;

fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
self.poll_receive()
}
}
7 changes: 7 additions & 0 deletions udev-sys/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "udev-sys"
version = "0.1.0"
authors = ["Jean Pierre Dudey <[email protected]>"]

[dependencies]
libc = "0.2"
Loading

0 comments on commit fe36f28

Please sign in to comment.