• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 16082515961

04 Jul 2025 08:23PM UTC coverage: 72.095% (-0.1%) from 72.193%
16082515961

push

github

poettering
seccomp-util: allowlist open_tree() as part of @file-system

Now that we make use of open_tree() in places we previously used
openat() with O_PATH, it makes sense to move it from @mount to
@file-system. Without the OPEN_TREE_CLONE flag open_tree() is after all
unprivileged.

Note that open_tree_attr() I left in @mount, since it's purpose is
really to set mount options when cloning, and that's clearly a mount
related thing, not so much something you could use unpriv.

Follow-up for: c5de7b14a

This addresses an issue tracked down by Antonio Feijoo: since the commit
that started to use open_tree() various apps started to crash because
they used seccomp filters and sd-device started to use open_tree()
internally.

300842 of 417287 relevant lines covered (72.09%)

715300.57 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

76.5
/src/shared/conf-parser.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <linux/ipv6.h>
4
#include <stdio.h>
5

6
#include "sd-id128.h"
7

8
#include "alloc-util.h"
9
#include "calendarspec.h"
10
#include "chase.h"
11
#include "conf-files.h"
12
#include "conf-parser.h"
13
#include "constants.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 "hash-funcs.h"
22
#include "hostname-util.h"
23
#include "id128-util.h"
24
#include "in-addr-prefix-util.h"
25
#include "ip-protocol-list.h"
26
#include "log.h"
27
#include "missing_network.h"
28
#include "nulstr-util.h"
29
#include "parse-helpers.h"
30
#include "parse-util.h"
31
#include "path-util.h"
32
#include "percent-util.h"
33
#include "process-util.h"
34
#include "rlimit-util.h"
35
#include "set.h"
36
#include "signal-util.h"
37
#include "siphash24.h"
38
#include "socket-util.h"
39
#include "stat-util.h"
40
#include "string-util.h"
41
#include "strv.h"
42
#include "syslog-util.h"
43
#include "time-util.h"
44
#include "utf8.h"
45

46
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(config_file_hash_ops_fclose,
499✔
47
                                              char, path_hash_func, path_compare,
48
                                              FILE, safe_fclose);
49

50
int config_item_table_lookup(
7,826✔
51
                const void *table,
52
                const char *section,
53
                const char *lvalue,
54
                ConfigParserCallback *ret_func,
55
                int *ret_ltype,
56
                void **ret_data,
57
                void *userdata) {
58

59
        assert(table);
7,826✔
60
        assert(lvalue);
7,826✔
61
        assert(ret_func);
7,826✔
62
        assert(ret_ltype);
7,826✔
63
        assert(ret_data);
7,826✔
64

65
        for (const ConfigTableItem *t = table; t->lvalue; t++) {
84,325✔
66

67
                if (!streq(lvalue, t->lvalue))
84,325✔
68
                        continue;
74,555✔
69

70
                if (!streq_ptr(section, t->section))
9,770✔
71
                        continue;
1,944✔
72

73
                *ret_func = t->parse;
7,826✔
74
                *ret_ltype = t->ltype;
7,826✔
75
                *ret_data = t->data;
7,826✔
76
                return 1;
7,826✔
77
        }
78

79
        *ret_func = NULL;
×
80
        *ret_ltype = 0;
×
81
        *ret_data = NULL;
×
82
        return 0;
×
83
}
84

85
int config_item_perf_lookup(
390,941✔
86
                const void *table,
87
                const char *section,
88
                const char *lvalue,
89
                ConfigParserCallback *ret_func,
90
                int *ret_ltype,
91
                void **ret_data,
92
                void *userdata) {
93

94
        ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
390,941✔
95
        const ConfigPerfItem *p;
390,941✔
96

97
        assert(table);
390,941✔
98
        assert(lvalue);
390,941✔
99
        assert(ret_func);
390,941✔
100
        assert(ret_ltype);
390,941✔
101
        assert(ret_data);
390,941✔
102

103
        if (section) {
390,941✔
104
                const char *key;
390,941✔
105

106
                key = strjoina(section, ".", lvalue);
2,736,587✔
107
                p = lookup(key, strlen(key));
390,941✔
108
        } else
109
                p = lookup(lvalue, strlen(lvalue));
×
110
        if (!p) {
390,941✔
111
                *ret_func = NULL;
5✔
112
                *ret_ltype = 0;
5✔
113
                *ret_data = NULL;
5✔
114
                return 0;
5✔
115
        }
116

117
        *ret_func = p->parse;
390,936✔
118
        *ret_ltype = p->ltype;
390,936✔
119
        *ret_data = (uint8_t*) userdata + p->offset;
390,936✔
120
        return 1;
390,936✔
121
}
122

123
/* Run the user supplied parser for an assignment */
124
static int next_assignment(
398,767✔
125
                const char *unit,
126
                const char *filename,
127
                unsigned line,
128
                ConfigItemLookup lookup,
129
                const void *table,
130
                const char *section,
131
                unsigned section_line,
132
                const char *lvalue,
133
                const char *rvalue,
134
                ConfigParseFlags flags,
135
                void *userdata) {
136

137
        ConfigParserCallback func = NULL;
398,767✔
138
        int ltype = 0;
398,767✔
139
        void *data = NULL;
398,767✔
140
        int r;
398,767✔
141

142
        assert(filename);
398,767✔
143
        assert(line > 0);
398,767✔
144
        assert(lookup);
398,767✔
145
        assert(lvalue);
398,767✔
146
        assert(rvalue);
398,767✔
147

148
        r = lookup(table, section, lvalue, &func, &ltype, &data, userdata);
398,767✔
149
        if (r < 0)
398,767✔
150
                return r;
398,767✔
151
        if (r > 0) {
398,767✔
152
                if (!func)
398,762✔
153
                        return 0;
154

155
                return func(unit, filename, line, section, section_line,
391,506✔
156
                            lvalue, ltype, rvalue, data, userdata);
157
        }
158

159
        /* Warn about unknown non-extension fields. */
160
        if (!(flags & CONFIG_PARSE_RELAXED) && !startswith(lvalue, "X-"))
5✔
161
                log_syntax(unit, LOG_WARNING, filename, line, 0,
5✔
162
                           "Unknown key '%s'%s%s%s, ignoring.",
163
                           lvalue,
164
                           section ? " in section [" : "",
165
                           strempty(section),
166
                           section ? "]" : "");
167

168
        return 0;
169
}
170

171
/* Parse a single logical line */
172
static int parse_line(
713,969✔
173
                const char *unit,
174
                const char *filename,
175
                unsigned line,
176
                const char *sections,
177
                ConfigItemLookup lookup,
178
                const void *table,
179
                ConfigParseFlags flags,
180
                char **section,
181
                unsigned *section_line,
182
                bool *section_ignored,
183
                char *l, /* is modified */
184
                void *userdata) {
185

186
        char *e;
713,969✔
187

188
        assert(filename);
713,969✔
189
        assert(line > 0);
713,969✔
190
        assert(lookup);
713,969✔
191
        assert(l);
713,969✔
192

193
        l = strstrip(l);
713,969✔
194
        if (isempty(l))
1,427,938✔
195
                return 0;
196

197
        if (l[0] == '\n')
569,762✔
198
                return 0;
199

200
        if (!utf8_is_valid(l))
569,762✔
201
                return log_syntax_invalid_utf8(unit, LOG_WARNING, filename, line, l);
×
202

203
        if (l[0] == '[') {
569,762✔
204
                _cleanup_free_ char *n = NULL;
110,391✔
205
                size_t k;
110,391✔
206

207
                k = strlen(l);
110,391✔
208
                assert(k > 0);
110,391✔
209

210
                if (l[k-1] != ']')
110,391✔
211
                        return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EBADMSG), "Invalid section header '%s'", l);
×
212

213
                n = strndup(l+1, k-2);
110,391✔
214
                if (!n)
110,391✔
215
                        return log_oom();
×
216

217
                if (!string_is_safe(n))
110,391✔
218
                        return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EBADMSG), "Bad characters in section header '%s'", l);
×
219

220
                if (sections && !nulstr_contains(sections, n)) {
110,391✔
221
                        bool ignore;
7,316✔
222

223
                        ignore = (flags & CONFIG_PARSE_RELAXED) || startswith(n, "X-");
7,316✔
224

225
                        if (!ignore)
226
                                NULSTR_FOREACH(t, sections)
56,592✔
227
                                        if (streq_ptr(n, startswith(t, "-"))) { /* Ignore sections prefixed with "-" in valid section list */
56,591✔
228
                                                ignore = true;
229
                                                break;
230
                                        }
231

232
                        if (!ignore)
7,297✔
233
                                log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown section '%s'. Ignoring.", n);
1✔
234

235
                        *section = mfree(*section);
7,316✔
236
                        *section_line = 0;
7,316✔
237
                        *section_ignored = true;
7,316✔
238
                } else {
239
                        free_and_replace(*section, n);
103,075✔
240
                        *section_line = line;
103,075✔
241
                        *section_ignored = false;
103,075✔
242
                }
243

244
                return 0;
110,391✔
245
        }
246

247
        if (sections && !*section) {
459,371✔
248
                if (!(flags & CONFIG_PARSE_RELAXED) && !*section_ignored)
60,604✔
249
                        log_syntax(unit, LOG_WARNING, filename, line, 0, "Assignment outside of section. Ignoring.");
×
250

251
                return 0;
60,604✔
252
        }
253

254
        e = strchr(l, '=');
398,767✔
255
        if (!e)
398,767✔
256
                return log_syntax(unit, LOG_WARNING, filename, line, 0,
×
257
                                  "Missing '=', ignoring line.");
258
        if (e == l)
398,767✔
259
                return log_syntax(unit, LOG_WARNING, filename, line, 0,
×
260
                                  "Missing key name before '=', ignoring line.");
261

262
        *e = 0;
398,767✔
263
        e++;
398,767✔
264

