]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/conf-parser.c
Merge pull request #1190 from poettering/rework-virt
[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
f757855e 27#include "sd-messages.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"
f757855e
LP
35#include "signal-util.h"
36#include "conf-parser.h"
e8e581bf 37
f975e971 38int config_item_table_lookup(
e9f3d2d5 39 const void *table,
ed5bcfbe 40 const char *section,
ed5bcfbe 41 const char *lvalue,
f975e971
LP
42 ConfigParserCallback *func,
43 int *ltype,
44 void **data,
ed5bcfbe
LP
45 void *userdata) {
46
e9f3d2d5 47 const ConfigTableItem *t;
f975e971
LP
48
49 assert(table);
ed5bcfbe 50 assert(lvalue);
f975e971
LP
51 assert(func);
52 assert(ltype);
53 assert(data);
ed5bcfbe 54
f975e971 55 for (t = table; t->lvalue; t++) {
ed5bcfbe 56
f975e971 57 if (!streq(lvalue, t->lvalue))
ed5bcfbe
LP
58 continue;
59
f975e971 60 if (!streq_ptr(section, t->section))
ed5bcfbe
LP
61 continue;
62
f975e971
LP
63 *func = t->parse;
64 *ltype = t->ltype;
65 *data = t->data;
66 return 1;
67 }
ed5bcfbe 68
f975e971
LP
69 return 0;
70}
10e87ee7 71
f975e971 72int config_item_perf_lookup(
e9f3d2d5 73 const void *table,
f975e971
LP
74 const char *section,
75 const char *lvalue,
76 ConfigParserCallback *func,
77 int *ltype,
78 void **data,
79 void *userdata) {
80
81 ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
82 const ConfigPerfItem *p;
83
84 assert(table);
85 assert(lvalue);
86 assert(func);
87 assert(ltype);
88 assert(data);
89
90 if (!section)
91 p = lookup(lvalue, strlen(lvalue));
92 else {
93 char *key;
94
b7def684 95 key = strjoin(section, ".", lvalue, NULL);
44d91056 96 if (!key)
f975e971
LP
97 return -ENOMEM;
98
99 p = lookup(key, strlen(key));
100 free(key);
ed5bcfbe
LP
101 }
102
f975e971
LP
103 if (!p)
104 return 0;
105
106 *func = p->parse;
107 *ltype = p->ltype;
108 *data = (uint8_t*) userdata + p->offset;
109 return 1;
110}
111
112/* Run the user supplied parser for an assignment */
e8e581bf
ZJS
113static int next_assignment(const char *unit,
114 const char *filename,
115 unsigned line,
116 ConfigItemLookup lookup,
e9f3d2d5 117 const void *table,
e8e581bf 118 const char *section,
71a61510 119 unsigned section_line,
e8e581bf
ZJS
120 const char *lvalue,
121 const char *rvalue,
122 bool relaxed,
123 void *userdata) {
f975e971
LP
124
125 ConfigParserCallback func = NULL;
126 int ltype = 0;
127 void *data = NULL;
128 int r;
129
130 assert(filename);
131 assert(line > 0);
132 assert(lookup);
133 assert(lvalue);
134 assert(rvalue);
135
136 r = lookup(table, section, lvalue, &func, &ltype, &data, userdata);
137 if (r < 0)
138 return r;
139
d937fbbd
LP
140 if (r > 0) {
141 if (func)
71a61510
TG
142 return func(unit, filename, line, section, section_line,
143 lvalue, ltype, rvalue, data, userdata);
d937fbbd
LP
144
145 return 0;
146 }
f975e971 147
46205bb6 148 /* Warn about unknown non-extension fields. */
10e87ee7 149 if (!relaxed && !startswith(lvalue, "X-"))
e8e581bf
ZJS
150 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
151 "Unknown lvalue '%s' in section '%s'", lvalue, section);
46205bb6 152
f1857be0 153 return 0;
ed5bcfbe
LP
154}
155
ed5bcfbe 156/* Parse a variable assignment line */
e8e581bf
ZJS
157static int parse_line(const char* unit,
158 const char *filename,
159 unsigned line,
160 const char *sections,
161 ConfigItemLookup lookup,
e9f3d2d5 162 const void *table,
e8e581bf 163 bool relaxed,
db5c0122 164 bool allow_include,
e8e581bf 165 char **section,
71a61510 166 unsigned *section_line,
342aea19 167 bool *section_ignored,
e8e581bf
ZJS
168 char *l,
169 void *userdata) {
f975e971 170
b2aa81ef 171 char *e;
ed5bcfbe 172
f975e971
LP
173 assert(filename);
174 assert(line > 0);
175 assert(lookup);
176 assert(l);
177
b2aa81ef 178 l = strstrip(l);
ed5bcfbe 179
b2aa81ef 180 if (!*l)
ed5bcfbe 181 return 0;
1ea86b18 182
d3b6d0c2 183 if (strchr(COMMENTS "\n", *l))
1ea86b18 184 return 0;
ed5bcfbe 185
b2aa81ef 186 if (startswith(l, ".include ")) {
db5c0122
LP
187 _cleanup_free_ char *fn = NULL;
188
b8e7a47b
LP
189 /* .includes are a bad idea, we only support them here
190 * for historical reasons. They create cyclic include
191 * problems and make it difficult to detect
192 * configuration file changes with an easy
193 * stat(). Better approaches, such as .d/ drop-in
194 * snippets exist.
195 *
196 * Support for them should be eventually removed. */
197
db5c0122
LP
198 if (!allow_include) {
199 log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
200 ".include not allowed here. Ignoring.");
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] != ']') {
e8e581bf
ZJS
219 log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
220 "Invalid section header '%s'", l);
ed5bcfbe
LP
221 return -EBADMSG;
222 }
223
f975e971
LP
224 n = strndup(l+1, k-2);
225 if (!n)
ed5bcfbe
LP
226 return -ENOMEM;
227
f975e971 228 if (sections && !nulstr_contains(sections, n)) {
42f4e3c4 229
342aea19 230 if (!relaxed && !startswith(n, "X-"))
e8e581bf
ZJS
231 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
232 "Unknown section '%s'. Ignoring.", n);
f975e971
LP
233
234 free(n);
91ffff96 235 free(*section);
f975e971 236 *section = NULL;
71a61510 237 *section_line = 0;
342aea19 238 *section_ignored = true;
f975e971
LP
239 } else {
240 free(*section);
241 *section = n;
71a61510 242 *section_line = line;
342aea19 243 *section_ignored = false;
f975e971 244 }
ed5bcfbe
LP
245
246 return 0;
247 }
248
62f168a0
LP
249 if (sections && !*section) {
250
342aea19 251 if (!relaxed && !*section_ignored)
e8e581bf
ZJS
252 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
253 "Assignment outside of section. Ignoring.");
62f168a0 254
10e87ee7 255 return 0;
62f168a0 256 }
10e87ee7 257
f975e971
LP
258 e = strchr(l, '=');
259 if (!e) {
e8e581bf 260 log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Missing '='.");
ed5bcfbe
LP
261 return -EBADMSG;
262 }
263
264 *e = 0;
265 e++;
266
e8e581bf
ZJS
267 return next_assignment(unit,
268 filename,
269 line,
270 lookup,
271 table,
272 *section,
71a61510 273 *section_line,
e8e581bf
ZJS
274 strstrip(l),
275 strstrip(e),
276 relaxed,
277 userdata);
ed5bcfbe
LP
278}
279
280/* Go through the file and parse each line */
e8e581bf
ZJS
281int config_parse(const char *unit,
282 const char *filename,
283 FILE *f,
284 const char *sections,
285 ConfigItemLookup lookup,
e9f3d2d5 286 const void *table,
e8e581bf 287 bool relaxed,
db5c0122 288 bool allow_include,
36f822c4 289 bool warn,
e8e581bf 290 void *userdata) {
f975e971 291
7fd1b19b
HH
292 _cleanup_free_ char *section = NULL, *continuation = NULL;
293 _cleanup_fclose_ FILE *ours = NULL;
71a61510 294 unsigned line = 0, section_line = 0;
342aea19 295 bool section_ignored = false;
ed5bcfbe
LP
296 int r;
297
298 assert(filename);
f975e971 299 assert(lookup);
ed5bcfbe 300
87f0e418 301 if (!f) {
245802dd 302 f = ours = fopen(filename, "re");
f975e971 303 if (!f) {
36f822c4
ZJS
304 /* Only log on request, except for ENOENT,
305 * since we return 0 to the caller. */
306 if (warn || errno == ENOENT)
307 log_full(errno == ENOENT ? LOG_DEBUG : LOG_ERR,
308 "Failed to open configuration file '%s': %m", filename);
9f43a07f 309 return errno == ENOENT ? 0 : -errno;
87f0e418 310 }
ed5bcfbe
LP
311 }
312
fdb9161c
LP
313 fd_warn_permissions(filename, fileno(f));
314
ed5bcfbe 315 while (!feof(f)) {
3dab2943
LP
316 char l[LINE_MAX], *p, *c = NULL, *e;
317 bool escaped = false;
ed5bcfbe
LP
318
319 if (!fgets(l, sizeof(l), f)) {
320 if (feof(f))
321 break;
322
56f64d95 323 log_error_errno(errno, "Failed to read configuration file '%s': %m", filename);
245802dd 324 return -errno;
ed5bcfbe
LP
325 }
326
3dab2943
LP
327 truncate_nl(l);
328
329 if (continuation) {
f975e971 330 c = strappend(continuation, l);
36f822c4
ZJS
331 if (!c) {
332 if (warn)
333 log_oom();
245802dd 334 return -ENOMEM;
36f822c4 335 }
3dab2943 336
97b11eed 337 continuation = mfree(continuation);
3dab2943
LP
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)
9b3a67c5 454DEFINE_PARSER(uint32, uint32_t, safe_atou32)
eb3491d9
ZJS
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)
ed5bcfbe 460
5556b5fe 461int config_parse_iec_size(const char* unit,
e8e581bf
ZJS
462 const char *filename,
463 unsigned line,
464 const char *section,
71a61510 465 unsigned section_line,
e8e581bf
ZJS
466 const char *lvalue,
467 int ltype,
468 const char *rvalue,
469 void *data,
470 void *userdata) {
ed5bcfbe
LP
471
472 size_t *sz = data;
9ba1a159 473 off_t o;
e8e581bf 474 int r;
ed5bcfbe
LP
475
476 assert(filename);
477 assert(lvalue);
478 assert(rvalue);
479 assert(data);
480
5556b5fe 481 r = parse_size(rvalue, 1024, &o);
e8e581bf 482 if (r < 0 || (off_t) (size_t) o != o) {
5556b5fe 483 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
9ba1a159
LP
484 return 0;
485 }
486
487 *sz = (size_t) o;
488 return 0;
489}
490
5556b5fe
LP
491int config_parse_si_size(const char* unit,
492 const char *filename,
493 unsigned line,
494 const char *section,
495 unsigned section_line,
496 const char *lvalue,
497 int ltype,
498 const char *rvalue,
499 void *data,
500 void *userdata) {
501
502 size_t *sz = data;
503 off_t o;
504 int r;
505
506 assert(filename);
507 assert(lvalue);
508 assert(rvalue);
509 assert(data);
510
511 r = parse_size(rvalue, 1000, &o);
512 if (r < 0 || (off_t) (size_t) o != o) {
513 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
514 return 0;
515 }
516
517 *sz = (size_t) o;
518 return 0;
519}
9ba1a159 520
5556b5fe 521int config_parse_iec_off(const char* unit,
e8e581bf
ZJS
522 const char *filename,
523 unsigned line,
524 const char *section,
71a61510 525 unsigned section_line,
e8e581bf
ZJS
526 const char *lvalue,
527 int ltype,
528 const char *rvalue,
529 void *data,
530 void *userdata) {
9ba1a159
LP
531
532 off_t *bytes = data;
e8e581bf 533 int r;
9ba1a159
LP
534
535 assert(filename);
536 assert(lvalue);
537 assert(rvalue);
538 assert(data);
539
540 assert_cc(sizeof(off_t) == sizeof(uint64_t));
541
5556b5fe 542 r = parse_size(rvalue, 1024, bytes);
e8e581bf 543 if (r < 0)
5556b5fe 544 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse size value, ignoring: %s", rvalue);
ed5bcfbe 545
ed5bcfbe
LP
546 return 0;
547}
548
e8e581bf
ZJS
549int config_parse_bool(const char* unit,
550 const char *filename,
551 unsigned line,
552 const char *section,
71a61510 553 unsigned section_line,
e8e581bf
ZJS
554 const char *lvalue,
555 int ltype,
556 const char *rvalue,
557 void *data,
558 void *userdata) {
ed5bcfbe
LP
559
560 int k;
561 bool *b = data;
562
563 assert(filename);
564 assert(lvalue);
565 assert(rvalue);
566 assert(data);
567
e8e581bf
ZJS
568 k = parse_boolean(rvalue);
569 if (k < 0) {
570 log_syntax(unit, LOG_ERR, filename, line, -k,
571 "Failed to parse boolean value, ignoring: %s", rvalue);
f975e971 572 return 0;
ed5bcfbe
LP
573 }
574
575 *b = !!k;
576 return 0;
577}
578
f757855e
LP
579int config_parse_tristate(
580 const char* unit,
581 const char *filename,
582 unsigned line,
583 const char *section,
584 unsigned section_line,
585 const char *lvalue,
586 int ltype,
587 const char *rvalue,
588 void *data,
589 void *userdata) {
590
591 int k, *t = data;
592
593 assert(filename);
594 assert(lvalue);
595 assert(rvalue);
596 assert(data);
597
598 /* A tristate is pretty much a boolean, except that it can
599 * also take the special value -1, indicating "uninitialized",
600 * much like NULL is for a pointer type. */
601
602 k = parse_boolean(rvalue);
603 if (k < 0) {
604 log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
605 return 0;
606 }
607
608 *t = !!k;
609 return 0;
610}
611
8f2665a4
LP
612int config_parse_string(
613 const char *unit,
614 const char *filename,
615 unsigned line,
616 const char *section,
617 unsigned section_line,
618 const char *lvalue,
619 int ltype,
620 const char *rvalue,
621 void *data,
622 void *userdata) {
623
624 char **s = data, *n;
ed5bcfbe
LP
625
626 assert(filename);
627 assert(lvalue);
628 assert(rvalue);
629 assert(data);
630
8f2665a4 631 if (!utf8_is_valid(rvalue)) {
b5d74213 632 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
7f110ff9
LP
633 return 0;
634 }
ed5bcfbe 635
8f2665a4
LP
636 if (isempty(rvalue))
637 n = NULL;
7f110ff9 638 else {
8f2665a4
LP
639 n = strdup(rvalue);
640 if (!n)
641 return log_oom();
7f110ff9 642 }
ed5bcfbe 643
8f2665a4
LP
644 free(*s);
645 *s = n;
646
ed5bcfbe
LP
647 return 0;
648}
57d42a5f 649
8f2665a4
LP
650int config_parse_path(
651 const char *unit,
652 const char *filename,
653 unsigned line,
654 const char *section,
655 unsigned section_line,
656 const char *lvalue,
657 int ltype,
658 const char *rvalue,
659 void *data,
660 void *userdata) {
034c6ed7 661
3b436292 662 char **s = data, *n;
034c6ed7
LP
663
664 assert(filename);
665 assert(lvalue);
666 assert(rvalue);
667 assert(data);
668
7f110ff9 669 if (!utf8_is_valid(rvalue)) {
b5d74213 670 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
7f110ff9
LP
671 return 0;
672 }
673
3b436292
LP
674 if (!path_is_absolute(rvalue)) {
675 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not an absolute path, ignoring: %s", rvalue);
f975e971 676 return 0;
034c6ed7
LP
677 }
678
7f110ff9
LP
679 n = strdup(rvalue);
680 if (!n)
74051b9b 681 return log_oom();
034c6ed7 682
01f78473
LP
683 path_kill_slashes(n);
684
034c6ed7
LP
685 free(*s);
686 *s = n;
687
688 return 0;
689}
57d42a5f 690
e8e581bf
ZJS
691int config_parse_strv(const char *unit,
692 const char *filename,
693 unsigned line,
694 const char *section,
71a61510 695 unsigned section_line,
e8e581bf
ZJS
696 const char *lvalue,
697 int ltype,
698 const char *rvalue,
699 void *data,
700 void *userdata) {
57d42a5f 701
a2a5291b
ZJS
702 char ***sv = data;
703 const char *word, *state;
57d42a5f 704 size_t l;
7f110ff9 705 int r;
57d42a5f
LP
706
707 assert(filename);
708 assert(lvalue);
709 assert(rvalue);
710 assert(data);
711
74051b9b 712 if (isempty(rvalue)) {
4589f5bb
LP
713 char **empty;
714
715 /* Empty assignment resets the list. As a special rule
716 * we actually fill in a real empty array here rather
717 * than NULL, since some code wants to know if
718 * something was set at all... */
719 empty = strv_new(NULL, NULL);
720 if (!empty)
721 return log_oom();
722
74051b9b 723 strv_free(*sv);
4589f5bb 724 *sv = empty;
853b8397 725 return 0;
74051b9b
LP
726 }
727
a2a5291b 728 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
6e18964d 729 char *n;
7f110ff9 730
a2a5291b 731 n = strndup(word, l);
853b8397
LP
732 if (!n)
733 return log_oom();
734
735 if (!utf8_is_valid(n)) {
b5d74213 736 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
9e602778 737 free(n);
7f110ff9
LP
738 continue;
739 }
740
6e18964d 741 r = strv_consume(sv, n);
853b8397
LP
742 if (r < 0)
743 return log_oom();
7f110ff9 744 }
b2fadec6
ZJS
745 if (!isempty(state))
746 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
747 "Trailing garbage, ignoring.");
57d42a5f 748
57d42a5f 749 return 0;
57d42a5f 750}
15ae422b 751
2ff7b0a5
LP
752int config_parse_mode(
753 const char *unit,
754 const char *filename,
755 unsigned line,
756 const char *section,
71a61510 757 unsigned section_line,
2ff7b0a5
LP
758 const char *lvalue,
759 int ltype,
760 const char *rvalue,
761 void *data,
762 void *userdata) {
f975e971
LP
763
764 mode_t *m = data;
f975e971
LP
765
766 assert(filename);
767 assert(lvalue);
768 assert(rvalue);
769 assert(data);
770
2ff7b0a5
LP
771 if (parse_mode(rvalue, m) < 0) {
772 log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse mode value, ignoring: %s", rvalue);
f975e971
LP
773 return 0;
774 }
775
f975e971
LP
776 return 0;
777}
213ba152 778
ca37242e
LP
779int config_parse_log_facility(
780 const char *unit,
781 const char *filename,
782 unsigned line,
783 const char *section,
784 unsigned section_line,
785 const char *lvalue,
786 int ltype,
787 const char *rvalue,
788 void *data,
789 void *userdata) {
213ba152
LP
790
791
792 int *o = data, x;
793
794 assert(filename);
795 assert(lvalue);
796 assert(rvalue);
797 assert(data);
798
799 x = log_facility_unshifted_from_string(rvalue);
800 if (x < 0) {
769d324c 801 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse log facility, ignoring: %s", rvalue);
213ba152
LP
802 return 0;
803 }
804
805 *o = (x << 3) | LOG_PRI(*o);
806
807 return 0;
808}
809
ca37242e
LP
810int config_parse_log_level(
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) {
213ba152
LP
821
822
823 int *o = data, x;
824
825 assert(filename);
826 assert(lvalue);
827 assert(rvalue);
828 assert(data);
829
830 x = log_level_from_string(rvalue);
831 if (x < 0) {
769d324c 832 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse log level, ignoring: %s", rvalue);
213ba152
LP
833 return 0;
834 }
835
836 *o = (*o & LOG_FACMASK) | x;
837 return 0;
838}
f757855e
LP
839
840int config_parse_signal(
841 const char *unit,
842 const char *filename,
843 unsigned line,
844 const char *section,
845 unsigned section_line,
846 const char *lvalue,
847 int ltype,
848 const char *rvalue,
849 void *data,
850 void *userdata) {
851
852 int *sig = data, r;
853
854 assert(filename);
855 assert(lvalue);
856 assert(rvalue);
857 assert(sig);
858
859 r = signal_from_string_try_harder(rvalue);
860 if (r <= 0) {
861 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse signal name, ignoring: %s", rvalue);
862 return 0;
863 }
864
865 *sig = r;
866 return 0;
867}
868
869int config_parse_personality(
870 const char *unit,
871 const char *filename,
872 unsigned line,
873 const char *section,
874 unsigned section_line,
875 const char *lvalue,
876 int ltype,
877 const char *rvalue,
878 void *data,
879 void *userdata) {
880
881 unsigned long *personality = data, p;
882
883 assert(filename);
884 assert(lvalue);
885 assert(rvalue);
886 assert(personality);
887
888 p = personality_from_string(rvalue);
889 if (p == PERSONALITY_INVALID) {
890 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse personality, ignoring: %s", rvalue);
891 return 0;
892 }
893
894 *personality = p;
895 return 0;
896}