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/>.
28 #include "conf-parser.h"
34 #include "path-util.h"
36 #include "exit-status.h"
37 #include "sd-messages.h"
39 int log_syntax_internal(const char *unit, int level,
40 const char *file, unsigned line, const char *func,
41 const char *config_file, unsigned config_line,
42 int error, const char *format, ...) {
44 _cleanup_free_ char *msg = NULL;
49 r = vasprintf(&msg, format, ap);
55 r = log_struct_internal(level,
57 getpid() == 1 ? "UNIT=%s" : "USER_UNIT=%s", unit,
58 MESSAGE_ID(SD_MESSAGE_CONFIG_ERROR),
59 "CONFIG_FILE=%s", config_file,
60 "CONFIG_LINE=%u", config_line,
61 "ERRNO=%d", error > 0 ? error : EINVAL,
62 "MESSAGE=[%s:%u] %s", config_file, config_line, msg,
65 r = log_struct_internal(level,
67 MESSAGE_ID(SD_MESSAGE_CONFIG_ERROR),
68 "CONFIG_FILE=%s", config_file,
69 "CONFIG_LINE=%u", config_line,
70 "ERRNO=%d", error > 0 ? error : EINVAL,
71 "MESSAGE=[%s:%u] %s", config_file, config_line, msg,
73 log_info("logged here: '%s': %d", msg, r);
77 int config_item_table_lookup(
81 ConfigParserCallback *func,
94 for (t = table; t->lvalue; t++) {
96 if (!streq(lvalue, t->lvalue))
99 if (!streq_ptr(section, t->section))
111 int config_item_perf_lookup(
115 ConfigParserCallback *func,
120 ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
121 const ConfigPerfItem *p;
130 p = lookup(lvalue, strlen(lvalue));
134 key = strjoin(section, ".", lvalue, NULL);
138 p = lookup(key, strlen(key));
147 *data = (uint8_t*) userdata + p->offset;
151 /* Run the user supplied parser for an assignment */
152 static int next_assignment(const char *unit,
153 const char *filename,
155 ConfigItemLookup lookup,
163 ConfigParserCallback func = NULL;
174 r = lookup(table, section, lvalue, &func, <ype, &data, userdata);
180 return func(unit, filename, line, section, lvalue, ltype,
181 rvalue, data, userdata);
186 /* Warn about unknown non-extension fields. */
187 if (!relaxed && !startswith(lvalue, "X-"))
188 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
189 "Unknown lvalue '%s' in section '%s'", lvalue, section);
194 /* Parse a variable assignment line */
195 static int parse_line(const char* unit,
196 const char *filename,
198 const char *sections,
199 ConfigItemLookup lookup,
218 if (strchr(COMMENTS "\n", *l))
221 if (startswith(l, ".include ")) {
222 _cleanup_free_ char *fn;
224 fn = file_in_same_dir(filename, strstrip(l+9));
228 return config_parse(unit, fn, NULL, sections, lookup, table, relaxed, userdata);
239 log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
240 "Invalid section header '%s'", l);
244 n = strndup(l+1, k-2);
248 if (sections && !nulstr_contains(sections, n)) {
251 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
252 "Unknown section '%s'. Ignoring.", n);
264 if (sections && !*section) {
267 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
268 "Assignment outside of section. Ignoring.");
275 log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Missing '='.");
282 return next_assignment(unit,
294 /* Go through the file and parse each line */
295 int config_parse(const char *unit,
296 const char *filename,
298 const char *sections,
299 ConfigItemLookup lookup,
305 _cleanup_free_ char *section = NULL, *continuation = NULL;
306 _cleanup_fclose_ FILE *ours = NULL;
313 f = ours = fopen(filename, "re");
315 log_error("Failed to open configuration file '%s': %m", filename);
321 char l[LINE_MAX], *p, *c = NULL, *e;
322 bool escaped = false;
324 if (!fgets(l, sizeof(l), f)) {
328 log_error("Failed to read configuration file '%s': %m", filename);
335 c = strappend(continuation, l);
345 for (e = p; *e; e++) {
358 continuation = strdup(l);
385 #define DEFINE_PARSER(type, vartype, conv_func) \
386 int config_parse_##type(const char *unit, \
387 const char *filename, \
389 const char *section, \
390 const char *lvalue, \
392 const char *rvalue, \
404 r = conv_func(rvalue, i); \
406 log_syntax(unit, LOG_ERR, filename, line, -r, \
407 "Failed to parse %s value, ignoring: %s", \
413 DEFINE_PARSER(int, int, safe_atoi)
414 DEFINE_PARSER(long, long, safe_atoli)
415 DEFINE_PARSER(uint64, uint64_t, safe_atou64)
416 DEFINE_PARSER(unsigned, unsigned, safe_atou)
417 DEFINE_PARSER(double, double, safe_atod)
418 DEFINE_PARSER(nsec, nsec_t, parse_nsec)
419 DEFINE_PARSER(sec, usec_t, parse_sec)
422 int config_parse_bytes_size(const char* unit,
423 const char *filename,
441 r = parse_bytes(rvalue, &o);
442 if (r < 0 || (off_t) (size_t) o != o) {
443 log_syntax(unit, LOG_ERR, filename, line, -r,
444 "Failed to parse byte value, ignoring: %s", rvalue);
453 int config_parse_bytes_off(const char* unit,
454 const char *filename,
471 assert_cc(sizeof(off_t) == sizeof(uint64_t));
473 r = parse_bytes(rvalue, bytes);
475 log_syntax(unit, LOG_ERR, filename, line, -r,
476 "Failed to parse bytes value, ignoring: %s", rvalue);
481 int config_parse_bool(const char* unit,
482 const char *filename,
499 k = parse_boolean(rvalue);
501 log_syntax(unit, LOG_ERR, filename, line, -k,
502 "Failed to parse boolean value, ignoring: %s", rvalue);
510 int config_parse_tristate(const char *unit,
511 const char *filename,
528 /* Tristates are like booleans, but can also take the 'default' value, i.e. "-1" */
530 k = parse_boolean(rvalue);
532 log_syntax(unit, LOG_ERR, filename, line, -k,
533 "Failed to parse boolean value, ignoring: %s", rvalue);
541 int config_parse_string(const char *unit,
542 const char *filename,
563 if (!utf8_is_valid(n)) {
564 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
565 "String is not UTF-8 clean, ignoring assignment: %s", rvalue);
581 int config_parse_path(const char *unit,
582 const char *filename,
599 if (!utf8_is_valid(rvalue)) {
600 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
601 "Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
605 if (!path_is_absolute(rvalue)) {
606 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
607 "Not an absolute path, ignoring: %s", rvalue);
615 path_kill_slashes(n);
623 int config_parse_strv(const char *unit,
624 const char *filename,
633 char *** sv = data, *w, *state;
642 if (isempty(rvalue)) {
645 /* Empty assignment resets the list. As a special rule
646 * we actually fill in a real empty array here rather
647 * than NULL, since some code wants to know if
648 * something was set at all... */
649 empty = strv_new(NULL, NULL);
658 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
659 _cleanup_free_ char *n;
661 n = cunescape_length(w, l);
665 if (!utf8_is_valid(n)) {
666 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
667 "String is not UTF-8 clean, ignoring: %s", rvalue);
671 r = strv_extend(sv, n);
679 int config_parse_path_strv(const char *unit,
680 const char *filename,
689 char*** sv = data, *w, *state;
698 if (isempty(rvalue)) {
699 /* Empty assignment resets the list */
705 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
706 _cleanup_free_ char *n;
712 if (!utf8_is_valid(n)) {
713 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
714 "Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
718 if (!path_is_absolute(n)) {
719 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
720 "Not an absolute path, ignoring: %s", rvalue);
724 path_kill_slashes(n);
725 r = strv_extend(sv, n);
733 int config_parse_mode(const char *unit,
734 const char *filename,
753 l = strtol(rvalue, &x, 8);
754 if (!x || x == rvalue || *x || errno) {
755 log_syntax(unit, LOG_ERR, filename, line, errno,
756 "Failed to parse mode value, ignoring: %s", rvalue);
760 if (l < 0000 || l > 07777) {
761 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
762 "Mode value out of range, ignoring: %s", rvalue);
770 int config_parse_facility(const char *unit,
771 const char *filename,
788 x = log_facility_unshifted_from_string(rvalue);
790 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
791 "Failed to parse log facility, ignoring: %s", rvalue);
795 *o = (x << 3) | LOG_PRI(*o);
800 int config_parse_level(const char *unit,
801 const char *filename,
818 x = log_level_from_string(rvalue);
820 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
821 "Failed to parse log level, ignoring: %s", rvalue);
825 *o = (*o & LOG_FACMASK) | x;
829 int config_parse_set_status(const char *unit,
830 const char *filename,
843 ExitStatusSet *status_set = data;
850 if (isempty(rvalue)) {
851 /* Empty assignment resets the list */
853 set_free(status_set->signal);
854 set_free(status_set->code);
856 status_set->signal = status_set->code = NULL;
860 FOREACH_WORD(w, l, rvalue, state) {
864 temp = strndup(w, l);
868 r = safe_atoi(temp, &val);
870 val = signal_from_string_try_harder(temp);
874 r = set_ensure_allocated(&status_set->signal, trivial_hash_func, trivial_compare_func);
878 r = set_put(status_set->signal, INT_TO_PTR(val));
880 log_syntax(unit, LOG_ERR, filename, line, -r,
881 "Unable to store: %s", w);
885 log_syntax(unit, LOG_ERR, filename, line, -val,
886 "Failed to parse value, ignoring: %s", w);
892 if (val < 0 || val > 255)
893 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
894 "Value %d is outside range 0-255, ignoring", val);
896 r = set_ensure_allocated(&status_set->code, trivial_hash_func, trivial_compare_func);
900 r = set_put(status_set->code, INT_TO_PTR(val));
902 log_syntax(unit, LOG_ERR, filename, line, -r,
903 "Unable to store: %s", w);