exp2l: Work around a NetBSD 10.0/i386 bug.
[gnulib.git] / lib / ttyname_r.c
blob507bc2d654780f2ceee1c25522a937527349deec
1 /* Determine name of a terminal.
3 Copyright (C) 2010-2024 Free Software Foundation, Inc.
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.
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.
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/>. */
18 /* Written by Bruno Haible <bruno@clisp.org>, 2010. */
20 #include <config.h>
22 #include <unistd.h>
24 #include <errno.h>
25 #include <limits.h>
26 #include <string.h>
27 #if defined __ANDROID__
28 # include <stdio.h>
29 #endif
31 int
32 ttyname_r (int fd, char *buf, size_t buflen)
33 #undef ttyname_r
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
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;
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))
76 size_t namelen = strlen (largerbuf) + 1;
77 if (namelen > buflen)
78 return ERANGE;
79 memcpy (buf, largerbuf, namelen);
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)
90 size_t namelen = strlen (name) + 1;
91 if (namelen > buflen)
92 return ERANGE;
93 memmove (buf, name, namelen);
95 # endif
96 return 0;
97 #elif HAVE_TTYNAME
98 /* Note: This is not multithread-safe. */
99 char *name;
100 size_t namelen;
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