diff options
Diffstat (limited to 'src/rrdbotd.c')
-rw-r--r-- | src/rrdbotd.c | 377 |
1 files changed, 377 insertions, 0 deletions
diff --git a/src/rrdbotd.c b/src/rrdbotd.c new file mode 100644 index 0000000..064c603 --- /dev/null +++ b/src/rrdbotd.c @@ -0,0 +1,377 @@ +/* + * 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> +#include <syslog.h> +#include <dirent.h> + +/* TODO: Abstract these headers away nicely */ +#include <bsnmp/asn1.h> +#include <bsnmp/snmp.h> + +#include "stringx.h" +#include "rrdbotd.h" + +/* TODO: Temporary */ +#include "snmpclient.h" + +/* ----------------------------------------------------------------------------- + * GLOBALS + */ + +/* TODO: These should be set from the command line */ +static int daemonized = 0; +static int debug_level = 7; + +/* ----------------------------------------------------------------------------- + * TESTS + */ + +#define OIDX_ifInOctets { 11, { 1, 3, 6, 1, 2, 1, 2, 2, 1, 10, 2, } } +struct asn_oid ifInOctens = OIDX_ifInOctets; + +static void +test_bsnmpd() +{ + struct snmp_pdu pdu, resp; + int n; + + snmp_client_init(&snmp_client); + snmp_client.trans = SNMP_TRANS_UDP; + snmp_open("northstar-link.ws.local", NULL, "wsnettle", "public"); + + snmp_pdu_create(&pdu, SNMP_PDU_GET); + + n = snmp_add_binding(&pdu, &ifInOctens, SNMP_SYNTAX_COUNTER, NULL); + if (snmp_dialog(&pdu, &resp)) + errx(1, "No response from '%s': %s", snmp_client.chost, snmp_client.error); + + if (snmp_pdu_check(&pdu, &resp) <= 0) + errx(1, "Error reading from server: %s", snmp_client.error); + + snmp_pdu_dump(&resp); + printf("done\n"); +} + +/* ----------------------------------------------------------------------------- + * 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) +{ + char* name = NULL; + char* value = NULL; + char* config; + char* next; + char* header; + char* p; + char* t; + int pos; + + config = read_config_file(configfile); + 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); + // TODO: Hand off pairs here + } + + 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", name, value); + // TODO: Hand off pairs here + } + + // TODO: Eventually no freeing + free(config); +} + +static void +parse_config_dir(const char* confdir) +{ + char olddir[MAXPATHLEN]; + char configfile[MAXPATHLEN]; + DIR* top; + struct dirent* tope; + DIR* dir; + struct dirent* dire; + + /* Get the current directory */ + if(!getcwd(olddir, MAXPATHLEN)) + *olddir = 0; + + if(chdir(confdir) == -1 || + (top = opendir(".")) == NULL) + err("couldn't read config directory: %s", confdir); + + while((tope = readdir(top)) != NULL) + { + /* Only go through the category directories */ + if(!(tope->d_type & DT_DIR)) + continue; + + /* None of these dumb dots */ + if(strcmp(tope->d_name, ".") == 0 || + strcmp(tope->d_name, "..") == 0) + continue; + + dir = opendir(tope->d_name); + if(!dir) + err("couldn't read config directory: %s/%s", confdir, tope->d_name); + + 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/%s", confdir, tope->d_name, dire->d_name); + configfile[MAXPATHLEN - 1] = 0; + + parse_config_file(configfile); + } + + closedir(dir); + } + + closedir(top); + + /* And put it back nicely */ + if(*olddir) + chdir(olddir); +} + +/* ----------------------------------------------------------------------------- + * LOGGING + */ + +static void +vmessage (int level, int err, const char* msg, va_list ap) +{ + #define MAX_MSGLEN 1024 + char buf[MAX_MSGLEN]; + int e = errno; + + if(daemonized) { + if (level >= LOG_DEBUG) + return; + } else { + if(debug_level < level) + return; + } + + ASSERT (msg); + snprintf(buf, MAX_MSGLEN, "%s%s", msg, err ? ": " : ""); + + if(err) + strncat(buf, strerror(e), MAX_MSGLEN); + + /* As a precaution */ + buf[MAX_MSGLEN - 1] = 0; + + /* Either to syslog or stderr */ + if (daemonized) + vsyslog (level, buf, ap); + else + vwarnx (buf, ap); +} + +void +rb_messagex (int level, const char* msg, ...) +{ + va_list ap; + va_start(ap, msg); + vmessage(level, 0, msg, ap); + va_end(ap); +} + +void +rb_message (int level, const char* msg, ...) +{ + va_list ap; + va_start(ap, msg); + vmessage(level, 1, msg, ap); + va_end(ap); +} + +/* ----------------------------------------------------------------------------- + * STARTUP + */ + +static void +usage() +{ + fprintf(stderr, "usage: rrdcollectd\n"); + fprintf(stderr, " rrdcollectd -v\n"); + exit(2); +} + +int +main(int argc, char* argv[]) +{ + int daemonize; + char ch; + + /* Parse the arguments nicely */ + while((ch = getopt(argc, argv, "v")) != -1) + { + switch(ch) + { + + /* Print version number */ + case 'v': + printf("rrdcollectd (version %s)\n", VERSION); + exit(0); + break; + + /* Usage information */ + case '?': + default: + usage(); + break; + } + } + + argc -= optind; + argv += optind; + + parse_config_dir("/data/projects/rrdui/conf"); + return 0; +} + |