tac: should fail when stdin is closed but doesn't
The uutils version of tac disagrees with GNU tac in the case where stdin is closed on the command line:
GNU prints an error message to stderr and returns exit status code 1:
$ tac <&-
tac: 'standard input': read error: Bad file descriptor
tac: -: Bad file descriptor
uutils prints nothing and returns exit status code 0:
$ ./target/debug/coreutils tac <&-
This is causing one of the GNU tests to fail.
Libstd opens stdin, stdout and stderr as /dev/null if they aren't open at program start to prevent std::io::{stdin,stdout,stderr} from pointing to unrelated file resources that are opened later. See https://github.com/rust-lang/rust/blob/17dfae79bbc3dabe1427073086acf7f7bd45148c/library/std/src/sys/unix/mod.rs#L54-L57
The stdlib could open /dev/null with different permissions in that case so that reads/writes still fail, like this: https://github.com/tavianator/bfs/blob/f4772fe4c13eb8b9b3c199d4e1703c242babcfd7/main.c#L88-L114
I came across this because one of the tests from gnu/tests/tail-2/follow-stdin.sh also uses <&- to provoke the bad fd error. (Actually <&- is also used in: gnu/tests/misc/{tac-2-nonseekable, sort-merge-fdlimit, sort-continue, tty}.sh and gnu/tests/cp/cp-mv-backup.sh).
I tried this, but it didn't work and I don't know why:
fn get_errno() -> i32 {
Error::last_os_error().raw_os_error().unwrap()
}
pub fn stdin_is_bad_fd() -> bool {
let fd = stdin().as_raw_fd();
// FIXME: this is never `true`, even with `<&-`
unsafe { libc::fcntl(fd, libc::F_GETFD) == -1 && get_errno() == libc::EBADF }
}
@jhscheer It's because of what @bjorn3 wrote in https://github.com/uutils/coreutils/issues/2873#issuecomment-1024940029
@jhscheer It's because of what @bjorn3 wrote in #2873 (comment)
Thanks.
There's a discussion about why stdlib is reopening the file descriptors here. @tavianator did you open an issue with your suggestion at the rust-lang repo?
So I guess, unless stdlib implements a better workaround than the one currently used, it's not likely we will ever pass the GNU tests mentioned above.
Ah so in the linked PR, https://github.com/rust-lang/rust/pull/75295#issuecomment-673178574 suggests using pipes to accomplish something similar to my suggestion in https://github.com/uutils/coreutils/issues/2873#issuecomment-1033288915. But RFC 1014 explicitly conflicts with that, as pointed out in https://github.com/rust-lang/rust/pull/75295#issuecomment-673900935. So we can't do that unless we're okay with reverting that RFC I guess.
I didn't open an issue, but there's already one: https://github.com/rust-lang/rust/issues/88825