1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
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
11 (at your option) any later version.
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
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
27 #include <netinet/ether.h>
29 #include "conf-parser.h"
35 #include "path-util.h"
37 #include "exit-status.h"
38 #include "sd-messages.h"
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, ...) {
45 _cleanup_free_ char *msg = NULL;
50 r = vasprintf(&msg, format, ap);
56 r = log_struct_internal(level,
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,
66 r = log_struct_internal(level,
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,
78 int config_item_table_lookup(
82 ConfigParserCallback *func,
95 for (t = table; t->lvalue; t++) {
97 if (!streq(lvalue, t->lvalue))
100 if (!streq_ptr(section, t->section))
112 int config_item_perf_lookup(
116 ConfigParserCallback *func,
121 ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
122 const ConfigPerfItem *p;
131 p = lookup(lvalue, strlen(lvalue));
135 key = strjoin(section, ".", lvalue, NULL);
139 p = lookup(key, strlen(key));
148 *data = (uint8_t*) userdata + p->offset;
152 /* Run the user supplied parser for an assignment */
153 static int next_assignment(const char *unit,
154 const char *filename,
156 ConfigItemLookup lookup,
159 unsigned section_line,
165 ConfigParserCallback func = NULL;
176 r = lookup(table, section, lvalue, &func, <ype, &data, userdata);
182 return func(unit, filename, line, section, section_line,
183 lvalue, ltype, rvalue, data, userdata);
188 /* Warn about unknown non-extension fields. */
189 if (!relaxed && !startswith(lvalue, "X-"))
190 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
191 "Unknown lvalue '%s' in section '%s'", lvalue, section);
196 /* Parse a variable assignment line */
197 static int parse_line(const char* unit,
198 const char *filename,
200 const char *sections,
201 ConfigItemLookup lookup,
206 unsigned *section_line,
222 if (strchr(COMMENTS "\n", *l))
225 if (startswith(l, ".include ")) {
226 _cleanup_free_ char *fn = NULL;
228 if (!allow_include) {
229 log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
230 ".include not allowed here. Ignoring.");
234 fn = file_in_same_dir(filename, strstrip(l+9));
238 return config_parse(unit, fn, NULL, sections, lookup, table, relaxed, false, userdata);
249 log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
250 "Invalid section header '%s'", l);
254 n = strndup(l+1, k-2);
258 if (sections && !nulstr_contains(sections, n)) {
261 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
262 "Unknown section '%s'. Ignoring.", n);
271 *section_line = line;
277 if (sections && !*section) {
280 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
281 "Assignment outside of section. Ignoring.");
288 log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Missing '='.");
295 return next_assignment(unit,
308 /* Go through the file and parse each line */
309 int config_parse(const char *unit,
310 const char *filename,
312 const char *sections,
313 ConfigItemLookup lookup,
319 _cleanup_free_ char *section = NULL, *continuation = NULL;
320 _cleanup_fclose_ FILE *ours = NULL;
321 unsigned line = 0, section_line = 0;
328 f = ours = fopen(filename, "re");
330 log_error("Failed to open configuration file '%s': %m", filename);
336 char l[LINE_MAX], *p, *c = NULL, *e;
337 bool escaped = false;
339 if (!fgets(l, sizeof(l), f)) {
343 log_error("Failed to read configuration file '%s': %m", filename);
350 c = strappend(continuation, l);
360 for (e = p; *e; e++) {
373 continuation = strdup(l);
402 #define DEFINE_PARSER(type, vartype, conv_func) \
403 int config_parse_##type(const char *unit, \
404 const char *filename, \
406 const char *section, \
407 unsigned section_line, \
408 const char *lvalue, \
410 const char *rvalue, \
422 r = conv_func(rvalue, i); \
424 log_syntax(unit, LOG_ERR, filename, line, -r, \
425 "Failed to parse %s value, ignoring: %s", \
431 DEFINE_PARSER(int, int, safe_atoi)
432 DEFINE_PARSER(long, long, safe_atoli)
433 DEFINE_PARSER(uint64, uint64_t, safe_atou64)
434 DEFINE_PARSER(unsigned, unsigned, safe_atou)
435 DEFINE_PARSER(double, double, safe_atod)
436 DEFINE_PARSER(nsec, nsec_t, parse_nsec)
437 DEFINE_PARSER(sec, usec_t, parse_sec)
440 int config_parse_bytes_size(const char* unit,
441 const char *filename,
444 unsigned section_line,
460 r = parse_bytes(rvalue, &o);
461 if (r < 0 || (off_t) (size_t) o != o) {
462 log_syntax(unit, LOG_ERR, filename, line, -r,
463 "Failed to parse byte value, ignoring: %s", rvalue);
472 int config_parse_bytes_off(const char* unit,
473 const char *filename,
476 unsigned section_line,
491 assert_cc(sizeof(off_t) == sizeof(uint64_t));
493 r = parse_bytes(rvalue, bytes);
495 log_syntax(unit, LOG_ERR, filename, line, -r,
496 "Failed to parse bytes value, ignoring: %s", rvalue);
501 int config_parse_bool(const char* unit,
502 const char *filename,
505 unsigned section_line,
520 k = parse_boolean(rvalue);
522 log_syntax(unit, LOG_ERR, filename, line, -k,
523 "Failed to parse boolean value, ignoring: %s", rvalue);
531 int config_parse_show_status(const char* unit,
532 const char *filename,
535 unsigned section_line,
543 ShowStatus *b = data;
550 k = parse_show_status(rvalue, b);
552 log_syntax(unit, LOG_ERR, filename, line, -k,
553 "Failed to parse show status setting, ignoring: %s", rvalue);
560 int config_parse_string(const char *unit,
561 const char *filename,
564 unsigned section_line,
583 if (!utf8_is_valid(n)) {
584 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
585 "String is not UTF-8 clean, ignoring assignment: %s", rvalue);
601 int config_parse_path(const char *unit,
602 const char *filename,
605 unsigned section_line,
621 if (!utf8_is_valid(rvalue)) {
622 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
623 "Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
627 offset = rvalue[0] == '-' && (streq(lvalue, "InaccessibleDirectories") ||
628 streq(lvalue, "ReadOnlyDirectories"));
629 if (!path_is_absolute(rvalue + offset)) {
630 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
631 "Not an absolute path, ignoring: %s", rvalue);
639 path_kill_slashes(n);
647 int config_parse_strv(const char *unit,
648 const char *filename,
651 unsigned section_line,
658 char *** sv = data, *w, *state;
667 if (isempty(rvalue)) {
670 /* Empty assignment resets the list. As a special rule
671 * we actually fill in a real empty array here rather
672 * than NULL, since some code wants to know if
673 * something was set at all... */
674 empty = strv_new(NULL, NULL);
683 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
684 _cleanup_free_ char *n;
686 n = cunescape_length(w, l);
690 if (!utf8_is_valid(n)) {
691 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
692 "String is not UTF-8 clean, ignoring: %s", rvalue);
696 r = strv_extend(sv, n);
704 int config_parse_path_strv(const char *unit,
705 const char *filename,
708 unsigned section_line,
715 char*** sv = data, *w, *state;
724 if (isempty(rvalue)) {
725 /* Empty assignment resets the list */
731 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
732 _cleanup_free_ char *n;
739 if (!utf8_is_valid(n)) {
740 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
741 "Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
745 offset = n[0] == '-' && (streq(lvalue, "InaccessibleDirectories") ||
746 streq(lvalue, "ReadOnlyDirectories"));
747 if (!path_is_absolute(n + offset)) {
748 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
749 "Not an absolute path, ignoring: %s", rvalue);
753 path_kill_slashes(n);
754 r = strv_extend(sv, n);
762 int config_parse_mode(const char *unit,
763 const char *filename,
766 unsigned section_line,
783 l = strtol(rvalue, &x, 8);
784 if (!x || x == rvalue || *x || errno) {
785 log_syntax(unit, LOG_ERR, filename, line, errno,
786 "Failed to parse mode value, ignoring: %s", rvalue);
790 if (l < 0000 || l > 07777) {
791 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
792 "Mode value out of range, ignoring: %s", rvalue);
800 int config_parse_facility(const char *unit,
801 const char *filename,
804 unsigned section_line,
819 x = log_facility_unshifted_from_string(rvalue);
821 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
822 "Failed to parse log facility, ignoring: %s", rvalue);
826 *o = (x << 3) | LOG_PRI(*o);
831 int config_parse_level(const char *unit,
832 const char *filename,
835 unsigned section_line,
850 x = log_level_from_string(rvalue);
852 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
853 "Failed to parse log level, ignoring: %s", rvalue);
857 *o = (*o & LOG_FACMASK) | x;
861 int config_parse_set_status(const char *unit,
862 const char *filename,
865 unsigned section_line,
876 ExitStatusSet *status_set = data;
883 if (isempty(rvalue)) {
884 /* Empty assignment resets the list */
886 set_free(status_set->signal);
887 set_free(status_set->code);
889 status_set->signal = status_set->code = NULL;
893 FOREACH_WORD(w, l, rvalue, state) {
897 temp = strndup(w, l);
901 r = safe_atoi(temp, &val);
903 val = signal_from_string_try_harder(temp);
907 r = set_ensure_allocated(&status_set->signal, trivial_hash_func, trivial_compare_func);
911 r = set_put(status_set->signal, INT_TO_PTR(val));
913 log_syntax(unit, LOG_ERR, filename, line, -r,
914 "Unable to store: %s", w);
918 log_syntax(unit, LOG_ERR, filename, line, -val,
919 "Failed to parse value, ignoring: %s", w);
925 if (val < 0 || val > 255)
926 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
927 "Value %d is outside range 0-255, ignoring", val);
929 r = set_ensure_allocated(&status_set->code, trivial_hash_func, trivial_compare_func);
933 r = set_put(status_set->code, INT_TO_PTR(val));
935 log_syntax(unit, LOG_ERR, filename, line, -r,
936 "Unable to store: %s", w);