265
        return next_assignment(unit,
398,767✔
266
                               filename,
267
                               line,
268
                               lookup,
269
                               table,
270
                               *section,
271
                               *section_line,
272
                               strstrip(l),
398,767✔
273
                               strstrip(e),
398,767✔
274
                               flags,
275
                               userdata);
276
}
277

278
/* Go through the file and parse each line */
279
int config_parse(
92,487✔
280
                const char *unit,
281
                const char *filename,
282
                FILE *f,
283
                const char *sections,
284
                ConfigItemLookup lookup,
285
                const void *table,
286
                ConfigParseFlags flags,
287
                void *userdata,
288
                struct stat *ret_stat) {
289

290
        _cleanup_free_ char *section = NULL, *continuation = NULL;
92,487✔
291
        _cleanup_fclose_ FILE *ours = NULL;
92,487✔
292
        unsigned line = 0, section_line = 0;
92,487✔
293
        bool section_ignored = false, bom_seen = false;
92,487✔
294
        struct stat st;
92,487✔
295
        int r, fd;
92,487✔
296

297
        assert(filename);
92,487✔
298
        assert(lookup);
92,487✔
299

300
        if (!f) {
92,487✔
301
                f = ours = fopen(filename, "re");
11,800✔
302
                if (!f) {
11,800✔
303
                        /* Only log on request, except for ENOENT,
304
                         * since we return 0 to the caller. */
305
                        if ((flags & CONFIG_PARSE_WARN) || errno == ENOENT)
×
306
                                log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno,
×
307
                                               "Failed to open configuration file '%s': %m", filename);
308

309
                        if (errno == ENOENT) {
×
310
                                if (ret_stat)
×
311
                                        *ret_stat = (struct stat) {};
×
312

313
                                return 0;
×
314
                        }
315

316
                        return -errno;
×
317
                }
318
        }
319

320
        fd = fileno(f);
92,487✔
321
        if (fd >= 0) { /* stream might not have an fd, let's be careful hence */
92,487✔
322

323
                if (fstat(fd, &st) < 0)
92,487✔
324
                        return log_full_errno(FLAGS_SET(flags, CONFIG_PARSE_WARN) ? LOG_ERR : LOG_DEBUG, errno,
×
325
                                              "Failed to fstat(%s): %m", filename);
326

327
                (void) stat_warn_permissions(filename, &st);
92,487✔
328
        } else
329
                st = (struct stat) {};
×
330

331
        for (;;) {
1,516,401✔
332
                _cleanup_free_ char *buf = NULL;
1,423,916✔
333
                bool escaped = false;
1,516,401✔
334
                char *l, *p, *e;
1,516,401✔
335

336
                r = read_line(f, LONG_LINE_MAX, &buf);
1,516,401✔
337
                if (r == 0)
1,516,401✔
338
                        break;
339
                if (r == -ENOBUFS) {
1,423,916✔
340
                        if (flags & CONFIG_PARSE_WARN)
1✔
341
                                log_error_errno(r, "%s:%u: Line too long", filename, line);
1✔
342

343
                        return r;
1✔
344
                }
345
                if (r < 0) {
1,423,915✔
346
                        if (FLAGS_SET(flags, CONFIG_PARSE_WARN))
×
347
                                log_error_errno(r, "%s:%u: Error while reading configuration file: %m", filename, line);
×
348

349
                        return r;
×
350
                }
351

352
                line++;
1,423,915✔
353

354
                l = skip_leading_chars(buf, WHITESPACE);
1,423,915✔
355
                if (*l != '\0' && strchr(COMMENTS, *l))
1,423,915✔
356
                        continue;
705,548✔
357

358
                l = buf;
718,367✔
359
                if (!bom_seen) {
718,367✔
360
                        char *q;
718,367✔
361

362
                        q = startswith(buf, UTF8_BYTE_ORDER_MARK);
718,367✔
363
                        if (q) {
718,367✔
364
                                l = q;
×
365
                                bom_seen = true;
×
366
                        }
367
                }
368

369
                if (continuation) {
718,367✔
370
                        if (strlen(continuation) + strlen(l) > LONG_LINE_MAX) {
4,397✔
371
                                if (flags & CONFIG_PARSE_WARN)
1✔
372
                                        log_error("%s:%u: Continuation line too long", filename, line);
1✔
373
                                return -ENOBUFS;
1✔
374
                        }
375

376
                        if (!strextend(&continuation, l)) {
4,396✔
377
                                if (flags & CONFIG_PARSE_WARN)
×
378
                                        log_oom();
×
379
                                return -ENOMEM;
×
380
                        }
381

382
                        p = continuation;
4,396✔
383
                } else
384
                        p = l;
385

386
                for (e = p; *e; e++) {
538,171,745✔
387
                        if (escaped)
537,453,379✔
388
                                escaped = false;
389
                        else if (*e == '\\')
537,453,109✔
390
                                escaped = true;
4,669✔
391
                }
392

393
                if (escaped) {
718,366✔
394
                        *(e-1) = ' ';
4,399✔
395

396
                        if (!continuation) {
4,399✔
397
                                continuation = strdup(l);
1,139✔
398
                                if (!continuation) {
1,139✔
399
                                        if (flags & CONFIG_PARSE_WARN)
×
400
                                                log_oom();
×
401
                                        return -ENOMEM;
×
402
                                }
403
                        }
404

405
                        continue;
4,399✔
406
                }
407

408
                r = parse_line(unit,
713,967✔
409
                               filename,
410
                               line,
411
                               sections,
412
                               lookup,
413
                               table,
414
                               flags,
415
                               &section,
416
                               &section_line,
417
                               &section_ignored,
418
                               p,
419
                               userdata);
420
                if (r < 0) {
713,967✔
421
                        if (flags & CONFIG_PARSE_WARN)
×
422
                                log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
×
423
                        return r;
×
424
                }
425

426
                continuation = mfree(continuation);
713,967✔
427
        }
428

429
        if (continuation) {
92,485✔
430
                r = parse_line(unit,
2✔
431
                               filename,
432
                               ++line,
433
                               sections,
434
                               lookup,
435
                               table,
436
                               flags,
437
                               &section,
438
                               &section_line,
439
                               &section_ignored,
440
                               continuation,
441
                               userdata);
442
                if (r < 0) {
2✔
443
                        if (flags & CONFIG_PARSE_WARN)
×
444
                                log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
×
445
                        return r;
×
446
                }
447
        }
448

449
        if (ret_stat)
92,485✔
450
                *ret_stat = st;
58,360✔
451

452
        return 1;
453
}
454

455
int hashmap_put_stats_by_path(Hashmap **stats_by_path, const char *path, const struct stat *st) {
46,155✔
456
        _cleanup_free_ struct stat *st_copy = NULL;
92,310✔
457
        _cleanup_free_ char *path_copy = NULL;
46,155✔
458
        int r;
46,155✔
459

460
        assert(stats_by_path);
46,155✔
461
        assert(path);
46,155✔
462
        assert(st);
46,155✔
463

464
        st_copy = newdup(struct stat, st, 1);
46,155✔
465
        if (!st_copy)
46,155✔
466
                return -ENOMEM;
467

468
        path_copy = strdup(path);
46,155✔
469
        if (!path_copy)
46,155✔
470
                return -ENOMEM;
471

472
        r = hashmap_ensure_put(stats_by_path, &path_hash_ops_free_free, path_copy, st_copy);
46,155✔
473
        if (r < 0)
46,155✔
474
                return r;
475

476
        assert(r > 0);
46,155✔
477
        TAKE_PTR(path_copy);
478
        TAKE_PTR(st_copy);
479
        return 0;
480
}
481

