summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/imfile.html13
-rw-r--r--plugins/imfile/imfile.c18
-rw-r--r--runtime/stream.c16
-rw-r--r--runtime/stream.h6
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&nbsp;/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) {