summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--ChangeLog63
-rw-r--r--Makefile.am12
-rw-r--r--action.c41
-rw-r--r--action.h4
-rw-r--r--configure.ac39
-rw-r--r--doc/Makefile.am2
-rw-r--r--doc/features.html3
-rw-r--r--doc/free_support.html56
-rw-r--r--doc/imuxsock.html62
-rw-r--r--doc/manual.html22
-rw-r--r--doc/ommail.html23
-rw-r--r--doc/rsyslog_conf.html32
-rw-r--r--doc/rsyslog_ng_comparison.html12
-rw-r--r--doc/status.html20
-rw-r--r--doc/syslog_protocol.html (renamed from doc/syslog-protocol.html)0
-rw-r--r--doc/troubleshoot.html59
-rw-r--r--plugins/imdiag/Makefile.am6
-rw-r--r--plugins/imdiag/imdiag.c197
-rw-r--r--plugins/imuxsock/imuxsock.c63
-rw-r--r--plugins/ommail/ommail.c116
-rw-r--r--rsyslog.conf6
-rw-r--r--runtime/conf.c45
-rw-r--r--runtime/conf.h4
-rw-r--r--runtime/queue.c1
-rw-r--r--runtime/rsyslog.h3
-rw-r--r--runtime/var.c40
-rw-r--r--runtime/var.h1
-rw-r--r--runtime/vmop.c37
-rw-r--r--runtime/vmop.h2
-rw-r--r--runtime/vmprg.c39
-rw-r--r--runtime/vmprg.h3
-rw-r--r--tcpsrv.c3
-rw-r--r--tests/.gitignore2
-rw-r--r--tests/1.rstest26
-rw-r--r--tests/2.rstest10
-rw-r--r--tests/DevNull.cfgtest3
-rw-r--r--tests/Makefile.am27
-rw-r--r--tests/NoExistFile.cfgtest3
-rwxr-xr-xtests/cfg.sh139
-rw-r--r--tests/cfg1.cfgtest3
-rw-r--r--tests/cfg1.testin2
-rw-r--r--tests/cfg2.cfgtest3
-rw-r--r--tests/cfg2.testin1
-rw-r--r--tests/cfg3.cfgtest5
-rw-r--r--tests/cfg3.testin1
-rw-r--r--tests/cfg4.cfgtest1
-rw-r--r--tests/cfg4.testin67
-rw-r--r--tests/err1.rstest7
-rw-r--r--tests/rscript-parse.c100
-rw-r--r--tests/rscript.c259
-rw-r--r--tests/testbench.h3
-rw-r--r--tools/Makefile.am6
-rw-r--r--tools/gethostn.c47
-rw-r--r--tools/iminternal.c3
-rw-r--r--tools/omfwd.c5
-rw-r--r--tools/rsyslogd.833
-rw-r--r--tools/syslogd.c287
58 files changed, 1743 insertions, 317 deletions
diff --git a/.gitignore b/.gitignore
index bb5e1609..ea044fbe 100644
--- a/.gitignore
+++ b/.gitignore
@@ -34,3 +34,4 @@ tmp*
log
logfile
debug
+core.*
diff --git a/ChangeLog b/ChangeLog
index c23a18d9..d06154f3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,67 @@
---------------------------------------------------------------------------
+Version 3.21.4 [DEVEL] (rgerhards), 2008-0????
+- enhanced doc for $ActionExecOnlyEveryNthTimeTimeout
+---------------------------------------------------------------------------
+Version 3.21.3 [DEVEL] (rgerhards), 2008-08-13
+- added ability to specify flow control mode for imuxsock
+- added ability to execute actions only after the n-th call of the action
+ This also lead to the addition of two new config directives:
+ $ActionExecOnlyEveryNthTime and $ActionExecOnlyEveryNthTimeTimeout
+ This feature is useful, for example, for alerting: it permits you to
+ send an alert only after at least n occurences of a specific message
+ have been seen by rsyslogd. This protectes against false positives
+ due to waiting for additional confirmation.
+- bugfix: IPv6 addresses could not be specified in forwarding actions
+ New syntax @[addr]:port introduced to enable that. Root problem was IPv6
+ addresses contain colons.
+- somewhat enhanced debugging messages
+- imported from 3.18.3:
+ - enhanced ommysql to support custom port to connect to server
+ Port can be set via new $ActionOmmysqlServerPort config directive
+ Note: this was a very minor change and thus deemed appropriate to be
+ done in the stable release.
+ - bugfix: misspelled config directive, previously was
+ $MainMsgQueueWorkeTimeoutrThreadShutdown, is now
+ $MainMsgQueueWorkerTimeoutThreadShutdown. Note that the misspelled
+ directive is not preserved - if the misspelled directive was used
+ (which I consider highly unlikely), the config file must be changed.
+ Thanks to lperr for reporting the bug.
+---------------------------------------------------------------------------
+Version 3.21.2 [DEVEL] (rgerhards), 2008-08-04
+- added $InputUnixListenSocketHostName config directive, which permits to
+ override the hostname being used on a local unix socket. This is useful
+ for differentiating "hosts" running in several jails. Feature was
+ suggested by David Darville, thanks for the suggestion.
+- enhanced ommail to support multiple email recipients. This is done by
+ specifying $ActionMailTo multiple times. Note that this introduces a
+ small incompatibility to previous config file syntax: the recipient
+ list is now reset for each action (we honestly believe that will
+ not cause any problem - apologies if it does).
+- enhanced troubleshooting documentation
+---------------------------------------------------------------------------
+Version 3.21.1 [DEVEL] (rgerhards), 2008-07-30
+- bugfix: no error was reported if the target of a $IncludeConfig
+ could not be accessed.
+- added testbed for common config errors
+- added doc for -u option to rsyslogd man page
+- enhanced config file checking - no active actions are detected
+- added -N rsyslogd command line option for a config validation run
+ (which does not execute actual syslogd code and does not interfere
+ with a running instance)
+- somewhat improved emergency configuration. It is now also selected
+ if the config contains no active actions
+- rsyslogd error messages are now reported to stderr by default. can be
+ turned off by the new "$ErrorMessagesToStderr off" directive
+ Thanks to HKS for suggesting the new features.
+---------------------------------------------------------------------------
+Version 3.21.0 [DEVEL] (rgerhards), 2008-07-18
+- starts a new devel branch
+- added a generic test driver for RainerScript plus some test cases
+ to the testbench
+- added a small diagnostic tool to obtain result of gethostname() API
+- imported all changes from 3.18.1 until today (some quite important,
+ see below)
+---------------------------------------------------------------------------
Version 3.19.11 [BETA] (rgerhards), 2008-08-25
This is a refresh of the beta. No beta-specific fixes have been added.
- included fixes from v3-stable (most importantly 3.18.3)
diff --git a/Makefile.am b/Makefile.am
index e78a413c..a3a6e19b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -50,9 +50,7 @@ EXTRA_DIST = \
contrib/gnutls/cert.pem \
contrib/gnutls/key.pem
-SUBDIRS = doc runtime . tests
-
-SUBDIRS += plugins/immark plugins/imuxsock plugins/imtcp plugins/imudp plugins/omtesting
+SUBDIRS = doc runtime . plugins/immark plugins/imuxsock plugins/imtcp plugins/imudp plugins/omtesting
if ENABLE_RSYSLOGD
SUBDIRS += tools
@@ -94,6 +92,10 @@ if ENABLE_IMFILE
SUBDIRS += plugins/imfile
endif
+if ENABLE_IMDIAG
+SUBDIRS += plugins/imdiag
+endif
+
if ENABLE_MAIL
SUBDIRS += plugins/ommail
endif
@@ -101,3 +103,7 @@ endif
if ENABLE_RFC3195
SUBDIRS += plugins/im3195
endif
+
+# tests are added as last element, because tests may need different
+# modules that need to be generated first
+SUBDIRS += tests
diff --git a/action.c b/action.c
index f7219405..3a2584de 100644
--- a/action.c
+++ b/action.c
@@ -54,6 +54,8 @@ DEFobjCurrIf(datetime)
DEFobjCurrIf(module)
DEFobjCurrIf(errmsg)
+static int iActExecEveryNthOccur = 0; /* execute action every n-th occurence (0,1=always) */
+static time_t iActExecEveryNthOccurTO = 0; /* timeout for n-occurence setting (in seconds, 0=never) */
static int glbliActionResumeInterval = 30;
int glbliActionResumeRetryCount = 0; /* how often should suspended actions be retried? */
@@ -174,6 +176,7 @@ rsRetVal actionConstruct(action_t **ppThis)
pThis->iResumeInterval = glbliActionResumeInterval;
pThis->iResumeRetryCount = glbliActionResumeRetryCount;
+ pThis->tLastOccur = time(NULL);
pthread_mutex_init(&pThis->mutActExec, NULL);
SYNC_OBJ_TOOL_INIT(pThis);
@@ -510,7 +513,36 @@ actionWriteToAction(action_t *pAction)
DEFiRet;
pMsgSave = NULL; /* indicate message poiner not saved */
- /* first check if this is a regular message or the repeation of
+ time(&now); /* we need this for several use cases, but obtain it once for performance reasons */
+
+ /* first, we check if the action should actually be called. The action-specific
+ * $ActionExecOnlyEveryNthTime permits us to execute an action only every Nth
+ * time. So we need to check if we need to drop the (otherwise perfectly executable)
+ * action for this reason. Note that in case we need to drop it, we return RS_RET_OK
+ * as the action was properly "passed to execution" from the upper layer's point
+ * of view. -- rgerhards, 2008-08-07.
+ */
+dbgprintf("NTH: conf: %d, actual %d\n", pAction->iExecEveryNthOccur, pAction->iNbrNoExec);
+ if(pAction->iExecEveryNthOccur > 1) {
+ /* we need to care about multiple occurences */
+ if( pAction->iExecEveryNthOccurTO > 0
+ && (now - pAction->tLastOccur) > pAction->iExecEveryNthOccurTO) {
+ dbgprintf("n-th occurence handling timed out (%d sec), restarting from 0\n",
+ (int) (now - pAction->tLastOccur));
+ pAction->iNbrNoExec = 0;
+ pAction->tLastOccur = now;
+ }
+ if(pAction->iNbrNoExec < pAction->iExecEveryNthOccur - 1) {
+ ++pAction->iNbrNoExec;
+ dbgprintf("action %p passed %d times to execution - less than neded - discarding\n",
+ pAction, pAction->iNbrNoExec);
+ FINALIZE;
+ } else {
+ pAction->iNbrNoExec = 0; /* we execute the action now, so the number of no execs is down to */
+ }
+ }
+
+ /* then check if this is a regular message or the repeation of
* a previous message. If so, we need to change the message text
* to "last message repeated n times" and then go ahead and write
* it. Please note that we can not modify the message object, because
@@ -545,7 +577,6 @@ actionWriteToAction(action_t *pAction)
dbgprintf("Called action, logging to %s\n", module.GetStateName(pAction->pMod));
- 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
*/
@@ -706,6 +737,8 @@ actionAddCfSysLineHdrl(void)
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));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionexeconlyeverynthtime", 0, eCmdHdlrInt, NULL, &iActExecEveryNthOccur, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionexeconlyeverynthtimetimeout", 0, eCmdHdlrInt, NULL, &iActExecEveryNthOccurTO, NULL));
finalize_it:
RETiRet;
@@ -737,6 +770,10 @@ addAction(action_t **ppAction, modInfo_t *pMod, void *pModData, omodStringReques
pAction->pModData = pModData;
pAction->bExecWhenPrevSusp = bActExecWhenPrevSusp;
pAction->iSecsExecOnceInterval = iActExecOnceInterval;
+ pAction->iExecEveryNthOccur = iActExecEveryNthOccur;
+ pAction->iExecEveryNthOccurTO = iActExecEveryNthOccurTO;
+ iActExecEveryNthOccur = 0; /* auto-reset */
+ iActExecEveryNthOccurTO = 0; /* auto-reset */
/* check if we can obtain the template pointers - TODO: move to separate function? */
pAction->iNumTpls = OMSRgetEntryCount(pOMSR);
diff --git a/action.h b/action.h
index 99108aab..c910fc1c 100644
--- a/action.h
+++ b/action.h
@@ -49,6 +49,10 @@ struct action_s {
int iResumeInterval;/* resume interval for this action */
int iResumeRetryCount;/* how often shall we retry a suspended action? (-1 --> eternal) */
int iNbrResRtry; /* number of retries since last suspend */
+ int iNbrNoExec; /* number of matches that did not yet yield to an exec */
+ int iExecEveryNthOccur;/* execute this action only every n-th occurence (with n=0,1 -> always) */
+ int iExecEveryNthOccurTO;/* timeout for n-th occurence feature */
+ time_t tLastOccur; /* time last occurence was seen (for timing them out) */
struct modInfo_s *pMod;/* pointer to output module handling this selector */
void *pModData; /* pointer to module data - content is module-specific */
int f_ReduceRepeated;/* reduce repeated lines 0 - no, 1 - yes */
diff --git a/configure.ac b/configure.ac
index 13ef63d0..ac55ff62 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.19.11],[rsyslog@lists.adiscon.com])
+AC_INIT([rsyslog],[3.21.4],[rsyslog@lists.adiscon.com])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([ChangeLog])
AC_CONFIG_HEADERS([config.h])
@@ -331,6 +331,19 @@ if test "$enable_valgrind" = "yes"; then
fi
+# compile diagnostic tools (small helpers usually not needed)
+AC_ARG_ENABLE(diagtools,
+ [AS_HELP_STRING([--enable-diagtools],[Enable diagnostic tools @<:@default=no@:>@])],
+ [case "${enableval}" in
+ yes) enable_diagtools="yes" ;;
+ no) enable_diagtools="no" ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --enable-diagtools) ;;
+ esac],
+ [enable_diagtools=no]
+)
+AM_CONDITIONAL(ENABLE_DIAGTOOLS, test x$enable_diagtools = xyes)
+
+
# MySQL support
AC_ARG_ENABLE(mysql,
@@ -550,6 +563,23 @@ AC_ARG_ENABLE(mail,
AM_CONDITIONAL(ENABLE_MAIL, test x$enable_mail = xyes)
+# imdiag support (so far we do not need a library, but we need to turn this on and off)
+# note that we enable this be default, because an important point is to make
+# it available to users who do not know much about how to handle things. It
+# would complicate things if we first needed to tell them how to enable imdiag.
+# rgerhards, 2008-07-25
+AC_ARG_ENABLE(imdiag,
+ [AS_HELP_STRING([--enable-imdiag],[Enable imdiag @<:@default=yes@:>@])],
+ [case "${enableval}" in
+ yes) enable_imdiag="yes" ;;
+ no) enable_imdiag="no" ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --enable-imdiag) ;;
+ esac],
+ [enable_imdiag=no]
+)
+AM_CONDITIONAL(ENABLE_IMDIAG, test x$enable_imdiag = xyes)
+
+
# RELP support
AC_ARG_ENABLE(relp,
[AS_HELP_STRING([--enable-relp],[Enable RELP support @<:@default=no@:>@])],
@@ -628,7 +658,6 @@ AM_CONDITIONAL(ENABLE_IMTEMPLATE, test x$enable_imtemplate = xyes)
AC_CONFIG_FILES([Makefile \
runtime/Makefile \
tools/Makefile \
- tests/Makefile \
doc/Makefile \
plugins/imudp/Makefile \
plugins/imtcp/Makefile \
@@ -640,6 +669,7 @@ AC_CONFIG_FILES([Makefile \
plugins/imtemplate/Makefile \
plugins/imfile/Makefile \
plugins/imrelp/Makefile \
+ plugins/imdiag/Makefile \
plugins/omtesting/Makefile \
plugins/omgssapi/Makefile \
plugins/ommysql/Makefile \
@@ -647,7 +677,8 @@ AC_CONFIG_FILES([Makefile \
plugins/omrelp/Makefile \
plugins/omlibdbi/Makefile \
plugins/ommail/Makefile \
- plugins/omsnmp/Makefile])
+ plugins/omsnmp/Makefile \
+ tests/Makefile])
AC_OUTPUT
echo "****************************************************"
@@ -663,6 +694,7 @@ 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 "imdiag enabled: $enable_imdiag"
echo "file input module enabled: $enable_imfile"
echo "input template module will be compiled: $enable_imtemplate"
echo "Large file support enabled: $enable_largefile"
@@ -671,6 +703,7 @@ echo "GnuTLS network stream driver enabled: $enable_gnutls"
echo "Enable GSSAPI Kerberos 5 support: $want_gssapi_krb5"
echo "Debug mode enabled: $enable_debug"
echo "Runtime Instrumentation enabled: $enable_rtinst"
+echo "Diagnostic tools enabled: $enable_diagtools"
echo "valgrind support settings enabled: $enable_valgrind"
echo "rsyslog runtime will be built: $enable_rsyslogrt"
echo "rsyslogd will be built: $enable_rsyslogd"
diff --git a/doc/Makefile.am b/doc/Makefile.am
index de3675de..edf3bbb5 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -24,7 +24,7 @@ html_files = \
rsyslog_tls.html \
rsyslog_reliable_forwarding.html \
rsyslog_stunnel.html \
- syslog-protocol.html \
+ syslog_protocol.html \
version_naming.html \
contributors.html \
dev_queue.html \
diff --git a/doc/features.html b/doc/features.html
index 2b3b31d9..d221eb77 100644
--- a/doc/features.html
+++ b/doc/features.html
@@ -74,7 +74,7 @@ easy multi-host support</li>
<li> massively multi-threaded with dynamic work thread pools
that start up and shut themselves down on an as-needed basis (great for
high log volume on multicore machines)</li>
-<li>very experimental and volatile support for <a href="syslog-protocol.html">syslog-protocol</a>
+<li>very experimental and volatile support for <a href="syslog_protocol.html">syslog-protocol</a>
compliant messages (it is volatile because standardization is currently
underway and this is a proof-of-concept implementation to aid this
effort)</li>
@@ -94,6 +94,7 @@ loadable plug-in</li>
via custom plugins</li>
<li> an easy-to-write to plugin interface</li>
<li> ability to send SNMP trap messages</li>
+<li> ability to filter out messages based on sequence of arrival</li>
<li>support for arbitrary complex boolean, string and
arithmetic expressions in message filters</li>
</ul>
diff --git a/doc/free_support.html b/doc/free_support.html
new file mode 100644
index 00000000..182a82cd
--- /dev/null
+++ b/doc/free_support.html
@@ -0,0 +1,56 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head>
+<meta http-equiv="Content-Language" content="en">
+<title>Free Support for Rsyslog</title>
+
+</head>
+<body>
+<h1>Free Services for Rsyslog</h1>
+<p><i>A personal word from Rainer, the lead developer of rsyslog:</i>
+<p><b>The rsyslog community provides ample free support resources. Please see our
+<a href="troubleshoot.html">troubleshooting guide</a> to get started.</b></p>
+<p>Every now and then I receive private mail with support questions. I appreciate
+any feedback, but I must limit my resources so that I can help driver a great logging
+system forward.
+<p>To do so, I have decided not to reply to unsolicited support emails, at least not
+with a solution (but rather a link to this page ;)). I hope this does not offend you. The
+reason is quite simple: If I do personal support, you gain some advantage without
+contributing something back. Think about it: if you ask your question on the public
+forum or mailing list, other with the same problem can you and, most importantly, even
+years later find your post (and the answer) and get the problem solved. So by
+solving your issue in public, you help create a great community ressource and also
+help your fellow users finding solutions quicker. In the long term, this
+also contributes to improved code because the more questions users can find
+solutions to themselves, the fewer I need to look at.
+<p>But it comes even better: the rsyslog community is much broader than Rainer ;) - there
+are helpful other members hanging around at the public places. They often answer
+questions, so that I do not need to look at them (btw, once again a big "thank you", folks!).
+And, more important, those folks have different background than me. So they often
+either know better how to solve your problem (e.g. because it is distro-specific)
+or they know how to better phrase it (after all, I like abstract terms and concepts ;)).
+So you do yourself a favor if you use the public places.
+<p>An excellent place to go to is the
+<a href="http://kb.monitorware.com/rsyslog-f40.html">rsyslog forum</a> inside the
+knowledge base (which in itself is a great place to visit!). For those used to
+mailing lists, the
+<a href="http://lists.adiscon.net/mailman/listinfo/rsyslog">rsyslog mailing list</a>
+also offers excellent advise.
+<p><b>Don't like to post your question in a public place?</b> Well, then you should
+consider purchasing <a href="professional_support.html">rsyslog professional support</a>.
+The fees are very low and help fund the project. If you use rsyslog seriously inside
+a corporate environment, there is no excuse for not getting one of the support
+packages ;)
+<p>Of course, things are different when I ask you to mail me privately. I'll usually do
+that when I think it makes sense, for example when we exchange debug logs.
+<p>I hope you now understand the free support options and the reasoning for them.
+I hope I haven't offended you with my words - this is not my intension. I just needed to
+make clear why there are some limits on my responsiveness. Happy logging!
+<p>[<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&nbsp;© 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>
diff --git a/doc/imuxsock.html b/doc/imuxsock.html
index ee367dbc..77491992 100644
--- a/doc/imuxsock.html
+++ b/doc/imuxsock.html
@@ -1,7 +1,7 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head>
-<meta http-equiv="Content-Language" content="en"><title>Unix Socket Input</title>
-
+<meta http-equiv="Content-Language" content="en">
+<title>Unix Socket Input</title>
</head>
<body>
<h1>Unix Socket Input</h1>
@@ -9,31 +9,65 @@
<p><b>Author: </b>Rainer Gerhards
&lt;rgerhards@adiscon.com&gt;</p>
<p><b>Description</b>:</p>
-<p>Provides the ability to accept syslog messages via local Unix
+<p><b>Provides the ability to accept syslog messages via local Unix
sockets. Most importantly, this is the mechanism by which the syslog(3)
-call delivers syslog messages to rsyslogd. So you need to have this
+call delivers syslog messages to rsyslogd.</b> So you need to have this
module loaded to read the system log socket and be able to process log
-messages from applications running on the local system.</p><p>Application-provided
-timestamps are ignored by default. This is needed, as some programs
-(e.g. sshd)&nbsp;log with inconsistent timezone information, what
+messages from applications running on the local system.</p>
+<p><b>Application-provided
+timestamps are ignored by default.</b> This is needed, as some programs
+(e.g. sshd) log with inconsistent timezone information, what
messes up the local logs (which by default don't even contain time zone
information). This seems to be consistent with what sysklogd did for
the past four years. Alternate behaviour may be desirable if
gateway-like processes send messages via the local log slot - in this
case, it can be enabled via the
-$InputUnixListenSocketIgnoreMsgTimestamp and $SystemLogSocketIgnoreMsgTimestamp config directives</p><p><b>Configuration Directives</b>:</p>
+$InputUnixListenSocketIgnoreMsgTimestamp and $SystemLogSocketIgnoreMsgTimestamp config directives</p>
+<p><b>Unix log sockets can be flow-controlled.</b> That is, if processing queues fill up,
+the unix socket reader is blocked for a short while. This may be useful to prevent overruning
+the queues (which may cause exessive disk-io where it actually would not be needed). However,
+flow-controlling a log socket (and especially the system log socket) can lead to a very
+unresponsive system. As such, flow control is disabled by default. That means any log records
+are places as quickly as possible into the processing queues. If you would like to have
+flow control, you need to enable it via the $SystemLogSocketFlowControl and
+$InputUnixListenSocketFlowControl config directives. Just make sure you thought about
+the implications. Note that for many systems, turning on flow control does not hurt.
+<p><b>Configuration Directives</b>:</p>
<ul>
-<li><span style="font-weight: bold;">$InputUnixListenSocketIgnoreMsgTimestamp</span> [<span style="font-weight: bold;">on</span>/off]<strong></strong><br>Ignore timestamps included in the message. Applies to the next socket being added.</li><li><span style="font-weight: bold;">$SystemLogSocketIgnoreMsgTimestamp</span> [<span style="font-weight: bold;">on</span>/off]<br>Ignore timestamps included in the messages, applies to messages received via the system log socket.</li><li><span style="font-weight: bold;">$OmitLocalLogging</span> (imuxsock) [on/<b>off</b>] --
-former -o option</li><li><span style="font-weight: bold;">$SystemLogSocketName</span> &lt;name-of-socket&gt; --
-former -p option</li><li><span style="font-weight: bold;">$AddUnixListenSocket</span> &lt;name-of-socket&gt; adds
-additional unix socket, default none -- former -a option</li></ul>
+<li><b>$InputUnixListenSocketIgnoreMsgTimestamp</b> [<b>on</b>/off]
+<br>Ignore timestamps included in the message. Applies to the next socket being added.</li>
+<li><b>$InputUnixListenSocketFlowControl</b> [on/<b>off</b>] - specifies if flow control should be applied
+to the next socket.</li>
+<li><b>$SystemLogSocketIgnoreMsgTimestamp</b> [<b>on</b>/off]<br>
+Ignore timestamps included in the messages, applies to messages received via the system log socket.</li>
+<li><b>$OmitLocalLogging</b> (imuxsock) [on/<b>off</b>] -- former -o option</li>
+<li><b>$SystemLogSocketName</b> &lt;name-of-socket&gt; -- former -p option</li>
+<li><b>$SystemLogFlowControl</b> [on/<b>off</b>] - specifies if flow control should be applied
+to the system log socket.</li>
+<li><b>$AddUnixListenSocket</b> &lt;name-of-socket&gt; adds additional unix socket, default none -- former -a option</li>
+<li><b>$InputUnixListenSocketHostName</b> &lt;hostname&gt; permits to override the hostname that
+shall be used inside messages taken from the <b>next</b> $AddUnixListenSocket socket. Note that
+the hostname must be specified before the $AddUnixListenSocket configuration directive, and it
+will only affect the next one and then automatically be reset. This functionality is provided so
+that the local hostname can be overridden in cases where that is desired.</li>
+</ul>
<b>Caveats/Known Bugs:</b><br>
<br>
This documentation is sparse and incomplete.
<p><b>Sample:</b></p>
<p>The following sample is the minimum setup required to accept syslog messages from applications running on the local system.<br>
</p>
-<textarea rows="15" cols="60">$ModLoad imuxsock # needs to be done just once
+<textarea rows="2" cols="70">$ModLoad imuxsock # needs to be done just once
+$SystemLogSocketFlowControl on # enable flow control (use if needed)
+</textarea>
+<p>The following sample is a configuration where rsyslogd pulls logs from two
+jails, and assigns different hostnames to each of the jails: </p>
+<textarea rows="6" cols="60">$ModLoad imuxsock # needs to be done just once
+
+$InputUnixListenSocketHostName jail1.example.net
+$AddUnixListenSocket /jail/1/dev/log
+$InputUnixListenSocketHostName jail2.example.net
+$AddUnixListenSocket /jail/2/dev/log
</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>
@@ -44,4 +78,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/manual.html b/doc/manual.html
index 91c58a43..eac0c131 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.19.11 (beta branch) of rsyslog.</b>
+<p><b>This documentation is for version 3.21.4 (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
@@ -33,19 +33,14 @@ the links below for the</b><br></p><ul>
<li><a href="troubleshoot.html">troubleshooting rsyslog problems</a></li>
<li><a href="rsyslog_conf.html">configuration file syntax (rsyslog.conf)</a></li>
-<li> <a href="property_replacer.html">property
-replacer, an important core component</a></li>
-<li>a commented <a href="sample.conf.html">sample
-rsyslog.conf</a>
-</li>
+<li> <a href="property_replacer.html">property replacer, an important core component</a></li>
+<li>a commented <a href="sample.conf.html">sample rsyslog.conf</a></li>
<li><a href="bugs.html">rsyslog bug list</a></li>
-<li><a href="rsyslog_packages.html"> rsyslog
-packages</a></li>
+<li><a href="rsyslog_packages.html"> rsyslog packages</a></li>
<li><a href="generic_design.html">backgrounder on
generic syslog application design</a><!-- not good as it currently is ;) <li><a href="contributors.html">contributor &quot;Hall of Fame&quot;</a>--></li>
-<li><a href="modules.html">description of rsyslog
-modules</a></li><li><a href="man_rsyslogd.html">rsyslogd man page</a>
-(heavily outdated)</li>
+<li><a href="modules.html">description of rsyslog modules</a></li>
+<li><a href="man_rsyslogd.html">rsyslogd man page</a> (heavily outdated)</li>
</ul>
<p><b>We have some in-depth papers on</b></p>
<ul>
@@ -74,8 +69,7 @@ the world needs another syslogd</a>".</p>
<p>Documentation is added continuously. Please note that the
documentation here
matches only the current version of rsyslog. If you use an older
-version, be sure
-to use the doc that came with it.</p>
+version, be sure to use the doc that came with it.</p>
<p><b>You can also browse the following online resources:</b></p>
<ul>
<li>the <a href="http://wiki.rsyslog.com/">rsyslog
@@ -101,4 +95,6 @@ If you would like to use rsyslog source code inside your open source project, yo
any restriction as long as your license is GPLv3 compatible. If your license is incompatible to GPLv3,
you may even be still permitted to use rsyslog source code. However, then you need to look at the way
<a href="licensing.html">rsyslog is licensed</a>.</p>
+<p>Feedback is always welcome, but if you have a support question, please do not
+mail Rainer directly (<a href="free_support.html">why not?</a>).
</body></html>
diff --git a/doc/ommail.html b/doc/ommail.html
index 62ded6d0..c18cf3f8 100644
--- a/doc/ommail.html
+++ b/doc/ommail.html
@@ -50,7 +50,10 @@ standard SMTP port.</li>
<li><span style="font-weight: bold;">$ActionMailFrom</span><br>
The email address used as the senders address. There is no default.</li>
<li><span style="font-weight: bold;">$ActionMailTo</span><br>
-The recipients email address. There is no default.</li>
+The recipient email addresses. There is no default. To specify multiple
+recpients, repeat this directive as often as needed. Note: <b>This directive
+must be specified for each new action and is automatically reset.</b>
+[Multiple recipients are supported for 3.21.2 and above.]</li>
<li><span style="font-weight: bold;">$ActionMailSubject</span><br>
The name of the <span style="font-weight: bold;">template</span>
to be used as the mail subject. If this is not specified, a more or
@@ -112,14 +115,28 @@ $ActionExecOnlyOnceEveryInterval 21600
# the if ... then ... mailBody mus be on one line!
if $msg contains 'hard disk fatal failure' then :ommail:;mailBody
</textarea>
+<p>The sample below is the same, but sends mail to two recipients:</p>
+<textarea rows="15" cols="80">$ModLoad ommail
+$ActionMailSMTPServer mail.example.net
+$ActionMailFrom rsyslog@example.net
+$ActionMailTo operator@example.net
+$ActionMailTo admin@example.net
+$template mailSubject,"disk problem on %hostname%"
+$template mailBody,"RSYSLOG Alert\r\nmsg='%msg%'"
+$ActionMailSubject mailSubject
+# make sure we receive a mail only once in six
+# hours (21,600 seconds ;))
+$ActionExecOnlyOnceEveryInterval 21600
+# the if ... then ... mailBody mus be on one line!
+if $msg contains 'hard disk fatal failure' then :ommail:;mailBody
+</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>"
<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>
+<p><font size="2">This documentation is part of the <a href="http://www.rsyslog.com/">rsyslog</a>
project.<br>
Copyright &copy; 2008 by <a href="http://www.gerhards.net/rainer">Rainer
Gerhards</a> and
diff --git a/doc/rsyslog_conf.html b/doc/rsyslog_conf.html
index 8f258a8b..69e16ac6 100644
--- a/doc/rsyslog_conf.html
+++ b/doc/rsyslog_conf.html
@@ -79,8 +79,33 @@ default, it is usually well-chosen and applicable in most cases.</p>
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><i><b>$ActionExecOnlyEveryNthTime</b> &lt;number&gt;</i> - If configured, the next action will
+only be executed every n-th time. For example, if configured to 3, the first two messages
+that go into the action will be dropped, the 3rd will actually cause the action to execute,
+the 4th and 5th will be dropped, the 6th executed under the action, ... and so on. Note:
+this setting is automatically re-set when the actual action is defined.</li>
+<li><i><b>$ActionExecOnlyEveryNthTimeTimeout</b> &lt;number-of-seconds&gt;</i> - has a meaning only if
+$ActionExecOnlyEveryNthTime is also configured for the same action. If so, the timeout
+setting specifies after which period the counting of "previous actions" expires and
+a new action count is begun. Specify 0 (the default) to disable timeouts.
+<br>
+<i>Why is this option needed?</i> Consider this case: a message comes in at, eg., 10am. That's
+count 1. Then, nothing happens for the next 10 hours. At 8pm, the next
+one occurs. That's count 2. Another 5 hours later, the next message
+occurs, bringing the total count to 3. Thus, this message now triggers
+the rule.
+<br>
+The question is if this is desired behavior? Or should the rule only be
+triggered if the messages occur within an e.g. 20 minute window? If the
+later is the case, you need a
+<br>
+$ActionExecOnlyEveryNthTimeTimeout 1200
+<br>
+This directive will timeout previous messages seen if they are older
+than 20 minutes. In the example above, the count would now be always 1
+and consequently no rule would ever be triggered.
+
+<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
@@ -142,6 +167,7 @@ default 60000 (1 minute)]</li>
<li><a href="rsconf1_droptrailinglfonreception.html">$DropTrailingLFOnReception</a></li>
<li><a href="rsconf1_dynafilecachesize.html">$DynaFileCacheSize</a></li>
<li><a href="rsconf1_escapecontrolcharactersonreceive.html">$EscapeControlCharactersOnReceive</a></li>
+<li>$ErrorMessagesToStderr [<b>on</b>|off] - direct rsyslogd error message to stderr (in addition to other targets)</li>
<li><a href="rsconf1_failonchownfailure.html">$FailOnChownFailure</a></li>
<li><a href="rsconf1_filecreatemode.html">$FileCreateMode</a></li>
<li><a href="rsconf1_filegroup.html">$FileGroup</a></li>
@@ -787,7 +813,7 @@ administration needs.<br>
forward messages it has received from the network to another host.
Specify the "-h" option to enable this.</b></p>
<p>To forward messages to another host, prepend the hostname with
-the at sign ("@").&nbsp; A single at sign means that messages will
+the at sign ("@"). A single at sign means that messages will
be forwarded via UDP protocol (the standard for syslog). If you prepend
two at signs ("@@"), the messages will be transmitted via TCP. Please
note that plain TCP based syslog is not officially standardized, but
diff --git a/doc/rsyslog_ng_comparison.html b/doc/rsyslog_ng_comparison.html
index 6d14d933..bc99cb8c 100644
--- a/doc/rsyslog_ng_comparison.html
+++ b/doc/rsyslog_ng_comparison.html
@@ -209,10 +209,8 @@ priority</td>
<td></td>
</tr>
<tr>
-<td valign="top">ability to filter on any other
-message
-field not mentioned above
-(including substrings and the like)</td>
+<td valign="top">ability to filter on any other message
+field not mentioned above (including substrings and the like)</td>
<td valign="top">yes</td>
<td valign="top">no</td>
</tr>
@@ -248,6 +246,12 @@ based on filters</td>
<td></td>
</tr>
<tr>
+<td valign="top">ability to filter out messages based on sequence of appearing</td>
+<td valign="top">yes (starting with 3.21.3)</td>
+<td valign="top">no</td>
+<td></td>
+</tr>
+<tr>
<td valign="top">powerful BSD-style hostname and
program name blocks for easy multi-host support</td>
<td valign="top">yes</td>
diff --git a/doc/status.html b/doc/status.html
index 90932fca..11e8ece3 100644
--- a/doc/status.html
+++ b/doc/status.html
@@ -2,24 +2,22 @@
<html><head><title>rsyslog status page</title></head>
<body>
<h2>rsyslog status page</h2>
-<p>This page reflects the status as of 2008-07-15.</p>
+<p>This page reflects the status as of 2008-08-13.</p>
<h2>Current Releases</h2>
-<!-- no devel at this time!
-<p><b>development:</b> 3.19.9 [2008-07-07] -
-<a href="http://www.rsyslog.com/Article250.phtml">change log</a> -
-<a href="http://www.rsyslog.com/Downloads-req-viewdownloaddetails-lid-117.phtml">download</a>
--->
+<p><b>development:</b> 3.21.3 [2008-08-13] -
+<a href="http://www.rsyslog.com/Article270.phtml">change log</a> -
+<a href="http://www.rsyslog.com/Downloads-req-viewdownloaddetails-lid-127.phtml">download</a>
<br><b>beta:</b> 3.19.10 [2008-07-15] -
<a href="http://www.rsyslog.com/Article256.phtml">change log</a> -
-<a href="http://www.rsyslog.com/Downloads-req-viewdownloaddetails-lid-109.phtml">download</a></p>
+<a href="http://www.rsyslog.com/Downloads-req-viewdownloaddetails-lid-120.phtml">download</a></p>
-<p><b>v3 stable:</b> 3.18.0 [2008-07-11] - <a href="http://www.rsyslog.com/Article254.phtml">change log</a> -
-<a href="http://www.rsyslog.com/Downloads-req-viewdownloaddetails-lid-120.phtml">download</a>
+<p><b>v3 stable:</b> 3.18.2 [2008-08-08] - <a href="http://www.rsyslog.com/Article268.phtml">change log</a> -
+<a href="http://www.rsyslog.com/Downloads-req-viewdownloaddetails-lid-126.phtml">download</a>
-<br><b>v2 stable:</b> 2.0.5 [2008-05-15] - <a href="http://www.rsyslog.com/Article226.phtml">change log</a> -
-<a href="http://www.rsyslog.com/Downloads-req-viewdownloaddetails-lid-104.phtml">download</a>
+<br><b>v2 stable:</b> 2.0.6 [2008-08-07] - <a href="http://www.rsyslog.com/Article266.phtml">change log</a> -
+<a href="http://www.rsyslog.com/Downloads-req-viewdownloaddetails-lid-125.phtml">download</a>
<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
diff --git a/doc/syslog-protocol.html b/doc/syslog_protocol.html
index 72de5c27..72de5c27 100644
--- a/doc/syslog-protocol.html
+++ b/doc/syslog_protocol.html
diff --git a/doc/troubleshoot.html b/doc/troubleshoot.html
index f2e9206b..7decbba2 100644
--- a/doc/troubleshoot.html
+++ b/doc/troubleshoot.html
@@ -12,7 +12,18 @@ the most recent development version. However, there is a version-specific
doc set in each tarball. If you installed rsyslog from a package, there usually
is a rsyslog-doc package, that often needs to be installed separately.
<li>The <a href="http://wiki.rsyslog.com">rsyslog wiki</a> provides user tips and experiences.
+<li>Check <a href="http://bugzilla.adiscon.com">the bugzilla</a> to see if your problem is a known
+(and even fixed ;)) bug.
</ul>
+<p><b>Configuration Problems</b>
+<p>Rsyslog 3.21.1 and above has been enhanced to support extended configuration checking.
+It offers a special command line switch (-N1) that puts it into "config verfication mode".
+In that mode, it interprets and check the configuration file, but does not startup. This
+mode can be used in parallel to a running instance of rsyslogd.
+<p>To enable it, run rsyslog interactively as follows:
+<p><b><i>/path/to/rsyslogd -f/path/to/config-file -N1</i></b>
+<p>You should also specify other options you usually give (like -c3 and whatever else).
+Any problems experienced are reported to stderr [aka "your screen" (if not redirected)].
<p><b>Asking for Help</b>
<p>If you can't find the answer yourself, you should look at these places for
community help.
@@ -23,6 +34,54 @@ the preferred method of obtaining support.
This is a low-volume list which occasional gets traffic spikes.
The mailing list is probably a good place for complex questions.
</ul>
+<p><b>Debug Log</b>
+<p>If you ask for help, there are chances that we need to ask for an rsyslog debug log.
+The debug log is a detailled report of what rsyslog does during processing. As such, it may
+even be useful for your very own troubleshooting. People have seen things inside their debug
+log that enabled them to find problems they did not see before. So having a look at the
+debug log, even before asking for help, may be useful.
+<p>Note that the debug log contains most of those things we consider useful. This is a lot
+of information, but may still be too few. So it sometimes may happen that you will be asked
+to run a specific version which has additional debug output. Also, we revise from time to
+time what is worth putting into the standard debug log. As such, log content may change
+from version to version. We do not guarantee any specific debug log contents, so do not
+rely on that. The amount of debug logging can also be controlled via some environment
+options. Please see <a href="debug.html">debugging support</a> for further details.
+<p>In general, it is advisable to run rsyslogd in the foreground to obtain the log.
+To do so, make sure you know which options are usually used when you start rsyslogd
+as a background daemon. Let's assume "-c3" is the only option used. Then, do the following:
+<ul>
+<li>make sure rsyslogd as a daemon is stopped (verify with ps -ef|grep rsyslogd)
+<li>make sure you have a console session with root permissions
+<li>run rsyslogd interactively: /sbin/rsyslogd ..your options.. -dn &gt; logfile
+<br>where "your options" is what you usually use. /sbin/rsyslogd is the full path
+to the rsyslogd binary (location different depending on distro).
+In our case, the command would be
+<br>/sbin/rsyslogd -c3 -dn &gt; logfile
+<li>press ctrl-C when you have sufficient data (e.g. a device logged a record)
+<br><b>NOTE: rsyslogd will NOT stop automatically - you need to ctrl-c out of it!</b>
+<li>Once you have done all that, you can review logfile. It contains the debug output.
+<li>When you are done, make sure you re-enable (and start) the background daemon!
+</ul>
+<p>If you need to submit the logfile, you may want to check if it contains any
+passwords or other sensitive data. If it does, you can change it to some <b>consistent</b>
+meaningless value. <b>Do not delete the lines</b>, as this renders the debug log
+unusable (and makes Rainer quite angry for wasted time, aka significantly reduces the chance
+he will remain motivated to look at your problem ;)). For the same reason, make sure
+whatever you change is change consistently. Really!
+<p>Debug log file can get quite large. Before submitting them, it is a good idea to zip them.
+Rainer has handled files of around 1 to 2 GB. If your's is larger ask before submitting. Often,
+it is sufficient to submit the first 2,000 lines of the log file and around another 1,000 around
+the area where you see a problem. Also,
+ask you can submit a file via private mail. Private mail is usually a good way to go for large files
+or files with sensitive content. However, do NOT send anything sensitive that you do not want
+the outside to be known. While Rainer so far made effort no to leak any sensitive information,
+there is no guarantee that doesn't happen. If you need a guarantee, you are probably a
+candidate for a <a href="professional_support.html">commercial support contract</a>. Free support
+comes without any guarantees, include no guarantee on confidentiality
+[aka "we don't want to be sued for work were are not even paid for ;)].
+<b>So if you submit debug logs, do so at your sole risk</b>. By submitting them, you accept
+this policy.
<p>[<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
diff --git a/plugins/imdiag/Makefile.am b/plugins/imdiag/Makefile.am
new file mode 100644
index 00000000..da5a3ddc
--- /dev/null
+++ b/plugins/imdiag/Makefile.am
@@ -0,0 +1,6 @@
+pkglib_LTLIBRARIES = imdiag.la
+
+imdiag_la_SOURCES = imdiag.c
+imdiag_la_CPPFLAGS = -I$(top_srcdir) $(pthreads_cflags) $(rsrt_cflags)
+imdiag_la_LDFLAGS = -module -avoid-version
+imdiag_la_LIBADD =
diff --git a/plugins/imdiag/imdiag.c b/plugins/imdiag/imdiag.c
new file mode 100644
index 00000000..3cd2dcf8
--- /dev/null
+++ b/plugins/imdiag/imdiag.c
@@ -0,0 +1,197 @@
+/* imdiag.c
+ * This is a diagnostics module, primarily meant for troubleshooting
+ * and information about the runtime state of rsyslog. It is implemented
+ * as an input plugin, because that interface best suits our needs
+ * and also enables us to inject test messages (something not yet
+ * implemented).
+ *
+ * File begun on 2008-07-25 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 <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#include "rsyslog.h"
+//#include "dirty.h"
+#include "cfsysline.h"
+#include "module-template.h"
+#include "net.h"
+#include "netstrm.h"
+#include "errmsg.h"
+
+MODULE_TYPE_INPUT
+
+/* static data */
+DEF_IMOD_STATIC_DATA
+DEFobjCurrIf(net)
+DEFobjCurrIf(netstrm)
+DEFobjCurrIf(errmsg)
+
+/* Module static data */
+netstrms_t *pNS; /**< pointer to network stream subsystem */
+netstrm_t **ppLstn[10]; /**< our netstream listners */
+int iLstnMax = 0; /**< max nbr of listeners currently supported */
+
+
+/* config settings */
+
+
+/* add a listen socket to our listen socket array. This is a callback
+ * invoked from the netstrm class. -- rgerhards, 2008-04-23
+ */
+static rsRetVal
+addTcpLstn(void *pUsr, netstrm_t *pLstn)
+{
+ DEFiRet;
+
+ ISOBJ_TYPE_assert(pLstn, netstrm);
+
+ if(iLstnMax >= sizeof(ppLstn)/sizeof(netstrm_t))
+ ABORT_FINALIZE(RS_RET_MAX_LSTN_REACHED);
+
+ ppLstn[pThis->iLstnMax] = pLstn;
+ ++iLstnMax;
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* initialize network stream subsystem */
+static rsRetVal
+initNetstrm(void)
+{
+ DEFiRet;
+
+ /* prepare network stream subsystem */
+ CHKiRet(netstrms.Construct(&pNS));
+ CHKiRet(netstrms.SetDrvrMode(pNS, 0)); /* always plain text */
+ //CHKiRet(netstrms.SetDrvrAuthMode(pThis->pNS, pThis->pszDrvrAuthMode));
+ //CHKiRet(netstrms.SetDrvrPermPeers(pThis->pNS, pThis->pPermPeers));
+ // TODO: set driver!
+ CHKiRet(netstrms.ConstructFinalize(pThis->pNS));
+
+ /* set up listeners */
+ CHKiRet(netstrm.LstnInit(pNS, NULL, addTcpLstn, "127.0.0.1", "44514", 1));
+
+finalize_it:
+ if(iRet != RS_RET_OK) {
+ if(pThis->pNS != NULL)
+ netstrms.Destruct(&pThis->pNS);
+ }
+ RETiRet;
+}
+
+
+/* This function is called to gather input. In our case, it is a bit abused
+ * to drive the listener loop for the diagnostics code.
+ */
+BEGINrunInput
+CODESTARTrunInput
+ENDrunInput
+
+
+/* initialize and return if will run or not */
+BEGINwillRun
+CODESTARTwillRun
+ iRet = initNetstrm();
+ENDwillRun
+
+
+BEGINafterRun
+CODESTARTafterRun
+ /* do cleanup here */
+ /* finally close our listen streams */
+ for(i = 0 ; i < iLstnMax ; ++i) {
+ netstrm.Destruct(ppLstn + i);
+ }
+
+ /* destruct netstream subsystem */
+ netstrms.Destruct(pNS);
+ENDafterRun
+
+
+BEGINmodExit
+CODESTARTmodExit
+ /* release objects we used */
+ objRelease(net, LM_NET_FILENAME);
+ objRelease(netstrm, LM_NETSTRMS_FILENAME);
+ objRelease(errmsg, CORE_COMPONENT);
+ENDmodExit
+
+
+static rsRetVal
+resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
+{
+ return RS_RET_OK;
+}
+
+
+
+BEGINqueryEtryPt
+CODESTARTqueryEtryPt
+CODEqueryEtryPt_STD_IMOD_QUERIES
+ENDqueryEtryPt
+
+
+BEGINmodInit()
+CODESTARTmodInit
+ *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
+CODEmodInit_QueryRegCFSLineHdlr
+ pOurTcpsrv = NULL;
+ /* request objects we use */
+ CHKiRet(objUse(net, LM_NET_FILENAME));
+ CHKiRet(objUse(netstrm, LM_NETSTRMS_FILENAME));
+ CHKiRet(objUse(errmsg, CORE_COMPONENT));
+
+#if 0
+ /* register config file handlers */
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputtcpserverrun", 0, eCmdHdlrGetWord,
+ addTCPListener, NULL, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputtcpmaxsessions", 0, eCmdHdlrInt,
+ NULL, &iTCPSessMax, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputtcpserverstreamdrivermode", 0,
+ eCmdHdlrInt, NULL, &iStrmDrvrMode, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputtcpserverstreamdriverauthmode", 0,
+ eCmdHdlrGetWord, NULL, &pszStrmDrvrAuthMode, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputtcpserverstreamdriverpermittedpeer", 0,
+ eCmdHdlrGetWord, setPermittedPeer, NULL, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler,
+ resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
+#endif
+ENDmodInit
+
+
+/* vim:set ai:
+ */
diff --git a/plugins/imuxsock/imuxsock.c b/plugins/imuxsock/imuxsock.c
index 05bcb642..4f1fcea4 100644
--- a/plugins/imuxsock/imuxsock.c
+++ b/plugins/imuxsock/imuxsock.c
@@ -73,12 +73,16 @@ static int startIndexUxLocalSockets; /* process funix from that index on (used t
static int funixParseHost[MAXFUNIX] = { 0, }; /* should parser parse host name? read-only after startup */
static int funixFlags[MAXFUNIX] = { ADDDATE, }; /* should parser parse host name? read-only after startup */
static uchar *funixn[MAXFUNIX] = { (uchar*) _PATH_LOG }; /* read-only after startup */
+static uchar *funixHName[MAXFUNIX] = { NULL, }; /* host-name override - if set, use this instead of actual name */
+static int funixFlowCtl[MAXFUNIX] = { eFLOWCTL_NO_DELAY, }; /* flow control settings for this socket */
static int funix[MAXFUNIX] = { -1, }; /* read-only after startup */
static int nfunix = 1; /* number of Unix sockets open / read-only after startup */
/* config settings */
static int bOmitLocalLogging = 0;
static uchar *pLogSockName = NULL;
+static uchar *pLogHostName = NULL; /* host name to use with this socket */
+static int bUseFlowCtl = 0; /* use flow control or not (if yes, only LIGHT is used! */
static int bIgnoreTimestamp = 1; /* ignore timestamps present in the incoming message? */
@@ -93,6 +97,14 @@ static rsRetVal setSystemLogTimestampIgnore(void __attribute__((unused)) *pVal,
RETiRet;
}
+/* set flowcontrol for the system log socket
+ */
+static rsRetVal setSystemLogFlowControl(void __attribute__((unused)) *pVal, int iNewVal)
+{
+ DEFiRet;
+ funixFlowCtl[0] = iNewVal ? eFLOWCTL_LIGHT_DELAY : eFLOWCTL_NO_DELAY;
+ RETiRet;
+}
/* add an additional listen socket. Socket names are added
* until the array is filled up. It is never reset, only at
@@ -100,6 +112,7 @@ static rsRetVal setSystemLogTimestampIgnore(void __attribute__((unused)) *pVal,
* TODO: we should change the array to a list so that we
* can support any number of listen socket names.
* rgerhards, 2007-12-20
+ * added capability to specify hostname for socket -- rgerhards, 2008-08-01
*/
static rsRetVal addLstnSocketName(void __attribute__((unused)) *pVal, uchar *pNewVal)
{
@@ -110,6 +123,9 @@ static rsRetVal addLstnSocketName(void __attribute__((unused)) *pVal, uchar *pNe
else {
funixParseHost[nfunix] = 0;
}
+ funixHName[nfunix] = pLogHostName;
+ pLogHostName = NULL; /* re-init for next, not freed because funixHName[] now owns it */
+ funixFlowCtl[nfunix] = bUseFlowCtl ? eFLOWCTL_LIGHT_DELAY : eFLOWCTL_NO_DELAY;
funixFlags[nfunix] = bIgnoreTimestamp ? ADDDATE : NOFLAG;
funixn[nfunix++] = pNewVal;
}
@@ -134,6 +150,10 @@ static rsRetVal discardFunixn(void)
free(funixn[i]);
funixn[i] = NULL;
}
+ if(funixHName[i] != NULL) {
+ free(funixHName[i]);
+ funixHName[i] = NULL;
+ }
}
return RS_RET_OK;
@@ -144,7 +164,6 @@ static int create_unix_socket(const char *path)
{
struct sockaddr_un sunx;
int fd;
- char line[MAXLINE +1];
if (path[0] == '\0')
return -1;
@@ -155,11 +174,9 @@ static int create_unix_socket(const char *path)
sunx.sun_family = AF_UNIX;
(void) strncpy(sunx.sun_path, path, sizeof(sunx.sun_path));
fd = socket(AF_UNIX, SOCK_DGRAM, 0);
- if (fd < 0 || bind(fd, (struct sockaddr *) &sunx,
- SUN_LEN(&sunx)) < 0 ||
+ if (fd < 0 || bind(fd, (struct sockaddr *) &sunx, SUN_LEN(&sunx)) < 0 ||
chmod(path, 0666) < 0) {
- snprintf(line, sizeof(line), "cannot create %s", path);
- errmsg.LogError(errno, NO_ERRCODE, "%s", line);
+ errmsg.LogError(errno, NO_ERRCODE, "connot create '%s'", path);
dbgprintf("cannot create %s (%d).\n", path, errno);
close(fd);
return -1;
@@ -171,18 +188,23 @@ static int create_unix_socket(const char *path)
/* This function receives data from a socket indicated to be ready
* to receive and submits the message received for processing.
* rgerhards, 2007-12-20
+ * Interface changed so that this function is passed the array index
+ * of the socket which is to be processed. This eases access to the
+ * growing number of properties. -- rgerhards, 2008-08-01
*/
-static rsRetVal readSocket(int fd, int bParseHost, int flags)
+static rsRetVal readSocket(int fd, int iSock)
{
DEFiRet;
int iRcvd;
uchar line[MAXLINE +1];
+ assert(iSock >= 0);
iRcvd = recv(fd, line, MAXLINE - 1, 0);
dbgprintf("Message from UNIX socket: #%d\n", fd);
if (iRcvd > 0) {
- parseAndSubmitMessage(glbl.GetLocalHostName(), (uchar*)"127.0.0.1", line,
- iRcvd, bParseHost, flags, eFLOWCTL_NO_DELAY);
+ parseAndSubmitMessage(funixHName[iSock] == NULL ? glbl.GetLocalHostName() : funixHName[iSock],
+ (uchar*)"127.0.0.1", line,
+ iRcvd, funixParseHost[iSock], funixFlags[iSock], funixFlowCtl[iSock]);
} else if (iRcvd < 0 && errno != EINTR) {
char errStr[1024];
rs_strerror_r(errno, errStr, sizeof(errStr));
@@ -194,8 +216,7 @@ static rsRetVal readSocket(int fd, int bParseHost, int flags)
}
-/* This function is called to gather input.
- */
+/* This function is called to gather input. */
BEGINrunInput
int maxfds;
int nfds;
@@ -237,7 +258,7 @@ CODESTARTrunInput
for (i = 0; i < nfunix && nfds > 0; i++) {
if ((fd = funix[i]) != -1 && FD_ISSET(fd, &readfds)) {
- readSocket(fd, funixParseHost[i], funixFlags[i]);
+ readSocket(fd, i);
--nfds; /* indicate we have processed one */
}
}
@@ -282,6 +303,9 @@ CODESTARTafterRun
/* free no longer needed string */
if(pLogSockName != NULL)
free(pLogSockName);
+ if(pLogHostName != NULL) {
+ free(pLogHostName);
+ }
discardFunixn();
nfunix = 1;
@@ -307,10 +331,15 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a
free(pLogSockName);
pLogSockName = NULL;
}
+ if(pLogHostName != NULL) {
+ free(pLogHostName);
+ pLogHostName = NULL;
+ }
discardFunixn();
nfunix = 1;
bIgnoreTimestamp = 1;
+ bUseFlowCtl = 0;
return RS_RET_OK;
}
@@ -324,6 +353,8 @@ CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(objUse(errmsg, CORE_COMPONENT));
CHKiRet(objUse(glbl, CORE_COMPONENT));
+ dbgprintf("imuxsock version %s initializing\n", PACKAGE_VERSION);
+
/* initialize funixn[] array */
for(i = 1 ; i < MAXFUNIX ; ++i) {
funixn[i] = NULL;
@@ -337,18 +368,24 @@ CODEmodInit_QueryRegCFSLineHdlr
NULL, &bIgnoreTimestamp, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogsocketname", 0, eCmdHdlrGetWord,
NULL, &pLogSockName, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensockethostname", 0, eCmdHdlrGetWord,
+ NULL, &pLogHostName, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketflowcontrol", 0, eCmdHdlrBinary,
+ NULL, &bUseFlowCtl, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"addunixlistensocket", 0, eCmdHdlrGetWord,
addLstnSocketName, NULL, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler,
resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
/* the following one is a (dirty) trick: the system log socket is not added via
- * an "addUnixListenSocket" config format. As such, the timestamp can not be modified
- * via $InputUnixListenSocketIgnoreMsgTimestamp". So we need to add a special directive
+ * an "addUnixListenSocket" config format. As such, it's properties can not be modified
+ * via $InputUnixListenSocket*". So we need to add a special directive
* for that. We should revisit all of that once we have the new config format...
* rgerhards, 2008-03-06
*/
CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogsocketignoremsgtimestamp", 0, eCmdHdlrBinary,
setSystemLogTimestampIgnore, NULL, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogsocketflowcontrol", 0, eCmdHdlrBinary,
+ setSystemLogFlowControl, NULL, STD_LOADABLE_MODULE_ID));
ENDmodInit
/* vim:set ai:
*/
diff --git a/plugins/ommail/ommail.c b/plugins/ommail/ommail.c
index 4bbb844a..5faadce3 100644
--- a/plugins/ommail/ommail.c
+++ b/plugins/ommail/ommail.c
@@ -60,10 +60,18 @@ DEF_OMOD_STATIC_DATA
DEFobjCurrIf(errmsg)
DEFobjCurrIf(glbl)
+/* we add a little support for multiple recipients. We do this via a
+ * singly-linked list, enqueued from the top. -- rgerhards, 2008-08-04
+ */
+typedef struct toRcpt_s toRcpt_t;
+struct toRcpt_s {
+ uchar *pszTo;
+ toRcpt_t *pNext;
+};
+static toRcpt_t *lstRcpt = NULL;
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) */
@@ -76,7 +84,7 @@ typedef struct _instanceData {
uchar *pszSrv;
uchar *pszSrvPort;
uchar *pszFrom;
- uchar *pszTo;
+ toRcpt_t *lstRcpt;
char RcvBuf[1024]; /* buffer for receiving server responses */
size_t lenRcvBuf;
size_t iRcvBuf; /* current index into the rcvBuf (buf empty if iRcvBuf == lenRcvBuf) */
@@ -85,6 +93,83 @@ typedef struct _instanceData {
} md; /* mode-specific data */
} instanceData;
+/* forward definitions (as few as possible) */
+static rsRetVal Send(int sock, char *msg, size_t len);
+static rsRetVal readResponse(instanceData *pData, int *piState, int iExpected);
+
+
+/* helpers for handling the recipient lists */
+
+/* destroy a complete recipient list */
+static void lstRcptDestruct(toRcpt_t *pRoot)
+{
+ toRcpt_t *pDel;
+
+ while(pRoot != NULL) {
+ pDel = pRoot;
+ pRoot = pRoot->pNext;
+ /* ready to disalloc */
+ free(pDel->pszTo);
+ free(pDel);
+ }
+}
+
+/* This function is called when a new recipient email address is to be
+ * added. rgerhards, 2008-08-04
+ */
+static rsRetVal
+addRcpt(void __attribute__((unused)) *pVal, uchar *pNewVal)
+{
+ DEFiRet;
+ toRcpt_t *pNew = NULL;
+
+ CHKmalloc(pNew = calloc(1, sizeof(toRcpt_t)));
+
+ pNew->pszTo = pNewVal;
+ pNew->pNext = lstRcpt;
+ lstRcpt = pNew;
+
+ dbgprintf("ommail::addRcpt adds recipient %s\n", pNewVal);
+
+finalize_it:
+ if(iRet != RS_RET_OK) {
+ if(pNew != NULL)
+ free(pNew);
+ free(pNewVal); /* in any case, this is no longer needed */
+ }
+
+ RETiRet;
+}
+
+
+/* output the recipient list to the mail server
+ * iStatusToCheck < 0 means no checking should happen
+ */
+static rsRetVal
+WriteRcpts(instanceData *pData, uchar *pszOp, size_t lenOp, int iStatusToCheck)
+{
+ toRcpt_t *pRcpt;
+ int iState;
+ DEFiRet;
+
+ assert(pData != NULL);
+ assert(pszOp != NULL);
+ assert(lenOp != 0);
+
+ for(pRcpt = pData->md.smtp.lstRcpt ; pRcpt != NULL ; pRcpt = pRcpt->pNext) {
+ dbgprintf("Sending '%s: <%s>'\n", pszOp, pRcpt->pszTo);
+ CHKiRet(Send(pData->md.smtp.sock, (char*)pszOp, lenOp));
+ CHKiRet(Send(pData->md.smtp.sock, ": <", sizeof(": <") - 1));
+ CHKiRet(Send(pData->md.smtp.sock, (char*)pRcpt->pszTo, strlen((char*)pRcpt->pszTo)));
+ CHKiRet(Send(pData->md.smtp.sock, ">\r\n", sizeof(">\r\n") - 1));
+ if(iStatusToCheck >= 0)
+ CHKiRet(readResponse(pData, &iState, iStatusToCheck));
+ }
+
+finalize_it:
+ RETiRet;
+}
+/* end helpers for handling the recipient lists */
BEGINcreateInstance
CODESTARTcreateInstance
@@ -107,8 +192,7 @@ CODESTARTfreeInstance
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);
+ lstRcptDestruct(pData->md.smtp.lstRcpt);
}
ENDfreeInstance
@@ -426,10 +510,7 @@ sendSMTP(instanceData *pData, uchar *body, uchar *subject)
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(WriteRcpts(pData, (uchar*)"RCPT TO", sizeof("RCPT TO") - 1, 250));
CHKiRet(Send(pData->md.smtp.sock, "DATA\r\n", sizeof("DATA\r\n") - 1));
CHKiRet(readResponse(pData, &iState, 354));
@@ -443,9 +524,7 @@ sendSMTP(instanceData *pData, uchar *body, uchar *subject)
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(WriteRcpts(pData, (uchar*)"To", sizeof("To") - 1, -1));
CHKiRet(Send(pData->md.smtp.sock, "Subject: ", sizeof("Subject: ") - 1));
CHKiRet(Send(pData->md.smtp.sock, (char*)subject, strlen((char*)subject)));
@@ -531,13 +610,14 @@ CODESTARTparseSelectorAct
errmsg.LogError(0, RS_RET_MAIL_NO_FROM, "no sender address given - specify $ActionMailFrom");
ABORT_FINALIZE(RS_RET_MAIL_NO_FROM);
}
- if(pszTo == NULL) {
+ if(lstRcpt == NULL) {
errmsg.LogError(0, RS_RET_MAIL_NO_TO, "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);
+ pData->md.smtp.lstRcpt = lstRcpt; /* we "hand over" this memory */
+ lstRcpt = NULL; /* note: this is different from pre-3.21.2 versions! */
if(pszSubject == NULL) {
/* if no subject is configured, we need just one template string */
@@ -576,10 +656,8 @@ static rsRetVal freeConfigVariables(void)
free(pszFrom);
pszFrom = NULL;
}
- if(pszTo != NULL) {
- free(pszTo);
- pszTo = NULL;
- }
+ lstRcptDestruct(lstRcpt);
+ lstRcpt = NULL;
RETiRet;
}
@@ -621,10 +699,12 @@ CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(objUse(errmsg, CORE_COMPONENT));
CHKiRet(objUse(glbl, CORE_COMPONENT));
+ dbgprintf("ommail version %s initializing\n", VERSION);
+
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 *)"actionmailto", 0, eCmdHdlrGetWord, addRcpt, NULL, 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));
diff --git a/rsyslog.conf b/rsyslog.conf
index ce7d131a..47fc4402 100644
--- a/rsyslog.conf
+++ b/rsyslog.conf
@@ -5,9 +5,9 @@
# If you do not load inputs, nothing happens!
# You may need to set the module load path if modules are not found.
-$ModLoad immark.so # provides --MARK-- message capability
-$ModLoad imuxsock.so # provides support for local system logging (e.g. via logger command)
-$ModLoad imklog.so # kernel logging (formerly provided by rklogd)
+$ModLoad immark # provides --MARK-- message capability
+$ModLoad imuxsock # provides support for local system logging (e.g. via logger command)
+$ModLoad imklog # kernel logging (formerly provided by rklogd)
# Log all kernel messages to the console.
# Logging much else clutters up the screen.
diff --git a/runtime/conf.c b/runtime/conf.c
index 71b2b2da..ffe67dbe 100644
--- a/runtime/conf.c
+++ b/runtime/conf.c
@@ -83,6 +83,8 @@ DEFobjCurrIf(module)
DEFobjCurrIf(errmsg)
DEFobjCurrIf(net)
+static int iNbrActions; /* number of actions the running config has. Needs to be init on ReInitConf() */
+
/* The following global variables are used for building
* tag and host selector lines during startup and config reload.
* This is stored as a global variable pool because of its ease. It is
@@ -188,6 +190,7 @@ doIncludeLine(uchar **pp, __attribute__((unused)) void* pVal)
char pattern[MAXFNAME];
uchar *cfgFile;
glob_t cfgFiles;
+ int result;
size_t i = 0;
struct stat fileInfo;
@@ -195,14 +198,21 @@ doIncludeLine(uchar **pp, __attribute__((unused)) void* pVal)
ASSERT(*pp != NULL);
if(getSubString(pp, (char*) pattern, sizeof(pattern) / sizeof(char), ' ') != 0) {
- errmsg.LogError(0, RS_RET_NOT_FOUND, "could not extract group name");
+ errmsg.LogError(0, RS_RET_NOT_FOUND, "could not parse config file name");
ABORT_FINALIZE(RS_RET_NOT_FOUND);
}
/* Use GLOB_MARK to append a trailing slash for directories.
* Required by doIncludeDirectory().
*/
- glob(pattern, GLOB_MARK, NULL, &cfgFiles);
+ result = glob(pattern, GLOB_MARK, NULL, &cfgFiles);
+ if(result != 0) {
+ char errStr[1024];
+ rs_strerror_r(errno, errStr, sizeof(errStr));
+ errmsg.LogError(0, RS_RET_FILE_NOT_FOUND, "error accessing config file or directory '%s': %s",
+ pattern, errStr);
+ ABORT_FINALIZE(RS_RET_FILE_NOT_FOUND);
+ }
for(i = 0; i < cfgFiles.gl_pathc; i++) {
cfgFile = (uchar*) cfgFiles.gl_pathv[i];
@@ -1060,6 +1070,7 @@ static rsRetVal cflineDoAction(uchar **p, action_t **ppAction)
pAction->f_ReduceRepeated = 0;
}
pAction->bEnabled = 1; /* action is enabled */
+ iNbrActions++; /* one more active action! */
}
break;
}
@@ -1159,6 +1170,34 @@ cfline(uchar *line, selector_t **pfCurr)
}
+/* Reinitialize the configuration subsystem. This is a "work-around" to the fact
+ * that we do not yet have actual config objects. This method is to be called
+ * whenever a totally new config is started (which means on startup and HUP).
+ * Note that it MUST NOT be called for an included config file.
+ * rgerhards, 2008-07-28
+ */
+static rsRetVal
+ReInitConf(void)
+{
+ DEFiRet;
+ iNbrActions = 0; /* this is what we created the function for ;) - action count is reset */
+ RETiRet;
+}
+
+
+/* return the current number of active actions
+ * rgerhards, 2008-07-28
+ */
+static rsRetVal
+GetNbrActActions(int *piNbrActions)
+{
+ DEFiRet;
+ assert(piNbrActions != NULL);
+ *piNbrActions = iNbrActions;
+ RETiRet;
+}
+
+
/* queryInterface function
* rgerhards, 2008-02-29
*/
@@ -1179,6 +1218,8 @@ CODESTARTobjQueryInterface(conf)
pIf->doIncludeLine = doIncludeLine;
pIf->cfline = cfline;
pIf->processConfFile = processConfFile;
+ pIf->ReInitConf = ReInitConf;
+ pIf->GetNbrActActions = GetNbrActActions;
finalize_it:
ENDobjQueryInterface(conf)
diff --git a/runtime/conf.h b/runtime/conf.h
index 31ca27b3..2494d4dc 100644
--- a/runtime/conf.h
+++ b/runtime/conf.h
@@ -37,8 +37,10 @@ BEGINinterface(conf) /* name must also be changed in ENDinterface macro! */
rsRetVal (*doIncludeLine)(uchar **pp, __attribute__((unused)) void* pVal);
rsRetVal (*cfline)(uchar *line, selector_t **pfCurr);
rsRetVal (*processConfFile)(uchar *pConfFile);
+ rsRetVal (*ReInitConf)(void);
+ rsRetVal (*GetNbrActActions)(int *);
ENDinterface(conf)
-#define confCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */
+#define confCURR_IF_VERSION 2 /* increment whenever you change the interface structure! */
/* prototypes */
diff --git a/runtime/queue.c b/runtime/queue.c
index 00f811a0..7e7d4152 100644
--- a/runtime/queue.c
+++ b/runtime/queue.c
@@ -2115,7 +2115,6 @@ queueEnqObj(queue_t *pThis, flowControl_t flowCtlType, void *pUsr)
if(pThis->bIsDA)
CHKiRet(queueChkStrtDA(pThis));
-
/* handle flow control
* There are two different flow control mechanisms: basic and advanced flow control.
* Basic flow control has always been implemented and protects the queue structures
diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h
index 95b2c756..f75a5663 100644
--- a/runtime/rsyslog.h
+++ b/runtime/rsyslog.h
@@ -123,6 +123,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth
RS_RET_TRUE = -3, /**< to indicate a true state (can be used as TRUE, legacy) */
RS_RET_FALSE = -2, /**< to indicate a false state (can be used as FALSE, legacy) */
RS_RET_NO_IRET = -8, /**< This is a trick for the debuging system - it means no iRet is provided */
+ RS_RET_VALIDATION_RUN = -9, /**< indicates a (config) validation run, processing not carried out */
RS_RET_ERR = -3000, /**< generic failure */
RS_TRUNCAT_TOO_LARGE = -3001, /**< truncation operation where too many chars should be truncated */
RS_RET_FOUND_AT_STRING_END = -3002, /**< some value found, but at the last pos of string */
@@ -248,6 +249,8 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth
RS_RET_RETRY = -2100, /**< call should be retried (e.g. EGAIN on recv) */
RS_RET_GSS_ERR = -2101, /**< generic error occured in GSSAPI subsystem */
RS_RET_CERTLESS = -2102, /**< state: we run without machine cert (this may be OK) */
+ RS_RET_NO_ACTIONS = -2103, /**< no active actions are configured (no output will be created) */
+ RS_RET_CONF_FILE_NOT_FOUND = -2104, /**< config file or directory not found */
/* RainerScript error messages (range 1000.. 1999) */
RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */
diff --git a/runtime/var.c b/runtime/var.c
index 7e51fc6d..559bc56c 100644
--- a/runtime/var.c
+++ b/runtime/var.c
@@ -29,6 +29,7 @@
*/
#include "config.h"
+#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
@@ -89,6 +90,44 @@ CODESTARTobjDebugPrint(var)
ENDobjDebugPrint(var)
+/* This function is similar to DebugPrint, but does not send its output to
+ * the debug log but instead to a caller-provided string. The idea here is that
+ * we can use this string to get a textual representation of a variable.
+ * Among others, this is useful for creating testbenches, our first use case for
+ * it. Here, it enables simple comparison of the resulting program to a
+ * reference program by simple string compare.
+ * Note that the caller must initialize the string object. We always add
+ * data to it. So, it can be easily combined into a chain of methods
+ * to generate the final string.
+ * rgerhards, 2008-07-07
+ */
+static rsRetVal
+Obj2Str(var_t *pThis, cstr_t *pstrPrg)
+{
+ DEFiRet;
+ size_t lenBuf;
+ uchar szBuf[2048];
+
+ ISOBJ_TYPE_assert(pThis, var);
+ assert(pstrPrg != NULL);
+ switch(pThis->varType) {
+ case VARTYPE_STR:
+ lenBuf = snprintf((char*) szBuf, sizeof(szBuf), "%s[cstr]", rsCStrGetSzStr(pThis->val.pStr));
+ break;
+ case VARTYPE_NUMBER:
+ lenBuf = snprintf((char*) szBuf, sizeof(szBuf), "%lld[nbr]", pThis->val.num);
+ break;
+ default:
+ lenBuf = snprintf((char*) szBuf, sizeof(szBuf), "**UNKNOWN**[%d]", pThis->varType);
+ break;
+ }
+ CHKiRet(rsCStrAppendStrWithLen(pstrPrg, szBuf, lenBuf));
+
+finalize_it:
+ RETiRet;
+}
+
+
/* duplicates a var instance
* rgerhards, 2008-02-25
*/
@@ -387,6 +426,7 @@ CODESTARTobjQueryInterface(var)
pIf->ConstructFinalize = varConstructFinalize;
pIf->Destruct = varDestruct;
pIf->DebugPrint = varDebugPrint;
+ pIf->Obj2Str = Obj2Str;
pIf->SetNumber = varSetNumber;
pIf->SetString = varSetString;
pIf->ConvForOperation = ConvForOperation;
diff --git a/runtime/var.h b/runtime/var.h
index bbe7ba33..6d890ec9 100644
--- a/runtime/var.h
+++ b/runtime/var.h
@@ -59,6 +59,7 @@ BEGINinterface(var) /* name must also be changed in ENDinterface macro! */
rsRetVal (*ConvToNumber)(var_t *pThis);
rsRetVal (*ConvToBool)(var_t *pThis);
rsRetVal (*ConvToString)(var_t *pThis);
+ rsRetVal (*Obj2Str)(var_t *pThis, cstr_t*);
rsRetVal (*Duplicate)(var_t *pThis, var_t **ppNew);
ENDinterface(var)
#define varCURR_IF_VERSION 1 /* increment whenever you change the interface above! */
diff --git a/runtime/vmop.c b/runtime/vmop.c
index 219315c4..fcacb15b 100644
--- a/runtime/vmop.c
+++ b/runtime/vmop.c
@@ -25,6 +25,7 @@
*/
#include "config.h"
+#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
@@ -81,6 +82,39 @@ CODESTARTobjDebugPrint(vmop)
ENDobjDebugPrint(vmop)
+/* This function is similar to DebugPrint, but does not send its output to
+ * the debug log but instead to a caller-provided string. The idea here is that
+ * we can use this string to get a textual representation of an operation.
+ * Among others, this is useful for creating testbenches, our first use case for
+ * it. Here, it enables simple comparison of the resulting program to a
+ * reference program by simple string compare.
+ * Note that the caller must initialize the string object. We always add
+ * data to it. So, it can be easily combined into a chain of methods
+ * to generate the final string.
+ * rgerhards, 2008-07-04
+ */
+static rsRetVal
+Obj2Str(vmop_t *pThis, cstr_t *pstrPrg)
+{
+ uchar *pOpcodeName;
+ uchar szBuf[2048];
+ size_t lenBuf;
+ DEFiRet;
+
+ ISOBJ_TYPE_assert(pThis, vmop);
+ assert(pstrPrg != NULL);
+ vmopOpcode2Str(pThis, &pOpcodeName);
+ lenBuf = snprintf((char*) szBuf, sizeof(szBuf), "%s\t", pOpcodeName);
+ CHKiRet(rsCStrAppendStrWithLen(pstrPrg, szBuf, lenBuf));
+ if(pThis->operand.pVar != NULL)
+ CHKiRet(var.Obj2Str(pThis->operand.pVar, pstrPrg));
+ CHKiRet(rsCStrAppendChar(pstrPrg, '\n'));
+
+finalize_it:
+ RETiRet;
+}
+
+
/* set operand (variant case)
* rgerhards, 2008-02-20
*/
@@ -206,8 +240,6 @@ CODESTARTobjQueryInterface(vmop)
* work here (if we can support an older interface version - that,
* of course, also affects the "if" above).
*/
- //xxxpIf->oID = OBJvmop;
-
pIf->Construct = vmopConstruct;
pIf->ConstructFinalize = vmopConstructFinalize;
pIf->Destruct = vmopDestruct;
@@ -215,6 +247,7 @@ CODESTARTobjQueryInterface(vmop)
pIf->SetOpcode = vmopSetOpcode;
pIf->SetVar = vmopSetVar;
pIf->Opcode2Str = vmopOpcode2Str;
+ pIf->Obj2Str = Obj2Str;
finalize_it:
ENDobjQueryInterface(vmop)
diff --git a/runtime/vmop.h b/runtime/vmop.h
index 97f924d7..c3d5d5f4 100644
--- a/runtime/vmop.h
+++ b/runtime/vmop.h
@@ -26,6 +26,7 @@
#define INCLUDED_VMOP_H
#include "ctok_token.h"
+#include "stringbuf.h"
/* machine instructions types */
typedef enum { /* do NOT start at 0 to detect uninitialized types after calloc() */
@@ -83,6 +84,7 @@ BEGINinterface(vmop) /* name must also be changed in ENDinterface macro! */
rsRetVal (*SetOpcode)(vmop_t *pThis, opcode_t opcode);
rsRetVal (*SetVar)(vmop_t *pThis, var_t *pVar);
rsRetVal (*Opcode2Str)(vmop_t *pThis, uchar **ppName);
+ rsRetVal (*Obj2Str)(vmop_t *pThis, cstr_t *pstr);
ENDinterface(vmop)
#define vmopCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */
diff --git a/runtime/vmprg.c b/runtime/vmprg.c
index a2b744d7..705e6948 100644
--- a/runtime/vmprg.c
+++ b/runtime/vmprg.c
@@ -24,12 +24,14 @@
*/
#include "config.h"
+#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "rsyslog.h"
#include "obj.h"
#include "vmprg.h"
+#include "stringbuf.h"
/* static data */
DEFobjStaticHelpers
@@ -79,6 +81,40 @@ CODESTARTobjDebugPrint(vmprg)
ENDobjDebugPrint(vmprg)
+/* This function is similar to DebugPrint, but does not send its output to
+ * the debug log but instead to a caller-provided string. The idea here is that
+ * we can use this string to get a textual representation of a bytecode program.
+ * Among others, this is useful for creating testbenches, our first use case for
+ * it. Here, it enables simple comparison of the resulting program to a
+ * reference program by simple string compare.
+ * Note that the caller must initialize the string object. We always add
+ * data to it. So, it can be easily combined into a chain of methods
+ * to generate the final string.
+ * rgerhards, 2008-07-04
+ */
+static rsRetVal
+Obj2Str(vmprg_t *pThis, cstr_t *pstrPrg)
+{
+ uchar szAddr[12];
+ vmop_t *pOp;
+ int i;
+ int lenAddr;
+ DEFiRet;
+
+ ISOBJ_TYPE_assert(pThis, vmprg);
+ assert(pstrPrg != NULL);
+ i = 0; /* "program counter" */
+ for(pOp = pThis->vmopRoot ; pOp != NULL ; pOp = pOp->pNext) {
+ lenAddr = snprintf((char*)szAddr, sizeof(szAddr), "%8.8d: ", i++);
+ CHKiRet(rsCStrAppendStrWithLen(pstrPrg, szAddr, lenAddr));
+ vmop.Obj2Str(pOp, pstrPrg);
+ }
+
+finalize_it:
+ RETiRet;
+}
+
+
/* add an operation (instruction) to the end of the current program. This
* function is expected to be called while creating the program, but never
* again after this is done and it is being executed. Results are undefined if
@@ -146,12 +182,11 @@ CODESTARTobjQueryInterface(vmprg)
* work here (if we can support an older interface version - that,
* of course, also affects the "if" above).
*/
- //xxxpIf->oID = OBJvmprg;
-
pIf->Construct = vmprgConstruct;
pIf->ConstructFinalize = vmprgConstructFinalize;
pIf->Destruct = vmprgDestruct;
pIf->DebugPrint = vmprgDebugPrint;
+ pIf->Obj2Str = Obj2Str;
pIf->AddOperation = vmprgAddOperation;
pIf->AddVarOperation = vmprgAddVarOperation;
finalize_it:
diff --git a/runtime/vmprg.h b/runtime/vmprg.h
index db1f62f0..c1042f7d 100644
--- a/runtime/vmprg.h
+++ b/runtime/vmprg.h
@@ -38,7 +38,7 @@
#define INCLUDED_VMPRG_H
#include "vmop.h"
-
+#include "stringbuf.h"
/* the vmprg object */
typedef struct vmprg_s {
@@ -56,6 +56,7 @@ BEGINinterface(vmprg) /* name must also be changed in ENDinterface macro! */
rsRetVal (*Destruct)(vmprg_t **ppThis);
rsRetVal (*AddOperation)(vmprg_t *pThis, vmop_t *pOp);
rsRetVal (*AddVarOperation)(vmprg_t *pThis, opcode_t opcode, var_t *pVar);
+ rsRetVal (*Obj2Str)(vmprg_t *pThis, cstr_t *pstr);
ENDinterface(vmprg)
#define vmprgCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */
diff --git a/tcpsrv.c b/tcpsrv.c
index 8aeb9f5c..73602135 100644
--- a/tcpsrv.c
+++ b/tcpsrv.c
@@ -1,8 +1,7 @@
/* tcpsrv.c
*
* Common code for plain TCP based servers. This is currently being
- * utilized by imtcp and imgssapi. I suspect that when we implement
- * SSL/TLS, that module could also use tcpsrv.
+ * utilized by imtcp and imgssapi.
*
* There are actually two classes within the tcpserver code: one is
* the tcpsrv itself, the other one is its sessions. This is a helper
diff --git a/tests/.gitignore b/tests/.gitignore
index e961c766..a8177ad4 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -1,3 +1,3 @@
-rscript_parse
+rscript
rt_init
tmp
diff --git a/tests/1.rstest b/tests/1.rstest
new file mode 100644
index 00000000..5c152589
--- /dev/null
+++ b/tests/1.rstest
@@ -0,0 +1,26 @@
+# a simple RainerScript test
+result: 0
+in:
+'test 1' <> $var or /* some comment */($SEVERITY == -4 +5 -(3 * - 2) and $fromhost == '127.0.0.1') then
+$$$
+out:
+00000000: PUSHCONSTANT test 1[cstr]
+00000001: PUSHMSGVAR var[cstr]
+00000002: !=
+00000003: PUSHMSGVAR severity[cstr]
+00000004: PUSHCONSTANT 4[nbr]
+00000005: UNARY_MINUS
+00000006: PUSHCONSTANT 5[nbr]
+00000007: +
+00000008: PUSHCONSTANT 3[nbr]
+00000009: PUSHCONSTANT 2[nbr]
+00000010: UNARY_MINUS
+00000011: *
+00000012: -
+00000013: ==
+00000014: PUSHMSGVAR fromhost[cstr]
+00000015: PUSHCONSTANT 127.0.0.1[cstr]
+00000016: ==
+00000017: and
+00000018: or
+$$$
diff --git a/tests/2.rstest b/tests/2.rstest
new file mode 100644
index 00000000..7fb5b799
--- /dev/null
+++ b/tests/2.rstest
@@ -0,0 +1,10 @@
+# a simple RainerScript test
+result: 0
+in:
+$msg contains 'test' then
+$$$
+out:
+00000000: PUSHMSGVAR msg[cstr]
+00000001: PUSHCONSTANT test[cstr]
+00000002: contains
+$$$
diff --git a/tests/DevNull.cfgtest b/tests/DevNull.cfgtest
new file mode 100644
index 00000000..d30d936b
--- /dev/null
+++ b/tests/DevNull.cfgtest
@@ -0,0 +1,3 @@
+rsyslogd: CONFIG ERROR: there are no active actions configured. Inputs will run, but no output whatsoever is created. [try http://www.rsyslog.com/e/2103 ]
+rsyslogd: EMERGENCY CONFIGURATION ACTIVATED - fix rsyslog config file!
+rsyslogd: End of config validation run. Bye.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index d85a56f8..2cfd5bfb 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,14 +1,29 @@
-check_PROGRAMS = rt_init rscript_parse
-TESTS = $(check_PROGRAMS)
+check_PROGRAMS = rt_init rscript
+TESTS = $(check_PROGRAMS) cfg.sh
+TESTS_ENVIRONMENT = RSYSLOG_MODDIR='$(abs_top_builddir)'/runtime/.libs/
+#TESTS = $(check_PROGRAMS)
test_files = testbench.h runtime-dummy.c
+EXTRA_DIST=1.rstest 2.rstest err1.rstest \
+ cfg.sh \
+ cfg1.cfgtest \
+ cfg1.testin \
+ cfg2.cfgtest \
+ cfg2.testin \
+ cfg3.cfgtest \
+ cfg3.testin \
+ cfg4.cfgtest \
+ cfg4.testin \
+ DevNull.cfgtest \
+ err1.rstest \
+ NoExistFile.cfgtest
rt_init_SOURCES = rt-init.c $(test_files)
rt_init_CPPFLAGS = -I$(top_srcdir) $(pthreads_cflags) $(rsrt_cflags)
rt_init_LDADD = $(rsrt_libs) $(zlib_libs) $(pthreads_libs)
rt_init_LDFLAGS = -export-dynamic
-rscript_parse_SOURCES = rscript-parse.c $(test_files)
-rscript_parse_CPPFLAGS = -I$(top_srcdir) $(pthreads_cflags) $(rsrt_cflags)
-rscript_parse_LDADD = $(rsrt_libs) $(zlib_libs) $(pthreads_libs)
-rscript_parse_LDFLAGS = -export-dynamic
+rscript_SOURCES = rscript.c $(test_files)
+rscript_CPPFLAGS = -I$(top_srcdir) $(pthreads_cflags) $(rsrt_cflags)
+rscript_LDADD = $(rsrt_libs) $(zlib_libs) $(pthreads_libs)
+rscript_LDFLAGS = -export-dynamic
diff --git a/tests/NoExistFile.cfgtest b/tests/NoExistFile.cfgtest
new file mode 100644
index 00000000..4cbcc029
--- /dev/null
+++ b/tests/NoExistFile.cfgtest
@@ -0,0 +1,3 @@
+rsyslogd: CONFIG ERROR: could not interpret master config file '/This/does/not/exist'. [try http://www.rsyslog.com/e/2013 ]
+rsyslogd: EMERGENCY CONFIGURATION ACTIVATED - fix rsyslog config file!
+rsyslogd: End of config validation run. Bye.
diff --git a/tests/cfg.sh b/tests/cfg.sh
new file mode 100755
index 00000000..99729823
--- /dev/null
+++ b/tests/cfg.sh
@@ -0,0 +1,139 @@
+# /bin/bash
+# This is a simple shell script that carries out some checks against
+# configurations we expect from some provided config files. We use
+# rsyslogd's verifcation function. Note that modifications to the
+# config elements, or even simple text changes, cause these checks to
+# fail. However, it should be fairly easy to adapt them to the changed
+# environment. And while nothing changed, they permit is to make sure
+# that everything works well and is not broken by interim changes.
+# Note that we always compare starting with the second output line.
+# This is because the first line contains the rsyslog version ;)
+# rgerhards, 2008-07-29
+#
+# Part of the testbench for rsyslog.
+#
+# 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.
+#set -x
+rm -f tmp
+echo "local directory"
+#
+# check empty config file
+#
+../tools/rsyslogd -c3 -N1 -f/dev/null 2>&1 |tail --lines=+2 > tmp
+cmp tmp $srcdir/DevNull.cfgtest
+if [ ! $? -eq 0 ]; then
+echo "DevNull.cfgtest failed"
+echo "Expected:"
+cat $srcdir/DevNull.cfgtest
+echo "Received:"
+cat tmp
+exit 1
+else
+echo "DevNull.cfgtest succeeded"
+fi;
+#
+# check missing config file
+#
+../tools/rsyslogd -c3 -N1 -f/This/does/not/exist 2>&1 |tail --lines=+2 > tmp
+cmp tmp $srcdir/NoExistFile.cfgtest
+if [ ! $? -eq 0 ]; then
+echo "NoExistFile.cfgtest failed"
+echo "Expected:"
+cat $srcdir/NoExistFile.cfgtest
+echo "Received:"
+cat tmp
+exit 1
+else
+echo "NoExistFile.cfgtest succeeded"
+fi;
+
+
+# TODO: re-enable the following checks. They need to have support in
+# rsyslogd so that the log file name is NOT contained in the error
+# messages - this prevents proper comparison in make distcheck
+rm -f tmp
+exit 0
+
+#
+# check config with invalid directive
+#
+../tools/rsyslogd -c3 -u2 -N1 -f$srcdir/cfg1.testin 2>&1 |tail --lines=+2 > tmp
+cmp tmp $srcdir/cfg1.cfgtest
+if [ ! $? -eq 0 ]; then
+echo "cfg1.cfgtest failed"
+echo "Expected:"
+cat $srcdir/cfg1.cfgtest
+echo "Received:"
+cat tmp
+exit 1
+else
+echo "cfg1.cfgtest succeeded"
+fi;
+#
+# now check for included config file. We use a sample similar to
+# the one with the invalid config directive, so that we may see
+# an effect of the included config ;)
+#
+../tools/rsyslogd -c3 -u2 -N1 -f$srcdir/cfg2.testin 2>&1 |tail --lines=+2 > tmp
+cmp tmp $srcdir/cfg2.cfgtest
+if [ ! $? -eq 0 ]; then
+echo "cfg2.cfgtest failed"
+echo "Expected:"
+cat $srcdir/cfg2.cfgtest
+echo "Received:"
+cat tmp
+exit 1
+else
+echo "cfg2.cfgtest succeeded"
+fi;
+#
+# check included config file, where included file does not exist
+#
+../tools/rsyslogd -c3 -u2 -N1 -f$srcdir/cfg3.testin 2>&1 |tail --lines=+2 > tmp
+cmp tmp $srcdir/cfg3.cfgtest
+if [ ! $? -eq 0 ]; then
+echo "cfg3.cfgtest failed"
+echo "Expected:"
+cat $srcdir/cfg3.cfgtest
+echo "Received:"
+cat tmp
+exit 1
+else
+echo "cfg3.cfgtest succeeded"
+fi;
+#
+# check a reasonable complex, but correct, log file
+#
+../tools/rsyslogd -c3 -u2 -N1 -f$srcdir/cfg4.testin 2>&1 |tail --lines=+2 > tmp
+cmp tmp $srcdir/cfg4.cfgtest
+if [ ! $? -eq 0 ]; then
+echo "cfg4.cfgtest failed"
+echo "Expected:"
+cat $srcdir/cfg4.cfgtest
+echo "Received:"
+cat tmp
+exit 1
+else
+echo "cfg4.cfgtest succeeded"
+fi;
+#
+# done, some cleanup
+#
+rm -f tmp
diff --git a/tests/cfg1.cfgtest b/tests/cfg1.cfgtest
new file mode 100644
index 00000000..099ba929
--- /dev/null
+++ b/tests/cfg1.cfgtest
@@ -0,0 +1,3 @@
+rsyslogd: invalid or yet-unknown config file command - have you forgotten to load a module? [try http://www.rsyslog.com/e/3003 ]
+rsyslogd: the last error occured in ./cfg1.testin, line 2
+rsyslogd: End of config validation run. Bye.
diff --git a/tests/cfg1.testin b/tests/cfg1.testin
new file mode 100644
index 00000000..7d7b594c
--- /dev/null
+++ b/tests/cfg1.testin
@@ -0,0 +1,2 @@
+*.* *
+$invaliddirective test
diff --git a/tests/cfg2.cfgtest b/tests/cfg2.cfgtest
new file mode 100644
index 00000000..b44a487e
--- /dev/null
+++ b/tests/cfg2.cfgtest
@@ -0,0 +1,3 @@
+rsyslogd: invalid or yet-unknown config file command - have you forgotten to load a module? [try http://www.rsyslog.com/e/3003 ]
+rsyslogd: the last error occured in cfg1.testin, line 2
+rsyslogd: End of config validation run. Bye.
diff --git a/tests/cfg2.testin b/tests/cfg2.testin
new file mode 100644
index 00000000..b6d98c8f
--- /dev/null
+++ b/tests/cfg2.testin
@@ -0,0 +1 @@
+$includeconfig cfg1.testin
diff --git a/tests/cfg3.cfgtest b/tests/cfg3.cfgtest
new file mode 100644
index 00000000..68bc17d4
--- /dev/null
+++ b/tests/cfg3.cfgtest
@@ -0,0 +1,5 @@
+rsyslogd: error accessing config file or directory 'file-does-not-exist': No such file or directory [try http://www.rsyslog.com/e/2040 ]
+rsyslogd: the last error occured in ./cfg3.testin, line 1
+rsyslogd: CONFIG ERROR: there are no active actions configured. Inputs will run, but no output whatsoever is created. [try http://www.rsyslog.com/e/2103 ]
+rsyslogd: EMERGENCY CONFIGURATION ACTIVATED - fix rsyslog config file!
+rsyslogd: End of config validation run. Bye.
diff --git a/tests/cfg3.testin b/tests/cfg3.testin
new file mode 100644
index 00000000..9789d939
--- /dev/null
+++ b/tests/cfg3.testin
@@ -0,0 +1 @@
+$includeconfig file-does-not-exist
diff --git a/tests/cfg4.cfgtest b/tests/cfg4.cfgtest
new file mode 100644
index 00000000..04acf84f
--- /dev/null
+++ b/tests/cfg4.cfgtest
@@ -0,0 +1 @@
+rsyslogd: End of config validation run. Bye.
diff --git a/tests/cfg4.testin b/tests/cfg4.testin
new file mode 100644
index 00000000..a49c0fb6
--- /dev/null
+++ b/tests/cfg4.testin
@@ -0,0 +1,67 @@
+# This is more or less the sample config, but without imklog being
+# active. imklog must not always be present and as such may spoil
+# our testing result. The core point at this test is that a valid
+# config file should not lead to any error messages.
+# It may be a good idea to update this file from time to time, so that
+# it contains a reasonable complex config sample.
+
+# if you experience problems, check
+# http://www.rsyslog.com/troubleshoot for assistance
+
+# rsyslog v3: load input modules
+# If you do not load inputs, nothing happens!
+# You may need to set the module load path if modules are not found.
+
+#$ModLoad immark # provides --MARK-- message capability
+#$ModLoad imuxsock # provides support for local system logging (e.g. via logger command)
+#$ModLoad imklog # kernel logging (formerly provided by rklogd)
+
+# Log all kernel messages to the console.
+# Logging much else clutters up the screen.
+#kern.* /dev/console
+
+# Log anything (except mail) of level info or higher.
+# Don't log private authentication messages!
+*.info;mail.none;authpriv.none;cron.none -/var/log/messages
+
+# The authpriv file has restricted access.
+authpriv.* /var/log/secure
+
+# Log all the mail messages in one place.
+mail.* -/var/log/maillog
+
+
+# Log cron stuff
+cron.* -/var/log/cron
+
+# Everybody gets emergency messages
+*.emerg *
+
+# Save news errors of level crit and higher in a special file.
+uucp,news.crit -/var/log/spooler
+
+# Save boot messages also to boot.log
+local7.* /var/log/boot.log
+
+# Remote Logging (we use TCP for reliable delivery)
+# An on-disk queue is created for this action. If the remote host is
+# down, messages are spooled to disk and sent when it is up again.
+#$WorkDirectory /rsyslog/spool # where to place spool files
+#$ActionQueueFileName uniqName # unique name prefix for spool files
+#$ActionQueueMaxDiskSpace 1g # 1gb space limit (use as much as possible)
+#$ActionQueueSaveOnShutdown on # save messages to disk on shutdown
+#$ActionQueueType LinkedList # run asynchronously
+#$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:514
+
+
+# ######### Receiving Messages from Remote Hosts ##########
+# TCP Syslog Server:
+# provides TCP syslog reception and GSS-API (if compiled to support it)
+#$ModLoad imtcp.so # load module
+#$InputTCPServerRun 514 # start up TCP listener at port 514
+
+# UDP Syslog Server:
+#$ModLoad imudp.so # provides UDP syslog reception
+#$UDPServerRun 514 # start a UDP syslog server at standard port 514
diff --git a/tests/err1.rstest b/tests/err1.rstest
new file mode 100644
index 00000000..8c56887e
--- /dev/null
+++ b/tests/err1.rstest
@@ -0,0 +1,7 @@
+# This test case check for an error condition
+result: -2051
+in:
+'test 1' <> == $hostname
+$$$
+out:
+$$$
diff --git a/tests/rscript-parse.c b/tests/rscript-parse.c
deleted file mode 100644
index 176f3f7e..00000000
--- a/tests/rscript-parse.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/* This test checks runtime initialization and exit. Other than that, it
- * also serves as the most simplistic sample of how a test can be coded.
- *
- * Part of the testbench for rsyslog.
- * 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 <stdio.h>
-
-#include "rsyslog.h"
-#include "testbench.h"
-#include "ctok.h"
-#include "expr.h"
-
-MODULE_TYPE_TESTBENCH
-/* define addtional objects we need for our tests */
-DEFobjCurrIf(expr)
-DEFobjCurrIf(ctok)
-DEFobjCurrIf(ctok_token)
-
-BEGINInit
-CODESTARTInit
- pErrObj = "expr"; CHKiRet(objUse(expr, CORE_COMPONENT));
- pErrObj = "ctok"; CHKiRet(objUse(ctok, CORE_COMPONENT));
- pErrObj = "ctok_token"; CHKiRet(objUse(ctok_token, CORE_COMPONENT));
-ENDInit
-
-BEGINExit
-CODESTARTExit
-ENDExit
-
-BEGINTest
- ctok_t *tok;
- ctok_token_t *pToken;
- expr_t *pExpr;
- /* the string below is an expression as defined up to 3.19.x - note that the
- * then and the space after it MUST be present!
- */
- uchar szExpr[] = " $msg contains 'test' then ";
- /*uchar szSynErr[] = "$msg == 1 and syntaxerror ";*/
-CODESTARTTest
- /* we first need a tokenizer... */
- CHKiRet(ctok.Construct(&tok));
- CHKiRet(ctok.Setpp(tok, szExpr));
- CHKiRet(ctok.ConstructFinalize(tok));
-
- /* now construct our expression */
- CHKiRet(expr.Construct(&pExpr));
- CHKiRet(expr.ConstructFinalize(pExpr));
-
- /* ready to go... */
- CHKiRet(expr.Parse(pExpr, tok));
-
- /* we now need to parse off the "then" - and note an error if it is
- * missing...
- *
- * rgerhards, 2008-07-01: we disable the check below, because I can not
- * find the cause of the misalignment. The problem is that pToken structure has
- * a different member alignment inside the runtime library then inside of
- * this program. I checked compiler options, but could not find the cause.
- * Should anyone have any insight, I'd really appreciate if you drop me
- * a line.
- */
-#if 0
- CHKiRet(ctok.GetToken(tok, &pToken));
- if(pToken->tok != ctok_THEN) {
-//printf("invalid token, probably due to invalid alignment between runtime lib and this program\n");
- ctok_token.Destruct(&pToken);
- ABORT_FINALIZE(RS_RET_SYNTAX_ERROR);
- }
-
- ctok_token.Destruct(&pToken); /* no longer needed */
-#endif
-
- /* we are done, so we now need to restore things */
- CHKiRet(ctok.Destruct(&tok));
-finalize_it:
- /* here we may do custom error reporting */
- if(iRet != RS_RET_OK) {
- uchar *pp;
- ctok.Getpp(tok, &pp);
- printf("error on or before '%s'\n", pp);
- }
-ENDTest
diff --git a/tests/rscript.c b/tests/rscript.c
new file mode 100644
index 00000000..d4e8caeb
--- /dev/null
+++ b/tests/rscript.c
@@ -0,0 +1,259 @@
+/* This test checks runtime initialization and exit. Other than that, it
+ * also serves as the most simplistic sample of how a test can be coded.
+ *
+ * Part of the testbench for rsyslog.
+ *
+ * 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 <stdio.h>
+#include <glob.h>
+#include <sys/stat.h>
+
+#include "rsyslog.h"
+#include "testbench.h"
+#include "ctok.h"
+#include "expr.h"
+
+MODULE_TYPE_TESTBENCH
+/* define addtional objects we need for our tests */
+DEFobjCurrIf(expr)
+DEFobjCurrIf(ctok)
+DEFobjCurrIf(ctok_token)
+DEFobjCurrIf(vmprg)
+
+BEGINInit
+CODESTARTInit
+ pErrObj = "expr"; CHKiRet(objUse(expr, CORE_COMPONENT));
+ pErrObj = "ctok"; CHKiRet(objUse(ctok, CORE_COMPONENT));
+ pErrObj = "ctok_token"; CHKiRet(objUse(ctok_token, CORE_COMPONENT));
+ pErrObj = "vmprg"; CHKiRet(objUse(vmprg, CORE_COMPONENT));
+ENDInit
+
+BEGINExit
+CODESTARTExit
+ENDExit
+
+
+/* perform a single test. This involves compiling the test script,
+ * checking the result of the compilation (iRet) and a check of the
+ * generated program (via a simple strcmp). The resulting program
+ * check is only done if the test should not detect a syntax error
+ * (for obvious reasons, there is no point in checking the result of
+ * a failed compilation).
+ * rgerhards, 2008-07--07
+ */
+static rsRetVal
+PerformTest(cstr_t *pstrIn, rsRetVal iRetExpected, cstr_t *pstrOut)
+{
+ cstr_t *pstrPrg = NULL;
+ ctok_t *tok = NULL;
+ ctok_token_t *pToken = NULL;
+ expr_t *pExpr;
+ rsRetVal localRet;
+ DEFiRet;
+
+ /* we first need a tokenizer... */
+ CHKiRet(ctok.Construct(&tok));
+ CHKiRet(ctok.Setpp(tok, rsCStrGetSzStr(pstrIn)));
+ CHKiRet(ctok.ConstructFinalize(tok));
+
+ /* now construct our expression */
+ CHKiRet(expr.Construct(&pExpr));
+ CHKiRet(expr.ConstructFinalize(pExpr));
+
+ /* ready to go... */
+ localRet = expr.Parse(pExpr, tok);
+
+ /* check if we expected an error */
+ if(localRet != iRetExpected) {
+ printf("Error in compile return code. Expected %d, received %d\n",
+ iRetExpected, localRet);
+ CHKiRet(rsCStrConstruct(&pstrPrg));
+ CHKiRet(vmprg.Obj2Str(pExpr->pVmprg, pstrPrg));
+ printf("generated vmprg:\n%s\n", rsCStrGetSzStr(pstrPrg));
+ ABORT_FINALIZE(iRetExpected == RS_RET_OK ? localRet : RS_RET_ERR);
+ }
+
+ if(iRetExpected != RS_RET_OK)
+ FINALIZE; /* if we tested an error case, we are done */
+
+ /* OK, we got a compiled program, so now let's compare that */
+
+ CHKiRet(rsCStrConstruct(&pstrPrg));
+ CHKiRet(vmprg.Obj2Str(pExpr->pVmprg, pstrPrg));
+
+ if(strcmp((char*)rsCStrGetSzStr(pstrPrg), (char*)rsCStrGetSzStr(pstrOut))) {
+ printf("error: compiled program different from expected result!\n");
+ printf("generated vmprg:\n%s\n", rsCStrGetSzStr(pstrPrg));
+ printf("expected:\n%s\n", rsCStrGetSzStr(pstrOut));
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+
+finalize_it:
+ /* we are done, so we now need to restore things */
+ if(pToken != NULL)
+ ctok_token.Destruct(&pToken); /* no longer needed */
+ if(pstrPrg != NULL)
+ rsCStrDestruct(&pstrPrg);
+ if(tok != NULL)
+ ctok.Destruct(&tok);
+ RETiRet;
+}
+
+
+/* a helper macro to generate some often-used code... */
+#define CHKEOF \
+ if(feof(fp)) { \
+ printf("error: unexpected end of control file %s\n", pszFileName); \
+ ABORT_FINALIZE(RS_RET_ERR); \
+ }
+/* process a single test file
+ * Note that we do not do a real parser here. The effort is not
+ * justified by what we need to do. So it is a quick shot.
+ * rgerhards, 2008-07-07
+ */
+static rsRetVal
+ProcessTestFile(uchar *pszFileName)
+{
+ FILE *fp;
+ char *lnptr = NULL;
+ size_t lenLn;
+ cstr_t *pstrIn = NULL;
+ cstr_t *pstrOut = NULL;
+ rsRetVal iRetExpected;
+ DEFiRet;
+
+ if((fp = fopen((char*)pszFileName, "r")) == NULL) {
+ perror((char*)pszFileName);
+ ABORT_FINALIZE(RS_RET_FILE_NOT_FOUND);
+ }
+
+ /* skip comments at start of file */
+
+ getline(&lnptr, &lenLn, fp);
+ while(!feof(fp)) {
+ if(*lnptr == '#')
+ getline(&lnptr, &lenLn, fp);
+ else
+ break; /* first non-comment */
+ }
+ CHKEOF;
+
+ /* once we had a comment, the next line MUST be "result: <nbr>". Anything
+ * after nbr is simply ignored.
+ */
+ if(sscanf(lnptr, "result: %d", &iRetExpected) != 1) {
+ printf("error in result line, scanf failed, line: '%s'\n", lnptr);
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+ getline(&lnptr, &lenLn, fp); CHKEOF;
+
+ /* and now we look for "in:" (and again ignore the rest...) */
+ if(strncmp(lnptr, "in:", 3)) {
+ printf("error: expected 'in:'-line, but got: '%s'\n", lnptr);
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+ /* if we reach this point, we need to read in the input script. It is
+ * terminated by a line with three sole $ ($$$\n)
+ */
+ CHKiRet(rsCStrConstruct(&pstrIn));
+ getline(&lnptr, &lenLn, fp); CHKEOF;
+ while(strncmp(lnptr, "$$$\n", 4)) {
+ CHKiRet(rsCStrAppendStr(pstrIn, (uchar*)lnptr));
+ getline(&lnptr, &lenLn, fp); CHKEOF;
+ }
+ getline(&lnptr, &lenLn, fp); CHKEOF; /* skip $$$-line */
+
+ /* and now we look for "out:" (and again ignore the rest...) */
+ if(strncmp(lnptr, "out:", 4)) {
+ printf("error: expected 'out:'-line, but got: '%s'\n", lnptr);
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+ /* if we reach this point, we need to read in the expected program code. It is
+ * terminated by a line with three sole $ ($$$\n)
+ */
+ CHKiRet(rsCStrConstruct(&pstrOut));
+ getline(&lnptr, &lenLn, fp); CHKEOF;
+ while(strncmp(lnptr, "$$$\n", 4)) {
+ CHKiRet(rsCStrAppendStr(pstrOut, (uchar*)lnptr));
+ getline(&lnptr, &lenLn, fp); CHKEOF;
+ }
+
+ /* un-comment for testing:
+ * printf("iRet: %d, script: %s\n, out: %s\n", iRetExpected, rsCStrGetSzStr(pstrIn),rsCStrGetSzStr(pstrOut));
+ */
+ if(rsCStrGetSzStr(pstrIn) == NULL) {
+ printf("error: input script is empty!\n");
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+ if(rsCStrGetSzStr(pstrOut) == NULL && iRetExpected == RS_RET_OK) {
+ printf("error: output script is empty!\n");
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+
+ CHKiRet(PerformTest(pstrIn, iRetExpected, pstrOut));
+
+finalize_it:
+ if(pstrIn != NULL)
+ rsCStrDestruct(&pstrIn);
+ if(pstrOut != NULL)
+ rsCStrDestruct(&pstrOut);
+ RETiRet;
+}
+
+
+/* This test is parameterized. It search for test control files and
+ * loads all that it finds. To add tests, simply create new .rstest
+ * files.
+ * rgerhards, 2008-07-07
+ */
+BEGINTest
+ uchar *testFile;
+ glob_t testFiles;
+ size_t i = 0;
+ struct stat fileInfo;
+CODESTARTTest
+ glob("*.rstest", GLOB_MARK, NULL, &testFiles);
+
+ for(i = 0; i < testFiles.gl_pathc; i++) {
+ testFile = (uchar*) testFiles.gl_pathv[i];
+
+ if(stat((char*) testFile, &fileInfo) != 0)
+ continue; /* continue with the next file if we can't stat() the file */
+
+ /* all regular files are run through the test logic. Symlinks don't work. */
+ if(S_ISREG(fileInfo.st_mode)) { /* config file */
+ printf("processing RainerScript test file '%s'...\n", testFile);
+ iRet = ProcessTestFile((uchar*) testFile);
+ if(iRet != RS_RET_OK) {
+ /* in this case, re-run with debugging on */
+ printf("processing test case failed with %d, re-running with debug messages:\n",
+ iRet);
+ Debug = 1; /* these two are dirty, but we need them today... */
+ debugging_on = 1;
+ CHKiRet(ProcessTestFile((uchar*) testFile));
+ }
+ }
+ }
+ globfree(&testFiles);
+
+finalize_it:
+ENDTest
diff --git a/tests/testbench.h b/tests/testbench.h
index 6f26724a..12687743 100644
--- a/tests/testbench.h
+++ b/tests/testbench.h
@@ -40,7 +40,8 @@ int main(int __attribute__((unused)) argc, char __attribute__((unused)) *argv[])
CHKiRet(doTest()); \
CHKiRet(doExit()); \
finalize_it: \
- printf("test returns iRet %d\n", iRet); \
+ if(iRet != RS_RET_OK) \
+ printf("test returns iRet %d\n", iRet); \
RETiRet; \
}
diff --git a/tools/Makefile.am b/tools/Makefile.am
index b2b7a8ca..a265af9c 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -21,9 +21,13 @@ rsyslogd_SOURCES = \
pidfile.h \
\
../dirty.h
-
rsyslogd_CPPFLAGS = $(pthreads_cflags) $(rsrt_cflags)
rsyslogd_LDADD = $(zlib_libs) $(pthreads_libs) $(rsrt_libs)
rsyslogd_LDFLAGS = -export-dynamic
+if ENABLE_DIAGTOOLS
+sbin_PROGRAMS += rsyslog_diag_hostname
+rsyslog_diag_hostname_SOURCES = gethostn.c
+endif
+
EXTRA_DIST = $(man_MANS)
diff --git a/tools/gethostn.c b/tools/gethostn.c
new file mode 100644
index 00000000..df7ce38b
--- /dev/null
+++ b/tools/gethostn.c
@@ -0,0 +1,47 @@
+/* gethostn - a small diagnostic utility to show what the
+ * gethostname() API returns. Of course, this tool duplicates
+ * functionality already found in other tools. But the point is
+ * that the API shall be called by a program that is compiled like
+ * rsyslogd and does exactly what rsyslog does.
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int main(int __attribute__((unused)) argc, char __attribute__((unused)) *argv[])
+{
+ char hostname[4096]; /* this should always be sufficient ;) */
+ int err;
+
+ err = gethostname(hostname, sizeof(hostname));
+
+ if(err) {
+ perror("gethostname failed");
+ exit(1);
+ }
+
+ printf("hostname of this system is '%s'.\n", hostname);
+
+ return 0;
+}
diff --git a/tools/iminternal.c b/tools/iminternal.c
index 60460a99..0ceff3d8 100644
--- a/tools/iminternal.c
+++ b/tools/iminternal.c
@@ -185,6 +185,5 @@ rsRetVal modExitIminternal(void)
RETiRet;
}
-/*
- * vi:set ai:
+/* vim:set ai:
*/
diff --git a/tools/omfwd.c b/tools/omfwd.c
index 1b617ee1..df2f0342 100644
--- a/tools/omfwd.c
+++ b/tools/omfwd.c
@@ -509,6 +509,9 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1)
* applies to TCP-based syslog only and is ignored when specified with UDP).
* That is not yet implemented.
* rgerhards, 2006-12-07
+ * In order to support IPv6 addresses, we must introduce an extension to
+ * the hostname. If it is in square brackets, whatever is in them is treated as
+ * the hostname - without any exceptions ;) -- rgerhards, 2008-08-05
*/
if(*p == '(') {
/* at this position, it *must* be an option indicator */
@@ -555,6 +558,7 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1)
*/
errmsg.LogError(0, NO_ERRCODE, "Option block not terminated in forwarding action.");
}
+
/* extract the host first (we do a trick - we replace the ';' or ':' with a '\0')
* now skip to port and then template name. rgerhards 2005-07-06
*/
@@ -604,6 +608,7 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1)
} else {
CHKmalloc(pData->f_hname = strdup((char*) q));
}
+dbgprintf("hostname '%s', port '%s'\n", pData->f_hname, pData->port);
/* process template */
CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS,
diff --git a/tools/rsyslogd.8 b/tools/rsyslogd.8
index 91f2016e..05905412 100644
--- a/tools/rsyslogd.8
+++ b/tools/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 "11 July 2008" "Version 3.18.0" "Linux System Administration"
+.TH RSYSLOGD 8 "29 July 2008" "Version 3.21.1" "Linux System Administration"
.SH NAME
rsyslogd \- reliable and extended syslogd
.SH SYNOPSIS
@@ -21,12 +21,18 @@ rsyslogd \- reliable and extended syslogd
.I hostlist
]
.RB [ " \-n " ]
+.RB [ " \-N "
+.I level
+]
.br
.RB [ " \-q " ]
.RB [ " \-Q " ]
.RB [ " \-s "
.I domainlist
]
+.RB [ " \-u "
+.I userlevel
+]
.RB [ " \-v " ]
.RB [ " \-w " ]
.RB [ " \-x " ]
@@ -166,6 +172,19 @@ Avoid auto-backgrounding. This is needed especially if the
is started and controlled by
.BR init (8).
.TP
+.B "\-N " "level"
+Do a coNfig check. Do NOT run in regular mode, just check configuration
+file correctness.
+This option is meant to verify a config file. To do so, run rsyslogd
+interactively in foreground, specifying -f <config-file> and -N level.
+The level argument modifies behaviour. Currently, 0 is the same as
+not specifying the -N option at all (so this makes limited sense) and
+1 actually activates the code. Later, higher levels will mean more
+verbosity (this is a forward-compatibility option).
+.B rsyslogd
+is started and controlled by
+.BR init (8).
+.TP
.BI "\-q " "add hostname if DNS fails during ACL processing"
During ACL processing, hostnames are resolved to IP addreses for
performance reasons. If DNS fails during that process, the hostname
@@ -186,6 +205,18 @@ is specified and the host logging resolves to satu.infodrom.north.de
no domain would be cut, you will have to specify two domains like:
.BR "\-s north.de:infodrom.north.de" .
.TP
+.BI "\-u " "userlevel"
+This is a "catch all" option for some very seldomly-used user settings.
+The "userlevel" variable selects multiple things. Add the specific values
+to get the combined effect of them.
+A value of 1 prevents rsyslogd from parsing hostnames and tags inside
+messages.
+A value of 2 prevents rsyslogd from changing to the root directory. This
+is almost never a good idea in production use. This option was introduced
+in support of the internal testbed.
+To combine these two features, use a userlevel of 3 (1+2). Whenever you use
+an -u option, make sure you really understand what you do and why you do it.
+.TP
.B "\-v"
Print version and exit.
.TP
diff --git a/tools/syslogd.c b/tools/syslogd.c
index e432a67d..758d5ed1 100644
--- a/tools/syslogd.c
+++ b/tools/syslogd.c
@@ -255,6 +255,7 @@ static int bFinished = 0; /* used by termination signal handler, read-only excep
* is either 0 or the number of the signal that requested the
* termination.
*/
+static int iConfigVerify = 0; /* is this just a config verify run? */
/* Intervals at which we flush out "message repeated" messages,
* in seconds after previous message is logged. After each flush,
@@ -285,6 +286,7 @@ static int bDebugPrintCfSysLineHandlerList = 1;/* output cfsyslinehandler list i
static int bDebugPrintModuleList = 1;/* output module list in debug mode? */
static uchar cCCEscapeChar = '\\';/* character to be used to start an escape sequence for control chars */
static int bEscapeCCOnRcv = 1; /* escape control characters on reception: 0 - no, 1 - yes */
+static int bErrMsgToStderr = 1; /* print error messages to stderr (in addition to everything else)? */
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 */
@@ -418,7 +420,7 @@ static void processImInternal(void);
static int usage(void)
{
fprintf(stderr, "usage: rsyslogd [-cversion] [-46AdnqQvwx] [-lhostlist] [-sdomainlist]\n"
- " [-fconffile] [-ipidfile]\n"
+ " [-fconffile] [-ipidfile] [-Nlevel]\n"
"To run rsyslogd in native mode, use \"rsyslogd -c3 <other options>\"\n\n"
"For further information see http://www.rsyslog.com/doc\n");
exit(1); /* "good" exit - done to terminate usage() */
@@ -870,6 +872,7 @@ submitErrMsg(int iErr, uchar *msg)
RETiRet;
}
+
/* rgerhards 2004-11-09: the following is a function that can be used
* to log a message orginating from the syslogd itself. In sysklogd code,
* this is done by simply calling logmsg(). However, logmsg() is changed in
@@ -908,6 +911,18 @@ logmsgInternal(int iErr, int pri, uchar *msg, int flags)
datetime.getCurrTime(&(pMsg->tTIMESTAMP)); /* use the current time! */
flags |= INTERNAL_MSG;
+ /* we now check if we should print internal messages out to stderr. This was
+ * suggested by HKS as a way to help people troubleshoot rsyslog configuration
+ * (by running it interactively. This makes an awful lot of sense, so I add
+ * it here. -- rgerhards, 2008-07-28
+ * Note that error messages can not be disable during a config verify. This
+ * permits us to process unmodified config files which otherwise contain a
+ * supressor statement.
+ */
+ if(bErrMsgToStderr || iConfigVerify) {
+ fprintf(stderr, "rsyslogd: %s\n", msg);
+ }
+
if(bHaveMainQueue == 0) { /* not yet in queued mode */
iminternalAddMsg(pri, pMsg, flags);
} else {
@@ -1771,7 +1786,7 @@ void legacyOptsParseTCP(char ch, char *arg)
static char conflict = '\0';
if((conflict == 'g' && ch == 't') || (conflict == 't' && ch == 'g')) {
- fprintf(stderr, "rsyslog: If you want to use both -g and -t, use directives instead, -%c ignored.\n", ch);
+ fprintf(stderr, "rsyslogd: If you want to use both -g and -t, use directives instead, -%c ignored.\n", ch);
return;
} else
conflict = ch;
@@ -2190,11 +2205,15 @@ startInputModules(void)
/* INIT -- Initialize syslogd from configuration table
* init() is called at initial startup AND each time syslogd is HUPed
+ * Note that if iConfigVerify is set, only the config file is verified but nothing
+ * else happens. -- rgerhards, 2008-07-28
*/
-static void
+static rsRetVal
init(void)
{
DEFiRet;
+ rsRetVal localRet;
+ int iNbrActions;
char cbuf[BUFSIZ];
char bufStartUpMsg[512];
struct sigaction sigAct;
@@ -2237,22 +2256,42 @@ init(void)
*/
conf.cfsysline((uchar*)"ResetConfigVariables");
+ conf.ReInitConf();
+
/* open the configuration file */
- if((iRet = conf.processConfFile(ConfFile)) != RS_RET_OK) {
+ localRet = conf.processConfFile(ConfFile);
+ CHKiRet(conf.GetNbrActActions(&iNbrActions));
+
+ if(localRet != RS_RET_OK) {
+ errmsg.LogError(0, localRet, "CONFIG ERROR: could not interpret master config file '%s'.", ConfFile);
+ } else if(iNbrActions == 0) {
+ errmsg.LogError(0, RS_RET_NO_ACTIONS, "CONFIG ERROR: there are no active actions configured. Inputs will "
+ "run, but no output whatsoever is created.");
+ }
+
+ if(localRet != RS_RET_OK || iNbrActions == 0) {
/* rgerhards: this code is executed to set defaults when the
* config file could not be opened. We might think about
* abandoning the run in this case - but this, too, is not
* very clever... So we stick with what we have.
* We ignore any errors while doing this - we would be lost anyhow...
*/
+ errmsg.LogError(0, NO_ERRCODE, "EMERGENCY CONFIGURATION ACTIVATED - fix rsyslog config file!");
selector_t *f = NULL;
- char szTTYNameBuf[_POSIX_TTY_NAME_MAX+1]; /* +1 for NULL character */
- dbgprintf("primary config file could not be opened - using emergency definitions.\n");
+
+ /* note: we previously used _POSIY_TTY_NAME_MAX+1, but this turned out to be
+ * too low on linux... :-S -- rgerhards, 2008-07-28
+ */
+ char szTTYNameBuf[128];
conf.cfline((uchar*)"*.ERR\t" _PATH_CONSOLE, &f);
+ conf.cfline((uchar*)"syslog.*\t" _PATH_CONSOLE, &f);
conf.cfline((uchar*)"*.PANIC\t*", &f);
+ conf.cfline((uchar*)"syslog.*\troot", &f);
if(ttyname_r(0, szTTYNameBuf, sizeof(szTTYNameBuf)) == 0) {
snprintf(cbuf,sizeof(cbuf), "*.*\t%s", szTTYNameBuf);
conf.cfline((uchar*)cbuf, &f);
+ } else {
+ dbgprintf("error %d obtaining controlling terminal, not using that emergency rule\n", errno);
}
selectorAddList(f);
}
@@ -2290,6 +2329,12 @@ init(void)
}
}
+ /* we are done checking the config - now validate if we should actually run or not.
+ * If not, terminate. -- rgerhards, 2008-07-25
+ */
+ if(iConfigVerify)
+ ABORT_FINALIZE(RS_RET_VALIDATION_RUN);
+
/* switch the message object to threaded operation, if necessary */
if(MainMsgQueType == QUEUETYPE_DIRECT || iMainMsgQueueNumWorkers > 1) {
MsgEnableThreadSafety();
@@ -2371,7 +2416,9 @@ init(void)
sigaction(SIGHUP, &sigAct, NULL);
dbgprintf(" (re)started.\n");
- ENDfunc
+
+finalize_it:
+ RETiRet;
}
@@ -2638,7 +2685,6 @@ static rsRetVal loadBuildInModules(void)
* is that rsyslog will terminate if we can not register our built-in config commands.
* This, I think, is the right thing to do. -- rgerhards, 2007-07-31
*/
-// CHKiRet(regCfSysLineHdlr((uchar *)"workdirectory", 0, eCmdHdlrGetWord, NULL, &pszWorkDir, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"actionresumeretrycount", 0, eCmdHdlrInt, NULL, &glbliActionResumeRetryCount, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuefilename", 0, eCmdHdlrGetWord, NULL, &pszMainMsgQFName, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuesize", 0, eCmdHdlrInt, NULL, &iMainMsgQueueSize, NULL));
@@ -2679,6 +2725,7 @@ static rsRetVal loadBuildInModules(void)
NULL, &bDebugPrintCfSysLineHandlerList, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"moddir", 0, eCmdHdlrGetWord, NULL, &pModDir, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"errormessagestostderr", 0, eCmdHdlrBinary, NULL, &bErrMsgToStderr, NULL));
/* now add other modules handlers (we should work on that to be able to do it in ClassInit(), but so far
* that is not possible). -- rgerhards, 2008-01-28
@@ -2734,9 +2781,9 @@ static void printVersion(void)
* move code out of the too-long main() function.
* rgerhards, 2007-10-17
*/
-static void mainThread()
+static rsRetVal mainThread()
{
- BEGINfunc
+ DEFiRet;
uchar *pTmp;
/* Note: signals MUST be processed by the thread this code is running in. The reason
@@ -2765,7 +2812,8 @@ static void mainThread()
pTmp = template_StdPgSQLFmt;
tplLastStaticInit(tplAddLine(" StdPgSQLFmt", &pTmp));
- init();
+ CHKiRet(init());
+
if(Debug) {
dbgprintf("Debugging enabled, SIGUSR1 to turn off debugging.\n");
debugging_on = 1;
@@ -2784,7 +2832,9 @@ static void mainThread()
dbgprintf("initialization completed, transitioning to regular run mode\n");
mainloop();
- ENDfunc
+
+finalize_it:
+ RETiRet;
}
@@ -2967,6 +3017,98 @@ finalize_it:
}
+/* global initialization, to be done only once and before the mainloop is started.
+ * rgerhards, 2008-07-28 (extracted from realMain())
+ */
+static rsRetVal
+doGlblProcessInit(void)
+{
+ struct sigaction sigAct;
+ int num_fds;
+ int i;
+ DEFiRet;
+
+ checkPermissions();
+ thrdInit();
+
+ if( !(Debug || NoFork) )
+ {
+ dbgprintf("Checking pidfile.\n");
+ if (!check_pid(PidFile))
+ {
+ memset(&sigAct, 0, sizeof (sigAct));
+ sigemptyset(&sigAct.sa_mask);
+ sigAct.sa_handler = doexit;
+ sigaction(SIGTERM, &sigAct, NULL);
+
+ if (fork()) {
+ /* Parent process
+ */
+ sleep(300);
+ /* Not reached unless something major went wrong. 5
+ * minutes should be a fair amount of time to wait.
+ * Please note that this procedure is important since
+ * the father must not exit before syslogd isn't
+ * initialized or the klogd won't be able to flush its
+ * logs. -Joey
+ */
+ exit(1); /* "good" exit - after forking, not diasabling anything */
+ }
+ num_fds = getdtablesize();
+ for (i= 0; i < num_fds; i++)
+ (void) close(i);
+ untty();
+ }
+ else
+ {
+ fputs(" Already running.\n", stderr);
+ exit(1); /* "good" exit, done if syslogd is already running */
+ }
+ }
+ else
+ debugging_on = 1;
+
+ /* tuck my process id away */
+ dbgprintf("Writing pidfile %s.\n", PidFile);
+ if (!check_pid(PidFile))
+ {
+ if (!write_pid(PidFile))
+ {
+ fputs("Can't write pid.\n", stderr);
+ exit(1); /* exit during startup - questionable */
+ }
+ }
+ else
+ {
+ fputs("Pidfile (and pid) already exist.\n", stderr);
+ exit(1); /* exit during startup - questionable */
+ }
+ myPid = getpid(); /* save our pid for further testing (also used for messages) */
+
+ memset(&sigAct, 0, sizeof (sigAct));
+ sigemptyset(&sigAct.sa_mask);
+
+ sigAct.sa_handler = sigsegvHdlr;
+ sigaction(SIGSEGV, &sigAct, NULL);
+ sigAct.sa_handler = sigsegvHdlr;
+ sigaction(SIGABRT, &sigAct, NULL);
+ sigAct.sa_handler = doDie;
+ sigaction(SIGTERM, &sigAct, NULL);
+ sigAct.sa_handler = Debug ? doDie : SIG_IGN;
+ sigaction(SIGINT, &sigAct, NULL);
+ sigaction(SIGQUIT, &sigAct, NULL);
+ sigAct.sa_handler = reapchild;
+ sigaction(SIGCHLD, &sigAct, NULL);
+ sigAct.sa_handler = Debug ? debug_switch : SIG_IGN;
+ sigaction(SIGUSR1, &sigAct, NULL);
+ sigAct.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &sigAct, NULL);
+ sigaction(SIGXFSZ, &sigAct, NULL); /* do not abort if 2gig file limit is hit */
+
+ RETiRet;
+}
+
+
/* This is the main entry point into rsyslogd. Over time, we should try to
* modularize it a bit more...
*/
@@ -2974,16 +3116,15 @@ int realMain(int argc, char **argv)
{
DEFiRet;
- register int i;
register uchar *p;
- int num_fds;
int ch;
struct hostent *hent;
extern int optind;
extern char *optarg;
- struct sigaction sigAct;
int bEOptionWasGiven = 0;
int bImUxSockLoaded = 0; /* already generated a $ModLoad imuxsock? */
+ int iHelperUOpt;
+ int bChDirRoot = 1; /* change the current working directory to "/"? */
char *arg; /* for command line option processing */
uchar legacyConfLine[80];
uchar *LocalHostName;
@@ -3003,7 +3144,7 @@ int realMain(int argc, char **argv)
* 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) {
+ while((ch = getopt(argc, argv, "46aAc:def:g:hi:l:m:M:nN:opqQr::s:t:u:vwx")) != EOF) {
switch((char)ch) {
case '4':
case '6':
@@ -3015,6 +3156,7 @@ int realMain(int argc, char **argv)
case 'l':
case 'm': /* mark interval */
case 'n': /* don't fork */
+ case 'N': /* enable config verify mode */
case 'o':
case 'p':
case 'q': /* add hostname if DNS resolving has failed */
@@ -3078,9 +3220,6 @@ int realMain(int argc, char **argv)
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"
@@ -3213,6 +3352,9 @@ int realMain(int argc, char **argv)
case 'n': /* don't fork */
NoFork = 1;
break;
+ case 'N': /* enable config verify mode */
+ iConfigVerify = atoi(arg);
+ break;
case 'o':
if(iCompatibilityMode < 3) {
if(!bImUxSockLoaded) {
@@ -3263,8 +3405,11 @@ int realMain(int argc, char **argv)
fprintf(stderr, "-t option only supported in compatibility modes 0 to 2 - ignored\n");
break;
case 'u': /* misc user settings */
- if(atoi(arg) == 1)
+ iHelperUOpt = atoi(arg);
+ if(iHelperUOpt & 0x01)
bParseHOSTNAMEandTAG = 0;
+ if(iHelperUOpt & 0x02)
+ bChDirRoot = 0;
break;
case 'w': /* disable disallowed host warnigs */
glbl.SetOption_DisallowWarning(0);
@@ -3281,6 +3426,17 @@ int realMain(int argc, char **argv)
if(iRet != RS_RET_END_OF_LINKEDLIST)
FINALIZE;
+ if(iConfigVerify) {
+ fprintf(stderr, "rsyslogd: version %s, config validation run (level %d), master config %s\n",
+ VERSION, iConfigVerify, ConfFile);
+ }
+
+ if(bChDirRoot) {
+ if(chdir("/") != 0)
+ fprintf(stderr, "Can not do 'cd /' - still trying to run\n");
+ }
+
+
/* process compatibility mode settings */
if(iCompatibilityMode < 3) {
errmsg.LogError(0, NO_ERRCODE, "WARNING: rsyslogd is running in compatibility mode. Automatically "
@@ -3304,86 +3460,10 @@ int realMain(int argc, char **argv)
"more and cast your vote if you want us to keep this feature.");
}
- checkPermissions();
- thrdInit();
+ if(!iConfigVerify)
+ CHKiRet(doGlblProcessInit());
- if( !(Debug || NoFork) )
- {
- dbgprintf("Checking pidfile.\n");
- if (!check_pid(PidFile))
- {
- memset(&sigAct, 0, sizeof (sigAct));
- sigemptyset(&sigAct.sa_mask);
- sigAct.sa_handler = doexit;
- sigaction(SIGTERM, &sigAct, NULL);
-
- if (fork()) {
- /*
- * Parent process
- */
- sleep(300);
- /*
- * Not reached unless something major went wrong. 5
- * minutes should be a fair amount of time to wait.
- * Please note that this procedure is important since
- * the father must not exit before syslogd isn't
- * initialized or the klogd won't be able to flush its
- * logs. -Joey
- */
- exit(1); /* "good" exit - after forking, not diasabling anything */
- }
- num_fds = getdtablesize();
- for (i= 0; i < num_fds; i++)
- (void) close(i);
- untty();
- }
- else
- {
- fputs(" Already running.\n", stderr);
- exit(1); /* "good" exit, done if syslogd is already running */
- }
- }
- else
- debugging_on = 1;
-
- /* tuck my process id away */
- dbgprintf("Writing pidfile %s.\n", PidFile);
- if (!check_pid(PidFile))
- {
- if (!write_pid(PidFile))
- {
- fputs("Can't write pid.\n", stderr);
- exit(1); /* exit during startup - questionable */
- }
- }
- else
- {
- fputs("Pidfile (and pid) already exist.\n", stderr);
- exit(1); /* exit during startup - questionable */
- }
- myPid = getpid(); /* save our pid for further testing (also used for messages) */
-
- memset(&sigAct, 0, sizeof (sigAct));
- sigemptyset(&sigAct.sa_mask);
-
- sigAct.sa_handler = sigsegvHdlr;
- sigaction(SIGSEGV, &sigAct, NULL);
- sigAct.sa_handler = sigsegvHdlr;
- sigaction(SIGABRT, &sigAct, NULL);
- sigAct.sa_handler = doDie;
- sigaction(SIGTERM, &sigAct, NULL);
- sigAct.sa_handler = Debug ? doDie : SIG_IGN;
- sigaction(SIGINT, &sigAct, NULL);
- sigaction(SIGQUIT, &sigAct, NULL);
- sigAct.sa_handler = reapchild;
- sigaction(SIGCHLD, &sigAct, NULL);
- sigAct.sa_handler = Debug ? debug_switch : SIG_IGN;
- sigaction(SIGUSR1, &sigAct, NULL);
- sigAct.sa_handler = SIG_IGN;
- sigaction(SIGPIPE, &sigAct, NULL);
- sigaction(SIGXFSZ, &sigAct, NULL); /* do not abort if 2gig file limit is hit */
-
- mainThread();
+ CHKiRet(mainThread());
/* do any de-init's that need to be done AFTER this comment */
@@ -3392,9 +3472,12 @@ int realMain(int argc, char **argv)
thrdExit();
finalize_it:
- if(iRet != RS_RET_OK)
- fprintf(stderr, "rsyslogd run failed with error %d\n(see rsyslog.h "
- "or http://www.rsyslog.com/errcode to learn what that number means)\n", iRet);
+ if(iRet == RS_RET_VALIDATION_RUN) {
+ fprintf(stderr, "rsyslogd: End of config validation run. Bye.\n");
+ } else if(iRet != RS_RET_OK) {
+ fprintf(stderr, "rsyslogd run failed with error %d (see rsyslog.h "
+ "or try http://www.rsyslog.com/e/%d to learn what that number means)\n", iRet, iRet*-1);
+ }
ENDfunc
return 0;