8
8
mod platform;
9
9
10
10
use crate :: platform:: is_unsafe_overwrite;
11
+ use clap:: { Arg , ArgAction , Command } ;
12
+ use memchr:: memchr2;
11
13
use std:: fs:: { File , metadata} ;
12
- use std:: io:: { self , BufWriter , IsTerminal , Read , Write } ;
14
+ use std:: io:: { self , BufWriter , ErrorKind , IsTerminal , Read , Write } ;
13
15
/// Unix domain socket support
14
16
#[ cfg( unix) ]
15
17
use std:: net:: Shutdown ;
@@ -19,12 +21,11 @@ use std::os::fd::AsFd;
19
21
use std:: os:: unix:: fs:: FileTypeExt ;
20
22
#[ cfg( unix) ]
21
23
use std:: os:: unix:: net:: UnixStream ;
22
-
23
- use clap:: { Arg , ArgAction , Command } ;
24
- use memchr:: memchr2;
25
24
use thiserror:: Error ;
26
25
use uucore:: display:: Quotable ;
27
26
use uucore:: error:: UResult ;
27
+ #[ cfg( not( target_os = "windows" ) ) ]
28
+ use uucore:: libc;
28
29
use uucore:: locale:: get_message;
29
30
use uucore:: { fast_inc:: fast_inc_one, format_usage} ;
30
31
@@ -220,6 +221,15 @@ mod options {
220
221
221
222
#[ uucore:: main]
222
223
pub 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
+
223
233
let matches = uu_app ( ) . try_get_matches_from ( args) ?;
224
234
225
235
let number_mode = if matches. get_flag ( options:: NUMBER_NONBLANK ) {
@@ -502,7 +512,9 @@ fn write_fast<R: FdReadable>(handle: &mut InputHandle<R>) -> CatResult<()> {
502
512
if n == 0 {
503
513
break ;
504
514
}
505
- stdout_lock. write_all ( & buf[ ..n] ) ?;
515
+ stdout_lock
516
+ . write_all ( & buf[ ..n] )
517
+ . inspect_err ( handle_broken_pipe) ?;
506
518
}
507
519
Err ( e) => return Err ( e. into ( ) ) ,
508
520
}
@@ -513,7 +525,7 @@ fn write_fast<R: FdReadable>(handle: &mut InputHandle<R>) -> CatResult<()> {
513
525
// that will succeed, data pushed through splice will be output before
514
526
// the data buffered in stdout.lock. Therefore additional explicit flush
515
527
// is required here.
516
- stdout_lock. flush ( ) ?;
528
+ stdout_lock. flush ( ) . inspect_err ( handle_broken_pipe ) ?;
517
529
Ok ( ( ) )
518
530
}
519
531
@@ -584,7 +596,7 @@ fn write_lines<R: FdReadable>(
584
596
// and not be buffered internally to the `cat` process.
585
597
// Hence it's necessary to flush our buffer before every time we could potentially block
586
598
// on a `std::io::Read::read` call.
587
- writer. flush ( ) ?;
599
+ writer. flush ( ) . inspect_err ( handle_broken_pipe ) ?;
588
600
}
589
601
590
602
Ok ( ( ) )
@@ -704,11 +716,18 @@ fn write_end_of_line<W: Write>(
704
716
) -> CatResult < ( ) > {
705
717
writer. write_all ( end_of_line) ?;
706
718
if is_interactive {
707
- writer. flush ( ) ?;
719
+ writer. flush ( ) . inspect_err ( handle_broken_pipe ) ?;
708
720
}
709
721
Ok ( ( ) )
710
722
}
711
723
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
+
712
731
#[ cfg( test) ]
713
732
mod tests {
714
733
use std:: io:: { BufWriter , stdout} ;
0 commit comments