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: 5 additions & 3 deletions src/uucore/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down Expand Up @@ -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"]
Expand Down Expand Up @@ -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 = []
Expand Down
1 change: 0 additions & 1 deletion src/uucore/src/lib/features/i18n/datetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@
/// pick any calendar at runtime, so it links the data of all of them, which
/// every utility then pays for in relocations at startup.
macro_rules! new_formatter {
($fset:expr, $calendar:expr) => {

Check warning on line 75 in src/uucore/src/lib/features/i18n/datetime.rs

View workflow job for this annotation

GitHub Actions / Style/spelling (ubuntu-latest, feat_os_unix)

WARNING: `cspell`: Unknown word 'fset' (file:'src/uucore/src/lib/features/i18n/datetime.rs', line:75)
FixedCalendarDateTimeFormatter::try_new((&get_time_locale().0).into(), $fset)

Check warning on line 76 in src/uucore/src/lib/features/i18n/datetime.rs

View workflow job for this annotation

GitHub Actions / Style/spelling (ubuntu-latest, feat_os_unix)

WARNING: `cspell`: Unknown word 'fset' (file:'src/uucore/src/lib/features/i18n/datetime.rs', line:76)
.ok()
.map(|f| f.into_formatter($calendar))
};
Expand All @@ -83,10 +83,10 @@
/// to, so that %B agrees with %m. Thai month names are the same in the Buddhist
/// and Gregorian calendars.
macro_rules! new_month_formatter {
($fset:expr) => {

Check warning on line 86 in src/uucore/src/lib/features/i18n/datetime.rs

View workflow job for this annotation

GitHub Actions / Style/spelling (ubuntu-latest, feat_os_unix)

WARNING: `cspell`: Unknown word 'fset' (file:'src/uucore/src/lib/features/i18n/datetime.rs', line:86)
match get_locale_calendar_type(&get_time_locale().0) {
CalendarType::Persian => new_formatter!($fset, Persian),

Check warning on line 88 in src/uucore/src/lib/features/i18n/datetime.rs

View workflow job for this annotation

GitHub Actions / Style/spelling (ubuntu-latest, feat_os_unix)

WARNING: `cspell`: Unknown word 'fset' (file:'src/uucore/src/lib/features/i18n/datetime.rs', line:88)
CalendarType::Ethiopian => new_formatter!($fset, Ethiopian::new()),

Check warning on line 89 in src/uucore/src/lib/features/i18n/datetime.rs

View workflow job for this annotation

GitHub Actions / Style/spelling (ubuntu-latest, feat_os_unix)

WARNING: `cspell`: Unknown word 'fset' (file:'src/uucore/src/lib/features/i18n/datetime.rs', line:89)
CalendarType::Buddhist | CalendarType::Gregorian => new_formatter!($fset, Gregorian),
}
};
Expand Down Expand Up @@ -218,7 +218,6 @@
))]
fn get_locale_months_inner() -> Option<[Vec<u8>; 12]> {
use core::ffi::CStr;
use nix::libc;

let abmon_items: [libc::nl_item; 12] = [
libc::ABMON_1,
Expand Down
39 changes: 37 additions & 2 deletions src/uucore/src/lib/features/signals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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 <https://github.com/rust-lang/rust/blob/8ac1525e091d3db28e67adcbbd6db1e1deaa37fb/src/libstd/sys/unix/stack_overflow.rs#L71-L92> 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<usize> {
let signal_name_upcase = signal_name_or_value.to_uppercase();
Expand Down
28 changes: 2 additions & 26 deletions src/uucore/src/lib/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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 <https://github.com/rust-lang/rust/blob/8ac1525e091d3db28e67adcbbd6db1e1deaa37fb/src/libstd/sys/unix/stack_overflow.rs#L71-L92> 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..];
Expand All @@ -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();
Expand Down
14 changes: 6 additions & 8 deletions src/uucore/src/lib/mods/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -580,7 +578,7 @@ impl From<std::io::Error> for Box<dyn UError> {
/// // prints "fix me please!: Permission denied"
/// println!("{}", uio_result.unwrap_err());
/// ```
#[cfg(unix)]
#[cfg(all(feature = "nix", unix))]
impl<T> FromIo<UResult<T>> for Result<T, nix::Error> {
fn map_err_context(self, context: impl FnOnce() -> String) -> UResult<T> {
self.map_err(|e| {
Expand All @@ -592,7 +590,7 @@ impl<T> FromIo<UResult<T>> for Result<T, nix::Error> {
}
}

#[cfg(unix)]
#[cfg(all(feature = "nix", unix))]
impl<T> FromIo<UResult<T>> for nix::Error {
fn map_err_context(self, context: impl FnOnce() -> String) -> UResult<T> {
Err(Box::new(UIoError {
Expand All @@ -602,7 +600,7 @@ impl<T> FromIo<UResult<T>> for nix::Error {
}
}

#[cfg(unix)]
#[cfg(all(feature = "nix", unix))]
impl From<nix::Error> for UIoError {
fn from(f: nix::Error) -> Self {
Self {
Expand All @@ -612,7 +610,7 @@ impl From<nix::Error> for UIoError {
}
}

#[cfg(unix)]
#[cfg(all(feature = "nix", unix))]
impl From<nix::Error> for Box<dyn UError> {
fn from(f: nix::Error) -> Self {
let u_error: UIoError = f.into();
Expand Down Expand Up @@ -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;
Expand Down
23 changes: 0 additions & 23 deletions src/uucore/src/lib/mods/panic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
2 changes: 1 addition & 1 deletion src/uucore_procs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
Loading