tail: handle broken pipe gracefully

This commit is contained in:
Tomasz Guz 2025-07-10 14:49:15 +02:00
parent a060344c6b
commit f04ed45a0f
2 changed files with 31 additions and 0 deletions

View file

@ -40,6 +40,15 @@ use uucore::{show, show_error};
#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
// When we receive a SIGPIPE signal, we want to terminate the process so
// that we don't print any error messages to stderr. Rust ignores SIGPIPE
// (see https://github.com/rust-lang/rust/issues/62569), so we restore it's
// default action here.
#[cfg(not(target_os = "windows"))]
unsafe {
libc::signal(libc::SIGPIPE, libc::SIG_DFL);
}
let settings = parse_args(args)?;
settings.check_warnings();
@ -541,7 +550,16 @@ fn unbounded_tail<T: Read>(reader: &mut BufReader<T>, settings: &Settings) -> UR
}
_ => {}
}
#[cfg(not(target_os = "windows"))]
writer.flush()?;
// SIGPIPE is not available on Windows.
#[cfg(target_os = "windows")]
writer.flush().inspect_err(|err| {
if err.kind() == ErrorKind::BrokenPipe {
std::process::exit(13);
}
})?;
Ok(())
}

View file

@ -4897,6 +4897,19 @@ fn test_when_piped_input_then_no_broken_pipe() {
}
}
#[test]
fn test_when_output_closed_then_no_broken_pie() {
let mut cmd = new_ucmd!();
let mut child = cmd
.args(&[FOOBAR_TXT])
.set_stdout(Stdio::piped())
.run_no_wait();
// Dropping the stdout should not lead to an error.
// The "Broken pipe" error should be silently ignored.
child.close_stdout();
child.wait().unwrap().fails_silently();
}
#[test]
fn test_child_when_run_with_stderr_to_stdout() {
let ts = TestScenario::new("tail");