tty: support printing msys2 tty path

This commit is contained in:
Chris Denton
2026-04-29 15:50:11 +00:00
committed by Daniel Hofstetter
parent b3d8706a2c
commit a07879b8ab
4 changed files with 60 additions and 5 deletions
@@ -61,6 +61,7 @@ MinGW
Minix
MS-DOS
MSDOS
msys
NetBSD
Novell
Nushell
Generated
+1
View File
@@ -4374,6 +4374,7 @@ dependencies = [
"fluent",
"rustix",
"uucore",
"windows-sys 0.61.2",
]
[[package]]
+6
View File
@@ -27,6 +27,12 @@ fluent = { workspace = true }
[target.'cfg(unix)'.dependencies]
rustix = { workspace = true, features = ["fs", "termios"] }
[target.'cfg(windows)'.dependencies]
windows-sys = { workspace = true, features = [
"Win32_Storage_FileSystem",
"Win32_Foundation",
] }
[[bin]]
name = "tty"
path = "src/main.rs"
+52 -5
View File
@@ -58,11 +58,20 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
writeln!(stdout, "{}", translate!("tty-not-a-tty"))
};
#[cfg(target_os = "windows")]
let write_result = if std::io::stdin().is_terminal() {
writeln!(stdout, r"\\.\CON")
} else {
set_exit_code(1);
writeln!(stdout, "{}", translate!("tty-not-a-tty"))
let write_result = {
use std::os::windows::io::AsHandle;
let stdin = std::io::stdin();
let stdin_handle = stdin.as_handle();
if stdin_handle.is_terminal() {
writeln!(
stdout,
"{}",
file_name(stdin_handle).as_deref().unwrap_or(r"\\.\CON")
)
} else {
set_exit_code(1);
writeln!(stdout, "{}", translate!("tty-not-a-tty"))
}
};
if write_result.is_err() || stdout.flush().is_err() {
@@ -74,6 +83,44 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
Ok(())
}
#[cfg(target_os = "windows")]
fn file_name(handle: std::os::windows::io::BorrowedHandle) -> Option<String> {
// This code is adapted from rust's standard library
// https://github.com/rust-lang/rust/blob/0424cc16731e6141a18077f8ccde77ba148d9649/library/std/src/sys/io/is_terminal/windows.rs#L25
use std::mem::MaybeUninit;
use std::os::windows::io::AsRawHandle;
use windows_sys::Win32::Foundation::MAX_PATH;
use windows_sys::Win32::Storage::FileSystem::{FileNameInfo, GetFileInformationByHandleEx};
// Manually define FILE_NAME_INFO so we can more easily construct a stack buffer.
#[repr(C)]
#[allow(non_snake_case)]
struct FILE_NAME_INFO {
FileNameLength: u32,
FileName: [MaybeUninit<u16>; MAX_PATH as usize],
}
let mut name = FILE_NAME_INFO {
FileNameLength: 0,
FileName: [MaybeUninit::uninit(); MAX_PATH as usize],
};
unsafe {
let result = GetFileInformationByHandleEx(
handle.as_raw_handle(),
FileNameInfo,
(&raw mut name).cast(),
size_of::<FILE_NAME_INFO>() as u32,
);
if result == 0 {
None
} else {
let name = name.FileName.get(..name.FileNameLength as usize / 2)?;
// SAFETY: all elements up to FileNameLength have been initialized
let name: &[u16] = &*(std::ptr::from_ref::<[MaybeUninit<u16>]>(name) as *const [u16]);
// This should never fail for a valid msys terminal because they use ASCII names.
String::from_utf16(name).ok()
}
}
}
pub fn uu_app() -> Command {
let cmd = Command::new("tty")
.version(uucore::crate_version!())