From 5aee95b4e5720934745ecdc3ccdf9b833355f3aa Mon Sep 17 00:00:00 2001 From: Jan Scheer <jhscheer@users.noreply.github.com> Date: Mon, 16 May 2022 22:10:27 +0200 Subject: [PATCH] tail: add check to detect a closed file descriptor This is WIP or even WONT-FIX because there's a workaround in Rust's stdlib which prevents us from detecting a closed FD. see also the discussion at: https://github.com/uutils/coreutils/issues/2873 --- src/uu/tail/src/platform/mod.rs | 4 +++- src/uu/tail/src/platform/unix.rs | 28 +++++++++++++++++++--------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/uu/tail/src/platform/mod.rs b/src/uu/tail/src/platform/mod.rs index 7b7fd6fa3..f4cd6fb6c 100644 --- a/src/uu/tail/src/platform/mod.rs +++ b/src/uu/tail/src/platform/mod.rs @@ -9,7 +9,9 @@ */ #[cfg(unix)] -pub use self::unix::{stdin_is_pipe_or_fifo, supports_pid_checks, Pid, ProcessChecker}; +pub use self::unix::{ + stdin_is_bad_fd, stdin_is_pipe_or_fifo, supports_pid_checks, Pid, ProcessChecker, +}; #[cfg(windows)] pub use self::windows::{supports_pid_checks, Pid, ProcessChecker}; diff --git a/src/uu/tail/src/platform/unix.rs b/src/uu/tail/src/platform/unix.rs index 7ddf6edd0..00d21a6ae 100644 --- a/src/uu/tail/src/platform/unix.rs +++ b/src/uu/tail/src/platform/unix.rs @@ -51,13 +51,23 @@ fn get_errno() -> i32 { pub fn stdin_is_pipe_or_fifo() -> bool { let fd = stdin().lock().as_raw_fd(); - fd >= 0 // GNU tail checks fd >= 0 - && match fstat(fd) { - Ok(stat) => { - let mode = stat.st_mode as libc::mode_t; - // NOTE: This is probably not the most correct way to check this - (mode & S_IFIFO != 0) || (mode & S_IFSOCK != 0) - } - Err(err) => panic!("{}", err), - } + // GNU tail checks fd >= 0 + fd >= 0 + && match fstat(fd) { + Ok(stat) => { + let mode = stat.st_mode as libc::mode_t; + // NOTE: This is probably not the most correct way to check this + (mode & S_IFIFO != 0) || (mode & S_IFSOCK != 0) + } + Err(err) => panic!("{}", err), + } +} + +// FIXME: Detect a closed file descriptor, e.g.: `tail <&-` +pub fn stdin_is_bad_fd() -> bool { + let fd = stdin().as_raw_fd(); + // this is never `true`, even with `<&-` because stdlib is reopening fds as /dev/null + // see also: https://github.com/uutils/coreutils/issues/2873 + // (gnu/tests/tail-2/follow-stdin.sh fails because of this) + unsafe { libc::fcntl(fd, libc::F_GETFD) == -1 && get_errno() == libc::EBADF } }