]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/conf-parser.c
Merge pull request #9144 from yuwata/sysusers-spec
[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 (*l == '[') {
215 size_t k;
216 char *n;
217
218 k = strlen(l);
219 assert(k > 0);
220
221 if (l[k-1] != ']') {
222 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid section header '%s'", l);
223 return -EBADMSG;
224 }
225
226 n = strndup(l+1, k-2);
227 if (!n)
228 return -ENOMEM;
229
230 if (sections && !nulstr_contains(sections, n)) {
231
232 if (!(flags & CONFIG_PARSE_RELAXED) && !startswith(n, "X-"))
233 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown section '%s'. Ignoring.", n);
234
235 free(n);
236 *section = mfree(*section);
237 *section_line = 0;
238 *section_ignored = true;
239 } else {
240 free(*section);
241 *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 == ENOENT ? LOG_DEBUG : LOG_ERR,
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
402 continuation = mfree(continuation);
403 }
404
405 if (continuation) {
406 r = parse_line(unit,
407 filename,
408 ++line,
409 sections,
410 lookup,
411 table,
412 flags,
413 &section,
414 &section_line,
415 &section_ignored,
416 continuation,
417 userdata);
418 if (r < 0) {
419 if (flags & CONFIG_PARSE_WARN)
420 log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
421 return r;
422
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 (!utf8_is_valid(rvalue)) {
692 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
693 return 0;
694 }
695
696 if (free_and_strdup(s, empty_to_null(rvalue)) < 0)
697 return log_oom();
698
699 return 0;
700 }
701
702 int config_parse_path(
703 const char *unit,
704 const char *filename,
705 unsigned line,
706 const char *section,
707 unsigned section_line,
708 const char *lvalue,
709 int ltype,
710 const char *rvalue,
711 void *data,
712 void *userdata) {
713
714 char **s = data, *n;
715 bool fatal = ltype;
716
717 assert(filename);
718 assert(lvalue);
719 assert(rvalue);
720 assert(data);
721
722 if (isempty(rvalue)) {
723 n = NULL;
724 goto finalize;
725 }
726
727 if (!utf8_is_valid(rvalue)) {
728 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
729 return fatal ? -ENOEXEC : 0;
730 }
731
732 if (!path_is_absolute(rvalue)) {
733 log_syntax(unit, LOG_ERR, filename, line, 0,
734 "Not an absolute path%s: %s",
735 fatal ? "" : ", ignoring", rvalue);
736 return fatal ? -ENOEXEC : 0;
737 }
738
739 n = strdup(rvalue);
740 if (!n)
741 return log_oom();
742
743 path_kill_slashes(n);
744
745 finalize:
746 free(*s);
747 *s = n;
748
749 return 0;
750 }
751
752 int config_parse_strv(
753 const char *unit,
754 const char *filename,
755 unsigned line,
756 const char *section,
757 unsigned section_line,
758 const char *lvalue,
759 int ltype,
760 const char *rvalue,
761 void *data,
762 void *userdata) {
763
764 char ***sv = data;
765 int r;
766
767 assert(filename);
768 assert(lvalue);
769 assert(rvalue);
770 assert(data);
771
772 if (isempty(rvalue)) {
773 *sv = strv_free(*sv);
774 return 0;
775 }
776
777 for (;;) {
778 char *word = NULL;
779
780 r = extract_first_word(&rvalue, &word, NULL, EXTRACT_QUOTES|EXTRACT_RETAIN_ESCAPE);
781 if (r == 0)
782 break;
783 if (r == -ENOMEM)
784 return log_oom();
785 if (r < 0) {
786 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
787 break;
788 }
789
790 if (!utf8_is_valid(word)) {
791 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, word);
792 free(word);
793 continue;
794 }
795
796 r = strv_consume(sv, word);
797 if (r < 0)
798 return log_oom();
799 }
800
801 return 0;
802 }
803
804 int config_parse_warn_compat(
805 const char *unit,
806 const char *filename,
807 unsigned line,
808 const char *section,
809 unsigned section_line,
810 const char *lvalue,
811 int ltype,
812 const char *rvalue,
813 void *data,
814 void *userdata) {
815
816 Disabled reason = ltype;
817
818 switch(reason) {
819
820 case DISABLED_CONFIGURATION:
821 log_syntax(unit, LOG_DEBUG, filename, line, 0,
822 "Support for option %s= has been disabled at compile time and it is ignored", lvalue);
823 break;
824
825 case DISABLED_LEGACY:
826 log_syntax(unit, LOG_INFO, filename, line, 0,
827 "Support for option %s= has been removed and it is ignored", lvalue);
828 break;
829
830 case DISABLED_EXPERIMENTAL:
831 log_syntax(unit, LOG_INFO, filename, line, 0,
832 "Support for option %s= has not yet been enabled and it is ignored", lvalue);
833 break;
834 }
835
836 return 0;
837 }
838
839 int config_parse_log_facility(
840 const char *unit,
841 const char *filename,
842 unsigned line,
843 const char *section,
844 unsigned section_line,
845 const char *lvalue,
846 int ltype,
847 const char *rvalue,
848 void *data,
849 void *userdata) {
850
851 int *o = data, x;
852
853 assert(filename);
854 assert(lvalue);
855 assert(rvalue);
856 assert(data);
857
858 x = log_facility_unshifted_from_string(rvalue);
859 if (x < 0) {
860 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log facility, ignoring: %s", rvalue);
861 return 0;
862 }
863
864 *o = (x << 3) | LOG_PRI(*o);
865
866 return 0;
867 }
868
869 int config_parse_log_level(
870 const char *unit,
871 const char *filename,
872 unsigned line,
873 const char *section,
874 unsigned section_line,
875 const char *lvalue,
876 int ltype,
877 const char *rvalue,
878 void *data,
879 void *userdata) {
880
881 int *o = data, x;
882
883 assert(filename);
884 assert(lvalue);
885 assert(rvalue);
886 assert(data);
887
888 x = log_level_from_string(rvalue);
889 if (x < 0) {
890 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log level, ignoring: %s", rvalue);
891 return 0;
892 }
893
894 if (*o < 0) /* if it wasn't initialized so far, assume zero facility */
895 *o = x;
896 else
897 *o = (*o & LOG_FACMASK) | x;
898
899 return 0;
900 }
901
902 int config_parse_signal(
903 const char *unit,
904 const char *filename,
905 unsigned line,
906 const char *section,
907 unsigned section_line,
908 const char *lvalue,
909 int ltype,
910 const char *rvalue,
911 void *data,
912 void *userdata) {
913
914 int *sig = data, r;
915
916 assert(filename);
917 assert(lvalue);
918 assert(rvalue);
919 assert(sig);
920
921 r = signal_from_string(rvalue);
922 if (r <= 0) {
923 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse signal name, ignoring: %s", rvalue);
924 return 0;
925 }
926
927 *sig = r;
928 return 0;
929 }
930
931 int config_parse_personality(
932 const char *unit,
933 const char *filename,
934 unsigned line,
935 const char *section,
936 unsigned section_line,
937 const char *lvalue,
938 int ltype,
939 const char *rvalue,
940 void *data,
941 void *userdata) {
942
943 unsigned long *personality = data, p;
944
945 assert(filename);
946 assert(lvalue);
947 assert(rvalue);
948 assert(personality);
949
950 if (isempty(rvalue))
951 p = PERSONALITY_INVALID;
952 else {
953 p = personality_from_string(rvalue);
954 if (p == PERSONALITY_INVALID) {
955 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse personality, ignoring: %s", rvalue);
956 return 0;
957 }
958 }
959
960 *personality = p;
961 return 0;
962 }
963
964 int config_parse_ifname(
965 const char *unit,
966 const char *filename,
967 unsigned line,
968 const char *section,
969 unsigned section_line,
970 const char *lvalue,
971 int ltype,
972 const char *rvalue,
973 void *data,
974 void *userdata) {
975
976 char **s = data;
977 int r;
978
979 assert(filename);
980 assert(lvalue);
981 assert(rvalue);
982 assert(data);
983
984 if (isempty(rvalue)) {
985 *s = mfree(*s);
986 return 0;
987 }
988
989 if (!ifname_valid(rvalue)) {
990 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue);
991 return 0;
992 }
993
994 r = free_and_strdup(s, rvalue);
995 if (r < 0)
996 return log_oom();
997
998 return 0;
999 }
1000
1001 int config_parse_ip_port(
1002 const char *unit,
1003 const char *filename,
1004 unsigned line,
1005 const char *section,
1006 unsigned section_line,
1007 const char *lvalue,
1008 int ltype,
1009 const char *rvalue,
1010 void *data,
1011 void *userdata) {
1012
1013 uint16_t *s = data;
1014 uint16_t port;
1015 int r;
1016
1017 assert(filename);
1018 assert(lvalue);
1019 assert(rvalue);
1020 assert(data);
1021
1022 if (isempty(rvalue)) {
1023 *s = 0;
1024 return 0;
1025 }
1026
1027 r = parse_ip_port(rvalue, &port);
1028 if (r < 0) {
1029 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse port '%s'.", rvalue);
1030 return 0;
1031 }
1032
1033 *s = port;
1034
1035 return 0;
1036 }
1037
1038 int config_parse_join_controllers(
1039 const char *unit,
1040 const char *filename,
1041 unsigned line,
1042 const char *section,
1043 unsigned section_line,
1044 const char *lvalue,
1045 int ltype,
1046 const char *rvalue,
1047 void *data,
1048 void *userdata) {
1049
1050 char ****ret = data;
1051 const char *whole_rvalue = rvalue;
1052 unsigned n = 0;
1053 _cleanup_(strv_free_freep) char ***controllers = NULL;
1054
1055 assert(filename);
1056 assert(lvalue);
1057 assert(rvalue);
1058 assert(ret);
1059
1060 for (;;) {
1061 _cleanup_free_ char *word = NULL;
1062 char **l;
1063 int r;
1064
1065 r = extract_first_word(&rvalue, &word, NULL, EXTRACT_QUOTES);
1066 if (r < 0) {
1067 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid value for %s: %s", lvalue, whole_rvalue);
1068 return r;
1069 }
1070 if (r == 0)
1071 break;
1072
1073 l = strv_split(word, ",");
1074 if (!l)
1075 return log_oom();
1076 strv_uniq(l);
1077
1078 if (strv_length(l) <= 1) {
1079 strv_free(l);
1080 continue;
1081 }
1082
1083 if (!controllers) {
1084 controllers = new(char**, 2);
1085 if (!controllers) {
1086 strv_free(l);
1087 return log_oom();
1088 }
1089
1090 controllers[0] = l;
1091 controllers[1] = NULL;
1092
1093 n = 1;
1094 } else {
1095 char ***a;
1096 char ***t;
1097
1098 t = new0(char**, n+2);
1099 if (!t) {
1100 strv_free(l);
1101 return log_oom();
1102 }
1103
1104 n = 0;
1105
1106 for (a = controllers; *a; a++)
1107 if (strv_overlap(*a, l)) {
1108 if (strv_extend_strv(&l, *a, false) < 0) {
1109 strv_free(l);
1110 strv_free_free(t);
1111 return log_oom();
1112 }
1113
1114 } else {
1115 char **c;
1116
1117 c = strv_copy(*a);
1118 if (!c) {
1119 strv_free(l);
1120 strv_free_free(t);
1121 return log_oom();
1122 }
1123
1124 t[n++] = c;
1125 }
1126
1127 t[n++] = strv_uniq(l);
1128
1129 strv_free_free(controllers);
1130 controllers = t;
1131 }
1132 }
1133 if (!isempty(rvalue))
1134 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
1135
1136 /* As a special case, return a single empty strv, to override the default */
1137 if (!controllers) {
1138 controllers = new(char**, 2);
1139 if (!controllers)
1140 return log_oom();
1141 controllers[0] = strv_new(NULL, NULL);
1142 if (!controllers[0])
1143 return log_oom();
1144 controllers[1] = NULL;
1145 }
1146
1147 strv_free_free(*ret);
1148 *ret = TAKE_PTR(controllers);
1149
1150 return 0;
1151 }
1152
1153 int config_parse_mtu(
1154 const char *unit,
1155 const char *filename,
1156 unsigned line,
1157 const char *section,
1158 unsigned section_line,
1159 const char *lvalue,
1160 int ltype,
1161 const char *rvalue,
1162 void *data,
1163 void *userdata) {
1164
1165 uint32_t *mtu = data;
1166 int r;
1167
1168 assert(rvalue);
1169 assert(mtu);
1170
1171 r = parse_mtu(ltype, rvalue, mtu);
1172 if (r == -ERANGE) {
1173 log_syntax(unit, LOG_ERR, filename, line, r,
1174 "Maximum transfer unit (MTU) value out of range. Permitted range is %" PRIu32 "…%" PRIu32 ", ignoring: %s",
1175 (uint32_t) (ltype == AF_INET6 ? IPV6_MIN_MTU : IPV4_MIN_MTU), (uint32_t) UINT32_MAX,
1176 rvalue);
1177 return 0;
1178 }
1179 if (r < 0) {
1180 log_syntax(unit, LOG_ERR, filename, line, r,
1181 "Failed to parse MTU value '%s', ignoring: %m", rvalue);
1182 return 0;
1183 }
1184
1185 return 0;
1186 }
1187
1188 int config_parse_rlimit(
1189 const char *unit,
1190 const char *filename,
1191 unsigned line,
1192 const char *section,
1193 unsigned section_line,
1194 const char *lvalue,
1195 int ltype,
1196 const char *rvalue,
1197 void *data,
1198 void *userdata) {
1199
1200 struct rlimit **rl = data, d = {};
1201 int r;
1202
1203 assert(rvalue);
1204 assert(rl);
1205
1206 r = rlimit_parse(ltype, rvalue, &d);
1207 if (r == -EILSEQ) {
1208 log_syntax(unit, LOG_WARNING, filename, line, r, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue);
1209 return 0;
1210 }
1211 if (r < 0) {
1212 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
1213 return 0;
1214 }
1215
1216 if (rl[ltype])
1217 *rl[ltype] = d;
1218 else {
1219 rl[ltype] = newdup(struct rlimit, &d, 1);
1220 if (!rl[ltype])
1221 return log_oom();
1222 }
1223
1224 return 0;
1225 }