1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
10 #include "alloc-util.h"
13 #include "time-util.h"
15 /* An abstract parser for simple, line based, shallow configuration files consisting of variable assignments only. */
17 typedef enum ConfigParseFlags
{
18 CONFIG_PARSE_RELAXED
= 1 << 0, /* Do not warn about unknown non-extension fields */
19 CONFIG_PARSE_WARN
= 1 << 1, /* Emit non-debug messages */
22 /* Argument list for parsers of specific configuration settings. */
23 #define CONFIG_PARSER_ARGUMENTS \
25 const char *filename, \
27 const char *section, \
28 unsigned section_line, \
35 /* Prototype for a parser for a specific configuration setting */
36 typedef int (*ConfigParserCallback
)(CONFIG_PARSER_ARGUMENTS
);
38 /* A macro declaring a function prototype, following the typedef above, simply because it's so cumbersomely long
39 * otherwise. (And current emacs gets irritatingly slow when editing files that contain lots of very long function
40 * prototypes on the same screen…) */
41 #define CONFIG_PARSER_PROTOTYPE(name) int name(CONFIG_PARSER_ARGUMENTS)
43 /* Wraps information for parsing a specific configuration variable, to
44 * be stored in a simple array */
45 typedef struct ConfigTableItem
{
46 const char *section
; /* Section */
47 const char *lvalue
; /* Name of the variable */
48 ConfigParserCallback parse
; /* Function that is called to parse the variable's value */
49 int ltype
; /* Distinguish different variables passed to the same callback */
50 void *data
; /* Where to store the variable's data */
53 /* Wraps information for parsing a specific configuration variable, to
54 * be stored in a gperf perfect hashtable */
55 typedef struct ConfigPerfItem
{
56 const char *section_and_lvalue
; /* Section + "." + name of the variable */
57 ConfigParserCallback parse
; /* Function that is called to parse the variable's value */
58 int ltype
; /* Distinguish different variables passed to the same callback */
59 size_t offset
; /* Offset where to store data, from the beginning of userdata */
62 /* Prototype for a low-level gperf lookup function */
63 typedef const ConfigPerfItem
* (*ConfigPerfItemLookup
)(const char *section_and_lvalue
, unsigned length
);
65 /* Prototype for a generic high-level lookup function */
66 typedef int (*ConfigItemLookup
)(
70 ConfigParserCallback
*func
,
75 /* Linear table search implementation of ConfigItemLookup, based on
76 * ConfigTableItem arrays */
77 int config_item_table_lookup(const void *table
, const char *section
, const char *lvalue
, ConfigParserCallback
*func
, int *ltype
, void **data
, void *userdata
);
79 /* gperf implementation of ConfigItemLookup, based on gperf
80 * ConfigPerfItem tables */
81 int config_item_perf_lookup(const void *table
, const char *section
, const char *lvalue
, ConfigParserCallback
*func
, int *ltype
, void **data
, void *userdata
);
87 const char *sections
, /* nulstr */
88 ConfigItemLookup lookup
,
90 ConfigParseFlags flags
,
92 usec_t
*latest_mtime
); /* input/output, possibly NULL */
94 int config_parse_many_nulstr(
95 const char *conf_file
, /* possibly NULL */
96 const char *conf_file_dirs
, /* nulstr */
97 const char *sections
, /* nulstr */
98 ConfigItemLookup lookup
,
100 ConfigParseFlags flags
,
102 usec_t
*ret_mtime
); /* possibly NULL */
104 int config_parse_many(
105 const char* const* conf_files
, /* possibly empty */
106 const char* const* conf_file_dirs
,
107 const char *dropin_dirname
,
108 const char *sections
, /* nulstr */
109 ConfigItemLookup lookup
,
111 ConfigParseFlags flags
,
113 usec_t
*ret_mtime
); /* possibly NULL */
115 CONFIG_PARSER_PROTOTYPE(config_parse_int
);
116 CONFIG_PARSER_PROTOTYPE(config_parse_unsigned
);
117 CONFIG_PARSER_PROTOTYPE(config_parse_long
);
118 CONFIG_PARSER_PROTOTYPE(config_parse_uint8
);
119 CONFIG_PARSER_PROTOTYPE(config_parse_uint16
);
120 CONFIG_PARSER_PROTOTYPE(config_parse_uint32
);
121 CONFIG_PARSER_PROTOTYPE(config_parse_int32
);
122 CONFIG_PARSER_PROTOTYPE(config_parse_uint64
);
123 CONFIG_PARSER_PROTOTYPE(config_parse_double
);
124 CONFIG_PARSER_PROTOTYPE(config_parse_iec_size
);
125 CONFIG_PARSER_PROTOTYPE(config_parse_si_uint64
);
126 CONFIG_PARSER_PROTOTYPE(config_parse_iec_uint64
);
127 CONFIG_PARSER_PROTOTYPE(config_parse_bool
);
128 CONFIG_PARSER_PROTOTYPE(config_parse_id128
);
129 CONFIG_PARSER_PROTOTYPE(config_parse_tristate
);
130 CONFIG_PARSER_PROTOTYPE(config_parse_string
);
131 CONFIG_PARSER_PROTOTYPE(config_parse_path
);
132 CONFIG_PARSER_PROTOTYPE(config_parse_strv
);
133 CONFIG_PARSER_PROTOTYPE(config_parse_sec
);
134 CONFIG_PARSER_PROTOTYPE(config_parse_sec_def_infinity
);
135 CONFIG_PARSER_PROTOTYPE(config_parse_sec_def_unset
);
136 CONFIG_PARSER_PROTOTYPE(config_parse_nsec
);
137 CONFIG_PARSER_PROTOTYPE(config_parse_mode
);
138 CONFIG_PARSER_PROTOTYPE(config_parse_warn_compat
);
139 CONFIG_PARSER_PROTOTYPE(config_parse_log_facility
);
140 CONFIG_PARSER_PROTOTYPE(config_parse_log_level
);
141 CONFIG_PARSER_PROTOTYPE(config_parse_signal
);
142 CONFIG_PARSER_PROTOTYPE(config_parse_personality
);
143 CONFIG_PARSER_PROTOTYPE(config_parse_permille
);
144 CONFIG_PARSER_PROTOTYPE(config_parse_ifname
);
145 CONFIG_PARSER_PROTOTYPE(config_parse_ifnames
);
146 CONFIG_PARSER_PROTOTYPE(config_parse_ip_port
);
147 CONFIG_PARSER_PROTOTYPE(config_parse_mtu
);
148 CONFIG_PARSER_PROTOTYPE(config_parse_rlimit
);
149 CONFIG_PARSER_PROTOTYPE(config_parse_vlanprotocol
);
150 CONFIG_PARSER_PROTOTYPE(config_parse_hwaddr
);
151 CONFIG_PARSER_PROTOTYPE(config_parse_hwaddrs
);
152 CONFIG_PARSER_PROTOTYPE(config_parse_in_addr_non_null
);
153 CONFIG_PARSER_PROTOTYPE(config_parse_percent
);
154 CONFIG_PARSER_PROTOTYPE(config_parse_permyriad
);
156 typedef enum Disabled
{
157 DISABLED_CONFIGURATION
,
159 DISABLED_EXPERIMENTAL
,
162 #define DEFINE_CONFIG_PARSE(function, parser, msg) \
163 CONFIG_PARSER_PROTOTYPE(function) { \
171 r = parser(rvalue); \
173 log_syntax(unit, LOG_WARNING, filename, line, r, \
174 msg ", ignoring: %s", rvalue); \
182 #define DEFINE_CONFIG_PARSE_PTR(function, parser, type, msg) \
183 CONFIG_PARSER_PROTOTYPE(function) { \
192 r = parser(rvalue, i); \
194 log_syntax(unit, LOG_WARNING, filename, line, r, \
195 msg ", ignoring: %s", rvalue); \
200 #define DEFINE_CONFIG_PARSE_ENUM_FULL(function, from_string, type, msg) \
201 CONFIG_PARSER_PROTOTYPE(function) { \
209 x = from_string(rvalue); \
211 log_syntax(unit, LOG_WARNING, filename, line, x, \
212 msg ", ignoring: %s", rvalue); \
220 #define DEFINE_CONFIG_PARSE_ENUM(function, name, type, msg) \
221 DEFINE_CONFIG_PARSE_ENUM_FULL(function, name##_from_string, type, msg)
223 #define DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(function, name, type, default_value, msg) \
224 CONFIG_PARSER_PROTOTYPE(function) { \
232 if (isempty(rvalue)) { \
233 *i = default_value; \
237 x = name##_from_string(rvalue); \
239 log_syntax(unit, LOG_WARNING, filename, line, x, \
240 msg ", ignoring: %s", rvalue); \
248 #define DEFINE_CONFIG_PARSE_ENUMV(function, name, type, invalid, msg) \
249 CONFIG_PARSER_PROTOTYPE(function) { \
250 type **enums = data; \
251 _cleanup_free_ type *xs = NULL; \
260 xs = new0(type, 1); \
266 for (const char *p = rvalue;;) { \
267 _cleanup_free_ char *en = NULL; \
270 r = extract_first_word(&p, &en, NULL, 0); \
274 log_syntax(unit, LOG_WARNING, filename, line, r, \
275 msg ", ignoring: %s", en); \
281 x = name##_from_string(en); \
283 log_syntax(unit, LOG_WARNING, filename, line, x, \
284 msg ", ignoring: %s", en); \
288 for (type *ys = xs; x != invalid && *ys != invalid; ys++) \
290 log_syntax(unit, LOG_NOTICE, filename, line, 0, \
291 "Duplicate entry, ignoring: %s", \
300 new_xs = realloc(xs, (++i + 1) * sizeof(type)); \
306 *(xs + i) = invalid; \
309 return free_and_replace(*enums, xs); \