Skip to content
Closed
Show file tree
Hide file tree
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
3 changes: 3 additions & 0 deletions src/uu/yes/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ itertools = { workspace = true }
uucore = { workspace = true, features = ["pipes", "signals"] }
nix = { workspace = true }

[target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies]
uucore = { workspace = true, features = ["buf-copy"] }

[target.'cfg(not(unix))'.dependencies]
uucore = { workspace = true, features = ["pipes"] }

Expand Down
77 changes: 0 additions & 77 deletions src/uu/yes/src/splice.rs

This file was deleted.

65 changes: 44 additions & 21 deletions src/uu/yes/src/yes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,19 @@
use clap::{builder::ValueParser, crate_version, Arg, ArgAction, Command};
use std::error::Error;
use std::ffi::OsString;
use std::io::{self, Write};
use std::io::{stdout, Write};
use uucore::error::UResult;
use uucore::{format_usage, help_about, help_usage};

#[cfg(any(target_os = "linux", target_os = "android"))]
use std::os::fd::{AsFd, AsRawFd};
#[cfg(any(target_os = "linux", target_os = "android"))]
use std::os::fd::AsFd;
use uucore::error::{UResult, USimpleError};
use uucore::buf_copy::{is_pipe, splice_data_to_fd, splice_data_to_pipe};
#[cfg(any(target_os = "linux", target_os = "android"))]
use uucore::pipes::pipe;

#[cfg(unix)]
use uucore::signals::enable_pipe_errors;
use uucore::{format_usage, help_about, help_usage};
#[cfg(any(target_os = "linux", target_os = "android"))]
mod splice;

const ABOUT: &str = help_about!("yes.md");
const USAGE: &str = help_usage!("yes.md");
Expand All @@ -33,11 +37,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
args_into_buffer(&mut buffer, matches.get_many::<OsString>("STRING")).unwrap();
prepare_buffer(&mut buffer);

match exec(&buffer) {
Ok(()) => Ok(()),
Err(err) if err.kind() == io::ErrorKind::BrokenPipe => Ok(()),
Err(err) => Err(USimpleError::new(1, format!("standard output: {err}"))),
}
exec(&buffer)
}

pub fn uu_app() -> Command {
Expand Down Expand Up @@ -112,20 +112,43 @@ fn prepare_buffer(buf: &mut Vec<u8>) {
}
}

pub fn exec(bytes: &[u8]) -> io::Result<()> {
let stdout = io::stdout();
/// On Linux and Android, repeatedly call the splice function to write our buffered string into
/// standard output using the `splice` system call.
#[cfg(any(target_os = "linux", target_os = "android"))]
fn loop_splice_data<T>(bytes: &[u8], out: &T) -> UResult<()>
where
T: AsRawFd + AsFd,
{
let is_pipe = is_pipe(out)?;

// Under the if statements below, an Ok(()) is returned to indicate that the
// splice call failed but is still recoverable, i.e by using the
// stdout.write_all method.
if is_pipe {
loop {
if splice_data_to_pipe(bytes, out)?.1 {
return Ok(());
}
}
} else {
let (read, write) = pipe()?;
loop {
if splice_data_to_fd(bytes, &read, &write, out)?.1 {
return Ok(());
};
}
}
}

pub fn exec(bytes: &[u8]) -> UResult<()> {
let stdout = stdout();
let mut stdout = stdout.lock();

#[cfg(unix)]
enable_pipe_errors()?;

#[cfg(any(target_os = "linux", target_os = "android"))]
{
match splice::splice_data(bytes, &stdout.as_fd()) {
Ok(_) => return Ok(()),
Err(splice::Error::Io(err)) => return Err(err),
Err(splice::Error::Unsupported) => (),
}
}
// #[cfg(any(target_os = "linux", target_os = "android"))]
// loop_splice_data(bytes, &stdout)?;

loop {
stdout.write_all(bytes)?;
Expand Down
Loading