Blame agent/mibgroup/disman/event/mteTrigger.c.coverity

Packit 74c279
/*
Packit 74c279
 * DisMan Event MIB:
Packit 74c279
 *     Core implementation of the trigger handling behaviour
Packit 74c279
 */
Packit 74c279
Packit 74c279
#include <net-snmp/net-snmp-config.h>
Packit 74c279
#include <net-snmp/net-snmp-features.h>
Packit 74c279
#include <net-snmp/net-snmp-includes.h>
Packit 74c279
#include <net-snmp/agent/net-snmp-agent-includes.h>
Packit 74c279
#include "agent_global_vars.h"
Packit 74c279
#include "disman/event/mteTrigger.h"
Packit 74c279
#include "disman/event/mteEvent.h"
Packit 74c279
Packit 74c279
netsnmp_feature_child_of(disman_debugging, libnetsnmpmibs)
Packit 74c279
netsnmp_feature_child_of(mtetrigger, libnetsnmpmibs)
Packit 74c279
netsnmp_feature_child_of(mtetrigger_removeentry, mtetrigger)
Packit 74c279
Packit 74c279
netsnmp_tdata *trigger_table_data;
Packit 74c279
Packit 74c279
oid    _sysUpTime_instance[] = { 1, 3, 6, 1, 2, 1, 1, 3, 0 };
Packit 74c279
size_t _sysUpTime_inst_len   = OID_LENGTH(_sysUpTime_instance);
Packit 74c279
Packit 74c279
long mteTriggerFailures;
Packit 74c279
Packit 74c279
    /*
Packit 74c279
     * Initialize the container for the (combined) mteTrigger*Table,
Packit 74c279
     * regardless of which table initialisation routine is called first.
Packit 74c279
     */
Packit 74c279
Packit 74c279
void
Packit 74c279
init_trigger_table_data(void)
Packit 74c279
{
Packit 74c279
    DEBUGMSGTL(("disman:event:init", "init trigger container\n"));
Packit 74c279
    if (!trigger_table_data) {
Packit 74c279
        trigger_table_data = netsnmp_tdata_create_table("mteTriggerTable", 0);
Packit 74c279
        if (!trigger_table_data) {
Packit 74c279
            snmp_log(LOG_ERR, "failed to create mteTriggerTable");
Packit 74c279
            return;
Packit 74c279
        }
Packit 74c279
        DEBUGMSGTL(("disman:event:init", "create trigger container (%p)\n",
Packit 74c279
                                          trigger_table_data));
Packit 74c279
    }
Packit 74c279
    mteTriggerFailures = 0;
Packit 74c279
}
Packit 74c279
Packit 74c279
Packit 74c279
/** Initializes the mteTrigger module */
Packit 74c279
void
Packit 74c279
init_mteTrigger(void)
Packit 74c279
{
Packit 74c279
    init_trigger_table_data();
Packit 74c279
Packit 74c279
}
Packit 74c279
Packit 74c279
    /* ===================================================
Packit 74c279
     *
Packit 74c279
     * APIs for maintaining the contents of the (combined)
Packit 74c279
     *    mteTrigger*Table container.
Packit 74c279
     *
Packit 74c279
     * =================================================== */
Packit 74c279
Packit 74c279
#ifndef NETSNMP_FEATURE_REMOVE_DISMAN_DEBUGGING
Packit 74c279
void
Packit 74c279
_mteTrigger_dump(void)
Packit 74c279
{
Packit 74c279
    struct mteTrigger *entry;
Packit 74c279
    netsnmp_tdata_row *row;
Packit 74c279
    int i = 0;
Packit 74c279
Packit 74c279
    for (row = netsnmp_tdata_row_first(trigger_table_data);
Packit 74c279
         row;
Packit 74c279
         row = netsnmp_tdata_row_next(trigger_table_data, row)) {
Packit 74c279
        entry = (struct mteTrigger *)row->data;
Packit 74c279
        DEBUGMSGTL(("disman:event:dump", "TriggerTable entry %d: ", i));
Packit 74c279
        DEBUGMSGOID(("disman:event:dump", row->oid_index.oids, row->oid_index.len));
Packit 74c279
        DEBUGMSG(("disman:event:dump", "(%s, %s)",
Packit 74c279
                                         row->indexes->val.string,
Packit 74c279
                                         row->indexes->next_variable->val.string));
Packit 74c279
        DEBUGMSG(("disman:event:dump", ": %p, %p\n", row, entry));
Packit 74c279
        i++;
Packit 74c279
    }
Packit 74c279
    DEBUGMSGTL(("disman:event:dump", "TriggerTable %d entries\n", i));
Packit 74c279
}
Packit 74c279
#endif /* NETSNMP_FEATURE_REMOVE_DISMAN_DEBUGGING */
Packit 74c279
Packit 74c279
/*
Packit 74c279
 * Create a new row in the trigger table 
Packit 74c279
 */
Packit 74c279
netsnmp_tdata_row *
Packit 74c279
mteTrigger_createEntry(const char *mteOwner, char *mteTName, int fixed)
Packit 74c279
{
Packit 74c279
    struct mteTrigger *entry;
Packit 74c279
    netsnmp_tdata_row *row;
Packit 74c279
    size_t mteOwner_len = (mteOwner) ? strlen(mteOwner) : 0;
Packit 74c279
    size_t mteTName_len = (mteTName) ? strlen(mteTName) : 0;
Packit 74c279
Packit 74c279
    DEBUGMSGTL(("disman:event:table", "Create trigger entry (%s, %s)\n",
Packit 74c279
                                       mteOwner, mteTName));
Packit 74c279
    /*
Packit 74c279
     * Create the mteTrigger entry, and the
Packit 74c279
     * (table-independent) row wrapper structure...
Packit 74c279
     */
Packit 74c279
    entry = SNMP_MALLOC_TYPEDEF(struct mteTrigger);
Packit 74c279
    if (!entry)
Packit 74c279
        return NULL;
Packit 74c279
Packit 74c279
    row = netsnmp_tdata_create_row();
Packit 74c279
    if (!row) {
Packit 74c279
        SNMP_FREE(entry);
Packit 74c279
        return NULL;
Packit 74c279
    }
Packit 74c279
    row->data = entry;
Packit 74c279
Packit 74c279
    /*
Packit 74c279
     * ... initialize this row with the indexes supplied
Packit 74c279
     *     and the default values for the row...
Packit 74c279
     */
Packit 74c279
    if (mteOwner)
Packit 74c279
        memcpy(entry->mteOwner, mteOwner, mteOwner_len);
Packit 74c279
    netsnmp_table_row_add_index(row, ASN_OCTET_STR,
Packit 74c279
                                entry->mteOwner, mteOwner_len);
Packit 74c279
    if (mteTName)
Packit 74c279
        memcpy(entry->mteTName, mteTName, mteTName_len);
Packit 74c279
    netsnmp_table_row_add_index(row, ASN_PRIV_IMPLIED_OCTET_STR,
Packit 74c279
                                entry->mteTName, mteTName_len);
Packit 74c279
Packit 74c279
  /* entry->mteTriggerTest         = MTE_TRIGGER_BOOLEAN; */
Packit 74c279
    entry->mteTriggerValueID_len  = 2;  /* .0.0 */
Packit 74c279
    entry->mteTriggerFrequency    = 600;
Packit 74c279
    memcpy(entry->mteDeltaDiscontID, _sysUpTime_instance,
Packit 74c279
                              sizeof(_sysUpTime_instance));
Packit 74c279
    entry->mteDeltaDiscontID_len  =  _sysUpTime_inst_len;
Packit 74c279
    entry->mteDeltaDiscontIDType  = MTE_DELTAD_TTICKS;
Packit 74c279
    entry->flags                 |= MTE_TRIGGER_FLAG_SYSUPT;
Packit 74c279
    entry->mteTExTest             = (MTE_EXIST_PRESENT | MTE_EXIST_ABSENT);
Packit 74c279
    entry->mteTExStartup          = (MTE_EXIST_PRESENT | MTE_EXIST_ABSENT);
Packit 74c279
    entry->mteTBoolComparison     = MTE_BOOL_UNEQUAL;
Packit 74c279
    entry->flags                 |= MTE_TRIGGER_FLAG_BSTART;
Packit 74c279
    entry->mteTThStartup          = MTE_THRESH_START_RISEFALL;
Packit 74c279
Packit 74c279
    if (fixed)
Packit 74c279
        entry->flags |= MTE_TRIGGER_FLAG_FIXED;
Packit 74c279
Packit 74c279
    /*
Packit 74c279
     * ... and insert the row into the (common) table container
Packit 74c279
     */
Packit 74c279
    netsnmp_tdata_add_row(trigger_table_data, row);
Packit 74c279
    DEBUGMSGTL(("disman:event:table", "Trigger entry created\n"));
Packit 74c279
    return row;
Packit 74c279
}
Packit 74c279
Packit 74c279
#ifndef NETSNMP_FEATURE_REMOVE_MTETRIGGER_REMOVEENTRY
Packit 74c279
/*
Packit 74c279
 * Remove a row from the trigger table 
Packit 74c279
 */
