bug-glibc
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

ttyname fails for setid programs under linux/devfs


From: ben
Subject: ttyname fails for setid programs under linux/devfs
Date: Fri, 24 Oct 2003 04:12:23 +0100
User-agent: Mutt/1.5.4i

Hi,
I run Linux and use devfs, without the 'compatibility names', and I
recently discovered that write(1) invariably fails with the message
'can't find your tty's name!'. Further investigation revealed that
ttyname(3) currently tries the following two strategies:

1. Read the links in /proc/self/fd. This fails for write(1) because
   write is sgid tty, and the links in /proc/self/fd are readable only
   by root for setid processes.

2. Walk /dev and /dev/pts. This fails because my tty (/dev/vc/3) is
   not in either of these directories.

Two other minor flaws in the current implementation are that it
returns "/dev/tty" rather than the actual device for a fd open on
/dev/tty; and that if (say) a device file is created in /tmp and
opened, it will return the path that was opened rather than the
canonical name of the tty in /dev.

Therefore the patch below modifies ttyname_r to try these strategies:

1. If the fd we are given is open on /dev/tty, try to readlink
   /proc/self/tty (this will be a symlink to the ctty in kernel 2.8,
   according to comments in the source of procps); if that fails, try
   to extract the device number of our ctty out of /proc/self/stat;
   only if that fails return "/dev/tty".

2. Read the file /proc/tty/drivers, which maps device numbers to /dev
   file names.

3. Attempt to guess the name from its device number, using a routine I
   took out of procps.

4. Read the links in /proc/self/fd. This, unlike the other methods,
   will return the opened name rather than the canonical name; but I
   reasoned it was better than walking /dev...?

5. Walk an extended list of dirs in dev, including devfs dirs like
   /dev/vc and /dev/tts.

, and makes ttyname call ttyname_r (I couldn't see why it didn't
anyway... am I missing something?).

If you wish to make use of this, I hereby state that I donate all
rights in my code to the FSF, etc.... There is one function which is
not mine, out of procps: this is clearly marked so you can remove it
if you wish.

The diff is taken against glibc-2.3.2, but the files concerned haven't
changed since then in the current CVS version.

Ben

---BEGIN DIFF---

diff -Naur glibc-2.3.2-orig/sysdeps/unix/sysv/linux/ttyname.c 
glibc-2.3.2/sysdeps/unix/sysv/linux/ttyname.c
--- glibc-2.3.2-orig/sysdeps/unix/sysv/linux/ttyname.c  2002-11-02 
02:16:02.000000000 +0000
+++ glibc-2.3.2/sysdeps/unix/sysv/linux/ttyname.c       2003-10-23 
05:42:39.000000000 +0100
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991,92,93,1996-2001,2002 Free Software Foundation, Inc.
+/* Copyright (C) 1991,92,93,1995-2001, 2003 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
@@ -16,173 +16,30 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
-#include <errno.h>
-#include <limits.h>
-#include <stddef.h>
-#include <dirent.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include <stdio-common/_itoa.h>
-
-#if 0
-/* Is this used anywhere?  It is not exported.  */
-char *__ttyname;
-#endif
-
-static char *getttyname (const char *dev, dev_t mydev,
-                        ino64_t myino, int save, int *dostat)
-     internal_function;
-
-
-libc_freeres_ptr (static char *getttyname_name);
-
-static char *
-internal_function
-getttyname (const char *dev, dev_t mydev, ino64_t myino, int save, int *dostat)
-{
-  static size_t namelen;
-  struct stat64 st;
-  DIR *dirstream;
-  struct dirent64 *d;
-  size_t devlen = strlen (dev) + 1;
-
-  dirstream = __opendir (dev);
-  if (dirstream == NULL)
-    {
-      *dostat = -1;
-      return NULL;
-    }
-
-  while ((d = __readdir64 (dirstream)) != NULL)
-    if ((d->d_fileno == myino || *dostat)
-       && strcmp (d->d_name, "stdin")
-       && strcmp (d->d_name, "stdout")
-       && strcmp (d->d_name, "stderr"))
-      {
-       size_t dlen = _D_ALLOC_NAMLEN (d);
-       if (devlen + dlen > namelen)
-         {
-           free (getttyname_name);
-           namelen = 2 * (devlen + dlen); /* Big enough.  */
-           getttyname_name = malloc (namelen);
-           if (! getttyname_name)
-             {
-               *dostat = -1;
-               /* Perhaps it helps to free the directory stream buffer.  */
-               (void) __closedir (dirstream);
-               return NULL;
-             }
-           *((char *) __mempcpy (getttyname_name, dev, devlen - 1)) = '/';
-         }
-       memcpy (&getttyname_name[devlen], d->d_name, dlen);
-       if (__xstat64 (_STAT_VER, getttyname_name, &st) == 0
-#ifdef _STATBUF_ST_RDEV
-           && S_ISCHR (st.st_mode) && st.st_rdev == mydev
-#else
-           && d->d_fileno == myino && st.st_dev == mydev
-#endif
-          )
-         {
-           (void) __closedir (dirstream);
-#if 0
-           __ttyname = getttyname_name;
-#endif
-           __set_errno (save);
-           return getttyname_name;
-         }
-      }
-
-  (void) __closedir (dirstream);
-  __set_errno (save);
-  return NULL;
-}
+/* Ben Morrow <address@hidden> 2003-10-22 */
 
