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