diff options
Diffstat (limited to 'agent/mibgroup/ucd-snmp/logmatch.c')
-rw-r--r-- | agent/mibgroup/ucd-snmp/logmatch.c | 651 |
1 files changed, 651 insertions, 0 deletions
diff --git a/agent/mibgroup/ucd-snmp/logmatch.c b/agent/mibgroup/ucd-snmp/logmatch.c new file mode 100644 index 0000000..abca5ce --- /dev/null +++ b/agent/mibgroup/ucd-snmp/logmatch.c @@ -0,0 +1,651 @@ +/* Portions of this file are subject to the following copyrights. See + * the Net-SNMP's COPYING file for more details and other copyrights + * that may apply: + */ +/* + * Copyright © 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms specified in the COPYING file + * distributed with the Net-SNMP package. + */ +#include <net-snmp/net-snmp-config.h> + +#include "logmatch.h" + +#ifdef HAVE_REGEX_H + +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <regex.h> +#include <time.h> + +#include <net-snmp/net-snmp-includes.h> +#include <net-snmp/agent/net-snmp-agent-includes.h> + +#include "util_funcs/header_generic.h" +#include "util_funcs/header_simple_table.h" + +/* + * ------------------------------------------------ + * This function checks if the filename pattern + * contains the % character indicating a variable + * filename (i.e. it uses date/time format control + * codes, see 'man date') then expands those control + * codes based on current time and sets the + * filename field in the struct. + * Returns 1 if the filename changed, 0 otherwise + * ------------------------------------------------- + */ + +static int +logmatch_update_filename(const char * pattern, char * currentFilename) +{ + time_t t; + struct tm *tmp; + char newFilename[256]; + + /* + * ------------------------------------------------------------------- + * if the filename pattern doesn't have the "%" character just return, + * since there is no need for further processing + * ------------------------------------------------------------------- + */ + if (strchr(pattern, '%') == NULL) { + return 0; + } + + t = time(NULL); + tmp = localtime(&t); + + if (tmp == NULL) { + perror("localtime"); + return 0; + } + + /* result of expansion must fit into newFilename, otherwise returning */ + if (strftime(newFilename, sizeof(newFilename), pattern, tmp) == 0) { + return 0; + } + + /* if same as current filename, just return */ + if (strcmp(currentFilename, newFilename) == 0) { + return 0; + } else { + /* otherwise update currentFilename and return 1 */ + strcpy(currentFilename, newFilename); + return 1; + } +} + +struct logmatchstat { + char filenamePattern[256]; + char filename[256]; + char regEx[256]; + char name[256]; + FILE *logfile; + long currentFilePosition; + unsigned long globalMatchCounter; + unsigned long currentMatchCounter; + unsigned long matchCounter; + regex_t regexBuffer; + int myRegexError; + int virgin; + int thisIndex; + int frequency; +}; + +#define MAXLOGMATCH 250 + +static struct logmatchstat logmatchTable[MAXLOGMATCH]; +static int logmatchCount = 0; + +/*************************************************************** +* * +* updateLogmatch * +* this function is called back by snmpd alarms * +* * +***************************************************************/ + +static void +updateLogmatch(int iindex) +{ + + int matchResultCode; + char inbuf[1024]; + char perfilename[1024]; + FILE *perfile; + unsigned long pos, ccounter, counter; + int result; + int toobig; + int anyChanges = FALSE; + struct stat sb; + char lastFilename[256]; + + /* + * ------------------------------------ + * we can never be sure if this is the + * last time we are being called here, + * so we always update a persistent + * data file with our current file + * position + * ------------------------------------ + */ + + snprintf(perfilename, sizeof(perfilename), "%s/snmpd_logmatch_%s.pos", + get_persistent_directory(), logmatchTable[iindex].name); + + if (logmatchTable[iindex].virgin) { + + /* + * ------------------------------------ + * this is the first time we are being + * called; let's try to find an old + * file position stored in a persistent + * data file and restore it + * ------------------------------------ + */ + + if ((perfile = fopen(perfilename, "r"))) { + + /* + * ------------------------------------ + * the persistent data file exists so + * let's read it out + * ------------------------------------ + */ + + + pos = counter = ccounter = 0; + + if (fscanf(perfile, "%lu %lu %lu %s", + &pos, &ccounter, &counter, lastFilename)) { + + + /* + * ------------------------------------ + * the data could be read; now let's + * try to open the logfile to be + * scanned + * ------------------------------------ + */ + + if (logmatch_update_filename(logmatchTable[iindex].filenamePattern, + lastFilename) == 0) { + + /* + * --------------------------------- + * the filename is still the same as + * the one stored in the persistent + * data file. + * --------------------------------- + */ + + if ((logmatchTable[iindex].logfile = + fopen(logmatchTable[iindex].filename, "r"))) { + + + /* + * ------------------------------------ + * the log file could be opened; now + * let's try to set the pointer + * ------------------------------------ + */ + + if (!fseek + (logmatchTable[iindex].logfile, pos, SEEK_SET)) { + + + /* + * ------------------------------------ + * the pointer could be set - this is + * the most that we can do: if the + * pointer is smaller than the file + * size we must assume that the pointer + * still points to where it read the + * file last time; let's restore the + * data + * ------------------------------------ + */ + + logmatchTable[iindex].currentFilePosition = pos; + logmatchTable[iindex].currentMatchCounter = + ccounter; + } + + fclose(logmatchTable[iindex].logfile); + } + } + logmatchTable[iindex].globalMatchCounter = counter; + } + + fclose(perfile); + } + + logmatchTable[iindex].virgin = FALSE; + } + + /* + * ------------------------------------------- + * check if a new input file needs to be opened + * if yes, reset counter and position + * ------------------------------------------- + */ + + if (logmatch_update_filename(logmatchTable[iindex].filenamePattern, + logmatchTable[iindex].filename) == 1) { + logmatchTable[iindex].currentFilePosition = 0; + logmatchTable[iindex].currentMatchCounter = 0; + } + + + /* + * ------------------------------------ + * now the pointer and the counter are + * set either zero or reset to old + * value; now let's try to read some + * data + * ------------------------------------ + */ + + if (stat(logmatchTable[iindex].filename, &sb) == 0) { + + if (logmatchTable[iindex].currentFilePosition > sb.st_size) { + toobig = TRUE; + } else { + toobig = FALSE; + } + + if ((logmatchTable[iindex].logfile = + fopen(logmatchTable[iindex].filename, "r"))) { + + result = + fseek(logmatchTable[iindex].logfile, + logmatchTable[iindex].currentFilePosition, SEEK_SET); + + if (result || toobig || (errno == EINVAL) + || feof(logmatchTable[iindex].logfile)) { + + + /* + * ------------------------------------ + * when we are here that means we + * could't set the file position maybe + * the file was rotated; let's reset + * the filepointer, but not the counter + * ------------------------------------ + */ + + + logmatchTable[iindex].currentFilePosition = 0; + logmatchTable[iindex].currentMatchCounter = 0; + fseek(logmatchTable[iindex].logfile, 0, SEEK_SET); + anyChanges = TRUE; + } + + while (fgets + (inbuf, sizeof(inbuf), logmatchTable[iindex].logfile)) { + + matchResultCode = + regexec(&(logmatchTable[iindex].regexBuffer), + inbuf, 0, NULL, REG_NOTEOL); + + if (matchResultCode == 0) { + logmatchTable[iindex].globalMatchCounter++; + logmatchTable[iindex].currentMatchCounter++; + logmatchTable[iindex].matchCounter++; + anyChanges = TRUE; + } + } + + logmatchTable[iindex].currentFilePosition = + ftell(logmatchTable[iindex].logfile); + fclose(logmatchTable[iindex].logfile); + } + } + + + /* + * ------------------------------------ + * at this point we can be safe that + * our current file position is + * straightened out o.k. - we never + * know if this is the last time we are + * being called so save the position + * in a file + * ------------------------------------ + */ + + if (anyChanges && (perfile = fopen(perfilename, "w"))) { + + + /* + * ------------------------------------ + * o.k. lets write out our variable + * ------------------------------------ + */ + + fprintf(perfile, "%lu %lu %lu %s\n", + logmatchTable[iindex].currentFilePosition, + logmatchTable[iindex].currentMatchCounter, + logmatchTable[iindex].globalMatchCounter, + logmatchTable[iindex].filename); + + fclose(perfile); + } + +} + + +static void +updateLogmatch_Scheduled(unsigned int registrationNumber, + struct logmatchstat *logmatchtable) +{ + updateLogmatch(logmatchtable->thisIndex); +} + +/*************************************************************** +* * +* logmatch_parse_config * +* parse one line from snmpd.conf * +* * +***************************************************************/ + +static void +logmatch_parse_config(const char *token, char *cptr) +{ + + char space_name; + char space_path; + + if (logmatchCount < MAXLOGMATCH) { + logmatchTable[logmatchCount].frequency = 30; + logmatchTable[logmatchCount].thisIndex = logmatchCount; + + + /* + * ------------------------------------ + * be careful this counter needs to be + * reset from persistent storage + * ------------------------------------ + */ + + logmatchTable[logmatchCount].globalMatchCounter = 0; + logmatchTable[logmatchCount].currentMatchCounter = 0; + logmatchTable[logmatchCount].matchCounter = 0; + logmatchTable[logmatchCount].virgin = TRUE; + logmatchTable[logmatchCount].currentFilePosition = 0; + + + /* + * ------------------------------------ + * be careful: the flag 255 must fit to + * the size of regEx as definded in + * logmatch.h + * ------------------------------------ + */ + + sscanf(cptr, "%255s%c%255s%c %d %255c\n", + logmatchTable[logmatchCount].name, + &space_name, + logmatchTable[logmatchCount].filenamePattern, + &space_path, + &(logmatchTable[logmatchCount].frequency), + logmatchTable[logmatchCount].regEx); + + /* fill in filename with initial data */ + strcpy(logmatchTable[logmatchCount].filename, + logmatchTable[logmatchCount].filenamePattern); + logmatch_update_filename(logmatchTable[logmatchCount].filenamePattern, + logmatchTable[logmatchCount].filename); + + /* + * Log an error then return if any of the strings scanned in were + * larger then they should have been. + */ + if (space_name != ' ') { + snmp_log(LOG_ERR, "logmatch_parse_config: the name scanned " \ + "in from line %s is too large. logmatchCount = %d\n", + cptr, logmatchCount); + return; + } else if (space_path != ' ') { + snmp_log(LOG_ERR, "logmatch_parse_config: the file name " \ + "scanned in from line %s is too large. logmatchCount = %d\n", + cptr, logmatchCount); + return; + } + + /* + * ------------------------------------ + * just to be safe "NULL" the end of + * the arary regEx as sscanf won't do + * it with the %c modifier + * ------------------------------------ + */ + + logmatchTable[logmatchCount].regEx[255] = '\0'; + + + /* + * ------------------------------------ + * now compile the regular expression + * ------------------------------------ + */ + + logmatchTable[logmatchCount].myRegexError = + regcomp(&(logmatchTable[logmatchCount].regexBuffer), + logmatchTable[logmatchCount].regEx, + REG_EXTENDED | REG_NOSUB); + + if (logmatchTable[logmatchCount].frequency > 0) { + snmp_alarm_register(logmatchTable[logmatchCount].frequency, + SA_REPEAT, + (SNMPAlarmCallback *) + updateLogmatch_Scheduled, + &(logmatchTable[logmatchCount]) + ); + } + + logmatchCount++; + } +} + +/*************************************************************** +* * +* logmatch_free_config * +* free memory allocated by this mib module * +* * +***************************************************************/ + +static void +logmatch_free_config(void) +{ + int i; + + /* + * ------------------------------------ + * the only memory we have allocated + * is the memory allocated by regcomp + * ------------------------------------ + */ + + for (i = 0; i < logmatchCount; i++) { + + regfree(&(logmatchTable[i].regexBuffer)); + } + logmatchCount = 0; +} + + +#define LOGMATCH_INFO 0 +#define LOGMATCH_INDEX 1 +#define LOGMATCH_NAME 2 +#define LOGMATCH_FILENAME 3 +#define LOGMATCH_REGEX 4 +#define LOGMATCH_GLOBALCTR 5 +#define LOGMATCH_GLOBALCNT 6 +#define LOGMATCH_CURRENTCTR 7 +#define LOGMATCH_CURRENTCNT 8 +#define LOGMATCH_COUNTER 9 +#define LOGMATCH_COUNT 10 +#define LOGMATCH_FREQ 11 +#define LOGMATCH_ERROR 100 +#define LOGMATCH_MSG 101 + +/* + * OID functions + */ + +static u_char * +var_logmatch_table(struct variable *vp, + oid * name, + size_t * length, + int exact, + size_t * var_len, WriteMethod ** write_method) +{ + static long long_ret; + static char message[1024]; + int iindex; + struct logmatchstat *logmatch; + + if (vp->magic == LOGMATCH_INFO) { + if (header_generic(vp, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return (NULL); + } else { + if (header_simple_table + (vp, name, length, exact, var_len, write_method, + logmatchCount)) + return (NULL); + } + + + iindex = name[*length - 1] - 1; + logmatch = &logmatchTable[iindex]; + + if (logmatch->myRegexError == 0) + updateLogmatch(iindex); + + switch (vp->magic) { + case LOGMATCH_INFO: + long_ret = MAXLOGMATCH; + return (u_char *) & long_ret; + + case LOGMATCH_INDEX: + long_ret = iindex + 1; + return (u_char *) & long_ret; + + case LOGMATCH_NAME: + *var_len = strlen(logmatch->name); + return (u_char *) logmatch->name; + + case LOGMATCH_FILENAME: + *var_len = strlen(logmatch->filename); + return (u_char *) logmatch->filename; + + case LOGMATCH_REGEX: + *var_len = strlen(logmatch->regEx); + return (u_char *) logmatch->regEx; + + case LOGMATCH_GLOBALCTR: + case LOGMATCH_GLOBALCNT: + long_ret = (logmatch->globalMatchCounter); + return (u_char *) & long_ret; + + case LOGMATCH_CURRENTCTR: + case LOGMATCH_CURRENTCNT: + long_ret = (logmatch->currentMatchCounter); + return (u_char *) & long_ret; + + case LOGMATCH_COUNTER: + case LOGMATCH_COUNT: + long_ret = (logmatch->matchCounter); + logmatch->matchCounter = 0; + return (u_char *) & long_ret; + + case LOGMATCH_FREQ: + long_ret = logmatch->frequency; + return (u_char *) & long_ret; + + case LOGMATCH_ERROR: + if (logmatch->frequency >= 0 && logmatch->myRegexError == 0) + long_ret = 0; + else + long_ret = 1; + + return (u_char *) & long_ret; + + case LOGMATCH_MSG: + + regerror(logmatch->myRegexError, &(logmatch->regexBuffer), message, + sizeof(message)); + + *var_len = strlen(message); + return (u_char *) message; + + default: + DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_logmatch_table\n", + vp->magic)); + } + + return NULL; +} + +void +init_logmatch(void) +{ + struct variable2 logmatch_info[] = { + {LOGMATCH_INFO, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, + var_logmatch_table, 0} + }; + + struct variable2 logmatch_table[] = { + {LOGMATCH_INDEX, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, + var_logmatch_table, 1, {1}}, + {LOGMATCH_NAME, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY, + var_logmatch_table, 1, {2}}, + {LOGMATCH_FILENAME, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY, + var_logmatch_table, 1, {3}}, + {LOGMATCH_REGEX, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY, + var_logmatch_table, 1, {4}}, + {LOGMATCH_GLOBALCTR, ASN_COUNTER, NETSNMP_OLDAPI_RONLY, + var_logmatch_table, 1, {5}}, + {LOGMATCH_GLOBALCNT, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, + var_logmatch_table, 1, {6}}, + {LOGMATCH_CURRENTCTR, ASN_COUNTER, NETSNMP_OLDAPI_RONLY, + var_logmatch_table, 1, {7}}, + {LOGMATCH_CURRENTCNT, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, + var_logmatch_table, 1, {8}}, + {LOGMATCH_COUNTER, ASN_COUNTER, NETSNMP_OLDAPI_RONLY, + var_logmatch_table, 1, {9}}, + {LOGMATCH_COUNT, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, + var_logmatch_table, 1, {10}}, + {LOGMATCH_FREQ, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, + var_logmatch_table, 1, {11}}, + {LOGMATCH_ERROR, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, + var_logmatch_table, 1, {100}}, + {LOGMATCH_MSG, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY, + var_logmatch_table, 1, {101}} + }; + + /* + * Define the OID pointer to the top of the mib tree that we're + * registering underneath + */ + oid logmatch_info_oid[] = { NETSNMP_UCDAVIS_MIB, 16, 1 }; + oid logmatch_variables_oid[] = { NETSNMP_UCDAVIS_MIB, 16, 2, 1 }; + + /* + * register ourselves with the agent to handle our mib tree + */ + REGISTER_MIB("ucd-snmp/logmatch", logmatch_info, variable2, + logmatch_info_oid); + REGISTER_MIB("ucd-snmp/logmatch", logmatch_table, variable2, + logmatch_variables_oid); + + snmpd_register_config_handler("logmatch", logmatch_parse_config, + logmatch_free_config, + "logmatch name path cycletime regex"); + +} + +#endif /* HAVE_REGEX_H */ |