+#include <stddef.h>
+#include <limits.h>
+#include <errno.h>
 
-/* Static buffer in `ttyname'.  */
-libc_freeres_ptr (static char *ttyname_buf);
+static char __ttyname_buf[TTY_NAME_MAX];
 
+int __ttyname_r(int fd, char *buf, size_t buflen);
 
-/* Return the pathname of the terminal FD is open on, or NULL on errors.
-   The returned storage is good only until the next call to this function.  */
 char *
-ttyname (int fd)
+__ttyname(int fd)
 {
-  static size_t buflen;
-  char procname[30];
-  struct stat64 st, st1;
-  int dostat = 0;
-  char *name;
-  int save = errno;
-  int len;
-
-  if (!__isatty (fd))
-    return NULL;
+  int rv;
 
-  /* We try using the /proc filesystem.  */
-  *_fitoa_word (fd, __stpcpy (procname, "/proc/self/fd/"), 10, 0) = '\0';
+  rv = __ttyname_r(fd, __ttyname_buf, sizeof(__ttyname_buf));
 
-  if (buflen == 0)
+  if (rv)
     {
-      buflen = 4095;
-      ttyname_buf = (char *) malloc (buflen + 1);
-      if (ttyname_buf == NULL)
-       {
-         buflen = 0;
-         return NULL;
-       }
-    }
-
-  len = __readlink (procname, ttyname_buf, buflen);
-  if (len != -1
-      /* This is for Linux 2.0.  */
-      && ttyname_buf[0] != '[')
-    {
-      if ((size_t) len >= buflen)
-       return NULL;
-      /* readlink need not terminate the string.  */
-      ttyname_buf[len] = '\0';
-      return ttyname_buf;
-    }
-
-  if (__fxstat64 (_STAT_VER, fd, &st) < 0)
-    return NULL;
-
-  if (__xstat64 (_STAT_VER, "/dev/pts", &st1) == 0 && S_ISDIR (st1.st_mode))
-    {
-#ifdef _STATBUF_ST_RDEV
-      name = getttyname ("/dev/pts", st.st_rdev, st.st_ino, save, &dostat);
-#else
-      name = getttyname ("/dev/pts", st.st_dev, st.st_ino, save, &dostat);
-#endif
-    }
-  else
-    {
-      __set_errno (save);
-      name = NULL;
-    }
-
-  if (!name && dostat != -1)
-    {
-#ifdef _STATBUF_ST_RDEV
-      name = getttyname ("/dev", st.st_rdev, st.st_ino, save, &dostat);
-#else
-      name = getttyname ("/dev", st.st_dev, st.st_ino, save, &dostat);
-#endif
-    }
-
-  if (!name && dostat != -1)
-    {
-      dostat = 1;
-#ifdef _STATBUF_ST_RDEV
-      name = getttyname ("/dev", st.st_rdev, st.st_ino, save, &dostat);
-#else
-      name = getttyname ("/dev", st.st_dev, st.st_ino, save, &dostat);
-#endif
+      __set_errno(rv);
+      return NULL;
     }
 
-  return name;
+  return __ttyname_buf;
 }
