diff options
| -rw-r--r-- | Makefile.am | 2 | ||||
| -rw-r--r-- | common/compat.c | 13 | ||||
| -rw-r--r-- | common/compat.h | 4 | ||||
| -rw-r--r-- | configure.in | 3 | ||||
| -rw-r--r-- | tools/Makefile.am | 8 | ||||
| -rw-r--r-- | tools/rrdbot-create.c | 407 | 
6 files changed, 435 insertions, 2 deletions
| diff --git a/Makefile.am b/Makefile.am index 2dc888b..77d0c5b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@  EXTRA_DIST = common mib -SUBDIRS = bsnmp daemon mibs +SUBDIRS = bsnmp daemon tools mibs  # Clean up any EXTRA_DIST we're distributing  dist-hook: diff --git a/common/compat.c b/common/compat.c index 0c6c833..247560e 100644 --- a/common/compat.c +++ b/common/compat.c @@ -230,3 +230,16 @@ atexitv(voidfunc func, void* data)  }  #endif /* HAVE_ATEXITV */ + +#ifndef HAVE_XCALLOC + +void* +xcalloc(size_t size) +{ +    register void* value = calloc(1, size); +    if(value == NULL) +        errx("out of memory"); +    return value; +} + +#endif /* HAVE_XCALLOC */ diff --git a/common/compat.h b/common/compat.h index 7ef2f50..12ffad6 100644 --- a/common/compat.h +++ b/common/compat.h @@ -73,4 +73,8 @@ int strtob(const char* str);  void atexitv(void (*func)(void*), void* data);  #endif +#ifndef HAVE_XCALLOC +void* xcalloc(size_t size); +#endif +  #endif /* __COMPAT_H__ */ diff --git a/configure.in b/configure.in index 6438116..9dc3570 100644 --- a/configure.in +++ b/configure.in @@ -47,5 +47,6 @@ AC_MSG_RESULT()  AC_CONFIG_FILES([Makefile      mibs/Makefile      daemon/Makefile -    bsnmp/Makefile]) +    bsnmp/Makefile +    tools/Makefile])  AC_OUTPUT diff --git a/tools/Makefile.am b/tools/Makefile.am new file mode 100644 index 0000000..94dfa06 --- /dev/null +++ b/tools/Makefile.am @@ -0,0 +1,8 @@ + +sbin_PROGRAMS = rrdbot-create + +rrdbot_create_SOURCES = rrdbot-create.c ../common/usuals.h \ +                ../common/config-parser.h ../common/config-parser.c \ +                ../common/compat.h ../common/compat.c +rrdbot_create_CFLAGS = -I${top_srcdir}/common/ -I${top_srcdir} \ +                -DCONF_PREFIX=\"$(sysconfdir)\" -DDATA_PREFIX=\"$(datadir)\" diff --git a/tools/rrdbot-create.c b/tools/rrdbot-create.c new file mode 100644 index 0000000..6e2f143 --- /dev/null +++ b/tools/rrdbot-create.c @@ -0,0 +1,407 @@ +/* + * 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 <stdarg.h> + +/* ----------------------------------------------------------------------------- + * CONSTANTS + */ + +/* The default command line options */ +#define DEFAULT_CONFIG      CONF_PREFIX "/rrdbot" +#define DEFAULT_WORK        "/var/db/rrdbot" + +#define CONFIG_CREATE   "create" +#define CONFIG_RRA      "rra" +#define CONFIG_FIELD    "field." + +#define FIELD_VALID     "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-0123456789." + +/* ----------------------------------------------------------------------------- + * DECLARATIONS + */ + +typedef struct _create_arg +{ +    char* def; +    struct _create_arg* next; +} +create_arg; + +typedef struct _create_ctx +{ +    const char* workdir; +    const char* confname; +    int skip; +    create_arg* args; +} +create_ctx; + +/* Wether to print out status updates */ +static int g_verbose = 0; +static int g_print = 0; + +/* ----------------------------------------------------------------------------- + * HELPERS + */ + +void +verb(const char* fmt, ...) +{ +    va_list va; + +    if(!g_verbose) +        return; + +    va_start(va, fmt); +    vwarnx(fmt, va); +    va_end(va); +} + +/* ----------------------------------------------------------------------------- + * CREATE + */ + +void +create_file(create_ctx* ctx, const char* rrd) +{ +    create_arg* arg; +    int num = 0; +    int argc, r; +    const char** argv; + +    for(arg = ctx->args; arg; arg = arg->next) +        num++; + +    argv = (const char**)xcalloc(sizeof(char*) * (num + 5)); + +    argv[0] = "create"; +    argv[1] = rrd; +    argv[2] = "-b-1y";  /* Allow stuff up to a year old */ +    argv[3] = "-s10";   /* Up to 10 second resolution */ +    argc = 4; + +    if(!g_print) +        verb("creating rrd with command:"); + +    if(g_verbose || g_print) +        fprintf(stderr, "# rrd create '%s' -b-1y -s10 ", rrd); + +    for(arg = ctx->args; arg; arg = arg->next) +    { +        argv[argc++] = arg->def; + +        if(g_verbose || g_print) +            fprintf(stderr, "%s ", arg->def); +    } + +    if(g_verbose || g_print) +        fprintf(stderr, "\n"); + +    if(!g_print) +    { +        /* Always have to clear before calling rrdtool. klunky :( */ +        optind = 0; +        opterr = 0; + +        rrd_clear_error(); +        r = rrd_create(argc, argv); + +        if(r != 0) +            warnx("couldn't create rrd file: %s: %s", rrd, rrd_get_error()); +        else if(!g_print) +            verb("created rrd: %s", rrd); +    } + +    free(argv); +} + +void +check_create_file(create_ctx* ctx) +{ +    char rrd[MAXPATHLEN]; + +    ASSERT(ctx->confname); + +    snprintf(rrd, sizeof(rrd), "%s/%s.rrd", ctx->workdir, ctx->confname); +    rrd[sizeof(rrd) - 1] = 0; + +    /* Make sure it exists */ +    if(access(rrd, F_OK) == 0) +    { +        verb("rrd file already exists, skipping: %s", rrd); +        return; +    } +    else if(errno != ENOENT) +    { +        warn("couldn't check rrd file: %s", rrd); +        return; +    } + +    if(ctx->skip) +    { +        warnx("skipping rrd creation due to configuration errors: %s", rrd); +        return; +    } + +    create_file(ctx, rrd); +} + +static void +add_rras(create_ctx* ctx, char* value) +{ +    const char rrafmt[] = "RRA:%s"; +    create_arg* arg; +    char* def; +    char* t; +    int len; + +    while(value && *value) +    { +        t = strchr(value, ' '); +        if(t) +            *(t++) = 0; + +        len = strlen(rrafmt) + strlen(value) + 1; +        def = (char*)xcalloc(len); +        snprintf(def, len, rrafmt, strtrim(value)); +        def[len - 1] = 0; + +        arg = (create_arg*)xcalloc(sizeof(create_arg)); +        arg->def = def; +        arg->next = ctx->args; +        ctx->args = arg; + +        value = t; +    } +} + +static void +add_field(create_ctx* ctx, const char* field, char* value) +{ +    const char dsfmt[] = "DS:%s:%s"; +    create_arg* arg; +    char* def; +    int len; + +    len = strlen(dsfmt) + strlen(field) + strlen(value) + 1; +    def = (char*)xcalloc(len); +    snprintf(def, len, dsfmt, field, value); +    def[len - 1] = 0; + +    arg = (create_arg*)xcalloc(sizeof(create_arg)); +    arg->def = def; +    arg->next = ctx->args; +    ctx->args = arg; +} + + +/* ----------------------------------------------------------------------------- + * CONFIG CALLBACKS + */ + +int +cfg_value(const char* filename, const char* header, const char* name, +          char* value, void* data) +{ +    create_ctx* ctx = (create_ctx*)data; +    create_arg* arg; + +    ASSERT(filename); +    ASSERT(ctx); + +    if(!ctx->confname) +        ctx->confname = filename; + +    /* Called like this after each config file */ +    if(!header) +    { +        /* Create this file (if necessary) */ +        check_create_file(ctx); + +        /* Do cleanup */ +        ctx->confname = NULL; + +        for( ; ctx->args; ctx->args = ctx->args->next) +        { +            arg = ctx->args->next; +            free(ctx->args->def); +            free(ctx->args); +            ctx->args = arg; +        } + +        ctx->skip = 0; +        return 0; +    } + +    ASSERT(name && value); + +    /* Only process this section */ +    if(strcmp(header, CONFIG_CREATE) != 0) +        return; + +    /* The rra option */ +    if(strcmp(name, CONFIG_RRA) == 0) +        add_rras(ctx, value); + +    /* If it starts with "field." */ +    else if(strncmp(name, CONFIG_FIELD, KL(CONFIG_FIELD)) == 0) +    { +        const char* field; +        const char* t; + +        /* Check the name */ +        field = name + KL(CONFIG_FIELD); +        t = field + strspn(field, FIELD_VALID); +        if(*t) +        { +            warnx("%s: the '%s' field name must only contain characters, digits, underscore and dash", +                  ctx->confname, field); +            ctx->skip = 1; +            return; +        } + +        add_field(ctx, field, value); +    } + +    return 0; +} + +int +cfg_error(const char* filename, const char* errmsg, void* data) +{ +    create_ctx* ctx = (create_ctx*)data; + +    /* Skip the file on errors */ +    ctx->skip = 1; + +    warnx("%s", errmsg); +    return 0; +} + + +/* ----------------------------------------------------------------------------- + * STARTUP + */ + +static void +usage() +{ +    fprintf(stderr, "usage: rrdbot-create [-vn] [-c confdir] [-w workdir]\n"); +    fprintf(stderr, "       rrdbot-create -V\n"); +    exit(2); +} + +static void +version() +{ +    printf("rrdbot-create (version %s)\n", VERSION); +    printf("   default config directory: %s\n", DEFAULT_CONFIG); +    printf("   default work directory:   %s\n", DEFAULT_WORK); +    exit(0); +} + +int +main(int argc, char* argv[]) +{ +    const char* confdir = DEFAULT_CONFIG; +    create_ctx ctx; +    char ch; +    char* t; + +    memset(&ctx, 0, sizeof(ctx)); +    ctx.workdir = DEFAULT_WORK; + +    /* Parse the arguments nicely */ +    while((ch = getopt(argc, argv, "c:nw:vV")) != -1) +    { +        switch(ch) +        { + +        /* Config directory */ +        case 'c': +            confdir = DEFAULT_CONFIG; +            break; + +        /* Only print commands */ +        case 'n': +            g_print = 1; +            break; + +        /* Be verbose */ +        case 'v': +            g_verbose = 1; +            break; + +        /* Print version number */ +        case 'V': +            version(); +            break; + +        /* The work directory */ +        case 'w': +            ctx.workdir = optarg; +            break; + +        /* Usage information */ +        case '?': +        default: +            usage(); +            break; +        } +    } + +    argc -= optind; +    argv += optind; + +    if(argc != 0) +        usage(); + + +    /* +     * We parse the configuration, this calls cfg_value +     * which will do the actual creation of the files +     */ +    if(cfg_parse_dir(confdir, &ctx) == -1) +        exit(1); /* message already printed */ + +    return 0; +} | 
