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

systemd / systemd / 21084785420

16 Jan 2026 11:47PM UTC coverage: 72.748% (+0.2%) from 72.522%
21084785420

push

github

yuwata
socket: turn of loud logging when setting up sockopts in container fails due to privs

Various socktops will fail if we run in a container, due to lack of
privs (for example SO_RECVFORCE as used by the journald sockets). That's
typically not a big issue. Hence downgrade the log level.

Follow-up for: f7df0eab8

310553 of 426888 relevant lines covered (72.75%)

1128365.0 hits per line

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

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

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

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

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

67
                if (!streq(lvalue, t->lvalue))
88,059✔
68
                        continue;
78,128✔
69

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

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

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

103
        if (section) {
416,612✔
104
                const char *key;
416,612✔
105

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

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

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

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

155
                return func(unit, filename, line, section, section_line,
416,954✔
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(
738,781✔
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;
738,781✔
187

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

193
        l = strstrip(l);
738,781✔
194
        if (isempty(l))
1,477,562✔
195
                return 0;
196

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

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

203
        if (l[0] == '[') {
599,922✔
204
                _cleanup_free_ char *n = NULL;
116,701✔
205
                size_t k;
116,701✔
206

207
                k = strlen(l);
116,701✔
208
                assert(k > 0);
116,701✔
209

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

217
                if (!string_is_safe(n))
116,701✔
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)) {
116,701✔
221
                        bool ignore;
7,101✔
222

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

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

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

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

244
                return 0;
116,701✔
245
        }
246

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

251
                return 0;
58,622✔
252
        }
253

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

262
        *e = 0;
424,599✔
263
        e++;
424,599✔
264

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

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

297
        assert(filename);
85,084✔
298
        assert(lookup);
85,084✔
299

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

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

331
        for (;;) {
1,441,753✔
332
                _cleanup_free_ char *buf = NULL;
1,356,671✔
333
                bool escaped = false;
1,441,753✔
334
                char *l, *p, *e;
1,441,753✔
335

336
                r = read_line(f, LONG_LINE_MAX, &buf);
1,441,753✔
337
                if (r == 0)
1,441,753✔
338
                        break;
339
                if (r == -ENOBUFS) {
1,356,671✔
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,356,670✔
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,356,670✔
353

354
                l = skip_leading_chars(buf, WHITESPACE);
1,356,670✔
355
                if (*l != '\0' && strchr(COMMENTS, *l))
1,356,670✔
356
                        continue;
613,491✔
357

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

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

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

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

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

386
                for (e = p; *e; e++) {
539,084,340✔
387
                        if (escaped)
538,341,162✔
388
                                escaped = false;
389
                        else if (*e == '\\')
538,340,872✔
390
                                escaped = true;
4,689✔
391
                }
392

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

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

405
                        continue;
4,399✔
406
                }
407

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

429
        if (continuation) {
85,082✔
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)
85,082✔
450
                *ret_stat = st;
48,778✔
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,350✔
456
        _cleanup_free_ struct stat *st_copy = NULL;
104,700✔
457
        _cleanup_free_ char *path_copy = NULL;
52,350✔
458
        int r;
52,350✔
459

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

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

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

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

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

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

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

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

505
        STRV_FOREACH(fn, files) {
36,578✔
506
                _cleanup_fclose_ FILE *f = NULL;
530✔
507
                _cleanup_free_ char *fname = NULL;
530✔
508

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

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

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

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

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

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

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

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

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

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

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

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

571
                break;
572
        }
573

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

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

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

591
        if (ret_stats_by_path)
36,048✔
592
                *ret_stats_by_path = TAKE_PTR(stats_by_path);
9,754✔
593

594
        return 0;
595
}
596

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

611
        _cleanup_strv_free_ char **files = NULL;
36,048✔
612
        int r;
36,048✔
613

614
        assert(conf_file_dirs);
36,048✔
615
        assert(dropin_dirname);
36,048✔
616
        assert(table);
36,048✔
617

618
        r = conf_files_list_dropins(&files, dropin_dirname, root,
72,096✔
619
                                    FLAGS_SET(flags, CONFIG_PARSE_WARN) ? CONF_FILES_WARN : 0,
36,048✔
620
                                    conf_file_dirs);
621
        if (r < 0)
36,048✔
622
                return log_full_errno(FLAGS_SET(flags, CONFIG_PARSE_WARN) ? LOG_WARNING : LOG_DEBUG, r,
×
623
                                      "Failed to list drop-ins in %s: %m", dropin_dirname);
624

625
        r = config_parse_many_files(root, conf_files, files, sections, lookup, table, flags, userdata, ret_stats_by_path);
36,048✔
626
        if (r < 0)
36,048✔
627
                return r; /* config_parse_many_files() logs internally. */
628

629
        if (ret_dropin_files)
36,048✔
630
                *ret_dropin_files = TAKE_PTR(files);
10,120✔
631

632
        return 0;
633
}
634

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

