]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/conf-parser.c
license: LGPL-2.1+ -> LGPL-2.1-or-later
[thirdparty/systemd.git] / src / shared / conf-parser.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
a7334b09 2
ed5bcfbe 3#include <errno.h>
a8fbdf54
TA
4#include <limits.h>
5#include <stdint.h>
07630cea 6#include <stdio.h>
ed5bcfbe 7#include <stdlib.h>
a8fbdf54 8#include <sys/types.h>
07630cea 9
b5efdb8a 10#include "alloc-util.h"
e8461023 11#include "conf-files.h"
6bedfcbb 12#include "conf-parser.h"
e6dde451 13#include "def.h"
a8fbdf54 14#include "extract-word.h"
6bedfcbb 15#include "fd-util.h"
e6dde451 16#include "fileio.h"
f4f15635 17#include "fs-util.h"
16354eff 18#include "log.h"
07630cea 19#include "macro.h"
f5947a5e 20#include "missing_network.h"
d8b4d14d 21#include "nulstr-util.h"
6bedfcbb 22#include "parse-util.h"
9eb977db 23#include "path-util.h"
7b3e062c 24#include "process-util.h"
ef118d00 25#include "rlimit-util.h"
12963533 26#include "sd-id128.h"
f757855e 27#include "signal-util.h"
d31645ad 28#include "socket-util.h"
07630cea
LP
29#include "string-util.h"
30#include "strv.h"
7b3e062c 31#include "syslog-util.h"
a8fbdf54 32#include "time-util.h"
07630cea 33#include "utf8.h"
e8e581bf 34
f975e971 35int config_item_table_lookup(
e9f3d2d5 36 const void *table,
ed5bcfbe 37 const char *section,
ed5bcfbe 38 const char *lvalue,
f975e971
LP
39 ConfigParserCallback *func,
40 int *ltype,
41 void **data,
ed5bcfbe
LP
42 void *userdata) {
43
e9f3d2d5 44 const ConfigTableItem *t;
f975e971
LP
45
46 assert(table);
ed5bcfbe 47 assert(lvalue);
f975e971
LP
48 assert(func);
49 assert(ltype);
50 assert(data);
ed5bcfbe 51
f975e971 52 for (t = table; t->lvalue; t++) {
ed5bcfbe 53
f975e971 54 if (!streq(lvalue, t->lvalue))
ed5bcfbe
LP
55 continue;
56
f975e971 57 if (!streq_ptr(section, t->section))
ed5bcfbe
LP
58 continue;
59
f975e971
LP
60 *func = t->parse;
61 *ltype = t->ltype;
62 *data = t->data;
63 return 1;
64 }
ed5bcfbe 65
f975e971
LP
66 return 0;
67}
10e87ee7 68
f975e971 69int config_item_perf_lookup(
e9f3d2d5 70 const void *table,
f975e971
LP
71 const char *section,
72 const char *lvalue,
73 ConfigParserCallback *func,
74 int *ltype,
75 void **data,
76 void *userdata) {
77
78 ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
79 const ConfigPerfItem *p;
80
81 assert(table);
82 assert(lvalue);
83 assert(func);
84 assert(ltype);
85 assert(data);
86
4472fa6d
LP
87 if (section) {
88 const char *key;
f975e971 89
4472fa6d 90 key = strjoina(section, ".", lvalue);
f975e971 91 p = lookup(key, strlen(key));
4472fa6d
LP
92 } else
93 p = lookup(lvalue, strlen(lvalue));
f975e971
LP
94 if (!p)
95 return 0;
96
97 *func = p->parse;
98 *ltype = p->ltype;
99 *data = (uint8_t*) userdata + p->offset;
100 return 1;
101}
102
103/* Run the user supplied parser for an assignment */
bcde742e
LP
104static int next_assignment(
105 const char *unit,
106 const char *filename,
107 unsigned line,
108 ConfigItemLookup lookup,
109 const void *table,
110 const char *section,
111 unsigned section_line,
112 const char *lvalue,
113 const char *rvalue,
114 ConfigParseFlags flags,
115 void *userdata) {
f975e971
LP
116
117 ConfigParserCallback func = NULL;
118 int ltype = 0;
119 void *data = NULL;
120 int r;
121
122 assert(filename);
123 assert(line > 0);
124 assert(lookup);
125 assert(lvalue);
126 assert(rvalue);
127
128 r = lookup(table, section, lvalue, &func, &ltype, &data, userdata);
129 if (r < 0)
130 return r;
d937fbbd
LP
131 if (r > 0) {
132 if (func)
71a61510
TG
133 return func(unit, filename, line, section, section_line,
134 lvalue, ltype, rvalue, data, userdata);
d937fbbd
LP
135
136 return 0;
137 }
f975e971 138
46205bb6 139 /* Warn about unknown non-extension fields. */
bcde742e 140 if (!(flags & CONFIG_PARSE_RELAXED) && !startswith(lvalue, "X-"))
28f30f40
ZJS
141 log_syntax(unit, LOG_WARNING, filename, line, 0,
142 "Unknown key name '%s' in section '%s', ignoring.", lvalue, section);
46205bb6 143
f1857be0 144 return 0;
ed5bcfbe
LP
145}
146
8a37ce65 147/* Parse a single logical line */
bcde742e
LP
148static int parse_line(
149 const char* unit,
150 const char *filename,
151 unsigned line,
152 const char *sections,
153 ConfigItemLookup lookup,
154 const void *table,
155 ConfigParseFlags flags,
156 char **section,
157 unsigned *section_line,
158 bool *section_ignored,
159 char *l,
160 void *userdata) {
f975e971 161
7ade8982 162 char *e;
ed5bcfbe 163
f975e971
LP
164 assert(filename);
165 assert(line > 0);
166 assert(lookup);
167 assert(l);
168
b2aa81ef 169 l = strstrip(l);
b2aa81ef 170 if (!*l)
ed5bcfbe 171 return 0;
1ea86b18 172
9adbfeb3 173 if (*l == '\n')
1ea86b18 174 return 0;
ed5bcfbe 175
78d17fa0
YW
176 if (!utf8_is_valid(l))
177 return log_syntax_invalid_utf8(unit, LOG_WARNING, filename, line, l);
178
b2aa81ef 179 if (*l == '[') {
ed5bcfbe
LP
180 size_t k;
181 char *n;
182
b2aa81ef 183 k = strlen(l);
ed5bcfbe
LP
184 assert(k > 0);
185
3de39a1a
YW
186 if (l[k-1] != ']')
187 return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EBADMSG), "Invalid section header '%s'", l);
ed5bcfbe 188
f975e971
LP
189 n = strndup(l+1, k-2);
190 if (!n)
7a602af0 191 return log_oom();
ed5bcfbe 192
f975e971 193 if (sections && !nulstr_contains(sections, n)) {
ddeb3f5d
ZJS
194 bool ignore = flags & CONFIG_PARSE_RELAXED;
195 const char *t;
42f4e3c4 196
ddeb3f5d
ZJS
197 ignore = ignore || startswith(n, "X-");
198
199 if (!ignore)
200 NULSTR_FOREACH(t, sections)
201 if (streq_ptr(n, startswith(t, "-"))) {
202 ignore = true;
203 break;
204 }
205
206 if (!ignore)
12ca818f 207 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown section '%s'. Ignoring.", n);
f975e971
LP
208
209 free(n);
a1e58e8e 210 *section = mfree(*section);
71a61510 211 *section_line = 0;
342aea19 212 *section_ignored = true;
f975e971 213 } else {
97b9c506 214 free_and_replace(*section, n);
71a61510 215 *section_line = line;
342aea19 216 *section_ignored = false;
f975e971 217 }
ed5bcfbe
LP
218
219 return 0;
220 }
221
62f168a0 222 if (sections && !*section) {
bcde742e 223 if (!(flags & CONFIG_PARSE_RELAXED) && !*section_ignored)
12ca818f 224 log_syntax(unit, LOG_WARNING, filename, line, 0, "Assignment outside of section. Ignoring.");
62f168a0 225
10e87ee7 226 return 0;
62f168a0 227 }
10e87ee7 228
f975e971 229 e = strchr(l, '=');
2d4fffb0
ZJS
230 if (!e)
231 return log_syntax(unit, LOG_WARNING, filename, line, 0,
232 "Missing '=', ignoring line.");
8be8ed8c
ZJS
233 if (e == l)
234 return log_syntax(unit, LOG_WARNING, filename, line, 0,
235 "Missing key name before '=', ignoring line.");
ed5bcfbe
LP
236
237 *e = 0;
238 e++;
239
e8e581bf
ZJS
240 return next_assignment(unit,
241 filename,
242 line,
243 lookup,
244 table,
245 *section,
71a61510 246 *section_line,
e8e581bf
ZJS
247 strstrip(l),
248 strstrip(e),
bcde742e 249 flags,
e8e581bf 250 userdata);
ed5bcfbe
LP
251}
252
253/* Go through the file and parse each line */
e8e581bf
ZJS
254int config_parse(const char *unit,
255 const char *filename,
256 FILE *f,
257 const char *sections,
258 ConfigItemLookup lookup,
e9f3d2d5 259 const void *table,
bcde742e 260 ConfigParseFlags flags,
4f9ff96a
LP
261 void *userdata,
262 usec_t *ret_mtime) {
f975e971 263
7fd1b19b
HH
264 _cleanup_free_ char *section = NULL, *continuation = NULL;
265 _cleanup_fclose_ FILE *ours = NULL;
71a61510 266 unsigned line = 0, section_line = 0;
f9761a89 267 bool section_ignored = false, bom_seen = false;
14f594b9 268 int r, fd;
4f9ff96a 269 usec_t mtime;
ed5bcfbe
LP
270
271 assert(filename);
f975e971 272 assert(lookup);
ed5bcfbe 273
87f0e418 274 if (!f) {
245802dd 275 f = ours = fopen(filename, "re");
f975e971 276 if (!f) {
36f822c4
ZJS
277 /* Only log on request, except for ENOENT,
278 * since we return 0 to the caller. */
bcde742e 279 if ((flags & CONFIG_PARSE_WARN) || errno == ENOENT)
b8b846d7
LP
280 log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno,
281 "Failed to open configuration file '%s': %m", filename);
9f43a07f 282 return errno == ENOENT ? 0 : -errno;
87f0e418 283 }
ed5bcfbe
LP
284 }
285
14f594b9 286 fd = fileno(f);
4f9ff96a
LP
287 if (fd >= 0) { /* stream might not have an fd, let's be careful hence */
288 struct stat st;
289
290 if (fstat(fd, &st) < 0)
291 return log_full_errno(FLAGS_SET(flags, CONFIG_PARSE_WARN) ? LOG_ERR : LOG_DEBUG, errno,
292 "Failed to fstat(%s): %m", filename);
293
294 (void) stat_warn_permissions(filename, &st);
295 mtime = timespec_load(&st.st_mtim);
296 }
fdb9161c 297
9dd7ea9a 298 for (;;) {
e6dde451 299 _cleanup_free_ char *buf = NULL;
3dab2943 300 bool escaped = false;
92b5e605 301 char *l, *p, *e;
ed5bcfbe 302
e6dde451
LP
303 r = read_line(f, LONG_LINE_MAX, &buf);
304 if (r == 0)
305 break;
306 if (r == -ENOBUFS) {
bcde742e 307 if (flags & CONFIG_PARSE_WARN)
e6dde451
LP
308 log_error_errno(r, "%s:%u: Line too long", filename, line);
309
310 return r;
311 }
312 if (r < 0) {
5aca2e67 313 if (FLAGS_SET(flags, CONFIG_PARSE_WARN))
e6dde451 314 log_error_errno(r, "%s:%u: Error while reading configuration file: %m", filename, line);
ed5bcfbe 315
e6dde451 316 return r;
ed5bcfbe
LP
317 }
318
68c1ac15
YW
319 line++;
320
0ef69585
YW
321 l = skip_leading_chars(buf, WHITESPACE);
322 if (*l != '\0' && strchr(COMMENTS, *l))
9adbfeb3
YW
323 continue;
324
9dd7ea9a 325 l = buf;
f9761a89 326 if (!bom_seen) {
e6dde451 327 char *q;
9dd7ea9a 328
e6dde451
LP
329 q = startswith(buf, UTF8_BYTE_ORDER_MARK);
330 if (q) {
331 l = q;
f9761a89 332 bom_seen = true;
e6dde451
LP
333 }
334 }
3dab2943
LP
335
336 if (continuation) {
e6dde451 337 if (strlen(continuation) + strlen(l) > LONG_LINE_MAX) {
bcde742e 338 if (flags & CONFIG_PARSE_WARN)
e6dde451
LP
339 log_error("%s:%u: Continuation line too long", filename, line);
340 return -ENOBUFS;
341 }
342
92b5e605 343 if (!strextend(&continuation, l, NULL)) {
bcde742e 344 if (flags & CONFIG_PARSE_WARN)
36f822c4 345 log_oom();
245802dd 346 return -ENOMEM;
36f822c4 347 }
3dab2943 348
92b5e605 349 p = continuation;
3dab2943
LP
350 } else
351 p = l;
352
353 for (e = p; *e; e++) {
354 if (escaped)
355 escaped = false;
356 else if (*e == '\\')
357 escaped = true;
358 }
359
360 if (escaped) {
361 *(e-1) = ' ';
362
92b5e605 363 if (!continuation) {
f975e971 364 continuation = strdup(l);
36f822c4 365 if (!continuation) {
bcde742e 366 if (flags & CONFIG_PARSE_WARN)
36f822c4 367 log_oom();
245802dd 368 return -ENOMEM;
36f822c4 369 }
3dab2943
LP
370 }
371
372 continue;
373 }
374
e8e581bf
ZJS
375 r = parse_line(unit,
376 filename,
68c1ac15 377 line,
e8e581bf
ZJS
378 sections,
379 lookup,
380 table,
bcde742e 381 flags,
e8e581bf 382 &section,
71a61510 383 &section_line,
342aea19 384 &section_ignored,
e8e581bf
ZJS
385 p,
386 userdata);
36f822c4 387 if (r < 0) {
bcde742e 388 if (flags & CONFIG_PARSE_WARN)
e6dde451 389 log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
245802dd 390 return r;
36f822c4 391 }
92b5e605
LP
392
393 continuation = mfree(continuation);
ed5bcfbe
LP
394 }
395
4f29e0db
FB
396 if (continuation) {
397 r = parse_line(unit,
398 filename,
399 ++line,
400 sections,
401 lookup,
402 table,
403 flags,
404 &section,
405 &section_line,
406 &section_ignored,
407 continuation,
408 userdata);
409 if (r < 0) {
410 if (flags & CONFIG_PARSE_WARN)
411 log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
412 return r;
4f29e0db
FB
413 }
414 }
415
4f9ff96a
LP
416 if (ret_mtime)
417 *ret_mtime = mtime;
418
245802dd 419 return 0;
ed5bcfbe
LP
420}
421
23bb31aa 422static int config_parse_many_files(
43688c49 423 const char *conf_file,
23bb31aa 424 char **files,
43688c49
ZJS
425 const char *sections,
426 ConfigItemLookup lookup,
427 const void *table,
bcde742e 428 ConfigParseFlags flags,
4f9ff96a
LP
429 void *userdata,
430 usec_t *ret_mtime) {
43688c49 431
4f9ff96a 432 usec_t mtime = 0;
e8461023
JT
433 char **fn;
434 int r;
435
e8461023 436 if (conf_file) {
4f9ff96a 437 r = config_parse(NULL, conf_file, NULL, sections, lookup, table, flags, userdata, &mtime);
e8461023
JT
438 if (r < 0)
439 return r;
440 }
441
442 STRV_FOREACH(fn, files) {
4f9ff96a
LP
443 usec_t t;
444
445 r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata, &t);
e8461023
JT
446 if (r < 0)
447 return r;
4f9ff96a
LP
448 if (t > mtime) /* Find the newest */
449 mtime = t;
e8461023
JT
450 }
451
4f9ff96a
LP
452 if (ret_mtime)
453 *ret_mtime = mtime;
454
e8461023
JT
455 return 0;
456}
457
23bb31aa
ZJS
458/* Parse each config file in the directories specified as nulstr. */
459int config_parse_many_nulstr(
460 const char *conf_file,
461 const char *conf_file_dirs,
462 const char *sections,
463 ConfigItemLookup lookup,
464 const void *table,
bcde742e 465 ConfigParseFlags flags,
4f9ff96a
LP
466 void *userdata,
467 usec_t *ret_mtime) {
23bb31aa
ZJS
468
469 _cleanup_strv_free_ char **files = NULL;
470 int r;
471
b5084605 472 r = conf_files_list_nulstr(&files, ".conf", NULL, 0, conf_file_dirs);
23bb31aa
ZJS
473 if (r < 0)
474 return r;
475
4f9ff96a 476 return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata, ret_mtime);
23bb31aa
ZJS
477}
478
479/* Parse each config file in the directories specified as strv. */
480int config_parse_many(
481 const char *conf_file,
482 const char* const* conf_file_dirs,
483 const char *dropin_dirname,
484 const char *sections,
485 ConfigItemLookup lookup,
486 const void *table,
bcde742e 487 ConfigParseFlags flags,
9f83091e 488 void *userdata,
4f9ff96a 489 usec_t *ret_mtime) {
23bb31aa
ZJS
490
491 _cleanup_strv_free_ char **dropin_dirs = NULL;
492 _cleanup_strv_free_ char **files = NULL;
493 const char *suffix;
494 int r;
495
496 suffix = strjoina("/", dropin_dirname);
497 r = strv_extend_strv_concat(&dropin_dirs, (char**) conf_file_dirs, suffix);
498 if (r < 0)
499 return r;
500
b5084605 501 r = conf_files_list_strv(&files, ".conf", NULL, 0, (const char* const*) dropin_dirs);
23bb31aa
ZJS
502 if (r < 0)
503 return r;
504
4f9ff96a 505 return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata, ret_mtime);
23bb31aa
ZJS
506}
507
eb3491d9 508#define DEFINE_PARSER(type, vartype, conv_func) \
2d1729ca 509 DEFINE_CONFIG_PARSE_PTR(config_parse_##type, conv_func, vartype, "Failed to parse " #type " value")
94d75d64
LP
510
511DEFINE_PARSER(int, int, safe_atoi);
512DEFINE_PARSER(long, long, safe_atoli);
134e24e1 513DEFINE_PARSER(uint8, uint8_t, safe_atou8);
c7440e74 514DEFINE_PARSER(uint16, uint16_t, safe_atou16);
94d75d64 515DEFINE_PARSER(uint32, uint32_t, safe_atou32);
b57ebc60 516DEFINE_PARSER(int32, int32_t, safe_atoi32);
94d75d64
LP
517DEFINE_PARSER(uint64, uint64_t, safe_atou64);
518DEFINE_PARSER(unsigned, unsigned, safe_atou);
519DEFINE_PARSER(double, double, safe_atod);
520DEFINE_PARSER(nsec, nsec_t, parse_nsec);
521DEFINE_PARSER(sec, usec_t, parse_sec);
7b61ce3c 522DEFINE_PARSER(sec_def_infinity, usec_t, parse_sec_def_infinity);
94d75d64 523DEFINE_PARSER(mode, mode_t, parse_mode);
ed5bcfbe 524
5556b5fe 525int config_parse_iec_size(const char* unit,
e8e581bf
ZJS
526 const char *filename,
527 unsigned line,
528 const char *section,
71a61510 529 unsigned section_line,
e8e581bf
ZJS
530 const char *lvalue,
531 int ltype,
532 const char *rvalue,
533 void *data,
534 void *userdata) {
ed5bcfbe
LP
535
536 size_t *sz = data;
59f448cf 537 uint64_t v;
e8e581bf 538 int r;
ed5bcfbe
LP
539
540 assert(filename);
541 assert(lvalue);
542 assert(rvalue);
543 assert(data);
544
59f448cf 545 r = parse_size(rvalue, 1024, &v);
1e5f4e8b
YW
546 if (r >= 0 && (uint64_t) (size_t) v != v)
547 r = -ERANGE;
548 if (r < 0) {
d96edb2c 549 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse size value '%s', ignoring: %m", rvalue);
9ba1a159
LP
550 return 0;
551 }
552
59f448cf 553 *sz = (size_t) v;
9ba1a159
LP
554 return 0;
555}
556
50299121 557int config_parse_si_uint64(
78f3c4bc
LP
558 const char* unit,
559 const char *filename,
560 unsigned line,
561 const char *section,
562 unsigned section_line,
563 const char *lvalue,
564 int ltype,
565 const char *rvalue,
566 void *data,
567 void *userdata) {
5556b5fe 568
50299121 569 uint64_t *sz = data;
5556b5fe
LP
570 int r;
571
572 assert(filename);
573 assert(lvalue);
574 assert(rvalue);
575 assert(data);
576
50299121 577 r = parse_size(rvalue, 1000, sz);
d96edb2c
YW
578 if (r < 0)
579 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse size value '%s', ignoring: %m", rvalue);
5556b5fe 580
5556b5fe
LP
581 return 0;
582}
9ba1a159 583
78f3c4bc
LP
584int config_parse_iec_uint64(
585 const char* unit,
586 const char *filename,
587 unsigned line,
588 const char *section,
589 unsigned section_line,
590 const char *lvalue,
591 int ltype,
592 const char *rvalue,
593 void *data,
594 void *userdata) {
9ba1a159 595
59f448cf 596 uint64_t *bytes = data;
e8e581bf 597 int r;
9ba1a159
LP
598
599 assert(filename);
600 assert(lvalue);
601 assert(rvalue);
602 assert(data);
603
5556b5fe 604 r = parse_size(rvalue, 1024, bytes);
e8e581bf 605 if (r < 0)
d96edb2c 606 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
ed5bcfbe 607
ed5bcfbe
LP
608 return 0;
609}
610
e8e581bf
ZJS
611int config_parse_bool(const char* unit,
612 const char *filename,
613 unsigned line,
614 const char *section,
71a61510 615 unsigned section_line,
e8e581bf
ZJS
616 const char *lvalue,
617 int ltype,
618 const char *rvalue,
619 void *data,
620 void *userdata) {
ed5bcfbe
LP
621
622 int k;
623 bool *b = data;
2c75fb73 624 bool fatal = ltype;
ed5bcfbe
LP
625
626 assert(filename);
627 assert(lvalue);
628 assert(rvalue);
629 assert(data);
630
e8e581bf
ZJS
631 k = parse_boolean(rvalue);
632 if (k < 0) {
d96edb2c 633 log_syntax(unit, fatal ? LOG_ERR : LOG_WARNING, filename, line, k,
2c75fb73
ZJS
634 "Failed to parse boolean value%s: %s",
635 fatal ? "" : ", ignoring", rvalue);
636 return fatal ? -ENOEXEC : 0;
ed5bcfbe
LP
637 }
638
5d904a6a 639 *b = k;
ed5bcfbe
LP
640 return 0;
641}
642
12963533
TH
643int config_parse_id128(
644 const char *unit,
645 const char *filename,
646 unsigned line,
647 const char *section,
648 unsigned section_line,
649 const char *lvalue,
650 int ltype,
651 const char *rvalue,
652 void *data,
653 void *userdata) {
654
655 sd_id128_t t, *result = data;
656 int r;
657
658 assert(filename);
659 assert(lvalue);
660 assert(rvalue);
661
662 r = sd_id128_from_string(rvalue, &t);
d96edb2c
YW
663 if (r < 0) {
664 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse 128bit ID/UUID, ignoring: %s", rvalue);
665 return 0;
666 }
667
668 if (sd_id128_is_null(t)) {
669 log_syntax(unit, LOG_WARNING, filename, line, 0, "128bit ID/UUID is all 0, ignoring: %s", rvalue);
670 return 0;
671 }
12963533
TH
672
673 *result = t;
674 return 0;
675}
676
f757855e
LP
677int config_parse_tristate(
678 const char* unit,
679 const char *filename,
680 unsigned line,
681 const char *section,
682 unsigned section_line,
683 const char *lvalue,
684 int ltype,
685 const char *rvalue,
686 void *data,
687 void *userdata) {
688
689 int k, *t = data;
690
691 assert(filename);
692 assert(lvalue);
693 assert(rvalue);
694 assert(data);
695
696 /* A tristate is pretty much a boolean, except that it can
697 * also take the special value -1, indicating "uninitialized",
698 * much like NULL is for a pointer type. */
699
700 k = parse_boolean(rvalue);
701 if (k < 0) {
d96edb2c 702 log_syntax(unit, LOG_WARNING, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
f757855e
LP
703 return 0;
704 }
705
fec5929f 706 *t = k;
f757855e
LP
707 return 0;
708}
709
8f2665a4
LP
710int config_parse_string(
711 const char *unit,
712 const char *filename,
713 unsigned line,
714 const char *section,
715 unsigned section_line,
716 const char *lvalue,
717 int ltype,
718 const char *rvalue,
719 void *data,
720 void *userdata) {
721
5a4ff988 722 char **s = data;
ed5bcfbe
LP
723
724 assert(filename);
725 assert(lvalue);
726 assert(rvalue);
727 assert(data);
728
5a4ff988
LP
729 if (free_and_strdup(s, empty_to_null(rvalue)) < 0)
730 return log_oom();
8f2665a4 731
ed5bcfbe
LP
732 return 0;
733}
57d42a5f 734
8f2665a4
LP
735int config_parse_path(
736 const char *unit,
737 const char *filename,
738 unsigned line,
739 const char *section,
740 unsigned section_line,
741 const char *lvalue,
742 int ltype,
743 const char *rvalue,
744 void *data,
745 void *userdata) {
034c6ed7 746
c0d72c43 747 _cleanup_free_ char *n = NULL;
2c75fb73 748 bool fatal = ltype;
c0d72c43 749 char **s = data;
cd4f53c5 750 int r;
034c6ed7
LP
751
752 assert(filename);
753 assert(lvalue);
754 assert(rvalue);
755 assert(data);
756
8e7b5bd0 757 if (isempty(rvalue))
0fe50629 758 goto finalize;
0fe50629 759
7f110ff9
LP
760 n = strdup(rvalue);
761 if (!n)
74051b9b 762 return log_oom();
034c6ed7 763
cd4f53c5
YW
764 r = path_simplify_and_warn(n, PATH_CHECK_ABSOLUTE | (fatal ? PATH_CHECK_FATAL : 0), unit, filename, line, lvalue);
765 if (r < 0)
766 return fatal ? -ENOEXEC : 0;
01f78473 767
0fe50629 768finalize:
8e7b5bd0 769 return free_and_replace(*s, n);
034c6ed7 770}
57d42a5f 771
8249bb72
LP
772int config_parse_strv(
773 const char *unit,
774 const char *filename,
775 unsigned line,
776 const char *section,
777 unsigned section_line,
778 const char *lvalue,
779 int ltype,
780 const char *rvalue,
781 void *data,
782 void *userdata) {
57d42a5f 783
a2a5291b 784 char ***sv = data;
00d0fd06 785 int r;
57d42a5f
LP
786
787 assert(filename);
788 assert(lvalue);
789 assert(rvalue);
790 assert(data);
791
74051b9b 792 if (isempty(rvalue)) {
8249bb72 793 *sv = strv_free(*sv);
853b8397 794 return 0;
74051b9b
LP
795 }
796
d96edb2c 797 for (const char *p = rvalue;;) {
34f253f0 798 char *word = NULL;
00d0fd06 799
d96edb2c 800 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
34f253f0 801 if (r == 0)
d96edb2c 802 return 0;
34f253f0 803 if (r == -ENOMEM)
853b8397 804 return log_oom();
34f253f0 805 if (r < 0) {
d96edb2c
YW
806 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
807 return 0;
34f253f0 808 }
853b8397 809
34f253f0 810 r = strv_consume(sv, word);
853b8397
LP
811 if (r < 0)
812 return log_oom();
7f110ff9 813 }
57d42a5f 814}
15ae422b 815
1e35c5ab
RP
816int config_parse_warn_compat(
817 const char *unit,
818 const char *filename,
819 unsigned line,
820 const char *section,
821 unsigned section_line,
822 const char *lvalue,
823 int ltype,
824 const char *rvalue,
825 void *data,
826 void *userdata) {
7ef7e15b 827
1e35c5ab
RP
828 Disabled reason = ltype;
829
830 switch(reason) {
7ef7e15b 831
1e35c5ab
RP
832 case DISABLED_CONFIGURATION:
833 log_syntax(unit, LOG_DEBUG, filename, line, 0,
834 "Support for option %s= has been disabled at compile time and it is ignored", lvalue);
835 break;
7ef7e15b 836
1e35c5ab
RP
837 case DISABLED_LEGACY:
838 log_syntax(unit, LOG_INFO, filename, line, 0,
839 "Support for option %s= has been removed and it is ignored", lvalue);
840 break;
7ef7e15b 841
1e35c5ab
RP
842 case DISABLED_EXPERIMENTAL:
843 log_syntax(unit, LOG_INFO, filename, line, 0,
844 "Support for option %s= has not yet been enabled and it is ignored", lvalue);
845 break;
7ef7e15b 846 }
1e35c5ab
RP
847
848 return 0;
849}
850
ca37242e
LP
851int config_parse_log_facility(
852 const char *unit,
853 const char *filename,
854 unsigned line,
855 const char *section,
856 unsigned section_line,
857 const char *lvalue,
858 int ltype,
859 const char *rvalue,
860 void *data,
861 void *userdata) {
213ba152 862
213ba152
LP
863 int *o = data, x;
864
865 assert(filename);
866 assert(lvalue);
867 assert(rvalue);
868 assert(data);
869
870 x = log_facility_unshifted_from_string(rvalue);
871 if (x < 0) {
d96edb2c 872 log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse log facility, ignoring: %s", rvalue);
213ba152
LP
873 return 0;
874 }
875
876 *o = (x << 3) | LOG_PRI(*o);
877
878 return 0;
879}
880
ca37242e
LP
881int config_parse_log_level(
882 const char *unit,
883 const char *filename,
884 unsigned line,
885 const char *section,
886 unsigned section_line,
887 const char *lvalue,
888 int ltype,
889 const char *rvalue,
890 void *data,
891 void *userdata) {
213ba152 892
213ba152
LP
893 int *o = data, x;
894
895 assert(filename);
896 assert(lvalue);
897 assert(rvalue);
898 assert(data);
899
900 x = log_level_from_string(rvalue);
901 if (x < 0) {
d96edb2c 902 log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse log level, ignoring: %s", rvalue);
213ba152
LP
903 return 0;
904 }
905
d3070fbd
LP
906 if (*o < 0) /* if it wasn't initialized so far, assume zero facility */
907 *o = x;
908 else
909 *o = (*o & LOG_FACMASK) | x;
910
213ba152
LP
911 return 0;
912}
f757855e
LP
913
914int config_parse_signal(
915 const char *unit,
916 const char *filename,
917 unsigned line,
918 const char *section,
919 unsigned section_line,
920 const char *lvalue,
921 int ltype,
922 const char *rvalue,
923 void *data,
924 void *userdata) {
925
926 int *sig = data, r;
927
928 assert(filename);
929 assert(lvalue);
930 assert(rvalue);
931 assert(sig);
932
29a3db75 933 r = signal_from_string(rvalue);
f757855e 934 if (r <= 0) {
d96edb2c 935 log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse signal name, ignoring: %s", rvalue);
f757855e
LP
936 return 0;
937 }
938
939 *sig = r;
940 return 0;
941}
942
943int config_parse_personality(
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 unsigned long *personality = data, p;
956
957 assert(filename);
958 assert(lvalue);
959 assert(rvalue);
960 assert(personality);
961
40fdd636
LP
962 if (isempty(rvalue))
963 p = PERSONALITY_INVALID;
964 else {
965 p = personality_from_string(rvalue);
966 if (p == PERSONALITY_INVALID) {
d96edb2c 967 log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse personality, ignoring: %s", rvalue);
40fdd636
LP
968 return 0;
969 }
f757855e
LP
970 }
971
972 *personality = p;
973 return 0;
974}
d31645ad
LP
975
976int config_parse_ifname(
977 const char *unit,
978 const char *filename,
979 unsigned line,
980 const char *section,
981 unsigned section_line,
982 const char *lvalue,
983 int ltype,
984 const char *rvalue,
985 void *data,
986 void *userdata) {
987
988 char **s = data;
989 int r;
990
991 assert(filename);
992 assert(lvalue);
993 assert(rvalue);
994 assert(data);
995
996 if (isempty(rvalue)) {
997 *s = mfree(*s);
998 return 0;
999 }
1000
1001 if (!ifname_valid(rvalue)) {
d96edb2c 1002 log_syntax(unit, LOG_WARNING, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue);
d31645ad
LP
1003 return 0;
1004 }
1005
1006 r = free_and_strdup(s, rvalue);
1007 if (r < 0)
1008 return log_oom();
1009
1010 return 0;
1011}
177d0b20 1012
a5053a15
YW
1013int config_parse_ifnames(
1014 const char *unit,
1015 const char *filename,
1016 unsigned line,
1017 const char *section,
1018 unsigned section_line,
1019 const char *lvalue,
1020 int ltype,
1021 const char *rvalue,
1022 void *data,
1023 void *userdata) {
1024
1025 _cleanup_strv_free_ char **names = NULL;
1026 char ***s = data;
a5053a15
YW
1027 int r;
1028
1029 assert(filename);
1030 assert(lvalue);
1031 assert(rvalue);
1032 assert(data);
1033
1034 if (isempty(rvalue)) {
1035 *s = strv_free(*s);
1036 return 0;
1037 }
1038
d96edb2c 1039 for (const char *p = rvalue;;) {
a5053a15
YW
1040 _cleanup_free_ char *word = NULL;
1041
1042 r = extract_first_word(&p, &word, NULL, 0);
d96edb2c
YW
1043 if (r == -ENOMEM)
1044 return log_oom();
a5053a15 1045 if (r < 0) {
d96edb2c 1046 log_syntax(unit, LOG_WARNING, filename, line, r,
a5053a15
YW
1047 "Failed to extract interface name, ignoring assignment: %s",
1048 rvalue);
1049 return 0;
1050 }
1051 if (r == 0)
1052 break;
1053
1054 if (!ifname_valid_full(word, ltype)) {
d96edb2c 1055 log_syntax(unit, LOG_WARNING, filename, line, 0,
a5053a15
YW
1056 "Interface name is not valid or too long, ignoring assignment: %s",
1057 word);
1058 continue;
1059 }
1060
1061 r = strv_consume(&names, TAKE_PTR(word));
1062 if (r < 0)
1063 return log_oom();
1064 }
1065
1066 r = strv_extend_strv(s, names, true);
1067 if (r < 0)
1068 return log_oom();
1069
1070 return 0;
1071}
1072
177d0b20
SS
1073int config_parse_ip_port(
1074 const char *unit,
1075 const char *filename,
1076 unsigned line,
1077 const char *section,
1078 unsigned section_line,
1079 const char *lvalue,
1080 int ltype,
1081 const char *rvalue,
1082 void *data,
1083 void *userdata) {
1084
1085 uint16_t *s = data;
1086 uint16_t port;
1087 int r;
1088
1089 assert(filename);
1090 assert(lvalue);
1091 assert(rvalue);
1092 assert(data);
1093
1094 if (isempty(rvalue)) {
1095 *s = 0;
1096 return 0;
1097 }
1098
1099 r = parse_ip_port(rvalue, &port);
1100 if (r < 0) {
d96edb2c 1101 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse port '%s'.", rvalue);
177d0b20
SS
1102 return 0;
1103 }
1104
1105 *s = port;
1106
1107 return 0;
1108}
9ecdba8c 1109
79138a38
LP
1110int config_parse_mtu(
1111 const char *unit,
1112 const char *filename,
1113 unsigned line,
1114 const char *section,
1115 unsigned section_line,
1116 const char *lvalue,
1117 int ltype,
1118 const char *rvalue,
1119 void *data,
1120 void *userdata) {
1121
1122 uint32_t *mtu = data;
1123 int r;
1124
1125 assert(rvalue);
1126 assert(mtu);
1127
1128 r = parse_mtu(ltype, rvalue, mtu);
1129 if (r == -ERANGE) {
d96edb2c 1130 log_syntax(unit, LOG_WARNING, filename, line, r,
79138a38
LP
1131 "Maximum transfer unit (MTU) value out of range. Permitted range is %" PRIu32 "…%" PRIu32 ", ignoring: %s",
1132 (uint32_t) (ltype == AF_INET6 ? IPV6_MIN_MTU : IPV4_MIN_MTU), (uint32_t) UINT32_MAX,
1133 rvalue);
1134 return 0;
1135 }
1136 if (r < 0) {
d96edb2c 1137 log_syntax(unit, LOG_WARNING, filename, line, r,
79138a38
LP
1138 "Failed to parse MTU value '%s', ignoring: %m", rvalue);
1139 return 0;
1140 }
1141
1142 return 0;
1143}
4f424df7
LP
1144
1145int config_parse_rlimit(
1146 const char *unit,
1147 const char *filename,
1148 unsigned line,
1149 const char *section,
1150 unsigned section_line,
1151 const char *lvalue,
1152 int ltype,
1153 const char *rvalue,
1154 void *data,
1155 void *userdata) {
1156
1157 struct rlimit **rl = data, d = {};
1158 int r;
1159
1160 assert(rvalue);
1161 assert(rl);
1162
1163 r = rlimit_parse(ltype, rvalue, &d);
1164 if (r == -EILSEQ) {
1165 log_syntax(unit, LOG_WARNING, filename, line, r, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue);
1166 return 0;
1167 }
1168 if (r < 0) {
d96edb2c 1169 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
4f424df7
LP
1170 return 0;
1171 }
1172
1173 if (rl[ltype])
1174 *rl[ltype] = d;
1175 else {
1176 rl[ltype] = newdup(struct rlimit, &d, 1);
1177 if (!rl[ltype])
1178 return log_oom();
1179 }
1180
1181 return 0;
1182}
c07b23ca
MKB
1183
1184int config_parse_permille(const char* unit,
1185 const char *filename,
1186 unsigned line,
1187 const char *section,
1188 unsigned section_line,
1189 const char *lvalue,
1190 int ltype,
1191 const char *rvalue,
1192 void *data,
1193 void *userdata) {
1194
1195 unsigned *permille = data;
1196 int r;
1197
1198 assert(filename);
1199 assert(lvalue);
1200 assert(rvalue);
1201 assert(permille);
1202
1203 r = parse_permille(rvalue);
1204 if (r < 0) {
d96edb2c 1205 log_syntax(unit, LOG_WARNING, filename, line, r,
c07b23ca
MKB
1206 "Failed to parse permille value, ignoring: %s", rvalue);
1207 return 0;
1208 }
1209
1210 *permille = (unsigned) r;
1211
1212 return 0;
1213}
4df4df5b
RF
1214
1215int config_parse_vlanprotocol(const char* unit,
1216 const char *filename,
1217 unsigned line,
1218 const char *section,
1219 unsigned section_line,
1220 const char *lvalue,
1221 int ltype,
1222 const char *rvalue,
1223 void *data,
1224 void *userdata) {
1225 int *vlan_protocol = data;
1226 assert(filename);
1227 assert(lvalue);
1228
1229 if (isempty(rvalue)) {
1230 *vlan_protocol = -1;
1231 return 0;
1232 }
1233
1234 if (STR_IN_SET(rvalue, "802.1ad", "802.1AD"))
1235 *vlan_protocol = ETH_P_8021AD;
1236 else if (STR_IN_SET(rvalue, "802.1q", "802.1Q"))
1237 *vlan_protocol = ETH_P_8021Q;
1238 else {
d96edb2c 1239 log_syntax(unit, LOG_WARNING, filename, line, 0,
4df4df5b
RF
1240 "Failed to parse VLAN protocol value, ignoring: %s", rvalue);
1241 return 0;
1242 }
1243
1244 return 0;
1245}
9de5e321
AZ
1246
1247DEFINE_CONFIG_PARSE(config_parse_percent, parse_percent, "Failed to parse percent value");