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