1 /* Determine name of a terminal.
2 
3    Copyright (C) 2010-2021 Free Software Foundation, Inc.
4 
5    This file is free software: you can redistribute it and/or modify
6    it under the terms of the GNU Lesser General Public License as
7    published by the Free Software Foundation; either version 2.1 of the
8    License, or (at your option) any later version.
9 
10    This file is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public License
16    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
17 
18 /* Written by Bruno Haible <bruno@clisp.org>, 2010.  */
19 
20 #include <config.h>
21 
22 #include <unistd.h>
23 
24 #include <errno.h>
25 #include <limits.h>
26 #include <string.h>
27 #if defined __ANDROID__
28 # include <stdio.h>
29 #endif
30 
31 int
ttyname_r(int fd,char * buf,size_t buflen)32 ttyname_r (int fd, char *buf, size_t buflen)
33 #undef ttyname_r
34 {
35 #if defined __ANDROID__
36   /* On Android, read the result from the /proc file system.  */
37   if (!isatty (fd))
38     /* We rely on isatty to set errno properly (i.e. EBADF or ENOTTY).  */
39     return errno;
40   else if (buflen == 0)
41     return ERANGE;
42   else
43     {
44       char procfile[14+11+1];
45       char largerbuf[512];
46       ssize_t ret;
47       sprintf (procfile, "/proc/self/fd/%d", fd);
48       ret = (buflen < sizeof (largerbuf)
49              ? readlink (procfile, largerbuf, sizeof (largerbuf))
50              : readlink (procfile, buf, buflen <= INT_MAX ? buflen : INT_MAX));
51       if (ret < 0)
52         return errno;
53       if ((size_t) ret >= buflen)
54         return ERANGE;
55       if (buflen < sizeof (largerbuf))
56         memcpy (buf, largerbuf, (size_t) ret);
57       buf[(size_t) ret] = '\0';
58       return 0;
59     }
60 #elif HAVE_TTYNAME_R
61   /* When ttyname_r exists, use it.  */
62   /* This code is multithread-safe.  */
63   /* On Solaris, ttyname_r always fails if buflen < 128.  On OSF/1 5.1,
64      ttyname_r ignores the buffer size and assumes the buffer is large enough.
65      So provide a buffer that is large enough.  */
66   char largerbuf[512];
67 # if HAVE_POSIXDECL_TTYNAME_R
68   int err =
69     (buflen < sizeof (largerbuf)
70      ? ttyname_r (fd, largerbuf, sizeof (largerbuf))
71      : ttyname_r (fd, buf, buflen <= INT_MAX ? buflen : INT_MAX));
72   if (err != 0)
73     return err;
74   if (buflen < sizeof (largerbuf))
75     {
76       size_t namelen = strlen (largerbuf) + 1;
77       if (namelen > buflen)
78         return ERANGE;
79       memcpy (buf, largerbuf, namelen);
80     }
81 # else
82   char *name =
83     (buflen < sizeof (largerbuf)
84      ? ttyname_r (fd, largerbuf, sizeof (largerbuf))
85      : ttyname_r (fd, buf, buflen <= INT_MAX ? buflen : INT_MAX));
86   if (name == NULL)
87     return errno;
88   if (name != buf)
89     {
90       size_t namelen = strlen (name) + 1;
91       if (namelen > buflen)
92         return ERANGE;
93       memmove (buf, name, namelen);
94     }
95 # endif
96   return 0;
97 #elif HAVE_TTYNAME
98   /* Note: This is not multithread-safe.  */
99   char *name;
100   size_t namelen;
101 
102   name = ttyname (fd);
103   if (name == NULL)
104     return errno;
105   namelen = strlen (name) + 1;
106   if (namelen > buflen)
107     return ERANGE;
108   memcpy (buf, name, namelen);
109   return 0;
110 #else
111   /* Platforms like mingw: no ttys exist at all.  */
112   return ENOTTY;
113 #endif
114 }
115