Thanks for the bug report. The situation you describe seems to be a platform that does not conform to POSIX, since POSIX doesn't allow for isatty to succeed but ttyname to fail. So I expect you'll run into problems other than with the tty program, as other software will make the same assumptions that tty is making.

That being said, tty could do a better job about the situation. I installed the attached somewhat-more-ambitious patch, so that tty will do more-extensive checking of the results of isatty and/or ttyname (and so that it never needs to call both functions and worry about whether their results are consistent :-). Please give it a try on your platform.
From 2130da3df536a277749495621beadf662d2400e4 Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email protected]>
Date: Wed, 5 Apr 2017 11:34:42 -0700
Subject: [PATCH] tty: handle misconfigured namespaces
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

On some platforms, isatty succeeds but ttyname fails.
POSIX does not seem to allow this, but there it is.
Problem reported by Christian Brauner (Bug#26371).
While we’re at it, check for errors more carefully and return a
new exit status 4 if stdin is closed or a similar error occurs.
* doc/coreutils.texi (tty invocation): Document new behavior.
* init.cfg (stderr_fileno_):
Don't assume have_input_tty is not in the environment.
* src/tty.c (TTY_STDIN_ERROR): New constant.
(main): Exit with nonzero status if there is a usage error,
like other coreutils programs.
Check for error in getting stdin type.
* tests/misc/tty.sh: New file.
* tests/local.mk (all_tests): Add it.
---
 doc/coreutils.texi |  3 ++-
 init.cfg           |  1 +
 src/tty.c          | 33 +++++++++++++++++++++++----------
 tests/local.mk     |  1 +
 tests/misc/tty.sh  | 42 ++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 69 insertions(+), 11 deletions(-)
 create mode 100755 tests/misc/tty.sh

diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index c22e076..284e7e3 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -15041,9 +15041,10 @@ Exit status:
 
 @display
 0 if standard input is a terminal
-1 if standard input is not a terminal
+1 if standard input is a non-terminal file
 2 if given incorrect arguments
 3 if a write error occurs
+4 if standard input is closed or its type cannot be determined
 @end display
 
 
diff --git a/init.cfg b/init.cfg
index 2f747a3..af6b581 100644
--- a/init.cfg
+++ b/init.cfg
@@ -293,6 +293,7 @@ require_setfacl_()
 # Require a controlling input 'terminal'.
 require_controlling_input_terminal_()
 {
+  have_input_tty=yes
   tty -s || have_input_tty=no
   test -t 0 || have_input_tty=no
   if test "$have_input_tty" = no; then
diff --git a/src/tty.c b/src/tty.c
index c3fdabc..e908e7e 100644
--- a/src/tty.c
+++ b/src/tty.c
@@ -34,7 +34,8 @@
 enum
   {
     TTY_FAILURE = 2,
-    TTY_WRITE_ERROR = 3
+    TTY_WRITE_ERROR = 3,
+    TTY_STDIN_ERROR = 4
   };
 
 /* The official name of this program (e.g., no 'g' prefix).  */
@@ -77,7 +78,6 @@ Print the file name of the terminal connected to standard input.\n\
 int
 main (int argc, char **argv)
 {
-  char *tty;
   int optc;
 
   initialize_main (&argc, &argv);
@@ -109,16 +109,29 @@ main (int argc, char **argv)
     }
 
   if (optind < argc)
-    error (0, 0, _("extra operand %s"), quote (argv[optind]));
+    {
+      error (0, 0, _("extra operand %s"), quote (argv[optind]));
+      usage (TTY_FAILURE);
+    }
+
+  errno = ENOENT;
+
+  if (silent)
+    return (isatty (STDIN_FILENO) ? EXIT_SUCCESS
+            : errno == ENOTTY ? EXIT_FAILURE
+            : TTY_STDIN_ERROR);
+
+  int status = EXIT_SUCCESS;
+  char const *tty = ttyname (STDIN_FILENO);
 
-  tty = ttyname (STDIN_FILENO);
-  if (!silent)
+  if (! tty)
     {
-      if (tty)
-        puts (tty);
-      else
-        puts (_("not a tty"));
+      if (errno != ENOTTY)
+        error (TTY_STDIN_ERROR, errno, _("standard input"));
+      tty = _("not a tty");
+      status = EXIT_FAILURE;
     }
 
-  return isatty (STDIN_FILENO) ? EXIT_SUCCESS : EXIT_FAILURE;
+  puts (tty);
+  return status;
 }
diff --git a/tests/local.mk b/tests/local.mk
index 9f1a853..3fe9ba8 100644
--- a/tests/local.mk
+++ b/tests/local.mk
@@ -415,6 +415,7 @@ all_tests =					\
   tests/misc/truncate-parameters.sh		\
   tests/misc/truncate-relative.sh		\
   tests/misc/tsort.pl				\
+  tests/misc/tty.sh				\
   tests/misc/unexpand.pl			\
   tests/misc/uniq.pl				\
   tests/misc/uniq-perf.sh			\
diff --git a/tests/misc/tty.sh b/tests/misc/tty.sh
new file mode 100755
index 0000000..5931350
--- /dev/null
+++ b/tests/misc/tty.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+# Test 'tty'.
+
+# Copyright 2017 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Make sure there's a tty on stdin.
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tty
+
+if test -t 0; then
+  tty || fail=1
+  tty -s || fail=1
+fi
+
+returns_ 1 tty </dev/null || fail=1
+returns_ 1 tty -s </dev/null || fail=1
+
+returns_ 2 tty a || fail=1
+returns_ 2 tty -s a || fail=1
+
+if test -w /dev/full && test -c /dev/full; then
+  returns_ 3 tty >/dev/full || fail=1
+  returns_ 3 tty </dev/null >/dev/full || fail=1
+fi
+
+returns_ 4 tty <&- 2>/dev/null || fail=1
+returns_ 4 tty -s <&- || fail=1
+
+Exit $fail
-- 
2.9.3

Reply via email to