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
18 changes: 8 additions & 10 deletions src/uu/yes/src/yes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<true>()
&& p_write.write_all(bytes).is_ok()
&& let Ok((broker_read, broker_write)) = pipe::<true>()
&& 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)?;
}
}
}
Expand Down
Loading