md5, sha1, sha256, sha512: add gl_SET_CRYPTO_CHECK_DEFAULT
[gnulib.git] / lib / ttyname_r.c
index dc8b923..2689b26 100644 (file)
@@ -1,6 +1,6 @@
 /* Determine name of a terminal.
 
-   Copyright (C) 2010 Free Software Foundation, Inc.
+   Copyright (C) 2010-2013 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 #include <unistd.h>
 
 #include <errno.h>
+#include <limits.h>
 #include <string.h>
 
 int
 ttyname_r (int fd, char *buf, size_t buflen)
+#undef ttyname_r
 {
-#if HAVE_TTYNAME
+  /* When ttyname_r exists, use it.  */
+#if HAVE_TTYNAME_R
+  /* This code is multithread-safe.  */
+  /* On Solaris, ttyname_r always fails if buflen < 128.  On OSF/1 5.1,
+     ttyname_r ignores the buffer size and assumes the buffer is large enough.
+     So provide a buffer that is large enough.  */
+  char largerbuf[512];
+# if HAVE_POSIXDECL_TTYNAME_R
+  int err =
+    (buflen < sizeof (largerbuf)
+     ? ttyname_r (fd, largerbuf, sizeof (largerbuf))
+     : ttyname_r (fd, buf, buflen <= INT_MAX ? buflen : INT_MAX));
+  if (err != 0)
+    return err;
+  if (buflen < sizeof (largerbuf))
+    {
+      size_t namelen = strlen (largerbuf) + 1;
+      if (namelen > buflen)
+        return ERANGE;
+      memcpy (buf, largerbuf, namelen);
+    }
+# else
+  char *name =
+    (buflen < sizeof (largerbuf)
+     ? ttyname_r (fd, largerbuf, sizeof (largerbuf))
+     : ttyname_r (fd, buf, buflen <= INT_MAX ? buflen : INT_MAX));
+  if (name == NULL)
+    return errno;
+  if (name != buf)
+    {
+      size_t namelen = strlen (name) + 1;
+      if (namelen > buflen)
+        return ERANGE;
+      memmove (buf, name, namelen);
+    }
+# endif
+  return 0;
+#elif HAVE_TTYNAME
   /* Note: This is not multithread-safe.  */
   char *name;
   size_t namelen;