LCOV - differential code coverage report
Current view: top level - src/port - strerror.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 6.6 % 137 9 128 9
Current Date: 2023-04-08 15:15:32 Functions: 75.0 % 4 3 1 3
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * strerror.c
       4                 :  *    Replacements for standard strerror() and strerror_r() functions
       5                 :  *
       6                 :  * Portions Copyright (c) 1996-2023, 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 CBC           5 : pg_strerror(int errnum)
      36                 : {
      37                 :     static char errorstr_buf[PG_STRERROR_R_BUFLEN];
      38                 : 
      39               5 :     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             364 : 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             364 :     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             364 :     if (str == NULL || *str == '\0' || *str == '?')
      68 UBC           0 :         str = get_errno_symbol(errnum);
      69                 : 
      70 CBC         364 :     if (str == NULL)
      71                 :     {
      72 UBC           0 :         snprintf(buf, buflen, _("operating system error %d"), errnum);
      73               0 :         str = buf;
      74                 :     }
      75                 : 
      76 CBC         364 :     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             364 : 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             364 :     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 UBC           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                 : #if defined(ENOTEMPTY) && (ENOTEMPTY != EEXIST) /* same code on AIX */
     218               0 :         case ENOTEMPTY:
     219               0 :             return "ENOTEMPTY";
     220                 : #endif
     221               0 :         case ENOTSOCK:
     222               0 :             return "ENOTSOCK";
     223                 : #ifdef ENOTSUP
     224               0 :         case ENOTSUP:
     225               0 :             return "ENOTSUP";
     226                 : #endif
     227               0 :         case ENOTTY:
     228               0 :             return "ENOTTY";
     229               0 :         case ENXIO:
     230               0 :             return "ENXIO";
     231                 : #if defined(EOPNOTSUPP) && (!defined(ENOTSUP) || (EOPNOTSUPP != ENOTSUP))
     232                 :         case EOPNOTSUPP:
     233                 :             return "EOPNOTSUPP";
     234                 : #endif
     235                 : #ifdef EOVERFLOW
     236               0 :         case EOVERFLOW:
     237               0 :             return "EOVERFLOW";
     238                 : #endif
     239               0 :         case EPERM:
     240               0 :             return "EPERM";
     241               0 :         case EPIPE:
     242               0 :             return "EPIPE";
     243               0 :         case EPROTONOSUPPORT:
     244               0 :             return "EPROTONOSUPPORT";
     245               0 :         case ERANGE:
     246               0 :             return "ERANGE";
     247                 : #ifdef EROFS
     248               0 :         case EROFS:
     249               0 :             return "EROFS";
     250                 : #endif
     251               0 :         case ESRCH:
     252               0 :             return "ESRCH";
     253               0 :         case ETIMEDOUT:
     254               0 :             return "ETIMEDOUT";
     255                 : #ifdef ETXTBSY
     256               0 :         case ETXTBSY:
     257               0 :             return "ETXTBSY";
     258                 : #endif
     259                 : #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
     260                 :         case EWOULDBLOCK:
     261                 :             return "EWOULDBLOCK";
     262                 : #endif
     263               0 :         case EXDEV:
     264               0 :             return "EXDEV";
     265                 :     }
     266                 : 
     267               0 :     return NULL;
     268                 : }
     269                 : 
     270                 : 
     271                 : #ifdef WIN32
     272                 : 
     273                 : /*
     274                 :  * Windows' strerror() doesn't know the Winsock codes, so handle them this way
     275                 :  */
     276                 : static char *
     277                 : win32_socket_strerror(int errnum, char *buf, size_t buflen)
     278                 : {
     279                 :     static HANDLE handleDLL = INVALID_HANDLE_VALUE;
     280                 : 
     281                 :     if (handleDLL == INVALID_HANDLE_VALUE)
     282                 :     {
     283                 :         handleDLL = LoadLibraryEx("netmsg.dll", NULL,
     284                 :                                   DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE);
     285                 :         if (handleDLL == NULL)
     286                 :         {
     287                 :             snprintf(buf, buflen,
     288                 :                      "winsock error %d (could not load netmsg.dll to translate: error code %lu)",
     289                 :                      errnum, GetLastError());
     290                 :             return buf;
     291                 :         }
     292                 :     }
     293                 : 
     294                 :     ZeroMemory(buf, buflen);
     295                 :     if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS |
     296                 :                       FORMAT_MESSAGE_FROM_SYSTEM |
     297                 :                       FORMAT_MESSAGE_FROM_HMODULE,
     298                 :                       handleDLL,
     299                 :                       errnum,
     300                 :                       MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
     301                 :                       buf,
     302                 :                       buflen - 1,
     303                 :                       NULL) == 0)
     304                 :     {
     305                 :         /* Failed to get id */
     306                 :         snprintf(buf, buflen, "unrecognized winsock error %d", errnum);
     307                 :     }
     308                 : 
     309                 :     return buf;
     310                 : }
     311                 : 
     312                 : #endif                          /* WIN32 */
        

Generated by: LCOV version v1.16-55-g56c0a2a