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