summaryrefslogtreecommitdiffstats
path: root/plugins/imfile/imfile.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/imfile/imfile.c')
-rw-r--r--plugins/imfile/imfile.c144
1 files changed, 98 insertions, 46 deletions
diff --git a/plugins/imfile/imfile.c b/plugins/imfile/imfile.c
index 3981f9f7..cac3a55d 100644
--- a/plugins/imfile/imfile.c
+++ b/plugins/imfile/imfile.c
@@ -5,7 +5,7 @@
*
* Work originally begun on 2008-02-01 by Rainer Gerhards
*
- * Copyright 2008 Rainer Gerhards and Adiscon GmbH.
+ * Copyright 2008,2009 Rainer Gerhards and Adiscon GmbH.
*
* This file is part of rsyslog.
*
@@ -47,8 +47,11 @@
#include "datetime.h"
#include "unicode-helper.h"
#include "prop.h"
+#include "stringbuf.h"
+#include "ruleset.h"
MODULE_TYPE_INPUT /* must be present for input modules, do not remove */
+MODULE_TYPE_NOKEEP
/* defines */
@@ -59,6 +62,7 @@ DEFobjCurrIf(glbl)
DEFobjCurrIf(datetime)
DEFobjCurrIf(strm)
DEFobjCurrIf(prop)
+DEFobjCurrIf(ruleset)
typedef struct fileInfo_s {
uchar *pszFileName;
@@ -67,17 +71,27 @@ typedef struct fileInfo_s {
uchar *pszStateFile; /* file in which state between runs is to be stored */
int iFacility;
int iSeverity;
+ 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? */
+ ruleset_t *pRuleset; /* ruleset to bind listener to (use system default if unspecified) */
} fileInfo_t;
+/* forward definitions */
+static rsRetVal persistStrmState(fileInfo_t *pInfo);
+
/* config variables */
static uchar *pszFileName = NULL;
static uchar *pszFileTag = NULL;
static uchar *pszStateFile = NULL;
static int iPollInterval = 10; /* number of seconds to sleep when there was no file activity */
+static int iPersistStateInterval = 0; /* how often if state file to be persisted? (default 0->never) */
static int iFacility = 128; /* local0 */
static int iSeverity = 5; /* notice, as of rfc 3164 */
+static int readMode = 0; /* mode to use for ReadMultiLine call */
+static ruleset_t *pBindRuleset = NULL; /* ruleset to bind listener to (use system default if unspecified) */
static int iFilPtr = 0; /* number of files to be monitored; pointer to next free spot during config */
#define MAX_INPUT_FILES 100
@@ -107,7 +121,7 @@ static rsRetVal enqLine(fileInfo_t *pInfo, cstr_t *cstrLine)
MsgSetTAG(pMsg, pInfo->pszTag, pInfo->lenTag);
pMsg->iFacility = LOG_FAC(pInfo->iFacility);
pMsg->iSeverity = LOG_PRI(pInfo->iSeverity);
- pMsg->bParseHOSTNAME = 0;
+ MsgSetRuleset(pMsg, pInfo->pRuleset);
CHKiRet(submitMsg(pMsg));
finalize_it:
RETiRet;
@@ -154,10 +168,9 @@ openFile(fileInfo_t *pThis)
CHKiRet(strm.SeekCurrOffs(pThis->pStrm));
- /* OK, we could successfully read the file, so we now can request that it be deleted.
- * If we need it again, it will be written on the next shutdown.
+ /* note: we do not delete the state file, so that the last position remains
+ * known even in the case that rsyslogd aborts for some reason (like powerfail)
*/
- psSF->bDeleteOnClose = 1;
finalize_it:
if(psSF != NULL)
@@ -206,15 +219,19 @@ static rsRetVal pollFile(fileInfo_t *pThis, int *pbHadFileData)
}
/* loop below will be exited when strmReadLine() returns EOF */
- while(1) {
- CHKiRet(strm.ReadLine(pThis->pStrm, &pCStr));
+ while(glbl.GetGlobalInputTermState() == 0) {
+ CHKiRet(strm.ReadLine(pThis->pStrm, &pCStr, pThis->readMode));
*pbHadFileData = 1; /* this is just a flag, so set it and forget it */
CHKiRet(enqLine(pThis, pCStr)); /* process line */
rsCStrDestruct(&pCStr); /* discard string (must be done by us!) */
+ if(pThis->iPersistStateInterval > 0 && pThis->nRecords++ >= pThis->iPersistStateInterval) {
+ persistStrmState(pThis);
+ pThis->nRecords = 0;
+ }
}
finalize_it:
- /*EMPTY - just to keep the compiler happy, do NOT remove*/;
+ ; /*EMPTY STATEMENT - needed to keep compiler happy - see below! */
/* Note: the problem above is that pthread:cleanup_pop() is a macro which
* evaluates to something like "} while(0);". So the code would become
* "finalize_it: }", that is a label without a statement. The C standard does
@@ -244,27 +261,12 @@ finalize_it:
* IMPORTANT: the calling interface of this function can NOT be modified. It actually is
* called by pthreads. The provided argument is currently not being used.
*/
-/* ------------------------------------------------------------------------------------------ *
- * DO NOT TOUCH the following code - it will soon be part of the module generation macros! */
static void
inputModuleCleanup(void __attribute__((unused)) *arg)
{
BEGINfunc
-/* END no-touch zone *
- * ------------------------------------------------------------------------------------------ */
-
-
-
- /* so far not needed */
-
-
-
-/* ------------------------------------------------------------------------------------------ *
- * DO NOT TOUCH the following code - it will soon be part of the module generation macros! */
ENDfunc
}
-/* END no-touch zone *
- * ------------------------------------------------------------------------------------------ */
/* This function is called by the framework to gather the input. The module stays
@@ -292,30 +294,25 @@ BEGINrunInput
int i;
int bHadFileData; /* were there at least one file with data during this run? */
CODESTARTrunInput
- /* ------------------------------------------------------------------------------------------ *
- * DO NOT TOUCH the following code - it will soon be part of the module generation macros! */
pthread_cleanup_push(inputModuleCleanup, NULL);
- while(1) { /* endless loop - do NOT break; out of it! */
- /* END no-touch zone *
- * ------------------------------------------------------------------------------------------ */
-
- do {
- bHadFileData = 0;
- for(i = 0 ; i < iFilPtr ; ++i) {
- pollFile(&files[i], &bHadFileData);
- }
- } while(iFilPtr > 1 && bHadFileData == 1); /* waring: do...while()! */
-
- /* Note: the additional 10ns wait is vitally important. It guards rsyslog against totally
- * hogging the CPU if the users selects a polling interval of 0 seconds. It doesn't hurt any
- * other valid scenario. So do not remove. -- rgerhards, 2008-02-14
- */
- srSleep(iPollInterval, 10);
-
- /* ------------------------------------------------------------------------------------------ *
- * DO NOT TOUCH the following code - it will soon be part of the module generation macros! */
+ while(glbl.GetGlobalInputTermState() == 0) {
+ do {
+ bHadFileData = 0;
+ for(i = 0 ; i < iFilPtr ; ++i) {
+ if(glbl.GetGlobalInputTermState() == 1)
+ break; /* terminate input! */
+ pollFile(&files[i], &bHadFileData);
+ }
+ } while(iFilPtr > 1 && bHadFileData == 1 && glbl.GetGlobalInputTermState() == 0); /* warning: do...while()! */
+
+ /* Note: the additional 10ns wait is vitally important. It guards rsyslog against totally
+ * hogging the CPU if the users selects a polling interval of 0 seconds. It doesn't hurt any
+ * other valid scenario. So do not remove. -- rgerhards, 2008-02-14
+ */
+ if(glbl.GetGlobalInputTermState() == 0)
+ srSleep(iPollInterval, 10);
}
- /*NOTREACHED*/
+ DBGPRINTF("imfile: terminating upon request of rsyslog core\n");
pthread_cleanup_pop(0); /* just for completeness, but never called... */
RETiRet; /* use it to make sure the housekeeping is done! */
@@ -334,6 +331,11 @@ ENDrunInput
*/
BEGINwillRun
CODESTARTwillRun
+ /* free config variables we do no longer needed */
+ free(pszFileName);
+ free(pszFileTag);
+ free(pszStateFile);
+
if(iFilPtr == 0) {
errmsg.LogError(0, RS_RET_NO_RUN, "No files configured to be monitored");
ABORT_FINALIZE(RS_RET_NO_RUN);
@@ -365,7 +367,7 @@ persistStrmState(fileInfo_t *pInfo)
/* TODO: create a function persistObj in obj.c? */
CHKiRet(strm.Construct(&psSF));
- lenDir = strlen((char*)glbl.GetWorkDir());
+ lenDir = ustrlen(glbl.GetWorkDir());
if(lenDir > 0)
CHKiRet(strm.SetDir(psSF, glbl.GetWorkDir(), lenDir));
CHKiRet(strm.SettOperationsMode(psSF, STREAMMODE_WRITE_TRUNC));
@@ -401,6 +403,9 @@ CODESTARTafterRun
persistStrmState(&files[i]);
strm.Destruct(&(files[i].pStrm));
}
+ free(files[i].pszFileName);
+ free(files[i].pszTag);
+ free(files[i].pszStateFile);
}
if(pInputName != NULL)
@@ -408,6 +413,13 @@ CODESTARTafterRun
ENDafterRun
+BEGINisCompatibleWithFeature
+CODESTARTisCompatibleWithFeature
+ if(eFeat == sFEATURENonCancelInputTermination)
+ iRet = RS_RET_OK;
+ENDisCompatibleWithFeature
+
+
/* The following entry points are defined in module-template.h.
* In general, they need to be present, but you do NOT need to provide
* any code here.
@@ -420,12 +432,14 @@ CODESTARTmodExit
objRelease(glbl, CORE_COMPONENT);
objRelease(errmsg, CORE_COMPONENT);
objRelease(prop, CORE_COMPONENT);
+ objRelease(ruleset, CORE_COMPONENT);
ENDmodExit
BEGINqueryEtryPt
CODESTARTqueryEtryPt
CODEqueryEtryPt_STD_IMOD_QUERIES
+CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES
ENDqueryEtryPt
@@ -459,6 +473,8 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a
iPollInterval = 10;
iFacility = 128; /* local0 */
iSeverity = 5; /* notice, as of rfc 3164 */
+ readMode = 0;
+ pBindRuleset = NULL;
RETiRet;
}
@@ -499,6 +515,11 @@ static rsRetVal addMonitor(void __attribute__((unused)) *pVal, uchar *pNewVal)
pThis->iSeverity = iSeverity;
pThis->iFacility = iFacility;
+ pThis->iPersistStateInterval = iPersistStateInterval;
+ pThis->nRecords = 0;
+ pThis->readMode = readMode;
+ pThis->pRuleset = pBindRuleset;
+ iPersistStateInterval = 0;
} else {
errmsg.LogError(0, RS_RET_OUT_OF_DESRIPTORS, "Too many file monitors configured - ignoring this one");
ABORT_FINALIZE(RS_RET_OUT_OF_DESRIPTORS);
@@ -513,6 +534,29 @@ finalize_it:
RETiRet;
}
+
+/* accept a new ruleset to bind. Checks if it exists and complains, if not */
+static rsRetVal
+setRuleset(void __attribute__((unused)) *pVal, uchar *pszName)
+{
+ ruleset_t *pRuleset;
+ rsRetVal localRet;
+ DEFiRet;
+
+ localRet = ruleset.GetRuleset(&pRuleset, pszName);
+ if(localRet == RS_RET_NOT_FOUND) {
+ errmsg.LogError(0, NO_ERRCODE, "error: ruleset '%s' not found - ignored", pszName);
+ }
+ CHKiRet(localRet);
+ pBindRuleset = pRuleset;
+ DBGPRINTF("imfile current bind ruleset %p: '%s'\n", pRuleset, pszName);
+
+finalize_it:
+ free(pszName); /* no longer needed */
+ RETiRet;
+}
+
+
/* modInit() is called once the module is loaded. It must perform all module-wide
* initialization tasks. There are also a number of housekeeping tasks that the
* framework requires. These are handled by the macros. Please note that the
@@ -530,8 +574,10 @@ CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(objUse(glbl, CORE_COMPONENT));
CHKiRet(objUse(datetime, CORE_COMPONENT));
CHKiRet(objUse(strm, CORE_COMPONENT));
+ CHKiRet(objUse(ruleset, CORE_COMPONENT));
CHKiRet(objUse(prop, CORE_COMPONENT));
+ DBGPRINTF("imfile: version %s initializing\n", VERSION);
CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputfilename", 0, eCmdHdlrGetWord,
NULL, &pszFileName, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputfiletag", 0, eCmdHdlrGetWord,
@@ -544,6 +590,12 @@ CODEmodInit_QueryRegCFSLineHdlr
NULL, &iFacility, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputfilepollinterval", 0, eCmdHdlrInt,
NULL, &iPollInterval, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputfilereadmode", 0, eCmdHdlrInt,
+ NULL, &readMode, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputfilepersiststateinterval", 0, eCmdHdlrInt,
+ NULL, &iPersistStateInterval, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputfilebindruleset", 0, eCmdHdlrGetWord,
+ setRuleset, NULL, STD_LOADABLE_MODULE_ID));
/* that command ads a new file! */
CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputrunfilemonitor", 0, eCmdHdlrGetWord,
addMonitor, NULL, STD_LOADABLE_MODULE_ID));