PostgreSQL Source Code git master
strerror.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * strerror.c
4 * Replacements for standard strerror() and strerror_r() functions
5 *
6 * Portions Copyright (c) 1996-2025, 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
24static char *gnuish_strerror_r(int errnum, char *buf, size_t buflen);
25static char *get_errno_symbol(int errnum);
26#ifdef WIN32
27static 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 */
34char *
35pg_strerror(int errnum)
36{
37 static char errorstr_buf[PG_STRERROR_R_BUFLEN];
38
39 return pg_strerror_r(errnum, errorstr_buf, sizeof(errorstr_buf));
40}
41
42/*
43 * A slightly cleaned-up version of strerror_r()
44 */
45char *
46pg_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 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 if (str == NULL || *str == '\0' || *str == '?')
68 str = get_errno_symbol(errnum);
69
70 if (str == NULL)
71 {
72 snprintf(buf, buflen, _("operating system error %d"), errnum);
73 str = buf;
74 }
75
76 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 */
84static char *
85gnuish_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 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 */
112static char *
114{
115 switch (errnum)
116 {
117 case E2BIG:
118 return "E2BIG";
119 case EACCES:
120 return "EACCES";
121 case EADDRINUSE:
122 return "EADDRINUSE";
123 case EADDRNOTAVAIL:
124 return "EADDRNOTAVAIL";
125 case EAFNOSUPPORT:
126 return "EAFNOSUPPORT";
127#ifdef EAGAIN
128 case EAGAIN:
129 return "EAGAIN";
130#endif
131#ifdef EALREADY
132 case EALREADY:
133 return "EALREADY";
134#endif
135 case EBADF:
136 return "EBADF";
137#ifdef EBADMSG
138 case EBADMSG:
139 return "EBADMSG";
140#endif
141 case EBUSY:
142 return "EBUSY";
143 case ECHILD:
144 return "ECHILD";
145 case ECONNABORTED:
146 return "ECONNABORTED";
147 case ECONNREFUSED:
148 return "ECONNREFUSED";
149 case ECONNRESET:
150 return "ECONNRESET";
151 case EDEADLK:
152 return "EDEADLK";
153 case EDOM:
154 return "EDOM";
155 case EEXIST:
156 return "EEXIST";
157 case EFAULT:
158 return "EFAULT";
159 case EFBIG:
160 return "EFBIG";
161 case EHOSTDOWN:
162 return "EHOSTDOWN";
163 case EHOSTUNREACH:
164 return "EHOSTUNREACH";
165 case EIDRM:
166 return "EIDRM";
167 case EINPROGRESS:
168 return "EINPROGRESS";
169 case EINTR:
170 return "EINTR";
171 case EINVAL:
172 return "EINVAL";
173 case EIO:
174 return "EIO";
175 case EISCONN:
176 return "EISCONN";
177 case EISDIR:
178 return "EISDIR";
179#ifdef ELOOP
180 case ELOOP:
181 return "ELOOP";
182#endif
183 case EMFILE:
184 return "EMFILE";
185 case EMLINK:
186 return "EMLINK";
187 case EMSGSIZE:
188 return "EMSGSIZE";
189 case ENAMETOOLONG:
190 return "ENAMETOOLONG";
191 case ENETDOWN:
192 return "ENETDOWN";
193 case ENETRESET:
194 return "ENETRESET";
195 case ENETUNREACH:
196 return "ENETUNREACH";
197 case ENFILE:
198 return "ENFILE";
199 case ENOBUFS:
200 return "ENOBUFS";
201 case ENODEV:
202 return "ENODEV";
203 case ENOENT:
204 return "ENOENT";
205 case ENOEXEC:
206 return "ENOEXEC";
207 case ENOMEM:
208 return "ENOMEM";
209 case ENOSPC:
210 return "ENOSPC";
211 case ENOSYS:
212 return "ENOSYS";
213 case ENOTCONN:
214 return "ENOTCONN";
215 case ENOTDIR:
216 return "ENOTDIR";
217 case ENOTEMPTY:
218 return "ENOTEMPTY";
219 case ENOTSOCK:
220 return "ENOTSOCK";
221#ifdef ENOTSUP
222 case ENOTSUP:
223 return "ENOTSUP";
224#endif
225 case ENOTTY:
226 return "ENOTTY";
227 case ENXIO:
228 return "ENXIO";
229#if defined(EOPNOTSUPP) && (!defined(ENOTSUP) || (EOPNOTSUPP != ENOTSUP))
230 case EOPNOTSUPP:
231 return "EOPNOTSUPP";
232#endif
233#ifdef EOVERFLOW
234 case EOVERFLOW:
235 return "EOVERFLOW";
236#endif
237 case EPERM:
238 return "EPERM";
239 case EPIPE:
240 return "EPIPE";
241 case EPROTONOSUPPORT:
242 return "EPROTONOSUPPORT";
243 case ERANGE:
244 return "ERANGE";
245#ifdef EROFS
246 case EROFS:
247 return "EROFS";
248#endif
249 case ESRCH:
250 return "ESRCH";
251 case ETIMEDOUT:
252 return "ETIMEDOUT";
253#ifdef ETXTBSY
254 case ETXTBSY:
255 return "ETXTBSY";
256#endif
257#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
258 case EWOULDBLOCK:
259 return "EWOULDBLOCK";
260#endif
261 case EXDEV:
262 return "EXDEV";
263 }
264
265 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 */
274static char *
275win32_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 */
#define _(x)
Definition: elog.c:90
const char * str
static char * buf
Definition: pg_test_fsync.c:72
#define PG_STRERROR_R_BUFLEN
Definition: port.h:256
#define strerror
Definition: port.h:251
#define snprintf
Definition: port.h:238
#define strerror_r
Definition: port.h:255
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
#define EOVERFLOW
Definition: private.h:41
#define ENOTSUP
Definition: private.h:38
static char * get_errno_symbol(int errnum)
Definition: strerror.c:113
char * pg_strerror_r(int errnum, char *buf, size_t buflen)
Definition: strerror.c:46
static char * gnuish_strerror_r(int errnum, char *buf, size_t buflen)
Definition: strerror.c:85
char * pg_strerror(int errnum)
Definition: strerror.c:35
#define EISCONN
Definition: win32_port.h:378
#define ENETUNREACH
Definition: win32_port.h:402
#define ECONNABORTED
Definition: win32_port.h:372
#define EINTR
Definition: win32_port.h:364
#define EWOULDBLOCK
Definition: win32_port.h:370
#define EOPNOTSUPP
Definition: win32_port.h:388
#define EAFNOSUPPORT
Definition: win32_port.h:368
#define EHOSTUNREACH
Definition: win32_port.h:396
#define EADDRNOTAVAIL
Definition: win32_port.h:392
#define ETIMEDOUT
Definition: win32_port.h:406
#define EADDRINUSE
Definition: win32_port.h:390
#define EINPROGRESS
Definition: win32_port.h:376
#define ENETRESET
Definition: win32_port.h:400
#define ENOBUFS
Definition: win32_port.h:380
#define EHOSTDOWN
Definition: win32_port.h:394
#define ENETDOWN
Definition: win32_port.h:398
#define ECONNREFUSED
Definition: win32_port.h:384
#define EPROTONOSUPPORT
Definition: win32_port.h:382
#define EIDRM
Definition: win32_port.h:102
#define ECONNRESET
Definition: win32_port.h:374
#define ENOTSOCK
Definition: win32_port.h:386
#define EMSGSIZE
Definition: win32_port.h:366
#define EAGAIN
Definition: win32_port.h:362
#define ENOTCONN
Definition: win32_port.h:404