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

systemd / systemd / 14766779411

30 Apr 2025 04:55PM UTC coverage: 72.225% (-0.06%) from 72.282%
14766779411

push

github

web-flow
wait-online: handle varlink connection errors while waiting for DNS (#37283)

Currently, if systemd-networkd-wait-online is started with --dns, and
systemd-resolved is not running, it will exit with an error right away.
Similarly, if systemd-resolved is restarted while waiting for DNS
configuration, systemd-networkd-wait-online will not attempt to
re-connect, and will potentially never see subsequent DNS
configurations.

Improve this by adding socket units for the systemd-resolved varlink
servers, and re-establish the connection in systemd-networkd-wait-online
when we receive `SD_VARLINK_ERROR_DISCONNECTED`.

8 of 16 new or added lines in 2 files covered. (50.0%)

5825 existing lines in 217 files now uncovered.

297168 of 411450 relevant lines covered (72.22%)

695892.62 hits per line

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

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

3
#include <errno.h>
4
#include <limits.h>
5
#include <linux/ipv6.h>
6
#include <stdint.h>
7
#include <stdio.h>
8
#include <stdlib.h>
9
#include <sys/types.h>
10

11
#include "sd-id128.h"
12

13
#include "alloc-util.h"
14
#include "calendarspec.h"
15
#include "chase.h"
16
#include "conf-files.h"
17
#include "conf-parser.h"
18
#include "constants.h"
19
#include "dns-domain.h"
20
#include "escape.h"
21
#include "ether-addr-util.h"
22
#include "extract-word.h"
23
#include "fd-util.h"
24
#include "fileio.h"
25
#include "fs-util.h"
26
#include "hash-funcs.h"
27
#include "hostname-util.h"
28
#include "id128-util.h"
29
#include "in-addr-prefix-util.h"
30
#include "ip-protocol-list.h"
31
#include "log.h"
32
#include "macro.h"
33
#include "missing_network.h"
34
#include "nulstr-util.h"
35
#include "parse-helpers.h"
36
#include "parse-util.h"
37
#include "path-util.h"
38
#include "percent-util.h"
39
#include "process-util.h"
40
#include "rlimit-util.h"
41
#include "set.h"
42
#include "signal-util.h"
43
#include "socket-util.h"
44
#include "stat-util.h"
45
#include "string-util.h"
46
#include "strv.h"
47
#include "syslog-util.h"
48
#include "time-util.h"
49
#include "utf8.h"
50

51
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(config_file_hash_ops_fclose,
490✔
52
                                              char, path_hash_func, path_compare,
53
                                              FILE, safe_fclose);
54

55
int config_item_table_lookup(
7,745✔
56
                const void *table,
57
                const char *section,
58
                const char *lvalue,
59
                ConfigParserCallback *ret_func,
60
                int *ret_ltype,
61
                void **ret_data,
62
                void *userdata) {
63

64
        assert(table);
7,745✔
65
        assert(lvalue);
7,745✔
66
        assert(ret_func);
7,745✔
67
        assert(ret_ltype);
7,745✔
68
        assert(ret_data);
7,745✔
69

70
        for (const ConfigTableItem *t = table; t->lvalue; t++) {
83,833✔
71

72
                if (!streq(lvalue, t->lvalue))
83,833✔
73
                        continue;
74,144✔
74

75
                if (!streq_ptr(section, t->section))
9,689✔
76
                        continue;
1,944✔
77

78
                *ret_func = t->parse;
7,745✔
79
                *ret_ltype = t->ltype;
7,745✔
80
                *ret_data = t->data;
7,745✔
81
                return 1;
7,745✔
82
        }
83

84
        *ret_func = NULL;
×
85
        *ret_ltype = 0;
×
86
        *ret_data = NULL;
×
UNCOV
87
        return 0;
×
88
}
89

90
int config_item_perf_lookup(
375,375✔
91
                const void *table,
92
                const char *section,
93
                const char *lvalue,
94
                ConfigParserCallback *ret_func,
95
                int *ret_ltype,
96
                void **ret_data,
97
                void *userdata) {
98

99
        ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
375,375✔
100
        const ConfigPerfItem *p;
375,375✔
101

102
        assert(table);
375,375✔
103
        assert(lvalue);
375,375✔
104
        assert(ret_func);
375,375✔
105
        assert(ret_ltype);
375,375✔
106
        assert(ret_data);
375,375✔
107

108
        if (section) {
375,375✔
109
                const char *key;
375,375✔
110

111
                key = strjoina(section, ".", lvalue);
2,627,625✔
112
                p = lookup(key, strlen(key));
375,375✔
113
        } else
UNCOV
114
                p = lookup(lvalue, strlen(lvalue));
×
115
        if (!p) {
375,375✔
116
                *ret_func = NULL;
5✔
117
                *ret_ltype = 0;
5✔
118
                *ret_data = NULL;
5✔
119
                return 0;
5✔
120
        }
121

122
        *ret_func = p->parse;
375,370✔
123
        *ret_ltype = p->ltype;
375,370✔
124
        *ret_data = (uint8_t*) userdata + p->offset;
375,370✔
125
        return 1;
375,370✔
126
}
127

128
/* Run the user supplied parser for an assignment */
129
static int next_assignment(
383,120✔
130
                const char *unit,
131
                const char *filename,
132
                unsigned line,
133
                ConfigItemLookup lookup,
134
                const void *table,
135
                const char *section,
136
                unsigned section_line,
137
                const char *lvalue,
138
                const char *rvalue,
139
                ConfigParseFlags flags,
140
                void *userdata) {
141

142
        ConfigParserCallback func = NULL;
383,120✔
143
        int ltype = 0;
383,120✔
144
        void *data = NULL;
383,120✔
145
        int r;
383,120✔
146

147
        assert(filename);
383,120✔
148
        assert(line > 0);
383,120✔
149
        assert(lookup);
383,120✔
150
        assert(lvalue);
383,120✔
151
        assert(rvalue);
383,120✔
152

153
        r = lookup(table, section, lvalue, &func, &ltype, &data, userdata);
383,120✔
154
        if (r < 0)
383,120✔
155
                return r;
383,120✔
156
        if (r > 0) {
383,120✔
157
                if (!func)
383,115✔
158
                        return 0;
159

160
                return func(unit, filename, line, section, section_line,
376,005✔
161
                            lvalue, ltype, rvalue, data, userdata);
162
        }
163

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

173
        return 0;
174
}
175

176
/* Parse a single logical line */
177
static int parse_line(
685,219✔
178
                const char *unit,
179
                const char *filename,
180
                unsigned line,
181
                const char *sections,
182
                ConfigItemLookup lookup,
183
                const void *table,
184
                ConfigParseFlags flags,
185
                char **section,
186
                unsigned *section_line,
187
                bool *section_ignored,
188
                char *l, /* is modified */
189
                void *userdata) {
190

191
        char *e;
685,219✔
192

193
        assert(filename);
685,219✔
194
        assert(line > 0);
685,219✔
195
        assert(lookup);
685,219✔
196
        assert(l);
685,219✔
197

198
        l = strstrip(l);
685,219✔
199
        if (isempty(l))
1,370,438✔
200
                return 0;
201

202
        if (l[0] == '\n')
547,356✔
203
                return 0;
204

205
        if (!utf8_is_valid(l))
547,356✔
UNCOV
206
                return log_syntax_invalid_utf8(unit, LOG_WARNING, filename, line, l);
×
207

208
        if (l[0] == '[') {
547,356✔
209
                _cleanup_free_ char *n = NULL;
104,662✔
210
                size_t k;
104,662✔
211

212
                k = strlen(l);
104,662✔
213
                assert(k > 0);
104,662✔
214

215
                if (l[k-1] != ']')
104,662✔
UNCOV
216
                        return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EBADMSG), "Invalid section header '%s'", l);
×
217

218
                n = strndup(l+1, k-2);
104,662✔
219
                if (!n)
104,662✔
UNCOV
220
                        return log_oom();
×
221

222
                if (!string_is_safe(n))
104,662✔
UNCOV
223
                        return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EBADMSG), "Bad characters in section header '%s'", l);
×
224

225
                if (sections && !nulstr_contains(sections, n)) {
104,662✔
226
                        bool ignore;
7,014✔
227

228
                        ignore = (flags & CONFIG_PARSE_RELAXED) || startswith(n, "X-");
7,014✔
229

230
                        if (!ignore)
231
                                NULSTR_FOREACH(t, sections)
52,175✔
232
                                        if (streq_ptr(n, startswith(t, "-"))) { /* Ignore sections prefixed with "-" in valid section list */
52,174✔
233
                                                ignore = true;
234
                                                break;
235
                                        }
236

237
                        if (!ignore)
6,995✔
238
                                log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown section '%s'. Ignoring.", n);
1✔
239

240
                        *section = mfree(*section);
7,014✔
241
                        *section_line = 0;
7,014✔
242
                        *section_ignored = true;
7,014✔
243
                } else {
244
                        free_and_replace(*section, n);
97,648✔
245
                        *section_line = line;
97,648✔
246
                        *section_ignored = false;
97,648✔
247
                }
248

249
                return 0;
104,662✔
250
        }
251

252
        if (sections && !*section) {
442,694✔
253
                if (!(flags & CONFIG_PARSE_RELAXED) && !*section_ignored)
59,574✔
UNCOV
254
                        log_syntax(unit, LOG_WARNING, filename, line, 0, "Assignment outside of section. Ignoring.");
×
255

256
                return 0;
59,574✔
257
        }
258

259
        e = strchr(l, '=');
383,120✔
260
        if (!e)
383,120✔
UNCOV
261
                return log_syntax(unit, LOG_WARNING, filename, line, 0,
×
262
                                  "Missing '=', ignoring line.");
263
        if (e == l)
383,120✔
UNCOV
264
                return log_syntax(unit, LOG_WARNING, filename, line, 0,
×
265
                                  "Missing key name before '=', ignoring line.");
266

267
        *e = 0;
383,120✔
268
        e++;
383,120✔
269

