]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/conf-parser.c
bus-proxy: allow empty arguments to UpdateActivationEnvironment()
[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
LP
22#include <string.h>
23#include <stdio.h>
24#include <errno.h>
ed5bcfbe
LP
25#include <stdlib.h>
26
27#include "conf-parser.h"
e8461023 28#include "conf-files.h"
ed5bcfbe
LP
29#include "util.h"
30#include "macro.h"
57d42a5f 31#include "strv.h"
16354eff 32#include "log.h"
7f110ff9 33#include "utf8.h"
9eb977db 34#include "path-util.h"
e8e581bf
ZJS
35#include "sd-messages.h"
36
f975e971 37int config_item_table_lookup(
e9f3d2d5 38 const void *table,
ed5bcfbe 39 const char *section,
ed5bcfbe 40 const char *lvalue,
f975e971
LP
41 ConfigParserCallback *func,
42 int *ltype,
43 void **data,
ed5bcfbe
LP
44 void *userdata) {
45
e9f3d2d5 46 const ConfigTableItem *t;
f975e971
LP
47
48 assert(table);
ed5bcfbe 49 assert(lvalue);
f975e971
LP
50 assert(func);
51 assert(ltype);
52 assert(data);
ed5bcfbe 53
f975e971 54 for (t = table; t->lvalue; t++) {
ed5bcfbe 55
f975e971 56 if (!streq(lvalue, t->lvalue))
ed5bcfbe
LP
57 continue;
58
f975e971 59 if (!streq_ptr(section, t->section))
ed5bcfbe
LP
60 continue;
61
f975e971
LP
62 *func = t->parse;
63 *ltype = t->ltype;
64 *data = t->data;
65 return 1;
66 }
ed5bcfbe 67
f975e971
LP
68 return 0;
69}
10e87ee7 70
f975e971 71int config_item_perf_lookup(
e9f3d2d5 72 const void *table,
f975e971
LP
73 const char *section,
74 const char *lvalue,
75 ConfigParserCallback *func,
76 int *ltype,
77 void **data,
78 void *userdata) {
79
80 ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
81 const ConfigPerfItem *p;
82
83 assert(table);
84 assert(lvalue);
85 assert(func);
86 assert(ltype);
87 assert(data);
88
89 if (!section)
90 p = lookup(lvalue, strlen(lvalue));
91 else {
92 char *key;
93
b7def684 94 key = strjoin(section, ".", lvalue, NULL);
44d91056 95 if (!key)
f975e971
LP
96 return -ENOMEM;
97
98 p = lookup(key, strlen(key));
99 free(key);
ed5bcfbe
LP
100 }
101
f975e971
LP
102 if (!p)
103 return 0;
104
105 *func = p->parse;
106 *ltype = p->ltype;
107 *data = (uint8_t*) userdata + p->offset;
108 return 1;
109}
110
111/* Run the user supplied parser for an assignment */
e8e581bf
ZJS
112static int next_assignment(const char *unit,
113 const char *filename,
114 unsigned line,
115 ConfigItemLookup lookup,
e9f3d2d5 116 const void *table,
e8e581bf 117 const char *section,
71a61510 118 unsigned section_line,
e8e581bf
ZJS
119 const char *lvalue,
120 const char *rvalue,
121 bool relaxed,
122 void *userdata) {
f975e971
LP
123
124 ConfigParserCallback func = NULL;
125 int ltype = 0;
126 void *data = NULL;
127 int r;
128
129 assert(filename);
130 assert(line > 0);
131 assert(lookup);
132 assert(lvalue);
133 assert(rvalue);
134
135 r = lookup(table, section, lvalue, &func, &ltype, &data, userdata);
136 if (r < 0)
137 return r;
138
d937fbbd
LP
139 if (r > 0) {
140 if (func)
71a61510
TG
141 return func(unit, filename, line, section, section_line,
142 lvalue, ltype, rvalue, data, userdata);
d937fbbd
LP
143
144 return 0;
145 }
f975e971 146
46205bb6 147 /* Warn about unknown non-extension fields. */
10e87ee7 148 if (!relaxed && !startswith(lvalue, "X-"))
e8e581bf
ZJS
149 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
150 "Unknown lvalue '%s' in section '%s'", lvalue, section);
46205bb6 151
f1857be0 152 return 0;
ed5bcfbe
LP
153}
154
ed5bcfbe 155/* Parse a variable assignment line */
e8e581bf
ZJS
156static int parse_line(const char* unit,
157 const char *filename,
158 unsigned line,
159 const char *sections,
160 ConfigItemLookup lookup,
e9f3d2d5 161 const void *table,
e8e581bf 162 bool relaxed,
db5c0122 163 bool allow_include,
e8e581bf 164 char **section,
71a61510 165 unsigned *section_line,
342aea19 166 bool *section_ignored,
e8e581bf
ZJS
167 char *l,
168 void *userdata) {
f975e971 169
b2aa81ef 170 char *e;
ed5bcfbe 171
f975e971
LP
172 assert(filename);
173 assert(line > 0);
174 assert(lookup);
175 assert(l);
176
b2aa81ef 177 l = strstrip(l);
ed5bcfbe 178
b2aa81ef 179 if (!*l)
ed5bcfbe 180 return 0;
1ea86b18 181
d3b6d0c2 182 if (strchr(COMMENTS "\n", *l))
1ea86b18 183 return 0;
ed5bcfbe 184
b2aa81ef 185 if (startswith(l, ".include ")) {
db5c0122
LP
186 _cleanup_free_ char *fn = NULL;
187
b8e7a47b
LP
188 /* .includes are a bad idea, we only support them here
189 * for historical reasons. They create cyclic include
190 * problems and make it difficult to detect
191 * configuration file changes with an easy
192 * stat(). Better approaches, such as .d/ drop-in
193 * snippets exist.
194 *
195 * Support for them should be eventually removed. */
196
db5c0122
LP
197 if (!allow_include) {
198 log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
199 ".include not allowed here. Ignoring.");
200 return 0;
201 }
ed5bcfbe 202
f975e971
LP
203 fn = file_in_same_dir(filename, strstrip(l+9));
204 if (!fn)
b2aa81ef 205 return -ENOMEM;
ed5bcfbe 206
36f822c4 207 return config_parse(unit, fn, NULL, sections, lookup, table, relaxed, false, false, userdata);
ed5bcfbe
LP
208 }
209
b2aa81ef 210 if (*l == '[') {
ed5bcfbe
LP
211 size_t k;
212 char *n;
213
b2aa81ef 214 k = strlen(l);
ed5bcfbe
LP
215 assert(k > 0);
216
b2aa81ef 217 if (l[k-1] != ']') {
e8e581bf
ZJS
218 log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
219 "Invalid section header '%s'", l);
ed5bcfbe
LP
220 return -EBADMSG;
221 }
222
f975e971
LP
223 n = strndup(l+1, k-2);
224 if (!n)
ed5bcfbe
LP
225 return -ENOMEM;
226
f975e971 227 if (sections && !nulstr_contains(sections, n)) {
42f4e3c4 228
342aea19 229 if (!relaxed && !startswith(n, "X-"))
e8e581bf
ZJS
230 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
231 "Unknown section '%s'. Ignoring.", n);
f975e971
LP
232
233 free(n);
91ffff96 234 free(*section);
f975e971 235 *section = NULL;
71a61510 236 *section_line = 0;
342aea19 237 *section_ignored = true;
f975e971
LP
238 } else {
239 free(*section);
240 *section = n;
71a61510 241 *section_line = line;
342aea19 242 *section_ignored = false;
f975e971 243 }
ed5bcfbe
LP
244
245 return 0;
246 }
247
62f168a0
LP
248 if (sections && !*section) {
249
342aea19 250 if (!relaxed && !*section_ignored)
e8e581bf
ZJS
251 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
252 "Assignment outside of section. Ignoring.");
62f168a0 253
10e87ee7 254 return 0;
62f168a0 255 }
10e87ee7 256
f975e971
LP
257 e = strchr(l, '=');
258 if (!e) {
e8e581bf 259 log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Missing '='.");
ed5bcfbe
LP
260 return -EBADMSG;
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
LP
335
336 free(continuation);
337 continuation = NULL;
338 p = c;
339 } else
340 p = l;
341
342 for (e = p; *e; e++) {
343 if (escaped)
344 escaped = false;
345 else if (*e == '\\')
346 escaped = true;
347 }
348
349 if (escaped) {
350 *(e-1) = ' ';
351
352 if (c)
353 continuation = c;
f975e971
LP
354 else {
355 continuation = strdup(l);
36f822c4
ZJS
356 if (!continuation) {
357 if (warn)
358 log_oom();
245802dd 359 return -ENOMEM;
36f822c4 360 }
3dab2943
LP
361 }
362
363 continue;
364 }
365
e8e581bf
ZJS
366 r = parse_line(unit,
367 filename,
368 ++line,
369 sections,
370 lookup,
371 table,
372 relaxed,
db5c0122 373 allow_include,
e8e581bf 374 &section,
71a61510 375 &section_line,
342aea19 376 &section_ignored,
e8e581bf
ZJS
377 p,
378 userdata);
3dab2943
LP
379 free(c);
380
36f822c4
ZJS
381 if (r < 0) {
382 if (warn)
c33b3297
MS
383 log_warning_errno(r, "Failed to parse file '%s': %m",
384 filename);
245802dd 385 return r;
36f822c4 386 }
ed5bcfbe
LP
387 }
388
245802dd 389 return 0;
ed5bcfbe
LP
390}
391
e8461023
JT
392/* Parse each config file in the specified directories. */
393int config_parse_many(const char *conf_file,
394 const char *conf_file_dirs,
395 const char *sections,
396 ConfigItemLookup lookup,
397 const void *table,
398 bool relaxed,
399 void *userdata) {
400 _cleanup_strv_free_ char **files = NULL;
401 char **fn;
402 int r;
403
404 r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
405 if (r < 0)
406 return r;
407
408 if (conf_file) {
409 r = config_parse(NULL, conf_file, NULL, sections, lookup, table, relaxed, false, true, userdata);
410 if (r < 0)
411 return r;
412 }
413
414 STRV_FOREACH(fn, files) {
415 r = config_parse(NULL, *fn, NULL, sections, lookup, table, relaxed, false, true, userdata);
416 if (r < 0)
417 return r;
418 }
419
420 return 0;
421}
422
eb3491d9 423#define DEFINE_PARSER(type, vartype, conv_func) \
e8e581bf
ZJS
424 int config_parse_##type(const char *unit, \
425 const char *filename, \
eb3491d9
ZJS
426 unsigned line, \
427 const char *section, \
71a61510 428 unsigned section_line, \
eb3491d9
ZJS
429 const char *lvalue, \
430 int ltype, \
431 const char *rvalue, \
432 void *data, \
433 void *userdata) { \
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) \
e8e581bf
ZJS
445 log_syntax(unit, LOG_ERR, filename, line, -r, \
446 "Failed to parse %s value, ignoring: %s", \
98d75800 447 #type, rvalue); \
eb3491d9
ZJS
448 \
449 return 0; \
ed5bcfbe
LP
450 }
451
eb3491d9
ZJS
452DEFINE_PARSER(int, int, safe_atoi)
453DEFINE_PARSER(long, long, safe_atoli)
454DEFINE_PARSER(uint64, uint64_t, safe_atou64)
455DEFINE_PARSER(unsigned, unsigned, safe_atou)
456DEFINE_PARSER(double, double, safe_atod)
457DEFINE_PARSER(nsec, nsec_t, parse_nsec)
458DEFINE_PARSER(sec, usec_t, parse_sec)
ed5bcfbe 459
5556b5fe 460int config_parse_iec_size(const char* unit,
e8e581bf
ZJS
461 const char *filename,
462 unsigned line,
463 const char *section,
71a61510 464 unsigned section_line,
e8e581bf
ZJS
465 const char *lvalue,
466 int ltype,
467 const char *rvalue,
468 void *data,
469 void *userdata) {
ed5bcfbe
LP
470
471 size_t *sz = data;
9ba1a159 472 off_t o;
e8e581bf 473 int r;
ed5bcfbe
LP
474
475 assert(filename);
476 assert(lvalue);
477 assert(rvalue);
478 assert(data);
479
5556b5fe 480 r = parse_size(rvalue, 1024, &o);
e8e581bf 481 if (r < 0 || (off_t) (size_t) o != o) {
5556b5fe 482 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
9ba1a159
LP
483 return 0;
484 }
485
486 *sz = (size_t) o;
487 return 0;
488}
489
5556b5fe
LP
490int config_parse_si_size(const char* unit,
491 const char *filename,
492 unsigned line,
493 const char *section,
494 unsigned section_line,
495 const char *lvalue,
496 int ltype,
497 const char *rvalue,
498 void *data,
499 void *userdata) {
500
501 size_t *sz = data;
502 off_t o;
503 int r;
504
505 assert(filename);
506 assert(lvalue);
507 assert(rvalue);
508 assert(data);
509
510 r = parse_size(rvalue, 1000, &o);
511 if (r < 0 || (off_t) (size_t) o != o) {
512 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
513 return 0;
514 }
515
516 *sz = (size_t) o;
517 return 0;
518}
9ba1a159 519
5556b5fe 520int config_parse_iec_off(const char* unit,
e8e581bf
ZJS
521 const char *filename,
522 unsigned line,
523 const char *section,
71a61510 524 unsigned section_line,
e8e581bf
ZJS
525 const char *lvalue,
526 int ltype,
527 const char *rvalue,
528 void *data,
529 void *userdata) {
9ba1a159
LP
530
531 off_t *bytes = data;
e8e581bf 532 int r;
9ba1a159
LP
533
534 assert(filename);
535 assert(lvalue);
536 assert(rvalue);
537 assert(data);
538
539 assert_cc(sizeof(off_t) == sizeof(uint64_t));
540
5556b5fe 541 r = parse_size(rvalue, 1024, bytes);
e8e581bf 542 if (r < 0)
5556b5fe 543 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse size value, ignoring: %s", rvalue);
ed5bcfbe 544
ed5bcfbe
LP
545 return 0;
546}
547
e8e581bf
ZJS
548int config_parse_bool(const char* unit,
549 const char *filename,
550 unsigned line,
551 const char *section,
71a61510 552 unsigned section_line,
e8e581bf
ZJS
553 const char *lvalue,
554 int ltype,
555 const char *rvalue,
556 void *data,
557 void *userdata) {
ed5bcfbe
LP
558
559 int k;
560 bool *b = data;
561
562 assert(filename);
563 assert(lvalue);
564 assert(rvalue);
565 assert(data);
566
e8e581bf
ZJS
567 k = parse_boolean(rvalue);
568 if (k < 0) {
569 log_syntax(unit, LOG_ERR, filename, line, -k,
570 "Failed to parse boolean value, ignoring: %s", rvalue);
f975e971 571 return 0;
ed5bcfbe
LP
572 }
573
574 *b = !!k;
575 return 0;
576}
577
8f2665a4
LP
578int config_parse_string(
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 char **s = data, *n;
ed5bcfbe
LP
591
592 assert(filename);
593 assert(lvalue);
594 assert(rvalue);
595 assert(data);
596
8f2665a4 597 if (!utf8_is_valid(rvalue)) {
b5d74213 598 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
7f110ff9
LP
599 return 0;
600 }
ed5bcfbe 601
8f2665a4
LP
602 if (isempty(rvalue))
603 n = NULL;
7f110ff9 604 else {
8f2665a4
LP
605 n = strdup(rvalue);
606 if (!n)
607 return log_oom();
7f110ff9 608 }
ed5bcfbe 609
8f2665a4
LP
610 free(*s);
611 *s = n;
612
ed5bcfbe
LP
613 return 0;
614}
57d42a5f 615
8f2665a4
LP
616int config_parse_path(
617 const char *unit,
618 const char *filename,
619 unsigned line,
620 const char *section,
621 unsigned section_line,
622 const char *lvalue,
623 int ltype,
624 const char *rvalue,
625 void *data,
626 void *userdata) {
034c6ed7 627
3b436292 628 char **s = data, *n;
034c6ed7
LP
629
630 assert(filename);
631 assert(lvalue);
632 assert(rvalue);
633 assert(data);
634
7f110ff9 635 if (!utf8_is_valid(rvalue)) {
b5d74213 636 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
7f110ff9
LP
637 return 0;
638 }
639
3b436292
LP
640 if (!path_is_absolute(rvalue)) {
641 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not an absolute path, ignoring: %s", rvalue);
f975e971 642 return 0;
034c6ed7
LP
643 }
644
7f110ff9
LP
645 n = strdup(rvalue);
646 if (!n)
74051b9b 647 return log_oom();
034c6ed7 648
01f78473
LP
649 path_kill_slashes(n);
650
034c6ed7
LP
651 free(*s);
652 *s = n;
653
654 return 0;
655}
57d42a5f 656
e8e581bf
ZJS
657int config_parse_strv(const char *unit,
658 const char *filename,
659 unsigned line,
660 const char *section,
71a61510 661 unsigned section_line,
e8e581bf
ZJS
662 const char *lvalue,
663 int ltype,
664 const char *rvalue,
665 void *data,
666 void *userdata) {
57d42a5f 667
a2a5291b
ZJS
668 char ***sv = data;
669 const char *word, *state;
57d42a5f 670 size_t l;
7f110ff9 671 int r;
57d42a5f
LP
672
673 assert(filename);
674 assert(lvalue);
675 assert(rvalue);
676 assert(data);
677
74051b9b 678 if (isempty(rvalue)) {
4589f5bb
LP
679 char **empty;
680
681 /* Empty assignment resets the list. As a special rule
682 * we actually fill in a real empty array here rather
683 * than NULL, since some code wants to know if
684 * something was set at all... */
685 empty = strv_new(NULL, NULL);
686 if (!empty)
687 return log_oom();
688
74051b9b 689 strv_free(*sv);
4589f5bb 690 *sv = empty;
853b8397 691 return 0;
74051b9b
LP
692 }
693
a2a5291b 694 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
6e18964d 695 char *n;
7f110ff9 696
a2a5291b 697 n = strndup(word, l);
853b8397
LP
698 if (!n)
699 return log_oom();
700
701 if (!utf8_is_valid(n)) {
b5d74213 702 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
9e602778 703 free(n);
7f110ff9
LP
704 continue;
705 }
706
6e18964d 707 r = strv_consume(sv, n);
853b8397
LP
708 if (r < 0)
709 return log_oom();
7f110ff9 710 }
b2fadec6
ZJS
711 if (!isempty(state))
712 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
713 "Trailing garbage, ignoring.");
57d42a5f 714
57d42a5f 715 return 0;
57d42a5f 716}
15ae422b 717
2ff7b0a5
LP
718int config_parse_mode(
719 const char *unit,
720 const char *filename,
721 unsigned line,
722 const char *section,
71a61510 723 unsigned section_line,
2ff7b0a5
LP
724 const char *lvalue,
725 int ltype,
726 const char *rvalue,
727 void *data,
728 void *userdata) {
f975e971
LP
729
730 mode_t *m = data;
f975e971
LP
731
732 assert(filename);
733 assert(lvalue);
734 assert(rvalue);
735 assert(data);
736
2ff7b0a5
LP
737 if (parse_mode(rvalue, m) < 0) {
738 log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse mode value, ignoring: %s", rvalue);
f975e971
LP
739 return 0;
740 }
741
f975e971
LP
742 return 0;
743}
213ba152 744
ca37242e
LP
745int config_parse_log_facility(
746 const char *unit,
747 const char *filename,
748 unsigned line,
749 const char *section,
750 unsigned section_line,
751 const char *lvalue,
752 int ltype,
753 const char *rvalue,
754 void *data,
755 void *userdata) {
213ba152
LP
756
757
758 int *o = data, x;
759
760 assert(filename);
761 assert(lvalue);
762 assert(rvalue);
763 assert(data);
764
765 x = log_facility_unshifted_from_string(rvalue);
766 if (x < 0) {
769d324c 767 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse log facility, ignoring: %s", rvalue);
213ba152
LP
768 return 0;
769 }
770
771 *o = (x << 3) | LOG_PRI(*o);
772
773 return 0;
774}
775
ca37242e
LP
776int config_parse_log_level(
777 const char *unit,
778 const char *filename,
779 unsigned line,
780 const char *section,
781 unsigned section_line,
782 const char *lvalue,
783 int ltype,
784 const char *rvalue,
785 void *data,
786 void *userdata) {
213ba152
LP
787
788
789 int *o = data, x;
790
791 assert(filename);
792 assert(lvalue);
793 assert(rvalue);
794 assert(data);
795
796 x = log_level_from_string(rvalue);
797 if (x < 0) {
769d324c 798 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse log level, ignoring: %s", rvalue);
213ba152
LP
799 return 0;
800 }
801
802 *o = (*o & LOG_FACMASK) | x;
803 return 0;
804}