]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/conf-parser.c
network: also read mtime of drop-in configs
[thirdparty/systemd.git] / src / shared / conf-parser.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <errno.h>
4 #include <limits.h>
5 #include <stdint.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <sys/types.h>
9
10 #include "alloc-util.h"
11 #include "conf-files.h"
12 #include "conf-parser.h"
13 #include "def.h"
14 #include "extract-word.h"
15 #include "fd-util.h"
16 #include "fileio.h"
17 #include "fs-util.h"
18 #include "log.h"
19 #include "macro.h"
20 #include "missing_network.h"
21 #include "nulstr-util.h"
22 #include "parse-util.h"
23 #include "path-util.h"
24 #include "process-util.h"
25 #include "rlimit-util.h"
26 #include "sd-id128.h"
27 #include "signal-util.h"
28 #include "socket-util.h"
29 #include "string-util.h"
30 #include "strv.h"
31 #include "syslog-util.h"
32 #include "time-util.h"
33 #include "utf8.h"
34
35 int config_item_table_lookup(
36 const void *table,
37 const char *section,
38 const char *lvalue,
39 ConfigParserCallback *func,
40 int *ltype,
41 void **data,
42 void *userdata) {
43
44 const ConfigTableItem *t;
45
46 assert(table);
47 assert(lvalue);
48 assert(func);
49 assert(ltype);
50 assert(data);
51
52 for (t = table; t->lvalue; t++) {
53
54 if (!streq(lvalue, t->lvalue))
55 continue;
56
57 if (!streq_ptr(section, t->section))
58 continue;
59
60 *func = t->parse;
61 *ltype = t->ltype;
62 *data = t->data;
63 return 1;
64 }
65
66 return 0;
67 }
68
69 int config_item_perf_lookup(
70 const 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 const char *key;
89
90 key = strjoina(section, ".", lvalue);
91 p = lookup(key, strlen(key));
92 } else
93 p = lookup(lvalue, strlen(lvalue));
94 if (!p)
95 return 0;
96
97 *func = p->parse;
98 *ltype = p->ltype;
99 *data = (uint8_t*) userdata + p->offset;
100 return 1;
101 }
102
103 /* Run the user supplied parser for an assignment */
104 static int next_assignment(
105 const char *unit,
106 const char *filename,
107 unsigned line,
108 ConfigItemLookup lookup,
109 const void *table,
110 const char *section,
111 unsigned section_line,
112 const char *lvalue,
113 const char *rvalue,
114 ConfigParseFlags flags,
115 void *userdata) {
116
117 ConfigParserCallback func = NULL;
118 int ltype = 0;
119 void *data = NULL;
120 int r;
121
122 assert(filename);
123 assert(line > 0);
124 assert(lookup);
125 assert(lvalue);
126 assert(rvalue);
127
128 r = lookup(table, section, lvalue, &func, &ltype, &data, userdata);
129 if (r < 0)
130 return r;
131 if (r > 0) {
132 if (func)
133 return func(unit, filename, line, section, section_line,
134 lvalue, ltype, rvalue, data, userdata);
135
136 return 0;
137 }
138
139 /* Warn about unknown non-extension fields. */
140 if (!(flags & CONFIG_PARSE_RELAXED) && !startswith(lvalue, "X-"))
141 log_syntax(unit, LOG_WARNING, filename, line, 0,
142 "Unknown key name '%s' in section '%s', ignoring.", lvalue, section);
143
144 return 0;
145 }
146
147 /* Parse a single logical line */
148 static int parse_line(
149 const char* unit,
150 const char *filename,
151 unsigned line,
152 const char *sections,
153 ConfigItemLookup lookup,
154 const void *table,
155 ConfigParseFlags flags,
156 char **section,
157 unsigned *section_line,
158 bool *section_ignored,
159 char *l,
160 void *userdata) {
161
162 char *e, *include;
163
164 assert(filename);
165 assert(line > 0);
166 assert(lookup);
167 assert(l);
168
169 l = strstrip(l);
170 if (!*l)
171 return 0;
172
173 if (*l == '\n')
174 return 0;
175
176 include = first_word(l, ".include");
177 if (include) {
178 _cleanup_free_ char *fn = NULL;
179
180 /* .includes are a bad idea, we only support them here
181 * for historical reasons. They create cyclic include
182 * problems and make it difficult to detect
183 * configuration file changes with an easy
184 * stat(). Better approaches, such as .d/ drop-in
185 * snippets exist.
186 *
187 * Support for them should be eventually removed. */
188
189 if (!(flags & CONFIG_PARSE_ALLOW_INCLUDE)) {
190 log_syntax(unit, LOG_ERR, filename, line, 0, ".include not allowed here. Ignoring.");
191 return 0;
192 }
193
194 log_syntax(unit, LOG_WARNING, filename, line, 0,
195 ".include directives are deprecated, and support for them will be removed in a future version of systemd. "
196 "Please use drop-in files instead.");
197
198 fn = file_in_same_dir(filename, strstrip(include));
199 if (!fn)
200 return -ENOMEM;
201
202 return config_parse(unit, fn, NULL, sections, lookup, table, flags, userdata);
203 }
204
205 if (!utf8_is_valid(l))
206 return log_syntax_invalid_utf8(unit, LOG_WARNING, filename, line, l);
207
208 if (*l == '[') {
209 size_t k;
210 char *n;
211
212 k = strlen(l);
213 assert(k > 0);
214
215 if (l[k-1] != ']') {
216 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid section header '%s'", l);
217 return -EBADMSG;
218 }
219
220 n = strndup(l+1, k-2);
221 if (!n)
222 return -ENOMEM;
223
224 if (sections && !nulstr_contains(sections, n)) {
225 bool ignore = flags & CONFIG_PARSE_RELAXED;
226 const char *t;
227
228 ignore = ignore || startswith(n, "X-");
229
230 if (!ignore)
231 NULSTR_FOREACH(t, sections)
232 if (streq_ptr(n, startswith(t, "-"))) {
233 ignore = true;
234 break;
235 }
236
237 if (!ignore)
238 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown section '%s'. Ignoring.", n);
239
240 free(n);
241 *section = mfree(*section);
242 *section_line = 0;
243 *section_ignored = true;
244 } else {
245 free_and_replace(*section, n);
246 *section_line = line;
247 *section_ignored = false;
248 }
249
250 return 0;
251 }
252
253 if (sections && !*section) {
254 if (!(flags & CONFIG_PARSE_RELAXED) && !*section_ignored)
255 log_syntax(unit, LOG_WARNING, filename, line, 0, "Assignment outside of section. Ignoring.");
256
257 return 0;
258 }
259
260 e = strchr(l, '=');
261 if (!e)
262 return log_syntax(unit, LOG_WARNING, filename, line, 0,
263 "Missing '=', ignoring line.");
264 if (e == l)
265 return log_syntax(unit, LOG_WARNING, filename, line, 0,
266 "Missing key name before '=', ignoring line.");
267
268 *e = 0;
269 e++;
270
271 return next_assignment(unit,
272 filename,
273 line,
274 lookup,
275 table,
276 *section,
277 *section_line,
278 strstrip(l),
279 strstrip(e),
280 flags,
281 userdata);
282 }
283
284 /* Go through the file and parse each line */
285 int config_parse(const char *unit,
286 const char *filename,
287 FILE *f,
288 const char *sections,
289 ConfigItemLookup lookup,
290 const void *table,
291 ConfigParseFlags flags,
292 void *userdata) {
293
294 _cleanup_free_ char *section = NULL, *continuation = NULL;
295 _cleanup_fclose_ FILE *ours = NULL;
296 unsigned line = 0, section_line = 0;
297 bool section_ignored = false, bom_seen = false;
298 int r, fd;
299
300 assert(filename);
301 assert(lookup);
302
303 if (!f) {
304 f = ours = fopen(filename, "re");
305 if (!f) {
306 /* Only log on request, except for ENOENT,
307 * since we return 0 to the caller. */
308 if ((flags & CONFIG_PARSE_WARN) || errno == ENOENT)
309 log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno,
310 "Failed to open configuration file '%s': %m", filename);
311 return errno == ENOENT ? 0 : -errno;
312 }
313 }
314
315 fd = fileno(f);
316 if (fd >= 0) /* stream might not have an fd, let's be careful hence */
317 fd_warn_permissions(filename, fd);
318
319 for (;;) {
320 _cleanup_free_ char *buf = NULL;
321 bool escaped = false;
322 char *l, *p, *e;
323
324 r = read_line(f, LONG_LINE_MAX, &buf);
325 if (r == 0)
326 break;
327 if (r == -ENOBUFS) {
328 if (flags & CONFIG_PARSE_WARN)
329 log_error_errno(r, "%s:%u: Line too long", filename, line);
330
331 return r;
332 }
333 if (r < 0) {
334 if (CONFIG_PARSE_WARN)
335 log_error_errno(r, "%s:%u: Error while reading configuration file: %m", filename, line);
336
337 return r;
338 }
339
340 line++;
341
342 l = skip_leading_chars(buf, WHITESPACE);
343 if (*l != '\0' && strchr(COMMENTS, *l))
344 continue;
345
346 l = buf;
347 if (!bom_seen) {
348 char *q;
349
350 q = startswith(buf, UTF8_BYTE_ORDER_MARK);
351 if (q) {
352 l = q;
353 bom_seen = true;
354 }
355 }
356
357 if (continuation) {
358 if (strlen(continuation) + strlen(l) > LONG_LINE_MAX) {
359 if (flags & CONFIG_PARSE_WARN)
360 log_error("%s:%u: Continuation line too long", filename, line);
361 return -ENOBUFS;
362 }
363
364 if (!strextend(&continuation, l, NULL)) {
365 if (flags & CONFIG_PARSE_WARN)
366 log_oom();
367 return -ENOMEM;
368 }
369
370 p = continuation;
371 } else
372 p = l;
373
374 for (e = p; *e; e++) {
375 if (escaped)
376 escaped = false;
377 else if (*e == '\\')
378 escaped = true;
379 }
380
381 if (escaped) {
382 *(e-1) = ' ';
383
384 if (!continuation) {
385 continuation = strdup(l);
386 if (!continuation) {
387 if (flags & CONFIG_PARSE_WARN)
388 log_oom();
389 return -ENOMEM;
390 }
391 }
392
393 continue;
394 }
395
396 r = parse_line(unit,
397 filename,
398 line,
399 sections,
400 lookup,
401 table,
402 flags,
403 &section,
404 &section_line,
405 &section_ignored,
406 p,
407 userdata);
408 if (r < 0) {
409 if (flags & CONFIG_PARSE_WARN)
410 log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
411 return r;
412 }
413
414 continuation = mfree(continuation);
415 }
416
417 if (continuation) {
418 r = parse_line(unit,
419 filename,
420 ++line,
421 sections,
422 lookup,
423 table,
424 flags,
425 &section,
426 &section_line,
427 &section_ignored,
428 continuation,
429 userdata);
430 if (r < 0) {
431 if (flags & CONFIG_PARSE_WARN)
432 log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
433 return r;
434 }
435 }
436
437 return 0;
438 }
439
440 static int config_parse_many_files(
441 const char *conf_file,
442 char **files,
443 const char *sections,
444 ConfigItemLookup lookup,
445 const void *table,
446 ConfigParseFlags flags,
447 void *userdata) {
448
449 char **fn;
450 int r;
451
452 if (conf_file) {
453 r = config_parse(NULL, conf_file, NULL, sections, lookup, table, flags, userdata);
454 if (r < 0)
455 return r;
456 }
457
458 STRV_FOREACH(fn, files) {
459 r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata);
460 if (r < 0)
461 return r;
462 }
463
464 return 0;
465 }
466
467 /* Parse each config file in the directories specified as nulstr. */
468 int config_parse_many_nulstr(
469 const char *conf_file,
470 const char *conf_file_dirs,
471 const char *sections,
472 ConfigItemLookup lookup,
473 const void *table,
474 ConfigParseFlags flags,
475 void *userdata) {
476
477 _cleanup_strv_free_ char **files = NULL;
478 int r;
479
480 r = conf_files_list_nulstr(&files, ".conf", NULL, 0, conf_file_dirs);
481 if (r < 0)
482 return r;
483
484 return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata);
485 }
486
487 /* Parse each config file in the directories specified as strv. */
488 int config_parse_many(
489 const char *conf_file,
490 const char* const* conf_file_dirs,
491 const char *dropin_dirname,
492 const char *sections,
493 ConfigItemLookup lookup,
494 const void *table,
495 ConfigParseFlags flags,
496 void *userdata,
497 char ***ret_dropins) {
498
499 _cleanup_strv_free_ char **dropin_dirs = NULL;
500 _cleanup_strv_free_ char **files = NULL;
501 const char *suffix;
502 int r;
503
504 suffix = strjoina("/", dropin_dirname);
505 r = strv_extend_strv_concat(&dropin_dirs, (char**) conf_file_dirs, suffix);
506 if (r < 0)
507 return r;
508
509 r = conf_files_list_strv(&files, ".conf", NULL, 0, (const char* const*) dropin_dirs);
510 if (r < 0)
511 return r;
512
513 r = config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata);
514 if (r < 0)
515 return r;
516
517 if (ret_dropins)
518 *ret_dropins = TAKE_PTR(files);
519
520 return 0;
521 }
522
523 #define DEFINE_PARSER(type, vartype, conv_func) \
524 DEFINE_CONFIG_PARSE_PTR(config_parse_##type, conv_func, vartype, "Failed to parse " #type " value")
525
526 DEFINE_PARSER(int, int, safe_atoi);
527 DEFINE_PARSER(long, long, safe_atoli);
528 DEFINE_PARSER(uint8, uint8_t, safe_atou8);
529 DEFINE_PARSER(uint16, uint16_t, safe_atou16);
530 DEFINE_PARSER(uint32, uint32_t, safe_atou32);
531 DEFINE_PARSER(int32, int32_t, safe_atoi32);
532 DEFINE_PARSER(uint64, uint64_t, safe_atou64);
533 DEFINE_PARSER(unsigned, unsigned, safe_atou);
534 DEFINE_PARSER(double, double, safe_atod);
535 DEFINE_PARSER(nsec, nsec_t, parse_nsec);
536 DEFINE_PARSER(sec, usec_t, parse_sec);
537 DEFINE_PARSER(sec_def_infinity, usec_t, parse_sec_def_infinity);
538 DEFINE_PARSER(mode, mode_t, parse_mode);
539
540 int config_parse_iec_size(const char* unit,
541 const char *filename,
542 unsigned line,
543 const char *section,
544 unsigned section_line,
545 const char *lvalue,
546 int ltype,
547 const char *rvalue,
548 void *data,
549 void *userdata) {
550
551 size_t *sz = data;
552 uint64_t v;
553 int r;
554
555 assert(filename);
556 assert(lvalue);
557 assert(rvalue);
558 assert(data);
559
560 r = parse_size(rvalue, 1024, &v);
561 if (r >= 0 && (uint64_t) (size_t) v != v)
562 r = -ERANGE;
563 if (r < 0) {
564 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value '%s', ignoring: %m", rvalue);
565 return 0;
566 }
567
568 *sz = (size_t) v;
569 return 0;
570 }
571
572 int config_parse_si_uint64(
573 const char* unit,
574 const char *filename,
575 unsigned line,
576 const char *section,
577 unsigned section_line,
578 const char *lvalue,
579 int ltype,
580 const char *rvalue,
581 void *data,
582 void *userdata) {
583
584 uint64_t *sz = data;
585 int r;
586
587 assert(filename);
588 assert(lvalue);
589 assert(rvalue);
590 assert(data);
591
592 r = parse_size(rvalue, 1000, sz);
593 if (r < 0) {
594 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value '%s', ignoring: %m", rvalue);
595 return 0;
596 }
597
598 return 0;
599 }
600
601 int config_parse_iec_uint64(
602 const char* unit,
603 const char *filename,
604 unsigned line,
605 const char *section,
606 unsigned section_line,
607 const char *lvalue,
608 int ltype,
609 const char *rvalue,
610 void *data,
611 void *userdata) {
612
613 uint64_t *bytes = data;
614 int r;
615
616 assert(filename);
617 assert(lvalue);
618 assert(rvalue);
619 assert(data);
620
621 r = parse_size(rvalue, 1024, bytes);
622 if (r < 0)
623 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
624
625 return 0;
626 }
627
628 int config_parse_bool(const char* unit,
629 const char *filename,
630 unsigned line,
631 const char *section,
632 unsigned section_line,
633 const char *lvalue,
634 int ltype,
635 const char *rvalue,
636 void *data,
637 void *userdata) {
638
639 int k;
640 bool *b = data;
641 bool fatal = ltype;
642
643 assert(filename);
644 assert(lvalue);
645 assert(rvalue);
646 assert(data);
647
648 k = parse_boolean(rvalue);
649 if (k < 0) {
650 log_syntax(unit, LOG_ERR, filename, line, k,
651 "Failed to parse boolean value%s: %s",
652 fatal ? "" : ", ignoring", rvalue);
653 return fatal ? -ENOEXEC : 0;
654 }
655
656 *b = k;
657 return 0;
658 }
659
660 int config_parse_id128(
661 const char *unit,
662 const char *filename,
663 unsigned line,
664 const char *section,
665 unsigned section_line,
666 const char *lvalue,
667 int ltype,
668 const char *rvalue,
669 void *data,
670 void *userdata) {
671
672 sd_id128_t t, *result = data;
673 int r;
674
675 assert(filename);
676 assert(lvalue);
677 assert(rvalue);
678
679 r = sd_id128_from_string(rvalue, &t);
680 if (r < 0)
681 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse 128bit ID/UUID, ignoring: %s", rvalue);
682 else if (sd_id128_is_null(t))
683 log_syntax(unit, LOG_ERR, filename, line, 0, "128bit ID/UUID is all 0, ignoring: %s", rvalue);
684
685 *result = t;
686 return 0;
687 }
688
689 int config_parse_tristate(
690 const char* unit,
691 const char *filename,
692 unsigned line,
693 const char *section,
694 unsigned section_line,
695 const char *lvalue,
696 int ltype,
697 const char *rvalue,
698 void *data,
699 void *userdata) {
700
701 int k, *t = data;
702
703 assert(filename);
704 assert(lvalue);
705 assert(rvalue);
706 assert(data);
707
708 /* A tristate is pretty much a boolean, except that it can
709 * also take the special value -1, indicating "uninitialized",
710 * much like NULL is for a pointer type. */
711
712 k = parse_boolean(rvalue);
713 if (k < 0) {
714 log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
715 return 0;
716 }
717
718 *t = !!k;
719 return 0;
720 }
721
722 int config_parse_string(
723 const char *unit,
724 const char *filename,
725 unsigned line,
726 const char *section,
727 unsigned section_line,
728 const char *lvalue,
729 int ltype,
730 const char *rvalue,
731 void *data,
732 void *userdata) {
733
734 char **s = data;
735
736 assert(filename);
737 assert(lvalue);
738 assert(rvalue);
739 assert(data);
740
741 if (free_and_strdup(s, empty_to_null(rvalue)) < 0)
742 return log_oom();
743
744 return 0;
745 }
746
747 int config_parse_path(
748 const char *unit,
749 const char *filename,
750 unsigned line,
751 const char *section,
752 unsigned section_line,
753 const char *lvalue,
754 int ltype,
755 const char *rvalue,
756 void *data,
757 void *userdata) {
758
759 _cleanup_free_ char *n = NULL;
760 bool fatal = ltype;
761 char **s = data;
762 int r;
763
764 assert(filename);
765 assert(lvalue);
766 assert(rvalue);
767 assert(data);
768
769 if (isempty(rvalue))
770 goto finalize;
771
772 n = strdup(rvalue);
773 if (!n)
774 return log_oom();
775
776 r = path_simplify_and_warn(n, PATH_CHECK_ABSOLUTE | (fatal ? PATH_CHECK_FATAL : 0), unit, filename, line, lvalue);
777 if (r < 0)
778 return fatal ? -ENOEXEC : 0;
779
780 finalize:
781 return free_and_replace(*s, n);
782 }
783
784 int config_parse_strv(
785 const char *unit,
786 const char *filename,
787 unsigned line,
788 const char *section,
789 unsigned section_line,
790 const char *lvalue,
791 int ltype,
792 const char *rvalue,
793 void *data,
794 void *userdata) {
795
796 char ***sv = data;
797 int r;
798
799 assert(filename);
800 assert(lvalue);
801 assert(rvalue);
802 assert(data);
803
804 if (isempty(rvalue)) {
805 *sv = strv_free(*sv);
806 return 0;
807 }
808
809 for (;;) {
810 char *word = NULL;
811
812 r = extract_first_word(&rvalue, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
813 if (r == 0)
814 break;
815 if (r == -ENOMEM)
816 return log_oom();
817 if (r < 0) {
818 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
819 break;
820 }
821
822 r = strv_consume(sv, word);
823 if (r < 0)
824 return log_oom();
825 }
826
827 return 0;
828 }
829
830 int config_parse_warn_compat(
831 const char *unit,
832 const char *filename,
833 unsigned line,
834 const char *section,
835 unsigned section_line,
836 const char *lvalue,
837 int ltype,
838 const char *rvalue,
839 void *data,
840 void *userdata) {
841
842 Disabled reason = ltype;
843
844 switch(reason) {
845
846 case DISABLED_CONFIGURATION:
847 log_syntax(unit, LOG_DEBUG, filename, line, 0,
848 "Support for option %s= has been disabled at compile time and it is ignored", lvalue);
849 break;
850
851 case DISABLED_LEGACY:
852 log_syntax(unit, LOG_INFO, filename, line, 0,
853 "Support for option %s= has been removed and it is ignored", lvalue);
854 break;
855
856 case DISABLED_EXPERIMENTAL:
857 log_syntax(unit, LOG_INFO, filename, line, 0,
858 "Support for option %s= has not yet been enabled and it is ignored", lvalue);
859 break;
860 }
861
862 return 0;
863 }
864
865 int config_parse_log_facility(
866 const char *unit,
867 const char *filename,
868 unsigned line,
869 const char *section,
870 unsigned section_line,
871 const char *lvalue,
872 int ltype,
873 const char *rvalue,
874 void *data,
875 void *userdata) {
876
877 int *o = data, x;
878
879 assert(filename);
880 assert(lvalue);
881 assert(rvalue);
882 assert(data);
883
884 x = log_facility_unshifted_from_string(rvalue);
885 if (x < 0) {
886 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log facility, ignoring: %s", rvalue);
887 return 0;
888 }
889
890 *o = (x << 3) | LOG_PRI(*o);
891
892 return 0;
893 }
894
895 int config_parse_log_level(
896 const char *unit,
897 const char *filename,
898 unsigned line,
899 const char *section,
900 unsigned section_line,
901 const char *lvalue,
902 int ltype,
903 const char *rvalue,
904 void *data,
905 void *userdata) {
906
907 int *o = data, x;
908
909 assert(filename);
910 assert(lvalue);
911 assert(rvalue);
912 assert(data);
913
914 x = log_level_from_string(rvalue);
915 if (x < 0) {
916 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log level, ignoring: %s", rvalue);
917 return 0;
918 }
919
920 if (*o < 0) /* if it wasn't initialized so far, assume zero facility */
921 *o = x;
922 else
923 *o = (*o & LOG_FACMASK) | x;
924
925 return 0;
926 }
927
928 int config_parse_signal(
929 const char *unit,
930 const char *filename,
931 unsigned line,
932 const char *section,
933 unsigned section_line,
934 const char *lvalue,
935 int ltype,
936 const char *rvalue,
937 void *data,
938 void *userdata) {
939
940 int *sig = data, r;
941
942 assert(filename);
943 assert(lvalue);
944 assert(rvalue);
945 assert(sig);
946
947 r = signal_from_string(rvalue);
948 if (r <= 0) {
949 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse signal name, ignoring: %s", rvalue);
950 return 0;
951 }
952
953 *sig = r;
954 return 0;
955 }
956
957 int config_parse_personality(
958 const char *unit,
959 const char *filename,
960 unsigned line,
961 const char *section,
962 unsigned section_line,
963 const char *lvalue,
964 int ltype,
965 const char *rvalue,
966 void *data,
967 void *userdata) {
968
969 unsigned long *personality = data, p;
970
971 assert(filename);
972 assert(lvalue);
973 assert(rvalue);
974 assert(personality);
975
976 if (isempty(rvalue))
977 p = PERSONALITY_INVALID;
978 else {
979 p = personality_from_string(rvalue);
980 if (p == PERSONALITY_INVALID) {
981 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse personality, ignoring: %s", rvalue);
982 return 0;
983 }
984 }
985
986 *personality = p;
987 return 0;
988 }
989
990 int config_parse_ifname(
991 const char *unit,
992 const char *filename,
993 unsigned line,
994 const char *section,
995 unsigned section_line,
996 const char *lvalue,
997 int ltype,
998 const char *rvalue,
999 void *data,
1000 void *userdata) {
1001
1002 char **s = data;
1003 int r;
1004
1005 assert(filename);
1006 assert(lvalue);
1007 assert(rvalue);
1008 assert(data);
1009
1010 if (isempty(rvalue)) {
1011 *s = mfree(*s);
1012 return 0;
1013 }
1014
1015 if (!ifname_valid(rvalue)) {
1016 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue);
1017 return 0;
1018 }
1019
1020 r = free_and_strdup(s, rvalue);
1021 if (r < 0)
1022 return log_oom();
1023
1024 return 0;
1025 }
1026
1027 int config_parse_ifnames(
1028 const char *unit,
1029 const char *filename,
1030 unsigned line,
1031 const char *section,
1032 unsigned section_line,
1033 const char *lvalue,
1034 int ltype,
1035 const char *rvalue,
1036 void *data,
1037 void *userdata) {
1038
1039 _cleanup_strv_free_ char **names = NULL;
1040 char ***s = data;
1041 const char *p;
1042 int r;
1043
1044 assert(filename);
1045 assert(lvalue);
1046 assert(rvalue);
1047 assert(data);
1048
1049 if (isempty(rvalue)) {
1050 *s = strv_free(*s);
1051 return 0;
1052 }
1053
1054 p = rvalue;
1055 for (;;) {
1056 _cleanup_free_ char *word = NULL;
1057
1058 r = extract_first_word(&p, &word, NULL, 0);
1059 if (r < 0) {
1060 log_syntax(unit, LOG_ERR, filename, line, r,
1061 "Failed to extract interface name, ignoring assignment: %s",
1062 rvalue);
1063 return 0;
1064 }
1065 if (r == 0)
1066 break;
1067
1068 if (!ifname_valid_full(word, ltype)) {
1069 log_syntax(unit, LOG_ERR, filename, line, 0,
1070 "Interface name is not valid or too long, ignoring assignment: %s",
1071 word);
1072 continue;
1073 }
1074
1075 r = strv_consume(&names, TAKE_PTR(word));
1076 if (r < 0)
1077 return log_oom();
1078 }
1079
1080 r = strv_extend_strv(s, names, true);
1081 if (r < 0)
1082 return log_oom();
1083
1084 return 0;
1085 }
1086
1087 int config_parse_ip_port(
1088 const char *unit,
1089 const char *filename,
1090 unsigned line,
1091 const char *section,
1092 unsigned section_line,
1093 const char *lvalue,
1094 int ltype,
1095 const char *rvalue,
1096 void *data,
1097 void *userdata) {
1098
1099 uint16_t *s = data;
1100 uint16_t port;
1101 int r;
1102
1103 assert(filename);
1104 assert(lvalue);
1105 assert(rvalue);
1106 assert(data);
1107
1108 if (isempty(rvalue)) {
1109 *s = 0;
1110 return 0;
1111 }
1112
1113 r = parse_ip_port(rvalue, &port);
1114 if (r < 0) {
1115 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse port '%s'.", rvalue);
1116 return 0;
1117 }
1118
1119 *s = port;
1120
1121 return 0;
1122 }
1123
1124 int config_parse_mtu(
1125 const char *unit,
1126 const char *filename,
1127 unsigned line,
1128 const char *section,
1129 unsigned section_line,
1130 const char *lvalue,
1131 int ltype,
1132 const char *rvalue,
1133 void *data,
1134 void *userdata) {
1135
1136 uint32_t *mtu = data;
1137 int r;
1138
1139 assert(rvalue);
1140 assert(mtu);
1141
1142 r = parse_mtu(ltype, rvalue, mtu);
1143 if (r == -ERANGE) {
1144 log_syntax(unit, LOG_ERR, filename, line, r,
1145 "Maximum transfer unit (MTU) value out of range. Permitted range is %" PRIu32 "…%" PRIu32 ", ignoring: %s",
1146 (uint32_t) (ltype == AF_INET6 ? IPV6_MIN_MTU : IPV4_MIN_MTU), (uint32_t) UINT32_MAX,
1147 rvalue);
1148 return 0;
1149 }
1150 if (r < 0) {
1151 log_syntax(unit, LOG_ERR, filename, line, r,
1152 "Failed to parse MTU value '%s', ignoring: %m", rvalue);
1153 return 0;
1154 }
1155
1156 return 0;
1157 }
1158
1159 int config_parse_rlimit(
1160 const char *unit,
1161 const char *filename,
1162 unsigned line,
1163 const char *section,
1164 unsigned section_line,
1165 const char *lvalue,
1166 int ltype,
1167 const char *rvalue,
1168 void *data,
1169 void *userdata) {
1170
1171 struct rlimit **rl = data, d = {};
1172 int r;
1173
1174 assert(rvalue);
1175 assert(rl);
1176
1177 r = rlimit_parse(ltype, rvalue, &d);
1178 if (r == -EILSEQ) {
1179 log_syntax(unit, LOG_WARNING, filename, line, r, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue);
1180 return 0;
1181 }
1182 if (r < 0) {
1183 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
1184 return 0;
1185 }
1186
1187 if (rl[ltype])
1188 *rl[ltype] = d;
1189 else {
1190 rl[ltype] = newdup(struct rlimit, &d, 1);
1191 if (!rl[ltype])
1192 return log_oom();
1193 }
1194
1195 return 0;
1196 }
1197
1198 int config_parse_permille(const char* unit,
1199 const char *filename,
1200 unsigned line,
1201 const char *section,
1202 unsigned section_line,
1203 const char *lvalue,
1204 int ltype,
1205 const char *rvalue,
1206 void *data,
1207 void *userdata) {
1208
1209 unsigned *permille = data;
1210 int r;
1211
1212 assert(filename);
1213 assert(lvalue);
1214 assert(rvalue);
1215 assert(permille);
1216
1217 r = parse_permille(rvalue);
1218 if (r < 0) {
1219 log_syntax(unit, LOG_ERR, filename, line, r,
1220 "Failed to parse permille value, ignoring: %s", rvalue);
1221 return 0;
1222 }
1223
1224 *permille = (unsigned) r;
1225
1226 return 0;
1227 }
1228
1229 int config_parse_vlanprotocol(const char* unit,
1230 const char *filename,
1231 unsigned line,
1232 const char *section,
1233 unsigned section_line,
1234 const char *lvalue,
1235 int ltype,
1236 const char *rvalue,
1237 void *data,
1238 void *userdata) {
1239 int *vlan_protocol = data;
1240 assert(filename);
1241 assert(lvalue);
1242
1243 if (isempty(rvalue)) {
1244 *vlan_protocol = -1;
1245 return 0;
1246 }
1247
1248 if (STR_IN_SET(rvalue, "802.1ad", "802.1AD"))
1249 *vlan_protocol = ETH_P_8021AD;
1250 else if (STR_IN_SET(rvalue, "802.1q", "802.1Q"))
1251 *vlan_protocol = ETH_P_8021Q;
1252 else {
1253 log_syntax(unit, LOG_ERR, filename, line, 0,
1254 "Failed to parse VLAN protocol value, ignoring: %s", rvalue);
1255 return 0;
1256 }
1257
1258 return 0;
1259 }