LCOV - code coverage report
Current view: top level - src/port - strerror.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 9 72 12.5 %
Date: 2019-11-15 23:07:02 Functions: 3 4 75.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * strerror.c
       4             :  *    Replacements for standard strerror() and strerror_r() functions
       5             :  *
       6             :  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/port/strerror.c
      12             :  *
      13             :  *-------------------------------------------------------------------------
      14             :  */
      15             : #include "c.h"
      16             : 
      17             : /*
      18             :  * Within this file, "strerror" means the platform's function not pg_strerror,
      19             :  * and likewise for "strerror_r"
      20             :  */
      21             : #undef strerror
      22             : #undef strerror_r
      23             : 
      24             : static char *gnuish_strerror_r(int errnum, char *buf, size_t buflen);
      25             : static char *get_errno_symbol(int errnum);
      26             : #ifdef WIN32
      27             : static char *win32_socket_strerror(int errnum, char *buf, size_t buflen);
      28             : #endif
      29             : 
      30             : 
      31             : /*
      32             :  * A slightly cleaned-up version of strerror()
      33             :  */
      34             : char *
      35           2 : pg_strerror(int errnum)
      36             : {
      37             :     static char errorstr_buf[PG_STRERROR_R_BUFLEN];
      38             : 
      39           2 :     return pg_strerror_r(errnum, errorstr_buf, sizeof(errorstr_buf));
      40             : }
      41             : 
      42             : /*
      43             :  * A slightly cleaned-up version of strerror_r()
      44             :  */
      45             : char *
      46         378 : pg_strerror_r(int errnum, char *buf, size_t buflen)
      47             : {
      48             :     char       *str;
      49             : 
      50             :     /* If it's a Windows Winsock error, that needs special handling */
      51             : #ifdef WIN32
      52             :     /* Winsock error code range, per WinError.h */
      53             :     if (errnum >= 10000 && errnum <= 11999)
      54             :         return win32_socket_strerror(errnum, buf, buflen);
      55             : #endif
      56             : 
      57             :     /* Try the platform's strerror_r(), or maybe just strerror() */
      58         378 :     str = gnuish_strerror_r(errnum, buf, buflen);
      59             : 
      60             :     /*
      61             :      * Some strerror()s return an empty string for out-of-range errno.  This
      62             :      * is ANSI C spec compliant, but not exactly useful.  Also, we may get
      63             :      * back strings of question marks if libc cannot transcode the message to
      64             :      * the codeset specified by LC_CTYPE.  If we get nothing useful, first try
      65             :      * get_errno_symbol(), and if that fails, print the numeric errno.
      66             :      */
      67         378 :     if (str == NULL || *str == '\0' || *str == '?')
      68           0 :         str = get_errno_symbol(errnum);
      69             : 
      70         378 :     if (str == NULL)
      71             :     {
      72           0 :         snprintf(buf, buflen, _("operating system error %d"), errnum);
      73           0 :         str = buf;
      74             :     }
      75             : 
      76         378 :     return str;
      77             : }
      78             : 
      79             : /*
      80             :  * Simple wrapper to emulate GNU strerror_r if what the platform provides is
      81             :  * POSIX.  Also, if platform lacks strerror_r altogether, fall back to plain
      82             :  * strerror; it might not be very thread-safe, but tough luck.
      83             :  */
      84             : static char *
      85         378 : gnuish_strerror_r(int errnum, char *buf, size_t buflen)
      86             : {
      87             : #ifdef HAVE_STRERROR_R
      88             : #ifdef STRERROR_R_INT
      89             :     /* POSIX API */
      90             :     if (strerror_r(errnum, buf, buflen) == 0)
      91             :         return buf;
      92             :     return NULL;                /* let caller deal with failure */
      93             : #else
      94             :     /* GNU API */
      95         378 :     return strerror_r(errnum, buf, buflen);
      96             : #endif
      97             : #else                           /* !HAVE_STRERROR_R */
      98             :     char       *sbuf = strerror(errnum);
      99             : 
     100             :     if (sbuf == NULL)           /* can this still happen anywhere? */
     101             :         return NULL;
     102             :     /* To minimize thread-unsafety hazard, copy into caller's buffer */
     103             :     strlcpy(buf, sbuf, buflen);
     104             :     return buf;
     105             : #endif
     106             : }
     107             : 
     108             : /*
     109             :  * Returns a symbol (e.g. "ENOENT") for an errno code.
     110             :  * Returns NULL if the code is unrecognized.
     111             :  */
     112             : static char *
     113           0 : get_errno_symbol(int errnum)
     114             : {
     115           0 :     switch (errnum)
     116             :     {
     117             :         case E2BIG:
     118           0 :             return "E2BIG";
     119             :         case EACCES:
     120           0 :             return "EACCES";
     121             : #ifdef EADDRINUSE
     122             :         case EADDRINUSE:
     123           0 :             return "EADDRINUSE";
     124             : #endif
     125             : #ifdef EADDRNOTAVAIL
     126             :         case EADDRNOTAVAIL:
     127           0 :             return "EADDRNOTAVAIL";
     128             : #endif
     129             :         case EAFNOSUPPORT:
     130           0 :             return "EAFNOSUPPORT";
     131             : #ifdef EAGAIN
     132             :         case EAGAIN:
     133           0 :             return "EAGAIN";
     134             : #endif
     135             : #ifdef EALREADY
     136             :         case EALREADY:
     137           0 :             return "EALREADY";
     138             : #endif
     139             :         case EBADF:
     140           0 :             return "EBADF";
     141             : #ifdef EBADMSG
     142             :         case EBADMSG:
     143           0 :             return "EBADMSG";
     144             : #endif
     145             :         case EBUSY:
     146           0 :             return "EBUSY";
     147             :         case ECHILD:
     148           0 :             return "ECHILD";
     149             : #ifdef ECONNABORTED
     150             :         case ECONNABORTED:
     151           0 :             return "ECONNABORTED";
     152             : #endif
     153             :         case ECONNREFUSED:
     154           0 :             return "ECONNREFUSED";
     155             : #ifdef ECONNRESET
     156             :         case ECONNRESET:
     157           0 :             return "ECONNRESET";
     158             : #endif
     159             :         case EDEADLK:
     160           0 :             return "EDEADLK";
     161             :         case EDOM:
     162           0 :             return "EDOM";
     163             :         case EEXIST:
     164           0 :             return "EEXIST";
     165             :         case EFAULT:
     166           0 :             return "EFAULT";
     167             :         case EFBIG:
     168           0 :             return "EFBIG";
     169             : #ifdef EHOSTUNREACH
     170             :         case EHOSTUNREACH:
     171           0 :             return "EHOSTUNREACH";
     172             : #endif
     173             :         case EIDRM:
     174           0 :             return "EIDRM";
     175             :         case EINPROGRESS:
     176           0 :             return "EINPROGRESS";
     177             :         case EINTR:
     178           0 :             return "EINTR";
     179             :         case EINVAL:
     180           0 :             return "EINVAL";
     181             :         case EIO:
     182           0 :             return "EIO";
     183             : #ifdef EISCONN
     184             :         case EISCONN:
     185           0 :             return "EISCONN";
     186             : #endif
     187             :         case EISDIR:
     188           0 :             return "EISDIR";
     189             : #ifdef ELOOP
     190             :         case ELOOP:
     191           0 :             return "ELOOP";
     192             : #endif
     193             :         case EMFILE:
     194           0 :             return "EMFILE";
     195             :         case EMLINK:
     196           0 :             return "EMLINK";
     197             :         case EMSGSIZE:
     198           0 :             return "EMSGSIZE";
     199             :         case ENAMETOOLONG:
     200           0 :             return "ENAMETOOLONG";
     201             :         case ENFILE:
     202           0 :             return "ENFILE";
     203             :         case ENOBUFS:
     204           0 :             return "ENOBUFS";
     205             :         case ENODEV:
     206           0 :             return "ENODEV";
     207             :         case ENOENT:
     208           0 :             return "ENOENT";
     209             :         case ENOEXEC:
     210           0 :             return "ENOEXEC";
     211             :         case ENOMEM:
     212           0 :             return "ENOMEM";
     213             :         case ENOSPC:
     214           0 :             return "ENOSPC";
     215             :         case ENOSYS:
     216           0 :             return "ENOSYS";
     217             : #ifdef ENOTCONN
     218             :         case ENOTCONN:
     219           0 :             return "ENOTCONN";
     220             : #endif
     221             :         case ENOTDIR:
     222           0 :             return "ENOTDIR";
     223             : #if defined(ENOTEMPTY) && (ENOTEMPTY != EEXIST) /* same code on AIX */
     224             :         case ENOTEMPTY:
     225           0 :             return "ENOTEMPTY";
     226             : #endif
     227             : #ifdef ENOTSOCK
     228             :         case ENOTSOCK:
     229           0 :             return "ENOTSOCK";
     230             : #endif
     231             : #ifdef ENOTSUP
     232             :         case ENOTSUP:
     233           0 :             return "ENOTSUP";
     234             : #endif
     235             :         case ENOTTY:
     236           0 :             return "ENOTTY";
     237             :         case ENXIO:
     238           0 :             return "ENXIO";
     239             : #if defined(EOPNOTSUPP) && (!defined(ENOTSUP) || (EOPNOTSUPP != ENOTSUP))
     240             :         case EOPNOTSUPP:
     241             :             return "EOPNOTSUPP";
     242             : #endif
     243             : #ifdef EOVERFLOW
     244             :         case EOVERFLOW:
     245           0 :             return "EOVERFLOW";
     246             : #endif
     247             :         case EPERM:
     248           0 :             return "EPERM";
     249             :         case EPIPE:
     250           0 :             return "EPIPE";
     251             :         case EPROTONOSUPPORT:
     252           0 :             return "EPROTONOSUPPORT";
     253             :         case ERANGE:
     254           0 :             return "ERANGE";
     255             : #ifdef EROFS
     256             :         case EROFS:
     257           0 :             return "EROFS";
     258             : #endif
     259             :         case ESRCH:
     260           0 :             return "ESRCH";
     261             : #ifdef ETIMEDOUT
     262             :         case ETIMEDOUT:
     263           0 :             return "ETIMEDOUT";
     264             : #endif
     265             : #ifdef ETXTBSY
     266             :         case ETXTBSY:
     267           0 :             return "ETXTBSY";
     268             : #endif
     269             : #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
     270             :         case EWOULDBLOCK:
     271             :             return "EWOULDBLOCK";
     272             : #endif
     273             :         case EXDEV:
     274           0 :             return "EXDEV";
     275             :     }
     276             : 
     277           0 :     return NULL;
     278             : }
     279             : 
     280             : 
     281             : #ifdef WIN32
     282             : 
     283             : /*
     284             :  * Windows' strerror() doesn't know the Winsock codes, so handle them this way
     285             :  */
     286             : static char *
     287             : win32_socket_strerror(int errnum, char *buf, size_t buflen)
     288             : {
     289             :     static HANDLE handleDLL = INVALID_HANDLE_VALUE;
     290             : 
     291             :     if (handleDLL == INVALID_HANDLE_VALUE)
     292             :     {
     293             :         handleDLL = LoadLibraryEx("netmsg.dll", NULL,
     294             :                                   DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE);
     295             :         if (handleDLL == NULL)
     296             :         {
     297             :             snprintf(buf, buflen,
     298             :                      "winsock error %d (could not load netmsg.dll to translate: error code %lu)",
     299             :                      errnum, GetLastError());
     300             :             return buf;
     301             :         }
     302             :     }
     303             : 
     304             :     ZeroMemory(buf, buflen);
     305             :     if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS |
     306             :                       FORMAT_MESSAGE_FROM_SYSTEM |
     307             :                       FORMAT_MESSAGE_FROM_HMODULE,
     308             :                       handleDLL,
     309             :                       errnum,
     310             :                       MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
     311             :                       buf,
     312             :                       buflen - 1,
     313             :                       NULL) == 0)
     314             :     {
     315             :         /* Failed to get id */
     316             :         snprintf(buf, buflen, "unrecognized winsock error %d", errnum);
     317             :     }
     318             : 
     319             :     return buf;
     320             : }
     321             : 
     322             : #endif                          /* WIN32 */

Generated by: LCOV version 1.13