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