pmlag

Poor man's link aggregation
git clone git://git.finwo.net/app/pmlag
Log | Files | Refs | LICENSE

commit 9f9dc25f5ab60352e68544080c9144cf10c060f4
parent 876db202f8684ec30f015e8f83a190004a744a39
Author: finwo <finwo@pm.me>
Date:   Sat,  5 Sep 2026 22:50:16 +0200

Config parser mostly wired

Diffstat:
MMakefile | 10++++++++--
Aconfig/test.cnf | 1+
Mexample.conf | 13++++++++-----
Asrc/daemon/bond/config.c | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/daemon/bond/config.h | 10++++++++++
Asrc/daemon/bond/setup.c | 8++++++++
Asrc/daemon/bond/setup.h | 6++++++
Asrc/daemon/router/config.c | 154+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/daemon/router/config.h | 10++++++++++
Asrc/daemon/router/setup.c | 8++++++++
Asrc/daemon/router/setup.h | 6++++++
Msrc/main.c | 9++++++++-
Dsrc/util/config-root.c | 208-------------------------------------------------------------------------------
Dsrc/util/config-root.h | 15---------------
Asrc/util/config.c | 209+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/util/config.h | 15+++++++++++++++
Mtarget/common/Makefile | 1+
17 files changed, 507 insertions(+), 231 deletions(-)