646
        const char* const *conf_paths = (const char* const*) CONF_PATHS_STRV("");
24,244✔
647
        _cleanup_strv_free_ char **configs = NULL;
24,244✔
648
        int r, level = FLAGS_SET(flags, CONFIG_PARSE_WARN) ? LOG_WARNING : LOG_DEBUG;
24,244✔
649

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

655
        _cleanup_free_ char *dropin_dirname = strjoin(main_file, ".d");
48,488✔
656
        if (!dropin_dirname)
24,244✔
657
                return log_oom_full(level);
×
658

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

673
static int dropins_get_stats_by_path(
3,050✔
674
                const char* conf_file,
675
                const char* const* conf_file_dirs,
676
                Hashmap **stats_by_path) {
677

678
        _cleanup_strv_free_ char **files = NULL;
×
679
        _cleanup_free_ char *dropin_dirname = NULL;
3,050✔
680
        int r;
3,050✔
681

682
        assert(conf_file);
3,050✔
683
        assert(conf_file_dirs);
3,050✔
684
        assert(stats_by_path);
3,050✔
685

686
        r = path_extract_filename(conf_file, &dropin_dirname);
3,050✔
687
        if (r < 0)
3,050✔
688
                return r;
689
        if (r == O_DIRECTORY)
3,050✔
690
                return -EINVAL;
691

692
        if (!strextend(&dropin_dirname, ".d"))
3,050✔
693
                return -ENOMEM;
694

695
        r = conf_files_list_dropins(&files, dropin_dirname, /* root= */ NULL, /* flags= */ 0, conf_file_dirs);
3,050✔
696
        if (r < 0)
3,050✔
697
                return r;
698

699
        STRV_FOREACH(fn, files) {
3,061✔
700
                struct stat st;
11✔
701

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

706
                        return -errno;
×
707
                }
708

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

714
        return 0;
715
}
716

717
int config_get_stats_by_path(
754✔
718
                const char *suffix,
719
                const char *root,
720
                ConfFilesFlags flags,
721
                const char* const* dirs,
722
                bool check_dropins,
723
                Hashmap **ret) {
724

725
        _cleanup_hashmap_free_ Hashmap *stats_by_path = NULL;
754✔
726
        _cleanup_strv_free_ char **files = NULL;
754✔
727
        int r;
754✔
728

729
        assert(suffix);
754✔
730
        assert(dirs);
754✔
731
        assert(ret);
754✔
732

733
        /* Unlike config_parse(), this does not support stream. */
734

735
        r = conf_files_list_strv(&files, suffix, root, flags, dirs);
754✔
736
        if (r < 0)
754✔
737
                return r;
738

739
        STRV_FOREACH(f, files) {
33,878✔
740
                struct stat st;
33,124✔
741

742
                /* First read the main config file. */
743
                if (stat(*f, &st) < 0) {
33,124✔
744
                        if (errno == ENOENT)
×
745
                                continue;
30,074✔
746

747
                        return -errno;
×
748
                }
749

750
                /* Skipping an empty file. */
751
                if (null_or_empty(&st))
33,124✔
752
                        continue;
×
753

754
                r = hashmap_put_stats_by_path(&stats_by_path, *f, &st);
33,124✔
755
                if (r < 0)
33,124✔
756
                        return r;
757

758
                if (!check_dropins)
33,124✔
759
                        continue;
30,074✔
760

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

767
        *ret = TAKE_PTR(stats_by_path);
754✔
768
        return 0;
754✔
769
}
770

771
bool stats_by_path_equal(Hashmap *a, Hashmap *b) {
2,762✔
772
        struct stat *st_a, *st_b;
2,762✔
773
        const char *path;
2,762✔
774

775
        if (hashmap_size(a) != hashmap_size(b))
2,762✔
776
                return false;
2,762✔
777

778
        HASHMAP_FOREACH_KEY(st_a, path, a) {
34,296✔
779
                st_b = hashmap_get(b, path);
31,842✔
780
                if (!st_b)
31,842✔
781
                        return false;
198✔
782

783
                if (!stat_inode_unmodified(st_a, st_b))
31,840✔
784
                        return false;
785
        }
786

787
        return true;
2,454✔
788
}
789

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

803
        assert(parsers);
6,906✔
804
        assert(n_parsers > 0);
6,906✔
805
        assert(ltype >= 0);
6,906✔
806
        assert((size_t) ltype < n_parsers);
6,906✔
807
        assert(userdata);
6,906✔
808

809
        const ConfigSectionParser *e = parsers + ltype;
6,906✔
810
        assert(e->parser);
6,906✔
811

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

817
        return e->parser(unit, filename, line, section, section_line, lvalue, e->ltype, rvalue,
13,812✔
818
                         (uint8_t*) userdata + e->offset, userdata);
6,906✔
819
}
820

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

