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,
164 ConfigParserCallback func = NULL;
175 r = lookup(table, section, lvalue, &func, <ype, &data, userdata);
181 return func(unit, filename, line, section, lvalue, ltype,
182 rvalue, data, userdata);
187 /* Warn about unknown non-extension fields. */
188 if (!relaxed && !startswith(lvalue, "X-"))
189 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
190 "Unknown lvalue '%s' in section '%s'", lvalue, section);
195 /* Parse a variable assignment line */
196 static int parse_line(const char* unit,
197 const char *filename,
199 const char *sections,
200 ConfigItemLookup lookup,
220 if (strchr(COMMENTS "\n", *l))
223 if (startswith(l, ".include ")) {
224 _cleanup_free_ char *fn = NULL;
226 if (!allow_include) {
227 log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
228 ".include not allowed here. Ignoring.");
232 fn = file_in_same_dir(filename, strstrip(l+9));
236 return config_parse(unit, fn, NULL, sections, lookup, table, relaxed, false, userdata);
247 log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
248 "Invalid section header '%s'", l);
252 n = strndup(l+1, k-2);
256 if (sections && !nulstr_contains(sections, n)) {
259 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
260 "Unknown section '%s'. Ignoring.", n);
272 if (sections && !*section) {
275 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
276 "Assignment outside of section. Ignoring.");
283 log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Missing '='.");
290 return next_assignment(unit,
302 /* Go through the file and parse each line */
303 int config_parse(const char *unit,
304 const char *filename,
306 const char *sections,
307 ConfigItemLookup lookup,
313 _cleanup_free_ char *section = NULL, *continuation = NULL;
314 _cleanup_fclose_ FILE *ours = NULL;
322 f = ours = fopen(filename, "re");
324 log_error("Failed to open configuration file '%s': %m", filename);
330 char l[LINE_MAX], *p, *c = NULL, *e;
331 bool escaped = false;
333 if (!fgets(l, sizeof(l), f)) {
337 log_error("Failed to read configuration file '%s': %m", filename);
344 c = strappend(continuation, l);
354 for (e = p; *e; e++) {
367 continuation = strdup(l);
395 #define DEFINE_PARSER(type, vartype, conv_func) \
396 int config_parse_##type(const char *unit, \
397 const char *filename, \
399 const char *section, \
400 const char *lvalue, \
402 const char *rvalue, \
414 r = conv_func(rvalue, i); \
416 log_syntax(unit, LOG_ERR, filename, line, -r, \
417 "Failed to parse %s value, ignoring: %s", \
423 DEFINE_PARSER(int, int, safe_atoi)
424 DEFINE_PARSER(long, long, safe_atoli)
425 DEFINE_PARSER(uint64, uint64_t, safe_atou64)
426 DEFINE_PARSER(unsigned, unsigned, safe_atou)
427 DEFINE_PARSER(double, double, safe_atod)
428 DEFINE_PARSER(nsec, nsec_t, parse_nsec)
429 DEFINE_PARSER(sec, usec_t, parse_sec)
432 int config_parse_bytes_size(const char* unit,
433 const char *filename,
451 r = parse_bytes(rvalue, &o);
452 if (r < 0 || (off_t) (size_t) o != o) {
453 log_syntax(unit, LOG_ERR, filename, line, -r,
454 "Failed to parse byte value, ignoring: %s", rvalue);
463 int config_parse_bytes_off(const char* unit,
464 const char *filename,
481 assert_cc(sizeof(off_t) == sizeof(uint64_t));
483 r = parse_bytes(rvalue, bytes);
485 log_syntax(unit, LOG_ERR, filename, line, -r,
486 "Failed to parse bytes value, ignoring: %s", rvalue);
491 int config_parse_bool(const char* unit,
492 const char *filename,
509 k = parse_boolean(rvalue);
511 log_syntax(unit, LOG_ERR, filename, line, -k,
512 "Failed to parse boolean value, ignoring: %s", rvalue);
520 int config_parse_tristate(const char *unit,
521 const char *filename,
538 /* Tristates are like booleans, but can also take the 'default' value, i.e. "-1" */
540 k = parse_boolean(rvalue);
542 log_syntax(unit, LOG_ERR, filename, line, -k,
543 "Failed to parse boolean value, ignoring: %s", rvalue);
551 int config_parse_string(const char *unit,
552 const char *filename,
573 if (!utf8_is_valid(n)) {
574 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
575 "String is not UTF-8 clean, ignoring assignment: %s", rvalue);
591 int config_parse_path(const char *unit,
592 const char *filename,
610 if (!utf8_is_valid(rvalue)) {
611 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
612 "Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
616 offset = rvalue[0] == '-' && (streq(lvalue, "InaccessibleDirectories") ||
617 streq(lvalue, "ReadOnlyDirectories"));
618 if (!path_is_absolute(rvalue + offset)) {
619 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
620 "Not an absolute path, ignoring: %s", rvalue);
628 path_kill_slashes(n);
636 int config_parse_strv(const char *unit,
637 const char *filename,
646 char *** sv = data, *w, *state;
655 if (isempty(rvalue)) {
658 /* Empty assignment resets the list. As a special rule
659 * we actually fill in a real empty array here rather
660 * than NULL, since some code wants to know if
661 * something was set at all... */
662 empty = strv_new(NULL, NULL);
671 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
672 _cleanup_free_ char *n;
674 n = cunescape_length(w, l);
678 if (!utf8_is_valid(n)) {
679 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
680 "String is not UTF-8 clean, ignoring: %s", rvalue);
684 r = strv_extend(sv, n);
692 int config_parse_path_strv(const char *unit,
693 const char *filename,
702 char*** sv = data, *w, *state;
711 if (isempty(rvalue)) {
712 /* Empty assignment resets the list */
718 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
719 _cleanup_free_ char *n;
726 if (!utf8_is_valid(n)) {
727 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
728 "Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
732 offset = n[0] == '-' && (streq(lvalue, "InaccessibleDirectories") ||
733 streq(lvalue, "ReadOnlyDirectories"));
734 if (!path_is_absolute(n + offset)) {
735 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
736 "Not an absolute path, ignoring: %s", rvalue);
740 path_kill_slashes(n);
741 r = strv_extend(sv, n);
749 int config_parse_mode(const char *unit,
750 const char *filename,
769 l = strtol(rvalue, &x, 8);
770 if (!x || x == rvalue || *x || errno) {
771 log_syntax(unit, LOG_ERR, filename, line, errno,
772 "Failed to parse mode value, ignoring: %s", rvalue);
776 if (l < 0000 || l > 07777) {
777 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
778 "Mode value out of range, ignoring: %s", rvalue);
786 int config_parse_facility(const char *unit,
787 const char *filename,
804 x = log_facility_unshifted_from_string(rvalue);
806 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
807 "Failed to parse log facility, ignoring: %s", rvalue);
811 *o = (x << 3) | LOG_PRI(*o);
816 int config_parse_level(const char *unit,
817 const char *filename,
834 x = log_level_from_string(rvalue);
836 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
837 "Failed to parse log level, ignoring: %s", rvalue);
841 *o = (*o & LOG_FACMASK) | x;
845 int config_parse_set_status(const char *unit,
846 const char *filename,
859 ExitStatusSet *status_set = data;
866 if (isempty(rvalue)) {
867 /* Empty assignment resets the list */
869 set_free(status_set->signal);
870 set_free(status_set->code);
872 status_set->signal = status_set->code = NULL;
876 FOREACH_WORD(w, l, rvalue, state) {
880 temp = strndup(w, l);
884 r = safe_atoi(temp, &val);
886 val = signal_from_string_try_harder(temp);
890 r = set_ensure_allocated(&status_set->signal, trivial_hash_func, trivial_compare_func);
894 r = set_put(status_set->signal, INT_TO_PTR(val));
896 log_syntax(unit, LOG_ERR, filename, line, -r,
897 "Unable to store: %s", w);
901 log_syntax(unit, LOG_ERR, filename, line, -val,
902 "Failed to parse value, ignoring: %s", w);
908 if (val < 0 || val > 255)
909 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
910 "Value %d is outside range 0-255, ignoring", val);
912 r = set_ensure_allocated(&status_set->code, trivial_hash_func, trivial_compare_func);
916 r = set_put(status_set->code, INT_TO_PTR(val));
918 log_syntax(unit, LOG_ERR, filename, line, -r,
919 "Unable to store: %s", w);