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