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