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 "sd-messages.h"
28 #include "conf-files.h"
34 #include "path-util.h"
35 #include "signal-util.h"
36 #include "conf-parser.h"
38 int config_item_table_lookup(
42 ConfigParserCallback
*func
,
47 const ConfigTableItem
*t
;
55 for (t
= table
; t
->lvalue
; t
++) {
57 if (!streq(lvalue
, t
->lvalue
))
60 if (!streq_ptr(section
, t
->section
))
72 int config_item_perf_lookup(
76 ConfigParserCallback
*func
,
81 ConfigPerfItemLookup lookup
= (ConfigPerfItemLookup
) table
;
82 const ConfigPerfItem
*p
;
91 p
= lookup(lvalue
, strlen(lvalue
));
95 key
= strjoin(section
, ".", lvalue
, NULL
);
99 p
= lookup(key
, strlen(key
));
108 *data
= (uint8_t*) userdata
+ p
->offset
;
112 /* Run the user supplied parser for an assignment */
113 static int next_assignment(const char *unit
,
114 const char *filename
,
116 ConfigItemLookup lookup
,
119 unsigned section_line
,
125 ConfigParserCallback func
= NULL
;
136 r
= lookup(table
, section
, lvalue
, &func
, <ype
, &data
, userdata
);
142 return func(unit
, filename
, line
, section
, section_line
,
143 lvalue
, ltype
, rvalue
, data
, userdata
);
148 /* Warn about unknown non-extension fields. */
149 if (!relaxed
&& !startswith(lvalue
, "X-"))
150 log_syntax(unit
, LOG_WARNING
, filename
, line
, EINVAL
,
151 "Unknown lvalue '%s' in section '%s'", lvalue
, section
);
156 /* Parse a variable assignment line */
157 static int parse_line(const char* unit
,
158 const char *filename
,
160 const char *sections
,
161 ConfigItemLookup lookup
,
166 unsigned *section_line
,
167 bool *section_ignored
,
183 if (strchr(COMMENTS
"\n", *l
))
186 if (startswith(l
, ".include ")) {
187 _cleanup_free_
char *fn
= NULL
;
189 /* .includes are a bad idea, we only support them here
190 * for historical reasons. They create cyclic include
191 * problems and make it difficult to detect
192 * configuration file changes with an easy
193 * stat(). Better approaches, such as .d/ drop-in
196 * Support for them should be eventually removed. */
198 if (!allow_include
) {
199 log_syntax(unit
, LOG_ERR
, filename
, line
, EBADMSG
,
200 ".include not allowed here. Ignoring.");
204 fn
= file_in_same_dir(filename
, strstrip(l
+9));
208 return config_parse(unit
, fn
, NULL
, sections
, lookup
, table
, relaxed
, false, false, userdata
);
219 log_syntax(unit
, LOG_ERR
, filename
, line
, EBADMSG
,
220 "Invalid section header '%s'", l
);
224 n
= strndup(l
+1, k
-2);
228 if (sections
&& !nulstr_contains(sections
, n
)) {
230 if (!relaxed
&& !startswith(n
, "X-"))
231 log_syntax(unit
, LOG_WARNING
, filename
, line
, EINVAL
,
232 "Unknown section '%s'. Ignoring.", n
);
238 *section_ignored
= true;
242 *section_line
= line
;
243 *section_ignored
= false;
249 if (sections
&& !*section
) {
251 if (!relaxed
&& !*section_ignored
)
252 log_syntax(unit
, LOG_WARNING
, filename
, line
, EINVAL
,
253 "Assignment outside of section. Ignoring.");
260 log_syntax(unit
, LOG_WARNING
, filename
, line
, EINVAL
, "Missing '='.");
267 return next_assignment(unit
,
280 /* Go through the file and parse each line */
281 int config_parse(const char *unit
,
282 const char *filename
,
284 const char *sections
,
285 ConfigItemLookup lookup
,
292 _cleanup_free_
char *section
= NULL
, *continuation
= NULL
;
293 _cleanup_fclose_
FILE *ours
= NULL
;
294 unsigned line
= 0, section_line
= 0;
295 bool section_ignored
= false;
302 f
= ours
= fopen(filename
, "re");
304 /* Only log on request, except for ENOENT,
305 * since we return 0 to the caller. */
306 if (warn
|| errno
== ENOENT
)
307 log_full(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
,
308 "Failed to open configuration file '%s': %m", filename
);
309 return errno
== ENOENT
? 0 : -errno
;
313 fd_warn_permissions(filename
, fileno(f
));
316 char l
[LINE_MAX
], *p
, *c
= NULL
, *e
;
317 bool escaped
= false;
319 if (!fgets(l
, sizeof(l
), f
)) {
323 log_error_errno(errno
, "Failed to read configuration file '%s': %m", filename
);
330 c
= strappend(continuation
, l
);
337 continuation
= mfree(continuation
);
342 for (e
= p
; *e
; e
++) {
355 continuation
= strdup(l
);
383 log_warning_errno(r
, "Failed to parse file '%s': %m",
392 /* Parse each config file in the specified directories. */
393 int config_parse_many(const char *conf_file
,
394 const char *conf_file_dirs
,
395 const char *sections
,
396 ConfigItemLookup lookup
,
400 _cleanup_strv_free_
char **files
= NULL
;
404 r
= conf_files_list_nulstr(&files
, ".conf", NULL
, conf_file_dirs
);
409 r
= config_parse(NULL
, conf_file
, NULL
, sections
, lookup
, table
, relaxed
, false, true, userdata
);
414 STRV_FOREACH(fn
, files
) {
415 r
= config_parse(NULL
, *fn
, NULL
, sections
, lookup
, table
, relaxed
, false, true, userdata
);
423 #define DEFINE_PARSER(type, vartype, conv_func) \
424 int config_parse_##type(const char *unit, \
425 const char *filename, \
427 const char *section, \
428 unsigned section_line, \
429 const char *lvalue, \
431 const char *rvalue, \
443 r = conv_func(rvalue, i); \
445 log_syntax(unit, LOG_ERR, filename, line, -r, \
446 "Failed to parse %s value, ignoring: %s", \
452 DEFINE_PARSER(int, int, safe_atoi
)
453 DEFINE_PARSER(long, long, safe_atoli
)
454 DEFINE_PARSER(uint32
, uint32_t, safe_atou32
)
455 DEFINE_PARSER(uint64
, uint64_t, safe_atou64
)
456 DEFINE_PARSER(unsigned, unsigned, safe_atou
)
457 DEFINE_PARSER(double, double, safe_atod
)
458 DEFINE_PARSER(nsec
, nsec_t
, parse_nsec
)
459 DEFINE_PARSER(sec
, usec_t
, parse_sec
)
461 int config_parse_iec_size(const char* unit
,
462 const char *filename
,
465 unsigned section_line
,
481 r
= parse_size(rvalue
, 1024, &o
);
482 if (r
< 0 || (off_t
) (size_t) o
!= o
) {
483 log_syntax(unit
, LOG_ERR
, filename
, line
, r
< 0 ? -r
: ERANGE
, "Failed to parse size value, ignoring: %s", rvalue
);
491 int config_parse_si_size(const char* unit
,
492 const char *filename
,
495 unsigned section_line
,
511 r
= parse_size(rvalue
, 1000, &o
);
512 if (r
< 0 || (off_t
) (size_t) o
!= o
) {
513 log_syntax(unit
, LOG_ERR
, filename
, line
, r
< 0 ? -r
: ERANGE
, "Failed to parse size value, ignoring: %s", rvalue
);
521 int config_parse_iec_off(const char* unit
,
522 const char *filename
,
525 unsigned section_line
,
540 assert_cc(sizeof(off_t
) == sizeof(uint64_t));
542 r
= parse_size(rvalue
, 1024, bytes
);
544 log_syntax(unit
, LOG_ERR
, filename
, line
, -r
, "Failed to parse size value, ignoring: %s", rvalue
);
549 int config_parse_bool(const char* unit
,
550 const char *filename
,
553 unsigned section_line
,
568 k
= parse_boolean(rvalue
);
570 log_syntax(unit
, LOG_ERR
, filename
, line
, -k
,
571 "Failed to parse boolean value, ignoring: %s", rvalue
);
579 int config_parse_tristate(
581 const char *filename
,
584 unsigned section_line
,
598 /* A tristate is pretty much a boolean, except that it can
599 * also take the special value -1, indicating "uninitialized",
600 * much like NULL is for a pointer type. */
602 k
= parse_boolean(rvalue
);
604 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
612 int config_parse_string(
614 const char *filename
,
617 unsigned section_line
,
631 if (!utf8_is_valid(rvalue
)) {
632 log_invalid_utf8(unit
, LOG_ERR
, filename
, line
, EINVAL
, rvalue
);
650 int config_parse_path(
652 const char *filename
,
655 unsigned section_line
,
669 if (!utf8_is_valid(rvalue
)) {
670 log_invalid_utf8(unit
, LOG_ERR
, filename
, line
, EINVAL
, rvalue
);
674 if (!path_is_absolute(rvalue
)) {
675 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
, "Not an absolute path, ignoring: %s", rvalue
);
683 path_kill_slashes(n
);
691 int config_parse_strv(const char *unit
,
692 const char *filename
,
695 unsigned section_line
,
703 const char *word
, *state
;
712 if (isempty(rvalue
)) {
715 /* Empty assignment resets the list. As a special rule
716 * we actually fill in a real empty array here rather
717 * than NULL, since some code wants to know if
718 * something was set at all... */
719 empty
= strv_new(NULL
, NULL
);
728 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
731 n
= strndup(word
, l
);
735 if (!utf8_is_valid(n
)) {
736 log_invalid_utf8(unit
, LOG_ERR
, filename
, line
, EINVAL
, rvalue
);
741 r
= strv_consume(sv
, n
);
746 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
747 "Trailing garbage, ignoring.");
752 int config_parse_mode(
754 const char *filename
,
757 unsigned section_line
,
771 if (parse_mode(rvalue
, m
) < 0) {
772 log_syntax(unit
, LOG_ERR
, filename
, line
, errno
, "Failed to parse mode value, ignoring: %s", rvalue
);
779 int config_parse_log_facility(
781 const char *filename
,
784 unsigned section_line
,
799 x
= log_facility_unshifted_from_string(rvalue
);
801 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
, "Failed to parse log facility, ignoring: %s", rvalue
);
805 *o
= (x
<< 3) | LOG_PRI(*o
);
810 int config_parse_log_level(
812 const char *filename
,
815 unsigned section_line
,
830 x
= log_level_from_string(rvalue
);
832 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
, "Failed to parse log level, ignoring: %s", rvalue
);
836 *o
= (*o
& LOG_FACMASK
) | x
;
840 int config_parse_signal(
842 const char *filename
,
845 unsigned section_line
,
859 r
= signal_from_string_try_harder(rvalue
);
861 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
, "Failed to parse signal name, ignoring: %s", rvalue
);
869 int config_parse_personality(
871 const char *filename
,
874 unsigned section_line
,
881 unsigned long *personality
= data
, p
;
888 p
= personality_from_string(rvalue
);
889 if (p
== PERSONALITY_INVALID
) {
890 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
, "Failed to parse personality, ignoring: %s", rvalue
);