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