]> granicus.if.org Git - postgresql/commitdiff
Be more robust when strerror() doesn't give a useful result.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 7 Nov 2013 21:33:25 +0000 (16:33 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 7 Nov 2013 21:33:25 +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 a40b343ebcfb478515659bc52d84ecccd8ca97a5..831fe07120f6beb63d4ee7f13587e43a830be00f 100644 (file)
@@ -170,6 +170,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);
@@ -2784,7 +2785,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;
 
@@ -2796,10 +2797,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),
                /*------
@@ -2812,6 +2819,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