+
+weak_alias(__ttyname, ttyname);
diff -Naur glibc-2.3.2-orig/sysdeps/unix/sysv/linux/ttyname_r.c 
glibc-2.3.2/sysdeps/unix/sysv/linux/ttyname_r.c
--- glibc-2.3.2-orig/sysdeps/unix/sysv/linux/ttyname_r.c        2003-02-25 
02:05:29.000000000 +0000
+++ glibc-2.3.2/sysdeps/unix/sysv/linux/ttyname_r.c     2003-10-24 
03:56:16.000000000 +0100
@@ -16,6 +16,8 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
+/* Ben Morrow <address@hidden> 2003-10-22 */
+
 #include <errno.h>
 #include <limits.h>
 #include <stddef.h>
@@ -25,174 +27,339 @@
 #include <unistd.h>
 #include <string.h>
 #include <stdlib.h>
+#include <stdio.h>
+#include <sys/sysmacros.h>
 
-#include <stdio-common/_itoa.h>
-
-static int getttyname_r (char *buf, size_t buflen,
-                        dev_t mydev, ino64_t myino, int save,
-                        int *dostat) internal_function;
-
-static int
-internal_function
-getttyname_r (char *buf, size_t buflen, dev_t mydev, ino64_t myino,
-             int save, int *dostat)
-{
-  struct stat64 st;
-  DIR *dirstream;
-  struct dirent64 *d;
-  size_t devlen = strlen (buf);
-
-  dirstream = __opendir (buf);
-  if (dirstream == NULL)
-    {
-      *dostat = -1;
-      return errno;
-    }
+#define DEV_TTY_NUM (256 * 5)
+#define DEV_WALKS { "/dev/vc", "/dev/pts", "/dev/tts", "/dev/usb/tts", \
+                    "/dev/pty", "/dev", NULL }
+/* we want to search the smallest dirs first. /dev is very full on non-devfs 
systems. */
+#define CPP_STR_(x) #x
+#define CPP_STR(x) CPP_STR_(x)
+#define TTYDRV_FMT "%*s %" CPP_STR(TTY_NAME_MAX) "s %d %*s %*s"
+/* for reading /proc/tty/drivers */
+#define STAT_FMT "%*d %*s %*s %*d %*d %*d %d"
+/* for reading /proc/self/stat for our ctty */
+
+/* Finding a name given info about a device:
+ * put ttyname into buf; return 0 for success, error code for failure or
+ * -1 to try next method. Do not change errno; it is saved and restored
+ * around the call, though, so don't worry. Do check that the path you
+ * return is in fact the tty required, using IS_MYTTY below.
+ */
+/* read /proc/tty/drivers */
+static int tty_drivers(char *buf, size_t buflen, dev_t dev, ino64_t ino) 
internal_function;
+/* attempt to guess from the device number */
+static int dev_guess(char *buf, size_t buflen, dev_t dev, ino64_t ino) 
internal_function;
+/* search through the dirs in DEV_WALKS */
+static int walk_dev(char *buf, size_t buflen, dev_t dev, ino64_t ino) 
internal_function;
 
-  while ((d = __readdir64 (dirstream)) != NULL)
-    if ((d->d_fileno == myino || *dostat)
-       && strcmp (d->d_name, "stdin")
-       && strcmp (d->d_name, "stdout")
-       && strcmp (d->d_name, "stderr"))
-      {
-       char *cp;
-       size_t needed = _D_EXACT_NAMLEN (d) + 1;
-
-       if (needed > buflen)
-         {
-           *dostat = -1;
-           (void) __closedir (dirstream);
-           __set_errno (ERANGE);
-           return ERANGE;
-         }
+/* read a symlink */
+static int read_link(char *buf, size_t buflen, const char *name, dev_t dev, 
ino64_t ino) internal_function;
 
-       cp = __stpncpy (buf + devlen, d->d_name, needed);
-       cp[0] = '\0';
+/* Get real dev if we are given /dev/tty. 0 for error. */
+static dev_t self_stat(void) internal_function;
 
-       if (__xstat64 (_STAT_VER, buf, &st) == 0
 #ifdef _STATBUF_ST_RDEV
-           && S_ISCHR (st.st_mode) && st.st_rdev == mydev
+# define ST_RDEV st_rdev
+# define IS_MYTTY(st, dev, ino) (S_ISCHR((st).st_mode) && (st).st_rdev == dev) 
 #else
-           && d->d_fileno == myino && st.st_dev == mydev
+# define ST_RDEV st_dev
+# define IS_MYTTY(st, dev, ino) ((st).st_ino == ino && (st).st_dev == dev)
 #endif
-          )
-         {
-           (void) __closedir (dirstream);
-           __set_errno (save);
-           return 0;
-         }
-      }
 
