Skip to content

Commit

Permalink
Do not trap pipe errors in yes
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
eds-collabora authored and sylvestre committed Jul 1, 2022
1 parent c23936e commit f910c40
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 2 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/uu/yes/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ path = "src/yes.rs"

[dependencies]
clap = { version = "3.1", features = ["wrap_help", "cargo"] }
libc = "0.2.126"
uucore = { version=">=0.0.11", package="uucore", path="../../uucore", features=["pipes"] }

[target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies]
Expand Down
19 changes: 18 additions & 1 deletion src/uu/yes/src/yes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
/* last synced with: yes (GNU coreutils) 8.13 */

use std::borrow::Cow;
use std::io::{self, Write};
use std::io::{self, Result, Write};

#[macro_use]
extern crate clap;
Expand Down Expand Up @@ -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<()> {
let stdout = io::stdout();
let mut stdout = stdout.lock();

enable_pipe_errors()?;

#[cfg(any(target_os = "linux", target_os = "android"))]
{
match splice::splice_data(bytes, &stdout) {
Expand Down
16 changes: 15 additions & 1 deletion tests/by-util/test_yes.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
use std::io::Read;
use std::process::ExitStatus;

#[cfg(unix)]
use std::os::unix::process::ExitStatusExt;

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.
fn run(args: &[&str], expected: &[u8]) {
let mut cmd = new_ucmd!();
Expand All @@ -10,7 +24,7 @@ fn run(args: &[&str], expected: &[u8]) {
let mut buf = vec![0; expected.len()];
stdout.read_exact(&mut buf).unwrap();
drop(stdout);
assert!(child.wait().unwrap().success());
check_termination(&child.wait().unwrap());
assert_eq!(buf.as_slice(), expected);
}

Expand Down

0 comments on commit f910c40

Please sign in to comment.