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