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