1 /*#############################################################################
3 # IPFire.org - A linux based firewall #
4 # Copyright (C) 2023 IPFire Network Development Team #
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. #
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. #
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/>. #
19 #############################################################################*/
26 #include <sys/queue.h>
32 struct nw_config_entry
{
33 STAILQ_ENTRY(nw_config_entry
) nodes
;
35 char key
[NETWORK_CONFIG_KEY_MAX_LENGTH
];
36 char value
[NETWORK_CONFIG_KEY_MAX_LENGTH
];
42 // The path to the configuration file
45 STAILQ_HEAD(entries
, nw_config_entry
) entries
;
48 static void nw_config_entry_free(struct nw_config_entry
* entry
) {
52 static struct nw_config_entry
* nw_config_entry_create(
53 nw_config
* config
, const char* key
) {
62 // Allocate a new object
63 struct nw_config_entry
* entry
= calloc(1, sizeof(*entry
));
68 r
= nw_string_set(entry
->key
, key
);
72 // Append the new entry
73 STAILQ_INSERT_TAIL(&config
->entries
, entry
, nodes
);
78 nw_config_entry_free(entry
);
82 static void nw_config_free(nw_config
* config
) {
84 nw_config_flush(config
);
89 int nw_config_create(nw_config
** config
, const char* path
) {
92 nw_config
* c
= calloc(1, sizeof(*c
));
96 // Initialize reference counter
100 STAILQ_INIT(&c
->entries
);
104 r
= nw_string_set(c
->path
, path
);
108 // Try to read the configuration from path
109 r
= nw_config_read(c
);
124 nw_config
* nw_config_ref(nw_config
* config
) {
130 nw_config
* nw_config_unref(nw_config
* config
) {
131 if (--config
->nrefs
> 0)
134 nw_config_free(config
);
138 const char* nw_config_path(nw_config
* config
) {
145 int nw_config_flush(nw_config
* config
) {
146 struct nw_config_entry
* entry
= NULL
;
148 while (!STAILQ_EMPTY(&config
->entries
)) {
149 entry
= STAILQ_FIRST(&config
->entries
);
150 STAILQ_REMOVE_HEAD(&config
->entries
, nodes
);
153 nw_config_entry_free(entry
);
159 static int nw_config_readf(nw_config
* config
, FILE* f
) {
164 ssize_t bytes_read
= 0;
170 // Read the next line
171 bytes_read
= getline(&line
, &length
, f
);
175 // Key starts at the beginning of the line
178 // Value starts after '='
179 val
= strchr(line
, '=');
181 // Invalid line without a '=' character
188 // Strip any whitespace from value
189 r
= nw_string_strip(val
);
194 r
= nw_config_set(config
, key
, val
);
205 int nw_config_read(nw_config
* config
) {
209 // We cannot read if path is not set
210 if (!*config
->path
) {
216 f
= fopen(config
->path
, "r");
218 // Silently ignore if the file does not exist
222 ERROR("Could not read configuration file %s: %m\n", config
->path
);
228 r
= nw_config_readf(config
, f
);
237 static int nw_config_writef(nw_config
* config
, FILE* f
) {
238 struct nw_config_entry
* entry
= NULL
;
241 STAILQ_FOREACH(entry
, &config
->entries
, nodes
) {
242 // Skip if value is NULL
247 r
= fprintf(f
, "%s=%s\n", entry
->key
, entry
->value
);
249 ERROR("Failed to write configuration: %m\n");
257 int nw_config_write(nw_config
* config
) {
260 // We cannot write if path is not set
261 if (!*config
->path
) {
266 FILE* f
= fopen(config
->path
, "w");
268 ERROR("Failed to open %s for writing: %m\n", config
->path
);
273 // Write configuration
274 r
= nw_config_writef(config
, f
);
283 static struct nw_config_entry
* nw_config_find(nw_config
* config
, const char* key
) {
284 struct nw_config_entry
* entry
= NULL
;
286 STAILQ_FOREACH(entry
, &config
->entries
, nodes
) {
288 if (strcmp(entry
->key
, key
) != 0)
299 int nw_config_del(nw_config
* config
, const char* key
) {
300 struct nw_config_entry
* entry
= NULL
;
302 // Find an entry matching the key
303 entry
= nw_config_find(config
, key
);
305 // If there is no entry, there is nothing to do
309 // Otherwise remove the object
310 STAILQ_REMOVE(&config
->entries
, entry
, nw_config_entry
, nodes
);
313 nw_config_entry_free(entry
);
318 const char* nw_config_get(nw_config
* config
, const char* key
) {
319 struct nw_config_entry
* entry
= nw_config_find(config
, key
);
321 // Return the value if found and set
322 if (entry
&& *entry
->value
)
325 // Otherwise return NULL
329 int nw_config_set(nw_config
* config
, const char* key
, const char* value
) {
330 struct nw_config_entry
* entry
= NULL
;
332 // Delete the entry if val is NULL
334 return nw_config_del(config
, key
);
336 // Find any existing entries
337 entry
= nw_config_find(config
, key
);
339 // Create a new entry if it doesn't exist, yet
341 entry
= nw_config_entry_create(config
, key
);
346 // Store the new value
347 return nw_string_set(entry
->value
, value
);
350 int nw_config_get_int(nw_config
* config
, const char* key
, const int __default
) {
351 const char* value
= nw_config_get(config
, key
);
353 // Return zero if not set
357 return strtoul(value
, NULL
, 10);
360 int nw_config_set_int(nw_config
* config
, const char* key
, const int value
) {
364 // Format the value as string
365 r
= nw_string_format(__value
, "%d\n", value
);
369 return nw_config_set(config
, key
, __value
);