2 This file is part of systemd.
4 Copyright 2010 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include <sys/types.h>
28 #include "alloc-util.h"
29 #include "conf-files.h"
30 #include "conf-parser.h"
32 #include "extract-word.h"
38 #include "parse-util.h"
39 #include "path-util.h"
40 #include "process-util.h"
41 #include "signal-util.h"
42 #include "socket-util.h"
43 #include "string-util.h"
45 #include "syslog-util.h"
46 #include "time-util.h"
49 int config_item_table_lookup(
53 ConfigParserCallback
*func
,
58 const ConfigTableItem
*t
;
66 for (t
= table
; t
->lvalue
; t
++) {
68 if (!streq(lvalue
, t
->lvalue
))
71 if (!streq_ptr(section
, t
->section
))
83 int config_item_perf_lookup(
87 ConfigParserCallback
*func
,
92 ConfigPerfItemLookup lookup
= (ConfigPerfItemLookup
) table
;
93 const ConfigPerfItem
*p
;
102 p
= lookup(lvalue
, strlen(lvalue
));
106 key
= strjoin(section
, ".", lvalue
);
110 p
= lookup(key
, strlen(key
));
119 *data
= (uint8_t*) userdata
+ p
->offset
;
123 /* Run the user supplied parser for an assignment */
124 static int next_assignment(
126 const char *filename
,
128 ConfigItemLookup lookup
,
131 unsigned section_line
,
134 ConfigParseFlags flags
,
137 ConfigParserCallback func
= NULL
;
148 r
= lookup(table
, section
, lvalue
, &func
, <ype
, &data
, userdata
);
154 return func(unit
, filename
, line
, section
, section_line
,
155 lvalue
, ltype
, rvalue
, data
, userdata
);
160 /* Warn about unknown non-extension fields. */
161 if (!(flags
& CONFIG_PARSE_RELAXED
) && !startswith(lvalue
, "X-"))
162 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Unknown lvalue '%s' in section '%s'", lvalue
, section
);
167 /* Parse a variable assignment line */
168 static int parse_line(
170 const char *filename
,
172 const char *sections
,
173 ConfigItemLookup lookup
,
175 ConfigParseFlags flags
,
177 unsigned *section_line
,
178 bool *section_ignored
,
193 if (strchr(COMMENTS
"\n", *l
))
196 if (startswith(l
, ".include ")) {
197 _cleanup_free_
char *fn
= NULL
;
199 /* .includes are a bad idea, we only support them here
200 * for historical reasons. They create cyclic include
201 * problems and make it difficult to detect
202 * configuration file changes with an easy
203 * stat(). Better approaches, such as .d/ drop-in
206 * Support for them should be eventually removed. */
208 if (!(flags
& CONFIG_PARSE_ALLOW_INCLUDE
)) {
209 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, ".include not allowed here. Ignoring.");
213 fn
= file_in_same_dir(filename
, strstrip(l
+9));
217 return config_parse(unit
, fn
, NULL
, sections
, lookup
, table
, flags
, userdata
);
228 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid section header '%s'", l
);
232 n
= strndup(l
+1, k
-2);
236 if (sections
&& !nulstr_contains(sections
, n
)) {
238 if (!(flags
& CONFIG_PARSE_RELAXED
) && !startswith(n
, "X-"))
239 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Unknown section '%s'. Ignoring.", n
);
242 *section
= mfree(*section
);
244 *section_ignored
= true;
248 *section_line
= line
;
249 *section_ignored
= false;
255 if (sections
&& !*section
) {
257 if (!(flags
& CONFIG_PARSE_RELAXED
) && !*section_ignored
)
258 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Assignment outside of section. Ignoring.");
265 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Missing '='.");
272 return next_assignment(unit
,
285 /* Go through the file and parse each line */
286 int config_parse(const char *unit
,
287 const char *filename
,
289 const char *sections
,
290 ConfigItemLookup lookup
,
292 ConfigParseFlags flags
,
295 _cleanup_free_
char *section
= NULL
, *continuation
= NULL
;
296 _cleanup_fclose_
FILE *ours
= NULL
;
297 unsigned line
= 0, section_line
= 0;
298 bool section_ignored
= false;
305 f
= ours
= fopen(filename
, "re");
307 /* Only log on request, except for ENOENT,
308 * since we return 0 to the caller. */
309 if ((flags
& CONFIG_PARSE_WARN
) || errno
== ENOENT
)
310 log_full(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
,
311 "Failed to open configuration file '%s': %m", filename
);
312 return errno
== ENOENT
? 0 : -errno
;
316 fd_warn_permissions(filename
, fileno(f
));
319 _cleanup_free_
char *buf
= NULL
;
320 bool escaped
= false;
323 r
= read_line(f
, LONG_LINE_MAX
, &buf
);
327 if (flags
& CONFIG_PARSE_WARN
)
328 log_error_errno(r
, "%s:%u: Line too long", filename
, line
);
333 if (CONFIG_PARSE_WARN
)
334 log_error_errno(r
, "%s:%u: Error while reading configuration file: %m", filename
, line
);
340 if (!(flags
& CONFIG_PARSE_REFUSE_BOM
)) {
343 q
= startswith(buf
, UTF8_BYTE_ORDER_MARK
);
346 flags
|= CONFIG_PARSE_REFUSE_BOM
;
351 if (strlen(continuation
) + strlen(l
) > LONG_LINE_MAX
) {
352 if (flags
& CONFIG_PARSE_WARN
)
353 log_error("%s:%u: Continuation line too long", filename
, line
);
357 if (!strextend(&continuation
, l
, NULL
)) {
358 if (flags
& CONFIG_PARSE_WARN
)
367 for (e
= p
; *e
; e
++) {
378 continuation
= strdup(l
);
380 if (flags
& CONFIG_PARSE_WARN
)
402 if (flags
& CONFIG_PARSE_WARN
)
403 log_warning_errno(r
, "%s:%u: Failed to parse file: %m", filename
, line
);
408 continuation
= mfree(continuation
);
414 static int config_parse_many_files(
415 const char *conf_file
,
417 const char *sections
,
418 ConfigItemLookup lookup
,
420 ConfigParseFlags flags
,
427 r
= config_parse(NULL
, conf_file
, NULL
, sections
, lookup
, table
, flags
, userdata
);
432 STRV_FOREACH(fn
, files
) {
433 r
= config_parse(NULL
, *fn
, NULL
, sections
, lookup
, table
, flags
, userdata
);
441 /* Parse each config file in the directories specified as nulstr. */
442 int config_parse_many_nulstr(
443 const char *conf_file
,
444 const char *conf_file_dirs
,
445 const char *sections
,
446 ConfigItemLookup lookup
,
448 ConfigParseFlags flags
,
451 _cleanup_strv_free_
char **files
= NULL
;
454 r
= conf_files_list_nulstr(&files
, ".conf", NULL
, 0, conf_file_dirs
);
458 return config_parse_many_files(conf_file
, files
, sections
, lookup
, table
, flags
, userdata
);
461 /* Parse each config file in the directories specified as strv. */
462 int config_parse_many(
463 const char *conf_file
,
464 const char* const* conf_file_dirs
,
465 const char *dropin_dirname
,
466 const char *sections
,
467 ConfigItemLookup lookup
,
469 ConfigParseFlags flags
,
472 _cleanup_strv_free_
char **dropin_dirs
= NULL
;
473 _cleanup_strv_free_
char **files
= NULL
;
477 suffix
= strjoina("/", dropin_dirname
);
478 r
= strv_extend_strv_concat(&dropin_dirs
, (char**) conf_file_dirs
, suffix
);
482 r
= conf_files_list_strv(&files
, ".conf", NULL
, 0, (const char* const*) dropin_dirs
);
486 return config_parse_many_files(conf_file
, files
, sections
, lookup
, table
, flags
, userdata
);
489 #define DEFINE_PARSER(type, vartype, conv_func) \
490 int config_parse_##type( \
492 const char *filename, \
494 const char *section, \
495 unsigned section_line, \
496 const char *lvalue, \
498 const char *rvalue, \
510 r = conv_func(rvalue, i); \
512 log_syntax(unit, LOG_ERR, filename, line, r, \
513 "Failed to parse %s value, ignoring: %s", \
518 struct __useless_struct_to_allow_trailing_semicolon__
520 DEFINE_PARSER(int, int, safe_atoi
);
521 DEFINE_PARSER(long, long, safe_atoli
);
522 DEFINE_PARSER(uint8
, uint8_t, safe_atou8
);
523 DEFINE_PARSER(uint16
, uint16_t, safe_atou16
);
524 DEFINE_PARSER(uint32
, uint32_t, safe_atou32
);
525 DEFINE_PARSER(uint64
, uint64_t, safe_atou64
);
526 DEFINE_PARSER(unsigned, unsigned, safe_atou
);
527 DEFINE_PARSER(double, double, safe_atod
);
528 DEFINE_PARSER(nsec
, nsec_t
, parse_nsec
);
529 DEFINE_PARSER(sec
, usec_t
, parse_sec
);
530 DEFINE_PARSER(mode
, mode_t
, parse_mode
);
532 int config_parse_iec_size(const char* unit
,
533 const char *filename
,
536 unsigned section_line
,
552 r
= parse_size(rvalue
, 1024, &v
);
553 if (r
< 0 || (uint64_t) (size_t) v
!= v
) {
554 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
562 int config_parse_si_size(
564 const char *filename
,
567 unsigned section_line
,
583 r
= parse_size(rvalue
, 1000, &v
);
584 if (r
< 0 || (uint64_t) (size_t) v
!= v
) {
585 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
593 int config_parse_iec_uint64(
595 const char *filename
,
598 unsigned section_line
,
605 uint64_t *bytes
= data
;
613 r
= parse_size(rvalue
, 1024, bytes
);
615 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
620 int config_parse_bool(const char* unit
,
621 const char *filename
,
624 unsigned section_line
,
640 k
= parse_boolean(rvalue
);
642 log_syntax(unit
, LOG_ERR
, filename
, line
, k
,
643 "Failed to parse boolean value%s: %s",
644 fatal
? "" : ", ignoring", rvalue
);
645 return fatal
? -ENOEXEC
: 0;
652 int config_parse_tristate(
654 const char *filename
,
657 unsigned section_line
,
671 /* A tristate is pretty much a boolean, except that it can
672 * also take the special value -1, indicating "uninitialized",
673 * much like NULL is for a pointer type. */
675 k
= parse_boolean(rvalue
);
677 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
685 int config_parse_string(
687 const char *filename
,
690 unsigned section_line
,
704 if (!utf8_is_valid(rvalue
)) {
705 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
723 int config_parse_path(
725 const char *filename
,
728 unsigned section_line
,
743 if (isempty(rvalue
)) {
748 if (!utf8_is_valid(rvalue
)) {
749 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
750 return fatal
? -ENOEXEC
: 0;
753 if (!path_is_absolute(rvalue
)) {
754 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
755 "Not an absolute path%s: %s",
756 fatal
? "" : ", ignoring", rvalue
);
757 return fatal
? -ENOEXEC
: 0;
764 path_kill_slashes(n
);
773 int config_parse_strv(
775 const char *filename
,
778 unsigned section_line
,
793 if (isempty(rvalue
)) {
794 *sv
= strv_free(*sv
);
801 r
= extract_first_word(&rvalue
, &word
, NULL
, EXTRACT_QUOTES
|EXTRACT_RETAIN_ESCAPE
);
807 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
811 if (!utf8_is_valid(word
)) {
812 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, word
);
817 r
= strv_consume(sv
, word
);
825 int config_parse_log_facility(
827 const char *filename
,
830 unsigned section_line
,
844 x
= log_facility_unshifted_from_string(rvalue
);
846 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse log facility, ignoring: %s", rvalue
);
850 *o
= (x
<< 3) | LOG_PRI(*o
);
855 int config_parse_log_level(
857 const char *filename
,
860 unsigned section_line
,
874 x
= log_level_from_string(rvalue
);
876 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse log level, ignoring: %s", rvalue
);
880 if (*o
< 0) /* if it wasn't initialized so far, assume zero facility */
883 *o
= (*o
& LOG_FACMASK
) | x
;
888 int config_parse_signal(
890 const char *filename
,
893 unsigned section_line
,
907 r
= signal_from_string_try_harder(rvalue
);
909 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse signal name, ignoring: %s", rvalue
);
917 int config_parse_personality(
919 const char *filename
,
922 unsigned section_line
,
929 unsigned long *personality
= data
, p
;
937 p
= PERSONALITY_INVALID
;
939 p
= personality_from_string(rvalue
);
940 if (p
== PERSONALITY_INVALID
) {
941 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse personality, ignoring: %s", rvalue
);
950 int config_parse_ifname(
952 const char *filename
,
955 unsigned section_line
,
970 if (isempty(rvalue
)) {
975 if (!ifname_valid(rvalue
)) {
976 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue
);
980 r
= free_and_strdup(s
, rvalue
);
987 int config_parse_ip_port(
989 const char *filename
,
992 unsigned section_line
,
1008 if (isempty(rvalue
)) {
1013 r
= parse_ip_port(rvalue
, &port
);
1015 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse port '%s'.", rvalue
);