chiark / gitweb /
Move config_parse_join_controllers to shared, add test
[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 int config_parse_join_controllers(GENERIC_PARSER_ARGS);
175
176 #define DEFINE_CONFIG_PARSE_ENUM(function,name,type,msg)                \
177         int function(GENERIC_PARSER_ARGS) {                             \
178                 type *i = data, x;                                      \
179                                                                         \
180                 assert(filename);                                       \
181                 assert(lvalue);                                         \
182                 assert(rvalue);                                         \
183                 assert(data);                                           \
184                                                                         \
185                 if ((x = name##_from_string(rvalue)) < 0) {             \
186                         log_syntax(unit, LOG_ERR, filename, line, -x,   \
187                                    msg ", ignoring: %s", rvalue);       \
188                         return 0;                                       \
189                 }                                                       \
190                                                                         \
191                 *i = x;                                                 \
192                 return 0;                                               \
193         }
194
195 #define DEFINE_CONFIG_PARSE_ENUMV(function,name,type,invalid,msg)              \
196         int function(GENERIC_PARSER_ARGS) {                                    \
197                 type **enums = data, x, *ys;                                   \
198                 _cleanup_free_ type *xs = NULL;                                \
199                 const char *word, *state;                                      \
200                 size_t l, i = 0;                                               \
201                                                                                \
202                 assert(filename);                                              \
203                 assert(lvalue);                                                \
204                 assert(rvalue);                                                \
205                 assert(data);                                                  \
206                                                                                \
207                 xs = new0(type, 1);                                            \
208                 if (!xs)                                                       \
209                         return -ENOMEM;                                        \
210                                                                                \
211                 *xs = invalid;                                                 \
212                                                                                \
213                 FOREACH_WORD(word, l, rvalue, state) {                         \
214                         _cleanup_free_ char *en = NULL;                        \
215                         type *new_xs;                                          \
216                                                                                \
217                         en = strndup(word, l);                                 \
218                         if (!en)                                               \
219                                 return -ENOMEM;                                \
220                                                                                \
221                         if ((x = name##_from_string(en)) < 0) {                \
222                                 log_syntax(unit, LOG_ERR, filename, line,      \
223                                        -x, msg ", ignoring: %s", en);          \
224                                 continue;                                      \
225                         }                                                      \
226                                                                                \
227                         for (ys = xs; x != invalid && *ys != invalid; ys++) {  \
228                                 if (*ys == x) {                                \
229                                         log_syntax(unit, LOG_ERR, filename,    \
230                                               line, -x,                        \
231                                               "Duplicate entry, ignoring: %s", \
232                                               en);                             \
233                                         x = invalid;                           \
234                                 }                                              \
235                         }                                                      \
236                                                                                \
237                         if (x == invalid)                                      \
238                                 continue;                                      \
239                                                                                \
240                         *(xs + i) = x;                                         \
241                         new_xs = realloc(xs, (++i + 1) * sizeof(type));        \
242                         if (new_xs)                                            \
243                                 xs = new_xs;                                   \
244                         else                                                   \
245                                 return -ENOMEM;                                \
246                                                                                \
247                         *(xs + i) = invalid;                                   \
248                 }                                                              \
249                                                                                \
250                 free(*enums);                                                  \
251                 *enums = xs;                                                   \
252                 xs = NULL;                                                     \
253                                                                                \
254                 return 0;                                                      \
255         }