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
);
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(uint64
, uint64_t, safe_atou64
)
455 DEFINE_PARSER(unsigned, unsigned, safe_atou
)
456 DEFINE_PARSER(double, double, safe_atod
)
457 DEFINE_PARSER(nsec
, nsec_t
, parse_nsec
)
458 DEFINE_PARSER(sec
, usec_t
, parse_sec
)
460 int config_parse_iec_size(const char* unit
,
461 const char *filename
,
464 unsigned section_line
,
480 r
= parse_size(rvalue
, 1024, &o
);
481 if (r
< 0 || (off_t
) (size_t) o
!= o
) {
482 log_syntax(unit
, LOG_ERR
, filename
, line
, r
< 0 ? -r
: ERANGE
, "Failed to parse size value, ignoring: %s", rvalue
);
490 int config_parse_si_size(const char* unit
,
491 const char *filename
,
494 unsigned section_line
,
510 r
= parse_size(rvalue
, 1000, &o
);
511 if (r
< 0 || (off_t
) (size_t) o
!= o
) {
512 log_syntax(unit
, LOG_ERR
, filename
, line
, r
< 0 ? -r
: ERANGE
, "Failed to parse size value, ignoring: %s", rvalue
);
520 int config_parse_iec_off(const char* unit
,
521 const char *filename
,
524 unsigned section_line
,
539 assert_cc(sizeof(off_t
) == sizeof(uint64_t));
541 r
= parse_size(rvalue
, 1024, bytes
);
543 log_syntax(unit
, LOG_ERR
, filename
, line
, -r
, "Failed to parse size value, ignoring: %s", rvalue
);
548 int config_parse_bool(const char* unit
,
549 const char *filename
,
552 unsigned section_line
,
567 k
= parse_boolean(rvalue
);
569 log_syntax(unit
, LOG_ERR
, filename
, line
, -k
,
570 "Failed to parse boolean value, ignoring: %s", rvalue
);
578 int config_parse_string(
580 const char *filename
,
583 unsigned section_line
,
597 if (!utf8_is_valid(rvalue
)) {
598 log_invalid_utf8(unit
, LOG_ERR
, filename
, line
, EINVAL
, rvalue
);
616 int config_parse_path(
618 const char *filename
,
621 unsigned section_line
,
635 if (!utf8_is_valid(rvalue
)) {
636 log_invalid_utf8(unit
, LOG_ERR
, filename
, line
, EINVAL
, rvalue
);
640 if (!path_is_absolute(rvalue
)) {
641 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
, "Not an absolute path, ignoring: %s", rvalue
);
649 path_kill_slashes(n
);
657 int config_parse_strv(const char *unit
,
658 const char *filename
,
661 unsigned section_line
,
669 const char *word
, *state
;
678 if (isempty(rvalue
)) {
681 /* Empty assignment resets the list. As a special rule
682 * we actually fill in a real empty array here rather
683 * than NULL, since some code wants to know if
684 * something was set at all... */
685 empty
= strv_new(NULL
, NULL
);
694 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
697 n
= strndup(word
, l
);
701 if (!utf8_is_valid(n
)) {
702 log_invalid_utf8(unit
, LOG_ERR
, filename
, line
, EINVAL
, rvalue
);
707 r
= strv_consume(sv
, n
);
712 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
713 "Trailing garbage, ignoring.");
718 int config_parse_mode(
720 const char *filename
,
723 unsigned section_line
,
737 if (parse_mode(rvalue
, m
) < 0) {
738 log_syntax(unit
, LOG_ERR
, filename
, line
, errno
, "Failed to parse mode value, ignoring: %s", rvalue
);
745 int config_parse_log_facility(
747 const char *filename
,
750 unsigned section_line
,
765 x
= log_facility_unshifted_from_string(rvalue
);
767 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
, "Failed to parse log facility, ignoring: %s", rvalue
);
771 *o
= (x
<< 3) | LOG_PRI(*o
);
776 int config_parse_log_level(
778 const char *filename
,
781 unsigned section_line
,
796 x
= log_level_from_string(rvalue
);
798 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
, "Failed to parse log level, ignoring: %s", rvalue
);
802 *o
= (*o
& LOG_FACMASK
) | x
;