diff options
-rw-r--r-- | src/config.c | 156 | ||||
-rw-r--r-- | src/oidtab.c | 10 | ||||
-rw-r--r-- | src/slb.c | 2 | ||||
-rw-r--r-- | src/slb.h | 8 | ||||
-rw-r--r-- | src/snmploop.c | 169 |
5 files changed, 252 insertions, 93 deletions
diff --git a/src/config.c b/src/config.c index 93683f0..76ca179 100644 --- a/src/config.c +++ b/src/config.c @@ -417,8 +417,8 @@ find_asrtop(char *s) return NULL; } -static int -parse_assertion(char **argv, struct grecs_symtab *at, grecs_locus_t *locus) +static struct slb_assertion * +parse_assert_argv(char **argv, struct grecs_symtab *at, grecs_locus_t *locus) { struct slb_assertion *ap; int install; @@ -439,7 +439,7 @@ parse_assertion(char **argv, struct grecs_symtab *at, grecs_locus_t *locus) op = find_asrtop(s); if (!op) { grecs_error(locus, 0, _("invalid operation: %s"), s); - return 1; + return NULL; } opcode = op->opcode; flags ^= op->flags; @@ -447,7 +447,7 @@ parse_assertion(char **argv, struct grecs_symtab *at, grecs_locus_t *locus) oidlen = MAX_OID_LEN; if (!read_objid(argv[0], oid, &oidlen)) { grecs_error(locus, 0, _("cannot parse oid")); - return 1; + return NULL; } install = 1; @@ -457,8 +457,16 @@ parse_assertion(char **argv, struct grecs_symtab *at, grecs_locus_t *locus) ap->opcode = opcode; ap->flags = flags; - ap->value = grecs_strdup(argv[2]); - ap->vallen = strlen(ap->value); + if (strcmp(argv[2], "-prev") == 0) { + ap->value = NULL; + ap->flags |= SLB_ASSERT_PREV; + } else if (argv[2][0] == '-') { + ap->value = grecs_strdup(argv[2] + 1); + ap->vallen = strlen(ap->value); + } else { + ap->value = grecs_strdup(argv[2]); + ap->vallen = strlen(ap->value); + } clone_locus(&ap->locus, locus); len = strlen(argv[0]) + 1 + @@ -470,56 +478,115 @@ parse_assertion(char **argv, struct grecs_symtab *at, grecs_locus_t *locus) strcat(ap->text, argv[1]); strcat(ap->text, " "); strcat(ap->text, argv[2]); - return 0; + return ap; } -int +static struct slb_assertion * +parse_assert_string(char *str, struct grecs_symtab *at, grecs_locus_t *locus) +{ + struct slb_assertion *ap; + struct wordsplit ws; + + if (wordsplit(str, &ws, WRDSF_DEFFLAGS)) { + grecs_error(locus, 0, "can't split argument: %s", + wordsplit_strerror(&ws)); + return NULL; + } + if (ws.ws_wordc > 3) { + grecs_error(locus, 0, "too many arguments to assertion"); + wordsplit_free(&ws); + return NULL; + } else if (ws.ws_wordc < 3) { + grecs_error(locus, 0, "too few arguments to assertion"); + wordsplit_free(&ws); + return NULL; + } + ap = parse_assert_argv(ws.ws_wordv, at, locus); + wordsplit_free(&ws); + return ap; +} + +static int cb_server_assert(enum grecs_callback_command cmd, grecs_locus_t *locus, void *varptr, grecs_value_t *value, void *cb_data) { - struct grecs_symtab *at = *(struct grecs_symtab **)varptr; - int rc; + struct slb_server *srv = varptr; + void **pdata = cb_data; + struct slb_assertion *ap; - if (assert_n_strings(locus, cmd, value, 1, 3)) - return 1; + switch (cmd) { + case grecs_callback_section_begin: + ap = parse_assert_string(value->v.string, srv->assertions, + locus); + if (!ap) + return 1; + *pdata = ap; + break; - if (value->type == GRECS_TYPE_STRING) { - struct wordsplit ws; + case grecs_callback_section_end: + /*ap = *pdata;*/ + break; - if (wordsplit(value->v.string, &ws, WRDSF_DEFFLAGS)) { - grecs_error(locus, 0, - _("can't split argument: %s"), - wordsplit_strerror(&ws)); - return 1; - } - if (ws.ws_wordc > 3) { - grecs_error(locus, 0, - _("too many arguments to assertion")); - wordsplit_free(&ws); - return 1; - } else if (ws.ws_wordc < 3) { - grecs_error(locus, 0, - _("too few arguments to assertion")); - wordsplit_free(&ws); - return 1; + case grecs_callback_set_value: + if (value->type == GRECS_TYPE_STRING) { + if (!parse_assert_string(value->v.string, + srv->assertions, locus)) + return 1; + } else { + char *argv[4]; + + if (assert_n_strings(locus, cmd, value, 3, 3)) + return 1; + + argv[0] = value->v.arg.v[0]->v.string; + argv[1] = value->v.arg.v[1]->v.string; + argv[2] = value->v.arg.v[2]->v.string; + argv[3] = NULL; + if (!parse_assert_argv(argv, srv->assertions, locus)) + return 1; } - rc = parse_assertion(ws.ws_wordv, at, locus); - wordsplit_free(&ws); - } else { - char *argv[4]; - argv[0] = value->v.arg.v[0]->v.string; - argv[1] = value->v.arg.v[1]->v.string; - argv[2] = value->v.arg.v[2]->v.string; - argv[3] = NULL; - rc = parse_assertion(argv, at, locus); } + return 0; +} - return rc; +static int +cb_assertion_action(enum grecs_callback_command cmd, + grecs_locus_t *locus, + void *varptr, + grecs_value_t *value, + void *cb_data) +{ + struct slb_assertion *asrt = varptr; + if (assert_string_value(locus, cmd, value)) + return 1; + if (strcmp(value->v.string, "abort") == 0) + asrt->action = SLB_ASSERT_ABORT; + else if (strcmp(value->v.string, "warn") == 0) + asrt->action = SLB_ASSERT_WARN; + else if (strcmp(value->v.string, "reinit") == 0) + asrt->action = SLB_ASSERT_REINIT; + else { + grecs_error(locus, 0, "unknown action"); + return 1; + } + return 0; } +static struct grecs_keyword server_assert_kw[] = { + { "action", N_("{abort|warn|reinit}"), + N_("Action to take when the assertion fails"), + grecs_type_string, GRECS_DFLT, + NULL, 0, + cb_assertion_action }, + { "message", NULL, N_("Message to issue when the assertion fails"), + grecs_type_string, GRECS_DFLT, + NULL, offsetof(struct slb_assertion, text) }, + { NULL } +}; + int cb_server_macro(enum grecs_callback_command cmd, grecs_locus_t *locus, @@ -866,10 +933,11 @@ static struct grecs_keyword server_kw[] = { "Each of these can be suffixed with \"/i\" to request case-insensitive\n" "comparison.\n" "\n" - "A \"!\" in front of opcode reverts its meaning."), - grecs_type_string, GRECS_MULT, - NULL, offsetof(struct slb_server, assertions), - cb_server_assert }, + "A \"!\" in front of opcode reverts its meaning.\n\n" + "The block part is optional. If omitted, the default action is \"abort\""), + grecs_type_section, GRECS_MULT, + NULL, 0, + cb_server_assert, NULL, server_assert_kw }, { NULL } }; diff --git a/src/oidtab.c b/src/oidtab.c index c713a2b..09a0cde 100644 --- a/src/oidtab.c +++ b/src/oidtab.c @@ -73,6 +73,16 @@ oidtab_install(struct grecs_symtab *oidtab, struct slb_varinstance *vinst) return grecs_symtab_lookup_or_install(oidtab, &key, &install) == NULL; } +int +oidtab_delete(struct grecs_symtab *oidtab, struct slb_varinstance *vinst) +{ + struct slb_oidref key; + int install = 1; + + key.inst = vinst; + return grecs_symtab_remove(oidtab, &key); +} + static int _create_ref(void *sym, void *data) { @@ -126,6 +126,8 @@ slb_snmp_setup() itself should be printed, without the type prefix and quotes */ netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT, 1); + netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_NUMERIC_TIMETICKS, 1); } @@ -235,6 +235,7 @@ int varinst_allset(struct grecs_symtab *vit); struct grecs_symtab *create_oidtab(struct grecs_symtab *vit); int oidtab_install(struct grecs_symtab *oidtab, struct slb_varinstance *vinst); +int oidtab_delete(struct grecs_symtab *oidtab, struct slb_varinstance *vinst); struct slb_varinstance *oidtab_lookup(struct grecs_symtab *oidtab, oid *name, size_t name_length); @@ -313,6 +314,7 @@ char *slb_format_oid_value(oid *oid, size_t len, struct variable_list *vp, #define SLB_ASSERT_NEG 0x01 #define SLB_ASSERT_ICASE 0x02 +#define SLB_ASSERT_PREV 0x04 /* Opcodes */ #define SLB_ASSERT_EQ 1 @@ -323,11 +325,17 @@ char *slb_format_oid_value(oid *oid, size_t len, struct variable_list *vp, #define SLB_ASSERT_LT 6 #define SLB_ASSERT_LE 7 +/* Actions */ +#define SLB_ASSERT_ABORT 0 +#define SLB_ASSERT_WARN 1 +#define SLB_ASSERT_REINIT 2 + struct slb_assertion { oid name[MAX_OID_LEN]; size_t length; int opcode; int flags; + int action; char *value; size_t vallen; char *text; diff --git a/src/snmploop.c b/src/snmploop.c index 5d1e98e..3ce638f 100644 --- a/src/snmploop.c +++ b/src/snmploop.c @@ -66,6 +66,40 @@ slb_format_oid_value(oid *oid, size_t len, struct variable_list *vp, return (char*) cache->cache_buffer; } +static int +assrt_clear_prev(void *sym, void *data) +{ + struct slb_assertion *ap = sym; + if (ap->flags & SLB_ASSERT_PREV) { + free(ap->value); + ap->value = NULL; + } + return 0; +} + +static int +table_clear(void *sym, void *data) +{ + struct slb_table *tab = sym; + grecs_symtab_clear(tab->tab_idx); + return 0; +} + +/* Re-initialize server state */ +static int +slb_server_init(struct slb_server *srv, int clrflag) +{ + slb_node_state_init(srv->state); + srv->expr->ex_eval_count = 0; + grecs_symtab_enumerate(srv->assertions, + assrt_clear_prev, + NULL); + if (clrflag) { + grecs_symtab_enumerate(srv->tables, table_clear, NULL); + srv->flags &= ~clrflag; + } +} + #define E_VARINST_OK 0 #define E_VARINST_UNSUPPORTED 1 #define E_VARINST_OVERFLOW 2 @@ -125,7 +159,8 @@ varinst_assign(struct slb_varinstance *inst, struct variable_list *var, } static int -assertion_test(struct slb_assertion *ap, struct variable_list *vp) +assertion_test(struct slb_server *srv, struct slb_assertion *ap, + struct variable_list *vp) { size_t out_len = 0; int rc; @@ -134,40 +169,55 @@ assertion_test(struct slb_assertion *ap, struct variable_list *vp) buf = slb_format_oid_value(ap->name, ap->length, vp, &ap->cache); if (!buf) return 1; - switch (ap->opcode) { - case SLB_ASSERT_EQ: - rc = ((ap->flags & SLB_ASSERT_ICASE) ? strcasecmp : strcmp) - (ap->value, buf)== 0; - break; - case SLB_ASSERT_PREFIX: - rc = strlen(buf) >= ap->vallen && - ((ap->flags & SLB_ASSERT_ICASE) ? - strncasecmp : strncmp) (buf, ap->value, ap->vallen) - == 0; - break; - case SLB_ASSERT_SUFFIX: - rc = strlen(buf) >= ap->vallen && - ((ap->flags & SLB_ASSERT_ICASE) ? - strncasecmp : strncmp) - (buf + strlen(buf) - ap->vallen, - ap->value, ap->vallen) == 0; - break; - case SLB_ASSERT_GLOB: - rc = wildmatch(ap->value, buf, - ap->flags & SLB_ASSERT_ICASE) == 0; - break; - case SLB_ASSERT_EQUAL: - /* FIXME */ - rc = strtoul(buf, NULL, 10) == strtoul(ap->value, NULL, 10); - break; - case SLB_ASSERT_LT: - rc = strtoul(buf, NULL, 10) < strtoul(ap->value, NULL, 10); - break; - case SLB_ASSERT_LE: - rc = strtoul(buf, NULL, 10) <= strtoul(ap->value, NULL, 10); + + if (!ap->value) { + rc = 1; + } else { + switch (ap->opcode) { + case SLB_ASSERT_EQ: + rc = ((ap->flags & SLB_ASSERT_ICASE) ? + strcasecmp : strcmp) + (ap->value, buf) == 0; + break; + case SLB_ASSERT_PREFIX: + rc = strlen(buf) >= ap->vallen && + ((ap->flags & SLB_ASSERT_ICASE) ? + strncasecmp : strncmp) + (buf, ap->value, ap->vallen) == 0; + break; + case SLB_ASSERT_SUFFIX: + rc = strlen(buf) >= ap->vallen && + ((ap->flags & SLB_ASSERT_ICASE) ? + strncasecmp : strncmp) + (buf + strlen(buf) - ap->vallen, + ap->value, ap->vallen) == 0; + break; + case SLB_ASSERT_GLOB: + rc = wildmatch(ap->value, buf, + ap->flags & SLB_ASSERT_ICASE) == 0; + break; + case SLB_ASSERT_EQUAL: + /* FIXME */ + rc = strtoul(buf, NULL, 10) == + strtoul(ap->value, NULL, 10); + break; + case SLB_ASSERT_LT: + rc = strtoul(buf, NULL, 10) < + strtoul(ap->value, NULL, 10); + break; + case SLB_ASSERT_LE: + rc = strtoul(buf, NULL, 10) <= + strtoul(ap->value, NULL, 10); + } + if (ap->flags & SLB_ASSERT_NEG) + rc = !rc; + } + + if (ap->flags & SLB_ASSERT_PREV) { + free(ap->value); + ap->value = grecs_strdup(buf); + ap->vallen = strlen(ap->value); } - if (ap->flags & SLB_ASSERT_NEG) - rc = !rc; return rc; } @@ -184,14 +234,40 @@ process_result(struct slb_server *srv, struct snmp_pdu *pdu) ap = assertion_lookup(srv->assertions, vp->name, vp->name_length, NULL); - if (ap && !assertion_test(ap, vp)) { - logmsg(LOG_NOTICE, - "%s:%d: %s: assertion \"%s\" failed, got %s", - ap->locus.beg.file, ap->locus.beg.line, - srvid(srv), - ap->text, - ap->cache.cache_buffer); - return; + if (ap && !assertion_test(srv, ap, vp)) { + switch (ap->action) { + case SLB_ASSERT_ABORT: + logmsg(LOG_NOTICE, + "%s:%d: %s: assertion \"%s\" failed, " + "got %s", + ap->locus.beg.file, ap->locus.beg.line, + srvid(srv), + ap->text, + ap->cache.cache_buffer); + return; + + case SLB_ASSERT_WARN: + logmsg(LOG_NOTICE, + "%s:%d: %s: warning: " + "assertion \"%s\" failed, " + "got %s", + ap->locus.beg.file, ap->locus.beg.line, + srvid(srv), + ap->text, + ap->cache.cache_buffer); + break; + + case SLB_ASSERT_REINIT: + logmsg(LOG_NOTICE, + "%s:%d: %s: assertion \"%s\" failed " + "(got %s); re-initializing server", + ap->locus.beg.file, ap->locus.beg.line, + srvid(srv), + ap->text, + ap->cache.cache_buffer); + slb_server_init(srv, SLB_SRV_TAB_RESOLVED); + return; + } } inst = oidtab_lookup(srv->oidtab, vp->name, vp->name_length); @@ -312,7 +388,6 @@ oid_to_table(struct slb_server *srv, oid *oid, size_t oidlen) return clos.result; } - static void process_next(struct slb_server *srv, struct snmp_pdu *pdu) { @@ -358,11 +433,7 @@ _process_pdu(int operation, struct slb_server *srv, proc(srv, pdu); } else { logmsg(LOG_ERR, "server %s: timeout", srvid(srv)); - /* Re-initialize server state */ - slb_node_state_init(srv->state); - srv->expr->ex_eval_count = 0; - if (clrflag) - srv->flags &= ~clrflag; + slb_server_init(srv, clrflag); } } @@ -592,7 +663,7 @@ resolve_tabref(struct slb_varinstance *vinst, struct slb_server *srv) grecs_txtacc_grow_char(acc, 0); mib = grecs_txtacc_finish(acc, 0); vinst->vi_oidlen = MAX_OID_LEN; - /* FIXME: oidtab_delete(srv->oidtab, vinst) */ + oidtab_delete(srv->oidtab, vinst); if (!read_objid(mib, vinst->vi_oid, &vinst->vi_oidlen)) { logmsg(LOG_NOTICE, "%s:%d: cannot parse %s (MIB %s); " |