-  (void) __closedir (dirstream);
-  __set_errno (save);
-  /* It is not clear what to return in this case.  `isatty' says FD
-     refers to a TTY but no entry in /dev has this inode.  */
-  return ENOTTY;
+static int internal_function
+tty_drivers(char *buf, size_t buflen, dev_t dev, ino64_t ino)
+{
+  FILE *ttydrv;
+  char fmt[TTY_NAME_MAX];
+  int maj, ret = 0;
+  struct stat64 ttyst;
+
+  ttydrv = fopen("/proc/tty/drivers", "r");
+  if (!ttydrv)
+    {
+      return -1;
+    }
+
+  while (fscanf(ttydrv, TTYDRV_FMT, fmt, &maj) != EOF)
+    {
+      if (maj == major(dev))
+        {
+      restat:  
+         ret = snprintf(buf, buflen, fmt, minor(dev));
+         if (ret < 0 || ret > buflen)
+           {
+             ret = ERANGE;
+             break;
+           }
+
+         ret = -1;
+       
+         if (!__xstat64(_STAT_VER, buf, &ttyst) && IS_MYTTY(ttyst, dev, ino))
+           {
+             ret = 0;
+              break;
+           }
+         else
+            {
+             if (!strstr(fmt, "%d") && !strchr(fmt + 5, '/'))
+                {
+                 if (!strcmp(fmt, "/dev/pts"))
+                   strcat(fmt, "/%d");
+                 else
+                    strcat(fmt, "%d");
+                  goto restat;
+                }
+            }
+       }
+    }
+
+  fclose(ttydrv);
+  return ret;
 }
 
-/* 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 (int fd, char *buf, size_t buflen)
+static int internal_function
+read_link(char *buf, size_t buflen, const char *name, dev_t dev, ino64_t ino)
 {
-  char procname[30];
-  struct stat64 st, st1;
-  int dostat = 0;
-  int save = errno;
   int ret;
+  struct stat64 st;
 
-  /* Test for the absolute minimal size.  This makes life easier inside
-     the loop.  */
-  if (!buf)
-    {
-      __set_errno (EINVAL);
-      return EINVAL;
-    }
+  ret = __readlink (name, buf, buflen - 1);
 
-  if (buflen < sizeof ("/dev/pts/"))
+  if (ret == -1 && (errno == ENAMETOOLONG || errno == ERANGE))
     {
-      __set_errno (ERANGE);
       return ERANGE;
     }
 
-  /* 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 && errno == ENOENT)
+  if (ret != -1 && buf[0] != '[' && (!ino || /* /proc/self/tty is definitive */
+      (!__xstat64(_STAT_VER, buf, &st) && 
+      IS_MYTTY(st, dev, ino))))
     {
-      __set_errno (EBADF);
-      return EBADF;
+      buf[ret] = 0;
+      return 0;
     }
 
-  if (!__isatty (fd))
-    {
-      __set_errno (ENOTTY);
-      return ENOTTY;
-    }
+  return -1;
+}
 
