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