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

systemd / systemd / 21419361949

27 Jan 2026 02:53PM UTC coverage: 72.793% (-0.03%) from 72.821%
21419361949

push

github

keszybz
kernel-install: handle removal unsuccessful UKIs and loader entries separately

When a tries file exists, 90-uki-copy.install removes a previous UKI of the
same kernel version and all it's unbooted variants. This removal is guarded
behind a check for the existence of the already booted UKI, i.e. if uki.efi
already exists, uki.efi and uki+*.efi will be removed.

This leaves the edge case that if uki.efi does not exist, but only an unbooted,
e.g. uki+3.efi, it will not be removed. This is not a problem, if the number of
tries is constant between both builds, since a new uki+3.efi would overwrite
the existing one, but if the number of tries is changed to, e.g. uki+5.efi, we
are left with both uki+3.efi and uki+5.efi.

The same is done for loader entries.

311334 of 427698 relevant lines covered (72.79%)

1157141.18 hits per line

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

76.75
/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,
537✔
47
                                              char, path_hash_func, path_compare,
48
                                              FILE, safe_fclose);
49

50
int config_item_table_lookup(
8,534✔
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);
8,534✔
60
        assert(lvalue);
8,534✔
61
        assert(ret_func);
8,534✔
62
        assert(ret_ltype);
8,534✔
63
        assert(ret_data);
8,534✔
64

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

67
                if (!streq(lvalue, t->lvalue))
94,343✔
68
                        continue;
83,697✔
69

70
                if (!streq_ptr(section, t->section))
10,646✔
71
                        continue;
2,112✔
72

73
                *ret_func = t->parse;
8,534✔
74
                *ret_ltype = t->ltype;
8,534✔
75
                *ret_data = t->data;
8,534✔
76
                return 1;
