From 55d98fe97c39a13a6bddd991351e9ef8503ef84b Mon Sep 17 00:00:00 2001 From: Dmytro Kovalenko Date: Sun, 6 Aug 2023 22:42:09 +0300 Subject: [PATCH] Logind fallback support for unprivileged users (#83) --- .github/workflows/ci.yml | 4 +-- Cargo.lock | 21 +++++++++++++++ Cargo.toml | 1 + README.md | 8 ++++-- src/brightness/backlight.rs | 51 ++++++++++++++++++++++++++++++++++-- src/brightness/controller.rs | 2 +- 6 files changed, 80 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d4baa22..e9c9e0b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: steps: - uses: actions/checkout@v3 - run: sudo apt-get update - - run: sudo apt-get -y install v4l-utils libv4l-dev libudev-dev libvulkan-dev + - run: sudo apt-get -y install v4l-utils libv4l-dev libudev-dev libvulkan-dev libdbus-1-dev - run: make test lint: @@ -21,5 +21,5 @@ jobs: steps: - uses: actions/checkout@v3 - run: sudo apt-get update - - run: sudo apt-get -y install v4l-utils libv4l-dev libudev-dev libvulkan-dev + - run: sudo apt-get -y install v4l-utils libv4l-dev libudev-dev libvulkan-dev libdbus-1-dev - run: make lint diff --git a/Cargo.lock b/Cargo.lock index 2c13ab7..7cd4150 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -238,6 +238,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "dbus" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bb21987b9fb1613058ba3843121dd18b163b254d8a6e797e144cbac14d96d1b" +dependencies = [ + "libc", + "libdbus-sys", + "winapi", +] + [[package]] name = "ddc" version = "0.2.2" @@ -622,6 +633,15 @@ version = "0.2.141" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" +[[package]] +name = "libdbus-sys" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06085512b750d640299b79be4bad3d2fa90a9c00b1fd9e1b46364f66f0485c72" +dependencies = [ + "pkg-config", +] + [[package]] name = "libloading" version = "0.7.4" @@ -1515,6 +1535,7 @@ version = "4.3.0" dependencies = [ "ash", "chrono", + "dbus", "ddc-hi", "env_logger", "inotify", diff --git a/Cargo.toml b/Cargo.toml index dd905bb..7e2da87 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ env_logger = "0.9" inotify = "0.10" lazy_static = "1.4" xdg = "2.4.1" +dbus = "0.9.7" [dev-dependencies] mockall = "0.11.4" diff --git a/README.md b/README.md index ffdbaf8..53f6bf2 100644 --- a/README.md +++ b/README.md @@ -36,13 +36,17 @@ Use one of the available packages and methods below: [![CI](https://github.com/maximbaz/wluma/actions/workflows/ci.yml/badge.svg)](https://github.com/maximbaz/wluma/actions/workflows/ci.yml) -If you want to build the app yourself, make sure you use latest stable Rust, otherwise you might get compilation errors! Using `rustup` is perhaps the easiest. Ubuntu needs the following dependencies: `sudo apt-get -y install v4l-utils libv4l-dev libudev-dev libvulkan-dev`. +If you want to build the app yourself, make sure you use latest stable Rust, otherwise you might get compilation errors! Using `rustup` is perhaps the easiest. Ubuntu needs the following dependencies: `sudo apt-get -y install v4l-utils libv4l-dev libudev-dev libvulkan-dev libdbus-1-dev`. Then simply run `make build`. ## Permissions -In order to access backlight devices, `wluma` must either run as `root`, or preferrably instead you should add your user to `video` group in combination with installing the supplied `90-wluma-backlight.rules` udev rule (don't forget to reboot thereafter). +In order to access backlight devices, `wluma` must either: + +- have direct driver access: install the supplied `90-wluma-backlight.rules` udev rule, add your user to the `video` group and reboot (fastest) +- run on a system that uses `elogind` or `systemd-logind` (they provide a safe interface for unprivileged users to control device's brightness through `dbus`, no configuration necessary) +- run as `root` (not recommended) ## Configuration diff --git a/src/brightness/backlight.rs b/src/brightness/backlight.rs index b34adbf..e6b110d 100644 --- a/src/brightness/backlight.rs +++ b/src/brightness/backlight.rs @@ -1,4 +1,6 @@ use crate::device_file::{read, write}; +use dbus::channel::Sender; +use dbus::{self, blocking::Connection, Message}; use inotify::{Inotify, WatchMask}; use std::error::Error; use std::fs; @@ -6,21 +8,55 @@ use std::fs::{File, OpenOptions}; use std::io::ErrorKind; use std::path::Path; +struct Dbus { + connection: Connection, + message: Message, +} + pub struct Backlight { file: File, min_brightness: u64, max_brightness: u64, inotify: Inotify, current: Option, + dbus: Option, + has_write_permission: bool, } impl Backlight { pub fn new(path: &str, min_brightness: u64) -> Result> { let brightness_path = Path::new(path).join("brightness"); - let file = OpenOptions::new() + let mut file = OpenOptions::new() .read(true) .write(true) .open(&brightness_path)?; + let current_brightness = read(&mut file)?; + let has_write_permission = write(&mut file, current_brightness).is_ok(); + + let dbus = if has_write_permission { + None + } else { + let id = Path::new(path) + .file_name() + .and_then(|x| x.to_str()) + .ok_or("Unable to identify backlight ID")?; + + let message = Message::new_method_call( + "org.freedesktop.login1", + "/org/freedesktop/login1/session/auto", + "org.freedesktop.login1.Session", + "SetBrightness", + ) + .ok() + .map(|m| m.append2("backlight", id)); + + Connection::new_system().ok().and_then(|connection| { + message.map(|message| Dbus { + connection, + message, + }) + }) + }; let max_brightness = fs::read_to_string(Path::new(path).join("max_brightness"))? .trim() @@ -40,6 +76,8 @@ impl Backlight { max_brightness, inotify, current: None, + dbus, + has_write_permission, }) } } @@ -70,7 +108,16 @@ impl super::Brightness for Backlight { fn set(&mut self, value: u64) -> Result> { let value = value.clamp(self.min_brightness, self.max_brightness); - write(&mut self.file, value as f64)?; + if self.has_write_permission { + write(&mut self.file, value as f64)?; + } else if let Some(dbus) = &self.dbus { + dbus.connection + .send(dbus.message.duplicate()?.append1(value as u32)) + .map_err(|_| "Unable to send brightness change message via dbus")?; + } else { + Err(std::io::Error::from(ErrorKind::PermissionDenied))? + } + self.current = Some(value); // Consume file events to not trigger get() update diff --git a/src/brightness/controller.rs b/src/brightness/controller.rs index 6562aae..b7ebbeb 100644 --- a/src/brightness/controller.rs +++ b/src/brightness/controller.rs @@ -103,7 +103,7 @@ impl Controller { if target.reached(current) { self.target = None; } else { - let new_value = (current as i64 + target.step).max(0) as u64; + let new_value = current.saturating_add_signed(target.step); match self.brightness.set(new_value) { Ok(new_value) => self.current = Some(new_value), Err(err) => log::error!(