Load config dirs

This commit is contained in:
Matthias Schiffer 2018-12-29 17:00:31 +01:00
parent f4881eb5e2
commit 9e059f898a
Signed by: neocturne
GPG key ID: 16EF3F64CB201D9C
6 changed files with 125 additions and 38 deletions

View file

@ -1,4 +1,5 @@
project('pnc', 'c')
project('pnc', 'c', default_options : ['c_std=c11'])
add_project_arguments('-D_DEFAULT_SOURCE', language : 'c')
cc = meson.get_compiler('c')
ubox_dep = cc.find_library('ubox')

View file

@ -3,7 +3,6 @@
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -67,11 +66,7 @@ static ini_section_t * add_section(ini_file_t *file, const char *name) {
return section;
}
ini_file_t * read_ini_file(const char *filename) {
FILE *f = fopen(filename, "r");
if (!f)
return NULL;
ini_file_t * read_ini_file(FILE *f) {
ini_file_t *file = calloc(1, sizeof(*file));
if (!file)
goto error;
@ -135,7 +130,6 @@ ini_file_t * read_ini_file(const char *filename) {
error:
free(line);
fclose(f);
if (err) {
free_ini_file(file);

View file

@ -2,6 +2,8 @@
#include <libubox/list.h>
#include <stdio.h>
typedef struct {
struct list_head node;
char *key;
@ -18,5 +20,5 @@ typedef struct {
struct list_head sections;
} ini_file_t;
ini_file_t * read_ini_file(const char *filename);
ini_file_t * read_ini_file(FILE *f);
void free_ini_file(ini_file_t *file);

View file

@ -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;
}
char *name = strndup(filename, (ext - filename) - 1);
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;
if (strcmp(ext, "interface") == 0) {
interface_config_t *iface = read_interface_config(path);
free(iface);
int fd = openat(dirfd, filename, O_RDONLY);
if (fd < 0)
return false;
FILE *f = fdopen(fd, "r");
if (!f) {
close(fd);
return false;
}
free(name);
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;
}

View file

@ -2,4 +2,4 @@
#include <stdbool.h>
bool read_config_file(const char *path);
bool read_config(const char *path);

View file

@ -1,6 +1,6 @@
#include "config-load.h"
int main(int argc, char *argv[]) {
read_config_file(argv[1]);
read_config(argv[1]);
return 0;
}