comparison src/os/unix/ngx_errno.c @ 7784:8cc5b0365ee5

Improved maximum errno detection. Previously, systems without sys_nerr (or _sys_nerr) were handled with an assumption that errors start at 0 and continuous. This is, however, not something POSIX requires, and not true on some platforms. Notably, on Linux, where sys_nerr is no longer available for newly linked binaries starting with glibc 2.32, there are gaps in error list, which used to stop us from properly detecting maximum errno. Further, on GNU/Hurd errors start at 0x40000001. With this change, maximum errno detection is moved to the runtime code, now able to ignore gaps, and also detects the first error if needed. This fixes observed "Unknown error" messages as seen on Linux with glibc 2.32 and on GNU/Hurd.
author Maxim Dounin <mdounin@mdounin.ru>
date Mon, 01 Mar 2021 20:00:43 +0300
parents f1a0de6eb505
children c43a2e8fdf7e
comparison
equal deleted inserted replaced
7783:171682010da4 7784:8cc5b0365ee5
25 */ 25 */
26 26
27 27
28 static ngx_str_t *ngx_sys_errlist; 28 static ngx_str_t *ngx_sys_errlist;
29 static ngx_str_t ngx_unknown_error = ngx_string("Unknown error"); 29 static ngx_str_t ngx_unknown_error = ngx_string("Unknown error");
30 static ngx_err_t ngx_first_error;
31 static ngx_err_t ngx_last_error;
30 32
31 33
32 u_char * 34 u_char *
33 ngx_strerror(ngx_err_t err, u_char *errstr, size_t size) 35 ngx_strerror(ngx_err_t err, u_char *errstr, size_t size)
34 { 36 {
35 ngx_str_t *msg; 37 ngx_str_t *msg;
36 38
37 msg = ((ngx_uint_t) err < NGX_SYS_NERR) ? &ngx_sys_errlist[err]: 39 if (err >= ngx_first_error && err < ngx_last_error) {
38 &ngx_unknown_error; 40 msg = &ngx_sys_errlist[err - ngx_first_error];
41
42 } else {
43 msg = &ngx_unknown_error;
44 }
45
39 size = ngx_min(size, msg->len); 46 size = ngx_min(size, msg->len);
40 47
41 return ngx_cpymem(errstr, msg->data, size); 48 return ngx_cpymem(errstr, msg->data, size);
42 } 49 }
43 50
48 char *msg; 55 char *msg;
49 u_char *p; 56 u_char *p;
50 size_t len; 57 size_t len;
51 ngx_err_t err; 58 ngx_err_t err;
52 59
60 #if (NGX_SYS_NERR)
61 ngx_first_error = 0;
62 ngx_last_error = NGX_SYS_NERR;
63
64 #elif (EPERM > 1000 && EPERM < 0x7fffffff - 1000)
65
66 /*
67 * If number of errors is not known, and EPERM error code has large
68 * but reasonable value, guess possible error codes based on the error
69 * messages returned by strerror(), starting from EPERM. Notably,
70 * this covers GNU/Hurd, where errors start at 0x40000001.
71 */
72
73 for (err = EPERM; err > EPERM - 1000; err--) {
74 ngx_set_errno(0);
75 msg = strerror(err);
76
77 if (errno == EINVAL
78 || msg == NULL
79 || strncmp(msg, "Unknown error", 13) == 0)
80 {
81 continue;
82 }
83
84 ngx_first_error = err;
85 }
86
87 for (err = EPERM; err < EPERM + 1000; err++) {
88 ngx_set_errno(0);
89 msg = strerror(err);
90
91 if (errno == EINVAL
92 || msg == NULL
93 || strncmp(msg, "Unknown error", 13) == 0)
94 {
95 continue;
96 }
97
98 ngx_last_error = err + 1;
99 }
100
101 #else
102
103 /*
104 * If number of errors is not known, guess it based on the error
105 * messages returned by strerror().
106 */
107
108 ngx_first_error = 0;
109
110 for (err = 0; err < 1000; err++) {
111 ngx_set_errno(0);
112 msg = strerror(err);
113
114 if (errno == EINVAL
115 || msg == NULL
116 || strncmp(msg, "Unknown error", 13) == 0)
117 {
118 continue;
119 }
120
121 ngx_last_error = err + 1;
122 }
123
124 #endif
125
53 /* 126 /*
54 * ngx_strerror() is not ready to work at this stage, therefore, 127 * ngx_strerror() is not ready to work at this stage, therefore,
55 * malloc() is used and possible errors are logged using strerror(). 128 * malloc() is used and possible errors are logged using strerror().
56 */ 129 */
57 130
58 len = NGX_SYS_NERR * sizeof(ngx_str_t); 131 len = (ngx_last_error - ngx_first_error) * sizeof(ngx_str_t);
59 132
60 ngx_sys_errlist = malloc(len); 133 ngx_sys_errlist = malloc(len);
61 if (ngx_sys_errlist == NULL) { 134 if (ngx_sys_errlist == NULL) {
62 goto failed; 135 goto failed;
63 } 136 }
64 137
65 for (err = 0; err < NGX_SYS_NERR; err++) { 138 for (err = ngx_first_error; err < ngx_last_error; err++) {
66 msg = strerror(err); 139 msg = strerror(err);
140
141 if (msg == NULL) {
142 ngx_sys_errlist[err - ngx_first_error] = ngx_unknown_error;
143 continue;
144 }
145
67 len = ngx_strlen(msg); 146 len = ngx_strlen(msg);
68 147
69 p = malloc(len); 148 p = malloc(len);
70 if (p == NULL) { 149 if (p == NULL) {
71 goto failed; 150 goto failed;
72 } 151 }
73 152
74 ngx_memcpy(p, msg, len); 153 ngx_memcpy(p, msg, len);
75 ngx_sys_errlist[err].len = len; 154 ngx_sys_errlist[err - ngx_first_error].len = len;
76 ngx_sys_errlist[err].data = p; 155 ngx_sys_errlist[err - ngx_first_error].data = p;
77 } 156 }
78 157
79 return NGX_OK; 158 return NGX_OK;
80 159
81 failed: 160 failed: