LCOV - code coverage report
Current view: top level - src/port - strerror.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 9 137 6.6 %
Date: 2024-03-29 15:11:20 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-2024, 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           8 : pg_strerror(int errnum)
      36             : {
      37             :     static char errorstr_buf[PG_STRERROR_R_BUFLEN];
      38             : 
      39           8 :     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         652 : 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         652 :     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         652 :     if (str == NULL || *str == '\0' || *str == '?')
      68           0 :         str = get_errno_symbol(errnum);
      69             : 
      70         652 :     if (str == NULL)
      71             :     {
      72           0 :         snprintf(buf, buflen, _("operating system error %d"), errnum);
      73           0 :         str = buf;
      74             :     }
      75             : 
      76         652 :     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         652 : 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         652 :     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 1.14