Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1+ */
2 :
3 : #include <errno.h>
4 : #include <limits.h>
5 : #include <stdint.h>
6 : #include <stdio.h>
7 : #include <stdlib.h>
8 : #include <string.h>
9 : #include <sys/types.h>
10 :
11 : #include "alloc-util.h"
12 : #include "conf-files.h"
13 : #include "conf-parser.h"
14 : #include "def.h"
15 : #include "extract-word.h"
16 : #include "fd-util.h"
17 : #include "fileio.h"
18 : #include "fs-util.h"
19 : #include "log.h"
20 : #include "macro.h"
21 : #include "missing.h"
22 : #include "nulstr-util.h"
23 : #include "parse-util.h"
24 : #include "path-util.h"
25 : #include "process-util.h"
26 : #include "rlimit-util.h"
27 : #include "signal-util.h"
28 : #include "socket-util.h"
29 : #include "string-util.h"
30 : #include "strv.h"
31 : #include "syslog-util.h"
32 : #include "time-util.h"
33 : #include "utf8.h"
34 :
35 5226 : int config_item_table_lookup(
36 : const void *table,
37 : const char *section,
38 : const char *lvalue,
39 : ConfigParserCallback *func,
40 : int *ltype,
41 : void **data,
42 : void *userdata) {
43 :
44 : const ConfigTableItem *t;
45 :
46 5226 : assert(table);
47 5226 : assert(lvalue);
48 5226 : assert(func);
49 5226 : assert(ltype);
50 5226 : assert(data);
51 :
52 29202 : for (t = table; t->lvalue; t++) {
53 :
54 24575 : if (!streq(lvalue, t->lvalue))
55 23976 : continue;
56 :
57 599 : if (!streq_ptr(section, t->section))
58 0 : continue;
59 :
60 599 : *func = t->parse;
61 599 : *ltype = t->ltype;
62 599 : *data = t->data;
63 599 : return 1;
64 : }
65 :
66 4627 : return 0;
67 : }
68 :
69 379 : int config_item_perf_lookup(
70 : const void *table,
71 : const char *section,
72 : const char *lvalue,
73 : ConfigParserCallback *func,
74 : int *ltype,
75 : void **data,
76 : void *userdata) {
77 :
78 379 : ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
79 : const ConfigPerfItem *p;
80 :
81 379 : assert(table);
82 379 : assert(lvalue);
83 379 : assert(func);
84 379 : assert(ltype);
85 379 : assert(data);
86 :
87 379 : if (section) {
88 : const char *key;
89 :
90 2653 : key = strjoina(section, ".", lvalue);
91 379 : p = lookup(key, strlen(key));
92 : } else
93 0 : p = lookup(lvalue, strlen(lvalue));
94 379 : if (!p)
95 0 : return 0;
96 :
97 379 : *func = p->parse;
98 379 : *ltype = p->ltype;
99 379 : *data = (uint8_t*) userdata + p->offset;
100 379 : return 1;
101 : }
102 :
103 : /* Run the user supplied parser for an assignment */
104 5605 : static int next_assignment(
105 : const char *unit,
106 : const char *filename,
107 : unsigned line,
108 : ConfigItemLookup lookup,
109 : const void *table,
110 : const char *section,
111 : unsigned section_line,
112 : const char *lvalue,
113 : const char *rvalue,
114 : ConfigParseFlags flags,
115 : void *userdata) {
116 :
117 5605 : ConfigParserCallback func = NULL;
118 5605 : int ltype = 0;
119 5605 : void *data = NULL;
120 : int r;
121 :
122 5605 : assert(filename);
123 5605 : assert(line > 0);
124 5605 : assert(lookup);
125 5605 : assert(lvalue);
126 5605 : assert(rvalue);
127 :
128 5605 : r = lookup(table, section, lvalue, &func, <ype, &data, userdata);
129 5605 : if (r < 0)
130 0 : return r;
131 5605 : if (r > 0) {
132 978 : if (func)
133 971 : return func(unit, filename, line, section, section_line,
134 : lvalue, ltype, rvalue, data, userdata);
135 :
136 7 : return 0;
137 : }
138 :
139 : /* Warn about unknown non-extension fields. */
140 4627 : if (!(flags & CONFIG_PARSE_RELAXED) && !startswith(lvalue, "X-"))
141 0 : log_syntax(unit, LOG_WARNING, filename, line, 0,
142 : "Unknown key name '%s' in section '%s', ignoring.", lvalue, section);
143 :
144 4627 : return 0;
145 : }
146 :
147 : /* Parse a single logical line */
148 8401 : static int parse_line(
149 : const char* unit,
150 : const char *filename,
151 : unsigned line,
152 : const char *sections,
153 : ConfigItemLookup lookup,
154 : const void *table,
155 : ConfigParseFlags flags,
156 : char **section,
157 : unsigned *section_line,
158 : bool *section_ignored,
159 : char *l,
160 : void *userdata) {
161 :
162 : char *e, *include;
163 :
164 8401 : assert(filename);
165 8401 : assert(line > 0);
166 8401 : assert(lookup);
167 8401 : assert(l);
168 :
169 8401 : l = strstrip(l);
170 8401 : if (!*l)
171 1223 : return 0;
172 :
173 7178 : if (*l == '\n')
174 0 : return 0;
175 :
176 7178 : include = first_word(l, ".include");
177 7178 : if (include) {
178 0 : _cleanup_free_ char *fn = NULL;
179 :
180 : /* .includes are a bad idea, we only support them here
181 : * for historical reasons. They create cyclic include
182 : * problems and make it difficult to detect
183 : * configuration file changes with an easy
184 : * stat(). Better approaches, such as .d/ drop-in
185 : * snippets exist.
186 : *
187 : * Support for them should be eventually removed. */
188 :
189 0 : if (!(flags & CONFIG_PARSE_ALLOW_INCLUDE)) {
190 0 : log_syntax(unit, LOG_ERR, filename, line, 0, ".include not allowed here. Ignoring.");
191 0 : return 0;
192 : }
193 :
194 0 : log_syntax(unit, LOG_WARNING, filename, line, 0,
195 : ".include directives are deprecated, and support for them will be removed in a future version of systemd. "
196 : "Please use drop-in files instead.");
197 :
198 0 : fn = file_in_same_dir(filename, strstrip(include));
199 0 : if (!fn)
200 0 : return -ENOMEM;
201 :
202 0 : return config_parse(unit, fn, NULL, sections, lookup, table, flags, userdata);
203 : }
204 :
205 7178 : if (!utf8_is_valid(l))
206 0 : return log_syntax_invalid_utf8(unit, LOG_WARNING, filename, line, l);
207 :
208 7178 : if (*l == '[') {
209 : size_t k;
210 : char *n;
211 :
212 1573 : k = strlen(l);
213 1573 : assert(k > 0);
214 :
215 1573 : if (l[k-1] != ']') {
216 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid section header '%s'", l);
217 0 : return -EBADMSG;
218 : }
219 :
220 1573 : n = strndup(l+1, k-2);
221 1573 : if (!n)
222 0 : return -ENOMEM;
223 :
224 1573 : if (sections && !nulstr_contains(sections, n)) {
225 :
226 0 : if (!(flags & CONFIG_PARSE_RELAXED) && !startswith(n, "X-"))
227 0 : log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown section '%s'. Ignoring.", n);
228 :
229 0 : free(n);
230 0 : *section = mfree(*section);
231 0 : *section_line = 0;
232 0 : *section_ignored = true;
233 : } else {
234 1573 : free_and_replace(*section, n);
235 1573 : *section_line = line;
236 1573 : *section_ignored = false;
237 : }
238 :
239 1573 : return 0;
240 : }
241 :
242 5605 : if (sections && !*section) {
243 0 : if (!(flags & CONFIG_PARSE_RELAXED) && !*section_ignored)
244 0 : log_syntax(unit, LOG_WARNING, filename, line, 0, "Assignment outside of section. Ignoring.");
245 :
246 0 : return 0;
247 : }
248 :
249 5605 : e = strchr(l, '=');
250 5605 : if (!e)
251 0 : return log_syntax(unit, LOG_WARNING, filename, line, 0,
252 : "Missing '=', ignoring line.");
253 5605 : if (e == l)
254 0 : return log_syntax(unit, LOG_WARNING, filename, line, 0,
255 : "Missing key name before '=', ignoring line.");
256 :
257 5605 : *e = 0;
258 5605 : e++;
259 :
260 5605 : return next_assignment(unit,
261 : filename,
262 : line,
263 : lookup,
264 : table,
265 : *section,
266 : *section_line,
267 5605 : strstrip(l),
268 5605 : strstrip(e),
269 : flags,
270 : userdata);
271 : }
272 :
273 : /* Go through the file and parse each line */
274 862 : int config_parse(const char *unit,
275 : const char *filename,
276 : FILE *f,
277 : const char *sections,
278 : ConfigItemLookup lookup,
279 : const void *table,
280 : ConfigParseFlags flags,
281 : void *userdata) {
282 :
283 862 : _cleanup_free_ char *section = NULL, *continuation = NULL;
284 862 : _cleanup_fclose_ FILE *ours = NULL;
285 862 : unsigned line = 0, section_line = 0;
286 862 : bool section_ignored = false;
287 : int r;
288 :
289 862 : assert(filename);
290 862 : assert(lookup);
291 :
292 862 : if (!f) {
293 19 : f = ours = fopen(filename, "re");
294 19 : if (!f) {
295 : /* Only log on request, except for ENOENT,
296 : * since we return 0 to the caller. */
297 13 : if ((flags & CONFIG_PARSE_WARN) || errno == ENOENT)
298 13 : log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno,
299 : "Failed to open configuration file '%s': %m", filename);
300 13 : return errno == ENOENT ? 0 : -errno;
301 : }
302 : }
303 :
304 849 : fd_warn_permissions(filename, fileno(f));
305 :
306 12045 : for (;;) {
307 12894 : _cleanup_free_ char *buf = NULL;
308 12894 : bool escaped = false;
309 : char *l, *p, *e;
310 :
311 12894 : r = read_line(f, LONG_LINE_MAX, &buf);
312 12894 : if (r == 0)
313 847 : break;
314 12047 : if (r == -ENOBUFS) {
315 1 : if (flags & CONFIG_PARSE_WARN)
316 1 : log_error_errno(r, "%s:%u: Line too long", filename, line);
317 :
318 1 : return r;
319 : }
320 12046 : if (r < 0) {
321 : if (CONFIG_PARSE_WARN)
322 0 : log_error_errno(r, "%s:%u: Error while reading configuration file: %m", filename, line);
323 :
324 0 : return r;
325 : }
326 :
327 12046 : l = skip_leading_chars(buf, WHITESPACE);
328 12046 : if (*l != '\0' && strchr(COMMENTS, *l))
329 2604 : continue;
330 :
331 9442 : l = buf;
332 9442 : if (!(flags & CONFIG_PARSE_REFUSE_BOM)) {
333 : char *q;
334 :
335 9442 : q = startswith(buf, UTF8_BYTE_ORDER_MARK);
336 9442 : if (q) {
337 0 : l = q;
338 0 : flags |= CONFIG_PARSE_REFUSE_BOM;
339 : }
340 : }
341 :
342 9442 : if (continuation) {
343 1040 : if (strlen(continuation) + strlen(l) > LONG_LINE_MAX) {
344 1 : if (flags & CONFIG_PARSE_WARN)
345 1 : log_error("%s:%u: Continuation line too long", filename, line);
346 1 : return -ENOBUFS;
347 : }
348 :
349 1039 : if (!strextend(&continuation, l, NULL)) {
350 0 : if (flags & CONFIG_PARSE_WARN)
351 0 : log_oom();
352 0 : return -ENOMEM;
353 : }
354 :
355 1039 : p = continuation;
356 : } else
357 8402 : p = l;
358 :
359 523112148 : for (e = p; *e; e++) {
360 523102707 : if (escaped)
361 41 : escaped = false;
362 523102666 : else if (*e == '\\')
363 1083 : escaped = true;
364 : }
365 :
366 9441 : if (escaped) {
367 1042 : *(e-1) = ' ';
368 :
369 1042 : if (!continuation) {
370 15 : continuation = strdup(l);
371 15 : if (!continuation) {
372 0 : if (flags & CONFIG_PARSE_WARN)
373 0 : log_oom();
374 0 : return -ENOMEM;
375 : }
376 : }
377 :
378 1042 : continue;
379 : }
380 :
381 8399 : r = parse_line(unit,
382 : filename,
383 : ++line,
384 : sections,
385 : lookup,
386 : table,
387 : flags,
388 : §ion,
389 : §ion_line,
390 : §ion_ignored,
391 : p,
392 : userdata);
393 8399 : if (r < 0) {
394 0 : if (flags & CONFIG_PARSE_WARN)
395 0 : log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
396 0 : return r;
397 : }
398 :
399 8399 : continuation = mfree(continuation);
400 : }
401 :
402 847 : if (continuation) {
403 2 : r = parse_line(unit,
404 : filename,
405 : ++line,
406 : sections,
407 : lookup,
408 : table,
409 : flags,
410 : §ion,
411 : §ion_line,
412 : §ion_ignored,
413 : continuation,
414 : userdata);
415 2 : if (r < 0) {
416 0 : if (flags & CONFIG_PARSE_WARN)
417 0 : log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
418 0 : return r;
419 : }
420 : }
421 :
422 847 : return 0;
423 : }
424 :
425 16 : static int config_parse_many_files(
426 : const char *conf_file,
427 : char **files,
428 : const char *sections,
429 : ConfigItemLookup lookup,
430 : const void *table,
431 : ConfigParseFlags flags,
432 : void *userdata) {
433 :
434 : char **fn;
435 : int r;
436 :
437 16 : if (conf_file) {
438 16 : r = config_parse(NULL, conf_file, NULL, sections, lookup, table, flags, userdata);
439 16 : if (r < 0)
440 0 : return r;
441 : }
442 :
443 16 : STRV_FOREACH(fn, files) {
444 0 : r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata);
445 0 : if (r < 0)
446 0 : return r;
447 : }
448 :
449 16 : return 0;
450 : }
451 :
452 : /* Parse each config file in the directories specified as nulstr. */
453 13 : int config_parse_many_nulstr(
454 : const char *conf_file,
455 : const char *conf_file_dirs,
456 : const char *sections,
457 : ConfigItemLookup lookup,
458 : const void *table,
459 : ConfigParseFlags flags,
460 : void *userdata) {
461 :
462 13 : _cleanup_strv_free_ char **files = NULL;
463 : int r;
464 :
465 13 : r = conf_files_list_nulstr(&files, ".conf", NULL, 0, conf_file_dirs);
466 13 : if (r < 0)
467 0 : return r;
468 :
469 13 : return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata);
470 : }
471 :
472 : /* Parse each config file in the directories specified as strv. */
473 3 : int config_parse_many(
474 : const char *conf_file,
475 : const char* const* conf_file_dirs,
476 : const char *dropin_dirname,
477 : const char *sections,
478 : ConfigItemLookup lookup,
479 : const void *table,
480 : ConfigParseFlags flags,
481 : void *userdata) {
482 :
483 3 : _cleanup_strv_free_ char **dropin_dirs = NULL;
484 3 : _cleanup_strv_free_ char **files = NULL;
485 : const char *suffix;
486 : int r;
487 :
488 15 : suffix = strjoina("/", dropin_dirname);
489 3 : r = strv_extend_strv_concat(&dropin_dirs, (char**) conf_file_dirs, suffix);
490 3 : if (r < 0)
491 0 : return r;
492 :
493 3 : r = conf_files_list_strv(&files, ".conf", NULL, 0, (const char* const*) dropin_dirs);
494 3 : if (r < 0)
495 0 : return r;
496 :
497 3 : return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata);
498 : }
499 :
500 : #define DEFINE_PARSER(type, vartype, conv_func) \
501 : DEFINE_CONFIG_PARSE_PTR(config_parse_##type, conv_func, vartype, "Failed to parse " #type " value")
502 :
503 7 : DEFINE_PARSER(int, int, safe_atoi);
504 0 : DEFINE_PARSER(long, long, safe_atoli);
505 0 : DEFINE_PARSER(uint8, uint8_t, safe_atou8);
506 0 : DEFINE_PARSER(uint16, uint16_t, safe_atou16);
507 0 : DEFINE_PARSER(uint32, uint32_t, safe_atou32);
508 0 : DEFINE_PARSER(uint64, uint64_t, safe_atou64);
509 7 : DEFINE_PARSER(unsigned, unsigned, safe_atou);
510 0 : DEFINE_PARSER(double, double, safe_atod);
511 7 : DEFINE_PARSER(nsec, nsec_t, parse_nsec);
512 7 : DEFINE_PARSER(sec, usec_t, parse_sec);
513 0 : DEFINE_PARSER(sec_def_infinity, usec_t, parse_sec_def_infinity);
514 8 : DEFINE_PARSER(mode, mode_t, parse_mode);
515 :
516 9 : int config_parse_iec_size(const char* unit,
517 : const char *filename,
518 : unsigned line,
519 : const char *section,
520 : unsigned section_line,
521 : const char *lvalue,
522 : int ltype,
523 : const char *rvalue,
524 : void *data,
525 : void *userdata) {
526 :
527 9 : size_t *sz = data;
528 : uint64_t v;
529 : int r;
530 :
531 9 : assert(filename);
532 9 : assert(lvalue);
533 9 : assert(rvalue);
534 9 : assert(data);
535 :
536 9 : r = parse_size(rvalue, 1024, &v);
537 : if (r >= 0 && (uint64_t) (size_t) v != v)
538 : r = -ERANGE;
539 9 : if (r < 0) {
540 3 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value '%s', ignoring: %m", rvalue);
541 3 : return 0;
542 : }
543 :
544 6 : *sz = (size_t) v;
545 6 : return 0;
546 : }
547 :
548 9 : int config_parse_si_size(
549 : const char* unit,
550 : const char *filename,
551 : unsigned line,
552 : const char *section,
553 : unsigned section_line,
554 : const char *lvalue,
555 : int ltype,
556 : const char *rvalue,
557 : void *data,
558 : void *userdata) {
559 :
560 9 : size_t *sz = data;
561 : uint64_t v;
562 : int r;
563 :
564 9 : assert(filename);
565 9 : assert(lvalue);
566 9 : assert(rvalue);
567 9 : assert(data);
568 :
569 9 : r = parse_size(rvalue, 1000, &v);
570 : if (r >= 0 && (uint64_t) (size_t) v != v)
571 : r = -ERANGE;
572 9 : if (r < 0) {
573 3 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value '%s', ignoring: %m", rvalue);
574 3 : return 0;
575 : }
576 :
577 6 : *sz = (size_t) v;
578 6 : return 0;
579 : }
580 :
581 2 : int config_parse_iec_uint64(
582 : const char* unit,
583 : const char *filename,
584 : unsigned line,
585 : const char *section,
586 : unsigned section_line,
587 : const char *lvalue,
588 : int ltype,
589 : const char *rvalue,
590 : void *data,
591 : void *userdata) {
592 :
593 2 : uint64_t *bytes = data;
594 : int r;
595 :
596 2 : assert(filename);
597 2 : assert(lvalue);
598 2 : assert(rvalue);
599 2 : assert(data);
600 :
601 2 : r = parse_size(rvalue, 1024, bytes);
602 2 : if (r < 0)
603 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
604 :
605 2 : return 0;
606 : }
607 :
608 20 : int config_parse_bool(const char* unit,
609 : const char *filename,
610 : unsigned line,
611 : const char *section,
612 : unsigned section_line,
613 : const char *lvalue,
614 : int ltype,
615 : const char *rvalue,
616 : void *data,
617 : void *userdata) {
618 :
619 : int k;
620 20 : bool *b = data;
621 20 : bool fatal = ltype;
622 :
623 20 : assert(filename);
624 20 : assert(lvalue);
625 20 : assert(rvalue);
626 20 : assert(data);
627 :
628 20 : k = parse_boolean(rvalue);
629 20 : if (k < 0) {
630 0 : log_syntax(unit, LOG_ERR, filename, line, k,
631 : "Failed to parse boolean value%s: %s",
632 : fatal ? "" : ", ignoring", rvalue);
633 0 : return fatal ? -ENOEXEC : 0;
634 : }
635 :
636 20 : *b = k;
637 20 : return 0;
638 : }
639 :
640 0 : int config_parse_tristate(
641 : const char* unit,
642 : const char *filename,
643 : unsigned line,
644 : const char *section,
645 : unsigned section_line,
646 : const char *lvalue,
647 : int ltype,
648 : const char *rvalue,
649 : void *data,
650 : void *userdata) {
651 :
652 0 : int k, *t = data;
653 :
654 0 : assert(filename);
655 0 : assert(lvalue);
656 0 : assert(rvalue);
657 0 : assert(data);
658 :
659 : /* A tristate is pretty much a boolean, except that it can
660 : * also take the special value -1, indicating "uninitialized",
661 : * much like NULL is for a pointer type. */
662 :
663 0 : k = parse_boolean(rvalue);
664 0 : if (k < 0) {
665 0 : log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
666 0 : return 0;
667 : }
668 :
669 0 : *t = !!k;
670 0 : return 0;
671 : }
672 :
673 108 : int config_parse_string(
674 : const char *unit,
675 : const char *filename,
676 : unsigned line,
677 : const char *section,
678 : unsigned section_line,
679 : const char *lvalue,
680 : int ltype,
681 : const char *rvalue,
682 : void *data,
683 : void *userdata) {
684 :
685 108 : char **s = data;
686 :
687 108 : assert(filename);
688 108 : assert(lvalue);
689 108 : assert(rvalue);
690 108 : assert(data);
691 :
692 108 : if (free_and_strdup(s, empty_to_null(rvalue)) < 0)
693 0 : return log_oom();
694 :
695 108 : return 0;
696 : }
697 :
698 7 : int config_parse_path(
699 : const char *unit,
700 : const char *filename,
701 : unsigned line,
702 : const char *section,
703 : unsigned section_line,
704 : const char *lvalue,
705 : int ltype,
706 : const char *rvalue,
707 : void *data,
708 : void *userdata) {
709 :
710 7 : _cleanup_free_ char *n = NULL;
711 7 : bool fatal = ltype;
712 7 : char **s = data;
713 : int r;
714 :
715 7 : assert(filename);
716 7 : assert(lvalue);
717 7 : assert(rvalue);
718 7 : assert(data);
719 :
720 7 : if (isempty(rvalue))
721 0 : goto finalize;
722 :
723 7 : n = strdup(rvalue);
724 7 : if (!n)
725 0 : return log_oom();
726 :
727 7 : r = path_simplify_and_warn(n, PATH_CHECK_ABSOLUTE | (fatal ? PATH_CHECK_FATAL : 0), unit, filename, line, lvalue);
728 7 : if (r < 0)
729 2 : return fatal ? -ENOEXEC : 0;
730 :
731 5 : finalize:
732 5 : return free_and_replace(*s, n);
733 : }
734 :
735 510 : int config_parse_strv(
736 : const char *unit,
737 : const char *filename,
738 : unsigned line,
739 : const char *section,
740 : unsigned section_line,
741 : const char *lvalue,
742 : int ltype,
743 : const char *rvalue,
744 : void *data,
745 : void *userdata) {
746 :
747 510 : char ***sv = data;
748 : int r;
749 :
750 510 : assert(filename);
751 510 : assert(lvalue);
752 510 : assert(rvalue);
753 510 : assert(data);
754 :
755 510 : if (isempty(rvalue)) {
756 1 : *sv = strv_free(*sv);
757 1 : return 0;
758 : }
759 :
760 519 : for (;;) {
761 1028 : char *word = NULL;
762 :
763 1028 : r = extract_first_word(&rvalue, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
764 1028 : if (r == 0)
765 509 : break;
766 519 : if (r == -ENOMEM)
767 0 : return log_oom();
768 519 : if (r < 0) {
769 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
770 0 : break;
771 : }
772 :
773 519 : r = strv_consume(sv, word);
774 519 : if (r < 0)
775 0 : return log_oom();
776 : }
777 :
778 509 : return 0;
779 : }
780 :
781 0 : int config_parse_warn_compat(
782 : const char *unit,
783 : const char *filename,
784 : unsigned line,
785 : const char *section,
786 : unsigned section_line,
787 : const char *lvalue,
788 : int ltype,
789 : const char *rvalue,
790 : void *data,
791 : void *userdata) {
792 :
793 0 : Disabled reason = ltype;
794 :
795 0 : switch(reason) {
796 :
797 0 : case DISABLED_CONFIGURATION:
798 0 : log_syntax(unit, LOG_DEBUG, filename, line, 0,
799 : "Support for option %s= has been disabled at compile time and it is ignored", lvalue);
800 0 : break;
801 :
802 0 : case DISABLED_LEGACY:
803 0 : log_syntax(unit, LOG_INFO, filename, line, 0,
804 : "Support for option %s= has been removed and it is ignored", lvalue);
805 0 : break;
806 :
807 0 : case DISABLED_EXPERIMENTAL:
808 0 : log_syntax(unit, LOG_INFO, filename, line, 0,
809 : "Support for option %s= has not yet been enabled and it is ignored", lvalue);
810 0 : break;
811 : }
812 :
813 0 : return 0;
814 : }
815 :
816 3 : int config_parse_log_facility(
817 : const char *unit,
818 : const char *filename,
819 : unsigned line,
820 : const char *section,
821 : unsigned section_line,
822 : const char *lvalue,
823 : int ltype,
824 : const char *rvalue,
825 : void *data,
826 : void *userdata) {
827 :
828 3 : int *o = data, x;
829 :
830 3 : assert(filename);
831 3 : assert(lvalue);
832 3 : assert(rvalue);
833 3 : assert(data);
834 :
835 3 : x = log_facility_unshifted_from_string(rvalue);
836 3 : if (x < 0) {
837 1 : log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log facility, ignoring: %s", rvalue);
838 1 : return 0;
839 : }
840 :
841 2 : *o = (x << 3) | LOG_PRI(*o);
842 :
843 2 : return 0;
844 : }
845 :
846 3 : int config_parse_log_level(
847 : const char *unit,
848 : const char *filename,
849 : unsigned line,
850 : const char *section,
851 : unsigned section_line,
852 : const char *lvalue,
853 : int ltype,
854 : const char *rvalue,
855 : void *data,
856 : void *userdata) {
857 :
858 3 : int *o = data, x;
859 :
860 3 : assert(filename);
861 3 : assert(lvalue);
862 3 : assert(rvalue);
863 3 : assert(data);
864 :
865 3 : x = log_level_from_string(rvalue);
866 3 : if (x < 0) {
867 1 : log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log level, ignoring: %s", rvalue);
868 1 : return 0;
869 : }
870 :
871 2 : if (*o < 0) /* if it wasn't initialized so far, assume zero facility */
872 0 : *o = x;
873 : else
874 2 : *o = (*o & LOG_FACMASK) | x;
875 :
876 2 : return 0;
877 : }
878 :
879 0 : int config_parse_signal(
880 : const char *unit,
881 : const char *filename,
882 : unsigned line,
883 : const char *section,
884 : unsigned section_line,
885 : const char *lvalue,
886 : int ltype,
887 : const char *rvalue,
888 : void *data,
889 : void *userdata) {
890 :
891 0 : int *sig = data, r;
892 :
893 0 : assert(filename);
894 0 : assert(lvalue);
895 0 : assert(rvalue);
896 0 : assert(sig);
897 :
898 0 : r = signal_from_string(rvalue);
899 0 : if (r <= 0) {
900 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse signal name, ignoring: %s", rvalue);
901 0 : return 0;
902 : }
903 :
904 0 : *sig = r;
905 0 : return 0;
906 : }
907 :
908 0 : int config_parse_personality(
909 : const char *unit,
910 : const char *filename,
911 : unsigned line,
912 : const char *section,
913 : unsigned section_line,
914 : const char *lvalue,
915 : int ltype,
916 : const char *rvalue,
917 : void *data,
918 : void *userdata) {
919 :
920 0 : unsigned long *personality = data, p;
921 :
922 0 : assert(filename);
923 0 : assert(lvalue);
924 0 : assert(rvalue);
925 0 : assert(personality);
926 :
927 0 : if (isempty(rvalue))
928 0 : p = PERSONALITY_INVALID;
929 : else {
930 0 : p = personality_from_string(rvalue);
931 0 : if (p == PERSONALITY_INVALID) {
932 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse personality, ignoring: %s", rvalue);
933 0 : return 0;
934 : }
935 : }
936 :
937 0 : *personality = p;
938 0 : return 0;
939 : }
940 :
941 0 : int config_parse_ifname(
942 : const char *unit,
943 : const char *filename,
944 : unsigned line,
945 : const char *section,
946 : unsigned section_line,
947 : const char *lvalue,
948 : int ltype,
949 : const char *rvalue,
950 : void *data,
951 : void *userdata) {
952 :
953 0 : char **s = data;
954 : int r;
955 :
956 0 : assert(filename);
957 0 : assert(lvalue);
958 0 : assert(rvalue);
959 0 : assert(data);
960 :
961 0 : if (isempty(rvalue)) {
962 0 : *s = mfree(*s);
963 0 : return 0;
964 : }
965 :
966 0 : if (!ifname_valid(rvalue)) {
967 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue);
968 0 : return 0;
969 : }
970 :
971 0 : r = free_and_strdup(s, rvalue);
972 0 : if (r < 0)
973 0 : return log_oom();
974 :
975 0 : return 0;
976 : }
977 :
978 0 : int config_parse_ip_port(
979 : const char *unit,
980 : const char *filename,
981 : unsigned line,
982 : const char *section,
983 : unsigned section_line,
984 : const char *lvalue,
985 : int ltype,
986 : const char *rvalue,
987 : void *data,
988 : void *userdata) {
989 :
990 0 : uint16_t *s = data;
991 : uint16_t port;
992 : int r;
993 :
994 0 : assert(filename);
995 0 : assert(lvalue);
996 0 : assert(rvalue);
997 0 : assert(data);
998 :
999 0 : if (isempty(rvalue)) {
1000 0 : *s = 0;
1001 0 : return 0;
1002 : }
1003 :
1004 0 : r = parse_ip_port(rvalue, &port);
1005 0 : if (r < 0) {
1006 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse port '%s'.", rvalue);
1007 0 : return 0;
1008 : }
1009 :
1010 0 : *s = port;
1011 :
1012 0 : return 0;
1013 : }
1014 :
1015 0 : int config_parse_mtu(
1016 : const char *unit,
1017 : const char *filename,
1018 : unsigned line,
1019 : const char *section,
1020 : unsigned section_line,
1021 : const char *lvalue,
1022 : int ltype,
1023 : const char *rvalue,
1024 : void *data,
1025 : void *userdata) {
1026 :
1027 0 : uint32_t *mtu = data;
1028 : int r;
1029 :
1030 0 : assert(rvalue);
1031 0 : assert(mtu);
1032 :
1033 0 : r = parse_mtu(ltype, rvalue, mtu);
1034 0 : if (r == -ERANGE) {
1035 0 : log_syntax(unit, LOG_ERR, filename, line, r,
1036 : "Maximum transfer unit (MTU) value out of range. Permitted range is %" PRIu32 "…%" PRIu32 ", ignoring: %s",
1037 : (uint32_t) (ltype == AF_INET6 ? IPV6_MIN_MTU : IPV4_MIN_MTU), (uint32_t) UINT32_MAX,
1038 : rvalue);
1039 0 : return 0;
1040 : }
1041 0 : if (r < 0) {
1042 0 : log_syntax(unit, LOG_ERR, filename, line, r,
1043 : "Failed to parse MTU value '%s', ignoring: %m", rvalue);
1044 0 : return 0;
1045 : }
1046 :
1047 0 : return 0;
1048 : }
1049 :
1050 20 : int config_parse_rlimit(
1051 : const char *unit,
1052 : const char *filename,
1053 : unsigned line,
1054 : const char *section,
1055 : unsigned section_line,
1056 : const char *lvalue,
1057 : int ltype,
1058 : const char *rvalue,
1059 : void *data,
1060 : void *userdata) {
1061 :
1062 20 : struct rlimit **rl = data, d = {};
1063 : int r;
1064 :
1065 20 : assert(rvalue);
1066 20 : assert(rl);
1067 :
1068 20 : r = rlimit_parse(ltype, rvalue, &d);
1069 20 : if (r == -EILSEQ) {
1070 1 : log_syntax(unit, LOG_WARNING, filename, line, r, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue);
1071 1 : return 0;
1072 : }
1073 19 : if (r < 0) {
1074 3 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
1075 3 : return 0;
1076 : }
1077 :
1078 16 : if (rl[ltype])
1079 13 : *rl[ltype] = d;
1080 : else {
1081 3 : rl[ltype] = newdup(struct rlimit, &d, 1);
1082 3 : if (!rl[ltype])
1083 0 : return log_oom();
1084 : }
1085 :
1086 16 : return 0;
1087 : }
1088 :
1089 0 : int config_parse_permille(const char* unit,
1090 : const char *filename,
1091 : unsigned line,
1092 : const char *section,
1093 : unsigned section_line,
1094 : const char *lvalue,
1095 : int ltype,
1096 : const char *rvalue,
1097 : void *data,
1098 : void *userdata) {
1099 :
1100 0 : unsigned *permille = data;
1101 : int r;
1102 :
1103 0 : assert(filename);
1104 0 : assert(lvalue);
1105 0 : assert(rvalue);
1106 0 : assert(permille);
1107 :
1108 0 : r = parse_permille(rvalue);
1109 0 : if (r < 0) {
1110 0 : log_syntax(unit, LOG_ERR, filename, line, r,
1111 : "Failed to parse permille value, ignoring: %s", rvalue);
1112 0 : return 0;
1113 : }
1114 :
1115 0 : *permille = (unsigned) r;
1116 :
1117 0 : return 0;
1118 : }
|