From 2e49271677ffad7e33fb13821fa0bf12f9f7906e Mon Sep 17 00:00:00 2001 From: Gijs Burghoorn Date: Sun, 25 Jun 2023 21:07:08 +0200 Subject: [PATCH 1/4] Update Dependencies: Ratatui and Crossterm --- Cargo.lock | 199 ++++++++++++++++++--------------------- Cargo.toml | 4 +- src/config.rs | 2 +- src/main.rs | 4 +- src/ui/chunks.rs | 2 +- src/ui/input_field.rs | 15 +-- src/ui/key_menu.rs | 14 +-- src/ui/mod.rs | 4 +- src/ui/status_message.rs | 12 +-- src/ui/switcher.rs | 8 +- 10 files changed, 124 insertions(+), 140 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 39535db..2aa4f82 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -34,12 +34,12 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "crossterm" -version = "0.20.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ebde6a9dd5e331cd6c6f48253254d117642c31653baa475e394657c59c1f7d" +checksum = "a84cda67535339806297f1b331d6dd6320470d2a0fe65381e79ee9e156dd3d13" dependencies = [ "bitflags", - "crossterm_winapi 0.8.0", + "crossterm_winapi", "libc 0.2.139", "mio", "parking_lot", @@ -48,31 +48,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "crossterm" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85525306c4291d1b73ce93c8acf9c339f9b213aef6c1d85c3830cbf1c16325c" -dependencies = [ - "bitflags", - "crossterm_winapi 0.9.0", - "libc 0.2.139", - "mio", - "parking_lot", - "signal-hook", - "signal-hook-mio", - "winapi", -] - -[[package]] -name = "crossterm_winapi" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a6966607622438301997d3dac0d2f6e9a90c68bb6bc1785ea98456ab93c0507" -dependencies = [ - "winapi", -] - [[package]] name = "crossterm_winapi" version = "0.9.0" @@ -109,20 +84,11 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - [[package]] name = "lemurs" version = "0.3.1" dependencies = [ - "crossterm 0.22.1", + "crossterm", "env_logger", "libc 0.2.139", "log", @@ -131,9 +97,9 @@ dependencies = [ "pam", "pgs-files", "rand", + "ratatui", "serde", "toml", - "tui", "unicode-width", "users 0.11.0", ] @@ -180,24 +146,14 @@ dependencies = [ [[package]] name = "mio" -version = "0.7.14" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc 0.2.139", "log", - "miow", - "ntapi", - "winapi", -] - -[[package]] -name = "miow" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" -dependencies = [ - "winapi", + "wasi", + "windows-sys", ] [[package]] @@ -213,21 +169,6 @@ dependencies = [ "memoffset", ] -[[package]] -name = "ntapi" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" -dependencies = [ - "winapi", -] - -[[package]] -name = "numtoa" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" - [[package]] name = "once_cell" version = "1.17.1" @@ -256,27 +197,25 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.11.2" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ - "instant", "lock_api", "parking_lot_core", ] [[package]] name = "parking_lot_core" -version = "0.8.6" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ "cfg-if", - "instant", "libc 0.2.139", "redox_syscall", "smallvec", - "winapi", + "windows-targets", ] [[package]] @@ -343,21 +282,25 @@ dependencies = [ ] [[package]] -name = "redox_syscall" -version = "0.2.16" +name = "ratatui" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +checksum = "ce841e0486e7c2412c3740168ede33adeba8e154a15107b879d8162d77c7174e" dependencies = [ "bitflags", + "cassowary", + "crossterm", + "unicode-segmentation", + "unicode-width", ] [[package]] -name = "redox_termios" -version = "0.1.2" +name = "redox_syscall" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8440d8acb4fd3d277125b4bd01a6f38aee8d814b3b5fc09b3f2b825d37d3fe8f" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "redox_syscall", + "bitflags", ] [[package]] @@ -433,18 +376,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "termion" -version = "1.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "077185e2eac69c3f8379a4298e1e07cd36beb962290d4a51199acf0fdc10607e" -dependencies = [ - "libc 0.2.139", - "numtoa", - "redox_syscall", - "redox_termios", -] - [[package]] name = "toml" version = "0.5.11" @@ -454,20 +385,6 @@ dependencies = [ "serde", ] -[[package]] -name = "tui" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39c8ce4e27049eed97cfa363a5048b09d995e209994634a0efc26a14ab6c0c23" -dependencies = [ - "bitflags", - "cassowary", - "crossterm 0.20.0", - "termion", - "unicode-segmentation", - "unicode-width", -] - [[package]] name = "unicode-ident" version = "1.0.6" @@ -532,3 +449,69 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" diff --git a/Cargo.toml b/Cargo.toml index 8aeb051..f86f2f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,9 +17,9 @@ license = "MIT or APACHE" [dependencies] # UI and TUI interface -tui = { version = "0.16.0", features = [ "crossterm" ] } +ratatui = "0.21.0" +crossterm = "0.26" unicode-width = "0.1" -crossterm = { version = "0.22" } # Interacting with the kernel interfaces rand = "0.8.4" diff --git a/src/config.rs b/src/config.rs index 75dbd7b..d263797 100644 --- a/src/config.rs +++ b/src/config.rs @@ -7,7 +7,7 @@ use crossterm::event::KeyCode; use log::error; use serde::{de::Error, Deserialize}; -use tui::style::{Color, Modifier}; +use ratatui::style::{Color, Modifier}; pub fn get_color(color: &str) -> Color { if let Some(color) = str_to_color(color) { diff --git a/src/main.rs b/src/main.rs index 07f8e01..54c961d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,8 +9,8 @@ use crossterm::{ terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, }; use log::{error, info, warn}; -use tui::backend::CrosstermBackend; -use tui::Terminal; +use ratatui::backend::CrosstermBackend; +use ratatui::Terminal; mod auth; mod chvt; diff --git a/src/ui/chunks.rs b/src/ui/chunks.rs index bff8830..dba8239 100644 --- a/src/ui/chunks.rs +++ b/src/ui/chunks.rs @@ -1,4 +1,4 @@ -use tui::{ +use ratatui::{ backend::Backend, layout::{Constraint, Direction, Layout, Rect}, Frame, diff --git a/src/ui/input_field.rs b/src/ui/input_field.rs index 0c55ccf..c2cace6 100644 --- a/src/ui/input_field.rs +++ b/src/ui/input_field.rs @@ -1,5 +1,5 @@ use crossterm::event::{KeyCode, KeyModifiers}; -use tui::{ +use ratatui::{ layout::Rect, style::Style, terminal::Frame, @@ -290,7 +290,7 @@ impl InputFieldWidget { pub fn render( &mut self, - frame: &mut Frame, + frame: &mut Frame, area: Rect, is_focused: bool, ) { @@ -302,17 +302,18 @@ impl InputFieldWidget { self.width = inner.width; let show_string = self.show_string(); - let widget = Paragraph::new(show_string.as_ref()) - .style(self.get_text_style(is_focused)) - .block(self.get_block(is_focused)); - - frame.render_widget(widget, area); if is_focused { let Rect { x, y, .. } = inner; let cursor_offset = get_byte_offset_of_char_offset(&show_string, self.cursor.into()); frame.set_cursor(x + show_string[..cursor_offset].width() as u16, y); } + + let widget = Paragraph::new(show_string) + .style(self.get_text_style(is_focused)) + .block(self.get_block(is_focused)); + + frame.render_widget(widget, area); } pub(crate) fn key_press( diff --git a/src/ui/key_menu.rs b/src/ui/key_menu.rs index b68559b..650f495 100644 --- a/src/ui/key_menu.rs +++ b/src/ui/key_menu.rs @@ -1,11 +1,11 @@ use std::process::{Command, Output}; use crossterm::event::KeyCode; -use tui::layout::{Alignment, Rect}; -use tui::style::Style; -use tui::text::{Span, Spans, Text}; -use tui::widgets::Paragraph; -use tui::Frame; +use ratatui::layout::{Alignment, Rect}; +use ratatui::style::Style; +use ratatui::text::{Span, Line, Text}; +use ratatui::widgets::Paragraph; +use ratatui::Frame; use crate::config::{ get_color, get_key, get_modifiers, PowerControlConfig, SwitcherConfig, SwitcherVisibility, @@ -54,7 +54,7 @@ impl KeyMenuWidget { style } - pub fn render(&self, frame: &mut Frame, area: Rect) { + pub fn render(&self, frame: &mut Frame, area: Rect) { let mut items = Vec::new(); if self.power_config.allow_shutdown { @@ -93,7 +93,7 @@ impl KeyMenuWidget { } let mut text = Text::raw(""); - text.lines.push(Spans(items)); + text.lines.push(Line::from(items)); let left_widget = Paragraph::new(text); frame.render_widget(left_widget, area); diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 063dd2f..4257bf3 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -17,8 +17,8 @@ use crossterm::execute; use crossterm::terminal::{ disable_raw_mode, enable_raw_mode, Clear, ClearType, EnterAlternateScreen, LeaveAlternateScreen, }; -use tui::backend::CrosstermBackend; -use tui::{backend::Backend, Frame, Terminal}; +use ratatui::backend::CrosstermBackend; +use ratatui::{backend::Backend, Frame, Terminal}; mod chunks; mod input_field; diff --git a/src/ui/status_message.rs b/src/ui/status_message.rs index 53fc2a1..30a94c9 100644 --- a/src/ui/status_message.rs +++ b/src/ui/status_message.rs @@ -1,8 +1,8 @@ -use tui::backend::Backend; -use tui::layout::Rect; -use tui::style::Color; -use tui::widgets::Paragraph; -use tui::Frame; +use ratatui::backend::Backend; +use ratatui::layout::Rect; +use ratatui::style::{Style, Color}; +use ratatui::widgets::Paragraph; +use ratatui::Frame; use crate::auth::AuthenticationError; @@ -86,7 +86,7 @@ impl StatusMessage { pub fn render(status: Option, frame: &mut Frame, area: Rect) { if let Some(status_message) = status { let widget = Paragraph::new(<&'static str>::from(status_message.clone())).style( - tui::style::Style::default().fg(if status_message.is_error() { + Style::default().fg(if status_message.is_error() { Color::Red } else { Color::Yellow diff --git a/src/ui/switcher.rs b/src/ui/switcher.rs index 5bd393e..e4756a9 100644 --- a/src/ui/switcher.rs +++ b/src/ui/switcher.rs @@ -1,10 +1,10 @@ use crossterm::event::KeyCode; use log::warn; -use tui::{ +use ratatui::{ layout::{Alignment, Rect}, style::Style, terminal::Frame, - text::{Span, Spans, Text}, + text::{Span, Line, Text}, widgets::{Block, Paragraph}, }; @@ -281,7 +281,7 @@ impl SwitcherWidget { pub fn render( &self, - frame: &mut Frame, + frame: &mut Frame, area: Rect, is_focused: bool, ) { @@ -378,7 +378,7 @@ impl SwitcherWidget { )); } - let text = Text::from(Spans::from(spans)); + let text = Text::from(Line::from(spans)); let widget = Paragraph::new(text) .block(Block::default()) .alignment(Alignment::Center); From 52e6e2340794e95bf53018c9fe558772f9f217d9 Mon Sep 17 00:00:00 2001 From: Gijs Burghoorn Date: Mon, 26 Jun 2023 18:12:45 +0200 Subject: [PATCH 2/4] Chore: Cargo fmt --- src/ui/key_menu.rs | 2 +- src/ui/status_message.rs | 2 +- src/ui/switcher.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ui/key_menu.rs b/src/ui/key_menu.rs index 650f495..2ce9db6 100644 --- a/src/ui/key_menu.rs +++ b/src/ui/key_menu.rs @@ -3,7 +3,7 @@ use std::process::{Command, Output}; use crossterm::event::KeyCode; use ratatui::layout::{Alignment, Rect}; use ratatui::style::Style; -use ratatui::text::{Span, Line, Text}; +use ratatui::text::{Line, Span, Text}; use ratatui::widgets::Paragraph; use ratatui::Frame; diff --git a/src/ui/status_message.rs b/src/ui/status_message.rs index 30a94c9..141b5aa 100644 --- a/src/ui/status_message.rs +++ b/src/ui/status_message.rs @@ -1,6 +1,6 @@ use ratatui::backend::Backend; use ratatui::layout::Rect; -use ratatui::style::{Style, Color}; +use ratatui::style::{Color, Style}; use ratatui::widgets::Paragraph; use ratatui::Frame; diff --git a/src/ui/switcher.rs b/src/ui/switcher.rs index e4756a9..7eeef4a 100644 --- a/src/ui/switcher.rs +++ b/src/ui/switcher.rs @@ -4,7 +4,7 @@ use ratatui::{ layout::{Alignment, Rect}, style::Style, terminal::Frame, - text::{Span, Line, Text}, + text::{Line, Span, Text}, widgets::{Block, Paragraph}, }; From 7ae1db45c96214f550f6483c94b64a9c7c199cd4 Mon Sep 17 00:00:00 2001 From: Gijs Burghoorn Date: Sun, 25 Jun 2023 20:59:13 +0200 Subject: [PATCH 3/4] Draft: Add log-file size limit --- Cargo.lock | 80 +++++----- Cargo.toml | 2 + src/post_login/mod.rs | 63 +++----- src/post_login/wait_with_log.rs | 275 ++++++++++++++++++++++++++++++++ src/post_login/x.rs | 31 ++-- 5 files changed, 353 insertions(+), 98 deletions(-) create mode 100644 src/post_login/wait_with_log.rs diff --git a/Cargo.lock b/Cargo.lock index 2aa4f82..9017981 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -40,7 +40,7 @@ checksum = "a84cda67535339806297f1b331d6dd6320470d2a0fe65381e79ee9e156dd3d13" dependencies = [ "bitflags", "crossterm_winapi", - "libc 0.2.139", + "libc 0.2.147", "mio", "parking_lot", "signal-hook", @@ -50,9 +50,9 @@ dependencies = [ [[package]] name = "crossterm_winapi" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c" +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" dependencies = [ "winapi", ] @@ -69,12 +69,12 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", - "libc 0.2.139", + "libc 0.2.147", "wasi", ] @@ -90,8 +90,9 @@ version = "0.3.1" dependencies = [ "crossterm", "env_logger", - "libc 0.2.139", + "libc 0.2.147", "log", + "mio", "nix", "once_cell", "pam", @@ -112,15 +113,15 @@ checksum = "e32a70cf75e5846d53a673923498228bbec6a8624708a9ea5645f075d6276122" [[package]] name = "libc" -version = "0.2.139" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" dependencies = [ "autocfg", "scopeguard", @@ -128,12 +129,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" [[package]] name = "memoffset" @@ -150,7 +148,7 @@ version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ - "libc 0.2.139", + "libc 0.2.147", "log", "wasi", "windows-sys", @@ -165,15 +163,15 @@ dependencies = [ "bitflags", "cc", "cfg-if", - "libc 0.2.139", + "libc 0.2.147", "memoffset", ] [[package]] name = "once_cell" -version = "1.17.1" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "pam" @@ -181,7 +179,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa2bdc959c201c047004a1420a92aaa1dd1a6b64d5ef333aa3a4ac764fb93097" dependencies = [ - "libc 0.2.139", + "libc 0.2.147", "pam-sys", "users 0.8.1", ] @@ -192,7 +190,7 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd4858311a097f01a0006ef7d0cd50bca81ec430c949d7bf95cbefd202282434" dependencies = [ - "libc 0.2.139", + "libc 0.2.147", ] [[package]] @@ -212,7 +210,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ "cfg-if", - "libc 0.2.139", + "libc 0.2.147", "redox_syscall", "smallvec", "windows-targets", @@ -235,18 +233,18 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.51" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" +checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.23" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" dependencies = [ "proc-macro2", ] @@ -257,7 +255,7 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ - "libc 0.2.139", + "libc 0.2.147", "rand_chacha", "rand_core", ] @@ -311,18 +309,18 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "serde" -version = "1.0.152" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.152" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" +checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" dependencies = [ "proc-macro2", "quote", @@ -335,7 +333,7 @@ version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9" dependencies = [ - "libc 0.2.139", + "libc 0.2.147", "signal-hook-registry", ] @@ -345,7 +343,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" dependencies = [ - "libc 0.2.139", + "libc 0.2.147", "mio", "signal-hook", ] @@ -356,7 +354,7 @@ version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" dependencies = [ - "libc 0.2.139", + "libc 0.2.147", ] [[package]] @@ -367,9 +365,9 @@ checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "syn" -version = "1.0.109" +version = "2.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +checksum = "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616" dependencies = [ "proc-macro2", "quote", @@ -387,9 +385,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.6" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" [[package]] name = "unicode-segmentation" @@ -409,7 +407,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fed7d0912567d35f88010c23dbaf865e9da8b5227295e8dc0f2fdd109155ab7" dependencies = [ - "libc 0.2.139", + "libc 0.2.147", ] [[package]] @@ -418,7 +416,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24cc0f6d6f267b73e5a2cadf007ba8f9bc39c6a6f9666f8cf25ea809a153b032" dependencies = [ - "libc 0.2.139", + "libc 0.2.147", "log", ] diff --git a/Cargo.toml b/Cargo.toml index f86f2f0..d38cd93 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,8 @@ ratatui = "0.21.0" crossterm = "0.26" unicode-width = "0.1" +mio = { version = "0.8.8", features = [ "os-poll", "os-ext" ] } + # Interacting with the kernel interfaces rand = "0.8.4" nix = "0.23.1" diff --git a/src/post_login/mod.rs b/src/post_login/mod.rs index 2e1d2e2..bb81f27 100644 --- a/src/post_login/mod.rs +++ b/src/post_login/mod.rs @@ -1,8 +1,7 @@ use log::{error, info, warn}; use std::error::Error; use std::fmt::Display; -use std::fs::{self, File}; -use std::os::fd::{FromRawFd, IntoRawFd}; +use std::fs; use std::path::Path; use users::get_user_groups; @@ -17,9 +16,11 @@ use crate::post_login::x::setup_x; use nix::unistd::{Gid, Uid}; +use self::wait_with_log::LemursChild; use self::x::XSetupError; pub(crate) mod env_variables; +mod wait_with_log; mod x; const SYSTEM_SHELL: &str = "/bin/sh"; @@ -75,20 +76,6 @@ impl From for EnvironmentStartError { } } -fn output_command_to_log(mut command: Command, log_path: &Path) -> Command { - if let Ok(file) = File::create(log_path) { - let fd = file.into_raw_fd(); - - command - .stdout(unsafe { Stdio::from_raw_fd(fd) }) - .stderr(unsafe { Stdio::from_raw_fd(fd) }); - } else { - warn!("Failed to create and open file to log into"); - } - - command -} - fn lower_command_permissions_to_user( mut command: Command, user_info: &AuthUserInfo<'_>, @@ -119,15 +106,19 @@ fn lower_command_permissions_to_user( } pub enum SpawnedEnvironment { - X11 { server: Child, client: Child }, - Wayland(Child), + X11 { + server: LemursChild, + client: LemursChild, + }, + Wayland(LemursChild), Tty(Child), } impl SpawnedEnvironment { pub fn pid(&self) -> u32 { match self { - Self::X11 { client, .. } | Self::Wayland(client) | Self::Tty(client) => client.id(), + Self::X11 { client, .. } | Self::Wayland(client) => client.id(), + Self::Tty(client) => client.id(), } } @@ -146,8 +137,8 @@ impl SpawnedEnvironment { } }; - info!("Killing X server"); - match server.kill() { + info!("Telling X server to shut down"); + match server.send_sigterm() { Ok(_) => {} Err(err) => error!("Failed to terminate X11. Reason: {err}"), } @@ -158,7 +149,11 @@ impl SpawnedEnvironment { Err(err) => error!("Failed to wait for X11. Reason: {err}"), } } - Self::Wayland(mut client) | Self::Tty(mut client) => match client.wait() { + Self::Wayland(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}"), + }, + 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}"), }, @@ -181,16 +176,7 @@ impl PostLoginEnvironment { let mut client = lower_command_permissions_to_user(Command::new(SYSTEM_SHELL), user_info); - let mut client = if config.do_log { - info!( - "Setup client to log `stdout` and `stderr` to '{log_path}'", - log_path = config.client_log_path - ); - output_command_to_log(client, Path::new(&config.client_log_path)) - } else { - client.stdout(Stdio::null()).stderr(Stdio::null()); - client - }; + let log_path = config.do_log.then_some(Path::new(&config.client_log_path)); if let Some(shell_login_flag) = shell_login_flag { client.arg(shell_login_flag); @@ -201,13 +187,13 @@ impl PostLoginEnvironment { match self { PostLoginEnvironment::X { xinitrc_path } => { info!("Starting X11 session"); + let server = setup_x(process_env, user_info, config) .map_err(EnvironmentStartError::XSetup)?; - let client = match client - .arg(format!("{} {}", "/etc/lemurs/xsetup.sh", xinitrc_path)) - .spawn() - { + client.arg(format!("{} {}", "/etc/lemurs/xsetup.sh", xinitrc_path)); + + let client = match LemursChild::spawn(client, log_path) { Ok(child) => child, Err(err) => { error!("Failed to start X11 environment. Reason '{}'", err); @@ -219,7 +205,10 @@ impl PostLoginEnvironment { } PostLoginEnvironment::Wayland { script_path } => { info!("Starting Wayland session"); - let child = match client.arg(script_path).spawn() { + + client.arg(script_path); + + let child = match LemursChild::spawn(client, log_path) { Ok(child) => child, Err(err) => { error!("Failed to start Wayland Compositor. Reason '{err}'"); diff --git a/src/post_login/wait_with_log.rs b/src/post_login/wait_with_log.rs new file mode 100644 index 0000000..e8b6fb8 --- /dev/null +++ b/src/post_login/wait_with_log.rs @@ -0,0 +1,275 @@ +//! This module implements a thread that ensures that the log files don't exceed a specific size. + +use std::fs::OpenOptions; +use std::io::{self, BufWriter}; +use std::path::Path; +use std::process::{Child, Command, ExitStatus, Stdio}; +use std::thread::JoinHandle; + +use std::io::Read; + +use log::info; +use mio::unix::pipe::Receiver; +use mio::{Events, Interest, Poll, Token, Waker}; + +/// 64MB +const LOG_WRITER_SIZE_LIMIT: usize = 67_108_864; + +struct LimitSizeWriter { + writer: BufWriter, + current_byte_count: usize, + size_limit: usize, +} + +impl io::Write for LimitSizeWriter { + fn write(&mut self, buf: &[u8]) -> io::Result { + debug_assert!(self.current_byte_count <= self.size_limit); + + if self.current_byte_count >= self.size_limit { + return Ok(buf.len()); + } + + let write_len = usize::min(buf.len(), self.size_limit - self.current_byte_count); + + let written_len = self.writer.write(&buf[..write_len])?; + self.current_byte_count += write_len; + + if written_len != write_len { + return Ok(written_len); + } + + Ok(buf.len()) + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + self.writer.flush() + } +} + +impl LimitSizeWriter { + pub fn new(writer: W, size_limit: usize) -> Self { + Self { + writer: BufWriter::new(writer), + current_byte_count: 0, + size_limit, + } + } +} + +/// This is a wrapper of the rust std `Child` struct. +/// +/// This makes handling spawning, killing and waiting a lot easier to combine with the +/// output log files. +pub enum LemursChild { + NoLog(Child), + Log(LimitedOutputChild), +} + +pub struct LimitedOutputChild { + process: Child, + log_thread: Option<(Waker, JoinHandle>)>, +} + +impl LemursChild { + pub fn spawn(mut command: Command, log_path: Option<&Path>) -> io::Result { + Ok(match log_path { + None => Self::NoLog( + command + .stdin(Stdio::null()) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn()?, + ), + Some(log_path) => Self::Log(LimitedOutputChild::spawn(command, log_path)?), + }) + } + + pub fn wait(&mut self) -> io::Result { + match self { + Self::NoLog(process) => process.wait(), + Self::Log(process) => process.wait(), + } + } + + pub fn try_wait(&mut self) -> io::Result> { + match self { + Self::NoLog(process) => process.try_wait(), + Self::Log(process) => process.try_wait(), + } + } + + pub fn kill(&mut self) -> io::Result<()> { + match self { + Self::NoLog(process) => process.kill(), + Self::Log(process) => process.kill(), + } + } + + pub fn send_sigterm(&self) -> io::Result<()> { + let i = unsafe { libc::kill(self.id() as libc::pid_t, libc::SIGTERM) }; + + Ok(()) + } + + pub fn id(&self) -> u32 { + match self { + Self::NoLog(process) => process.id(), + Self::Log(process) => process.id(), + } + } +} + +impl LimitedOutputChild { + pub fn spawn(mut command: Command, log_path: &Path) -> io::Result { + const STDOUT_PIPE_RECV: Token = Token(0); + const STDERR_PIPE_RECV: Token = Token(1); + const WAKER_TOKEN: Token = Token(2); + + let mut poll = Poll::new()?; + let mut events = Events::with_capacity(128); + + command + .stdin(Stdio::null()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()); + + use io::Write; + + let mut file_options = OpenOptions::new(); + file_options.create(true); + file_options.write(true); + file_options.truncate(true); + + let mut process = command.spawn()?; + + let file = file_options.open(log_path)?; + + let Some(stdout) = process.stdout.take() else { + return Err(io::Error::new(io::ErrorKind::Other, "Failed to grab stdout")); + }; + + let Some(stderr) = process.stderr.take() else { + return Err(io::Error::new(io::ErrorKind::Other, "Failed to grab stderr")); + }; + + let mut stdout_receiver = Receiver::from(stdout); + stdout_receiver.set_nonblocking(true)?; + poll.registry() + .register(&mut stdout_receiver, STDOUT_PIPE_RECV, Interest::READABLE)?; + + let mut stderr_receiver = Receiver::from(stderr); + stderr_receiver.set_nonblocking(true)?; + poll.registry() + .register(&mut stderr_receiver, STDERR_PIPE_RECV, Interest::READABLE)?; + + let waker = Waker::new(poll.registry(), WAKER_TOKEN)?; + + let mut file_handle = LimitSizeWriter::new(file, LOG_WRITER_SIZE_LIMIT); + + let join_handle = std::thread::spawn(move || loop { + poll.poll(&mut events, None)?; + + fn forward_receiver_to_file( + receiver: &mut Receiver, + file_handle: &mut LimitSizeWriter, + is_read_closed: bool, + ) -> io::Result<()> { + let mut buf = [0u8; 2048]; + + loop { + if is_read_closed { + let mut v = Vec::new(); + receiver.read_to_end(&mut v)?; + file_handle.write_all(&v)?; + + break; + } + + match receiver.read(&mut buf) { + Err(err) if err.kind() == std::io::ErrorKind::WouldBlock => { + break; + } + Err(err) => return Err(err), + Ok(n) => { + file_handle.write_all(&buf[..n])?; + } + } + } + + Ok(()) + } + + for event in events.iter() { + match event.token() { + x if x == WAKER_TOKEN => { + return Ok(()); + } + x if x == STDOUT_PIPE_RECV => forward_receiver_to_file( + &mut stdout_receiver, + &mut file_handle, + event.is_read_closed(), + )?, + x if x == STDERR_PIPE_RECV => forward_receiver_to_file( + &mut stderr_receiver, + &mut file_handle, + event.is_read_closed(), + )?, + _ => { + return Err(io::Error::new(io::ErrorKind::Other, "Invalid event")); + } + } + } + }); + + Ok(Self { + process, + log_thread: Some((waker, join_handle)), + }) + } + + fn stop_logging(&mut self) -> io::Result<()> { + if let Some((waker, join_handle)) = self.log_thread.take() { + waker.wake()?; + + info!("Joining with logging thread."); + + join_handle + .join() + .expect("Failed to join with log thread")?; + } + + Ok(()) + } + + pub fn wait(&mut self) -> io::Result { + let exit_status = self.process.wait()?; + + self.stop_logging()?; + + Ok(exit_status) + } + + pub fn try_wait(&mut self) -> io::Result> { + let exit_status = match self.process.try_wait()? { + None => return Ok(None), + Some(exit_status) => exit_status, + }; + + self.stop_logging()?; + + Ok(Some(exit_status)) + } + + pub fn kill(&mut self) -> io::Result<()> { + self.process.kill()?; + + self.stop_logging()?; + + Ok(()) + } + + pub fn id(&self) -> u32 { + self.process.id() + } +} diff --git a/src/post_login/x.rs b/src/post_login/x.rs index 7ab1ba7..4b74e20 100644 --- a/src/post_login/x.rs +++ b/src/post_login/x.rs @@ -7,7 +7,7 @@ use std::env; use std::error::Error; use std::fmt::Display; use std::fs::remove_file; -use std::process::{Child, Command, Stdio}; +use std::process::{Command, Stdio}; use std::sync::atomic::AtomicBool; use std::{thread, time}; @@ -18,7 +18,7 @@ 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; +use crate::post_login::wait_with_log::LemursChild; const XSTART_CHECK_INTERVAL_MILLIS: u64 = 100; @@ -74,7 +74,7 @@ pub fn setup_x( process_env: &mut EnvironmentContainer, user_info: &AuthUserInfo, config: &Config, -) -> Result { +) -> Result { use std::os::unix::process::CommandExt; info!("Start setup of X server"); @@ -137,25 +137,16 @@ pub fn setup_x( let mut child = Command::new(super::SYSTEM_SHELL); - let mut child = if config.do_log { - info!( - "Setup XServer to log `stdout` and `stderr` to '{log_path}'", - log_path = config.xserver_log_path - ); - output_command_to_log(child, Path::new(&config.xserver_log_path)) - } else { - child.stdout(Stdio::null()).stderr(Stdio::null()); - child - }; + let log_path = config.do_log.then_some(Path::new(&config.xserver_log_path)); - let mut child = child + child .arg("-c") - .arg(format!("/usr/bin/X {display_value} vt{doubledigit_vtnr}")) - .spawn() - .map_err(|err| { - error!("Failed to start X server. Reason: {}", err); - XSetupError::XServerStart - })?; + .arg(format!("/usr/bin/X {display_value} vt{doubledigit_vtnr}")); + + let mut child = LemursChild::spawn(child, log_path).map_err(|err| { + error!("Failed to start X server. Reason: {}", err); + XSetupError::XServerStart + })?; // See note above unsafe { From bb54e11c4a2f7f09891ea2460754b46819f7dd22 Mon Sep 17 00:00:00 2001 From: Gijs Burghoorn Date: Mon, 26 Jun 2023 18:20:30 +0200 Subject: [PATCH 4/4] Chore: Cargo clippy --- src/post_login/wait_with_log.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/post_login/wait_with_log.rs b/src/post_login/wait_with_log.rs index e8b6fb8..024377b 100644 --- a/src/post_login/wait_with_log.rs +++ b/src/post_login/wait_with_log.rs @@ -107,7 +107,7 @@ impl LemursChild { } pub fn send_sigterm(&self) -> io::Result<()> { - let i = unsafe { libc::kill(self.id() as libc::pid_t, libc::SIGTERM) }; + unsafe { libc::kill(self.id() as libc::pid_t, libc::SIGTERM) }; Ok(()) }