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