mirror of
https://github.com/coastalwhite/lemurs
synced 2024-11-10 05:14:11 +00:00
Draft: Add log-file size limit
This commit is contained in:
parent
52e6e23407
commit
7ae1db45c9
5 changed files with 353 additions and 98 deletions
80
Cargo.lock
generated
80
Cargo.lock
generated
|
@ -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",
|
||||
]
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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<XSetupError> 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}'");
|
||||
|
|
275
src/post_login/wait_with_log.rs
Normal file
275
src/post_login/wait_with_log.rs
Normal file
|
@ -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<W: io::Write> {
|
||||
writer: BufWriter<W>,
|
||||
current_byte_count: usize,
|
||||
size_limit: usize,
|
||||
}
|
||||
|
||||
impl<W: io::Write> io::Write for LimitSizeWriter<W> {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
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<W: io::Write> LimitSizeWriter<W> {
|
||||
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<io::Result<()>>)>,
|
||||
}
|
||||
|
||||
impl LemursChild {
|
||||
pub fn spawn(mut command: Command, log_path: Option<&Path>) -> io::Result<Self> {
|
||||
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<ExitStatus> {
|
||||
match self {
|
||||
Self::NoLog(process) => process.wait(),
|
||||
Self::Log(process) => process.wait(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
|
||||
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<Self> {
|
||||
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<impl io::Write>,
|
||||
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<ExitStatus> {
|
||||
let exit_status = self.process.wait()?;
|
||||
|
||||
self.stop_logging()?;
|
||||
|
||||
Ok(exit_status)
|
||||
}
|
||||
|
||||
pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
|
||||
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()
|
||||
}
|
||||
}
|
|
@ -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<Child, XSetupError> {
|
||||
) -> Result<LemursChild, XSetupError> {
|
||||
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 {
|
||||
|
|
Loading…
Reference in a new issue