diff --git a/src/uu/yes/src/yes.rs b/src/uu/yes/src/yes.rs index a24fb8e4688..b07b496345f 100644 --- a/src/uu/yes/src/yes.rs +++ b/src/uu/yes/src/yes.rs @@ -111,23 +111,21 @@ pub fn exec(bytes: &[u8]) -> io::Result<()> { let stdout = rustix::stdio::stdout(); // improve throughput let _ = rustix::pipe::fcntl_setpipe_size(stdout, MAX_ROOTLESS_PIPE_SIZE); - // don't show any error from fast-path and fallback to write for proper message + // GNU catches all strace injections for zero-copy syscalls except for 1st one (checking support of it) // tee() cannot control offset. We can do tee only if original bytes.len() is multiple of PIPE_BUF, // but it is slower than mixing splice even it reduces syscalls... + let bytes_len = bytes.len(); if let Ok((p_read, mut p_write)) = pipe::() && p_write.write_all(bytes).is_ok() && let Ok((broker_read, broker_write)) = pipe::() + && Ok(bytes_len) == tee(&p_read, &broker_write, MAX_ROOTLESS_PIPE_SIZE) + && uucore::pipes::drain_pipe(&broker_read, &stdout, bytes_len)?.is_ok() { - 'splice: while let Ok(mut remain) = tee(&p_read, &broker_write, MAX_ROOTLESS_PIPE_SIZE) { - debug_assert!(remain == bytes.len(), "splice() should cleanup pipe"); + // fallback from tee() is possible since we did not send anything to stdout yet + while let Ok(mut remain) = tee(&p_read, &broker_write, MAX_ROOTLESS_PIPE_SIZE) { + debug_assert!(remain == bytes_len, "splice should cleanup pipe"); while remain > 0 { - if let Ok(s) = splice(&broker_read, &stdout, remain) { - remain -= s; - } else { - // avoid output breakage with reduced remain even if it would not happen - RawWriter(stdout).write_all(&bytes[bytes.len() - remain..])?; - break 'splice; - } + remain -= splice(&broker_read, &stdout, remain)?; } } }