Packit 74c279
void
Packit 74c279
mteTrigger_removeEntry(netsnmp_tdata_row *row)
Packit 74c279
{
Packit 74c279
    struct mteTrigger *entry;
Packit 74c279
Packit 74c279
    if (!row)
Packit 74c279
        return;                 /* Nothing to remove */
Packit 74c279
    entry = (struct mteTrigger *)
Packit 74c279
        netsnmp_tdata_remove_and_delete_row(trigger_table_data, row);
Packit 74c279
    if (entry) {
Packit 74c279
        mteTrigger_disable( entry );
Packit 74c279
        SNMP_FREE(entry);
Packit 74c279
    }
Packit 74c279
}
Packit 74c279
#endif /* NETSNMP_FEATURE_REMOVE_MTETRIGGER_REMOVEENTRY */
Packit 74c279
Packit 74c279
    /* ===================================================
Packit 74c279
     *
Packit 74c279
     * APIs for evaluating a trigger,
Packit 74c279
     *   and firing the appropriate event
Packit 74c279
     *
Packit 74c279
     * =================================================== */
Packit 74c279
const char *_ops[] = { "",
Packit 74c279
                "!=", /* MTE_BOOL_UNEQUAL      */
Packit 74c279
                "==", /* MTE_BOOL_EQUAL        */
Packit 74c279
                "<",  /* MTE_BOOL_LESS         */
Packit 74c279
                "<=", /* MTE_BOOL_LESSEQUAL    */
Packit 74c279
                ">",  /* MTE_BOOL_GREATER      */
Packit 74c279
                ">="  /* MTE_BOOL_GREATEREQUAL */  };
