diff options
| author | Stef Walter <stef@memberwebs.com> | 2006-01-28 02:52:38 +0000 | 
|---|---|---|
| committer | Stef Walter <stef@memberwebs.com> | 2006-01-28 02:52:38 +0000 | 
| commit | c127605b17195e34a73b7a8c8d401769cdf60795 (patch) | |
| tree | 138853c9c6869d7d76413dbbb3763d7a42423aa4 | |
| parent | fbfb057e8bed90f73850d8e871e4d70e8fa705ce (diff) | |
Move config parser stuff into common directory for use by other binaries.
| -rw-r--r-- | common/compat.c | 51 | ||||
| -rw-r--r-- | common/compat.h | 4 | ||||
| -rw-r--r-- | common/config-parser.c | 270 | ||||
| -rw-r--r-- | common/config-parser.h | 50 | ||||
| -rw-r--r-- | common/usuals.h (renamed from daemon/usuals.h) | 0 | ||||
| -rw-r--r-- | daemon/Makefile.am | 1 | ||||
| -rw-r--r-- | daemon/config.c | 204 | ||||
| -rw-r--r-- | daemon/rrdbotd.c | 50 | ||||
| -rw-r--r-- | daemon/rrdbotd.h | 3 | 
9 files changed, 419 insertions, 214 deletions
| diff --git a/common/compat.c b/common/compat.c index 9d2f53f..0c6c833 100644 --- a/common/compat.c +++ b/common/compat.c @@ -179,3 +179,54 @@ strlcat(char* dst, const char* src, size_t siz)  }  #endif /* HAVE_STRLCAT */ + +#ifndef HAVE_ATEXITV + +typedef void (*voidfunc)(void*); +typedef struct _exit_stack +{ +    voidfunc func; +    void* data; + +    /* We have a list of these beauties */ +    struct _exit_stack* next; +} +exit_stack; + +/* Our exit stack */ +static exit_stack* atexits = NULL; +static int atexit_registered = 0; + +static void +atexit_do_stack(void) +{ +    exit_stack* next; +    for(; atexits; atexits = next) +    { +        next = atexits->next; +        (atexits->func)(atexits->data); +        free(atexits); +    } +} + +void +atexitv(voidfunc func, void* data) +{ +    exit_stack* ae; + +    ASSERT(func); + +    ae = (exit_stack*)calloc(1, sizeof(exit_stack)); +    if(ae) +    { +        ae->func = func; +        ae->data = data; +        ae->next = atexits; +        atexits = ae; + +        if(!atexit_registered) +            atexit(atexit_do_stack); +    } +} + +#endif /* HAVE_ATEXITV */ diff --git a/common/compat.h b/common/compat.h index 17967f4..7ef2f50 100644 --- a/common/compat.h +++ b/common/compat.h @@ -69,4 +69,8 @@ char* strtrim(char* data);  int strtob(const char* str);  #endif +#ifndef HAVE_ATEXITV +void atexitv(void (*func)(void*), void* data); +#endif +  #endif /* __COMPAT_H__ */ diff --git a/common/config-parser.c b/common/config-parser.c new file mode 100644 index 0000000..5c1aa98 --- /dev/null +++ b/common/config-parser.c @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2005, Nate Nielsen + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + *     * Redistributions of source code must retain the above + *       copyright notice, this list of conditions and the + *       following disclaimer. + *     * Redistributions in binary form must reproduce the + *       above copyright notice, this list of conditions and + *       the following disclaimer in the documentation and/or + *       other materials provided with the distribution. + *     * The names of contributors to this software may not be + *       used to endorse or promote products derived from this + *       software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * + * CONTRIBUTORS + *  Nate Nielsen <nielsen@memberwebs.com> + */ + +#include "usuals.h" +#include <errno.h> +#include <unistd.h> +#include <syslog.h> +#include <stdarg.h> +#include <dirent.h> + +#include "config-parser.h" + +static void +errmsg(const char* filename, void* data, const char* msg, ...) +{ +    #define MAX_MSGLEN  1024 +    char buf[MAX_MSGLEN]; +    va_list ap; + +    va_start(ap, msg); +    vsnprintf(buf, MAX_MSGLEN, msg, ap); +    buf[MAX_MSGLEN - 1] = 0; +    cfg_error(filename, buf, data); +    va_end(ap); +} + +/* ----------------------------------------------------------------------------- + * CONFIG PARSER + */ + +static char* +read_config_file(const char* configfile, void* data) +{ +    char* config = NULL; +    FILE* f = NULL; +    long len; + +    ASSERT(configfile); + +    f = fopen(configfile, "r"); +    if(f == NULL) +    { +        errmsg(configfile, data, "couldn't open config file: %s", configfile); +        return NULL; +    } + +    /* Figure out size */ +    if(fseek(f, 0, SEEK_END) == -1 || (len = ftell(f)) == -1 || fseek(f, 0, SEEK_SET) == -1) +    { +        errmsg(configfile, data, "couldn't seek config file: %s", configfile); +        return NULL; +    } + +    if((config = (char*)malloc(len + 2)) == NULL) +    { +        errmsg(configfile, data, "out of memory"); +        return NULL; +    } + +    /* And read in one block */ +    if(fread(config, 1, len, f) != len) +    { +        errmsg(configfile, data, "couldn't read config file: %s", configfile); +        return NULL; +    } + +    fclose(f); + +    /* Null terminate the data */ +    config[len] = '\n'; +    config[len + 1] = 0; + +    /* Remove nasty dos line endings */ +    strcln(config, '\r'); + +    return config; +} + +int +cfg_parse_file(const char* filename, void* data, char** memory) +{ +    char* name = NULL; +    char* value = NULL; +    char* config; +    char* next; +    char* header; +    int ret = -1; +    char* p; +    char* t; +    int pos; + +    ASSERT(filename); + +    config = read_config_file(filename, data); +    next = config; + +    /* Go through lines and process them */ +    while((t = strchr(next, '\n')) != NULL) +    { +        *t = 0; +        p = next; /* Do this before cleaning below */ +        next = t + 1; + +        t = strbtrim(p); + +        /* Continuation line (had spaces at start) */ +        if(p < t && *t) +        { +            if(!value) +            { +                errmsg(filename, data, "%s: invalid continuation in config: %s", +                       filename, p); +                goto finally; +            } + +            /* Calculate the end of the current value */ +            t = value + strlen(value); +            ASSERT(t < p); + +            /* Continuations are separated by spaces */ +            *t = ' '; +            t++; + +            continue; +        } + +        /* No continuation hand off value if necessary */ +        if(name && value) +        { +            if(cfg_value(filename, header, name, value, data) == -1) +                goto finally; +        } + +        name = NULL; +        value = NULL; + +        /* Empty lines / comments at start / comments without continuation */ +        if(!*t || *p == '#') +            continue; + +        /* A header */ +        if(*p == '[') +        { +            t = p + strcspn(p, "]"); +            if(!*t || t == p + 1) +            { +                errmsg(filename, data, "%s: invalid config header: %s", +                       filename, p); +                goto finally; +            } + +            *t = 0; +            header = strtrim(p + 1); +            continue; +        } + +        /* Look for the break between name = value on the same line */ +        t = p + strcspn(p, ":="); +        if(!*t) +        { +            errmsg(filename, data, "%s: invalid config line: %s", +                   filename, p); +            goto finally; +        } + +        /* Null terminate and split value part */ +        *t = 0; +        t++; + +        name = strtrim(p); +        value = strtrim(t); +    } + +    if(name && value) +    { +        if(cfg_value(filename, header, name, value, data) == -1) +            goto finally; +    } + +    ret = 0; + + +finally: + +    if(!memory || ret != 0) +        free(config); +    else if(memory) +        *memory = config; + +    return ret; +} + +int +cfg_parse_dir(const char* dirname, void* data) +{ +    char olddir[MAXPATHLEN]; +    struct dirent* dire; +    char *memory; +    DIR* dir; + +    ASSERT(dir != NULL); + +    if(!getcwd(olddir, MAXPATHLEN)) +        olddir[0] = 0; + +    if(chdir(dirname) == -1) +        errmsg(NULL, data, "couldn't list config directory: %s", dirname); + +    dir = opendir("."); +    if(!dir) +    { +        errmsg(NULL, data, "couldn't list config directory: %s", dirname); +        return -1; +    } + +    while((dire = readdir(dir)) != NULL) +    { +        if(dire->d_type != DT_REG && dire->d_type != DT_LNK) +            continue; + +        /* Build a happy path name */ +        cfg_parse_file(dire->d_name, data, &memory); + +        /* We call it with blanks after files */ +        if(cfg_value(dire->d_name, NULL, NULL, NULL, data) == -1) +            break; + +        /* Keep the memory around */ +        if(memory) +            atexitv(free, memory); +    } + +    closedir(dir); + +    return 0; +} diff --git a/common/config-parser.h b/common/config-parser.h new file mode 100644 index 0000000..94d96c9 --- /dev/null +++ b/common/config-parser.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2005, Nate Nielsen + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + *     * Redistributions of source code must retain the above + *       copyright notice, this list of conditions and the + *       following disclaimer. + *     * Redistributions in binary form must reproduce the + *       above copyright notice, this list of conditions and + *       the following disclaimer in the documentation and/or + *       other materials provided with the distribution. + *     * The names of contributors to this software may not be + *       used to endorse or promote products derived from this + *       software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * + * CONTRIBUTORS + *  Nate Nielsen <nielsen@memberwebs.com> + */ + +#ifndef __CONFIG_PARSER_H__ +#define __CONFIG_PARSER_H__ + +/* Callbacks must be defined by the caller */ +extern int cfg_value(const char* filename, const char* header, const char* name, +                     char* value, void* data); +extern int cfg_errcallback(const char* filename, const char* errmsg, void* data); + +/* Calling these will call the callbacks above */ +int cfg_parse_dir(const char* dirname, void* data); +int cfg_parse_file(const char* filename, void* data, char** memory); + +#endif /* __CONFIG_PARSER_H__ */ diff --git a/daemon/usuals.h b/common/usuals.h index 5fece3f..5fece3f 100644 --- a/daemon/usuals.h +++ b/common/usuals.h diff --git a/daemon/Makefile.am b/daemon/Makefile.am index fbc275d..dda6ceb 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -7,6 +7,7 @@ rrdbotd_SOURCES = rrdbotd.c rrdbotd.h config.c usuals.h \                  ../common/sock-any.h ../common/sock-any.c \                  ../common/compat.h ../common/compat.c \                  ../common/hash.h ../common/hash.c \ +                ../common/config-parser.h ../common/config-parser.c \                  ../mib/parse.c  rrdbotd_CFLAGS = -I${top_srcdir}/common/ -I${top_srcdir}/bsnmp/ -I${top_srcdir} \                   -DCONF_PREFIX=\"$(sysconfdir)\" -DDATA_PREFIX=\"$(datadir)\" diff --git a/daemon/config.c b/daemon/config.c index 9b38bcb..f45d1f0 100644 --- a/daemon/config.c +++ b/daemon/config.c @@ -41,6 +41,7 @@  #include <unistd.h>  #include <syslog.h>  #include <dirent.h> +#include <string.h>  #include "rrdbotd.h" @@ -53,7 +54,6 @@  typedef struct _config_ctx  {      const char* confname; -    char* configmem;      uint interval;      uint timeout;      rb_item* items; @@ -181,14 +181,10 @@ config_done(config_ctx* ctx)       * This allows all the users of these strings not to worry       * about reallocating or freeing them       */ -    rb_atexit(free, ctx->configmem); -    ctx->configmem = NULL;      /* Clear current config and get ready for next */      ctx->items = NULL;      ctx->interval = 0; - -  }  static void @@ -374,180 +370,66 @@ config_value(const char* header, const char* name, char* value,      }  } -/* ----------------------------------------------------------------------------- - * CONFIG FILES - */ - -static char* -read_config_file(const char* configfile) +void +rb_config_parse()  { -    char* config = NULL; -    FILE* f = NULL; -    long len; - -    ASSERT(configfile); - -    f = fopen(configfile, "r"); -    if(f == NULL) -        err(1, "couldn't open config file: %s", configfile); - -    /* Figure out size */ -    if(fseek(f, 0, SEEK_END) == -1 || (len = ftell(f)) == -1 || fseek(f, 0, SEEK_SET) == -1) -        err(1, "couldn't seek config file: %s", configfile); - -    if((config = (char*)malloc(len + 2)) == NULL) -        errx(1, "out of memory"); - -    /* And read in one block */ -    if(fread(config, 1, len, f) != len) -        err(1, "couldn't read config file: %s", configfile); +    config_ctx ctx; -    fclose(f); +    /* Setup the hash tables properly */ +    g_state.poll_by_key = hsh_create(); +    g_state.host_by_name = hsh_create(); -    /* Null terminate the data */ -    config[len] = '\n'; -    config[len + 1] = 0; +    memset(&ctx, 0, sizeof(ctx)); -    /* Remove nasty dos line endings */ -    strcln(config, '\r'); +    if(cfg_parse_dir(g_state.confdir, &ctx) == -1) +        exit(2); /* message already printed */ -    rb_messagex(LOG_DEBUG, "read config file: %s", configfile); -    return config; +    if(!g_state.polls) +        errx(1, "no config files found in config directory: %s", g_state.confdir);  } -static void -parse_config_file(const char* configfile, config_ctx *ctx) -{ -    char* name = NULL; -    char* value = NULL; -    char* config; -    char* next; -    char* header; -    char* p; -    char* t; -    int pos; - -    config = read_config_file(configfile); -    ctx->configmem = config; -    next = config; - -    /* Go through lines and process them */ -    while((t = strchr(next, '\n')) != NULL) -    { -        *t = 0; -        p = next; /* Do this before cleaning below */ -        next = t + 1; - -        t = strbtrim(p); - -        /* Continuation line (had spaces at start) */ -        if(p < t && *t) -        { -            if(!value) -                errx(2, "%s: invalid continuation in config: %s", -                     ctx->confname, p); - -            /* Calculate the end of the current value */ -            t = value + strlen(value); -            ASSERT(t < p); - -            /* Continuations are separated by spaces */ -            *t = ' '; -            t++; - -            continue; -        } - -        // No continuation hand off value if necessary -        if(name && value) -        { -            rb_messagex(LOG_DEBUG, "config: %s: [%s] %s = %s", -                        ctx->confname, header, name, value); -            config_value(header, name, value, ctx); -        } - -        name = NULL; -        value = NULL; - -        /* Empty lines / comments at start / comments without continuation */ -        if(!*t || *p == '#') -            continue; - -        /* A header */ -        if(*p == '[') -        { -            t = p + strcspn(p, "]"); -            if(!*t || t == p + 1) -                errx(2, "%s: invalid config header: %s", ctx->confname, p); - -            *t = 0; -            header = strtrim(p + 1); -            continue; -        } - -        /* Look for the break between name = value on the same line */ -        t = p + strcspn(p, ":="); -        if(!*t) -            errx(2, "%s: invalid config line: %s", ctx->confname, p); - -        /* Null terminate and split value part */ -        *t = 0; -        t++; - -        name = strtrim(p); -        value = strtrim(t); -    } - -    if(name && value) -    { -        rb_messagex(LOG_DEBUG, "config: %s: [%s] %s = %s", -                    ctx->confname, header, name, value); -        config_value(header, name, value, ctx); -    } - -    config_done(ctx); - -    /* If nobody claimed this memory then we don't need to keep it around */ -    if(ctx->configmem) -        free(ctx->configmem); -    ctx->configmem = NULL; -} +/* ----------------------------------------------------------------------------- + * CONFIG CALLBACKS + */ -void -rb_config_parse() +int +cfg_value(const char* filename, const char* header, const char* name, +          char* value, void* data)  { -    char configfile[MAXPATHLEN]; -    struct dirent* dire; -    config_ctx ctx; -    DIR* dir; +    config_ctx* ctx = (config_ctx*)data; -    /* Setup the hash tables properly */ -    g_state.poll_by_key = hsh_create(); -    g_state.host_by_name = hsh_create(); +    ASSERT(filename); +    ASSERT(ctx); -    dir = opendir(g_state.confdir); -    if(!dir) -        err(1, "couldn't list config directory: %s", g_state.confdir); +    /* A little setup where necessary */ +    if(!ctx->confname) +        ctx->confname = filename; -    while((dire = readdir(dir)) != NULL) +    /* Called like this after each file */ +    if(!header)      { -        if(dire->d_type != DT_REG && dire->d_type != DT_LNK) -            continue; +        config_done(ctx); +        ctx->confname = NULL; +        return 0; +    } -        /* Build a happy path name */ -        snprintf(configfile, MAXPATHLEN, "%s/%s", g_state.confdir, dire->d_name); -        configfile[MAXPATHLEN - 1] = 0; +    ASSERT(ctx->confname); +    ASSERT(name && value && header); -        memset(&ctx, 0, sizeof(ctx)); -        ctx.confname = dire->d_name; +    rb_messagex(LOG_DEBUG, "config: %s: [%s] %s = %s", +                ctx->confname, header, name, value); -        parse_config_file(configfile, &ctx); -    } +    config_value(header, name, value, ctx); -    if(!g_state.polls) -        errx(1, "no config files found in config directory: %s", g_state.confdir); +    return 0; +} -    closedir(dir); +int +cfg_error(const char* filename, const char* errmsg, void* data) +{ +    /* Just exit on errors */ +    errx(2, "%s", errmsg); +    return 0;  }  /* ----------------------------------------------------------------------------- diff --git a/daemon/rrdbotd.c b/daemon/rrdbotd.c index a9171e8..0b998b3 100644 --- a/daemon/rrdbotd.c +++ b/daemon/rrdbotd.c @@ -99,56 +99,6 @@ test(int argc, char* argv[])  }  /* ----------------------------------------------------------------------------- - * CLEANUP - */ - -typedef struct _exit_stack -{ -    voidfunc func; -    void* data; - -    /* We have a list of these beauties */ -    struct _exit_stack* next; -} -exit_stack; - -/* Our exit stack */ -static exit_stack* atexits = NULL; -static int atexit_registered = 0; - -static void -atexit_do_stack(void) -{ -    exit_stack* next; -    for(; atexits; atexits = next) -    { -        next = atexits->next; -        (atexits->func)(atexits->data); -        free(atexits); -    } -} - -void -rb_atexit(voidfunc func, void* data) -{ -    exit_stack* ae; - -    ASSERT(func); - -    ae = (exit_stack*)calloc(1, sizeof(exit_stack)); -    if(ae) -    { -        ae->func = func; -        ae->data = data; -        ae->next = atexits; -        atexits = ae; - -        if(!atexit_registered) -            atexit(atexit_do_stack); -    } -} - -/* -----------------------------------------------------------------------------   * LOGGING   */ diff --git a/daemon/rrdbotd.h b/daemon/rrdbotd.h index 1a9782b..b211007 100644 --- a/daemon/rrdbotd.h +++ b/daemon/rrdbotd.h @@ -152,9 +152,6 @@ void rb_messagex(int level, const char* msg, ...);  void rb_message(int level, const char* msg, ...);  void rb_vmessage(int level, int err, const char* msg, va_list ap); -typedef void (*voidfunc)(void*); -void rb_atexit (voidfunc func, void* data); -  /* -----------------------------------------------------------------------------   * CONFIG (config.c)   */ | 
