feat: detect stale file handles if not notified

This commit is contained in:
Jeremy Wall 2024-06-07 10:15:19 -04:00
parent 0b0fe7df8e
commit 20adbc02fb
2 changed files with 18 additions and 5 deletions

View File

@ -9,5 +9,5 @@ description = "A small log redirection utility"
[dependencies] [dependencies]
anyhow = "1.0.86" anyhow = "1.0.86"
clap = { version = "4.5.4", features = ["derive"] } clap = { version = "4.5.4", features = ["derive"] }
nix = { version = "0.29.0", features = ["signal", "process"] } nix = { version = "0.29.0", features = ["signal", "process", "fs"] }
tokio = { version = "1.38.0", features = ["process", "signal", "rt", "rt-multi-thread", "macros", "io-util", "fs"] } tokio = { version = "1.38.0", features = ["process", "signal", "rt", "rt-multi-thread", "macros", "io-util", "fs"] }

View File

@ -1,4 +1,5 @@
use std::convert::From; use std::convert::From;
use std::os::fd::AsRawFd;
use std::path::PathBuf; use std::path::PathBuf;
use std::process::{ExitCode, ExitStatus, Stdio}; use std::process::{ExitCode, ExitStatus, Stdio};
@ -66,6 +67,12 @@ async fn cleanup(
)); ));
} }
fn check_for_stale_handle(f: &File) -> anyhow::Result<bool> {
let fd = f.as_raw_fd();
let stats = nix::sys::stat::fstat(fd)?;
return Ok(stats.st_nlink > 0);
}
#[tokio::main] #[tokio::main]
async fn main() -> anyhow::Result<ExitCode> { async fn main() -> anyhow::Result<ExitCode> {
let args = Args::parse(); let args = Args::parse();
@ -121,9 +128,12 @@ async fn main() -> anyhow::Result<ExitCode> {
out_result = stdout_reader.read(&mut stdout_buffer) => { out_result = stdout_reader.read(&mut stdout_buffer) => {
match out_result { match out_result {
Ok(n) => { Ok(n) => {
// TODO(zaphar): It is possible we should try to reopen the file if this if !check_for_stale_handle(&stdout_writer)? {
// write fails in some cases. stdout_writer.flush().await?;
stdout_writer = File::options().append(true).create(true).open(stdout_path).await?;
}
if let Err(_) = stdout_writer.write(&stdout_buffer[0..n]).await { if let Err(_) = stdout_writer.write(&stdout_buffer[0..n]).await {
stdout_writer.flush().await?;
stdout_writer = File::options().append(true).create(true).open(stdout_path).await?; stdout_writer = File::options().append(true).create(true).open(stdout_path).await?;
} }
}, },
@ -139,9 +149,12 @@ async fn main() -> anyhow::Result<ExitCode> {
err_result = stderr_reader.read(&mut stderr_buffer) => { err_result = stderr_reader.read(&mut stderr_buffer) => {
match err_result { match err_result {
Ok(n) => { Ok(n) => {
// TODO(zaphar): It is possible we should try to reopen the file if this if !check_for_stale_handle(&stderr_writer)? {
// write fails in some cases. stderr_writer.flush().await?;
stderr_writer = File::options().append(true).create(true).open(stderr_path).await?;
}
if let Err(_) = stderr_writer.write(&stderr_buffer[0..n]).await { if let Err(_) = stderr_writer.write(&stderr_buffer[0..n]).await {
stderr_writer.flush().await?;
stderr_writer = File::options().append(true).create(true).open(stderr_path).await?; stderr_writer = File::options().append(true).create(true).open(stderr_path).await?;
} }
}, },