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