270
        return next_assignment(unit,
383,120✔
271
                               filename,
272
                               line,
273
                               lookup,
274
                               table,
275
                               *section,
276
                               *section_line,
277
                               strstrip(l),
383,120✔
278
                               strstrip(e),
383,120✔
279
                               flags,
280
                               userdata);
281
}
282

283
/* Go through the file and parse each line */
284
int config_parse(
90,693✔
285
                const char *unit,
286
                const char *filename,
287
                FILE *f,
288
                const char *sections,
289
                ConfigItemLookup lookup,
290
                const void *table,
291
                ConfigParseFlags flags,
292
                void *userdata,
293
                struct stat *ret_stat) {
294

295
        _cleanup_free_ char *section = NULL, *continuation = NULL;
90,693✔
296
        _cleanup_fclose_ FILE *ours = NULL;
90,693✔
297
        unsigned line = 0, section_line = 0;
90,693✔
298
        bool section_ignored = false, bom_seen = false;
90,693✔
299
        struct stat st;
90,693✔
300
        int r, fd;
90,693✔
301

302
        assert(filename);
90,693✔
303
        assert(lookup);
90,693✔
304

305
        if (!f) {
90,693✔
306
                f = ours = fopen(filename, "re");
11,692✔
307
                if (!f) {
11,692✔
308
                        /* Only log on request, except for ENOENT,
309
                         * since we return 0 to the caller. */
310
                        if ((flags & CONFIG_PARSE_WARN) || errno == ENOENT)
×
UNCOV
311
                                log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno,
×
312
                                               "Failed to open configuration file '%s': %m", filename);
313

314
                        if (errno == ENOENT) {
×
315
                                if (ret_stat)
×
UNCOV
316
                                        *ret_stat = (struct stat) {};
×
317

UNCOV
318
                                return 0;
×
319
                        }
320

UNCOV
321
                        return -errno;
×
322
                }
323
        }
324

325
        fd = fileno(f);
90,693✔
326
        if (fd >= 0) { /* stream might not have an fd, let's be careful hence */
90,693✔
327

328
                if (fstat(fd, &st) < 0)
90,693✔
UNCOV
329
                        return log_full_errno(FLAGS_SET(flags, CONFIG_PARSE_WARN) ? LOG_ERR : LOG_DEBUG, errno,
×
330
                                              "Failed to fstat(%s): %m", filename);
331

332
                (void) stat_warn_permissions(filename, &st);
90,693✔
333
        } else
UNCOV
334
                st = (struct stat) {};
×
335

336
        for (;;) {
1,470,022✔
337
                _cleanup_free_ char *buf = NULL;
1,379,331✔
338
                bool escaped = false;
1,470,022✔
339
                char *l, *p, *e;
1,470,022✔
340

341
                r = read_line(f, LONG_LINE_MAX, &buf);
1,470,022✔
342
                if (r == 0)
1,470,022✔
343
                        break;
344
                if (r == -ENOBUFS) {
1,379,331✔
345
                        if (flags & CONFIG_PARSE_WARN)
1✔
346
                                log_error_errno(r, "%s:%u: Line too long", filename, line);
1✔
347

348
                        return r;
1✔
349
                }
350
                if (r < 0) {
1,379,330✔
351
                        if (FLAGS_SET(flags, CONFIG_PARSE_WARN))
×
UNCOV
352
                                log_error_errno(r, "%s:%u: Error while reading configuration file: %m", filename, line);
×
353

UNCOV
354
                        return r;
×
355
                }
356

357
                line++;
1,379,330✔
358

359
                l = skip_leading_chars(buf, WHITESPACE);
1,379,330✔
360
                if (*l != '\0' && strchr(COMMENTS, *l))
1,379,330✔
361
                        continue;
689,713✔
362

363
                l = buf;
689,617✔
364
                if (!bom_seen) {
689,617✔
365
                        char *q;
689,617✔
366

367
                        q = startswith(buf, UTF8_BYTE_ORDER_MARK);
689,617✔
368
                        if (q) {
689,617✔
369
                                l = q;
×
UNCOV
370
                                bom_seen = true;
×
371
                        }
372
                }
373

374
                if (continuation) {
689,617✔
375
                        if (strlen(continuation) + strlen(l) > LONG_LINE_MAX) {
4,397✔
376
                                if (flags & CONFIG_PARSE_WARN)
1✔
377
                                        log_error("%s:%u: Continuation line too long", filename, line);
1✔
378
                                return -ENOBUFS;
1✔
379
                        }
380

381
                        if (!strextend(&continuation, l)) {
4,396✔
382
                                if (flags & CONFIG_PARSE_WARN)
×
383
                                        log_oom();
×
UNCOV
384
                                return -ENOMEM;
×
385
                        }
386

387
                        p = continuation;
4,396✔
388
                } else
389
                        p = l;
390

391
                for (e = p; *e; e++) {
537,786,537✔
392
                        if (escaped)
537,096,921✔
393
                                escaped = false;
394
                        else if (*e == '\\')
537,096,651✔
395
                                escaped = true;
4,669✔
396
                }
397

398
                if (escaped) {
689,616✔
399
                        *(e-1) = ' ';
4,399✔
400

401
                        if (!continuation) {
4,399✔
402
                                continuation = strdup(l);
1,139✔
403
                                if (!continuation) {
1,139✔
404
                                        if (flags & CONFIG_PARSE_WARN)
×
405
                                                log_oom();
×
UNCOV
406
                                        return -ENOMEM;
×
407
                                }
408
                        }
409

410
                        continue;
4,399✔
411
                }
412

413
                r = parse_line(unit,
685,217✔
414
                               filename,
415
                               line,
416
                               sections,
417
                               lookup,
418
                               table,
419
                               flags,
420
                               &section,
421
                               &section_line,
422
                               &section_ignored,
423
                               p,
424
                               userdata);
425
                if (r < 0) {
685,217✔
426
                        if (flags & CONFIG_PARSE_WARN)
×
427
                                log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
×
UNCOV
428
                        return r;
×
429
                }
430

431
                continuation = mfree(continuation);
685,217✔
432
        }
433

434
        if (continuation) {
90,691✔
435
                r = parse_line(unit,
2✔
436
                               filename,
437
                               ++line,
438
                               sections,
439
                               lookup,
440
                               table,
441
                               flags,
442
                               &section,
443
                               &section_line,
444
                               &section_ignored,
445
                               continuation,
446
                               userdata);
447
                if (r < 0) {
2✔
448
                        if (flags & CONFIG_PARSE_WARN)
×
449
                                log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
×
UNCOV
450
                        return r;
×
451
                }
452
        }
453

454
        if (ret_stat)
90,691✔
455
                *ret_stat = st;
57,088✔
456

457
        return 1;
458
}
459

460
int hashmap_put_stats_by_path(Hashmap **stats_by_path, const char *path, const struct stat *st) {
45,492✔
461
        _cleanup_free_ struct stat *st_copy = NULL;
90,984✔
462
        _cleanup_free_ char *path_copy = NULL;
45,492✔
463
        int r;
45,492✔
464

465
        assert(stats_by_path);
45,492✔
466
        assert(path);
45,492✔
467
        assert(st);
45,492✔
468

469
        st_copy = newdup(struct stat, st, 1);
45,492✔
470
        if (!st_copy)
45,492✔
471
                return -ENOMEM;
472

473
        path_copy = strdup(path);
45,492✔
474
        if (!path_copy)
45,492✔
475
                return -ENOMEM;
476

477
        r = hashmap_ensure_put(stats_by_path, &path_hash_ops_free_free, path_copy, st_copy);
45,492✔
478
        if (r < 0)
45,492✔
479
                return r;
480

481
        assert(r > 0);
45,492✔
482
        TAKE_PTR(path_copy);
483
        TAKE_PTR(st_copy);
484
        return 0;
485
}
486

