]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/conf-parser.c
Merge pull request #7154 from keszybz/bootspec
[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
6
7 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
a7334b09
LP
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 15 Lesser General Public License for more details.
a7334b09 16
5430f7f2 17 You should have received a copy of the GNU Lesser General Public License
a7334b09
LP
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
ed5bcfbe 21#include <errno.h>
a8fbdf54
TA
22#include <limits.h>
23#include <stdint.h>
07630cea 24#include <stdio.h>
ed5bcfbe 25#include <stdlib.h>
07630cea 26#include <string.h>
a8fbdf54 27#include <sys/types.h>
07630cea 28
b5efdb8a 29#include "alloc-util.h"
e8461023 30#include "conf-files.h"
6bedfcbb 31#include "conf-parser.h"
e6dde451 32#include "def.h"
a8fbdf54 33#include "extract-word.h"
6bedfcbb 34#include "fd-util.h"
e6dde451 35#include "fileio.h"
f4f15635 36#include "fs-util.h"
16354eff 37#include "log.h"
07630cea 38#include "macro.h"
6bedfcbb 39#include "parse-util.h"
9eb977db 40#include "path-util.h"
7b3e062c 41#include "process-util.h"
f757855e 42#include "signal-util.h"
d31645ad 43#include "socket-util.h"
07630cea
LP
44#include "string-util.h"
45#include "strv.h"
7b3e062c 46#include "syslog-util.h"
a8fbdf54 47#include "time-util.h"
07630cea 48#include "utf8.h"
e8e581bf 49
f975e971 50int config_item_table_lookup(
e9f3d2d5 51 const void *table,
ed5bcfbe 52 const char *section,
ed5bcfbe 53 const char *lvalue,
f975e971
LP
54 ConfigParserCallback *func,
55 int *ltype,
56 void **data,
ed5bcfbe
LP
57 void *userdata) {
58
e9f3d2d5 59 const ConfigTableItem *t;
f975e971
LP
60
61 assert(table);
ed5bcfbe 62 assert(lvalue);
f975e971
LP
63 assert(func);
64 assert(ltype);
65 assert(data);
ed5bcfbe 66
f975e971 67 for (t = table; t->lvalue; t++) {
ed5bcfbe 68
f975e971 69 if (!streq(lvalue, t->lvalue))
ed5bcfbe
LP
70 continue;
71
f975e971 72 if (!streq_ptr(section, t->section))
ed5bcfbe
LP
73 continue;
74
f975e971
LP
75 *func = t->parse;
76 *ltype = t->ltype;
77 *data = t->data;
78 return 1;
79 }
ed5bcfbe 80
f975e971
LP
81 return 0;
82}
10e87ee7 83
f975e971 84int config_item_perf_lookup(
e9f3d2d5 85 const void *table,
f975e971
LP
86 const char *section,
87 const char *lvalue,
88 ConfigParserCallback *func,
89 int *ltype,
90 void **data,
91 void *userdata) {
92
93 ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
94 const ConfigPerfItem *p;
95
96 assert(table);
97 assert(lvalue);
98 assert(func);
99 assert(ltype);
100 assert(data);
101
102 if (!section)
103 p = lookup(lvalue, strlen(lvalue));
104 else {
105 char *key;
106
605405c6 107 key = strjoin(section, ".", lvalue);
44d91056 108 if (!key)
f975e971
LP
109 return -ENOMEM;
110
111 p = lookup(key, strlen(key));
112 free(key);
ed5bcfbe
LP
113 }
114
f975e971
LP
115 if (!p)
116 return 0;
117
118 *func = p->parse;
119 *ltype = p->ltype;
120 *data = (uint8_t*) userdata + p->offset;
121 return 1;
122}
123
124/* Run the user supplied parser for an assignment */
bcde742e
LP
125static int next_assignment(
126 const char *unit,
127 const char *filename,
128 unsigned line,
129 ConfigItemLookup lookup,
130 const void *table,
131 const char *section,
132 unsigned section_line,
133 const char *lvalue,
134 const char *rvalue,
135 ConfigParseFlags flags,
136 void *userdata) {
f975e971
LP
137
138 ConfigParserCallback func = NULL;
139 int ltype = 0;
140 void *data = NULL;
141 int r;
142
143 assert(filename);
144 assert(line > 0);
145 assert(lookup);
146 assert(lvalue);
147 assert(rvalue);
148
149 r = lookup(table, section, lvalue, &func, &ltype, &data, userdata);
150 if (r < 0)
151 return r;
152
d937fbbd
LP
153 if (r > 0) {
154 if (func)
71a61510
TG
155 return func(unit, filename, line, section, section_line,
156 lvalue, ltype, rvalue, data, userdata);
d937fbbd
LP
157
158 return 0;
159 }
f975e971 160
46205bb6 161 /* Warn about unknown non-extension fields. */
bcde742e 162 if (!(flags & CONFIG_PARSE_RELAXED) && !startswith(lvalue, "X-"))
12ca818f 163 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown lvalue '%s' in section '%s'", lvalue, section);
46205bb6 164
f1857be0 165 return 0;
ed5bcfbe
LP
166}
167
ed5bcfbe 168/* Parse a variable assignment line */
bcde742e
LP
169static int parse_line(
170 const char* unit,
171 const char *filename,
172 unsigned line,
173 const char *sections,
174 ConfigItemLookup lookup,
175 const void *table,
176 ConfigParseFlags flags,
177 char **section,
178 unsigned *section_line,
179 bool *section_ignored,
180 char *l,
181 void *userdata) {
f975e971 182
b2aa81ef 183 char *e;
ed5bcfbe 184
f975e971
LP
185 assert(filename);
186 assert(line > 0);
187 assert(lookup);
188 assert(l);
189
b2aa81ef 190 l = strstrip(l);
b2aa81ef 191 if (!*l)
ed5bcfbe 192 return 0;
1ea86b18 193
d3b6d0c2 194 if (strchr(COMMENTS "\n", *l))
1ea86b18 195 return 0;
ed5bcfbe 196
b2aa81ef 197 if (startswith(l, ".include ")) {
db5c0122
LP
198 _cleanup_free_ char *fn = NULL;
199
b8e7a47b
LP
200 /* .includes are a bad idea, we only support them here
201 * for historical reasons. They create cyclic include
202 * problems and make it difficult to detect
203 * configuration file changes with an easy
204 * stat(). Better approaches, such as .d/ drop-in
205 * snippets exist.
206 *
207 * Support for them should be eventually removed. */
208
bcde742e 209 if (!(flags & CONFIG_PARSE_ALLOW_INCLUDE)) {
12ca818f 210 log_syntax(unit, LOG_ERR, filename, line, 0, ".include not allowed here. Ignoring.");
db5c0122
LP
211 return 0;
212 }
ed5bcfbe 213
f975e971
LP
214 fn = file_in_same_dir(filename, strstrip(l+9));
215 if (!fn)
b2aa81ef 216 return -ENOMEM;
ed5bcfbe 217
bcde742e 218 return config_parse(unit, fn, NULL, sections, lookup, table, flags, userdata);
ed5bcfbe
LP
219 }
220
b2aa81ef 221 if (*l == '[') {
ed5bcfbe
LP
222 size_t k;
223 char *n;
224
b2aa81ef 225 k = strlen(l);
ed5bcfbe
LP
226 assert(k > 0);
227
b2aa81ef 228 if (l[k-1] != ']') {
12ca818f 229 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid section header '%s'", l);
ed5bcfbe
LP
230 return -EBADMSG;
231 }
232
f975e971
LP
233 n = strndup(l+1, k-2);
234 if (!n)
ed5bcfbe
LP
235 return -ENOMEM;
236
f975e971 237 if (sections && !nulstr_contains(sections, n)) {
42f4e3c4 238
bcde742e 239 if (!(flags & CONFIG_PARSE_RELAXED) && !startswith(n, "X-"))
12ca818f 240 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown section '%s'. Ignoring.", n);
f975e971
LP
241
242 free(n);
a1e58e8e 243 *section = mfree(*section);
71a61510 244 *section_line = 0;
342aea19 245 *section_ignored = true;
f975e971
LP
246 } else {
247 free(*section);
248 *section = n;
71a61510 249 *section_line = line;
342aea19 250 *section_ignored = false;
f975e971 251 }
ed5bcfbe
LP
252
253 return 0;
254 }
255
62f168a0
LP
256 if (sections && !*section) {
257
bcde742e 258 if (!(flags & CONFIG_PARSE_RELAXED) && !*section_ignored)
12ca818f 259 log_syntax(unit, LOG_WARNING, filename, line, 0, "Assignment outside of section. Ignoring.");
62f168a0 260
10e87ee7 261 return 0;
62f168a0 262 }
10e87ee7 263
f975e971
LP
264 e = strchr(l, '=');
265 if (!e) {
12ca818f
LP
266 log_syntax(unit, LOG_WARNING, filename, line, 0, "Missing '='.");
267 return -EINVAL;
ed5bcfbe
LP
268 }
269
270 *e = 0;
271 e++;
272
e8e581bf
ZJS
273 return next_assignment(unit,
274 filename,
275 line,
276 lookup,
277 table,
278 *section,
71a61510 279 *section_line,
e8e581bf
ZJS
280 strstrip(l),
281 strstrip(e),
bcde742e 282 flags,
e8e581bf 283 userdata);
ed5bcfbe
LP
284}
285
286/* Go through the file and parse each line */
e8e581bf
ZJS
287int config_parse(const char *unit,
288 const char *filename,
289 FILE *f,
290 const char *sections,
291 ConfigItemLookup lookup,
e9f3d2d5 292 const void *table,
bcde742e 293 ConfigParseFlags flags,
e8e581bf 294 void *userdata) {
f975e971 295
7fd1b19b
HH
296 _cleanup_free_ char *section = NULL, *continuation = NULL;
297 _cleanup_fclose_ FILE *ours = NULL;
71a61510 298 unsigned line = 0, section_line = 0;
bcde742e 299 bool section_ignored = false;
ed5bcfbe
LP
300 int r;
301
302 assert(filename);
f975e971 303 assert(lookup);
ed5bcfbe 304
87f0e418 305 if (!f) {
245802dd 306 f = ours = fopen(filename, "re");
f975e971 307 if (!f) {
36f822c4
ZJS
308 /* Only log on request, except for ENOENT,
309 * since we return 0 to the caller. */
bcde742e 310 if ((flags & CONFIG_PARSE_WARN) || errno == ENOENT)
36f822c4
ZJS
311 log_full(errno == ENOENT ? LOG_DEBUG : LOG_ERR,
312 "Failed to open configuration file '%s': %m", filename);
9f43a07f 313 return errno == ENOENT ? 0 : -errno;
87f0e418 314 }
ed5bcfbe
LP
315 }
316
fdb9161c
LP
317 fd_warn_permissions(filename, fileno(f));
318
9dd7ea9a 319 for (;;) {
e6dde451 320 _cleanup_free_ char *buf = NULL;
3dab2943 321 bool escaped = false;
92b5e605 322 char *l, *p, *e;
ed5bcfbe 323
e6dde451
LP
324 r = read_line(f, LONG_LINE_MAX, &buf);
325 if (r == 0)
326 break;
327 if (r == -ENOBUFS) {
bcde742e 328 if (flags & CONFIG_PARSE_WARN)
e6dde451
LP
329 log_error_errno(r, "%s:%u: Line too long", filename, line);
330
331 return r;
332 }
333 if (r < 0) {
bcde742e 334 if (CONFIG_PARSE_WARN)
e6dde451 335 log_error_errno(r, "%s:%u: Error while reading configuration file: %m", filename, line);
ed5bcfbe 336
e6dde451 337 return r;
ed5bcfbe
LP
338 }
339
9dd7ea9a 340 l = buf;
bcde742e 341 if (!(flags & CONFIG_PARSE_REFUSE_BOM)) {
e6dde451 342 char *q;
9dd7ea9a 343
e6dde451
LP
344 q = startswith(buf, UTF8_BYTE_ORDER_MARK);
345 if (q) {
346 l = q;
bcde742e 347 flags |= CONFIG_PARSE_REFUSE_BOM;
e6dde451
LP
348 }
349 }
3dab2943
LP
350
351 if (continuation) {
e6dde451 352 if (strlen(continuation) + strlen(l) > LONG_LINE_MAX) {
bcde742e 353 if (flags & CONFIG_PARSE_WARN)
e6dde451
LP
354 log_error("%s:%u: Continuation line too long", filename, line);
355 return -ENOBUFS;
356 }
357
92b5e605 358 if (!strextend(&continuation, l, NULL)) {
bcde742e 359 if (flags & CONFIG_PARSE_WARN)
36f822c4 360 log_oom();
245802dd 361 return -ENOMEM;
36f822c4 362 }
3dab2943 363
92b5e605 364 p = continuation;
3dab2943
LP
365 } else
366 p = l;
367
368 for (e = p; *e; e++) {
369 if (escaped)
370 escaped = false;
371 else if (*e == '\\')
372 escaped = true;
373 }
374
375 if (escaped) {
376 *(e-1) = ' ';
377
92b5e605 378 if (!continuation) {
f975e971 379 continuation = strdup(l);
36f822c4 380 if (!continuation) {
bcde742e 381 if (flags & CONFIG_PARSE_WARN)
36f822c4 382 log_oom();
245802dd 383 return -ENOMEM;
36f822c4 384 }
3dab2943
LP
385 }
386
387 continue;
388 }
389
e8e581bf
ZJS
390 r = parse_line(unit,
391 filename,
392 ++line,
393 sections,
394 lookup,
395 table,
bcde742e 396 flags,
e8e581bf 397 &section,
71a61510 398 &section_line,
342aea19 399 &section_ignored,
e8e581bf
ZJS
400 p,
401 userdata);
36f822c4 402 if (r < 0) {
bcde742e 403 if (flags & CONFIG_PARSE_WARN)
e6dde451 404 log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
245802dd 405 return r;
92b5e605 406
36f822c4 407 }
92b5e605
LP
408
409 continuation = mfree(continuation);
ed5bcfbe
LP
410 }
411
245802dd 412 return 0;
ed5bcfbe
LP
413}
414
23bb31aa 415static int config_parse_many_files(
43688c49 416 const char *conf_file,
23bb31aa 417 char **files,
43688c49
ZJS
418 const char *sections,
419 ConfigItemLookup lookup,
420 const void *table,
bcde742e 421 ConfigParseFlags flags,
43688c49
ZJS
422 void *userdata) {
423
e8461023
JT
424 char **fn;
425 int r;
426
e8461023 427 if (conf_file) {
bcde742e 428 r = config_parse(NULL, conf_file, NULL, sections, lookup, table, flags, userdata);
e8461023
JT
429 if (r < 0)
430 return r;
431 }
432
433 STRV_FOREACH(fn, files) {
bcde742e 434 r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata);
e8461023
JT
435 if (r < 0)
436 return r;
437 }
438
439 return 0;
440}
441
23bb31aa
ZJS
442/* Parse each config file in the directories specified as nulstr. */
443int config_parse_many_nulstr(
444 const char *conf_file,
445 const char *conf_file_dirs,
446 const char *sections,
447 ConfigItemLookup lookup,
448 const void *table,
bcde742e 449 ConfigParseFlags flags,
23bb31aa
ZJS
450 void *userdata) {
451
452 _cleanup_strv_free_ char **files = NULL;
453 int r;
454
b5084605 455 r = conf_files_list_nulstr(&files, ".conf", NULL, 0, conf_file_dirs);
23bb31aa
ZJS
456 if (r < 0)
457 return r;
458
bcde742e 459 return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata);
23bb31aa
ZJS
460}
461
462/* Parse each config file in the directories specified as strv. */
463int config_parse_many(
464 const char *conf_file,
465 const char* const* conf_file_dirs,
466 const char *dropin_dirname,
467 const char *sections,
468 ConfigItemLookup lookup,
469 const void *table,
bcde742e 470 ConfigParseFlags flags,
23bb31aa
ZJS
471 void *userdata) {
472
473 _cleanup_strv_free_ char **dropin_dirs = NULL;
474 _cleanup_strv_free_ char **files = NULL;
475 const char *suffix;
476 int r;
477
478 suffix = strjoina("/", dropin_dirname);
479 r = strv_extend_strv_concat(&dropin_dirs, (char**) conf_file_dirs, suffix);
480 if (r < 0)
481 return r;
482
b5084605 483 r = conf_files_list_strv(&files, ".conf", NULL, 0, (const char* const*) dropin_dirs);
23bb31aa
ZJS
484 if (r < 0)
485 return r;
486
bcde742e 487 return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata);
23bb31aa
ZJS
488}
489
eb3491d9 490#define DEFINE_PARSER(type, vartype, conv_func) \
94d75d64
LP
491 int config_parse_##type( \
492 const char *unit, \
493 const char *filename, \
494 unsigned line, \
495 const char *section, \
496 unsigned section_line, \
497 const char *lvalue, \
498 int ltype, \
499 const char *rvalue, \
500 void *data, \
501 void *userdata) { \
eb3491d9
ZJS
502 \
503 vartype *i = data; \
504 int r; \
505 \
506 assert(filename); \
507 assert(lvalue); \
508 assert(rvalue); \
509 assert(data); \
510 \
511 r = conv_func(rvalue, i); \
512 if (r < 0) \
12ca818f 513 log_syntax(unit, LOG_ERR, filename, line, r, \
e8e581bf 514 "Failed to parse %s value, ignoring: %s", \
98d75800 515 #type, rvalue); \
eb3491d9
ZJS
516 \
517 return 0; \
94d75d64
LP
518 } \
519 struct __useless_struct_to_allow_trailing_semicolon__
520
521DEFINE_PARSER(int, int, safe_atoi);
522DEFINE_PARSER(long, long, safe_atoli);
134e24e1 523DEFINE_PARSER(uint8, uint8_t, safe_atou8);
c7440e74 524DEFINE_PARSER(uint16, uint16_t, safe_atou16);
94d75d64
LP
525DEFINE_PARSER(uint32, uint32_t, safe_atou32);
526DEFINE_PARSER(uint64, uint64_t, safe_atou64);
527DEFINE_PARSER(unsigned, unsigned, safe_atou);
528DEFINE_PARSER(double, double, safe_atod);
529DEFINE_PARSER(nsec, nsec_t, parse_nsec);
530DEFINE_PARSER(sec, usec_t, parse_sec);
531DEFINE_PARSER(mode, mode_t, parse_mode);
ed5bcfbe 532
5556b5fe 533int config_parse_iec_size(const char* unit,
e8e581bf
ZJS
534 const char *filename,
535 unsigned line,
536 const char *section,
71a61510 537 unsigned section_line,
e8e581bf
ZJS
538 const char *lvalue,
539 int ltype,
540 const char *rvalue,
541 void *data,
542 void *userdata) {
ed5bcfbe
LP
543
544 size_t *sz = data;
59f448cf 545 uint64_t v;
e8e581bf 546 int r;
ed5bcfbe
LP
547
548 assert(filename);
549 assert(lvalue);
550 assert(rvalue);
551 assert(data);
552
59f448cf
LP
553 r = parse_size(rvalue, 1024, &v);
554 if (r < 0 || (uint64_t) (size_t) v != v) {
12ca818f 555 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
9ba1a159
LP
556 return 0;
557 }
558
59f448cf 559 *sz = (size_t) v;
9ba1a159
LP
560 return 0;
561}
562
78f3c4bc
LP
563int config_parse_si_size(
564 const char* unit,
565 const char *filename,
566 unsigned line,
567 const char *section,
568 unsigned section_line,
569 const char *lvalue,
570 int ltype,
571 const char *rvalue,
572 void *data,
573 void *userdata) {
5556b5fe
LP
574
575 size_t *sz = data;
59f448cf 576 uint64_t v;
5556b5fe
LP
577 int r;
578
579 assert(filename);
580 assert(lvalue);
581 assert(rvalue);
582 assert(data);
583
59f448cf
LP
584 r = parse_size(rvalue, 1000, &v);
585 if (r < 0 || (uint64_t) (size_t) v != v) {
12ca818f 586 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
5556b5fe
LP
587 return 0;
588 }
589
59f448cf 590 *sz = (size_t) v;
5556b5fe
LP
591 return 0;
592}
9ba1a159 593
78f3c4bc
LP
594int config_parse_iec_uint64(
595 const char* unit,
596 const char *filename,
597 unsigned line,
598 const char *section,
599 unsigned section_line,
600 const char *lvalue,
601 int ltype,
602 const char *rvalue,
603 void *data,
604 void *userdata) {
9ba1a159 605
59f448cf 606 uint64_t *bytes = data;
e8e581bf 607 int r;
9ba1a159
LP
608
609 assert(filename);
610 assert(lvalue);
611 assert(rvalue);
612 assert(data);
613
5556b5fe 614 r = parse_size(rvalue, 1024, bytes);
e8e581bf 615 if (r < 0)
59f448cf 616 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
ed5bcfbe 617
ed5bcfbe
LP
618 return 0;
619}
620
e8e581bf
ZJS
621int config_parse_bool(const char* unit,
622 const char *filename,
623 unsigned line,
624 const char *section,
71a61510 625 unsigned section_line,
e8e581bf
ZJS
626 const char *lvalue,
627 int ltype,
628 const char *rvalue,
629 void *data,
630 void *userdata) {
ed5bcfbe
LP
631
632 int k;
633 bool *b = data;
2c75fb73 634 bool fatal = ltype;
ed5bcfbe
LP
635
636 assert(filename);
637 assert(lvalue);
638 assert(rvalue);
639 assert(data);
640
e8e581bf
ZJS
641 k = parse_boolean(rvalue);
642 if (k < 0) {
2c75fb73
ZJS
643 log_syntax(unit, LOG_ERR, filename, line, k,
644 "Failed to parse boolean value%s: %s",
645 fatal ? "" : ", ignoring", rvalue);
646 return fatal ? -ENOEXEC : 0;
ed5bcfbe
LP
647 }
648
649 *b = !!k;
650 return 0;
651}
652
f757855e
LP
653int config_parse_tristate(
654 const char* unit,
655 const char *filename,
656 unsigned line,
657 const char *section,
658 unsigned section_line,
659 const char *lvalue,
660 int ltype,
661 const char *rvalue,
662 void *data,
663 void *userdata) {
664
665 int k, *t = data;
666
667 assert(filename);
668 assert(lvalue);
669 assert(rvalue);
670 assert(data);
671
672 /* A tristate is pretty much a boolean, except that it can
673 * also take the special value -1, indicating "uninitialized",
674 * much like NULL is for a pointer type. */
675
676 k = parse_boolean(rvalue);
677 if (k < 0) {
678 log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
679 return 0;
680 }
681
682 *t = !!k;
683 return 0;
684}
685
8f2665a4
LP
686int config_parse_string(
687 const char *unit,
688 const char *filename,
689 unsigned line,
690 const char *section,
691 unsigned section_line,
692 const char *lvalue,
693 int ltype,
694 const char *rvalue,
695 void *data,
696 void *userdata) {
697
698 char **s = data, *n;
ed5bcfbe
LP
699
700 assert(filename);
701 assert(lvalue);
702 assert(rvalue);
703 assert(data);
704
8f2665a4 705 if (!utf8_is_valid(rvalue)) {
0e05ee04 706 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
7f110ff9
LP
707 return 0;
708 }
ed5bcfbe 709
8f2665a4
LP
710 if (isempty(rvalue))
711 n = NULL;
7f110ff9 712 else {
8f2665a4
LP
713 n = strdup(rvalue);
714 if (!n)
715 return log_oom();
7f110ff9 716 }
ed5bcfbe 717
8f2665a4
LP
718 free(*s);
719 *s = n;
720
ed5bcfbe
LP
721 return 0;
722}
57d42a5f 723
8f2665a4
LP
724int config_parse_path(
725 const char *unit,
726 const char *filename,
727 unsigned line,
728 const char *section,
729 unsigned section_line,
730 const char *lvalue,
731 int ltype,
732 const char *rvalue,
733 void *data,
734 void *userdata) {
034c6ed7 735
3b436292 736 char **s = data, *n;
2c75fb73 737 bool fatal = ltype;
034c6ed7
LP
738
739 assert(filename);
740 assert(lvalue);
741 assert(rvalue);
742 assert(data);
743
0fe50629
YW
744 if (isempty(rvalue)) {
745 n = NULL;
746 goto finalize;
747 }
748
7f110ff9 749 if (!utf8_is_valid(rvalue)) {
0e05ee04 750 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
2c75fb73 751 return fatal ? -ENOEXEC : 0;
7f110ff9
LP
752 }
753
3b436292 754 if (!path_is_absolute(rvalue)) {
2c75fb73
ZJS
755 log_syntax(unit, LOG_ERR, filename, line, 0,
756 "Not an absolute path%s: %s",
757 fatal ? "" : ", ignoring", rvalue);
758 return fatal ? -ENOEXEC : 0;
034c6ed7
LP
759 }
760
7f110ff9
LP
761 n = strdup(rvalue);
762 if (!n)
74051b9b 763 return log_oom();
034c6ed7 764
01f78473
LP
765 path_kill_slashes(n);
766
0fe50629 767finalize:
034c6ed7
LP
768 free(*s);
769 *s = n;
770
771 return 0;
772}
57d42a5f 773
8249bb72
LP
774int config_parse_strv(
775 const char *unit,
776 const char *filename,
777 unsigned line,
778 const char *section,
779 unsigned section_line,
780 const char *lvalue,
781 int ltype,
782 const char *rvalue,
783 void *data,
784 void *userdata) {
57d42a5f 785
a2a5291b 786 char ***sv = data;
00d0fd06 787 int r;
57d42a5f
LP
788
789 assert(filename);
790 assert(lvalue);
791 assert(rvalue);
792 assert(data);
793
74051b9b 794 if (isempty(rvalue)) {
8249bb72 795 *sv = strv_free(*sv);
853b8397 796 return 0;
74051b9b
LP
797 }
798
34f253f0
DR
799 for (;;) {
800 char *word = NULL;
00d0fd06 801
9a82ab95 802 r = extract_first_word(&rvalue, &word, NULL, EXTRACT_QUOTES|EXTRACT_RETAIN_ESCAPE);
34f253f0
DR
803 if (r == 0)
804 break;
805 if (r == -ENOMEM)
853b8397 806 return log_oom();
34f253f0
DR
807 if (r < 0) {
808 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
809 break;
810 }
853b8397 811
34f253f0 812 if (!utf8_is_valid(word)) {
b4958f42 813 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, word);
34f253f0 814 free(word);
7f110ff9
LP
815 continue;
816 }
8249bb72 817
34f253f0 818 r = strv_consume(sv, word);
853b8397
LP
819 if (r < 0)
820 return log_oom();
7f110ff9 821 }
57d42a5f 822
57d42a5f 823 return 0;
57d42a5f 824}
15ae422b 825
ca37242e
LP
826int config_parse_log_facility(
827 const char *unit,
828 const char *filename,
829 unsigned line,
830 const char *section,
831 unsigned section_line,
832 const char *lvalue,
833 int ltype,
834 const char *rvalue,
835 void *data,
836 void *userdata) {
213ba152 837
213ba152
LP
838 int *o = data, x;
839
840 assert(filename);
841 assert(lvalue);
842 assert(rvalue);
843 assert(data);
844
845 x = log_facility_unshifted_from_string(rvalue);
846 if (x < 0) {
12ca818f 847 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log facility, ignoring: %s", rvalue);
213ba152
LP
848 return 0;
849 }
850
851 *o = (x << 3) | LOG_PRI(*o);
852
853 return 0;
854}
855
ca37242e
LP
856int config_parse_log_level(
857 const char *unit,
858 const char *filename,
859 unsigned line,
860 const char *section,
861 unsigned section_line,
862 const char *lvalue,
863 int ltype,
864 const char *rvalue,
865 void *data,
866 void *userdata) {
213ba152 867
213ba152
LP
868 int *o = data, x;
869
870 assert(filename);
871 assert(lvalue);
872 assert(rvalue);
873 assert(data);
874
875 x = log_level_from_string(rvalue);
876 if (x < 0) {
12ca818f 877 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log level, ignoring: %s", rvalue);
213ba152
LP
878 return 0;
879 }
880
d3070fbd
LP
881 if (*o < 0) /* if it wasn't initialized so far, assume zero facility */
882 *o = x;
883 else
884 *o = (*o & LOG_FACMASK) | x;
885
213ba152
LP
886 return 0;
887}
f757855e
LP
888
889int config_parse_signal(
890 const char *unit,
891 const char *filename,
892 unsigned line,
893 const char *section,
894 unsigned section_line,
895 const char *lvalue,
896 int ltype,
897 const char *rvalue,
898 void *data,
899 void *userdata) {
900
901 int *sig = data, r;
902
903 assert(filename);
904 assert(lvalue);
905 assert(rvalue);
906 assert(sig);
907
908 r = signal_from_string_try_harder(rvalue);
909 if (r <= 0) {
12ca818f 910 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse signal name, ignoring: %s", rvalue);
f757855e
LP
911 return 0;
912 }
913
914 *sig = r;
915 return 0;
916}
917
918int config_parse_personality(
919 const char *unit,
920 const char *filename,
921 unsigned line,
922 const char *section,
923 unsigned section_line,
924 const char *lvalue,
925 int ltype,
926 const char *rvalue,
927 void *data,
928 void *userdata) {
929
930 unsigned long *personality = data, p;
931
932 assert(filename);
933 assert(lvalue);
934 assert(rvalue);
935 assert(personality);
936
40fdd636
LP
937 if (isempty(rvalue))
938 p = PERSONALITY_INVALID;
939 else {
940 p = personality_from_string(rvalue);
941 if (p == PERSONALITY_INVALID) {
942 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse personality, ignoring: %s", rvalue);
943 return 0;
944 }
f757855e
LP
945 }
946
947 *personality = p;
948 return 0;
949}
d31645ad
LP
950
951int config_parse_ifname(
952 const char *unit,
953 const char *filename,
954 unsigned line,
955 const char *section,
956 unsigned section_line,
957 const char *lvalue,
958 int ltype,
959 const char *rvalue,
960 void *data,
961 void *userdata) {
962
963 char **s = data;
964 int r;
965
966 assert(filename);
967 assert(lvalue);
968 assert(rvalue);
969 assert(data);
970
971 if (isempty(rvalue)) {
972 *s = mfree(*s);
973 return 0;
974 }
975
976 if (!ifname_valid(rvalue)) {
977 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue);
978 return 0;
979 }
980
981 r = free_and_strdup(s, rvalue);
982 if (r < 0)
983 return log_oom();
984
985 return 0;
986}
177d0b20
SS
987
988int config_parse_ip_port(
989 const char *unit,
990 const char *filename,
991 unsigned line,
992 const char *section,
993 unsigned section_line,
994 const char *lvalue,
995 int ltype,
996 const char *rvalue,
997 void *data,
998 void *userdata) {
999
1000 uint16_t *s = data;
1001 uint16_t port;
1002 int r;
1003
1004 assert(filename);
1005 assert(lvalue);
1006 assert(rvalue);
1007 assert(data);
1008
1009 if (isempty(rvalue)) {
1010 *s = 0;
1011 return 0;
1012 }
1013
1014 r = parse_ip_port(rvalue, &port);
1015 if (r < 0) {
1016 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse port '%s'.", rvalue);
1017 return 0;
1018 }
1019
1020 *s = port;
1021
1022 return 0;
1023}