826
int config_section_compare_func(const ConfigSection *x, const ConfigSection *y) {
6,087✔
827
        int r;
6,087✔
828

829
        r = strcmp(x->filename, y->filename);
6,087✔
830
        if (r != 0)
6,087✔
831
                return r;
832

833
        return CMP(x->line, y->line);
5,718✔
834
}
835

836
DEFINE_HASH_OPS(config_section_hash_ops, ConfigSection, config_section_hash_func, config_section_compare_func);
837

838
int config_section_new(const char *filename, unsigned line, ConfigSection **ret) {
7,878✔
839
        ConfigSection *cs;
7,878✔
840

841
        assert(filename);
7,878✔
842
        assert(line > 0);
7,878✔
843
        assert(ret);
7,878✔
844

845
        cs = malloc0(offsetof(ConfigSection, filename) + strlen(filename) + 1);
7,878✔
846
        if (!cs)
7,878✔
847
                return -ENOMEM;
7,878✔
848

849
        strcpy(cs->filename, filename);
7,878✔
850
        cs->line = line;
7,878✔
851

852
        *ret = TAKE_PTR(cs);
7,878✔
853
        return 0;
7,878✔
854
}
855

856
static int _hashmap_by_section_find_unused_line(
35✔
857
                HashmapBase *entries_by_section,
858
                const char *filename,
859
                unsigned *ret) {
860

861
        ConfigSection *cs;
35✔
862
        unsigned n = 0;
35✔
863
        void *entry;
35✔
864

865
        HASHMAP_BASE_FOREACH_KEY(entry, cs, entries_by_section) {
565✔
866
                if (filename && !streq(cs->filename, filename))
530✔
867
                        continue;
×
868
                n = MAX(n, cs->line);
530✔
869
        }
870

871
        /* overflow? */
872
        if (n >= UINT_MAX)
35✔
873
                return -EFBIG;
35✔
874

875
        *ret = n + 1;
35✔
876
        return 0;
35✔
877
}
878

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

884
        return _hashmap_by_section_find_unused_line(HASHMAP_BASE(entries_by_section), filename, ret);
20✔
885
}
886

887
int ordered_hashmap_by_section_find_unused_line(
15✔
888
        OrderedHashmap *entries_by_section,
889
        const char *filename,
890
        unsigned *ret) {
891

892
        return _hashmap_by_section_find_unused_line(HASHMAP_BASE(entries_by_section), filename, ret);
15✔
893
}
894

