LCOV - code coverage report
Current view: top level - src/port - strerror.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 13.1 % 84 11
Test Date: 2026-01-26 10:56:24 Functions: 50.0 % 4 2
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 6.8 % 73 5

             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                 :           6 : pg_strerror_r(int errnum, char *buf, size_t buflen)
      47                 :             : {
      48                 :           6 :         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                 :           6 :         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   [ +  -  +  -  :           6 :         if (str == NULL || *str == '\0' || *str == '?')
                   -  + ]
      68                 :           0 :                 str = get_errno_symbol(errnum);
      69                 :             : 
      70         [ +  - ]:           6 :         if (str == NULL)
      71                 :             :         {
      72                 :           0 :                 snprintf(buf, buflen, _("operating system error %d"), errnum);
      73                 :           0 :                 str = buf;
      74                 :           0 :         }
      75                 :             : 
      76                 :          12 :         return str;
      77                 :           6 : }
      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                 :           6 : 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         [ -  + ]:           6 :         if (strerror_r(errnum, buf, buflen) == 0)
      91                 :           6 :                 return buf;
      92                 :           0 :         return NULL;                            /* let caller deal with failure */
      93                 :             : #else
      94                 :             :         /* GNU API */
      95                 :             :         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                 :           6 : }
     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                 :             :                 case EADDRINUSE:
     122                 :           0 :                         return "EADDRINUSE";
     123                 :             :                 case EADDRNOTAVAIL:
     124                 :           0 :                         return "EADDRNOTAVAIL";
     125                 :             :                 case EAFNOSUPPORT:
     126                 :           0 :                         return "EAFNOSUPPORT";
     127                 :             : #ifdef EAGAIN
     128                 :             :                 case EAGAIN:
     129                 :           0 :                         return "EAGAIN";
     130                 :             : #endif
     131                 :             : #ifdef EALREADY
     132                 :             :                 case EALREADY:
     133                 :           0 :                         return "EALREADY";
     134                 :             : #endif
     135                 :             :                 case EBADF:
     136                 :           0 :                         return "EBADF";
     137                 :             : #ifdef EBADMSG
     138                 :             :                 case EBADMSG:
     139                 :           0 :                         return "EBADMSG";
     140                 :             : #endif
     141                 :             :                 case EBUSY:
     142                 :           0 :                         return "EBUSY";
     143                 :             :                 case ECHILD:
     144                 :           0 :                         return "ECHILD";
     145                 :             :                 case ECONNABORTED:
     146                 :           0 :                         return "ECONNABORTED";
     147                 :             :                 case ECONNREFUSED:
     148                 :           0 :                         return "ECONNREFUSED";
     149                 :             :                 case ECONNRESET:
     150                 :           0 :                         return "ECONNRESET";
     151                 :             :                 case EDEADLK:
     152                 :           0 :                         return "EDEADLK";
     153                 :             :                 case EDOM:
     154                 :           0 :                         return "EDOM";
     155                 :             :                 case EEXIST:
     156                 :           0 :                         return "EEXIST";
     157                 :             :                 case EFAULT:
     158                 :           0 :                         return "EFAULT";
     159                 :             :                 case EFBIG:
     160                 :           0 :                         return "EFBIG";
     161                 :             :                 case EHOSTDOWN:
     162                 :           0 :                         return "EHOSTDOWN";
     163                 :             :                 case EHOSTUNREACH:
     164                 :           0 :                         return "EHOSTUNREACH";
     165                 :             :                 case EIDRM:
     166                 :           0 :                         return "EIDRM";
     167                 :             :                 case EINPROGRESS:
     168                 :           0 :                         return "EINPROGRESS";
     169                 :             :                 case EINTR:
     170                 :           0 :                         return "EINTR";
     171                 :             :                 case EINVAL:
     172                 :           0 :                         return "EINVAL";
     173                 :             :                 case EIO:
     174                 :           0 :                         return "EIO";
     175                 :             :                 case EISCONN:
     176                 :           0 :                         return "EISCONN";
     177                 :             :                 case EISDIR:
     178                 :           0 :                         return "EISDIR";
     179                 :             : #ifdef ELOOP
     180                 :             :                 case ELOOP:
     181                 :           0 :                         return "ELOOP";
     182                 :             : #endif
     183                 :             :                 case EMFILE:
     184                 :           0 :                         return "EMFILE";
     185                 :             :                 case EMLINK:
     186                 :           0 :                         return "EMLINK";
     187                 :             :                 case EMSGSIZE:
     188                 :           0 :                         return "EMSGSIZE";
     189                 :             :                 case ENAMETOOLONG:
     190                 :           0 :                         return "ENAMETOOLONG";
     191                 :             :                 case ENETDOWN:
     192                 :           0 :                         return "ENETDOWN";
     193                 :             :                 case ENETRESET:
     194                 :           0 :                         return "ENETRESET";
     195                 :             :                 case ENETUNREACH:
     196                 :           0 :                         return "ENETUNREACH";
     197                 :             :                 case ENFILE:
     198                 :           0 :                         return "ENFILE";
     199                 :             :                 case ENOBUFS:
     200                 :           0 :                         return "ENOBUFS";
     201                 :             :                 case ENODEV:
     202                 :           0 :                         return "ENODEV";
     203                 :             :                 case ENOENT:
     204                 :           0 :                         return "ENOENT";
     205                 :             :                 case ENOEXEC:
     206                 :           0 :                         return "ENOEXEC";
     207                 :             :                 case ENOMEM:
     208                 :           0 :                         return "ENOMEM";
     209                 :             :                 case ENOSPC:
     210                 :           0 :                         return "ENOSPC";
     211                 :             :                 case ENOSYS:
     212                 :           0 :                         return "ENOSYS";
     213                 :             :                 case ENOTCONN:
     214                 :           0 :                         return "ENOTCONN";
     215                 :             :                 case ENOTDIR:
     216                 :           0 :                         return "ENOTDIR";
     217                 :             :                 case ENOTEMPTY:
     218                 :           0 :                         return "ENOTEMPTY";
     219                 :             :                 case ENOTSOCK:
     220                 :           0 :                         return "ENOTSOCK";
     221                 :             : #ifdef ENOTSUP
     222                 :             :                 case ENOTSUP:
     223                 :           0 :                         return "ENOTSUP";
     224                 :             : #endif
     225                 :             :                 case ENOTTY:
     226                 :           0 :                         return "ENOTTY";
     227                 :             :                 case ENXIO:
     228                 :           0 :                         return "ENXIO";
     229                 :             : #if defined(EOPNOTSUPP) && (!defined(ENOTSUP) || (EOPNOTSUPP != ENOTSUP))
     230                 :             :                 case EOPNOTSUPP:
     231                 :           0 :                         return "EOPNOTSUPP";
     232                 :             : #endif
     233                 :             : #ifdef EOVERFLOW
     234                 :             :                 case EOVERFLOW:
     235                 :           0 :                         return "EOVERFLOW";
     236                 :             : #endif
     237                 :             :                 case EPERM:
     238                 :           0 :                         return "EPERM";
     239                 :             :                 case EPIPE:
     240                 :           0 :                         return "EPIPE";
     241                 :             :                 case EPROTONOSUPPORT:
     242                 :           0 :                         return "EPROTONOSUPPORT";
     243                 :             :                 case ERANGE:
     244                 :           0 :                         return "ERANGE";
     245                 :             : #ifdef EROFS
     246                 :             :                 case EROFS:
     247                 :           0 :                         return "EROFS";
     248                 :             : #endif
     249                 :             :                 case ESRCH:
     250                 :           0 :                         return "ESRCH";
     251                 :             :                 case ETIMEDOUT:
     252                 :           0 :                         return "ETIMEDOUT";
     253                 :             : #ifdef ETXTBSY
     254                 :             :                 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                 :             :                 case EXDEV:
     262                 :           0 :                         return "EXDEV";
     263                 :             :         }
     264                 :             : 
     265                 :           0 :         return NULL;
     266                 :           0 : }
     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.3.2-1