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