Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 14 additions & 23 deletions src/uu/tee/src/tee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ use uucore::display::Quotable;
use uucore::error::{UResult, strip_errno};
use uucore::translate;

// This error kind will never be raised by std
// Use it for termination when all writers exited
use ErrorKind::Other as AllWriterExited;

mod cli;
pub use crate::cli::uu_app;
use crate::cli::{Options, OutputErrorMode, options};
Expand Down Expand Up @@ -59,14 +63,11 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
fn tee(options: &Options) -> Result<()> {
#[cfg(unix)]
{
// ErrorKind::Other is raised by MultiWriter when all writers have exited.
// This is therefore just a clever way to stop all writers

if options.ignore_interrupts {
ignore_interrupts().map_err(|_| Error::from(ErrorKind::Other))?;
ignore_interrupts().map_err(|_| Error::from(AllWriterExited))?;
}
if options.output_error.is_some() {
disable_pipe_errors().map_err(|_| Error::from(ErrorKind::Other))?;
disable_pipe_errors().map_err(|_| Error::from(AllWriterExited))?;
}
}
let mut writers: Vec<NamedWriter> = options
Expand Down Expand Up @@ -97,17 +98,12 @@ fn tee(options: &Options) -> Result<()> {

// We cannot use std::io::copy here as it doesn't flush the output buffer
let res = match output.copy_unbuffered(input) {
// ErrorKind::Other is raised by MultiWriter when all writers
// have exited, so that copy will abort. It's equivalent to
// success of this part (if there was an error that should
// cause a failure from any writer, that error would have been
// returned instead).
Err(e) if e.kind() != ErrorKind::Other => Err(e),
Err(e) if e.kind() != AllWriterExited => Err(e),
_ => Ok(()),
};

if had_open_errors || res.is_err() || output.error_occurred() {
Err(Error::from(ErrorKind::Other))
Err(Error::from(AllWriterExited))
} else {
Ok(())
}
Expand Down Expand Up @@ -203,24 +199,19 @@ impl MultiWriter {
self.writers
.retain_mut(|writer| match writer.inner.write_all(buf) {
Ok(()) => true,
// if let guard needs Rust 1.95+ <https://github.com/rust-lang/rust/issues/51114>
Err(e) => {
if let Err(e) = process_error(mode, e, writer, &mut self.ignored_errors) {
self.aborted.get_or_insert(e);
}
false
}
});
self.aborted.take().map_or(
if self.writers.is_empty() {
// This error kind will never be raised by the standard
// library, so we can use it for early termination of
// `copy`
Err(Error::from(ErrorKind::Other))
} else {
Ok(())
},
Err,
)
match self.aborted.take() {
Some(e) => Err(e),
None if self.writers.is_empty() => Err(Error::from(AllWriterExited)),
None => Ok(()),
}
}
}

Expand Down
Loading