]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/conf-parser.h
config-parser: introduce new CONFIG_PARSER_PROTOTYPE() macro
[thirdparty/systemd.git] / src / shared / conf-parser.h
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 #pragma once
3
4 /***
5 This file is part of systemd.
6
7 Copyright 2010 Lennart Poettering
8 ***/
9
10 #include <errno.h>
11 #include <stdbool.h>
12 #include <stddef.h>
13 #include <stdio.h>
14 #include <syslog.h>
15
16 #include "alloc-util.h"
17 #include "log.h"
18 #include "macro.h"
19
20 /* An abstract parser for simple, line based, shallow configuration files consisting of variable assignments only. */
21
22 typedef enum ConfigParseFlags {
23 CONFIG_PARSE_RELAXED = 1U << 0,
24 CONFIG_PARSE_ALLOW_INCLUDE = 1U << 1,
25 CONFIG_PARSE_WARN = 1U << 2,
26 CONFIG_PARSE_REFUSE_BOM = 1U << 3,
27 } ConfigParseFlags;
28
29 /* Argument list for parsers of specific configuration settings. */
30 #define CONFIG_PARSER_ARGUMENTS \
31 const char *unit, \
32 const char *filename, \
33 unsigned line, \
34 const char *section, \
35 unsigned section_line, \
36 const char *lvalue, \
37 int ltype, \
38 const char *rvalue, \
39 void *data, \
40 void *userdata
41
42 /* Prototype for a parser for a specific configuration setting */
43 typedef int (*ConfigParserCallback)(CONFIG_PARSER_ARGUMENTS);
44
45 /* A macro declaring the a function prototype, following the typedef above, simply because it's so cumbersomely long
46 * otherwise. (And current emacs gets irritatingly slow when editing files that contain lots of very long function
47 * prototypes on the same screen…) */
48 #define CONFIG_PARSER_PROTOTYPE(name) int name(CONFIG_PARSER_ARGUMENTS)
49
50 /* Wraps information for parsing a specific configuration variable, to
51 * be stored in a simple array */
52 typedef struct ConfigTableItem {
53 const char *section; /* Section */
54 const char *lvalue; /* Name of the variable */
55 ConfigParserCallback parse; /* Function that is called to parse the variable's value */
56 int ltype; /* Distinguish different variables passed to the same callback */
57 void *data; /* Where to store the variable's data */
58 } ConfigTableItem;
59
60 /* Wraps information for parsing a specific configuration variable, to
61 * be stored in a gperf perfect hashtable */
62 typedef struct ConfigPerfItem {
63 const char *section_and_lvalue; /* Section + "." + name of the variable */
64 ConfigParserCallback parse; /* Function that is called to parse the variable's value */
65 int ltype; /* Distinguish different variables passed to the same callback */
66 size_t offset; /* Offset where to store data, from the beginning of userdata */
67 } ConfigPerfItem;
68
69 /* Prototype for a low-level gperf lookup function */
70 typedef const ConfigPerfItem* (*ConfigPerfItemLookup)(const char *section_and_lvalue, unsigned length);
71
72 /* Prototype for a generic high-level lookup function */
73 typedef int (*ConfigItemLookup)(
74 const void *table,
75 const char *section,
76 const char *lvalue,
77 ConfigParserCallback *func,
78 int *ltype,
79 void **data,
80 void *userdata);
81
82 /* Linear table search implementation of ConfigItemLookup, based on
83 * ConfigTableItem arrays */
84 int config_item_table_lookup(const void *table, const char *section, const char *lvalue, ConfigParserCallback *func, int *ltype, void **data, void *userdata);
85
86 /* gperf implementation of ConfigItemLookup, based on gperf
87 * ConfigPerfItem tables */
88 int config_item_perf_lookup(const void *table, const char *section, const char *lvalue, ConfigParserCallback *func, int *ltype, void **data, void *userdata);
89
90 int config_parse(
91 const char *unit,
92 const char *filename,
93 FILE *f,
94 const char *sections, /* nulstr */
95 ConfigItemLookup lookup,
96 const void *table,
97 ConfigParseFlags flags,
98 void *userdata);
99
100 int config_parse_many_nulstr(
101 const char *conf_file, /* possibly NULL */
102 const char *conf_file_dirs, /* nulstr */
103 const char *sections, /* nulstr */
104 ConfigItemLookup lookup,
105 const void *table,
106 ConfigParseFlags flags,
107 void *userdata);
108
109 int config_parse_many(
110 const char *conf_file, /* possibly NULL */
111 const char* const* conf_file_dirs,
112 const char *dropin_dirname,
113 const char *sections, /* nulstr */
114 ConfigItemLookup lookup,
115 const void *table,
116 ConfigParseFlags flags,
117 void *userdata);
118
119 CONFIG_PARSER_PROTOTYPE(config_parse_int);
120 CONFIG_PARSER_PROTOTYPE(config_parse_unsigned);
121 CONFIG_PARSER_PROTOTYPE(config_parse_long);
122 CONFIG_PARSER_PROTOTYPE(config_parse_uint8);
123 CONFIG_PARSER_PROTOTYPE(config_parse_uint16);
124 CONFIG_PARSER_PROTOTYPE(config_parse_uint32);
125 CONFIG_PARSER_PROTOTYPE(config_parse_uint64);
126 CONFIG_PARSER_PROTOTYPE(config_parse_double);
127 CONFIG_PARSER_PROTOTYPE(config_parse_iec_size);
128 CONFIG_PARSER_PROTOTYPE(config_parse_si_size);
129 CONFIG_PARSER_PROTOTYPE(config_parse_iec_uint64);
130 CONFIG_PARSER_PROTOTYPE(config_parse_bool);
131 CONFIG_PARSER_PROTOTYPE(config_parse_tristate);
132 CONFIG_PARSER_PROTOTYPE(config_parse_string);
133 CONFIG_PARSER_PROTOTYPE(config_parse_path);
134 CONFIG_PARSER_PROTOTYPE(config_parse_strv);
135 CONFIG_PARSER_PROTOTYPE(config_parse_sec);
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_ifname);
144 CONFIG_PARSER_PROTOTYPE(config_parse_ip_port);
145 CONFIG_PARSER_PROTOTYPE(config_parse_join_controllers);
146 CONFIG_PARSER_PROTOTYPE(config_parse_mtu);
147 CONFIG_PARSER_PROTOTYPE(config_parse_rlimit);
148
149 typedef enum Disabled {
150 DISABLED_CONFIGURATION,
151 DISABLED_LEGACY,
152 DISABLED_EXPERIMENTAL,
153 } Disabled;
154
155 #define DEFINE_CONFIG_PARSE_ENUM(function,name,type,msg) \
156 CONFIG_PARSER_PROTOTYPE(function) { \
157 type *i = data, x; \
158 \
159 assert(filename); \
160 assert(lvalue); \
161 assert(rvalue); \
162 assert(data); \
163 \
164 if ((x = name##_from_string(rvalue)) < 0) { \
165 log_syntax(unit, LOG_ERR, filename, line, -x, \
166 msg ", ignoring: %s", rvalue); \
167 return 0; \
168 } \
169 \
170 *i = x; \
171 return 0; \
172 }
173
174 #define DEFINE_CONFIG_PARSE_ENUMV(function,name,type,invalid,msg) \
175 CONFIG_PARSER_PROTOTYPE(function) { \
176 type **enums = data, x, *ys; \
177 _cleanup_free_ type *xs = NULL; \
178 const char *word, *state; \
179 size_t l, i = 0; \
180 \
181 assert(filename); \
182 assert(lvalue); \
183 assert(rvalue); \
184 assert(data); \
185 \
186 xs = new0(type, 1); \
187 if (!xs) \
188 return -ENOMEM; \
189 \
190 *xs = invalid; \
191 \
192 FOREACH_WORD(word, l, rvalue, state) { \
193 _cleanup_free_ char *en = NULL; \
194 type *new_xs; \
195 \
196 en = strndup(word, l); \
197 if (!en) \
198 return -ENOMEM; \
199 \
200 if ((x = name##_from_string(en)) < 0) { \
201 log_syntax(unit, LOG_ERR, filename, line, \
202 -x, msg ", ignoring: %s", en); \
203 continue; \
204 } \
205 \
206 for (ys = xs; x != invalid && *ys != invalid; ys++) { \
207 if (*ys == x) { \
208 log_syntax(unit, LOG_ERR, filename, \
209 line, -x, \
210 "Duplicate entry, ignoring: %s", \
211 en); \
212 x = invalid; \
213 } \
214 } \
215 \
216 if (x == invalid) \
217 continue; \
218 \
219 *(xs + i) = x; \
220 new_xs = realloc(xs, (++i + 1) * sizeof(type)); \
221 if (new_xs) \
222 xs = new_xs; \
223 else \
224 return -ENOMEM; \
225 \
226 *(xs + i) = invalid; \
227 } \
228 \
229 free(*enums); \
230 *enums = xs; \
231 xs = NULL; \
232 \
233 return 0; \
234 }