diff --git a/src/uu/tee/src/tee.rs b/src/uu/tee/src/tee.rs index 8f96f4cc73d..afbe4a96307 100644 --- a/src/uu/tee/src/tee.rs +++ b/src/uu/tee/src/tee.rs @@ -249,11 +249,12 @@ enum Writer { impl Writer { pub fn write_all(&mut self, buf: &[u8]) -> Result<()> { + use uucore::io::AsFdExt as _; match self { // File does not have line buffering - Self::File(f) => f.write_all(buf), + Self::File(f) => f.write_all_no_retry(buf), #[cfg(any(unix, target_os = "wasi"))] - Self::Stdout(s) => s.write_all(buf), + Self::Stdout(s) => s.0.write_all_no_retry(buf), #[cfg(not(any(unix, target_os = "wasi")))] Self::Stdout(s) => { s.write_all(buf)?; diff --git a/src/uucore/src/lib/mods/io.rs b/src/uucore/src/lib/mods/io.rs index eccbd10e37a..9c3c7ce7b0b 100644 --- a/src/uucore/src/lib/mods/io.rs +++ b/src/uucore/src/lib/mods/io.rs @@ -53,6 +53,31 @@ impl io::Write for RawWriter { } } +// write_all retries with EINTR which is sometimes not compatible with GNU +#[cfg(any(unix, target_os = "wasi"))] +pub trait AsFdExt { + fn write_all_no_retry(&self, buf: &[u8]) -> io::Result<()>; +} +#[cfg(any(unix, target_os = "wasi"))] +impl AsFdExt for T { + fn write_all_no_retry(&self, mut buf: &[u8]) -> io::Result<()> { + let fd = self.as_fd(); + while !buf.is_empty() { + match rustix::io::write(fd, buf) { + Ok(0) => { + return Err(io::Error::new( + io::ErrorKind::WriteZero, + "failed to write whole buffer", + )); + } + Ok(n) => buf = &buf[n..], + Err(e) => return Err(e.into()), + } + } + Ok(()) + } +} + /// abstraction wrapper for native file handle / file descriptor // todo: remove clone introducing additional syscall dependency pub struct OwnedFileDescriptorOrHandle {