aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/config.c156
-rw-r--r--src/oidtab.c10
-rw-r--r--src/slb.c2
-rw-r--r--src/slb.h8
-rw-r--r--src/snmploop.c169
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)
{
diff --git a/src/slb.c b/src/slb.c
index 51e4d92..b8acb5c 100644
--- a/src/slb.c
+++ b/src/slb.c
@@ -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);
}
diff --git a/src/slb.h b/src/slb.h
index b4f49fb..a2739fb 100644
--- a/src/slb.h
+++ b/src/slb.h
@@ -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); "

Return to:

Send suggestions and report system problems to the System administrator.