From 5710b413963d2fde9d062127ed72672b8a58a07e Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 7 Jul 2011 08:22:40 +0200 Subject: milestone/[PARTWORK]: integrted script filter, but var access is missing --- grammar/rainerscript.c | 658 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 658 insertions(+) create mode 100644 grammar/rainerscript.c (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c new file mode 100644 index 00000000..801a52b2 --- /dev/null +++ b/grammar/rainerscript.c @@ -0,0 +1,658 @@ +/* rainerscript.c - routines to support RainerScript config language + * + * Module begun 2011-07-01 by Rainer Gerhards + * + * Copyright 2011 Rainer Gerhards and Adiscon GmbH. + * + * This file is part of the rsyslog runtime library. + * + * The rsyslog runtime library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The rsyslog runtime library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the rsyslog runtime library. If not, see . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. + */ + +#include "config.h" +#include +#include +#include +#include +#include +#include "rainerscript.h" +#include "parserif.h" +#include "grammar.h" + +void +readConfFile(FILE *fp, es_str_t **str) +{ + char ln[10240]; + char buf[512]; + int lenBuf; + int bWriteLineno = 0; + int len, i; + int start; /* start index of to be submitted text */ + int bContLine = 0; + int lineno = 0; + + *str = es_newStr(4096); + + while(fgets(ln, sizeof(ln), fp) != NULL) { + ++lineno; + if(bWriteLineno) { + bWriteLineno = 0; + lenBuf = sprintf(buf, "PreprocFileLineNumber(%d)\n", lineno); + es_addBuf(str, buf, lenBuf); + } + len = strlen(ln); + /* if we are continuation line, we need to drop leading WS */ + if(bContLine) { + for(start = 0 ; start < len && isspace(ln[start]) ; ++start) + /* JUST SCAN */; + } else { + start = 0; + } + for(i = len - 1 ; i >= start && isspace(ln[i]) ; --i) + /* JUST SCAN */; + if(i >= 0) { + if(ln[i] == '\\') { + --i; + bContLine = 1; + } else { + if(bContLine) /* write line number if we had cont line */ + bWriteLineno = 1; + bContLine = 0; + } + /* add relevant data to buffer */ + es_addBuf(str, ln+start, i+1 - start); + } + if(!bContLine) + es_addChar(str, '\n'); + } + /* indicate end of buffer to flex */ + es_addChar(str, '\0'); + es_addChar(str, '\0'); +} + +struct nvlst* +nvlstNew(es_str_t *name, es_str_t *value) +{ + struct nvlst *lst; + + if((lst = malloc(sizeof(struct nvlst))) != NULL) { + lst->next = NULL; + lst->name = name; + lst->value = value; + } + + return lst; +} + +void +nvlstDestruct(struct nvlst *lst) +{ + struct nvlst *toDel; + + while(lst != NULL) { + toDel = lst; + lst = lst->next; + es_deleteStr(toDel->name); + es_deleteStr(toDel->value); + free(toDel); + } +} + +void +nvlstPrint(struct nvlst *lst) +{ + char *name, *value; + dbgprintf("nvlst %p:\n", lst); + while(lst != NULL) { + name = es_str2cstr(lst->name, NULL); + value = es_str2cstr(lst->value, NULL); + dbgprintf("\tname: '%s', value '%s'\n", name, value); + free(name); + free(value); + lst = lst->next; + } +} + +struct cnfobj* +cnfobjNew(enum cnfobjType objType, struct nvlst *lst) +{ + struct cnfobj *o; + + if((o = malloc(sizeof(struct nvlst))) != NULL) { + o->objType = objType; + o->nvlst = lst; + } + + return o; +} + +void +cnfobjDestruct(struct cnfobj *o) +{ + if(o != NULL) { + nvlstDestruct(o->nvlst); + free(o); + } +} + +void +cnfobjPrint(struct cnfobj *o) +{ + dbgprintf("obj: '%s'\n", cnfobjType2str(o->objType)); + nvlstPrint(o->nvlst); +} + + +struct cnfactlst* +cnfactlstNew(enum cnfactType actType, struct nvlst *lst, char *actLine) +{ + struct cnfactlst *actlst; + + if((actlst = malloc(sizeof(struct cnfactlst))) != NULL) { + actlst->next = NULL; + actlst->syslines = NULL; + actlst->actType = actType; + if(actType == CNFACT_V2) + actlst->data.lst = lst; + else + actlst->data.legActLine = actLine; + } + return actlst; +} + +struct cnfactlst* +cnfactlstAddSysline(struct cnfactlst* actlst, char *line) +{ + struct cnfcfsyslinelst *cflst; + + if((cflst = malloc(sizeof(struct cnfcfsyslinelst))) != NULL) { + cflst->next = NULL; + cflst->line = line; + if(actlst->syslines == NULL) { + actlst->syslines = cflst; + } else { + cflst->next = actlst->syslines; + actlst->syslines = cflst; + } + } + return actlst; +} + +void +cnfactlstDestruct(struct cnfactlst *actlst) +{ + struct cnfactlst *toDel; + + while(actlst != NULL) { + toDel = actlst; + actlst = actlst->next; + if(toDel->actType == CNFACT_V2) + nvlstDestruct(toDel->data.lst); + else + free(toDel->data.legActLine); + free(toDel); + } + +} + +static inline struct cnfcfsyslinelst* +cnfcfsyslinelstReverse(struct cnfcfsyslinelst *lst) +{ + struct cnfcfsyslinelst *curr, *prev; + if(lst == NULL) + return NULL; + prev = NULL; + while(lst != NULL) { + curr = lst; + lst = lst->next; + curr->next = prev; + prev = curr; + } + return prev; +} + +struct cnfactlst* +cnfactlstReverse(struct cnfactlst *actlst) +{ + struct cnfactlst *curr, *prev; + + prev = NULL; + while(actlst != NULL) { + //dbgprintf("reversing: %s\n", actlst->data.legActLine); + curr = actlst; + actlst = actlst->next; + curr->syslines = cnfcfsyslinelstReverse(curr->syslines); + curr->next = prev; + prev = curr; + } + return prev; +} + +void +cnfactlstPrint(struct cnfactlst *actlst) +{ + struct cnfcfsyslinelst *cflst; + + while(actlst != NULL) { + dbgprintf("aclst %p: ", actlst); + if(actlst->actType == CNFACT_V2) { + dbgprintf("V2 action type: "); + nvlstPrint(actlst->data.lst); + } else { + dbgprintf("legacy action line: '%s'\n", + actlst->data.legActLine); + } + for( cflst = actlst->syslines + ; cflst != NULL ; cflst = cflst->next) { + dbgprintf("action:cfsysline: '%s'\n", cflst->line); + } + actlst = actlst->next; + } +} + +struct cnfexpr* +cnfexprNew(unsigned nodetype, struct cnfexpr *l, struct cnfexpr *r) +{ + struct cnfexpr *expr; + + /* optimize some constructs during parsing */ + if(nodetype == 'M' && r->nodetype == 'N') { + ((struct cnfnumval*)r)->val *= -1; + expr = r; + goto done; + } + + if((expr = malloc(sizeof(struct cnfexpr))) != NULL) { + expr->nodetype = nodetype; + expr->l = l; + expr->r = r; + } +done: + return expr; +} + +/* ensure that retval is a number; if string is no number, + * emit error message and set number to 0. + */ +static inline long long +exprret2Number(struct exprret *r) +{ + if(r->datatype == 'S') { + dbgprintf("toNumber CONVERSION MISSING\n"); abort(); + } + return r->d.n; +} + +/* ensure that retval is a string; if string is no number, + * emit error message and set number to 0. + */ +static inline es_str_t * +exprret2String(struct exprret *r) +{ + if(r->datatype == 'N') { + dbgprintf("toString CONVERSION MISSING\n"); abort(); + } + return r->d.estr; +} + +#define COMP_NUM_BINOP(x) \ + cnfexprEval(expr->l, &l); \ + cnfexprEval(expr->r, &r); \ + ret->datatype = 'N'; \ + ret->d.n = exprret2Number(&l) x exprret2Number(&r) + +/* evaluate an expression. + * Note that we try to avoid malloc whenever possible (because on + * the large overhead it has, especially on highly threaded programs). + * As such, the each caller level must provide buffer space for the + * result on its stack during recursion. This permits the callee to store + * the return value without malloc. As the value is a somewhat larger + * struct, we could otherwise not return it without malloc. + * Note that we implement boolean shortcut operations. For our needs, there + * simply is no case where full evaluation would make any sense at all. + */ +void +cnfexprEval(struct cnfexpr *expr, struct exprret *ret) +{ + struct exprret r, l; /* memory for subexpression results */ + + //dbgprintf("eval expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); + switch(expr->nodetype) { + case CMP_EQ: + COMP_NUM_BINOP(==); + break; + case CMP_NE: + COMP_NUM_BINOP(!=); + break; + case CMP_LE: + COMP_NUM_BINOP(<=); + break; + case CMP_GE: + COMP_NUM_BINOP(>=); + break; + case CMP_LT: + COMP_NUM_BINOP(<); + break; + case CMP_GT: + COMP_NUM_BINOP(>); + break; + case OR: + cnfexprEval(expr->l, &l); + ret->datatype = 'N'; + if(exprret2Number(&l)) { + ret->d.n = 1ll; + } else { + cnfexprEval(expr->r, &r); + if(exprret2Number(&r)) + ret->d.n = 1ll; + else + ret->d.n = 0ll; + } + break; + case AND: + cnfexprEval(expr->l, &l); + ret->datatype = 'N'; + if(exprret2Number(&l)) { + cnfexprEval(expr->r, &r); + if(exprret2Number(&r)) + ret->d.n = 1ll; + else + ret->d.n = 0ll; + } else { + ret->d.n = 0ll; + } + break; + case NOT: + cnfexprEval(expr->r, &r); + ret->datatype = 'N'; + ret->d.n = !exprret2Number(&r); + break; + case 'N': + ret->datatype = 'N'; + ret->d.n = ((struct cnfnumval*)expr)->val; + break; + case '+': + COMP_NUM_BINOP(+); + break; + case '-': + COMP_NUM_BINOP(-); + break; + case '*': + COMP_NUM_BINOP(*); + break; + case '/': + COMP_NUM_BINOP(/); + break; + case '%': + COMP_NUM_BINOP(%); + break; + case 'M': + cnfexprEval(expr->r, &r); + ret->datatype = 'N'; + ret->d.n = -exprret2Number(&r); + break; + default: + ret->datatype = 'N'; + ret->d.n = 0ll; + dbgprintf("eval error: unknown nodetype %u\n", + (unsigned) expr->nodetype); + break; + } +} + +/* Evaluate an expression as a bool. This is added because expressions are + * mostly used inside filters, and so this function is quite common and + * important. + */ +int +cnfexprEvalBool(struct cnfexpr *expr) +{ + struct exprret ret; + cnfexprEval(expr, &ret); + return exprret2Number(&ret); +} + +inline static void +doIndent(int indent) +{ + int i; + for(i = 0 ; i < indent ; ++i) + dbgprintf(" "); +} +void +cnfexprPrint(struct cnfexpr *expr, int indent) +{ + struct cnffparamlst *param; + //dbgprintf("expr %p, indent %d, type '%c'\n", expr, indent, expr->nodetype); + switch(expr->nodetype) { + case CMP_EQ: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("==\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_NE: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("!=\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_LE: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("<=\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_GE: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf(">=\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_LT: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("<\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_GT: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf(">\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_CONTAINS: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("CONTAINS\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_CONTAINSI: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("CONTAINS_I\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_STARTSWITH: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("STARTSWITH\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_STARTSWITHI: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("STARTSWITH_I\n"); + cnfexprPrint(expr->r, indent+1); + break; + case OR: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("OR\n"); + cnfexprPrint(expr->r, indent+1); + break; + case AND: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("AND\n"); + cnfexprPrint(expr->r, indent+1); + break; + case NOT: + doIndent(indent); + dbgprintf("NOT\n"); + cnfexprPrint(expr->r, indent+1); + break; + case 'S': + doIndent(indent); + cstrPrint("string '", ((struct cnfstringval*)expr)->estr); + dbgprintf("'\n"); + break; + case 'N': + doIndent(indent); + dbgprintf("%lld\n", ((struct cnfnumval*)expr)->val); + break; + case 'V': + doIndent(indent); + dbgprintf("var '%s'\n", ((struct cnfvar*)expr)->name); + break; + case 'F': + doIndent(indent); + cstrPrint("function '", ((struct cnffunc*)expr)->fname); + dbgprintf("'\n"); + for( param = ((struct cnffunc*)expr)->paramlst + ; param != NULL + ; param = param->next) { + cnfexprPrint(param->expr, indent+1); + } + break; + case '+': + case '-': + case '*': + case '/': + case '%': + case 'M': + if(expr->l != NULL) + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("%c\n", (char) expr->nodetype); + cnfexprPrint(expr->r, indent+1); + break; + default: + dbgprintf("error: unknown nodetype %u\n", + (unsigned) expr->nodetype); + break; + } +} + +struct cnfnumval* +cnfnumvalNew(long long val) +{ + struct cnfnumval *numval; + if((numval = malloc(sizeof(struct cnfnumval))) != NULL) { + numval->nodetype = 'N'; + numval->val = val; + } + return numval; +} + +struct cnfstringval* +cnfstringvalNew(es_str_t *estr) +{ + struct cnfstringval *strval; + if((strval = malloc(sizeof(struct cnfstringval))) != NULL) { + strval->nodetype = 'S'; + strval->estr = estr; + } + return strval; +} + +struct cnfvar* +cnfvarNew(char *name) +{ + struct cnfvar *var; + if((var = malloc(sizeof(struct cnfvar))) != NULL) { + var->nodetype = 'V'; + var->name = name; + } + return var; +} + +struct cnfrule * +cnfruleNew(enum cnfFiltType filttype, struct cnfactlst *actlst) +{ + struct cnfrule* cnfrule; + if((cnfrule = malloc(sizeof(struct cnfrule))) != NULL) { + cnfrule->nodetype = 'R'; + cnfrule->filttype = filttype; + cnfrule->actlst = cnfactlstReverse(actlst); + } + return cnfrule; +} + +void +cnfrulePrint(struct cnfrule *rule) +{ + dbgprintf("------ start rule %p:\n", rule); + dbgprintf("%s: ", cnfFiltType2str(rule->filttype)); + switch(rule->filttype) { + case CNFFILT_NONE: + break; + case CNFFILT_PRI: + case CNFFILT_PROP: + dbgprintf("%s\n", rule->filt.s); + break; + case CNFFILT_SCRIPT: + dbgprintf("\n"); + cnfexprPrint(rule->filt.expr, 0); + break; + } + cnfactlstPrint(rule->actlst); + dbgprintf("------ end rule %p\n", rule); +} + +struct cnffparamlst * +cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next) +{ + struct cnffparamlst* lst; + if((lst = malloc(sizeof(struct cnffparamlst))) != NULL) { + lst->nodetype = 'P'; + lst->expr = expr; + lst->next = next; + } + return lst; +} + +struct cnffunc * +cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) +{ + struct cnffunc* func; + if((func = malloc(sizeof(struct cnffunc))) != NULL) { + func->nodetype = 'F'; + func->fname = fname; + func->paramlst = paramlst; + } + return func; +} + +void +cstrPrint(char *text, es_str_t *estr) +{ + char *str; + str = es_str2cstr(estr, NULL); + dbgprintf("%s%s", text, str); + free(str); +} -- cgit v1.2.3 From 8a9e0cc68e3314b02065dcd3424201f25f176dfb Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 7 Jul 2011 16:35:51 +0200 Subject: milestone/[PARTWORK]: obtaining msg vars integrated, "==" works for strings --- grammar/rainerscript.c | 68 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 18 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 801a52b2..ea23dc1a 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -291,8 +291,9 @@ done: static inline long long exprret2Number(struct exprret *r) { + long long n; if(r->datatype == 'S') { - dbgprintf("toNumber CONVERSION MISSING\n"); abort(); + n = es_str2num(r->d.estr); } return r->d.n; } @@ -301,22 +302,24 @@ exprret2Number(struct exprret *r) * emit error message and set number to 0. */ static inline es_str_t * -exprret2String(struct exprret *r) +exprret2String(struct exprret *r, int *bMustFree) { if(r->datatype == 'N') { - dbgprintf("toString CONVERSION MISSING\n"); abort(); + *bMustFree = 1; + return es_newStrFromNumber(r->d.n); } + *bMustFree = 0; return r->d.estr; } #define COMP_NUM_BINOP(x) \ - cnfexprEval(expr->l, &l); \ - cnfexprEval(expr->r, &r); \ + cnfexprEval(expr->l, &l, usrptr); \ + cnfexprEval(expr->r, &r, usrptr); \ ret->datatype = 'N'; \ ret->d.n = exprret2Number(&l) x exprret2Number(&r) /* evaluate an expression. - * Note that we try to avoid malloc whenever possible (because on + * Note that we try to avoid malloc whenever possible (because of * the large overhead it has, especially on highly threaded programs). * As such, the each caller level must provide buffer space for the * result on its stack during recursion. This permits the callee to store @@ -326,14 +329,35 @@ exprret2String(struct exprret *r) * simply is no case where full evaluation would make any sense at all. */ void -cnfexprEval(struct cnfexpr *expr, struct exprret *ret) +cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) { struct exprret r, l; /* memory for subexpression results */ + es_str_t *estr; + int bMustFree; //dbgprintf("eval expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); switch(expr->nodetype) { case CMP_EQ: - COMP_NUM_BINOP(==); + cnfexprEval(expr->l, &l, usrptr); + cnfexprEval(expr->r, &r, usrptr); + ret->datatype = 'N'; + if(l.datatype == 'S') { + if(r.datatype == 'S') { + ret->d.n = !es_strcmp(l.d.estr, r.d.estr); + } else { + estr = exprret2String(&r, &bMustFree); + ret->d.n = !es_strcmp(l.d.estr, estr); + if(bMustFree) es_deleteStr(estr); + } + } else { + if(r.datatype == 'S') { + estr = exprret2String(&l, &bMustFree); + ret->d.n = !es_strcmp(r.d.estr, estr); + if(bMustFree) es_deleteStr(estr); + } else { + ret->d.n = (l.d.n == r.d.n); + } + } break; case CMP_NE: COMP_NUM_BINOP(!=); @@ -351,12 +375,12 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret) COMP_NUM_BINOP(>); break; case OR: - cnfexprEval(expr->l, &l); + cnfexprEval(expr->l, &l, usrptr); ret->datatype = 'N'; if(exprret2Number(&l)) { ret->d.n = 1ll; } else { - cnfexprEval(expr->r, &r); + cnfexprEval(expr->r, &r, usrptr); if(exprret2Number(&r)) ret->d.n = 1ll; else @@ -364,10 +388,10 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret) } break; case AND: - cnfexprEval(expr->l, &l); + cnfexprEval(expr->l, &l, usrptr); ret->datatype = 'N'; if(exprret2Number(&l)) { - cnfexprEval(expr->r, &r); + cnfexprEval(expr->r, &r, usrptr); if(exprret2Number(&r)) ret->d.n = 1ll; else @@ -377,7 +401,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret) } break; case NOT: - cnfexprEval(expr->r, &r); + cnfexprEval(expr->r, &r, usrptr); ret->datatype = 'N'; ret->d.n = !exprret2Number(&r); break; @@ -385,6 +409,14 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret) ret->datatype = 'N'; ret->d.n = ((struct cnfnumval*)expr)->val; break; + case 'S': + ret->datatype = 'S'; + ret->d.estr = es_strdup(((struct cnfstringval*)expr)->estr); + break; + case 'V': + ret->datatype = 'S'; + ret->d.estr = cnfGetVar(((struct cnfvar*)expr)->name, usrptr); + break; case '+': COMP_NUM_BINOP(+); break; @@ -401,15 +433,15 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret) COMP_NUM_BINOP(%); break; case 'M': - cnfexprEval(expr->r, &r); + cnfexprEval(expr->r, &r, usrptr); ret->datatype = 'N'; ret->d.n = -exprret2Number(&r); break; default: ret->datatype = 'N'; ret->d.n = 0ll; - dbgprintf("eval error: unknown nodetype %u\n", - (unsigned) expr->nodetype); + dbgprintf("eval error: unknown nodetype %u['%c']\n", + (unsigned) expr->nodetype, (char) expr->nodetype); break; } } @@ -419,10 +451,10 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret) * important. */ int -cnfexprEvalBool(struct cnfexpr *expr) +cnfexprEvalBool(struct cnfexpr *expr, void *usrptr) { struct exprret ret; - cnfexprEval(expr, &ret); + cnfexprEval(expr, &ret, usrptr); return exprret2Number(&ret); } -- cgit v1.2.3 From 834fe024b4e53f65d9622a176116f232e212e326 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 8 Jul 2011 07:13:56 +0200 Subject: milestone/[PARTWORK]: implemented "CONTAINS" --- grammar/rainerscript.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index ea23dc1a..bcc73af0 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -332,8 +332,9 @@ void cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) { struct exprret r, l; /* memory for subexpression results */ - es_str_t *estr; + es_str_t *estr_r, *estr_l; int bMustFree; + int bMustFree2; //dbgprintf("eval expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); switch(expr->nodetype) { @@ -345,15 +346,15 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) if(r.datatype == 'S') { ret->d.n = !es_strcmp(l.d.estr, r.d.estr); } else { - estr = exprret2String(&r, &bMustFree); - ret->d.n = !es_strcmp(l.d.estr, estr); - if(bMustFree) es_deleteStr(estr); + estr_r = exprret2String(&r, &bMustFree); + ret->d.n = !es_strcmp(l.d.estr, estr_r); + if(bMustFree) es_deleteStr(estr_r); } } else { if(r.datatype == 'S') { - estr = exprret2String(&l, &bMustFree); - ret->d.n = !es_strcmp(r.d.estr, estr); - if(bMustFree) es_deleteStr(estr); + estr_l = exprret2String(&l, &bMustFree); + ret->d.n = !es_strcmp(r.d.estr, estr_l); + if(bMustFree) es_deleteStr(estr_l); } else { ret->d.n = (l.d.n == r.d.n); } @@ -374,6 +375,17 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) case CMP_GT: COMP_NUM_BINOP(>); break; + case CMP_CONTAINS: + cnfexprEval(expr->l, &l, usrptr); + cnfexprEval(expr->r, &r, usrptr); + estr_r = exprret2String(&r, &bMustFree); + estr_l = exprret2String(&l, &bMustFree2); + ret->datatype = 'N'; +dbgprintf("ZZZZ: contains ret %d\n", es_strContains(estr_l, estr_r)); + ret->d.n = es_strContains(estr_l, estr_r) != -1; + if(bMustFree) es_deleteStr(estr_r); + if(bMustFree2) es_deleteStr(estr_l); + break; case OR: cnfexprEval(expr->l, &l, usrptr); ret->datatype = 'N'; -- cgit v1.2.3 From d9ea755214ab75afa039a4df89f828d4b8b30ef0 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 8 Jul 2011 09:13:39 +0200 Subject: milestone/[PARTWORK]: implemented comparison operations --- grammar/rainerscript.c | 252 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 219 insertions(+), 33 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index bcc73af0..0def9653 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -286,14 +286,17 @@ done: } /* ensure that retval is a number; if string is no number, - * emit error message and set number to 0. + * try to convert it to one. The semantics from es_str2num() + * are used (bSuccess tells if the conversion went well or not). */ static inline long long -exprret2Number(struct exprret *r) +exprret2Number(struct exprret *r, int *bSuccess) { long long n; if(r->datatype == 'S') { - n = es_str2num(r->d.estr); + n = es_str2num(r->d.estr, bSuccess); + } else { + *bSuccess = 1; } return r->d.n; } @@ -316,7 +319,17 @@ exprret2String(struct exprret *r, int *bMustFree) cnfexprEval(expr->l, &l, usrptr); \ cnfexprEval(expr->r, &r, usrptr); \ ret->datatype = 'N'; \ - ret->d.n = exprret2Number(&l) x exprret2Number(&r) + ret->d.n = exprret2Number(&l, &convok_l) x exprret2Number(&r, &convok_r) + +#define PREP_TWO_STRINGS \ + cnfexprEval(expr->l, &l, usrptr); \ + cnfexprEval(expr->r, &r, usrptr); \ + estr_r = exprret2String(&r, &bMustFree); \ + estr_l = exprret2String(&l, &bMustFree2) + +#define FREE_TWO_STRINGS \ + if(bMustFree) es_deleteStr(estr_r); \ + if(bMustFree2) es_deleteStr(estr_l) /* evaluate an expression. * Note that we try to avoid malloc whenever possible (because of @@ -333,67 +346,239 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) { struct exprret r, l; /* memory for subexpression results */ es_str_t *estr_r, *estr_l; - int bMustFree; - int bMustFree2; + int convok_r, convok_l; + int bMustFree, bMustFree2; + long long n_r, n_l; //dbgprintf("eval expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); switch(expr->nodetype) { + /* note: comparison operations are extremely similar. The code can be copyied, only + * places flagged with "CMP" need to be changed. + */ case CMP_EQ: cnfexprEval(expr->l, &l, usrptr); cnfexprEval(expr->r, &r, usrptr); ret->datatype = 'N'; if(l.datatype == 'S') { if(r.datatype == 'S') { - ret->d.n = !es_strcmp(l.d.estr, r.d.estr); + ret->d.n = !es_strcmp(l.d.estr, r.d.estr); /*CMP*/ } else { - estr_r = exprret2String(&r, &bMustFree); - ret->d.n = !es_strcmp(l.d.estr, estr_r); - if(bMustFree) es_deleteStr(estr_r); + n_l = exprret2Number(&l, &convok_l); + if(convok_l) { + ret->d.n = (n_l == r.d.n); /*CMP*/ + } else { + estr_r = exprret2String(&r, &bMustFree); + ret->d.n = !es_strcmp(l.d.estr, estr_r); /*CMP*/ + if(bMustFree) es_deleteStr(estr_r); + } } } else { if(r.datatype == 'S') { - estr_l = exprret2String(&l, &bMustFree); - ret->d.n = !es_strcmp(r.d.estr, estr_l); - if(bMustFree) es_deleteStr(estr_l); + n_r = exprret2Number(&r, &convok_r); + if(convok_r) { + ret->d.n = (l.d.n == n_r); /*CMP*/ + } else { + estr_l = exprret2String(&l, &bMustFree); + ret->d.n = !es_strcmp(r.d.estr, estr_l); /*CMP*/ + if(bMustFree) es_deleteStr(estr_l); + } } else { - ret->d.n = (l.d.n == r.d.n); + ret->d.n = (l.d.n == r.d.n); /*CMP*/ } } break; case CMP_NE: - COMP_NUM_BINOP(!=); + cnfexprEval(expr->l, &l, usrptr); + cnfexprEval(expr->r, &r, usrptr); + ret->datatype = 'N'; + if(l.datatype == 'S') { + if(r.datatype == 'S') { + ret->d.n = es_strcmp(l.d.estr, r.d.estr); /*CMP*/ + } else { + n_l = exprret2Number(&l, &convok_l); + if(convok_l) { + ret->d.n = (n_l != r.d.n); /*CMP*/ + } else { + estr_r = exprret2String(&r, &bMustFree); + ret->d.n = es_strcmp(l.d.estr, estr_r); /*CMP*/ + if(bMustFree) es_deleteStr(estr_r); + } + } + } else { + if(r.datatype == 'S') { + n_r = exprret2Number(&r, &convok_r); + if(convok_r) { + ret->d.n = (l.d.n != n_r); /*CMP*/ + } else { + estr_l = exprret2String(&l, &bMustFree); + ret->d.n = es_strcmp(r.d.estr, estr_l); /*CMP*/ + if(bMustFree) es_deleteStr(estr_l); + } + } else { + ret->d.n = (l.d.n != r.d.n); /*CMP*/ + } + } break; case CMP_LE: - COMP_NUM_BINOP(<=); + cnfexprEval(expr->l, &l, usrptr); + cnfexprEval(expr->r, &r, usrptr); + ret->datatype = 'N'; + if(l.datatype == 'S') { + if(r.datatype == 'S') { + ret->d.n = es_strcmp(l.d.estr, r.d.estr) <= 0; /*CMP*/ + } else { + n_l = exprret2Number(&l, &convok_l); + if(convok_l) { + ret->d.n = (n_l <= r.d.n); /*CMP*/ + } else { + estr_r = exprret2String(&r, &bMustFree); + ret->d.n = es_strcmp(l.d.estr, estr_r) <= 0; /*CMP*/ + if(bMustFree) es_deleteStr(estr_r); + } + } + } else { + if(r.datatype == 'S') { + n_r = exprret2Number(&r, &convok_r); + if(convok_r) { + ret->d.n = (l.d.n <= n_r); /*CMP*/ + } else { + estr_l = exprret2String(&l, &bMustFree); + ret->d.n = es_strcmp(r.d.estr, estr_l) <= 0; /*CMP*/ + if(bMustFree) es_deleteStr(estr_l); + } + } else { + ret->d.n = (l.d.n <= r.d.n); /*CMP*/ + } + } break; case CMP_GE: - COMP_NUM_BINOP(>=); + cnfexprEval(expr->l, &l, usrptr); + cnfexprEval(expr->r, &r, usrptr); + ret->datatype = 'N'; + if(l.datatype == 'S') { + if(r.datatype == 'S') { + ret->d.n = es_strcmp(l.d.estr, r.d.estr) >= 0; /*CMP*/ + } else { + n_l = exprret2Number(&l, &convok_l); + if(convok_l) { + ret->d.n = (n_l >= r.d.n); /*CMP*/ + } else { + estr_r = exprret2String(&r, &bMustFree); + ret->d.n = es_strcmp(l.d.estr, estr_r) >= 0; /*CMP*/ + if(bMustFree) es_deleteStr(estr_r); + } + } + } else { + if(r.datatype == 'S') { + n_r = exprret2Number(&r, &convok_r); + if(convok_r) { + ret->d.n = (l.d.n >= n_r); /*CMP*/ + } else { + estr_l = exprret2String(&l, &bMustFree); + ret->d.n = es_strcmp(r.d.estr, estr_l) >= 0; /*CMP*/ + if(bMustFree) es_deleteStr(estr_l); + } + } else { + ret->d.n = (l.d.n >= r.d.n); /*CMP*/ + } + } break; case CMP_LT: - COMP_NUM_BINOP(<); + cnfexprEval(expr->l, &l, usrptr); + cnfexprEval(expr->r, &r, usrptr); + ret->datatype = 'N'; + if(l.datatype == 'S') { + if(r.datatype == 'S') { + ret->d.n = es_strcmp(l.d.estr, r.d.estr) < 0; /*CMP*/ + } else { + n_l = exprret2Number(&l, &convok_l); + if(convok_l) { + ret->d.n = (n_l < r.d.n); /*CMP*/ + } else { + estr_r = exprret2String(&r, &bMustFree); + ret->d.n = es_strcmp(l.d.estr, estr_r) < 0; /*CMP*/ + if(bMustFree) es_deleteStr(estr_r); + } + } + } else { + if(r.datatype == 'S') { + n_r = exprret2Number(&r, &convok_r); + if(convok_r) { + ret->d.n = (l.d.n < n_r); /*CMP*/ + } else { + estr_l = exprret2String(&l, &bMustFree); + ret->d.n = es_strcmp(r.d.estr, estr_l) < 0; /*CMP*/ + if(bMustFree) es_deleteStr(estr_l); + } + } else { + ret->d.n = (l.d.n < r.d.n); /*CMP*/ + } + } break; case CMP_GT: - COMP_NUM_BINOP(>); - break; - case CMP_CONTAINS: cnfexprEval(expr->l, &l, usrptr); cnfexprEval(expr->r, &r, usrptr); - estr_r = exprret2String(&r, &bMustFree); - estr_l = exprret2String(&l, &bMustFree2); ret->datatype = 'N'; -dbgprintf("ZZZZ: contains ret %d\n", es_strContains(estr_l, estr_r)); + if(l.datatype == 'S') { + if(r.datatype == 'S') { + ret->d.n = es_strcmp(l.d.estr, r.d.estr) > 0; /*CMP*/ + } else { + n_l = exprret2Number(&l, &convok_l); + if(convok_l) { + ret->d.n = (n_l > r.d.n); /*CMP*/ + } else { + estr_r = exprret2String(&r, &bMustFree); + ret->d.n = es_strcmp(l.d.estr, estr_r) > 0; /*CMP*/ + if(bMustFree) es_deleteStr(estr_r); + } + } + } else { + if(r.datatype == 'S') { + n_r = exprret2Number(&r, &convok_r); + if(convok_r) { + ret->d.n = (l.d.n > n_r); /*CMP*/ + } else { + estr_l = exprret2String(&l, &bMustFree); + ret->d.n = es_strcmp(r.d.estr, estr_l) > 0; /*CMP*/ + if(bMustFree) es_deleteStr(estr_l); + } + } else { + ret->d.n = (l.d.n > r.d.n); /*CMP*/ + } + } + break; + case CMP_STARTSWITH: + PREP_TWO_STRINGS; + ret->datatype = 'N'; + ret->d.n = es_strncmp(estr_l, estr_r, estr_r->lenStr) == 0; + FREE_TWO_STRINGS; + break; + case CMP_STARTSWITHI: + PREP_TWO_STRINGS; + ret->datatype = 'N'; + ret->d.n = es_strncasecmp(estr_l, estr_r, estr_r->lenStr) == 0; + FREE_TWO_STRINGS; + break; + case CMP_CONTAINS: + PREP_TWO_STRINGS; + ret->datatype = 'N'; ret->d.n = es_strContains(estr_l, estr_r) != -1; - if(bMustFree) es_deleteStr(estr_r); - if(bMustFree2) es_deleteStr(estr_l); + FREE_TWO_STRINGS; + break; + case CMP_CONTAINSI: + PREP_TWO_STRINGS; + ret->datatype = 'N'; + ret->d.n = es_strCaseContains(estr_l, estr_r) != -1; + FREE_TWO_STRINGS; break; case OR: cnfexprEval(expr->l, &l, usrptr); ret->datatype = 'N'; - if(exprret2Number(&l)) { + if(exprret2Number(&l, &convok_l)) { ret->d.n = 1ll; } else { cnfexprEval(expr->r, &r, usrptr); - if(exprret2Number(&r)) + if(exprret2Number(&r, &convok_r)) ret->d.n = 1ll; else ret->d.n = 0ll; @@ -402,9 +587,9 @@ dbgprintf("ZZZZ: contains ret %d\n", es_strContains(estr_l, estr_r)); case AND: cnfexprEval(expr->l, &l, usrptr); ret->datatype = 'N'; - if(exprret2Number(&l)) { + if(exprret2Number(&l, &convok_l)) { cnfexprEval(expr->r, &r, usrptr); - if(exprret2Number(&r)) + if(exprret2Number(&r, &convok_r)) ret->d.n = 1ll; else ret->d.n = 0ll; @@ -415,7 +600,7 @@ dbgprintf("ZZZZ: contains ret %d\n", es_strContains(estr_l, estr_r)); case NOT: cnfexprEval(expr->r, &r, usrptr); ret->datatype = 'N'; - ret->d.n = !exprret2Number(&r); + ret->d.n = !exprret2Number(&r, &convok_r); break; case 'N': ret->datatype = 'N'; @@ -447,7 +632,7 @@ dbgprintf("ZZZZ: contains ret %d\n", es_strContains(estr_l, estr_r)); case 'M': cnfexprEval(expr->r, &r, usrptr); ret->datatype = 'N'; - ret->d.n = -exprret2Number(&r); + ret->d.n = -exprret2Number(&r, &convok_r); break; default: ret->datatype = 'N'; @@ -465,9 +650,10 @@ dbgprintf("ZZZZ: contains ret %d\n", es_strContains(estr_l, estr_r)); int cnfexprEvalBool(struct cnfexpr *expr, void *usrptr) { + int convok; struct exprret ret; cnfexprEval(expr, &ret, usrptr); - return exprret2Number(&ret); + return exprret2Number(&ret, &convok); } inline static void -- cgit v1.2.3 From 379bd30a5481056c2e5e71443149fb6b3b2295fc Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 8 Jul 2011 14:50:35 +0200 Subject: milestone/[PARTWORK]: integrated all variable types (msg/sys/cee) --- grammar/rainerscript.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 0def9653..91e71e97 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -285,6 +285,7 @@ done: return expr; } + /* ensure that retval is a number; if string is no number, * try to convert it to one. The semantics from es_str2num() * are used (bSuccess tells if the conversion went well or not). @@ -315,21 +316,28 @@ exprret2String(struct exprret *r, int *bMustFree) return r->d.estr; } +#define FREE_BOTH_RET \ + if(r.datatype == 'S') es_deleteStr(r.d.estr); \ + if(l.datatype == 'S') es_deleteStr(l.d.estr) + #define COMP_NUM_BINOP(x) \ cnfexprEval(expr->l, &l, usrptr); \ cnfexprEval(expr->r, &r, usrptr); \ ret->datatype = 'N'; \ - ret->d.n = exprret2Number(&l, &convok_l) x exprret2Number(&r, &convok_r) + ret->d.n = exprret2Number(&l, &convok_l) x exprret2Number(&r, &convok_r); \ + FREE_BOTH_RET #define PREP_TWO_STRINGS \ cnfexprEval(expr->l, &l, usrptr); \ cnfexprEval(expr->r, &r, usrptr); \ estr_r = exprret2String(&r, &bMustFree); \ - estr_l = exprret2String(&l, &bMustFree2) + estr_l = exprret2String(&l, &bMustFree2); \ + FREE_BOTH_RET #define FREE_TWO_STRINGS \ if(bMustFree) es_deleteStr(estr_r); \ - if(bMustFree2) es_deleteStr(estr_l) + if(bMustFree2) es_deleteStr(estr_l); \ + FREE_BOTH_RET /* evaluate an expression. * Note that we try to avoid malloc whenever possible (because of @@ -386,6 +394,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) ret->d.n = (l.d.n == r.d.n); /*CMP*/ } } + FREE_BOTH_RET; break; case CMP_NE: cnfexprEval(expr->l, &l, usrptr); @@ -418,6 +427,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) ret->d.n = (l.d.n != r.d.n); /*CMP*/ } } + FREE_BOTH_RET; break; case CMP_LE: cnfexprEval(expr->l, &l, usrptr); @@ -450,6 +460,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) ret->d.n = (l.d.n <= r.d.n); /*CMP*/ } } + FREE_BOTH_RET; break; case CMP_GE: cnfexprEval(expr->l, &l, usrptr); @@ -482,6 +493,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) ret->d.n = (l.d.n >= r.d.n); /*CMP*/ } } + FREE_BOTH_RET; break; case CMP_LT: cnfexprEval(expr->l, &l, usrptr); @@ -514,6 +526,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) ret->d.n = (l.d.n < r.d.n); /*CMP*/ } } + FREE_BOTH_RET; break; case CMP_GT: cnfexprEval(expr->l, &l, usrptr); @@ -546,6 +559,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) ret->d.n = (l.d.n > r.d.n); /*CMP*/ } } + FREE_BOTH_RET; break; case CMP_STARTSWITH: PREP_TWO_STRINGS; @@ -583,6 +597,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) else ret->d.n = 0ll; } + FREE_BOTH_RET; break; case AND: cnfexprEval(expr->l, &l, usrptr); @@ -596,11 +611,13 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) } else { ret->d.n = 0ll; } + FREE_BOTH_RET; break; case NOT: cnfexprEval(expr->r, &r, usrptr); ret->datatype = 'N'; ret->d.n = !exprret2Number(&r, &convok_r); + if(r.datatype == 'S') es_deleteStr(r.d.estr); break; case 'N': ret->datatype = 'N'; @@ -633,6 +650,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) cnfexprEval(expr->r, &r, usrptr); ret->datatype = 'N'; ret->d.n = -exprret2Number(&r, &convok_r); + if(r.datatype == 'S') es_deleteStr(r.d.estr); break; default: ret->datatype = 'N'; -- cgit v1.2.3 From f2ef6cd10699ab9f91b9e3e53726512cd290ea68 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 8 Jul 2011 19:00:23 +0200 Subject: optimized function representation --- grammar/rainerscript.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 91e71e97..de15d5f3 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -685,6 +685,9 @@ void cnfexprPrint(struct cnfexpr *expr, int indent) { struct cnffparamlst *param; + struct cnffunc *func; + int i; + //dbgprintf("expr %p, indent %d, type '%c'\n", expr, indent, expr->nodetype); switch(expr->nodetype) { case CMP_EQ: @@ -779,12 +782,11 @@ cnfexprPrint(struct cnfexpr *expr, int indent) break; case 'F': doIndent(indent); - cstrPrint("function '", ((struct cnffunc*)expr)->fname); - dbgprintf("'\n"); - for( param = ((struct cnffunc*)expr)->paramlst - ; param != NULL - ; param = param->next) { - cnfexprPrint(param->expr, indent+1); + func = (struct cnffunc*) expr; + cstrPrint("function '", func->fname); + dbgprintf("' (%u params)\n", (unsigned) func->nParams); + for(i = 0 ; i < func->nParams ; ++i) { + cnfexprPrint(func->expr[i], indent+1); } break; case '+': @@ -888,10 +890,28 @@ struct cnffunc * cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) { struct cnffunc* func; - if((func = malloc(sizeof(struct cnffunc))) != NULL) { + struct cnffparamlst *param, *toDel; + unsigned short i; + unsigned short nParams; + + /* we first need to find out how many params we have */ + nParams = 0; + for(param = paramlst ; param != NULL ; param = param->next) + ++nParams; + if((func = malloc(sizeof(struct cnffunc) + (nParams * sizeof(struct cnfexp*)))) + != NULL) { func->nodetype = 'F'; func->fname = fname; - func->paramlst = paramlst; + func->nParams = nParams; + func->fID = 0; /* use name */ + /* shuffle params over to array (access speed!) */ + param = paramlst; + for(i = 0 ; i < nParams ; ++i) { + func->expr[i] = param->expr; + toDel = param; + param = param->next; + free(toDel); + } } return func; } -- cgit v1.2.3 From f5e0bbe2d9d1d9594a01fc869392374d1a44afbe Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sat, 9 Jul 2011 09:30:17 +0200 Subject: milestone/[PARTWORK]: implemented RainerScript functions --- grammar/rainerscript.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 110 insertions(+), 6 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index de15d5f3..41107de5 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -316,6 +316,91 @@ exprret2String(struct exprret *r, int *bMustFree) return r->d.estr; } +/* Perform a function call. This has been moved out of cnfExprEval in order + * to keep the code small and easier to maintain. + */ +static inline void +doFuncCall(struct cnffunc *func, struct exprret *ret, void* usrptr) +{ + char *fname; + char *envvar; + int bMustFree; + es_str_t *estr; + char *str; + struct exprret r[CNFFUNC_MAX_ARGS]; + + dbgprintf("rainerscript: executing function id %d\n", func->fID); + switch(func->fID) { + case CNFFUNC_STRLEN: + if(func->expr[0]->nodetype == 'S') { + /* if we already have a string, we do not need to + * do one more recursive call. + */ + ret->d.n = es_strlen(((struct cnfstringval*) func->expr[0])->estr); + } else { + cnfexprEval(func->expr[0], &r[0], usrptr); + estr = exprret2String(&r[0], &bMustFree); + ret->d.n = es_strlen(estr); + if(bMustFree) es_deleteStr(estr); + } + ret->datatype = 'N'; + break; + case CNFFUNC_GETENV: + /* note: the optimizer shall have replaced calls to getenv() + * with a constant argument to a single string (once obtained via + * getenv()). So we do NOT need to check if there is just a + * string following. + */ + cnfexprEval(func->expr[0], &r[0], usrptr); + estr = exprret2String(&r[0], &bMustFree); + str = (char*) es_str2cstr(estr, NULL); + envvar = getenv(str); + ret->datatype = 'S'; + ret->d.estr = es_newStrFromCStr(envvar, strlen(envvar)); + if(bMustFree) es_deleteStr(estr); + if(r[0].datatype == 'S') es_deleteStr(r[0].d.estr); + free(str); + break; + case CNFFUNC_TOLOWER: + cnfexprEval(func->expr[0], &r[0], usrptr); + estr = exprret2String(&r[0], &bMustFree); + if(!bMustFree) /* let caller handle that M) */ + estr = es_strdup(estr); + es_tolower(estr); + ret->datatype = 'S'; + ret->d.estr = estr; + break; + case CNFFUNC_CSTR: + cnfexprEval(func->expr[0], &r[0], usrptr); + estr = exprret2String(&r[0], &bMustFree); + if(!bMustFree) /* let caller handle that M) */ + estr = es_strdup(estr); + ret->datatype = 'S'; + ret->d.estr = estr; + break; + case CNFFUNC_CNUM: + if(func->expr[0]->nodetype == 'N') { + ret->d.n = ((struct cnfnumval*)func->expr[0])->val; + } else if(func->expr[0]->nodetype == 'S') { + ret->d.n = es_str2num(((struct cnfstringval*) func->expr[0])->estr, + NULL); + } else { + cnfexprEval(func->expr[0], &r[0], usrptr); + ret->d.n = exprret2Number(&r[0], NULL); + if(r[0].datatype == 'S') es_deleteStr(r[0].d.estr); + } + ret->datatype = 'N'; + break; + default: + if(Debug) { + fname = es_str2cstr(func->fname, NULL); + dbgprintf("rainerscript: invalid function id %u (name '%s')\n", + (unsigned) func->fID, fname); + free(fname); + } + } +} + #define FREE_BOTH_RET \ if(r.datatype == 'S') es_deleteStr(r.d.estr); \ if(l.datatype == 'S') es_deleteStr(l.d.estr) @@ -329,10 +414,9 @@ exprret2String(struct exprret *r, int *bMustFree) #define PREP_TWO_STRINGS \ cnfexprEval(expr->l, &l, usrptr); \ - cnfexprEval(expr->r, &r, usrptr); \ - estr_r = exprret2String(&r, &bMustFree); \ estr_l = exprret2String(&l, &bMustFree2); \ - FREE_BOTH_RET + cnfexprEval(expr->r, &r, usrptr); \ + estr_r = exprret2String(&r, &bMustFree) #define FREE_TWO_STRINGS \ if(bMustFree) es_deleteStr(estr_r); \ @@ -652,6 +736,9 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) ret->d.n = -exprret2Number(&r, &convok_r); if(r.datatype == 'S') es_deleteStr(r.d.estr); break; + case 'F': + doFuncCall((struct cnffunc*) expr, ret, usrptr); + break; default: ret->datatype = 'N'; ret->d.n = 0ll; @@ -684,7 +771,6 @@ doIndent(int indent) void cnfexprPrint(struct cnfexpr *expr, int indent) { - struct cnffparamlst *param; struct cnffunc *func; int i; @@ -784,7 +870,7 @@ cnfexprPrint(struct cnfexpr *expr, int indent) doIndent(indent); func = (struct cnffunc*) expr; cstrPrint("function '", func->fname); - dbgprintf("' (%u params)\n", (unsigned) func->nParams); + dbgprintf("' (id:%d, params:%hu)\n", func->fID, func->nParams); for(i = 0 ; i < func->nParams ; ++i) { cnfexprPrint(func->expr[i], indent+1); } @@ -886,6 +972,24 @@ cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next) return lst; } +static inline enum cnffuncid +funcName2ID(es_str_t *fname) +{ + if(!es_strbufcmp(fname, (unsigned char*)"strlen", sizeof("strlen") - 1)) { + return CNFFUNC_STRLEN; + } else if(!es_strbufcmp(fname, (unsigned char*)"getenv", sizeof("getenv") - 1)) { + return CNFFUNC_GETENV; + } else if(!es_strbufcmp(fname, (unsigned char*)"tolower", sizeof("tolower") - 1)) { + return CNFFUNC_TOLOWER; + } else if(!es_strbufcmp(fname, (unsigned char*)"cstr", sizeof("cstr") - 1)) { + return CNFFUNC_CSTR; + } else if(!es_strbufcmp(fname, (unsigned char*)"cnum", sizeof("cnum") - 1)) { + return CNFFUNC_CNUM; + } else { + return CNFFUNC_INVALID; + } +} + struct cnffunc * cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) { @@ -903,7 +1007,7 @@ cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) func->nodetype = 'F'; func->fname = fname; func->nParams = nParams; - func->fID = 0; /* use name */ + func->fID = funcName2ID(fname); /* shuffle params over to array (access speed!) */ param = paramlst; for(i = 0 ; i < nParams ; ++i) { -- cgit v1.2.3 From 59f8ebdba75d693f7b462f51b7b50136b590dea7 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sat, 9 Jul 2011 09:43:06 +0200 Subject: checking number of parameters provided to function --- grammar/rainerscript.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 41107de5..f8809e13 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -398,6 +398,8 @@ doFuncCall(struct cnffunc *func, struct exprret *ret, void* usrptr) (unsigned) func->fID, fname); free(fname); } + ret->datatype = 'N'; + ret->d.n = 0; } } @@ -972,18 +974,46 @@ cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next) return lst; } +/* Obtain function id from name AND number of params. Issues the + * relevant error messages if errors are detected. + */ static inline enum cnffuncid -funcName2ID(es_str_t *fname) +funcName2ID(es_str_t *fname, unsigned short nParams) { if(!es_strbufcmp(fname, (unsigned char*)"strlen", sizeof("strlen") - 1)) { + if(nParams != 1) { + parser_errmsg("number of parameters for strlen() must be one " + "but is %d.", nParams); + return CNFFUNC_INVALID; + } return CNFFUNC_STRLEN; } else if(!es_strbufcmp(fname, (unsigned char*)"getenv", sizeof("getenv") - 1)) { + if(nParams != 1) { + parser_errmsg("number of parameters for getenv() must be one " + "but is %d.", nParams); + return CNFFUNC_INVALID; + } return CNFFUNC_GETENV; } else if(!es_strbufcmp(fname, (unsigned char*)"tolower", sizeof("tolower") - 1)) { + if(nParams != 1) { + parser_errmsg("number of parameters for tolower() must be one " + "but is %d.", nParams); + return CNFFUNC_INVALID; + } return CNFFUNC_TOLOWER; } else if(!es_strbufcmp(fname, (unsigned char*)"cstr", sizeof("cstr") - 1)) { + if(nParams != 1) { + parser_errmsg("number of parameters for cstr() must be one " + "but is %d.", nParams); + return CNFFUNC_INVALID; + } return CNFFUNC_CSTR; } else if(!es_strbufcmp(fname, (unsigned char*)"cnum", sizeof("cnum") - 1)) { + if(nParams != 1) { + parser_errmsg("number of parameters for cnum() must be one " + "but is %d.", nParams); + return CNFFUNC_INVALID; + } return CNFFUNC_CNUM; } else { return CNFFUNC_INVALID; @@ -1007,7 +1037,7 @@ cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) func->nodetype = 'F'; func->fname = fname; func->nParams = nParams; - func->fID = funcName2ID(fname); + func->fID = funcName2ID(fname, nParams); /* shuffle params over to array (access speed!) */ param = paramlst; for(i = 0 ; i < nParams ; ++i) { -- cgit v1.2.3 From 6ebf9ada253ffd8c88cbe84a46fd5aa3bfd58367 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sat, 9 Jul 2011 18:00:29 +0200 Subject: milestone/[WORKS AGAIN!]: looks like the new conf format is integrated finally completed $IncludeConfig processing. --- grammar/rainerscript.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index f8809e13..680f8775 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -28,6 +28,9 @@ #include #include #include +#include +#include +#include #include #include "rainerscript.h" #include "parserif.h" @@ -1050,6 +1053,55 @@ cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) return func; } +int +cnfDoInclude(char *name) +{ + char *cfgFile; + unsigned i; + int result; + glob_t cfgFiles; + struct stat fileInfo; + + /* Use GLOB_MARK to append a trailing slash for directories. + * Required by doIncludeDirectory(). + */ + result = glob(name, GLOB_MARK, NULL, &cfgFiles); + if(result == GLOB_NOSPACE || result == GLOB_ABORTED) { +#if 0 + char errStr[1024]; + rs_strerror_r(errno, errStr, sizeof(errStr)); + errmsg.LogError(0, RS_RET_FILE_NOT_FOUND, "error accessing config file or directory '%s': %s", + pattern, errStr); + ABORT_FINALIZE(RS_RET_FILE_NOT_FOUND); +#endif + dbgprintf("includeconfig glob error %d\n", errno); + return 1; + } + + for(i = 0; i < cfgFiles.gl_pathc; i++) { + cfgFile = cfgFiles.gl_pathv[i]; + + if(stat(cfgFile, &fileInfo) != 0) + continue; /* continue with the next file if we can't stat() the file */ + + if(S_ISREG(fileInfo.st_mode)) { /* config file */ + dbgprintf("requested to include config file '%s'\n", cfgFile); + cnfSetLexFile(cfgFile); + } else if(S_ISDIR(fileInfo.st_mode)) { /* config directory */ + if(strcmp(name, cfgFile)) { + /* do not include ourselves! */ + dbgprintf("requested to include directory '%s'\n", cfgFile); + cnfDoInclude(cfgFile); + } + } else { + dbgprintf("warning: unable to process IncludeConfig directive '%s'\n", cfgFile); + } + } + + globfree(&cfgFiles); + return 0; +} + void cstrPrint(char *text, es_str_t *estr) { -- cgit v1.2.3 From 384cf4702406a69825190ce0e28cfbcd1e3ccb8e Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 15 Jul 2011 14:51:53 +0200 Subject: renamed exprret type to var in spite of more generic use --- grammar/rainerscript.c | 92 +++++++++++++++++++++++++------------------------- 1 file changed, 46 insertions(+), 46 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 680f8775..5d64abb4 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -294,7 +294,7 @@ done: * are used (bSuccess tells if the conversion went well or not). */ static inline long long -exprret2Number(struct exprret *r, int *bSuccess) +var2Number(struct var *r, int *bSuccess) { long long n; if(r->datatype == 'S') { @@ -309,7 +309,7 @@ exprret2Number(struct exprret *r, int *bSuccess) * emit error message and set number to 0. */ static inline es_str_t * -exprret2String(struct exprret *r, int *bMustFree) +var2String(struct var *r, int *bMustFree) { if(r->datatype == 'N') { *bMustFree = 1; @@ -323,14 +323,14 @@ exprret2String(struct exprret *r, int *bMustFree) * to keep the code small and easier to maintain. */ static inline void -doFuncCall(struct cnffunc *func, struct exprret *ret, void* usrptr) +doFuncCall(struct cnffunc *func, struct var *ret, void* usrptr) { char *fname; char *envvar; int bMustFree; es_str_t *estr; char *str; - struct exprret r[CNFFUNC_MAX_ARGS]; + struct var r[CNFFUNC_MAX_ARGS]; dbgprintf("rainerscript: executing function id %d\n", func->fID); switch(func->fID) { @@ -342,7 +342,7 @@ doFuncCall(struct cnffunc *func, struct exprret *ret, void* usrptr) ret->d.n = es_strlen(((struct cnfstringval*) func->expr[0])->estr); } else { cnfexprEval(func->expr[0], &r[0], usrptr); - estr = exprret2String(&r[0], &bMustFree); + estr = var2String(&r[0], &bMustFree); ret->d.n = es_strlen(estr); if(bMustFree) es_deleteStr(estr); } @@ -355,7 +355,7 @@ doFuncCall(struct cnffunc *func, struct exprret *ret, void* usrptr) * string following. */ cnfexprEval(func->expr[0], &r[0], usrptr); - estr = exprret2String(&r[0], &bMustFree); + estr = var2String(&r[0], &bMustFree); str = (char*) es_str2cstr(estr, NULL); envvar = getenv(str); ret->datatype = 'S'; @@ -366,7 +366,7 @@ doFuncCall(struct cnffunc *func, struct exprret *ret, void* usrptr) break; case CNFFUNC_TOLOWER: cnfexprEval(func->expr[0], &r[0], usrptr); - estr = exprret2String(&r[0], &bMustFree); + estr = var2String(&r[0], &bMustFree); if(!bMustFree) /* let caller handle that M) */ estr = es_strdup(estr); es_tolower(estr); @@ -375,7 +375,7 @@ doFuncCall(struct cnffunc *func, struct exprret *ret, void* usrptr) break; case CNFFUNC_CSTR: cnfexprEval(func->expr[0], &r[0], usrptr); - estr = exprret2String(&r[0], &bMustFree); + estr = var2String(&r[0], &bMustFree); if(!bMustFree) /* let caller handle that M) */ estr = es_strdup(estr); ret->datatype = 'S'; @@ -389,7 +389,7 @@ doFuncCall(struct cnffunc *func, struct exprret *ret, void* usrptr) NULL); } else { cnfexprEval(func->expr[0], &r[0], usrptr); - ret->d.n = exprret2Number(&r[0], NULL); + ret->d.n = var2Number(&r[0], NULL); if(r[0].datatype == 'S') es_deleteStr(r[0].d.estr); } ret->datatype = 'N'; @@ -414,14 +414,14 @@ doFuncCall(struct cnffunc *func, struct exprret *ret, void* usrptr) cnfexprEval(expr->l, &l, usrptr); \ cnfexprEval(expr->r, &r, usrptr); \ ret->datatype = 'N'; \ - ret->d.n = exprret2Number(&l, &convok_l) x exprret2Number(&r, &convok_r); \ + ret->d.n = var2Number(&l, &convok_l) x var2Number(&r, &convok_r); \ FREE_BOTH_RET #define PREP_TWO_STRINGS \ cnfexprEval(expr->l, &l, usrptr); \ - estr_l = exprret2String(&l, &bMustFree2); \ + estr_l = var2String(&l, &bMustFree2); \ cnfexprEval(expr->r, &r, usrptr); \ - estr_r = exprret2String(&r, &bMustFree) + estr_r = var2String(&r, &bMustFree) #define FREE_TWO_STRINGS \ if(bMustFree) es_deleteStr(estr_r); \ @@ -439,9 +439,9 @@ doFuncCall(struct cnffunc *func, struct exprret *ret, void* usrptr) * simply is no case where full evaluation would make any sense at all. */ void -cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) +cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) { - struct exprret r, l; /* memory for subexpression results */ + struct var r, l; /* memory for subexpression results */ es_str_t *estr_r, *estr_l; int convok_r, convok_l; int bMustFree, bMustFree2; @@ -460,22 +460,22 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) if(r.datatype == 'S') { ret->d.n = !es_strcmp(l.d.estr, r.d.estr); /*CMP*/ } else { - n_l = exprret2Number(&l, &convok_l); + n_l = var2Number(&l, &convok_l); if(convok_l) { ret->d.n = (n_l == r.d.n); /*CMP*/ } else { - estr_r = exprret2String(&r, &bMustFree); + estr_r = var2String(&r, &bMustFree); ret->d.n = !es_strcmp(l.d.estr, estr_r); /*CMP*/ if(bMustFree) es_deleteStr(estr_r); } } } else { if(r.datatype == 'S') { - n_r = exprret2Number(&r, &convok_r); + n_r = var2Number(&r, &convok_r); if(convok_r) { ret->d.n = (l.d.n == n_r); /*CMP*/ } else { - estr_l = exprret2String(&l, &bMustFree); + estr_l = var2String(&l, &bMustFree); ret->d.n = !es_strcmp(r.d.estr, estr_l); /*CMP*/ if(bMustFree) es_deleteStr(estr_l); } @@ -493,22 +493,22 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) if(r.datatype == 'S') { ret->d.n = es_strcmp(l.d.estr, r.d.estr); /*CMP*/ } else { - n_l = exprret2Number(&l, &convok_l); + n_l = var2Number(&l, &convok_l); if(convok_l) { ret->d.n = (n_l != r.d.n); /*CMP*/ } else { - estr_r = exprret2String(&r, &bMustFree); + estr_r = var2String(&r, &bMustFree); ret->d.n = es_strcmp(l.d.estr, estr_r); /*CMP*/ if(bMustFree) es_deleteStr(estr_r); } } } else { if(r.datatype == 'S') { - n_r = exprret2Number(&r, &convok_r); + n_r = var2Number(&r, &convok_r); if(convok_r) { ret->d.n = (l.d.n != n_r); /*CMP*/ } else { - estr_l = exprret2String(&l, &bMustFree); + estr_l = var2String(&l, &bMustFree); ret->d.n = es_strcmp(r.d.estr, estr_l); /*CMP*/ if(bMustFree) es_deleteStr(estr_l); } @@ -526,22 +526,22 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) if(r.datatype == 'S') { ret->d.n = es_strcmp(l.d.estr, r.d.estr) <= 0; /*CMP*/ } else { - n_l = exprret2Number(&l, &convok_l); + n_l = var2Number(&l, &convok_l); if(convok_l) { ret->d.n = (n_l <= r.d.n); /*CMP*/ } else { - estr_r = exprret2String(&r, &bMustFree); + estr_r = var2String(&r, &bMustFree); ret->d.n = es_strcmp(l.d.estr, estr_r) <= 0; /*CMP*/ if(bMustFree) es_deleteStr(estr_r); } } } else { if(r.datatype == 'S') { - n_r = exprret2Number(&r, &convok_r); + n_r = var2Number(&r, &convok_r); if(convok_r) { ret->d.n = (l.d.n <= n_r); /*CMP*/ } else { - estr_l = exprret2String(&l, &bMustFree); + estr_l = var2String(&l, &bMustFree); ret->d.n = es_strcmp(r.d.estr, estr_l) <= 0; /*CMP*/ if(bMustFree) es_deleteStr(estr_l); } @@ -559,22 +559,22 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) if(r.datatype == 'S') { ret->d.n = es_strcmp(l.d.estr, r.d.estr) >= 0; /*CMP*/ } else { - n_l = exprret2Number(&l, &convok_l); + n_l = var2Number(&l, &convok_l); if(convok_l) { ret->d.n = (n_l >= r.d.n); /*CMP*/ } else { - estr_r = exprret2String(&r, &bMustFree); + estr_r = var2String(&r, &bMustFree); ret->d.n = es_strcmp(l.d.estr, estr_r) >= 0; /*CMP*/ if(bMustFree) es_deleteStr(estr_r); } } } else { if(r.datatype == 'S') { - n_r = exprret2Number(&r, &convok_r); + n_r = var2Number(&r, &convok_r); if(convok_r) { ret->d.n = (l.d.n >= n_r); /*CMP*/ } else { - estr_l = exprret2String(&l, &bMustFree); + estr_l = var2String(&l, &bMustFree); ret->d.n = es_strcmp(r.d.estr, estr_l) >= 0; /*CMP*/ if(bMustFree) es_deleteStr(estr_l); } @@ -592,22 +592,22 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) if(r.datatype == 'S') { ret->d.n = es_strcmp(l.d.estr, r.d.estr) < 0; /*CMP*/ } else { - n_l = exprret2Number(&l, &convok_l); + n_l = var2Number(&l, &convok_l); if(convok_l) { ret->d.n = (n_l < r.d.n); /*CMP*/ } else { - estr_r = exprret2String(&r, &bMustFree); + estr_r = var2String(&r, &bMustFree); ret->d.n = es_strcmp(l.d.estr, estr_r) < 0; /*CMP*/ if(bMustFree) es_deleteStr(estr_r); } } } else { if(r.datatype == 'S') { - n_r = exprret2Number(&r, &convok_r); + n_r = var2Number(&r, &convok_r); if(convok_r) { ret->d.n = (l.d.n < n_r); /*CMP*/ } else { - estr_l = exprret2String(&l, &bMustFree); + estr_l = var2String(&l, &bMustFree); ret->d.n = es_strcmp(r.d.estr, estr_l) < 0; /*CMP*/ if(bMustFree) es_deleteStr(estr_l); } @@ -625,22 +625,22 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) if(r.datatype == 'S') { ret->d.n = es_strcmp(l.d.estr, r.d.estr) > 0; /*CMP*/ } else { - n_l = exprret2Number(&l, &convok_l); + n_l = var2Number(&l, &convok_l); if(convok_l) { ret->d.n = (n_l > r.d.n); /*CMP*/ } else { - estr_r = exprret2String(&r, &bMustFree); + estr_r = var2String(&r, &bMustFree); ret->d.n = es_strcmp(l.d.estr, estr_r) > 0; /*CMP*/ if(bMustFree) es_deleteStr(estr_r); } } } else { if(r.datatype == 'S') { - n_r = exprret2Number(&r, &convok_r); + n_r = var2Number(&r, &convok_r); if(convok_r) { ret->d.n = (l.d.n > n_r); /*CMP*/ } else { - estr_l = exprret2String(&l, &bMustFree); + estr_l = var2String(&l, &bMustFree); ret->d.n = es_strcmp(r.d.estr, estr_l) > 0; /*CMP*/ if(bMustFree) es_deleteStr(estr_l); } @@ -677,11 +677,11 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) case OR: cnfexprEval(expr->l, &l, usrptr); ret->datatype = 'N'; - if(exprret2Number(&l, &convok_l)) { + if(var2Number(&l, &convok_l)) { ret->d.n = 1ll; } else { cnfexprEval(expr->r, &r, usrptr); - if(exprret2Number(&r, &convok_r)) + if(var2Number(&r, &convok_r)) ret->d.n = 1ll; else ret->d.n = 0ll; @@ -691,9 +691,9 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) case AND: cnfexprEval(expr->l, &l, usrptr); ret->datatype = 'N'; - if(exprret2Number(&l, &convok_l)) { + if(var2Number(&l, &convok_l)) { cnfexprEval(expr->r, &r, usrptr); - if(exprret2Number(&r, &convok_r)) + if(var2Number(&r, &convok_r)) ret->d.n = 1ll; else ret->d.n = 0ll; @@ -705,7 +705,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) case NOT: cnfexprEval(expr->r, &r, usrptr); ret->datatype = 'N'; - ret->d.n = !exprret2Number(&r, &convok_r); + ret->d.n = !var2Number(&r, &convok_r); if(r.datatype == 'S') es_deleteStr(r.d.estr); break; case 'N': @@ -738,7 +738,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) case 'M': cnfexprEval(expr->r, &r, usrptr); ret->datatype = 'N'; - ret->d.n = -exprret2Number(&r, &convok_r); + ret->d.n = -var2Number(&r, &convok_r); if(r.datatype == 'S') es_deleteStr(r.d.estr); break; case 'F': @@ -761,9 +761,9 @@ int cnfexprEvalBool(struct cnfexpr *expr, void *usrptr) { int convok; - struct exprret ret; + struct var ret; cnfexprEval(expr, &ret, usrptr); - return exprret2Number(&ret, &convok); + return var2Number(&ret, &convok); } inline static void -- cgit v1.2.3 From 84ca2c443680de2c7e98f27972fb6300a025d62d Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 15 Jul 2011 15:32:11 +0200 Subject: better check for config errors --- grammar/rainerscript.c | 44 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 5d64abb4..16140a3f 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -95,7 +95,8 @@ nvlstNew(es_str_t *name, es_str_t *value) if((lst = malloc(sizeof(struct nvlst))) != NULL) { lst->next = NULL; lst->name = name; - lst->value = value; + lst->val.datatype = 'S'; + lst->val.d.estr = value; } return lst; @@ -110,7 +111,8 @@ nvlstDestruct(struct nvlst *lst) toDel = lst; lst = lst->next; es_deleteStr(toDel->name); - es_deleteStr(toDel->value); + if(toDel->val.datatype == 'S') + es_deleteStr(toDel->val.d.estr); free(toDel); } } @@ -122,7 +124,8 @@ nvlstPrint(struct nvlst *lst) dbgprintf("nvlst %p:\n", lst); while(lst != NULL) { name = es_str2cstr(lst->name, NULL); - value = es_str2cstr(lst->value, NULL); + // TODO: support for non-string types + value = es_str2cstr(lst->val.d.estr, NULL); dbgprintf("\tname: '%s', value '%s'\n", name, value); free(name); free(value); @@ -130,12 +133,47 @@ nvlstPrint(struct nvlst *lst) } } +/* find a name starting at node lst. Returns node with this + * name or NULL, if none found. + */ +struct nvlst* +nvlstFindName(struct nvlst *lst, es_str_t *name) +{ + while(lst != NULL && es_strcmp(lst->name, name)) + lst = lst->next; + return lst; +} + + +/* check if there are duplicate names inside a nvlst and emit + * an error message, if so. + */ +static inline void +nvlstChkDupes(struct nvlst *lst) +{ + char *cstr; + + while(lst != NULL) { + if(nvlstFindName(lst->next, lst->name) != NULL) { + cstr = es_str2cstr(lst->name, NULL); + parser_errmsg("duplicate parameter '%s' -- " + "interpretation is ambigious, one value " + "will be randomly selected. Fix this problem.", + cstr); + free(cstr); + } + lst = lst->next; + } +} + + struct cnfobj* cnfobjNew(enum cnfobjType objType, struct nvlst *lst) { struct cnfobj *o; if((o = malloc(sizeof(struct nvlst))) != NULL) { + nvlstChkDupes(lst); o->objType = objType; o->nvlst = lst; } -- cgit v1.2.3 From 127d61fea78c967d2cdc536f898da425ffdd8a11 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 19 Jul 2011 09:31:17 +0200 Subject: milestone: first steps at global() conf obj implementation also, the foundation for accessing conf file params has been laid. Still more work to do... --- grammar/rainerscript.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 16140a3f..754910da 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -97,6 +97,7 @@ nvlstNew(es_str_t *name, es_str_t *value) lst->name = name; lst->val.datatype = 'S'; lst->val.d.estr = value; + lst->bUsed = 0; } return lst; @@ -145,6 +146,18 @@ nvlstFindName(struct nvlst *lst, es_str_t *name) } +/* find a name starting at node lst. SAme as nvlstFindName, but + * for classical C strings. This is useful because the config system + * uses C string constants. + */ +static inline struct nvlst* +nvlstFindNameCStr(struct nvlst *lst, char *name) +{ + while(lst != NULL && es_strbufcmp(lst->name, (uchar*)name, strlen(name))) + lst = lst->next; + return lst; +} + /* check if there are duplicate names inside a nvlst and emit * an error message, if so. */ @@ -167,6 +180,113 @@ nvlstChkDupes(struct nvlst *lst) } +/* check for unused params and emit error message is found. This must + * be called after all config params have been pulled from the object + * (otherwise the flags are not correctly set). + */ +void +nvlstChkUnused(struct nvlst *lst) +{ + char *cstr; + + while(lst != NULL) { + if(!lst->bUsed) { + cstr = es_str2cstr(lst->name, NULL); + parser_errmsg("parameter '%s' not known -- " + "typo in config file?", + cstr); + free(cstr); + } + lst = lst->next; + } +} + + +/* get a single parameter according to its definition. Helper to + * nvlstGetParams. + */ +static inline void +nvlstGetParam(struct nvlst *valnode, struct cnfparamdescr *param, + struct cnfparamvals *vals) +{ + dbgprintf("XXXX: in nvlstGetParam, name '%s', type %d\n", + param->name, (int) param->type); + switch(param->type) { + case eCmdHdlrUID: + break; + case eCmdHdlrGID: + break; + case eCmdHdlrBinary: + break; + case eCmdHdlrFileCreateMode: + break; + case eCmdHdlrInt: + break; + case eCmdHdlrSize: + break; + case eCmdHdlrGetChar: + break; + case eCmdHdlrFacility: + break; + case eCmdHdlrSeverity: + break; + case eCmdHdlrGetWord: + break; + case eCmdHdlrString: + break; + case eCmdHdlrGoneAway: + parser_errmsg("parameter '%s' is no longer supported", + param->name); + break; + default: + dbgprintf("error: invalid param type\n"); + break; + } +} + + +/* obtain conf params from an nvlst and emit error messages if + * necessary. If an already-existing param value is passed, that is + * used. If NULL is passed instead, a new one is allocated. In that case, + * it is the caller's duty to free it when no longer needed. + * NULL is returned on error, otherwise a pointer to the vals array. + */ +struct cnfparamvals* +nvlstGetParams(struct nvlst *lst, struct cnfparamblk *params, + struct cnfparamvals *vals) +{ + int i; + struct nvlst *valnode; + struct cnfparamdescr *param; + + if(params->version != CNFPARAMBLK_VERSION) { + dbgprintf("nvlstGetParams: invalid param block version " + "%d, expected %d\n", + params->version, CNFPARAMBLK_VERSION); + return NULL; + } + + if(vals == NULL) { + if((vals = malloc(params->nParams * + sizeof(struct cnfparamvals))) == NULL) + return NULL; + } + + for(i = 0 ; i < params->nParams ; ++i) { + param = params->descr + i; + if((valnode = nvlstFindNameCStr(lst, param->name)) == NULL) + continue; + if(vals[i].bUsed) { + parser_errmsg("parameter '%s' specified more than once - " + "one instance is ignored. Fix config", param->name); + continue; + } + nvlstGetParam(lst, param, vals + i); + } + return vals; +} + + struct cnfobj* cnfobjNew(enum cnfobjType objType, struct nvlst *lst) { @@ -1140,6 +1260,25 @@ cnfDoInclude(char *name) return 0; } +/* find the index (or -1!) for a config param by name. This is used to + * address the parameter array. Of course, we could use with static + * indices, but that would create some extra bug potential. So we + * resort to names. As we do this only during the initial config parsing + * stage the (considerable!) extra overhead is OK. -- rgerhards, 2011-07-19 + */ +int +cnfparamGetIdx(struct cnfparamblk *params, char *name) +{ + int i; + for(i = 0 ; i < params->nParams ; ++i) + if(!strcmp(params->descr[i].name, name)) + break; + if(i == params->nParams) + i = -1; /* not found */ + return i; +} + + void cstrPrint(char *text, es_str_t *estr) { -- cgit v1.2.3 From 47c961eac280f72a472ad82764f8fd450ba3643f Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 19 Jul 2011 11:23:57 +0200 Subject: milestone: two syntaxes for get conf param implemented --- grammar/rainerscript.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 75 insertions(+), 4 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 754910da..502deece 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -202,21 +202,59 @@ nvlstChkUnused(struct nvlst *lst) } +static inline void +doGetBinary(struct nvlst *valnode, struct cnfparamdescr *param, + struct cnfparamvals *val) +{ + val->val.datatype = 'N'; + if(!es_strbufcmp(valnode->val.d.estr, (unsigned char*) "on", 2)) { + val->val.d.n = 1; + } else if(!es_strbufcmp(valnode->val.d.estr, (unsigned char*) "off", 3)) { + val->val.d.n = 0; + } else { + parser_errmsg("parameter '%s' must be \"on\" or \"off\" but " + "is neither. Results unpredictable.", param->name); + val->val.d.n = 0; + } +} + + +static inline void +doGetWord(struct nvlst *valnode, struct cnfparamdescr *param, + struct cnfparamvals *val) +{ + es_size_t i; + unsigned char *c; + val->val.datatype = 'S'; + val->val.d.estr = es_newStr(32); + c = es_getBufAddr(valnode->val.d.estr); + for(i = 0 ; i < es_strlen(valnode->val.d.estr) && !isspace(c[i]) ; ++i) { + es_addChar(&val->val.d.estr, c[i]); + } + if(i != es_strlen(valnode->val.d.estr)) { + parser_errmsg("parameter '%s' contains whitespace, which is not " + "permitted - data after first whitespace ignored", + param->name); + } +} + /* get a single parameter according to its definition. Helper to * nvlstGetParams. */ static inline void nvlstGetParam(struct nvlst *valnode, struct cnfparamdescr *param, - struct cnfparamvals *vals) + struct cnfparamvals *val) { dbgprintf("XXXX: in nvlstGetParam, name '%s', type %d\n", param->name, (int) param->type); + val->bUsed = 1; switch(param->type) { case eCmdHdlrUID: break; case eCmdHdlrGID: break; case eCmdHdlrBinary: + doGetBinary(valnode, param, val); break; case eCmdHdlrFileCreateMode: break; @@ -231,8 +269,11 @@ nvlstGetParam(struct nvlst *valnode, struct cnfparamdescr *param, case eCmdHdlrSeverity: break; case eCmdHdlrGetWord: + doGetWord(valnode, param, val); break; case eCmdHdlrString: + val->val.datatype = 'S'; + val->val.d.estr = es_strdup(valnode->val.d.estr); break; case eCmdHdlrGoneAway: parser_errmsg("parameter '%s' is no longer supported", @@ -267,9 +308,9 @@ nvlstGetParams(struct nvlst *lst, struct cnfparamblk *params, } if(vals == NULL) { - if((vals = malloc(params->nParams * + if((vals = calloc(params->nParams, sizeof(struct cnfparamvals))) == NULL) - return NULL; + return NULL; } for(i = 0 ; i < params->nParams ; ++i) { @@ -281,12 +322,42 @@ nvlstGetParams(struct nvlst *lst, struct cnfparamblk *params, "one instance is ignored. Fix config", param->name); continue; } - nvlstGetParam(lst, param, vals + i); + nvlstGetParam(valnode, param, vals + i); } return vals; } +void +cnfparamsPrint(struct cnfparamblk *params, struct cnfparamvals *vals) +{ + int i; + char *cstr; + + for(i = 0 ; i < params->nParams ; ++i) { + dbgprintf("%s: ", params->descr[i].name); + if(vals[i].bUsed) { + // TODO: other types! + switch(vals[i].val.datatype) { + case 'S': + cstr = es_str2cstr(vals[i].val.d.estr, NULL); + dbgprintf(" '%s'", cstr); + free(cstr); + break; + case 'N': + dbgprintf("%lld", vals[i].val.d.n); + break; + default: + dbgprintf("(unsupported datatype %c)", + vals[i].val.datatype); + } + } else { + dbgprintf("(unset)"); + } + dbgprintf("\n"); + } +} + struct cnfobj* cnfobjNew(enum cnfobjType objType, struct nvlst *lst) { -- cgit v1.2.3 From 74c2e98c13daf60bf5371f77111196679dd7df55 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 19 Jul 2011 17:53:23 +0200 Subject: milestone: glbl obj parameters settable via new conf interface --- grammar/rainerscript.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 502deece..92b07a5f 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -158,6 +158,7 @@ nvlstFindNameCStr(struct nvlst *lst, char *name) return lst; } + /* check if there are duplicate names inside a nvlst and emit * an error message, if so. */ @@ -247,6 +248,7 @@ nvlstGetParam(struct nvlst *valnode, struct cnfparamdescr *param, { dbgprintf("XXXX: in nvlstGetParam, name '%s', type %d\n", param->name, (int) param->type); + valnode->bUsed = 1; val->bUsed = 1; switch(param->type) { case eCmdHdlrUID: -- cgit v1.2.3 From 02d44ba72d450199838dfa25eafcdf8c759ee5d4 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 19 Jul 2011 18:26:26 +0200 Subject: milestone: size syntax implemented --- grammar/rainerscript.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 92b07a5f..76e3a0a4 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -203,6 +203,53 @@ nvlstChkUnused(struct nvlst *lst) } +static inline void +doGetSize(struct nvlst *valnode, struct cnfparamdescr *param, + struct cnfparamvals *val) +{ + unsigned char *c; + es_size_t i; + long long n; + c = es_getBufAddr(valnode->val.d.estr); + n = 0; + i = 0; + while(i < es_strlen(valnode->val.d.estr) && isdigit(*c)) { + n = 10 * n + *c - '0'; + ++i; + ++c; + } + if(i < es_strlen(valnode->val.d.estr)) { + ++i; + switch(*c) { + /* traditional binary-based definitions */ + case 'k': n *= 1024; break; + case 'm': n *= 1024 * 1024; break; + case 'g': n *= 1024 * 1024 * 1024; break; + case 't': n *= (int64) 1024 * 1024 * 1024 * 1024; break; /* tera */ + case 'p': n *= (int64) 1024 * 1024 * 1024 * 1024 * 1024; break; /* peta */ + case 'e': n *= (int64) 1024 * 1024 * 1024 * 1024 * 1024 * 1024; break; /* exa */ + /* and now the "new" 1000-based definitions */ + case 'K': n *= 1000; break; + case 'M': n *= 1000000; break; + case 'G': n *= 1000000000; break; + /* we need to use the multiplication below because otherwise + * the compiler gets an error during constant parsing */ + case 'T': n *= (int64) 1000 * 1000000000; break; /* tera */ + case 'P': n *= (int64) 1000000 * 1000000000; break; /* peta */ + case 'E': n *= (int64) 1000000000 * 1000000000; break; /* exa */ + default: --i; break; /* indicates error */ + } + } + if(i == es_strlen(valnode->val.d.estr)) { + val->val.datatype = 'N'; + val->val.d.n = n; + } else { + parser_errmsg("parameter '%s' does not contain a valid size", + param->name); + } +} + + static inline void doGetBinary(struct nvlst *valnode, struct cnfparamdescr *param, struct cnfparamvals *val) @@ -263,6 +310,7 @@ nvlstGetParam(struct nvlst *valnode, struct cnfparamdescr *param, case eCmdHdlrInt: break; case eCmdHdlrSize: + doGetSize(valnode, param, val); break; case eCmdHdlrGetChar: break; -- cgit v1.2.3 From 5820c5f3e8dc69bdee969d6487d084e884595069 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 20 Jul 2011 17:37:44 +0200 Subject: milestone: done plumbing to call plugin create action instance entry point --- grammar/rainerscript.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 76e3a0a4..c953c840 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -146,14 +146,15 @@ nvlstFindName(struct nvlst *lst, es_str_t *name) } -/* find a name starting at node lst. SAme as nvlstFindName, but +/* find a name starting at node lst. Same as nvlstFindName, but * for classical C strings. This is useful because the config system * uses C string constants. */ static inline struct nvlst* nvlstFindNameCStr(struct nvlst *lst, char *name) { - while(lst != NULL && es_strbufcmp(lst->name, (uchar*)name, strlen(name))) + es_size_t lenName = strlen(name); + while(lst != NULL && es_strcasebufcmp(lst->name, (uchar*)name, lenName)) lst = lst->next; return lst; } -- cgit v1.2.3 From 63446424c057f527c9c17be7e06f306a130789b4 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 21 Jul 2011 13:55:45 +0200 Subject: fixing minor memory leaks --- grammar/rainerscript.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index c953c840..0b2ee7cb 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -475,6 +475,7 @@ cnfactlstAddSysline(struct cnfactlst* actlst, char *line) return actlst; } + void cnfactlstDestruct(struct cnfactlst *actlst) { @@ -483,6 +484,7 @@ cnfactlstDestruct(struct cnfactlst *actlst) while(actlst != NULL) { toDel = actlst; actlst = actlst->next; + cnfcfsyslinelstDestruct(toDel->syslines); if(toDel->actType == CNFACT_V2) nvlstDestruct(toDel->data.lst); else @@ -1245,6 +1247,28 @@ cnfrulePrint(struct cnfrule *rule) dbgprintf("------ end rule %p\n", rule); } +void +cnfcfsyslinelstDestruct(struct cnfcfsyslinelst *cfslst) +{ + struct cnfcfsyslinelst *toDel; + while(cfslst != NULL) { + toDel = cfslst; + cfslst = cfslst->next; + free(toDel->line); + free(toDel); + } +} + +void +cnfruleDestruct(struct cnfrule *rule) +{ + if( rule->filttype == CNFFILT_PRI + || rule->filttype == CNFFILT_PROP) + free(rule->filt.s); + cnfactlstDestruct(rule->actlst); + free(rule); +} + struct cnffparamlst * cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next) { @@ -1382,6 +1406,23 @@ cnfDoInclude(char *name) return 0; } +void +varDelete(struct var *v) +{ + if(v->datatype == 'S') + es_deleteStr(v->d.estr); +} + +void +cnfparamvalsDestruct(struct cnfparamvals *paramvals, struct cnfparamblk *blk) +{ + int i; + for(i = 0 ; i < blk->nParams ; ++i) { + varDelete(¶mvals[i].val); + } + free(paramvals); +} + /* find the index (or -1!) for a config param by name. This is used to * address the parameter array. Of course, we could use with static * indices, but that would create some extra bug potential. So we -- cgit v1.2.3 From 052f8e2ef64ca039219ac83a9d9372f3eb3a5aed Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 21 Jul 2011 17:45:39 +0200 Subject: bugfix: abort in omfile (in brand-new code) --- grammar/rainerscript.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 0b2ee7cb..43c5a677 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -449,6 +449,8 @@ cnfactlstNew(enum cnfactType actType, struct nvlst *lst, char *actLine) actlst->next = NULL; actlst->syslines = NULL; actlst->actType = actType; + actlst->lineno = yylineno; + actlst->cnfFile = strdup(cnfcurrfn); if(actType == CNFACT_V2) actlst->data.lst = lst; else @@ -484,6 +486,7 @@ cnfactlstDestruct(struct cnfactlst *actlst) while(actlst != NULL) { toDel = actlst; actlst = actlst->next; + free(toDel->cnfFile); cnfcfsyslinelstDestruct(toDel->syslines); if(toDel->actType == CNFACT_V2) nvlstDestruct(toDel->data.lst); -- cgit v1.2.3 From ca377701e0200a0766abe3bb33f4cab3ccaad451 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 22 Jul 2011 11:32:26 +0200 Subject: milestone: all syntaxes for new config handler implemented so far, mostly compile-time tested. Real testing happens as side-activity when implementing other parts of the new config system --- grammar/rainerscript.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 43c5a677..fe99e4aa 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -30,11 +30,15 @@ #include #include #include +#include +#include #include +#include #include #include "rainerscript.h" #include "parserif.h" #include "grammar.h" +#include "srUtils.h" void readConfFile(FILE *fp, es_str_t **str) @@ -267,6 +271,104 @@ doGetBinary(struct nvlst *valnode, struct cnfparamdescr *param, } } +/* A file create-mode must be a four-digit octal number + * starting with '0'. + */ +static inline void +doGetFileCreateMode(struct nvlst *valnode, struct cnfparamdescr *param, + struct cnfparamvals *val) +{ + int fmtOK = 0; + char *cstr; + uchar *c; + + if(es_strlen(valnode->val.d.estr) == 4) { + c = es_getBufAddr(valnode->val.d.estr); + if(!( (c[0] == '0') + && (c[1] >= '0' && c[1] <= '7') + && (c[2] >= '0' && c[2] <= '7') + && (c[3] >= '0' && c[3] <= '7') ) ) { + fmtOK = 1; + } + } + + if(fmtOK) { + val->val.datatype = 'N'; + val->val.d.n = (c[1]-'0') * 64 + (c[2]-'0') * 8 + (c[3]-'0');; + } else { + cstr = es_str2cstr(valnode->val.d.estr, NULL); + parser_errmsg("file modes need to be specified as " + "4-digit octal numbers starting with '0' -" + "parameter '%s=\"%s\"' is not a file mode", + param->name, cstr); + free(cstr); + } +} + +static inline void +doGetGID(struct nvlst *valnode, struct cnfparamdescr *param, + struct cnfparamvals *val) +{ + char *cstr; + struct group *resultBuf; + struct group wrkBuf; + char stringBuf[2048]; /* 2048 has been proven to be large enough */ + + cstr = es_str2cstr(valnode->val.d.estr, NULL); + getgrnam_r(cstr, &wrkBuf, stringBuf, sizeof(stringBuf), &resultBuf); + if(resultBuf == NULL) { + parser_errmsg("parameter '%s': ID for group %s could not " + "be found", param->name, cstr); + } else { + val->val.datatype = 'N'; + val->val.d.n = resultBuf->gr_gid; + dbgprintf("param '%s': uid %d obtained for group '%s'\n", + param->name, (int) resultBuf->gr_gid, cstr); + } + free(cstr); +} + +static inline void +doGetUID(struct nvlst *valnode, struct cnfparamdescr *param, + struct cnfparamvals *val) +{ + char *cstr; + struct passwd *resultBuf; + struct passwd wrkBuf; + char stringBuf[2048]; /* 2048 has been proven to be large enough */ + + cstr = es_str2cstr(valnode->val.d.estr, NULL); + getpwnam_r(cstr, &wrkBuf, stringBuf, sizeof(stringBuf), &resultBuf); + if(resultBuf == NULL) { + parser_errmsg("parameter '%s': ID for user %s could not " + "be found", param->name, cstr); + } else { + val->val.datatype = 'N'; + val->val.d.n = resultBuf->pw_uid; + dbgprintf("param '%s': uid %d obtained for user '%s'\n", + param->name, (int) resultBuf->pw_uid, cstr); + } + free(cstr); +} + +/* note: we support all integer formats that es_str2num support, + * so hex and octal representations are also valid. + */ +static inline void +doGetInt(struct nvlst *valnode, struct cnfparamdescr *param, + struct cnfparamvals *val) +{ + long long n; + int bSuccess; + + n = es_str2num(valnode->val.d.estr, &bSuccess); + if(!bSuccess) { + parser_errmsg("parameter '%s' is not a proper number", + param->name); + } + val->val.datatype = 'N'; + val->val.d.n = n; +} static inline void doGetWord(struct nvlst *valnode, struct cnfparamdescr *param, @@ -287,6 +389,19 @@ doGetWord(struct nvlst *valnode, struct cnfparamdescr *param, } } +static inline void +doGetChar(struct nvlst *valnode, struct cnfparamdescr *param, + struct cnfparamvals *val) +{ + if(es_strlen(valnode->val.d.estr) != 1) { + parser_errmsg("parameter '%s' must contain exactly one character " + "but contains %d - cannot be processed", + param->name, es_strlen(valnode->val.d.estr)); + } + val->val.datatype = 'S'; + val->val.d.estr = es_strdup(valnode->val.d.estr); +} + /* get a single parameter according to its definition. Helper to * nvlstGetParams. */ @@ -294,30 +409,45 @@ static inline void nvlstGetParam(struct nvlst *valnode, struct cnfparamdescr *param, struct cnfparamvals *val) { + uchar *cstr; + dbgprintf("XXXX: in nvlstGetParam, name '%s', type %d\n", param->name, (int) param->type); valnode->bUsed = 1; val->bUsed = 1; switch(param->type) { case eCmdHdlrUID: + doGetUID(valnode, param, val); break; case eCmdHdlrGID: + doGetGID(valnode, param, val); break; case eCmdHdlrBinary: doGetBinary(valnode, param, val); break; case eCmdHdlrFileCreateMode: + doGetFileCreateMode(valnode, param, val); break; case eCmdHdlrInt: + doGetInt(valnode, param, val); break; case eCmdHdlrSize: doGetSize(valnode, param, val); break; case eCmdHdlrGetChar: + doGetChar(valnode, param, val); break; case eCmdHdlrFacility: + cstr = (uchar*) es_str2cstr(valnode->val.d.estr, NULL); + val->val.datatype = 'N'; + val->val.d.n = decodeSyslogName(cstr, syslogFacNames); + free(cstr); break; case eCmdHdlrSeverity: + cstr = (uchar*) es_str2cstr(valnode->val.d.estr, NULL); + val->val.datatype = 'N'; + val->val.d.n = decodeSyslogName(cstr, syslogPriNames); + free(cstr); break; case eCmdHdlrGetWord: doGetWord(valnode, param, val); -- cgit v1.2.3 From 9757aeb56445eee3aca2b43e6b3efa1f1cb59ba3 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 22 Jul 2011 18:03:43 +0200 Subject: milestone: queue object now has a param handler for new conf interface ... and action queue defs use this new interface (but not yet the main queues) --- grammar/rainerscript.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index fe99e4aa..1b44974c 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -35,9 +35,11 @@ #include #include #include +#include "rsyslog.h" #include "rainerscript.h" #include "parserif.h" #include "grammar.h" +#include "queue.h" #include "srUtils.h" void @@ -271,6 +273,30 @@ doGetBinary(struct nvlst *valnode, struct cnfparamdescr *param, } } +static inline void +doGetQueueType(struct nvlst *valnode, struct cnfparamdescr *param, + struct cnfparamvals *val) +{ + char *cstr; + if(!es_strcasebufcmp(valnode->val.d.estr, (uchar*)"fixedarray", 10)) { + val->val.d.n = QUEUETYPE_FIXED_ARRAY; + } else if(!es_strcasebufcmp(valnode->val.d.estr, (uchar*)"linkedlist", 10)) { + val->val.d.n = QUEUETYPE_LINKEDLIST; + } else if(!es_strcasebufcmp(valnode->val.d.estr, (uchar*)"disk", 4)) { + val->val.d.n = QUEUETYPE_DISK; + } else if(!es_strcasebufcmp(valnode->val.d.estr, (uchar*)"direct", 6)) { + val->val.d.n = QUEUETYPE_DIRECT; + } else { + cstr = es_str2cstr(valnode->val.d.estr, NULL); + parser_errmsg("param '%s': unknown queue type: '%s'", + param->name, cstr); + free(cstr); + } +dbgprintf("XXXXX: queue type: %d\n", (int)val->val.d.n); + val->val.datatype = 'N'; +} + + /* A file create-mode must be a four-digit octal number * starting with '0'. */ @@ -416,6 +442,9 @@ nvlstGetParam(struct nvlst *valnode, struct cnfparamdescr *param, valnode->bUsed = 1; val->bUsed = 1; switch(param->type) { + case eCmdHdlrQueueType: + doGetQueueType(valnode, param, val); + break; case eCmdHdlrUID: doGetUID(valnode, param, val); break; -- cgit v1.2.3 From 26a668f8fa352e63aefcc762eadd123002b3895d Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 11 Oct 2011 12:26:48 +0200 Subject: added support for v6 config system to omfwd --- grammar/rainerscript.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 1b44974c..22a90cb7 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -437,8 +437,8 @@ nvlstGetParam(struct nvlst *valnode, struct cnfparamdescr *param, { uchar *cstr; - dbgprintf("XXXX: in nvlstGetParam, name '%s', type %d\n", - param->name, (int) param->type); + dbgprintf("XXXX: in nvlstGetParam, name '%s', type %d, valnode->bUsed %d\n", + param->name, (int) param->type, valnode->bUsed); valnode->bUsed = 1; val->bUsed = 1; switch(param->type) { -- cgit v1.2.3 From ce8e072564da6c3ef16755d8c3df8614895a717e Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 1 Feb 2012 17:35:03 +0100 Subject: conf file: bufgix: legacy parsing of some filters did not work correctly --- grammar/rainerscript.c | 1 - 1 file changed, 1 deletion(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 22a90cb7..d1d64e6e 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -292,7 +292,6 @@ doGetQueueType(struct nvlst *valnode, struct cnfparamdescr *param, param->name, cstr); free(cstr); } -dbgprintf("XXXXX: queue type: %d\n", (int)val->val.d.n); val->val.datatype = 'N'; } -- cgit v1.2.3 From feac49c13b36ec885f73151dea6aee4e4b439cdc Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 23 Apr 2012 16:54:08 +0200 Subject: bugfix: number conversion in expression evaluation was not always correct was invalid when the property was no string. Currently all props are strings, so this bug never could hit in practice. --- grammar/rainerscript.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index d1d64e6e..320e66d0 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -743,9 +743,11 @@ var2Number(struct var *r, int *bSuccess) if(r->datatype == 'S') { n = es_str2num(r->d.estr, bSuccess); } else { - *bSuccess = 1; + n = r->d.n; + if(bSuccess) + *bSuccess = 1; } - return r->d.n; + return n; } /* ensure that retval is a string; if string is no number, -- cgit v1.2.3 From db350988f0ab0b57f6a4aed0da20b5f41499690f Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 29 May 2012 10:45:44 +0200 Subject: first experiments with regexp'es in RainerScript --- grammar/rainerscript.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 320e66d0..ce0298fb 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -839,6 +839,11 @@ doFuncCall(struct cnffunc *func, struct var *ret, void* usrptr) } ret->datatype = 'N'; break; + case CNFFUNC_RE_MATCH: + dbgprintf("TODO: implement re_match()\n"); + ret->d.n = 1; + ret->datatype = 'N'; + break; default: if(Debug) { fname = es_str2cstr(func->fname, NULL); @@ -892,7 +897,7 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) int bMustFree, bMustFree2; long long n_r, n_l; - //dbgprintf("eval expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); + dbgprintf("eval expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); switch(expr->nodetype) { /* note: comparison operations are extremely similar. The code can be copyied, only * places flagged with "CMP" need to be changed. @@ -1450,6 +1455,9 @@ cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next) static inline enum cnffuncid funcName2ID(es_str_t *fname, unsigned short nParams) { +{ char *s;s=es_str2cstr(fname, NULL); +dbgprintf("ZZZZ: func: '%s', nParams: %d\n", s, nParams); +free(s);} if(!es_strbufcmp(fname, (unsigned char*)"strlen", sizeof("strlen") - 1)) { if(nParams != 1) { parser_errmsg("number of parameters for strlen() must be one " @@ -1485,6 +1493,13 @@ funcName2ID(es_str_t *fname, unsigned short nParams) return CNFFUNC_INVALID; } return CNFFUNC_CNUM; + } else if(!es_strbufcmp(fname, (unsigned char*)"re_match", sizeof("re_match") - 1)) { + if(nParams != 2) { + parser_errmsg("number of parameters for re_match() must be two " + "but is %d.", nParams); + return CNFFUNC_INVALID; + } + return CNFFUNC_RE_MATCH; } else { return CNFFUNC_INVALID; } -- cgit v1.2.3 From 61dbf692b3789e87bfaeb648c729787c81795d29 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 5 Jun 2012 10:52:51 +0200 Subject: restructured cfsysline handling a bit so that we have cleaner code --- grammar/rainerscript.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 320e66d0..2752f4af 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -623,14 +623,13 @@ cnfactlstAddSysline(struct cnfactlst* actlst, char *line) struct cnfcfsyslinelst *cflst; if((cflst = malloc(sizeof(struct cnfcfsyslinelst))) != NULL) { - cflst->next = NULL; cflst->line = line; if(actlst->syslines == NULL) { - actlst->syslines = cflst; + cflst->next = NULL; } else { cflst->next = actlst->syslines; - actlst->syslines = cflst; } + actlst->syslines = cflst; } return actlst; } -- cgit v1.2.3 From 2c0548538ef0a2f86472f000d09e49eedf278caa Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 5 Jun 2012 11:41:55 +0200 Subject: regression fix: last memleak bugfix caused abort in some situations The problem was introduced by the fix I did roughly an hour ago. Obviously, no released version is affected. --- grammar/rainerscript.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 2752f4af..66932c77 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1409,6 +1409,9 @@ cnfrulePrint(struct cnfrule *rule) dbgprintf("------ end rule %p\n", rule); } +/* note: the sysline itself was already freed during processing + * and as such MUST NOT be freed again! + */ void cnfcfsyslinelstDestruct(struct cnfcfsyslinelst *cfslst) { @@ -1416,7 +1419,6 @@ cnfcfsyslinelstDestruct(struct cnfcfsyslinelst *cfslst) while(cfslst != NULL) { toDel = cfslst; cfslst = cfslst->next; - free(toDel->line); free(toDel); } } -- cgit v1.2.3 From 85dea8048aed1b2d74eec57b30155898892daa37 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 11 Jun 2012 17:38:47 +0200 Subject: bugfix: expression-based filters with AND/OR could segfault due to a problem with boolean shortcut operations. From the user's perspective, the segfault is almost non-deterministic (it occurs when a shortcut is used). Thanks to Lars Peterson for providing the initial bug report and his support in solving it. --- grammar/rainerscript.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 66932c77..a5cc10c2 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1129,8 +1129,9 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) ret->d.n = 1ll; else ret->d.n = 0ll; + if(r.datatype == 'S') es_deleteStr(r.d.estr); } - FREE_BOTH_RET; + if(l.datatype == 'S') es_deleteStr(l.d.estr); break; case AND: cnfexprEval(expr->l, &l, usrptr); @@ -1141,10 +1142,11 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) ret->d.n = 1ll; else ret->d.n = 0ll; + if(r.datatype == 'S') es_deleteStr(r.d.estr); } else { ret->d.n = 0ll; } - FREE_BOTH_RET; + if(l.datatype == 'S') es_deleteStr(l.d.estr); break; case NOT: cnfexprEval(expr->r, &r, usrptr); -- cgit v1.2.3 From c8324b3460a85d57ca1bcfa481168d566069a0d1 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 12 Jun 2012 18:52:32 +0200 Subject: milestone: regex is compiled from script based filter --- grammar/rainerscript.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 3 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index bcdbdf3b..dfaff869 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -41,6 +41,11 @@ #include "grammar.h" #include "queue.h" #include "srUtils.h" +#include "regexp.h" +#include "obj.h" + +DEFobjCurrIf(obj) +DEFobjCurrIf(regexp) void readConfFile(FILE *fp, es_str_t **str) @@ -1458,9 +1463,6 @@ cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next) static inline enum cnffuncid funcName2ID(es_str_t *fname, unsigned short nParams) { -{ char *s;s=es_str2cstr(fname, NULL); -dbgprintf("ZZZZ: func: '%s', nParams: %d\n", s, nParams); -free(s);} if(!es_strbufcmp(fname, (unsigned char*)"strlen", sizeof("strlen") - 1)) { if(nParams != 1) { parser_errmsg("number of parameters for strlen() must be one " @@ -1508,6 +1510,41 @@ free(s);} } } + +static inline rsRetVal +initFunc_re_match(struct cnffunc *func) +{ + rsRetVal localRet; + char *regex = NULL; + regex_t *re; + DEFiRet; + + func->funcdata = NULL; + if(func->expr[1]->nodetype != 'S') { + parser_errmsg("param 2 of re_match() must be a constant string"); + FINALIZE; + } + + CHKmalloc(re = malloc(sizeof(regex_t))); + func->funcdata = re; + + regex = es_str2cstr(((struct cnfstringval*) func->expr[1])->estr, NULL); + + if((localRet = objUse(regexp, LM_REGEXP_FILENAME)) == RS_RET_OK) { + if(regexp.regcomp(re, (char*) regex, REG_EXTENDED) != 0) { + parser_errmsg("cannot compile regex '%s'", regex); + ABORT_FINALIZE(RS_RET_ERR); + } + } else { /* regexp object could not be loaded */ + parser_errmsg("could not load regex support - regex ignored"); + ABORT_FINALIZE(RS_RET_ERR); + } + +finalize_it: + free(regex); + RETiRet; +} + struct cnffunc * cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) { @@ -1534,6 +1571,14 @@ cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) param = param->next; free(toDel); } + /* some functions require special initialization */ + switch(func->fID) { + case CNFFUNC_RE_MATCH: + /* need to compile the regexp in param 2, so this MUST be a constant */ + initFunc_re_match(func); + break; + default:break; + } } return func; } @@ -1631,3 +1676,13 @@ cstrPrint(char *text, es_str_t *estr) dbgprintf("%s%s", text, str); free(str); } + +/* init must be called once before any parsing of the script files start */ +rsRetVal +initRainerscript(void) +{ + DEFiRet; + CHKiRet(objGetObjInterface(&obj)); +finalize_it: + RETiRet; +} -- cgit v1.2.3 From ba00396eee5b8f8717639da396b010631ad5baa7 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 13 Jun 2012 17:51:22 +0200 Subject: re_match() function now also executes things now basically work. however, there is at least a (small) memory leak and the code needs to be further reviewed --- grammar/rainerscript.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index dfaff869..2f7057c5 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -754,8 +754,7 @@ var2Number(struct var *r, int *bSuccess) return n; } -/* ensure that retval is a string; if string is no number, - * emit error message and set number to 0. +/* ensure that retval is a string */ static inline es_str_t * var2String(struct var *r, int *bMustFree) @@ -779,6 +778,7 @@ doFuncCall(struct cnffunc *func, struct var *ret, void* usrptr) int bMustFree; es_str_t *estr; char *str; + int retval; struct var r[CNFFUNC_MAX_ARGS]; dbgprintf("rainerscript: executing function id %d\n", func->fID); @@ -844,9 +844,21 @@ doFuncCall(struct cnffunc *func, struct var *ret, void* usrptr) ret->datatype = 'N'; break; case CNFFUNC_RE_MATCH: - dbgprintf("TODO: implement re_match()\n"); - ret->d.n = 1; + cnfexprEval(func->expr[0], &r[0], usrptr); + estr = var2String(&r[0], &bMustFree); + str = es_str2cstr(estr, NULL); + retval = regexp.regexec(func->funcdata, str, 0, NULL, 0); + if(retval == 0) + ret->d.n = 1; + else { + ret->d.n = 0; + if(retval != REG_NOMATCH) { + DBGPRINTF("re_match: regexec returned error %d\n", retval); + } + } ret->datatype = 'N'; + if(bMustFree) es_deleteStr(estr); + free(str); break; default: if(Debug) { -- cgit v1.2.3 From 488d0aaaa2a6d55e016d6b5b097cb3e20e49e191 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 14 Jun 2012 18:18:53 +0200 Subject: fixing memory leaks in expression-based filters most recently added by re_match() function --- grammar/rainerscript.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 2f7057c5..be8272b4 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -821,6 +821,7 @@ doFuncCall(struct cnffunc *func, struct var *ret, void* usrptr) es_tolower(estr); ret->datatype = 'S'; ret->d.estr = estr; + if(r[0].datatype == 'S') es_deleteStr(r[0].d.estr); break; case CNFFUNC_CSTR: cnfexprEval(func->expr[0], &r[0], usrptr); @@ -829,6 +830,7 @@ doFuncCall(struct cnffunc *func, struct var *ret, void* usrptr) estr = es_strdup(estr); ret->datatype = 'S'; ret->d.estr = estr; + if(r[0].datatype == 'S') es_deleteStr(r[0].d.estr); break; case CNFFUNC_CNUM: if(func->expr[0]->nodetype == 'N') { @@ -859,6 +861,7 @@ doFuncCall(struct cnffunc *func, struct var *ret, void* usrptr) ret->datatype = 'N'; if(bMustFree) es_deleteStr(estr); free(str); + if(r[0].datatype == 'S') es_deleteStr(r[0].d.estr); break; default: if(Debug) { @@ -1221,6 +1224,77 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) } } +//--------------------------------------------------------- + +static inline void +cnffuncDestruct(struct cnffunc *func) +{ + unsigned short i; + + for(i = 0 ; i < func->nParams ; ++i) { + cnfexprDestruct(func->expr[i]); + } + /* some functions require special destruction */ + switch(func->fID) { + case CNFFUNC_RE_MATCH: + regexp.regfree(func->funcdata); + free(func->funcdata); + break; + default:break; + } +} + +/* Destruct an expression and all sub-expressions contained in it. + */ +void +cnfexprDestruct(struct cnfexpr *expr) +{ + + dbgprintf("cnfexprDestruct expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); + switch(expr->nodetype) { + case CMP_NE: + case CMP_EQ: + case CMP_LE: + case CMP_GE: + case CMP_LT: + case CMP_GT: + case CMP_STARTSWITH: + case CMP_STARTSWITHI: + case CMP_CONTAINS: + case CMP_CONTAINSI: + case OR: + case AND: + case '+': + case '-': + case '*': + case '/': + case '%': /* binary */ + cnfexprDestruct(expr->l); + cnfexprDestruct(expr->r); + break; + case NOT: + case 'M': /* unary */ + cnfexprDestruct(expr->r); + break; + case 'N': + break; + case 'S': + es_deleteStr(((struct cnfstringval*)expr)->estr); + break; + case 'V': + free(((struct cnfvar*)expr)->name); + break; + case 'F': + cnffuncDestruct((struct cnffunc*)expr); + break; + default:break; + } + free(expr); +} + +//---- END + + /* Evaluate an expression as a bool. This is added because expressions are * mostly used inside filters, and so this function is quite common and * important. -- cgit v1.2.3 From 3da62eee866a1edeb133c1c50fbffdebd261c8e6 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 14 Jun 2012 18:59:06 +0200 Subject: bugfix: small static memory leak in expression based filters function names were not freed upon config shutdown --- grammar/rainerscript.c | 1 + 1 file changed, 1 insertion(+) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index be8272b4..f542b7f2 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1239,6 +1239,7 @@ cnffuncDestruct(struct cnffunc *func) case CNFFUNC_RE_MATCH: regexp.regfree(func->funcdata); free(func->funcdata); + free(func->fname); break; default:break; } -- cgit v1.2.3 From 46ccc9e77f5e2ee3ded1ca79e973fafdc37e4c0f Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 20 Jun 2012 09:34:31 +0200 Subject: milestone: module() can load module in legacy mode --- grammar/rainerscript.c | 1 - 1 file changed, 1 deletion(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index f542b7f2..3bfb2e07 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -682,7 +682,6 @@ cnfactlstReverse(struct cnfactlst *actlst) prev = NULL; while(actlst != NULL) { - //dbgprintf("reversing: %s\n", actlst->data.legActLine); curr = actlst; actlst = actlst->next; curr->syslines = cnfcfsyslinelstReverse(curr->syslines); -- cgit v1.2.3 From 6258cb42fd407b9388de63c746634b4df03e78eb Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sat, 25 Aug 2012 13:30:53 +0200 Subject: milestone: base plumbing for LIST-type templates mostly in place --- grammar/rainerscript.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 3bfb2e07..1ccac575 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -98,6 +98,44 @@ readConfFile(FILE *fp, es_str_t **str) es_addChar(str, '\0'); } +struct objlst* +objlstNew(struct cnfobj *o) +{ + struct objlst *lst; + + if((lst = malloc(sizeof(struct objlst))) != NULL) { + lst->next = NULL; + lst->obj = o; + } +dbgprintf("AAAA: creating new objlst\n"); +cnfobjPrint(o); + + return lst; +} + +void +objlstDestruct(struct objlst *lst) +{ + struct objlst *toDel; + + while(lst != NULL) { + toDel = lst; + lst = lst->next; + // TODO: delete object + free(toDel); + } +} + +void +objlstPrint(struct objlst *lst) +{ + dbgprintf("objlst %p:\n", lst); + while(lst != NULL) { + cnfobjPrint(lst->obj); + lst = lst->next; + } +} + struct nvlst* nvlstNew(es_str_t *name, es_str_t *value) { @@ -581,6 +619,7 @@ cnfobjNew(enum cnfobjType objType, struct nvlst *lst) nvlstChkDupes(lst); o->objType = objType; o->nvlst = lst; + o->subobjs = NULL; } return o; -- cgit v1.2.3 From 76e9968c0890cb4db068c953db6e6574b6c28da0 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sat, 25 Aug 2012 17:17:27 +0200 Subject: milestone: LIST-type templates work, but no all options yet present --- grammar/rainerscript.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 1ccac575..33630a76 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -113,6 +113,24 @@ cnfobjPrint(o); return lst; } +/* add object to end of object list, always returns pointer to root object */ +struct objlst* +objlstAdd(struct objlst *root, struct cnfobj *o) +{ + struct objlst *l; + struct objlst *newl; + + newl = objlstNew(o); + if(root == 0) { + root = newl; + } else { /* find last, linear search ok, as only during config phase */ + for(l = root ; l->next != NULL ; l = l->next) + ; + l->next = newl; + } + return root; +} + void objlstDestruct(struct objlst *lst) { -- cgit v1.2.3 From 396743e19aed8494c68c3a41ce140e884d4a71af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Mon, 3 Sep 2012 19:22:18 +0200 Subject: Free configuration objects after use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Miloslav Trmač --- grammar/rainerscript.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 33630a76..56a6376d 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -139,7 +139,7 @@ objlstDestruct(struct objlst *lst) while(lst != NULL) { toDel = lst; lst = lst->next; - // TODO: delete object + cnfobjDestruct(toDel->obj); free(toDel); } } @@ -648,6 +648,7 @@ cnfobjDestruct(struct cnfobj *o) { if(o != NULL) { nvlstDestruct(o->nvlst); + objlstDestruct(o->subobjs); free(o); } } -- cgit v1.2.3 From 0bf6991bf6c155ff43c394c284e23dfe6b0fc53f Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 4 Sep 2012 10:50:07 +0200 Subject: new ruleengine: first code for stmt handling --- grammar/rainerscript.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 33630a76..0d236c1e 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -107,7 +107,6 @@ objlstNew(struct cnfobj *o) lst->next = NULL; lst->obj = o; } -dbgprintf("AAAA: creating new objlst\n"); cnfobjPrint(o); return lst; @@ -1497,6 +1496,48 @@ cnfexprPrint(struct cnfexpr *expr, int indent) break; } } +void +cnfstmtPrint(struct cnfstmt *stmt, int indent) +{ + //dbgprintf("stmt %p, indent %d, type '%c'\n", expr, indent, expr->nodetype); + switch(stmt->nodetype) { + case S_STOP: + doIndent(indent); dbgprintf("STOP\n"); + break; + case S_ACT: + doIndent(indent); dbgprintf("ACTION %p\n", stmt->d.act); + break; + case S_IF: + doIndent(indent); dbgprintf("IF\n"); + cnfexprPrint(stmt->d.cond.expr, indent+1); + doIndent(indent); dbgprintf("THEN\n"); + cnfstmtPrint(stmt->d.cond.t_then, indent+1); + if(stmt->d.cond.t_else != NULL) { + doIndent(indent); dbgprintf("ELSE\n"); + cnfstmtPrint(stmt->d.cond.t_else, indent+1); + } + doIndent(indent); dbgprintf("END IF\n"); + break; + case S_PRIFILT: + doIndent(indent); dbgprintf("PRIFILT\n"); + cnfexprPrint(stmt->d.cond.expr, indent+1); + doIndent(indent); dbgprintf("THEN\n"); + cnfstmtPrint(stmt->d.cond.t_then, indent+1); + doIndent(indent); dbgprintf("END PRIFILT\n"); + break; + case S_PROPFILT: + doIndent(indent); dbgprintf("PROPFILT\n"); + cnfexprPrint(stmt->d.cond.expr, indent+1); + doIndent(indent); dbgprintf("THEN\n"); + cnfstmtPrint(stmt->d.cond.t_then, indent+1); + doIndent(indent); dbgprintf("END PROPFILT\n"); + break; + default: + dbgprintf("error: unknown stmt type %u\n", + (unsigned) stmt->nodetype); + break; + } +} struct cnfnumval* cnfnumvalNew(long long val) @@ -1531,6 +1572,17 @@ cnfvarNew(char *name) return var; } +struct cnfstmt * +cnfstmtNew(unsigned s_type) +{ + struct cnfstmt* cnfstmt; + if((cnfstmt = malloc(sizeof(struct cnfstmt))) != NULL) { + cnfstmt->nodetype = s_type; + cnfstmt->next = NULL; + } + return cnfstmt; +} + struct cnfrule * cnfruleNew(enum cnfFiltType filttype, struct cnfactlst *actlst) { -- cgit v1.2.3 From 493ddeaa770de41ab5a6bb5279eed355c84b12ee Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 4 Sep 2012 11:05:19 +0200 Subject: new ruleengine: add &-operator (legacy action list) --- grammar/rainerscript.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 0d236c1e..d9812fee 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1519,8 +1519,8 @@ cnfstmtPrint(struct cnfstmt *stmt, int indent) doIndent(indent); dbgprintf("END IF\n"); break; case S_PRIFILT: - doIndent(indent); dbgprintf("PRIFILT\n"); - cnfexprPrint(stmt->d.cond.expr, indent+1); + doIndent(indent); dbgprintf("PRIFILT '%s'\n", stmt->d.cond.printable); + //cnfexprPrint(stmt->d.cond.expr, indent+1); doIndent(indent); dbgprintf("THEN\n"); cnfstmtPrint(stmt->d.cond.t_then, indent+1); doIndent(indent); dbgprintf("END PRIFILT\n"); -- cgit v1.2.3 From 68b9fe72b89ff47efdbed8fea4185bac84279a51 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 4 Sep 2012 12:00:01 +0200 Subject: new ruleengine: script block correctly built --- grammar/rainerscript.c | 102 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 66 insertions(+), 36 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 2d5bbd9b..b127b906 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -130,6 +130,25 @@ objlstAdd(struct objlst *root, struct cnfobj *o) return root; } +/* add stmt to current script, always return root stmt pointer */ +struct cnfstmt* +scriptAddStmt(struct cnfstmt *root, struct cnfstmt *s) +{ + struct cnfstmt *l; +dbgprintf("RRRR: scriptAddStmt(%p, %p): ", root, s); + + if(root == NULL) { + root = s; +dbgprintf("root set to %p\n", s); + } else { /* find last, linear search ok, as only during config phase */ + for(l = root ; l->next != NULL ; l = l->next) + ; + l->next = s; +dbgprintf("%p->next = %p\n", l, s); + } + return root; +} + void objlstDestruct(struct objlst *lst) { @@ -1498,45 +1517,47 @@ cnfexprPrint(struct cnfexpr *expr, int indent) } } void -cnfstmtPrint(struct cnfstmt *stmt, int indent) +cnfstmtPrint(struct cnfstmt *root, int indent) { + struct cnfstmt *stmt; //dbgprintf("stmt %p, indent %d, type '%c'\n", expr, indent, expr->nodetype); - switch(stmt->nodetype) { - case S_STOP: - doIndent(indent); dbgprintf("STOP\n"); - break; - case S_ACT: - doIndent(indent); dbgprintf("ACTION %p\n", stmt->d.act); - break; - case S_IF: - doIndent(indent); dbgprintf("IF\n"); - cnfexprPrint(stmt->d.cond.expr, indent+1); - doIndent(indent); dbgprintf("THEN\n"); - cnfstmtPrint(stmt->d.cond.t_then, indent+1); - if(stmt->d.cond.t_else != NULL) { - doIndent(indent); dbgprintf("ELSE\n"); - cnfstmtPrint(stmt->d.cond.t_else, indent+1); + for(stmt = root ; stmt != NULL ; stmt = stmt->next) { + switch(stmt->nodetype) { + case S_STOP: + doIndent(indent); dbgprintf("STOP\n"); + break; + case S_ACT: + doIndent(indent); dbgprintf("ACTION %p (%s)\n", stmt->d.act, stmt->printable); + break; + case S_IF: + doIndent(indent); dbgprintf("IF\n"); + cnfexprPrint(stmt->d.cond.expr, indent+1); + doIndent(indent); dbgprintf("THEN\n"); + cnfstmtPrint(stmt->d.cond.t_then, indent+1); + if(stmt->d.cond.t_else != NULL) { + doIndent(indent); dbgprintf("ELSE\n"); + cnfstmtPrint(stmt->d.cond.t_else, indent+1); + } + doIndent(indent); dbgprintf("END IF\n"); + break; + case S_PRIFILT: + doIndent(indent); dbgprintf("PRIFILT '%s'\n", stmt->printable); + //cnfexprPrint(stmt->d.cond.expr, indent+1); + cnfstmtPrint(stmt->d.cond.t_then, indent+1); + doIndent(indent); dbgprintf("END PRIFILT\n"); + break; + case S_PROPFILT: + doIndent(indent); dbgprintf("PROPFILT\n"); + cnfexprPrint(stmt->d.cond.expr, indent+1); + doIndent(indent); dbgprintf("THEN\n"); + cnfstmtPrint(stmt->d.cond.t_then, indent+1); + doIndent(indent); dbgprintf("END PROPFILT\n"); + break; + default: + dbgprintf("error: unknown stmt type %u\n", + (unsigned) stmt->nodetype); + break; } - doIndent(indent); dbgprintf("END IF\n"); - break; - case S_PRIFILT: - doIndent(indent); dbgprintf("PRIFILT '%s'\n", stmt->d.cond.printable); - //cnfexprPrint(stmt->d.cond.expr, indent+1); - doIndent(indent); dbgprintf("THEN\n"); - cnfstmtPrint(stmt->d.cond.t_then, indent+1); - doIndent(indent); dbgprintf("END PRIFILT\n"); - break; - case S_PROPFILT: - doIndent(indent); dbgprintf("PROPFILT\n"); - cnfexprPrint(stmt->d.cond.expr, indent+1); - doIndent(indent); dbgprintf("THEN\n"); - cnfstmtPrint(stmt->d.cond.t_then, indent+1); - doIndent(indent); dbgprintf("END PROPFILT\n"); - break; - default: - dbgprintf("error: unknown stmt type %u\n", - (unsigned) stmt->nodetype); - break; } } @@ -1873,6 +1894,15 @@ cstrPrint(char *text, es_str_t *estr) free(str); } +char * +rmLeadingSpace(char *s) +{ + char *p; + for(p = s ; *p && isspace(*p) ; ++p) + ; + return(p); +} + /* init must be called once before any parsing of the script files start */ rsRetVal initRainerscript(void) -- cgit v1.2.3 From c596f1c1b2b6df18a9209d436a8255d96f437b54 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 4 Sep 2012 14:51:35 +0200 Subject: new ruleengine: PROP and PRI legacy filter structures properly created --- grammar/rainerscript.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 79 insertions(+), 7 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index b127b906..0e3f30ae 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -37,6 +37,7 @@ #include #include "rsyslog.h" #include "rainerscript.h" +#include "conf.h" #include "parserif.h" #include "grammar.h" #include "queue.h" @@ -47,6 +48,37 @@ DEFobjCurrIf(obj) DEFobjCurrIf(regexp) +static char* +getFIOPName(unsigned iFIOP) +{ + char *pRet; + switch(iFIOP) { + case FIOP_CONTAINS: + pRet = "contains"; + break; + case FIOP_ISEQUAL: + pRet = "isequal"; + break; + case FIOP_STARTSWITH: + pRet = "startswith"; + break; + case FIOP_REGEX: + pRet = "regex"; + break; + case FIOP_EREREGEX: + pRet = "ereregex"; + break; + case FIOP_ISEMPTY: + pRet = "isempty"; + break; + default: + pRet = "NOP"; + break; + } + return pRet; +} + + void readConfFile(FILE *fp, es_str_t **str) { @@ -1531,26 +1563,42 @@ cnfstmtPrint(struct cnfstmt *root, int indent) break; case S_IF: doIndent(indent); dbgprintf("IF\n"); - cnfexprPrint(stmt->d.cond.expr, indent+1); + cnfexprPrint(stmt->d.s_if.expr, indent+1); doIndent(indent); dbgprintf("THEN\n"); - cnfstmtPrint(stmt->d.cond.t_then, indent+1); - if(stmt->d.cond.t_else != NULL) { + cnfstmtPrint(stmt->d.s_if.t_then, indent+1); + if(stmt->d.s_if.t_else != NULL) { doIndent(indent); dbgprintf("ELSE\n"); - cnfstmtPrint(stmt->d.cond.t_else, indent+1); + cnfstmtPrint(stmt->d.s_if.t_else, indent+1); } doIndent(indent); dbgprintf("END IF\n"); break; case S_PRIFILT: doIndent(indent); dbgprintf("PRIFILT '%s'\n", stmt->printable); //cnfexprPrint(stmt->d.cond.expr, indent+1); - cnfstmtPrint(stmt->d.cond.t_then, indent+1); + cnfstmtPrint(stmt->d.s_prifilt.t_then, indent+1); doIndent(indent); dbgprintf("END PRIFILT\n"); break; case S_PROPFILT: doIndent(indent); dbgprintf("PROPFILT\n"); - cnfexprPrint(stmt->d.cond.expr, indent+1); + doIndent(indent); dbgprintf("\tProperty.: '%s'\n", + propIDToName(stmt->d.s_propfilt.propID)); + if(stmt->d.s_propfilt.propName != NULL) { + char *cstr; + cstr = es_str2cstr(stmt->d.s_propfilt.propName, NULL); + doIndent(indent); + dbgprintf("\tCEE-Prop.: '%s'\n", cstr); + free(cstr); + } + doIndent(indent); dbgprintf("\tOperation: "); + if(stmt->d.s_propfilt.isNegated) + dbgprintf("NOT "); + dbgprintf("'%s'\n", getFIOPName(stmt->d.s_propfilt.operation)); + if(stmt->d.s_propfilt.pCSCompValue != NULL) { + doIndent(indent); dbgprintf("\tValue....: '%s'\n", + rsCStrGetSzStrNoNULL(stmt->d.s_propfilt.pCSCompValue)); + } doIndent(indent); dbgprintf("THEN\n"); - cnfstmtPrint(stmt->d.cond.t_then, indent+1); + cnfstmtPrint(stmt->d.s_propfilt.t_then, indent+1); doIndent(indent); dbgprintf("END PROPFILT\n"); break; default: @@ -1605,6 +1653,30 @@ cnfstmtNew(unsigned s_type) return cnfstmt; } +struct cnfstmt * +cnfstmtNewPRIFILT(char *prifilt, struct cnfstmt *t_then) +{ + struct cnfstmt* cnfstmt; + if((cnfstmt = cnfstmtNew(S_PRIFILT)) != NULL) { + cnfstmt->printable = (uchar*)strdup(prifilt); + cnfstmt->d.s_prifilt.t_then = t_then; + DecodePRIFilter((uchar*)prifilt, cnfstmt->d.s_prifilt.pmask); + } + return cnfstmt; +} + +struct cnfstmt * +cnfstmtNewPROPFILT(char *propfilt, struct cnfstmt *t_then) +{ + struct cnfstmt* cnfstmt; + if((cnfstmt = cnfstmtNew(S_PROPFILT)) != NULL) { + cnfstmt->printable = (uchar*)strdup(propfilt); + cnfstmt->d.s_propfilt.t_then = t_then; + DecodePropFilter((uchar*)propfilt, cnfstmt); + } + return cnfstmt; +} + struct cnfrule * cnfruleNew(enum cnfFiltType filttype, struct cnfactlst *actlst) { -- cgit v1.2.3 From 72f9fe88b24428067557a71405ee641a641bf7c4 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 4 Sep 2012 15:18:37 +0200 Subject: new ruleengine: v6+ action object properly constructed --- grammar/rainerscript.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 0e3f30ae..6e3bae68 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1677,6 +1677,23 @@ cnfstmtNewPROPFILT(char *propfilt, struct cnfstmt *t_then) return cnfstmt; } +struct cnfstmt * +cnfstmtNewAct(struct nvlst *lst) +{ + struct cnfstmt* cnfstmt; + if((cnfstmt = cnfstmtNew(S_ACT)) == NULL) + goto done; + if(actionNewInst(lst, &cnfstmt->d.act) != RS_RET_OK) { + // TODO:RS_RET_WARN? + parser_errmsg("errors occured in file '%s' around line %d", + cnfcurrfn, yylineno); + cnfstmt->nodetype = S_NOP; /* disable action! */ + goto done; + } + cnfstmt->printable = (uchar*)"action()"; +done: return cnfstmt; +} + struct cnfrule * cnfruleNew(enum cnfFiltType filttype, struct cnfactlst *actlst) { -- cgit v1.2.3 From 3dd73d7f7194139a9b8bf1668f6192ead0c801ec Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 4 Sep 2012 15:54:40 +0200 Subject: new ruleengine: legacy action object properly constructed --- grammar/rainerscript.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 6e3bae68..20cf2f6d 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -39,6 +39,7 @@ #include "rainerscript.h" #include "conf.h" #include "parserif.h" +#include "rsconf.h" #include "grammar.h" #include "queue.h" #include "srUtils.h" @@ -1555,6 +1556,9 @@ cnfstmtPrint(struct cnfstmt *root, int indent) //dbgprintf("stmt %p, indent %d, type '%c'\n", expr, indent, expr->nodetype); for(stmt = root ; stmt != NULL ; stmt = stmt->next) { switch(stmt->nodetype) { + case S_NOP: + doIndent(indent); dbgprintf("NOP\n"); + break; case S_STOP: doIndent(indent); dbgprintf("STOP\n"); break; @@ -1694,6 +1698,27 @@ cnfstmtNewAct(struct nvlst *lst) done: return cnfstmt; } +struct cnfstmt * +cnfstmtNewLegaAct(uchar *actline) +{ + struct cnfstmt* cnfstmt; + rsRetVal localRet; + if((cnfstmt = cnfstmtNew(S_ACT)) == NULL) + goto done; + cnfstmt->printable = (uchar*)strdup((char*)actline); + localRet = cflineDoAction(loadConf, &actline, &cnfstmt->d.act); + if(localRet != RS_RET_OK && localRet != RS_RET_OK_WARN) { + parser_errmsg("%s occured in file '%s' around line %d", + (localRet == RS_RET_OK_WARN) ? "warnings" : "errors", + cnfcurrfn, yylineno); + if(localRet != RS_RET_OK_WARN) { + cnfstmt->nodetype = S_NOP; /* disable action! */ + goto done; + } + } +done: return cnfstmt; +} + struct cnfrule * cnfruleNew(enum cnfFiltType filttype, struct cnfactlst *actlst) { -- cgit v1.2.3 From d3e96418f514cd69592be24af6a632a8491820fc Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 6 Sep 2012 10:48:24 +0200 Subject: new ruleengine: implement rainerscript execution engine --- grammar/rainerscript.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 20cf2f6d..dc2ef64c 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -49,7 +49,7 @@ DEFobjCurrIf(obj) DEFobjCurrIf(regexp) -static char* +char* getFIOPName(unsigned iFIOP) { char *pRet; -- cgit v1.2.3 From 77ea54a5b98e80738914587bd0f252befeffe4f7 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 6 Sep 2012 17:17:50 +0200 Subject: new ruleengine: restore action iterator functionality --- grammar/rainerscript.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index dc2ef64c..0ebfb44e 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1699,14 +1699,14 @@ done: return cnfstmt; } struct cnfstmt * -cnfstmtNewLegaAct(uchar *actline) +cnfstmtNewLegaAct(char *actline) { struct cnfstmt* cnfstmt; rsRetVal localRet; if((cnfstmt = cnfstmtNew(S_ACT)) == NULL) goto done; cnfstmt->printable = (uchar*)strdup((char*)actline); - localRet = cflineDoAction(loadConf, &actline, &cnfstmt->d.act); + localRet = cflineDoAction(loadConf, (uchar**)&actline, &cnfstmt->d.act); if(localRet != RS_RET_OK && localRet != RS_RET_OK_WARN) { parser_errmsg("%s occured in file '%s' around line %d", (localRet == RS_RET_OK_WARN) ? "warnings" : "errors", -- cgit v1.2.3 From 8795df908b969f6e226256a3cd25cc976491533b Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 6 Sep 2012 18:23:16 +0200 Subject: new ruleengine: properly freeing stmt tree --- grammar/rainerscript.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 0ebfb44e..d6a51191 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1635,6 +1635,7 @@ cnfstringvalNew(es_str_t *estr) return strval; } + struct cnfvar* cnfvarNew(char *name) { @@ -1657,12 +1658,57 @@ cnfstmtNew(unsigned s_type) return cnfstmt; } +void +cnfstmtDestruct(struct cnfstmt *root) +{ + struct cnfstmt *stmt, *todel; + for(stmt = root ; stmt != NULL ; ) { + switch(stmt->nodetype) { + case S_NOP: + case S_STOP: + break; + case S_ACT: +dbgprintf("XXXX: destruct action %p\n", stmt->d.act); + actionDestruct(stmt->d.act); + break; + case S_IF: + cnfexprDestruct(stmt->d.s_if.expr); + if(stmt->d.s_if.t_then != NULL) { + cnfstmtDestruct(stmt->d.s_if.t_then); + } + if(stmt->d.s_if.t_else != NULL) { + cnfstmtDestruct(stmt->d.s_if.t_else); + } + break; + case S_PRIFILT: + cnfstmtDestruct(stmt->d.s_prifilt.t_then); + break; + case S_PROPFILT: + if(stmt->d.s_propfilt.propName != NULL) + es_deleteStr(stmt->d.s_propfilt.propName); + if(stmt->d.s_propfilt.regex_cache != NULL) + rsCStrRegexDestruct(&stmt->d.s_propfilt.regex_cache); + if(stmt->d.s_propfilt.pCSCompValue != NULL) + cstrDestruct(&stmt->d.s_propfilt.pCSCompValue); + cnfstmtDestruct(stmt->d.s_propfilt.t_then); + break; + default: + dbgprintf("error: unknown stmt type during destruct %u\n", + (unsigned) stmt->nodetype); + break; + } + todel = stmt; + stmt = stmt->next; + free(todel); + } +} + struct cnfstmt * cnfstmtNewPRIFILT(char *prifilt, struct cnfstmt *t_then) { struct cnfstmt* cnfstmt; if((cnfstmt = cnfstmtNew(S_PRIFILT)) != NULL) { - cnfstmt->printable = (uchar*)strdup(prifilt); + cnfstmt->printable = (uchar*)prifilt; cnfstmt->d.s_prifilt.t_then = t_then; DecodePRIFilter((uchar*)prifilt, cnfstmt->d.s_prifilt.pmask); } @@ -1676,6 +1722,9 @@ cnfstmtNewPROPFILT(char *propfilt, struct cnfstmt *t_then) if((cnfstmt = cnfstmtNew(S_PROPFILT)) != NULL) { cnfstmt->printable = (uchar*)strdup(propfilt); cnfstmt->d.s_propfilt.t_then = t_then; + cnfstmt->d.s_propfilt.propName = NULL; + cnfstmt->d.s_propfilt.regex_cache = NULL; + cnfstmt->d.s_propfilt.pCSCompValue = NULL; DecodePropFilter((uchar*)propfilt, cnfstmt); } return cnfstmt; -- cgit v1.2.3 From 92c030bb767b7f7306a3b8d015b901bb8f1f79b9 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 10 Sep 2012 16:59:20 +0200 Subject: new ruleengine: more cleanup --- grammar/rainerscript.c | 169 +------------------------------------------------ 1 file changed, 1 insertion(+), 168 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index d6a51191..295e46b6 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -2,7 +2,7 @@ * * Module begun 2011-07-01 by Rainer Gerhards * - * Copyright 2011 Rainer Gerhards and Adiscon GmbH. + * Copyright 2011-2012 Rainer Gerhards and Adiscon GmbH. * * This file is part of the rsyslog runtime library. * @@ -712,116 +712,6 @@ cnfobjPrint(struct cnfobj *o) } -struct cnfactlst* -cnfactlstNew(enum cnfactType actType, struct nvlst *lst, char *actLine) -{ - struct cnfactlst *actlst; - - if((actlst = malloc(sizeof(struct cnfactlst))) != NULL) { - actlst->next = NULL; - actlst->syslines = NULL; - actlst->actType = actType; - actlst->lineno = yylineno; - actlst->cnfFile = strdup(cnfcurrfn); - if(actType == CNFACT_V2) - actlst->data.lst = lst; - else - actlst->data.legActLine = actLine; - } - return actlst; -} - -struct cnfactlst* -cnfactlstAddSysline(struct cnfactlst* actlst, char *line) -{ - struct cnfcfsyslinelst *cflst; - - if((cflst = malloc(sizeof(struct cnfcfsyslinelst))) != NULL) { - cflst->line = line; - if(actlst->syslines == NULL) { - cflst->next = NULL; - } else { - cflst->next = actlst->syslines; - } - actlst->syslines = cflst; - } - return actlst; -} - - -void -cnfactlstDestruct(struct cnfactlst *actlst) -{ - struct cnfactlst *toDel; - - while(actlst != NULL) { - toDel = actlst; - actlst = actlst->next; - free(toDel->cnfFile); - cnfcfsyslinelstDestruct(toDel->syslines); - if(toDel->actType == CNFACT_V2) - nvlstDestruct(toDel->data.lst); - else - free(toDel->data.legActLine); - free(toDel); - } - -} - -static inline struct cnfcfsyslinelst* -cnfcfsyslinelstReverse(struct cnfcfsyslinelst *lst) -{ - struct cnfcfsyslinelst *curr, *prev; - if(lst == NULL) - return NULL; - prev = NULL; - while(lst != NULL) { - curr = lst; - lst = lst->next; - curr->next = prev; - prev = curr; - } - return prev; -} - -struct cnfactlst* -cnfactlstReverse(struct cnfactlst *actlst) -{ - struct cnfactlst *curr, *prev; - - prev = NULL; - while(actlst != NULL) { - curr = actlst; - actlst = actlst->next; - curr->syslines = cnfcfsyslinelstReverse(curr->syslines); - curr->next = prev; - prev = curr; - } - return prev; -} - -void -cnfactlstPrint(struct cnfactlst *actlst) -{ - struct cnfcfsyslinelst *cflst; - - while(actlst != NULL) { - dbgprintf("aclst %p: ", actlst); - if(actlst->actType == CNFACT_V2) { - dbgprintf("V2 action type: "); - nvlstPrint(actlst->data.lst); - } else { - dbgprintf("legacy action line: '%s'\n", - actlst->data.legActLine); - } - for( cflst = actlst->syslines - ; cflst != NULL ; cflst = cflst->next) { - dbgprintf("action:cfsysline: '%s'\n", cflst->line); - } - actlst = actlst->next; - } -} - struct cnfexpr* cnfexprNew(unsigned nodetype, struct cnfexpr *l, struct cnfexpr *r) { @@ -1768,63 +1658,6 @@ cnfstmtNewLegaAct(char *actline) done: return cnfstmt; } -struct cnfrule * -cnfruleNew(enum cnfFiltType filttype, struct cnfactlst *actlst) -{ - struct cnfrule* cnfrule; - if((cnfrule = malloc(sizeof(struct cnfrule))) != NULL) { - cnfrule->nodetype = 'R'; - cnfrule->filttype = filttype; - cnfrule->actlst = cnfactlstReverse(actlst); - } - return cnfrule; -} - -void -cnfrulePrint(struct cnfrule *rule) -{ - dbgprintf("------ start rule %p:\n", rule); - dbgprintf("%s: ", cnfFiltType2str(rule->filttype)); - switch(rule->filttype) { - case CNFFILT_NONE: - break; - case CNFFILT_PRI: - case CNFFILT_PROP: - dbgprintf("%s\n", rule->filt.s); - break; - case CNFFILT_SCRIPT: - dbgprintf("\n"); - cnfexprPrint(rule->filt.expr, 0); - break; - } - cnfactlstPrint(rule->actlst); - dbgprintf("------ end rule %p\n", rule); -} - -/* note: the sysline itself was already freed during processing - * and as such MUST NOT be freed again! - */ -void -cnfcfsyslinelstDestruct(struct cnfcfsyslinelst *cfslst) -{ - struct cnfcfsyslinelst *toDel; - while(cfslst != NULL) { - toDel = cfslst; - cfslst = cfslst->next; - free(toDel); - } -} - -void -cnfruleDestruct(struct cnfrule *rule) -{ - if( rule->filttype == CNFFILT_PRI - || rule->filttype == CNFFILT_PROP) - free(rule->filt.s); - cnfactlstDestruct(rule->actlst); - free(rule); -} - struct cnffparamlst * cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next) { -- cgit v1.2.3 From d3bb43798c95f9d95f9e031387f4aedd814c34ab Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 10 Sep 2012 18:17:34 +0200 Subject: new ruleengine: fix memory leaks & a little cleanup --- grammar/rainerscript.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 295e46b6..30600ea3 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1468,7 +1468,6 @@ cnfstmtPrint(struct cnfstmt *root, int indent) break; case S_PRIFILT: doIndent(indent); dbgprintf("PRIFILT '%s'\n", stmt->printable); - //cnfexprPrint(stmt->d.cond.expr, indent+1); cnfstmtPrint(stmt->d.s_prifilt.t_then, indent+1); doIndent(indent); dbgprintf("END PRIFILT\n"); break; @@ -1543,6 +1542,7 @@ cnfstmtNew(unsigned s_type) struct cnfstmt* cnfstmt; if((cnfstmt = malloc(sizeof(struct cnfstmt))) != NULL) { cnfstmt->nodetype = s_type; + cnfstmt->printable = NULL; cnfstmt->next = NULL; } return cnfstmt; @@ -1558,7 +1558,6 @@ cnfstmtDestruct(struct cnfstmt *root) case S_STOP: break; case S_ACT: -dbgprintf("XXXX: destruct action %p\n", stmt->d.act); actionDestruct(stmt->d.act); break; case S_IF: @@ -1587,6 +1586,7 @@ dbgprintf("XXXX: destruct action %p\n", stmt->d.act); (unsigned) stmt->nodetype); break; } + free(stmt->printable); todel = stmt; stmt = stmt->next; free(todel); @@ -1610,7 +1610,7 @@ cnfstmtNewPROPFILT(char *propfilt, struct cnfstmt *t_then) { struct cnfstmt* cnfstmt; if((cnfstmt = cnfstmtNew(S_PROPFILT)) != NULL) { - cnfstmt->printable = (uchar*)strdup(propfilt); + cnfstmt->printable = (uchar*)propfilt; cnfstmt->d.s_propfilt.t_then = t_then; cnfstmt->d.s_propfilt.propName = NULL; cnfstmt->d.s_propfilt.regex_cache = NULL; @@ -1633,7 +1633,7 @@ cnfstmtNewAct(struct nvlst *lst) cnfstmt->nodetype = S_NOP; /* disable action! */ goto done; } - cnfstmt->printable = (uchar*)"action()"; + cnfstmt->printable = (uchar*)strdup("action()"); done: return cnfstmt; } -- cgit v1.2.3 From b4bc665643b707509ddbcbb9ca5726cd89350441 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 12 Sep 2012 15:33:13 +0200 Subject: bugfix: abort when invalid property name was configured --- grammar/rainerscript.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 30600ea3..d588ccc9 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1609,13 +1609,15 @@ struct cnfstmt * cnfstmtNewPROPFILT(char *propfilt, struct cnfstmt *t_then) { struct cnfstmt* cnfstmt; + rsRetVal lRet; if((cnfstmt = cnfstmtNew(S_PROPFILT)) != NULL) { cnfstmt->printable = (uchar*)propfilt; cnfstmt->d.s_propfilt.t_then = t_then; cnfstmt->d.s_propfilt.propName = NULL; cnfstmt->d.s_propfilt.regex_cache = NULL; cnfstmt->d.s_propfilt.pCSCompValue = NULL; - DecodePropFilter((uchar*)propfilt, cnfstmt); + lRet = DecodePropFilter((uchar*)propfilt, cnfstmt); +dbgprintf("AAAA: DecodePropFilter returns %d\n", lRet); } return cnfstmt; } -- cgit v1.2.3 From 10bef02e8f8f6bec4f1c18d9c634aa6927f4611a Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 13 Sep 2012 09:30:20 +0200 Subject: bugfix: missing support for escape sequences in RainerScript Only \' was supported. Now the usual set is supported. Note that v5 used \x as escape where x was any character (e.g. "\n" meant "n" and NOT LF). This also means there is some incompatibility to v5 for well-know sequences. Better break it now than later. --- grammar/rainerscript.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index a5cc10c2..de63f692 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1616,3 +1616,142 @@ cstrPrint(char *text, es_str_t *estr) dbgprintf("%s%s", text, str); free(str); } + + +/* we need a function to check for octal digits */ +static inline int +isodigit(uchar c) +{ + return(c >= '0' && c <= '7'); +} + +/** + * Get numerical value of a hex digit. This is a helper function. + * @param[in] c a character containing 0..9, A..Z, a..z anything else + * is an (undetected) error. + */ +static inline int +hexDigitVal(char c) +{ + int r; + if(c < 'A') + r = c - '0'; + else if(c < 'a') + r = c - 'A' + 10; + else + r = c - 'a' + 10; + return r; +} + +/* Handle the actual unescaping. + * a helper to unescapeStr(), to help make the function easier to read. + */ +static inline void +doUnescape(unsigned char *c, int len, int *iSrc, int iDst) +{ + if(c[*iSrc] == '\\') { + if(++(*iSrc) == len) { + /* error, incomplete escape, treat as single char */ + c[iDst] = '\\'; + } + /* regular case, unescape */ + switch(c[*iSrc]) { + case 'a': + c[iDst] = '\007'; + break; + case 'b': + c[iDst] = '\b'; + break; + case 'f': + c[iDst] = '\014'; + break; + case 'n': + c[iDst] = '\n'; + break; + case 'r': + c[iDst] = '\r'; + break; + case 't': + c[iDst] = '\t'; + break; + case '\'': + c[iDst] = '\''; + break; + case '"': + c[iDst] = '"'; + break; + case '?': + c[iDst] = '?'; + break; + case '$': + c[iDst] = '$'; + break; + case '\\': + c[iDst] = '\\'; + break; + case 'x': + if( (*iSrc)+2 >= len + || !isxdigit(c[(*iSrc)+1]) + || !isxdigit(c[(*iSrc)+2])) { + /* error, incomplete escape, use as is */ + c[iDst] = '\\'; + --(*iSrc); + } + c[iDst] = (hexDigitVal(c[(*iSrc)+1]) << 4) + + hexDigitVal(c[(*iSrc)+2]); + *iSrc += 2; + break; + case '0': /* octal escape */ + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + if( (*iSrc)+2 >= len + || !isodigit(c[(*iSrc)+1]) + || !isodigit(c[(*iSrc)+2])) { + /* error, incomplete escape, use as is */ + c[iDst] = '\\'; + --(*iSrc); + } + c[iDst] = ((c[(*iSrc) ] - '0') << 6) + + ((c[(*iSrc)+1] - '0') << 3) + + ( c[(*iSrc)+2] - '0'); + *iSrc += 2; + break; + default: + /* error, incomplete escape, indicate by '?' */ + c[iDst] = '?'; + break; + } + } else { + /* regular character */ + c[iDst] = c[*iSrc]; + } +} + +void +unescapeStr(uchar *s, int len) +{ + int iSrc, iDst; + assert(s != NULL); + + /* scan for first escape sequence (if we are luky, there is none!) */ + iSrc = 0; + while(iSrc < len && s[iSrc] != '\\') + ++iSrc; + /* now we have a sequence or end of string. In any case, we process + * all remaining characters (maybe 0!) and unescape. + */ + if(iSrc != len) { + iDst = iSrc; + while(iSrc < len) { + doUnescape(s, len, &iSrc, iDst); + ++iSrc; + ++iDst; + } + } + s[iDst] = '\0'; +} -- cgit v1.2.3 From 11910c59138332a884ed753401afdd84feeb1832 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 13 Sep 2012 11:37:58 +0200 Subject: Fixing string unescaping (new code from this morning's commit) --- grammar/rainerscript.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index de63f692..e458187c 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1752,6 +1752,6 @@ unescapeStr(uchar *s, int len) ++iSrc; ++iDst; } + s[iDst] = '\0'; } - s[iDst] = '\0'; } -- cgit v1.2.3 From e162d378c717e0cc1157aa06d99af69e51fdc20e Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 13 Sep 2012 15:26:22 +0200 Subject: Add set/unset stmt to grammar & AST ... but not yet to executing engine --- grammar/rainerscript.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index b0a79458..c7344628 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1466,6 +1466,16 @@ cnfstmtPrint(struct cnfstmt *root, int indent) } doIndent(indent); dbgprintf("END IF\n"); break; + case S_SET: + doIndent(indent); dbgprintf("SET %s =\n", + stmt->d.s_set.varname); + cnfexprPrint(stmt->d.s_set.expr, indent+1); + doIndent(indent); dbgprintf("END SET\n"); + break; + case S_UNSET: + doIndent(indent); dbgprintf("UNSET %s\n", + stmt->d.s_unset.varname); + break; case S_PRIFILT: doIndent(indent); dbgprintf("PRIFILT '%s'\n", stmt->printable); cnfstmtPrint(stmt->d.s_prifilt.t_then, indent+1); @@ -1569,6 +1579,13 @@ cnfstmtDestruct(struct cnfstmt *root) cnfstmtDestruct(stmt->d.s_if.t_else); } break; + case S_SET: + free(stmt->d.s_set.varname); + cnfexprDestruct(stmt->d.s_set.expr); + break; + case S_UNSET: + free(stmt->d.s_set.varname); + break; case S_PRIFILT: cnfstmtDestruct(stmt->d.s_prifilt.t_then); break; @@ -1593,6 +1610,27 @@ cnfstmtDestruct(struct cnfstmt *root) } } +struct cnfstmt * +cnfstmtNewSet(char *var, struct cnfexpr *expr) +{ + struct cnfstmt* cnfstmt; + if((cnfstmt = cnfstmtNew(S_SET)) != NULL) { + cnfstmt->d.s_set.varname = (uchar*) var; + cnfstmt->d.s_set.expr = expr; + } + return cnfstmt; +} + +struct cnfstmt * +cnfstmtNewUnset(char *var) +{ + struct cnfstmt* cnfstmt; + if((cnfstmt = cnfstmtNew(S_UNSET)) != NULL) { + cnfstmt->d.s_unset.varname = (uchar*) var; + } + return cnfstmt; +} + struct cnfstmt * cnfstmtNewPRIFILT(char *prifilt, struct cnfstmt *t_then) { -- cgit v1.2.3 From 0a331d59cabba8294bb755597d664b8e2bd780bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Mon, 3 Sep 2012 19:22:18 +0200 Subject: Free configuration objects after use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Miloslav Trmač --- grammar/rainerscript.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index f4896da8..5e6e492d 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -139,7 +139,7 @@ objlstDestruct(struct objlst *lst) while(lst != NULL) { toDel = lst; lst = lst->next; - // TODO: delete object + cnfobjDestruct(toDel->obj); free(toDel); } } @@ -648,6 +648,7 @@ cnfobjDestruct(struct cnfobj *o) { if(o != NULL) { nvlstDestruct(o->nvlst); + objlstDestruct(o->subobjs); free(o); } } -- cgit v1.2.3 From 447f0e6421f2576d57623a398f90b8dd2eb8becf Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 17 Sep 2012 16:23:15 +0200 Subject: new ruleengine: implement script concatenation (& operator) --- grammar/rainerscript.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index c7344628..05d489a3 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1189,6 +1189,14 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) ret->datatype = 'S'; ret->d.estr = cnfGetVar(((struct cnfvar*)expr)->name, usrptr); break; + case '&': + /* TODO: think about optimization, should be possible ;) */ + PREP_TWO_STRINGS; + ret->datatype = 'S'; + ret->d.estr = es_strdup(estr_l); + es_addStr(&ret->d.estr, estr_r); + FREE_TWO_STRINGS; + break; case '+': COMP_NUM_BINOP(+); break; @@ -1263,6 +1271,7 @@ cnfexprDestruct(struct cnfexpr *expr) case CMP_CONTAINSI: case OR: case AND: + case '&': case '+': case '-': case '*': -- cgit v1.2.3 From 66929c7c1b37719b94d11a56b44fcfb23052237c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 18 Sep 2012 12:58:33 +0200 Subject: new ruleengine: implement native JSON in RainerScript --- grammar/rainerscript.c | 54 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 8 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 05d489a3..e7299e62 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -738,12 +738,14 @@ done: * try to convert it to one. The semantics from es_str2num() * are used (bSuccess tells if the conversion went well or not). */ -static inline long long +static long long var2Number(struct var *r, int *bSuccess) { long long n; if(r->datatype == 'S') { n = es_str2num(r->d.estr, bSuccess); + } else if(r->datatype == 'J') { + n = (r->d.json == NULL) ? 0 : json_object_get_int(r->d.json); } else { n = r->d.n; if(bSuccess) @@ -757,12 +759,27 @@ var2Number(struct var *r, int *bSuccess) static inline es_str_t * var2String(struct var *r, int *bMustFree) { + es_str_t *estr; + char *cstr; + rs_size_t lenstr; if(r->datatype == 'N') { *bMustFree = 1; - return es_newStrFromNumber(r->d.n); + estr = es_newStrFromNumber(r->d.n); + } else if(r->datatype == 'J') { + *bMustFree = 1; + if(r->d.json == NULL) { + cstr = "", + lenstr = 0; + } else { + cstr = (char*)json_object_get_string(r->d.json); + lenstr = strlen(cstr); + } + estr = es_newStrFromCStr(cstr, lenstr); + } else { + *bMustFree = 0; + estr = r->d.estr; } - *bMustFree = 0; - return r->d.estr; + return estr; } /* Perform a function call. This has been moved out of cnfExprEval in order @@ -873,6 +890,27 @@ doFuncCall(struct cnffunc *func, struct var *ret, void* usrptr) } } +static inline void +evalVar(struct cnfvar *var, void *usrptr, struct var *ret) +{ + rsRetVal localRet; + es_str_t *estr; + struct json_object *json; + + if(var->name[0] == '$' && var->name[1] == '!') { + /* TODO: unify string libs */ + estr = es_newStrFromBuf(var->name+1, strlen(var->name)-1); + localRet = msgGetCEEPropJSON((msg_t*)usrptr, estr, &json); + es_deleteStr(estr); + ret->datatype = 'J'; + ret->d.json = (localRet == RS_RET_OK) ? json : NULL; + } else { + ret->datatype = 'S'; + ret->d.estr = cnfGetVar(var->name, usrptr); + } + +} + #define FREE_BOTH_RET \ if(r.datatype == 'S') es_deleteStr(r.d.estr); \ if(l.datatype == 'S') es_deleteStr(l.d.estr) @@ -1186,8 +1224,7 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) ret->d.estr = es_strdup(((struct cnfstringval*)expr)->estr); break; case 'V': - ret->datatype = 'S'; - ret->d.estr = cnfGetVar(((struct cnfvar*)expr)->name, usrptr); + evalVar((struct cnfvar*)expr, usrptr, ret); break; case '&': /* TODO: think about optimization, should be possible ;) */ @@ -1430,6 +1467,7 @@ cnfexprPrint(struct cnfexpr *expr, int indent) cnfexprPrint(func->expr[i], indent+1); } break; + case '&': case '+': case '-': case '*': @@ -1443,8 +1481,8 @@ cnfexprPrint(struct cnfexpr *expr, int indent) cnfexprPrint(expr->r, indent+1); break; default: - dbgprintf("error: unknown nodetype %u\n", - (unsigned) expr->nodetype); + dbgprintf("error: unknown nodetype %u['%c']\n", + (unsigned) expr->nodetype, (char) expr->nodetype); break; } } -- cgit v1.2.3 From a5dcf8cdb7db791d3f43e8cc4f793380739807c8 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 20 Sep 2012 11:26:24 +0200 Subject: Implement RainerScript field() function --- grammar/rainerscript.c | 112 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 105 insertions(+), 7 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index e7299e62..9eeda64e 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -744,11 +744,13 @@ var2Number(struct var *r, int *bSuccess) long long n; if(r->datatype == 'S') { n = es_str2num(r->d.estr, bSuccess); - } else if(r->datatype == 'J') { - n = (r->d.json == NULL) ? 0 : json_object_get_int(r->d.json); } else { - n = r->d.n; - if(bSuccess) + if(r->datatype == 'J') { + n = (r->d.json == NULL) ? 0 : json_object_get_int(r->d.json); + } else { + n = r->d.n; + } + if(bSuccess != NULL) *bSuccess = 1; } return n; @@ -782,6 +784,67 @@ var2String(struct var *r, int *bMustFree) return estr; } +static uchar* +var2CString(struct var *r, int *bMustFree) +{ + uchar *cstr; + es_str_t *estr; + estr = var2String(r, bMustFree); + cstr = (uchar*) es_str2cstr(estr, NULL); + if(*bMustFree) + es_deleteStr(estr); + *bMustFree = 1; + return cstr; +} + +rsRetVal +doExtractField(uchar *str, uchar delim, int matchnbr, uchar **resstr) +{ + int iCurrFld; + int iLen; + uchar *pBuf; + uchar *pFld; + uchar *pFldEnd; + DEFiRet; + + /* first, skip to the field in question */ + iCurrFld = 1; + pFld = str; + while(*pFld && iCurrFld < matchnbr) { + /* skip fields until the requested field or end of string is found */ + while(*pFld && (uchar) *pFld != delim) + ++pFld; /* skip to field terminator */ + if(*pFld == delim) { + ++pFld; /* eat it */ + ++iCurrFld; + } + } + dbgprintf("field() field requested %d, field found %d\n", matchnbr, iCurrFld); + + if(iCurrFld == matchnbr) { + /* field found, now extract it */ + /* first of all, we need to find the end */ + pFldEnd = pFld; + while(*pFldEnd && *pFldEnd != delim) + ++pFldEnd; + --pFldEnd; /* we are already at the delimiter - so we need to + * step back a little not to copy it as part of the field. */ + /* we got our end pointer, now do the copy */ + iLen = pFldEnd - pFld + 1; /* the +1 is for an actual char, NOT \0! */ + CHKmalloc(pBuf = MALLOC((iLen + 1) * sizeof(char))); + /* now copy */ + memcpy(pBuf, pFld, iLen); + pBuf[iLen] = '\0'; /* terminate it */ + if(*(pFldEnd+1) != '\0') + ++pFldEnd; /* OK, skip again over delimiter char */ + *resstr = pBuf; + } else { + ABORT_FINALIZE(RS_RET_FIELD_NOT_FOUND); + } +finalize_it: + RETiRet; +} + /* Perform a function call. This has been moved out of cnfExprEval in order * to keep the code small and easier to maintain. */ @@ -793,8 +856,12 @@ doFuncCall(struct cnffunc *func, struct var *ret, void* usrptr) int bMustFree; es_str_t *estr; char *str; + uchar *resStr; int retval; struct var r[CNFFUNC_MAX_ARGS]; + int delim; + int matchnbr; + rsRetVal localRet; dbgprintf("rainerscript: executing function id %d\n", func->fID); switch(func->fID) { @@ -862,8 +929,7 @@ doFuncCall(struct cnffunc *func, struct var *ret, void* usrptr) break; case CNFFUNC_RE_MATCH: cnfexprEval(func->expr[0], &r[0], usrptr); - estr = var2String(&r[0], &bMustFree); - str = es_str2cstr(estr, NULL); + str = (char*) var2CString(&r[0], &bMustFree); retval = regexp.regexec(func->funcdata, str, 0, NULL, 0); if(retval == 0) ret->d.n = 1; @@ -874,10 +940,35 @@ doFuncCall(struct cnffunc *func, struct var *ret, void* usrptr) } } ret->datatype = 'N'; - if(bMustFree) es_deleteStr(estr); + if(bMustFree) free(str); free(str); if(r[0].datatype == 'S') es_deleteStr(r[0].d.estr); break; + case CNFFUNC_FIELD: + cnfexprEval(func->expr[0], &r[0], usrptr); + cnfexprEval(func->expr[1], &r[1], usrptr); + cnfexprEval(func->expr[2], &r[2], usrptr); + str = (char*) var2CString(&r[0], &bMustFree); + delim = var2Number(&r[1], NULL); + matchnbr = var2Number(&r[2], NULL); + localRet = doExtractField((uchar*)str, (char) delim, matchnbr, &resStr); +dbgprintf("RRRR: field() returns %d, str: '%s'\n", localRet, resStr); + if(localRet == RS_RET_OK) { + ret->d.estr = es_newStrFromCStr((char*)resStr, strlen((char*)resStr)); + free(resStr); + } else if(localRet == RS_RET_OK) { + ret->d.estr = es_newStrFromCStr("***FIELD NOT FOUND***", + sizeof("***FIELD NOT FOUND***")-1); + } else { + ret->d.estr = es_newStrFromCStr("***ERROR in field() FUNCTION***", + sizeof("***ERROR in field() FUNCTION***")-1); + } + ret->datatype = 'S'; + if(bMustFree) free(str); + if(r[0].datatype == 'S') es_deleteStr(r[0].d.estr); + if(r[1].datatype == 'S') es_deleteStr(r[1].d.estr); + if(r[2].datatype == 'S') es_deleteStr(r[2].d.estr); + break; default: if(Debug) { fname = es_str2cstr(func->fname, NULL); @@ -1805,6 +1896,13 @@ funcName2ID(es_str_t *fname, unsigned short nParams) return CNFFUNC_INVALID; } return CNFFUNC_RE_MATCH; + } else if(!es_strbufcmp(fname, (unsigned char*)"field", sizeof("field") - 1)) { + if(nParams != 3) { + parser_errmsg("number of parameters for field() must be three " + "but is %d.", nParams); + return CNFFUNC_INVALID; + } + return CNFFUNC_FIELD; } else { return CNFFUNC_INVALID; } -- cgit v1.2.3 From 24a248d021c9d2c19b71eef26d3ddf8731e4541b Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 20 Sep 2012 15:08:39 +0200 Subject: Implement RainerScript prifield() function --- grammar/rainerscript.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 2 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 9eeda64e..558ec78f 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -861,6 +861,7 @@ doFuncCall(struct cnffunc *func, struct var *ret, void* usrptr) struct var r[CNFFUNC_MAX_ARGS]; int delim; int matchnbr; + struct funcData_prifilt *pPrifilt; rsRetVal localRet; dbgprintf("rainerscript: executing function id %d\n", func->fID); @@ -952,7 +953,6 @@ doFuncCall(struct cnffunc *func, struct var *ret, void* usrptr) delim = var2Number(&r[1], NULL); matchnbr = var2Number(&r[2], NULL); localRet = doExtractField((uchar*)str, (char) delim, matchnbr, &resStr); -dbgprintf("RRRR: field() returns %d, str: '%s'\n", localRet, resStr); if(localRet == RS_RET_OK) { ret->d.estr = es_newStrFromCStr((char*)resStr, strlen((char*)resStr)); free(resStr); @@ -969,6 +969,16 @@ dbgprintf("RRRR: field() returns %d, str: '%s'\n", localRet, resStr); if(r[1].datatype == 'S') es_deleteStr(r[1].d.estr); if(r[2].datatype == 'S') es_deleteStr(r[2].d.estr); break; + case CNFFUNC_PRIFILT: + pPrifilt = (struct funcData_prifilt*) func->funcdata; + if( (pPrifilt->pmask[((msg_t*)usrptr)->iFacility] == TABLE_NOPRI) || + ((pPrifilt->pmask[((msg_t*)usrptr)->iFacility] + & (1<<((msg_t*)usrptr)->iSeverity)) == 0) ) + ret->d.n = 0; + else + ret->d.n = 1; + ret->datatype = 'N'; + break; default: if(Debug) { fname = es_str2cstr(func->fname, NULL); @@ -1371,10 +1381,14 @@ cnffuncDestruct(struct cnffunc *func) /* some functions require special destruction */ switch(func->fID) { case CNFFUNC_RE_MATCH: - regexp.regfree(func->funcdata); + if(func->funcdata != NULL) + regexp.regfree(func->funcdata); free(func->funcdata); free(func->fname); break; + case CNFFUNC_PRIFILT: + free(func->funcdata); + break; default:break; } } @@ -1554,6 +1568,18 @@ cnfexprPrint(struct cnfexpr *expr, int indent) func = (struct cnffunc*) expr; cstrPrint("function '", func->fname); dbgprintf("' (id:%d, params:%hu)\n", func->fID, func->nParams); + if(func->fID == CNFFUNC_PRIFILT) { + struct funcData_prifilt *pD; + pD = (struct funcData_prifilt*) func->funcdata; + doIndent(indent+1); + dbgprintf("pmask: "); + for (i = 0; i <= LOG_NFACILITIES; i++) + if (pD->pmask[i] == TABLE_NOPRI) + dbgprintf(" X "); + else + dbgprintf("%2X ", pD->pmask[i]); + dbgprintf("\n"); + } for(i = 0 ; i < func->nParams ; ++i) { cnfexprPrint(func->expr[i], indent+1); } @@ -1903,6 +1929,13 @@ funcName2ID(es_str_t *fname, unsigned short nParams) return CNFFUNC_INVALID; } return CNFFUNC_FIELD; + } else if(!es_strbufcmp(fname, (unsigned char*)"prifilt", sizeof("prifilt") - 1)) { + if(nParams != 1) { + parser_errmsg("number of parameters for prifilt() must be one " + "but is %d.", nParams); + return CNFFUNC_INVALID; + } + return CNFFUNC_PRIFILT; } else { return CNFFUNC_INVALID; } @@ -1943,6 +1976,29 @@ finalize_it: RETiRet; } + +static inline rsRetVal +initFunc_prifilt(struct cnffunc *func) +{ + struct funcData_prifilt *pData; + uchar *cstr; + DEFiRet; + + func->funcdata = NULL; + if(func->expr[0]->nodetype != 'S') { + parser_errmsg("param 1 of prifilt() must be a constant string"); + FINALIZE; + } + + CHKmalloc(pData = calloc(1, sizeof(struct funcData_prifilt))); + func->funcdata = pData; + cstr = (uchar*)es_str2cstr(((struct cnfstringval*) func->expr[0])->estr, NULL); + CHKiRet(DecodePRIFilter(cstr, pData->pmask)); + free(cstr); +finalize_it: + RETiRet; +} + struct cnffunc * cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) { @@ -1975,6 +2031,9 @@ cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) /* need to compile the regexp in param 2, so this MUST be a constant */ initFunc_re_match(func); break; + case CNFFUNC_PRIFILT: + initFunc_prifilt(func); + break; default:break; } } -- cgit v1.2.3 From 7351fcc0e2635bf29c556b189190507c8c5202c9 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 20 Sep 2012 16:11:22 +0200 Subject: Add skeleton for RainerScript optimizer actual optimization is not yet done --- grammar/rainerscript.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 558ec78f..d0a97f06 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1862,6 +1862,89 @@ cnfstmtNewLegaAct(char *actline) done: return cnfstmt; } + +/* (recursively) optimize an expression */ +void +cnfexprOptimize(struct cnfexpr *expr) +{ + struct var r, l; /* memory for subexpression results */ + es_str_t *estr_r, *estr_l; + int convok_r, convok_l; + int bMustFree, bMustFree2; + long long n_r, n_l; + + dbgprintf("optimize expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); + switch(expr->nodetype) { + case '&': + break; + case '+': + break; + case '-': + break; + case '*': + break; + case '/': + break; + case '%': + break; + default:DBGPRINTF("expr optimizer error: unknown nodetype %u['%c']\n", + (unsigned) expr->nodetype, (char) expr->nodetype); + break; + } + +} + +/* (recursively) optimize a statement */ +void +cnfstmtOptimize(struct cnfstmt *root) +{ + struct cnfstmt *stmt, *prevstmt; + + prevstmt = NULL; + for(stmt = root ; stmt != NULL ; stmt = stmt->next) { +dbgprintf("RRRR: stmtOptimize: stmt %p, nodetype %u\n", stmt, stmt->nodetype); + switch(stmt->nodetype) { + case S_NOP: + /* unchain NOPs, first NOP remains (TODO?) */ + if(prevstmt != NULL) { + DBGPRINTF("removing NOP\n"); + prevstmt->next = stmt->next; +#warning remove memleak, destruct + } + break; + case S_IF: + cnfexprOptimize(stmt->d.s_if.expr); + if(stmt->d.s_if.t_then != NULL) { + cnfstmtOptimize(stmt->d.s_if.t_then); + } + if(stmt->d.s_if.t_else != NULL) { + cnfstmtOptimize(stmt->d.s_if.t_else); + } + break; + case S_PRIFILT: + cnfstmtOptimize(stmt->d.s_prifilt.t_then); + break; + case S_PROPFILT: + cnfstmtOptimize(stmt->d.s_propfilt.t_then); + break; + case S_SET: + cnfexprOptimize(stmt->d.s_set.expr); + break; + case S_STOP: + case S_UNSET: + case S_ACT: + /* nothing to do */ + break; + default: + dbgprintf("error: unknown stmt type %u during optimizer run\n", + (unsigned) stmt->nodetype); + break; + } + prevstmt = stmt; + } +} + + struct cnffparamlst * cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next) { -- cgit v1.2.3 From b16637ed74abee89d69e1e1cf0d7d9c9898e861e Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 21 Sep 2012 08:36:28 +0200 Subject: Implement script optimizer basic constant folding & NOP removal --- grammar/rainerscript.c | 195 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 164 insertions(+), 31 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index d0a97f06..5db62abc 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -49,6 +49,8 @@ DEFobjCurrIf(obj) DEFobjCurrIf(regexp) +void cnfexprOptimize(struct cnfexpr *expr); + char* getFIOPName(unsigned iFIOP) { @@ -168,16 +170,13 @@ struct cnfstmt* scriptAddStmt(struct cnfstmt *root, struct cnfstmt *s) { struct cnfstmt *l; -dbgprintf("RRRR: scriptAddStmt(%p, %p): ", root, s); if(root == NULL) { root = s; -dbgprintf("root set to %p\n", s); } else { /* find last, linear search ok, as only during config phase */ for(l = root ; l->next != NULL ; l = l->next) ; l->next = s; -dbgprintf("%p->next = %p\n", l, s); } return root; } @@ -1819,7 +1818,6 @@ cnfstmtNewPROPFILT(char *propfilt, struct cnfstmt *t_then) cnfstmt->d.s_propfilt.regex_cache = NULL; cnfstmt->d.s_propfilt.pCSCompValue = NULL; lRet = DecodePropFilter((uchar*)propfilt, cnfstmt); -dbgprintf("AAAA: DecodePropFilter returns %d\n", lRet); } return cnfstmt; } @@ -1863,68 +1861,201 @@ done: return cnfstmt; } +/* returns 1 if the two expressions are constants, 0 otherwise + * if both are constants, the expression subtrees are destructed + * (this is an aid for constant folding optimizing) + */ +static int +getConstNumber(struct cnfexpr *expr, long long *l, long long *r) +{ + int ret = 0; + cnfexprOptimize(expr->l); + cnfexprOptimize(expr->r); + if(expr->l->nodetype == 'N') { + if(expr->r->nodetype == 'N') { + ret = 1; + *l = ((struct cnfnumval*)expr->l)->val; + *r = ((struct cnfnumval*)expr->r)->val; + cnfexprDestruct(expr->l); + cnfexprDestruct(expr->r); + } else if(expr->r->nodetype == 'S') { + ret = 1; + *l = ((struct cnfnumval*)expr->l)->val; + *r = es_str2num(((struct cnfstringval*)expr->r)->estr, NULL); + cnfexprDestruct(expr->l); + cnfexprDestruct(expr->r); + } + } else if(expr->l->nodetype == 'S') { + if(expr->r->nodetype == 'N') { + ret = 1; + *l = es_str2num(((struct cnfstringval*)expr->l)->estr, NULL); + *r = ((struct cnfnumval*)expr->r)->val; + cnfexprDestruct(expr->l); + cnfexprDestruct(expr->r); + } else if(expr->r->nodetype == 'S') { + ret = 1; + *l = es_str2num(((struct cnfstringval*)expr->l)->estr, NULL); + *r = es_str2num(((struct cnfstringval*)expr->r)->estr, NULL); + cnfexprDestruct(expr->l); + cnfexprDestruct(expr->r); + } + } + return ret; +} + + +/* constant folding for string concatenation */ +static inline void +constFoldConcat(struct cnfexpr *expr) +{ + es_str_t *estr; + cnfexprOptimize(expr->l); + cnfexprOptimize(expr->r); + if(expr->l->nodetype == 'S') { + if(expr->r->nodetype == 'S') { + estr = ((struct cnfstringval*)expr->l)->estr; + ((struct cnfstringval*)expr->l)->estr = NULL; + es_addStr(&estr, ((struct cnfstringval*)expr->r)->estr); + cnfexprDestruct(expr->l); + cnfexprDestruct(expr->r); + expr->nodetype = 'S'; + ((struct cnfstringval*)expr)->estr = estr; + } else if(expr->r->nodetype == 'N') { + es_str_t *numstr; + estr = ((struct cnfstringval*)expr->l)->estr; + ((struct cnfstringval*)expr->l)->estr = NULL; + numstr = es_newStrFromNumber(((struct cnfnumval*)expr->r)->val); + es_addStr(&estr, numstr); + es_deleteStr(numstr); + cnfexprDestruct(expr->l); + cnfexprDestruct(expr->r); + expr->nodetype = 'S'; + ((struct cnfstringval*)expr)->estr = estr; + } + } else if(expr->l->nodetype == 'N') { + if(expr->r->nodetype == 'S') { + estr = es_newStrFromNumber(((struct cnfnumval*)expr->l)->val); + es_addStr(&estr, ((struct cnfstringval*)expr->r)->estr); + cnfexprDestruct(expr->l); + cnfexprDestruct(expr->r); + expr->nodetype = 'S'; + ((struct cnfstringval*)expr)->estr = estr; + } else if(expr->r->nodetype == 'S') { + es_str_t *numstr; + estr = es_newStrFromNumber(((struct cnfnumval*)expr->l)->val); + numstr = es_newStrFromNumber(((struct cnfnumval*)expr->r)->val); + es_addStr(&estr, numstr); + es_deleteStr(numstr); + cnfexprDestruct(expr->l); + cnfexprDestruct(expr->r); + expr->nodetype = 'S'; + ((struct cnfstringval*)expr)->estr = estr; + } + } +} + + /* (recursively) optimize an expression */ void cnfexprOptimize(struct cnfexpr *expr) { - struct var r, l; /* memory for subexpression results */ - es_str_t *estr_r, *estr_l; - int convok_r, convok_l; - int bMustFree, bMustFree2; - long long n_r, n_l; + long long ln, rn; dbgprintf("optimize expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); switch(expr->nodetype) { case '&': + constFoldConcat(expr); break; case '+': + if(getConstNumber(expr, &ln, &rn)) { + expr->nodetype = 'N'; + ((struct cnfnumval*)expr)->val = ln + rn; + } break; case '-': + if(getConstNumber(expr, &ln, &rn)) { + expr->nodetype = 'N'; + ((struct cnfnumval*)expr)->val = ln - rn; + } break; case '*': + if(getConstNumber(expr, &ln, &rn)) { + expr->nodetype = 'N'; + ((struct cnfnumval*)expr)->val = ln * rn; + } break; case '/': + if(getConstNumber(expr, &ln, &rn)) { + expr->nodetype = 'N'; + ((struct cnfnumval*)expr)->val = ln / rn; + } break; case '%': + if(getConstNumber(expr, &ln, &rn)) { + expr->nodetype = 'N'; + ((struct cnfnumval*)expr)->val = ln % rn; + } break; - default:DBGPRINTF("expr optimizer error: unknown nodetype %u['%c']\n", - (unsigned) expr->nodetype, (char) expr->nodetype); + default:/* nodetype we cannot optimize */ break; } } +/* removes NOPs from a statement list and returns the + * first non-NOP entry. + */ +static inline struct cnfstmt * +removeNOPs(struct cnfstmt *root) +{ + struct cnfstmt *stmt, *toDel, *prevstmt = NULL; + struct cnfstmt *newRoot = NULL; + + if(root == NULL) goto done; + stmt = root; + while(stmt != NULL) { +dbgprintf("RRRR: removeNOPs: stmt %p, nodetype %u\n", stmt, stmt->nodetype); + if(stmt->nodetype == S_NOP) { + if(prevstmt != NULL) + /* end chain, is rebuild if more non-NOPs follow */ + prevstmt->next = NULL; + toDel = stmt; + stmt = stmt->next; + cnfstmtDestruct(toDel); + } else { + if(newRoot == NULL) + newRoot = stmt; + if(prevstmt != NULL) + prevstmt->next = stmt; + prevstmt = stmt; + stmt = stmt->next; + } + } +done: return newRoot; +} + /* (recursively) optimize a statement */ void cnfstmtOptimize(struct cnfstmt *root) { - struct cnfstmt *stmt, *prevstmt; - - prevstmt = NULL; + struct cnfstmt *stmt; + if(root == NULL) goto done; for(stmt = root ; stmt != NULL ; stmt = stmt->next) { dbgprintf("RRRR: stmtOptimize: stmt %p, nodetype %u\n", stmt, stmt->nodetype); switch(stmt->nodetype) { - case S_NOP: - /* unchain NOPs, first NOP remains (TODO?) */ - if(prevstmt != NULL) { - DBGPRINTF("removing NOP\n"); - prevstmt->next = stmt->next; -#warning remove memleak, destruct - } - break; case S_IF: cnfexprOptimize(stmt->d.s_if.expr); - if(stmt->d.s_if.t_then != NULL) { - cnfstmtOptimize(stmt->d.s_if.t_then); - } - if(stmt->d.s_if.t_else != NULL) { - cnfstmtOptimize(stmt->d.s_if.t_else); - } + stmt->d.s_if.t_then = removeNOPs(stmt->d.s_if.t_then); + stmt->d.s_if.t_else = removeNOPs(stmt->d.s_if.t_else); + cnfstmtOptimize(stmt->d.s_if.t_then); + cnfstmtOptimize(stmt->d.s_if.t_else); break; case S_PRIFILT: + stmt->d.s_prifilt.t_then = removeNOPs(stmt->d.s_prifilt.t_then); cnfstmtOptimize(stmt->d.s_prifilt.t_then); break; case S_PROPFILT: + stmt->d.s_propfilt.t_then = removeNOPs(stmt->d.s_propfilt.t_then); cnfstmtOptimize(stmt->d.s_propfilt.t_then); break; case S_SET: @@ -1932,16 +2063,18 @@ dbgprintf("RRRR: stmtOptimize: stmt %p, nodetype %u\n", stmt, stmt->nodetype); break; case S_STOP: case S_UNSET: - case S_ACT: - /* nothing to do */ + case S_ACT: /* nothing to do */ + break; + case S_NOP: + DBGPRINTF("optimizer error: we see a NOP, how come?\n"); break; default: dbgprintf("error: unknown stmt type %u during optimizer run\n", (unsigned) stmt->nodetype); break; } - prevstmt = stmt; } +done: /*EMPTY*/; } -- cgit v1.2.3 From 87f415f16fec001a4f87e18817bace73f19d6416 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 21 Sep 2012 10:41:05 +0200 Subject: Implement script optimization IF -> PRIFILT --- grammar/rainerscript.c | 82 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 63 insertions(+), 19 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 5db62abc..9440dd2f 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1382,14 +1382,11 @@ cnffuncDestruct(struct cnffunc *func) case CNFFUNC_RE_MATCH: if(func->funcdata != NULL) regexp.regfree(func->funcdata); - free(func->funcdata); - free(func->fname); - break; - case CNFFUNC_PRIFILT: - free(func->funcdata); break; default:break; } + free(func->funcdata); + free(func->fname); } /* Destruct an expression and all sub-expressions contained in it. @@ -1464,6 +1461,22 @@ doIndent(int indent) for(i = 0 ; i < indent ; ++i) dbgprintf(" "); } + +static void +pmaskPrint(uchar *pmask, int indent) +{ + int i; + doIndent(indent); + dbgprintf("pmask: "); + for (i = 0; i <= LOG_NFACILITIES; i++) + if (pmask[i] == TABLE_NOPRI) + dbgprintf(" X "); + else + dbgprintf("%2X ", pmask[i]); + dbgprintf("\n"); +} + + void cnfexprPrint(struct cnfexpr *expr, int indent) { @@ -1570,14 +1583,7 @@ cnfexprPrint(struct cnfexpr *expr, int indent) if(func->fID == CNFFUNC_PRIFILT) { struct funcData_prifilt *pD; pD = (struct funcData_prifilt*) func->funcdata; - doIndent(indent+1); - dbgprintf("pmask: "); - for (i = 0; i <= LOG_NFACILITIES; i++) - if (pD->pmask[i] == TABLE_NOPRI) - dbgprintf(" X "); - else - dbgprintf("%2X ", pD->pmask[i]); - dbgprintf("\n"); + pmaskPrint(pD->pmask, indent+1); } for(i = 0 ; i < func->nParams ; ++i) { cnfexprPrint(func->expr[i], indent+1); @@ -1641,7 +1647,12 @@ cnfstmtPrint(struct cnfstmt *root, int indent) break; case S_PRIFILT: doIndent(indent); dbgprintf("PRIFILT '%s'\n", stmt->printable); + pmaskPrint(stmt->d.s_prifilt.pmask, indent); cnfstmtPrint(stmt->d.s_prifilt.t_then, indent+1); + if(stmt->d.s_prifilt.t_else != NULL) { + doIndent(indent); dbgprintf("ELSE\n"); + cnfstmtPrint(stmt->d.s_prifilt.t_else, indent+1); + } doIndent(indent); dbgprintf("END PRIFILT\n"); break; case S_PROPFILT: @@ -1751,6 +1762,7 @@ cnfstmtDestruct(struct cnfstmt *root) break; case S_PRIFILT: cnfstmtDestruct(stmt->d.s_prifilt.t_then); + cnfstmtDestruct(stmt->d.s_prifilt.t_else); break; case S_PROPFILT: if(stmt->d.s_propfilt.propName != NULL) @@ -1801,6 +1813,7 @@ cnfstmtNewPRIFILT(char *prifilt, struct cnfstmt *t_then) if((cnfstmt = cnfstmtNew(S_PRIFILT)) != NULL) { cnfstmt->printable = (uchar*)prifilt; cnfstmt->d.s_prifilt.t_then = t_then; + cnfstmt->d.s_prifilt.t_else = NULL; DecodePRIFilter((uchar*)prifilt, cnfstmt->d.s_prifilt.pmask); } return cnfstmt; @@ -2014,7 +2027,6 @@ removeNOPs(struct cnfstmt *root) if(root == NULL) goto done; stmt = root; while(stmt != NULL) { -dbgprintf("RRRR: removeNOPs: stmt %p, nodetype %u\n", stmt, stmt->nodetype); if(stmt->nodetype == S_NOP) { if(prevstmt != NULL) /* end chain, is rebuild if more non-NOPs follow */ @@ -2034,6 +2046,41 @@ dbgprintf("RRRR: removeNOPs: stmt %p, nodetype %u\n", stmt, stmt->nodetype); done: return newRoot; } + +static inline void +cnfstmtOptimizeIf(struct cnfstmt *stmt) +{ + struct cnfstmt *t_then, *t_else; + struct cnfexpr *expr; + struct cnffunc *func; + struct funcData_prifilt *prifilt; + + expr = stmt->d.s_if.expr; + cnfexprOptimize(expr); + stmt->d.s_if.t_then = removeNOPs(stmt->d.s_if.t_then); + stmt->d.s_if.t_else = removeNOPs(stmt->d.s_if.t_else); + cnfstmtOptimize(stmt->d.s_if.t_then); + cnfstmtOptimize(stmt->d.s_if.t_else); + + if(stmt->d.s_if.expr->nodetype == 'F') { + func = (struct cnffunc*)expr; + if(func->fID == CNFFUNC_PRIFILT) { + DBGPRINTF("optimize IF to PRIFILT\n"); + t_then = stmt->d.s_if.t_then; + t_else = stmt->d.s_if.t_else; + stmt->nodetype = S_PRIFILT; + prifilt = (struct funcData_prifilt*) func->funcdata; + memcpy(stmt->d.s_prifilt.pmask, prifilt->pmask, + sizeof(prifilt->pmask)); + stmt->d.s_prifilt.t_then = t_then; + stmt->d.s_prifilt.t_else = t_else; + stmt->printable = (uchar*) + es_str2cstr(((struct cnfstringval*)func->expr[0])->estr, NULL); + cnfexprDestruct(expr); + } + } +} + /* (recursively) optimize a statement */ void cnfstmtOptimize(struct cnfstmt *root) @@ -2044,11 +2091,7 @@ cnfstmtOptimize(struct cnfstmt *root) dbgprintf("RRRR: stmtOptimize: stmt %p, nodetype %u\n", stmt, stmt->nodetype); switch(stmt->nodetype) { case S_IF: - cnfexprOptimize(stmt->d.s_if.expr); - stmt->d.s_if.t_then = removeNOPs(stmt->d.s_if.t_then); - stmt->d.s_if.t_else = removeNOPs(stmt->d.s_if.t_else); - cnfstmtOptimize(stmt->d.s_if.t_then); - cnfstmtOptimize(stmt->d.s_if.t_else); + cnfstmtOptimizeIf(stmt); break; case S_PRIFILT: stmt->d.s_prifilt.t_then = removeNOPs(stmt->d.s_prifilt.t_then); @@ -2232,6 +2275,7 @@ cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) func->nodetype = 'F'; func->fname = fname; func->nParams = nParams; + func->funcdata = NULL; func->fID = funcName2ID(fname, nParams); /* shuffle params over to array (access speed!) */ param = paramlst; -- cgit v1.2.3 From 1636c64ef0a5173ffbf25b47b8d714e8df77b9c6 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 21 Sep 2012 18:58:01 +0200 Subject: Improve script execution speed for important string-comparisons --- grammar/rainerscript.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 9440dd2f..d0c2dc6b 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1025,8 +1025,13 @@ evalVar(struct cnfvar *var, void *usrptr, struct var *ret) #define PREP_TWO_STRINGS \ cnfexprEval(expr->l, &l, usrptr); \ estr_l = var2String(&l, &bMustFree2); \ - cnfexprEval(expr->r, &r, usrptr); \ - estr_r = var2String(&r, &bMustFree) + if(expr->r->nodetype == 'S') { \ + estr_r = ((struct cnfstringval*)expr->r)->estr;\ + bMustFree = 0; \ + } else { \ + cnfexprEval(expr->r, &r, usrptr); \ + estr_r = var2String(&r, &bMustFree); \ + } #define FREE_TWO_STRINGS \ if(bMustFree) es_deleteStr(estr_r); \ -- cgit v1.2.3 From be26632b1e269652992ae6f336c5dd7e2dbec7ab Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 24 Sep 2012 18:31:22 +0200 Subject: PoC: optimize omdicard --> STOP --- grammar/rainerscript.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index d0c2dc6b..e5154156 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -45,6 +45,7 @@ #include "srUtils.h" #include "regexp.h" #include "obj.h" +#include "modules.h" DEFobjCurrIf(obj) DEFobjCurrIf(regexp) @@ -2086,6 +2087,19 @@ cnfstmtOptimizeIf(struct cnfstmt *stmt) } } + +static inline void +cnfstmtOptimizeAct(struct cnfstmt *stmt) +{ + action_t *pAct; + + pAct = stmt->d.act; + if(!strcmp((char*)modGetName(stmt->d.act->pMod), "builtin:omdiscard")) { + DBGPRINTF("RainerScript Optimizer: replacing omdiscard by STOP\n"); + stmt->nodetype = S_STOP; + } +} + /* (recursively) optimize a statement */ void cnfstmtOptimize(struct cnfstmt *root) @@ -2109,9 +2123,11 @@ dbgprintf("RRRR: stmtOptimize: stmt %p, nodetype %u\n", stmt, stmt->nodetype); case S_SET: cnfexprOptimize(stmt->d.s_set.expr); break; + case S_ACT: + cnfstmtOptimizeAct(stmt); + break; case S_STOP: - case S_UNSET: - case S_ACT: /* nothing to do */ + case S_UNSET: /* nothing to do */ break; case S_NOP: DBGPRINTF("optimizer error: we see a NOP, how come?\n"); -- cgit v1.2.3 From 8d99cfe38509aeadf169ba63c0d6c841eb2ecbe3 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 24 Sep 2012 18:59:26 +0200 Subject: Clean up implementation of omdiscard-->STOP optimization --- grammar/rainerscript.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index e5154156..ab07e0c4 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -2071,7 +2071,7 @@ cnfstmtOptimizeIf(struct cnfstmt *stmt) if(stmt->d.s_if.expr->nodetype == 'F') { func = (struct cnffunc*)expr; if(func->fID == CNFFUNC_PRIFILT) { - DBGPRINTF("optimize IF to PRIFILT\n"); + DBGPRINTF("optimizer: change IF to PRIFILT\n"); t_then = stmt->d.s_if.t_then; t_else = stmt->d.s_if.t_else; stmt->nodetype = S_PRIFILT; @@ -2095,7 +2095,8 @@ cnfstmtOptimizeAct(struct cnfstmt *stmt) pAct = stmt->d.act; if(!strcmp((char*)modGetName(stmt->d.act->pMod), "builtin:omdiscard")) { - DBGPRINTF("RainerScript Optimizer: replacing omdiscard by STOP\n"); + DBGPRINTF("optimizer: replacing omdiscard by STOP\n"); + actionDestruct(stmt->d.act); stmt->nodetype = S_STOP; } } -- cgit v1.2.3 From 39b9aac66390eab4a7a9c0898744363a61cd4457 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 24 Sep 2012 19:37:16 +0200 Subject: cleanup & better debug output - removed no longer needed function - debug log now contains action type for action objects --- grammar/rainerscript.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index ab07e0c4..d3e82fae 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1628,7 +1628,7 @@ cnfstmtPrint(struct cnfstmt *root, int indent) doIndent(indent); dbgprintf("STOP\n"); break; case S_ACT: - doIndent(indent); dbgprintf("ACTION %p (%s)\n", stmt->d.act, stmt->printable); + doIndent(indent); dbgprintf("ACTION %p [%s]\n", stmt->d.act, stmt->printable); break; case S_IF: doIndent(indent); dbgprintf("IF\n"); @@ -1845,6 +1845,7 @@ struct cnfstmt * cnfstmtNewAct(struct nvlst *lst) { struct cnfstmt* cnfstmt; + char namebuf[256]; if((cnfstmt = cnfstmtNew(S_ACT)) == NULL) goto done; if(actionNewInst(lst, &cnfstmt->d.act) != RS_RET_OK) { @@ -1854,7 +1855,10 @@ cnfstmtNewAct(struct nvlst *lst) cnfstmt->nodetype = S_NOP; /* disable action! */ goto done; } - cnfstmt->printable = (uchar*)strdup("action()"); + snprintf(namebuf, sizeof(namebuf)-1, "action(type=\"%s\" ...)", + modGetName(cnfstmt->d.act->pMod)); + namebuf[255] = '\0'; /* be on safe side */ + cnfstmt->printable = (uchar*)strdup(namebuf); done: return cnfstmt; } -- cgit v1.2.3 From 6b9457c4d73f9732645094d2efed85e02b1f9d03 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 25 Sep 2012 13:01:36 +0200 Subject: Implement Script Optimizer: remove always-true PRIFILT --- grammar/rainerscript.c | 48 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 4 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index d3e82fae..b8edf991 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -51,6 +51,7 @@ DEFobjCurrIf(obj) DEFobjCurrIf(regexp) void cnfexprOptimize(struct cnfexpr *expr); +static void cnfstmtOptimizePRIFilt(struct cnfstmt *stmt); char* getFIOPName(unsigned iFIOP) @@ -2087,11 +2088,11 @@ cnfstmtOptimizeIf(struct cnfstmt *stmt) stmt->printable = (uchar*) es_str2cstr(((struct cnfstringval*)func->expr[0])->estr, NULL); cnfexprDestruct(expr); + cnfstmtOptimizePRIFilt(stmt); } } } - static inline void cnfstmtOptimizeAct(struct cnfstmt *stmt) { @@ -2105,6 +2106,46 @@ cnfstmtOptimizeAct(struct cnfstmt *stmt) } } +static void +cnfstmtOptimizePRIFilt(struct cnfstmt *stmt) +{ + int i; + int isAlways = 1; + struct cnfstmt *subroot, *last; + + stmt->d.s_prifilt.t_then = removeNOPs(stmt->d.s_prifilt.t_then); + cnfstmtOptimize(stmt->d.s_prifilt.t_then); + + for(i = 0; i <= LOG_NFACILITIES; i++) + if(stmt->d.s_prifilt.pmask[i] != 0xff) { + isAlways = 0; + break; + } + if(!isAlways) + goto done; + + DBGPRINTF("optimizer: removing always-true PRIFILT %p\n", stmt); + if(stmt->d.s_prifilt.t_else != NULL) { + parser_errmsg("error: always-true PRI filter has else part!\n"); + // TODO: enable (requires changes in action.c) cnfstmtDestruct(stmt->d.s_prifilt.t_else); + } + subroot = stmt->d.s_prifilt.t_then; + if(subroot == NULL) { + /* very strange, we set it to NOP, best we can do + * This case is NOT expected in practice + */ + stmt->nodetype = S_NOP; + goto done; + } + for(last = subroot ; last->next != NULL ; last = last->next) + /* find last node in subtree */; + last->next = stmt->next; + memcpy(stmt, subroot, sizeof(struct cnfstmt)); + free(subroot); + +done: return; +} + /* (recursively) optimize a statement */ void cnfstmtOptimize(struct cnfstmt *root) @@ -2118,8 +2159,7 @@ dbgprintf("RRRR: stmtOptimize: stmt %p, nodetype %u\n", stmt, stmt->nodetype); cnfstmtOptimizeIf(stmt); break; case S_PRIFILT: - stmt->d.s_prifilt.t_then = removeNOPs(stmt->d.s_prifilt.t_then); - cnfstmtOptimize(stmt->d.s_prifilt.t_then); + cnfstmtOptimizePRIFilt(stmt); break; case S_PROPFILT: stmt->d.s_propfilt.t_then = removeNOPs(stmt->d.s_propfilt.t_then); @@ -2143,7 +2183,7 @@ dbgprintf("RRRR: stmtOptimize: stmt %p, nodetype %u\n", stmt, stmt->nodetype); break; } } -done: /*EMPTY*/; +done: return; } -- cgit v1.2.3 From 7dea4b3f324d9f99b57fd574f149b558d8804d6c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 25 Sep 2012 13:48:42 +0200 Subject: fix optimizer-introduced memleak in action destruction --- grammar/rainerscript.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index b8edf991..dd7eda72 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -2127,7 +2127,7 @@ cnfstmtOptimizePRIFilt(struct cnfstmt *stmt) DBGPRINTF("optimizer: removing always-true PRIFILT %p\n", stmt); if(stmt->d.s_prifilt.t_else != NULL) { parser_errmsg("error: always-true PRI filter has else part!\n"); - // TODO: enable (requires changes in action.c) cnfstmtDestruct(stmt->d.s_prifilt.t_else); + cnfstmtDestruct(stmt->d.s_prifilt.t_else); } subroot = stmt->d.s_prifilt.t_then; if(subroot == NULL) { -- cgit v1.2.3 From 79fc8640704054cd4c31c80c643a9756d639eceb Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 25 Sep 2012 14:51:51 +0200 Subject: fix small memory leak during script optimization --- grammar/rainerscript.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index dd7eda72..2e066d78 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -2129,6 +2129,8 @@ cnfstmtOptimizePRIFilt(struct cnfstmt *stmt) parser_errmsg("error: always-true PRI filter has else part!\n"); cnfstmtDestruct(stmt->d.s_prifilt.t_else); } + free(stmt->printable); + stmt->printable = NULL; subroot = stmt->d.s_prifilt.t_then; if(subroot == NULL) { /* very strange, we set it to NOP, best we can do -- cgit v1.2.3 From d397bb25265b8b0926af050c4187cfbc5ab074ca Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 25 Sep 2012 15:19:34 +0200 Subject: fix invalid free caused by optimized script execution --- grammar/rainerscript.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index d0c2dc6b..199aaa97 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1035,8 +1035,9 @@ evalVar(struct cnfvar *var, void *usrptr, struct var *ret) #define FREE_TWO_STRINGS \ if(bMustFree) es_deleteStr(estr_r); \ + if(expr->r->nodetype != 'S' && r.datatype == 'S') es_deleteStr(r.d.estr); \ if(bMustFree2) es_deleteStr(estr_l); \ - FREE_BOTH_RET + if(l.datatype == 'S') es_deleteStr(l.d.estr) /* evaluate an expression. * Note that we try to avoid malloc whenever possible (because of -- cgit v1.2.3 From 87fb978c809fbc0432f5216251fbc7782d574f97 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 25 Sep 2012 15:58:07 +0200 Subject: detect unreachable statements and emit warning message --- grammar/rainerscript.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 90bbb335..04072cdb 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -2175,6 +2175,9 @@ dbgprintf("RRRR: stmtOptimize: stmt %p, nodetype %u\n", stmt, stmt->nodetype); cnfstmtOptimizeAct(stmt); break; case S_STOP: + if(stmt->next != NULL) + parser_errmsg("STOP is followed by unreachable statements!\n"); + break; case S_UNSET: /* nothing to do */ break; case S_NOP: -- cgit v1.2.3 From eb18d9b23248732da3cba2b170ddc271ae7ec346 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 25 Sep 2012 17:22:22 +0200 Subject: slight optimization of == in string comparisons --- grammar/rainerscript.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 04072cdb..035b017d 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1066,23 +1066,31 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) * places flagged with "CMP" need to be changed. */ case CMP_EQ: + /* this is optimized in regard to right param as a PoC for all compOps + * So this is a NOT yet the copy template! + */ cnfexprEval(expr->l, &l, usrptr); - cnfexprEval(expr->r, &r, usrptr); ret->datatype = 'N'; if(l.datatype == 'S') { - if(r.datatype == 'S') { - ret->d.n = !es_strcmp(l.d.estr, r.d.estr); /*CMP*/ + if(expr->r->nodetype == 'S') { + ret->d.n = !es_strcmp(l.d.estr, ((struct cnfstringval*)expr->r)->estr); /*CMP*/ } else { - n_l = var2Number(&l, &convok_l); - if(convok_l) { - ret->d.n = (n_l == r.d.n); /*CMP*/ + cnfexprEval(expr->r, &r, usrptr); + if(r.datatype == 'S') { + ret->d.n = !es_strcmp(l.d.estr, r.d.estr); /*CMP*/ } else { - estr_r = var2String(&r, &bMustFree); - ret->d.n = !es_strcmp(l.d.estr, estr_r); /*CMP*/ - if(bMustFree) es_deleteStr(estr_r); + n_l = var2Number(&l, &convok_l); + if(convok_l) { + ret->d.n = (n_l == r.d.n); /*CMP*/ + } else { + estr_r = var2String(&r, &bMustFree); + ret->d.n = !es_strcmp(l.d.estr, estr_r); /*CMP*/ + if(bMustFree) es_deleteStr(estr_r); + } } } } else { + cnfexprEval(expr->r, &r, usrptr); if(r.datatype == 'S') { n_r = var2Number(&r, &convok_r); if(convok_r) { -- cgit v1.2.3 From c6cb5bf4aa75b79bdc3cd1af38788a32bd2c8e1a Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 25 Sep 2012 17:37:35 +0200 Subject: fix invalid free in PoC == optimization --- grammar/rainerscript.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 035b017d..a2455755 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1088,6 +1088,7 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) if(bMustFree) es_deleteStr(estr_r); } } + if(r.datatype == 'S') es_deleteStr(r.d.estr); } } else { cnfexprEval(expr->r, &r, usrptr); @@ -1103,8 +1104,9 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) } else { ret->d.n = (l.d.n == r.d.n); /*CMP*/ } + if(r.datatype == 'S') es_deleteStr(r.d.estr); } - FREE_BOTH_RET; + if(l.datatype == 'S') es_deleteStr(l.d.estr); break; case CMP_NE: cnfexprEval(expr->l, &l, usrptr); -- cgit v1.2.3 From 2ce900aea233b9f8b0447658f2dc3565c3103e78 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 27 Sep 2012 10:03:12 +0200 Subject: bugfix: config errors did not always cause statement to fail This could lead to startup with invalid parameters. --- grammar/rainerscript.c | 129 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 108 insertions(+), 21 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 5e6e492d..9e0d04c7 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -271,13 +271,14 @@ nvlstChkUnused(struct nvlst *lst) } -static inline void +static inline int doGetSize(struct nvlst *valnode, struct cnfparamdescr *param, struct cnfparamvals *val) { unsigned char *c; es_size_t i; long long n; + int r; c = es_getBufAddr(valnode->val.d.estr); n = 0; i = 0; @@ -311,17 +312,21 @@ doGetSize(struct nvlst *valnode, struct cnfparamdescr *param, if(i == es_strlen(valnode->val.d.estr)) { val->val.datatype = 'N'; val->val.d.n = n; + r = 1; } else { parser_errmsg("parameter '%s' does not contain a valid size", param->name); + r = 0; } + return r; } -static inline void +static inline int doGetBinary(struct nvlst *valnode, struct cnfparamdescr *param, struct cnfparamvals *val) { + int r = 1; val->val.datatype = 'N'; if(!es_strbufcmp(valnode->val.d.estr, (unsigned char*) "on", 2)) { val->val.d.n = 1; @@ -331,14 +336,17 @@ doGetBinary(struct nvlst *valnode, struct cnfparamdescr *param, parser_errmsg("parameter '%s' must be \"on\" or \"off\" but " "is neither. Results unpredictable.", param->name); val->val.d.n = 0; + r = 0; } + return r; } -static inline void +static inline int doGetQueueType(struct nvlst *valnode, struct cnfparamdescr *param, struct cnfparamvals *val) { char *cstr; + int r = 1; if(!es_strcasebufcmp(valnode->val.d.estr, (uchar*)"fixedarray", 10)) { val->val.d.n = QUEUETYPE_FIXED_ARRAY; } else if(!es_strcasebufcmp(valnode->val.d.estr, (uchar*)"linkedlist", 10)) { @@ -352,15 +360,17 @@ doGetQueueType(struct nvlst *valnode, struct cnfparamdescr *param, parser_errmsg("param '%s': unknown queue type: '%s'", param->name, cstr); free(cstr); + r = 0; } val->val.datatype = 'N'; + return r; } /* A file create-mode must be a four-digit octal number * starting with '0'. */ -static inline void +static inline int doGetFileCreateMode(struct nvlst *valnode, struct cnfparamdescr *param, struct cnfparamvals *val) { @@ -389,13 +399,15 @@ doGetFileCreateMode(struct nvlst *valnode, struct cnfparamdescr *param, param->name, cstr); free(cstr); } + return fmtOK; } -static inline void +static inline int doGetGID(struct nvlst *valnode, struct cnfparamdescr *param, struct cnfparamvals *val) { char *cstr; + int r; struct group *resultBuf; struct group wrkBuf; char stringBuf[2048]; /* 2048 has been proven to be large enough */ @@ -405,20 +417,24 @@ doGetGID(struct nvlst *valnode, struct cnfparamdescr *param, if(resultBuf == NULL) { parser_errmsg("parameter '%s': ID for group %s could not " "be found", param->name, cstr); + r = 0; } else { val->val.datatype = 'N'; val->val.d.n = resultBuf->gr_gid; dbgprintf("param '%s': uid %d obtained for group '%s'\n", param->name, (int) resultBuf->gr_gid, cstr); + r = 1; } free(cstr); + return r; } -static inline void +static inline int doGetUID(struct nvlst *valnode, struct cnfparamdescr *param, struct cnfparamvals *val) { char *cstr; + int r; struct passwd *resultBuf; struct passwd wrkBuf; char stringBuf[2048]; /* 2048 has been proven to be large enough */ @@ -428,19 +444,22 @@ doGetUID(struct nvlst *valnode, struct cnfparamdescr *param, if(resultBuf == NULL) { parser_errmsg("parameter '%s': ID for user %s could not " "be found", param->name, cstr); + r = 0; } else { val->val.datatype = 'N'; val->val.d.n = resultBuf->pw_uid; dbgprintf("param '%s': uid %d obtained for user '%s'\n", param->name, (int) resultBuf->pw_uid, cstr); + r = 1; } free(cstr); + return r; } /* note: we support all integer formats that es_str2num support, * so hex and octal representations are also valid. */ -static inline void +static inline int doGetInt(struct nvlst *valnode, struct cnfparamdescr *param, struct cnfparamvals *val) { @@ -454,13 +473,47 @@ doGetInt(struct nvlst *valnode, struct cnfparamdescr *param, } val->val.datatype = 'N'; val->val.d.n = n; + return bSuccess; } -static inline void +static inline int +doGetNonNegInt(struct nvlst *valnode, struct cnfparamdescr *param, + struct cnfparamvals *val) +{ + int bSuccess; + + if((bSuccess = doGetInt(valnode, param, val))) { + if(val->val.d.n < 0) { + parser_errmsg("parameter '%s' cannot be less than zero (was %lld)", + param->name, val->val.d.n); + bSuccess = 0; + } + } + return bSuccess; +} + +static inline int +doGetPositiveInt(struct nvlst *valnode, struct cnfparamdescr *param, + struct cnfparamvals *val) +{ + int bSuccess; + + if((bSuccess = doGetInt(valnode, param, val))) { + if(val->val.d.n < 1) { + parser_errmsg("parameter '%s' cannot be less than one (was %lld)", + param->name, val->val.d.n); + bSuccess = 0; + } + } + return bSuccess; +} + +static inline int doGetWord(struct nvlst *valnode, struct cnfparamdescr *param, struct cnfparamvals *val) { es_size_t i; + int r = 1; unsigned char *c; val->val.datatype = 'S'; val->val.d.estr = es_newStr(32); @@ -472,30 +525,36 @@ doGetWord(struct nvlst *valnode, struct cnfparamdescr *param, parser_errmsg("parameter '%s' contains whitespace, which is not " "permitted - data after first whitespace ignored", param->name); + r = 0; } + return r; } -static inline void +static inline int doGetChar(struct nvlst *valnode, struct cnfparamdescr *param, struct cnfparamvals *val) { + int r = 1; if(es_strlen(valnode->val.d.estr) != 1) { parser_errmsg("parameter '%s' must contain exactly one character " "but contains %d - cannot be processed", param->name, es_strlen(valnode->val.d.estr)); + r = 0; } val->val.datatype = 'S'; val->val.d.estr = es_strdup(valnode->val.d.estr); + return r; } /* get a single parameter according to its definition. Helper to - * nvlstGetParams. + * nvlstGetParams. returns 1 if success, 0 otherwise */ -static inline void +static inline int nvlstGetParam(struct nvlst *valnode, struct cnfparamdescr *param, struct cnfparamvals *val) { uchar *cstr; + int r; dbgprintf("XXXX: in nvlstGetParam, name '%s', type %d, valnode->bUsed %d\n", param->name, (int) param->type, valnode->bUsed); @@ -503,56 +562,68 @@ nvlstGetParam(struct nvlst *valnode, struct cnfparamdescr *param, val->bUsed = 1; switch(param->type) { case eCmdHdlrQueueType: - doGetQueueType(valnode, param, val); + r = doGetQueueType(valnode, param, val); break; case eCmdHdlrUID: - doGetUID(valnode, param, val); + r = doGetUID(valnode, param, val); break; case eCmdHdlrGID: - doGetGID(valnode, param, val); + r = doGetGID(valnode, param, val); break; case eCmdHdlrBinary: - doGetBinary(valnode, param, val); + r = doGetBinary(valnode, param, val); break; case eCmdHdlrFileCreateMode: - doGetFileCreateMode(valnode, param, val); + r = doGetFileCreateMode(valnode, param, val); break; case eCmdHdlrInt: - doGetInt(valnode, param, val); + r = doGetInt(valnode, param, val); + break; + case eCmdHdlrNonNegInt: + r = doGetPositiveInt(valnode, param, val); + break; + case eCmdHdlrPositiveInt: + r = doGetPositiveInt(valnode, param, val); break; case eCmdHdlrSize: - doGetSize(valnode, param, val); + r = doGetSize(valnode, param, val); break; case eCmdHdlrGetChar: - doGetChar(valnode, param, val); + r = doGetChar(valnode, param, val); break; case eCmdHdlrFacility: cstr = (uchar*) es_str2cstr(valnode->val.d.estr, NULL); val->val.datatype = 'N'; val->val.d.n = decodeSyslogName(cstr, syslogFacNames); free(cstr); + r = 1; break; case eCmdHdlrSeverity: cstr = (uchar*) es_str2cstr(valnode->val.d.estr, NULL); val->val.datatype = 'N'; val->val.d.n = decodeSyslogName(cstr, syslogPriNames); free(cstr); + r = 1; break; case eCmdHdlrGetWord: - doGetWord(valnode, param, val); + r = doGetWord(valnode, param, val); break; case eCmdHdlrString: val->val.datatype = 'S'; val->val.d.estr = es_strdup(valnode->val.d.estr); + r = 1; break; case eCmdHdlrGoneAway: parser_errmsg("parameter '%s' is no longer supported", param->name); + r = 1; /* this *is* valid! */ break; default: dbgprintf("error: invalid param type\n"); + r = 0; break; } + return r; } @@ -567,6 +638,8 @@ nvlstGetParams(struct nvlst *lst, struct cnfparamblk *params, struct cnfparamvals *vals) { int i; + int bValsWasNULL; + int bInError = 0; struct nvlst *valnode; struct cnfparamdescr *param; @@ -578,9 +651,12 @@ nvlstGetParams(struct nvlst *lst, struct cnfparamblk *params, } if(vals == NULL) { + bValsWasNULL = 1; if((vals = calloc(params->nParams, sizeof(struct cnfparamvals))) == NULL) return NULL; + } else { + bValsWasNULL = 0; } for(i = 0 ; i < params->nParams ; ++i) { @@ -592,8 +668,19 @@ nvlstGetParams(struct nvlst *lst, struct cnfparamblk *params, "one instance is ignored. Fix config", param->name); continue; } - nvlstGetParam(valnode, param, vals + i); + if(!nvlstGetParam(valnode, param, vals + i)) { + bInError = 1; + } } + + + if(bInError) { + if(bValsWasNULL) + cnfparamvalsDestruct(vals, params); + vals = NULL; + } + +dbgprintf("DDDD: vals %p\n", vals); return vals; } -- cgit v1.2.3 From 38cdf1abaddea47aa5e9d11d97fade6a2455b632 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 28 Sep 2012 11:06:16 +0200 Subject: Implement RainerScript ruleset() statement --- grammar/rainerscript.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 1a14b212..4e484804 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -732,7 +732,6 @@ nvlstGetParams(struct nvlst *lst, struct cnfparamblk *params, vals = NULL; } -dbgprintf("DDDD: vals %p\n", vals); return vals; } @@ -777,6 +776,7 @@ cnfobjNew(enum cnfobjType objType, struct nvlst *lst) o->objType = objType; o->nvlst = lst; o->subobjs = NULL; + o->script = NULL; } return o; -- cgit v1.2.3 From 04c0124eb7dee70be4abeeba5e10d363154c8b40 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 28 Sep 2012 14:45:34 +0200 Subject: rainerscript: add basic plumbing for arrays can be used in expressions, but always evaluate to the first element, only --- grammar/rainerscript.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 4e484804..af51dbc2 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1428,6 +1428,13 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) ret->datatype = 'S'; ret->d.estr = es_strdup(((struct cnfstringval*)expr)->estr); break; + case S_ARRAY: + /* if an array is used with "normal" operations, it just evaluates + * to its first element. + */ + ret->datatype = 'S'; + ret->d.estr = es_strdup(((struct cnfarray*)expr)->arr[0]); + break; case 'V': evalVar((struct cnfvar*)expr, usrptr, ret); break; @@ -1474,6 +1481,17 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) //--------------------------------------------------------- +static inline void +cnfarrayDestruct(struct cnfarray *ar) +{ + unsigned short i; + + for(i = 0 ; i < ar->nmemb ; ++i) { + es_deleteStr(ar->arr[i]); + } + free(ar->arr); +} + static inline void cnffuncDestruct(struct cnffunc *func) { @@ -1538,6 +1556,9 @@ cnfexprDestruct(struct cnfexpr *expr) case 'F': cnffuncDestruct((struct cnffunc*)expr); break; + case S_ARRAY: + cnfarrayDestruct((struct cnfarray*)expr); + break; default:break; } free(expr); @@ -1588,7 +1609,7 @@ cnfexprPrint(struct cnfexpr *expr, int indent) struct cnffunc *func; int i; - //dbgprintf("expr %p, indent %d, type '%c'\n", expr, indent, expr->nodetype); + dbgprintf("expr %p, indent %d, type '%c'\n", expr, indent, expr->nodetype); switch(expr->nodetype) { case CMP_EQ: cnfexprPrint(expr->l, indent+1); @@ -1672,6 +1693,15 @@ cnfexprPrint(struct cnfexpr *expr, int indent) cstrPrint("string '", ((struct cnfstringval*)expr)->estr); dbgprintf("'\n"); break; + case S_ARRAY: +dbgprintf("DDDD: %d members\n", ((struct cnfarray*)expr)->nmemb); + doIndent(indent); dbgprintf("ARRAY:\n"); + for(i = 0 ; i < ((struct cnfarray*)expr)->nmemb ; ++i) { + doIndent(indent+1); + cstrPrint("string '", ((struct cnfarray*)expr)->arr[i]); + dbgprintf("'\n"); + } + break; case 'N': doIndent(indent); dbgprintf("%lld\n", ((struct cnfnumval*)expr)->val); @@ -1813,6 +1843,39 @@ cnfstringvalNew(es_str_t *estr) return strval; } +/* creates array AND adds first element to it */ +struct cnfarray* +cnfarrayNew(es_str_t *val) +{ + struct cnfarray *ar; + if((ar = malloc(sizeof(struct cnfarray))) != NULL) { + ar->nodetype = S_ARRAY; + ar->nmemb = 1; + if((ar->arr = malloc(sizeof(es_str_t*))) == NULL) { + free(ar); + ar = NULL; + goto done; + } + ar->arr[0] = val; + } +done: return ar; +} + +/* creates array AND adds first element to it */ +struct cnfarray* +cnfarrayAdd(struct cnfarray *ar, es_str_t *val) +{ + es_str_t **newptr; + if((newptr = realloc(ar->arr, (ar->nmemb+1)*sizeof(es_str_t*))) == NULL) { + DBGPRINTF("cnfarrayAdd: realloc failed, item ignored, ar->arr=%p\n", ar->arr); + goto done; + } else { + ar->arr = newptr; + ar->arr[ar->nmemb] = val; + ar->nmemb++; + } +done: return ar; +} struct cnfvar* cnfvarNew(char *name) -- cgit v1.2.3 From bc9ca278b57dedfe30bfb8812b1e3c2f50982057 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 28 Sep 2012 17:42:07 +0200 Subject: implement RainerScript array-based string comparison operations --- grammar/rainerscript.c | 90 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 77 insertions(+), 13 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index af51dbc2..5b01bf47 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1100,6 +1100,41 @@ evalVar(struct cnfvar *var, void *usrptr, struct var *ret) } +/* perform a string comparision operation against a while array. Semantic is + * that one one comparison is true, the whole construct is true. + * TODO: we can obviously optimize this process. One idea is to + * compile a regex, which should work faster than serial comparison. + */ +static int +evalStrArrayCmp(es_str_t *estr_l, struct cnfarray* ar, int cmpop) +{ + int i; + int r = 0; + for(i = 0 ; (r == 0) && (i < ar->nmemb) ; ++i) { + switch(cmpop) { + case CMP_EQ: + r = es_strcmp(estr_l, ar->arr[i]) == 0; + break; + case CMP_NE: + r = es_strcmp(estr_l, ar->arr[i]) != 0; + break; + case CMP_STARTSWITH: + r = es_strncmp(estr_l, ar->arr[i], es_strlen(ar->arr[i])) == 0; + break; + case CMP_STARTSWITHI: + r = es_strncasecmp(estr_l, ar->arr[i], es_strlen(ar->arr[i])) == 0; + break; + case CMP_CONTAINS: + r = es_strContains(estr_l, ar->arr[i]) != -1; + break; + case CMP_CONTAINSI: + r = es_strCaseContains(estr_l, ar->arr[i]) != -1; + break; + } + } + return r; +} + #define FREE_BOTH_RET \ if(r.datatype == 'S') es_deleteStr(r.d.estr); \ if(l.datatype == 'S') es_deleteStr(l.d.estr) @@ -1111,13 +1146,14 @@ evalVar(struct cnfvar *var, void *usrptr, struct var *ret) ret->d.n = var2Number(&l, &convok_l) x var2Number(&r, &convok_r); \ FREE_BOTH_RET +/* NOTE: array as right-hand argument MUST be handled by user */ #define PREP_TWO_STRINGS \ cnfexprEval(expr->l, &l, usrptr); \ estr_l = var2String(&l, &bMustFree2); \ if(expr->r->nodetype == 'S') { \ estr_r = ((struct cnfstringval*)expr->r)->estr;\ bMustFree = 0; \ - } else { \ + } else if(expr->r->nodetype != S_ARRAY) { \ cnfexprEval(expr->r, &r, usrptr); \ estr_r = var2String(&r, &bMustFree); \ } @@ -1161,6 +1197,8 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) if(l.datatype == 'S') { if(expr->r->nodetype == 'S') { ret->d.n = !es_strcmp(l.d.estr, ((struct cnfstringval*)expr->r)->estr); /*CMP*/ + } else if(expr->r->nodetype == S_ARRAY) { + ret->d.n = evalStrArrayCmp(l.d.estr, (struct cnfarray*) expr->r, CMP_EQ); } else { cnfexprEval(expr->r, &r, usrptr); if(r.datatype == 'S') { @@ -1200,16 +1238,22 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) cnfexprEval(expr->r, &r, usrptr); ret->datatype = 'N'; if(l.datatype == 'S') { - if(r.datatype == 'S') { - ret->d.n = es_strcmp(l.d.estr, r.d.estr); /*CMP*/ + if(expr->r->nodetype == 'S') { + ret->d.n = es_strcmp(l.d.estr, ((struct cnfstringval*)expr->r)->estr); /*CMP*/ + } else if(expr->r->nodetype == S_ARRAY) { + ret->d.n = evalStrArrayCmp(l.d.estr, (struct cnfarray*) expr->r, CMP_NE); } else { - n_l = var2Number(&l, &convok_l); - if(convok_l) { - ret->d.n = (n_l != r.d.n); /*CMP*/ + if(r.datatype == 'S') { + ret->d.n = es_strcmp(l.d.estr, r.d.estr); /*CMP*/ } else { - estr_r = var2String(&r, &bMustFree); - ret->d.n = es_strcmp(l.d.estr, estr_r); /*CMP*/ - if(bMustFree) es_deleteStr(estr_r); + n_l = var2Number(&l, &convok_l); + if(convok_l) { + ret->d.n = (n_l != r.d.n); /*CMP*/ + } else { + estr_r = var2String(&r, &bMustFree); + ret->d.n = es_strcmp(l.d.estr, estr_r); /*CMP*/ + if(bMustFree) es_deleteStr(estr_r); + } } } } else { @@ -1363,25 +1407,41 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) case CMP_STARTSWITH: PREP_TWO_STRINGS; ret->datatype = 'N'; - ret->d.n = es_strncmp(estr_l, estr_r, estr_r->lenStr) == 0; + if(expr->r->nodetype == S_ARRAY) { + ret->d.n = evalStrArrayCmp(estr_l, (struct cnfarray*) expr->r, CMP_STARTSWITH); + } else { + ret->d.n = es_strncmp(estr_l, estr_r, estr_r->lenStr) == 0; + } FREE_TWO_STRINGS; break; case CMP_STARTSWITHI: PREP_TWO_STRINGS; ret->datatype = 'N'; - ret->d.n = es_strncasecmp(estr_l, estr_r, estr_r->lenStr) == 0; + if(expr->r->nodetype == S_ARRAY) { + ret->d.n = evalStrArrayCmp(estr_l, (struct cnfarray*) expr->r, CMP_STARTSWITHI); + } else { + ret->d.n = es_strncasecmp(estr_l, estr_r, estr_r->lenStr) == 0; + } FREE_TWO_STRINGS; break; case CMP_CONTAINS: PREP_TWO_STRINGS; ret->datatype = 'N'; - ret->d.n = es_strContains(estr_l, estr_r) != -1; + if(expr->r->nodetype == S_ARRAY) { + ret->d.n = evalStrArrayCmp(estr_l, (struct cnfarray*) expr->r, CMP_CONTAINS); + } else { + ret->d.n = es_strContains(estr_l, estr_r) != -1; + } FREE_TWO_STRINGS; break; case CMP_CONTAINSI: PREP_TWO_STRINGS; ret->datatype = 'N'; - ret->d.n = es_strCaseContains(estr_l, estr_r) != -1; + if(expr->r->nodetype == S_ARRAY) { + ret->d.n = evalStrArrayCmp(estr_l, (struct cnfarray*) expr->r, CMP_CONTAINSI); + } else { + ret->d.n = es_strCaseContains(estr_l, estr_r) != -1; + } FREE_TWO_STRINGS; break; case OR: @@ -1441,6 +1501,10 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) case '&': /* TODO: think about optimization, should be possible ;) */ PREP_TWO_STRINGS; + if(expr->r->nodetype == S_ARRAY) { + estr_r = ((struct cnfarray*)expr->r)->arr[0]; + bMustFree = 0; + } ret->datatype = 'S'; ret->d.estr = es_strdup(estr_l); es_addStr(&ret->d.estr, estr_r); -- cgit v1.2.3 From e3a611ac6204e785d8f85ff54156dac5a722968f Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 28 Sep 2012 17:46:50 +0200 Subject: cleanup --- grammar/rainerscript.c | 1 - 1 file changed, 1 deletion(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 5b01bf47..d77721b8 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -22,7 +22,6 @@ * A copy of the GPL can be found in the file "COPYING" in this distribution. * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. */ - #include "config.h" #include #include -- cgit v1.2.3 From c0ccd3ff253401ce2081a5d2042f50af35b07233 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 1 Oct 2012 10:29:38 +0200 Subject: implement string arrays for config objects as a tester, imudp now supports binding to multiple options based on a string array --- grammar/rainerscript.c | 147 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 122 insertions(+), 25 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index d77721b8..6f9310db 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -51,6 +51,9 @@ DEFobjCurrIf(regexp) void cnfexprOptimize(struct cnfexpr *expr); static void cnfstmtOptimizePRIFilt(struct cnfstmt *stmt); +static void cnfarrayPrint(struct cnfarray *ar, int indent); +static void cnfarrayContentDestruct(struct cnfarray *ar); +static struct cnfarray* cnfarrayDup(struct cnfarray *old); char* getFIOPName(unsigned iFIOP) @@ -206,13 +209,12 @@ objlstPrint(struct objlst *lst) } struct nvlst* -nvlstNew(es_str_t *name, es_str_t *value) +nvlstNewStr(es_str_t *value) { struct nvlst *lst; if((lst = malloc(sizeof(struct nvlst))) != NULL) { lst->next = NULL; - lst->name = name; lst->val.datatype = 'S'; lst->val.d.estr = value; lst->bUsed = 0; @@ -221,6 +223,28 @@ nvlstNew(es_str_t *name, es_str_t *value) return lst; } +struct nvlst* +nvlstNewArray(struct cnfarray *ar) +{ + struct nvlst *lst; + + if((lst = malloc(sizeof(struct nvlst))) != NULL) { + lst->next = NULL; + lst->val.datatype = 'A'; + lst->val.d.ar = ar; + lst->bUsed = 0; + } + + return lst; +} + +struct nvlst* +nvlstSetName(struct nvlst *lst, es_str_t *name) +{ + lst->name = name; + return lst; +} + void nvlstDestruct(struct nvlst *lst) { @@ -230,8 +254,7 @@ nvlstDestruct(struct nvlst *lst) toDel = lst; lst = lst->next; es_deleteStr(toDel->name); - if(toDel->val.datatype == 'S') - es_deleteStr(toDel->val.d.estr); + varDelete(&toDel->val); free(toDel); } } @@ -243,11 +266,21 @@ nvlstPrint(struct nvlst *lst) dbgprintf("nvlst %p:\n", lst); while(lst != NULL) { name = es_str2cstr(lst->name, NULL); - // TODO: support for non-string types - value = es_str2cstr(lst->val.d.estr, NULL); - dbgprintf("\tname: '%s', value '%s'\n", name, value); + switch(lst->val.datatype) { + case 'A': + dbgprintf("\tname: '%s':\n", name); + cnfarrayPrint(lst->val.d.ar, 5); + break; + case 'S': + value = es_str2cstr(lst->val.d.estr, NULL); + dbgprintf("\tname: '%s', value '%s'\n", name, value); + free(value); + break; + default:dbgprintf("nvlstPrint: unknown type '%c' [%d]\n", + lst->val.datatype, lst->val.datatype); + break; + } free(name); - free(value); lst = lst->next; } } @@ -566,6 +599,7 @@ doGetWord(struct nvlst *valnode, struct cnfparamdescr *param, es_size_t i; int r = 1; unsigned char *c; + val->val.datatype = 'S'; val->val.d.estr = es_newStr(32); c = es_getBufAddr(valnode->val.d.estr); @@ -574,13 +608,37 @@ doGetWord(struct nvlst *valnode, struct cnfparamdescr *param, } if(i != es_strlen(valnode->val.d.estr)) { parser_errmsg("parameter '%s' contains whitespace, which is not " - "permitted - data after first whitespace ignored", + "permitted", param->name); r = 0; } return r; } +static inline int +doGetArray(struct nvlst *valnode, struct cnfparamdescr *param, + struct cnfparamvals *val) +{ + int r = 1; + + switch(valnode->val.datatype) { + case 'S': + /* a constant string is assumed to be a single-element array */ + val->val.datatype = 'A'; + val->val.d.ar = cnfarrayNew(es_strdup(valnode->val.d.estr)); + break; + case 'A': + val->val.datatype = 'A'; + val->val.d.ar = cnfarrayDup(valnode->val.d.ar); + break; + default:parser_errmsg("parameter '%s' must be an array, but is a " + "different datatype", param->name); + r = 0; + break; + } + return r; +} + static inline int doGetChar(struct nvlst *valnode, struct cnfparamdescr *param, struct cnfparamvals *val) @@ -607,8 +665,15 @@ nvlstGetParam(struct nvlst *valnode, struct cnfparamdescr *param, uchar *cstr; int r; - dbgprintf("XXXX: in nvlstGetParam, name '%s', type %d, valnode->bUsed %d\n", + DBGPRINTF("nvlstGetParam: name '%s', type %d, valnode->bUsed %d\n", param->name, (int) param->type, valnode->bUsed); + if(valnode->val.datatype != 'S' && param->type != eCmdHdlrArray) { + parser_errmsg("parameter '%s' is not a string, which is not " + "permitted", + param->name); + r = 0; + goto done; + } valnode->bUsed = 1; val->bUsed = 1; switch(param->type) { @@ -664,6 +729,9 @@ nvlstGetParam(struct nvlst *valnode, struct cnfparamdescr *param, val->val.d.estr = es_strdup(valnode->val.d.estr); r = 1; break; + case eCmdHdlrArray: + r = doGetArray(valnode, param, val); + break; case eCmdHdlrGoneAway: parser_errmsg("parameter '%s' is no longer supported", param->name); @@ -674,7 +742,7 @@ nvlstGetParam(struct nvlst *valnode, struct cnfparamdescr *param, r = 0; break; } - return r; +done: return r; } @@ -751,6 +819,9 @@ cnfparamsPrint(struct cnfparamblk *params, struct cnfparamvals *vals) dbgprintf(" '%s'", cstr); free(cstr); break; + case 'A': + cnfarrayPrint(vals[i].val.d.ar, 0); + break; case 'N': dbgprintf("%lld", vals[i].val.d.n); break; @@ -1544,11 +1615,10 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) //--------------------------------------------------------- -static inline void -cnfarrayDestruct(struct cnfarray *ar) +static void +cnfarrayContentDestruct(struct cnfarray *ar) { unsigned short i; - for(i = 0 ; i < ar->nmemb ; ++i) { es_deleteStr(ar->arr[i]); } @@ -1620,7 +1690,7 @@ cnfexprDestruct(struct cnfexpr *expr) cnffuncDestruct((struct cnffunc*)expr); break; case S_ARRAY: - cnfarrayDestruct((struct cnfarray*)expr); + cnfarrayContentDestruct((struct cnfarray*)expr); break; default:break; } @@ -1665,6 +1735,17 @@ pmaskPrint(uchar *pmask, int indent) dbgprintf("\n"); } +static void +cnfarrayPrint(struct cnfarray *ar, int indent) +{ + int i; + doIndent(indent); dbgprintf("ARRAY:\n"); + for(i = 0 ; i < ar->nmemb ; ++i) { + doIndent(indent+1); + cstrPrint("string '", ar->arr[i]); + dbgprintf("'\n"); + } +} void cnfexprPrint(struct cnfexpr *expr, int indent) @@ -1757,13 +1838,7 @@ cnfexprPrint(struct cnfexpr *expr, int indent) dbgprintf("'\n"); break; case S_ARRAY: -dbgprintf("DDDD: %d members\n", ((struct cnfarray*)expr)->nmemb); - doIndent(indent); dbgprintf("ARRAY:\n"); - for(i = 0 ; i < ((struct cnfarray*)expr)->nmemb ; ++i) { - doIndent(indent+1); - cstrPrint("string '", ((struct cnfarray*)expr)->arr[i]); - dbgprintf("'\n"); - } + cnfarrayPrint((struct cnfarray*)expr, indent); break; case 'N': doIndent(indent); @@ -1924,7 +1999,6 @@ cnfarrayNew(es_str_t *val) done: return ar; } -/* creates array AND adds first element to it */ struct cnfarray* cnfarrayAdd(struct cnfarray *ar, es_str_t *val) { @@ -1940,6 +2014,19 @@ cnfarrayAdd(struct cnfarray *ar, es_str_t *val) done: return ar; } +/* duplicate an array (deep copy) */ +static struct cnfarray* +cnfarrayDup(struct cnfarray *old) +{ + int i; + struct cnfarray *ar; + ar = cnfarrayNew(es_strdup(old->arr[0])); + for(i = 1 ; i < old->nmemb ; ++i) { + cnfarrayAdd(ar, es_strdup(old->arr[i])); + } + return ar; +} + struct cnfvar* cnfvarNew(char *name) { @@ -2647,8 +2734,16 @@ cnfDoInclude(char *name) void varDelete(struct var *v) { - if(v->datatype == 'S') + switch(v->datatype) { + case 'S': es_deleteStr(v->d.estr); + break; + case 'A': + cnfarrayContentDestruct(v->d.ar); + free(v->d.ar); + break; + default:break; + } } void @@ -2656,7 +2751,9 @@ cnfparamvalsDestruct(struct cnfparamvals *paramvals, struct cnfparamblk *blk) { int i; for(i = 0 ; i < blk->nParams ; ++i) { - varDelete(¶mvals[i].val); + if(paramvals[i].bUsed) { + varDelete(¶mvals[i].val); + } } free(paramvals); } -- cgit v1.2.3 From c5f9139c71d9d371dbdea4a3024c589820314ba8 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 1 Oct 2012 10:53:24 +0200 Subject: fix: invalid free in array-based string comparisons --- grammar/rainerscript.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 6f9310db..5638ba42 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1229,9 +1229,9 @@ evalStrArrayCmp(es_str_t *estr_l, struct cnfarray* ar, int cmpop) } #define FREE_TWO_STRINGS \ - if(bMustFree) es_deleteStr(estr_r); \ - if(expr->r->nodetype != 'S' && r.datatype == 'S') es_deleteStr(r.d.estr); \ - if(bMustFree2) es_deleteStr(estr_l); \ + if(bMustFree) es_deleteStr(estr_r); \ + if(expr->r->nodetype != S_ARRAY && r.datatype == 'S') es_deleteStr(r.d.estr); \ + if(bMustFree2) es_deleteStr(estr_l); \ if(l.datatype == 'S') es_deleteStr(l.d.estr) /* evaluate an expression. @@ -1479,6 +1479,7 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) ret->datatype = 'N'; if(expr->r->nodetype == S_ARRAY) { ret->d.n = evalStrArrayCmp(estr_l, (struct cnfarray*) expr->r, CMP_STARTSWITH); + bMustFree = 0; } else { ret->d.n = es_strncmp(estr_l, estr_r, estr_r->lenStr) == 0; } @@ -1489,6 +1490,7 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) ret->datatype = 'N'; if(expr->r->nodetype == S_ARRAY) { ret->d.n = evalStrArrayCmp(estr_l, (struct cnfarray*) expr->r, CMP_STARTSWITHI); + bMustFree = 0; } else { ret->d.n = es_strncasecmp(estr_l, estr_r, estr_r->lenStr) == 0; } @@ -1499,6 +1501,7 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) ret->datatype = 'N'; if(expr->r->nodetype == S_ARRAY) { ret->d.n = evalStrArrayCmp(estr_l, (struct cnfarray*) expr->r, CMP_CONTAINS); + bMustFree = 0; } else { ret->d.n = es_strContains(estr_l, estr_r) != -1; } @@ -1509,6 +1512,7 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) ret->datatype = 'N'; if(expr->r->nodetype == S_ARRAY) { ret->d.n = evalStrArrayCmp(estr_l, (struct cnfarray*) expr->r, CMP_CONTAINSI); + bMustFree = 0; } else { ret->d.n = es_strCaseContains(estr_l, estr_r) != -1; } -- cgit v1.2.3 From 8f11516a0efd92f0d6c2fc167faa3f1146596fdd Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 1 Oct 2012 11:11:14 +0200 Subject: refactor: unify nodetypes --- grammar/rainerscript.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 5638ba42..00776a2c 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1223,14 +1223,14 @@ evalStrArrayCmp(es_str_t *estr_l, struct cnfarray* ar, int cmpop) if(expr->r->nodetype == 'S') { \ estr_r = ((struct cnfstringval*)expr->r)->estr;\ bMustFree = 0; \ - } else if(expr->r->nodetype != S_ARRAY) { \ + } else if(expr->r->nodetype != 'A') { \ cnfexprEval(expr->r, &r, usrptr); \ estr_r = var2String(&r, &bMustFree); \ } #define FREE_TWO_STRINGS \ if(bMustFree) es_deleteStr(estr_r); \ - if(expr->r->nodetype != S_ARRAY && r.datatype == 'S') es_deleteStr(r.d.estr); \ + if(expr->r->nodetype != 'A' && r.datatype == 'S') es_deleteStr(r.d.estr); \ if(bMustFree2) es_deleteStr(estr_l); \ if(l.datatype == 'S') es_deleteStr(l.d.estr) @@ -1267,7 +1267,7 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) if(l.datatype == 'S') { if(expr->r->nodetype == 'S') { ret->d.n = !es_strcmp(l.d.estr, ((struct cnfstringval*)expr->r)->estr); /*CMP*/ - } else if(expr->r->nodetype == S_ARRAY) { + } else if(expr->r->nodetype == 'A') { ret->d.n = evalStrArrayCmp(l.d.estr, (struct cnfarray*) expr->r, CMP_EQ); } else { cnfexprEval(expr->r, &r, usrptr); @@ -1310,7 +1310,7 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) if(l.datatype == 'S') { if(expr->r->nodetype == 'S') { ret->d.n = es_strcmp(l.d.estr, ((struct cnfstringval*)expr->r)->estr); /*CMP*/ - } else if(expr->r->nodetype == S_ARRAY) { + } else if(expr->r->nodetype == 'A') { ret->d.n = evalStrArrayCmp(l.d.estr, (struct cnfarray*) expr->r, CMP_NE); } else { if(r.datatype == 'S') { @@ -1477,7 +1477,7 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) case CMP_STARTSWITH: PREP_TWO_STRINGS; ret->datatype = 'N'; - if(expr->r->nodetype == S_ARRAY) { + if(expr->r->nodetype == 'A') { ret->d.n = evalStrArrayCmp(estr_l, (struct cnfarray*) expr->r, CMP_STARTSWITH); bMustFree = 0; } else { @@ -1488,7 +1488,7 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) case CMP_STARTSWITHI: PREP_TWO_STRINGS; ret->datatype = 'N'; - if(expr->r->nodetype == S_ARRAY) { + if(expr->r->nodetype == 'A') { ret->d.n = evalStrArrayCmp(estr_l, (struct cnfarray*) expr->r, CMP_STARTSWITHI); bMustFree = 0; } else { @@ -1499,7 +1499,7 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) case CMP_CONTAINS: PREP_TWO_STRINGS; ret->datatype = 'N'; - if(expr->r->nodetype == S_ARRAY) { + if(expr->r->nodetype == 'A') { ret->d.n = evalStrArrayCmp(estr_l, (struct cnfarray*) expr->r, CMP_CONTAINS); bMustFree = 0; } else { @@ -1510,7 +1510,7 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) case CMP_CONTAINSI: PREP_TWO_STRINGS; ret->datatype = 'N'; - if(expr->r->nodetype == S_ARRAY) { + if(expr->r->nodetype == 'A') { ret->d.n = evalStrArrayCmp(estr_l, (struct cnfarray*) expr->r, CMP_CONTAINSI); bMustFree = 0; } else { @@ -1562,7 +1562,7 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) ret->datatype = 'S'; ret->d.estr = es_strdup(((struct cnfstringval*)expr)->estr); break; - case S_ARRAY: + case 'A': /* if an array is used with "normal" operations, it just evaluates * to its first element. */ @@ -1575,7 +1575,7 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) case '&': /* TODO: think about optimization, should be possible ;) */ PREP_TWO_STRINGS; - if(expr->r->nodetype == S_ARRAY) { + if(expr->r->nodetype == 'A') { estr_r = ((struct cnfarray*)expr->r)->arr[0]; bMustFree = 0; } @@ -1693,7 +1693,7 @@ cnfexprDestruct(struct cnfexpr *expr) case 'F': cnffuncDestruct((struct cnffunc*)expr); break; - case S_ARRAY: + case 'A': cnfarrayContentDestruct((struct cnfarray*)expr); break; default:break; @@ -1841,7 +1841,7 @@ cnfexprPrint(struct cnfexpr *expr, int indent) cstrPrint("string '", ((struct cnfstringval*)expr)->estr); dbgprintf("'\n"); break; - case S_ARRAY: + case 'A': cnfarrayPrint((struct cnfarray*)expr, indent); break; case 'N': @@ -1991,7 +1991,7 @@ cnfarrayNew(es_str_t *val) { struct cnfarray *ar; if((ar = malloc(sizeof(struct cnfarray))) != NULL) { - ar->nodetype = S_ARRAY; + ar->nodetype = 'A'; ar->nmemb = 1; if((ar->arr = malloc(sizeof(es_str_t*))) == NULL) { free(ar); -- cgit v1.2.3 From 11c203c6732ebe939571919ee85f414f0457a017 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 1 Oct 2012 12:00:52 +0200 Subject: implement imtcp "permittedPeers" module-global parameter --- grammar/rainerscript.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 00776a2c..17b482ab 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -52,8 +52,6 @@ DEFobjCurrIf(regexp) void cnfexprOptimize(struct cnfexpr *expr); static void cnfstmtOptimizePRIFilt(struct cnfstmt *stmt); static void cnfarrayPrint(struct cnfarray *ar, int indent); -static void cnfarrayContentDestruct(struct cnfarray *ar); -static struct cnfarray* cnfarrayDup(struct cnfarray *old); char* getFIOPName(unsigned iFIOP) @@ -1619,7 +1617,7 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) //--------------------------------------------------------- -static void +void cnfarrayContentDestruct(struct cnfarray *ar) { unsigned short i; @@ -2019,7 +2017,7 @@ done: return ar; } /* duplicate an array (deep copy) */ -static struct cnfarray* +struct cnfarray* cnfarrayDup(struct cnfarray *old) { int i; -- cgit v1.2.3 From 873e806df047de8ac59a90d850698d7b7c80e58f Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 1 Oct 2012 17:48:36 +0200 Subject: implement RainerScript "call" statement --- grammar/rainerscript.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 17b482ab..2e5381f4 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -45,6 +45,7 @@ #include "regexp.h" #include "obj.h" #include "modules.h" +#include "ruleset.h" DEFobjCurrIf(obj) DEFobjCurrIf(regexp) @@ -1887,6 +1888,7 @@ void cnfstmtPrint(struct cnfstmt *root, int indent) { struct cnfstmt *stmt; + char *cstr; //dbgprintf("stmt %p, indent %d, type '%c'\n", expr, indent, expr->nodetype); for(stmt = root ; stmt != NULL ; stmt = stmt->next) { switch(stmt->nodetype) { @@ -1896,6 +1898,11 @@ cnfstmtPrint(struct cnfstmt *root, int indent) case S_STOP: doIndent(indent); dbgprintf("STOP\n"); break; + case S_CALL: + cstr = es_str2cstr(stmt->d.s_call.name, NULL); + doIndent(indent); dbgprintf("CALL [%s]\n", cstr); + free(cstr); + break; case S_ACT: doIndent(indent); dbgprintf("ACTION %p [%s]\n", stmt->d.act, stmt->printable); break; @@ -1935,7 +1942,6 @@ cnfstmtPrint(struct cnfstmt *root, int indent) doIndent(indent); dbgprintf("\tProperty.: '%s'\n", propIDToName(stmt->d.s_propfilt.propID)); if(stmt->d.s_propfilt.propName != NULL) { - char *cstr; cstr = es_str2cstr(stmt->d.s_propfilt.propName, NULL); doIndent(indent); dbgprintf("\tCEE-Prop.: '%s'\n", cstr); @@ -2061,6 +2067,9 @@ cnfstmtDestruct(struct cnfstmt *root) case S_NOP: case S_STOP: break; + case S_CALL: + es_deleteStr(stmt->d.s_call.name); + break; case S_ACT: actionDestruct(stmt->d.act); break; @@ -2116,6 +2125,16 @@ cnfstmtNewSet(char *var, struct cnfexpr *expr) return cnfstmt; } +struct cnfstmt * +cnfstmtNewCall(es_str_t *name) +{ + struct cnfstmt* cnfstmt; + if((cnfstmt = cnfstmtNew(S_CALL)) != NULL) { + cnfstmt->d.s_call.name = name; + } + return cnfstmt; +} + struct cnfstmt * cnfstmtNewUnset(char *var) { @@ -2461,6 +2480,31 @@ cnfstmtOptimizePRIFilt(struct cnfstmt *stmt) done: return; } +/* we abuse "optimize" a bit. Actually, we obtain a ruleset pointer, as + * all rulesets are only known later in the process (now!). + */ +static void +cnfstmtOptimizeCall(struct cnfstmt *stmt) +{ + ruleset_t *pRuleset; + rsRetVal localRet; + uchar *rsName; + + rsName = (uchar*) es_str2cstr(stmt->d.s_call.name, NULL); + localRet = rulesetGetRuleset(loadConf, &pRuleset, rsName); + if(localRet != RS_RET_OK) { + /* in that case, we accept that a NOP will "survive" */ + parser_errmsg("ruleset '%s' cannot be found\n", rsName); + es_deleteStr(stmt->d.s_call.name); + stmt->nodetype = S_NOP; + goto done; + } + DBGPRINTF("CALL obtained ruleset ptr %p for ruleset %s\n", pRuleset, rsName); + stmt->d.s_call.stmt = pRuleset->root; +done: + free(rsName); + return; +} /* (recursively) optimize a statement */ void cnfstmtOptimize(struct cnfstmt *root) @@ -2486,6 +2530,9 @@ dbgprintf("RRRR: stmtOptimize: stmt %p, nodetype %u\n", stmt, stmt->nodetype); case S_ACT: cnfstmtOptimizeAct(stmt); break; + case S_CALL: + cnfstmtOptimizeCall(stmt); + break; case S_STOP: if(stmt->next != NULL) parser_errmsg("STOP is followed by unreachable statements!\n"); -- cgit v1.2.3 From 81c8658769962dcc988734b23e354dfb1e54fcb0 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 1 Oct 2012 18:26:48 +0200 Subject: bugfix: ruleset(){} directive errornously changed default ruleset much like the $ruleset legacy conf statement. This potentially lead to statements being assigned to the wrong ruleset. --- grammar/rainerscript.c | 1 + 1 file changed, 1 insertion(+) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 2e5381f4..a72b4155 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -2129,6 +2129,7 @@ struct cnfstmt * cnfstmtNewCall(es_str_t *name) { struct cnfstmt* cnfstmt; +dbgprintf("DDDD: got CALL\n"); if((cnfstmt = cnfstmtNew(S_CALL)) != NULL) { cnfstmt->d.s_call.name = name; } -- cgit v1.2.3 From fa541af5778a78e148d3e4a43da7f0d34513ed82 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 1 Oct 2012 18:52:58 +0200 Subject: implement "continue" RainerScript statement --- grammar/rainerscript.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index a72b4155..7e75326c 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -2129,7 +2129,6 @@ struct cnfstmt * cnfstmtNewCall(es_str_t *name) { struct cnfstmt* cnfstmt; -dbgprintf("DDDD: got CALL\n"); if((cnfstmt = cnfstmtNew(S_CALL)) != NULL) { cnfstmt->d.s_call.name = name; } @@ -2146,6 +2145,12 @@ cnfstmtNewUnset(char *var) return cnfstmt; } +struct cnfstmt * +cnfstmtNewContinue(void) +{ + return cnfstmtNew(S_NOP); +} + struct cnfstmt * cnfstmtNewPRIFILT(char *prifilt, struct cnfstmt *t_then) { -- cgit v1.2.3 From 431932d8d63a0f85694c1ec5ec43435a048ffff7 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 9 Oct 2012 15:24:04 +0200 Subject: bugfix: in (non)equal comparisons the position of arrays influenced result This behaviour is OK for "contains"-type of comparisons (which have quite different semantics), but not for == and <>, which shall be commutative. This has been fixed now, so there is no difference any longer if the constant string array is the left or right hand operand. We solved this via the optimizer, as it keeps the actual script execution code small. --- grammar/rainerscript.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 7e75326c..ad6a32e8 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1173,6 +1173,8 @@ evalVar(struct cnfvar *var, void *usrptr, struct var *ret) * that one one comparison is true, the whole construct is true. * TODO: we can obviously optimize this process. One idea is to * compile a regex, which should work faster than serial comparison. + * Note: compiling a regex does NOT work at all. I experimented with that + * and it was generally 5 to 10 times SLOWER than what we do here... */ static int evalStrArrayCmp(es_str_t *estr_l, struct cnfarray* ar, int cmpop) @@ -1756,7 +1758,6 @@ cnfexprPrint(struct cnfexpr *expr, int indent) struct cnffunc *func; int i; - dbgprintf("expr %p, indent %d, type '%c'\n", expr, indent, expr->nodetype); switch(expr->nodetype) { case CMP_EQ: cnfexprPrint(expr->l, indent+1); @@ -2322,6 +2323,7 @@ void cnfexprOptimize(struct cnfexpr *expr) { long long ln, rn; + struct cnfexpr *exprswap; dbgprintf("optimize expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); switch(expr->nodetype) { @@ -2358,6 +2360,19 @@ cnfexprOptimize(struct cnfexpr *expr) ((struct cnfnumval*)expr)->val = ln % rn; } break; + case CMP_NE: + case CMP_EQ: + if(expr->l->nodetype == 'A') { + if(expr->r->nodetype == 'A') { + parser_errmsg("warning: '==' or '<>' " + "comparison of two constant string " + "arrays makes no sense"); + } else { /* swap for simpler execution step */ + exprswap = expr->l; + expr->l = expr->r; + expr->r = exprswap; + } + } default:/* nodetype we cannot optimize */ break; } -- cgit v1.2.3 From d91e8c31a1e342eb15b0839b9e721730fcad0549 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 11 Oct 2012 12:14:55 +0200 Subject: bugfix: some config processing warning messages were treated as errors --- grammar/rainerscript.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index ad6a32e8..a98277af 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -2186,10 +2186,14 @@ cnfstmtNewAct(struct nvlst *lst) { struct cnfstmt* cnfstmt; char namebuf[256]; + rsRetVal localRet; if((cnfstmt = cnfstmtNew(S_ACT)) == NULL) goto done; - if(actionNewInst(lst, &cnfstmt->d.act) != RS_RET_OK) { - // TODO:RS_RET_WARN? + localRet = actionNewInst(lst, &cnfstmt->d.act); + if(localRet == RS_RET_OK_WARN) { + parser_errmsg("warnings occured in file '%s' around line %d", + cnfcurrfn, yylineno); + } else if(actionNewInst(lst, &cnfstmt->d.act) != RS_RET_OK) { parser_errmsg("errors occured in file '%s' around line %d", cnfcurrfn, yylineno); cnfstmt->nodetype = S_NOP; /* disable action! */ -- cgit v1.2.3 From 9fa59604e94f72225180e5fe28d18c4ec3374d61 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 11 Oct 2012 12:22:49 +0200 Subject: bugfixes in regards to action() - bugfix: small memory leak when processing action() statements - bugfix: unknown action() parameters were not reported --- grammar/rainerscript.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index a98277af..be568238 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -2203,6 +2203,8 @@ cnfstmtNewAct(struct nvlst *lst) modGetName(cnfstmt->d.act->pMod)); namebuf[255] = '\0'; /* be on safe side */ cnfstmt->printable = (uchar*)strdup(namebuf); + nvlstChkUnused(lst); + nvlstDestruct(lst); done: return cnfstmt; } -- cgit v1.2.3 From 1b7e8bd1a8c33f317de66dafed4db16923ae394b Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 11 Oct 2012 12:38:17 +0200 Subject: fix regression introduced by last commit action object was created twice, resulting in memleak --- grammar/rainerscript.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index be568238..9483e116 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -2193,7 +2193,7 @@ cnfstmtNewAct(struct nvlst *lst) if(localRet == RS_RET_OK_WARN) { parser_errmsg("warnings occured in file '%s' around line %d", cnfcurrfn, yylineno); - } else if(actionNewInst(lst, &cnfstmt->d.act) != RS_RET_OK) { + } else if(localRet != RS_RET_OK) { parser_errmsg("errors occured in file '%s' around line %d", cnfcurrfn, yylineno); cnfstmt->nodetype = S_NOP; /* disable action! */ -- cgit v1.2.3 From bf1eef67ddfe16682d2733713ec0b2a3301840b9 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 24 Oct 2012 14:44:45 +0200 Subject: cleanup --- grammar/rainerscript.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 9483e116..733ebef4 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -2458,7 +2458,7 @@ cnfstmtOptimizeAct(struct cnfstmt *stmt) action_t *pAct; pAct = stmt->d.act; - if(!strcmp((char*)modGetName(stmt->d.act->pMod), "builtin:omdiscard")) { + if(!strcmp((char*)modGetName(pAct->pMod), "builtin:omdiscard")) { DBGPRINTF("optimizer: replacing omdiscard by STOP\n"); actionDestruct(stmt->d.act); stmt->nodetype = S_STOP; -- cgit v1.2.3 From ec314dabec6cedddb26340c8321f6e59fa29f507 Mon Sep 17 00:00:00 2001 From: oxpa Date: Fri, 2 Nov 2012 17:00:58 +0100 Subject: bugfix: potential segfault when re_match() function was used Thanks to oxpa for the patch. closes: http://bugzilla.adiscon.com/show_bug.cgi?id=371 --- grammar/rainerscript.c | 1 - 1 file changed, 1 deletion(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 733ebef4..36254632 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1099,7 +1099,6 @@ doFuncCall(struct cnffunc *func, struct var *ret, void* usrptr) } ret->datatype = 'N'; if(bMustFree) free(str); - free(str); if(r[0].datatype == 'S') es_deleteStr(r[0].d.estr); break; case CNFFUNC_FIELD: -- cgit v1.2.3 From 275230ceb1b09d2d62e436bd06e6a04a295d3a4d Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 8 Nov 2012 10:55:52 +0100 Subject: bugfix: potential segfault due to invalid param handling in comparisons This could happen in RainerScript comparisons (like contains); in some cases an unitialized variable was accessed, which could lead to an invalid free and in turn to a segfault. Closes: http://bugzilla.adiscon.com/show_bug.cgi?id=372 Thanks to Georgi Georgiev for reporting this bug and his great help in solving it. --- grammar/rainerscript.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 733ebef4..2420ef31 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1231,7 +1231,7 @@ evalStrArrayCmp(es_str_t *estr_l, struct cnfarray* ar, int cmpop) #define FREE_TWO_STRINGS \ if(bMustFree) es_deleteStr(estr_r); \ - if(expr->r->nodetype != 'A' && r.datatype == 'S') es_deleteStr(r.d.estr); \ + if(expr->r->nodetype != 'S' && expr->r->nodetype != 'A' && r.datatype == 'S') es_deleteStr(r.d.estr); \ if(bMustFree2) es_deleteStr(estr_l); \ if(l.datatype == 'S') es_deleteStr(l.d.estr) -- cgit v1.2.3 From dc8f9b531c6c53af7a81a5a378ba1c1514f7a47c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 9 Nov 2012 12:12:17 +0100 Subject: bugfix: $IncludeConfig did not correctly process directories closes: http://bugzilla.adiscon.com/show_bug.cgi?id=376 The testbench was also enhanced to check for these cases. Thanks to Georgi Georgiev for the bug report. Also minor bugfix: no error msg on unreadable $IncludeConfig path --- grammar/rainerscript.c | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 9e0d04c7..072bdd5d 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -680,7 +680,6 @@ nvlstGetParams(struct nvlst *lst, struct cnfparamblk *params, vals = NULL; } -dbgprintf("DDDD: vals %p\n", vals); return vals; } @@ -1818,24 +1817,29 @@ int cnfDoInclude(char *name) { char *cfgFile; + char *finalName; unsigned i; int result; glob_t cfgFiles; struct stat fileInfo; - - /* Use GLOB_MARK to append a trailing slash for directories. - * Required by doIncludeDirectory(). - */ - result = glob(name, GLOB_MARK, NULL, &cfgFiles); - if(result == GLOB_NOSPACE || result == GLOB_ABORTED) { -#if 0 + char nameBuf[MAXFNAME+1]; + + finalName = name; + if(stat(name, &fileInfo) == 0) { + /* stat usually fails if we have a wildcard - so this does NOT indicate error! */ + if(S_ISDIR(fileInfo.st_mode)) { + /* if we have a directory, we need to add "*" to get its files */ + snprintf(nameBuf, sizeof(nameBuf), "%s*", name); + finalName = nameBuf; + } + } + /* Use GLOB_MARK to append a trailing slash for directories. */ + result = glob(finalName, GLOB_MARK, NULL, &cfgFiles); + if(result == GLOB_NOSPACE || result == GLOB_ABORTED || cfgFiles.gl_pathc == 0) { char errStr[1024]; rs_strerror_r(errno, errStr, sizeof(errStr)); - errmsg.LogError(0, RS_RET_FILE_NOT_FOUND, "error accessing config file or directory '%s': %s", - pattern, errStr); - ABORT_FINALIZE(RS_RET_FILE_NOT_FOUND); -#endif - dbgprintf("includeconfig glob error %d\n", errno); + parser_errmsg("error accessing config file or directory '%s': %s", + finalName, errStr); return 1; } @@ -1849,11 +1853,8 @@ cnfDoInclude(char *name) dbgprintf("requested to include config file '%s'\n", cfgFile); cnfSetLexFile(cfgFile); } else if(S_ISDIR(fileInfo.st_mode)) { /* config directory */ - if(strcmp(name, cfgFile)) { - /* do not include ourselves! */ - dbgprintf("requested to include directory '%s'\n", cfgFile); - cnfDoInclude(cfgFile); - } + dbgprintf("requested to include directory '%s'\n", cfgFile); + cnfDoInclude(cfgFile); } else { dbgprintf("warning: unable to process IncludeConfig directive '%s'\n", cfgFile); } -- cgit v1.2.3 From 0f6300f1e6a038f37c406b2362218ea043def55b Mon Sep 17 00:00:00 2001 From: Georgi Georgiev Date: Tue, 13 Nov 2012 09:40:32 +0900 Subject: Silently ignore wildcard includes that match nothing This will avoid an error message when including an empty directory. --- grammar/rainerscript.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 39ff6df3..e54c9060 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -2778,8 +2778,15 @@ cnfDoInclude(char *name) } } /* Use GLOB_MARK to append a trailing slash for directories. */ - result = glob(finalName, GLOB_MARK, NULL, &cfgFiles); - if(result == GLOB_NOSPACE || result == GLOB_ABORTED || cfgFiles.gl_pathc == 0) { + /* Use GLOB_NOMAGIC to detect wildcards that match nothing. */ + result = glob(finalName, GLOB_MARK | GLOB_NOMAGIC, NULL, &cfgFiles); + + /* Silently ignore wildcards that match nothing */ + if(result == GLOB_NOMATCH) { + return 1; + } + + if(result == GLOB_NOSPACE || result == GLOB_ABORTED) { char errStr[1024]; rs_strerror_r(errno, errStr, sizeof(errStr)); parser_errmsg("error accessing config file or directory '%s': %s", @@ -2790,8 +2797,13 @@ cnfDoInclude(char *name) for(i = 0; i < cfgFiles.gl_pathc; i++) { cfgFile = cfgFiles.gl_pathv[i]; - if(stat(cfgFile, &fileInfo) != 0) - continue; /* continue with the next file if we can't stat() the file */ + if(stat(cfgFile, &fileInfo) != 0) + { + char errStr[1024]; + rs_strerror_r(errno, errStr, sizeof(errStr)); + parser_errmsg("error accessing config file or directory '%s': %s", + cfgFile, errStr); + } if(S_ISREG(fileInfo.st_mode)) { /* config file */ dbgprintf("requested to include config file '%s'\n", cfgFile); -- cgit v1.2.3 From 1d10872062828aede81c775bf19023f3ca8f85fa Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 14 Nov 2012 08:49:57 +0100 Subject: make sure inaccessible config file is not tried to be processed The processing loop was not terminated when an unaccessible file was detected, and so processing was done using unitialized data, which could lead to all sorts of problems. Also did some minor cleanup. --- grammar/rainerscript.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index e54c9060..27ff5376 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -2777,6 +2777,7 @@ cnfDoInclude(char *name) finalName = nameBuf; } } + /* Use GLOB_MARK to append a trailing slash for directories. */ /* Use GLOB_NOMAGIC to detect wildcards that match nothing. */ result = glob(finalName, GLOB_MARK | GLOB_NOMAGIC, NULL, &cfgFiles); @@ -2796,13 +2797,12 @@ cnfDoInclude(char *name) for(i = 0; i < cfgFiles.gl_pathc; i++) { cfgFile = cfgFiles.gl_pathv[i]; - - if(stat(cfgFile, &fileInfo) != 0) - { + if(stat(cfgFile, &fileInfo) != 0) { char errStr[1024]; rs_strerror_r(errno, errStr, sizeof(errStr)); parser_errmsg("error accessing config file or directory '%s': %s", cfgFile, errStr); + continue; } if(S_ISREG(fileInfo.st_mode)) { /* config file */ -- cgit v1.2.3 From 1d3c4454403eb038220f8fd075f0bc836b2e03ed Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 20 Nov 2012 10:08:06 +0100 Subject: regression fix: rsyslog terminated when wild-card $includeFile did not find files Unfortunately, this is often the case by default in many distros. --- grammar/rainerscript.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 27ff5376..1116c913 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -2757,6 +2757,9 @@ cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) return func; } +/* returns 0 if everything is OK and config parsing shall continue, + * and 1 if things are so wrong that config parsing shall be aborted. + */ int cnfDoInclude(char *name) { @@ -2784,7 +2787,7 @@ cnfDoInclude(char *name) /* Silently ignore wildcards that match nothing */ if(result == GLOB_NOMATCH) { - return 1; + return 0; } if(result == GLOB_NOSPACE || result == GLOB_ABORTED) { @@ -2802,7 +2805,7 @@ cnfDoInclude(char *name) rs_strerror_r(errno, errStr, sizeof(errStr)); parser_errmsg("error accessing config file or directory '%s': %s", cfgFile, errStr); - continue; + return 1; } if(S_ISREG(fileInfo.st_mode)) { /* config file */ -- cgit v1.2.3 From 4a857f4629d5ca4ff4c59875bc798e70b1811ba9 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 20 Nov 2012 14:31:35 +0100 Subject: improve $IncludeConfig error messages --- grammar/rainerscript.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 1116c913..0dc505a7 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -2770,6 +2770,7 @@ cnfDoInclude(char *name) glob_t cfgFiles; struct stat fileInfo; char nameBuf[MAXFNAME+1]; + char cwdBuf[MAXFNAME+1]; finalName = name; if(stat(name, &fileInfo) == 0) { @@ -2793,8 +2794,9 @@ cnfDoInclude(char *name) if(result == GLOB_NOSPACE || result == GLOB_ABORTED) { char errStr[1024]; rs_strerror_r(errno, errStr, sizeof(errStr)); - parser_errmsg("error accessing config file or directory '%s': %s", - finalName, errStr); + getcwd(cwdBuf, sizeof(cwdBuf)); + parser_errmsg("error accessing config file or directory '%s' [cwd:%s]: %s", + finalName, cwdBuf, errStr); return 1; } @@ -2803,8 +2805,9 @@ cnfDoInclude(char *name) if(stat(cfgFile, &fileInfo) != 0) { char errStr[1024]; rs_strerror_r(errno, errStr, sizeof(errStr)); - parser_errmsg("error accessing config file or directory '%s': %s", - cfgFile, errStr); + getcwd(cwdBuf, sizeof(cwdBuf)); + parser_errmsg("error accessing config file or directory '%s' " + "[cwd: %s]: %s", cfgFile, cwdBuf, errStr); return 1; } -- cgit v1.2.3 From f161dfefd2455547847f0355b7a3a87063780a43 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 28 Nov 2012 10:11:14 +0100 Subject: silence some primarily cosmetic compiler warning messages --- grammar/rainerscript.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 0dc505a7..f7f09697 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -2794,7 +2794,8 @@ cnfDoInclude(char *name) if(result == GLOB_NOSPACE || result == GLOB_ABORTED) { char errStr[1024]; rs_strerror_r(errno, errStr, sizeof(errStr)); - getcwd(cwdBuf, sizeof(cwdBuf)); + if(getcwd(cwdBuf, sizeof(cwdBuf)) == NULL) + strcpy(cwdBuf, "??getcwd() failed??"); parser_errmsg("error accessing config file or directory '%s' [cwd:%s]: %s", finalName, cwdBuf, errStr); return 1; @@ -2805,7 +2806,8 @@ cnfDoInclude(char *name) if(stat(cfgFile, &fileInfo) != 0) { char errStr[1024]; rs_strerror_r(errno, errStr, sizeof(errStr)); - getcwd(cwdBuf, sizeof(cwdBuf)); + if(getcwd(cwdBuf, sizeof(cwdBuf)) == NULL) + strcpy(cwdBuf, "??getcwd() failed??"); parser_errmsg("error accessing config file or directory '%s' " "[cwd: %s]: %s", cfgFile, cwdBuf, errStr); return 1; -- cgit v1.2.3 From 62f6a7d7b4b3c9fee0fffea961a201d24a059b2c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 30 Nov 2012 17:09:28 +0100 Subject: fix missing functionality: ruleset(){} could not specify ruleset queue The "queue.xxx" parameter set was not supported, and legacy ruleset config statements did not work (by intention). The fix introduces the "queue.xxx" parameter set. It has some regression potential, but only for the new functionality. Note that using that interface it is possible to specify duplicate queue file names, which will cause trouble. This will be solved in v7.3, because there is a too-large regression potential for the v7.2 stable branch. --- grammar/rainerscript.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index f7f09697..6b21bc9a 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -802,6 +802,30 @@ nvlstGetParams(struct nvlst *lst, struct cnfparamblk *params, } +/* check if at least one cnfparamval is actually set + * returns 1 if so, 0 otherwise + */ +int +cnfparamvalsIsSet(struct cnfparamblk *params, struct cnfparamvals *vals) +{ + int i; + + if(vals == NULL) + return 0; + if(params->version != CNFPARAMBLK_VERSION) { + dbgprintf("nvlstGetParams: invalid param block version " + "%d, expected %d\n", + params->version, CNFPARAMBLK_VERSION); + return 0; + } + for(i = 0 ; i < params->nParams ; ++i) { + if(vals[i].bUsed) + return 1; + } + return 0; +} + + void cnfparamsPrint(struct cnfparamblk *params, struct cnfparamvals *vals) { -- cgit v1.2.3 From 66654e116395e8cf3d40e83453e212b670abb632 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 11 Dec 2012 10:02:00 +0100 Subject: enhance optimizer: detect eq-comparison for syslog facility ... and replace it with a (much faster) prifilt() call --- grammar/rainerscript.c | 140 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 131 insertions(+), 9 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index f7f09697..d39d5f2a 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -50,9 +50,69 @@ DEFobjCurrIf(obj) DEFobjCurrIf(regexp) -void cnfexprOptimize(struct cnfexpr *expr); +struct cnfexpr* cnfexprOptimize(struct cnfexpr *expr); static void cnfstmtOptimizePRIFilt(struct cnfstmt *stmt); static void cnfarrayPrint(struct cnfarray *ar, int indent); +struct cnffunc * cnffuncNew_prifilt(int fac); + +/* debug support: convert token to a human-readable string. Note that + * this function only supports a single thread due to a static buffer. + * This is deemed a solid solution, as it is intended to be used during + * startup, only. + * NOTE: This function MUST be updated if new tokens are defined in the + * grammar. + */ +char * +tokenToString(int token) +{ + char *tokstr; + static char tokbuf[512]; + + switch(token) { + case NAME: tokstr = "NAME"; break; + case FUNC: tokstr = "FUNC"; break; + case BEGINOBJ: tokstr ="BEGINOBJ"; break; + case ENDOBJ: tokstr ="ENDOBJ"; break; + case BEGIN_ACTION: tokstr ="BEGIN_ACTION"; break; + case BEGIN_PROPERTY: tokstr ="BEGIN_PROPERTY"; break; + case BEGIN_CONSTANT: tokstr ="BEGIN_CONSTANT"; break; + case BEGIN_TPL: tokstr ="BEGIN_TPL"; break; + case BEGIN_RULESET: tokstr ="BEGIN_RULESET"; break; + case STOP: tokstr ="STOP"; break; + case SET: tokstr ="SET"; break; + case UNSET: tokstr ="UNSET"; break; + case CONTINUE: tokstr ="CONTINUE"; break; + case CALL: tokstr ="CALL"; break; + case LEGACY_ACTION: tokstr ="LEGACY_ACTION"; break; + case LEGACY_RULESET: tokstr ="LEGACY_RULESET"; break; + case PRIFILT: tokstr ="PRIFILT"; break; + case PROPFILT: tokstr ="PROPFILT"; break; + case IF: tokstr ="IF"; break; + case THEN: tokstr ="THEN"; break; + case ELSE: tokstr ="ELSE"; break; + case OR: tokstr ="OR"; break; + case AND: tokstr ="AND"; break; + case NOT: tokstr ="NOT"; break; + case VAR: tokstr ="VAR"; break; + case STRING: tokstr ="STRING"; break; + case NUMBER: tokstr ="NUMBER"; break; + case CMP_EQ: tokstr ="CMP_EQ"; break; + case CMP_NE: tokstr ="CMP_NE"; break; + case CMP_LE: tokstr ="CMP_LE"; break; + case CMP_GE: tokstr ="CMP_GE"; break; + case CMP_LT: tokstr ="CMP_LT"; break; + case CMP_GT: tokstr ="CMP_GT"; break; + case CMP_CONTAINS: tokstr ="CMP_CONTAINS"; break; + case CMP_CONTAINSI: tokstr ="CMP_CONTAINSI"; break; + case CMP_STARTSWITH: tokstr ="CMP_STARTSWITH"; break; + case CMP_STARTSWITHI: tokstr ="CMP_STARTSWITHI"; break; + case UMINUS: tokstr ="UMINUS"; break; + default: snprintf(tokbuf, sizeof(tokbuf), "%c[%d]", token, token); + tokstr = tokbuf; break; + } + return tokstr; +} + char* getFIOPName(unsigned iFIOP) @@ -275,8 +335,8 @@ nvlstPrint(struct nvlst *lst) dbgprintf("\tname: '%s', value '%s'\n", name, value); free(value); break; - default:dbgprintf("nvlstPrint: unknown type '%c' [%d]\n", - lst->val.datatype, lst->val.datatype); + default:dbgprintf("nvlstPrint: unknown type '%s'\n", + tokenToString(lst->val.datatype)); break; } free(name); @@ -1253,7 +1313,7 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) int bMustFree, bMustFree2; long long n_r, n_l; - dbgprintf("eval expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); + dbgprintf("eval expr %p, type '%s'\n", expr, tokenToString(expr->nodetype)); switch(expr->nodetype) { /* note: comparison operations are extremely similar. The code can be copyied, only * places flagged with "CMP" need to be changed. @@ -1655,7 +1715,7 @@ void cnfexprDestruct(struct cnfexpr *expr) { - dbgprintf("cnfexprDestruct expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); + dbgprintf("cnfexprDestruct expr %p, type '%s'\n", expr, tokenToString(expr->nodetype)); switch(expr->nodetype) { case CMP_NE: case CMP_EQ: @@ -2323,14 +2383,41 @@ constFoldConcat(struct cnfexpr *expr) } +/* optimize a comparison with a variable as left-hand operand */ +static inline struct cnfexpr* +cnfexprOptimize_CMP_var(struct cnfexpr *expr) +{ + struct cnffunc *func; + + dbgprintf("VAR, name is '%s'\n", ((struct cnfvar*)expr->l)->name); + if(!strcmp("$syslogfacility-text", ((struct cnfvar*)expr->l)->name)) { + if(expr->r->nodetype == 'S') { + char *cstr = es_str2cstr(((struct cnfstringval*)expr->r)->estr, NULL); + int fac = decodeSyslogName((uchar*)cstr, syslogFacNames); + if(fac == -1) { + parser_errmsg("invalid facility '%s', expression will always " + "evaluate to FALSE", cstr); + } else { + /* we can acutally optimize! */ + DBGPRINTF("optimizer: change comparison OP to FUNC prifilt()\n"); + cnfexprDestruct(expr); + func = cnffuncNew_prifilt(fac); + expr = (struct cnfexpr*) func; + } + free(cstr); + } + } + return expr; +} + /* (recursively) optimize an expression */ -void +struct cnfexpr* cnfexprOptimize(struct cnfexpr *expr) { long long ln, rn; struct cnfexpr *exprswap; - dbgprintf("optimize expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); + dbgprintf("optimize expr %p, type '%s'\n", expr, tokenToString(expr->nodetype)); switch(expr->nodetype) { case '&': constFoldConcat(expr); @@ -2367,6 +2454,8 @@ cnfexprOptimize(struct cnfexpr *expr) break; case CMP_NE: case CMP_EQ: + expr->l = cnfexprOptimize(expr->l); + expr->r = cnfexprOptimize(expr->r); if(expr->l->nodetype == 'A') { if(expr->r->nodetype == 'A') { parser_errmsg("warning: '==' or '<>' " @@ -2377,11 +2466,22 @@ cnfexprOptimize(struct cnfexpr *expr) expr->l = expr->r; expr->r = exprswap; } + } else if(expr->l->nodetype == 'V') { + expr = cnfexprOptimize_CMP_var(expr); } - default:/* nodetype we cannot optimize */ + break; + case AND: + case OR:/* keep recursion goin' on... */ + expr->l = cnfexprOptimize(expr->l); + expr->r = cnfexprOptimize(expr->r); + break; + case NOT:/* keep recursion goin' on... */ + expr->r = cnfexprOptimize(expr->r); + break; + default:/* nodetypes we cannot optimize */ break; } - + return expr; } /* removes NOPs from a statement list and returns the @@ -2715,6 +2815,7 @@ finalize_it: RETiRet; } + struct cnffunc * cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) { @@ -2757,6 +2858,27 @@ cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) return func; } + +/* A special function to create a prifilt() expression during optimization + * phase. + */ +struct cnffunc * +cnffuncNew_prifilt(int fac) +{ + struct cnffunc* func; + + if((func = malloc(sizeof(struct cnffunc))) != NULL) { + func->nodetype = 'F'; + func->fname = es_newStrFromCStr("prifilt", sizeof("prifilt")-1); + func->nParams = 0; + func->fID = CNFFUNC_PRIFILT; + func->funcdata = calloc(1, sizeof(struct funcData_prifilt)); + ((struct funcData_prifilt *)func->funcdata)->pmask[fac >> 3] = TABLE_ALLPRI; + } + return func; +} + + /* returns 0 if everything is OK and config parsing shall continue, * and 1 if things are so wrong that config parsing shall be aborted. */ -- cgit v1.2.3 From b49e20f0912f77dc9f4e3b849b11aed5d915a7d8 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 11 Dec 2012 11:11:15 +0100 Subject: script optimizer: support NOT pri matches --- grammar/rainerscript.c | 46 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index d39d5f2a..413964d6 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -144,6 +144,15 @@ getFIOPName(unsigned iFIOP) return pRet; } +static void +prifiltInvert(struct funcData_prifilt *prifilt) +{ + int i; + for(i = 0 ; i < LOG_NFACILITIES+1 ; ++i) { + prifilt->pmask[i] = ~prifilt->pmask[i]; + } +} + void readConfFile(FILE *fp, es_str_t **str) @@ -1715,7 +1724,13 @@ void cnfexprDestruct(struct cnfexpr *expr) { - dbgprintf("cnfexprDestruct expr %p, type '%s'\n", expr, tokenToString(expr->nodetype)); + if(expr == NULL) { + /* this is valid and can happen during optimizer run! */ + DBGPRINTF("cnfexprDestruct got NULL ptr - valid, so doing nothing\n"); + return; + } + + DBGPRINTF("cnfexprDestruct expr %p, type '%s'\n", expr, tokenToString(expr->nodetype)); switch(expr->nodetype) { case CMP_NE: case CMP_EQ: @@ -2383,13 +2398,15 @@ constFoldConcat(struct cnfexpr *expr) } -/* optimize a comparison with a variable as left-hand operand */ +/* optimize a comparison with a variable as left-hand operand + * NOTE: Currently support CMP_EQ, CMP_NE only and code NEEDS + * TO BE CHANGED for other comparisons! + */ static inline struct cnfexpr* cnfexprOptimize_CMP_var(struct cnfexpr *expr) { struct cnffunc *func; - dbgprintf("VAR, name is '%s'\n", ((struct cnfvar*)expr->l)->name); if(!strcmp("$syslogfacility-text", ((struct cnfvar*)expr->l)->name)) { if(expr->r->nodetype == 'S') { char *cstr = es_str2cstr(((struct cnfstringval*)expr->r)->estr, NULL); @@ -2400,8 +2417,10 @@ cnfexprOptimize_CMP_var(struct cnfexpr *expr) } else { /* we can acutally optimize! */ DBGPRINTF("optimizer: change comparison OP to FUNC prifilt()\n"); - cnfexprDestruct(expr); func = cnffuncNew_prifilt(fac); + if(expr->nodetype == CMP_NE) + prifiltInvert(func->funcdata); + cnfexprDestruct(expr); expr = (struct cnfexpr*) func; } free(cstr); @@ -2410,6 +2429,24 @@ cnfexprOptimize_CMP_var(struct cnfexpr *expr) return expr; } +static inline struct cnfexpr* +cnfexprOptimize_NOT(struct cnfexpr *expr) +{ + struct cnffunc *func; + + if(expr->r->nodetype == 'F') { + func = (struct cnffunc *)expr->r; + if(func->fID == CNFFUNC_PRIFILT) { + DBGPRINTF("optimize NOT prifilt() to inverted prifilt()\n"); + expr->r = NULL; + cnfexprDestruct(expr); + prifiltInvert(func->funcdata); + expr = (struct cnfexpr*) func; + } + } + return expr; +} + /* (recursively) optimize an expression */ struct cnfexpr* cnfexprOptimize(struct cnfexpr *expr) @@ -2477,6 +2514,7 @@ cnfexprOptimize(struct cnfexpr *expr) break; case NOT:/* keep recursion goin' on... */ expr->r = cnfexprOptimize(expr->r); + expr = cnfexprOptimize_NOT(expr); break; default:/* nodetypes we cannot optimize */ break; -- cgit v1.2.3 From 79e09b2bf8167e281beab0115ea280914f428919 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 11 Dec 2012 11:24:05 +0100 Subject: script optimizer: optimize and/or on PRI filters --- grammar/rainerscript.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 413964d6..5d68d944 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -153,6 +153,21 @@ prifiltInvert(struct funcData_prifilt *prifilt) } } +/* combine a prifilt with AND/OR (the respective token values are + * used to keep things simple). + */ +static void +prifiltCombine(struct funcData_prifilt *prifilt, struct funcData_prifilt *prifilt2, int mode) +{ + int i; + for(i = 0 ; i < LOG_NFACILITIES+1 ; ++i) { + if(mode == AND) + prifilt->pmask[i] = prifilt->pmask[i] & prifilt2->pmask[i]; + else + prifilt->pmask[i] = prifilt->pmask[i] | prifilt2->pmask[i]; + } +} + void readConfFile(FILE *fp, es_str_t **str) @@ -2447,6 +2462,27 @@ cnfexprOptimize_NOT(struct cnfexpr *expr) return expr; } +static inline struct cnfexpr* +cnfexprOptimize_AND_OR(struct cnfexpr *expr) +{ + struct cnffunc *funcl, *funcr; + + if(expr->l->nodetype == 'F') { + if(expr->r->nodetype == 'F') { + funcl = (struct cnffunc *)expr->l; + funcr = (struct cnffunc *)expr->r; + if(funcl->fID == CNFFUNC_PRIFILT && funcr->fID == CNFFUNC_PRIFILT) { + DBGPRINTF("optimize combine AND/OR prifilt()\n"); + expr->l = NULL; + prifiltCombine(funcl->funcdata, funcr->funcdata, expr->nodetype); + cnfexprDestruct(expr); + expr = (struct cnfexpr*) funcl; + } + } + } + return expr; +} + /* (recursively) optimize an expression */ struct cnfexpr* cnfexprOptimize(struct cnfexpr *expr) @@ -2511,6 +2547,7 @@ cnfexprOptimize(struct cnfexpr *expr) case OR:/* keep recursion goin' on... */ expr->l = cnfexprOptimize(expr->l); expr->r = cnfexprOptimize(expr->r); + expr = cnfexprOptimize_AND_OR(expr); break; case NOT:/* keep recursion goin' on... */ expr->r = cnfexprOptimize(expr->r); -- cgit v1.2.3 From 39b75f728860597b26cd93bbc297ad9eac6fea1f Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 11 Dec 2012 11:28:00 +0100 Subject: bugfix: optimizer stopped prematurely on some operations --- grammar/rainerscript.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 5d68d944..8284d87a 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -2543,6 +2543,17 @@ cnfexprOptimize(struct cnfexpr *expr) expr = cnfexprOptimize_CMP_var(expr); } break; + case CMP_LE: + case CMP_GE: + case CMP_LT: + case CMP_GT: + case CMP_CONTAINS: + case CMP_CONTAINSI: + case CMP_STARTSWITH: + case CMP_STARTSWITHI: + expr->l = cnfexprOptimize(expr->l); + expr->r = cnfexprOptimize(expr->r); + break; case AND: case OR:/* keep recursion goin' on... */ expr->l = cnfexprOptimize(expr->l); -- cgit v1.2.3 From b2a7f20af7fa6bc54de132dffe2c2e9108ca2889 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 11 Dec 2012 12:27:16 +0100 Subject: script optimizer: severity eq/ne to prifilt() --- grammar/rainerscript.c | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 8284d87a..27b22487 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -153,6 +153,22 @@ prifiltInvert(struct funcData_prifilt *prifilt) } } +/* set prifilt so that it matches for all severities, sev is its numerical + * value. Mode is one of the compop tokens CMP_EQ, CMP_LT, CMP_LE, CMP_GT, + * CMP_GE, CMP_NE. + */ +static void +prifiltSetSeverity(struct funcData_prifilt *prifilt, int sev, int mode) +{ + int i; + for(i = 0 ; i < LOG_NFACILITIES+1 ; ++i) { + if(mode == CMP_EQ || mode == CMP_NE) + prifilt->pmask[i] = 1 << sev; + } + if(mode == CMP_NE) + prifiltInvert(prifilt); +} + /* combine a prifilt with AND/OR (the respective token values are * used to keep things simple). */ @@ -2440,6 +2456,20 @@ cnfexprOptimize_CMP_var(struct cnfexpr *expr) } free(cstr); } + } else if(!strcmp("$syslogseverity", ((struct cnfvar*)expr->l)->name)) { + if(expr->r->nodetype == 'N') { + int sev = (int) ((struct cnfnumval*)expr->r)->val; + if(sev >= 0 && sev <= 7) { + DBGPRINTF("optimizer: change comparison OP to FUNC prifilt()\n"); + func = cnffuncNew_prifilt(0); /* fac is irrelevant, set below... */ + prifiltSetSeverity(func->funcdata, sev, expr->nodetype); + cnfexprDestruct(expr); + expr = (struct cnfexpr*) func; + } else { + parser_errmsg("invalid syslogseverity %d, expression will always " + "evaluate to FALSE", sev); + } + } } return expr; } @@ -2610,8 +2640,7 @@ cnfstmtOptimizeIf(struct cnfstmt *stmt) struct cnffunc *func; struct funcData_prifilt *prifilt; - expr = stmt->d.s_if.expr; - cnfexprOptimize(expr); + expr = stmt->d.s_if.expr = cnfexprOptimize(stmt->d.s_if.expr); stmt->d.s_if.t_then = removeNOPs(stmt->d.s_if.t_then); stmt->d.s_if.t_else = removeNOPs(stmt->d.s_if.t_else); cnfstmtOptimize(stmt->d.s_if.t_then); @@ -2629,8 +2658,11 @@ cnfstmtOptimizeIf(struct cnfstmt *stmt) sizeof(prifilt->pmask)); stmt->d.s_prifilt.t_then = t_then; stmt->d.s_prifilt.t_else = t_else; - stmt->printable = (uchar*) - es_str2cstr(((struct cnfstringval*)func->expr[0])->estr, NULL); + if(func->nParams == 0) + stmt->printable = (uchar*)strdup("[Optimizer Result]"); + else + stmt->printable = (uchar*) + es_str2cstr(((struct cnfstringval*)func->expr[0])->estr, NULL); cnfexprDestruct(expr); cnfstmtOptimizePRIFilt(stmt); } @@ -2737,7 +2769,7 @@ dbgprintf("RRRR: stmtOptimize: stmt %p, nodetype %u\n", stmt, stmt->nodetype); cnfstmtOptimize(stmt->d.s_propfilt.t_then); break; case S_SET: - cnfexprOptimize(stmt->d.s_set.expr); + stmt->d.s_set.expr = cnfexprOptimize(stmt->d.s_set.expr); break; case S_ACT: cnfstmtOptimizeAct(stmt); -- cgit v1.2.3 From a71660d49804caec0e0beb0cfaa2b5cd64fc1af6 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 11 Dec 2012 12:53:39 +0100 Subject: script optimizer: severity lt/le/gt/ge to prifilt() --- grammar/rainerscript.c | 62 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 46 insertions(+), 16 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 27b22487..353d012e 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -160,10 +160,22 @@ prifiltInvert(struct funcData_prifilt *prifilt) static void prifiltSetSeverity(struct funcData_prifilt *prifilt, int sev, int mode) { + static int lessthanmasks[] = { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; int i; for(i = 0 ; i < LOG_NFACILITIES+1 ; ++i) { if(mode == CMP_EQ || mode == CMP_NE) prifilt->pmask[i] = 1 << sev; + else if(mode == CMP_LT) + prifilt->pmask[i] = lessthanmasks[sev]; + else if(mode == CMP_LE) + prifilt->pmask[i] = lessthanmasks[sev+1]; + else if(mode == CMP_GT) + prifilt->pmask[i] = ~lessthanmasks[sev+1]; + else if(mode == CMP_GE) + prifilt->pmask[i] = ~lessthanmasks[sev]; + else + DBGPRINTF("prifiltSetSeverity: program error, invalid mode %s\n", + tokenToString(mode)); } if(mode == CMP_NE) prifiltInvert(prifilt); @@ -2429,6 +2441,32 @@ constFoldConcat(struct cnfexpr *expr) } +/* optimize comparisons with syslog severity. This is a special + * handler as the numerical values also support GT, LT, etc ops. + */ +static inline struct cnfexpr* +cnfexprOptimize_CMP_severity(struct cnfexpr *expr) +{ + struct cnffunc *func; + + if(!strcmp("$syslogseverity", ((struct cnfvar*)expr->l)->name)) { + if(expr->r->nodetype == 'N') { + int sev = (int) ((struct cnfnumval*)expr->r)->val; + if(sev >= 0 && sev <= 7) { + DBGPRINTF("optimizer: change comparison OP to FUNC prifilt()\n"); + func = cnffuncNew_prifilt(0); /* fac is irrelevant, set below... */ + prifiltSetSeverity(func->funcdata, sev, expr->nodetype); + cnfexprDestruct(expr); + expr = (struct cnfexpr*) func; + } else { + parser_errmsg("invalid syslogseverity %d, expression will always " + "evaluate to FALSE", sev); + } + } + } + return expr; +} + /* optimize a comparison with a variable as left-hand operand * NOTE: Currently support CMP_EQ, CMP_NE only and code NEEDS * TO BE CHANGED for other comparisons! @@ -2456,20 +2494,8 @@ cnfexprOptimize_CMP_var(struct cnfexpr *expr) } free(cstr); } - } else if(!strcmp("$syslogseverity", ((struct cnfvar*)expr->l)->name)) { - if(expr->r->nodetype == 'N') { - int sev = (int) ((struct cnfnumval*)expr->r)->val; - if(sev >= 0 && sev <= 7) { - DBGPRINTF("optimizer: change comparison OP to FUNC prifilt()\n"); - func = cnffuncNew_prifilt(0); /* fac is irrelevant, set below... */ - prifiltSetSeverity(func->funcdata, sev, expr->nodetype); - cnfexprDestruct(expr); - expr = (struct cnfexpr*) func; - } else { - parser_errmsg("invalid syslogseverity %d, expression will always " - "evaluate to FALSE", sev); - } - } + } else { + expr = cnfexprOptimize_CMP_severity(expr); } return expr; } @@ -2577,6 +2603,10 @@ cnfexprOptimize(struct cnfexpr *expr) case CMP_GE: case CMP_LT: case CMP_GT: + expr->l = cnfexprOptimize(expr->l); + expr->r = cnfexprOptimize(expr->r); + expr = cnfexprOptimize_CMP_severity(expr); + break; case CMP_CONTAINS: case CMP_CONTAINSI: case CMP_STARTSWITH: @@ -2585,12 +2615,12 @@ cnfexprOptimize(struct cnfexpr *expr) expr->r = cnfexprOptimize(expr->r); break; case AND: - case OR:/* keep recursion goin' on... */ + case OR: expr->l = cnfexprOptimize(expr->l); expr->r = cnfexprOptimize(expr->r); expr = cnfexprOptimize_AND_OR(expr); break; - case NOT:/* keep recursion goin' on... */ + case NOT: expr->r = cnfexprOptimize(expr->r); expr = cnfexprOptimize_NOT(expr); break; -- cgit v1.2.3 From 3c9fb9017fedcc0637f235e4c348287112f18447 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 11 Dec 2012 15:36:34 +0100 Subject: script optimizer: support numerical facilities in compare operations as well --- grammar/rainerscript.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 5 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 353d012e..e4c4f519 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -153,7 +153,7 @@ prifiltInvert(struct funcData_prifilt *prifilt) } } -/* set prifilt so that it matches for all severities, sev is its numerical +/* set prifilt so that it matches for some severities, sev is its numerical * value. Mode is one of the compop tokens CMP_EQ, CMP_LT, CMP_LE, CMP_GT, * CMP_GE, CMP_NE. */ @@ -181,6 +181,45 @@ prifiltSetSeverity(struct funcData_prifilt *prifilt, int sev, int mode) prifiltInvert(prifilt); } +/* set prifilt so that it matches for some facilities, fac is its numerical + * value. Mode is one of the compop tokens CMP_EQ, CMP_LT, CMP_LE, CMP_GT, + * CMP_GE, CMP_NE. For the given facilities, all severities are enabled. + * NOTE: fac MUST be in the range 0..24 (not multiplied by 8)! + */ +static void +prifiltSetFacility(struct funcData_prifilt *prifilt, int fac, int mode) +{ + int i; + + memset(prifilt->pmask, 0, sizeof(prifilt->pmask)); + switch(mode) { + case CMP_EQ: + prifilt->pmask[fac] = TABLE_ALLPRI; + break; + case CMP_NE: + prifilt->pmask[fac] = TABLE_ALLPRI; + prifiltInvert(prifilt); + break; + case CMP_LT: + for(i = 0 ; i < fac ; ++i) + prifilt->pmask[i] = TABLE_ALLPRI; + break; + case CMP_LE: + for(i = 0 ; i < fac+1 ; ++i) + prifilt->pmask[i] = TABLE_ALLPRI; + break; + case CMP_GE: + for(i = fac ; i < LOG_NFACILITIES+1 ; ++i) + prifilt->pmask[i] = TABLE_ALLPRI; + break; + case CMP_GT: + for(i = fac+1 ; i < LOG_NFACILITIES+1 ; ++i) + prifilt->pmask[i] = TABLE_ALLPRI; + break; + default:break; + } +} + /* combine a prifilt with AND/OR (the respective token values are * used to keep things simple). */ @@ -2441,11 +2480,11 @@ constFoldConcat(struct cnfexpr *expr) } -/* optimize comparisons with syslog severity. This is a special +/* optimize comparisons with syslog severity/facility. This is a special * handler as the numerical values also support GT, LT, etc ops. */ static inline struct cnfexpr* -cnfexprOptimize_CMP_severity(struct cnfexpr *expr) +cnfexprOptimize_CMP_severity_facility(struct cnfexpr *expr) { struct cnffunc *func; @@ -2463,6 +2502,20 @@ cnfexprOptimize_CMP_severity(struct cnfexpr *expr) "evaluate to FALSE", sev); } } + } else if(!strcmp("$syslogfacility", ((struct cnfvar*)expr->l)->name)) { + if(expr->r->nodetype == 'N') { + int fac = (int) ((struct cnfnumval*)expr->r)->val; + if(fac >= 0 && fac <= 24) { + DBGPRINTF("optimizer: change comparison OP to FUNC prifilt()\n"); + func = cnffuncNew_prifilt(0); /* fac is irrelevant, set below... */ + prifiltSetFacility(func->funcdata, fac, expr->nodetype); + cnfexprDestruct(expr); + expr = (struct cnfexpr*) func; + } else { + parser_errmsg("invalid syslogfacility %d, expression will always " + "evaluate to FALSE", fac); + } + } } return expr; } @@ -2495,7 +2548,7 @@ cnfexprOptimize_CMP_var(struct cnfexpr *expr) free(cstr); } } else { - expr = cnfexprOptimize_CMP_severity(expr); + expr = cnfexprOptimize_CMP_severity_facility(expr); } return expr; } @@ -2605,7 +2658,7 @@ cnfexprOptimize(struct cnfexpr *expr) case CMP_GT: expr->l = cnfexprOptimize(expr->l); expr->r = cnfexprOptimize(expr->r); - expr = cnfexprOptimize_CMP_severity(expr); + expr = cnfexprOptimize_CMP_severity_facility(expr); break; case CMP_CONTAINS: case CMP_CONTAINSI: -- cgit v1.2.3 From a8437e146808ee68c9b5979767a186a3da079107 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 11 Dec 2012 15:46:08 +0100 Subject: script optimizer: support textual severities in compare operations as well --- grammar/rainerscript.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index e4c4f519..8f20bfcd 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -2547,6 +2547,23 @@ cnfexprOptimize_CMP_var(struct cnfexpr *expr) } free(cstr); } + } else if(!strcmp("$syslogseverity-text", ((struct cnfvar*)expr->l)->name)) { + if(expr->r->nodetype == 'S') { + char *cstr = es_str2cstr(((struct cnfstringval*)expr->r)->estr, NULL); + int sev = decodeSyslogName((uchar*)cstr, syslogPriNames); + if(sev == -1) { + parser_errmsg("invalid syslogseverity '%s', expression will always " + "evaluate to FALSE", cstr); + } else { + /* we can acutally optimize! */ + DBGPRINTF("optimizer: change comparison OP to FUNC prifilt()\n"); + func = cnffuncNew_prifilt(0); + prifiltSetSeverity(func->funcdata, sev, expr->nodetype); + cnfexprDestruct(expr); + expr = (struct cnfexpr*) func; + } + free(cstr); + } } else { expr = cnfexprOptimize_CMP_severity_facility(expr); } -- cgit v1.2.3 From db01eab26b163362652afa7931762de1aafb4c32 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 18 Dec 2012 12:33:36 +0100 Subject: cosmetic: silence compiler warning --- grammar/rainerscript.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 6b21bc9a..c5f2148e 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1250,6 +1250,10 @@ evalStrArrayCmp(es_str_t *estr_l, struct cnfarray* ar, int cmpop) } else if(expr->r->nodetype != 'A') { \ cnfexprEval(expr->r, &r, usrptr); \ estr_r = var2String(&r, &bMustFree); \ + } else { \ + /* Note: this is not really necessary, but if we do not */ \ + /* do it, we get a very irritating compiler warning... */ \ + estr_r = NULL; \ } #define FREE_TWO_STRINGS \ -- cgit v1.2.3 From 3b0f635bd579c4cc00e189871e77ef120a6c6a4d Mon Sep 17 00:00:00 2001 From: Chandler Latour Date: Tue, 8 Jan 2013 12:01:10 +0100 Subject: bugfix: doGetFileCreateMode() had invalid validity check ;) --- grammar/rainerscript.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index c5f2148e..0584d6a9 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -463,17 +463,17 @@ doGetFileCreateMode(struct nvlst *valnode, struct cnfparamdescr *param, if(es_strlen(valnode->val.d.estr) == 4) { c = es_getBufAddr(valnode->val.d.estr); - if(!( (c[0] == '0') - && (c[1] >= '0' && c[1] <= '7') - && (c[2] >= '0' && c[2] <= '7') - && (c[3] >= '0' && c[3] <= '7') ) ) { + if( (c[0] == '0') + && (c[1] >= '0' && c[1] <= '7') + && (c[2] >= '0' && c[2] <= '7') + && (c[3] >= '0' && c[3] <= '7') ) { fmtOK = 1; } } if(fmtOK) { val->val.datatype = 'N'; - val->val.d.n = (c[1]-'0') * 64 + (c[2]-'0') * 8 + (c[3]-'0');; + val->val.d.n = (c[1]-'0') * 64 + (c[2]-'0') * 8 + (c[3]-'0'); } else { cstr = es_str2cstr(valnode->val.d.estr, NULL); parser_errmsg("file modes need to be specified as " -- cgit v1.2.3 From d748ba250ea9cf77866f50bbcc8bd1fd97ee9c72 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sun, 27 Jan 2013 12:36:22 +0100 Subject: optimize: use binary search on EQ/NEQ array matches Conflicts: grammar/rainerscript.c --- grammar/rainerscript.c | 66 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 20 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 8c79cc5d..69f77c50 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -287,6 +287,14 @@ readConfFile(FILE *fp, es_str_t **str) es_addChar(str, '\0'); } +/* comparison function for qsort() and bsearch() string array compare */ +static int +qs_arrcmp(const void *s1, const void *s2) +{ + return es_strcmp(*((es_str_t**)s1), *((es_str_t**)s2)); +} + + struct objlst* objlstNew(struct cnfobj *o) { @@ -1355,26 +1363,29 @@ evalStrArrayCmp(es_str_t *estr_l, struct cnfarray* ar, int cmpop) { int i; int r = 0; - for(i = 0 ; (r == 0) && (i < ar->nmemb) ; ++i) { - switch(cmpop) { - case CMP_EQ: - r = es_strcmp(estr_l, ar->arr[i]) == 0; - break; - case CMP_NE: - r = es_strcmp(estr_l, ar->arr[i]) != 0; - break; - case CMP_STARTSWITH: - r = es_strncmp(estr_l, ar->arr[i], es_strlen(ar->arr[i])) == 0; - break; - case CMP_STARTSWITHI: - r = es_strncasecmp(estr_l, ar->arr[i], es_strlen(ar->arr[i])) == 0; - break; - case CMP_CONTAINS: - r = es_strContains(estr_l, ar->arr[i]) != -1; - break; - case CMP_CONTAINSI: - r = es_strCaseContains(estr_l, ar->arr[i]) != -1; - break; + es_str_t **res; + if(cmpop == CMP_EQ) { + res = bsearch(&estr_l, ar->arr, ar->nmemb, sizeof(es_str_t*), qs_arrcmp); + r = res != NULL; + } else if(cmpop == CMP_NE) { + res = bsearch(&estr_l, ar->arr, ar->nmemb, sizeof(es_str_t*), qs_arrcmp); + r = res == NULL; + } else { + for(i = 0 ; (r == 0) && (i < ar->nmemb) ; ++i) { + switch(cmpop) { + case CMP_STARTSWITH: + r = es_strncmp(estr_l, ar->arr[i], es_strlen(ar->arr[i])) == 0; + break; + case CMP_STARTSWITHI: + r = es_strncasecmp(estr_l, ar->arr[i], es_strlen(ar->arr[i])) == 0; + break; + case CMP_CONTAINS: + r = es_strContains(estr_l, ar->arr[i]) != -1; + break; + case CMP_CONTAINSI: + r = es_strCaseContains(estr_l, ar->arr[i]) != -1; + break; + } } } return r; @@ -2637,6 +2648,18 @@ cnfexprOptimize_AND_OR(struct cnfexpr *expr) return expr; } + +/* optimize array for EQ/NEQ comparisons. We sort the array in + * this case so that we can apply binary search later on. + */ +static inline void +cnfexprOptimize_CMPEQ_arr(struct cnfarray *arr) +{ + DBGPRINTF("optimizer: sorting array for CMP_EQ/NEQ comparison\n"); + qsort(arr->arr, arr->nmemb, sizeof(es_str_t*), qs_arrcmp); +} + + /* (recursively) optimize an expression */ struct cnfexpr* cnfexprOptimize(struct cnfexpr *expr) @@ -2696,6 +2719,9 @@ cnfexprOptimize(struct cnfexpr *expr) } else if(expr->l->nodetype == 'V') { expr = cnfexprOptimize_CMP_var(expr); } + if(expr->r->nodetype == 'A') { + cnfexprOptimize_CMPEQ_arr((struct cnfarray *)expr->r); + } break; case CMP_LE: case CMP_GE: -- cgit v1.2.3 From 1a2c9eab35eff0c3698eacb1f2d10b63e678f658 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 8 Feb 2013 15:29:38 +0100 Subject: bugfix: script == comparison did not work properly on JSON objects --- grammar/rainerscript.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 69f77c50..83ed7680 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1475,6 +1475,29 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) } if(r.datatype == 'S') es_deleteStr(r.d.estr); } + } else if(l.datatype == 'J') { + estr_l = var2String(&l, &bMustFree); + if(expr->r->nodetype == 'S') { + ret->d.n = !es_strcmp(estr_l, ((struct cnfstringval*)expr->r)->estr); /*CMP*/ + } else if(expr->r->nodetype == 'A') { + ret->d.n = evalStrArrayCmp(estr_l, (struct cnfarray*) expr->r, CMP_EQ); + } else { + cnfexprEval(expr->r, &r, usrptr); + if(r.datatype == 'S') { + ret->d.n = !es_strcmp(estr_l, r.d.estr); /*CMP*/ + } else { + n_l = var2Number(&l, &convok_l); + if(convok_l) { + ret->d.n = (n_l == r.d.n); /*CMP*/ + } else { + estr_r = var2String(&r, &bMustFree); + ret->d.n = !es_strcmp(estr_l, estr_r); /*CMP*/ + if(bMustFree) es_deleteStr(estr_r); + } + } + if(r.datatype == 'S') es_deleteStr(r.d.estr); + } + if(bMustFree) es_deleteStr(estr_l); } else { cnfexprEval(expr->r, &r, usrptr); if(r.datatype == 'S') { -- cgit v1.2.3 From 2da01aa019afdcacbed7cb08f41f72fc7482f0ab Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sun, 10 Feb 2013 12:42:25 +0100 Subject: field() function now supports a string as field delimiter also done a bugfix: field() function did never return "***FIELD NOT FOUND***" instead it returned "***ERROR in field() FUNCTION***" in that case --- grammar/rainerscript.c | 65 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 58 insertions(+), 7 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 83ed7680..6dbdad63 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1137,8 +1137,8 @@ var2CString(struct var *r, int *bMustFree) return cstr; } -rsRetVal -doExtractField(uchar *str, uchar delim, int matchnbr, uchar **resstr) +static rsRetVal +doExtractFieldByChar(uchar *str, uchar delim, int matchnbr, uchar **resstr) { int iCurrFld; int iLen; @@ -1175,8 +1175,51 @@ doExtractField(uchar *str, uchar delim, int matchnbr, uchar **resstr) /* now copy */ memcpy(pBuf, pFld, iLen); pBuf[iLen] = '\0'; /* terminate it */ - if(*(pFldEnd+1) != '\0') - ++pFldEnd; /* OK, skip again over delimiter char */ + *resstr = pBuf; + } else { + ABORT_FINALIZE(RS_RET_FIELD_NOT_FOUND); + } +finalize_it: + RETiRet; +} + + +static rsRetVal +doExtractFieldByStr(uchar *str, char *delim, rs_size_t lenDelim, int matchnbr, uchar **resstr) +{ + int iCurrFld; + int iLen; + uchar *pBuf; + uchar *pFld; + uchar *pFldEnd; + DEFiRet; + + /* first, skip to the field in question */ + iCurrFld = 1; + pFld = str; + while(pFld != NULL && iCurrFld < matchnbr) { + if((pFld = (uchar*) strstr((char*)pFld, delim)) != NULL) { + pFld += lenDelim; + ++iCurrFld; + } + } + dbgprintf("field() field requested %d, field found %d\n", matchnbr, iCurrFld); + + if(iCurrFld == matchnbr) { + /* field found, now extract it */ + /* first of all, we need to find the end */ + pFldEnd = (uchar*) strstr((char*)pFld, delim); + if(pFldEnd == NULL) { + iLen = strlen((char*) pFld); + } else { /* found delmiter! Note that pFldEnd *is* already on + * the first delmi char, we don't need that. */ + iLen = pFldEnd - pFld; + } + /* we got our end pointer, now do the copy */ + CHKmalloc(pBuf = MALLOC((iLen + 1) * sizeof(char))); + /* now copy */ + memcpy(pBuf, pFld, iLen); + pBuf[iLen] = '\0'; /* terminate it */ *resstr = pBuf; } else { ABORT_FINALIZE(RS_RET_FIELD_NOT_FOUND); @@ -1289,13 +1332,21 @@ doFuncCall(struct cnffunc *func, struct var *ret, void* usrptr) cnfexprEval(func->expr[1], &r[1], usrptr); cnfexprEval(func->expr[2], &r[2], usrptr); str = (char*) var2CString(&r[0], &bMustFree); - delim = var2Number(&r[1], NULL); matchnbr = var2Number(&r[2], NULL); - localRet = doExtractField((uchar*)str, (char) delim, matchnbr, &resStr); + if(r[1].datatype == 'S') { + char *delimstr; + delimstr = (char*) es_str2cstr(r[1].d.estr, NULL); + localRet = doExtractFieldByStr((uchar*)str, delimstr, es_strlen(r[1].d.estr), + matchnbr, &resStr); + free(delimstr); + } else { + delim = var2Number(&r[1], NULL); + localRet = doExtractFieldByChar((uchar*)str, (char) delim, matchnbr, &resStr); + } if(localRet == RS_RET_OK) { ret->d.estr = es_newStrFromCStr((char*)resStr, strlen((char*)resStr)); free(resStr); - } else if(localRet == RS_RET_OK) { + } else if(localRet == RS_RET_FIELD_NOT_FOUND) { ret->d.estr = es_newStrFromCStr("***FIELD NOT FOUND***", sizeof("***FIELD NOT FOUND***")-1); } else { -- cgit v1.2.3 From b129a96287492685050f6f80f8f0204122b22e77 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 28 Feb 2013 10:02:27 +0100 Subject: bugfix: include files got included in the wrong order This happens if an $IncludeConfig directive was done on multiple files (e.g. the distro default of $IncludeConfig /etc/rsyslog.d/*.conf). In that case, the order of include file processing is reversed, which could lead to all sorts of problems. Thanks to Nathan Stratton Treadway for his great analysis of the problem, which made bug fixing really easy. --- grammar/rainerscript.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 0584d6a9..20b86c5c 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -2793,7 +2793,7 @@ cnfDoInclude(char *name) { char *cfgFile; char *finalName; - unsigned i; + int i; int result; glob_t cfgFiles; struct stat fileInfo; @@ -2829,7 +2829,12 @@ cnfDoInclude(char *name) return 1; } - for(i = 0; i < cfgFiles.gl_pathc; i++) { + /* note: bison "stacks" the files, so we need to submit them + * in reverse order to the *stack* in order to get the proper + * parsing order. Also see + * http://bugzilla.adiscon.com/show_bug.cgi?id=411 + */ + for(i = cfgFiles.gl_pathc - 1; i >= 0 ; i--) { cfgFile = cfgFiles.gl_pathv[i]; if(stat(cfgFile, &fileInfo) != 0) { char errStr[1024]; -- cgit v1.2.3 From b097e889a14de1341262e53c70451f67bbe077ab Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 15 Mar 2013 16:59:40 +0100 Subject: bugfix: segfault in expression optimizer closes: http://bugzilla.adiscon.com/show_bug.cgi?id=423 --- grammar/rainerscript.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 7ef7bf7f..8a9c9aaa 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -2635,7 +2635,7 @@ cnfexprOptimize_CMP_severity_facility(struct cnfexpr *expr) /* optimize a comparison with a variable as left-hand operand * NOTE: Currently support CMP_EQ, CMP_NE only and code NEEDS - * TO BE CHANGED for other comparisons! + * TO BE CHANGED fgr other comparisons! */ static inline struct cnfexpr* cnfexprOptimize_CMP_var(struct cnfexpr *expr) @@ -2790,10 +2790,10 @@ cnfexprOptimize(struct cnfexpr *expr) expr->l = expr->r; expr->r = exprswap; } - } else if(expr->l->nodetype == 'V') { - expr = cnfexprOptimize_CMP_var(expr); } - if(expr->r->nodetype == 'A') { + if(expr->l->nodetype == 'V') { + expr = cnfexprOptimize_CMP_var(expr); + } else if(expr->r->nodetype == 'A') { cnfexprOptimize_CMPEQ_arr((struct cnfarray *)expr->r); } break; -- cgit v1.2.3 From 619c70d31f33deb8538636ac1302a2d4032a844e Mon Sep 17 00:00:00 2001 From: Philippe Muller Date: Wed, 20 Mar 2013 09:27:04 +0100 Subject: bugfix: RainerScript getenv() function caused segfault when var was not found This patch is released under ASL 2.0 as of email conversation from 2013-03-20. Signed-off-by: Rainer Gerhards --- grammar/rainerscript.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 20b86c5c..b04e53b5 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1071,8 +1071,12 @@ doFuncCall(struct cnffunc *func, struct var *ret, void* usrptr) estr = var2String(&r[0], &bMustFree); str = (char*) es_str2cstr(estr, NULL); envvar = getenv(str); + if(envvar == NULL) { + ret->d.estr = es_newStr(0); + } else { + ret->d.estr = es_newStrFromCStr(envvar, strlen(envvar)); + } ret->datatype = 'S'; - ret->d.estr = es_newStrFromCStr(envvar, strlen(envvar)); if(bMustFree) es_deleteStr(estr); if(r[0].datatype == 'S') es_deleteStr(r[0].d.estr); free(str); -- cgit v1.2.3 From 5e6ba49ef3ae3bc79c2dc1aa160900a5f776c72a Mon Sep 17 00:00:00 2001 From: Martin Carpenter Date: Tue, 27 Nov 2012 09:35:48 +0100 Subject: Fix for glob(3)s that lack GLOB_NOMAGIC Conflicts: configure.ac --- grammar/rainerscript.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 065e815a..8ef7429d 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -3256,12 +3256,16 @@ cnfDoInclude(char *name) /* Use GLOB_MARK to append a trailing slash for directories. */ /* Use GLOB_NOMAGIC to detect wildcards that match nothing. */ - result = glob(finalName, GLOB_MARK | GLOB_NOMAGIC, NULL, &cfgFiles); - +#ifdef HAVE_GLOB_NOMAGIC /* Silently ignore wildcards that match nothing */ + result = glob(finalName, GLOB_MARK | GLOB_NOMAGIC, NULL, &cfgFiles); if(result == GLOB_NOMATCH) { - return 0; - } +#else + result = glob(finalName, GLOB_MARK, NULL, &cfgFiles); + if(result == GLOB_NOMATCH && containsGlobWildcard(finalName)) { +#endif /* HAVE_GLOB_NOMAGIC */ + return 0; + } if(result == GLOB_NOSPACE || result == GLOB_ABORTED) { char errStr[1024]; -- cgit v1.2.3 From 1b2f93da31d0331244aa7c72068f4ec324e2cb71 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 27 Mar 2013 17:05:26 +0100 Subject: add RainerScript re_extract() function --- grammar/rainerscript.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 103 insertions(+), 2 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 8ef7429d..00e1e835 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1228,6 +1228,96 @@ finalize_it: RETiRet; } +static inline void +doFunc_re_extract(struct cnffunc *func, struct var *ret, void* usrptr) +{ + size_t submatchnbr; + short matchnbr; + regmatch_t pmatch[50]; + int bMustFree; + es_str_t *estr; + char *str; + struct var r[CNFFUNC_MAX_ARGS]; + int iLenBuf; + unsigned iOffs; + short iTry = 0; + uchar bFound = 0; + iOffs = 0; + sbool bHadNoMatch = 0; + + cnfexprEval(func->expr[0], &r[0], usrptr); + /* search string is already part of the compiled regex, so we don't + * need it here! + */ + cnfexprEval(func->expr[2], &r[2], usrptr); + cnfexprEval(func->expr[3], &r[3], usrptr); + str = (char*) var2CString(&r[0], &bMustFree); + matchnbr = (short) var2Number(&r[2], NULL); + submatchnbr = (size_t) var2Number(&r[3], NULL); + if(submatchnbr > sizeof(pmatch)/sizeof(regmatch_t)) { + DBGPRINTF("re_extract() submatch %d is too large\n", submatchnbr); + bHadNoMatch = 1; + goto finalize_it; + } + + /* first see if we find a match, iterating through the series of + * potential matches over the string. + */ + while(!bFound) { + int iREstat; + iREstat = regexp.regexec(func->funcdata, (char*)(str + iOffs), + submatchnbr+1, pmatch, 0); + dbgprintf("re_extract: regexec return is %d\n", iREstat); + if(iREstat == 0) { + if(pmatch[0].rm_so == -1) { + dbgprintf("oops ... start offset of successful regexec is -1\n"); + break; + } + if(iTry == matchnbr) { + bFound = 1; + } else { + dbgprintf("re_extract: regex found at offset %d, new offset %d, tries %d\n", + iOffs, (int) (iOffs + pmatch[0].rm_eo), iTry); + iOffs += pmatch[0].rm_eo; + ++iTry; + } + } else { + break; + } + } + dbgprintf("re_extract: regex: end search, found %d\n", bFound); + if(!bFound) { + bHadNoMatch = 1; + goto finalize_it; + } else { + /* Match- but did it match the one we wanted? */ + /* we got no match! */ + if(pmatch[submatchnbr].rm_so == -1) { + bHadNoMatch = 1; + goto finalize_it; + } + /* OK, we have a usable match - we now need to malloc pB */ + iLenBuf = pmatch[submatchnbr].rm_eo - pmatch[submatchnbr].rm_so; + estr = es_newStrFromBuf(str + iOffs + pmatch[submatchnbr].rm_so, + iLenBuf); + } + + if(bMustFree) free(str); + if(r[0].datatype == 'S') es_deleteStr(r[0].d.estr); + if(r[2].datatype == 'S') es_deleteStr(r[2].d.estr); + if(r[3].datatype == 'S') es_deleteStr(r[3].d.estr); +finalize_it: + if(bHadNoMatch) { + cnfexprEval(func->expr[4], &r[4], usrptr); + estr = var2String(&r[4], &bMustFree); + if(r[4].datatype == 'S') es_deleteStr(r[4].d.estr); + } + ret->datatype = 'S'; + ret->d.estr = estr; + return; +} + + /* Perform a function call. This has been moved out of cnfExprEval in order * to keep the code small and easier to maintain. */ @@ -1331,6 +1421,9 @@ doFuncCall(struct cnffunc *func, struct var *ret, void* usrptr) if(bMustFree) free(str); if(r[0].datatype == 'S') es_deleteStr(r[0].d.estr); break; + case CNFFUNC_RE_EXTRACT: + doFunc_re_extract(func, ret, usrptr); + break; case CNFFUNC_FIELD: cnfexprEval(func->expr[0], &r[0], usrptr); cnfexprEval(func->expr[1], &r[1], usrptr); @@ -1908,6 +2001,7 @@ cnffuncDestruct(struct cnffunc *func) /* some functions require special destruction */ switch(func->fID) { case CNFFUNC_RE_MATCH: + case CNFFUNC_RE_EXTRACT: if(func->funcdata != NULL) regexp.regfree(func->funcdata); break; @@ -2988,7 +3082,6 @@ cnfstmtOptimize(struct cnfstmt *root) struct cnfstmt *stmt; if(root == NULL) goto done; for(stmt = root ; stmt != NULL ; stmt = stmt->next) { -dbgprintf("RRRR: stmtOptimize: stmt %p, nodetype %u\n", stmt, stmt->nodetype); switch(stmt->nodetype) { case S_IF: cnfstmtOptimizeIf(stmt); @@ -3088,6 +3181,13 @@ funcName2ID(es_str_t *fname, unsigned short nParams) return CNFFUNC_INVALID; } return CNFFUNC_RE_MATCH; + } else if(!es_strbufcmp(fname, (unsigned char*)"re_extract", sizeof("re_extract") - 1)) { + if(nParams != 5) { + parser_errmsg("number of parameters for re_extract() must be five " + "but is %d.", nParams); + return CNFFUNC_INVALID; + } + return CNFFUNC_RE_EXTRACT; } else if(!es_strbufcmp(fname, (unsigned char*)"field", sizeof("field") - 1)) { if(nParams != 3) { parser_errmsg("number of parameters for field() must be three " @@ -3118,7 +3218,7 @@ initFunc_re_match(struct cnffunc *func) func->funcdata = NULL; if(func->expr[1]->nodetype != 'S') { - parser_errmsg("param 2 of re_match() must be a constant string"); + parser_errmsg("param 2 of re_match/extract() must be a constant string"); FINALIZE; } @@ -3196,6 +3296,7 @@ cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) /* some functions require special initialization */ switch(func->fID) { case CNFFUNC_RE_MATCH: + case CNFFUNC_RE_EXTRACT: /* need to compile the regexp in param 2, so this MUST be a constant */ initFunc_re_match(func); break; -- cgit v1.2.3 From cbf0ed9541fee2a480dda3533d1604a9df4ae9bb Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 4 Apr 2013 10:07:49 +0200 Subject: bugfix: script == comparison did not work properly on JSON objects backport from 7.3 branch --- grammar/rainerscript.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index b04e53b5..c14295af 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1317,6 +1317,29 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) } if(r.datatype == 'S') es_deleteStr(r.d.estr); } + } else if(l.datatype == 'J') { + estr_l = var2String(&l, &bMustFree); + if(expr->r->nodetype == 'S') { + ret->d.n = !es_strcmp(estr_l, ((struct cnfstringval*)expr->r)->estr); /*CMP*/ + } else if(expr->r->nodetype == 'A') { + ret->d.n = evalStrArrayCmp(estr_l, (struct cnfarray*) expr->r, CMP_EQ); + } else { + cnfexprEval(expr->r, &r, usrptr); + if(r.datatype == 'S') { + ret->d.n = !es_strcmp(estr_l, r.d.estr); /*CMP*/ + } else { + n_l = var2Number(&l, &convok_l); + if(convok_l) { + ret->d.n = (n_l == r.d.n); /*CMP*/ + } else { + estr_r = var2String(&r, &bMustFree); + ret->d.n = !es_strcmp(estr_l, estr_r); /*CMP*/ + if(bMustFree) es_deleteStr(estr_r); + } + } + if(r.datatype == 'S') es_deleteStr(r.d.estr); + } + if(bMustFree) es_deleteStr(estr_l); } else { cnfexprEval(expr->r, &r, usrptr); if(r.datatype == 'S') { -- cgit v1.2.3 From 9b85b24d1323c91a06aeef08bbbde7a96afd46d6 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 4 Apr 2013 16:01:00 +0200 Subject: bugfix: nested if/prifilt conditions did not work properly closes: http://bugzilla.adiscon.com/show_bug.cgi?id=415 --- grammar/rainerscript.c | 188 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 127 insertions(+), 61 deletions(-) (limited to 'grammar/rainerscript.c') diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index c14295af..186887b4 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1285,7 +1285,9 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) int bMustFree, bMustFree2; long long n_r, n_l; - dbgprintf("eval expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); + DBGPRINTF("eval expr %p, type '%c'[%s](%u)\n", expr, expr->nodetype, + + tokenval2str(expr->nodetype), expr->nodetype); switch(expr->nodetype) { /* note: comparison operations are extremely similar. The code can be copyied, only * places flagged with "CMP" need to be changed. @@ -1939,31 +1941,33 @@ cnfexprPrint(struct cnfexpr *expr, int indent) break; } } +/* print only the given stmt + * if "subtree" equals 1, the full statement subtree is printed, else + * really only the statement. + */ void -cnfstmtPrint(struct cnfstmt *root, int indent) +cnfstmtPrintOnly(struct cnfstmt *stmt, int indent, sbool subtree) { - struct cnfstmt *stmt; char *cstr; - //dbgprintf("stmt %p, indent %d, type '%c'\n", expr, indent, expr->nodetype); - for(stmt = root ; stmt != NULL ; stmt = stmt->next) { - switch(stmt->nodetype) { - case S_NOP: - doIndent(indent); dbgprintf("NOP\n"); - break; - case S_STOP: - doIndent(indent); dbgprintf("STOP\n"); - break; - case S_CALL: - cstr = es_str2cstr(stmt->d.s_call.name, NULL); - doIndent(indent); dbgprintf("CALL [%s]\n", cstr); - free(cstr); - break; - case S_ACT: - doIndent(indent); dbgprintf("ACTION %p [%s]\n", stmt->d.act, stmt->printable); - break; - case S_IF: - doIndent(indent); dbgprintf("IF\n"); - cnfexprPrint(stmt->d.s_if.expr, indent+1); + switch(stmt->nodetype) { + case S_NOP: + doIndent(indent); dbgprintf("NOP\n"); + break; + case S_STOP: + doIndent(indent); dbgprintf("STOP\n"); + break; + case S_CALL: + cstr = es_str2cstr(stmt->d.s_call.name, NULL); + doIndent(indent); dbgprintf("CALL [%s]\n", cstr); + free(cstr); + break; + case S_ACT: + doIndent(indent); dbgprintf("ACTION %p [%s]\n", stmt->d.act, stmt->printable); + break; + case S_IF: + doIndent(indent); dbgprintf("IF\n"); + cnfexprPrint(stmt->d.s_if.expr, indent+1); + if(subtree) { doIndent(indent); dbgprintf("THEN\n"); cnfstmtPrint(stmt->d.s_if.t_then, indent+1); if(stmt->d.s_if.t_else != NULL) { @@ -1971,54 +1975,67 @@ cnfstmtPrint(struct cnfstmt *root, int indent) cnfstmtPrint(stmt->d.s_if.t_else, indent+1); } doIndent(indent); dbgprintf("END IF\n"); - break; - case S_SET: - doIndent(indent); dbgprintf("SET %s =\n", - stmt->d.s_set.varname); - cnfexprPrint(stmt->d.s_set.expr, indent+1); - doIndent(indent); dbgprintf("END SET\n"); - break; - case S_UNSET: - doIndent(indent); dbgprintf("UNSET %s\n", - stmt->d.s_unset.varname); - break; - case S_PRIFILT: - doIndent(indent); dbgprintf("PRIFILT '%s'\n", stmt->printable); - pmaskPrint(stmt->d.s_prifilt.pmask, indent); + } + break; + case S_SET: + doIndent(indent); dbgprintf("SET %s =\n", + stmt->d.s_set.varname); + cnfexprPrint(stmt->d.s_set.expr, indent+1); + doIndent(indent); dbgprintf("END SET\n"); + break; + case S_UNSET: + doIndent(indent); dbgprintf("UNSET %s\n", + stmt->d.s_unset.varname); + break; + case S_PRIFILT: + doIndent(indent); dbgprintf("PRIFILT '%s'\n", stmt->printable); + pmaskPrint(stmt->d.s_prifilt.pmask, indent); + if(subtree) { cnfstmtPrint(stmt->d.s_prifilt.t_then, indent+1); if(stmt->d.s_prifilt.t_else != NULL) { doIndent(indent); dbgprintf("ELSE\n"); cnfstmtPrint(stmt->d.s_prifilt.t_else, indent+1); } doIndent(indent); dbgprintf("END PRIFILT\n"); - break; - case S_PROPFILT: - doIndent(indent); dbgprintf("PROPFILT\n"); - doIndent(indent); dbgprintf("\tProperty.: '%s'\n", - propIDToName(stmt->d.s_propfilt.propID)); - if(stmt->d.s_propfilt.propName != NULL) { - cstr = es_str2cstr(stmt->d.s_propfilt.propName, NULL); - doIndent(indent); - dbgprintf("\tCEE-Prop.: '%s'\n", cstr); - free(cstr); - } - doIndent(indent); dbgprintf("\tOperation: "); - if(stmt->d.s_propfilt.isNegated) - dbgprintf("NOT "); - dbgprintf("'%s'\n", getFIOPName(stmt->d.s_propfilt.operation)); - if(stmt->d.s_propfilt.pCSCompValue != NULL) { - doIndent(indent); dbgprintf("\tValue....: '%s'\n", - rsCStrGetSzStrNoNULL(stmt->d.s_propfilt.pCSCompValue)); - } + } + break; + case S_PROPFILT: + doIndent(indent); dbgprintf("PROPFILT\n"); + doIndent(indent); dbgprintf("\tProperty.: '%s'\n", + propIDToName(stmt->d.s_propfilt.propID)); + if(stmt->d.s_propfilt.propName != NULL) { + cstr = es_str2cstr(stmt->d.s_propfilt.propName, NULL); + doIndent(indent); + dbgprintf("\tCEE-Prop.: '%s'\n", cstr); + free(cstr); + } + doIndent(indent); dbgprintf("\tOperation: "); + if(stmt->d.s_propfilt.isNegated) + dbgprintf("NOT "); + dbgprintf("'%s'\n", getFIOPName(stmt->d.s_propfilt.operation)); + if(stmt->d.s_propfilt.pCSCompValue != NULL) { + doIndent(indent); dbgprintf("\tValue....: '%s'\n", + rsCStrGetSzStrNoNULL(stmt->d.s_propfilt.pCSCompValue)); + } + if(subtree) { doIndent(indent); dbgprintf("THEN\n"); cnfstmtPrint(stmt->d.s_propfilt.t_then, indent+1); doIndent(indent); dbgprintf("END PROPFILT\n"); - break; - default: - dbgprintf("error: unknown stmt type %u\n", - (unsigned) stmt->nodetype); - break; } + break; + default: + dbgprintf("error: unknown stmt type %u\n", + (unsigned) stmt->nodetype); + break; + } +} +void +cnfstmtPrint(struct cnfstmt *root, int indent) +{ + struct cnfstmt *stmt; + //dbgprintf("stmt %p, indent %d, type '%c'\n", expr, indent, expr->nodetype); + for(stmt = root ; stmt != NULL ; stmt = stmt->next) { + cnfstmtPrintOnly(stmt, indent, 1); } } @@ -3099,3 +3116,52 @@ unescapeStr(uchar *s, int len) s[iDst] = '\0'; } } + +char * +tokenval2str(int tok) +{ + if(tok < 256) return ""; + switch(tok) { + case NAME: return "NAME"; + case FUNC: return "FUNC"; + case BEGINOBJ: return "BEGINOBJ"; + case ENDOBJ: return "ENDOBJ"; + case BEGIN_ACTION: return "BEGIN_ACTION"; + case BEGIN_PROPERTY: return "BEGIN_PROPERTY"; + case BEGIN_CONSTANT: return "BEGIN_CONSTANT"; + case BEGIN_TPL: return "BEGIN_TPL"; + case BEGIN_RULESET: return "BEGIN_RULESET"; + case STOP: return "STOP"; + case SET: return "SET"; + case UNSET: return "UNSET"; + case CONTINUE: return "CONTINUE"; + case CALL: return "CALL"; + case LEGACY_ACTION: return "LEGACY_ACTION"; + case LEGACY_RULESET: return "LEGACY_RULESET"; + case PRIFILT: return "PRIFILT"; + case PROPFILT: return "PROPFILT"; + case BSD_TAG_SELECTOR: return "BSD_TAG_SELECTOR"; + case BSD_HOST_SELECTOR: return "BSD_HOST_SELECTOR"; + case IF: return "IF"; + case THEN: return "THEN"; + case ELSE: return "ELSE"; + case OR: return "OR"; + case AND: return "AND"; + case NOT: return "NOT"; + case VAR: return "VAR"; + case STRING: return "STRING"; + case NUMBER: return "NUMBER"; + case CMP_EQ: return "CMP_EQ"; + case CMP_NE: return "CMP_NE"; + case CMP_LE: return "CMP_LE"; + case CMP_GE: return "CMP_GE"; + case CMP_LT: return "CMP_LT"; + case CMP_GT: return "CMP_GT"; + case CMP_CONTAINS: return "CMP_CONTAINS"; + case CMP_CONTAINSI: return "CMP_CONTAINSI"; + case CMP_STARTSWITH: return "CMP_STARTSWITH"; + case CMP_STARTSWITHI: return "CMP_STARTSWITHI"; + case UMINUS: return "UMINUS"; + default: return "UNKNOWN TOKEN"; + } +} -- cgit v1.2.3