LCOV - code coverage report
Current view: top level - src/port - strerror.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 5.1 % 137 7
Test Date: 2026-07-03 19:57:34 Functions: 50.0 % 4 2
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 5.7 % 70 4

             Branch data     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                 :         533 : 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                 :         533 :     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   [ +  -  +  -  :         533 :     if (str == NULL || *str == '\0' || *str == '?')
                   -  + ]
      68                 :           0 :         str = get_errno_symbol(errnum);
      69                 :             : 
      70         [ -  + ]:         533 :     if (str == NULL)
      71                 :             :     {
      72                 :           0 :         snprintf(buf, buflen, _("operating system error %d"), errnum);
      73                 :           0 :         str = buf;
      74                 :             :     }
      75                 :             : 
      76                 :         533 :     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                 :         533 : 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                 :         533 :     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                 :             : #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 2.0-1