]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - sysdeps/unix/sysv/linux/ttyname_r.c
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / sysdeps / unix / sysv / linux / ttyname_r.c
index 3255ce3e00ca617410250ba03adcdae6335bc958..d1ea0d931cc95f710a9c2454d016fa4d62fba3ed 100644 (file)
@@ -1,20 +1,19 @@
-/* Copyright (C) 1991,92,93,95,96,97,98,99 Free Software Foundation, Inc.
+/* Copyright (C) 1991-2019 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Library General Public License as
-   published by the Free Software Foundation; either version 2 of the
-   License, or (at your option) any later version.
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library 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
-   Library General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU Library General Public
-   License along with the GNU C Library; see the file COPYING.LIB.  If not,
-   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
 
 #include <errno.h>
 #include <limits.h>
 #include <dirent.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <termios.h>
 #include <unistd.h>
 #include <string.h>
 #include <stdlib.h>
 
-#include <stdio-common/_itoa.h>
+#include <_itoa.h>
 
-static int getttyname_r __P ((char *buf, size_t buflen,
-                             dev_t mydev, ino_t myino, int save,
-                             int *dostat)) internal_function;
+#include "ttyname.h"
+
+static int getttyname_r (char *buf, size_t buflen,
+                        const struct stat64 *mytty, int save,
+                        int *dostat);
 
 static int
-internal_function
-getttyname_r (buf, buflen, mydev, myino, save, dostat)
-     char *buf;
-     size_t buflen;
-     dev_t mydev;
-     ino_t myino;
-     int save;
-     int *dostat;
+attribute_compat_text_section
+getttyname_r (char *buf, size_t buflen, const struct stat64 *mytty,
+             int save, int *dostat)
 {
-  struct stat st;
+  struct stat64 st;
   DIR *dirstream;
-  struct dirent *d;
+  struct dirent64 *d;
   size_t devlen = strlen (buf);
 
   dirstream = __opendir (buf);
@@ -54,8 +51,8 @@ getttyname_r (buf, buflen, mydev, myino, save, dostat)
       return errno;
     }
 
-  while ((d = __readdir (dirstream)) != NULL)
-    if (((ino_t) d->d_fileno == myino || *dostat)
+  while ((d = __readdir64 (dirstream)) != NULL)
+    if ((d->d_fileno == mytty->st_ino || *dostat)
        && strcmp (d->d_name, "stdin")
        && strcmp (d->d_name, "stdout")
        && strcmp (d->d_name, "stderr"))
@@ -74,13 +71,8 @@ getttyname_r (buf, buflen, mydev, myino, save, dostat)
        cp = __stpncpy (buf + devlen, d->d_name, needed);
        cp[0] = '\0';
 
-       if (__xstat (_STAT_VER, buf, &st) == 0
-#ifdef _STATBUF_ST_RDEV
-           && S_ISCHR (st.st_mode) && st.st_rdev == mydev
-#else
-           && (ino_t) d->d_fileno == myino && st.st_dev == mydev
-#endif
-          )
+       if (__xstat64 (_STAT_VER, buf, &st) == 0
+           && is_mytty (mytty, &st))
          {
            (void) __closedir (dirstream);
            __set_errno (save);
@@ -98,17 +90,13 @@ getttyname_r (buf, buflen, mydev, myino, save, dostat)
 /* Store at most BUFLEN character of the pathname of the terminal FD is
    open on in BUF.  Return 0 on success,  otherwise an error number.  */
 int
-__ttyname_r (fd, buf, buflen)
-     int fd;
-     char *buf;
-     size_t buflen;
+__ttyname_r (int fd, char *buf, size_t buflen)
 {
-  static int dev_pts_available = 1;
   char procname[30];
-  struct stat st, st1;
+  struct stat64 st, st1;
   int dostat = 0;
+  int doispty = 0;
   int save = errno;
-  int ret;
 
   /* Test for the absolute minimal size.  This makes life easier inside
      the loop.  */
@@ -124,75 +112,86 @@ __ttyname_r (fd, buf, buflen)
       return ERANGE;
     }
 
