diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2012-02-20 12:24:48 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2012-02-20 12:24:48 +0200 |
commit | 330125a219489f1253fa7d1d9eba9e5ddeb82770 (patch) | |
tree | c9397a854a2ae7d3318380dce5f32bba2fd74945 | |
parent | 73b4e38d693e80c8e2f8c8f990e063c9e919894a (diff) | |
download | slb-330125a219489f1253fa7d1d9eba9e5ddeb82770.tar.gz slb-330125a219489f1253fa7d1d9eba9e5ddeb82770.tar.bz2 |
Introduce "assertion actions".
* src/config.c (parse_assertion): Handle "-prev" value.
(cb_server_assert): Handle block statement.
(cb_assertion_action): New callback.
(server_kw) <assert>: Can be a block statement.
* src/oidtab.c (oidtab_delete): New functions.
* src/slb.c (slb_snmp_setup): Set the NETSNMP_DS_LIB_NUMERIC_TIMETICKS
option.
* src/slb.h (oidtab_delete): New proto.
(SLB_ASSERT_PREV): New flag.
(SLB_ASSERT_ABORT,SLB_ASSERT_WARN)
(SLB_ASSERT_REINIT): New constants.
(slb_assertion) <action>: New member.
* src/snmploop.c (assertion_test): Handle "-prev" value
(compare with previous value of the same OID, when available.
(process_result): Handle different assertion actions.
(_process_pdu): Call slb_server_init.
(resolve_tabref): Call oidtab_delete.
-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 @@ -419,4 +419,4 @@ find_asrtop(char *s) -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) { @@ -441,3 +441,3 @@ parse_assertion(char **argv, struct grecs_symtab *at, grecs_locus_t *locus) grecs_error(locus, 0, _("invalid operation: %s"), s); - return 1; + return NULL; } @@ -449,3 +449,3 @@ parse_assertion(char **argv, struct grecs_symtab *at, grecs_locus_t *locus) grecs_error(locus, 0, _("cannot parse oid")); - return 1; + return NULL; } @@ -459,4 +459,12 @@ parse_assertion(char **argv, struct grecs_symtab *at, grecs_locus_t *locus) 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); @@ -472,6 +480,31 @@ parse_assertion(char **argv, struct grecs_symtab *at, grecs_locus_t *locus) 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, @@ -482,42 +515,76 @@ cb_server_assert(enum grecs_callback_command cmd, { - 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 @@ -868,6 +935,7 @@ static struct grecs_keyword server_kw[] = { "\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 @@ -75,2 +75,12 @@ oidtab_install(struct grecs_symtab *oidtab, struct slb_varinstance *vinst) +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 @@ -128,2 +128,4 @@ slb_snmp_setup() NETSNMP_DS_LIB_QUICK_PRINT, 1); + netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_NUMERIC_TIMETICKS, 1); } @@ -237,2 +237,3 @@ 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, @@ -315,2 +316,3 @@ char *slb_format_oid_value(oid *oid, size_t len, struct variable_list *vp, #define SLB_ASSERT_ICASE 0x02 +#define SLB_ASSERT_PREV 0x04 @@ -325,2 +327,7 @@ char *slb_format_oid_value(oid *oid, size_t len, struct variable_list *vp, +/* Actions */ +#define SLB_ASSERT_ABORT 0 +#define SLB_ASSERT_WARN 1 +#define SLB_ASSERT_REINIT 2 + struct slb_assertion { @@ -330,2 +337,3 @@ struct slb_assertion { int flags; + int action; char *value; diff --git a/src/snmploop.c b/src/snmploop.c index 5d1e98e..3ce638f 100644 --- a/src/snmploop.c +++ b/src/snmploop.c @@ -68,2 +68,36 @@ slb_format_oid_value(oid *oid, size_t len, struct variable_list *vp, +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 @@ -127,3 +161,4 @@ 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) { @@ -136,36 +171,51 @@ assertion_test(struct slb_assertion *ap, struct variable_list *vp) 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; @@ -186,10 +236,36 @@ process_result(struct slb_server *srv, struct snmp_pdu *pdu) 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; + } } @@ -314,3 +390,2 @@ oid_to_table(struct slb_server *srv, oid *oid, size_t oidlen) - static void @@ -360,7 +435,3 @@ _process_pdu(int operation, struct slb_server *srv, 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); } @@ -594,3 +665,3 @@ resolve_tabref(struct slb_varinstance *vinst, struct slb_server *srv) 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)) { |