]>
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 LP |
22 | #include <string.h> |
23 | #include <stdio.h> | |
24 | #include <errno.h> | |
ed5bcfbe LP |
25 | #include <stdlib.h> |
26 | ||
f757855e | 27 | #include "sd-messages.h" |
e8461023 | 28 | #include "conf-files.h" |
ed5bcfbe LP |
29 | #include "util.h" |
30 | #include "macro.h" | |
57d42a5f | 31 | #include "strv.h" |
16354eff | 32 | #include "log.h" |
7f110ff9 | 33 | #include "utf8.h" |
9eb977db | 34 | #include "path-util.h" |
f757855e LP |
35 | #include "signal-util.h" |
36 | #include "conf-parser.h" | |
e8e581bf | 37 | |
f975e971 | 38 | int config_item_table_lookup( |
e9f3d2d5 | 39 | const void *table, |
ed5bcfbe | 40 | const char *section, |
ed5bcfbe | 41 | const char *lvalue, |
f975e971 LP |
42 | ConfigParserCallback *func, |
43 | int *ltype, | |
44 | void **data, | |
ed5bcfbe LP |
45 | void *userdata) { |
46 | ||
e9f3d2d5 | 47 | const ConfigTableItem *t; |
f975e971 LP |
48 | |
49 | assert(table); | |
ed5bcfbe | 50 | assert(lvalue); |
f975e971 LP |
51 | assert(func); |
52 | assert(ltype); | |
53 | assert(data); | |
ed5bcfbe | 54 | |
f975e971 | 55 | for (t = table; t->lvalue; t++) { |
ed5bcfbe | 56 | |
f975e971 | 57 | if (!streq(lvalue, t->lvalue)) |
ed5bcfbe LP |
58 | continue; |
59 | ||
f975e971 | 60 | if (!streq_ptr(section, t->section)) |
ed5bcfbe LP |
61 | continue; |
62 | ||
f975e971 LP |
63 | *func = t->parse; |
64 | *ltype = t->ltype; | |
65 | *data = t->data; | |
66 | return 1; | |
67 | } | |
ed5bcfbe | 68 | |
f975e971 LP |
69 | return 0; |
70 | } | |
10e87ee7 | 71 | |
f975e971 | 72 | int config_item_perf_lookup( |
e9f3d2d5 | 73 | const void *table, |
f975e971 LP |
74 | const char *section, |
75 | const char *lvalue, | |
76 | ConfigParserCallback *func, | |
77 | int *ltype, | |
78 | void **data, | |
79 | void *userdata) { | |
80 | ||
81 | ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table; | |
82 | const ConfigPerfItem *p; | |
83 | ||
84 | assert(table); | |
85 | assert(lvalue); | |
86 | assert(func); | |
87 | assert(ltype); | |
88 | assert(data); | |
89 | ||
90 | if (!section) | |
91 | p = lookup(lvalue, strlen(lvalue)); | |
92 | else { | |
93 | char *key; | |
94 | ||
b7def684 | 95 | key = strjoin(section, ".", lvalue, NULL); |
44d91056 | 96 | if (!key) |
f975e971 LP |
97 | return -ENOMEM; |
98 | ||
99 | p = lookup(key, strlen(key)); | |
100 | free(key); | |
ed5bcfbe LP |
101 | } |
102 | ||
f975e971 LP |
103 | if (!p) |
104 | return 0; | |
105 | ||
106 | *func = p->parse; | |
107 | *ltype = p->ltype; | |
108 | *data = (uint8_t*) userdata + p->offset; | |
109 | return 1; | |
110 | } | |
111 | ||
112 | /* Run the user supplied parser for an assignment */ | |
e8e581bf ZJS |
113 | static int next_assignment(const char *unit, |
114 | const char *filename, | |
115 | unsigned line, | |
116 | ConfigItemLookup lookup, | |
e9f3d2d5 | 117 | const void *table, |
e8e581bf | 118 | const char *section, |
71a61510 | 119 | unsigned section_line, |
e8e581bf ZJS |
120 | const char *lvalue, |
121 | const char *rvalue, | |
122 | bool relaxed, | |
123 | void *userdata) { | |
f975e971 LP |
124 | |
125 | ConfigParserCallback func = NULL; | |
126 | int ltype = 0; | |
127 | void *data = NULL; | |
128 | int r; | |
129 | ||
130 | assert(filename); | |
131 | assert(line > 0); | |
132 | assert(lookup); | |
133 | assert(lvalue); | |
134 | assert(rvalue); | |
135 | ||
136 | r = lookup(table, section, lvalue, &func, <ype, &data, userdata); | |
137 | if (r < 0) | |
138 | return r; | |
139 | ||
d937fbbd LP |
140 | if (r > 0) { |
141 | if (func) | |
71a61510 TG |
142 | return func(unit, filename, line, section, section_line, |
143 | lvalue, ltype, rvalue, data, userdata); | |
d937fbbd LP |
144 | |
145 | return 0; | |
146 | } | |
f975e971 | 147 | |
46205bb6 | 148 | /* Warn about unknown non-extension fields. */ |
10e87ee7 | 149 | if (!relaxed && !startswith(lvalue, "X-")) |
e8e581bf ZJS |
150 | log_syntax(unit, LOG_WARNING, filename, line, EINVAL, |
151 | "Unknown lvalue '%s' in section '%s'", lvalue, section); | |
46205bb6 | 152 | |
f1857be0 | 153 | return 0; |
ed5bcfbe LP |
154 | } |
155 | ||
ed5bcfbe | 156 | /* Parse a variable assignment line */ |
e8e581bf ZJS |
157 | static int parse_line(const char* unit, |
158 | const char *filename, | |
159 | unsigned line, | |
160 | const char *sections, | |
161 | ConfigItemLookup lookup, | |
e9f3d2d5 | 162 | const void *table, |
e8e581bf | 163 | bool relaxed, |
db5c0122 | 164 | bool allow_include, |
e8e581bf | 165 | char **section, |
71a61510 | 166 | unsigned *section_line, |
342aea19 | 167 | bool *section_ignored, |
e8e581bf ZJS |
168 | char *l, |
169 | void *userdata) { | |
f975e971 | 170 | |
b2aa81ef | 171 | char *e; |
ed5bcfbe | 172 | |
f975e971 LP |
173 | assert(filename); |
174 | assert(line > 0); | |
175 | assert(lookup); | |
176 | assert(l); | |
177 | ||
b2aa81ef | 178 | l = strstrip(l); |
ed5bcfbe | 179 | |
b2aa81ef | 180 | if (!*l) |
ed5bcfbe | 181 | return 0; |
1ea86b18 | 182 | |
d3b6d0c2 | 183 | if (strchr(COMMENTS "\n", *l)) |
1ea86b18 | 184 | return 0; |
ed5bcfbe | 185 | |
b2aa81ef | 186 | if (startswith(l, ".include ")) { |
db5c0122 LP |
187 | _cleanup_free_ char *fn = NULL; |
188 | ||
b8e7a47b LP |
189 | /* .includes are a bad idea, we only support them here |
190 | * for historical reasons. They create cyclic include | |
191 | * problems and make it difficult to detect | |
192 | * configuration file changes with an easy | |
193 | * stat(). Better approaches, such as .d/ drop-in | |
194 | * snippets exist. | |
195 | * | |
196 | * Support for them should be eventually removed. */ | |
197 | ||
db5c0122 LP |
198 | if (!allow_include) { |
199 | log_syntax(unit, LOG_ERR, filename, line, EBADMSG, | |
200 | ".include not allowed here. Ignoring."); | |
201 | return 0; | |
202 | } | |
ed5bcfbe | 203 | |
f975e971 LP |
204 | fn = file_in_same_dir(filename, strstrip(l+9)); |
205 | if (!fn) | |
b2aa81ef | 206 | return -ENOMEM; |
ed5bcfbe | 207 | |
36f822c4 | 208 | return config_parse(unit, fn, NULL, sections, lookup, table, relaxed, false, false, userdata); |
ed5bcfbe LP |
209 | } |
210 | ||
b2aa81ef | 211 | if (*l == '[') { |
ed5bcfbe LP |
212 | size_t k; |
213 | char *n; | |
214 | ||
b2aa81ef | 215 | k = strlen(l); |
ed5bcfbe LP |
216 | assert(k > 0); |
217 | ||
b2aa81ef | 218 | if (l[k-1] != ']') { |
e8e581bf ZJS |
219 | log_syntax(unit, LOG_ERR, filename, line, EBADMSG, |
220 | "Invalid section header '%s'", l); | |
ed5bcfbe LP |
221 | return -EBADMSG; |
222 | } | |
223 | ||
f975e971 LP |
224 | n = strndup(l+1, k-2); |
225 | if (!n) | |
ed5bcfbe LP |
226 | return -ENOMEM; |
227 | ||
f975e971 | 228 | if (sections && !nulstr_contains(sections, n)) { |
42f4e3c4 | 229 | |
342aea19 | 230 | if (!relaxed && !startswith(n, "X-")) |
e8e581bf ZJS |
231 | log_syntax(unit, LOG_WARNING, filename, line, EINVAL, |
232 | "Unknown section '%s'. Ignoring.", n); | |
f975e971 LP |
233 | |
234 | free(n); | |
91ffff96 | 235 | free(*section); |
f975e971 | 236 | *section = NULL; |
71a61510 | 237 | *section_line = 0; |
342aea19 | 238 | *section_ignored = true; |
f975e971 LP |
239 | } else { |
240 | free(*section); | |
241 | *section = n; | |
71a61510 | 242 | *section_line = line; |
342aea19 | 243 | *section_ignored = false; |
f975e971 | 244 | } |
ed5bcfbe LP |
245 | |
246 | return 0; | |
247 | } | |
248 | ||
62f168a0 LP |
249 | if (sections && !*section) { |
250 | ||
342aea19 | 251 | if (!relaxed && !*section_ignored) |
e8e581bf ZJS |
252 | log_syntax(unit, LOG_WARNING, filename, line, EINVAL, |
253 | "Assignment outside of section. Ignoring."); | |
62f168a0 | 254 | |
10e87ee7 | 255 | return 0; |
62f168a0 | 256 | } |
10e87ee7 | 257 | |
f975e971 LP |
258 | e = strchr(l, '='); |
259 | if (!e) { | |
e8e581bf | 260 | log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Missing '='."); |
ed5bcfbe LP |
261 | return -EBADMSG; |
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) \ |
e8e581bf ZJS |
424 | int config_parse_##type(const char *unit, \ |
425 | const char *filename, \ | |
eb3491d9 ZJS |
426 | unsigned line, \ |
427 | const char *section, \ | |
71a61510 | 428 | unsigned section_line, \ |
eb3491d9 ZJS |
429 | const char *lvalue, \ |
430 | int ltype, \ | |
431 | const char *rvalue, \ | |
432 | void *data, \ | |
433 | void *userdata) { \ | |
434 | \ | |
435 | vartype *i = data; \ | |
436 | int r; \ | |
437 | \ | |
438 | assert(filename); \ | |
439 | assert(lvalue); \ | |
440 | assert(rvalue); \ | |
441 | assert(data); \ | |
442 | \ | |
443 | r = conv_func(rvalue, i); \ | |
444 | if (r < 0) \ | |
e8e581bf ZJS |
445 | log_syntax(unit, LOG_ERR, filename, line, -r, \ |
446 | "Failed to parse %s value, ignoring: %s", \ | |
98d75800 | 447 | #type, rvalue); \ |
eb3491d9 ZJS |
448 | \ |
449 | return 0; \ | |
ed5bcfbe LP |
450 | } |
451 | ||
eb3491d9 ZJS |
452 | DEFINE_PARSER(int, int, safe_atoi) |
453 | DEFINE_PARSER(long, long, safe_atoli) | |
9b3a67c5 | 454 | DEFINE_PARSER(uint32, uint32_t, safe_atou32) |
eb3491d9 ZJS |
455 | DEFINE_PARSER(uint64, uint64_t, safe_atou64) |
456 | DEFINE_PARSER(unsigned, unsigned, safe_atou) | |
457 | DEFINE_PARSER(double, double, safe_atod) | |
458 | DEFINE_PARSER(nsec, nsec_t, parse_nsec) | |
459 | DEFINE_PARSER(sec, usec_t, parse_sec) | |
ed5bcfbe | 460 | |
5556b5fe | 461 | int config_parse_iec_size(const char* unit, |
e8e581bf ZJS |
462 | const char *filename, |
463 | unsigned line, | |
464 | const char *section, | |
71a61510 | 465 | unsigned section_line, |
e8e581bf ZJS |
466 | const char *lvalue, |
467 | int ltype, | |
468 | const char *rvalue, | |
469 | void *data, | |
470 | void *userdata) { | |
ed5bcfbe LP |
471 | |
472 | size_t *sz = data; | |
9ba1a159 | 473 | off_t o; |
e8e581bf | 474 | int r; |
ed5bcfbe LP |
475 | |
476 | assert(filename); | |
477 | assert(lvalue); | |
478 | assert(rvalue); | |
479 | assert(data); | |
480 | ||
5556b5fe | 481 | r = parse_size(rvalue, 1024, &o); |
e8e581bf | 482 | if (r < 0 || (off_t) (size_t) o != o) { |
5556b5fe | 483 | log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue); |
9ba1a159 LP |
484 | return 0; |
485 | } | |
486 | ||
487 | *sz = (size_t) o; | |
488 | return 0; | |
489 | } | |
490 | ||
5556b5fe LP |
491 | int config_parse_si_size(const char* unit, |
492 | const char *filename, | |
493 | unsigned line, | |
494 | const char *section, | |
495 | unsigned section_line, | |
496 | const char *lvalue, | |
497 | int ltype, | |
498 | const char *rvalue, | |
499 | void *data, | |
500 | void *userdata) { | |
501 | ||
502 | size_t *sz = data; | |
503 | off_t o; | |
504 | int r; | |
505 | ||
506 | assert(filename); | |
507 | assert(lvalue); | |
508 | assert(rvalue); | |
509 | assert(data); | |
510 | ||
511 | r = parse_size(rvalue, 1000, &o); | |
512 | if (r < 0 || (off_t) (size_t) o != o) { | |
513 | log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue); | |
514 | return 0; | |
515 | } | |
516 | ||
517 | *sz = (size_t) o; | |
518 | return 0; | |
519 | } | |
9ba1a159 | 520 | |
5556b5fe | 521 | int config_parse_iec_off(const char* unit, |
e8e581bf ZJS |
522 | const char *filename, |
523 | unsigned line, | |
524 | const char *section, | |
71a61510 | 525 | unsigned section_line, |
e8e581bf ZJS |
526 | const char *lvalue, |
527 | int ltype, | |
528 | const char *rvalue, | |
529 | void *data, | |
530 | void *userdata) { | |
9ba1a159 LP |
531 | |
532 | off_t *bytes = data; | |
e8e581bf | 533 | int r; |
9ba1a159 LP |
534 | |
535 | assert(filename); | |
536 | assert(lvalue); | |
537 | assert(rvalue); | |
538 | assert(data); | |
539 | ||
540 | assert_cc(sizeof(off_t) == sizeof(uint64_t)); | |
541 | ||
5556b5fe | 542 | r = parse_size(rvalue, 1024, bytes); |
e8e581bf | 543 | if (r < 0) |
5556b5fe | 544 | log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse size value, ignoring: %s", rvalue); |
ed5bcfbe | 545 | |
ed5bcfbe LP |
546 | return 0; |
547 | } | |
548 | ||
e8e581bf ZJS |
549 | int config_parse_bool(const char* unit, |
550 | const char *filename, | |
551 | unsigned line, | |
552 | const char *section, | |
71a61510 | 553 | unsigned section_line, |
e8e581bf ZJS |
554 | const char *lvalue, |
555 | int ltype, | |
556 | const char *rvalue, | |
557 | void *data, | |
558 | void *userdata) { | |
ed5bcfbe LP |
559 | |
560 | int k; | |
561 | bool *b = data; | |
562 | ||
563 | assert(filename); | |
564 | assert(lvalue); | |
565 | assert(rvalue); | |
566 | assert(data); | |
567 | ||
e8e581bf ZJS |
568 | k = parse_boolean(rvalue); |
569 | if (k < 0) { | |
570 | log_syntax(unit, LOG_ERR, filename, line, -k, | |
571 | "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)) { |
b5d74213 | 632 | log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, 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)) { |
b5d74213 | 670 | log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue); |
7f110ff9 LP |
671 | return 0; |
672 | } | |
673 | ||
3b436292 LP |
674 | if (!path_is_absolute(rvalue)) { |
675 | log_syntax(unit, LOG_ERR, filename, line, EINVAL, "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)) { | |
b5d74213 | 736 | log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, 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 ZJS |
745 | if (!isempty(state)) |
746 | log_syntax(unit, LOG_ERR, filename, line, EINVAL, | |
747 | "Trailing garbage, ignoring."); | |
57d42a5f | 748 | |
57d42a5f | 749 | return 0; |
57d42a5f | 750 | } |
15ae422b | 751 | |
2ff7b0a5 LP |
752 | int config_parse_mode( |
753 | const char *unit, | |
754 | const char *filename, | |
755 | unsigned line, | |
756 | const char *section, | |
71a61510 | 757 | unsigned section_line, |
2ff7b0a5 LP |
758 | const char *lvalue, |
759 | int ltype, | |
760 | const char *rvalue, | |
761 | void *data, | |
762 | void *userdata) { | |
f975e971 LP |
763 | |
764 | mode_t *m = data; | |
f975e971 LP |
765 | |
766 | assert(filename); | |
767 | assert(lvalue); | |
768 | assert(rvalue); | |
769 | assert(data); | |
770 | ||
2ff7b0a5 LP |
771 | if (parse_mode(rvalue, m) < 0) { |
772 | log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse mode value, ignoring: %s", rvalue); | |
f975e971 LP |
773 | return 0; |
774 | } | |
775 | ||
f975e971 LP |
776 | return 0; |
777 | } | |
213ba152 | 778 | |
ca37242e LP |
779 | int config_parse_log_facility( |
780 | const char *unit, | |
781 | const char *filename, | |
782 | unsigned line, | |
783 | const char *section, | |
784 | unsigned section_line, | |
785 | const char *lvalue, | |
786 | int ltype, | |
787 | const char *rvalue, | |
788 | void *data, | |
789 | void *userdata) { | |
213ba152 LP |
790 | |
791 | ||
792 | int *o = data, x; | |
793 | ||
794 | assert(filename); | |
795 | assert(lvalue); | |
796 | assert(rvalue); | |
797 | assert(data); | |
798 | ||
799 | x = log_facility_unshifted_from_string(rvalue); | |
800 | if (x < 0) { | |
769d324c | 801 | log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse log facility, ignoring: %s", rvalue); |
213ba152 LP |
802 | return 0; |
803 | } | |
804 | ||
805 | *o = (x << 3) | LOG_PRI(*o); | |
806 | ||
807 | return 0; | |
808 | } | |
809 | ||
ca37242e LP |
810 | int config_parse_log_level( |
811 | const char *unit, | |
812 | const char *filename, | |
813 | unsigned line, | |
814 | const char *section, | |
815 | unsigned section_line, | |
816 | const char *lvalue, | |
817 | int ltype, | |
818 | const char *rvalue, | |
819 | void *data, | |
820 | void *userdata) { | |
213ba152 LP |
821 | |
822 | ||
823 | int *o = data, x; | |
824 | ||
825 | assert(filename); | |
826 | assert(lvalue); | |
827 | assert(rvalue); | |
828 | assert(data); | |
829 | ||
830 | x = log_level_from_string(rvalue); | |
831 | if (x < 0) { | |
769d324c | 832 | log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse log level, ignoring: %s", rvalue); |
213ba152 LP |
833 | return 0; |
834 | } | |
835 | ||
836 | *o = (*o & LOG_FACMASK) | x; | |
837 | return 0; | |
838 | } | |
f757855e LP |
839 | |
840 | int config_parse_signal( | |
841 | const char *unit, | |
842 | const char *filename, | |
843 | unsigned line, | |
844 | const char *section, | |
845 | unsigned section_line, | |
846 | const char *lvalue, | |
847 | int ltype, | |
848 | const char *rvalue, | |
849 | void *data, | |
850 | void *userdata) { | |
851 | ||
852 | int *sig = data, r; | |
853 | ||
854 | assert(filename); | |
855 | assert(lvalue); | |
856 | assert(rvalue); | |
857 | assert(sig); | |
858 | ||
859 | r = signal_from_string_try_harder(rvalue); | |
860 | if (r <= 0) { | |
861 | log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse signal name, ignoring: %s", rvalue); | |
862 | return 0; | |
863 | } | |
864 | ||
865 | *sig = r; | |
866 | return 0; | |
867 | } | |
868 | ||
869 | int config_parse_personality( | |
870 | const char *unit, | |
871 | const char *filename, | |
872 | unsigned line, | |
873 | const char *section, | |
874 | unsigned section_line, | |
875 | const char *lvalue, | |
876 | int ltype, | |
877 | const char *rvalue, | |
878 | void *data, | |
879 | void *userdata) { | |
880 | ||
881 | unsigned long *personality = data, p; | |
882 | ||
883 | assert(filename); | |
884 | assert(lvalue); | |
885 | assert(rvalue); | |
886 | assert(personality); | |
887 | ||
888 | p = personality_from_string(rvalue); | |
889 | if (p == PERSONALITY_INVALID) { | |
890 | log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse personality, ignoring: %s", rvalue); | |
891 | return 0; | |
892 | } | |
893 | ||
894 | *personality = p; | |
895 | return 0; | |
896 | } |