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);
273 if (sections && !*section) {
276 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
277 "Assignment outside of section. Ignoring.");
284 log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Missing '='.");
291 return next_assignment(unit,
303 /* Go through the file and parse each line */
304 int config_parse(const char *unit,
305 const char *filename,
307 const char *sections,
308 ConfigItemLookup lookup,
314 _cleanup_free_ char *section = NULL, *continuation = NULL;
315 _cleanup_fclose_ FILE *ours = NULL;
323 f = ours = fopen(filename, "re");
325 log_error("Failed to open configuration file '%s': %m", filename);
331 char l[LINE_MAX], *p, *c = NULL, *e;
332 bool escaped = false;
334 if (!fgets(l, sizeof(l), f)) {
338 log_error("Failed to read configuration file '%s': %m", filename);
345 c = strappend(continuation, l);
355 for (e = p; *e; e++) {
368 continuation = strdup(l);
396 #define DEFINE_PARSER(type, vartype, conv_func) \
397 int config_parse_##type(const char *unit, \
398 const char *filename, \
400 const char *section, \
401 const char *lvalue, \
403 const char *rvalue, \
415 r = conv_func(rvalue, i); \
417 log_syntax(unit, LOG_ERR, filename, line, -r, \
418 "Failed to parse %s value, ignoring: %s", \
424 DEFINE_PARSER(int, int, safe_atoi)
425 DEFINE_PARSER(long, long, safe_atoli)
426 DEFINE_PARSER(uint64, uint64_t, safe_atou64)
427 DEFINE_PARSER(unsigned, unsigned, safe_atou)
428 DEFINE_PARSER(double, double, safe_atod)
429 DEFINE_PARSER(nsec, nsec_t, parse_nsec)
430 DEFINE_PARSER(sec, usec_t, parse_sec)
433 int config_parse_bytes_size(const char* unit,
434 const char *filename,
452 r = parse_bytes(rvalue, &o);
453 if (r < 0 || (off_t) (size_t) o != o) {
454 log_syntax(unit, LOG_ERR, filename, line, -r,
455 "Failed to parse byte value, ignoring: %s", rvalue);
464 int config_parse_bytes_off(const char* unit,
465 const char *filename,
482 assert_cc(sizeof(off_t) == sizeof(uint64_t));
484 r = parse_bytes(rvalue, bytes);
486 log_syntax(unit, LOG_ERR, filename, line, -r,
487 "Failed to parse bytes value, ignoring: %s", rvalue);
492 int config_parse_bool(const char* unit,
493 const char *filename,
510 k = parse_boolean(rvalue);
512 log_syntax(unit, LOG_ERR, filename, line, -k,
513 "Failed to parse boolean value, ignoring: %s", rvalue);
521 int config_parse_string(const char *unit,
522 const char *filename,
543 if (!utf8_is_valid(n)) {
544 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
545 "String is not UTF-8 clean, ignoring assignment: %s", rvalue);
561 int config_parse_path(const char *unit,
562 const char *filename,
580 if (!utf8_is_valid(rvalue)) {
581 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
582 "Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
586 offset = rvalue[0] == '-' && (streq(lvalue, "InaccessibleDirectories") ||
587 streq(lvalue, "ReadOnlyDirectories"));
588 if (!path_is_absolute(rvalue + offset)) {
589 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
590 "Not an absolute path, ignoring: %s", rvalue);
598 path_kill_slashes(n);
606 int config_parse_strv(const char *unit,
607 const char *filename,
616 char *** sv = data, *w, *state;
625 if (isempty(rvalue)) {
628 /* Empty assignment resets the list. As a special rule
629 * we actually fill in a real empty array here rather
630 * than NULL, since some code wants to know if
631 * something was set at all... */
632 empty = strv_new(NULL, NULL);
641 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
642 _cleanup_free_ char *n;
644 n = cunescape_length(w, l);
648 if (!utf8_is_valid(n)) {
649 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
650 "String is not UTF-8 clean, ignoring: %s", rvalue);
654 r = strv_extend(sv, n);
662 int config_parse_path_strv(const char *unit,
663 const char *filename,
672 char*** sv = data, *w, *state;
681 if (isempty(rvalue)) {
682 /* Empty assignment resets the list */
688 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
689 _cleanup_free_ char *n;
696 if (!utf8_is_valid(n)) {
697 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
698 "Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
702 offset = n[0] == '-' && (streq(lvalue, "InaccessibleDirectories") ||
703 streq(lvalue, "ReadOnlyDirectories"));
704 if (!path_is_absolute(n + offset)) {
705 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
706 "Not an absolute path, ignoring: %s", rvalue);
710 path_kill_slashes(n);
711 r = strv_extend(sv, n);
719 int config_parse_mode(const char *unit,
720 const char *filename,
739 l = strtol(rvalue, &x, 8);
740 if (!x || x == rvalue || *x || errno) {
741 log_syntax(unit, LOG_ERR, filename, line, errno,
742 "Failed to parse mode value, ignoring: %s", rvalue);
746 if (l < 0000 || l > 07777) {
747 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
748 "Mode value out of range, ignoring: %s", rvalue);
756 int config_parse_facility(const char *unit,
757 const char *filename,
774 x = log_facility_unshifted_from_string(rvalue);
776 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
777 "Failed to parse log facility, ignoring: %s", rvalue);
781 *o = (x << 3) | LOG_PRI(*o);
786 int config_parse_level(const char *unit,
787 const char *filename,
804 x = log_level_from_string(rvalue);
806 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
807 "Failed to parse log level, ignoring: %s", rvalue);
811 *o = (*o & LOG_FACMASK) | x;
815 int config_parse_set_status(const char *unit,
816 const char *filename,
829 ExitStatusSet *status_set = data;
836 if (isempty(rvalue)) {
837 /* Empty assignment resets the list */
839 set_free(status_set->signal);
840 set_free(status_set->code);
842 status_set->signal = status_set->code = NULL;
846 FOREACH_WORD(w, l, rvalue, state) {
850 temp = strndup(w, l);
854 r = safe_atoi(temp, &val);
856 val = signal_from_string_try_harder(temp);
860 r = set_ensure_allocated(&status_set->signal, trivial_hash_func, trivial_compare_func);
864 r = set_put(status_set->signal, INT_TO_PTR(val));
866 log_syntax(unit, LOG_ERR, filename, line, -r,
867 "Unable to store: %s", w);
871 log_syntax(unit, LOG_ERR, filename, line, -val,
872 "Failed to parse value, ignoring: %s", w);
878 if (val < 0 || val > 255)
879 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
880 "Value %d is outside range 0-255, ignoring", val);
882 r = set_ensure_allocated(&status_set->code, trivial_hash_func, trivial_compare_func);
886 r = set_put(status_set->code, INT_TO_PTR(val));
888 log_syntax(unit, LOG_ERR, filename, line, -r,
889 "Unable to store: %s", w);