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