1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 03:27:44 +00:00

Do not trap pipe errors in yes

This is part of fixing the tee tests. 'yes' is used by the GNU test
suite to identify what the SIGPIPE exit code is on the target
platform. By trapping SIGPIPE, it creates a requirement that other
utilities also trap SIGPIPE (and exit 0 after SIGPIPE). This is
sometimes at odds with their desired behaviour.
This commit is contained in:
Ed Smith 2022-06-25 23:16:49 +01:00 committed by Sylvestre Ledru
parent 7a961a94a5
commit 5c13e88f8b
4 changed files with 35 additions and 2 deletions

1
Cargo.lock generated
View file

@ -3096,6 +3096,7 @@ name = "uu_yes"
version = "0.0.14" version = "0.0.14"
dependencies = [ dependencies = [
"clap 3.1.18", "clap 3.1.18",
"libc",
"nix", "nix",
"uucore", "uucore",
] ]

View file

@ -16,6 +16,7 @@ path = "src/yes.rs"
[dependencies] [dependencies]
clap = { version = "3.1", features = ["wrap_help", "cargo"] } clap = { version = "3.1", features = ["wrap_help", "cargo"] }
libc = "0.2.126"
uucore = { version=">=0.0.11", package="uucore", path="../../uucore", features=["pipes"] } uucore = { version=">=0.0.11", package="uucore", path="../../uucore", features=["pipes"] }
[target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies] [target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies]

View file

@ -8,7 +8,7 @@
/* last synced with: yes (GNU coreutils) 8.13 */ /* last synced with: yes (GNU coreutils) 8.13 */
use std::borrow::Cow; use std::borrow::Cow;
use std::io::{self, Write}; use std::io::{self, Result, Write};
#[macro_use] #[macro_use]
extern crate clap; extern crate clap;
@ -70,10 +70,27 @@ fn prepare_buffer<'a>(input: &'a str, buffer: &'a mut [u8; BUF_SIZE]) -> &'a [u8
} }
} }
#[cfg(unix)]
fn enable_pipe_errors() -> Result<()> {
let ret = unsafe { libc::signal(libc::SIGPIPE, libc::SIG_DFL) };
if ret == libc::SIG_ERR {
return Err(io::Error::new(io::ErrorKind::Other, ""));
}
Ok(())
}
#[cfg(not(unix))]
fn enable_pipe_errors() -> Result<()> {
// Do nothing.
Ok(())
}
pub fn exec(bytes: &[u8]) -> io::Result<()> { pub fn exec(bytes: &[u8]) -> io::Result<()> {
let stdout = io::stdout(); let stdout = io::stdout();
let mut stdout = stdout.lock(); let mut stdout = stdout.lock();
enable_pipe_errors()?;
#[cfg(any(target_os = "linux", target_os = "android"))] #[cfg(any(target_os = "linux", target_os = "android"))]
{ {
match splice::splice_data(bytes, &stdout) { match splice::splice_data(bytes, &stdout) {

View file

@ -1,7 +1,21 @@
use std::io::Read; use std::io::Read;
use std::process::ExitStatus;
#[cfg(unix)]
use std::os::unix::process::ExitStatusExt;
use crate::common::util::*; use crate::common::util::*;
#[cfg(unix)]
fn check_termination(result: &ExitStatus) {
assert_eq!(result.signal(), Some(libc::SIGPIPE as i32));
}
#[cfg(not(unix))]
fn check_termination(result: &ExitStatus) {
assert!(result.success(), "yes did not exit successfully");
}
/// Run `yes`, capture some of the output, close the pipe, and verify it. /// Run `yes`, capture some of the output, close the pipe, and verify it.
fn run(args: &[&str], expected: &[u8]) { fn run(args: &[&str], expected: &[u8]) {
let mut cmd = new_ucmd!(); let mut cmd = new_ucmd!();
@ -10,7 +24,7 @@ fn run(args: &[&str], expected: &[u8]) {
let mut buf = vec![0; expected.len()]; let mut buf = vec![0; expected.len()];
stdout.read_exact(&mut buf).unwrap(); stdout.read_exact(&mut buf).unwrap();
drop(stdout); drop(stdout);
assert!(child.wait().unwrap().success()); check_termination(&child.wait().unwrap());
assert_eq!(buf.as_slice(), expected); assert_eq!(buf.as_slice(), expected);
} }