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