]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/conf-parser.c
shared/install: Preserve escape characters for escaped unit names
[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
b41dd0d2 325 if (strchr(COMMENTS, *skip_leading_chars(buf, WHITESPACE)))
9adbfeb3
YW
326 continue;
327
9dd7ea9a 328 l = buf;
bcde742e 329 if (!(flags & CONFIG_PARSE_REFUSE_BOM)) {
e6dde451 330 char *q;
9dd7ea9a 331
e6dde451
LP
332 q = startswith(buf, UTF8_BYTE_ORDER_MARK);
333 if (q) {
334 l = q;
bcde742e 335 flags |= CONFIG_PARSE_REFUSE_BOM;
e6dde451
LP
336 }
337 }
3dab2943
LP
338
339 if (continuation) {
e6dde451 340 if (strlen(continuation) + strlen(l) > LONG_LINE_MAX) {
bcde742e 341 if (flags & CONFIG_PARSE_WARN)
e6dde451
LP
342 log_error("%s:%u: Continuation line too long", filename, line);
343 return -ENOBUFS;
344 }
345
92b5e605 346 if (!strextend(&continuation, l, NULL)) {
bcde742e 347 if (flags & CONFIG_PARSE_WARN)
36f822c4 348 log_oom();
245802dd 349 return -ENOMEM;
36f822c4 350 }
3dab2943 351
92b5e605 352 p = continuation;
3dab2943
LP
353 } else
354 p = l;
355
356 for (e = p; *e; e++) {
357 if (escaped)
358 escaped = false;
359 else if (*e == '\\')
360 escaped = true;
361 }
362
363 if (escaped) {
364 *(e-1) = ' ';
365
92b5e605 366 if (!continuation) {
f975e971 367 continuation = strdup(l);
36f822c4 368 if (!continuation) {
bcde742e 369 if (flags & CONFIG_PARSE_WARN)
36f822c4 370 log_oom();
245802dd 371 return -ENOMEM;
36f822c4 372 }
3dab2943
LP
373 }
374
375 continue;
376 }
377
e8e581bf
ZJS
378 r = parse_line(unit,
379 filename,
380 ++line,
381 sections,
382 lookup,
383 table,
bcde742e 384 flags,
e8e581bf 385 &section,
71a61510 386 &section_line,
342aea19 387 &section_ignored,
e8e581bf
ZJS
388 p,
389 userdata);
36f822c4 390 if (r < 0) {
bcde742e 391 if (flags & CONFIG_PARSE_WARN)
e6dde451 392 log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
245802dd 393 return r;
36f822c4 394 }
92b5e605
LP
395
396 continuation = mfree(continuation);
ed5bcfbe
LP
397 }
398
4f29e0db
FB
399 if (continuation) {
400 r = parse_line(unit,
401 filename,
402 ++line,
403 sections,
404 lookup,
405 table,
406 flags,
407 &section,
408 &section_line,
409 &section_ignored,
410 continuation,
411 userdata);
412 if (r < 0) {
413 if (flags & CONFIG_PARSE_WARN)
414 log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
415 return r;
4f29e0db
FB
416 }
417 }
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,
43688c49
ZJS
429 void *userdata) {
430
e8461023
JT
431 char **fn;
432 int r;
433
e8461023 434 if (conf_file) {
bcde742e 435 r = config_parse(NULL, conf_file, NULL, sections, lookup, table, flags, userdata);
e8461023
JT
436 if (r < 0)
437 return r;
438 }
439
440 STRV_FOREACH(fn, files) {
bcde742e 441 r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata);
e8461023
JT
442 if (r < 0)
443 return r;
444 }
445
446 return 0;
447}
448
23bb31aa
ZJS
449/* Parse each config file in the directories specified as nulstr. */
450int config_parse_many_nulstr(
451 const char *conf_file,
452 const char *conf_file_dirs,
453 const char *sections,
454 ConfigItemLookup lookup,
455 const void *table,
bcde742e 456 ConfigParseFlags flags,
23bb31aa
ZJS
457 void *userdata) {
458
459 _cleanup_strv_free_ char **files = NULL;
460 int r;
461
b5084605 462 r = conf_files_list_nulstr(&files, ".conf", NULL, 0, conf_file_dirs);
23bb31aa
ZJS
463 if (r < 0)
464 return r;
465
bcde742e 466 return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata);
23bb31aa
ZJS
467}
468
469/* Parse each config file in the directories specified as strv. */
470int config_parse_many(
471 const char *conf_file,
472 const char* const* conf_file_dirs,
473 const char *dropin_dirname,
474 const char *sections,
475 ConfigItemLookup lookup,
476 const void *table,
bcde742e 477 ConfigParseFlags flags,
23bb31aa
ZJS
478 void *userdata) {
479
480 _cleanup_strv_free_ char **dropin_dirs = NULL;
481 _cleanup_strv_free_ char **files = NULL;
482 const char *suffix;
483 int r;
484
485 suffix = strjoina("/", dropin_dirname);
486 r = strv_extend_strv_concat(&dropin_dirs, (char**) conf_file_dirs, suffix);
487 if (r < 0)
488 return r;
489
b5084605 490 r = conf_files_list_strv(&files, ".conf", NULL, 0, (const char* const*) dropin_dirs);
23bb31aa
ZJS
491 if (r < 0)
492 return r;
493
bcde742e 494 return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata);
23bb31aa
ZJS
495}
496
eb3491d9 497#define DEFINE_PARSER(type, vartype, conv_func) \
2d1729ca 498 DEFINE_CONFIG_PARSE_PTR(config_parse_##type, conv_func, vartype, "Failed to parse " #type " value")
94d75d64
LP
499
500DEFINE_PARSER(int, int, safe_atoi);
501DEFINE_PARSER(long, long, safe_atoli);
134e24e1 502DEFINE_PARSER(uint8, uint8_t, safe_atou8);
c7440e74 503DEFINE_PARSER(uint16, uint16_t, safe_atou16);
94d75d64
LP
504DEFINE_PARSER(uint32, uint32_t, safe_atou32);
505DEFINE_PARSER(uint64, uint64_t, safe_atou64);
506DEFINE_PARSER(unsigned, unsigned, safe_atou);
507DEFINE_PARSER(double, double, safe_atod);
508DEFINE_PARSER(nsec, nsec_t, parse_nsec);
509DEFINE_PARSER(sec, usec_t, parse_sec);
7b61ce3c 510DEFINE_PARSER(sec_def_infinity, usec_t, parse_sec_def_infinity);
94d75d64 511DEFINE_PARSER(mode, mode_t, parse_mode);
ed5bcfbe 512
5556b5fe 513int config_parse_iec_size(const char* unit,
e8e581bf
ZJS
514 const char *filename,
515 unsigned line,
516 const char *section,
71a61510 517 unsigned section_line,
e8e581bf
ZJS
518 const char *lvalue,
519 int ltype,
520 const char *rvalue,
521 void *data,
522 void *userdata) {
ed5bcfbe
LP
523
524 size_t *sz = data;
59f448cf 525 uint64_t v;
e8e581bf 526 int r;
ed5bcfbe
LP
527
528 assert(filename);
529 assert(lvalue);
530 assert(rvalue);
531 assert(data);
532
59f448cf 533 r = parse_size(rvalue, 1024, &v);
1e5f4e8b
YW
534 if (r >= 0 && (uint64_t) (size_t) v != v)
535 r = -ERANGE;
536 if (r < 0) {
537 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value '%s', ignoring: %m", rvalue);
9ba1a159
LP
538 return 0;
539 }
540
59f448cf 541 *sz = (size_t) v;
9ba1a159
LP
542 return 0;
543}
544
78f3c4bc
LP
545int config_parse_si_size(
546 const char* unit,
547 const char *filename,
548 unsigned line,
549 const char *section,
550 unsigned section_line,
551 const char *lvalue,
552 int ltype,
553 const char *rvalue,
554 void *data,
555 void *userdata) {
5556b5fe
LP
556
557 size_t *sz = data;
59f448cf 558 uint64_t v;
5556b5fe
LP
559 int r;
560
561 assert(filename);
562 assert(lvalue);
563 assert(rvalue);
564 assert(data);
565
59f448cf 566 r = parse_size(rvalue, 1000, &v);
1e5f4e8b
YW
567 if (r >= 0 && (uint64_t) (size_t) v != v)
568 r = -ERANGE;
569 if (r < 0) {
570 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value '%s', ignoring: %m", rvalue);
5556b5fe
LP
571 return 0;
572 }
573
59f448cf 574 *sz = (size_t) v;
5556b5fe
LP
575 return 0;
576}
9ba1a159 577
78f3c4bc
LP
578int config_parse_iec_uint64(
579 const char* unit,
580 const char *filename,
581 unsigned line,
582 const char *section,
583 unsigned section_line,
584 const char *lvalue,
585 int ltype,
586 const char *rvalue,
587 void *data,
588 void *userdata) {
9ba1a159 589
59f448cf 590 uint64_t *bytes = data;
e8e581bf 591 int r;
9ba1a159
LP
592
593 assert(filename);
594 assert(lvalue);
595 assert(rvalue);
596 assert(data);
597
5556b5fe 598 r = parse_size(rvalue, 1024, bytes);
e8e581bf 599 if (r < 0)
59f448cf 600 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
ed5bcfbe 601
ed5bcfbe
LP
602 return 0;
603}
604
e8e581bf
ZJS
605int config_parse_bool(const char* unit,
606 const char *filename,
607 unsigned line,
608 const char *section,
71a61510 609 unsigned section_line,
e8e581bf
ZJS
610 const char *lvalue,
611 int ltype,
612 const char *rvalue,
613 void *data,
614 void *userdata) {
ed5bcfbe
LP
615
616 int k;
617 bool *b = data;
2c75fb73 618 bool fatal = ltype;
ed5bcfbe
LP
619
620 assert(filename);
621 assert(lvalue);
622 assert(rvalue);
623 assert(data);
624
e8e581bf
ZJS
625 k = parse_boolean(rvalue);
626 if (k < 0) {
2c75fb73
ZJS
627 log_syntax(unit, LOG_ERR, filename, line, k,
628 "Failed to parse boolean value%s: %s",
629 fatal ? "" : ", ignoring", rvalue);
630 return fatal ? -ENOEXEC : 0;
ed5bcfbe
LP
631 }
632
5d904a6a 633 *b = k;
ed5bcfbe
LP
634 return 0;
635}
636
f757855e
LP
637int config_parse_tristate(
638 const char* unit,
639 const char *filename,
640 unsigned line,
641 const char *section,
642 unsigned section_line,
643 const char *lvalue,
644 int ltype,
645 const char *rvalue,
646 void *data,
647 void *userdata) {
648
649 int k, *t = data;
650
651 assert(filename);
652 assert(lvalue);
653 assert(rvalue);
654 assert(data);
655
656 /* A tristate is pretty much a boolean, except that it can
657 * also take the special value -1, indicating "uninitialized",
658 * much like NULL is for a pointer type. */
659
660 k = parse_boolean(rvalue);
661 if (k < 0) {
662 log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
663 return 0;
664 }
665
666 *t = !!k;
667 return 0;
668}
669
8f2665a4
LP
670int config_parse_string(
671 const char *unit,
672 const char *filename,
673 unsigned line,
674 const char *section,
675 unsigned section_line,
676 const char *lvalue,
677 int ltype,
678 const char *rvalue,
679 void *data,
680 void *userdata) {
681
5a4ff988 682 char **s = data;
ed5bcfbe
LP
683
684 assert(filename);
685 assert(lvalue);
686 assert(rvalue);
687 assert(data);
688
5a4ff988
LP
689 if (free_and_strdup(s, empty_to_null(rvalue)) < 0)
690 return log_oom();
8f2665a4 691
ed5bcfbe
LP
692 return 0;
693}
57d42a5f 694
8f2665a4
LP
695int config_parse_path(
696 const char *unit,
697 const char *filename,
698 unsigned line,
699 const char *section,
700 unsigned section_line,
701 const char *lvalue,
702 int ltype,
703 const char *rvalue,
704 void *data,
705 void *userdata) {
034c6ed7 706
c0d72c43 707 _cleanup_free_ char *n = NULL;
2c75fb73 708 bool fatal = ltype;
c0d72c43 709 char **s = data;
cd4f53c5 710 int r;
034c6ed7
LP
711
712 assert(filename);
713 assert(lvalue);
714 assert(rvalue);
715 assert(data);
716
8e7b5bd0 717 if (isempty(rvalue))
0fe50629 718 goto finalize;
0fe50629 719
7f110ff9
LP
720 n = strdup(rvalue);
721 if (!n)
74051b9b 722 return log_oom();
034c6ed7 723
cd4f53c5
YW
724 r = path_simplify_and_warn(n, PATH_CHECK_ABSOLUTE | (fatal ? PATH_CHECK_FATAL : 0), unit, filename, line, lvalue);
725 if (r < 0)
726 return fatal ? -ENOEXEC : 0;
01f78473 727
0fe50629 728finalize:
8e7b5bd0 729 return free_and_replace(*s, n);
034c6ed7 730}
57d42a5f 731
8249bb72
LP
732int config_parse_strv(
733 const char *unit,
734 const char *filename,
735 unsigned line,
736 const char *section,
737 unsigned section_line,
738 const char *lvalue,
739 int ltype,
740 const char *rvalue,
741 void *data,
742 void *userdata) {
57d42a5f 743
a2a5291b 744 char ***sv = data;
00d0fd06 745 int r;
57d42a5f
LP
746
747 assert(filename);
748 assert(lvalue);
749 assert(rvalue);
750 assert(data);
751
74051b9b 752 if (isempty(rvalue)) {
8249bb72 753 *sv = strv_free(*sv);
853b8397 754 return 0;
74051b9b
LP
755 }
756
34f253f0
DR
757 for (;;) {
758 char *word = NULL;
00d0fd06 759
9a82ab95 760 r = extract_first_word(&rvalue, &word, NULL, EXTRACT_QUOTES|EXTRACT_RETAIN_ESCAPE);
34f253f0
DR
761 if (r == 0)
762 break;
763 if (r == -ENOMEM)
853b8397 764 return log_oom();
34f253f0
DR
765 if (r < 0) {
766 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
767 break;
768 }
853b8397 769
34f253f0 770 r = strv_consume(sv, word);
853b8397
LP
771 if (r < 0)
772 return log_oom();
7f110ff9 773 }
57d42a5f 774
57d42a5f 775 return 0;
57d42a5f 776}
15ae422b 777
1e35c5ab
RP
778int config_parse_warn_compat(
779 const char *unit,
780 const char *filename,
781 unsigned line,
782 const char *section,
783 unsigned section_line,
784 const char *lvalue,
785 int ltype,
786 const char *rvalue,
787 void *data,
788 void *userdata) {
7ef7e15b 789
1e35c5ab
RP
790 Disabled reason = ltype;
791
792 switch(reason) {
7ef7e15b 793
1e35c5ab
RP
794 case DISABLED_CONFIGURATION:
795 log_syntax(unit, LOG_DEBUG, filename, line, 0,
796 "Support for option %s= has been disabled at compile time and it is ignored", lvalue);
797 break;
7ef7e15b 798
1e35c5ab
RP
799 case DISABLED_LEGACY:
800 log_syntax(unit, LOG_INFO, filename, line, 0,
801 "Support for option %s= has been removed and it is ignored", lvalue);
802 break;
7ef7e15b 803
1e35c5ab
RP
804 case DISABLED_EXPERIMENTAL:
805 log_syntax(unit, LOG_INFO, filename, line, 0,
806 "Support for option %s= has not yet been enabled and it is ignored", lvalue);
807 break;
7ef7e15b 808 }
1e35c5ab
RP
809
810 return 0;
811}
812
ca37242e
LP
813int config_parse_log_facility(
814 const char *unit,
815 const char *filename,
816 unsigned line,
817 const char *section,
818 unsigned section_line,
819 const char *lvalue,
820 int ltype,
821 const char *rvalue,
822 void *data,
823 void *userdata) {
213ba152 824
213ba152
LP
825 int *o = data, x;
826
827 assert(filename);
828 assert(lvalue);
829 assert(rvalue);
830 assert(data);
831
832 x = log_facility_unshifted_from_string(rvalue);
833 if (x < 0) {
12ca818f 834 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log facility, ignoring: %s", rvalue);
213ba152
LP
835 return 0;
836 }
837
838 *o = (x << 3) | LOG_PRI(*o);
839
840 return 0;
841}
842
ca37242e
LP
843int config_parse_log_level(
844 const char *unit,
845 const char *filename,
846 unsigned line,
847 const char *section,
848 unsigned section_line,
849 const char *lvalue,
850 int ltype,
851 const char *rvalue,
852 void *data,
853 void *userdata) {
213ba152 854
213ba152
LP
855 int *o = data, x;
856
857 assert(filename);
858 assert(lvalue);
859 assert(rvalue);
860 assert(data);
861
862 x = log_level_from_string(rvalue);
863 if (x < 0) {
12ca818f 864 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log level, ignoring: %s", rvalue);
213ba152
LP
865 return 0;
866 }
867
d3070fbd
LP
868 if (*o < 0) /* if it wasn't initialized so far, assume zero facility */
869 *o = x;
870 else
871 *o = (*o & LOG_FACMASK) | x;
872
213ba152
LP
873 return 0;
874}
f757855e
LP
875
876int config_parse_signal(
877 const char *unit,
878 const char *filename,
879 unsigned line,
880 const char *section,
881 unsigned section_line,
882 const char *lvalue,
883 int ltype,
884 const char *rvalue,
885 void *data,
886 void *userdata) {
887
888 int *sig = data, r;
889
890 assert(filename);
891 assert(lvalue);
892 assert(rvalue);
893 assert(sig);
894
29a3db75 895 r = signal_from_string(rvalue);
f757855e 896 if (r <= 0) {
12ca818f 897 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse signal name, ignoring: %s", rvalue);
f757855e
LP
898 return 0;
899 }
900
901 *sig = r;
902 return 0;
903}
904
905int config_parse_personality(
906 const char *unit,
907 const char *filename,
908 unsigned line,
909 const char *section,
910 unsigned section_line,
911 const char *lvalue,
912 int ltype,
913 const char *rvalue,
914 void *data,
915 void *userdata) {
916
917 unsigned long *personality = data, p;
918
919 assert(filename);
920 assert(lvalue);
921 assert(rvalue);
922 assert(personality);
923
40fdd636
LP
924 if (isempty(rvalue))
925 p = PERSONALITY_INVALID;
926 else {
927 p = personality_from_string(rvalue);
928 if (p == PERSONALITY_INVALID) {
929 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse personality, ignoring: %s", rvalue);
930 return 0;
931 }
f757855e
LP
932 }
933
934 *personality = p;
935 return 0;
936}
d31645ad
LP
937
938int config_parse_ifname(
939 const char *unit,
940 const char *filename,
941 unsigned line,
942 const char *section,
943 unsigned section_line,
944 const char *lvalue,
945 int ltype,
946 const char *rvalue,
947 void *data,
948 void *userdata) {
949
950 char **s = data;
951 int r;
952
953 assert(filename);
954 assert(lvalue);
955 assert(rvalue);
956 assert(data);
957
958 if (isempty(rvalue)) {
959 *s = mfree(*s);
960 return 0;
961 }
962
963 if (!ifname_valid(rvalue)) {
964 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue);
965 return 0;
966 }
967
968 r = free_and_strdup(s, rvalue);
969 if (r < 0)
970 return log_oom();
971
972 return 0;
973}
177d0b20
SS
974
975int config_parse_ip_port(
976 const char *unit,
977 const char *filename,
978 unsigned line,
979 const char *section,
980 unsigned section_line,
981 const char *lvalue,
982 int ltype,
983 const char *rvalue,
984 void *data,
985 void *userdata) {
986
987 uint16_t *s = data;
988 uint16_t port;
989 int r;
990
991 assert(filename);
992 assert(lvalue);
993 assert(rvalue);
994 assert(data);
995
996 if (isempty(rvalue)) {
997 *s = 0;
998 return 0;
999 }
1000
1001 r = parse_ip_port(rvalue, &port);
1002 if (r < 0) {
1003 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse port '%s'.", rvalue);
1004 return 0;
1005 }
1006
1007 *s = port;
1008
1009 return 0;
1010}
9ecdba8c 1011
79138a38
LP
1012int config_parse_mtu(
1013 const char *unit,
1014 const char *filename,
1015 unsigned line,
1016 const char *section,
1017 unsigned section_line,
1018 const char *lvalue,
1019 int ltype,
1020 const char *rvalue,
1021 void *data,
1022 void *userdata) {
1023
1024 uint32_t *mtu = data;
1025 int r;
1026
1027 assert(rvalue);
1028 assert(mtu);
1029
1030 r = parse_mtu(ltype, rvalue, mtu);
1031 if (r == -ERANGE) {
1032 log_syntax(unit, LOG_ERR, filename, line, r,
1033 "Maximum transfer unit (MTU) value out of range. Permitted range is %" PRIu32 "…%" PRIu32 ", ignoring: %s",
1034 (uint32_t) (ltype == AF_INET6 ? IPV6_MIN_MTU : IPV4_MIN_MTU), (uint32_t) UINT32_MAX,
1035 rvalue);
1036 return 0;
1037 }
1038 if (r < 0) {
1039 log_syntax(unit, LOG_ERR, filename, line, r,
1040 "Failed to parse MTU value '%s', ignoring: %m", rvalue);
1041 return 0;
1042 }
1043
1044 return 0;
1045}
4f424df7
LP
1046
1047int config_parse_rlimit(
1048 const char *unit,
1049 const char *filename,
1050 unsigned line,
1051 const char *section,
1052 unsigned section_line,
1053 const char *lvalue,
1054 int ltype,
1055 const char *rvalue,
1056 void *data,
1057 void *userdata) {
1058
1059 struct rlimit **rl = data, d = {};
1060 int r;
1061
1062 assert(rvalue);
1063 assert(rl);
1064
1065 r = rlimit_parse(ltype, rvalue, &d);
1066 if (r == -EILSEQ) {
1067 log_syntax(unit, LOG_WARNING, filename, line, r, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue);
1068 return 0;
1069 }
1070 if (r < 0) {
1071 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
1072 return 0;
1073 }
1074
1075 if (rl[ltype])
1076 *rl[ltype] = d;
1077 else {
1078 rl[ltype] = newdup(struct rlimit, &d, 1);
1079 if (!rl[ltype])
1080 return log_oom();
1081 }
1082
1083 return 0;
1084}
c07b23ca
MKB
1085
1086int config_parse_permille(const char* unit,
1087 const char *filename,
1088 unsigned line,
1089 const char *section,
1090 unsigned section_line,
1091 const char *lvalue,
1092 int ltype,
1093 const char *rvalue,
1094 void *data,
1095 void *userdata) {
1096
1097 unsigned *permille = data;
1098 int r;
1099
1100 assert(filename);
1101 assert(lvalue);
1102 assert(rvalue);
1103 assert(permille);
1104
1105 r = parse_permille(rvalue);
1106 if (r < 0) {
1107 log_syntax(unit, LOG_ERR, filename, line, r,
1108 "Failed to parse permille value, ignoring: %s", rvalue);
1109 return 0;
1110 }
1111
1112 *permille = (unsigned) r;
1113
1114 return 0;
1115}