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