From 0fe9ee8d6a212e5b676f327b727c9d404edc7781 Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Fri, 17 Mar 2006 17:27:28 +0000 Subject: Move src/ to module/ subdir --- Makefile.am | 2 +- configure.in | 2 +- module/Makefile.am | 16 + module/bsnmp-regex.c | 1025 +++++++++++++++++++++++++++++++++++++++++++++++++ module/regex-tree.def | 20 + module/usuals.h | 32 ++ src/Makefile.am | 16 - src/bsnmp-regex.c | 1025 ------------------------------------------------- src/regex-tree.def | 20 - src/usuals.h | 32 -- 10 files changed, 1095 insertions(+), 1095 deletions(-) create mode 100644 module/Makefile.am create mode 100644 module/bsnmp-regex.c create mode 100644 module/regex-tree.def create mode 100644 module/usuals.h delete mode 100644 src/Makefile.am delete mode 100644 src/bsnmp-regex.c delete mode 100644 src/regex-tree.def delete mode 100644 src/usuals.h diff --git a/Makefile.am b/Makefile.am index 941939e..9bb1356 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ # EXTRA_DIST = BUGS -SUBDIRS = src +SUBDIRS = module diff --git a/configure.in b/configure.in index fbaa423..60fb871 100644 --- a/configure.in +++ b/configure.in @@ -52,5 +52,5 @@ AC_FUNC_MALLOC AC_FUNC_MEMCMP dnl TODO AC_CHECK_FUNCS([atexit inet_ntoa inet_pton memset strerror strspn strtol]) -AC_CONFIG_FILES([Makefile src/Makefile]) +AC_CONFIG_FILES([Makefile module/Makefile]) AC_OUTPUT diff --git a/module/Makefile.am b/module/Makefile.am new file mode 100644 index 0000000..6f10233 --- /dev/null +++ b/module/Makefile.am @@ -0,0 +1,16 @@ + +INCLUDES = -DCONF_PREFIX=\"$(sysconfdir)\" + +moduledir = $(prefix)/lib +module_LTLIBRARIES = snmp_regex.la + +snmp_regex_la_LDFLAGS = -module +snmp_regex_la_SOURCES = regex_tree.c regex_tree.h regex_oid.h \ + bsnmp-regex.c + +regex_tree.c: regex-tree.def + gensnmptree -p regex_ < regex-tree.def + gensnmptree -e regexData > regex_oid.h < regex-tree.def + +CLEANFILES = regex_tree.* \ + regex_oid.h diff --git a/module/bsnmp-regex.c b/module/bsnmp-regex.c new file mode 100644 index 0000000..98a94a9 --- /dev/null +++ b/module/bsnmp-regex.c @@ -0,0 +1,1025 @@ + +#include "usuals.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef WITH_PCRE +#include +#else +#include +#endif + +#include "regex_tree.h" +#include "regex_oid.h" + +#define DEFAULT_CONFIG CONF_PREFIX "/rrdbot" +#define DEFAULT_FIFO "/var/run/snmp-regex.fifo" + +/* our module handle */ +static struct lmodule *module; + +/* OIDs */ +static const struct asn_oid oid_regex = OIDX_regexData; + +/* the Object Resource registration index */ +static u_int reg_index = 0; + +/* Various match types */ +enum { + TYPE_UNKNOWN = 0, + TYPE_COUNTER, + TYPE_INTEGER +}; + +struct data_entry { + uint32_t index; + TAILQ_ENTRY(data_entry) link; + + int type; + char *descr; + +#ifdef WITH_PCRE + pcre *regex; + pcre_extra *extra; +#else + regex_t regex; +#endif + char *result; + + uint64_t last_update; + uint64_t value; +}; + +TAILQ_HEAD(data_entry_list, data_entry); + +/* list of peers */ +static struct data_entry_list entries = TAILQ_HEAD_INITIALIZER(entries); +static uint32_t entry_count = 0; + + +/* configuration */ +static u_char *regex_config = NULL; +static char *config_memory = NULL; + +/* The FIFO log */ +static u_char *regex_fifo = NULL; +static int fifo_fd = -1; +static void *fifo_sel = NULL; + +/* Buffer for parsing logs */ +#define LINE_LENGTH 1024 +static char line_buffer[LINE_LENGTH]; + +/* ----------------------------------------------------------------------------- + * HELPERS + */ + +static void +emsg(const char *format, ...) +{ + va_list va; + va_start(va, format); + vsyslog(LOG_ERR, format, va); + va_end(va); +} + +static void +strcln (char* data, char ch) +{ + char* p; + for (p = data; *data; data++, p++) { + while (*data == ch) + data++; + *p = *data; + } + /* null terminate */ + *p = 0; +} + +static void +stretrim (char* data) +{ + char* t = data + strlen (data); + while (t > data && isspace (*(t - 1))) { + t--; + *t = 0; + } +} + +static char* +strbtrim (const char* data) +{ + while (*data && isspace (*data)) + ++data; + return (char*)data; +} + +static char* +strtrim (char* data) +{ + data = (char*)strbtrim (data); + stretrim (data); + return data; +} + +static uint64_t +getcurrticks () +{ + struct timeval tp; + uint64_t t; + + /* Update tick count */ + if (gettimeofday (&tp, NULL) < 0) { + emsg ("couldn't get current time: %s", strerror (errno)); + return 0; + } + + t = (((uint64_t)tp.tv_sec) * 100) + (((uint64_t)tp.tv_usec) / 10000); + return t; +} + +#ifndef WITH_PCRE + +static const char* +regex_msg (int code) +{ + ASSERT (code != 0); + + switch (code) { + case REG_NOMATCH: + return "The regexec() function failed to match"; + case REG_BADPAT: + return "invalid regular expression"; + case REG_ECOLLATE: + return "invalid collating element"; + case REG_ECTYPE: + return "invalid character class"; + case REG_EESCAPE: + return "'\' applied to unescapable character"; + case REG_ESUBREG: + return "invalid backreference number"; + case REG_EBRACK: + return "brackets '[ ]' not balanced"; + case REG_EPAREN: + return "parentheses '( )' not balanced"; + case REG_EBRACE: + return "braces '{ }' not balanced"; + case REG_BADBR: + return "invalid repetition count(s) in '{ }'"; + case REG_ERANGE: + return "invalid character range in '[ ]'"; + case REG_ESPACE: + return "ran out of memory"; + case REG_BADRPT: + return "'?', '*', or '+' operand invalid"; + case REG_EMPTY: + return "empty (sub)expression"; + case REG_ILLSEQ: + return "illegal byte sequence (bad multibyte character)"; + + case REG_ASSERT: + case REG_INVARG: + default: + return "internal or unknown error"; + } +} + +#endif /* WITH_PCRE */ + +/* ----------------------------------------------------------------------------- + * MATCHING + */ + +static int +process_match (struct data_entry *data, char *result) +{ + char *t; + int i; + + switch(data->type) { + case TYPE_COUNTER: + data->value++; + break; + case TYPE_INTEGER: + if (!result) { + emsg ("match, but no result data for '%s'", data->descr); + return -1; + } + + i = strtol (result, &t, 10); + if (*t) { + emsg ("invalid integer for '%s': %s", data->descr, result); + return -1; + } + + data->value = i; + break; + + default: + ASSERT(0); + break; + } + + data->last_update = getcurrticks (); + + /* + fprintf(stderr, "updated '%s' to value '%lld' at '%lld'\n", + data->descr, data->value, data->last_update); + */ + + return 0; +} + +static char* +process_result (struct data_entry *data, char *line, int len, +#ifdef WITH_PCRE + int *ovector, int substrings) +#else + regmatch_t *pm) +#endif +{ + char *result; + char *p, *t; + int rlen, l; + int idx; + + /* Some nice little optimizations */ + if (!data->result) + return NULL; + if (strchr (data->result, '\\') == NULL) + return strdup (data->result); + + /* Figure out the string length */ + rlen = strlen (data->result) + 1; + for (p = data->result; *p; p++) { + if(p[0] == '\\') { + p++; + if(p[0] == '\\' || !isdigit(p[0])) + continue; + idx = p[0] - '0'; + ASSERT (idx >= 0 && idx <= 9); +#ifdef WITH_PCRE + if (idx < substrings) { + ASSERT (ovector[(idx * 2) + 1] >= ovector[idx * 2]); + ASSERT (ovector[(idx * 2) + 1] < len); + ASSERT (ovector[idx * 2] < len); + rlen += (ovector[(idx * 2) + 1]) - (ovector[idx * 2]); + rlen += 1; + } +#else /* WITH_PCRE */ + if (pm[idx].rm_so != -1 && pm[idx].rm_eo != -1) { + ASSERT (pm[idx].rm_eo >= pm[idx].rm_so); + ASSERT (pm[idx].rm_eo < len); + ASSERT (pm[idx].rm_so < len); + rlen += (pm[idx].rm_eo - pm[idx].rm_so); + rlen += 1; + } +#endif /* WITH_PCRE */ + } + } + + result = (char*)calloc(rlen, 1); + if (!result) { + emsg ("out of memory"); + return NULL; + } + + for (p = data->result, t = result; *p; p++) { + if (p[0] == '\\') { + p++; + if (isdigit(p[0])) { + idx = p[0] - '0'; +#ifdef WITH_PCRE + if (idx < substrings) { + l = (ovector[(idx * 2) + 1]) - (ovector[idx * 2]); + memcpy (t, line + (ovector[idx * 2]), l); + t += l; + } +#else /* WITH_PCRE */ + if (pm[idx].rm_so != -1 && pm[idx].rm_eo != -1) { + l = pm[idx].rm_eo - pm[idx].rm_so; + memcpy (t, line + pm[idx].rm_so, l); + t += l; + } +#endif /* WITH _PCRE */ + + continue; + } + } + + *t++ = *p; + } + + *t = 0; + return result; +} + +static void +process_log (char *line, int len) +{ + struct data_entry *data; + char *result; + int r; + +#ifdef WITH_PCRE + int ovector[30]; +#else + regmatch_t pm[10]; +#endif + + for (data = TAILQ_FIRST (&entries); data; + data = TAILQ_NEXT (data, link)) { + + result = NULL; + +#ifdef WITH_PCRE + memset (ovector, 0, sizeof (ovector)); + r = pcre_exec (data->regex, data->extra, line, len, 0, + PCRE_NOTEMPTY | PCRE_NO_UTF8_CHECK, ovector, 30); + + if (r == PCRE_ERROR_NOMATCH) + continue; + else if (r == PCRE_ERROR_NOMEMORY) { + emsg ("out of memory"); + return; + } else if (r < 0) { + emsg ("internal error in matching code: %d", r); + return; + } + + result = process_result (data, line, len, ovector, r); + +#else + r = regexec (&(data->regex), line, 10, pm, 0); + if (r == REG_NOMATCH) + continue; + else if (r != 0) { + emsg ("internal error in matching code: %d", r); + return; + } + + result = process_result (data, line, len, pm); +#endif + + process_match (data, result); + free (result); + } +} + +/* ----------------------------------------------------------------------------- + * LOG READING + */ + +static void +close_fifo () +{ + if (fifo_sel) { + fd_deselect (fifo_sel); + fifo_sel = NULL; + } + + if (fifo_fd != -1) { + close (fifo_fd); + fifo_fd = -1; + } + + memset (line_buffer, 0, sizeof (line_buffer)); +} + +static void +receive_log (int fd, void *data) +{ + char *t; + int len; + int r, l; + + ASSERT (fd == fifo_fd); + + len = strlen (line_buffer); + ASSERT (len < LINE_LENGTH); + + do { + r = read (fd, line_buffer + len, (LINE_LENGTH - 1) - len); + + if (r < 0 && errno != EAGAIN) { + emsg ("couldn't read from fifo: %s: %s", regex_fifo, strerror (errno)); + return; + + /* Got data, null terminate */ + } else if (r > 0) { + len += r; + ASSERT (len < LINE_LENGTH); + line_buffer[len] = 0; + } + + /* Break really long lines */ + if (len >= LINE_LENGTH - 1) + line_buffer[len - 1] = '\n'; + + for (;;) { + t = strchr (line_buffer, '\n'); + if (t == NULL) + break; + + /* Break line (also DOS line) */ + *t = 0; + if (line_buffer != t && *(t - 1) == '\r') + *(t - 1) = 0; + l = (t + 1) - line_buffer; + + /* Send it off */ + process_log (line_buffer, l); + + /* Move data to front of buffer */ + ASSERT (l <= len); + memmove (line_buffer, t + 1, (len - l) + 1); + len -= l; + } + + } while (r > 0); +} + +static int +open_fifo () +{ + struct stat sb; + + close_fifo (); + + ASSERT (regex_fifo && regex_fifo[0]); + + if (stat (regex_fifo, &sb) == 0) { + /* Complain if it's not a FIFO */ + if (!S_ISFIFO (sb.st_mode)) { + emsg ("file or directory already exists: %s", regex_fifo); + return -1; + } + + } else if (errno == ENOENT) { + /* Try and create it */ + if (mkfifo (regex_fifo, S_IRWXU | S_IRWXG | S_IRWXO) < 0) { + emsg ("couldn't create fifo: %s: %s", regex_fifo, strerror (errno)); + return -1; + } + + } else { + emsg ("couldn't access fifo: %s: %s", regex_fifo, strerror (errno)); + return -1; + } + + fifo_fd = open (regex_fifo, O_RDONLY | O_NONBLOCK); + if (fifo_fd < 0) { + emsg ("couldn't open fifo: %s: %s", regex_fifo, strerror (errno)); + return -1; + } + + fifo_sel = fd_select (fifo_fd, receive_log, NULL, module); + if (!fifo_sel) { + emsg ("couldn't listen on fifo: %s: %s", regex_fifo, strerror (errno)); + return -1; + } + + memset (line_buffer, 0, sizeof (line_buffer)); + return 0; +} + +/* ----------------------------------------------------------------------------- + * CONFIG PARSING + */ + +static void +config_free (struct data_entry *data) +{ +#ifdef WITH_PCRE + if (data->regex) + free (data->regex); + if (data->extra) + free (data->extra); +#else + regfree (&(data->regex)); +#endif + + free (data); +} + +static void +config_free_all () +{ + struct data_entry *data; + while ((data = TAILQ_FIRST(&entries)) != NULL) { + TAILQ_REMOVE (&entries, data, link); + config_free (data); + } +} + +static int +config_entry (struct data_entry *data, char *name, char type, char *regex, + char *result, char *flags, int line) +{ +#ifdef WITH_PCRE + const char *errptr; + int erroffset; + int options = 0; +#else + int options = REG_EXTENDED; + int r; +#endif + + ASSERT (regex); + ASSERT (flags); + ASSERT (data); + ASSERT (type); + ASSERT (name); + + /* Figure out the type first */ + switch (type) { + case 'c': + data->type = TYPE_COUNTER; + break; + case 'i': + data->type = TYPE_INTEGER; + break; + case '\0': + return -2; + default: + emsg ("[line %d] invalid or unknown entry type: %c", line, type); + return -1; + } + + /* Parse any options we have */ + for (; *flags; flags++) { + switch (flags[0]) { + case 'i': +#ifdef WITH_PCRE + options |= PCRE_CASELESS; +#else + options |= REG_ICASE; +#endif + break; + default: + emsg ("[line %d] invalid flag: %c", line, flags[0]); + return -1; + } + } + + /* The name */ + data->descr = name; + + /* Parse the regex */ +#ifdef WITH_PCRE + data->regex = pcre_compile (regex, options, &errptr, &erroffset, NULL); + if (!data->regex) { + emsg ("[line %d] invalid regular expression: %s", line, errptr); + return -1; + } + /* Optimize the regex, ignore errors */ + data->extra = pcre_study (data->regex, 0, &errptr); +#else + r = regcomp (&(data->regex), regex, options); + if (r != 0) { + emsg ("[line %d] invalid regular expression: %s", line, regex_msg (r)); + return -1; + } +#endif + + /* Replacement data */ + if (data->type != TYPE_COUNTER && !result) { + emsg ("[line %d] no match text specified in entry", line); + return -1; + } + data->result = result; + + return 0; +} + +static int +config_line (char *name, char *value, int line) +{ + struct data_entry *data; + char *regex = NULL; + char *result = NULL; + char *flags = NULL; + char type; + char delimiter; + char *t; + int r; + + /* config_parse trims this for us */ + ASSERT (!isspace(value[0])); + + /* The type of entry */ + type = value[0]; + ++value; + + /* Next thing is the delimiter */ + if (!*value) + return -2; + delimiter = value[0]; + ++value; + + /* Look for the next delimiter */ + t = strchr (value, delimiter); + if (!t) + return -2; + *t = 0; + regex = value; + value = t + 1; + + /* And the result */ + t = strchr (value, delimiter); + if (t) { + *t = 0; + t++; + result = value; + } + + /* The flags */ + flags = t ? t : value; + + /* Now populate an entry */ + data = (struct data_entry*)calloc(1, sizeof (*data)); + if (!data) { + emsg ("out of memory"); + return -1; + } + + /* Now make an entry out of it all */ + r = config_entry (data, name, type, regex, result, flags, line); + + if (r < 0) { + free (data); + return r; + } + + /* Put it in our table */ + data->index = entry_count++; + INSERT_OBJECT_INT (data, &entries); + + return 0; +} + +static int +config_read () +{ + FILE *f = NULL; + long len; + + ASSERT (regex_config && regex_config[0]); + + f = fopen (regex_config, "r"); + if (f == NULL) { + emsg ("couldn't open config file: %s", regex_config); + return -1; + } + + /* Figure out size */ + if (fseek (f, 0, SEEK_END) == -1 || (len = ftell (f)) == -1 || fseek (f, 0, SEEK_SET) == -1) { + emsg ("couldn't seek config file: %s", regex_config); + return -1; + } + + ASSERT (!config_memory); + + if ((config_memory = (char*)malloc (len + 2)) == NULL) { + emsg ("out of memory"); + return -1; + } + + /* And read in one block */ + if(fread(config_memory, 1, len, f) != len) { + emsg ("couldn't read config file: %s", regex_config); + free (config_memory); + config_memory = NULL; + return -1; + } + + fclose (f); + + /* Null terminate the data */ + config_memory[len] = '\n'; + config_memory[len + 1] = 0; + + return 0; +} + +static int +config_parse () +{ + char* next; + char* p; + char* t; + int line = 0; + int r; + + config_free_all (); + + /* Reads raw config file into config_memory */ + if (config_read () < 0) + return -1; + + ASSERT (config_memory); + + /* Remove nasty dos line endings */ + strcln(config_memory, '\r'); + + next = config_memory; + while ((t = strchr (next, '\n')) != NULL) { + + *t = 0; + p = next; + next = t + 1; + t = strbtrim (p); + line++; + + /* blank lines, comments */ + if (!*t || *t == '#') + continue; + + t = strchr (t, ':'); + if (t == NULL) { + emsg ("invalid config line: %s", p); + return -1; + } + + *t = 0; + t++; + + /* Pass of the name and value */ + r = config_line (strtrim (p), strtrim (t), line); + if (r < 0) { + + /* If -2 was returned, no error message was printed */ + if (r == -2) + emsg ("[line %d] invalid configuration file", line); + + return -1; + } + } + + return 0; +} + + +/* ----------------------------------------------------------------------------- + * CALLBACKS + */ + +int +op_regexconfig (struct snmp_context *ctx, struct snmp_value *value, + u_int sub, u_int iidx, enum snmp_op op) +{ + asn_subid_t which = value->var.subs[sub - 1]; + int r = SNMP_ERR_NOERROR; + + switch (which) { + case LEAF_regexConfig: + + if (op == SNMP_OP_GET) + return string_get (value, regex_config, -1); + + /* Remainder only at initialization */ + if (community != COMM_INITIALIZE) + return SNMP_ERR_NOT_WRITEABLE; + + switch (op) { + case SNMP_OP_SET: + if ((r = string_save (value, ctx, -1, ®ex_config)) == SNMP_ERR_NOERROR) { + if (!regex_config[0]) + r = SNMP_ERR_WRONG_VALUE; + else if (config_parse () < 0) + r = SNMP_ERR_GENERR; + } + if (r != SNMP_ERR_NOERROR) + string_rollback (ctx, ®ex_config); + break; + case SNMP_OP_COMMIT: + string_commit (ctx); + break; + case SNMP_OP_ROLLBACK: + string_rollback (ctx, ®ex_config); + break; + default: + ASSERT(0); + break; + } + + return r; + + + case LEAF_regexFifo: + + if (op == SNMP_OP_GET) + return string_get (value, regex_fifo, -1); + + /* Remainder only at initialization */ + if (community != COMM_INITIALIZE) + return SNMP_ERR_NOT_WRITEABLE; + + switch (op) { + case SNMP_OP_SET: + if ((r = string_save (value, ctx, -1, ®ex_fifo)) == SNMP_ERR_NOERROR) { + if (!regex_fifo[0]) + r = SNMP_ERR_WRONG_VALUE; + else if (open_fifo () < 0) + r = SNMP_ERR_GENERR; + } + if (r != SNMP_ERR_NOERROR) + string_rollback (ctx, ®ex_config); + break; + case SNMP_OP_COMMIT: + string_commit (ctx); + break; + case SNMP_OP_ROLLBACK: + string_rollback (ctx, ®ex_fifo); + break; + default: + ASSERT(0); + break; + } + + return r; + } + + ASSERT(0); + return -1; +} + +int +op_regex (struct snmp_context *ctx, struct snmp_value *value, + u_int sub, u_int iidx, enum snmp_op op) +{ + asn_subid_t which = value->var.subs[sub - 1]; + + switch (op) { + case SNMP_OP_GET: + break; + + case SNMP_OP_SET: + return SNMP_ERR_NOT_WRITEABLE; + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + return SNMP_ERR_NOERROR; + + default: + ASSERT(0); + break; + } + + switch (which) { + case LEAF_regexCount: + value->v.integer = entry_count; + break; + + default: + ASSERT(0); + break; + } + + return SNMP_ERR_NOERROR; +} + +int +op_regexentry (struct snmp_context *ctx, struct snmp_value *value, + u_int sub, u_int iidx, enum snmp_op op) +{ + asn_subid_t which = value->var.subs[sub - 1]; + struct data_entry *data; + uint64_t ticks; + + switch (op) { + case SNMP_OP_GETNEXT: + data = NEXT_OBJECT_INT (&entries, &value->var, sub); + if (data == NULL) + return SNMP_ERR_NOSUCHNAME; + value->var.len = sub + 1; + value->var.subs[sub] = data->index; + break; + + case SNMP_OP_GET: + data = FIND_OBJECT_INT (&entries, &value->var, sub); + if (data == NULL) + return SNMP_ERR_NOSUCHNAME; + break; + + case SNMP_OP_SET: + if (index_decode (&value->var, sub, iidx, &data)) + return SNMP_ERR_NO_CREATION; + data = FIND_OBJECT_INT (&entries, &value->var, sub); + if (data != NULL) + return SNMP_ERR_NOT_WRITEABLE; + return SNMP_ERR_NO_CREATION; + + default: + ASSERT(0); + break; + } + + switch (which) { + case LEAF_regexIndex: + value->v.integer = data->index; + break; + + case LEAF_regexDescr: + return (string_get (value, data->descr, -1)); + + case LEAF_regexLast: + if (data->last_update) { + ticks = getcurrticks (); + if (ticks == 0) + return SNMP_ERR_GENERR; + value->v.uint32 = (ticks - data->last_update); + } else { + value->v.uint32 = 0; + } + break; + + case LEAF_regexValue: + value->v.uint32 = data->value; + break; + + default: + ASSERT(0); + break; + }; + + return SNMP_ERR_NOERROR; +} + +/* ----------------------------------------------------------------------------- + * MODULE + */ + +/* the initialisation function */ +static int +module_init (struct lmodule *mod, int argc, char *argv[]) +{ + module = mod; + + if (argc != 0) { + syslog(LOG_ERR, "bad number of arguments for %s", __func__); + return EINVAL; + } + + regex_config = strdup (DEFAULT_CONFIG); + if (!regex_config) + return ENOMEM; + + regex_fifo = strdup (DEFAULT_FIFO); + if (!regex_fifo) { + free (regex_config); + return ENOMEM; + } + + return 0; +} + +/* Module is started */ +static void +module_start (void) +{ + reg_index = or_register (&oid_regex, "The MIB for regex data.", module); + + /* Initial reads */ + receive_log (fifo_fd, NULL); +} + +/* Called, when the module is to be unloaded after it was successfully loaded */ +static int +module_fini (void) +{ + if (reg_index) + or_unregister (reg_index); + + ASSERT (regex_config); + free (regex_config); + + ASSERT (regex_fifo); + free (regex_fifo); + + close_fifo (); + config_free_all (); + + return 0; +} + +const struct snmp_module config = { + .comment = "This module implements SNMP listing of data from regular expressions", + .init = module_init, + .start = module_start, + .fini = module_fini, + .tree = regex_ctree, + .tree_size = regex_CTREE_SIZE, +}; + + diff --git a/module/regex-tree.def b/module/regex-tree.def new file mode 100644 index 0000000..3305ada --- /dev/null +++ b/module/regex-tree.def @@ -0,0 +1,20 @@ +(1 internet + (4 private + (1 enterprises + (10277 regexData + + # Valid only during configuration + (0 regexConfig OCTETSTRING op_regexconfig GET SET) + (1 regexFifo OCTETSTRING op_regexconfig GET SET) + + (10 regexCount INTEGER op_regex GET) + (11 regexEntry : INTEGER op_regexentry + (1 regexIndex INTEGER GET) + (2 regexDescr OCTETSTRING GET) + (3 regexLast TIMETICKS GET) + (4 regexValue INTEGER GET) + ) + ) + ) + ) +) diff --git a/module/usuals.h b/module/usuals.h new file mode 100644 index 0000000..6dc7b08 --- /dev/null +++ b/module/usuals.h @@ -0,0 +1,32 @@ + +#ifndef __USUALS_H__ +#define __USUALS_H__ + +#include + +#include "config.h" + +#include +#include +#include +#include +#include + +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#define countof(x) (sizeof(x) / sizeof(x[0])) + +#ifdef _DEBUG + #include "assert.h" + #define ASSERT(x) assert(x) +#else + #define ASSERT(x) +#endif + +#endif /* __USUALS_H__ */ diff --git a/src/Makefile.am b/src/Makefile.am deleted file mode 100644 index 6f10233..0000000 --- a/src/Makefile.am +++ /dev/null @@ -1,16 +0,0 @@ - -INCLUDES = -DCONF_PREFIX=\"$(sysconfdir)\" - -moduledir = $(prefix)/lib -module_LTLIBRARIES = snmp_regex.la - -snmp_regex_la_LDFLAGS = -module -snmp_regex_la_SOURCES = regex_tree.c regex_tree.h regex_oid.h \ - bsnmp-regex.c - -regex_tree.c: regex-tree.def - gensnmptree -p regex_ < regex-tree.def - gensnmptree -e regexData > regex_oid.h < regex-tree.def - -CLEANFILES = regex_tree.* \ - regex_oid.h diff --git a/src/bsnmp-regex.c b/src/bsnmp-regex.c deleted file mode 100644 index 98a94a9..0000000 --- a/src/bsnmp-regex.c +++ /dev/null @@ -1,1025 +0,0 @@ - -#include "usuals.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#ifdef WITH_PCRE -#include -#else -#include -#endif - -#include "regex_tree.h" -#include "regex_oid.h" - -#define DEFAULT_CONFIG CONF_PREFIX "/rrdbot" -#define DEFAULT_FIFO "/var/run/snmp-regex.fifo" - -/* our module handle */ -static struct lmodule *module; - -/* OIDs */ -static const struct asn_oid oid_regex = OIDX_regexData; - -/* the Object Resource registration index */ -static u_int reg_index = 0; - -/* Various match types */ -enum { - TYPE_UNKNOWN = 0, - TYPE_COUNTER, - TYPE_INTEGER -}; - -struct data_entry { - uint32_t index; - TAILQ_ENTRY(data_entry) link; - - int type; - char *descr; - -#ifdef WITH_PCRE - pcre *regex; - pcre_extra *extra; -#else - regex_t regex; -#endif - char *result; - - uint64_t last_update; - uint64_t value; -}; - -TAILQ_HEAD(data_entry_list, data_entry); - -/* list of peers */ -static struct data_entry_list entries = TAILQ_HEAD_INITIALIZER(entries); -static uint32_t entry_count = 0; - - -/* configuration */ -static u_char *regex_config = NULL; -static char *config_memory = NULL; - -/* The FIFO log */ -static u_char *regex_fifo = NULL; -static int fifo_fd = -1; -static void *fifo_sel = NULL; - -/* Buffer for parsing logs */ -#define LINE_LENGTH 1024 -static char line_buffer[LINE_LENGTH]; - -/* ----------------------------------------------------------------------------- - * HELPERS - */ - -static void -emsg(const char *format, ...) -{ - va_list va; - va_start(va, format); - vsyslog(LOG_ERR, format, va); - va_end(va); -} - -static void -strcln (char* data, char ch) -{ - char* p; - for (p = data; *data; data++, p++) { - while (*data == ch) - data++; - *p = *data; - } - /* null terminate */ - *p = 0; -} - -static void -stretrim (char* data) -{ - char* t = data + strlen (data); - while (t > data && isspace (*(t - 1))) { - t--; - *t = 0; - } -} - -static char* -strbtrim (const char* data) -{ - while (*data && isspace (*data)) - ++data; - return (char*)data; -} - -static char* -strtrim (char* data) -{ - data = (char*)strbtrim (data); - stretrim (data); - return data; -} - -static uint64_t -getcurrticks () -{ - struct timeval tp; - uint64_t t; - - /* Update tick count */ - if (gettimeofday (&tp, NULL) < 0) { - emsg ("couldn't get current time: %s", strerror (errno)); - return 0; - } - - t = (((uint64_t)tp.tv_sec) * 100) + (((uint64_t)tp.tv_usec) / 10000); - return t; -} - -#ifndef WITH_PCRE - -static const char* -regex_msg (int code) -{ - ASSERT (code != 0); - - switch (code) { - case REG_NOMATCH: - return "The regexec() function failed to match"; - case REG_BADPAT: - return "invalid regular expression"; - case REG_ECOLLATE: - return "invalid collating element"; - case REG_ECTYPE: - return "invalid character class"; - case REG_EESCAPE: - return "'\' applied to unescapable character"; - case REG_ESUBREG: - return "invalid backreference number"; - case REG_EBRACK: - return "brackets '[ ]' not balanced"; - case REG_EPAREN: - return "parentheses '( )' not balanced"; - case REG_EBRACE: - return "braces '{ }' not balanced"; - case REG_BADBR: - return "invalid repetition count(s) in '{ }'"; - case REG_ERANGE: - return "invalid character range in '[ ]'"; - case REG_ESPACE: - return "ran out of memory"; - case REG_BADRPT: - return "'?', '*', or '+' operand invalid"; - case REG_EMPTY: - return "empty (sub)expression"; - case REG_ILLSEQ: - return "illegal byte sequence (bad multibyte character)"; - - case REG_ASSERT: - case REG_INVARG: - default: - return "internal or unknown error"; - } -} - -#endif /* WITH_PCRE */ - -/* ----------------------------------------------------------------------------- - * MATCHING - */ - -static int -process_match (struct data_entry *data, char *result) -{ - char *t; - int i; - - switch(data->type) { - case TYPE_COUNTER: - data->value++; - break; - case TYPE_INTEGER: - if (!result) { - emsg ("match, but no result data for '%s'", data->descr); - return -1; - } - - i = strtol (result, &t, 10); - if (*t) { - emsg ("invalid integer for '%s': %s", data->descr, result); - return -1; - } - - data->value = i; - break; - - default: - ASSERT(0); - break; - } - - data->last_update = getcurrticks (); - - /* - fprintf(stderr, "updated '%s' to value '%lld' at '%lld'\n", - data->descr, data->value, data->last_update); - */ - - return 0; -} - -static char* -process_result (struct data_entry *data, char *line, int len, -#ifdef WITH_PCRE - int *ovector, int substrings) -#else - regmatch_t *pm) -#endif -{ - char *result; - char *p, *t; - int rlen, l; - int idx; - - /* Some nice little optimizations */ - if (!data->result) - return NULL; - if (strchr (data->result, '\\') == NULL) - return strdup (data->result); - - /* Figure out the string length */ - rlen = strlen (data->result) + 1; - for (p = data->result; *p; p++) { - if(p[0] == '\\') { - p++; - if(p[0] == '\\' || !isdigit(p[0])) - continue; - idx = p[0] - '0'; - ASSERT (idx >= 0 && idx <= 9); -#ifdef WITH_PCRE - if (idx < substrings) { - ASSERT (ovector[(idx * 2) + 1] >= ovector[idx * 2]); - ASSERT (ovector[(idx * 2) + 1] < len); - ASSERT (ovector[idx * 2] < len); - rlen += (ovector[(idx * 2) + 1]) - (ovector[idx * 2]); - rlen += 1; - } -#else /* WITH_PCRE */ - if (pm[idx].rm_so != -1 && pm[idx].rm_eo != -1) { - ASSERT (pm[idx].rm_eo >= pm[idx].rm_so); - ASSERT (pm[idx].rm_eo < len); - ASSERT (pm[idx].rm_so < len); - rlen += (pm[idx].rm_eo - pm[idx].rm_so); - rlen += 1; - } -#endif /* WITH_PCRE */ - } - } - - result = (char*)calloc(rlen, 1); - if (!result) { - emsg ("out of memory"); - return NULL; - } - - for (p = data->result, t = result; *p; p++) { - if (p[0] == '\\') { - p++; - if (isdigit(p[0])) { - idx = p[0] - '0'; -#ifdef WITH_PCRE - if (idx < substrings) { - l = (ovector[(idx * 2) + 1]) - (ovector[idx * 2]); - memcpy (t, line + (ovector[idx * 2]), l); - t += l; - } -#else /* WITH_PCRE */ - if (pm[idx].rm_so != -1 && pm[idx].rm_eo != -1) { - l = pm[idx].rm_eo - pm[idx].rm_so; - memcpy (t, line + pm[idx].rm_so, l); - t += l; - } -#endif /* WITH _PCRE */ - - continue; - } - } - - *t++ = *p; - } - - *t = 0; - return result; -} - -static void -process_log (char *line, int len) -{ - struct data_entry *data; - char *result; - int r; - -#ifdef WITH_PCRE - int ovector[30]; -#else - regmatch_t pm[10]; -#endif - - for (data = TAILQ_FIRST (&entries); data; - data = TAILQ_NEXT (data, link)) { - - result = NULL; - -#ifdef WITH_PCRE - memset (ovector, 0, sizeof (ovector)); - r = pcre_exec (data->regex, data->extra, line, len, 0, - PCRE_NOTEMPTY | PCRE_NO_UTF8_CHECK, ovector, 30); - - if (r == PCRE_ERROR_NOMATCH) - continue; - else if (r == PCRE_ERROR_NOMEMORY) { - emsg ("out of memory"); - return; - } else if (r < 0) { - emsg ("internal error in matching code: %d", r); - return; - } - - result = process_result (data, line, len, ovector, r); - -#else - r = regexec (&(data->regex), line, 10, pm, 0); - if (r == REG_NOMATCH) - continue; - else if (r != 0) { - emsg ("internal error in matching code: %d", r); - return; - } - - result = process_result (data, line, len, pm); -#endif - - process_match (data, result); - free (result); - } -} - -/* ----------------------------------------------------------------------------- - * LOG READING - */ - -static void -close_fifo () -{ - if (fifo_sel) { - fd_deselect (fifo_sel); - fifo_sel = NULL; - } - - if (fifo_fd != -1) { - close (fifo_fd); - fifo_fd = -1; - } - - memset (line_buffer, 0, sizeof (line_buffer)); -} - -static void -receive_log (int fd, void *data) -{ - char *t; - int len; - int r, l; - - ASSERT (fd == fifo_fd); - - len = strlen (line_buffer); - ASSERT (len < LINE_LENGTH); - - do { - r = read (fd, line_buffer + len, (LINE_LENGTH - 1) - len); - - if (r < 0 && errno != EAGAIN) { - emsg ("couldn't read from fifo: %s: %s", regex_fifo, strerror (errno)); - return; - - /* Got data, null terminate */ - } else if (r > 0) { - len += r; - ASSERT (len < LINE_LENGTH); - line_buffer[len] = 0; - } - - /* Break really long lines */ - if (len >= LINE_LENGTH - 1) - line_buffer[len - 1] = '\n'; - - for (;;) { - t = strchr (line_buffer, '\n'); - if (t == NULL) - break; - - /* Break line (also DOS line) */ - *t = 0; - if (line_buffer != t && *(t - 1) == '\r') - *(t - 1) = 0; - l = (t + 1) - line_buffer; - - /* Send it off */ - process_log (line_buffer, l); - - /* Move data to front of buffer */ - ASSERT (l <= len); - memmove (line_buffer, t + 1, (len - l) + 1); - len -= l; - } - - } while (r > 0); -} - -static int -open_fifo () -{ - struct stat sb; - - close_fifo (); - - ASSERT (regex_fifo && regex_fifo[0]); - - if (stat (regex_fifo, &sb) == 0) { - /* Complain if it's not a FIFO */ - if (!S_ISFIFO (sb.st_mode)) { - emsg ("file or directory already exists: %s", regex_fifo); - return -1; - } - - } else if (errno == ENOENT) { - /* Try and create it */ - if (mkfifo (regex_fifo, S_IRWXU | S_IRWXG | S_IRWXO) < 0) { - emsg ("couldn't create fifo: %s: %s", regex_fifo, strerror (errno)); - return -1; - } - - } else { - emsg ("couldn't access fifo: %s: %s", regex_fifo, strerror (errno)); - return -1; - } - - fifo_fd = open (regex_fifo, O_RDONLY | O_NONBLOCK); - if (fifo_fd < 0) { - emsg ("couldn't open fifo: %s: %s", regex_fifo, strerror (errno)); - return -1; - } - - fifo_sel = fd_select (fifo_fd, receive_log, NULL, module); - if (!fifo_sel) { - emsg ("couldn't listen on fifo: %s: %s", regex_fifo, strerror (errno)); - return -1; - } - - memset (line_buffer, 0, sizeof (line_buffer)); - return 0; -} - -/* ----------------------------------------------------------------------------- - * CONFIG PARSING - */ - -static void -config_free (struct data_entry *data) -{ -#ifdef WITH_PCRE - if (data->regex) - free (data->regex); - if (data->extra) - free (data->extra); -#else - regfree (&(data->regex)); -#endif - - free (data); -} - -static void -config_free_all () -{ - struct data_entry *data; - while ((data = TAILQ_FIRST(&entries)) != NULL) { - TAILQ_REMOVE (&entries, data, link); - config_free (data); - } -} - -static int -config_entry (struct data_entry *data, char *name, char type, char *regex, - char *result, char *flags, int line) -{ -#ifdef WITH_PCRE - const char *errptr; - int erroffset; - int options = 0; -#else - int options = REG_EXTENDED; - int r; -#endif - - ASSERT (regex); - ASSERT (flags); - ASSERT (data); - ASSERT (type); - ASSERT (name); - - /* Figure out the type first */ - switch (type) { - case 'c': - data->type = TYPE_COUNTER; - break; - case 'i': - data->type = TYPE_INTEGER; - break; - case '\0': - return -2; - default: - emsg ("[line %d] invalid or unknown entry type: %c", line, type); - return -1; - } - - /* Parse any options we have */ - for (; *flags; flags++) { - switch (flags[0]) { - case 'i': -#ifdef WITH_PCRE - options |= PCRE_CASELESS; -#else - options |= REG_ICASE; -#endif - break; - default: - emsg ("[line %d] invalid flag: %c", line, flags[0]); - return -1; - } - } - - /* The name */ - data->descr = name; - - /* Parse the regex */ -#ifdef WITH_PCRE - data->regex = pcre_compile (regex, options, &errptr, &erroffset, NULL); - if (!data->regex) { - emsg ("[line %d] invalid regular expression: %s", line, errptr); - return -1; - } - /* Optimize the regex, ignore errors */ - data->extra = pcre_study (data->regex, 0, &errptr); -#else - r = regcomp (&(data->regex), regex, options); - if (r != 0) { - emsg ("[line %d] invalid regular expression: %s", line, regex_msg (r)); - return -1; - } -#endif - - /* Replacement data */ - if (data->type != TYPE_COUNTER && !result) { - emsg ("[line %d] no match text specified in entry", line); - return -1; - } - data->result = result; - - return 0; -} - -static int -config_line (char *name, char *value, int line) -{ - struct data_entry *data; - char *regex = NULL; - char *result = NULL; - char *flags = NULL; - char type; - char delimiter; - char *t; - int r; - - /* config_parse trims this for us */ - ASSERT (!isspace(value[0])); - - /* The type of entry */ - type = value[0]; - ++value; - - /* Next thing is the delimiter */ - if (!*value) - return -2; - delimiter = value[0]; - ++value; - - /* Look for the next delimiter */ - t = strchr (value, delimiter); - if (!t) - return -2; - *t = 0; - regex = value; - value = t + 1; - - /* And the result */ - t = strchr (value, delimiter); - if (t) { - *t = 0; - t++; - result = value; - } - - /* The flags */ - flags = t ? t : value; - - /* Now populate an entry */ - data = (struct data_entry*)calloc(1, sizeof (*data)); - if (!data) { - emsg ("out of memory"); - return -1; - } - - /* Now make an entry out of it all */ - r = config_entry (data, name, type, regex, result, flags, line); - - if (r < 0) { - free (data); - return r; - } - - /* Put it in our table */ - data->index = entry_count++; - INSERT_OBJECT_INT (data, &entries); - - return 0; -} - -static int -config_read () -{ - FILE *f = NULL; - long len; - - ASSERT (regex_config && regex_config[0]); - - f = fopen (regex_config, "r"); - if (f == NULL) { - emsg ("couldn't open config file: %s", regex_config); - return -1; - } - - /* Figure out size */ - if (fseek (f, 0, SEEK_END) == -1 || (len = ftell (f)) == -1 || fseek (f, 0, SEEK_SET) == -1) { - emsg ("couldn't seek config file: %s", regex_config); - return -1; - } - - ASSERT (!config_memory); - - if ((config_memory = (char*)malloc (len + 2)) == NULL) { - emsg ("out of memory"); - return -1; - } - - /* And read in one block */ - if(fread(config_memory, 1, len, f) != len) { - emsg ("couldn't read config file: %s", regex_config); - free (config_memory); - config_memory = NULL; - return -1; - } - - fclose (f); - - /* Null terminate the data */ - config_memory[len] = '\n'; - config_memory[len + 1] = 0; - - return 0; -} - -static int -config_parse () -{ - char* next; - char* p; - char* t; - int line = 0; - int r; - - config_free_all (); - - /* Reads raw config file into config_memory */ - if (config_read () < 0) - return -1; - - ASSERT (config_memory); - - /* Remove nasty dos line endings */ - strcln(config_memory, '\r'); - - next = config_memory; - while ((t = strchr (next, '\n')) != NULL) { - - *t = 0; - p = next; - next = t + 1; - t = strbtrim (p); - line++; - - /* blank lines, comments */ - if (!*t || *t == '#') - continue; - - t = strchr (t, ':'); - if (t == NULL) { - emsg ("invalid config line: %s", p); - return -1; - } - - *t = 0; - t++; - - /* Pass of the name and value */ - r = config_line (strtrim (p), strtrim (t), line); - if (r < 0) { - - /* If -2 was returned, no error message was printed */ - if (r == -2) - emsg ("[line %d] invalid configuration file", line); - - return -1; - } - } - - return 0; -} - - -/* ----------------------------------------------------------------------------- - * CALLBACKS - */ - -int -op_regexconfig (struct snmp_context *ctx, struct snmp_value *value, - u_int sub, u_int iidx, enum snmp_op op) -{ - asn_subid_t which = value->var.subs[sub - 1]; - int r = SNMP_ERR_NOERROR; - - switch (which) { - case LEAF_regexConfig: - - if (op == SNMP_OP_GET) - return string_get (value, regex_config, -1); - - /* Remainder only at initialization */ - if (community != COMM_INITIALIZE) - return SNMP_ERR_NOT_WRITEABLE; - - switch (op) { - case SNMP_OP_SET: - if ((r = string_save (value, ctx, -1, ®ex_config)) == SNMP_ERR_NOERROR) { - if (!regex_config[0]) - r = SNMP_ERR_WRONG_VALUE; - else if (config_parse () < 0) - r = SNMP_ERR_GENERR; - } - if (r != SNMP_ERR_NOERROR) - string_rollback (ctx, ®ex_config); - break; - case SNMP_OP_COMMIT: - string_commit (ctx); - break; - case SNMP_OP_ROLLBACK: - string_rollback (ctx, ®ex_config); - break; - default: - ASSERT(0); - break; - } - - return r; - - - case LEAF_regexFifo: - - if (op == SNMP_OP_GET) - return string_get (value, regex_fifo, -1); - - /* Remainder only at initialization */ - if (community != COMM_INITIALIZE) - return SNMP_ERR_NOT_WRITEABLE; - - switch (op) { - case SNMP_OP_SET: - if ((r = string_save (value, ctx, -1, ®ex_fifo)) == SNMP_ERR_NOERROR) { - if (!regex_fifo[0]) - r = SNMP_ERR_WRONG_VALUE; - else if (open_fifo () < 0) - r = SNMP_ERR_GENERR; - } - if (r != SNMP_ERR_NOERROR) - string_rollback (ctx, ®ex_config); - break; - case SNMP_OP_COMMIT: - string_commit (ctx); - break; - case SNMP_OP_ROLLBACK: - string_rollback (ctx, ®ex_fifo); - break; - default: - ASSERT(0); - break; - } - - return r; - } - - ASSERT(0); - return -1; -} - -int -op_regex (struct snmp_context *ctx, struct snmp_value *value, - u_int sub, u_int iidx, enum snmp_op op) -{ - asn_subid_t which = value->var.subs[sub - 1]; - - switch (op) { - case SNMP_OP_GET: - break; - - case SNMP_OP_SET: - return SNMP_ERR_NOT_WRITEABLE; - - case SNMP_OP_ROLLBACK: - case SNMP_OP_COMMIT: - return SNMP_ERR_NOERROR; - - default: - ASSERT(0); - break; - } - - switch (which) { - case LEAF_regexCount: - value->v.integer = entry_count; - break; - - default: - ASSERT(0); - break; - } - - return SNMP_ERR_NOERROR; -} - -int -op_regexentry (struct snmp_context *ctx, struct snmp_value *value, - u_int sub, u_int iidx, enum snmp_op op) -{ - asn_subid_t which = value->var.subs[sub - 1]; - struct data_entry *data; - uint64_t ticks; - - switch (op) { - case SNMP_OP_GETNEXT: - data = NEXT_OBJECT_INT (&entries, &value->var, sub); - if (data == NULL) - return SNMP_ERR_NOSUCHNAME; - value->var.len = sub + 1; - value->var.subs[sub] = data->index; - break; - - case SNMP_OP_GET: - data = FIND_OBJECT_INT (&entries, &value->var, sub); - if (data == NULL) - return SNMP_ERR_NOSUCHNAME; - break; - - case SNMP_OP_SET: - if (index_decode (&value->var, sub, iidx, &data)) - return SNMP_ERR_NO_CREATION; - data = FIND_OBJECT_INT (&entries, &value->var, sub); - if (data != NULL) - return SNMP_ERR_NOT_WRITEABLE; - return SNMP_ERR_NO_CREATION; - - default: - ASSERT(0); - break; - } - - switch (which) { - case LEAF_regexIndex: - value->v.integer = data->index; - break; - - case LEAF_regexDescr: - return (string_get (value, data->descr, -1)); - - case LEAF_regexLast: - if (data->last_update) { - ticks = getcurrticks (); - if (ticks == 0) - return SNMP_ERR_GENERR; - value->v.uint32 = (ticks - data->last_update); - } else { - value->v.uint32 = 0; - } - break; - - case LEAF_regexValue: - value->v.uint32 = data->value; - break; - - default: - ASSERT(0); - break; - }; - - return SNMP_ERR_NOERROR; -} - -/* ----------------------------------------------------------------------------- - * MODULE - */ - -/* the initialisation function */ -static int -module_init (struct lmodule *mod, int argc, char *argv[]) -{ - module = mod; - - if (argc != 0) { - syslog(LOG_ERR, "bad number of arguments for %s", __func__); - return EINVAL; - } - - regex_config = strdup (DEFAULT_CONFIG); - if (!regex_config) - return ENOMEM; - - regex_fifo = strdup (DEFAULT_FIFO); - if (!regex_fifo) { - free (regex_config); - return ENOMEM; - } - - return 0; -} - -/* Module is started */ -static void -module_start (void) -{ - reg_index = or_register (&oid_regex, "The MIB for regex data.", module); - - /* Initial reads */ - receive_log (fifo_fd, NULL); -} - -/* Called, when the module is to be unloaded after it was successfully loaded */ -static int -module_fini (void) -{ - if (reg_index) - or_unregister (reg_index); - - ASSERT (regex_config); - free (regex_config); - - ASSERT (regex_fifo); - free (regex_fifo); - - close_fifo (); - config_free_all (); - - return 0; -} - -const struct snmp_module config = { - .comment = "This module implements SNMP listing of data from regular expressions", - .init = module_init, - .start = module_start, - .fini = module_fini, - .tree = regex_ctree, - .tree_size = regex_CTREE_SIZE, -}; - - diff --git a/src/regex-tree.def b/src/regex-tree.def deleted file mode 100644 index 3305ada..0000000 --- a/src/regex-tree.def +++ /dev/null @@ -1,20 +0,0 @@ -(1 internet - (4 private - (1 enterprises - (10277 regexData - - # Valid only during configuration - (0 regexConfig OCTETSTRING op_regexconfig GET SET) - (1 regexFifo OCTETSTRING op_regexconfig GET SET) - - (10 regexCount INTEGER op_regex GET) - (11 regexEntry : INTEGER op_regexentry - (1 regexIndex INTEGER GET) - (2 regexDescr OCTETSTRING GET) - (3 regexLast TIMETICKS GET) - (4 regexValue INTEGER GET) - ) - ) - ) - ) -) diff --git a/src/usuals.h b/src/usuals.h deleted file mode 100644 index 6dc7b08..0000000 --- a/src/usuals.h +++ /dev/null @@ -1,32 +0,0 @@ - -#ifndef __USUALS_H__ -#define __USUALS_H__ - -#include - -#include "config.h" - -#include -#include -#include -#include -#include - -#ifndef max -#define max(a,b) (((a) > (b)) ? (a) : (b)) -#endif - -#ifndef min -#define min(a,b) (((a) < (b)) ? (a) : (b)) -#endif - -#define countof(x) (sizeof(x) / sizeof(x[0])) - -#ifdef _DEBUG - #include "assert.h" - #define ASSERT(x) assert(x) -#else - #define ASSERT(x) -#endif - -#endif /* __USUALS_H__ */ -- cgit v1.2.3