#include "config-load.h" #include "config-process.h" #include "device.h" #include "util.h" #include #include #include #include #include #include #include #include #include typedef struct _load_ctx { struct avl_tree subtypes; struct avl_tree devices; } load_ctx_t; static const char * extname(const char *filename) { const char *dot = strrchr(filename, '.'); return dot ? (dot+1) : NULL; } static bool isfile(int fd) { struct stat buf; if (fstat(fd, &buf) < 0) return false; return (buf.st_mode & S_IFMT) == S_IFREG; } static bool read_config_file(load_ctx_t *ctx, int dirfd, const char *filename) { const char *ext = extname(filename); if (!ext) return true; struct avl_tree *target_tree; if (strcmp(ext, "sub") == 0 || strcmp(ext, "gen") == 0) target_tree = &ctx->subtypes; else if (get_device_type(ext)) target_tree = &ctx->devices; else return true; int fd = openat(dirfd, filename, O_RDONLY); if (fd < 0) return false; if (!isfile(fd)) { close(fd); return true; } 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; config_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) { config_object_free(obj); return false; } NODE_NAME(obj) = name; obj->type = strdup(ext); if (!obj->type) { config_object_free(obj); return false; } avl_insert(target_tree, &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) read_config_file(ctx, fd, ent->d_name); closedir(dir); return true; } bool read_config(const char *path) { load_ctx_t ctx; avl_init(&ctx.subtypes, avl_strcmp, true, NULL); avl_init(&ctx.devices, avl_strcmp, true, NULL); bool ret = read_config_dir(&ctx, path); struct avl_tree *subtypes = config_process_subtypes(&ctx.subtypes); struct avl_tree *devices = config_process_devices(&ctx.devices); free(subtypes); device_t *dev, *tmp; avl_remove_all_elements(devices, dev, node, tmp) dev->type->free_device(dev); free(devices); return ret; }