blob: ca23b2d3f201edac07f5dbc38b45444bbeef86e3 [file] [log] [blame]
/*
* Copyright (C) Igor Sysoev
* Copyright (C) Nginx, Inc.
*/
#include <ngx_config.h>
#include <ngx_core.h>
static ngx_str_t ngx_unknown_error = ngx_string("Unknown error");
#if (NGX_HAVE_STRERRORDESC_NP)
/*
* The strerrordesc_np() function, introduced in glibc 2.32, is
* async-signal-safe. This makes it possible to use it directly,
* without copying error messages.
*/
u_char *
ngx_strerror(ngx_err_t err, u_char *errstr, size_t size)
{
size_t len;
const char *msg;
msg = strerrordesc_np(err);
if (msg == NULL) {
msg = (char *) ngx_unknown_error.data;
len = ngx_unknown_error.len;
} else {
len = ngx_strlen(msg);
}
size = ngx_min(size, len);
return ngx_cpymem(errstr, msg, size);
}
ngx_int_t
ngx_strerror_init(void)
{
return NGX_OK;
}
#else
/*
* The strerror() messages are copied because:
*
* 1) strerror() and strerror_r() functions are not Async-Signal-Safe,
* therefore, they cannot be used in signal handlers;
*
* 2) a direct sys_errlist[] array may be used instead of these functions,
* but Linux linker warns about its 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 ngx_str_t *ngx_sys_errlist;
static ngx_err_t ngx_first_error;
static ngx_err_t ngx_last_error;
u_char *
ngx_strerror(ngx_err_t err, u_char *errstr, size_t size)
{
ngx_str_t *msg;
if (err >= ngx_first_error && err < ngx_last_error) {
msg = &ngx_sys_errlist[err - ngx_first_error];
} else {
msg = &ngx_unknown_error;
}
size = ngx_min(size, msg->len);
return ngx_cpymem(errstr, msg->data, size);
}
ngx_int_t
ngx_strerror_init(void)
{
char *msg;
u_char *p;
size_t len;
ngx_err_t err;
#if (NGX_SYS_NERR)
ngx_first_error = 0;
ngx_last_error = NGX_SYS_NERR;
#elif (EPERM > 1000 && EPERM < 0x7fffffff - 1000)
/*
* If number of errors is not known, and EPERM error code has large
* but reasonable value, guess possible error codes based on the error
* messages returned by strerror(), starting from EPERM. Notably,
* this covers GNU/Hurd, where errors start at 0x40000001.
*/
for (err = EPERM; err > EPERM - 1000; err--) {
ngx_set_errno(0);
msg = strerror(err);
if (errno == EINVAL
|| msg == NULL
|| strncmp(msg, "Unknown error", 13) == 0)
{
continue;
}
ngx_first_error = err;
}
for (err = EPERM; err < EPERM + 1000; err++) {
ngx_set_errno(0);
msg = strerror(err);
if (errno == EINVAL
|| msg == NULL
|| strncmp(msg, "Unknown error", 13) == 0)
{
continue;
}
ngx_last_error = err + 1;
}
#else
/*
* If number of errors is not known, guess it based on the error
* messages returned by strerror().
*/
ngx_first_error = 0;
for (err = 0; err < 1000; err++) {
ngx_set_errno(0);
msg = strerror(err);
if (errno == EINVAL
|| msg == NULL
|| strncmp(msg, "Unknown error", 13) == 0)
{
continue;
}
ngx_last_error = err + 1;
}
#endif
/*
* ngx_strerror() is not ready to work at this stage, therefore,
* malloc() is used and possible errors are logged using strerror().
*/
len = (ngx_last_error - ngx_first_error) * sizeof(ngx_str_t);
ngx_sys_errlist = malloc(len);
if (ngx_sys_errlist == NULL) {
goto failed;
}
for (err = ngx_first_error; err < ngx_last_error; err++) {
msg = strerror(err);
if (msg == NULL) {
ngx_sys_errlist[err - ngx_first_error] = ngx_unknown_error;
continue;
}
len = ngx_strlen(msg);
p = malloc(len);
if (p == NULL) {
goto failed;
}
ngx_memcpy(p, msg, len);
ngx_sys_errlist[err - ngx_first_error].len = len;
ngx_sys_errlist[err - ngx_first_error].data = p;
}
return NGX_OK;
failed:
err = errno;
ngx_log_stderr(0, "malloc(%uz) failed (%d: %s)", len, err, strerror(err));
return NGX_ERROR;
}
#endif