| |
| /* |
| * 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 |