<NME> udev.rs
<BEF> use libudev::{Context, MonitorBuilder, MonitorSocket, Event, EventType, Enumerator, Result as UdevResult};
use nix::sys::stat::{dev_t, fstat};
use std::borrow::Borrow;
use std::collections::HashMap;
//! *Note:* Once inserted into the event loop, the [`UdevBackend`] will only notify you about *changes*
//! in the device list. To get an initial snapshot of the state during your initialization, you need to
//! call its `device_list` method.
//!
//! ```no_run
//! use smithay::backend::udev::{UdevBackend, UdevEvent};
//!
//! let udev = UdevBackend::new("seat0", None).expect("Failed to monitor udev.");
//!
//! for (dev_id, node_path) in udev.device_list() {
//!     // process the initial list of devices
pub struct UdevBackend<B: Borrow<DrmBackend> + 'static, H: DrmHandler<B> + 'static, S: Session + 'static, T: UdevHandler<B, H> + 'static> {
    devices: HashMap<dev_t, (StateToken<DrmDevice<B>>, FdEventSource<(StateToken<DrmDevice<B>>, H)>)>,
    monitor: MonitorSocket,
    session: StateToken<S>,
    handler: T,
    logger: ::slog::Logger,
}
//!         // a new device has been added
impl<B: From<DrmBackend> + Borrow<DrmBackend> + 'static, H: DrmHandler<B> + 'static, S: Session + 'static, T: UdevHandler<B, H> + 'static> UdevBackend<B, H, S, T> {
    pub fn new<'a, L>(mut evlh: &mut EventLoopHandle,
                      context: &Context,
                      session_token: &StateToken<S>,
                      mut handler: T,
                      logger: L)
        -> Result<UdevBackend<B, H, S, T>>