482
static int config_parse_many_files(
46,088✔
483
                const char *root,
484
                const char* const* conf_files,
485
                char **files,
486
                const char *sections,
487
                ConfigItemLookup lookup,
488
                const void *table,
489
                ConfigParseFlags flags,
490
                void *userdata,
491
                Hashmap **ret_stats_by_path) {
492

493
        _cleanup_hashmap_free_ Hashmap *stats_by_path = NULL;
46,088✔
494
        _cleanup_ordered_hashmap_free_ OrderedHashmap *dropins = NULL;
46,088✔
495
        _cleanup_set_free_ Set *inodes = NULL;
46,088✔
496
        struct stat st;
46,088✔
497
        int r, level = FLAGS_SET(flags, CONFIG_PARSE_WARN) ? LOG_WARNING : LOG_DEBUG;
46,088✔
498

499
        if (ret_stats_by_path) {
46,088✔
500
                stats_by_path = hashmap_new(&path_hash_ops_free_free);
9,494✔
501
                if (!stats_by_path)
9,494✔
502
                        return log_oom_full(level);
×
503
        }
504

505
        STRV_FOREACH(fn, files) {
46,587✔
506
                _cleanup_fclose_ FILE *f = NULL;
499✔
507
                _cleanup_free_ char *fname = NULL;
499✔
508

509
                r = chase_and_fopen_unlocked(*fn, root, CHASE_AT_RESOLVE_IN_ROOT, "re", &fname, &f);
499✔
510
                if (r == -ENOENT)
499✔
511
                        continue;
×
512
                if (r < 0)
499✔
513
                        return log_full_errno(level, r, "Failed to open %s: %m", *fn);
×
514

515
                int fd = fileno(f);
499✔
516

517
                r = ordered_hashmap_ensure_put(&dropins, &config_file_hash_ops_fclose, *fn, f);
499✔
518
                if (r < 0) {
499✔
519
                        assert(r == -ENOMEM);
×
520
                        return log_oom_full(level);
×
521
                }
522
                assert(r > 0);
499✔
523
                TAKE_PTR(f);
499✔
524

525
                /* Get inodes for all drop-ins. Later we'll verify if main config is a symlink to or is
526
                 * symlinked as one of them. If so, we skip reading main config file directly. */
527

528
                _cleanup_free_ struct stat *st_dropin = new(struct stat, 1);
998✔
529
                if (!st_dropin)
499✔
530
                        return log_oom_full(level);
×
531

532
                if (fstat(fd, st_dropin) < 0)
499✔
533
                        return log_full_errno(level, errno, "Failed to stat %s: %m", *fn);
×
534

535
                r = set_ensure_consume(&inodes, &inode_hash_ops, TAKE_PTR(st_dropin));
499✔
536
                if (r < 0)
499✔
537
                        return log_oom_full(level);
×
538
        }
539

540
        /* First read the first found main config file. */
541
        STRV_FOREACH(fn, conf_files) {
46,749✔
542
                _cleanup_fclose_ FILE *f = NULL;
46,726✔
543

544
                r = chase_and_fopen_unlocked(*fn, root, CHASE_AT_RESOLVE_IN_ROOT, "re", NULL, &f);
46,726✔
545
                if (r == -ENOENT)
46,726✔
546
                        continue;
661✔
547
                if (r < 0)
46,065✔
548
                        return log_full_errno(level, r, "Failed to open %s: %m", *fn);
×
549

550
                if (inodes) {
46,065✔
551
                        if (fstat(fileno(f), &st) < 0)
364✔
552
                                return log_full_errno(level, errno, "Failed to stat %s: %m", *fn);
×
553

554
                        if (set_contains(inodes, &st)) {
364✔
555
                                log_debug("%s: symlink to/symlinked as drop-in, will be read later.", *fn);
×
556
                                break;
557
                        }
558
                }
559

560
                r = config_parse(/* unit= */ NULL, *fn, f, sections, lookup, table, flags, userdata, &st);
46,065✔
561
                if (r < 0)
46,065✔
562
                        return r; /* config_parse() logs internally. */
563
                assert(r > 0);
46,065✔
564

565
                if (ret_stats_by_path) {
46,065✔
566
                        r = hashmap_put_stats_by_path(&stats_by_path, *fn, &st);
9,494✔
567
                        if (r < 0)
9,494✔
568
                                return log_full_errno(level, r, "Failed to save stats of %s: %m", *fn);
×
569
                }
570

571
                break;
572
        }
573

574
        /* Then read all the drop-ins. */
575

576
        const char *path_dropin;
46,088✔
577
        FILE *f_dropin;
46,088✔
578
        ORDERED_HASHMAP_FOREACH_KEY(f_dropin, path_dropin, dropins) {
92,675✔
579
                r = config_parse(/* unit= */ NULL, path_dropin, f_dropin, sections, lookup, table, flags, userdata, &st);
499✔
580
                if (r < 0)
499✔
581
                        return r; /* config_parse() logs internally. */
×
582
                assert(r > 0);
499✔
583

584
                if (ret_stats_by_path) {
499✔
585
                        r = hashmap_put_stats_by_path(&stats_by_path, path_dropin, &st);
240✔
586
                        if (r < 0)
240✔
587
                                return log_full_errno(level, r, "Failed to save stats of %s: %m", path_dropin);
×
588
                }
589
        }
590

591
        if (ret_stats_by_path)
46,088✔
592
                *ret_stats_by_path = TAKE_PTR(stats_by_path);
9,494✔
593

594
        return 0;
595
}
596

597
/* Parse each config file in the directories specified as strv. */
598
int config_parse_many(
46,088✔
599
                const char* const* conf_files,
600
                const char* const* conf_file_dirs,
601
                const char *dropin_dirname,
602
                const char *root,
603
                const char *sections,
604
                ConfigItemLookup lookup,
605
                const void *table,
606
                ConfigParseFlags flags,
607
                void *userdata,
608
                Hashmap **ret_stats_by_path,
609
                char ***ret_dropin_files) {
610

611
        _cleanup_strv_free_ char **files = NULL;
46,088✔
612
        int r;
46,088✔
613

614
        assert(conf_file_dirs);
46,088✔
615
        assert(dropin_dirname);
46,088✔
616
        assert(table);
46,088✔
617

618
        r = conf_files_list_dropins(&files, dropin_dirname, root, conf_file_dirs);
46,088✔
619
        if (r < 0)
46,088✔
620
                return log_full_errno(FLAGS_SET(flags, CONFIG_PARSE_WARN) ? LOG_WARNING : LOG_DEBUG, r,
×
621
                                      "Failed to list up drop-in configs in %s: %m", dropin_dirname);
622

623
        r = config_parse_many_files(root, conf_files, files, sections, lookup, table, flags, userdata, ret_stats_by_path);
46,088✔
624
        if (r < 0)
46,088✔
625
                return r; /* config_parse_many_files() logs internally. */
626

627
        if (ret_dropin_files)
46,088✔
628
                *ret_dropin_files = TAKE_PTR(files);
9,808✔
629

630
        return 0;
631
}
632

633
int config_parse_standard_file_with_dropins_full(
34,621✔
634
                const char *root,
635
                const char *main_file,    /* A path like "systemd/frobnicator.conf" */
636
                const char *sections,
637
                ConfigItemLookup lookup,
638
                const void *table,
639
                ConfigParseFlags flags,
640
                void *userdata,
641
                Hashmap **ret_stats_by_path,
642
                char ***ret_dropin_files) {
643

644
        const char* const *conf_paths = (const char* const*) CONF_PATHS_STRV("");
34,621✔
645
        _cleanup_strv_free_ char **configs = NULL;
34,621✔
646
        int r, level = FLAGS_SET(flags, CONFIG_PARSE_WARN) ? LOG_WARNING : LOG_DEBUG;
34,621✔
647

648
        /* Build the list of main config files */
649
        r = strv_extend_strv_biconcat(&configs, root, conf_paths, main_file);
34,621✔
650
        if (r < 0)
34,621✔
651
                return log_oom_full(level);
×
652

653
        _cleanup_free_ char *dropin_dirname = strjoin(main_file, ".d");
69,242✔
654
        if (!dropin_dirname)
34,621✔
655
                return log_oom_full(level);
×
656

657
        return config_parse_many(
34,621✔
658
                        (const char* const*) configs,
659
                        conf_paths,
660
                        dropin_dirname,
661
                        root,
662
                        sections,
663
                        lookup,
664
                        table,
665
                        flags,
666
                        userdata,
667
                        ret_stats_by_path,
668
                        ret_dropin_files);
669
}
670

671
static int dropins_get_stats_by_path(
2,705✔
672
                const char* conf_file,
673
                const char* const* conf_file_dirs,
674
                Hashmap **stats_by_path) {
675

676
        _cleanup_strv_free_ char **files = NULL;
×
677
        _cleanup_free_ char *dropin_dirname = NULL;
2,705✔
678
        int r;
2,705✔
679

680
        assert(conf_file);
2,705✔
681
        assert(conf_file_dirs);
2,705✔
682
        assert(stats_by_path);
2,705✔
683

684
        r = path_extract_filename(conf_file, &dropin_dirname);
2,705✔
685
        if (r < 0)
2,705✔
686
                return r;
687
        if (r == O_DIRECTORY)
2,705✔
688
                return -EINVAL;
689

690
        if (!strextend(&dropin_dirname, ".d"))
2,705✔
691
                return -ENOMEM;
692

693
        r = conf_files_list_dropins(&files, dropin_dirname, /* root = */ NULL, conf_file_dirs);
2,705✔
694
        if (r < 0)
2,705✔
695
                return r;
696

697
        STRV_FOREACH(fn, files) {
2,716✔
698
                struct stat st;
11✔
699

700
                if (stat(*fn, &st) < 0) {
11✔
701
                        if (errno == ENOENT)
×
702
                                continue;
×
703

704
                        return -errno;
×
705
                }
706

707
                r = hashmap_put_stats_by_path(stats_by_path, *fn, &st);
11✔
708
                if (r < 0)
11✔
709
                        return r;
710
        }
711

712
        return 0;
713
}
714

715
int config_get_stats_by_path(
668✔
716
                const char *suffix,
717
                const char *root,
718
                unsigned flags,
719
                const char* const* dirs,
720
                bool check_dropins,
721
                Hashmap **ret) {
722

723
        _cleanup_hashmap_free_ Hashmap *stats_by_path = NULL;
668✔
724
        _cleanup_strv_free_ char **files = NULL;
668✔
725
        int r;
668✔
726

727
        assert(suffix);
668✔
728
        assert(dirs);
668✔
729
        assert(ret);
668✔
730

731
        /* Unlike config_parse(), this does not support stream. */
732

733
        r = conf_files_list_strv(&files, suffix, root, flags, dirs);
668✔
734
        if (r < 0)
668✔
735
                return r;
736

737
        STRV_FOREACH(f, files) {
28,687✔
738
                struct stat st;
28,019✔
739

740
                /* First read the main config file. */
741
                if (stat(*f, &st) < 0) {
28,019✔
742
                        if (errno == ENOENT)
×
743
                                continue;
25,314✔
744

745
                        return -errno;
×
746
                }
747

748
                /* Skipping an empty file. */
749
                if (null_or_empty(&st))
28,019✔
750
                        continue;
×
751

752
                r = hashmap_put_stats_by_path(&stats_by_path, *f, &st);
28,019✔
753
                if (r < 0)
28,019✔
754
                        return r;
755

756
                if (!check_dropins)
28,019✔
757
                        continue;
25,314✔
758

759
                /* Then read all the drop-ins if requested. */
760
                r = dropins_get_stats_by_path(*f, dirs, &stats_by_path);
2,705✔
761
                if (r < 0)
2,705✔
762
                        return r;
763
        }
764

765
        *ret = TAKE_PTR(stats_by_path);
668✔
766
        return 0;
668✔
767
}
768

769
bool stats_by_path_equal(Hashmap *a, Hashmap *b) {
2,590✔
770
        struct stat *st_a, *st_b;
2,590✔
771
        const char *path;
2,590✔
772

773
        if (hashmap_size(a) != hashmap_size(b))
2,590✔
774
                return false;
2,590✔
775

776
        HASHMAP_FOREACH_KEY(st_a, path, a) {
29,349✔
777
                st_b = hashmap_get(b, path);
27,058✔
778
                if (!st_b)
27,058✔
779
                        return false;
195✔
780

781
                if (!stat_inode_unmodified(st_a, st_b))
27,056✔
782
                        return false;
783
        }
784

785
        return true;
2,291✔
786
}
787

