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>
34 struct nw_config_entry
{
35 STAILQ_ENTRY(nw_config_entry
) nodes
;
37 char key
[NETWORK_CONFIG_KEY_MAX_LENGTH
];
38 char value
[NETWORK_CONFIG_KEY_MAX_LENGTH
];
41 struct nw_config_option
{
42 STAILQ_ENTRY(nw_config_option
) nodes
;
48 nw_config_option_read_callback_t read_callback
;
49 nw_config_option_write_callback_t write_callback
;
56 STAILQ_HEAD(config_entries
, nw_config_entry
) entries
;
59 STAILQ_HEAD(parser_entries
, nw_config_option
) options
;
62 static void nw_config_entry_free(struct nw_config_entry
* entry
) {
66 static void nw_config_option_free(struct nw_config_option
* option
) {
70 static struct nw_config_entry
* nw_config_entry_create(
71 nw_config
* config
, const char* key
) {
80 // Allocate a new object
81 struct nw_config_entry
* entry
= calloc(1, sizeof(*entry
));
86 r
= nw_string_set(entry
->key
, key
);
90 // Append the new entry
91 STAILQ_INSERT_TAIL(&config
->entries
, entry
, nodes
);
96 nw_config_entry_free(entry
);
100 static void nw_config_free(nw_config
* config
) {
101 struct nw_config_option
* option
= NULL
;
104 nw_config_flush(config
);
107 while (!STAILQ_EMPTY(&config
->options
)) {
108 option
= STAILQ_FIRST(&config
->options
);
109 STAILQ_REMOVE_HEAD(&config
->options
, nodes
);
112 nw_config_option_free(option
);
118 int nw_config_create(nw_config
** config
, FILE* f
) {
121 nw_config
* c
= calloc(1, sizeof(*c
));
125 // Initialize reference counter
128 // Initialise entries
129 STAILQ_INIT(&c
->entries
);
131 // Initialise options
132 STAILQ_INIT(&c
->options
);
134 // Read configuration
136 r
= nw_config_read(c
, f
);
151 int nw_config_open(nw_config
** config
, const char* path
) {
156 f
= fopen(path
, "r");
160 // Create a new configuration
161 r
= nw_config_create(config
, f
);
170 nw_config
* nw_config_ref(nw_config
* config
) {
176 nw_config
* nw_config_unref(nw_config
* config
) {
177 if (--config
->nrefs
> 0)
180 nw_config_free(config
);
184 int nw_config_copy(nw_config
* config
, nw_config
** copy
) {
185 struct nw_config_entry
* entry
= NULL
;
189 // Create a new configuration
190 r
= nw_config_create(&c
, NULL
);
195 STAILQ_FOREACH(entry
, &config
->entries
, nodes
) {
196 r
= nw_config_set(c
, entry
->key
, entry
->value
);
211 int nw_config_flush(nw_config
* config
) {
212 struct nw_config_entry
* entry
= NULL
;
214 while (!STAILQ_EMPTY(&config
->entries
)) {
215 entry
= STAILQ_FIRST(&config
->entries
);
216 STAILQ_REMOVE_HEAD(&config
->entries
, nodes
);
219 nw_config_entry_free(entry
);
225 int nw_config_read(nw_config
* config
, FILE* f
) {
230 ssize_t bytes_read
= 0;
236 // Read the next line
237 bytes_read
= getline(&line
, &length
, f
);
241 // Key starts at the beginning of the line
244 // Value starts after '='
245 val
= strchr(line
, '=');
247 // Invalid line without a '=' character
254 // Strip any whitespace from value
255 r
= nw_string_strip(val
);
260 r
= nw_config_set(config
, key
, val
);
271 int nw_config_write(nw_config
* config
, FILE* f
) {
272 struct nw_config_entry
* entry
= NULL
;
275 STAILQ_FOREACH(entry
, &config
->entries
, nodes
) {
276 // Skip if value is NULL
281 r
= fprintf(f
, "%s=%s\n", entry
->key
, entry
->value
);
283 ERROR("Failed to write configuration: %m\n");
291 static struct nw_config_entry
* nw_config_find(nw_config
* config
, const char* key
) {
292 struct nw_config_entry
* entry
= NULL
;
294 STAILQ_FOREACH(entry
, &config
->entries
, nodes
) {
296 if (strcmp(entry
->key
, key
) != 0)
307 int nw_config_del(nw_config
* config
, const char* key
) {
308 struct nw_config_entry
* entry
= NULL
;
310 // Find an entry matching the key
311 entry
= nw_config_find(config
, key
);
313 // If there is no entry, there is nothing to do
317 // Otherwise remove the object
318 STAILQ_REMOVE(&config
->entries
, entry
, nw_config_entry
, nodes
);
321 nw_config_entry_free(entry
);
326 const char* nw_config_get(nw_config
* config
, const char* key
) {
327 struct nw_config_entry
* entry
= nw_config_find(config
, key
);
329 // Return the value if found and set
330 if (entry
&& *entry
->value
)
333 // Otherwise return NULL
337 int nw_config_set(nw_config
* config
, const char* key
, const char* value
) {
338 struct nw_config_entry
* entry
= NULL
;
341 DEBUG("%p: Setting %s = %s\n", config
, key
, value
);
343 // Delete the entry if val is NULL
345 return nw_config_del(config
, key
);
347 // Find any existing entries
348 entry
= nw_config_find(config
, key
);
350 // Create a new entry if it doesn't exist, yet
352 entry
= nw_config_entry_create(config
, key
);
357 // Store the new value
358 return nw_string_set(entry
->value
, value
);
361 int nw_config_get_int(nw_config
* config
, const char* key
, const int __default
) {
365 const char* value
= nw_config_get(config
, key
);
367 // Return zero if not set
372 r
= strtoul(value
, &p
, 10);
374 // If we have characters following the input, we throw it away
381 int nw_config_set_int(nw_config
* config
, const char* key
, const int value
) {
385 // Format the value as string
386 r
= nw_string_format(__value
, "%d", value
);
390 return nw_config_set(config
, key
, __value
);
393 static const char* nw_config_true
[] = {
400 int nw_config_get_bool(nw_config
* config
, const char* key
) {
401 const char* value
= nw_config_get(config
, key
);
403 // No value indicates false
407 // Check if we match any known true words
408 for (const char** s
= nw_config_true
; *s
; s
++) {
409 if (strcasecmp(value
, *s
) == 0)
413 // No match means false
417 int nw_config_set_bool(nw_config
* config
, const char* key
, const int value
) {
418 return nw_config_set(config
, key
, value
? "true" : "false");
425 int nw_config_options_read(nw_config
* config
) {
426 struct nw_config_option
* option
= NULL
;
429 STAILQ_FOREACH(option
, &config
->options
, nodes
) {
430 r
= option
->read_callback(config
, option
->key
, option
->value
, option
->data
);
438 int nw_config_options_write(nw_config
* config
) {
439 struct nw_config_option
* option
= NULL
;
442 STAILQ_FOREACH(option
, &config
->options
, nodes
) {
443 r
= option
->write_callback(config
, option
->key
, option
->value
, option
->data
);
451 int nw_config_option_add(nw_config
* config
, const char* key
, void* value
,
452 nw_config_option_read_callback_t read_callback
,
453 nw_config_option_write_callback_t write_callback
, void* data
) {
455 if (!key
|| !value
|| !read_callback
|| !write_callback
)
458 // Allocate a new option
459 struct nw_config_option
* option
= calloc(1, sizeof(*option
));
467 option
->value
= value
;
470 option
->read_callback
= read_callback
;
471 option
->write_callback
= write_callback
;
474 // Append the new option
475 STAILQ_INSERT_TAIL(&config
->options
, option
, nodes
);
480 int nw_config_read_int(nw_config
* config
, const char* key
, void* value
, void* data
) {
482 *(int*)value
= nw_config_get_int(config
, key
, -1);
487 int nw_config_write_int(nw_config
* config
,
488 const char* key
, const void* value
, void* data
) {
494 int nw_config_read_string(nw_config
* config
, const char* key
, void* value
, void* data
) {
496 const char* p
= nw_config_get(config
, key
);
498 *(const char**)value
= p
;
503 int nw_config_write_string(nw_config
* config
,
504 const char* key
, const void* value
, void* data
) {
505 return nw_config_set(config
, key
, *(const char**)value
);
510 int nw_config_read_string_table(nw_config
* config
, const char* key
, void* value
, void* data
) {
511 const char* s
= NULL
;
512 int* v
= (int*)value
;
514 const nw_string_table_t
* table
= (nw_string_table_t
*)data
;
517 s
= nw_config_get(config
, key
);
521 // Lookup the string in the table
522 *v
= nw_string_table_lookup_id(table
, s
);
524 // If the result is negative, nothing was found
531 int nw_config_write_string_table(nw_config
* config
,
532 const char* key
, const void* value
, void* data
) {
533 int* v
= (int*)value
;
535 const nw_string_table_t
* table
= (nw_string_table_t
*)data
;
538 const char* s
= nw_string_table_lookup_string(table
, *v
);
542 return nw_config_set(config
, key
, s
);
547 int nw_config_read_address(nw_config
* config
, const char* key
, void* value
, void* data
) {
548 nw_address_t
* address
= (nw_address_t
*)value
;
552 const char* p
= nw_config_get(config
, key
);
556 r
= nw_address_from_string(address
, p
);
558 ERROR("Could not parse address: %s\n", p
);
563 int nw_config_write_address(nw_config
* config
,
564 const char* key
, const void* value
, void* data
) {
565 const nw_address_t
* address
= (nw_address_t
*)value
;
568 // Format the address to string
569 char* p
= nw_address_to_string(address
);
574 r
= nw_config_set(config
, key
, p
);