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