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