105436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* strerror_r.c --- POSIX compatible system error routine
205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
305436638acc7c010349a69c3395f1a57c642dc62Ying Wang   Copyright (C) 2010-2012 Free Software Foundation, Inc.
405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
505436638acc7c010349a69c3395f1a57c642dc62Ying Wang   This program is free software: you can redistribute it and/or modify
605436638acc7c010349a69c3395f1a57c642dc62Ying Wang   it under the terms of the GNU General Public License as published by
705436638acc7c010349a69c3395f1a57c642dc62Ying Wang   the Free Software Foundation; either version 3 of the License, or
805436638acc7c010349a69c3395f1a57c642dc62Ying Wang   (at your option) any later version.
905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
1005436638acc7c010349a69c3395f1a57c642dc62Ying Wang   This program is distributed in the hope that it will be useful,
1105436638acc7c010349a69c3395f1a57c642dc62Ying Wang   but WITHOUT ANY WARRANTY; without even the implied warranty of
1205436638acc7c010349a69c3395f1a57c642dc62Ying Wang   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1305436638acc7c010349a69c3395f1a57c642dc62Ying Wang   GNU General Public License for more details.
1405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
1505436638acc7c010349a69c3395f1a57c642dc62Ying Wang   You should have received a copy of the GNU General Public License
1605436638acc7c010349a69c3395f1a57c642dc62Ying Wang   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
1705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
1805436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Written by Bruno Haible <bruno@clisp.org>, 2010.  */
1905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
2005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <config.h>
2105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
2205436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Enable declaration of sys_nerr and sys_errlist in <errno.h> on NetBSD.  */
2305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#define _NETBSD_SOURCE 1
2405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
2505436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Specification.  */
2605436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <string.h>
2705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
2805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <errno.h>
2905436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <stdio.h>
3005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <stdlib.h>
3105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
3205436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include "strerror-override.h"
3305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
3405436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if (__GLIBC__ >= 2 || defined __UCLIBC__ || defined __CYGWIN__) && HAVE___XPG_STRERROR_R /* glibc >= 2.3.4, cygwin >= 1.7.9 */
3505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
3605436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define USE_XPG_STRERROR_R 1
3705436638acc7c010349a69c3395f1a57c642dc62Ying Wangextern int __xpg_strerror_r (int errnum, char *buf, size_t buflen);
3805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
3905436638acc7c010349a69c3395f1a57c642dc62Ying Wang#elif HAVE_DECL_STRERROR_R && !(__GLIBC__ >= 2 || defined __UCLIBC__ || defined __CYGWIN__)
4005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
4105436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* The system's strerror_r function is OK, except that its third argument
4205436638acc7c010349a69c3395f1a57c642dc62Ying Wang   is 'int', not 'size_t', or its return type is wrong.  */
4305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
4405436638acc7c010349a69c3395f1a57c642dc62Ying Wang# include <limits.h>
4505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
4605436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define USE_SYSTEM_STRERROR_R 1
4705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
4805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#else /* (__GLIBC__ >= 2 || defined __UCLIBC__ || defined __CYGWIN__ ? !HAVE___XPG_STRERROR_R : !HAVE_DECL_STRERROR_R) */
4905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
5005436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Use the system's strerror().  Exclude glibc and cygwin because the
5105436638acc7c010349a69c3395f1a57c642dc62Ying Wang   system strerror_r has the wrong return type, and cygwin 1.7.9
5205436638acc7c010349a69c3395f1a57c642dc62Ying Wang   strerror_r clobbers strerror.  */
5305436638acc7c010349a69c3395f1a57c642dc62Ying Wang# undef strerror
5405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
5505436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define USE_SYSTEM_STRERROR 1
5605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
5705436638acc7c010349a69c3395f1a57c642dc62Ying Wang# if defined __NetBSD__ || defined __hpux || ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) || defined __sgi || (defined __sun && !defined _LP64) || defined __CYGWIN__
5805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
5905436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* No locking needed.  */
6005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
6105436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Get catgets internationalization functions.  */
6205436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  if HAVE_CATGETS
6305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#   include <nl_types.h>
6405436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  endif
6505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
6605436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Get sys_nerr, sys_errlist on HP-UX (otherwise only declared in C++ mode).
6705436638acc7c010349a69c3395f1a57c642dc62Ying Wang   Get sys_nerr, sys_errlist on IRIX (otherwise only declared with _SGIAPI).  */
6805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  if defined __hpux || defined __sgi
6905436638acc7c010349a69c3395f1a57c642dc62Ying Wangextern int sys_nerr;
7005436638acc7c010349a69c3395f1a57c642dc62Ying Wangextern char *sys_errlist[];
7105436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  endif
7205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
7305436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Get sys_nerr on Solaris.  */
7405436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  if defined __sun && !defined _LP64
7505436638acc7c010349a69c3395f1a57c642dc62Ying Wangextern int sys_nerr;
7605436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  endif
7705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
7805436638acc7c010349a69c3395f1a57c642dc62Ying Wang# else
7905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
8005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  include "glthread/lock.h"
8105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
8205436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* This lock protects the buffer returned by strerror().  We assume that
8305436638acc7c010349a69c3395f1a57c642dc62Ying Wang   no other uses of strerror() exist in the program.  */
8405436638acc7c010349a69c3395f1a57c642dc62Ying Wanggl_lock_define_initialized(static, strerror_lock)
8505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
8605436638acc7c010349a69c3395f1a57c642dc62Ying Wang# endif
8705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
8805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
8905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
9005436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* On MSVC, there is no snprintf() function, just a _snprintf().
9105436638acc7c010349a69c3395f1a57c642dc62Ying Wang   It is of lower quality, but sufficient for the simple use here.
9205436638acc7c010349a69c3395f1a57c642dc62Ying Wang   We only have to make sure to NUL terminate the result (_snprintf
9305436638acc7c010349a69c3395f1a57c642dc62Ying Wang   does not NUL terminate, like strncpy).  */
9405436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if !HAVE_SNPRINTF
9505436638acc7c010349a69c3395f1a57c642dc62Ying Wangstatic int
9605436638acc7c010349a69c3395f1a57c642dc62Ying Wanglocal_snprintf (char *buf, size_t buflen, const char *format, ...)
9705436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
9805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  va_list args;
9905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int result;
10005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
10105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  va_start (args, format);
10205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  result = _vsnprintf (buf, buflen, format, args);
10305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  va_end (args);
10405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (buflen > 0 && (result < 0 || result >= buflen))
10505436638acc7c010349a69c3395f1a57c642dc62Ying Wang    buf[buflen - 1] = '\0';
10605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return result;
10705436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
10805436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define snprintf local_snprintf
10905436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
11005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
11105436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Copy as much of MSG into BUF as possible, without corrupting errno.
11205436638acc7c010349a69c3395f1a57c642dc62Ying Wang   Return 0 if MSG fit in BUFLEN, otherwise return ERANGE.  */
11305436638acc7c010349a69c3395f1a57c642dc62Ying Wangstatic int
11405436638acc7c010349a69c3395f1a57c642dc62Ying Wangsafe_copy (char *buf, size_t buflen, const char *msg)
11505436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
11605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  size_t len = strlen (msg);
11705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int ret;
11805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
11905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (len < buflen)
12005436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
12105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* Although POSIX allows memcpy() to corrupt errno, we don't
12205436638acc7c010349a69c3395f1a57c642dc62Ying Wang         know of any implementation where this is a real problem.  */
12305436638acc7c010349a69c3395f1a57c642dc62Ying Wang      memcpy (buf, msg, len + 1);
12405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      ret = 0;
12505436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
12605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  else
12705436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
12805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      memcpy (buf, msg, buflen - 1);
12905436638acc7c010349a69c3395f1a57c642dc62Ying Wang      buf[buflen - 1] = '\0';
13005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      ret = ERANGE;
13105436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
13205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return ret;
13305436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
13405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
13505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
13605436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
13705436638acc7c010349a69c3395f1a57c642dc62Ying Wangstrerror_r (int errnum, char *buf, size_t buflen)
13805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#undef strerror_r
13905436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
14005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Filter this out now, so that rest of this replacement knows that
14105436638acc7c010349a69c3395f1a57c642dc62Ying Wang     there is room for a non-empty message and trailing NUL.  */
14205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (buflen <= 1)
14305436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
14405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (buflen)
14505436638acc7c010349a69c3395f1a57c642dc62Ying Wang        *buf = '\0';
14605436638acc7c010349a69c3395f1a57c642dc62Ying Wang      return ERANGE;
14705436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
14805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  *buf = '\0';
14905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
15005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Check for gnulib overrides.  */
15105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  {
15205436638acc7c010349a69c3395f1a57c642dc62Ying Wang    char const *msg = strerror_override (errnum);
15305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
15405436638acc7c010349a69c3395f1a57c642dc62Ying Wang    if (msg)
15505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      return safe_copy (buf, buflen, msg);
15605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  }
15705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
15805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  {
15905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    int ret;
16005436638acc7c010349a69c3395f1a57c642dc62Ying Wang    int saved_errno = errno;
16105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
16205436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if USE_XPG_STRERROR_R
16305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
16405436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
16505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      ret = __xpg_strerror_r (errnum, buf, buflen);
16605436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (ret < 0)
16705436638acc7c010349a69c3395f1a57c642dc62Ying Wang        ret = errno;
16805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (!*buf)
16905436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
17005436638acc7c010349a69c3395f1a57c642dc62Ying Wang          /* glibc 2.13 would not touch buf on err, so we have to fall
17105436638acc7c010349a69c3395f1a57c642dc62Ying Wang             back to GNU strerror_r which always returns a thread-safe
17205436638acc7c010349a69c3395f1a57c642dc62Ying Wang             untruncated string to (partially) copy into our buf.  */
17305436638acc7c010349a69c3395f1a57c642dc62Ying Wang          safe_copy (buf, buflen, strerror_r (errnum, buf, buflen));
17405436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
17505436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
17605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
17705436638acc7c010349a69c3395f1a57c642dc62Ying Wang#elif USE_SYSTEM_STRERROR_R
17805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
17905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    if (buflen > INT_MAX)
18005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      buflen = INT_MAX;
18105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
18205436638acc7c010349a69c3395f1a57c642dc62Ying Wang# ifdef __hpux
18305436638acc7c010349a69c3395f1a57c642dc62Ying Wang    /* On HP-UX 11.31, strerror_r always fails when buflen < 80; it
18405436638acc7c010349a69c3395f1a57c642dc62Ying Wang       also fails to change buf on EINVAL.  */
18505436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
18605436638acc7c010349a69c3395f1a57c642dc62Ying Wang      char stackbuf[80];
18705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
18805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (buflen < sizeof stackbuf)
18905436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
19005436638acc7c010349a69c3395f1a57c642dc62Ying Wang          ret = strerror_r (errnum, stackbuf, sizeof stackbuf);
19105436638acc7c010349a69c3395f1a57c642dc62Ying Wang          if (ret == 0)
19205436638acc7c010349a69c3395f1a57c642dc62Ying Wang            ret = safe_copy (buf, buflen, stackbuf);
19305436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
19405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      else
19505436638acc7c010349a69c3395f1a57c642dc62Ying Wang        ret = strerror_r (errnum, buf, buflen);
19605436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
19705436638acc7c010349a69c3395f1a57c642dc62Ying Wang# else
19805436638acc7c010349a69c3395f1a57c642dc62Ying Wang    ret = strerror_r (errnum, buf, buflen);
19905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
20005436638acc7c010349a69c3395f1a57c642dc62Ying Wang    /* Some old implementations may return (-1, EINVAL) instead of EINVAL.  */
20105436638acc7c010349a69c3395f1a57c642dc62Ying Wang    if (ret < 0)
20205436638acc7c010349a69c3395f1a57c642dc62Ying Wang      ret = errno;
20305436638acc7c010349a69c3395f1a57c642dc62Ying Wang# endif
20405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
20505436638acc7c010349a69c3395f1a57c642dc62Ying Wang# ifdef _AIX
20605436638acc7c010349a69c3395f1a57c642dc62Ying Wang    /* AIX returns 0 rather than ERANGE when truncating strings; try
20705436638acc7c010349a69c3395f1a57c642dc62Ying Wang       again until we are sure we got the entire string.  */
20805436638acc7c010349a69c3395f1a57c642dc62Ying Wang    if (!ret && strlen (buf) == buflen - 1)
20905436638acc7c010349a69c3395f1a57c642dc62Ying Wang      {
21005436638acc7c010349a69c3395f1a57c642dc62Ying Wang        char stackbuf[STACKBUF_LEN];
21105436638acc7c010349a69c3395f1a57c642dc62Ying Wang        size_t len;
21205436638acc7c010349a69c3395f1a57c642dc62Ying Wang        strerror_r (errnum, stackbuf, sizeof stackbuf);
21305436638acc7c010349a69c3395f1a57c642dc62Ying Wang        len = strlen (stackbuf);
21405436638acc7c010349a69c3395f1a57c642dc62Ying Wang        /* STACKBUF_LEN should have been large enough.  */
21505436638acc7c010349a69c3395f1a57c642dc62Ying Wang        if (len + 1 == sizeof stackbuf)
21605436638acc7c010349a69c3395f1a57c642dc62Ying Wang          abort ();
21705436638acc7c010349a69c3395f1a57c642dc62Ying Wang        if (buflen <= len)
21805436638acc7c010349a69c3395f1a57c642dc62Ying Wang          ret = ERANGE;
21905436638acc7c010349a69c3395f1a57c642dc62Ying Wang      }
22005436638acc7c010349a69c3395f1a57c642dc62Ying Wang# else
22105436638acc7c010349a69c3395f1a57c642dc62Ying Wang    /* Solaris 10 does not populate buf on ERANGE.  OpenBSD 4.7
22205436638acc7c010349a69c3395f1a57c642dc62Ying Wang       truncates early on ERANGE rather than return a partial integer.
22305436638acc7c010349a69c3395f1a57c642dc62Ying Wang       We prefer the maximal string.  We set buf[0] earlier, and we
22405436638acc7c010349a69c3395f1a57c642dc62Ying Wang       know of no implementation that modifies buf to be an
22505436638acc7c010349a69c3395f1a57c642dc62Ying Wang       unterminated string, so this strlen should be portable in
22605436638acc7c010349a69c3395f1a57c642dc62Ying Wang       practice (rather than pulling in a safer strnlen).  */
22705436638acc7c010349a69c3395f1a57c642dc62Ying Wang    if (ret == ERANGE && strlen (buf) < buflen - 1)
22805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      {
22905436638acc7c010349a69c3395f1a57c642dc62Ying Wang        char stackbuf[STACKBUF_LEN];
23005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
23105436638acc7c010349a69c3395f1a57c642dc62Ying Wang        /* STACKBUF_LEN should have been large enough.  */
23205436638acc7c010349a69c3395f1a57c642dc62Ying Wang        if (strerror_r (errnum, stackbuf, sizeof stackbuf) == ERANGE)
23305436638acc7c010349a69c3395f1a57c642dc62Ying Wang          abort ();
23405436638acc7c010349a69c3395f1a57c642dc62Ying Wang        safe_copy (buf, buflen, stackbuf);
23505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      }
23605436638acc7c010349a69c3395f1a57c642dc62Ying Wang# endif
23705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
23805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#else /* USE_SYSTEM_STRERROR */
23905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
24005436638acc7c010349a69c3395f1a57c642dc62Ying Wang    /* Try to do what strerror (errnum) does, but without clobbering the
24105436638acc7c010349a69c3395f1a57c642dc62Ying Wang       buffer used by strerror().  */
24205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
24305436638acc7c010349a69c3395f1a57c642dc62Ying Wang# if defined __NetBSD__ || defined __hpux || ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) || defined __CYGWIN__ /* NetBSD, HP-UX, native Windows, Cygwin */
24405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
24505436638acc7c010349a69c3395f1a57c642dc62Ying Wang    /* NetBSD:         sys_nerr, sys_errlist are declared through _NETBSD_SOURCE
24605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                       and <errno.h> above.
24705436638acc7c010349a69c3395f1a57c642dc62Ying Wang       HP-UX:          sys_nerr, sys_errlist are declared explicitly above.
24805436638acc7c010349a69c3395f1a57c642dc62Ying Wang       native Windows: sys_nerr, sys_errlist are declared in <stdlib.h>.
24905436638acc7c010349a69c3395f1a57c642dc62Ying Wang       Cygwin:         sys_nerr, sys_errlist are declared in <errno.h>.  */
25005436638acc7c010349a69c3395f1a57c642dc62Ying Wang    if (errnum >= 0 && errnum < sys_nerr)
25105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      {
25205436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  if HAVE_CATGETS && (defined __NetBSD__ || defined __hpux)
25305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#   if defined __NetBSD__
25405436638acc7c010349a69c3395f1a57c642dc62Ying Wang        nl_catd catd = catopen ("libc", NL_CAT_LOCALE);
25505436638acc7c010349a69c3395f1a57c642dc62Ying Wang        const char *errmsg =
25605436638acc7c010349a69c3395f1a57c642dc62Ying Wang          (catd != (nl_catd)-1
25705436638acc7c010349a69c3395f1a57c642dc62Ying Wang           ? catgets (catd, 1, errnum, sys_errlist[errnum])
25805436638acc7c010349a69c3395f1a57c642dc62Ying Wang           : sys_errlist[errnum]);
25905436638acc7c010349a69c3395f1a57c642dc62Ying Wang#   endif
26005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#   if defined __hpux
26105436638acc7c010349a69c3395f1a57c642dc62Ying Wang        nl_catd catd = catopen ("perror", NL_CAT_LOCALE);
26205436638acc7c010349a69c3395f1a57c642dc62Ying Wang        const char *errmsg =
26305436638acc7c010349a69c3395f1a57c642dc62Ying Wang          (catd != (nl_catd)-1
26405436638acc7c010349a69c3395f1a57c642dc62Ying Wang           ? catgets (catd, 1, 1 + errnum, sys_errlist[errnum])
26505436638acc7c010349a69c3395f1a57c642dc62Ying Wang           : sys_errlist[errnum]);
26605436638acc7c010349a69c3395f1a57c642dc62Ying Wang#   endif
26705436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  else
26805436638acc7c010349a69c3395f1a57c642dc62Ying Wang        const char *errmsg = sys_errlist[errnum];
26905436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  endif
27005436638acc7c010349a69c3395f1a57c642dc62Ying Wang        if (errmsg == NULL || *errmsg == '\0')
27105436638acc7c010349a69c3395f1a57c642dc62Ying Wang          ret = EINVAL;
27205436638acc7c010349a69c3395f1a57c642dc62Ying Wang        else
27305436638acc7c010349a69c3395f1a57c642dc62Ying Wang          ret = safe_copy (buf, buflen, errmsg);
27405436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  if HAVE_CATGETS && (defined __NetBSD__ || defined __hpux)
27505436638acc7c010349a69c3395f1a57c642dc62Ying Wang        if (catd != (nl_catd)-1)
27605436638acc7c010349a69c3395f1a57c642dc62Ying Wang          catclose (catd);
27705436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  endif
27805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      }
27905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    else
28005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      ret = EINVAL;
28105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
28205436638acc7c010349a69c3395f1a57c642dc62Ying Wang# elif defined __sgi || (defined __sun && !defined _LP64) /* IRIX, Solaris <= 9 32-bit */
28305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
28405436638acc7c010349a69c3395f1a57c642dc62Ying Wang    /* For a valid error number, the system's strerror() function returns
28505436638acc7c010349a69c3395f1a57c642dc62Ying Wang       a pointer to a not copied string, not to a buffer.  */
28605436638acc7c010349a69c3395f1a57c642dc62Ying Wang    if (errnum >= 0 && errnum < sys_nerr)
28705436638acc7c010349a69c3395f1a57c642dc62Ying Wang      {
28805436638acc7c010349a69c3395f1a57c642dc62Ying Wang        char *errmsg = strerror (errnum);
28905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
29005436638acc7c010349a69c3395f1a57c642dc62Ying Wang        if (errmsg == NULL || *errmsg == '\0')
29105436638acc7c010349a69c3395f1a57c642dc62Ying Wang          ret = EINVAL;
29205436638acc7c010349a69c3395f1a57c642dc62Ying Wang        else
29305436638acc7c010349a69c3395f1a57c642dc62Ying Wang          ret = safe_copy (buf, buflen, errmsg);
29405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      }
29505436638acc7c010349a69c3395f1a57c642dc62Ying Wang    else
29605436638acc7c010349a69c3395f1a57c642dc62Ying Wang      ret = EINVAL;
29705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
29805436638acc7c010349a69c3395f1a57c642dc62Ying Wang# else
29905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
30005436638acc7c010349a69c3395f1a57c642dc62Ying Wang    gl_lock_lock (strerror_lock);
30105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
30205436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
30305436638acc7c010349a69c3395f1a57c642dc62Ying Wang      char *errmsg = strerror (errnum);
30405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
30505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* For invalid error numbers, strerror() on
30605436638acc7c010349a69c3395f1a57c642dc62Ying Wang           - IRIX 6.5 returns NULL,
30705436638acc7c010349a69c3395f1a57c642dc62Ying Wang           - HP-UX 11 returns an empty string.  */
30805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (errmsg == NULL || *errmsg == '\0')
30905436638acc7c010349a69c3395f1a57c642dc62Ying Wang        ret = EINVAL;
31005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      else
31105436638acc7c010349a69c3395f1a57c642dc62Ying Wang        ret = safe_copy (buf, buflen, errmsg);
31205436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
31305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
31405436638acc7c010349a69c3395f1a57c642dc62Ying Wang    gl_lock_unlock (strerror_lock);
31505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
31605436638acc7c010349a69c3395f1a57c642dc62Ying Wang# endif
31705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
31805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
31905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
32005436638acc7c010349a69c3395f1a57c642dc62Ying Wang    if (ret == EINVAL && !*buf)
32105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      snprintf (buf, buflen, "Unknown error %d", errnum);
32205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
32305436638acc7c010349a69c3395f1a57c642dc62Ying Wang    errno = saved_errno;
32405436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return ret;
32505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  }
32605436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
327