diff --git a/Makefile b/Makefile @@ -3,11 +3,17 @@ TARGET:=linux-glibc-amd64 .PHONY: default default: build/${TARGET}/pmlag -build/${TARGET}/pmlag: build/${TARGET} $(wildcard src/*.c src/*.h src/*/*.c src/*/*.h) +FIND:=$(shell command -v gfind find) + +WATCH?= +WATCH+=$(shell $(FIND) src -type f -name '*.c') +WATCH+=$(shell $(FIND) src -type f -name '*.h') + +build/${TARGET}/pmlag: build/${TARGET} $(WATCH) cd build/${TARGET} && dep install $(MAKE) --directory build/${TARGET} TARGET=${TARGET} -build/${TARGET}: $(wildcard src/*.c src/*.h src/*/*.c src/*/*.h) +build/${TARGET}: $(WATCH) mkdir -p build/${TARGET} cp -rT manpage.1.md build/${TARGET}/manpage.1.md cp -rT src/ build/${TARGET}/src diff --git a/config/test.cnf b/config/test.cnf @@ -0,0 +1 @@ + diff --git a/example.conf b/example.conf @@ -14,15 +14,18 @@ bond bon1 # Routed interface, L3 only # Auto-announce routes -routed rnic0 +router rnic0 + interface eth1 + interface eth2 address 192.0.0.1/32 - route auto + redistribute kernel # Routed interface, L3 only # Fixed routes -routed rnic1 +router rnic1 address 192.0.0.1/32 address fe80::1/128 + interface eth1 route 0.0.0.0/0 neighbour 9c:6b:00:60:05:98 ttl 3600 @@ -34,11 +37,11 @@ routed rnic1 # Routed interface, L3 only # Mixed routes -routed rnic1 +router rnic2 address 192.0.0.1/32 address fe80::1/128 # Propagate routes with metric +50 - route auto + redistribute kernel ttl 300 metric 50 # Static routes diff --git a/src/daemon/bond/config.c b/src/daemon/bond/config.c @@ -0,0 +1,55 @@ +#include <stdio.h> +#include <stdlib.h> +#include <strings.h> + +#include "util/config.h" + +#include "config.h" + +struct cnf_directive * cfg_parse_bond(FILE *fd, struct cnf_directive *dir, void *user) { + int i; + + if (dir->argc != 1) { + fprintf(stderr, "`bond` directive accepts only 1 argument\n"); + exit(1); + } + + printf("Defining bond: %s\n", dir->argv[0]); + + for(;;) { + if (dir) cnf_directive_free(dir); + dir = cnf_directive_read(fd); + if (!dir) break; // EOF = done + + // Make following blocks identical in structure + if(0) {} + + else if (!strcasecmp("interface", dir->name)) { + for( i = 0 ; i < dir->argc ; i++ ) { + printf(" add iface: %s\n", dir->argv[i]); + } + } + + else if (!strcasecmp("address", dir->name)) { + for( i = 0 ; i < dir->argc ; i++ ) { + printf(" got addr: %s\n", dir->argv[i]); + } + } + + else if (!strcasecmp("mac", dir->name)) { + if (dir->argc != 1) { + fprintf(stderr, "`mac` directive accepts only 1 argument\n"); + exit(1); + } + printf(" set mac: %s\n", dir->argv[0]); + } + + else { + // unknown directive + return dir; + } + + } + + return NULL; +} diff --git a/src/daemon/bond/config.h b/src/daemon/bond/config.h @@ -0,0 +1,10 @@ +#ifndef __PMLAG_DAEMON_BOND_CONFIG_H__ +#define __PMLAG_DAEMON_BOND_CONFIG_H__ + +#include <stdio.h> + +#include "finwo/cnfparse.h" + +struct cnf_directive * cfg_parse_bond(FILE *fd, struct cnf_directive *dir, void *user); + +#endif // __PMLAG_DAEMON_BOND_CONFIG_H__ diff --git a/src/daemon/bond/setup.c b/src/daemon/bond/setup.c @@ -0,0 +1,8 @@ +#include "util/config.h" + +#include "setup.h" +#include "config.h" + +void daemon_bond_setup() { + cfg_register_directive("bond", cfg_parse_bond); +} diff --git a/src/daemon/bond/setup.h b/src/daemon/bond/setup.h @@ -0,0 +1,6 @@ +#ifndef __PMLAG_DAEMON_BOND_SETUP_H__ +#define __PMLAG_DAEMON_BOND_SETUP_H__ + +void daemon_bond_setup(); + +#endif // __PMLAG_DAEMON_BOND_SETUP_H__ diff --git a/src/daemon/router/config.c b/src/daemon/router/config.c @@ -0,0 +1,154 @@ +#include <stdio.h> +#include <stdlib.h> +#include <strings.h> + +#include "util/config.h" + +#include "config.h" + +struct cnf_directive * cfg_parse_redistribute(FILE *fd, struct cnf_directive *dir, void *user) { + int i; + + if (dir->argc < 1) { + fprintf(stderr, "`redistribute` directive needs at least 1 argument\n"); + exit(1); + } + + // TODO: start building redistribute entry + + + for(;;) { + if (dir) cnf_directive_free(dir); + dir = cnf_directive_read(fd); + if (!dir) break; // EOF = done + // Make following blocks identical in structure + if(0) {} + + else if (!strcasecmp("ttl", dir->name)) { + // TODO: route->ttl = atoi(argv[0]) + } + + else if (!strcasecmp("metric", dir->name)) { + // TODO: route->metric = atoi(argv[0]) + } + + else { + // unknown directive + break; + } + } + + // Cleanup + // TODO: store redist in current router def + + // Return the unparsed dir if set + return dir; +} + +struct cnf_directive * cfg_parse_route(FILE *fd, struct cnf_directive *dir, void *user) { + int i; + + if (dir->argc < 1) { + fprintf(stderr, "`route` directive needs at least 1\n"); + exit(1); + } + + // TODO: start building route + + for(;;) { + if (dir) cnf_directive_free(dir); + dir = cnf_directive_read(fd); + if (!dir) break; // EOF = done +cfg_parse_route_reparse: + // Make following blocks identical in structure + if(0) {} + + else if (!strcasecmp("ttl", dir->name)) { + // TODO: route->ttl = atoi(argv[0]) + } + + else if (!strcasecmp("metric", dir->name)) { + // TODO: route->metric = atoi(argv[0]) + } + + else if (!strcasecmp("neighbour", dir->name)) { + // TODO: route->neighbour[] = parse_mac(argv[0]) + } + + else { + // unknown directive + break; + } + } + + // Cleanup + // TODO: store route in current router def + + // Return the unparsed dir if set + return dir; +} + +struct cnf_directive * cfg_parse_router(FILE *fd, struct cnf_directive *dir, void *user) { + int i; + + if (dir->argc != 1) { + fprintf(stderr, "`router` directive accepts only 1 argument\n"); + exit(1); + } + + printf("Defining router: %s\n", dir->argv[0]); + + for(;;) { + if (dir) cnf_directive_free(dir); + dir = cnf_directive_read(fd); + if (!dir) break; // EOF = done + +cfg_parse_router_reparse: + + // Make following blocks identical in structure + if(0) {} + + else if (!strcasecmp("interface", dir->name)) { + for( i = 0 ; i < dir->argc ; i++ ) { + printf(" add iface: %s\n", dir->argv[i]); + } + } + + else if (!strcasecmp("address", dir->name)) { + for( i = 0 ; i < dir->argc ; i++ ) { + printf(" got addr: %s\n", dir->argv[i]); + } + } + + // else if (!strcasecmp("mac", dir->name)) { + // if (dir->argc != 1) { + // fprintf(stderr, "`mac` directive accepts only 1 argument\n"); + // exit(1); + // } + // printf(" set mac: %s\n", dir->argv[0]); + // } + + else if (!strcasecmp("route", dir->name)) { + dir = cfg_parse_route(fd, dir, user); + if (!dir) continue; + goto cfg_parse_router_reparse; + } + + else if (!strcasecmp("redistribute", dir->name)) { + dir = cfg_parse_redistribute(fd, dir, user); + if (!dir) continue; + goto cfg_parse_router_reparse; + } + + + else { + // unknown directive + break; + } + + } + + // TODO: store router in actual config + + return dir; +} diff --git a/src/daemon/router/config.h b/src/daemon/router/config.h @@ -0,0 +1,10 @@ +#ifndef __PMLAG_DAEMON_ROUTER_CONFIG_H__ +#define __PMLAG_DAEMON_ROUTER_CONFIG_H__ + +#include <stdio.h> + +#include "finwo/cnfparse.h" + +struct cnf_directive * cfg_parse_router(FILE *fd, struct cnf_directive *dir, void *user); + +#endif // __PMLAG_DAEMON_ROUTER_CONFIG_H__ diff --git a/src/daemon/router/setup.c b/src/daemon/router/setup.c @@ -0,0 +1,8 @@ +#include "util/config.h" + +#include "setup.h" +#include "config.h" + +void daemon_router_setup() { + cfg_register_directive("router", cfg_parse_router); +} diff --git a/src/daemon/router/setup.h b/src/daemon/router/setup.h @@ -0,0 +1,6 @@ +#ifndef __PMLAG_DAEMON_ROUTER_SETUP_H__ +#define __PMLAG_DAEMON_ROUTER_SETUP_H__ + +void daemon_router_setup(); + +#endif // __PMLAG_DAEMON_ROUTER_SETUP_H__ diff --git a/src/main.c b/src/main.c @@ -11,7 +11,10 @@ extern "C" { #include "cofyc/argparse.h" -#include "util/config-root.h" +#include "util/config.h" + +#include "daemon/bond/setup.h" +#include "daemon/router/setup.h" static const char *const usage[] = { __NAME " [options]", @@ -37,6 +40,10 @@ int main(int argc, const char **argv) { OPT_END(), }; + // Initialize components + daemon_bond_setup(); + daemon_router_setup(); + // Parse command line arguments struct argparse argparse; argparse_init(&argparse, options, usage, 0); diff --git a/src/util/config-root.c b/src/util/config-root.c @@ -1,208 +0,0 @@ -#include <glob.h> -#include <libgen.h> -#include <stdlib.h> -#include <string.h> -#include <strings.h> -#include <unistd.h> - -#include "config-root.h" - -#define CFG_MAX_REG 256 - -static int handler_count = 0; -static const char *handler_name[CFG_MAX_REG]; -static cfg_directive_fn handler_fn[CFG_MAX_REG]; - -void cfg_register_directive(const char *name, cfg_directive_fn fn) { - handler_name[handler_count] = name; - handler_fn [handler_count] = fn; - handler_count++; -} - -int cfg_parse(const char *wd, FILE *fd, void *user) { - struct cnf_directive *dir = NULL; - glob_t globbuf; - int globflags; - int i; - - char *strtmp = NULL; - FILE *nfd; - - for(;;) { - if (dir) cnf_directive_free(dir); - dir = cnf_directive_read(fd); - if (!dir) break; // EOF = done - -cfg_parse_reparse: - - // Core handlers - if (!strcasecmp("include", dir->name)) { - globflags = GLOB_ERR; - for ( i = 0 ; i < dir->argc ; i++ ) { - strtmp = malloc(snprintf(NULL, 0, "%s/%s", wd, dir->argv[i])+1); - sprintf(strtmp, "%s/%s", wd, dir->argv[i]); - glob(strtmp, globflags, NULL, &globbuf); - free(strtmp); - globflags = GLOB_ERR | GLOB_APPEND; - } - for( i = 0 ; i < globbuf.gl_pathc ; i++ ) { - strtmp = calloc(strlen(globbuf.gl_pathv[i])+1, 1); - strcpy(strtmp, globbuf.gl_pathv[i]); - dirname(strtmp); - nfd = fopen(globbuf.gl_pathv[i], "r"); - if (!nfd) { - perror("Could not open config file for reading"); - return CFG_RET_ERROR; - } - if (cfg_parse(strtmp, nfd, user) < 0) { - fprintf(stderr, "Error during reading configuration from %s\n", globbuf.gl_pathv[i]); - return CFG_RET_ERROR; - } - fclose(nfd); - free(strtmp); - } - globfree(&globbuf); - continue; - } - - // Dynamic handlers - for(i = 0 ; i < handler_count ; i++) { - if (!strcasecmp(handler_name[i], dir->name)) { - dir = handler_fn[i](fd, dir, user); - if (dir) goto cfg_parse_reparse; - goto cfg_parse_cleanup; - } - } - - // Here = not found - fprintf(stderr, "Unknown directive: %s\n", dir->name); - return CFG_RET_ERROR; - } - - // Cleanup here -cfg_parse_cleanup: - if (dir) cnf_directive_free(dir); - - return CFG_RET_OK; -} - -// #include <stdio.h> -// #include <stdlib.h> -// #include <string.h> - -// #include "config.h" - -// #include "benhoyt/inih.h" -// #include "finwo/mindex.h" - -// int mindex_bond_cmp(const void *a, const void *b, void *udata) { -// (void)udata; -// const struct pmlag_configuration_bond *_a = a; -// const struct pmlag_configuration_bond *_b = b; -// return strcmp(_a->name, _b->name); -// } - -// void mindex_bond_purge(void *item, void *udata) { -// struct pmlag_configuration_bond *bond = item; -// (void)udata; -// if (!item) return; -// if (bond->name) free(bond->name); -// } - -// #ifndef MIN -// #define MIN(a,b) ((a)<(b)?(a):(b)) -// #endif - -// static int config_load_handler( -// void *user, -// const char *section, -// const char *name, -// const char *value -// ) { -// // struct pmlag_bond *bond = NULL; -// // struct pmlag_iface *iface = NULL; -// // int bond_index = 0; -// // int iface_index = 0; -// struct pmlag_configuration* config = (struct pmlag_configuration *) user; - -// // Detect invalid entries -// int i, l; -// for( i = 0, l = strlen(name) ; i < l ; i++ ) { -// if (name[i] == 0x5F ) continue; // '_' -// if (name[i] >= 0x30 && name[i] <= 0x39) continue; // 0-9 -// if (name[i] >= 0x41 && name[i] <= 0x5A) continue; // A-Z -// if (name[i] >= 0x61 && name[i] <= 0x7A) continue; // a-z -// return 0; // Reject -// } - -// // Strip # comments from values -// char *found_comment = strstr(value, "#"); -// if (found_comment) { -// for(; found_comment > (value + 1) ;) { -// if ( *(found_comment) >= 0x21 && *(found_comment-1) <= 0x7E ) break; -// found_comment--; -// } -// *found_comment = 0x00; -// } - -// // Find or create bond -// struct pmlag_configuration_bond *config_bond = mindex_get(config->bonds, (&(struct pmlag_configuration_bond){ .name = (char *)section })); -// if (!config_bond) { -// config_bond = calloc(1, sizeof(struct pmlag_configuration_bond)); -// config_bond->name = strdup(section); -// mindex_set(config->bonds, config_bond); -// } - -// // // Find the bond -// // struct pmlag_configuration_bond *config_bond = NULL; -// // for( i = 0 ; i < config->bond_len ; i++ ) { -// // if (!strcmp(config->bonds[i].name, section)) { -// // config_bond = &(config->bonds[i]); -// // break; -// // } -// // } -// // printf("%s:%d\n", __FILE__, __LINE__); -// // // Build new bond if missing -// // if (!config_bond) { -// // // Expand array size if needed -// // if ((config->bond_len+1) > config->bond_cap) { -// // config->bond_cap = MIN(1, config->bond_cap*2); -// // config->bonds = realloc(config->bonds, config->bond_cap * sizeof(struct pmlag_configuration_bond)); -// // } -// // // Append new entry to list -// // memset(&(config->bonds[config->bond_len]), 0, sizeof(struct pmlag_configuration_bond)); -// // config_bond = &(config->bonds[config->bond_len]); -// // config->bond_len++; -// // } - -// // Detect # comments and remove them - -// return 1; -// } - -// struct pmlag_configuration * config_load(char * filepath, struct pmlag_configuration *config) { -// // Load config, entry-by-entry -// if (!config) { -// config = calloc(1, sizeof(struct pmlag_configuration)); -// } -// if (!config->bonds) { -// config->bonds = mindex_init(mindex_bond_cmp, mindex_bond_purge, NULL); -// } - -// if (ini_parse(filepath, config_load_handler, config) < 0) { -// fprintf(stderr, "Can not load %s\n", filepath); -// return NULL; -// } - -// printf("bond_len: %ld\n", mindex_length(config->bonds)); -// printf("\n"); -// printf("bonds:\n"); -// int l = mindex_length(config->bonds); -// for(int i = 0 ; i < l ; i++) { -// struct pmlag_configuration_bond *bond = mindex_nth(config->bonds, i); -// printf(" - %s\n", bond->name); -// } -// printf("\n"); - -// return config; -// } diff --git a/src/util/config-root.h b/src/util/config-root.h @@ -1,15 +0,0 @@ -#ifndef __PMLAG_UTIL_CONFIG_ROOT_H__ -#define __PMLAG_UTIL_CONFIG_ROOT_H__ - -#include <stdio.h> - -#include "finwo/cnfparse.h" - -#define CFG_RET_ERROR -1 -#define CFG_RET_OK 0 - -typedef struct cnf_directive * (*cfg_directive_fn)(FILE *fd, struct cnf_directive *dir, void *user); -void cfg_register_directive(const char *name, cfg_directive_fn fn); -int cfg_parse(const char *wd, FILE *fd, void *user); - -#endif // __PMLAG_UTIL_CONFIG_ROOT_H__ diff --git a/src/util/config.c b/src/util/config.c @@ -0,0 +1,209 @@ +#include <glob.h> +#include <libgen.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <unistd.h> + +#include "config.h" + +#define CFG_MAX_REG 256 + +static int handler_count = 0; +static const char *handler_name[CFG_MAX_REG]; +static cfg_directive_fn handler_fn[CFG_MAX_REG]; + +void cfg_register_directive(const char *name, cfg_directive_fn fn) { + handler_name[handler_count] = name; + handler_fn [handler_count] = fn; + handler_count++; +} + +int cfg_parse(const char *wd, FILE *fd, void *user) { + struct cnf_directive *dir = NULL; + glob_t globbuf; + int globflags; + int i; + + char *strtmp = NULL; + FILE *nfd; + + for(;;) { + if (dir) cnf_directive_free(dir); + dir = cnf_directive_read(fd); + if (!dir) break; // EOF = done + +cfg_parse_reparse: + + // Core handlers + if (!strcasecmp("include", dir->name)) { + globflags = GLOB_ERR; + for ( i = 0 ; i < dir->argc ; i++ ) { + strtmp = malloc(snprintf(NULL, 0, "%s/%s", wd, dir->argv[i])+1); + sprintf(strtmp, "%s/%s", wd, dir->argv[i]); + glob(strtmp, globflags, NULL, &globbuf); + free(strtmp); + globflags = GLOB_ERR | GLOB_APPEND; + } + for( i = 0 ; i < globbuf.gl_pathc ; i++ ) { + strtmp = calloc(strlen(globbuf.gl_pathv[i])+1, 1); + strcpy(strtmp, globbuf.gl_pathv[i]); + dirname(strtmp); + nfd = fopen(globbuf.gl_pathv[i], "r"); + if (!nfd) { + perror("Could not open config file for reading"); + return CFG_RET_ERROR; + } + if (cfg_parse(strtmp, nfd, user) < 0) { + fprintf(stderr, "Error during reading configuration from %s\n", globbuf.gl_pathv[i]); + return CFG_RET_ERROR; + } + fclose(nfd); + free(strtmp); + } + globfree(&globbuf); + continue; + } + + // Dynamic handlers + for(i = 0 ; i < handler_count ; i++) { + if (!strcasecmp(handler_name[i], dir->name)) { + dir = handler_fn[i](fd, dir, user); + if (dir) goto cfg_parse_reparse; + break; + } + } + + if (i == handler_count) { + // Here = not found + fprintf(stderr, "Unknown directive: %s\n", dir->name); + return CFG_RET_ERROR; + } + } + + // Cleanup here + if (dir) cnf_directive_free(dir); + + return CFG_RET_OK; +} + +// #include <stdio.h> +// #include <stdlib.h> +// #include <string.h> + +// #include "config.h" + +// #include "benhoyt/inih.h" +// #include "finwo/mindex.h" + +// int mindex_bond_cmp(const void *a, const void *b, void *udata) { +// (void)udata; +// const struct pmlag_configuration_bond *_a = a; +// const struct pmlag_configuration_bond *_b = b; +// return strcmp(_a->name, _b->name); +// } + +// void mindex_bond_purge(void *item, void *udata) { +// struct pmlag_configuration_bond *bond = item; +// (void)udata; +// if (!item) return; +// if (bond->name) free(bond->name); +// } + +// #ifndef MIN +// #define MIN(a,b) ((a)<(b)?(a):(b)) +// #endif + +// static int config_load_handler( +// void *user, +// const char *section, +// const char *name, +// const char *value +// ) { +// // struct pmlag_bond *bond = NULL; +// // struct pmlag_iface *iface = NULL; +// // int bond_index = 0; +// // int iface_index = 0; +// struct pmlag_configuration* config = (struct pmlag_configuration *) user; + +// // Detect invalid entries +// int i, l; +// for( i = 0, l = strlen(name) ; i < l ; i++ ) { +// if (name[i] == 0x5F ) continue; // '_' +// if (name[i] >= 0x30 && name[i] <= 0x39) continue; // 0-9 +// if (name[i] >= 0x41 && name[i] <= 0x5A) continue; // A-Z +// if (name[i] >= 0x61 && name[i] <= 0x7A) continue; // a-z +// return 0; // Reject +// } + +// // Strip # comments from values +// char *found_comment = strstr(value, "#"); +// if (found_comment) { +// for(; found_comment > (value + 1) ;) { +// if ( *(found_comment) >= 0x21 && *(found_comment-1) <= 0x7E ) break; +// found_comment--; +// } +// *found_comment = 0x00; +// } + +// // Find or create bond +// struct pmlag_configuration_bond *config_bond = mindex_get(config->bonds, (&(struct pmlag_configuration_bond){ .name = (char *)section })); +// if (!config_bond) { +// config_bond = calloc(1, sizeof(struct pmlag_configuration_bond)); +// config_bond->name = strdup(section); +// mindex_set(config->bonds, config_bond); +// } + +// // // Find the bond +// // struct pmlag_configuration_bond *config_bond = NULL; +// // for( i = 0 ; i < config->bond_len ; i++ ) { +// // if (!strcmp(config->bonds[i].name, section)) { +// // config_bond = &(config->bonds[i]); +// // break; +// // } +// // } +// // printf("%s:%d\n", __FILE__, __LINE__); +// // // Build new bond if missing +// // if (!config_bond) { +// // // Expand array size if needed +// // if ((config->bond_len+1) > config->bond_cap) { +// // config->bond_cap = MIN(1, config->bond_cap*2); +// // config->bonds = realloc(config->bonds, config->bond_cap * sizeof(struct pmlag_configuration_bond)); +// // } +// // // Append new entry to list +// // memset(&(config->bonds[config->bond_len]), 0, sizeof(struct pmlag_configuration_bond)); +// // config_bond = &(config->bonds[config->bond_len]); +// // config->bond_len++; +// // } + +// // Detect # comments and remove them + +// return 1; +// } + +// struct pmlag_configuration * config_load(char * filepath, struct pmlag_configuration *config) { +// // Load config, entry-by-entry +// if (!config) { +// config = calloc(1, sizeof(struct pmlag_configuration)); +// } +// if (!config->bonds) { +// config->bonds = mindex_init(mindex_bond_cmp, mindex_bond_purge, NULL); +// } + +// if (ini_parse(filepath, config_load_handler, config) < 0) { +// fprintf(stderr, "Can not load %s\n", filepath); +// return NULL; +// } + +// printf("bond_len: %ld\n", mindex_length(config->bonds)); +// printf("\n"); +// printf("bonds:\n"); +// int l = mindex_length(config->bonds); +// for(int i = 0 ; i < l ; i++) { +// struct pmlag_configuration_bond *bond = mindex_nth(config->bonds, i); +// printf(" - %s\n", bond->name); +// } +// printf("\n"); + +// return config; +// } diff --git a/src/util/config.h b/src/util/config.h @@ -0,0 +1,15 @@ +#ifndef __PMLAG_UTIL_CONFIG_H__ +#define __PMLAG_UTIL_CONFIG_H__ + +#include <stdio.h> + +#include "finwo/cnfparse.h" + +#define CFG_RET_ERROR -1 +#define CFG_RET_OK 0 + +typedef struct cnf_directive * (*cfg_directive_fn)(FILE *fd, struct cnf_directive *dir, void *user); +void cfg_register_directive(const char *name, cfg_directive_fn fn); +int cfg_parse(const char *wd, FILE *fd, void *user); + +#endif // __PMLAG_UTIL_CONFIG_H__ diff --git a/target/common/Makefile b/target/common/Makefile @@ -6,6 +6,7 @@ TARGET?= SRC:= SRC+=$(wildcard src/*.c) SRC+=$(wildcard src/*/*.c) +SRC+=$(wildcard src/*/*/*.c) CFLAGS?=-Wall -s -O2