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