diff --git a/Cargo.lock b/Cargo.lock index 367360ea6..97f5c7eff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3096,6 +3096,7 @@ name = "uu_yes" version = "0.0.14" dependencies = [ "clap 3.1.18", + "libc", "nix", "uucore", ] diff --git a/src/uu/yes/Cargo.toml b/src/uu/yes/Cargo.toml index e2c6d8450..6aaa83371 100644 --- a/src/uu/yes/Cargo.toml +++ b/src/uu/yes/Cargo.toml @@ -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] diff --git a/src/uu/yes/src/yes.rs b/src/uu/yes/src/yes.rs index 879f60579..f78ddbfb6 100644 --- a/src/uu/yes/src/yes.rs +++ b/src/uu/yes/src/yes.rs @@ -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; @@ -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) { diff --git a/tests/by-util/test_yes.rs b/tests/by-util/test_yes.rs index 7325cb4bc..20561ced6 100644 --- a/tests/by-util/test_yes.rs +++ b/tests/by-util/test_yes.rs @@ -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!(); @@ -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); }