@@ -67,58 +67,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
67
67
}
68
68
} ;
69
69
70
- log:: trace!( "Setting process umask." ) ;
71
- umask ( Mode :: S_IWGRP | Mode :: S_IWOTH ) ;
72
-
73
- let runtime_path = "/run/swhkd/" ;
74
- if !Path :: new ( runtime_path) . exists ( ) {
75
- match fs:: create_dir_all ( Path :: new ( runtime_path) ) {
76
- Ok ( _) => {
77
- log:: debug!( "Created runtime directory." ) ;
78
- match fs:: set_permissions ( Path :: new ( runtime_path) , Permissions :: from_mode ( 0o600 ) ) {
79
- Ok ( _) => log:: debug!( "Set runtime directory to readonly." ) ,
80
- Err ( e) => log:: error!( "Failed to set runtime directory to readonly: {}" , e) ,
81
- }
82
- }
83
- Err ( e) => log:: error!( "Failed to create runtime directory: {}" , e) ,
84
- }
85
- }
86
-
87
- let pidfile: String = format ! ( "{}swhkd_{}.pid" , runtime_path, invoking_uid) ;
88
- if Path :: new ( & pidfile) . exists ( ) {
89
- log:: trace!( "Reading {} file and checking for running instances." , pidfile) ;
90
- let swhkd_pid = match fs:: read_to_string ( & pidfile) {
91
- Ok ( swhkd_pid) => swhkd_pid,
92
- Err ( e) => {
93
- log:: error!( "Unable to read {} to check all running instances" , e) ;
94
- exit ( 1 ) ;
95
- }
96
- } ;
97
- log:: debug!( "Previous PID: {}" , swhkd_pid) ;
98
-
99
- let mut sys = System :: new_all ( ) ;
100
- sys. refresh_all ( ) ;
101
- for ( pid, process) in sys. processes ( ) {
102
- if pid. to_string ( ) == swhkd_pid && process. exe ( ) == env:: current_exe ( ) . unwrap ( ) {
103
- log:: error!( "Swhkd is already running!" ) ;
104
- log:: error!( "pid of existing swhkd process: {}" , pid. to_string( ) ) ;
105
- log:: error!( "To close the existing swhkd process, run `sudo killall swhkd`" ) ;
106
- exit ( 1 ) ;
107
- }
108
- }
109
- }
110
-
111
- match fs:: write ( & pidfile, id ( ) . to_string ( ) ) {
112
- Ok ( _) => { }
113
- Err ( e) => {
114
- log:: error!( "Unable to write to {}: {}" , pidfile, e) ;
115
- exit ( 1 ) ;
116
- }
117
- }
118
-
119
- if check_user_permissions ( ) . is_err ( ) {
120
- exit ( 1 ) ;
121
- }
70
+ setup_swhkd ( invoking_uid) ;
122
71
123
72
let root_resuid = perms:: get_resuid ( ) ;
124
73
let root_resgid = perms:: get_resgid ( ) ;
@@ -212,7 +161,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
212
161
tokio:: pin!( hotkey_repeat_timer) ;
213
162
214
163
// The socket that we're sending the commands to.
215
- let socket_file_path = fetch_xdg_runtime_path ( ) ;
164
+ let socket_file_path = fetch_xdg_runtime_socket_path ( ) ;
216
165
loop {
217
166
select ! {
218
167
_ = & mut hotkey_repeat_timer, if & last_hotkey. is_some( ) => {
@@ -372,7 +321,7 @@ fn send_command(hotkey: config::Hotkey, socket_path: &Path) {
372
321
}
373
322
}
374
323
375
- pub fn check_user_permissions ( ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
324
+ pub fn check_input_group ( ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
376
325
if !Uid :: current ( ) . is_root ( ) {
377
326
let groups = nix:: unistd:: getgroups ( ) ;
378
327
for ( _, groups) in groups. iter ( ) . enumerate ( ) {
@@ -440,7 +389,7 @@ pub fn fetch_xdg_config_path() -> PathBuf {
440
389
config_file_path
441
390
}
442
391
443
- pub fn fetch_xdg_runtime_path ( ) -> PathBuf {
392
+ pub fn fetch_xdg_runtime_socket_path ( ) -> PathBuf {
444
393
match env:: var ( "XDG_RUNTIME_DIR" ) {
445
394
Ok ( val) => {
446
395
log:: debug!( "XDG_RUNTIME_DIR exists: {:#?}" , val) ;
@@ -453,3 +402,73 @@ pub fn fetch_xdg_runtime_path() -> PathBuf {
453
402
}
454
403
}
455
404
}
405
+
406
+ pub fn setup_swhkd ( invoking_uid : u32 ) {
407
+ // Set a sane process umask.
408
+ log:: trace!( "Setting process umask." ) ;
409
+ umask ( Mode :: S_IWGRP | Mode :: S_IWOTH ) ;
410
+
411
+ // Get the runtime path and create it if needed.
412
+ let runtime_path: String = match env:: var ( "XDG_RUNTIME_DIR" ) {
413
+ Ok ( runtime_path) => {
414
+ log:: debug!( "XDG_RUNTIME_DIR exists: {:#?}" , runtime_path) ;
415
+ Path :: new ( & runtime_path) . join ( "swhkd" ) . to_str ( ) . unwrap ( ) . to_owned ( )
416
+ }
417
+ Err ( _) => {
418
+ log:: error!( "XDG_RUNTIME_DIR has not been set." ) ;
419
+ String :: from ( "/run/swhkd/" )
420
+ }
421
+ } ;
422
+ if !Path :: new ( & runtime_path) . exists ( ) {
423
+ match fs:: create_dir_all ( Path :: new ( & runtime_path) ) {
424
+ Ok ( _) => {
425
+ log:: debug!( "Created runtime directory." ) ;
426
+ match fs:: set_permissions ( Path :: new ( & runtime_path) , Permissions :: from_mode ( 0o600 ) ) {
427
+ Ok ( _) => log:: debug!( "Set runtime directory to readonly." ) ,
428
+ Err ( e) => log:: error!( "Failed to set runtime directory to readonly: {}" , e) ,
429
+ }
430
+ }
431
+ Err ( e) => log:: error!( "Failed to create runtime directory: {}" , e) ,
432
+ }
433
+ }
434
+
435
+ // Get the PID file path for instance tracking.
436
+ let pidfile: String = format ! ( "{}swhkd_{}.pid" , runtime_path, invoking_uid) ;
437
+ if Path :: new ( & pidfile) . exists ( ) {
438
+ log:: trace!( "Reading {} file and checking for running instances." , pidfile) ;
439
+ let swhkd_pid = match fs:: read_to_string ( & pidfile) {
440
+ Ok ( swhkd_pid) => swhkd_pid,
441
+ Err ( e) => {
442
+ log:: error!( "Unable to read {} to check all running instances" , e) ;
443
+ exit ( 1 ) ;
444
+ }
445
+ } ;
446
+ log:: debug!( "Previous PID: {}" , swhkd_pid) ;
447
+
448
+ // Check if swhkd is already running!
449
+ let mut sys = System :: new_all ( ) ;
450
+ sys. refresh_all ( ) ;
451
+ for ( pid, process) in sys. processes ( ) {
452
+ if pid. to_string ( ) == swhkd_pid && process. exe ( ) == env:: current_exe ( ) . unwrap ( ) {
453
+ log:: error!( "Swhkd is already running!" ) ;
454
+ log:: error!( "pid of existing swhkd process: {}" , pid. to_string( ) ) ;
455
+ log:: error!( "To close the existing swhkd process, run `sudo killall swhkd`" ) ;
456
+ exit ( 1 ) ;
457
+ }
458
+ }
459
+ }
460
+
461
+ // Write to the pid file.
462
+ match fs:: write ( & pidfile, id ( ) . to_string ( ) ) {
463
+ Ok ( _) => { }
464
+ Err ( e) => {
465
+ log:: error!( "Unable to write to {}: {}" , pidfile, e) ;
466
+ exit ( 1 ) ;
467
+ }
468
+ }
469
+
470
+ // Check if the user is in input group.
471
+ if check_input_group ( ) . is_err ( ) {
472
+ exit ( 1 ) ;
473
+ }
474
+ }
0 commit comments