/* * Copyright (C) Igor Sysoev * Copyright (C) Nginx, Inc. */ #include #include 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