788
int config_section_parse(
6,764✔
789
                const ConfigSectionParser *parsers,
790
                size_t n_parsers,
791
                const char *unit,
792
                const char *filename,
793
                unsigned line,
794
                const char *section,
795
                unsigned section_line,
796
                const char *lvalue,
797
                int ltype,
798
                const char *rvalue,
799
                void *userdata) {
800

801
        assert(parsers);
6,764✔
802
        assert(n_parsers > 0);
6,764✔
803
        assert(ltype >= 0);
6,764✔
804
        assert((size_t) ltype < n_parsers);
6,764✔
805
        assert(userdata);
6,764✔
806

807
        const ConfigSectionParser *e = parsers + ltype;
6,764✔
808
        assert(e->parser);
6,764✔
809

810
        /* This is used when a object is dynamically allocated per [SECTION] in a config parser, e.g.
811
         * [Address] for systemd.network. Takes the allocated object as 'userdata', then it is passed to
812
         * config parsers in the table. The 'data' field points to an element of the passed object, where
813
         * its offset is given by the table. */
814

815
        return e->parser(unit, filename, line, section, section_line, lvalue, e->ltype, rvalue,
13,528✔
816
                         (uint8_t*) userdata + e->offset, userdata);
6,764✔
817
}
818

819
void config_section_hash_func(const ConfigSection *c, struct siphash *state) {
18,500✔
820
        siphash24_compress_string(c->filename, state);
18,500✔
821
        siphash24_compress_typesafe(c->line, state);
18,500✔
822
}
18,500✔
823

824
int config_section_compare_func(const ConfigSection *x, const ConfigSection *y) {
6,200✔
825
        int r;
6,200✔
826

827
        r = strcmp(x->filename, y->filename);
6,200✔
828
        if (r != 0)
6,200✔
829
                return r;
830

831
        return CMP(x->line, y->line);
5,755✔
832
}
833

834
DEFINE_HASH_OPS(config_section_hash_ops, ConfigSection, config_section_hash_func, config_section_compare_func);
835

836
int config_section_new(const char *filename, unsigned line, ConfigSection **ret) {
7,723✔
837
        ConfigSection *cs;
7,723✔
838

839
        assert(filename);
7,723✔
840
        assert(line > 0);
7,723✔
841
        assert(ret);
7,723✔
842

843
        cs = malloc0(offsetof(ConfigSection, filename) + strlen(filename) + 1);
7,723✔
844
        if (!cs)
7,723✔
845
                return -ENOMEM;
7,723✔
846

847
        strcpy(cs->filename, filename);
7,723✔
848
        cs->line = line;
7,723✔
849

850
        *ret = TAKE_PTR(cs);
7,723✔
851
        return 0;
7,723✔
852
}
853

854
static int _hashmap_by_section_find_unused_line(
34✔
855
                HashmapBase *entries_by_section,
856
                const char *filename,
857
                unsigned *ret) {
858

859
        ConfigSection *cs;
34✔
860
        unsigned n = 0;
34✔
861
        void *entry;
34✔
862

863
        HASHMAP_BASE_FOREACH_KEY(entry, cs, entries_by_section) {
544✔
864
                if (filename && !streq(cs->filename, filename))
510✔
865
                        continue;
×
866
                n = MAX(n, cs->line);
510✔
867
        }
868

869
        /* overflow? */
870
        if (n >= UINT_MAX)
34✔
871
                return -EFBIG;
34✔
872

873
        *ret = n + 1;
34✔
874
        return 0;
34✔
875
}
876

877
int hashmap_by_section_find_unused_line(
20✔
878
        Hashmap *entries_by_section,
879
        const char *filename,
880
        unsigned *ret) {
881

882
        return _hashmap_by_section_find_unused_line(HASHMAP_BASE(entries_by_section), filename, ret);
20✔
883
}
884

885
int ordered_hashmap_by_section_find_unused_line(
14✔
886
        OrderedHashmap *entries_by_section,
887
        const char *filename,
888
        unsigned *ret) {
889

890
        return _hashmap_by_section_find_unused_line(HASHMAP_BASE(entries_by_section), filename, ret);
14✔
891
}
892

