diff options
Diffstat (limited to 'src/config-load.c')
-rw-r--r-- | src/config-load.c | 142 |
1 files changed, 116 insertions, 26 deletions
diff --git a/src/config-load.c b/src/config-load.c index 9335813..28b5953 100644 --- a/src/config-load.c +++ b/src/config-load.c @@ -2,54 +2,144 @@ #include "config-ini.h" #include "types.h" +#include <libubox/avl.h> +#include <libubox/avl-cmp.h> + +#include <sys/types.h> +#include <dirent.h> #include <errno.h> -#include <stdio.h> +#include <fcntl.h> #include <stdlib.h> #include <string.h> +#include <unistd.h> -static const char * simple_basename(const char *path) { - const char *slash = strrchr(path, '/'); - return slash ? (slash+1) : path; -} +typedef enum { + LOAD_TYPE_INTERFACE, + LOAD_TYPE_SUBCONFIG, + LOAD_TYPE_GENERATOR, + LOAD_TYPE_DEVICE, + N_LOAD_TYPES, +} load_type_t; + +typedef struct { + struct avl_node node; + char *type; + ini_file_t *data; +} load_object_t; + +typedef struct { + struct avl_tree objects[N_LOAD_TYPES]; +} load_ctx_t; static const char * extname(const char *filename) { const char *dot = strrchr(filename, '.'); return dot ? (dot+1) : NULL; } -static interface_config_t * read_interface_config(const char *path) { - ini_file_t *file = read_ini_file(path); - ini_section_t *section; - ini_field_t *field; - - list_for_each_entry(section, &file->sections, node) { - printf("%s\n", section->name); - - list_for_each_entry(field, §ion->fields, node) - printf("%s.%s=%s\n", section->name, field->key, field->value); - } - - free_ini_file(file); - - return NULL; +static void free_object(load_object_t *obj) { + free_ini_file(obj->data); + free(obj->type); + free(NODE_NAME(obj)); + free(obj); } -bool read_config_file(const char *path) { - const char *filename = simple_basename(path); +static bool read_config_file(load_ctx_t *ctx, int dirfd, const char *filename) { const char *ext = extname(filename); if (!ext) { errno = EINVAL; return false; } + load_type_t type; + if (strcmp(ext, "interface") == 0) + type = LOAD_TYPE_INTERFACE; + else if (strcmp(ext, "sub") == 0) + type = LOAD_TYPE_SUBCONFIG; + else if (strcmp(ext, "gen") == 0) + type = LOAD_TYPE_GENERATOR; + else if (strcmp(ext, "bridge") == 0) + type = LOAD_TYPE_DEVICE; + else + return true; + + int fd = openat(dirfd, filename, O_RDONLY); + if (fd < 0) + return false; + + FILE *f = fdopen(fd, "r"); + if (!f) { + close(fd); + return false; + } + + ini_file_t *data = read_ini_file(f); + fclose(f); + + if (!data) + return false; + + load_object_t *obj = calloc(1, sizeof(*obj)); + if (!obj) { + free_ini_file(data); + return false; + } + obj->data = data; + char *name = strndup(filename, (ext - filename) - 1); + if (!name) { + free_object(obj); + return false; + } + NODE_NAME(obj) = name; - if (strcmp(ext, "interface") == 0) { - interface_config_t *iface = read_interface_config(path); - free(iface); + obj->type = strdup(ext); + if (!obj->type) { + free_object(obj); + return false; } - free(name); + avl_insert(&ctx->objects[type], &obj->node); return true; } + +static bool read_config_dir(load_ctx_t *ctx, const char *path) { + DIR *dir = opendir(path); + if (!dir) + return false; + + int fd = dirfd(dir); + + struct dirent *ent; + while ((ent = readdir(dir)) != NULL) { + if (ent->d_type == DT_REG) + read_config_file(ctx, fd, ent->d_name); + } + + closedir(dir); + + return true; +} + +bool read_config(const char *path) { + load_ctx_t ctx; + for (size_t i = 0; i < N_LOAD_TYPES; i++) + avl_init(&ctx.objects[i], avl_strcmp, true, NULL); + + bool ret = read_config_dir(&ctx, path); + + for (size_t i = 0; i < N_LOAD_TYPES; i++) { + load_object_t *obj; + avl_for_each_element(&ctx.objects[i], obj, node) { + printf("%s(%u): %s\n", obj->type, (unsigned)i, NODE_NAME(obj)); + } + } + + for (size_t i = 0; i < N_LOAD_TYPES; i++) { + load_object_t *obj, *tmp; + avl_for_each_element_safe(&ctx.objects[i], obj, node, tmp) + free_object(obj); + } + + return ret; +} |