summaryrefslogtreecommitdiffstats
path: root/src/config-load.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/config-load.c')
-rw-r--r--src/config-load.c142
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, &section->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;
+}