Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/bin/coreutils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>(utils: &UtilityMap<T>, name: &str) {
println!("{name} {VERSION} (multi-call binary)\n");
println!("Usage: {name} [function [arguments...]]");
Expand All @@ -40,6 +43,11 @@ fn usage<T>(utils: &UtilityMap<T>, 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();
Expand Down
8 changes: 0 additions & 8 deletions src/uu/env/src/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(())
})
}
Expand Down
9 changes: 7 additions & 2 deletions src/uucore/src/lib/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
27 changes: 0 additions & 27 deletions src/uucore/src/lib/mods/panic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
17 changes: 0 additions & 17 deletions src/uucore_procs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -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");
Expand Down
Loading