]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/conf-parser.c
conf-parser: turn three bool function params into a flags fields
[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(const char* unit,
563 const char *filename,
564 unsigned line,
565 const char *section,
566 unsigned section_line,
567 const char *lvalue,
568 int ltype,
569 const char *rvalue,
570 void *data,
571 void *userdata) {
572
573 size_t *sz = data;
574 uint64_t v;
575 int r;
576
577 assert(filename);
578 assert(lvalue);
579 assert(rvalue);
580 assert(data);
581
582 r = parse_size(rvalue, 1000, &v);
583 if (r < 0 || (uint64_t) (size_t) v != v) {
584 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
585 return 0;
586 }
587
588 *sz = (size_t) v;
589 return 0;
590 }
591
592 int config_parse_iec_uint64(const char* unit,
593 const char *filename,
594 unsigned line,
595 const char *section,
596 unsigned section_line,
597 const char *lvalue,
598 int ltype,
599 const char *rvalue,
600 void *data,
601 void *userdata) {
602
603 uint64_t *bytes = data;
604 int r;
605
606 assert(filename);
607 assert(lvalue);
608 assert(rvalue);
609 assert(data);
610
611 r = parse_size(rvalue, 1024, bytes);
612 if (r < 0)
613 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
614
615 return 0;
616 }
617
618 int config_parse_bool(const char* unit,
619 const char *filename,
620 unsigned line,
621 const char *section,
622 unsigned section_line,
623 const char *lvalue,
624 int ltype,
625 const char *rvalue,
626 void *data,
627 void *userdata) {
628
629 int k;
630 bool *b = data;
631 bool fatal = ltype;
632
633 assert(filename);
634 assert(lvalue);
635 assert(rvalue);
636 assert(data);
637
638 k = parse_boolean(rvalue);
639 if (k < 0) {
640 log_syntax(unit, LOG_ERR, filename, line, k,
641 "Failed to parse boolean value%s: %s",
642 fatal ? "" : ", ignoring", rvalue);
643 return fatal ? -ENOEXEC : 0;
644 }
645
646 *b = !!k;
647 return 0;
648 }
649
650 int config_parse_tristate(
651 const char* unit,
652 const char *filename,
653 unsigned line,
654 const char *section,
655 unsigned section_line,
656 const char *lvalue,
657 int ltype,
658 const char *rvalue,
659 void *data,
660 void *userdata) {
661
662 int k, *t = data;
663
664 assert(filename);
665 assert(lvalue);
666 assert(rvalue);
667 assert(data);
668
669 /* A tristate is pretty much a boolean, except that it can
670 * also take the special value -1, indicating "uninitialized",
671 * much like NULL is for a pointer type. */
672
673 k = parse_boolean(rvalue);
674 if (k < 0) {
675 log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
676 return 0;
677 }
678
679 *t = !!k;
680 return 0;
681 }
682
683 int config_parse_string(
684 const char *unit,
685 const char *filename,
686 unsigned line,
687 const char *section,
688 unsigned section_line,
689 const char *lvalue,
690 int ltype,
691 const char *rvalue,
692 void *data,
693 void *userdata) {
694
695 char **s = data, *n;
696
697 assert(filename);
698 assert(lvalue);
699 assert(rvalue);
700 assert(data);
701
702 if (!utf8_is_valid(rvalue)) {
703 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
704 return 0;
705 }
706
707 if (isempty(rvalue))
708 n = NULL;
709 else {
710 n = strdup(rvalue);
711 if (!n)
712 return log_oom();
713 }
714
715 free(*s);
716 *s = n;
717
718 return 0;
719 }
720
721 int config_parse_path(
722 const char *unit,
723 const char *filename,
724 unsigned line,
725 const char *section,
726 unsigned section_line,
727 const char *lvalue,
728 int ltype,
729 const char *rvalue,
730 void *data,
731 void *userdata) {
732
733 char **s = data, *n;
734 bool fatal = ltype;
735
736 assert(filename);
737 assert(lvalue);
738 assert(rvalue);
739 assert(data);
740
741 if (isempty(rvalue)) {
742 n = NULL;
743 goto finalize;
744 }
745
746 if (!utf8_is_valid(rvalue)) {
747 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
748 return fatal ? -ENOEXEC : 0;
749 }
750
751 if (!path_is_absolute(rvalue)) {
752 log_syntax(unit, LOG_ERR, filename, line, 0,
753 "Not an absolute path%s: %s",
754 fatal ? "" : ", ignoring", rvalue);
755 return fatal ? -ENOEXEC : 0;
756 }
757
758 n = strdup(rvalue);
759 if (!n)
760 return log_oom();
761
762 path_kill_slashes(n);
763
764 finalize:
765 free(*s);
766 *s = n;
767
768 return 0;
769 }
770
771 int config_parse_strv(
772 const char *unit,
773 const char *filename,
774 unsigned line,
775 const char *section,
776 unsigned section_line,
777 const char *lvalue,
778 int ltype,
779 const char *rvalue,
780 void *data,
781 void *userdata) {
782
783 char ***sv = data;
784 int r;
785
786 assert(filename);
787 assert(lvalue);
788 assert(rvalue);
789 assert(data);
790
791 if (isempty(rvalue)) {
792 *sv = strv_free(*sv);
793 return 0;
794 }
795
796 for (;;) {
797 char *word = NULL;
798
799 r = extract_first_word(&rvalue, &word, NULL, EXTRACT_QUOTES|EXTRACT_RETAIN_ESCAPE);
800 if (r == 0)
801 break;
802 if (r == -ENOMEM)
803 return log_oom();
804 if (r < 0) {
805 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
806 break;
807 }
808
809 if (!utf8_is_valid(word)) {
810 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, word);
811 free(word);
812 continue;
813 }
814
815 r = strv_consume(sv, word);
816 if (r < 0)
817 return log_oom();
818 }
819
820 return 0;
821 }
822
823 int config_parse_log_facility(
824 const char *unit,
825 const char *filename,
826 unsigned line,
827 const char *section,
828 unsigned section_line,
829 const char *lvalue,
830 int ltype,
831 const char *rvalue,
832 void *data,
833 void *userdata) {
834
835
836 int *o = data, x;
837
838 assert(filename);
839 assert(lvalue);
840 assert(rvalue);
841 assert(data);
842
843 x = log_facility_unshifted_from_string(rvalue);
844 if (x < 0) {
845 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log facility, ignoring: %s", rvalue);
846 return 0;
847 }
848
849 *o = (x << 3) | LOG_PRI(*o);
850
851 return 0;
852 }
853
854 int config_parse_log_level(
855 const char *unit,
856 const char *filename,
857 unsigned line,
858 const char *section,
859 unsigned section_line,
860 const char *lvalue,
861 int ltype,
862 const char *rvalue,
863 void *data,
864 void *userdata) {
865
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 *o = (*o & LOG_FACMASK) | x;
881 return 0;
882 }
883
884 int config_parse_signal(
885 const char *unit,
886 const char *filename,
887 unsigned line,
888 const char *section,
889 unsigned section_line,
890 const char *lvalue,
891 int ltype,
892 const char *rvalue,
893 void *data,
894 void *userdata) {
895
896 int *sig = data, r;
897
898 assert(filename);
899 assert(lvalue);
900 assert(rvalue);
901 assert(sig);
902
903 r = signal_from_string_try_harder(rvalue);
904 if (r <= 0) {
905 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse signal name, ignoring: %s", rvalue);
906 return 0;
907 }
908
909 *sig = r;
910 return 0;
911 }
912
913 int config_parse_personality(
914 const char *unit,
915 const char *filename,
916 unsigned line,
917 const char *section,
918 unsigned section_line,
919 const char *lvalue,
920 int ltype,
921 const char *rvalue,
922 void *data,
923 void *userdata) {
924
925 unsigned long *personality = data, p;
926
927 assert(filename);
928 assert(lvalue);
929 assert(rvalue);
930 assert(personality);
931
932 if (isempty(rvalue))
933 p = PERSONALITY_INVALID;
934 else {
935 p = personality_from_string(rvalue);
936 if (p == PERSONALITY_INVALID) {
937 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse personality, ignoring: %s", rvalue);
938 return 0;
939 }
940 }
941
942 *personality = p;
943 return 0;
944 }
945
946 int config_parse_ifname(
947 const char *unit,
948 const char *filename,
949 unsigned line,
950 const char *section,
951 unsigned section_line,
952 const char *lvalue,
953 int ltype,
954 const char *rvalue,
955 void *data,
956 void *userdata) {
957
958 char **s = data;
959 int r;
960
961 assert(filename);
962 assert(lvalue);
963 assert(rvalue);
964 assert(data);
965
966 if (isempty(rvalue)) {
967 *s = mfree(*s);
968 return 0;
969 }
970
971 if (!ifname_valid(rvalue)) {
972 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue);
973 return 0;
974 }
975
976 r = free_and_strdup(s, rvalue);
977 if (r < 0)
978 return log_oom();
979
980 return 0;
981 }
982
983 int config_parse_ip_port(
984 const char *unit,
985 const char *filename,
986 unsigned line,
987 const char *section,
988 unsigned section_line,
989 const char *lvalue,
990 int ltype,
991 const char *rvalue,
992 void *data,
993 void *userdata) {
994
995 uint16_t *s = data;
996 uint16_t port;
997 int r;
998
999 assert(filename);
1000 assert(lvalue);
1001 assert(rvalue);
1002 assert(data);
1003
1004 if (isempty(rvalue)) {
1005 *s = 0;
1006 return 0;
1007 }
1008
1009 r = parse_ip_port(rvalue, &port);
1010 if (r < 0) {
1011 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse port '%s'.", rvalue);
1012 return 0;
1013 }
1014
1015 *s = port;
1016
1017 return 0;
1018 }