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