From 44640c96317891a067832185ded36874694fb299 Mon Sep 17 00:00:00 2001 From: Christopher Dryden Date: Thu, 12 Feb 2026 11:57:09 +0000 Subject: [PATCH 1/3] date,comm,tty: fix write error detection for io-errors GNU test --- src/uu/comm/src/comm.rs | 4 +++- src/uu/date/src/date.rs | 3 +++ src/uu/tty/src/tty.rs | 4 ++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/uu/comm/src/comm.rs b/src/uu/comm/src/comm.rs index 42ec1c0ec12..9257c1b7d1a 100644 --- a/src/uu/comm/src/comm.rs +++ b/src/uu/comm/src/comm.rs @@ -310,7 +310,9 @@ fn comm( .map_err_context(|| translate!("comm-error-write"))?; } - writer.flush().ok(); + writer + .flush() + .map_err_context(|| translate!("comm-error-write"))?; if should_check_order && (checker1.has_error || checker2.has_error) { // Print the input error message once at the end diff --git a/src/uu/date/src/date.rs b/src/uu/date/src/date.rs index 62d22b0c20c..5eab073fd52 100644 --- a/src/uu/date/src/date.rs +++ b/src/uu/date/src/date.rs @@ -510,6 +510,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { } } + stdout.flush().map_err(|e| { + USimpleError::new(1, translate!("date-error-write", "error" => e)) + })?; Ok(()) } diff --git a/src/uu/tty/src/tty.rs b/src/uu/tty/src/tty.rs index e2c541cff26..0e9aa77b2d4 100644 --- a/src/uu/tty/src/tty.rs +++ b/src/uu/tty/src/tty.rs @@ -19,13 +19,13 @@ mod options { #[uucore::main] pub fn uumain(args: impl uucore::Args) -> UResult<()> { + let matches = uucore::clap_localization::handle_clap_result_with_exit_code(uu_app(), args, 2)?; + // Disable SIGPIPE so we can handle broken pipe errors gracefully // and exit with code 3 instead of being killed by the signal. #[cfg(unix)] let _ = uucore::signals::disable_pipe_errors(); - let matches = uucore::clap_localization::handle_clap_result_with_exit_code(uu_app(), args, 2)?; - let silent = matches.get_flag(options::SILENT); // If silent, we don't need the name, only whether or not stdin is a tty. From bea2aa2b609d2cd23f0a90cb037bc1082bb97aec Mon Sep 17 00:00:00 2001 From: Christopher Dryden Date: Thu, 12 Feb 2026 12:01:05 +0000 Subject: [PATCH 2/3] date,comm,tty: add integration tests for write error handling --- tests/by-util/test_comm.rs | 15 +++++++++++++++ tests/by-util/test_date.rs | 12 ++++++++++++ tests/by-util/test_tty.rs | 8 ++++++++ 3 files changed, 35 insertions(+) diff --git a/tests/by-util/test_comm.rs b/tests/by-util/test_comm.rs index e314cfaf1f4..500899a2043 100644 --- a/tests/by-util/test_comm.rs +++ b/tests/by-util/test_comm.rs @@ -727,3 +727,18 @@ fn test_read_error() { .fails() .stderr_contains("comm: /proc/self/mem: Input/output error"); } + +#[test] +#[cfg(unix)] +fn test_comm_write_error_dev_full() { + use std::fs::OpenOptions; + let scene = TestScenario::new(util_name!()); + scene.fixtures.write("a", "a\n"); + let dev_full = OpenOptions::new().write(true).open("/dev/full").unwrap(); + scene + .ucmd() + .args(&["a", "a"]) + .set_stdout(dev_full) + .fails() + .stderr_contains("No space left on device"); +} diff --git a/tests/by-util/test_date.rs b/tests/by-util/test_date.rs index 7a5625a0189..11d42b9c5e2 100644 --- a/tests/by-util/test_date.rs +++ b/tests/by-util/test_date.rs @@ -2066,3 +2066,15 @@ fn test_percent_percent_not_replaced() { .stdout_is(expected); } } + +#[test] +#[cfg(unix)] +fn test_date_write_error_dev_full() { + use std::fs::OpenOptions; + let dev_full = OpenOptions::new().write(true).open("/dev/full").unwrap(); + new_ucmd!() + .arg("+%s") + .set_stdout(dev_full) + .fails() + .stderr_contains("write error"); +} diff --git a/tests/by-util/test_tty.rs b/tests/by-util/test_tty.rs index 9e1db7a21c2..b5aa23aa78e 100644 --- a/tests/by-util/test_tty.rs +++ b/tests/by-util/test_tty.rs @@ -87,3 +87,11 @@ fn test_stdout_fail() { let status = proc.wait().unwrap(); assert_eq!(status.code(), Some(3)); } + +#[test] +#[cfg(unix)] +fn test_version_pipe_no_stderr() { + let mut child = new_ucmd!().arg("--version").run_no_wait(); + child.close_stdout(); + child.wait().unwrap().no_stderr(); +} From 2c35d155b68de702e3cb4cac8a460f0f1ce5147d Mon Sep 17 00:00:00 2001 From: Christopher Dryden Date: Thu, 12 Feb 2026 12:21:23 +0000 Subject: [PATCH 3/3] fix: cargo fmt and restrict /dev/full tests to Linux --- src/uu/date/src/date.rs | 6 +++--- tests/by-util/test_comm.rs | 2 +- tests/by-util/test_date.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/uu/date/src/date.rs b/src/uu/date/src/date.rs index 5eab073fd52..13c42ec74cc 100644 --- a/src/uu/date/src/date.rs +++ b/src/uu/date/src/date.rs @@ -510,9 +510,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { } } - stdout.flush().map_err(|e| { - USimpleError::new(1, translate!("date-error-write", "error" => e)) - })?; + stdout + .flush() + .map_err(|e| USimpleError::new(1, translate!("date-error-write", "error" => e)))?; Ok(()) } diff --git a/tests/by-util/test_comm.rs b/tests/by-util/test_comm.rs index 500899a2043..6c6b88246f2 100644 --- a/tests/by-util/test_comm.rs +++ b/tests/by-util/test_comm.rs @@ -729,7 +729,7 @@ fn test_read_error() { } #[test] -#[cfg(unix)] +#[cfg(target_os = "linux")] fn test_comm_write_error_dev_full() { use std::fs::OpenOptions; let scene = TestScenario::new(util_name!()); diff --git a/tests/by-util/test_date.rs b/tests/by-util/test_date.rs index 11d42b9c5e2..134a63843cd 100644 --- a/tests/by-util/test_date.rs +++ b/tests/by-util/test_date.rs @@ -2068,7 +2068,7 @@ fn test_percent_percent_not_replaced() { } #[test] -#[cfg(unix)] +#[cfg(target_os = "linux")] fn test_date_write_error_dev_full() { use std::fs::OpenOptions; let dev_full = OpenOptions::new().write(true).open("/dev/full").unwrap();