summaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'plugins')
-rw-r--r--plugins/cust1/Makefile.am6
-rw-r--r--plugins/im3195/im3195.c3
-rw-r--r--plugins/imdiag/imdiag.c390
-rw-r--r--plugins/imfile/imfile.c77
-rw-r--r--plugins/imgssapi/imgssapi.c5
-rw-r--r--plugins/imklog/bsd.c9
-rw-r--r--plugins/imklog/imklog.c48
-rw-r--r--plugins/imklog/imklog.h1
-rw-r--r--plugins/imklog/ksym_mod.c42
-rw-r--r--plugins/imklog/ksyms.h4
-rw-r--r--plugins/imklog/linux.c25
-rw-r--r--plugins/immark/immark.c1
-rw-r--r--plugins/imrelp/imrelp.c21
-rw-r--r--plugins/imtcp/imtcp.c70
-rw-r--r--plugins/imudp/imudp.c257
-rw-r--r--plugins/imuxsock/imuxsock.c27
-rw-r--r--plugins/omgssapi/omgssapi.c3
-rw-r--r--plugins/ommail/ommail.c2
-rw-r--r--plugins/ommysql/ommysql.c2
-rw-r--r--plugins/omoracle/Makefile.am8
-rw-r--r--plugins/omoracle/omoracle.c572
-rw-r--r--plugins/omoracle/omoracle.h31
-rw-r--r--plugins/omoracle/omoracle.te13
-rw-r--r--plugins/ompgsql/ompgsql.c24
-rw-r--r--plugins/omprog/Makefile.am8
-rw-r--r--plugins/omprog/omprog.c357
-rw-r--r--plugins/omrelp/omrelp.c2
-rw-r--r--plugins/omsnmp/omsnmp.c2
-rw-r--r--plugins/omstdout/Makefile.am8
-rw-r--r--plugins/omstdout/omstdout.c203
-rw-r--r--plugins/omtemplate/Makefile.am8
-rw-r--r--plugins/omtemplate/omtemplate.c220
-rw-r--r--plugins/omtesting/omtesting.c156
33 files changed, 2371 insertions, 234 deletions
diff --git a/plugins/cust1/Makefile.am b/plugins/cust1/Makefile.am
new file mode 100644
index 00000000..d2e075f9
--- /dev/null
+++ b/plugins/cust1/Makefile.am
@@ -0,0 +1,6 @@
+pkglib_LTLIBRARIES = cust1.la
+
+cust1_la_SOURCES = cust1.c
+cust1_la_CPPFLAGS = -I$(top_srcdir) $(PTHREADS_CFLAGS) $(RSRT_CFLAGS)
+cust1_la_LDFLAGS = -module -avoid-version
+cust1_la_LIBADD =
diff --git a/plugins/im3195/im3195.c b/plugins/im3195/im3195.c
index 1c2502fe..106da2c8 100644
--- a/plugins/im3195/im3195.c
+++ b/plugins/im3195/im3195.c
@@ -47,6 +47,7 @@
#include "liblogging/syslogmessage.h"
#include "module-template.h"
#include "cfsysline.h"
+#include "msg.h"
#include "errmsg.h"
MODULE_TYPE_INPUT
@@ -83,7 +84,7 @@ void OnReceive(srAPIObj __attribute__((unused)) *pMyAPI, srSLMGObj* pSLMG)
srSLMGGetRawMSG(pSLMG, &pszRawMsg);
parseAndSubmitMessage(fromHost, fromHostIP, pszRawMsg, strlen((char*)pszRawMsg),
- MSG_PARSE_HOSTNAME, NOFLAG, eFLOWCTL_FULL_DELAY, (uchar*)"im3195");
+ PARSE_HOSTNAME, eFLOWCTL_FULL_DELAY, (uchar*)"im3195", NULL, 0);
}
diff --git a/plugins/imdiag/imdiag.c b/plugins/imdiag/imdiag.c
index 77e99236..7cacc44a 100644
--- a/plugins/imdiag/imdiag.c
+++ b/plugins/imdiag/imdiag.c
@@ -1,5 +1,3 @@
-#warning "imdiag is NOT supported in this version of rsyslog"
-#if 0
/* imdiag.c
* This is a diagnostics module, primarily meant for troubleshooting
* and information about the runtime state of rsyslog. It is implemented
@@ -9,7 +7,7 @@
*
* File begun on 2008-07-25 by RGerhards
*
- * Copyright 2008 Rainer Gerhards and Adiscon GmbH.
+ * Copyright 2008, 2009 Rainer Gerhards and Adiscon GmbH.
*
* This file is part of rsyslog.
*
@@ -28,8 +26,8 @@
*
* A copy of the GPL can be found in the file "COPYING" in this distribution.
*/
-
#include "config.h"
+#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
@@ -45,117 +43,406 @@
#include <fcntl.h>
#endif
#include "rsyslog.h"
-//#include "dirty.h"
+#include "dirty.h"
#include "cfsysline.h"
#include "module-template.h"
+#include "unicode-helper.h"
#include "net.h"
#include "netstrm.h"
#include "errmsg.h"
+#include "tcpsrv.h"
+#include "srUtils.h"
+#include "msg.h"
+#include "datetime.h"
+#include "net.h" /* for permittedPeers, may be removed when this is removed */
MODULE_TYPE_INPUT
/* static data */
DEF_IMOD_STATIC_DATA
+DEFobjCurrIf(tcpsrv)
+DEFobjCurrIf(tcps_sess)
DEFobjCurrIf(net)
DEFobjCurrIf(netstrm)
DEFobjCurrIf(errmsg)
+DEFobjCurrIf(datetime)
+DEFobjCurrIf(prop)
/* Module static data */
-netstrms_t *pNS; /**< pointer to network stream subsystem */
-netstrm_t **ppLstn[10]; /**< our netstream listners */
-int iLstnMax = 0; /**< max nbr of listeners currently supported */
+static tcpsrv_t *pOurTcpsrv = NULL; /* our TCP server(listener) TODO: change for multiple instances */
+static permittedPeers_t *pPermPeersRoot = NULL;
+static prop_t *pInputName = NULL; /* there is only one global inputName for all messages generated by this input */
+static prop_t *pRcvDummy = NULL;
+static prop_t *pRcvIPDummy = NULL;
/* config settings */
+static int iTCPSessMax = 20; /* max number of sessions */
+static int iStrmDrvrMode = 0; /* mode for stream driver, driver-dependent (0 mostly means plain tcp) */
+static uchar *pszStrmDrvrAuthMode = NULL; /* authentication mode to use */
+static uchar *pszInputName = NULL; /* value for inputname property, NULL is OK and handled by core engine */
+
+
+/* callbacks */
+/* this shall go into a specific ACL module! */
+static int
+isPermittedHost(struct sockaddr __attribute__((unused)) *addr, char __attribute__((unused)) *fromHostFQDN,
+ void __attribute__((unused)) *pUsrSrv, void __attribute__((unused)) *pUsrSess)
+{
+ return 1; /* TODO: implement ACLs ... or via some other way? */
+}
+
+
+static rsRetVal
+doOpenLstnSocks(tcpsrv_t *pSrv)
+{
+ ISOBJ_TYPE_assert(pSrv, tcpsrv);
+ return tcpsrv.create_tcp_socket(pSrv);
+}
+
+
+static rsRetVal
+doRcvData(tcps_sess_t *pSess, char *buf, size_t lenBuf, ssize_t *piLenRcvd)
+{
+ DEFiRet;
+ assert(pSess != NULL);
+ assert(piLenRcvd != NULL);
+
+ *piLenRcvd = lenBuf;
+ CHKiRet(netstrm.Rcv(pSess->pStrm, (uchar*) buf, piLenRcvd));
+finalize_it:
+ RETiRet;
+}
+
+static rsRetVal
+onRegularClose(tcps_sess_t *pSess)
+{
+ DEFiRet;
+ assert(pSess != NULL);
+ /* process any incomplete frames left over */
+ tcps_sess.PrepareClose(pSess);
+ /* Session closed */
+ tcps_sess.Close(pSess);
+ RETiRet;
+}
-/* add a listen socket to our listen socket array. This is a callback
- * invoked from the netstrm class. -- rgerhards, 2008-04-23
+
+static rsRetVal
+onErrClose(tcps_sess_t *pSess)
+{
+ DEFiRet;
+ assert(pSess != NULL);
+
+ tcps_sess.Close(pSess);
+ RETiRet;
+}
+
+/* ------------------------------ end callbacks ------------------------------ */
+
+
+/* get the first word delimited by space from a given string. The pointer is
+ * advanced to after the word. Any leading spaces are discarded. If the
+ * output buffer is too small, parsing ends on buffer full condition.
+ * An empty buffer is returned if there is no more data inside the string.
+ * rgerhards, 2009-05-27
+ */
+#define TO_LOWERCASE 1
+#define NO_MODIFY 0
+static void
+getFirstWord(uchar **ppszSrc, uchar *pszBuf, size_t lenBuf, int options)
+{
+ uchar c;
+ uchar *pszSrc = *ppszSrc;
+
+ while(*pszSrc && *pszSrc == ' ')
+ ++pszSrc; /* skip to first non-space */
+
+ while(*pszSrc && *pszSrc != ' ' && lenBuf > 1) {
+ c = *pszSrc++;
+ if(options & TO_LOWERCASE)
+ c = tolower(c);
+ *pszBuf++ = c;
+ lenBuf--;
+ }
+
+ *pszBuf = '\0';
+ *ppszSrc = pszSrc;
+}
+
+
+/* send a response back to the originator
+ * rgerhards, 2009-05-27
+ */
+static rsRetVal __attribute__((format(printf, 2, 3)))
+sendResponse(tcps_sess_t *pSess, char *fmt, ...)
+{
+ va_list ap;
+ ssize_t len;
+ uchar buf[1024];
+ DEFiRet;
+
+ va_start(ap, fmt);
+ len = vsnprintf((char*)buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+ CHKiRet(netstrm.Send(pSess->pStrm, buf, &len));
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* actually submit a message to the rsyslog core
*/
static rsRetVal
-addTcpLstn(void *pUsr, netstrm_t *pLstn)
+doInjectMsg(int iNum)
{
+ uchar szMsg[1024];
+ msg_t *pMsg;
+ struct syslogTime stTime;
+ time_t ttGenTime;
DEFiRet;
- ISOBJ_TYPE_assert(pLstn, netstrm);
+ snprintf((char*)szMsg, sizeof(szMsg)/sizeof(uchar),
+ "<167>Mar 1 01:00:00 172.20.245.8 tag msgnum:%8.8d:\n", iNum);
+
+ datetime.getCurrTime(&stTime, &ttGenTime);
+ /* we now create our own message object and submit it to the queue */
+ CHKiRet(msgConstructWithTime(&pMsg, &stTime, ttGenTime));
+ MsgSetRawMsg(pMsg, (char*) szMsg, ustrlen(szMsg));
+ MsgSetInputName(pMsg, pInputName);
+ MsgSetFlowControlType(pMsg, eFLOWCTL_NO_DELAY);
+ pMsg->msgFlags = NEEDS_PARSING | PARSE_HOSTNAME;
+ pMsg->bParseHOSTNAME = 1;
+ MsgSetRcvFrom(pMsg, pRcvDummy);
+ CHKiRet(MsgSetRcvFromIP(pMsg, pRcvIPDummy));
+ CHKiRet(submitMsg(pMsg));
- if(iLstnMax >= sizeof(ppLstn)/sizeof(netstrm_t))
- ABORT_FINALIZE(RS_RET_MAX_LSTN_REACHED);
+finalize_it:
+ RETiRet;
+}
- ppLstn[pThis->iLstnMax] = pLstn;
- ++iLstnMax;
+
+/* This function injects messages. Command format:
+ * injectmsg <fromnbr> <number-of-messages>
+ * rgerhards, 2009-05-27
+ */
+static rsRetVal
+injectMsg(uchar *pszCmd, tcps_sess_t *pSess)
+{
+ uchar wordBuf[1024];
+ int iFrom;
+ int nMsgs;
+ int i;
+ DEFiRet;
+
+ /* we do not check errors here! */
+ getFirstWord(&pszCmd, wordBuf, sizeof(wordBuf)/sizeof(uchar), TO_LOWERCASE);
+ iFrom = atoi((char*)wordBuf);
+ getFirstWord(&pszCmd, wordBuf, sizeof(wordBuf)/sizeof(uchar), TO_LOWERCASE);
+ nMsgs = atoi((char*)wordBuf);
+
+ for(i = 0 ; i < nMsgs ; ++i) {
+ doInjectMsg(i + iFrom);
+ }
+
+ CHKiRet(sendResponse(pSess, "%d messages injected\n", nMsgs));
finalize_it:
RETiRet;
}
-/* initialize network stream subsystem */
+/* This function waits until the main queue is drained (size = 0)
+ */
static rsRetVal
-initNetstrm(void)
+waitMainQEmpty(tcps_sess_t *pSess)
{
+ int iMsgQueueSize;
+ int iPrint = 0;
DEFiRet;
- /* prepare network stream subsystem */
- CHKiRet(netstrms.Construct(&pNS));
- CHKiRet(netstrms.SetDrvrMode(pNS, 0)); /* always plain text */
- //CHKiRet(netstrms.SetDrvrAuthMode(pThis->pNS, pThis->pszDrvrAuthMode));
- //CHKiRet(netstrms.SetDrvrPermPeers(pThis->pNS, pThis->pPermPeers));
- // TODO: set driver!
- CHKiRet(netstrms.ConstructFinalize(pThis->pNS));
+ CHKiRet(diagGetMainMsgQSize(&iMsgQueueSize));
+ while(iMsgQueueSize > 0) {
+ if(iPrint++ % 500 == 0)
+ dbgprintf("imdiag sleeping, wait mainq drain, curr size %d\n", iMsgQueueSize);
+ srSleep(0,2); /* wait a little bit */
+ CHKiRet(diagGetMainMsgQSize(&iMsgQueueSize));
+ }
- /* set up listeners */
- CHKiRet(netstrm.LstnInit(pNS, NULL, addTcpLstn, "127.0.0.1", "44514", 1));
+ CHKiRet(sendResponse(pSess, "mainqueue empty\n"));
finalize_it:
- if(iRet != RS_RET_OK) {
- if(pThis->pNS != NULL)
- netstrms.Destruct(&pThis->pNS);
+ RETiRet;
+}
+
+/* Function to handle received messages. This is our core function!
+ * rgerhards, 2009-05-24
+ */
+static rsRetVal
+OnMsgReceived(tcps_sess_t *pSess, uchar *pRcv, int iLenMsg)
+{
+ int iMsgQueueSize;
+ uchar *pszMsg;
+ uchar cmdBuf[1024];
+ DEFiRet;
+
+ assert(pSess != NULL);
+ assert(pRcv != NULL);
+
+ /* NOTE: pRcv is NOT a C-String but rather an array of characters
+ * WITHOUT a termination \0 char. So we need to convert it to one
+ * before proceeding.
+ */
+ CHKmalloc(pszMsg = malloc(sizeof(uchar) * (iLenMsg + 1)));
+ memcpy(pszMsg, pRcv, iLenMsg);
+ pszMsg[iLenMsg] = '\0';
+
+ getFirstWord(&pszMsg, cmdBuf, sizeof(cmdBuf)/sizeof(uchar), TO_LOWERCASE);
+
+ dbgprintf("imdiag received command '%s'\n", cmdBuf);
+ if(!ustrcmp(cmdBuf, UCHAR_CONSTANT("getmainmsgqueuesize"))) {
+ CHKiRet(diagGetMainMsgQSize(&iMsgQueueSize));
+ CHKiRet(sendResponse(pSess, "%d\n", iMsgQueueSize));
+ } else if(!ustrcmp(cmdBuf, UCHAR_CONSTANT("waitmainqueueempty"))) {
+ CHKiRet(waitMainQEmpty(pSess));
+ } else if(!ustrcmp(cmdBuf, UCHAR_CONSTANT("injectmsg"))) {
+ CHKiRet(injectMsg(pszMsg, pSess));
+ } else {
+ dbgprintf("imdiag unkown command '%s'\n", cmdBuf);
+ CHKiRet(sendResponse(pSess, "unkown command '%s'\n", cmdBuf));
}
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* set permitted peer -- rgerhards, 2008-05-19
+ */
+static rsRetVal
+setPermittedPeer(void __attribute__((unused)) *pVal, uchar *pszID)
+{
+ DEFiRet;
+ CHKiRet(net.AddPermittedPeer(&pPermPeersRoot, pszID));
+ free(pszID); /* no longer needed, but we need to free as of interface def */
+finalize_it:
RETiRet;
}
-/* This function is called to gather input. In our case, it is a bit abused
- * to drive the listener loop for the diagnostics code.
+static rsRetVal addTCPListener(void __attribute__((unused)) *pVal, uchar *pNewVal)
+{
+ DEFiRet;
+
+ if(pOurTcpsrv == NULL) {
+ CHKiRet(tcpsrv.Construct(&pOurTcpsrv));
+ CHKiRet(tcpsrv.SetSessMax(pOurTcpsrv, iTCPSessMax));
+ CHKiRet(tcpsrv.SetCBIsPermittedHost(pOurTcpsrv, isPermittedHost));
+ CHKiRet(tcpsrv.SetCBRcvData(pOurTcpsrv, doRcvData));
+ CHKiRet(tcpsrv.SetCBOpenLstnSocks(pOurTcpsrv, doOpenLstnSocks));
+ CHKiRet(tcpsrv.SetCBOnRegularClose(pOurTcpsrv, onRegularClose));
+ CHKiRet(tcpsrv.SetCBOnErrClose(pOurTcpsrv, onErrClose));
+ CHKiRet(tcpsrv.SetDrvrMode(pOurTcpsrv, iStrmDrvrMode));
+ CHKiRet(tcpsrv.SetOnMsgReceive(pOurTcpsrv, OnMsgReceived));
+ /* now set optional params, but only if they were actually configured */
+ if(pszStrmDrvrAuthMode != NULL) {
+ CHKiRet(tcpsrv.SetDrvrAuthMode(pOurTcpsrv, pszStrmDrvrAuthMode));
+ }
+ if(pPermPeersRoot != NULL) {
+ CHKiRet(tcpsrv.SetDrvrPermPeers(pOurTcpsrv, pPermPeersRoot));
+ }
+ }
+
+ /* initialized, now add socket */
+ CHKiRet(tcpsrv.SetInputName(pOurTcpsrv, pszInputName == NULL ?
+ UCHAR_CONSTANT("imdiag") : pszInputName));
+ tcpsrv.configureTCPListen(pOurTcpsrv, pNewVal);
+
+finalize_it:
+ if(iRet != RS_RET_OK) {
+ errmsg.LogError(0, NO_ERRCODE, "error %d trying to add listener", iRet);
+ if(pOurTcpsrv != NULL)
+ tcpsrv.Destruct(&pOurTcpsrv);
+ }
+ RETiRet;
+}
+
+/* This function is called to gather input.
*/
BEGINrunInput
CODESTARTrunInput
+ CHKiRet(tcpsrv.ConstructFinalize(pOurTcpsrv));
+ iRet = tcpsrv.Run(pOurTcpsrv);
+finalize_it:
ENDrunInput
/* initialize and return if will run or not */
BEGINwillRun
CODESTARTwillRun
- iRet = initNetstrm();
+ /* first apply some config settings */
+ if(pOurTcpsrv == NULL)
+ ABORT_FINALIZE(RS_RET_NO_RUN);
+ /* we need to create the inputName property (only once during our lifetime) */
+ CHKiRet(prop.Construct(&pInputName));
+ CHKiRet(prop.SetString(pInputName, UCHAR_CONSTANT("imdiag"), sizeof("imdiag") - 1));
+ CHKiRet(prop.ConstructFinalize(pInputName));
+
+ CHKiRet(prop.Construct(&pRcvDummy));
+ CHKiRet(prop.SetString(pRcvDummy, UCHAR_CONSTANT("127.0.0.1"), sizeof("127.0.0.1") - 1));
+ CHKiRet(prop.ConstructFinalize(pRcvDummy));
+
+ CHKiRet(prop.Construct(&pRcvIPDummy));
+ CHKiRet(prop.SetString(pRcvIPDummy, UCHAR_CONSTANT("127.0.0.1"), sizeof("127.0.0.1") - 1));
+ CHKiRet(prop.ConstructFinalize(pRcvIPDummy));
+
+finalize_it:
ENDwillRun
BEGINafterRun
CODESTARTafterRun
- /* do cleanup here */
- /* finally close our listen streams */
- for(i = 0 ; i < iLstnMax ; ++i) {
- netstrm.Destruct(ppLstn + i);
- }
-
- /* destruct netstream subsystem */
- netstrms.Destruct(pNS);
+ if(pInputName != NULL)
+ prop.Destruct(&pInputName);
+ if(pRcvDummy != NULL)
+ prop.Destruct(&pRcvDummy);
+ if(pRcvIPDummy != NULL)
+ prop.Destruct(&pRcvIPDummy);
ENDafterRun
BEGINmodExit
CODESTARTmodExit
+ if(pOurTcpsrv != NULL)
+ iRet = tcpsrv.Destruct(&pOurTcpsrv);
+
+ if(pPermPeersRoot != NULL) {
+ net.DestructPermittedPeers(&pPermPeersRoot);
+ }
+
/* release objects we used */
objRelease(net, LM_NET_FILENAME);
objRelease(netstrm, LM_NETSTRMS_FILENAME);
+ objRelease(tcps_sess, LM_TCPSRV_FILENAME);
+ objRelease(tcpsrv, LM_TCPSRV_FILENAME);
objRelease(errmsg, CORE_COMPONENT);
+ objRelease(datetime, CORE_COMPONENT);
+ objRelease(prop, CORE_COMPONENT);
ENDmodExit
static rsRetVal
resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
{
+ iTCPSessMax = 200;
+ iStrmDrvrMode = 0;
+ free(pszInputName);
+ pszInputName = NULL;
+ if(pszStrmDrvrAuthMode != NULL) {
+ free(pszStrmDrvrAuthMode);
+ pszStrmDrvrAuthMode = NULL;
+ }
return RS_RET_OK;
}
@@ -175,25 +462,28 @@ CODEmodInit_QueryRegCFSLineHdlr
/* request objects we use */
CHKiRet(objUse(net, LM_NET_FILENAME));
CHKiRet(objUse(netstrm, LM_NETSTRMS_FILENAME));
+ CHKiRet(objUse(tcps_sess, LM_TCPSRV_FILENAME));
+ CHKiRet(objUse(tcpsrv, LM_TCPSRV_FILENAME));
CHKiRet(objUse(errmsg, CORE_COMPONENT));
+ CHKiRet(objUse(datetime, CORE_COMPONENT));
+ CHKiRet(objUse(prop, CORE_COMPONENT));
-#if 0
/* register config file handlers */
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputtcpserverrun", 0, eCmdHdlrGetWord,
+ CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("imdiagserverrun"), 0, eCmdHdlrGetWord,
addTCPListener, NULL, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputtcpmaxsessions", 0, eCmdHdlrInt,
+ CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("imdiagmaxsessions"), 0, eCmdHdlrInt,
NULL, &iTCPSessMax, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputtcpserverstreamdrivermode", 0,
+ CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("imdiagserverstreamdrivermode"), 0,
eCmdHdlrInt, NULL, &iStrmDrvrMode, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputtcpserverstreamdriverauthmode", 0,
+ CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("imdiagserverstreamdriverauthmode"), 0,
eCmdHdlrGetWord, NULL, &pszStrmDrvrAuthMode, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputtcpserverstreamdriverpermittedpeer", 0,
+ CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("imdiagserverstreamdriverpermittedpeer"), 0,
eCmdHdlrGetWord, setPermittedPeer, NULL, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler,
+ CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("imdiagserverinputname"), 0,
+ eCmdHdlrGetWord, NULL, &pszInputName, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("resetconfigvariables"), 1, eCmdHdlrCustomHandler,
resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
-#endif
ENDmodInit
-#endif
/* vim:set ai:
diff --git a/plugins/imfile/imfile.c b/plugins/imfile/imfile.c
index b0211bf6..7c588f90 100644
--- a/plugins/imfile/imfile.c
+++ b/plugins/imfile/imfile.c
@@ -45,6 +45,8 @@
#include "errmsg.h"
#include "glbl.h"
#include "datetime.h"
+#include "unicode-helper.h"
+#include "prop.h"
MODULE_TYPE_INPUT /* must be present for input modules, do not remove */
@@ -55,10 +57,13 @@ DEF_IMOD_STATIC_DATA /* must be present, starts static data */
DEFobjCurrIf(errmsg)
DEFobjCurrIf(glbl)
DEFobjCurrIf(datetime)
+DEFobjCurrIf(strm)
+DEFobjCurrIf(prop)
typedef struct fileInfo_s {
uchar *pszFileName;
uchar *pszTag;
+ size_t lenTag;
uchar *pszStateFile; /* file in which state between runs is to be stored */
int iFacility;
int iSeverity;
@@ -78,6 +83,7 @@ static int iFilPtr = 0; /* number of files to be monitored; pointer to next fre
#define MAX_INPUT_FILES 100
static fileInfo_t files[MAX_INPUT_FILES];
+static prop_t *pInputName = NULL; /* there is only one global inputName for all messages generated by this input */
/* enqueue the read file line as a message. The provided string is
* not freed - thuis must be done by the caller.
@@ -94,12 +100,11 @@ static rsRetVal enqLine(fileInfo_t *pInfo, cstr_t *cstrLine)
CHKiRet(msgConstruct(&pMsg));
MsgSetFlowControlType(pMsg, eFLOWCTL_FULL_DELAY);
- MsgSetInputName(pMsg, "imfile");
- MsgSetUxTradMsg(pMsg, (char*)rsCStrGetSzStr(cstrLine));
- MsgSetRawMsg(pMsg, (char*)rsCStrGetSzStr(cstrLine));
- MsgSetMSG(pMsg, (char*)rsCStrGetSzStr(cstrLine));
- MsgSetHOSTNAME(pMsg, (char*)glbl.GetLocalHostName());
- MsgSetTAG(pMsg, (char*)pInfo->pszTag);
+ MsgSetInputName(pMsg, pInputName);
+ MsgSetRawMsg(pMsg, (char*)rsCStrGetSzStr(cstrLine), cstrLen(cstrLine));
+ MsgSetMSGoffs(pMsg, 0); /* we do not have a header... */
+ MsgSetHOSTNAME(pMsg, glbl.GetLocalHostName(), ustrlen(glbl.GetLocalHostName()));
+ MsgSetTAG(pMsg, pInfo->pszTag, pInfo->lenTag);
pMsg->iFacility = LOG_FAC(pInfo->iFacility);
pMsg->iSeverity = LOG_PRI(pInfo->iSeverity);
pMsg->bParseHOSTNAME = 0;
@@ -138,16 +143,16 @@ openFile(fileInfo_t *pThis)
/* If we reach this point, we have a .si file */
- CHKiRet(strmConstruct(&psSF));
- CHKiRet(strmSettOperationsMode(psSF, STREAMMODE_READ));
- CHKiRet(strmSetsType(psSF, STREAMTYPE_FILE_SINGLE));
- CHKiRet(strmSetFName(psSF, pszSFNam, lenSFNam));
- CHKiRet(strmConstructFinalize(psSF));
+ CHKiRet(strm.Construct(&psSF));
+ CHKiRet(strm.SettOperationsMode(psSF, STREAMMODE_READ));
+ CHKiRet(strm.SetsType(psSF, STREAMTYPE_FILE_SINGLE));
+ CHKiRet(strm.SetFName(psSF, pszSFNam, lenSFNam));
+ CHKiRet(strm.ConstructFinalize(psSF));
/* read back in the object */
CHKiRet(obj.Deserialize(&pThis->pStrm, (uchar*) "strm", psSF, NULL, pThis));
- CHKiRet(strmSeekCurrOffs(pThis->pStrm));
+ 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.
@@ -156,14 +161,14 @@ openFile(fileInfo_t *pThis)
finalize_it:
if(psSF != NULL)
- strmDestruct(&psSF);
+ strm.Destruct(&psSF);
if(iRet != RS_RET_OK) {
- CHKiRet(strmConstruct(&pThis->pStrm));
- CHKiRet(strmSettOperationsMode(pThis->pStrm, STREAMMODE_READ));
- CHKiRet(strmSetsType(pThis->pStrm, STREAMTYPE_FILE_MONITOR));
- CHKiRet(strmSetFName(pThis->pStrm, pThis->pszFileName, strlen((char*) pThis->pszFileName)));
- CHKiRet(strmConstructFinalize(pThis->pStrm));
+ CHKiRet(strm.Construct(&pThis->pStrm));
+ CHKiRet(strm.SettOperationsMode(pThis->pStrm, STREAMMODE_READ));
+ CHKiRet(strm.SetsType(pThis->pStrm, STREAMTYPE_FILE_MONITOR));
+ CHKiRet(strm.SetFName(pThis->pStrm, pThis->pszFileName, strlen((char*) pThis->pszFileName)));
+ CHKiRet(strm.ConstructFinalize(pThis->pStrm));
}
RETiRet;
@@ -202,7 +207,7 @@ static rsRetVal pollFile(fileInfo_t *pThis, int *pbHadFileData)
/* loop below will be exited when strmReadLine() returns EOF */
while(1) {
- CHKiRet(strmReadLine(pThis->pStrm, &pCStr));
+ CHKiRet(strm.ReadLine(pThis->pStrm, &pCStr));
*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!) */
@@ -334,6 +339,11 @@ CODESTARTwillRun
ABORT_FINALIZE(RS_RET_NO_RUN);
}
+ /* we need to create the inputName property (only once during our lifetime) */
+ CHKiRet(prop.Construct(&pInputName));
+ CHKiRet(prop.SetString(pInputName, UCHAR_CONSTANT("imfile"), sizeof("imfile") - 1));
+ CHKiRet(prop.ConstructFinalize(pInputName));
+
finalize_it:
ENDwillRun
@@ -353,21 +363,20 @@ persistStrmState(fileInfo_t *pInfo)
ASSERT(pInfo != NULL);
/* TODO: create a function persistObj in obj.c? */
- CHKiRet(strmConstruct(&psSF));
- CHKiRet(strmSetDir(psSF, glbl.GetWorkDir(), strlen((char*)glbl.GetWorkDir())));
- CHKiRet(strmSettOperationsMode(psSF, STREAMMODE_WRITE));
- CHKiRet(strmSetiAddtlOpenFlags(psSF, O_TRUNC));
- CHKiRet(strmSetsType(psSF, STREAMTYPE_FILE_SINGLE));
- CHKiRet(strmSetFName(psSF, pInfo->pszStateFile, strlen((char*) pInfo->pszStateFile)));
- CHKiRet(strmConstructFinalize(psSF));
+ CHKiRet(strm.Construct(&psSF));
+ CHKiRet(strm.SetDir(psSF, glbl.GetWorkDir(), strlen((char*)glbl.GetWorkDir())));
+ CHKiRet(strm.SettOperationsMode(psSF, STREAMMODE_WRITE_TRUNC));
+ CHKiRet(strm.SetsType(psSF, STREAMTYPE_FILE_SINGLE));
+ CHKiRet(strm.SetFName(psSF, pInfo->pszStateFile, strlen((char*) pInfo->pszStateFile)));
+ CHKiRet(strm.ConstructFinalize(psSF));
- CHKiRet(strmSerialize(pInfo->pStrm, psSF));
+ CHKiRet(strm.Serialize(pInfo->pStrm, psSF));
- CHKiRet(strmDestruct(&psSF));
+ CHKiRet(strm.Destruct(&psSF));
finalize_it:
if(psSF != NULL)
- strmDestruct(&psSF);
+ strm.Destruct(&psSF);
RETiRet;
}
@@ -387,9 +396,12 @@ CODESTARTafterRun
for(i = 0 ; i < iFilPtr ; ++i) {
if(files[i].pStrm != NULL) { /* stream open? */
persistStrmState(&files[i]);
- strmDestruct(&(files[i].pStrm));
+ strm.Destruct(&(files[i].pStrm));
}
}
+
+ if(pInputName != NULL)
+ prop.Destruct(&pInputName);
ENDafterRun
@@ -400,9 +412,11 @@ ENDafterRun
BEGINmodExit
CODESTARTmodExit
/* release objects we used */
+ objRelease(strm, CORE_COMPONENT);
objRelease(datetime, CORE_COMPONENT);
objRelease(glbl, CORE_COMPONENT);
objRelease(errmsg, CORE_COMPONENT);
+ objRelease(prop, CORE_COMPONENT);
ENDmodExit
@@ -470,6 +484,7 @@ static rsRetVal addMonitor(void __attribute__((unused)) *pVal, uchar *pNewVal)
ABORT_FINALIZE(RS_RET_CONFIG_ERROR);
} else {
pThis->pszTag = (uchar*) strdup((char*) pszFileTag);
+ pThis->lenTag = ustrlen(pThis->pszTag);
}
if(pszStateFile == NULL) {
@@ -511,6 +526,8 @@ CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(objUse(errmsg, CORE_COMPONENT));
CHKiRet(objUse(glbl, CORE_COMPONENT));
CHKiRet(objUse(datetime, CORE_COMPONENT));
+ CHKiRet(objUse(strm, CORE_COMPONENT));
+ CHKiRet(objUse(prop, CORE_COMPONENT));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputfilename", 0, eCmdHdlrGetWord,
NULL, &pszFileName, STD_LOADABLE_MODULE_ID));
diff --git a/plugins/imgssapi/imgssapi.c b/plugins/imgssapi/imgssapi.c
index debe935e..d8791880 100644
--- a/plugins/imgssapi/imgssapi.c
+++ b/plugins/imgssapi/imgssapi.c
@@ -9,7 +9,7 @@
* NOTE: read comments in module-template.h to understand how this file
* works!
*
- * Copyright 2007 Rainer Gerhards and Adiscon GmbH.
+ * Copyright 2007, 2009 Rainer Gerhards and Adiscon GmbH.
*
* This file is part of rsyslog.
*
@@ -249,7 +249,6 @@ onErrClose(tcps_sess_t *pSess)
static rsRetVal
doOpenLstnSocks(tcpsrv_t *pSrv)
{
- int *pRet = NULL;
gsssrv_t *pGSrv;
DEFiRet;
@@ -331,7 +330,7 @@ addGSSListener(void __attribute__((unused)) *pVal, uchar *pNewVal)
CHKiRet(tcpsrv.SetCBOnSessAccept(pOurTcpsrv, onSessAccept));
CHKiRet(tcpsrv.SetCBOnRegularClose(pOurTcpsrv, onRegularClose));
CHKiRet(tcpsrv.SetCBOnErrClose(pOurTcpsrv, onErrClose));
- tcpsrv.configureTCPListen(pOurTcpsrv, (char *) pNewVal);
+ tcpsrv.configureTCPListen(pOurTcpsrv, pNewVal);
CHKiRet(tcpsrv.ConstructFinalize(pOurTcpsrv));
}
diff --git a/plugins/imklog/bsd.c b/plugins/imklog/bsd.c
index 090c4e9b..6d7b6c98 100644
--- a/plugins/imklog/bsd.c
+++ b/plugins/imklog/bsd.c
@@ -83,6 +83,11 @@ static int fklog = -1; /* /dev/klog */
# define _PATH_KLOG "/dev/klog"
#endif
+static uchar *GetPath(void)
+{
+ return pszPath ? pszPath : _PATH_KLOG;
+}
+
/* open the kernel log - will be called inside the willRun() imklog
* entry point. -- rgerhards, 2008-04-09
*/
@@ -91,9 +96,9 @@ klogWillRun(void)
{
DEFiRet;
- fklog = open(_PATH_KLOG, O_RDONLY, 0);
+ fklog = open(GetPath(), O_RDONLY, 0);
if (fklog < 0) {
- dbgprintf("can't open %s (%d)\n", _PATH_KLOG, errno);
+ dbgprintf("can't open %s (%d)\n", GetPath(), errno);
iRet = RS_RET_ERR; // TODO: better error code
}
diff --git a/plugins/imklog/imklog.c b/plugins/imklog/imklog.c
index 20bc34ab..7994c5eb 100644
--- a/plugins/imklog/imklog.c
+++ b/plugins/imklog/imklog.c
@@ -18,7 +18,7 @@
* Please note that this file replaces the klogd daemon that was
* also present in pre-v3 versions of rsyslog.
*
- * Copyright (C) 2008 by Rainer Gerhards and Adiscon GmbH
+ * Copyright (C) 2008, 2009 by Rainer Gerhards and Adiscon GmbH
*
* This file is part of rsyslog.
*
@@ -44,6 +44,7 @@
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
+#include <stdlib.h>
#include "dirty.h"
#include "cfsysline.h"
@@ -53,6 +54,8 @@
#include "datetime.h"
#include "imklog.h"
#include "glbl.h"
+#include "prop.h"
+#include "unicode-helper.h"
MODULE_TYPE_INPUT
@@ -60,6 +63,7 @@ MODULE_TYPE_INPUT
DEF_IMOD_STATIC_DATA
DEFobjCurrIf(datetime)
DEFobjCurrIf(glbl)
+DEFobjCurrIf(prop)
/* configuration settings */
int dbgPrintSymbols = 0; /* this one is extern so the helpers can access it! */
@@ -68,6 +72,8 @@ int use_syscall = 0;
int symbol_lookup = 0; /* on recent kernels > 2.6, the kernel does this */
int bPermitNonKernel = 0; /* permit logging of messages not having LOG_KERN facility */
int iFacilIntMsg; /* the facility to use for internal messages (set by driver) */
+uchar *pszPath = NULL;
+int console_log_level = -1;
/* TODO: configuration for the following directives must be implemented. It
* was not done yet because we either do not yet have a config handler for
* that type or I thought it was acceptable to push it to a later stage when
@@ -75,9 +81,11 @@ int iFacilIntMsg; /* the facility to use for internal messages (set by driver) *
* changes resulting from that). -- rgerhards, 2007-12-20
*/
char *symfile = NULL;
-int console_log_level = -1;
+static prop_t *pInputName = NULL; /* there is only one global inputName for all messages generated by this module */
+static prop_t *pLocalHostIP = NULL; /* a pseudo-constant propterty for 127.0.0.1 */
+
/* enqueue the the kernel message into the message queue.
* The provided msg string is not freed - thus must be done
* by the caller.
@@ -94,15 +102,13 @@ enqMsg(uchar *msg, uchar* pszTag, int iFacility, int iSeverity)
CHKiRet(msgConstruct(&pMsg));
MsgSetFlowControlType(pMsg, eFLOWCTL_LIGHT_DELAY);
- MsgSetInputName(pMsg, "imklog");
- MsgSetRawMsg(pMsg, (char*)msg);
- MsgSetUxTradMsg(pMsg, (char*)msg);
- MsgSetRawMsg(pMsg, (char*)msg);
- MsgSetMSG(pMsg, (char*)msg);
- MsgSetRcvFrom(pMsg, (char*)glbl.GetLocalHostName());
- MsgSetRcvFromIP(pMsg, (uchar*)"127.0.0.1");
- MsgSetHOSTNAME(pMsg, (char*)glbl.GetLocalHostName());
- MsgSetTAG(pMsg, (char*)pszTag);
+ MsgSetInputName(pMsg, pInputName);
+ MsgSetRawMsgWOSize(pMsg, (char*)msg);
+ MsgSetMSGoffs(pMsg, 0); /* we do not have a header... */
+ MsgSetRcvFrom(pMsg, glbl.GetLocalHostNameProp());
+ MsgSetRcvFromIP(pMsg, pLocalHostIP);
+ MsgSetHOSTNAME(pMsg, glbl.GetLocalHostName(), ustrlen(glbl.GetLocalHostName()));
+ MsgSetTAG(pMsg, pszTag, ustrlen(pszTag));
pMsg->iFacility = LOG_FAC(iFacility);
pMsg->iSeverity = LOG_PRI(iSeverity);
pMsg->bParseHOSTNAME = 0;
@@ -229,13 +235,23 @@ ENDrunInput
BEGINwillRun
CODESTARTwillRun
+ /* we need to create the inputName property (only once during our lifetime) */
+ CHKiRet(prop.CreateStringProp(&pInputName, UCHAR_CONSTANT("imklog"), sizeof("imklog") - 1));
+ CHKiRet(prop.CreateStringProp(&pLocalHostIP, UCHAR_CONSTANT("127.0.0.1"), sizeof("127.0.0.1") - 1));
+
iRet = klogWillRun();
+finalize_it:
ENDwillRun
BEGINafterRun
CODESTARTafterRun
iRet = klogAfterRun();
+
+ if(pInputName != NULL)
+ prop.Destruct(&pInputName);
+ if(pLocalHostIP != NULL)
+ prop.Destruct(&pLocalHostIP);
ENDafterRun
@@ -244,6 +260,9 @@ CODESTARTmodExit
/* release objects we used */
objRelease(glbl, CORE_COMPONENT);
objRelease(datetime, CORE_COMPONENT);
+ objRelease(prop, CORE_COMPONENT);
+ if(pszPath != NULL)
+ free(pszPath);
ENDmodExit
@@ -260,6 +279,10 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a
symfile = NULL;
symbol_lookup = 0;
bPermitNonKernel = 0;
+ if(pszPath != NULL) {
+ free(pszPath);
+ pszPath = NULL;
+ }
iFacilIntMsg = klogFacilIntMsg();
return RS_RET_OK;
}
@@ -270,14 +293,17 @@ CODESTARTmodInit
CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(objUse(datetime, CORE_COMPONENT));
CHKiRet(objUse(glbl, CORE_COMPONENT));
+ CHKiRet(objUse(prop, CORE_COMPONENT));
iFacilIntMsg = klogFacilIntMsg();
CHKiRet(omsdRegCFSLineHdlr((uchar *)"debugprintkernelsymbols", 0, eCmdHdlrBinary, NULL, &dbgPrintSymbols, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogpath", 0, eCmdHdlrGetWord, NULL, &pszPath, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogsymbollookup", 0, eCmdHdlrBinary, NULL, &symbol_lookup, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogsymbolstwice", 0, eCmdHdlrBinary, NULL, &symbols_twice, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogusesyscallinterface", 0, eCmdHdlrBinary, NULL, &use_syscall, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogpermitnonkernelfacility", 0, eCmdHdlrBinary, NULL, &bPermitNonKernel, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogconsoleloglevel", 0, eCmdHdlrInt, NULL, &console_log_level, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"kloginternalmsgfacility", 0, eCmdHdlrFacility, NULL, &iFacilIntMsg, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
ENDmodInit
diff --git a/plugins/imklog/imklog.h b/plugins/imklog/imklog.h
index 37bd58b0..c183026d 100644
--- a/plugins/imklog/imklog.h
+++ b/plugins/imklog/imklog.h
@@ -52,6 +52,7 @@ extern int symbol_lookup;
extern char *symfile;
extern int console_log_level;
extern int dbgPrintSymbols;
+extern uchar *pszPath;
/* the functions below may be called by the drivers */
rsRetVal imklogLogIntMsg(int priority, char *fmt, ...) __attribute__((format(printf,2, 3)));
diff --git a/plugins/imklog/ksym_mod.c b/plugins/imklog/ksym_mod.c
index 6e48e89e..be5fdee9 100644
--- a/plugins/imklog/ksym_mod.c
+++ b/plugins/imklog/ksym_mod.c
@@ -1,9 +1,8 @@
-/*
- * ksym_mod.c - functions for building symbol lookup tables for klogd
+/* ksym_mod.c - functions for building symbol lookup tables for klogd
* Copyright (c) 1995, 1996 Dr. G.W. Wettstein <greg@wind.rmcc.com>
* Copyright (c) 1996 Enjellic Systems Development
* Copyright (c) 1998-2007 Martin Schulze <joey@infodrom.org>
- * Copyright (C) 2007-2008 Rainer Gerhards <rgerhards@adiscon.com>
+ * Copyright (C) 2007-2009 Rainer Gerhards <rgerhards@adiscon.com>
*
* This file is part of rsyslog.
*
@@ -83,7 +82,6 @@
* Changed llseek() to lseek64() in order to skip a libc warning.
*/
-
/* Includes. */
#include "config.h"
#include <stdio.h>
@@ -112,7 +110,7 @@
#define KSYMS "/proc/kallsyms"
static int num_modules = 0;
-struct Module *sym_array_modules = (struct Module *) 0;
+struct Module *sym_array_modules = (struct Module *) NULL;
static int have_modules = 0;
@@ -266,7 +264,7 @@ static void FreeModules()
}
free(sym_array_modules);
- sym_array_modules = (struct Module *) 0;
+ sym_array_modules = (struct Module *) NULL;
num_modules = 0;
return;
}
@@ -390,11 +388,11 @@ static int AddSymbol(line)
mp->sym_array = (struct sym_table *) realloc(mp->sym_array, \
(mp->num_syms+1) * sizeof(struct sym_table));
- if ( mp->sym_array == (struct sym_table *) 0 )
+ if ( mp->sym_array == (struct sym_table *) NULL )
return(0);
mp->sym_array[mp->num_syms].name = strdup(p);
- if ( mp->sym_array[mp->num_syms].name == (char *) 0 )
+ if ( mp->sym_array[mp->num_syms].name == (char *) NULL )
return(0);
/* Stuff interesting information into the module. */
@@ -424,15 +422,21 @@ static int AddSymbol(line)
* If a match cannot be found a diagnostic string is printed.
* If a match is found the pointer to the symbolic name most
* closely matching the address is returned.
+ *
+ * TODO: We are using int values for the offset, but longs for the value
+ * values. This may create some trouble in the future (on 64 Bit OS?).
+ * Anyhow, I have not changed this, because we do not seem to have any
+ * issue and my understanding of this code is limited (and I don't see
+ * need to invest more time to dig much deeper).
+ * rgerhards, 2009-04-17
**************************************************************************/
extern char * LookupModuleSymbol(value, sym)
unsigned long value;
struct symbol *sym;
{
- auto int nmod,
- nsym;
- auto struct sym_table *last;
- auto struct Module *mp;
+ int nmod, nsym;
+ struct sym_table *last;
+ struct Module *mp;
static char ret[100];
sym->size = 0;
@@ -443,8 +447,7 @@ extern char * LookupModuleSymbol(value, sym)
for (nmod = 0; nmod < num_modules; ++nmod) {
mp = &sym_array_modules[nmod];
- /*
- * Run through the list of symbols in this module and
+ /* Run through the list of symbols in this module and
* see if the address can be resolved.
*/
for(nsym = 1, last = &mp->sym_array[0];
@@ -453,13 +456,12 @@ extern char * LookupModuleSymbol(value, sym)
if ( mp->sym_array[nsym].value > value )
{
if ( sym->size == 0 ||
- (value - last->value) < sym->offset ||
- ( (sym->offset == (value - last->value)) &&
- (mp->sym_array[nsym].value-last->value) < sym->size ) )
+ (int) (value - last->value) < sym->offset ||
+ ( (sym->offset == (int) (value - last->value)) &&
+ (int) (mp->sym_array[nsym].value-last->value) < sym->size ) )
{
sym->offset = value - last->value;
- sym->size = mp->sym_array[nsym].value - \
- last->value;
+ sym->size = mp->sym_array[nsym].value - last->value;
ret[sizeof(ret)-1] = '\0';
if ( mp->name == NULL )
snprintf(ret, sizeof(ret)-1,
@@ -478,5 +480,5 @@ extern char * LookupModuleSymbol(value, sym)
return(ret);
/* It has been a hopeless exercise. */
- return((char *) 0);
+ return(NULL);
}
diff --git a/plugins/imklog/ksyms.h b/plugins/imklog/ksyms.h
index b5362ff3..a168947b 100644
--- a/plugins/imklog/ksyms.h
+++ b/plugins/imklog/ksyms.h
@@ -2,7 +2,7 @@
* Copyright (c) 1995, 1996 Dr. G.W. Wettstein <greg@wind.rmcc.com>
* Copyright (c) 1996 Enjellic Systems Development
* Copyright (c) 2004-7 Martin Schulze <joey@infodrom.org>
- * Copyright (c) 2007-2008 Rainer Gerhards <rgerhards@adiscon.com>
+ * Copyright (c) 2007-2009 Rainer Gerhards <rgerhards@adiscon.com>
*
* This file is part of rsyslog.
*
@@ -26,7 +26,7 @@
struct symbol
{
- char *name;
+ uchar *name;
int size;
int offset;
};
diff --git a/plugins/imklog/linux.c b/plugins/imklog/linux.c
index 198b7c0e..727708a5 100644
--- a/plugins/imklog/linux.c
+++ b/plugins/imklog/linux.c
@@ -37,6 +37,7 @@
#include "msg.h"
#include "module-template.h"
#include "imklog.h"
+#include "unicode-helper.h"
/* Includes. */
@@ -84,19 +85,21 @@ static enum LOGSRC {none, proc, kernel} logsrc;
extern int ksyslog(int type, char *buf, int len);
+static uchar *GetPath(void)
+{
+ return pszPath ? pszPath : UCHAR_CONSTANT(_PATH_KLOG);
+}
+
static void CloseLogSrc(void)
{
- /* Turn on logging of messages to console, but only if we had the -c
- * option -- rgerhards, 2007-08-01
- */
- if (console_log_level != -1)
+ /* Turn on logging of messages to console, but only if a log level was speficied */
+ if(console_log_level != -1)
ksyslog(7, NULL, 0);
/* Shutdown the log sources. */
- switch ( logsrc )
- {
+ switch(logsrc) {
case kernel:
- ksyslog(0, 0, 0);
+ ksyslog(0, NULL, 0);
imklogLogIntMsg(LOG_INFO, "Kernel logging (ksyslog) stopped.");
break;
case proc:
@@ -135,7 +138,7 @@ static enum LOGSRC GetKernelLogSrc(void)
* file system is available to get kernel messages from.
*/
if ( use_syscall ||
- ((stat(_PATH_KLOG, &sb) < 0) && (errno == ENOENT)) )
+ ((stat((char*)GetPath(), &sb) < 0) && (errno == ENOENT)) )
{
/* Initialize kernel logging. */
ksyslog(1, NULL, 0);
@@ -144,14 +147,14 @@ static enum LOGSRC GetKernelLogSrc(void)
return(kernel);
}
- if ( (kmsg = open(_PATH_KLOG, O_RDONLY)) < 0 )
+ if ( (kmsg = open((char*)GetPath(), O_RDONLY|O_CLOEXEC)) < 0 )
{
imklogLogIntMsg(LOG_ERR, "imklog: Cannot open proc file system, %d.\n", errno);
- ksyslog(7, NULL, 0); /* TODO: check this, implement more */
+ ksyslog(7, NULL, 0);
return(none);
}
- imklogLogIntMsg(LOG_INFO, "imklog %s, log source = %s started.", VERSION, _PATH_KLOG);
+ imklogLogIntMsg(LOG_INFO, "imklog %s, log source = %s started.", VERSION, GetPath());
return(proc);
}
diff --git a/plugins/immark/immark.c b/plugins/immark/immark.c
index 323da3fe..8504f872 100644
--- a/plugins/immark/immark.c
+++ b/plugins/immark/immark.c
@@ -41,6 +41,7 @@
#include "cfsysline.h"
#include "module-template.h"
#include "errmsg.h"
+#include "msg.h"
MODULE_TYPE_INPUT
diff --git a/plugins/imrelp/imrelp.c b/plugins/imrelp/imrelp.c
index b01dd98b..b9e7b2f8 100644
--- a/plugins/imrelp/imrelp.c
+++ b/plugins/imrelp/imrelp.c
@@ -4,7 +4,7 @@
*
* File begun on 2008-03-13 by RGerhards
*
- * Copyright 2008 Rainer Gerhards and Adiscon GmbH.
+ * Copyright 2008, 2009 Rainer Gerhards and Adiscon GmbH.
*
* This file is part of rsyslog.
*
@@ -42,15 +42,20 @@
#include "cfsysline.h"
#include "module-template.h"
#include "net.h"
+#include "msg.h"
+#include "unicode-helper.h"
+#include "prop.h"
MODULE_TYPE_INPUT
/* static data */
DEF_IMOD_STATIC_DATA
DEFobjCurrIf(net)
+DEFobjCurrIf(prop)
/* Module static data */
static relpEngine_t *pRelpEngine; /* our relp engine */
+static prop_t *pInputName = NULL; /* there is only one global inputName for all messages generated by this module */
/* config settings */
@@ -83,8 +88,8 @@ static relpRetVal
onSyslogRcv(uchar *pHostname, uchar __attribute__((unused)) *pIP, uchar *pMsg, size_t lenMsg)
{
DEFiRet;
- parseAndSubmitMessage(pHostname, (uchar*) "[unset]", pMsg, lenMsg, MSG_PARSE_HOSTNAME,
- NOFLAG, eFLOWCTL_LIGHT_DELAY, (uchar*)"imrelp");
+ parseAndSubmitMessage(pHostname, (uchar*) "[unset]", pMsg, lenMsg, PARSE_HOSTNAME,
+ eFLOWCTL_LIGHT_DELAY, pInputName, NULL, 0);
RETiRet;
}
@@ -129,6 +134,11 @@ CODESTARTwillRun
//net.PrintAllowedSenders(2); /* TCP */
if(pRelpEngine == NULL)
ABORT_FINALIZE(RS_RET_NO_RUN);
+
+ /* we need to create the inputName property (only once during our lifetime) */
+ CHKiRet(prop.Construct(&pInputName));
+ CHKiRet(prop.SetString(pInputName, UCHAR_CONSTANT("imrelp"), sizeof("imrelp") - 1));
+ CHKiRet(prop.ConstructFinalize(pInputName));
finalize_it:
ENDwillRun
@@ -142,6 +152,9 @@ CODESTARTafterRun
net.pAllowedSenders_TCP = NULL;
}
#endif
+
+ if(pInputName != NULL)
+ prop.Destruct(&pInputName);
ENDafterRun
@@ -151,6 +164,7 @@ CODESTARTmodExit
iRet = relpEngineDestruct(&pRelpEngine);
/* release objects we used */
+ objRelease(prop, CORE_COMPONENT);
objRelease(net, LM_NET_FILENAME);
ENDmodExit
@@ -176,6 +190,7 @@ CODESTARTmodInit
CODEmodInit_QueryRegCFSLineHdlr
pRelpEngine = NULL;
/* request objects we use */
+ CHKiRet(objUse(prop, CORE_COMPONENT));
CHKiRet(objUse(net, LM_NET_FILENAME));
/* register config file handlers */
diff --git a/plugins/imtcp/imtcp.c b/plugins/imtcp/imtcp.c
index 7b3eeda5..e1f513c8 100644
--- a/plugins/imtcp/imtcp.c
+++ b/plugins/imtcp/imtcp.c
@@ -3,7 +3,7 @@
*
* File begun on 2007-12-21 by RGerhards (extracted from syslogd.c)
*
- * Copyright 2007 Rainer Gerhards and Adiscon GmbH.
+ * Copyright 2007, 2009 Rainer Gerhards and Adiscon GmbH.
*
* This file is part of rsyslog.
*
@@ -56,10 +56,12 @@
#include "dirty.h"
#include "cfsysline.h"
#include "module-template.h"
+#include "unicode-helper.h"
#include "net.h"
#include "netstrm.h"
#include "errmsg.h"
#include "tcpsrv.h"
+#include "ruleset.h"
#include "net.h" /* for permittedPeers, may be removed when this is removed */
MODULE_TYPE_INPUT
@@ -71,6 +73,7 @@ DEFobjCurrIf(tcps_sess)
DEFobjCurrIf(net)
DEFobjCurrIf(netstrm)
DEFobjCurrIf(errmsg)
+DEFobjCurrIf(ruleset)
/* Module static data */
static tcpsrv_t *pOurTcpsrv = NULL; /* our TCP server(listener) TODO: change for multiple instances */
@@ -80,7 +83,10 @@ static permittedPeers_t *pPermPeersRoot = NULL;
/* config settings */
static int iTCPSessMax = 200; /* max number of sessions */
static int iStrmDrvrMode = 0; /* mode for stream driver, driver-dependent (0 mostly means plain tcp) */
+static int iAddtlFrameDelim = TCPSRV_NO_ADDTL_DELIMITER; /* addtl frame delimiter, e.g. for netscreen, default none */
static uchar *pszStrmDrvrAuthMode = NULL; /* authentication mode to use */
+static uchar *pszInputName = NULL; /* value for inputname property, NULL is OK and handled by core engine */
+static ruleset_t *pBindRuleset = NULL; /* ruleset to bind listener to (use system default if unspecified) */
/* callbacks */
@@ -89,7 +95,7 @@ static int
isPermittedHost(struct sockaddr *addr, char *fromHostFQDN, void __attribute__((unused)) *pUsrSrv,
void __attribute__((unused)) *pUsrSess)
{
- return net.isAllowedSender((uchar*) "TCP", addr, fromHostFQDN);
+ return net.isAllowedSender(UCHAR_CONSTANT("TCP"), addr, fromHostFQDN);
}
@@ -154,6 +160,27 @@ finalize_it:
}
+/* 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("imtcp current bind ruleset %p: '%s'\n", pRuleset, pszName);
+
+finalize_it:
+ free(pszName); /* no longer needed */
+ RETiRet;
+}
+
+
static rsRetVal addTCPListener(void __attribute__((unused)) *pVal, uchar *pNewVal)
{
DEFiRet;
@@ -167,6 +194,7 @@ static rsRetVal addTCPListener(void __attribute__((unused)) *pVal, uchar *pNewVa
CHKiRet(tcpsrv.SetCBOnRegularClose(pOurTcpsrv, onRegularClose));
CHKiRet(tcpsrv.SetCBOnErrClose(pOurTcpsrv, onErrClose));
CHKiRet(tcpsrv.SetDrvrMode(pOurTcpsrv, iStrmDrvrMode));
+ CHKiRet(tcpsrv.SetAddtlFrameDelim(pOurTcpsrv, iAddtlFrameDelim));
/* now set optional params, but only if they were actually configured */
if(pszStrmDrvrAuthMode != NULL) {
CHKiRet(tcpsrv.SetDrvrAuthMode(pOurTcpsrv, pszStrmDrvrAuthMode));
@@ -174,11 +202,14 @@ static rsRetVal addTCPListener(void __attribute__((unused)) *pVal, uchar *pNewVa
if(pPermPeersRoot != NULL) {
CHKiRet(tcpsrv.SetDrvrPermPeers(pOurTcpsrv, pPermPeersRoot));
}
- /* most params set, now start listener */
- tcpsrv.configureTCPListen(pOurTcpsrv, (char *) pNewVal);
- CHKiRet(tcpsrv.ConstructFinalize(pOurTcpsrv));
}
+ /* initialized, now add socket and listener params */
+ CHKiRet(tcpsrv.SetRuleset(pOurTcpsrv, pBindRuleset));
+ CHKiRet(tcpsrv.SetInputName(pOurTcpsrv, pszInputName == NULL ?
+ UCHAR_CONSTANT("imtcp") : pszInputName));
+ tcpsrv.configureTCPListen(pOurTcpsrv, pNewVal);
+
finalize_it:
if(iRet != RS_RET_OK) {
errmsg.LogError(0, NO_ERRCODE, "error %d trying to add listener", iRet);
@@ -195,7 +226,9 @@ CODESTARTrunInput
/* TODO: we must be careful to start the listener here. Currently, tcpsrv.c seems to
* do that in ConstructFinalize
*/
+ CHKiRet(tcpsrv.ConstructFinalize(pOurTcpsrv));
iRet = tcpsrv.Run(pOurTcpsrv);
+finalize_it:
ENDrunInput
@@ -213,7 +246,7 @@ ENDwillRun
BEGINafterRun
CODESTARTafterRun
/* do cleanup here */
- net.clearAllowedSenders((uchar*)"TCP");
+ net.clearAllowedSenders(UCHAR_CONSTANT("TCP"));
ENDafterRun
@@ -232,6 +265,7 @@ CODESTARTmodExit
objRelease(tcps_sess, LM_TCPSRV_FILENAME);
objRelease(tcpsrv, LM_TCPSRV_FILENAME);
objRelease(errmsg, CORE_COMPONENT);
+ objRelease(ruleset, CORE_COMPONENT);
ENDmodExit
@@ -240,6 +274,11 @@ resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unus
{
iTCPSessMax = 200;
iStrmDrvrMode = 0;
+ iAddtlFrameDelim = TCPSRV_NO_ADDTL_DELIMITER;
+ free(pszInputName);
+ pszInputName = NULL;
+ free(pszStrmDrvrAuthMode);
+ pszStrmDrvrAuthMode = NULL;
return RS_RET_OK;
}
@@ -262,19 +301,26 @@ CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(objUse(tcps_sess, LM_TCPSRV_FILENAME));
CHKiRet(objUse(tcpsrv, LM_TCPSRV_FILENAME));
CHKiRet(objUse(errmsg, CORE_COMPONENT));
+ CHKiRet(objUse(ruleset, CORE_COMPONENT));
/* register config file handlers */
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputtcpserverrun", 0, eCmdHdlrGetWord,
+ CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserverrun"), 0, eCmdHdlrGetWord,
addTCPListener, NULL, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputtcpmaxsessions", 0, eCmdHdlrInt,
+ CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpmaxsessions"), 0, eCmdHdlrInt,
NULL, &iTCPSessMax, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputtcpserverstreamdrivermode", 0,
+ CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserverstreamdrivermode"), 0,
eCmdHdlrInt, NULL, &iStrmDrvrMode, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputtcpserverstreamdriverauthmode", 0,
+ CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserverstreamdriverauthmode"), 0,
eCmdHdlrGetWord, NULL, &pszStrmDrvrAuthMode, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputtcpserverstreamdriverpermittedpeer", 0,
+ CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserverstreamdriverpermittedpeer"), 0,
eCmdHdlrGetWord, setPermittedPeer, NULL, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler,
+ CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserveraddtlframedelimiter"), 0, eCmdHdlrInt,
+ NULL, &iAddtlFrameDelim, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserverinputname"), 0,
+ eCmdHdlrGetWord, NULL, &pszInputName, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserverbindruleset"), 0,
+ eCmdHdlrGetWord, setRuleset, NULL, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("resetconfigvariables"), 1, eCmdHdlrCustomHandler,
resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
ENDmodInit
diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c
index 79d51263..718c3090 100644
--- a/plugins/imudp/imudp.c
+++ b/plugins/imudp/imudp.c
@@ -6,7 +6,7 @@
*
* File begun on 2007-12-21 by RGerhards (extracted from syslogd.c)
*
- * Copyright 2007 Rainer Gerhards and Adiscon GmbH.
+ * Copyright 2007-2009 Rainer Gerhards and Adiscon GmbH.
*
* This file is part of rsyslog.
*
@@ -40,6 +40,11 @@
#include "srUtils.h"
#include "errmsg.h"
#include "glbl.h"
+#include "msg.h"
+#include "parser.h"
+#include "datetime.h"
+#include "prop.h"
+#include "unicode-helper.h"
MODULE_TYPE_INPUT
@@ -50,6 +55,8 @@ DEF_IMOD_STATIC_DATA
DEFobjCurrIf(errmsg)
DEFobjCurrIf(glbl)
DEFobjCurrIf(net)
+DEFobjCurrIf(datetime)
+DEFobjCurrIf(prop)
static int iMaxLine; /* maximum UDP message size supported */
static time_t ttLastDiscard = 0; /* timestamp when a message from a non-permitted sender was last discarded
@@ -63,6 +70,10 @@ static uchar *pRcvBuf = NULL; /* receive buffer (for a single packet). We use a
* it so that we can check available memory in willRun() and request
* termination if we can not get it. -- rgerhards, 2007-12-27
*/
+static prop_t *pInputName = NULL; /* our inputName currently is always "imudp", and this will hold it */
+// TODO: static ruleset_t *pBindRuleset = NULL; /* ruleset to bind listener to (use system default if unspecified) */
+#define TIME_REQUERY_DFLT 2
+static int iTimeRequery = TIME_REQUERY_DFLT;/* how often is time to be queried inside tight recv loop? 0=always */
/* config settings */
@@ -90,7 +101,7 @@ static rsRetVal addListner(void __attribute__((unused)) *pVal, uchar *pNewVal)
else
bindAddr = pszBindAddr;
- dbgprintf("Trying to open syslog UDP ports at %s:%s.\n",
+ DBGPRINTF("Trying to open syslog UDP ports at %s:%s.\n",
(bindAddr == NULL) ? (uchar*)"*" : bindAddr, pNewVal);
newSocks = net.create_udp_socket(bindAddr, (pNewVal == NULL || *pNewVal == '\0') ? (uchar*) "514" : pNewVal, 1);
@@ -130,20 +141,161 @@ finalize_it:
}
+#if 0 /* TODO: implement when tehre is time, requires restructure of socket array! */
+/* 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("imudp current bind ruleset %p: '%s'\n", pRuleset, pszName);
+
+finalize_it:
+ free(pszName); /* no longer needed */
+ RETiRet;
+}
+#endif
+
+
+/* This function is a helper to runInput. I have extracted it
+ * from the main loop just so that we do not have that large amount of code
+ * in a single place. This function takes a socket and pulls messages from
+ * it until the socket does not have any more waiting.
+ * rgerhards, 2008-01-08
+ * We try to read from the file descriptor until there
+ * is no more data. This is done in the hope to get better performance
+ * out of the system. However, this also means that a descriptor
+ * monopolizes processing while it contains data. This can lead to
+ * data loss in other descriptors. However, if the system is incapable of
+ * handling the workload, we will loss data in any case. So it doesn't really
+ * matter where the actual loss occurs - it is always random, because we depend
+ * on scheduling order. -- rgerhards, 2008-10-02
+ */
+static inline rsRetVal
+processSocket(int fd, struct sockaddr_storage *frominetPrev, int *pbIsPermitted,
+ uchar *fromHost, uchar *fromHostFQDN, uchar *fromHostIP)
+{
+ DEFiRet;
+ int iNbrTimeUsed;
+ time_t ttGenTime;
+ struct syslogTime stTime;
+ socklen_t socklen;
+ ssize_t lenRcvBuf;
+ struct sockaddr_storage frominet;
+ msg_t *pMsg;
+ prop_t *propFromHost = NULL;
+ prop_t *propFromHostIP = NULL;
+ char errStr[1024];
+
+ iNbrTimeUsed = 0;
+ while(1) { /* loop is terminated if we have a bad receive, done below in the body */
+ socklen = sizeof(struct sockaddr_storage);
+ lenRcvBuf = recvfrom(fd, (char*) pRcvBuf, iMaxLine, 0, (struct sockaddr *)&frominet, &socklen);
+ if(lenRcvBuf < 0) {
+ if(errno != EINTR && errno != EAGAIN) {
+ rs_strerror_r(errno, errStr, sizeof(errStr));
+ DBGPRINTF("INET socket error: %d = %s.\n", errno, errStr);
+ errmsg.LogError(errno, NO_ERRCODE, "recvfrom inet");
+ }
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+
+ /* if we reach this point, we had a good receive and can process the packet received */
+ /* check if we have a different sender than before, if so, we need to query some new values */
+ if(memcmp(&frominet, frominetPrev, socklen) != 0) {
+ CHKiRet(net.cvthname(&frominet, fromHost, fromHostFQDN, fromHostIP));
+ memcpy(frominetPrev, &frominet, socklen); /* update cache indicator */
+ /* Here we check if a host is permitted to send us
+ * syslog messages. If it isn't, we do not further
+ * process the message but log a warning (if we are
+ * configured to do this).
+ * rgerhards, 2005-09-26
+ */
+ *pbIsPermitted = net.isAllowedSender((uchar*)"UDP",
+ (struct sockaddr *)&frominet, (char*)fromHostFQDN);
+
+ if(!*pbIsPermitted) {
+ DBGPRINTF("%s is not an allowed sender\n", (char*)fromHostFQDN);
+ if(glbl.GetOption_DisallowWarning) {
+ time_t tt;
+
+ time(&tt);
+ if(tt > ttLastDiscard + 60) {
+ ttLastDiscard = tt;
+ errmsg.LogError(0, NO_ERRCODE,
+ "UDP message from disallowed sender %s discarded",
+ (char*)fromHost);
+ }
+ }
+ }
+ }
+
+ DBGPRINTF("recv(%d,%d)/%s,acl:%d,msg:%.80s\n", fd, (int) lenRcvBuf, fromHost, *pbIsPermitted, pRcvBuf);
+
+ if(*pbIsPermitted) {
+ if((iTimeRequery == 0) || (iNbrTimeUsed++ % iTimeRequery) == 0) {
+ datetime.getCurrTime(&stTime, &ttGenTime);
+ }
+ /* we now create our own message object and submit it to the queue */
+ CHKiRet(msgConstructWithTime(&pMsg, &stTime, ttGenTime));
+ MsgSetRawMsg(pMsg, (char*)pRcvBuf, lenRcvBuf);
+ MsgSetInputName(pMsg, pInputName);
+ MsgSetFlowControlType(pMsg, eFLOWCTL_NO_DELAY);
+ pMsg->msgFlags = NEEDS_PARSING | PARSE_HOSTNAME;
+ pMsg->bParseHOSTNAME = 1;
+ MsgSetRcvFromStr(pMsg, fromHost, ustrlen(fromHost), &propFromHost);
+ CHKiRet(MsgSetRcvFromIPStr(pMsg, fromHostIP, ustrlen(fromHostIP), &propFromHostIP));
+ CHKiRet(submitMsg(pMsg));
+ }
+ }
+
+finalize_it:
+ if(propFromHost != NULL)
+ prop.Destruct(&propFromHost);
+ if(propFromHostIP != NULL)
+ prop.Destruct(&propFromHostIP);
+
+ RETiRet;
+}
+
+
/* This function is called to gather input.
+ * Note that udpLstnSocks must be non-NULL because otherwise we would not have
+ * indicated that we want to run (or we have a programming error ;)). -- rgerhards, 2008-10-02
+ * rgerhards, 2008-10-07: I have implemented a very simple, yet in most cases probably
+ * highly efficient "name caching". Before querying a name, I now check if the name to be
+ * queried is the same as the one queried in the last message processed. If that is the
+ * case, we can simple re-use the previous value. This algorithm works quite well with
+ * few sender, especially if they emit messages in bursts. The more sender and the
+ * more intermixed messages arrive, the less this algorithm works, but the overhead
+ * is so minimal (a simple memory compare and move) that this does not hurt. Even
+ * with a real name lookup cache, this optimization here is useful as it is quicker
+ * than even a cache lookup).
*/
BEGINrunInput
int maxfds;
int nfds;
int i;
fd_set readfds;
- struct sockaddr_storage frominet;
- socklen_t socklen;
+ struct sockaddr_storage frominetPrev;
+ int bIsPermitted;
uchar fromHost[NI_MAXHOST];
uchar fromHostIP[NI_MAXHOST];
uchar fromHostFQDN[NI_MAXHOST];
- ssize_t l;
CODESTARTrunInput
+ /* start "name caching" algo by making sure the previous system indicator
+ * is invalidated.
+ */
+ bIsPermitted = 0;
+ memset(&frominetPrev, 0, sizeof(frominetPrev));
/* this is an endless loop - it is terminated when the thread is
* signalled to do so. This, however, is handled by the framework,
* right into the sleep below.
@@ -158,17 +310,14 @@ CODESTARTrunInput
maxfds = 0;
FD_ZERO (&readfds);
- /* Add the UDP listen sockets to the list of read descriptors.
- */
- if(udpLstnSocks != NULL) {
- for (i = 0; i < *udpLstnSocks; i++) {
- if (udpLstnSocks[i+1] != -1) {
- if(Debug)
- net.debugListenInfo(udpLstnSocks[i+1], "UDP");
- FD_SET(udpLstnSocks[i+1], &readfds);
- if(udpLstnSocks[i+1]>maxfds) maxfds=udpLstnSocks[i+1];
- }
- }
+ /* Add the UDP listen sockets to the list of read descriptors. */
+ for (i = 0; i < *udpLstnSocks; i++) {
+ if (udpLstnSocks[i+1] != -1) {
+ if(Debug)
+ net.debugListenInfo(udpLstnSocks[i+1], "UDP");
+ FD_SET(udpLstnSocks[i+1], &readfds);
+ if(udpLstnSocks[i+1]>maxfds) maxfds=udpLstnSocks[i+1];
+ }
}
if(Debug) {
dbgprintf("--------imUDP calling select, active file descriptors (max %d): ", maxfds);
@@ -181,53 +330,14 @@ CODESTARTrunInput
/* wait for io to become ready */
nfds = select(maxfds+1, (fd_set *) &readfds, NULL, NULL, NULL);
- if(udpLstnSocks != NULL) {
- for (i = 0; nfds && i < *udpLstnSocks; i++) {
- if (FD_ISSET(udpLstnSocks[i+1], &readfds)) {
- socklen = sizeof(frominet);
- l = recvfrom(udpLstnSocks[i+1], (char*) pRcvBuf, iMaxLine, 0,
- (struct sockaddr *)&frominet, &socklen);
- if (l > 0) {
- if(net.cvthname(&frominet, fromHost, fromHostFQDN, fromHostIP) == RS_RET_OK) {
- dbgprintf("Message from inetd socket: #%d, host: %s\n",
- udpLstnSocks[i+1], fromHost);
- /* Here we check if a host is permitted to send us
- * syslog messages. If it isn't, we do not further
- * process the message but log a warning (if we are
- * configured to do this).
- * rgerhards, 2005-09-26
- */
- if(net.isAllowedSender((uchar*) "UDP",
- (struct sockaddr *)&frominet, (char*)fromHostFQDN)) {
- parseAndSubmitMessage(fromHost, fromHostIP, pRcvBuf, l,
- MSG_PARSE_HOSTNAME, NOFLAG, eFLOWCTL_NO_DELAY, (uchar*)"imudp");
- } else {
- dbgprintf("%s is not an allowed sender\n", (char*)fromHostFQDN);
- if(glbl.GetOption_DisallowWarning) {
- time_t tt;
-
- time(&tt);
- if(tt > ttLastDiscard + 60) {
- ttLastDiscard = tt;
- errmsg.LogError(0, NO_ERRCODE,
- "UDP message from disallowed sender %s discarded",
- (char*)fromHost);
- }
- }
- }
- }
- } else if (l < 0 && errno != EINTR && errno != EAGAIN) {
- char errStr[1024];
- rs_strerror_r(errno, errStr, sizeof(errStr));
- dbgprintf("INET socket error: %d = %s.\n", errno, errStr);
- errmsg.LogError(errno, NO_ERRCODE, "recvfrom inet");
- /* should be harmless */
- sleep(1);
- }
- --nfds; /* indicate we have processed one */
- }
- }
- }
+ for(i = 0; nfds && i < *udpLstnSocks; i++) {
+ if(FD_ISSET(udpLstnSocks[i+1], &readfds)) {
+ processSocket(udpLstnSocks[i+1], &frominetPrev, &bIsPermitted,
+ fromHost, fromHostFQDN, fromHostIP);
+ --nfds; /* indicate we have processed one descriptor */
+ }
+ }
+ /* end of a run, back to loop for next recv() */
}
return iRet;
@@ -237,6 +347,11 @@ ENDrunInput
/* initialize and return if will run or not */
BEGINwillRun
CODESTARTwillRun
+ /* we need to create the inputName property (only once during our lifetime) */
+ CHKiRet(prop.Construct(&pInputName));
+ CHKiRet(prop.SetString(pInputName, UCHAR_CONSTANT("imudp"), sizeof("imudp") - 1));
+ CHKiRet(prop.ConstructFinalize(pInputName));
+
net.PrintAllowedSenders(1); /* UDP */
/* if we could not set up any listners, there is no point in running... */
@@ -264,6 +379,8 @@ CODESTARTafterRun
free(pRcvBuf);
pRcvBuf = NULL;
}
+ if(pInputName != NULL)
+ prop.Destruct(&pInputName);
ENDafterRun
@@ -272,6 +389,8 @@ CODESTARTmodExit
/* release what we no longer need */
objRelease(errmsg, CORE_COMPONENT);
objRelease(glbl, CORE_COMPONENT);
+ objRelease(datetime, CORE_COMPONENT);
+ objRelease(prop, CORE_COMPONENT);
objRelease(net, LM_NET_FILENAME);
ENDmodExit
@@ -291,6 +410,7 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a
net.closeUDPListenSockets(udpLstnSocks);
udpLstnSocks = NULL;
}
+ iTimeRequery = TIME_REQUERY_DFLT;/* the default is to query only every second time */
return RS_RET_OK;
}
@@ -301,16 +421,23 @@ CODESTARTmodInit
CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(objUse(errmsg, CORE_COMPONENT));
CHKiRet(objUse(glbl, CORE_COMPONENT));
+ CHKiRet(objUse(datetime, CORE_COMPONENT));
+ CHKiRet(objUse(prop, CORE_COMPONENT));
CHKiRet(objUse(net, LM_NET_FILENAME));
/* register config file handlers */
+ /* TODO: add - but this requires more changes, no time right now...
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"udpserverbindruleset", 0, eCmdHdlrGetWord,
+ setRuleset, NULL, STD_LOADABLE_MODULE_ID));
+ */
CHKiRet(omsdRegCFSLineHdlr((uchar *)"udpserverrun", 0, eCmdHdlrGetWord,
addListner, NULL, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"udpserveraddress", 0, eCmdHdlrGetWord,
NULL, &pszBindAddr, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"udpservertimerequery", 0, eCmdHdlrInt,
+ NULL, &iTimeRequery, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler,
resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
ENDmodInit
-/*
- * vi:set ai:
+/* vim:set ai:
*/
diff --git a/plugins/imuxsock/imuxsock.c b/plugins/imuxsock/imuxsock.c
index 55b8b2df..6d60efaf 100644
--- a/plugins/imuxsock/imuxsock.c
+++ b/plugins/imuxsock/imuxsock.c
@@ -37,11 +37,14 @@
#include <sys/un.h>
#include "dirty.h"
#include "cfsysline.h"
+#include "unicode-helper.h"
#include "module-template.h"
#include "srUtils.h"
#include "errmsg.h"
#include "net.h"
#include "glbl.h"
+#include "msg.h"
+#include "prop.h"
MODULE_TYPE_INPUT
@@ -65,7 +68,9 @@ MODULE_TYPE_INPUT
DEF_IMOD_STATIC_DATA
DEFobjCurrIf(errmsg)
DEFobjCurrIf(glbl)
+DEFobjCurrIf(prop)
+static prop_t *pInputName = NULL; /* our inputName currently is always "imudp", and this will hold it */
static int startIndexUxLocalSockets; /* process funix from that index on (used to
* suppress local logging. rgerhards 2005-08-01
* read-only after startup
@@ -221,7 +226,8 @@ static rsRetVal readSocket(int fd, int iSock)
if (iRcvd > 0) {
parseAndSubmitMessage(funixHName[iSock] == NULL ? glbl.GetLocalHostName() : funixHName[iSock],
(uchar*)"127.0.0.1", pRcv,
- iRcvd, funixParseHost[iSock], funixFlags[iSock], funixFlowCtl[iSock], (uchar*)"imuxsock");
+ iRcvd, funixParseHost[iSock] ? (funixFlags[iSock] | PARSE_HOSTNAME) : funixFlags[iSock],
+ funixFlowCtl[iSock], pInputName, NULL, 0);
} else if (iRcvd < 0 && errno != EINTR) {
char errStr[1024];
rs_strerror_r(errno, errStr, sizeof(errStr));
@@ -304,7 +310,12 @@ CODESTARTwillRun
dbgprintf("Opened UNIX socket '%s' (fd %d).\n", funixn[i], funix[i]);
}
- RETiRet;
+ /* we need to create the inputName property (only once during our lifetime) */
+ CHKiRet(prop.Construct(&pInputName));
+ CHKiRet(prop.SetString(pInputName, UCHAR_CONSTANT("imudp"), sizeof("imudp") - 1));
+ CHKiRet(prop.ConstructFinalize(pInputName));
+
+finalize_it:
ENDwillRun
@@ -322,14 +333,14 @@ CODESTARTafterRun
if (funixn[i] && funix[i] != -1)
unlink((char*) funixn[i]);
/* free no longer needed string */
- if(pLogSockName != NULL)
- free(pLogSockName);
- if(pLogHostName != NULL) {
- free(pLogHostName);
- }
+ free(pLogSockName);
+ free(pLogHostName);
discardFunixn();
nfunix = 1;
+
+ if(pInputName != NULL)
+ prop.Destruct(&pInputName);
ENDafterRun
@@ -337,6 +348,7 @@ BEGINmodExit
CODESTARTmodExit
objRelease(glbl, CORE_COMPONENT);
objRelease(errmsg, CORE_COMPONENT);
+ objRelease(prop, CORE_COMPONENT);
ENDmodExit
@@ -373,6 +385,7 @@ CODESTARTmodInit
CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(objUse(errmsg, CORE_COMPONENT));
CHKiRet(objUse(glbl, CORE_COMPONENT));
+ CHKiRet(objUse(prop, CORE_COMPONENT));
dbgprintf("imuxsock version %s initializing\n", PACKAGE_VERSION);
diff --git a/plugins/omgssapi/omgssapi.c b/plugins/omgssapi/omgssapi.c
index e0cc8af6..7b5a46e1 100644
--- a/plugins/omgssapi/omgssapi.c
+++ b/plugins/omgssapi/omgssapi.c
@@ -44,6 +44,7 @@
#include <pthread.h>
#include <gssapi/gssapi.h>
#include "dirty.h"
+#include "conf.h"
#include "syslogd-types.h"
#include "srUtils.h"
#include "net.h"
@@ -444,7 +445,7 @@ CODESTARTdoAction
/* error! */
dbgprintf("error forwarding via tcp, suspending\n");
pData->eDestState = eDestFORW_SUSP;
- iRet = RS_RET_SUSPENDED;
+ ABORT_FINALIZE(RS_RET_SUSPENDED);
}
break;
}
diff --git a/plugins/ommail/ommail.c b/plugins/ommail/ommail.c
index 5faadce3..3a7669c9 100644
--- a/plugins/ommail/ommail.c
+++ b/plugins/ommail/ommail.c
@@ -44,7 +44,7 @@
#include <netdb.h>
#include <time.h>
#include <sys/socket.h>
-#include "dirty.h"
+#include "conf.h"
#include "syslogd-types.h"
#include "srUtils.h"
#include "cfsysline.h"
diff --git a/plugins/ommysql/ommysql.c b/plugins/ommysql/ommysql.c
index ecf738a9..d6870a7b 100644
--- a/plugins/ommysql/ommysql.c
+++ b/plugins/ommysql/ommysql.c
@@ -36,7 +36,7 @@
#include <errno.h>
#include <time.h>
#include <mysql.h>
-#include "dirty.h"
+#include "conf.h"
#include "syslogd-types.h"
#include "srUtils.h"
#include "template.h"
diff --git a/plugins/omoracle/Makefile.am b/plugins/omoracle/Makefile.am
new file mode 100644
index 00000000..11257fb2
--- /dev/null
+++ b/plugins/omoracle/Makefile.am
@@ -0,0 +1,8 @@
+pkglib_LTLIBRARIES = omoracle.la
+
+omoracle_la_SOURCES = omoracle.c omoracle.h
+omoracle_la_CPPFLAGS = $(RSRT_CFLAGS) $(PTHREADS_CFLAGS) $(ORACLE_CFLAGS)
+omoracle_la_LDFLAGS = -module -avoid-version
+omoracle_la_LIBADD = $(ORACLE_LIBS)
+
+#EXTRA_DIST =
diff --git a/plugins/omoracle/omoracle.c b/plugins/omoracle/omoracle.c
new file mode 100644
index 00000000..331b7dd4
--- /dev/null
+++ b/plugins/omoracle/omoracle.c
@@ -0,0 +1,572 @@
+/** omoracle.c
+
+ This is an output module feeding directly to an Oracle
+ database. It uses Oracle Call Interface, a propietary module
+ provided by Oracle.
+
+ Selector lines to be used are of this form:
+
+ :omoracle:;TemplateName
+
+ The module gets its configuration via rsyslog $... directives,
+ namely:
+
+ $OmoracleDBUser: user name to log in on the database.
+
+ $OmoracleDBPassword: password to log in on the database.
+
+ $OmoracleDB: connection string (an Oracle easy connect or a db
+ name as specified by tnsnames.ora)
+
+ $OmoracleBatchSize: Number of elements to send to the DB on each
+ transaction.
+
+ $OmoracleBatchItemSize: Number of characters each property may
+ have. Make it as big as the longest value you expect for *any*
+ property in the sentence. For instance, if you expect 5 arguments
+ to the statement, 4 have 10 bytes and the 5th may be up to 3KB,
+ then specify $OmoracleBatchItemSize 3072. Please, remember to
+ leave space to the trailing \0!!
+
+ $OmoracleStatementTemplate: Name of the template containing the
+ statement to be prepared and executed in batches. Please note that
+ Oracle's prepared statements have their placeholders as
+ ':identifier', and this module uses the colon to guess how many
+ placeholders there will be.
+
+ All these directives are mandatory. The dbstring can be an Oracle
+ easystring or a DB name, as present in the tnsnames.ora file.
+
+ The form of the template is just a list of strings you want
+ inserted to the DB, for instance:
+
+ $template TestStmt,"%hostname%%msg%"
+
+ Will provide the arguments to a statement like
+
+ $OmoracleStatement \
+ insert into foo(hostname,message)values(:host,:message)
+
+ Also note that identifiers to placeholders are arbitrarry. You
+ need to define the properties on the template in the correct order
+ you want them passed to the statement!
+
+ This file is licensed under the terms of the GPL version 3 or, at
+ your choice, any later version. Exceptionally (perhaps), you are
+ allowed to link to the Oracle Call Interface in your derived work
+
+ Author: Luis Fernando Muñoz Mejías
+ <Luis.Fernando.Munoz.Mejias@cern.ch>
+
+ This file is part of rsyslog.
+*/
+#include "config.h"
+#include "rsyslog.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <oci.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <time.h>
+#include <assert.h>
+#include <ctype.h>
+#include "dirty.h"
+#include "syslogd-types.h"
+#include "srUtils.h"
+#include "template.h"
+#include "module-template.h"
+#include "errmsg.h"
+#include "cfsysline.h"
+#include "omoracle.h"
+
+MODULE_TYPE_OUTPUT
+
+/** */
+DEF_OMOD_STATIC_DATA
+DEFobjCurrIf(errmsg)
+
+/** */
+struct oracle_batch
+{
+ /* Batch size */
+ int size;
+ /* Last element inserted in the buffer. The batch will be
+ * executed when n == size */
+ int n;
+ /* Number of arguments the statement takes */
+ int arguments;
+ /** Maximum size of each parameter */
+ int param_size;
+ /* Parameters to pass to the statement on this transaction */
+ char*** parameters;
+ /* Binding parameters */
+ OCIBind** bindings;
+};
+
+typedef struct _instanceData {
+ /* Environment handler, the base for any OCI work. */
+ OCIEnv* environment;
+ /* Session handler, the actual DB connection object. */
+ OCISession* session;
+ /* Error handler for OCI calls. */
+ OCIError* error;
+ /* Prepared statement. */
+ OCIStmt* statement;
+ /* Service handler. */
+ OCISvcCtx* service;
+ /* Credentials object for the connection. */
+ OCIAuthInfo* authinfo;
+ /* Connection string, kept here for possible retries. */
+ char* connection;
+ /* Statement to be prepared. */
+ char* txt_statement;
+ /* Batch */
+ struct oracle_batch batch;
+} instanceData;
+
+/** Database name, to be filled by the $OmoracleDB directive */
+static char* db_name;
+/** Database user name, to be filled by the $OmoracleDBUser
+ * directive */
+static char* db_user;
+/** Database password, to be filled by the $OmoracleDBPassword */
+static char* db_password;
+/** Batch size. */
+static int batch_size;
+/** Size of each element in the batch. */
+static int batch_item_size;
+/** Statement to prepare and execute */
+static char* db_statement;
+
+/** Generic function for handling errors from OCI.
+
+ It will be called only inside CHECKERR and CHECKENV macros.
+
+ Arguments: handle The error or environment handle to check.
+ htype: OCI_HTYPE_* constant, usually OCI_HTYPE_ERROR or
+ OCI_HTYPE_ENV
+ status: status code to check, usually the return value of an OCI
+ function.
+
+ Returns OCI_SUCCESS on success, OCI_ERROR otherwise.
+*/
+static int oci_errors(void* handle, ub4 htype, sword status)
+{
+ sb4 errcode;
+ unsigned char buf[MAX_BUFSIZE];
+
+ switch (status) {
+ case OCI_SUCCESS:
+ return OCI_SUCCESS;
+ break;
+ case OCI_SUCCESS_WITH_INFO:
+ errmsg.LogError(0, NO_ERRCODE, "OCI SUCCESS - With info\n");
+ break;
+ case OCI_NEED_DATA:
+ errmsg.LogError(0, NO_ERRCODE, "OCI NEEDS MORE DATA\n");
+ break;
+ case OCI_ERROR:
+ dbgprintf ("OCI GENERAL ERROR\n");
+ if (handle) {
+ OCIErrorGet(handle, 1, NULL, &errcode, buf,
+ sizeof buf, htype);
+ errmsg.LogError(0, NO_ERRCODE, "Error message: %s", buf);
+ } else
+ errmsg.LogError(0, NO_ERRCODE, "NULL handle\n"
+ "Unable to extract further "
+ "information");
+ break;
+ case OCI_INVALID_HANDLE:
+ errmsg.LogError(0, NO_ERRCODE, "OCI INVALID HANDLE\n");
+ break;
+ case OCI_STILL_EXECUTING:
+ errmsg.LogError(0, NO_ERRCODE, "Still executing...\n");
+ break;
+ case OCI_CONTINUE:
+ errmsg.LogError(0, NO_ERRCODE, "OCI CONTINUE\n");
+ break;
+ }
+ return OCI_ERROR;
+}
+
+/** Callback for OCIBindDynamic.
+ *
+ * OCI doesn't insert an array of char* by itself (although it can
+ * handle arrays of int), so we must either run in batches of size one
+ * (no way) or bind all parameters with OCI_DATA_AT_EXEC instead of
+ * OCI_DEFAULT, and then give this function as an argument to
+ * OCIBindDynamic so that it is able to handle all strings in a single
+ * server trip.
+ *
+ * See the documentation of OCIBindDynamic
+ * (http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28395/oci16rel003.htm#i444015)
+ * for more details.
+ */
+static int bind_dynamic (char** in, OCIBind __attribute__((unused))* bind,
+ int iter, int __attribute__((unused)) idx,
+ char** out, int* buflen, unsigned char* piece,
+ void** bd)
+{
+ *out = in[iter];
+ *buflen = strlen(*out) + 1;
+ dbgprintf ("omoracle bound line %d, length %d: %s\n", iter, *buflen,
+ *out);
+ *piece = OCI_ONE_PIECE;
+ *bd = NULL;
+ return OCI_CONTINUE;
+}
+
+
+/** Returns the number of bind parameters for the statement given as
+ * an argument. It counts the number of appearances of ':', as in
+ *
+ * insert into foo(bar, baz) values(:bar, :baz)
+ *
+ * while taking in account that string literals must not be parsed. */
+static int count_bind_parameters(char* p)
+{
+ int n = 0;
+ int enable = 1;
+
+ for (; *p; p++)
+ if (enable && *p == BIND_MARK )
+ n++;
+ else if (*p == '\'')
+ enable ^= 1;
+ dbgprintf ("omoracle statement has %d parameters\n", n);
+ return n;
+}
+
+/** Prepares the statement, binding all its positional parameters */
+static int prepare_statement(instanceData* pData)
+{
+ int i;
+ DEFiRet;
+
+ CHECKERR(pData->error,
+ OCIStmtPrepare(pData->statement,
+ pData->error,
+ pData->txt_statement,
+ strlen(pData->txt_statement),
+ OCI_NTV_SYNTAX, OCI_DEFAULT));
+ for (i = 0; i < pData->batch.arguments; i++) {
+ CHECKERR(pData->error,
+ OCIBindByPos(pData->statement,
+ pData->batch.bindings+i,
+ pData->error, i+1, NULL,
+ pData->batch.param_size,
+ SQLT_STR, NULL, NULL, NULL,
+ 0, 0, OCI_DATA_AT_EXEC));
+ CHECKERR(pData->error,
+ OCIBindDynamic(pData->batch.bindings[i],
+ pData->error,
+ pData->batch.parameters[i],
+ bind_dynamic, NULL, NULL));
+ }
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* Resource allocation */
+BEGINcreateInstance
+ int i, j;
+ struct template* tpl;
+CODESTARTcreateInstance
+
+ ASSERT(pData != NULL);
+
+ CHECKENV(pData->environment,
+ OCIEnvCreate((void*) &(pData->environment), OCI_DEFAULT,
+ NULL, NULL, NULL, NULL, 0, NULL));
+ CHECKENV(pData->environment,
+ OCIHandleAlloc(pData->environment, (void*) &(pData->error),
+ OCI_HTYPE_ERROR, 0, NULL));
+ CHECKENV(pData->environment,
+ OCIHandleAlloc(pData->environment, (void*) &(pData->authinfo),
+ OCI_HTYPE_AUTHINFO, 0, NULL));
+ CHECKENV(pData->environment,
+ OCIHandleAlloc(pData->environment, (void*) &(pData->statement),
+ OCI_HTYPE_STMT, 0, NULL));
+ tpl = tplFind(db_statement, strlen(db_statement));
+ pData->txt_statement = strdup(tpl->pEntryRoot->data.constant.pConstant);
+ CHKmalloc(pData->txt_statement);
+ dbgprintf("omoracle will run stored statement: %s\n",
+ pData->txt_statement);
+
+ pData->batch.n = 0;
+ pData->batch.size = batch_size;
+ pData->batch.param_size = batch_item_size *
+ sizeof ***pData->batch.parameters;
+ pData->batch.arguments = count_bind_parameters(pData->txt_statement);
+
+ /* I know, this can be done with a single malloc() call but this is
+ * easier to read. :) */
+ pData->batch.parameters = calloc(pData->batch.arguments,
+ sizeof *pData->batch.parameters);
+ CHKmalloc(pData->batch.parameters);
+ for (i = 0; i < pData->batch.arguments; i++) {
+ pData->batch.parameters[i] = calloc(pData->batch.size,
+ sizeof **pData->batch.parameters);
+ CHKmalloc(pData->batch.parameters[i]);
+ for (j = 0; j < pData->batch.size; j++) {
+ /* Each entry has at most
+ * pData->batch.param_size bytes because OCI
+ * doesn't like null-terminated strings when
+ * operating with batches, and the maximum
+ * size of each entry must be provided when
+ * binding parameters. pData->batch.param_size
+ * is long enough for usual entries. */
+ pData->batch.parameters[i][j] = malloc(pData->batch.param_size);
+ CHKmalloc(pData->batch.parameters[i][j]);
+ }
+ }
+
+ pData->batch.bindings = calloc(pData->batch.arguments,
+ sizeof *pData->batch.bindings);
+ CHKmalloc(pData->batch.bindings);
+
+finalize_it:
+ENDcreateInstance
+
+/* Inserts all stored statements into the database, releasing any
+ * allocated memory. */
+static int insert_to_db(instanceData* pData)
+{
+ DEFiRet;
+
+ CHECKERR(pData->error,
+ OCIStmtExecute(pData->service,
+ pData->statement,
+ pData->error,
+ pData->batch.n, 0, NULL, NULL,
+ OCI_BATCH_ERRORS));
+
+finalize_it:
+ pData->batch.n = 0;
+ OCITransCommit(pData->service, pData->error, 0);
+ dbgprintf ("omoracle insertion to DB %s\n", iRet == RS_RET_OK ?
+ "succeeded" : "did not succeed");
+ RETiRet;
+}
+
+/** Close the session and free anything allocated by
+ createInstance. */
+BEGINfreeInstance
+ int i, j;
+CODESTARTfreeInstance
+
+/* Before actually releasing our resources, let's try to commit
+ * anything pending so that we don't lose any messages. */
+ insert_to_db(pData);
+ OCISessionRelease(pData->service, pData->error, NULL, 0, OCI_DEFAULT);
+ OCIHandleFree(pData->environment, OCI_HTYPE_ENV);
+ OCIHandleFree(pData->error, OCI_HTYPE_ERROR);
+ OCIHandleFree(pData->service, OCI_HTYPE_SVCCTX);
+ OCIHandleFree(pData->authinfo, OCI_HTYPE_AUTHINFO);
+ OCIHandleFree(pData->statement, OCI_HTYPE_STMT);
+ free(pData->connection);
+ free(pData->txt_statement);
+ for (i = 0; i < pData->batch.arguments; i++) {
+ for (j = 0; j < pData->batch.size; j++)
+ free(pData->batch.parameters[i][j]);
+ free(pData->batch.parameters[i]);
+ }
+ free(pData->batch.parameters);
+ free(pData->batch.bindings);
+ dbgprintf ("omoracle freed all its resources\n");
+
+ENDfreeInstance
+
+BEGINtryResume
+CODESTARTtryResume
+ /* Here usually only a reconnect is done. The rsyslog core will call
+ * this entry point from time to time when the action suspended itself.
+ * Note that the rsyslog core expects that if the plugin suspended itself
+ * the action was not carried out during that invocation. Thus, rsyslog
+ * will call the action with *the same* data item again AFTER a resume
+ * was successful. As such, tryResume should NOT write the failed data
+ * item. If it needs to for some reason, it must delete the item again,
+ * otherwise, it will get duplicated.
+ * This handling inside the rsyslog core is important to be able to
+ * preserve data over rsyslog restarts. With it, the core can ensure that
+ * it queues all not-yet-processed messages without the plugin needing
+ * to take care about that.
+ * So in essence, it is recommended that just a reconnet is tried, but
+ * the last action not restarted. Note that it is not a real problem
+ * (but causes a slight performance degradation) if tryResume returns
+ * successfully but the next call to doAction() immediately returns
+ * RS_RET_SUSPENDED. So it is OK to do the actual restart inside doAction().
+ * ... of course I don't know why Oracle might need a full restart...
+ * rgerhards, 2009-03-26
+ */
+ dbgprintf("omoracle attempting to reconnect to DB server\n");
+ OCISessionRelease(pData->service, pData->error, NULL, 0, OCI_DEFAULT);
+ OCIHandleFree(pData->service, OCI_HTYPE_SVCCTX);
+ CHECKERR(pData->error, OCISessionGet(pData->environment, pData->error,
+ &pData->service, pData->authinfo,
+ pData->connection,
+ strlen(pData->connection), NULL, 0,
+ NULL, NULL, NULL, OCI_DEFAULT));
+ CHKiRet(prepare_statement(pData));
+
+finalize_it:
+ENDtryResume
+
+static rsRetVal startSession(instanceData* pData, char* connection, char* user,
+ char * password)
+{
+ DEFiRet;
+ CHECKERR(pData->error,
+ OCIAttrSet(pData->authinfo, OCI_HTYPE_AUTHINFO, user,
+ strlen(user), OCI_ATTR_USERNAME, pData->error));
+ CHECKERR(pData->error,
+ OCIAttrSet(pData->authinfo, OCI_HTYPE_AUTHINFO, password,
+ strlen(password), OCI_ATTR_PASSWORD, pData->error));
+ CHECKERR(pData->error,
+ OCISessionGet(pData->environment, pData->error,
+ &pData->service, pData->authinfo, connection,
+ strlen(connection), NULL, 0, NULL, NULL, NULL,
+ OCI_DEFAULT));
+finalize_it:
+ if (iRet != RS_RET_OK)
+ errmsg.LogError(0, NO_ERRCODE,
+ "Unable to start Oracle session\n");
+ RETiRet;
+}
+
+
+BEGINisCompatibleWithFeature
+CODESTARTisCompatibleWithFeature
+ /* Right now, this module is compatible with nothing. */
+ iRet = RS_RET_INCOMPATIBLE;
+ENDisCompatibleWithFeature
+
+BEGINparseSelectorAct
+CODESTARTparseSelectorAct
+CODE_STD_STRING_REQUESTparseSelectorAct(1);
+
+ if (strncmp((char*) p, ":omoracle:", sizeof ":omoracle:" - 1)) {
+ ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED);
+ }
+
+ p += sizeof ":omoracle:" - 1;
+
+ if (*p == '\0' || *p == ',') {
+ errmsg.LogError(0, NO_ERRCODE,
+ "Wrong char processing module arguments: %c\n",
+ *p);
+ ABORT_FINALIZE(RS_RET_INVALID_PARAMS);
+ }
+
+ CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0,
+ OMSR_TPL_AS_ARRAY, " StdFmt"));
+ CHKiRet(createInstance(&pData));
+ CHKmalloc(pData->connection = strdup(db_name));
+ CHKiRet(startSession(pData, db_name, db_user, db_password));
+
+ CHKiRet(prepare_statement(pData));
+
+ dbgprintf ("omoracle module got all its resources allocated "
+ "and connected to the DB\n");
+
+CODE_STD_FINALIZERparseSelectorAct
+ENDparseSelectorAct
+
+BEGINdoAction
+ int i;
+ char **params = (char**) ppString[0];
+CODESTARTdoAction
+
+ if (pData->batch.n == pData->batch.size) {
+ dbgprintf("omoracle batch size limit hit, sending into DB\n");
+ CHKiRet(insert_to_db(pData));
+ }
+
+ for (i = 0; i < pData->batch.arguments && params[i]; i++) {
+ dbgprintf("batch[%d][%d]=%s\n", i, pData->batch.n, params[i]);
+ strncpy(pData->batch.parameters[i][pData->batch.n], params[i],
+ pData->batch.param_size);
+ CHKmalloc(pData->batch.parameters[i][pData->batch.n]);
+ }
+ pData->batch.n++;
+
+finalize_it:
+ENDdoAction
+
+BEGINmodExit
+CODESTARTmodExit
+ENDmodExit
+
+BEGINdbgPrintInstInfo
+CODESTARTdbgPrintInstInfo
+ENDdbgPrintInstInfo
+
+
+BEGINqueryEtryPt
+CODESTARTqueryEtryPt
+CODEqueryEtryPt_STD_OMOD_QUERIES
+ENDqueryEtryPt
+
+static rsRetVal
+resetConfigVariables(uchar __attribute__((unused)) *pp,
+ void __attribute__((unused)) *pVal)
+{
+ int n;
+ DEFiRet;
+ if(db_user != NULL)
+ free(db_user);
+ if(db_name != NULL)
+ free(db_name);
+ if (db_password != NULL) {
+ n = strlen(db_password);
+ memset(db_password, 0, n);
+ free(db_password);
+ }
+ if (db_statement != NULL)
+ free(db_statement);
+ db_name = db_user = db_password = db_statement = NULL;
+ batch_size = batch_item_size = 0;
+ RETiRet;
+}
+
+BEGINmodInit()
+ rsRetVal (*supported_options)(unsigned long *pOpts);
+ unsigned long opts;
+CODESTARTmodInit
+ *ipIFVersProvided = CURR_MOD_IF_VERSION;
+CODEmodInit_QueryRegCFSLineHdlr
+ CHKiRet(objUse(errmsg, CORE_COMPONENT));
+ CHKiRet(omsdRegCFSLineHdlr((uchar*) "resetconfigvariables", 1,
+ eCmdHdlrCustomHandler, resetConfigVariables,
+ NULL, STD_LOADABLE_MODULE_ID));
+
+ CHKiRet(omsdRegCFSLineHdlr((uchar*) "omoracledbuser", 0,
+ eCmdHdlrGetWord, NULL, &db_user,
+ STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar*) "omoracledbpassword", 0,
+ eCmdHdlrGetWord, NULL, &db_password,
+ STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar*) "omoracledb", 0,
+ eCmdHdlrGetWord, NULL, &db_name,
+ STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar*) "omoraclebatchsize", 0,
+ eCmdHdlrInt, NULL, &batch_size,
+ STD_LOADABLE_MODULE_ID));
+ CHKiRet(pHostQueryEtryPt((uchar*)"OMSRgetSupportedTplOpts", &supported_options));
+ CHKiRet((*supported_options)(&opts));
+ if (!(opts & OMSR_TPL_AS_ARRAY))
+ ABORT_FINALIZE(RS_RET_RSCORE_TOO_OLD);
+
+ CHKiRet(omsdRegCFSLineHdlr((uchar*) "omoraclestatementtemplate", 0,
+ eCmdHdlrGetWord, NULL,
+ &db_statement, STD_LOADABLE_MODULE_ID));
+
+ CHKiRet(omsdRegCFSLineHdlr((uchar*) "omoraclebatchitemsize", 0,
+ eCmdHdlrInt, NULL,
+ &batch_item_size, STD_LOADABLE_MODULE_ID));
+
+ENDmodInit
diff --git a/plugins/omoracle/omoracle.h b/plugins/omoracle/omoracle.h
new file mode 100644
index 00000000..0ff879b3
--- /dev/null
+++ b/plugins/omoracle/omoracle.h
@@ -0,0 +1,31 @@
+/** Definitions for the Oracle output module.
+
+ This module needs OCI to be installed (on Red Hat-like systems
+ this is usually the oracle-instantclient-devel RPM).
+
+ This file is part of rsyslog.
+
+ This file is licensed under the terms of the GPL version 3 or, at
+ your choice, any later version. Exceptionally (perhaps), you are
+ allowed to link to the Oracle Call Interface in your derived work
+
+ Author: Luis Fernando Muñoz Mejías <Luis.Fernando.Munoz.Mejias@cern.ch>
+*/
+#ifndef __OMORACLEH__
+#define __OMORACLEH__
+
+/** Macros to make error handling easier. */
+
+/** Checks for errors on the OCI handling. */
+#define CHECKERR(handle,status) CHKiRet(oci_errors((handle), \
+ OCI_HTYPE_ERROR, (status)))
+
+/** Checks for errors when handling the environment of OCI. */
+#define CHECKENV(handle,status) CHKiRet(oci_errors((handle), \
+ OCI_HTYPE_ENV, (status)))
+
+enum { MAX_BUFSIZE = 2048 };
+
+#define BIND_MARK ':'
+
+#endif
diff --git a/plugins/omoracle/omoracle.te b/plugins/omoracle/omoracle.te
new file mode 100644
index 00000000..81eb6cf1
--- /dev/null
+++ b/plugins/omoracle/omoracle.te
@@ -0,0 +1,13 @@
+
+module omoracle 1.0;
+
+require {
+ type syslogd_t;
+ type port_t;
+ class process { execstack execmem };
+ class tcp_socket name_connect;
+}
+
+#============= syslogd_t ==============
+allow syslogd_t port_t:tcp_socket name_connect;
+allow syslogd_t self:process { execstack execmem };
diff --git a/plugins/ompgsql/ompgsql.c b/plugins/ompgsql/ompgsql.c
index 6daac1c7..cb6b6a4d 100644
--- a/plugins/ompgsql/ompgsql.c
+++ b/plugins/ompgsql/ompgsql.c
@@ -40,7 +40,7 @@
#include <errno.h>
#include <time.h>
#include <libpq-fe.h>
-#include "dirty.h"
+#include "conf.h"
#include "syslogd-types.h"
#include "srUtils.h"
#include "template.h"
@@ -170,6 +170,9 @@ tryExec(uchar *pszCmd, instanceData *pData)
int bHadError = 0;
/* try insert */
+BEGINfunc
+RUNLOG_VAR("%p", pData->f_hpgsql);
+RUNLOG_VAR("%s", pszCmd);
pgRet = PQexec(pData->f_hpgsql, (char*)pszCmd);
execState = PQresultStatus(pgRet);
if(execState != PGRES_COMMAND_OK && execState != PGRES_TUPLES_OK) {
@@ -178,6 +181,7 @@ tryExec(uchar *pszCmd, instanceData *pData)
}
PQclear(pgRet);
+ENDfunc
return(bHadError);
}
@@ -230,6 +234,14 @@ CODESTARTtryResume
}
ENDtryResume
+
+BEGINbeginTransaction
+CODESTARTbeginTransaction
+dbgprintf("ompgsql: beginTransaction\n");
+ iRet = writePgSQL((uchar*) "begin", pData); /* TODO: make user-configurable */
+ENDbeginTransaction
+
+
BEGINdoAction
CODESTARTdoAction
dbgprintf("\n");
@@ -237,6 +249,13 @@ CODESTARTdoAction
ENDdoAction
+BEGINendTransaction
+CODESTARTendTransaction
+ iRet = writePgSQL((uchar*) "commit;", pData); /* TODO: make user-configurable */
+dbgprintf("ompgsql: endTransaction\n");
+ENDendTransaction
+
+
BEGINparseSelectorAct
int iPgSQLPropErr = 0;
CODESTARTparseSelectorAct
@@ -314,6 +333,7 @@ ENDmodExit
BEGINqueryEtryPt
CODESTARTqueryEtryPt
CODEqueryEtryPt_STD_OMOD_QUERIES
+CODEqueryEtryPt_TXIF_OMOD_QUERIES /* we support the transactional interface! */
ENDqueryEtryPt
@@ -322,6 +342,8 @@ CODESTARTmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(objUse(errmsg, CORE_COMPONENT));
+ INITChkCoreFeature(bCoreSupportsBatching, CORE_FEATURE_BATCHING);
+ DBGPRINTF("ompgsql: %susing transactional output interface.\n", bCoreSupportsBatching ? "" : "not ");
ENDmodInit
/* vi:set ai:
*/
diff --git a/plugins/omprog/Makefile.am b/plugins/omprog/Makefile.am
new file mode 100644
index 00000000..63fe09b8
--- /dev/null
+++ b/plugins/omprog/Makefile.am
@@ -0,0 +1,8 @@
+pkglib_LTLIBRARIES = omprog.la
+
+omprog_la_SOURCES = omprog.c
+omprog_la_CPPFLAGS = $(RSRT_CFLAGS) $(PTHREADS_CFLAGS)
+omprog_la_LDFLAGS = -module -avoid-version
+omprog_la_LIBADD =
+
+EXTRA_DIST =
diff --git a/plugins/omprog/omprog.c b/plugins/omprog/omprog.c
new file mode 100644
index 00000000..01fa7cea
--- /dev/null
+++ b/plugins/omprog/omprog.c
@@ -0,0 +1,357 @@
+/* omprog.c
+ * This output plugin enables rsyslog to execute a program and
+ * feed it the message stream as standard input.
+ *
+ * NOTE: read comments in module-template.h for more specifics!
+ *
+ * File begun on 2009-04-01 by RGerhards
+ *
+ * Copyright 2009 Rainer Gerhards and Adiscon GmbH.
+ *
+ * This file is part of rsyslog.
+ *
+ * Rsyslog is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Rsyslog 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Rsyslog. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+ */
+#include "config.h"
+#include "rsyslog.h"
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <signal.h>
+#include <errno.h>
+#include <unistd.h>
+#include <wait.h>
+#include "conf.h"
+#include "syslogd-types.h"
+#include "srUtils.h"
+#include "template.h"
+#include "module-template.h"
+#include "errmsg.h"
+#include "cfsysline.h"
+
+MODULE_TYPE_OUTPUT
+
+/* internal structures
+ */
+DEF_OMOD_STATIC_DATA
+DEFobjCurrIf(errmsg)
+
+typedef struct _instanceData {
+ uchar *szBinary; /* name of binary to call */
+ pid_t pid; /* pid of currently running process */
+ int fdPipe; /* file descriptor to write to */
+ int bIsRunning; /* is binary currently running? 0-no, 1-yes */
+} instanceData;
+
+/* config settings */
+static uchar *szBinary = NULL; /* name of binary to call */
+
+BEGINcreateInstance
+CODESTARTcreateInstance
+ENDcreateInstance
+
+
+BEGINisCompatibleWithFeature
+CODESTARTisCompatibleWithFeature
+ if(eFeat == sFEATURERepeatedMsgReduction)
+ iRet = RS_RET_OK;
+ENDisCompatibleWithFeature
+
+
+BEGINfreeInstance
+CODESTARTfreeInstance
+ if(pData->szBinary != NULL)
+ free(pData->szBinary);
+ENDfreeInstance
+
+
+BEGINdbgPrintInstInfo
+CODESTARTdbgPrintInstInfo
+ENDdbgPrintInstInfo
+
+
+BEGINtryResume
+CODESTARTtryResume
+ENDtryResume
+
+
+/* execute the child process (must be called in child context
+ * after fork).
+ */
+
+static void execBinary(instanceData *pData, int fdStdin)
+{
+ int i;
+ struct sigaction sigAct;
+ char *newargv[] = { NULL };
+ char *newenviron[] = { NULL };
+
+ assert(pData != NULL);
+
+ fclose(stdin);
+ dup(fdStdin);
+ //fclose(stdout);
+
+ /* we close all file handles as we fork soon
+ * Is there a better way to do this? - mail me! rgerhards@adiscon.com
+ */
+# ifndef VALGRIND /* we can not use this with valgrind - too many errors... */
+ for(i = 3 ; i <= 65535 ; ++i)
+ close(i);
+# endif
+
+ /* reset signal handlers to default */
+ memset(&sigAct, 0, sizeof(sigAct));
+ sigfillset(&sigAct.sa_mask);
+ sigAct.sa_handler = SIG_DFL;
+ for(i = 1 ; i < NSIG ; ++i)
+ sigaction(i, &sigAct, NULL);
+
+ alarm(0);
+
+ /* finally exec child */
+ execve((char*)pData->szBinary, newargv, newenviron);
+ /* switch to?
+ execlp((char*)program, (char*) program, (char*)arg, NULL);
+ */
+
+ /* we should never reach this point, but if we do, we terminate */
+ exit(1);
+}
+
+
+/* creates a pipe and starts program, uses pipe as stdin for program.
+ * rgerhards, 2009-04-01
+ */
+static rsRetVal
+openPipe(instanceData *pData)
+{
+ int pipefd[2];
+ pid_t cpid;
+ DEFiRet;
+
+ assert(pData != NULL);
+
+ if(pipe(pipefd) == -1) {
+ ABORT_FINALIZE(RS_RET_ERR_CREAT_PIPE);
+ }
+
+ DBGPRINTF("executing program '%s'\n", pData->szBinary);
+
+ /* NO OUTPUT AFTER FORK! */
+
+ cpid = fork();
+ if(cpid == -1) {
+ ABORT_FINALIZE(RS_RET_ERR_FORK);
+ }
+
+ if(cpid == 0) {
+ /* we are now the child, just set the right selectors and
+ * exec the binary. If that fails, there is not much we can do.
+ */
+ close(pipefd[1]);
+ execBinary(pData, pipefd[0]);
+ /*NO CODE HERE - WILL NEVER BE REACHED!*/
+ }
+
+ DBGPRINTF("child has pid %d\n", cpid);
+ pData->fdPipe = pipefd[1];
+ pData->pid = cpid;
+ close(pipefd[0]);
+ pData->bIsRunning = 1;
+finalize_it:
+ RETiRet;
+}
+
+
+/* clean up after a terminated child
+ */
+static inline rsRetVal
+cleanup(instanceData *pData)
+{
+ int status;
+ int ret;
+ char errStr[1024];
+ DEFiRet;
+
+ assert(pData != NULL);
+ assert(pData->bIsRunning == 1);
+RUNLOG_VAR("%d", pData->pid);
+ ret = waitpid(pData->pid, &status, 0);
+ if(ret != pData->pid) {
+ /* if waitpid() fails, we can not do much - try to ignore it... */
+ DBGPRINTF("waitpid() returned state %d[%s], future malfunction may happen\n", ret,
+ rs_strerror_r(errno, errStr, sizeof(errStr)));
+ } else {
+ /* check if we should print out some diagnostic information */
+ DBGPRINTF("waitpid status return for program '%s': %2.2x\n",
+ pData->szBinary, status);
+ if(WIFEXITED(status)) {
+ errmsg.LogError(0, NO_ERRCODE, "program '%s' exited normally, state %d",
+ pData->szBinary, WEXITSTATUS(status));
+ } else if(WIFSIGNALED(status)) {
+ errmsg.LogError(0, NO_ERRCODE, "program '%s' terminated by signal %d.",
+ pData->szBinary, WTERMSIG(status));
+ }
+ }
+
+ pData->bIsRunning = 0;
+ RETiRet;
+}
+
+
+/* try to restart the binary when it has stopped.
+ */
+static inline rsRetVal
+tryRestart(instanceData *pData)
+{
+ DEFiRet;
+ assert(pData != NULL);
+ assert(pData->bIsRunning == 0);
+
+ iRet = openPipe(pData);
+ RETiRet;
+}
+
+
+/* write to pipe
+ * note that we do not try to run block-free. If the users fears something
+ * may block (and this not be acceptable), the action should be run on its
+ * own action queue.
+ */
+static rsRetVal
+writePipe(instanceData *pData, uchar *szMsg)
+{
+ int lenWritten;
+ int lenWrite;
+ int writeOffset;
+ char errStr[1024];
+ DEFiRet;
+
+ assert(pData != NULL);
+
+ lenWrite = strlen((char*)szMsg);
+ writeOffset = 0;
+
+ do
+ {
+ lenWritten = write(pData->fdPipe, ((char*)szMsg)+writeOffset, lenWrite);
+ if(lenWritten == -1) {
+ switch(errno) {
+ case EPIPE:
+ DBGPRINTF("Program '%s' terminated, trying to restart\n",
+ pData->szBinary);
+ CHKiRet(cleanup(pData));
+ CHKiRet(tryRestart(pData));
+ break;
+ default:
+ DBGPRINTF("error %d writing to pipe: %s\n", errno,
+ rs_strerror_r(errno, errStr, sizeof(errStr)));
+ ABORT_FINALIZE(RS_RET_ERR_WRITE_PIPE);
+ break;
+ }
+ } else {
+ writeOffset += lenWritten;
+ }
+ } while(lenWritten != lenWrite);
+
+
+finalize_it:
+ RETiRet;
+}
+
+
+BEGINdoAction
+CODESTARTdoAction
+ if(pData->bIsRunning == 0) {
+ openPipe(pData);
+ }
+
+ iRet = writePipe(pData, ppString[0]);
+
+ if(iRet != RS_RET_OK)
+ iRet = RS_RET_SUSPENDED;
+ENDdoAction
+
+
+BEGINparseSelectorAct
+CODESTARTparseSelectorAct
+CODE_STD_STRING_REQUESTparseSelectorAct(1)
+ /* first check if this config line is actually for us */
+ if(strncmp((char*) p, ":omprog:", sizeof(":omprog:") - 1)) {
+ ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED);
+ }
+
+ /* ok, if we reach this point, we have something for us */
+ p += sizeof(":omprog:") - 1; /* eat indicator sequence (-1 because of '\0'!) */
+ CHKiRet(createInstance(&pData));
+
+ CHKmalloc(pData->szBinary = (uchar*) strdup((char*)szBinary));
+ /* check if a non-standard template is to be applied */
+ if(*(p-1) == ';')
+ --p;
+ CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, 0, (uchar*) "RSYSLOG_FileFormat"));
+CODE_STD_FINALIZERparseSelectorAct
+ENDparseSelectorAct
+
+
+BEGINmodExit
+CODESTARTmodExit
+ if(szBinary != NULL) {
+ free(szBinary);
+ szBinary = NULL;
+ }
+ CHKiRet(objRelease(errmsg, CORE_COMPONENT));
+finalize_it:
+ENDmodExit
+
+
+BEGINqueryEtryPt
+CODESTARTqueryEtryPt
+CODEqueryEtryPt_STD_OMOD_QUERIES
+ENDqueryEtryPt
+
+
+
+/* Reset config variables for this module to default values.
+ */
+static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
+{
+ DEFiRet;
+
+ if(szBinary != NULL) {
+ free(szBinary);
+ szBinary = NULL;
+ }
+
+ RETiRet;
+}
+
+
+BEGINmodInit()
+CODESTARTmodInit
+ *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
+CODEmodInit_QueryRegCFSLineHdlr
+ CHKiRet(objUse(errmsg, CORE_COMPONENT));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionomprogbinary", 0, eCmdHdlrGetWord, NULL, &szBinary, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
+CODEmodInit_QueryRegCFSLineHdlr
+ENDmodInit
+
+/* vi:set ai:
+ */
diff --git a/plugins/omrelp/omrelp.c b/plugins/omrelp/omrelp.c
index 8d74c82f..d5ef8b4f 100644
--- a/plugins/omrelp/omrelp.c
+++ b/plugins/omrelp/omrelp.c
@@ -36,7 +36,7 @@
#include <errno.h>
#include <ctype.h>
#include <librelp.h>
-#include "dirty.h"
+#include "conf.h"
#include "syslogd-types.h"
#include "srUtils.h"
#include "cfsysline.h"
diff --git a/plugins/omsnmp/omsnmp.c b/plugins/omsnmp/omsnmp.c
index 72fa8d64..4db60e62 100644
--- a/plugins/omsnmp/omsnmp.c
+++ b/plugins/omsnmp/omsnmp.c
@@ -36,7 +36,7 @@
#include <netdb.h>
#include <ctype.h>
#include <assert.h>
-#include "dirty.h"
+#include "conf.h"
#include "syslogd-types.h"
#include "cfsysline.h"
#include "module-template.h"
diff --git a/plugins/omstdout/Makefile.am b/plugins/omstdout/Makefile.am
new file mode 100644
index 00000000..9f5d497f
--- /dev/null
+++ b/plugins/omstdout/Makefile.am
@@ -0,0 +1,8 @@
+pkglib_LTLIBRARIES = omstdout.la
+
+omstdout_la_SOURCES = omstdout.c
+omstdout_la_CPPFLAGS = $(RSRT_CFLAGS) $(PTHREADS_CFLAGS)
+omstdout_la_LDFLAGS = -module -avoid-version
+omstdout_la_LIBADD =
+
+EXTRA_DIST =
diff --git a/plugins/omstdout/omstdout.c b/plugins/omstdout/omstdout.c
new file mode 100644
index 00000000..b9125f19
--- /dev/null
+++ b/plugins/omstdout/omstdout.c
@@ -0,0 +1,203 @@
+/* omstdout.c
+ * send all output to stdout - this is primarily a test driver (but may
+ * be used for weired use cases). Not tested for robustness!
+ *
+ * NOTE: read comments in module-template.h for more specifics!
+ *
+ * File begun on 2009-03-19 by RGerhards
+ *
+ * Copyright 2009 Rainer Gerhards and Adiscon GmbH.
+ *
+ * This file is part of rsyslog.
+ *
+ * Rsyslog is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Rsyslog 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Rsyslog. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+ */
+#include "config.h"
+#include "rsyslog.h"
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <signal.h>
+#include <errno.h>
+#include <unistd.h>
+#include "conf.h"
+#include "syslogd-types.h"
+#include "srUtils.h"
+#include "template.h"
+#include "module-template.h"
+#include "errmsg.h"
+#include "cfsysline.h"
+
+MODULE_TYPE_OUTPUT
+
+/* internal structures
+ */
+DEF_OMOD_STATIC_DATA
+
+/* config variables */
+static int bUseArrayInterface; /* shall action use array instead of string template interface? */
+
+
+typedef struct _instanceData {
+ int bUseArrayInterface; /* uses action use array instead of string template interface? */
+} instanceData;
+
+BEGINcreateInstance
+CODESTARTcreateInstance
+ENDcreateInstance
+
+
+BEGINisCompatibleWithFeature
+CODESTARTisCompatibleWithFeature
+ if(eFeat == sFEATURERepeatedMsgReduction)
+ iRet = RS_RET_OK;
+ENDisCompatibleWithFeature
+
+
+BEGINfreeInstance
+CODESTARTfreeInstance
+ENDfreeInstance
+
+
+BEGINdbgPrintInstInfo
+CODESTARTdbgPrintInstInfo
+ENDdbgPrintInstInfo
+
+
+BEGINtryResume
+CODESTARTtryResume
+ENDtryResume
+
+BEGINdoAction
+ char **szParams;
+ char *toWrite;
+ int iParamVal;
+ int iParam;
+ int iBuf;
+ char szBuf[65564];
+CODESTARTdoAction
+ if(pData->bUseArrayInterface) {
+ /* if we use array passing, we need to put together a string
+ * ourselves. At this point, please keep in mind that omstdout is
+ * primarily a testing aid. Other modules may do different processing
+ * if they would like to support downlevel versions which do not support
+ * array-passing, but also use that interface on cores who do...
+ * So this code here is also more or less an example of how to do that.
+ * rgerhards, 2009-04-03
+ */
+ szParams = (char**) (ppString[0]);
+ /* In array-passing mode, ppString[] contains a NULL-terminated array
+ * of char *pointers.
+ */
+ iParam = 0;
+ iBuf = 0;
+ while(szParams[iParam] != NULL) {
+ if(iParam > 0)
+ szBuf[iBuf++] = ','; /* all but first need a delimiter */
+ iParamVal = 0;
+ while(szParams[iParam][iParamVal] != '\0' && iBuf < (int) sizeof(szBuf)) {
+ szBuf[iBuf++] = szParams[iParam][iParamVal++];
+ }
+ ++iParam;
+ }
+ szBuf[iBuf] = '\0';
+ toWrite = szBuf;
+ } else {
+ toWrite = (char*) ppString[0];
+ }
+ write(1, toWrite, strlen(toWrite)); /* 1 is stdout! */
+ENDdoAction
+
+
+BEGINparseSelectorAct
+ int iTplOpts;
+CODESTARTparseSelectorAct
+CODE_STD_STRING_REQUESTparseSelectorAct(1)
+ /* first check if this config line is actually for us */
+ if(strncmp((char*) p, ":omstdout:", sizeof(":omstdout:") - 1)) {
+ ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED);
+ }
+
+ /* ok, if we reach this point, we have something for us */
+ p += sizeof(":omstdout:") - 1; /* eat indicator sequence (-1 because of '\0'!) */
+ CHKiRet(createInstance(&pData));
+
+ /* check if a non-standard template is to be applied */
+ if(*(p-1) == ';')
+ --p;
+ iTplOpts = (bUseArrayInterface == 0) ? 0 : OMSR_TPL_AS_ARRAY;
+ CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, iTplOpts, (uchar*) "RSYSLOG_FileFormat"));
+ pData->bUseArrayInterface = bUseArrayInterface;
+CODE_STD_FINALIZERparseSelectorAct
+ENDparseSelectorAct
+
+
+BEGINmodExit
+CODESTARTmodExit
+ENDmodExit
+
+
+BEGINqueryEtryPt
+CODESTARTqueryEtryPt
+CODEqueryEtryPt_STD_OMOD_QUERIES
+ENDqueryEtryPt
+
+
+
+/* Reset config variables for this module to default values.
+ */
+static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
+{
+ DEFiRet;
+ bUseArrayInterface = 0;
+ RETiRet;
+}
+
+
+BEGINmodInit()
+ rsRetVal localRet;
+ rsRetVal (*pomsrGetSupportedTplOpts)(unsigned long *pOpts);
+ unsigned long opts;
+ int bArrayPassingSupported; /* does core support template passing as an array? */
+CODESTARTmodInit
+ *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
+CODEmodInit_QueryRegCFSLineHdlr
+ /* check if the rsyslog core supports parameter passing code */
+ bArrayPassingSupported = 0;
+ localRet = pHostQueryEtryPt((uchar*)"OMSRgetSupportedTplOpts", &pomsrGetSupportedTplOpts);
+ if(localRet == RS_RET_OK) {
+ /* found entry point, so let's see if core supports array passing */
+ CHKiRet((*pomsrGetSupportedTplOpts)(&opts));
+ if(opts & OMSR_TPL_AS_ARRAY)
+ bArrayPassingSupported = 1;
+ } else if(localRet != RS_RET_ENTRY_POINT_NOT_FOUND) {
+ ABORT_FINALIZE(localRet); /* Something else went wrong, what is not acceptable */
+ }
+ DBGPRINTF("omstdout: array-passing is %ssupported by rsyslog core.\n", bArrayPassingSupported ? "" : "not ");
+
+ if(bArrayPassingSupported) {
+ /* enable config comand only if core supports it */
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionomstdoutarrayinterface", 0, eCmdHdlrBinary, NULL,
+ &bUseArrayInterface, STD_LOADABLE_MODULE_ID));
+ }
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler,
+ resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
+ENDmodInit
+
+/* vi:set ai:
+ */
diff --git a/plugins/omtemplate/Makefile.am b/plugins/omtemplate/Makefile.am
new file mode 100644
index 00000000..e816c7c6
--- /dev/null
+++ b/plugins/omtemplate/Makefile.am
@@ -0,0 +1,8 @@
+pkglib_LTLIBRARIES = omtemplate.la
+
+omtemplate_la_SOURCES = omtemplate.c
+omtemplate_la_CPPFLAGS = $(RSRT_CFLAGS) $(PTHREADS_CFLAGS)
+omtemplate_la_LDFLAGS = -module -avoid-version
+omtemplate_la_LIBADD =
+
+EXTRA_DIST =
diff --git a/plugins/omtemplate/omtemplate.c b/plugins/omtemplate/omtemplate.c
new file mode 100644
index 00000000..5577f8c6
--- /dev/null
+++ b/plugins/omtemplate/omtemplate.c
@@ -0,0 +1,220 @@
+/* omtemplate.c
+ * This is a template for an output module. It implements a very
+ * simple single-threaded output, just as thought of by the output
+ * plugin interface.
+ *
+ * NOTE: read comments in module-template.h for more specifics!
+ *
+ * File begun on 2009-03-16 by RGerhards
+ *
+ * Copyright 2009 Rainer Gerhards and Adiscon GmbH.
+ *
+ * This file is part of rsyslog.
+ *
+ * Rsyslog is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Rsyslog 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Rsyslog. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+ */
+#include "config.h"
+#include "rsyslog.h"
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <signal.h>
+#include <errno.h>
+#include <time.h>
+#include "conf.h"
+#include "syslogd-types.h"
+#include "srUtils.h"
+#include "template.h"
+#include "module-template.h"
+#include "errmsg.h"
+#include "cfsysline.h"
+
+MODULE_TYPE_OUTPUT
+
+/* internal structures
+ */
+DEF_OMOD_STATIC_DATA
+DEFobjCurrIf(errmsg)
+
+typedef struct _instanceData {
+ /* here you need to define all action-specific data. A record of type
+ * instanceData will be handed over to each instance of the action. Keep
+ * in mind that there may be several invocations of the same type of action
+ * inside rsyslog.conf, and this is what keeps them apart. Do NOT use
+ * static data for this!
+ */
+ unsigned iSrvPort; /* sample: server port */
+} instanceData;
+
+/* config variables
+ * For the configuration interface, we need to keep track of some settings. This
+ * is done in global variables. It works as follows: when configuration statements
+ * are entered, the config file handler (or custom function) sets the global
+ * variable here. When the action then actually is instantiated, this handler
+ * copies over to instanceData whatever configuration settings (from the global
+ * variables) apply. The global variables are NEVER used inside an action
+ * instance (at least this is how it is supposed to work ;)
+ */
+static int iSrvPort = 0; /* sample: server port */
+
+
+BEGINcreateInstance
+CODESTARTcreateInstance
+ENDcreateInstance
+
+
+BEGINisCompatibleWithFeature
+CODESTARTisCompatibleWithFeature
+ /* use this to specify if select features are supported by this
+ * plugin. If not, the framework will handle that. Currently, only
+ * RepeatedMsgReduction ("last message repeated n times") is optional.
+ */
+ if(eFeat == sFEATURERepeatedMsgReduction)
+ iRet = RS_RET_OK;
+ENDisCompatibleWithFeature
+
+
+BEGINfreeInstance
+CODESTARTfreeInstance
+ /* this is a cleanup callback. All dynamically-allocated resources
+ * in instance data must be cleaned up here. Prime examples are
+ * malloc()ed memory, file & database handles and the like.
+ */
+ENDfreeInstance
+
+
+BEGINdbgPrintInstInfo
+CODESTARTdbgPrintInstInfo
+ /* permits to spit out some debug info */
+ENDdbgPrintInstInfo
+
+
+BEGINtryResume
+CODESTARTtryResume
+ /* this is called when an action has been suspended and the
+ * rsyslog core tries to resume it. The action must then
+ * retry (if possible) and report RS_RET_OK if it succeeded
+ * or RS_RET_SUSPENDED otherwise.
+ * Note that no data can be written in this callback, as it is
+ * not present. Prime examples of what can be retried are
+ * reconnects to remote hosts, reconnects to database,
+ * opening of files and the like.
+ * If there is no retry-type of operation, the action may
+ * return RS_RET_OK, so that it will get called on its doAction
+ * entry point (where it receives data), retries there, and
+ * immediately returns RS_RET_SUSPENDED if that does not work
+ * out. This disables some optimizations in the core's retry logic,
+ * but is a valid and expected behaviour. Note that it is also OK
+ * for the retry entry point to return OK but the immediately following
+ * doAction call to fail. In real life, for example, a buggy com line
+ * may cause such behaviour.
+ * Note that there is no guarantee that the core will very quickly
+ * call doAction after the retry succeeded. Today, it does, but that may
+ * not always be the case.
+ */
+ENDtryResume
+
+BEGINdoAction
+CODESTARTdoAction
+ /* this is where you receive the message and need to carry out the
+ * action. Data is provided in ppString[i] where 0 <= i <= num of strings
+ * requested.
+ * Return RS_RET_OK if all goes well, RS_RET_SUSPENDED if the action can
+ * currently not complete, or an error code or RS_RET_DISABLED. The later
+ * two should only be returned if there is no hope that the action can be
+ * restored unless an rsyslog restart (prime example is an invalid config).
+ * Error code or RS_RET_DISABLED permanently disables the action, up to
+ * the next restart.
+ */
+ENDdoAction
+
+
+BEGINparseSelectorAct
+CODESTARTparseSelectorAct
+CODE_STD_STRING_REQUESTparseSelectorAct(1)
+ /* first check if this config line is actually for us
+ * This is a clumpsy interface. We receive the action-part of the selector line
+ * and need to look at the first characters. If they match our signature
+ * ":omtemplate:", then we need to instantiate an action. It is recommended that
+ * newer actions just watch for the template and all other parameters are passed in
+ * via $-config-lines, this will hopefully be compatbile with future config syntaxes.
+ * If we do not detect our signature, we must return with RS_RET_CONFLINE_UNPROCESSED
+ * and NOT do anything else.
+ */
+ if(strncmp((char*) p, ":omtemplate:", sizeof(":omtemplate:") - 1)) {
+ ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED);
+ }
+
+ /* ok, if we reach this point, we have something for us */
+ p += sizeof(":omtemplate:") - 1; /* eat indicator sequence (-1 because of '\0'!) */
+ CHKiRet(createInstance(&pData));
+
+ /* check if a non-standard template is to be applied */
+ if(*(p-1) == ';')
+ --p;
+ /* if we have, call rsyslog runtime to get us template. Note that StdFmt below is
+ * the standard name. Currently, we may need to patch tools/syslogd.c if we need
+ * to add a new standard template.
+ */
+ CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_RQD_TPL_OPT_SQL, (uchar*) " StdFmt"));
+
+ /* if we reach this point, all went well, and we can copy over to instanceData
+ * those configuration elements that we need.
+ */
+ pData->iSrvPort = (unsigned) iSrvPort; /* set configured port */
+
+CODE_STD_FINALIZERparseSelectorAct
+ENDparseSelectorAct
+
+
+BEGINmodExit
+CODESTARTmodExit
+ENDmodExit
+
+
+BEGINqueryEtryPt
+CODESTARTqueryEtryPt
+CODEqueryEtryPt_STD_OMOD_QUERIES
+ENDqueryEtryPt
+
+
+/* Reset config variables for this module to default values.
+ */
+static rsRetVal
+resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
+{
+ DEFiRet;
+ iSrvPort = 0; /* zero is the default port */
+ RETiRet;
+}
+
+
+BEGINmodInit()
+CODESTARTmodInit
+ *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
+CODEmodInit_QueryRegCFSLineHdlr
+ CHKiRet(objUse(errmsg, CORE_COMPONENT));
+ /* register our config handlers */
+ /* confguration parameters MUST always be specified in lower case! */
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionomtemplteserverport", 0, eCmdHdlrInt, NULL, &iSrvPort, STD_LOADABLE_MODULE_ID));
+ /* "resetconfigvariables" should be provided. Notat that it is a chained directive */
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
+ENDmodInit
+
+/* vi:set ai:
+ */
diff --git a/plugins/omtesting/omtesting.c b/plugins/omtesting/omtesting.c
index 411bcf88..8f6cdbe5 100644
--- a/plugins/omtesting/omtesting.c
+++ b/plugins/omtesting/omtesting.c
@@ -22,7 +22,7 @@
* NOTE: read comments in module-template.h to understand how this file
* works!
*
- * Copyright 2007 Rainer Gerhards and Adiscon GmbH.
+ * Copyright 2007, 2009 Rainer Gerhards and Adiscon GmbH.
*
* This file is part of rsyslog.
*
@@ -46,12 +46,14 @@
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
+#include <time.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include "dirty.h"
#include "syslogd-types.h"
#include "module-template.h"
+#include "cfsysline.h"
MODULE_TYPE_OUTPUT
@@ -59,9 +61,18 @@ MODULE_TYPE_OUTPUT
*/
DEF_OMOD_STATIC_DATA
+static int bEchoStdout = 0; /* echo non-failed messages to stdout */
+
typedef struct _instanceData {
+ enum { MD_SLEEP, MD_FAIL, MD_RANDFAIL, MD_ALWAYS_SUSPEND }
+ mode;
+ int bEchoStdout;
int iWaitSeconds;
int iWaitUSeconds; /* milli-seconds (one million of a second, just to make sure...) */
+ int iCurrCallNbr;
+ int iFailFrequency;
+ int iResumeAfter;
+ int iCurrRetries;
} instanceData;
BEGINcreateInstance
@@ -85,19 +96,106 @@ CODESTARTisCompatibleWithFeature
ENDisCompatibleWithFeature
-BEGINtryResume
-CODESTARTtryResume
-ENDtryResume
+/* implement "fail" command in retry processing */
+static rsRetVal doFailOnResume(instanceData *pData)
+{
+ DEFiRet;
-BEGINdoAction
-CODESTARTdoAction
+ dbgprintf("fail retry curr %d, max %d\n", pData->iCurrRetries, pData->iResumeAfter);
+ if(++pData->iCurrRetries == pData->iResumeAfter) {
+ iRet = RS_RET_OK;
+ } else {
+ iRet = RS_RET_SUSPENDED;
+ }
+
+ RETiRet;
+}
+
+
+/* implement "fail" command */
+static rsRetVal doFail(instanceData *pData)
+{
+ DEFiRet;
+
+ dbgprintf("fail curr %d, frquency %d\n", pData->iCurrCallNbr, pData->iFailFrequency);
+ if(pData->iCurrCallNbr++ % pData->iFailFrequency == 0) {
+ pData->iCurrRetries = 0;
+ iRet = RS_RET_SUSPENDED;
+ }
+
+ RETiRet;
+}
+
+
+/* implement "sleep" command */
+static rsRetVal doSleep(instanceData *pData)
+{
+ DEFiRet;
struct timeval tvSelectTimeout;
dbgprintf("sleep(%d, %d)\n", pData->iWaitSeconds, pData->iWaitUSeconds);
tvSelectTimeout.tv_sec = pData->iWaitSeconds;
tvSelectTimeout.tv_usec = pData->iWaitUSeconds; /* milli seconds */
select(0, NULL, NULL, NULL, &tvSelectTimeout);
- //dbgprintf(":omtesting: end doAction(), iRet %d\n", iRet);
+ RETiRet;
+}
+
+
+/* implement "randomfail" command */
+static rsRetVal doRandFail(void)
+{
+ DEFiRet;
+ if((rand() >> 4) < (RAND_MAX >> 5)) { /* rougly same probability */
+ iRet = RS_RET_OK;
+ dbgprintf("omtesting randfail: succeeded this time\n");
+ } else {
+ iRet = RS_RET_SUSPENDED;
+ dbgprintf("omtesting randfail: failed this time\n");
+ }
+ RETiRet;
+}
+
+
+BEGINtryResume
+CODESTARTtryResume
+ dbgprintf("omtesting tryResume() called\n");
+ switch(pData->mode) {
+ case MD_SLEEP:
+ break;
+ case MD_FAIL:
+ iRet = doFailOnResume(pData);
+ break;
+ case MD_RANDFAIL:
+ iRet = doRandFail();
+ break;
+ case MD_ALWAYS_SUSPEND:
+ iRet = RS_RET_SUSPENDED;
+ }
+ dbgprintf("omtesting tryResume() returns iRet %d\n", iRet);
+ENDtryResume
+
+
+BEGINdoAction
+CODESTARTdoAction
+ dbgprintf("omtesting received msg '%s'\n", ppString[0]);
+ switch(pData->mode) {
+ case MD_SLEEP:
+ iRet = doSleep(pData);
+ break;
+ case MD_FAIL:
+ iRet = doFail(pData);
+ break;
+ case MD_RANDFAIL:
+ iRet = doRandFail();
+ case MD_ALWAYS_SUSPEND:
+ iRet = RS_RET_SUSPENDED;
+ }
+
+ if(iRet == RS_RET_OK && pData->bEchoStdout) {
+ fprintf(stdout, "%s", ppString[0]);
+ fflush(stdout);
+ }
+ dbgprintf(":omtesting: end doAction(), iRet %d\n", iRet);
ENDdoAction
@@ -113,7 +211,7 @@ BEGINparseSelectorAct
int i;
uchar szBuf[1024];
CODESTARTparseSelectorAct
-CODE_STD_STRING_REQUESTparseSelectorAct(0)
+CODE_STD_STRING_REQUESTparseSelectorAct(1)
/* code here is quick and dirty - if you like, clean it up. But keep
* in mind it is just a testing aid ;) -- rgerhards, 2007-12-31
*/
@@ -135,6 +233,7 @@ CODE_STD_STRING_REQUESTparseSelectorAct(0)
if(isspace(*p))
++p;
+ dbgprintf("omtesting command: '%s'\n", szBuf);
if(!strcmp((char*) szBuf, "sleep")) {
/* parse seconds */
for(i = 0 ; *p && !isspace(*p) && ((unsigned) i < sizeof(szBuf) - 1) ; ++i) {
@@ -152,12 +251,43 @@ CODE_STD_STRING_REQUESTparseSelectorAct(0)
if(isspace(*p))
++p;
pData->iWaitUSeconds = atoi((char*) szBuf);
- }
- /* once there are other modes, here is the spot to add it! */
- else {
+ pData->mode = MD_SLEEP;
+ } else if(!strcmp((char*) szBuf, "fail")) {
+ /* "fail fail-freqency resume-after"
+ * fail-frequency specifies how often doAction() fails
+ * resume-after speicifes how fast tryResume() should come back with success
+ * all numbers being "times called"
+ */
+ /* parse fail-frequence */
+ for(i = 0 ; *p && !isspace(*p) && ((unsigned) i < sizeof(szBuf) - 1) ; ++i) {
+ szBuf[i] = *p++;
+ }
+ szBuf[i] = '\0';
+ if(isspace(*p))
+ ++p;
+ pData->iFailFrequency = atoi((char*) szBuf);
+ /* parse resume-after */
+ for(i = 0 ; *p && !isspace(*p) && ((unsigned) i < sizeof(szBuf) - 1) ; ++i) {
+ szBuf[i] = *p++;
+ }
+ szBuf[i] = '\0';
+ if(isspace(*p))
+ ++p;
+ pData->iResumeAfter = atoi((char*) szBuf);
+ pData->iCurrCallNbr = 1;
+ pData->mode = MD_FAIL;
+ } else if(!strcmp((char*) szBuf, "randfail")) {
+ pData->mode = MD_RANDFAIL;
+ } else if(!strcmp((char*) szBuf, "always_suspend")) {
+ pData->mode = MD_ALWAYS_SUSPEND;
+ } else {
dbgprintf("invalid mode '%s', doing 'sleep 1 0' - fix your config\n", szBuf);
}
+ pData->bEchoStdout = bEchoStdout;
+ CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS,
+ (uchar*)"RSYSLOG_TraditionalForwardFormat"));
+
CODE_STD_FINALIZERparseSelectorAct
ENDparseSelectorAct
@@ -177,6 +307,10 @@ BEGINmodInit()
CODESTARTmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
CODEmodInit_QueryRegCFSLineHdlr
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionomtestingechostdout", 0, eCmdHdlrBinary, NULL,
+ &bEchoStdout, STD_LOADABLE_MODULE_ID));
+ /* we seed the random-number generator in any case... */
+ srand(time(NULL));
ENDmodInit
/*
* vi:set ai: