diff options
author | Stef Walter <stef@memberwebs.com> | 2006-01-27 00:45:54 +0000 |
---|---|---|
committer | Stef Walter <stef@memberwebs.com> | 2006-01-27 00:45:54 +0000 |
commit | a4f6f05bd37adf54d84561dab6b11365c0e2b860 (patch) | |
tree | d7c3220f9bbf8d11d12bea6f80e190aa78c6d1af /src/config.c | |
parent | 965ffa71d8352d53b48d08ffd7fee3e4bcafcfa6 (diff) |
Move rrdbot code into right project.
Diffstat (limited to 'src/config.c')
-rw-r--r-- | src/config.c | 575 |
1 files changed, 0 insertions, 575 deletions
diff --git a/src/config.c b/src/config.c deleted file mode 100644 index ca64514..0000000 --- a/src/config.c +++ /dev/null @@ -1,575 +0,0 @@ -/* - * 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 <dirent.h> - -#include "stringx.h" -#include "rrdbotd.h" - -/* TODO: Put file names in all the parsing error messages */ - -/* - * These routines parse the configuration files and setup the in memory - * data structures. They're mostly run before becoming a daemon, and just - * exit on error. - */ - -typedef struct _config_ctx -{ - const char* confname; - char* configmem; - uint interval; - uint timeout; - rb_item* items; -} -config_ctx; - -/* ----------------------------------------------------------------------------- - * STRINGS - */ - -#define CONFIG_POLL "poll" -#define CONFIG_INTERVAL "interval" -#define CONFIG_FIELD "field." -#define CONFIG_SNMP "snmp" - -#define FIELD_VALID "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-0123456789." - -/* ----------------------------------------------------------------------------- - * CONFIG LOADING - */ - -static rb_item* -sort_items_by_host(rb_item *item) -{ - rb_item *sort = NULL; - rb_item *cur; - rb_item *it; - - while(item) - { - cur = item; - item = item->next; - cur->next = NULL; - - /* First item */ - if(!sort) - { - sort = cur; - continue; - } - - /* Before first item */ - else if(cur->host <= sort->host) - { - cur->next = sort; - sort = cur; - continue; - } - - for(it = sort; it->next; it = it->next) - { - if(cur->host <= sort->next->host) - break; - } - - ASSERT(it); - cur->next = it->next; - it->next = cur; - } - - return sort; -} - -static void -config_done(config_ctx* ctx) -{ - char key[MAXPATHLEN]; - rb_item* it; - rb_poller* poll; - char *t; - - /* No polling specified */ - if(!ctx->items) - return; - - /* Make sure we found an interval */ - if(ctx->interval == 0) - errx(2, "no interval specified in config file: %s", ctx->confname); - - if(ctx->timeout == 0) - ctx->timeout = g_state.timeout; - - /* And a nice key for lookups */ - snprintf(key, sizeof(key), "%d-%d:%s/%s.rrd", ctx->timeout, - ctx->interval, g_state.rrddir, ctx->confname); - key[sizeof(key) - 1] = 0; - - /* See if we have one of these pollers already */ - poll = (rb_poller*)hsh_get(g_state.poll_by_key, key, -1); - if(!poll) - { - poll = (rb_poller*)calloc(1, sizeof(*poll)); - - if(!poll || !hsh_set(g_state.poll_by_key, key, -1, poll)) - errx(1, "out of memory"); - - strcpy(poll->key, key); - t = strchr(poll->key, ':'); - ASSERT(t); - poll->rrdname = t + 1; - - poll->interval = ctx->interval * 1000; - poll->timeout = ctx->timeout * 1000; - - /* Add it to the main lists */ - poll->next = g_state.polls; - g_state.polls = poll; - } - - /* Get the last item and add to the list */ - for(it = ctx->items; it->next; it = it->next) - it->poller = poll; - - ASSERT(it); - it->poller = poll; - - /* Add the items to this poller */ - it->next = poll->items; - poll->items = sort_items_by_host(ctx->items); - - /* - * This remains allocated for the life of the program as - * All the configuration strings are in this memory. - * 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 -parse_uri(char *uri, char** scheme, char** host, - char** user, char** path, config_ctx* ctx) -{ - /* Copy only for error messages as we mess with original */ - char* copy = strdup(uri); - char* t; - - *host = NULL; - *path = NULL; - *user = NULL; - - *scheme = strsep(&uri, ":"); - if(uri == NULL) - errx(2, "invalid poll uri (scheme invalid): %s", copy); - - if((uri[0] != '/' && uri[1] != '/')) - errx(2, "invalid poll uri (scheme invalid): %s", copy); - - uri += 2; - *host = strsep(&uri, "/"); - if(*host[0]) - { - /* Parse the user name out from the host */ - t = strchr(*host, '@'); - if(t) - { - *t = 0; - *user = *host; - *host = t + 1; - } - } - - if(!*host[0]) - errx(2, "invalid poll uri (no hostname found): %s", copy); - - if(!uri || !uri[0] || !uri[1]) - errx(2, "invalid poll uri (no pathname found): %s", copy); - - *path = uri; - - /* This copy only for error messages */ - free(copy); -} - -static rb_item* -parse_item(const char* field, char* uri, config_ctx *ctx) -{ - rb_item *ritem; - rb_host *rhost; - - char* host; - char* user; - char* scheme; - char* path; - - /* Parse the SNMP URI */ - parse_uri(uri, &scheme, &host, &user, &path, ctx); - ASSERT(scheme && host && path); - - /* TODO: SNMP version support */ - - /* Currently we only support SNMP pollers */ - if(strcmp(scheme, CONFIG_SNMP) != 0) - errx(2, "invalid poll scheme: %s", scheme); - - /* TODO: THis code assumes all hosts have the same community - the lookups below won't work wehn host/community is different */ - - /* See if we can find an associated host */ - rhost = (rb_host*)hsh_get(g_state.host_by_name, host, -1); - if(!rhost) - { - /* Make a new one if necessary */ - rhost = (rb_host*)calloc(1, sizeof(*rhost)); - - if(!rhost || !hsh_set(g_state.host_by_name, host, -1, rhost)) - errx(1, "out of memory"); - - /* TODO: Version support */ - rhost->version = 1; - rhost->name = host; - rhost->community = user ? user : "public"; - - /* TODO: Eventually resolving should be in a separate thread, - and done regularly */ - if(sock_any_pton(host, &(rhost->address), - SANY_OPT_DEFPORT(161) | SANY_OPT_DEFLOCAL) == -1) - { - rb_message(LOG_WARNING, "couldn't resolve host address (ignoring): %s", host); - free(rhost); - return; - } - - /* And add it to the list */ - rhost->next = g_state.hosts; - g_state.hosts = rhost; - } - - /* Make a new item */ - ritem = calloc(1, sizeof(*ritem)); - if(!ritem) - errx(1, "out of memory"); - - ritem->rrdfield = field; - ritem->host = rhost; - ritem->poller = NULL; /* Set later in config_done */ - ritem->req = NULL; - ritem->value = RB_UNKNOWN; - - /* And parse the OID */ - if(rb_parse_mib(path, &(ritem->snmpfield)) == -1) - errx(2, "invalid OID: %s", path + 1); - - /* And add it to the list */ - ritem->next = ctx->items; - ctx->items = ritem; -} - -static void -config_value(const char* header, const char* name, char* value, - config_ctx* ctx) -{ - if(strcmp(header, "poll") != 0) - return; - - if(strcmp(name, CONFIG_INTERVAL) == 0) - { - char* t; - int i; - - if(ctx->interval > 0) - errx(2, CONFIG_INTERVAL " specified twice: %s", value); - - i = strtol(value, &t, 10); - if(i < 1) - err(2, CONFIG_INTERVAL " must be a positive number: %s", value); - - ctx->interval = (uint32_t)i; - } - - /* If it starts with "field." */ - if(strncmp(name, CONFIG_FIELD, KL(CONFIG_FIELD)) == 0) - { - rb_poller* poll; - const char* field; - const char* t; - - /* Check the name */ - field = name + KL(CONFIG_FIELD); - t = field + strspn(field, FIELD_VALID); - if(*t) - err(2, "the '%s' field name must only contain characters, digits, underscore and dash", field); - - /* Parse out the field */ - parse_item(field, value, ctx); - } -} - -/* ----------------------------------------------------------------------------- - * CONFIG FILES - */ - -static char* -read_config_file(const char* configfile) -{ - 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); - - fclose(f); - - /* Null terminate the data */ - config[len] = '\n'; - config[len + 1] = 0; - - /* Remove nasty dos line endings */ - remove_cr(config); - - rb_messagex(LOG_DEBUG, "read config file: %s", configfile); - return config; -} - -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 = trim_start(p); - - /* Continuation line (had spaces at start) */ - if(p < t && *t) - { - if(!value) - errx(2, "invalid continuation in config: %s", 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, "parsed configuration value: [%s] %s = %s", 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, "invalid config header: %s", p); - - *t = 0; - header = trim_space(p + 1); - continue; - } - - /* Look for the break between name = value on the same line */ - t = p + strcspn(p, ":="); - if(!*t) - errx(2, "invalid config line: %s", p); - - /* Null terminate and split value part */ - *t = 0; - t++; - - name = trim_space(p); - value = trim_space(t); - } - - if(name && value) - { - rb_messagex(LOG_DEBUG, "parsed configuration value: [%s] %s = %s", 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; -} - -void -rb_config_parse() -{ - char configfile[MAXPATHLEN]; - struct dirent* dire; - config_ctx ctx; - DIR* dir; - - /* Setup the hash tables properly */ - g_state.poll_by_key = hsh_create(); - g_state.host_by_name = hsh_create(); - - dir = opendir(g_state.confdir); - if(!dir) - err("couldn't read config directory: %s", g_state.confdir); - - while((dire = readdir(dir)) != NULL) - { - if(dire->d_type != DT_REG && dire->d_type != DT_LNK) - continue; - - /* Build a happy path name */ - snprintf(configfile, MAXPATHLEN, "%s/%s", g_state.confdir, dire->d_name); - configfile[MAXPATHLEN - 1] = 0; - - memset(&ctx, 0, sizeof(ctx)); - ctx.confname = dire->d_name; - - parse_config_file(configfile, &ctx); - } - - closedir(dir); -} - -/* ----------------------------------------------------------------------------- - * FREEING MEMORY - */ - -static void -free_items(rb_item* item) -{ - rb_item* next; - for(; item; item = next) - { - next = item->next; - free(item); - } -} - -static void -free_hosts(rb_host* host) -{ - rb_host* next; - for(; host; host = next) - { - next = host->next; - free(host); - } -} - -static void -free_pollers(rb_poller* poll) -{ - rb_poller* next; - for(; poll; poll = next) - { - free_items(poll->items); - - next = poll->next; - free(poll); - } - -} - -void -rb_config_free() -{ - hsh_free(g_state.poll_by_key); - hsh_free(g_state.host_by_name); - - free_hosts(g_state.hosts); - - /* Note that rb_item's are owned by pollers */ - free_pollers(g_state.polls); -} |