487
static int config_parse_many_files(
44,933✔
488
                const char *root,
489
                const char* const* conf_files,
490
                char **files,
491
                const char *sections,
492
                ConfigItemLookup lookup,
493
                const void *table,
494
                ConfigParseFlags flags,
495
                void *userdata,
496
                Hashmap **ret_stats_by_path) {
497

498
        _cleanup_hashmap_free_ Hashmap *stats_by_path = NULL;
44,933✔
499
        _cleanup_ordered_hashmap_free_ OrderedHashmap *dropins = NULL;
44,933✔
500
        _cleanup_set_free_ Set *inodes = NULL;
44,933✔
501
        struct stat st;
44,933✔
502
        int r, level = FLAGS_SET(flags, CONFIG_PARSE_WARN) ? LOG_WARNING : LOG_DEBUG;
44,933✔
503

504
        if (ret_stats_by_path) {
44,933✔
505
                stats_by_path = hashmap_new(&path_hash_ops_free_free);
8,247✔
506
                if (!stats_by_path)
8,247✔
UNCOV
507
                        return log_oom_full(level);
×
508
        }
509

510
        STRV_FOREACH(fn, files) {
45,423✔
511
                _cleanup_fclose_ FILE *f = NULL;
490✔
512
                _cleanup_free_ char *fname = NULL;
490✔
513

514
                r = chase_and_fopen_unlocked(*fn, root, CHASE_AT_RESOLVE_IN_ROOT, "re", &fname, &f);
490✔
515
                if (r == -ENOENT)
490✔
UNCOV
516
                        continue;
×
517
                if (r < 0)
490✔
UNCOV
518
                        return log_full_errno(level, r, "Failed to open %s: %m", *fn);
×
519

520
                int fd = fileno(f);
490✔
521

522
                r = ordered_hashmap_ensure_put(&dropins, &config_file_hash_ops_fclose, *fn, f);
490✔
523
                if (r < 0) {
490✔
524
                        assert(r == -ENOMEM);
×
UNCOV
525
                        return log_oom_full(level);
×
526
                }
527
                assert(r > 0);
490✔
528
                TAKE_PTR(f);
490✔
529

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

533
                _cleanup_free_ struct stat *st_dropin = new(struct stat, 1);
980✔
534
                if (!st_dropin)
490✔
UNCOV
535
                        return log_oom_full(level);
×
536

537
                if (fstat(fd, st_dropin) < 0)
490✔
UNCOV
538
                        return log_full_errno(level, errno, "Failed to stat %s: %m", *fn);
×
539

540
                r = set_ensure_consume(&inodes, &inode_hash_ops, TAKE_PTR(st_dropin));
490✔
541
                if (r < 0)
490✔
UNCOV
542
                        return log_oom_full(level);
×
543
        }
544

545
        /* First read the first found main config file. */
546
        STRV_FOREACH(fn, conf_files) {
45,584✔
547
                _cleanup_fclose_ FILE *f = NULL;
45,561✔
548

549
                r = chase_and_fopen_unlocked(*fn, root, CHASE_AT_RESOLVE_IN_ROOT, "re", NULL, &f);
45,561✔
550
                if (r == -ENOENT)
45,561✔
551
                        continue;
651✔
552
                if (r < 0)
44,910✔
UNCOV
553
                        return log_full_errno(level, r, "Failed to open %s: %m", *fn);
×
554

555
                if (inodes) {
44,910✔
556
                        if (fstat(fileno(f), &st) < 0)
356✔
UNCOV
557
                                return log_full_errno(level, errno, "Failed to stat %s: %m", *fn);
×
558

559
                        if (set_contains(inodes, &st)) {
356✔
UNCOV
560
                                log_debug("%s: symlink to/symlinked as drop-in, will be read later.", *fn);
×
561
                                break;
562
                        }
563
                }
564

565
                r = config_parse(/* unit= */ NULL, *fn, f, sections, lookup, table, flags, userdata, &st);
44,910✔
566
                if (r < 0)
44,910✔
567
                        return r; /* config_parse() logs internally. */
568
                assert(r > 0);
44,910✔
569

570
                if (ret_stats_by_path) {
44,910✔
571
                        r = hashmap_put_stats_by_path(&stats_by_path, *fn, &st);
8,247✔
572
                        if (r < 0)
8,247✔
UNCOV
573
                                return log_full_errno(level, r, "Failed to save stats of %s: %m", *fn);
×
574
                }
575

576
                break;
577
        }
578

579
        /* Then read all the drop-ins. */
580

581
        const char *path_dropin;
44,933✔
582
        FILE *f_dropin;
44,933✔
583
        ORDERED_HASHMAP_FOREACH_KEY(f_dropin, path_dropin, dropins) {
90,356✔
584
                r = config_parse(/* unit= */ NULL, path_dropin, f_dropin, sections, lookup, table, flags, userdata, &st);
490✔
585
                if (r < 0)
490✔
UNCOV
586
                        return r; /* config_parse() logs internally. */
×
587
                assert(r > 0);
490✔
588

589
                if (ret_stats_by_path) {
490✔
590
                        r = hashmap_put_stats_by_path(&stats_by_path, path_dropin, &st);
240✔
591
                        if (r < 0)
240✔
UNCOV
592
                                return log_full_errno(level, r, "Failed to save stats of %s: %m", path_dropin);
×
593
                }
594
        }
595

596
        if (ret_stats_by_path)
44,933✔
597
                *ret_stats_by_path = TAKE_PTR(stats_by_path);
8,247✔
598

599
        return 0;
600
}
601

602
/* Parse each config file in the directories specified as strv. */
603
int config_parse_many(
44,933✔
604
                const char* const* conf_files,
605
                const char* const* conf_file_dirs,
606
                const char *dropin_dirname,
607
                const char *root,
608
                const char *sections,
609
                ConfigItemLookup lookup,
610
                const void *table,
611
                ConfigParseFlags flags,
612
                void *userdata,
613
                Hashmap **ret_stats_by_path,
614
                char ***ret_dropin_files) {
615

616
        _cleanup_strv_free_ char **files = NULL;
44,933✔
617
        int r;
44,933✔
618

619
        assert(conf_file_dirs);
44,933✔
620
        assert(dropin_dirname);
44,933✔
621
        assert(table);
44,933✔
622

623
        r = conf_files_list_dropins(&files, dropin_dirname, root, conf_file_dirs);
44,933✔
624
        if (r < 0)
44,933✔
UNCOV
625
                return log_full_errno(FLAGS_SET(flags, CONFIG_PARSE_WARN) ? LOG_WARNING : LOG_DEBUG, r,
×
626
                                      "Failed to list up drop-in configs in %s: %m", dropin_dirname);
627

628
        r = config_parse_many_files(root, conf_files, files, sections, lookup, table, flags, userdata, ret_stats_by_path);
44,933✔
629
        if (r < 0)
44,933✔
630
                return r; /* config_parse_many_files() logs internally. */
631

632
        if (ret_dropin_files)
44,933✔
633
                *ret_dropin_files = TAKE_PTR(files);
8,558✔
634

635
        return 0;
636
}
637

638
int config_parse_standard_file_with_dropins_full(
34,828✔
639
                const char *root,
640
                const char *main_file,    /* A path like "systemd/frobnicator.conf" */
641
                const char *sections,
642
                ConfigItemLookup lookup,
643
                const void *table,
644
                ConfigParseFlags flags,
645
                void *userdata,
646
                Hashmap **ret_stats_by_path,
647
                char ***ret_dropin_files) {
648

649
        const char* const *conf_paths = (const char* const*) CONF_PATHS_STRV("");
34,828✔
650
        _cleanup_strv_free_ char **configs = NULL;
34,828✔
651
        int r, level = FLAGS_SET(flags, CONFIG_PARSE_WARN) ? LOG_WARNING : LOG_DEBUG;
34,828✔
652

653
        /* Build the list of main config files */
654
        r = strv_extend_strv_biconcat(&configs, root, conf_paths, main_file);
34,828✔
655
        if (r < 0)
34,828✔
UNCOV
656
                return log_oom_full(level);
×
657

658
        _cleanup_free_ char *dropin_dirname = strjoin(main_file, ".d");
69,656✔
659
        if (!dropin_dirname)
34,828✔
UNCOV
660
                return log_oom_full(level);
×
661

662
        return config_parse_many(
34,828✔
663
                        (const char* const*) configs,
664
                        conf_paths,
665
                        dropin_dirname,
666
                        root,
667
                        sections,
668
                        lookup,
669
                        table,
670
                        flags,
671
                        userdata,
672
                        ret_stats_by_path,
673
                        ret_dropin_files);
674
}
675

676
static int dropins_get_stats_by_path(
2,383✔
677
                const char* conf_file,
678
                const char* const* conf_file_dirs,
679
                Hashmap **stats_by_path) {
680

UNCOV
681
        _cleanup_strv_free_ char **files = NULL;
×
682
        _cleanup_free_ char *dropin_dirname = NULL;
2,383✔
683
        int r;
2,383✔
684

685
        assert(conf_file);
2,383✔
686
        assert(conf_file_dirs);
2,383✔
687
        assert(stats_by_path);
2,383✔
688

689
        r = path_extract_filename(conf_file, &dropin_dirname);
2,383✔
690
        if (r < 0)
2,383✔
691
                return r;
692
        if (r == O_DIRECTORY)
2,383✔
693
                return -EINVAL;
694

695
        if (!strextend(&dropin_dirname, ".d"))
2,383✔
696
                return -ENOMEM;
697

698
        r = conf_files_list_dropins(&files, dropin_dirname, /* root = */ NULL, conf_file_dirs);
2,383✔
699
        if (r < 0)
2,383✔
700
                return r;
701

702
        STRV_FOREACH(fn, files) {
2,394✔
703
                struct stat st;
11✔
704

705
                if (stat(*fn, &st) < 0) {
11✔
706
                        if (errno == ENOENT)
×
UNCOV
707
                                continue;
×
708

UNCOV
709
                        return -errno;
×
710
                }
711

712
                r = hashmap_put_stats_by_path(stats_by_path, *fn, &st);
11✔
713
                if (r < 0)
11✔
714
                        return r;
715
        }
716

717
        return 0;
718
}
719

720
int config_get_stats_by_path(
672✔
721
                const char *suffix,
722
                const char *root,
723
                unsigned flags,
724
                const char* const* dirs,
725
                bool check_dropins,
726
                Hashmap **ret) {
727

728
        _cleanup_hashmap_free_ Hashmap *stats_by_path = NULL;
672✔
729
        _cleanup_strv_free_ char **files = NULL;
672✔
730
        int r;
672✔
731

732
        assert(suffix);
672✔
733
        assert(dirs);
672✔
734
        assert(ret);
672✔
735

736
        /* Unlike config_parse(), this does not support stream. */
737

738
        r = conf_files_list_strv(&files, suffix, root, flags, dirs);
672✔
739
        if (r < 0)
672✔
740
                return r;
741

742
        STRV_FOREACH(f, files) {
28,385✔
743
                struct stat st;
27,713✔
744

745
                /* First read the main config file. */
746
                if (stat(*f, &st) < 0) {
27,713✔
UNCOV
747
                        if (errno == ENOENT)
×
748
                                continue;
25,330✔
749

UNCOV
750
                        return -errno;
×
751
                }
752

753
                /* Skipping an empty file. */
754
                if (null_or_empty(&st))
27,713✔
UNCOV
755
                        continue;
×
756

757
                r = hashmap_put_stats_by_path(&stats_by_path, *f, &st);
27,713✔
758
                if (r < 0)
27,713✔
759
                        return r;
760

761
                if (!check_dropins)
27,713✔
762
                        continue;
25,330✔
763

764
                /* Then read all the drop-ins if requested. */
765
                r = dropins_get_stats_by_path(*f, dirs, &stats_by_path);
2,383✔
766
                if (r < 0)
2,383✔
767
                        return r;
768
        }
769

770
        *ret = TAKE_PTR(stats_by_path);
672✔
771
        return 0;
672✔
772
}
773

774
bool stats_by_path_equal(Hashmap *a, Hashmap *b) {
2,263✔
775
        struct stat *st_a, *st_b;
2,263✔
776
        const char *path;
2,263✔
777

778
        if (hashmap_size(a) != hashmap_size(b))
2,263✔
779
                return false;
2,263✔
780

781
        HASHMAP_FOREACH_KEY(st_a, path, a) {
27,862✔
782
                st_b = hashmap_get(b, path);
25,865✔
783
                if (!st_b)
25,865✔
784
                        return false;
157✔
785

786
                if (!stat_inode_unmodified(st_a, st_b))
25,862✔
787
                        return false;
788
        }
789

790
        return true;
1,997✔
791
}
792

