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, &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 */
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                                &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 
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, &ether_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