Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Be more robust when strerror() doesn't give a useful result.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 7 Nov 2013 21:33:39 +0000 (16:33 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 7 Nov 2013 21:33:39 +0000 (16:33 -0500)
Back-patch commits 8e68816cc2567642c6fcca4eaac66c25e0ae5ced and
8dace66e0735ca39b779922d02c24ea2686e6521 into the stable branches.
Buildfarm testing revealed no great portability surprises, and it
seems useful to have this robustness improvement in all branches.

src/backend/utils/error/elog.c

index 6b3ba2a31cab2d0c9cbb53a09b3638c4f37ab2d4..6c4146a21ccc7d4ef632ae0fa57766a1b29b42f7 100644 (file)
@@ -149,6 +149,7 @@ static void send_message_to_server_log(ErrorData *edata);
 static void send_message_to_frontend(ErrorData *edata);
 static char *expand_fmt_string(const char *fmt, ErrorData *edata);
 static const char *useful_strerror(int errnum);
+static const char *get_errno_symbol(int errnum);
 static const char *error_severity(int elevel);
 static void append_with_tabs(StringInfo buf, const char *str);
 static bool is_log_level_output(int elevel, int log_min_level);
@@ -2551,7 +2552,7 @@ expand_fmt_string(const char *fmt, ErrorData *edata)
 static const char *
 useful_strerror(int errnum)
 {
-   /* this buffer is only used if errno has a bogus value */
+   /* this buffer is only used if strerror() and get_errno_symbol() fail */
    static char errorstr_buf[48];
    const char *str;
 
@@ -2563,10 +2564,16 @@ useful_strerror(int errnum)
    str = strerror(errnum);
 
    /*
-    * Some strerror()s return an empty string for out-of-range errno. This is
-    * ANSI C spec compliant, but not exactly useful.
+    * Some strerror()s return an empty string for out-of-range errno.  This
+    * is ANSI C spec compliant, but not exactly useful.  Also, we may get
+    * back strings of question marks if libc cannot transcode the message to
+    * the codeset specified by LC_CTYPE.  If we get nothing useful, first try
+    * get_errno_symbol(), and if that fails, print the numeric errno.
     */
-   if (str == NULL || *str == '\0')
+   if (str == NULL || *str == '\0' || *str == '?')
+       str = get_errno_symbol(errnum);
+
+   if (str == NULL)
    {
        snprintf(errorstr_buf, sizeof(errorstr_buf),
        /*------
@@ -2579,6 +2586,178 @@ useful_strerror(int errnum)
    return str;
 }
 
+/*
+ * Returns a symbol (e.g. "ENOENT") for an errno code.
+ * Returns NULL if the code is unrecognized.
+ */
+static const char *
+get_errno_symbol(int errnum)
+{
+   switch (errnum)
+   {
+       case E2BIG:
+           return "E2BIG";
+       case EACCES:
+           return "EACCES";
+#ifdef EADDRINUSE
+       case EADDRINUSE:
+           return "EADDRINUSE";
+#endif
+#ifdef EADDRNOTAVAIL
+       case EADDRNOTAVAIL:
+           return "EADDRNOTAVAIL";
+#endif
+       case EAFNOSUPPORT:
+           return "EAFNOSUPPORT";
+#ifdef EAGAIN
+       case EAGAIN:
+           return "EAGAIN";
+#endif
+#ifdef EALREADY
+       case EALREADY:
+           return "EALREADY";
+#endif
+       case EBADF:
+           return "EBADF";
+#ifdef EBADMSG
+       case EBADMSG:
+           return "EBADMSG";
+#endif
+       case EBUSY:
+           return "EBUSY";
+       case ECHILD:
+           return "ECHILD";
+#ifdef ECONNABORTED
+       case ECONNABORTED:
+           return "ECONNABORTED";
+#endif
+       case ECONNREFUSED:
+           return "ECONNREFUSED";
+#ifdef ECONNRESET
+       case ECONNRESET:
+           return "ECONNRESET";
+#endif
+       case EDEADLK:
+           return "EDEADLK";
+       case EDOM:
+           return "EDOM";
+       case EEXIST:
+           return "EEXIST";
+       case EFAULT:
+           return "EFAULT";
+       case EFBIG:
+           return "EFBIG";
+#ifdef EHOSTUNREACH
+       case EHOSTUNREACH:
+           return "EHOSTUNREACH";
+#endif
+       case EIDRM:
+           return "EIDRM";
+       case EINPROGRESS:
+           return "EINPROGRESS";
+       case EINTR:
+           return "EINTR";
+       case EINVAL:
+           return "EINVAL";
+       case EIO:
+           return "EIO";
+#ifdef EISCONN
+       case EISCONN:
+           return "EISCONN";
+#endif
+       case EISDIR:
+           return "EISDIR";
+#ifdef ELOOP
+       case ELOOP:
+           return "ELOOP";
+#endif
+       case EMFILE:
+           return "EMFILE";
+       case EMLINK:
+           return "EMLINK";
+       case EMSGSIZE:
+           return "EMSGSIZE";
+       case ENAMETOOLONG:
+           return "ENAMETOOLONG";
+       case ENFILE:
+           return "ENFILE";
+       case ENOBUFS:
+           return "ENOBUFS";
+       case ENODEV:
+           return "ENODEV";
+       case ENOENT:
+           return "ENOENT";
+       case ENOEXEC:
+           return "ENOEXEC";
+       case ENOMEM:
+           return "ENOMEM";
+       case ENOSPC:
+           return "ENOSPC";
+       case ENOSYS:
+           return "ENOSYS";
+#ifdef ENOTCONN
+       case ENOTCONN:
+           return "ENOTCONN";
+#endif
+       case ENOTDIR:
+           return "ENOTDIR";
+#if defined(ENOTEMPTY) && (ENOTEMPTY != EEXIST) /* same code on AIX */
+       case ENOTEMPTY:
+           return "ENOTEMPTY";
+#endif
+#ifdef ENOTSOCK
+       case ENOTSOCK:
+           return "ENOTSOCK";
+#endif
+#ifdef ENOTSUP
+       case ENOTSUP:
+           return "ENOTSUP";
+#endif
+       case ENOTTY:
+           return "ENOTTY";
+       case ENXIO:
+           return "ENXIO";
+#if defined(EOPNOTSUPP) && (!defined(ENOTSUP) || (EOPNOTSUPP != ENOTSUP))
+       case EOPNOTSUPP:
+           return "EOPNOTSUPP";
+#endif
+#ifdef EOVERFLOW
+       case EOVERFLOW:
+           return "EOVERFLOW";
+#endif
+       case EPERM:
+           return "EPERM";
+       case EPIPE:
+           return "EPIPE";
+       case EPROTONOSUPPORT:
+           return "EPROTONOSUPPORT";
+       case ERANGE:
+           return "ERANGE";
+#ifdef EROFS
+       case EROFS:
+           return "EROFS";
+#endif
+       case ESRCH:
+           return "ESRCH";
+#ifdef ETIMEDOUT
+       case ETIMEDOUT:
+           return "ETIMEDOUT";
+#endif
+#ifdef ETXTBSY
+       case ETXTBSY:
+           return "ETXTBSY";
+#endif
+#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
+       case EWOULDBLOCK:
+           return "EWOULDBLOCK";
+#endif
+       case EXDEV:
+           return "EXDEV";
+   }
+
+   return NULL;
+}
+
 
 /*
  * error_severity --- get localized string representing elevel