1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) Nginx, Inc.
5  */
6 
7 
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 
11 
12 static ngx_str_t   ngx_unknown_error = ngx_string("Unknown error");
13 
14 
15 #if (NGX_HAVE_STRERRORDESC_NP)
16 
17 /*
18  * The strerrordesc_np() function, introduced in glibc 2.32, is
19  * async-signal-safe.  This makes it possible to use it directly,
20  * without copying error messages.
21  */
22 
23 
24 u_char *
ngx_strerror(ngx_err_t err,u_char * errstr,size_t size)25 ngx_strerror(ngx_err_t err, u_char *errstr, size_t size)
26 {
27     size_t       len;
28     const char  *msg;
29 
30     msg = strerrordesc_np(err);
31 
32     if (msg == NULL) {
33         msg = (char *) ngx_unknown_error.data;
34         len = ngx_unknown_error.len;
35 
36     } else {
37         len = ngx_strlen(msg);
38     }
39 
40     size = ngx_min(size, len);
41 
42     return ngx_cpymem(errstr, msg, size);
43 }
44 
45 
46 ngx_int_t
ngx_strerror_init(void)47 ngx_strerror_init(void)
48 {
49     return NGX_OK;
50 }
51 
52 
53 #else
54 
55 /*
56  * The strerror() messages are copied because:
57  *
58  * 1) strerror() and strerror_r() functions are not Async-Signal-Safe,
59  *    therefore, they cannot be used in signal handlers;
60  *
61  * 2) a direct sys_errlist[] array may be used instead of these functions,
62  *    but Linux linker warns about its usage:
63  *
64  * warning: `sys_errlist' is deprecated; use `strerror' or `strerror_r' instead
65  * warning: `sys_nerr' is deprecated; use `strerror' or `strerror_r' instead
66  *
67  *    causing false bug reports.
68  */
69 
70 
71 static ngx_str_t  *ngx_sys_errlist;
72 static ngx_err_t   ngx_first_error;
73 static ngx_err_t   ngx_last_error;
74 
75 
76 u_char *
ngx_strerror(ngx_err_t err,u_char * errstr,size_t size)77 ngx_strerror(ngx_err_t err, u_char *errstr, size_t size)
78 {
79     ngx_str_t  *msg;
80 
81     if (err >= ngx_first_error && err < ngx_last_error) {
82         msg = &ngx_sys_errlist[err - ngx_first_error];
83 
84     } else {
85         msg = &ngx_unknown_error;
86     }
87 
88     size = ngx_min(size, msg->len);
89 
90     return ngx_cpymem(errstr, msg->data, size);
91 }
92 
93 
94 ngx_int_t
ngx_strerror_init(void)95 ngx_strerror_init(void)
96 {
97     char       *msg;
98     u_char     *p;
99     size_t      len;
100     ngx_err_t   err;
101 
102 #if (NGX_SYS_NERR)
103     ngx_first_error = 0;
104     ngx_last_error = NGX_SYS_NERR;
105 
106 #elif (EPERM > 1000 && EPERM < 0x7fffffff - 1000)
107 
108     /*
109      * If number of errors is not known, and EPERM error code has large
110      * but reasonable value, guess possible error codes based on the error
111      * messages returned by strerror(), starting from EPERM.  Notably,
112      * this covers GNU/Hurd, where errors start at 0x40000001.
113      */
114 
115     for (err = EPERM; err > EPERM - 1000; err--) {
116         ngx_set_errno(0);
117         msg = strerror(err);
118 
119         if (errno == EINVAL
120             || msg == NULL
121             || strncmp(msg, "Unknown error", 13) == 0)
122         {
123             continue;
124         }
125 
126         ngx_first_error = err;
127     }
128 
129     for (err = EPERM; err < EPERM + 1000; err++) {
130         ngx_set_errno(0);
131         msg = strerror(err);
132 
133         if (errno == EINVAL
134             || msg == NULL
135             || strncmp(msg, "Unknown error", 13) == 0)
136         {
137             continue;
138         }
139 
140         ngx_last_error = err + 1;
141     }
142 
143 #else
144 
145     /*
146      * If number of errors is not known, guess it based on the error
147      * messages returned by strerror().
148      */
149 
150     ngx_first_error = 0;
151 
152     for (err = 0; err < 1000; err++) {
153         ngx_set_errno(0);
154         msg = strerror(err);
155 
156         if (errno == EINVAL
157             || msg == NULL
158             || strncmp(msg, "Unknown error", 13) == 0)
159         {
160             continue;
161         }
162 
163         ngx_last_error = err + 1;
164     }
165 
166 #endif
167 
168     /*
169      * ngx_strerror() is not ready to work at this stage, therefore,
170      * malloc() is used and possible errors are logged using strerror().
171      */
172 
173     len = (ngx_last_error - ngx_first_error) * sizeof(ngx_str_t);
174 
175     ngx_sys_errlist = malloc(len);
176     if (ngx_sys_errlist == NULL) {
177         goto failed;
178     }
179 
180     for (err = ngx_first_error; err < ngx_last_error; err++) {
181         msg = strerror(err);
182 
183         if (msg == NULL) {
184             ngx_sys_errlist[err - ngx_first_error] = ngx_unknown_error;
185             continue;
186         }
187 
188         len = ngx_strlen(msg);
189 
190         p = malloc(len);
191         if (p == NULL) {
192             goto failed;
193         }
194 
195         ngx_memcpy(p, msg, len);
196         ngx_sys_errlist[err - ngx_first_error].len = len;
197         ngx_sys_errlist[err - ngx_first_error].data = p;
198     }
199 
200     return NGX_OK;
201 
202 failed:
203 
204     err = errno;
205     ngx_log_stderr(0, "malloc(%uz) failed (%d: %s)", len, err, strerror(err));
206 
207     return NGX_ERROR;
208 }
209 
210 #endif
211