895
#define DEFINE_PARSER(type, vartype, conv_func)                         \
896
        DEFINE_CONFIG_PARSE_PTR(config_parse_##type, conv_func, vartype)
897

898
DEFINE_PARSER(int, int, safe_atoi);
199✔
899
DEFINE_PARSER(long, long, safe_atoli);
×
900
DEFINE_PARSER(uint8, uint8_t, safe_atou8);
23✔
901
DEFINE_PARSER(uint16, uint16_t, safe_atou16);
5✔
902
DEFINE_PARSER(uint32, uint32_t, safe_atou32);
180✔
903
DEFINE_PARSER(int32, int32_t, safe_atoi32);
12✔
904
DEFINE_PARSER(uint64, uint64_t, safe_atou64);
187✔
905
DEFINE_PARSER(unsigned, unsigned, safe_atou);
2,319✔
906
DEFINE_PARSER(double, double, safe_atod);
×
907
DEFINE_PARSER(nsec, nsec_t, parse_nsec);
7✔
908
DEFINE_PARSER(sec, usec_t, parse_sec);
3,826✔
909
DEFINE_PARSER(sec_def_infinity, usec_t, parse_sec_def_infinity);
×
910
DEFINE_PARSER(mode, mode_t, parse_mode);
7,146✔
911
DEFINE_PARSER(pid, pid_t, parse_pid);
2✔
912

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

925
        size_t *sz = ASSERT_PTR(data);
777✔
926
        uint64_t v;
777✔
927
        int r;
777✔
928

929
        assert(filename);
777✔
930
        assert(lvalue);
777✔
931
        assert(rvalue);
777✔
932

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

939
        *sz = (size_t) v;
774✔
940
        return 1;
774✔
941
}
942

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

955
        uint64_t *sz = ASSERT_PTR(data);
9✔
956
        int r;
9✔
957

958
        assert(filename);
9✔
959
        assert(lvalue);
9✔
960
        assert(rvalue);
9✔
961

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

966
        return 1;
967
}
968

969
int config_parse_iec_uint64(
5✔
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
        uint64_t *bytes = ASSERT_PTR(data);
5✔
982
        int r;
5✔
983

984
        assert(filename);
5✔
985
        assert(lvalue);
5✔
986
        assert(rvalue);
5✔
987

988
        r = parse_size(rvalue, 1024, bytes);
5✔
989
        if (r < 0)
5✔
990
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
991

992
        return 1;
993
}
994

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

1007
        uint64_t *bytes = ASSERT_PTR(data);
×
1008

1009
        assert(rvalue);
×
1010

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

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

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

1031
        bool *b = ASSERT_PTR(data);
53,611✔
1032
        bool fatal = ltype;
53,611✔
1033
        int r;
53,611✔
1034

1035
        assert(filename);
53,611✔
1036
        assert(lvalue);
53,611✔
1037
        assert(rvalue);
53,611✔
1038

1039
        r = parse_boolean(rvalue);
53,611✔
1040
        if (r < 0) {
53,611✔
1041
                log_syntax_parse_error_full(unit, filename, line, r, fatal, lvalue, rvalue);
×
1042
                return fatal ? -ENOEXEC : 0;
×
1043
        }
1044

1045
        *b = r;
53,611✔
1046
        return 1; /* set */
53,611✔
1047
}
1048

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

1061
        uint32_t *flags = ASSERT_PTR(data);
68✔
1062
        int r;
68✔
1063

1064
        assert(ltype != 0);
68✔
1065

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

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

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

1086
        uint32_t *flags = ASSERT_PTR(data);
66✔
1087
        int r;
66✔
1088

1089
        assert(ltype != 0);
66✔
1090

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

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

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

1111
        sd_id128_t *result = data;
11✔
1112
        int r;
11✔
1113

1114
        assert(filename);
11✔
1115
        assert(lvalue);
11✔
1116
        assert(rvalue);
11✔
1117

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

1126
        return 1;
1127
}
1128

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

1141
        int r, *t = ASSERT_PTR(data);
5,641✔
1142

1143
        assert(filename);
5,641✔
1144
        assert(lvalue);
5,641✔
1145
        assert(rvalue);
5,641✔
1146

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

1150
        if (isempty(rvalue)) {
5,641✔
1151
                *t = -1;
×
1152
                return 1;
×
1153
        }
1154

1155
        r = parse_tristate(rvalue, t);
5,641✔
1156
        if (r < 0)
5,641✔
1157
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1158

1159
        return 1;
1160
}
1161

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

1174
        char **s = ASSERT_PTR(data);
35,292✔
1175
        int r;
35,292✔
1176

1177
        assert(filename);
