Fix Solaris problems with ttyname_r.
[gpgme.git] / src / ttyname_r.c
index 810c2175c4ae43f13ae727e9accfe3510a1eca0a..105e0af5eb2c59cedaaafadf4441da312d6b3326 100644 (file)
@@ -1,22 +1,21 @@
 /* ttyname_r.c - A ttyname_r() replacement.
-   Copyright (C) 2003, 2004 g10 Code GmbH
+   Copyright (C) 2003, 2004, 2012 g10 Code GmbH
 
    This file is part of GPGME.
+
    GPGME is free software; you can redistribute it and/or modify it
    under the terms of the GNU Lesser General Public License as
    published by the Free Software Foundation; either version 2.1 of
    the License, or (at your option) any later version.
-   
+
    GPGME is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.
-   
+
    You should have received a copy of the GNU Lesser General Public
-   License along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA.  */
+   License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
 
 #if HAVE_CONFIG_H
 #include <config.h>
 #endif
 
 \f
-#ifdef __GNUC__
+#if !HAVE_TTYNAME_R && defined(__GNUC__)
 # warning ttyname is not thread-safe, and ttyname_r is missing
 #endif
 
 int
-ttyname_r (int fd, char *buf, size_t buflen)
+_gpgme_ttyname_r (int fd, char *buf, size_t buflen)
 {
+#if HAVE_TTYNAME_R
+# if HAVE_BROKEN_TTYNAME_R
+   /* Solaris fails if BUFLEN is less than 128. OSF/1 5.1 completely
+      ignores BUFLEN.  We use a large buffer to woraround this.  */
+  {
+    char largebuf[512];
+    size_t namelen;
+    int rc;
+
+#  if HAVE_POSIXDECL_TTYNAME_R
+    if (buflen < sizeof (largebuf))
+      {
+        rc = ttyname_r (fd, largebuf, (int)sizeof (largebuf));
+        if (!rc)
+          {
+            namelen = strlen (largebuf) + 1;
+            if (namelen > buflen)
+              rc = ERANGE;
+            else
+              memcpy (buf, largebuf, namelen);
+          }
+      }
+    else
+      rc = ttyname_r (fd, buf, (int)buflen);
+
+#  else /*!HAVE_POSIXDECL_TTYNAME_R*/
+    char *name;
+
+    if (buflen < sizeof (largebuf))
+      name = ttyname_r (fd, largebuf, (int)sizeof (largebuf));
+    else
+      name = ttyname_r (fd, buf, (int)buflen);
+    rc = name? 0 : (errno? errno : -1);
+    if (!rc && buf != name)
+      {
+        namelen = strlen (name) + 1;
+        if (namelen > buflen)
+          rc = ERANGE;
+        else
+          memmove (buf, name, namelen);
+      }
+#  endif
+
+    return rc;
+  }
+# else /*!HAVE_BROKEN_TTYNAME_R*/
+  {
+    int rc;
+
+#  if HAVE_POSIXDECL_TTYNAME_R
+
+    rc = ttyname_r (fd, buf, buflen);
+
+#  else /*!HAVE_POSIXDECL_TTYNAME_R*/
+    char *name;
+    size_t namelen;
+
+    name = ttyname_r (fd, buf, (int)buflen);
+    rc = name? 0 : (errno? errno : -1);
+    if (!rc && buf != name)
+      {
+        namelen = strlen (name) + 1;
+        if (namelen > buflen)
+          rc = ERANGE;
+        else
+          memmove (buf, name, namelen);
+      }
+#  endif
+
+    return rc;
+  }
+# endif /*!HAVE_BROKEN_TTYNAME_R*/
+#else /*!HAVE_TTYNAME_R*/
   char *tty;
 
-#if HAVE_W32_SYSTEM
+# if HAVE_W32_SYSTEM
   /* We use this default one for now.  AFAICS we only need it to be
      passed to gpg and in turn to pinentry.  Providing a replacement
      is needed because elsewhere we bail out on error.  If we
-     eventually implement a pinentry for Windows it is uinlikely that
+     eventually implement a pinentry for Windows it is inlikely that
      we need a real tty at all.  */
-  tty = "/dev/tty"; 
-#else
+  tty = "/dev/tty";
+# else
   tty = ttyname (fd);
   if (!tty)
-    return errno;
-#endif
-  
+    return errno? errno : -1;
+# endif
+
   strncpy (buf, tty, buflen);
   buf[buflen - 1] = '\0';
   return (strlen (tty) >= buflen) ? ERANGE : 0;
+#endif /*!HAVE_TTYNAME_R*/
 }