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