]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/conf-parser.c
shutdown: Fix last try detection
[thirdparty/systemd.git] / src / shared / conf-parser.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <errno.h>
4 #include <limits.h>
5 #include <stdint.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <sys/types.h>
9
10 #include "alloc-util.h"
11 #include "conf-files.h"
12 #include "conf-parser.h"
13 #include "def.h"
14 #include "dns-domain.h"
15 #include "escape.h"
16 #include "ether-addr-util.h"
17 #include "extract-word.h"
18 #include "fd-util.h"
19 #include "fileio.h"
20 #include "fs-util.h"
21 #include "hostname-util.h"
22 #include "in-addr-util.h"
23 #include "log.h"
24 #include "macro.h"
25 #include "missing_network.h"
26 #include "nulstr-util.h"
27 #include "parse-helpers.h"
28 #include "parse-util.h"
29 #include "path-util.h"
30 #include "percent-util.h"
31 #include "process-util.h"
32 #include "rlimit-util.h"
33 #include "sd-id128.h"
34 #include "set.h"
35 #include "signal-util.h"
36 #include "socket-util.h"
37 #include "stat-util.h"
38 #include "string-util.h"
39 #include "strv.h"
40 #include "syslog-util.h"
41 #include "time-util.h"
42 #include "utf8.h"
43
44 int config_item_table_lookup(
45 const void *table,
46 const char *section,
47 const char *lvalue,
48 ConfigParserCallback *ret_func,
49 int *ret_ltype,
50 void **ret_data,
51 void *userdata) {
52
53 const ConfigTableItem *t;
54
55 assert(table);
56 assert(lvalue);
57 assert(ret_func);
58 assert(ret_ltype);
59 assert(ret_data);
60
61 for (t = table; t->lvalue; t++) {
62
63 if (!streq(lvalue, t->lvalue))
64 continue;
65
66 if (!streq_ptr(section, t->section))
67 continue;
68
69 *ret_func = t->parse;
70 *ret_ltype = t->ltype;
71 *ret_data = t->data;
72 return 1;
73 }
74
75 *ret_func = NULL;
76 *ret_ltype = 0;
77 *ret_data = NULL;
78 return 0;
79 }
80
81 int config_item_perf_lookup(
82 const void *table,
83 const char *section,
84 const char *lvalue,
85 ConfigParserCallback *ret_func,
86 int *ret_ltype,
87 void **ret_data,
88 void *userdata) {
89
90 ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
91 const ConfigPerfItem *p;
92
93 assert(table);
94 assert(lvalue);
95 assert(ret_func);
96 assert(ret_ltype);
97 assert(ret_data);
98
99 if (section) {
100 const char *key;
101
102 key = strjoina(section, ".", lvalue);
103 p = lookup(key, strlen(key));
104 } else
105 p = lookup(lvalue, strlen(lvalue));
106 if (!p) {
107 *ret_func = NULL;
108 *ret_ltype = 0;
109 *ret_data = NULL;
110 return 0;
111 }
112
113 *ret_func = p->parse;
114 *ret_ltype = p->ltype;
115 *ret_data = (uint8_t*) userdata + p->offset;
116 return 1;
117 }
118
119 /* Run the user supplied parser for an assignment */
120 static int next_assignment(
121 const char *unit,
122 const char *filename,
123 unsigned line,
124 ConfigItemLookup lookup,
125 const void *table,
126 const char *section,
127 unsigned section_line,
128 const char *lvalue,
129 const char *rvalue,
130 ConfigParseFlags flags,
131 void *userdata) {
132
133 ConfigParserCallback func = NULL;
134 int ltype = 0;
135 void *data = NULL;
136 int r;
137
138 assert(filename);
139 assert(line > 0);
140 assert(lookup);
141 assert(lvalue);
142 assert(rvalue);
143
144 r = lookup(table, section, lvalue, &func, &ltype, &data, userdata);
145 if (r < 0)
146 return r;
147 if (r > 0) {
148 if (!func)
149 return 0;
150
151 return func(unit, filename, line, section, section_line,
152 lvalue, ltype, rvalue, data, userdata);
153 }
154
155 /* Warn about unknown non-extension fields. */
156 if (!(flags & CONFIG_PARSE_RELAXED) && !startswith(lvalue, "X-"))
157 log_syntax(unit, LOG_WARNING, filename, line, 0,
158 "Unknown key name '%s' in section '%s', ignoring.", lvalue, section);
159
160 return 0;
161 }
162
163 /* Parse a single logical line */
164 static int parse_line(
165 const char* unit,
166 const char *filename,
167 unsigned line,
168 const char *sections,
169 ConfigItemLookup lookup,
170 const void *table,
171 ConfigParseFlags flags,
172 char **section,
173 unsigned *section_line,
174 bool *section_ignored,
175 char *l, /* is modified */
176 void *userdata) {
177
178 char *e;
179
180 assert(filename);
181 assert(line > 0);
182 assert(lookup);
183 assert(l);
184
185 l = strstrip(l);
186 if (isempty(l))
187 return 0;
188
189 if (l[0] == '\n')
190 return 0;
191
192 if (!utf8_is_valid(l))
193 return log_syntax_invalid_utf8(unit, LOG_WARNING, filename, line, l);
194
195 if (l[0] == '[') {
196 _cleanup_free_ char *n = NULL;
197 size_t k;
198
199 k = strlen(l);
200 assert(k > 0);
201
202 if (l[k-1] != ']')
203 return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EBADMSG), "Invalid section header '%s'", l);
204
205 n = strndup(l+1, k-2);
206 if (!n)
207 return log_oom();
208
209 if (!string_is_safe(n))
210 return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EBADMSG), "Bad characters in section header '%s'", l);
211
212 if (sections && !nulstr_contains(sections, n)) {
213 bool ignore;
214 const char *t;
215
216 ignore = (flags & CONFIG_PARSE_RELAXED) || startswith(n, "X-");
217
218 if (!ignore)
219 NULSTR_FOREACH(t, sections)
220 if (streq_ptr(n, startswith(t, "-"))) { /* Ignore sections prefixed with "-" in valid section list */
221 ignore = true;
222 break;
223 }
224
225 if (!ignore)
226 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown section '%s'. Ignoring.", n);
227
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 if (!(flags & CONFIG_PARSE_RELAXED) && !*section_ignored)
242 log_syntax(unit, LOG_WARNING, filename, line, 0, "Assignment outside of section. Ignoring.");
243
244 return 0;
245 }
246
247 e = strchr(l, '=');
248 if (!e)
249 return log_syntax(unit, LOG_WARNING, filename, line, 0,
250 "Missing '=', ignoring line.");
251 if (e == l)
252 return log_syntax(unit, LOG_WARNING, filename, line, 0,
253 "Missing key name before '=', ignoring line.");
254
255 *e = 0;
256 e++;
257
258 return next_assignment(unit,
259 filename,
260 line,
261 lookup,
262 table,
263 *section,
264 *section_line,
265 strstrip(l),
266 strstrip(e),
267 flags,
268 userdata);
269 }
270
271 /* Go through the file and parse each line */
272 int config_parse(
273 const char *unit,
274 const char *filename,
275 FILE *f,
276 const char *sections,
277 ConfigItemLookup lookup,
278 const void *table,
279 ConfigParseFlags flags,
280 void *userdata,
281 struct stat *ret_stat) {
282
283 _cleanup_free_ char *section = NULL, *continuation = NULL;
284 _cleanup_fclose_ FILE *ours = NULL;
285 unsigned line = 0, section_line = 0;
286 bool section_ignored = false, bom_seen = false;
287 struct stat st;
288 int r, fd;
289
290 assert(filename);
291 assert(lookup);
292
293 if (!f) {
294 f = ours = fopen(filename, "re");
295 if (!f) {
296 /* Only log on request, except for ENOENT,
297 * since we return 0 to the caller. */
298 if ((flags & CONFIG_PARSE_WARN) || errno == ENOENT)
299 log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno,
300 "Failed to open configuration file '%s': %m", filename);
301
302 if (errno == ENOENT) {
303 if (ret_stat)
304 *ret_stat = (struct stat) {};
305
306 return 0;
307 }
308
309 return -errno;
310 }
311 }
312
313 fd = fileno(f);
314 if (fd >= 0) { /* stream might not have an fd, let's be careful hence */
315
316 if (fstat(fd, &st) < 0)
317 return log_full_errno(FLAGS_SET(flags, CONFIG_PARSE_WARN) ? LOG_ERR : LOG_DEBUG, errno,
318 "Failed to fstat(%s): %m", filename);
319
320 (void) stat_warn_permissions(filename, &st);
321 } else
322 st = (struct stat) {};
323
324 for (;;) {
325 _cleanup_free_ char *buf = NULL;
326 bool escaped = false;
327 char *l, *p, *e;
328
329 r = read_line(f, LONG_LINE_MAX, &buf);
330 if (r == 0)
331 break;
332 if (r == -ENOBUFS) {
333 if (flags & CONFIG_PARSE_WARN)
334 log_error_errno(r, "%s:%u: Line too long", filename, line);
335
336 return r;
337 }
338 if (r < 0) {
339 if (FLAGS_SET(flags, CONFIG_PARSE_WARN))
340 log_error_errno(r, "%s:%u: Error while reading configuration file: %m", filename, line);
341
342 return r;
343 }
344
345 line++;
346
347 l = skip_leading_chars(buf, WHITESPACE);
348 if (*l != '\0' && strchr(COMMENTS, *l))
349 continue;
350
351 l = buf;
352 if (!bom_seen) {
353 char *q;
354
355 q = startswith(buf, UTF8_BYTE_ORDER_MARK);
356 if (q) {
357 l = q;
358 bom_seen = true;
359 }
360 }
361
362 if (continuation) {
363 if (strlen(continuation) + strlen(l) > LONG_LINE_MAX) {
364 if (flags & CONFIG_PARSE_WARN)
365 log_error("%s:%u: Continuation line too long", filename, line);
366 return -ENOBUFS;
367 }
368
369 if (!strextend(&continuation, l)) {
370 if (flags & CONFIG_PARSE_WARN)
371 log_oom();
372 return -ENOMEM;
373 }
374
375 p = continuation;
376 } else
377 p = l;
378
379 for (e = p; *e; e++) {
380 if (escaped)
381 escaped = false;
382 else if (*e == '\\')
383 escaped = true;
384 }
385
386 if (escaped) {
387 *(e-1) = ' ';
388
389 if (!continuation) {
390 continuation = strdup(l);
391 if (!continuation) {
392 if (flags & CONFIG_PARSE_WARN)
393 log_oom();
394 return -ENOMEM;
395 }
396 }
397
398 continue;
399 }
400
401 r = parse_line(unit,
402 filename,
403 line,
404 sections,
405 lookup,
406 table,
407 flags,
408 &section,
409 &section_line,
410 &section_ignored,
411 p,
412 userdata);
413 if (r < 0) {
414 if (flags & CONFIG_PARSE_WARN)
415 log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
416 return r;
417 }
418
419 continuation = mfree(continuation);
420 }
421
422 if (continuation) {
423 r = parse_line(unit,
424 filename,
425 ++line,
426 sections,
427 lookup,
428 table,
429 flags,
430 &section,
431 &section_line,
432 &section_ignored,
433 continuation,
434 userdata);
435 if (r < 0) {
436 if (flags & CONFIG_PARSE_WARN)
437 log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
438 return r;
439 }
440 }
441
442 if (ret_stat)
443 *ret_stat = st;
444
445 return 1;
446 }
447
448 int hashmap_put_stats_by_path(Hashmap **stats_by_path, const char *path, const struct stat *st) {
449 _cleanup_free_ struct stat *st_copy = NULL;
450 _cleanup_free_ char *path_copy = NULL;
451 int r;
452
453 assert(stats_by_path);
454 assert(path);
455 assert(st);
456
457 r = hashmap_ensure_allocated(stats_by_path, &path_hash_ops_free_free);
458 if (r < 0)
459 return r;
460
461 st_copy = newdup(struct stat, st, 1);
462 if (!st_copy)
463 return -ENOMEM;
464
465 path_copy = strdup(path);
466 if (!path)
467 return -ENOMEM;
468
469 r = hashmap_put(*stats_by_path, path_copy, st_copy);
470 if (r < 0)
471 return r;
472
473 assert(r > 0);
474 TAKE_PTR(path_copy);
475 TAKE_PTR(st_copy);
476 return 0;
477 }
478
479 static int config_parse_many_files(
480 const char* const* conf_files,
481 char **files,
482 const char *sections,
483 ConfigItemLookup lookup,
484 const void *table,
485 ConfigParseFlags flags,
486 void *userdata,
487 Hashmap **ret_stats_by_path) {
488
489 _cleanup_hashmap_free_ Hashmap *stats_by_path = NULL;
490 struct stat st;
491 int r;
492
493 if (ret_stats_by_path) {
494 stats_by_path = hashmap_new(&path_hash_ops_free_free);
495 if (!stats_by_path)
496 return -ENOMEM;
497 }
498
499 /* First read the first found main config file. */
500 STRV_FOREACH(fn, conf_files) {
501 r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata, &st);
502 if (r < 0)
503 return r;
504 if (r == 0)
505 continue;
506
507 if (ret_stats_by_path) {
508 r = hashmap_put_stats_by_path(&stats_by_path, *fn, &st);
509 if (r < 0)
510 return r;
511 }
512
513 break;
514 }
515
516 /* Then read all the drop-ins. */
517 STRV_FOREACH(fn, files) {
518 r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata, &st);
519 if (r < 0)
520 return r;
521 if (r == 0)
522 continue;
523
524 if (ret_stats_by_path) {
525 r = hashmap_put_stats_by_path(&stats_by_path, *fn, &st);
526 if (r < 0)
527 return r;
528 }
529 }
530
531 if (ret_stats_by_path)
532 *ret_stats_by_path = TAKE_PTR(stats_by_path);
533
534 return 0;
535 }
536
537 /* Parse each config file in the directories specified as nulstr. */
538 int config_parse_many_nulstr(
539 const char *conf_file,
540 const char *conf_file_dirs,
541 const char *sections,
542 ConfigItemLookup lookup,
543 const void *table,
544 ConfigParseFlags flags,
545 void *userdata,
546 Hashmap **ret_stats_by_path) {
547
548 _cleanup_strv_free_ char **files = NULL;
549 int r;
550
551 r = conf_files_list_nulstr(&files, ".conf", NULL, 0, conf_file_dirs);
552 if (r < 0)
553 return r;
554
555 return config_parse_many_files(STRV_MAKE_CONST(conf_file),
556 files, sections, lookup, table, flags, userdata,
557 ret_stats_by_path);
558 }
559
560 static int config_get_dropin_files(
561 const char* const* conf_file_dirs,
562 const char *dropin_dirname,
563 char ***ret) {
564
565 _cleanup_strv_free_ char **dropin_dirs = NULL;
566 const char *suffix;
567 int r;
568
569 assert(conf_file_dirs);
570 assert(dropin_dirname);
571 assert(ret);
572
573 suffix = strjoina("/", dropin_dirname);
574 r = strv_extend_strv_concat(&dropin_dirs, (char**) conf_file_dirs, suffix);
575 if (r < 0)
576 return r;
577
578 return conf_files_list_strv(ret, ".conf", NULL, 0, (const char* const*) dropin_dirs);
579 }
580
581 /* Parse each config file in the directories specified as strv. */
582 int config_parse_many(
583 const char* const* conf_files,
584 const char* const* conf_file_dirs,
585 const char *dropin_dirname,
586 const char *sections,
587 ConfigItemLookup lookup,
588 const void *table,
589 ConfigParseFlags flags,
590 void *userdata,
591 Hashmap **ret_stats_by_path,
592 char ***ret_dropin_files) {
593
594 _cleanup_strv_free_ char **files = NULL;
595 int r;
596
597 assert(conf_file_dirs);
598 assert(dropin_dirname);
599 assert(sections);
600 assert(table);
601
602 r = config_get_dropin_files(conf_file_dirs, dropin_dirname, &files);
603 if (r < 0)
604 return r;
605
606 r = config_parse_many_files(conf_files, files, sections, lookup, table, flags, userdata, ret_stats_by_path);
607 if (r < 0)
608 return r;
609
610 if (ret_dropin_files)
611 *ret_dropin_files = TAKE_PTR(files);
612
613 return 0;
614 }
615
616 static int dropins_get_stats_by_path(
617 const char* conf_file,
618 const char* const* conf_file_dirs,
619 Hashmap **stats_by_path) {
620
621 _cleanup_strv_free_ char **files = NULL;
622 _cleanup_free_ char *dropin_dirname = NULL;
623 int r;
624
625 assert(conf_file);
626 assert(conf_file_dirs);
627 assert(stats_by_path);
628
629 r = path_extract_filename(conf_file, &dropin_dirname);
630 if (r < 0)
631 return r;
632 if (r == O_DIRECTORY)
633 return -EINVAL;
634
635 if (!strextend(&dropin_dirname, ".d"))
636 return -ENOMEM;
637
638 r = config_get_dropin_files(conf_file_dirs, dropin_dirname, &files);
639 if (r < 0)
640 return r;
641
642 STRV_FOREACH(fn, files) {
643 struct stat st;
644
645 if (stat(*fn, &st) < 0) {
646 if (errno == ENOENT)
647 continue;
648
649 return -errno;
650 }
651
652 r = hashmap_put_stats_by_path(stats_by_path, *fn, &st);
653 if (r < 0)
654 return r;
655 }
656
657 return 0;
658 }
659
660 int config_get_stats_by_path(
661 const char *suffix,
662 const char *root,
663 unsigned flags,
664 const char* const* dirs,
665 bool check_dropins,
666 Hashmap **ret) {
667
668 _cleanup_hashmap_free_ Hashmap *stats_by_path = NULL;
669 _cleanup_strv_free_ char **files = NULL;
670 int r;
671
672 assert(suffix);
673 assert(dirs);
674 assert(ret);
675
676 /* Unlike config_parse(), this does not support stream. */
677
678 r = conf_files_list_strv(&files, suffix, root, flags, dirs);
679 if (r < 0)
680 return r;
681
682 STRV_FOREACH(f, files) {
683 struct stat st;
684
685 /* First read the main config file. */
686 if (stat(*f, &st) < 0) {
687 if (errno == ENOENT)
688 continue;
689
690 return -errno;
691 }
692
693 r = hashmap_put_stats_by_path(&stats_by_path, *f, &st);
694 if (r < 0)
695 return r;
696
697 if (!check_dropins)
698 continue;
699
700 /* Then read all the drop-ins if requested. */
701 r = dropins_get_stats_by_path(*f, dirs, &stats_by_path);
702 if (r < 0)
703 return r;
704 }
705
706 *ret = TAKE_PTR(stats_by_path);
707 return 0;
708 }
709
710 bool stats_by_path_equal(Hashmap *a, Hashmap *b) {
711 struct stat *st_a, *st_b;
712 const char *path;
713
714 if (hashmap_size(a) != hashmap_size(b))
715 return false;
716
717 HASHMAP_FOREACH_KEY(st_a, path, a) {
718 st_b = hashmap_get(b, path);
719 if (!st_b)
720 return false;
721
722 if (!stat_inode_unmodified(st_a, st_b))
723 return false;
724 }
725
726 return true;
727 }
728
729 static void config_section_hash_func(const ConfigSection *c, struct siphash *state) {
730 siphash24_compress_string(c->filename, state);
731 siphash24_compress(&c->line, sizeof(c->line), state);
732 }
733
734 static int config_section_compare_func(const ConfigSection *x, const ConfigSection *y) {
735 int r;
736
737 r = strcmp(x->filename, y->filename);
738 if (r != 0)
739 return r;
740
741 return CMP(x->line, y->line);
742 }
743
744 DEFINE_HASH_OPS(config_section_hash_ops, ConfigSection, config_section_hash_func, config_section_compare_func);
745
746 int config_section_new(const char *filename, unsigned line, ConfigSection **s) {
747 ConfigSection *cs;
748
749 cs = malloc0(offsetof(ConfigSection, filename) + strlen(filename) + 1);
750 if (!cs)
751 return -ENOMEM;
752
753 strcpy(cs->filename, filename);
754 cs->line = line;
755
756 *s = TAKE_PTR(cs);
757
758 return 0;
759 }
760
761 unsigned hashmap_find_free_section_line(Hashmap *hashmap) {
762 ConfigSection *cs;
763 unsigned n = 0;
764 void *entry;
765
766 HASHMAP_FOREACH_KEY(entry, cs, hashmap)
767 if (n < cs->line)
768 n = cs->line;
769
770 return n + 1;
771 }
772
773 #define DEFINE_PARSER(type, vartype, conv_func) \
774 DEFINE_CONFIG_PARSE_PTR(config_parse_##type, conv_func, vartype, "Failed to parse " #type " value")
775
776 DEFINE_PARSER(int, int, safe_atoi);
777 DEFINE_PARSER(long, long, safe_atoli);
778 DEFINE_PARSER(uint8, uint8_t, safe_atou8);
779 DEFINE_PARSER(uint16, uint16_t, safe_atou16);
780 DEFINE_PARSER(uint32, uint32_t, safe_atou32);
781 DEFINE_PARSER(int32, int32_t, safe_atoi32);
782 DEFINE_PARSER(uint64, uint64_t, safe_atou64);
783 DEFINE_PARSER(unsigned, unsigned, safe_atou);
784 DEFINE_PARSER(double, double, safe_atod);
785 DEFINE_PARSER(nsec, nsec_t, parse_nsec);
786 DEFINE_PARSER(sec, usec_t, parse_sec);
787 DEFINE_PARSER(sec_def_infinity, usec_t, parse_sec_def_infinity);
788 DEFINE_PARSER(mode, mode_t, parse_mode);
789 DEFINE_PARSER(pid, pid_t, parse_pid);
790
791 int config_parse_iec_size(
792 const char* unit,
793 const char *filename,
794 unsigned line,
795 const char *section,
796 unsigned section_line,
797 const char *lvalue,
798 int ltype,
799 const char *rvalue,
800 void *data,
801 void *userdata) {
802
803 size_t *sz = data;
804 uint64_t v;
805 int r;
806
807 assert(filename);
808 assert(lvalue);
809 assert(rvalue);
810 assert(data);
811
812 r = parse_size(rvalue, 1024, &v);
813 if (r >= 0 && (uint64_t) (size_t) v != v)
814 r = -ERANGE;
815 if (r < 0) {
816 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse size value '%s', ignoring: %m", rvalue);
817 return 0;
818 }
819
820 *sz = (size_t) v;
821 return 0;
822 }
823
824 int config_parse_si_uint64(
825 const char* unit,
826 const char *filename,
827 unsigned line,
828 const char *section,
829 unsigned section_line,
830 const char *lvalue,
831 int ltype,
832 const char *rvalue,
833 void *data,
834 void *userdata) {
835
836 uint64_t *sz = data;
837 int r;
838
839 assert(filename);
840 assert(lvalue);
841 assert(rvalue);
842 assert(data);
843
844 r = parse_size(rvalue, 1000, sz);
845 if (r < 0)
846 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse size value '%s', ignoring: %m", rvalue);
847
848 return 0;
849 }
850
851 int config_parse_iec_uint64(
852 const char* unit,
853 const char *filename,
854 unsigned line,
855 const char *section,
856 unsigned section_line,
857 const char *lvalue,
858 int ltype,
859 const char *rvalue,
860 void *data,
861 void *userdata) {
862
863 uint64_t *bytes = data;
864 int r;
865
866 assert(filename);
867 assert(lvalue);
868 assert(rvalue);
869 assert(data);
870
871 r = parse_size(rvalue, 1024, bytes);
872 if (r < 0)
873 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
874
875 return 0;
876 }
877
878 int config_parse_iec_uint64_infinity(
879 const char* unit,
880 const char *filename,
881 unsigned line,
882 const char *section,
883 unsigned section_line,
884 const char *lvalue,
885 int ltype,
886 const char *rvalue,
887 void *data,
888 void *userdata) {
889
890 uint64_t *bytes = data;
891
892 assert(rvalue);
893 assert(data);
894
895 if (streq(rvalue, "infinity")) {
896 *bytes = UINT64_MAX;
897 return 0;
898 }
899
900 return config_parse_iec_uint64(unit, filename, line, section, section_line, lvalue, ltype, rvalue, data, userdata);
901 }
902
903 int config_parse_bool(
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 int k;
916 bool *b = data;
917 bool fatal = ltype;
918
919 assert(filename);
920 assert(lvalue);
921 assert(rvalue);
922 assert(data);
923
924 k = parse_boolean(rvalue);
925 if (k < 0) {
926 log_syntax(unit, fatal ? LOG_ERR : LOG_WARNING, filename, line, k,
927 "Failed to parse boolean value%s: %s",
928 fatal ? "" : ", ignoring", rvalue);
929 return fatal ? -ENOEXEC : 0;
930 }
931
932 *b = k;
933 return 0;
934 }
935
936 int config_parse_id128(
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 sd_id128_t t, *result = data;
949 int r;
950
951 assert(filename);
952 assert(lvalue);
953 assert(rvalue);
954
955 r = sd_id128_from_string(rvalue, &t);
956 if (r < 0) {
957 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse 128bit ID/UUID, ignoring: %s", rvalue);
958 return 0;
959 }
960
961 if (sd_id128_is_null(t)) {
962 log_syntax(unit, LOG_WARNING, filename, line, 0, "128bit ID/UUID is all 0, ignoring: %s", rvalue);
963 return 0;
964 }
965
966 *result = t;
967 return 0;
968 }
969
970 int config_parse_tristate(
971 const char* unit,
972 const char *filename,
973 unsigned line,
974 const char *section,
975 unsigned section_line,
976 const char *lvalue,
977 int ltype,
978 const char *rvalue,
979 void *data,
980 void *userdata) {
981
982 int k, *t = data;
983
984 assert(filename);
985 assert(lvalue);
986 assert(rvalue);
987 assert(data);
988
989 /* A tristate is pretty much a boolean, except that it can also take an empty string,
990 * indicating "uninitialized", much like NULL is for a pointer type. */
991
992 if (isempty(rvalue)) {
993 *t = -1;
994 return 0;
995 }
996
997 k = parse_boolean(rvalue);
998 if (k < 0) {
999 log_syntax(unit, LOG_WARNING, filename, line, k,
1000 "Failed to parse boolean value for %s=, ignoring: %s", lvalue, rvalue);
1001 return 0;
1002 }
1003
1004 *t = k;
1005 return 0;
1006 }
1007
1008 int config_parse_string(
1009 const char *unit,
1010 const char *filename,
1011 unsigned line,
1012 const char *section,
1013 unsigned section_line,
1014 const char *lvalue,
1015 int ltype,
1016 const char *rvalue,
1017 void *data,
1018 void *userdata) {
1019
1020 char **s = ASSERT_PTR(data);
1021
1022 assert(filename);
1023 assert(lvalue);
1024 assert(rvalue);
1025
1026 if (isempty(rvalue)) {
1027 *s = mfree(*s);
1028 return 0;
1029 }
1030
1031 if (FLAGS_SET(ltype, CONFIG_PARSE_STRING_SAFE) && !string_is_safe(rvalue)) {
1032 _cleanup_free_ char *escaped = NULL;
1033
1034 escaped = cescape(rvalue);
1035 log_syntax(unit, LOG_WARNING, filename, line, 0,
1036 "Specified string contains unsafe characters, ignoring: %s", strna(escaped));
1037 return 0;
1038 }
1039
1040 if (FLAGS_SET(ltype, CONFIG_PARSE_STRING_ASCII) && !ascii_is_valid(rvalue)) {
1041 _cleanup_free_ char *escaped = NULL;
1042
1043 escaped = cescape(rvalue);
1044 log_syntax(unit, LOG_WARNING, filename, line, 0,
1045 "Specified string contains invalid ASCII characters, ignoring: %s", strna(escaped));
1046 return 0;
1047 }
1048
1049 return free_and_strdup_warn(s, empty_to_null(rvalue));
1050 }
1051
1052 int config_parse_dns_name(
1053 const char *unit,
1054 const char *filename,
1055 unsigned line,
1056 const char *section,
1057 unsigned section_line,
1058 const char *lvalue,
1059 int ltype,
1060 const char *rvalue,
1061 void *data,
1062 void *userdata) {
1063
1064 char **hostname = ASSERT_PTR(data);
1065 int r;
1066
1067 assert(filename);
1068 assert(lvalue);
1069 assert(rvalue);
1070
1071 if (isempty(rvalue)) {
1072 *hostname = mfree(*hostname);
1073 return 0;
1074 }
1075
1076 r = dns_name_is_valid(rvalue);
1077 if (r < 0) {
1078 log_syntax(unit, LOG_WARNING, filename, line, r,
1079 "Failed to check validity of DNS domain name '%s', ignoring assignment: %m", rvalue);
1080 return 0;
1081 }
1082 if (r == 0) {
1083 log_syntax(unit, LOG_WARNING, filename, line, 0,
1084 "Specified invalid DNS domain name, ignoring assignment: %s", rvalue);
1085 return 0;
1086 }
1087
1088 return free_and_strdup_warn(hostname, rvalue);
1089 }
1090
1091 int config_parse_hostname(
1092 const char *unit,
1093 const char *filename,
1094 unsigned line,
1095 const char *section,
1096 unsigned section_line,
1097 const char *lvalue,
1098 int ltype,
1099 const char *rvalue,
1100 void *data,
1101 void *userdata) {
1102
1103 char **hostname = ASSERT_PTR(data);
1104
1105 assert(filename);
1106 assert(lvalue);
1107 assert(rvalue);
1108
1109 if (isempty(rvalue)) {
1110 *hostname = mfree(*hostname);
1111 return 0;
1112 }
1113
1114 if (!hostname_is_valid(rvalue, 0)) {
1115 log_syntax(unit, LOG_WARNING, filename, line, 0,
1116 "Specified invalid hostname, ignoring assignment: %s", rvalue);
1117 return 0;
1118 }
1119
1120 return config_parse_dns_name(unit, filename, line, section, section_line,
1121 lvalue, ltype, rvalue, data, userdata);
1122 }
1123
1124 int config_parse_path(
1125 const char *unit,
1126 const char *filename,
1127 unsigned line,
1128 const char *section,
1129 unsigned section_line,
1130 const char *lvalue,
1131 int ltype,
1132 const char *rvalue,
1133 void *data,
1134 void *userdata) {
1135
1136 _cleanup_free_ char *n = NULL;
1137 bool fatal = ltype;
1138 char **s = data;
1139 int r;
1140
1141 assert(filename);
1142 assert(lvalue);
1143 assert(rvalue);
1144 assert(data);
1145
1146 if (isempty(rvalue))
1147 goto finalize;
1148
1149 n = strdup(rvalue);
1150 if (!n)
1151 return log_oom();
1152
1153 r = path_simplify_and_warn(n, PATH_CHECK_ABSOLUTE | (fatal ? PATH_CHECK_FATAL : 0), unit, filename, line, lvalue);
1154 if (r < 0)
1155 return fatal ? -ENOEXEC : 0;
1156
1157 finalize:
1158 return free_and_replace(*s, n);
1159 }
1160
1161 int config_parse_strv(
1162 const char *unit,
1163 const char *filename,
1164 unsigned line,
1165 const char *section,
1166 unsigned section_line,
1167 const char *lvalue,
1168 int ltype,
1169 const char *rvalue,
1170 void *data,
1171 void *userdata) {
1172
1173 char ***sv = data;
1174 int r;
1175
1176 assert(filename);
1177 assert(lvalue);
1178 assert(rvalue);
1179 assert(data);
1180
1181 if (isempty(rvalue)) {
1182 *sv = strv_free(*sv);
1183 return 0;
1184 }
1185
1186 for (const char *p = rvalue;;) {
1187 char *word = NULL;
1188
1189 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
1190 if (r == 0)
1191 return 0;
1192 if (r == -ENOMEM)
1193 return log_oom();
1194 if (r < 0) {
1195 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
1196 return 0;
1197 }
1198
1199 r = strv_consume(sv, word);
1200 if (r < 0)
1201 return log_oom();
1202 }
1203 }
1204
1205 int config_parse_warn_compat(
1206 const char *unit,
1207 const char *filename,
1208 unsigned line,
1209 const char *section,
1210 unsigned section_line,
1211 const char *lvalue,
1212 int ltype,
1213 const char *rvalue,
1214 void *data,
1215 void *userdata) {
1216
1217 Disabled reason = ltype;
1218
1219 switch (reason) {
1220
1221 case DISABLED_CONFIGURATION:
1222 log_syntax(unit, LOG_DEBUG, filename, line, 0,
1223 "Support for option %s= has been disabled at compile time and it is ignored", lvalue);
1224 break;
1225
1226 case DISABLED_LEGACY:
1227 log_syntax(unit, LOG_INFO, filename, line, 0,
1228 "Support for option %s= has been removed and it is ignored", lvalue);
1229 break;
1230
1231 case DISABLED_EXPERIMENTAL:
1232 log_syntax(unit, LOG_INFO, filename, line, 0,
1233 "Support for option %s= has not yet been enabled and it is ignored", lvalue);
1234 break;
1235 }
1236
1237 return 0;
1238 }
1239
1240 int config_parse_log_facility(
1241 const char *unit,
1242 const char *filename,
1243 unsigned line,
1244 const char *section,
1245 unsigned section_line,
1246 const char *lvalue,
1247 int ltype,
1248 const char *rvalue,
1249 void *data,
1250 void *userdata) {
1251
1252 int *o = data, x;
1253
1254 assert(filename);
1255 assert(lvalue);
1256 assert(rvalue);
1257 assert(data);
1258
1259 x = log_facility_unshifted_from_string(rvalue);
1260 if (x < 0) {
1261 log_syntax(unit, LOG_WARNING, filename, line, x, "Failed to parse log facility, ignoring: %s", rvalue);
1262 return 0;
1263 }
1264
1265 *o = (x << 3) | LOG_PRI(*o);
1266
1267 return 0;
1268 }
1269
1270 int config_parse_log_level(
1271 const char *unit,
1272 const char *filename,
1273 unsigned line,
1274 const char *section,
1275 unsigned section_line,
1276 const char *lvalue,
1277 int ltype,
1278 const char *rvalue,
1279 void *data,
1280 void *userdata) {
1281
1282 int *o = data, x;
1283
1284 assert(filename);
1285 assert(lvalue);
1286 assert(rvalue);
1287 assert(data);
1288
1289 x = log_level_from_string(rvalue);
1290 if (x < 0) {
1291 log_syntax(unit, LOG_WARNING, filename, line, x, "Failed to parse log level, ignoring: %s", rvalue);
1292 return 0;
1293 }
1294
1295 if (*o < 0) /* if it wasn't initialized so far, assume zero facility */
1296 *o = x;
1297 else
1298 *o = (*o & LOG_FACMASK) | x;
1299
1300 return 0;
1301 }
1302
1303 int config_parse_signal(
1304 const char *unit,
1305 const char *filename,
1306 unsigned line,
1307 const char *section,
1308 unsigned section_line,
1309 const char *lvalue,
1310 int ltype,
1311 const char *rvalue,
1312 void *data,
1313 void *userdata) {
1314
1315 int *sig = data, r;
1316
1317 assert(filename);
1318 assert(lvalue);
1319 assert(rvalue);
1320 assert(sig);
1321
1322 r = signal_from_string(rvalue);
1323 if (r <= 0) {
1324 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse signal name, ignoring: %s", rvalue);
1325 return 0;
1326 }
1327
1328 *sig = r;
1329 return 0;
1330 }
1331
1332 int config_parse_personality(
1333 const char *unit,
1334 const char *filename,
1335 unsigned line,
1336 const char *section,
1337 unsigned section_line,
1338 const char *lvalue,
1339 int ltype,
1340 const char *rvalue,
1341 void *data,
1342 void *userdata) {
1343
1344 unsigned long *personality = data, p;
1345
1346 assert(filename);
1347 assert(lvalue);
1348 assert(rvalue);
1349 assert(personality);
1350
1351 if (isempty(rvalue))
1352 p = PERSONALITY_INVALID;
1353 else {
1354 p = personality_from_string(rvalue);
1355 if (p == PERSONALITY_INVALID) {
1356 log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse personality, ignoring: %s", rvalue);
1357 return 0;
1358 }
1359 }
1360
1361 *personality = p;
1362 return 0;
1363 }
1364
1365 int config_parse_ifname(
1366 const char *unit,
1367 const char *filename,
1368 unsigned line,
1369 const char *section,
1370 unsigned section_line,
1371 const char *lvalue,
1372 int ltype,
1373 const char *rvalue,
1374 void *data,
1375 void *userdata) {
1376
1377 char **s = data;
1378 int r;
1379
1380 assert(filename);
1381 assert(lvalue);
1382 assert(rvalue);
1383 assert(data);
1384
1385 if (isempty(rvalue)) {
1386 *s = mfree(*s);
1387 return 0;
1388 }
1389
1390 if (!ifname_valid(rvalue)) {
1391 log_syntax(unit, LOG_WARNING, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue);
1392 return 0;
1393 }
1394
1395 r = free_and_strdup(s, rvalue);
1396 if (r < 0)
1397 return log_oom();
1398
1399 return 0;
1400 }
1401
1402 int config_parse_ifnames(
1403 const char *unit,
1404 const char *filename,
1405 unsigned line,
1406 const char *section,
1407 unsigned section_line,
1408 const char *lvalue,
1409 int ltype,
1410 const char *rvalue,
1411 void *data,
1412 void *userdata) {
1413
1414 _cleanup_strv_free_ char **names = NULL;
1415 char ***s = data;
1416 int r;
1417
1418 assert(filename);
1419 assert(lvalue);
1420 assert(rvalue);
1421 assert(data);
1422
1423 if (isempty(rvalue)) {
1424 *s = strv_free(*s);
1425 return 0;
1426 }
1427
1428 for (const char *p = rvalue;;) {
1429 _cleanup_free_ char *word = NULL;
1430
1431 r = extract_first_word(&p, &word, NULL, 0);
1432 if (r == -ENOMEM)
1433 return log_oom();
1434 if (r < 0) {
1435 log_syntax(unit, LOG_WARNING, filename, line, r,
1436 "Failed to extract interface name, ignoring assignment: %s",
1437 rvalue);
1438 return 0;
1439 }
1440 if (r == 0)
1441 break;
1442
1443 if (!ifname_valid_full(word, ltype)) {
1444 log_syntax(unit, LOG_WARNING, filename, line, 0,
1445 "Interface name is not valid or too long, ignoring assignment: %s",
1446 word);
1447 continue;
1448 }
1449
1450 r = strv_consume(&names, TAKE_PTR(word));
1451 if (r < 0)
1452 return log_oom();
1453 }
1454
1455 r = strv_extend_strv(s, names, true);
1456 if (r < 0)
1457 return log_oom();
1458
1459 return 0;
1460 }
1461
1462 int config_parse_ip_port(
1463 const char *unit,
1464 const char *filename,
1465 unsigned line,
1466 const char *section,
1467 unsigned section_line,
1468 const char *lvalue,
1469 int ltype,
1470 const char *rvalue,
1471 void *data,
1472 void *userdata) {
1473
1474 uint16_t *s = data;
1475 uint16_t port;
1476 int r;
1477
1478 assert(filename);
1479 assert(lvalue);
1480 assert(rvalue);
1481 assert(data);
1482
1483 if (isempty(rvalue)) {
1484 *s = 0;
1485 return 0;
1486 }
1487
1488 r = parse_ip_port(rvalue, &port);
1489 if (r < 0) {
1490 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse port '%s'.", rvalue);
1491 return 0;
1492 }
1493
1494 *s = port;
1495
1496 return 0;
1497 }
1498
1499 int config_parse_mtu(
1500 const char *unit,
1501 const char *filename,
1502 unsigned line,
1503 const char *section,
1504 unsigned section_line,
1505 const char *lvalue,
1506 int ltype,
1507 const char *rvalue,
1508 void *data,
1509 void *userdata) {
1510
1511 uint32_t *mtu = data;
1512 int r;
1513
1514 assert(rvalue);
1515 assert(mtu);
1516
1517 r = parse_mtu(ltype, rvalue, mtu);
1518 if (r == -ERANGE) {
1519 log_syntax(unit, LOG_WARNING, filename, line, r,
1520 "Maximum transfer unit (MTU) value out of range. Permitted range is %" PRIu32 "…%" PRIu32 ", ignoring: %s",
1521 (uint32_t) (ltype == AF_INET6 ? IPV6_MIN_MTU : IPV4_MIN_MTU), (uint32_t) UINT32_MAX,
1522 rvalue);
1523 return 0;
1524 }
1525 if (r < 0) {
1526 log_syntax(unit, LOG_WARNING, filename, line, r,
1527 "Failed to parse MTU value '%s', ignoring: %m", rvalue);
1528 return 0;
1529 }
1530
1531 return 0;
1532 }
1533
1534 int config_parse_rlimit(
1535 const char *unit,
1536 const char *filename,
1537 unsigned line,
1538 const char *section,
1539 unsigned section_line,
1540 const char *lvalue,
1541 int ltype,
1542 const char *rvalue,
1543 void *data,
1544 void *userdata) {
1545
1546 struct rlimit **rl = data, d = {};
1547 int r;
1548
1549 assert(rvalue);
1550 assert(rl);
1551
1552 r = rlimit_parse(ltype, rvalue, &d);
1553 if (r == -EILSEQ) {
1554 log_syntax(unit, LOG_WARNING, filename, line, r, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue);
1555 return 0;
1556 }
1557 if (r < 0) {
1558 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
1559 return 0;
1560 }
1561
1562 if (rl[ltype])
1563 *rl[ltype] = d;
1564 else {
1565 rl[ltype] = newdup(struct rlimit, &d, 1);
1566 if (!rl[ltype])
1567 return log_oom();
1568 }
1569
1570 return 0;
1571 }
1572
1573 int config_parse_permille(
1574 const char* unit,
1575 const char *filename,
1576 unsigned line,
1577 const char *section,
1578 unsigned section_line,
1579 const char *lvalue,
1580 int ltype,
1581 const char *rvalue,
1582 void *data,
1583 void *userdata) {
1584
1585 unsigned *permille = data;
1586 int r;
1587
1588 assert(filename);
1589 assert(lvalue);
1590 assert(rvalue);
1591 assert(permille);
1592
1593 r = parse_permille(rvalue);
1594 if (r < 0) {
1595 log_syntax(unit, LOG_WARNING, filename, line, r,
1596 "Failed to parse permille value, ignoring: %s", rvalue);
1597 return 0;
1598 }
1599
1600 *permille = (unsigned) r;
1601
1602 return 0;
1603 }
1604
1605 int config_parse_vlanprotocol(
1606 const char* unit,
1607 const char *filename,
1608 unsigned line,
1609 const char *section,
1610 unsigned section_line,
1611 const char *lvalue,
1612 int ltype,
1613 const char *rvalue,
1614 void *data,
1615 void *userdata) {
1616
1617 int *vlan_protocol = data;
1618
1619 assert(filename);
1620 assert(lvalue);
1621
1622 if (isempty(rvalue)) {
1623 *vlan_protocol = -1;
1624 return 0;
1625 }
1626
1627 if (STR_IN_SET(rvalue, "802.1ad", "802.1AD"))
1628 *vlan_protocol = ETH_P_8021AD;
1629 else if (STR_IN_SET(rvalue, "802.1q", "802.1Q"))
1630 *vlan_protocol = ETH_P_8021Q;
1631 else {
1632 log_syntax(unit, LOG_WARNING, filename, line, 0,
1633 "Failed to parse VLAN protocol value, ignoring: %s", rvalue);
1634 return 0;
1635 }
1636
1637 return 0;
1638 }
1639
1640 int config_parse_hw_addr(
1641 const char *unit,
1642 const char *filename,
1643 unsigned line,
1644 const char *section,
1645 unsigned section_line,
1646 const char *lvalue,
1647 int ltype,
1648 const char *rvalue,
1649 void *data,
1650 void *userdata) {
1651
1652 struct hw_addr_data a, *hwaddr = data;
1653 int r;
1654
1655 assert(filename);
1656 assert(lvalue);
1657 assert(rvalue);
1658 assert(data);
1659
1660 if (isempty(rvalue)) {
1661 *hwaddr = HW_ADDR_NULL;
1662 return 0;
1663 }
1664
1665 r = parse_hw_addr_full(rvalue, ltype, &a);
1666 if (r < 0) {
1667 log_syntax(unit, LOG_WARNING, filename, line, r,
1668 "Not a valid hardware address, ignoring assignment: %s", rvalue);
1669 return 0;
1670 }
1671
1672 *hwaddr = a;
1673 return 0;
1674 }
1675
1676 int config_parse_hw_addrs(
1677 const char *unit,
1678 const char *filename,
1679 unsigned line,
1680 const char *section,
1681 unsigned section_line,
1682 const char *lvalue,
1683 int ltype,
1684 const char *rvalue,
1685 void *data,
1686 void *userdata) {
1687
1688 Set **hwaddrs = data;
1689 int r;
1690
1691 assert(filename);
1692 assert(lvalue);
1693 assert(rvalue);
1694 assert(data);
1695
1696 if (isempty(rvalue)) {
1697 /* Empty assignment resets the list */
1698 *hwaddrs = set_free(*hwaddrs);
1699 return 0;
1700 }
1701
1702 for (const char *p = rvalue;;) {
1703 _cleanup_free_ char *word = NULL;
1704 _cleanup_free_ struct hw_addr_data *n = NULL;
1705
1706 r = extract_first_word(&p, &word, NULL, 0);
1707 if (r == 0)
1708 return 0;
1709 if (r == -ENOMEM)
1710 return log_oom();
1711 if (r < 0) {
1712 log_syntax(unit, LOG_WARNING, filename, line, r,
1713 "Invalid syntax, ignoring: %s", rvalue);
1714 return 0;
1715 }
1716
1717 n = new(struct hw_addr_data, 1);
1718 if (!n)
1719 return log_oom();
1720
1721 r = parse_hw_addr_full(word, ltype, n);
1722 if (r < 0) {
1723 log_syntax(unit, LOG_WARNING, filename, line, r,
1724 "Not a valid hardware address, ignoring: %s", word);
1725 continue;
1726 }
1727
1728 r = set_ensure_consume(hwaddrs, &hw_addr_hash_ops_free, TAKE_PTR(n));
1729 if (r < 0)
1730 return log_oom();
1731 }
1732 }
1733
1734 int config_parse_ether_addr(
1735 const char *unit,
1736 const char *filename,
1737 unsigned line,
1738 const char *section,
1739 unsigned section_line,
1740 const char *lvalue,
1741 int ltype,
1742 const char *rvalue,
1743 void *data,
1744 void *userdata) {
1745
1746 _cleanup_free_ struct ether_addr *n = NULL;
1747 struct ether_addr **hwaddr = data;
1748 int r;
1749
1750 assert(filename);
1751 assert(lvalue);
1752 assert(rvalue);
1753 assert(data);
1754
1755 if (isempty(rvalue)) {
1756 *hwaddr = mfree(*hwaddr);
1757 return 0;
1758 }
1759
1760 n = new0(struct ether_addr, 1);
1761 if (!n)
1762 return log_oom();
1763
1764 r = parse_ether_addr(rvalue, n);
1765 if (r < 0) {
1766 log_syntax(unit, LOG_WARNING, filename, line, r,
1767 "Not a valid MAC address, ignoring assignment: %s", rvalue);
1768 return 0;
1769 }
1770
1771 free_and_replace(*hwaddr, n);
1772
1773 return 0;
1774 }
1775
1776 int config_parse_ether_addrs(
1777 const char *unit,
1778 const char *filename,
1779 unsigned line,
1780 const char *section,
1781 unsigned section_line,
1782 const char *lvalue,
1783 int ltype,
1784 const char *rvalue,
1785 void *data,
1786 void *userdata) {
1787
1788 Set **hwaddrs = data;
1789 int r;
1790
1791 assert(filename);
1792 assert(lvalue);
1793 assert(rvalue);
1794 assert(data);
1795
1796 if (isempty(rvalue)) {
1797 /* Empty assignment resets the list */
1798 *hwaddrs = set_free(*hwaddrs);
1799 return 0;
1800 }
1801
1802 for (const char *p = rvalue;;) {
1803 _cleanup_free_ char *word = NULL;
1804 _cleanup_free_ struct ether_addr *n = NULL;
1805
1806 r = extract_first_word(&p, &word, NULL, 0);
1807 if (r == 0)
1808 return 0;
1809 if (r == -ENOMEM)
1810 return log_oom();
1811 if (r < 0) {
1812 log_syntax(unit, LOG_WARNING, filename, line, r,
1813 "Invalid syntax, ignoring: %s", rvalue);
1814 return 0;
1815 }
1816
1817 n = new(struct ether_addr, 1);
1818 if (!n)
1819 return log_oom();
1820
1821 r = parse_ether_addr(word, n);
1822 if (r < 0) {
1823 log_syntax(unit, LOG_WARNING, filename, line, r,
1824 "Not a valid MAC address, ignoring: %s", word);
1825 continue;
1826 }
1827
1828 r = set_ensure_consume(hwaddrs, &ether_addr_hash_ops_free, TAKE_PTR(n));
1829 if (r < 0)
1830 return log_oom();
1831 }
1832 }
1833
1834 int config_parse_in_addr_non_null(
1835 const char *unit,
1836 const char *filename,
1837 unsigned line,
1838 const char *section,
1839 unsigned section_line,
1840 const char *lvalue,
1841 int ltype,
1842 const char *rvalue,
1843 void *data,
1844 void *userdata) {
1845
1846 /* data must be a pointer to struct in_addr or in6_addr, and the type is determined by ltype. */
1847 struct in_addr *ipv4 = data;
1848 struct in6_addr *ipv6 = data;
1849 union in_addr_union a;
1850 int r;
1851
1852 assert(filename);
1853 assert(lvalue);
1854 assert(rvalue);
1855 assert(data);
1856 assert(IN_SET(ltype, AF_INET, AF_INET6));
1857
1858 if (isempty(rvalue)) {
1859 if (ltype == AF_INET)
1860 *ipv4 = (struct in_addr) {};
1861 else
1862 *ipv6 = (struct in6_addr) {};
1863 return 0;
1864 }
1865
1866 r = in_addr_from_string(ltype, rvalue, &a);
1867 if (r < 0) {
1868 log_syntax(unit, LOG_WARNING, filename, line, r,
1869 "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
1870 return 0;
1871 }
1872
1873 if (!in_addr_is_set(ltype, &a)) {
1874 log_syntax(unit, LOG_WARNING, filename, line, 0,
1875 "%s= cannot be the ANY address, ignoring: %s", lvalue, rvalue);
1876 return 0;
1877 }
1878
1879 if (ltype == AF_INET)
1880 *ipv4 = a.in;
1881 else
1882 *ipv6 = a.in6;
1883 return 0;
1884 }
1885
1886 DEFINE_CONFIG_PARSE(config_parse_percent, parse_percent, "Failed to parse percent value");
1887 DEFINE_CONFIG_PARSE(config_parse_permyriad, parse_permyriad, "Failed to parse permyriad value");