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 /* .includes are a bad idea, we only support them here
229 * for historical reasons. They create cyclic include
230 * problems and make it difficult to detect
231 * configuration file changes with an easy
232 * stat(). Better approaches, such as .d/ drop-in
235 * Support for them should be eventually removed. */
237 if (!allow_include) {
238 log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
239 ".include not allowed here. Ignoring.");
243 fn = file_in_same_dir(filename, strstrip(l+9));
247 return config_parse(unit, fn, NULL, sections, lookup, table, relaxed, false, userdata);
258 log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
259 "Invalid section header '%s'", l);
263 n = strndup(l+1, k-2);
267 if (sections && !nulstr_contains(sections, n)) {
270 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
271 "Unknown section '%s'. Ignoring.", n);
280 *section_line = line;
286 if (sections && !*section) {
289 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
290 "Assignment outside of section. Ignoring.");
297 log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Missing '='.");
304 return next_assignment(unit,
317 /* Go through the file and parse each line */
318 int config_parse(const char *unit,
319 const char *filename,
321 const char *sections,
322 ConfigItemLookup lookup,
328 _cleanup_free_ char *section = NULL, *continuation = NULL;
329 _cleanup_fclose_ FILE *ours = NULL;
330 unsigned line = 0, section_line = 0;
337 f = ours = fopen(filename, "re");
339 log_error("Failed to open configuration file '%s': %m", filename);
344 fd_warn_permissions(filename, fileno(f));
347 char l[LINE_MAX], *p, *c = NULL, *e;
348 bool escaped = false;
350 if (!fgets(l, sizeof(l), f)) {
354 log_error("Failed to read configuration file '%s': %m", filename);
361 c = strappend(continuation, l);
371 for (e = p; *e; e++) {
384 continuation = strdup(l);
413 #define DEFINE_PARSER(type, vartype, conv_func) \
414 int config_parse_##type(const char *unit, \
415 const char *filename, \
417 const char *section, \
418 unsigned section_line, \
419 const char *lvalue, \
421 const char *rvalue, \
433 r = conv_func(rvalue, i); \
435 log_syntax(unit, LOG_ERR, filename, line, -r, \
436 "Failed to parse %s value, ignoring: %s", \
442 DEFINE_PARSER(int, int, safe_atoi)
443 DEFINE_PARSER(long, long, safe_atoli)
444 DEFINE_PARSER(uint64, uint64_t, safe_atou64)
445 DEFINE_PARSER(unsigned, unsigned, safe_atou)
446 DEFINE_PARSER(double, double, safe_atod)
447 DEFINE_PARSER(nsec, nsec_t, parse_nsec)
448 DEFINE_PARSER(sec, usec_t, parse_sec)
450 int config_parse_iec_size(const char* unit,
451 const char *filename,
454 unsigned section_line,
470 r = parse_size(rvalue, 1024, &o);
471 if (r < 0 || (off_t) (size_t) o != o) {
472 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
480 int config_parse_si_size(const char* unit,
481 const char *filename,
484 unsigned section_line,
500 r = parse_size(rvalue, 1000, &o);
501 if (r < 0 || (off_t) (size_t) o != o) {
502 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
510 int config_parse_iec_off(const char* unit,
511 const char *filename,
514 unsigned section_line,
529 assert_cc(sizeof(off_t) == sizeof(uint64_t));
531 r = parse_size(rvalue, 1024, bytes);
533 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse size value, ignoring: %s", rvalue);
538 int config_parse_bool(const char* unit,
539 const char *filename,
542 unsigned section_line,
557 k = parse_boolean(rvalue);
559 log_syntax(unit, LOG_ERR, filename, line, -k,
560 "Failed to parse boolean value, ignoring: %s", rvalue);
568 int config_parse_show_status(const char* unit,
569 const char *filename,
572 unsigned section_line,
580 ShowStatus *b = data;
587 k = parse_show_status(rvalue, b);
589 log_syntax(unit, LOG_ERR, filename, line, -k,
590 "Failed to parse show status setting, ignoring: %s", rvalue);
597 int config_parse_string(const char *unit,
598 const char *filename,
601 unsigned section_line,
620 if (!utf8_is_valid(n)) {
621 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
622 "String is not UTF-8 clean, ignoring assignment: %s", rvalue);
638 int config_parse_path(const char *unit,
639 const char *filename,
642 unsigned section_line,
658 if (!utf8_is_valid(rvalue)) {
659 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
660 "Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
664 offset = rvalue[0] == '-' && (streq(lvalue, "InaccessibleDirectories") ||
665 streq(lvalue, "ReadOnlyDirectories"));
666 if (!path_is_absolute(rvalue + offset)) {
667 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
668 "Not an absolute path, ignoring: %s", rvalue);
676 path_kill_slashes(n);
684 int config_parse_strv(const char *unit,
685 const char *filename,
688 unsigned section_line,
695 char *** sv = data, *w, *state;
704 if (isempty(rvalue)) {
707 /* Empty assignment resets the list. As a special rule
708 * we actually fill in a real empty array here rather
709 * than NULL, since some code wants to know if
710 * something was set at all... */
711 empty = strv_new(NULL, NULL);
720 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
721 _cleanup_free_ char *n;
723 n = cunescape_length(w, l);
727 if (!utf8_is_valid(n)) {
728 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
729 "String is not UTF-8 clean, ignoring: %s", rvalue);
733 r = strv_extend(sv, n);
741 int config_parse_path_strv(const char *unit,
742 const char *filename,
745 unsigned section_line,
752 char*** sv = data, *w, *state;
761 if (isempty(rvalue)) {
762 /* Empty assignment resets the list */
768 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
769 _cleanup_free_ char *n;
776 if (!utf8_is_valid(n)) {
777 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
778 "Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
782 offset = n[0] == '-' && (streq(lvalue, "InaccessibleDirectories") ||
783 streq(lvalue, "ReadOnlyDirectories"));
784 if (!path_is_absolute(n + offset)) {
785 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
786 "Not an absolute path, ignoring: %s", rvalue);
790 path_kill_slashes(n);
791 r = strv_extend(sv, n);
799 int config_parse_mode(const char *unit,
800 const char *filename,
803 unsigned section_line,
820 l = strtol(rvalue, &x, 8);
821 if (!x || x == rvalue || *x || errno) {
822 log_syntax(unit, LOG_ERR, filename, line, errno,
823 "Failed to parse mode value, ignoring: %s", rvalue);
827 if (l < 0000 || l > 07777) {
828 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
829 "Mode value out of range, ignoring: %s", rvalue);
837 int config_parse_facility(const char *unit,
838 const char *filename,
841 unsigned section_line,
856 x = log_facility_unshifted_from_string(rvalue);
858 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
859 "Failed to parse log facility, ignoring: %s", rvalue);
863 *o = (x << 3) | LOG_PRI(*o);
868 int config_parse_level(const char *unit,
869 const char *filename,
872 unsigned section_line,
887 x = log_level_from_string(rvalue);
889 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
890 "Failed to parse log level, ignoring: %s", rvalue);
894 *o = (*o & LOG_FACMASK) | x;
898 int config_parse_set_status(const char *unit,
899 const char *filename,
902 unsigned section_line,
913 ExitStatusSet *status_set = data;
920 if (isempty(rvalue)) {
921 /* Empty assignment resets the list */
923 set_free(status_set->signal);
924 set_free(status_set->code);
926 status_set->signal = status_set->code = NULL;
930 FOREACH_WORD(w, l, rvalue, state) {
934 temp = strndup(w, l);
938 r = safe_atoi(temp, &val);
940 val = signal_from_string_try_harder(temp);
944 r = set_ensure_allocated(&status_set->signal, trivial_hash_func, trivial_compare_func);
948 r = set_put(status_set->signal, INT_TO_PTR(val));
950 log_syntax(unit, LOG_ERR, filename, line, -r,
951 "Unable to store: %s", w);
955 log_syntax(unit, LOG_ERR, filename, line, -val,
956 "Failed to parse value, ignoring: %s", w);
962 if (val < 0 || val > 255)
963 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
964 "Value %d is outside range 0-255, ignoring", val);
966 r = set_ensure_allocated(&status_set->code, trivial_hash_func, trivial_compare_func);
970 r = set_put(status_set->code, INT_TO_PTR(val));
972 log_syntax(unit, LOG_ERR, filename, line, -r,
973 "Unable to store: %s", w);