]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/conf-parser.c
Merge pull request #1783 from vcaputo/still_make_progress_when_throttling
[thirdparty/systemd.git] / src / shared / conf-parser.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
ed5bcfbe 2
a7334b09
LP
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
a7334b09
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
a7334b09 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
a7334b09
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
ed5bcfbe 22#include <errno.h>
07630cea 23#include <stdio.h>
ed5bcfbe 24#include <stdlib.h>
07630cea 25#include <string.h>
ed5bcfbe 26
f757855e 27#include "sd-messages.h"
07630cea 28
b5efdb8a 29#include "alloc-util.h"
e8461023 30#include "conf-files.h"
6bedfcbb
LP
31#include "conf-parser.h"
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"
07630cea
LP
43#include "utf8.h"
44#include "util.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}