*/
if (!use_utf_8)
utf_8_to_acp_truncated(errbuf);
-#elif defined(HAVE_GNU_STRERROR_R)
- /*
- * We have a GNU-style strerror_r(), which is *not* guaranteed to
- * do anything to the buffer handed to it, and which returns a
- * pointer to the error string, which may or may not be in
- * the buffer.
- *
- * It is, however, guaranteed to succeed.
- */
- char strerror_buf[PCAP_ERRBUF_SIZE];
- char *errstring = strerror_r(errnum, strerror_buf, PCAP_ERRBUF_SIZE);
- snprintf(p, errbuflen_remaining, "%s", errstring);
-#elif defined(HAVE_POSIX_STRERROR_R)
- /*
- * We have a POSIX-style strerror_r(), which is guaranteed to fill
- * in the buffer, but is not guaranteed to succeed.
- */
- int err = strerror_r(errnum, p, errbuflen_remaining);
- if (err == EINVAL) {
- /*
- * UNIX 03 says this isn't guaranteed to produce a
- * fallback error message.
- */
- snprintf(p, errbuflen_remaining, "Unknown error: %d",
- errnum);
- } else if (err == ERANGE) {
- /*
- * UNIX 03 says this isn't guaranteed to produce a
- * fallback error message.
- */
- snprintf(p, errbuflen_remaining,
- "Message for error %d is too long", errnum);
- }
#else
/*
- * We have neither _wcserror_s() nor strerror_r(), so we're
- * stuck with using pcap_strerror().
+ * Either Windows without _wcserror_s() or not Windows. Let pcap_strerror()
+ * solve the non-UTF-16 part of this problem space.
*/
snprintf(p, errbuflen_remaining, "%s", pcap_strerror(errnum));
#endif
}
/*
- * Not all systems have strerror().
+ * A long time ago the purpose of this function was to hide the difference
+ * between those Unix-like OSes that implemented strerror() and those that
+ * didn't. All the currently supported OSes implement strerror(), which is in
+ * POSIX.1-2001, uniformly and that particular problem no longer exists. But
+ * now they implement a few incompatible thread-safe variants of strerror(),
+ * and hiding that difference is the current purpose of this function.
*/
const char *
pcap_strerror(int errnum)
{
-#ifdef HAVE_STRERROR
#ifdef _WIN32
static thread_local char errbuf[PCAP_ERRBUF_SIZE];
errno_t err = strerror_s(errbuf, PCAP_ERRBUF_SIZE, errnum);
if (err != 0) /* err = 0 if successful */
pcapint_strlcpy(errbuf, "strerror_s() error", PCAP_ERRBUF_SIZE);
return (errbuf);
+#elif defined(HAVE_GNU_STRERROR_R)
+ /*
+ * We have a GNU-style strerror_r(), which is *not* guaranteed to
+ * do anything to the buffer handed to it, and which returns a
+ * pointer to the error string, which may or may not be in
+ * the buffer.
+ *
+ * It is, however, guaranteed to succeed.
+ *
+ * At the time of this writing this applies to the following cases,
+ * each of which allows to use either the GNU implementation or the
+ * POSIX implementation, and this source tree defines _GNU_SOURCE to
+ * use the GNU implementation:
+ * - Hurd
+ * - Linux with GNU libc
+ * - Linux with uClibc-ng
+ */
+ static thread_local char errbuf[PCAP_ERRBUF_SIZE];
+ return strerror_r(errnum, errbuf, PCAP_ERRBUF_SIZE);
+#elif defined(HAVE_POSIX_STRERROR_R)
+ /*
+ * We have a POSIX-style strerror_r(), which is guaranteed to fill
+ * in the buffer, but is not guaranteed to succeed.
+ *
+ * At the time of this writing this applies to the following cases:
+ * - AIX 7
+ * - FreeBSD
+ * - Haiku
+ * - HP-UX 11
+ * - illumos
+ * - Linux with musl libc
+ * - macOS
+ * - NetBSD
+ * - OpenBSD
+ * - Solaris 10 & 11
+ */
+ static thread_local char errbuf[PCAP_ERRBUF_SIZE];
+ int err = strerror_r(errnum, errbuf, PCAP_ERRBUF_SIZE);
+ switch (err) {
+ case EINVAL:
+ /*
+ * UNIX 03 says this isn't guaranteed to produce a
+ * fallback error message.
+ */
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "Unknown error: %d", errnum);
+ break;
+ case ERANGE:
+ /*
+ * UNIX 03 says this isn't guaranteed to produce a
+ * fallback error message.
+ */
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "Message for error %d is too long", errnum);
+ break;
+ default:
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "strerror_r(%d, ...) unexpectedly returned %d",
+ errnum, err);
+ }
+ return errbuf;
#else
+ /*
+ * At the time of this writing every supported OS implements strerror()
+ * and at least one thread-safe variant thereof, so this is a very
+ * unlikely last-resort branch. Particular implementations of strerror()
+ * may be thread-safe, but this is neither required nor guaranteed.
+ */
return (strerror(errnum));
#endif /* _WIN32 */
-#else
- extern int sys_nerr;
- extern const char *const sys_errlist[];
- static thread_local char errbuf[PCAP_ERRBUF_SIZE];
-
- if ((unsigned int)errnum < sys_nerr)
- return ((char *)sys_errlist[errnum]);
- (void)snprintf(errbuf, sizeof errbuf, "Unknown error: %d", errnum);
- return (errbuf);
-#endif
}
int
.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
.\"
-.TH PCAP_STRERROR 3PCAP "3 January 2014"
+.TH PCAP_STRERROR 3PCAP "12 March 2024"
.SH NAME
pcap_strerror \- convert an errno value to a string
.SH SYNOPSIS
.ft
.fi
.SH DESCRIPTION
-.BR pcap_strerror ()
-is provided in case
-.BR strerror (3)
-isn't available. It returns an error message string corresponding to
+This function returns an error message string corresponding to
.IR error .
+It uses either
+.BR strerror (3)
+or its thread-safe variant if one is available, which currently is the case in
+every supported OS.
+.SH BACKWARD COMPATIBILITY
+This function was not thread-safe in libpcap before 1.8.1 on Windows and
+in libpcap before 1.11.0 on all other OSes.
.SH SEE ALSO
.BR pcap (3PCAP)