@@ -11,8 +11,6 @@ use std::ffi::OsString;
1111use std:: io:: { self , Write } ;
1212use uucore:: error:: { UResult , USimpleError } ;
1313use uucore:: format_usage;
14- #[ cfg( unix) ]
15- use uucore:: signals:: enable_pipe_errors;
1614use uucore:: translate;
1715
1816// it's possible that using a smaller or larger buffer might provide better performance on some
@@ -29,7 +27,12 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
2927
3028 match exec ( & buffer) {
3129 Ok ( ( ) ) => Ok ( ( ) ) ,
32- Err ( err) if err. kind ( ) == io:: ErrorKind :: BrokenPipe => Ok ( ( ) ) ,
30+ Err ( err) if err. kind ( ) == io:: ErrorKind :: BrokenPipe => {
31+ // When SIGPIPE is trapped (SIG_IGN), write operations return EPIPE.
32+ // GNU coreutils prints an error message in this case.
33+ eprintln ! ( "yes: stdout: Broken pipe" ) ;
34+ Ok ( ( ) )
35+ }
3336 Err ( err) => Err ( USimpleError :: new (
3437 1 ,
3538 translate ! ( "yes-error-standard-output" , "error" => err) ,
@@ -113,8 +116,16 @@ fn prepare_buffer(buf: &mut Vec<u8>) {
113116pub fn exec ( bytes : & [ u8 ] ) -> io:: Result < ( ) > {
114117 let stdout = io:: stdout ( ) ;
115118 let mut stdout = stdout. lock ( ) ;
116- #[ cfg( unix) ]
117- enable_pipe_errors ( ) ?;
119+
120+ // SIGPIPE handling:
121+ // Rust ignores SIGPIPE by default (rust-lang/rust#62569). When write() fails
122+ // because the pipe is closed, it returns EPIPE error instead of being killed by
123+ // the signal. We catch this error in uumain() and print a diagnostic message,
124+ // matching GNU coreutils behavior.
125+ //
126+ // Key point: We do NOT restore SIGPIPE to SIG_DFL. This preserves POSIX signal
127+ // inheritance semantics - if the parent set SIGPIPE to SIG_IGN (e.g., `trap '' PIPE`),
128+ // we respect that setting and rely on EPIPE error handling.
118129
119130 loop {
120131 stdout. write_all ( bytes) ?;
0 commit comments