From 61e0cc19c9b3794b7db4cdda856fe3f47f29a214 Mon Sep 17 00:00:00 2001 From: Lon Hohberger Date: Mon, 17 Aug 2009 16:53:58 -0400 Subject: [PATCH] Integrate config file processing Signed-off-by: Lon Hohberger --- Makefile | 2 + common/options.c | 2 +- config/Makefile | 49 ++++++++ config/config-stack.h | 32 +++++ config/config.l | 104 ++++++++++++++++ config/config.y | 104 ++++++++++++++++ config/example.conf | 26 ++++ config/simpleconfig.c | 269 ++++++++++++++++++++++++++++++++++++++++ config/simpleconfig.h | 49 ++++++++ include/server_plugin.h | 2 +- include/simpleconfig.h | 49 ++++++++ server/Makefile | 6 +- server/libvirt.c | 12 +- server/main.c | 51 +++++++- server/mcast.c | 1 + server/plugin.c | 5 +- 16 files changed, 749 insertions(+), 14 deletions(-) create mode 100644 config/Makefile create mode 100644 config/config-stack.h create mode 100644 config/config.l create mode 100644 config/config.y create mode 100644 config/example.conf create mode 100644 config/simpleconfig.c create mode 100644 config/simpleconfig.h create mode 100644 include/simpleconfig.h diff --git a/Makefile b/Makefile index c95bbaf..19f9a69 100644 --- a/Makefile +++ b/Makefile @@ -12,11 +12,13 @@ all: + make -C config make -C common make -C client make -C server clean: + make -C config clean make -C common clean make -C client clean make -C server clean diff --git a/common/options.c b/common/options.c index 38dd48b..d50f5b0 100644 --- a/common/options.c +++ b/common/options.c @@ -334,7 +334,7 @@ static struct arg_info _arg_info[] = { "IP port (default=1229)", assign_port }, - { 'I', "-I ", "multicast_address", + { 'I', "-I ", "interface", "Network interface name to listen on", assign_interface }, diff --git a/config/Makefile b/config/Makefile new file mode 100644 index 0000000..1161625 --- /dev/null +++ b/config/Makefile @@ -0,0 +1,49 @@ +############################################################################### +############################################################################### +## +## Copyright (C) 2006 Red Hat, Inc. +## +## This copyrighted material is made available to anyone wishing to use, +## modify, copy, or redistribute it subject to the terms and conditions +## of the GNU General Public License v.2. +## +############################################################################### +############################################################################### + +include ../Makefile.top + +TARGETS=libsimpleconfig.a + +libsimpleconfig_a_SOURCE= config.tab.c \ + config.c simpleconfig.c + +INCLUDES=-I../include \ + -I/usr/include/openais -I/usr/include/libvirt \ + -I/usr/include/nss3 -I/usr/include/nspr4 \ + -I../../../cman/lib -I../../../ccs/lib -I/usr/include/libxml2 \ + -I/usr/include/libvirt + +CFLAGS+=-DFENCE_RELEASE_NAME=\"devel\" -Wno-unused + +LIBS+=-L../../../cman/lib -L../../../ccs/lib -L${libdir}/openais \ + -L../../../dlm/lib -lnss3 -lxml2 + +all: ${TARGETS} + +libsimpleconfig.a: ${libsimpleconfig_a_SOURCE:.c=.o} + ar rc $@ $^ + +config.tab.c config.tab.h: config.y + bison -d $^ + +config.c: config.tab.h config.l + flex -oconfig.c config.l + +%.o: %.c + gcc $(CFLAGS) -c -o $@ $^ $(INCLUDES) + +clean: + rm -f ${TARGETS} *~ *.o testprog config.tab.c config.tab.h config.c + +install: + diff --git a/config/config-stack.h b/config/config-stack.h new file mode 100644 index 0000000..3781cd9 --- /dev/null +++ b/config/config-stack.h @@ -0,0 +1,32 @@ +#ifndef _CONFIG_STACK_H +#define _CONFIG_STACK_H + +int yyparse (void); +extern FILE *yyin; + +struct value { + char *id; + char *val; + struct value *next; +}; + + +struct node { + char *id; + struct node *nodes; + struct value *values; + struct node *next; +}; + + +struct parser_context { + struct value *val_list; + struct node *node_list; + struct parser_context *next; +}; + +extern struct value *val_list; +extern struct node *node_list; +extern struct parser_context *context_stack; + +#endif diff --git a/config/config.l b/config/config.l new file mode 100644 index 0000000..a077ec7 --- /dev/null +++ b/config/config.l @@ -0,0 +1,104 @@ +%{ +#include +#include +#include +#include "config-stack.h" +#include "config.tab.h" +#include "simpleconfig.h" + +struct value *val_list = NULL; +struct node *node_list = NULL; +struct parser_context *context_stack = NULL; + +int _line_count = 1; + +%} +%% +[\n] { + ++_line_count; +} + +[ \t]* {} + +\#[^\n]* {} + +"{" { + struct parser_context *c = NULL; + //printf("obrace\n"); + + c = malloc(sizeof(*c)); + assert(c); + + c->next = context_stack; + c->val_list = val_list; + c->node_list = node_list; + + context_stack = c; + val_list = NULL; + node_list = NULL; + + return T_OBRACE; +} + +"}" { + return T_CBRACE; +} + +";" { + return T_SEMI; +} + +"=" { + return T_EQ; +} + +[^ \t{};=\"\n]+ { + yylval.sval = strdup(yytext); + return T_ID; +} + +\"[^\"]+\" { + yylval.sval = strdup(yytext+1); + yylval.sval[strlen(yytext)-2] = 0; + return T_VAL; +} + +%% +void +reset_vars(void) +{ + _line_count = 1; +} + + +int +yywrap(void) +{ + return 1; +} + + +#ifdef STANDALONE +int +main(int argc, char *argv[]) +{ + char value[80]; + config_object_t *c = NULL; + + yyout = fopen("/dev/null","w"); + + c = sc_init(); + sc_parse(c, NULL); + sc_dump(c, stdout); + if (argc >= 2) { + if (sc_get(c, argv[1], value, sizeof(value)) == 0) + printf("%s = %s\n", argv[1], value); + else + printf("Not found\n"); + } + + sc_release(c); + + return 0; +} +#endif diff --git a/config/config.y b/config/config.y new file mode 100644 index 0000000..4b81963 --- /dev/null +++ b/config/config.y @@ -0,0 +1,104 @@ +%{ +#include +#include +#include +#include +#include "config-stack.h" + +extern int yylex (void); +int yyerror(const char *foo); + +static int +value_add(char *id, char *val, struct value **list) +{ + struct value *v; + + v = malloc(sizeof(*v)); + assert(v); + + memset(v, 0, sizeof(*v)); + v->id = id; + v->val = val; + //snprintf(v->id, sizeof(v->id), "%s", id); + //snprintf(v->val, sizeof(v->val), "%s", val); + //printf("add %s %s on to %p\n", id, val, *list); + + v->next = *list; + *list = v; + + //printf("new list %p\n", *list); + return 0; +} + + +static int +node_add(char *id, struct value *vallist, struct node *nodelist, + struct node **list) +{ + struct node *n; + + n = malloc(sizeof(*n)); + assert(n); + + //printf("nodes %p values %p\n", nodelist, vallist); + + memset(n, 0, sizeof(*n)); + //snprintf(n->id, sizeof(n->id), "%s", id); + n->id = id; /* malloc'd during parsing */ + n->values = vallist; + n->nodes = nodelist; + n->next = *list; + *list = n; + + return 0; +} + +%} + +%token T_ID +%token T_VAL +%token T_OBRACE T_CBRACE T_EQ T_SEMI + +%start stuff + +%union { + char *sval; + int ival; +} + +%% +node: + T_ID T_OBRACE stuff T_CBRACE { + struct parser_context *c = NULL; + + c = context_stack; + node_add($1, val_list, node_list, &c->node_list); + val_list = c->val_list; + node_list = c->node_list; + context_stack = c->next; + + free(c); + } + | + T_ID T_OBRACE T_CBRACE /* Empty config block */ + ; + +stuff: + node stuff | assign stuff | node | assign + ; + +assign: + T_ID T_EQ T_VAL T_SEMI { + value_add($1, $3, &val_list); + } + ; +%% + +extern int _line_count; + +int +yyerror(const char *foo) +{ + printf("%s on line %d\n", foo, _line_count); + return 0; +} diff --git a/config/example.conf b/config/example.conf new file mode 100644 index 0000000..4cdcf66 --- /dev/null +++ b/config/example.conf @@ -0,0 +1,26 @@ +fence_virtd { + debug ="99"; + listener = "multicast"; + backend = "libvirt"; +} + +listeners { + multicast { + key_file = "/etc/cluster/fence_xvm.key"; + ip_family = "ipv4"; + multicast_address = "225.0.0.14"; + interface = "virbr0"; + hash = "sha256"; + auth = "sha256"; + } + + serial { + directory = "/var/run/fence_virtd"; + } +} + +backends { + libvirt { + uri = "qemu:///system"; + } +} diff --git a/config/simpleconfig.c b/config/simpleconfig.c new file mode 100644 index 0000000..f358d91 --- /dev/null +++ b/config/simpleconfig.c @@ -0,0 +1,269 @@ +#include +#include +#include +#include +#include "simpleconfig.h" +#include "config-stack.h" + +static pthread_mutex_t parser_mutex = PTHREAD_MUTEX_INITIALIZER; + +static int +print_value(struct value *v, int depth, FILE *fp) +{ + int x; + for (x = 0; x < depth; x++) + fprintf(fp, "\t"); + fprintf(fp, "%s = \"%s\";\n", v->id, v->val); + + return 0; +} + + +static void +_sc_dump_d(struct node *node, int depth, FILE *fp) +{ + struct node *n; + struct value *v; + int x; + + if (!node) { + //printf("Empty node\n"); + return; + } + + for (x = 0; x < depth; x++) + fprintf(fp, "\t"); + fprintf(fp, "%s {\n", node->id); + + for (n = node->nodes; n; n = n->next) { + _sc_dump_d(n, depth+1, fp); + } + + for (v = node->values; v; v = v->next) { + print_value(v, depth+1, fp); + } + + for (x = 0; x < depth; x++) + fprintf(fp, "\t"); + fprintf(fp, "}\n\n"); +} + + +static void +_sc_dump(config_info_t *config, FILE *fp) +{ + struct node *n, *node; + struct value *v, *values; + + if (!config) + return; + + values = ((struct parser_context *)config)->val_list; + node = ((struct parser_context *)config)->node_list; + + for (n = node; n; n = n->next) { + _sc_dump_d(n, 0, fp); + } + + for (v = values; v; v = v->next) { + print_value(v, 0, fp); + } +} + + +static int +free_value(struct value *v) +{ + int x; + + if (v) { + free(v->id); + free(v->val); + free(v); + } + + return 0; +} + + +static void +_sc_free_node(struct node *node) +{ + struct node *n; + struct value *v; + int x; + + if (!node) + return; + + while (node->nodes) { + n = node->nodes; + if (n) { + node->nodes = node->nodes->next; + _sc_free_node(n); + } + } + + while (node->values) { + v = node->values; + node->values = node->values->next; + free_value(v); + } + + free(node->id); + free(node); +} + + +static int +_sc_free(config_info_t *config) +{ + struct node *n, *nlist; + struct value *v, *vlist; + + if (!config) + return -1; + + vlist = ((struct parser_context *)config)->val_list; + nlist = ((struct parser_context *)config)->node_list; + + while (nlist) { + n = nlist; + nlist = nlist->next; + _sc_free_node(n); + } + + ((struct parser_context *)config)->node_list = NULL; + + while (vlist) { + v = vlist; + vlist = vlist->next; + free_value(v); + } + + ((struct parser_context *)config)->val_list = NULL; + + free(config); + + return 0; +} + + +static int +_sc_get(config_info_t *config, const char *key, char *value, size_t valuesz) +{ + char buf[1024]; + struct node *n, *node = ((struct parser_context *)config)->node_list; + struct value *v, *values = ((struct parser_context *)config)->val_list; + char *ptr; + char *slash; + int found; + + ptr = (char *)key; + while ((slash = strchr(ptr, '/'))) { + memset(buf, 0, sizeof(buf)); + strncpy(buf, ptr, (slash - ptr)); + ptr = ++slash; + + found = 0; + + for (n = node; n; n = n->next) { + if (!strcasecmp(n->id, buf)) { + node = n->nodes; + values = n->values; + found = 1; + break; + } + } + + if (!found) + return 1; + } + + if (ptr[0] == '@') { + ++ptr; + found = 0; + + for (v = values; v; v = v->next) { + if (!strcasecmp(v->id, ptr)) { + snprintf(value, valuesz, "%s", v->val); + return 0; + } + } + } + + return 1; +} + + +static int +_sc_parse(const char *filename, config_info_t **config) +{ + struct parser_context *c; + FILE *fp = NULL; + int ret = 0; + + if (!config) + return -1; + + pthread_mutex_lock(&parser_mutex); + if (filename) { + fp = fopen(filename, "r"); + yyin = fp; + if (!fp) + return -1; + } + + ret = yyparse(); + + if (!ret) { + c = malloc(sizeof(*c)); + if (!c) + return -1; + c->node_list = node_list; + c->val_list = val_list; + c->next = NULL; + val_list = NULL; + node_list = NULL; + *config = (config_info_t *)c; + } + + if (fp) + fclose(fp); + + pthread_mutex_unlock(&parser_mutex); + + return ret; +} + + +static const config_object_t sc_object = { + .get = _sc_get, + .parse = _sc_parse, + .free = _sc_free, + .dump = _sc_dump, + .info = NULL +}; + + +config_object_t * +sc_init(void) +{ + config_object_t *o; + + o = malloc(sizeof(*o)); + if (!o) + return NULL; + memset(o, 0, sizeof(*o)); + memcpy(o, &sc_object, sizeof(*o)); + + return o; +} + + +void +sc_release(config_object_t *c) +{ + sc_free(c); + free(c); +} diff --git a/config/simpleconfig.h b/config/simpleconfig.h new file mode 100644 index 0000000..6a65b3b --- /dev/null +++ b/config/simpleconfig.h @@ -0,0 +1,49 @@ +#ifndef _SIMPLECONFIG_H +#define _SIMPLECONFIG_H + +typedef void config_info_t; + +typedef int (*config_get_t)(config_info_t *config, const char *key, + char *value, size_t valuesz); +typedef int (*config_parse_t)(const char *filename, config_info_t **config); +typedef int (*config_free_t)(config_info_t *config); +typedef void (*config_dump_t)(config_info_t *config, FILE *fp); + +/* + * We use an abstract object here so we do not have to link loadable + * modules against the configuration library. + */ + +typedef struct { + config_get_t get; + config_parse_t parse; + config_free_t free; + config_dump_t dump; + config_info_t *info; +} config_object_t; + +/* + * These macros may be called from within a loadable module + */ +#define sc_get(obj, key, value, valuesz) \ + obj->get(obj->info, key, value, valuesz) +#define sc_parse(obj, filename) \ + obj->parse(filename, &obj->info) +#define sc_free(obj) \ + obj->free(obj->info) +#define sc_dump(obj, fp) \ + obj->dump(obj->info, fp) + +/* + * Do not call the below functions from loadable modules. Doing so + * requires linking the configuration library in to the modules, which + * is what we want to avoid. + */ + +/* Returns a copy of our simple config object */ +config_object_t *sc_init(void); + +/* Frees a previously-allocated copy of our simple config object */ +void sc_release(config_object_t *c); + +#endif diff --git a/include/server_plugin.h b/include/server_plugin.h index b63419f..ac70e32 100644 --- a/include/server_plugin.h +++ b/include/server_plugin.h @@ -49,7 +49,7 @@ typedef int (*fence_status_callback)(const char *vm_name, is responding to requests. */ typedef int (*fence_devstatus_callback)(void *priv); -typedef int (*fence_init_callback)(srv_context_t *c); +typedef int (*fence_init_callback)(srv_context_t *c, config_object_t *config); typedef int (*fence_cleanup_callback)(srv_context_t c); typedef struct _fence_callbacks { diff --git a/include/simpleconfig.h b/include/simpleconfig.h new file mode 100644 index 0000000..6a65b3b --- /dev/null +++ b/include/simpleconfig.h @@ -0,0 +1,49 @@ +#ifndef _SIMPLECONFIG_H +#define _SIMPLECONFIG_H + +typedef void config_info_t; + +typedef int (*config_get_t)(config_info_t *config, const char *key, + char *value, size_t valuesz); +typedef int (*config_parse_t)(const char *filename, config_info_t **config); +typedef int (*config_free_t)(config_info_t *config); +typedef void (*config_dump_t)(config_info_t *config, FILE *fp); + +/* + * We use an abstract object here so we do not have to link loadable + * modules against the configuration library. + */ + +typedef struct { + config_get_t get; + config_parse_t parse; + config_free_t free; + config_dump_t dump; + config_info_t *info; +} config_object_t; + +/* + * These macros may be called from within a loadable module + */ +#define sc_get(obj, key, value, valuesz) \ + obj->get(obj->info, key, value, valuesz) +#define sc_parse(obj, filename) \ + obj->parse(filename, &obj->info) +#define sc_free(obj) \ + obj->free(obj->info) +#define sc_dump(obj, fp) \ + obj->dump(obj->info, fp) + +/* + * Do not call the below functions from loadable modules. Doing so + * requires linking the configuration library in to the modules, which + * is what we want to avoid. + */ + +/* Returns a copy of our simple config object */ +config_object_t *sc_init(void); + +/* Frees a previously-allocated copy of our simple config object */ +void sc_release(config_object_t *c); + +#endif diff --git a/server/Makefile b/server/Makefile index ff644f5..85d4d2a 100644 --- a/server/Makefile +++ b/server/Makefile @@ -29,14 +29,16 @@ CFLAGS+=-DFENCE_RELEASE_NAME=\"devel\" -D_MODULE LIBS+=-L/usr/lib64/openais -lnss3 -lxml2 -lSaCkpt -lccs -lvirt -lcman \ -L../common -lfence_virt + +MAIN_LIBS=-L../config -lsimpleconfig all: ${TARGETS} fence_virtd: ${fence_virtd_SOURCES:.c=.o} - gcc -o $@ $^ $(LIBS) -L../common -lfence_virt + gcc -o $@ $^ $(LIBS) $(MAIN_LIBS) libvirt.so: ${libvirt_so_SOURCES:.c=.o} - gcc -o $@ $^ $(LIBS) -shared -L../common -lvirt + gcc -o $@ $^ $(LIBS) -shared %.o: %.c gcc $(CFLAGS) -c -o $@ $^ $(INCLUDES) diff --git a/server/libvirt.c b/server/libvirt.c index 6cf24d5..8a32e24 100644 --- a/server/libvirt.c +++ b/server/libvirt.c @@ -44,6 +44,7 @@ #include #include //#include +#include #include /* Local includes */ @@ -277,11 +278,18 @@ libvirt_reboot(const char *vm_name, void *priv) } static int -libvirt_init(srv_context_t *c) +libvirt_init(srv_context_t *c, config_object_t *config) { virConnectPtr vp; + char value[256]; + char *uri = NULL; - vp = virConnectOpen(NULL); + if (sc_get(config, "backends/libvirt/@uri", value, sizeof(value)) == 0) { + uri = value; + printf("Using %s\n", uri); + } + + vp = virConnectOpen(uri); if (!vp) return -1; *c = (void *)vp; diff --git a/server/main.c b/server/main.c index 2856ee6..be9ace2 100644 --- a/server/main.c +++ b/server/main.c @@ -6,6 +6,7 @@ #include /* Local includes */ +#include #include #include @@ -14,13 +15,51 @@ extern fence_callbacks_t libvirt_callbacks; /* should be in a header */ int main(int argc, char **argv) { - const char *plugin_name = "libvirt"; + char val[80]; + config_object_t *config; const plugin_t *p; srv_context_t mcast_context; srv_context_t libvirt_context; /*XXX these should be differently named context types */ + int debug_set = 0; + int opt; - dset(99); + config = sc_init(); + + while ((opt = getopt(argc, argv, "f:d:")) != EOF) { + switch(opt) { + case 'f': + printf("Using %s\n", optarg); + if (sc_parse(config, optarg) != 0) { + printf("Failed to parse %s\n", optarg); + return -1; + } + break; + case 'd': + dset(atoi(optarg)); + debug_set = 1; + break; + default: + break; + } + } + + + if (!debug_set) { + if (sc_get(config, "fence_virtd/@debug", + val, sizeof(val)) == 0) + dset(atoi(val)); + } + + sc_dump(config, stdout); + + if (sc_get(config, "fence_virtd/@backend", val, sizeof(val))) { + printf("Failed to determine backend.\n"); + printf("%s\n", val); + return -1; + } + + printf("Backend plugin: %s\n", val); #ifdef _MODULE if (plugin_load("./libvirt.so") < 0) { @@ -29,13 +68,13 @@ main(int argc, char **argv) #endif plugin_dump(); - p = plugin_find(plugin_name); + p = plugin_find(val); if (!p) { - printf("Could not find plugin \"%s\n", plugin_name); + printf("Could not find plugin \"%s\n", val); } - if (p->init(&libvirt_context) < 0) { - printf("%s failed to initialize\n", plugin_name); + if (p->init(&libvirt_context, config) < 0) { + printf("%s failed to initialize\n", val); return 1; } diff --git a/server/mcast.c b/server/mcast.c index 9d50892..a5ed27d 100644 --- a/server/mcast.c +++ b/server/mcast.c @@ -42,6 +42,7 @@ #include #include #include +#include #include /* Local includes */ diff --git a/server/plugin.c b/server/plugin.c index f055b17..4c9f4d9 100644 --- a/server/plugin.c +++ b/server/plugin.c @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -82,9 +83,9 @@ plugin_find(const char *name) int -plugin_init(const plugin_t *p, srv_context_t *c) +plugin_init(const plugin_t *p, srv_context_t *c, config_object_t *config) { - return p->init(c); + return p->init(c, config); }