#include "config-load.h" #include "config-ini.h" #include "types.h" #include #include #include #include #include #include #include #include #include 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 void free_object(load_object_t *obj) { free_ini_file(obj->data); free(obj->type); free(NODE_NAME(obj)); free(obj); } 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; obj->type = strdup(ext); if (!obj->type) { free_object(obj); return false; } 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; }