diff --git a/extra/config.toml b/extra/config.toml index 101baf6..8f693ff 100644 --- a/extra/config.toml +++ b/extra/config.toml @@ -48,6 +48,13 @@ x11_display = ":1" # to 0. xserver_timeout_secs = 60 +# Where to log to for the client. The Client is the Desktop Environment or +# Window Manager for Xorg, the Compositor for Wayland and the Shell for TTY. +client_log_path = "/var/log/lemurs.client.log" + +# Where to log to for the XServer. +xserver_log_path = "/var/log/lemurs.xorg.log" + # The PAM service that should be used to login pam_service = "lemurs" diff --git a/src/config.rs b/src/config.rs index c772844..cad0d92 100644 --- a/src/config.rs +++ b/src/config.rs @@ -156,6 +156,9 @@ toml_config_struct! { Config, PartialConfig, x11_display => String, xserver_timeout_secs => u16, + client_log_path => String, + xserver_log_path => String, + pam_service => String, shell_login_flag => ShellLoginFlag, diff --git a/src/post_login/mod.rs b/src/post_login/mod.rs index cab8fe7..5abaabf 100644 --- a/src/post_login/mod.rs +++ b/src/post_login/mod.rs @@ -1,7 +1,9 @@ use log::{error, info, warn}; use std::error::Error; use std::fmt::Display; -use std::fs; +use std::fs::{self, File}; +use std::os::fd::{FromRawFd, IntoRawFd}; +use std::path::Path; use users::get_user_groups; @@ -73,6 +75,16 @@ impl From for EnvironmentStartError { } } +fn output_command_to_log(mut command: Command, log_path: &Path) -> Command { + let fd = File::create(log_path).unwrap().into_raw_fd(); + + command + .stdout(unsafe { Stdio::from_raw_fd(fd) }) + .stderr(unsafe { Stdio::from_raw_fd(fd) }); + + command +} + fn lower_command_permissions_to_user( mut command: Command, user_info: &AuthUserInfo<'_>, @@ -113,44 +125,29 @@ impl SpawnedEnvironment { } pub fn wait(self) { - let child = match self { - Self::X11 { client, .. } | Self::Wayland(client) | Self::Tty(client) => client, - }; + info!("Waiting for client to exit"); - let child_output = match child.wait_with_output() { - Ok(output) => output, - Err(err) => { - error!("Failed to wait for environment to exit, Reason: '{}'", err); - return; - } - }; - - // Print the stdout if it is at all available - match std::str::from_utf8(&child_output.stdout) { - Ok(output) => { - if !output.trim().is_empty() { - info!("Environment's stdout: \"\"\"\n{}\n\"\"\"", output.trim()); - } - } - Err(err) => { - warn!("Failed to read STDOUT output as UTF-8. Reason: '{}'", err); - } - }; - - // Return the `stderr` if the child process did not exit correctly. - if !child_output.status.success() { - warn!("Environment came back with non-zero exit code."); - - match std::str::from_utf8(&child_output.stderr) { - Ok(output) => { - if !output.trim().is_empty() { - warn!("Environment's stderr: \"\"\"\n{}\n\"\"\"", output.trim()); + match self { + Self::X11 { + mut client, + mut server, + } => { + match client.wait() { + Ok(exit_code) => info!("Client exited with exit code `{exit_code}`"), + Err(err) => { + error!("Failed to wait for client. Reason: {err}"); } + }; + + match server.kill() { + Ok(_) => {} + Err(err) => error!("Failed to terminate X11. Reason: {err}"), } - Err(err) => { - warn!("Failed to read STDERR output as UTF-8. Reason: '{}'", err); - } - }; + } + Self::Wayland(mut client) | Self::Tty(mut client) => match client.wait() { + Ok(exit_code) => info!("Client exited with exit code `{exit_code}`"), + Err(err) => error!("Failed to wait for client. Reason: {err}"), + }, } } } @@ -168,7 +165,13 @@ impl PostLoginEnvironment { ShellLoginFlag::Long => Some("--login"), }; - let mut client = lower_command_permissions_to_user(Command::new(SYSTEM_SHELL), user_info); + let client = lower_command_permissions_to_user(Command::new(SYSTEM_SHELL), user_info); + + info!( + "Setup client to log `stdout` and `stderr` to '{log_path}'", + log_path = config.client_log_path + ); + let mut client = output_command_to_log(client, Path::new(&config.client_log_path)); if let Some(shell_login_flag) = shell_login_flag { client.arg(shell_login_flag); @@ -184,8 +187,6 @@ impl PostLoginEnvironment { let client = match client .arg(format!("{} {}", "/etc/lemurs/xsetup.sh", xinitrc_path)) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) .spawn() { Ok(child) => child, @@ -199,12 +200,7 @@ impl PostLoginEnvironment { } PostLoginEnvironment::Wayland { script_path } => { info!("Starting Wayland session"); - let child = match client - .arg(script_path) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn() - { + let child = match client.arg(script_path).spawn() { Ok(child) => child, Err(err) => { error!("Failed to start Wayland Compositor. Reason '{err}'"); diff --git a/src/post_login/x.rs b/src/post_login/x.rs index 823c3a3..1ccc2b2 100644 --- a/src/post_login/x.rs +++ b/src/post_login/x.rs @@ -7,18 +7,18 @@ use std::env; use std::error::Error; use std::fmt::Display; use std::fs::remove_file; -use std::io::Read; use std::process::{Child, Command, Stdio}; use std::sync::atomic::AtomicBool; use std::{thread, time}; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use log::{error, info}; use crate::auth::AuthUserInfo; use crate::config::Config; use crate::env_container::EnvironmentContainer; +use crate::post_login::output_command_to_log; const XSTART_CHECK_INTERVAL_MILLIS: u64 = 100; @@ -135,11 +135,15 @@ pub fn setup_x( libc::signal(SIGUSR1, SIG_IGN); } - let mut child = Command::new(super::SYSTEM_SHELL) + let child = Command::new(super::SYSTEM_SHELL); + info!( + "Setup XServer to log `stdout` and `stderr` to '{log_path}'", + log_path = config.xserver_log_path + ); + let mut child = output_command_to_log(child, Path::new(&config.xserver_log_path)); + let mut child = child .arg("-c") .arg(format!("/usr/bin/X {display_value} vt{doubledigit_vtnr}")) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) .spawn() .map_err(|err| { error!("Failed to start X server. Reason: {}", err); @@ -171,20 +175,6 @@ pub fn setup_x( if let Some(status) = child.try_wait().unwrap_or(None) { error!("X server died before signaling it was ready to received connections. Status code: {status}."); - if let Some(mut stdout) = child.stdout.take() { - let mut buf = String::new(); - if stdout.read_to_string(&mut buf).is_ok() { - error!("X server STDOUT: '''\n{buf}\n'''"); - } - } - - if let Some(mut stdout) = child.stdout.take() { - let mut buf = String::new(); - if stdout.read_to_string(&mut buf).is_ok() { - error!("X server STDERR: '''\n{buf}\n'''"); - } - } - return Err(XSetupError::XServerPrematureExit); }