]> git.ipfire.org Git - people/ms/network.git/blob - src/networkd/config.c
networkd: Implement writing configuration files
[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 <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/queue.h>
26
27 #include "config.h"
28 #include "logging.h"
29 #include "string.h"
30
31 struct nw_config_entry {
32 STAILQ_ENTRY(nw_config_entry) nodes;
33
34 char key[NETWORK_CONFIG_KEY_MAX_LENGTH];
35 char value[NETWORK_CONFIG_KEY_MAX_LENGTH];
36 };
37
38 struct nw_config {
39 int nrefs;
40
41 STAILQ_HEAD(entries, nw_config_entry) entries;
42 };
43
44 static void nw_config_entry_free(struct nw_config_entry* entry) {
45 free(entry);
46 }
47
48 static struct nw_config_entry* nw_config_entry_create(
49 struct nw_config* config, const char* key) {
50 int r;
51
52 // Check input value
53 if (!key) {
54 errno = EINVAL;
55 return NULL;
56 }
57
58 // Allocate a new object
59 struct nw_config_entry* entry = calloc(1, sizeof(*entry));
60 if (!entry)
61 return NULL;
62
63 // Store the key
64 r = nw_string_set(entry->key, key);
65 if (r)
66 goto ERROR;
67
68 // Append the new entry
69 STAILQ_INSERT_TAIL(&config->entries, entry, nodes);
70
71 ERROR:
72 nw_config_entry_free(entry);
73 return NULL;
74 }
75
76 static void nw_config_free(struct nw_config* config) {
77 struct nw_config_entry* entry = NULL;
78
79 while (!STAILQ_EMPTY(&config->entries)) {
80 entry = STAILQ_FIRST(&config->entries);
81 STAILQ_REMOVE_HEAD(&config->entries, nodes);
82
83 // Free the entry
84 nw_config_entry_free(entry);
85 }
86
87 free(config);
88 }
89
90 int nw_config_create(struct nw_config** config) {
91 struct nw_config* c = calloc(1, sizeof(*c));
92 if (!c)
93 return 1;
94
95 // Initialize reference counter
96 c->nrefs = 1;
97
98 // Initialise entries
99 STAILQ_INIT(&c->entries);
100
101 *config = c;
102
103 return 0;
104 }
105
106 struct nw_config* nw_config_ref(struct nw_config* config) {
107 config->nrefs++;
108
109 return config;
110 }
111
112 struct nw_config* nw_config_unref(struct nw_config* config) {
113 if (--config->nrefs > 0)
114 return config;
115
116 nw_config_free(config);
117 return NULL;
118 }
119
120 static int nw_config_parse(struct nw_config* config, FILE* f) {
121 // XXX TODO
122
123 return 0;
124 }
125
126 int nw_config_readf(struct nw_config** config, FILE* f) {
127 int r;
128
129 // Create a new config object
130 r = nw_config_create(config);
131 if (r)
132 return r;
133
134 // Parse the configuration
135 r = nw_config_parse(*config, f);
136 if (r)
137 goto ERROR;
138
139 return 0;
140
141 ERROR:
142 nw_config_free(*config);
143 return r;
144 }
145
146 int nw_config_read(struct nw_config** config, const char* path) {
147 FILE* f = NULL;
148 int r;
149
150 // Open the file
151 f = fopen(path, "r");
152 if (!f) {
153 ERROR("Could not read configuration file %s: %m\n", path);
154 r = 1;
155 goto ERROR;
156 }
157
158 // Read from file
159 r = nw_config_readf(config, f);
160
161 ERROR:
162 if (f)
163 fclose(f);
164
165 return r;
166 }
167
168 int nw_config_writef(struct nw_config* config, FILE* f) {
169 struct nw_config_entry* entry = NULL;
170 int r;
171
172 STAILQ_FOREACH(entry, &config->entries, nodes) {
173 // Skip if value is NULL
174 if (!*entry->value)
175 continue;
176
177 // Write the entry
178 r = fprintf(f, "%s=\"%s\"\n", entry->key, entry->value);
179 if (r < 0) {
180 ERROR("Failed to write configuration: %m\n");
181 return r;
182 }
183 }
184
185 return 0;
186 }
187
188 int nw_config_write(struct nw_config* config, const char* path) {
189 int r;
190
191 FILE* f = fopen(path, "w");
192 if (!f) {
193 ERROR("Failed to open %s for writing: %m\n", path);
194 r = 1;
195 goto ERROR;
196 }
197
198 // Write configuration
199 r = nw_config_writef(config, f);
200
201 ERROR:
202 if (f)
203 fclose(f);
204
205 return r;
206 }
207
208 static struct nw_config_entry* nw_config_find(struct nw_config* config, const char* key) {
209 struct nw_config_entry* entry = NULL;
210
211 STAILQ_FOREACH(entry, &config->entries, nodes) {
212 // Key must match
213 if (strcmp(entry->key, key) != 0)
214 continue;
215
216 // Match!
217 return entry;
218 }
219
220 // No match
221 return NULL;
222 }
223
224 int nw_config_del(struct nw_config* config, const char* key) {
225 struct nw_config_entry* entry = NULL;
226
227 // Find an entry matching the key
228 entry = nw_config_find(config, key);
229
230 // If there is no entry, there is nothing to do
231 if (!entry)
232 return 0;
233
234 // Otherwise remove the object
235 STAILQ_REMOVE(&config->entries, entry, nw_config_entry, nodes);
236
237 // Free the entry
238 nw_config_entry_free(entry);
239
240 return 0;
241 }
242
243 int nw_config_set(struct nw_config* config, const char* key, const char* value) {
244 struct nw_config_entry* entry = NULL;
245
246 // Delete the entry if val is NULL
247 if (!value)
248 return nw_config_del(config, key);
249
250 // Find any existing entries
251 entry = nw_config_find(config, key);
252
253 // Create a new entry if it doesn't exist, yet
254 if (!entry) {
255 entry = nw_config_entry_create(config, key);
256 if (!entry)
257 return 1;
258 }
259
260 // Store the new value
261 return nw_string_set(entry->value, value);
262 }
263
264 const char* nw_config_get(struct nw_config* config, const char* key) {
265 struct nw_config_entry* entry = nw_config_find(config, key);
266
267 // Return the value if found and set
268 if (entry && *entry->value)
269 return entry->value;
270
271 // Otherwise return NULL
272 return NULL;
273 }
274
275 unsigned int nw_config_get_unsigned_int(struct nw_config* config, const char* key) {
276 const char* value = nw_config_get(config, key);
277
278 // Return zero if not set
279 if (!value)
280 return 0;
281
282 return strtoul(value, NULL, 10);
283 }