Packit 74c279
Packit 74c279
void
Packit 74c279
_mteTrigger_failure( /* int error, */ const char *msg )
Packit 74c279
{
Packit 74c279
    /*
Packit 74c279
     * XXX - Send an mteTriggerFailure trap
Packit 74c279
     *           (if configured to do so)
Packit 74c279
     */
Packit 74c279
    mteTriggerFailures++;
Packit 74c279
    snmp_log(LOG_ERR, "%s\n", msg );
Packit 74c279
    return;
Packit 74c279
}
Packit 74c279
Packit 74c279
void
Packit 74c279
mteTrigger_run( unsigned int reg, void *clientarg)
Packit 74c279
{
Packit 74c279
    struct mteTrigger *entry = (struct mteTrigger *)clientarg;
Packit 74c279
    netsnmp_variable_list *var, *vtmp;
Packit 74c279
    netsnmp_variable_list *vp1, *vp1_prev;
Packit 74c279
    netsnmp_variable_list *vp2, *vp2_prev;
Packit 74c279
    netsnmp_variable_list *dvar = NULL;
Packit 74c279
    netsnmp_variable_list *dv1  = NULL, *dv2 = NULL;
Packit 74c279
    netsnmp_variable_list sysUT_var;
Packit 74c279
    int  cmp = 0, n, n2;
Packit 74c279
    long value;
Packit 74c279
    const char *reason;
Packit 74c279
Packit 74c279
    if (!entry) {
Packit 74c279
        snmp_alarm_unregister( reg );
Packit 74c279
        return;
Packit 74c279
    }
Packit 74c279
    if (!(entry->flags & MTE_TRIGGER_FLAG_ENABLED ) ||
Packit 74c279
        !(entry->flags & MTE_TRIGGER_FLAG_ACTIVE  ) ||
Packit 74c279
        !(entry->flags & MTE_TRIGGER_FLAG_VALID  )) {
Packit 74c279
        return;
Packit 74c279
    }
Packit 74c279
Packit 74c279
    {
Packit 74c279
	if (netsnmp_processing_set) {
Packit 74c279
	    /*
Packit 74c279
	     * netsnmp_handle_request will not be responsive to our efforts to
Packit 74c279
	     *	Retrieve the requested MIB value(s)...
Packit 74c279
	     * so we will skip it.
Packit 74c279
	     * https://sourceforge.net/tracker/
Packit 74c279
	     *	index.php?func=detail&aid=1557406&group_id=12694&atid=112694
Packit 74c279
	     */
Packit 74c279
	    DEBUGMSGTL(("disman:event:trigger:monitor",
Packit 74c279
		"Skipping trigger (%s) while netsnmp_processing_set\n",
Packit 74c279
		entry->mteTName));
Packit 74c279
	    return;
Packit 74c279
	}
Packit 74c279
    }
Packit 74c279
Packit 74c279
    /*
Packit 74c279
     * Retrieve the requested MIB value(s)...
Packit 74c279
     */
Packit 74c279
    DEBUGMSGTL(( "disman:event:trigger:monitor", "Running trigger (%s)\n", entry->mteTName));
Packit 74c279
    var = (netsnmp_variable_list *)SNMP_MALLOC_TYPEDEF( netsnmp_variable_list );
Packit 74c279
    if (!var) {
Packit 74c279
        _mteTrigger_failure("failed to create mteTrigger query varbind");
Packit 74c279
        return;
Packit 74c279
    }
Packit 74c279
    snmp_set_var_objid( var, entry->mteTriggerValueID,
Packit 74c279
                             entry->mteTriggerValueID_len );
Packit 74c279
    if ( entry->flags & MTE_TRIGGER_FLAG_VWILD ) {
Packit 74c279
        n = netsnmp_query_walk( var, entry->session );
Packit 74c279
    } else {
Packit 74c279
        n = netsnmp_query_get(  var, entry->session );
Packit 74c279
    }
Packit 74c279
    if ( n != SNMP_ERR_NOERROR ) {
Packit 74c279
        DEBUGMSGTL(( "disman:event:trigger:monitor", "Trigger query (%s) failed: %d\n",
Packit 74c279
                           (( entry->flags & MTE_TRIGGER_FLAG_VWILD ) ? "walk" : "get"), n));
Packit 74c279
        _mteTrigger_failure( "failed to run mteTrigger query" );
Packit 74c279
        snmp_free_varbind(var);
Packit 74c279
        return;
Packit 74c279
    }
Packit 74c279
Packit 74c279
    /*
Packit 74c279
     * ... canonicalise the results (to simplify later comparisons)...
Packit 74c279
     */
Packit 74c279
Packit 74c279
    vp1 = var;                vp1_prev = NULL;
Packit 74c279
    vp2 = entry->old_results; vp2_prev = NULL;
Packit 74c279
    entry->count=0;
Packit 74c279
    while (vp1) {
Packit 74c279
           /*
Packit 74c279
            * Flatten various missing values/exceptions into a single form
Packit 74c279
            */ 
Packit 74c279
	switch (vp1->type) {
Packit 74c279
        case SNMP_NOSUCHINSTANCE:
Packit 74c279
        case SNMP_NOSUCHOBJECT:
Packit 74c279
        case ASN_PRIV_RETRY:   /* Internal only ? */
Packit 74c279
            vp1->type = ASN_NULL;
Packit 74c279
        }
Packit 74c279
           /*
Packit 74c279
            * Keep track of how many entries have been retrieved.
Packit 74c279
            */ 
Packit 74c279
           entry->count++;
Packit 74c279
        
Packit 74c279
           /*
Packit 74c279
            * Ensure previous and current result match
Packit 74c279
            *  (with corresponding entries in both lists)
Packit 74c279
            * and set the flags indicating which triggers are armed
Packit 74c279
            */ 
Packit 74c279
        if (vp2) {
Packit 74c279
            cmp = snmp_oid_compare(vp1->name, vp1->name_length,
Packit 74c279
                                   vp2->name, vp2->name_length);
Packit 74c279
            if ( cmp < 0 ) {
Packit 74c279
                /*
Packit 74c279
                 * If a new value has appeared, insert a matching
Packit 74c279
                 * dummy entry into the previous result list.
Packit 74c279
                 *
Packit 74c279
                 * XXX - check how this is best done.
Packit 74c279
                 */
Packit 74c279
                vtmp = SNMP_MALLOC_TYPEDEF( netsnmp_variable_list );
Packit 74c279
                if (!vtmp) {
Packit 74c279
                    _mteTrigger_failure(
Packit 74c279
                          "failed to create mteTrigger temp varbind");
Packit 74c279
                    snmp_free_varbind(var);
Packit 74c279
                    return;
Packit 74c279
                }
Packit 74c279
                vtmp->type = ASN_NULL;
Packit 74c279
                snmp_set_var_objid( vtmp, vp1->name, vp1->name_length );
Packit 74c279
                vtmp->next_variable = vp2;
Packit 74c279
                if (vp2_prev) {
Packit 74c279
                    vp2_prev->next_variable = vtmp;
Packit 74c279
                } else {
Packit 74c279
                    entry->old_results      = vtmp;
Packit 74c279
                }
Packit 74c279
                vp2_prev   = vtmp;
Packit 74c279
                vp1->index = MTE_ARMED_ALL;	/* XXX - plus a new flag */
Packit 74c279
                vp1_prev   = vp1;
Packit 74c279
                vp1        = vp1->next_variable;
Packit 74c279
            }
Packit 74c279
            else if ( cmp == 0 ) {
Packit 74c279
                /*
Packit 74c279
                 * If it's a continuing entry, just copy across the armed flags
Packit 74c279
                 */
Packit 74c279
                vp1->index = vp2->index;
Packit 74c279
                vp1_prev   = vp1;
Packit 74c279
                vp1        = vp1->next_variable;
Packit 74c279
                vp2_prev   = vp2;
Packit 74c279
                vp2        = vp2->next_variable;
Packit 74c279
            } else {
Packit 74c279
                /*
Packit 74c279
                 * If a value has just disappeared, insert a
Packit 74c279
                 * matching dummy entry into the current result list.
Packit 74c279
                 *
Packit 74c279
                 * XXX - check how this is best done.
Packit 74c279
                 *
Packit 74c279
                 */
Packit 74c279
                if ( vp2->type != ASN_NULL ) {
Packit 74c279
                    vtmp = SNMP_MALLOC_TYPEDEF( netsnmp_variable_list );
Packit 74c279
                    if (!vtmp) {
Packit 74c279
                        _mteTrigger_failure(
Packit 74c279
                                 "failed to create mteTrigger temp varbind");
Packit 74c279
                        snmp_free_varbind(var);
Packit 74c279
                        return;
Packit 74c279
                    }
Packit 74c279
                    vtmp->type = ASN_NULL;
Packit 74c279
                    snmp_set_var_objid( vtmp, vp2->name, vp2->name_length );
Packit 74c279
                    vtmp->next_variable = vp1;
Packit 74c279
                    if (vp1_prev) {
Packit 74c279
                        vp1_prev->next_variable = vtmp;
Packit 74c279
                    } else {
Packit 74c279
                        var                     = vtmp;
Packit 74c279
                    }
Packit 74c279
                    vp1_prev = vtmp;
Packit 74c279
                    vp2_prev = vp2;
Packit 74c279
                    vp2      = vp2->next_variable;
Packit 74c279
                } else {
Packit 74c279
                    /*
Packit 74c279
                     * But only if this entry has *just* disappeared.  If the
Packit 74c279
                     * entry from the last run was a dummy too, then remove it.
Packit 74c279
                     *   (leaving vp2_prev unchanged)
Packit 74c279
                     */
Packit 74c279
                    vtmp = vp2;
Packit 74c279
                    if (vp2_prev) {
Packit 74c279
                        vp2_prev->next_variable = vp2->next_variable;
Packit 74c279
                    } else {
Packit 74c279
                        entry->old_results      = vp2->next_variable;
Packit 74c279
                    }
Packit 74c279
                    vp2  = vp2->next_variable;
Packit 74c279
                    vtmp->next_variable = NULL;
Packit 74c279
                    snmp_free_varbind( vtmp );
Packit 74c279
                }
Packit 74c279
            }
Packit 74c279
        } else {
Packit 74c279
            /*
Packit 74c279
             * No more old results to compare.
Packit 74c279
             * Either all remaining values have only just been created ...
Packit 74c279
             *   (and we need to create dummy 'old' entries for them)
Packit 74c279
             */
Packit 74c279
            if ( vp2_prev ) {
Packit 74c279
                vtmp = SNMP_MALLOC_TYPEDEF( netsnmp_variable_list );
Packit 74c279
                if (!vtmp) {
Packit 74c279
                    _mteTrigger_failure(
Packit 74c279
                             "failed to create mteTrigger temp varbind");
Packit 74c279
                    snmp_free_varbind(var);
Packit 74c279
                    return;
Packit 74c279
                }
Packit 74c279
                vtmp->type = ASN_NULL;
Packit 74c279
                snmp_set_var_objid( vtmp, vp1->name, vp1->name_length );
Packit 74c279
                vtmp->next_variable     = vp2_prev->next_variable;
Packit 74c279
                vp2_prev->next_variable = vtmp;
Packit 74c279
                vp2_prev                = vtmp;
Packit 74c279
            }
Packit 74c279
            /*
Packit 74c279
             * ... or this is the first run through
Packit 74c279
             *   (and there were no old results at all)
Packit 74c279
             *
Packit 74c279
             * In either case, mark the current entry as armed and new.
Packit 74c279
             * Note that we no longer need to maintain 'vp1_prev'
Packit 74c279
             */
Packit 74c279
            vp1->index = MTE_ARMED_ALL;	/* XXX - plus a new flag */
Packit 74c279
            vp1        = vp1->next_variable;
Packit 74c279
        }
Packit 74c279
    }
Packit 74c279
Packit 74c279
    /*
Packit 74c279
     * ... and then work through these result(s), deciding
Packit 74c279
     *     whether or not to trigger the corresponding event.
Packit 74c279
     *
Packit 74c279
     *  Note that there's no point in evaluating Existence or
Packit 74c279
     *    Boolean tests if there's no corresponding event.
Packit 74c279
     *   (Even if the trigger matched, nothing would be done anyway).
Packit 74c279
     */
Packit 74c279
    if ((entry->mteTriggerTest & MTE_TRIGGER_EXISTENCE) &&
Packit 74c279
        (entry->mteTExEvent[0] != '\0' )) {
Packit 74c279
        /*
Packit 74c279
         * If we don't have a record of previous results,
Packit 74c279
         * this must be the first time through, so consider
Packit 74c279
         * the mteTriggerExistenceStartup tests.
Packit 74c279
         */
Packit 74c279
        if ( !entry->old_results ) {
Packit 74c279
            /*
Packit 74c279
             * With the 'present(0)' test, the trigger should fire
Packit 74c279
             *   for each value in the varbind list returned
Packit 74c279
             *   (whether the monitored value is wildcarded or not).
Packit 74c279
             */
Packit 74c279
            if (entry->mteTExTest & entry->mteTExStartup & MTE_EXIST_PRESENT) {
Packit 74c279
                for (vp1 = var; vp1; vp1=vp1->next_variable) {
Packit 74c279
                    DEBUGMSGTL(( "disman:event:trigger:fire",
Packit 74c279
                                 "Firing initial existence test: "));
Packit 74c279
                    DEBUGMSGOID(("disman:event:trigger:fire",
Packit 74c279
                                 vp1->name, vp1->name_length));
Packit 74c279
                    DEBUGMSG((   "disman:event:trigger:fire",
Packit 74c279
                                 " (present)\n"));
Packit 74c279
                    entry->mteTriggerXOwner   = entry->mteTExObjOwner;
Packit 74c279
                    entry->mteTriggerXObjects = entry->mteTExObjects;
Packit 74c279
                    entry->mteTriggerFired    = vp1;
Packit 74c279
                    n = entry->mteTriggerValueID_len;
Packit 74c279
                    mteEvent_fire(entry->mteTExEvOwner, entry->mteTExEvent, 
Packit 74c279
                                  entry, vp1->name+n, vp1->name_length-n);
Packit 74c279
                }
Packit 74c279
            }
Packit 74c279
            /*
Packit 74c279
             * An initial 'absent(1)' test only makes sense when
Packit 74c279
             *   monitoring a non-wildcarded OID (how would we know
Packit 74c279
             *   which rows of the table "ought" to exist, but don't?)
Packit 74c279
             */
Packit 74c279
            if (entry->mteTExTest & entry->mteTExStartup & MTE_EXIST_ABSENT) {
Packit 74c279
                if (!(entry->flags & MTE_TRIGGER_FLAG_VWILD) &&
Packit 74c279
                    var->type == ASN_NULL ) {
Packit 74c279
                    DEBUGMSGTL(( "disman:event:trigger:fire",
Packit 74c279
                                 "Firing initial existence test: "));
Packit 74c279
                    DEBUGMSGOID(("disman:event:trigger:fire",
Packit 74c279
                                 var->name, var->name_length));
Packit 74c279
                    DEBUGMSG((   "disman:event:trigger:fire",
Packit 74c279
                                 " (absent)\n"));
Packit 74c279
                    entry->mteTriggerXOwner   = entry->mteTExObjOwner;
Packit 74c279
                    entry->mteTriggerXObjects = entry->mteTExObjects;
Packit 74c279
                    /*
Packit 74c279
                     * It's unclear what value the 'mteHotValue' payload
Packit 74c279
                     *  should take when a monitored instance does not
Packit 74c279
                     *  exist on startup. The only sensible option is
Packit 74c279
                     *  to report a NULL value, but this clashes with
Packit 74c279
                     * the syntax of the mteHotValue MIB object.
Packit 74c279
                     */
Packit 74c279
                    entry->mteTriggerFired    = var;
Packit 74c279
                    n = entry->mteTriggerValueID_len;
Packit 74c279
                    mteEvent_fire(entry->mteTExEvOwner, entry->mteTExEvent, 
Packit 74c279
                                  entry, var->name+n, var->name_length-n);
Packit 74c279
                }
Packit 74c279
            }
Packit 74c279
        } /* !old_results */
Packit 74c279
            /*
Packit 74c279
             * Otherwise, compare the current set of results with
Packit 74c279
             * the previous ones, looking for changes.  We can
Packit 74c279
             * assume that the two lists match (see above).
Packit 74c279
             */
Packit 74c279
        else {
Packit 74c279
            for (vp1 = var, vp2 = entry->old_results;
Packit 74c279
                 vp1;
Packit 74c279
                 vp1=vp1->next_variable, vp2=vp2->next_variable) {
Packit 74c279
Packit 74c279
                /* Use this field to indicate that the trigger should fire */
Packit 74c279
                entry->mteTriggerFired = NULL;
Packit 74c279
                reason                 = NULL;
Packit 74c279
Packit 74c279
                if ((entry->mteTExTest & MTE_EXIST_PRESENT) &&
Packit 74c279
                    (vp1->type != ASN_NULL) &&
Packit 74c279
                    (vp2->type == ASN_NULL)) {
Packit 74c279
                    /* A new instance has appeared */
Packit 74c279
                    entry->mteTriggerFired = vp1;
Packit 74c279
                    reason = "(present)";
Packit 74c279
Packit 74c279
                } else if ((entry->mteTExTest & MTE_EXIST_ABSENT) &&
Packit 74c279
                    (vp1->type == ASN_NULL) &&
Packit 74c279
                    (vp2->type != ASN_NULL)) {
Packit 74c279
Packit 74c279
                    /*
Packit 74c279
                     * A previous instance has disappeared.
Packit 74c279
                     *
Packit 74c279
                     * It's unclear what value the 'mteHotValue' payload
Packit 74c279
                     *  should take when this happens - the previous
Packit 74c279
                     *  value (vp2), or a NULL value (vp1) ?
Packit 74c279
                     * NULL makes more sense logically, but clashes
Packit 74c279
                     *  with the syntax of the mteHotValue MIB object.
Packit 74c279
                     */
Packit 74c279
                    entry->mteTriggerFired = vp2;
Packit 74c279
                    reason = "(absent)";
Packit 74c279
Packit 74c279
                } else if ((entry->mteTExTest & MTE_EXIST_CHANGED) &&
Packit 74c279
                    ((vp1->val_len != vp2->val_len) || 
Packit 74c279
                     (memcmp( vp1->val.string, vp2->val.string,
Packit 74c279
                              vp1->val_len) != 0 ))) {
Packit 74c279
                    /*
Packit 74c279
                     * This comparison detects changes in *any* type
Packit 74c279
                     *  of value, numeric or string (or even OID).
Packit 74c279
                     *
Packit 74c279
                     * Unfortunately, the default 'mteTriggerFired'
Packit 74c279
                     *  notification payload can't report non-numeric
Packit 74c279
                     *  changes properly (see syntax of 'mteHotValue')
Packit 74c279
                     */
Packit 74c279
                    entry->mteTriggerFired = vp1;
Packit 74c279
                    reason = "(changed)";
Packit 74c279
                }
Packit 74c279
                if ( entry->mteTriggerFired ) {
Packit 74c279
                    /*
Packit 74c279
                     * One of the above tests has matched,
Packit 74c279
                     *   so fire the trigger.
Packit 74c279
                     */
Packit 74c279
                    DEBUGMSGTL(( "disman:event:trigger:fire",
Packit 74c279
                                 "Firing existence test: "));
Packit 74c279
                    DEBUGMSGOID(("disman:event:trigger:fire",
Packit 74c279
                                 vp1->name, vp1->name_length));
Packit 74c279
                    DEBUGMSG((   "disman:event:trigger:fire",
Packit 74c279
                                 " %s\n", reason));
Packit 74c279
                    entry->mteTriggerXOwner   = entry->mteTExObjOwner;
Packit 74c279
                    entry->mteTriggerXObjects = entry->mteTExObjects;
Packit 74c279
                    n = entry->mteTriggerValueID_len;
Packit 74c279
                    mteEvent_fire(entry->mteTExEvOwner, entry->mteTExEvent, 
Packit 74c279
                                  entry, vp1->name+n, vp1->name_length-n);
Packit 74c279
                }
Packit 74c279
            }
Packit 74c279
        } /* !old_results - end of else block */
Packit 74c279
    } /* MTE_TRIGGER_EXISTENCE */
Packit 74c279
Packit 74c279
    /*
Packit 74c279
     * We'll need sysUpTime.0 regardless...
Packit 74c279
     */
Packit 74c279
    DEBUGMSGTL(("disman:event:delta", "retrieve sysUpTime.0\n"));
Packit 74c279
    memset( &sysUT_var, 0, sizeof( netsnmp_variable_list ));
Packit 74c279
    snmp_set_var_objid( &sysUT_var, _sysUpTime_instance, _sysUpTime_inst_len );
Packit 74c279
    netsnmp_query_get(  &sysUT_var, entry->session );
Packit 74c279
Packit 74c279
    if (( entry->mteTriggerTest & MTE_TRIGGER_BOOLEAN   ) ||
Packit 74c279
        ( entry->mteTriggerTest & MTE_TRIGGER_THRESHOLD )) {
Packit 74c279
        /*
Packit 74c279
         * Although Existence tests can work with any syntax values,
Packit 74c279
         * Boolean and Threshold tests are integer-only.  Ensure that
Packit 74c279
         * the returned value(s) are appropriate.
Packit 74c279
         *
Packit 74c279
         * Note that we only need to check the first value, since all
Packit 74c279
         *  instances of a given object should have the same syntax.
Packit 74c279
         */
Packit 74c279
        switch (var->type) {
Packit 74c279
        case ASN_INTEGER:
Packit 74c279
        case ASN_COUNTER:
Packit 74c279
        case ASN_GAUGE:
Packit 74c279
        case ASN_TIMETICKS:
Packit 74c279
        case ASN_UINTEGER:
Packit 74c279
        case ASN_COUNTER64:
Packit 74c279
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
Packit 74c279
        case ASN_OPAQUE_COUNTER64:
Packit 74c279
        case ASN_OPAQUE_U64:
Packit 74c279
        case ASN_OPAQUE_I64:
Packit 74c279
#endif
Packit 74c279
            /* OK */
Packit 74c279
            break;
Packit 74c279
        default:
Packit 74c279
            /*
Packit 74c279
             * Other syntax values can't be used for Boolean/Theshold
Packit 74c279
             * tests. Report this as an error, and then rotate the
Packit 74c279
             * results ready for the next run, (which will presumably
Packit 74c279
             * also detect this as an error once again!)
Packit 74c279
             */
Packit 74c279
            DEBUGMSGTL(( "disman:event:trigger:fire",
Packit 74c279
                         "Returned non-integer result(s): "));
Packit 74c279
            DEBUGMSGOID(("disman:event:trigger:fire",
Packit 74c279
                         var->name, var->name_length));
Packit 74c279
            DEBUGMSG((   "disman:event:trigger:fire",
Packit 74c279
                         " (boolean/threshold) %d\n", var->type));
Packit 74c279
            snmp_free_varbind( entry->old_results );
Packit 74c279
            entry->old_results = var;
Packit 74c279
            return;
Packit 74c279
        }
Packit 74c279
Packit 74c279
Packit 74c279
        /*
Packit 74c279
         * Retrieve the discontinuity markers for delta-valued samples.
Packit 74c279
         * (including sysUpTime.0 if not specified explicitly).
Packit 74c279
         */
Packit 74c279
        if ( entry->flags & MTE_TRIGGER_FLAG_DELTA ) {
Packit 74c279
Packit 74c279
            if (!(entry->flags & MTE_TRIGGER_FLAG_SYSUPT)) {
Packit 74c279
                /*
Packit 74c279
                 * ... but only retrieve the configured discontinuity
Packit 74c279
                 *      marker(s) if they refer to something different.
Packit 74c279
                 */
Packit 74c279
                DEBUGMSGTL(( "disman:event:delta",
Packit 74c279
                             "retrieve discontinuity marker(s): "));
Packit 74c279
                DEBUGMSGOID(("disman:event:delta", entry->mteDeltaDiscontID,
Packit 74c279
                                               entry->mteDeltaDiscontID_len ));
Packit 74c279
                DEBUGMSG((   "disman:event:delta", " %s\n", 
Packit 74c279
                     (entry->flags & MTE_TRIGGER_FLAG_DWILD ? " (wild)" : "")));
Packit 74c279
Packit 74c279
                dvar = (netsnmp_variable_list *)
Packit 74c279
                                SNMP_MALLOC_TYPEDEF( netsnmp_variable_list );
Packit 74c279
                if (!dvar) {
Packit 74c279
                    _mteTrigger_failure(
Packit 74c279
                            "failed to create mteTrigger delta query varbind");
Packit 74c279
                    return;
Packit 74c279
                }
Packit 74c279
                snmp_set_var_objid( dvar, entry->mteDeltaDiscontID,
Packit 74c279
                                          entry->mteDeltaDiscontID_len );
Packit 74c279
                if ( entry->flags & MTE_TRIGGER_FLAG_DWILD ) {
Packit 74c279
                    n = netsnmp_query_walk( dvar, entry->session );
Packit 74c279
                } else {
Packit 74c279
                    n = netsnmp_query_get(  dvar, entry->session );
Packit 74c279
                }
Packit 74c279
                if ( n != SNMP_ERR_NOERROR ) {
Packit 74c279
                    _mteTrigger_failure( "failed to run mteTrigger delta query" );
Packit 74c279
                    snmp_free_varbind( dvar );
Packit 74c279
                    return;
Packit 74c279
                }
Packit 74c279
            }
Packit 74c279
Packit 74c279
            /*
Packit 74c279
             * We can't calculate delta values the first time through,
Packit 74c279
             *  so there's no point in evaluating the remaining tests.
Packit 74c279
             *
Packit 74c279
             * Save the results (and discontinuity markers),
Packit 74c279
             *   ready for the next run.
Packit 74c279
             */
Packit 74c279
            if ( !entry->old_results ) {
Packit 74c279
                entry->old_results =  var;
Packit 74c279
                entry->old_deltaDs = dvar;
Packit 74c279
                entry->sysUpTime   = *sysUT_var.val.integer;
Packit 74c279
                return;
Packit 74c279
            }
Packit 74c279
            /*
Packit 74c279
             * If the sysUpTime marker has been reset (or strictly,
Packit 74c279
             *   has advanced by less than the monitor frequency),
Packit 74c279
             *  there's no point in trying the remaining tests.
Packit 74c279
             */
Packit 74c279
Packit 74c279
            if (*sysUT_var.val.integer < entry->sysUpTime) {
Packit 74c279
                DEBUGMSGTL(( "disman:event:delta",
Packit 74c279
                             "single discontinuity: (sysUT)\n"));
Packit 74c279
                snmp_free_varbind( entry->old_results );
Packit 74c279
                snmp_free_varbind( entry->old_deltaDs );
Packit 74c279
                entry->old_results =  var;
Packit 74c279
                entry->old_deltaDs = dvar;
Packit 74c279
                entry->sysUpTime   = *sysUT_var.val.integer;
Packit 74c279
                return;
Packit 74c279
            }
Packit 74c279
            /*
Packit 74c279
             * Similarly if a separate (non-wildcarded) discontinuity
Packit 74c279
             *  marker has changed, then there's no
Packit 74c279
             *  point in trying to evaluate these tests either.
Packit 74c279
             */
Packit 74c279
            if (!(entry->flags & MTE_TRIGGER_FLAG_DWILD)  &&
Packit 74c279
                !(entry->flags & MTE_TRIGGER_FLAG_SYSUPT) &&
Packit 74c279
                  (!entry->old_deltaDs ||
Packit 74c279
                   (entry->old_deltaDs->val.integer != dvar->val.integer))) {
Packit 74c279
                DEBUGMSGTL((  "disman:event:delta", "single discontinuity: ("));
Packit 74c279
                DEBUGMSGOID(( "disman:event:delta", entry->mteDeltaDiscontID,
Packit 74c279
                                           entry->mteDeltaDiscontID_len));
Packit 74c279
                DEBUGMSG((    "disman:event:delta", ")\n"));
Packit 74c279
                snmp_free_varbind( entry->old_results );
Packit 74c279
                snmp_free_varbind( entry->old_deltaDs );
Packit 74c279
                entry->old_results =  var;
Packit 74c279
                entry->old_deltaDs = dvar;
Packit 74c279
                entry->sysUpTime   = *sysUT_var.val.integer;
Packit 74c279
                return;
Packit 74c279
            }
Packit 74c279
Packit 74c279
            /*
Packit 74c279
             * Ensure that the list of (wildcarded) discontinuity 
Packit 74c279
             *  markers matches the list of monitored values
Packit 74c279
             *  (inserting/removing discontinuity varbinds as needed)
Packit 74c279
             *
Packit 74c279
             * XXX - An alternative approach would be to use the list
Packit 74c279
             *    of monitored values (instance subidentifiers) to build
Packit 74c279
             *    the exact list of delta markers to retrieve earlier.
Packit 74c279
             */
Packit 74c279
            if (entry->flags & MTE_TRIGGER_FLAG_DWILD) {
Packit 74c279
                vp1      =  var;
Packit 74c279
                vp2      = dvar;
Packit 74c279
                vp2_prev = NULL;
Packit 74c279
                n  = entry->mteTriggerValueID_len;
Packit 74c279
                n2 = entry->mteDeltaDiscontID_len;
Packit 74c279
                while (vp1) {
Packit 74c279
                    /*
Packit 74c279
                     * For each monitored instance, check whether
Packit 74c279
                     *   there's a matching discontinuity entry.
Packit 74c279
                     */
Packit 74c279
                    cmp = snmp_oid_compare(vp1->name+n,  vp1->name_length-n,
Packit 74c279
                                           vp2->name+n2, vp2->name_length-n2 );
Packit 74c279
                    if ( cmp < 0 ) {
Packit 74c279
                        /*
Packit 74c279
                         * If a discontinuity entry is missing,
Packit 74c279
                         *   insert a (dummy) varbind.
Packit 74c279
                         * The corresponding delta calculation will
Packit 74c279
                         *   fail, but this simplifies the later code.
Packit 74c279
                         */
Packit 74c279
                        vtmp = (netsnmp_variable_list *)
Packit 74c279
                                SNMP_MALLOC_TYPEDEF( netsnmp_variable_list );
Packit 74c279
                        if (!vtmp) {
Packit 74c279
                            _mteTrigger_failure(
Packit 74c279
                                  "failed to create mteTrigger discontinuity varbind");
Packit 74c279
                            snmp_free_varbind(dvar);
Packit 74c279
                            return;
Packit 74c279
                        }
Packit 74c279
                        snmp_set_var_objid(vtmp, entry->mteDeltaDiscontID,
Packit 74c279
                                                 entry->mteDeltaDiscontID_len);
Packit 74c279
                            /* XXX - append instance subids */
Packit 74c279
                        vtmp->next_variable     = vp2;
Packit 74c279
                        vp2_prev->next_variable = vtmp;
Packit 74c279
                        vp2_prev                = vtmp;
Packit 74c279
                        vp1 = vp1->next_variable;
Packit 74c279
                    } else if ( cmp == 0 ) {
Packit 74c279
                        /*
Packit 74c279
                         * Matching discontinuity entry -  all OK.
Packit 74c279
                         */
Packit 74c279
                        vp2_prev = vp2;
Packit 74c279
                        vp2      = vp2->next_variable;
Packit 74c279
                        vp1      = vp1->next_variable;
Packit 74c279
                    } else {
Packit 74c279
                        /*
Packit 74c279
                         * Remove unneeded discontinuity entry
Packit 74c279
                         */
Packit 74c279
                        vtmp = vp2;
Packit 74c279
                        vp2_prev->next_variable = vp2->next_variable;
Packit 74c279
                        vp2                     = vp2->next_variable;
Packit 74c279
                        vtmp->next_variable = NULL;
Packit 74c279
                        snmp_free_varbind( vtmp );
Packit 74c279
                    }
Packit 74c279
                }
Packit 74c279
                /*
Packit 74c279
                 * XXX - Now need to ensure that the old list of
Packit 74c279
                 *   delta discontinuity markers matches as well.
Packit 74c279
                 */
Packit 74c279
            }
Packit 74c279
        } /* delta samples */
Packit 74c279
    } /* Boolean/Threshold test checks */
Packit 74c279
Packit 74c279
Packit 74c279
Packit 74c279
    /*
Packit 74c279
     * Only run the Boolean tests if there's an event to be triggered
Packit 74c279
     */
Packit 74c279
    if ((entry->mteTriggerTest & MTE_TRIGGER_BOOLEAN) &&
Packit 74c279
        (entry->mteTBoolEvent[0] != '\0' )) {
Packit 74c279
Packit 74c279
        if (entry->flags & MTE_TRIGGER_FLAG_DELTA) {
Packit 74c279
            vp2 = entry->old_results;
Packit 74c279
            if (entry->flags & MTE_TRIGGER_FLAG_DWILD) {
Packit 74c279
                dv1 = dvar;
Packit 74c279
                dv2 = entry->old_deltaDs;
Packit 74c279
            }
Packit 74c279
        }
Packit 74c279
        for ( vp1 = var; vp1; vp1=vp1->next_variable ) {
Packit 74c279
            /*
Packit 74c279
             * Determine the value to be monitored...
Packit 74c279
             */
Packit 74c279
            if ( !vp1->val.integer ) {  /* No value */
Packit 74c279
                if ( vp2 )
Packit 74c279
                    vp2 = vp2->next_variable;
Packit 74c279
                continue;
Packit 74c279
            }
Packit 74c279
            if (entry->flags & MTE_TRIGGER_FLAG_DELTA) {
Packit 74c279
                if (entry->flags & MTE_TRIGGER_FLAG_DWILD) {
Packit 74c279
                    /*
Packit 74c279
                     * We've already checked any non-wildcarded
Packit 74c279
                     *   discontinuity markers (inc. sysUpTime.0).
Packit 74c279
                     * Validate this particular sample against
Packit 74c279
                     *   the relevant wildcarded marker...
Packit 74c279
                     */
Packit 74c279
                    if ((dv1->type == ASN_NULL)  ||
Packit 74c279
                        (dv1->type != dv2->type) ||
Packit 74c279
                        (*dv1->val.integer != *dv2->val.integer)) {
Packit 74c279
                        /*
Packit 74c279
                         * Bogus or changed discontinuity marker.
Packit 74c279
                         * Need to skip this sample.
Packit 74c279
                         */
Packit 74c279
    DEBUGMSGTL(( "disman:event:delta", "discontinuity occurred: "));
Packit 74c279
    DEBUGMSGOID(("disman:event:delta", vp1->name,
Packit 74c279
                                       vp1->name_length ));
Packit 74c279
    DEBUGMSG((   "disman:event:delta", " \n" ));
Packit 74c279
                        vp2 = vp2->next_variable;
Packit 74c279
                        continue;
Packit 74c279
                    }
Packit 74c279
                }
Packit 74c279
                /*
Packit 74c279
                 * ... and check there is a previous sample to calculate
Packit 74c279
                 *   the delta value against (regardless of whether the
Packit 74c279
                 *   discontinuity marker was wildcarded or not).
Packit 74c279
                 */
Packit 74c279
                if (vp2->type == ASN_NULL) {
Packit 74c279
    DEBUGMSGTL(( "disman:event:delta", "missing sample: "));
Packit 74c279
    DEBUGMSGOID(("disman:event:delta", vp1->name,
Packit 74c279
                                       vp1->name_length ));
Packit 74c279
    DEBUGMSG((   "disman:event:delta", " \n" ));
Packit 74c279
                    vp2 = vp2->next_variable;
Packit 74c279
                    continue;
Packit 74c279
                }
Packit 74c279
                value = (*vp1->val.integer - *vp2->val.integer);
Packit 74c279
    DEBUGMSGTL(( "disman:event:delta", "delta sample: "));
Packit 74c279
    DEBUGMSGOID(("disman:event:delta", vp1->name,
Packit 74c279
                                       vp1->name_length ));
Packit 74c279
    DEBUGMSG((   "disman:event:delta", " (%ld - %ld) = %ld\n",
Packit 74c279
                *vp1->val.integer,  *vp2->val.integer, value));
Packit 74c279
                vp2 = vp2->next_variable;
Packit 74c279
            } else {
Packit 74c279
                value = *vp1->val.integer;
Packit 74c279
            }
Packit 74c279
Packit 74c279
            /*
Packit 74c279
             * ... evaluate the comparison ...
Packit 74c279
             */
Packit 74c279
            switch (entry->mteTBoolComparison) {
Packit 74c279
            case MTE_BOOL_UNEQUAL:
Packit 74c279
                cmp = ( value != entry->mteTBoolValue );
Packit 74c279
                break;
Packit 74c279
            case MTE_BOOL_EQUAL:
Packit 74c279
                cmp = ( value == entry->mteTBoolValue );
Packit 74c279
                break;
Packit 74c279
            case MTE_BOOL_LESS:
Packit 74c279
                cmp = ( value <  entry->mteTBoolValue );
Packit 74c279
                break;
Packit 74c279
            case MTE_BOOL_LESSEQUAL:
Packit 74c279
                cmp = ( value <= entry->mteTBoolValue );
Packit 74c279
                break;
Packit 74c279
            case MTE_BOOL_GREATER:
Packit 74c279
                cmp = ( value >  entry->mteTBoolValue );
Packit 74c279
                break;
Packit 74c279
            case MTE_BOOL_GREATEREQUAL:
Packit 74c279
                cmp = ( value >= entry->mteTBoolValue );
Packit 74c279
                break;
Packit 74c279
            }
Packit 74c279
    DEBUGMSGTL(( "disman:event:delta", "Bool comparison: (%ld %s %ld) %d\n",
Packit 74c279
                          value, _ops[entry->mteTBoolComparison],
Packit 74c279
                          entry->mteTBoolValue, cmp));
Packit 74c279
Packit 74c279
            /*
Packit 74c279
             * ... and decide whether to trigger the event.
Packit 74c279
             *    (using the 'index' field of the varbind structure
Packit 74c279
             *     to remember whether the trigger has already fired)
Packit 74c279
             */
Packit 74c279
            if ( cmp ) {
Packit 74c279
              if (vp1->index & MTE_ARMED_BOOLEAN ) {
Packit 74c279
                vp1->index &= ~MTE_ARMED_BOOLEAN;
Packit 74c279
                /*
Packit 74c279
                 * NB: Clear the trigger armed flag even if the
Packit 74c279
                 *   (starting) event dosn't actually fire.
Packit 74c279
                 *   Otherwise initially true (but suppressed)
Packit 74c279
                 *   triggers will fire on the *second* probe.
Packit 74c279
                 */
Packit 74c279
                if ( entry->old_results ||
Packit 74c279
                    (entry->flags & MTE_TRIGGER_FLAG_BSTART)) {
Packit 74c279
                    DEBUGMSGTL(( "disman:event:trigger:fire",
Packit 74c279
                                 "Firing boolean test: "));
Packit 74c279
                    DEBUGMSGOID(("disman:event:trigger:fire",
Packit 74c279
                                 vp1->name, vp1->name_length));
Packit 74c279
                    DEBUGMSG((   "disman:event:trigger:fire", "%s\n",
Packit 74c279
                                  (entry->old_results ? "" : " (startup)")));
Packit 74c279
                    entry->mteTriggerXOwner   = entry->mteTBoolObjOwner;
Packit 74c279
                    entry->mteTriggerXObjects = entry->mteTBoolObjects;
Packit 74c279
                    /*
Packit 74c279
                     * XXX - when firing a delta-based trigger, should
Packit 74c279
                     *   'mteHotValue' report the actual value sampled
Packit 74c279
                     *   (as here), or the delta that triggered the event ?
Packit 74c279
                     */
Packit 74c279
                    entry->mteTriggerFired    = vp1;
Packit 74c279
                    n = entry->mteTriggerValueID_len;
Packit 74c279
                    mteEvent_fire(entry->mteTBoolEvOwner, entry->mteTBoolEvent, 
Packit 74c279
                                  entry, vp1->name+n, vp1->name_length-n);
Packit 74c279
                }
Packit 74c279
              }
Packit 74c279
            } else {
Packit 74c279
                vp1->index |= MTE_ARMED_BOOLEAN;
Packit 74c279
            }
Packit 74c279
        }
Packit 74c279
    }
Packit 74c279
Packit 74c279
Packit 74c279
    /*
Packit 74c279
     * Only run the basic threshold tests if there's an event to
Packit 74c279
     *    be triggered.  (Either rising or falling will do)
Packit 74c279
     */
Packit 74c279
    if (( entry->mteTriggerTest & MTE_TRIGGER_THRESHOLD ) &&
Packit 74c279
        ((entry->mteTThRiseEvent[0] != '\0' ) ||
Packit 74c279
         (entry->mteTThFallEvent[0] != '\0' ))) {
Packit 74c279
Packit 74c279
        /*
Packit 74c279
         * The same delta-sample validation from Boolean
Packit 74c279
         *   tests also applies here too.
Packit 74c279
         */
Packit 74c279
        if (entry->flags & MTE_TRIGGER_FLAG_DELTA) {
Packit 74c279
            vp2 = entry->old_results;
Packit 74c279
            if (entry->flags & MTE_TRIGGER_FLAG_DWILD) {
Packit 74c279
                dv1 = dvar;
Packit 74c279
                dv2 = entry->old_deltaDs;
Packit 74c279
            }
Packit 74c279
        }
Packit 74c279
        for ( vp1 = var; vp1; vp1=vp1->next_variable ) {
Packit 74c279
            /*
Packit 74c279
             * Determine the value to be monitored...
Packit 74c279
             */
Packit 74c279
            if ( !vp1->val.integer ) {  /* No value */
Packit 74c279
                if ( vp2 )
Packit 74c279
                    vp2 = vp2->next_variable;
Packit 74c279
                continue;
Packit 74c279
            }
Packit 74c279
            if (entry->flags & MTE_TRIGGER_FLAG_DELTA) {
Packit 74c279
                if (entry->flags & MTE_TRIGGER_FLAG_DWILD) {
Packit 74c279
                    /*
Packit 74c279
                     * We've already checked any non-wildcarded
Packit 74c279
                     *   discontinuity markers (inc. sysUpTime.0).
Packit 74c279
                     * Validate this particular sample against
Packit 74c279
                     *   the relevant wildcarded marker...
Packit 74c279
                     */
Packit 74c279
                    if ((dv1->type == ASN_NULL)  ||
Packit 74c279
                        (dv1->type != dv2->type) ||
Packit 74c279
                        (*dv1->val.integer != *dv2->val.integer)) {
Packit 74c279
                        /*
Packit 74c279
                         * Bogus or changed discontinuity marker.
Packit 74c279
                         * Need to skip this sample.
Packit 74c279
                         */
Packit 74c279
                        vp2 = vp2->next_variable;
Packit 74c279
                        continue;
Packit 74c279
                    }
Packit 74c279
                }
Packit 74c279
                /*
Packit 74c279
                 * ... and check there is a previous sample to calculate
Packit 74c279
                 *   the delta value against (regardless of whether the
Packit 74c279
                 *   discontinuity marker was wildcarded or not).
Packit 74c279
                 */
Packit 74c279
                if (vp2->type == ASN_NULL) {
Packit 74c279
                    vp2 = vp2->next_variable;
Packit 74c279
                    continue;
Packit 74c279
                }
Packit 74c279
                value = (*vp1->val.integer - *vp2->val.integer);
Packit 74c279
                vp2 = vp2->next_variable;
Packit 74c279
            } else {
Packit 74c279
                value = *vp1->val.integer;
Packit 74c279
            }
Packit 74c279
Packit 74c279
            /*
Packit 74c279
             * ... evaluate the single-value comparisons,
Packit 74c279
             *     and decide whether to trigger the event.
Packit 74c279
             */
Packit 74c279
            cmp = vp1->index;   /* working copy of 'armed' flags */
Packit 74c279
            if ( value >= entry->mteTThRiseValue ) {
Packit 74c279
              if (cmp & MTE_ARMED_TH_RISE ) {
Packit 74c279
                cmp &= ~MTE_ARMED_TH_RISE;
Packit 74c279
                cmp |=  MTE_ARMED_TH_FALL;
Packit 74c279
                /*
Packit 74c279
                 * NB: Clear the trigger armed flag even if the
Packit 74c279
                 *   (starting) event dosn't actually fire.
Packit 74c279
                 *   Otherwise initially true (but suppressed)
Packit 74c279
                 *   triggers will fire on the *second* probe.
Packit 74c279
                 * Similarly for falling thresholds (see below).
Packit 74c279
                 */
Packit 74c279
                if ( entry->old_results ||
Packit 74c279
                    (entry->mteTThStartup & MTE_THRESH_START_RISE)) {
Packit 74c279
                    DEBUGMSGTL(( "disman:event:trigger:fire",
Packit 74c279
                                 "Firing rising threshold test: "));
Packit 74c279
                    DEBUGMSGOID(("disman:event:trigger:fire",
Packit 74c279
                                 vp1->name, vp1->name_length));
Packit 74c279
                    DEBUGMSG((   "disman:event:trigger:fire", "%s\n",
Packit 74c279
                                 (entry->old_results ? "" : " (startup)")));
Packit 74c279
                    /*
Packit 74c279
                     * If no riseEvent is configured, we need still to
Packit 74c279
                     *  set the armed flags appropriately, but there's
Packit 74c279
                     *  no point in trying to fire the (missing) event.
Packit 74c279
                     */
Packit 74c279
                    if (entry->mteTThRiseEvent[0] != '\0' ) {
Packit 74c279
                        entry->mteTriggerXOwner   = entry->mteTThObjOwner;
Packit 74c279
                        entry->mteTriggerXObjects = entry->mteTThObjects;
Packit 74c279
                        entry->mteTriggerFired    = vp1;
Packit 74c279
                        n = entry->mteTriggerValueID_len;
Packit 74c279
                        mteEvent_fire(entry->mteTThRiseOwner,
Packit 74c279
                                      entry->mteTThRiseEvent, 
Packit 74c279
                                      entry, vp1->name+n, vp1->name_length-n);
Packit 74c279
                    }
Packit 74c279
                }
Packit 74c279
              }
Packit 74c279
            }
Packit 74c279
Packit 74c279
            if ( value <= entry->mteTThFallValue ) {
Packit 74c279
              if (cmp & MTE_ARMED_TH_FALL ) {
Packit 74c279
                cmp &= ~MTE_ARMED_TH_FALL;
Packit 74c279
                cmp |=  MTE_ARMED_TH_RISE;
Packit 74c279
                /* Clear the trigger armed flag (see above) */
Packit 74c279
                if ( entry->old_results ||
Packit 74c279
                    (entry->mteTThStartup & MTE_THRESH_START_FALL)) {
Packit 74c279
                    DEBUGMSGTL(( "disman:event:trigger:fire",
Packit 74c279
                                 "Firing falling threshold test: "));
Packit 74c279
                    DEBUGMSGOID(("disman:event:trigger:fire",
Packit 74c279
                                 vp1->name, vp1->name_length));
Packit 74c279
                    DEBUGMSG((   "disman:event:trigger:fire", "%s\n",
Packit 74c279
                                 (entry->old_results ? "" : " (startup)")));
Packit 74c279
                    /*
Packit 74c279
                     * Similarly, if no fallEvent is configured,
Packit 74c279
                     *  there's no point in trying to fire it either.
Packit 74c279
                     */
Packit 74c279
                    if (entry->mteTThRiseEvent[0] != '\0' ) {
Packit 74c279
                        entry->mteTriggerXOwner   = entry->mteTThObjOwner;
Packit 74c279
                        entry->mteTriggerXObjects = entry->mteTThObjects;
Packit 74c279
                        entry->mteTriggerFired    = vp1;
Packit 74c279
                        n = entry->mteTriggerValueID_len;
Packit 74c279
                        mteEvent_fire(entry->mteTThFallOwner,
Packit 74c279
                                      entry->mteTThFallEvent, 
Packit 74c279
                                      entry, vp1->name+n, vp1->name_length-n);
Packit 74c279
                    }
Packit 74c279
                }
Packit 74c279
              }
Packit 74c279
            }
Packit 74c279
            vp1->index = cmp;
Packit 74c279
        }
Packit 74c279
    }
Packit 74c279
Packit 74c279
    /*
Packit 74c279
     * The same processing also works for delta-threshold tests (if configured)
Packit 74c279
     */
Packit 74c279
    if (( entry->mteTriggerTest & MTE_TRIGGER_THRESHOLD ) &&
Packit 74c279
        ((entry->mteTThDRiseEvent[0] != '\0' ) ||
Packit 74c279
         (entry->mteTThDFallEvent[0] != '\0' ))) {
Packit 74c279
Packit 74c279
        /*
Packit 74c279
         * Delta-threshold tests can only be used with
Packit 74c279
         *   absolute valued samples.
Packit 74c279
         */
Packit 74c279
        vp2 = entry->old_results;
Packit 74c279
        if (entry->flags & MTE_TRIGGER_FLAG_DELTA) {
Packit 74c279
            DEBUGMSGTL(( "disman:event:trigger",
Packit 74c279
                         "Delta-threshold on delta-sample\n"));
Packit 74c279
        } else if ( vp2 != NULL ) {
Packit 74c279
          for ( vp1 = var; vp1; vp1=vp1->next_variable ) {
Packit 74c279
            /*
Packit 74c279
             * Determine the value to be monitored...
Packit 74c279
             *  (similar to previous delta-sample processing,
Packit 74c279
             *   but without the discontinuity marker checks)
Packit 74c279
             */
Packit 74c279
            if (!vp2) {
Packit 74c279
                break;   /* Run out of 'old' values */
Packit 74c279
            }
Packit 74c279
            if (( !vp1->val.integer ) ||
Packit 74c279
                (vp2->type == ASN_NULL)) {
Packit 74c279
                vp2 = vp2->next_variable;
Packit 74c279
                continue;
Packit 74c279
            }
Packit 74c279
            value = (*vp1->val.integer - *vp2->val.integer);
Packit 74c279
            vp2 = vp2->next_variable;
Packit 74c279
Packit 74c279
            /*
Packit 74c279
             * ... evaluate the single-value comparisons,
Packit 74c279
             *     and decide whether to trigger the event.
Packit 74c279
             */
Packit 74c279
            cmp = vp1->index;   /* working copy of 'armed' flags */
Packit 74c279
            if ( value >= entry->mteTThDRiseValue ) {
Packit 74c279
                if (vp1->index & MTE_ARMED_TH_DRISE ) {
Packit 74c279
                    DEBUGMSGTL(( "disman:event:trigger:fire",
Packit 74c279
                                 "Firing rising delta threshold test: "));
Packit 74c279
                    DEBUGMSGOID(("disman:event:trigger:fire",
Packit 74c279
                                 vp1->name, vp1->name_length));
Packit 74c279
                    DEBUGMSG((   "disman:event:trigger:fire", "\n"));
Packit 74c279
                    cmp &= ~MTE_ARMED_TH_DRISE;
Packit 74c279
                    cmp |=  MTE_ARMED_TH_DFALL;
Packit 74c279
                    /*
Packit 74c279
                     * If no riseEvent is configured, we need still to
Packit 74c279
                     *  set the armed flags appropriately, but there's
Packit 74c279
                     *  no point in trying to fire the (missing) event.
Packit 74c279
                     */
Packit 74c279
                    if (entry->mteTThDRiseEvent[0] != '\0' ) {
Packit 74c279
                        entry->mteTriggerXOwner   = entry->mteTThObjOwner;
Packit 74c279
                        entry->mteTriggerXObjects = entry->mteTThObjects;
Packit 74c279
                        entry->mteTriggerFired    = vp1;
Packit 74c279
                        n = entry->mteTriggerValueID_len;
Packit 74c279
                        mteEvent_fire(entry->mteTThDRiseOwner,
Packit 74c279
                                      entry->mteTThDRiseEvent, 
Packit 74c279
                                      entry, vp1->name+n, vp1->name_length-n);
Packit 74c279
                    }
Packit 74c279
                }
Packit 74c279
            }
Packit 74c279
Packit 74c279
            if ( value <= entry->mteTThDFallValue ) {
Packit 74c279
                if (vp1->index & MTE_ARMED_TH_DFALL ) {
Packit 74c279
                    DEBUGMSGTL(( "disman:event:trigger:fire",
Packit 74c279
                                 "Firing falling delta threshold test: "));
Packit 74c279
                    DEBUGMSGOID(("disman:event:trigger:fire",
Packit 74c279
                                 vp1->name, vp1->name_length));
Packit 74c279
                    DEBUGMSG((   "disman:event:trigger:fire", "\n"));
Packit 74c279
                    cmp &= ~MTE_ARMED_TH_DFALL;
Packit 74c279
                    cmp |=  MTE_ARMED_TH_DRISE;
Packit 74c279
                    /*
Packit 74c279
                     * Similarly, if no fallEvent is configured,
Packit 74c279
                     *  there's no point in trying to fire it either.
Packit 74c279
                     */
Packit 74c279
                    if (entry->mteTThDRiseEvent[0] != '\0' ) {
Packit 74c279
                        entry->mteTriggerXOwner   = entry->mteTThObjOwner;
Packit 74c279
                        entry->mteTriggerXObjects = entry->mteTThObjects;
Packit 74c279
                        entry->mteTriggerFired    = vp1;
Packit 74c279
                        n = entry->mteTriggerValueID_len;
Packit 74c279
                        mteEvent_fire(entry->mteTThDFallOwner,
Packit 74c279
                                      entry->mteTThDFallEvent, 
Packit 74c279
                                      entry, vp1->name+n, vp1->name_length-n);
Packit 74c279
                    }
Packit 74c279
                }
Packit 74c279
            }
Packit 74c279
            vp1->index = cmp;
Packit 74c279
          }
Packit 74c279
        }
Packit 74c279
    }
Packit 74c279
Packit 74c279
    /*
Packit 74c279
     * Finally, rotate the results - ready for the next run.
Packit 74c279
     */
Packit 74c279
    snmp_free_varbind( entry->old_results );
Packit 74c279
    entry->old_results = var;
Packit 74c279
    if ( entry->flags & MTE_TRIGGER_FLAG_DELTA ) {
Packit 74c279
        snmp_free_varbind( entry->old_deltaDs );
Packit 74c279
        entry->old_deltaDs = dvar;
Packit 74c279
        entry->sysUpTime   = *sysUT_var.val.integer;
Packit 74c279
    }
Packit 74c279
}
Packit 74c279
Packit 74c279
void
Packit 74c279
mteTrigger_enable( struct mteTrigger *entry )
Packit 74c279
{
Packit 74c279
    if (!entry)
Packit 74c279
        return;
Packit 74c279
Packit 74c279
    if (entry->alarm) {
Packit 74c279
        /* XXX - or explicitly call mteTrigger_disable ?? */
Packit 74c279
        snmp_alarm_unregister( entry->alarm );
Packit 74c279
        entry->alarm = 0;
Packit 74c279
    }
Packit 74c279
Packit 74c279
    if (entry->mteTriggerFrequency) {
Packit 74c279
        /*
Packit 74c279
         * register once to run ASAP, and another to run
Packit 74c279
         * at the trigger frequency
Packit 74c279
         */
Packit 74c279
        snmp_alarm_register(0, 0, mteTrigger_run, entry );
Packit 74c279
        entry->alarm = snmp_alarm_register(
Packit 74c279
                           entry->mteTriggerFrequency, SA_REPEAT,
Packit 74c279
                           mteTrigger_run, entry );
Packit 74c279
    }
Packit 74c279
}
Packit 74c279
Packit 74c279
void
Packit 74c279
mteTrigger_disable( struct mteTrigger *entry )
Packit 74c279
{
Packit 74c279
    if (!entry)
Packit 74c279
        return;
Packit 74c279
Packit 74c279
    if (entry->alarm) {
Packit 74c279
        snmp_alarm_unregister( entry->alarm );
Packit 74c279
        entry->alarm = 0;
Packit 74c279
        /* XXX - perhaps release any previous results */
Packit 74c279
    }
Packit 74c279
}
Packit 74c279
Packit 74c279
long _mteTrigger_MaxCount = 0;
Packit 74c279
long _mteTrigger_countEntries(void)
Packit 74c279
{
Packit 74c279
    struct mteTrigger *entry;
Packit 74c279
    netsnmp_tdata_row *row;
Packit 74c279
    long count = 0;
Packit 74c279
Packit 74c279
    for (row = netsnmp_tdata_row_first(trigger_table_data);
Packit 74c279
         row;
Packit 74c279
         row = netsnmp_tdata_row_next(trigger_table_data, row)) {
Packit 74c279
        entry  = (struct mteTrigger *)row->data;
Packit 74c279
        count += entry->count;
Packit 74c279
    }
Packit 74c279
Packit 74c279
    return count;
Packit 74c279
}
Packit 74c279
Packit 74c279
long mteTrigger_getNumEntries(int max)
Packit 74c279
{
Packit 74c279
    long count;
Packit 74c279
    /* XXX - implement some form of caching ??? */
Packit 74c279
    count = _mteTrigger_countEntries();
Packit 74c279
    if ( count > _mteTrigger_MaxCount )
Packit 74c279
        _mteTrigger_MaxCount = count;
Packit 74c279
    
Packit 74c279
    return ( max ?  _mteTrigger_MaxCount : count);
Packit 74c279
}