From 89abeef6da9b25a77288da697cd00e0ed27b6ae7 Mon Sep 17 00:00:00 2001 From: mattsu Date: Mon, 9 Mar 2026 19:28:55 +0900 Subject: [PATCH 1/2] refactor(sigpipe): move startup handling to binary entry points --- src/bin/coreutils.rs | 8 ++++++++ src/uucore/src/lib/lib.rs | 9 +++++++-- src/uucore_procs/src/lib.rs | 17 ----------------- 3 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/bin/coreutils.rs b/src/bin/coreutils.rs index 59634849a6b..66f0bcb73ee 100644 --- a/src/bin/coreutils.rs +++ b/src/bin/coreutils.rs @@ -16,6 +16,9 @@ const VERSION: &str = env!("CARGO_PKG_VERSION"); include!(concat!(env!("OUT_DIR"), "/uutils_map.rs")); +#[cfg(unix)] +uucore::init_startup_state_capture!(); + fn usage(utils: &UtilityMap, name: &str) { println!("{name} {VERSION} (multi-call binary)\n"); println!("Usage: {name} [function [arguments...]]"); @@ -40,6 +43,11 @@ fn usage(utils: &UtilityMap, name: &str) { #[allow(clippy::cognitive_complexity)] fn main() { + #[cfg(unix)] + if !uucore::signals::sigpipe_was_ignored() { + let _ = uucore::signals::enable_pipe_errors(); + } + uucore::panic::mute_sigpipe_panic(); let utils = util_map(); diff --git a/src/uucore/src/lib/lib.rs b/src/uucore/src/lib/lib.rs index 4b2cb9b502b..408fbd32092 100644 --- a/src/uucore/src/lib/lib.rs +++ b/src/uucore/src/lib/lib.rs @@ -186,12 +186,17 @@ pub fn get_canonical_util_name(util_name: &str) -> &str { #[macro_export] macro_rules! bin { ($util:ident) => { + #[cfg(unix)] + uucore::init_startup_state_capture!(); + pub fn main() { use std::io::Write; use uucore::locale; - // Preserve inherited SIGPIPE settings (e.g., from env --default-signal=PIPE) - uucore::panic::preserve_inherited_sigpipe(); + #[cfg(unix)] + if !uucore::signals::sigpipe_was_ignored() { + let _ = uucore::signals::enable_pipe_errors(); + } // suppress extraneous error output for SIGPIPE failures/panics uucore::panic::mute_sigpipe_panic(); diff --git a/src/uucore_procs/src/lib.rs b/src/uucore_procs/src/lib.rs index 391db32907e..793b089b136 100644 --- a/src/uucore_procs/src/lib.rs +++ b/src/uucore_procs/src/lib.rs @@ -18,8 +18,6 @@ use quote::quote; /// A procedural macro to define the main function of a uutils binary. /// /// This macro handles: -/// - SIGPIPE state capture at process startup (before Rust runtime overrides it) -/// - SIGPIPE restoration to default if parent didn't explicitly ignore it /// - Disabling Rust signal handlers for proper core dumps /// - Error handling and exit code management #[proc_macro_attribute] @@ -29,24 +27,9 @@ pub fn main(args: TokenStream, stream: TokenStream) -> TokenStream { let signals = !args.to_string().contains("no_signals"); let new = quote!( - // Initialize SIGPIPE state capture at process startup (Unix only). - // This must be at module level to set up the .init_array static that runs - // before main() to capture whether SIGPIPE was ignored by the parent process. - #[cfg(all(#signals, unix))] - uucore::init_startup_state_capture!(); - pub fn uumain(args: impl uucore::Args) -> i32 { #stream - // Restore SIGPIPE to default if it wasn't explicitly ignored by parent. - // The Rust runtime ignores SIGPIPE, but we need to respect the parent's - // signal disposition for proper pipeline behavior (GNU compatibility). - // needed even for true --version - #[cfg(unix)] - if !uucore::signals::sigpipe_was_ignored() { - let _ = uucore::signals::enable_pipe_errors(); - } - // disable rust signal handlers (otherwise processes don't dump core after e.g. one SIGSEGV) #[cfg(all(#signals, unix))] uucore::disable_rust_signal_handlers().expect("Disabling rust signal handlers failed"); From 36a08c3b05fed67e0f369d87fd7f8e6bf1659b67 Mon Sep 17 00:00:00 2001 From: mattsu Date: Mon, 9 Mar 2026 19:28:57 +0900 Subject: [PATCH 2/2] refactor(sigpipe): remove obsolete env-based restoration --- src/uu/env/src/env.rs | 8 -------- src/uucore/src/lib/mods/panic.rs | 27 --------------------------- 2 files changed, 35 deletions(-) diff --git a/src/uu/env/src/env.rs b/src/uu/env/src/env.rs index 162b0b6d9e2..9de9a6e2bca 100644 --- a/src/uu/env/src/env.rs +++ b/src/uu/env/src/env.rs @@ -1058,14 +1058,6 @@ where signal_fn(sig)?; log.record(sig_value, action_kind, explicit); - // Set environment variable to communicate to Rust child processes - // that SIGPIPE should be default (not ignored) - if matches!(action_kind, SignalActionKind::Default) && sig_value == libc::SIGPIPE as usize { - unsafe { - env::set_var("RUST_SIGPIPE", "default"); - } - } - Ok(()) }) } diff --git a/src/uucore/src/lib/mods/panic.rs b/src/uucore/src/lib/mods/panic.rs index 2a67a10ba8d..8c170b3c8cd 100644 --- a/src/uucore/src/lib/mods/panic.rs +++ b/src/uucore/src/lib/mods/panic.rs @@ -43,30 +43,3 @@ pub fn mute_sigpipe_panic() { } })); } - -/// Preserve inherited SIGPIPE settings from parent process. -/// -/// Rust unconditionally sets SIGPIPE to SIG_IGN on startup. This function -/// checks if the parent process (e.g., `env --default-signal=PIPE`) intended -/// for SIGPIPE to be set to default by checking the RUST_SIGPIPE environment -/// variable. If set to "default", it restores SIGPIPE to SIG_DFL. -#[cfg(unix)] -pub fn preserve_inherited_sigpipe() { - use nix::libc; - - // Check if parent specified that SIGPIPE should be default - if let Ok(val) = std::env::var("RUST_SIGPIPE") { - if val == "default" { - unsafe { - libc::signal(libc::SIGPIPE, libc::SIG_DFL); - // Remove the environment variable so child processes don't inherit it incorrectly - std::env::remove_var("RUST_SIGPIPE"); - } - } - } -} - -#[cfg(not(unix))] -pub fn preserve_inherited_sigpipe() { - // No-op on non-Unix platforms -}