(root)/
glibc-2.38/
sysdeps/
posix/
ttyname.c
       1  /* Copyright (C) 1991-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <errno.h>
      19  #include <limits.h>
      20  #include <stddef.h>
      21  #include <dirent.h>
      22  #include <sys/types.h>
      23  #include <sys/stat.h>
      24  #include <unistd.h>
      25  #include <string.h>
      26  #include <stdlib.h>
      27  #include <set-freeres.h>
      28  
      29  char *__ttyname;
      30  
      31  static char *getttyname (int fd, dev_t mydev, ino_t myino,
      32  			 int save, int *dostat);
      33  
      34  
      35  static char *getttyname_name;
      36  weak_alias (getttyname_name, __ttyname_freemem_ptr)
      37  
      38  static char *
      39  getttyname (int fd, dev_t mydev, ino_t myino, int save, int *dostat)
      40  {
      41    static const char dev[] = "/dev";
      42    static size_t namelen;
      43    struct stat st;
      44    DIR *dirstream;
      45    struct dirent *d;
      46  
      47    dirstream = __opendir (dev);
      48    if (dirstream == NULL)
      49      {
      50        *dostat = -1;
      51        return NULL;
      52      }
      53  
      54    while ((d = __readdir (dirstream)) != NULL)
      55      if (((ino_t) d->d_fileno == myino || *dostat)
      56  	&& strcmp (d->d_name, "stdin")
      57  	&& strcmp (d->d_name, "stdout")
      58  	&& strcmp (d->d_name, "stderr"))
      59        {
      60  	size_t dlen = _D_ALLOC_NAMLEN (d);
      61  	if (sizeof (dev) + dlen > namelen)
      62  	  {
      63  	    free (getttyname_name);
      64  	    namelen = 2 * (sizeof (dev) + dlen); /* Big enough.  */
      65  	    getttyname_name = malloc (namelen);
      66  	    if (! getttyname_name)
      67  	      {
      68  		*dostat = -1;
      69  		/* Perhaps it helps to free the directory stream buffer.  */
      70  		(void) __closedir (dirstream);
      71  		return NULL;
      72  	      }
      73  	    *((char *) __mempcpy (getttyname_name, dev, sizeof (dev) - 1))
      74  	      = '/';
      75  	  }
      76  	(void) __mempcpy (&getttyname_name[sizeof (dev)], d->d_name, dlen);
      77  	if (stat (getttyname_name, &st) == 0
      78  #ifdef _STATBUF_ST_RDEV
      79  	    && S_ISCHR (st.st_mode) && st.st_rdev == mydev
      80  #else
      81  	    && (ino_t) d->d_fileno == myino && st.st_dev == mydev
      82  #endif
      83  	   )
      84  	  {
      85  	    (void) __closedir (dirstream);
      86  	    __ttyname = getttyname_name;
      87  	    __set_errno (save);
      88  	    return getttyname_name;
      89  	  }
      90        }
      91  
      92    (void) __closedir (dirstream);
      93    __set_errno (save);
      94    return NULL;
      95  }
      96  
      97  /* Return the pathname of the terminal FD is open on, or NULL on errors.
      98     The returned storage is good only until the next call to this function.  */
      99  char *
     100  ttyname (int fd)
     101  {
     102    struct stat st;
     103    int dostat = 0;
     104    char *name;
     105    int save = errno;
     106  
     107    if (!__isatty (fd))
     108      return NULL;
     109  
     110    if (fstat (fd, &st) < 0)
     111      return NULL;
     112  
     113  #ifdef _STATBUF_ST_RDEV
     114    name = getttyname (fd, st.st_rdev, st.st_ino, save, &dostat);
     115  #else
     116    name = getttyname (fd, st.st_dev, st.st_ino, save, &dostat);
     117  #endif
     118  
     119    if (!name && dostat != -1)
     120      {
     121        dostat = 1;
     122  #ifdef _STATBUF_ST_RDEV
     123        name = getttyname (fd, st.st_rdev, st.st_ino, save, &dostat);
     124  #else
     125        name = getttyname (fd, st.st_dev, st.st_ino, save, &dostat);
     126  #endif
     127      }
     128  
     129    return name;
     130  }