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
nxt_strerror_start(void)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 = nxt_length("Unknown error");
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 *
nxt_bootstrap_strerror(nxt_err_t err,u_char * errstr,size_t size)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 *
nxt_runtime_strerror(nxt_err_t err,u_char * errstr,size_t size)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