Improve notation of BuiltinTrancheNames
[pgsql.git] / src / port / strerror.c
blob1070a49802e25af575eb70680c6acb6e090abd55
1 /*-------------------------------------------------------------------------
3 * strerror.c
4 * Replacements for standard strerror() and strerror_r() functions
6 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
10 * IDENTIFICATION
11 * src/port/strerror.c
13 *-------------------------------------------------------------------------
15 #include "c.h"
18 * Within this file, "strerror" means the platform's function not pg_strerror,
19 * and likewise for "strerror_r"
21 #undef strerror
22 #undef strerror_r
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
32 * A slightly cleaned-up version of strerror()
34 char *
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()
45 char *
46 pg_strerror_r(int errnum, char *buf, size_t buflen)
48 char *str;
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
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);
70 if (str == NULL)
72 snprintf(buf, buflen, _("operating system error %d"), errnum);
73 str = buf;
76 return str;
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.
84 static char *
85 gnuish_strerror_r(int errnum, char *buf, size_t buflen)
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);
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
109 * Returns a symbol (e.g. "ENOENT") for an errno code.
110 * Returns NULL if the code is unrecognized.
112 static char *
113 get_errno_symbol(int errnum)
115 switch (errnum)
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 #if defined(ENOTEMPTY) && (ENOTEMPTY != EEXIST) /* same code on AIX */
218 case ENOTEMPTY:
219 return "ENOTEMPTY";
220 #endif
221 case ENOTSOCK:
222 return "ENOTSOCK";
223 #ifdef ENOTSUP
224 case ENOTSUP:
225 return "ENOTSUP";
226 #endif
227 case ENOTTY:
228 return "ENOTTY";
229 case ENXIO:
230 return "ENXIO";
231 #if defined(EOPNOTSUPP) && (!defined(ENOTSUP) || (EOPNOTSUPP != ENOTSUP))
232 case EOPNOTSUPP:
233 return "EOPNOTSUPP";
234 #endif
235 #ifdef EOVERFLOW
236 case EOVERFLOW:
237 return "EOVERFLOW";
238 #endif
239 case EPERM:
240 return "EPERM";
241 case EPIPE:
242 return "EPIPE";
243 case EPROTONOSUPPORT:
244 return "EPROTONOSUPPORT";
245 case ERANGE:
246 return "ERANGE";
247 #ifdef EROFS
248 case EROFS:
249 return "EROFS";
250 #endif
251 case ESRCH:
252 return "ESRCH";
253 case ETIMEDOUT:
254 return "ETIMEDOUT";
255 #ifdef ETXTBSY
256 case ETXTBSY:
257 return "ETXTBSY";
258 #endif
259 #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
260 case EWOULDBLOCK:
261 return "EWOULDBLOCK";
262 #endif
263 case EXDEV:
264 return "EXDEV";
267 return NULL;
271 #ifdef WIN32
274 * Windows' strerror() doesn't know the Winsock codes, so handle them this way
276 static char *
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());
290 return buf;
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)
305 /* Failed to get id */
306 snprintf(buf, buflen, "unrecognized winsock error %d", errnum);
309 return buf;
312 #endif /* WIN32 */