]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/conf-parser.c
Merge pull request #2495 from heftig/master
[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"
a8fbdf54 31#include "extract-word.h"
6bedfcbb 32#include "fd-util.h"
f4f15635 33#include "fs-util.h"
16354eff 34#include "log.h"
07630cea 35#include "macro.h"
6bedfcbb 36#include "parse-util.h"
9eb977db 37#include "path-util.h"
7b3e062c 38#include "process-util.h"
f757855e 39#include "signal-util.h"
07630cea
LP
40#include "string-util.h"
41#include "strv.h"
7b3e062c 42#include "syslog-util.h"
a8fbdf54 43#include "time-util.h"
07630cea 44#include "utf8.h"
e8e581bf 45
f975e971 46int config_item_table_lookup(
e9f3d2d5 47 const void *table,
ed5bcfbe 48 const char *section,
ed5bcfbe 49 const char *lvalue,
f975e971
LP
50 ConfigParserCallback *func,
51 int *ltype,
52 void **data,
ed5bcfbe
LP
53 void *userdata) {
54
e9f3d2d5 55 const ConfigTableItem *t;
f975e971
LP
56
57 assert(table);
ed5bcfbe 58 assert(lvalue);
f975e971
LP
59 assert(func);
60 assert(ltype);
61 assert(data);
ed5bcfbe 62
f975e971 63 for (t = table; t->lvalue; t++) {
ed5bcfbe 64
f975e971 65 if (!streq(lvalue, t->lvalue))
ed5bcfbe
LP
66 continue;
67
f975e971 68 if (!streq_ptr(section, t->section))
ed5bcfbe
LP
69 continue;
70
f975e971
LP
71 *func = t->parse;
72 *ltype = t->ltype;
73 *data = t->data;
74 return 1;
75 }
ed5bcfbe 76
f975e971
LP
77 return 0;
78}
10e87ee7 79
f975e971 80int config_item_perf_lookup(
e9f3d2d5 81 const void *table,
f975e971
LP
82 const char *section,
83 const char *lvalue,
84 ConfigParserCallback *func,
85 int *ltype,
86 void **data,
87 void *userdata) {
88
89 ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
90 const ConfigPerfItem *p;
91
92 assert(table);
93 assert(lvalue);
94 assert(func);
95 assert(ltype);
96 assert(data);
97
98 if (!section)
99 p = lookup(lvalue, strlen(lvalue));
100 else {
101 char *key;
102
b7def684 103 key = strjoin(section, ".", lvalue, NULL);
44d91056 104 if (!key)
f975e971
LP
105 return -ENOMEM;
106
107 p = lookup(key, strlen(key));
108 free(key);
ed5bcfbe
LP
109 }
110
f975e971
LP
111 if (!p)
112 return 0;
113
114 *func = p->parse;
115 *ltype = p->ltype;
116 *data = (uint8_t*) userdata + p->offset;
117 return 1;
118}
119
120/* Run the user supplied parser for an assignment */
e8e581bf
ZJS
121static int next_assignment(const char *unit,
122 const char *filename,
123 unsigned line,
124 ConfigItemLookup lookup,
e9f3d2d5 125 const void *table,
e8e581bf 126 const char *section,
71a61510 127 unsigned section_line,
e8e581bf
ZJS
128 const char *lvalue,
129 const char *rvalue,
130 bool relaxed,
131 void *userdata) {
f975e971
LP
132
133 ConfigParserCallback func = NULL;
134 int ltype = 0;
135 void *data = NULL;
136 int r;
137
138 assert(filename);
139 assert(line > 0);
140 assert(lookup);
141 assert(lvalue);
142 assert(rvalue);
143
144 r = lookup(table, section, lvalue, &func, &ltype, &data, userdata);
145 if (r < 0)
146 return r;
147
d937fbbd
LP
148 if (r > 0) {
149 if (func)
71a61510
TG
150 return func(unit, filename, line, section, section_line,
151 lvalue, ltype, rvalue, data, userdata);
d937fbbd
LP
152
153 return 0;
154 }
f975e971 155
46205bb6 156 /* Warn about unknown non-extension fields. */
10e87ee7 157 if (!relaxed && !startswith(lvalue, "X-"))
12ca818f 158 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown lvalue '%s' in section '%s'", lvalue, section);
46205bb6 159
f1857be0 160 return 0;
ed5bcfbe
LP
161}
162
ed5bcfbe 163/* Parse a variable assignment line */
e8e581bf
ZJS
164static int parse_line(const char* unit,
165 const char *filename,
166 unsigned line,
167 const char *sections,
168 ConfigItemLookup lookup,
e9f3d2d5 169 const void *table,
e8e581bf 170 bool relaxed,
db5c0122 171 bool allow_include,
e8e581bf 172 char **section,
71a61510 173 unsigned *section_line,
342aea19 174 bool *section_ignored,
e8e581bf
ZJS
175 char *l,
176 void *userdata) {
f975e971 177
b2aa81ef 178 char *e;
ed5bcfbe 179
f975e971
LP
180 assert(filename);
181 assert(line > 0);
182 assert(lookup);
183 assert(l);
184
b2aa81ef 185 l = strstrip(l);
ed5bcfbe 186
b2aa81ef 187 if (!*l)
ed5bcfbe 188 return 0;
1ea86b18 189
d3b6d0c2 190 if (strchr(COMMENTS "\n", *l))
1ea86b18 191 return 0;
ed5bcfbe 192
b2aa81ef 193 if (startswith(l, ".include ")) {
db5c0122
LP
194 _cleanup_free_ char *fn = NULL;
195
b8e7a47b
LP
196 /* .includes are a bad idea, we only support them here
197 * for historical reasons. They create cyclic include
198 * problems and make it difficult to detect
199 * configuration file changes with an easy
200 * stat(). Better approaches, such as .d/ drop-in
201 * snippets exist.
202 *
203 * Support for them should be eventually removed. */
204
db5c0122 205 if (!allow_include) {
12ca818f 206 log_syntax(unit, LOG_ERR, filename, line, 0, ".include not allowed here. Ignoring.");
db5c0122
LP
207 return 0;
208 }
ed5bcfbe 209
f975e971
LP
210 fn = file_in_same_dir(filename, strstrip(l+9));
211 if (!fn)
b2aa81ef 212 return -ENOMEM;
ed5bcfbe 213
36f822c4 214 return config_parse(unit, fn, NULL, sections, lookup, table, relaxed, false, false, userdata);
ed5bcfbe
LP
215 }
216
b2aa81ef 217 if (*l == '[') {
ed5bcfbe
LP
218 size_t k;
219 char *n;
220
b2aa81ef 221 k = strlen(l);
ed5bcfbe
LP
222 assert(k > 0);
223
b2aa81ef 224 if (l[k-1] != ']') {
12ca818f 225 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid section header '%s'", l);
ed5bcfbe
LP
226 return -EBADMSG;
227 }
228
f975e971
LP
229 n = strndup(l+1, k-2);
230 if (!n)
ed5bcfbe
LP
231 return -ENOMEM;
232
f975e971 233 if (sections && !nulstr_contains(sections, n)) {
42f4e3c4 234
342aea19 235 if (!relaxed && !startswith(n, "X-"))
12ca818f 236 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown section '%s'. Ignoring.", n);
f975e971
LP
237
238 free(n);
a1e58e8e 239 *section = mfree(*section);
71a61510 240 *section_line = 0;
342aea19 241 *section_ignored = true;
f975e971
LP
242 } else {
243 free(*section);
244 *section = n;
71a61510 245 *section_line = line;
342aea19 246 *section_ignored = false;
f975e971 247 }
ed5bcfbe
LP
248
249 return 0;
250 }
251
62f168a0
LP
252 if (sections && !*section) {
253
342aea19 254 if (!relaxed && !*section_ignored)
12ca818f 255 log_syntax(unit, LOG_WARNING, filename, line, 0, "Assignment outside of section. Ignoring.");
62f168a0 256
10e87ee7 257 return 0;
62f168a0 258 }
10e87ee7 259
f975e971
LP
260 e = strchr(l, '=');
261 if (!e) {
12ca818f
LP
262 log_syntax(unit, LOG_WARNING, filename, line, 0, "Missing '='.");
263 return -EINVAL;
ed5bcfbe
LP
264 }
265
266 *e = 0;
267 e++;
268
e8e581bf
ZJS
269 return next_assignment(unit,
270 filename,
271 line,
272 lookup,
273 table,
274 *section,
71a61510 275 *section_line,
e8e581bf
ZJS
276 strstrip(l),
277 strstrip(e),
278 relaxed,
279 userdata);
ed5bcfbe
LP
280}
281
282/* Go through the file and parse each line */
e8e581bf
ZJS
283int config_parse(const char *unit,
284 const char *filename,
285 FILE *f,
286 const char *sections,
287 ConfigItemLookup lookup,
e9f3d2d5 288 const void *table,
e8e581bf 289 bool relaxed,
db5c0122 290 bool allow_include,
36f822c4 291 bool warn,
e8e581bf 292 void *userdata) {
f975e971 293
7fd1b19b
HH
294 _cleanup_free_ char *section = NULL, *continuation = NULL;
295 _cleanup_fclose_ FILE *ours = NULL;
71a61510 296 unsigned line = 0, section_line = 0;
342aea19 297 bool section_ignored = false;
ed5bcfbe
LP
298 int r;
299
300 assert(filename);
f975e971 301 assert(lookup);
ed5bcfbe 302
87f0e418 303 if (!f) {
245802dd 304 f = ours = fopen(filename, "re");
f975e971 305 if (!f) {
36f822c4
ZJS
306 /* Only log on request, except for ENOENT,
307 * since we return 0 to the caller. */
308 if (warn || errno == ENOENT)
309 log_full(errno == ENOENT ? LOG_DEBUG : LOG_ERR,
310 "Failed to open configuration file '%s': %m", filename);
9f43a07f 311 return errno == ENOENT ? 0 : -errno;
87f0e418 312 }
ed5bcfbe
LP
313 }
314
fdb9161c
LP
315 fd_warn_permissions(filename, fileno(f));
316
ed5bcfbe 317 while (!feof(f)) {
3dab2943
LP
318 char l[LINE_MAX], *p, *c = NULL, *e;
319 bool escaped = false;
ed5bcfbe
LP
320
321 if (!fgets(l, sizeof(l), f)) {
322 if (feof(f))
323 break;
324
56f64d95 325 log_error_errno(errno, "Failed to read configuration file '%s': %m", filename);
245802dd 326 return -errno;
ed5bcfbe
LP
327 }
328
3dab2943
LP
329 truncate_nl(l);
330
331 if (continuation) {
f975e971 332 c = strappend(continuation, l);
36f822c4
ZJS
333 if (!c) {
334 if (warn)
335 log_oom();
245802dd 336 return -ENOMEM;
36f822c4 337 }
3dab2943 338
97b11eed 339 continuation = mfree(continuation);
3dab2943
LP
340 p = c;
341 } else
342 p = l;
343
344 for (e = p; *e; e++) {
345 if (escaped)
346 escaped = false;
347 else if (*e == '\\')
348 escaped = true;
349 }
350
351 if (escaped) {
352 *(e-1) = ' ';
353
354 if (c)
355 continuation = c;
f975e971
LP
356 else {
357 continuation = strdup(l);
36f822c4
ZJS
358 if (!continuation) {
359 if (warn)
360 log_oom();
245802dd 361 return -ENOMEM;
36f822c4 362 }
3dab2943
LP
363 }
364
365 continue;
366 }
367
e8e581bf
ZJS
368 r = parse_line(unit,
369 filename,
370 ++line,
371 sections,
372 lookup,
373 table,
374 relaxed,
db5c0122 375 allow_include,
e8e581bf 376 &section,
71a61510 377 &section_line,
342aea19 378 &section_ignored,
e8e581bf
ZJS
379 p,
380 userdata);
3dab2943
LP
381 free(c);
382
36f822c4
ZJS
383 if (r < 0) {
384 if (warn)
c33b3297
MS
385 log_warning_errno(r, "Failed to parse file '%s': %m",
386 filename);
245802dd 387 return r;
36f822c4 388 }
ed5bcfbe
LP
389 }
390
245802dd 391 return 0;
ed5bcfbe
LP
392}
393
e8461023
JT
394/* Parse each config file in the specified directories. */
395int config_parse_many(const char *conf_file,
396 const char *conf_file_dirs,
397 const char *sections,
398 ConfigItemLookup lookup,
399 const void *table,
400 bool relaxed,
401 void *userdata) {
402 _cleanup_strv_free_ char **files = NULL;
403 char **fn;
404 int r;
405
406 r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
407 if (r < 0)
408 return r;
409
410 if (conf_file) {
411 r = config_parse(NULL, conf_file, NULL, sections, lookup, table, relaxed, false, true, userdata);
412 if (r < 0)
413 return r;
414 }
415
416 STRV_FOREACH(fn, files) {
417 r = config_parse(NULL, *fn, NULL, sections, lookup, table, relaxed, false, true, userdata);
418 if (r < 0)
419 return r;
420 }
421
422 return 0;
423}
424
eb3491d9 425#define DEFINE_PARSER(type, vartype, conv_func) \
94d75d64
LP
426 int config_parse_##type( \
427 const char *unit, \
428 const char *filename, \
429 unsigned line, \
430 const char *section, \
431 unsigned section_line, \
432 const char *lvalue, \
433 int ltype, \
434 const char *rvalue, \
435 void *data, \
436 void *userdata) { \
eb3491d9
ZJS
437 \
438 vartype *i = data; \
439 int r; \
440 \
441 assert(filename); \
442 assert(lvalue); \
443 assert(rvalue); \
444 assert(data); \
445 \
446 r = conv_func(rvalue, i); \
447 if (r < 0) \
12ca818f 448 log_syntax(unit, LOG_ERR, filename, line, r, \
e8e581bf 449 "Failed to parse %s value, ignoring: %s", \
98d75800 450 #type, rvalue); \
eb3491d9
ZJS
451 \
452 return 0; \
94d75d64
LP
453 } \
454 struct __useless_struct_to_allow_trailing_semicolon__
455
456DEFINE_PARSER(int, int, safe_atoi);
457DEFINE_PARSER(long, long, safe_atoli);
458DEFINE_PARSER(uint32, uint32_t, safe_atou32);
459DEFINE_PARSER(uint64, uint64_t, safe_atou64);
460DEFINE_PARSER(unsigned, unsigned, safe_atou);
461DEFINE_PARSER(double, double, safe_atod);
462DEFINE_PARSER(nsec, nsec_t, parse_nsec);
463DEFINE_PARSER(sec, usec_t, parse_sec);
464DEFINE_PARSER(mode, mode_t, parse_mode);
ed5bcfbe 465
5556b5fe 466int config_parse_iec_size(const char* unit,
e8e581bf
ZJS
467 const char *filename,
468 unsigned line,
469 const char *section,
71a61510 470 unsigned section_line,
e8e581bf
ZJS
471 const char *lvalue,
472 int ltype,
473 const char *rvalue,
474 void *data,
475 void *userdata) {
ed5bcfbe
LP
476
477 size_t *sz = data;
59f448cf 478 uint64_t v;
e8e581bf 479 int r;
ed5bcfbe
LP
480
481 assert(filename);
482 assert(lvalue);
483 assert(rvalue);
484 assert(data);
485
59f448cf
LP
486 r = parse_size(rvalue, 1024, &v);
487 if (r < 0 || (uint64_t) (size_t) v != v) {
12ca818f 488 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
9ba1a159
LP
489 return 0;
490 }
491
59f448cf 492 *sz = (size_t) v;
9ba1a159
LP
493 return 0;
494}
495
5556b5fe
LP
496int config_parse_si_size(const char* unit,
497 const char *filename,
498 unsigned line,
499 const char *section,
500 unsigned section_line,
501 const char *lvalue,
502 int ltype,
503 const char *rvalue,
504 void *data,
505 void *userdata) {
506
507 size_t *sz = data;
59f448cf 508 uint64_t v;
5556b5fe
LP
509 int r;
510
511 assert(filename);
512 assert(lvalue);
513 assert(rvalue);
514 assert(data);
515
59f448cf
LP
516 r = parse_size(rvalue, 1000, &v);
517 if (r < 0 || (uint64_t) (size_t) v != v) {
12ca818f 518 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
5556b5fe
LP
519 return 0;
520 }
521
59f448cf 522 *sz = (size_t) v;
5556b5fe
LP
523 return 0;
524}
9ba1a159 525
59f448cf 526int config_parse_iec_uint64(const char* unit,
e8e581bf
ZJS
527 const char *filename,
528 unsigned line,
529 const char *section,
71a61510 530 unsigned section_line,
e8e581bf
ZJS
531 const char *lvalue,
532 int ltype,
533 const char *rvalue,
534 void *data,
535 void *userdata) {
9ba1a159 536
59f448cf 537 uint64_t *bytes = data;
e8e581bf 538 int r;
9ba1a159
LP
539
540 assert(filename);
541 assert(lvalue);
542 assert(rvalue);
543 assert(data);
544
5556b5fe 545 r = parse_size(rvalue, 1024, bytes);
e8e581bf 546 if (r < 0)
59f448cf 547 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
ed5bcfbe 548
ed5bcfbe
LP
549 return 0;
550}
551
e8e581bf
ZJS
552int config_parse_bool(const char* unit,
553 const char *filename,
554 unsigned line,
555 const char *section,
71a61510 556 unsigned section_line,
e8e581bf
ZJS
557 const char *lvalue,
558 int ltype,
559 const char *rvalue,
560 void *data,
561 void *userdata) {
ed5bcfbe
LP
562
563 int k;
564 bool *b = data;
565
566 assert(filename);
567 assert(lvalue);
568 assert(rvalue);
569 assert(data);
570
e8e581bf
ZJS
571 k = parse_boolean(rvalue);
572 if (k < 0) {
12ca818f 573 log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
f975e971 574 return 0;
ed5bcfbe
LP
575 }
576
577 *b = !!k;
578 return 0;
579}
580
f757855e
LP
581int config_parse_tristate(
582 const char* unit,
583 const char *filename,
584 unsigned line,
585 const char *section,
586 unsigned section_line,
587 const char *lvalue,
588 int ltype,
589 const char *rvalue,
590 void *data,
591 void *userdata) {
592
593 int k, *t = data;
594
595 assert(filename);
596 assert(lvalue);
597 assert(rvalue);
598 assert(data);
599
600 /* A tristate is pretty much a boolean, except that it can
601 * also take the special value -1, indicating "uninitialized",
602 * much like NULL is for a pointer type. */
603
604 k = parse_boolean(rvalue);
605 if (k < 0) {
606 log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
607 return 0;
608 }
609
610 *t = !!k;
611 return 0;
612}
613
8f2665a4
LP
614int config_parse_string(
615 const char *unit,
616 const char *filename,
617 unsigned line,
618 const char *section,
619 unsigned section_line,
620 const char *lvalue,
621 int ltype,
622 const char *rvalue,
623 void *data,
624 void *userdata) {
625
626 char **s = data, *n;
ed5bcfbe
LP
627
628 assert(filename);
629 assert(lvalue);
630 assert(rvalue);
631 assert(data);
632
8f2665a4 633 if (!utf8_is_valid(rvalue)) {
0e05ee04 634 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
7f110ff9
LP
635 return 0;
636 }
ed5bcfbe 637
8f2665a4
LP
638 if (isempty(rvalue))
639 n = NULL;
7f110ff9 640 else {
8f2665a4
LP
641 n = strdup(rvalue);
642 if (!n)
643 return log_oom();
7f110ff9 644 }
ed5bcfbe 645
8f2665a4
LP
646 free(*s);
647 *s = n;
648
ed5bcfbe
LP
649 return 0;
650}
57d42a5f 651
8f2665a4
LP
652int config_parse_path(
653 const char *unit,
654 const char *filename,
655 unsigned line,
656 const char *section,
657 unsigned section_line,
658 const char *lvalue,
659 int ltype,
660 const char *rvalue,
661 void *data,
662 void *userdata) {
034c6ed7 663
3b436292 664 char **s = data, *n;
034c6ed7
LP
665
666 assert(filename);
667 assert(lvalue);
668 assert(rvalue);
669 assert(data);
670
7f110ff9 671 if (!utf8_is_valid(rvalue)) {
0e05ee04 672 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
7f110ff9
LP
673 return 0;
674 }
675
3b436292 676 if (!path_is_absolute(rvalue)) {
12ca818f 677 log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", rvalue);
f975e971 678 return 0;
034c6ed7
LP
679 }
680
7f110ff9
LP
681 n = strdup(rvalue);
682 if (!n)
74051b9b 683 return log_oom();
034c6ed7 684
01f78473
LP
685 path_kill_slashes(n);
686
034c6ed7
LP
687 free(*s);
688 *s = n;
689
690 return 0;
691}
57d42a5f 692
e8e581bf
ZJS
693int config_parse_strv(const char *unit,
694 const char *filename,
695 unsigned line,
696 const char *section,
71a61510 697 unsigned section_line,
e8e581bf
ZJS
698 const char *lvalue,
699 int ltype,
700 const char *rvalue,
701 void *data,
702 void *userdata) {
57d42a5f 703
a2a5291b 704 char ***sv = data;
57d42a5f
LP
705
706 assert(filename);
707 assert(lvalue);
708 assert(rvalue);
709 assert(data);
710
74051b9b 711 if (isempty(rvalue)) {
4589f5bb
LP
712 char **empty;
713
714 /* Empty assignment resets the list. As a special rule
715 * we actually fill in a real empty array here rather
716 * than NULL, since some code wants to know if
717 * something was set at all... */
718 empty = strv_new(NULL, NULL);
719 if (!empty)
720 return log_oom();
721
74051b9b 722 strv_free(*sv);
4589f5bb 723 *sv = empty;
853b8397 724 return 0;
74051b9b
LP
725 }
726
34f253f0
DR
727 for (;;) {
728 char *word = NULL;
729 int r;
730 r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES);
731 if (r == 0)
732 break;
733 if (r == -ENOMEM)
853b8397 734 return log_oom();
34f253f0
DR
735 if (r < 0) {
736 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
737 break;
738 }
853b8397 739
34f253f0 740 if (!utf8_is_valid(word)) {
0e05ee04 741 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
34f253f0 742 free(word);
7f110ff9
LP
743 continue;
744 }
34f253f0 745 r = strv_consume(sv, word);
853b8397
LP
746 if (r < 0)
747 return log_oom();
7f110ff9 748 }
57d42a5f 749
57d42a5f 750 return 0;
57d42a5f 751}
15ae422b 752
ca37242e
LP
753int config_parse_log_facility(
754 const char *unit,
755 const char *filename,
756 unsigned line,
757 const char *section,
758 unsigned section_line,
759 const char *lvalue,
760 int ltype,
761 const char *rvalue,
762 void *data,
763 void *userdata) {
213ba152
LP
764
765
766 int *o = data, x;
767
768 assert(filename);
769 assert(lvalue);
770 assert(rvalue);
771 assert(data);
772
773 x = log_facility_unshifted_from_string(rvalue);
774 if (x < 0) {
12ca818f 775 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log facility, ignoring: %s", rvalue);
213ba152
LP
776 return 0;
777 }
778
779 *o = (x << 3) | LOG_PRI(*o);
780
781 return 0;
782}
783
ca37242e
LP
784int config_parse_log_level(
785 const char *unit,
786 const char *filename,
787 unsigned line,
788 const char *section,
789 unsigned section_line,
790 const char *lvalue,
791 int ltype,
792 const char *rvalue,
793 void *data,
794 void *userdata) {
213ba152
LP
795
796
797 int *o = data, x;
798
799 assert(filename);
800 assert(lvalue);
801 assert(rvalue);
802 assert(data);
803
804 x = log_level_from_string(rvalue);
805 if (x < 0) {
12ca818f 806 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log level, ignoring: %s", rvalue);
213ba152
LP
807 return 0;
808 }
809
810 *o = (*o & LOG_FACMASK) | x;
811 return 0;
812}
f757855e
LP
813
814int config_parse_signal(
815 const char *unit,
816 const char *filename,
817 unsigned line,
818 const char *section,
819 unsigned section_line,
820 const char *lvalue,
821 int ltype,
822 const char *rvalue,
823 void *data,
824 void *userdata) {
825
826 int *sig = data, r;
827
828 assert(filename);
829 assert(lvalue);
830 assert(rvalue);
831 assert(sig);
832
833 r = signal_from_string_try_harder(rvalue);
834 if (r <= 0) {
12ca818f 835 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse signal name, ignoring: %s", rvalue);
f757855e
LP
836 return 0;
837 }
838
839 *sig = r;
840 return 0;
841}
842
843int config_parse_personality(
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) {
854
855 unsigned long *personality = data, p;
856
857 assert(filename);
858 assert(lvalue);
859 assert(rvalue);
860 assert(personality);
861
862 p = personality_from_string(rvalue);
863 if (p == PERSONALITY_INVALID) {
12ca818f 864 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse personality, ignoring: %s", rvalue);
f757855e
LP
865 return 0;
866 }
867
868 *personality = p;
869 return 0;
870}