chiark / gitweb /
shared/conf-parser: define a macro for the repeating argument set
[elogind.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   systemd is free software; you can redistribute it and/or modify it
10   under the terms of the GNU Lesser General Public License as published by
11   the Free Software Foundation; either version 2.1 of the License, or
12   (at your option) any later version.
13
14   systemd is distributed in the hope that it will be useful, but
15   WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   Lesser General Public License for more details.
18
19   You should have received a copy of the GNU Lesser General Public License
20   along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 ***/
22
23 #include <errno.h>
24 #include <stdbool.h>
25 #include <stddef.h>
26 #include <stdio.h>
27 #include <syslog.h>
28
29 #include "alloc-util.h"
30 #include "log.h"
31 #include "macro.h"
32
33 /* An abstract parser for simple, line based, shallow configuration files consisting of variable assignments only. */
34
35 typedef enum ConfigParseFlags {
36         CONFIG_PARSE_RELAXED       = 1U << 0,
37         CONFIG_PARSE_ALLOW_INCLUDE = 1U << 1,
38         CONFIG_PARSE_WARN          = 1U << 2,
39         CONFIG_PARSE_REFUSE_BOM    = 1U << 3,
40 } ConfigParseFlags;
41
42 /* Prototype for a parser for a specific configuration setting */
43 typedef int (*ConfigParserCallback)(const char *unit,
44                                     const char *filename,
45                                     unsigned line,
46                                     const char *section,
47                                     unsigned section_line,
48                                     const char *lvalue,
49                                     int ltype,
50                                     const char *rvalue,
51                                     void *data,
52                                     void *userdata);
53
54 /* Wraps information for parsing a specific configuration variable, to
55  * be stored in a simple array */
56 typedef struct ConfigTableItem {
57         const char *section;            /* Section */
58         const char *lvalue;             /* Name of the variable */
59         ConfigParserCallback parse;     /* Function that is called to parse the variable's value */
60         int ltype;                      /* Distinguish different variables passed to the same callback */
61         void *data;                     /* Where to store the variable's data */
62 } ConfigTableItem;
63
64 /* Wraps information for parsing a specific configuration variable, to
65  * be stored in a gperf perfect hashtable */
66 typedef struct ConfigPerfItem {
67         const char *section_and_lvalue; /* Section + "." + name of the variable */
68         ConfigParserCallback parse;     /* Function that is called to parse the variable's value */
69         int ltype;                      /* Distinguish different variables passed to the same callback */
70         size_t offset;                  /* Offset where to store data, from the beginning of userdata */
71 } ConfigPerfItem;
72
73 /* Prototype for a low-level gperf lookup function */
74 typedef const ConfigPerfItem* (*ConfigPerfItemLookup)(const char *section_and_lvalue, unsigned length);
75
76 /* Prototype for a generic high-level lookup function */
77 typedef int (*ConfigItemLookup)(
78                 const void *table,
79                 const char *section,
80                 const char *lvalue,
81                 ConfigParserCallback *func,
82                 int *ltype,
83                 void **data,
84                 void *userdata);
85
86 /* Linear table search implementation of ConfigItemLookup, based on
87  * ConfigTableItem arrays */
88 int config_item_table_lookup(const void *table, const char *section, const char *lvalue, ConfigParserCallback *func, int *ltype, void **data, void *userdata);
89
90 /* gperf implementation of ConfigItemLookup, based on gperf
91  * ConfigPerfItem tables */
92 int config_item_perf_lookup(const void *table, const char *section, const char *lvalue, ConfigParserCallback *func, int *ltype, void **data, void *userdata);
93
94 int config_parse(
95                 const char *unit,
96                 const char *filename,
97                 FILE *f,
98                 const char *sections,  /* nulstr */
99                 ConfigItemLookup lookup,
100                 const void *table,
101                 ConfigParseFlags flags,
102                 void *userdata);
103
104 int config_parse_many_nulstr(
105                 const char *conf_file,      /* possibly NULL */
106                 const char *conf_file_dirs, /* nulstr */
107                 const char *sections,       /* nulstr */
108                 ConfigItemLookup lookup,
109                 const void *table,
110                 ConfigParseFlags flags,
111                 void *userdata);
112
113 #if 0 /// UNNEEDED by elogind
114 int config_parse_many(
115                 const char *conf_file,      /* possibly NULL */
116                 const char* const* conf_file_dirs,
117                 const char *dropin_dirname,
118                 const char *sections,       /* nulstr */
119                 ConfigItemLookup lookup,
120                 const void *table,
121                 ConfigParseFlags flags,
122                 void *userdata);
123 #endif // 0
124
125 /* Generic parsers */
126 #if 0 /// UNNEEDED by elogind
127 #endif // 0
128 #if 0 /// UNNEEDED by elogind
129 #endif // 0
130 #if 0 /// UNNEEDED by elogind
131 #endif // 0
132 #if 0 /// UNNEEDED by elogind
133 #endif // 0
134 #if 0 /// UNNEEDED by elogind
135 #endif // 0
136 #if 0 /// UNNEEDED by elogind
137 #endif // 0
138 #define GENERIC_PARSER_ARGS \
139                 const char *unit,                                       \
140                 const char *filename,                                   \
141                 unsigned line,                                          \
142                 const char *section,                                    \
143                 unsigned section_line,                                  \
144                 const char *lvalue,                                     \
145                 int ltype,                                              \
146                 const char *rvalue,                                     \
147                 void *data,                                             \
148                 void *userdata
149 int config_parse_int(GENERIC_PARSER_ARGS);
150 int config_parse_unsigned(GENERIC_PARSER_ARGS);
151 int config_parse_long(GENERIC_PARSER_ARGS);
152 int config_parse_uint8(GENERIC_PARSER_ARGS);
153 int config_parse_uint16(GENERIC_PARSER_ARGS);
154 int config_parse_uint32(GENERIC_PARSER_ARGS);
155 int config_parse_uint64(GENERIC_PARSER_ARGS);
156 int config_parse_double(GENERIC_PARSER_ARGS);
157 int config_parse_iec_size(GENERIC_PARSER_ARGS);
158 int config_parse_si_size(GENERIC_PARSER_ARGS);
159 int config_parse_iec_uint64(GENERIC_PARSER_ARGS);
160 int config_parse_bool(GENERIC_PARSER_ARGS);
161 int config_parse_tristate(GENERIC_PARSER_ARGS);
162 int config_parse_string(GENERIC_PARSER_ARGS);
163 int config_parse_path(GENERIC_PARSER_ARGS);
164 int config_parse_strv(GENERIC_PARSER_ARGS);
165 int config_parse_sec(GENERIC_PARSER_ARGS);
166 int config_parse_nsec(GENERIC_PARSER_ARGS);
167 int config_parse_mode(GENERIC_PARSER_ARGS);
168 int config_parse_log_facility(GENERIC_PARSER_ARGS);
169 int config_parse_log_level(GENERIC_PARSER_ARGS);
170 int config_parse_signal(GENERIC_PARSER_ARGS);
171 int config_parse_personality(GENERIC_PARSER_ARGS);
172 int config_parse_ifname(GENERIC_PARSER_ARGS);
173 int config_parse_ip_port(GENERIC_PARSER_ARGS);
174
175 #define DEFINE_CONFIG_PARSE_ENUM(function,name,type,msg)                \
176         int function(GENERIC_PARSER_ARGS) {                             \
177                 type *i = data, x;                                      \
178                                                                         \
179                 assert(filename);                                       \
180                 assert(lvalue);                                         \
181                 assert(rvalue);                                         \
182                 assert(data);                                           \
183                                                                         \
184                 if ((x = name##_from_string(rvalue)) < 0) {             \
185                         log_syntax(unit, LOG_ERR, filename, line, -x,   \
186                                    msg ", ignoring: %s", rvalue);       \
187                         return 0;                                       \
188                 }                                                       \
189                                                                         \
190                 *i = x;                                                 \
191                 return 0;                                               \
192         }
193
194 #define DEFINE_CONFIG_PARSE_ENUMV(function,name,type,invalid,msg)              \
195         int function(GENERIC_PARSER_ARGS) {                                    \
196                 type **enums = data, x, *ys;                                   \
197                 _cleanup_free_ type *xs = NULL;                                \
198                 const char *word, *state;                                      \
199                 size_t l, i = 0;                                               \
200                                                                                \
201                 assert(filename);                                              \
202                 assert(lvalue);                                                \
203                 assert(rvalue);                                                \
204                 assert(data);                                                  \
205                                                                                \
206                 xs = new0(type, 1);                                            \
207                 if (!xs)                                                       \
208                         return -ENOMEM;                                        \
209                                                                                \
210                 *xs = invalid;                                                 \
211                                                                                \
212                 FOREACH_WORD(word, l, rvalue, state) {                         \
213                         _cleanup_free_ char *en = NULL;                        \
214                         type *new_xs;                                          \
215                                                                                \
216                         en = strndup(word, l);                                 \
217                         if (!en)                                               \
218                                 return -ENOMEM;                                \
219                                                                                \
220                         if ((x = name##_from_string(en)) < 0) {                \
221                                 log_syntax(unit, LOG_ERR, filename, line,      \
222                                        -x, msg ", ignoring: %s", en);          \
223                                 continue;                                      \
224                         }                                                      \
225                                                                                \
226                         for (ys = xs; x != invalid && *ys != invalid; ys++) {  \
227                                 if (*ys == x) {                                \
228                                         log_syntax(unit, LOG_ERR, filename,    \
229                                               line, -x,                        \
230                                               "Duplicate entry, ignoring: %s", \
231                                               en);                             \
232                                         x = invalid;                           \
233                                 }                                              \
234                         }                                                      \
235                                                                                \
236                         if (x == invalid)                                      \
237                                 continue;                                      \
238                                                                                \
239                         *(xs + i) = x;                                         \
240                         new_xs = realloc(xs, (++i + 1) * sizeof(type));        \
241                         if (new_xs)                                            \
242                                 xs = new_xs;                                   \
243                         else                                                   \
244                                 return -ENOMEM;                                \
245                                                                                \
246                         *(xs + i) = invalid;                                   \
247                 }                                                              \
248                                                                                \
249                 free(*enums);                                                  \
250                 *enums = xs;                                                   \
251                 xs = NULL;                                                     \
252                                                                                \
253                 return 0;                                                      \
254         }