-  if (ret == -1 && errno == ENAMETOOLONG)
-    {
-      __set_errno (ERANGE);
-      return ERANGE;
-    }
+/* 
+ * This function is a slightly modified version of 
+ * proc/devname.c:guess_name from procps-3.1.9
+ * by Albert Cahalan.
+ * That file is distributed under the LGPL.
+ *
+ * This function fails for devfs names; however, we try this after
+ * we try /proc/tty/drivers so we will only fail for (devfs &&
+ * no old names && /proc not mounted) which is pretty unlikely.
+ */
+static int internal_function
+dev_guess(char *buf, size_t buflen, dev_t dev, ino64_t ino)
+{
+  int maj, min, tmpmin, rvi;
+  char t0, t1;
+  struct stat64 sbuf;
+  
+  maj = major(dev);
+  min = minor(dev);
+  tmpmin = min;
+
+  switch(maj){
+  case   4:
+    if(min<64){
+      rvi = snprintf(buf, buflen, "/dev/tty%d", min);
+      break;
+    }
+    if(min<128){  /* to 255 on newer systems */
+      rvi = snprintf(buf, buflen, "/dev/ttyS%d", min-64);
+      break;
+    }
+    tmpmin = min & 0x3f;  /* FALL THROUGH */
+  case   3:      /* /dev/[pt]ty[p-za-o][0-9a-z] is 936 */
+    t0 = "pqrstuvwxyzabcde"[tmpmin>>4];
+    t1 = "0123456789abcdef"[tmpmin&0x0f];
+    rvi = snprintf(buf, buflen, "/dev/tty%c%c", t0, t1);
+    break;
+  case  17:  rvi = snprintf(buf, buflen, "/dev/ttyH%d",  min); break;
+  case  19:  rvi = snprintf(buf, buflen, "/dev/ttyC%d",  min); break;
+  case  22:  rvi = snprintf(buf, buflen, "/dev/ttyD%d",  min); break; /* 
devices.txt */
+  case  23:  rvi = snprintf(buf, buflen, "/dev/ttyD%d",  min); break; /* 
driver code */
+  case  24:  rvi = snprintf(buf, buflen, "/dev/ttyE%d",  min); break;
+  case  32:  rvi = snprintf(buf, buflen, "/dev/ttyX%d",  min); break;
+  case  43:  rvi = snprintf(buf, buflen, "/dev/ttyI%d",  min); break;
+  case  46:  rvi = snprintf(buf, buflen, "/dev/ttyR%d",  min); break;
+  case  48:  rvi = snprintf(buf, buflen, "/dev/ttyL%d",  min); break;
+  case  57:  rvi = snprintf(buf, buflen, "/dev/ttyP%d",  min); break;
+  case  71:  rvi = snprintf(buf, buflen, "/dev/ttyF%d",  min); break;
+  case  75:  rvi = snprintf(buf, buflen, "/dev/ttyW%d",  min); break;
+  case  78:  rvi = snprintf(buf, buflen, "/dev/ttyM%d",  min); break; /* 
conflict */
+  case 105:  rvi = snprintf(buf, buflen, "/dev/ttyV%d",  min); break;
+  case 112:  rvi = snprintf(buf, buflen, "/dev/ttyM%d",  min); break; /* 
conflict */
+  /* 136 ... 143 are /dev/pts/0, /dev/pts/1, /dev/pts/2 ... */
+  case 136 ... 143:  rvi = snprintf(buf, buflen, "/dev/pts/%d",  
min+(maj-136)*256); break;
+  case 148:  rvi = snprintf(buf, buflen, "/dev/ttyT%d",  min); break;
+  case 154:  rvi = snprintf(buf, buflen, "/dev/ttySR%d", min); break;
+  case 156:  rvi = snprintf(buf, buflen, "/dev/ttySR%d", min+256); break;
+  case 164:  rvi = snprintf(buf, buflen, "/dev/ttyCH%d",  min); break;
+  case 166:  rvi = snprintf(buf, buflen, "/dev/ttyACM%d", min); break; /* 
bummer, 9-char */
+  case 172:  rvi = snprintf(buf, buflen, "/dev/ttyMX%d",  min); break;
+  case 174:  rvi = snprintf(buf, buflen, "/dev/ttySI%d",  min); break;
+  case 188:  rvi = snprintf(buf, buflen, "/dev/ttyUSB%d", min); break; /* 
bummer, 9-char */
+  default: return -1;
+  }
 
-  if (ret != -1 && buf[0] != '[')
-    {
-      buf[ret] = '\0';
-      return 0;
-    }
+  if (rvi < 0 || rvi > buflen)
+    return ERANGE;
 
-  if (__fxstat64 (_STAT_VER, fd, &st) < 0)
-    return errno;
+  if (!__xstat64(_STAT_VER, buf, &sbuf) && IS_MYTTY(sbuf, dev, ino))
+    return 0;
 
-  /* Prepare the result buffer.  */
-  memcpy (buf, "/dev/pts/", sizeof ("/dev/pts/"));
-  buflen -= sizeof ("/dev/pts/") - 1;
+  return -1;
+}
 
