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