]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/conf-parser.c
journald: parse configuration file
[thirdparty/systemd.git] / src / conf-parser.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
ed5bcfbe 2
a7334b09
LP
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
ed5bcfbe
LP
22#include <string.h>
23#include <stdio.h>
24#include <errno.h>
25#include <assert.h>
26#include <stdlib.h>
27
28#include "conf-parser.h"
29#include "util.h"
30#include "macro.h"
57d42a5f 31#include "strv.h"
16354eff 32#include "log.h"
ed5bcfbe 33
f975e971
LP
34int config_item_table_lookup(
35 void *table,
ed5bcfbe 36 const char *section,
ed5bcfbe 37 const char *lvalue,
f975e971
LP
38 ConfigParserCallback *func,
39 int *ltype,
40 void **data,
ed5bcfbe
LP
41 void *userdata) {
42
f975e971
LP
43 ConfigTableItem *t;
44
45 assert(table);
ed5bcfbe 46 assert(lvalue);
f975e971
LP
47 assert(func);
48 assert(ltype);
49 assert(data);
ed5bcfbe 50
f975e971 51 for (t = table; t->lvalue; t++) {
ed5bcfbe 52
f975e971 53 if (!streq(lvalue, t->lvalue))
ed5bcfbe
LP
54 continue;
55
f975e971 56 if (!streq_ptr(section, t->section))
ed5bcfbe
LP
57 continue;
58
f975e971
LP
59 *func = t->parse;
60 *ltype = t->ltype;
61 *data = t->data;
62 return 1;
63 }
ed5bcfbe 64
f975e971
LP
65 return 0;
66}
10e87ee7 67
f975e971
LP
68int config_item_perf_lookup(
69 void *table,
70 const char *section,
71 const char *lvalue,
72 ConfigParserCallback *func,
73 int *ltype,
74 void **data,
75 void *userdata) {
76
77 ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
78 const ConfigPerfItem *p;
79
80 assert(table);
81 assert(lvalue);
82 assert(func);
83 assert(ltype);
84 assert(data);
85
86 if (!section)
87 p = lookup(lvalue, strlen(lvalue));
88 else {
89 char *key;
90
44d91056
LP
91 key = join(section, ".", lvalue, NULL);
92 if (!key)
f975e971
LP
93 return -ENOMEM;
94
95 p = lookup(key, strlen(key));
96 free(key);
ed5bcfbe
LP
97 }
98
f975e971
LP
99 if (!p)
100 return 0;
101
102 *func = p->parse;
103 *ltype = p->ltype;
104 *data = (uint8_t*) userdata + p->offset;
105 return 1;
106}
107
108/* Run the user supplied parser for an assignment */
109static int next_assignment(
110 const char *filename,
111 unsigned line,
112 ConfigItemLookup lookup,
113 void *table,
114 const char *section,
115 const char *lvalue,
116 const char *rvalue,
117 bool relaxed,
118 void *userdata) {
119
120 ConfigParserCallback func = NULL;
121 int ltype = 0;
122 void *data = NULL;
123 int r;
124
125 assert(filename);
126 assert(line > 0);
127 assert(lookup);
128 assert(lvalue);
129 assert(rvalue);
130
131 r = lookup(table, section, lvalue, &func, &ltype, &data, userdata);
132 if (r < 0)
133 return r;
134
d937fbbd
LP
135 if (r > 0) {
136 if (func)
137 return func(filename, line, section, lvalue, ltype, rvalue, data, userdata);
138
139 return 0;
140 }
f975e971 141
46205bb6 142 /* Warn about unknown non-extension fields. */
10e87ee7 143 if (!relaxed && !startswith(lvalue, "X-"))
f975e971 144 log_info("[%s:%u] Unknown lvalue '%s' in section '%s'. Ignoring.", filename, line, lvalue, section);
46205bb6 145
f1857be0 146 return 0;
ed5bcfbe
LP
147}
148
ed5bcfbe 149/* Parse a variable assignment line */
f975e971
LP
150static int parse_line(
151 const char *filename,
152 unsigned line,
153 const char *sections,
154 ConfigItemLookup lookup,
155 void *table,
156 bool relaxed,
157 char **section,
158 char *l,
159 void *userdata) {
160
b2aa81ef 161 char *e;
ed5bcfbe 162
f975e971
LP
163 assert(filename);
164 assert(line > 0);
165 assert(lookup);
166 assert(l);
167
b2aa81ef 168 l = strstrip(l);
ed5bcfbe 169
b2aa81ef 170 if (!*l)
ed5bcfbe 171 return 0;
1ea86b18 172
b2aa81ef 173 if (strchr(COMMENTS, *l))
1ea86b18 174 return 0;
ed5bcfbe 175
b2aa81ef
LP
176 if (startswith(l, ".include ")) {
177 char *fn;
ed5bcfbe
LP
178 int r;
179
f975e971
LP
180 fn = file_in_same_dir(filename, strstrip(l+9));
181 if (!fn)
b2aa81ef 182 return -ENOMEM;
ed5bcfbe 183
f975e971 184 r = config_parse(fn, NULL, sections, lookup, table, relaxed, userdata);
b2aa81ef
LP
185 free(fn);
186
ed5bcfbe
LP
187 return r;
188 }
189
b2aa81ef 190 if (*l == '[') {
ed5bcfbe
LP
191 size_t k;
192 char *n;
193
b2aa81ef 194 k = strlen(l);
ed5bcfbe
LP
195 assert(k > 0);
196
b2aa81ef 197 if (l[k-1] != ']') {
16354eff 198 log_error("[%s:%u] Invalid section header.", filename, line);
ed5bcfbe
LP
199 return -EBADMSG;
200 }
201
f975e971
LP
202 n = strndup(l+1, k-2);
203 if (!n)
ed5bcfbe
LP
204 return -ENOMEM;
205
f975e971 206 if (sections && !nulstr_contains(sections, n)) {
42f4e3c4 207
f975e971
LP
208 if (!relaxed)
209 log_info("[%s:%u] Unknown section '%s'. Ignoring.", filename, line, n);
210
211 free(n);
212 *section = NULL;
213 } else {
214 free(*section);
215 *section = n;
216 }
ed5bcfbe
LP
217
218 return 0;
219 }
220
f975e971 221 if (sections && !*section)
10e87ee7
LP
222 return 0;
223
f975e971
LP
224 e = strchr(l, '=');
225 if (!e) {
16354eff 226 log_error("[%s:%u] Missing '='.", filename, line);
ed5bcfbe
LP
227 return -EBADMSG;
228 }
229
230 *e = 0;
231 e++;
232
f975e971
LP
233 return next_assignment(
234 filename,
235 line,
236 lookup,
237 table,
238 *section,
239 strstrip(l),
240 strstrip(e),
241 relaxed,
242 userdata);
ed5bcfbe
LP
243}
244
245/* Go through the file and parse each line */
f975e971
LP
246int config_parse(
247 const char *filename,
248 FILE *f,
249 const char *sections,
250 ConfigItemLookup lookup,
251 void *table,
252 bool relaxed,
253 void *userdata) {
254
ed5bcfbe
LP
255 unsigned line = 0;
256 char *section = NULL;
ed5bcfbe 257 int r;
63ad1ab4 258 bool ours = false;
3dab2943 259 char *continuation = NULL;
ed5bcfbe
LP
260
261 assert(filename);
f975e971 262 assert(lookup);
ed5bcfbe 263
87f0e418 264 if (!f) {
f975e971
LP
265 f = fopen(filename, "re");
266 if (!f) {
87f0e418
LP
267 r = -errno;
268 log_error("Failed to open configuration file '%s': %s", filename, strerror(-r));
269 goto finish;
270 }
63ad1ab4
LP
271
272 ours = true;
ed5bcfbe
LP
273 }
274
275 while (!feof(f)) {
3dab2943
LP
276 char l[LINE_MAX], *p, *c = NULL, *e;
277 bool escaped = false;
ed5bcfbe
LP
278
279 if (!fgets(l, sizeof(l), f)) {
280 if (feof(f))
281 break;
282
283 r = -errno;
16354eff 284 log_error("Failed to read configuration file '%s': %s", filename, strerror(-r));
ed5bcfbe
LP
285 goto finish;
286 }
287
3dab2943
LP
288 truncate_nl(l);
289
290 if (continuation) {
f975e971
LP
291 c = strappend(continuation, l);
292 if (!c) {
3dab2943
LP
293 r = -ENOMEM;
294 goto finish;
295 }
296
297 free(continuation);
298 continuation = NULL;
299 p = c;
300 } else
301 p = l;
302
303 for (e = p; *e; e++) {
304 if (escaped)
305 escaped = false;
306 else if (*e == '\\')
307 escaped = true;
308 }
309
310 if (escaped) {
311 *(e-1) = ' ';
312
313 if (c)
314 continuation = c;
f975e971
LP
315 else {
316 continuation = strdup(l);
8ea913b2 317 if (!continuation) {
f975e971
LP
318 r = -ENOMEM;
319 goto finish;
320 }
3dab2943
LP
321 }
322
323 continue;
324 }
325
f975e971
LP
326 r = parse_line(filename,
327 ++line,
328 sections,
329 lookup,
330 table,
331 relaxed,
332 &section,
333 p,
334 userdata);
3dab2943
LP
335 free(c);
336
337 if (r < 0)
ed5bcfbe
LP
338 goto finish;
339 }
340
341 r = 0;
342
343finish:
344 free(section);
3dab2943 345 free(continuation);
ed5bcfbe 346
63ad1ab4 347 if (f && ours)
ed5bcfbe
LP
348 fclose(f);
349
350 return r;
351}
352
353int config_parse_int(
354 const char *filename,
355 unsigned line,
356 const char *section,
357 const char *lvalue,
2b583ce6 358 int ltype,
ed5bcfbe
LP
359 const char *rvalue,
360 void *data,
361 void *userdata) {
362
363 int *i = data;
364 int r;
365
366 assert(filename);
367 assert(lvalue);
368 assert(rvalue);
369 assert(data);
370
371 if ((r = safe_atoi(rvalue, i)) < 0) {
f975e971
LP
372 log_error("[%s:%u] Failed to parse numeric value, ingoring: %s", filename, line, rvalue);
373 return 0;
ed5bcfbe
LP
374 }
375
376 return 0;
377}
378
916abb21
LP
379int config_parse_long(
380 const char *filename,
381 unsigned line,
382 const char *section,
383 const char *lvalue,
384 int ltype,
385 const char *rvalue,
386 void *data,
387 void *userdata) {
388
389 long *i = data;
390 int r;
391
392 assert(filename);
393 assert(lvalue);
394 assert(rvalue);
395 assert(data);
396
397 if ((r = safe_atoli(rvalue, i)) < 0) {
f975e971
LP
398 log_error("[%s:%u] Failed to parse numeric value, ignoring: %s", filename, line, rvalue);
399 return 0;
916abb21
LP
400 }
401
402 return 0;
403}
404
ec863ba6
LP
405int config_parse_uint64(
406 const char *filename,
407 unsigned line,
408 const char *section,
409 const char *lvalue,
2b583ce6 410 int ltype,
ec863ba6
LP
411 const char *rvalue,
412 void *data,
413 void *userdata) {
414
415 uint64_t *u = data;
416 int r;
417
418 assert(filename);
419 assert(lvalue);
420 assert(rvalue);
421 assert(data);
422
423 if ((r = safe_atou64(rvalue, u)) < 0) {
f975e971
LP
424 log_error("[%s:%u] Failed to parse numeric value, ignoring: %s", filename, line, rvalue);
425 return 0;
ec863ba6
LP
426 }
427
428 return 0;
429}
430
ed5bcfbe
LP
431int config_parse_unsigned(
432 const char *filename,
433 unsigned line,
434 const char *section,
435 const char *lvalue,
2b583ce6 436 int ltype,
ed5bcfbe
LP
437 const char *rvalue,
438 void *data,
439 void *userdata) {
440
441 unsigned *u = data;
442 int r;
443
444 assert(filename);
445 assert(lvalue);
446 assert(rvalue);
447 assert(data);
448
449 if ((r = safe_atou(rvalue, u)) < 0) {
16354eff 450 log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
ed5bcfbe
LP
451 return r;
452 }
453
454 return 0;
455}
456
457int config_parse_size(
458 const char *filename,
459 unsigned line,
460 const char *section,
461 const char *lvalue,
2b583ce6 462 int ltype,
ed5bcfbe
LP
463 const char *rvalue,
464 void *data,
465 void *userdata) {
466
467 size_t *sz = data;
468 unsigned u;
469 int r;
470
471 assert(filename);
472 assert(lvalue);
473 assert(rvalue);
474 assert(data);
475
476 if ((r = safe_atou(rvalue, &u)) < 0) {
f975e971
LP
477 log_error("[%s:%u] Failed to parse numeric value, ignoring: %s", filename, line, rvalue);
478 return 0;
ed5bcfbe
LP
479 }
480
481 *sz = (size_t) u;
482 return 0;
483}
484
485int config_parse_bool(
486 const char *filename,
487 unsigned line,
488 const char *section,
489 const char *lvalue,
2b583ce6 490 int ltype,
ed5bcfbe
LP
491 const char *rvalue,
492 void *data,
493 void *userdata) {
494
495 int k;
496 bool *b = data;
497
498 assert(filename);
499 assert(lvalue);
500 assert(rvalue);
501 assert(data);
502
503 if ((k = parse_boolean(rvalue)) < 0) {
f975e971
LP
504 log_error("[%s:%u] Failed to parse boolean value, ignoring: %s", filename, line, rvalue);
505 return 0;
ed5bcfbe
LP
506 }
507
508 *b = !!k;
509 return 0;
510}
511
512int config_parse_string(
513 const char *filename,
514 unsigned line,
515 const char *section,
516 const char *lvalue,
2b583ce6 517 int ltype,
ed5bcfbe
LP
518 const char *rvalue,
519 void *data,
520 void *userdata) {
521
522 char **s = data;
523 char *n;
524
525 assert(filename);
526 assert(lvalue);
527 assert(rvalue);
528 assert(data);
529
530 if (*rvalue) {
531 if (!(n = strdup(rvalue)))
532 return -ENOMEM;
533 } else
534 n = NULL;
535
536 free(*s);
537 *s = n;
538
539 return 0;
540}
57d42a5f 541
034c6ed7
LP
542int config_parse_path(
543 const char *filename,
544 unsigned line,
545 const char *section,
546 const char *lvalue,
2b583ce6 547 int ltype,
034c6ed7
LP
548 const char *rvalue,
549 void *data,
550 void *userdata) {
551
552 char **s = data;
553 char *n;
554
555 assert(filename);
556 assert(lvalue);
557 assert(rvalue);
558 assert(data);
559
15ae422b 560 if (!path_is_absolute(rvalue)) {
f975e971
LP
561 log_error("[%s:%u] Not an absolute path, ignoring: %s", filename, line, rvalue);
562 return 0;
034c6ed7
LP
563 }
564
565 if (!(n = strdup(rvalue)))
566 return -ENOMEM;
567
01f78473
LP
568 path_kill_slashes(n);
569
034c6ed7
LP
570 free(*s);
571 *s = n;
572
573 return 0;
574}
57d42a5f
LP
575
576int config_parse_strv(
577 const char *filename,
578 unsigned line,
579 const char *section,
580 const char *lvalue,
2b583ce6 581 int ltype,
57d42a5f
LP
582 const char *rvalue,
583 void *data,
584 void *userdata) {
585
586 char*** sv = data;
587 char **n;
588 char *w;
589 unsigned k;
590 size_t l;
591 char *state;
592
593 assert(filename);
594 assert(lvalue);
595 assert(rvalue);
596 assert(data);
597
598 k = strv_length(*sv);
034c6ed7 599 FOREACH_WORD_QUOTED(w, l, rvalue, state)
57d42a5f
LP
600 k++;
601
602 if (!(n = new(char*, k+1)))
603 return -ENOMEM;
604
3251df7d
LP
605 if (*sv)
606 for (k = 0; (*sv)[k]; k++)
607 n[k] = (*sv)[k];
7418040c
LP
608 else
609 k = 0;
3251df7d 610
034c6ed7 611 FOREACH_WORD_QUOTED(w, l, rvalue, state)
f60f22df 612 if (!(n[k++] = cunescape_length(w, l)))
57d42a5f
LP
613 goto fail;
614
615 n[k] = NULL;
616 free(*sv);
617 *sv = n;
618
619 return 0;
620
621fail:
622 for (; k > 0; k--)
623 free(n[k-1]);
034c6ed7 624 free(n);
57d42a5f
LP
625
626 return -ENOMEM;
627}
15ae422b
LP
628
629int config_parse_path_strv(
630 const char *filename,
631 unsigned line,
632 const char *section,
633 const char *lvalue,
2b583ce6 634 int ltype,
15ae422b
LP
635 const char *rvalue,
636 void *data,
637 void *userdata) {
638
639 char*** sv = data;
640 char **n;
641 char *w;
642 unsigned k;
643 size_t l;
644 char *state;
645 int r;
646
647 assert(filename);
648 assert(lvalue);
649 assert(rvalue);
650 assert(data);
651
652 k = strv_length(*sv);
653 FOREACH_WORD_QUOTED(w, l, rvalue, state)
654 k++;
655
656 if (!(n = new(char*, k+1)))
657 return -ENOMEM;
658
659 k = 0;
660 if (*sv)
661 for (; (*sv)[k]; k++)
662 n[k] = (*sv)[k];
663
664 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
f60f22df 665 if (!(n[k] = cunescape_length(w, l))) {
15ae422b
LP
666 r = -ENOMEM;
667 goto fail;
668 }
669
670 if (!path_is_absolute(n[k])) {
f975e971
LP
671 log_error("[%s:%u] Not an absolute path, ignoring: %s", filename, line, rvalue);
672 free(n[k]);
673 continue;
15ae422b
LP
674 }
675
01f78473
LP
676 path_kill_slashes(n[k]);
677
15ae422b
LP
678 k++;
679 }
680
681 n[k] = NULL;
682 free(*sv);
683 *sv = n;
684
685 return 0;
686
687fail:
688 free(n[k]);
689 for (; k > 0; k--)
690 free(n[k-1]);
691 free(n);
692
693 return r;
694}
f975e971
LP
695
696int config_parse_usec(
697 const char *filename,
698 unsigned line,
699 const char *section,
700 const char *lvalue,
701 int ltype,
702 const char *rvalue,
703 void *data,
704 void *userdata) {
705
706 usec_t *usec = data;
707
708 assert(filename);
709 assert(lvalue);
710 assert(rvalue);
711 assert(data);
712
713 if (parse_usec(rvalue, usec) < 0) {
714 log_error("[%s:%u] Failed to parse time value, ignoring: %s", filename, line, rvalue);
715 return 0;
716 }
717
718 return 0;
719}
720
721int config_parse_mode(
722 const char *filename,
723 unsigned line,
724 const char *section,
725 const char *lvalue,
726 int ltype,
727 const char *rvalue,
728 void *data,
729 void *userdata) {
730
731 mode_t *m = data;
732 long l;
733 char *x = NULL;
734
735 assert(filename);
736 assert(lvalue);
737 assert(rvalue);
738 assert(data);
739
740 errno = 0;
741 l = strtol(rvalue, &x, 8);
742 if (!x || *x || errno) {
743 log_error("[%s:%u] Failed to parse mode value, ignoring: %s", filename, line, rvalue);
744 return 0;
745 }
746
747 if (l < 0000 || l > 07777) {
748 log_error("[%s:%u] mode value out of range, ignoring: %s", filename, line, rvalue);
749 return 0;
750 }
751
752 *m = (mode_t) l;
753 return 0;
754}
e6960940
LP
755
756int config_parse_bytes(
757 const char *filename,
758 unsigned line,
759 const char *section,
760 const char *lvalue,
761 int ltype,
762 const char *rvalue,
763 void *data,
764 void *userdata) {
765
766 uint64_t *bytes = data;
767
768 assert(filename);
769 assert(lvalue);
770 assert(rvalue);
771 assert(data);
772
773 assert_cc(sizeof(off_t) == sizeof(uint64_t));
774
775 if (parse_bytes(rvalue, bytes) < 0) {
776 log_error("[%s:%u] Failed to parse bytes value, ignoring: %s", filename, line, rvalue);
777 return 0;
778 }
779
780 return 0;
781}