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