]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/conf-parser.c
conf-parser: shorten config_parse_string() by using free_and_strdup() and empty_to_null()
[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 int config_parse_##type( \
506 const char *unit, \
507 const char *filename, \
508 unsigned line, \
509 const char *section, \
510 unsigned section_line, \
511 const char *lvalue, \
512 int ltype, \
513 const char *rvalue, \
514 void *data, \
515 void *userdata) { \
516 \
517 vartype *i = data; \
518 int r; \
519 \
520 assert(filename); \
521 assert(lvalue); \
522 assert(rvalue); \
523 assert(data); \
524 \
525 r = conv_func(rvalue, i); \
526 if (r < 0) \
527 log_syntax(unit, LOG_ERR, filename, line, r, \
528 "Failed to parse %s value, ignoring: %s", \
529 #type, rvalue); \
530 \
531 return 0; \
532 }
533
534 DEFINE_PARSER(int, int, safe_atoi);
535 DEFINE_PARSER(long, long, safe_atoli);
536 DEFINE_PARSER(uint8, uint8_t, safe_atou8);
537 DEFINE_PARSER(uint16, uint16_t, safe_atou16);
538 DEFINE_PARSER(uint32, uint32_t, safe_atou32);
539 DEFINE_PARSER(uint64, uint64_t, safe_atou64);
540 DEFINE_PARSER(unsigned, unsigned, safe_atou);
541 DEFINE_PARSER(double, double, safe_atod);
542 DEFINE_PARSER(nsec, nsec_t, parse_nsec);
543 DEFINE_PARSER(sec, usec_t, parse_sec);
544 DEFINE_PARSER(mode, mode_t, parse_mode);
545
546 int config_parse_iec_size(const char* unit,
547 const char *filename,
548 unsigned line,
549 const char *section,
550 unsigned section_line,
551 const char *lvalue,
552 int ltype,
553 const char *rvalue,
554 void *data,
555 void *userdata) {
556
557 size_t *sz = data;
558 uint64_t v;
559 int r;
560
561 assert(filename);
562 assert(lvalue);
563 assert(rvalue);
564 assert(data);
565
566 r = parse_size(rvalue, 1024, &v);
567 if (r < 0 || (uint64_t) (size_t) v != v) {
568 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
569 return 0;
570 }
571
572 *sz = (size_t) v;
573 return 0;
574 }
575
576 int config_parse_si_size(
577 const char* unit,
578 const char *filename,
579 unsigned line,
580 const char *section,
581 unsigned section_line,
582 const char *lvalue,
583 int ltype,
584 const char *rvalue,
585 void *data,
586 void *userdata) {
587
588 size_t *sz = data;
589 uint64_t v;
590 int r;
591
592 assert(filename);
593 assert(lvalue);
594 assert(rvalue);
595 assert(data);
596
597 r = parse_size(rvalue, 1000, &v);
598 if (r < 0 || (uint64_t) (size_t) v != v) {
599 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
600 return 0;
601 }
602
603 *sz = (size_t) v;
604 return 0;
605 }
606
607 int config_parse_iec_uint64(
608 const char* unit,
609 const char *filename,
610 unsigned line,
611 const char *section,
612 unsigned section_line,
613 const char *lvalue,
614 int ltype,
615 const char *rvalue,
616 void *data,
617 void *userdata) {
618
619 uint64_t *bytes = data;
620 int r;
621
622 assert(filename);
623 assert(lvalue);
624 assert(rvalue);
625 assert(data);
626
627 r = parse_size(rvalue, 1024, bytes);
628 if (r < 0)
629 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
630
631 return 0;
632 }
633
634 int config_parse_bool(const char* unit,
635 const char *filename,
636 unsigned line,
637 const char *section,
638 unsigned section_line,
639 const char *lvalue,
640 int ltype,
641 const char *rvalue,
642 void *data,
643 void *userdata) {
644
645 int k;
646 bool *b = data;
647 bool fatal = ltype;
648
649 assert(filename);
650 assert(lvalue);
651 assert(rvalue);
652 assert(data);
653
654 k = parse_boolean(rvalue);
655 if (k < 0) {
656 log_syntax(unit, LOG_ERR, filename, line, k,
657 "Failed to parse boolean value%s: %s",
658 fatal ? "" : ", ignoring", rvalue);
659 return fatal ? -ENOEXEC : 0;
660 }
661
662 *b = !!k;
663 return 0;
664 }
665
666 int config_parse_tristate(
667 const char* unit,
668 const char *filename,
669 unsigned line,
670 const char *section,
671 unsigned section_line,
672 const char *lvalue,
673 int ltype,
674 const char *rvalue,
675 void *data,
676 void *userdata) {
677
678 int k, *t = data;
679
680 assert(filename);
681 assert(lvalue);
682 assert(rvalue);
683 assert(data);
684
685 /* A tristate is pretty much a boolean, except that it can
686 * also take the special value -1, indicating "uninitialized",
687 * much like NULL is for a pointer type. */
688
689 k = parse_boolean(rvalue);
690 if (k < 0) {
691 log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
692 return 0;
693 }
694
695 *t = !!k;
696 return 0;
697 }
698
699 int config_parse_string(
700 const char *unit,
701 const char *filename,
702 unsigned line,
703 const char *section,
704 unsigned section_line,
705 const char *lvalue,
706 int ltype,
707 const char *rvalue,
708 void *data,
709 void *userdata) {
710
711 char **s = data;
712
713 assert(filename);
714 assert(lvalue);
715 assert(rvalue);
716 assert(data);
717
718 if (!utf8_is_valid(rvalue)) {
719 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
720 return 0;
721 }
722
723 if (free_and_strdup(s, empty_to_null(rvalue)) < 0)
724 return log_oom();
725
726 return 0;
727 }
728
729 int config_parse_path(
730 const char *unit,
731 const char *filename,
732 unsigned line,
733 const char *section,
734 unsigned section_line,
735 const char *lvalue,
736 int ltype,
737 const char *rvalue,
738 void *data,
739 void *userdata) {
740
741 char **s = data, *n;
742 bool fatal = ltype;
743
744 assert(filename);
745 assert(lvalue);
746 assert(rvalue);
747 assert(data);
748
749 if (isempty(rvalue)) {
750 n = NULL;
751 goto finalize;
752 }
753
754 if (!utf8_is_valid(rvalue)) {
755 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
756 return fatal ? -ENOEXEC : 0;
757 }
758
759 if (!path_is_absolute(rvalue)) {
760 log_syntax(unit, LOG_ERR, filename, line, 0,
761 "Not an absolute path%s: %s",
762 fatal ? "" : ", ignoring", rvalue);
763 return fatal ? -ENOEXEC : 0;
764 }
765
766 n = strdup(rvalue);
767 if (!n)
768 return log_oom();
769
770 path_kill_slashes(n);
771
772 finalize:
773 free(*s);
774 *s = n;
775
776 return 0;
777 }
778
779 int config_parse_strv(
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 char ***sv = data;
792 int r;
793
794 assert(filename);
795 assert(lvalue);
796 assert(rvalue);
797 assert(data);
798
799 if (isempty(rvalue)) {
800 *sv = strv_free(*sv);
801 return 0;
802 }
803
804 for (;;) {
805 char *word = NULL;
806
807 r = extract_first_word(&rvalue, &word, NULL, EXTRACT_QUOTES|EXTRACT_RETAIN_ESCAPE);
808 if (r == 0)
809 break;
810 if (r == -ENOMEM)
811 return log_oom();
812 if (r < 0) {
813 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
814 break;
815 }
816
817 if (!utf8_is_valid(word)) {
818 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, word);
819 free(word);
820 continue;
821 }
822
823 r = strv_consume(sv, word);
824 if (r < 0)
825 return log_oom();
826 }
827
828 return 0;
829 }
830
831 int config_parse_warn_compat(
832 const char *unit,
833 const char *filename,
834 unsigned line,
835 const char *section,
836 unsigned section_line,
837 const char *lvalue,
838 int ltype,
839 const char *rvalue,
840 void *data,
841 void *userdata) {
842 Disabled reason = ltype;
843
844 switch(reason) {
845 case DISABLED_CONFIGURATION:
846 log_syntax(unit, LOG_DEBUG, filename, line, 0,
847 "Support for option %s= has been disabled at compile time and it is ignored", lvalue);
848 break;
849 case DISABLED_LEGACY:
850 log_syntax(unit, LOG_INFO, filename, line, 0,
851 "Support for option %s= has been removed and it is ignored", lvalue);
852 break;
853 case DISABLED_EXPERIMENTAL:
854 log_syntax(unit, LOG_INFO, filename, line, 0,
855 "Support for option %s= has not yet been enabled and it is ignored", lvalue);
856 break;
857 };
858
859 return 0;
860 }
861
862 int config_parse_log_facility(
863 const char *unit,
864 const char *filename,
865 unsigned line,
866 const char *section,
867 unsigned section_line,
868 const char *lvalue,
869 int ltype,
870 const char *rvalue,
871 void *data,
872 void *userdata) {
873
874 int *o = data, x;
875
876 assert(filename);
877 assert(lvalue);
878 assert(rvalue);
879 assert(data);
880
881 x = log_facility_unshifted_from_string(rvalue);
882 if (x < 0) {
883 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log facility, ignoring: %s", rvalue);
884 return 0;
885 }
886
887 *o = (x << 3) | LOG_PRI(*o);
888
889 return 0;
890 }
891
892 int config_parse_log_level(
893 const char *unit,
894 const char *filename,
895 unsigned line,
896 const char *section,
897 unsigned section_line,
898 const char *lvalue,
899 int ltype,
900 const char *rvalue,
901 void *data,
902 void *userdata) {
903
904 int *o = data, x;
905
906 assert(filename);
907 assert(lvalue);
908 assert(rvalue);
909 assert(data);
910
911 x = log_level_from_string(rvalue);
912 if (x < 0) {
913 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log level, ignoring: %s", rvalue);
914 return 0;
915 }
916
917 if (*o < 0) /* if it wasn't initialized so far, assume zero facility */
918 *o = x;
919 else
920 *o = (*o & LOG_FACMASK) | x;
921
922 return 0;
923 }
924
925 int config_parse_signal(
926 const char *unit,
927 const char *filename,
928 unsigned line,
929 const char *section,
930 unsigned section_line,
931 const char *lvalue,
932 int ltype,
933 const char *rvalue,
934 void *data,
935 void *userdata) {
936
937 int *sig = data, r;
938
939 assert(filename);
940 assert(lvalue);
941 assert(rvalue);
942 assert(sig);
943
944 r = signal_from_string(rvalue);
945 if (r <= 0) {
946 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse signal name, ignoring: %s", rvalue);
947 return 0;
948 }
949
950 *sig = r;
951 return 0;
952 }
953
954 int config_parse_personality(
955 const char *unit,
956 const char *filename,
957 unsigned line,
958 const char *section,
959 unsigned section_line,
960 const char *lvalue,
961 int ltype,
962 const char *rvalue,
963 void *data,
964 void *userdata) {
965
966 unsigned long *personality = data, p;
967
968 assert(filename);
969 assert(lvalue);
970 assert(rvalue);
971 assert(personality);
972
973 if (isempty(rvalue))
974 p = PERSONALITY_INVALID;
975 else {
976 p = personality_from_string(rvalue);
977 if (p == PERSONALITY_INVALID) {
978 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse personality, ignoring: %s", rvalue);
979 return 0;
980 }
981 }
982
983 *personality = p;
984 return 0;
985 }
986
987 int config_parse_ifname(
988 const char *unit,
989 const char *filename,
990 unsigned line,
991 const char *section,
992 unsigned section_line,
993 const char *lvalue,
994 int ltype,
995 const char *rvalue,
996 void *data,
997 void *userdata) {
998
999 char **s = data;
1000 int r;
1001
1002 assert(filename);
1003 assert(lvalue);
1004 assert(rvalue);
1005 assert(data);
1006
1007 if (isempty(rvalue)) {
1008 *s = mfree(*s);
1009 return 0;
1010 }
1011
1012 if (!ifname_valid(rvalue)) {
1013 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue);
1014 return 0;
1015 }
1016
1017 r = free_and_strdup(s, rvalue);
1018 if (r < 0)
1019 return log_oom();
1020
1021 return 0;
1022 }
1023
1024 int config_parse_ip_port(
1025 const char *unit,
1026 const char *filename,
1027 unsigned line,
1028 const char *section,
1029 unsigned section_line,
1030 const char *lvalue,
1031 int ltype,
1032 const char *rvalue,
1033 void *data,
1034 void *userdata) {
1035
1036 uint16_t *s = data;
1037 uint16_t port;
1038 int r;
1039
1040 assert(filename);
1041 assert(lvalue);
1042 assert(rvalue);
1043 assert(data);
1044
1045 if (isempty(rvalue)) {
1046 *s = 0;
1047 return 0;
1048 }
1049
1050 r = parse_ip_port(rvalue, &port);
1051 if (r < 0) {
1052 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse port '%s'.", rvalue);
1053 return 0;
1054 }
1055
1056 *s = port;
1057
1058 return 0;
1059 }
1060
1061 int config_parse_join_controllers(
1062 const char *unit,
1063 const char *filename,
1064 unsigned line,
1065 const char *section,
1066 unsigned section_line,
1067 const char *lvalue,
1068 int ltype,
1069 const char *rvalue,
1070 void *data,
1071 void *userdata) {
1072
1073 char ****ret = data;
1074 const char *whole_rvalue = rvalue;
1075 unsigned n = 0;
1076 _cleanup_(strv_free_freep) char ***controllers = NULL;
1077
1078 assert(filename);
1079 assert(lvalue);
1080 assert(rvalue);
1081 assert(ret);
1082
1083 for (;;) {
1084 _cleanup_free_ char *word = NULL;
1085 char **l;
1086 int r;
1087
1088 r = extract_first_word(&rvalue, &word, NULL, EXTRACT_QUOTES);
1089 if (r < 0) {
1090 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid value for %s: %s", lvalue, whole_rvalue);
1091 return r;
1092 }
1093 if (r == 0)
1094 break;
1095
1096 l = strv_split(word, ",");
1097 if (!l)
1098 return log_oom();
1099 strv_uniq(l);
1100
1101 if (strv_length(l) <= 1) {
1102 strv_free(l);
1103 continue;
1104 }
1105
1106 if (!controllers) {
1107 controllers = new(char**, 2);
1108 if (!controllers) {
1109 strv_free(l);
1110 return log_oom();
1111 }
1112
1113 controllers[0] = l;
1114 controllers[1] = NULL;
1115
1116 n = 1;
1117 } else {
1118 char ***a;
1119 char ***t;
1120
1121 t = new0(char**, n+2);
1122 if (!t) {
1123 strv_free(l);
1124 return log_oom();
1125 }
1126
1127 n = 0;
1128
1129 for (a = controllers; *a; a++)
1130 if (strv_overlap(*a, l)) {
1131 if (strv_extend_strv(&l, *a, false) < 0) {
1132 strv_free(l);
1133 strv_free_free(t);
1134 return log_oom();
1135 }
1136
1137 } else {
1138 char **c;
1139
1140 c = strv_copy(*a);
1141 if (!c) {
1142 strv_free(l);
1143 strv_free_free(t);
1144 return log_oom();
1145 }
1146
1147 t[n++] = c;
1148 }
1149
1150 t[n++] = strv_uniq(l);
1151
1152 strv_free_free(controllers);
1153 controllers = t;
1154 }
1155 }
1156 if (!isempty(rvalue))
1157 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
1158
1159 /* As a special case, return a single empty strv, to override the default */
1160 if (!controllers) {
1161 controllers = new(char**, 2);
1162 if (!controllers)
1163 return log_oom();
1164 controllers[0] = strv_new(NULL, NULL);
1165 if (!controllers[0])
1166 return log_oom();
1167 controllers[1] = NULL;
1168 }
1169
1170 strv_free_free(*ret);
1171 *ret = TAKE_PTR(controllers);
1172
1173 return 0;
1174 }
1175
1176 int config_parse_mtu(
1177 const char *unit,
1178 const char *filename,
1179 unsigned line,
1180 const char *section,
1181 unsigned section_line,
1182 const char *lvalue,
1183 int ltype,
1184 const char *rvalue,
1185 void *data,
1186 void *userdata) {
1187
1188 uint32_t *mtu = data;
1189 int r;
1190
1191 assert(rvalue);
1192 assert(mtu);
1193
1194 r = parse_mtu(ltype, rvalue, mtu);
1195 if (r == -ERANGE) {
1196 log_syntax(unit, LOG_ERR, filename, line, r,
1197 "Maximum transfer unit (MTU) value out of range. Permitted range is %" PRIu32 "…%" PRIu32 ", ignoring: %s",
1198 (uint32_t) (ltype == AF_INET6 ? IPV6_MIN_MTU : IPV4_MIN_MTU), (uint32_t) UINT32_MAX,
1199 rvalue);
1200 return 0;
1201 }
1202 if (r < 0) {
1203 log_syntax(unit, LOG_ERR, filename, line, r,
1204 "Failed to parse MTU value '%s', ignoring: %m", rvalue);
1205 return 0;
1206 }
1207
1208 return 0;
1209 }
1210
1211 int config_parse_rlimit(
1212 const char *unit,
1213 const char *filename,
1214 unsigned line,
1215 const char *section,
1216 unsigned section_line,
1217 const char *lvalue,
1218 int ltype,
1219 const char *rvalue,
1220 void *data,
1221 void *userdata) {
1222
1223 struct rlimit **rl = data, d = {};
1224 int r;
1225
1226 assert(rvalue);
1227 assert(rl);
1228
1229 r = rlimit_parse(ltype, rvalue, &d);
1230 if (r == -EILSEQ) {
1231 log_syntax(unit, LOG_WARNING, filename, line, r, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue);
1232 return 0;
1233 }
1234 if (r < 0) {
1235 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
1236 return 0;
1237 }
1238
1239 if (rl[ltype])
1240 *rl[ltype] = d;
1241 else {
1242 rl[ltype] = newdup(struct rlimit, &d, 1);
1243 if (!rl[ltype])
1244 return log_oom();
1245 }
1246
1247 return 0;
1248 }