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