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