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