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