diff --git a/.vscode/cspell.dictionaries/workspace.wordlist.txt b/.vscode/cspell.dictionaries/workspace.wordlist.txt index d4a7b52fb91..e42f24a948d 100644 --- a/.vscode/cspell.dictionaries/workspace.wordlist.txt +++ b/.vscode/cspell.dictionaries/workspace.wordlist.txt @@ -154,6 +154,7 @@ IFSOCK IRGRP IROTH IRUSR +ISDIR ISGID ISUID ISVTX @@ -205,6 +206,7 @@ setgid setgroups settime setuid +socketpair socktype statfs statp diff --git a/Cargo.lock b/Cargo.lock index d3a59a95d00..99cf61458a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1692,6 +1692,15 @@ dependencies = [ "libc", ] +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -1729,6 +1738,7 @@ dependencies = [ "cfg-if", "cfg_aliases", "libc", + "memoffset", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index e75f4be5900..d4ae1eb00ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -537,7 +537,13 @@ hex-literal = "1.0.0" rstest.workspace = true [target.'cfg(unix)'.dev-dependencies] -nix = { workspace = true, features = ["process", "signal", "user", "term"] } +nix = { workspace = true, features = [ + "process", + "signal", + "socket", + "user", + "term", +] } rlimit = "0.10.1" xattr.workspace = true diff --git a/src/uucore/src/lib/features/fs.rs b/src/uucore/src/lib/features/fs.rs index 5c228376d02..b9888654047 100644 --- a/src/uucore/src/lib/features/fs.rs +++ b/src/uucore/src/lib/features/fs.rs @@ -720,7 +720,9 @@ pub fn is_stdin_directory(stdin: &Stdin) -> bool { { use nix::sys::stat::fstat; let mode = fstat(stdin.as_fd()).unwrap().st_mode as mode_t; - has!(mode, S_IFDIR) + // We use the S_IFMT mask ala S_ISDIR() to avoid mistaking + // sockets for directories. + mode & S_IFMT == S_IFDIR } #[cfg(windows)] diff --git a/tests/by-util/test_tr.rs b/tests/by-util/test_tr.rs index 0121f87aa63..491fd64ee02 100644 --- a/tests/by-util/test_tr.rs +++ b/tests/by-util/test_tr.rs @@ -1563,3 +1563,24 @@ fn test_broken_pipe_no_error() { .run_stdout_starts_with(b"") .fails_silently(); } + +#[cfg(not(windows))] +#[test] +fn test_stdin_is_socket() { + use nix::sys::socket::{AddressFamily, SockFlag, SockType, socketpair}; + use nix::unistd::write; + + let (fd1, fd2) = socketpair( + AddressFamily::Unix, + SockType::Stream, + None, + SockFlag::empty(), + ) + .unwrap(); + write(fd1, b"::").unwrap(); + new_ucmd!() + .args(&[":", ";"]) + .set_stdin(fd2) + .succeeds() + .stdout_is(";;"); +}