diff --git a/src/greeter.rs b/src/greeter.rs index 735077a..bc3a22e 100644 --- a/src/greeter.rs +++ b/src/greeter.rs @@ -90,6 +90,8 @@ impl SecretDisplay { #[derive(SmartDefault)] pub struct Greeter { + pub debug: bool, + #[default(DEFAULT_LOCALE)] pub locale: Locale, pub config: Option, @@ -351,6 +353,7 @@ impl Greeter { let xsession_wrapper_desc = format!("wrapper command to initialize X server and launch X11 sessions (default: {DEFAULT_XSESSION_WRAPPER})"); + opts.optflag("d", "debug", "enable debug logging to /tmp/tuigreet.log"); opts.optflag("h", "help", "show this usage information"); opts.optflag("v", "version", "print version information"); opts.optopt("c", "cmd", "command to run", "COMMAND"); @@ -418,6 +421,10 @@ impl Greeter { } } + if self.config().opt_present("debug") { + self.debug = true; + } + if self.config().opt_present("issue") && self.config().opt_present("greeting") { eprintln!("Only one of --issue and --greeting may be used at the same time"); print_usage(opts); @@ -463,7 +470,9 @@ impl Greeter { title: fl!("title_users"), options: get_users(min_uid, max_uid), selected: 0, - } + }; + + log!(self.debug, "found {} users", self.users.options.len()); } if self.config().opt_present("remember-session") && self.config().opt_present("remember-user-session") { diff --git a/src/info.rs b/src/info.rs index 13cd616..c6b3cc4 100644 --- a/src/info.rs +++ b/src/info.rs @@ -229,6 +229,8 @@ pub fn get_sessions(greeter: &Greeter) -> Result, Box> { files.sort_by(|a, b| a.name.cmp(&b.name)); + log!(greeter.debug, "found {} sessions", files.len()); + Ok(files) } diff --git a/src/ipc.rs b/src/ipc.rs index 7687847..d032698 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -9,6 +9,7 @@ use tokio::sync::{ use crate::{ event::Event, info::{delete_last_user_session, delete_last_user_session_path, write_last_user_session, write_last_user_session_path, write_last_username}, + macros::SafeDebug, ui::sessions::{Session, SessionSource, SessionType}, AuthStatus, Greeter, Mode, }; @@ -31,7 +32,9 @@ impl Ipc { })) } - pub async fn send(&self, request: Request) { + pub async fn send(&self, greeter: &Greeter, request: Request) { + log!(greeter.debug, "sending request to greetd: {}", request.safe_repr()); + let _ = self.0.tx.read().await.send(request).await; } @@ -66,6 +69,8 @@ impl Ipc { } async fn parse_response(&mut self, greeter: &mut Greeter, response: Response) -> Result<(), Box> { + log!(greeter.debug, "received greetd message: {:?}", response); + match response { Response::AuthMessage { auth_message_type, auth_message } => match auth_message_type { AuthMessageType::Secret => { @@ -85,7 +90,7 @@ impl Ipc { AuthMessageType::Error => { greeter.message = Some(auth_message); - self.send(Request::PostAuthMessageResponse { response: None }).await; + self.send(greeter, Request::PostAuthMessageResponse { response: None }).await; } AuthMessageType::Info => { @@ -98,12 +103,14 @@ impl Ipc { greeter.message = Some(auth_message.trim_end().to_string()); } - self.send(Request::PostAuthMessageResponse { response: None }).await; + self.send(greeter, Request::PostAuthMessageResponse { response: None }).await; } }, Response::Success => { if greeter.done { + log!(greeter.debug, "greetd acknowledged session start, exiting"); + if greeter.remember { write_last_username(&greeter.username); @@ -130,6 +137,8 @@ impl Ipc { let _ = sender.send(Event::Exit(AuthStatus::Success)).await; } } else { + log!(greeter.debug, "authentication successful, starting session"); + let command = greeter.session_source.command(greeter).map(str::to_string); if let Some(command) = command { @@ -148,10 +157,13 @@ impl Ipc { let _ = env; self - .send(Request::StartSession { - cmd: vec!["true".to_string()], - env: vec![], - }) + .send( + greeter, + Request::StartSession { + cmd: vec!["true".to_string()], + env: vec![], + }, + ) .await; } } @@ -165,9 +177,12 @@ impl Ipc { ErrorType::AuthError => { greeter.message = Some(fl!("failed")); self - .send(Request::CreateSession { - username: greeter.username.value.clone(), - }) + .send( + greeter, + Request::CreateSession { + username: greeter.username.value.clone(), + }, + ) .await; greeter.reset(true).await; } diff --git a/src/keyboard.rs b/src/keyboard.rs index 27f6401..e5e69c8 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -212,9 +212,12 @@ pub async fn handle(greeter: Arc>, input: KeyEvent, ipc: Ipc) -> greeter.message = None; ipc - .send(Request::PostAuthMessageResponse { - response: Some(greeter.buffer.clone()), - }) + .send( + &greeter, + Request::PostAuthMessageResponse { + response: Some(greeter.buffer.clone()), + }, + ) .await; greeter.buffer = String::new(); @@ -356,9 +359,12 @@ async fn validate_username(greeter: &mut Greeter, ipc: &Ipc) { greeter.message = None; ipc - .send(Request::CreateSession { - username: greeter.username.value.clone(), - }) + .send( + greeter, + Request::CreateSession { + username: greeter.username.value.clone(), + }, + ) .await; greeter.buffer = String::new(); diff --git a/src/macros.rs b/src/macros.rs index 90941cb..a80f980 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1,9 +1,52 @@ +use greetd_ipc::Request; + +pub const LOG_FILE: &str = "/tmp/tuigreet.log"; + +pub trait SafeDebug { + fn safe_repr(&self) -> String; +} + +impl SafeDebug for Request { + fn safe_repr(&self) -> String { + match self { + msg @ &Request::CancelSession => format!("{:?}", msg), + msg @ &Request::CreateSession { .. } => format!("{:?}", msg), + &Request::PostAuthMessageResponse { .. } => "PostAuthMessageResponse".to_string(), + msg @ &Request::StartSession { .. } => format!("{:?}", msg), + } + } +} + macro_rules! fl { ($message_id:literal) => {{ i18n_embed_fl::fl!($crate::ui::MESSAGES, $message_id) }}; ($message_id:literal, $($args:expr),*) => {{ - i18n_embed_fl::fl!($crate::ui::MESSAGES, $message_id, $($args), *) + i18n_embed_fl::fl!($crate::ui::MESSAGES, $message_id, $($args),*) + }}; +} + +macro_rules! log { + ($enabled:expr, $message:literal) => {{ + if $enabled { + use std::{io::Write, fs::OpenOptions}; + + if let Ok(mut file) = OpenOptions::new().write(true).append(true).open(crate::macros::LOG_FILE) { + let _ = write!(file, "{}: ", chrono::Utc::now().to_string()); + let _ = writeln!(file, $message); + } + } + }}; + + ($enabled:expr, $message:literal, $($args:expr),*) => {{ + if $enabled { + use std::{io::Write, fs::OpenOptions}; + + if let Ok(mut file) = OpenOptions::new().write(true).append(true).open(crate::macros::LOG_FILE) { + let _ = write!(file, "{}: ", chrono::Utc::now().to_string()); + let _ = writeln!(file, $message, $($args),*); + } + } }}; } diff --git a/src/main.rs b/src/main.rs index 767ce60..11833e0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -42,6 +42,8 @@ async fn run() -> Result<(), Box> { let mut greeter = Greeter::new(events.sender()).await; let mut stdout = io::stdout(); + log!(greeter.debug, "tuigreet started"); + register_panic_handler(); enable_raw_mode()?; @@ -57,10 +59,15 @@ async fn run() -> Result<(), Box> { if greeter.remember && !greeter.username.value.is_empty() { greeter.working = true; + log!(greeter.debug, "creating remembered session for user {}", greeter.username.value); + ipc - .send(Request::CreateSession { - username: greeter.username.value.clone(), - }) + .send( + &greeter, + Request::CreateSession { + username: greeter.username.value.clone(), + }, + ) .await; } @@ -79,6 +86,8 @@ async fn run() -> Result<(), Box> { loop { if let Some(status) = greeter.read().await.exit { + log!(greeter.read().await.debug, "exiting main loop"); + return Err(status.into()); } @@ -100,6 +109,8 @@ async fn run() -> Result<(), Box> { } async fn exit(greeter: &mut Greeter, status: AuthStatus) { + log!(greeter.debug, "preparing exit with status {}", status); + match status { AuthStatus::Success => {} AuthStatus::Cancel | AuthStatus::Failure => Ipc::cancel(greeter).await,