]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/conf-parser.h
Merge pull request #16145 from poettering/qrcode-dlopen
[thirdparty/systemd.git] / src / shared / conf-parser.h
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
c2f1db8f 2#pragma once
ed5bcfbe 3
a8fbdf54 4#include <errno.h>
10e87ee7 5#include <stdbool.h>
a8fbdf54 6#include <stddef.h>
71d35b6b 7#include <stdio.h>
a8fbdf54 8#include <syslog.h>
ed5bcfbe 9
a8fbdf54
TA
10#include "alloc-util.h"
11#include "log.h"
e8e581bf 12#include "macro.h"
4f9ff96a 13#include "time-util.h"
e8e581bf 14
bcde742e
LP
15/* An abstract parser for simple, line based, shallow configuration files consisting of variable assignments only. */
16
17typedef enum ConfigParseFlags {
94a404cb 18 CONFIG_PARSE_RELAXED = 1 << 0, /* Do not warn about unknown non-extension fields */
7ade8982 19 CONFIG_PARSE_WARN = 1 << 1, /* Emit non-debug messages */
bcde742e 20} ConfigParseFlags;
ed5bcfbe 21
1f12b48a
LP
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
f975e971 35/* Prototype for a parser for a specific configuration setting */
1f12b48a
LP
36typedef int (*ConfigParserCallback)(CONFIG_PARSER_ARGUMENTS);
37
38/* A macro declaring the 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)
f975e971
LP
42
43/* Wraps information for parsing a specific configuration variable, to
44 * be stored in a simple array */
45typedef 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
e5a7f173 54 * be stored in a gperf perfect hashtable */
f975e971
LP
55typedef 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 */
63typedef const ConfigPerfItem* (*ConfigPerfItemLookup)(const char *section_and_lvalue, unsigned length);
64
65/* Prototype for a generic high-level lookup function */
66typedef int (*ConfigItemLookup)(
e9f3d2d5 67 const void *table,
f975e971
LP
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 */
e9f3d2d5 77int config_item_table_lookup(const void *table, const char *section, const char *lvalue, ConfigParserCallback *func, int *ltype, void **data, void *userdata);
f975e971
LP
78
79/* gperf implementation of ConfigItemLookup, based on gperf
80 * ConfigPerfItem tables */
e9f3d2d5 81int config_item_perf_lookup(const void *table, const char *section, const char *lvalue, ConfigParserCallback *func, int *ltype, void **data, void *userdata);
f975e971 82
43688c49
ZJS
83int config_parse(
84 const char *unit,
85 const char *filename,
86 FILE *f,
4f9ff96a 87 const char *sections, /* nulstr */
43688c49
ZJS
88 ConfigItemLookup lookup,
89 const void *table,
bcde742e 90 ConfigParseFlags flags,
4f9ff96a
LP
91 void *userdata,
92 usec_t *ret_mtime); /* possibly NULL */
43688c49
ZJS
93
94int 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,
bcde742e 100 ConfigParseFlags flags,
4f9ff96a
LP
101 void *userdata,
102 usec_t *ret_mtime); /* possibly NULL */
e8461023 103
23bb31aa
ZJS
104int config_parse_many(
105 const char *conf_file, /* possibly NULL */
106 const char* const* conf_file_dirs,
107 const char *dropin_dirname,
108 const char *sections, /* nulstr */
109 ConfigItemLookup lookup,
110 const void *table,
bcde742e 111 ConfigParseFlags flags,
9f83091e 112 void *userdata,
4f9ff96a 113 usec_t *ret_mtime); /* possibly NULL */
23bb31aa 114
1f12b48a
LP
115CONFIG_PARSER_PROTOTYPE(config_parse_int);
116CONFIG_PARSER_PROTOTYPE(config_parse_unsigned);
117CONFIG_PARSER_PROTOTYPE(config_parse_long);
118CONFIG_PARSER_PROTOTYPE(config_parse_uint8);
119CONFIG_PARSER_PROTOTYPE(config_parse_uint16);
120CONFIG_PARSER_PROTOTYPE(config_parse_uint32);
b57ebc60 121CONFIG_PARSER_PROTOTYPE(config_parse_int32);
1f12b48a
LP
122CONFIG_PARSER_PROTOTYPE(config_parse_uint64);
123CONFIG_PARSER_PROTOTYPE(config_parse_double);
124CONFIG_PARSER_PROTOTYPE(config_parse_iec_size);
50299121 125CONFIG_PARSER_PROTOTYPE(config_parse_si_uint64);
1f12b48a
LP
126CONFIG_PARSER_PROTOTYPE(config_parse_iec_uint64);
127CONFIG_PARSER_PROTOTYPE(config_parse_bool);
12963533 128CONFIG_PARSER_PROTOTYPE(config_parse_id128);
1f12b48a
LP
129CONFIG_PARSER_PROTOTYPE(config_parse_tristate);
130CONFIG_PARSER_PROTOTYPE(config_parse_string);
131CONFIG_PARSER_PROTOTYPE(config_parse_path);
132CONFIG_PARSER_PROTOTYPE(config_parse_strv);
133CONFIG_PARSER_PROTOTYPE(config_parse_sec);
7b61ce3c 134CONFIG_PARSER_PROTOTYPE(config_parse_sec_def_infinity);
dc653bf4 135CONFIG_PARSER_PROTOTYPE(config_parse_sec_def_unset);
1f12b48a
LP
136CONFIG_PARSER_PROTOTYPE(config_parse_nsec);
137CONFIG_PARSER_PROTOTYPE(config_parse_mode);
138CONFIG_PARSER_PROTOTYPE(config_parse_warn_compat);
139CONFIG_PARSER_PROTOTYPE(config_parse_log_facility);
140CONFIG_PARSER_PROTOTYPE(config_parse_log_level);
141CONFIG_PARSER_PROTOTYPE(config_parse_signal);
142CONFIG_PARSER_PROTOTYPE(config_parse_personality);
c07b23ca 143CONFIG_PARSER_PROTOTYPE(config_parse_permille);
1f12b48a 144CONFIG_PARSER_PROTOTYPE(config_parse_ifname);
a5053a15 145CONFIG_PARSER_PROTOTYPE(config_parse_ifnames);
1f12b48a 146CONFIG_PARSER_PROTOTYPE(config_parse_ip_port);
1f12b48a
LP
147CONFIG_PARSER_PROTOTYPE(config_parse_mtu);
148CONFIG_PARSER_PROTOTYPE(config_parse_rlimit);
4df4df5b 149CONFIG_PARSER_PROTOTYPE(config_parse_vlanprotocol);
e8e581bf 150
1e35c5ab
RP
151typedef enum Disabled {
152 DISABLED_CONFIGURATION,
153 DISABLED_LEGACY,
154 DISABLED_EXPERIMENTAL,
155} Disabled;
156
2d1729ca
YW
157#define DEFINE_CONFIG_PARSE(function, parser, msg) \
158 CONFIG_PARSER_PROTOTYPE(function) { \
159 int *i = data, r; \
160 \
161 assert(filename); \
162 assert(lvalue); \
163 assert(rvalue); \
164 assert(data); \
165 \
166 r = parser(rvalue); \
167 if (r < 0) { \
d96edb2c 168 log_syntax(unit, LOG_WARNING, filename, line, r, \
2d1729ca
YW
169 msg ", ignoring: %s", rvalue); \
170 return 0; \
171 } \
172 \
173 *i = r; \
174 return 0; \
175 }
176
177#define DEFINE_CONFIG_PARSE_PTR(function, parser, type, msg) \
178 CONFIG_PARSER_PROTOTYPE(function) { \
179 type *i = data; \
180 int r; \
181 \
182 assert(filename); \
183 assert(lvalue); \
184 assert(rvalue); \
185 assert(data); \
186 \
187 r = parser(rvalue, i); \
188 if (r < 0) \
d96edb2c 189 log_syntax(unit, LOG_WARNING, filename, line, r, \
2d1729ca
YW
190 msg ", ignoring: %s", rvalue); \
191 \
192 return 0; \
193 }
194
195#define DEFINE_CONFIG_PARSE_ENUM(function, name, type, msg) \
196 CONFIG_PARSER_PROTOTYPE(function) { \
197 type *i = data, x; \
198 \
199 assert(filename); \
200 assert(lvalue); \
201 assert(rvalue); \
202 assert(data); \
203 \
204 x = name##_from_string(rvalue); \
205 if (x < 0) { \
d96edb2c 206 log_syntax(unit, LOG_WARNING, filename, line, 0, \
2d1729ca
YW
207 msg ", ignoring: %s", rvalue); \
208 return 0; \
209 } \
210 \
211 *i = x; \
212 return 0; \
213 }
214
215#define DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(function, name, type, default_value, msg) \
1f12b48a 216 CONFIG_PARSER_PROTOTYPE(function) { \
487393e9
LP
217 type *i = data, x; \
218 \
219 assert(filename); \
220 assert(lvalue); \
221 assert(rvalue); \
222 assert(data); \
223 \
2d1729ca
YW
224 if (isempty(rvalue)) { \
225 *i = default_value; \
226 return 0; \
227 } \
228 \
229 x = name##_from_string(rvalue); \
230 if (x < 0) { \
d96edb2c 231 log_syntax(unit, LOG_WARNING, filename, line, 0, \
e8e581bf 232 msg ", ignoring: %s", rvalue); \
c0b34696 233 return 0; \
487393e9
LP
234 } \
235 \
236 *i = x; \
487393e9
LP
237 return 0; \
238 }
916484f5 239
2d1729ca 240#define DEFINE_CONFIG_PARSE_ENUMV(function, name, type, invalid, msg) \
1f12b48a 241 CONFIG_PARSER_PROTOTYPE(function) { \
77c10205
TG
242 type **enums = data, x, *ys; \
243 _cleanup_free_ type *xs = NULL; \
a2a5291b 244 const char *word, *state; \
916484f5
TG
245 size_t l, i = 0; \
246 \
247 assert(filename); \
248 assert(lvalue); \
249 assert(rvalue); \
250 assert(data); \
251 \
252 xs = new0(type, 1); \
9ed794a3 253 if (!xs) \
83e341a6
TG
254 return -ENOMEM; \
255 \
916484f5
TG
256 *xs = invalid; \
257 \
a2a5291b 258 FOREACH_WORD(word, l, rvalue, state) { \
916484f5 259 _cleanup_free_ char *en = NULL; \
77c10205 260 type *new_xs; \
916484f5 261 \
a2a5291b 262 en = strndup(word, l); \
916484f5 263 if (!en) \
d96edb2c 264 return log_oom(); \
916484f5
TG
265 \
266 if ((x = name##_from_string(en)) < 0) { \
d96edb2c 267 log_syntax(unit, LOG_WARNING, filename, line, 0, \
2d1729ca 268 msg ", ignoring: %s", en); \
916484f5
TG
269 continue; \
270 } \
271 \
272 for (ys = xs; x != invalid && *ys != invalid; ys++) { \
273 if (*ys == x) { \
2d1729ca
YW
274 log_syntax(unit, LOG_NOTICE, filename, \
275 line, 0, \
276 "Duplicate entry, ignoring: %s", \
277 en); \
916484f5
TG
278 x = invalid; \
279 } \
280 } \
281 \
282 if (x == invalid) \
283 continue; \
284 \
285 *(xs + i) = x; \
77c10205
TG
286 new_xs = realloc(xs, (++i + 1) * sizeof(type)); \
287 if (new_xs) \
288 xs = new_xs; \
289 else \
d96edb2c 290 return log_oom(); \
83e341a6 291 \
916484f5
TG
292 *(xs + i) = invalid; \
293 } \
294 \
5f92e517 295 free_and_replace(*enums, xs); \
916484f5
TG
296 return 0; \
297 }