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