-  if (!__isatty (fd))
-    {
-      __set_errno (ENOTTY);
-      return ENOTTY;
-    }
+  /* isatty check, tcgetattr is used because it sets the correct
+     errno (EBADF resp. ENOTTY) on error.  */
+  struct termios term;
+  if (__glibc_unlikely (__tcgetattr (fd, &term) < 0))
+    return errno;
+
+  if (__fxstat64 (_STAT_VER, fd, &st) < 0)
+    return errno;
 
   /* We try using the /proc filesystem.  */
   *_fitoa_word (fd, __stpcpy (procname, "/proc/self/fd/"), 10, 0) = '\0';
 
-  ret = __readlink (procname, buf, buflen - 1);
-  if (ret != -1 && buf[0] != '[')
-    return 0;
-  if (ret == -1 && errno == ENAMETOOLONG)
+  ssize_t ret = __readlink (procname, buf, buflen - 1);
+  if (__glibc_unlikely (ret == -1 && errno == ENAMETOOLONG))
     {
       __set_errno (ERANGE);
       return ERANGE;
     }
 
-  if (__fxstat (_STAT_VER, fd, &st) < 0)
-    return errno;
+  if (__glibc_likely (ret != -1))
+    {
+#define UNREACHABLE_LEN strlen ("(unreachable)")
+      if (ret > UNREACHABLE_LEN
+         && memcmp (buf, "(unreachable)", UNREACHABLE_LEN) == 0)
+       {
+         memmove (buf, buf + UNREACHABLE_LEN, ret - UNREACHABLE_LEN);
+         ret -= UNREACHABLE_LEN;
+       }
+
+      /* readlink need not terminate the string.  */
+      buf[ret] = '\0';
+
+      /* Verify readlink result, fall back on iterating through devices.  */
+      if (buf[0] == '/'
+         && __xstat64 (_STAT_VER, buf, &st1) == 0
+         && is_mytty (&st, &st1))
+       return 0;
+
+      doispty = 1;
+    }
 
   /* Prepare the result buffer.  */
   memcpy (buf, "/dev/pts/", sizeof ("/dev/pts/"));
   buflen -= sizeof ("/dev/pts/") - 1;
 
-  if (dev_pts_available)
+  if (__xstat64 (_STAT_VER, buf, &st1) == 0 && S_ISDIR (st1.st_mode))
     {
-      if (__xstat (_STAT_VER, buf, &st1) == 0 && S_ISDIR (st1.st_mode))
-       {
-#ifdef _STATBUF_ST_RDEV
-         ret = getttyname_r (buf, buflen, st.st_rdev, st.st_ino, save,
-                             &dostat);
-#else
-         ret = getttyname_r (buf, buflen, st.st_dev, st.st_ino, save,
-                             &dostat);
-#endif
-       }
-      else
-       {
-         __set_errno (save);
-         ret = ENOENT;
-         dev_pts_available = 0;
-       }
+      ret = getttyname_r (buf, buflen, &st, save,
+                         &dostat);
+    }
+  else
+    {
+      __set_errno (save);
+      ret = ENOENT;
     }
 
   if (ret && dostat != -1)
     {
       buf[sizeof ("/dev/") - 1] = '\0';
       buflen += sizeof ("pts/") - 1;
-#ifdef _STATBUF_ST_RDEV
-      ret = getttyname_r (buf, buflen, st.st_rdev, st.st_ino, save,
-                         &dostat);
-#else
-      ret = getttyname_r (buf, buflen, st.st_dev, st.st_ino, save,
+      ret = getttyname_r (buf, buflen, &st, save,
                          &dostat);
-#endif
     }
 
   if (ret && dostat != -1)
     {
       buf[sizeof ("/dev/") - 1] = '\0';
       dostat = 1;
-#ifdef _STATBUF_ST_RDEV
-      ret = getttyname_r (buf, buflen, st.st_rdev, st.st_ino,
-                         save, &dostat);
-#else
-      ret = getttyname_r (buf, buflen, st.st_dev, st.st_ino,
+      ret = getttyname_r (buf, buflen, &st,
                          save, &dostat);
-#endif
+    }
+
+  if (ret && doispty && is_pty (&st))
+    {
+      /* We failed to figure out the TTY's name, but we can at least
+         signal that we did verify that it really is a PTY slave.
+         This happens when we have inherited the file descriptor from
+         a different mount namespace.  */
+      __set_errno (ENODEV);
+      return ENODEV;
     }
 
   return ret;