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