8,534✔
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(
433,786✔
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;
433,786✔
95
        const ConfigPerfItem *p;
433,786✔
96

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

103
        if (section) {
433,786✔
104
                const char *key;
433,786✔
105

106
                key = strjoina(section, ".", lvalue);
3,036,502✔
107
                p = lookup(key, strlen(key));
433,786✔
108
        } else
109
                p = lookup(lvalue, strlen(lvalue));
×
110
        if (!p) {
433,786✔
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;
433,781✔
118
        *ret_ltype = p->ltype;
433,781✔
119
        *ret_data = (uint8_t*) userdata + p->offset;
433,781✔
120
        return 1;
433,781✔
121
}
122

123
/* Run the user supplied parser for an assignment */
124
static int next_assignment(
442,320✔
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;
442,320✔
138
        int ltype = 0;
442,320✔
139
        void *data = NULL;
442,320✔
140
        int r;
442,320✔
141

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

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

155
                return func(unit, filename, line, section, section_line,
434,120✔
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(
771,418✔
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;
771,418✔
187

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

193
        l = strstrip(l);
771,418✔
194
        if (isempty(l))
1,542,836✔
195
                return 0;
196

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

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

203
        if (l[0] == '[') {
626,415✔
204
                _cleanup_free_ char *n = NULL;
121,243✔
205
                size_t k;
121,243✔
206

207
                k = strlen(l);
121,243✔
208
                assert(k > 0);
121,243✔
209

210
                if (l[k-1] != ']')
121,243✔
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);
121,243✔
214
                if (!n)
121,243✔
215
                        return log_oom();
×
216

217
                if (!string_is_safe(n))
121,243✔
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)) {
121,243✔
221
                        bool ignore;
7,362✔
222

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

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

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

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

244
                return 0;
121,243✔
245
        }
246

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

251
                return 0;
62,852✔
252
        }
253

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

262
        *e = 0;
442,320✔
263
        e++;
442,320✔
264

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

278
/* Go through the file and parse each line */
279
int config_parse(
89,444✔
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;
89,444✔
291
        _cleanup_fclose_ FILE *ours = NULL;
89,444✔
292
        unsigned line = 0, section_line = 0;
89,444✔
293
        bool section_ignored = false, bom_seen = false;
89,444✔
294
        struct stat st;
89,444✔
295
        int r, fd;
89,444✔
296

297
        assert(filename);
89,444✔
298
        assert(lookup);
89,444✔
299

300
        if (!f) {
89,444✔
301
                f = ours = fopen(filename, "re");
13,052✔
302
                if (!f) {
13,052✔
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);
89,444✔
321
        if (fd >= 0) { /* stream might not have an fd, let's be careful hence */
89,444✔
322

323
                if (fstat(fd, &st) < 0)
89,444✔
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);
89,444✔
328
        } else
329
                st = (struct stat) {};
×
330

331
        for (;;) {
1,510,521✔
332
                _cleanup_free_ char *buf = NULL;
1,421,079✔
333
                bool escaped = false;
1,510,521✔
334
                char *l, *p, *e;
1,510,521✔
335

336
                r = read_line(f, LONG_LINE_MAX, &buf);
1,510,521✔
337
                if (r == 0)
1,510,521✔
338
                        break;
339
                if (r == -ENOBUFS) {
1,421,079✔
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,421,078✔
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,421,078✔
353

354
                l = skip_leading_chars(buf, WHITESPACE);
1,421,078✔
355
                if (*l != '\0' && strchr(COMMENTS, *l))
1,421,078✔
356
                        continue;
644,944✔
357

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

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

369
                if (continuation) {
776,134✔
370
                        if (strlen(continuation) + strlen(l) > LONG_LINE_MAX) {
4,715✔
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,714✔
377
                                if (flags & CONFIG_PARSE_WARN)
×
378
                                        log_oom();
×
379
                                return -ENOMEM;
×
380
                        }
381

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

386
                for (e = p; *e; e++) {
539,937,575✔
387
                        if (escaped)
539,161,442✔
388
                                escaped = false;
389
                        else if (*e == '\\')
539,161,134✔
390
                                escaped = true;
5,025✔
391
                }
392

393
                if (escaped) {
776,133✔
394
                        *(e-1) = ' ';
4,717✔
395

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

405
                        continue;
4,717✔
406
                }
407

408
                r = parse_line(unit,
771,416✔
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) {
771,416✔
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);
771,416✔
427
        }
428

429
        if (continuation) {
89,442✔
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)
89,442✔
450
                *ret_stat = st;
51,100✔
451

452
        return 1;
453
}
454

455
int hashmap_put_stats_by_path(Hashmap **stats_by_path, const char *path, const struct stat *st) {
52,405✔
456
        _cleanup_free_ struct stat *st_copy = NULL;
104,810✔
457
        _cleanup_free_ char *path_copy = NULL;
52,405✔
458
        int r;
52,405✔
459

460
        assert(stats_by_path);
52,405✔
461
        assert(path);
52,405✔
462
        assert(st);
52,405✔
463

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

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

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

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

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

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

500
        if (ret_stats_by_path) {
37,888✔
501
                stats_by_path = hashmap_new(&path_hash_ops_free_free);
9,778✔
502
                if (!stats_by_path)
9,778✔
503
                        return log_oom_full(level);
×
504
        }
505

506
        /* Pin and stat() all dropins */
507
        STRV_FOREACH(fn, files) {
38,425✔
508
                _cleanup_fclose_ FILE *f = NULL;
537✔
509
                r = chase_and_fopenat_unlocked(root_fd, *fn, CHASE_AT_RESOLVE_IN_ROOT|CHASE_MUST_BE_REGULAR, "re", /* ret_path= */ NULL, &f);
537✔
510
                if (r == -ENOENT)
537✔
511
                        continue;
×
512
                if (r < 0)
537✔
513
                        return log_full_errno(level, r, "Failed to open %s: %m", *fn);
×
514

515
                int fd = fileno(f);
537✔
516
                assert(fd >= 0);
537✔
517

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

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

529
                _cleanup_free_ struct stat *st_dropin = new(struct stat, 1);
1,074✔
530
                if (!st_dropin)
537✔
531
                        return log_oom_full(level);
×
532

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

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

541
        /* First process the first found main config file. */
542
        STRV_FOREACH(fn, conf_files) {
40,071✔
543
                _cleanup_fclose_ FILE *f = NULL;
39,698✔
544
                r = chase_and_fopenat_unlocked(root_fd, *fn, CHASE_AT_RESOLVE_IN_ROOT|CHASE_MUST_BE_REGULAR, "re", /* ret_path= */ NULL, &f);
39,698✔
545
                if (r == -ENOENT)
39,698✔
546
                        continue;
2,183✔
547
                if (r < 0)
37,515✔
548
                        return log_full_errno(level, r, "Failed to open %s: %m", *fn);
×
549

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

554
                        if (set_contains(inodes, &st)) {
388✔
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);
37,515✔
561
                if (r < 0)
37,515✔
562
                        return r; /* config_parse() logs internally. */
563
                assert(r > 0);
37,515✔
564

565
                if (ret_stats_by_path) {
37,515✔
566
                        r = hashmap_put_stats_by_path(&stats_by_path, *fn, &st);
9,778✔
567
                        if (r < 0)
9,778✔
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
        const char *path_dropin;
37,888✔
576
        FILE *f_dropin;
37,888✔
577
        ORDERED_HASHMAP_FOREACH_KEY(f_dropin, path_dropin, dropins) {
76,313✔
578
                r = config_parse(/* unit= */ NULL, path_dropin, f_dropin, sections, lookup, table, flags, userdata, &st);
537✔
579
                if (r < 0)
537✔
580
                        return r; /* config_parse() logs internally. */
×
581
                assert(r > 0);
537✔
582

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

590
        if (ret_stats_by_path)
37,888✔
591
                *ret_stats_by_path = TAKE_PTR(stats_by_path);
9,778✔
592

593
        return 0;
594
}
595

596
static int normalize_root_fd(const char *root, int *root_fd, int *ret_opened_fd) {
37,888✔
597
        assert(root_fd);
37,888✔
598
        assert(ret_opened_fd);
37,888✔
599

600
        /* Normalizes a root dir specification: if root_fd is already valid, keep it. Otherwise, we open the
601
         * specified dir */
602

603
        if (*root_fd >= 0 || IN_SET(*root_fd, AT_FDCWD, XAT_FDROOT)) {
37,888✔
604
                *ret_opened_fd = -EBADF;
26,652✔
605
                return 0;
26,652✔
606
        }
607

608
        if (empty_or_root(root)) {
11,236✔
609
                *root_fd = XAT_FDROOT;
11,075✔
610
                *ret_opened_fd = -EBADF;
11,075✔
611
                return 0;
11,075✔
612
        }
613

614
        int fd = open(root, O_CLOEXEC|O_PATH|O_DIRECTORY);
161✔
615
        if (fd < 0)
161✔
616
                return log_error_errno(errno, "Failed to open root directory '%s': %m", root);
×
617

618
        *ret_opened_fd = *root_fd = fd;
161✔
619
        return 0;
161✔
620
}
621

622
/* Parse each config file in the directories specified as strv. */
623
int config_parse_many_full(
37,888✔
624
                const char* const* conf_files,
625
                const char* const* conf_file_dirs,
626
                const char *dropin_dirname,
627
                const char *root,
628
                int root_fd,
629
                const char *sections,
630
                ConfigItemLookup lookup,
631
                const void *table,
632
                ConfigParseFlags flags,
633
                void *userdata,
634
                Hashmap **ret_stats_by_path,
635
                char ***ret_dropin_files) {
636

637
        _cleanup_strv_free_ char **files = NULL;
×
638
        int r;
37,888✔
639

640
        assert(conf_file_dirs);
37,888✔
641
        assert(dropin_dirname);
37,888✔
642
        assert(table);
37,888✔
643

644
        _cleanup_close_ int opened_root_fd = -EBADF;
37,888✔
645
        r = normalize_root_fd(root, &root_fd, &opened_root_fd);
37,888✔
646
        if (r < 0)
37,888✔
647
                return r;
648

649
        r = conf_files_list_dropins(
75,776✔
650
                        &files,
651
                        dropin_dirname,
652
                        root,
653
                        root_fd,
654
                        FLAGS_SET(flags, CONFIG_PARSE_WARN) ? CONF_FILES_WARN : 0,
37,888✔
655
                        conf_file_dirs);
656
        if (r < 0)
37,888✔
657
                return log_full_errno(FLAGS_SET(flags, CONFIG_PARSE_WARN) ? LOG_WARNING : LOG_DEBUG, r,
×
658
                                      "Failed to list drop-ins in %s: %m", dropin_dirname);
659

660
        r = config_parse_many_files(
37,888✔
661
                        root,
662
                        root_fd,
663
                        conf_files,
664
                        files,
665
                        sections,
666
                        lookup,
667
                        table,
668
                        flags,
669
                        userdata,
670
                        ret_stats_by_path);
671
        if (r < 0)
37,888✔
672
                return r; /* config_parse_many_files() logs internally. */
673

674
        if (ret_dropin_files)
37,888✔
675
                *ret_dropin_files = TAKE_PTR(files);
10,147✔
676

677
        return 0;
678
}
679

680
int config_parse_standard_file_with_dropins_full(
25,969✔
681
                const char *root,
682
                int root_fd,
683
                const char *main_file,    /* A path like "systemd/frobnicator.conf" */
684
                const char *sections,
685
                ConfigItemLookup lookup,
686
                const void *table,
687
                ConfigParseFlags flags,
688
                void *userdata,
689
                Hashmap **ret_stats_by_path,
690
                char ***ret_dropin_files) {
691

692
        const char* const *conf_file_dirs = (const char* const*) CONF_PATHS_STRV("");
25,969✔
693
        _cleanup_strv_free_ char **conf_files = NULL;
25,969✔
694
        int r, level = FLAGS_SET(flags, CONFIG_PARSE_WARN) ? LOG_WARNING : LOG_DEBUG;
25,969✔
695

696
        /* Build the list of main config files */
697
        r = strv_extend_strv_concat(
25,969✔
698
                        &conf_files,
699
                        conf_file_dirs,
700
                        main_file);
701
        if (r < 0)
25,969✔
702
                return log_oom_full(level);
×
703

704
        _cleanup_free_ char *dropin_dirname = strjoin(main_file, ".d");
51,938✔
705
        if (!dropin_dirname)
25,969✔
706
                return log_oom_full(level);
×
707

708
        return config_parse_many_full(
25,969✔
709
                        (const char* const*) conf_files,
710
                        conf_file_dirs,
711
                        dropin_dirname,
712
                        root,
713
                        root_fd,
714
                        sections,
715
                        lookup,
716
                        table,
717
                        flags,
718
                        userdata,
719
                        ret_stats_by_path,
720
                        ret_dropin_files);
721
}
722

723
static int dropins_get_stats_by_path(
3,002✔
724
                const char* conf_file,
725
                const char* const* conf_file_dirs,
726
                Hashmap **stats_by_path) {
727

728
        _cleanup_strv_free_ char **files = NULL;
×
729
        _cleanup_free_ char *dropin_dirname = NULL;
3,002✔
730
        int r;
3,002✔
731

732
        assert(conf_file);
3,002✔
733
        assert(conf_file_dirs);
3,002✔
734
        assert(stats_by_path);
3,002✔
735

736
        r = path_extract_filename(conf_file, &dropin_dirname);
3,002✔
737
        if (r < 0)
3,002✔
738
                return r;
739
        if (r == O_DIRECTORY)
3,002✔
740
                return -EINVAL;
741

742
        if (!strextend(&dropin_dirname, ".d"))
3,002✔
743
                return -ENOMEM;
744

745
        r = conf_files_list_dropins(
3,002✔
746
                        &files,
747
                        dropin_dirname,
748
                        /* root= */ NULL,
749
                        /* root_fd= */ XAT_FDROOT,
750
                        /* flags= */ 0,
751
                        conf_file_dirs);
752
        if (r < 0)
3,002✔
753
                return r;
754

755
        STRV_FOREACH(fn, files) {
3,013✔
756
                struct stat st;
11✔
757

758
                if (stat(*fn, &st) < 0) {
11✔
759
                        if (errno == ENOENT)
×
760
                                continue;
×
761

762
                        return -errno;
×
763
                }
764

765
                r = hashmap_put_stats_by_path(stats_by_path, *fn, &st);
11✔
766
                if (r < 0)
11✔
767
                        return r;
768
        }
769

770
        return 0;
771
}
772

773
int config_get_stats_by_path(
742✔
774
                const char *suffix,
775
                const char *root,
776
                ConfFilesFlags flags,
777
                const char* const* dirs,
778
                bool check_dropins,
779
                Hashmap **ret) {
780

781
        _cleanup_hashmap_free_ Hashmap *stats_by_path = NULL;
742✔
782
        _cleanup_strv_free_ char **files = NULL;
742✔
783
        int r;
742✔
784

785
        assert(suffix);
742✔
786
        assert(dirs);
742✔
787
        assert(ret);
742✔
788

789
        /* Unlike config_parse(), this does not support stream. */
790

791
        r = conf_files_list_strv(&files, suffix, root, flags, dirs);
742✔
792
        if (r < 0)
742✔
793
                return r;
794

795
        STRV_FOREACH(f, files) {
33,339✔
796
                struct stat st;
32,597✔
797

798
                /* First read the main config file. */
799
                if (stat(*f, &st) < 0) {
32,597✔
800
                        if (errno == ENOENT)
×
801
                                continue;
29,595✔
802

803
                        return -errno;
×
804
                }
805

806
                /* Skipping an empty file. */
807
                if (null_or_empty(&st))
32,597✔
808
                        continue;
×
809

810
                r = hashmap_put_stats_by_path(&stats_by_path, *f, &st);
32,597✔
811
                if (r < 0)
32,597✔
812
                        return r;
813

814
                if (!check_dropins)
32,597✔
815
                        continue;
29,595✔
816

817
                /* Then read all the drop-ins if requested. */
818
                r = dropins_get_stats_by_path(*f, dirs, &stats_by_path);
3,002✔
819
                if (r < 0)
3,002✔
820
                        return r;
821
        }
822

823
        *ret = TAKE_PTR(stats_by_path);
742✔
824
        return 0;
742✔
825
}
826

827
bool stats_by_path_equal(Hashmap *a, Hashmap *b) {
2,750✔
828
        struct stat *st_a, *st_b;
2,750✔
829
        const char *path;
2,750✔
830

831
        if (hashmap_size(a) != hashmap_size(b))
2,750✔
832
                return false;
2,750✔
833

834
        HASHMAP_FOREACH_KEY(st_a, path, a) {
33,452✔
835
                st_b = hashmap_get(b, path);
31,014✔
836
                if (!st_b)
31,014✔
837
                        return false;
198✔
838

839
                if (!stat_inode_unmodified(st_a, st_b))
31,011✔
840
                        return false;
841
        }
842

843
        return true;
2,438✔
844
}
845

846
int config_section_parse(
6,906✔
847
                const ConfigSectionParser *parsers,
848
                size_t n_parsers,
849
                const char *unit,
850
                const char *filename,
851
                unsigned line,
852
                const char *section,
853
                unsigned section_line,
854
                const char *lvalue,
855
                int ltype,
856
                const char *rvalue,
857
                void *userdata) {
858

859
        assert(parsers);
6,906✔
860
        assert(n_parsers > 0);
6,906✔
861
        assert(ltype >= 0);
6,906✔
862
        assert((size_t) ltype < n_parsers);
6,906✔
863
        assert(userdata);
6,906✔
864

865
        const ConfigSectionParser *e = parsers + ltype;
6,906✔
866
        assert(e->parser);
6,906✔
867

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

873
        return e->parser(unit, filename, line, section, section_line, lvalue, e->ltype, rvalue,
13,812✔
874
                         (uint8_t*) userdata + e->offset, userdata);
6,906✔
875
}
876

877
void config_section_hash_func(const ConfigSection *c, struct siphash *state) {
18,821✔
878
        siphash24_compress_string(c->filename, state);
18,821✔
879
        siphash24_compress_typesafe(c->line, state);
18,821✔
880
}
18,821✔
881

882
int config_section_compare_func(const ConfigSection *x, const ConfigSection *y) {
5,821✔
883
        int r;
5,821✔
884

885
        r = strcmp(x->filename, y->filename);
5,821✔
886
        if (r != 0)
5,821✔
887
                return r;
888

889
        return CMP(x->line, y->line);
5,458✔
890
}
891

892
DEFINE_HASH_OPS(config_section_hash_ops, ConfigSection, config_section_hash_func, config_section_compare_func);
893

894
int config_section_new(const char *filename, unsigned line, ConfigSection **ret) {
7,878✔
895
        ConfigSection *cs;
7,878✔
896

897
        assert(filename);
7,878✔
898
        assert(line > 0);
7,878✔
899
        assert(ret);
7,878✔
900

901
        cs = malloc0(offsetof(ConfigSection, filename) + strlen(filename) + 1);
7,878✔
902
        if (!cs)
7,878✔
903
                return -ENOMEM;
7,878✔
904

905
        strcpy(cs->filename, filename);
7,878✔
906
        cs->line = line;
7,878✔
907

908
        *ret = TAKE_PTR(cs);
7,878✔
909
        return 0;
7,878✔
910
}
911

912
static int _hashmap_by_section_find_unused_line(
35✔
913
                HashmapBase *entries_by_section,
914
                const char *filename,
915
                unsigned *ret) {
916

917
        ConfigSection *cs;
35✔
918
        unsigned n = 0;
35✔
919
        void *entry;
35✔
920

921
        HASHMAP_BASE_FOREACH_KEY(entry, cs, entries_by_section) {
565✔
922
                if (filename && !streq(cs->filename, filename))
530✔
923
                        continue;
×
924
                n = MAX(n, cs->line);
530✔
925
        }
926

927
        /* overflow? */
928
        if (n >= UINT_MAX)
35✔
929
                return -EFBIG;
35✔
930

931
        *ret = n + 1;
35✔
932
        return 0;
35✔
933
}
934

935
int hashmap_by_section_find_unused_line(
20✔
936
        Hashmap *entries_by_section,
937
        const char *filename,
938
        unsigned *ret) {
939

940
        return _hashmap_by_section_find_unused_line(HASHMAP_BASE(entries_by_section), filename, ret);
20✔
941
}
942

943
int ordered_hashmap_by_section_find_unused_line(
15✔
944
        OrderedHashmap *entries_by_section,
945
        const char *filename,
946
        unsigned *ret) {
947

948
        return _hashmap_by_section_find_unused_line(HASHMAP_BASE(entries_by_section), filename, ret);
15✔
949
}
950

951
#define DEFINE_PARSER(type, vartype, conv_func)                         \
952
        DEFINE_CONFIG_PARSE_PTR(config_parse_##type, conv_func, vartype)
953

954
DEFINE_PARSER(int, int, safe_atoi);
231✔
955
DEFINE_PARSER(long, long, safe_atoli);
×
956
DEFINE_PARSER(uint8, uint8_t, safe_atou8);
23✔
957
DEFINE_PARSER(uint16, uint16_t, safe_atou16);
5✔
958
DEFINE_PARSER(uint32, uint32_t, safe_atou32);
180✔
959
DEFINE_PARSER(int32, int32_t, safe_atoi32);
12✔
960
DEFINE_PARSER(uint64, uint64_t, safe_atou64);
203✔
961
DEFINE_PARSER(unsigned, unsigned, safe_atou);
2,416✔
962
DEFINE_PARSER(double, double, safe_atod);
×
963
DEFINE_PARSER(nsec, nsec_t, parse_nsec);
7✔
964
DEFINE_PARSER(sec, usec_t, parse_sec);
4,003✔
965
DEFINE_PARSER(sec_def_infinity, usec_t, parse_sec_def_infinity);
×
966
DEFINE_PARSER(mode, mode_t, parse_mode);
7,790✔
967
DEFINE_PARSER(pid, pid_t, parse_pid);
2✔
968

969
int config_parse_iec_size(
798✔
970
                const char *unit,
971
                const char *filename,
972
                unsigned line,
973
                const char *section,
974
                unsigned section_line,
975
                const char *lvalue,
976
                int ltype,
977
                const char *rvalue,
978
                void *data,
979
                void *userdata) {
980

981
        size_t *sz = ASSERT_PTR(data);
798✔
982
        uint64_t v;
798✔
983
        int r;
798✔
984

985
        assert(filename);
798✔
986
        assert(lvalue);
798✔
987
        assert(rvalue);
798✔
988

989
        r = parse_size(rvalue, 1024, &v);
798✔
990
        if (r >= 0 && (uint64_t) (size_t) v != v)
798✔
991
                r = -ERANGE;
992
        if (r < 0)
798✔
993
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
3✔
994

995
        *sz = (size_t) v;
795✔
996
        return 1;
795✔
997
}
998

999
int config_parse_si_uint64(
9✔
1000
                const char *unit,
1001
                const char *filename,
1002
                unsigned line,
1003
                const char *section,
1004
                unsigned section_line,
1005
                const char *lvalue,
1006
                int ltype,
1007
                const char *rvalue,
1008
                void *data,
1009
                void *userdata) {
1010

1011
        uint64_t *sz = ASSERT_PTR(data);
9✔
1012
        int r;
9✔
1013

1014
        assert(filename);
9✔
1015
        assert(lvalue);
9✔
1016
        assert(rvalue);
9✔
1017

1018
        r = parse_size(rvalue, 1000, sz);
9✔
1019
        if (r < 0)
9✔
1020
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
3✔
1021

1022
        return 1;
1023
}
1024

1025
int config_parse_iec_uint64(
5✔
1026
                const char *unit,
1027
                const char *filename,
1028
                unsigned line,
1029
                const char *section,
1030
                unsigned section_line,
1031
                const char *lvalue,
1032
                int ltype,
1033
                const char *rvalue,
1034
                void *data,
1035
                void *userdata) {
1036

1037
        uint64_t *bytes = ASSERT_PTR(data);
5✔
1038
        int r;
5✔
1039

1040
        assert(filename);
5✔
1041
        assert(lvalue);
5✔
1042
        assert(rvalue);
5✔
1043

1044
        r = parse_size(rvalue, 1024, bytes);
5✔
1045
        if (r < 0)
5✔
1046
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1047

1048
        return 1;
1049
}
1050

1051
int config_parse_iec_uint64_infinity(
×
1052
                const char *unit,
1053
                const char *filename,
1054
                unsigned line,
1055
                const char *section,
1056
                unsigned section_line,
1057
                const char *lvalue,
1058
                int ltype,
1059
                const char *rvalue,
1060
                void *data,
1061
                void *userdata) {
1062

1063
        uint64_t *bytes = ASSERT_PTR(data);
×
1064

1065
        assert(rvalue);
×
1066

1067
        if (streq(rvalue, "infinity")) {
×
1068
                *bytes = UINT64_MAX;
×
1069
                return 1;
×
1070
        }
1071

1072
        return config_parse_iec_uint64(unit, filename, line, section, section_line, lvalue, ltype, rvalue, data, userdata);
×
1073
}
1074

1075
int config_parse_bool(
55,924✔
1076
                const char *unit,
1077
                const char *filename,
1078
                unsigned line,
1079
                const char *section,
1080
                unsigned section_line,
1081
                const char *lvalue,
1082
                int ltype,
1083
                const char *rvalue,
1084
                void *data,
1085
                void *userdata) {
1086

1087
        bool *b = ASSERT_PTR(data);
55,924✔
1088
        bool fatal = ltype;
55,924✔
1089
        int r;
55,924✔
1090

1091
        assert(filename);
55,924✔
1092
        assert(lvalue);
55,924✔
1093
        assert(rvalue);
55,924✔
1094

1095
        r = parse_boolean(rvalue);
55,924✔
1096
        if (r < 0) {
55,924✔
1097
                log_syntax_parse_error_full(unit, filename, line, r, fatal, lvalue, rvalue);
×
1098
                return fatal ? -ENOEXEC : 0;
×
1099
        }
1100

1101
        *b = r;
55,924✔
1102
        return 1; /* set */
55,924✔
1103
}
1104

1105
int config_parse_uint32_flag(
68✔
1106
                const char *unit,
1107
                const char *filename,
1108
                unsigned line,
1109
                const char *section,
1110
                unsigned section_line,
1111
                const char *lvalue,
1112
                int ltype,
1113
                const char *rvalue,
1114
                void *data,
1115
                void *userdata) {
1116

1117
        uint32_t *flags = ASSERT_PTR(data);
68✔
1118
        int r;
68✔
1119

1120
        assert(ltype != 0);
68✔
1121

1122
        r = isempty(rvalue) ? 0 : parse_boolean(rvalue);
136✔
1123
        if (r < 0)
68✔
1124
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1125

1126
        SET_FLAG(*flags, ltype, r);
68✔
1127
        return 1;
68✔
1128
}
1129

1130
int config_parse_uint32_invert_flag(
66✔
1131
                const char *unit,
1132
                const char *filename,
1133
                unsigned line,
1134
                const char *section,
1135
                unsigned section_line,
1136
                const char *lvalue,
1137
                int ltype,
1138
                const char *rvalue,
1139
                void *data,
1140
                void *userdata) {
1141

1142
        uint32_t *flags = ASSERT_PTR(data);
66✔
1143
        int r;
66✔
1144

1145
        assert(ltype != 0);
66✔
1146

1147
        r = isempty(rvalue) ? 0 : parse_boolean(rvalue);
132✔
1148
        if (r < 0)
66✔
1149
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1150

1151
        SET_FLAG(*flags, ltype, !r);
66✔
1152
        return 1;
66✔
1153
}
1154

1155
int config_parse_id128(
11✔
1156
                const char *unit,
1157
                const char *filename,
1158
                unsigned line,
1159
                const char *section,
1160
                unsigned section_line,
1161
                const char *lvalue,
1162
                int ltype,
1163
                const char *rvalue,
1164
                void *data,
1165
                void *userdata) {
1166

1167
        sd_id128_t *result = data;
11✔
1168
        int r;
11✔
1169

1170
        assert(filename);
11✔
1171
        assert(lvalue);
11✔
1172
        assert(rvalue);
11✔
1173

1174
        r = id128_from_string_nonzero(rvalue, result);
11✔
1175
        if (r == -ENXIO) {
11✔
1176
                log_syntax(unit, LOG_WARNING, filename, line, r, "128-bit ID/UUID is all 0, ignoring: %s", rvalue);
×
1177
                return 0;
×
1178
        }
1179
        if (r < 0)
11✔
1180
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1181

1182
        return 1;
1183
}
1184

1185
int config_parse_tristate(
5,758✔
1186
                const char *unit,
1187
                const char *filename,
1188
                unsigned line,
1189
                const char *section,
1190
                unsigned section_line,
1191
                const char *lvalue,
1192
                int ltype,
1193
                const char *rvalue,
1194
                void *data,
1195
                void *userdata) {
1196

1197
        int r, *t = ASSERT_PTR(data);
5,758✔
1198

1199
        assert(filename);
5,758✔
1200
        assert(lvalue);
5,758✔
1201
        assert(rvalue);
5,758✔
1202

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

1206
        if (isempty(rvalue)) {
5,758✔
1207
                *t = -1;
×
1208
                return 1;
×
1209
        }
1210

1211
        r = parse_tristate(rvalue, t);
5,758✔
1212
        if (r < 0)
5,758✔
1213
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1214

1215
        return 1;
1216
}
1217

1218
int config_parse_string(
37,276✔
1219
                const char *unit,
1220
                const char *filename,
1221
                unsigned line,
1222
                const char *section,
1223
                unsigned section_line,
1224
                const char *lvalue,
1225
                int ltype,
1226
                const char *rvalue,
1227
                void *data,
1228
                void *userdata) {
1229

1230
        char **s = ASSERT_PTR(data);
37,276✔
1231
        int r;
37,276✔
1232

1233
        assert(filename);
37,276✔
1234
        assert(lvalue);
37,276✔
1235
        assert(rvalue);
37,276✔
1236

1237
        if (isempty(rvalue)) {
37,276✔
1238
                *s = mfree(*s);
×
1239
                return 1;
×
1240
        }
1241

1242
        if (FLAGS_SET(ltype, CONFIG_PARSE_STRING_SAFE) && !string_is_safe(rvalue)) {
37,276✔
1243
                _cleanup_free_ char *escaped = NULL;
×
1244

1245
                escaped = cescape(rvalue);
×
1246
                log_syntax(unit, LOG_WARNING, filename, line, 0,
×
1247
                           "Specified string contains unsafe characters, ignoring: %s", strna(escaped));
1248
                return 0;
×
1249
        }
1250

1251
        if (FLAGS_SET(ltype, CONFIG_PARSE_STRING_ASCII) && !ascii_is_valid(rvalue)) {
37,287✔
1252
                _cleanup_free_ char *escaped = NULL;
×
1253

1254
                escaped = cescape(rvalue);
×
1255
                log_syntax(unit, LOG_WARNING, filename, line, 0,
×
1256
                           "Specified string contains invalid ASCII characters, ignoring: %s", strna(escaped));
1257
                return 0;
×
1258
        }
1259

1260
        r = free_and_strdup_warn(s, rvalue);
37,276✔
1261
        if (r < 0)
37,276✔
1262
                return r;
×
1263

1264
        return 1;
1265
}
1266

1267
int config_parse_dns_name(
3,029✔
1268
                const char *unit,
1269
                const char *filename,
1270
                unsigned line,
1271
                const char *section,
1272
                unsigned section_line,
1273
                const char *lvalue,
1274
                int ltype,
1275
                const char *rvalue,
1276
                void *data,
1277
                void *userdata) {
1278

1279
        char **hostname = ASSERT_PTR(data);
3,029✔
1280
        int r;
3,029✔
1281

1282
        assert(filename);
3,029✔
1283
        assert(lvalue);
3,029✔
1284
        assert(rvalue);
3,029✔
1285

1286
        if (isempty(rvalue)) {
3,029✔
1287
                *hostname = mfree(*hostname);
×
1288
                return 1;
×
1289
        }
1290

1291
        r = dns_name_is_valid(rvalue);
3,029✔
1292
        if (r < 0) {
3,029✔
1293
                log_syntax(unit, LOG_WARNING, filename, line, r,
×
1294
                           "Failed to check validity of DNS domain name '%s', ignoring assignment: %m", rvalue);
1295
                return 0;
×
1296
        }
1297
        if (r == 0) {
3,029✔
1298
                log_syntax(unit, LOG_WARNING, filename, line, 0,
×
1299
                           "Specified invalid DNS domain name, ignoring assignment: %s", rvalue);
1300
                return 0;
×
1301
        }
1302

1303
        r = free_and_strdup_warn(hostname, rvalue);
3,029✔
1304
        if (r < 0)
3,029✔
1305
                return r;
×
1306

1307
        return 1;
1308
}
1309

1310
int config_parse_hostname(
23✔
1311
                const char *unit,
1312
                const char *filename,
1313
                unsigned line,
1314
                const char *section,
1315
                unsigned section_line,
1316
                const char *lvalue,
1317
                int ltype,
1318
                const char *rvalue,
1319
                void *data,
1320
                void *userdata) {
1321

1322
        char **hostname = ASSERT_PTR(data);
23✔
1323

1324
        assert(filename);
23✔
1325
        assert(lvalue);
23✔
1326
        assert(rvalue);
23✔
1327

1328
        if (isempty(rvalue)) {
23✔
1329
                *hostname = mfree(*hostname);
×
1330
                return 1;
×
1331
        }
1332

1333
        if (!hostname_is_valid(rvalue, 0)) {
23✔
1334
                log_syntax(unit, LOG_WARNING, filename, line, 0,
×
1335
                           "Specified invalid hostname, ignoring assignment: %s", rvalue);
1336
                return 0;
×
1337
        }
1338

1339
        return config_parse_dns_name(unit, filename, line, section, section_line,
23✔
1340
                                     lvalue, ltype, rvalue, data, userdata);
1341
}
1342

1343
int config_parse_path(
1,515✔
1344
                const char *unit,
1345
                const char *filename,
1346
                unsigned line,
1347
                const char *section,
1348
                unsigned section_line,
1349
                const char *lvalue,
1350
                int ltype,
1351
                const char *rvalue,
1352
                void *data,
1353
                void *userdata) {
1354

1355
        _cleanup_free_ char *n = NULL;
1,515✔
1356
        bool fatal = ltype;
1,515✔
1357
        char **s = ASSERT_PTR(data);
1,515✔
1358
        int r;
1,515✔
1359

1360
        assert(filename);
1,515✔
1361
        assert(lvalue);
1,515✔
1362
        assert(rvalue);
1,515✔
1363

1364
        if (isempty(rvalue)) {
1,515✔
1365
                *s = mfree(*s);
×
1366
                return 1;
×
1367
        }
1368

1369
        n = strdup(rvalue);
1,515✔
1370
        if (!n)
1,515✔
1371
                return log_oom();
×
1372

1373
        r = path_simplify_and_warn(n, PATH_CHECK_ABSOLUTE | (fatal ? PATH_CHECK_FATAL : 0), unit, filename, line, lvalue);
2,973✔
1374
        if (r < 0)
1,515✔
1375
                return fatal ? -ENOEXEC : 0;
2✔
1376

1377
        free_and_replace(*s, n);
1,513✔
1378
        return 1;
1,513✔
1379
}
1380

1381
int config_parse_strv(
37,340✔
1382
                const char *unit,
1383
                const char *filename,
1384
                unsigned line,
1385
                const char *section,
1386
                unsigned section_line,
1387
                const char *lvalue,
1388
                int ltype, /* When true, duplicated entries will be filtered. */
1389
                const char *rvalue,
1390
                void *data,
1391
                void *userdata) {
1392

1393
        char ***sv = ASSERT_PTR(data);
37,340✔
1394
        int r;
37,340✔
1395

1396
        assert(filename);
37,340✔
1397
        assert(lvalue);
37,340✔
1398
        assert(rvalue);
37,340✔
1399

1400
        if (isempty(rvalue)) {
37,340✔
1401
                *sv = strv_free(*sv);
2✔
1402
                return 1;
37,340✔
1403
        }
1404

1405
        _cleanup_strv_free_ char **strv = NULL;
37,338✔
1406
        for (const char *p = rvalue;;) {
80,693✔
1407
                char *word;
80,693✔
1408

1409
                r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
80,693✔
1410
                if (r < 0)
80,693✔
1411
                        return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1412
                if (r == 0)
80,693✔
1413
                        break;
1414

1415
                r = strv_consume(&strv, word);
43,355✔
1416
                if (r < 0)
43,355✔
1417
                        return log_oom();
×
1418
        }
1419

1420
        r = strv_extend_strv_consume(sv, TAKE_PTR(strv), /* filter_duplicates= */ ltype);
37,338✔
1421
        if (r < 0)
37,338✔
1422
                return log_oom();
×
1423

1424
        return 1;
1425
}
1426

1427
int config_parse_warn_compat(
×
1428
                const char *unit,
1429
                const char *filename,
1430
                unsigned line,
1431
                const char *section,
1432
                unsigned section_line,
1433
                const char *lvalue,
1434
                int ltype,
1435
                const char *rvalue,
1436
                void *data,
1437
                void *userdata) {
1438

1439
        Disabled reason = ltype;
×
1440

1441
        switch (reason) {
×
1442

1443
        case DISABLED_CONFIGURATION:
×
1444
                log_syntax(unit, LOG_DEBUG, filename, line, 0,
×
1445
                           "Support for option %s= has been disabled at compile time and it is ignored", lvalue);
1446
                break;
1447

1448
        case DISABLED_LEGACY:
×
1449
                log_syntax(unit, LOG_INFO, filename, line, 0,
×
1450
                           "Support for option %s= has been removed and it is ignored", lvalue);
1451
                break;
1452

1453
        case DISABLED_EXPERIMENTAL:
×
1454
                log_syntax(unit, LOG_INFO, filename, line, 0,
×
1455
                           "Support for option %s= has not yet been enabled and it is ignored", lvalue);
1456
                break;
1457
        }
1458

1459
        return 0;
×
1460
}
1461

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

1474
        int *o = data, x;
3✔
1475

1476
        assert(filename);
3✔
1477
        assert(lvalue);
3✔
1478
        assert(rvalue);
3✔
1479
        assert(data);
3✔
1480

1481
        x = log_facility_unshifted_from_string(rvalue);
3✔
1482
        if (x < 0)
3✔
1483
                return log_syntax_parse_error(unit, filename, line, x, lvalue, rvalue);
1✔
1484

1485
        *o = (x << 3) | LOG_PRI(*o);
2✔
1486

1487
        return 1;
2✔
1488
}
1489

1490
int config_parse_log_level(
3✔
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
        int *o = data, x;
3✔
1503

1504
        assert(filename);
3✔
1505
        assert(lvalue);
3✔
1506
        assert(rvalue);
3✔
1507
        assert(data);
3✔
1508

1509
        x = log_level_from_string(rvalue);
3✔
1510
        if (x < 0)
3✔
1511
                return log_syntax_parse_error(unit, filename, line, x, lvalue, rvalue);
1✔
1512

1513
        if (*o < 0) /* if it wasn't initialized so far, assume zero facility */
2✔
1514
                *o = x;
×
1515
        else
1516
                *o = (*o & LOG_FACMASK) | x;
2✔
1517

1518
        return 1;
1519
}
1520

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

1533
        int *sig = data, r;
252✔
1534

1535
        assert(filename);
252✔
1536
        assert(lvalue);
252✔
1537
        assert(rvalue);
252✔
1538
        assert(sig);
252✔
1539

1540
        r = signal_from_string(rvalue);
252✔
1541
        if (r <= 0)
252✔
1542
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1543

1544
        *sig = r;
252✔
1545
        return 1;
252✔
1546
}
1547

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

1560
        unsigned long *personality = data, p;
×
1561

1562
        assert(filename);
×
1563
        assert(lvalue);
×
1564
        assert(rvalue);
×
1565
        assert(personality);
×
1566

1567
        if (isempty(rvalue)) {
×
1568
                *personality = PERSONALITY_INVALID;
×
1569
                return 1;
×
1570
        }
1571

1572
        p = personality_from_string(rvalue);
×
1573
        if (p == PERSONALITY_INVALID)
×
1574
                return log_syntax_parse_error(unit, filename, line, 0, lvalue, rvalue);
×
1575

1576
        *personality = p;
×
1577
        return 1;
×
1578
}
1579

1580
int config_parse_ifname(
1,983✔
1581
                const char *unit,
1582
                const char *filename,
1583
                unsigned line,
1584
                const char *section,
1585
                unsigned section_line,
1586
                const char *lvalue,
1587
                int ltype,
1588
                const char *rvalue,
1589
                void *data,
1590
                void *userdata) {
1591

1592
        char **s = ASSERT_PTR(data);
1,983✔
1593
        int r;
1,983✔
1594

1595
        assert(filename);
1,983✔
1596
        assert(lvalue);
1,983✔
1597
        assert(rvalue);
1,983✔
1598

1599
        if (isempty(rvalue)) {
1,983✔
1600
                *s = mfree(*s);
×
1601
                return 1;
×
1602
        }
1603

1604
        if (!ifname_valid(rvalue)) {
1,983✔
1605
                log_syntax(unit, LOG_WARNING, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue);
×
1606
                return 0;
×
1607
        }
1608

1609
        r = free_and_strdup_warn(s, rvalue);
1,983✔
1610
        if (r < 0)
1,983✔
1611
                return r;
×
1612

1613
        return 1;
1614
}
1615

1616
int config_parse_ifnames(
17✔
1617
                const char *unit,
1618
                const char *filename,
1619
                unsigned line,
1620
                const char *section,
1621
                unsigned section_line,
1622
                const char *lvalue,
1623
                int ltype,
1624
                const char *rvalue,
1625
                void *data,
1626
                void *userdata) {
1627

1628
        _cleanup_strv_free_ char **names = NULL;
17✔
1629
        char ***s = ASSERT_PTR(data);
17✔
1630
        int r;
17✔
1631

1632
        assert(filename);
17✔
1633
        assert(lvalue);
17✔
1634
        assert(rvalue);
17✔
1635

1636
        if (isempty(rvalue)) {
17✔
1637
                *s = strv_free(*s);
×
1638
                return 1;
×
1639
        }
1640

1641
        for (const char *p = rvalue;;) {
17✔
1642
                _cleanup_free_ char *word = NULL;
31✔
1643

1644
                r = extract_first_word(&p, &word, NULL, 0);
48✔
1645
                if (r < 0)
48✔
1646
                        return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1647
                if (r == 0)
48✔
1648
                        break;
1649

1650
                if (!ifname_valid_full(word, ltype)) {
31✔
1651
                        log_syntax(unit, LOG_WARNING, filename, line, 0,
×
1652
                                   "Interface name is not valid or too long, ignoring assignment: %s",
1653
                                   word);
1654
                        continue;
×
1655
                }
1656

1657
                r = strv_consume(&names, TAKE_PTR(word));
31✔
1658
                if (r < 0)
31✔
1659
                        return log_oom();
×
1660
        }
1661

1662
        r = strv_extend_strv(s, names, true);
17✔
1663
        if (r < 0)
17✔
1664
                return log_oom();
×
1665

1666
        return 1;
1667
}
1668

1669
int config_parse_ip_port(
27✔
1670
                const char *unit,
1671
                const char *filename,
1672
                unsigned line,
1673
                const char *section,
1674
                unsigned section_line,
1675
                const char *lvalue,
1676
                int ltype,
1677
                const char *rvalue,
1678
                void *data,
1679
                void *userdata) {
1680

1681
        uint16_t *s = ASSERT_PTR(data);
27✔
1682
        uint16_t port;
27✔
1683
        int r;
27✔
1684

1685
        assert(filename);
27✔
1686
        assert(lvalue);
27✔
1687
        assert(rvalue);
27✔
1688

1689
        if (isempty(rvalue)) {
27✔
1690
                *s = 0;
×
1691
                return 1;
×
1692
        }
1693

1694
        r = parse_ip_port(rvalue, &port);
27✔
1695
        if (r < 0)
27✔
1696
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1697

1698
        *s = port;
27✔
1699
        return 1;
27✔
1700
}
1701

1702
int config_parse_mtu(
176✔
1703
                const char *unit,
1704
                const char *filename,
1705
                unsigned line,
1706
                const char *section,
1707
                unsigned section_line,
1708
                const char *lvalue,
1709
                int ltype,
1710
                const char *rvalue,
1711
                void *data,
1712
                void *userdata) {
1713

1714
        uint32_t *mtu = ASSERT_PTR(data);
176✔
1715
        int r;
176✔
1716

1717
        assert(rvalue);
176✔
1718

1719
        r = parse_mtu(ltype, rvalue, mtu);
176✔
1720
        if (r == -ERANGE) {
176✔
1721
                log_syntax(unit, LOG_WARNING, filename, line, r,
×
1722
                           "Maximum transfer unit (MTU) value out of range. Permitted range is %" PRIu32 "…%" PRIu32 ", ignoring: %s",
1723
                           (uint32_t) (ltype == AF_INET6 ? IPV6_MIN_MTU : IPV4_MIN_MTU), (uint32_t) UINT32_MAX,
1724
                           rvalue);
1725
                return 0;
×
1726
        }
1727
        if (r < 0)
176✔
1728
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1729

1730
        return 1;
1731
}
1732

1733
int config_parse_rlimit(
825✔
1734
                const char *unit,
1735
                const char *filename,
1736
                unsigned line,
1737
                const char *section,
1738
                unsigned section_line,
1739
                const char *lvalue,
1740
                int ltype,
1741
                const char *rvalue,
1742
                void *data,
1743
                void *userdata) {
1744

1745
        struct rlimit **rl = data, d = {};
825✔
1746
        int r;
825✔
1747

1748
        assert(rvalue);
825✔
1749
        assert(rl);
825✔
1750

1751
        r = rlimit_parse(ltype, rvalue, &d);
825✔
1752
        if (r == -EILSEQ) {
825✔
1753
                log_syntax(unit, LOG_WARNING, filename, line, r, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue);
1✔
1754
                return 0;
1✔
1755
        }
1756
        if (r < 0)
824✔
1757
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
3✔
1758

1759
        if (rl[ltype])
821✔
1760
                *rl[ltype] = d;
13✔
1761
        else {
1762
                rl[ltype] = newdup(struct rlimit, &d, 1);
808✔
1763
                if (!rl[ltype])
808✔
1764
                        return log_oom();
×
1765
        }
1766

1767
        return 1;
1768
}
1769

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

1782
        unsigned *permille = ASSERT_PTR(data);
×
1783
        int r;
×
1784

1785
        assert(filename);
×
1786
        assert(lvalue);
×
1787
        assert(rvalue);
×
1788

1789
        r = parse_permille(rvalue);
×
1790
        if (r < 0)
×
1791
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1792

1793
        *permille = (unsigned) r;
×
1794
        return 1;
×
1795
}
1796

1797
int config_parse_vlanprotocol(
2✔
1798
                const char *unit,
1799
                const char *filename,
1800
                unsigned line,
1801
                const char *section,
1802
                unsigned section_line,
1803
                const char *lvalue,
1804
                int ltype,
1805
                const char *rvalue,
1806
                void *data,
1807
                void *userdata) {
1808

1809
        int *vlan_protocol = data;
2✔
1810

1811
        assert(filename);
2✔
1812
        assert(lvalue);
2✔
1813

1814
        if (isempty(rvalue)) {
2✔
1815
                *vlan_protocol = -1;
×
1816
                return 1;
×
1817
        }
1818

1819
        if (STR_IN_SET(rvalue, "802.1ad", "802.1AD"))
2✔
1820
                *vlan_protocol = ETH_P_8021AD;
2✔
1821
        else if (STR_IN_SET(rvalue, "802.1q", "802.1Q"))
×
1822
                *vlan_protocol = ETH_P_8021Q;
×
1823
        else
1824
                return log_syntax_parse_error(unit, filename, line, 0, lvalue, rvalue);
×
1825

1826
        return 1;
2✔
1827
}
1828

1829
int config_parse_hw_addr(
560✔
1830
                const char *unit,
1831
                const char *filename,
1832
                unsigned line,
1833
                const char *section,
1834
                unsigned section_line,
1835
                const char *lvalue,
1836
                int ltype,
1837
                const char *rvalue,
1838
                void *data,
1839
                void *userdata) {
1840

1841
        struct hw_addr_data *hwaddr = ASSERT_PTR(data);
560✔
1842
        int r;
560✔
1843

1844
        assert(filename);
560✔
1845
        assert(lvalue);
560✔
1846
        assert(rvalue);
560✔
1847

1848
        if (isempty(rvalue)) {
560✔
1849
                *hwaddr = HW_ADDR_NULL;
×
1850
                return 1;
×
1851
        }
1852

1853
        r = parse_hw_addr_full(rvalue, ltype, hwaddr);
560✔
1854
        if (r < 0)
560✔
1855
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1856

1857
        return 1;
1858
}
1859

1860
int config_parse_hw_addrs(
17✔
1861
                const char *unit,
1862
                const char *filename,
1863
                unsigned line,
1864
                const char *section,
1865
                unsigned section_line,
1866
                const char *lvalue,
1867
                int ltype,
1868
                const char *rvalue,
1869
                void *data,
1870
                void *userdata) {
1871

1872
        Set **hwaddrs = ASSERT_PTR(data);
17✔
1873
        int r;
17✔
1874

1875
        assert(filename);
17✔
1876
        assert(lvalue);
17✔
1877
        assert(rvalue);
17✔
1878

1879
        if (isempty(rvalue)) {
17✔
1880
                /* Empty assignment resets the list */
1881
                *hwaddrs = set_free(*hwaddrs);
×
1882
                return 1;
×
1883
        }
1884

1885
        for (const char *p = rvalue;;) {
17✔
1886
                _cleanup_free_ char *word = NULL;
17✔
1887
                _cleanup_free_ struct hw_addr_data *n = NULL;
34✔
1888

1889
                r = extract_first_word(&p, &word, NULL, 0);
34✔
1890
                if (r < 0)
34✔
1891
                        return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1892
                if (r == 0)
34✔
1893
                        return 1;
1894

1895
                n = new(struct hw_addr_data, 1);
17✔
1896
                if (!n)
17✔
1897
                        return log_oom();
×
1898

1899
                r = parse_hw_addr_full(word, ltype, n);
17✔
1900
                if (r < 0) {
17✔
1901
                        log_syntax(unit, LOG_WARNING, filename, line, r,
×
1902
                                   "Not a valid hardware address, ignoring: %s", word);
1903
                        continue;
×
1904
                }
1905

1906
                r = set_ensure_consume(hwaddrs, &hw_addr_hash_ops_free, TAKE_PTR(n));
17✔
1907
                if (r < 0)
17✔
1908
                        return log_oom();
×
1909
        }
1910
}
1911

1912
int config_parse_ether_addr(
26✔
1913
                const char *unit,
1914
                const char *filename,
1915
                unsigned line,
1916
                const char *section,
1917
                unsigned section_line,
1918
                const char *lvalue,
1919
                int ltype,
1920
                const char *rvalue,
1921
                void *data,
1922
                void *userdata) {
1923

1924
        _cleanup_free_ struct ether_addr *n = NULL;
26✔
1925
        struct ether_addr **hwaddr = ASSERT_PTR(data);
26✔
1926
        int r;
26✔
1927

1928
        assert(filename);
26✔
1929
        assert(lvalue);
26✔
1930
        assert(rvalue);
26✔
1931

1932
        if (isempty(rvalue)) {
26✔
1933
                *hwaddr = mfree(*hwaddr);
1✔
1934
                return 1;
1✔
1935
        }
1936

1937
        n = new0(struct ether_addr, 1);
25✔
1938
        if (!n)
25✔
1939
                return log_oom();
×
1940

1941
        r = parse_ether_addr(rvalue, n);
25✔
1942
        if (r < 0)
25✔
1943
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
15✔
1944

1945
        free_and_replace(*hwaddr, n);
10✔
1946
        return 1;
10✔
1947
}
1948

1949
int config_parse_ether_addrs(
28✔
1950
                const char *unit,
1951
                const char *filename,
1952
                unsigned line,
1953
                const char *section,
1954
                unsigned section_line,
1955
                const char *lvalue,
1956
                int ltype,
1957
                const char *rvalue,
1958
                void *data,
1959
                void *userdata) {
1960

1961
        Set **hwaddrs = ASSERT_PTR(data);
28✔
1962
        int r;
28✔
1963

1964
        assert(filename);
28✔
1965
        assert(lvalue);
28✔
1966
        assert(rvalue);
28✔
1967

1968
        if (isempty(rvalue)) {
28✔
1969
                /* Empty assignment resets the list */
1970
                *hwaddrs = set_free(*hwaddrs);
1✔
1971
                return 1;
1✔
1972
        }
1973

1974
        for (const char *p = rvalue;;) {
27✔
1975
                _cleanup_free_ char *word = NULL;
20✔
1976
                _cleanup_free_ struct ether_addr *n = NULL;
65✔
1977

1978
                r = extract_first_word(&p, &word, NULL, 0);
65✔
1979
                if (r < 0)
65✔
1980
                        return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1981
                if (r == 0)
65✔
1982
                        return 1;
1983

1984
                n = new(struct ether_addr, 1);
38✔
1985
                if (!n)
38✔
1986
                        return log_oom();
×
1987

1988
                r = parse_ether_addr(word, n);
38✔
1989
                if (r < 0) {
38✔
1990
                        log_syntax(unit, LOG_WARNING, filename, line, r,
18✔
1991
                                   "Not a valid MAC address, ignoring: %s", word);
1992
                        continue;
18✔
1993
                }
1994

1995
                r = set_ensure_consume(hwaddrs, &ether_addr_hash_ops_free, TAKE_PTR(n));
20✔
1996
                if (r < 0)
20✔
1997
                        return log_oom();
×
1998
        }
1999
}
2000

2001
int config_parse_in_addr_non_null(
47✔
2002
                const char *unit,
2003
                const char *filename,
2004
                unsigned line,
2005
                const char *section,
2006
                unsigned section_line,
2007
                const char *lvalue,
2008
                int ltype,
2009
                const char *rvalue,
2010
                void *data,
2011
                void *userdata) {
2012

2013
        /* data must be a pointer to struct in_addr or in6_addr, and the type is determined by ltype. */
2014
        struct in_addr *ipv4 = ASSERT_PTR(data);
47✔
2015
        struct in6_addr *ipv6 = ASSERT_PTR(data);
47✔
2016
        union in_addr_union a;
47✔
2017
        int r;
47✔
2018

2019
        assert(filename);
47✔
2020
        assert(lvalue);
47✔
2021
        assert(rvalue);
47✔
2022
        assert(IN_SET(ltype, AF_INET, AF_INET6));
47✔
2023

2024
        if (isempty(rvalue)) {
47✔
2025
                if (ltype == AF_INET)
×
2026
                        *ipv4 = (struct in_addr) {};
×
2027
                else
2028
                        *ipv6 = (struct in6_addr) {};
×
2029
                return 1;
×
2030
        }
2031

2032
        r = in_addr_from_string(ltype, rvalue, &a);
47✔
2033
        if (r < 0)
47✔
2034
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
18✔
2035

2036
        if (!in_addr_is_set(ltype, &a)) {
29✔
2037
                log_syntax(unit, LOG_WARNING, filename, line, 0,
×
2038
                           "%s= cannot be the ANY address, ignoring: %s", lvalue, rvalue);
2039
                return 0;
×
2040
        }
2041

2042
        if (ltype == AF_INET)
29✔
2043
                *ipv4 = a.in;
28✔
2044
        else
2045
                *ipv6 = a.in6;
1✔
2046
        return 1;
2047
}
2048

2049
int config_parse_in_addr_data(
73✔
2050
                const char *unit,
2051
                const char *filename,
2052
                unsigned line,
2053
                const char *section,
2054
                unsigned section_line,
2055
                const char *lvalue,
2056
                int ltype,
2057
                const char *rvalue,
2058
                void *data,
2059
                void *userdata) {
2060

2061
        struct in_addr_data *p = ASSERT_PTR(data);
73✔
2062
        int r;
73✔
2063

2064
        assert(filename);
73✔
2065
        assert(lvalue);
73✔
2066

2067
        if (isempty(rvalue)) {
73✔
2068
                *p = (struct in_addr_data) {};
×
2069
                return 1;
×
2070
        }
2071

2072
        r = in_addr_from_string_auto(rvalue, &p->family, &p->address);
73✔
2073
        if (r < 0)
73✔
2074
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
2075

2076
        return 1;
2077
}
2078

2079
int config_parse_in_addr_prefix(
4,993✔
2080
                const char *unit,
2081
                const char *filename,
2082
                unsigned line,
2083
                const char *section,
2084
                unsigned section_line,
2085
                const char *lvalue,
2086
                int ltype, /* takes boolean, whether we warn about missing prefixlen */
2087
                const char *rvalue,
2088
                void *data,
2089
                void *userdata) {
2090

2091
        struct in_addr_prefix *p = ASSERT_PTR(data);
4,993✔
2092
        int r;
4,993✔
2093

2094
        assert(filename);
4,993✔
2095
        assert(lvalue);
4,993✔
2096

2097
        if (isempty(rvalue)) {
4,993✔
2098
                *p = (struct in_addr_prefix) {};
×
2099
                return 1;
×
2100
        }
2101

2102
        r = in_addr_prefix_from_string_auto_full(rvalue, ltype ? PREFIXLEN_REFUSE : PREFIXLEN_FULL, &p->family, &p->address, &p->prefixlen);
4,993✔
2103
        if (r == -ENOANO) {
4,993✔
2104
                r = in_addr_prefix_from_string_auto(rvalue, &p->family, &p->address, &p->prefixlen);
14✔
2105
                if (r >= 0)
14✔
2106
                        log_syntax(unit, LOG_WARNING, filename, line, r,
14✔
2107
                                   "%s=%s is specified without prefix length. Assuming the prefix length is %u. "
2108
                                   "Please specify the prefix length explicitly.", lvalue, rvalue, p->prefixlen);
2109
        }
2110
        if (r < 0)
4,993✔
2111
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
35✔
2112

2113
        return 1;
2114
}
2115

2116
int config_parse_unsigned_bounded(
92✔
2117
                const char *unit,
2118
                const char *filename,
2119
                unsigned line,
2120
                const char *section,
2121
                unsigned section_line,
2122
                const char *lvalue,
2123
                const char *rvalue,
2124
                unsigned min,
2125
                unsigned max,
2126
                bool ignoring,
2127
                unsigned *ret) {
2128

2129
        int r;
92✔
2130

2131
        assert(filename);
92✔
2132
        assert(lvalue);
92✔
2133
        assert(rvalue);
92✔
2134
        assert(ret);
92✔
2135

2136
        r = safe_atou_bounded(rvalue, min, max, ret);
92✔
2137
        if (r == -ERANGE) {
92✔
2138
                log_syntax(unit, LOG_WARNING, filename, line, r,
×
2139
                           "Invalid '%s=%s', allowed range is %u..%u%s.",
2140
                           lvalue, rvalue, min, max, ignoring ? ", ignoring" : "");
2141
                return ignoring ? 0 : r;
×
2142
        }
2143
        if (r < 0)
92✔
2144
                return log_syntax_parse_error_full(unit, filename, line, r, /* critical= */ !ignoring, lvalue, rvalue);
×
2145

2146
        return 1;  /* Return 1 if something was set */
2147
}
2148

2149
int config_parse_calendar(
×
2150
                const char *unit,
2151
                const char *filename,
2152
                unsigned line,
2153
                const char *section,
2154
                unsigned section_line,
2155
                const char *lvalue,
2156
                int ltype,
2157
                const char *rvalue,
2158
                void *data,
2159
                void *userdata) {
2160

2161
        CalendarSpec **cr = data;
×
2162
        _cleanup_(calendar_spec_freep) CalendarSpec *c = NULL;
×
2163
        int r;
×
2164

2165
        assert(filename);
×
2166
        assert(lvalue);
×
2167
        assert(rvalue);
×
2168
        assert(data);
×
2169

2170
        if (isempty(rvalue)) {
×
2171
                *cr = calendar_spec_free(*cr);
×
2172
                return 1;
×
2173
        }
2174

2175
        r = calendar_spec_from_string(rvalue, &c);
×
2176
        if (r < 0)
×
2177
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
2178

2179
        free_and_replace_full(*cr, c, calendar_spec_free);
×
2180
        return 1;
×
2181
}
2182

2183
DEFINE_CONFIG_PARSE(config_parse_percent, parse_percent);
×
2184
DEFINE_CONFIG_PARSE(config_parse_permyriad, parse_permyriad);
1✔
2185
DEFINE_CONFIG_PARSE_PTR(config_parse_sec_fix_0, parse_sec_fix_0, usec_t);
251✔
2186

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

2199
        char **tz = ASSERT_PTR(data);
1✔
2200
        int r;
1✔
2201

2202
        assert(filename);
1✔
2203
        assert(lvalue);
1✔
2204
        assert(rvalue);
1✔
2205

2206
        if (isempty(rvalue)) {
1✔
2207
                *tz = mfree(*tz);
×
2208
                return 1;
×
2209
        }
2210

2211
        r = verify_timezone(rvalue, LOG_WARNING);
1✔
2212
        if (r < 0)
1✔
2213
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
2214

2215
        r = free_and_strdup_warn(tz, rvalue);
1✔
2216
        if (r < 0)
1✔
2217
                return r;
×
2218

2219
        return 1;
2220
}
2221

2222
int config_parse_ip_protocol(
6✔
2223
                const char *unit,
2224
                const char *filename,
2225
                unsigned line,
2226
                const char *section,
2227
                unsigned section_line,
2228
                const char *lvalue,
2229
                int ltype,
2230
                const char *rvalue,
2231
                void *data,
2232
                void *userdata) {
2233

2234
        uint8_t *proto = ASSERT_PTR(data);
6✔
2235
        int r;
6✔
2236

2237
        r = isempty(rvalue) ? 0 : parse_ip_protocol_full(rvalue, /* relaxed= */ ltype);
12✔
2238
        if (r < 0)
6✔
2239
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
2240

2241
        if (r > UINT8_MAX) {
6✔
2242
                /* linux/fib_rules.h and linux/fou.h define the netlink field as one byte, so we need to
2243
                 * reject protocols numbers that don't fit in one byte. */
2244
                log_syntax(unit, LOG_WARNING, filename, line, r,
×
2245
                           "Invalid '%s=%s', allowed range is 0..255, ignoring.",
2246
                           lvalue, rvalue);
2247
                return 0;
×
2248
        }
2249

2250
        *proto = r;
6✔
2251
        return 1; /* done. */
6✔
2252
}
2253

2254
int config_parse_loadavg(
1✔
2255
                const char *unit,
2256
                const char *filename,
2257
                unsigned line,
2258
                const char *section,
2259
                unsigned section_line,
2260
                const char *lvalue,
2261
                int ltype,
2262
                const char *rvalue,
2263
                void *data,
2264
                void *userdata) {
2265

2266
        loadavg_t *i = ASSERT_PTR(data);
1✔
2267
        int r;
1✔
2268

2269
        assert(rvalue);
1✔
2270

2271
        r = parse_permyriad(rvalue);
1✔
2272
        if (r < 0)
1✔
2273
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
2274

2275
        r = store_loadavg_fixed_point(r / 100, r % 100, i);
1✔
2276
        if (r < 0)
1✔
2277
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
2278

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