10Sigor@sysoev.ru 20Sigor@sysoev.ru /* 30Sigor@sysoev.ru * Copyright (C) Igor Sysoev 40Sigor@sysoev.ru * Copyright (C) NGINX, Inc. 50Sigor@sysoev.ru */ 60Sigor@sysoev.ru 70Sigor@sysoev.ru #include <nxt_main.h> 80Sigor@sysoev.ru 90Sigor@sysoev.ru 100Sigor@sysoev.ru /* 110Sigor@sysoev.ru * The strerror() messages are copied because: 120Sigor@sysoev.ru * 130Sigor@sysoev.ru * 1) strerror() and strerror_r() functions are not Async-Signal-Safe, 140Sigor@sysoev.ru * therefore, they can not be used in signal handlers; 150Sigor@sysoev.ru * 160Sigor@sysoev.ru * 2) a direct sys_errlist[] array may be used instead of these functions, 170Sigor@sysoev.ru * but Linux linker warns about this usage: 180Sigor@sysoev.ru * 190Sigor@sysoev.ru * warning: `sys_errlist' is deprecated; use `strerror' or `strerror_r' instead 200Sigor@sysoev.ru * warning: `sys_nerr' is deprecated; use `strerror' or `strerror_r' instead 210Sigor@sysoev.ru * 220Sigor@sysoev.ru * causing false bug reports. 230Sigor@sysoev.ru */ 240Sigor@sysoev.ru 250Sigor@sysoev.ru static u_char *nxt_bootstrap_strerror(nxt_err_t err, u_char *errstr, 260Sigor@sysoev.ru size_t size); 270Sigor@sysoev.ru static u_char *nxt_runtime_strerror(nxt_err_t err, u_char *errstr, size_t size); 280Sigor@sysoev.ru 290Sigor@sysoev.ru 300Sigor@sysoev.ru nxt_strerror_t nxt_strerror = nxt_bootstrap_strerror; 310Sigor@sysoev.ru static nxt_str_t *nxt_sys_errlist; 320Sigor@sysoev.ru static nxt_uint_t nxt_sys_nerr; 330Sigor@sysoev.ru 340Sigor@sysoev.ru 350Sigor@sysoev.ru nxt_int_t 360Sigor@sysoev.ru nxt_strerror_start(void) 370Sigor@sysoev.ru { 380Sigor@sysoev.ru char *msg; 390Sigor@sysoev.ru u_char *p; 40*10Sigor@sysoev.ru size_t size, length, n; 410Sigor@sysoev.ru nxt_uint_t err, invalid; 420Sigor@sysoev.ru 430Sigor@sysoev.ru /* The last entry. */ 440Sigor@sysoev.ru size = sizeof("Unknown error") - 1; 450Sigor@sysoev.ru 460Sigor@sysoev.ru /* 470Sigor@sysoev.ru * Linux has holes for error codes 41 and 58, so the loop 480Sigor@sysoev.ru * stops only after 100 invalid codes in succession. 490Sigor@sysoev.ru */ 500Sigor@sysoev.ru 510Sigor@sysoev.ru for (invalid = 0; invalid < 100 && nxt_sys_nerr < 65536; nxt_sys_nerr++) { 520Sigor@sysoev.ru 530Sigor@sysoev.ru nxt_set_errno(0); 540Sigor@sysoev.ru msg = strerror((int) nxt_sys_nerr); 550Sigor@sysoev.ru 560Sigor@sysoev.ru /* 570Sigor@sysoev.ru * strerror() behaviour on passing invalid error code depends 580Sigor@sysoev.ru * on OS and version: 590Sigor@sysoev.ru * Linux returns "Unknown error NN"; 600Sigor@sysoev.ru * FreeBSD, NetBSD and OpenBSD return "Unknown error: NN" 610Sigor@sysoev.ru * and set errno to EINVAL; 620Sigor@sysoev.ru * Solaris 10 returns "Unknown error" and sets errno to EINVAL; 630Sigor@sysoev.ru * Solaris 9 returns "Unknown error"; 640Sigor@sysoev.ru * Solaris 2 returns NULL; 650Sigor@sysoev.ru * MacOSX returns "Unknown error: NN"; 660Sigor@sysoev.ru * AIX returns "Error NNN occurred."; 670Sigor@sysoev.ru * HP-UX returns "Unknown error" for invalid codes lesser than 250 680Sigor@sysoev.ru * or empty string for larger codes. 690Sigor@sysoev.ru */ 700Sigor@sysoev.ru 710Sigor@sysoev.ru if (msg == NULL) { 720Sigor@sysoev.ru invalid++; 730Sigor@sysoev.ru continue; 740Sigor@sysoev.ru } 750Sigor@sysoev.ru 76*10Sigor@sysoev.ru length = nxt_strlen(msg); 77*10Sigor@sysoev.ru size += length; 780Sigor@sysoev.ru 79*10Sigor@sysoev.ru if (length == 0 /* HP-UX empty strings. */ 800Sigor@sysoev.ru || nxt_errno == NXT_EINVAL 810Sigor@sysoev.ru || nxt_memcmp(msg, "Unknown error", 13) == 0) 820Sigor@sysoev.ru { 830Sigor@sysoev.ru invalid++; 840Sigor@sysoev.ru continue; 850Sigor@sysoev.ru } 860Sigor@sysoev.ru 870Sigor@sysoev.ru #if (NXT_AIX) 880Sigor@sysoev.ru 890Sigor@sysoev.ru if (nxt_memcmp(msg, "Error ", 6) == 0 90*10Sigor@sysoev.ru && nxt_memcmp(msg + length - 10, " occurred.", 9) == 0) 910Sigor@sysoev.ru { 920Sigor@sysoev.ru invalid++; 930Sigor@sysoev.ru continue; 940Sigor@sysoev.ru } 950Sigor@sysoev.ru 960Sigor@sysoev.ru #endif 970Sigor@sysoev.ru } 980Sigor@sysoev.ru 990Sigor@sysoev.ru nxt_sys_nerr -= invalid; 1000Sigor@sysoev.ru 1010Sigor@sysoev.ru nxt_main_log_debug("sys_nerr: %d", nxt_sys_nerr); 1020Sigor@sysoev.ru 1030Sigor@sysoev.ru n = (nxt_sys_nerr + 1) * sizeof(nxt_str_t); 1040Sigor@sysoev.ru 1050Sigor@sysoev.ru nxt_sys_errlist = nxt_malloc(n + size); 1060Sigor@sysoev.ru if (nxt_sys_errlist == NULL) { 1070Sigor@sysoev.ru return NXT_ERROR; 1080Sigor@sysoev.ru } 1090Sigor@sysoev.ru 1100Sigor@sysoev.ru p = (u_char *) nxt_sys_errlist + n; 1110Sigor@sysoev.ru 1120Sigor@sysoev.ru for (err = 0; err < nxt_sys_nerr; err++) { 1130Sigor@sysoev.ru msg = strerror((int) err); 114*10Sigor@sysoev.ru length = nxt_strlen(msg); 1150Sigor@sysoev.ru 116*10Sigor@sysoev.ru nxt_sys_errlist[err].length = length; 117*10Sigor@sysoev.ru nxt_sys_errlist[err].start = p; 1180Sigor@sysoev.ru 119*10Sigor@sysoev.ru p = nxt_cpymem(p, msg, length); 1200Sigor@sysoev.ru } 1210Sigor@sysoev.ru 122*10Sigor@sysoev.ru nxt_sys_errlist[err].length = 13; 123*10Sigor@sysoev.ru nxt_sys_errlist[err].start = p; 1240Sigor@sysoev.ru nxt_memcpy(p, "Unknown error", 13); 1250Sigor@sysoev.ru 1260Sigor@sysoev.ru nxt_strerror = nxt_runtime_strerror; 1270Sigor@sysoev.ru 1280Sigor@sysoev.ru return NXT_OK; 1290Sigor@sysoev.ru } 1300Sigor@sysoev.ru 1310Sigor@sysoev.ru 1320Sigor@sysoev.ru static u_char * 1330Sigor@sysoev.ru nxt_bootstrap_strerror(nxt_err_t err, u_char *errstr, size_t size) 1340Sigor@sysoev.ru { 1350Sigor@sysoev.ru return nxt_cpystrn(errstr, (u_char *) strerror(err), size); 1360Sigor@sysoev.ru } 1370Sigor@sysoev.ru 1380Sigor@sysoev.ru 1390Sigor@sysoev.ru static u_char * 1400Sigor@sysoev.ru nxt_runtime_strerror(nxt_err_t err, u_char *errstr, size_t size) 1410Sigor@sysoev.ru { 1420Sigor@sysoev.ru nxt_str_t *msg; 1430Sigor@sysoev.ru nxt_uint_t n; 1440Sigor@sysoev.ru 1450Sigor@sysoev.ru n = nxt_min((nxt_uint_t) err, nxt_sys_nerr); 1460Sigor@sysoev.ru 1470Sigor@sysoev.ru msg = &nxt_sys_errlist[n]; 1480Sigor@sysoev.ru 149*10Sigor@sysoev.ru size = nxt_min(size, msg->length); 1500Sigor@sysoev.ru 151*10Sigor@sysoev.ru return nxt_cpymem(errstr, msg->start, size); 1520Sigor@sysoev.ru } 153