diff options
Diffstat (limited to 'runtime')
-rw-r--r-- | runtime/Makefile.am | 18 | ||||
-rw-r--r-- | runtime/conf.c | 388 | ||||
-rw-r--r-- | runtime/conf.h | 19 | ||||
-rw-r--r-- | runtime/ctok.c | 629 | ||||
-rw-r--r-- | runtime/ctok.h | 56 | ||||
-rw-r--r-- | runtime/ctok_token.c | 129 | ||||
-rw-r--r-- | runtime/ctok_token.h | 88 | ||||
-rw-r--r-- | runtime/datetime.c | 1 | ||||
-rw-r--r-- | runtime/errmsg.c | 1 | ||||
-rw-r--r-- | runtime/expr.c | 482 | ||||
-rw-r--r-- | runtime/expr.h | 57 | ||||
-rw-r--r-- | runtime/msg.c | 118 | ||||
-rw-r--r-- | runtime/msg.h | 2 | ||||
-rw-r--r-- | runtime/rsconf.c | 323 | ||||
-rw-r--r-- | runtime/rsyslog.c | 23 | ||||
-rw-r--r-- | runtime/rsyslog.h | 1 | ||||
-rw-r--r-- | runtime/rule.c | 31 | ||||
-rw-r--r-- | runtime/rule.h | 6 | ||||
-rw-r--r-- | runtime/statsobj.c | 1 | ||||
-rw-r--r-- | runtime/sysvar.c | 204 | ||||
-rw-r--r-- | runtime/sysvar.h | 47 | ||||
-rw-r--r-- | runtime/vm.c | 869 | ||||
-rw-r--r-- | runtime/vm.h | 68 | ||||
-rw-r--r-- | runtime/vmop.c | 307 | ||||
-rw-r--r-- | runtime/vmop.h | 129 | ||||
-rw-r--r-- | runtime/vmprg.c | 236 | ||||
-rw-r--r-- | runtime/vmprg.h | 69 | ||||
-rw-r--r-- | runtime/vmstk.c | 234 | ||||
-rw-r--r-- | runtime/vmstk.h | 56 |
29 files changed, 359 insertions, 4233 deletions
diff --git a/runtime/Makefile.am b/runtime/Makefile.am index 232d8f03..ac4f4279 100644 --- a/runtime/Makefile.am +++ b/runtime/Makefile.am @@ -55,12 +55,6 @@ librsyslog_la_SOURCES = \ statsobj.h \ sync.c \ sync.h \ - expr.c \ - expr.h \ - ctok.c \ - ctok.h \ - ctok_token.c \ - ctok_token.h \ stream.c \ stream.h \ var.c \ @@ -69,16 +63,6 @@ librsyslog_la_SOURCES = \ wtp.h \ wti.c \ wti.h \ - sysvar.c \ - sysvar.h \ - vm.c \ - vm.h \ - vmstk.c \ - vmstk.h \ - vmprg.c \ - vmprg.h \ - vmop.c \ - vmop.h \ queue.c \ queue.h \ ruleset.c \ @@ -117,7 +101,7 @@ librsyslog_la_SOURCES = \ if WITH_MODDIRS librsyslog_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -D_PATH_MODDIR=\"$(pkglibdir)/:$(moddirs)\" $(PTHREADS_CFLAGS) $(LIBEE_CFLAGS) -I\$(top_srcdir)/tools else -librsyslog_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -D_PATH_MODDIR=\"$(pkglibdir)/\" -I$(top_srcdir) $(PTHREADS_CFLAGS) $(LIBEE_CFLAGS) -I\$(top_srcdir)/tools +librsyslog_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -D_PATH_MODDIR=\"$(pkglibdir)/\" -I$(top_srcdir) $(PTHREADS_CFLAGS) $(LIBEE_CFLAGS) -I\$(top_srcdir)/tools -I\$(top_srcdir)/grammar endif #librsyslog_la_LDFLAGS = -module -avoid-version librsyslog_la_LIBADD = $(DL_LIBS) $(RT_LIBS) $(LIBEE_LIBS) diff --git a/runtime/conf.c b/runtime/conf.c index 0dd53754..27077ea9 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -65,9 +65,6 @@ #include "srUtils.h" #include "errmsg.h" #include "net.h" -#include "expr.h" -#include "ctok.h" -#include "ctok_token.h" #include "rule.h" #include "ruleset.h" #include "rsconf.h" @@ -78,15 +75,11 @@ #endif /* forward definitions */ -static rsRetVal cfline(rsconf_t *conf, uchar *line, rule_t **pfCurr); -static rsRetVal processConfFile(rsconf_t *conf, uchar *pConfFile); +//static rsRetVal cfline(rsconf_t *conf, uchar *line, rule_t **pfCurr); /* static data */ DEFobjStaticHelpers -DEFobjCurrIf(expr) -DEFobjCurrIf(ctok) -DEFobjCurrIf(ctok_token) DEFobjCurrIf(module) DEFobjCurrIf(errmsg) DEFobjCurrIf(net) @@ -104,149 +97,9 @@ int bConfStrictScoping = 0; /* force strict scoping during config processing? */ * be run in a single thread anyways. So there can be no race conditions. * rgerhards 2005-10-18 */ -static EHostnameCmpMode eDfltHostnameCmpMode = HN_NO_COMP; -static cstr_t *pDfltHostnameCmp = NULL; -static cstr_t *pDfltProgNameCmp = NULL; - - -/* process a directory and include all of its files into - * the current config file. There is no specific order of inclusion, - * files are included in the order they are read from the directory. - * The caller must have make sure that the provided parameter is - * indeed a directory. - * rgerhards, 2007-08-01 - */ -static rsRetVal doIncludeDirectory(rsconf_t *conf, uchar *pDirName) -{ - DEFiRet; - int iEntriesDone = 0; - DIR *pDir; - union { - struct dirent d; - char b[offsetof(struct dirent, d_name) + NAME_MAX + 1]; - } u; - struct dirent *res; - size_t iDirNameLen; - size_t iFileNameLen; - uchar szFullFileName[MAXFNAME]; - - ASSERT(pDirName != NULL); - - if((pDir = opendir((char*) pDirName)) == NULL) { - errmsg.LogError(errno, RS_RET_FOPEN_FAILURE, "error opening include directory"); - ABORT_FINALIZE(RS_RET_FOPEN_FAILURE); - } - - /* prepare file name buffer */ - iDirNameLen = strlen((char*) pDirName); - memcpy(szFullFileName, pDirName, iDirNameLen); - - /* now read the directory */ - iEntriesDone = 0; - while(readdir_r(pDir, &u.d, &res) == 0) { - if(res == NULL) - break; /* this also indicates end of directory */ -# ifdef DT_REG - /* TODO: find an alternate way to checking for special files if this is - * not defined. This is currently a known problem on HP UX, but the work- - * around is simple: do not create special files in that directory. So - * fixing this is actually not the most important thing on earth... - * rgerhards, 2008-03-04 - */ - if(res->d_type != DT_REG) - continue; /* we are not interested in special files */ -# endif - if(res->d_name[0] == '.') - continue; /* these files we are also not interested in */ - ++iEntriesDone; - /* construct filename */ - iFileNameLen = strlen(res->d_name); - if (iFileNameLen > NAME_MAX) - iFileNameLen = NAME_MAX; - memcpy(szFullFileName + iDirNameLen, res->d_name, iFileNameLen); - *(szFullFileName + iDirNameLen + iFileNameLen) = '\0'; - dbgprintf("including file '%s'\n", szFullFileName); - processConfFile(conf, szFullFileName); - /* we deliberately ignore the iRet of processConfFile() - this is because - * failure to process one file does not mean all files will fail. By ignoring, - * we retry with the next file, which is the best thing we can do. -- rgerhards, 2007-08-01 - */ - } - - if(iEntriesDone == 0) { - /* I just make it a debug output, because I can think of a lot of cases where it - * makes sense not to have any files. E.g. a system maintainer may place a $Include - * into the config file just in case, when additional modules be installed. When none - * are installed, the directory will be empty, which is fine. -- rgerhards 2007-08-01 - */ - dbgprintf("warning: the include directory contained no files - this may be ok.\n"); - } - -finalize_it: - if(pDir != NULL) - closedir(pDir); - - RETiRet; -} - - -/* process a $include config line. That type of line requires - * inclusion of another file. - * rgerhards, 2007-08-01 - */ -rsRetVal -doIncludeLine(rsconf_t *conf, uchar **pp, __attribute__((unused)) void* pVal) -{ - DEFiRet; - char pattern[MAXFNAME]; - uchar *cfgFile; - glob_t cfgFiles; - int result; - size_t i = 0; - struct stat fileInfo; - - ASSERT(pp != NULL); - ASSERT(*pp != NULL); - - if(getSubString(pp, (char*) pattern, sizeof(pattern) / sizeof(char), ' ') != 0) { - errmsg.LogError(0, RS_RET_NOT_FOUND, "could not parse config file name"); - ABORT_FINALIZE(RS_RET_NOT_FOUND); - } - - /* Use GLOB_MARK to append a trailing slash for directories. - * Required by doIncludeDirectory(). - */ - result = glob(pattern, GLOB_MARK, NULL, &cfgFiles); - if(result == GLOB_NOSPACE || result == GLOB_ABORTED) { - 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); - } - - for(i = 0; i < cfgFiles.gl_pathc; i++) { - cfgFile = (uchar*) cfgFiles.gl_pathv[i]; - - if(stat((char*) 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); - iRet = processConfFile(conf, cfgFile); - } else if(S_ISDIR(fileInfo.st_mode)) { /* config directory */ - dbgprintf("requested to include directory '%s'\n", cfgFile); - iRet = doIncludeDirectory(conf, cfgFile); - } else { /* TODO: shall we handle symlinks or not? */ - dbgprintf("warning: unable to process IncludeConfig directive '%s'\n", cfgFile); - } - } - - globfree(&cfgFiles); - -finalize_it: - RETiRet; -} +EHostnameCmpMode eDfltHostnameCmpMode = HN_NO_COMP; +cstr_t *pDfltHostnameCmp = NULL; +cstr_t *pDfltProgNameCmp = NULL; /* process a $ModLoad config line. */ @@ -354,7 +207,7 @@ finalize_it: * 2004-11-17 rgerhards */ rsRetVal -cfsysline(rsconf_t *conf, uchar *p) +cfsysline(uchar *p) { DEFiRet; uchar szCmd[64]; @@ -389,120 +242,6 @@ finalize_it: } - - -/* process a configuration file - * started with code from init() by rgerhards on 2007-07-31 - */ -static rsRetVal -processConfFile(rsconf_t *conf, uchar *pConfFile) -{ - int iLnNbr = 0; - FILE *cf; - rule_t *pCurrRule = NULL; - uchar *p; - uchar cbuf[CFGLNSIZ]; - uchar *cline; - int i; - int bHadAnError = 0; - uchar *pszOrgLine = NULL; - size_t lenLine; - DEFiRet; - ASSERT(pConfFile != NULL); - - if((cf = fopen((char*)pConfFile, "r")) == NULL) { - ABORT_FINALIZE(RS_RET_FOPEN_FAILURE); - } - - /* Now process the file. - */ - cline = cbuf; - while (fgets((char*)cline, sizeof(cbuf) - (cline - cbuf), cf) != NULL) { - ++iLnNbr; - /* drop LF - TODO: make it better, replace fgets(), but its clean as it is */ - lenLine = ustrlen(cline); - if(cline[lenLine-1] == '\n') { - cline[lenLine-1] = '\0'; - } - free(pszOrgLine); - pszOrgLine = ustrdup(cline); /* save if needed for errmsg, NULL ptr is OK */ - /* check for end-of-section, comments, strip off trailing - * spaces and newline character. - */ - p = cline; - skipWhiteSpace(&p); - if (*p == '\0' || *p == '#') - continue; - - /* we now need to copy the characters to the begin of line. As this overlaps, - * we can not use strcpy(). -- rgerhards, 2008-03-20 - * TODO: review the code at whole - this is highly suspect (but will go away - * once we do the rest of RainerScript). - */ - for( i = 0 ; p[i] != '\0' ; ++i) { - cline[i] = p[i]; - } - cline[i] = '\0'; - - for (p = (uchar*) strchr((char*)cline, '\0'); isspace((int) *--p);) - /*EMPTY*/; - if (*p == '\\') { - if ((p - cbuf) > CFGLNSIZ - 30) { - /* Oops the buffer is full - what now? */ - cline = cbuf; - } else { - *p = 0; - cline = p; - continue; - } - } else - cline = cbuf; - *++p = '\0'; /* TODO: check this */ - - /* we now have the complete line, and are positioned at the first non-whitespace - * character. So let's process it - */ - if(cfline(conf, cbuf, &pCurrRule) != RS_RET_OK) { - /* we log a message, but otherwise ignore the error. After all, the next - * line can be correct. -- rgerhards, 2007-08-02 - */ - uchar szErrLoc[MAXFNAME + 64]; - dbgprintf("config line NOT successfully processed\n"); - snprintf((char*)szErrLoc, sizeof(szErrLoc) / sizeof(uchar), - "%s, line %d", pConfFile, iLnNbr); - errmsg.LogError(0, NO_ERRCODE, "the last error occured in %s:\"%s\"", (char*)szErrLoc, (char*)pszOrgLine); - bHadAnError = 1; - } - } - - /* we probably have one selector left to be added - so let's do that now */ - if(pCurrRule != NULL) { - CHKiRet(ruleset.AddRule(conf, rule.GetAssRuleset(pCurrRule), &pCurrRule)); - } - - /* close the configuration file */ - fclose(cf); - -finalize_it: - if(iRet != RS_RET_OK) { - char errStr[1024]; - if(pCurrRule != NULL) - rule.Destruct(&pCurrRule); - - rs_strerror_r(errno, errStr, sizeof(errStr)); - dbgprintf("error %d processing config file '%s'; os error (if any): %s\n", - iRet, pConfFile, errStr); - } - - free(pszOrgLine); - - if(bHadAnError && (iRet == RS_RET_OK)) { /* a bit dirty, enhance in future releases */ - iRet = RS_RET_NONFATAL_CONFIG_ERR; - } - RETiRet; -} - - /* Helper to cfline() and its helpers. Parses a template name * from an "action" line. Must be called with the Line pointer * pointing to the first character after the semicolon. @@ -602,7 +341,7 @@ cflineParseFileName(uchar* p, uchar *pFileName, omodStringRequest_t *pOMSR, int * rgerhards 2005-09-15 */ /* GPLv3 - stems back to sysklogd */ -static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule) +rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule) { uchar *p; register uchar *q; @@ -619,7 +358,7 @@ static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule ASSERT(*pline != NULL); ISOBJ_TYPE_assert(pRule, rule); - dbgprintf(" - traditional PRI filter\n"); + dbgprintf(" - traditional PRI filter '%s'\n", *pline); errno = 0; /* keep strerror_r() stuff out of logerror messages */ pRule->f_filter_type = FILTER_PRI; @@ -632,7 +371,6 @@ static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule /* scan through the list of selectors */ for (p = *pline; *p && *p != '\t' && *p != ' ';) { - /* find the end of this facility name list */ for (q = p; *q && *q != '\t' && *q++ != '.'; ) continue; @@ -643,8 +381,10 @@ static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule *bp = '\0'; /* skip cruft */ - while (strchr(",;", *q)) - q++; + if(*q) { + while (strchr(",;", *q)) + q++; + } /* decode priority name */ if ( *buf == '!' ) { @@ -755,81 +495,12 @@ static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule } -/* Helper to cfline(). This function processes an "if" type of filter, - * what essentially means it parses an expression. As usual, - * It processes the line up to the beginning of the action part. - * A pointer to that beginnig is passed back to the caller. - * rgerhards 2008-01-19 - */ -static rsRetVal cflineProcessIfFilter(uchar **pline, register rule_t *f) -{ - DEFiRet; - ctok_t *tok; - ctok_token_t *pToken; - - ASSERT(pline != NULL); - ASSERT(*pline != NULL); - ASSERT(f != NULL); - - dbgprintf(" - general expression-based filter\n"); - errno = 0; /* keep strerror_r() stuff out of logerror messages */ - - f->f_filter_type = FILTER_EXPR; - - /* if we come to over here, pline starts with "if ". We just skip that part. */ - (*pline) += 3; - - /* we first need a tokenizer... */ - CHKiRet(ctok.Construct(&tok)); - CHKiRet(ctok.Setpp(tok, *pline)); - CHKiRet(ctok.ConstructFinalize(tok)); - - /* now construct our expression */ - CHKiRet(expr.Construct(&f->f_filterData.f_expr)); - CHKiRet(expr.ConstructFinalize(f->f_filterData.f_expr)); - - /* ready to go... */ - CHKiRet(expr.Parse(f->f_filterData.f_expr, tok)); - - /* we now need to parse off the "then" - and note an error if it is - * missing... - */ - CHKiRet(ctok.GetToken(tok, &pToken)); - if(pToken->tok != ctok_THEN) { - ctok_token.Destruct(&pToken); - ABORT_FINALIZE(RS_RET_SYNTAX_ERROR); - } - - ctok_token.Destruct(&pToken); /* no longer needed */ - - /* we are done, so we now need to restore things */ - CHKiRet(ctok.Getpp(tok, pline)); - CHKiRet(ctok.Destruct(&tok)); - - /* debug support - print vmprg after construction (uncomment to use) */ - /* vmprgDebugPrint(f->f_filterData.f_expr->pVmprg); */ - - /* we now need to skip whitespace to the action part, else we confuse - * the legacy rsyslog conf parser. -- rgerhards, 2008-02-25 - */ - while(isspace(**pline)) - ++(*pline); - -finalize_it: - if(iRet == RS_RET_SYNTAX_ERROR) { - errmsg.LogError(0, RS_RET_SYNTAX_ERROR, "syntax error in expression"); - } - - RETiRet; -} - - /* Helper to cfline(). This function takes the filter part of a property * based filter and decodes it. It processes the line up to the beginning * of the action part. A pointer to that beginnig is passed back to the caller. * rgerhards 2005-09-15 */ -static rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f) +rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f) { rsParsObj *pPars; cstr_t *pCSCompOp; @@ -841,7 +512,7 @@ static rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f) ASSERT(*pline != NULL); ASSERT(f != NULL); - dbgprintf(" - property-based filter\n"); + dbgprintf(" - property-based filter '%s'\n", *pline); errno = 0; /* keep strerror_r() stuff out of logerror messages */ f->f_filter_type = FILTER_PROP; @@ -901,7 +572,6 @@ static rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f) iOffset = 0; } -dbgprintf("XXX: offset is %d, string '%s'\n", iOffset, rsCStrGetSzStrNoNULL(pCSCompOp)); if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "contains", 8)) { f->f_filterData.prop.operation = FIOP_CONTAINS; } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "isequal", 7)) { @@ -920,7 +590,6 @@ dbgprintf("XXX: offset is %d, string '%s'\n", iOffset, rsCStrGetSzStrNoNULL(pCSC } rsCStrDestruct(&pCSCompOp); /* no longer needed */ -dbgprintf("XXX: fiop is %u\n", (unsigned) f->f_filterData.prop.operation); if(f->f_filterData.prop.operation != FIOP_ISEMPTY) { /* read compare value */ iRet = parsQuotedCStr(pPars, &f->f_filterData.prop.pCSCompValue); @@ -951,7 +620,7 @@ dbgprintf("XXX: fiop is %u\n", (unsigned) f->f_filterData.prop.operation); * from the config file ("+/-hostname"). It stores it for further reference. * rgerhards 2005-10-19 */ -static rsRetVal cflineProcessHostSelector(rsconf_t *conf, uchar **pline) +rsRetVal cflineProcessHostSelector(uchar **pline) { DEFiRet; @@ -1001,7 +670,7 @@ finalize_it: * from the config file ("!tagname"). It stores it for further reference. * rgerhards 2005-10-18 */ -static rsRetVal cflineProcessTagSelector(rsconf_t *conf, uchar **pline) +rsRetVal cflineProcessTagSelector(uchar **pline) { DEFiRet; @@ -1039,6 +708,7 @@ finalize_it: } +#if 0 /* read the filter part of a configuration line and store the filter * in the supplied rule_t * rgerhards, 2007-08-01 @@ -1055,12 +725,6 @@ static rsRetVal cflineDoFilter(uchar **pp, rule_t *f) case ':': CHKiRet(cflineProcessPropFilter(pp, f)); break; - case 'i': /* "if" filter? */ - if(*(*pp+1) && (*(*pp+1) == 'f') && isspace(*(*pp+2))) { - CHKiRet(cflineProcessIfFilter(pp, f)); - break; - } - /*FALLTHROUGH*/ default: CHKiRet(cflineProcessTradPRIFilter(pp, f)); break; @@ -1081,12 +745,13 @@ static rsRetVal cflineDoFilter(uchar **pp, rule_t *f) finalize_it: RETiRet; } +#endif /* process the action part of a selector line * rgerhards, 2007-08-01 */ -static rsRetVal cflineDoAction(rsconf_t *conf, uchar **p, action_t **ppAction) +rsRetVal cflineDoAction(rsconf_t *conf, uchar **p, action_t **ppAction) { modInfo_t *pMod; cfgmodules_etry_t *node; @@ -1147,6 +812,7 @@ static rsRetVal cflineDoAction(rsconf_t *conf, uchar **p, action_t **ppAction) } +#if 0 /* Process a configuration file line in traditional "filter selector" format * or one that builds upon this format. Note that ppRule may be a NULL pointer, * which is valid and happens if there is no previous line (right at the start @@ -1207,15 +873,15 @@ cfline(rsconf_t *conf, uchar *line, rule_t **pfCurr) /* check type of line and call respective processing */ switch(*line) { case '!': - iRet = cflineProcessTagSelector(conf, &line); + iRet = cflineProcessTagSelector(&line); break; case '+': case '-': - iRet = cflineProcessHostSelector(conf, &line); + iRet = cflineProcessHostSelector(&line); break; case '$': ++line; /* eat '$' */ - iRet = cfsysline(conf, line); + iRet = cfsysline(line); break; default: iRet = cflineClassic(conf, line, pfCurr); @@ -1224,6 +890,7 @@ cfline(rsconf_t *conf, uchar *line, rule_t **pfCurr) RETiRet; } +#endif /* return the current number of active actions @@ -1256,9 +923,6 @@ CODESTARTobjQueryInterface(conf) pIf->doNameLine = doNameLine; pIf->cfsysline = cfsysline; pIf->doModLoad = doModLoad; - pIf->doIncludeLine = doIncludeLine; - pIf->cfline = cfline; - pIf->processConfFile = processConfFile; pIf->GetNbrActActions = GetNbrActActions; finalize_it: @@ -1410,9 +1074,6 @@ CODESTARTObjClassExit(conf) } /* release objects we no longer need */ - objRelease(expr, CORE_COMPONENT); - objRelease(ctok, CORE_COMPONENT); - objRelease(ctok_token, CORE_COMPONENT); objRelease(module, CORE_COMPONENT); objRelease(errmsg, CORE_COMPONENT); objRelease(net, LM_NET_FILENAME); @@ -1427,9 +1088,6 @@ ENDObjClassExit(conf) */ BEGINAbstractObjClassInit(conf, 1, OBJ_IS_CORE_MODULE) /* class, version - CHANGE class also in END MACRO! */ /* request objects we use */ - CHKiRet(objUse(expr, CORE_COMPONENT)); - CHKiRet(objUse(ctok, CORE_COMPONENT)); - CHKiRet(objUse(ctok_token, CORE_COMPONENT)); CHKiRet(objUse(module, CORE_COMPONENT)); CHKiRet(objUse(errmsg, CORE_COMPONENT)); CHKiRet(objUse(net, LM_NET_FILENAME)); /* TODO: make this dependcy go away! */ diff --git a/runtime/conf.h b/runtime/conf.h index 096af630..9253e880 100644 --- a/runtime/conf.h +++ b/runtime/conf.h @@ -21,6 +21,7 @@ */ #ifndef INCLUDED_CONF_H #define INCLUDED_CONF_H +#include "action.h" /* definitions used for doNameLine to differentiate between different command types * (with otherwise identical code). This is a left-over from the previous config @@ -34,11 +35,8 @@ extern int bConfStrictScoping; /* force strict scoping during config processing? /* interfaces */ BEGINinterface(conf) /* name must also be changed in ENDinterface macro! */ rsRetVal (*doNameLine)(uchar **pp, void* pVal); - rsRetVal (*cfsysline)(rsconf_t *conf, uchar *p); + rsRetVal (*cfsysline)(uchar *p); rsRetVal (*doModLoad)(uchar **pp, __attribute__((unused)) void* pVal); - rsRetVal (*doIncludeLine)(rsconf_t *conf, uchar **pp, __attribute__((unused)) void* pVal); - rsRetVal (*cfline)(rsconf_t *conf, uchar *line, rule_t **pfCurr); - rsRetVal (*processConfFile)(rsconf_t *conf, uchar *pConfFile); rsRetVal (*GetNbrActActions)(rsconf_t *conf, int *); /* version 4 -- 2010-07-23 rgerhards */ /* "just" added global variables @@ -48,8 +46,10 @@ BEGINinterface(conf) /* name must also be changed in ENDinterface macro! */ */ /* version 5 -- 2011-04-19 rgerhards */ /* complete revamp, we now use the rsconf object */ + /* version 6 -- 2011-07-06 rgerhards */ + /* again a complete revamp, using flex/bison based parser now */ ENDinterface(conf) -#define confCURR_IF_VERSION 5 /* increment whenever you change the interface structure! */ +#define confCURR_IF_VERSION 6 /* increment whenever you change the interface structure! */ /* in Version 3, entry point "ReInitConf()" was removed, as we do not longer need * to support restart-type HUP -- rgerhards, 2009-07-15 */ @@ -63,5 +63,14 @@ PROTOTYPEObj(conf); rsRetVal cflineParseTemplateName(uchar** pp, omodStringRequest_t *pOMSR, int iEntry, int iTplOpts, uchar *dfltTplName); rsRetVal cflineParseFileName(uchar* p, uchar *pFileName, omodStringRequest_t *pOMSR, int iEntry, int iTplOpts, uchar *pszTpl); +/* more dirt to cover the new config interface (will go away...) */ +rsRetVal cflineProcessTagSelector(uchar **pline); +rsRetVal cflineProcessHostSelector(uchar **pline); +rsRetVal cflineProcessTradPRIFilter(uchar **pline, rule_t *pRule); +rsRetVal cflineProcessPropFilter(uchar **pline, rule_t *f); +rsRetVal cflineDoAction(rsconf_t *conf, uchar **p, action_t **ppAction); +extern EHostnameCmpMode eDfltHostnameCmpMode; +extern cstr_t *pDfltHostnameCmp; +extern cstr_t *pDfltProgNameCmp; #endif /* #ifndef INCLUDED_CONF_H */ diff --git a/runtime/ctok.c b/runtime/ctok.c deleted file mode 100644 index 19c9bd24..00000000 --- a/runtime/ctok.c +++ /dev/null @@ -1,629 +0,0 @@ -/* ctok.c - helper class to tokenize an input stream - which surprisingly - * currently does not work with streams but with string. But that will - * probably change over time ;) This class was originally written to support - * the expression module but may evolve when (if) the expression module is - * expanded (or aggregated) by a full-fledged ctoken based config parser. - * Obviously, this class is used together with config files and not any other - * parse function. - * - * Module begun 2008-02-19 by Rainer Gerhards - * - * Copyright (C) 2008 by 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 <http://www.gnu.org/licenses/>. - * - * 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 <stdlib.h> -#include <ctype.h> -#include <strings.h> -#include <assert.h> - -#include "rsyslog.h" -#include "template.h" -#include "ctok.h" - -/* static data */ -DEFobjStaticHelpers -DEFobjCurrIf(ctok_token) -DEFobjCurrIf(var) - - -/* Standard-Constructor - */ -BEGINobjConstruct(ctok) /* be sure to specify the object type also in END macro! */ -ENDobjConstruct(ctok) - - -/* ConstructionFinalizer - * rgerhards, 2008-01-09 - */ -rsRetVal ctokConstructFinalize(ctok_t __attribute__((unused)) *pThis) -{ - DEFiRet; - RETiRet; -} - - -/* destructor for the ctok object */ -BEGINobjDestruct(ctok) /* be sure to specify the object type also in END and CODESTART macros! */ -CODESTARTobjDestruct(ctok) - /* ... then free resources */ -ENDobjDestruct(ctok) - - -/* unget character from input stream. At most one character can be ungotten. - * This funtion is only permitted to be called after at least one character - * has been read from the stream. Right now, we handle the situation simply by - * moving the string "stream" pointer one position backwards. If we work with - * real streams (some time), the strm object will handle the functionality - * itself. -- rgerhards, 2008-02-19 - */ -static rsRetVal -ctokUngetCharFromStream(ctok_t *pThis, uchar __attribute__((unused)) c) -{ - DEFiRet; - - ISOBJ_TYPE_assert(pThis, ctok); - --pThis->pp; - - RETiRet; -} - - -/* get the next character from the input "stream". Note that this version - * does NOT look for comment characters as end-of-stream, so it is suitable - * when building constant strings! -- rgerhards, 2010-03-01 - */ -static inline rsRetVal -ctokGetCharFromStreamNoComment(ctok_t *pThis, uchar *pc) -{ - DEFiRet; - - ISOBJ_TYPE_assert(pThis, ctok); - ASSERT(pc != NULL); - - /* end of string or begin of comment terminates the "stream" */ - if(*pThis->pp == '\0') { - ABORT_FINALIZE(RS_RET_EOS); - } else { - *pc = *pThis->pp; - ++pThis->pp; - } - -finalize_it: - RETiRet; -} - - -/* get the next character from the input "stream" (currently just a in-memory - * string...) -- rgerhards, 2008-02-19 - */ -static rsRetVal -ctokGetCharFromStream(ctok_t *pThis, uchar *pc) -{ - DEFiRet; - - ISOBJ_TYPE_assert(pThis, ctok); - ASSERT(pc != NULL); - - CHKiRet(ctokGetCharFromStreamNoComment(pThis, pc)); - /* begin of comment terminates the "stream"! */ - if(*pc == '#') { - ABORT_FINALIZE(RS_RET_EOS); - } - -finalize_it: - RETiRet; -} - - -/* skip whitespace in the input "stream". - * rgerhards, 2008-02-19 - */ -static rsRetVal -ctokSkipWhitespaceFromStream(ctok_t *pThis) -{ - DEFiRet; - uchar c; - - ISOBJ_TYPE_assert(pThis, ctok); - - CHKiRet(ctokGetCharFromStream(pThis, &c)); - while(isspace(c)) { - CHKiRet(ctokGetCharFromStream(pThis, &c)); - } - - /* we must unget the one non-whitespace we found */ - CHKiRet(ctokUngetCharFromStream(pThis, c)); - -dbgprintf("skipped whitespace, stream now '%s'\n", pThis->pp); -finalize_it: - RETiRet; -} - - -/* get the next word from the input "stream" (currently just a in-memory - * string...). A word is anything from the current location until the - * first non-alphanumeric character. If the word is longer - * than the provided memory buffer, parsing terminates when buffer length - * has been reached. A buffer of 128 bytes or more should always be by - * far sufficient. -- rgerhards, 2008-02-19 - */ -static rsRetVal -ctokGetWordFromStream(ctok_t *pThis, uchar *pWordBuf, size_t lenWordBuf) -{ - DEFiRet; - uchar c; - - ISOBJ_TYPE_assert(pThis, ctok); - ASSERT(pWordBuf != NULL); - ASSERT(lenWordBuf > 0); - - CHKiRet(ctokSkipWhitespaceFromStream(pThis)); - - CHKiRet(ctokGetCharFromStream(pThis, &c)); - while((isalnum(c) || c == '_' || c == '-') && lenWordBuf > 1) { - *pWordBuf++ = c; - --lenWordBuf; - CHKiRet(ctokGetCharFromStream(pThis, &c)); - } - *pWordBuf = '\0'; /* there is always space for this - see while() */ - - /* push back the char that we have read too much */ - CHKiRet(ctokUngetCharFromStream(pThis, c)); - -finalize_it: - RETiRet; -} - - -/* read in a constant number - * This is the "number" ABNF element - * rgerhards, 2008-02-19 - */ -static rsRetVal -ctokGetNumber(ctok_t *pThis, ctok_token_t *pToken) -{ - DEFiRet; - number_t n; /* the parsed number */ - uchar c; - int valC; - int iBase; - - ISOBJ_TYPE_assert(pThis, ctok); - ASSERT(pToken != NULL); - - pToken->tok = ctok_NUMBER; - - CHKiRet(ctokGetCharFromStream(pThis, &c)); - if(c == '0') { /* octal? */ - CHKiRet(ctokGetCharFromStream(pThis, &c)); - if(c == 'x') { /* nope, hex! */ - CHKiRet(ctokGetCharFromStream(pThis, &c)); - c = tolower(c); - iBase = 16; - } else { - iBase = 8; - } - } else { - iBase = 10; - } - - n = 0; - /* this loop is quite simple, a variable name is terminated by whitespace. */ - while(isdigit(c) || (c >= 'a' && c <= 'f')) { - if(isdigit(c)) { - valC = c - '0'; - } else { - valC = c - 'a' + 10; - } - - if(valC >= iBase) { - if(iBase == 8) { - ABORT_FINALIZE(RS_RET_INVALID_OCTAL_DIGIT); - } else { - ABORT_FINALIZE(RS_RET_INVALID_HEX_DIGIT); - } - } - /* we now have the next value and know it is right */ - n = n * iBase + valC; - CHKiRet(ctokGetCharFromStream(pThis, &c)); - c = tolower(c); - } - - /* we need to unget the character that made the loop terminate */ - CHKiRet(ctokUngetCharFromStream(pThis, c)); - - CHKiRet(var.SetNumber(pToken->pVar, n)); - -finalize_it: - RETiRet; -} - - -/* read in a variable - * This covers both msgvar and sysvar from the ABNF. - * rgerhards, 2008-02-19 - */ -static rsRetVal -ctokGetVar(ctok_t *pThis, ctok_token_t *pToken) -{ - DEFiRet; - uchar c; - cstr_t *pstrVal = NULL; - - ISOBJ_TYPE_assert(pThis, ctok); - ASSERT(pToken != NULL); - - CHKiRet(ctokGetCharFromStream(pThis, &c)); - - if(c == '$') { /* second dollar, we have a system variable */ - pToken->tok = ctok_SYSVAR; - CHKiRet(ctokGetCharFromStream(pThis, &c)); /* "eat" it... */ - } else if(c == '!') { /* cee variable indicator */ - pToken->tok = ctok_CEEVAR; - CHKiRet(ctokGetCharFromStream(pThis, &c)); /* "eat" it... */ - } else { - pToken->tok = ctok_MSGVAR; - } - - CHKiRet(cstrConstruct(&pstrVal)); - /* this loop is quite simple, a variable name is terminated when a non-supported - * character is detected. Note that we currently permit a numerical digit as the - * first char, which is not permitted by ABNF. -- rgerhards, 2009-03-10 - */ - while(isalpha(c) || isdigit(c) || (c == '_') || (c == '-')) { - CHKiRet(cstrAppendChar(pstrVal, tolower(c))); - CHKiRet(ctokGetCharFromStream(pThis, &c)); - } - CHKiRet(ctokUngetCharFromStream(pThis, c)); /* put not processed char back */ - - CHKiRet(cstrFinalize(pstrVal)); - - CHKiRet(var.SetString(pToken->pVar, pstrVal)); - pstrVal = NULL; - -finalize_it: - if(iRet != RS_RET_OK) { - if(pstrVal != NULL) { - cstrDestruct(&pstrVal); - } - } - - RETiRet; -} - - -/* read in a simple string (simpstr in ABNF) - * rgerhards, 2008-02-19 - */ -static rsRetVal -ctokGetSimpStr(ctok_t *pThis, ctok_token_t *pToken) -{ - DEFiRet; - uchar c; - int bInEsc = 0; - cstr_t *pstrVal; - - ISOBJ_TYPE_assert(pThis, ctok); - ASSERT(pToken != NULL); - - pToken->tok = ctok_SIMPSTR; - - CHKiRet(cstrConstruct(&pstrVal)); - CHKiRet(ctokGetCharFromStreamNoComment(pThis, &c)); - /* while we are in escape mode (had a backslash), no sequence - * terminates the loop. If outside, it is terminated by a single quote. - */ - while(bInEsc || c != '\'') { - if(bInEsc) { - CHKiRet(cstrAppendChar(pstrVal, c)); - bInEsc = 0; - } else { - if(c == '\\') { - bInEsc = 1; - } else { - CHKiRet(cstrAppendChar(pstrVal, c)); - } - } - CHKiRet(ctokGetCharFromStreamNoComment(pThis, &c)); - } - CHKiRet(cstrFinalize(pstrVal)); - - CHKiRet(var.SetString(pToken->pVar, pstrVal)); - pstrVal = NULL; - -finalize_it: - if(iRet != RS_RET_OK) { - if(pstrVal != NULL) { - cstrDestruct(&pstrVal); - } - } - - RETiRet; -} - - -/* Unget a token. The token ungotten will be returned the next time - * ctokGetToken() is called. Only one token can be ungotten at a time. - * If a second token is ungotten, the first is lost. This is considered - * a programming error. - * rgerhards, 2008-02-20 - */ -static rsRetVal -ctokUngetToken(ctok_t *pThis, ctok_token_t *pToken) -{ - DEFiRet; - - ISOBJ_TYPE_assert(pThis, ctok); - ASSERT(pToken != NULL); - ASSERT(pThis->pUngotToken == NULL); - - pThis->pUngotToken = pToken; - - RETiRet; -} - - -/* skip an inine comment (just like a C-comment) - * rgerhards, 2008-02-20 - */ -static rsRetVal -ctokSkipInlineComment(ctok_t *pThis) -{ - DEFiRet; - uchar c; - int bHadAsterisk = 0; - - ISOBJ_TYPE_assert(pThis, ctok); - - CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read a charater */ - while(!(bHadAsterisk && c == '/')) { - bHadAsterisk = (c == '*') ? 1 : 0; - CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read next */ - } - -finalize_it: - RETiRet; -} - - - -/* Get the *next* token from the input stream. This parses the next token and - * ignores any whitespace in between. End of stream is communicated via iRet. - * The returned token must either be destructed by the caller OR being passed - * back to ctokUngetToken(). - * rgerhards, 2008-02-19 - */ -static rsRetVal -ctokGetToken(ctok_t *pThis, ctok_token_t **ppToken) -{ - DEFiRet; - ctok_token_t *pToken; - uchar c; - uchar szWord[128]; - int bRetry = 0; /* retry parse? Only needed for inline comments... */ - cstr_t *pstrVal; - - ISOBJ_TYPE_assert(pThis, ctok); - ASSERT(ppToken != NULL); - - /* first check if we have an ungotten token and, if so, provide that - * one back (without any parsing). -- rgerhards, 2008-02-20 - */ - if(pThis->pUngotToken != NULL) { - *ppToken = pThis->pUngotToken; - pThis->pUngotToken = NULL; - FINALIZE; - } - - /* setup the stage - create our token */ - CHKiRet(ctok_token.Construct(&pToken)); - CHKiRet(ctok_token.ConstructFinalize(pToken)); - - /* find the next token. We may loop when we have inline comments */ - do { - bRetry = 0; - CHKiRet(ctokSkipWhitespaceFromStream(pThis)); - CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read a charater */ - switch(c) { - case '=': /* == */ - CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read a character */ - pToken->tok = (c == '=')? ctok_CMP_EQ : ctok_INVALID; - break; - case '!': /* != */ - CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read a character */ - pToken->tok = (c == '=')? ctok_CMP_NEQ : ctok_INVALID; - break; - case '<': /* <, <=, <> */ - CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read a character */ - if(c == '=') { - pToken->tok = ctok_CMP_LTEQ; - } else if(c == '>') { - pToken->tok = ctok_CMP_NEQ; - } else { - pToken->tok = ctok_CMP_LT; - } - break; - case '>': /* >, >= */ - CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read a character */ - if(c == '=') { - pToken->tok = ctok_CMP_GTEQ; - } else { - pToken->tok = ctok_CMP_GT; - } - break; - case '+': - pToken->tok = ctok_PLUS; - break; - case '-': - pToken->tok = ctok_MINUS; - break; - case '*': - pToken->tok = ctok_TIMES; - break; - case '/': /* /, /.* ... *./ (comments, mungled here for obvious reasons...) */ - CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read a charater */ - if(c == '*') { - /* we have a comment and need to skip it */ - ctokSkipInlineComment(pThis); - bRetry = 1; - } else { - CHKiRet(ctokUngetCharFromStream(pThis, c)); /* put back, not processed */ - } - pToken->tok = ctok_DIV; - break; - case '%': - pToken->tok = ctok_MOD; - break; - case '(': - pToken->tok = ctok_LPAREN; - break; - case ')': - pToken->tok = ctok_RPAREN; - break; - case ',': - pToken->tok = ctok_COMMA; - break; - case '&': - pToken->tok = ctok_STRADD; - break; - case '$': - CHKiRet(ctokGetVar(pThis, pToken)); - break; - case '\'': /* simple string, this is somewhat more elaborate */ - CHKiRet(ctokGetSimpStr(pThis, pToken)); - break; - case '"': - /* TODO: template string parser */ - ABORT_FINALIZE(RS_RET_NOT_IMPLEMENTED); - break; - default: - CHKiRet(ctokUngetCharFromStream(pThis, c)); /* push back, we need it in any case */ - if(isdigit(c)) { - CHKiRet(ctokGetNumber(pThis, pToken)); - } else { /* now we check if we have a multi-char sequence */ - CHKiRet(ctokGetWordFromStream(pThis, szWord, sizeof(szWord)/sizeof(uchar))); - if(!strcasecmp((char*)szWord, "and")) { - pToken->tok = ctok_AND; - } else if(!strcasecmp((char*)szWord, "or")) { - pToken->tok = ctok_OR; - } else if(!strcasecmp((char*)szWord, "not")) { - pToken->tok = ctok_NOT; - } else if(!strcasecmp((char*)szWord, "contains")) { - pToken->tok = ctok_CMP_CONTAINS; - } else if(!strcasecmp((char*)szWord, "contains_i")) { - pToken->tok = ctok_CMP_CONTAINSI; - } else if(!strcasecmp((char*)szWord, "startswith")) { - pToken->tok = ctok_CMP_STARTSWITH; - } else if(!strcasecmp((char*)szWord, "startswith_i")) { - pToken->tok = ctok_CMP_STARTSWITHI; - } else if(!strcasecmp((char*)szWord, "then")) { - pToken->tok = ctok_THEN; - } else { - /* finally, we check if it is a function */ - CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read a charater */ - if(c == '(') { - /* push c back, higher level parser needs it */ - CHKiRet(ctokUngetCharFromStream(pThis, c)); - pToken->tok = ctok_FUNCTION; - /* fill function name */ - CHKiRet(cstrConstruct(&pstrVal)); - CHKiRet(rsCStrSetSzStr(pstrVal, szWord)); - CHKiRet(cstrFinalize(pstrVal)); - CHKiRet(var.SetString(pToken->pVar, pstrVal)); - } else { /* give up... */ - dbgprintf("parser has an invalid word (token) '%s'\n", szWord); - pToken->tok = ctok_INVALID; - } - } - } - break; - } - } while(bRetry); /* warning: do ... while()! */ - - *ppToken = pToken; - dbgoprint((obj_t*) pToken, "token: %d\n", pToken->tok); - -finalize_it: -/*dbgprintf("ctokGetToken, returns %d, returns token %d, addr %p\n", iRet, (*ppToken)->tok, &((*ppToken)->tok));*/ - if(iRet != RS_RET_OK) { - if(pToken != NULL) - ctok_token.Destruct(&pToken); - } - - RETiRet; -} - - -/* property set methods */ -/* simple ones first */ -DEFpropSetMeth(ctok, pp, uchar*) - -/* return the current position of pp - most important as currently we do only - * partial parsing, so the rest must know where to start from... - * rgerhards, 2008-02-19 - */ -static rsRetVal -ctokGetpp(ctok_t *pThis, uchar **pp) -{ - DEFiRet; - ASSERT(pp != NULL); - *pp = pThis->pp; - RETiRet; -} - - -/* queryInterface function - * rgerhards, 2008-02-21 - */ -BEGINobjQueryInterface(ctok) -CODESTARTobjQueryInterface(ctok) - if(pIf->ifVersion != ctokCURR_IF_VERSION) { /* check for current version, increment on each change */ - ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED); - } - - /* ok, we have the right interface, so let's fill it - * Please note that we may also do some backwards-compatibility - * work here (if we can support an older interface version - that, - * of course, also affects the "if" above). - */ - pIf->Construct = ctokConstruct; - pIf->ConstructFinalize = ctokConstructFinalize; - pIf->Destruct = ctokDestruct; - pIf->Getpp = ctokGetpp; - pIf->GetToken = ctokGetToken; - pIf->UngetToken = ctokUngetToken; - pIf->Setpp = ctokSetpp; -finalize_it: -ENDobjQueryInterface(ctok) - - - -BEGINObjClassInit(ctok, 1, OBJ_IS_CORE_MODULE) /* class, version */ - /* request objects we use */ - CHKiRet(objUse(ctok_token, CORE_COMPONENT)); - CHKiRet(objUse(var, CORE_COMPONENT)); - - OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, ctokConstructFinalize); -ENDObjClassInit(ctok) - -/* vi:set ai: - */ diff --git a/runtime/ctok.h b/runtime/ctok.h deleted file mode 100644 index 591f0838..00000000 --- a/runtime/ctok.h +++ /dev/null @@ -1,56 +0,0 @@ -/* The ctok object (implements a config file tokenizer). - * - * Copyright 2008 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 <http://www.gnu.org/licenses/>. - * - * 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. - */ -#ifndef INCLUDED_CTOK_H -#define INCLUDED_CTOK_H - -#include "obj.h" -#include "stringbuf.h" -#include "ctok_token.h" - -/* the ctokession object */ -typedef struct ctok_s { - BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ - uchar *pp; /* this points to the next unread character, it is a reminescent of pp in - the config parser code ;) */ - ctok_token_t *pUngotToken; /* buffer for ctokUngetToken(), NULL if not set */ -} ctok_t; - - -/* interfaces */ -BEGINinterface(ctok) /* name must also be changed in ENDinterface macro! */ - INTERFACEObjDebugPrint(ctok); - INTERFACEpropSetMeth(ctok, pp, uchar*); - rsRetVal (*Construct)(ctok_t **ppThis); - rsRetVal (*ConstructFinalize)(ctok_t __attribute__((unused)) *pThis); - rsRetVal (*Destruct)(ctok_t **ppThis); - rsRetVal (*Getpp)(ctok_t *pThis, uchar **pp); - rsRetVal (*GetToken)(ctok_t *pThis, ctok_token_t **ppToken); - rsRetVal (*UngetToken)(ctok_t *pThis, ctok_token_t *pToken); -ENDinterface(ctok) -#define ctokCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */ - - -/* prototypes */ -PROTOTYPEObj(ctok); - -#endif /* #ifndef INCLUDED_CTOK_H */ diff --git a/runtime/ctok_token.c b/runtime/ctok_token.c deleted file mode 100644 index 8c17f693..00000000 --- a/runtime/ctok_token.c +++ /dev/null @@ -1,129 +0,0 @@ -/* ctok_token - implements the token_t class. - * - * Module begun 2008-02-20 by Rainer Gerhards - * - * Copyright 2008 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 <http://www.gnu.org/licenses/>. - * - * 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 <stdlib.h> -#include <ctype.h> -#include <strings.h> -#include <assert.h> - -#include "rsyslog.h" -#include "template.h" -#include "ctok_token.h" - -/* static data */ -DEFobjStaticHelpers -DEFobjCurrIf(var) - - -/* Standard-Constructor - */ -BEGINobjConstruct(ctok_token) /* be sure to specify the object type also in END macro! */ - /* TODO: we may optimize the code below and alloc var only if actually - * needed (but we need it quite often) - */ - CHKiRet(var.Construct(&pThis->pVar)); - CHKiRet(var.ConstructFinalize(pThis->pVar)); -finalize_it: -ENDobjConstruct(ctok_token) - - -/* ConstructionFinalizer - * rgerhards, 2008-01-09 - */ -rsRetVal ctok_tokenConstructFinalize(ctok_token_t __attribute__((unused)) *pThis) -{ - DEFiRet; - RETiRet; -} - - -/* destructor for the ctok object */ -BEGINobjDestruct(ctok_token) /* be sure to specify the object type also in END and CODESTART macros! */ -CODESTARTobjDestruct(ctok_token) - if(pThis->pVar != NULL) { - var.Destruct(&pThis->pVar); - } -ENDobjDestruct(ctok_token) - - -/* get the cstr_t from the token, but do not destruct it. This is meant to - * be used by a caller who passes on the string to some other function. The - * caller is responsible for destructing it. - * rgerhards, 2008-02-20 - */ -static rsRetVal -ctok_tokenUnlinkVar(ctok_token_t *pThis, var_t **ppVar) -{ - DEFiRet; - - ISOBJ_TYPE_assert(pThis, ctok_token); - ASSERT(ppVar != NULL); - - *ppVar = pThis->pVar; - pThis->pVar = NULL; - - RETiRet; -} - - -/* tell the caller if the supplied token is a compare operation */ -static int ctok_tokenIsCmpOp(ctok_token_t *pThis) -{ - return(pThis->tok >= ctok_CMP_EQ && pThis->tok <= ctok_CMP_GTEQ); -} - -/* queryInterface function - * rgerhards, 2008-02-21 - */ -BEGINobjQueryInterface(ctok_token) -CODESTARTobjQueryInterface(ctok_token) - if(pIf->ifVersion != ctok_tokenCURR_IF_VERSION) { /* check for current version, increment on each change */ - ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED); - } - - /* ok, we have the right interface, so let's fill it - * Please note that we may also do some backwards-compatibility - * work here (if we can support an older interface version - that, - * of course, also affects the "if" above). - */ - pIf->Construct = ctok_tokenConstruct; - pIf->ConstructFinalize = ctok_tokenConstructFinalize; - pIf->Destruct = ctok_tokenDestruct; - pIf->UnlinkVar = ctok_tokenUnlinkVar; - pIf->IsCmpOp = ctok_tokenIsCmpOp; -finalize_it: -ENDobjQueryInterface(ctok_token) - - -BEGINObjClassInit(ctok_token, 1, OBJ_IS_CORE_MODULE) /* class, version */ - /* request objects we use */ - CHKiRet(objUse(var, CORE_COMPONENT)); - - OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, ctok_tokenConstructFinalize); -ENDObjClassInit(ctok_token) - -/* vi:set ai: - */ diff --git a/runtime/ctok_token.h b/runtime/ctok_token.h deleted file mode 100644 index 1413c699..00000000 --- a/runtime/ctok_token.h +++ /dev/null @@ -1,88 +0,0 @@ -/* The ctok_token object - * - * Copyright 2008 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 <http://www.gnu.org/licenses/>. - * - * 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. - */ -#ifndef INCLUDED_CTOK_TOKEN_H -#define INCLUDED_CTOK_TOKEN_H - -#include "obj.h" -#include "var.h" - -/* the tokens... I use numbers below so that the tokens can be easier - * identified in debug output. These ID's are also partly resused as opcodes. - * As such, they should be kept below 1,000 so that they do not interfer - * with the rest of the opcodes. - */ -typedef struct { - BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ - enum { - ctok_INVALID = 0, - ctok_OR = 1, - ctok_AND = 2, - ctok_PLUS = 3, - ctok_MINUS = 4, - ctok_TIMES = 5, /* "*" */ - ctok_DIV = 6, - ctok_MOD = 7, - ctok_NOT = 8, - ctok_RPAREN = 9, - ctok_LPAREN = 10, - ctok_COMMA = 11, - ctok_SYSVAR = 12, - ctok_MSGVAR = 13, - ctok_SIMPSTR = 14, - ctok_TPLSTR = 15, - ctok_NUMBER = 16, - ctok_FUNCTION = 17, - ctok_THEN = 18, - ctok_STRADD = 19, - ctok_CEEVAR = 20, - ctok_CMP_EQ = 100, /* all compare operations must be in a row */ - ctok_CMP_NEQ = 101, - ctok_CMP_LT = 102, - ctok_CMP_GT = 103, - ctok_CMP_LTEQ = 104, - ctok_CMP_CONTAINS = 105, - ctok_CMP_STARTSWITH = 106, - ctok_CMP_CONTAINSI = 107, - ctok_CMP_STARTSWITHI = 108, - ctok_CMP_GTEQ = 109 /* end compare operations */ - } tok; - var_t *pVar; -} ctok_token_t; - - -/* interfaces */ -BEGINinterface(ctok_token) /* name must also be changed in ENDinterface macro! */ - INTERFACEObjDebugPrint(ctok_token); - rsRetVal (*Construct)(ctok_token_t **ppThis); - rsRetVal (*ConstructFinalize)(ctok_token_t __attribute__((unused)) *pThis); - rsRetVal (*Destruct)(ctok_token_t **ppThis); - rsRetVal (*UnlinkVar)(ctok_token_t *pThis, var_t **ppVar); - int (*IsCmpOp)(ctok_token_t *pThis); -ENDinterface(ctok_token) -#define ctok_tokenCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */ - - -/* prototypes */ -PROTOTYPEObj(ctok_token); - -#endif /* #ifndef INCLUDED_CTOK_TOKEN_H */ diff --git a/runtime/datetime.c b/runtime/datetime.c index 89452f1c..753d2068 100644 --- a/runtime/datetime.c +++ b/runtime/datetime.c @@ -40,7 +40,6 @@ #include "obj.h" #include "modules.h" #include "datetime.h" -#include "sysvar.h" #include "srUtils.h" #include "stringbuf.h" #include "errmsg.h" diff --git a/runtime/errmsg.c b/runtime/errmsg.c index 3c3ee02c..d9062931 100644 --- a/runtime/errmsg.c +++ b/runtime/errmsg.c @@ -35,7 +35,6 @@ #include "rsyslog.h" #include "obj.h" #include "errmsg.h" -#include "sysvar.h" #include "srUtils.h" #include "stringbuf.h" diff --git a/runtime/expr.c b/runtime/expr.c deleted file mode 100644 index 01431474..00000000 --- a/runtime/expr.c +++ /dev/null @@ -1,482 +0,0 @@ -/* expr.c - an expression class. - * This module contains all code needed to represent expressions. Most - * importantly, that means code to parse and execute them. Expressions - * heavily depend on (loadable) functions, so it works in conjunction - * with the function manager. - * - * Module begun 2007-11-30 by Rainer Gerhards - * - * Copyright 2007, 2008 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 <http://www.gnu.org/licenses/>. - * - * 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 <stdlib.h> -#include <assert.h> - -#include "rsyslog.h" -#include "template.h" -#include "expr.h" - -/* static data */ -DEFobjStaticHelpers -DEFobjCurrIf(vmprg) -DEFobjCurrIf(var) -DEFobjCurrIf(ctok_token) -DEFobjCurrIf(ctok) - - -/* ------------------------------ parser functions ------------------------------ */ -/* the following functions implement the parser. They are all static. For - * simplicity, the function names match their ABNF definition. The ABNF is defined - * in the doc set. See file expression.html for details. I do *not* reproduce it - * here in an effort to keep both files in sync. - * - * All functions receive the current expression object as parameter as well as the - * current tokenizer. - * - * rgerhards, 2008-02-19 - */ - -/* forward definition - thanks to recursive ABNF, we can not avoid at least one ;) */ -static rsRetVal expr(expr_t *pThis, ctok_t *tok); - - -static rsRetVal -function(expr_t *pThis, ctok_t *tok) -{ - DEFiRet; - ctok_token_t *pToken = NULL; - int iNumArgs = 0; - var_t *pVar; - - ISOBJ_TYPE_assert(pThis, expr); - ISOBJ_TYPE_assert(tok, ctok); - - CHKiRet(ctok.GetToken(tok, &pToken)); - /* note: pToken is destructed in finalize_it */ - - if(pToken->tok == ctok_LPAREN) { - CHKiRet(ctok_token.Destruct(&pToken)); /* token processed, "eat" it */ - CHKiRet(ctok.GetToken(tok, &pToken)); /* get next one */ - } else - ABORT_FINALIZE(RS_RET_FUNC_NO_LPAREN); - - /* we first push all the params on the stack. Then we call the function */ - while(pToken->tok != ctok_RPAREN) { - ++iNumArgs; - CHKiRet(ctok.UngetToken(tok, pToken)); /* not for us, so let others process it */ - CHKiRet(expr(pThis, tok)); - CHKiRet(ctok.GetToken(tok, &pToken)); /* get next one, needed for while() check */ - if(pToken->tok == ctok_COMMA) { - CHKiRet(ctok_token.Destruct(&pToken)); /* token processed, "eat" it */ - CHKiRet(ctok.GetToken(tok, &pToken)); /* get next one */ - if(pToken->tok == ctok_RPAREN) { - ABORT_FINALIZE(RS_RET_FUNC_MISSING_EXPR); - } - } - } - - - /* now push number of arguments - this must be on top of the stack */ - CHKiRet(var.Construct(&pVar)); - CHKiRet(var.ConstructFinalize(pVar)); - CHKiRet(var.SetNumber(pVar, iNumArgs)); - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_PUSHCONSTANT, pVar)); /* add to program */ - - -finalize_it: - if(pToken != NULL) { - ctok_token.Destruct(&pToken); /* "eat" processed token */ - } - - RETiRet; -} - - -static rsRetVal -terminal(expr_t *pThis, ctok_t *tok) -{ - DEFiRet; - ctok_token_t *pToken = NULL; - var_t *pVar; - - ISOBJ_TYPE_assert(pThis, expr); - ISOBJ_TYPE_assert(tok, ctok); - - CHKiRet(ctok.GetToken(tok, &pToken)); - /* note: pToken is destructed in finalize_it */ - - switch(pToken->tok) { - case ctok_SIMPSTR: - dbgoprint((obj_t*) pThis, "simpstr\n"); - CHKiRet(ctok_token.UnlinkVar(pToken, &pVar)); - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_PUSHCONSTANT, pVar)); /* add to program */ - break; - case ctok_NUMBER: - dbgoprint((obj_t*) pThis, "number\n"); - CHKiRet(ctok_token.UnlinkVar(pToken, &pVar)); - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_PUSHCONSTANT, pVar)); /* add to program */ - break; - case ctok_FUNCTION: - dbgoprint((obj_t*) pThis, "function\n"); - CHKiRet(function(pThis, tok)); /* this creates the stack call frame */ - /* ... but we place the call instruction onto the stack ourselfs (because - * we have all relevant information) - */ - CHKiRet(ctok_token.UnlinkVar(pToken, &pVar)); - CHKiRet(var.ConvToString(pVar)); /* make sure we have a string */ - CHKiRet(vmprg.AddCallOperation(pThis->pVmprg, pVar->val.pStr)); /* add to program */ - CHKiRet(var.Destruct(&pVar)); - break; - case ctok_MSGVAR: - dbgoprint((obj_t*) pThis, "MSGVAR\n"); - CHKiRet(ctok_token.UnlinkVar(pToken, &pVar)); - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_PUSHMSGVAR, pVar)); /* add to program */ - break; - case ctok_CEEVAR: - dbgoprint((obj_t*) pThis, "SYSVAR\n"); - CHKiRet(ctok_token.UnlinkVar(pToken, &pVar)); - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_PUSHCEEVAR, pVar)); /* add to program */ - break; - case ctok_SYSVAR: - dbgoprint((obj_t*) pThis, "SYSVAR\n"); - CHKiRet(ctok_token.UnlinkVar(pToken, &pVar)); - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_PUSHSYSVAR, pVar)); /* add to program */ - break; - case ctok_LPAREN: - dbgoprint((obj_t*) pThis, "expr\n"); - CHKiRet(ctok_token.Destruct(&pToken)); /* "eat" processed token */ - CHKiRet(expr(pThis, tok)); - CHKiRet(ctok.GetToken(tok, &pToken)); /* get next one */ - if(pToken->tok != ctok_RPAREN) - ABORT_FINALIZE(RS_RET_SYNTAX_ERROR); - break; - default: - dbgoprint((obj_t*) pThis, "invalid token %d\n", pToken->tok); - ABORT_FINALIZE(RS_RET_SYNTAX_ERROR); - break; - } - -finalize_it: - if(pToken != NULL) { - ctok_token.Destruct(&pToken); /* "eat" processed token */ - } - - RETiRet; -} - -static rsRetVal -factor(expr_t *pThis, ctok_t *tok) -{ - DEFiRet; - ctok_token_t *pToken; - int bWasNot; - int bWasUnaryMinus; - - ISOBJ_TYPE_assert(pThis, expr); - ISOBJ_TYPE_assert(tok, ctok); - - CHKiRet(ctok.GetToken(tok, &pToken)); - if(pToken->tok == ctok_NOT) { - dbgprintf("not\n"); - bWasNot = 1; - CHKiRet(ctok_token.Destruct(&pToken)); /* no longer needed */ - CHKiRet(ctok.GetToken(tok, &pToken)); /* get new one for next check */ - } else { - bWasNot = 0; - } - - if(pToken->tok == ctok_MINUS) { - dbgprintf("unary minus\n"); - bWasUnaryMinus = 1; - CHKiRet(ctok_token.Destruct(&pToken)); /* no longer needed */ - } else { - bWasUnaryMinus = 0; - /* we could not process the token, so push it back */ - CHKiRet(ctok.UngetToken(tok, pToken)); - } - - CHKiRet(terminal(pThis, tok)); - - /* warning: the order if the two following ifs is important. Do not change them, this - * would change the semantics of the expression! - */ - if(bWasUnaryMinus) { - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_UNARY_MINUS, NULL)); /* add to program */ - } - - if(bWasNot == 1) { - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_NOT, NULL)); /* add to program */ - } - -finalize_it: - RETiRet; -} - - -static rsRetVal -term(expr_t *pThis, ctok_t *tok) -{ - DEFiRet; - ctok_token_t *pToken; - - ISOBJ_TYPE_assert(pThis, expr); - ISOBJ_TYPE_assert(tok, ctok); - - CHKiRet(factor(pThis, tok)); - - /* *(("*" / "/" / "%") factor) part */ - CHKiRet(ctok.GetToken(tok, &pToken)); - while(pToken->tok == ctok_TIMES || pToken->tok == ctok_DIV || pToken->tok == ctok_MOD) { - dbgoprint((obj_t*) pThis, "/,*,%%\n"); - CHKiRet(factor(pThis, tok)); - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, (opcode_t) pToken->tok, NULL)); /* add to program */ - CHKiRet(ctok_token.Destruct(&pToken)); /* no longer needed */ - CHKiRet(ctok.GetToken(tok, &pToken)); - } - - /* unget the token that made us exit the loop - it's obviously not one - * we can process. - */ - CHKiRet(ctok.UngetToken(tok, pToken)); - -finalize_it: - RETiRet; -} - -static rsRetVal -val(expr_t *pThis, ctok_t *tok) -{ - DEFiRet; - ctok_token_t *pToken; - - ISOBJ_TYPE_assert(pThis, expr); - ISOBJ_TYPE_assert(tok, ctok); - - CHKiRet(term(pThis, tok)); - - /* *(("+" / "-") term) part */ - CHKiRet(ctok.GetToken(tok, &pToken)); - while(pToken->tok == ctok_PLUS || pToken->tok == ctok_MINUS || pToken->tok == ctok_STRADD) { - dbgoprint((obj_t*) pThis, "+/-/&\n"); - CHKiRet(term(pThis, tok)); - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, (opcode_t) pToken->tok, NULL)); /* add to program */ - CHKiRet(ctok_token.Destruct(&pToken)); /* no longer needed */ - CHKiRet(ctok.GetToken(tok, &pToken)); - } - - /* unget the token that made us exit the loop - it's obviously not one - * we can process. - */ - CHKiRet(ctok.UngetToken(tok, pToken)); - -finalize_it: - RETiRet; -} - - -static rsRetVal -e_cmp(expr_t *pThis, ctok_t *tok) -{ - DEFiRet; - ctok_token_t *pToken; - - ISOBJ_TYPE_assert(pThis, expr); - ISOBJ_TYPE_assert(tok, ctok); - - CHKiRet(val(pThis, tok)); - - /* 0*1(cmp_op val) part */ - CHKiRet(ctok.GetToken(tok, &pToken)); - if(ctok_token.IsCmpOp(pToken)) { - dbgoprint((obj_t*) pThis, "cmp\n"); - CHKiRet(val(pThis, tok)); - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, (opcode_t) pToken->tok, NULL)); /* add to program */ - CHKiRet(ctok_token.Destruct(&pToken)); /* no longer needed */ - } else { - /* we could not process the token, so push it back */ - CHKiRet(ctok.UngetToken(tok, pToken)); - } - - -finalize_it: - RETiRet; -} - - -static rsRetVal -e_and(expr_t *pThis, ctok_t *tok) -{ - DEFiRet; - ctok_token_t *pToken; - - ISOBJ_TYPE_assert(pThis, expr); - ISOBJ_TYPE_assert(tok, ctok); - - CHKiRet(e_cmp(pThis, tok)); - - /* *("and" e_cmp) part */ - CHKiRet(ctok.GetToken(tok, &pToken)); - while(pToken->tok == ctok_AND) { - dbgoprint((obj_t*) pThis, "and\n"); - CHKiRet(e_cmp(pThis, tok)); - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_AND, NULL)); /* add to program */ - CHKiRet(ctok_token.Destruct(&pToken)); /* no longer needed */ - CHKiRet(ctok.GetToken(tok, &pToken)); - } - - /* unget the token that made us exit the loop - it's obviously not one - * we can process. - */ - CHKiRet(ctok.UngetToken(tok, pToken)); - -finalize_it: - RETiRet; -} - - -static rsRetVal -expr(expr_t *pThis, ctok_t *tok) -{ - DEFiRet; - ctok_token_t *pToken; - - ISOBJ_TYPE_assert(pThis, expr); - ISOBJ_TYPE_assert(tok, ctok); - - CHKiRet(e_and(pThis, tok)); - - /* *("or" e_and) part */ - CHKiRet(ctok.GetToken(tok, &pToken)); - while(pToken->tok == ctok_OR) { - dbgoprint((obj_t*) pThis, "found OR\n"); - CHKiRet(e_and(pThis, tok)); - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_OR, NULL)); /* add to program */ - CHKiRet(ctok_token.Destruct(&pToken)); /* no longer needed */ - CHKiRet(ctok.GetToken(tok, &pToken)); - } - - /* unget the token that made us exit the loop - it's obviously not one - * we can process. - */ - CHKiRet(ctok.UngetToken(tok, pToken)); - -finalize_it: - RETiRet; -} - - -/* ------------------------------ end parser functions ------------------------------ */ - - -/* ------------------------------ actual expr object functions ------------------------------ */ - -/* Standard-Constructor - * rgerhards, 2008-02-09 (a rainy Tenerife return flight day ;)) - */ -BEGINobjConstruct(expr) /* be sure to specify the object type also in END macro! */ -ENDobjConstruct(expr) - - -/* ConstructionFinalizer - * rgerhards, 2008-01-09 - */ -rsRetVal exprConstructFinalize(expr_t __attribute__((unused)) *pThis) -{ - DEFiRet; - - ISOBJ_TYPE_assert(pThis, expr); - - RETiRet; -} - - -/* destructor for the expr object */ -BEGINobjDestruct(expr) /* be sure to specify the object type also in END and CODESTART macros! */ -CODESTARTobjDestruct(expr) - if(pThis->pVmprg != NULL) - vmprg.Destruct(&pThis->pVmprg); -ENDobjDestruct(expr) - - -/* parse an expression object based on a given tokenizer - * rgerhards, 2008-02-19 - */ -rsRetVal -exprParse(expr_t *pThis, ctok_t *tok) -{ - DEFiRet; - - ISOBJ_TYPE_assert(pThis, expr); - ISOBJ_TYPE_assert(tok, ctok); - - /* first, we need to make sure we have a program where we can add to what we parse... */ - CHKiRet(vmprg.Construct(&pThis->pVmprg)); - CHKiRet(vmprg.ConstructFinalize(pThis->pVmprg)); - - /* happy parsing... */ - CHKiRet(expr(pThis, tok)); - dbgoprint((obj_t*) pThis, "successfully parsed/created expression\n"); - -finalize_it: - RETiRet; -} - - -/* queryInterface function - * rgerhards, 2008-02-21 - */ -BEGINobjQueryInterface(expr) -CODESTARTobjQueryInterface(expr) - if(pIf->ifVersion != exprCURR_IF_VERSION) { /* check for current version, increment on each change */ - ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED); - } - - /* ok, we have the right interface, so let's fill it - * Please note that we may also do some backwards-compatibility - * work here (if we can support an older interface version - that, - * of course, also affects the "if" above). - */ - pIf->Construct = exprConstruct; - pIf->ConstructFinalize = exprConstructFinalize; - pIf->Destruct = exprDestruct; - pIf->Parse = exprParse; -finalize_it: -ENDobjQueryInterface(expr) - - -/* Initialize the expr class. Must be called as the very first method - * before anything else is called inside this class. - * rgerhards, 2008-02-19 - */ -BEGINObjClassInit(expr, 1, OBJ_IS_CORE_MODULE) /* class, version */ - /* request objects we use */ - CHKiRet(objUse(var, CORE_COMPONENT)); - CHKiRet(objUse(vmprg, CORE_COMPONENT)); - CHKiRet(objUse(var, CORE_COMPONENT)); - CHKiRet(objUse(ctok_token, CORE_COMPONENT)); - CHKiRet(objUse(ctok, CORE_COMPONENT)); - - OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, exprConstructFinalize); -ENDObjClassInit(expr) - -/* vi:set ai: - */ diff --git a/runtime/expr.h b/runtime/expr.h deleted file mode 100644 index 1afe1a1f..00000000 --- a/runtime/expr.h +++ /dev/null @@ -1,57 +0,0 @@ -/* The expr object. - * - * Copyright 2008 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 <http://www.gnu.org/licenses/>. - * - * 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. - */ -#ifndef INCLUDED_EXPR_H -#define INCLUDED_EXPR_H - -#include "obj.h" -#include "ctok.h" -#include "vmprg.h" -#include "stringbuf.h" - -/* a node inside an expression tree */ -typedef struct exprNode_s { - char dummy; -} exprNode_t; - - -/* the expression object */ -typedef struct expr_s { - BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ - vmprg_t *pVmprg; /* the expression in vmprg format - ready to execute */ -} expr_t; - - -/* interfaces */ -BEGINinterface(expr) /* name must also be changed in ENDinterface macro! */ - INTERFACEObjDebugPrint(expr); - rsRetVal (*Construct)(expr_t **ppThis); - rsRetVal (*ConstructFinalize)(expr_t __attribute__((unused)) *pThis); - rsRetVal (*Destruct)(expr_t **ppThis); - rsRetVal (*Parse)(expr_t *pThis, ctok_t *ctok); -ENDinterface(expr) -#define exprCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */ - -/* prototypes */ -PROTOTYPEObj(expr); - -#endif /* #ifndef INCLUDED_EXPR_H */ diff --git a/runtime/msg.c b/runtime/msg.c index c5cbb5c8..b440d6ca 100644 --- a/runtime/msg.c +++ b/runtime/msg.c @@ -37,6 +37,7 @@ #include <ctype.h> #include <sys/socket.h> #include <netdb.h> +#include <libestr.h> #include <libee/libee.h> #if HAVE_MALLOC_H # include <malloc.h> @@ -46,7 +47,6 @@ #include "stringbuf.h" #include "template.h" #include "msg.h" -#include "var.h" #include "datetime.h" #include "glbl.h" #include "regexp.h" @@ -480,16 +480,13 @@ getRcvFromIP(msg_t *pM) } - -/* map a property name (string) to a property ID */ -rsRetVal propNameToID(cstr_t *pCSPropName, propid_t *pPropID) +/* map a property name (C string) to a property ID */ +rsRetVal +propNameStrToID(uchar *pName, propid_t *pPropID) { - uchar *pName; DEFiRet; - assert(pCSPropName != NULL); - assert(pPropID != NULL); - pName = rsCStrGetSzStrNoNULL(pCSPropName); + assert(pName != NULL); /* sometimes there are aliases to the original MonitoWare * property names. These come after || in the ifs below. */ @@ -577,6 +574,21 @@ rsRetVal propNameToID(cstr_t *pCSPropName, propid_t *pPropID) } +/* map a property name (string) to a property ID */ +rsRetVal +propNameToID(cstr_t *pCSPropName, propid_t *pPropID) +{ + uchar *pName; + DEFiRet; + + assert(pCSPropName != NULL); + assert(pPropID != NULL); + pName = rsCStrGetSzStrNoNULL(pCSPropName); + iRet = propNameStrToID(pName, pPropID); + RETiRet; +} + + /* map a property ID to a name string (useful for displaying) */ uchar *propIDToName(propid_t propID) { @@ -3095,98 +3107,68 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe, } -/* 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. +/* The function returns a cee variable suitable for use with RainerScript. + * Note: caller must free the returned string. * 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) +es_str_t* +msgGetCEEVarNew(msg_t *pMsg, char *name) { - DEFiRet; - var_t *pVar; - cstr_t *pstrProp; - es_str_t *str = NULL; + es_str_t *estr = NULL; es_str_t *epropName = NULL; - int r; + struct ee_field *field; ISOBJ_TYPE_assert(pMsg, msg); - ASSERT(propName != NULL); - ASSERT(ppVar != NULL); - /* make sure we have a var_t instance */ - CHKiRet(var.Construct(&pVar)); - CHKiRet(var.ConstructFinalize(pVar)); - - epropName = es_newStrFromBuf((char*)propName->pBuf, propName->iStrLen); - r = ee_getEventFieldAsString(pMsg->event, epropName, &str); - - if(r != EE_OK) { - DBGPRINTF("msgGtCEEVar: libee error %d during ee_getEventFieldAsString\n", r); - CHKiRet(cstrConstruct(&pstrProp)); - CHKiRet(cstrFinalize(pstrProp)); - } else { - CHKiRet(cstrConstructFromESStr(&pstrProp, str)); + if(pMsg->event == NULL) { + estr = es_newStr(1); + goto done; } - /* now create a string object out of it and hand that over to the var */ - CHKiRet(var.SetString(pVar, pstrProp)); - es_deleteStr(str); - - /* finally store var */ - *ppVar = pVar; + epropName = es_newStrFromCStr(name, strlen(name)); // TODO: optimize (in grammar!) + 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); -finalize_it: - if(epropName != NULL) - es_deleteStr(epropName); - RETiRet; +done: + return estr; } -/* The returns a message 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. - * rgerhards, 2008-02-25 +/* Return an es_str_t for given message property. */ -rsRetVal -msgGetMsgVar(msg_t *pThis, cstr_t *pstrPropName, var_t **ppVar) +es_str_t* +msgGetMsgVarNew(msg_t *pThis, uchar *name) { - DEFiRet; - var_t *pVar; size_t propLen; uchar *pszProp = NULL; - cstr_t *pstrProp; propid_t propid; unsigned short bMustBeFreed = 0; + es_str_t *estr; ISOBJ_TYPE_assert(pThis, msg); - ASSERT(pstrPropName != NULL); - ASSERT(ppVar != NULL); - - /* make sure we have a var_t instance */ - CHKiRet(var.Construct(&pVar)); - CHKiRet(var.ConstructFinalize(pVar)); /* always call MsgGetProp() without a template specifier */ /* TODO: optimize propNameToID() call -- rgerhards, 2009-06-26 */ - propNameToID(pstrPropName, &propid); + propNameStrToID(name, &propid); pszProp = (uchar*) MsgGetProp(pThis, NULL, propid, NULL, &propLen, &bMustBeFreed); - /* now create a string object out of it and hand that over to the var */ - CHKiRet(rsCStrConstructFromszStr(&pstrProp, pszProp)); - CHKiRet(var.SetString(pVar, pstrProp)); - - /* finally store var */ - *ppVar = pVar; - -finalize_it: +dbgprintf("ZZZZ: var %s returns '%s'\n", name, pszProp); + estr = es_newStrFromCStr((char*)pszProp, propLen); if(bMustBeFreed) free(pszProp); - RETiRet; + return estr; } diff --git a/runtime/msg.h b/runtime/msg.h index 01a1e059..55d2dfc0 100644 --- a/runtime/msg.h +++ b/runtime/msg.h @@ -170,6 +170,7 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe, size_t *pPropLen, unsigned short *pbMustBeFreed); char *textpri(char *pRes, size_t pResLen, int pri); rsRetVal msgGetMsgVar(msg_t *pThis, cstr_t *pstrPropName, var_t **ppVar); +es_str_t* msgGetMsgVarNew(msg_t *pThis, uchar *name); rsRetVal MsgEnableThreadSafety(void); uchar *getRcvFrom(msg_t *pM); void getTAG(msg_t *pM, uchar **ppBuf, int *piLen); @@ -177,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 cb76e6da..5df4c2c8 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -31,6 +31,7 @@ #include <errno.h> #include <unistd.h> #include <grp.h> +#include <stdarg.h> #include <sys/resource.h> #include <sys/types.h> #include <sys/stat.h> @@ -38,6 +39,7 @@ #include "rsyslog.h" #include "obj.h" #include "srUtils.h" +#include "rule.h" #include "ruleset.h" #include "modules.h" #include "conf.h" @@ -63,16 +65,20 @@ #include "parser.h" #include "outchannel.h" #include "threads.h" +#include "datetime.h" +#include "parserif.h" #include "dirty.h" /* static data */ DEFobjStaticHelpers +DEFobjCurrIf(rule) DEFobjCurrIf(ruleset) DEFobjCurrIf(module) DEFobjCurrIf(conf) DEFobjCurrIf(errmsg) DEFobjCurrIf(glbl) DEFobjCurrIf(parser) +DEFobjCurrIf(datetime) /* exported static data */ rsconf_t *runConf = NULL;/* the currently running config */ @@ -92,6 +98,7 @@ static uchar template_StdPgSQLFmt[] = "\"insert into SystemEvents (Message, Faci static uchar template_spoofadr[] = "\"%fromhost-ip%\""; /* end templates */ +void cnfDoCfsysline(char *ln); /* Standard-Constructor */ @@ -212,6 +219,241 @@ CODESTARTobjDebugPrint(rsconf) ENDobjDebugPrint(rsconf) +rsRetVal +cnfDoActlst(struct cnfactlst *actlst, rule_t *pRule) +{ + struct cnfcfsyslinelst *cflst; + action_t *pAction; + uchar *str; + DEFiRet; + + while(actlst != NULL) { + dbgprintf("aclst %p: ", actlst); + if(actlst->actType == CNFACT_V2) { + dbgprintf("V2 action type not yet handled\n"); + } else { + dbgprintf("legacy action line:%s\n", actlst->data.legActLine); + str = (uchar*) actlst->data.legActLine; + iRet = cflineDoAction(loadConf, &str, &pAction); + iRet = llAppend(&(pRule)->llActList, NULL, (void*) pAction); + } + for( cflst = actlst->syslines + ; cflst != NULL ; cflst = cflst->next) { + cnfDoCfsysline(cflst->line); + } + actlst = actlst->next; + } + 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; + +void +parser_errmsg(char *fmt, ...) +{ + va_list ap; + char errBuf[1024]; + + va_start(ap, fmt); + if(vsnprintf(errBuf, sizeof(errBuf), fmt, ap) == sizeof(errBuf)) + errBuf[1024] = '\0'; + errmsg.LogError(0, RS_RET_CONF_PARSE_ERROR, + "error during parsing file %s, on or before line %d: %s", + cnfcurrfn, yylineno, errBuf); + va_end(ap); +} + +int +yyerror(char *s) +{ + parser_errmsg("%s", s); + return 0; +} +void cnfDoObj(struct cnfobj *o) +{ + dbgprintf("cnf:global:obj: "); + cnfobjPrint(o); + cnfobjDestruct(o); +} + +void cnfDoRule(struct cnfrule *cnfrule) +{ + rule_t *pRule; + uchar *str; + rsRetVal iRet = RS_RET_OK; //DEFiRet; + + dbgprintf("cnf:global:rule\n"); + cnfrulePrint(cnfrule); + + CHKiRet(rule.Construct(&pRule)); /* create "fresh" selector */ + CHKiRet(rule.SetAssRuleset(pRule, ruleset.GetCurrent(loadConf))); + CHKiRet(rule.ConstructFinalize(pRule)); + + switch(cnfrule->filttype) { + case CNFFILT_NONE: + break; + case CNFFILT_PRI: + str = (uchar*) cnfrule->filt.s; + iRet = cflineProcessTradPRIFilter(&str, pRule); + break; + case CNFFILT_PROP: + dbgprintf("%s\n", cnfrule->filt.s); + str = (uchar*) cnfrule->filt.s; + iRet = cflineProcessPropFilter(&str, pRule); + break; + case CNFFILT_SCRIPT: + pRule->f_filter_type = FILTER_EXPR; + pRule->f_filterData.expr = cnfrule->filt.expr; + break; + } + /* we now check if there are some global (BSD-style) filter conditions + * and, if so, we copy them over. rgerhards, 2005-10-18 + */ + if(pDfltProgNameCmp != NULL) { + CHKiRet(rsCStrConstructFromCStr(&(pRule->pCSProgNameComp), pDfltProgNameCmp)); + } + + if(eDfltHostnameCmpMode != HN_NO_COMP) { + pRule->eHostnameCmpMode = eDfltHostnameCmpMode; + CHKiRet(rsCStrConstructFromCStr(&(pRule->pCSHostnameComp), pDfltHostnameCmp)); + } + + cnfDoActlst(cnfrule->actlst, pRule); + + CHKiRet(ruleset.AddRule(loadConf, rule.GetAssRuleset(pRule), &pRule)); + +finalize_it: + //TODO: do something with error states + ; +} + +void cnfDoCfsysline(char *ln) +{ + dbgprintf("cnf:global:cfsysline: %s\n", ln); + /* the legacy system needs the "$" stripped */ + conf.cfsysline((uchar*) ln+1); + dbgprintf("cnf:cfsysline call done\n"); +} + +void cnfDoBSDTag(char *ln) +{ + dbgprintf("cnf:global:BSD tag: %s\n", ln); + cflineProcessTagSelector((uchar**)&ln); +} + +void cnfDoBSDHost(char *ln) +{ + dbgprintf("cnf:global:BSD host: %s\n", ln); + cflineProcessHostSelector((uchar**)&ln); +} + +es_str_t* +cnfGetVar(char *name, void *usrptr) +{ + es_str_t *estr; + if(name[0] == '$') { + 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; +} +/*------------------------------ end interface to flex/bison parser ------------------------------*/ + + + /* drop to specified group * if something goes wrong, the function never returns * Note that such an abort can cause damage to on-disk structures, so we should @@ -549,19 +791,6 @@ static rsRetVal setActionResumeInterval(void __attribute__((unused)) *pVal, int } -/* this method is needed to shuffle the current conf object down to the - * IncludeConfig handler. - */ -static rsRetVal -doIncludeLine(void *pVal, uchar *pNewVal) -{ - DEFiRet; - iRet = conf.doIncludeLine(ourConf, pVal, pNewVal); - free(pNewVal); - RETiRet; -} - - /* set the maximum message size */ static rsRetVal setMaxMsgSize(void __attribute__((unused)) *pVal, long iNewVal) { @@ -840,8 +1069,6 @@ initLegacyConf(void) setActionResumeInterval, NULL, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"modload", 0, eCmdHdlrCustomHandler, conf.doModLoad, NULL, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"includeconfig", 0, eCmdHdlrCustomHandler, - doIncludeLine, NULL, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"maxmessagesize", 0, eCmdHdlrSize, setMaxMsgSize, NULL, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"defaultruleset", 0, eCmdHdlrGetWord, @@ -990,10 +1217,8 @@ validateConf(void) rsRetVal load(rsconf_t **cnf, uchar *confFile) { - rsRetVal localRet; int iNbrActions; - int bHadConfigErr = 0; - char cbuf[BUFSIZ]; + int r; DEFiRet; CHKiRet(rsconfConstruct(&loadConf)); @@ -1003,54 +1228,26 @@ ourConf = loadConf; // TODO: remove, once ourConf is gone! CHKiRet(initLegacyConf()); /* open the configuration file */ - localRet = conf.processConfFile(loadConf, confFile); - CHKiRet(conf.GetNbrActActions(loadConf, &iNbrActions)); - - if(localRet != RS_RET_OK && localRet != RS_RET_NONFATAL_CONFIG_ERR) { - errmsg.LogError(0, localRet, "CONFIG ERROR: could not interpret master config file '%s'.", confFile); - bHadConfigErr = 1; - } else if(iNbrActions == 0) { - errmsg.LogError(0, RS_RET_NO_ACTIONS, "CONFIG ERROR: there are no active actions configured. Inputs will " - "run, but no output whatsoever is created."); - bHadConfigErr = 1; + r = cnfSetLexFile((char*)confFile); + if(r == 0) { + r = yyparse(); + conf.GetNbrActActions(loadConf, &iNbrActions); } - if((localRet != RS_RET_OK && localRet != RS_RET_NONFATAL_CONFIG_ERR) || iNbrActions == 0) { - - /* rgerhards: this code is executed to set defaults when the - * config file could not be opened. We might think about - * abandoning the run in this case - but this, too, is not - * very clever... So we stick with what we have. - * We ignore any errors while doing this - we would be lost anyhow... - */ - errmsg.LogError(0, NO_ERRCODE, "EMERGENCY CONFIGURATION ACTIVATED - fix rsyslog config file!"); - - /* note: we previously used _POSIY_TTY_NAME_MAX+1, but this turned out to be - * too low on linux... :-S -- rgerhards, 2008-07-28 - */ - char szTTYNameBuf[128]; - rule_t *pRule = NULL; /* initialization to NULL is *vitally* important! */ - conf.cfline(loadConf, UCHAR_CONSTANT("*.ERR\t" _PATH_CONSOLE), &pRule); - conf.cfline(loadConf, UCHAR_CONSTANT("syslog.*\t" _PATH_CONSOLE), &pRule); - conf.cfline(loadConf, UCHAR_CONSTANT("*.PANIC\t*"), &pRule); - conf.cfline(loadConf, UCHAR_CONSTANT("syslog.*\troot"), &pRule); - if(ttyname_r(0, szTTYNameBuf, sizeof(szTTYNameBuf)) == 0) { - snprintf(cbuf,sizeof(cbuf), "*.*\t%s", szTTYNameBuf); - conf.cfline(loadConf, (uchar*)cbuf, &pRule); - } else { - DBGPRINTF("error %d obtaining controlling terminal, not using that emergency rule\n", errno); - } - ruleset.AddRule(loadConf, ruleset.GetCurrent(loadConf), &pRule); + if(r == 1) { + errmsg.LogError(0, RS_RET_CONF_PARSE_ERROR, + "CONFIG ERROR: could not interpret master " + "config file '%s'.", confFile); + ABORT_FINALIZE(RS_RET_CONF_PARSE_ERROR); + } else if(iNbrActions == 0) { + errmsg.LogError(0, RS_RET_NO_ACTIONS, "CONFIG ERROR: there are no " + "active actions configured. Inputs will " + "run, but no output whatsoever is created."); + ABORT_FINALIZE(RS_RET_NO_ACTIONS); } CHKiRet(validateConf()); - - /* return warning state if we had some acceptable problems */ - if(bHadConfigErr) { - iRet = RS_RET_NONFATAL_CONFIG_ERR; - } - /* we are done checking the config - now validate if we should actually run or not. * If not, terminate. -- rgerhards, 2008-07-25 * TODO: iConfigVerify -- should it be pulled from the config, or leave as is (option)? @@ -1065,7 +1262,7 @@ ourConf = loadConf; // TODO: remove, once ourConf is gone! *cnf = loadConf; // TODO: enable this once all config code is moved to here! loadConf = NULL; - dbgprintf("rsyslog finished loading initial config %p\n", loadConf); + dbgprintf("rsyslog finished loading master config %p\n", loadConf); rsconfDebugPrint(loadConf); finalize_it: @@ -1102,10 +1299,12 @@ ENDobjQueryInterface(rsconf) BEGINObjClassInit(rsconf, 1, OBJ_IS_CORE_MODULE) /* class, version */ /* request objects we use */ CHKiRet(objUse(ruleset, CORE_COMPONENT)); + CHKiRet(objUse(rule, CORE_COMPONENT)); CHKiRet(objUse(module, CORE_COMPONENT)); 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 */ @@ -1117,11 +1316,13 @@ ENDObjClassInit(rsconf) /* De-initialize the rsconf class. */ BEGINObjClassExit(rsconf, OBJ_IS_CORE_MODULE) /* class, version */ + objRelease(rule, CORE_COMPONENT); objRelease(ruleset, CORE_COMPONENT); objRelease(module, CORE_COMPONENT); objRelease(conf, CORE_COMPONENT); objRelease(errmsg, CORE_COMPONENT); objRelease(glbl, CORE_COMPONENT); + objRelease(datetime, CORE_COMPONENT); objRelease(parser, CORE_COMPONENT); ENDObjClassExit(rsconf) diff --git a/runtime/rsyslog.c b/runtime/rsyslog.c index 2b8f2b64..cbab06b7 100644 --- a/runtime/rsyslog.c +++ b/runtime/rsyslog.c @@ -62,16 +62,9 @@ #include "rsyslog.h" #include "obj.h" -#include "vm.h" -#include "sysvar.h" #include "stringbuf.h" #include "wti.h" #include "wtp.h" -#include "expr.h" -#include "ctok.h" -#include "vmop.h" -#include "vmstk.h" -#include "vmprg.h" #include "datetime.h" #include "queue.h" #include "conf.h" @@ -178,22 +171,6 @@ rsrtInit(char **ppErrObj, obj_if_t *pObjIF) CHKiRet(glblClassInit(NULL)); if(ppErrObj != NULL) *ppErrObj = "msg"; CHKiRet(msgClassInit(NULL)); - if(ppErrObj != NULL) *ppErrObj = "ctok_token"; - CHKiRet(ctok_tokenClassInit(NULL)); - if(ppErrObj != NULL) *ppErrObj = "ctok"; - CHKiRet(ctokClassInit(NULL)); - if(ppErrObj != NULL) *ppErrObj = "vmstk"; - CHKiRet(vmstkClassInit(NULL)); - if(ppErrObj != NULL) *ppErrObj = "sysvar"; - CHKiRet(sysvarClassInit(NULL)); - if(ppErrObj != NULL) *ppErrObj = "vm"; - CHKiRet(vmClassInit(NULL)); - if(ppErrObj != NULL) *ppErrObj = "vmop"; - CHKiRet(vmopClassInit(NULL)); - if(ppErrObj != NULL) *ppErrObj = "vmprg"; - CHKiRet(vmprgClassInit(NULL)); - if(ppErrObj != NULL) *ppErrObj = "expr"; - CHKiRet(exprClassInit(NULL)); if(ppErrObj != NULL) *ppErrObj = "rule"; CHKiRet(ruleClassInit(NULL)); if(ppErrObj != NULL) *ppErrObj = "ruleset"; diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index 0b0dc921..39f00ebc 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -360,6 +360,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_CMD_GONE_AWAY = -2204,/**< config directive existed, but no longer supported */ RS_RET_ERR_SCHED_PARAMS = -2205,/**< there is a problem with configured thread scheduling params */ RS_RET_SOCKNAME_MISSING = -2206,/**< no socket name configured where one is required */ + RS_RET_CONF_PARSE_ERROR = -2207,/**< (fatal) error parsing config file */ /* RainerScript error messages (range 1000.. 1999) */ RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */ diff --git a/runtime/rule.c b/runtime/rule.c index 3dcee877..cbd2660d 100644 --- a/runtime/rule.c +++ b/runtime/rule.c @@ -36,18 +36,15 @@ #include "action.h" #include "rule.h" #include "errmsg.h" -#include "vm.h" -#include "var.h" #include "srUtils.h" #include "batch.h" +#include "parserif.h" #include "unicode-helper.h" /* static data */ DEFobjStaticHelpers DEFobjCurrIf(errmsg) -DEFobjCurrIf(expr) DEFobjCurrIf(var) -DEFobjCurrIf(vm) /* support for simple textual representation of FIOP names @@ -123,8 +120,6 @@ shouldProcessThisMessage(rule_t *pRule, msg_t *pMsg, sbool *bProcessMsg) uchar *pszPropVal; int bRet = 0; size_t propLen; - vm_t *pVM = NULL; - var_t *pResult = NULL; ISOBJ_TYPE_assert(pRule, rule); assert(pMsg != NULL); @@ -186,14 +181,8 @@ shouldProcessThisMessage(rule_t *pRule, msg_t *pMsg, sbool *bProcessMsg) else bRet = 1; } else if(pRule->f_filter_type == FILTER_EXPR) { - CHKiRet(vm.Construct(&pVM)); - CHKiRet(vm.ConstructFinalize(pVM)); - CHKiRet(vm.SetMsg(pVM, pMsg)); - CHKiRet(vm.ExecProg(pVM, pRule->f_filterData.f_expr->pVmprg)); - CHKiRet(vm.PopBoolFromStack(pVM, &pResult)); - dbgprintf("result of rainerscript filter evaluation: %lld\n", pResult->val.num); - /* VM is destructed on function exit */ - bRet = (pResult->val.num) ? 1 : 0; + bRet = cnfexprEvalBool(pRule->f_filterData.expr, pMsg); + dbgprintf("result of rainerscript filter evaluation: %d\n", bRet); } else { assert(pRule->f_filter_type == FILTER_PROP); /* assert() just in case... */ pszPropVal = MsgGetProp(pMsg, NULL, pRule->f_filterData.prop.propID, @@ -271,13 +260,6 @@ shouldProcessThisMessage(rule_t *pRule, msg_t *pMsg, sbool *bProcessMsg) } finalize_it: - /* destruct in any case, not just on error, but it makes error handling much easier */ - if(pVM != NULL) - vm.Destruct(&pVM); - - if(pResult != NULL) - var.Destruct(&pResult); - *bProcessMsg = bRet; RETiRet; } @@ -356,9 +338,6 @@ CODESTARTobjDestruct(rule) rsCStrRegexDestruct(&pThis->f_filterData.prop.regex_cache); if(pThis->f_filterData.prop.propName != NULL) es_deleteStr(pThis->f_filterData.prop.propName); - } else if(pThis->f_filter_type == FILTER_EXPR) { - if(pThis->f_filterData.f_expr != NULL) - expr.Destruct(&pThis->f_filterData.f_expr); } llDestroy(&pThis->llActList); @@ -476,9 +455,7 @@ ENDobjQueryInterface(rule) */ BEGINObjClassExit(rule, OBJ_IS_CORE_MODULE) /* class, version */ objRelease(errmsg, CORE_COMPONENT); - objRelease(expr, CORE_COMPONENT); objRelease(var, CORE_COMPONENT); - objRelease(vm, CORE_COMPONENT); ENDObjClassExit(rule) @@ -489,9 +466,7 @@ ENDObjClassExit(rule) BEGINObjClassInit(rule, 1, OBJ_IS_CORE_MODULE) /* class, version */ /* request objects we use */ CHKiRet(objUse(errmsg, CORE_COMPONENT)); - CHKiRet(objUse(expr, CORE_COMPONENT)); CHKiRet(objUse(var, CORE_COMPONENT)); - CHKiRet(objUse(vm, CORE_COMPONENT)); /* set our own handlers */ OBJSetMethodHandler(objMethod_DEBUGPRINT, ruleDebugPrint); diff --git a/runtime/rule.h b/runtime/rule.h index 3b34e11a..76ed5f0b 100644 --- a/runtime/rule.h +++ b/runtime/rule.h @@ -2,7 +2,7 @@ * * This implements rules within rsyslog. * - * Copyright 2009 Rainer Gerhards and Adiscon GmbH. + * Copyright 2009-2011 Rainer Gerhards and Adiscon GmbH. * * This file is part of the rsyslog runtime library. * @@ -28,7 +28,7 @@ #include "libestr.h" #include "linkedlist.h" #include "regexp.h" -#include "expr.h" +#include "rainerscript.h" /* the rule object */ struct rule_s { @@ -52,7 +52,7 @@ struct rule_s { propid_t propID; /* ID of the requested property */ es_str_t *propName; /* name of property for CEE-based filters */ } prop; - expr_t *f_expr; /* expression object */ + struct cnfexpr *expr; /* expression object */ } f_filterData; ruleset_t *pRuleset; /* associated ruleset */ diff --git a/runtime/statsobj.c b/runtime/statsobj.c index e1a89cf4..d1213a34 100644 --- a/runtime/statsobj.c +++ b/runtime/statsobj.c @@ -36,7 +36,6 @@ #include "unicode-helper.h" #include "obj.h" #include "statsobj.h" -#include "sysvar.h" #include "srUtils.h" #include "stringbuf.h" diff --git a/runtime/sysvar.c b/runtime/sysvar.c deleted file mode 100644 index ecc31e2d..00000000 --- a/runtime/sysvar.c +++ /dev/null @@ -1,204 +0,0 @@ -/* sysvar.c - imlements rsyslog system variables - * - * At least for now, this class only has static functions and no - * instances. - * - * Module begun 2008-02-25 by Rainer Gerhards - * - * Copyright (C) 2008 by 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 <http://www.gnu.org/licenses/>. - * - * 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 <stdio.h> -#include <stdlib.h> -#include <assert.h> - -#include "rsyslog.h" -#include "obj.h" -#include "stringbuf.h" -#include "sysvar.h" -#include "datetime.h" - -/* static data */ -DEFobjStaticHelpers -DEFobjCurrIf(var) -DEFobjCurrIf(datetime) -DEFobjCurrIf(glbl) - - -/* Standard-Constructor - */ -BEGINobjConstruct(sysvar) /* be sure to specify the object type also in END macro! */ -ENDobjConstruct(sysvar) - - -/* ConstructionFinalizer - * rgerhards, 2008-01-09 - */ -static rsRetVal -sysvarConstructFinalize(sysvar_t __attribute__((unused)) *pThis) -{ - DEFiRet; - RETiRet; -} - - -/* destructor for the sysvar object */ -BEGINobjDestruct(sysvar) /* be sure to specify the object type also in END and CODESTART macros! */ -CODESTARTobjDestruct(sysvar) -ENDobjDestruct(sysvar) - - -/* 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. - * Added 2007-07-10 rgerhards - * 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, cstr_t **ppStr) -{ - DEFiRet; - uchar szBuf[16]; - struct syslogTime t; - - datetime.getCurrTime(&t, NULL); - switch(eNow) { - case NOW_NOW: - snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%4.4d-%2.2d-%2.2d", t.year, t.month, t.day); - break; - case NOW_YEAR: - snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%4.4d", t.year); - break; - case NOW_MONTH: - snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%2.2d", t.month); - break; - case NOW_DAY: - snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%2.2d", t.day); - break; - case NOW_HOUR: - snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%2.2d", t.hour); - break; - case NOW_MINUTE: - 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 */ - CHKiRet(rsCStrConstructFromszStr(ppStr, szBuf)); - -finalize_it: - RETiRet; -} - - -/* The function returns a system 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. - * rgerhards, 2008-02-25 - */ -static rsRetVal -GetVar(cstr_t *pstrVarName, var_t **ppVar) -{ - DEFiRet; - var_t *pVar; - cstr_t *pstrProp; - - ASSERT(pstrVarName != NULL); - ASSERT(ppVar != NULL); - - /* make sure we have a var_t instance */ - CHKiRet(var.Construct(&pVar)); - CHKiRet(var.ConstructFinalize(pVar)); - - /* now begin the actual variable evaluation */ - if(!rsCStrSzStrCmp(pstrVarName, (uchar*)"now", sizeof("now") - 1)) { - CHKiRet(getNOW(NOW_NOW, &pstrProp)); - } else if(!rsCStrSzStrCmp(pstrVarName, (uchar*)"year", sizeof("year") - 1)) { - CHKiRet(getNOW(NOW_YEAR, &pstrProp)); - } else if(!rsCStrSzStrCmp(pstrVarName, (uchar*)"month", sizeof("month") - 1)) { - CHKiRet(getNOW(NOW_MONTH, &pstrProp)); - } else if(!rsCStrSzStrCmp(pstrVarName, (uchar*)"day", sizeof("day") - 1)) { - CHKiRet(getNOW(NOW_DAY, &pstrProp)); - } else if(!rsCStrSzStrCmp(pstrVarName, (uchar*)"hour", sizeof("hour") - 1)) { - CHKiRet(getNOW(NOW_HOUR, &pstrProp)); - } else if(!rsCStrSzStrCmp(pstrVarName, (uchar*)"minute", sizeof("minute") - 1)) { - CHKiRet(getNOW(NOW_MINUTE, &pstrProp)); - } else if(!rsCStrSzStrCmp(pstrVarName, (uchar*)"myhostname", sizeof("myhostname") - 1)) { - CHKiRet(rsCStrConstructFromszStr(&pstrProp, glbl.GetLocalHostName())); - } else { - ABORT_FINALIZE(RS_RET_SYSVAR_NOT_FOUND); - } - - /* now hand the string over to the var object */ - CHKiRet(var.SetString(pVar, pstrProp)); - - /* finally store var */ - *ppVar = pVar; - -finalize_it: - RETiRet; -} - - -/* queryInterface function - * rgerhards, 2008-02-21 - */ -BEGINobjQueryInterface(sysvar) -CODESTARTobjQueryInterface(sysvar) - if(pIf->ifVersion != sysvarCURR_IF_VERSION) { /* check for current version, increment on each change */ - ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED); - } - - /* ok, we have the right interface, so let's fill it - * Please note that we may also do some backwards-compatibility - * work here (if we can support an older interface version - that, - * of course, also affects the "if" above). - */ - pIf->Construct = sysvarConstruct; - pIf->ConstructFinalize = sysvarConstructFinalize; - pIf->Destruct = sysvarDestruct; - pIf->GetVar = GetVar; -finalize_it: -ENDobjQueryInterface(sysvar) - - -/* Initialize the sysvar class. Must be called as the very first method - * before anything else is called inside this class. - * rgerhards, 2008-02-19 - */ -BEGINObjClassInit(sysvar, 1, OBJ_IS_CORE_MODULE) /* class, version */ - /* request objects we use */ - CHKiRet(objUse(var, CORE_COMPONENT)); - CHKiRet(objUse(datetime, CORE_COMPONENT)); - CHKiRet(objUse(glbl, CORE_COMPONENT)); - - /* set our own handlers */ - OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, sysvarConstructFinalize); -ENDObjClassInit(sysvar) - -/* vi:set ai: - */ diff --git a/runtime/sysvar.h b/runtime/sysvar.h deleted file mode 100644 index 35051b64..00000000 --- a/runtime/sysvar.h +++ /dev/null @@ -1,47 +0,0 @@ -/* The sysvar object. So far, no instance can be defined (makes logically no - * sense). - * - * Copyright 2008 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 <http://www.gnu.org/licenses/>. - * - * 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. - */ -#ifndef INCLUDED_SYSVAR_H -#define INCLUDED_SYSVAR_H - -/* the sysvar object - not really used... */ -typedef struct sysvar_s { - BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ -} sysvar_t; - - -/* interfaces */ -BEGINinterface(sysvar) /* name must also be changed in ENDinterface macro! */ - INTERFACEObjDebugPrint(sysvar); - rsRetVal (*Construct)(sysvar_t **ppThis); - rsRetVal (*ConstructFinalize)(sysvar_t __attribute__((unused)) *pThis); - rsRetVal (*Destruct)(sysvar_t **ppThis); - rsRetVal (*GetVar)(cstr_t *pstrPropName, var_t **ppVar); -ENDinterface(sysvar) -#define sysvarCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */ - - -/* prototypes */ -PROTOTYPEObj(sysvar); - -#endif /* #ifndef INCLUDED_SYSVAR_H */ diff --git a/runtime/vm.c b/runtime/vm.c deleted file mode 100644 index bbc8d346..00000000 --- a/runtime/vm.c +++ /dev/null @@ -1,869 +0,0 @@ -/* vm.c - the arithmetic stack of a virtual machine. - * - * Module begun 2008-02-22 by Rainer Gerhards - * - * Copyright 2008 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 <http://www.gnu.org/licenses/>. - * - * 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 <stdlib.h> -#include <string.h> -#include <assert.h> -#include <ctype.h> - -#include "rsyslog.h" -#include "obj.h" -#include "vm.h" -#include "sysvar.h" -#include "stringbuf.h" -#include "unicode-helper.h" - -/* static data */ -DEFobjStaticHelpers -DEFobjCurrIf(vmstk) -DEFobjCurrIf(var) -DEFobjCurrIf(sysvar) - -static pthread_mutex_t mutGetenv; /* we need to make this global because otherwise we can not guarantee proper init! */ - -/* ------------------------------ function registry code and structures ------------------------------ */ - -/* we maintain a registry of known functions */ -/* currently, this is a singly-linked list, this shall become a binary - * tree when we add the real call interface. So far, entries are added - * at the root, only. - */ -typedef struct s_rsf_entry { - cstr_t *pName; /* function name */ - prsf_t rsf; /* pointer to function code */ - struct s_rsf_entry *pNext; /* Pointer to next element or NULL */ -} rsf_entry_t; -rsf_entry_t *funcRegRoot = NULL; - - -/* add a function to the function registry. - * The handed-over cstr_t* object must no longer be used by the caller. - * A duplicate function name is an error. - * rgerhards, 2009-04-06 - */ -static rsRetVal -rsfrAddFunction(uchar *szName, prsf_t rsf) -{ - rsf_entry_t *pEntry; - size_t lenName; - DEFiRet; - - assert(szName != NULL); - assert(rsf != NULL); - - /* first check if we have a duplicate name, with the current approach this means - * we need to go through the whole list. - */ - lenName = strlen((char*)szName); - for(pEntry = funcRegRoot ; pEntry != NULL ; pEntry = pEntry->pNext) - if(!rsCStrSzStrCmp(pEntry->pName, szName, lenName)) - ABORT_FINALIZE(RS_RET_DUP_FUNC_NAME); - - /* unique name, so add to head of list */ - CHKmalloc(pEntry = calloc(1, sizeof(rsf_entry_t))); - CHKiRet(rsCStrConstructFromszStr(&pEntry->pName, szName)); - CHKiRet(cstrFinalize(pEntry->pName)); - pEntry->rsf = rsf; - pEntry->pNext = funcRegRoot; - funcRegRoot = pEntry; - -finalize_it: - if(iRet != RS_RET_OK && iRet != RS_RET_DUP_FUNC_NAME) - free(pEntry); - - RETiRet; -} - - -/* find a function inside the function registry - * The caller provides a cstr_t with the function name and receives - * a function pointer back. If no function is found, an RS_RET_UNKNW_FUNC - * error is returned. So if the function returns with RS_RET_OK, the caller - * can savely assume the function pointer is valid. - * rgerhards, 2009-04-06 - */ -static rsRetVal -findRSFunction(cstr_t *pcsName, prsf_t *prsf) -{ - rsf_entry_t *pEntry; - rsf_entry_t *pFound; - DEFiRet; - - assert(prsf != NULL); - - /* find function by list walkthrough. */ - pFound = NULL; - for(pEntry = funcRegRoot ; pEntry != NULL && pFound == NULL ; pEntry = pEntry->pNext) - if(!rsCStrCStrCmp(pEntry->pName, pcsName)) - pFound = pEntry; - - if(pFound == NULL) - ABORT_FINALIZE(RS_RET_UNKNW_FUNC); - - *prsf = pFound->rsf; - -finalize_it: - RETiRet; -} - - -/* find the name of a RainerScript function whom's function pointer - * is known. This function returns the cstr_t object, which MUST NOT - * be modified by the caller. - * rgerhards, 2009-04-06 - */ -static rsRetVal -findRSFunctionName(prsf_t rsf, cstr_t **ppcsName) -{ - rsf_entry_t *pEntry; - rsf_entry_t *pFound; - DEFiRet; - - assert(rsf != NULL); - assert(ppcsName != NULL); - - /* find function by list walkthrough. */ - pFound = NULL; - for(pEntry = funcRegRoot ; pEntry != NULL && pFound == NULL ; pEntry = pEntry->pNext) - if(pEntry->rsf == rsf) - pFound = pEntry; - - if(pFound == NULL) - ABORT_FINALIZE(RS_RET_UNKNW_FUNC); - - *ppcsName = pFound->pName; - -finalize_it: - RETiRet; -} - - -/* free the whole function registry - */ -static void -rsfrRemoveAll(void) -{ - rsf_entry_t *pEntry; - rsf_entry_t *pEntryDel; - - BEGINfunc - pEntry = funcRegRoot; - while(pEntry != NULL) { - pEntryDel = pEntry; - pEntry = pEntry->pNext; - cstrDestruct(&pEntryDel->pName); - free(pEntryDel); - } - funcRegRoot = NULL; - ENDfunc -} - - -/* ------------------------------ end function registry code and structures ------------------------------ */ - - -/* ------------------------------ instruction set implementation ------------------------------ * - * The following functions implement the VM's instruction set. - */ -#define BEGINop(instruction) \ - static rsRetVal op##instruction(vm_t *pThis, __attribute__((unused)) vmop_t *pOp) \ - { \ - DEFiRet; - -#define CODESTARTop(instruction) \ - ISOBJ_TYPE_assert(pThis, vm); - -#define PUSHRESULTop(operand, res) \ - /* we have a result, so let's push it */ \ - var.SetNumber(operand, res); \ - vmstk.Push(pThis->pStk, operand); /* result */ - -#define ENDop(instruction) \ - RETiRet; \ - } - -/* code generator for boolean operations */ -#define BOOLOP(name, OPERATION) \ -BEGINop(name) /* remember to set the instruction also in the ENDop macro! */ \ - var_t *operand1; \ - var_t *operand2; \ -CODESTARTop(name) \ - vmstk.PopBool(pThis->pStk, &operand1); \ - vmstk.PopBool(pThis->pStk, &operand2); \ - if(operand1->val.num OPERATION operand2->val.num) { \ - CHKiRet(var.SetNumber(operand1, 1)); \ - } else { \ - CHKiRet(var.SetNumber(operand1, 0)); \ - } \ - vmstk.Push(pThis->pStk, operand1); /* result */ \ - var.Destruct(&operand2); /* no longer needed */ \ -finalize_it: \ -ENDop(name) -BOOLOP(OR, ||) -BOOLOP(AND, &&) -#undef BOOLOP - - -/* code generator for numerical operations */ -#define NUMOP(name, OPERATION) \ -BEGINop(name) /* remember to set the instruction also in the ENDop macro! */ \ - var_t *operand1; \ - var_t *operand2; \ -CODESTARTop(name) \ - vmstk.PopNumber(pThis->pStk, &operand1); \ - vmstk.PopNumber(pThis->pStk, &operand2); \ - operand1->val.num = operand1->val.num OPERATION operand2->val.num; \ - vmstk.Push(pThis->pStk, operand1); /* result */ \ - var.Destruct(&operand2); /* no longer needed */ \ -ENDop(name) -NUMOP(PLUS, +) -NUMOP(MINUS, -) -NUMOP(TIMES, *) -NUMOP(DIV, /) -NUMOP(MOD, %) -#undef BOOLOP - - -/* code generator for compare operations */ -#define BEGINCMPOP(name) \ -BEGINop(name) \ - var_t *operand1; \ - var_t *operand2; \ - number_t bRes; \ -CODESTARTop(name) \ - CHKiRet(vmstk.Pop2CommOp(pThis->pStk, &operand1, &operand2)); \ - /* data types are equal (so we look only at operand1), but we must \ - * check which type we have to deal with... \ - */ \ - switch(operand1->varType) { -#define ENDCMPOP(name) \ - default: \ - bRes = 0; /* we do not abort just so that we have a value. TODO: reconsider */ \ - break; \ - } \ - \ - /* we have a result, so let's push it */ \ - var.SetNumber(operand1, bRes); \ - vmstk.Push(pThis->pStk, operand1); /* result */ \ - var.Destruct(&operand2); /* no longer needed */ \ -finalize_it: \ -ENDop(name) - -BEGINCMPOP(CMP_EQ) /* remember to change the name also in the END macro! */ - case VARTYPE_NUMBER: - bRes = operand1->val.num == operand2->val.num; - break; - case VARTYPE_STR: - bRes = !rsCStrCStrCmp(operand1->val.pStr, operand2->val.pStr); - break; -ENDCMPOP(CMP_EQ) - -BEGINCMPOP(CMP_NEQ) /* remember to change the name also in the END macro! */ - case VARTYPE_NUMBER: - bRes = operand1->val.num != operand2->val.num; - break; - case VARTYPE_STR: - bRes = rsCStrCStrCmp(operand1->val.pStr, operand2->val.pStr); - break; -ENDCMPOP(CMP_NEQ) - -BEGINCMPOP(CMP_LT) /* remember to change the name also in the END macro! */ - case VARTYPE_NUMBER: - bRes = operand1->val.num < operand2->val.num; - break; - case VARTYPE_STR: - bRes = rsCStrCStrCmp(operand1->val.pStr, operand2->val.pStr) < 0; - break; -ENDCMPOP(CMP_LT) - -BEGINCMPOP(CMP_GT) /* remember to change the name also in the END macro! */ - case VARTYPE_NUMBER: - bRes = operand1->val.num > operand2->val.num; - break; - case VARTYPE_STR: - bRes = rsCStrCStrCmp(operand1->val.pStr, operand2->val.pStr) > 0; - break; -ENDCMPOP(CMP_GT) - -BEGINCMPOP(CMP_LTEQ) /* remember to change the name also in the END macro! */ - case VARTYPE_NUMBER: - bRes = operand1->val.num <= operand2->val.num; - break; - case VARTYPE_STR: - bRes = rsCStrCStrCmp(operand1->val.pStr, operand2->val.pStr) <= 0; - break; -ENDCMPOP(CMP_LTEQ) - -BEGINCMPOP(CMP_GTEQ) /* remember to change the name also in the END macro! */ - case VARTYPE_NUMBER: - bRes = operand1->val.num >= operand2->val.num; - break; - case VARTYPE_STR: - bRes = rsCStrCStrCmp(operand1->val.pStr, operand2->val.pStr) >= 0; - break; -ENDCMPOP(CMP_GTEQ) - -#undef BEGINCMPOP -#undef ENDCMPOP -/* end regular compare operations */ - -/* comare operations that work on strings, only */ -BEGINop(CMP_CONTAINS) /* remember to set the instruction also in the ENDop macro! */ - var_t *operand1; - var_t *operand2; - number_t bRes; -CODESTARTop(CMP_CONTAINS) - /* operand2 is on top of stack, so needs to be popped first */ - vmstk.PopString(pThis->pStk, &operand2); - vmstk.PopString(pThis->pStk, &operand1); - /* TODO: extend cstr class so that it supports location of cstr inside cstr */ - bRes = (rsCStrLocateInSzStr(operand2->val.pStr, rsCStrGetSzStr(operand1->val.pStr)) == -1) ? 0 : 1; - - /* we have a result, so let's push it */ - PUSHRESULTop(operand1, bRes); - var.Destruct(&operand2); /* no longer needed */ -ENDop(CMP_CONTAINS) - - -BEGINop(CMP_CONTAINSI) /* remember to set the instruction also in the ENDop macro! */ - var_t *operand1; - var_t *operand2; - number_t bRes; -CODESTARTop(CMP_CONTAINSI) - /* operand2 is on top of stack, so needs to be popped first */ - vmstk.PopString(pThis->pStk, &operand2); - vmstk.PopString(pThis->pStk, &operand1); -var.DebugPrint(operand1); \ -var.DebugPrint(operand2); \ - /* TODO: extend cstr class so that it supports location of cstr inside cstr */ - bRes = (rsCStrCaseInsensitiveLocateInSzStr(operand2->val.pStr, rsCStrGetSzStr(operand1->val.pStr)) == -1) ? 0 : 1; - - /* we have a result, so let's push it */ - PUSHRESULTop(operand1, bRes); - var.Destruct(&operand2); /* no longer needed */ -ENDop(CMP_CONTAINSI) - - -BEGINop(CMP_STARTSWITH) /* remember to set the instruction also in the ENDop macro! */ - var_t *operand1; - var_t *operand2; - number_t bRes; -CODESTARTop(CMP_STARTSWITH) - /* operand2 is on top of stack, so needs to be popped first */ - vmstk.PopString(pThis->pStk, &operand2); - vmstk.PopString(pThis->pStk, &operand1); - /* TODO: extend cstr class so that it supports location of cstr inside cstr */ - bRes = (rsCStrStartsWithSzStr(operand1->val.pStr, rsCStrGetSzStr(operand2->val.pStr), - rsCStrLen(operand2->val.pStr)) == 0) ? 1 : 0; - - /* we have a result, so let's push it */ - PUSHRESULTop(operand1, bRes); - var.Destruct(&operand2); /* no longer needed */ -ENDop(CMP_STARTSWITH) - - -BEGINop(CMP_STARTSWITHI) /* remember to set the instruction also in the ENDop macro! */ - var_t *operand1; - var_t *operand2; - number_t bRes; -CODESTARTop(CMP_STARTSWITHI) - /* operand2 is on top of stack, so needs to be popped first */ - vmstk.PopString(pThis->pStk, &operand2); - vmstk.PopString(pThis->pStk, &operand1); - /* TODO: extend cstr class so that it supports location of cstr inside cstr */ - bRes = (rsCStrCaseInsensitveStartsWithSzStr(operand1->val.pStr, rsCStrGetSzStr(operand2->val.pStr), - rsCStrLen(operand2->val.pStr)) == 0) ? 1 : 0; - - /* we have a result, so let's push it */ - PUSHRESULTop(operand1, bRes); - var.Destruct(&operand2); /* no longer needed */ -ENDop(CMP_STARTSWITHI) - -/* end comare operations that work on strings, only */ - -BEGINop(STRADD) /* remember to set the instruction also in the ENDop macro! */ - var_t *operand1; - var_t *operand2; -CODESTARTop(STRADD) - vmstk.PopString(pThis->pStk, &operand2); - vmstk.PopString(pThis->pStk, &operand1); - - CHKiRet(rsCStrAppendCStr(operand1->val.pStr, operand2->val.pStr)); - CHKiRet(cstrFinalize(operand1->val.pStr)); - - /* we have a result, so let's push it */ - vmstk.Push(pThis->pStk, operand1); - var.Destruct(&operand2); /* no longer needed */ -finalize_it: -ENDop(STRADD) - -BEGINop(NOT) /* remember to set the instruction also in the ENDop macro! */ - var_t *operand; -CODESTARTop(NOT) - vmstk.PopBool(pThis->pStk, &operand); - PUSHRESULTop(operand, !operand->val.num); -ENDop(NOT) - -BEGINop(UNARY_MINUS) /* remember to set the instruction also in the ENDop macro! */ - var_t *operand; -CODESTARTop(UNARY_MINUS) - vmstk.PopNumber(pThis->pStk, &operand); - PUSHRESULTop(operand, -operand->val.num); -ENDop(UNARY_MINUS) - - -BEGINop(PUSHCONSTANT) /* remember to set the instruction also in the ENDop macro! */ - var_t *pVarDup; /* we need to duplicate the var, as we need to hand it over */ -CODESTARTop(PUSHCONSTANT) - CHKiRet(var.Duplicate(pOp->operand.pVar, &pVarDup)); - vmstk.Push(pThis->pStk, pVarDup); -finalize_it: -ENDop(PUSHCONSTANT) - - -BEGINop(PUSHMSGVAR) /* remember to set the instruction also in the ENDop macro! */ - var_t *pVal; /* the value to push */ - cstr_t *pstrVal; -CODESTARTop(PUSHMSGVAR) -dbgprintf("XXX: pushMSGVAR, var '%s'\n", rsCStrGetSzStr(pOp->operand.pVar->val.pStr)); - if(pThis->pMsg == NULL) { - /* TODO: flag an error message! As a work-around, we permit - * execution to continue here with an empty string - */ - /* TODO: create a method in var to create a string var? */ - CHKiRet(var.Construct(&pVal)); - CHKiRet(var.ConstructFinalize(pVal)); - CHKiRet(rsCStrConstructFromszStr(&pstrVal, (uchar*)"")); - CHKiRet(var.SetString(pVal, pstrVal)); - } else { - /* we have a message, so pull value from there */ - CHKiRet(msgGetMsgVar(pThis->pMsg, pOp->operand.pVar->val.pStr, &pVal)); - } - - /* if we reach this point, we have a valid pVal and can push it */ - vmstk.Push(pThis->pStk, pVal); -finalize_it: -ENDop(PUSHMSGVAR) - - -BEGINop(PUSHCEEVAR) /* remember to set the instruction also in the ENDop macro! */ - var_t *pVal; /* the value to push */ - cstr_t *pstrVal; -CODESTARTop(PUSHCEEVAR) -dbgprintf("XXX: pushCEEVAR, var '%s'\n", rsCStrGetSzStr(pOp->operand.pVar->val.pStr)); - if(pThis->pMsg == NULL) { - /* TODO: flag an error message! As a work-around, we permit - * execution to continue here with an empty string - */ - CHKiRet(var.Construct(&pVal)); - CHKiRet(var.ConstructFinalize(pVal)); - CHKiRet(rsCStrConstructFromszStr(&pstrVal, (uchar*)"")); - CHKiRet(var.SetString(pVal, pstrVal)); - } else { - /* we have a message, so pull value from there */ - CHKiRet(msgGetCEEVar(pThis->pMsg, pOp->operand.pVar->val.pStr, &pVal)); - } - - /* if we reach this point, we have a valid pVal and can push it */ - vmstk.Push(pThis->pStk, pVal); -dbgprintf("XXX: pushCEEVAR, result '%s'\n", rsCStrGetSzStr(pVal->val.pStr)); -finalize_it: -ENDop(PUSHCEEVAR) - - -BEGINop(PUSHSYSVAR) /* remember to set the instruction also in the ENDop macro! */ - var_t *pVal; /* the value to push */ -CODESTARTop(PUSHSYSVAR) - CHKiRet(sysvar.GetVar(pOp->operand.pVar->val.pStr, &pVal)); - vmstk.Push(pThis->pStk, pVal); -finalize_it: - if(Debug && iRet != RS_RET_OK) { - if(iRet == RS_RET_SYSVAR_NOT_FOUND) { - DBGPRINTF("rainerscript: sysvar '%s' not found\n", - rsCStrGetSzStrNoNULL(pOp->operand.pVar->val.pStr)); - } else { - DBGPRINTF("rainerscript: error %d trying to obtain sysvar '%s'\n", - iRet, rsCStrGetSzStrNoNULL(pOp->operand.pVar->val.pStr)); - } - } -ENDop(PUSHSYSVAR) - -/* The function call operation is only very roughly implemented. While the plumbing - * to reach this instruction is fine, the instruction itself currently supports only - * functions with a single argument AND with a name that we know. - * TODO: later, we can add here the real logic, that involves looking up function - * names, loading them dynamically ... and all that... - * implementation begun 2009-03-10 by rgerhards - */ -BEGINop(FUNC_CALL) /* remember to set the instruction also in the ENDop macro! */ - var_t *numOperands; -CODESTARTop(FUNC_CALL) - vmstk.PopNumber(pThis->pStk, &numOperands); - CHKiRet((*pOp->operand.rsf)(pThis->pStk, numOperands->val.num)); - var.Destruct(&numOperands); /* no longer needed */ -finalize_it: -ENDop(FUNC_CALL) - - -/* ------------------------------ end instruction set implementation ------------------------------ */ - - -/* ------------------------------ begin built-in function implementation ------------------------------ */ -/* note: this shall probably be moved to a separate module, but for the time being we do it directly - * in here. This is on our way to get from a dirty to a clean solution via baby steps that are - * a bit less dirty each time... - * - * The advantage of doing it here is that we do not yet need to think about how to handle the - * exit case, where we must not unload function modules which functions are still referenced. - * - * CALLING INTERFACE: - * The function must pop its parameters off the stack and pop its result onto - * the stack when it is finished. The number of parameters the function was - * called with is provided to it. If the argument count is less then what the function - * expected, it may handle the situation with defaults (or return an error). If the - * argument count is greater than expected, returnung an error is highly - * recommended (use RS_RET_INVLD_NBR_ARGUMENTS for these cases). - * - * All function names are prefixed with "rsf_" (RainerScript Function) to have - * a separate "name space". - * - * rgerhards, 2009-04-06 - */ - - -/* The strlen function, also probably a prototype of how all functions should be - * implemented. - * rgerhards, 2009-04-06 - */ -static rsRetVal -rsf_strlen(vmstk_t *pStk, int numOperands) -{ - DEFiRet; - var_t *operand1; - int iStrlen; - - if(numOperands != 1) - ABORT_FINALIZE(RS_RET_INVLD_NBR_ARGUMENTS); - - /* pop args and do operaton (trivial case here...) */ - vmstk.PopString(pStk, &operand1); - iStrlen = strlen((char*) rsCStrGetSzStr(operand1->val.pStr)); - - /* Store result and cleanup */ - var.SetNumber(operand1, iStrlen); - vmstk.Push(pStk, operand1); -finalize_it: - RETiRet; -} - - -/* The getenv function. Note that we guard the OS call by a mutex, as that - * function is not guaranteed to be thread-safe. This implementation here is far from - * being optimal, at least we should cache the result. This is left TODO for - * a later revision. - * rgerhards, 2009-11-03 - */ -static rsRetVal -rsf_getenv(vmstk_t *pStk, int numOperands) -{ - DEFiRet; - var_t *operand1; - char *envResult; - cstr_t *pCstr; - - if(numOperands != 1) - ABORT_FINALIZE(RS_RET_INVLD_NBR_ARGUMENTS); - - /* pop args and do operaton (trivial case here...) */ - vmstk.PopString(pStk, &operand1); - d_pthread_mutex_lock(&mutGetenv); - envResult = getenv((char*) rsCStrGetSzStr(operand1->val.pStr)); - DBGPRINTF("rsf_getenv(): envvar '%s', return '%s'\n", rsCStrGetSzStr(operand1->val.pStr), - envResult == NULL ? "(NULL)" : envResult); - iRet = rsCStrConstructFromszStr(&pCstr, (envResult == NULL) ? UCHAR_CONSTANT("") : (uchar*)envResult); - d_pthread_mutex_unlock(&mutGetenv); - if(iRet != RS_RET_OK) - FINALIZE; /* need to do this after mutex is unlocked! */ - - /* Store result and cleanup */ - var.SetString(operand1, pCstr); - vmstk.Push(pStk, operand1); -finalize_it: - RETiRet; -} - - -/* The "tolower" function, which converts its sole argument to lower case. - * Quite honestly, currently this is primarily a test driver for me... - * rgerhards, 2009-04-06 - */ -static rsRetVal -rsf_tolower(vmstk_t *pStk, int numOperands) -{ - DEFiRet; - var_t *operand1; - uchar *pSrc; - cstr_t *pcstr; - int iStrlen; - - if(numOperands != 1) - ABORT_FINALIZE(RS_RET_INVLD_NBR_ARGUMENTS); - - /* pop args and do operaton */ - CHKiRet(cstrConstruct(&pcstr)); - vmstk.PopString(pStk, &operand1); - pSrc = cstrGetSzStr(operand1->val.pStr); - iStrlen = strlen((char*)pSrc); // TODO: use count from string! - while(iStrlen--) { - CHKiRet(cstrAppendChar(pcstr, tolower(*pSrc++))); - } - - /* Store result and cleanup */ - CHKiRet(cstrFinalize(pcstr)); - var.SetString(operand1, pcstr); - vmstk.Push(pStk, operand1); -finalize_it: - RETiRet; -} - - -/* Standard-Constructor - */ -BEGINobjConstruct(vm) /* be sure to specify the object type also in END macro! */ -ENDobjConstruct(vm) - - -/* ConstructionFinalizer - * rgerhards, 2008-01-09 - */ -static rsRetVal -vmConstructFinalize(vm_t __attribute__((unused)) *pThis) -{ - DEFiRet; - ISOBJ_TYPE_assert(pThis, vm); - - CHKiRet(vmstk.Construct(&pThis->pStk)); - CHKiRet(vmstk.ConstructFinalize(pThis->pStk)); - -finalize_it: - RETiRet; -} - - -/* destructor for the vm object */ -BEGINobjDestruct(vm) /* be sure to specify the object type also in END and CODESTART macros! */ -CODESTARTobjDestruct(vm) - if(pThis->pStk != NULL) - vmstk.Destruct(&pThis->pStk); - if(pThis->pMsg != NULL) - msgDestruct(&pThis->pMsg); -ENDobjDestruct(vm) - - -/* debugprint for the vm object */ -BEGINobjDebugPrint(vm) /* be sure to specify the object type also in END and CODESTART macros! */ -CODESTARTobjDebugPrint(vm) - dbgoprint((obj_t*) pThis, "rsyslog virtual machine, currently no state info available\n"); -ENDobjDebugPrint(vm) - - -/* execute a program - */ -static rsRetVal -execProg(vm_t *pThis, vmprg_t *pProg) -{ - DEFiRet; - vmop_t *pCurrOp; /* virtual instruction pointer */ - - ISOBJ_TYPE_assert(pThis, vm); - ISOBJ_TYPE_assert(pProg, vmprg); - -#define doOP(OP) case opcode_##OP: DBGPRINTF("rainerscript: opcode %s\n", #OP); \ - CHKiRet(op##OP(pThis, pCurrOp)); break - pCurrOp = pProg->vmopRoot; /* TODO: do this via a method! */ - while(pCurrOp != NULL && pCurrOp->opcode != opcode_END_PROG) { - DBGPRINTF("rainerscript: executing step, opcode %d...\n", pCurrOp->opcode); - switch(pCurrOp->opcode) { - doOP(OR); - doOP(AND); - doOP(CMP_EQ); - doOP(CMP_NEQ); - doOP(CMP_LT); - doOP(CMP_GT); - doOP(CMP_LTEQ); - doOP(CMP_GTEQ); - doOP(CMP_CONTAINS); - doOP(CMP_CONTAINSI); - doOP(CMP_STARTSWITH); - doOP(CMP_STARTSWITHI); - doOP(NOT); - doOP(PUSHCONSTANT); - doOP(PUSHMSGVAR); - doOP(PUSHCEEVAR); - doOP(PUSHSYSVAR); - doOP(STRADD); - doOP(PLUS); - doOP(MINUS); - doOP(TIMES); - doOP(DIV); - doOP(MOD); - doOP(UNARY_MINUS); - doOP(FUNC_CALL); - default: - dbgoprint((obj_t*) pThis, "invalid instruction %d in vmprg\n", pCurrOp->opcode); - ABORT_FINALIZE(RS_RET_INVALID_VMOP); - break; - } - /* so far, we have plain sequential execution, so on to next... */ - pCurrOp = pCurrOp->pNext; - } -#undef doOP - - /* if we reach this point, our program has intintionally terminated - * (no error state). - */ - -finalize_it: - DBGPRINTF("rainerscript: script execution terminated with state %d\n", iRet); - RETiRet; -} - - -/* Set the current message object for the VM. It *is* valid to set a - * NULL message object, what simply means there is none. Message - * objects are properly reference counted. - */ -static rsRetVal -SetMsg(vm_t *pThis, msg_t *pMsg) -{ - DEFiRet; - if(pThis->pMsg != NULL) { - msgDestruct(&pThis->pMsg); - } - - if(pMsg != NULL) { - pThis->pMsg = MsgAddRef(pMsg); - } - - RETiRet; -} - - -/* Pop a var from the stack and return it to caller. The variable type is not - * changed, it is taken from the stack as is. This functionality is - * partly needed. We may (or may not ;)) be able to remove it once we have - * full RainerScript support. -- rgerhards, 2008-02-25 - */ -static rsRetVal -PopVarFromStack(vm_t *pThis, var_t **ppVar) -{ - DEFiRet; - CHKiRet(vmstk.Pop(pThis->pStk, ppVar)); -finalize_it: - RETiRet; -} - - -/* Pop a boolean from the stack and return it to caller. This functionality is - * partly needed. We may (or may not ;)) be able to remove it once we have - * full RainerScript support. -- rgerhards, 2008-02-25 - */ -static rsRetVal -PopBoolFromStack(vm_t *pThis, var_t **ppVar) -{ - DEFiRet; - CHKiRet(vmstk.PopBool(pThis->pStk, ppVar)); -finalize_it: - RETiRet; -} - - -/* queryInterface function - * rgerhards, 2008-02-21 - */ -BEGINobjQueryInterface(vm) -CODESTARTobjQueryInterface(vm) - if(pIf->ifVersion != vmCURR_IF_VERSION) { /* check for current version, increment on each change */ - ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED); - } - - /* ok, we have the right interface, so let's fill it - * Please note that we may also do some backwards-compatibility - * work here (if we can support an older interface version - that, - * of course, also affects the "if" above). - */ - pIf->Construct = vmConstruct; - pIf->ConstructFinalize = vmConstructFinalize; - pIf->Destruct = vmDestruct; - pIf->DebugPrint = vmDebugPrint; - pIf->ExecProg = execProg; - pIf->PopBoolFromStack = PopBoolFromStack; - pIf->PopVarFromStack = PopVarFromStack; - pIf->SetMsg = SetMsg; - pIf->FindRSFunction = findRSFunction; - pIf->FindRSFunctionName = findRSFunctionName; -finalize_it: -ENDobjQueryInterface(vm) - - -/* Exit the vm class. - * rgerhards, 2009-04-06 - */ -BEGINObjClassExit(vm, OBJ_IS_CORE_MODULE) /* class, version */ - rsfrRemoveAll(); - objRelease(sysvar, CORE_COMPONENT); - objRelease(var, CORE_COMPONENT); - objRelease(vmstk, CORE_COMPONENT); - - pthread_mutex_destroy(&mutGetenv); -ENDObjClassExit(vm) - - -/* Initialize the vm class. Must be called as the very first method - * before anything else is called inside this class. - * rgerhards, 2008-02-19 - */ -BEGINObjClassInit(vm, 1, OBJ_IS_CORE_MODULE) /* class, version */ - /* request objects we use */ - CHKiRet(objUse(vmstk, CORE_COMPONENT)); - CHKiRet(objUse(var, CORE_COMPONENT)); - CHKiRet(objUse(sysvar, CORE_COMPONENT)); - - /* set our own handlers */ - OBJSetMethodHandler(objMethod_DEBUGPRINT, vmDebugPrint); - OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, vmConstructFinalize); - - /* register built-in functions // TODO: move to its own module */ - CHKiRet(rsfrAddFunction((uchar*)"strlen", rsf_strlen)); - CHKiRet(rsfrAddFunction((uchar*)"tolower", rsf_tolower)); - CHKiRet(rsfrAddFunction((uchar*)"getenv", rsf_getenv)); - - pthread_mutex_init(&mutGetenv, NULL); - -ENDObjClassInit(vm) - -/* vi:set ai: - */ diff --git a/runtime/vm.h b/runtime/vm.h deleted file mode 100644 index cb3c69d0..00000000 --- a/runtime/vm.h +++ /dev/null @@ -1,68 +0,0 @@ -/* The vm object. - * - * This implements the rsyslog virtual machine. The initial implementation is - * done to support complex user-defined expressions, but it may evolve into a - * much more useful thing over time. - * - * The virtual machine uses rsyslog variables as its memory storage system. - * All computation is done on a stack (vmstk). The vm supports a given - * instruction set and executes programs of type vmprg, which consist of - * single operations defined in vmop (which hold the instruction and the - * data). - * - * Copyright 2008 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 <http://www.gnu.org/licenses/>. - * - * 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. - */ -#ifndef INCLUDED_VM_H -#define INCLUDED_VM_H - -#include "msg.h" -#include "vmstk.h" -#include "vmprg.h" - -/* the vm object */ -typedef struct vm_s { - BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ - vmstk_t *pStk; /* The stack */ - msg_t *pMsg; /* the current message (or NULL, if we have none) */ -} vm_t; - - -/* interfaces */ -BEGINinterface(vm) /* name must also be changed in ENDinterface macro! */ - INTERFACEObjDebugPrint(vm); - rsRetVal (*Construct)(vm_t **ppThis); - rsRetVal (*ConstructFinalize)(vm_t __attribute__((unused)) *pThis); - rsRetVal (*Destruct)(vm_t **ppThis); - rsRetVal (*ExecProg)(vm_t *pThis, vmprg_t *pProg); - rsRetVal (*PopBoolFromStack)(vm_t *pThis, var_t **ppVar); /* there are a few cases where we need this... */ - rsRetVal (*PopVarFromStack)(vm_t *pThis, var_t **ppVar); /* there are a few cases where we need this... */ - rsRetVal (*SetMsg)(vm_t *pThis, msg_t *pMsg); /* there are a few cases where we need this... */ - /* v2 (4.1.7) */ - rsRetVal (*FindRSFunction)(cstr_t *pcsName, prsf_t *prsf); /* 2009-06-04 */ - rsRetVal (*FindRSFunctionName)(prsf_t rsf, cstr_t **ppcsName); /* 2009-06-04 */ -ENDinterface(vm) -#define vmCURR_IF_VERSION 2 /* increment whenever you change the interface structure! */ - - -/* prototypes */ -PROTOTYPEObj(vm); - -#endif /* #ifndef INCLUDED_VM_H */ diff --git a/runtime/vmop.c b/runtime/vmop.c deleted file mode 100644 index ea627220..00000000 --- a/runtime/vmop.c +++ /dev/null @@ -1,307 +0,0 @@ -/* vmop.c - abstracts an operation (instructed) supported by the - * rsyslog virtual machine - * - * Module begun 2008-02-20 by Rainer Gerhards - * - * Copyright 2007, 2008 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 <http://www.gnu.org/licenses/>. - * - * 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 <stdio.h> -#include <stdlib.h> -#include <assert.h> - -#include "rsyslog.h" -#include "obj.h" -#include "vmop.h" -#include "vm.h" - -/* static data */ -DEFobjStaticHelpers -DEFobjCurrIf(var) -DEFobjCurrIf(vm) - - -/* forward definitions */ -static rsRetVal vmopOpcode2Str(vmop_t *pThis, uchar **ppName); - -/* Standard-Constructor - */ -BEGINobjConstruct(vmop) /* be sure to specify the object type also in END macro! */ -ENDobjConstruct(vmop) - - -/* ConstructionFinalizer - * rgerhards, 2008-01-09 - */ -rsRetVal vmopConstructFinalize(vmop_t __attribute__((unused)) *pThis) -{ - DEFiRet; - ISOBJ_TYPE_assert(pThis, vmop); - RETiRet; -} - - -/* destructor for the vmop object */ -BEGINobjDestruct(vmop) /* be sure to specify the object type also in END and CODESTART macros! */ -CODESTARTobjDestruct(vmop) - if(pThis->opcode != opcode_FUNC_CALL) { - if(pThis->operand.pVar != NULL) - var.Destruct(&pThis->operand.pVar); - } -ENDobjDestruct(vmop) - - -/* DebugPrint support for the vmop object */ -BEGINobjDebugPrint(vmop) /* be sure to specify the object type also in END and CODESTART macros! */ - uchar *pOpcodeName; - cstr_t *pStrVar; -CODESTARTobjDebugPrint(vmop) - vmopOpcode2Str(pThis, &pOpcodeName); - if(pThis->opcode == opcode_FUNC_CALL) { - CHKiRet(vm.FindRSFunctionName(pThis->operand.rsf, &pStrVar)); - assert(pStrVar != NULL); - } else { - CHKiRet(rsCStrConstruct(&pStrVar)); - if(pThis->operand.pVar != NULL) { - CHKiRet(var.Obj2Str(pThis->operand.pVar, pStrVar)); - } - } - CHKiRet(cstrFinalize(pStrVar)); - dbgoprint((obj_t*) pThis, "%.12s\t%s\n", pOpcodeName, rsCStrGetSzStrNoNULL(pStrVar)); - if(pThis->opcode != opcode_FUNC_CALL) - rsCStrDestruct(&pStrVar); -finalize_it: -ENDobjDebugPrint(vmop) - - -/* This function is similar to DebugPrint, but does not send its output to - * the debug log but instead to a caller-provided string. The idea here is that - * we can use this string to get a textual representation of an operation. - * Among others, this is useful for creating testbenches, our first use case for - * it. Here, it enables simple comparison of the resulting program to a - * reference program by simple string compare. - * Note that the caller must initialize the string object. We always add - * data to it. So, it can be easily combined into a chain of methods - * to generate the final string. - * rgerhards, 2008-07-04 - */ -static rsRetVal -Obj2Str(vmop_t *pThis, cstr_t *pstrPrg) -{ - uchar *pOpcodeName; - cstr_t *pcsFuncName; - uchar szBuf[2048]; - size_t lenBuf; - DEFiRet; - - ISOBJ_TYPE_assert(pThis, vmop); - assert(pstrPrg != NULL); - vmopOpcode2Str(pThis, &pOpcodeName); - lenBuf = snprintf((char*) szBuf, sizeof(szBuf), "%s\t", pOpcodeName); - CHKiRet(rsCStrAppendStrWithLen(pstrPrg, szBuf, lenBuf)); - if(pThis->opcode == opcode_FUNC_CALL) { - CHKiRet(vm.FindRSFunctionName(pThis->operand.rsf, &pcsFuncName)); - CHKiRet(rsCStrAppendCStr(pstrPrg, pcsFuncName)); - } else { - if(pThis->operand.pVar != NULL) - CHKiRet(var.Obj2Str(pThis->operand.pVar, pstrPrg)); - } - CHKiRet(cstrAppendChar(pstrPrg, '\n')); - -finalize_it: - RETiRet; -} - - -/* set function - * rgerhards, 2009-04-06 - */ -static rsRetVal -vmopSetFunc(vmop_t *pThis, cstr_t *pcsFuncName) -{ - prsf_t rsf; /* pointer to function */ - DEFiRet; - ISOBJ_TYPE_assert(pThis, vmop); - CHKiRet(vm.FindRSFunction(pcsFuncName, &rsf)); /* check if function exists and obtain pointer to it */ - assert(rsf != NULL); /* just double-check, would be very hard to find! */ - pThis->operand.rsf = rsf; -finalize_it: - RETiRet; -} - - -/* set operand (variant case) - * rgerhards, 2008-02-20 - */ -static rsRetVal -vmopSetVar(vmop_t *pThis, var_t *pVar) -{ - DEFiRet; - ISOBJ_TYPE_assert(pThis, vmop); - ISOBJ_TYPE_assert(pVar, var); - pThis->operand.pVar = pVar; - RETiRet; -} - - -/* set operation - * rgerhards, 2008-02-20 - */ -static rsRetVal -vmopSetOpcode(vmop_t *pThis, opcode_t opcode) -{ - DEFiRet; - ISOBJ_TYPE_assert(pThis, vmop); - pThis->opcode = opcode; - RETiRet; -} - - -/* a way to turn an opcode into a readable string - */ -static rsRetVal -vmopOpcode2Str(vmop_t *pThis, uchar **ppName) -{ - DEFiRet; - ISOBJ_TYPE_assert(pThis, vmop); - - switch(pThis->opcode) { - case opcode_OR: - *ppName = (uchar*) "or"; - break; - case opcode_AND: - *ppName = (uchar*) "and"; - break; - case opcode_PLUS: - *ppName = (uchar*) "add"; - break; - case opcode_MINUS: - *ppName = (uchar*) "sub"; - break; - case opcode_TIMES: - *ppName = (uchar*) "mul"; - break; - case opcode_DIV: - *ppName = (uchar*) "div"; - break; - case opcode_MOD: - *ppName = (uchar*) "mod"; - break; - case opcode_NOT: - *ppName = (uchar*) "not"; - break; - case opcode_CMP_EQ: - *ppName = (uchar*) "cmp_=="; - break; - case opcode_CMP_NEQ: - *ppName = (uchar*) "cmp_!="; - break; - case opcode_CMP_LT: - *ppName = (uchar*) "cmp_<"; - break; - case opcode_CMP_GT: - *ppName = (uchar*) "cmp_>"; - break; - case opcode_CMP_LTEQ: - *ppName = (uchar*) "cmp_<="; - break; - case opcode_CMP_CONTAINS: - *ppName = (uchar*) "contains"; - break; - case opcode_CMP_STARTSWITH: - *ppName = (uchar*) "startswith"; - break; - case opcode_CMP_GTEQ: - *ppName = (uchar*) "cmp_>="; - break; - case opcode_PUSHSYSVAR: - *ppName = (uchar*) "push_sysvar"; - break; - case opcode_PUSHMSGVAR: - *ppName = (uchar*) "push_msgvar"; - break; - case opcode_PUSHCONSTANT: - *ppName = (uchar*) "push_const"; - break; - case opcode_POP: - *ppName = (uchar*) "pop"; - break; - case opcode_UNARY_MINUS: - *ppName = (uchar*) "unary_minus"; - break; - case opcode_STRADD: - *ppName = (uchar*) "strconcat"; - break; - case opcode_FUNC_CALL: - *ppName = (uchar*) "func_call"; - break; - default: - *ppName = (uchar*) "!invalid_opcode!"; - break; - } - - RETiRet; -} - - -/* queryInterface function - * rgerhards, 2008-02-21 - */ -BEGINobjQueryInterface(vmop) -CODESTARTobjQueryInterface(vmop) - if(pIf->ifVersion != vmopCURR_IF_VERSION) { /* check for current version, increment on each change */ - ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED); - } - - /* ok, we have the right interface, so let's fill it - * Please note that we may also do some backwards-compatibility - * work here (if we can support an older interface version - that, - * of course, also affects the "if" above). - */ - pIf->Construct = vmopConstruct; - pIf->ConstructFinalize = vmopConstructFinalize; - pIf->Destruct = vmopDestruct; - pIf->DebugPrint = vmopDebugPrint; - pIf->SetFunc = vmopSetFunc; - pIf->SetOpcode = vmopSetOpcode; - pIf->SetVar = vmopSetVar; - pIf->Opcode2Str = vmopOpcode2Str; - pIf->Obj2Str = Obj2Str; -finalize_it: -ENDobjQueryInterface(vmop) - - -/* Initialize the vmop class. Must be called as the very first method - * before anything else is called inside this class. - * rgerhards, 2008-02-19 - */ -BEGINObjClassInit(vmop, 1, OBJ_IS_CORE_MODULE) /* class, version */ - /* request objects we use */ - CHKiRet(objUse(var, CORE_COMPONENT)); - CHKiRet(objUse(vm, CORE_COMPONENT)); - - OBJSetMethodHandler(objMethod_DEBUGPRINT, vmopDebugPrint); - OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, vmopConstructFinalize); -ENDObjClassInit(vmop) - -/* vi:set ai: - */ diff --git a/runtime/vmop.h b/runtime/vmop.h deleted file mode 100644 index c085a940..00000000 --- a/runtime/vmop.h +++ /dev/null @@ -1,129 +0,0 @@ -/* The vmop object. - * - * Copyright 2008 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of rsyslog. - * - * 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 <http://www.gnu.org/licenses/>. - * - * 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. - */ -#ifndef INCLUDED_VMOP_H -#define INCLUDED_VMOP_H - -#include "ctok_token.h" -#include "vmstk.h" -#include "stringbuf.h" - -/* machine instructions types */ -typedef enum { /* do NOT start at 0 to detect uninitialized types after calloc() */ - opcode_INVALID = 0, - /* for simplicity of debugging and reading dumps, we use the same IDs - * that the tokenizer uses where this applicable. - */ - opcode_OR = ctok_OR, - opcode_AND = ctok_AND, - opcode_STRADD= ctok_STRADD, - opcode_PLUS = ctok_PLUS, - opcode_MINUS = ctok_MINUS, - opcode_TIMES = ctok_TIMES, /* "*" */ - opcode_DIV = ctok_DIV, - opcode_MOD = ctok_MOD, - opcode_NOT = ctok_NOT, - opcode_CMP_EQ = ctok_CMP_EQ, /* all compare operations must be in a row */ - opcode_CMP_NEQ = ctok_CMP_NEQ, - opcode_CMP_LT = ctok_CMP_LT, - opcode_CMP_GT = ctok_CMP_GT, - opcode_CMP_LTEQ = ctok_CMP_LTEQ, - opcode_CMP_CONTAINS = ctok_CMP_CONTAINS, - opcode_CMP_STARTSWITH = ctok_CMP_STARTSWITH, - opcode_CMP_CONTAINSI = ctok_CMP_CONTAINSI, - opcode_CMP_STARTSWITHI = ctok_CMP_STARTSWITHI, - opcode_CMP_GTEQ = ctok_CMP_GTEQ, /* end compare operations */ - /* here we start our own codes */ - opcode_POP = 1000, /* requires var operand to receive result */ - opcode_PUSHSYSVAR = 1001, /* requires var operand */ - opcode_PUSHMSGVAR = 1002, /* requires var operand */ - opcode_PUSHCONSTANT = 1003, /* requires var operand */ - opcode_PUSHCEEVAR = 1004, /* requires var operand */ - opcode_UNARY_MINUS = 1010, - opcode_FUNC_CALL = 1012, - opcode_END_PROG = 2000 -} opcode_t; - - -/* Additional doc, operation specific - - FUNC_CALL - All parameter passing is via the stack. Parameters are placed onto the stack in reverse order, - that means the last parameter is on top of the stack, the first at the bottom location. - At the actual top of the stack is the number of parameters. This permits functions to be - called with variable number of arguments. The function itself is responsible for poping - the right number of parameters of the stack and complaining if the number is incorrect. - On exit, a single return value must be pushed onto the stack. The FUNC_CALL operation - is generic. Its pVar argument contains the function name string (TODO: very slow, make - faster in later releases). - - Sample Function call: sampleFunc(p1, p2, p3) ; returns number 4711 (sample) - Stacklayout on entry (order is top to bottom): - 3 - p3 - p2 - p1 - ... other vars ... - - Stack on exit - 4711 - ... other vars ... - - */ - - -/* the vmop object */ -typedef struct vmop_s { - BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ - opcode_t opcode; - union { - var_t *pVar; - prsf_t rsf; /* pointer to function for "call" instruction */ - } operand; - struct vmop_s *pNext; /* next operation or NULL, if end of program (logically this belongs to vmprg) */ -} vmop_t; - - -/* interfaces */ -BEGINinterface(vmop) /* name must also be changed in ENDinterface macro! */ - INTERFACEObjDebugPrint(vmop); - rsRetVal (*Construct)(vmop_t **ppThis); - rsRetVal (*ConstructFinalize)(vmop_t __attribute__((unused)) *pThis); - rsRetVal (*Destruct)(vmop_t **ppThis); - rsRetVal (*SetOpcode)(vmop_t *pThis, opcode_t opcode); - rsRetVal (*SetVar)(vmop_t *pThis, var_t *pVar); - rsRetVal (*Opcode2Str)(vmop_t *pThis, uchar **ppName); - rsRetVal (*Obj2Str)(vmop_t *pThis, cstr_t *pstr); - /* v2 */ - rsRetVal (*SetFunc)(vmop_t *pThis, cstr_t *pcsFuncName); -ENDinterface(vmop) -#define vmopCURR_IF_VERSION 2 /* increment whenever you change the interface structure! */ -/* interface changes, v1 -> v2 - * added SetFuct after existing function pointers -- rgerhards, 2009-04-06 - */ - -/* the remaining prototypes */ -PROTOTYPEObj(vmop); - -#endif /* #ifndef INCLUDED_VMOP_H */ diff --git a/runtime/vmprg.c b/runtime/vmprg.c deleted file mode 100644 index 07757b98..00000000 --- a/runtime/vmprg.c +++ /dev/null @@ -1,236 +0,0 @@ -/* vmprg.c - abstracts a program (bytecode) for the rsyslog virtual machine - * - * Module begun 2008-02-20 by Rainer Gerhards - * - * Copyright 2007, 2008 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 <http://www.gnu.org/licenses/>. - * - * 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 <stdio.h> -#include <stdlib.h> -#include <assert.h> - -#include "rsyslog.h" -#include "obj.h" -#include "vmprg.h" -#include "stringbuf.h" - -/* static data */ -DEFobjStaticHelpers -DEFobjCurrIf(vmop) - - -/* Standard-Constructor - */ -BEGINobjConstruct(vmprg) /* be sure to specify the object type also in END macro! */ -ENDobjConstruct(vmprg) - - -/* ConstructionFinalizer - * rgerhards, 2008-01-09 - */ -static rsRetVal -vmprgConstructFinalize(vmprg_t __attribute__((unused)) *pThis) -{ - DEFiRet; - ISOBJ_TYPE_assert(pThis, vmprg); - RETiRet; -} - - -/* destructor for the vmprg object */ -BEGINobjDestruct(vmprg) /* be sure to specify the object type also in END and CODESTART macros! */ - vmop_t *pOp; - vmop_t *pTmp; -CODESTARTobjDestruct(vmprg) - /* we need to destruct the program elements! */ - for(pOp = pThis->vmopRoot ; pOp != NULL ; ) { - pTmp = pOp; - pOp = pOp->pNext; - vmop.Destruct(&pTmp); - } -ENDobjDestruct(vmprg) - - -/* destructor for the vmop object */ -BEGINobjDebugPrint(vmprg) /* be sure to specify the object type also in END and CODESTART macros! */ - vmop_t *pOp; -CODESTARTobjDebugPrint(vmprg) - dbgoprint((obj_t*) pThis, "VM Program:\n"); - for(pOp = pThis->vmopRoot ; pOp != NULL ; pOp = pOp->pNext) { - vmop.DebugPrint(pOp); - } -ENDobjDebugPrint(vmprg) - - -/* This function is similar to DebugPrint, but does not send its output to - * the debug log but instead to a caller-provided string. The idea here is that - * we can use this string to get a textual representation of a bytecode program. - * Among others, this is useful for creating testbenches, our first use case for - * it. Here, it enables simple comparison of the resulting program to a - * reference program by simple string compare. - * Note that the caller must initialize the string object. We always add - * data to it. So, it can be easily combined into a chain of methods - * to generate the final string. - * rgerhards, 2008-07-04 - */ -static rsRetVal -Obj2Str(vmprg_t *pThis, cstr_t *pstrPrg) -{ - uchar szAddr[12]; - vmop_t *pOp; - int i; - int lenAddr; - DEFiRet; - - ISOBJ_TYPE_assert(pThis, vmprg); - assert(pstrPrg != NULL); - i = 0; /* "program counter" */ - for(pOp = pThis->vmopRoot ; pOp != NULL ; pOp = pOp->pNext) { - lenAddr = snprintf((char*)szAddr, sizeof(szAddr), "%8.8d: ", i++); - CHKiRet(rsCStrAppendStrWithLen(pstrPrg, szAddr, lenAddr)); - vmop.Obj2Str(pOp, pstrPrg); - } - -finalize_it: - RETiRet; -} - - -/* add an operation (instruction) to the end of the current program. This - * function is expected to be called while creating the program, but never - * again after this is done and it is being executed. Results are undefined if - * it is called after execution. - */ -static rsRetVal -vmprgAddOperation(vmprg_t *pThis, vmop_t *pOp) -{ - DEFiRet; - - ISOBJ_TYPE_assert(pThis, vmprg); - ISOBJ_TYPE_assert(pOp, vmop); - - if(pThis->vmopRoot == NULL) { - pThis->vmopRoot = pOp; - } else { - pThis->vmopLast->pNext = pOp; - } - pThis->vmopLast = pOp; - - RETiRet; -} - - -/* this is a shortcut for high-level callers. It creates a new vmop, sets its - * parameters and adds it to the program - all in one big step. If there is no - * var associated with this operation, the caller can simply supply NULL as - * pVar. - */ -static rsRetVal -vmprgAddVarOperation(vmprg_t *pThis, opcode_t opcode, var_t *pVar) -{ - DEFiRet; - vmop_t *pOp; - - ISOBJ_TYPE_assert(pThis, vmprg); - - /* construct and fill vmop */ - CHKiRet(vmop.Construct(&pOp)); - CHKiRet(vmop.ConstructFinalize(pOp)); - CHKiRet(vmop.SetOpcode(pOp, opcode)); - if(pVar != NULL) - CHKiRet(vmop.SetVar(pOp, pVar)); - - /* and add it to the program */ - CHKiRet(vmprgAddOperation(pThis, pOp)); - -finalize_it: - RETiRet; -} - - -/* this is another shortcut for high-level callers. It is similar to vmprgAddVarOperation - * but adds a call operation. Among others, this include a check if the function - * is known. - */ -static rsRetVal -vmprgAddCallOperation(vmprg_t *pThis, cstr_t *pcsName) -{ - DEFiRet; - vmop_t *pOp; - - ISOBJ_TYPE_assert(pThis, vmprg); - - /* construct and fill vmop */ - CHKiRet(vmop.Construct(&pOp)); - CHKiRet(vmop.ConstructFinalize(pOp)); - CHKiRet(vmop.SetFunc(pOp, pcsName)); - CHKiRet(vmop.SetOpcode(pOp, opcode_FUNC_CALL)); - - /* and add it to the program */ - CHKiRet(vmprgAddOperation(pThis, pOp)); - -finalize_it: - RETiRet; -} - - -/* queryInterface function - * rgerhards, 2008-02-21 - */ -BEGINobjQueryInterface(vmprg) -CODESTARTobjQueryInterface(vmprg) - if(pIf->ifVersion != vmprgCURR_IF_VERSION) { /* check for current version, increment on each change */ - ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED); - } - - /* ok, we have the right interface, so let's fill it - * Please note that we may also do some backwards-compatibility - * work here (if we can support an older interface version - that, - * of course, also affects the "if" above). - */ - pIf->Construct = vmprgConstruct; - pIf->ConstructFinalize = vmprgConstructFinalize; - pIf->Destruct = vmprgDestruct; - pIf->DebugPrint = vmprgDebugPrint; - pIf->Obj2Str = Obj2Str; - pIf->AddOperation = vmprgAddOperation; - pIf->AddVarOperation = vmprgAddVarOperation; - pIf->AddCallOperation = vmprgAddCallOperation; -finalize_it: -ENDobjQueryInterface(vmprg) - - -/* Initialize the vmprg class. Must be called as the very first method - * before anything else is called inside this class. - * rgerhards, 2008-02-19 - */ -BEGINObjClassInit(vmprg, 1, OBJ_IS_CORE_MODULE) /* class, version */ - /* request objects we use */ - CHKiRet(objUse(vmop, CORE_COMPONENT)); - - /* set our own handlers */ - OBJSetMethodHandler(objMethod_DEBUGPRINT, vmprgDebugPrint); - OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, vmprgConstructFinalize); -ENDObjClassInit(vmprg) - -/* vi:set ai: - */ diff --git a/runtime/vmprg.h b/runtime/vmprg.h deleted file mode 100644 index 66f03913..00000000 --- a/runtime/vmprg.h +++ /dev/null @@ -1,69 +0,0 @@ -/* The vmprg object. - * - * The program is made up of vmop_t's, one after another. When we support - * branching (or user-defined functions) at some time, well do this via - * special branch opcodes. They will then contain the actual memory - * address of a logical program entry that we shall branch to. Other than - * that, all execution is serial - that is one opcode is executed after - * the other. This class implements a logical program store, modelled - * after real main memory. A linked list of opcodes is used to implement it. - * In the future, we may use linked lists of array's to enhance performance, - * but for the time being we have taken the simplistic approach (which also - * reduces risk of bugs during initial development). The necessary pointers - * for this are already implemented in vmop. Though this is not the 100% - * correct place, we have opted this time in favor of performance, which - * made them go there. - * - * Copyright 2008 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 <http://www.gnu.org/licenses/>. - * - * 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. - */ -#ifndef INCLUDED_VMPRG_H -#define INCLUDED_VMPRG_H - -#include "vmop.h" -#include "stringbuf.h" - -/* the vmprg object */ -typedef struct vmprg_s { - BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ - vmop_t *vmopRoot; /* start of program */ - vmop_t *vmopLast; /* last vmop of program (for adding new ones) */ -} vmprg_t; - - -/* interfaces */ -BEGINinterface(vmprg) /* name must also be changed in ENDinterface macro! */ - INTERFACEObjDebugPrint(vmprg); - rsRetVal (*Construct)(vmprg_t **ppThis); - rsRetVal (*ConstructFinalize)(vmprg_t __attribute__((unused)) *pThis); - rsRetVal (*Destruct)(vmprg_t **ppThis); - rsRetVal (*AddOperation)(vmprg_t *pThis, vmop_t *pOp); - rsRetVal (*AddVarOperation)(vmprg_t *pThis, opcode_t opcode, var_t *pVar); - rsRetVal (*Obj2Str)(vmprg_t *pThis, cstr_t *pstr); - /* v2 (4.1.7) */ - rsRetVal (*AddCallOperation)(vmprg_t *pThis, cstr_t *pVar); /* added 2009-04-06 */ -ENDinterface(vmprg) -#define vmprgCURR_IF_VERSION 2 /* increment whenever you change the interface structure! */ - - -/* prototypes */ -PROTOTYPEObj(vmprg); - -#endif /* #ifndef INCLUDED_VMPRG_H */ diff --git a/runtime/vmstk.c b/runtime/vmstk.c deleted file mode 100644 index 1ee3d485..00000000 --- a/runtime/vmstk.c +++ /dev/null @@ -1,234 +0,0 @@ -/* vmstk.c - the arithmetic stack of a virtual machine. - * - * Module begun 2008-02-21 by Rainer Gerhards - * - * Copyright 2008 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 <http://www.gnu.org/licenses/>. - * - * 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 <stdlib.h> -#include <assert.h> - -#include "rsyslog.h" -#include "obj.h" -#include "vmstk.h" - -/* static data */ -DEFobjStaticHelpers -DEFobjCurrIf(var) - - -/* Standard-Constructor - */ -BEGINobjConstruct(vmstk) /* be sure to specify the object type also in END macro! */ -ENDobjConstruct(vmstk) - - -/* ConstructionFinalizer - * rgerhards, 2008-01-09 - */ -static rsRetVal -vmstkConstructFinalize(vmstk_t __attribute__((unused)) *pThis) -{ - DEFiRet; - ISOBJ_TYPE_assert(pThis, vmstk); - RETiRet; -} - - -/* destructor for the vmstk object */ -BEGINobjDestruct(vmstk) /* be sure to specify the object type also in END and CODESTART macros! */ -CODESTARTobjDestruct(vmstk) -ENDobjDestruct(vmstk) - - -/* debugprint for the vmstk object */ -BEGINobjDebugPrint(vmstk) /* be sure to specify the object type also in END and CODESTART macros! */ -CODESTARTobjDebugPrint(vmstk) - dbgoprint((obj_t*) pThis, "stack contents:\n"); -ENDobjDebugPrint(vmstk) - - -/* push a value on the stack. The provided pVar is now owned - * by the stack. If the user intends to continue use it, it - * must be duplicated. - */ -static rsRetVal -push(vmstk_t *pThis, var_t *pVar) -{ - DEFiRet; - - ISOBJ_TYPE_assert(pThis, vmstk); - ISOBJ_TYPE_assert(pVar, var); - - if(pThis->iStkPtr >= VMSTK_SIZE) - ABORT_FINALIZE(RS_RET_OUT_OF_STACKSPACE); - - pThis->vStk[pThis->iStkPtr++] = pVar; - -finalize_it: - RETiRet; -} - - -/* pop a value from the stack - * IMPORTANT: the stack pointer always points to the NEXT FREE entry. So in - * order to pop, we must access the element one below the stack pointer. - * The user is responsible for destructing the ppVar returned. - */ -static rsRetVal -pop(vmstk_t *pThis, var_t **ppVar) -{ - DEFiRet; - - ISOBJ_TYPE_assert(pThis, vmstk); - ASSERT(ppVar != NULL); - - if(pThis->iStkPtr == 0) - ABORT_FINALIZE(RS_RET_STACK_EMPTY); - - *ppVar = pThis->vStk[--pThis->iStkPtr]; - -finalize_it: - RETiRet; -} - - -/* pop a boolean value from the stack - * The user is responsible for destructing the ppVar returned. - */ -static rsRetVal -popBool(vmstk_t *pThis, var_t **ppVar) -{ - DEFiRet; - - /* assertions are done in pop(), we do not duplicate here */ - CHKiRet(pop(pThis, ppVar)); - CHKiRet(var.ConvToBool(*ppVar)); - -finalize_it: - RETiRet; -} - - -/* pop a number value from the stack - * The user is responsible for destructing the ppVar returned. - */ -static rsRetVal -popNumber(vmstk_t *pThis, var_t **ppVar) -{ - DEFiRet; - - /* assertions are done in pop(), we do not duplicate here */ - CHKiRet(pop(pThis, ppVar)); - CHKiRet(var.ConvToNumber(*ppVar)); - -finalize_it: - RETiRet; -} - - -/* pop a number value from the stack - * The user is responsible for destructing the ppVar returned. - */ -static rsRetVal -popString(vmstk_t *pThis, var_t **ppVar) -{ - DEFiRet; - - /* assertions are done in pop(), we do not duplicate here */ - CHKiRet(pop(pThis, ppVar)); - CHKiRet(var.ConvToString(*ppVar)); - -finalize_it: - RETiRet; -} - - -/* pop two variables for a common operation, e.g. a compare. When this - * functions returns, both variables have the same type, but the type - * is not set to anything specific. - * The user is responsible for destructing the ppVar's returned. - * A quick note on the name: it means pop 2 variable for a common - * opertion - just in case you wonder (I don't really like the name, - * but I didn't come up with a better one...). - * rgerhards, 2008-02-25 - */ -static rsRetVal -pop2CommOp(vmstk_t *pThis, var_t **ppVar1, var_t **ppVar2) -{ - DEFiRet; - - /* assertions are done in pop(), we do not duplicate here */ - /* operand two must be popped first, because it is at the top of stack */ - CHKiRet(pop(pThis, ppVar2)); - CHKiRet(pop(pThis, ppVar1)); - CHKiRet(var.ConvForOperation(*ppVar1, *ppVar2)); - -finalize_it: - RETiRet; -} - - -/* queryInterface function - * rgerhards, 2008-02-21 - */ -BEGINobjQueryInterface(vmstk) -CODESTARTobjQueryInterface(vmstk) - if(pIf->ifVersion != vmstkCURR_IF_VERSION) { /* check for current version, increment on each change */ - ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED); - } - - /* ok, we have the right interface, so let's fill it - * Please note that we may also do some backwards-compatibility - * work here (if we can support an older interface version - that, - * of course, also affects the "if" above). - */ - pIf->Construct = vmstkConstruct; - pIf->ConstructFinalize = vmstkConstructFinalize; - pIf->Destruct = vmstkDestruct; - pIf->DebugPrint = vmstkDebugPrint; - pIf->Push = push; - pIf->Pop = pop; - pIf->PopBool = popBool; - pIf->PopNumber = popNumber; - pIf->PopString = popString; - pIf->Pop2CommOp = pop2CommOp; - -finalize_it: -ENDobjQueryInterface(vmstk) - - -/* Initialize the vmstk class. Must be called as the very first method - * before anything else is called inside this class. - * rgerhards, 2008-02-19 - */ -BEGINObjClassInit(vmstk, 1, OBJ_IS_CORE_MODULE) /* class, version */ - /* request objects we use */ - CHKiRet(objUse(var, CORE_COMPONENT)); - - /* set our own handlers */ - OBJSetMethodHandler(objMethod_DEBUGPRINT, vmstkDebugPrint); - OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, vmstkConstructFinalize); -ENDObjClassInit(vmstk) - -/* vi:set ai: - */ diff --git a/runtime/vmstk.h b/runtime/vmstk.h deleted file mode 100644 index 06657cf4..00000000 --- a/runtime/vmstk.h +++ /dev/null @@ -1,56 +0,0 @@ -/* The vmstk object. - * - * Copyright 2008 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 <http://www.gnu.org/licenses/>. - * - * 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. - */ -#ifndef INCLUDED_VMSTK_H -#define INCLUDED_VMSTK_H - -/* The max size of the stack - TODO: make configurable */ -#define VMSTK_SIZE 256 - -/* the vmstk object */ -struct vmstk_s { - BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ - var_t *vStk[VMSTK_SIZE];/* the actual stack */ - int iStkPtr; /* stack pointer, points to next free location, grows from 0 --> topend */ -}; - - -/* interfaces */ -BEGINinterface(vmstk) /* name must also be changed in ENDinterface macro! */ - INTERFACEObjDebugPrint(vmstk); - rsRetVal (*Construct)(vmstk_t **ppThis); - rsRetVal (*ConstructFinalize)(vmstk_t __attribute__((unused)) *pThis); - rsRetVal (*Destruct)(vmstk_t **ppThis); - rsRetVal (*Push)(vmstk_t *pThis, var_t *pVar); - rsRetVal (*Pop)(vmstk_t *pThis, var_t **ppVar); - rsRetVal (*PopBool)(vmstk_t *pThis, var_t **ppVar); - rsRetVal (*PopNumber)(vmstk_t *pThis, var_t **ppVar); - rsRetVal (*PopString)(vmstk_t *pThis, var_t **ppVar); - rsRetVal (*Pop2CommOp)(vmstk_t *pThis, var_t **ppVar1, var_t **ppVar2); -ENDinterface(vmstk) -#define vmstkCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */ - - -/* prototypes */ -PROTOTYPEObj(vmstk); - -#endif /* #ifndef INCLUDED_VMSTK_H */ |