Skip to content
Open
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
33 changes: 32 additions & 1 deletion tests/by-util/test_tee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore nopipe
// spell-checker:ignore nopipe EFBIG Fsize SIGXFSZ XFSZ

#![allow(clippy::borrow_as_ptr)]

Expand Down Expand Up @@ -262,6 +262,37 @@ mod linux_only {
use uutests::at_and_ucmd;
use uutests::new_ucmd;

#[test]
fn test_tee_append_short_write_before_file_size_error() {
use rustix::process::Resource;
use uutests::util::TestScenario;

const FILE_LIMIT: u64 = 4137;

let content: Vec<u8> = (0..100_000).map(|n| (n % 251) as u8).collect();
let scene = TestScenario::new("tee");
let at = &scene.fixtures;
at.write_bytes("input", &content);

// Append mode prevents splice from writing to the file, naturally
// exercising write_all: the file-size limit allows a prefix, then the
// retry fails. Ignore SIGXFSZ only in the child so it reports EFBIG
// without changing signal handling in other concurrently running tests.
scene
.cmd("sh")
.args(&["-c", "trap '' XFSZ; exec \"$@\"", "sh"])
.arg(&scene.bin_path)
.args(&["tee", "-a", "limited"])
.set_stdin(at.open("input"))
.set_stdout(Stdio::piped())
.limit(Resource::Fsize, FILE_LIMIT, FILE_LIMIT)
.fails_with_code(1)
.stdout_is_bytes(&content)
.stderr_is("tee: limited: File too large\n");

assert_eq!(at.read_bytes("limited"), content[..FILE_LIMIT as usize]);
}

fn make_broken_pipe() -> std::io::PipeWriter {
let (read, write) = std::io::pipe().expect("Failed to create pipe");
// Drop the read end of the pipe
Expand Down
6 changes: 6 additions & 0 deletions util/build-gnu.sh
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,12 @@ grep -rlE '/usr/local/bin/\s?/usr/local/bin' init.cfg tests/* | xargs -r "${SED}
# we should not regress our project just to match what GNU is going.
# So, do some changes on the fly

# strace only injects faults into traced calls. Include splice to force tee's
Comment thread
mattsu2020 marked this conversation as resolved.
# stdout path to use read/write and exercise short-write retries. The
# replacement stops matching after the first edit, avoiding duplicate options.
sed -i 's/-e trace=write /-e trace=write,splice -e fault=splice /' \

@oech3 oech3 Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it mean splice fails only for fd=1 if --trace-fds=1 is given?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.
With --trace-fds=1, the fault injection applies only to splice calls operating on fd 1.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is OK. But I'd like to add test case with failure of splice for fd=0 at different PR. Both uses write_all, but they exist on different place.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ll address it in a separate PR.

tests/tee/short-write.sh

sed -i -e "s|removed directory 'a/'|removed directory 'a'|g" tests/rm/v-slash.sh

# 'rel' doesn't exist. Our implementation is giving a better message.
Expand Down
Loading