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