summaryrefslogtreecommitdiff
path: root/src/config.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/config.c')
-rw-r--r--src/config.c575
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);
-}