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