gpgme-tool: Use membuf functions to build up strings.
[gpgme.git] / src / ttyname_r.c
1 /* ttyname_r.c - A ttyname_r() replacement.
2    Copyright (C) 2003, 2004, 2012 g10 Code GmbH
3
4    This file is part of GPGME.
5
6    GPGME is free software; you can redistribute it and/or modify it
7    under the terms of the GNU Lesser General Public License as
8    published by the Free Software Foundation; either version 2.1 of
9    the License, or (at your option) any later version.
10
11    GPGME is distributed in the hope that it will be useful, but
12    WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #if HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 #include <stdlib.h>
24 #include <errno.h>
25 #include <string.h>
26 #ifdef HAVE_UNISTD_H
27 # include <unistd.h>
28 #endif
29
30 \f
31 #if !HAVE_TTYNAME_R && defined(__GNUC__)
32 # warning ttyname is not thread-safe, and ttyname_r is missing
33 #endif
34
35 int
36 _gpgme_ttyname_r (int fd, char *buf, size_t buflen)
37 {
38 #if HAVE_TTYNAME_R
39 # if HAVE_BROKEN_TTYNAME_R
40    /* Solaris fails if BUFLEN is less than 128. OSF/1 5.1 completely
41       ignores BUFLEN.  We use a large buffer to woraround this.  */
42   {
43     char largebuf[512];
44     size_t namelen;
45     int rc;
46
47 #  if HAVE_POSIXDECL_TTYNAME_R
48     if (buflen < sizeof (largebuf))
49       {
50         rc = ttyname_r (fd, largebuf, (int)sizeof (largebuf));
51         if (!rc)
52           {
53             namelen = strlen (largebuf) + 1;
54             if (namelen > buflen)
55               rc = ERANGE;
56             else
57               memcpy (buf, largebuf, namelen);
58           }
59       }
60     else
61       rc = ttyname_r (fd, buf, (int)buflen);
62
63 #  else /*!HAVE_POSIXDECL_TTYNAME_R*/
64     char *name;
65
66     if (buflen < sizeof (largebuf))
67       name = ttyname_r (fd, largebuf, (int)sizeof (largebuf));
68     else
69       name = ttyname_r (fd, buf, (int)buflen);
70     rc = name? 0 : (errno? errno : -1);
71     if (!rc && buf != name)
72       {
73         namelen = strlen (name) + 1;
74         if (namelen > buflen)
75           rc = ERANGE;
76         else
77           memmove (buf, name, namelen);
78       }
79 #  endif
80
81     return rc;
82   }
83 # else /*!HAVE_BROKEN_TTYNAME_R*/
84   {
85     int rc;
86
87 #  if HAVE_POSIXDECL_TTYNAME_R
88
89     rc = ttyname_r (fd, buf, buflen);
90
91 #  else /*!HAVE_POSIXDECL_TTYNAME_R*/
92     char *name;
93     size_t namelen;
94
95     name = ttyname_r (fd, buf, (int)buflen);
96     rc = name? 0 : (errno? errno : -1);
97     if (!rc && buf != name)
98       {
99         namelen = strlen (name) + 1;
100         if (namelen > buflen)
101           rc = ERANGE;
102         else
103           memmove (buf, name, namelen);
104       }
105 #  endif
106
107     return rc;
108   }
109 # endif /*!HAVE_BROKEN_TTYNAME_R*/
110 #else /*!HAVE_TTYNAME_R*/
111   char *tty;
112
113 # if HAVE_W32_SYSTEM
114   /* We use this default one for now.  AFAICS we only need it to be
115      passed to gpg and in turn to pinentry.  Providing a replacement
116      is needed because elsewhere we bail out on error.  If we
117      eventually implement a pinentry for Windows it is inlikely that
118      we need a real tty at all.  */
119   tty = "/dev/tty";
120 # else
121   tty = ttyname (fd);
122   if (!tty)
123     return errno? errno : -1;
124 # endif
125
126   strncpy (buf, tty, buflen);
127   buf[buflen - 1] = '\0';
128   return (strlen (tty) >= buflen) ? ERANGE : 0;
129 #endif /*!HAVE_TTYNAME_R*/
130 }