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
config_item_table_lookup(const void * table,const char * section,const char * lvalue,ConfigParserCallback * ret_func,int * ret_ltype,void ** ret_data,void * userdata)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
config_item_perf_lookup(const void * table,const char * section,const char * lvalue,ConfigParserCallback * ret_func,int * ret_ltype,void ** ret_data,void * userdata)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 */
next_assignment(const char * unit,const char * filename,unsigned line,ConfigItemLookup lookup,const void * table,const char * section,unsigned section_line,const char * lvalue,const char * rvalue,ConfigParseFlags flags,void * userdata)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, <ype, &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 */
parse_line(const char * unit,const char * filename,unsigned line,const char * sections,ConfigItemLookup lookup,const void * table,ConfigParseFlags flags,char ** section,unsigned * section_line,bool * section_ignored,char * l,void * userdata)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 */
config_parse(const char * unit,const char * filename,FILE * f,const char * sections,ConfigItemLookup lookup,const void * table,ConfigParseFlags flags,void * userdata,struct stat * ret_stat)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 §ion,
409 §ion_line,
410 §ion_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 §ion,
431 §ion_line,
432 §ion_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
hashmap_put_stats_by_path(Hashmap ** stats_by_path,const char * path,const struct stat * st)448 static 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
config_parse_many_files(const char * const * conf_files,char ** files,const char * sections,ConfigItemLookup lookup,const void * table,ConfigParseFlags flags,void * userdata,Hashmap ** ret_stats_by_path)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. */
config_parse_many_nulstr(const char * conf_file,const char * conf_file_dirs,const char * sections,ConfigItemLookup lookup,const void * table,ConfigParseFlags flags,void * userdata,Hashmap ** ret_stats_by_path)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
config_get_dropin_files(const char * const * conf_file_dirs,const char * dropin_dirname,char *** ret)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. */
config_parse_many(const char * const * conf_files,const char * const * conf_file_dirs,const char * dropin_dirname,const char * sections,ConfigItemLookup lookup,const void * table,ConfigParseFlags flags,void * userdata,Hashmap ** ret_stats_by_path)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
593 _cleanup_strv_free_ char **files = NULL;
594 int r;
595
596 assert(conf_file_dirs);
597 assert(dropin_dirname);
598 assert(sections);
599 assert(table);
600
601 r = config_get_dropin_files(conf_file_dirs, dropin_dirname, &files);
602 if (r < 0)
603 return r;
604
605 return config_parse_many_files(conf_files, files, sections, lookup, table, flags, userdata, ret_stats_by_path);
606 }
607
config_get_stats_by_path_one(const char * conf_file,const char * const * conf_file_dirs,Hashmap * stats_by_path)608 static int config_get_stats_by_path_one(
609 const char* conf_file,
610 const char* const* conf_file_dirs,
611 Hashmap *stats_by_path) {
612
613 _cleanup_strv_free_ char **files = NULL;
614 _cleanup_free_ char *dropin_dirname = NULL;
615 struct stat st;
616 int r;
617
618 assert(conf_file);
619 assert(conf_file_dirs);
620 assert(stats_by_path);
621
622 /* Unlike config_parse(), this does not support stream. */
623
624 r = path_extract_filename(conf_file, &dropin_dirname);
625 if (r < 0)
626 return r;
627 if (r == O_DIRECTORY)
628 return -EINVAL;
629
630 if (!strextend(&dropin_dirname, ".d"))
631 return -ENOMEM;
632
633 r = config_get_dropin_files(conf_file_dirs, dropin_dirname, &files);
634 if (r < 0)
635 return r;
636
637 /* First read the main config file. */
638 r = RET_NERRNO(stat(conf_file, &st));
639 if (r >= 0) {
640 r = hashmap_put_stats_by_path(&stats_by_path, conf_file, &st);
641 if (r < 0)
642 return r;
643 } else if (r != -ENOENT)
644 return r;
645
646 /* Then read all the drop-ins. */
647 STRV_FOREACH(fn, files) {
648 if (stat(*fn, &st) < 0) {
649 if (errno == ENOENT)
650 continue;
651
652 return -errno;
653 }
654
655 r = hashmap_put_stats_by_path(&stats_by_path, *fn, &st);
656 if (r < 0)
657 return r;
658 }
659
660 return 0;
661 }
662
config_get_stats_by_path(const char * suffix,const char * root,unsigned flags,const char * const * dirs,Hashmap ** ret)663 int config_get_stats_by_path(
664 const char *suffix,
665 const char *root,
666 unsigned flags,
667 const char* const* dirs,
668 Hashmap **ret) {
669
670 _cleanup_hashmap_free_ Hashmap *stats_by_path = NULL;
671 _cleanup_strv_free_ char **files = NULL;
672 int r;
673
674 assert(suffix);
675 assert(dirs);
676 assert(ret);
677
678 r = conf_files_list_strv(&files, suffix, root, flags, dirs);
679 if (r < 0)
680 return r;
681
682 stats_by_path = hashmap_new(&path_hash_ops_free_free);
683 if (!stats_by_path)
684 return -ENOMEM;
685
686 STRV_FOREACH(f, files) {
687 r = config_get_stats_by_path_one(*f, dirs, stats_by_path);
688 if (r < 0)
689 return r;
690 }
691
692 *ret = TAKE_PTR(stats_by_path);
693 return 0;
694 }
695
stats_by_path_equal(Hashmap * a,Hashmap * b)696 bool stats_by_path_equal(Hashmap *a, Hashmap *b) {
697 struct stat *st_a, *st_b;
698 const char *path;
699
700 if (hashmap_size(a) != hashmap_size(b))
701 return false;
702
703 HASHMAP_FOREACH_KEY(st_a, path, a) {
704 st_b = hashmap_get(b, path);
705 if (!st_b)
706 return false;
707
708 if (!stat_inode_unmodified(st_a, st_b))
709 return false;
710 }
711
712 return true;
713 }
714
config_section_hash_func(const ConfigSection * c,struct siphash * state)715 static void config_section_hash_func(const ConfigSection *c, struct siphash *state) {
716 siphash24_compress_string(c->filename, state);
717 siphash24_compress(&c->line, sizeof(c->line), state);
718 }
719
config_section_compare_func(const ConfigSection * x,const ConfigSection * y)720 static int config_section_compare_func(const ConfigSection *x, const ConfigSection *y) {
721 int r;
722
723 r = strcmp(x->filename, y->filename);
724 if (r != 0)
725 return r;
726
727 return CMP(x->line, y->line);
728 }
729
730 DEFINE_HASH_OPS(config_section_hash_ops, ConfigSection, config_section_hash_func, config_section_compare_func);
731
config_section_new(const char * filename,unsigned line,ConfigSection ** s)732 int config_section_new(const char *filename, unsigned line, ConfigSection **s) {
733 ConfigSection *cs;
734
735 cs = malloc0(offsetof(ConfigSection, filename) + strlen(filename) + 1);
736 if (!cs)
737 return -ENOMEM;
738
739 strcpy(cs->filename, filename);
740 cs->line = line;
741
742 *s = TAKE_PTR(cs);
743
744 return 0;
745 }
746
hashmap_find_free_section_line(Hashmap * hashmap)747 unsigned hashmap_find_free_section_line(Hashmap *hashmap) {
748 ConfigSection *cs;
749 unsigned n = 0;
750 void *entry;
751
752 HASHMAP_FOREACH_KEY(entry, cs, hashmap)
753 if (n < cs->line)
754 n = cs->line;
755
756 return n + 1;
757 }
758
759 #define DEFINE_PARSER(type, vartype, conv_func) \
760 DEFINE_CONFIG_PARSE_PTR(config_parse_##type, conv_func, vartype, "Failed to parse " #type " value")
761
762 DEFINE_PARSER(int, int, safe_atoi);
763 DEFINE_PARSER(long, long, safe_atoli);
764 DEFINE_PARSER(uint8, uint8_t, safe_atou8);
765 DEFINE_PARSER(uint16, uint16_t, safe_atou16);
766 DEFINE_PARSER(uint32, uint32_t, safe_atou32);
767 DEFINE_PARSER(int32, int32_t, safe_atoi32);
768 DEFINE_PARSER(uint64, uint64_t, safe_atou64);
769 DEFINE_PARSER(unsigned, unsigned, safe_atou);
770 DEFINE_PARSER(double, double, safe_atod);
771 DEFINE_PARSER(nsec, nsec_t, parse_nsec);
772 DEFINE_PARSER(sec, usec_t, parse_sec);
773 DEFINE_PARSER(sec_def_infinity, usec_t, parse_sec_def_infinity);
774 DEFINE_PARSER(mode, mode_t, parse_mode);
775 DEFINE_PARSER(pid, pid_t, parse_pid);
776
config_parse_iec_size(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)777 int config_parse_iec_size(
778 const char* unit,
779 const char *filename,
780 unsigned line,
781 const char *section,
782 unsigned section_line,
783 const char *lvalue,
784 int ltype,
785 const char *rvalue,
786 void *data,
787 void *userdata) {
788
789 size_t *sz = data;
790 uint64_t v;
791 int r;
792
793 assert(filename);
794 assert(lvalue);
795 assert(rvalue);
796 assert(data);
797
798 r = parse_size(rvalue, 1024, &v);
799 if (r >= 0 && (uint64_t) (size_t) v != v)
800 r = -ERANGE;
801 if (r < 0) {
802 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse size value '%s', ignoring: %m", rvalue);
803 return 0;
804 }
805
806 *sz = (size_t) v;
807 return 0;
808 }
809
config_parse_si_uint64(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)810 int config_parse_si_uint64(
811 const char* unit,
812 const char *filename,
813 unsigned line,
814 const char *section,
815 unsigned section_line,
816 const char *lvalue,
817 int ltype,
818 const char *rvalue,
819 void *data,
820 void *userdata) {
821
822 uint64_t *sz = data;
823 int r;
824
825 assert(filename);
826 assert(lvalue);
827 assert(rvalue);
828 assert(data);
829
830 r = parse_size(rvalue, 1000, sz);
831 if (r < 0)
832 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse size value '%s', ignoring: %m", rvalue);
833
834 return 0;
835 }
836
config_parse_iec_uint64(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)837 int config_parse_iec_uint64(
838 const char* unit,
839 const char *filename,
840 unsigned line,
841 const char *section,
842 unsigned section_line,
843 const char *lvalue,
844 int ltype,
845 const char *rvalue,
846 void *data,
847 void *userdata) {
848
849 uint64_t *bytes = data;
850 int r;
851
852 assert(filename);
853 assert(lvalue);
854 assert(rvalue);
855 assert(data);
856
857 r = parse_size(rvalue, 1024, bytes);
858 if (r < 0)
859 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
860
861 return 0;
862 }
863
config_parse_iec_uint64_infinity(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)864 int config_parse_iec_uint64_infinity(
865 const char* unit,
866 const char *filename,
867 unsigned line,
868 const char *section,
869 unsigned section_line,
870 const char *lvalue,
871 int ltype,
872 const char *rvalue,
873 void *data,
874 void *userdata) {
875
876 uint64_t *bytes = data;
877
878 assert(rvalue);
879 assert(data);
880
881 if (streq(rvalue, "infinity")) {
882 *bytes = UINT64_MAX;
883 return 0;
884 }
885
886 return config_parse_iec_uint64(unit, filename, line, section, section_line, lvalue, ltype, rvalue, data, userdata);
887 }
888
config_parse_bool(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)889 int config_parse_bool(
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 k;
902 bool *b = data;
903 bool fatal = ltype;
904
905 assert(filename);
906 assert(lvalue);
907 assert(rvalue);
908 assert(data);
909
910 k = parse_boolean(rvalue);
911 if (k < 0) {
912 log_syntax(unit, fatal ? LOG_ERR : LOG_WARNING, filename, line, k,
913 "Failed to parse boolean value%s: %s",
914 fatal ? "" : ", ignoring", rvalue);
915 return fatal ? -ENOEXEC : 0;
916 }
917
918 *b = k;
919 return 0;
920 }
921
config_parse_id128(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)922 int config_parse_id128(
923 const char *unit,
924 const char *filename,
925 unsigned line,
926 const char *section,
927 unsigned section_line,
928 const char *lvalue,
929 int ltype,
930 const char *rvalue,
931 void *data,
932 void *userdata) {
933
934 sd_id128_t t, *result = data;
935 int r;
936
937 assert(filename);
938 assert(lvalue);
939 assert(rvalue);
940
941 r = sd_id128_from_string(rvalue, &t);
942 if (r < 0) {
943 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse 128bit ID/UUID, ignoring: %s", rvalue);
944 return 0;
945 }
946
947 if (sd_id128_is_null(t)) {
948 log_syntax(unit, LOG_WARNING, filename, line, 0, "128bit ID/UUID is all 0, ignoring: %s", rvalue);
949 return 0;
950 }
951
952 *result = t;
953 return 0;
954 }
955
config_parse_tristate(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)956 int config_parse_tristate(
957 const char* unit,
958 const char *filename,
959 unsigned line,
960 const char *section,
961 unsigned section_line,
962 const char *lvalue,
963 int ltype,
964 const char *rvalue,
965 void *data,
966 void *userdata) {
967
968 int k, *t = data;
969
970 assert(filename);
971 assert(lvalue);
972 assert(rvalue);
973 assert(data);
974
975 /* A tristate is pretty much a boolean, except that it can also take an empty string,
976 * indicating "uninitialized", much like NULL is for a pointer type. */
977
978 if (isempty(rvalue)) {
979 *t = -1;
980 return 0;
981 }
982
983 k = parse_boolean(rvalue);
984 if (k < 0) {
985 log_syntax(unit, LOG_WARNING, filename, line, k,
986 "Failed to parse boolean value for %s=, ignoring: %s", lvalue, rvalue);
987 return 0;
988 }
989
990 *t = k;
991 return 0;
992 }
993
config_parse_string(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)994 int config_parse_string(
995 const char *unit,
996 const char *filename,
997 unsigned line,
998 const char *section,
999 unsigned section_line,
1000 const char *lvalue,
1001 int ltype,
1002 const char *rvalue,
1003 void *data,
1004 void *userdata) {
1005
1006 char **s = ASSERT_PTR(data);
1007
1008 assert(filename);
1009 assert(lvalue);
1010 assert(rvalue);
1011
1012 if (isempty(rvalue)) {
1013 *s = mfree(*s);
1014 return 0;
1015 }
1016
1017 if (FLAGS_SET(ltype, CONFIG_PARSE_STRING_SAFE) && !string_is_safe(rvalue)) {
1018 _cleanup_free_ char *escaped = NULL;
1019
1020 escaped = cescape(rvalue);
1021 log_syntax(unit, LOG_WARNING, filename, line, 0,
1022 "Specified string contains unsafe characters, ignoring: %s", strna(escaped));
1023 return 0;
1024 }
1025
1026 if (FLAGS_SET(ltype, CONFIG_PARSE_STRING_ASCII) && !ascii_is_valid(rvalue)) {
1027 _cleanup_free_ char *escaped = NULL;
1028
1029 escaped = cescape(rvalue);
1030 log_syntax(unit, LOG_WARNING, filename, line, 0,
1031 "Specified string contains invalid ASCII characters, ignoring: %s", strna(escaped));
1032 return 0;
1033 }
1034
1035 return free_and_strdup_warn(s, empty_to_null(rvalue));
1036 }
1037
config_parse_dns_name(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1038 int config_parse_dns_name(
1039 const char *unit,
1040 const char *filename,
1041 unsigned line,
1042 const char *section,
1043 unsigned section_line,
1044 const char *lvalue,
1045 int ltype,
1046 const char *rvalue,
1047 void *data,
1048 void *userdata) {
1049
1050 char **hostname = ASSERT_PTR(data);
1051 int r;
1052
1053 assert(filename);
1054 assert(lvalue);
1055 assert(rvalue);
1056
1057 if (isempty(rvalue)) {
1058 *hostname = mfree(*hostname);
1059 return 0;
1060 }
1061
1062 r = dns_name_is_valid(rvalue);
1063 if (r < 0) {
1064 log_syntax(unit, LOG_WARNING, filename, line, r,
1065 "Failed to check validity of DNS domain name '%s', ignoring assignment: %m", rvalue);
1066 return 0;
1067 }
1068 if (r == 0) {
1069 log_syntax(unit, LOG_WARNING, filename, line, 0,
1070 "Specified invalid DNS domain name, ignoring assignment: %s", rvalue);
1071 return 0;
1072 }
1073
1074 return free_and_strdup_warn(hostname, rvalue);
1075 }
1076
config_parse_hostname(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1077 int config_parse_hostname(
1078 const char *unit,
1079 const char *filename,
1080 unsigned line,
1081 const char *section,
1082 unsigned section_line,
1083 const char *lvalue,
1084 int ltype,
1085 const char *rvalue,
1086 void *data,
1087 void *userdata) {
1088
1089 char **hostname = ASSERT_PTR(data);
1090
1091 assert(filename);
1092 assert(lvalue);
1093 assert(rvalue);
1094
1095 if (isempty(rvalue)) {
1096 *hostname = mfree(*hostname);
1097 return 0;
1098 }
1099
1100 if (!hostname_is_valid(rvalue, 0)) {
1101 log_syntax(unit, LOG_WARNING, filename, line, 0,
1102 "Specified invalid hostname, ignoring assignment: %s", rvalue);
1103 return 0;
1104 }
1105
1106 return config_parse_dns_name(unit, filename, line, section, section_line,
1107 lvalue, ltype, rvalue, data, userdata);
1108 }
1109
config_parse_path(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1110 int config_parse_path(
1111 const char *unit,
1112 const char *filename,
1113 unsigned line,
1114 const char *section,
1115 unsigned section_line,
1116 const char *lvalue,
1117 int ltype,
1118 const char *rvalue,
1119 void *data,
1120 void *userdata) {
1121
1122 _cleanup_free_ char *n = NULL;
1123 bool fatal = ltype;
1124 char **s = data;
1125 int r;
1126
1127 assert(filename);
1128 assert(lvalue);
1129 assert(rvalue);
1130 assert(data);
1131
1132 if (isempty(rvalue))
1133 goto finalize;
1134
1135 n = strdup(rvalue);
1136 if (!n)
1137 return log_oom();
1138
1139 r = path_simplify_and_warn(n, PATH_CHECK_ABSOLUTE | (fatal ? PATH_CHECK_FATAL : 0), unit, filename, line, lvalue);
1140 if (r < 0)
1141 return fatal ? -ENOEXEC : 0;
1142
1143 finalize:
1144 return free_and_replace(*s, n);
1145 }
1146
config_parse_strv(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1147 int config_parse_strv(
1148 const char *unit,
1149 const char *filename,
1150 unsigned line,
1151 const char *section,
1152 unsigned section_line,
1153 const char *lvalue,
1154 int ltype,
1155 const char *rvalue,
1156 void *data,
1157 void *userdata) {
1158
1159 char ***sv = data;
1160 int r;
1161
1162 assert(filename);
1163 assert(lvalue);
1164 assert(rvalue);
1165 assert(data);
1166
1167 if (isempty(rvalue)) {
1168 *sv = strv_free(*sv);
1169 return 0;
1170 }
1171
1172 for (const char *p = rvalue;;) {
1173 char *word = NULL;
1174
1175 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
1176 if (r == 0)
1177 return 0;
1178 if (r == -ENOMEM)
1179 return log_oom();
1180 if (r < 0) {
1181 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
1182 return 0;
1183 }
1184
1185 r = strv_consume(sv, word);
1186 if (r < 0)
1187 return log_oom();
1188 }
1189 }
1190
config_parse_warn_compat(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1191 int config_parse_warn_compat(
1192 const char *unit,
1193 const char *filename,
1194 unsigned line,
1195 const char *section,
1196 unsigned section_line,
1197 const char *lvalue,
1198 int ltype,
1199 const char *rvalue,
1200 void *data,
1201 void *userdata) {
1202
1203 Disabled reason = ltype;
1204
1205 switch (reason) {
1206
1207 case DISABLED_CONFIGURATION:
1208 log_syntax(unit, LOG_DEBUG, filename, line, 0,
1209 "Support for option %s= has been disabled at compile time and it is ignored", lvalue);
1210 break;
1211
1212 case DISABLED_LEGACY:
1213 log_syntax(unit, LOG_INFO, filename, line, 0,
1214 "Support for option %s= has been removed and it is ignored", lvalue);
1215 break;
1216
1217 case DISABLED_EXPERIMENTAL:
1218 log_syntax(unit, LOG_INFO, filename, line, 0,
1219 "Support for option %s= has not yet been enabled and it is ignored", lvalue);
1220 break;
1221 }
1222
1223 return 0;
1224 }
1225
config_parse_log_facility(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1226 int config_parse_log_facility(
1227 const char *unit,
1228 const char *filename,
1229 unsigned line,
1230 const char *section,
1231 unsigned section_line,
1232 const char *lvalue,
1233 int ltype,
1234 const char *rvalue,
1235 void *data,
1236 void *userdata) {
1237
1238 int *o = data, x;
1239
1240 assert(filename);
1241 assert(lvalue);
1242 assert(rvalue);
1243 assert(data);
1244
1245 x = log_facility_unshifted_from_string(rvalue);
1246 if (x < 0) {
1247 log_syntax(unit, LOG_WARNING, filename, line, x, "Failed to parse log facility, ignoring: %s", rvalue);
1248 return 0;
1249 }
1250
1251 *o = (x << 3) | LOG_PRI(*o);
1252
1253 return 0;
1254 }
1255
config_parse_log_level(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1256 int config_parse_log_level(
1257 const char *unit,
1258 const char *filename,
1259 unsigned line,
1260 const char *section,
1261 unsigned section_line,
1262 const char *lvalue,
1263 int ltype,
1264 const char *rvalue,
1265 void *data,
1266 void *userdata) {
1267
1268 int *o = data, x;
1269
1270 assert(filename);
1271 assert(lvalue);
1272 assert(rvalue);
1273 assert(data);
1274
1275 x = log_level_from_string(rvalue);
1276 if (x < 0) {
1277 log_syntax(unit, LOG_WARNING, filename, line, x, "Failed to parse log level, ignoring: %s", rvalue);
1278 return 0;
1279 }
1280
1281 if (*o < 0) /* if it wasn't initialized so far, assume zero facility */
1282 *o = x;
1283 else
1284 *o = (*o & LOG_FACMASK) | x;
1285
1286 return 0;
1287 }
1288
config_parse_signal(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1289 int config_parse_signal(
1290 const char *unit,
1291 const char *filename,
1292 unsigned line,
1293 const char *section,
1294 unsigned section_line,
1295 const char *lvalue,
1296 int ltype,
1297 const char *rvalue,
1298 void *data,
1299 void *userdata) {
1300
1301 int *sig = data, r;
1302
1303 assert(filename);
1304 assert(lvalue);
1305 assert(rvalue);
1306 assert(sig);
1307
1308 r = signal_from_string(rvalue);
1309 if (r <= 0) {
1310 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse signal name, ignoring: %s", rvalue);
1311 return 0;
1312 }
1313
1314 *sig = r;
1315 return 0;
1316 }
1317
config_parse_personality(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1318 int config_parse_personality(
1319 const char *unit,
1320 const char *filename,
1321 unsigned line,
1322 const char *section,
1323 unsigned section_line,
1324 const char *lvalue,
1325 int ltype,
1326 const char *rvalue,
1327 void *data,
1328 void *userdata) {
1329
1330 unsigned long *personality = data, p;
1331
1332 assert(filename);
1333 assert(lvalue);
1334 assert(rvalue);
1335 assert(personality);
1336
1337 if (isempty(rvalue))
1338 p = PERSONALITY_INVALID;
1339 else {
1340 p = personality_from_string(rvalue);
1341 if (p == PERSONALITY_INVALID) {
1342 log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse personality, ignoring: %s", rvalue);
1343 return 0;
1344 }
1345 }
1346
1347 *personality = p;
1348 return 0;
1349 }
1350
config_parse_ifname(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1351 int config_parse_ifname(
1352 const char *unit,
1353 const char *filename,
1354 unsigned line,
1355 const char *section,
1356 unsigned section_line,
1357 const char *lvalue,
1358 int ltype,
1359 const char *rvalue,
1360 void *data,
1361 void *userdata) {
1362
1363 char **s = data;
1364 int r;
1365
1366 assert(filename);
1367 assert(lvalue);
1368 assert(rvalue);
1369 assert(data);
1370
1371 if (isempty(rvalue)) {
1372 *s = mfree(*s);
1373 return 0;
1374 }
1375
1376 if (!ifname_valid(rvalue)) {
1377 log_syntax(unit, LOG_WARNING, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue);
1378 return 0;
1379 }
1380
1381 r = free_and_strdup(s, rvalue);
1382 if (r < 0)
1383 return log_oom();
1384
1385 return 0;
1386 }
1387
config_parse_ifnames(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1388 int config_parse_ifnames(
1389 const char *unit,
1390 const char *filename,
1391 unsigned line,
1392 const char *section,
1393 unsigned section_line,
1394 const char *lvalue,
1395 int ltype,
1396 const char *rvalue,
1397 void *data,
1398 void *userdata) {
1399
1400 _cleanup_strv_free_ char **names = NULL;
1401 char ***s = data;
1402 int r;
1403
1404 assert(filename);
1405 assert(lvalue);
1406 assert(rvalue);
1407 assert(data);
1408
1409 if (isempty(rvalue)) {
1410 *s = strv_free(*s);
1411 return 0;
1412 }
1413
1414 for (const char *p = rvalue;;) {
1415 _cleanup_free_ char *word = NULL;
1416
1417 r = extract_first_word(&p, &word, NULL, 0);
1418 if (r == -ENOMEM)
1419 return log_oom();
1420 if (r < 0) {
1421 log_syntax(unit, LOG_WARNING, filename, line, r,
1422 "Failed to extract interface name, ignoring assignment: %s",
1423 rvalue);
1424 return 0;
1425 }
1426 if (r == 0)
1427 break;
1428
1429 if (!ifname_valid_full(word, ltype)) {
1430 log_syntax(unit, LOG_WARNING, filename, line, 0,
1431 "Interface name is not valid or too long, ignoring assignment: %s",
1432 word);
1433 continue;
1434 }
1435
1436 r = strv_consume(&names, TAKE_PTR(word));
1437 if (r < 0)
1438 return log_oom();
1439 }
1440
1441 r = strv_extend_strv(s, names, true);
1442 if (r < 0)
1443 return log_oom();
1444
1445 return 0;
1446 }
1447
config_parse_ip_port(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1448 int config_parse_ip_port(
1449 const char *unit,
1450 const char *filename,
1451 unsigned line,
1452 const char *section,
1453 unsigned section_line,
1454 const char *lvalue,
1455 int ltype,
1456 const char *rvalue,
1457 void *data,
1458 void *userdata) {
1459
1460 uint16_t *s = data;
1461 uint16_t port;
1462 int r;
1463
1464 assert(filename);
1465 assert(lvalue);
1466 assert(rvalue);
1467 assert(data);
1468
1469 if (isempty(rvalue)) {
1470 *s = 0;
1471 return 0;
1472 }
1473
1474 r = parse_ip_port(rvalue, &port);
1475 if (r < 0) {
1476 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse port '%s'.", rvalue);
1477 return 0;
1478 }
1479
1480 *s = port;
1481
1482 return 0;
1483 }
1484
config_parse_mtu(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1485 int config_parse_mtu(
1486 const char *unit,
1487 const char *filename,
1488 unsigned line,
1489 const char *section,
1490 unsigned section_line,
1491 const char *lvalue,
1492 int ltype,
1493 const char *rvalue,
1494 void *data,
1495 void *userdata) {
1496
1497 uint32_t *mtu = data;
1498 int r;
1499
1500 assert(rvalue);
1501 assert(mtu);
1502
1503 r = parse_mtu(ltype, rvalue, mtu);
1504 if (r == -ERANGE) {
1505 log_syntax(unit, LOG_WARNING, filename, line, r,
1506 "Maximum transfer unit (MTU) value out of range. Permitted range is %" PRIu32 "…%" PRIu32 ", ignoring: %s",
1507 (uint32_t) (ltype == AF_INET6 ? IPV6_MIN_MTU : IPV4_MIN_MTU), (uint32_t) UINT32_MAX,
1508 rvalue);
1509 return 0;
1510 }
1511 if (r < 0) {
1512 log_syntax(unit, LOG_WARNING, filename, line, r,
1513 "Failed to parse MTU value '%s', ignoring: %m", rvalue);
1514 return 0;
1515 }
1516
1517 return 0;
1518 }
1519
config_parse_rlimit(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1520 int config_parse_rlimit(
1521 const char *unit,
1522 const char *filename,
1523 unsigned line,
1524 const char *section,
1525 unsigned section_line,
1526 const char *lvalue,
1527 int ltype,
1528 const char *rvalue,
1529 void *data,
1530 void *userdata) {
1531
1532 struct rlimit **rl = data, d = {};
1533 int r;
1534
1535 assert(rvalue);
1536 assert(rl);
1537
1538 r = rlimit_parse(ltype, rvalue, &d);
1539 if (r == -EILSEQ) {
1540 log_syntax(unit, LOG_WARNING, filename, line, r, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue);
1541 return 0;
1542 }
1543 if (r < 0) {
1544 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
1545 return 0;
1546 }
1547
1548 if (rl[ltype])
1549 *rl[ltype] = d;
1550 else {
1551 rl[ltype] = newdup(struct rlimit, &d, 1);
1552 if (!rl[ltype])
1553 return log_oom();
1554 }
1555
1556 return 0;
1557 }
1558
config_parse_permille(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1559 int config_parse_permille(
1560 const char* unit,
1561 const char *filename,
1562 unsigned line,
1563 const char *section,
1564 unsigned section_line,
1565 const char *lvalue,
1566 int ltype,
1567 const char *rvalue,
1568 void *data,
1569 void *userdata) {
1570
1571 unsigned *permille = data;
1572 int r;
1573
1574 assert(filename);
1575 assert(lvalue);
1576 assert(rvalue);
1577 assert(permille);
1578
1579 r = parse_permille(rvalue);
1580 if (r < 0) {
1581 log_syntax(unit, LOG_WARNING, filename, line, r,
1582 "Failed to parse permille value, ignoring: %s", rvalue);
1583 return 0;
1584 }
1585
1586 *permille = (unsigned) r;
1587
1588 return 0;
1589 }
1590
config_parse_vlanprotocol(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1591 int config_parse_vlanprotocol(
1592 const char* unit,
1593 const char *filename,
1594 unsigned line,
1595 const char *section,
1596 unsigned section_line,
1597 const char *lvalue,
1598 int ltype,
1599 const char *rvalue,
1600 void *data,
1601 void *userdata) {
1602
1603 int *vlan_protocol = data;
1604
1605 assert(filename);
1606 assert(lvalue);
1607
1608 if (isempty(rvalue)) {
1609 *vlan_protocol = -1;
1610 return 0;
1611 }
1612
1613 if (STR_IN_SET(rvalue, "802.1ad", "802.1AD"))
1614 *vlan_protocol = ETH_P_8021AD;
1615 else if (STR_IN_SET(rvalue, "802.1q", "802.1Q"))
1616 *vlan_protocol = ETH_P_8021Q;
1617 else {
1618 log_syntax(unit, LOG_WARNING, filename, line, 0,
1619 "Failed to parse VLAN protocol value, ignoring: %s", rvalue);
1620 return 0;
1621 }
1622
1623 return 0;
1624 }
1625
config_parse_hw_addr(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1626 int config_parse_hw_addr(
1627 const char *unit,
1628 const char *filename,
1629 unsigned line,
1630 const char *section,
1631 unsigned section_line,
1632 const char *lvalue,
1633 int ltype,
1634 const char *rvalue,
1635 void *data,
1636 void *userdata) {
1637
1638 struct hw_addr_data a, *hwaddr = data;
1639 int r;
1640
1641 assert(filename);
1642 assert(lvalue);
1643 assert(rvalue);
1644 assert(data);
1645
1646 if (isempty(rvalue)) {
1647 *hwaddr = HW_ADDR_NULL;
1648 return 0;
1649 }
1650
1651 r = parse_hw_addr_full(rvalue, ltype, &a);
1652 if (r < 0) {
1653 log_syntax(unit, LOG_WARNING, filename, line, r,
1654 "Not a valid hardware address, ignoring assignment: %s", rvalue);
1655 return 0;
1656 }
1657
1658 *hwaddr = a;
1659 return 0;
1660 }
1661
config_parse_hw_addrs(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1662 int config_parse_hw_addrs(
1663 const char *unit,
1664 const char *filename,
1665 unsigned line,
1666 const char *section,
1667 unsigned section_line,
1668 const char *lvalue,
1669 int ltype,
1670 const char *rvalue,
1671 void *data,
1672 void *userdata) {
1673
1674 Set **hwaddrs = data;
1675 int r;
1676
1677 assert(filename);
1678 assert(lvalue);
1679 assert(rvalue);
1680 assert(data);
1681
1682 if (isempty(rvalue)) {
1683 /* Empty assignment resets the list */
1684 *hwaddrs = set_free(*hwaddrs);
1685 return 0;
1686 }
1687
1688 for (const char *p = rvalue;;) {
1689 _cleanup_free_ char *word = NULL;
1690 _cleanup_free_ struct hw_addr_data *n = NULL;
1691
1692 r = extract_first_word(&p, &word, NULL, 0);
1693 if (r == 0)
1694 return 0;
1695 if (r == -ENOMEM)
1696 return log_oom();
1697 if (r < 0) {
1698 log_syntax(unit, LOG_WARNING, filename, line, r,
1699 "Invalid syntax, ignoring: %s", rvalue);
1700 return 0;
1701 }
1702
1703 n = new(struct hw_addr_data, 1);
1704 if (!n)
1705 return log_oom();
1706
1707 r = parse_hw_addr_full(word, ltype, n);
1708 if (r < 0) {
1709 log_syntax(unit, LOG_WARNING, filename, line, r,
1710 "Not a valid hardware address, ignoring: %s", word);
1711 continue;
1712 }
1713
1714 r = set_ensure_consume(hwaddrs, &hw_addr_hash_ops_free, TAKE_PTR(n));
1715 if (r < 0)
1716 return log_oom();
1717 }
1718 }
1719
config_parse_ether_addr(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1720 int config_parse_ether_addr(
1721 const char *unit,
1722 const char *filename,
1723 unsigned line,
1724 const char *section,
1725 unsigned section_line,
1726 const char *lvalue,
1727 int ltype,
1728 const char *rvalue,
1729 void *data,
1730 void *userdata) {
1731
1732 _cleanup_free_ struct ether_addr *n = NULL;
1733 struct ether_addr **hwaddr = data;
1734 int r;
1735
1736 assert(filename);
1737 assert(lvalue);
1738 assert(rvalue);
1739 assert(data);
1740
1741 if (isempty(rvalue)) {
1742 *hwaddr = mfree(*hwaddr);
1743 return 0;
1744 }
1745
1746 n = new0(struct ether_addr, 1);
1747 if (!n)
1748 return log_oom();
1749
1750 r = parse_ether_addr(rvalue, n);
1751 if (r < 0) {
1752 log_syntax(unit, LOG_WARNING, filename, line, r,
1753 "Not a valid MAC address, ignoring assignment: %s", rvalue);
1754 return 0;
1755 }
1756
1757 free_and_replace(*hwaddr, n);
1758
1759 return 0;
1760 }
1761
config_parse_ether_addrs(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1762 int config_parse_ether_addrs(
1763 const char *unit,
1764 const char *filename,
1765 unsigned line,
1766 const char *section,
1767 unsigned section_line,
1768 const char *lvalue,
1769 int ltype,
1770 const char *rvalue,
1771 void *data,
1772 void *userdata) {
1773
1774 Set **hwaddrs = data;
1775 int r;
1776
1777 assert(filename);
1778 assert(lvalue);
1779 assert(rvalue);
1780 assert(data);
1781
1782 if (isempty(rvalue)) {
1783 /* Empty assignment resets the list */
1784 *hwaddrs = set_free(*hwaddrs);
1785 return 0;
1786 }
1787
1788 for (const char *p = rvalue;;) {
1789 _cleanup_free_ char *word = NULL;
1790 _cleanup_free_ struct ether_addr *n = NULL;
1791
1792 r = extract_first_word(&p, &word, NULL, 0);
1793 if (r == 0)
1794 return 0;
1795 if (r == -ENOMEM)
1796 return log_oom();
1797 if (r < 0) {
1798 log_syntax(unit, LOG_WARNING, filename, line, r,
1799 "Invalid syntax, ignoring: %s", rvalue);
1800 return 0;
1801 }
1802
1803 n = new(struct ether_addr, 1);
1804 if (!n)
1805 return log_oom();
1806
1807 r = parse_ether_addr(word, n);
1808 if (r < 0) {
1809 log_syntax(unit, LOG_WARNING, filename, line, r,
1810 "Not a valid MAC address, ignoring: %s", word);
1811 continue;
1812 }
1813
1814 r = set_ensure_consume(hwaddrs, ðer_addr_hash_ops_free, TAKE_PTR(n));
1815 if (r < 0)
1816 return log_oom();
1817 }
1818 }
1819
config_parse_in_addr_non_null(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1820 int config_parse_in_addr_non_null(
1821 const char *unit,
1822 const char *filename,
1823 unsigned line,
1824 const char *section,
1825 unsigned section_line,
1826 const char *lvalue,
1827 int ltype,
1828 const char *rvalue,
1829 void *data,
1830 void *userdata) {
1831
1832 /* data must be a pointer to struct in_addr or in6_addr, and the type is determined by ltype. */
1833 struct in_addr *ipv4 = data;
1834 struct in6_addr *ipv6 = data;
1835 union in_addr_union a;
1836 int r;
1837
1838 assert(filename);
1839 assert(lvalue);
1840 assert(rvalue);
1841 assert(data);
1842 assert(IN_SET(ltype, AF_INET, AF_INET6));
1843
1844 if (isempty(rvalue)) {
1845 if (ltype == AF_INET)
1846 *ipv4 = (struct in_addr) {};
1847 else
1848 *ipv6 = (struct in6_addr) {};
1849 return 0;
1850 }
1851
1852 r = in_addr_from_string(ltype, rvalue, &a);
1853 if (r < 0) {
1854 log_syntax(unit, LOG_WARNING, filename, line, r,
1855 "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
1856 return 0;
1857 }
1858
1859 if (!in_addr_is_set(ltype, &a)) {
1860 log_syntax(unit, LOG_WARNING, filename, line, 0,
1861 "%s= cannot be the ANY address, ignoring: %s", lvalue, rvalue);
1862 return 0;
1863 }
1864
1865 if (ltype == AF_INET)
1866 *ipv4 = a.in;
1867 else
1868 *ipv6 = a.in6;
1869 return 0;
1870 }
1871
1872 DEFINE_CONFIG_PARSE(config_parse_percent, parse_percent, "Failed to parse percent value");
1873 DEFINE_CONFIG_PARSE(config_parse_permyriad, parse_permyriad, "Failed to parse permyriad value");
1874