diff --git a/src/uucore/Cargo.toml b/src/uucore/Cargo.toml index b1867dae76e..367fbfd230e 100644 --- a/src/uucore/Cargo.toml +++ b/src/uucore/Cargo.toml @@ -106,6 +106,7 @@ dns-lookup = { workspace = true, optional = true } rustix = { workspace = true, optional = true } [target.'cfg(unix)'.dependencies] +libc = { workspace = true } # utmpx is unix-only, so its dependencies must not be pulled into other targets # (the uptime feature enables utmpx and now builds on windows too). nix = { workspace = true, optional = true } @@ -151,7 +152,7 @@ utmp-classic = { workspace = true, optional = true } [features] default = ["signals"] # * non-default features -backup-control = [] +backup-control = ["fs"] colors = [] diagnostics = ["dep:ariadne"] checksum = ["base64-simd", "quoting-style", "rustix/fs", "sum"] @@ -184,16 +185,17 @@ i18n-datetime = [ "icu_datetime", "jiff-icu", "jiff", + "libc", ] mode = ["libc", "quoting-style", "rustix/process"] -perms = ["entries", "libc", "safe-traversal", "walkdir"] +perms = ["entries", "fs", "libc", "safe-traversal", "walkdir"] buf-copy = ["pipes"] parser-num = ["extendedbigdecimal", "num-traits"] parser-size = ["parser-num", "procfs"] parser-glob = ["glob"] parser = ["parser-num", "parser-size", "parser-glob"] pipes = ["fs", "rustix/pipe"] -process = ["libc", "nix/user", "rustix/process", "windows-sys"] +process = ["libc", "nix/signal", "nix/user", "rustix/process", "windows-sys"] proc-info = ["tty", "walkdir"] quoting-style = ["i18n-common"] ranges = [] diff --git a/src/uucore/src/lib/features/i18n/datetime.rs b/src/uucore/src/lib/features/i18n/datetime.rs index 144555fccaa..0c08a6e50ad 100644 --- a/src/uucore/src/lib/features/i18n/datetime.rs +++ b/src/uucore/src/lib/features/i18n/datetime.rs @@ -218,7 +218,6 @@ pub fn get_locale_months() -> Option<&'static [Vec; 12]> { ))] fn get_locale_months_inner() -> Option<[Vec; 12]> { use core::ffi::CStr; - use nix::libc; let abmon_items: [libc::nl_item; 12] = [ libc::ABMON_1, diff --git a/src/uucore/src/lib/features/signals.rs b/src/uucore/src/lib/features/signals.rs index 02ed0d0c0db..7be58ad73e0 100644 --- a/src/uucore/src/lib/features/signals.rs +++ b/src/uucore/src/lib/features/signals.rs @@ -12,12 +12,12 @@ #[cfg(unix)] use nix::errno::Errno; -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(unix)] use nix::libc; #[cfg(unix)] use nix::sys::signal::{ SaFlags, SigAction, SigHandler, SigHandler::SigDfl, SigHandler::SigIgn, SigSet, Signal, - Signal::SIGINT, Signal::SIGPIPE, sigaction, signal, + Signal::SIGBUS, Signal::SIGINT, Signal::SIGPIPE, Signal::SIGSEGV, sigaction, signal, }; /// The default signal value. @@ -528,6 +528,41 @@ pub static ALL_SIGNALS: [&str; 32] = [ "URG", "XCPU", "XFSZ", "VTALRM", "PROF", "WINCH", "POLL", "PWR", "SYS", ]; +/// Disables the custom signal handlers installed by Rust for stack-overflow handling. With those custom signal handlers processes ignore the first SIGBUS and SIGSEGV signal they receive. +/// See for details. +#[cfg(unix)] +pub fn disable_rust_signal_handlers() -> Result<(), Errno> { + unsafe { + sigaction( + SIGSEGV, + &SigAction::new(SigDfl, SaFlags::empty(), SigSet::all()), + ) + }?; + unsafe { + sigaction( + SIGBUS, + &SigAction::new(SigDfl, SaFlags::empty(), SigSet::all()), + ) + }?; + Ok(()) +} + +/// 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() { + // Check if parent specified that SIGPIPE should be default + if std::env::var_os("RUST_SIGPIPE").is_some_and(|v| v == "default") { + unsafe { libc::signal(libc::SIGPIPE, libc::SIG_DFL) }; + // Remove the environment variable so child processes don't inherit it incorrectly + unsafe { std::env::remove_var("RUST_SIGPIPE") }; + } +} + /// Returns the signal number for a given signal name or value. pub fn signal_by_name_or_value(signal_name_or_value: &str) -> Option { let signal_name_upcase = signal_name_or_value.to_uppercase(); diff --git a/src/uucore/src/lib/lib.rs b/src/uucore/src/lib/lib.rs index 2eca5a546f6..9a8b3d26f33 100644 --- a/src/uucore/src/lib/lib.rs +++ b/src/uucore/src/lib/lib.rs @@ -181,12 +181,6 @@ pub use crate::features::smack; //## core functions -#[cfg(unix)] -use nix::errno::Errno; -#[cfg(unix)] -use nix::sys::signal::{ - SaFlags, SigAction, SigHandler::SigDfl, SigSet, Signal::SIGBUS, Signal::SIGSEGV, sigaction, -}; use std::borrow::Cow; use std::ffi::{OsStr, OsString}; use std::io::{BufRead, BufReader}; @@ -199,25 +193,6 @@ use std::str; use std::str::Utf8Chunk; use std::sync::{LazyLock, atomic::Ordering}; -/// Disables the custom signal handlers installed by Rust for stack-overflow handling. With those custom signal handlers processes ignore the first SIGBUS and SIGSEGV signal they receive. -/// See for details. -#[cfg(unix)] -pub fn disable_rust_signal_handlers() -> Result<(), Errno> { - unsafe { - sigaction( - SIGSEGV, - &SigAction::new(SigDfl, SaFlags::empty(), SigSet::all()), - ) - }?; - unsafe { - sigaction( - SIGBUS, - &SigAction::new(SigDfl, SaFlags::empty(), SigSet::all()), - ) - }?; - Ok(()) -} - pub fn get_canonical_util_name(util_name: &str) -> &str { // remove the "uu_" prefix let util_name = &util_name[3..]; @@ -238,7 +213,8 @@ macro_rules! bin_inner { use uucore::locale; // Preserve inherited SIGPIPE settings (e.g., from env --default-signal=PIPE) - uucore::panic::preserve_inherited_sigpipe(); + #[cfg(all(unix, not(target_os = "fuchsia")))] + uucore::signals::preserve_inherited_sigpipe(); // suppress extraneous error output for SIGPIPE failures/panics uucore::panic::mute_sigpipe_panic(); diff --git a/src/uucore/src/lib/mods/error.rs b/src/uucore/src/lib/mods/error.rs index 3d3d02f56be..494fd4f64ff 100644 --- a/src/uucore/src/lib/mods/error.rs +++ b/src/uucore/src/lib/mods/error.rs @@ -440,9 +440,7 @@ impl Display for UIoError { // writable file owned by someone else) and "Permission denied" // for EACCES. Prefer the errno when available (#15020). #[cfg(unix)] - PermissionDenied - if self.inner.raw_os_error() == Some(nix::errno::Errno::EPERM as i32) => - { + PermissionDenied if self.inner.raw_os_error() == Some(libc::EPERM as _) => { "Operation not permitted" } PermissionDenied => "Permission denied", @@ -580,7 +578,7 @@ impl From for Box { /// // prints "fix me please!: Permission denied" /// println!("{}", uio_result.unwrap_err()); /// ``` -#[cfg(unix)] +#[cfg(all(feature = "nix", unix))] impl FromIo> for Result { fn map_err_context(self, context: impl FnOnce() -> String) -> UResult { self.map_err(|e| { @@ -592,7 +590,7 @@ impl FromIo> for Result { } } -#[cfg(unix)] +#[cfg(all(feature = "nix", unix))] impl FromIo> for nix::Error { fn map_err_context(self, context: impl FnOnce() -> String) -> UResult { Err(Box::new(UIoError { @@ -602,7 +600,7 @@ impl FromIo> for nix::Error { } } -#[cfg(unix)] +#[cfg(all(feature = "nix", unix))] impl From for UIoError { fn from(f: nix::Error) -> Self { Self { @@ -612,7 +610,7 @@ impl From for UIoError { } } -#[cfg(unix)] +#[cfg(all(feature = "nix", unix))] impl From for Box { fn from(f: nix::Error) -> Self { let u_error: UIoError = f.into(); @@ -901,7 +899,7 @@ mod tests { } #[test] - #[cfg(unix)] + #[cfg(all(feature = "nix", unix))] fn test_nix_error_conversion() { use super::{FromIo, UIoError}; use nix::errno::Errno; diff --git a/src/uucore/src/lib/mods/panic.rs b/src/uucore/src/lib/mods/panic.rs index a0e77b03b4f..0eae6a9d8d2 100644 --- a/src/uucore/src/lib/mods/panic.rs +++ b/src/uucore/src/lib/mods/panic.rs @@ -42,26 +42,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 std::env::var_os("RUST_SIGPIPE").is_some_and(|v| v == "default") { - unsafe { libc::signal(libc::SIGPIPE, libc::SIG_DFL) }; - // Remove the environment variable so child processes don't inherit it incorrectly - unsafe { std::env::remove_var("RUST_SIGPIPE") }; - } -} - -#[cfg(not(unix))] -pub fn preserve_inherited_sigpipe() { - // No-op on non-Unix platforms -} diff --git a/src/uucore_procs/src/lib.rs b/src/uucore_procs/src/lib.rs index e74bbd3c888..eb39ee77ca3 100644 --- a/src/uucore_procs/src/lib.rs +++ b/src/uucore_procs/src/lib.rs @@ -50,7 +50,7 @@ pub fn main(args: TokenStream, stream: TokenStream) -> TokenStream { // 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"); + uucore::signals::disable_rust_signal_handlers().expect("Disabling rust signal handlers failed"); let result = uumain(args); match result { Ok(()) => uucore::error::get_exit_code(),