mirror of
https://github.com/uutils/coreutils.git
synced 2025-12-23 08:47:37 +00:00
Merge 02875d0b98 into 87ba3afd19
This commit is contained in:
commit
fce25ec9fa
6 changed files with 73 additions and 5 deletions
|
|
@ -133,6 +133,7 @@ setfattr
|
|||
setlocale
|
||||
shortcode
|
||||
shortcodes
|
||||
sigaction
|
||||
siginfo
|
||||
sigusr
|
||||
strcasecmp
|
||||
|
|
|
|||
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -3782,6 +3782,7 @@ dependencies = [
|
|||
"clap",
|
||||
"codspeed-divan-compat",
|
||||
"fluent",
|
||||
"nix",
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
"tempfile",
|
||||
|
|
|
|||
1
fuzz/Cargo.lock
generated
1
fuzz/Cargo.lock
generated
|
|
@ -1653,6 +1653,7 @@ dependencies = [
|
|||
"bigdecimal",
|
||||
"clap",
|
||||
"fluent",
|
||||
"nix",
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
"thiserror",
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ path = "src/seq.rs"
|
|||
[dependencies]
|
||||
bigdecimal = { workspace = true }
|
||||
clap = { workspace = true }
|
||||
nix = { workspace = true }
|
||||
num-bigint = { workspace = true }
|
||||
num-traits = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
// spell-checker:ignore (ToDO) bigdecimal extendedbigdecimal numberparse hexadecimalfloat biguint
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::io::{BufWriter, Write, stdout};
|
||||
#[cfg(unix)]
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
use clap::{Arg, ArgAction, Command};
|
||||
use num_bigint::BigUint;
|
||||
|
|
@ -209,16 +211,18 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
padding,
|
||||
);
|
||||
|
||||
match result {
|
||||
Ok(()) => Ok(()),
|
||||
Err(err) if err.kind() == std::io::ErrorKind::BrokenPipe => {
|
||||
let sigpipe_ignored = sigpipe_is_ignored();
|
||||
if let Err(err) = result {
|
||||
if err.kind() == std::io::ErrorKind::BrokenPipe {
|
||||
// GNU seq prints the Broken pipe message but still exits with status 0
|
||||
// unless SIGPIPE was explicitly ignored, in which case it should fail.
|
||||
let err = err.map_err_context(|| "write error".into());
|
||||
uucore::show_error!("{err}");
|
||||
Ok(())
|
||||
return if sigpipe_ignored { Err(err) } else { Ok(()) };
|
||||
}
|
||||
Err(err) => Err(err.map_err_context(|| "write error".into())),
|
||||
return Err(err.map_err_context(|| "write error".into()));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn uu_app() -> Command {
|
||||
|
|
@ -332,6 +336,44 @@ fn fast_print_seq(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
static SIGPIPE_WAS_IGNORED: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
#[cfg(unix)]
|
||||
/// # Safety
|
||||
/// This function runs once at process initialization and only observes the
|
||||
/// current `SIGPIPE` handler, so there are no extra safety requirements for callers.
|
||||
unsafe extern "C" fn capture_sigpipe_state() {
|
||||
use nix::libc;
|
||||
use std::{mem::MaybeUninit, ptr};
|
||||
|
||||
let mut current = MaybeUninit::<libc::sigaction>::uninit();
|
||||
if unsafe { libc::sigaction(libc::SIGPIPE, ptr::null(), current.as_mut_ptr()) } == 0 {
|
||||
let ignored = unsafe { current.assume_init() }.sa_sigaction == libc::SIG_IGN;
|
||||
SIGPIPE_WAS_IGNORED.store(ignored, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(unix, not(target_os = "macos")))]
|
||||
#[used]
|
||||
#[unsafe(link_section = ".init_array")]
|
||||
static CAPTURE_SIGPIPE_STATE: unsafe extern "C" fn() = capture_sigpipe_state;
|
||||
|
||||
#[cfg(all(unix, target_os = "macos"))]
|
||||
#[used]
|
||||
#[unsafe(link_section = "__DATA,__mod_init_func")]
|
||||
static CAPTURE_SIGPIPE_STATE_APPLE: unsafe extern "C" fn() = capture_sigpipe_state;
|
||||
|
||||
#[cfg(unix)]
|
||||
fn sigpipe_is_ignored() -> bool {
|
||||
SIGPIPE_WAS_IGNORED.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
const fn sigpipe_is_ignored() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn done_printing<T: Zero + PartialOrd>(next: &T, increment: &T, last: &T) -> bool {
|
||||
if increment >= &T::zero() {
|
||||
next > last
|
||||
|
|
|
|||
|
|
@ -4,6 +4,10 @@
|
|||
// file that was distributed with this source code.
|
||||
// spell-checker:ignore lmnop xlmnop
|
||||
use uutests::new_ucmd;
|
||||
#[cfg(unix)]
|
||||
use uutests::util::TestScenario;
|
||||
#[cfg(unix)]
|
||||
use uutests::util_name;
|
||||
|
||||
#[test]
|
||||
fn test_invalid_arg() {
|
||||
|
|
@ -203,6 +207,24 @@ fn test_width_invalid_float() {
|
|||
.usage_error("invalid floating point argument: '1e2.3'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn test_sigpipe_ignored_reports_write_error() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let seq_bin = scene.bin_path.clone().into_os_string();
|
||||
let script = "trap '' PIPE; { \"$SEQ_BIN\" seq inf 2>err; echo $? >code; } | head -n1";
|
||||
let result = scene.cmd_shell(script).env("SEQ_BIN", &seq_bin).succeeds();
|
||||
|
||||
assert_eq!(result.stdout_str(), "1\n");
|
||||
|
||||
let err_contents = scene.fixtures.read("err");
|
||||
assert!(
|
||||
err_contents.contains("seq: write error: Broken pipe"),
|
||||
"stderr missing write error message: {err_contents:?}"
|
||||
);
|
||||
assert_eq!(scene.fixtures.read("code"), "1\n");
|
||||
}
|
||||
|
||||
// ---- Tests for the big integer based path ----
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue