getprogname: Work around program name truncation when possible.
[gnulib.git] / lib / ttyname_r.c
blobc6364aeacaf68f22a553489b9179b73f3d5c2f32
1 /* Determine name of a terminal.
3 Copyright (C) 2010-2018 Free Software Foundation, Inc.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program 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 General Public License for more details.
15 You should have received a copy of the GNU 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>
28 int
29 ttyname_r (int fd, char *buf, size_t buflen)
30 #undef ttyname_r
32 /* When ttyname_r exists, use it. */
33 #if HAVE_TTYNAME_R
34 /* This code is multithread-safe. */
35 /* On Solaris, ttyname_r always fails if buflen < 128. On OSF/1 5.1,
36 ttyname_r ignores the buffer size and assumes the buffer is large enough.
37 So provide a buffer that is large enough. */
38 char largerbuf[512];
39 # if HAVE_POSIXDECL_TTYNAME_R
40 int err =
41 (buflen < sizeof (largerbuf)
42 ? ttyname_r (fd, largerbuf, sizeof (largerbuf))
43 : ttyname_r (fd, buf, buflen <= INT_MAX ? buflen : INT_MAX));
44 if (err != 0)
45 return err;
46 if (buflen < sizeof (largerbuf))
48 size_t namelen = strlen (largerbuf) + 1;
49 if (namelen > buflen)
50 return ERANGE;
51 memcpy (buf, largerbuf, namelen);
53 # else
54 char *name =
55 (buflen < sizeof (largerbuf)
56 ? ttyname_r (fd, largerbuf, sizeof (largerbuf))
57 : ttyname_r (fd, buf, buflen <= INT_MAX ? buflen : INT_MAX));
58 if (name == NULL)
59 return errno;
60 if (name != buf)
62 size_t namelen = strlen (name) + 1;
63 if (namelen > buflen)
64 return ERANGE;
65 memmove (buf, name, namelen);
67 # endif
68 return 0;
69 #elif HAVE_TTYNAME
70 /* Note: This is not multithread-safe. */
71 char *name;
72 size_t namelen;
74 name = ttyname (fd);
75 if (name == NULL)
76 return errno;
77 namelen = strlen (name) + 1;
78 if (namelen > buflen)
79 return ERANGE;
80 memcpy (buf, name, namelen);
81 return 0;
82 #else
83 /* Platforms like mingw: no ttys exist at all. */
84 return ENOTTY;
85 #endif