From e3480438e89f74019f271b1b5501bb9eed2e0d2a Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Thu, 7 Nov 2013 16:33:18 -0500 Subject: [PATCH] Be more robust when strerror() doesn't give a useful result. 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 | 187 ++++++++++++++++++++++++++++++++- 1 file changed, 183 insertions(+), 4 deletions(-) diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c index cebfeebad7..35cb875a12 100644 --- a/src/backend/utils/error/elog.c +++ b/src/backend/utils/error/elog.c @@ -172,6 +172,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); @@ -2928,7 +2929,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; @@ -2940,10 +2941,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), /*------ @@ -2956,6 +2963,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 -- 2.40.0