793
int config_section_parse(
5,872✔
794
                const ConfigSectionParser *parsers,
795
                size_t n_parsers,
796
                const char *unit,
797
                const char *filename,
798
                unsigned line,
799
                const char *section,
800
                unsigned section_line,
801
                const char *lvalue,
802
                int ltype,
803
                const char *rvalue,
804
                void *userdata) {
805

806
        assert(parsers);
5,872✔
807
        assert(n_parsers > 0);
5,872✔
808
        assert(ltype >= 0);
5,872✔
809
        assert((size_t) ltype < n_parsers);
5,872✔
810
        assert(userdata);
5,872✔
811

812
        const ConfigSectionParser *e = parsers + ltype;
5,872✔
813
        assert(e->parser);
5,872✔
814

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

820
        return e->parser(unit, filename, line, section, section_line, lvalue, e->ltype, rvalue,
11,744✔
821
                         (uint8_t*) userdata + e->offset, userdata);
5,872✔
822
}
823

824
void config_section_hash_func(const ConfigSection *c, struct siphash *state) {
16,484✔
825
        siphash24_compress_string(c->filename, state);
16,484✔
826
        siphash24_compress_typesafe(c->line, state);
16,484✔
827
}
16,484✔
828

829
int config_section_compare_func(const ConfigSection *x, const ConfigSection *y) {
5,709✔
830
        int r;
5,709✔
831

832
        r = strcmp(x->filename, y->filename);
5,709✔
833
        if (r != 0)
5,709✔
834
                return r;
835

836
        return CMP(x->line, y->line);
5,354✔
837
}
838

839
DEFINE_HASH_OPS(config_section_hash_ops, ConfigSection, config_section_hash_func, config_section_compare_func);
840

841
int config_section_new(const char *filename, unsigned line, ConfigSection **ret) {
6,793✔
842
        ConfigSection *cs;
6,793✔
843

844
        assert(filename);
6,793✔
845
        assert(line > 0);
6,793✔
846
        assert(ret);
6,793✔
847

848
        cs = malloc0(offsetof(ConfigSection, filename) + strlen(filename) + 1);
6,793✔
849
        if (!cs)
6,793✔
850
                return -ENOMEM;
851

852
        strcpy(cs->filename, filename);
6,793✔
853
        cs->line = line;
6,793✔
854

855
        *ret = TAKE_PTR(cs);
6,793✔
856
        return 0;
6,793✔
857
}
858

859
int _hashmap_by_section_find_unused_line(
32✔
860
                HashmapBase *entries_by_section,
861
                const char *filename,
862
                unsigned *ret) {
863

864
        ConfigSection *cs;
32✔
865
        unsigned n = 0;
32✔
866
        void *entry;
32✔
867

868
        HASHMAP_BASE_FOREACH_KEY(entry, cs, entries_by_section) {
542✔
869
                if (filename && !streq(cs->filename, filename))
510✔
UNCOV
870
                        continue;
×
871
                n = MAX(n, cs->line);
510✔
872
        }
873

874
        /* overflow? */
875
        if (n >= UINT_MAX)
32✔
876
                return -EFBIG;
32✔
877

878
        *ret = n + 1;
32✔
879
        return 0;
32✔
880
}
881

