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