1 2 /* 3 * Copyright (C) Igor Sysoev 4 * Copyright (C) NGINX, Inc. 5 */ 6 7 #include <nxt_main.h> 8 9 10 /* 11 * The strerror() messages are copied because: 12 * 13 * 1) strerror() and strerror_r() functions are not Async-Signal-Safe, 14 * therefore, they can not be used in signal handlers; 15 * 16 * 2) a direct sys_errlist[] array may be used instead of these functions, 17 * but Linux linker warns about this usage: 18 * 19 * warning: `sys_errlist' is deprecated; use `strerror' or `strerror_r' instead 20 * warning: `sys_nerr' is deprecated; use `strerror' or `strerror_r' instead 21 * 22 * causing false bug reports. 23 */ 24 25 static u_char *nxt_bootstrap_strerror(nxt_err_t err, u_char *errstr, 26 size_t size); 27 static u_char *nxt_runtime_strerror(nxt_err_t err, u_char *errstr, size_t size); 28 29 30 nxt_strerror_t nxt_strerror = nxt_bootstrap_strerror; 31 static nxt_str_t *nxt_sys_errlist; 32 static nxt_uint_t nxt_sys_nerr; 33 34 35 nxt_int_t 36 nxt_strerror_start(void) 37 { 38 char *msg; 39 u_char *p; 40 size_t size, length, n; 41 nxt_uint_t err, invalid; 42 43 /* The last entry. */ 44 size = sizeof("Unknown error") - 1; 45 46 /* 47 * Linux has holes for error codes 41 and 58, so the loop 48 * stops only after 100 invalid codes in succession. 49 */ 50 51 for (invalid = 0; invalid < 100 && nxt_sys_nerr < 65536; nxt_sys_nerr++) { 52 53 nxt_set_errno(0); 54 msg = strerror((int) nxt_sys_nerr); 55 56 /* 57 * strerror() behaviour on passing invalid error code depends 58 * on OS and version: 59 * Linux returns "Unknown error NN"; 60 * FreeBSD, NetBSD and OpenBSD return "Unknown error: NN" 61 * and set errno to EINVAL; 62 * Solaris 10 returns "Unknown error" and sets errno to EINVAL; 63 * Solaris 9 returns "Unknown error"; 64 * Solaris 2 returns NULL; 65 * MacOSX returns "Unknown error: NN"; 66 * AIX returns "Error NNN occurred."; 67 * HP-UX returns "Unknown error" for invalid codes lesser than 250 68 * or empty string for larger codes. 69 */ 70 71 if (msg == NULL) { 72 invalid++; 73 continue; 74 } 75 76 length = nxt_strlen(msg); 77 size += length; 78 79 if (length == 0 /* HP-UX empty strings. */ 80 || nxt_errno == NXT_EINVAL 81 || nxt_memcmp(msg, "Unknown error", 13) == 0) 82 { 83 invalid++; 84 continue; 85 } 86 87 #if (NXT_AIX) 88 89 if (nxt_memcmp(msg, "Error ", 6) == 0 90 && nxt_memcmp(msg + length - 10, " occurred.", 9) == 0) 91 { 92 invalid++; 93 continue; 94 } 95 96 #endif 97 } 98 99 nxt_sys_nerr -= invalid; 100 101 nxt_main_log_debug("sys_nerr: %d", nxt_sys_nerr); 102 103 n = (nxt_sys_nerr + 1) * sizeof(nxt_str_t); 104 105 nxt_sys_errlist = nxt_malloc(n + size); 106 if (nxt_sys_errlist == NULL) { 107 return NXT_ERROR; 108 } 109 110 p = nxt_pointer_to(nxt_sys_errlist, n); 111 112 for (err = 0; err < nxt_sys_nerr; err++) { 113 msg = strerror((int) err); 114 length = nxt_strlen(msg); 115 116 nxt_sys_errlist[err].length = length; 117 nxt_sys_errlist[err].start = p; 118 119 p = nxt_cpymem(p, msg, length); 120 } 121 122 nxt_sys_errlist[err].length = 13; 123 nxt_sys_errlist[err].start = p; 124 nxt_memcpy(p, "Unknown error", 13); 125 126 nxt_strerror = nxt_runtime_strerror; 127 128 return NXT_OK; 129 } 130 131 132 static u_char * 133 nxt_bootstrap_strerror(nxt_err_t err, u_char *errstr, size_t size) 134 { 135 return nxt_cpystrn(errstr, (u_char *) strerror(err), size); 136 } 137 138 139 static u_char * 140 nxt_runtime_strerror(nxt_err_t err, u_char *errstr, size_t size) 141 { 142 nxt_str_t *msg; 143 nxt_uint_t n; 144 145 n = nxt_min((nxt_uint_t) err, nxt_sys_nerr); 146 147 msg = &nxt_sys_errlist[n]; 148 149 size = nxt_min(size, msg->length); 150 151 return nxt_cpymem(errstr, msg->start, size); 152 } 153