88mod platform;
99
1010use crate :: platform:: is_unsafe_overwrite;
11+ use clap:: { Arg , ArgAction , Command } ;
12+ use memchr:: memchr2;
1113use std:: fs:: { File , metadata} ;
12- use std:: io:: { self , BufWriter , IsTerminal , Read , Write } ;
14+ use std:: io:: { self , BufWriter , ErrorKind , IsTerminal , Read , Write } ;
1315/// Unix domain socket support
1416#[ cfg( unix) ]
1517use std:: net:: Shutdown ;
@@ -19,12 +21,11 @@ use std::os::fd::AsFd;
1921use std:: os:: unix:: fs:: FileTypeExt ;
2022#[ cfg( unix) ]
2123use std:: os:: unix:: net:: UnixStream ;
22-
23- use clap:: { Arg , ArgAction , Command } ;
24- use memchr:: memchr2;
2524use thiserror:: Error ;
2625use uucore:: display:: Quotable ;
2726use uucore:: error:: UResult ;
27+ #[ cfg( not( target_os = "windows" ) ) ]
28+ use uucore:: libc;
2829use uucore:: locale:: get_message;
2930use uucore:: { fast_inc:: fast_inc_one, format_usage} ;
3031
@@ -220,6 +221,15 @@ mod options {
220221
221222#[ uucore:: main]
222223pub fn uumain ( args : impl uucore:: Args ) -> UResult < ( ) > {
224+ // When we receive a SIGPIPE signal, we want to terminate the process so
225+ // that we don't print any error messages to stderr. Rust ignores SIGPIPE
226+ // (see https://github.com/rust-lang/rust/issues/62569), so we restore it's
227+ // default action here.
228+ #[ cfg( not( target_os = "windows" ) ) ]
229+ unsafe {
230+ libc:: signal ( libc:: SIGPIPE , libc:: SIG_DFL ) ;
231+ }
232+
223233 let matches = uu_app ( ) . try_get_matches_from ( args) ?;
224234
225235 let number_mode = if matches. get_flag ( options:: NUMBER_NONBLANK ) {
@@ -502,7 +512,9 @@ fn write_fast<R: FdReadable>(handle: &mut InputHandle<R>) -> CatResult<()> {
502512 if n == 0 {
503513 break ;
504514 }
505- stdout_lock. write_all ( & buf[ ..n] ) ?;
515+ stdout_lock
516+ . write_all ( & buf[ ..n] )
517+ . inspect_err ( handle_broken_pipe) ?;
506518 }
507519 Err ( e) => return Err ( e. into ( ) ) ,
508520 }
@@ -513,7 +525,7 @@ fn write_fast<R: FdReadable>(handle: &mut InputHandle<R>) -> CatResult<()> {
513525 // that will succeed, data pushed through splice will be output before
514526 // the data buffered in stdout.lock. Therefore additional explicit flush
515527 // is required here.
516- stdout_lock. flush ( ) ?;
528+ stdout_lock. flush ( ) . inspect_err ( handle_broken_pipe ) ?;
517529 Ok ( ( ) )
518530}
519531
@@ -584,7 +596,7 @@ fn write_lines<R: FdReadable>(
584596 // and not be buffered internally to the `cat` process.
585597 // Hence it's necessary to flush our buffer before every time we could potentially block
586598 // on a `std::io::Read::read` call.
587- writer. flush ( ) ?;
599+ writer. flush ( ) . inspect_err ( handle_broken_pipe ) ?;
588600 }
589601
590602 Ok ( ( ) )
@@ -704,11 +716,18 @@ fn write_end_of_line<W: Write>(
704716) -> CatResult < ( ) > {
705717 writer. write_all ( end_of_line) ?;
706718 if is_interactive {
707- writer. flush ( ) ?;
719+ writer. flush ( ) . inspect_err ( handle_broken_pipe ) ?;
708720 }
709721 Ok ( ( ) )
710722}
711723
724+ fn handle_broken_pipe ( error : & io:: Error ) {
725+ // SIGPIPE is not available on Windows.
726+ if cfg ! ( target_os = "windows" ) && error. kind ( ) == ErrorKind :: BrokenPipe {
727+ std:: process:: exit ( 13 ) ;
728+ }
729+ }
730+
712731#[ cfg( test) ]
713732mod tests {
714733 use std:: io:: { BufWriter , stdout} ;
0 commit comments