summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRainer Gerhards <rgerhards@adiscon.com>2008-04-16 16:58:15 +0200
committerRainer Gerhards <rgerhards@adiscon.com>2008-04-16 16:58:15 +0200
commitc5178a4d21cf8ca3362b8a8394d0e762801550a4 (patch)
tree0916303e0cd18e00397a6eb28a64b32aa5908c4d
parent65cdfc1777e1c189f28dfe11fa1ab0d08930b458 (diff)
parent11a526bcee95dab6a5bf2cc25a07dc6d65eaa177 (diff)
downloadrsyslog-c5178a4d21cf8ca3362b8a8394d0e762801550a4.tar.gz
rsyslog-c5178a4d21cf8ca3362b8a8394d0e762801550a4.tar.xz
rsyslog-c5178a4d21cf8ca3362b8a8394d0e762801550a4.zip
Merge branch 'master' into beta
3.17.x is the new beta Conflicts: ChangeLog configure.ac
-rw-r--r--ChangeLog53
-rw-r--r--Makefile.am6
-rw-r--r--action.c32
-rw-r--r--action.h4
-rw-r--r--conf.c4
-rw-r--r--configure.ac82
-rw-r--r--doc/Makefile.am3
-rw-r--r--doc/features.html10
-rw-r--r--doc/imgssapi.html6
-rw-r--r--doc/imklog.html69
-rw-r--r--doc/manual.html5
-rw-r--r--doc/ommail.html9
-rw-r--r--doc/property_replacer.html46
-rw-r--r--doc/queues.html12
-rw-r--r--doc/rsyslog_conf.html86
-rw-r--r--doc/rsyslog_ng_comparison.html24
-rw-r--r--doc/status.html18
-rw-r--r--expr.c2
-rw-r--r--glbl.h1
-rw-r--r--modules.c14
-rw-r--r--msg.c42
-rw-r--r--net.c47
-rw-r--r--net.h5
-rw-r--r--obj-types.h2
-rw-r--r--obj.c10
-rw-r--r--obj.h4
-rw-r--r--omfwd.c12
-rw-r--r--omusrmsg.c6
-rw-r--r--outchannel.c51
-rw-r--r--parse.c58
-rw-r--r--parse.h2
-rw-r--r--plugins/imfile/imfile.c5
-rw-r--r--plugins/imklog/Makefile.am12
-rw-r--r--plugins/imklog/bsd.c181
-rw-r--r--plugins/imklog/imklog.c680
-rw-r--r--plugins/imklog/imklog.h32
-rw-r--r--plugins/imklog/ksym.c54
-rw-r--r--plugins/imklog/ksym_mod.c12
-rw-r--r--plugins/imklog/linux.c544
-rw-r--r--plugins/imuxsock/imuxsock.c2
-rw-r--r--plugins/omgssapi/omgssapi.c17
-rw-r--r--plugins/ommail/Makefile.am6
-rw-r--r--plugins/ommail/ommail.c630
-rw-r--r--plugins/omrelp/omrelp.c12
-rw-r--r--queue.c111
-rw-r--r--queue.h15
-rw-r--r--rsyslog.conf2
-rw-r--r--rsyslog.conf.52
-rw-r--r--rsyslog.h5
-rw-r--r--rsyslogd.82
-rw-r--r--stringbuf.h1
-rw-r--r--syslogd.c347
-rw-r--r--syslogd.h3
-rw-r--r--tcpsrv.c28
-rw-r--r--template.c52
-rw-r--r--template.h2
-rw-r--r--wti.c8
-rw-r--r--wtp.c1
-rw-r--r--wtp.h2
59 files changed, 2520 insertions, 973 deletions
diff --git a/ChangeLog b/ChangeLog
index e552db4d..8735ed71 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,56 @@
+Version 3.17.2 (rgerhards), 2008-04-??
+- this version is the new beta
+---------------------------------------------------------------------------
+Version 3.17.1 (rgerhards), 2008-04-15
+- removed dependency on MAXHOSTNAMELEN as much as it made sense.
+ GNU/Hurd does not define it (because it has no limit), and we have taken
+ care for cases where it is undefined now. However, some very few places
+ remain where IMHO it currently is not worth fixing the code. If it is
+ not defined, we have used a generous value of 1K, which is above IETF
+ RFC's on hostname length at all. The memory consumption is no issue, as
+ there are only a handful of this buffers allocated *per run* -- that's
+ also the main reason why we consider it not worth to be fixed any further.
+- enhanced legacy syslog parser to handle slightly malformed messages
+ (with a space in front of the timestamp) - at least HP procurve is
+ known to do that and I won't outrule that others also do it. The
+ change looks quite unintrusive and so we added it to the parser.
+- implemented klogd functionality for BSD
+- implemented high precision timestamps for the kernel log. Thanks to
+ Michael Biebl for pointing out that the kernel log did not have them.
+- provided ability to discard non-kernel messages if they are present
+ in the kernel log (seems to happen on BSD)
+- implemented $KLogInternalMsgFacility config directive
+- implemented $KLogPermitNonKernelFacility config directive
+Plus a number of bugfixes that were applied to v3-stable and beta
+branches (not mentioned here in detail).
+---------------------------------------------------------------------------
+Version 3.17.0 (rgerhards), 2008-04-08
+- added native ability to send mail messages
+- removed no longer needed file relptuil.c/.h
+- added $ActionExecOnlyOnceEveryInterval config directive
+- bugfix: memory leaks in script engine
+- bugfix: zero-length strings were not supported in object
+ deserializer
+- properties are now case-insensitive everywhere (script, filters,
+ templates)
+- added the capability to specify a processing (actually dequeue)
+ timeframe with queues - so things can be configured to be done
+ at off-peak hours
+- We have removed the 32 character size limit (from RFC3164) on the
+ tag. This had bad effects on existing envrionments, as sysklogd didn't
+ obey it either (probably another bug in RFC3164...). We now receive
+ the full size, but will modify the outputs so that only 32 characters
+ max are used by default. If you need large tags in the output, you need
+ to provide custom templates.
+- changed command line processing. -v, -M, -c options are now parsed
+ and processed before all other options. Inter-option dependencies
+ have been relieved. Among others, permits to specify intial module
+ load path via -M only (not the environment) which makes it much
+ easier to work with non-standard module library locations. Thanks
+ to varmojfekoj for suggesting this change. Matches bugzilla bug 55.
+- bugfix: some messages were emited without hostname
+Plus a number of bugfixes that were applied to v3-stable and beta
+branches (not mentioned here in detail).
---------------------------------------------------------------------------
Version 3.16.0 (rgerhards), 2008-04-??
- new v3-stable (3.16.x) based on beta 3.15.x (RELP support)
diff --git a/Makefile.am b/Makefile.am
index 659acfb2..0e75710c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -183,7 +183,7 @@ SUBDIRS = . doc
SUBDIRS += plugins/immark plugins/imuxsock plugins/imtcp plugins/imudp plugins/omtesting
-if ENABLE_IMKLOGD
+if ENABLE_IMKLOG
SUBDIRS += plugins/imklog
endif
@@ -218,3 +218,7 @@ endif
if ENABLE_IMFILE
SUBDIRS += plugins/imfile
endif
+
+if ENABLE_MAIL
+SUBDIRS += plugins/ommail
+endif
diff --git a/action.c b/action.c
index 99ae8b32..39c37b5b 100644
--- a/action.c
+++ b/action.c
@@ -74,8 +74,10 @@ static int iActionQtoEnq = 2000; /* timeout for queue enque */
static int iActionQtoWrkShutdown = 60000; /* timeout for worker thread shutdown */
static int iActionQWrkMinMsgs = 100; /* minimum messages per worker needed to start a new one */
static int bActionQSaveOnShutdown = 1; /* save queue on shutdown (when DA enabled)? */
-static int iActionQueueDeqSlowdown = 0; /* dequeue slowdown (simple rate limiting) */
static int64 iActionQueMaxDiskSpace = 0; /* max disk space allocated 0 ==> unlimited */
+static int iActionQueueDeqSlowdown = 0; /* dequeue slowdown (simple rate limiting) */
+static int iActionQueueDeqtWinFromHr = 0; /* hour begin of time frame when queue is to be dequeued */
+static int iActionQueueDeqtWinToHr = 25; /* hour begin of time frame when queue is to be dequeued */
/* the counter below counts actions created. It is used to obtain unique IDs for the action. They
* should not be relied on for any long-term activity (e.g. disk queue names!), but they are nice
@@ -113,8 +115,10 @@ actionResetQueueParams(void)
iActionQtoWrkShutdown = 60000; /* timeout for worker thread shutdown */
iActionQWrkMinMsgs = 100; /* minimum messages per worker needed to start a new one */
bActionQSaveOnShutdown = 1; /* save queue on shutdown (when DA enabled)? */
- iActionQueueDeqSlowdown = 0;
iActionQueMaxDiskSpace = 0;
+ iActionQueueDeqSlowdown = 0;
+ iActionQueueDeqtWinFromHr = 0;
+ iActionQueueDeqtWinToHr = 25; /* 25 disables time windowed dequeuing */
glbliActionResumeRetryCount = 0; /* I guess it is smart to reset this one, too */
@@ -237,7 +241,9 @@ actionConstructFinalize(action_t *pThis)
setQPROP(queueSetiDiscardSeverity, "$ActionQueueDiscardSeverity", iActionQDiscardSeverity);
setQPROP(queueSetiMinMsgsPerWrkr, "$ActionQueueWorkerThreadMinimumMessages", iActionQWrkMinMsgs);
setQPROP(queueSetbSaveOnShutdown, "$ActionQueueSaveOnShutdown", bActionQSaveOnShutdown);
- setQPROP(queueSetiDeqSlowdown, "$ActionQueueDequeueSlowdown", iActionQueueDeqSlowdown);
+ setQPROP(queueSetiDeqSlowdown, "$ActionQueueDequeueSlowdown", iActionQueueDeqSlowdown);
+ setQPROP(queueSetiDeqtWinFromHr, "$ActionQueueDequeueTimeBegin", iActionQueueDeqtWinFromHr);
+ setQPROP(queueSetiDeqtWinToHr, "$ActionQueueDequeueTimeEnd", iActionQueueDeqtWinToHr);
# undef setQPROP
# undef setQPROPstr
@@ -498,6 +504,7 @@ actionWriteToAction(action_t *pAction)
{
msg_t *pMsgSave; /* to save current message pointer, necessary to restore
it in case it needs to be updated (e.g. repeated msgs) */
+ time_t now;
DEFiRet;
pMsgSave = NULL; /* indicate message poiner not saved */
@@ -536,7 +543,20 @@ actionWriteToAction(action_t *pAction)
dbgprintf("Called action, logging to %s", module.GetStateName(pAction->pMod));
- time(&pAction->f_time); /* we need this for message repeation processing */
+ time(&now); /* we need this for message repeation processing AND $ActionExecOnlyOnceEveryInterval */
+ /* now check if we need to drop the message because otherwise the action would be too
+ * frequently called. -- rgerhards, 2008-04-08
+ */
+ if(pAction->f_time != 0 && pAction->iSecsExecOnceInterval + pAction->tLastExec > now) {
+ /* in this case we need to discard the message - its not yet time to exec the action */
+ dbgprintf("action not yet ready again to be executed, onceInterval %d, tCurr %d, tNext %d\n",
+ (int) pAction->iSecsExecOnceInterval, (int) now,
+ (int) (pAction->iSecsExecOnceInterval + pAction->tLastExec));
+ FINALIZE;
+ }
+
+ pAction->tLastExec = now; /* we need this OnceInterval */
+ pAction->f_time = now; /* we need this for message repeation processing */
/* When we reach this point, we have a valid, non-disabled action.
* So let's enqueue our message for execution. -- rgerhards, 2007-07-24
@@ -680,6 +700,8 @@ actionAddCfSysLineHdrl(void)
CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuemaxfilesize", 0, eCmdHdlrSize, NULL, &iActionQueMaxFileSize, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuesaveonshutdown", 0, eCmdHdlrBinary, NULL, &bActionQSaveOnShutdown, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuedequeueslowdown", 0, eCmdHdlrInt, NULL, &iActionQueueDeqSlowdown, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuedequeuetimebegin", 0, eCmdHdlrInt, NULL, &iActionQueueDeqtWinFromHr, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuedequeuetimeend", 0, eCmdHdlrInt, NULL, &iActionQueueDeqtWinToHr, NULL));
finalize_it:
RETiRet;
@@ -710,6 +732,7 @@ addAction(action_t **ppAction, modInfo_t *pMod, void *pModData, omodStringReques
pAction->pMod = pMod;
pAction->pModData = pModData;
pAction->bExecWhenPrevSusp = bActExecWhenPrevSusp;
+ pAction->iSecsExecOnceInterval = iActExecOnceInterval;
/* check if we can obtain the template pointers - TODO: move to separate function? */
pAction->iNumTpls = OMSRgetEntryCount(pOMSR);
@@ -800,6 +823,5 @@ finalize_it:
RETiRet;
}
-
/* vi:set ai:
*/
diff --git a/action.h b/action.h
index 1fa05c15..99108aab 100644
--- a/action.h
+++ b/action.h
@@ -39,8 +39,10 @@ extern int glbliActionResumeRetryCount;
/* the following struct defines the action object data structure
*/
struct action_s {
- time_t f_time; /* time this was last written */
+ time_t f_time; /* used for "message repeated n times" - be careful, old, old code */
+ time_t tLastExec; /* time this action was last executed */
int bExecWhenPrevSusp;/* execute only when previous action is suspended? */
+ int iSecsExecOnceInterval; /* if non-zero, minimum seconds to wait until action is executed again */
short bEnabled; /* is the related action enabled (1) or disabled (0)? */
short bSuspended; /* is the related action temporarily suspended? */
time_t ttResumeRtry; /* when is it time to retry the resume? */
diff --git a/conf.c b/conf.c
index f87ab992..dac46970 100644
--- a/conf.c
+++ b/conf.c
@@ -816,7 +816,7 @@ static rsRetVal cflineProcessPropFilter(uchar **pline, register selector_t *f)
}
/* read property */
- iRet = parsDelimCStr(pPars, &f->f_filterData.prop.pCSPropName, ',', 1, 1);
+ iRet = parsDelimCStr(pPars, &f->f_filterData.prop.pCSPropName, ',', 1, 1, 1);
if(iRet != RS_RET_OK) {
errmsg.LogError(NO_ERRCODE, "error %d parsing filter property - ignoring selector", iRet);
rsParsDestruct(pPars);
@@ -824,7 +824,7 @@ static rsRetVal cflineProcessPropFilter(uchar **pline, register selector_t *f)
}
/* read operation */
- iRet = parsDelimCStr(pPars, &pCSCompOp, ',', 1, 1);
+ iRet = parsDelimCStr(pPars, &pCSCompOp, ',', 1, 1, 1);
if(iRet != RS_RET_OK) {
errmsg.LogError(NO_ERRCODE, "error %d compare operation property - ignoring selector", iRet);
rsParsDestruct(pPars);
diff --git a/configure.ac b/configure.ac
index a1595bd2..8a5f6222 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.61)
-AC_INIT([rsyslog],[3.16.0],[rsyslog@lists.adiscon.com])
+AC_INIT([rsyslog],[3.17.2],[rsyslog@lists.adiscon.com])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([syslogd.c])
AC_CONFIG_HEADERS([config.h])
@@ -21,9 +21,11 @@ AC_CANONICAL_HOST
case "${host}" in
*-*-linux*)
+ os_type="linux"
;;
*-*-*darwin*|*-*-freebsd*|*-*-netbsd*|*-*-openbsd*)
- AC_DEFINE([BSD], [1], [Description])
+ AC_DEFINE([OS_BSD], [1], [Indicator for a BSD OS])
+ os_type="bsd"
;;
esac
@@ -83,6 +85,22 @@ AC_FUNC_STRERROR_R
AC_FUNC_VPRINTF
AC_CHECK_FUNCS([flock basename alarm clock_gettime gethostbyname gethostname gettimeofday localtime_r memset mkdir regcomp select setid socket strcasecmp strchr strdup strerror strndup strnlen strrchr strstr strtol strtoul uname ttyname_r])
+# Check for MAXHOSTNAMELEN
+AC_MSG_CHECKING(for MAXHOSTNAMELEN)
+AC_TRY_COMPILE([
+ #include <sys/param.h>
+ ], [
+ return MAXHOSTNAMELEN;
+ ]
+ ,
+ AC_MSG_RESULT(yes)
+ ,
+ # note: we use 1024 here, which should be far more than needed by any system. If that's too low, we simply
+ # life with the need to change it. Most of the code doesn't need it anyways, but there are a few places
+ # where it actually is needed and it makes no sense to change them.
+ AC_DEFINE(MAXHOSTNAMELEN, 1024, [Define with a value if your <sys/param.h> does not define MAXHOSTNAMELEN])
+ AC_MSG_RESULT(no; defined as 64)
+)
# Large file support
AC_ARG_ENABLE(largefile,
@@ -202,7 +220,9 @@ AC_ARG_ENABLE(klog,
esac],
[enable_klog="yes"]
)
-AM_CONDITIONAL(ENABLE_IMKLOGD, test x$enable_klog = xyes)
+AM_CONDITIONAL(ENABLE_IMKLOG, test x$enable_klog = xyes)
+AM_CONDITIONAL(ENABLE_IMKLOG_BSD, test x$os_type = xbsd)
+AM_CONDITIONAL(ENABLE_IMKLOG_LINUX, test x$os_type = xlinux)
#
# SYSLOG_UNIXAF
@@ -413,6 +433,42 @@ AC_SUBST(libdbi_cflags)
AC_SUBST(libdbi_libs)
+# openssl support
+AC_ARG_ENABLE(openssl,
+ [AS_HELP_STRING([--enable-openssl],[Enable openssl support @<:@default=yes@:>@])],
+ [case "${enableval}" in
+ yes) enable_openssl="yes" ;;
+ no) enable_openssl="no" ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --enable-openssl) ;;
+ esac],
+ [enable_openssl=no]
+)
+if test "x$enable_openssl" = "xyes"; then
+ AC_CHECK_HEADERS(
+ [openssl/ssl.h],,
+ [AC_MSG_FAILURE([openssl is missing])]
+ )
+ AC_CHECK_LIB(
+ [crypto],
+ [CRYPTO_new_ex_data],
+ [openssl_cflags=""
+ openssl_libs="-lcrypto"
+ ],
+ [AC_MSG_FAILURE([library 'crypto' is missing (needed for openssl)])]
+ )
+ AC_CHECK_LIB(
+ [ssl],
+ [SSL_library_init],
+ [ openssl_libs+="-lssl"
+ ],
+ [AC_MSG_FAILURE([library 'ssl' is missing (needed for openssl)])]
+ )
+fi
+AM_CONDITIONAL(ENABLE_OPENSSL, test x$enable_openssl = xyes)
+AC_SUBST(openssl_cflags)
+AC_SUBST(openssl_libs)
+
+
# SNMP support
AC_ARG_ENABLE(snmp,
[AS_HELP_STRING([--enable-snmp],[Enable SNMP support @<:@default=no@:>@])],
@@ -455,6 +511,19 @@ AC_ARG_ENABLE(rsyslogd,
AM_CONDITIONAL(ENABLE_RSYSLOGD, test x$enable_rsyslogd = xyes)
+# Mail support (so far we do not need a library, but we need to turn this on and off)
+AC_ARG_ENABLE(mail,
+ [AS_HELP_STRING([--enable-mail],[Enable mail support @<:@default=no@:>@])],
+ [case "${enableval}" in
+ yes) enable_mail="yes" ;;
+ no) enable_mail="no" ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --enable-mail) ;;
+ esac],
+ [enable_mail=no]
+)
+AM_CONDITIONAL(ENABLE_MAIL, test x$enable_mail = xyes)
+
+
# RELP support
AC_ARG_ENABLE(relp,
[AS_HELP_STRING([--enable-relp],[Enable RELP support @<:@default=no@:>@])],
@@ -466,7 +535,7 @@ AC_ARG_ENABLE(relp,
[enable_relp=no]
)
if test "x$enable_relp" = "xyes"; then
- PKG_CHECK_MODULES(RELP, relp)
+ PKG_CHECK_MODULES(RELP, relp >= 0.1.1)
fi
AM_CONDITIONAL(ENABLE_RELP, test x$enable_relp = xyes)
AC_SUBST(RELP_CFLAGS)
@@ -562,6 +631,7 @@ AC_CONFIG_FILES([Makefile \
plugins/ompgsql/Makefile \
plugins/omrelp/Makefile \
plugins/omlibdbi/Makefile \
+ plugins/ommail/Makefile \
plugins/omsnmp/Makefile])
AC_OUTPUT
@@ -569,13 +639,14 @@ echo "****************************************************"
echo "rsyslog will be compiled with the following settings:"
echo
echo "Multithreading support enabled: $enable_pthreads"
-echo "Klog functionality enabled: $enable_klog"
+echo "Klog functionality enabled: $enable_klog ($os_type)"
echo "Regular expressions support enabled: $enable_regexp"
echo "Zlib compression support enabled: $enable_zlib"
echo "MySql support enabled: $enable_mysql"
echo "libdbi support enabled: $enable_libdbi"
echo "PostgreSQL support enabled: $enable_pgsql"
echo "SNMP support enabled: $enable_snmp"
+echo "Mail support enabled: $enable_mail"
echo "RELP support enabled: $enable_relp"
echo "file input module enabled: $enable_imfile"
echo "input template module will be compiled: $enable_imtemplate"
@@ -584,6 +655,7 @@ echo "Networking support enabled: $enable_inet"
echo "Enable GSSAPI Kerberos 5 support: $want_gssapi_krb5"
echo "Debug mode enabled: $enable_debug"
echo "Runtime Instrumentation enabled: $enable_rtinst"
+echo "openssl enabled: $enable_openssl"
echo "valgrind support settings enabled: $enable_valgrind"
echo "rsyslogd will be built: $enable_rsyslogd"
diff --git a/doc/Makefile.am b/doc/Makefile.am
index c1d41cf8..6eb82b81 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -31,6 +31,9 @@ html_files = \
imfile.html \
imtcp.html \
imgssapi.html \
+ imrelp.html \
+ imuxsock.html \
+ imklog.html \
professional_support.html \
queues.html \
queueWorkerLogic.dia \
diff --git a/doc/features.html b/doc/features.html
index 9573030e..13fc34c6 100644
--- a/doc/features.html
+++ b/doc/features.html
@@ -1,7 +1,5 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-<html><head><title>rsyslog features</title>
-
-</head>
+<html><head><title>rsyslog features</title></head>
<body>
<h1>RSyslog - Features</h1>
<p><b>This page lists both current features as well as
@@ -25,19 +23,19 @@ to MySQL databases</a></li>
<li> native support for writing to Postgres databases</li>
<li>direct support for Firebird/Interbase,
OpenTDS (MS SQL, Sybase), SQLLite, Ingres, Oracle, and mSQL via libdbi,
-a database abstraction layer (almost as good as native)</li>
+a database abstraction layer (almost as good as native)</li><li>native support for <a href="ommail.html">sending mail messages</a> (first seen in 3.17.0)</li>
<li>support for (plain) tcp based syslog - much better
reliability</li>
<li>support for sending and receiving compressed syslog messages</li>
<li>support for on-demand on-disk spooling of messages that can
not be processed fast enough (a great feature for <a href="rsyslog_high_database_rate.html">writing massive
-amounts of syslog messages to a database</a>)</li>
+amounts of syslog messages to a database</a>)</li><li>support for selectively <a href="http://wiki.rsyslog.com/index.php/OffPeakHours">processing messages only during specific timeframes</a> and spooling them to disk otherwise</li>
<li>ability to monitor text files and convert their contents
into syslog messages (one per line)</li>
<li>ability to configure backup syslog/database servers - if
the primary fails, control is switched to a prioritized list of backups</li>
<li>support for receiving messages via reliable <a href="http://www.monitorware.com/Common/en/glossary/rfc3195.php">
-RFC 3195</a> delivery</li>
+RFC 3195</a> delivery (a bit clumpsy to build right now...)</li>
<li>ability to generate file names and directories (log
targets) dynamically, based on many different properties</li>
<li>control of log output format, including ability to present
diff --git a/doc/imgssapi.html b/doc/imgssapi.html
index af15e59e..cf16eb01 100644
--- a/doc/imgssapi.html
+++ b/doc/imgssapi.html
@@ -10,7 +10,9 @@
<p><b>Description</b>:</p>
<p>Provides the ability to receive syslog messages from the
network protected via Kerberos 5 encryption and authentication. This
-module also accept plain tcp syslog messages on the same port if configured to do so. If you need just plain tcp, use&nbsp; <a href="imtcp.html">imtcp</a> instead.</p>
+module also accept plain tcp syslog messages on the same port if configured to do so. If you need just plain tcp, use <a href="imtcp.html">imtcp</a> instead.</p>
+<p>There is also an <a href="gssapi.html">overview of gssapi support in rsyslog</a> available. We recommend reading
+it before digging into the configuration parameters.</p>
<p><b>Configuration Directives</b>:</p>
<ul>
<li>InputGSSServerRun &lt;port&gt;<br>
@@ -47,4 +49,4 @@ Copyright © 2008 by <a href="http://www.gerhards.net/rainer">Rainer
Gerhards</a> and
<a href="http://www.adiscon.com/">Adiscon</a>.
Released under the GNU GPL version 3 or higher.</font></p>
-</body></html> \ No newline at end of file
+</body></html>
diff --git a/doc/imklog.html b/doc/imklog.html
new file mode 100644
index 00000000..92c1881a
--- /dev/null
+++ b/doc/imklog.html
@@ -0,0 +1,69 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head>
+<meta http-equiv="Content-Language" content="en"><title>Kernel Log Input Module (imklog)</title>
+
+</head>
+<body>
+<h1>Kernel Log Input Module</h1>
+<p><b>Module Name:&nbsp;&nbsp;&nbsp; imklog</b></p>
+<p><b>Author: </b>Rainer Gerhards
+&lt;rgerhards@adiscon.com&gt;</p>
+<p><b>Description</b>:</p>
+<p>Reads messages from the kernel log and submits them to the
+syslog engine.</p>
+<p><b>Configuration Directives</b>:</p>
+<ul>
+<li><strong>$KLogInternalMsgFacility
+&lt;facility&gt;</strong><br>
+The facility which messages internally generated by imklog will have.
+imklog generates some messages of itself (e.g. on problems, startup and
+shutdown) and these do not stem from the kernel. Historically, under
+Linux, these too have "kern" facility. Thus, on Linux platforms the
+default is "kern" while on others it is "syslogd". You usually do not
+need to specify this configuratin directive - it is included primarily
+for few limited cases where it is needed for good reason. Bottom line:
+if you don't have a good idea why you should use this setting, do not
+touch it.</li>
+<li><span style="font-weight: bold;">$KLogPermitNonKernelFacility
+[on/<span style="font-style: italic;">off</span>]<br>
+</span>At least under BSD the kernel log may contain entries
+with non-kernel facilities. This setting controls how those are
+handled. The default is "off", in which case these messages are
+ignored. Switch it to on to submit non-kernel messages to rsyslog
+processing.<span style="font-weight: bold;"></span></li>
+<li><span style="font-weight: bold;"></span>$DebugPrintKernelSymbols
+(imklog) [on/<b>off</b>]<br>
+Linux only, ignored on other platforms (but may be specified)</li>
+<li>$klogSymbolLookup (imklog) [<b>on</b>/off] --
+former klogd -x option<br>
+Linux only, ignored on other platforms (but may be specified)</li>
+<li>$klogUseSyscallInterface (imklog)&nbsp; [on/<b>off</b>]
+-- former klogd -2 option<br>
+Linux only, ignored on other platforms (but may be specified)</li>
+<li>$klogSymbolsTwice (imklog) [on/<b>off</b>] --
+former klogd -s option<br>
+Linux only, ignored on other platforms (but may be specified)<br style="font-weight: bold;">
+</li>
+</ul>
+<b>Caveats/Known Bugs:</b>
+<p>This is obviously platform specific and requires platform
+drivers.
+Currently, imklog functionality is available on Linux and BSD.</p>
+<p><b>Sample:</b></p>
+<p>The following sample pulls messages from the kernel log. All
+parameters are left by default, which is usually a good idea. Please
+note that loading the plugin is sufficient to activate it. No directive
+is needed to start pulling kernel messages.<br>
+</p>
+<textarea rows="15" cols="60">$ModLoad imklog
+</textarea>
+<p>[<a href="rsyslog_conf.html">rsyslog.conf overview</a>]
+[<a href="manual.html">manual index</a>] [<a href="http://www.rsyslog.com/">rsyslog site</a>]</p>
+<p><font size="2">This documentation is part of the
+<a href="http://www.rsyslog.com/">rsyslog</a>
+project.<br>
+Copyright © 2008 by <a href="http://www.gerhards.net/rainer">Rainer
+Gerhards</a> and
+<a href="http://www.adiscon.com/">Adiscon</a>.
+Released under the GNU GPL version 3 or higher.</font></p>
+</body></html> \ No newline at end of file
diff --git a/doc/manual.html b/doc/manual.html
index 9c906497..894a7876 100644
--- a/doc/manual.html
+++ b/doc/manual.html
@@ -16,7 +16,7 @@ relay chains while at the same time being very easy to setup for the
novice user. And as we know what enterprise users really need, there is
also <a href="professional_support.html">professional
rsyslog support</a> available directly from the source!</p>
-<p><b>This documentation is for version 3.15.1 (beta branch) of rsyslog.</b>
+<p><b>This documentation is for version 3.17.1 (devel branch) of rsyslog.</b>
Visit the <i> <a href="http://www.rsyslog.com/doc-status.html">rsyslog status page</a></i></b> to obtain current
version information and project status.
</p><p><b>If you like rsyslog, you might
@@ -63,7 +63,8 @@ php-syslog-ng with rsyslog</a></li>
<li><a href="rsyslog_recording_pri.html">recording
the syslog priority (severity and facility) to the log file</a></li>
<li><a href="http://www.rsyslog.com/Article19.phtml">preserving
-syslog sender over NAT</a> (online only)</li><li><a href="gssapi.html">an overview and howto of rsyslog gssapi support</a></li>
+syslog sender over NAT</a> (online only)</li>
+<li><a href="gssapi.html">an overview and howto of rsyslog gssapi support</a></li>
<li><a href="debug.html">debug support in rsyslog</a></li>
<li><a href="dev_queue.html">the rsyslog message queue object</a></li>
</ul>
diff --git a/doc/ommail.html b/doc/ommail.html
index b6b7c2ad..ba06a366 100644
--- a/doc/ommail.html
+++ b/doc/ommail.html
@@ -110,9 +110,8 @@ $ActionMailSubject mailSubject
$ActionExecOnlyOnceEveryInterval 21600
# the if ... then ... mailBody mus be on one line!
if $msg contains 'hard disk fatal failure' then :ommail:;mailBody
-</textarea><br>
-<br>
-A more advanced example plus a discussion on using the email feature
+</textarea>
+<p>A more advanced example plus a discussion on using the email feature
inside a reliable system can be found in Rainer's blogpost
"<a style="font-style: italic;" href="http://rgerhards.blogspot.com/2008/04/why-is-native-email-capability.html">Why
is native email capability an advantage for a syslogd?</a>"
@@ -121,8 +120,8 @@ is native email capability an advantage for a syslogd?</a>"
<p><font size="2">This documentation is part of the
<a href="http://www.rsyslog.com/">rsyslog</a>
project.<br>
-Copyright © 2008 by <a href="http://www.gerhards.net/rainer">Rainer
+Copyright &copy; 2008 by <a href="http://www.gerhards.net/rainer">Rainer
Gerhards</a> and
<a href="http://www.adiscon.com/">Adiscon</a>.
Released under the GNU GPL version 3 or higher.</font></p>
-</body></html> \ No newline at end of file
+</body></html>
diff --git a/doc/property_replacer.html b/doc/property_replacer.html
index 3484acf2..a2efaede 100644
--- a/doc/property_replacer.html
+++ b/doc/property_replacer.html
@@ -1,7 +1,5 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-<html><head><title>The Rsyslogd Property Replacer</title>
-
-</head>
+<html><head><title>The Rsyslogd Property Replacer</title></head>
<body>
<h1>The Property Replacer</h1>
<p><b>The property replacer is a core component in
@@ -17,7 +15,7 @@ modified by the property replacer. The full syntax is as follows:</p>
<blockquote><b><code>%propname:fromChar:toChar:options%</code></b></blockquote>
<h2>Available Properties</h2>
<p><b><code>propname</code></b> is the
-name of the property to access. It is case-sensitive.
+name of the property to access. It is case-insensitive (prior to 3.17.0, they were case-senstive).
Currently supported are:</p>
<table>
<tbody>
@@ -31,11 +29,11 @@ Currently supported are:</p>
socket. Should be useful for debugging.</td>
</tr>
<tr>
-<td><b>UxTradMsg</b></td>
+<td><b>uxtradmsg</b></td>
<td>will disappear soon - do NOT use!</td>
</tr>
<tr>
-<td><b>HOSTNAME</b></td>
+<td><b>hostname</b></td>
<td>hostname from the message</td>
</tr>
<tr>
@@ -43,7 +41,7 @@ socket. Should be useful for debugging.</td>
<td>alias for HOSTNAME</td>
</tr>
<tr>
-<td><b>FROMHOST</b></td>
+<td><b>fromhost</b></td>
<td>hostname of the system the message was received from
(in a relay chain, this is the system immediately in front of us and
not necessarily the original sender)</td>
@@ -59,16 +57,16 @@ BSD syslogd. For example, when TAG is "named[12345]", programname is
"named".</td>
</tr>
<tr>
-<td><b>PRI</b></td>
+<td><b>pri</b></td>
<td>PRI part of the message - undecoded (single value)</td>
</tr>
<tr>
-<td><b>PRI-text</b></td>
+<td><b>pri-text</b></td>
<td>the PRI part of the message in a textual form (e.g.
"syslog.info")</td>
</tr>
<tr>
-<td><b>IUT</b></td>
+<td><span style="font-weight: bold;">iut</span></td>
<td>the monitorware InfoUnitType - used when talking
to a <a href="http://www.monitorware.com">MonitorWare</a>
backend (also for <a href="http://www.phplogcon.org/">phpLogCon</a>)</td>
@@ -110,67 +108,67 @@ what was provided in the message (in most cases,
only seconds)</td>
</tr>
<tr>
-<td><b>TIMESTAMP</b></td>
+<td><b>timestamp</b></td>
<td>alias for timereported</td>
</tr>
<tr>
-<td><b>PROTOCOL-VERSION</b></td>
+<td><b>protocol-version</b></td>
<td>The contents of the PROTCOL-VERSION field from IETF
draft draft-ietf-syslog-protcol</td>
</tr>
<tr>
-<td><b>STRUCTURED-DATA</b></td>
+<td><b>structured-data</b></td>
<td>The contents of the STRUCTURED-DATA field from IETF
draft draft-ietf-syslog-protocol</td>
</tr>
<tr>
-<td><b>APP-NAME</b></td>
+<td><b>app-name</b></td>
<td>The contents of the APP-NAME field from IETF draft
draft-ietf-syslog-protocol</td>
</tr>
<tr>
-<td><b>PROCID</b></td>
+<td><b>procid</b></td>
<td>The contents of the PROCID field from IETF draft
draft-ietf-syslog-protocol</td>
</tr>
<tr>
-<td height="24"><b>MSGID</b></td>
+<td height="24"><b>msgid</b></td>
<td height="24">The contents of the MSGID field from
IETF draft draft-ietf-syslog-protocol</td>
</tr>
<tr>
-<td><b>$NOW</b></td>
+<td><b>$now</b></td>
<td>The current date stamp in the format YYYY-MM-DD</td>
</tr>
<tr>
-<td><b>$YEAR</b></td>
+<td><b>$year</b></td>
<td>The current year (4-digit)</td>
</tr>
<tr>
-<td><b>$MONTH</b></td>
+<td><b>$month</b></td>
<td>The current month (2-digit)</td>
</tr>
<tr>
-<td><b>$DAY</b></td>
+<td><b>$day</b></td>
<td>The current day of the month (2-digit)</td>
</tr>
<tr>
-<td><b>$HOUR</b></td>
+<td><b>$hour</b></td>
<td>The current hour in military (24 hour) time (2-digit)</td>
</tr>
<tr>
-<td><b>$HHOUR</b></td>
+<td><b>$hhour</b></td>
<td>The current half hour we are in. From minute 0 to 29,
this is always 0 while
from 30 to 59 it is always 1.</td>
</tr>
<tr>
-<td><b>$QHOUR</b></td>
+<td><b>$qhour</b></td>
<td>The current quarter hour we are in. Much like $HHOUR, but values
range from 0 to 3 (for the four quater hours that are in each hour)</td>
</tr>
<tr>
-<td><b>$MINUTE</b></td>
+<td><b>$minute</b></td>
<td>The current minute (2-digit)</td>
</tr>
</tbody>
diff --git a/doc/queues.html b/doc/queues.html
index 80641d8c..a2074d36 100644
--- a/doc/queues.html
+++ b/doc/queues.html
@@ -288,7 +288,17 @@ directive allows to specify how long (in microseconds) dequeueing should be
delayed. While simple, it still is powerful. For example, using a
DequeueSlowdown delay of 1,000 microseconds on a UDP send action ensures that no
more than 1,000 messages can be sent within a second (actually less, as there is
-also some time needed for the processing itself). </p>
+also some time needed for the processing itself).</p><h2>Processing Timeframes</h2><p>Queues
+can be set to dequeue (process) messages only during certain
+timeframes. This is useful if you, for example, would like to transfer
+the bulk of messages only during off-peak hours, e.g. when you have
+only limited bandwidth on the network path the the central server.</p><p>Currently,
+only a single timeframe is supported and, even worse, it can only be
+specified by the hour. It is not hard to extend rsyslog's capabilities
+in this regard - it was just not requested so far. So if you need more
+fine-grained control, let us know and we'll probably implement it.
+There are two configuration directives, both should be used together or
+results are unpredictable:" <i>$&lt;object&gt;QueueDequeueTimeBegin &lt;hour&gt;</i>" and&nbsp;"<i>$&lt;object&gt;QueueDequeueTimeEnd &lt;hour&gt;</i>". The hour parameter must be specified in 24-hour format (so 10pm is 22). A use case for this parameter can be found in the <a href="http://wiki.rsyslog.com/index.php/OffPeakHours">rsyslog wiki</a>. </p>
<h2>Terminating Queues</h2>
<p>Terminating a process sounds easy, but can be complex.
<span style="font-size: 12pt; line-height: 115%; font-family: 'Times New Roman',serif;" lang="EN-US">
diff --git a/doc/rsyslog_conf.html b/doc/rsyslog_conf.html
index 2a0f0c60..9325f73c 100644
--- a/doc/rsyslog_conf.html
+++ b/doc/rsyslog_conf.html
@@ -26,22 +26,30 @@ number of modules. Here is the entry point to their documentation and
what they do (list is currently not complete)</p>
<ul>
<li><a href="omsnmp.html">omsnmp</a> - SNMP
-trap output module</li><li><a href="omrelp.html">omrelp</a> - RELP output module</li>
+trap output module</li>
+<li><a href="omrelp.html">omrelp</a> - RELP
+output module</li>
<li>omgss - output module for GSS-enabled syslog</li>
<li>ommysql - output module for MySQL</li>
<li>ompgsql - output module for PostgreSQL</li>
<li><a href="omlibdbi.html">omlibdbi</a> -
generic database output module (Firebird/Interbase, MS SQL, Sybase,
SQLLite, Ingres, Oracle, mSQL)</li>
+<li><a href="ommail.html">ommail</a> -
+permits rsyslog to alert folks by mail if something important happens</li>
<li><a href="imfile.html">imfile</a>
--&nbsp; input module for text files</li><li><a href="imrelp.html">imrelp</a> - RELP input module</li>
+-&nbsp; input module for text files</li>
+<li><a href="imrelp.html">imrelp</a> - RELP
+input module</li>
<li>imudp - udp syslog message input</li>
<li><a href="imtcp.html">imtcp</a> - input
plugin for plain tcp syslog</li>
<li><a href="imgssapi.html">imgssapi</a> -
input plugin for plain tcp and GSS-enable syslog</li>
<li>immark - support for mark messages</li>
-<li>imklog - kernel logging</li><li><a href="imuxsock.html">imuxsock</a> - unix sockets, including the system log socket</li>
+<li><a href="imklog.html">imklog</a> - kernel logging</li>
+<li><a href="imuxsock.html">imuxsock</a> -
+unix sockets, including the system log socket</li>
</ul>
<p>Please note that each module provides configuration
directives, which are NOT necessarily being listed below. Also
@@ -64,7 +72,19 @@ unstable...). So you have been warned ;)</p>
many parameter settings modify queue parameters. If in doubt, use the
default, it is usually well-chosen and applicable in most cases.</p>
<ul>
-<li><a href="rsconf1_actionexeconlywhenpreviousissuspended.html">$ActionExecOnlyWhenPreviousIsSuspended</a></li><li>$ActionFileDefaultTemplate [templateName] - sets a new default template for file actions</li><li>$ActionFileEnableSync [on/<span style="font-weight: bold;">off</span>] - enables file syncing capability of omfile</li><li>$ActionForwardDefaultTemplate [templateName] - sets a new default template for UDP and plain TCP forwarding action</li><li>$ActionGSSForwardDefaultTemplate [templateName] - sets a new default template for GSS-API forwarding action</li>
+<li><a href="rsconf1_actionexeconlywhenpreviousissuspended.html">$ActionExecOnlyWhenPreviousIsSuspended</a></li>
+<li>$ActionExecOnlyOnceEveryInterval &lt;seconds&gt; -
+execute action only if the last execute is at last
+&lt;seconds&gt; seconds in the past (more info in <a href="ommail.html">ommail</a>,
+but may be used with any action)</li>
+<li>$ActionFileDefaultTemplate [templateName] - sets a new
+default template for file actions</li>
+<li>$ActionFileEnableSync [on/<span style="font-weight: bold;">off</span>] - enables file
+syncing capability of omfile</li>
+<li>$ActionForwardDefaultTemplate [templateName] - sets a new
+default template for UDP and plain TCP forwarding action</li>
+<li>$ActionGSSForwardDefaultTemplate [templateName] - sets a
+new default template for GSS-API forwarding action</li>
<li>$ActionQueueCheckpointInterval &lt;number&gt;</li>
<li>$ActionQueueDequeueSlowdown &lt;number&gt; [number
is timeout in <i> micro</i>seconds (1000000us is 1sec!),
@@ -98,12 +118,13 @@ default 60000 (1 minute)]</li>
worker threads, default 1, recommended 1</li>
<li>$ActionQueueWorkerThreadMinumumMessages
&lt;number&gt;, default 100</li>
-<li><a href="rsconf1_actionresumeinterval.html">$ActionResumeInterval</a></li><li>$ActionResumeRetryCount &lt;number&gt; [default 0,
+<li><a href="rsconf1_actionresumeinterval.html">$ActionResumeInterval</a></li>
+<li>$ActionResumeRetryCount &lt;number&gt; [default 0,
-1 means eternal]</li>
<li><a href="rsconf1_allowedsender.html">$AllowedSender</a></li>
<li><a href="rsconf1_controlcharacterescapeprefix.html">$ControlCharacterEscapePrefix</a></li>
<li><a href="rsconf1_debugprintcfsyslinehandlerlist.html">$DebugPrintCFSyslineHandlerList</a></li>
-<li>$DebugPrintKernelSymbols (imklog) [on/<b>off</b>]</li>
+
<li><a href="rsconf1_debugprintmodulelist.html">$DebugPrintModuleList</a></li>
<li><a href="rsconf1_debugprinttemplatelist.html">$DebugPrintTemplateList</a></li>
<li><a href="rsconf1_dircreatemode.html">$DirCreateMode</a></li>
@@ -120,14 +141,7 @@ worker threads, default 1, recommended 1</li>
<li><a href="rsconf1_gssforwardservicename.html">$GssForwardServiceName</a></li>
<li><a href="rsconf1_gsslistenservicename.html">$GssListenServiceName</a></li>
<li><a href="rsconf1_gssmode.html">$GssMode</a></li>
-<li><a href="rsconf1_includeconfig.html">$IncludeConfig</a></li>
-<li>$klogSymbolLookup (imklog) [<b>on</b>/off] --
-former klogd -x option</li>
-<li>$klogUseSyscallInterface (imklog)&nbsp; [on/<b>off</b>]
--- former klogd -2 option</li>
-<li>$klogSymbolsTwice (imklog) [on/<b>off</b>] --
-former klogd -s option</li>
-<li>$MainMsgQueueCheckpointInterval &lt;number&gt;</li>
+<li><a href="rsconf1_includeconfig.html">$IncludeConfig</a></li><li>MainMsgQueueCheckpointInterval &lt;number&gt;</li>
<li>$MainMsgQueueDequeueSlowdown &lt;number&gt; [number
is timeout in <i> micro</i>seconds (1000000us is 1sec!),
default 0 (no delay). Simple rate-limiting!]</li>
@@ -166,11 +180,11 @@ worker threads, default 1, recommended 1</li>
(immark)</li>
<li><a href="rsconf1_moddir.html">$ModDir</a></li>
<li><a href="rsconf1_modload.html">$ModLoad</a></li>
-
<li><a href="rsconf1_repeatedmsgreduction.html">$RepeatedMsgReduction</a></li>
<li><a href="rsconf1_resetconfigvariables.html">$ResetConfigVariables</a></li>
<li>$WorkDirectory &lt;name&gt; (directory for spool
-and other work files)</li><li>$UDPServerAddress &lt;IP&gt; (imudp) -- local IP
+and other work files)</li>
+<li>$UDPServerAddress &lt;IP&gt; (imudp) -- local IP
address (or name) the UDP listens should bind to</li>
<li>$UDPServerRun &lt;port&gt; (imudp) -- former
-r&lt;port&gt; option, default 514, start UDP server on this
@@ -302,18 +316,29 @@ template:</p>
DynFile,"/var/log/system-%HOSTNAME%.log"</code></blockquote>
<p>This template can then be used when defining an output
selector line. It will result in something like
-"/var/log/system-localhost.log"</p><p>Template
+"/var/log/system-localhost.log"</p>
+<p>Template
names beginning with "RSYSLOG_" are reserved for rsyslog use. Do NOT
use them if, otherwise you may receive a conflict in the future (and
quite unpredictable behaviour). There is a small set of pre-defined
-templates that you can use without the need to define it:</p><ul><li><span style="font-weight: bold;">RSYSLOG_TraditionalFileFormat</span> - the "old style" default log file format with low-precision timestamps</li><li><span style="font-weight: bold;">RSYSLOG_FileFormat</span> - a modern-style logfile format similar to TraditionalFileFormat, buth with high-precision timestamps and timezone information</li><li><span style="font-weight: bold;">RSYSLOG_TraditionalForwardFormat</span>
+templates that you can use without the need to define it:</p>
+<ul>
+<li><span style="font-weight: bold;">RSYSLOG_TraditionalFileFormat</span>
+- the "old style" default log file format with low-precision timestamps</li>
+<li><span style="font-weight: bold;">RSYSLOG_FileFormat</span>
+- a modern-style logfile format similar to TraditionalFileFormat, buth
+with high-precision timestamps and timezone information</li>
+<li><span style="font-weight: bold;">RSYSLOG_TraditionalForwardFormat</span>
- the traditional forwarding format with low-precision timestamps. Most
-useful if you send&nbsp;messages to other syslogd's or rsyslogd below
-version 3.12.5.</li><li><span style="font-weight: bold;">RSYSLOG_ForwardFormat</span>
+useful if you send&nbsp;messages to other syslogd's or rsyslogd
+below
+version 3.12.5.</li>
+<li><span style="font-weight: bold;">RSYSLOG_ForwardFormat</span>
- a new high-precision forwarding format very similar to the
traditional one, but with high-precision timestamps and timezone
information. Recommended to be used when sending messages to rsyslog
-3.12.5 or above.</li><li><span style="font-weight: bold;">RSYSLOG_SyslogProtocol23Format</span>
+3.12.5 or above.</li>
+<li><span style="font-weight: bold;">RSYSLOG_SyslogProtocol23Format</span>
- the format specified in IETF's internet-draft
ietf-syslog-protocol-23, which is assumed to be come the new syslog
standard RFC. This format includes several improvements. The rsyslog
@@ -321,7 +346,8 @@ message parser understands this format, so you can use it together with
all relatively recent versions of rsyslog. Other syslogd's may get
hopelessly confused if receiving that format, so check before you use
it. Note that the format is unlikely to change when the final RFC comes
-out, but this may happen.</li></ul>
+out, but this may happen.</li>
+</ul>
<h2>Output Channels</h2>
<p>Output Channels are a new concept first introduced in rsyslog
0.9.0. <b>As of this writing, it is most likely that they will
@@ -524,7 +550,8 @@ once they are implemented, it can make very much sense
</tr>
<tr>
<td>regex</td>
-<td>Compares the property against the provided POSIX regular
+<td>Compares the property against the provided POSIX
+regular
expression.</td>
</tr>
</tbody>
@@ -567,10 +594,12 @@ code), this can be done easily by:</p>
"ID-4711". Please note that the comparison is case-sensitive, so it
would not match if "id-4711" would be contained in the message.</p>
<p><code><b>:msg, regex, "fatal .* error"</b></code></p>
-<p>This filter uses a POSIX regular expression. It matches when the
+<p>This filter uses a POSIX regular expression. It matches when
+the
string contains the words "fatal" and "error" with anything in between
(e.g. "fatal net error" and "fatal lib error" but not "fatal error" as
-two spaces are required by the regular expression!).</p><p>Getting property-based filters right can sometimes be
+two spaces are required by the regular expression!).</p>
+<p>Getting property-based filters right can sometimes be
challenging. In order to help you do it with as minimal effort as
possible, rsyslogd spits out debug information for all property-based
filters during their evaluation. To enable this, run rsyslogd in
@@ -635,9 +664,12 @@ startswith 'DEVNAME' and <span style="font-weight: bold;">not</span>
($msg contains 'error1' or $msg contains
'error0') then /var/log/somelog<br>
</code>
-<br>If you would like to do case-insensitive comparisons, use
+<br>
+If you would like to do case-insensitive comparisons, use
"contains_i" instead of "contains" and "startswith_i" instead of
-"startswith".<br><br>Note that regular expressions are currently NOT
+"startswith".<br>
+<br>
+Note that regular expressions are currently NOT
supported in expression-based filters. These will be added later when
function support is added to the expression engine (the reason is that
regular expressions will be a separate loadable module, which requires
diff --git a/doc/rsyslog_ng_comparison.html b/doc/rsyslog_ng_comparison.html
index 2a1d15bd..28413337 100644
--- a/doc/rsyslog_ng_comparison.html
+++ b/doc/rsyslog_ng_comparison.html
@@ -1,12 +1,11 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-<html><head>
-<meta content="de" http-equiv="Content-Language"><title>rsyslog vs. syslog-ng - a comparison</title>
+<html><head><title>rsyslog vs. syslog-ng - a comparison</title>
</head>
<body>
<h1>rsyslog vs. syslog-ng</h1>
<p><small><i>Written by <a href="http://www.gerhards.net/rainer">Rainer Gerhards</a>
-(2008-02-28)</i></small></p>
+(2008-04-08)</i></small></p>
<p>We have often been asked about a comparison sheet between
rsyslog and syslog-ng. Unfortunately, I do not know much about
syslog-ng, I did not even use it once. Also, there seems to be no
@@ -122,7 +121,9 @@ based framing on syslog/tcp connections</td>
<td valign="top">yes</td>
</tr>
<tr>
-<td valign="top">syslog over RELP<br>this is a truely reliable solution (plain tcp syslog can lose messages!)</td>
+<td valign="top">syslog over RELP<br>
+truly reliable message delivery (<a href="http://rgerhards.blogspot.com/2008/04/on-unreliability-of-plain-tcp-syslog.html">Why
+is plain tcp syslog not reliable?</a>)</td>
<td valign="top">yes</td>
<td valign="top">no</td>
</tr>
@@ -337,6 +338,15 @@ be placed on different disk</td>
<td valign="top">no</td>
</tr>
<tr>
+<td valign="top">ability to process spooled
+messages only during a configured timeframe (e.g. process messages only
+during off-peak hours, during peak hours they are enqueued only)</td>
+<td valign="top"><a href="http://wiki.rsyslog.com/index.php/OffPeakHours">yes</a><br>
+(can independently be configured for the main queue and each action
+queue)</td>
+<td valign="top">no</td>
+</tr>
+<tr>
<td valign="top">ability to configure backup
syslog/database servers </td>
<td valign="top">yes</td>
@@ -416,6 +426,10 @@ including ability to present channel and priority as visible log data</td>
<td valign="top">yes</td>
<td valign="top">not sure...</td>
</tr>
+<tr><td valign="top">native ability to send mail messages</td>
+<td valign="top">yes (<a href="ommail.html">ommail</a>, introduced in 3.17.0)</td>
+<td valign="top">not sure...</td>
+</tr>
<tr>
<td valign="top">good timestamp format control; at a
minimum, ISO 8601/RFC 3339 second-resolution UTC zone</td>
@@ -564,6 +578,6 @@ feature sheet. I have not yet been able to fully work through it. In
the mean time, you may want to read it in parallel. It is available at
<a href="http://www.balabit.com/network-security/syslog-ng/features/detailed/">Balabit's
site</a>.</p>
-<p>This document is current as of 2008-02-28 and definitely
+<p>This document is current as of 2008-04-08 and definitely
incomplete (I did not yet manage to complete it!).</p>
</body></html> \ No newline at end of file
diff --git a/doc/status.html b/doc/status.html
index d7111a50..63a3f588 100644
--- a/doc/status.html
+++ b/doc/status.html
@@ -2,19 +2,23 @@
<html><head><title>rsyslog status page</title></head>
<body>
<h2>rsyslog status page</h2>
-<p>This page reflects the status as of 2008-04-04.</p>
+<p>This page reflects the status as of 2008-04-15.</p>
<h2>Current Releases</h2>
-<p><b>development:</b> 3.15.0 -
-<a href="http://www.rsyslog.com/Article203.phtml">change log</a> -
-<a href="http://www.rsyslog.com/Downloads-index-req-getit-lid-93.phtml">download</a></p>
+<p><b>development:</b> 3.17.1 -
+<a href="http://www.rsyslog.com/Article213.phtml">change log</a> -
+<a href="http://www.rsyslog.com/Downloads-req-viewdownloaddetails-lid-98.phtml">download</a>
-<p><b>v3 stable:</b> 3.14.0 - <a href="http://www.rsyslog.com/Article205.phtml">change log</a> -
-<a href="http://www.rsyslog.com/Downloads-index-req-getit-lid-94.phtml">download</a>
+<br><b>beta:</b> 3.15.1 -
+<a href="http://www.rsyslog.com/Article210.phtml">change log</a> -
+<a href="http://www.rsyslog.com/Downloads-req-viewdownloaddetails-lid-97.phtml">download</a></p>
+
+<p><b>v3 stable:</b> 3.14.2 - <a href="http://www.rsyslog.com/Article209.phtml">change log</a> -
+<a href="http://www.rsyslog.com/Downloads-req-viewdownloaddetails-lid-96.phtml">download</a>
<br><b>v2 stable:</b> 2.0.4 - <a href="http://www.rsyslog.com/Article197.phtml">change log</a> -
<a href="http://www.rsyslog.com/Downloads-index-req-getit-lid-90.phtml">download</a>
-<br>v0 and v1 are depricated and no longer supported. If you absolutely do not like to
+<br>v0 and v1 are deprecated and no longer supported. If you absolutely do not like to
upgrade, you may consider purchasing a
<a href="professional_support.html">commercial rsyslog support package</a>. Just let us point
out that it is really not a good idea to still run a v0 version.
diff --git a/expr.c b/expr.c
index 0f6e7460..9c357404 100644
--- a/expr.c
+++ b/expr.c
@@ -336,7 +336,7 @@ ENDobjConstruct(expr)
/* ConstructionFinalizer
* rgerhards, 2008-01-09
*/
-rsRetVal exprConstructFinalize(expr_t *pThis)
+rsRetVal exprConstructFinalize(expr_t __attribute__((unused)) *pThis)
{
DEFiRet;
diff --git a/glbl.h b/glbl.h
index fb55fb76..6d08ddd5 100644
--- a/glbl.h
+++ b/glbl.h
@@ -33,6 +33,7 @@
#define glblGetIOBufSize() 4096 /* size of the IO buffer, e.g. for strm class */
+extern uchar *glblModPath; /* module load path */
extern uchar *pszWorkDir;
#define glblGetWorkDir() (pszWorkDir == NULL ? (uchar*) "" : pszWorkDir)
diff --git a/modules.c b/modules.c
index 57df48b1..32a71c0c 100644
--- a/modules.c
+++ b/modules.c
@@ -39,6 +39,9 @@
#include <time.h>
#include <assert.h>
#include <errno.h>
+#ifdef OS_BSD
+# include "libgen.h"
+#endif
#include <dlfcn.h> /* TODO: replace this with the libtools equivalent! */
@@ -780,6 +783,17 @@ BEGINAbstractObjClassInit(module, 1, OBJ_IS_CORE_MODULE) /* class, version - CHA
SetModDir(pModPath);
}
+ /* now check if another module path was set via the command line (-M)
+ * if so, that overrides the environment. Please note that we must use
+ * a global setting here because the command line parser can NOT call
+ * into the module object, because it is not initialized at that point. So
+ * instead a global setting is changed and we pick it up as soon as we
+ * initialize -- rgerhards, 2008-04-04
+ */
+ if(glblModPath != NULL) {
+ SetModDir(glblModPath);
+ }
+
/* request objects we use */
CHKiRet(objUse(errmsg, CORE_COMPONENT));
ENDObjClassInit(module)
diff --git a/msg.c b/msg.c
index 7c020a61..9a12d572 100644
--- a/msg.c
+++ b/msg.c
@@ -1604,20 +1604,17 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
pRes = getMSG(pMsg);
} else if(!strcmp((char*) pName, "rawmsg")) {
pRes = getRawMsg(pMsg);
- } else if(!strcmp((char*) pName, "UxTradMsg")) {
+ } else if(!strcmp((char*) pName, "uxtradmsg")) {
pRes = getUxTradMsg(pMsg);
- } else if( !strcmp((char*) pName, "FROMHOST")
- || !strcmp((char*) pName, "fromhost")) {
+ } else if(!strcmp((char*) pName, "fromhost")) {
pRes = getRcvFrom(pMsg);
- } else if(!strcmp((char*) pName, "source")
- || !strcmp((char*) pName, "hostname")
- || !strcmp((char*) pName, "HOSTNAME")) {
+ } else if(!strcmp((char*) pName, "source") || !strcmp((char*) pName, "hostname")) {
pRes = getHOSTNAME(pMsg);
} else if(!strcmp((char*) pName, "syslogtag")) {
pRes = getTAG(pMsg);
- } else if(!strcmp((char*) pName, "PRI")) {
+ } else if(!strcmp((char*) pName, "pri")) {
pRes = getPRI(pMsg);
- } else if(!strcmp((char*) pName, "PRI-text")) {
+ } else if(!strcmp((char*) pName, "pri-text")) {
pBuf = malloc(20 * sizeof(char));
if(pBuf == NULL) {
*pbMustBeFreed = 0;
@@ -1639,57 +1636,57 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
} else if(!strcmp((char*) pName, "timegenerated")) {
pRes = getTimeGenerated(pMsg, pTpe->data.field.eDateFormat);
} else if(!strcmp((char*) pName, "timereported")
- || !strcmp((char*) pName, "TIMESTAMP")) {
+ || !strcmp((char*) pName, "timestamp")) {
pRes = getTimeReported(pMsg, pTpe->data.field.eDateFormat);
} else if(!strcmp((char*) pName, "programname")) {
pRes = getProgramName(pMsg);
- } else if(!strcmp((char*) pName, "PROTOCOL-VERSION")) {
+ } else if(!strcmp((char*) pName, "protocol-version")) {
pRes = getProtocolVersionString(pMsg);
- } else if(!strcmp((char*) pName, "STRUCTURED-DATA")) {
+ } else if(!strcmp((char*) pName, "structured-data")) {
pRes = getStructuredData(pMsg);
- } else if(!strcmp((char*) pName, "APP-NAME")) {
+ } else if(!strcmp((char*) pName, "app-name")) {
pRes = getAPPNAME(pMsg);
- } else if(!strcmp((char*) pName, "PROCID")) {
+ } else if(!strcmp((char*) pName, "procid")) {
pRes = getPROCID(pMsg);
- } else if(!strcmp((char*) pName, "MSGID")) {
+ } else if(!strcmp((char*) pName, "msgid")) {
pRes = getMSGID(pMsg);
/* here start system properties (those, that do not relate to the message itself */
- } else if(!strcmp((char*) pName, "$NOW")) {
+ } else if(!strcmp((char*) pName, "$now")) {
if((pRes = (char*) getNOW(NOW_NOW)) == NULL) {
return "***OUT OF MEMORY***";
} else
*pbMustBeFreed = 1; /* all of these functions allocate dyn. memory */
- } else if(!strcmp((char*) pName, "$YEAR")) {
+ } else if(!strcmp((char*) pName, "$year")) {
if((pRes = (char*) getNOW(NOW_YEAR)) == NULL) {
return "***OUT OF MEMORY***";
} else
*pbMustBeFreed = 1; /* all of these functions allocate dyn. memory */
- } else if(!strcmp((char*) pName, "$MONTH")) {
+ } else if(!strcmp((char*) pName, "$month")) {
if((pRes = (char*) getNOW(NOW_MONTH)) == NULL) {
return "***OUT OF MEMORY***";
} else
*pbMustBeFreed = 1; /* all of these functions allocate dyn. memory */
- } else if(!strcmp((char*) pName, "$DAY")) {
+ } else if(!strcmp((char*) pName, "$day")) {
if((pRes = (char*) getNOW(NOW_DAY)) == NULL) {
return "***OUT OF MEMORY***";
} else
*pbMustBeFreed = 1; /* all of these functions allocate dyn. memory */
- } else if(!strcmp((char*) pName, "$HOUR")) {
+ } else if(!strcmp((char*) pName, "$hour")) {
if((pRes = (char*) getNOW(NOW_HOUR)) == NULL) {
return "***OUT OF MEMORY***";
} else
*pbMustBeFreed = 1; /* all of these functions allocate dyn. memory */
- } else if(!strcmp((char*) pName, "$HHOUR")) {
+ } else if(!strcmp((char*) pName, "$hhour")) {
if((pRes = (char*) getNOW(NOW_HHOUR)) == NULL) {
return "***OUT OF MEMORY***";
} else
*pbMustBeFreed = 1; /* all of these functions allocate dyn. memory */
- } else if(!strcmp((char*) pName, "$QHOUR")) {
+ } else if(!strcmp((char*) pName, "$qhour")) {
if((pRes = (char*) getNOW(NOW_QHOUR)) == NULL) {
return "***OUT OF MEMORY***";
} else
*pbMustBeFreed = 1; /* all of these functions allocate dyn. memory */
- } else if(!strcmp((char*) pName, "$MINUTE")) {
+ } else if(!strcmp((char*) pName, "$minute")) {
if((pRes = (char*) getNOW(NOW_MINUTE)) == NULL) {
return "***OUT OF MEMORY***";
} else
@@ -1698,6 +1695,7 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
/* there is no point in continuing, we may even otherwise render the
* error message unreadable. rgerhards, 2007-07-10
*/
+ dbgprintf("invalid property name: '%s'\n", pName);
return "**INVALID PROPERTY NAME**";
}
diff --git a/net.c b/net.c
index ab669323..bbd6bec7 100644
--- a/net.c
+++ b/net.c
@@ -580,7 +580,7 @@ static int isAllowedSender(struct AllowedSenders *pAllowRoot, struct sockaddr *p
static int
should_use_so_bsdcompat(void)
{
-#ifndef BSD
+#ifndef OS_BSD
static int init_done;
static int so_bsdcompat_is_obsolete;
@@ -608,9 +608,9 @@ should_use_so_bsdcompat(void)
so_bsdcompat_is_obsolete = 1;
}
return !so_bsdcompat_is_obsolete;
-#else /* #ifndef BSD */
+#else /* #ifndef OS_BSD */
return 1;
-#endif /* #ifndef BSD */
+#endif /* #ifndef OS_BSD */
}
#ifndef SO_BSDCOMPAT
/* this shall prevent compiler errors due to undfined name */
@@ -852,6 +852,44 @@ finalize_it:
}
+/* get the name of the local host. A pointer to a character pointer is passed
+ * in, which on exit points to the local hostname. This buffer is dynamically
+ * allocated and must be free()ed by the caller. If the functions returns an
+ * error, the pointer is NULL. This function is based on GNU/Hurd's localhostname
+ * function.
+ * rgerhards, 20080-04-10
+ */
+static rsRetVal
+getLocalHostname(uchar **ppName)
+{
+ DEFiRet;
+ uchar *buf = NULL;
+ size_t buf_len = 0;
+
+ assert(ppName != NULL);
+
+ do {
+ if(buf == NULL) {
+ buf_len = 128; /* Initial guess */
+ CHKmalloc(buf = malloc(buf_len));
+ } else {
+ buf_len += buf_len;
+ CHKmalloc(buf = realloc (buf, buf_len));
+ }
+ } while((gethostname((char*)buf, buf_len) == 0 && !memchr (buf, '\0', buf_len)) || errno == ENAMETOOLONG);
+
+ *ppName = buf;
+ buf = NULL;
+
+finalize_it:
+ if(iRet != RS_RET_OK) {
+ if(buf != NULL)
+ free(buf);
+ }
+ RETiRet;
+}
+
+
/* closes the UDP listen sockets (if they exist) and frees
* all dynamically assigned memory.
*/
@@ -948,7 +986,7 @@ int *create_udp_socket(uchar *hostname, uchar *pszPort, int bIsServer)
/* We need to enable BSD compatibility. Otherwise an attacker
* could flood our log files by sending us tons of ICMP errors.
*/
-#if !defined(BSD) && !defined(__hpux)
+#if !defined(OS_BSD) && !defined(__hpux)
if (should_use_so_bsdcompat()) {
if (setsockopt(*s, SOL_SOCKET, SO_BSDCOMPAT,
(char *) &on, sizeof(on)) < 0) {
@@ -1047,6 +1085,7 @@ CODESTARTobjQueryInterface(net)
pIf->closeUDPListenSockets = closeUDPListenSockets;
pIf->isAllowedSender = isAllowedSender;
pIf->should_use_so_bsdcompat = should_use_so_bsdcompat;
+ pIf->getLocalHostname = getLocalHostname;
finalize_it:
ENDobjQueryInterface(net)
diff --git a/net.h b/net.h
index 2004dcfc..0f5b0bc1 100644
--- a/net.h
+++ b/net.h
@@ -34,7 +34,7 @@
#define ADDR_NAME 0x01 /* address is hostname wildcard) */
#define ADDR_PRI6 0x02 /* use IPv6 address prior to IPv4 when resolving */
-#ifdef BSD
+#ifdef OS_BSD
# ifndef _KERNEL
# define s6_addr32 __u6_addr.__u6_addr32
# endif
@@ -97,6 +97,7 @@ BEGINinterface(net) /* name must also be changed in ENDinterface macro! */
int *(*create_udp_socket)(uchar *hostname, uchar *LogPort, int bIsServer);
void (*closeUDPListenSockets)(int *finet);
int (*isAllowedSender)(struct AllowedSenders *pAllowRoot, struct sockaddr *pFrom, const char *pszFromHost);
+ rsRetVal (*getLocalHostname)(uchar**);
int (*should_use_so_bsdcompat)(void);
/* data memebers - these should go away over time... TODO */
int *pACLAddHostnameOnFail; /* add hostname to acl when DNS resolving has failed */
@@ -105,7 +106,7 @@ BEGINinterface(net) /* name must also be changed in ENDinterface macro! */
struct AllowedSenders *pAllowedSenders_TCP;
struct AllowedSenders *pAllowedSenders_GSS;
ENDinterface(net)
-#define netCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */
+#define netCURR_IF_VERSION 2 /* increment whenever you change the interface structure! */
/* prototypes */
PROTOTYPEObj(net);
diff --git a/obj-types.h b/obj-types.h
index afbe1a8b..4cd45153 100644
--- a/obj-types.h
+++ b/obj-types.h
@@ -210,7 +210,7 @@ rsRetVal objName##ClassExit(void) \
#define CODESTARTObjClassExit(objName)
#define ENDObjClassExit(objName) \
- iRet = obj.UnregisterObj((uchar*)#objName, pObjInfoOBJ); \
+ iRet = obj.UnregisterObj((uchar*)#objName); \
RETiRet; \
}
diff --git a/obj.c b/obj.c
index bb907d4f..7a4435ea 100644
--- a/obj.c
+++ b/obj.c
@@ -1074,7 +1074,7 @@ RegisterObj(uchar *pszObjName, objInfo_t *pInfo)
if(i >= OBJ_NUM_IDS) ABORT_FINALIZE(RS_RET_OBJ_REGISTRY_OUT_OF_SPACE);
arrObjInfo[i] = pInfo;
- dbgprintf("object '%s' successfully registered with index %d, qIF %p\n", pszObjName, i, pInfo->QueryIF);
+ /* DEV debug only: dbgprintf("object '%s' successfully registered with index %d, qIF %p\n", pszObjName, i, pInfo->QueryIF); */
finalize_it:
if(iRet != RS_RET_OK) {
@@ -1090,14 +1090,13 @@ finalize_it:
* rgerhards, 2008-03-10
*/
static rsRetVal
-UnregisterObj(uchar *pszObjName, objInfo_t *pInfo)
+UnregisterObj(uchar *pszObjName)
{
DEFiRet;
int bFound;
int i;
assert(pszObjName != NULL);
- assert(pInfo != NULL);
bFound = 0;
i = 0;
@@ -1114,7 +1113,7 @@ UnregisterObj(uchar *pszObjName, objInfo_t *pInfo)
ABORT_FINALIZE(RS_RET_OBJ_NOT_REGISTERED);
InfoDestruct(&arrObjInfo[i]);
- dbgprintf("object '%s' successfully unregistered with index %d\n", pszObjName, i);
+ /* DEV debug only: dbgprintf("object '%s' successfully unregistered with index %d\n", pszObjName, i); */
finalize_it:
if(iRet != RS_RET_OK) {
@@ -1138,7 +1137,7 @@ UseObj(char *srcFile, uchar *pObjName, uchar *pObjFile, interface_t *pIf)
objInfo_t *pObjInfo;
- dbgprintf("source file %s requests object '%s', ifIsLoaded %d\n", srcFile, pObjName, pIf->ifIsLoaded);
+ /* DEV debug only: dbgprintf("source file %s requests object '%s', ifIsLoaded %d\n", srcFile, pObjName, pIf->ifIsLoaded); */
if(pIf->ifIsLoaded == 1) {
ABORT_FINALIZE(RS_RET_OK); /* we are already set */
@@ -1171,7 +1170,6 @@ UseObj(char *srcFile, uchar *pObjName, uchar *pObjFile, interface_t *pIf)
}
/* if we reach this point, we have a valid pObjInfo */
- //if(pObjInfo->pModInfo != NULL) { /* NULL means core module */
if(pObjFile != NULL) { /* NULL means core module */
module.Use(srcFile, pObjInfo->pModInfo); /* increase refcount */
}
diff --git a/obj.h b/obj.h
index 87c6c91d..29ad2ae4 100644
--- a/obj.h
+++ b/obj.h
@@ -104,13 +104,13 @@ BEGINinterface(obj) /* name must also be changed in ENDinterface macro! */
rsRetVal (*SerializeProp)(strm_t *pStrm, uchar *pszPropName, propType_t propType, void *pUsr);
rsRetVal (*EndSerialize)(strm_t *pStrm);
rsRetVal (*RegisterObj)(uchar *pszObjName, objInfo_t *pInfo);
- rsRetVal (*UnregisterObj)(uchar *pszObjName, objInfo_t *pInfo);
+ rsRetVal (*UnregisterObj)(uchar *pszObjName);
rsRetVal (*Deserialize)(void *ppObj, uchar *pszTypeExpected, strm_t *pStrm, rsRetVal (*fFixup)(obj_t*,void*), void *pUsr);
rsRetVal (*DeserializePropBag)(obj_t *pObj, strm_t *pStrm);
rsRetVal (*SetName)(obj_t *pThis, uchar *pszName);
uchar * (*GetName)(obj_t *pThis);
ENDinterface(obj)
-#define objCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */
+#define objCURR_IF_VERSION 2 /* increment whenever you change the interface structure! */
/* prototypes */
diff --git a/omfwd.c b/omfwd.c
index 19d09379..67ef4b64 100644
--- a/omfwd.c
+++ b/omfwd.c
@@ -71,7 +71,7 @@ DEFobjCurrIf(net)
DEFobjCurrIf(tcpclt)
typedef struct _instanceData {
- char f_hname[MAXHOSTNAMELEN+1];
+ char *f_hname;
short sock; /* file descriptor */
int *pSockArray; /* sockets to use for UDP */
enum { /* TODO: we shoud revisit these definitions */
@@ -145,6 +145,9 @@ CODESTARTfreeInstance
tcpclt.Destruct(&pData->pTCPClt);
}
+ if(pData->f_hname != NULL)
+ free(pData->f_hname);
+
ENDfreeInstance
@@ -540,10 +543,11 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1)
/* TODO: make this if go away! */
if(*p == ';') {
*p = '\0'; /* trick to obtain hostname (later)! */
- strcpy(pData->f_hname, (char*) q);
+ CHKmalloc(pData->f_hname = strdup((char*) q));
*p = ';';
- } else
- strcpy(pData->f_hname, (char*) q);
+ } else {
+ CHKmalloc(pData->f_hname = strdup((char*) q));
+ }
/* process template */
CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS,
diff --git a/omusrmsg.c b/omusrmsg.c
index c4008140..42d3291d 100644
--- a/omusrmsg.c
+++ b/omusrmsg.c
@@ -119,7 +119,7 @@ static void endtty()
* BSD because they are not available there. We only emulate what we actually
* need! rgerhards 2005-03-18
*/
-#ifdef BSD
+#ifdef OS_BSD
static FILE *BSD_uf = NULL;
void setutent(void)
{
@@ -145,7 +145,7 @@ void endutent(void)
fclose(BSD_uf);
BSD_uf = NULL;
}
-#endif
+#endif /* #ifdef OS_BSD */
/*
@@ -209,7 +209,7 @@ static rsRetVal wallmsg(uchar* pMsg, instanceData *pData)
/* is this slot used? */
if (ut.ut_name[0] == '\0')
continue;
-#ifndef BSD
+#ifndef OS_BSD
if (ut.ut_type != USER_PROCESS)
continue;
#endif
diff --git a/outchannel.c b/outchannel.c
index 394371f0..d013ea08 100644
--- a/outchannel.c
+++ b/outchannel.c
@@ -91,12 +91,12 @@ static void skip_Comma(char **pp)
/* helper to ochAddLine. Parses a comma-delimited field
* The field is delimited by SP or comma. Leading whitespace
* is "eaten" and does not become part of the field content.
- * returns: 0 - ok, 1 - failure
*/
-static int get_Field(uchar **pp, uchar **pField)
+static rsRetVal get_Field(uchar **pp, uchar **pField)
{
+ DEFiRet;
register uchar *p;
- cstr_t *pStrB;
+ cstr_t *pStrB = NULL;
assert(pp != NULL);
assert(*pp != NULL);
@@ -105,21 +105,25 @@ static int get_Field(uchar **pp, uchar **pField)
skip_Comma((char**)pp);
p = *pp;
- if(rsCStrConstruct(&pStrB) != RS_RET_OK)
- return 1;
+ CHKiRet(rsCStrConstruct(&pStrB));
rsCStrSetAllocIncrement(pStrB, 32);
/* copy the field */
while(*p && *p != ' ' && *p != ',') {
- rsCStrAppendChar(pStrB, *p++);
+ CHKiRet(rsCStrAppendChar(pStrB, *p++));
}
*pp = p;
- rsCStrFinish(pStrB);
- if(rsCStrConvSzStrAndDestruct(pStrB, pField, 0) != RS_RET_OK)
- return 1;
+ CHKiRet(rsCStrFinish(pStrB));
+ CHKiRet(rsCStrConvSzStrAndDestruct(pStrB, pField, 0));
- return 0;
+finalize_it:
+ if(iRet != RS_RET_OK) {
+ if(pStrB != NULL)
+ rsCStrDestruct(&pStrB);
+ }
+
+ RETiRet;
}
@@ -156,12 +160,12 @@ static int get_off_t(uchar **pp, off_t *pOff_t)
* current position to the end of line and returns it
* to the caller. Leading white space is removed, but
* not trailing.
- * returns: 0 - ok, 1 - failure
*/
-static inline int get_restOfLine(uchar **pp, uchar **pBuf)
+static inline rsRetVal get_restOfLine(uchar **pp, uchar **pBuf)
{
+ DEFiRet;
register uchar *p;
- cstr_t *pStrB;
+ cstr_t *pStrB = NULL;
assert(pp != NULL);
assert(*pp != NULL);
@@ -170,21 +174,25 @@ static inline int get_restOfLine(uchar **pp, uchar **pBuf)
skip_Comma((char**)pp);
p = *pp;
- if(rsCStrConstruct(&pStrB) != RS_RET_OK)
- return 1;
+ CHKiRet(rsCStrConstruct(&pStrB));
rsCStrSetAllocIncrement(pStrB, 32);
/* copy the field */
while(*p) {
- rsCStrAppendChar(pStrB, *p++);
+ CHKiRet(rsCStrAppendChar(pStrB, *p++));
}
*pp = p;
- rsCStrFinish(pStrB);
- if(rsCStrConvSzStrAndDestruct(pStrB, pBuf, 0) != RS_RET_OK)
- return 1;
+ CHKiRet(rsCStrFinish(pStrB));
+ CHKiRet(rsCStrConvSzStrAndDestruct(pStrB, pBuf, 0));
- return 0;
+finalize_it:
+ if(iRet != RS_RET_OK) {
+ if(pStrB != NULL)
+ rsCStrDestruct(&pStrB);
+ }
+
+ RETiRet;
}
@@ -291,6 +299,5 @@ void ochPrintList(void)
pOch = pOch->pNext; /* done, go next */
}
}
-/*
- * vi:set ai:
+/* vi:set ai:
*/
diff --git a/parse.c b/parse.c
index bca6457d..171e5355 100644
--- a/parse.c
+++ b/parse.c
@@ -235,15 +235,16 @@ rsRetVal parsSkipWhitespace(rsParsObj *pThis)
* 0 means "no", 1 "yes"
* - bTrimLeading
* - bTrimTrailing
+ * - bConvLower - convert string to lower case?
*
* Output:
* ppCStr Pointer to the parsed string - must be freed by caller!
*/
-rsRetVal parsDelimCStr(rsParsObj *pThis, cstr_t **ppCStr, char cDelim, int bTrimLeading, int bTrimTrailing)
+rsRetVal parsDelimCStr(rsParsObj *pThis, cstr_t **ppCStr, char cDelim, int bTrimLeading, int bTrimTrailing, int bConvLower)
{
DEFiRet;
register unsigned char *pC;
- cstr_t *pCStr;
+ cstr_t *pCStr = NULL;
rsCHECKVALIDOBJECT(pThis, OIDrsPars);
@@ -254,12 +255,8 @@ rsRetVal parsDelimCStr(rsParsObj *pThis, cstr_t **ppCStr, char cDelim, int bTrim
pC = rsCStrGetBufBeg(pThis->pCStr) + pThis->iCurrPos;
- while(pThis->iCurrPos < rsCStrLen(pThis->pCStr)
- && *pC != cDelim) {
- if((iRet = rsCStrAppendChar(pCStr, *pC)) != RS_RET_OK) {
- rsCStrDestruct(&pCStr);
- FINALIZE;
- }
+ while(pThis->iCurrPos < rsCStrLen(pThis->pCStr) && *pC != cDelim) {
+ CHKiRet(rsCStrAppendChar(pCStr, bConvLower ? tolower(*pC) : *pC));
++pThis->iCurrPos;
++pC;
}
@@ -271,22 +268,21 @@ rsRetVal parsDelimCStr(rsParsObj *pThis, cstr_t **ppCStr, char cDelim, int bTrim
/* We got the string, now take it and see if we need to
* remove anything at its end.
*/
- if((iRet = rsCStrFinish(pCStr)) != RS_RET_OK) {
- rsCStrDestruct (&pCStr);
- FINALIZE;
- }
+ CHKiRet(rsCStrFinish(pCStr));
if(bTrimTrailing) {
- if((iRet = rsCStrTrimTrailingWhiteSpace(pCStr))
- != RS_RET_OK) {
- rsCStrDestruct (&pCStr);
- FINALIZE;
- }
+ CHKiRet(rsCStrTrimTrailingWhiteSpace(pCStr));
}
/* done! */
*ppCStr = pCStr;
+
finalize_it:
+ if(iRet != RS_RET_OK) {
+ if(pCStr != NULL)
+ rsCStrDestruct(&pCStr);
+ }
+
RETiRet;
}
@@ -308,13 +304,12 @@ finalize_it:
rsRetVal parsQuotedCStr(rsParsObj *pThis, cstr_t **ppCStr)
{
register unsigned char *pC;
- cstr_t *pCStr;
+ cstr_t *pCStr = NULL;
DEFiRet;
rsCHECKVALIDOBJECT(pThis, OIDrsPars);
- if((iRet = parsSkipAfterChar(pThis, '"')) != RS_RET_OK)
- FINALIZE;
+ CHKiRet(parsSkipAfterChar(pThis, '"'));
pC = rsCStrGetBufBeg(pThis->pCStr) + pThis->iCurrPos;
/* OK, we most probably can obtain a value... */
@@ -331,16 +326,10 @@ rsRetVal parsQuotedCStr(rsParsObj *pThis, cstr_t **ppCStr)
* to the output buffer (but do not rely on this,
* we might later introduce other things, like \007!
*/
- if((iRet = rsCStrAppendChar(pCStr, *pC)) != RS_RET_OK) {
- rsCStrDestruct(&pCStr);
- FINALIZE;
- }
+ CHKiRet(rsCStrAppendChar(pCStr, *pC));
}
} else { /* regular character */
- if((iRet = rsCStrAppendChar(pCStr, *pC)) != RS_RET_OK) {
- rsCStrDestruct (&pCStr);
- FINALIZE;
- }
+ CHKiRet(rsCStrAppendChar(pCStr, *pC));
}
++pThis->iCurrPos;
++pC;
@@ -350,19 +339,22 @@ rsRetVal parsQuotedCStr(rsParsObj *pThis, cstr_t **ppCStr)
++pThis->iCurrPos; /* 'eat' trailing quote */
} else {
/* error - improperly quoted string! */
- rsCStrDestruct (&pCStr);
+ rsCStrDestruct(&pCStr);
ABORT_FINALIZE(RS_RET_MISSING_TRAIL_QUOTE);
}
/* We got the string, let's finish it... */
- if((iRet = rsCStrFinish(pCStr)) != RS_RET_OK) {
- rsCStrDestruct (&pCStr);
- FINALIZE;
- }
+ CHKiRet(rsCStrFinish(pCStr));
/* done! */
*ppCStr = pCStr;
+
finalize_it:
+ if(iRet != RS_RET_OK) {
+ if(pCStr != NULL)
+ rsCStrDestruct(&pCStr);
+ }
+
RETiRet;
}
diff --git a/parse.h b/parse.h
index 483c109b..b7ac950d 100644
--- a/parse.h
+++ b/parse.h
@@ -91,7 +91,7 @@ rsRetVal parsSkipWhitespace(rsParsObj *pThis);
* Output:
* ppCStr Pointer to the parsed string
*/
-rsRetVal parsDelimCStr(rsParsObj *pThis, cstr_t **ppCStr, char cDelim, int bTrimLeading, int bTrimTrailing);
+rsRetVal parsDelimCStr(rsParsObj *pThis, cstr_t **ppCStr, char cDelim, int bTrimLeading, int bTrimTrailing, int bConvLower);
rsRetVal parsSkipAfterChar(rsParsObj *pThis, char c);
rsRetVal parsQuotedCStr(rsParsObj *pThis, cstr_t **ppCStr);
diff --git a/plugins/imfile/imfile.c b/plugins/imfile/imfile.c
index 162cab9f..75e54f04 100644
--- a/plugins/imfile/imfile.c
+++ b/plugins/imfile/imfile.c
@@ -95,7 +95,7 @@ static rsRetVal enqLine(fileInfo_t *pInfo, cstr_t *cstrLine)
MsgSetUxTradMsg(pMsg, (char*)rsCStrGetSzStr(cstrLine));
MsgSetRawMsg(pMsg, (char*)rsCStrGetSzStr(cstrLine));
MsgSetMSG(pMsg, (char*)rsCStrGetSzStr(cstrLine));
- MsgSetHOSTNAME(pMsg, LocalHostName);
+ MsgSetHOSTNAME(pMsg, (char*)LocalHostName);
MsgSetTAG(pMsg, (char*)pInfo->pszTag);
pMsg->iFacility = LOG_FAC(pInfo->iFacility);
pMsg->iSeverity = LOG_PRI(pInfo->iSeverity);
@@ -379,6 +379,9 @@ ENDafterRun
*/
BEGINmodExit
CODESTARTmodExit
+ /* release objects we used */
+ objRelease(datetime, CORE_COMPONENT);
+ objRelease(errmsg, CORE_COMPONENT);
ENDmodExit
diff --git a/plugins/imklog/Makefile.am b/plugins/imklog/Makefile.am
index 11e00962..246b3306 100644
--- a/plugins/imklog/Makefile.am
+++ b/plugins/imklog/Makefile.am
@@ -1,6 +1,16 @@
pkglib_LTLIBRARIES = imklog.la
-imklog_la_SOURCES = imklog.c imklog.h module.h ksym.c ksyms.h ksym_mod.c
+imklog_la_SOURCES = imklog.c imklog.h
+
+# select klog "driver"
+if ENABLE_IMKLOG_BSD
+imklog_la_SOURCES += bsd.c
+endif
+
+if ENABLE_IMKLOG_LINUX
+imklog_la_SOURCES += linux.c module.h ksym.c ksyms.h ksym_mod.c
+endif
+
imklog_la_CPPFLAGS = -I$(top_srcdir) $(pthreads_cflags)
imklog_la_LDFLAGS = -module -avoid-version
imklog_la_LIBADD =
diff --git a/plugins/imklog/bsd.c b/plugins/imklog/bsd.c
new file mode 100644
index 00000000..39b644c0
--- /dev/null
+++ b/plugins/imklog/bsd.c
@@ -0,0 +1,181 @@
+/* klog for BSD, based on the FreeBSD syslogd implementation.
+ *
+ * This contains OS-specific functionality to read the BSD
+ * kernel log. For a general overview, see head comment in
+ * imklog.c.
+ *
+ * Copyright (C) 2008 by Rainer Gerhards for the modifications of
+ * the original FreeBSD sources.
+ *
+ * I would like to express my gratitude to those folks which
+ * layed an important foundation for rsyslog to build on.
+ *
+ * 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.
+ *
+ * This file is based on earlier work included in the FreeBSD sources. We
+ * integrated it into the rsyslog project. The copyright below applies, and
+ * I also reproduce the original license under which we aquired the code:
+ *
+ * Copyright (c) 1983, 1988, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * If you would like to use the code under the BSD license, you should
+ * aquire your own copy of BSD's syslogd, from which we have taken it. The
+ * code in this file is modified and may only be used under the terms of
+ * the GPLv3+ as specified above.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+
+#include "rsyslog.h"
+#include "imklog.h"
+
+/* globals */
+static int fklog = -1; /* /dev/klog */
+
+#ifndef _PATH_KLOG
+# define _PATH_KLOG "/dev/klog"
+#endif
+
+/* open the kernel log - will be called inside the willRun() imklog
+ * entry point. -- rgerhards, 2008-04-09
+ */
+rsRetVal
+klogWillRun(void)
+{
+ DEFiRet;
+
+ fklog = open(_PATH_KLOG, O_RDONLY, 0);
+ if (fklog < 0) {
+ dbgprintf("can't open %s (%d)\n", _PATH_KLOG, errno);
+ iRet = RS_RET_ERR; // TODO: better error code
+ }
+
+ RETiRet;
+}
+
+
+/* Read /dev/klog while data are available, split into lines.
+ * Contrary to standard BSD syslogd, we do a blocking read. We can
+ * afford this as imklog is running on its own threads. So if we have
+ * a single file, it really doesn't matter if we wait inside a 1-file
+ * select or the read() directly.
+ */
+static void
+readklog(void)
+{
+ char *p, *q, line[MAXLINE + 1];
+ int len, i;
+
+ len = 0;
+ for (;;) {
+ dbgprintf("----------imklog waiting for kernel log line\n");
+ i = read(fklog, line + len, MAXLINE - 1 - len);
+ if (i > 0) {
+ line[i + len] = '\0';
+ } else {
+ if (i < 0 && errno != EINTR && errno != EAGAIN) {
+ imklogLogIntMsg(LOG_ERR,
+ "imklog error %d reading kernel log - shutting down imklog",
+ errno);
+ fklog = -1;
+ }
+ break;
+ }
+
+ for (p = line; (q = strchr(p, '\n')) != NULL; p = q + 1) {
+ *q = '\0';
+ Syslog(LOG_INFO, (uchar*) p);
+ }
+ len = strlen(p);
+ if (len >= MAXLINE - 1) {
+ Syslog(LOG_INFO, (uchar*)p);
+ len = 0;
+ }
+ if (len > 0)
+ memmove(line, p, len + 1);
+ }
+ if (len > 0)
+ Syslog(LOG_INFO, (uchar*)line);
+}
+
+
+/* to be called in the module's AfterRun entry point
+ * rgerhards, 2008-04-09
+ */
+rsRetVal klogAfterRun(void)
+{
+ DEFiRet;
+ if(fklog != -1)
+ close(fklog);
+ RETiRet;
+}
+
+
+
+/* to be called in the module's WillRun entry point, this is the main
+ * "message pull" mechanism.
+ * rgerhards, 2008-04-09
+ */
+rsRetVal klogLogKMsg(void)
+{
+ DEFiRet;
+ readklog();
+ RETiRet;
+}
+
+
+/* provide the (system-specific) default facility for internal messages
+ * rgerhards, 2008-04-14
+ */
+int
+klogFacilIntMsg(void)
+{
+ return LOG_SYSLOG;
+}
diff --git a/plugins/imklog/imklog.c b/plugins/imklog/imklog.c
index bfea8c6f..c6fb1592 100644
--- a/plugins/imklog/imklog.c
+++ b/plugins/imklog/imklog.c
@@ -1,14 +1,24 @@
-/* The kernel log input module for Linux. This file heavily
- * borrows from the klogd daemon provided by the sysklogd project.
- * Many thanks for this piece of software.
+/* The kernel log module.
+ *
+ * This is an abstracted module. As Linux and BSD kernel log is conceptually the
+ * same, we do not do different input plugins for them but use
+ * imklog in both cases, just with different "backend drivers" for
+ * the different platforms. This also enables a rsyslog.conf to
+ * be used on multiple platforms without the need to take care of
+ * what the kernel log is coming from.
+ *
+ * See platform-specific files (e.g. linux.c, bsd.c) in the plugin's
+ * working directory. For other systems with similar kernel logging
+ * functionality, no new input plugin shall be written but rather a
+ * driver be developed for imklog. Please note that imklog itself is
+ * mostly concerned with handling the interface. Any real action happens
+ * in the drivers, as things may be pretty different on different
+ * platforms.
*
* Please note that this file replaces the klogd daemon that was
* also present in pre-v3 versions of rsyslog.
*
- * I have begun to convert this to an input module on 2007-12-17.
- * IMPORTANT: more than a single instance is currently not supported. This
- * needs to be revisited once the config file and input module interface
- * supports multiple instances!
+ * Copyright (C) 2008 by Rainer Gerhards and Adiscon GmbH
*
* This file is part of rsyslog.
*
@@ -29,559 +39,157 @@
*/
#include "config.h"
#include "rsyslog.h"
-#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
-#include <signal.h>
#include <string.h>
-#include <pthread.h>
+#include <stdarg.h>
+#include <ctype.h>
+
#include "syslogd.h"
#include "cfsysline.h"
-#include "template.h"
+#include "obj.h"
#include "msg.h"
#include "module-template.h"
+#include "datetime.h"
#include "imklog.h"
MODULE_TYPE_INPUT
/* Module static data */
DEF_IMOD_STATIC_DATA
+DEFobjCurrIf(datetime)
/* configuration settings TODO: move to instance data? */
int dbgPrintSymbols = 0; /* this one is extern so the helpers can access it! */
-static int symbols_twice = 0;
-static int use_syscall = 0;
-static int symbol_lookup = 1;
+int symbols_twice = 0;
+int use_syscall = 0;
+int symbol_lookup = 1;
+int bPermitNonKernel = 0; /* permit logging of messages not having LOG_KERN facility */
+int iFacilIntMsg; /* the facility to use for internal messages (set by driver) */
/* 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
* I gained more handson experience with the input module interface (and the
* changes resulting from that). -- rgerhards, 2007-12-20
*/
-static char *symfile = NULL;
-static int console_log_level = -1;
-
-
-/* Includes. */
-#include <unistd.h>
-#include <errno.h>
-#include <sys/fcntl.h>
-#include <sys/stat.h>
-
-#if HAVE_TIME_H
-# include <time.h>
-#endif
-
-#include <stdarg.h>
-#include <paths.h>
-#include "ksyms.h"
-
-#define __LIBRARY__
-#include <unistd.h>
-
-
-#if !defined(__GLIBC__)
-# define __NR_ksyslog __NR_syslog
-_syscall3(int,ksyslog,int, type, char *, buf, int, len);
-#else
-#include <sys/klog.h>
-#define ksyslog klogctl
-#endif
-
-
-
-#ifndef _PATH_KLOG
-#define _PATH_KLOG "/proc/kmsg"
-#endif
-
-#define LOG_BUFFER_SIZE 4096
-#define LOG_LINE_LENGTH 1000
-
-static int kmsg;
-static char log_buffer[LOG_BUFFER_SIZE];
-
-static enum LOGSRC {none, proc, kernel} logsrc;
-
+char *symfile = NULL;
+int console_log_level = -1;
-/* Function prototypes. */
-extern int ksyslog(int type, char *buf, int len);
-
-
-/* Write a message to the message queue.
- * returns -1 if it fails, something else otherwise
+/* enqueue the the kernel message into the message queue.
+ * The provided msg string is not freed - thus must be done
+ * by the caller.
+ * rgerhards, 2008-04-12
*/
-static rsRetVal writeSyslogV(int iPRI, const char *szFmt, va_list va)
+static rsRetVal
+enqMsg(uchar *msg, uchar* pszTag, int iFacility, int iSeverity)
{
DEFiRet;
- int iChars;
- int iLen;
- time_t tNow;
- char msgBuf[2048]; /* we use the same size as sysklogd to remain compatible */
-
- assert(szFmt != NULL);
-
- /* build the message */
- time(&tNow);
- /* we can use sprintf safely below, because we know the size of the constants.
- * By doing so, we save some cpu cycles and code complexity (for unnecessary
- * error checking).
- */
- iLen = sprintf(msgBuf, "<%d>%.15s kernel: ", iPRI, ctime(&tNow) + 4);
-
- iChars = vsnprintf(msgBuf + iLen, sizeof(msgBuf) / sizeof(char) - iLen, szFmt, va);
-
- /* here we must create our message object and supply it to the message queue
- */
- CHKiRet(parseAndSubmitMessage(LocalHostName, msgBuf, strlen(msgBuf), MSG_DONT_PARSE_HOSTNAME, NOFLAG, eFLOWCTL_LIGHT_DELAY));
+ msg_t *pMsg;
+
+ assert(msg != NULL);
+ assert(pszTag != NULL);
+
+ CHKiRet(msgConstruct(&pMsg));
+ MsgSetFlowControlType(pMsg, eFLOWCTL_LIGHT_DELAY);
+ MsgSetUxTradMsg(pMsg, (char*)msg);
+ MsgSetRawMsg(pMsg, (char*)msg);
+ MsgSetMSG(pMsg, (char*)msg);
+ MsgSetHOSTNAME(pMsg, (char*)LocalHostName);
+ MsgSetTAG(pMsg, (char*)pszTag);
+ pMsg->iFacility = LOG_FAC(iFacility);
+ pMsg->iSeverity = LOG_PRI(iSeverity);
+ pMsg->bParseHOSTNAME = 0;
+ datetime.getCurrTime(&(pMsg->tTIMESTAMP)); /* use the current time! */
+ CHKiRet(submitMsg(pMsg));
finalize_it:
RETiRet;
}
-/* And now the same with variable arguments */
-static int writeSyslog(int iPRI, const char *szFmt, ...)
-{
- int iRet;
- va_list va;
-
- assert(szFmt != NULL);
- va_start(va, szFmt);
- iRet = writeSyslogV(iPRI, szFmt, va);
- va_end(va);
-
- return(iRet);
-}
-
-rsRetVal Syslog(int priority, char *fmt, ...) __attribute__((format(printf,2, 3)));
-rsRetVal Syslog(int priority, char *fmt, ...)
+/* parse the PRI from a kernel message. At least BSD seems to have
+ * non-kernel messages inside the kernel log...
+ * Expected format: "<pri>". piPri is only valid if the function
+ * successfully returns. If there was a proper pri ppSz is advanced to the
+ * position right after ">".
+ * rgerhards, 2008-04-14
+ */
+static rsRetVal
+parsePRI(uchar **ppSz, int *piPri)
{
DEFiRet;
- va_list ap;
- char *argl;
-
- /* Output using syslog. */
- if (!strcmp(fmt, "%s")) {
- va_start(ap, fmt);
- argl = va_arg(ap, char *);
- if (argl[0] == '<' && argl[1] && argl[2] == '>') {
- switch ( argl[1] )
- {
- case '0':
- priority = LOG_EMERG;
- break;
- case '1':
- priority = LOG_ALERT;
- break;
- case '2':
- priority = LOG_CRIT;
- break;
- case '3':
- priority = LOG_ERR;
- break;
- case '4':
- priority = LOG_WARNING;
- break;
- case '5':
- priority = LOG_NOTICE;
- break;
- case '6':
- priority = LOG_INFO;
- break;
- case '7':
- default:
- priority = LOG_DEBUG;
- }
- argl += 3;
- }
- iRet = writeSyslog(priority, fmt, argl);
- va_end(ap);
- } else {
- va_start(ap, fmt);
- iRet = writeSyslogV(priority, fmt, ap);
- va_end(ap);
- }
-
- RETiRet;
-}
-
-
-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)
- ksyslog(7, NULL, 0);
-
- /* Shutdown the log sources. */
- switch ( logsrc )
- {
- case kernel:
- ksyslog(0, 0, 0);
- Syslog(LOG_INFO, "Kernel logging (ksyslog) stopped.");
- break;
- case proc:
- close(kmsg);
- Syslog(LOG_INFO, "Kernel logging (proc) stopped.");
- break;
- case none:
- break;
- }
+ int i;
+ uchar *pSz;
- return;
-}
+ assert(ppSz != NULL);
+ pSz = *ppSz;
+ assert(pSz != NULL);
+ assert(piPri != NULL);
+ if(*pSz != '<' || !isdigit(*(pSz+1)))
+ ABORT_FINALIZE(RS_RET_INVALID_PRI);
-static enum LOGSRC GetKernelLogSrc(void)
-{
- auto struct stat sb;
-
- /* Set level of kernel console messaging.. */
- if ( (console_log_level != -1) &&
- (ksyslog(8, NULL, console_log_level) < 0) &&
- (errno == EINVAL) )
- {
- /*
- * An invalid arguement error probably indicates that
- * a pre-0.14 kernel is being run. At this point we
- * issue an error message and simply shut-off console
- * logging completely.
- */
- Syslog(LOG_WARNING, "Cannot set console log level - disabling "
- "console output.");
+ ++pSz;
+ i = 0;
+ while(isdigit(*pSz)) {
+ i = i * 10 + *pSz - '0';
}
- /*
- * First do a stat to determine whether or not the proc based
- * file system is available to get kernel messages from.
- */
- if ( use_syscall ||
- ((stat(_PATH_KLOG, &sb) < 0) && (errno == ENOENT)) )
- {
- /* Initialize kernel logging. */
- ksyslog(1, NULL, 0);
- Syslog(LOG_INFO, "imklogd %s, log source = ksyslog "
- "started.", VERSION);
- return(kernel);
- }
+ if(*pSz != '>')
+ ABORT_FINALIZE(RS_RET_INVALID_PRI);
- if ( (kmsg = open(_PATH_KLOG, O_RDONLY)) < 0 )
- {
- char sz[512];
- snprintf(sz, sizeof(sz), "imklog: Cannot open proc file system, %d - %s.\n", errno, strerror(errno));
- logmsgInternal(LOG_SYSLOG|LOG_ERR, sz, ADDDATE);
- ksyslog(7, NULL, 0); /* TODO: check this, implement more */
- return(none);
- }
+ /* OK, we have a valid PRI */
+ *piPri = i;
- Syslog(LOG_INFO, "imklog %s, log source = %s started.", \
- VERSION, _PATH_KLOG);
- return(proc);
+finalize_it:
+ RETiRet;
}
-/* Copy characters from ptr to line until a char in the delim
- * string is encountered or until min( space, len ) chars have
- * been copied.
- *
- * Returns the actual number of chars copied.
+/* log an imklog-internal message
+ * rgerhards, 2008-04-14
*/
-static int copyin( char *line, int space,
- const char *ptr, int len,
- const char *delim )
+rsRetVal imklogLogIntMsg(int priority, char *fmt, ...)
{
- auto int i;
- auto int count;
-
- count = len < space ? len : space;
+ DEFiRet;
+ va_list ap;
+ uchar msgBuf[2048]; /* we use the same size as sysklogd to remain compatible */
+ uchar *pLogMsg;
- for(i=0; i<count && !strchr(delim, *ptr); i++ ) {
- *line++ = *ptr++;
- }
+ va_start(ap, fmt);
+ vsnprintf((char*)msgBuf, sizeof(msgBuf) / sizeof(char), fmt, ap);
+ pLogMsg = msgBuf;
+ va_end(ap);
- return(i);
-}
+ iRet = enqMsg((uchar*)pLogMsg, (uchar*) ((iFacilIntMsg == LOG_KERN) ? "kernel:" : "imklog:"),
+ iFacilIntMsg, LOG_PRI(priority));
-/*
- * Messages are separated by "\n". Messages longer than
- * LOG_LINE_LENGTH are broken up.
- *
- * Kernel symbols show up in the input buffer as : "[<aaaaaa>]",
- * where "aaaaaa" is the address. These are replaced with
- * "[symbolname+offset/size]" in the output line - symbolname,
- * offset, and size come from the kernel symbol table.
- *
- * If a kernel symbol happens to fall at the end of a message close
- * in length to LOG_LINE_LENGTH, the symbol will not be expanded.
- * (This should never happen, since the kernel should never generate
- * messages that long.
- *
- * To preserve the original addresses, lines containing kernel symbols
- * are output twice. Once with the symbols converted and again with the
- * original text. Just in case somebody wants to run their own Oops
- * analysis on the syslog, e.g. ksymoops.
- */
-static void LogLine(char *ptr, int len)
-{
- enum parse_state_enum {
- PARSING_TEXT,
- PARSING_SYMSTART, /* at < */
- PARSING_SYMBOL,
- PARSING_SYMEND /* at ] */
- };
-
- static char line_buff[LOG_LINE_LENGTH];
-
- static char *line =line_buff;
- static enum parse_state_enum parse_state = PARSING_TEXT;
- static int space = sizeof(line_buff)-1;
-
- static char *sym_start; /* points at the '<' of a symbol */
-
- auto int delta = 0; /* number of chars copied */
- auto int symbols_expanded = 0; /* 1 if symbols were expanded */
- auto int skip_symbol_lookup = 0; /* skip symbol lookup on this pass */
- auto char *save_ptr = ptr; /* save start of input line */
- auto int save_len = len; /* save length at start of input line */
-
- while( len > 0 )
- {
- if( space == 0 ) /* line buffer is full */
- {
- /*
- ** Line too long. Start a new line.
- */
- *line = 0; /* force null terminator */
-
- dbgprintf("Line buffer full:\n");
- dbgprintf("\tLine: %s\n", line);
-
- Syslog( LOG_INFO, "%s", line_buff );
- line = line_buff;
- space = sizeof(line_buff)-1;
- parse_state = PARSING_TEXT;
- symbols_expanded = 0;
- skip_symbol_lookup = 0;
- save_ptr = ptr;
- save_len = len;
- }
-
- switch( parse_state )
- {
- case PARSING_TEXT:
- delta = copyin( line, space, ptr, len, "\n[" );
- line += delta;
- ptr += delta;
- space -= delta;
- len -= delta;
-
- if( space == 0 || len == 0 )
- {
- break; /* full line_buff or end of input buffer */
- }
-
- if( *ptr == '\0' ) /* zero byte */
- {
- ptr++; /* skip zero byte */
- space -= 1;
- len -= 1;
-
- break;
- }
-
- if( *ptr == '\n' ) /* newline */
- {
- ptr++; /* skip newline */
- space -= 1;
- len -= 1;
-
- *line = 0; /* force null terminator */
- Syslog( LOG_INFO, "%s", line_buff );
- line = line_buff;
- space = sizeof(line_buff)-1;
- if (symbols_twice) {
- if (symbols_expanded) {
- /* reprint this line without symbol lookup */
- symbols_expanded = 0;
- skip_symbol_lookup = 1;
- ptr = save_ptr;
- len = save_len;
- }
- else
- {
- skip_symbol_lookup = 0;
- save_ptr = ptr;
- save_len = len;
- }
- }
- break;
- }
- if( *ptr == '[' ) /* possible kernel symbol */
- {
- *line++ = *ptr++;
- space -= 1;
- len -= 1;
- if (!skip_symbol_lookup)
- parse_state = PARSING_SYMSTART; /* at < */
- break;
- }
- /* Now that line_buff is no longer fed to *printf as format
- * string, '%'s are no longer "dangerous".
- */
- break;
-
- case PARSING_SYMSTART:
- if( *ptr != '<' )
- {
- parse_state = PARSING_TEXT; /* not a symbol */
- break;
- }
-
- /*
- ** Save this character for now. If this turns out to
- ** be a valid symbol, this char will be replaced later.
- ** If not, we'll just leave it there.
- */
-
- sym_start = line; /* this will point at the '<' */
-
- *line++ = *ptr++;
- space -= 1;
- len -= 1;
- parse_state = PARSING_SYMBOL; /* symbol... */
- break;
-
- case PARSING_SYMBOL:
- delta = copyin( line, space, ptr, len, ">\n[" );
- line += delta;
- ptr += delta;
- space -= delta;
- len -= delta;
- if( space == 0 || len == 0 )
- {
- break; /* full line_buff or end of input buffer */
- }
- if( *ptr != '>' )
- {
- parse_state = PARSING_TEXT;
- break;
- }
-
- *line++ = *ptr++; /* copy the '>' */
- space -= 1;
- len -= 1;
-
- parse_state = PARSING_SYMEND;
-
- break;
-
- case PARSING_SYMEND:
- if( *ptr != ']' )
- {
- parse_state = PARSING_TEXT; /* not a symbol */
- break;
- }
-
- /*
- ** It's really a symbol! Replace address with the
- ** symbol text.
- */
- {
- auto int sym_space;
-
- unsigned long value;
- auto struct symbol sym;
- auto char *symbol;
-
- *(line-1) = 0; /* null terminate the address string */
- value = strtoul(sym_start+1, (char **) 0, 16);
- *(line-1) = '>'; /* put back delim */
-
- if ( !symbol_lookup || (symbol = LookupSymbol(value, &sym)) == (char *)0 )
- {
- parse_state = PARSING_TEXT;
- break;
- }
-
- /*
- ** verify there is room in the line buffer
- */
- sym_space = space + ( line - sym_start );
- if( (unsigned) sym_space < strlen(symbol) + 30 ) /*(30 should be overkill)*/
- {
- parse_state = PARSING_TEXT; /* not enough space */
- break;
- }
-
- delta = sprintf( sym_start, "%s+%d/%d]",
- symbol, sym.offset, sym.size );
-
- space = sym_space + delta;
- line = sym_start + delta;
- symbols_expanded = 1;
- }
- ptr++;
- len--;
- parse_state = PARSING_TEXT;
- break;
-
- default: /* Can't get here! */
- parse_state = PARSING_TEXT;
-
- }
- }
-
- return;
+ RETiRet;
}
-static void LogKernelLine(void)
+/* log a kernel message
+ * rgerhards, 2008-04-14
+ */
+rsRetVal Syslog(int priority, uchar *pMsg)
{
- auto int rdcnt;
+ DEFiRet;
+ rsRetVal localRet;
- /*
- * Zero-fill the log buffer. This should cure a multitude of
- * problems with klogd logging the tail end of the message buffer
- * which will contain old messages. Then read the kernel log
- * messages into this fresh buffer.
- */
- memset(log_buffer, '\0', sizeof(log_buffer));
- if ( (rdcnt = ksyslog(2, log_buffer, sizeof(log_buffer)-1)) < 0 )
- {
- char sz[512];
- if(errno == EINTR)
- return;
- snprintf(sz, sizeof(sz), "imklog: Error return from sys_sycall: %d - %s\n", errno, strerror(errno));
- logmsgInternal(LOG_SYSLOG|LOG_ERR, sz, ADDDATE);
- }
- else
- LogLine(log_buffer, rdcnt);
- return;
-}
+ /* Output using syslog */
+ localRet = parsePRI(&pMsg, &priority);
+ if(localRet != RS_RET_INVALID_PRI && localRet != RS_RET_OK)
+ FINALIZE;
+ /* if we don't get the pri, we use whatever we were supplied */
+ /* ignore non-kernel messages if not permitted */
+ if(bPermitNonKernel == 0 && LOG_FAC(priority) != LOG_KERN)
+ FINALIZE; /* silently ignore */
-static void LogProcLine(void)
-{
- auto int rdcnt;
+ iRet = enqMsg((uchar*)pMsg, (uchar*) "kernel:", LOG_FAC(priority), LOG_PRI(priority));
- /*
- * Zero-fill the log buffer. This should cure a multitude of
- * problems with klogd logging the tail end of the message buffer
- * which will contain old messages. Then read the kernel messages
- * from the message pseudo-file into this fresh buffer.
- */
- memset(log_buffer, '\0', sizeof(log_buffer));
- if ( (rdcnt = read(kmsg, log_buffer, sizeof(log_buffer)-1)) < 0 )
- {
- if ( errno == EINTR )
- return;
- Syslog(LOG_ERR, "Cannot read proc file system: %d - %s.", errno, strerror(errno));
- }
- else
- LogLine(log_buffer, rdcnt);
-
- return;
+finalize_it:
+ RETiRet;
}
@@ -592,64 +200,32 @@ CODESTARTrunInput
* right into the sleep below.
*/
while(!pThrd->bShallStop) {
- /* we do not need to handle the RS_RET_TERMINATE_NOW case any
- * special because we just need to terminate. This may be different
- * if a cleanup is needed. But for now, we can just use CHKiRet().
- * rgerhards, 2007-12-17
+ /* klogLogKMsg() waits for the next kernel message, obtains it
+ * and then submits it to the rsyslog main queue.
+ * rgerhards, 2008-04-09
*/
- switch ( logsrc )
- {
- case kernel:
- LogKernelLine();
- break;
- case proc:
- LogProcLine();
- break;
- case none:
- /* TODO: We need to handle this case here somewhat more intelligent
- * This is now at least partly done - code should never reach this point
- * as willRun() already checked for the "none" status -- rgerhards, 2007-12-17
- */
- pause();
- break;
- }
+ CHKiRet(klogLogKMsg());
}
- RETiRet;
+finalize_it:
ENDrunInput
BEGINwillRun
- /* Initialize this module. If that fails, we tell the engine we don't like to run */
- /* Determine where kernel logging information is to come from. */
- logsrc = GetKernelLogSrc();
- if(logsrc == none) {
- iRet = RS_RET_NO_KERNEL_LOGSRC;
- } else {
- if (symbol_lookup) {
- symbol_lookup = (InitKsyms(symfile) == 1);
- symbol_lookup |= InitMsyms();
- if (symbol_lookup == 0) {
- Syslog(LOG_WARNING, "cannot find any symbols, turning off symbol lookups\n");
- }
- }
- }
CODESTARTwillRun
+ iRet = klogWillRun();
ENDwillRun
BEGINafterRun
CODESTARTafterRun
- /* cleanup here */
- if(logsrc != none)
- CloseLogSrc();
-
- DeinitKsyms();
- DeinitMsyms();
+ iRet = klogAfterRun();
ENDafterRun
BEGINmodExit
CODESTARTmodExit
+ /* release objects we used */
+ objRelease(datetime, CORE_COMPONENT);
ENDmodExit
@@ -665,6 +241,8 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a
use_syscall = 0;
symfile = NULL;
symbol_lookup = 1;
+ bPermitNonKernel = 0;
+ iFacilIntMsg = klogFacilIntMsg();
return RS_RET_OK;
}
@@ -672,17 +250,17 @@ BEGINmodInit()
CODESTARTmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
CODEmodInit_QueryRegCFSLineHdlr
+ CHKiRet(objUse(datetime, CORE_COMPONENT));
+
+ iFacilIntMsg = klogFacilIntMsg();
+
CHKiRet(omsdRegCFSLineHdlr((uchar *)"debugprintkernelsymbols", 0, eCmdHdlrBinary, NULL, &dbgPrintSymbols, 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 *)"kloginternalmsgfacility", 0, eCmdHdlrFacility, NULL, &iFacilIntMsg, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
ENDmodInit
-/*
- * Local variables:
- * c-indent-level: 8
- * c-basic-offset: 8
- * tab-width: 8
- * End:
- * vi:set ai:
+/* vim:set ai:
*/
diff --git a/plugins/imklog/imklog.h b/plugins/imklog/imklog.h
index 71525a79..a37ecc9e 100644
--- a/plugins/imklog/imklog.h
+++ b/plugins/imklog/imklog.h
@@ -2,8 +2,10 @@
* These are the definitions for the klog message generation module.
*
* File begun on 2007-12-17 by RGerhards
+ * Major change: 2008-04-09: switched to a driver interface for
+ * several platforms
*
- * Copyright 2007 Rainer Gerhards and Adiscon GmbH.
+ * Copyright 2007-2008 Rainer Gerhards and Adiscon GmbH.
*
* This file is part of rsyslog.
*
@@ -28,9 +30,33 @@
#include "rsyslog.h"
#include "syslogd.h"
-/* global variables */
+/* interface to "drivers"
+ * the platform specific drivers must implement these entry points. Only one
+ * driver may be active at any given time, thus we simply rely on the linker
+ * to resolve the addresses.
+ * rgerhards, 2008-04-09
+ */
+rsRetVal klogLogKMsg(void);
+rsRetVal klogWillRun(void);
+rsRetVal klogAfterRun(void);
+int klogFacilIntMsg(void);
+
+/* the following data members may be accessed by the "drivers"
+ * I admit this is not the cleanest way to doing things, but I honestly
+ * believe it is appropriate for the job that needs to be done.
+ * rgerhards, 2008-04-09
+ */
+extern int symbols_twice;
+extern int use_syscall;
+extern int symbol_lookup;
+extern char *symfile;
+extern int console_log_level;
extern int dbgPrintSymbols;
+/* the functions below may be called by the drivers */
+rsRetVal imklogLogIntMsg(int priority, char *fmt, ...) __attribute__((format(printf,2, 3)));
+rsRetVal Syslog(int priority, uchar *msg);
+
/* prototypes */
extern int InitKsyms(char *);
extern void DeinitKsyms(void);
@@ -38,8 +64,6 @@ extern int InitMsyms(void);
extern void DeinitMsyms(void);
extern char * ExpandKadds(char *, char *);
extern void SetParanoiaLevel(int);
-extern void vsyslog(int pri, const char *fmt, va_list ap);
-rsRetVal Syslog(int priority, char *fmt, ...) __attribute__((format(printf,2, 3)));
#endif /* #ifndef IMKLOG_H_INCLUDED */
/* vi:set ai:
diff --git a/plugins/imklog/ksym.c b/plugins/imklog/ksym.c
index b7d5903e..1c2af124 100644
--- a/plugins/imklog/ksym.c
+++ b/plugins/imklog/ksym.c
@@ -185,18 +185,18 @@ extern int InitKsyms(char *mapfile)
if ( mapfile != (char *) 0 ) {
if ( (sym_file = fopen(mapfile, "r")) == (FILE *) 0 )
{
- Syslog(LOG_WARNING, "Cannot open map file: %s.", mapfile);
+ imklogLogIntMsg(LOG_WARNING, "Cannot open map file: %s.", mapfile);
return(0);
}
} else {
if ( (mapfile = FindSymbolFile()) == (char *) 0 ) {
- Syslog(LOG_WARNING, "Cannot find map file.");
+ imklogLogIntMsg(LOG_WARNING, "Cannot find map file.");
dbgprintf("Cannot find map file.\n");
return(0);
}
if ( (sym_file = fopen(mapfile, "r")) == (FILE *) 0 ) {
- Syslog(LOG_WARNING, "Cannot open map file.");
+ imklogLogIntMsg(LOG_WARNING, "Cannot open map file.");
dbgprintf("Cannot open map file.\n");
return(0);
}
@@ -213,7 +213,7 @@ extern int InitKsyms(char *mapfile)
*/
while ( !feof(sym_file) ) {
if ( fscanf(sym_file, "%lx %c %s\n", &address, &type, sym) != 3 ) {
- Syslog(LOG_ERR, "Error in symbol table input (#1).");
+ imklogLogIntMsg(LOG_ERR, "Error in symbol table input (#1).");
fclose(sym_file);
return(0);
}
@@ -221,7 +221,7 @@ extern int InitKsyms(char *mapfile)
dbgprintf("Address: %lx, Type: %c, Symbol: %s\n", address, type, sym);
if ( AddSymbol(address, sym) == 0 ) {
- Syslog(LOG_ERR, "Error adding symbol - %s.", sym);
+ imklogLogIntMsg(LOG_ERR, "Error adding symbol - %s.", sym);
fclose(sym_file);
return(0);
}
@@ -231,19 +231,19 @@ extern int InitKsyms(char *mapfile)
}
- Syslog(LOG_INFO, "Loaded %d symbols from %s.", num_syms, mapfile);
+ imklogLogIntMsg(LOG_INFO, "Loaded %d symbols from %s.", num_syms, mapfile);
switch(version) {
case -1:
- Syslog(LOG_WARNING, "Symbols do not match kernel version.");
+ imklogLogIntMsg(LOG_WARNING, "Symbols do not match kernel version.");
num_syms = 0;
break;
case 0:
- Syslog(LOG_WARNING, "Cannot verify that symbols match kernel version.");
+ imklogLogIntMsg(LOG_WARNING, "Cannot verify that symbols match kernel version.");
break;
case 1:
- Syslog(LOG_INFO, "Symbols match kernel version %s.", vstring);
+ imklogLogIntMsg(LOG_INFO, "Symbols match kernel version %s.", vstring);
break;
}
@@ -296,12 +296,12 @@ static char *FindSymbolFile(void)
**mf = system_maps;
auto struct utsname utsname;
- static char symfile[100];
+ static char mysymfile[100];
auto FILE *sym_file = (FILE *) 0;
if ( uname(&utsname) < 0 ) {
- Syslog(LOG_ERR, "Cannot get kernel version information.");
+ imklogLogIntMsg(LOG_ERR, "Cannot get kernel version information.");
return(0);
}
@@ -309,19 +309,19 @@ static char *FindSymbolFile(void)
for(mf = system_maps; *mf != (char *) 0 && file == (char *) 0; ++mf) {
- snprintf(symfile, sizeof(symfile), "%s-%s", *mf, utsname.release);
- dbgprintf("Trying %s.\n", symfile);
- if ( (sym_file = fopen(symfile, "r")) != (FILE *) 0 ) {
- if (CheckMapVersion(symfile) == 1)
- file = symfile;
+ snprintf(mysymfile, sizeof(mysymfile), "%s-%s", *mf, utsname.release);
+ dbgprintf("Trying %s.\n", mysymfile);
+ if ( (sym_file = fopen(mysymfile, "r")) != (FILE *) 0 ) {
+ if (CheckMapVersion(mysymfile) == 1)
+ file = mysymfile;
fclose(sym_file);
}
if (sym_file == (FILE *) 0 || file == (char *) 0) {
- sprintf (symfile, "%s", *mf);
- dbgprintf("Trying %s.\n", symfile);
- if ( (sym_file = fopen(symfile, "r")) != (FILE *) 0 ) {
- if (CheckMapVersion(symfile) == 1)
- file = symfile;
+ sprintf (mysymfile, "%s", *mf);
+ dbgprintf("Trying %s.\n", mysymfile);
+ if ( (sym_file = fopen(mysymfile, "r")) != (FILE *) 0 ) {
+ if (CheckMapVersion(mysymfile) == 1)
+ file = mysymfile;
fclose(sym_file);
}
}
@@ -410,13 +410,13 @@ static int CheckVersion(char *version)
* version level.
*/
if ( uname(&utsname) < 0 ) {
- Syslog(LOG_ERR, "Cannot get kernel version information.");
+ imklogLogIntMsg(LOG_ERR, "Cannot get kernel version information.");
return(0);
}
dbgprintf("Comparing kernel %s with symbol table %s.\n", utsname.release, vstring);
if ( sscanf (utsname.release, "%d.%d.%d", &major, &minor, &patch) < 3 ) {
- Syslog(LOG_ERR, "Kernel send bogus release string `%s'.", utsname.release);
+ imklogLogIntMsg(LOG_ERR, "Kernel send bogus release string `%s'.", utsname.release);
return(0);
}
@@ -470,12 +470,12 @@ static int CheckMapVersion(char *fname)
* now need to search this file and look for version
* information.
*/
- Syslog(LOG_INFO, "Inspecting %s", fname);
+ imklogLogIntMsg(LOG_INFO, "Inspecting %s", fname);
version = 0;
while ( !feof(sym_file) && (version == 0) ) {
if ( fscanf(sym_file, "%lx %c %s\n", &address, &type, sym) != 3 ) {
- Syslog(LOG_ERR, "Error in symbol table input (#2).");
+ imklogLogIntMsg(LOG_ERR, "Error in symbol table input (#2).");
fclose(sym_file);
return(0);
}
@@ -487,7 +487,7 @@ static int CheckMapVersion(char *fname)
switch ( version ) {
case -1:
- Syslog(LOG_ERR, "Symbol table has incorrect version number.\n");
+ imklogLogIntMsg(LOG_ERR, "Symbol table has incorrect version number.\n");
break;
case 0:
dbgprintf("No version information found.\n");
@@ -684,7 +684,7 @@ extern char *ExpandKadds(char *line, char *el)
*/
if ( i_am_paranoid &&
(strstr(line, "Oops:") != (char *) 0) && !InitMsyms() )
- Syslog(LOG_WARNING, "Cannot load kernel module symbols.\n");
+ imklogLogIntMsg(LOG_WARNING, "Cannot load kernel module symbols.\n");
/*
diff --git a/plugins/imklog/ksym_mod.c b/plugins/imklog/ksym_mod.c
index 11535a5f..bef810b4 100644
--- a/plugins/imklog/ksym_mod.c
+++ b/plugins/imklog/ksym_mod.c
@@ -158,10 +158,10 @@ extern int InitMsyms(void)
if ( ksyms == NULL ) {
if ( errno == ENOENT )
- Syslog(LOG_INFO, "No module symbols loaded - "
+ imklogLogIntMsg(LOG_INFO, "No module symbols loaded - "
"kernel modules not enabled.\n");
else
- Syslog(LOG_ERR, "Error loading kernel symbols " \
+ imklogLogIntMsg(LOG_ERR, "Error loading kernel symbols " \
"- %s\n", strerror(errno));
fclose(ksyms);
return(0);
@@ -201,9 +201,9 @@ extern int InitMsyms(void)
}
if ( rtn == 0 )
- Syslog(LOG_INFO, "No module symbols loaded.");
+ imklogLogIntMsg(LOG_INFO, "No module symbols loaded.");
else
- Syslog(LOG_INFO, "Loaded %d %s from %d module%s", rtn, \
+ imklogLogIntMsg(LOG_INFO, "Loaded %d %s from %d module%s", rtn, \
(rtn == 1) ? "symbol" : "symbols", \
num_modules, (num_modules == 1) ? "." : "s.");
@@ -296,7 +296,7 @@ struct Module *AddModule(module)
if ( sym_array_modules == NULL )
{
- Syslog(LOG_WARNING, "Cannot allocate Module array.\n");
+ imklogLogIntMsg(LOG_WARNING, "Cannot allocate Module array.\n");
return NULL;
}
mp = sym_array_modules;
@@ -308,7 +308,7 @@ struct Module *AddModule(module)
if ( mp == NULL )
{
- Syslog(LOG_WARNING, "Cannot allocate Module array.\n");
+ imklogLogIntMsg(LOG_WARNING, "Cannot allocate Module array.\n");
return NULL;
}
diff --git a/plugins/imklog/linux.c b/plugins/imklog/linux.c
new file mode 100644
index 00000000..a742a456
--- /dev/null
+++ b/plugins/imklog/linux.c
@@ -0,0 +1,544 @@
+/* klog for linux, based on the FreeBSD syslogd implementation.
+ *
+ * This contains OS-specific functionality to read the BSD
+ * kernel log. For a general overview, see head comment in
+ * imklog.c.
+ *
+ * This file heavily borrows from the klogd daemon provided by
+ * the sysklogd project. Many thanks for this piece of software.
+ *
+ * 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 <stdio.h>
+#include <assert.h>
+#include <signal.h>
+#include <string.h>
+#include <pthread.h>
+#include "syslogd.h"
+#include "cfsysline.h"
+#include "template.h"
+#include "msg.h"
+#include "module-template.h"
+#include "imklog.h"
+
+
+/* Includes. */
+#include <unistd.h>
+#include <errno.h>
+#include <sys/fcntl.h>
+#include <sys/stat.h>
+
+#if HAVE_TIME_H
+# include <time.h>
+#endif
+
+#include <stdarg.h>
+#include <paths.h>
+#include "ksyms.h"
+
+#define __LIBRARY__
+#include <unistd.h>
+
+
+#if !defined(__GLIBC__)
+# define __NR_ksyslog __NR_syslog
+_syscall3(int,ksyslog,int, type, char *, buf, int, len);
+#else
+#include <sys/klog.h>
+#define ksyslog klogctl
+#endif
+
+
+
+#ifndef _PATH_KLOG
+#define _PATH_KLOG "/proc/kmsg"
+#endif
+
+#define LOG_BUFFER_SIZE 4096
+#define LOG_LINE_LENGTH 1000
+
+static int kmsg;
+static char log_buffer[LOG_BUFFER_SIZE];
+
+static enum LOGSRC {none, proc, kernel} logsrc;
+
+
+/* Function prototypes. */
+extern int ksyslog(int type, char *buf, int len);
+
+
+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)
+ ksyslog(7, NULL, 0);
+
+ /* Shutdown the log sources. */
+ switch ( logsrc )
+ {
+ case kernel:
+ ksyslog(0, 0, 0);
+ imklogLogIntMsg(LOG_INFO, "Kernel logging (ksyslog) stopped.");
+ break;
+ case proc:
+ close(kmsg);
+ imklogLogIntMsg(LOG_INFO, "Kernel logging (proc) stopped.");
+ break;
+ case none:
+ break;
+ }
+
+ return;
+}
+
+
+static enum LOGSRC GetKernelLogSrc(void)
+{
+ auto struct stat sb;
+
+ /* Set level of kernel console messaging.. */
+ if ( (console_log_level != -1) &&
+ (ksyslog(8, NULL, console_log_level) < 0) &&
+ (errno == EINVAL) )
+ {
+ /*
+ * An invalid arguement error probably indicates that
+ * a pre-0.14 kernel is being run. At this point we
+ * issue an error message and simply shut-off console
+ * logging completely.
+ */
+ imklogLogIntMsg(LOG_WARNING, "Cannot set console log level - disabling "
+ "console output.");
+ }
+
+ /*
+ * First do a stat to determine whether or not the proc based
+ * file system is available to get kernel messages from.
+ */
+ if ( use_syscall ||
+ ((stat(_PATH_KLOG, &sb) < 0) && (errno == ENOENT)) )
+ {
+ /* Initialize kernel logging. */
+ ksyslog(1, NULL, 0);
+ imklogLogIntMsg(LOG_INFO, "imklogd %s, log source = ksyslog "
+ "started.", VERSION);
+ return(kernel);
+ }
+
+ if ( (kmsg = open(_PATH_KLOG, O_RDONLY)) < 0 )
+ {
+ char sz[512];
+ snprintf(sz, sizeof(sz), "imklog: Cannot open proc file system, %d - %s.\n", errno, strerror(errno));
+ logmsgInternal(LOG_SYSLOG|LOG_ERR, sz, ADDDATE);
+ ksyslog(7, NULL, 0); /* TODO: check this, implement more */
+ return(none);
+ }
+
+ imklogLogIntMsg(LOG_INFO, "imklog %s, log source = %s started.", VERSION, _PATH_KLOG);
+ return(proc);
+}
+
+
+/* Copy characters from ptr to line until a char in the delim
+ * string is encountered or until min( space, len ) chars have
+ * been copied.
+ *
+ * Returns the actual number of chars copied.
+ */
+static int copyin( uchar *line, int space,
+ const char *ptr, int len,
+ const char *delim )
+{
+ auto int i;
+ auto int count;
+
+ count = len < space ? len : space;
+
+ for(i=0; i<count && !strchr(delim, *ptr); i++ ) {
+ *line++ = *ptr++;
+ }
+
+ return(i);
+}
+
+/*
+ * Messages are separated by "\n". Messages longer than
+ * LOG_LINE_LENGTH are broken up.
+ *
+ * Kernel symbols show up in the input buffer as : "[<aaaaaa>]",
+ * where "aaaaaa" is the address. These are replaced with
+ * "[symbolname+offset/size]" in the output line - symbolname,
+ * offset, and size come from the kernel symbol table.
+ *
+ * If a kernel symbol happens to fall at the end of a message close
+ * in length to LOG_LINE_LENGTH, the symbol will not be expanded.
+ * (This should never happen, since the kernel should never generate
+ * messages that long.
+ *
+ * To preserve the original addresses, lines containing kernel symbols
+ * are output twice. Once with the symbols converted and again with the
+ * original text. Just in case somebody wants to run their own Oops
+ * analysis on the syslog, e.g. ksymoops.
+ */
+static void LogLine(char *ptr, int len)
+{
+ enum parse_state_enum {
+ PARSING_TEXT,
+ PARSING_SYMSTART, /* at < */
+ PARSING_SYMBOL,
+ PARSING_SYMEND /* at ] */
+ };
+
+ static uchar line_buff[LOG_LINE_LENGTH];
+
+ static uchar *line =line_buff;
+ static enum parse_state_enum parse_state = PARSING_TEXT;
+ static int space = sizeof(line_buff)-1;
+
+ static uchar *sym_start; /* points at the '<' of a symbol */
+
+ auto int delta = 0; /* number of chars copied */
+ auto int symbols_expanded = 0; /* 1 if symbols were expanded */
+ auto int skip_symbol_lookup = 0; /* skip symbol lookup on this pass */
+ auto char *save_ptr = ptr; /* save start of input line */
+ auto int save_len = len; /* save length at start of input line */
+
+ while( len > 0 )
+ {
+ if( space == 0 ) /* line buffer is full */
+ {
+ /*
+ ** Line too long. Start a new line.
+ */
+ *line = 0; /* force null terminator */
+
+ dbgprintf("Line buffer full:\n");
+ dbgprintf("\tLine: %s\n", line);
+
+ Syslog(LOG_INFO, line_buff);
+ line = line_buff;
+ space = sizeof(line_buff)-1;
+ parse_state = PARSING_TEXT;
+ symbols_expanded = 0;
+ skip_symbol_lookup = 0;
+ save_ptr = ptr;
+ save_len = len;
+ }
+
+ switch( parse_state )
+ {
+ case PARSING_TEXT:
+ delta = copyin(line, space, ptr, len, "\n[" );
+ line += delta;
+ ptr += delta;
+ space -= delta;
+ len -= delta;
+
+ if( space == 0 || len == 0 )
+ {
+ break; /* full line_buff or end of input buffer */
+ }
+
+ if( *ptr == '\0' ) /* zero byte */
+ {
+ ptr++; /* skip zero byte */
+ space -= 1;
+ len -= 1;
+
+ break;
+ }
+
+ if( *ptr == '\n' ) /* newline */
+ {
+ ptr++; /* skip newline */
+ space -= 1;
+ len -= 1;
+
+ *line = 0; /* force null terminator */
+ Syslog(LOG_INFO, line_buff);
+ line = line_buff;
+ space = sizeof(line_buff)-1;
+ if (symbols_twice) {
+ if (symbols_expanded) {
+ /* reprint this line without symbol lookup */
+ symbols_expanded = 0;
+ skip_symbol_lookup = 1;
+ ptr = save_ptr;
+ len = save_len;
+ }
+ else
+ {
+ skip_symbol_lookup = 0;
+ save_ptr = ptr;
+ save_len = len;
+ }
+ }
+ break;
+ }
+ if( *ptr == '[' ) /* possible kernel symbol */
+ {
+ *line++ = *ptr++;
+ space -= 1;
+ len -= 1;
+ if (!skip_symbol_lookup)
+ parse_state = PARSING_SYMSTART; /* at < */
+ break;
+ }
+ /* Now that line_buff is no longer fed to *printf as format
+ * string, '%'s are no longer "dangerous".
+ */
+ break;
+
+ case PARSING_SYMSTART:
+ if( *ptr != '<' )
+ {
+ parse_state = PARSING_TEXT; /* not a symbol */
+ break;
+ }
+
+ /*
+ ** Save this character for now. If this turns out to
+ ** be a valid symbol, this char will be replaced later.
+ ** If not, we'll just leave it there.
+ */
+
+ sym_start = line; /* this will point at the '<' */
+
+ *line++ = *ptr++;
+ space -= 1;
+ len -= 1;
+ parse_state = PARSING_SYMBOL; /* symbol... */
+ break;
+
+ case PARSING_SYMBOL:
+ delta = copyin( line, space, ptr, len, ">\n[" );
+ line += delta;
+ ptr += delta;
+ space -= delta;
+ len -= delta;
+ if( space == 0 || len == 0 )
+ {
+ break; /* full line_buff or end of input buffer */
+ }
+ if( *ptr != '>' )
+ {
+ parse_state = PARSING_TEXT;
+ break;
+ }
+
+ *line++ = *ptr++; /* copy the '>' */
+ space -= 1;
+ len -= 1;
+
+ parse_state = PARSING_SYMEND;
+
+ break;
+
+ case PARSING_SYMEND:
+ if( *ptr != ']' )
+ {
+ parse_state = PARSING_TEXT; /* not a symbol */
+ break;
+ }
+
+ /*
+ ** It's really a symbol! Replace address with the
+ ** symbol text.
+ */
+ {
+ auto int sym_space;
+
+ unsigned long value;
+ auto struct symbol sym;
+ auto char *symbol;
+
+ *(line-1) = 0; /* null terminate the address string */
+ value = strtoul((char*)(sym_start+1), (char **) 0, 16);
+ *(line-1) = '>'; /* put back delim */
+
+ if ( !symbol_lookup || (symbol = LookupSymbol(value, &sym)) == (char *)0 )
+ {
+ parse_state = PARSING_TEXT;
+ break;
+ }
+
+ /*
+ ** verify there is room in the line buffer
+ */
+ sym_space = space + ( line - sym_start );
+ if( (unsigned) sym_space < strlen(symbol) + 30 ) /*(30 should be overkill)*/
+ {
+ parse_state = PARSING_TEXT; /* not enough space */
+ break;
+ }
+
+ // TODO: sprintf!!!!
+ delta = sprintf( (char*) sym_start, "%s+%d/%d]",
+ symbol, sym.offset, sym.size );
+
+ space = sym_space + delta;
+ line = sym_start + delta;
+ symbols_expanded = 1;
+ }
+ ptr++;
+ len--;
+ parse_state = PARSING_TEXT;
+ break;
+
+ default: /* Can't get here! */
+ parse_state = PARSING_TEXT;
+
+ }
+ }
+
+ return;
+}
+
+
+static void LogKernelLine(void)
+{
+ auto int rdcnt;
+
+ /*
+ * Zero-fill the log buffer. This should cure a multitude of
+ * problems with klogd logging the tail end of the message buffer
+ * which will contain old messages. Then read the kernel log
+ * messages into this fresh buffer.
+ */
+ memset(log_buffer, '\0', sizeof(log_buffer));
+ if ( (rdcnt = ksyslog(2, log_buffer, sizeof(log_buffer)-1)) < 0 )
+ {
+ char sz[512];
+ if(errno == EINTR)
+ return;
+ snprintf(sz, sizeof(sz), "imklog: Error return from sys_sycall: %d - %s\n", errno, strerror(errno));
+ logmsgInternal(LOG_SYSLOG|LOG_ERR, sz, ADDDATE);
+ }
+ else
+ LogLine(log_buffer, rdcnt);
+ return;
+}
+
+
+static void LogProcLine(void)
+{
+ auto int rdcnt;
+
+ /*
+ * Zero-fill the log buffer. This should cure a multitude of
+ * problems with klogd logging the tail end of the message buffer
+ * which will contain old messages. Then read the kernel messages
+ * from the message pseudo-file into this fresh buffer.
+ */
+ memset(log_buffer, '\0', sizeof(log_buffer));
+ if ( (rdcnt = read(kmsg, log_buffer, sizeof(log_buffer)-1)) < 0 ) {
+ if ( errno == EINTR )
+ return;
+ imklogLogIntMsg(LOG_ERR, "Cannot read proc file system: %d - %s.", errno, strerror(errno));
+ } else {
+ LogLine(log_buffer, rdcnt);
+ }
+
+ return;
+}
+
+
+/* to be called in the module's WillRun entry point
+ * rgerhards, 2008-04-09
+ */
+rsRetVal klogLogKMsg(void)
+{
+ DEFiRet;
+ switch(logsrc) {
+ case kernel:
+ LogKernelLine();
+ break;
+ case proc:
+ LogProcLine();
+ break;
+ case none:
+ /* TODO: We need to handle this case here somewhat more intelligent
+ * This is now at least partly done - code should never reach this point
+ * as willRun() already checked for the "none" status -- rgerhards, 2007-12-17
+ */
+ pause();
+ break;
+ }
+ RETiRet;
+}
+
+
+/* to be called in the module's WillRun entry point
+ * rgerhards, 2008-04-09
+ */
+rsRetVal klogWillRun(void)
+{
+ DEFiRet;
+ /* Initialize this module. If that fails, we tell the engine we don't like to run */
+ /* Determine where kernel logging information is to come from. */
+ logsrc = GetKernelLogSrc();
+ if(logsrc == none) {
+ iRet = RS_RET_NO_KERNEL_LOGSRC;
+ } else {
+ if (symbol_lookup) {
+ symbol_lookup = (InitKsyms(symfile) == 1);
+ symbol_lookup |= InitMsyms();
+ if (symbol_lookup == 0) {
+ imklogLogIntMsg(LOG_WARNING, "cannot find any symbols, turning off symbol lookups\n");
+ }
+ }
+ }
+
+ RETiRet;
+}
+
+
+/* to be called in the module's AfterRun entry point
+ * rgerhards, 2008-04-09
+ */
+rsRetVal klogAfterRun(void)
+{
+ DEFiRet;
+ /* cleanup here */
+ if(logsrc != none)
+ CloseLogSrc();
+
+ DeinitKsyms();
+ DeinitMsyms();
+
+ RETiRet;
+}
+
+
+/* provide the (system-specific) default facility for internal messages
+ * rgerhards, 2008-04-14
+ */
+int
+klogFacilIntMsg(void)
+{
+ return LOG_KERN;
+}
+
+
+/* vi:set ai:
+ */
diff --git a/plugins/imuxsock/imuxsock.c b/plugins/imuxsock/imuxsock.c
index 3cdcbf0a..f8798039 100644
--- a/plugins/imuxsock/imuxsock.c
+++ b/plugins/imuxsock/imuxsock.c
@@ -181,7 +181,7 @@ static rsRetVal readSocket(int fd, int bParseHost, int flags)
iRcvd = recv(fd, line, MAXLINE - 1, 0);
dbgprintf("Message from UNIX socket: #%d\n", fd);
if (iRcvd > 0) {
- parseAndSubmitMessage(LocalHostName, line, iRcvd, bParseHost, flags, eFLOWCTL_LIGHT_DELAY);
+ parseAndSubmitMessage((char*)LocalHostName, line, iRcvd, bParseHost, flags, eFLOWCTL_LIGHT_DELAY);
} else if (iRcvd < 0 && errno != EINTR) {
char errStr[1024];
rs_strerror_r(errno, errStr, sizeof(errStr));
diff --git a/plugins/omgssapi/omgssapi.c b/plugins/omgssapi/omgssapi.c
index 9a7e8ab9..8c6a2006 100644
--- a/plugins/omgssapi/omgssapi.c
+++ b/plugins/omgssapi/omgssapi.c
@@ -4,7 +4,7 @@
* NOTE: read comments in module-template.h to understand how this file
* works!
*
- * Copyright 2007 Rainer Gerhards and Adiscon GmbH.
+ * Copyright 2007, 2008 Rainer Gerhards and Adiscon GmbH.
*
* This file is part of rsyslog.
*
@@ -79,7 +79,7 @@ DEFobjCurrIf(gssutil)
DEFobjCurrIf(tcpclt)
typedef struct _instanceData {
- char f_hname[MAXHOSTNAMELEN+1];
+ char *f_hname;
short sock; /* file descriptor */
enum { /* TODO: we shoud revisit these definitions */
eDestFORW,
@@ -162,6 +162,9 @@ CODESTARTfreeInstance
tcpclt.Destruct(&pData->pTCPClt);
if(pData->sock >= 0)
close(pData->sock);
+
+ if(pData->f_hname != NULL)
+ free(pData->f_hname);
ENDfreeInstance
@@ -592,10 +595,11 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1)
/* TODO: make this if go away! */
if(*p == ';') {
*p = '\0'; /* trick to obtain hostname (later)! */
- strcpy(pData->f_hname, (char*) q);
+ CHKmalloc(pData->f_hname = strdup((char*) q));
*p = ';';
- } else
- strcpy(pData->f_hname, (char*) q);
+ } else {
+ CHKmalloc(pData->f_hname = strdup((char*) q));
+ }
/* process template */
CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS,
@@ -701,6 +705,5 @@ CODEmodInit_QueryRegCFSLineHdlr
ENDmodInit
#endif /* #ifdef USE_GSSAPI */
-/*
- * vi:set ai:
+/* vi:set ai:
*/
diff --git a/plugins/ommail/Makefile.am b/plugins/ommail/Makefile.am
new file mode 100644
index 00000000..7e9f5f13
--- /dev/null
+++ b/plugins/ommail/Makefile.am
@@ -0,0 +1,6 @@
+pkglib_LTLIBRARIES = ommail.la
+
+ommail_la_SOURCES = ommail.c
+ommail_la_CPPFLAGS = -I$(top_srcdir) $(pthreads_cflags)
+ommail_la_LDFLAGS = -module -avoid-version
+ommail_la_LIBADD =
diff --git a/plugins/ommail/ommail.c b/plugins/ommail/ommail.c
new file mode 100644
index 00000000..218c73c9
--- /dev/null
+++ b/plugins/ommail/ommail.c
@@ -0,0 +1,630 @@
+/* ommail.c
+ *
+ * This is an implementation of a mail sending output module. So far, we
+ * only support direct SMTP, that is talking to a SMTP server. In the long
+ * term, support for using sendmail should also be implemented. Please note
+ * that the SMTP protocol implementation is a very bare one. We support
+ * RFC821/822 messages, without any authentication and any other nice
+ * features (no MIME, no nothing). It is assumed that proper firewalling
+ * and/or STMP server configuration is used together with this module.
+ *
+ * NOTE: read comments in module-template.h to understand how this file
+ * works!
+ *
+ * File begun on 2008-04-04 by RGerhards
+ *
+ * Copyright 2008 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 <unistd.h>
+#include <errno.h>
+#include <netdb.h>
+#include <time.h>
+#include <sys/socket.h>
+#include "syslogd.h"
+#include "syslogd-types.h"
+#include "srUtils.h"
+#include "cfsysline.h"
+#include "module-template.h"
+#include "errmsg.h"
+
+MODULE_TYPE_OUTPUT
+
+/* internal structures
+ */
+DEF_OMOD_STATIC_DATA
+DEFobjCurrIf(errmsg)
+
+static uchar *pszSrv = NULL;
+static uchar *pszSrvPort = NULL;
+static uchar *pszFrom = NULL;
+static uchar *pszTo = NULL;
+static uchar *pszSubject = NULL;
+static int bEnableBody = 1; /* should a mail body be generated? (set to 0 eg for SMS gateways) */
+
+typedef struct _instanceData {
+ int iMode; /* 0 - smtp, 1 - sendmail */
+ int bHaveSubject; /* is a subject configured? (if so, it is the second string provided by rsyslog core) */
+ int bEnableBody; /* is a body configured? (if so, it is the second string provided by rsyslog core) */
+ union {
+ struct {
+ uchar *pszSrv;
+ uchar *pszSrvPort;
+ uchar *pszFrom;
+ uchar *pszTo;
+ char RcvBuf[1024]; /* buffer for receiving server responses */
+ size_t lenRcvBuf;
+ size_t iRcvBuf; /* current index into the rcvBuf (buf empty if iRcvBuf == lenRcvBuf) */
+ int sock; /* socket to this server (most important when we do multiple msgs per mail) */
+ } smtp;
+ } md; /* mode-specific data */
+} instanceData;
+
+
+BEGINcreateInstance
+CODESTARTcreateInstance
+ENDcreateInstance
+
+
+BEGINisCompatibleWithFeature
+CODESTARTisCompatibleWithFeature
+ if(eFeat == sFEATURERepeatedMsgReduction)
+ iRet = RS_RET_OK;
+ENDisCompatibleWithFeature
+
+
+BEGINfreeInstance
+CODESTARTfreeInstance
+ if(pData->iMode == 0) {
+ if(pData->md.smtp.pszSrv != NULL)
+ free(pData->md.smtp.pszSrv);
+ if(pData->md.smtp.pszSrvPort != NULL)
+ free(pData->md.smtp.pszSrvPort);
+ if(pData->md.smtp.pszFrom != NULL)
+ free(pData->md.smtp.pszFrom);
+ if(pData->md.smtp.pszTo != NULL)
+ free(pData->md.smtp.pszTo);
+ }
+ENDfreeInstance
+
+
+BEGINdbgPrintInstInfo
+CODESTARTdbgPrintInstInfo
+ printf("mail"); /* TODO: extend! */
+ENDdbgPrintInstInfo
+
+
+/* TCP support code, should probably be moved to net.c or some place else... -- rgerhards, 2008-04-04 */
+
+/* "receive" a character from the remote server. A single character
+ * is returned. Returns RS_RET_NO_MORE_DATA if the server has closed
+ * the connection and RS_RET_IO_ERROR if something goes wrong. This
+ * is a blocking read.
+ * rgerhards, 2008-04-04
+ */
+static rsRetVal
+getRcvChar(instanceData *pData, char *pC)
+{
+ DEFiRet;
+ ssize_t lenBuf;
+ assert(pData != NULL);
+
+ if(pData->md.smtp.iRcvBuf == pData->md.smtp.lenRcvBuf) { /* buffer empty? */
+ /* yes, we need to read the next server response */
+ do {
+ lenBuf = recv(pData->md.smtp.sock, pData->md.smtp.RcvBuf, sizeof(pData->md.smtp.RcvBuf), 0);
+ if(lenBuf == 0) {
+ ABORT_FINALIZE(RS_RET_NO_MORE_DATA);
+ } else if(lenBuf < 0) {
+ if(errno != EAGAIN) {
+ ABORT_FINALIZE(RS_RET_IO_ERROR);
+ }
+ } else {
+ /* good read */
+ pData->md.smtp.iRcvBuf = 0;
+ pData->md.smtp.lenRcvBuf = lenBuf;
+ }
+
+ } while(lenBuf < 1);
+ }
+
+ /* when we reach this point, we have a non-empty buffer */
+ *pC = pData->md.smtp.RcvBuf[pData->md.smtp.iRcvBuf++];
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* close the mail server connection
+ * rgerhards, 2008-04-08
+ */
+static rsRetVal
+serverDisconnect(instanceData *pData)
+{
+ DEFiRet;
+ assert(pData != NULL);
+
+ if(pData->md.smtp.sock != -1) {
+ close(pData->md.smtp.sock);
+ pData->md.smtp.sock = -1;
+ }
+
+ RETiRet;
+}
+
+
+/* open a connection to the mail server
+ * rgerhards, 2008-04-04
+ */
+static rsRetVal
+serverConnect(instanceData *pData)
+{
+ struct addrinfo *res = NULL;
+ struct addrinfo hints;
+ char *smtpPort;
+ char *smtpSrv;
+ char errStr[1024];
+
+ DEFiRet;
+ assert(pData != NULL);
+
+ if(pData->md.smtp.pszSrv == NULL)
+ smtpSrv = "127.0.0.1";
+ else
+ smtpSrv = (char*)pData->md.smtp.pszSrv;
+
+ if(pData->md.smtp.pszSrvPort == NULL)
+ smtpPort = "25";
+ else
+ smtpPort = (char*)pData->md.smtp.pszSrvPort;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC; /* TODO: make configurable! */
+ hints.ai_socktype = SOCK_STREAM;
+ if(getaddrinfo(smtpSrv, smtpPort, &hints, &res) != 0) {
+ dbgprintf("error %d in getaddrinfo\n", errno);
+ ABORT_FINALIZE(RS_RET_IO_ERROR);
+ }
+
+ if((pData->md.smtp.sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1) {
+ dbgprintf("couldn't create send socket, reason %s", rs_strerror_r(errno, errStr, sizeof(errStr)));
+ ABORT_FINALIZE(RS_RET_IO_ERROR);
+ }
+
+ if(connect(pData->md.smtp.sock, res->ai_addr, res->ai_addrlen) != 0) {
+ dbgprintf("create tcp connection failed, reason %s", rs_strerror_r(errno, errStr, sizeof(errStr)));
+ ABORT_FINALIZE(RS_RET_IO_ERROR);
+ }
+
+finalize_it:
+ if(res != NULL)
+ freeaddrinfo(res);
+
+ if(iRet != RS_RET_OK) {
+ if(pData->md.smtp.sock != -1) {
+ close(pData->md.smtp.sock);
+ pData->md.smtp.sock = -1;
+ }
+ }
+
+ RETiRet;
+}
+
+
+/* send text to the server, blocking send */
+static rsRetVal
+Send(int sock, char *msg, size_t len)
+{
+ DEFiRet;
+ size_t offsBuf = 0;
+ ssize_t lenSend;
+
+ assert(msg != NULL);
+
+ if(len == 0) /* it's valid, but does not make much sense ;) */
+ FINALIZE;
+
+ do {
+ lenSend = send(sock, msg + offsBuf, len - offsBuf, 0);
+ if(lenSend == -1) {
+ if(errno != EAGAIN) {
+ dbgprintf("message not (tcp)send, errno %d", errno);
+ ABORT_FINALIZE(RS_RET_TCP_SEND_ERROR);
+ }
+ } else if(lenSend != (ssize_t) len) {
+ offsBuf += len; /* on to next round... */
+ } else {
+ FINALIZE;
+ }
+ } while(1);
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* send body text to the server, blocking send
+ * The body is special in that we must escape a leading dot inside a line
+ */
+static rsRetVal
+bodySend(instanceData *pData, char *msg, size_t len)
+{
+ DEFiRet;
+ char szBuf[2048];
+ size_t iSrc;
+ size_t iBuf = 0;
+ int bHadCR = 0;
+ int bInStartOfLine = 1;
+
+ assert(pData != NULL);
+ assert(msg != NULL);
+
+ for(iSrc = 0 ; iSrc < len ; ++iSrc) {
+ if(iBuf >= sizeof(szBuf) - 1) { /* one is reserved for our extra dot */
+ CHKiRet(Send(pData->md.smtp.sock, szBuf, iBuf));
+ iBuf = 0;
+ }
+ szBuf[iBuf++] = msg[iSrc];
+ switch(msg[iSrc]) {
+ case '\r':
+ bHadCR = 1;
+ break;
+ case '\n':
+ if(bHadCR)
+ bInStartOfLine = 1;
+ bHadCR = 0;
+ break;
+ case '.':
+ if(bInStartOfLine)
+ szBuf[iBuf++] = '.'; /* space is always reserved for this! */
+ /*FALLTHROUGH*/
+ default:
+ bInStartOfLine = 0;
+ bHadCR = 0;
+ break;
+ }
+ }
+
+ if(iBuf > 0) { /* incomplete buffer to send (the *usual* case)? */
+ CHKiRet(Send(pData->md.smtp.sock, szBuf, iBuf));
+ }
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* read response line from server
+ */
+static rsRetVal
+readResponseLn(instanceData *pData, char *pLn, size_t lenLn)
+{
+ DEFiRet;
+ size_t i = 0;
+ char c;
+
+ assert(pData != NULL);
+ assert(pLn != NULL);
+
+ do {
+ CHKiRet(getRcvChar(pData, &c));
+ if(c == '\n')
+ break;
+ if(i < (lenLn - 1)) /* if line is too long, we simply discard the rest */
+ pLn[i++] = c;
+ } while(1);
+ pLn[i] = '\0';
+ dbgprintf("smtp server response: %s\n", pLn); /* do not remove, this is helpful in troubleshooting SMTP probs! */
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* read numerical response code from server and compare it to requried response code.
+ * If they two don't match, return RS_RET_SMTP_ERROR.
+ * rgerhards, 2008-04-07
+ */
+static rsRetVal
+readResponse(instanceData *pData, int *piState, int iExpected)
+{
+ DEFiRet;
+ int bCont;
+ char buf[128];
+
+ assert(pData != NULL);
+ assert(piState != NULL);
+
+ bCont = 1;
+ do {
+ CHKiRet(readResponseLn(pData, buf, sizeof(buf)));
+ /* note: the code below is not 100% clean as we may have received less than 4 characters.
+ * However, as we have a fixed size this will not create a vulnerability. An error will
+ * also most likely be generated, so it is quite acceptable IMHO -- rgerhards, 2008-04-08
+ */
+ if(buf[3] != '-') { /* last or only response line? */
+ bCont = 0;
+ *piState = buf[0] - '0';
+ *piState = *piState * 10 + buf[1] - '0';
+ *piState = *piState * 10 + buf[2] - '0';
+ if(*piState != iExpected)
+ ABORT_FINALIZE(RS_RET_SMTP_ERROR);
+ }
+ } while(bCont);
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* create a timestamp suitable for use with the Date: SMTP body header
+ * rgerhards, 2008-04-08
+ */
+static void
+mkSMTPTimestamp(uchar *pszBuf, size_t lenBuf)
+{
+ time_t tCurr;
+ struct tm tmCurr;
+ static const char szDay[][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
+ static const char szMonth[][4] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+
+ time(&tCurr);
+ gmtime_r(&tCurr, &tmCurr);
+ snprintf((char*)pszBuf, lenBuf, "Date: %s, %2d %s %4d %2d:%02d:%02d UT\r\n", szDay[tmCurr.tm_wday], tmCurr.tm_mday,
+ szMonth[tmCurr.tm_mon], 1900 + tmCurr.tm_year, tmCurr.tm_hour, tmCurr.tm_min, tmCurr.tm_sec);
+}
+
+
+/* send a message via SMTP
+ * rgerhards, 2008-04-04
+ */
+static rsRetVal
+sendSMTP(instanceData *pData, uchar *body, uchar *subject)
+{
+ DEFiRet;
+ int iState; /* SMTP state */
+ uchar szDateBuf[64];
+
+ assert(pData != NULL);
+
+ CHKiRet(serverConnect(pData));
+ CHKiRet(readResponse(pData, &iState, 220));
+
+ CHKiRet(Send(pData->md.smtp.sock, "HELO ", 5));
+ CHKiRet(Send(pData->md.smtp.sock, (char*)LocalHostName, strlen((char*)LocalHostName)));
+ CHKiRet(Send(pData->md.smtp.sock, "\r\n", sizeof("\r\n") - 1));
+ CHKiRet(readResponse(pData, &iState, 250));
+
+ CHKiRet(Send(pData->md.smtp.sock, "MAIL FROM: <", sizeof("MAIL FROM: <") - 1));
+ CHKiRet(Send(pData->md.smtp.sock, (char*)pData->md.smtp.pszFrom, strlen((char*)pData->md.smtp.pszFrom)));
+ CHKiRet(Send(pData->md.smtp.sock, ">\r\n", sizeof(">\r\n") - 1));
+ CHKiRet(readResponse(pData, &iState, 250));
+
+ CHKiRet(Send(pData->md.smtp.sock, "RCPT TO: <", sizeof("RCPT TO: <") - 1));
+ CHKiRet(Send(pData->md.smtp.sock, (char*)pData->md.smtp.pszTo, strlen((char*)pData->md.smtp.pszTo)));
+ CHKiRet(Send(pData->md.smtp.sock, ">\r\n", sizeof(">\r\n") - 1));
+ CHKiRet(readResponse(pData, &iState, 250));
+
+ CHKiRet(Send(pData->md.smtp.sock, "DATA\r\n", sizeof("DATA\r\n") - 1));
+ CHKiRet(readResponse(pData, &iState, 354));
+
+ /* now come the data part */
+ /* header */
+ mkSMTPTimestamp(szDateBuf, sizeof(szDateBuf));
+ CHKiRet(Send(pData->md.smtp.sock, (char*)szDateBuf, strlen((char*)szDateBuf)));
+
+ CHKiRet(Send(pData->md.smtp.sock, "From: <", sizeof("From: <") - 1));
+ CHKiRet(Send(pData->md.smtp.sock, (char*)pData->md.smtp.pszFrom, strlen((char*)pData->md.smtp.pszFrom)));
+ CHKiRet(Send(pData->md.smtp.sock, ">\r\n", sizeof(">\r\n") - 1));
+
+ CHKiRet(Send(pData->md.smtp.sock, "To: <", sizeof("To: <") - 1));
+ CHKiRet(Send(pData->md.smtp.sock, (char*)pData->md.smtp.pszTo, strlen((char*)pData->md.smtp.pszTo)));
+ CHKiRet(Send(pData->md.smtp.sock, ">\r\n", sizeof(">\r\n") - 1));
+
+ CHKiRet(Send(pData->md.smtp.sock, "Subject: ", sizeof("Subject: ") - 1));
+ CHKiRet(Send(pData->md.smtp.sock, (char*)subject, strlen((char*)subject)));
+ CHKiRet(Send(pData->md.smtp.sock, "\r\n", sizeof("\r\n") - 1));
+
+ CHKiRet(Send(pData->md.smtp.sock, "X-Mailer: rsyslog-immail\r\n", sizeof("x-mailer: rsyslog-immail\r\n") - 1));
+
+ CHKiRet(Send(pData->md.smtp.sock, "\r\n", sizeof("\r\n") - 1)); /* indicate end of header */
+
+ /* body */
+ if(pData->bEnableBody)
+ CHKiRet(bodySend(pData, (char*)body, strlen((char*) body)));
+
+ /* end of data, back to envelope transaction */
+ CHKiRet(Send(pData->md.smtp.sock, "\r\n.\r\n", sizeof("\r\n.\r\n") - 1));
+ CHKiRet(readResponse(pData, &iState, 250));
+
+ CHKiRet(Send(pData->md.smtp.sock, "QUIT\r\n", sizeof("QUIT\r\n") - 1));
+ CHKiRet(readResponse(pData, &iState, 221));
+
+ /* we are finished, a new connection is created for each request, so let's close it now */
+ CHKiRet(serverDisconnect(pData));
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* in tryResume we check if we can connect to the server in question. If that is OK,
+ * we close the connection without doing any actual SMTP transaction. It will be
+ * reopened during the actual send process. This may not be the best way to do it if
+ * there is a problem inside the SMTP transaction. However, we can't find that out without
+ * actually initiating something, and that would be bad. The logic here helps us
+ * correctly recover from an unreachable/down mail server, which is probably the majority
+ * of problem cases. For SMTP transaction problems, we will do lots of retries, but if it
+ * is a temporary problem, it will be fixed anyhow. So I consider this implementation to
+ * be clean enough, especially as I think other approaches have other weaknesses.
+ * rgerhards, 2008-04-08
+ */
+BEGINtryResume
+CODESTARTtryResume
+ CHKiRet(serverConnect(pData));
+ CHKiRet(serverDisconnect(pData)); /* if we fail, we will never reach this line */
+finalize_it:
+ if(iRet == RS_RET_IO_ERROR)
+ iRet = RS_RET_SUSPENDED;
+ENDtryResume
+
+
+BEGINdoAction
+CODESTARTdoAction
+ dbgprintf(" Mail\n");
+
+ /* forward */
+ if(pData->bHaveSubject)
+ iRet = sendSMTP(pData, ppString[0], ppString[1]);
+ else
+ iRet = sendSMTP(pData, ppString[0], (uchar*)"message from rsyslog");
+
+ if(iRet != RS_RET_OK) {
+ /* error! */
+ dbgprintf("error sending mail, suspending\n");
+ iRet = RS_RET_SUSPENDED;
+ }
+ENDdoAction
+
+
+BEGINparseSelectorAct
+CODESTARTparseSelectorAct
+ if(!strncmp((char*) p, ":ommail:", sizeof(":ommail:") - 1)) {
+ p += sizeof(":ommail:") - 1; /* eat indicator sequence (-1 because of '\0'!) */
+ } else {
+ ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED);
+ }
+
+ /* ok, if we reach this point, we have something for us */
+ if((iRet = createInstance(&pData)) != RS_RET_OK)
+ FINALIZE;
+
+ /* TODO: check strdup() result */
+
+ if(pszFrom == NULL) {
+ errmsg.LogError(NO_ERRCODE, "no sender address given - specify $ActionMailFrom");
+ ABORT_FINALIZE(RS_RET_MAIL_NO_FROM);
+ }
+ if(pszTo == NULL) {
+ errmsg.LogError(NO_ERRCODE, "no recipient address given - specify $ActionMailTo");
+ ABORT_FINALIZE(RS_RET_MAIL_NO_TO);
+ }
+
+ pData->md.smtp.pszFrom = (uchar*) strdup((char*)pszFrom);
+ pData->md.smtp.pszTo = (uchar*) strdup((char*)pszTo);
+
+ if(pszSubject == NULL) {
+ /* if no subject is configured, we need just one template string */
+ CODE_STD_STRING_REQUESTparseSelectorAct(1)
+ } else {
+ CODE_STD_STRING_REQUESTparseSelectorAct(2)
+ pData->bHaveSubject = 1;
+ CHKiRet(OMSRsetEntry(*ppOMSR, 1, (uchar*)strdup((char*) pszSubject), OMSR_NO_RQD_TPL_OPTS));
+ }
+ if(pszSrv != NULL)
+ pData->md.smtp.pszSrv = (uchar*) strdup((char*)pszSrv);
+ if(pszSrvPort != NULL)
+ pData->md.smtp.pszSrvPort = (uchar*) strdup((char*)pszSrvPort);
+ pData->bEnableBody = bEnableBody;
+
+ /* process template */
+ CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, (uchar*) "RSYSLOG_FileFormat"));
+CODE_STD_FINALIZERparseSelectorAct
+ENDparseSelectorAct
+
+
+/* Free string config variables and reset them to NULL (not necessarily the default!) */
+static rsRetVal freeConfigVariables(void)
+{
+ DEFiRet;
+
+ if(pszSrv != NULL) {
+ free(pszSrv);
+ pszSrv = NULL;
+ }
+ if(pszSrvPort != NULL) {
+ free(pszSrvPort);
+ pszSrvPort = NULL;
+ }
+ if(pszFrom != NULL) {
+ free(pszFrom);
+ pszFrom = NULL;
+ }
+ if(pszTo != NULL) {
+ free(pszTo);
+ pszTo = NULL;
+ }
+
+ RETiRet;
+}
+
+
+BEGINmodExit
+CODESTARTmodExit
+ /* cleanup our allocations */
+ freeConfigVariables();
+
+ /* release what we no longer need */
+ objRelease(errmsg, CORE_COMPONENT);
+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;
+ bEnableBody = 1;
+ iRet = freeConfigVariables();
+ RETiRet;
+}
+
+
+BEGINmodInit()
+CODESTARTmodInit
+ *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
+CODEmodInit_QueryRegCFSLineHdlr
+ /* tell which objects we need */
+ CHKiRet(objUse(errmsg, CORE_COMPONENT));
+
+ CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionmailsmtpserver", 0, eCmdHdlrGetWord, NULL, &pszSrv, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionmailsmtpport", 0, eCmdHdlrGetWord, NULL, &pszSrvPort, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionmailfrom", 0, eCmdHdlrGetWord, NULL, &pszFrom, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionmailto", 0, eCmdHdlrGetWord, NULL, &pszTo, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionmailsubject", 0, eCmdHdlrGetWord, NULL, &pszSubject, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionmailenablebody", 0, eCmdHdlrBinary, NULL, &bEnableBody, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr( (uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
+ENDmodInit
+
+/* vim:set ai:
+ */
diff --git a/plugins/omrelp/omrelp.c b/plugins/omrelp/omrelp.c
index 39d25812..04571682 100644
--- a/plugins/omrelp/omrelp.c
+++ b/plugins/omrelp/omrelp.c
@@ -53,7 +53,7 @@ DEFobjCurrIf(errmsg)
static relpEngine_t *pRelpEngine; /* our relp engine */
typedef struct _instanceData {
- char f_hname[MAXHOSTNAMELEN+1];
+ char *f_hname;
int compressionLevel; /* 0 - no compression, else level for zlib */
char *port;
int bInitialConnect; /* is this the initial connection request of our module? (0-no, 1-yes) */
@@ -98,6 +98,9 @@ CODESTARTfreeInstance
if(pData->pRelpClt != NULL)
relpEngineCltDestruct(pRelpEngine, &pData->pRelpClt);
+ if(pData->f_hname != NULL)
+ free(pData->f_hname);
+
ENDfreeInstance
@@ -284,10 +287,11 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1)
/* TODO: make this if go away! */
if(*p == ';') {
*p = '\0'; /* trick to obtain hostname (later)! */
- strcpy(pData->f_hname, (char*) q);
+ CHKmalloc(pData->f_hname = strdup((char*) q));
*p = ';';
- } else
- strcpy(pData->f_hname, (char*) q);
+ } else {
+ CHKmalloc(pData->f_hname = strdup((char*) q));
+ }
/* process template */
CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, (uchar*) "RSYSLOG_ForwardFormat"));
diff --git a/queue.c b/queue.c
index 20ead4a1..0f58c545 100644
--- a/queue.c
+++ b/queue.c
@@ -39,6 +39,7 @@
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h> /* required for HP UX */
+#include <time.h>
#include <errno.h>
#include "rsyslog.h"
@@ -56,6 +57,7 @@ DEFobjStaticHelpers
/* forward-definitions */
rsRetVal queueChkPersist(queue_t *pThis);
static rsRetVal queueSetEnqOnly(queue_t *pThis, int bEnqOnly, int bLockMutex);
+static rsRetVal queueRateLimiter(queue_t *pThis);
static int queueChkStopWrkrDA(queue_t *pThis);
static int queueIsIdleDA(queue_t *pThis);
static rsRetVal queueConsumerDA(queue_t *pThis, wti_t *pWti, int iCancelStateSave);
@@ -272,6 +274,8 @@ queueStartDA(queue_t *pThis)
CHKiRet(queueSettoActShutdown(pThis->pqDA, pThis->toActShutdown));
CHKiRet(queueSettoEnq(pThis->pqDA, pThis->toEnq));
CHKiRet(queueSetEnqOnly(pThis->pqDA, pThis->bDAEnqOnly, MUTEX_ALREADY_LOCKED));
+ CHKiRet(queueSetiDeqtWinFromHr(pThis->pqDA, pThis->iDeqtWinFromHr));
+ CHKiRet(queueSetiDeqtWinToHr(pThis->pqDA, pThis->iDeqtWinToHr));
CHKiRet(queueSetiHighWtrMrk(pThis->pqDA, 0));
CHKiRet(queueSetiDiscardMrk(pThis->pqDA, 0));
if(pThis->toQShutdown == 0) {
@@ -1268,6 +1272,7 @@ rsRetVal queueConstruct(queue_t **ppThis, queueType_t qType, int iWorkerThreads,
pThis->iMaxQueueSize = iMaxQueueSize;
pThis->pConsumer = pConsumer;
pThis->iNumWorkerThreads = iWorkerThreads;
+ pThis->iDeqtWinToHr = 25; /* disable time-windowed dequeuing by default */
pThis->pszFilePrefix = NULL;
pThis->qType = qType;
@@ -1412,12 +1417,10 @@ queueDequeueConsumable(queue_t *pThis, wti_t *pWti, int iCancelStateSave)
* on the nail [exact value]) -- rgerhards, 2008-03-14
*/
if(iQueueSize < pThis->iFullDlyMrk) {
-dbgoprint((obj_t*) pThis, "queue size %d below FullDlyMrk %d\n", iQueueSize, pThis->iFullDlyMrk);
pthread_cond_broadcast(&pThis->belowFullDlyWtrMrk);
}
if(iQueueSize < pThis->iLightDlyMrk) {
-dbgoprint((obj_t*) pThis, "queue size %d below LightDlyMrk %d\n", iQueueSize, pThis->iLightDlyMrk);
pthread_cond_broadcast(&pThis->belowLightDlyWtrMrk);
}
@@ -1451,6 +1454,104 @@ finalize_it:
}
+/* The rate limiter
+ *
+ * Here we may wait if a dequeue time window is defined or if we are
+ * rate-limited. TODO: If we do so, we should also look into the
+ * way new worker threads are spawned. Obviously, it doesn't make much
+ * sense to spawn additional worker threads when none of them can do any
+ * processing. However, it is deemed acceptable to allow this for an initial
+ * implementation of the timeframe/rate limiting feature.
+ * Please also note that these feature could also be implemented at the action
+ * level. However, that would limit them to be used together with actions. We have
+ * taken the broader approach, moving it right into the queue. This is even
+ * necessary if we want to prevent spawning of multiple unnecessary worker
+ * threads as described above. -- rgerhards, 2008-04-02
+ *
+ *
+ * time window: tCurr is current time; tFrom is start time, tTo is end time (in mil 24h format).
+ * We may have tFrom = 4, tTo = 10 --> run from 4 to 10 hrs. nice and happy
+ * we may also have tFrom= 22, tTo = 4 -> run from 10pm to 4am, which is actually two
+ * windows: 0-4; 22-23:59
+ * so when to run? Let's assume we have 3am
+ *
+ * if(tTo < tFrom) {
+ * if(tCurr < tTo [3 < 4] || tCurr > tFrom [3 > 22])
+ * do work
+ * else
+ * sleep for tFrom - tCurr "hours" [22 - 5 --> 17]
+ * } else {
+ * if(tCurr >= tFrom [3 >= 4] && tCurr < tTo [3 < 10])
+ * do work
+ * else
+ * sleep for tTo - tCurr "hours" [4 - 3 --> 1]
+ * }
+ *
+ * Bottom line: we need to check which type of window we have and need to adjust our
+ * logic accordingly. Of course, sleep calculations need to be done up to the minute,
+ * but you get the idea from the code above.
+ */
+static rsRetVal
+queueRateLimiter(queue_t *pThis)
+{
+ DEFiRet;
+ int iDelay;
+ int iHrCurr;
+ time_t tCurr;
+ struct tm m;
+
+ ISOBJ_TYPE_assert(pThis, queue);
+
+ dbgoprint((obj_t*) pThis, "entering rate limiter\n");
+
+ iDelay = 0;
+ if(pThis->iDeqtWinToHr != 25) { /* 25 means disabled */
+ /* time calls are expensive, so only do them when needed */
+ time(&tCurr);
+ localtime_r(&tCurr, &m);
+ iHrCurr = m.tm_hour;
+
+ if(pThis->iDeqtWinToHr < pThis->iDeqtWinFromHr) {
+ if(iHrCurr < pThis->iDeqtWinToHr || iHrCurr > pThis->iDeqtWinFromHr) {
+ ; /* do not delay */
+ } else {
+ iDelay = (pThis->iDeqtWinFromHr - iHrCurr) * 3600;
+ /* this time, we are already into the next hour, so we need
+ * to subtract our current minute and seconds.
+ */
+ iDelay -= m.tm_min * 60;
+ iDelay -= m.tm_sec;
+ }
+ } else {
+ if(iHrCurr >= pThis->iDeqtWinFromHr && iHrCurr < pThis->iDeqtWinToHr) {
+ ; /* do not delay */
+ } else {
+ if(iHrCurr < pThis->iDeqtWinFromHr) {
+ iDelay = (pThis->iDeqtWinFromHr - iHrCurr - 1) * 3600; /* -1 as we are already in the hour */
+ iDelay += (60 - m.tm_min) * 60;
+ iDelay += 60 - m.tm_sec;
+ } else {
+ iDelay = (24 - iHrCurr + pThis->iDeqtWinFromHr) * 3600;
+ /* this time, we are already into the next hour, so we need
+ * to subtract our current minute and seconds.
+ */
+ iDelay -= m.tm_min * 60;
+ iDelay -= m.tm_sec;
+ }
+ }
+ }
+ }
+
+ if(iDelay > 0) {
+ dbgoprint((obj_t*) pThis, "outside dequeue time window, delaying %d seconds\n", iDelay);
+ srSleep(iDelay, 0);
+ }
+
+ RETiRet;
+}
+
+
+
/* This is the queue consumer in the regular (non-DA) case. It is
* protected by the queue mutex, but MUST release it as soon as possible.
* rgerhards, 2008-01-21
@@ -1691,6 +1792,7 @@ rsRetVal queueStart(queue_t *pThis) /* this is the ConstructionFinalizer */
lenBuf = snprintf((char*)pszBuf, sizeof(pszBuf), "%s:Reg", obj.GetName((obj_t*) pThis));
CHKiRet(wtpConstruct (&pThis->pWtpReg));
CHKiRet(wtpSetDbgHdr (pThis->pWtpReg, pszBuf, lenBuf));
+ CHKiRet(wtpSetpfRateLimiter (pThis->pWtpReg, (rsRetVal (*)(void *pUsr)) queueRateLimiter));
CHKiRet(wtpSetpfChkStopWrkr (pThis->pWtpReg, (rsRetVal (*)(void *pUsr, int)) queueChkStopWrkrReg));
CHKiRet(wtpSetpfIsIdle (pThis->pWtpReg, (rsRetVal (*)(void *pUsr, int)) queueIsIdleReg));
CHKiRet(wtpSetpfDoWork (pThis->pWtpReg, (rsRetVal (*)(void *pUsr, void *pWti, int)) queueConsumerReg));
@@ -2152,6 +2254,8 @@ finalize_it:
/* some simple object access methods */
DEFpropSetMeth(queue, iPersistUpdCnt, int);
+DEFpropSetMeth(queue, iDeqtWinFromHr, int);
+DEFpropSetMeth(queue, iDeqtWinToHr, int);
DEFpropSetMeth(queue, toQShutdown, long);
DEFpropSetMeth(queue, toActShutdown, long);
DEFpropSetMeth(queue, toWrkShutdown, long);
@@ -2214,6 +2318,5 @@ BEGINObjClassInit(queue, 1, OBJ_IS_CORE_MODULE)
OBJSetMethodHandler(objMethod_SETPROPERTY, queueSetProperty);
ENDObjClassInit(queue)
-/*
- * vi:set ai:
+/* vi:set ai:
*/
diff --git a/queue.h b/queue.h
index e07d034b..9e75b31b 100644
--- a/queue.h
+++ b/queue.h
@@ -83,9 +83,20 @@ typedef struct queue_s {
int toActShutdown; /* timeout for long-running action shutdown in ms */
int toWrkShutdown; /* timeout for idle workers in ms, -1 means indefinite (0 is immediate) */
int toEnq; /* enqueue timeout */
- /* rate limiting settings (will be expanded */
+ /* rate limiting settings (will be expanded) */
int iDeqSlowdown; /* slow down dequeue by specified nbr of microseconds */
/* end rate limiting */
+ /* dequeue time window settings (may also be expanded) */
+ int iDeqtWinFromHr; /* begin of dequeue time window (hour only) */
+ int iDeqtWinToHr; /* end of dequeue time window (hour only), set to 25 to disable deq window! */
+ /* note that begin and end have specific semantics. It is a big difference if we have
+ * begin 4, end 22 or begin 22, end 4. In the later case, dequeuing will run from 10p,
+ * throughout the night and stop at 4 in the morning. In the first case, it will start
+ * at 4am, run throughout the day, and stop at 10 in the evening! So far, not logic is
+ * applied to detect user configuration errors (and tell me how should we detect what
+ * the user really wanted...). -- rgerhards, 2008-04-02
+ */
+ /* ane dequeue time window */
rsRetVal (*pConsumer)(void *,void*); /* user-supplied consumer function for dequeued messages */
/* calling interface for pConsumer: arg1 is the global user pointer from this structure, arg2 is the
* user pointer that was dequeued (actual sample: for actions, arg1 is the pAction and arg2 is pointer
@@ -174,6 +185,8 @@ rsRetVal queueConstruct(queue_t **ppThis, queueType_t qType, int iWorkerThreads,
int iMaxQueueSize, rsRetVal (*pConsumer)(void*,void*));
PROTOTYPEObjClassInit(queue);
PROTOTYPEpropSetMeth(queue, iPersistUpdCnt, int);
+PROTOTYPEpropSetMeth(queue, iDeqtWinFromHr, int);
+PROTOTYPEpropSetMeth(queue, iDeqtWinToHr, int);
PROTOTYPEpropSetMeth(queue, toQShutdown, long);
PROTOTYPEpropSetMeth(queue, toActShutdown, long);
PROTOTYPEpropSetMeth(queue, toWrkShutdown, long);
diff --git a/rsyslog.conf b/rsyslog.conf
index 2ff7d271..9a91823c 100644
--- a/rsyslog.conf
+++ b/rsyslog.conf
@@ -41,7 +41,7 @@ local7.* /var/log/boot.log
#$ActionQueueMaxDiskSpace 1g # 1gb space limit (use as much as possible)
#$ActionQueueSaveOnShutdown on # save messages to disk on shutdown
#$ActionQueueType LinkedList # run asynchronously
-#$ActionResumeRetryCount -1 # infinety retries if host is down
+#$ActionResumeRetryCount -1 # infinite retries if host is down
# remote host is: name/ip:port, e.g. 192.168.0.1:514, port optional
#*.* @@remote-host
diff --git a/rsyslog.conf.5 b/rsyslog.conf.5
index 4fa98ef2..1c47f535 100644
--- a/rsyslog.conf.5
+++ b/rsyslog.conf.5
@@ -17,7 +17,7 @@
.\" along with this program; if not, write to the Free Software
.\" Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
.\"
-.TH RSYSLOG.CONF 5 "07 April 2008" "Version 3.15.1" "Linux System Administration"
+.TH RSYSLOG.CONF 5 "07 April 2008" "Version 3.17.0" "Linux System Administration"
.SH NAME
rsyslog.conf \- rsyslogd(8) configuration file
.SH DESCRIPTION
diff --git a/rsyslog.h b/rsyslog.h
index a80d43db..c73c659c 100644
--- a/rsyslog.h
+++ b/rsyslog.h
@@ -167,6 +167,11 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth
RS_RET_MODULE_LOAD_ERR_DLOPEN = -2066, /**< module could not be loaded - problem in dlopen() */
RS_RET_MODULE_LOAD_ERR_NO_INIT = -2067, /**< module could not be loaded - init() missing */
RS_RET_MODULE_LOAD_ERR_INIT_FAILED = -2068, /**< module could not be loaded - init() failed */
+ RS_RET_NO_SOCKET = -2069, /**< socket could not be obtained or was not provided */
+ RS_RET_SMTP_ERROR = -2070, /**< error during SMTP transation */
+ RS_RET_MAIL_NO_TO = -2071, /**< recipient for mail destination is missing */
+ RS_RET_MAIL_NO_FROM = -2072, /**< sender for mail destination is missing */
+ RS_RET_INVALID_PRI = -2073, /**< PRI value is invalid */
/* RainerScript error messages (range 1000.. 1999) */
RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */
diff --git a/rsyslogd.8 b/rsyslogd.8
index 0125d589..2aa911d9 100644
--- a/rsyslogd.8
+++ b/rsyslogd.8
@@ -1,7 +1,7 @@
.\" Copyright 2004-2008 Rainer Gerhards and Adiscon for the rsyslog modifications
.\" May be distributed under the GNU General Public License
.\"
-.TH RSYSLOGD 8 "02 April 2008" "Version 3.14.0" "Linux System Administration"
+.TH RSYSLOGD 8 "07 April 2008" "Version 3.17.0" "Linux System Administration"
.SH NAME
rsyslogd \- reliable and extended syslogd
.SH SYNOPSIS
diff --git a/stringbuf.h b/stringbuf.h
index 0d617699..e44e86e1 100644
--- a/stringbuf.h
+++ b/stringbuf.h
@@ -121,6 +121,7 @@ void rsCStrSetAllocIncrement(cstr_t *pThis, int iNewIncrement);
rsRetVal rsCStrAppendInt(cstr_t *pThis, long i);
+rsRetVal strExit(void); /* TODO: remove once we have a real object interface! */
uchar* rsCStrGetSzStr(cstr_t *pThis);
uchar* rsCStrGetSzStrNoNULL(cstr_t *pThis);
rsRetVal rsCStrSetSzStr(cstr_t *pThis, uchar *pszNew);
diff --git a/syslogd.c b/syslogd.c
index 26dd35ca..bf4f5e67 100644
--- a/syslogd.c
+++ b/syslogd.c
@@ -216,7 +216,7 @@ static rsRetVal GlobalClassExit(void);
#if defined(SYSLOGD_PIDNAME)
# undef _PATH_LOGPID
# if defined(FSSTND)
-# ifdef BSD
+# ifdef OS_BSD
# define _PATH_VARRUN "/var/run/"
# endif
# if defined(__sun) || defined(__hpux)
@@ -301,10 +301,12 @@ static uchar cCCEscapeChar = '\\';/* character to be used to start an escape seq
static int bEscapeCCOnRcv = 1; /* escape control characters on reception: 0 - no, 1 - yes */
int bReduceRepeatMsgs; /* reduce repeated message - 0 - no, 1 - yes */
int bActExecWhenPrevSusp; /* execute action only when previous one was suspended? */
+int iActExecOnceInterval = 0; /* execute action once every nn seconds */
uchar *pszWorkDir = NULL;/* name of rsyslog's spool directory (without trailing slash) */
+uchar *glblModPath = NULL; /* module load path - only used during initial init, only settable via -M command line option */
/* end global config file state variables */
-char LocalHostName[MAXHOSTNAMELEN+1];/* our hostname - read-only after startup */
+uchar *LocalHostName;/* our hostname - read-only after startup */
char *LocalDomain; /* our local domain name - read-only after startup */
int MarkInterval = 20 * 60; /* interval between marks in seconds - read-only after startup */
int family = PF_UNSPEC; /* protocol family (IPv4, IPv6 or both), set via cmdline */
@@ -338,8 +340,10 @@ static int iMainMsgQtoEnq = 2000; /* timeout for queue enque */
static int iMainMsgQtoWrkShutdown = 60000; /* timeout for worker thread shutdown */
static int iMainMsgQWrkMinMsgs = 100; /* minimum messages per worker needed to start a new one */
static int iMainMsgQDeqSlowdown = 0; /* dequeue slowdown (simple rate limiting) */
-static int bMainMsgQSaveOnShutdown = 1; /* save queue on shutdown (when DA enabled)? */
static int64 iMainMsgQueMaxDiskSpace = 0; /* max disk space allocated 0 ==> unlimited */
+static int bMainMsgQSaveOnShutdown = 1; /* save queue on shutdown (when DA enabled)? */
+static int iMainMsgQueueDeqtWinFromHr = 0; /* hour begin of time frame when queue is to be dequeued */
+static int iMainMsgQueueDeqtWinToHr = 25; /* hour begin of time frame when queue is to be dequeued */
/* support for simple textual representation of FIOP names
@@ -376,6 +380,7 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a
{
cCCEscapeChar = '#';
bActExecWhenPrevSusp = 0;
+ iActExecOnceInterval = 0;
bDebugPrintTemplateList = 1;
bDebugPrintCfSysLineHandlerList = 1;
bDebugPrintModuleList = 1;
@@ -892,8 +897,8 @@ logmsgInternal(int pri, char *msg, int flags)
CHKiRet(msgConstruct(&pMsg));
MsgSetUxTradMsg(pMsg, msg);
MsgSetRawMsg(pMsg, msg);
- MsgSetHOSTNAME(pMsg, LocalHostName);
- MsgSetRcvFrom(pMsg, LocalHostName);
+ MsgSetHOSTNAME(pMsg, (char*)LocalHostName);
+ MsgSetRcvFrom(pMsg, (char*)LocalHostName);
MsgSetTAG(pMsg, "rsyslogd:");
pMsg->iFacility = LOG_FAC(pri);
pMsg->iSeverity = LOG_PRI(pri);
@@ -1385,11 +1390,18 @@ static int parseLegacySyslogMsg(msg_t *pMsg, int flags)
/* Check to see if msg contains a timestamp. We stary trying with a
* high-precision one...
*/
- if(datetime.ParseTIMESTAMP3339(&(pMsg->tTIMESTAMP), &p2parse) == TRUE)
+ if(datetime.ParseTIMESTAMP3339(&(pMsg->tTIMESTAMP), &p2parse) == TRUE) {
/* we are done - parse pointer is moved by ParseTIMESTAMP3339 */;
- else if(datetime.ParseTIMESTAMP3164(&(pMsg->tTIMESTAMP), p2parse) == TRUE)
+ } else if(datetime.ParseTIMESTAMP3164(&(pMsg->tTIMESTAMP), p2parse) == TRUE) {
p2parse += 16;
- else {
+ } else if(*p2parse == ' ') { /* try to see if it is slighly malformed - HP procurve seems to do that sometimes */
+ if(datetime.ParseTIMESTAMP3164(&(pMsg->tTIMESTAMP), p2parse+1) == TRUE) {
+ /* indeed, we got it! */
+ p2parse += 17;
+ } else {
+ flags |= ADDDATE;
+ }
+ } else {
flags |= ADDDATE;
}
@@ -1858,6 +1870,8 @@ freeAllDynMemForTermination(void)
free(pszMainMsgQFName);
if(pModDir != NULL)
free(pModDir);
+ if(LocalHostName != NULL)
+ free(LocalHostName);
}
@@ -2197,8 +2211,7 @@ init(void)
pDfltProgNameCmp = NULL;
eDfltHostnameCmpMode = HN_NO_COMP;
- dbgprintf("rsyslog %s.\n", VERSION);
- dbgprintf("Called init.\n");
+ dbgprintf("rsyslog %s - called init()\n", VERSION);
/* delete the message queue, which also flushes all messages left over */
if(pMsgQueue != NULL) {
@@ -2321,6 +2334,8 @@ init(void)
setQPROP(queueSetiMinMsgsPerWrkr, "$MainMsgQueueWorkerThreadMinimumMessages", iMainMsgQWrkMinMsgs);
setQPROP(queueSetbSaveOnShutdown, "$MainMsgQueueSaveOnShutdown", bMainMsgQSaveOnShutdown);
setQPROP(queueSetiDeqSlowdown, "$MainMsgQueueDequeueSlowdown", iMainMsgQDeqSlowdown);
+ setQPROP(queueSetiDeqtWinFromHr, "$MainMsgQueueDequeueTimeBegin", iMainMsgQueueDeqtWinFromHr);
+ setQPROP(queueSetiDeqtWinToHr, "$MainMsgQueueDequeueTimeEnd", iMainMsgQueueDeqtWinToHr);
# undef setQPROP
# undef setQPROPstr
@@ -2685,8 +2700,11 @@ static rsRetVal loadBuildInModules(void)
CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuemaxfilesize", 0, eCmdHdlrSize, NULL, &iMainMsgQueMaxFileSize, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuemaxdiskspace", 0, eCmdHdlrSize, NULL, &iMainMsgQueMaxDiskSpace, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuesaveonshutdown", 0, eCmdHdlrBinary, NULL, &bMainMsgQSaveOnShutdown, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuedequeuetimebegin", 0, eCmdHdlrInt, NULL, &iMainMsgQueueDeqtWinFromHr, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuedequeuetimeend", 0, eCmdHdlrInt, NULL, &iMainMsgQueueDeqtWinToHr, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"repeatedmsgreduction", 0, eCmdHdlrBinary, NULL, &bReduceRepeatMsgs, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"actionexeconlywhenpreviousissuspended", 0, eCmdHdlrBinary, NULL, &bActExecWhenPrevSusp, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionexeconlyonceeveryinterval", 0, eCmdHdlrInt, NULL, &iActExecOnceInterval, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"actionresumeinterval", 0, eCmdHdlrInt, setActionResumeInterval, NULL, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"controlcharacterescapeprefix", 0, eCmdHdlrGetChar, NULL, &cCCEscapeChar, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"escapecontrolcharactersonreceive", 0, eCmdHdlrBinary, NULL, &bEscapeCCOnRcv, NULL));
@@ -2764,21 +2782,6 @@ static void mainThread()
BEGINfunc
uchar *pTmp;
-#if 0 // code moved back to main()
- /* doing some core initializations */
- if((iRet = modInitIminternal()) != RS_RET_OK) {
- fprintf(stderr, "fatal error: could not initialize errbuf object (error code %d).\n",
- iRet);
- exit(1); /* "good" exit, leaving at init for fatal error */
- }
-
- if((iRet = loadBuildInModules()) != RS_RET_OK) {
- fprintf(stderr, "fatal error: could not activate built-in modules. Error code %d.\n",
- iRet);
- exit(1); /* "good" exit, leaving at init for fatal error */
- }
-#endif
-
/* 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
*/
@@ -2803,7 +2806,6 @@ static void mainThread()
pTmp = template_StdPgSQLFmt;
tplLastStaticInit(tplAddLine(" StdPgSQLFmt", &pTmp));
- dbgprintf("Starting.\n");
init();
if(Debug) {
dbgprintf("Debugging enabled, SIGUSR1 to turn off debugging.\n");
@@ -2820,6 +2822,7 @@ static void mainThread()
* do the init() and then restart things.
* rgerhards, 2005-10-24
*/
+ dbgprintf("initialization completed, transitioning to regular run mode\n");
mainloop();
ENDfunc
@@ -2971,6 +2974,72 @@ GlobalClassExit(void)
}
+/* some support for command line option parsing. Any non-trivial options must be
+ * buffered until the complete command line has been parsed. This is necessary to
+ * prevent dependencies between the options. That, in turn, means we need to have
+ * something that is capable of buffering options and there values. The follwing
+ * functions handle that.
+ * rgerhards, 2008-04-04
+ */
+typedef struct bufOpt {
+ struct bufOpt *pNext;
+ char optchar;
+ char *arg;
+} bufOpt_t;
+static bufOpt_t *bufOptRoot = NULL;
+static bufOpt_t *bufOptLast = NULL;
+
+/* add option buffer */
+static rsRetVal
+bufOptAdd(char opt, char *arg)
+{
+ DEFiRet;
+ bufOpt_t *pBuf;
+
+ if((pBuf = malloc(sizeof(bufOpt_t))) == NULL)
+ ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
+
+ pBuf->optchar = opt;
+ pBuf->arg = arg;
+ pBuf->pNext = NULL;
+
+ if(bufOptLast == NULL) {
+ bufOptRoot = pBuf; /* then there is also no root! */
+ } else {
+ bufOptLast->pNext = pBuf;
+ }
+ bufOptLast = pBuf;
+
+finalize_it:
+ RETiRet;
+}
+
+
+
+/* remove option buffer from top of list, return values and destruct buffer itself.
+ * returns RS_RET_END_OF_LINKEDLIST when no more options are present.
+ * (we use int *opt instead of char *opt to keep consistent with getopt())
+ */
+static rsRetVal
+bufOptRemove(int *opt, char **arg)
+{
+ DEFiRet;
+ bufOpt_t *pBuf;
+
+ if(bufOptRoot == NULL)
+ ABORT_FINALIZE(RS_RET_END_OF_LINKEDLIST);
+ pBuf = bufOptRoot;
+
+ *opt = pBuf->optchar;
+ *arg = pBuf->arg;
+
+ bufOptRoot = pBuf->pNext;
+ free(pBuf);
+
+finalize_it:
+ RETiRet;
+}
+
/* This is the main entry point into rsyslogd. Over time, we should try to
* modularize it a bit more...
@@ -2990,15 +3059,125 @@ int realMain(int argc, char **argv)
int bIsFirstOption = 1;
int bEOptionWasGiven = 0;
int bImUxSockLoaded = 0; /* already generated a $ModLoad imuxsock? */
+ char *arg; /* for command line option processing */
uchar legacyConfLine[80];
- gethostname(LocalHostName, sizeof(LocalHostName));
- if ( (p = strchr(LocalHostName, '.')) ) {
+ /* 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
+ * the parameters down below in the correct order. For example, we must know the
+ * value of -M before we can do the init, but at the same time we need to have
+ * the base classes init before we can process most of the options. Now, with the
+ * split of functionality, this is no longer a problem. Thanks to varmofekoj for
+ * suggesting this algo.
+ * Note: where we just need to set some flags and can do so without knowledge
+ * of other options, we do this during the inital option processing. With later
+ * versions (if a dependency on -c option is introduced), we must move that code
+ * to other places, but I think it is quite appropriate and saves code to do this
+ * only when actually neeeded.
+ * rgerhards, 2008-04-04
+ */
+ while ((ch = getopt(argc, argv, "46aAc:def:g:hi:l:m:M:nopqQr::s:t:u:vwx")) != EOF) {
+ switch((char)ch) {
+ case '4':
+ case '6':
+ case 'A':
+ case 'a':
+ case 'f': /* configuration file */
+ case 'h':
+ case 'i': /* pid file name */
+ case 'l':
+ case 'm': /* mark interval */
+ case 'n': /* don't fork */
+ case 'o':
+ case 'p':
+ case 'q': /* add hostname if DNS resolving has failed */
+ case 'Q': /* dont resolve hostnames in ACL to IPs */
+ case 's':
+ case 'u': /* misc user settings */
+ case 'w': /* disable disallowed host warnigs */
+ case 'x': /* disable dns for remote messages */
+ CHKiRet(bufOptAdd(ch, optarg));
+ break;
+ case 'c': /* compatibility mode */
+ if(!bIsFirstOption) {
+ fprintf(stderr, "-c option MUST be specified as the first option - aborting...\n");
+ usage();
+ exit(1);
+ }
+ iCompatibilityMode = atoi(optarg);
+ break;
+ case 'd': /* debug - must be handled now, so that debug is active during init! */
+ Debug = 1;
+ break;
+ case 'e': /* log every message (no repeat message supression) */
+ fprintf(stderr, "note: -e option is no longer supported, every message is now logged by default\n");
+ bEOptionWasGiven = 1;
+ break;
+ case 'g': /* enable tcp gssapi logging */
+#if defined(SYSLOG_INET) && defined(USE_GSSAPI)
+ CHKiRet(bufOptAdd('g', optarg));
+#else
+ fprintf(stderr, "rsyslogd: -g not valid - not compiled with gssapi support");
+#endif
+ break;
+ case 'M': /* default module load path -- this MUST be carried out immediately! */
+ glblModPath = (uchar*) optarg;
+ break;
+ case 'r': /* accept remote messages */
+#ifdef SYSLOG_INET
+ CHKiRet(bufOptAdd(ch, optarg));
+#else
+ fprintf(stderr, "rsyslogd: -r not valid - not compiled with network support\n");
+#endif
+ break;
+ case 't': /* enable tcp logging */
+#ifdef SYSLOG_INET
+ CHKiRet(bufOptAdd(ch, optarg));
+#else
+ fprintf(stderr, "rsyslogd: -t not valid - not compiled with network support\n");
+#endif
+ break;
+ case 'v': /* MUST be carried out immediately! */
+ printVersion();
+ exit(0); /* exit for -v option - so this is a "good one" */
+ case '?':
+ default:
+ usage();
+ }
+ bIsFirstOption = 0; /* we already saw an option character */
+ }
+
+ if ((argc -= optind))
+ usage();
+
+ dbgprintf("rsyslogd %s startup, compatibility mode %d, module path '%s'\n",
+ VERSION, iCompatibilityMode, glblModPath == NULL ? "" : (char*)glblModPath);
+
+ /* we are done with the initial option parsing and processing. Now we init the system. */
+
+ ppid = getpid();
+
+ if(chdir ("/") != 0)
+ fprintf(stderr, "Can not do 'cd /' - still trying to run\n");
+
+ CHKiRet_Hdlr(InitGlobalClasses()) {
+ fprintf(stderr, "rsyslogd initializiation failed - global classes could not be initialized.\n"
+ "Did you do a \"make install\"?\n"
+ "Suggested action: run rsyslogd with -d -n options to see what exactly "
+ "fails.\n");
+ FINALIZE;
+ }
+
+ /* doing some core initializations */
+
+ /* get our host and domain names - we need to do this early as we may emit
+ * error log messages, which need the correct hostname. -- rgerhards, 2008-04-04
+ */
+ net.getLocalHostname(&LocalHostName);
+ if((p = strchr((char*)LocalHostName, '.'))) {
*p++ = '\0';
LocalDomain = p;
- }
- else
- {
+ } else {
LocalDomain = "";
/* It's not clearly defined whether gethostname()
@@ -3014,11 +3193,12 @@ int realMain(int argc, char **argv)
/* TODO: gethostbyname() is not thread-safe, but replacing it is
* not urgent as we do not run on multiple threads here. rgerhards, 2007-09-25
*/
- hent = gethostbyname(LocalHostName);
+ hent = gethostbyname((char*)LocalHostName);
if(hent) {
- snprintf(LocalHostName, sizeof(LocalHostName), "%s", hent->h_name);
+ free(LocalHostName);
+ CHKmalloc(LocalHostName = (uchar*)strdup(hent->h_name));
- if ( (p = strchr(LocalHostName, '.')) )
+ if((p = strchr((char*)LocalHostName, '.')))
{
*p++ = '\0';
LocalDomain = p;
@@ -3026,21 +3206,11 @@ int realMain(int argc, char **argv)
}
}
- /* Convert to lower case to recognize the correct domain laterly
- */
- for (p = (char *)LocalDomain; *p ; p++)
- if (isupper((int) *p))
- *p = (char)tolower((int)*p);
+ /* Convert to lower case to recognize the correct domain laterly */
+ for (p = (char *)LocalDomain ; *p ; p++)
+ *p = (char)tolower((int)*p);
- CHKiRet_Hdlr(InitGlobalClasses()) {
- fprintf(stderr, "rsyslogd initializiation failed - global classes could not be initialized.\n"
- "Did you do a \"make install\"?\n"
- "Suggested action: run rsyslogd with -d -n options to see what exactly "
- "fails.\n");
- FINALIZE;
- }
-
- /* doing some core initializations */
+ /* initialize the objects */
if((iRet = modInitIminternal()) != RS_RET_OK) {
fprintf(stderr, "fatal error: could not initialize errbuf object (error code %d).\n",
iRet);
@@ -3053,14 +3223,10 @@ int realMain(int argc, char **argv)
exit(1); /* "good" exit, leaving at init for fatal error */
}
- ppid = getpid();
-
- if(chdir ("/") != 0)
- fprintf(stderr, "Can not do 'cd /' - still trying to run\n");
-
- /* END core initializations */
+ /* END core initializations - we now come back to carrying out command line options*/
- while ((ch = getopt(argc, argv, "46aAc:def:g:hi:l:m:M:nopqQr::s:t:u:vwx")) != EOF) {
+ while((iRet = bufOptRemove(&ch, &arg)) == RS_RET_OK) {
+ dbgprintf("deque option %c, optarg '%s'\n", ch, arg);
switch((char)ch) {
case '4':
family = PF_INET;
@@ -3077,39 +3243,20 @@ int realMain(int argc, char **argv)
legacyOptsEnq((uchar *) "ModLoad imuxsock");
bImUxSockLoaded = 1;
}
- snprintf((char *) legacyConfLine, sizeof(legacyConfLine), "addunixlistensocket %s", optarg);
+ snprintf((char *) legacyConfLine, sizeof(legacyConfLine), "addunixlistensocket %s", arg);
legacyOptsEnq(legacyConfLine);
} else {
fprintf(stderr, "error -a is no longer supported, use module imuxsock instead");
}
break;
- case 'c': /* compatibility mode */
- if(!bIsFirstOption) {
- fprintf(stderr, "-c option MUST be specified as the first option - aborting...\n");
- usage();
- exit(1);
- }
- iCompatibilityMode = atoi(optarg);
- break;
- case 'd': /* debug */
- Debug = 1;
- break;
- case 'e': /* log every message (no repeat message supression) */
- fprintf(stderr, "note: -e option is no longer supported, every message is now logged by default\n");
- bEOptionWasGiven = 1;
- break;
case 'f': /* configuration file */
- ConfFile = (uchar*) optarg;
+ ConfFile = (uchar*) arg;
break;
case 'g': /* enable tcp gssapi logging */
-#if defined(SYSLOG_INET) && defined(USE_GSSAPI)
if(iCompatibilityMode < 3) {
- legacyOptsParseTCP(ch, optarg);
+ legacyOptsParseTCP(ch, arg);
} else
fprintf(stderr, "-g option only supported in compatibility modes 0 to 2 - ignored\n");
-#else
- fprintf(stderr, "rsyslogd: -g not valid - not compiled with gssapi support");
-#endif
break;
case 'h':
if(iCompatibilityMode < 3) {
@@ -3119,25 +3266,22 @@ int realMain(int argc, char **argv)
}
break;
case 'i': /* pid file name */
- PidFile = optarg;
+ PidFile = arg;
break;
case 'l':
if (LocalHosts) {
fprintf (stderr, "rsyslogd: Only one -l argument allowed, the first one is taken.\n");
} else {
- LocalHosts = crunch_list(optarg);
+ LocalHosts = crunch_list(arg);
}
break;
case 'm': /* mark interval */
if(iCompatibilityMode < 3) {
- MarkInterval = atoi(optarg) * 60;
+ MarkInterval = atoi(arg) * 60;
} else
fprintf(stderr,
"-m option only supported in compatibility modes 0 to 2 - ignored\n");
break;
- case 'M': /* default module load path */
- module.SetModDir((uchar*)optarg);
- break;
case 'n': /* don't fork */
NoFork = 1;
break;
@@ -3158,7 +3302,7 @@ int realMain(int argc, char **argv)
legacyOptsEnq((uchar *) "ModLoad imuxsock");
bImUxSockLoaded = 1;
}
- snprintf((char *) legacyConfLine, sizeof(legacyConfLine), "SystemLogSocketName %s", optarg);
+ snprintf((char *) legacyConfLine, sizeof(legacyConfLine), "SystemLogSocketName %s", arg);
legacyOptsEnq(legacyConfLine);
} else {
fprintf(stderr, "error -p is no longer supported, use module imuxsock instead");
@@ -3170,42 +3314,30 @@ int realMain(int argc, char **argv)
*net.pACLDontResolve = 1;
break;
case 'r': /* accept remote messages */
-#ifdef SYSLOG_INET
if(iCompatibilityMode < 3) {
legacyOptsEnq((uchar *) "ModLoad imudp");
- snprintf((char *) legacyConfLine, sizeof(legacyConfLine), "UDPServerRun %s", optarg);
+ snprintf((char *) legacyConfLine, sizeof(legacyConfLine), "UDPServerRun %s", arg);
legacyOptsEnq(legacyConfLine);
} else
- fprintf(stderr,
- "-r option only supported in compatibility modes 0 to 2 - ignored\n");
-#else
- fprintf(stderr, "rsyslogd: -r not valid - not compiled with network support\n");
-#endif
+ fprintf(stderr, "-r option only supported in compatibility modes 0 to 2 - ignored\n");
break;
case 's':
if (StripDomains) {
fprintf (stderr, "rsyslogd: Only one -s argument allowed, the first one is taken.\n");
} else {
- StripDomains = crunch_list(optarg);
+ StripDomains = crunch_list(arg);
}
break;
case 't': /* enable tcp logging */
-#ifdef SYSLOG_INET
if(iCompatibilityMode < 3) {
- legacyOptsParseTCP(ch, optarg);
+ legacyOptsParseTCP(ch, arg);
} else
fprintf(stderr, "-t option only supported in compatibility modes 0 to 2 - ignored\n");
-#else
- fprintf(stderr, "rsyslogd: -t not valid - not compiled with network support\n");
-#endif
break;
case 'u': /* misc user settings */
- if(atoi(optarg) == 1)
+ if(atoi(arg) == 1)
bParseHOSTNAMEandTAG = 0;
break;
- case 'v':
- printVersion();
- exit(0); /* exit for -v option - so this is a "good one" */
case 'w': /* disable disallowed host warnigs */
option_DisallowWarning = 0;
break;
@@ -3216,15 +3348,12 @@ int realMain(int argc, char **argv)
default:
usage();
}
- bIsFirstOption = 0; /* we already saw an option character */
}
- if ((argc -= optind))
- usage();
+ if(iRet != RS_RET_END_OF_LINKEDLIST)
+ FINALIZE;
- /* TODO: this should go away at a reasonable stage of v3 development.
- * rgerhards, 2007-12-19
- */
+ /* process compatibility mode settings */
if(iCompatibilityMode < 3) {
errmsg.LogError(NO_ERRCODE, "WARNING: rsyslogd is running in compatibility mode. Automatically "
"generated config directives may interfer with your rsyslog.conf settings. "
@@ -3250,7 +3379,7 @@ int realMain(int argc, char **argv)
checkPermissions();
thrdInit();
- if ( !(Debug || NoFork) )
+ if( !(Debug || NoFork) )
{
dbgprintf("Checking pidfile.\n");
if (!check_pid(PidFile))
@@ -3289,8 +3418,6 @@ int realMain(int argc, char **argv)
else
debugging_on = 1;
- dbgprintf("Compatibility Mode: %d\n", iCompatibilityMode);
-
/* tuck my process id away */
dbgprintf("Writing pidfile %s.\n", PidFile);
if (!check_pid(PidFile))
diff --git a/syslogd.h b/syslogd.h
index 4eefd325..46de8d28 100644
--- a/syslogd.h
+++ b/syslogd.h
@@ -134,7 +134,7 @@ rsRetVal logmsgInternal(int pri, char *msg, int flags);
void logmsg(msg_t *pMsg, int flags);
rsRetVal submitMsg(msg_t *pMsg);
extern int glblHadMemShortage; /* indicates if we had memory shortage some time during the run */
-extern char LocalHostName[];
+extern uchar *LocalHostName;
extern int family;
extern int NoHops;
extern int send_to_all;
@@ -149,6 +149,7 @@ extern char ctty[];
extern int MarkInterval;
extern int bReduceRepeatMsgs;
extern int bActExecWhenPrevSusp;
+extern int iActExecOnceInterval;
/* Intervals at which we flush out "message repeated" messages,
* in seconds after previous message is logged. After each flush,
diff --git a/tcpsrv.c b/tcpsrv.c
index adbe26e0..955fb9b5 100644
--- a/tcpsrv.c
+++ b/tcpsrv.c
@@ -141,32 +141,6 @@ configureTCPListen(tcpsrv_t *pThis, char *cOptarg)
}
-#if 0 // I think this is no longer needed
-static void
-configureTCPListenSessMax(char *cOptarg)
-{
- register int i;
- register char *pArg = cOptarg;
-
- assert(cOptarg != NULL);
-
- /* number of sessions */
- i = 0;
- while(isdigit((int) *pArg)) {
- i = i * 10 + *pArg++ - '0';
- }
-
- if(i > 0)
- pThis->iSessMax = i;
- else {
- /* too small, need to adjust */
- errmsg.LogError(NO_ERRCODE, "TCP session max configured to %s - changing to 1.\n", cOptarg);
- pThis->iSessMax = 1;
- }
-}
-#endif
-
-
/* Initialize the session table
* returns 0 if OK, somewhat else otherwise
*/
@@ -353,7 +327,7 @@ static int *create_tcp_socket(tcpsrv_t *pThis)
/* We need to enable BSD compatibility. Otherwise an attacker
* could flood our log files by sending us tons of ICMP errors.
*/
-#ifndef BSD
+#ifndef OS_BSD
if(net.should_use_so_bsdcompat()) {
if (setsockopt(*s, SOL_SOCKET, SO_BSDCOMPAT,
(char *) &on, sizeof(on)) < 0) {
diff --git a/template.c b/template.c
index 75c9ce78..844c5aec 100644
--- a/template.c
+++ b/template.c
@@ -188,11 +188,13 @@ static void doSQLEmergencyEscape(register uchar *p, int escapeMode)
* new parameter escapeMode is 0 - standard sql, 1 - "smart" engines
* 2005-09-22 rgerhards
*/
-void doSQLEscape(uchar **pp, size_t *pLen, unsigned short *pbMustBeFreed, int escapeMode)
+rsRetVal
+doSQLEscape(uchar **pp, size_t *pLen, unsigned short *pbMustBeFreed, int escapeMode)
{
+ DEFiRet;
uchar *p;
int iLen;
- cstr_t *pStrB;
+ cstr_t *pStrB = NULL;
uchar *pszGenerated;
assert(pp != NULL);
@@ -210,44 +212,25 @@ void doSQLEscape(uchar **pp, size_t *pLen, unsigned short *pbMustBeFreed, int es
/* when we get out of the loop, we are either at the
* string terminator or the first \'. */
if(*p == '\0')
- return; /* nothing to do in this case! */
+ FINALIZE; /* nothing to do in this case! */
p = *pp;
iLen = *pLen;
- if(rsCStrConstruct(&pStrB) != RS_RET_OK) {
- /* oops - no mem ... Do emergency... */
- doSQLEmergencyEscape(p, escapeMode);
- return;
- }
+ CHKiRet(rsCStrConstruct(&pStrB));
while(*p) {
if(*p == '\'') {
- if(rsCStrAppendChar(pStrB, (escapeMode == 0) ? '\'' : '\\') != RS_RET_OK) {
- doSQLEmergencyEscape(*pp, escapeMode);
- rsCStrDestruct(&pStrB);
- return;
- }
+ CHKiRet(rsCStrAppendChar(pStrB, (escapeMode == 0) ? '\'' : '\\'));
iLen++; /* reflect the extra character */
} else if((escapeMode == 1) && (*p == '\\')) {
- if(rsCStrAppendChar(pStrB, '\\') != RS_RET_OK) {
- doSQLEmergencyEscape(*pp, escapeMode);
- rsCStrDestruct(&pStrB);
- return;
- }
+ CHKiRet(rsCStrAppendChar(pStrB, '\\'));
iLen++; /* reflect the extra character */
}
- if(rsCStrAppendChar(pStrB, *p) != RS_RET_OK) {
- doSQLEmergencyEscape(*pp, escapeMode);
- rsCStrDestruct(&pStrB);
- return;
- }
+ CHKiRet(rsCStrAppendChar(pStrB, *p));
++p;
}
- rsCStrFinish(pStrB);
- if(rsCStrConvSzStrAndDestruct(pStrB, &pszGenerated, 0) != RS_RET_OK) {
- doSQLEmergencyEscape(*pp, escapeMode);
- return;
- }
+ CHKiRet(rsCStrFinish(pStrB));
+ CHKiRet(rsCStrConvSzStrAndDestruct(pStrB, &pszGenerated, 0));
if(*pbMustBeFreed)
free(*pp); /* discard previous value */
@@ -255,6 +238,15 @@ void doSQLEscape(uchar **pp, size_t *pLen, unsigned short *pbMustBeFreed, int es
*pp = pszGenerated;
*pLen = iLen;
*pbMustBeFreed = 1;
+
+finalize_it:
+ if(iRet != RS_RET_OK) {
+ doSQLEmergencyEscape(*pp, escapeMode);
+ if(pStrB != NULL)
+ rsCStrDestruct(&pStrB);
+ }
+
+ RETiRet;
}
@@ -385,7 +377,6 @@ static int do_Constant(unsigned char **pp, struct template *pTpl)
if((pTpe = tpeConstruct(pTpl)) == NULL) {
/* OK, we are out of luck. Let's invalidate the
* entry and that's it.
- * TODO: add panic message once we have a mechanism for this
*/
pTpe->eEntryType = UNDEFINED;
return 1;
@@ -510,7 +501,8 @@ static int do_Parameter(unsigned char **pp, struct template *pTpl)
pTpe->eEntryType = FIELD;
while(*p && *p != '%' && *p != ':') {
- rsCStrAppendChar(pStrB, *p++);
+ rsCStrAppendChar(pStrB, tolower(*p));
+ ++p; /* do NOT do this in tolower()! */
}
/* got the name*/
diff --git a/template.h b/template.h
index 40ccfa50..5b0bcdb4 100644
--- a/template.h
+++ b/template.h
@@ -109,7 +109,7 @@ void tplLastStaticInit(struct template *tpl);
* rgerhards, 2007-08-06
*/
rsRetVal tplToString(struct template *pTpl, msg_t *pMsg, uchar** ppSz);
-void doSQLEscape(uchar **pp, size_t *pLen, unsigned short *pbMustBeFreed, int escapeMode);
+rsRetVal doSQLEscape(uchar **pp, size_t *pLen, unsigned short *pbMustBeFreed, int escapeMode);
rsRetVal templateInit();
diff --git a/wti.c b/wti.c
index 8afd250d..82cd2165 100644
--- a/wti.c
+++ b/wti.c
@@ -371,6 +371,14 @@ wtiWorker(wti_t *pThis)
pthread_yield(); /* see big comment in function header */
# endif
+ /* if we have a rate-limiter set for this worker pool, let's call it. Please
+ * keep in mind that the rate-limiter may hold us for an extended period
+ * of time. -- rgerhards, 2008-04-02
+ */
+ if(pWtp->pfRateLimiter != NULL) {
+ pWtp->pfRateLimiter(pWtp->pUsr);
+ }
+
wtpSetInactivityGuard(pThis->pWtp, 0, LOCK_MUTEX); /* must be set before usr mutex is locked! */
BEGIN_MTX_PROTECTED_OPERATIONS(pWtp->pmutUsr, LOCK_MUTEX);
diff --git a/wtp.c b/wtp.c
index d5126268..fcc7589c 100644
--- a/wtp.c
+++ b/wtp.c
@@ -546,6 +546,7 @@ DEFpropSetMeth(wtp, pUsr, void*);
DEFpropSetMethPTR(wtp, pmutUsr, pthread_mutex_t);
DEFpropSetMethPTR(wtp, pcondBusy, pthread_cond_t);
DEFpropSetMethFP(wtp, pfChkStopWrkr, rsRetVal(*pVal)(void*, int));
+DEFpropSetMethFP(wtp, pfRateLimiter, rsRetVal(*pVal)(void*));
DEFpropSetMethFP(wtp, pfIsIdle, rsRetVal(*pVal)(void*, int));
DEFpropSetMethFP(wtp, pfDoWork, rsRetVal(*pVal)(void*, void*, int));
DEFpropSetMethFP(wtp, pfOnIdle, rsRetVal(*pVal)(void*, int));
diff --git a/wtp.h b/wtp.h
index 33f4e244..13ebe536 100644
--- a/wtp.h
+++ b/wtp.h
@@ -69,6 +69,7 @@ typedef struct wtp_s {
pthread_mutex_t *pmutUsr;
pthread_cond_t *pcondBusy; /* condition the user will signal "busy again, keep runing" on (awakes worker) */
rsRetVal (*pfChkStopWrkr)(void *pUsr, int);
+ rsRetVal (*pfRateLimiter)(void *pUsr);
rsRetVal (*pfIsIdle)(void *pUsr, int);
rsRetVal (*pfDoWork)(void *pUsr, void *pWti, int);
rsRetVal (*pfOnIdle)(void *pUsr, int);
@@ -100,6 +101,7 @@ rsRetVal wtpShutdownAll(wtp_t *pThis, wtpState_t tShutdownCmd, struct timespec *
int wtpGetCurNumWrkr(wtp_t *pThis, int bLockMutex);
PROTOTYPEObjClassInit(wtp);
PROTOTYPEpropSetMethFP(wtp, pfChkStopWrkr, rsRetVal(*pVal)(void*, int));
+PROTOTYPEpropSetMethFP(wtp, pfRateLimiter, rsRetVal(*pVal)(void*));
PROTOTYPEpropSetMethFP(wtp, pfIsIdle, rsRetVal(*pVal)(void*, int));
PROTOTYPEpropSetMethFP(wtp, pfDoWork, rsRetVal(*pVal)(void*, void*, int));
PROTOTYPEpropSetMethFP(wtp, pfOnIdle, rsRetVal(*pVal)(void*, int));