Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 8e68816

Browse files
committed
Be more robust when strerror() doesn't give a useful result.
glibc, at least, is capable of returning "???" instead of anything useful if it doesn't like the setting of LC_CTYPE. If this happens, or in the previously-known case of strerror() returning an empty string, try to print the C macro name for the error code ("EACCES" etc). Only if we don't have the error code in our compiled-in list of popular error codes (which covers most though not quite all of what's called out in the POSIX spec) will we fall back to printing a numeric error code. This should simplify debugging. Note that this functionality is currently only provided for %m in backend ereport/elog messages. That may be sufficient, since we don't fool with the locale environment in frontend clients, but it's foreseeable that we might want similar code in libpq for instance. There was some talk of back-patching this, but let's see how the buildfarm likes it first. It seems likely that at least some of the POSIX-defined error code symbols don't exist on all platforms. I don't want to clutter the entire list with #ifdefs, but we may need more than are here now. MauMau, edited by me
1 parent bb45c64 commit 8e68816

File tree

1 file changed

+157
-4
lines changed

1 file changed

+157
-4
lines changed

src/backend/utils/error/elog.c

+157-4
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ static void send_message_to_server_log(ErrorData *edata);
173173
static void send_message_to_frontend(ErrorData *edata);
174174
static char *expand_fmt_string(const char *fmt, ErrorData *edata);
175175
static const char *useful_strerror(int errnum);
176+
static const char *get_errno_symbol(int errnum);
176177
static const char *error_severity(int elevel);
177178
static void append_with_tabs(StringInfo buf, const char *str);
178179
static bool is_log_level_output(int elevel, int log_min_level);
@@ -3206,7 +3207,7 @@ expand_fmt_string(const char *fmt, ErrorData *edata)
32063207
static const char *
32073208
useful_strerror(int errnum)
32083209
{
3209-
/* this buffer is only used if errno has a bogus value */
3210+
/* this buffer is only used if strerror() and get_errno_symbol() fail */
32103211
static char errorstr_buf[48];
32113212
const char *str;
32123213

@@ -3218,10 +3219,16 @@ useful_strerror(int errnum)
32183219
str = strerror(errnum);
32193220

32203221
/*
3221-
* Some strerror()s return an empty string for out-of-range errno. This is
3222-
* ANSI C spec compliant, but not exactly useful.
3222+
* Some strerror()s return an empty string for out-of-range errno. This
3223+
* is ANSI C spec compliant, but not exactly useful. Also, we may get
3224+
* back strings of question marks if libc cannot transcode the message to
3225+
* the codeset specified by LC_CTYPE. If we get nothing useful, first try
3226+
* get_errno_symbol(), and if that fails, print the numeric errno.
32233227
*/
3224-
if (str == NULL || *str == '\0')
3228+
if (str == NULL || *str == '\0' || *str == '?')
3229+
str = get_errno_symbol(errnum);
3230+
3231+
if (str == NULL)
32253232
{
32263233
snprintf(errorstr_buf, sizeof(errorstr_buf),
32273234
/*------
@@ -3234,6 +3241,152 @@ useful_strerror(int errnum)
32343241
return str;
32353242
}
32363243

3244+
/*
3245+
* Returns a symbol (e.g. "ENOENT") for an errno code.
3246+
* Returns NULL if the code is unrecognized.
3247+
*/
3248+
static const char *
3249+
get_errno_symbol(int errnum)
3250+
{
3251+
switch (errnum)
3252+
{
3253+
case E2BIG:
3254+
return "E2BIG";
3255+
case EACCES:
3256+
return "EACCES";
3257+
case EADDRINUSE:
3258+
return "EADDRINUSE";
3259+
case EADDRNOTAVAIL:
3260+
return "EADDRNOTAVAIL";
3261+
case EAFNOSUPPORT:
3262+
return "EAFNOSUPPORT";
3263+
#ifdef EAGAIN
3264+
case EAGAIN:
3265+
return "EAGAIN";
3266+
#endif
3267+
case EALREADY:
3268+
return "EALREADY";
3269+
case EBADF:
3270+
return "EBADF";
3271+
case EBADMSG:
3272+
return "EBADMSG";
3273+
case EBUSY:
3274+
return "EBUSY";
3275+
case ECHILD:
3276+
return "ECHILD";
3277+
case ECONNABORTED:
3278+
return "ECONNABORTED";
3279+
case ECONNREFUSED:
3280+
return "ECONNREFUSED";
3281+
#ifdef ECONNRESET
3282+
case ECONNRESET:
3283+
return "ECONNRESET";
3284+
#endif
3285+
case EDEADLK:
3286+
return "EDEADLK";
3287+
case EDOM:
3288+
return "EDOM";
3289+
case EEXIST:
3290+
return "EEXIST";
3291+
case EFAULT:
3292+
return "EFAULT";
3293+
case EFBIG:
3294+
return "EFBIG";
3295+
case EHOSTUNREACH:
3296+
return "EHOSTUNREACH";
3297+
case EIDRM:
3298+
return "EIDRM";
3299+
case EINPROGRESS:
3300+
return "EINPROGRESS";
3301+
case EINTR:
3302+
return "EINTR";
3303+
case EINVAL:
3304+
return "EINVAL";
3305+
case EIO:
3306+
return "EIO";
3307+
case EISCONN:
3308+
return "EISCONN";
3309+
case EISDIR:
3310+
return "EISDIR";
3311+
case ELOOP:
3312+
return "ELOOP";
3313+
case EMFILE:
3314+
return "EMFILE";
3315+
case EMLINK:
3316+
return "EMLINK";
3317+
case EMSGSIZE:
3318+
return "EMSGSIZE";
3319+
case ENAMETOOLONG:
3320+
return "ENAMETOOLONG";
3321+
case ENFILE:
3322+
return "ENFILE";
3323+
case ENOBUFS:
3324+
return "ENOBUFS";
3325+
case ENODEV:
3326+
return "ENODEV";
3327+
case ENOENT:
3328+
return "ENOENT";
3329+
case ENOEXEC:
3330+
return "ENOEXEC";
3331+
case ENOMEM:
3332+
return "ENOMEM";
3333+
case ENOSPC:
3334+
return "ENOSPC";
3335+
case ENOSYS:
3336+
return "ENOSYS";
3337+
case ENOTCONN:
3338+
return "ENOTCONN";
3339+
case ENOTDIR:
3340+
return "ENOTDIR";
3341+
#if defined(ENOTEMPTY) && (ENOTEMPTY != EEXIST) /* same code on AIX */
3342+
case ENOTEMPTY:
3343+
return "ENOTEMPTY";
3344+
#endif
3345+
case ENOTSOCK:
3346+
return "ENOTSOCK";
3347+
#ifdef ENOTSUP
3348+
case ENOTSUP:
3349+
return "ENOTSUP";
3350+
#endif
3351+
case ENOTTY:
3352+
return "ENOTTY";
3353+
case ENXIO:
3354+
return "ENXIO";
3355+
#if defined(EOPNOTSUPP) && (!defined(ENOTSUP) || (EOPNOTSUPP != ENOTSUP))
3356+
case EOPNOTSUPP:
3357+
return "EOPNOTSUPP";
3358+
#endif
3359+
case EOVERFLOW:
3360+
return "EOVERFLOW";
3361+
case EPERM:
3362+
return "EPERM";
3363+
case EPIPE:
3364+
return "EPIPE";
3365+
case EPROTONOSUPPORT:
3366+
return "EPROTONOSUPPORT";
3367+
case ERANGE:
3368+
return "ERANGE";
3369+
#ifdef EROFS
3370+
case EROFS:
3371+
return "EROFS";
3372+
#endif
3373+
case ESRCH:
3374+
return "ESRCH";
3375+
case ETIMEDOUT:
3376+
return "ETIMEDOUT";
3377+
case ETXTBSY:
3378+
return "ETXTBSY";
3379+
#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
3380+
case EWOULDBLOCK:
3381+
return "EWOULDBLOCK";
3382+
#endif
3383+
case EXDEV:
3384+
return "EXDEV";
3385+
}
3386+
3387+
return NULL;
3388+
}
3389+
32373390

32383391
/*
32393392
* error_severity --- get localized string representing elevel

0 commit comments

Comments
 (0)