1 /*-------------------------------------------------------------------------
4 * Replacements for standard strerror() and strerror_r() functions
6 * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
13 *-------------------------------------------------------------------------
18 * Within this file, "strerror" means the platform's function not pg_strerror,
19 * and likewise for "strerror_r"
24 static char *gnuish_strerror_r(int errnum
, char *buf
, size_t buflen
);
25 static char *get_errno_symbol(int errnum
);
27 static char *win32_socket_strerror(int errnum
, char *buf
, size_t buflen
);
32 * A slightly cleaned-up version of strerror()
35 pg_strerror(int errnum
)
37 static char errorstr_buf
[PG_STRERROR_R_BUFLEN
];
39 return pg_strerror_r(errnum
, errorstr_buf
, sizeof(errorstr_buf
));
43 * A slightly cleaned-up version of strerror_r()
46 pg_strerror_r(int errnum
, char *buf
, size_t buflen
)
50 /* If it's a Windows Winsock error, that needs special handling */
52 /* Winsock error code range, per WinError.h */
53 if (errnum
>= 10000 && errnum
<= 11999)
54 return win32_socket_strerror(errnum
, buf
, buflen
);
57 /* Try the platform's strerror_r(), or maybe just strerror() */
58 str
= gnuish_strerror_r(errnum
, buf
, buflen
);
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.
67 if (str
== NULL
|| *str
== '\0' || *str
== '?')
68 str
= get_errno_symbol(errnum
);
72 snprintf(buf
, buflen
, _("operating system error %d"), errnum
);
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.
85 gnuish_strerror_r(int errnum
, char *buf
, size_t buflen
)
87 #ifdef HAVE_STRERROR_R
90 if (strerror_r(errnum
, buf
, buflen
) == 0)
92 return NULL
; /* let caller deal with failure */
95 return strerror_r(errnum
, buf
, buflen
);
97 #else /* !HAVE_STRERROR_R */
98 char *sbuf
= strerror(errnum
);
100 if (sbuf
== NULL
) /* can this still happen anywhere? */
102 /* To minimize thread-unsafety hazard, copy into caller's buffer */
103 strlcpy(buf
, sbuf
, buflen
);
109 * Returns a symbol (e.g. "ENOENT") for an errno code.
110 * Returns NULL if the code is unrecognized.
113 get_errno_symbol(int errnum
)
124 return "EADDRNOTAVAIL";
126 return "EAFNOSUPPORT";
146 return "ECONNABORTED";
148 return "ECONNREFUSED";
164 return "EHOSTUNREACH";
168 return "EINPROGRESS";
190 return "ENAMETOOLONG";
196 return "ENETUNREACH";
217 #if defined(ENOTEMPTY) && (ENOTEMPTY != EEXIST) /* same code on AIX */
231 #if defined(EOPNOTSUPP) && (!defined(ENOTSUP) || (EOPNOTSUPP != ENOTSUP))
243 case EPROTONOSUPPORT
:
244 return "EPROTONOSUPPORT";
259 #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
261 return "EWOULDBLOCK";
274 * Windows' strerror() doesn't know the Winsock codes, so handle them this way
277 win32_socket_strerror(int errnum
, char *buf
, size_t buflen
)
279 static HANDLE handleDLL
= INVALID_HANDLE_VALUE
;
281 if (handleDLL
== INVALID_HANDLE_VALUE
)
283 handleDLL
= LoadLibraryEx("netmsg.dll", NULL
,
284 DONT_RESOLVE_DLL_REFERENCES
| LOAD_LIBRARY_AS_DATAFILE
);
285 if (handleDLL
== NULL
)
287 snprintf(buf
, buflen
,
288 "winsock error %d (could not load netmsg.dll to translate: error code %lu)",
289 errnum
, GetLastError());
294 ZeroMemory(buf
, buflen
);
295 if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS
|
296 FORMAT_MESSAGE_FROM_SYSTEM
|
297 FORMAT_MESSAGE_FROM_HMODULE
,
300 MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
),
305 /* Failed to get id */
306 snprintf(buf
, buflen
, "unrecognized winsock error %d", errnum
);