From be878ad3583f4c33786ba4e930218e619da0ce29 Mon Sep 17 00:00:00 2001 From: William Edwards Date: Sat, 15 Feb 2025 12:28:09 -0800 Subject: [PATCH] fix(CompositeDevice): use early and late rules to fix hiding devices at boot time --- src/input/manager.rs | 6 ------ src/udev/mod.rs | 34 +++++++++++++++++++++++++++------- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/input/manager.rs b/src/input/manager.rs index 33d0b00..5aeebc3 100644 --- a/src/input/manager.rs +++ b/src/input/manager.rs @@ -211,12 +211,6 @@ impl Manager { /// Starts listening for [Command] messages to be sent from clients and /// dispatch those events. pub async fn run(&mut self) -> Result<(), Box> { - // Delay initial discovery by a short amount of time to allow udev - // rules to process for the first time. - // TODO: Figure out a better way to prevent udev from not running hiding - // rules too early in boot. - tokio::time::sleep(Duration::from_millis(4000)).await; - let dbus_for_listen_on_dbus = self.dbus.clone(); let cmd_tx_all_devices = self.tx.clone(); diff --git a/src/udev/mod.rs b/src/udev/mod.rs index 43cf7b2..756210c 100644 --- a/src/udev/mod.rs +++ b/src/udev/mod.rs @@ -13,7 +13,8 @@ use udev::Enumerator; use self::device::Device; -const RULE_HIDE_DEVICE_PRIORITY: &str = "50"; +const RULE_HIDE_DEVICE_EARLY_PRIORITY: &str = "50"; +const RULE_HIDE_DEVICE_LATE_PRIORITY: &str = "96"; const RULES_PREFIX: &str = "/run/udev/rules.d"; /// Hide the given input device from regular users. @@ -36,7 +37,7 @@ pub async fn hide_device(path: &str) -> Result<(), Box> { "/usr/bin/chmod" }; - // Create a udev rule to hide the device + // Create an early udev rule to hide the device let rule = format!( r#"# Hides devices stemming from {name} # Managed by InputPlumber, this file will be autoremoved during configuration changes. @@ -48,11 +49,26 @@ KERNEL=="hidraw[0-9]*", SUBSYSTEM=="{subsystem}", MODE:="0000", GROUP:="root", R LABEL="inputplumber_end" "# ); - - // Write the udev rule fs::create_dir_all(RULES_PREFIX)?; let rule_path = - format!("{RULES_PREFIX}/{RULE_HIDE_DEVICE_PRIORITY}-inputplumber-hide-{name}.rules"); + format!("{RULES_PREFIX}/{RULE_HIDE_DEVICE_EARLY_PRIORITY}-inputplumber-hide-{name}.rules"); + fs::write(rule_path, rule)?; + + // Create a late udev rule to hide the device. This is needed for devices that + // are available at boot time because the early rule will not be applied. + let rule = format!( + r#"# Hides devices stemming from {name} +# Managed by InputPlumber, this file will be autoremoved during configuration changes. +{match_rule}, GOTO="inputplumber_valid" +GOTO="inputplumber_end" +LABEL="inputplumber_valid" +KERNEL=="js[0-9]*|event[0-9]*", SUBSYSTEM=="{subsystem}", MODE="000", GROUP="root", TAG-="uaccess", RUN+="{chmod_cmd} 000 /dev/input/%k" +KERNEL=="hidraw[0-9]*", SUBSYSTEM=="{subsystem}", MODE="000", GROUP="root", TAG-="uaccess", RUN+="{chmod_cmd} 000 /dev/%k" +LABEL="inputplumber_end" +"# + ); + let rule_path = + format!("{RULES_PREFIX}/{RULE_HIDE_DEVICE_LATE_PRIORITY}-inputplumber-hide-{name}.rules"); fs::write(rule_path, rule)?; // Reload udev @@ -70,7 +86,10 @@ pub async fn unhide_device(path: String) -> Result<(), Box> { return Err("Unable to determine parent for device".into()); }; let rule_path = - format!("{RULES_PREFIX}/{RULE_HIDE_DEVICE_PRIORITY}-inputplumber-hide-{name}.rules"); + format!("{RULES_PREFIX}/{RULE_HIDE_DEVICE_EARLY_PRIORITY}-inputplumber-hide-{name}.rules"); + fs::remove_file(rule_path)?; + let rule_path = + format!("{RULES_PREFIX}/{RULE_HIDE_DEVICE_LATE_PRIORITY}-inputplumber-hide-{name}.rules"); fs::remove_file(rule_path)?; // Reload udev @@ -87,7 +106,8 @@ pub async fn unhide_all() -> Result<(), Box> { continue; }; let filename = entry.file_name().to_string_lossy().to_string(); - if !filename.starts_with(format!("{RULE_HIDE_DEVICE_PRIORITY}-inputplumber-hide").as_str()) + if !filename + .starts_with(format!("{RULE_HIDE_DEVICE_EARLY_PRIORITY}-inputplumber-hide").as_str()) { continue; }