summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRainer Gerhards <rgerhards@adiscon.com>2007-07-27 16:55:40 +0000
committerRainer Gerhards <rgerhards@adiscon.com>2007-07-27 16:55:40 +0000
commit1d96a98daf4ac4c4ec9e664e328f1aac4bf6af9e (patch)
tree249ec71321b657a6a37b91f1d03f4e2c4bf07697
parent8193522d85290df659d8c2e505e8c47f39db9267 (diff)
downloadrsyslog-1d96a98daf4ac4c4ec9e664e328f1aac4bf6af9e.tar.gz
rsyslog-1d96a98daf4ac4c4ec9e664e328f1aac4bf6af9e.tar.xz
rsyslog-1d96a98daf4ac4c4ec9e664e328f1aac4bf6af9e.zip
- added omsr object (objomsr.c, objomsr.h) - template request for output
modules - changed doAction() interface - templates and output string generation for doActon() is now fully
-rw-r--r--module-template.h31
-rw-r--r--modules.h6
-rw-r--r--objomsr.c3
-rw-r--r--objomsr.h7
-rw-r--r--omdiscard.c1
-rw-r--r--omfile.c77
-rw-r--r--omfwd.c31
-rw-r--r--ommysql.c44
-rw-r--r--omshell.c6
-rw-r--r--omusrmsg.c42
-rw-r--r--rsyslog.h1
-rw-r--r--syslogd-types.h1
-rw-r--r--syslogd.c245
-rw-r--r--syslogd.h6
14 files changed, 276 insertions, 225 deletions
diff --git a/module-template.h b/module-template.h
index 2d34893e..470d81d8 100644
--- a/module-template.h
+++ b/module-template.h
@@ -25,6 +25,8 @@
#ifndef MODULE_TEMPLATE_H_INCLUDED
#define MODULE_TEMPLATE_H_INCLUDED 1
+#include "objomsr.h"
+
/* to following macros are used to generate function headers and standard
* functionality. It works as follows (described on the sample case of
* createInstance()):
@@ -89,13 +91,13 @@ static rsRetVal isCompatibleWithFeature(syslogFeature __attribute__((unused)) eF
/* doAction()
*/
#define BEGINdoAction \
-static rsRetVal doAction(selector_t *f, uchar __attribute__((unused)) *pMsg, instanceData __attribute__((unused)) *pData)\
+static rsRetVal doAction(selector_t *f, uchar __attribute__((unused)) **ppString, unsigned __attribute__((unused)) iMsgOpts, instanceData __attribute__((unused)) *pData)\
{\
rsRetVal iRet = RS_RET_OK;
#define CODESTARTdoAction \
assert(f != NULL);\
- assert(pMsg != NULL);
+ assert(ppString != NULL);
#define ENDdoAction \
return iRet;\
@@ -191,10 +193,18 @@ static rsRetVal getWriteFDForSelect(selector_t *f, void *pModData, short *fd)\
* Extra comments:
* try to process a selector action line. Checks if the action
* applies to this module and, if so, processed it. If not, it
- * is left untouched. The driver will then call another module
+ * is left untouched. The driver will then call another module.
+ * On exit, ppModData must point to instance data. Also, a string
+ * request object must be created and filled. A macro is defined
+ * for that.
+ * For the most usual case, we have defined a macro below.
+ * If more than one string is requested, the macro can be used together
+ * with own code that overwrites the entry count. In this case, the
+ * macro must come before the own code. It is recommended to be
+ * placed right after CODESTARTparseSelectorAct.
*/
#define BEGINparseSelectorAct \
-static rsRetVal parseSelectorAct(uchar **pp, selector_t *f, void **ppModData)\
+static rsRetVal parseSelectorAct(uchar **pp, selector_t *f, void **ppModData, omodStringRequest_t **ppOMSR)\
{\
rsRetVal iRet = RS_RET_OK;\
uchar *p;\
@@ -204,13 +214,24 @@ static rsRetVal parseSelectorAct(uchar **pp, selector_t *f, void **ppModData)\
assert(pp != NULL);\
assert(ppModData != NULL);\
assert(f != NULL);\
+ assert(ppOMSR != NULL);\
p = *pp;
+#define CODE_STD_STRING_REQUESTparseSelectorAct(NumStrReqEntries) \
+ if((iRet = OMSRconstruct(ppOMSR, NumStrReqEntries)) != RS_RET_OK)\
+ goto do_abort;\
+
#define ENDparseSelectorAct \
+do_abort:\
if(iRet == RS_RET_OK) {\
*ppModData = pData;\
*pp = p;\
- }\
+ } else {\
+ /* cleanup, we failed */\
+ if(*ppOMSR != NULL)\
+ OMSRdestruct(*ppOMSR);\
+ *ppOMSR = NULL;\
+ }\
return iRet;\
}
diff --git a/modules.h b/modules.h
index 19695eba..e6398a2e 100644
--- a/modules.h
+++ b/modules.h
@@ -30,6 +30,8 @@
#ifndef MODULES_H_INCLUDED
#define MODULES_H_INCLUDED 1
+#include "objomsr.h"
+
typedef enum eModType_ {
eMOD_IN, /* input module */
eMOD_OUT, /* output module */
@@ -77,8 +79,8 @@ typedef struct moduleInfo {
struct {/* data for output modules */
/* below: perform the configured action
*/
- rsRetVal (*doAction)(selector_t*, uchar*, void*);
- rsRetVal (*parseSelectorAct)(uchar**, selector_t*, void**);
+ rsRetVal (*doAction)(selector_t*, uchar**, unsigned, void*);
+ rsRetVal (*parseSelectorAct)(uchar**, selector_t*, void**,omodStringRequest_t**);
} om;
} mod;
} modInfo_t;
diff --git a/objomsr.c b/objomsr.c
index 85aaee95..00e5e668 100644
--- a/objomsr.c
+++ b/objomsr.c
@@ -101,6 +101,7 @@ rsRetVal OMSRsetEntry(omodStringRequest_t *pThis, int iEntry, uchar *pTplName, i
assert(pTplName != NULL);
assert(iEntry < pThis->iNumEntries);
+printf("OMSRsetEntry %s: %d\n", pTplName, iTplOpts);
if(pThis->ppTplName[iEntry] != NULL)
free(pThis->ppTplName[iEntry]);
pThis->ppTplName[iEntry] = pTplName; /* TODO: do we need to copy? */
@@ -135,7 +136,7 @@ int OMSRgetEntry(omodStringRequest_t *pThis, int iEntry, uchar **ppTplName, int
*ppTplName = pThis->ppTplName[iEntry];
*piTplOpts = pThis->piTplOpts[iEntry];
- return pThis->iNumEntries;
+ return RS_RET_OK;
}
/*
* vi:set ai:
diff --git a/objomsr.h b/objomsr.h
index c84b2870..f6eae475 100644
--- a/objomsr.h
+++ b/objomsr.h
@@ -22,10 +22,15 @@
#ifndef OBJOMSR_H_INCLUDED
#define OBJOMSR_H_INCLUDED
+/* define flags for required template options */
+#define OMSR_NO_RQD_TPL_OPTS 0
+#define OMSR_RQD_TPL_OPT_SQL 1
+/* next option is 2, 4, 8, ... */
+
struct omodStringRequest_s { /* strings requested by output module for doAction() */
int iNumEntries; /* number of array entries for data elements below */
uchar **ppTplName; /* pointer to array of template names */
- int *piTplOpts; /* pointer to array of check-options when pulling template */
+ int *piTplOpts;/* pointer to array of check-options when pulling template */
};
typedef struct omodStringRequest_s omodStringRequest_t;
diff --git a/omdiscard.c b/omdiscard.c
index 54eab33d..3a29d2d3 100644
--- a/omdiscard.c
+++ b/omdiscard.c
@@ -76,6 +76,7 @@ ENDfreeInstance
BEGINparseSelectorAct
CODESTARTparseSelectorAct
+CODE_STD_STRING_REQUESTparseSelectorAct(0)
pData = NULL; /* this action does not have any instance data */
p = *pp;
diff --git a/omfile.c b/omfile.c
index 701e96e9..13e436bf 100644
--- a/omfile.c
+++ b/omfile.c
@@ -96,13 +96,13 @@ ENDisCompatibleWithFeature
BEGINdbgPrintInstInfo
CODESTARTdbgPrintInstInfo
if(pData->bDynamicName) {
- printf("[dynamic]\n\ttemplate='%s'\n"
+ printf("[dynamic]\n\ttemplate='%s'"
"\tfile cache size=%d\n"
"\tcreate directories: %s\n"
"\tfile owner %d, group %d\n"
"\tdirectory owner %d, group %d\n"
"\tfail if owner/group can not be set: %s\n",
- pData->f_fname,
+ pData->f_fname,
pData->iDynaFileCacheSize,
pData->bCreateDirs ? "yes" : "no",
pData->fileUID, pData->fileGID,
@@ -125,7 +125,7 @@ ENDdbgPrintInstInfo
* removed.
* rgerhards 2005-06-21
*/
-static rsRetVal cflineParseOutchannel(selector_t *f, instanceData *pData, uchar* p)
+static rsRetVal cflineParseOutchannel(instanceData *pData, uchar* p, omodStringRequest_t *pOMSR, int iEntry, int iTplOpts)
{
rsRetVal iRet = RS_RET_OK;
size_t i;
@@ -189,16 +189,7 @@ static rsRetVal cflineParseOutchannel(selector_t *f, instanceData *pData, uchar*
if(*p == ';')
++p; /* eat it */
- if((iRet = cflineParseTemplateName(&p, szBuf,
- sizeof(szBuf) / sizeof(char))) == RS_RET_OK) {
- if(szBuf[0] == '\0') /* no template? */
- strcpy(szBuf, " TradFmt"); /* use default! */
-
- iRet = cflineSetTemplateAndIOV(f, szBuf);
-
- dprintf("[outchannel]filename: '%s', template: '%s', size: %lu\n", pData->f_fname, szBuf,
- pData->f_sizeLimit);
- }
+ iRet = cflineParseTemplateName(&p, pOMSR, iEntry, iTplOpts, (uchar*) " TradFmt");
return(iRet);
}
@@ -309,33 +300,24 @@ static void dynaFileFreeCache(instanceData *pData)
}
-/* This function handles dynamic file names. It generates a new one
- * based on the current message, checks if that file is already open
- * and, if not, does everything needed to switch to the new one.
+/* This function handles dynamic file names. It checks if the
+ * requested file name is already open and, if not, does everything
+ * needed to switch to the it.
* Function returns 0 if all went well and non-zero otherwise.
* On successful return pData->fd must point to the correct file to
* be written.
* This is a helper to writeFile(). rgerhards, 2007-07-03
*/
-static int prepareDynFile(selector_t *f, instanceData *pData)
+static int prepareDynFile(instanceData *pData, uchar *newFileName, unsigned iMsgOpts)
{
- uchar *newFileName;
time_t ttOldest; /* timestamp of oldest element */
int iOldest;
int i;
int iFirstFree;
dynaFileCacheEntry **pCache;
- assert(f != NULL);
assert(pData != NULL);
- if((newFileName = tplToString(pData->pTpl, f->f_pMsg)) == NULL) {
- /* memory shortage - there is nothing we can do to resolve it.
- * We silently ignore it, this is probably the best we can do.
- */
- glblHadMemShortage = TRUE;
- dprintf("prepareDynfile(): could not create file name, discarding this request\n");
- return -1;
- }
+ assert(newFileName != NULL);
pCache = pData->dynCache;
@@ -343,10 +325,8 @@ static int prepareDynFile(selector_t *f, instanceData *pData)
* I *hope* this will be a performance enhancement.
*/
if( (pData->iCurrElt != -1)
- && !strcmp((char*) newFileName,
- (char*) pCache[pData->iCurrElt])) {
+ && !strcmp((char*) newFileName, (char*) pCache[pData->iCurrElt])) {
/* great, we are all set */
- free(newFileName);
pCache[pData->iCurrElt]->lastUsed = time(NULL); /* update timestamp for LRU */
return 0;
}
@@ -366,7 +346,6 @@ static int prepareDynFile(selector_t *f, instanceData *pData)
/* we found our element! */
pData->fd = pCache[i]->fd;
pData->iCurrElt = i;
- free(newFileName);
pCache[i]->lastUsed = time(NULL); /* update timestamp for LRU */
return 0;
}
@@ -393,7 +372,6 @@ static int prepareDynFile(selector_t *f, instanceData *pData)
if(pCache[iFirstFree] == NULL) {
glblHadMemShortage = TRUE;
dprintf("prepareDynfile(): could not alloc mem, discarding this request\n");
- free(newFileName);
return -1;
}
}
@@ -443,17 +421,16 @@ static int prepareDynFile(selector_t *f, instanceData *pData)
* message. Otherwise, we could run into a never-ending loop. The bad
* news is that we also lose errors on startup messages, but so it is.
*/
- if(f->f_pMsg->msgFlags & INTERNAL_MSG)
+ if(iMsgOpts & INTERNAL_MSG)
dprintf("Could not open dynaFile, discarding message\n");
else
logerrorSz("Could not open dynamic file '%s' - discarding message", (char*)newFileName);
- free(newFileName);
dynaFileDelCacheEntry(pCache, iFirstFree, 1);
return -1;
}
pCache[iFirstFree]->fd = pData->fd;
- pCache[iFirstFree]->pName = newFileName;
+ pCache[iFirstFree]->pName = (uchar*)strdup((char*)newFileName); /* TODO: check for NULL (very unlikely) */
pCache[iFirstFree]->lastUsed = time(NULL);
pData->iCurrElt = iFirstFree;
dprintf("Added new entry %d for file cache, file '%s'.\n",
@@ -467,7 +444,7 @@ static int prepareDynFile(selector_t *f, instanceData *pData)
* will be called for all outputs using file semantics,
* for example also for pipes.
*/
-static rsRetVal writeFile(selector_t *f, uchar *pMsg, instanceData *pData)
+static rsRetVal writeFile(selector_t *f, uchar **ppString, unsigned iMsgOpts, instanceData *pData)
{
off_t actualFileSize;
rsRetVal iRet = RS_RET_OK;
@@ -479,7 +456,7 @@ static rsRetVal writeFile(selector_t *f, uchar *pMsg, instanceData *pData)
* check if it still is ok or a new file needs to be created
*/
if(pData->bDynamicName) {
- if(prepareDynFile(f, pData) != 0)
+ if(prepareDynFile(pData, ppString[1], iMsgOpts) != 0)
return RS_RET_ERR;
}
@@ -516,7 +493,7 @@ again:
}
}
- if (write(pData->fd, pMsg, strlen((char*)pMsg)) < 0) {
+ if (write(pData->fd, ppString[0], strlen((char*)ppString[0])) < 0) {
int e = errno;
/* If a named pipe is full, just ignore it for now
@@ -598,7 +575,7 @@ CODESTARTdoAction
* all others are doomed.
*/
if(pData->bDynamicName || (pData->fd != -1))
- iRet = writeFile(f, pMsg, pData);
+ iRet = writeFile(f, ppString, iMsgOpts, pData);
ENDdoAction
@@ -628,6 +605,7 @@ CODESTARTparseSelectorAct
switch (*p)
{
case '$':
+ CODE_STD_STRING_REQUESTparseSelectorAct(1)
/* rgerhards 2005-06-21: this is a special setting for output-channel
* definitions. In the long term, this setting will probably replace
* anything else, but for the time being we must co-exist with the
@@ -635,7 +613,7 @@ CODESTARTparseSelectorAct
* rgerhards, 2007-07-24: output-channels will go away. We keep them
* for compatibility reasons, but seems to have been a bad idea.
*/
- if((iRet = cflineParseOutchannel(f, pData, p)) == RS_RET_OK) {
+ if((iRet = cflineParseOutchannel(pData, p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS)) == RS_RET_OK) {
pData->bDynamicName = 0;
pData->fCreateMode = fCreateMode; /* preserve current setting */
pData->fDirCreateMode = fDirCreateMode; /* preserve current setting */
@@ -647,16 +625,16 @@ CODESTARTparseSelectorAct
case '?': /* This is much like a regular file handle, but we need to obtain
* a template name. rgerhards, 2007-07-03
*/
+ CODE_STD_STRING_REQUESTparseSelectorAct(2)
++p; /* eat '?' */
- if((iRet = cflineParseFileName(f, p, (uchar*) pData->f_fname)) != RS_RET_OK)
+ if((iRet = cflineParseFileName(p, (uchar*) pData->f_fname, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS))
+ != RS_RET_OK)
break;
- pData->pTpl = tplFind((char*)pData->f_fname,
- strlen((char*) pData->f_fname));
- if(pData->pTpl == NULL) {
- logerrorSz("Template '%s' not found - dynaFile deactivated.", pData->f_fname);
- iRet = RS_RET_NOT_FOUND; /* that's it... :( */
+ /* "filename" is actually a template name, we need this as string 1. So let's add it
+ * to the pOMSR. -- rgerhards, 2007-07-27
+ */
+ if((iRet = OMSRsetEntry(*ppOMSR, 1, (uchar*)strdup(pData->f_fname), OMSR_NO_RQD_TPL_OPTS)) != RS_RET_OK)
break;
- }
pData->bDynamicName = 1;
pData->iCurrElt = -1; /* no current element */
@@ -681,6 +659,7 @@ CODESTARTparseSelectorAct
case '|':
case '/':
+ CODE_STD_STRING_REQUESTparseSelectorAct(1)
/* rgerhards, 2007-0726: first check if file or pipe */
if(*p == '|') {
pData->fileType = eTypePIPE;
@@ -693,7 +672,8 @@ CODESTARTparseSelectorAct
* to use is specified. So we need to scan for the first coma first
* and then look at the rest of the line.
*/
- if((iRet = cflineParseFileName(f, p, (uchar*) pData->f_fname)) != RS_RET_OK)
+ if((iRet = cflineParseFileName(p, (uchar*) pData->f_fname, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS))
+ != RS_RET_OK)
break;
pData->bDynamicName = 0;
@@ -736,7 +716,6 @@ CODESTARTmodInit
*ipIFVersProvided = 1; /* so far, we only support the initial definition */
ENDmodInit
-
/*
* vi:set ai:
*/
diff --git a/omfwd.c b/omfwd.c
index 84436381..83409201 100644
--- a/omfwd.c
+++ b/omfwd.c
@@ -602,7 +602,7 @@ CODESTARTdoAction
dprintf("Not sending message to remote.\n");
else {
pData->ttSuspend = time(NULL);
- psz = (char*) pMsg;
+ psz = (char*) ppString[0];
l = strlen((char*) psz);
if (l > MAXLINE)
l = MAXLINE;
@@ -710,10 +710,8 @@ BEGINparseSelectorAct
int error;
int bErr;
struct addrinfo hints, *res;
- char szTemplateName[128];
CODESTARTparseSelectorAct
- p = *pp;
-
+CODE_STD_STRING_REQUESTparseSelectorAct(1)
if(*p == '@') {
if((iRet = createInstance(&pData)) != RS_RET_OK)
return iRet;
@@ -828,21 +826,20 @@ CODESTARTparseSelectorAct
++p;
}
+ /* TODO: make this if go away! */
if(*p == ';') {
*p = '\0'; /* trick to obtain hostname (later)! */
- ++p;
- /* Now look for the template! */
- cflineParseTemplateName(&p, szTemplateName,
- sizeof(szTemplateName) / sizeof(char));
+ strcpy(pData->f_hname, (char*) q);
+ *p = ';';
} else
- szTemplateName[0] = '\0';
- if(szTemplateName[0] == '\0') {
- /* we do not have a template, so let's use the default */
- strcpy(szTemplateName, " StdFwdFmt");
- }
+ strcpy(pData->f_hname, (char*) q);
+
+ /* process template */
+ if((iRet = cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, (uchar*) " StdFwdFmt"))
+ != RS_RET_OK)
+ return iRet;
/* first set the pData->eDestState */
- strcpy(pData->f_hname, (char*) q);
memset(&hints, 0, sizeof(hints));
/* port must be numeric, because config file syntax requests this */
hints.ai_flags = AI_NUMERICSERV;
@@ -857,12 +854,6 @@ CODESTARTparseSelectorAct
pData->f_addr = res;
}
- /* then try to find the template */
- if((iRet = cflineSetTemplateAndIOV(f, szTemplateName)) == RS_RET_OK) {
- dprintf("forwarding host: '%s:%s/%s' template '%s'\n", q, getFwdSyslogPt(pData),
- pData->protocol == FORW_UDP ? "udp" : "tcp",
- szTemplateName);
- }
/*
* Otherwise the host might be unknown due to an
* inaccessible nameserver (perhaps on the same
diff --git a/ommysql.c b/ommysql.c
index 67803b5c..d5c327c1 100644
--- a/ommysql.c
+++ b/ommysql.c
@@ -321,16 +321,14 @@ rsRetVal writeMySQL(register selector_t *f, uchar *psz, instanceData *pData)
BEGINdoAction
CODESTARTdoAction
dprintf("\n");
- iRet = writeMySQL(f, pMsg, pData);
+ iRet = writeMySQL(f, ppString[0], pData);
ENDdoAction
BEGINparseSelectorAct
int iMySQLPropErr = 0;
- char szTemplateName[128];
CODESTARTparseSelectorAct
- p = *pp;
-
+CODE_STD_STRING_REQUESTparseSelectorAct(1)
/* yes, the if below is redundant, but I need it now. Will go away as
* the code further changes. -- rgerhards, 2007-07-25
*/
@@ -341,8 +339,7 @@ CODESTARTparseSelectorAct
switch (*p)
{
- case '>':
- /* rger 2004-10-28: added support for MySQL
+ case '>': /* rger 2004-10-28: added support for MySQL
* >server,dbname,userid,password
* rgerhards 2005-08-12: changed rsyslogd so that
* if no DB is selected and > is used, an error
@@ -376,34 +373,15 @@ CODESTARTparseSelectorAct
iMySQLPropErr++;
if(getSubString(&p, pData->f_dbpwd, _DB_MAXPWDLEN+1, ';'))
iMySQLPropErr++;
- if(*p == '\n' || *p == '\0') {
- /* assign default format if none given! */
- szTemplateName[0] = '\0';
- } else {
- /* we have a template specifier! */
- if((iRet = cflineParseTemplateName(&p, szTemplateName,
- sizeof(szTemplateName) / sizeof(char))) != RS_RET_OK)
- break;
- }
-
- if(szTemplateName[0] == '\0')
- strcpy(szTemplateName, " StdDBFmt");
-
- if((iRet = cflineSetTemplateAndIOV(f, szTemplateName)) != RS_RET_OK)
- break;
-
- dprintf(" template '%s'\n", szTemplateName);
-
- /* If db used, the template have to use the SQL option.
- This is for your own protection (prevent sql injection). */
- if (f->f_pTpl->optFormatForSQL == 0) {
- iRet = RS_RET_NO_SQL_STRING;
- logerror("DB logging disabled. You have to use"
- " the SQL or stdSQL option in your template!\n");
- break;
- }
+ /* now check for template
+ * We specify that the SQL option must be present in the template.
+ * This is for your own protection (prevent sql injection).
+ */
+ if((iRet = cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_RQD_TPL_OPT_SQL, (uchar*) " StdSQLFmt"))
+ != RS_RET_OK)
+ return iRet;
- /* If we dedect invalid properties, we disable logging,
+ /* If we detect invalid properties, we disable logging,
* because right properties are vital at this place.
* Retries make no sense.
*/
diff --git a/omshell.c b/omshell.c
index efeb7bf7..5a25cc9f 100644
--- a/omshell.c
+++ b/omshell.c
@@ -81,14 +81,14 @@ CODESTARTdoAction
* rgerhards, 2007-07-20
*/
dprintf("\n");
- if(execProg((uchar*) pData->progName, 1, pMsg) == 0)
+ if(execProg((uchar*) pData->progName, 1, ppString[0]) == 0)
logerrorSz("Executing program '%s' failed", (char*)pData->progName);
ENDdoAction
BEGINparseSelectorAct
CODESTARTparseSelectorAct
- p = *pp;
+CODE_STD_STRING_REQUESTparseSelectorAct(1)
/* yes, the if below is redundant, but I need it now. Will go away as
* the code further changes. -- rgerhards, 2007-07-25
*/
@@ -103,7 +103,7 @@ CODESTARTparseSelectorAct
case '^': /* bkalkbrenner 2005-09-20: execute shell command */
dprintf("exec\n");
++p;
- iRet = cflineParseFileName(f, p, (uchar*) pData->progName);
+ iRet = cflineParseFileName(p, (uchar*) pData->progName, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS);
break;
default:
iRet = RS_RET_CONFLINE_UNPROCESSED;
diff --git a/omusrmsg.c b/omusrmsg.c
index 3c47fb8d..96b18375 100644
--- a/omusrmsg.c
+++ b/omusrmsg.c
@@ -247,15 +247,15 @@ BEGINdoAction
CODESTARTdoAction
dprintf("\n");
/* TODO: change wallmsg so that it returns iRet */
- wallmsg(f, pMsg, pData);
+ wallmsg(f, ppString[0], pData);
ENDdoAction
BEGINparseSelectorAct
uchar *q;
int i;
- char szTemplateName[128];
CODESTARTparseSelectorAct
+CODE_STD_STRING_REQUESTparseSelectorAct(1)
#if 0 /* TODO: think about it and activate later - see comments in else below */
if(**pp != '*')
@@ -267,20 +267,11 @@ CODESTARTparseSelectorAct
if(*p == '*') { /* wall */
dprintf ("write-all");
+ ++p; /* eat '*' */
pData->bIsWall = 1; /* write to all users */
- if(*(p+1) == ';') {
- /* we have a template specifier! */
- p += 2; /* eat "*;" */
- if((iRet = cflineParseTemplateName(&p, szTemplateName,
- sizeof(szTemplateName) / sizeof(uchar))) != RS_RET_OK)
- return iRet;
- }
- else /* assign default format if none given! */
- szTemplateName[0] = '\0';
- if(szTemplateName[0] == '\0')
- strcpy(szTemplateName, " WallFmt");
- if((iRet = cflineSetTemplateAndIOV(f, szTemplateName)) == RS_RET_OK)
- dprintf(" template '%s'\n", szTemplateName);
+ if((iRet = cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, (uchar*) " WallFmt"))
+ != RS_RET_OK)
+ return iRet;
} else {
/* everything else is currently treated as a user name
* TODO: we must reconsider this - see also comment in
@@ -300,26 +291,13 @@ CODESTARTparseSelectorAct
q++;
p = q;
}
- /* done, now check if we have a template name
+ /* done, on to the template
* TODO: we need to handle the case where i >= MAXUNAME!
*/
- szTemplateName[0] = '\0';
- if(*p == ';') {
- /* we have a template specifier! */
- ++p; /* eat ";" */
- if((iRet = cflineParseTemplateName(&p, szTemplateName,
- sizeof(szTemplateName) / sizeof(char))) != RS_RET_OK)
- return iRet;
- }
- if(szTemplateName[0] == '\0')
- strcpy(szTemplateName, " StdUsrMsgFmt");
- iRet = cflineSetTemplateAndIOV(f, szTemplateName);
- /* NOTE: if you intend to do anything else here, be sure to
- * chck iRet - as we currently have nothing else to do, we do not
- * care (yet).
- */
+ if((iRet = cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, (uchar*)" StdUsrMsgFmt"))
+ != RS_RET_OK)
+ return iRet;
}
-
ENDparseSelectorAct
diff --git a/rsyslog.h b/rsyslog.h
index 560e0f10..149e589c 100644
--- a/rsyslog.h
+++ b/rsyslog.h
@@ -58,6 +58,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth
RS_RET_NO_SQL_STRING = -2005, /**< string is not suitable for use as SQL */
RS_RET_DISABLE_ACTION = -2006, /**< action requests that it be disabled */
RS_RET_SUSPENDED = -2007, /**< something was suspended, not neccesarily an error */
+ RS_RET_RQD_TPLOPT_MISSING = -2008,/**< a required template option is missing */
RS_RET_OK = 0 /**< operation successful */
};
typedef enum rsRetVal_ rsRetVal; /**< friendly type for global return value */
diff --git a/syslogd-types.h b/syslogd-types.h
index 1792f509..9aff6c88 100644
--- a/syslogd-types.h
+++ b/syslogd-types.h
@@ -161,6 +161,7 @@ struct filed {
int iNumTpls; /* number of array entries for template element below */
struct template **ppTpl; /* array of template to use - strings must be passed to doAction
* in this order. */
+ uchar **ppMsgs; /* array of message pointers for doAction */
struct template __attribute__((deprecated)) *f_pTpl; /* pointer to template to use */
struct msg* f_pMsg; /* pointer to the message (this will
* replace the other vars with msg
diff --git a/syslogd.c b/syslogd.c
index e46adffe..fb697046 100644
--- a/syslogd.c
+++ b/syslogd.c
@@ -3059,8 +3059,8 @@ rsRetVal fprintlog(register selector_t *f)
msg_t *pMsgSave; /* to save current message pointer, necessary to restore
it in case it needs to be updated (e.g. repeated msgs) */
pMsgSave = NULL; /* indicate message poiner not saved */
- uchar *pszMsg;
rsRetVal iRet = RS_RET_OK;
+ int i;
/* first check if this is a regular message or the repeation of
* a previous message. If so, we need to change the message text
@@ -3102,14 +3102,17 @@ rsRetVal fprintlog(register selector_t *f)
/* When we reach this point, we have a valid, non-disabled action.
* So let's execute it. -- rgerhards, 2007-07-24
*/
- if((pszMsg = tplToString(f->f_pTpl, f->f_pMsg)) == NULL) {
- dprintf("memory alloc failed while generating message string - message ignored\n");
- glblHadMemShortage = 1;
- iRet = RS_RET_OUT_OF_MEMORY;
- } else {
- iRet = f->pMod->mod.om.doAction(f, pszMsg, f->pModData); /* call configured action */
- free(pszMsg);
+ /* here we must loop to process all requested strings */
+
+ for(i = 0 ; i < f->iNumTpls ; ++i) {
+ if((f->ppMsgs[i] = tplToString(f->ppTpl[i], f->f_pMsg)) == NULL) {
+ dprintf("memory alloc failed while generating message strings - message ignored\n");
+ glblHadMemShortage = 1;
+ iRet = RS_RET_OUT_OF_MEMORY;
+ goto finalize_it;
+ }
}
+ iRet = f->pMod->mod.om.doAction(f, f->ppMsgs, f->f_pMsg->msgFlags, f->pModData); /* call configured action */
if(iRet == RS_RET_DISABLE_ACTION)
f->bEnabled = 0; /* that's it... */
@@ -3117,6 +3120,15 @@ rsRetVal fprintlog(register selector_t *f)
if(iRet == RS_RET_OK)
f->f_prevcount = 0; /* message process, so we start a new cycle */
+finalize_it:
+ /* cleanup */
+ for(i = 0 ; i < f->iNumTpls ; ++i) {
+ if(f->ppMsgs[i] != NULL) {
+ free(f->ppMsgs[i]);
+ f->ppMsgs[i] = NULL;
+ }
+ }
+
if(pMsgSave != NULL) {
/* we had saved the original message pointer. That was
* done because we needed to create a temporary one
@@ -3803,7 +3815,7 @@ void cfsysline(uchar *p)
assert(p != NULL);
errno = 0;
- dprintf("cfsysline --> %s", p);
+ dprintf("cfsysline --> %s\n", p);
if(getSubString(&p, (char*) szCmd, sizeof(szCmd) / sizeof(uchar), ' ') != 0) {
logerror("Invalid $-configline - could not extract command - line ignored\n");
return;
@@ -3899,6 +3911,11 @@ static void freeSelectors(void)
if(f->f_pMsg != NULL)
MsgDestruct(f->f_pMsg);
+
+ if(f->ppTpl != NULL)
+ free(f->ppTpl);
+ if(f->ppMsgs != NULL)
+ free(f->ppMsgs);
/* done with this entry, we now need to delete itself */
fPrev = f;
f = f->f_next;
@@ -4025,6 +4042,10 @@ static void init()
#else
while (fgets(cline, sizeof(cline), cf) != NULL) {
#endif
+ /* drop LF - TODO: make it better, replace fgets(), but its clean as it is */
+ if(cline[strlen(cline)-1] == '\n') {
+ cline[strlen(cline) -1] = '\0';
+ }
/*
* check for end-of-section, comments, strip off trailing
* spaces and newline character.
@@ -4238,67 +4259,65 @@ static void init()
dprintf(" restarted.\n");
}
-/* helper to cfline() and its helpers. Assign the right template
- * to a filed entry and allocates memory for its iovec.
- * rgerhards 2004-11-19
- */
-rsRetVal cflineSetTemplateAndIOV(selector_t *f, char *pTemplateName)
-{
- rsRetVal iRet = RS_RET_OK;
- char errMsg[512];
- assert(f != NULL);
- assert(pTemplateName != NULL);
-
- /* Ok, we got everything, so it now is time to look up the
- * template (Hint: templates MUST be defined before they are
- * used!) and initialize the pointer to it PLUS the iov
- * pointer. We do the later because the template tells us
- * how many elements iov must have - and this can never change.
- */
- if((f->f_pTpl = tplFind(pTemplateName, strlen(pTemplateName))) == NULL) {
- snprintf(errMsg, sizeof(errMsg) / sizeof(char),
- " Could not find template '%s' - selector line disabled\n",
- pTemplateName);
- errno = 0;
- logerror(errMsg);
- iRet = RS_RET_NOT_FOUND;
- }
- return iRet;
-}
-
/* 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.
- * Everything is stored in the filed struct. If there is no
- * template name (it is empty), than it is ensured that the
- * returned string is "\0". So you can count on the first character
- * to be \0 in this case.
* rgerhards 2004-11-19
+ * changed function to work with OMSR. -- rgerhards, 2007-07-27
+ * the default template is to be used when no template is specified.
*/
-rsRetVal cflineParseTemplateName(uchar** pp,
- register char* pTemplateName, int iLenTemplate)
+rsRetVal cflineParseTemplateName(uchar** pp, omodStringRequest_t *pOMSR, int iEntry, int iTplOpts, uchar *dfltTplName)
{
- register uchar *p;
+ uchar *p;
+ uchar *tplName;
rsRetVal iRet = RS_RET_OK;
- int i;
+ rsCStrObj *pStrB;
assert(pp != NULL);
assert(*pp != NULL);
+ assert(pOMSR != NULL);
+dprintf("cflineParsetTemplateName opts: %d\n", iTplOpts);
p =*pp;
+ /* a template must follow - search it and complain, if not found
+ */
+ skipWhiteSpace(&p);
+ if(*p == ';')
+ ++p; /* eat it */
+ else if(*p != '\0' && *p != '#') {
+ logerror("invalid character in selector line - ';template' expected");
+ iRet = RS_RET_ERR;
+ goto finalize_it;
+ }
- /* Just as a general precaution, we skip whitespace. */
- while(*p && isspace((int) *p))
- ++p;
+ skipWhiteSpace(&p); /* go to begin of template name */
- i = 1; /* we start at 1 so that we reserve space for the '\0'! */
- while(*p && i < iLenTemplate) {
- *pTemplateName++ = *p++;
- ++i;
+ if(*p == '\0') {
+ /* no template specified, use the default */
+ /* TODO: check NULL ptr */
+ tplName = (uchar*) strdup((char*)dfltTplName);
+ } else {
+ /* template specified, pick it up */
+ if((pStrB = rsCStrConstruct()) == NULL) {
+ glblHadMemShortage = 1;
+ iRet = RS_RET_OUT_OF_MEMORY;
+ goto finalize_it;
+ }
+
+ /* now copy the string */
+ while(*p && *p != '#' && !isspace((int) *p)) {
+ if((iRet = rsCStrAppendChar(pStrB, *p)) != RS_RET_OK) goto finalize_it;
+ ++p;
+ }
+ if((iRet = rsCStrFinish(pStrB)) != RS_RET_OK) goto finalize_it;
+ tplName = rsCStrConvSzStrAndDestruct(pStrB);
}
- *pTemplateName = '\0';
+ iRet = OMSRsetEntry(pOMSR, iEntry, tplName, iTplOpts);
+ if(iRet != RS_RET_OK) goto finalize_it;
+
+finalize_it:
*pp = p;
return iRet;
@@ -4306,19 +4325,20 @@ rsRetVal cflineParseTemplateName(uchar** pp,
/* Helper to cfline(). Parses a file name up until the first
* comma and then looks for the template specifier. Tries
- * to find that template. Everything is stored in the
- * filed struct.
+ * to find that template.
* rgerhards 2004-11-18
* parameter pFileName must point to a buffer large enough
* to hold the largest possible filename.
* rgerhards, 2007-07-25
+ * updated to include OMSR pointer -- rgerhards, 2007-07-27
*/
-rsRetVal cflineParseFileName(selector_t *f, uchar* p, uchar *pFileName)
+rsRetVal cflineParseFileName(uchar* p, uchar *pFileName, omodStringRequest_t *pOMSR, int iEntry, int iTplOpts)
{
register uchar *pName;
int i;
rsRetVal iRet = RS_RET_OK;
- char szTemplateName[128]; /* should be more than sufficient */
+
+ assert(pOMSR != NULL);
pName = pFileName;
i = 1; /* we start at 1 so that we reseve space for the '\0'! */
@@ -4328,23 +4348,7 @@ rsRetVal cflineParseFileName(selector_t *f, uchar* p, uchar *pFileName)
}
*pName = '\0';
- /* got the file name - now let's look for the template to use
- * Just as a general precaution, we skip whitespace.
- */
- while(*p && isspace((int) *p))
- ++p;
- if(*p == ';')
- ++p; /* eat it */
-
- if((iRet = cflineParseTemplateName(&p, szTemplateName,
- sizeof(szTemplateName) / sizeof(char))) != RS_RET_OK)
- return iRet;
-
- if(szTemplateName[0] == '\0') /* no template? */
- strcpy(szTemplateName, " TradFmt"); /* use default! */
-
- if((iRet = cflineSetTemplateAndIOV(f, szTemplateName)) == RS_RET_OK)
- dprintf("filename: '%s', template: '%s'\n", pFileName, szTemplateName);
+ iRet = cflineParseTemplateName(&p, pOMSR, iEntry, iTplOpts, (uchar*) " TradFmt");
return iRet;
}
@@ -4711,8 +4715,95 @@ static rsRetVal cflineProcessTagSelector(uchar **pline)
}
+/* add an Action to the current selector
+ * The pOMSR is freed, as it is not needed after this function.
+ * rgerhards, 2007-07-27
+ */
+rsRetVal addAction(selector_t *f, modInfo_t *pMod, void *pModData, omodStringRequest_t *pOMSR)
+{
+ rsRetVal iRet = RS_RET_OK;
+ int i;
+ int iTplOpts;
+ uchar *pTplName;
+ char errMsg[512];
+
+ assert(f != NULL);
+ assert(pMod != NULL);
+ assert(pOMSR != NULL);
+ dprintf("Module %s processed this config line.\n", modGetName(pMod));
+
+ /* check if we can obtain the template pointers - TODO: move to separat function? */
+ f->iNumTpls = OMSRgetEntryCount(pOMSR);
+ /* we first need to create the template pointer array */
+ if((f->ppTpl = calloc(1, sizeof(struct template *))) == NULL) {
+ iRet = RS_RET_OUT_OF_MEMORY;
+ glblHadMemShortage = 1;
+ goto finalize_it;
+ }
+ /* and now the array for doAction() message pointers */
+ if((f->ppMsgs = calloc(1, sizeof(uchar *))) == NULL) {
+ iRet = RS_RET_OUT_OF_MEMORY;
+ glblHadMemShortage = 1;
+ goto finalize_it;
+ }
+
+ for(i = 0 ; i < f->iNumTpls ; ++i) {
+ if((iRet = OMSRgetEntry(pOMSR, i, &pTplName, &iTplOpts)) != RS_RET_OK) goto finalize_it;
+ /* Ok, we got everything, so it now is time to look up the
+ * template (Hint: templates MUST be defined before they are
+ * used!)
+ */
+ if((f->ppTpl[i] = tplFind((char*)pTplName, strlen((char*)pTplName))) == NULL) {
+ snprintf(errMsg, sizeof(errMsg) / sizeof(char),
+ " Could not find template '%s' - selector line disabled\n",
+ pTplName);
+ errno = 0;
+ logerror(errMsg);
+ iRet = RS_RET_NOT_FOUND;
+ goto finalize_it;
+ }
+ /* check required template options */
+dprintf("iTplOpts %d, check %d\n", iTplOpts, OMSR_RQD_TPL_OPT_SQL);
+ if( (iTplOpts & OMSR_RQD_TPL_OPT_SQL)
+ && (f->ppTpl[i]->optFormatForSQL == 0)) {
+ errno = 0;
+ logerror("Selector disabled. To use this action, you have to specify "
+ "the SQL or stdSQL option in your template!\n");
+ iRet = RS_RET_RQD_TPLOPT_MISSING;
+ goto finalize_it;
+ }
+
+ dprintf("template: '%s' assgined\n", pTplName);
+ /* TODO: generate macro CHKiRet((code));? */
+ }
+
+ f->pMod = pMod;
+ f->pModData = pModData;
+ /* now check if the module is compatible with select features */
+ if(pMod->isCompatibleWithFeature(sFEATURERepeatedMsgReduction) == RS_RET_OK)
+ f->f_ReduceRepeated = bReduceRepeatMsgs;
+ else {
+ dprintf("module is incompatible with RepeatedMsgReduction - turned off\n");
+ f->f_ReduceRepeated = 0;
+ }
+ f->bEnabled = 1; /* action is enabled */
+
+finalize_it:
+ if(iRet == RS_RET_OK)
+ iRet = OMSRdestruct(pOMSR);
+ else {
+ /* do not overwrite error state! */
+ OMSRdestruct(pOMSR);
+ /* TODO: free pMod instance data, potential mem leak */
+ /* TODO: better said - where is the selector_t AND its elements destroyed? */
+ }
+
+ return iRet;
+}
+
+
/*
- * Crack a configuration file line
+ * Cranck a configuration file line
* rgerhards 2004-11-17: well, I somewhat changed this function. It now does NOT
* handle config lines in general, but only lines that reflect actual filter
* pairs (the original syslog message line format). Extended lines (those starting
@@ -4727,6 +4818,7 @@ static rsRetVal cfline(char *line, register selector_t *f)
uchar *p;
rsRetVal iRet;
modInfo_t *pMod;
+ omodStringRequest_t *pOMSR;
void *pModData;
dprintf("cfline(%s)", line);
@@ -4776,9 +4868,10 @@ static rsRetVal cfline(char *line, register selector_t *f)
/* loop through all modules and see if one picks up the line */
pMod = omodGetNxt(NULL);
while(pMod != NULL) {
- iRet = pMod->mod.om.parseSelectorAct(&p , f, &pModData);
+ iRet = pMod->mod.om.parseSelectorAct(&p , f, &pModData, &pOMSR);
dprintf("trying selector action for %s: %d\n", modGetName(pMod), iRet);
if(iRet == RS_RET_OK) {
+ addAction(f, pMod, pModData, pOMSR);
dprintf("Module %s processed this config line.\n",
modGetName(pMod));
f->pMod = pMod;
diff --git a/syslogd.h b/syslogd.h
index afe177fd..b553d5fc 100644
--- a/syslogd.h
+++ b/syslogd.h
@@ -21,6 +21,7 @@
#define SYSLOGD_H_INCLUDED 1
#include "syslogd-types.h"
+#include "objomsr.h"
#ifdef USE_NETZIP
#include <zlib.h>
@@ -83,9 +84,8 @@ int formatTimestamp3164(struct syslogTime *ts, char* pBuf, size_t iLenBuf);
void iovCreate(selector_t *f);
char *iovAsString(selector_t *f);
void untty(void);
-rsRetVal cflineSetTemplateAndIOV(selector_t *f, char *pTemplateName);
-rsRetVal cflineParseTemplateName(uchar** pp, register char* pTemplateName, int iLenTemplate);
-rsRetVal cflineParseFileName(selector_t *f, uchar* p, uchar *pFileName);
+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);
int getSubString(uchar **ppSrc, char *pDst, size_t DstSize, char cSep);
extern int glblHadMemShortage; /* indicates if we had memory shortage some time during the run */