Branch data 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 : 20904 : 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 [ - + ]: 20904 : assert(table);
47 [ - + ]: 20904 : assert(lvalue);
48 [ - + ]: 20904 : assert(func);
49 [ - + ]: 20904 : assert(ltype);
50 [ - + ]: 20904 : assert(data);
51 : :
52 [ + + ]: 116808 : for (t = table; t->lvalue; t++) {
53 : :
54 [ + + ]: 98300 : if (!streq(lvalue, t->lvalue))
55 : 95904 : continue;
56 : :
57 [ - + ]: 2396 : if (!streq_ptr(section, t->section))
58 : 0 : continue;
59 : :
60 : 2396 : *func = t->parse;
61 : 2396 : *ltype = t->ltype;
62 : 2396 : *data = t->data;
63 : 2396 : return 1;
64 : : }
65 : :
66 : 18508 : return 0;
67 : : }
68 : :
69 : 1516 : 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 : 1516 : ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
79 : : const ConfigPerfItem *p;
80 : :
81 [ - + ]: 1516 : assert(table);
82 [ - + ]: 1516 : assert(lvalue);
83 [ - + ]: 1516 : assert(func);
84 [ - + ]: 1516 : assert(ltype);
85 [ - + ]: 1516 : assert(data);
86 : :
87 [ + - ]: 1516 : if (section) {
88 : : const char *key;
89 : :
90 [ + + + - : 10612 : key = strjoina(section, ".", lvalue);
- + - + +
+ + - ]
91 : 1516 : p = lookup(key, strlen(key));
92 : : } else
93 : 0 : p = lookup(lvalue, strlen(lvalue));
94 [ - + ]: 1516 : if (!p)
95 : 0 : return 0;
96 : :
97 : 1516 : *func = p->parse;
98 : 1516 : *ltype = p->ltype;
99 : 1516 : *data = (uint8_t*) userdata + p->offset;
100 : 1516 : return 1;
101 : : }
102 : :
103 : : /* Run the user supplied parser for an assignment */
104 : 22420 : 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 : 22420 : ConfigParserCallback func = NULL;
118 : 22420 : int ltype = 0;
119 : 22420 : void *data = NULL;
120 : : int r;
121 : :
122 [ - + ]: 22420 : assert(filename);
123 [ - + ]: 22420 : assert(line > 0);
124 [ - + ]: 22420 : assert(lookup);
125 [ - + ]: 22420 : assert(lvalue);
126 [ - + ]: 22420 : assert(rvalue);
127 : :
128 : 22420 : r = lookup(table, section, lvalue, &func, <ype, &data, userdata);
129 [ - + ]: 22420 : if (r < 0)
130 : 0 : return r;
131 [ + + ]: 22420 : if (r > 0) {
132 [ + + ]: 3912 : if (func)
133 : 3884 : return func(unit, filename, line, section, section_line,
134 : : lvalue, ltype, rvalue, data, userdata);
135 : :
136 : 28 : return 0;
137 : : }
138 : :
139 : : /* Warn about unknown non-extension fields. */
140 [ - + # # ]: 18508 : 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 : 18508 : return 0;
145 : : }
146 : :
147 : : /* Parse a single logical line */
148 : 33604 : 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 [ - + ]: 33604 : assert(filename);
165 [ - + ]: 33604 : assert(line > 0);
166 [ - + ]: 33604 : assert(lookup);
167 [ - + ]: 33604 : assert(l);
168 : :
169 : 33604 : l = strstrip(l);
170 [ + + ]: 33604 : if (!*l)
171 : 4892 : return 0;
172 : :
173 [ - + ]: 28712 : if (*l == '\n')
174 : 0 : return 0;
175 : :
176 : 28712 : include = first_word(l, ".include");
177 [ - + ]: 28712 : 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 [ - + ]: 28712 : if (!utf8_is_valid(l))
206 [ # # ]: 0 : return log_syntax_invalid_utf8(unit, LOG_WARNING, filename, line, l);
207 : :
208 [ + + ]: 28712 : if (*l == '[') {
209 : : size_t k;
210 : : char *n;
211 : :
212 : 6292 : k = strlen(l);
213 [ - + ]: 6292 : assert(k > 0);
214 : :
215 [ - + ]: 6292 : 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 : 6292 : n = strndup(l+1, k-2);
221 [ - + ]: 6292 : if (!n)
222 : 0 : return -ENOMEM;
223 : :
224 [ + + - + ]: 6292 : 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 : 6292 : free_and_replace(*section, n);
235 : 6292 : *section_line = line;
236 : 6292 : *section_ignored = false;
237 : : }
238 : :
239 : 6292 : return 0;
240 : : }
241 : :
242 [ + + - + ]: 22420 : 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 : 22420 : e = strchr(l, '=');
250 [ - + ]: 22420 : if (!e)
251 [ # # ]: 0 : return log_syntax(unit, LOG_WARNING, filename, line, 0,
252 : : "Missing '=', ignoring line.");
253 [ - + ]: 22420 : if (e == l)
254 [ # # ]: 0 : return log_syntax(unit, LOG_WARNING, filename, line, 0,
255 : : "Missing key name before '=', ignoring line.");
256 : :
257 : 22420 : *e = 0;
258 : 22420 : e++;
259 : :
260 : 22420 : return next_assignment(unit,
261 : : filename,
262 : : line,
263 : : lookup,
264 : : table,
265 : : *section,
266 : : *section_line,
267 : 22420 : strstrip(l),
268 : 22420 : strstrip(e),
269 : : flags,
270 : : userdata);
271 : : }
272 : :
273 : : /* Go through the file and parse each line */
274 : 3448 : 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 : 3448 : _cleanup_free_ char *section = NULL, *continuation = NULL;
284 : 3448 : _cleanup_fclose_ FILE *ours = NULL;
285 : 3448 : unsigned line = 0, section_line = 0;
286 : 3448 : bool section_ignored = false;
287 : : int r;
288 : :
289 [ - + ]: 3448 : assert(filename);
290 [ - + ]: 3448 : assert(lookup);
291 : :
292 [ + + ]: 3448 : if (!f) {
293 : 76 : f = ours = fopen(filename, "re");
294 [ + + ]: 76 : if (!f) {
295 : : /* Only log on request, except for ENOENT,
296 : : * since we return 0 to the caller. */
297 [ - + # # ]: 52 : if ((flags & CONFIG_PARSE_WARN) || errno == ENOENT)
298 [ + - + + ]: 52 : log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno,
299 : : "Failed to open configuration file '%s': %m", filename);
300 [ - + ]: 52 : return errno == ENOENT ? 0 : -errno;
301 : : }
302 : : }
303 : :
304 : 3396 : fd_warn_permissions(filename, fileno(f));
305 : :
306 : 48180 : for (;;) {
307 [ + + + + ]: 51576 : _cleanup_free_ char *buf = NULL;
308 : 51576 : bool escaped = false;
309 : : char *l, *p, *e;
310 : :
311 : 51576 : r = read_line(f, LONG_LINE_MAX, &buf);
312 [ + + ]: 51576 : if (r == 0)
313 : 3388 : break;
314 [ + + ]: 48188 : if (r == -ENOBUFS) {
315 [ + - ]: 4 : if (flags & CONFIG_PARSE_WARN)
316 [ + - ]: 4 : log_error_errno(r, "%s:%u: Line too long", filename, line);
317 : :
318 : 4 : return r;
319 : : }
320 [ - + ]: 48184 : 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 : 48184 : l = skip_leading_chars(buf, WHITESPACE);
328 [ + + + + ]: 48184 : if (*l != '\0' && strchr(COMMENTS, *l))
329 : 10416 : continue;
330 : :
331 : 37768 : l = buf;
332 [ + - ]: 37768 : if (!(flags & CONFIG_PARSE_REFUSE_BOM)) {
333 : : char *q;
334 : :
335 : 37768 : q = startswith(buf, UTF8_BYTE_ORDER_MARK);
336 [ - + ]: 37768 : if (q) {
337 : 0 : l = q;
338 : 0 : flags |= CONFIG_PARSE_REFUSE_BOM;
339 : : }
340 : : }
341 : :
342 [ + + ]: 37768 : if (continuation) {
343 [ + + ]: 4160 : if (strlen(continuation) + strlen(l) > LONG_LINE_MAX) {
344 [ + - ]: 4 : if (flags & CONFIG_PARSE_WARN)
345 [ + - ]: 4 : log_error("%s:%u: Continuation line too long", filename, line);
346 : 4 : return -ENOBUFS;
347 : : }
348 : :
349 [ - + ]: 4156 : if (!strextend(&continuation, l, NULL)) {
350 [ # # ]: 0 : if (flags & CONFIG_PARSE_WARN)
351 : 0 : log_oom();
352 : 0 : return -ENOMEM;
353 : : }
354 : :
355 : 4156 : p = continuation;
356 : : } else
357 : 33608 : p = l;
358 : :
359 [ + + ]: 2092448592 : for (e = p; *e; e++) {
360 [ + + ]: 2092410828 : if (escaped)
361 : 164 : escaped = false;
362 [ + + ]: 2092410664 : else if (*e == '\\')
363 : 4332 : escaped = true;
364 : : }
365 : :
366 [ + + ]: 37764 : if (escaped) {
367 : 4168 : *(e-1) = ' ';
368 : :
369 [ + + ]: 4168 : if (!continuation) {
370 : 60 : continuation = strdup(l);
371 [ - + ]: 60 : if (!continuation) {
372 [ # # ]: 0 : if (flags & CONFIG_PARSE_WARN)
373 : 0 : log_oom();
374 : 0 : return -ENOMEM;
375 : : }
376 : : }
377 : :
378 : 4168 : continue;
379 : : }
380 : :
381 : 33596 : 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 [ - + ]: 33596 : 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 : 33596 : continuation = mfree(continuation);
400 : : }
401 : :
402 [ + + ]: 3388 : if (continuation) {
403 : 8 : 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 [ - + ]: 8 : 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 : 3388 : return 0;
423 : : }
424 : :
425 : 64 : 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 [ + - ]: 64 : if (conf_file) {
438 : 64 : r = config_parse(NULL, conf_file, NULL, sections, lookup, table, flags, userdata);
439 [ - + ]: 64 : if (r < 0)
440 : 0 : return r;
441 : : }
442 : :
443 [ + - - + ]: 64 : 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 : 64 : return 0;
450 : : }
451 : :
452 : : /* Parse each config file in the directories specified as nulstr. */
453 : 52 : 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 : 52 : _cleanup_strv_free_ char **files = NULL;
463 : : int r;
464 : :
465 : 52 : r = conf_files_list_nulstr(&files, ".conf", NULL, 0, conf_file_dirs);
466 [ - + ]: 52 : if (r < 0)
467 : 0 : return r;
468 : :
469 : 52 : 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 : 12 : 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 : 12 : _cleanup_strv_free_ char **dropin_dirs = NULL;
484 : 12 : _cleanup_strv_free_ char **files = NULL;
485 : : const char *suffix;
486 : : int r;
487 : :
488 [ + + + - : 60 : suffix = strjoina("/", dropin_dirname);
- + - + +
+ + - ]
489 : 12 : r = strv_extend_strv_concat(&dropin_dirs, (char**) conf_file_dirs, suffix);
490 [ - + ]: 12 : if (r < 0)
491 : 0 : return r;
492 : :
493 : 12 : r = conf_files_list_strv(&files, ".conf", NULL, 0, (const char* const*) dropin_dirs);
494 [ - + ]: 12 : if (r < 0)
495 : 0 : return r;
496 : :
497 : 12 : 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 [ - + - + : 28 : 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 [ - + - + : 28 : DEFINE_PARSER(unsigned, unsigned, safe_atou);
- + - + +
+ + - ]
510 [ # # # # : 0 : DEFINE_PARSER(double, double, safe_atod);
# # # # #
# # # ]
511 [ - + - + : 28 : DEFINE_PARSER(nsec, nsec_t, parse_nsec);
- + - + +
+ + - ]
512 [ - + - + : 28 : DEFINE_PARSER(sec, usec_t, parse_sec);
- + - + +
+ + - ]
513 [ # # # # : 0 : DEFINE_PARSER(sec_def_infinity, usec_t, parse_sec_def_infinity);
# # # # #
# # # ]
514 [ - + - + : 32 : DEFINE_PARSER(mode, mode_t, parse_mode);
- + - + +
+ + - ]
515 : :
516 : 36 : 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 : 36 : size_t *sz = data;
528 : : uint64_t v;
529 : : int r;
530 : :
531 [ - + ]: 36 : assert(filename);
532 [ - + ]: 36 : assert(lvalue);
533 [ - + ]: 36 : assert(rvalue);
534 [ - + ]: 36 : assert(data);
535 : :
536 : 36 : r = parse_size(rvalue, 1024, &v);
537 : : if (r >= 0 && (uint64_t) (size_t) v != v)
538 : : r = -ERANGE;
539 [ + + ]: 36 : if (r < 0) {
540 [ + - ]: 12 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value '%s', ignoring: %m", rvalue);
541 : 12 : return 0;
542 : : }
543 : :
544 : 24 : *sz = (size_t) v;
545 : 24 : return 0;
546 : : }
547 : :
548 : 36 : 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 : 36 : size_t *sz = data;
561 : : uint64_t v;
562 : : int r;
563 : :
564 [ - + ]: 36 : assert(filename);
565 [ - + ]: 36 : assert(lvalue);
566 [ - + ]: 36 : assert(rvalue);
567 [ - + ]: 36 : assert(data);
568 : :
569 : 36 : r = parse_size(rvalue, 1000, &v);
570 : : if (r >= 0 && (uint64_t) (size_t) v != v)
571 : : r = -ERANGE;
572 [ + + ]: 36 : if (r < 0) {
573 [ + - ]: 12 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value '%s', ignoring: %m", rvalue);
574 : 12 : return 0;
575 : : }
576 : :
577 : 24 : *sz = (size_t) v;
578 : 24 : return 0;
579 : : }
580 : :
581 : 8 : 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 : 8 : uint64_t *bytes = data;
594 : : int r;
595 : :
596 [ - + ]: 8 : assert(filename);
597 [ - + ]: 8 : assert(lvalue);
598 [ - + ]: 8 : assert(rvalue);
599 [ - + ]: 8 : assert(data);
600 : :
601 : 8 : r = parse_size(rvalue, 1024, bytes);
602 [ - + ]: 8 : if (r < 0)
603 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
604 : :
605 : 8 : return 0;
606 : : }
607 : :
608 : 80 : 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 : 80 : bool *b = data;
621 : 80 : bool fatal = ltype;
622 : :
623 [ - + ]: 80 : assert(filename);
624 [ - + ]: 80 : assert(lvalue);
625 [ - + ]: 80 : assert(rvalue);
626 [ - + ]: 80 : assert(data);
627 : :
628 : 80 : k = parse_boolean(rvalue);
629 [ - + ]: 80 : 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 : 80 : *b = k;
637 : 80 : 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 : 432 : 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 : 432 : char **s = data;
686 : :
687 [ - + ]: 432 : assert(filename);
688 [ - + ]: 432 : assert(lvalue);
689 [ - + ]: 432 : assert(rvalue);
690 [ - + ]: 432 : assert(data);
691 : :
692 [ - + ]: 432 : if (free_and_strdup(s, empty_to_null(rvalue)) < 0)
693 : 0 : return log_oom();
694 : :
695 : 432 : return 0;
696 : : }
697 : :
698 : 28 : 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 : 28 : _cleanup_free_ char *n = NULL;
711 : 28 : bool fatal = ltype;
712 : 28 : char **s = data;
713 : : int r;
714 : :
715 [ - + ]: 28 : assert(filename);
716 [ - + ]: 28 : assert(lvalue);
717 [ - + ]: 28 : assert(rvalue);
718 [ - + ]: 28 : assert(data);
719 : :
720 [ - + ]: 28 : if (isempty(rvalue))
721 : 0 : goto finalize;
722 : :
723 : 28 : n = strdup(rvalue);
724 [ - + ]: 28 : if (!n)
725 : 0 : return log_oom();
726 : :
727 [ - + ]: 28 : r = path_simplify_and_warn(n, PATH_CHECK_ABSOLUTE | (fatal ? PATH_CHECK_FATAL : 0), unit, filename, line, lvalue);
728 [ + + ]: 28 : if (r < 0)
729 [ - + ]: 8 : return fatal ? -ENOEXEC : 0;
730 : :
731 : 20 : finalize:
732 : 20 : return free_and_replace(*s, n);
733 : : }
734 : :
735 : 2040 : 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 : 2040 : char ***sv = data;
748 : : int r;
749 : :
750 [ - + ]: 2040 : assert(filename);
751 [ - + ]: 2040 : assert(lvalue);
752 [ - + ]: 2040 : assert(rvalue);
753 [ - + ]: 2040 : assert(data);
754 : :
755 [ + + ]: 2040 : if (isempty(rvalue)) {
756 : 4 : *sv = strv_free(*sv);
757 : 4 : return 0;
758 : : }
759 : :
760 : 2076 : for (;;) {
761 : 4112 : char *word = NULL;
762 : :
763 : 4112 : r = extract_first_word(&rvalue, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
764 [ + + ]: 4112 : if (r == 0)
765 : 2036 : break;
766 [ - + ]: 2076 : if (r == -ENOMEM)
767 : 0 : return log_oom();
768 [ - + ]: 2076 : if (r < 0) {
769 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
770 : 0 : break;
771 : : }
772 : :
773 : 2076 : r = strv_consume(sv, word);
774 [ - + ]: 2076 : if (r < 0)
775 : 0 : return log_oom();
776 : : }
777 : :
778 : 2036 : 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 : 12 : 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 : 12 : int *o = data, x;
829 : :
830 [ - + ]: 12 : assert(filename);
831 [ - + ]: 12 : assert(lvalue);
832 [ - + ]: 12 : assert(rvalue);
833 [ - + ]: 12 : assert(data);
834 : :
835 : 12 : x = log_facility_unshifted_from_string(rvalue);
836 [ + + ]: 12 : if (x < 0) {
837 [ + - ]: 4 : log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log facility, ignoring: %s", rvalue);
838 : 4 : return 0;
839 : : }
840 : :
841 : 8 : *o = (x << 3) | LOG_PRI(*o);
842 : :
843 : 8 : return 0;
844 : : }
845 : :
846 : 12 : 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 : 12 : int *o = data, x;
859 : :
860 [ - + ]: 12 : assert(filename);
861 [ - + ]: 12 : assert(lvalue);
862 [ - + ]: 12 : assert(rvalue);
863 [ - + ]: 12 : assert(data);
864 : :
865 : 12 : x = log_level_from_string(rvalue);
866 [ + + ]: 12 : if (x < 0) {
867 [ + - ]: 4 : log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log level, ignoring: %s", rvalue);
868 : 4 : return 0;
869 : : }
870 : :
871 [ - + ]: 8 : if (*o < 0) /* if it wasn't initialized so far, assume zero facility */
872 : 0 : *o = x;
873 : : else
874 : 8 : *o = (*o & LOG_FACMASK) | x;
875 : :
876 : 8 : 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 : 80 : 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 : 80 : struct rlimit **rl = data, d = {};
1063 : : int r;
1064 : :
1065 [ - + ]: 80 : assert(rvalue);
1066 [ - + ]: 80 : assert(rl);
1067 : :
1068 : 80 : r = rlimit_parse(ltype, rvalue, &d);
1069 [ + + ]: 80 : if (r == -EILSEQ) {
1070 [ + - ]: 4 : log_syntax(unit, LOG_WARNING, filename, line, r, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue);
1071 : 4 : return 0;
1072 : : }
1073 [ + + ]: 76 : if (r < 0) {
1074 [ + - ]: 12 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
1075 : 12 : return 0;
1076 : : }
1077 : :
1078 [ + + ]: 64 : if (rl[ltype])
1079 : 52 : *rl[ltype] = d;
1080 : : else {
1081 : 12 : rl[ltype] = newdup(struct rlimit, &d, 1);
1082 [ - + ]: 12 : if (!rl[ltype])
1083 : 0 : return log_oom();
1084 : : }
1085 : :
1086 : 64 : 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 : : }
|