]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/conf-parser.c
Merge pull request #1659 from vcaputo/journal_verify_envalid
[thirdparty/systemd.git] / src / shared / conf-parser.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
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 Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <string.h>
23 #include <stdio.h>
24 #include <errno.h>
25 #include <stdlib.h>
26
27 #include "sd-messages.h"
28 #include "conf-files.h"
29 #include "util.h"
30 #include "macro.h"
31 #include "strv.h"
32 #include "log.h"
33 #include "utf8.h"
34 #include "path-util.h"
35 #include "signal-util.h"
36 #include "conf-parser.h"
37
38 int config_item_table_lookup(
39 const void *table,
40 const char *section,
41 const char *lvalue,
42 ConfigParserCallback *func,
43 int *ltype,
44 void **data,
45 void *userdata) {
46
47 const ConfigTableItem *t;
48
49 assert(table);
50 assert(lvalue);
51 assert(func);
52 assert(ltype);
53 assert(data);
54
55 for (t = table; t->lvalue; t++) {
56
57 if (!streq(lvalue, t->lvalue))
58 continue;
59
60 if (!streq_ptr(section, t->section))
61 continue;
62
63 *func = t->parse;
64 *ltype = t->ltype;
65 *data = t->data;
66 return 1;
67 }
68
69 return 0;
70 }
71
72 int config_item_perf_lookup(
73 const void *table,
74 const char *section,
75 const char *lvalue,
76 ConfigParserCallback *func,
77 int *ltype,
78 void **data,
79 void *userdata) {
80
81 ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
82 const ConfigPerfItem *p;
83
84 assert(table);
85 assert(lvalue);
86 assert(func);
87 assert(ltype);
88 assert(data);
89
90 if (!section)
91 p = lookup(lvalue, strlen(lvalue));
92 else {
93 char *key;
94
95 key = strjoin(section, ".", lvalue, NULL);
96 if (!key)
97 return -ENOMEM;
98
99 p = lookup(key, strlen(key));
100 free(key);
101 }
102
103 if (!p)
104 return 0;
105
106 *func = p->parse;
107 *ltype = p->ltype;
108 *data = (uint8_t*) userdata + p->offset;
109 return 1;
110 }
111
112 /* Run the user supplied parser for an assignment */
113 static int next_assignment(const char *unit,
114 const char *filename,
115 unsigned line,
116 ConfigItemLookup lookup,
117 const void *table,
118 const char *section,
119 unsigned section_line,
120 const char *lvalue,
121 const char *rvalue,
122 bool relaxed,
123 void *userdata) {
124
125 ConfigParserCallback func = NULL;
126 int ltype = 0;
127 void *data = NULL;
128 int r;
129
130 assert(filename);
131 assert(line > 0);
132 assert(lookup);
133 assert(lvalue);
134 assert(rvalue);
135
136 r = lookup(table, section, lvalue, &func, &ltype, &data, userdata);
137 if (r < 0)
138 return r;
139
140 if (r > 0) {
141 if (func)
142 return func(unit, filename, line, section, section_line,
143 lvalue, ltype, rvalue, data, userdata);
144
145 return 0;
146 }
147
148 /* Warn about unknown non-extension fields. */
149 if (!relaxed && !startswith(lvalue, "X-"))
150 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown lvalue '%s' in section '%s'", lvalue, section);
151
152 return 0;
153 }
154
155 /* Parse a variable assignment line */
156 static int parse_line(const char* unit,
157 const char *filename,
158 unsigned line,
159 const char *sections,
160 ConfigItemLookup lookup,
161 const void *table,
162 bool relaxed,
163 bool allow_include,
164 char **section,
165 unsigned *section_line,
166 bool *section_ignored,
167 char *l,
168 void *userdata) {
169
170 char *e;
171
172 assert(filename);
173 assert(line > 0);
174 assert(lookup);
175 assert(l);
176
177 l = strstrip(l);
178
179 if (!*l)
180 return 0;
181
182 if (strchr(COMMENTS "\n", *l))
183 return 0;
184
185 if (startswith(l, ".include ")) {
186 _cleanup_free_ char *fn = NULL;
187
188 /* .includes are a bad idea, we only support them here
189 * for historical reasons. They create cyclic include
190 * problems and make it difficult to detect
191 * configuration file changes with an easy
192 * stat(). Better approaches, such as .d/ drop-in
193 * snippets exist.
194 *
195 * Support for them should be eventually removed. */
196
197 if (!allow_include) {
198 log_syntax(unit, LOG_ERR, filename, line, 0, ".include not allowed here. Ignoring.");
199 return 0;
200 }
201
202 fn = file_in_same_dir(filename, strstrip(l+9));
203 if (!fn)
204 return -ENOMEM;
205
206 return config_parse(unit, fn, NULL, sections, lookup, table, relaxed, false, false, userdata);
207 }
208
209 if (*l == '[') {
210 size_t k;
211 char *n;
212
213 k = strlen(l);
214 assert(k > 0);
215
216 if (l[k-1] != ']') {
217 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid section header '%s'", l);
218 return -EBADMSG;
219 }
220
221 n = strndup(l+1, k-2);
222 if (!n)
223 return -ENOMEM;
224
225 if (sections && !nulstr_contains(sections, n)) {
226
227 if (!relaxed && !startswith(n, "X-"))
228 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown section '%s'. Ignoring.", n);
229
230 free(n);
231 *section = mfree(*section);
232 *section_line = 0;
233 *section_ignored = true;
234 } else {
235 free(*section);
236 *section = n;
237 *section_line = line;
238 *section_ignored = false;
239 }
240
241 return 0;
242 }
243
244 if (sections && !*section) {
245
246 if (!relaxed && !*section_ignored)
247 log_syntax(unit, LOG_WARNING, filename, line, 0, "Assignment outside of section. Ignoring.");
248
249 return 0;
250 }
251
252 e = strchr(l, '=');
253 if (!e) {
254 log_syntax(unit, LOG_WARNING, filename, line, 0, "Missing '='.");
255 return -EINVAL;
256 }
257
258 *e = 0;
259 e++;
260
261 return next_assignment(unit,
262 filename,
263 line,
264 lookup,
265 table,
266 *section,
267 *section_line,
268 strstrip(l),
269 strstrip(e),
270 relaxed,
271 userdata);
272 }
273
274 /* Go through the file and parse each line */
275 int config_parse(const char *unit,
276 const char *filename,
277 FILE *f,
278 const char *sections,
279 ConfigItemLookup lookup,
280 const void *table,
281 bool relaxed,
282 bool allow_include,
283 bool warn,
284 void *userdata) {
285
286 _cleanup_free_ char *section = NULL, *continuation = NULL;
287 _cleanup_fclose_ FILE *ours = NULL;
288 unsigned line = 0, section_line = 0;
289 bool section_ignored = false;
290 int r;
291
292 assert(filename);
293 assert(lookup);
294
295 if (!f) {
296 f = ours = fopen(filename, "re");
297 if (!f) {
298 /* Only log on request, except for ENOENT,
299 * since we return 0 to the caller. */
300 if (warn || errno == ENOENT)
301 log_full(errno == ENOENT ? LOG_DEBUG : LOG_ERR,
302 "Failed to open configuration file '%s': %m", filename);
303 return errno == ENOENT ? 0 : -errno;
304 }
305 }
306
307 fd_warn_permissions(filename, fileno(f));
308
309 while (!feof(f)) {
310 char l[LINE_MAX], *p, *c = NULL, *e;
311 bool escaped = false;
312
313 if (!fgets(l, sizeof(l), f)) {
314 if (feof(f))
315 break;
316
317 log_error_errno(errno, "Failed to read configuration file '%s': %m", filename);
318 return -errno;
319 }
320
321 truncate_nl(l);
322
323 if (continuation) {
324 c = strappend(continuation, l);
325 if (!c) {
326 if (warn)
327 log_oom();
328 return -ENOMEM;
329 }
330
331 continuation = mfree(continuation);
332 p = c;
333 } else
334 p = l;
335
336 for (e = p; *e; e++) {
337 if (escaped)
338 escaped = false;
339 else if (*e == '\\')
340 escaped = true;
341 }
342
343 if (escaped) {
344 *(e-1) = ' ';
345
346 if (c)
347 continuation = c;
348 else {
349 continuation = strdup(l);
350 if (!continuation) {
351 if (warn)
352 log_oom();
353 return -ENOMEM;
354 }
355 }
356
357 continue;
358 }
359
360 r = parse_line(unit,
361 filename,
362 ++line,
363 sections,
364 lookup,
365 table,
366 relaxed,
367 allow_include,
368 &section,
369 &section_line,
370 &section_ignored,
371 p,
372 userdata);
373 free(c);
374
375 if (r < 0) {
376 if (warn)
377 log_warning_errno(r, "Failed to parse file '%s': %m",
378 filename);
379 return r;
380 }
381 }
382
383 return 0;
384 }
385
386 /* Parse each config file in the specified directories. */
387 int config_parse_many(const char *conf_file,
388 const char *conf_file_dirs,
389 const char *sections,
390 ConfigItemLookup lookup,
391 const void *table,
392 bool relaxed,
393 void *userdata) {
394 _cleanup_strv_free_ char **files = NULL;
395 char **fn;
396 int r;
397
398 r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
399 if (r < 0)
400 return r;
401
402 if (conf_file) {
403 r = config_parse(NULL, conf_file, NULL, sections, lookup, table, relaxed, false, true, userdata);
404 if (r < 0)
405 return r;
406 }
407
408 STRV_FOREACH(fn, files) {
409 r = config_parse(NULL, *fn, NULL, sections, lookup, table, relaxed, false, true, userdata);
410 if (r < 0)
411 return r;
412 }
413
414 return 0;
415 }
416
417 #define DEFINE_PARSER(type, vartype, conv_func) \
418 int config_parse_##type( \
419 const char *unit, \
420 const char *filename, \
421 unsigned line, \
422 const char *section, \
423 unsigned section_line, \
424 const char *lvalue, \
425 int ltype, \
426 const char *rvalue, \
427 void *data, \
428 void *userdata) { \
429 \
430 vartype *i = data; \
431 int r; \
432 \
433 assert(filename); \
434 assert(lvalue); \
435 assert(rvalue); \
436 assert(data); \
437 \
438 r = conv_func(rvalue, i); \
439 if (r < 0) \
440 log_syntax(unit, LOG_ERR, filename, line, r, \
441 "Failed to parse %s value, ignoring: %s", \
442 #type, rvalue); \
443 \
444 return 0; \
445 } \
446 struct __useless_struct_to_allow_trailing_semicolon__
447
448 DEFINE_PARSER(int, int, safe_atoi);
449 DEFINE_PARSER(long, long, safe_atoli);
450 DEFINE_PARSER(uint32, uint32_t, safe_atou32);
451 DEFINE_PARSER(uint64, uint64_t, safe_atou64);
452 DEFINE_PARSER(unsigned, unsigned, safe_atou);
453 DEFINE_PARSER(double, double, safe_atod);
454 DEFINE_PARSER(nsec, nsec_t, parse_nsec);
455 DEFINE_PARSER(sec, usec_t, parse_sec);
456 DEFINE_PARSER(mode, mode_t, parse_mode);
457
458 int config_parse_iec_size(const char* unit,
459 const char *filename,
460 unsigned line,
461 const char *section,
462 unsigned section_line,
463 const char *lvalue,
464 int ltype,
465 const char *rvalue,
466 void *data,
467 void *userdata) {
468
469 size_t *sz = data;
470 uint64_t v;
471 int r;
472
473 assert(filename);
474 assert(lvalue);
475 assert(rvalue);
476 assert(data);
477
478 r = parse_size(rvalue, 1024, &v);
479 if (r < 0 || (uint64_t) (size_t) v != v) {
480 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
481 return 0;
482 }
483
484 *sz = (size_t) v;
485 return 0;
486 }
487
488 int config_parse_si_size(const char* unit,
489 const char *filename,
490 unsigned line,
491 const char *section,
492 unsigned section_line,
493 const char *lvalue,
494 int ltype,
495 const char *rvalue,
496 void *data,
497 void *userdata) {
498
499 size_t *sz = data;
500 uint64_t v;
501 int r;
502
503 assert(filename);
504 assert(lvalue);
505 assert(rvalue);
506 assert(data);
507
508 r = parse_size(rvalue, 1000, &v);
509 if (r < 0 || (uint64_t) (size_t) v != v) {
510 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
511 return 0;
512 }
513
514 *sz = (size_t) v;
515 return 0;
516 }
517
518 int config_parse_iec_uint64(const char* unit,
519 const char *filename,
520 unsigned line,
521 const char *section,
522 unsigned section_line,
523 const char *lvalue,
524 int ltype,
525 const char *rvalue,
526 void *data,
527 void *userdata) {
528
529 uint64_t *bytes = data;
530 int r;
531
532 assert(filename);
533 assert(lvalue);
534 assert(rvalue);
535 assert(data);
536
537 r = parse_size(rvalue, 1024, bytes);
538 if (r < 0)
539 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
540
541 return 0;
542 }
543
544 int config_parse_bool(const char* unit,
545 const char *filename,
546 unsigned line,
547 const char *section,
548 unsigned section_line,
549 const char *lvalue,
550 int ltype,
551 const char *rvalue,
552 void *data,
553 void *userdata) {
554
555 int k;
556 bool *b = data;
557
558 assert(filename);
559 assert(lvalue);
560 assert(rvalue);
561 assert(data);
562
563 k = parse_boolean(rvalue);
564 if (k < 0) {
565 log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
566 return 0;
567 }
568
569 *b = !!k;
570 return 0;
571 }
572
573 int config_parse_tristate(
574 const char* unit,
575 const char *filename,
576 unsigned line,
577 const char *section,
578 unsigned section_line,
579 const char *lvalue,
580 int ltype,
581 const char *rvalue,
582 void *data,
583 void *userdata) {
584
585 int k, *t = data;
586
587 assert(filename);
588 assert(lvalue);
589 assert(rvalue);
590 assert(data);
591
592 /* A tristate is pretty much a boolean, except that it can
593 * also take the special value -1, indicating "uninitialized",
594 * much like NULL is for a pointer type. */
595
596 k = parse_boolean(rvalue);
597 if (k < 0) {
598 log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
599 return 0;
600 }
601
602 *t = !!k;
603 return 0;
604 }
605
606 int config_parse_string(
607 const char *unit,
608 const char *filename,
609 unsigned line,
610 const char *section,
611 unsigned section_line,
612 const char *lvalue,
613 int ltype,
614 const char *rvalue,
615 void *data,
616 void *userdata) {
617
618 char **s = data, *n;
619
620 assert(filename);
621 assert(lvalue);
622 assert(rvalue);
623 assert(data);
624
625 if (!utf8_is_valid(rvalue)) {
626 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
627 return 0;
628 }
629
630 if (isempty(rvalue))
631 n = NULL;
632 else {
633 n = strdup(rvalue);
634 if (!n)
635 return log_oom();
636 }
637
638 free(*s);
639 *s = n;
640
641 return 0;
642 }
643
644 int config_parse_path(
645 const char *unit,
646 const char *filename,
647 unsigned line,
648 const char *section,
649 unsigned section_line,
650 const char *lvalue,
651 int ltype,
652 const char *rvalue,
653 void *data,
654 void *userdata) {
655
656 char **s = data, *n;
657
658 assert(filename);
659 assert(lvalue);
660 assert(rvalue);
661 assert(data);
662
663 if (!utf8_is_valid(rvalue)) {
664 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
665 return 0;
666 }
667
668 if (!path_is_absolute(rvalue)) {
669 log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", rvalue);
670 return 0;
671 }
672
673 n = strdup(rvalue);
674 if (!n)
675 return log_oom();
676
677 path_kill_slashes(n);
678
679 free(*s);
680 *s = n;
681
682 return 0;
683 }
684
685 int config_parse_strv(const char *unit,
686 const char *filename,
687 unsigned line,
688 const char *section,
689 unsigned section_line,
690 const char *lvalue,
691 int ltype,
692 const char *rvalue,
693 void *data,
694 void *userdata) {
695
696 char ***sv = data;
697 const char *word, *state;
698 size_t l;
699 int r;
700
701 assert(filename);
702 assert(lvalue);
703 assert(rvalue);
704 assert(data);
705
706 if (isempty(rvalue)) {
707 char **empty;
708
709 /* Empty assignment resets the list. As a special rule
710 * we actually fill in a real empty array here rather
711 * than NULL, since some code wants to know if
712 * something was set at all... */
713 empty = strv_new(NULL, NULL);
714 if (!empty)
715 return log_oom();
716
717 strv_free(*sv);
718 *sv = empty;
719 return 0;
720 }
721
722 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
723 char *n;
724
725 n = strndup(word, l);
726 if (!n)
727 return log_oom();
728
729 if (!utf8_is_valid(n)) {
730 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
731 free(n);
732 continue;
733 }
734
735 r = strv_consume(sv, n);
736 if (r < 0)
737 return log_oom();
738 }
739 if (!isempty(state))
740 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
741
742 return 0;
743 }
744
745 int config_parse_log_facility(
746 const char *unit,
747 const char *filename,
748 unsigned line,
749 const char *section,
750 unsigned section_line,
751 const char *lvalue,
752 int ltype,
753 const char *rvalue,
754 void *data,
755 void *userdata) {
756
757
758 int *o = data, x;
759
760 assert(filename);
761 assert(lvalue);
762 assert(rvalue);
763 assert(data);
764
765 x = log_facility_unshifted_from_string(rvalue);
766 if (x < 0) {
767 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log facility, ignoring: %s", rvalue);
768 return 0;
769 }
770
771 *o = (x << 3) | LOG_PRI(*o);
772
773 return 0;
774 }
775
776 int config_parse_log_level(
777 const char *unit,
778 const char *filename,
779 unsigned line,
780 const char *section,
781 unsigned section_line,
782 const char *lvalue,
783 int ltype,
784 const char *rvalue,
785 void *data,
786 void *userdata) {
787
788
789 int *o = data, x;
790
791 assert(filename);
792 assert(lvalue);
793 assert(rvalue);
794 assert(data);
795
796 x = log_level_from_string(rvalue);
797 if (x < 0) {
798 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log level, ignoring: %s", rvalue);
799 return 0;
800 }
801
802 *o = (*o & LOG_FACMASK) | x;
803 return 0;
804 }
805
806 int config_parse_signal(
807 const char *unit,
808 const char *filename,
809 unsigned line,
810 const char *section,
811 unsigned section_line,
812 const char *lvalue,
813 int ltype,
814 const char *rvalue,
815 void *data,
816 void *userdata) {
817
818 int *sig = data, r;
819
820 assert(filename);
821 assert(lvalue);
822 assert(rvalue);
823 assert(sig);
824
825 r = signal_from_string_try_harder(rvalue);
826 if (r <= 0) {
827 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse signal name, ignoring: %s", rvalue);
828 return 0;
829 }
830
831 *sig = r;
832 return 0;
833 }
834
835 int config_parse_personality(
836 const char *unit,
837 const char *filename,
838 unsigned line,
839 const char *section,
840 unsigned section_line,
841 const char *lvalue,
842 int ltype,
843 const char *rvalue,
844 void *data,
845 void *userdata) {
846
847 unsigned long *personality = data, p;
848
849 assert(filename);
850 assert(lvalue);
851 assert(rvalue);
852 assert(personality);
853
854 p = personality_from_string(rvalue);
855 if (p == PERSONALITY_INVALID) {
856 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse personality, ignoring: %s", rvalue);
857 return 0;
858 }
859
860 *personality = p;
861 return 0;
862 }