blob: bd8b68aaad791ed354fcc3f38d2b76f308f62777 [file] [log] [blame]
Willy Tarreau36b9e222018-11-11 15:19:52 +01001#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <netdb.h>
5#include <ctype.h>
6#include <pwd.h>
7#include <grp.h>
8#include <errno.h>
9#include <sys/types.h>
10#include <sys/stat.h>
11#include <fcntl.h>
12#include <unistd.h>
13
14#include <common/cfgparse.h>
15#include <proto/compression.h>
16
17/*
18 * parse a line in a <global> section. Returns the error code, 0 if OK, or
19 * any combination of :
20 * - ERR_ABORT: must abort ASAP
21 * - ERR_FATAL: we can continue parsing but not start the service
22 * - ERR_WARN: a warning has been emitted
23 * - ERR_ALERT: an alert has been emitted
24 * Only the two first ones can stop processing, the two others are just
25 * indicators.
26 */
27int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
28{
29 int err_code = 0;
30 char *errmsg = NULL;
31
32 if (!strcmp(args[0], "global")) { /* new section */
33 /* no option, nothing special to do */
34 alertif_too_many_args(0, file, linenum, args, &err_code);
35 goto out;
36 }
37 else if (!strcmp(args[0], "daemon")) {
38 if (alertif_too_many_args(0, file, linenum, args, &err_code))
39 goto out;
40 global.mode |= MODE_DAEMON;
41 }
42 else if (!strcmp(args[0], "master-worker")) {
43 if (alertif_too_many_args(1, file, linenum, args, &err_code))
44 goto out;
45 if (*args[1]) {
46 if (!strcmp(args[1], "no-exit-on-failure")) {
47 global.tune.options |= GTUNE_NOEXIT_ONFAILURE;
48 } else {
49 ha_alert("parsing [%s:%d] : '%s' only supports 'no-exit-on-failure' option.\n", file, linenum, args[0]);
50 err_code |= ERR_ALERT | ERR_FATAL;
51 goto out;
52 }
53 }
54 global.mode |= MODE_MWORKER;
55 }
56 else if (!strcmp(args[0], "debug")) {
57 if (alertif_too_many_args(0, file, linenum, args, &err_code))
58 goto out;
59 global.mode |= MODE_DEBUG;
60 }
61 else if (!strcmp(args[0], "noepoll")) {
62 if (alertif_too_many_args(0, file, linenum, args, &err_code))
63 goto out;
64 global.tune.options &= ~GTUNE_USE_EPOLL;
65 }
66 else if (!strcmp(args[0], "nokqueue")) {
67 if (alertif_too_many_args(0, file, linenum, args, &err_code))
68 goto out;
69 global.tune.options &= ~GTUNE_USE_KQUEUE;
70 }
71 else if (!strcmp(args[0], "nopoll")) {
72 if (alertif_too_many_args(0, file, linenum, args, &err_code))
73 goto out;
74 global.tune.options &= ~GTUNE_USE_POLL;
75 }
Willy Tarreaubeb859a2018-11-22 18:07:59 +010076 else if (!strcmp(args[0], "busy-polling")) { /* "no busy-polling" or "busy-polling" */
77 if (alertif_too_many_args(0, file, linenum, args, &err_code))
78 goto out;
79 if (kwm == KWM_NO)
80 global.tune.options &= ~GTUNE_BUSY_POLLING;
81 else
82 global.tune.options |= GTUNE_BUSY_POLLING;
83 }
Willy Tarreau636848a2019-04-15 19:38:50 +020084 else if (!strcmp(args[0], "set-dumpable")) { /* "no set-dumpable" or "set-dumpable" */
85 if (alertif_too_many_args(0, file, linenum, args, &err_code))
86 goto out;
87 if (kwm == KWM_NO)
88 global.tune.options &= ~GTUNE_SET_DUMPABLE;
89 else
90 global.tune.options |= GTUNE_SET_DUMPABLE;
91 }
Willy Tarreau36b9e222018-11-11 15:19:52 +010092 else if (!strcmp(args[0], "nosplice")) {
93 if (alertif_too_many_args(0, file, linenum, args, &err_code))
94 goto out;
95 global.tune.options &= ~GTUNE_USE_SPLICE;
96 }
97 else if (!strcmp(args[0], "nogetaddrinfo")) {
98 if (alertif_too_many_args(0, file, linenum, args, &err_code))
99 goto out;
100 global.tune.options &= ~GTUNE_USE_GAI;
101 }
102 else if (!strcmp(args[0], "noreuseport")) {
103 if (alertif_too_many_args(0, file, linenum, args, &err_code))
104 goto out;
105 global.tune.options &= ~GTUNE_USE_REUSEPORT;
106 }
107 else if (!strcmp(args[0], "quiet")) {
108 if (alertif_too_many_args(0, file, linenum, args, &err_code))
109 goto out;
110 global.mode |= MODE_QUIET;
111 }
112 else if (!strcmp(args[0], "tune.runqueue-depth")) {
113 if (alertif_too_many_args(1, file, linenum, args, &err_code))
114 goto out;
115 if (global.tune.runqueue_depth != 0) {
116 ha_alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
117 err_code |= ERR_ALERT;
118 goto out;
119 }
120 if (*(args[1]) == 0) {
121 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
122 err_code |= ERR_ALERT | ERR_FATAL;
123 goto out;
124 }
125 global.tune.runqueue_depth = atol(args[1]);
126
127 }
128 else if (!strcmp(args[0], "tune.maxpollevents")) {
129 if (alertif_too_many_args(1, file, linenum, args, &err_code))
130 goto out;
131 if (global.tune.maxpollevents != 0) {
132 ha_alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
133 err_code |= ERR_ALERT;
134 goto out;
135 }
136 if (*(args[1]) == 0) {
137 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
138 err_code |= ERR_ALERT | ERR_FATAL;
139 goto out;
140 }
141 global.tune.maxpollevents = atol(args[1]);
142 }
143 else if (!strcmp(args[0], "tune.maxaccept")) {
144 if (alertif_too_many_args(1, file, linenum, args, &err_code))
145 goto out;
146 if (global.tune.maxaccept != 0) {
147 ha_alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
148 err_code |= ERR_ALERT;
149 goto out;
150 }
151 if (*(args[1]) == 0) {
152 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
153 err_code |= ERR_ALERT | ERR_FATAL;
154 goto out;
155 }
156 global.tune.maxaccept = atol(args[1]);
157 }
158 else if (!strcmp(args[0], "tune.chksize")) {
159 if (alertif_too_many_args(1, file, linenum, args, &err_code))
160 goto out;
161 if (*(args[1]) == 0) {
162 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
163 err_code |= ERR_ALERT | ERR_FATAL;
164 goto out;
165 }
166 global.tune.chksize = atol(args[1]);
167 }
168 else if (!strcmp(args[0], "tune.recv_enough")) {
169 if (alertif_too_many_args(1, file, linenum, args, &err_code))
170 goto out;
171 if (*(args[1]) == 0) {
172 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
173 err_code |= ERR_ALERT | ERR_FATAL;
174 goto out;
175 }
176 global.tune.recv_enough = atol(args[1]);
177 }
178 else if (!strcmp(args[0], "tune.buffers.limit")) {
179 if (alertif_too_many_args(1, file, linenum, args, &err_code))
180 goto out;
181 if (*(args[1]) == 0) {
182 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
183 err_code |= ERR_ALERT | ERR_FATAL;
184 goto out;
185 }
186 global.tune.buf_limit = atol(args[1]);
187 if (global.tune.buf_limit) {
188 if (global.tune.buf_limit < 3)
189 global.tune.buf_limit = 3;
190 if (global.tune.buf_limit <= global.tune.reserved_bufs)
191 global.tune.buf_limit = global.tune.reserved_bufs + 1;
192 }
193 }
194 else if (!strcmp(args[0], "tune.buffers.reserve")) {
195 if (alertif_too_many_args(1, file, linenum, args, &err_code))
196 goto out;
197 if (*(args[1]) == 0) {
198 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
199 err_code |= ERR_ALERT | ERR_FATAL;
200 goto out;
201 }
202 global.tune.reserved_bufs = atol(args[1]);
203 if (global.tune.reserved_bufs < 2)
204 global.tune.reserved_bufs = 2;
205 if (global.tune.buf_limit && global.tune.buf_limit <= global.tune.reserved_bufs)
206 global.tune.buf_limit = global.tune.reserved_bufs + 1;
207 }
208 else if (!strcmp(args[0], "tune.bufsize")) {
209 if (alertif_too_many_args(1, file, linenum, args, &err_code))
210 goto out;
211 if (*(args[1]) == 0) {
212 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
213 err_code |= ERR_ALERT | ERR_FATAL;
214 goto out;
215 }
216 global.tune.bufsize = atol(args[1]);
Willy Tarreauc77d3642018-12-12 06:19:42 +0100217 /* round it up to support a two-pointer alignment at the end */
218 global.tune.bufsize = (global.tune.bufsize + 2 * sizeof(void *) - 1) & -(2 * sizeof(void *));
Willy Tarreau36b9e222018-11-11 15:19:52 +0100219 if (global.tune.bufsize <= 0) {
220 ha_alert("parsing [%s:%d] : '%s' expects a positive integer argument.\n", file, linenum, args[0]);
221 err_code |= ERR_ALERT | ERR_FATAL;
222 goto out;
223 }
224 }
225 else if (!strcmp(args[0], "tune.maxrewrite")) {
226 if (alertif_too_many_args(1, file, linenum, args, &err_code))
227 goto out;
228 if (*(args[1]) == 0) {
229 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
230 err_code |= ERR_ALERT | ERR_FATAL;
231 goto out;
232 }
233 global.tune.maxrewrite = atol(args[1]);
234 if (global.tune.maxrewrite < 0) {
235 ha_alert("parsing [%s:%d] : '%s' expects a positive integer argument.\n", file, linenum, args[0]);
236 err_code |= ERR_ALERT | ERR_FATAL;
237 goto out;
238 }
239 }
240 else if (!strcmp(args[0], "tune.idletimer")) {
241 unsigned int idle;
242 const char *res;
243
244 if (alertif_too_many_args(1, file, linenum, args, &err_code))
245 goto out;
246 if (*(args[1]) == 0) {
247 ha_alert("parsing [%s:%d] : '%s' expects a timer value between 0 and 65535 ms.\n", file, linenum, args[0]);
248 err_code |= ERR_ALERT | ERR_FATAL;
249 goto out;
250 }
251
252 res = parse_time_err(args[1], &idle, TIME_UNIT_MS);
253 if (res) {
254 ha_alert("parsing [%s:%d]: unexpected character '%c' in argument to <%s>.\n",
255 file, linenum, *res, args[0]);
256 err_code |= ERR_ALERT | ERR_FATAL;
257 goto out;
258 }
259
260 if (idle > 65535) {
261 ha_alert("parsing [%s:%d] : '%s' expects a timer value between 0 and 65535 ms.\n", file, linenum, args[0]);
262 err_code |= ERR_ALERT | ERR_FATAL;
263 goto out;
264 }
265 global.tune.idle_timer = idle;
266 }
267 else if (!strcmp(args[0], "tune.rcvbuf.client")) {
268 if (alertif_too_many_args(1, file, linenum, args, &err_code))
269 goto out;
270 if (global.tune.client_rcvbuf != 0) {
271 ha_alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
272 err_code |= ERR_ALERT;
273 goto out;
274 }
275 if (*(args[1]) == 0) {
276 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
277 err_code |= ERR_ALERT | ERR_FATAL;
278 goto out;
279 }
280 global.tune.client_rcvbuf = atol(args[1]);
281 }
282 else if (!strcmp(args[0], "tune.rcvbuf.server")) {
283 if (alertif_too_many_args(1, file, linenum, args, &err_code))
284 goto out;
285 if (global.tune.server_rcvbuf != 0) {
286 ha_alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
287 err_code |= ERR_ALERT;
288 goto out;
289 }
290 if (*(args[1]) == 0) {
291 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
292 err_code |= ERR_ALERT | ERR_FATAL;
293 goto out;
294 }
295 global.tune.server_rcvbuf = atol(args[1]);
296 }
297 else if (!strcmp(args[0], "tune.sndbuf.client")) {
298 if (alertif_too_many_args(1, file, linenum, args, &err_code))
299 goto out;
300 if (global.tune.client_sndbuf != 0) {
301 ha_alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
302 err_code |= ERR_ALERT;
303 goto out;
304 }
305 if (*(args[1]) == 0) {
306 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
307 err_code |= ERR_ALERT | ERR_FATAL;
308 goto out;
309 }
310 global.tune.client_sndbuf = atol(args[1]);
311 }
312 else if (!strcmp(args[0], "tune.sndbuf.server")) {
313 if (alertif_too_many_args(1, file, linenum, args, &err_code))
314 goto out;
315 if (global.tune.server_sndbuf != 0) {
316 ha_alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
317 err_code |= ERR_ALERT;
318 goto out;
319 }
320 if (*(args[1]) == 0) {
321 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
322 err_code |= ERR_ALERT | ERR_FATAL;
323 goto out;
324 }
325 global.tune.server_sndbuf = atol(args[1]);
326 }
327 else if (!strcmp(args[0], "tune.pipesize")) {
328 if (alertif_too_many_args(1, file, linenum, args, &err_code))
329 goto out;
330 if (*(args[1]) == 0) {
331 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
332 err_code |= ERR_ALERT | ERR_FATAL;
333 goto out;
334 }
335 global.tune.pipesize = atol(args[1]);
336 }
337 else if (!strcmp(args[0], "tune.http.cookielen")) {
338 if (alertif_too_many_args(1, file, linenum, args, &err_code))
339 goto out;
340 if (*(args[1]) == 0) {
341 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
342 err_code |= ERR_ALERT | ERR_FATAL;
343 goto out;
344 }
345 global.tune.cookie_len = atol(args[1]) + 1;
346 }
347 else if (!strcmp(args[0], "tune.http.logurilen")) {
348 if (alertif_too_many_args(1, file, linenum, args, &err_code))
349 goto out;
350 if (*(args[1]) == 0) {
351 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
352 err_code |= ERR_ALERT | ERR_FATAL;
353 goto out;
354 }
355 global.tune.requri_len = atol(args[1]) + 1;
356 }
357 else if (!strcmp(args[0], "tune.http.maxhdr")) {
358 if (alertif_too_many_args(1, file, linenum, args, &err_code))
359 goto out;
360 if (*(args[1]) == 0) {
361 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
362 err_code |= ERR_ALERT | ERR_FATAL;
363 goto out;
364 }
365 global.tune.max_http_hdr = atoi(args[1]);
366 if (global.tune.max_http_hdr < 1 || global.tune.max_http_hdr > 32767) {
367 ha_alert("parsing [%s:%d] : '%s' expects a numeric value between 1 and 32767\n",
368 file, linenum, args[0]);
369 err_code |= ERR_ALERT | ERR_FATAL;
370 goto out;
371 }
372 }
373 else if (!strcmp(args[0], "tune.comp.maxlevel")) {
374 if (alertif_too_many_args(1, file, linenum, args, &err_code))
375 goto out;
376 if (*args[1]) {
377 global.tune.comp_maxlevel = atoi(args[1]);
378 if (global.tune.comp_maxlevel < 1 || global.tune.comp_maxlevel > 9) {
379 ha_alert("parsing [%s:%d] : '%s' expects a numeric value between 1 and 9\n",
380 file, linenum, args[0]);
381 err_code |= ERR_ALERT | ERR_FATAL;
382 goto out;
383 }
384 } else {
385 ha_alert("parsing [%s:%d] : '%s' expects a numeric value between 1 and 9\n",
386 file, linenum, args[0]);
387 err_code |= ERR_ALERT | ERR_FATAL;
388 goto out;
389 }
390 }
391 else if (!strcmp(args[0], "tune.pattern.cache-size")) {
392 if (*args[1]) {
393 global.tune.pattern_cache = atoi(args[1]);
394 if (global.tune.pattern_cache < 0) {
395 ha_alert("parsing [%s:%d] : '%s' expects a positive numeric value\n",
396 file, linenum, args[0]);
397 err_code |= ERR_ALERT | ERR_FATAL;
398 goto out;
399 }
400 } else {
401 ha_alert("parsing [%s:%d] : '%s' expects a positive numeric value\n",
402 file, linenum, args[0]);
403 err_code |= ERR_ALERT | ERR_FATAL;
404 goto out;
405 }
406 }
407 else if (!strcmp(args[0], "uid")) {
408 if (alertif_too_many_args(1, file, linenum, args, &err_code))
409 goto out;
410 if (global.uid != 0) {
411 ha_alert("parsing [%s:%d] : user/uid already specified. Continuing.\n", file, linenum);
412 err_code |= ERR_ALERT;
413 goto out;
414 }
415 if (*(args[1]) == 0) {
416 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
417 err_code |= ERR_ALERT | ERR_FATAL;
418 goto out;
419 }
420 if (strl2irc(args[1], strlen(args[1]), &global.uid) != 0) {
421 ha_warning("parsing [%s:%d] : uid: string '%s' is not a number.\n | You might want to use the 'user' parameter to use a system user name.\n", file, linenum, args[1]);
422 err_code |= ERR_WARN;
423 goto out;
424 }
425
426 }
427 else if (!strcmp(args[0], "gid")) {
428 if (alertif_too_many_args(1, file, linenum, args, &err_code))
429 goto out;
430 if (global.gid != 0) {
431 ha_alert("parsing [%s:%d] : group/gid already specified. Continuing.\n", file, linenum);
432 err_code |= ERR_ALERT;
433 goto out;
434 }
435 if (*(args[1]) == 0) {
436 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
437 err_code |= ERR_ALERT | ERR_FATAL;
438 goto out;
439 }
440 if (strl2irc(args[1], strlen(args[1]), &global.gid) != 0) {
441 ha_warning("parsing [%s:%d] : gid: string '%s' is not a number.\n | You might want to use the 'group' parameter to use a system group name.\n", file, linenum, args[1]);
442 err_code |= ERR_WARN;
443 goto out;
444 }
445 }
446 else if (!strcmp(args[0], "external-check")) {
447 if (alertif_too_many_args(0, file, linenum, args, &err_code))
448 goto out;
449 global.external_check = 1;
450 }
451 /* user/group name handling */
452 else if (!strcmp(args[0], "user")) {
453 struct passwd *ha_user;
454 if (alertif_too_many_args(1, file, linenum, args, &err_code))
455 goto out;
456 if (global.uid != 0) {
457 ha_alert("parsing [%s:%d] : user/uid already specified. Continuing.\n", file, linenum);
458 err_code |= ERR_ALERT;
459 goto out;
460 }
461 errno = 0;
462 ha_user = getpwnam(args[1]);
463 if (ha_user != NULL) {
464 global.uid = (int)ha_user->pw_uid;
465 }
466 else {
467 ha_alert("parsing [%s:%d] : cannot find user id for '%s' (%d:%s)\n", file, linenum, args[1], errno, strerror(errno));
468 err_code |= ERR_ALERT | ERR_FATAL;
469 }
470 }
471 else if (!strcmp(args[0], "group")) {
472 struct group *ha_group;
473 if (alertif_too_many_args(1, file, linenum, args, &err_code))
474 goto out;
475 if (global.gid != 0) {
476 ha_alert("parsing [%s:%d] : gid/group was already specified. Continuing.\n", file, linenum);
477 err_code |= ERR_ALERT;
478 goto out;
479 }
480 errno = 0;
481 ha_group = getgrnam(args[1]);
482 if (ha_group != NULL) {
483 global.gid = (int)ha_group->gr_gid;
484 }
485 else {
486 ha_alert("parsing [%s:%d] : cannot find group id for '%s' (%d:%s)\n", file, linenum, args[1], errno, strerror(errno));
487 err_code |= ERR_ALERT | ERR_FATAL;
488 }
489 }
490 /* end of user/group name handling*/
491 else if (!strcmp(args[0], "nbproc")) {
492 if (alertif_too_many_args(1, file, linenum, args, &err_code))
493 goto out;
494 if (*(args[1]) == 0) {
495 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
496 err_code |= ERR_ALERT | ERR_FATAL;
497 goto out;
498 }
499 global.nbproc = atol(args[1]);
Willy Tarreaua38a7172019-02-02 17:11:28 +0100500 all_proc_mask = nbits(global.nbproc);
Willy Tarreauff9c9142019-02-07 10:39:36 +0100501 if (global.nbproc < 1 || global.nbproc > MAX_PROCS) {
Willy Tarreau36b9e222018-11-11 15:19:52 +0100502 ha_alert("parsing [%s:%d] : '%s' must be between 1 and %d (was %d).\n",
Willy Tarreauff9c9142019-02-07 10:39:36 +0100503 file, linenum, args[0], MAX_PROCS, global.nbproc);
Willy Tarreau36b9e222018-11-11 15:19:52 +0100504 err_code |= ERR_ALERT | ERR_FATAL;
505 goto out;
506 }
507 }
508 else if (!strcmp(args[0], "nbthread")) {
509 if (alertif_too_many_args(1, file, linenum, args, &err_code))
510 goto out;
511 if (*(args[1]) == 0) {
512 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
513 err_code |= ERR_ALERT | ERR_FATAL;
514 goto out;
515 }
516 global.nbthread = parse_nbthread(args[1], &errmsg);
517 if (!global.nbthread) {
518 ha_alert("parsing [%s:%d] : '%s' %s.\n",
519 file, linenum, args[0], errmsg);
520 err_code |= ERR_ALERT | ERR_FATAL;
521 goto out;
522 }
523 }
524 else if (!strcmp(args[0], "maxconn")) {
525 if (alertif_too_many_args(1, file, linenum, args, &err_code))
526 goto out;
527 if (global.maxconn != 0) {
528 ha_alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
529 err_code |= ERR_ALERT;
530 goto out;
531 }
532 if (*(args[1]) == 0) {
533 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
534 err_code |= ERR_ALERT | ERR_FATAL;
535 goto out;
536 }
537 global.maxconn = atol(args[1]);
538#ifdef SYSTEM_MAXCONN
Willy Tarreauca783d42019-03-13 10:03:07 +0100539 if (global.maxconn > SYSTEM_MAXCONN && cfg_maxconn <= SYSTEM_MAXCONN) {
540 ha_alert("parsing [%s:%d] : maxconn value %d too high for this system.\nLimiting to %d. Please use '-n' to force the value.\n", file, linenum, global.maxconn, SYSTEM_MAXCONN);
541 global.maxconn = SYSTEM_MAXCONN;
Willy Tarreau36b9e222018-11-11 15:19:52 +0100542 err_code |= ERR_ALERT;
543 }
544#endif /* SYSTEM_MAXCONN */
545 }
546 else if (!strcmp(args[0], "ssl-server-verify")) {
547 if (alertif_too_many_args(1, file, linenum, args, &err_code))
548 goto out;
549 if (*(args[1]) == 0) {
550 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
551 err_code |= ERR_ALERT | ERR_FATAL;
552 goto out;
553 }
554 if (strcmp(args[1],"none") == 0)
555 global.ssl_server_verify = SSL_SERVER_VERIFY_NONE;
556 else if (strcmp(args[1],"required") == 0)
557 global.ssl_server_verify = SSL_SERVER_VERIFY_REQUIRED;
558 else {
559 ha_alert("parsing [%s:%d] : '%s' expects 'none' or 'required' as argument.\n", file, linenum, args[0]);
560 err_code |= ERR_ALERT | ERR_FATAL;
561 goto out;
562 }
563 }
564 else if (!strcmp(args[0], "maxconnrate")) {
565 if (alertif_too_many_args(1, file, linenum, args, &err_code))
566 goto out;
567 if (global.cps_lim != 0) {
568 ha_alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
569 err_code |= ERR_ALERT;
570 goto out;
571 }
572 if (*(args[1]) == 0) {
573 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
574 err_code |= ERR_ALERT | ERR_FATAL;
575 goto out;
576 }
577 global.cps_lim = atol(args[1]);
578 }
579 else if (!strcmp(args[0], "maxsessrate")) {
580 if (alertif_too_many_args(1, file, linenum, args, &err_code))
581 goto out;
582 if (global.sps_lim != 0) {
583 ha_alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
584 err_code |= ERR_ALERT;
585 goto out;
586 }
587 if (*(args[1]) == 0) {
588 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
589 err_code |= ERR_ALERT | ERR_FATAL;
590 goto out;
591 }
592 global.sps_lim = atol(args[1]);
593 }
594 else if (!strcmp(args[0], "maxsslrate")) {
595 if (alertif_too_many_args(1, file, linenum, args, &err_code))
596 goto out;
597 if (global.ssl_lim != 0) {
598 ha_alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
599 err_code |= ERR_ALERT;
600 goto out;
601 }
602 if (*(args[1]) == 0) {
603 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
604 err_code |= ERR_ALERT | ERR_FATAL;
605 goto out;
606 }
607 global.ssl_lim = atol(args[1]);
608 }
609 else if (!strcmp(args[0], "maxcomprate")) {
610 if (alertif_too_many_args(1, file, linenum, args, &err_code))
611 goto out;
612 if (*(args[1]) == 0) {
613 ha_alert("parsing [%s:%d] : '%s' expects an integer argument in kb/s.\n", file, linenum, args[0]);
614 err_code |= ERR_ALERT | ERR_FATAL;
615 goto out;
616 }
617 global.comp_rate_lim = atoi(args[1]) * 1024;
618 }
619 else if (!strcmp(args[0], "maxpipes")) {
620 if (alertif_too_many_args(1, file, linenum, args, &err_code))
621 goto out;
622 if (global.maxpipes != 0) {
623 ha_alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
624 err_code |= ERR_ALERT;
625 goto out;
626 }
627 if (*(args[1]) == 0) {
628 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
629 err_code |= ERR_ALERT | ERR_FATAL;
630 goto out;
631 }
632 global.maxpipes = atol(args[1]);
633 }
634 else if (!strcmp(args[0], "maxzlibmem")) {
635 if (alertif_too_many_args(1, file, linenum, args, &err_code))
636 goto out;
637 if (*(args[1]) == 0) {
638 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
639 err_code |= ERR_ALERT | ERR_FATAL;
640 goto out;
641 }
642 global.maxzlibmem = atol(args[1]) * 1024L * 1024L;
643 }
644 else if (!strcmp(args[0], "maxcompcpuusage")) {
645 if (alertif_too_many_args(1, file, linenum, args, &err_code))
646 goto out;
647 if (*(args[1]) == 0) {
648 ha_alert("parsing [%s:%d] : '%s' expects an integer argument between 0 and 100.\n", file, linenum, args[0]);
649 err_code |= ERR_ALERT | ERR_FATAL;
650 goto out;
651 }
652 compress_min_idle = 100 - atoi(args[1]);
653 if (compress_min_idle > 100) {
654 ha_alert("parsing [%s:%d] : '%s' expects an integer argument between 0 and 100.\n", file, linenum, args[0]);
655 err_code |= ERR_ALERT | ERR_FATAL;
656 goto out;
657 }
658 }
659
660 else if (!strcmp(args[0], "ulimit-n")) {
661 if (alertif_too_many_args(1, file, linenum, args, &err_code))
662 goto out;
663 if (global.rlimit_nofile != 0) {
664 ha_alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
665 err_code |= ERR_ALERT;
666 goto out;
667 }
668 if (*(args[1]) == 0) {
669 ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
670 err_code |= ERR_ALERT | ERR_FATAL;
671 goto out;
672 }
673 global.rlimit_nofile = atol(args[1]);
674 }
675 else if (!strcmp(args[0], "chroot")) {
676 if (alertif_too_many_args(1, file, linenum, args, &err_code))
677 goto out;
678 if (global.chroot != NULL) {
679 ha_alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
680 err_code |= ERR_ALERT;
681 goto out;
682 }
683 if (*(args[1]) == 0) {
684 ha_alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
685 err_code |= ERR_ALERT | ERR_FATAL;
686 goto out;
687 }
688 global.chroot = strdup(args[1]);
689 }
690 else if (!strcmp(args[0], "description")) {
691 int i, len=0;
692 char *d;
693
694 if (!*args[1]) {
695 ha_alert("parsing [%s:%d]: '%s' expects a string argument.\n",
696 file, linenum, args[0]);
697 err_code |= ERR_ALERT | ERR_FATAL;
698 goto out;
699 }
700
701 for (i = 1; *args[i]; i++)
702 len += strlen(args[i]) + 1;
703
704 if (global.desc)
705 free(global.desc);
706
707 global.desc = d = calloc(1, len);
708
709 d += snprintf(d, global.desc + len - d, "%s", args[1]);
710 for (i = 2; *args[i]; i++)
711 d += snprintf(d, global.desc + len - d, " %s", args[i]);
712 }
713 else if (!strcmp(args[0], "node")) {
714 int i;
715 char c;
716
717 if (alertif_too_many_args(1, file, linenum, args, &err_code))
718 goto out;
719
720 for (i=0; args[1][i]; i++) {
721 c = args[1][i];
722 if (!isupper((unsigned char)c) && !islower((unsigned char)c) &&
723 !isdigit((unsigned char)c) && c != '_' && c != '-' && c != '.')
724 break;
725 }
726
727 if (!i || args[1][i]) {
728 ha_alert("parsing [%s:%d]: '%s' requires valid node name - non-empty string"
729 " with digits(0-9), letters(A-Z, a-z), dot(.), hyphen(-) or underscode(_).\n",
730 file, linenum, args[0]);
731 err_code |= ERR_ALERT | ERR_FATAL;
732 goto out;
733 }
734
735 if (global.node)
736 free(global.node);
737
738 global.node = strdup(args[1]);
739 }
740 else if (!strcmp(args[0], "pidfile")) {
741 if (alertif_too_many_args(1, file, linenum, args, &err_code))
742 goto out;
743 if (global.pidfile != NULL) {
744 ha_alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
745 err_code |= ERR_ALERT;
746 goto out;
747 }
748 if (*(args[1]) == 0) {
749 ha_alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
750 err_code |= ERR_ALERT | ERR_FATAL;
751 goto out;
752 }
753 global.pidfile = strdup(args[1]);
754 }
755 else if (!strcmp(args[0], "unix-bind")) {
756 int cur_arg = 1;
757 while (*(args[cur_arg])) {
758 if (!strcmp(args[cur_arg], "prefix")) {
759 if (global.unix_bind.prefix != NULL) {
760 ha_alert("parsing [%s:%d] : unix-bind '%s' already specified. Continuing.\n", file, linenum, args[cur_arg]);
761 err_code |= ERR_ALERT;
762 cur_arg += 2;
763 continue;
764 }
765
766 if (*(args[cur_arg+1]) == 0) {
767 ha_alert("parsing [%s:%d] : unix_bind '%s' expects a path as an argument.\n", file, linenum, args[cur_arg]);
768 err_code |= ERR_ALERT | ERR_FATAL;
769 goto out;
770 }
771 global.unix_bind.prefix = strdup(args[cur_arg+1]);
772 cur_arg += 2;
773 continue;
774 }
775
776 if (!strcmp(args[cur_arg], "mode")) {
777
778 global.unix_bind.ux.mode = strtol(args[cur_arg + 1], NULL, 8);
779 cur_arg += 2;
780 continue;
781 }
782
783 if (!strcmp(args[cur_arg], "uid")) {
784
785 global.unix_bind.ux.uid = atol(args[cur_arg + 1 ]);
786 cur_arg += 2;
787 continue;
788 }
789
790 if (!strcmp(args[cur_arg], "gid")) {
791
792 global.unix_bind.ux.gid = atol(args[cur_arg + 1 ]);
793 cur_arg += 2;
794 continue;
795 }
796
797 if (!strcmp(args[cur_arg], "user")) {
798 struct passwd *user;
799
800 user = getpwnam(args[cur_arg + 1]);
801 if (!user) {
802 ha_alert("parsing [%s:%d] : '%s' : '%s' unknown user.\n",
803 file, linenum, args[0], args[cur_arg + 1 ]);
804 err_code |= ERR_ALERT | ERR_FATAL;
805 goto out;
806 }
807
808 global.unix_bind.ux.uid = user->pw_uid;
809 cur_arg += 2;
810 continue;
811 }
812
813 if (!strcmp(args[cur_arg], "group")) {
814 struct group *group;
815
816 group = getgrnam(args[cur_arg + 1]);
817 if (!group) {
818 ha_alert("parsing [%s:%d] : '%s' : '%s' unknown group.\n",
819 file, linenum, args[0], args[cur_arg + 1 ]);
820 err_code |= ERR_ALERT | ERR_FATAL;
821 goto out;
822 }
823
824 global.unix_bind.ux.gid = group->gr_gid;
825 cur_arg += 2;
826 continue;
827 }
828
829 ha_alert("parsing [%s:%d] : '%s' only supports the 'prefix', 'mode', 'uid', 'gid', 'user' and 'group' options.\n",
830 file, linenum, args[0]);
831 err_code |= ERR_ALERT | ERR_FATAL;
832 goto out;
833 }
834 }
835 else if (!strcmp(args[0], "log")) { /* "no log" or "log ..." */
836 if (!parse_logsrv(args, &global.logsrvs, (kwm == KWM_NO), &errmsg)) {
837 ha_alert("parsing [%s:%d] : %s : %s\n", file, linenum, args[0], errmsg);
838 err_code |= ERR_ALERT | ERR_FATAL;
839 goto out;
840 }
841 }
842 else if (!strcmp(args[0], "log-send-hostname")) { /* set the hostname in syslog header */
843 char *name;
844
845 if (global.log_send_hostname != NULL) {
846 ha_alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
847 err_code |= ERR_ALERT;
848 goto out;
849 }
850
851 if (*(args[1]))
852 name = args[1];
853 else
854 name = hostname;
855
856 free(global.log_send_hostname);
857 global.log_send_hostname = strdup(name);
858 }
859 else if (!strcmp(args[0], "server-state-base")) { /* path base where HAProxy can find server state files */
860 if (global.server_state_base != NULL) {
861 ha_alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
862 err_code |= ERR_ALERT;
863 goto out;
864 }
865
866 if (!*(args[1])) {
867 ha_alert("parsing [%s:%d] : '%s' expects one argument: a directory path.\n", file, linenum, args[0]);
868 err_code |= ERR_FATAL;
869 goto out;
870 }
871
872 global.server_state_base = strdup(args[1]);
873 }
874 else if (!strcmp(args[0], "server-state-file")) { /* path to the file where HAProxy can load the server states */
875 if (global.server_state_file != NULL) {
876 ha_alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
877 err_code |= ERR_ALERT;
878 goto out;
879 }
880
881 if (!*(args[1])) {
882 ha_alert("parsing [%s:%d] : '%s' expect one argument: a file path.\n", file, linenum, args[0]);
883 err_code |= ERR_FATAL;
884 goto out;
885 }
886
887 global.server_state_file = strdup(args[1]);
888 }
889 else if (!strcmp(args[0], "log-tag")) { /* tag to report to syslog */
890 if (alertif_too_many_args(1, file, linenum, args, &err_code))
891 goto out;
892 if (*(args[1]) == 0) {
893 ha_alert("parsing [%s:%d] : '%s' expects a tag for use in syslog.\n", file, linenum, args[0]);
894 err_code |= ERR_ALERT | ERR_FATAL;
895 goto out;
896 }
897 chunk_destroy(&global.log_tag);
898 chunk_initstr(&global.log_tag, strdup(args[1]));
899 }
900 else if (!strcmp(args[0], "spread-checks")) { /* random time between checks (0-50) */
901 if (alertif_too_many_args(1, file, linenum, args, &err_code))
902 goto out;
903 if (global.spread_checks != 0) {
904 ha_alert("parsing [%s:%d]: spread-checks already specified. Continuing.\n", file, linenum);
905 err_code |= ERR_ALERT;
906 goto out;
907 }
908 if (*(args[1]) == 0) {
909 ha_alert("parsing [%s:%d]: '%s' expects an integer argument (0..50).\n", file, linenum, args[0]);
910 err_code |= ERR_ALERT | ERR_FATAL;
911 goto out;
912 }
913 global.spread_checks = atol(args[1]);
914 if (global.spread_checks < 0 || global.spread_checks > 50) {
915 ha_alert("parsing [%s:%d]: 'spread-checks' needs a positive value in range 0..50.\n", file, linenum);
916 err_code |= ERR_ALERT | ERR_FATAL;
917 }
918 }
919 else if (!strcmp(args[0], "max-spread-checks")) { /* maximum time between first and last check */
920 const char *err;
921 unsigned int val;
922
923 if (alertif_too_many_args(1, file, linenum, args, &err_code))
924 goto out;
925 if (*(args[1]) == 0) {
926 ha_alert("parsing [%s:%d]: '%s' expects an integer argument (0..50).\n", file, linenum, args[0]);
927 err_code |= ERR_ALERT | ERR_FATAL;
928 goto out;
929 }
930
931 err = parse_time_err(args[1], &val, TIME_UNIT_MS);
932 if (err) {
933 ha_alert("parsing [%s:%d]: unsupported character '%c' in '%s' (wants an integer delay).\n", file, linenum, *err, args[0]);
934 err_code |= ERR_ALERT | ERR_FATAL;
935 }
936 global.max_spread_checks = val;
937 if (global.max_spread_checks < 0) {
938 ha_alert("parsing [%s:%d]: '%s' needs a positive delay in milliseconds.\n",file, linenum, args[0]);
939 err_code |= ERR_ALERT | ERR_FATAL;
940 }
941 }
942 else if (strcmp(args[0], "cpu-map") == 0) {
943 /* map a process list to a CPU set */
944#ifdef USE_CPU_AFFINITY
945 char *slash;
946 unsigned long proc = 0, thread = 0, cpus;
947 int i, j, n, autoinc;
948
949 if (!*args[1] || !*args[2]) {
950 ha_alert("parsing [%s:%d] : %s expects a process number "
951 " ('all', 'odd', 'even', a number from 1 to %d or a range), "
952 " followed by a list of CPU ranges with numbers from 0 to %d.\n",
Willy Tarreau5799e9c2019-03-05 18:14:03 +0100953 file, linenum, args[0], LONGBITS, LONGBITS - 1);
Willy Tarreau36b9e222018-11-11 15:19:52 +0100954 err_code |= ERR_ALERT | ERR_FATAL;
955 goto out;
956 }
957
958 if ((slash = strchr(args[1], '/')) != NULL)
959 *slash = 0;
960
Willy Tarreau5799e9c2019-03-05 18:14:03 +0100961 /* note: we silently ignore processes over MAX_PROCS and
962 * threads over MAX_THREADS so as not to make configurations a
963 * pain to maintain.
964 */
965 if (parse_process_number(args[1], &proc, LONGBITS, &autoinc, &errmsg)) {
Willy Tarreau36b9e222018-11-11 15:19:52 +0100966 ha_alert("parsing [%s:%d] : %s : %s\n", file, linenum, args[0], errmsg);
967 err_code |= ERR_ALERT | ERR_FATAL;
968 goto out;
969 }
970
971 if (slash) {
Willy Tarreau5799e9c2019-03-05 18:14:03 +0100972 if (parse_process_number(slash+1, &thread, LONGBITS, NULL, &errmsg)) {
Willy Tarreau36b9e222018-11-11 15:19:52 +0100973 ha_alert("parsing [%s:%d] : %s : %s\n", file, linenum, args[0], errmsg);
974 err_code |= ERR_ALERT | ERR_FATAL;
975 goto out;
976 }
977 *slash = '/';
978
979 if (autoinc && atleast2(proc) && atleast2(thread)) {
980 ha_alert("parsing [%s:%d] : %s : '%s' : unable to automatically bind "
981 "a process range _AND_ a thread range\n",
982 file, linenum, args[0], args[1]);
983 err_code |= ERR_ALERT | ERR_FATAL;
984 goto out;
985 }
986 }
987
988 if (parse_cpu_set((const char **)args+2, &cpus, &errmsg)) {
989 ha_alert("parsing [%s:%d] : %s : %s\n", file, linenum, args[0], errmsg);
990 err_code |= ERR_ALERT | ERR_FATAL;
991 goto out;
992 }
993
994 if (autoinc &&
995 my_popcountl(proc) != my_popcountl(cpus) &&
996 my_popcountl(thread) != my_popcountl(cpus)) {
997 ha_alert("parsing [%s:%d] : %s : PROC/THREAD range and CPU sets "
998 "must have the same size to be automatically bound\n",
999 file, linenum, args[0]);
1000 err_code |= ERR_ALERT | ERR_FATAL;
1001 goto out;
1002 }
1003
Willy Tarreauff9c9142019-02-07 10:39:36 +01001004 for (i = n = 0; i < MAX_PROCS; i++) {
Willy Tarreau36b9e222018-11-11 15:19:52 +01001005 /* No mapping for this process */
1006 if (!(proc & (1UL << i)))
1007 continue;
1008
1009 /* Mapping at the process level */
1010 if (!thread) {
1011 if (!autoinc)
1012 global.cpu_map.proc[i] = cpus;
1013 else {
1014 n += my_ffsl(cpus >> n);
1015 global.cpu_map.proc[i] = (1UL << (n-1));
1016 }
1017 continue;
1018 }
1019
1020 /* Mapping at the thread level */
1021 for (j = 0; j < MAX_THREADS; j++) {
1022 /* Np mapping for this thread */
1023 if (!(thread & (1UL << j)))
1024 continue;
1025
1026 if (!autoinc)
1027 global.cpu_map.thread[i][j] = cpus;
1028 else {
1029 n += my_ffsl(cpus >> n);
1030 global.cpu_map.thread[i][j] = (1UL << (n-1));
1031 }
1032 }
1033 }
1034#else
1035 ha_alert("parsing [%s:%d] : '%s' is not enabled, please check build options for USE_CPU_AFFINITY.\n",
1036 file, linenum, args[0]);
1037 err_code |= ERR_ALERT | ERR_FATAL;
1038 goto out;
1039#endif /* ! USE_CPU_AFFINITY */
1040 }
1041 else if (strcmp(args[0], "setenv") == 0 || strcmp(args[0], "presetenv") == 0) {
1042 if (alertif_too_many_args(3, file, linenum, args, &err_code))
1043 goto out;
1044
1045 if (*(args[2]) == 0) {
1046 ha_alert("parsing [%s:%d]: '%s' expects a name and a value.\n", file, linenum, args[0]);
1047 err_code |= ERR_ALERT | ERR_FATAL;
1048 goto out;
1049 }
1050
1051 /* "setenv" overwrites, "presetenv" only sets if not yet set */
1052 if (setenv(args[1], args[2], (args[0][0] == 's')) != 0) {
1053 ha_alert("parsing [%s:%d]: '%s' failed on variable '%s' : %s.\n", file, linenum, args[0], args[1], strerror(errno));
1054 err_code |= ERR_ALERT | ERR_FATAL;
1055 goto out;
1056 }
1057 }
1058 else if (!strcmp(args[0], "unsetenv")) {
1059 int arg;
1060
1061 if (*(args[1]) == 0) {
1062 ha_alert("parsing [%s:%d]: '%s' expects at least one variable name.\n", file, linenum, args[0]);
1063 err_code |= ERR_ALERT | ERR_FATAL;
1064 goto out;
1065 }
1066
1067 for (arg = 1; *args[arg]; arg++) {
1068 if (unsetenv(args[arg]) != 0) {
1069 ha_alert("parsing [%s:%d]: '%s' failed on variable '%s' : %s.\n", file, linenum, args[0], args[arg], strerror(errno));
1070 err_code |= ERR_ALERT | ERR_FATAL;
1071 goto out;
1072 }
1073 }
1074 }
1075 else if (!strcmp(args[0], "resetenv")) {
1076 extern char **environ;
1077 char **env = environ;
1078
1079 /* args contain variable names to keep, one per argument */
1080 while (*env) {
1081 int arg;
1082
1083 /* look for current variable in among all those we want to keep */
1084 for (arg = 1; *args[arg]; arg++) {
1085 if (strncmp(*env, args[arg], strlen(args[arg])) == 0 &&
1086 (*env)[strlen(args[arg])] == '=')
1087 break;
1088 }
1089
1090 /* delete this variable */
1091 if (!*args[arg]) {
1092 char *delim = strchr(*env, '=');
1093
1094 if (!delim || delim - *env >= trash.size) {
1095 ha_alert("parsing [%s:%d]: '%s' failed to unset invalid variable '%s'.\n", file, linenum, args[0], *env);
1096 err_code |= ERR_ALERT | ERR_FATAL;
1097 goto out;
1098 }
1099
1100 memcpy(trash.area, *env, delim - *env);
1101 trash.area[delim - *env] = 0;
1102
1103 if (unsetenv(trash.area) != 0) {
1104 ha_alert("parsing [%s:%d]: '%s' failed to unset variable '%s' : %s.\n", file, linenum, args[0], *env, strerror(errno));
1105 err_code |= ERR_ALERT | ERR_FATAL;
1106 goto out;
1107 }
1108 }
1109 else
1110 env++;
1111 }
1112 }
1113 else {
1114 struct cfg_kw_list *kwl;
1115 int index;
1116 int rc;
1117
1118 list_for_each_entry(kwl, &cfg_keywords.list, list) {
1119 for (index = 0; kwl->kw[index].kw != NULL; index++) {
1120 if (kwl->kw[index].section != CFG_GLOBAL)
1121 continue;
1122 if (strcmp(kwl->kw[index].kw, args[0]) == 0) {
1123 rc = kwl->kw[index].parse(args, CFG_GLOBAL, NULL, NULL, file, linenum, &errmsg);
1124 if (rc < 0) {
1125 ha_alert("parsing [%s:%d] : %s\n", file, linenum, errmsg);
1126 err_code |= ERR_ALERT | ERR_FATAL;
1127 }
1128 else if (rc > 0) {
1129 ha_warning("parsing [%s:%d] : %s\n", file, linenum, errmsg);
1130 err_code |= ERR_WARN;
1131 goto out;
1132 }
1133 goto out;
1134 }
1135 }
1136 }
1137
1138 ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
1139 err_code |= ERR_ALERT | ERR_FATAL;
1140 }
1141
1142 out:
1143 free(errmsg);
1144 return err_code;
1145}
1146