@@ -30,11 +30,33 @@ pub async fn hide_device(path: &str) -> Result<(), Box<dyn Error>> {
3030 return Err ( "Unable to create match rule for device" . into ( ) ) ;
3131 } ;
3232
33+ // Create the directory to move devnodes to
34+ tokio:: fs:: create_dir_all ( "/dev/inputplumber/sources" ) . await ?;
35+
3336 // Find the chmod command to use for hiding
3437 let chmod_cmd = if Path :: new ( "/bin/chmod" ) . exists ( ) {
35- "/bin/chmod"
38+ "/bin/chmod" . to_string ( )
39+ } else if Path :: new ( "/usr/bin/chmod" ) . exists ( ) {
40+ "/usr/bin/chmod" . to_string ( )
3641 } else {
37- "/usr/bin/chmod"
42+ let output = Command :: new ( "which" ) . arg ( "chmod" ) . output ( ) . await ?;
43+ if !output. status . success ( ) {
44+ return Err ( "Unable to determine chmod command location" . into ( ) ) ;
45+ }
46+ str:: from_utf8 ( output. stdout . as_slice ( ) ) ?. trim ( ) . to_string ( )
47+ } ;
48+
49+ // Find the mv command to use for hiding
50+ let mv_cmd = if Path :: new ( "/bin/mv" ) . exists ( ) {
51+ "/bin/mv" . to_string ( )
52+ } else if Path :: new ( "/usr/bin/mv" ) . exists ( ) {
53+ "/usr/bin/mv" . to_string ( )
54+ } else {
55+ let output = std:: process:: Command :: new ( "which" ) . arg ( "mv" ) . output ( ) ?;
56+ if !output. status . success ( ) {
57+ return Err ( "Unable to determine mv command location" . into ( ) ) ;
58+ }
59+ str:: from_utf8 ( output. stdout . as_slice ( ) ) ?. trim ( ) . to_string ( )
3860 } ;
3961
4062 // Create an early udev rule to hide the device
@@ -44,8 +66,10 @@ pub async fn hide_device(path: &str) -> Result<(), Box<dyn Error>> {
4466{match_rule}, GOTO="inputplumber_valid"
4567GOTO="inputplumber_end"
4668LABEL="inputplumber_valid"
47- KERNEL=="js[0-9]*|event[0-9]*", SUBSYSTEM=="{subsystem}", MODE:="0000", GROUP:="root", RUN:="{chmod_cmd} 000 /dev/input/%k", SYMLINK+="inputplumber/by-hidden/%k"
48- KERNEL=="hidraw[0-9]*", SUBSYSTEM=="{subsystem}", MODE:="0000", GROUP:="root", RUN:="{chmod_cmd} 000 /dev/%k", SYMLINK+="inputplumber/by-hidden/%k"
69+ KERNEL=="js[0-9]*|event[0-9]*", SUBSYSTEM=="{subsystem}", MODE:="0000", GROUP:="root", RUN+="{chmod_cmd} 000 /dev/input/%k", SYMLINK+="inputplumber/by-hidden/%k"
70+ KERNEL=="hidraw[0-9]*", SUBSYSTEM=="{subsystem}", MODE:="0000", GROUP:="root", RUN+="{chmod_cmd} 000 /dev/%k", SYMLINK+="inputplumber/by-hidden/%k"
71+ KERNEL=="js[0-9]*|event[0-9]*", SUBSYSTEM=="{subsystem}", RUN+="{mv_cmd} /dev/input/%k /dev/inputplumber/sources/%k"
72+ KERNEL=="hidraw[0-9]*", SUBSYSTEM=="{subsystem}", RUN+="{mv_cmd} /dev/%k /dev/inputplumber/sources/%k"
4973LABEL="inputplumber_end"
5074"#
5175 ) ;
@@ -65,6 +89,8 @@ GOTO="inputplumber_end"
6589LABEL="inputplumber_valid"
6690KERNEL=="js[0-9]*|event[0-9]*", SUBSYSTEM=="{subsystem}", MODE="000", GROUP="root", TAG-="uaccess", RUN+="{chmod_cmd} 000 /dev/input/%k"
6791KERNEL=="hidraw[0-9]*", SUBSYSTEM=="{subsystem}", MODE="000", GROUP="root", TAG-="uaccess", RUN+="{chmod_cmd} 000 /dev/%k"
92+ KERNEL=="js[0-9]*|event[0-9]*", SUBSYSTEM=="{subsystem}", RUN+="{mv_cmd} /dev/input/%k /dev/inputplumber/sources/%k"
93+ KERNEL=="hidraw[0-9]*", SUBSYSTEM=="{subsystem}", RUN+="{mv_cmd} /dev/%k /dev/inputplumber/sources/%k"
6894LABEL="inputplumber_end"
6995"#
7096 ) ;
@@ -96,6 +122,17 @@ pub async fn unhide_device(path: String) -> Result<(), Box<dyn Error>> {
96122 ) ;
97123 fs:: remove_file ( rule_path) ?;
98124
125+ // Move the device back
126+ let src_path = format ! ( "/dev/inputplumber/sources/{name}" ) ;
127+ let dst_path = if name. as_str ( ) . starts_with ( "event" ) {
128+ format ! ( "/dev/input/{name}" )
129+ } else {
130+ format ! ( "/dev/{name}" )
131+ } ;
132+ if let Err ( e) = fs:: rename ( & src_path, & dst_path) {
133+ log:: warn!( "Failed to move device node from {src_path} to {dst_path}: {e}" ) ;
134+ }
135+
99136 // Reload udev
100137 reload_children ( parent) . await ?;
101138
@@ -104,6 +141,7 @@ pub async fn unhide_device(path: String) -> Result<(), Box<dyn Error>> {
104141
105142/// Unhide all devices hidden by InputPlumber
106143pub async fn unhide_all ( ) -> Result < ( ) , Box < dyn Error > > {
144+ // Remove all created udev rules
107145 let entries = fs:: read_dir ( RULES_PREFIX ) ?;
108146 for entry in entries {
109147 let Ok ( entry) = entry else {
@@ -117,6 +155,24 @@ pub async fn unhide_all() -> Result<(), Box<dyn Error>> {
117155 fs:: remove_file ( path) ?;
118156 }
119157
158+ // Move all devices back
159+ let entries = fs:: read_dir ( "/dev/inputplumber/sources" ) ?;
160+ for entry in entries {
161+ let Ok ( entry) = entry else {
162+ continue ;
163+ } ;
164+ let path = entry. path ( ) ;
165+ let name = entry. file_name ( ) . to_string_lossy ( ) . to_string ( ) ;
166+ let dst_path = if name. as_str ( ) . starts_with ( "event" ) {
167+ format ! ( "/dev/input/{name}" )
168+ } else {
169+ format ! ( "/dev/{name}" )
170+ } ;
171+ if let Err ( e) = fs:: rename ( & path, & dst_path) {
172+ log:: warn!( "Failed to move device node from {path:?} to {dst_path}: {e}" ) ;
173+ }
174+ }
175+
120176 // Reload udev rules
121177 reload_all ( ) . await ?;
122178
0 commit comments