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