]> git.proxmox.com Git - systemd.git/blob - src/shared/conf-parser.h
New upstream version 249~rc1
[systemd.git] / src / shared / conf-parser.h
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 #pragma once
3
4 #include <errno.h>
5 #include <stdbool.h>
6 #include <stddef.h>
7 #include <stdio.h>
8 #include <syslog.h>
9
10 #include "alloc-util.h"
11 #include "log.h"
12 #include "macro.h"
13 #include "time-util.h"
14
15 /* An abstract parser for simple, line based, shallow configuration files consisting of variable assignments only. */
16
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 */
20 } ConfigParseFlags;
21
22 /* Argument list for parsers of specific configuration settings. */
23 #define CONFIG_PARSER_ARGUMENTS \
24 const char *unit, \
25 const char *filename, \
26 unsigned line, \
27 const char *section, \
28 unsigned section_line, \
29 const char *lvalue, \
30 int ltype, \
31 const char *rvalue, \
32 void *data, \
33 void *userdata
34
35 /* Prototype for a parser for a specific configuration setting */
36 typedef int (*ConfigParserCallback)(CONFIG_PARSER_ARGUMENTS);
37
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)
42
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 */
51 } ConfigTableItem;
52
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 */
60 } ConfigPerfItem;
61
62 /* Prototype for a low-level gperf lookup function */
63 typedef const ConfigPerfItem* (*ConfigPerfItemLookup)(const char *section_and_lvalue, unsigned length);
64
65 /* Prototype for a generic high-level lookup function */
66 typedef int (*ConfigItemLookup)(
67 const void *table,
68 const char *section,
69 const char *lvalue,
70 ConfigParserCallback *func,
71 int *ltype,
72 void **data,
73 void *userdata);
74
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);
78
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);
82
83 int config_parse(
84 const char *unit,
85 const char *filename,
86 FILE *f,
87 const char *sections, /* nulstr */
88 ConfigItemLookup lookup,
89 const void *table,
90 ConfigParseFlags flags,
91 void *userdata,
92 usec_t *latest_mtime); /* input/output, possibly NULL */
93
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,
99 const void *table,
100 ConfigParseFlags flags,
101 void *userdata,
102 usec_t *ret_mtime); /* possibly NULL */
103
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,
110 const void *table,
111 ConfigParseFlags flags,
112 void *userdata,
113 usec_t *ret_mtime); /* possibly NULL */
114
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);
155
156 typedef enum Disabled {
157 DISABLED_CONFIGURATION,
158 DISABLED_LEGACY,
159 DISABLED_EXPERIMENTAL,
160 } Disabled;
161
162 #define DEFINE_CONFIG_PARSE(function, parser, msg) \
163 CONFIG_PARSER_PROTOTYPE(function) { \
164 int *i = data, r; \
165 \
166 assert(filename); \
167 assert(lvalue); \
168 assert(rvalue); \
169 assert(data); \
170 \
171 r = parser(rvalue); \
172 if (r < 0) { \
173 log_syntax(unit, LOG_WARNING, filename, line, r, \
174 msg ", ignoring: %s", rvalue); \
175 return 0; \
176 } \
177 \
178 *i = r; \
179 return 0; \
180 }
181
182 #define DEFINE_CONFIG_PARSE_PTR(function, parser, type, msg) \
183 CONFIG_PARSER_PROTOTYPE(function) { \
184 type *i = data; \
185 int r; \
186 \
187 assert(filename); \
188 assert(lvalue); \
189 assert(rvalue); \
190 assert(data); \
191 \
192 r = parser(rvalue, i); \
193 if (r < 0) \
194 log_syntax(unit, LOG_WARNING, filename, line, r, \
195 msg ", ignoring: %s", rvalue); \
196 \
197 return 0; \
198 }
199
200 #define DEFINE_CONFIG_PARSE_ENUM_FULL(function, from_string, type, msg) \
201 CONFIG_PARSER_PROTOTYPE(function) { \
202 type *i = data, x; \
203 \
204 assert(filename); \
205 assert(lvalue); \
206 assert(rvalue); \
207 assert(data); \
208 \
209 x = from_string(rvalue); \
210 if (x < 0) { \
211 log_syntax(unit, LOG_WARNING, filename, line, x, \
212 msg ", ignoring: %s", rvalue); \
213 return 0; \
214 } \
215 \
216 *i = x; \
217 return 0; \
218 }
219
220 #define DEFINE_CONFIG_PARSE_ENUM(function, name, type, msg) \
221 DEFINE_CONFIG_PARSE_ENUM_FULL(function, name##_from_string, type, msg)
222
223 #define DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(function, name, type, default_value, msg) \
224 CONFIG_PARSER_PROTOTYPE(function) { \
225 type *i = data, x; \
226 \
227 assert(filename); \
228 assert(lvalue); \
229 assert(rvalue); \
230 assert(data); \
231 \
232 if (isempty(rvalue)) { \
233 *i = default_value; \
234 return 0; \
235 } \
236 \
237 x = name##_from_string(rvalue); \
238 if (x < 0) { \
239 log_syntax(unit, LOG_WARNING, filename, line, x, \
240 msg ", ignoring: %s", rvalue); \
241 return 0; \
242 } \
243 \
244 *i = x; \
245 return 0; \
246 }
247
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; \
252 size_t i = 0; \
253 int r; \
254 \
255 assert(filename); \
256 assert(lvalue); \
257 assert(rvalue); \
258 assert(data); \
259 \
260 xs = new0(type, 1); \
261 if (!xs) \
262 return -ENOMEM; \
263 \
264 *xs = invalid; \
265 \
266 for (const char *p = rvalue;;) { \
267 _cleanup_free_ char *en = NULL; \
268 type x, *new_xs; \
269 \
270 r = extract_first_word(&p, &en, NULL, 0); \
271 if (r == -ENOMEM) \
272 return log_oom(); \
273 if (r < 0) { \
274 log_syntax(unit, LOG_WARNING, filename, line, r, \
275 msg ", ignoring: %s", en); \
276 return 0; \
277 } \
278 if (r == 0) \
279 break; \
280 \
281 x = name##_from_string(en); \
282 if (x < 0) { \
283 log_syntax(unit, LOG_WARNING, filename, line, x, \
284 msg ", ignoring: %s", en); \
285 continue; \
286 } \
287 \
288 for (type *ys = xs; x != invalid && *ys != invalid; ys++) \
289 if (*ys == x) { \
290 log_syntax(unit, LOG_NOTICE, filename, line, 0, \
291 "Duplicate entry, ignoring: %s", \
292 en); \
293 x = invalid; \
294 } \
295 \
296 if (x == invalid) \
297 continue; \
298 \
299 *(xs + i) = x; \
300 new_xs = realloc(xs, (++i + 1) * sizeof(type)); \
301 if (new_xs) \
302 xs = new_xs; \
303 else \
304 return log_oom(); \
305 \
306 *(xs + i) = invalid; \
307 } \
308 \
309 return free_and_replace(*enums, xs); \
310 }