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