35,292✔
1178
        assert(lvalue);
35,292✔
1179
        assert(rvalue);
35,292✔
1180

1181
        if (isempty(rvalue)) {
35,292✔
1182
                *s = mfree(*s);
×
1183
                return 1;
×
1184
        }
1185

1186
        if (FLAGS_SET(ltype, CONFIG_PARSE_STRING_SAFE) && !string_is_safe(rvalue)) {
35,292✔
1187
                _cleanup_free_ char *escaped = NULL;
×
1188

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

1195
        if (FLAGS_SET(ltype, CONFIG_PARSE_STRING_ASCII) && !ascii_is_valid(rvalue)) {
35,303✔
1196
                _cleanup_free_ char *escaped = NULL;
×
1197

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

1204
        r = free_and_strdup_warn(s, rvalue);
35,292✔
1205
        if (r < 0)
35,292✔
1206
                return r;
×
1207

1208
        return 1;
1209
}
1210

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

1223
        char **hostname = ASSERT_PTR(data);
3,029✔
1224
        int r;
3,029✔
1225

1226
        assert(filename);
3,029✔
1227
        assert(lvalue);
3,029✔
1228
        assert(rvalue);
3,029✔
1229

1230
        if (isempty(rvalue)) {
3,029✔
1231
                *hostname = mfree(*hostname);
×
1232
                return 1;
×
1233
        }
1234

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

1247
        r = free_and_strdup_warn(hostname, rvalue);
3,029✔
1248
        if (r < 0)
3,029✔
1249
                return r;
×
1250

1251
        return 1;
1252
}
1253

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

1266
        char **hostname = ASSERT_PTR(data);
23✔
1267

1268
        assert(filename);
23✔
1269
        assert(lvalue);
23✔
1270
        assert(rvalue);
23✔
1271

1272
        if (isempty(rvalue)) {
23✔
1273
                *hostname = mfree(*hostname);
×
1274
                return 1;
×
1275
        }
1276

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

1283
        return config_parse_dns_name(unit, filename, line, section, section_line,
23✔
1284
                                     lvalue, ltype, rvalue, data, userdata);
1285
}
1286

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

1299
        _cleanup_free_ char *n = NULL;
1,420✔
1300
        bool fatal = ltype;
1,420✔
1301
        char **s = ASSERT_PTR(data);
1,420✔
1302
        int r;
1,420✔
1303

1304
        assert(filename);
1,420✔
1305
        assert(lvalue);
1,420✔
1306
        assert(rvalue);
1,420✔
1307

1308
        if (isempty(rvalue)) {
1,420✔
1309
                *s = mfree(*s);
×
1310
                return 1;
×
1311
        }
1312

1313
        n = strdup(rvalue);
1,420✔
1314
        if (!n)
1,420✔
1315
                return log_oom();
×
1316

1317
        r = path_simplify_and_warn(n, PATH_CHECK_ABSOLUTE | (fatal ? PATH_CHECK_FATAL : 0), unit, filename, line, lvalue);
2,840✔
1318
        if (r < 0)
1,420✔
1319
                return fatal ? -ENOEXEC : 0;
2✔
1320

1321
        free_and_replace(*s, n);
1,418✔
1322
        return 1;
1,418✔
1323
}
1324

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

1337
        char ***sv = ASSERT_PTR(data);
35,297✔
1338
        int r;
35,297✔
1339

1340
        assert(filename);
35,297✔
1341
        assert(lvalue);
35,297✔
1342
        assert(rvalue);
35,297✔
1343

1344
        if (isempty(rvalue)) {
35,297✔
1345
                *sv = strv_free(*sv);
2✔
1346
                return 1;
35,297✔
1347
        }
1348

1349
        _cleanup_strv_free_ char **strv = NULL;
35,295✔
1350
        for (const char *p = rvalue;;) {
76,236✔
1351
                char *word;
76,236✔
1352

1353
                r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
76,236✔
1354
                if (r < 0)
76,236✔
1355
                        return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1356
                if (r == 0)
76,236✔
1357
                        break;
1358

1359
                r = strv_consume(&strv, word);
40,941✔
1360
                if (r < 0)
40,941✔
1361
                        return log_oom();
×
1362
        }
1363

