]> git.ipfire.org Git - people/ms/network.git/blob - src/networkd/config.c
networkd: config: Actually return entry instead of freeing it straight away
[people/ms/network.git] / src / networkd / config.c
1 /*#############################################################################
2 # #
3 # IPFire.org - A linux based firewall #
4 # Copyright (C) 2023 IPFire Network Development Team #
5 # #
6 # This program is free software: you can redistribute it and/or modify #
7 # it under the terms of the GNU General Public License as published by #
8 # the Free Software Foundation, either version 3 of the License, or #
9 # (at your option) any later version. #
10 # #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
15 # #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
18 # #
19 #############################################################################*/
20
21 #include <errno.h>
22 #include <limits.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/queue.h>
27
28 #include "config.h"
29 #include "logging.h"
30 #include "string.h"
31
32 struct nw_config_entry {
33 STAILQ_ENTRY(nw_config_entry) nodes;
34
35 char key[NETWORK_CONFIG_KEY_MAX_LENGTH];
36 char value[NETWORK_CONFIG_KEY_MAX_LENGTH];
37 };
38
39 struct nw_config {
40 int nrefs;
41
42 // The path to the configuration file
43 char path[PATH_MAX];
44
45 STAILQ_HEAD(entries, nw_config_entry) entries;
46 };
47
48 static void nw_config_entry_free(struct nw_config_entry* entry) {
49 free(entry);
50 }
51
52 static struct nw_config_entry* nw_config_entry_create(
53 struct nw_config* config, const char* key) {
54 int r;
55
56 // Check input value
57 if (!key) {
58 errno = EINVAL;
59 return NULL;
60 }
61
62 // Allocate a new object
63 struct nw_config_entry* entry = calloc(1, sizeof(*entry));
64 if (!entry)
65 return NULL;
66
67 // Store the key
68 r = nw_string_set(entry->key, key);
69 if (r)
70 goto ERROR;
71
72 // Append the new entry
73 STAILQ_INSERT_TAIL(&config->entries, entry, nodes);
74
75 return entry;
76
77 ERROR:
78 nw_config_entry_free(entry);
79 return NULL;
80 }
81
82 static void nw_config_free(struct nw_config* config) {
83 // Flush all entries
84 nw_config_flush(config);
85
86 free(config);
87 }
88
89 int nw_config_create(struct nw_config** config, const char* path) {
90 int r;
91
92 struct nw_config* c = calloc(1, sizeof(*c));
93 if (!c)
94 return 1;
95
96 // Initialize reference counter
97 c->nrefs = 1;
98
99 // Initialise entries
100 STAILQ_INIT(&c->entries);
101
102 // Store the path
103 if (path) {
104 r = nw_string_set(c->path, path);
105 if (r)
106 goto ERROR;
107
108 // Try to read the configuration from path
109 r = nw_config_read(c);
110 if (r)
111 goto ERROR;
112 }
113
114 *config = c;
115
116 return 0;
117
118 ERROR:
119 nw_config_free(c);
120
121 return r;
122 }
123
124 struct nw_config* nw_config_ref(struct nw_config* config) {
125 config->nrefs++;
126
127 return config;
128 }
129
130 struct nw_config* nw_config_unref(struct nw_config* config) {
131 if (--config->nrefs > 0)
132 return config;
133
134 nw_config_free(config);
135 return NULL;
136 }
137
138 const char* nw_config_path(struct nw_config* config) {
139 if (*config->path)
140 return config->path;
141
142 return NULL;
143 }
144
145 int nw_config_flush(struct nw_config* config) {
146 struct nw_config_entry* entry = NULL;
147
148 while (!STAILQ_EMPTY(&config->entries)) {
149 entry = STAILQ_FIRST(&config->entries);
150 STAILQ_REMOVE_HEAD(&config->entries, nodes);
151
152 // Free the entry
153 nw_config_entry_free(entry);
154 }
155
156 return 0;
157 }
158
159 static int nw_config_readf(struct nw_config* config, FILE* f) {
160 // XXX TODO
161
162 return 0;
163 }
164
165 int nw_config_read(struct nw_config* config) {
166 FILE* f = NULL;
167 int r;
168
169 // We cannot read if path is not set
170 if (!*config->path) {
171 errno = ENOTSUP;
172 return 1;
173 }
174
175 // Open the file
176 f = fopen(config->path, "r");
177 if (!f) {
178 // Silently ignore if the file does not exist
179 if (errno == ENOENT)
180 return 0;
181
182 ERROR("Could not read configuration file %s: %m\n", config->path);
183 r = 1;
184 goto ERROR;
185 }
186
187 // Read from file
188 r = nw_config_readf(config, f);
189
190 ERROR:
191 if (f)
192 fclose(f);
193
194 return r;
195 }
196
197 static int nw_config_writef(struct nw_config* config, FILE* f) {
198 struct nw_config_entry* entry = NULL;
199 int r;
200
201 STAILQ_FOREACH(entry, &config->entries, nodes) {
202 // Skip if value is NULL
203 if (!*entry->value)
204 continue;
205
206 // Write the entry
207 r = fprintf(f, "%s=\"%s\"\n", entry->key, entry->value);
208 if (r < 0) {
209 ERROR("Failed to write configuration: %m\n");
210 return r;
211 }
212 }
213
214 return 0;
215 }
216
217 int nw_config_write(struct nw_config* config) {
218 int r;
219
220 // We cannot write if path is not set
221 if (!*config->path) {
222 errno = ENOTSUP;
223 return 1;
224 }
225
226 FILE* f = fopen(config->path, "w");
227 if (!f) {
228 ERROR("Failed to open %s for writing: %m\n", config->path);
229 r = 1;
230 goto ERROR;
231 }
232
233 // Write configuration
234 r = nw_config_writef(config, f);
235
236 ERROR:
237 if (f)
238 fclose(f);
239
240 return r;
241 }
242
243 static struct nw_config_entry* nw_config_find(struct nw_config* config, const char* key) {
244 struct nw_config_entry* entry = NULL;
245
246 STAILQ_FOREACH(entry, &config->entries, nodes) {
247 // Key must match
248 if (strcmp(entry->key, key) != 0)
249 continue;
250
251 // Match!
252 return entry;
253 }
254
255 // No match
256 return NULL;
257 }
258
259 int nw_config_del(struct nw_config* config, const char* key) {
260 struct nw_config_entry* entry = NULL;
261
262 // Find an entry matching the key
263 entry = nw_config_find(config, key);
264
265 // If there is no entry, there is nothing to do
266 if (!entry)
267 return 0;
268
269 // Otherwise remove the object
270 STAILQ_REMOVE(&config->entries, entry, nw_config_entry, nodes);
271
272 // Free the entry
273 nw_config_entry_free(entry);
274
275 return 0;
276 }
277
278 const char* nw_config_get(struct nw_config* config, const char* key) {
279 struct nw_config_entry* entry = nw_config_find(config, key);
280
281 // Return the value if found and set
282 if (entry && *entry->value)
283 return entry->value;
284
285 // Otherwise return NULL
286 return NULL;
287 }
288
289 int nw_config_set(struct nw_config* config, const char* key, const char* value) {
290 struct nw_config_entry* entry = NULL;
291
292 // Delete the entry if val is NULL
293 if (!value)
294 return nw_config_del(config, key);
295
296 // Find any existing entries
297 entry = nw_config_find(config, key);
298
299 // Create a new entry if it doesn't exist, yet
300 if (!entry) {
301 entry = nw_config_entry_create(config, key);
302 if (!entry)
303 return 1;
304 }
305
306 // Store the new value
307 return nw_string_set(entry->value, value);
308 }
309
310 int nw_config_get_int(struct nw_config* config, const char* key, const int __default) {
311 const char* value = nw_config_get(config, key);
312
313 // Return zero if not set
314 if (!value)
315 return __default;
316
317 return strtoul(value, NULL, 10);
318 }
319
320 int nw_config_set_int(struct nw_config* config, const char* key, const int value) {
321 char __value[1024];
322 int r;
323
324 // Format the value as string
325 r = nw_string_format(__value, "%d\n", value);
326 if (r)
327 return r;
328
329 return nw_config_set(config, key, __value);
330 }