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 ++++++++++-- runtime/msg.c | 42 +++++++++++++++++++++ runtime/msg.h | 1 + runtime/rsconf.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 161 insertions(+), 5 deletions(-) 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'; diff --git a/runtime/msg.c b/runtime/msg.c index 96fe1b2c..4e96a02f 100644 --- a/runtime/msg.c +++ b/runtime/msg.c @@ -3116,9 +3116,51 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe, * to rewrite the script engine as well! * rgerhards, 2010-12-03 */ +es_str_t* +msgGetCEEVarNew(msg_t *pMsg, char *name) +{ + es_str_t *estr = NULL; + es_str_t *epropName = NULL; + struct ee_field *field; + + ISOBJ_TYPE_assert(pMsg, msg); + + if(pMsg->event == NULL) { + estr = es_newStr(1); + goto done; + } + + epropName = es_newStrFromCStr(name, strlen(name)); // TODO: optimize (in grammar!) +dbgprintf("ZZZZ: pmsg->event %p\n", pMsg->event); + field = ee_getEventField(pMsg->event, epropName); + if(field != NULL) { + estr = ee_getFieldValueAsStr(field, 0); + } + if(estr == NULL) { + DBGPRINTF("msgGetCEEVar: error obtaining var (field=%p, var='%s')\n", + field, name); + estr = es_newStrFromCStr("*ERROR*", sizeof("*ERROR*") - 1); + } + es_deleteStr(epropName); + +done: + return estr; +} + + +/* The function returns a cee variable suitable for use with RainerScript. Most importantly, this means + * that the value is returned in a var_t object. The var_t is constructed inside this function and + * MUST be freed by the caller. + * Note that we need to do a lot of conversions between es_str_t and cstr -- this will go away once + * we have moved larger parts of rsyslog to es_str_t. Acceptable for the moment, especially as we intend + * to rewrite the script engine as well! + * rgerhards, 2010-12-03 + * + */ rsRetVal msgGetCEEVar(msg_t *pMsg, cstr_t *propName, var_t **ppVar) { +#warning remove as part of cleanup DEFiRet; var_t *pVar; cstr_t *pstrProp; diff --git a/runtime/msg.h b/runtime/msg.h index 19debb03..55d2dfc0 100644 --- a/runtime/msg.h +++ b/runtime/msg.h @@ -178,6 +178,7 @@ char *getTimeReported(msg_t *pM, enum tplFormatTypes eFmt); char *getPRI(msg_t *pMsg); void getRawMsg(msg_t *pM, uchar **pBuf, int *piLen); rsRetVal msgGetCEEVar(msg_t *pThis, cstr_t *propName, var_t **ppVar); +es_str_t* msgGetCEEVarNew(msg_t *pMsg, char *name); /* TODO: remove these five (so far used in action.c) */ diff --git a/runtime/rsconf.c b/runtime/rsconf.c index c1bc3b72..d12a258b 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -65,6 +65,7 @@ #include "parser.h" #include "outchannel.h" #include "threads.h" +#include "datetime.h" #include "parserif.h" #include "dirty.h" @@ -77,6 +78,7 @@ DEFobjCurrIf(conf) DEFobjCurrIf(errmsg) DEFobjCurrIf(glbl) DEFobjCurrIf(parser) +DEFobjCurrIf(datetime) /* exported static data */ rsconf_t *runConf = NULL;/* the currently running config */ @@ -244,6 +246,87 @@ cnfDoActlst(struct cnfactlst *actlst, rule_t *pRule) RETiRet; } +/* This function returns the current date in different + * variants. It is used to construct the $NOW series of + * system properties. The returned buffer must be freed + * by the caller when no longer needed. If the function + * can not allocate memory, it returns a NULL pointer. + * TODO: this was taken from msg.c and we should consolidate it with the code + * there. This is especially important when we increase the number of system + * variables (what we definitely want to do). + */ +typedef enum ENOWType { NOW_NOW, NOW_YEAR, NOW_MONTH, NOW_DAY, NOW_HOUR, NOW_MINUTE } eNOWType; +static rsRetVal +getNOW(eNOWType eNow, es_str_t **estr) +{ + DEFiRet; + uchar szBuf[16]; + struct syslogTime t; + es_size_t len; + + datetime.getCurrTime(&t, NULL); + switch(eNow) { + case NOW_NOW: + len = snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), + "%4.4d-%2.2d-%2.2d", t.year, t.month, t.day); + break; + case NOW_YEAR: + len = snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%4.4d", t.year); + break; + case NOW_MONTH: + len = snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%2.2d", t.month); + break; + case NOW_DAY: + len = snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%2.2d", t.day); + break; + case NOW_HOUR: + len = snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%2.2d", t.hour); + break; + case NOW_MINUTE: + len = snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%2.2d", t.minute); + break; + } + + /* now create a string object out of it and hand that over to the var */ + *estr = es_newStrFromCStr((char*)szBuf, len); + + RETiRet; +} + + + +static inline es_str_t * +getSysVar(char *name) +{ + es_str_t *estr = NULL; + rsRetVal iRet = RS_RET_OK; + + if(!strcmp(name, "now")) { + CHKiRet(getNOW(NOW_NOW, &estr)); + } else if(!strcmp(name, "year")) { + CHKiRet(getNOW(NOW_YEAR, &estr)); + } else if(!strcmp(name, "month")) { + CHKiRet(getNOW(NOW_MONTH, &estr)); + } else if(!strcmp(name, "day")) { + CHKiRet(getNOW(NOW_DAY, &estr)); + } else if(!strcmp(name, "hour")) { + CHKiRet(getNOW(NOW_HOUR, &estr)); + } else if(!strcmp(name, "minute")) { + CHKiRet(getNOW(NOW_MINUTE, &estr)); + } else if(!strcmp(name, "myhostname")) { + char *hn = (char*)glbl.GetLocalHostName(); + estr = es_newStrFromCStr(hn, strlen(hn)); + } else { + ABORT_FINALIZE(RS_RET_SYSVAR_NOT_FOUND); + } +finalize_it: + if(iRet != RS_RET_OK) { + dbgprintf("getSysVar error iRet %d\n", iRet); + if(estr == NULL) + estr = es_newStrFromCStr("*ERROR*", sizeof("*ERROR*") - 1); + } + return estr; +} /*------------------------------ interface to flex/bison parser ------------------------------*/ extern int yylineno; @@ -350,9 +433,19 @@ es_str_t* cnfGetVar(char *name, void *usrptr) { es_str_t *estr; - dbgprintf("ZZZZ: var '%s' requested\n", name); if(name[0] == '$') { - estr = msgGetMsgVarNew((msg_t*) usrptr, (uchar*)name+1); + if(name[1] == '$') + estr = getSysVar(name+2); + else if(name[1] == '!') + estr = msgGetCEEVarNew((msg_t*) usrptr, name+2); + else + estr = msgGetMsgVarNew((msg_t*) usrptr, (uchar*)name+1); + } + if(Debug) { + char *s; + s = es_str2cstr(estr, NULL); + dbgprintf("rainerscript: var '%s': '%s'\n", name, s); + free(s); } return estr; } @@ -1258,6 +1351,7 @@ BEGINObjClassInit(rsconf, 1, OBJ_IS_CORE_MODULE) /* class, version */ CHKiRet(objUse(conf, CORE_COMPONENT)); CHKiRet(objUse(errmsg, CORE_COMPONENT)); CHKiRet(objUse(glbl, CORE_COMPONENT)); + CHKiRet(objUse(datetime, CORE_COMPONENT)); CHKiRet(objUse(parser, CORE_COMPONENT)); /* now set our own handlers */ @@ -1275,6 +1369,7 @@ BEGINObjClassExit(rsconf, OBJ_IS_CORE_MODULE) /* class, version */ objRelease(conf, CORE_COMPONENT); objRelease(errmsg, CORE_COMPONENT); objRelease(glbl, CORE_COMPONENT); + objRelease(datetime, CORE_COMPONENT); objRelease(parser, CORE_COMPONENT); ENDObjClassExit(rsconf) -- cgit