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 "conf-parser.h"
28 #include "conf-files.h"
34 #include "path-util.h"
35 #include "sd-messages.h"
37 int config_item_table_lookup(
41 ConfigParserCallback
*func
,
46 const ConfigTableItem
*t
;
54 for (t
= table
; t
->lvalue
; t
++) {
56 if (!streq(lvalue
, t
->lvalue
))
59 if (!streq_ptr(section
, t
->section
))
71 int config_item_perf_lookup(
75 ConfigParserCallback
*func
,
80 ConfigPerfItemLookup lookup
= (ConfigPerfItemLookup
) table
;
81 const ConfigPerfItem
*p
;
90 p
= lookup(lvalue
, strlen(lvalue
));
94 key
= strjoin(section
, ".", lvalue
, NULL
);
98 p
= lookup(key
, strlen(key
));
107 *data
= (uint8_t*) userdata
+ p
->offset
;
111 /* Run the user supplied parser for an assignment */
112 static int next_assignment(const char *unit
,
113 const char *filename
,
115 ConfigItemLookup lookup
,
118 unsigned section_line
,
124 ConfigParserCallback func
= NULL
;
135 r
= lookup(table
, section
, lvalue
, &func
, <ype
, &data
, userdata
);
141 return func(unit
, filename
, line
, section
, section_line
,
142 lvalue
, ltype
, rvalue
, data
, userdata
);
147 /* Warn about unknown non-extension fields. */
148 if (!relaxed
&& !startswith(lvalue
, "X-"))
149 log_syntax(unit
, LOG_WARNING
, filename
, line
, EINVAL
,
150 "Unknown lvalue '%s' in section '%s'", lvalue
, section
);
155 /* Parse a variable assignment line */
156 static int parse_line(const char* unit
,
157 const char *filename
,
159 const char *sections
,
160 ConfigItemLookup lookup
,
165 unsigned *section_line
,
166 bool *section_ignored
,
182 if (strchr(COMMENTS
"\n", *l
))
185 if (startswith(l
, ".include ")) {
186 _cleanup_free_
char *fn
= NULL
;
188 /* .includes are a bad idea, we only support them here
189 * for historical reasons. They create cyclic include
190 * problems and make it difficult to detect
191 * configuration file changes with an easy
192 * stat(). Better approaches, such as .d/ drop-in
195 * Support for them should be eventually removed. */
197 if (!allow_include
) {
198 log_syntax(unit
, LOG_ERR
, filename
, line
, EBADMSG
,
199 ".include not allowed here. Ignoring.");
203 fn
= file_in_same_dir(filename
, strstrip(l
+9));
207 return config_parse(unit
, fn
, NULL
, sections
, lookup
, table
, relaxed
, false, false, userdata
);
218 log_syntax(unit
, LOG_ERR
, filename
, line
, EBADMSG
,
219 "Invalid section header '%s'", l
);
223 n
= strndup(l
+1, k
-2);
227 if (sections
&& !nulstr_contains(sections
, n
)) {
229 if (!relaxed
&& !startswith(n
, "X-"))
230 log_syntax(unit
, LOG_WARNING
, filename
, line
, EINVAL
,
231 "Unknown section '%s'. Ignoring.", n
);
237 *section_ignored
= true;
241 *section_line
= line
;
242 *section_ignored
= false;
248 if (sections
&& !*section
) {
250 if (!relaxed
&& !*section_ignored
)
251 log_syntax(unit
, LOG_WARNING
, filename
, line
, EINVAL
,
252 "Assignment outside of section. Ignoring.");
259 log_syntax(unit
, LOG_WARNING
, filename
, line
, EINVAL
, "Missing '='.");
266 return next_assignment(unit
,
279 /* Go through the file and parse each line */
280 int config_parse(const char *unit
,
281 const char *filename
,
283 const char *sections
,
284 ConfigItemLookup lookup
,
291 _cleanup_free_
char *section
= NULL
, *continuation
= NULL
;
292 _cleanup_fclose_
FILE *ours
= NULL
;
293 unsigned line
= 0, section_line
= 0;
294 bool section_ignored
= false;
301 f
= ours
= fopen(filename
, "re");
303 /* Only log on request, except for ENOENT,
304 * since we return 0 to the caller. */
305 if (warn
|| errno
== ENOENT
)
306 log_full(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
,
307 "Failed to open configuration file '%s': %m", filename
);
308 return errno
== ENOENT
? 0 : -errno
;
312 fd_warn_permissions(filename
, fileno(f
));
315 char l
[LINE_MAX
], *p
, *c
= NULL
, *e
;
316 bool escaped
= false;
318 if (!fgets(l
, sizeof(l
), f
)) {
322 log_error_errno(errno
, "Failed to read configuration file '%s': %m", filename
);
329 c
= strappend(continuation
, l
);
336 continuation
= mfree(continuation
);
341 for (e
= p
; *e
; e
++) {
354 continuation
= strdup(l
);
382 log_warning_errno(r
, "Failed to parse file '%s': %m",
391 /* Parse each config file in the specified directories. */
392 int config_parse_many(const char *conf_file
,
393 const char *conf_file_dirs
,
394 const char *sections
,
395 ConfigItemLookup lookup
,
399 _cleanup_strv_free_
char **files
= NULL
;
403 r
= conf_files_list_nulstr(&files
, ".conf", NULL
, conf_file_dirs
);
408 r
= config_parse(NULL
, conf_file
, NULL
, sections
, lookup
, table
, relaxed
, false, true, userdata
);
413 STRV_FOREACH(fn
, files
) {
414 r
= config_parse(NULL
, *fn
, NULL
, sections
, lookup
, table
, relaxed
, false, true, userdata
);
422 #define DEFINE_PARSER(type, vartype, conv_func) \
423 int config_parse_##type(const char *unit, \
424 const char *filename, \
426 const char *section, \
427 unsigned section_line, \
428 const char *lvalue, \
430 const char *rvalue, \
442 r = conv_func(rvalue, i); \
444 log_syntax(unit, LOG_ERR, filename, line, -r, \
445 "Failed to parse %s value, ignoring: %s", \
451 DEFINE_PARSER(int, int, safe_atoi
)
452 DEFINE_PARSER(long, long, safe_atoli
)
453 DEFINE_PARSER(uint64
, uint64_t, safe_atou64
)
454 DEFINE_PARSER(unsigned, unsigned, safe_atou
)
455 DEFINE_PARSER(double, double, safe_atod
)
456 DEFINE_PARSER(nsec
, nsec_t
, parse_nsec
)
457 DEFINE_PARSER(sec
, usec_t
, parse_sec
)
459 int config_parse_iec_size(const char* unit
,
460 const char *filename
,
463 unsigned section_line
,
479 r
= parse_size(rvalue
, 1024, &o
);
480 if (r
< 0 || (off_t
) (size_t) o
!= o
) {
481 log_syntax(unit
, LOG_ERR
, filename
, line
, r
< 0 ? -r
: ERANGE
, "Failed to parse size value, ignoring: %s", rvalue
);
489 int config_parse_si_size(const char* unit
,
490 const char *filename
,
493 unsigned section_line
,
509 r
= parse_size(rvalue
, 1000, &o
);
510 if (r
< 0 || (off_t
) (size_t) o
!= o
) {
511 log_syntax(unit
, LOG_ERR
, filename
, line
, r
< 0 ? -r
: ERANGE
, "Failed to parse size value, ignoring: %s", rvalue
);
519 int config_parse_iec_off(const char* unit
,
520 const char *filename
,
523 unsigned section_line
,
538 assert_cc(sizeof(off_t
) == sizeof(uint64_t));
540 r
= parse_size(rvalue
, 1024, bytes
);
542 log_syntax(unit
, LOG_ERR
, filename
, line
, -r
, "Failed to parse size value, ignoring: %s", rvalue
);
547 int config_parse_bool(const char* unit
,
548 const char *filename
,
551 unsigned section_line
,
566 k
= parse_boolean(rvalue
);
568 log_syntax(unit
, LOG_ERR
, filename
, line
, -k
,
569 "Failed to parse boolean value, ignoring: %s", rvalue
);
577 int config_parse_string(
579 const char *filename
,
582 unsigned section_line
,
596 if (!utf8_is_valid(rvalue
)) {
597 log_invalid_utf8(unit
, LOG_ERR
, filename
, line
, EINVAL
, rvalue
);
615 int config_parse_path(
617 const char *filename
,
620 unsigned section_line
,
634 if (!utf8_is_valid(rvalue
)) {
635 log_invalid_utf8(unit
, LOG_ERR
, filename
, line
, EINVAL
, rvalue
);
639 if (!path_is_absolute(rvalue
)) {
640 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
, "Not an absolute path, ignoring: %s", rvalue
);
648 path_kill_slashes(n
);
656 int config_parse_strv(const char *unit
,
657 const char *filename
,
660 unsigned section_line
,
668 const char *word
, *state
;
677 if (isempty(rvalue
)) {
680 /* Empty assignment resets the list. As a special rule
681 * we actually fill in a real empty array here rather
682 * than NULL, since some code wants to know if
683 * something was set at all... */
684 empty
= strv_new(NULL
, NULL
);
693 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
696 n
= strndup(word
, l
);
700 if (!utf8_is_valid(n
)) {
701 log_invalid_utf8(unit
, LOG_ERR
, filename
, line
, EINVAL
, rvalue
);
706 r
= strv_consume(sv
, n
);
711 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
712 "Trailing garbage, ignoring.");
717 int config_parse_mode(
719 const char *filename
,
722 unsigned section_line
,
736 if (parse_mode(rvalue
, m
) < 0) {
737 log_syntax(unit
, LOG_ERR
, filename
, line
, errno
, "Failed to parse mode value, ignoring: %s", rvalue
);
744 int config_parse_log_facility(
746 const char *filename
,
749 unsigned section_line
,
764 x
= log_facility_unshifted_from_string(rvalue
);
766 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
, "Failed to parse log facility, ignoring: %s", rvalue
);
770 *o
= (x
<< 3) | LOG_PRI(*o
);
775 int config_parse_log_level(
777 const char *filename
,
780 unsigned section_line
,
795 x
= log_level_from_string(rvalue
);
797 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
, "Failed to parse log level, ignoring: %s", rvalue
);
801 *o
= (*o
& LOG_FACMASK
) | x
;