From 20adbc02fb9e194e6f1afad45fea57fbfeb0723d Mon Sep 17 00:00:00 2001 From: Jeremy Wall Date: Fri, 7 Jun 2024 10:15:19 -0400 Subject: [PATCH] feat: detect stale file handles if not notified --- Cargo.toml | 2 +- src/main.rs | 21 +++++++++++++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 04416aa..1381b46 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,5 +9,5 @@ description = "A small log redirection utility" [dependencies] anyhow = "1.0.86" 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"] } diff --git a/src/main.rs b/src/main.rs index 7cc3c62..26d8a2c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ use std::convert::From; +use std::os::fd::AsRawFd; use std::path::PathBuf; use std::process::{ExitCode, ExitStatus, Stdio}; @@ -66,6 +67,12 @@ async fn cleanup( )); } +fn check_for_stale_handle(f: &File) -> anyhow::Result { + let fd = f.as_raw_fd(); + let stats = nix::sys::stat::fstat(fd)?; + return Ok(stats.st_nlink > 0); +} + #[tokio::main] async fn main() -> anyhow::Result { let args = Args::parse(); @@ -121,9 +128,12 @@ async fn main() -> anyhow::Result { out_result = stdout_reader.read(&mut stdout_buffer) => { match out_result { Ok(n) => { - // TODO(zaphar): It is possible we should try to reopen the file if this - // write fails in some cases. + if !check_for_stale_handle(&stdout_writer)? { + 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 { + stdout_writer.flush().await?; stdout_writer = File::options().append(true).create(true).open(stdout_path).await?; } }, @@ -139,9 +149,12 @@ async fn main() -> anyhow::Result { err_result = stderr_reader.read(&mut stderr_buffer) => { match err_result { Ok(n) => { - // TODO(zaphar): It is possible we should try to reopen the file if this - // write fails in some cases. + if !check_for_stale_handle(&stderr_writer)? { + 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 { + stderr_writer.flush().await?; stderr_writer = File::options().append(true).create(true).open(stderr_path).await?; } },