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