LCOV - code coverage report
Current view: top level - src/port - strerror.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 5.1 % 137 7
Test Date: 2026-02-17 17:20:33 Functions: 50.0 % 4 2
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-2026, 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            0 : pg_strerror(int errnum)
      36              : {
      37              :     static char errorstr_buf[PG_STRERROR_R_BUFLEN];
      38              : 
      39            0 :     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          462 : 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          462 :     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          462 :     if (str == NULL || *str == '\0' || *str == '?')
      68            0 :         str = get_errno_symbol(errnum);
      69              : 
      70          462 :     if (str == NULL)
      71              :     {
      72            0 :         snprintf(buf, buflen, _("operating system error %d"), errnum);
      73            0 :         str = buf;
      74              :     }
      75              : 
      76          462 :     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          462 : 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          462 :     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            0 :         case E2BIG:
     118            0 :             return "E2BIG";
     119            0 :         case EACCES:
     120            0 :             return "EACCES";
     121            0 :         case EADDRINUSE:
     122            0 :             return "EADDRINUSE";
     123            0 :         case EADDRNOTAVAIL:
     124            0 :             return "EADDRNOTAVAIL";
     125            0 :         case EAFNOSUPPORT:
     126            0 :             return "EAFNOSUPPORT";
     127              : #ifdef EAGAIN
     128            0 :         case EAGAIN:
     129            0 :             return "EAGAIN";
     130              : #endif
     131              : #ifdef EALREADY
     132            0 :         case EALREADY:
     133            0 :             return "EALREADY";
     134              : #endif
     135            0 :         case EBADF:
     136            0 :             return "EBADF";
     137              : #ifdef EBADMSG
     138            0 :         case EBADMSG:
     139            0 :             return "EBADMSG";
     140              : #endif
     141            0 :         case EBUSY:
     142            0 :             return "EBUSY";
     143            0 :         case ECHILD:
     144            0 :             return "ECHILD";
     145            0 :         case ECONNABORTED:
     146            0 :             return "ECONNABORTED";
     147            0 :         case ECONNREFUSED:
     148            0 :             return "ECONNREFUSED";
     149            0 :         case ECONNRESET:
     150            0 :             return "ECONNRESET";
     151            0 :         case EDEADLK:
     152            0 :             return "EDEADLK";
     153            0 :         case EDOM:
     154            0 :             return "EDOM";
     155            0 :         case EEXIST:
     156            0 :             return "EEXIST";
     157            0 :         case EFAULT:
     158            0 :             return "EFAULT";
     159            0 :         case EFBIG:
     160            0 :             return "EFBIG";
     161            0 :         case EHOSTDOWN:
     162            0 :             return "EHOSTDOWN";
     163            0 :         case EHOSTUNREACH:
     164            0 :             return "EHOSTUNREACH";
     165            0 :         case EIDRM:
     166            0 :             return "EIDRM";
     167            0 :         case EINPROGRESS:
     168            0 :             return "EINPROGRESS";
     169            0 :         case EINTR:
     170            0 :             return "EINTR";
     171            0 :         case EINVAL:
     172            0 :             return "EINVAL";
     173            0 :         case EIO:
     174            0 :             return "EIO";
     175            0 :         case EISCONN:
     176            0 :             return "EISCONN";
     177            0 :         case EISDIR:
     178            0 :             return "EISDIR";
     179              : #ifdef ELOOP
     180            0 :         case ELOOP:
     181            0 :             return "ELOOP";
     182              : #endif
     183            0 :         case EMFILE:
     184            0 :             return "EMFILE";
     185            0 :         case EMLINK:
     186            0 :             return "EMLINK";
     187            0 :         case EMSGSIZE:
     188            0 :             return "EMSGSIZE";
     189            0 :         case ENAMETOOLONG:
     190            0 :             return "ENAMETOOLONG";
     191            0 :         case ENETDOWN:
     192            0 :             return "ENETDOWN";
     193            0 :         case ENETRESET:
     194            0 :             return "ENETRESET";
     195            0 :         case ENETUNREACH:
     196            0 :             return "ENETUNREACH";
     197            0 :         case ENFILE:
     198            0 :             return "ENFILE";
     199            0 :         case ENOBUFS:
     200            0 :             return "ENOBUFS";
     201            0 :         case ENODEV:
     202            0 :             return "ENODEV";
     203            0 :         case ENOENT:
     204            0 :             return "ENOENT";
     205            0 :         case ENOEXEC:
     206            0 :             return "ENOEXEC";
     207            0 :         case ENOMEM:
     208            0 :             return "ENOMEM";
     209            0 :         case ENOSPC:
     210            0 :             return "ENOSPC";
     211            0 :         case ENOSYS:
     212            0 :             return "ENOSYS";
     213            0 :         case ENOTCONN:
     214            0 :             return "ENOTCONN";
     215            0 :         case ENOTDIR:
     216            0 :             return "ENOTDIR";
     217            0 :         case ENOTEMPTY:
     218            0 :             return "ENOTEMPTY";
     219            0 :         case ENOTSOCK:
     220            0 :             return "ENOTSOCK";
     221              : #ifdef ENOTSUP
     222            0 :         case ENOTSUP:
     223            0 :             return "ENOTSUP";
     224              : #endif
     225            0 :         case ENOTTY:
     226            0 :             return "ENOTTY";
     227            0 :         case ENXIO:
     228            0 :             return "ENXIO";
     229              : #if defined(EOPNOTSUPP) && (!defined(ENOTSUP) || (EOPNOTSUPP != ENOTSUP))
     230              :         case EOPNOTSUPP:
     231              :             return "EOPNOTSUPP";
     232              : #endif
     233              : #ifdef EOVERFLOW
     234            0 :         case EOVERFLOW:
     235            0 :             return "EOVERFLOW";
     236              : #endif
     237            0 :         case EPERM:
     238            0 :             return "EPERM";
     239            0 :         case EPIPE:
     240            0 :             return "EPIPE";
     241            0 :         case EPROTONOSUPPORT:
     242            0 :             return "EPROTONOSUPPORT";
     243            0 :         case ERANGE:
     244            0 :             return "ERANGE";
     245              : #ifdef EROFS
     246            0 :         case EROFS:
     247            0 :             return "EROFS";
     248              : #endif
     249            0 :         case ESRCH:
     250            0 :             return "ESRCH";
     251            0 :         case ETIMEDOUT:
     252            0 :             return "ETIMEDOUT";
     253              : #ifdef ETXTBSY
     254            0 :         case ETXTBSY:
     255            0 :             return "ETXTBSY";
     256              : #endif
     257              : #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
     258              :         case EWOULDBLOCK:
     259              :             return "EWOULDBLOCK";
     260              : #endif
     261            0 :         case EXDEV:
     262            0 :             return "EXDEV";
     263              :     }
     264              : 
     265            0 :     return NULL;
     266              : }
     267              : 
     268              : 
     269              : #ifdef WIN32
     270              : 
     271              : /*
     272              :  * Windows' strerror() doesn't know the Winsock codes, so handle them this way
     273              :  */
     274              : static char *
     275              : win32_socket_strerror(int errnum, char *buf, size_t buflen)
     276              : {
     277              :     static HANDLE handleDLL = INVALID_HANDLE_VALUE;
     278              : 
     279              :     if (handleDLL == INVALID_HANDLE_VALUE)
     280              :     {
     281              :         handleDLL = LoadLibraryEx("netmsg.dll", NULL,
     282              :                                   DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE);
     283              :         if (handleDLL == NULL)
     284              :         {
     285              :             snprintf(buf, buflen,
     286              :                      "winsock error %d (could not load netmsg.dll to translate: error code %lu)",
     287              :                      errnum, GetLastError());
     288              :             return buf;
     289              :         }
     290              :     }
     291              : 
     292              :     ZeroMemory(buf, buflen);
     293              :     if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS |
     294              :                       FORMAT_MESSAGE_FROM_SYSTEM |
     295              :                       FORMAT_MESSAGE_FROM_HMODULE,
     296              :                       handleDLL,
     297              :                       errnum,
     298              :                       MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
     299              :                       buf,
     300              :                       buflen - 1,
     301              :                       NULL) == 0)
     302              :     {
     303              :         /* Failed to get id */
     304              :         snprintf(buf, buflen, "unrecognized winsock error %d", errnum);
     305              :     }
     306              : 
     307              :     return buf;
     308              : }
     309              : 
     310              : #endif                          /* WIN32 */
        

Generated by: LCOV version 2.0-1