1364
        r = strv_extend_strv_consume(sv, TAKE_PTR(strv), /* filter_duplicates= */ ltype);
35,295✔
1365
        if (r < 0)
35,295✔
1366
                return log_oom();
×
1367

1368
        return 1;
1369
}
1370

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

1383
        Disabled reason = ltype;
×
1384

1385
        switch (reason) {
×
1386

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

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

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

1403
        return 0;
×
1404
}
1405

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

1418
        int *o = data, x;
3✔
1419

1420
        assert(filename);
3✔
1421
        assert(lvalue);
3✔
1422
        assert(rvalue);
3✔
1423
        assert(data);
3✔
1424

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

1429
        *o = (x << 3) | LOG_PRI(*o);
2✔
1430

1431
        return 1;
2✔
1432
}
1433

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

1446
        int *o = data, x;
3✔
1447

1448
        assert(filename);
3✔
1449
        assert(lvalue);
3✔
1450
        assert(rvalue);
3✔
1451
        assert(data);
3✔
1452

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

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

1462
        return 1;
1463
}
1464

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

1477
        int *sig = data, r;
249✔
1478

1479
        assert(filename);
249✔
1480
        assert(lvalue);
249✔
1481
        assert(rvalue);
249✔
1482
        assert(sig);
249✔
1483

1484
        r = signal_from_string(rvalue);
249✔
1485
        if (r <= 0)
249✔
1486
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1487

1488
        *sig = r;
249✔
1489
        return 1;
249✔
1490
}
1491

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

1504
        unsigned long *personality = data, p;
×
1505

1506
        assert(filename);
×
1507
        assert(lvalue);
×
1508
        assert(rvalue);
×
1509
        assert(personality);
×
1510

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

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

1520
        *personality = p;
×
1521
        return 1;
×
1522
}
1523

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

1536
        char **s = ASSERT_PTR(data);
1,983✔
1537
        int r;
1,983✔
1538

1539
        assert(filename);
1,983✔
1540
        assert(lvalue);
1,983✔
1541
        assert(rvalue);
1,983✔
1542

1543
        if (isempty(rvalue)) {
1,983✔
1544
                *s = mfree(*s);
×
1545
                return 1;
×
1546
        }
1547

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

1553
        r = free_and_strdup_warn(s, rvalue);
1,983✔
1554
        if (r < 0)
1,983✔
1555
                return r;
×
1556

1557
        return 1;
1558
}
1559

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

1572
        _cleanup_strv_free_ char **names = NULL;
17✔
1573
        char ***s = ASSERT_PTR(data);
17✔
1574
        int r;
17✔
1575

1576
        assert(filename);
17✔
1577
        assert(lvalue);
17✔
1578
        assert(rvalue);
17✔
1579

1580
        if (isempty(rvalue)) {
17✔
1581
                *s = strv_free(*s);
×
1582
                return 1;
×
1583
        }
1584

1585
        for (const char *p = rvalue;;) {
17✔
1586
                _cleanup_free_ char *word = NULL;
31✔
1587

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

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

1601
                r = strv_consume(&names, TAKE_PTR(word));
31✔
1602
                if (r < 0)
31✔
1603
                        return log_oom();
×
1604
        }
1605

1606
        r = strv_extend_strv(s, names, true);
17✔
1607
        if (r < 0)
17✔
1608
                return log_oom();
×
1609

1610
        return 1;
1611
}
1612

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

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

1629
        assert(filename);
27✔
1630
        assert(lvalue);
27✔
1631
        assert(rvalue);
27✔
1632

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

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

1642
        *s = port;
27✔
1643
        return 1;
27✔
1644
}
1645

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

1658
        uint32_t *mtu = ASSERT_PTR(data);
176✔
1659
        int r;
176✔
1660

1661
        assert(rvalue);
176✔
1662

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

1674
        return 1;
1675
}
1676

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

1689
        struct rlimit **rl = data, d = {};
801✔
1690
        int r;
801✔
1691

1692
        assert(rvalue);
801✔
1693
        assert(rl);
801✔
1694

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

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

1711
        return 1;
1712
}
1713

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

1726
        unsigned *permille = ASSERT_PTR(data);
×
1727
        int r;
×
1728

1729
        assert(filename);