882
#define DEFINE_PARSER(type, vartype, conv_func)                         \
883
        DEFINE_CONFIG_PARSE_PTR(config_parse_##type, conv_func, vartype)
884

885
DEFINE_PARSER(int, int, safe_atoi);
186✔
UNCOV
886
DEFINE_PARSER(long, long, safe_atoli);
×
887
DEFINE_PARSER(uint8, uint8_t, safe_atou8);
23✔
888
DEFINE_PARSER(uint16, uint16_t, safe_atou16);
5✔
889
DEFINE_PARSER(uint32, uint32_t, safe_atou32);
170✔
890
DEFINE_PARSER(int32, int32_t, safe_atoi32);
12✔
891
DEFINE_PARSER(uint64, uint64_t, safe_atou64);
186✔
892
DEFINE_PARSER(unsigned, unsigned, safe_atou);
1,828✔
UNCOV
893
DEFINE_PARSER(double, double, safe_atod);
×
894
DEFINE_PARSER(nsec, nsec_t, parse_nsec);
7✔
895
DEFINE_PARSER(sec, usec_t, parse_sec);
3,558✔
UNCOV
896
DEFINE_PARSER(sec_def_infinity, usec_t, parse_sec_def_infinity);
×
897
DEFINE_PARSER(mode, mode_t, parse_mode);
6,031✔
898
DEFINE_PARSER(pid, pid_t, parse_pid);
2✔
899

900
int config_parse_iec_size(
770✔
901
                const char *unit,
902
                const char *filename,
903
                unsigned line,
904
                const char *section,
905
                unsigned section_line,
906
                const char *lvalue,
907
                int ltype,
908
                const char *rvalue,
909
                void *data,
910
                void *userdata) {
911

912
        size_t *sz = ASSERT_PTR(data);
770✔
913
        uint64_t v;
770✔
914
        int r;
770✔
915

916
        assert(filename);
770✔
917
        assert(lvalue);
770✔
918
        assert(rvalue);
770✔
919

920
        r = parse_size(rvalue, 1024, &v);
770✔
921
        if (r >= 0 && (uint64_t) (size_t) v != v)
770✔
922
                r = -ERANGE;
923
        if (r < 0)
770✔
924
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
3✔
925

926
        *sz = (size_t) v;
767✔
927
        return 1;
767✔
928
}
929

930
int config_parse_si_uint64(
9✔
931
                const char *unit,
932
                const char *filename,
933
                unsigned line,
934
                const char *section,
935
                unsigned section_line,
936
                const char *lvalue,
937
                int ltype,
938
                const char *rvalue,
939
                void *data,
940
                void *userdata) {
941

942
        uint64_t *sz = ASSERT_PTR(data);
9✔
943
        int r;
9✔
944

945
        assert(filename);
9✔
946
        assert(lvalue);
9✔
947
        assert(rvalue);
9✔
948

949
        r = parse_size(rvalue, 1000, sz);
9✔
950
        if (r < 0)
9✔
951
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
3✔
952

953
        return 1;
954
}
955

956
int config_parse_iec_uint64(
2✔
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
        uint64_t *bytes = ASSERT_PTR(data);
2✔
969
        int r;
2✔
970

971
        assert(filename);
2✔
972
        assert(lvalue);
2✔
973
        assert(rvalue);
2✔
974

975
        r = parse_size(rvalue, 1024, bytes);
2✔
976
        if (r < 0)
2✔
UNCOV
977
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
978

979
        return 1;
980
}
981

UNCOV
982
int config_parse_iec_uint64_infinity(
×
983
                const char *unit,
984
                const char *filename,
985
                unsigned line,
986
                const char *section,
987
                unsigned section_line,
988
                const char *lvalue,
989
                int ltype,
990
                const char *rvalue,
991
                void *data,
992
                void *userdata) {
993

UNCOV
994
        uint64_t *bytes = ASSERT_PTR(data);
×
995

UNCOV
996
        assert(rvalue);
×
997

998
        if (streq(rvalue, "infinity")) {
×
999
                *bytes = UINT64_MAX;
×
UNCOV
1000
                return 1;
×
1001
        }
1002

UNCOV
1003
        return config_parse_iec_uint64(unit, filename, line, section, section_line, lvalue, ltype, rvalue, data, userdata);
×
1004
}
1005

1006
int config_parse_bool(
49,351✔
1007
                const char *unit,
1008
                const char *filename,
1009
                unsigned line,
1010
                const char *section,
1011
                unsigned section_line,
1012
                const char *lvalue,
1013
                int ltype,
1014
                const char *rvalue,
1015
                void *data,
1016
                void *userdata) {
1017

1018
        bool *b = ASSERT_PTR(data);
49,351✔
1019
        bool fatal = ltype;
49,351✔
1020
        int r;
49,351✔
1021

1022
        assert(filename);
49,351✔
1023
        assert(lvalue);
49,351✔
1024
        assert(rvalue);
49,351✔
1025

1026
        r = parse_boolean(rvalue);
49,351✔
1027
        if (r < 0) {
49,351✔
1028
                log_syntax_parse_error_full(unit, filename, line, r, fatal, lvalue, rvalue);
×
UNCOV
1029
                return fatal ? -ENOEXEC : 0;
×
1030
        }
1031

1032
        *b = r;
49,351✔
1033
        return 1; /* set */
49,351✔
1034
}
1035

1036
int config_parse_uint32_flag(
68✔
1037
                const char *unit,
1038
                const char *filename,
1039
                unsigned line,
1040
                const char *section,
1041
                unsigned section_line,
1042
                const char *lvalue,
1043
                int ltype,
1044
                const char *rvalue,
1045
                void *data,
1046
                void *userdata) {
1047

1048
        uint32_t *flags = ASSERT_PTR(data);
68✔
1049
        int r;
68✔
1050

1051
        assert(ltype != 0);
68✔
1052

1053
        r = isempty(rvalue) ? 0 : parse_boolean(rvalue);
136✔
1054
        if (r < 0)
68✔
UNCOV
1055
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1056

1057
        SET_FLAG(*flags, ltype, r);
68✔
1058
        return 1;
68✔
1059
}
1060

1061
int config_parse_uint32_invert_flag(
64✔
1062
                const char *unit,
1063
                const char *filename,
1064
                unsigned line,
1065
                const char *section,
1066
                unsigned section_line,
1067
                const char *lvalue,
1068
                int ltype,
1069
                const char *rvalue,
1070
                void *data,
1071
                void *userdata) {
1072

1073
        uint32_t *flags = ASSERT_PTR(data);
64✔
1074
        int r;
64✔
1075

1076
        assert(ltype != 0);
64✔
1077

1078
        r = isempty(rvalue) ? 0 : parse_boolean(rvalue);
128✔
1079
        if (r < 0)
64✔
UNCOV
1080
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1081

1082
        SET_FLAG(*flags, ltype, !r);
64✔
1083
        return 1;
64✔
1084
}
1085

1086
int config_parse_id128(
11✔
1087
                const char *unit,
1088
                const char *filename,
1089
                unsigned line,
1090
                const char *section,
1091
                unsigned section_line,
1092
                const char *lvalue,
1093
                int ltype,
1094
                const char *rvalue,
1095
                void *data,
1096
                void *userdata) {
1097

1098
        sd_id128_t *result = data;
11✔
1099
        int r;
11✔
1100

1101
        assert(filename);
11✔
1102
        assert(lvalue);
11✔
1103
        assert(rvalue);
11✔
1104

1105
        r = id128_from_string_nonzero(rvalue, result);
11✔
1106
        if (r == -ENXIO) {
11✔
1107
                log_syntax(unit, LOG_WARNING, filename, line, r, "128-bit ID/UUID is all 0, ignoring: %s", rvalue);
×
UNCOV
1108
                return 0;
×
1109
        }
1110
        if (r < 0)
11✔
UNCOV
1111
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1112

1113
        return 1;
1114
}
1115

1116
int config_parse_tristate(
6,831✔
1117
                const char *unit,
1118
                const char *filename,
1119
                unsigned line,
1120
                const char *section,
1121
                unsigned section_line,
1122
                const char *lvalue,
1123
                int ltype,
1124
                const char *rvalue,
1125
                void *data,
1126
                void *userdata) {
1127

1128
        int r, *t = ASSERT_PTR(data);
6,831✔
1129

1130
        assert(filename);
6,831✔
1131
        assert(lvalue);
6,831✔
1132
        assert(rvalue);
6,831✔
1133

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

1137
        if (isempty(rvalue)) {
6,831✔
1138
                *t = -1;
×
UNCOV
1139
                return 1;
×
1140
        }
1141

1142
        r = parse_tristate(rvalue, t);
6,831✔
1143
        if (r < 0)
6,831✔
UNCOV
1144
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1145

1146
        return 1;
1147
}
1148

1149
int config_parse_string(
32,312✔
1150
                const char *unit,
1151
                const char *filename,
1152
                unsigned line,
1153
                const char *section,
1154
                unsigned section_line,
1155
                const char *lvalue,
1156
                int ltype,
1157
                const char *rvalue,
1158
                void *data,
1159
                void *userdata) {
1160

1161
        char **s = ASSERT_PTR(data);
32,312✔
1162
        int r;
32,312✔
1163

1164
        assert(filename);
32,312✔
1165
        assert(lvalue);
32,312✔
1166
        assert(rvalue);
32,312✔
1167

1168
        if (isempty(rvalue)) {
32,312✔
1169
                *s = mfree(*s);
×
UNCOV
1170
                return 1;
×
1171
        }
1172

1173
        if (FLAGS_SET(ltype, CONFIG_PARSE_STRING_SAFE) && !string_is_safe(rvalue)) {
32,312✔
UNCOV
1174
                _cleanup_free_ char *escaped = NULL;
×
1175

1176
                escaped = cescape(rvalue);
×
UNCOV
1177
                log_syntax(unit, LOG_WARNING, filename, line, 0,
×
1178
                           "Specified string contains unsafe characters, ignoring: %s", strna(escaped));
UNCOV
1179
                return 0;
×
1180
        }
1181

1182
        if (FLAGS_SET(ltype, CONFIG_PARSE_STRING_ASCII) && !ascii_is_valid(rvalue)) {
32,320✔
UNCOV
1183
                _cleanup_free_ char *escaped = NULL;
×
1184

1185
                escaped = cescape(rvalue);
×
UNCOV
1186
                log_syntax(unit, LOG_WARNING, filename, line, 0,
×
1187
                           "Specified string contains invalid ASCII characters, ignoring: %s", strna(escaped));
UNCOV
1188
                return 0;
×
1189
        }
1190

1191
        r = free_and_strdup_warn(s, rvalue);
32,312✔
1192
        if (r < 0)
32,312✔
UNCOV
1193
                return r;
×
1194

1195
        return 1;
1196
}
1197

1198
int config_parse_dns_name(
22✔
1199
                const char *unit,
1200
                const char *filename,
1201
                unsigned line,
1202
                const char *section,
1203
                unsigned section_line,
1204
                const char *lvalue,
1205
                int ltype,
1206
                const char *rvalue,
1207
                void *data,
1208
                void *userdata) {
1209

1210
        char **hostname = ASSERT_PTR(data);
22✔
1211
        int r;
22✔
1212

1213
        assert(filename);
22✔
1214
        assert(lvalue);
22✔
1215
        assert(rvalue);
22✔
1216

1217
        if (isempty(rvalue)) {
22✔
1218
                *hostname = mfree(*hostname);
×
UNCOV
1219
                return 1;
×
1220
        }
1221

1222
        r = dns_name_is_valid(rvalue);
22✔
1223
        if (r < 0) {
22✔
UNCOV
1224
                log_syntax(unit, LOG_WARNING, filename, line, r,
×
1225
                           "Failed to check validity of DNS domain name '%s', ignoring assignment: %m", rvalue);
UNCOV
1226
                return 0;
×
1227
        }
1228
        if (r == 0) {
22✔
UNCOV
1229
                log_syntax(unit, LOG_WARNING, filename, line, 0,
×
1230
                           "Specified invalid DNS domain name, ignoring assignment: %s", rvalue);
UNCOV
1231
                return 0;
×
1232
        }
1233

1234
        r = free_and_strdup_warn(hostname, rvalue);
22✔
1235
        if (r < 0)
22✔
UNCOV
1236
                return r;
×
1237

1238
        return 1;
1239
}
1240

1241
int config_parse_hostname(
22✔
1242
                const char *unit,
1243
                const char *filename,
1244
                unsigned line,
1245
                const char *section,
1246
                unsigned section_line,
1247
                const char *lvalue,
1248
                int ltype,
1249
                const char *rvalue,
1250
                void *data,
1251
                void *userdata) {
1252

1253
        char **hostname = ASSERT_PTR(data);
22✔
1254

1255
        assert(filename);
22✔
1256
        assert(lvalue);
22✔
1257
        assert(rvalue);
22✔
1258

1259
        if (isempty(rvalue)) {
22✔
1260
                *hostname = mfree(*hostname);
×
UNCOV
1261
                return 1;
×
1262
        }
1263

1264
        if (!hostname_is_valid(rvalue, 0)) {
22✔
UNCOV
1265
                log_syntax(unit, LOG_WARNING, filename, line, 0,
×
1266
                           "Specified invalid hostname, ignoring assignment: %s", rvalue);
UNCOV
1267
                return 0;
×
1268
        }
1269

1270
        return config_parse_dns_name(unit, filename, line, section, section_line,
22✔
1271
                                     lvalue, ltype, rvalue, data, userdata);
1272
}
1273

1274
int config_parse_path(
1,417✔
1275
                const char *unit,
1276
                const char *filename,
1277
                unsigned line,
1278
                const char *section,
1279
                unsigned section_line,
1280
                const char *lvalue,
1281
                int ltype,
1282
                const char *rvalue,
1283
                void *data,
1284
                void *userdata) {
1285

1286
        _cleanup_free_ char *n = NULL;
1,417✔
1287
        bool fatal = ltype;
1,417✔
1288
        char **s = ASSERT_PTR(data);
1,417✔
1289
        int r;
1,417✔
1290

1291
        assert(filename);
1,417✔
1292
        assert(lvalue);
1,417✔
1293
        assert(rvalue);
1,417✔
1294

1295
        if (isempty(rvalue)) {
1,417✔
1296
                *s = mfree(*s);
×
UNCOV
1297
                return 1;
×
1298
        }
1299

1300
        n = strdup(rvalue);
1,417✔
1301
        if (!n)
1,417✔
UNCOV
1302
                return log_oom();
×
1303

1304
        r = path_simplify_and_warn(n, PATH_CHECK_ABSOLUTE | (fatal ? PATH_CHECK_FATAL : 0), unit, filename, line, lvalue);
2,834✔
1305
        if (r < 0)
1,417✔
1306
                return fatal ? -ENOEXEC : 0;
2✔
1307

1308
        free_and_replace(*s, n);
1,415✔
1309
        return 1;
1,415✔
1310
}
1311

1312
int config_parse_strv(
30,885✔
1313
                const char *unit,
1314
                const char *filename,
1315
                unsigned line,
1316
                const char *section,
1317
                unsigned section_line,
1318
                const char *lvalue,
1319
                int ltype, /* When true, duplicated entries will be filtered. */
1320
                const char *rvalue,
1321
                void *data,
1322
                void *userdata) {
1323

1324
        char ***sv = ASSERT_PTR(data);
30,885✔
1325
        int r;
30,885✔
1326

1327
        assert(filename);
30,885✔
1328
        assert(lvalue);
30,885✔
1329
        assert(rvalue);
30,885✔
1330

1331
        if (isempty(rvalue)) {
30,885✔
1332
                *sv = strv_free(*sv);
2✔
1333
                return 1;
30,885✔
1334
        }
1335

1336
        _cleanup_strv_free_ char **strv = NULL;
30,883✔
1337
        for (const char *p = rvalue;;) {
67,302✔
1338
                char *word;
67,302✔
1339

1340
                r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
67,302✔
1341
                if (r < 0)
67,302✔
UNCOV
1342
                        return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1343
                if (r == 0)
67,302✔
1344
                        break;
1345

1346
                r = strv_consume(&strv, word);
36,419✔
1347
                if (r < 0)
36,419✔
UNCOV
1348
                        return log_oom();
×
1349
        }
1350

1351
        r = strv_extend_strv_consume(sv, TAKE_PTR(strv), /* filter_duplicates = */ ltype);
30,883✔
1352
        if (r < 0)
30,883✔
UNCOV
1353
                return log_oom();
×
1354

1355
        return 1;
1356
}
1357

UNCOV
1358
int config_parse_warn_compat(
×
1359
                const char *unit,
1360
                const char *filename,
1361
                unsigned line,
1362
                const char *section,
1363
                unsigned section_line,
1364
                const char *lvalue,
1365
                int ltype,
1366
                const char *rvalue,
1367
                void *data,
1368
                void *userdata) {
1369

UNCOV
1370
        Disabled reason = ltype;
×
1371

UNCOV
1372
        switch (reason) {
×
1373

1374
        case DISABLED_CONFIGURATION:
×
UNCOV
1375
                log_syntax(unit, LOG_DEBUG, filename, line, 0,
×
1376
                           "Support for option %s= has been disabled at compile time and it is ignored", lvalue);
1377
                break;
1378

1379
        case DISABLED_LEGACY:
×
UNCOV
1380
                log_syntax(unit, LOG_INFO, filename, line, 0,
×
1381
                           "Support for option %s= has been removed and it is ignored", lvalue);
1382
                break;
1383

1384
        case DISABLED_EXPERIMENTAL:
×
UNCOV
1385
                log_syntax(unit, LOG_INFO, filename, line, 0,
×
1386
                           "Support for option %s= has not yet been enabled and it is ignored", lvalue);
1387
                break;
1388
        }
1389

UNCOV
1390
        return 0;
×
1391
}
1392

1393
int config_parse_log_facility(
3✔
1394
                const char *unit,
1395
                const char *filename,
1396
                unsigned line,
1397
                const char *section,
1398
                unsigned section_line,
1399
                const char *lvalue,
1400
                int ltype,
1401
                const char *rvalue,
1402
                void *data,
1403
                void *userdata) {
1404

1405
        int *o = data, x;
3✔
1406

1407
        assert(filename);
3✔
1408
        assert(lvalue);
3✔
1409
        assert(rvalue);
3✔
1410
        assert(data);
3✔
1411

1412
        x = log_facility_unshifted_from_string(rvalue);
3✔
1413
        if (x < 0)
3✔
1414
                return log_syntax_parse_error(unit, filename, line, x, lvalue, rvalue);
1✔
1415

1416
        *o = (x << 3) | LOG_PRI(*o);
2✔
1417

1418
        return 1;
2✔
1419
}
1420

1421
int config_parse_log_level(
3✔
1422
                const char *unit,
1423
                const char *filename,
1424
                unsigned line,
1425
                const char *section,
1426
                unsigned section_line,
1427
                const char *lvalue,
1428
                int ltype,
1429
                const char *rvalue,
1430
                void *data,
1431
                void *userdata) {
1432

1433
        int *o = data, x;
3✔
1434

1435
        assert(filename);
3✔
1436
        assert(lvalue);
3✔
1437
        assert(rvalue);
3✔
1438
        assert(data);
3✔
1439

1440
        x = log_level_from_string(rvalue);
3✔
1441
        if (x < 0)
3✔
1442
                return log_syntax_parse_error(unit, filename, line, x, lvalue, rvalue);
1✔
1443

1444
        if (*o < 0) /* if it wasn't initialized so far, assume zero facility */
2✔
UNCOV
1445
                *o = x;
×
1446
        else
1447
                *o = (*o & LOG_FACMASK) | x;
2✔
1448

1449
        return 1;
1450
}
1451

1452
int config_parse_signal(
241✔
1453
                const char *unit,
1454
                const char *filename,
1455
                unsigned line,
1456
                const char *section,
1457
                unsigned section_line,
1458
                const char *lvalue,
1459
                int ltype,
1460
                const char *rvalue,
1461
                void *data,
1462
                void *userdata) {
1463

1464
        int *sig = data, r;
241✔
1465

1466
        assert(filename);
241✔
1467
        assert(lvalue);
241✔
1468
        assert(rvalue);
241✔
1469
        assert(sig);
241✔
1470

1471
        r = signal_from_string(rvalue);
241✔
1472
        if (r <= 0)
241✔
UNCOV
1473
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1474

1475
        *sig = r;
241✔
1476
        return 1;
241✔
1477
}
1478

UNCOV
1479
int config_parse_personality(
×
1480
                const char *unit,
1481
                const char *filename,
1482
                unsigned line,
1483
                const char *section,
1484
                unsigned section_line,
1485
                const char *lvalue,
1486
                int ltype,
1487
                const char *rvalue,
1488
                void *data,
1489
                void *userdata) {
1490

UNCOV
1491
        unsigned long *personality = data, p;
×
1492

1493
        assert(filename);
×
1494
        assert(lvalue);
×
1495
        assert(rvalue);
×
UNCOV
1496
        assert(personality);
×
1497

1498
        if (isempty(rvalue)) {
×
1499
                *personality = PERSONALITY_INVALID;
×
UNCOV
1500
                return 1;
×
1501
        }
1502

1503
        p = personality_from_string(rvalue);
×
1504
        if (p == PERSONALITY_INVALID)
×
UNCOV
1505
                return log_syntax_parse_error(unit, filename, line, 0, lvalue, rvalue);
×
1506

1507
        *personality = p;
×
UNCOV
1508
        return 1;
×
1509
}
1510

1511
int config_parse_ifname(
1,718✔
1512
                const char *unit,
1513
                const char *filename,
1514
                unsigned line,
1515
                const char *section,
1516
                unsigned section_line,
1517
                const char *lvalue,
1518
                int ltype,
1519
                const char *rvalue,
1520
                void *data,
1521
                void *userdata) {
1522

1523
        char **s = ASSERT_PTR(data);
1,718✔
1524
        int r;
1,718✔
1525

1526
        assert(filename);
1,718✔
1527
        assert(lvalue);
1,718✔
1528
        assert(rvalue);
1,718✔
1529

1530
        if (isempty(rvalue)) {
1,718✔
1531
                *s = mfree(*s);
×
UNCOV
1532
                return 1;
×
1533
        }
1534

1535
        if (!ifname_valid(rvalue)) {
1,718✔
1536
                log_syntax(unit, LOG_WARNING, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue);
×
UNCOV
1537
                return 0;
×
1538
        }
1539

1540
        r = free_and_strdup_warn(s, rvalue);
1,718✔
1541
        if (r < 0)
1,718✔
UNCOV
1542
                return r;
×
1543

1544
        return 1;
1545
}
1546

1547
int config_parse_ifnames(
16✔
1548
                const char *unit,
1549
                const char *filename,
1550
                unsigned line,
1551
                const char *section,
1552
                unsigned section_line,
1553
                const char *lvalue,
1554
                int ltype,
1555
                const char *rvalue,
1556
                void *data,
1557
                void *userdata) {
1558

1559
        _cleanup_strv_free_ char **names = NULL;
16✔
1560
        char ***s = ASSERT_PTR(data);
16✔
1561
        int r;
16✔
1562

1563
        assert(filename);
16✔
1564
        assert(lvalue);
16✔
1565
        assert(rvalue);
16✔
1566

1567
        if (isempty(rvalue)) {
16✔
1568
                *s = strv_free(*s);
×
UNCOV
1569
                return 1;
×
1570
        }
1571

1572
        for (const char *p = rvalue;;) {
16✔
1573
                _cleanup_free_ char *word = NULL;
30✔
1574

1575
                r = extract_first_word(&p, &word, NULL, 0);
46✔
1576
                if (r < 0)
46✔
UNCOV
1577
                        return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1578
                if (r == 0)
46✔
1579
                        break;
1580

1581
                if (!ifname_valid_full(word, ltype)) {
30✔
UNCOV
1582
                        log_syntax(unit, LOG_WARNING, filename, line, 0,
×
1583
                                   "Interface name is not valid or too long, ignoring assignment: %s",
1584
                                   word);
UNCOV
1585
                        continue;
×
1586
                }
1587

1588
                r = strv_consume(&names, TAKE_PTR(word));
30✔
1589
                if (r < 0)
30✔
UNCOV
1590
                        return log_oom();
×
1591
        }
1592

1593
        r = strv_extend_strv(s, names, true);
16✔
1594
        if (r < 0)
16✔
UNCOV
1595
                return log_oom();
×
1596

1597
        return 1;
1598
}
1599

1600
int config_parse_ip_port(
27✔
1601
                const char *unit,
1602
                const char *filename,
1603
                unsigned line,
1604
                const char *section,
1605
                unsigned section_line,
1606
                const char *lvalue,
1607
                int ltype,
1608
                const char *rvalue,
1609
                void *data,
1610
                void *userdata) {
1611

1612
        uint16_t *s = ASSERT_PTR(data);
27✔
1613
        uint16_t port;
27✔
1614
        int r;
27✔
1615

1616
        assert(filename);
27✔
1617
        assert(lvalue);
27✔
1618
        assert(rvalue);
27✔
1619

1620
        if (isempty(rvalue)) {
27✔
1621
                *s = 0;
×
UNCOV
1622
                return 1;
×
1623
        }
1624

1625
        r = parse_ip_port(rvalue, &port);
27✔
1626
        if (r < 0)
27✔
UNCOV
1627
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1628

1629
        *s = port;
27✔
1630
        return 1;
27✔
1631
}
1632

1633
int config_parse_mtu(
141✔
1634
                const char *unit,
1635
                const char *filename,
1636
                unsigned line,
1637
                const char *section,
1638
                unsigned section_line,
1639
                const char *lvalue,
1640
                int ltype,
1641
                const char *rvalue,
1642
                void *data,
1643
                void *userdata) {
1644

1645
        uint32_t *mtu = ASSERT_PTR(data);
141✔
1646
        int r;
141✔
1647

1648
        assert(rvalue);
141✔
1649

1650
        r = parse_mtu(ltype, rvalue, mtu);
141✔
1651
        if (r == -ERANGE) {
141✔
UNCOV
1652
                log_syntax(unit, LOG_WARNING, filename, line, r,
×
1653
                           "Maximum transfer unit (MTU) value out of range. Permitted range is %" PRIu32 "…%" PRIu32 ", ignoring: %s",
1654
                           (uint32_t) (ltype == AF_INET6 ? IPV6_MIN_MTU : IPV4_MIN_MTU), (uint32_t) UINT32_MAX,
1655
                           rvalue);
UNCOV
1656
                return 0;
×
1657
        }
1658
        if (r < 0)
141✔
UNCOV
1659
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1660

1661
        return 1;
1662
}
1663

1664
int config_parse_rlimit(
811✔
1665
                const char *unit,
1666
                const char *filename,
1667
                unsigned line,
1668
                const char *section,
1669
                unsigned section_line,
1670
                const char *lvalue,
1671
                int ltype,
1672
                const char *rvalue,
1673
                void *data,
1674
                void *userdata) {
1675

1676
        struct rlimit **rl = data, d = {};
811✔
1677
        int r;
811✔
1678

1679
        assert(rvalue);
811✔
1680
        assert(rl);
811✔
1681

1682
        r = rlimit_parse(ltype, rvalue, &d);
811✔
1683
        if (r == -EILSEQ) {
811✔
1684
                log_syntax(unit, LOG_WARNING, filename, line, r, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue);
1✔
1685
                return 0;
1✔
1686
        }
1687
        if (r < 0)
810✔
1688
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
3✔
1689

1690
        if (rl[ltype])
807✔
1691
                *rl[ltype] = d;
13✔
1692
        else {
1693
                rl[ltype] = newdup(struct rlimit, &d, 1);
794✔
1694
                if (!rl[ltype])
794✔
UNCOV
1695
                        return log_oom();
×
1696
        }
1697

1698
        return 1;
1699
}
1700

UNCOV
1701
int config_parse_permille(
×
1702
                const char *unit,
1703
                const char *filename,
1704
                unsigned line,
1705
                const char *section,
1706
                unsigned section_line,
1707
                const char *lvalue,
1708
                int ltype,
1709
                const char *rvalue,
1710
                void *data,
1711
                void *userdata) {
1712

1713
        unsigned *permille = ASSERT_PTR(data);
×
UNCOV
1714
        int r;
×
1715

1716
        assert(filename);
×
1717
        assert(lvalue);
×
UNCOV
1718
        assert(rvalue);
×
1719

1720
        r = parse_permille(rvalue);
×
1721
        if (r < 0)
×
UNCOV
1722
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1723

1724
        *permille = (unsigned) r;
×
UNCOV
1725
        return 1;
×
1726
}
1727

1728
int config_parse_vlanprotocol(
2✔
1729
                const char *unit,
1730
                const char *filename,
1731
                unsigned line,
1732
                const char *section,
1733
                unsigned section_line,
1734
                const char *lvalue,
1735
                int ltype,
1736
                const char *rvalue,
1737
                void *data,
1738
                void *userdata) {
1739

1740
        int *vlan_protocol = data;
2✔
1741

1742
        assert(filename);
2✔
1743
        assert(lvalue);
2✔
1744

1745
        if (isempty(rvalue)) {
2✔
1746
                *vlan_protocol = -1;
×
UNCOV
1747
                return 1;
×
1748
        }
1749

1750
        if (STR_IN_SET(rvalue, "802.1ad", "802.1AD"))
2✔
1751
                *vlan_protocol = ETH_P_8021AD;
2✔
1752
        else if (STR_IN_SET(rvalue, "802.1q", "802.1Q"))
×
UNCOV
1753
                *vlan_protocol = ETH_P_8021Q;
×
1754
        else
UNCOV
1755
                return log_syntax_parse_error(unit, filename, line, 0, lvalue, rvalue);
×
1756

1757
        return 1;
2✔
1758
}
1759

1760
int config_parse_hw_addr(
499✔
1761
                const char *unit,
1762
                const char *filename,
1763
                unsigned line,
1764
                const char *section,
1765
                unsigned section_line,
1766
                const char *lvalue,
1767
                int ltype,
1768
                const char *rvalue,
1769
                void *data,
1770
                void *userdata) {
1771

1772
        struct hw_addr_data *hwaddr = ASSERT_PTR(data);
499✔
1773
        int r;
499✔
1774

1775
        assert(filename);
499✔
1776
        assert(lvalue);
499✔
1777
        assert(rvalue);
499✔
1778

1779
        if (isempty(rvalue)) {
499✔
1780
                *hwaddr = HW_ADDR_NULL;
×
UNCOV
1781
                return 1;
×
1782
        }
1783

1784
        r = parse_hw_addr_full(rvalue, ltype, hwaddr);
499✔
1785
        if (r < 0)
499✔
UNCOV
1786
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1787

1788
        return 1;
1789
}
1790

1791
int config_parse_hw_addrs(
17✔
1792
                const char *unit,
1793
                const char *filename,
1794
                unsigned line,
1795
                const char *section,
1796
                unsigned section_line,
1797
                const char *lvalue,
1798
                int ltype,
1799
                const char *rvalue,
1800
                void *data,
1801
                void *userdata) {
1802

1803
        Set **hwaddrs = ASSERT_PTR(data);
17✔
1804
        int r;
17✔
1805

1806
        assert(filename);
17✔
1807
        assert(lvalue);
17✔
1808
        assert(rvalue);
17✔
1809

1810
        if (isempty(rvalue)) {
17✔
1811
                /* Empty assignment resets the list */
1812
                *hwaddrs = set_free(*hwaddrs);
×
UNCOV
1813
                return 1;
×
1814
        }
1815

1816
        for (const char *p = rvalue;;) {
17✔
1817
                _cleanup_free_ char *word = NULL;
17✔
1818
                _cleanup_free_ struct hw_addr_data *n = NULL;
34✔
1819

1820
                r = extract_first_word(&p, &word, NULL, 0);
34✔
1821
                if (r < 0)
34✔
UNCOV
1822
                        return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1823
                if (r == 0)
34✔
1824
                        return 1;
1825

1826
                n = new(struct hw_addr_data, 1);
17✔
1827
                if (!n)
17✔
UNCOV
1828
                        return log_oom();
×
1829

1830
                r = parse_hw_addr_full(word, ltype, n);
17✔
1831
                if (r < 0) {
17✔
UNCOV
1832
                        log_syntax(unit, LOG_WARNING, filename, line, r,
×
1833
                                   "Not a valid hardware address, ignoring: %s", word);
UNCOV
1834
                        continue;
×
1835
                }
1836

1837
                r = set_ensure_consume(hwaddrs, &hw_addr_hash_ops_free, TAKE_PTR(n));
17✔
1838
                if (r < 0)
17✔
UNCOV
1839
                        return log_oom();
×
1840
        }
1841
}
1842

1843
int config_parse_ether_addr(
26✔
1844
                const char *unit,
1845
                const char *filename,
1846
                unsigned line,
1847
                const char *section,
1848
                unsigned section_line,
1849
                const char *lvalue,
1850
                int ltype,
1851
                const char *rvalue,
1852
                void *data,
1853
                void *userdata) {
1854

1855
        _cleanup_free_ struct ether_addr *n = NULL;
26✔
1856
        struct ether_addr **hwaddr = ASSERT_PTR(data);
26✔
1857
        int r;
26✔
1858

1859
        assert(filename);
26✔
1860
        assert(lvalue);
26✔
1861
        assert(rvalue);
26✔
1862

1863
        if (isempty(rvalue)) {
26✔
1864
                *hwaddr = mfree(*hwaddr);
1✔
1865
                return 1;
1✔
1866
        }
1867

1868
        n = new0(struct ether_addr, 1);
25✔
1869
        if (!n)
25✔
UNCOV
1870
                return log_oom();
×
1871

1872
        r = parse_ether_addr(rvalue, n);
25✔
1873
        if (r < 0)
25✔
1874
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
15✔
1875

1876
        free_and_replace(*hwaddr, n);
10✔
1877
        return 1;
10✔
1878
}
1879

1880
int config_parse_ether_addrs(
28✔
1881
                const char *unit,
1882
                const char *filename,
1883
                unsigned line,
1884
                const char *section,
1885
                unsigned section_line,
1886
                const char *lvalue,
1887
                int ltype,
1888
                const char *rvalue,
1889
                void *data,
1890
                void *userdata) {
1891

1892
        Set **hwaddrs = ASSERT_PTR(data);
28✔
1893
        int r;
28✔
1894

1895
        assert(filename);
28✔
1896
        assert(lvalue);
28✔
1897
        assert(rvalue);
28✔
1898

1899
        if (isempty(rvalue)) {
28✔
1900
                /* Empty assignment resets the list */
1901
                *hwaddrs = set_free(*hwaddrs);
1✔
1902
                return 1;
1✔
1903
        }
1904

1905
        for (const char *p = rvalue;;) {
27✔
1906
                _cleanup_free_ char *word = NULL;
20✔
1907
                _cleanup_free_ struct ether_addr *n = NULL;
65✔
1908

1909
                r = extract_first_word(&p, &word, NULL, 0);
65✔
1910
                if (r < 0)
65✔
UNCOV
1911
                        return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1912
                if (r == 0)
65✔
1913
                        return 1;
1914

1915
                n = new(struct ether_addr, 1);
38✔
1916
                if (!n)
38✔
UNCOV
1917
                        return log_oom();
×
1918

1919
                r = parse_ether_addr(word, n);
38✔
1920
                if (r < 0) {
38✔
1921
                        log_syntax(unit, LOG_WARNING, filename, line, r,
18✔
1922
                                   "Not a valid MAC address, ignoring: %s", word);
1923
                        continue;
18✔
1924
                }
1925

1926
                r = set_ensure_consume(hwaddrs, &ether_addr_hash_ops_free, TAKE_PTR(n));
20✔
1927
                if (r < 0)
20✔
UNCOV
1928
                        return log_oom();
×
1929
        }
1930
}
1931

1932
int config_parse_in_addr_non_null(
45✔
1933
                const char *unit,
1934
                const char *filename,
1935
                unsigned line,
1936
                const char *section,
1937
                unsigned section_line,
1938
                const char *lvalue,
1939
                int ltype,
1940
                const char *rvalue,
1941
                void *data,
1942
                void *userdata) {
1943

1944
        /* data must be a pointer to struct in_addr or in6_addr, and the type is determined by ltype. */
1945
        struct in_addr *ipv4 = ASSERT_PTR(data);
45✔
1946
        struct in6_addr *ipv6 = ASSERT_PTR(data);
45✔
1947
        union in_addr_union a;
45✔
1948
        int r;
45✔
1949

1950
        assert(filename);
45✔
1951
        assert(lvalue);
45✔
1952
        assert(rvalue);
45✔
1953
        assert(IN_SET(ltype, AF_INET, AF_INET6));
45✔
1954

1955
        if (isempty(rvalue)) {
45✔
1956
                if (ltype == AF_INET)
×
UNCOV
1957
                        *ipv4 = (struct in_addr) {};
×
1958
                else
1959
                        *ipv6 = (struct in6_addr) {};
×
UNCOV
1960
                return 1;
×
1961
        }
1962

1963
        r = in_addr_from_string(ltype, rvalue, &a);
45✔
1964
        if (r < 0)
45✔
1965
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
18✔
1966

1967
        if (!in_addr_is_set(ltype, &a)) {
27✔
UNCOV
1968
                log_syntax(unit, LOG_WARNING, filename, line, 0,
×
1969
                           "%s= cannot be the ANY address, ignoring: %s", lvalue, rvalue);
UNCOV
1970
                return 0;
×
1971
        }
1972

1973
        if (ltype == AF_INET)
27✔
1974
                *ipv4 = a.in;
26✔
1975
        else
1976
                *ipv6 = a.in6;
1✔
1977
        return 1;
1978
}
1979

1980
int config_parse_in_addr_data(
73✔
1981
                const char *unit,
1982
                const char *filename,
1983
                unsigned line,
1984
                const char *section,
1985
                unsigned section_line,
1986
                const char *lvalue,
1987
                int ltype,
1988
                const char *rvalue,
1989
                void *data,
1990
                void *userdata) {
1991

1992
        struct in_addr_data *p = ASSERT_PTR(data);
73✔
1993
        int r;
73✔
1994

1995
        assert(filename);
73✔
1996
        assert(lvalue);
73✔
1997

1998
        if (isempty(rvalue)) {
73✔
1999
                *p = (struct in_addr_data) {};
×
UNCOV
2000
                return 1;
×
2001
        }
2002

2003
        r = in_addr_from_string_auto(rvalue, &p->family, &p->address);
73✔
2004
        if (r < 0)
73✔
UNCOV
2005
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
2006

2007
        return 1;
2008
}
2009

2010
int config_parse_in_addr_prefix(
4,048✔
2011
                const char *unit,
2012
                const char *filename,
2013
                unsigned line,
2014
                const char *section,
2015
                unsigned section_line,
2016
                const char *lvalue,
2017
                int ltype, /* takes boolean, whether we warn about missing prefixlen */
2018
                const char *rvalue,
2019
                void *data,
2020
                void *userdata) {
2021

2022
        struct in_addr_prefix *p = ASSERT_PTR(data);
4,048✔
2023
        int r;
4,048✔
2024

2025
        assert(filename);
4,048✔
2026
        assert(lvalue);
4,048✔
2027

2028
        if (isempty(rvalue)) {
4,048✔
2029
                *p = (struct in_addr_prefix) {};
×
UNCOV
2030
                return 1;
×
2031
        }
2032

2033
        r = in_addr_prefix_from_string_auto_full(rvalue, ltype ? PREFIXLEN_REFUSE : PREFIXLEN_FULL, &p->family, &p->address, &p->prefixlen);
4,048✔
2034
        if (r == -ENOANO) {
4,048✔
2035
                r = in_addr_prefix_from_string_auto(rvalue, &p->family, &p->address, &p->prefixlen);
14✔
2036
                if (r >= 0)
14✔
2037
                        log_syntax(unit, LOG_WARNING, filename, line, r,
14✔
2038
                                   "%s=%s is specified without prefix length. Assuming the prefix length is %u. "
2039
                                   "Please specify the prefix length explicitly.", lvalue, rvalue, p->prefixlen);
2040
        }
2041
        if (r < 0)
4,048✔
2042
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
35✔
2043

2044
        return 1;
2045
}
2046

2047
int config_parse_unsigned_bounded(
90✔
2048
                const char *unit,
2049
                const char *filename,
2050
                unsigned line,
2051
                const char *section,
2052
                unsigned section_line,
2053
                const char *lvalue,
2054
                const char *rvalue,
2055
                unsigned min,
2056
                unsigned max,
2057
                bool ignoring,
2058
                unsigned *ret) {
2059

2060
        int r;
90✔
2061

2062
        assert(filename);
90✔
2063
        assert(lvalue);
90✔
2064
        assert(rvalue);
90✔
2065
        assert(ret);
90✔
2066

2067
        r = safe_atou_bounded(rvalue, min, max, ret);
90✔
2068
        if (r == -ERANGE) {
90✔
UNCOV
2069
                log_syntax(unit, LOG_WARNING, filename, line, r,
×
2070
                           "Invalid '%s=%s', allowed range is %u..%u%s.",
2071
                           lvalue, rvalue, min, max, ignoring ? ", ignoring" : "");
UNCOV
2072
                return ignoring ? 0 : r;
×
2073
        }
2074
        if (r < 0)
90✔
UNCOV
2075
                return log_syntax_parse_error_full(unit, filename, line, r, /* critical = */ !ignoring, lvalue, rvalue);
×
2076

2077
        return 1;  /* Return 1 if something was set */
2078
}
2079

UNCOV
2080
int config_parse_calendar(
×
2081
                const char *unit,
2082
                const char *filename,
2083
                unsigned line,
2084
                const char *section,
2085
                unsigned section_line,
2086
                const char *lvalue,
2087
                int ltype,
2088
                const char *rvalue,
2089
                void *data,
2090
                void *userdata) {
2091

2092
        CalendarSpec **cr = data;
×
2093
        _cleanup_(calendar_spec_freep) CalendarSpec *c = NULL;
×
UNCOV
2094
        int r;
×
2095

2096
        assert(filename);
×
2097
        assert(lvalue);
×
2098
        assert(rvalue);
×
UNCOV
2099
        assert(data);
×
2100

2101
        if (isempty(rvalue)) {
×
2102
                *cr = calendar_spec_free(*cr);
×
UNCOV
2103
                return 1;
×
2104
        }
2105

2106
        r = calendar_spec_from_string(rvalue, &c);
×
2107
        if (r < 0)
×
UNCOV
2108
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
2109

2110
        free_and_replace_full(*cr, c, calendar_spec_free);
×
UNCOV
2111
        return 1;
×
2112
}
2113

UNCOV
2114
DEFINE_CONFIG_PARSE(config_parse_percent, parse_percent);
×
2115
DEFINE_CONFIG_PARSE(config_parse_permyriad, parse_permyriad);
1✔
2116
DEFINE_CONFIG_PARSE_PTR(config_parse_sec_fix_0, parse_sec_fix_0, usec_t);
258✔
2117

2118
int config_parse_timezone(
1✔
2119
                const char *unit,
2120
                const char *filename,
2121
                unsigned line,
2122
                const char *section,
2123
                unsigned section_line,
2124
                const char *lvalue,
2125
                int ltype,
2126
                const char *rvalue,
2127
                void *data,
2128
                void *userdata) {
2129

2130
        char **tz = ASSERT_PTR(data);
1✔
2131
        int r;
1✔
2132

2133
        assert(filename);
1✔
2134
        assert(lvalue);
1✔
2135
        assert(rvalue);
1✔
2136

2137
        if (isempty(rvalue)) {
1✔
2138
                *tz = mfree(*tz);
×
UNCOV
2139
                return 1;
×
2140
        }
2141

2142
        r = verify_timezone(rvalue, LOG_WARNING);
1✔
2143
        if (r < 0)
1✔
UNCOV
2144
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
2145

2146
        r = free_and_strdup_warn(tz, rvalue);
1✔
2147
        if (r < 0)
1✔
UNCOV
2148
                return r;
×
2149

2150
        return 1;
2151
}
2152

2153
int config_parse_ip_protocol(
6✔
2154
                const char *unit,
2155
                const char *filename,
2156
                unsigned line,
2157
                const char *section,
2158
                unsigned section_line,
2159
                const char *lvalue,
2160
                int ltype,
2161
                const char *rvalue,
2162
                void *data,
2163
                void *userdata) {
2164

2165
        uint8_t *proto = ASSERT_PTR(data);
6✔
2166
        int r;
6✔
2167

2168
        r = isempty(rvalue) ? 0 : parse_ip_protocol_full(rvalue, /* relaxed= */ ltype);
12✔
2169
        if (r < 0)
6✔
UNCOV
2170
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
2171

2172
        if (r > UINT8_MAX) {
6✔
2173
                /* linux/fib_rules.h and linux/fou.h define the netlink field as one byte, so we need to
2174
                 * reject protocols numbers that don't fit in one byte. */
UNCOV
2175
                log_syntax(unit, LOG_WARNING, filename, line, r,
×
2176
                           "Invalid '%s=%s', allowed range is 0..255, ignoring.",
2177
                           lvalue, rvalue);
UNCOV
2178
                return 0;
×
2179
        }
2180

2181
        *proto = r;
6✔
2182
        return 1; /* done. */
6✔
2183
}
2184

2185
int config_parse_loadavg(
1✔
2186
                const char *unit,
2187
                const char *filename,
2188
                unsigned line,
2189
                const char *section,
2190
                unsigned section_line,
2191
                const char *lvalue,
2192
                int ltype,
2193
                const char *rvalue,
2194
                void *data,
2195
                void *userdata) {
2196

2197
        loadavg_t *i = ASSERT_PTR(data);
1✔
2198
        int r;
1✔
2199

2200
        assert(rvalue);
1✔
2201

2202
        r = parse_permyriad(rvalue);
1✔
2203
        if (r < 0)
1✔
UNCOV
2204
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
2205

2206
        r = store_loadavg_fixed_point(r / 100, r % 100, i);
1✔
2207
        if (r < 0)
1✔
UNCOV
2208
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
2209

2210
        return 1; /* done. */
2211
}
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