logind_dbus/
lib.rs

1//! Provides a DBus API for interacting with logind, which is useful for doing things such as inhibiting suspension.
2//!
3//! ```rust,no_run
4//! extern crate logind_dbus;
5//! use logind_dbus::LoginManager;
6//! 
7//! pub fn main() -> io::Result<()> {
8//!     let login_manager = LoginManager::new()?;
9//!     let suspend_lock = login_manager.connect().inhibit_suspend()?;
10//!     /// Do sensitive thing with the guarantee that suspend will not work.
11//! }
12//! ```
13
14#[macro_use]
15extern crate cascade;
16extern crate dbus;
17
18use dbus::{arg, BusType, Connection, ConnPath};
19use std::ops::Deref;
20
21/// An interface to `org.freedesktop.login1.Manager`.
22pub struct LoginManager {
23    conn: Connection
24}
25
26impl Deref for LoginManager {
27    type Target = Connection;
28    fn deref(&self) -> &Self::Target {
29        &self.conn
30    }
31}
32
33impl LoginManager {
34    pub fn new() -> Result<LoginManager, dbus::Error> {
35        Ok(Self { conn: Connection::get_private(BusType::System)? })
36    }
37
38    pub fn connect(&self) -> LoginManagerConnection {
39        LoginManagerConnection {
40            conn: self.with_path("org.freedesktop.login1", "/org/freedesktop/login1", 1000)
41        }
42    }
43}
44
45/// An established connection path for the login manager, through which the API is made accessible.
46pub struct LoginManagerConnection<'a> {
47    conn: ConnPath<'a, &'a Connection>
48}
49
50impl<'a> LoginManagerConnection<'a> {
51    /// Inhibit is the only API necessary to take a lock. It takes four arguments:
52    /// 
53    /// - **What** is a colon-separated list of lock types, i.e. `shutdown`, `sleep`, `idle`,
54    ///   `handle-power-key`, `handle-suspend-key`, `handle-hibernate-key`, `handle-lid-switch`.
55    ///   Example: "shutdown:idle"
56    /// - **Who** is a human-readable, descriptive string of who is taking the lock. Example: "Package Updater"
57    /// - **Why** is a human-readable, descriptive string of why the lock is taken. Example: "Package Update in Progress"
58    /// - **Mode** is one of `block` or `delay`.
59    /// 
60    /// # Notes
61    /// 
62    /// A root user session cannot use systemd inhibitors.
63    pub fn inhibit(&self, what: &str, who: &str, why: &str, mode: &str) -> Result<dbus::OwnedFd, dbus::Error> {
64        let mut m = self.conn.method_call_with_args(
65            &"org.freedesktop.login1.Manager".into(),
66            &"Inhibit".into(),
67            |msg| {
68                cascade! {
69                    arg::IterAppend::new(msg);
70                    ..append(what);
71                    ..append(who);
72                    ..append(why);
73                    ..append(mode);
74                }
75            })?;
76
77        m.as_result()?;
78        Ok(m.iter_init().read::<dbus::OwnedFd>()?)
79    }
80
81    /// Convenience method for inhibiting suspend.
82    /// 
83    /// Equivalent to `connection.inhibit("idle:shutdown:sleep", who, why, "block")`.
84    pub fn inhibit_suspend(&self, who: &str, why: &str) -> Result<dbus::OwnedFd, dbus::Error> {
85        self.inhibit("idle:shutdown:sleep", who, why, "block")
86    }
87}