×
1730
        assert(lvalue);
×
1731
        assert(rvalue);
×
1732

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

1737
        *permille = (unsigned) r;
×
1738
        return 1;
×
1739
}
1740

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

1753
        int *vlan_protocol = data;
2✔
1754

1755
        assert(filename);
2✔
1756
        assert(lvalue);
2✔
1757

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

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

1770
        return 1;
2✔
1771
}
1772

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

1785
        struct hw_addr_data *hwaddr = ASSERT_PTR(data);
560✔
1786
        int r;
560✔
1787

1788
        assert(filename);
560✔
1789
        assert(lvalue);
560✔
1790
        assert(rvalue);
560✔
1791

1792
        if (isempty(rvalue)) {
560✔
1793
                *hwaddr = HW_ADDR_NULL;
×
1794
                return 1;
×
1795
        }
1796

1797
        r = parse_hw_addr_full(rvalue, ltype, hwaddr);
560✔
1798
        if (r < 0)
560✔
1799
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1800

1801
        return 1;
1802
}
1803

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

1816
        Set **hwaddrs = ASSERT_PTR(data);
17✔
1817
        int r;
17✔
1818

1819
        assert(filename);
17✔
1820
        assert(lvalue);
17✔
1821
        assert(rvalue);
17✔
1822

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

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

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

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

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

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

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

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

1872
        assert(filename);
26✔
1873
        assert(lvalue);
26✔
1874
        assert(rvalue);
26✔
1875

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

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

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

1889
        free_and_replace(*hwaddr, n);
10✔
1890
        return 1;
10✔
1891
}
1892

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

1905
        Set **hwaddrs = ASSERT_PTR(data);
28✔
1906
        int r;
28✔
1907

1908
        assert(filename);
28✔
1909
        assert(lvalue);
28✔
1910
        assert(rvalue);
28✔
1911

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2005
        struct in_addr_data *p = ASSERT_PTR(data);
73✔
2006
        int r;
73✔
2007

2008
        assert(filename);
73✔
2009
        assert(lvalue);
73✔
2010

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

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

2020
        return 1;
2021
}
2022

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

2035
        struct in_addr_prefix *p = ASSERT_PTR(data);
4,993✔
2036
        int r;
4,993✔
2037

2038
        assert(filename);
4,993✔
2039
        assert(lvalue);
4,993✔
2040

2041
        if (isempty(rvalue)) {
4,993✔
2042
                *p = (struct in_addr_prefix) {};
×
2043
                return 1;
×
2044
        }
2045

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

2057
        return 1;
2058
}
2059

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

2073
        int r;
92✔
2074

2075
        assert(filename);
92✔
2076
        assert(lvalue);
92✔
2077
        assert(rvalue);
92✔
2078
        assert(ret);
92✔
2079

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

2090
        return 1;  /* Return 1 if something was set */
2091
}
2092

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

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

2109
        assert(filename);
×
2110
        assert(lvalue);
×
2111
        assert(rvalue);
×
2112
        assert(data);
×
2113

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

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

2123
        free_and_replace_full(*cr, c, calendar_spec_free);
×
2124
        return 1;
×
2125
}
2126

2127
DEFINE_CONFIG_PARSE(config_parse_percent, parse_percent);
×
2128
DEFINE_CONFIG_PARSE(config_parse_permyriad, parse_permyriad);
1✔
2129
DEFINE_CONFIG_PARSE_PTR(config_parse_sec_fix_0, parse_sec_fix_0, usec_t);
245✔
2130

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

2143
        char **tz = ASSERT_PTR(data);
1✔
2144
        int r;
1✔
2145

2146
        assert(filename);
1✔
2147
        assert(lvalue);
1✔
2148
        assert(rvalue);
1✔
2149

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

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

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

2163
        return 1;
2164
}
2165

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

2178
        uint8_t *proto = ASSERT_PTR(data);
6✔
2179
        int r;
6✔
2180

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

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

2194
        *proto = r;
6✔
2195
        return 1; /* done. */
6✔
2196
}
2197

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

2210
        loadavg_t *i = ASSERT_PTR(data);
1✔
2211
        int r;
1✔
2212

2213
        assert(rvalue);
1✔
2214

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

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

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