-  if (__xstat64 (_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
+static int internal_function
+walk_dev(char *buf, size_t buflen, dev_t dev, ino64_t ino)
+{
+  struct stat64 st;
+  DIR *dirstream;
+  struct dirent64 *d;
+  const char *walks[] = DEV_WALKS, **i;
+  int ret;
+
+  for(i = walks; *i; i++)
     {
-      __set_errno (save);
-      ret = ENOENT;
+      dirstream = __opendir (*i);
+      if (dirstream == NULL)
+        continue; 
+
+/* this fails if we are under chroot and our tty was opened before the chroot:
+ * the correct dev file will now have a different ino.
+ */
+      while ((d = __readdir64 (dirstream)) != NULL)
+        if ((!ino || d->d_fileno == ino) /* if we are looking for a real
+                                         * device for /dev/tty we have to
+                                         * stat every entry in /dev:
+                                         * too bad :(.
+                                         */
+            && strcmp (d->d_name, "stdin")
+            && strcmp (d->d_name, "stdout")
+            && strcmp (d->d_name, "stderr"))
+          {
+            ret = snprintf(buf, buflen, "%s/%s", *i, d->d_name);
+            if (ret < 0 || ret >= buflen)
+              {
+               ret = ERANGE;
+               goto out;
+              }
+
+           ret = -1;
+
+            if (!__xstat64 (_STAT_VER, buf, &st) && IS_MYTTY(st, dev, ino))
+              {
+               ret = 0;
+               goto out;
+              }
+          }
+
+      (void) __closedir(dirstream);
     }
 
-  if (ret && dostat != -1)
+  return -1;
+
+out:
+  (void) __closedir (dirstream);
+  return ret;
+}
+
+static dev_t internal_function
+self_stat(void)
+{
+  FILE *fp;
+  int tty = 0;
+
+  fp = fopen("/proc/self/stat", "r");
+  if (!fp)
+    return 0;
+
+  if (fscanf(fp, STAT_FMT, &tty) == EOF)
+    tty = 0;
+
+  fclose(fp);
+  return tty;
+}
+
+int
+__ttyname_r (int fd, char *buf, size_t buflen)
+{
+  char linkname[sizeof("/proc/self/fd/12345678")];
+  struct stat64 st;
+  dev_t dev;
+  ino64_t ino;
+  int ret, errno_save;
+
+  errno_save = errno;
+
+  ret = EINVAL;
+  if (!buf) goto out;
+
+  ret = ENOTTY;
+  if (!__isatty(fd)) goto out;
+
+  ret = __fxstat64(_STAT_VER, fd, &st);
+  if (ret) 
     {
-      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,
-                         &dostat);
-#endif
+      ret = errno;
+      goto out;
     }
 
-  if (ret && dostat != -1)
+  dev = st.ST_RDEV;
+  ino = st.st_ino;
+
+  if (dev == DEV_TTY_NUM)
     {
-      buf[sizeof ("/dev/") - 1] = '\0';
-      dostat = 1;
+      ino = 0;
+      ret = read_link(buf, buflen, "/proc/self/tty", dev, ino);
+      if (ret >= 0) goto out;
+
 #ifdef _STATBUF_ST_RDEV
-      ret = getttyname_r (buf, buflen, st.st_rdev, st.st_ino,
-                         save, &dostat);
+      dev = self_stat();
 #else
-      ret = getttyname_r (buf, buflen, st.st_dev, st.st_ino,
-                         save, &dostat);
+      dev = 0;
+      /* /proc/self/stat won't give us the ino */
 #endif
+      if (!dev)
+        {
+          ret = 0;
+          /* yes, it's pretty useless, but it's the best we can do */
+          if (buflen < sizeof("/dev/tty"))
+            ret = ERANGE;
+          else
+            strncpy(buf, "/dev/tty", buflen);
+      
+          goto out;
+        }
+    }
+      
+
+  ret = tty_drivers(buf, buflen, dev, ino);
+  if(ret >= 0) goto out;
+
+  ret = dev_guess(buf, buflen, dev, ino);
+  if (ret >= 0) goto out;
+
+  if (ino)
+    {
+      sprintf(linkname, "/proc/self/fd/%d", fd);
+      ret = read_link(buf, buflen, linkname, dev, ino);
+      if (ret >=0 ) goto out;
     }
 
+  ret = walk_dev(buf, buflen, dev, ino);
+  if (ret < 0) ret = ENOENT;
+
+out:
+  __set_errno(errno_save);
   return ret;
 }
 
-weak_alias (__ttyname_r, ttyname_r)
+weak_alias (__ttyname_r, ttyname_r);

---END DIFF---

-- 
Musica Dei donum optimi, trahit homines, trahit deos.    |
Musica truces molit animos, tristesque mentes erigit.    |   address@hidden
Musica vel ipsas arbores et horridas movet feras.        |




reply via email to

[Prev in Thread] Current Thread [Next in Thread]