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