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