summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/Makefile.am8
-rw-r--r--tools/omfile.c30
-rw-r--r--tools/ompipe.c3
-rw-r--r--tools/smfile.c135
-rw-r--r--tools/smfile.h31
-rw-r--r--tools/smfwd.c142
-rw-r--r--tools/smfwd.h30
-rw-r--r--tools/smtradfile.c128
-rw-r--r--tools/smtradfile.h31
-rw-r--r--tools/smtradfwd.c139
-rw-r--r--tools/smtradfwd.h30
-rw-r--r--tools/syncdemo.c440
-rw-r--r--tools/syslogd.c200
13 files changed, 1292 insertions, 55 deletions
diff --git a/tools/Makefile.am b/tools/Makefile.am
index f0a8df5f..8f2989ca 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -21,6 +21,14 @@ rsyslogd_SOURCES = \
pmrfc5424.h \
pmrfc3164.c \
pmrfc3164.h \
+ smtradfile.c \
+ smtradfile.h \
+ smfile.c \
+ smfile.h \
+ smfwd.c \
+ smfwd.h \
+ smtradfwd.c \
+ smtradfwd.h \
iminternal.c \
iminternal.h \
pidfile.c \
diff --git a/tools/omfile.c b/tools/omfile.c
index d9dce4f9..57089cfd 100644
--- a/tools/omfile.c
+++ b/tools/omfile.c
@@ -48,10 +48,13 @@
#include <libgen.h>
#include <unistd.h>
#include <sys/file.h>
-
#ifdef OS_SOLARIS
# include <fcntl.h>
#endif
+#ifdef HAVE_ATOMIC_BUILTINS
+# include <pthread.h>
+#endif
+
#include "conf.h"
#include "syslogd-types.h"
@@ -89,10 +92,13 @@ static uint64 clockFileAccess = 0;
static unsigned clockFileAccess = 0;
#endif
/* and the "tick" function */
+#ifndef HAVE_ATOMIC_BUILTINS
+static pthread_mutex_t mutClock;
+#endif
static inline uint64
getClockFileAccess(void)
{
- return ATOMIC_INC_AND_FETCH(clockFileAccess);
+ return ATOMIC_INC_AND_FETCH(&clockFileAccess, &mutClock);
}
@@ -125,7 +131,7 @@ static uid_t dirGID; /* GID to be used for newly created directories */
static int bCreateDirs = 1;/* auto-create directories for dynaFiles: 0 - no, 1 - yes */
static int bEnableSync = 0;/* enable syncing of files (no dash in front of pathname in conf): 0 - no, 1 - yes */
static int iZipLevel = 0; /* zip compression mode (0..9 as usual) */
-static bool bFlushOnTXEnd = FLUSHONTX_DFLT;/* flush write buffers when transaction has ended? */
+static sbool bFlushOnTXEnd = FLUSHONTX_DFLT;/* flush write buffers when transaction has ended? */
static int64 iIOBufSize = IOBUF_DFLT_SIZE; /* size of an io buffer */
static int iFlushInterval = FLUSH_INTRVL_DFLT; /* how often flush the output buffer on inactivity? */
static int bUseAsyncWriter = USE_ASYNCWRITER_DFLT; /* should we enable asynchronous writing? */
@@ -142,7 +148,7 @@ typedef struct _instanceData {
int fDirCreateMode; /* creation mode for mkdir() */
int bCreateDirs; /* auto-create directories? */
int bSyncFile; /* should the file by sync()'ed? 1- yes, 0- no */
- bool bForceChown; /* force chown() on existing files? */
+ sbool bForceChown; /* force chown() on existing files? */
uid_t fileUID; /* IDs for creation */
uid_t dirUID;
gid_t fileGID;
@@ -161,8 +167,8 @@ typedef struct _instanceData {
int iZipLevel; /* zip mode to use for this selector */
int iIOBufSize; /* size of associated io buffer */
int iFlushInterval; /* how fast flush buffer on inactivity? */
- bool bFlushOnTXEnd; /* flush write buffers when transaction has ended? */
- bool bUseAsyncWriter; /* use async stream writer? */
+ sbool bFlushOnTXEnd; /* flush write buffers when transaction has ended? */
+ sbool bUseAsyncWriter; /* use async stream writer? */
} instanceData;
@@ -188,8 +194,9 @@ CODESTARTdbgPrintInstInfo
dbgprintf("\tflush interval=%d\n", pData->iFlushInterval);
dbgprintf("\tfile cache size=%d\n", pData->iDynaFileCacheSize);
dbgprintf("\tcreate directories: %s\n", pData->bCreateDirs ? "yes" : "no");
- dbgprintf("\tfile owner %d, group %d\n", pData->fileUID, pData->fileGID);
- dbgprintf("\tdirectory owner %d, group %d\n", pData->dirUID, pData->dirGID);
+ dbgprintf("\tfile owner %d, group %d\n", (int) pData->fileUID, (int) pData->fileGID);
+ dbgprintf("\tforce chown() for all files: %s\n", pData->bForceChown ? "yes" : "no");
+ dbgprintf("\tdirectory owner %d, group %d\n", (int) pData->dirUID, (int) pData->dirGID);
dbgprintf("\tdir create mode 0%3.3o, file create mode 0%3.3o\n",
pData->fDirCreateMode, pData->fCreateMode);
dbgprintf("\tfail if owner/group can not be set: %s\n", pData->bFailOnChown ? "yes" : "no");
@@ -548,7 +555,6 @@ prepareDynFile(instanceData *pData, uchar *newFileName, unsigned iMsgOpts)
iFirstFree = pData->iCurrCacheSize++;
}
-// RG: this is the begin of a potential problem area
/* Note that the following code sequence does not work with the cache entry itself,
* but rather with pData->pStrm, the (sole) stream pointer in the non-dynafile case.
* The cache array is only updated after the open was successful. -- rgerhards, 2010-03-21
@@ -607,7 +613,7 @@ doWrite(instanceData *pData, uchar *pszBuf, int lenBuf)
ASSERT(pData != NULL);
ASSERT(pszBuf != NULL);
-dbgprintf("doWrite, pData->pStrm %p, lenBuf %d\n", pData->pStrm, lenBuf);
+dbgprintf("write to stream, pData->pStrm %p, lenBuf %d\n", pData->pStrm, lenBuf);
if(pData->pStrm != NULL){
CHKiRet(strm.Write(pData->pStrm, pszBuf, lenBuf));
FINALIZE;
@@ -854,6 +860,7 @@ CODESTARTmodExit
objRelease(errmsg, CORE_COMPONENT);
objRelease(strm, CORE_COMPONENT);
free(pszFileDfltTplName);
+ DESTROY_ATOMIC_HELPER_MUT(mutClock);
ENDmodExit
@@ -871,6 +878,9 @@ CODESTARTmodInit
CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(objUse(errmsg, CORE_COMPONENT));
CHKiRet(objUse(strm, CORE_COMPONENT));
+
+ INIT_ATOMIC_HELPER_MUT(mutClock);
+
INITChkCoreFeature(bCoreSupportsBatching, CORE_FEATURE_BATCHING);
DBGPRINTF("omfile: %susing transactional output interface.\n", bCoreSupportsBatching ? "" : "not ");
CHKiRet(omsdRegCFSLineHdlr((uchar *)"dynafilecachesize", 0, eCmdHdlrInt, (void*) setDynaFileCacheSize, NULL, STD_LOADABLE_MODULE_ID));
diff --git a/tools/ompipe.c b/tools/ompipe.c
index 5fb9b27e..cf22bc84 100644
--- a/tools/ompipe.c
+++ b/tools/ompipe.c
@@ -36,9 +36,12 @@
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
+#include <unistd.h>
#include <string.h>
+#include <unistd.h>
#include <assert.h>
#include <errno.h>
+#include <fcntl.h>
#include <sys/file.h>
#include "syslogd.h"
diff --git a/tools/smfile.c b/tools/smfile.c
new file mode 100644
index 00000000..5e4a775f
--- /dev/null
+++ b/tools/smfile.c
@@ -0,0 +1,135 @@
+/* smfile.c
+ * This is a strgen module for the traditional file format.
+ *
+ * Format generated:
+ * "%TIMESTAMP:::date-rfc3339% %HOSTNAME% %syslogtag%%msg:::sp-if-no-1st-sp%%msg:::drop-last-lf%\n"
+ * Note that this is the same as smtradfile.c, except that we do have a RFC3339 timestamp. However,
+ * we have copied over the code from there, it is too simple to go through all the hassle
+ * of having a single code base.
+ *
+ * NOTE: read comments in module-template.h to understand how this file
+ * works!
+ *
+ * File begun on 2010-06-01 by RGerhards
+ *
+ * Copyright 2010 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 <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include "syslogd.h"
+#include "conf.h"
+#include "syslogd-types.h"
+#include "template.h"
+#include "msg.h"
+#include "module-template.h"
+#include "unicode-helper.h"
+
+MODULE_TYPE_STRGEN
+STRGEN_NAME("RSYSLOG_FileFormat")
+
+/* internal structures
+ */
+DEF_SMOD_STATIC_DATA
+
+
+/* config data */
+
+
+/* This strgen tries to minimize the amount of reallocs be first obtaining pointers to all strings
+ * needed (including their length) and then calculating the actual space required. So when we
+ * finally copy, we know exactly what we need. So we do at most one alloc.
+ */
+BEGINstrgen
+ register int iBuf;
+ uchar *pTimeStamp;
+ size_t lenTimeStamp;
+ uchar *pHOSTNAME;
+ size_t lenHOSTNAME;
+ uchar *pTAG;
+ int lenTAG;
+ uchar *pMSG;
+ size_t lenMSG;
+ size_t lenTotal;
+CODESTARTstrgen
+ /* first obtain all strings and their length (if not fixed) */
+ pTimeStamp = (uchar*) getTimeReported(pMsg, tplFmtRFC3339Date);
+ lenTimeStamp = ustrlen(pTimeStamp);
+ pHOSTNAME = (uchar*) getHOSTNAME(pMsg);
+ lenHOSTNAME = getHOSTNAMELen(pMsg);
+ getTAG(pMsg, &pTAG, &lenTAG);
+ pMSG = getMSG(pMsg);
+ lenMSG = getMSGLen(pMsg);
+
+ /* calculate len, constants for spaces and similar fixed strings */
+ lenTotal = lenTimeStamp + 1 + lenHOSTNAME + 1 + lenTAG + lenMSG + 2;
+ if(pMSG[0] != ' ')
+ ++lenTotal; /* then we need to introduce one additional space */
+
+ /* now make sure buffer is large enough */
+ if(lenTotal >= *pLenBuf)
+ CHKiRet(ExtendBuf(ppBuf, pLenBuf, lenTotal));
+
+ /* and concatenate the resulting string */
+ memcpy(*ppBuf, pTimeStamp, lenTimeStamp);
+ iBuf = lenTimeStamp;
+ *(*ppBuf + iBuf++) = ' ';
+
+ memcpy(*ppBuf + iBuf, pHOSTNAME, lenHOSTNAME);
+ iBuf += lenHOSTNAME;
+ *(*ppBuf + iBuf++) = ' ';
+
+ memcpy(*ppBuf + iBuf, pTAG, lenTAG);
+ iBuf += lenTAG;
+
+ if(pMSG[0] != ' ')
+ *(*ppBuf + iBuf++) = ' ';
+ memcpy(*ppBuf + iBuf, pMSG, lenMSG);
+ iBuf += lenMSG;
+
+ /* trailer */
+ *(*ppBuf + iBuf++) = '\n';
+ *(*ppBuf + iBuf) = '\0';
+
+finalize_it:
+ENDstrgen
+
+
+BEGINmodExit
+CODESTARTmodExit
+ENDmodExit
+
+
+BEGINqueryEtryPt
+CODESTARTqueryEtryPt
+CODEqueryEtryPt_STD_SMOD_QUERIES
+ENDqueryEtryPt
+
+
+BEGINmodInit(smfile)
+CODESTARTmodInit
+ *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
+CODEmodInit_QueryRegCFSLineHdlr
+
+ dbgprintf("rsyslog standard file format strgen init called, compiled with version %s\n", VERSION);
+ENDmodInit
diff --git a/tools/smfile.h b/tools/smfile.h
new file mode 100644
index 00000000..10946db5
--- /dev/null
+++ b/tools/smfile.h
@@ -0,0 +1,31 @@
+/* smfile.h
+ * These are the definitions for the traditional file format stringen module.
+ *
+ * File begun on 2010-06-04 by RGerhards
+ *
+ * Copyright 2010 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.
+ */
+#ifndef SMFILE_H_INCLUDED
+#define SMFILE_H_INCLUDED 1
+
+/* prototypes */
+rsRetVal modInitsmfile(int iIFVersRequested __attribute__((unused)), int *ipIFVersProvided, rsRetVal (**pQueryEtryPt)(), rsRetVal (*pHostQueryEtryPt)(uchar*, rsRetVal (**)()), modInfo_t*);
+
+#endif /* #ifndef SMFILE_H_INCLUDED */
diff --git a/tools/smfwd.c b/tools/smfwd.c
new file mode 100644
index 00000000..fe33fb2c
--- /dev/null
+++ b/tools/smfwd.c
@@ -0,0 +1,142 @@
+/* smfwd.c
+ * This is a strgen module for the traditional (network) forwarding format.
+ *
+ * Format generated:
+ * "<%PRI%>%TIMESTAMP:::date-rfc3339% %HOSTNAME% %syslogtag:1:32%%msg:::sp-if-no-1st-sp%%msg%"
+ *
+ * NOTE: read comments in module-template.h to understand how this file
+ * works!
+ *
+ * File begun on 2010-06-01 by RGerhards
+ *
+ * Copyright 2010 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 <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include "syslogd.h"
+#include "conf.h"
+#include "syslogd-types.h"
+#include "template.h"
+#include "msg.h"
+#include "module-template.h"
+#include "unicode-helper.h"
+
+MODULE_TYPE_STRGEN
+STRGEN_NAME("RSYSLOG_ForwardFormat")
+
+/* internal structures
+ */
+DEF_SMOD_STATIC_DATA
+
+
+/* config data */
+
+
+/* This strgen tries to minimize the amount of reallocs be first obtaining pointers to all strings
+ * needed (including their length) and then calculating the actual space required. So when we
+ * finally copy, we know exactly what we need. So we do at most one alloc.
+ */
+BEGINstrgen
+ register int iBuf;
+ char *pPRI;
+ size_t lenPRI;
+ uchar *pTimeStamp;
+ size_t lenTimeStamp;
+ uchar *pHOSTNAME;
+ size_t lenHOSTNAME;
+ uchar *pTAG;
+ int lenTAG;
+ uchar *pMSG;
+ size_t lenMSG;
+ size_t lenTotal;
+CODESTARTstrgen
+ /* first obtain all strings and their length (if not fixed) */
+ pPRI = getPRI(pMsg);
+ lenPRI = strlen(pPRI);
+ pTimeStamp = (uchar*) getTimeReported(pMsg, tplFmtRFC3339Date);
+ lenTimeStamp = ustrlen(pTimeStamp);
+ pHOSTNAME = (uchar*) getHOSTNAME(pMsg);
+ lenHOSTNAME = getHOSTNAMELen(pMsg);
+ getTAG(pMsg, &pTAG, &lenTAG);
+ if(lenTAG > 32)
+ lenTAG = 32; /* for forwarding, a max of 32 chars is permitted (RFC!) */
+ pMSG = getMSG(pMsg);
+ lenMSG = getMSGLen(pMsg);
+
+ /* calculate len, constants for spaces and similar fixed strings */
+ lenTotal = 1 + lenPRI + 1 + lenTimeStamp + 1 + lenHOSTNAME + 1 + lenTAG + lenMSG + 1;
+ if(pMSG[0] != ' ')
+ ++lenTotal; /* then we need to introduce one additional space */
+
+ /* now make sure buffer is large enough */
+ if(lenTotal >= *pLenBuf)
+ CHKiRet(ExtendBuf(ppBuf, pLenBuf, lenTotal));
+
+ /* and concatenate the resulting string */
+ **ppBuf = '<';
+ memcpy(*ppBuf + 1, pPRI, lenPRI);
+ iBuf = lenPRI + 1;
+ *(*ppBuf + iBuf++) = '>';
+
+ memcpy(*ppBuf + iBuf, pTimeStamp, lenTimeStamp);
+ iBuf += lenTimeStamp;
+ *(*ppBuf + iBuf++) = ' ';
+
+ memcpy(*ppBuf + iBuf, pHOSTNAME, lenHOSTNAME);
+ iBuf += lenHOSTNAME;
+ *(*ppBuf + iBuf++) = ' ';
+
+ memcpy(*ppBuf + iBuf, pTAG, lenTAG);
+ iBuf += lenTAG;
+
+ if(pMSG[0] != ' ')
+ *(*ppBuf + iBuf++) = ' ';
+ memcpy(*ppBuf + iBuf, pMSG, lenMSG);
+ iBuf += lenMSG;
+
+ /* string terminator */
+ *(*ppBuf + iBuf) = '\0';
+
+finalize_it:
+ENDstrgen
+
+
+BEGINmodExit
+CODESTARTmodExit
+ENDmodExit
+
+
+BEGINqueryEtryPt
+CODESTARTqueryEtryPt
+CODEqueryEtryPt_STD_SMOD_QUERIES
+ENDqueryEtryPt
+
+
+BEGINmodInit(smfwd)
+CODESTARTmodInit
+ *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
+CODEmodInit_QueryRegCFSLineHdlr
+
+ dbgprintf("rsyslog standard (network) forward format strgen init called, compiled with version %s\n", VERSION);
+ENDmodInit
diff --git a/tools/smfwd.h b/tools/smfwd.h
new file mode 100644
index 00000000..191a6bf1
--- /dev/null
+++ b/tools/smfwd.h
@@ -0,0 +1,30 @@
+/* smfwd.h
+ *
+ * File begun on 2010-06-04 by RGerhards
+ *
+ * Copyright 2010 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.
+ */
+#ifndef SMFWD_H_INCLUDED
+#define SMFWD_H_INCLUDED 1
+
+/* prototypes */
+rsRetVal modInitsmfwd(int iIFVersRequested __attribute__((unused)), int *ipIFVersProvided, rsRetVal (**pQueryEtryPt)(), rsRetVal (*pHostQueryEtryPt)(uchar*, rsRetVal (**)()), modInfo_t*);
+
+#endif /* #ifndef SMFWD_H_INCLUDED */
diff --git a/tools/smtradfile.c b/tools/smtradfile.c
new file mode 100644
index 00000000..eff2f99a
--- /dev/null
+++ b/tools/smtradfile.c
@@ -0,0 +1,128 @@
+/* smtradfile.c
+ * This is a strgen module for the traditional file format.
+ *
+ * Format generated:
+ * "%TIMESTAMP% %HOSTNAME% %syslogtag%%msg:::sp-if-no-1st-sp%%msg:::drop-last-lf%\n"
+ *
+ * NOTE: read comments in module-template.h to understand how this file
+ * works!
+ *
+ * File begun on 2010-06-01 by RGerhards
+ *
+ * Copyright 2010 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 <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include "syslogd.h"
+#include "conf.h"
+#include "syslogd-types.h"
+#include "template.h"
+#include "msg.h"
+#include "module-template.h"
+#include "unicode-helper.h"
+
+MODULE_TYPE_STRGEN
+STRGEN_NAME("RSYSLOG_TraditionalFileFormat")
+
+/* internal structures
+ */
+DEF_SMOD_STATIC_DATA
+
+
+/* config data */
+
+
+/* This strgen tries to minimize the amount of reallocs be first obtaining pointers to all strings
+ * needed (including their length) and then calculating the actual space required. So when we
+ * finally copy, we know exactly what we need. So we do at most one alloc.
+ */
+BEGINstrgen
+ register int iBuf;
+ uchar *pTimeStamp;
+ uchar *pHOSTNAME;
+ size_t lenHOSTNAME;
+ uchar *pTAG;
+ int lenTAG;
+ uchar *pMSG;
+ size_t lenMSG;
+ size_t lenTotal;
+CODESTARTstrgen
+ /* first obtain all strings and their length (if not fixed) */
+ pTimeStamp = (uchar*) getTimeReported(pMsg, tplFmtRFC3164Date);
+ pHOSTNAME = (uchar*) getHOSTNAME(pMsg);
+ lenHOSTNAME = getHOSTNAMELen(pMsg);
+ getTAG(pMsg, &pTAG, &lenTAG);
+ pMSG = getMSG(pMsg);
+ lenMSG = getMSGLen(pMsg);
+
+ /* calculate len, constants for spaces and similar fixed strings */
+ lenTotal = CONST_LEN_TIMESTAMP_3164 + 1 + lenHOSTNAME + 1 + lenTAG + lenMSG + 2;
+ if(pMSG[0] != ' ')
+ ++lenTotal; /* then we need to introduce one additional space */
+
+ /* now make sure buffer is large enough */
+ if(lenTotal >= *pLenBuf)
+ CHKiRet(ExtendBuf(ppBuf, pLenBuf, lenTotal));
+
+ /* and concatenate the resulting string */
+ memcpy(*ppBuf, pTimeStamp, CONST_LEN_TIMESTAMP_3164);
+ *(*ppBuf + CONST_LEN_TIMESTAMP_3164) = ' ';
+
+ memcpy(*ppBuf + CONST_LEN_TIMESTAMP_3164 + 1, pHOSTNAME, lenHOSTNAME);
+ iBuf = CONST_LEN_TIMESTAMP_3164 + 1 + lenHOSTNAME;
+ *(*ppBuf + iBuf++) = ' ';
+
+ memcpy(*ppBuf + iBuf, pTAG, lenTAG);
+ iBuf += lenTAG;
+
+ if(pMSG[0] != ' ')
+ *(*ppBuf + iBuf++) = ' ';
+ memcpy(*ppBuf + iBuf, pMSG, lenMSG);
+ iBuf += lenMSG;
+
+ /* trailer */
+ *(*ppBuf + iBuf++) = '\n';
+ *(*ppBuf + iBuf) = '\0';
+
+finalize_it:
+ENDstrgen
+
+
+BEGINmodExit
+CODESTARTmodExit
+ENDmodExit
+
+
+BEGINqueryEtryPt
+CODESTARTqueryEtryPt
+CODEqueryEtryPt_STD_SMOD_QUERIES
+ENDqueryEtryPt
+
+
+BEGINmodInit(smtradfile)
+CODESTARTmodInit
+ *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
+CODEmodInit_QueryRegCFSLineHdlr
+ dbgprintf("traditional file format strgen init called, compiled with version %s\n", VERSION);
+ENDmodInit
diff --git a/tools/smtradfile.h b/tools/smtradfile.h
new file mode 100644
index 00000000..afc737ed
--- /dev/null
+++ b/tools/smtradfile.h
@@ -0,0 +1,31 @@
+/* smtradfile.h
+ * These are the definitions for the traditional file format stringen module.
+ *
+ * File begun on 2010-06-01 by RGerhards
+ *
+ * Copyright 2010 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.
+ */
+#ifndef SMTRADFILE_H_INCLUDED
+#define SMTRADFILE_H_INCLUDED 1
+
+/* prototypes */
+rsRetVal modInitsmtradfile(int iIFVersRequested __attribute__((unused)), int *ipIFVersProvided, rsRetVal (**pQueryEtryPt)(), rsRetVal (*pHostQueryEtryPt)(uchar*, rsRetVal (**)()), modInfo_t*);
+
+#endif /* #ifndef SMTRADFILE_H_INCLUDED */
diff --git a/tools/smtradfwd.c b/tools/smtradfwd.c
new file mode 100644
index 00000000..88dc6082
--- /dev/null
+++ b/tools/smtradfwd.c
@@ -0,0 +1,139 @@
+/* smtradfwd.c
+ * This is a strgen module for the traditional forwarding format.
+ *
+ * Format generated:
+ * "<%PRI%>%TIMESTAMP% %HOSTNAME% %syslogtag:1:32%%msg:::sp-if-no-1st-sp%%msg%"
+ *
+ * NOTE: read comments in module-template.h to understand how this file
+ * works!
+ *
+ * File begun on 2010-06-01 by RGerhards
+ *
+ * Copyright 2010 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 <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include "syslogd.h"
+#include "conf.h"
+#include "syslogd-types.h"
+#include "template.h"
+#include "msg.h"
+#include "module-template.h"
+#include "unicode-helper.h"
+
+MODULE_TYPE_STRGEN
+STRGEN_NAME("RSYSLOG_TraditionalForwardFormat")
+
+/* internal structures
+ */
+DEF_SMOD_STATIC_DATA
+
+
+/* config data */
+
+
+/* This strgen tries to minimize the amount of reallocs be first obtaining pointers to all strings
+ * needed (including their length) and then calculating the actual space required. So when we
+ * finally copy, we know exactly what we need. So we do at most one alloc.
+ */
+BEGINstrgen
+ register int iBuf;
+ char *pPRI;
+ size_t lenPRI;
+ uchar *pTimeStamp;
+ uchar *pHOSTNAME;
+ size_t lenHOSTNAME;
+ uchar *pTAG;
+ int lenTAG;
+ uchar *pMSG;
+ size_t lenMSG;
+ size_t lenTotal;
+CODESTARTstrgen
+ /* first obtain all strings and their length (if not fixed) */
+ pPRI = getPRI(pMsg);
+ lenPRI = strlen(pPRI);
+ pTimeStamp = (uchar*) getTimeReported(pMsg, tplFmtRFC3164Date);
+ pHOSTNAME = (uchar*) getHOSTNAME(pMsg);
+ lenHOSTNAME = getHOSTNAMELen(pMsg);
+ getTAG(pMsg, &pTAG, &lenTAG);
+ if(lenTAG > 32)
+ lenTAG = 32; /* for forwarding, a max of 32 chars is permitted (RFC!) */
+ pMSG = getMSG(pMsg);
+ lenMSG = getMSGLen(pMsg);
+
+ /* calculate len, constants for spaces and similar fixed strings */
+ lenTotal = 1 + lenPRI + 1 + CONST_LEN_TIMESTAMP_3164 + 1 + lenHOSTNAME + 1 + lenTAG + lenMSG + 1;
+ if(pMSG[0] != ' ')
+ ++lenTotal; /* then we need to introduce one additional space */
+
+ /* now make sure buffer is large enough */
+ if(lenTotal >= *pLenBuf)
+ CHKiRet(ExtendBuf(ppBuf, pLenBuf, lenTotal));
+
+ /* and concatenate the resulting string */
+ **ppBuf = '<';
+ memcpy(*ppBuf + 1, pPRI, lenPRI);
+ iBuf = lenPRI + 1;
+ *(*ppBuf + iBuf++) = '>';
+
+ memcpy(*ppBuf + iBuf, pTimeStamp, CONST_LEN_TIMESTAMP_3164);
+ iBuf += CONST_LEN_TIMESTAMP_3164;
+ *(*ppBuf + iBuf++) = ' ';
+
+ memcpy(*ppBuf + iBuf, pHOSTNAME, lenHOSTNAME);
+ iBuf += lenHOSTNAME;
+ *(*ppBuf + iBuf++) = ' ';
+
+ memcpy(*ppBuf + iBuf, pTAG, lenTAG);
+ iBuf += lenTAG;
+
+ if(pMSG[0] != ' ')
+ *(*ppBuf + iBuf++) = ' ';
+ memcpy(*ppBuf + iBuf, pMSG, lenMSG);
+ iBuf += lenMSG;
+
+ /* string terminator */
+ *(*ppBuf + iBuf) = '\0';
+
+finalize_it:
+ENDstrgen
+
+
+BEGINmodExit
+CODESTARTmodExit
+ENDmodExit
+
+
+BEGINqueryEtryPt
+CODESTARTqueryEtryPt
+CODEqueryEtryPt_STD_SMOD_QUERIES
+ENDqueryEtryPt
+
+
+BEGINmodInit(smtradfwd)
+CODESTARTmodInit
+ *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
+CODEmodInit_QueryRegCFSLineHdlr
+ dbgprintf("rsyslog traditional (network) forward format strgen init called, compiled with version %s\n", VERSION);
+ENDmodInit
diff --git a/tools/smtradfwd.h b/tools/smtradfwd.h
new file mode 100644
index 00000000..9ff0ab54
--- /dev/null
+++ b/tools/smtradfwd.h
@@ -0,0 +1,30 @@
+/* smtradfwd.h
+ *
+ * File begun on 2010-06-04 by RGerhards
+ *
+ * Copyright 2010 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.
+ */
+#ifndef SMTRADFWD_H_INCLUDED
+#define SMTRADFWD_H_INCLUDED 1
+
+/* prototypes */
+rsRetVal modInitsmtradfwd(int iIFVersRequested __attribute__((unused)), int *ipIFVersProvided, rsRetVal (**pQueryEtryPt)(), rsRetVal (*pHostQueryEtryPt)(uchar*, rsRetVal (**)()), modInfo_t*);
+
+#endif /* #ifndef SMTRADFWD_H_INCLUDED */
diff --git a/tools/syncdemo.c b/tools/syncdemo.c
new file mode 100644
index 00000000..89a5c6cc
--- /dev/null
+++ b/tools/syncdemo.c
@@ -0,0 +1,440 @@
+/* syncdemo - a program to demonstrate the performance and validity of different
+ * synchronization methods as well as some timing properties.
+ *
+ * The task to be done is very simple: a single gloabl integer is to to incremented
+ * by multiple threads. All this is done in a very-high concurrency environment. Note that
+ * the test is unfair to mechanisms likes spinlocks, because we have almost only wait
+ * time but no real processing time between the waits. However, the test provides
+ * some good insight into atomic instructions vs. other synchronisation methods.
+ * It also proves that garbling variables by not doing proper synchronisation is
+ * highly likely. For best results, this program should be executed on a
+ * multiprocessor machine (on a uniprocessor, it will probably not display the
+ * problems caused by missing synchronisation).
+ *
+ * Note: partitioned processing mode means that all computation is first done
+ * locally and the final result is then combined doing proper synchronization.
+ * This mode is used as a baseline for uninterrupted processing.
+ *
+ * compile with $ gcc -O1 -o syncdemo -lpthread syncdemo.c
+ *
+ * Alternatively, you may use -O0, but not a higher level. Note that
+ * the gcc code generator does in neither case generate code really
+ * suitable to compare "part" and "none" modes. If you absolutely need
+ * to do that, you need to use inline assembly. However, the results should
+ * be fairly OK when consitently using either -O0 or -O1. If you see a big loss
+ * of performance when you compare "none" and "part", be sure to run
+ * "none" with -t1 and watch out for the results! In any case, looking at the generated
+ * assembly code is vital to interpret results correctly. Review of generated assembly
+ * done on 2010-05-05 indicates that -O0 is probably the best choice. Note that we
+ * use the volatile attribute in one spot. This is used because it results in the
+ * best comparable result for our gcc 4.4.3, not really to invoke the volatile semantics.
+ *
+ * use "gcc -g -Wa,-ahl=syncdemo.s -lpthread syncdemo.c" to obtain a mixed code/assembly listing.
+ *
+ * This program REQUIRES linux. With slight modification, it may run on Solaris.
+ * Note that gcc on Sparc does NOT offer atomic instruction support!
+ *
+ * Copyright (C) 2010 by Rainer Gerhards <rgerhards@hq.adiscon.com>
+ * Released under the GNU GPLv3.
+ *
+ * Inspired by (retrieved 2010-04-13)
+ * http://www.alexonlinux.com/multithreaded-simple-data-type-access-and-atomic-variables
+ */
+#define _GNU_SOURCE
+#include <sched.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <semaphore.h>
+#include <stdlib.h>
+#include <linux/unistd.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <getopt.h>
+
+
+typedef enum { part, none, atomic, cas, spinlock, mutex, semaphore } syncType_t;
+static syncType_t syncTypes[] = { part, none, atomic, cas, spinlock, mutex, semaphore };
+
+/* config settings */
+static int bCPUAffinity = 0;
+static int procs = 0; /* number of processors */
+static int numthrds = 0; /* if zero, => equal num of processors */
+static unsigned goal = 50000000; /* 50 million */
+static int bCSV = 0; /* generate CSV output? */
+static int numIterations = 1; /* number of iterations */
+static int dummyLoad = 0; /* number of dummy load iterations to generate */
+syncType_t syncType;
+static int bAllSyncTypes = 0;
+
+static int global_int = 0; /* our global counter */
+static unsigned thrd_WorkToDo; /* number of computations each thread must do */
+static volatile int bStartRun = 0; /* indicate to flag when threads should start */
+
+static struct timeval tvStart, tvEnd; /* used for timing one testing iteration */
+
+/* statistic counters */
+static long long totalRuntime;
+static unsigned minRuntime = 999999999;
+static unsigned maxRuntime = 0;
+
+/* sync objects (if needed) */
+static pthread_mutex_t mut;
+static pthread_spinlock_t spin;
+static sem_t sem;
+
+static char*
+getSyncMethName(syncType_t st)
+{
+ switch(st) {
+ case part : return "partition";
+ case none : return "none";
+ case atomic : return "atomic op";
+ case spinlock : return "spin lock";
+ case mutex : return "mutex";
+ case semaphore: return "semaphore";
+ case cas : return "cas";
+ }
+}
+
+
+static pid_t
+gettid()
+{
+ return syscall( __NR_gettid );
+}
+
+
+void *workerThread( void *arg )
+{
+ int i, j;
+ volatile int partval = 0; /* use volatile so that gcc generates code similar to global var */
+ int *partptr;
+ int oldval, newval; /* for CAS sync mode */
+ int thrd_num = (int)(long)arg;
+ cpu_set_t set;
+
+ CPU_ZERO(&set);
+ CPU_SET(thrd_num % procs, &set);
+ if(syncType == part) {
+ partval = 0;
+ }
+
+ /* if enabled, try to put thread on a fixed CPU (the one that corresponds to the
+ * thread ID). This may
+ */
+ if(bCPUAffinity) {
+ if (sched_setaffinity( gettid(), sizeof( cpu_set_t ), &set )) {
+ perror( "sched_setaffinity" );
+ return NULL;
+ }
+ }
+
+ /* wait for "go" */
+ while(bStartRun == 0)
+ /*WAIT!*/;
+
+ for (i = 0; i < thrd_WorkToDo; i++) {
+ switch(syncType) {
+ case part:
+ ///* one needs to use inline assembly to get this right... */
+ //asm("addl $1, global_int(%rip)");
+ partval++;
+ break;
+ case none:
+ global_int++;
+ break;
+ case atomic:
+ __sync_fetch_and_add(&global_int,1);
+ break;
+ case cas:
+ do {
+ oldval = global_int;
+ newval = oldval + 1;
+ } while(!__sync_bool_compare_and_swap(&global_int, oldval, newval));
+ break;
+ case mutex:
+ pthread_mutex_lock(&mut);
+ global_int++;
+ pthread_mutex_unlock(&mut);
+ break;
+ case spinlock:
+ pthread_spin_lock(&spin);
+ global_int++;
+ pthread_spin_unlock(&spin);
+ break;
+ case semaphore:
+ sem_wait(&sem);
+ global_int++;
+ sem_post(&sem);
+ break;
+ }
+
+ /* we now generate "dummy load" if instructed to do so. The idea is that
+ * we do some other work, as in real life, so that we have a better
+ * ratio of sync vs. actual work to do.
+ */
+ for(j = 0 ; j < dummyLoad ; ++j) {
+ /* be careful: compiler may optimize loop out! */;
+ }
+ }
+
+ if(syncType == part) {
+ pthread_mutex_lock(&mut);
+ global_int += partval;
+ pthread_mutex_unlock(&mut);
+ }
+
+ return NULL;
+}
+
+
+static void beginTiming(void)
+{
+ if(!(bCSV || bAllSyncTypes)) {
+ printf("Test Parameters:\n");
+ printf("\tNumber of Cores.........: %d\n", procs);
+ printf("\tNumber of Threads.......: %d\n", numthrds);
+ printf("\tSet Affinity............: %s\n", bCPUAffinity ? "yes" : "no");
+ printf("\tCount to................: %u\n", goal);
+ printf("\tWork for each Thread....: %u\n", thrd_WorkToDo);
+ printf("\tDummy Load Counter......: %d\n", dummyLoad);
+ printf("\tSync Method used........: %s\n", getSyncMethName(syncType));
+ }
+ gettimeofday(&tvStart, NULL);
+}
+
+
+static void endTiming(void)
+{
+ unsigned delta;
+ long sec, usec;
+ long runtime;
+
+ gettimeofday(&tvEnd, NULL);
+ if(tvStart.tv_usec > tvEnd.tv_usec) {
+ tvEnd.tv_sec--;
+ tvEnd.tv_usec += 1000000;
+ }
+
+ sec = tvEnd.tv_sec - tvStart.tv_sec;
+ usec = tvEnd.tv_usec - tvStart.tv_usec;
+
+ delta = thrd_WorkToDo * numthrds - global_int;
+ if(!bAllSyncTypes) {
+ if(bCSV) {
+ printf("%s,%d,%d,%d,%u,%u,%ld.%06.6ld\n",
+ getSyncMethName(syncType), procs, numthrds, bCPUAffinity, goal, delta, sec, usec);
+ } else {
+ printf("measured (sytem time) runtime is %ld.% 6.6ld seconds\n", sec, usec);
+ if(delta == 0) {
+ printf("Computation was done correctly.\n");
+ } else {
+ printf("Computation INCORRECT,\n"
+ "\texpected %9u\n"
+ "\treal %9u\n"
+ "\toff by %9u\n",
+ thrd_WorkToDo * numthrds,
+ global_int,
+ delta);
+ }
+ }
+ }
+
+ runtime = sec * 1000 + (usec / 1000);
+ totalRuntime += runtime;
+ if(runtime < minRuntime)
+ minRuntime = runtime;
+ if(runtime > maxRuntime)
+ maxRuntime = runtime;
+}
+
+
+static void
+usage(void)
+{
+ fprintf(stderr, "Usage: syncdemo -a -c<num> -t<num>\n");
+ fprintf(stderr, "\t-a set CPU affinity\n");
+ fprintf(stderr, "\t-i number of iterations\n");
+ fprintf(stderr, "\t-c<num> count to <num>\n");
+ fprintf(stderr, "\t-d<num> dummy load, <num> iterations\n");
+ fprintf(stderr, "\t-t<num> number of threads to use\n");
+ fprintf(stderr, "\t-s<type> sync-type to use (none, atomic, mutex, spin, semaphore)\n");
+ fprintf(stderr, "\t-C generate CSV output\n");
+ fprintf(stderr, "\t-A test ALL sync types\n");
+ exit(2);
+}
+
+
+/* carry out the actual test (one iteration)
+ */
+static void
+singleTest(void)
+{
+ int i;
+ pthread_t *thrs;
+
+ global_int = 0;
+ bStartRun = 0;
+
+ thrs = malloc(sizeof(pthread_t) * numthrds);
+ if (thrs == NULL) {
+ perror( "malloc" );
+ exit(1);
+ }
+
+ thrd_WorkToDo = goal / numthrds;
+
+ for (i = 0; i < numthrds; i++) {
+ if(pthread_create( &thrs[i], NULL, workerThread, (void *)(long)i )) {
+ perror( "pthread_create" );
+ procs = i;
+ break;
+ }
+ }
+
+ beginTiming();
+ bStartRun = 1; /* start the threads (they are busy-waiting so far!) */
+
+ for (i = 0; i < numthrds; i++)
+ pthread_join( thrs[i], NULL );
+
+ endTiming();
+
+ free( thrs );
+
+}
+
+
+/* display an unsigned ms runtime count as string. Note that the
+ * string is inside a dynamically allocated buffer, which the caller
+ * must free to prevent a memory leak.
+ */
+char *
+dispRuntime(unsigned rt)
+{
+ static char *fmtbuf;
+
+ fmtbuf = malloc(32 * sizeof(char));
+ snprintf(fmtbuf, 32, "%u.%03.3u",
+ rt / 1000, rt % 1000);
+ return(fmtbuf);
+}
+
+
+doTest(syncType_t st)
+{
+ int i;
+
+ syncType = st;
+ totalRuntime = 0;
+ minRuntime = 999999999;
+ maxRuntime = 0;
+ for(i = 0 ; i < numIterations ; ++i) {
+ //printf("starting iteration %d\n", i);
+ singleTest();
+ }
+
+ /* we have a memory leak due to calling dispRuntime(), but we don't
+ * care as we terminate immediately.
+ */
+ printf("%-10s: total runtime %6ld.%3.3u, avg %s, min %s, max %s\n",
+ getSyncMethName(st),
+ (long)totalRuntime/1000, (unsigned)(totalRuntime % 1000),
+ dispRuntime((unsigned) (totalRuntime / numIterations)),
+ dispRuntime(minRuntime),
+ dispRuntime(maxRuntime));
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ int i;
+ int opt;
+
+ while((opt = getopt(argc, argv, "ac:d:i:t:s:CA")) != EOF) {
+ switch((char)opt) {
+ case 'A':
+ bAllSyncTypes = 1;
+ break;
+ case 'a':
+ bCPUAffinity = 1;
+ break;
+ case 'c':
+ goal = (unsigned) atol(optarg);
+ break;
+ case 'd':
+ dummyLoad = atoi(optarg);
+ break;
+ case 'i':
+ numIterations = atoi(optarg);
+ break;
+ case 't':
+ numthrds = atoi(optarg);
+ break;
+ case 'C':
+ bCSV = 1;
+ break;
+ case 's':
+ if(!strcmp(optarg, "none"))
+ syncType = none;
+ else if(!strcmp(optarg, "part"))
+ syncType = part;
+ else if(!strcmp(optarg, "atomic"))
+ syncType = atomic;
+ else if(!strcmp(optarg, "cas"))
+ syncType = cas;
+ else if(!strcmp(optarg, "mutex")) {
+ syncType = mutex;
+ pthread_mutex_init(&mut, NULL);
+ } else if(!strcmp(optarg, "spin")) {
+ syncType = spinlock;
+ } else if(!strcmp(optarg, "semaphore")) {
+ syncType = semaphore;
+ sem_init(&sem, 0, 1);
+ } else {
+ fprintf(stderr, "error: invalid sync mode '%s'\n", optarg);
+ usage();
+ }
+ break;
+ default:usage();
+ break;
+ }
+ }
+
+ /* for simplicity, we init all sync helpers no matter if we need them */
+ pthread_mutex_init(&mut, NULL);
+ pthread_spin_init(&spin, PTHREAD_PROCESS_PRIVATE);
+ sem_init(&sem, 0, 1);
+
+ /* Getting number of CPUs */
+ procs = (int)sysconf(_SC_NPROCESSORS_ONLN);
+ if(procs < 0) {
+ perror("sysconf");
+ return -1;
+ }
+
+ if(numthrds < 1) {
+ numthrds = procs;
+ }
+
+ if(bAllSyncTypes) {
+ for(i = 0 ; i < sizeof(syncTypes) / sizeof(syncType_t) ; ++i) {
+ doTest(syncTypes[i]);
+ }
+ printf("Done running tests, result based on:\n");
+ printf("\tNumber of Cores.........: %d\n", procs);
+ printf("\tNumber of Threads.......: %d\n", numthrds);
+ printf("\tSet CPU Affinity........: %s\n", bCPUAffinity ? "yes" : "no");
+ printf("\tCount to................: %u\n", goal);
+ printf("\tWork for each Thread....: %u\n", thrd_WorkToDo);
+ printf("\tDummy Load Counter......: %d\n", dummyLoad);
+ printf("\tIterations..............: %d\n", numIterations);
+ } else {
+ doTest(syncType);
+ }
+
+ return 0;
+}
diff --git a/tools/syslogd.c b/tools/syslogd.c
index 887ffbd2..9b7b77ab 100644
--- a/tools/syslogd.c
+++ b/tools/syslogd.c
@@ -20,18 +20,6 @@
*
* For further information, please see http://www.rsyslog.com
*
- * \author Rainer Gerhards <rgerhards@adiscon.com>
- * \date 2003-10-17
- * Some initial modifications on the sysklogd package to support
- * liblogging. These have actually not yet been merged to the
- * source you see currently (but they hopefully will)
- *
- * \date 2004-10-28
- * Restarted the modifications of sysklogd. This time, we
- * focus on a simpler approach first. The initial goal is to
- * provide MySQL database support (so that syslogd can log
- * to the database).
- *
* rsyslog - An Enhanced syslogd Replacement.
* Copyright 2003-2009 Rainer Gerhards and Adiscon GmbH.
*
@@ -128,6 +116,10 @@
#include "omdiscard.h"
#include "pmrfc5424.h"
#include "pmrfc3164.h"
+#include "smfile.h"
+#include "smtradfile.h"
+#include "smfwd.h"
+#include "smtradfwd.h"
#include "threads.h"
#include "wti.h"
#include "queue.h"
@@ -333,15 +325,15 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a
/* hardcoded standard templates (used for defaults) */
static uchar template_DebugFormat[] = "\"Debug line with all properties:\nFROMHOST: '%FROMHOST%', fromhost-ip: '%fromhost-ip%', HOSTNAME: '%HOSTNAME%', PRI: %PRI%,\nsyslogtag '%syslogtag%', programname: '%programname%', APP-NAME: '%APP-NAME%', PROCID: '%PROCID%', MSGID: '%MSGID%',\nTIMESTAMP: '%TIMESTAMP%', STRUCTURED-DATA: '%STRUCTURED-DATA%',\nmsg: '%msg%'\nescaped msg: '%msg:::drop-cc%'\nrawmsg: '%rawmsg%'\n\n\"";
static uchar template_SyslogProtocol23Format[] = "\"<%PRI%>1 %TIMESTAMP:::date-rfc3339% %HOSTNAME% %APP-NAME% %PROCID% %MSGID% %STRUCTURED-DATA% %msg%\n\"";
-static uchar template_TraditionalFileFormat[] = "\"%TIMESTAMP% %HOSTNAME% %syslogtag%%msg:::sp-if-no-1st-sp%%msg:::drop-last-lf%\n\"";
-static uchar template_FileFormat[] = "\"%TIMESTAMP:::date-rfc3339% %HOSTNAME% %syslogtag%%msg:::sp-if-no-1st-sp%%msg:::drop-last-lf%\n\"";
+static uchar template_TraditionalFileFormat[] = "=RSYSLOG_TraditionalFileFormat";
+static uchar template_FileFormat[] = "=RSYSLOG_FileFormat";
+static uchar template_ForwardFormat[] = "=RSYSLOG_ForwardFormat";
+static uchar template_TraditionalForwardFormat[] = "=RSYSLOG_TraditionalForwardFormat";
static uchar template_WallFmt[] = "\"\r\n\7Message from syslogd@%HOSTNAME% at %timegenerated% ...\r\n %syslogtag%%msg%\n\r\"";
-static uchar template_ForwardFormat[] = "\"<%PRI%>%TIMESTAMP:::date-rfc3339% %HOSTNAME% %syslogtag:1:32%%msg:::sp-if-no-1st-sp%%msg%\"";
-static uchar template_TraditionalForwardFormat[] = "\"<%PRI%>%TIMESTAMP% %HOSTNAME% %syslogtag:1:32%%msg:::sp-if-no-1st-sp%%msg%\"";
static uchar template_StdUsrMsgFmt[] = "\" %syslogtag%%msg%\n\r\"";
static uchar template_StdDBFmt[] = "\"insert into SystemEvents (Message, Facility, FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values ('%msg%', %syslogfacility%, '%HOSTNAME%', %syslogpriority%, '%timereported:::date-mysql%', '%timegenerated:::date-mysql%', %iut%, '%syslogtag%')\",SQL";
static uchar template_StdPgSQLFmt[] = "\"insert into SystemEvents (Message, Facility, FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values ('%msg%', %syslogfacility%, '%HOSTNAME%', %syslogpriority%, '%timereported:::date-pgsql%', '%timegenerated:::date-pgsql%', %iut%, '%syslogtag%')\",STDSQL";
-/* end template */
+/* end templates */
/* up to the next comment, prototypes that should be removed by reordering */
@@ -574,7 +566,7 @@ logmsgInternal(int iErr, int pri, uchar *msg, int flags)
* permits us to process unmodified config files which otherwise contain a
* supressor statement.
*/
- if(((Debug || NoFork) && bErrMsgToStderr) || iConfigVerify) {
+ if(((Debug == DEBUG_FULL || NoFork) && bErrMsgToStderr) || iConfigVerify) {
if(LOG_PRI(pri) == LOG_ERR)
fprintf(stderr, "rsyslogd: %s\n", msg);
}
@@ -591,6 +583,106 @@ finalize_it:
RETiRet;
}
+/* check message against ACL set
+ * rgerhards, 2009-11-16
+ */
+#if 0
+static inline rsRetVal
+chkMsgAgainstACL() {
+ /* 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(net.CmpHost(&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;
+
+ datetime.GetTime(&tt);
+ if(tt > ttLastDiscard + 60) {
+ ttLastDiscard = tt;
+ errmsg.LogError(0, NO_ERRCODE,
+ "UDP message from disallowed sender %s discarded",
+ (char*)fromHost);
+ }
+ }
+ }
+ }
+}
+#endif
+
+
+/* preprocess a batch of messages, that is ready them for actual processing. This is done
+ * as a first stage and totally in parallel to any other worker active in the system. So
+ * it helps us keep up the overall concurrency level.
+ * rgerhards, 2010-06-09
+ */
+static inline rsRetVal
+preprocessBatch(batch_t *pBatch) {
+ uchar fromHost[NI_MAXHOST];
+ uchar fromHostIP[NI_MAXHOST];
+ uchar fromHostFQDN[NI_MAXHOST];
+ prop_t *propFromHost = NULL;
+ prop_t *propFromHostIP = NULL;
+ int bSingleRuleset;
+ ruleset_t *batchRuleset; /* the ruleset used for all message inside the batch, if there is a single one */
+ int bIsPermitted;
+ msg_t *pMsg;
+ int i;
+ rsRetVal localRet;
+ DEFiRet;
+
+ bSingleRuleset = 1;
+ batchRuleset = (pBatch->nElem > 0) ? ((msg_t*) pBatch->pElem[0].pUsrp)->pRuleset : NULL;
+
+ for(i = 0 ; i < pBatch->nElem && !*(pBatch->pbShutdownImmediate) ; i++) {
+ pMsg = (msg_t*) pBatch->pElem[i].pUsrp;
+ if((pMsg->msgFlags & NEEDS_ACLCHK_U) != 0) {
+ DBGPRINTF("msgConsumer: UDP ACL must be checked for message (hostname-based)\n");
+ if(net.cvthname(pMsg->rcvFrom.pfrominet, fromHost, fromHostFQDN, fromHostIP) != RS_RET_OK)
+ continue;
+ bIsPermitted = net.isAllowedSender2((uchar*)"UDP",
+ (struct sockaddr *)pMsg->rcvFrom.pfrominet, (char*)fromHostFQDN, 1);
+ if(!bIsPermitted) {
+ DBGPRINTF("Message from '%s' discarded, not a permitted sender host\n",
+ fromHostFQDN);
+ pBatch->pElem[i].state = BATCH_STATE_DISC;
+ } else {
+ /* save some of the info we obtained */
+ MsgSetRcvFromStr(pMsg, fromHost, ustrlen(fromHost), &propFromHost);
+ CHKiRet(MsgSetRcvFromIPStr(pMsg, fromHostIP, ustrlen(fromHostIP), &propFromHostIP));
+ pMsg->msgFlags &= ~NEEDS_ACLCHK_U;
+ }
+ }
+ if((pMsg->msgFlags & NEEDS_PARSING) != 0) {
+ if((localRet = parser.ParseMsg(pMsg)) != RS_RET_OK) {
+ DBGPRINTF("Message discarded, parsing error %d\n", localRet);
+ pBatch->pElem[i].state = BATCH_STATE_DISC;
+ }
+ }
+ if(pMsg->pRuleset != batchRuleset)
+ bSingleRuleset = 0;
+ }
+
+ batchSetSingleRuleset(pBatch, bSingleRuleset);
+
+finalize_it:
+ if(propFromHost != NULL)
+ prop.Destruct(&propFromHost);
+ if(propFromHostIP != NULL)
+ prop.Destruct(&propFromHostIP);
+ RETiRet;
+}
/* The consumer of dequeued messages. This function is called by the
* queue engine on dequeueing of a message. It runs on a SEPARATE
@@ -601,27 +693,18 @@ finalize_it:
static rsRetVal
msgConsumer(void __attribute__((unused)) *notNeeded, batch_t *pBatch, int *pbShutdownImmediate)
{
- int i;
- msg_t *pMsg;
- rsRetVal localRet;
DEFiRet;
-
assert(pBatch != NULL);
-
+ pBatch->pbShutdownImmediate = pbShutdownImmediate; /* TODO: move this to batch creation! */
+ preprocessBatch(pBatch);
+//pBatch->bSingleRuleset = 0; // TODO: testing aid, remove!!!!
+ ruleset.ProcessBatch(pBatch);
+//TODO: the BATCH_STATE_COMM must be set somewhere down the road, but we
+//do not have this yet and so we emulate -- 2010-06-10
+int i;
for(i = 0 ; i < pBatch->nElem && !*pbShutdownImmediate ; i++) {
- pMsg = (msg_t*) pBatch->pElem[i].pUsrp;
- DBGPRINTF("msgConsumer processes msg %d/%d\n", i, pBatch->nElem);
- if((pMsg->msgFlags & NEEDS_PARSING) != 0) {
- localRet = parser.ParseMsg(pMsg);
- if(localRet == RS_RET_OK)
- ruleset.ProcessMsg(pMsg);
- } else {
- ruleset.ProcessMsg(pMsg);
- }
- /* if we reach this point, the message is considered committed (by definition!) */
pBatch->pElem[i].state = BATCH_STATE_COMM;
}
-
RETiRet;
}
@@ -671,7 +754,7 @@ multiSubmitMsg(multi_submit_t *pMultiSub)
pRuleset = MsgGetRuleset(pMultiSub->ppMsgs[0]);
pQueue = (pRuleset == NULL) ? pMsgQueue : ruleset.GetRulesetQueue(pRuleset);
- iRet = qqueueMultiEnqObj(pQueue, pMultiSub);
+ iRet = pQueue->MultiEnq(pQueue, pMultiSub);
pMultiSub->nElem = 0;
finalize_it:
@@ -909,10 +992,10 @@ static void doDie(int sig)
# define MSG2 "DoDie called 5 times - unconditional exit\n"
static int iRetries = 0; /* debug aid */
dbgprintf(MSG1);
- if(Debug)
+ if(Debug == DEBUG_FULL)
write(1, MSG1, sizeof(MSG1) - 1);
if(iRetries++ == 4) {
- if(Debug)
+ if(Debug == DEBUG_FULL)
write(1, MSG2, sizeof(MSG2) - 1);
abort();
}
@@ -1091,6 +1174,9 @@ static rsRetVal setMaxFiles(void __attribute__((unused)) *pVal, int iFiles)
iFiles, errStr, (long) maxFiles.rlim_max);
ABORT_FINALIZE(RS_RET_ERR_RLIM_NOFILE);
}
+#ifdef USE_UNLIMITED_SELECT
+ glbl.SetFdSetSize(howmany(iFiles, __NFDBITS) * sizeof (fd_mask));
+#endif
DBGPRINTF("Max number of files set to %d [kernel max %ld].\n", iFiles, (long) maxFiles.rlim_max);
finalize_it:
@@ -1673,6 +1759,25 @@ finalize_it:
}
+
+/* Put the rsyslog main thread to sleep for n seconds. This was introduced as
+ * a quick and dirty workaround for a privilege drop race in regard to listener
+ * startup, which itself was a result of the not-yet-done proper coding of
+ * privilege drop code (quite some effort). It may be useful for other occasions, too.
+ * is specified).
+ * rgerhards, 2009-06-12
+ */
+static rsRetVal
+putToSleep(void __attribute__((unused)) *pVal, int iNewVal)
+{
+ DEFiRet;
+ DBGPRINTF("rsyslog main thread put to sleep via $sleep %d directive...\n", iNewVal);
+ srSleep(iNewVal, 0);
+ DBGPRINTF("rsyslog main thread continues after $sleep %d\n", iNewVal);
+ RETiRet;
+}
+
+
/* Switch to either an already existing rule set or start a new one. The
* named rule set becomes the new "current" rule set (what means that new
* actions are added to it).
@@ -1918,6 +2023,12 @@ static rsRetVal loadBuildInModules(void)
CHKiRet(parser.AddDfltParser(UCHAR_CONSTANT("rsyslog.rfc5424")));
CHKiRet(parser.AddDfltParser(UCHAR_CONSTANT("rsyslog.rfc3164")));
+ /* load build-in strgen modules */
+ CHKiRet(module.doModInit(modInitsmfile, UCHAR_CONSTANT("builtin-smfile"), NULL));
+ CHKiRet(module.doModInit(modInitsmtradfile, UCHAR_CONSTANT("builtin-smtradfile"), NULL));
+ CHKiRet(module.doModInit(modInitsmfwd, UCHAR_CONSTANT("builtin-smfwd"), NULL));
+ CHKiRet(module.doModInit(modInitsmtradfwd, UCHAR_CONSTANT("builtin-smtradfwd"), NULL));
+
/* ok, initialization of the command handler probably does not 100% belong right in
* this space here. However, with the current design, this is actually quite a good
* place to put it. We might decide to shuffle it around later, but for the time
@@ -1929,6 +2040,7 @@ static rsRetVal loadBuildInModules(void)
CHKiRet(regCfSysLineHdlr((uchar *)"actionresumeretrycount", 0, eCmdHdlrInt, NULL, &glbliActionResumeRetryCount, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"defaultruleset", 0, eCmdHdlrGetWord, setDefaultRuleset, NULL, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"ruleset", 0, eCmdHdlrGetWord, setCurrRuleset, NULL, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"sleep", 0, eCmdHdlrInt, putToSleep, NULL, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuefilename", 0, eCmdHdlrGetWord, NULL, &pszMainMsgQFName, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuesize", 0, eCmdHdlrInt, NULL, &iMainMsgQueueSize, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuehighwatermark", 0, eCmdHdlrInt, NULL, &iMainMsgQHighWtrMark, NULL));
@@ -2035,10 +2147,6 @@ static rsRetVal mainThread()
DEFiRet;
uchar *pTmp;
- /* Note: signals MUST be processed by the thread this code is running in. The reason
- * is that we need to interrupt the select() system call. -- rgerhards, 2007-10-17
- */
-
/* initialize the build-in templates */
pTmp = template_DebugFormat;
tplAddLine("RSYSLOG_DebugFormat", &pTmp);
@@ -2102,7 +2210,7 @@ static rsRetVal mainThread()
* is still in its infancy (and not really done), we currently accept this issue.
* rgerhards, 2009-06-29
*/
- if(!(Debug || NoFork)) {
+ if(!(Debug == DEBUG_FULL || NoFork)) {
close(1);
close(2);
bErrMsgToStderr = 0;
@@ -2294,7 +2402,7 @@ doGlblProcessInit(void)
thrdInit();
- if( !(Debug || NoFork) )
+ if( !(Debug == DEBUG_FULL || NoFork) )
{
DBGPRINTF("Checking pidfile.\n");
if (!check_pid(PidFile))
@@ -2395,6 +2503,7 @@ int realMain(int argc, char **argv)
uchar *LocalHostName;
uchar *LocalDomain;
uchar *LocalFQDNName;
+ char cwdbuf[128]; /* buffer to obtain/display current working directory */
/* first, parse the command line options. We do not carry out any actual work, just
* see what we should do. This relieves us from certain anomalies and we can process
@@ -2481,8 +2590,9 @@ int realMain(int argc, char **argv)
if ((argc -= optind))
usage();
- DBGPRINTF("rsyslogd %s startup, compatibility mode %d, module path '%s'\n",
- VERSION, iCompatibilityMode, glblModPath == NULL ? "" : (char*)glblModPath);
+ DBGPRINTF("rsyslogd %s startup, compatibility mode %d, module path '%s', cwd:%s\n",
+ VERSION, iCompatibilityMode, glblModPath == NULL ? "" : (char*)glblModPath,
+ getcwd(cwdbuf, sizeof(cwdbuf)));
/* we are done with the initial option parsing and processing. Now we init the system. */