893
#define DEFINE_PARSER(type, vartype, conv_func)                         \
894
        DEFINE_CONFIG_PARSE_PTR(config_parse_##type, conv_func, vartype)
895

896
DEFINE_PARSER(int, int, safe_atoi);
190✔
897
DEFINE_PARSER(long, long, safe_atoli);
×
898
DEFINE_PARSER(uint8, uint8_t, safe_atou8);
23✔
899
DEFINE_PARSER(uint16, uint16_t, safe_atou16);
5✔
900
DEFINE_PARSER(uint32, uint32_t, safe_atou32);
174✔
901
DEFINE_PARSER(int32, int32_t, safe_atoi32);
12✔
902
DEFINE_PARSER(uint64, uint64_t, safe_atou64);
187✔
903
DEFINE_PARSER(unsigned, unsigned, safe_atou);
1,820✔
904
DEFINE_PARSER(double, double, safe_atod);
×
905
DEFINE_PARSER(nsec, nsec_t, parse_nsec);
7✔
906
DEFINE_PARSER(sec, usec_t, parse_sec);
3,614✔
907
DEFINE_PARSER(sec_def_infinity, usec_t, parse_sec_def_infinity);
×
908
DEFINE_PARSER(mode, mode_t, parse_mode);
6,277✔
909
DEFINE_PARSER(pid, pid_t, parse_pid);
3✔
910

911
int config_parse_iec_size(
770✔
912
                const char *unit,
913
                const char *filename,
914
                unsigned line,
915
                const char *section,
916
                unsigned section_line,
917
                const char *lvalue,
918
                int ltype,
919
                const char *rvalue,
920
                void *data,
921
                void *userdata) {
922

923
        size_t *sz = ASSERT_PTR(data);
770✔
924
        uint64_t v;
770✔
925
        int r;
770✔
926

927
        assert(filename);
770✔
928
        assert(lvalue);
770✔
929
        assert(rvalue);
770✔
930

931
        r = parse_size(rvalue, 1024, &v);
770✔
932
        if (r >= 0 && (uint64_t) (size_t) v != v)
770✔
933
                r = -ERANGE;
934
        if (r < 0)
770✔
935
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
3✔
936

937
        *sz = (size_t) v;
767✔
938
        return 1;
767✔
939
}
940

941
int config_parse_si_uint64(
9✔
942
                const char *unit,
943
                const char *filename,
944
                unsigned line,
945
                const char *section,
946
                unsigned section_line,
947
                const char *lvalue,
948
                int ltype,
949
                const char *rvalue,
950
                void *data,
951
                void *userdata) {
952

953
        uint64_t *sz = ASSERT_PTR(data);
9✔
954
        int r;
9✔
955

956
        assert(filename);
9✔
957
        assert(lvalue);
9✔
958
        assert(rvalue);
9✔
959

960
        r = parse_size(rvalue, 1000, sz);
9✔
961
        if (r < 0)
9✔
962
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
3✔
963

964
        return 1;
965
}
966

967
int config_parse_iec_uint64(
2✔
968
                const char *unit,
969
                const char *filename,
970
                unsigned line,
971
                const char *section,
972
                unsigned section_line,
973
                const char *lvalue,
974
                int ltype,
975
                const char *rvalue,
976
                void *data,
977
                void *userdata) {
978

979
        uint64_t *bytes = ASSERT_PTR(data);
2✔
980
        int r;
2✔
981

982
        assert(filename);
2✔
983
        assert(lvalue);
2✔
984
        assert(rvalue);
2✔
985

986
        r = parse_size(rvalue, 1024, bytes);
2✔
987
        if (r < 0)
2✔
988
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
989

990
        return 1;
991
}
992

993
int config_parse_iec_uint64_infinity(
×
994
                const char *unit,
995
                const char *filename,
996
                unsigned line,
997
                const char *section,
998
                unsigned section_line,
999
                const char *lvalue,
1000
                int ltype,
1001
                const char *rvalue,
1002
                void *data,
1003
                void *userdata) {
1004

1005
        uint64_t *bytes = ASSERT_PTR(data);
×
1006

1007
        assert(rvalue);
×
1008

1009
        if (streq(rvalue, "infinity")) {
×
1010
                *bytes = UINT64_MAX;
×
1011
                return 1;
×
1012
        }
1013

1014
        return config_parse_iec_uint64(unit, filename, line, section, section_line, lvalue, ltype, rvalue, data, userdata);
×
1015
}
1016

1017
int config_parse_bool(
50,478✔
1018
                const char *unit,
1019
                const char *filename,
1020
                unsigned line,
1021
                const char *section,
1022
                unsigned section_line,
1023
                const char *lvalue,
1024
                int ltype,
1025
                const char *rvalue,
1026
                void *data,
1027
                void *userdata) {
1028

1029
        bool *b = ASSERT_PTR(data);
50,478✔
1030
        bool fatal = ltype;
50,478✔
1031
        int r;
50,478✔
1032

1033
        assert(filename);
50,478✔
1034
        assert(lvalue);
50,478✔
1035
        assert(rvalue);
50,478✔
1036

1037
        r = parse_boolean(rvalue);
50,478✔
1038
        if (r < 0) {
50,478✔
1039
                log_syntax_parse_error_full(unit, filename, line, r, fatal, lvalue, rvalue);
×
1040
                return fatal ? -ENOEXEC : 0;
×
1041
        }
1042

1043
        *b = r;
50,478✔
1044
        return 1; /* set */
50,478✔
1045
}
1046

1047
int config_parse_uint32_flag(
68✔
1048
                const char *unit,
1049
                const char *filename,
1050
                unsigned line,
1051
                const char *section,
1052
                unsigned section_line,
1053
                const char *lvalue,
1054
                int ltype,
1055
                const char *rvalue,
1056
                void *data,
1057
                void *userdata) {
1058

1059
        uint32_t *flags = ASSERT_PTR(data);
68✔
1060
        int r;
68✔
1061

1062
        assert(ltype != 0);
68✔
1063

1064
        r = isempty(rvalue) ? 0 : parse_boolean(rvalue);
136✔
1065
        if (r < 0)
68✔
1066
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1067

1068
        SET_FLAG(*flags, ltype, r);
68✔
1069
        return 1;
68✔
1070
}
1071

1072
int config_parse_uint32_invert_flag(
66✔
1073
                const char *unit,
1074
                const char *filename,
1075
                unsigned line,
1076
                const char *section,
1077
                unsigned section_line,
1078
                const char *lvalue,
1079
                int ltype,
1080
                const char *rvalue,
1081
                void *data,
1082
                void *userdata) {
1083

1084
        uint32_t *flags = ASSERT_PTR(data);
66✔
1085
        int r;
66✔
1086

1087
        assert(ltype != 0);
66✔
1088

1089
        r = isempty(rvalue) ? 0 : parse_boolean(rvalue);
132✔
1090
        if (r < 0)
66✔
1091
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1092

1093
        SET_FLAG(*flags, ltype, !r);
66✔
1094
        return 1;
66✔
1095
}
1096

1097
int config_parse_id128(
11✔
1098
                const char *unit,
1099
                const char *filename,
1100
                unsigned line,
1101
                const char *section,
1102
                unsigned section_line,
1103
                const char *lvalue,
1104
                int ltype,
1105
                const char *rvalue,
1106
                void *data,
1107
                void *userdata) {
1108

1109
        sd_id128_t *result = data;
11✔
1110
        int r;
11✔
1111

1112
        assert(filename);
11✔
1113
        assert(lvalue);
11✔
1114
        assert(rvalue);
11✔
1115

1116
        r = id128_from_string_nonzero(rvalue, result);
11✔
1117
        if (r == -ENXIO) {
11✔
1118
                log_syntax(unit, LOG_WARNING, filename, line, r, "128-bit ID/UUID is all 0, ignoring: %s", rvalue);
×
1119
                return 0;
×
1120
        }
1121
        if (r < 0)
11✔
1122
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1123

1124
        return 1;
1125
}
1126

1127
int config_parse_tristate(
5,500✔
1128
                const char *unit,
1129
                const char *filename,
1130
                unsigned line,
1131
                const char *section,
1132
                unsigned section_line,
1133
                const char *lvalue,
1134
                int ltype,
1135
                const char *rvalue,
1136
                void *data,
1137
                void *userdata) {
1138

1139
        int r, *t = ASSERT_PTR(data);
5,500✔
1140

1141
        assert(filename);
5,500✔
1142
        assert(lvalue);
5,500✔
1143
        assert(rvalue);
5,500✔
1144

1145
        /* A tristate is pretty much a boolean, except that it can also take an empty string,
1146
         * indicating "uninitialized", much like NULL is for a pointer type. */
1147

1148
        if (isempty(rvalue)) {
5,500✔
1149
                *t = -1;
×
1150
                return 1;
×
1151
        }
1152

1153
        r = parse_tristate(rvalue, t);
5,500✔
1154
        if (r < 0)
5,500✔
1155
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1156

1157
        return 1;
1158
}
1159

1160
int config_parse_string(
32,716✔
1161
                const char *unit,
1162
                const char *filename,
1163
                unsigned line,
1164
                const char *section,
1165
                unsigned section_line,
1166
                const char *lvalue,
1167
                int ltype,
1168
                const char *rvalue,
1169
                void *data,
1170
                void *userdata) {
1171

1172
        char **s = ASSERT_PTR(data);
32,716✔
1173
        int r;
32,716✔
1174

1175
        assert(filename);
32,716✔
1176
        assert(lvalue);
32,716✔
1177
        assert(rvalue);
32,716✔
1178

1179
        if (isempty(rvalue)) {
32,716✔
1180
                *s = mfree(*s);
×
1181
                return 1;
×
1182
        }
1183

1184
        if (FLAGS_SET(ltype, CONFIG_PARSE_STRING_SAFE) && !string_is_safe(rvalue)) {
32,716✔
1185
                _cleanup_free_ char *escaped = NULL;
×
1186

1187
                escaped = cescape(rvalue);
×
1188
                log_syntax(unit, LOG_WARNING, filename, line, 0,
×
1189
                           "Specified string contains unsafe characters, ignoring: %s", strna(escaped));
1190
                return 0;
×
1191
        }
1192

1193
        if (FLAGS_SET(ltype, CONFIG_PARSE_STRING_ASCII) && !ascii_is_valid(rvalue)) {
32,724✔
1194
                _cleanup_free_ char *escaped = NULL;
×
1195

1196
                escaped = cescape(rvalue);
×
1197
                log_syntax(unit, LOG_WARNING, filename, line, 0,
×
1198
                           "Specified string contains invalid ASCII characters, ignoring: %s", strna(escaped));
1199
                return 0;
×
1200
        }
1201

1202
        r = free_and_strdup_warn(s, rvalue);
32,716✔
1203
        if (r < 0)
32,716✔
1204
                return r;
×
1205

1206
        return 1;
1207
}
1208

1209
int config_parse_dns_name(
22✔
1210
                const char *unit,
1211
                const char *filename,
1212
                unsigned line,
1213
                const char *section,
1214
                unsigned section_line,
1215
                const char *lvalue,
1216
                int ltype,
1217
                const char *rvalue,
1218
                void *data,
1219
                void *userdata) {
1220

1221
        char **hostname = ASSERT_PTR(data);
22✔
1222
        int r;
22✔
1223

1224
        assert(filename);
22✔
1225
        assert(lvalue);
22✔
1226
        assert(rvalue);
22✔
1227

1228
        if (isempty(rvalue)) {
22✔
1229
                *hostname = mfree(*hostname);
×
1230
                return 1;
×
1231
        }
1232

1233
        r = dns_name_is_valid(rvalue);
22✔
1234
        if (r < 0) {
22✔
1235
                log_syntax(unit, LOG_WARNING, filename, line, r,
×
1236
                           "Failed to check validity of DNS domain name '%s', ignoring assignment: %m", rvalue);
1237
                return 0;
×
1238
        }
1239
        if (r == 0) {
22✔
1240
                log_syntax(unit, LOG_WARNING, filename, line, 0,
×
1241
                           "Specified invalid DNS domain name, ignoring assignment: %s", rvalue);
1242
                return 0;
×
1243
        }
1244

1245
        r = free_and_strdup_warn(hostname, rvalue);
22✔
1246
        if (r < 0)
22✔
1247
                return r;
×
1248

1249
        return 1;
1250
}
1251

1252
int config_parse_hostname(
22✔
1253
                const char *unit,
1254
                const char *filename,
1255
                unsigned line,
1256
                const char *section,
1257
                unsigned section_line,
1258
                const char *lvalue,
1259
                int ltype,
1260
                const char *rvalue,
1261
                void *data,
1262
                void *userdata) {
1263

1264
        char **hostname = ASSERT_PTR(data);
22✔
1265

1266
        assert(filename);
22✔
1267
        assert(lvalue);
22✔
1268
        assert(rvalue);
22✔
1269

1270
        if (isempty(rvalue)) {
22✔
1271
                *hostname = mfree(*hostname);
×
1272
                return 1;
×
1273
        }
1274

1275
        if (!hostname_is_valid(rvalue, 0)) {
22✔
1276
                log_syntax(unit, LOG_WARNING, filename, line, 0,
×
1277
                           "Specified invalid hostname, ignoring assignment: %s", rvalue);
1278
                return 0;
×
1279
        }
1280

1281
        return config_parse_dns_name(unit, filename, line, section, section_line,
22✔
1282
                                     lvalue, ltype, rvalue, data, userdata);
1283
}
1284

1285
int config_parse_path(
1,410✔
1286
                const char *unit,
1287
                const char *filename,
1288
                unsigned line,
1289
                const char *section,
1290
                unsigned section_line,
1291
                const char *lvalue,
1292
                int ltype,
1293
                const char *rvalue,
1294
                void *data,
1295
                void *userdata) {
1296

1297
        _cleanup_free_ char *n = NULL;
1,410✔
1298
        bool fatal = ltype;
1,410✔
1299
        char **s = ASSERT_PTR(data);
1,410✔
1300
        int r;
1,410✔
1301

1302
        assert(filename);
1,410✔
1303
        assert(lvalue);
1,410✔
1304
        assert(rvalue);
1,410✔
1305

1306
        if (isempty(rvalue)) {
1,410✔
1307
                *s = mfree(*s);
×
1308
                return 1;
×
1309
        }
1310

1311
        n = strdup(rvalue);
1,410✔
1312
        if (!n)
1,410✔
1313
                return log_oom();
×
1314

1315
        r = path_simplify_and_warn(n, PATH_CHECK_ABSOLUTE | (fatal ? PATH_CHECK_FATAL : 0), unit, filename, line, lvalue);
2,820✔
1316
        if (r < 0)
1,410✔
1317
                return fatal ? -ENOEXEC : 0;
2✔
1318

1319
        free_and_replace(*s, n);
1,408✔
1320
        return 1;
1,408✔
1321
}
1322

1323
int config_parse_strv(
31,313✔
1324
                const char *unit,
1325
                const char *filename,
1326
                unsigned line,
1327
                const char *section,
1328
                unsigned section_line,
1329
                const char *lvalue,
1330
                int ltype, /* When true, duplicated entries will be filtered. */
1331
                const char *rvalue,
1332
                void *data,
1333
                void *userdata) {
1334

1335
        char ***sv = ASSERT_PTR(data);
31,313✔
1336
        int r;
31,313✔
1337

1338
        assert(filename);
31,313✔
1339
        assert(lvalue);
31,313✔
1340
        assert(rvalue);
31,313✔
1341

1342
        if (isempty(rvalue)) {
31,313✔
1343
                *sv = strv_free(*sv);
2✔
1344
                return 1;
31,313✔
1345
        }
1346

1347
        _cleanup_strv_free_ char **strv = NULL;
31,311✔
1348
        for (const char *p = rvalue;;) {
68,174✔
1349
                char *word;
68,174✔
1350

1351
                r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
68,174✔
1352
                if (r < 0)
68,174✔
1353
                        return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1354
                if (r == 0)
68,174✔
1355
                        break;
1356

1357
                r = strv_consume(&strv, word);
36,863✔
1358
                if (r < 0)
36,863✔
1359
                        return log_oom();
×
1360
        }
1361

1362
        r = strv_extend_strv_consume(sv, TAKE_PTR(strv), /* filter_duplicates = */ ltype);
31,311✔
1363
        if (r < 0)
31,311✔
1364
                return log_oom();
×
1365

1366
        return 1;
1367
}
1368

1369
int config_parse_warn_compat(
×
1370
                const char *unit,
1371
                const char *filename,
1372
                unsigned line,
1373
                const char *section,
1374
                unsigned section_line,
1375
                const char *lvalue,
1376
                int ltype,
1377
                const char *rvalue,
1378
                void *data,
1379
                void *userdata) {
1380

1381
        Disabled reason = ltype;
×
1382

1383
        switch (reason) {
×
1384

1385
        case DISABLED_CONFIGURATION:
×
1386
                log_syntax(unit, LOG_DEBUG, filename, line, 0,
×
1387
                           "Support for option %s= has been disabled at compile time and it is ignored", lvalue);
1388
                break;
1389

1390
        case DISABLED_LEGACY:
×
1391
                log_syntax(unit, LOG_INFO, filename, line, 0,
×
1392
                           "Support for option %s= has been removed and it is ignored", lvalue);
1393
                break;
1394

1395
        case DISABLED_EXPERIMENTAL:
×
1396
                log_syntax(unit, LOG_INFO, filename, line, 0,
×
1397
                           "Support for option %s= has not yet been enabled and it is ignored", lvalue);
1398
                break;
1399
        }
1400

1401
        return 0;
×
1402
}
1403

1404
int config_parse_log_facility(
3✔
1405
                const char *unit,
1406
                const char *filename,
1407
                unsigned line,
1408
                const char *section,
1409
                unsigned section_line,
1410
                const char *lvalue,
1411
                int ltype,
1412
                const char *rvalue,
1413
                void *data,
1414
                void *userdata) {
1415

1416
        int *o = data, x;
3✔
1417

1418
        assert(filename);
3✔
1419
        assert(lvalue);
3✔
1420
        assert(rvalue);
3✔
1421
        assert(data);
3✔
1422

1423
        x = log_facility_unshifted_from_string(rvalue);
3✔
1424
        if (x < 0)
3✔
1425
                return log_syntax_parse_error(unit, filename, line, x, lvalue, rvalue);
1✔
1426

1427
        *o = (x << 3) | LOG_PRI(*o);
2✔
1428

1429
        return 1;
2✔
1430
}
1431

1432
int config_parse_log_level(
3✔
1433
                const char *unit,
1434
                const char *filename,
1435
                unsigned line,
1436
                const char *section,
1437
                unsigned section_line,
1438
                const char *lvalue,
1439
                int ltype,
1440
                const char *rvalue,
1441
                void *data,
1442
                void *userdata) {
1443

1444
        int *o = data, x;
3✔
1445

1446
        assert(filename);
3✔
1447
        assert(lvalue);
3✔
1448
        assert(rvalue);
3✔
1449
        assert(data);
3✔
1450

1451
        x = log_level_from_string(rvalue);
3✔
1452
        if (x < 0)
3✔
1453
                return log_syntax_parse_error(unit, filename, line, x, lvalue, rvalue);
1✔
1454

1455
        if (*o < 0) /* if it wasn't initialized so far, assume zero facility */
2✔
1456
                *o = x;
×
1457
        else
1458
                *o = (*o & LOG_FACMASK) | x;
2✔
1459

1460
        return 1;
1461
}
1462

1463
int config_parse_signal(
242✔
1464
                const char *unit,
1465
                const char *filename,
1466
                unsigned line,
1467
                const char *section,
1468
                unsigned section_line,
1469
                const char *lvalue,
1470
                int ltype,
1471
                const char *rvalue,
1472
                void *data,
1473
                void *userdata) {
1474

1475
        int *sig = data, r;
242✔
1476

1477
        assert(filename);
242✔
1478
        assert(lvalue);
242✔
1479
        assert(rvalue);
242✔
1480
        assert(sig);
242✔
1481

1482
        r = signal_from_string(rvalue);
242✔
1483
        if (r <= 0)
242✔
1484
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1485

1486
        *sig = r;
242✔
1487
        return 1;
242✔
1488
}
1489

1490
int config_parse_personality(
×
1491
                const char *unit,
1492
                const char *filename,
1493
                unsigned line,
1494
                const char *section,
1495
                unsigned section_line,
1496
                const char *lvalue,
1497
                int ltype,
1498
                const char *rvalue,
1499
                void *data,
1500
                void *userdata) {
1501

1502
        unsigned long *personality = data, p;
×
1503

1504
        assert(filename);
×
1505
        assert(lvalue);
×
1506
        assert(rvalue);
×
1507
        assert(personality);
×
1508

1509
        if (isempty(rvalue)) {
×
1510
                *personality = PERSONALITY_INVALID;
×
1511
                return 1;
×
1512
        }
1513

1514
        p = personality_from_string(rvalue);
×
1515
        if (p == PERSONALITY_INVALID)
×
1516
                return log_syntax_parse_error(unit, filename, line, 0, lvalue, rvalue);
×
1517

1518
        *personality = p;
×
1519
        return 1;
×
1520
}
1521

1522
int config_parse_ifname(
1,943✔
1523
                const char *unit,
1524
                const char *filename,
1525
                unsigned line,
1526
                const char *section,
1527
                unsigned section_line,
1528
                const char *lvalue,
1529
                int ltype,
1530
                const char *rvalue,
1531
                void *data,
1532
                void *userdata) {
1533

1534
        char **s = ASSERT_PTR(data);
1,943✔
1535
        int r;
1,943✔
1536

1537
        assert(filename);
1,943✔
1538
        assert(lvalue);
1,943✔
1539
        assert(rvalue);
1,943✔
1540

1541
        if (isempty(rvalue)) {
1,943✔
1542
                *s = mfree(*s);
×
1543
                return 1;
×
1544
        }
1545

1546
        if (!ifname_valid(rvalue)) {
1,943✔
1547
                log_syntax(unit, LOG_WARNING, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue);
×
1548
                return 0;
×
1549
        }
1550

1551
        r = free_and_strdup_warn(s, rvalue);
1,943✔
1552
        if (r < 0)
1,943✔
1553
                return r;
×
1554

1555
        return 1;
1556
}
1557

1558
int config_parse_ifnames(
16✔
1559
                const char *unit,
1560
                const char *filename,
1561
                unsigned line,
1562
                const char *section,
1563
                unsigned section_line,
1564
                const char *lvalue,
1565
                int ltype,
1566
                const char *rvalue,
1567
                void *data,
1568
                void *userdata) {
1569

1570
        _cleanup_strv_free_ char **names = NULL;
16✔
1571
        char ***s = ASSERT_PTR(data);
16✔
1572
        int r;
16✔
1573

1574
        assert(filename);
16✔
1575
        assert(lvalue);
16✔
1576
        assert(rvalue);
16✔
1577

1578
        if (isempty(rvalue)) {
16✔
1579
                *s = strv_free(*s);
×
1580
                return 1;
×
1581
        }
1582

1583
        for (const char *p = rvalue;;) {
16✔
1584
                _cleanup_free_ char *word = NULL;
30✔
1585

1586
                r = extract_first_word(&p, &word, NULL, 0);
46✔
1587
                if (r < 0)
46✔
1588
                        return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1589
                if (r == 0)
46✔
1590
                        break;
1591

1592
                if (!ifname_valid_full(word, ltype)) {
30✔
1593
                        log_syntax(unit, LOG_WARNING, filename, line, 0,
×
1594
                                   "Interface name is not valid or too long, ignoring assignment: %s",
1595
                                   word);
1596
                        continue;
×
1597
                }
1598

1599
                r = strv_consume(&names, TAKE_PTR(word));
30✔
1600
                if (r < 0)
30✔
1601
                        return log_oom();
×
1602
        }
1603

1604
        r = strv_extend_strv(s, names, true);
16✔
1605
        if (r < 0)
16✔
1606
                return log_oom();
×
1607

1608
        return 1;
1609
}
1610

1611
int config_parse_ip_port(
27✔
1612
                const char *unit,
1613
                const char *filename,
1614
                unsigned line,
1615
                const char *section,
1616
                unsigned section_line,
1617
                const char *lvalue,
1618
                int ltype,
1619
                const char *rvalue,
1620
                void *data,
1621
                void *userdata) {
1622

1623
        uint16_t *s = ASSERT_PTR(data);
27✔
1624
        uint16_t port;
27✔
1625
        int r;
27✔
1626

1627
        assert(filename);
27✔
1628
        assert(lvalue);
27✔
1629
        assert(rvalue);
27✔
1630

1631
        if (isempty(rvalue)) {
27✔
1632
                *s = 0;
×
1633
                return 1;
×
1634
        }
1635

1636
        r = parse_ip_port(rvalue, &port);
27✔
1637
        if (r < 0)
27✔
1638
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1639

1640
        *s = port;
27✔
1641
        return 1;
27✔
1642
}
1643

1644
int config_parse_mtu(
173✔
1645
                const char *unit,
1646
                const char *filename,
1647
                unsigned line,
1648
                const char *section,
1649
                unsigned section_line,
1650
                const char *lvalue,
1651
                int ltype,
1652
                const char *rvalue,
1653
                void *data,
1654
                void *userdata) {
1655

1656
        uint32_t *mtu = ASSERT_PTR(data);
173✔
1657
        int r;
173✔
1658

1659
        assert(rvalue);
173✔
1660

1661
        r = parse_mtu(ltype, rvalue, mtu);
173✔
1662
        if (r == -ERANGE) {
173✔
1663
                log_syntax(unit, LOG_WARNING, filename, line, r,
×
1664
                           "Maximum transfer unit (MTU) value out of range. Permitted range is %" PRIu32 "…%" PRIu32 ", ignoring: %s",
1665
                           (uint32_t) (ltype == AF_INET6 ? IPV6_MIN_MTU : IPV4_MIN_MTU), (uint32_t) UINT32_MAX,
1666
                           rvalue);
1667
                return 0;
×
1668
        }
1669
        if (r < 0)
173✔
1670
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1671

1672
        return 1;
1673
}
1674

1675
int config_parse_rlimit(
777✔
1676
                const char *unit,
1677
                const char *filename,
1678
                unsigned line,
1679
                const char *section,
1680
                unsigned section_line,
1681
                const char *lvalue,
1682
                int ltype,
1683
                const char *rvalue,
1684
                void *data,
1685
                void *userdata) {
1686

1687
        struct rlimit **rl = data, d = {};
777✔
1688
        int r;
777✔
1689

1690
        assert(rvalue);
777✔
1691
        assert(rl);
777✔
1692

1693
        r = rlimit_parse(ltype, rvalue, &d);
777✔
1694
        if (r == -EILSEQ) {
777✔
1695
                log_syntax(unit, LOG_WARNING, filename, line, r, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue);
1✔
1696
                return 0;
1✔
1697
        }
1698
        if (r < 0)
776✔
1699
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
3✔
1700

1701
        if (rl[ltype])
773✔
1702
                *rl[ltype] = d;
13✔
1703
        else {
1704
                rl[ltype] = newdup(struct rlimit, &d, 1);
760✔
1705
                if (!rl[ltype])
760✔
1706
                        return log_oom();
×
1707
        }
1708

1709
        return 1;
1710
}
1711

1712
int config_parse_permille(
×
1713
                const char *unit,
1714
                const char *filename,
1715
                unsigned line,
1716
                const char *section,
1717
                unsigned section_line,
1718
                const char *lvalue,
1719
                int ltype,
1720
                const char *rvalue,
1721
                void *data,
1722
                void *userdata) {
1723

1724
        unsigned *permille = ASSERT_PTR(data);
×
1725
        int r;
×
1726

1727
        assert(filename);
×
1728
        assert(lvalue);
×
1729
        assert(rvalue);
×
1730

1731
        r = parse_permille(rvalue);
×
1732
        if (r < 0)
×
1733
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1734

1735
        *permille = (unsigned) r;
×
1736
        return 1;
×
1737
}
1738

1739
int config_parse_vlanprotocol(
2✔
1740
                const char *unit,
1741
                const char *filename,
1742
                unsigned line,
1743
                const char *section,
1744
                unsigned section_line,
1745
                const char *lvalue,
1746
                int ltype,
1747
                const char *rvalue,
1748
                void *data,
1749
                void *userdata) {
1750

1751
        int *vlan_protocol = data;
2✔
1752

1753
        assert(filename);
2✔
1754
        assert(lvalue);
2✔
1755

1756
        if (isempty(rvalue)) {
2✔
1757
                *vlan_protocol = -1;
×
1758
                return 1;
×
1759
        }
1760

1761
        if (STR_IN_SET(rvalue, "802.1ad", "802.1AD"))
2✔
1762
                *vlan_protocol = ETH_P_8021AD;
2✔
1763
        else if (STR_IN_SET(rvalue, "802.1q", "802.1Q"))
×
1764
                *vlan_protocol = ETH_P_8021Q;
×
1765
        else
1766
                return log_syntax_parse_error(unit, filename, line, 0, lvalue, rvalue);
×
1767

1768
        return 1;
2✔
1769
}
1770

1771
int config_parse_hw_addr(
535✔
1772
                const char *unit,
1773
                const char *filename,
1774
                unsigned line,
1775
                const char *section,
1776
                unsigned section_line,
1777
                const char *lvalue,
1778
                int ltype,
1779
                const char *rvalue,
1780
                void *data,
1781
                void *userdata) {
1782

1783
        struct hw_addr_data *hwaddr = ASSERT_PTR(data);
535✔
1784
        int r;
535✔
1785

1786
        assert(filename);
535✔
1787
        assert(lvalue);
535✔
1788
        assert(rvalue);
535✔
1789

1790
        if (isempty(rvalue)) {
535✔
1791
                *hwaddr = HW_ADDR_NULL;
×
1792
                return 1;
×
1793
        }
1794

1795
        r = parse_hw_addr_full(rvalue, ltype, hwaddr);
535✔
1796
        if (r < 0)
535✔
1797
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1798

1799
        return 1;
1800
}
1801

1802
int config_parse_hw_addrs(
17✔
1803
                const char *unit,
1804
                const char *filename,
1805
                unsigned line,
1806
                const char *section,
1807
                unsigned section_line,
1808
                const char *lvalue,
1809
                int ltype,
1810
                const char *rvalue,
1811
                void *data,
1812
                void *userdata) {
1813

1814
        Set **hwaddrs = ASSERT_PTR(data);
17✔
1815
        int r;
17✔
1816

1817
        assert(filename);
17✔
1818
        assert(lvalue);
17✔
1819
        assert(rvalue);
17✔
1820

1821
        if (isempty(rvalue)) {
17✔
1822
                /* Empty assignment resets the list */
1823
                *hwaddrs = set_free(*hwaddrs);
×
1824
                return 1;
×
1825
        }
1826

1827
        for (const char *p = rvalue;;) {
17✔
1828
                _cleanup_free_ char *word = NULL;
17✔
1829
                _cleanup_free_ struct hw_addr_data *n = NULL;
34✔
1830

1831
                r = extract_first_word(&p, &word, NULL, 0);
34✔
1832
                if (r < 0)
34✔
1833
                        return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1834
                if (r == 0)
34✔
1835
                        return 1;
1836

1837
                n = new(struct hw_addr_data, 1);
17✔
1838
                if (!n)
17✔
1839
                        return log_oom();
×
1840

1841
                r = parse_hw_addr_full(word, ltype, n);
17✔
1842
                if (r < 0) {
17✔
1843
                        log_syntax(unit, LOG_WARNING, filename, line, r,
×
1844
                                   "Not a valid hardware address, ignoring: %s", word);
1845
                        continue;
×
1846
                }
1847

1848
                r = set_ensure_consume(hwaddrs, &hw_addr_hash_ops_free, TAKE_PTR(n));
17✔
1849
                if (r < 0)
17✔
1850
                        return log_oom();
×
1851
        }
1852
}
1853

1854
int config_parse_ether_addr(
26✔
1855
                const char *unit,
1856
                const char *filename,
1857
                unsigned line,
1858
                const char *section,
1859
                unsigned section_line,
1860
                const char *lvalue,
1861
                int ltype,
1862
                const char *rvalue,
1863
                void *data,
1864
                void *userdata) {
1865

1866
        _cleanup_free_ struct ether_addr *n = NULL;
26✔
1867
        struct ether_addr **hwaddr = ASSERT_PTR(data);
26✔
1868
        int r;
26✔
1869

1870
        assert(filename);
26✔
1871
        assert(lvalue);
26✔
1872
        assert(rvalue);
26✔
1873

1874
        if (isempty(rvalue)) {
26✔
1875
                *hwaddr = mfree(*hwaddr);
1✔
1876
                return 1;
1✔
1877
        }
1878

1879
        n = new0(struct ether_addr, 1);
25✔
1880
        if (!n)
25✔
1881
                return log_oom();
×
1882

1883
        r = parse_ether_addr(rvalue, n);
25✔
1884
        if (r < 0)
25✔
1885
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
15✔
1886

1887
        free_and_replace(*hwaddr, n);
10✔
1888
        return 1;
10✔
1889
}
1890

1891
int config_parse_ether_addrs(
28✔
1892
                const char *unit,
1893
                const char *filename,
1894
                unsigned line,
1895
                const char *section,
1896
                unsigned section_line,
1897
                const char *lvalue,
1898
                int ltype,
1899
                const char *rvalue,
1900
                void *data,
1901
                void *userdata) {
1902

1903
        Set **hwaddrs = ASSERT_PTR(data);
28✔
1904
        int r;
28✔
1905

1906
        assert(filename);
28✔
1907
        assert(lvalue);
28✔
1908
        assert(rvalue);
28✔
1909

1910
        if (isempty(rvalue)) {
28✔
1911
                /* Empty assignment resets the list */
1912
                *hwaddrs = set_free(*hwaddrs);
1✔
1913
                return 1;
1✔
1914
        }
1915

1916
        for (const char *p = rvalue;;) {
27✔
1917
                _cleanup_free_ char *word = NULL;
20✔
1918
                _cleanup_free_ struct ether_addr *n = NULL;
65✔
1919

1920
                r = extract_first_word(&p, &word, NULL, 0);
65✔
1921
                if (r < 0)
65✔
1922
                        return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1923
                if (r == 0)
65✔
1924
                        return 1;
1925

1926
                n = new(struct ether_addr, 1);
38✔
1927
                if (!n)
38✔
1928
                        return log_oom();
×
1929

1930
                r = parse_ether_addr(word, n);
38✔
1931
                if (r < 0) {
38✔
1932
                        log_syntax(unit, LOG_WARNING, filename, line, r,
18✔
1933
                                   "Not a valid MAC address, ignoring: %s", word);
1934
                        continue;
18✔
1935
                }
1936

1937
                r = set_ensure_consume(hwaddrs, &ether_addr_hash_ops_free, TAKE_PTR(n));
20✔
1938
                if (r < 0)
20✔
1939
                        return log_oom();
×
1940
        }
1941
}
1942

1943
int config_parse_in_addr_non_null(
47✔
1944
                const char *unit,
1945
                const char *filename,
1946
                unsigned line,
1947
                const char *section,
1948
                unsigned section_line,
1949
                const char *lvalue,
1950
                int ltype,
1951
                const char *rvalue,
1952
                void *data,
1953
                void *userdata) {
1954

1955
        /* data must be a pointer to struct in_addr or in6_addr, and the type is determined by ltype. */
1956
        struct in_addr *ipv4 = ASSERT_PTR(data);
47✔
1957
        struct in6_addr *ipv6 = ASSERT_PTR(data);
47✔
1958
        union in_addr_union a;
47✔
1959
        int r;
47✔
1960

1961
        assert(filename);
47✔
1962
        assert(lvalue);
47✔
1963
        assert(rvalue);
47✔
1964
        assert(IN_SET(ltype, AF_INET, AF_INET6));
47✔
1965

1966
        if (isempty(rvalue)) {
47✔
1967
                if (ltype == AF_INET)
×
1968
                        *ipv4 = (struct in_addr) {};
×
1969
                else
1970
                        *ipv6 = (struct in6_addr) {};
×
1971
                return 1;
×
1972
        }
1973

1974
        r = in_addr_from_string(ltype, rvalue, &a);
47✔
1975
        if (r < 0)
47✔
1976
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
18✔
1977

1978
        if (!in_addr_is_set(ltype, &a)) {
29✔
1979
                log_syntax(unit, LOG_WARNING, filename, line, 0,
×
1980
                           "%s= cannot be the ANY address, ignoring: %s", lvalue, rvalue);
1981
                return 0;
×
1982
        }
1983

1984
        if (ltype == AF_INET)
29✔
1985
                *ipv4 = a.in;
28✔
1986
        else
1987
                *ipv6 = a.in6;
1✔
1988
        return 1;
1989
}
1990

1991
int config_parse_in_addr_data(
73✔
1992
                const char *unit,
1993
                const char *filename,
1994
                unsigned line,
1995
                const char *section,
1996
                unsigned section_line,
1997
                const char *lvalue,
1998
                int ltype,
1999
                const char *rvalue,
2000
                void *data,
2001
                void *userdata) {
2002

2003
        struct in_addr_data *p = ASSERT_PTR(data);
73✔
2004
        int r;
73✔
2005

2006
        assert(filename);
73✔
2007
        assert(lvalue);
73✔
2008

2009
        if (isempty(rvalue)) {
73✔
2010
                *p = (struct in_addr_data) {};
×
2011
                return 1;
×
2012
        }
2013

2014
        r = in_addr_from_string_auto(rvalue, &p->family, &p->address);
73✔
2015
        if (r < 0)
73✔
2016
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
2017

2018
        return 1;
2019
}
2020

2021
int config_parse_in_addr_prefix(
4,886✔
2022
                const char *unit,
2023
                const char *filename,
2024
                unsigned line,
2025
                const char *section,
2026
                unsigned section_line,
2027
                const char *lvalue,
2028
                int ltype, /* takes boolean, whether we warn about missing prefixlen */
2029
                const char *rvalue,
2030
                void *data,
2031
                void *userdata) {
2032

2033
        struct in_addr_prefix *p = ASSERT_PTR(data);
4,886✔
2034
        int r;
4,886✔
2035

2036
        assert(filename);
4,886✔
2037
        assert(lvalue);
4,886✔
2038

2039
        if (isempty(rvalue)) {
4,886✔
2040
                *p = (struct in_addr_prefix) {};
×
2041
                return 1;
×
2042
        }
2043

2044
        r = in_addr_prefix_from_string_auto_full(rvalue, ltype ? PREFIXLEN_REFUSE : PREFIXLEN_FULL, &p->family, &p->address, &p->prefixlen);
4,886✔
2045
        if (r == -ENOANO) {
4,886✔
2046
                r = in_addr_prefix_from_string_auto(rvalue, &p->family, &p->address, &p->prefixlen);
14✔
2047
                if (r >= 0)
14✔
2048
                        log_syntax(unit, LOG_WARNING, filename, line, r,
14✔
2049
                                   "%s=%s is specified without prefix length. Assuming the prefix length is %u. "
2050
                                   "Please specify the prefix length explicitly.", lvalue, rvalue, p->prefixlen);
2051
        }
2052
        if (r < 0)
4,886✔
2053
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
35✔
2054

2055
        return 1;
2056
}
2057

2058
int config_parse_unsigned_bounded(
92✔
2059
                const char *unit,
2060
                const char *filename,
2061
                unsigned line,
2062
                const char *section,
2063
                unsigned section_line,
2064
                const char *lvalue,
2065
                const char *rvalue,
2066
                unsigned min,
2067
                unsigned max,
2068
                bool ignoring,
2069
                unsigned *ret) {
2070

2071
        int r;
92✔
2072

2073
        assert(filename);
92✔
2074
        assert(lvalue);
92✔
2075
        assert(rvalue);
92✔
2076
        assert(ret);
92✔
2077

2078
        r = safe_atou_bounded(rvalue, min, max, ret);
92✔
2079
        if (r == -ERANGE) {
92✔
2080
                log_syntax(unit, LOG_WARNING, filename, line, r,
×
2081
                           "Invalid '%s=%s', allowed range is %u..%u%s.",
2082
                           lvalue, rvalue, min, max, ignoring ? ", ignoring" : "");
2083
                return ignoring ? 0 : r;
×
2084
        }
2085
        if (r < 0)
92✔
2086
                return log_syntax_parse_error_full(unit, filename, line, r, /* critical = */ !ignoring, lvalue, rvalue);
×
2087

2088
        return 1;  /* Return 1 if something was set */
2089
}
2090

2091
int config_parse_calendar(
×
2092
                const char *unit,
2093
                const char *filename,
2094
                unsigned line,
2095
                const char *section,
2096
                unsigned section_line,
2097
                const char *lvalue,
2098
                int ltype,
2099
                const char *rvalue,
2100
                void *data,
2101
                void *userdata) {
2102

2103
        CalendarSpec **cr = data;
×
2104
        _cleanup_(calendar_spec_freep) CalendarSpec *c = NULL;
×
2105
        int r;
×
2106

2107
        assert(filename);
×
2108
        assert(lvalue);
×
2109
        assert(rvalue);
×
2110
        assert(data);
×
2111

2112
        if (isempty(rvalue)) {
×
2113
                *cr = calendar_spec_free(*cr);
×
2114
                return 1;
×
2115
        }
2116

2117
        r = calendar_spec_from_string(rvalue, &c);
×
2118
        if (r < 0)
×
2119
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
2120

2121
        free_and_replace_full(*cr, c, calendar_spec_free);
×
2122
        return 1;
×
2123
}
2124

2125
DEFINE_CONFIG_PARSE(config_parse_percent, parse_percent);
×
2126
DEFINE_CONFIG_PARSE(config_parse_permyriad, parse_permyriad);
1✔
2127
DEFINE_CONFIG_PARSE_PTR(config_parse_sec_fix_0, parse_sec_fix_0, usec_t);
249✔
2128

2129
int config_parse_timezone(
1✔
2130
                const char *unit,
2131
                const char *filename,
2132
                unsigned line,
2133
                const char *section,
2134
                unsigned section_line,
2135
                const char *lvalue,
2136
                int ltype,
2137
                const char *rvalue,
2138
                void *data,
2139
                void *userdata) {
2140

2141
        char **tz = ASSERT_PTR(data);
1✔
2142
        int r;
1✔
2143

2144
        assert(filename);
1✔
2145
        assert(lvalue);
1✔
2146
        assert(rvalue);
1✔
2147

2148
        if (isempty(rvalue)) {
1✔
2149
                *tz = mfree(*tz);
×
2150
                return 1;
×
2151
        }
2152

2153
        r = verify_timezone(rvalue, LOG_WARNING);
1✔
2154
        if (r < 0)
1✔
2155
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
2156

2157
        r = free_and_strdup_warn(tz, rvalue);
1✔
2158
        if (r < 0)
1✔
2159
                return r;
×
2160

2161
        return 1;
2162
}
2163

2164
int config_parse_ip_protocol(
6✔
2165
                const char *unit,
2166
                const char *filename,
2167
                unsigned line,
2168
                const char *section,
2169
                unsigned section_line,
2170
                const char *lvalue,
2171
                int ltype,
2172
                const char *rvalue,
2173
                void *data,
2174
                void *userdata) {
2175

2176
        uint8_t *proto = ASSERT_PTR(data);
6✔
2177
        int r;
6✔
2178

2179
        r = isempty(rvalue) ? 0 : parse_ip_protocol_full(rvalue, /* relaxed= */ ltype);
12✔
2180
        if (r < 0)
6✔
2181
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
2182

2183
        if (r > UINT8_MAX) {
6✔
2184
                /* linux/fib_rules.h and linux/fou.h define the netlink field as one byte, so we need to
2185
                 * reject protocols numbers that don't fit in one byte. */
2186
                log_syntax(unit, LOG_WARNING, filename, line, r,
×
2187
                           "Invalid '%s=%s', allowed range is 0..255, ignoring.",
2188
                           lvalue, rvalue);
2189
                return 0;
×
2190
        }
2191

2192
        *proto = r;
6✔
2193
        return 1; /* done. */
6✔
2194
}
2195

2196
int config_parse_loadavg(
1✔
2197
                const char *unit,
2198
                const char *filename,
2199
                unsigned line,
2200
                const char *section,
2201
                unsigned section_line,
2202
                const char *lvalue,
2203
                int ltype,
2204
                const char *rvalue,
2205
                void *data,
2206
                void *userdata) {
2207

2208
        loadavg_t *i = ASSERT_PTR(data);
1✔
2209
        int r;
1✔
2210

2211
        assert(rvalue);
1✔
2212

2213
        r = parse_permyriad(rvalue);
1✔
2214
        if (r < 0)
1✔
2215
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
2216

2217
        r = store_loadavg_fixed_point(r / 100, r % 100, i);
1✔
2218
        if (r < 0)
1✔
2219
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
2220

2221
        return 1; /* done. */
2222
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc