diff options
-rw-r--r-- | doc/imfile.html | 13 | ||||
-rw-r--r-- | plugins/imfile/imfile.c | 18 | ||||
-rw-r--r-- | runtime/stream.c | 16 | ||||
-rw-r--r-- | runtime/stream.h | 6 |
4 files changed, 42 insertions, 11 deletions
diff --git a/doc/imfile.html b/doc/imfile.html index a69f62e9..ab60373b 100644 --- a/doc/imfile.html +++ b/doc/imfile.html @@ -106,6 +106,14 @@ This mode should defined when having multiline messages. The value can range fro <br>0 (<strong>default</strong>) - line based (Each line is a new message) <br>1 - paragraph (There is a blank line between log messages) <br>2 - indented (New log messages start at the beginning of a line. If a line starts with a space it is part of the log message before it) +<li><b>escapeLF</b> [<b>on</b>/off]</b><br> +This is only meaningful if multi-line messages are to be processed. LF characters embedded into +syslog messages cause a lot of trouble, as most tools and even the legacy syslog TCP protocol +do not expect these. If set to "on", this option avoid this trouble by properly escaping +LF characters to the 4-byte sequence "#012". This is consistent with other rsyslog control character +escaping. By default, escaping is turned on. If you turn it off, make sure you test very carefully +with all associated tools. Please note that if you intend to use plain TCP syslog with embedded +LF characters, you need to enable octet-counted framing. <li><b>MaxLinesAtOnce</b> [number]</b> <br> This is useful if multiple files need to be monitored. If set to 0, each file @@ -160,6 +168,11 @@ input(type="imfile" File="/path/to/file2" <p><b>Legacy Configuration Directives</b>:</p> +<p>Note: in order to preserve compatibility with previous versions, the +LF escaping in multi-line messages is turned off for legacy-configured +file monitors (the "escapeLF" input parameter). This can cause serious problems. +So it is highly suggested that new deployments use the new input() statement +and keep LF escaping turned on. <ul> <li><strong>$InputFileName /path/to/file</strong><br> equivalent to: File </li> diff --git a/plugins/imfile/imfile.c b/plugins/imfile/imfile.c index 45882fb2..44209047 100644 --- a/plugins/imfile/imfile.c +++ b/plugins/imfile/imfile.c @@ -81,7 +81,8 @@ typedef struct fileInfo_s { int nRecords; /**< How many records did we process before persisting the stream? */ int iPersistStateInterval; /**< how often should state be persisted? (0=on close only) */ strm_t *pStrm; /* its stream (NULL if not assigned) */ - int readMode; /* which mode to use in ReadMulteLine call? */ + uint8_t readMode; /* which mode to use in ReadMulteLine call? */ + sbool escapeLF; /* escape LF inside the MSG content? */ ruleset_t *pRuleset; /* ruleset to bind listener to (use system default if unspecified) */ ratelimit_t *ratelimiter; multi_submit_t multiSub; @@ -110,7 +111,8 @@ struct instanceConf_s { int iPersistStateInterval; int iFacility; int iSeverity; - int readMode; + uint8_t readMode; + sbool escapeLF; int maxLinesAtOnce; ruleset_t *pBindRuleset; /* ruleset to bind listener to (use system default if unspecified) */ struct instanceConf_s *next; @@ -156,6 +158,7 @@ static struct cnfparamdescr inppdescr[] = { { "facility", eCmdHdlrFacility, 0 }, { "ruleset", eCmdHdlrString, 0 }, { "readmode", eCmdHdlrInt, 0 }, + { "escapelf", eCmdHdlrBinary, 0 }, { "maxlinesatonce", eCmdHdlrInt, 0 }, { "maxsubmitatonce", eCmdHdlrInt, 0 }, { "persiststateinterval", eCmdHdlrInt, 0 } @@ -168,6 +171,7 @@ static struct cnfparamblk inppblk = #include "im-helper.h" /* must be included AFTER the type definitions! */ + /* enqueue the read file line as a message. The provided string is * not freed - thuis must be done by the caller. */ @@ -295,7 +299,7 @@ static rsRetVal pollFile(fileInfo_t *pThis, int *pbHadFileData) while(glbl.GetGlobalInputTermState() == 0) { if(pThis->maxLinesAtOnce != 0 && nProcessed >= pThis->maxLinesAtOnce) break; - CHKiRet(strm.ReadLine(pThis->pStrm, &pCStr, pThis->readMode)); + CHKiRet(strm.ReadLine(pThis->pStrm, &pCStr, pThis->readMode, pThis->escapeLF)); ++nProcessed; *pbHadFileData = 1; /* this is just a flag, so set it and forget it */ CHKiRet(enqLine(pThis, pCStr)); /* process line */ @@ -341,6 +345,7 @@ createInstance(instanceConf_t **pinst) inst->maxLinesAtOnce = 10240; inst->iPersistStateInterval = 0; inst->readMode = 0; + inst->escapeLF = 1; /* node created, let's add to config */ if(loadModConf->tail == NULL) { @@ -389,6 +394,7 @@ static rsRetVal addInstance(void __attribute__((unused)) *pVal, uchar *pNewVal) inst->maxLinesAtOnce = cs.maxLinesAtOnce; inst->iPersistStateInterval = cs.iPersistStateInterval; inst->readMode = cs.readMode; + inst->escapeLF = 0; /* reset legacy system */ cs.iPersistStateInterval = 0; @@ -409,7 +415,6 @@ addListner(instanceConf_t *inst) if(iFilPtr < MAX_INPUT_FILES) { pThis = &files[iFilPtr]; - //TODO: optimize, save strdup? pThis->pszFileName = (uchar*) strdup((char*) inst->pszFileName); pThis->pszTag = (uchar*) strdup((char*) inst->pszTag); pThis->lenTag = ustrlen(pThis->pszTag); @@ -424,6 +429,7 @@ addListner(instanceConf_t *inst) pThis->maxLinesAtOnce = inst->maxLinesAtOnce; pThis->iPersistStateInterval = inst->iPersistStateInterval; pThis->readMode = inst->readMode; + pThis->escapeLF = inst->escapeLF; pThis->pRuleset = inst->pBindRuleset; pThis->nRecords = 0; } else { @@ -475,7 +481,9 @@ CODESTARTnewInpInst } else if(!strcmp(inppblk.descr[i].name, "facility")) { inst->iSeverity = pvals[i].val.d.n; } else if(!strcmp(inppblk.descr[i].name, "readmode")) { - inst->readMode = pvals[i].val.d.n; + inst->readMode = (uint8_t) pvals[i].val.d.n; + } else if(!strcmp(inppblk.descr[i].name, "escapelf")) { + inst->escapeLF = (sbool) pvals[i].val.d.n; } else if(!strcmp(inppblk.descr[i].name, "maxlinesatonce")) { inst->maxLinesAtOnce = pvals[i].val.d.n; } else if(!strcmp(inppblk.descr[i].name, "persiststateinterval")) { diff --git a/runtime/stream.c b/runtime/stream.c index 444a33ff..5ffbf10a 100644 --- a/runtime/stream.c +++ b/runtime/stream.c @@ -680,7 +680,7 @@ static rsRetVal strmUnreadChar(strm_t *pThis, uchar c) * destruction of the returned CStr object! -- dlang 2010-12-13 */ static rsRetVal -strmReadLine(strm_t *pThis, cstr_t **ppCStr, int mode) +strmReadLine(strm_t *pThis, cstr_t **ppCStr, uint8_t mode, sbool bEscapeLF) { /* mode = 0 single line mode (equivalent to ReadLine) * mode = 1 LFLF mode (paragraph, blank line between entries) @@ -690,6 +690,7 @@ strmReadLine(strm_t *pThis, cstr_t **ppCStr, int mode) uchar c; uchar finished; rsRetVal readCharRet; + sbool bPrevWasNL; DEFiRet; ASSERT(pThis != NULL); @@ -715,18 +716,25 @@ strmReadLine(strm_t *pThis, cstr_t **ppCStr, int mode) CHKiRet(cstrFinalize(*ppCStr)); } else if(mode == 1) { finished=0; + bPrevWasNL = 0; while(finished == 0){ if(c != '\n') { CHKiRet(cstrAppendChar(*ppCStr, c)); CHKiRet(strmReadChar(pThis, &c)); + bPrevWasNL = 0; } else { if ((((*ppCStr)->iStrLen) > 0) ){ - if ((*ppCStr)->pBuf[(*ppCStr)->iStrLen -1 ] == '\n'){ - rsCStrTruncate(*ppCStr,1); /* remove the prior newline */ + if(bPrevWasNL) { + rsCStrTruncate(*ppCStr, (bEscapeLF) ? 4 : 1); /* remove the prior newline */ finished=1; } else { - CHKiRet(cstrAppendChar(*ppCStr, c)); + if(bEscapeLF) { + CHKiRet(rsCStrAppendStrWithLen(*ppCStr, (uchar*)"#012", sizeof("#012")-1)); + } else { + CHKiRet(cstrAppendChar(*ppCStr, c)); + } CHKiRet(strmReadChar(pThis, &c)); + bPrevWasNL = 1; } } else { finished=1; /* this is a blank line, a \n with nothing since the last complete record */ diff --git a/runtime/stream.h b/runtime/stream.h index 4f4a4301..092d3226 100644 --- a/runtime/stream.h +++ b/runtime/stream.h @@ -66,6 +66,7 @@ #define STREAM_H_INCLUDED #include <pthread.h> +#include <stdint.h> #include "obj-types.h" #include "glbl.h" #include "stream.h" @@ -188,7 +189,7 @@ BEGINinterface(strm) /* name must also be changed in ENDinterface macro! */ INTERFACEpropSetMeth(strm, iFlushInterval, int); INTERFACEpropSetMeth(strm, pszSizeLimitCmd, uchar*); /* v6 added */ - rsRetVal (*ReadLine)(strm_t *pThis, cstr_t **ppCStr, int mode); + rsRetVal (*ReadLine)(strm_t *pThis, cstr_t **ppCStr, uint8_t mode, sbool bEscapeLF); /* v7 added 2012-09-14 */ INTERFACEpropSetMeth(strm, bVeryReliableZip, int); /* v8 added 2013-03-21 */ @@ -197,7 +198,8 @@ BEGINinterface(strm) /* name must also be changed in ENDinterface macro! */ INTERFACEpropSetMeth(strm, cryprov, cryprov_if_t*); INTERFACEpropSetMeth(strm, cryprovData, void*); ENDinterface(strm) -#define strmCURR_IF_VERSION 9 /* increment whenever you change the interface structure! */ +#define strmCURR_IF_VERSION 10 /* increment whenever you change the interface structure! */ +/* V10, 2013-09-10: added new parameter bEscapeLF, changed mode to uint8_t (rgerhards) */ static inline int strmGetCurrFileNum(strm_t *pStrm) { |