Back to index

glibc  2.9
ttyname.c
Go to the documentation of this file.
00001 /* Copyright (C) 1991,92,93,1996-2002,2006 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003 
00004    The GNU C Library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Lesser General Public
00006    License as published by the Free Software Foundation; either
00007    version 2.1 of the License, or (at your option) any later version.
00008 
00009    The GNU C Library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Lesser General Public License for more details.
00013 
00014    You should have received a copy of the GNU Lesser General Public
00015    License along with the GNU C Library; if not, write to the Free
00016    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00017    02111-1307 USA.  */
00018 
00019 #include <errno.h>
00020 #include <limits.h>
00021 #include <stddef.h>
00022 #include <dirent.h>
00023 #include <sys/types.h>
00024 #include <sys/stat.h>
00025 #include <termios.h>
00026 #include <unistd.h>
00027 #include <string.h>
00028 #include <stdlib.h>
00029 
00030 #include <stdio-common/_itoa.h>
00031 #include <kernel-features.h>
00032 
00033 #if 0
00034 /* Is this used anywhere?  It is not exported.  */
00035 char *__ttyname;
00036 #endif
00037 
00038 static char *getttyname (const char *dev, dev_t mydev,
00039                       ino64_t myino, int save, int *dostat)
00040      internal_function;
00041 
00042 
00043 libc_freeres_ptr (static char *getttyname_name);
00044 
00045 static char *
00046 internal_function attribute_compat_text_section
00047 getttyname (const char *dev, dev_t mydev, ino64_t myino, int save, int *dostat)
00048 {
00049   static size_t namelen;
00050   struct stat64 st;
00051   DIR *dirstream;
00052   struct dirent64 *d;
00053   size_t devlen = strlen (dev) + 1;
00054 
00055   dirstream = __opendir (dev);
00056   if (dirstream == NULL)
00057     {
00058       *dostat = -1;
00059       return NULL;
00060     }
00061 
00062   while ((d = __readdir64 (dirstream)) != NULL)
00063     if ((d->d_fileno == myino || *dostat)
00064        && strcmp (d->d_name, "stdin")
00065        && strcmp (d->d_name, "stdout")
00066        && strcmp (d->d_name, "stderr"))
00067       {
00068        size_t dlen = _D_ALLOC_NAMLEN (d);
00069        if (devlen + dlen > namelen)
00070          {
00071            free (getttyname_name);
00072            namelen = 2 * (devlen + dlen); /* Big enough.  */
00073            getttyname_name = malloc (namelen);
00074            if (! getttyname_name)
00075              {
00076               *dostat = -1;
00077               /* Perhaps it helps to free the directory stream buffer.  */
00078               (void) __closedir (dirstream);
00079               return NULL;
00080              }
00081            *((char *) __mempcpy (getttyname_name, dev, devlen - 1)) = '/';
00082          }
00083        memcpy (&getttyname_name[devlen], d->d_name, dlen);
00084        if (__xstat64 (_STAT_VER, getttyname_name, &st) == 0
00085 #ifdef _STATBUF_ST_RDEV
00086            && S_ISCHR (st.st_mode) && st.st_rdev == mydev
00087 #else
00088            && d->d_fileno == myino && st.st_dev == mydev
00089 #endif
00090           )
00091          {
00092            (void) __closedir (dirstream);
00093 #if 0
00094            __ttyname = getttyname_name;
00095 #endif
00096            __set_errno (save);
00097            return getttyname_name;
00098          }
00099       }
00100 
00101   (void) __closedir (dirstream);
00102   __set_errno (save);
00103   return NULL;
00104 }
00105 
00106 
00107 /* Static buffer in `ttyname'.  */
00108 libc_freeres_ptr (static char *ttyname_buf);
00109 
00110 
00111 /* Return the pathname of the terminal FD is open on, or NULL on errors.
00112    The returned storage is good only until the next call to this function.  */
00113 char *
00114 ttyname (int fd)
00115 {
00116   static size_t buflen;
00117   char procname[30];
00118   struct stat64 st, st1;
00119   int dostat = 0;
00120   char *name;
00121   int save = errno;
00122   struct termios term;
00123 
00124   /* isatty check, tcgetattr is used because it sets the correct
00125      errno (EBADF resp. ENOTTY) on error.  */
00126   if (__builtin_expect (__tcgetattr (fd, &term) < 0, 0))
00127     return NULL;
00128 
00129   /* We try using the /proc filesystem.  */
00130   *_fitoa_word (fd, __stpcpy (procname, "/proc/self/fd/"), 10, 0) = '\0';
00131 
00132   if (buflen == 0)
00133     {
00134       buflen = 4095;
00135       ttyname_buf = (char *) malloc (buflen + 1);
00136       if (ttyname_buf == NULL)
00137        {
00138          buflen = 0;
00139          return NULL;
00140        }
00141     }
00142 
00143   ssize_t len = __readlink (procname, ttyname_buf, buflen);
00144   if (__builtin_expect (len == -1 && errno == ENOENT, 0))
00145     {
00146       __set_errno (EBADF);
00147       return NULL;
00148     }
00149 
00150   if (__builtin_expect (len != -1
00151 #ifndef __ASSUME_PROC_SELF_FD_SYMLINK
00152                      /* This is for Linux 2.0.  */
00153                      && ttyname_buf[0] != '['
00154 #endif
00155                      , 1))
00156     {
00157       if ((size_t) len >= buflen)
00158        return NULL;
00159       /* readlink need not terminate the string.  */
00160       ttyname_buf[len] = '\0';
00161       return ttyname_buf;
00162     }
00163 
00164   if (__fxstat64 (_STAT_VER, fd, &st) < 0)
00165     return NULL;
00166 
00167   if (__xstat64 (_STAT_VER, "/dev/pts", &st1) == 0 && S_ISDIR (st1.st_mode))
00168     {
00169 #ifdef _STATBUF_ST_RDEV
00170       name = getttyname ("/dev/pts", st.st_rdev, st.st_ino, save, &dostat);
00171 #else
00172       name = getttyname ("/dev/pts", st.st_dev, st.st_ino, save, &dostat);
00173 #endif
00174     }
00175   else
00176     {
00177       __set_errno (save);
00178       name = NULL;
00179     }
00180 
00181   if (!name && dostat != -1)
00182     {
00183 #ifdef _STATBUF_ST_RDEV
00184       name = getttyname ("/dev", st.st_rdev, st.st_ino, save, &dostat);
00185 #else
00186       name = getttyname ("/dev", st.st_dev, st.st_ino, save, &dostat);
00187 #endif
00188     }
00189 
00190   if (!name && dostat != -1)
00191     {
00192       dostat = 1;
00193 #ifdef _STATBUF_ST_RDEV
00194       name = getttyname ("/dev", st.st_rdev, st.st_ino, save, &dostat);
00195 #else
00196       name = getttyname ("/dev", st.st_dev, st.st_ino, save, &dostat);
00197 #endif
00198     }
00199 
00200   return name;
00201 }