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"
29 #include "conf-files.h"
30 #include "conf-parser.h"
34 #include "parse-util.h"
35 #include "path-util.h"
36 #include "signal-util.h"
37 #include "string-util.h"
42 int config_item_table_lookup(
46 ConfigParserCallback
*func
,
51 const ConfigTableItem
*t
;
59 for (t
= table
; t
->lvalue
; t
++) {
61 if (!streq(lvalue
, t
->lvalue
))
64 if (!streq_ptr(section
, t
->section
))
76 int config_item_perf_lookup(
80 ConfigParserCallback
*func
,
85 ConfigPerfItemLookup lookup
= (ConfigPerfItemLookup
) table
;
86 const ConfigPerfItem
*p
;
95 p
= lookup(lvalue
, strlen(lvalue
));
99 key
= strjoin(section
, ".", lvalue
, NULL
);
103 p
= lookup(key
, strlen(key
));
112 *data
= (uint8_t*) userdata
+ p
->offset
;
116 /* Run the user supplied parser for an assignment */
117 static int next_assignment(const char *unit
,
118 const char *filename
,
120 ConfigItemLookup lookup
,
123 unsigned section_line
,
129 ConfigParserCallback func
= NULL
;
140 r
= lookup(table
, section
, lvalue
, &func
, <ype
, &data
, userdata
);
146 return func(unit
, filename
, line
, section
, section_line
,
147 lvalue
, ltype
, rvalue
, data
, userdata
);
152 /* Warn about unknown non-extension fields. */
153 if (!relaxed
&& !startswith(lvalue
, "X-"))
154 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Unknown lvalue '%s' in section '%s'", lvalue
, section
);
159 /* Parse a variable assignment line */
160 static int parse_line(const char* unit
,
161 const char *filename
,
163 const char *sections
,
164 ConfigItemLookup lookup
,
169 unsigned *section_line
,
170 bool *section_ignored
,
186 if (strchr(COMMENTS
"\n", *l
))
189 if (startswith(l
, ".include ")) {
190 _cleanup_free_
char *fn
= NULL
;
192 /* .includes are a bad idea, we only support them here
193 * for historical reasons. They create cyclic include
194 * problems and make it difficult to detect
195 * configuration file changes with an easy
196 * stat(). Better approaches, such as .d/ drop-in
199 * Support for them should be eventually removed. */
201 if (!allow_include
) {
202 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, ".include not allowed here. Ignoring.");
206 fn
= file_in_same_dir(filename
, strstrip(l
+9));
210 return config_parse(unit
, fn
, NULL
, sections
, lookup
, table
, relaxed
, false, false, userdata
);
221 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid section header '%s'", l
);
225 n
= strndup(l
+1, k
-2);
229 if (sections
&& !nulstr_contains(sections
, n
)) {
231 if (!relaxed
&& !startswith(n
, "X-"))
232 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Unknown section '%s'. Ignoring.", n
);
235 *section
= mfree(*section
);
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
, 0, "Assignment outside of section. Ignoring.");
258 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Missing '='.");
265 return next_assignment(unit
,
278 /* Go through the file and parse each line */
279 int config_parse(const char *unit
,
280 const char *filename
,
282 const char *sections
,
283 ConfigItemLookup lookup
,
290 _cleanup_free_
char *section
= NULL
, *continuation
= NULL
;
291 _cleanup_fclose_
FILE *ours
= NULL
;
292 unsigned line
= 0, section_line
= 0;
293 bool section_ignored
= false;
300 f
= ours
= fopen(filename
, "re");
302 /* Only log on request, except for ENOENT,
303 * since we return 0 to the caller. */
304 if (warn
|| errno
== ENOENT
)
305 log_full(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
,
306 "Failed to open configuration file '%s': %m", filename
);
307 return errno
== ENOENT
? 0 : -errno
;
311 fd_warn_permissions(filename
, fileno(f
));
314 char l
[LINE_MAX
], *p
, *c
= NULL
, *e
;
315 bool escaped
= false;
317 if (!fgets(l
, sizeof(l
), f
)) {
321 log_error_errno(errno
, "Failed to read configuration file '%s': %m", filename
);
328 c
= strappend(continuation
, l
);
335 continuation
= mfree(continuation
);
340 for (e
= p
; *e
; e
++) {
353 continuation
= strdup(l
);
381 log_warning_errno(r
, "Failed to parse file '%s': %m",
390 /* Parse each config file in the specified directories. */
391 int config_parse_many(const char *conf_file
,
392 const char *conf_file_dirs
,
393 const char *sections
,
394 ConfigItemLookup lookup
,
398 _cleanup_strv_free_
char **files
= NULL
;
402 r
= conf_files_list_nulstr(&files
, ".conf", NULL
, conf_file_dirs
);
407 r
= config_parse(NULL
, conf_file
, NULL
, sections
, lookup
, table
, relaxed
, false, true, userdata
);
412 STRV_FOREACH(fn
, files
) {
413 r
= config_parse(NULL
, *fn
, NULL
, sections
, lookup
, table
, relaxed
, false, true, userdata
);
421 #define DEFINE_PARSER(type, vartype, conv_func) \
422 int config_parse_##type( \
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", \
450 struct __useless_struct_to_allow_trailing_semicolon__
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
);
460 DEFINE_PARSER(mode
, mode_t
, parse_mode
);
462 int config_parse_iec_size(const char* unit
,
463 const char *filename
,
466 unsigned section_line
,
482 r
= parse_size(rvalue
, 1024, &v
);
483 if (r
< 0 || (uint64_t) (size_t) v
!= v
) {
484 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
492 int config_parse_si_size(const char* unit
,
493 const char *filename
,
496 unsigned section_line
,
512 r
= parse_size(rvalue
, 1000, &v
);
513 if (r
< 0 || (uint64_t) (size_t) v
!= v
) {
514 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
522 int config_parse_iec_uint64(const char* unit
,
523 const char *filename
,
526 unsigned section_line
,
533 uint64_t *bytes
= data
;
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
, "Failed to parse boolean value, ignoring: %s", rvalue
);
577 int config_parse_tristate(
579 const char *filename
,
582 unsigned section_line
,
596 /* A tristate is pretty much a boolean, except that it can
597 * also take the special value -1, indicating "uninitialized",
598 * much like NULL is for a pointer type. */
600 k
= parse_boolean(rvalue
);
602 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
610 int config_parse_string(
612 const char *filename
,
615 unsigned section_line
,
629 if (!utf8_is_valid(rvalue
)) {
630 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
648 int config_parse_path(
650 const char *filename
,
653 unsigned section_line
,
667 if (!utf8_is_valid(rvalue
)) {
668 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
672 if (!path_is_absolute(rvalue
)) {
673 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute path, ignoring: %s", rvalue
);
681 path_kill_slashes(n
);
689 int config_parse_strv(const char *unit
,
690 const char *filename
,
693 unsigned section_line
,
701 const char *word
, *state
;
710 if (isempty(rvalue
)) {
713 /* Empty assignment resets the list. As a special rule
714 * we actually fill in a real empty array here rather
715 * than NULL, since some code wants to know if
716 * something was set at all... */
717 empty
= strv_new(NULL
, NULL
);
726 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
729 n
= strndup(word
, l
);
733 if (!utf8_is_valid(n
)) {
734 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
739 r
= strv_consume(sv
, n
);
744 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
749 int config_parse_log_facility(
751 const char *filename
,
754 unsigned section_line
,
769 x
= log_facility_unshifted_from_string(rvalue
);
771 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse log facility, ignoring: %s", rvalue
);
775 *o
= (x
<< 3) | LOG_PRI(*o
);
780 int config_parse_log_level(
782 const char *filename
,
785 unsigned section_line
,
800 x
= log_level_from_string(rvalue
);
802 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse log level, ignoring: %s", rvalue
);
806 *o
= (*o
& LOG_FACMASK
) | x
;
810 int config_parse_signal(
812 const char *filename
,
815 unsigned section_line
,
829 r
= signal_from_string_try_harder(rvalue
);
831 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse signal name, ignoring: %s", rvalue
);
839 int config_parse_personality(
841 const char *filename
,
844 unsigned section_line
,
851 unsigned long *personality
= data
, p
;
858 p
= personality_from_string(rvalue
);
859 if (p
== PERSONALITY_INVALID
) {
860 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse personality, ignoring: %s", rvalue
);