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
21 changes: 16 additions & 5 deletions src/uu/tty/src/tty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,31 @@
}

let mut stdout = std::io::stdout();

let name = nix::unistd::ttyname(std::io::stdin());

let write_result = match name {
Ok(name) => stdout.write_all_os(name.as_os_str()),
Ok(name) => {
if let Err(e) = stdout.write_all_os(name.as_os_str()) {
Err(e)
} else if let Err(e) = writeln!(stdout) {
Err(e)
} else {
stdout.flush()
}
}
Err(_) => {
set_exit_code(1);
writeln!(stdout, "{}", translate!("tty-not-a-tty"))
}
};

if write_result.is_err() || stdout.flush().is_err() {
// Don't return to prevent a panic later when another flush is attempted
// because the `uucore_procs::main` macro inserts a flush after execution for every utility.
if let Err(e) = write_result {
eprintln!("tty: write error: {}", e);

Check failure on line 55 in src/uu/tty/src/tty.rs

View workflow job for this annotation

GitHub Actions / Style and Lint (ubuntu-24.04, unix)

ERROR: `cargo clippy`: variables can be used directly in the `format!` string (file:'src/uu/tty/src/tty.rs', line:55)

Check failure on line 55 in src/uu/tty/src/tty.rs

View workflow job for this annotation

GitHub Actions / Style and Lint (unix)

ERROR: `cargo clippy`: variables can be used directly in the `format!` string (file:'src/uu/tty/src/tty.rs', line:55)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why did you change this?

Copy link
Author

Choose a reason for hiding this comment

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

@ChrisDryden I removed it because I thought it was redundant (flush was already called in line 37), but I've now restored it to match the original pattern.

Copy link
Contributor

Choose a reason for hiding this comment

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

I guess we can extract it from OS provided err message.
(Also please cargo fmt)

std::process::exit(3);
}

if let Err(e) = stdout.flush() {
eprintln!("tty: write error: {}", e);

Check failure on line 60 in src/uu/tty/src/tty.rs

View workflow job for this annotation

GitHub Actions / Style and Lint (ubuntu-24.04, unix)

ERROR: `cargo clippy`: variables can be used directly in the `format!` string (file:'src/uu/tty/src/tty.rs', line:60)

Check failure on line 60 in src/uu/tty/src/tty.rs

View workflow job for this annotation

GitHub Actions / Style and Lint (unix)

ERROR: `cargo clippy`: variables can be used directly in the `format!` string (file:'src/uu/tty/src/tty.rs', line:60)
std::process::exit(3);
}

Expand Down
41 changes: 41 additions & 0 deletions tests/by-util/test_tty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,44 @@ fn test_stdout_fail() {
let status = proc.wait().unwrap();
assert_eq!(status.code(), Some(3));
}

#[test]
#[cfg(all(unix, not(target_os = "freebsd")))]
fn test_newline_in_output() {
// Test that output ends with a newline, regardless of success or failure
let result = new_ucmd!().run();
let stdout = result.stdout_str();

// Whether it's "not a tty\n" or an actual tty path, it should end with newline
assert!(
stdout.ends_with('\n'),
"Output should end with newline, got: {:?}",
stdout
);
}

#[test]
#[cfg(all(unix, not(target_os = "freebsd")))]
#[ignore = "Fails on some CI environments - see https://github.com/uutils/coreutils/pull/10252"]
fn test_write_error_dev_full() {
use std::process::{Command, Stdio};
use uutests::at_and_ts;

let (_, ts) = at_and_ts!();

// Redirect stdout to /dev/full which causes write errors
let output = Command::new(ts.bin_path.to_str().unwrap())
.arg(&ts.util_name)
.stdout(Stdio::from(File::create("/dev/full").unwrap()))
.output()
.unwrap();

// Should exit with code 3 and print error to stderr
assert_eq!(output.status.code(), Some(3));
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
stderr.contains("write error"),
"Should contain 'write error' in stderr, got: {:?}",
stderr
);
}
Loading