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