diff options
Diffstat (limited to 'src/nxt_errno.c')
-rw-r--r-- | src/nxt_errno.c | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/src/nxt_errno.c b/src/nxt_errno.c new file mode 100644 index 00000000..64e043e5 --- /dev/null +++ b/src/nxt_errno.c @@ -0,0 +1,152 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) NGINX, Inc. + */ + +#include <nxt_main.h> + + +/* + * The strerror() messages are copied because: + * + * 1) strerror() and strerror_r() functions are not Async-Signal-Safe, + * therefore, they can not be used in signal handlers; + * + * 2) a direct sys_errlist[] array may be used instead of these functions, + * but Linux linker warns about this usage: + * + * warning: `sys_errlist' is deprecated; use `strerror' or `strerror_r' instead + * warning: `sys_nerr' is deprecated; use `strerror' or `strerror_r' instead + * + * causing false bug reports. + */ + +static u_char *nxt_bootstrap_strerror(nxt_err_t err, u_char *errstr, + size_t size); +static u_char *nxt_runtime_strerror(nxt_err_t err, u_char *errstr, size_t size); + + +nxt_strerror_t nxt_strerror = nxt_bootstrap_strerror; +static nxt_str_t *nxt_sys_errlist; +static nxt_uint_t nxt_sys_nerr; + + +nxt_int_t +nxt_strerror_start(void) +{ + char *msg; + u_char *p; + size_t size, len, n; + nxt_uint_t err, invalid; + + /* The last entry. */ + size = sizeof("Unknown error") - 1; + + /* + * Linux has holes for error codes 41 and 58, so the loop + * stops only after 100 invalid codes in succession. + */ + + for (invalid = 0; invalid < 100 && nxt_sys_nerr < 65536; nxt_sys_nerr++) { + + nxt_set_errno(0); + msg = strerror((int) nxt_sys_nerr); + + /* + * strerror() behaviour on passing invalid error code depends + * on OS and version: + * Linux returns "Unknown error NN"; + * FreeBSD, NetBSD and OpenBSD return "Unknown error: NN" + * and set errno to EINVAL; + * Solaris 10 returns "Unknown error" and sets errno to EINVAL; + * Solaris 9 returns "Unknown error"; + * Solaris 2 returns NULL; + * MacOSX returns "Unknown error: NN"; + * AIX returns "Error NNN occurred."; + * HP-UX returns "Unknown error" for invalid codes lesser than 250 + * or empty string for larger codes. + */ + + if (msg == NULL) { + invalid++; + continue; + } + + len = nxt_strlen(msg); + size += len; + + if (len == 0 /* HP-UX empty strings. */ + || nxt_errno == NXT_EINVAL + || nxt_memcmp(msg, "Unknown error", 13) == 0) + { + invalid++; + continue; + } + +#if (NXT_AIX) + + if (nxt_memcmp(msg, "Error ", 6) == 0 + && nxt_memcmp(msg + len - 10, " occurred.", 9) == 0) + { + invalid++; + continue; + } + +#endif + } + + nxt_sys_nerr -= invalid; + + nxt_main_log_debug("sys_nerr: %d", nxt_sys_nerr); + + n = (nxt_sys_nerr + 1) * sizeof(nxt_str_t); + + nxt_sys_errlist = nxt_malloc(n + size); + if (nxt_sys_errlist == NULL) { + return NXT_ERROR; + } + + p = (u_char *) nxt_sys_errlist + n; + + for (err = 0; err < nxt_sys_nerr; err++) { + msg = strerror((int) err); + len = nxt_strlen(msg); + + nxt_sys_errlist[err].len = len; + nxt_sys_errlist[err].data = p; + + p = nxt_cpymem(p, msg, len); + } + + nxt_sys_errlist[err].len = 13; + nxt_sys_errlist[err].data = p; + nxt_memcpy(p, "Unknown error", 13); + + nxt_strerror = nxt_runtime_strerror; + + return NXT_OK; +} + + +static u_char * +nxt_bootstrap_strerror(nxt_err_t err, u_char *errstr, size_t size) +{ + return nxt_cpystrn(errstr, (u_char *) strerror(err), size); +} + + +static u_char * +nxt_runtime_strerror(nxt_err_t err, u_char *errstr, size_t size) +{ + nxt_str_t *msg; + nxt_uint_t n; + + n = nxt_min((nxt_uint_t) err, nxt_sys_nerr); + + msg = &nxt_sys_errlist[n]; + + size = nxt_min(size, msg->len); + + return nxt_cpymem(errstr, msg->data, size); +} |