//! }).expect("Failed to insert the udev source into the event loop");
        L: Into<Option<::slog::Logger>>
    {
        let logger = ::slog_or_stdlog(logger).new(o!("smithay_module" => "backend_udev"));
        let seat = String::from(evlh.state().get(&session_token).seat());
        let devices = all_gpus(context, seat)
            .chain_err(|| ErrorKind::FailedToScan)?
            .into_iter()
use nix::sys::stat::{dev_t, stat};
            .flat_map(|path| {
                match unsafe { DrmDevice::new_from_fd(
                    {
                        let session = evlh.state().get_mut(session_token);
                        match session.open(&path) {
                            Ok(fd) => fd,
                            Err(err) => {
                                warn!(logger, "Unable to open drm device {:?}, Error: {:?}. Skipping", path, err);
use udev::{Enumerator, EventType, MonitorBuilder, MonitorSocket};

use calloop::{EventSource, Interest, Mode, Poll, PostAction, Readiness, Token, TokenFactory};

use slog::{debug, info, o, warn};

/// Backend to monitor available drm devices.
///
/// Provides a way to automatically scan for available gpus and notifies the
/// given handler of any changes. Can be used to provide hot-plug functionality for gpus and
/// attached monitors.
pub struct UdevBackend {
    devices: HashMap<dev_t, PathBuf>,
    monitor: MonitorSocket,
    token: Option<Token>,
                                    let device = evlh.state().remove(token);
                                    let fd = device.as_raw_fd();
                                    drop(device);
                                    let session = evlh.state().get_mut(session_token);
                                    if let Err(err) = session.close(fd) {
                                        warn!(logger, "Failed to close dropped device. Error: {:?}. Ignoring", err);
                                    };
        use udev::AsRaw;
        f.debug_struct("UdevBackend")
            .field("devices", &self.devices)
            .field("monitor", &format!("MonitorSocket ({:?})", self.monitor.as_raw()))
            .field("logger", &self.logger)
            .finish()
    }
}
                                let device = evlh.state().remove(token);
                                let fd = device.as_raw_fd();
                                drop(device);
                                let session = evlh.state().get_mut(session_token);
                                if let Err(err) = session.close(fd) {
                                    warn!(logger, "Failed to close dropped device. Error: {:?}. Ignoring", err);
                                };

impl UdevBackend {
    /// Creates a new [`UdevBackend`]
                        None => {
                            let fd = device.as_raw_fd();
                            drop(device); //drops master
                            let session = evlh.state().get_mut(session_token);
                            if let Err(err) = session.close(fd) {
                                warn!(logger, "Failed to close device. Error: {:?}. Ignoring", err);
                            }
        L: Into<Option<::slog::Logger>>,
    {
        let log = crate::slog_or_fallback(logger).new(o!("smithay_module" => "backend_udev"));

        let devices = all_gpus(seat)?
            .into_iter()
            // Create devices
            .flat_map(|path| match stat(&path) {
                Ok(stat) => Some((stat.st_rdev, path)),
                Err(err) => {
                    warn!(log, "Unable to get id of {:?}, Error: {:?}. Skipping", path, err);
                    None
                }
            })
            .collect();
        Ok(UdevBackend {
            devices,
            monitor,
            session: session_token.clone(),
            handler,
            logger,
        })
            logger: log,
        })
    }

    /// Get a list of DRM devices currently known to the backend
    ///
    /// You should call this once before inserting the event source into your
            let device = state.remove(device);
            let fd = device.as_raw_fd();
            drop(device);
            let session = state.get_mut(&self.session);
            if let Err(err) = session.close(fd) {
                warn!(self.logger, "Failed to close device. Error: {:?}. Ignoring", err);
            };
        }
    }
}


    fn process_events<F>(
        &mut self,
        _: Readiness,
        token: Token,
        mut callback: F,
    ) -> std::io::Result<PostAction>
    where
        F: FnMut(UdevEvent, &mut ()),
    {
        if Some(token) != self.token {
            return Ok(PostAction::Continue);
        }
        let monitor = self.monitor.clone();
        for event in monitor {
            debug!(
                self.logger,
                "Udev event: type={}, devnum={:?} devnode={:?}",
                event.event_type(),
                event.devnum(),
                event.devnode()
            );
            match event.event_type() {
                // New device
                EventType::Add => {
                    if let (Some(path), Some(devnum)) = (event.devnode(), event.devnum()) {
                        info!(self.logger, "New device: #{} at {}", devnum, path.display());
                        if self.devices.insert(devnum, path.to_path_buf()).is_none() {
                            callback(
                                UdevEvent::Added {
                                    device_id: devnum,
                                    path: path.to_path_buf(),
                                },
                                &mut (),
                            );
                        }
                    }
                }
                // Device removed
                EventType::Remove => {
                    if let Some(devnum) = event.devnum() {
                        info!(self.logger, "Device removed: #{}", devnum);
                        if self.devices.remove(&devnum).is_some() {
                            callback(UdevEvent::Removed { device_id: devnum }, &mut ());
                        }
                    }
                }
                // New connector
                EventType::Change => {
                    if let Some(devnum) = event.devnum() {
                        info!(self.logger, "Device changed: #{}", devnum);
                        if self.devices.contains_key(&devnum) {
                            let mut device = {
                                match unsafe { DrmDevice::new_from_fd(
                                    {
                                        let session_token = evlh.state().get(token).session.clone();
                                        let logger = evlh.state().get(token).logger.clone();
                                        let session = evlh.state().get_mut(&session_token);
                                        match session.open(path) {
                                            Ok(fd) => fd,
                                            Err(err) => {
                                                warn!(logger, "Unable to open drm device {:?}, Error: {:?}. Skipping", path, err);
    }

    fn register(&mut self, poll: &mut Poll, factory: &mut TokenFactory) -> calloop::Result<()> {
        self.token = Some(factory.token());
        poll.register(self.as_raw_fd(), Interest::READ, Mode::Level, self.token.unwrap())
    }

    fn reregister(&mut self, poll: &mut Poll, factory: &mut TokenFactory) -> calloop::Result<()> {
        self.token = Some(factory.token());
        poll.reregister(self.as_raw_fd(), Interest::READ, Mode::Level, self.token.unwrap())
    }

    fn unregister(&mut self, poll: &mut Poll) -> calloop::Result<()> {
        self.token = None;
        poll.unregister(self.as_raw_fd())
    }
                                        evlh.state().get_mut(token).devices.insert(devnum, (dev_token, fd_event_source));
                                    } else {
                                        evlh.state().with_value(token, |state, udev| {
                                            let session_token = udev.session.clone();
                                            state.with_value(&session_token, |state, session| {
                                                let mut state: StateProxy = state.into();
                                                udev.handler.device_removed(&mut state, &dev_token);
                                                let device = state.remove(dev_token);
                                                let fd = device.as_raw_fd();
                                                drop(device);
                                                if let Err(err) = session.close(fd) {
                                                    warn!(udev.logger, "Failed to close dropped device. Error: {:?}. Ignoring", err);
                                                };
                                            })
                                        })
                                    }
                                },
                                None => {
                                    let fd = device.as_raw_fd();
                                    drop(device);
                                    evlh.state().with_value(token, |state, udev| {
                                        state.with_value(&udev.session, |_, session| {
                                            if let Err(err) = session.close(fd) {
                                                warn!(udev.logger, "Failed to close unused device. Error: {:?}", err);
                                            }
                                        })
                                    })
                                },
                            };
/// Returns the path of the primary GPU device if any
///
                    // Device removed
                    EventType::Remove => {
                        evlh.state().with_value(token, |state, udev| {
                            let session_token = udev.session.clone();
                            state.with_value(&session_token, |state, session| {
                                info!(udev.logger, "Device Remove");
                                if let Some(devnum) = event.devnum() {
                                    if let Some((device, fd_event_source)) = udev.devices.remove(&devnum) {
                                        fd_event_source.remove();
                                        let mut state: StateProxy = state.into();
                                        udev.handler.device_removed(&mut state, &device);
                                        let device = state.remove(device);
                                        let fd = device.as_raw_fd();
                                        drop(device);
                                        if let Err(err) = session.close(fd) {
                                            warn!(udev.logger, "Failed to close device {:?}. Error: {:?}. Ignoring", event.sysname(), err);
                                        };
                                    }
                                }
                            })
                        })
                    },
                    // New connector
            }
            false
        })
        .flat_map(|device| device.devnode().map(PathBuf::from))
        .next()
    {
        Ok(Some(path))
    } else {
        all_gpus(seat).map(|all| all.into_iter().next())
    }
}

/// Returns the paths of all available GPU devices
///
/// Might be used for manual  [`DrmDevice`](crate::backend::drm::DrmDevice)
/// initialization.
pub fn all_gpus<S: AsRef<str>>(seat: S) -> io::Result<Vec<PathBuf>> {
    let mut enumerator = Enumerator::new()?;
    enumerator.match_subsystem("drm")?;
    enumerator.match_sysname("card[0-9]*")?;
    Ok(enumerator
        .scan_devices()?
        .filter(|device| {
            device
                .property_value("ID_SEAT")
                .map(|x| x.to_os_string())
                .unwrap_or_else(|| OsString::from("seat0"))
                == *seat.as_ref()
        })
        .flat_map(|device| device.devnode().map(PathBuf::from))
        .collect())
}

/// Returns the loaded driver for a device named by it's [`dev_t`](::nix::sys::stat::dev_t).
pub fn driver(dev: dev_t) -> io::Result<Option<OsString>> {
    let mut enumerator = Enumerator::new()?;
    enumerator.match_subsystem("drm")?;
    enumerator.match_sysname("card[0-9]*")?;
    Ok(enumerator
        .scan_devices()?
        .filter(|device| device.devnum() == Some(dev))
        .flat_map(|dev| {
            let mut device = Some(dev);
            while let Some(dev) = device {
                if dev.driver().is_some() {
                    return dev.driver().map(std::ffi::OsStr::to_os_string);
                }
                device = dev.parent();
            }
            None
        })
        .next())
}

<MSG> Get input working

<DFF> @@ -1,4 +1,5 @@
 use libudev::{Context, MonitorBuilder, MonitorSocket, Event, EventType, Enumerator, Result as UdevResult};
+use nix::fcntl;
 use nix::sys::stat::{dev_t, fstat};
 use std::borrow::Borrow;
 use std::collections::HashMap;
@@ -16,7 +17,7 @@ use ::backend::session::{Session, SessionObserver};
 pub struct UdevBackend<B: Borrow<DrmBackend> + 'static, H: DrmHandler<B> + 'static, S: Session + 'static, T: UdevHandler<B, H> + 'static> {
     devices: HashMap<dev_t, (StateToken<DrmDevice<B>>, FdEventSource<(StateToken<DrmDevice<B>>, H)>)>,
     monitor: MonitorSocket,
-    session: StateToken<S>,
+    session: S,
     handler: T,
     logger: ::slog::Logger,
 }
@@ -24,7 +25,7 @@ pub struct UdevBackend<B: Borrow<DrmBackend> + 'static, H: DrmHandler<B> + 'stat
 impl<B: From<DrmBackend> + Borrow<DrmBackend> + 'static, H: DrmHandler<B> + 'static, S: Session + 'static, T: UdevHandler<B, H> + 'static> UdevBackend<B, H, S, T> {
     pub fn new<'a, L>(mut evlh: &mut EventLoopHandle,
                       context: &Context,
-                      session_token: &StateToken<S>,
+                      mut session: S,
                       mut handler: T,
                       logger: L)
         -> Result<UdevBackend<B, H, S, T>>
@@ -32,7 +33,7 @@ impl<B: From<DrmBackend> + Borrow<DrmBackend> + 'static, H: DrmHandler<B> + 'sta
         L: Into<Option<::slog::Logger>>
     {
         let logger = ::slog_or_stdlog(logger).new(o!("smithay_module" => "backend_udev"));
-        let seat = String::from(evlh.state().get(&session_token).seat());
+        let seat = session.seat();
         let devices = all_gpus(context, seat)
             .chain_err(|| ErrorKind::FailedToScan)?
             .into_iter()
@@ -40,8 +41,7 @@ impl<B: From<DrmBackend> + Borrow<DrmBackend> + 'static, H: DrmHandler<B> + 'sta
             .flat_map(|path| {
                 match unsafe { DrmDevice::new_from_fd(
                     {
-                        let session = evlh.state().get_mut(session_token);
-                        match session.open(&path) {
+                        match session.open(&path, fcntl::O_RDWR | fcntl::O_CLOEXEC | fcntl::O_NOCTTY | fcntl::O_NONBLOCK) {
                             Ok(fd) => fd,
                             Err(err) => {
                                 warn!(logger, "Unable to open drm device {:?}, Error: {:?}. Skipping", path, err);
@@ -63,7 +63,6 @@ impl<B: From<DrmBackend> + Borrow<DrmBackend> + 'static, H: DrmHandler<B> + 'sta
                                     let device = evlh.state().remove(token);
                                     let fd = device.as_raw_fd();
                                     drop(device);
-                                    let session = evlh.state().get_mut(session_token);
                                     if let Err(err) = session.close(fd) {
                                         warn!(logger, "Failed to close dropped device. Error: {:?}. Ignoring", err);
                                     };
@@ -78,7 +77,6 @@ impl<B: From<DrmBackend> + Borrow<DrmBackend> + 'static, H: DrmHandler<B> + 'sta
                                 let device = evlh.state().remove(token);
                                 let fd = device.as_raw_fd();
                                 drop(device);
-                                let session = evlh.state().get_mut(session_token);
                                 if let Err(err) = session.close(fd) {
                                     warn!(logger, "Failed to close dropped device. Error: {:?}. Ignoring", err);
                                 };
@@ -88,7 +86,6 @@ impl<B: From<DrmBackend> + Borrow<DrmBackend> + 'static, H: DrmHandler<B> + 'sta
                         None => {
                             let fd = device.as_raw_fd();
                             drop(device); //drops master
-                            let session = evlh.state().get_mut(session_token);
                             if let Err(err) = session.close(fd) {
                                 warn!(logger, "Failed to close device. Error: {:?}. Ignoring", err);
                             }
@@ -110,7 +107,7 @@ impl<B: From<DrmBackend> + Borrow<DrmBackend> + 'static, H: DrmHandler<B> + 'sta
         Ok(UdevBackend {
             devices,
             monitor,
-            session: session_token.clone(),
+            session,
             handler,
             logger,
         })
@@ -124,11 +121,11 @@ impl<B: From<DrmBackend> + Borrow<DrmBackend> + 'static, H: DrmHandler<B> + 'sta
             let device = state.remove(device);
             let fd = device.as_raw_fd();
             drop(device);
-            let session = state.get_mut(&self.session);
-            if let Err(err) = session.close(fd) {
+            if let Err(err) = self.session.close(fd) {
                 warn!(self.logger, "Failed to close device. Error: {:?}. Ignoring", err);
             };
         }
+        info!(self.logger, "All devices closed");
     }
 }
 
@@ -187,10 +184,8 @@ where
                             let mut device = {
                                 match unsafe { DrmDevice::new_from_fd(
                                     {
-                                        let session_token = evlh.state().get(token).session.clone();
                                         let logger = evlh.state().get(token).logger.clone();
-                                        let session = evlh.state().get_mut(&session_token);
-                                        match session.open(path) {
+                                        match evlh.state().get_mut(token).session.open(path, fcntl::O_RDWR | fcntl::O_CLOEXEC | fcntl::O_NOCTTY | fcntl::O_NONBLOCK) {
                                             Ok(fd) => fd,
                                             Err(err) => {
                                                 warn!(logger, "Unable to open drm device {:?}, Error: {:?}. Skipping", path, err);
@@ -213,29 +208,24 @@ where
                                         evlh.state().get_mut(token).devices.insert(devnum, (dev_token, fd_event_source));
                                     } else {
                                         evlh.state().with_value(token, |state, udev| {
-                                            let session_token = udev.session.clone();
-                                            state.with_value(&session_token, |state, session| {
-                                                let mut state: StateProxy = state.into();
-                                                udev.handler.device_removed(&mut state, &dev_token);
-                                                let device = state.remove(dev_token);
-                                                let fd = device.as_raw_fd();
-                                                drop(device);
-                                                if let Err(err) = session.close(fd) {
-                                                    warn!(udev.logger, "Failed to close dropped device. Error: {:?}. Ignoring", err);
-                                                };
-                                            })
+                                            let mut state: StateProxy = state.into();
+                                            udev.handler.device_removed(&mut state, &dev_token);
+                                            let device = state.remove(dev_token);
+                                            let fd = device.as_raw_fd();
+                                            drop(device);
+                                            if let Err(err) = udev.session.close(fd) {
+                                                warn!(udev.logger, "Failed to close dropped device. Error: {:?}. Ignoring", err);
+                                            };
                                         })
                                     }
                                 },
                                 None => {
                                     let fd = device.as_raw_fd();
                                     drop(device);
-                                    evlh.state().with_value(token, |state, udev| {
-                                        state.with_value(&udev.session, |_, session| {
-                                            if let Err(err) = session.close(fd) {
-                                                warn!(udev.logger, "Failed to close unused device. Error: {:?}", err);
-                                            }
-                                        })
+                                    evlh.state().with_value(token, |_state, udev| {
+                                        if let Err(err) = udev.session.close(fd) {
+                                            warn!(udev.logger, "Failed to close unused device. Error: {:?}", err);
+                                        }
                                     })
                                 },
                             };
@@ -244,23 +234,20 @@ where
                     // Device removed
                     EventType::Remove => {
                         evlh.state().with_value(token, |state, udev| {
-                            let session_token = udev.session.clone();
-                            state.with_value(&session_token, |state, session| {
-                                info!(udev.logger, "Device Remove");
-                                if let Some(devnum) = event.devnum() {
-                                    if let Some((device, fd_event_source)) = udev.devices.remove(&devnum) {
-                                        fd_event_source.remove();
-                                        let mut state: StateProxy = state.into();
-                                        udev.handler.device_removed(&mut state, &device);
-                                        let device = state.remove(device);
-                                        let fd = device.as_raw_fd();
-                                        drop(device);
-                                        if let Err(err) = session.close(fd) {
-                                            warn!(udev.logger, "Failed to close device {:?}. Error: {:?}. Ignoring", event.sysname(), err);
-                                        };
-                                    }
+                            info!(udev.logger, "Device Remove");
+                            if let Some(devnum) = event.devnum() {
+                                if let Some((device, fd_event_source)) = udev.devices.remove(&devnum) {
+                                    fd_event_source.remove();
+                                    let mut state: StateProxy = state.into();
+                                    udev.handler.device_removed(&mut state, &device);
+                                    let device = state.remove(device);
+                                    let fd = device.as_raw_fd();
+                                    drop(device);
+                                    if let Err(err) = udev.session.close(fd) {
+                                        warn!(udev.logger, "Failed to close device {:?}. Error: {:?}. Ignoring", event.sysname(), err);
+                                    };
                                 }
-                            })
+                            }
                         })
                     },
                     // New connector

Get input working