summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog58
-rw-r--r--Makefile.am9
-rw-r--r--action.c20
-rw-r--r--action.h3
-rw-r--r--configure.ac53
-rw-r--r--dirty.h1
-rw-r--r--doc/Makefile.am2
-rw-r--r--doc/expression.html21
-rw-r--r--doc/imsolaris.html47
-rw-r--r--doc/imuxsock.html30
-rw-r--r--doc/manual.html6
-rw-r--r--doc/omoracle.html11
-rw-r--r--doc/omuxsock.html43
-rw-r--r--doc/rainerscript.html18
-rw-r--r--doc/rsconf1_omfileforcechown.html64
-rw-r--r--doc/rsyslog_conf_global.html11
-rw-r--r--doc/rsyslog_conf_modules.html2
-rw-r--r--gss-misc.c25
-rw-r--r--plugins/imgssapi/imgssapi.c16
-rw-r--r--plugins/imklog/solaris.c184
-rw-r--r--plugins/imklog/solaris_cddl.c293
-rw-r--r--plugins/imklog/solaris_cddl.h2
-rw-r--r--plugins/imsolaris/Makefile.am6
-rw-r--r--plugins/imsolaris/imsolaris.c391
-rw-r--r--plugins/imsolaris/imsolaris.h2
-rw-r--r--plugins/imsolaris/sun_cddl.c419
-rw-r--r--plugins/imsolaris/sun_cddl.h7
-rw-r--r--plugins/imudp/imudp.c20
-rw-r--r--plugins/imuxsock/imuxsock.c47
-rw-r--r--plugins/omoracle/omoracle.c64
-rw-r--r--plugins/omprog/omprog.c3
-rw-r--r--plugins/omstdout/omstdout.c2
-rw-r--r--plugins/omuxsock/Makefile.am8
-rw-r--r--plugins/omuxsock/omuxsock.c315
-rw-r--r--runtime/Makefile.am1
-rw-r--r--runtime/atomic.h86
-rw-r--r--runtime/cfsysline.c8
-rw-r--r--runtime/debug.c25
-rw-r--r--runtime/debug.h5
-rw-r--r--runtime/glbl.c12
-rw-r--r--runtime/glbl.h11
-rw-r--r--runtime/msg.c15
-rw-r--r--runtime/msg.h2
-rw-r--r--runtime/net.c8
-rw-r--r--runtime/nsdsel_ptcp.c51
-rw-r--r--runtime/nsdsel_ptcp.h5
-rw-r--r--runtime/parser.c29
-rw-r--r--runtime/prop.c6
-rw-r--r--runtime/prop.h2
-rw-r--r--runtime/queue.c10
-rw-r--r--runtime/queue.h1
-rw-r--r--runtime/rsyslog.c2
-rw-r--r--runtime/rsyslog.h22
-rw-r--r--runtime/stream.c3
-rw-r--r--runtime/unlimited_select.h45
-rw-r--r--runtime/vm.c44
-rw-r--r--runtime/wti.c11
-rw-r--r--runtime/wti.h1
-rw-r--r--runtime/wtp.c24
-rw-r--r--runtime/wtp.h3
-rw-r--r--solaris/README38
-rw-r--r--solaris/cddllicense.txt242
-rw-r--r--template.c1
-rw-r--r--tests/Makefile.am20
-rwxr-xr-xtests/complex1.sh5
-rwxr-xr-xtests/diag.sh22
-rw-r--r--tests/diagtalker.c157
-rw-r--r--tests/historical/DiagTalker.java (renamed from tests/DiagTalker.java)1
-rw-r--r--tests/historical/README2
-rw-r--r--tests/msleep.c51
-rw-r--r--tests/nettester.c83
-rwxr-xr-xtests/rsf_getenv.sh17
-rw-r--r--tests/rt-init.c2
-rw-r--r--tests/tcpflood.c15
-rw-r--r--tests/testsuites/rsf_getenv.conf17
-rw-r--r--tests/testsuites/uxsock_simple.conf10
-rwxr-xr-xtests/threadingmqaq.sh3
-rwxr-xr-xtests/uxsock_simple.sh31
-rw-r--r--tests/uxsockrcvr.c157
-rw-r--r--tools/omfile.c30
-rw-r--r--tools/ompipe.c2
-rw-r--r--tools/syslogd.c78
82 files changed, 3409 insertions, 210 deletions
diff --git a/ChangeLog b/ChangeLog
index b8cbdb42..38d0595f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,7 +1,57 @@
+---------------------------------------------------------------------------
+Version 4.7.3 [v4-devel] (rgerhards), 2010-??-??
+- added omuxsock, which permits to write message to local Unix sockets
+ this is the counterpart to imuxsock, enabling fast local forwarding
- added imptcp, a simplified, Linux-specific and potentielly fast
syslog plain tcp input plugin (NOT supporting TLS!)
---------------------------------------------------------------------------
-Version 4.6.4 [v4-stable] (rgerhards), 2010-08.05
+Version 4.7.2 [v4-devel] (rgerhards), 2010-05-03
+- bugfix: problems with atomic operations emulaton
+ replaced atomic operation emulation with new code. The previous code
+ seemed to have some issue and also limited concurrency severely. The
+ whole atomic operation emulation has been rewritten.
+- added new $Sleep directive to hold processing for a couple of seconds
+ during startup
+- bugfix: programname filter in ! configuration can not be reset
+ Thanks to Kiss Gabor for the patch.
+---------------------------------------------------------------------------
+Version 4.7.1 [v4-devel] (rgerhards), 2010-04-22
+- Solaris support much improved -- was not truely usable in 4.7.0
+ Solaris is no longer supported in imklog, but rather there is a new
+ plugin imsolaris, which is used to pull local log sources on a Solaris
+ machine.
+- testbench improvement: Java is no longer needed for testing tool creation
+---------------------------------------------------------------------------
+Version 4.7.0 [v4-devel] (rgerhards), 2010-04-14
+- new: support for Solaris added (but not yet the Solaris door API)
+- added function getenv() to RainerScript
+- added new config option $InputUnixListenSocketCreatePath
+ to permit the auto-creation of pathes to additional log sockets. This
+ turns out to be useful if they reside on temporary file systems and
+ rsyslogd starts up before the daemons that create these sockets
+ (rsyslogd always creates the socket itself if it does not exist).
+- added $LogRSyslogStatusMessages configuration directive
+ permitting to turn off rsyslog start/stop/HUP messages. See Debian
+ ticket http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=463793
+- added new config directive $omfileForceChown to (try to) fix some broken
+ system configs.
+ See ticket for details: http://bugzilla.adiscon.com/show_bug.cgi?id=150
+- added $EscapeControlCharacterTab config directive
+ Thanks to Jonathan Bond-Caron for the patch.
+- added option to use unlimited-size select() calls
+ Thanks to varmjofekoj for the patch
+- debugondemand mode caused backgrounding to fail - close to a bug, but I'd
+ consider the ability to background in this mode a new feature...
+- bugfix (kind of): check if TCP connection is still alive if using TLS
+ Thanks to Jonathan Bond-Caron for the patch.
+- imported changes from 4.5.7 and below
+- bugfix: potential segfault when -p command line option was used
+ Thanks for varmojfekoj for pointing me at this bug.
+- bugfix: potential segfaults during queue shutdown
+ (bugs require certain non-standard settings to appear)
+ Thanks to varmojfekoj for the patch [imported from 4.5.8]
+---------------------------------------------------------------------------
+Version 4.6.4 [v4-stable] (rgerhards), 2010-08-05
- bugfix: zero-sized (empty) messages were processed by imtcp
they are now dropped as they always should have been
- bugfix: programname filter in ! configuration can not be reset
@@ -26,12 +76,18 @@ Version 4.6.3 [v4-stable] (rgerhards), 2010-07-07
message-induced off-by-one error (potential segfault) (see 4.6.2)
The analysis has been completed and a better fix been crafted and
integrated.
+- bugfix: the T/P/E config size specifiers did not work properly under
+ all 32-bit platforms
+- bugfix: local unix system log socket was deleted even when it was
+ not configured
- some doc fixes; incorrect config samples could cause confusion
thanks to Anthony Edwards for pointing the problems out
---------------------------------------------------------------------------
Version 4.6.2 [v4-stable] (rgerhards), 2010-03-26
- new feature: "." action type added to support writing files to relative
pathes (this is primarily meant as a debug aid)
+- added replacements for atomic instructions on systems that do not
+ support them. [backport of Stefen Sledz' patch for v5)
- new feature: $OMFileAsyncWriting directive added
it permits to specifiy if asynchronous writing should be done or not
- bugfix(temporary): message-induced off-by-one error (potential segfault)
diff --git a/Makefile.am b/Makefile.am
index 439cb417..111756f6 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -59,6 +59,10 @@ if ENABLE_IMKLOG
SUBDIRS += plugins/imklog
endif
+if ENABLE_IMSOLARIS
+SUBDIRS += plugins/imsolaris
+endif
+
if ENABLE_GSSAPI
SUBDIRS += plugins/omgssapi plugins/imgssapi
endif
@@ -95,6 +99,10 @@ if ENABLE_OMSTDOUT
SUBDIRS += plugins/omstdout
endif
+if ENABLE_OMUXSOCK
+SUBDIRS += plugins/omuxsock
+endif
+
if ENABLE_OMTEMPLATE
SUBDIRS += plugins/omtemplate
endif
@@ -139,5 +147,6 @@ SUBDIRS += tests
# in a make distcheck is so that we detect code that accidently was not updated
# when some global update happened.
DISTCHECK_CONFIGURE_FLAGS=--enable-gssapi_krb5 --enable-imfile --enable-snmp --enable-pgsql --enable-libdbi --enable-mysql --enable-omtemplate --enable-imtemplate --enable-relp --enable-rsyslogd --enable-mail --enable-klog --enable-diagtools --enable-gnutls --enable-omstdout --enable-omprog --enable-imdiag --enable-shave --enable-extended-tests \
+ --enable-omuxsock \
--enable-imptcp
ACLOCAL_AMFLAGS = -I m4
diff --git a/action.c b/action.c
index 724dea4b..5451ef13 100644
--- a/action.c
+++ b/action.c
@@ -200,7 +200,7 @@ rsRetVal actionDestruct(action_t *pThis)
/* message ptr cleanup */
for(i = 0 ; i < pThis->iNumTpls ; ++i) {
- if(pThis->ppMsgs[i] != NULL) {
+ if(((uchar**)pThis->ppMsgs)[i] != NULL) {
switch(pThis->eParamPassing) {
case ACT_ARRAY_PASSING:
#if 0 /* later! */
@@ -214,7 +214,7 @@ rsRetVal actionDestruct(action_t *pThis)
#endif
break;
case ACT_STRING_PASSING:
- d_free(pThis->ppMsgs[i]);
+ d_free(((uchar**)pThis->ppMsgs)[i]);
break;
default:
assert(0);
@@ -475,10 +475,10 @@ actionCallDoAction(action_t *pAction, msg_t *pMsg)
for(i = 0 ; i < pAction->iNumTpls ; ++i) {
switch(pAction->eParamPassing) {
case ACT_STRING_PASSING:
- CHKiRet(tplToString(pAction->ppTpl[i], pMsg, &(pAction->ppMsgs[i]), &(pAction->lenMsgs[i])));
+ CHKiRet(tplToString(pAction->ppTpl[i], pMsg, &(((uchar**)pAction->ppMsgs)[i]), &(pAction->lenMsgs[i])));
break;
case ACT_ARRAY_PASSING:
- CHKiRet(tplToArray(pAction->ppTpl[i], pMsg, (uchar***) &(pAction->ppMsgs[i])));
+ CHKiRet(tplToArray(pAction->ppTpl[i], pMsg, (uchar***) &(((uchar**)pAction->ppMsgs)[i])));
break;
default:assert(0); /* software bug if this happens! */
}
@@ -526,16 +526,16 @@ actionCallDoAction(action_t *pAction, msg_t *pMsg)
finalize_it:
/* cleanup */
for(i = 0 ; i < pAction->iNumTpls ; ++i) {
- if(pAction->ppMsgs[i] != NULL) {
+ if(((uchar**)pAction->ppMsgs)[i] != NULL) {
switch(pAction->eParamPassing) {
case ACT_ARRAY_PASSING:
iArr = 0;
- while(((char **)pAction->ppMsgs[i])[iArr] != NULL) {
- d_free(((char **)pAction->ppMsgs[i])[iArr++]);
- ((char **)pAction->ppMsgs[i])[iArr++] = NULL;
+ while((((uchar***)pAction->ppMsgs)[i][iArr]) != NULL) {
+ d_free(((uchar ***)pAction->ppMsgs)[i][iArr++]);
+ ((uchar ***)pAction->ppMsgs)[i][iArr++] = NULL;
}
- d_free(pAction->ppMsgs[i]);
- pAction->ppMsgs[i] = NULL;
+ d_free(((uchar**)pAction->ppMsgs)[i]);
+ ((uchar**)pAction->ppMsgs)[i] = NULL;
break;
case ACT_STRING_PASSING:
break;
diff --git a/action.h b/action.h
index 579a1215..c4ef94bb 100644
--- a/action.h
+++ b/action.h
@@ -74,7 +74,8 @@ struct action_s {
SYNC_OBJ_TOOL; /* required for mutex support */
pthread_mutex_t mutActExec; /* mutex to guard actual execution of doAction for single-threaded modules */
uchar *pszName; /* action name (for documentation) */
- uchar **ppMsgs; /* pointer to action-calling parameters (kept in structure to save alloc() time!) */
+ //uchar **ppMsgs; /* pointer to action-calling parameters (kept in structure to save alloc() time!) */
+ void *ppMsgs; /* pointer to action-calling parameters (kept in structure to save alloc() time!) */
size_t *lenMsgs; /* length of message in ppMsgs */
};
typedef struct action_s action_t;
diff --git a/configure.ac b/configure.ac
index ce34e53d..27c8d69f 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],[4.6.4],[rsyslog@lists.adiscon.com])
+AC_INIT([rsyslog],[4.7.2],[rsyslog@lists.adiscon.com])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([ChangeLog])
AC_CONFIG_MACRO_DIR([m4])
@@ -84,6 +84,7 @@ AC_TYPE_UINT8_T
AC_HEADER_TIME
AC_STRUCT_TM
AC_C_VOLATILE
+AC_C_TYPEOF
sa_includes="\
$ac_includes_default
@@ -126,6 +127,9 @@ AC_TRY_COMPILE([
# check for availability of atomic operations
RS_ATOMIC_OPERATIONS
+# fall back to POSIX sems for atomic operations (cpu expensive)
+AC_CHECK_HEADERS([semaphore.h])
+
# Additional module directories
AC_ARG_WITH(moddirs,
@@ -274,6 +278,7 @@ AC_ARG_ENABLE(klog,
AM_CONDITIONAL(ENABLE_IMKLOG, test x$enable_klog = xyes)
AM_CONDITIONAL(ENABLE_IMKLOG_BSD, test x$os_type = xbsd)
AM_CONDITIONAL(ENABLE_IMKLOG_LINUX, test x$os_type = xlinux)
+AM_CONDITIONAL(ENABLE_IMKLOG_SOLARIS, test x$os_type = xsolaris)
#
@@ -335,6 +340,21 @@ AC_ARG_ENABLE([fsstnd],
])
+# support for unlimited select() syscall
+AC_ARG_ENABLE(unlimited_select,
+ [AS_HELP_STRING([--enable-unlimited-select],[Enable unlimited select() syscall @<:@default=no@:>@])],
+ [case "${enableval}" in
+ yes) enable_unlimited_select="yes" ;;
+ no) enable_unlimited_select="no" ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --enable-unlimited-select) ;;
+ esac],
+ [enable_unlimited_select="no"]
+)
+if test "$enable_unlimited_select" = "yes"; then
+ AC_DEFINE(USE_UNLIMITED_SELECT, 1, [If defined, the select() syscall won't be limited to a particular number of file descriptors.])
+fi
+
+
# debug
AC_ARG_ENABLE(debug,
[AS_HELP_STRING([--enable-debug],[Enable debug mode @<:@default=no@:>@])],
@@ -727,6 +747,18 @@ AC_ARG_ENABLE(imfile,
AM_CONDITIONAL(ENABLE_IMFILE, test x$enable_imfile = xyes)
+# settings for the door input module (under solaris, thus default off)
+AC_ARG_ENABLE(imsolaris,
+ [AS_HELP_STRING([--enable-imsolaris],[door input module enabled @<:@default=no@:>@])],
+ [case "${enableval}" in
+ yes) enable_imsolaris="yes" ;;
+ no) enable_imsolaris="no" ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --enable-imsolaris) ;;
+ esac],
+ [enable_imsolaris=no]
+)
+AM_CONDITIONAL(ENABLE_IMSOLARIS, test x$enable_imsolaris = xyes)
+
# settings for the ptcp input module
AC_ARG_ENABLE(imptcp,
[AS_HELP_STRING([--enable-imptcp],[plain tcp input module enabled @<:@default=no@:>@])],
@@ -765,6 +797,20 @@ AC_ARG_ENABLE(omstdout,
)
AM_CONDITIONAL(ENABLE_OMSTDOUT, test x$enable_omstdout = xyes)
+
+# settings for omuxsock
+AC_ARG_ENABLE(omuxsock,
+ [AS_HELP_STRING([--enable-omuxsock],[Compiles stdout module @<:@default=no@:>@])],
+ [case "${enableval}" in
+ yes) enable_omuxsock="yes" ;;
+ no) enable_omuxsock="no" ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --enable-omuxsock) ;;
+ esac],
+ [enable_omuxsock=no]
+)
+AM_CONDITIONAL(ENABLE_OMUXSOCK, test x$enable_omuxsock = xyes)
+
+
# This provides a vehicle to integrate custom modules, that are not
# part of rsyslog, into the build process. It is named cust1, so that
# additional such modules can easily be added.
@@ -840,7 +886,9 @@ AC_CONFIG_FILES([Makefile \
plugins/omtemplate/Makefile \
plugins/omprog/Makefile \
plugins/omstdout/Makefile \
+ plugins/omuxsock/Makefile \
plugins/imfile/Makefile \
+ plugins/imsolaris/Makefile \
plugins/imptcp/Makefile \
plugins/imrelp/Makefile \
plugins/imdiag/Makefile \
@@ -868,18 +916,21 @@ echo " Zlib compression support enabled: $enable_zlib"
echo " rsyslog runtime will be built: $enable_rsyslogrt"
echo " rsyslogd will be built: $enable_rsyslogd"
echo " custom module 1 will be built: $enable_cust1"
+echo " Unlimited select() support enabled: $enable_unlimited_select"
echo
echo "---{ input plugins }---"
echo " Klog functionality enabled: $enable_klog ($os_type)"
echo " plain tcp input module enabled: $enable_imptcp"
echo " imdiag enabled: $enable_imdiag"
echo " file input module enabled: $enable_imfile"
+echo " Solaris input module enabled: $enable_imsolaris"
echo " input template module will be compiled: $enable_imtemplate"
echo
echo "---{ output plugins }---"
echo " Mail support enabled: $enable_mail"
echo " omprog module will be compiled: $enable_omprog"
echo " omstdout module will be compiled: $enable_omstdout"
+echo " omuxsock module will be compiled: $enable_omuxsock"
echo " output template module will be compiled: $enable_omtemplate"
echo
echo "---{ database support }---"
diff --git a/dirty.h b/dirty.h
index 0153cb69..f1904574 100644
--- a/dirty.h
+++ b/dirty.h
@@ -54,6 +54,7 @@ extern int bReduceRepeatMsgs;
extern int bDropTrailingLF;
extern uchar cCCEscapeChar;
extern int bEscapeCCOnRcv;
+extern int bEscapeTab;
#ifdef USE_NETZIP
/* config param: minimum message size to try compression. The smaller
* the message, the less likely is any compression gain. We check for
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 7ba86ad4..72954e9c 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -40,6 +40,7 @@ html_files = \
imptcp.html \
imgssapi.html \
imrelp.html \
+ imsolaris.html \
imuxsock.html \
imklog.html \
queues.html \
@@ -100,6 +101,7 @@ html_files = \
gssapi.html \
licensing.html \
ommail.html \
+ omuxsock.html \
omrelp.html \
syslog_parsing.html \
troubleshoot.html \
diff --git a/doc/expression.html b/doc/expression.html
index 9e37cb7a..c401d9ab 100644
--- a/doc/expression.html
+++ b/doc/expression.html
@@ -1,17 +1,22 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head>
-<meta http-equiv="Content-Language" content="en"><title>Expressions</title></head>
+<meta http-equiv="Content-Language" content="en">
+<title>Expressions in rsyslog</title></head>
<body>
-<a href="rsyslog_conf_filter.html">back</a>
-<h1>Expressions</h1>
+<a href="rsyslog_conf_filter.html">back to rsyslog filter conditions</a>
+<h1>Expressions in rsyslog</h1>
<p>Rsyslog supports expressions at a growing number of places. So
-far, they are supported for filtering messages.</p><p>Expression support is provided by RainerScript. For now, please see the formal expression definition in <a href="rainerscript.html">RainerScript ABNF</a>. It is the "expr" node.</p><p>C-like comments (/* some comment */) are supported <span style="font-weight: bold;">inside</span> the expression, but not yet in the rest of the configuration file.</p><p>[<a href="rsyslog_conf.html">rsyslog.conf overview</a>]
+far, they are supported for filtering messages.</p>
+<p>Expression support is provided by RainerScript. Please see the
+<a href="rainerscript.html">RainerScript documentation</a> for more details.</p>
+<p>C-like comments (/* some comment */) are supported <b>inside</b> the expression,
+but not yet in the rest of the configuration file.</p>
+
+<p>[<a href="rsyslog_conf.html">rsyslog.conf overview</a>]
[<a href="manual.html">manual index</a>] [<a href="http://www.rsyslog.com/">rsyslog site</a>]</p>
<p><font size="2">This documentation is part of the
-<a href="http://www.rsyslog.com/">rsyslog</a>
-project.<br>
-Copyright © 2008 by <a href="http://www.gerhards.net/rainer">Rainer
-Gerhards</a> and
+<a href="http://www.rsyslog.com/">rsyslog</a> project.<br>
+Copyright &copy; 2008, 2009 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/imsolaris.html b/doc/imsolaris.html
new file mode 100644
index 00000000..ce0e7e84
--- /dev/null
+++ b/doc/imsolaris.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head>
+<meta http-equiv="Content-Language" content="en">
+<title>Solaris Input Module (imsolaris)</title>
+
+</head>
+<body>
+<a href="rsyslog_conf_modules.html">back</a>
+
+<h1>Solaris Input Module</h1>
+<p><b>Module Name:&nbsp;&nbsp;&nbsp; imsolaris</b></p>
+<p><b>Author: </b>Rainer Gerhards
+&lt;rgerhards@adiscon.com&gt;</p>
+<p><b>Description</b>:</p>
+<p>Reads local Solaris log messages including the kernel log.</p>
+<p>This module is specifically tailored for Solaris. Under Solaris, there
+is no special kernel input device. Instead, both kernel messages as well as
+messages emitted via syslog() are received from a single source.
+<p>This module obeys the Solaris door() mechanism to detect a running syslogd
+instance. As such, only one can be active at one time. If it detects another
+active intance at startup, the module disables itself, but rsyslog will
+continue to run.
+<p><b>Configuration Directives</b>:</p>
+<ul>
+<li><strong>$IMSolarisLogSocketName &lt;name&gt;</strong><br>
+This is the name of the log socket (stream) to read. If not given, /dev/log
+is read.
+</li>
+</ul>
+<b>Caveats/Known Bugs:</b>
+<p>None currently known. For obvious reasons, works on Solaris, only (and compilation
+will most probably fail on any other platform).
+<p><b>Sample:</b></p>
+<p>The following sample pulls messages from the default log source
+<br>
+</p>
+<textarea rows="15" cols="60">$ModLoad imsolaris
+</textarea>
+<p>[<a href="rsyslog_conf.html">rsyslog.conf overview</a>]
+[<a href="manual.html">manual index</a>] [<a href="http://www.rsyslog.com/">rsyslog site</a>]</p>
+<p><font size="2">This documentation is part of the
+<a href="http://www.rsyslog.com/">rsyslog</a>
+project.<br>
+Copyright &copy; 2010 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 472470a0..381374d2 100644
--- a/doc/imuxsock.html
+++ b/doc/imuxsock.html
@@ -46,6 +46,18 @@ Ignore timestamps included in the messages, applies to messages received via the
<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>$InputUnixListenSocketCreatePath</b> [on/<b>off</b>] - create directories in the socket path
+if they do not already exist. They are created with 0755 permissions with the owner being the process under
+which rsyslogd runs. The default is not to create directories. Keep in mind, though, that rsyslogd always
+creates the socket itself if it does not exist (just not the directories by default).
+<br>Note that this statement affects the
+next $AddUnixListenSocket directive that follows in sequence in the configuration file. It never works
+on the system log socket (where it is deemed unnecessary). Also note that it is automatically
+being reset to &quot;off&quot; after the $AddUnixListenSocket directive, so if you would have it active
+for two additional listen sockets, you need to specify it in front of each one. This option is primarily considered
+useful for defining additional sockets that reside on non-permanent file systems. As rsyslogd probably starts
+up before the daemons that create these sockets, it is a vehicle to enable rsyslogd to listen to those
+sockets even though their directories do not yet exist. [available since 4.7.0 and 5.3.0]</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
@@ -57,26 +69,38 @@ that the local hostname can be overridden in cases where that is desired.</li>
<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>The following sample is the minimum setup required to accept syslog messages from applications running
+on the local system.<br>
</p>
<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
+<textarea rows="6" cols="70">$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>The following sample is a configuration where rsyslogd reads the openssh log
+messages via a separate socket, but this socket is created on a temporary file
+system. As rsyslogd starts up before the sshd, it needs to create the socket
+directories, because it otherwise can not open the socket and thus not listen
+to openssh messages. Note that it is vital not to place any other socket between
+the $InputUnixListenSocketCreatePath and the $InputUnixListenSocketHostName.</p>
+<textarea rows="6" cols="70">$ModLoad imuxsock # needs to be done just once
+
+$InputUnixListenSocketCreatePath on # turn on for *next* socket
+$InputUnixListenSocketHostName /var/run/sshd/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>
<p><font size="2">This documentation is part of the
<a href="http://www.rsyslog.com/">rsyslog</a>
project.<br>
-Copyright © 2008 by <a href="http://www.gerhards.net/rainer">Rainer
+Copyright &copy; 2008-2010 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>
diff --git a/doc/manual.html b/doc/manual.html
index aff23c8b..0e4166d0 100644
--- a/doc/manual.html
+++ b/doc/manual.html
@@ -19,9 +19,9 @@ rsyslog support</a> available directly from the source!</p>
<p><b>Please visit the <a href="http://www.rsyslog.com/sponsors">rsyslog sponsor's page</a>
to honor the project sponsors or become one yourself!</b> We are very grateful for any help towards the
project goals.</p>
-<p><b>This documentation is for version 4.6.4 (v4-stable branch) of rsyslog.</b>
-Visit the <i> <a href="http://www.rsyslog.com/status">rsyslog status page</a></i></b> to obtain current
-version information and project status.
+<p><b>This documentation is for version 4.7.2 (v4-devel branch) of rsyslog.</b>
+Visit the <i> <a href="http://www.rsyslog.com/status">rsyslog status page</a></i></b>
+to obtain current version information and project status.
</p><p><b>If you like rsyslog, you might
want to lend us a helping hand. </b>It doesn't require a lot of
time - even a single mouse click helps. Learn <a href="how2help.html">how to help the rsyslog project</a>.
diff --git a/doc/omoracle.html b/doc/omoracle.html
index cfcf277f..2bb6aa5d 100644
--- a/doc/omoracle.html
+++ b/doc/omoracle.html
@@ -13,10 +13,11 @@
<p><b>Available since: </b>: 4.3.0
<p><b>Status: </b>: contributed module, not maitained by rsyslog core authors
<p><b>Description</b>:</p>
-<p>This module provides native support for logging to Oracle databases. It offers
-superior performance over the more generic <a href="omlibdbi.html">omlibdbi</a> module.
-It also includes a number of enhancements, most importantly prepared statements and
-batching, what provides a big performance improvements.
+<p>This module provides native support for logging to Oracle
+databases. It offers superior performance over the more
+generic <a href="omlibdbi.html">omlibdbi</a> module. It also includes
+a number of enhancements, most importantly prepared statements and
+batching, what provides a big performance improvement.
</p>
<p>Note that this module is maintained by its original author. If you need assistance with it,
it is suggested to post questions to the
@@ -63,7 +64,7 @@ it is suggested to post questions to the
$OmoracleStatement \
insert into foo(hostname,message)values(:host,:message)
- Also note that identifiers to placeholders are arbitrarry. You
+ Also note that identifiers to placeholders are arbitrary. You
need to define the properties on the template in the correct order
you want them passed to the statement!
</pre>
diff --git a/doc/omuxsock.html b/doc/omuxsock.html
new file mode 100644
index 00000000..5fa569eb
--- /dev/null
+++ b/doc/omuxsock.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><title>Unix sockets output module (omuxsock) - sending syslog messages to local socket</title>
+<a href="features.html">back</a>
+</head>
+<body>
+<h1>Unix sockets Output Module (omuxsock)</h1>
+<p><b>Module Name:&nbsp;&nbsp;&nbsp; omuxsock</b></p>
+<p><b>Available since:&nbsp;&nbsp;&nbsp;</b> 4.7.3, 5.5.7</p>
+<p><b>Author: </b>Rainer Gerhards &lt;rgerhards@adiscon.com&gt;</p>
+<p><b>Description</b>:</p>
+<p>This module supports sending syslog messages to local Unix sockets.
+Thus it provided a fast message-passing interface between different rsyslog
+instances. The counterpart to omuxsock is <a href="imuxsock.html">imuxsock</a>.
+Note that the template used together with omuxsock must be suitable to be
+processed by the receiver.
+<p><b>Configuration Directives</b>:</p>
+<ul>
+<li><b>$OMUxSockSocket</b><br>
+Name of the socket to send data to. This has no default and <b>must</b>
+be set.
+</li>
+<li><b>$OMUxSockDefaultTemplate</b><br>
+This can be used to override the default template to be used together
+with omuxsock. This is primarily useful if there are many forwarding
+actions and each of them should use the same template.</li>
+</ul>
+<b>Caveats/Known Bugs:</b>
+<p>Currently, only datagram sockets are supported.
+<p><b>Sample:</b></p>
+<p>The following sample writes all messages to the "/tmp/socksample" socket.
+</p>
+<textarea rows="4" cols="80">$ModLoad omucsock
+$OMUxSockSocket /tmp/socksample
+*.* :omuxsock:
+</textarea>
+[<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 &copy; 2010 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/rainerscript.html b/doc/rainerscript.html
index ef0e41cb..63a79040 100644
--- a/doc/rainerscript.html
+++ b/doc/rainerscript.html
@@ -51,13 +51,25 @@ of a and b should be tested as "a &lt;&gt; b". The "not" operator
should be reserved to cases where it actually is needed to form a
complex boolean expression. In those cases, parenthesis are highly
recommended.
+<h2>Functions</h2>
+<p>RainerScript supports a currently quite limited set of functions:
+<ul>
+<li>getenv(str) - like the OS call, returns the value of the environment
+variable, if it exists. Returns an empty string if it does not exist.
+<li>strlen(str) - returns the length of the provided string
+<li>tolower(str) - converts the provided string into lowercase
+</ul>
+<p>The following example can be used to build a dynamic filter based on some environment
+variable:
+<pre>
+if $msg contains getenv('TRIGGERVAR') then /path/to/errfile
+</pre>
<p>[<a href="rsyslog_conf.html">rsyslog.conf overview</a>]
[<a href="manual.html">manual index</a>] [<a href="http://www.rsyslog.com/">rsyslog site</a>]</p>
<p><font size="2">This documentation is part of the
<a href="http://www.rsyslog.com/">rsyslog</a>
project.<br>
-Copyright © 2008 by <a href="http://www.gerhards.net/rainer">Rainer
-Gerhards</a> and
+Copyright &copy; 2008, 2009 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/rsconf1_omfileforcechown.html b/doc/rsconf1_omfileforcechown.html
new file mode 100644
index 00000000..7415a6f6
--- /dev/null
+++ b/doc/rsconf1_omfileforcechown.html
@@ -0,0 +1,64 @@
+<html>
+<head>
+<title>rsyslog.conf file</title>
+</head>
+<body>
+<a href="rsyslog_conf_global.html">back</a>
+
+<h2>$omfileForceChown</h2>
+<p><b>Type:</b> global configuration directive</p>
+<p><b>Parameter Values:</b> boolean (on/off, yes/no)</p>
+<p><b>Available since:</b> 4.7.0+, 5.3.0+</p>
+<p><b>Default:</b> off</p>
+<p><b>Description:</b></p>
+<p>Forces rsyslogd to change the ownership for output files that already exist. Please note
+that this tries to fix a potential problem that exists outside the scope of rsyslog. Actually,
+it tries to fix invalid ownership/permission settings set by the original file creator.
+<p>Rsyslog changes the ownership during initial execution with root privileges. When a privelege
+drop is configured, privileges are dropped after the file owner ship is changed. Not that this currently
+is a limitation in rsyslog's privilege drop code, which is on the TODO list to be removed. See Caveats
+section below for the important implications.
+<p><b>Caveats:</b></p>
+<p>This directive tries to fix a problem that actually is outside the scope of rsyslog. As such,
+there are a couple of restrictions and situations in which it will not work. <b>Users are strongly
+encouraged to fix their system instead of turning this directive on</b> - it should only be used
+as a last resort.
+<p>At least in the following scenario, this directive will fail expectedly:
+<p>It does not address
+the situation that someone changes the ownership *after* rsyslogd has started.
+Let's, for example, consider a log rotation script.
+<ul>
+<li>rsyslog is started
+<li>ownership is changed
+<li>privileges dropped
+<li>log rotation (lr) script starts
+<li>lr removes files
+<li>lr creates new files with root:adm (or whatever else)
+<li>lr HUPs rsyslogd
+<li>rsyslogd closes files
+<li>rsyslogd tries to open files
+<li>rsyslogd tries to change ownership --&gt; fail as we are non-root now
+<li>file open fails
+</ul>
+
+Please note that once the privilege drop code is refactored, this directive will
+no longer work, because then privileges will be dropped before any action is performed,
+and thus we will no longer be able to chown files that do not belong to the
+user rsyslogd is configured to run under.
+
+<p>So <b>expect the directive to go away</b>. It will not
+be removed in version 4, but may disappear at any time for any version greater than 4.
+
+<p><b>Sample:</b></p>
+<p><code><b>$FileOwner loguser</b>
+<br><b>$omfileForceChown on</b></code></p>
+
+<p>[<a href="rsyslog_conf.html">rsyslog.conf overview</a>] [<a href="manual.html">manual
+index</a>] [<a href="http://www.rsyslog.com/">rsyslog site</a>]</p>
+<p><font size="2">This documentation is part of the
+<a href="http://www.rsyslog.com/">rsyslog</a> project.<br>
+Copyright &copy; 2007 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 2 or higher.</font></p>
+</body>
+</html>
diff --git a/doc/rsyslog_conf_global.html b/doc/rsyslog_conf_global.html
index ce46bac2..8c1cc9a7 100644
--- a/doc/rsyslog_conf_global.html
+++ b/doc/rsyslog_conf_global.html
@@ -130,6 +130,7 @@ our paper on <a href="multi_ruleset.html">using multiple rule sets in rsyslog</a
<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><b>$EscapeControlCharactersOnReceive</b> [<b>on</b>|off] - escape USASCII HT character</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>
@@ -149,6 +150,10 @@ Usually that should not be a big issue, as the restart-type HUP can easily be re
something along the lines of &quot;/etc/init.d/rsyslog restart&quot;.
</li>
<li><a href="rsconf1_includeconfig.html">$IncludeConfig</a></li><li>MainMsgQueueCheckpointInterval &lt;number&gt;</li>
+<li><b>$LogRSyslogStatusMessages</b> [<b>on</b>/off] - If set to on (the default),
+rsyslog emits message on startup and shutdown as well as when it is HUPed.
+This information might be needed by some log analyzers. If set to off, no such
+status messages are logged, what may be useful for other scenarios.
<li>$MainMsgQueueDequeueSlowdown &lt;number&gt; [number
is timeout in <i> micro</i>seconds (1000000us is 1sec!),
default 0 (no delay). Simple rate-limiting!]</li>
@@ -229,6 +234,7 @@ error recovery thus can handle write errors without data loss. Note that this op
severely reduces the effect of zip compression and should be switched to off
for that use case. Note that the default -on- is primarily an aid to preserve
the traditional syslogd behaviour.</li>
+<li><a href="rsconf1_omfileforcechown.html">$omfileForceChown</a> - force ownership change for all files</li>
<li><b>$RepeatedMsgContainsOriginalMsg</b> [on/<b>off</b>] - "last message repeated n times" messages, if generated,
have a different format that contains the message that is being repeated.
Note that only the first "n" characters are included, with n to be at least 80 characters, most
@@ -267,6 +273,9 @@ the value, the less precise the timestamp.
<li><a href="droppriv.html">$PrivDropToGroupID</a></li>
<li><a href="droppriv.html">$PrivDropToUser</a></li>
<li><a href="droppriv.html">$PrivDropToUserID</a></li>
+<li><b>$Sleep</b> &lt;seconds&gt; - puts the rsyslog main thread to sleep for the specified
+number of seconds immediately when the directive is encountered. You should have a
+good reason for using this directive!</li>
<li><a href="rsconf1_umask.html">$UMASK</a></li>
</ul>
<p><b>Where &lt;size_nbr&gt; is specified above,</b>
@@ -285,7 +294,7 @@ point of view, "1,,0.0.,.,0" also has the value 1000. </p>
[<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 &copy; 2008, 2009 by <a href="http://www.gerhards.net/rainer">Rainer Gerhards</a> and
+Copyright &copy; 2008-2010 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>
diff --git a/doc/rsyslog_conf_modules.html b/doc/rsyslog_conf_modules.html
index 19f69da6..b2830535 100644
--- a/doc/rsyslog_conf_modules.html
+++ b/doc/rsyslog_conf_modules.html
@@ -33,6 +33,7 @@ to message generators.
<li>immark - support for mark messages</li>
<li><a href="imklog.html">imklog</a> - kernel logging</li>
<li><a href="imuxsock.html">imuxsock</a> - unix sockets, including the system log socket</li>
+<li><a href="imsolaris.html">imsolaris</a> - input for the Sun Solaris system log source</li>
<li><a href="im3195.html">im3195</a> - accepts syslog messages via RFC 3195</li>
</ul>
@@ -52,6 +53,7 @@ SQLLite, Ingres, Oracle, mSQL)</li>
<li><a href="ommail.html">ommail</a> -
permits rsyslog to alert folks by mail if something important happens</li>
<li><a href="omoracle.html">omoracle</a> - output module for Oracle (native OCI interface)</li>
+<li><a href="omuxsock.html">omuxsock</a> - output module Unix domain sockets</li>
</ul>
<h2>Library Modules</h2>
diff --git a/gss-misc.c b/gss-misc.c
index c9220595..978454ff 100644
--- a/gss-misc.c
+++ b/gss-misc.c
@@ -51,11 +51,14 @@
#include "obj.h"
#include "errmsg.h"
#include "gss-misc.h"
+#include "glbl.h"
+#include "unlimited_select.h"
MODULE_TYPE_LIB
/* static data */
DEFobjStaticHelpers
+DEFobjCurrIf(glbl)
DEFobjCurrIf(errmsg)
static void display_status_(char *m, OM_uint32 code, int type)
@@ -108,28 +111,38 @@ static int read_all(int fd, char *buf, unsigned int nbyte)
{
int ret;
char *ptr;
- fd_set rfds;
struct timeval tv;
+#ifdef USE_UNLIMITED_SELECT
+ fd_set *pRfds = malloc(glbl.GetFdSetSize());
+#else
+ fd_set rfds;
+ fd_set *pRfds = &rfds;
+#endif
for (ptr = buf; nbyte; ptr += ret, nbyte -= ret) {
- FD_ZERO(&rfds);
- FD_SET(fd, &rfds);
+ FD_ZERO(pRfds);
+ FD_SET(fd, pRfds);
tv.tv_sec = 1;
tv.tv_usec = 0;
- if ((ret = select(FD_SETSIZE, &rfds, NULL, NULL, &tv)) <= 0
- || !FD_ISSET(fd, &rfds))
+ if ((ret = select(FD_SETSIZE, pRfds, NULL, NULL, &tv)) <= 0
+ || !FD_ISSET(fd, pRfds)) {
+ freeFdSet(pRfds);
return ret;
+ }
ret = recv(fd, ptr, nbyte, 0);
if (ret < 0) {
if (errno == EINTR)
continue;
+ freeFdSet(pRfds);
return (ret);
} else if (ret == 0) {
+ freeFdSet(pRfds);
return (ptr - buf);
}
}
+ freeFdSet(pRfds);
return (ptr - buf);
}
@@ -264,6 +277,7 @@ BEGINObjClassExit(gssutil, OBJ_IS_LOADABLE_MODULE) /* CHANGE class also in END M
CODESTARTObjClassExit(gssutil)
/* release objects we no longer need */
objRelease(errmsg, CORE_COMPONENT);
+ objRelease(glbl, CORE_COMPONENT);
ENDObjClassExit(gssutil)
@@ -274,6 +288,7 @@ ENDObjClassExit(gssutil)
BEGINAbstractObjClassInit(gssutil, 1, OBJ_IS_LOADABLE_MODULE) /* class, version - CHANGE class also in END MACRO! */
/* request objects we use */
CHKiRet(objUse(errmsg, CORE_COMPONENT));
+ CHKiRet(objUse(glbl, CORE_COMPONENT));
ENDObjClassInit(gssutil)
diff --git a/plugins/imgssapi/imgssapi.c b/plugins/imgssapi/imgssapi.c
index d8791880..1aad6622 100644
--- a/plugins/imgssapi/imgssapi.c
+++ b/plugins/imgssapi/imgssapi.c
@@ -56,6 +56,7 @@
#include "errmsg.h"
#include "netstrm.h"
#include "glbl.h"
+#include "unlimited_select.h"
MODULE_TYPE_INPUT
@@ -414,15 +415,20 @@ OnSessAcceptGSS(tcpsrv_t *pThis, tcps_sess_t *pSess)
CHKiRet(netstrm.GetSock(pSess->pStrm, &fdSess)); // TODO: method access!
if (allowedMethods & ALLOWEDMETHOD_TCP) {
int len;
- fd_set fds;
struct timeval tv;
+#ifdef USE_UNLIMITED_SELECT
+ fd_set *pFds = malloc(glbl.GetFdSetSize());
+#else
+ fd_set fds;
+ fd_set *pFds = &fds;
+#endif
do {
- FD_ZERO(&fds);
- FD_SET(fdSess, &fds);
+ FD_ZERO(pFds);
+ FD_SET(fdSess, pFds);
tv.tv_sec = 1;
tv.tv_usec = 0;
- ret = select(fdSess + 1, &fds, NULL, NULL, &tv);
+ ret = select(fdSess + 1, pFds, NULL, NULL, &tv);
} while (ret < 0 && errno == EINTR);
if (ret < 0) {
errmsg.LogError(0, RS_RET_ERR, "TCP session %p will be closed, error ignored\n", pSess);
@@ -475,6 +481,8 @@ OnSessAcceptGSS(tcpsrv_t *pThis, tcps_sess_t *pSess)
pGSess->allowedMethods = ALLOWEDMETHOD_TCP;
ABORT_FINALIZE(RS_RET_OK); // TODO: define good error codes
}
+
+ freeFdSet(pFds);
}
context = &pGSess->gss_context;
diff --git a/plugins/imklog/solaris.c b/plugins/imklog/solaris.c
new file mode 100644
index 00000000..8a6d5af1
--- /dev/null
+++ b/plugins/imklog/solaris.c
@@ -0,0 +1,184 @@
+/* klog driver for solaris
+ *
+ * This contains OS-specific functionality to read the
+ * kernel log. For a general overview, see head comment in
+ * imklog.c.
+ *
+ * This file relies on Sun code in solaris_cddl.c. We have split
+ * it from Sun's code to keep the copyright issue as simple as possible.
+ *
+ * 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.
+ *
+ * If that may be required, an exception is granted to permit linking
+ * this code to the code in solaris_cddl.c that is under the cddl license.
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/socket.h>
+
+
+
+#include "rsyslog.h"
+#include "imklog.h"
+#include "srUtils.h"
+#include "unicode-helper.h"
+#include "solaris_cddl.h"
+
+/* globals */
+static int fklog; // TODO: remove
+#ifndef _PATH_KLOG
+# define _PATH_KLOG "/dev/log"
+#endif
+
+
+static uchar *GetPath(void)
+{
+ return pszPath ? pszPath : UCHAR_CONSTANT(_PATH_KLOG);
+}
+
+/* open the kernel log - will be called inside the willRun() imklog
+ * entry point. -- rgerhards, 2008-04-09
+ */
+rsRetVal
+klogWillRun(void)
+{
+ DEFiRet;
+
+ fklog = sun_openklog((char*) GetPath(), O_RDONLY);
+ if (fklog < 0) {
+ char errStr[1024];
+ int err = errno;
+ rs_strerror_r(err, errStr, sizeof(errStr));
+ DBGPRINTF("error %s opening log socket: %s\n",
+ errStr, GetPath());
+ iRet = RS_RET_ERR; // TODO: better error code
+ }
+
+ RETiRet;
+}
+
+
+#if 0
+/* Read /dev/klog while data are available, split into lines.
+ * Contrary to standard BSD syslogd, we do a blocking read. We can
+ * afford this as imklog is running on its own threads. So if we have
+ * a single file, it really doesn't matter if we wait inside a 1-file
+ * select or the read() directly.
+ */
+static void
+readklog(void)
+{
+ char *p, *q;
+ int len, i;
+ int iMaxLine;
+ uchar bufRcv[4096+1];
+ uchar *pRcv = NULL; /* receive buffer */
+
+ iMaxLine = klog_getMaxLine();
+
+ /* we optimize performance: if iMaxLine is below 4K (which it is in almost all
+ * cases, we use a fixed buffer on the stack. Only if it is higher, heap memory
+ * is used. We could use alloca() to achive a similar aspect, but there are so
+ * many issues with alloca() that I do not want to take that route.
+ * rgerhards, 2008-09-02
+ */
+ if((size_t) iMaxLine < sizeof(bufRcv) - 1) {
+ pRcv = bufRcv;
+ } else {
+ if((pRcv = (uchar*) malloc(sizeof(uchar) * (iMaxLine + 1))) == NULL)
+ iMaxLine = sizeof(bufRcv) - 1; /* better this than noting */
+ }
+
+ len = 0;
+ for (;;) {
+ dbgprintf("----------imklog(BSD) waiting for kernel log line\n");
+ i = read(fklog, pRcv + len, iMaxLine - len);
+ if (i > 0) {
+ pRcv[i + len] = '\0';
+ } else {
+ if (i < 0 && errno != EINTR && errno != EAGAIN) {
+ imklogLogIntMsg(LOG_ERR,
+ "imklog error %d reading kernel log - shutting down imklog",
+ errno);
+ fklog = -1;
+ }
+ break;
+ }
+
+ for(p = pRcv; (q = strchr(p, '\n')) != NULL; p = q + 1) {
+ *q = '\0';
+ Syslog(LOG_INFO, (uchar*) p);
+ }
+ len = strlen(p);
+ if (len >= iMaxLine - 1) {
+ Syslog(LOG_INFO, (uchar*)p);
+ len = 0;
+ }
+ if (len > 0)
+ memmove(pRcv, p, len + 1);
+ }
+ if (len > 0)
+ Syslog(LOG_INFO, pRcv);
+
+ if(pRcv != NULL && (size_t) iMaxLine >= sizeof(bufRcv) - 1)
+ free(pRcv);
+}
+#endif
+
+
+/* to be called in the module's AfterRun entry point
+ * rgerhards, 2008-04-09
+ */
+rsRetVal klogAfterRun(void)
+{
+ DEFiRet;
+ if(fklog != -1)
+ close(fklog);
+ RETiRet;
+}
+
+
+
+/* to be called in the module's WillRun entry point, this is the main
+ * "message pull" mechanism.
+ * rgerhards, 2008-04-09
+ */
+rsRetVal klogLogKMsg(void)
+{
+ DEFiRet;
+ sun_sys_poll();
+ RETiRet;
+}
+
+
+/* provide the (system-specific) default facility for internal messages
+ * rgerhards, 2008-04-14
+ */
+int
+klogFacilIntMsg(void)
+{
+ return LOG_SYSLOG;
+}
+
diff --git a/plugins/imklog/solaris_cddl.c b/plugins/imklog/solaris_cddl.c
new file mode 100644
index 00000000..7e86c68c
--- /dev/null
+++ b/plugins/imklog/solaris_cddl.c
@@ -0,0 +1,293 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Portions Copyright 2010 by Rainer Gerhards and Adiscon
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
+ * All Rights Reserved
+ */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+#include "config.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <pthread.h>
+#include <sys/poll.h>
+#include <pthread.h>
+#include <fcntl.h>
+#include <stropts.h>
+#include <assert.h>
+#include <sys/strlog.h>
+
+#include "rsyslog.h"
+#include "imklog.h"
+
+/* TODO: this define should be changed over time to the more generic
+ * system-provided (configurable) upper limit. However, it is quite
+ * unexpected that Solaris-emitted messages are so long, so it seems
+ * acceptable to set a fixed (relatively high) limit for the time
+ * being -- and gain some experience with it. -- rgerhars, 2010-04-12
+ */
+#define MAXLINE 4096
+
+static struct pollfd Pfd; /* Pollfd for local the log device */
+
+
+/* findnl_bkwd:
+ * Scans each character in buf until it finds the last newline in buf,
+ * or the scanned character becomes the last COMPLETE character in buf.
+ * Returns the number of scanned bytes.
+ *
+ * buf - pointer to a buffer containing the message string
+ * len - the length of the buffer
+ */
+size_t
+findnl_bkwd(const char *buf, const size_t len)
+{
+ const char *p;
+ size_t mb_cur_max;
+
+ if (len == 0) {
+ return (0);
+ }
+
+ mb_cur_max = MB_CUR_MAX;
+
+ if (mb_cur_max == 1) {
+ /* single-byte locale */
+ for (p = buf + len - 1; p != buf; p--) {
+ if (*p == '\n') {
+ return ((size_t)(p - buf));
+ }
+ }
+ return ((size_t)len);
+ } else {
+ /* multi-byte locale */
+ int mlen;
+ const char *nl;
+ size_t rem;
+
+ p = buf;
+ nl = NULL;
+ for (rem = len; rem >= mb_cur_max; ) {
+ mlen = mblen(p, mb_cur_max);
+ if (mlen == -1) {
+ /*
+ * Invalid character found.
+ */
+ dbgprintf("klog:findnl_bkwd: Invalid MB sequence\n");
+ /*
+ * handle as a single byte character.
+ */
+ p++;
+ rem--;
+ } else {
+ /*
+ * It's guaranteed that *p points to
+ * the 1st byte of a multibyte character.
+ */
+ if (*p == '\n') {
+ nl = p;
+ }
+ p += mlen;
+ rem -= mlen;
+ }
+ }
+ if (nl) {
+ return ((size_t)(nl - buf));
+ }
+ /*
+ * no newline nor null byte found.
+ * Also it's guaranteed that *p points to
+ * the 1st byte of a (multibyte) character
+ * at this point.
+ */
+ return (len - rem);
+ }
+}
+//___ end
+
+
+/* Attempts to open the local log device
+ * and return a file descriptor.
+ */
+int
+sun_openklog(char *name, int mode)
+{
+ int fd;
+ struct strioctl str;
+
+ if ((fd = open(name, mode)) < 0) {
+ dbgprintf("klog:openklog: cannot open %s (%d)\n",
+ name, errno);
+ return (-1);
+ }
+ str.ic_cmd = I_CONSLOG;
+ str.ic_timout = 0;
+ str.ic_len = 0;
+ str.ic_dp = NULL;
+ if (ioctl(fd, I_STR, &str) < 0) {
+ dbgprintf("klog:openklog: cannot register to log "
+ "console messages (%d)\n", errno);
+ return (-1);
+ }
+ Pfd.fd = fd;
+ Pfd.events = POLLIN;
+ return (fd);
+}
+
+
+/*
+ * Pull up one message from log driver.
+ */
+void
+sun_getkmsg()
+{
+ int flags = 0, i;
+ char *lastline;
+ struct strbuf ctl, dat;
+ struct log_ctl hdr;
+ char buf[MAXLINE+1];
+ size_t buflen;
+ size_t len;
+ char tmpbuf[MAXLINE+1];
+
+ dat.maxlen = MAXLINE;
+ dat.buf = buf;
+ ctl.maxlen = sizeof (struct log_ctl);
+ ctl.buf = (caddr_t)&hdr;
+
+ while ((i = getmsg(Pfd.fd, &ctl, &dat, &flags)) == MOREDATA) {
+ lastline = &dat.buf[dat.len];
+ *lastline = '\0';
+
+ dbgprintf("klog:sys_poll: getmsg: dat.len = %d\n", dat.len);
+ buflen = strlen(buf);
+ len = findnl_bkwd(buf, buflen);
+
+ (void) memcpy(tmpbuf, buf, len);
+ tmpbuf[len] = '\0';
+
+ Syslog(LOG_INFO, (uchar*) buf);
+
+ if (len != buflen) {
+ /* If anything remains in buf */
+ size_t remlen;
+
+ if (buf[len] == '\n') {
+ /* skip newline */
+ len++;
+ }
+
+ /* Move the remaining bytes to
+ * the beginnning of buf.
+ */
+
+ remlen = buflen - len;
+ (void) memcpy(buf, &buf[len], remlen);
+ dat.maxlen = MAXLINE - remlen;
+ dat.buf = &buf[remlen];
+ } else {
+ dat.maxlen = MAXLINE;
+ dat.buf = buf;
+ }
+ }
+
+ if (i == 0 && dat.len > 0) {
+ dat.buf[dat.len] = '\0';
+ /* Format sys will enqueue the log message.
+ * Set the sync flag if timeout != 0, which
+ * means that we're done handling all the
+ * initial messages ready during startup.
+ */
+ dbgprintf("klog:getkmsg: getmsg: dat.maxlen = %d\n", dat.maxlen);
+ dbgprintf("klog:getkmsg: getmsg: dat.len = %d\n", dat.len);
+ dbgprintf("klog:getkmsg: getmsg: strlen(dat.buf) = %d\n", strlen(dat.buf));
+ dbgprintf("klog:getkmsg: getmsg: dat.buf = \"%s\"\n", dat.buf);
+ dbgprintf("klog:getkmsg: buf len = %d\n", strlen(buf));
+ Syslog(LOG_INFO, (uchar*) buf);
+ } else if (i < 0 && errno != EINTR) {
+ if(1){ /* V5-TODO: rsyslog-like termination! (!shutting_down) { */
+ dbgprintf("klog:kernel log driver read error");
+ }
+ // TODO trigger retry logic
+ //(void) close(Pfd.fd);
+ //Pfd.fd = -1;
+ }
+}
+
+
+/* this thread listens to the local stream log driver for log messages
+ * generated by this host, formats them, and queues them to the logger
+ * thread.
+ */
+/*ARGSUSED*/
+void *
+sun_sys_poll()
+{
+ int nfds;
+
+ dbgprintf("klog:sys_poll: sys_thread started\n");
+
+ for (;;) {
+ errno = 0;
+
+ nfds = poll(&Pfd, 1, INFTIM);
+
+ if (nfds == 0)
+ continue;
+
+ if (nfds < 0) {
+ if (errno != EINTR)
+ dbgprintf("klog:poll error");
+ continue;
+ }
+ if (Pfd.revents & POLLIN) {
+ sun_getkmsg();
+ } else {
+ /* TODO: shutdown, the rsyslog way (in v5!) -- check shutdown flag */
+ if (Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) {
+ // TODO: trigger retry logic
+/* logerror("kernel log driver poll error");
+ (void) close(Pfd.fd);
+ Pfd.fd = -1;
+ */
+ }
+ }
+
+ }
+ /*NOTREACHED*/
+ return (NULL);
+}
diff --git a/plugins/imklog/solaris_cddl.h b/plugins/imklog/solaris_cddl.h
new file mode 100644
index 00000000..d48ef628
--- /dev/null
+++ b/plugins/imklog/solaris_cddl.h
@@ -0,0 +1,2 @@
+void *sun_sys_poll();
+int sun_openklog(char *name, int mode);
diff --git a/plugins/imsolaris/Makefile.am b/plugins/imsolaris/Makefile.am
new file mode 100644
index 00000000..b4ee1c29
--- /dev/null
+++ b/plugins/imsolaris/Makefile.am
@@ -0,0 +1,6 @@
+pkglib_LTLIBRARIES = imsolaris.la
+
+imsolaris_la_SOURCES = imsolaris.c sun_cddl.c sun_cddl.h imsolaris.h
+imsolaris_la_CPPFLAGS = -I$(top_srcdir) $(PTHREADS_CFLAGS) $(RSRT_CFLAGS)
+imsolaris_la_LDFLAGS = -module -avoid-version
+imsolaris_la_LIBADD = -ldoor -lpthread
diff --git a/plugins/imsolaris/imsolaris.c b/plugins/imsolaris/imsolaris.c
new file mode 100644
index 00000000..6b07ba2b
--- /dev/null
+++ b/plugins/imsolaris/imsolaris.c
@@ -0,0 +1,391 @@
+/* imsolaris.c
+ * This input module is used to gather local log data under Solaris. This
+ * includes messages from local applications AS WELL AS the kernel log.
+ * I first considered to make all of this available via imklog, but that
+ * did not lock appropriately on second thought. So I created this module
+ * that does anything for local message recption.
+ *
+ * This module is not meant to be used on plaforms other than Solaris. As
+ * such, trying to compile it elswhere will probably fail with all sorts
+ * of errors.
+ *
+ * Some notes on the Solaris syslog mechanism:
+ * Both system (kernel) and application log messages are provided via
+ * a single message stream.
+ *
+ * Solaris checks if the syslogd is running. If so, syslog() emits messages
+ * to the log socket, only. Otherwise, it emits messages to the console.
+ * It is possible to gather these console messages as well. However, then
+ * we clutter the console.
+ * Solaris does this "syslogd alive check" in a somewhat unexpected way
+ * (at least unexpected for me): it uses the so-called "door" mechanism, a
+ * fast RPC facility. I first thought that the door API was used to submit
+ * the actual syslog messages. But this is not the case. Instead, a door
+ * call is done, and the server process inside rsyslog simply does NOTHING
+ * but return. All that Solaris sylsogd() is interested in is if the door
+ * server (we) responds and thus can be considered alive. The actual message
+ * is then submitted via the usual stream. I have to admit I do not
+ * understand why the message itself is not passed via this high-performance
+ * API. But anyhow, that's nothing I can change, so the most important thing
+ * is to note how Solaris does this thing ;)
+ * The syslog() library call checks syslogd state for *each* call (what a
+ * waste of time...) and decides each time if the message should go to the
+ * console or not. According to OpenSolaris sources, it looks like there is
+ * message loss potential when the door file is created before all data has
+ * been pulled from the stream. While I have to admit that I do not fully
+ * understand that problem, I will follow the original code advise and do
+ * one complete pull cycle on the log socket (until it has no further data
+ * available) and only thereafter create the door file and start the "regular"
+ * pull cycle. As of my understanding, there is a minimal race between the
+ * point where the intial pull cycle has ended and the door file is created,
+ * but that race is also present in OpenSolaris syslogd code, so it should
+ * not matter that much (plus, I do not know how to avoid it...)
+ *
+ * File begun on 2010-04-15 by RGerhards
+ *
+ * Copyright 2010 Rainer Gerhards and Adiscon GmbH.
+ *
+ * This file is part of rsyslog.
+ *
+ * Rsyslog is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Rsyslog is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Rsyslog. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+ */
+#include "config.h"
+#include "rsyslog.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <assert.h>
+#include <string.h>
+#include <stropts.h>
+#include <sys/strlog.h>
+#include <errno.h>
+#include "dirty.h"
+#include "cfsysline.h"
+#include "unicode-helper.h"
+#include "module-template.h"
+#include "srUtils.h"
+#include "errmsg.h"
+#include "net.h"
+#include "glbl.h"
+#include "msg.h"
+#include "prop.h"
+#include "sun_cddl.h"
+
+MODULE_TYPE_INPUT
+
+/* defines */
+#define PATH_LOG "/dev/log"
+
+
+/* Module static data */
+DEF_IMOD_STATIC_DATA
+DEFobjCurrIf(errmsg)
+DEFobjCurrIf(glbl)
+DEFobjCurrIf(prop)
+
+
+/* config settings */
+static prop_t *pInputName = NULL; /* our inputName currently is always "imuxsock", and this will hold it */
+static char *LogName = NULL; /* the log socket name TODO: make configurable! */
+
+
+/* a function to replace the sun logerror() function.
+ * It generates an error message from the supplied string. The main
+ * reason for not calling logError directly is that sun_cddl.c does not
+ * know or has acces to rsyslog objects (namely errmsg) -- and we do not
+ * want to do this effort. -- rgerhards, 2010-04-19
+ */
+void
+imsolaris_logerror(int err, char *errStr)
+{
+ errmsg.LogError(err, RS_RET_ERR_DOOR, "%s", errStr);
+}
+
+
+/* we try to recover a failed file by closing and re-opening
+ * it. We loop until the re-open works, but wait between each
+ * failure. If the open succeeds, we assume all is well. If it is
+ * not, we will run into the retry process with the next
+ * iteration.
+ * rgerhards, 2010-04-19
+ */
+static void
+tryRecover(void)
+{
+ int tryNum = 1;
+ int waitsecs;
+ int waitusecs;
+ rsRetVal iRet;
+
+ close(sun_Pfd.fd);
+ sun_Pfd.fd = -1;
+
+ while(1) { /* loop broken inside */
+ iRet = sun_openklog((LogName == NULL) ? PATH_LOG : LogName);
+ if(iRet == RS_RET_OK) {
+ if(tryNum > 1) {
+ errmsg.LogError(0, iRet, "failure on system log socket recovered.");
+ }
+ break;
+ }
+ /* failure, so sleep a bit. We wait try*10 ms, with a max of 15 seconds */
+ if(tryNum == 1) {
+ errmsg.LogError(0, iRet, "failure on system log socket, trying to recover...");
+ }
+ waitusecs = tryNum * 10000;
+ waitsecs = waitusecs / 1000000;
+ DBGPRINTF("imsolaris: try %d to recover system log socket in %d.%d seconds\n",
+ tryNum, waitsecs, waitusecs);
+ if(waitsecs > 15) {
+ waitsecs = 15;
+ waitusecs = 0;
+ } else {
+ waitusecs = waitusecs % 1000000;
+ }
+ srSleep(waitsecs, waitusecs);
+ ++tryNum;
+ }
+}
+
+
+/* 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
+readLog(int fd, uchar *pRcv, int iMaxLine)
+{
+ DEFiRet;
+ struct strbuf data;
+ struct strbuf ctl;
+ struct log_ctl hdr;
+ int flags;
+ msg_t *pMsg;
+ int ret;
+ char errStr[1024];
+
+ data.buf = (char*)pRcv;
+ data.maxlen = iMaxLine;
+ ctl.maxlen = sizeof (struct log_ctl);
+ ctl.buf = (caddr_t)&hdr;
+ flags = 0;
+ ret = getmsg(fd, &ctl, &data, &flags);
+ if(ret < 0) {
+ if(errno == EINTR) {
+ FINALIZE;
+ } else {
+ int en = errno;
+ rs_strerror_r(errno, errStr, sizeof(errStr));
+ DBGPRINTF("imsolaris: stream input error on fd %d: %s.\n", fd, errStr);
+ errmsg.LogError(en, NO_ERRCODE, "imsolaris: stream input error: %s", errStr);
+ tryRecover();
+ }
+ } else {
+ DBGPRINTF("imsolaris: message from log stream %d: %s\n", fd, pRcv);
+ pRcv[data.len] = '\0'; /* make sure it is a valid C-String */
+ CHKiRet(msgConstruct(&pMsg));
+ MsgSetInputName(pMsg, pInputName);
+ MsgSetRawMsg(pMsg, (char*)pRcv, strlen((char*)pRcv));
+ MsgSetHOSTNAME(pMsg, glbl.GetLocalHostName(), ustrlen(glbl.GetLocalHostName()));
+ pMsg->iFacility = LOG_FAC(hdr.pri);
+ pMsg->iSeverity = LOG_PRI(hdr.pri);
+ pMsg->bParseHOSTNAME = 0;
+ pMsg->msgFlags = NEEDS_PARSING | NO_PRI_IN_RAW;
+ CHKiRet(submitMsg(pMsg));
+ }
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* once the system is fully initialized, we wait for new messages.
+ * We may think about replacing this with a read-loop, thus saving
+ * us the overhead of the poll.
+ * The timeout variable is the timeout to use for poll. During startup,
+ * it should be set to 0 (non-blocking) and later to -1 (infinit, blocking).
+ * This mimics the (strange) behaviour of the original syslogd.
+ * rgerhards, 2010-04-19
+ */
+static inline rsRetVal
+getMsgs(int timeout)
+{
+ DEFiRet;
+ int nfds;
+ int iMaxLine;
+ uchar *pRcv = NULL; /* receive buffer */
+ uchar bufRcv[4096+1];
+ char errStr[1024];
+
+ iMaxLine = glbl.GetMaxLine();
+
+ /* we optimize performance: if iMaxLine is below 4K (which it is in almost all
+ * cases, we use a fixed buffer on the stack. Only if it is higher, heap memory
+ * is used. We could use alloca() to achive a similar aspect, but there are so
+ * many issues with alloca() that I do not want to take that route.
+ * rgerhards, 2008-09-02
+ */
+ if((size_t) iMaxLine < sizeof(bufRcv) - 1) {
+ pRcv = bufRcv;
+ } else {
+ CHKmalloc(pRcv = (uchar*) malloc(sizeof(uchar) * (iMaxLine + 1)));
+ }
+
+ do {
+ DBGPRINTF("imsolaris: waiting for next message (timeout %d)...\n", timeout);
+ if(timeout == 0) {
+ nfds = poll(&sun_Pfd, 1, timeout); /* wait without timeout */
+
+ /* v5-TODO: here we must check if we should terminante! */
+
+ if(nfds == 0) {
+ if(timeout == 0) {
+ DBGPRINTF("imsolaris: no more messages, getMsgs() terminates\n");
+ FINALIZE;
+ } else {
+ continue;
+ }
+ }
+
+ if(nfds < 0) {
+ if(errno != EINTR) {
+ int en = errno;
+ rs_strerror_r(en, errStr, sizeof(errStr));
+ DBGPRINTF("imsolaris: poll error: %d = %s.\n", errno, errStr);
+ errmsg.LogError(en, NO_ERRCODE, "imsolaris: poll error: %s",
+ errStr);
+ }
+ continue;
+ }
+ if(sun_Pfd.revents & POLLIN) {
+ readLog(sun_Pfd.fd, pRcv, iMaxLine);
+ } else if(sun_Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) {
+ tryRecover();
+ }
+ } else {
+ /* if we have an infinite wait, we do not use poll at all
+ * I'd consider this a waste of time. However, I do not totally
+ * remove the code, as it may be useful if we decide at some
+ * point to provide a capability to support multiple input streams
+ * at once (this may be useful for a jail). In that case, the poll()
+ * loop would be needed, and so it doesn't make much sense to change
+ * the code to not support it. -- rgerhards, 2010-04-20
+ */
+ readLog(sun_Pfd.fd, pRcv, iMaxLine);
+ }
+
+ } while(1); /* TODO: in v5, we must check the termination predicate */
+
+ /* Note: in v4, this code is never reached (our thread will be cancelled) */
+
+finalize_it:
+ if(pRcv != NULL && (size_t) iMaxLine >= sizeof(bufRcv) - 1)
+ free(pRcv);
+
+ RETiRet;
+}
+
+
+/* This function is called to gather input. */
+BEGINrunInput
+CODESTARTrunInput
+ /* this is an endless loop - it is terminated when the thread is
+ * signalled to do so. This, however, is handled by the framework,
+ * right into the sleep below.
+ */
+
+ DBGPRINTF("imsolaris: doing startup poll before openeing door()\n");
+ CHKiRet(getMsgs(0));
+
+ /* note: sun's syslogd code claims that the door should only
+ * be opened when the log stream has been polled. So file header
+ * comment of this file for more details.
+ */
+ sun_open_door();
+ DBGPRINTF("imsolaris: starting regular poll loop\n");
+ iRet = getMsgs(-1); /* this is the primary poll loop, infinite timeout */
+
+finalize_it:
+ RETiRet;
+ENDrunInput
+
+
+BEGINwillRun
+CODESTARTwillRun
+ /* we need to create the inputName property (only once during our lifetime) */
+ CHKiRet(prop.Construct(&pInputName));
+ CHKiRet(prop.SetString(pInputName, UCHAR_CONSTANT("imsolaris"), sizeof("imsolaris") - 1));
+ CHKiRet(prop.ConstructFinalize(pInputName));
+
+ iRet = sun_openklog((LogName == NULL) ? PATH_LOG : LogName);
+ if(iRet != RS_RET_OK) {
+ errmsg.LogError(0, iRet, "error opening system log socket");
+ }
+finalize_it:
+ENDwillRun
+
+
+BEGINafterRun
+CODESTARTafterRun
+ /* do cleanup here */
+ if(pInputName != NULL)
+ prop.Destruct(&pInputName);
+ free(LogName);
+ENDafterRun
+
+
+BEGINmodExit
+CODESTARTmodExit
+ sun_delete_doorfiles();
+ objRelease(glbl, CORE_COMPONENT);
+ objRelease(errmsg, CORE_COMPONENT);
+ objRelease(prop, CORE_COMPONENT);
+ENDmodExit
+
+
+BEGINqueryEtryPt
+CODESTARTqueryEtryPt
+CODEqueryEtryPt_STD_IMOD_QUERIES
+ENDqueryEtryPt
+
+static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp,
+ void __attribute__((unused)) *pVal)
+{
+ return RS_RET_OK;
+}
+
+
+BEGINmodInit()
+CODESTARTmodInit
+ *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
+CODEmodInit_QueryRegCFSLineHdlr
+ CHKiRet(objUse(errmsg, CORE_COMPONENT));
+ CHKiRet(objUse(glbl, CORE_COMPONENT));
+ CHKiRet(objUse(prop, CORE_COMPONENT));
+
+ DBGPRINTF("imsolaris version %s initializing\n", PACKAGE_VERSION);
+
+ /* register config file handlers */
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler,
+ resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"imsolarislogsocketname", 0, eCmdHdlrGetWord,
+ NULL, &LogName, STD_LOADABLE_MODULE_ID));
+ENDmodInit
+/* vim:set ai:
+ */
diff --git a/plugins/imsolaris/imsolaris.h b/plugins/imsolaris/imsolaris.h
new file mode 100644
index 00000000..e73380fa
--- /dev/null
+++ b/plugins/imsolaris/imsolaris.h
@@ -0,0 +1,2 @@
+rsRetVal solaris_readLog(int fd);
+void imsolaris_logerror(int err, char *errStr);
diff --git a/plugins/imsolaris/sun_cddl.c b/plugins/imsolaris/sun_cddl.c
new file mode 100644
index 00000000..6d49c8bc
--- /dev/null
+++ b/plugins/imsolaris/sun_cddl.c
@@ -0,0 +1,419 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Portions Copyright 2010 by Rainer Gerhards and Adiscon
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
+ * All Rights Reserved
+ */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <pthread.h>
+#include <fcntl.h>
+#include <stropts.h>
+#include <assert.h>
+
+#include <sys/param.h>
+#include <sys/strlog.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/poll.h>
+#include <door.h>
+#include <sys/door.h>
+
+#include "rsyslog.h"
+#include "srUtils.h"
+#include "debug.h"
+#include "imsolaris.h"
+
+#define DOORFILE "/var/run/syslog_door"
+#define RELATIVE_DOORFILE "../var/run/syslog_door"
+#define OLD_DOORFILE "/etc/.syslog_door"
+
+/* Buffer to allocate for error messages: */
+#define ERRMSG_LEN 1024
+
+/* Max number of door server threads for syslogd. Since door is used
+ * to check the health of syslogd, we don't need large number of
+ * server threads.
+ */
+#define MAX_DOOR_SERVER_THR 3
+
+
+struct pollfd sun_Pfd; /* Pollfd for local log device */
+
+static int DoorFd = -1;
+static int DoorCreated = 0;
+static char *DoorFileName = DOORFILE;
+
+/* for managing door server threads */
+static pthread_mutex_t door_server_cnt_lock = PTHREAD_MUTEX_INITIALIZER;
+static uint_t door_server_cnt = 0;
+static pthread_attr_t door_thr_attr;
+
+/* the 'server' function that we export via the door. It does
+ * nothing but return.
+ */
+/*ARGSUSED*/
+static void
+server( void __attribute__((unused)) *cookie,
+ char __attribute__((unused)) *argp,
+ size_t __attribute__((unused)) arg_size,
+ door_desc_t __attribute__((unused)) *dp,
+ __attribute__((unused)) uint_t n )
+{
+ (void) door_return(NULL, 0, NULL, 0);
+ /* NOTREACHED */
+}
+
+/*ARGSUSED*/
+static void *
+create_door_thr(void __attribute__((unused)) *arg)
+{
+ (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+ (void) door_return(NULL, 0, NULL, 0);
+
+ /* If there is an error in door_return(), it will return here and
+ * the thread will exit. Hence we need to decrement door_server_cnt.
+ */
+ (void) pthread_mutex_lock(&door_server_cnt_lock);
+ door_server_cnt--;
+ (void) pthread_mutex_unlock(&door_server_cnt_lock);
+ return (NULL);
+}
+
+/*
+ * Manage door server thread pool.
+ */
+/*ARGSUSED*/
+static void
+door_server_pool(door_info_t __attribute__((unused)) *dip)
+{
+ (void) pthread_mutex_lock(&door_server_cnt_lock);
+ if (door_server_cnt <= MAX_DOOR_SERVER_THR &&
+ pthread_create(NULL, &door_thr_attr, create_door_thr, NULL) == 0) {
+ door_server_cnt++;
+ (void) pthread_mutex_unlock(&door_server_cnt_lock);
+ return;
+ }
+
+ (void) pthread_mutex_unlock(&door_server_cnt_lock);
+}
+
+void
+sun_delete_doorfiles(void)
+{
+ struct stat sb;
+ int err;
+ char line[ERRMSG_LEN+1];
+
+ if (lstat(DoorFileName, &sb) == 0 && !S_ISDIR(sb.st_mode)) {
+ if (unlink(DoorFileName) < 0) {
+ err = errno;
+ (void) snprintf(line, sizeof (line),
+ "unlink() of %s failed - fatal", DoorFileName);
+ imsolaris_logerror(err, line);
+ DBGPRINTF("delete_doorfiles: error: %s, "
+ "errno=%d\n", line, err);
+ exit(1);
+ }
+
+ DBGPRINTF("delete_doorfiles: deleted %s\n", DoorFileName);
+ }
+
+ if (strcmp(DoorFileName, DOORFILE) == 0) {
+ if (lstat(OLD_DOORFILE, &sb) == 0 && !S_ISDIR(sb.st_mode)) {
+ if (unlink(OLD_DOORFILE) < 0) {
+ err = errno;
+ (void) snprintf(line, sizeof (line),
+ "unlink() of %s failed", OLD_DOORFILE);
+ DBGPRINTF("delete_doorfiles: %s\n", line);
+
+ if (err != EROFS) {
+ errno = err;
+ (void) strlcat(line, " - fatal",
+ sizeof (line));
+ imsolaris_logerror(err, line);
+ DBGPRINTF("delete_doorfiles: "
+ "error: %s, errno=%d\n",
+ line, err);
+ exit(1);
+ }
+
+ DBGPRINTF("delete_doorfiles: unlink() "
+ "failure OK on RO file system\n");
+ }
+
+ DBGPRINTF("delete_doorfiles: deleted %s\n",
+ OLD_DOORFILE);
+ }
+ }
+
+ if (DoorFd != -1) {
+ (void) door_revoke(DoorFd);
+ }
+
+ DBGPRINTF("delete_doorfiles: revoked door: DoorFd=%d\n",
+ DoorFd);
+}
+
+
+/* Create the door file. If the filesystem
+ * containing /etc is writable, create symlinks /etc/.syslog_door
+ * to them. On systems that do not support /var/run, create
+ * /etc/.syslog_door directly.
+ */
+void
+sun_open_door(void)
+{
+ struct stat buf;
+ door_info_t info;
+ char line[ERRMSG_LEN+1];
+ int err;
+
+ /* first see if another instance of imsolaris OR another
+ * syslogd is running by trying a door call - if it succeeds,
+ * there is already one active.
+ */
+
+ if (!DoorCreated) {
+ int door;
+
+ if ((door = open(DoorFileName, O_RDONLY)) >= 0) {
+ DBGPRINTF("open_door: %s opened "
+ "successfully\n", DoorFileName);
+
+ if (door_info(door, &info) >= 0) {
+ DBGPRINTF("open_door: "
+ "door_info:info.di_target = %ld\n",
+ info.di_target);
+
+ if (info.di_target > 0) {
+ (void) sprintf(line, "syslogd pid %ld"
+ " already running. Cannot "
+ "start another syslogd pid %ld",
+ info.di_target, getpid());
+ DBGPRINTF("open_door: error: "
+ "%s\n", line);
+ imsolaris_logerror(0, line);
+ exit(1);
+ }
+ }
+
+ (void) close(door);
+ } else {
+ if (lstat(DoorFileName, &buf) < 0) {
+ err = errno;
+
+ DBGPRINTF("open_door: lstat() of %s "
+ "failed, errno=%d\n",
+ DoorFileName, err);
+
+ if ((door = creat(DoorFileName, 0644)) < 0) {
+ err = errno;
+ (void) snprintf(line, sizeof (line),
+ "creat() of %s failed - fatal",
+ DoorFileName);
+ DBGPRINTF("open_door: error: %s, "
+ "errno=%d\n", line,
+ err);
+ imsolaris_logerror(err, line);
+ sun_delete_doorfiles();
+ exit(1);
+ }
+
+ (void) fchmod(door,
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+
+ DBGPRINTF("open_door: creat() of %s "
+ "succeeded\n",
+ DoorFileName);
+
+ (void) close(door);
+ }
+ }
+
+ if (strcmp(DoorFileName, DOORFILE) == 0) {
+ if (lstat(OLD_DOORFILE, &buf) == 0) {
+ DBGPRINTF("open_door: lstat() of %s "
+ "succeeded\n", OLD_DOORFILE);
+
+ if (S_ISDIR(buf.st_mode)) {
+ (void) snprintf(line, sizeof (line),
+ "%s is a directory - fatal",
+ OLD_DOORFILE);
+ DBGPRINTF("open_door: error: "
+ "%s\n", line);
+ imsolaris_logerror(0, line);
+ sun_delete_doorfiles();
+ exit(1);
+ }
+
+ DBGPRINTF("open_door: %s is not a "
+ "directory\n", OLD_DOORFILE);
+ if (unlink(OLD_DOORFILE) < 0) {
+ err = errno;
+ (void) snprintf(line, sizeof (line),
+ "unlink() of %s failed",
+ OLD_DOORFILE);
+ DBGPRINTF("open_door: %s\n",
+ line);
+
+ if (err != EROFS) {
+ DBGPRINTF("open_door: "
+ "error: %s, "
+ "errno=%d\n",
+ line, err);
+ (void) strcat(line, " - fatal");
+ imsolaris_logerror(err, line);
+ sun_delete_doorfiles();
+ exit(1);
+ }
+
+ DBGPRINTF("open_door: unlink "
+ "failure OK on RO file "
+ "system\n");
+ }
+ } else {
+ DBGPRINTF("open_door: file %s doesn't "
+ "exist\n", OLD_DOORFILE);
+ }
+
+ if (symlink(RELATIVE_DOORFILE, OLD_DOORFILE) < 0) {
+ err = errno;
+ (void) snprintf(line, sizeof (line),
+ "symlink %s -> %s failed", OLD_DOORFILE,
+ RELATIVE_DOORFILE);
+ DBGPRINTF("open_door: %s\n",
+ line);
+
+ if (err != EROFS) {
+ DBGPRINTF("open_door: error: %s, "
+ "errno=%d\n", line,
+ err);
+ (void) strcat(line, " - fatal");
+ imsolaris_logerror(err, line);
+ sun_delete_doorfiles();
+ exit(1);
+ }
+
+ DBGPRINTF("open_door: symlink failure OK "
+ "on RO file system\n");
+ } else {
+ DBGPRINTF("open_door: symlink %s -> %s "
+ "succeeded\n",
+ OLD_DOORFILE, RELATIVE_DOORFILE);
+ }
+ }
+
+ if ((DoorFd = door_create(server, 0,
+ DOOR_REFUSE_DESC)) < 0) {
+ //???? DOOR_NO_CANEL requires newer libs??? DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) < 0) {
+ err = errno;
+ (void) sprintf(line, "door_create() failed - fatal");
+ DBGPRINTF("open_door: error: %s, errno=%d\n",
+ line, err);
+ imsolaris_logerror(err, line);
+ sun_delete_doorfiles();
+ exit(1);
+ }
+ //???? (void) door_setparam(DoorFd, DOOR_PARAM_DATA_MAX, 0);
+ DBGPRINTF("open_door: door_create() succeeded, "
+ "DoorFd=%d\n", DoorFd);
+
+ DoorCreated = 1;
+ }
+
+ (void) fdetach(DoorFileName); /* just in case... */
+
+ (void) door_server_create(door_server_pool);
+
+ if (fattach(DoorFd, DoorFileName) < 0) {
+ err = errno;
+ (void) snprintf(line, sizeof (line), "fattach() of fd"
+ " %d to %s failed - fatal", DoorFd, DoorFileName);
+ DBGPRINTF("open_door: error: %s, errno=%d\n",
+ line, err);
+ imsolaris_logerror(err, line);
+ sun_delete_doorfiles();
+ exit(1);
+ }
+
+ DBGPRINTF("open_door: attached server() to %s\n",
+ DoorFileName);
+
+}
+
+
+/* Attempts to open the local log device
+ * and return a file descriptor.
+ */
+rsRetVal
+sun_openklog(char *name)
+{
+ DEFiRet;
+ int fd;
+ struct strioctl str;
+ char errBuf[1024];
+
+ if((fd = open(name, O_RDONLY)) < 0) {
+ rs_strerror_r(errno, errBuf, sizeof(errBuf));
+ DBGPRINTF("imsolaris:openklog: cannot open %s: %s\n",
+ name, errBuf);
+ ABORT_FINALIZE(RS_RET_ERR_OPEN_KLOG);
+ }
+ str.ic_cmd = I_CONSLOG;
+ str.ic_timout = 0;
+ str.ic_len = 0;
+ str.ic_dp = NULL;
+ if (ioctl(fd, I_STR, &str) < 0) {
+ rs_strerror_r(errno, errBuf, sizeof(errBuf));
+ DBGPRINTF("imsolaris:openklog: cannot register to log "
+ "console messages: %s\n", errBuf);
+ ABORT_FINALIZE(RS_RET_ERR_AQ_CONLOG);
+ }
+ sun_Pfd.fd = fd;
+ sun_Pfd.events = POLLIN;
+ DBGPRINTF("imsolaris/openklog: opened '%s' as fd %d.\n", name, fd);
+
+finalize_it:
+ RETiRet;
+}
diff --git a/plugins/imsolaris/sun_cddl.h b/plugins/imsolaris/sun_cddl.h
new file mode 100644
index 00000000..42e4b799
--- /dev/null
+++ b/plugins/imsolaris/sun_cddl.h
@@ -0,0 +1,7 @@
+rsRetVal sun_openklog(char *name);
+void prepare_sys_poll(void);
+void sun_sys_poll(void);
+void sun_open_door(void);
+void sun_delete_doorfiles(void);
+
+extern struct pollfd sun_Pfd; /* Pollfd for local log device */
diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c
index f8555f00..d76f3544 100644
--- a/plugins/imudp/imudp.c
+++ b/plugins/imudp/imudp.c
@@ -45,6 +45,7 @@
#include "datetime.h"
#include "prop.h"
#include "unicode-helper.h"
+#include "unlimited_select.h"
MODULE_TYPE_INPUT
@@ -287,12 +288,18 @@ BEGINrunInput
int maxfds;
int nfds;
int i;
- fd_set readfds;
struct sockaddr_storage frominetPrev;
int bIsPermitted;
uchar fromHost[NI_MAXHOST];
uchar fromHostIP[NI_MAXHOST];
uchar fromHostFQDN[NI_MAXHOST];
+#ifdef USE_UNLIMITED_SELECT
+ fd_set *pReadfds = malloc(glbl.GetFdSetSize());
+#else
+ fd_set readfds;
+ fd_set *pReadfds = &readfds;
+#endif
+
CODESTARTrunInput
/* start "name caching" algo by making sure the previous system indicator
* is invalidated.
@@ -311,30 +318,30 @@ CODESTARTrunInput
* is given without -a, we do not need to listen at all..
*/
maxfds = 0;
- FD_ZERO (&readfds);
+ FD_ZERO (pReadfds);
/* Add the UDP listen sockets to the list of read descriptors. */
for (i = 0; i < *udpLstnSocks; i++) {
if (udpLstnSocks[i+1] != -1) {
if(Debug)
net.debugListenInfo(udpLstnSocks[i+1], "UDP");
- FD_SET(udpLstnSocks[i+1], &readfds);
+ FD_SET(udpLstnSocks[i+1], pReadfds);
if(udpLstnSocks[i+1]>maxfds) maxfds=udpLstnSocks[i+1];
}
}
if(Debug) {
dbgprintf("--------imUDP calling select, active file descriptors (max %d): ", maxfds);
for (nfds = 0; nfds <= maxfds; ++nfds)
- if ( FD_ISSET(nfds, &readfds) )
+ if ( FD_ISSET(nfds, pReadfds) )
dbgprintf("%d ", nfds);
dbgprintf("\n");
}
/* wait for io to become ready */
- nfds = select(maxfds+1, (fd_set *) &readfds, NULL, NULL, NULL);
+ nfds = select(maxfds+1, (fd_set *) pReadfds, NULL, NULL, NULL);
for(i = 0; nfds && i < *udpLstnSocks; i++) {
- if(FD_ISSET(udpLstnSocks[i+1], &readfds)) {
+ if(FD_ISSET(udpLstnSocks[i+1], pReadfds)) {
processSocket(udpLstnSocks[i+1], &frominetPrev, &bIsPermitted,
fromHost, fromHostFQDN, fromHostIP);
--nfds; /* indicate we have processed one descriptor */
@@ -343,6 +350,7 @@ CODESTARTrunInput
/* end of a run, back to loop for next recv() */
}
+ freeFdSet(pReadfds);
return iRet;
ENDrunInput
diff --git a/plugins/imuxsock/imuxsock.c b/plugins/imuxsock/imuxsock.c
index 5567a405..daa3bb47 100644
--- a/plugins/imuxsock/imuxsock.c
+++ b/plugins/imuxsock/imuxsock.c
@@ -45,6 +45,7 @@
#include "glbl.h"
#include "msg.h"
#include "prop.h"
+#include "unlimited_select.h"
MODULE_TYPE_INPUT
@@ -77,6 +78,7 @@ 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] = { IGNDATE, }; /* should parser parse host name? read-only after startup */
+static int funixCreateSockPath[MAXFUNIX] = { 0, }; /* auto-creation of socket directory? */
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 */
@@ -89,6 +91,8 @@ 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? */
+#define DFLT_bCreateSockPath 0
+static int bCreateSockPath = DFLT_bCreateSockPath; /* auto-create socket path? */
/* set the timestamp ignore / not ignore option for the system
@@ -132,6 +136,7 @@ static rsRetVal addLstnSocketName(void __attribute__((unused)) *pVal, uchar *pNe
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 ? IGNDATE : NOFLAG;
+ funixCreateSockPath[nfunix] = bCreateSockPath;
funixn[nfunix++] = pNewVal;
}
else {
@@ -165,7 +170,7 @@ static rsRetVal discardFunixn(void)
}
-static int create_unix_socket(const char *path)
+static int create_unix_socket(const char *path, int bCreatePath)
{
struct sockaddr_un sunx;
int fd;
@@ -177,6 +182,9 @@ static int create_unix_socket(const char *path)
memset(&sunx, 0, sizeof(sunx));
sunx.sun_family = AF_UNIX;
+ if(bCreatePath) {
+ makeFileParentDirs((uchar*)path, strlen(path), 0755, -1, -1, 0);
+ }
(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 ||
@@ -249,7 +257,13 @@ BEGINrunInput
int nfds;
int i;
int fd;
- fd_set readfds;
+#ifdef USE_UNLIMITED_SELECT
+ fd_set *pReadfds = malloc(glbl.GetFdSetSize());
+#else
+ fd_set readfds;
+ fd_set *pReadfds = &readfds;
+#endif
+
CODESTARTrunInput
/* this is an endless loop - it is terminated when the thread is
* signalled to do so. This, however, is handled by the framework,
@@ -263,11 +277,11 @@ CODESTARTrunInput
* is given without -a, we do not need to listen at all..
*/
maxfds = 0;
- FD_ZERO (&readfds);
+ FD_ZERO (pReadfds);
/* Copy master connections */
for (i = startIndexUxLocalSockets; i < nfunix; i++) {
if (funix[i] != -1) {
- FD_SET(funix[i], &readfds);
+ FD_SET(funix[i], pReadfds);
if (funix[i]>maxfds) maxfds=funix[i];
}
}
@@ -275,22 +289,23 @@ CODESTARTrunInput
if(Debug) {
dbgprintf("--------imuxsock calling select, active file descriptors (max %d): ", maxfds);
for (nfds= 0; nfds <= maxfds; ++nfds)
- if ( FD_ISSET(nfds, &readfds) )
+ if ( FD_ISSET(nfds, pReadfds) )
dbgprintf("%d ", nfds);
dbgprintf("\n");
}
/* wait for io to become ready */
- nfds = select(maxfds+1, (fd_set *) &readfds, NULL, NULL, NULL);
+ nfds = select(maxfds+1, (fd_set *) pReadfds, NULL, NULL, NULL);
for (i = 0; i < nfunix && nfds > 0; i++) {
- if ((fd = funix[i]) != -1 && FD_ISSET(fd, &readfds)) {
+ if ((fd = funix[i]) != -1 && FD_ISSET(fd, pReadfds)) {
readSocket(fd, i);
--nfds; /* indicate we have processed one */
}
}
}
+ freeFdSet(pReadfds);
RETiRet;
ENDrunInput
@@ -300,13 +315,22 @@ CODESTARTwillRun
register int i;
/* first apply some config settings */
- startIndexUxLocalSockets = bOmitLocalLogging ? 1 : 0;
+# ifdef OS_SOLARIS
+ /* under solaris, we must NEVER process the local log socket, because
+ * it is implemented there differently. If we used it, we would actually
+ * delete it and render the system partly unusable. So don't do that.
+ * rgerhards, 2010-03-26
+ */
+ startIndexUxLocalSockets = 1;
+# else
+ startIndexUxLocalSockets = bOmitLocalLogging ? 1 : 0;
+# endif
if(pLogSockName != NULL)
funixn[0] = pLogSockName;
/* initialize and return if will run or not */
for (i = startIndexUxLocalSockets ; i < nfunix ; i++) {
- if ((funix[i] = create_unix_socket((char*) funixn[i])) != -1)
+ if ((funix[i] = create_unix_socket((char*) funixn[i], funixCreateSockPath[i])) != -1)
dbgprintf("Opened UNIX socket '%s' (fd %d).\n", funixn[i], funix[i]);
}
@@ -329,7 +353,7 @@ CODESTARTafterRun
close(funix[i]);
/* Clean-up files. */
- for (i = 0; i < nfunix; i++)
+ for(i = startIndexUxLocalSockets; i < nfunix; i++)
if (funixn[i] && funix[i] != -1)
unlink((char*) funixn[i]);
/* free no longer needed string */
@@ -376,6 +400,7 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a
nfunix = 1;
bIgnoreTimestamp = 1;
bUseFlowCtl = 0;
+ bCreateSockPath = DFLT_bCreateSockPath;
return RS_RET_OK;
}
@@ -409,6 +434,8 @@ CODEmodInit_QueryRegCFSLineHdlr
NULL, &pLogHostName, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketflowcontrol", 0, eCmdHdlrBinary,
NULL, &bUseFlowCtl, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketcreatepath", 0, eCmdHdlrBinary,
+ NULL, &bCreateSockPath, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"addunixlistensocket", 0, eCmdHdlrGetWord,
addLstnSocketName, NULL, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler,
diff --git a/plugins/omoracle/omoracle.c b/plugins/omoracle/omoracle.c
index 331b7dd4..48ee1fa4 100644
--- a/plugins/omoracle/omoracle.c
+++ b/plugins/omoracle/omoracle.c
@@ -47,9 +47,9 @@
$OmoracleStatement \
insert into foo(hostname,message)values(:host,:message)
- Also note that identifiers to placeholders are arbitrarry. You
- need to define the properties on the template in the correct order
- you want them passed to the statement!
+ Also note that identifiers to placeholders are arbitrary. You need
+ to define the properties on the template in the correct order you
+ want them passed to the statement!
This file is licensed under the terms of the GPL version 3 or, at
your choice, any later version. Exceptionally (perhaps), you are
@@ -87,7 +87,8 @@ MODULE_TYPE_OUTPUT
DEF_OMOD_STATIC_DATA
DEFobjCurrIf(errmsg)
-/** */
+/** Structure defining a batch of items to be sent to the database in
+ * the same statement execution. */
struct oracle_batch
{
/* Batch size */
@@ -162,8 +163,10 @@ static int oci_errors(void* handle, ub4 htype, sword status)
return OCI_SUCCESS;
break;
case OCI_SUCCESS_WITH_INFO:
- errmsg.LogError(0, NO_ERRCODE, "OCI SUCCESS - With info\n");
- break;
+ OCIErrorGet(handle, 1, NULL, &errcode, buf, sizeof buf, htype);
+ errmsg.LogError(0, NO_ERRCODE, "OCI SUCCESS - With info: %s",
+ buf);
+ return OCI_SUCCESS_WITH_INFO;
case OCI_NEED_DATA:
errmsg.LogError(0, NO_ERRCODE, "OCI NEEDS MORE DATA\n");
break;
@@ -180,6 +183,9 @@ static int oci_errors(void* handle, ub4 htype, sword status)
break;
case OCI_INVALID_HANDLE:
errmsg.LogError(0, NO_ERRCODE, "OCI INVALID HANDLE\n");
+ /* In this case we may have to trigger a call to
+ * tryResume(). */
+ return RS_RET_SUSPENDED;
break;
case OCI_STILL_EXECUTING:
errmsg.LogError(0, NO_ERRCODE, "Still executing...\n");
@@ -332,6 +338,48 @@ CODESTARTcreateInstance
finalize_it:
ENDcreateInstance
+/* Analyses the errors during a batch statement execution, and logs
+ * all the corresponding ORA-MESSAGES, together with some useful
+ * information. */
+static void log_detailed_err(instanceData* pData)
+{
+ DEFiRet;
+ int errs, i, row, code, j;
+ OCIError *er = NULL, *er2 = NULL;
+ unsigned char buf[MAX_BUFSIZE];
+
+ OCIAttrGet(pData->statement, OCI_HTYPE_STMT, &errs, 0,
+ OCI_ATTR_NUM_DML_ERRORS, pData->error);
+ errmsg.LogError(0, NO_ERRCODE, "OCI: %d errors in execution of "
+ "statement: %s", errs, pData->txt_statement);
+
+ CHECKENV(pData->environment,
+ OCIHandleAlloc(pData->environment, &er, OCI_HTYPE_ERROR,
+ 0, NULL));
+ CHECKENV(pData->environment,
+ OCIHandleAlloc(pData->environment, &er2, OCI_HTYPE_ERROR,
+ 0, NULL));
+
+ for (i = 0; i < errs; i++) {
+ OCIParamGet(pData->error, OCI_HTYPE_ERROR,
+ er2, &er, i);
+ OCIAttrGet(er, OCI_HTYPE_ERROR, &row, 0,
+ OCI_ATTR_DML_ROW_OFFSET, er2);
+ errmsg.LogError(0, NO_ERRCODE, "OCI failure in row %d:", row);
+ for (j = 0; j < pData->batch.arguments; j++)
+ errmsg.LogError(0, NO_ERRCODE, "%s",
+ pData->batch.parameters[j][row]);
+ OCIErrorGet(er, 1, NULL, &code, buf, sizeof buf,
+ OCI_HTYPE_ERROR);
+ errmsg.LogError(0, NO_ERRCODE, "FAILURE DETAILS: %s", buf);
+ }
+
+finalize_it:
+ OCIHandleFree(er, OCI_HTYPE_ERROR);
+ OCIHandleFree(er2, OCI_HTYPE_ERROR);
+}
+
+
/* Inserts all stored statements into the database, releasing any
* allocated memory. */
static int insert_to_db(instanceData* pData)
@@ -346,6 +394,10 @@ static int insert_to_db(instanceData* pData)
OCI_BATCH_ERRORS));
finalize_it:
+ if (iRet == OCI_SUCCESS_WITH_INFO) {
+ log_detailed_err(pData);
+ iRet = RS_RET_OK;
+ }
pData->batch.n = 0;
OCITransCommit(pData->service, pData->error, 0);
dbgprintf ("omoracle insertion to DB %s\n", iRet == RS_RET_OK ?
diff --git a/plugins/omprog/omprog.c b/plugins/omprog/omprog.c
index 01fa7cea..2687e7a3 100644
--- a/plugins/omprog/omprog.c
+++ b/plugins/omprog/omprog.c
@@ -169,7 +169,7 @@ openPipe(instanceData *pData)
/*NO CODE HERE - WILL NEVER BE REACHED!*/
}
- DBGPRINTF("child has pid %d\n", cpid);
+ DBGPRINTF("child has pid %d\n", (int) cpid);
pData->fdPipe = pipefd[1];
pData->pid = cpid;
close(pipefd[0]);
@@ -191,7 +191,6 @@ cleanup(instanceData *pData)
assert(pData != NULL);
assert(pData->bIsRunning == 1);
-RUNLOG_VAR("%d", pData->pid);
ret = waitpid(pData->pid, &status, 0);
if(ret != pData->pid) {
/* if waitpid() fails, we can not do much - try to ignore it... */
diff --git a/plugins/omstdout/omstdout.c b/plugins/omstdout/omstdout.c
index b3ec6287..929de703 100644
--- a/plugins/omstdout/omstdout.c
+++ b/plugins/omstdout/omstdout.c
@@ -103,7 +103,7 @@ CODESTARTdoAction
* So this code here is also more or less an example of how to do that.
* rgerhards, 2009-04-03
*/
- szParams = (char**) (ppString[0]);
+ szParams = (char**)(void*) (ppString[0]);
/* In array-passing mode, ppString[] contains a NULL-terminated array
* of char *pointers.
*/
diff --git a/plugins/omuxsock/Makefile.am b/plugins/omuxsock/Makefile.am
new file mode 100644
index 00000000..997232d9
--- /dev/null
+++ b/plugins/omuxsock/Makefile.am
@@ -0,0 +1,8 @@
+pkglib_LTLIBRARIES = omuxsock.la
+
+omuxsock_la_SOURCES = omuxsock.c
+omuxsock_la_CPPFLAGS = $(RSRT_CFLAGS) $(PTHREADS_CFLAGS)
+omuxsock_la_LDFLAGS = -module -avoid-version
+omuxsock_la_LIBADD =
+
+EXTRA_DIST =
diff --git a/plugins/omuxsock/omuxsock.c b/plugins/omuxsock/omuxsock.c
new file mode 100644
index 00000000..c66e63aa
--- /dev/null
+++ b/plugins/omuxsock/omuxsock.c
@@ -0,0 +1,315 @@
+/* omuxsock.c
+ * This is the implementation of datgram unix domain socket forwarding.
+ *
+ * NOTE: read comments in module-template.h to understand how this file
+ * works!
+ *
+ * File begun on 2007-07-20 by RGerhards (extracted from syslogd.c)
+ * This file is under development and has not yet arrived at being fully
+ * self-contained and a real object. So far, it is mostly an excerpt
+ * of the "old" message code without any modifications. However, it
+ * helps to have things at the right place one we go to the meat of it.
+ *
+ * Copyright 2010 Rainer Gerhards and Adiscon GmbH.
+ *
+ * This file is part of rsyslog.
+ *
+ * Rsyslog is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Rsyslog is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Rsyslog. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+ */
+#include "config.h"
+#include "rsyslog.h"
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <assert.h>
+#include <errno.h>
+#include <unistd.h>
+#include "conf.h"
+#include "srUtils.h"
+#include "template.h"
+#include "msg.h"
+#include "cfsysline.h"
+#include "module-template.h"
+#include "glbl.h"
+#include "errmsg.h"
+#include "unicode-helper.h"
+
+MODULE_TYPE_OUTPUT
+
+/* internal structures
+ */
+DEF_OMOD_STATIC_DATA
+DEFobjCurrIf(errmsg)
+DEFobjCurrIf(glbl)
+
+#define INVLD_SOCK -1
+
+typedef struct _instanceData {
+ permittedPeers_t *pPermPeers;
+ uchar *sockName;
+ int sock;
+ int bIsConnected; /* are we connected to remote host? 0 - no, 1 - yes, UDP means addr resolved */
+ struct sockaddr_un addr;
+} instanceData;
+
+/* config data */
+static uchar *tplName = NULL; /* name of the default template to use */
+static uchar *sockName = NULL; /* name of the default template to use */
+
+static rsRetVal doTryResume(instanceData *pData);
+
+/* Close socket.
+ */
+static inline rsRetVal
+closeSocket(instanceData *pData)
+{
+ DEFiRet;
+ if(pData->sock != INVLD_SOCK) {
+ close(pData->sock);
+ pData->sock = INVLD_SOCK;
+ }
+pData->bIsConnected = 0; // TODO: remove this variable altogether
+ RETiRet;
+}
+
+
+
+BEGINcreateInstance
+CODESTARTcreateInstance
+ pData->sock = INVLD_SOCK;
+ENDcreateInstance
+
+
+BEGINisCompatibleWithFeature
+CODESTARTisCompatibleWithFeature
+ if(eFeat == sFEATURERepeatedMsgReduction)
+ iRet = RS_RET_OK;
+ENDisCompatibleWithFeature
+
+
+BEGINfreeInstance
+CODESTARTfreeInstance
+ /* final cleanup */
+ closeSocket(pData);
+ free(pData->sockName);
+ENDfreeInstance
+
+
+BEGINdbgPrintInstInfo
+CODESTARTdbgPrintInstInfo
+ DBGPRINTF("%s", pData->sockName);
+ENDdbgPrintInstInfo
+
+
+/* Send a message via UDP
+ * rgehards, 2007-12-20
+ */
+static rsRetVal sendMsg(instanceData *pData, char *msg, size_t len)
+{
+ DEFiRet;
+ unsigned lenSent = 0;
+
+ if(pData->sock == INVLD_SOCK) {
+ CHKiRet(doTryResume(pData));
+ }
+
+ if(pData->sock != INVLD_SOCK) {
+ /* we need to track if we have success sending to the remote
+ * peer. Success is indicated by at least one sendto() call
+ * succeeding. We track this be bSendSuccess. We can not simply
+ * rely on lsent, as a call might initially work, but a later
+ * call fails. Then, lsent has the error status, even though
+ * the sendto() succeeded. -- rgerhards, 2007-06-22
+ */
+ lenSent = sendto(pData->sock, msg, len, 0, &pData->addr, sizeof(pData->addr));
+ if(lenSent == len) {
+ int eno = errno;
+ char errStr[1024];
+ DBGPRINTF("omuxsock suspending: sendto(), socket %d, error: %d = %s.\n",
+ pData->sock, eno, rs_strerror_r(eno, errStr, sizeof(errStr)));
+ }
+ }
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* open socket to remote system
+ */
+static inline rsRetVal
+openSocket(instanceData *pData)
+{
+ DEFiRet;
+ assert(pData->sock == INVLD_SOCK);
+
+ if((pData->sock = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
+ char errStr[1024];
+ int eno = errno;
+ DBGPRINTF("error %d creating AF_UNIX/SOCK_DGRAM: %s.\n",
+ eno, rs_strerror_r(eno, errStr, sizeof(errStr)));
+ pData->sock = INVLD_SOCK;
+ ABORT_FINALIZE(RS_RET_NO_SOCKET);
+
+ }
+
+ /* set up server address structure */
+ memset(&pData->addr, 0, sizeof(pData->addr));
+ pData->addr.sun_family = AF_UNIX;
+ strcpy(pData->addr.sun_path, (char*)pData->sockName);
+
+finalize_it:
+ if(iRet != RS_RET_OK) {
+ closeSocket(pData);
+ }
+ RETiRet;
+}
+
+
+
+/* try to resume connection if it is not ready
+ */
+static rsRetVal doTryResume(instanceData *pData)
+{
+ DEFiRet;
+
+ DBGPRINTF("omuxsock trying to resume\n");
+ closeSocket(pData);
+ iRet = openSocket(pData);
+
+ if(iRet != RS_RET_OK) {
+ iRet = RS_RET_SUSPENDED;
+ }
+
+ RETiRet;
+}
+
+
+BEGINtryResume
+CODESTARTtryResume
+ iRet = doTryResume(pData);
+ENDtryResume
+
+BEGINdoAction
+ char *psz = NULL; /* temporary buffering */
+ register unsigned l;
+ int iMaxLine;
+CODESTARTdoAction
+ CHKiRet(doTryResume(pData));
+
+ iMaxLine = glbl.GetMaxLine();
+
+ DBGPRINTF(" omuxsock:%s\n", pData->sockName);
+
+ psz = (char*) ppString[0];
+ l = strlen((char*) psz);
+ if((int) l > iMaxLine)
+ l = iMaxLine;
+
+ CHKiRet(sendMsg(pData, psz, l));
+
+finalize_it:
+ENDdoAction
+
+
+BEGINparseSelectorAct
+CODESTARTparseSelectorAct
+CODE_STD_STRING_REQUESTparseSelectorAct(1)
+
+ /* first check if this config line is actually for us */
+ if(strncmp((char*) p, ":omuxsock:", sizeof(":omuxsock:") - 1)) {
+ ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED);
+ }
+
+ /* ok, if we reach this point, we have something for us */
+ p += sizeof(":omuxsock:") - 1; /* eat indicator sequence (-1 because of '\0'!) */
+ CHKiRet(createInstance(&pData));
+
+ /* check if a non-standard template is to be applied */
+ if(*(p-1) == ';')
+ --p;
+ CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, 0, tplName == NULL ? UCHAR_CONSTANT("RSYSLOG_TraditionalForwardFormat")
+ : tplName ));
+
+ if(sockName == NULL) {
+ errmsg.LogError(0, RS_RET_NO_SOCK_CONFIGURED, "No output socket configured for omuxsock\n");
+ ABORT_FINALIZE(RS_RET_NO_SOCK_CONFIGURED);
+ }
+
+ pData->sockName = sockName;
+ sockName = NULL; /* pData is now owner and will fee it */
+
+CODE_STD_FINALIZERparseSelectorAct
+ENDparseSelectorAct
+
+
+/* a common function to free our configuration variables - used both on exit
+ * and on $ResetConfig processing. -- rgerhards, 2008-05-16
+ */
+static inline void
+freeConfigVars(void)
+{
+ free(tplName);
+ tplName = NULL;
+ free(sockName);
+ sockName = NULL;
+}
+
+
+BEGINmodExit
+CODESTARTmodExit
+ /* release what we no longer need */
+ objRelease(errmsg, CORE_COMPONENT);
+ objRelease(glbl, CORE_COMPONENT);
+
+ freeConfigVars();
+ENDmodExit
+
+
+BEGINqueryEtryPt
+CODESTARTqueryEtryPt
+CODEqueryEtryPt_STD_OMOD_QUERIES
+ENDqueryEtryPt
+
+
+/* Reset config variables for this module to default values.
+ * rgerhards, 2008-03-28
+ */
+static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
+{
+ freeConfigVars();
+ return RS_RET_OK;
+}
+
+
+BEGINmodInit()
+CODESTARTmodInit
+ *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
+CODEmodInit_QueryRegCFSLineHdlr
+ CHKiRet(objUse(glbl, CORE_COMPONENT));
+ CHKiRet(objUse(errmsg, CORE_COMPONENT));
+
+ CHKiRet(regCfSysLineHdlr((uchar *)"omuxsockdefaulttemplate", 0, eCmdHdlrGetWord, NULL, &tplName, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"omuxsocksocket", 0, eCmdHdlrGetWord, NULL, &sockName, NULL));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
+ENDmodInit
+
+/* vim:set ai:
+ */
diff --git a/runtime/Makefile.am b/runtime/Makefile.am
index 14abe722..c1a15198 100644
--- a/runtime/Makefile.am
+++ b/runtime/Makefile.am
@@ -15,6 +15,7 @@ librsyslog_la_SOURCES = \
nsd.h \
glbl.h \
glbl.c \
+ unlimited_select.h \
conf.c \
conf.h \
parser.h \
diff --git a/runtime/atomic.h b/runtime/atomic.h
index d5aaf56b..fc3e0b2d 100644
--- a/runtime/atomic.h
+++ b/runtime/atomic.h
@@ -31,8 +31,6 @@
* A copy of the GPL can be found in the file "COPYING" in this distribution.
* A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution.
*/
-#include "config.h" /* autotools! */
-
#ifndef INCLUDED_ATOMIC_H
#define INCLUDED_ATOMIC_H
@@ -41,17 +39,28 @@
* They simply came in too late. -- rgerhards, 2008-04-02
*/
#ifdef HAVE_ATOMIC_BUILTINS
-# define ATOMIC_INC(data) ((void) __sync_fetch_and_add(&(data), 1))
+# define ATOMIC_INC(data, phlpmut) ((void) __sync_fetch_and_add(data, 1))
# define ATOMIC_INC_AND_FETCH(data) __sync_fetch_and_add(&(data), 1)
-# define ATOMIC_DEC(data) ((void) __sync_sub_and_fetch(&(data), 1))
-# define ATOMIC_DEC_AND_FETCH(data) __sync_sub_and_fetch(&(data), 1)
+# define ATOMIC_DEC(data, phlpmut) ((void) __sync_sub_and_fetch(data, 1))
+# define ATOMIC_DEC_AND_FETCH(data, phlpmut) __sync_sub_and_fetch(data, 1)
# define ATOMIC_FETCH_32BIT(data) ((unsigned) __sync_fetch_and_and(&(data), 0xffffffff))
# define ATOMIC_STORE_1_TO_32BIT(data) __sync_lock_test_and_set(&(data), 1)
-# define ATOMIC_STORE_0_TO_INT(data) __sync_fetch_and_and(&(data), 0)
-# define ATOMIC_STORE_1_TO_INT(data) __sync_fetch_and_or(&(data), 1)
+# define ATOMIC_STORE_0_TO_INT(data, phlpmut) __sync_fetch_and_and(data, 0)
+# define ATOMIC_STORE_1_TO_INT(data, phlpmut) __sync_fetch_and_or(data, 1)
# define ATOMIC_STORE_INT_TO_INT(data, val) __sync_fetch_and_or(&(data), (val))
# define ATOMIC_CAS(data, oldVal, newVal) __sync_bool_compare_and_swap(&(data), (oldVal), (newVal));
-# define ATOMIC_CAS_VAL(data, oldVal, newVal) __sync_val_compare_and_swap(&(data), (oldVal), (newVal));
+# define ATOMIC_CAS_VAL(data, oldVal, newVal, phlpmut) __sync_val_compare_and_swap(data, (oldVal), (newVal));
+
+ /* functions below are not needed if we have atomics */
+# define DEF_ATOMIC_HELPER_MUT(x)
+# define INIT_ATOMIC_HELPER_MUT(x)
+# define DESTROY_ATOMIC_HELPER_MUT(x)
+
+ /* the following operations should preferrably be done atomic, but it is
+ * not fatal if not -- that means we can live with some missed updates. So be
+ * sure to use these macros only if that really does not matter!
+ */
+# define PREFER_ATOMIC_INC(data) ((void) __sync_fetch_and_add(&(data), 1))
#else
/* note that we gained parctical proof that theoretical problems DO occur
* if we do not properly address them. See this blog post for details:
@@ -60,12 +69,63 @@
* simply go ahead and do without them - use mutexes or other things. The
* code needs to be checked against all those cases. -- rgerhards, 2009-01-30
*/
+ #include <pthread.h>
+# define ATOMIC_INC(data, phlpmut) { \
+ pthread_mutex_lock(phlpmut); \
+ ++(*(data)); \
+ pthread_mutex_unlock(phlpmut); \
+ }
+
+# define ATOMIC_STORE_0_TO_INT(data, hlpmut) { \
+ pthread_mutex_lock(&hlpmut); \
+ *(data) = 0; \
+ pthread_mutex_unlock(&hlpmut); \
+ }
+
+# define ATOMIC_STORE_1_TO_INT(data, hlpmut) { \
+ pthread_mutex_lock(&hlpmut); \
+ *(data) = 1; \
+ pthread_mutex_unlock(&hlpmut); \
+ }
+
+ static inline int
+ ATOMIC_CAS_VAL(int *data, int oldVal, int newVal, pthread_mutex_t *phlpmut) {
+ int val;
+ pthread_mutex_lock(phlpmut);
+ if(*data == oldVal) {
+ *data = newVal;
+ }
+ val = *data;
+ pthread_mutex_unlock(phlpmut);
+ return(val);
+ }
+
+# define ATOMIC_DEC(data, phlpmut) { \
+ pthread_mutex_lock(phlpmut); \
+ --(*(data)); \
+ pthread_mutex_unlock(phlpmut); \
+ }
+
+ static inline int
+ ATOMIC_DEC_AND_FETCH(int *data, pthread_mutex_t *phlpmut) {
+ int val;
+ pthread_mutex_lock(phlpmut);
+ val = --(*data);
+ pthread_mutex_unlock(phlpmut);
+ return(val);
+ }
+#if 0
# warning "atomic builtins not available, using nul operations - rsyslogd will probably be racy!"
-# define ATOMIC_INC(data) (++(data))
-# define ATOMIC_DEC(data) (--(data))
-# define ATOMIC_DEC_AND_FETCH(data) (--(data))
-# define ATOMIC_FETCH_32BIT(data) (data)
-# define ATOMIC_STORE_1_TO_32BIT(data) (data) = 1
+# define ATOMIC_INC_AND_FETCH(data) (++(data))
+# define ATOMIC_FETCH_32BIT(data) (data) // TODO: del
+# define ATOMIC_STORE_1_TO_32BIT(data) (data) = 1 // TODO: del
+#endif
+# define DEF_ATOMIC_HELPER_MUT(x) pthread_mutex_t x
+# define INIT_ATOMIC_HELPER_MUT(x) pthread_mutex_init(&(x), NULL)
+# define DESTROY_ATOMIC_HELPER_MUT(x) pthread_mutex_init(&(x), NULL)
+
+# define PREFER_ATOMIC_INC(data) ((void) ++data)
+
#endif
#endif /* #ifndef INCLUDED_ATOMIC_H */
diff --git a/runtime/cfsysline.c b/runtime/cfsysline.c
index 184c0d87..5df8e64c 100644
--- a/runtime/cfsysline.c
+++ b/runtime/cfsysline.c
@@ -217,9 +217,11 @@ static rsRetVal doGetSize(uchar **pp, rsRetVal (*pSetHdlr)(void*, uid_t), void *
case 'K': i *= 1000; ++(*pp); break;
case 'M': i *= 1000000; ++(*pp); break;
case 'G': i *= 1000000000; ++(*pp); break;
- case 'T': i *= 1000000000000; ++(*pp); break; /* tera */
- case 'P': i *= 1000000000000000; ++(*pp); break; /* peta */
- case 'E': i *= 1000000000000000000; ++(*pp); break; /* exa */
+ /* we need to use the multiplication below because otherwise
+ * the compiler gets an error during constant parsing */
+ case 'T': i *= (int64) 1000 * 1000000000; ++(*pp); break; /* tera */
+ case 'P': i *= (int64) 1000000 * 1000000000; ++(*pp); break; /* peta */
+ case 'E': i *= (int64) 1000000000 * 1000000000; ++(*pp); break; /* exa */
}
/* done */
diff --git a/runtime/debug.c b/runtime/debug.c
index 9b7c2952..0ada909b 100644
--- a/runtime/debug.c
+++ b/runtime/debug.c
@@ -154,7 +154,9 @@ static pthread_key_t keyCallStack;
*/
static void dbgMutexCancelCleanupHdlr(void *pmut)
{
- pthread_mutex_unlock((pthread_mutex_t*) pmut);
+ int ret;
+ ret = pthread_mutex_unlock((pthread_mutex_t*) pmut);
+ assert(ret == 0);
}
@@ -846,6 +848,7 @@ dbgprint(obj_t *pObj, char *pszMsg, size_t lenMsg)
size_t lenWriteBuf;
struct timespec t;
uchar *pszObjName = NULL;
+ int ret;
/* we must get the object name before we lock the mutex, because the object
* potentially calls back into us. If we locked the mutex, we would deadlock
@@ -857,7 +860,8 @@ dbgprint(obj_t *pObj, char *pszMsg, size_t lenMsg)
pszObjName = obj.GetName(pObj);
}
- pthread_mutex_lock(&mutdbgprint);
+ ret = pthread_mutex_lock(&mutdbgprint);
+ assert(ret == 0); /* make sure mutex operation does not fail */
pthread_cleanup_push(dbgMutexCancelCleanupHdlr, &mutdbgprint);
/* The bWasNL handler does not really work. It works if no thread
@@ -941,6 +945,15 @@ dbgoprint(obj_t *pObj, char *fmt, ...)
va_start(ap, fmt);
lenWriteBuf = vsnprintf(pszWriteBuf, sizeof(pszWriteBuf), fmt, ap);
va_end(ap);
+ if(lenWriteBuf >= sizeof(pszWriteBuf)) {
+ /* prevent buffer overrruns and garbagge display */
+ pszWriteBuf[sizeof(pszWriteBuf) - 5] = '.';
+ pszWriteBuf[sizeof(pszWriteBuf) - 4] = '.';
+ pszWriteBuf[sizeof(pszWriteBuf) - 3] = '.';
+ pszWriteBuf[sizeof(pszWriteBuf) - 2] = '\n';
+ pszWriteBuf[sizeof(pszWriteBuf) - 1] = '\0';
+ lenWriteBuf = sizeof(pszWriteBuf);
+ }
dbgprint(pObj, pszWriteBuf, lenWriteBuf);
}
@@ -952,7 +965,7 @@ void
dbgprintf(char *fmt, ...)
{
va_list ap;
- char pszWriteBuf[20480];
+ char pszWriteBuf[32*1024];
size_t lenWriteBuf;
if(!(Debug && debugging_on))
@@ -1060,7 +1073,7 @@ int dbgEntrFunc(dbgFuncDB_t **ppFuncDB, const char *file, const char *func, int
}
/* when we reach this point, we have a fully-initialized FuncDB! */
- ATOMIC_INC(pFuncDB->nTimesCalled);
+ PREFER_ATOMIC_INC(pFuncDB->nTimesCalled);
if(bLogFuncFlow && dbgPrintNameIsInList((const uchar*)pFuncDB->file, printNameFileRoot))
dbgprintf("%s:%d: %s: enter\n", pFuncDB->file, pFuncDB->line, pFuncDB->func);
if(pThrd->stackPtr >= (int) (sizeof(pThrd->callStack) / sizeof(dbgFuncDB_t*))) {
@@ -1280,11 +1293,11 @@ dbgGetRuntimeOptions(void)
/* this is earlier in the process than the -d option, as such it
* allows us to spit out debug messages from the very beginning.
*/
- Debug = 1;
+ Debug = DEBUG_FULL;
debugging_on = 1;
} else if(!strcasecmp((char*)optname, "debugondemand")) {
/* Enables debugging, but turns off debug output */
- Debug = 1;
+ Debug = DEBUG_ONDEMAND;
debugging_on = 1;
dbgprintf("Note: debug on demand turned on via configuraton file, "
"use USR1 signal to activate.\n");
diff --git a/runtime/debug.h b/runtime/debug.h
index dcbfb930..cfdf819c 100644
--- a/runtime/debug.h
+++ b/runtime/debug.h
@@ -29,6 +29,11 @@
#include <pthread.h>
#include "obj-types.h"
+/* some settings for various debug modes */
+#define DEBUG_OFF 0
+#define DEBUG_ONDEMAND 1
+#define DEBUG_FULL 2
+
/* external static data elements (some time to be replaced) */
extern int Debug; /* debug flag - read-only after startup */
extern int debugging_on; /* read-only, except on sig USR1 */
diff --git a/runtime/glbl.c b/runtime/glbl.c
index 7fa61963..58558ed2 100644
--- a/runtime/glbl.c
+++ b/runtime/glbl.c
@@ -72,6 +72,9 @@ static uchar *pszDfltNetstrmDrvr = NULL; /* module name of default netstream dri
static uchar *pszDfltNetstrmDrvrCAF = NULL; /* default CA file for the netstrm driver */
static uchar *pszDfltNetstrmDrvrKeyFile = NULL; /* default key file for the netstrm driver (server) */
static uchar *pszDfltNetstrmDrvrCertFile = NULL; /* default cert file for the netstrm driver (server) */
+#ifdef USE_UNLIMITED_SELECT
+static int iFdSetSize = howmany(FD_SETSIZE, __NFDBITS) * sizeof (fd_mask); /* size of select() bitmask in bytes */
+#endif
/* define a macro for the simple properties' set and get functions
@@ -104,6 +107,9 @@ SIMP_PROP(DisableDNS, bDisableDNS, int)
SIMP_PROP(LocalDomain, LocalDomain, uchar*)
SIMP_PROP(StripDomains, StripDomains, char**)
SIMP_PROP(LocalHosts, LocalHosts, char**)
+#ifdef USE_UNLIMITED_SELECT
+SIMP_PROP(FdSetSize, iFdSetSize, int)
+#endif
SIMP_PROP_SET(LocalFQDNName, LocalFQDNName, uchar*)
SIMP_PROP_SET(LocalHostName, LocalHostName, uchar*)
@@ -261,6 +267,9 @@ CODESTARTobjQueryInterface(glbl)
SIMP_PROP(DfltNetstrmDrvrCAF)
SIMP_PROP(DfltNetstrmDrvrKeyFile)
SIMP_PROP(DfltNetstrmDrvrCertFile)
+#ifdef USE_UNLIMITED_SELECT
+ SIMP_PROP(FdSetSize)
+#endif
#undef SIMP_PROP
finalize_it:
ENDobjQueryInterface(glbl)
@@ -295,6 +304,9 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a
bOptimizeUniProc = 1;
bHUPisRestart = 0;
bPreserveFQDN = 0;
+#ifdef USE_UNLIMITED_SELECT
+ iFdSetSize = howmany(FD_SETSIZE, __NFDBITS) * sizeof (fd_mask);
+#endif
return RS_RET_OK;
}
diff --git a/runtime/glbl.h b/runtime/glbl.h
index dcfb6d5f..6a332576 100644
--- a/runtime/glbl.h
+++ b/runtime/glbl.h
@@ -62,9 +62,18 @@ BEGINinterface(glbl) /* name must also be changed in ENDinterface macro! */
/* added v3, 2009-06-30 */
rsRetVal (*GenerateLocalHostNameProperty)(void);
prop_t* (*GetLocalHostNameProp)(void);
+ /* note: v4, v5 are already used by more recent versions, so we need to skip them! */
+ /* added v6, 2009-11-16 as part of varmojfekoj's "unlimited select()" patch
+ * Note that it must be always present, otherwise the interface would have different
+ * versions depending on compile settings, what is not acceptable.
+ * Use this property with care, it is only truly available if UNLIMITED_SELECT is enabled
+ * (I did not yet further investigate the details, because that code hopefully can be removed
+ * at some later stage).
+ */
+ SIMP_PROP(FdSetSize, int)
#undef SIMP_PROP
ENDinterface(glbl)
-#define glblCURR_IF_VERSION 3 /* increment whenever you change the interface structure! */
+#define glblCURR_IF_VERSION 6 /* increment whenever you change the interface structure! */
/* version 2 had PreserveFQDN added - rgerhards, 2008-12-08 */
/* the remaining prototypes */
diff --git a/runtime/msg.c b/runtime/msg.c
index 91057f97..57291def 100644
--- a/runtime/msg.c
+++ b/runtime/msg.c
@@ -748,7 +748,7 @@ BEGINobjDestruct(msg) /* be sure to specify the object type also in END and CODE
CODESTARTobjDestruct(msg)
/* DEV Debugging only ! dbgprintf("msgDestruct\t0x%lx, Ref now: %d\n", (unsigned long)pThis, pThis->iRefCount - 1); */
# ifdef HAVE_ATOMIC_BUILTINS
- currRefCount = ATOMIC_DEC_AND_FETCH(pThis->iRefCount);
+ currRefCount = ATOMIC_DEC_AND_FETCH(&pThis->iRefCount, NULL);
# else
MsgLock(pThis);
currRefCount = --pThis->iRefCount;
@@ -800,9 +800,18 @@ CODESTARTobjDestruct(msg)
* that we trim too often when the counter wraps.
*/
static unsigned iTrimCtr = 1;
+# ifdef HAVE_ATOMICS
if(ATOMIC_INC_AND_FETCH(iTrimCtr) % 100000 == 0) {
malloc_trim(128*1024);
}
+# else
+static pthread_mutex_t mutTrimCtr = PTHREAD_MUTEX_INITIALIZER;
+ d_pthread_mutex_lock(&mutTrimCtr);
+ if(iTrimCtr++ % 100000 == 0) {
+ malloc_trim(128*1024);
+ }
+ d_pthread_mutex_unlock(&mutTrimCtr);
+# endif
}
# endif
} else {
@@ -1002,7 +1011,7 @@ msg_t *MsgAddRef(msg_t *pM)
{
assert(pM != NULL);
# ifdef HAVE_ATOMIC_BUILTINS
- ATOMIC_INC(pM->iRefCount);
+ ATOMIC_INC(&pM->iRefCount, NULL);
# else
MsgLock(pM);
pM->iRefCount++;
@@ -3048,7 +3057,7 @@ static rsRetVal msgConstructFinalizer(msg_t *pThis)
* rgerhards, 2008-01-14
*/
static rsRetVal
-MsgGetSeverity(obj_t *pThis, int *piSeverity)
+MsgGetSeverity(obj_t_ptr pThis, int *piSeverity)
{
ISOBJ_TYPE_assert(pThis, msg);
assert(piSeverity != NULL);
diff --git a/runtime/msg.h b/runtime/msg.h
index 3a02365b..cda206fc 100644
--- a/runtime/msg.h
+++ b/runtime/msg.h
@@ -32,6 +32,7 @@
#include "obj.h"
#include "syslogd-types.h"
#include "template.h"
+#include "atomic.h"
/* rgerhards 2004-11-08: The following structure represents a
@@ -130,6 +131,7 @@ struct msg {
#define MARK 0x008 /* this message is a mark */
#define NEEDS_PARSING 0x010 /* raw message, must be parsed before processing can be done */
#define PARSE_HOSTNAME 0x020 /* parse the hostname during message parsing */
+#define NO_PRI_IN_RAW 0x100 /* rawmsg does not include a PRI (Solaris!), but PRI is already set correctly in the msg object */
/* function prototypes
diff --git a/runtime/net.c b/runtime/net.c
index fe6eef5b..4eb5a3bb 100644
--- a/runtime/net.c
+++ b/runtime/net.c
@@ -502,8 +502,8 @@ static inline void MaskIP4 (struct in_addr *addr, uint8_t bits) {
addr->s_addr &= htonl(0xffffffff << (32 - bits));
}
-#define SIN(sa) ((struct sockaddr_in *)(sa))
-#define SIN6(sa) ((struct sockaddr_in6 *)(sa))
+#define SIN(sa) ((struct sockaddr_in *)(void*)(sa))
+#define SIN6(sa) ((struct sockaddr_in6 *)(void*)(sa))
/* This is a cancel-safe getnameinfo() version, because we learned
@@ -1165,12 +1165,12 @@ void debugListenInfo(int fd, char *type)
switch(sa.sa_family) {
case PF_INET:
szFamily = "IPv4";
- ipv4 = (struct sockaddr_in*) &sa;
+ ipv4 = (struct sockaddr_in*)(void*) &sa;
port = ntohs(ipv4->sin_port);
break;
case PF_INET6:
szFamily = "IPv6";
- ipv6 = (struct sockaddr_in6*) &sa;
+ ipv6 = (struct sockaddr_in6*)(void*) &sa;
port = ntohs(ipv6->sin6_port);
break;
default:
diff --git a/runtime/nsdsel_ptcp.c b/runtime/nsdsel_ptcp.c
index 41b85e0c..e2cfca7c 100644
--- a/runtime/nsdsel_ptcp.c
+++ b/runtime/nsdsel_ptcp.c
@@ -36,6 +36,7 @@
#include "errmsg.h"
#include "nsd_ptcp.h"
#include "nsdsel_ptcp.h"
+#include "unlimited_select.h"
/* static data */
DEFobjStaticHelpers
@@ -47,14 +48,23 @@ DEFobjCurrIf(glbl)
*/
BEGINobjConstruct(nsdsel_ptcp) /* be sure to specify the object type also in END macro! */
pThis->maxfds = 0;
+#ifdef USE_UNLIMITED_SELECT
+ pThis->pReadfds = calloc(1, glbl.GetFdSetSize());
+ pThis->pWritefds = calloc(1, glbl.GetFdSetSize());
+#else
FD_ZERO(&pThis->readfds);
FD_ZERO(&pThis->writefds);
+#endif
ENDobjConstruct(nsdsel_ptcp)
/* destructor for the nsdsel_ptcp object */
BEGINobjDestruct(nsdsel_ptcp) /* be sure to specify the object type also in END and CODESTART macros! */
CODESTARTobjDestruct(nsdsel_ptcp)
+#ifdef USE_UNLIMITED_SELECT
+ freeFdSet(pThis->pReadfds);
+ freeFdSet(pThis->pWritefds);
+#endif
ENDobjDestruct(nsdsel_ptcp)
@@ -65,20 +75,27 @@ Add(nsdsel_t *pNsdsel, nsd_t *pNsd, nsdsel_waitOp_t waitOp)
DEFiRet;
nsdsel_ptcp_t *pThis = (nsdsel_ptcp_t*) pNsdsel;
nsd_ptcp_t *pSock = (nsd_ptcp_t*) pNsd;
+#ifdef USE_UNLIMITED_SELECT
+ fd_set *pReadfds = pThis->pReadfds;
+ fd_set *pWritefds = pThis->pWritefds;
+#else
+ fd_set *pReadfds = &pThis->readfds;
+ fd_set *pWritefds = &pThis->writefds;
+#endif
ISOBJ_TYPE_assert(pSock, nsd_ptcp);
ISOBJ_TYPE_assert(pThis, nsdsel_ptcp);
switch(waitOp) {
case NSDSEL_RD:
- FD_SET(pSock->sock, &pThis->readfds);
+ FD_SET(pSock->sock, pReadfds);
break;
case NSDSEL_WR:
- FD_SET(pSock->sock, &pThis->writefds);
+ FD_SET(pSock->sock, pWritefds);
break;
case NSDSEL_RDWR:
- FD_SET(pSock->sock, &pThis->readfds);
- FD_SET(pSock->sock, &pThis->writefds);
+ FD_SET(pSock->sock, pReadfds);
+ FD_SET(pSock->sock, pWritefds);
break;
}
@@ -98,6 +115,13 @@ Select(nsdsel_t *pNsdsel, int *piNumReady)
DEFiRet;
int i;
nsdsel_ptcp_t *pThis = (nsdsel_ptcp_t*) pNsdsel;
+#ifdef USE_UNLIMITED_SELECT
+ fd_set *pReadfds = pThis->pReadfds;
+ fd_set *pWritefds = pThis->pWritefds;
+#else
+ fd_set *pReadfds = &pThis->readfds;
+ fd_set *pWritefds = &pThis->writefds;
+#endif
ISOBJ_TYPE_assert(pThis, nsdsel_ptcp);
assert(piNumReady != NULL);
@@ -106,13 +130,13 @@ Select(nsdsel_t *pNsdsel, int *piNumReady)
// TODO: name in dbgprintf!
dbgprintf("--------<NSDSEL_PTCP> calling select, active fds (max %d): ", pThis->maxfds);
for(i = 0; i <= pThis->maxfds; ++i)
- if(FD_ISSET(i, &pThis->readfds) || FD_ISSET(i, &pThis->writefds))
+ if(FD_ISSET(i, pReadfds) || FD_ISSET(i, pWritefds))
dbgprintf("%d ", i);
dbgprintf("\n");
}
/* now do the select */
- *piNumReady = select(pThis->maxfds+1, &pThis->readfds, &pThis->writefds, NULL, NULL);
+ *piNumReady = select(pThis->maxfds+1, pReadfds, pWritefds, NULL, NULL);
RETiRet;
}
@@ -125,6 +149,13 @@ IsReady(nsdsel_t *pNsdsel, nsd_t *pNsd, nsdsel_waitOp_t waitOp, int *pbIsReady)
DEFiRet;
nsdsel_ptcp_t *pThis = (nsdsel_ptcp_t*) pNsdsel;
nsd_ptcp_t *pSock = (nsd_ptcp_t*) pNsd;
+#ifdef USE_UNLIMITED_SELECT
+ fd_set *pReadfds = pThis->pReadfds;
+ fd_set *pWritefds = pThis->pWritefds;
+#else
+ fd_set *pReadfds = &pThis->readfds;
+ fd_set *pWritefds = &pThis->writefds;
+#endif
ISOBJ_TYPE_assert(pThis, nsdsel_ptcp);
ISOBJ_TYPE_assert(pSock, nsd_ptcp);
@@ -132,14 +163,14 @@ IsReady(nsdsel_t *pNsdsel, nsd_t *pNsd, nsdsel_waitOp_t waitOp, int *pbIsReady)
switch(waitOp) {
case NSDSEL_RD:
- *pbIsReady = FD_ISSET(pSock->sock, &pThis->readfds);
+ *pbIsReady = FD_ISSET(pSock->sock, pReadfds);
break;
case NSDSEL_WR:
- *pbIsReady = FD_ISSET(pSock->sock, &pThis->writefds);
+ *pbIsReady = FD_ISSET(pSock->sock, pWritefds);
break;
case NSDSEL_RDWR:
- *pbIsReady = FD_ISSET(pSock->sock, &pThis->readfds)
- | FD_ISSET(pSock->sock, &pThis->writefds);
+ *pbIsReady = FD_ISSET(pSock->sock, pReadfds)
+ | FD_ISSET(pSock->sock, pWritefds);
break;
}
diff --git a/runtime/nsdsel_ptcp.h b/runtime/nsdsel_ptcp.h
index 6c0c7fa7..f9ec8210 100644
--- a/runtime/nsdsel_ptcp.h
+++ b/runtime/nsdsel_ptcp.h
@@ -31,8 +31,13 @@ typedef nsdsel_if_t nsdsel_ptcp_if_t; /* we just *implement* this interface */
struct nsdsel_ptcp_s {
BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */
int maxfds;
+#ifdef USE_UNLIMITED_SELECT
+ fd_set *pReadfds;
+ fd_set *pWritefds;
+#else
fd_set readfds;
fd_set writefds;
+#endif
};
/* interface is defined in nsd.h, we just implement it! */
diff --git a/runtime/parser.c b/runtime/parser.c
index 36e88ebd..810bf42b 100644
--- a/runtime/parser.c
+++ b/runtime/parser.c
@@ -287,19 +287,24 @@ rsRetVal parseMsg(msg_t *pMsg)
msg = pMsg->pszRawMsg;
pri = DEFUPRI;
iPriText = 0;
- if(*msg == '<') {
- /* while we process the PRI, we also fill the PRI textual representation
- * inside the msg object. This may not be ideal from an OOP point of view,
- * but it offers us performance...
- */
- pri = 0;
- while(--lenMsg > 0 && isdigit((int) *++msg)) {
- pri = 10 * pri + (*msg - '0');
+ if(pMsg->msgFlags & NO_PRI_IN_RAW) {
+ /* In this case, simply do so as if the pri would be right at top */
+ MsgSetAfterPRIOffs(pMsg, 0);
+ } else {
+ if(*msg == '<') {
+ /* while we process the PRI, we also fill the PRI textual representation
+ * inside the msg object. This may not be ideal from an OOP point of view,
+ * but it offers us performance...
+ */
+ pri = 0;
+ while(--lenMsg > 0 && isdigit((int) *++msg)) {
+ pri = 10 * pri + (*msg - '0');
+ }
+ if(*msg == '>')
+ ++msg;
+ if(pri & ~(LOG_FACMASK|LOG_PRIMASK))
+ pri = DEFUPRI;
}
- if(*msg == '>')
- ++msg;
- if(pri & ~(LOG_FACMASK|LOG_PRIMASK))
- pri = DEFUPRI;
}
pMsg->iFacility = LOG_FAC(pri);
pMsg->iSeverity = LOG_PRI(pri);
diff --git a/runtime/prop.c b/runtime/prop.c
index d188b2ed..7f2a56ff 100644
--- a/runtime/prop.c
+++ b/runtime/prop.c
@@ -53,6 +53,7 @@ DEFobjStaticHelpers
*/
BEGINobjConstruct(prop) /* be sure to specify the object type also in END macro! */
pThis->iRefCount = 1;
+ INIT_ATOMIC_HELPER_MUT(pThis->mutRefCount);
ENDobjConstruct(prop)
@@ -60,11 +61,12 @@ ENDobjConstruct(prop)
BEGINobjDestruct(prop) /* be sure to specify the object type also in END and CODESTART macros! */
int currRefCount;
CODESTARTobjDestruct(prop)
- currRefCount = ATOMIC_DEC_AND_FETCH(pThis->iRefCount);
+ currRefCount = ATOMIC_DEC_AND_FETCH(&pThis->iRefCount, &pThis->mutRefCount);
if(currRefCount == 0) {
/* (only) in this case we need to actually destruct the object */
if(pThis->len >= CONF_PROP_BUFSIZE)
free(pThis->szVal.psz);
+ DESTROY_ATOMIC_HELPER_MUT(pThis->mutRefCount);
} else {
pThis = NULL; /* tell framework NOT to destructing the object! */
}
@@ -132,7 +134,7 @@ propConstructFinalize(prop_t __attribute__((unused)) *pThis)
*/
static rsRetVal AddRef(prop_t *pThis)
{
- ATOMIC_INC(pThis->iRefCount);
+ ATOMIC_INC(&pThis->iRefCount, &pThis->mutRefCount);
return RS_RET_OK;
}
diff --git a/runtime/prop.h b/runtime/prop.h
index e3519664..07b2ab7e 100644
--- a/runtime/prop.h
+++ b/runtime/prop.h
@@ -24,6 +24,7 @@
*/
#ifndef INCLUDED_PROP_H
#define INCLUDED_PROP_H
+#include "atomic.h"
/* the prop object */
struct prop_s {
@@ -34,6 +35,7 @@ struct prop_s {
uchar sz[CONF_PROP_BUFSIZE];
} szVal;
int len; /* we use int intentionally, otherwise we may get some troubles... */
+ DEF_ATOMIC_HELPER_MUT(mutRefCount);
};
/* interfaces */
diff --git a/runtime/queue.c b/runtime/queue.c
index 9d7a9058..bedefb77 100644
--- a/runtime/queue.c
+++ b/runtime/queue.c
@@ -110,7 +110,7 @@ static inline void queueDrain(qqueue_t *pThis)
ASSERT(pThis != NULL);
/* iQueueSize is not decremented by qDel(), so we need to do it ourselves */
- while(ATOMIC_DEC_AND_FETCH(pThis->iQueueSize) > 0) {
+ while(ATOMIC_DEC_AND_FETCH(&pThis->iQueueSize, &pThis->mutQueueSize) > 0) {
pThis->qDel(pThis, &pUsr);
if(pUsr != NULL) {
objDestruct(pUsr);
@@ -1028,7 +1028,7 @@ qqueueAdd(qqueue_t *pThis, void *pUsr)
CHKiRet(pThis->qAdd(pThis, pUsr));
if(pThis->qType != QUEUETYPE_DIRECT) {
- ATOMIC_INC(pThis->iQueueSize);
+ ATOMIC_INC(&pThis->iQueueSize, &pThis->mutQueueSize);
dbgoprint((obj_t*) pThis, "entry added, size now %d entries\n", pThis->iQueueSize);
}
@@ -1057,7 +1057,7 @@ qqueueDel(qqueue_t *pThis, void *pUsr)
iRet = qqueueGetUngottenObj(pThis, (obj_t**) pUsr);
} else {
iRet = pThis->qDel(pThis, pUsr);
- ATOMIC_DEC(pThis->iQueueSize);
+ ATOMIC_DEC(&pThis->iQueueSize, &pThis->mutQueueSize);
}
dbgoprint((obj_t*) pThis, "entry deleted, state %d, size now %d entries\n",
@@ -1345,6 +1345,8 @@ rsRetVal qqueueConstruct(qqueue_t **ppThis, queueType_t qType, int iWorkerThread
break;
}
+ INIT_ATOMIC_HELPER_MUT(pThis->mutQueueSize);
+
finalize_it:
OBJCONSTRUCT_CHECK_SUCCESS_AND_CLEANUP
RETiRet;
@@ -2065,6 +2067,8 @@ CODESTARTobjDestruct(qqueue)
pthread_cond_destroy(&pThis->belowFullDlyWtrMrk);
pthread_cond_destroy(&pThis->belowLightDlyWtrMrk);
+ DESTROY_ATOMIC_HELPER_MUT(pThis->mutQueueSize);
+
/* type-specific destructor */
iRet = pThis->qDestruct(pThis);
diff --git a/runtime/queue.h b/runtime/queue.h
index 1d82d8d9..aafdaa45 100644
--- a/runtime/queue.h
+++ b/runtime/queue.h
@@ -160,6 +160,7 @@ typedef struct queue_s {
strm_t *pRead; /* current file to be read */
} disk;
} tVars;
+ DEF_ATOMIC_HELPER_MUT(mutQueueSize);
} qqueue_t;
/* some symbolic constants for easier reference */
diff --git a/runtime/rsyslog.c b/runtime/rsyslog.c
index 443d0f41..c209ae30 100644
--- a/runtime/rsyslog.c
+++ b/runtime/rsyslog.c
@@ -80,6 +80,7 @@
#include "prop.h"
#include "rule.h"
#include "ruleset.h"
+#include "atomic.h"
/* forward definitions */
static rsRetVal dfltErrLogger(int, uchar *errMsg);
@@ -215,6 +216,7 @@ rsrtExit(void)
glblClassExit();
rulesetClassExit();
ruleClassExit();
+
objClassExit(); /* *THIS* *MUST/SHOULD?* always be the first class initilizer being called (except debug)! */
}
diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h
index 907b9c1a..9dd45b38 100644
--- a/runtime/rsyslog.h
+++ b/runtime/rsyslog.h
@@ -61,6 +61,7 @@
/* define some base data types */
+
typedef unsigned char uchar;/* get rid of the unhandy "unsigned char" */
typedef struct thrdInfo thrdInfo_t;
typedef struct obj_s obj_t;
@@ -78,8 +79,6 @@ typedef struct nsd_gsspi_s nsd_gsspi_t;
typedef struct nsd_nss_s nsd_nss_t;
typedef struct nsdsel_ptcp_s nsdsel_ptcp_t;
typedef struct nsdsel_gtls_s nsdsel_gtls_t;
-typedef obj_t nsd_t;
-typedef obj_t nsdsel_t;
typedef struct msg msg_t;
typedef struct prop_s prop_t;
typedef struct interface_s interface_t;
@@ -98,6 +97,21 @@ typedef rsRetVal (*prsf_t)(struct vmstk_s*, int); /* pointer to a RainerScript f
typedef struct tcpLstnPortList_s tcpLstnPortList_t; // TODO: rename?
typedef struct strmLstnPortList_s strmLstnPortList_t; // TODO: rename?
+/* under Solaris (actually only SPARC), we need to redefine some types
+ * to be void, so that we get void* pointers. Otherwise, we will see
+ * alignment errors.
+ */
+#ifdef OS_SOLARIS
+ typedef void * obj_t_ptr;
+ typedef void nsd_t;
+ typedef void nsdsel_t;
+#else
+ typedef obj_t *obj_t_ptr;
+ typedef obj_t nsd_t;
+ typedef obj_t nsdsel_t;
+#endif
+
+
/* some universal 64 bit define... */
typedef long long int64;
typedef long long unsigned uint64;
@@ -360,6 +374,10 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth
RS_RET_VAR_NOT_FOUND = -2142, /**< variable not found */
RS_RET_EMPTY_MSG = -2143, /**< provided (raw) MSG is empty */
RS_RET_PEER_CLOSED_CONN = -2144, /**< remote peer closed connection (information, no error) */
+ RS_RET_ERR_OPEN_KLOG = -2145, /**< error opening the kernel log socket (primarily solaris) */
+ RS_RET_ERR_AQ_CONLOG = -2146, /**< error aquiring console log (on solaris) */
+ RS_RET_ERR_DOOR = -2147, /**< some problems with handling the Solaris door functionality */
+ RS_RET_NO_SOCK_CONFIGURED = -2166, /**< no socket (name) was configured where one is required */
RS_RET_NO_LSTN_DEFINED = -2172, /**< no listener defined (e.g. inside an input module) */
RS_RET_EPOLL_CR_FAILED = -2173, /**< epoll_create() failed */
RS_RET_EPOLL_CTL_FAILED = -2174, /**< epoll_ctl() failed */
diff --git a/runtime/stream.c b/runtime/stream.c
index e8805a40..e6680adc 100644
--- a/runtime/stream.c
+++ b/runtime/stream.c
@@ -215,7 +215,8 @@ doPhysOpen(strm_t *pThis)
}
pThis->fd = open((char*)pThis->pszCurrFName, iFlags, pThis->tOpenMode);
- DBGPRINTF("file '%s' opened as #%d with mode %d\n", pThis->pszCurrFName, pThis->fd, pThis->tOpenMode);
+ DBGPRINTF("file '%s' opened as #%d with mode %d\n", pThis->pszCurrFName,
+ pThis->fd, (int) pThis->tOpenMode);
if(pThis->fd == -1) {
char errStr[1024];
int err = errno;
diff --git a/runtime/unlimited_select.h b/runtime/unlimited_select.h
new file mode 100644
index 00000000..32dadc03
--- /dev/null
+++ b/runtime/unlimited_select.h
@@ -0,0 +1,45 @@
+/* unlimited_select.h
+ * Tweak the macros for accessing fd_set so that the select() syscall
+ * won't be limited to a particular number of file descriptors.
+ *
+ * Copyright 2009 Rainer Gerhards and Adiscon GmbH.
+ *
+ * This file is part of rsyslog.
+ *
+ * Rsyslog is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Rsyslog is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Rsyslog. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+ */
+
+#ifndef UNLIMITED_SELECT_H_INCLUDED
+
+#include <string.h>
+#include <stdlib.h>
+#include <sys/select.h>
+#include "glbl.h"
+
+#ifdef USE_UNLIMITED_SELECT
+# undef FD_ZERO
+# define FD_ZERO(set) memset((set), 0, glbl.GetFdSetSize());
+#endif
+
+#ifdef USE_UNLIMITED_SELECT
+void freeFdSet(fd_set *p) {
+ free(p);
+}
+#else
+# define freeFdSet(x)
+#endif
+
+#endif /* #ifndef UNLIMITED_SELECT_H_INCLUDED */
diff --git a/runtime/vm.c b/runtime/vm.c
index aaf3c879..0ed174d1 100644
--- a/runtime/vm.c
+++ b/runtime/vm.c
@@ -34,6 +34,7 @@
#include "vm.h"
#include "sysvar.h"
#include "stringbuf.h"
+#include "unicode-helper.h"
/* static data */
DEFobjStaticHelpers
@@ -41,6 +42,8 @@ DEFobjCurrIf(vmstk)
DEFobjCurrIf(var)
DEFobjCurrIf(sysvar)
+static pthread_mutex_t mutGetenv; /* we need to make this global because otherwise we can not guarantee proper init! */
+
/* ------------------------------ function registry code and structures ------------------------------ */
/* we maintain a registry of known functions */
@@ -542,6 +545,42 @@ finalize_it:
}
+/* The getenv function. Note that we guard the OS call by a mutex, as that
+ * function is not guaranteed to be thread-safe. This implementation here is far from
+ * being optimal, at least we should cache the result. This is left TODO for
+ * a later revision.
+ * rgerhards, 2009-11-03
+ */
+static rsRetVal
+rsf_getenv(vmstk_t *pStk, int numOperands)
+{
+ DEFiRet;
+ var_t *operand1;
+ char *envResult;
+ cstr_t *pCstr;
+
+ if(numOperands != 1)
+ ABORT_FINALIZE(RS_RET_INVLD_NBR_ARGUMENTS);
+
+ /* pop args and do operaton (trivial case here...) */
+ vmstk.PopString(pStk, &operand1);
+ d_pthread_mutex_lock(&mutGetenv);
+ envResult = getenv((char*) rsCStrGetSzStr(operand1->val.pStr));
+ DBGPRINTF("rsf_getenv(): envvar '%s', return '%s'\n", rsCStrGetSzStr(operand1->val.pStr),
+ envResult == NULL ? "(NULL)" : envResult);
+ iRet = rsCStrConstructFromszStr(&pCstr, (envResult == NULL) ? UCHAR_CONSTANT("") : (uchar*)envResult);
+ d_pthread_mutex_unlock(&mutGetenv);
+ if(iRet != RS_RET_OK)
+ FINALIZE; /* need to do this after mutex is unlocked! */
+
+ /* Store result and cleanup */
+ var.SetString(operand1, pCstr);
+ vmstk.Push(pStk, operand1);
+finalize_it:
+ RETiRet;
+}
+
+
/* The "tolower" function, which converts its sole argument to lower case.
* Quite honestly, currently this is primarily a test driver for me...
* rgerhards, 2009-04-06
@@ -759,6 +798,8 @@ BEGINObjClassExit(vm, OBJ_IS_CORE_MODULE) /* class, version */
objRelease(sysvar, CORE_COMPONENT);
objRelease(var, CORE_COMPONENT);
objRelease(vmstk, CORE_COMPONENT);
+
+ pthread_mutex_destroy(&mutGetenv);
ENDObjClassExit(vm)
@@ -779,6 +820,9 @@ BEGINObjClassInit(vm, 1, OBJ_IS_CORE_MODULE) /* class, version */
/* register built-in functions // TODO: move to its own module */
CHKiRet(rsfrAddFunction((uchar*)"strlen", rsf_strlen));
CHKiRet(rsfrAddFunction((uchar*)"tolower", rsf_tolower));
+ CHKiRet(rsfrAddFunction((uchar*)"getenv", rsf_getenv));
+
+ pthread_mutex_init(&mutGetenv, NULL);
ENDObjClassInit(vm)
diff --git a/runtime/wti.c b/runtime/wti.c
index abdf4add..90bb14ed 100644
--- a/runtime/wti.c
+++ b/runtime/wti.c
@@ -146,7 +146,7 @@ wtiSetState(wti_t *pThis, qWrkCmd_t tCmd, int bActiveOnly, int bLockMutex)
break;
}
/* apply the new state */
- unsigned val = ATOMIC_CAS_VAL(pThis->tCurrCmd, tCurrCmd, tCmd);
+ unsigned val = ATOMIC_CAS_VAL((int*)&pThis->tCurrCmd, tCurrCmd, tCmd, &pThis->mutCurrCmd);
if(val != tCurrCmd) {
DBGPRINTF("wtiSetState PROBLEM, tCurrCmd %d overwritten with %d, wanted to set %d\n", tCurrCmd, val, tCmd);
}
@@ -178,7 +178,7 @@ wtiCancelThrd(wti_t *pThis)
dbgoprint((obj_t*) pThis, "canceling worker thread, curr stat %d\n", pThis->tCurrCmd);
pthread_cancel(pThis->thrdID);
wtiSetState(pThis, eWRKTHRD_TERMINATING, 0, MUTEX_ALREADY_LOCKED);
- ATOMIC_STORE_1_TO_INT(pThis->pWtp->bThrdStateChanged); /* indicate change, so harverster will be called */
+ wtpSetThrdStateChanged(pThis->pWtp, 1); /* indicate change, so harverster will be called */
}
d_pthread_mutex_unlock(&pThis->mut);
@@ -209,6 +209,7 @@ CODESTARTobjDestruct(wti)
/* actual destruction */
pthread_cond_destroy(&pThis->condExitDone);
pthread_mutex_destroy(&pThis->mut);
+ DESTROY_ATOMIC_HELPER_MUT(pThis->mutCurrCmd);
free(pThis->pszDbgHdr);
ENDobjDestruct(wti)
@@ -219,6 +220,7 @@ ENDobjDestruct(wti)
BEGINobjConstruct(wti) /* be sure to specify the object type also in END macro! */
pthread_cond_init(&pThis->condExitDone, NULL);
pthread_mutex_init(&pThis->mut, NULL);
+ INIT_ATOMIC_HELPER_MUT(pThis->mutCurrCmd);
ENDobjConstruct(wti)
@@ -326,8 +328,7 @@ wtiWorkerCancelCleanup(void *arg)
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &iCancelStateSave);
d_pthread_mutex_lock(&pWtp->mut);
wtiSetState(pThis, eWRKTHRD_TERMINATING, 0, MUTEX_ALREADY_LOCKED);
- /* TODO: sync access? I currently think it is NOT needed -- rgerhards, 2008-01-28 */
- ATOMIC_STORE_1_TO_INT(pWtp->bThrdStateChanged); /* indicate change, so harverster will be called */
+ wtpSetThrdStateChanged(pWtp, 1); /* indicate change, so harverster will be called */
d_pthread_mutex_unlock(&pWtp->mut);
pthread_setcancelstate(iCancelStateSave, NULL);
@@ -414,7 +415,7 @@ wtiWorker(wti_t *pThis)
pWtp->pfOnWorkerShutdown(pWtp->pUsr);
wtiSetState(pThis, eWRKTHRD_TERMINATING, 0, MUTEX_ALREADY_LOCKED);
- ATOMIC_STORE_1_TO_INT(pWtp->bThrdStateChanged); /* indicate change, so harverster will be called */
+ wtpSetThrdStateChanged(pWtp, 1); /* indicate change, so harverster will be called */
d_pthread_mutex_unlock(&pThis->mut);
pthread_setcancelstate(iCancelStateSave, NULL);
diff --git a/runtime/wti.h b/runtime/wti.h
index 72653b15..d81672f3 100644
--- a/runtime/wti.h
+++ b/runtime/wti.h
@@ -39,6 +39,7 @@ typedef struct wti_s {
pthread_mutex_t mut;
bool bShutdownRqtd; /* shutdown for this thread requested? 0 - no , 1 - yes */
uchar *pszDbgHdr; /* header string for debug messages */
+ DEF_ATOMIC_HELPER_MUT(mutCurrCmd);
} wti_t;
/* some symbolic constants for easier reference */
diff --git a/runtime/wtp.c b/runtime/wtp.c
index 0c66dd11..fff37c2f 100644
--- a/runtime/wtp.c
+++ b/runtime/wtp.c
@@ -97,6 +97,7 @@ BEGINobjConstruct(wtp) /* be sure to specify the object type also in END macro!
pThis->pfOnWorkerCancel = NotImplementedDummy;
pThis->pfOnWorkerStartup = NotImplementedDummy;
pThis->pfOnWorkerShutdown = NotImplementedDummy;
+ INIT_ATOMIC_HELPER_MUT(pThis->mutThrdStateChanged);
ENDobjConstruct(wtp)
@@ -153,6 +154,7 @@ CODESTARTobjDestruct(wtp)
pthread_cond_destroy(&pThis->condThrdTrm);
pthread_mutex_destroy(&pThis->mut);
pthread_mutex_destroy(&pThis->mutThrdShutdwn);
+ DESTROY_ATOMIC_HELPER_MUT(pThis->mutThrdStateChanged);
free(pThis->pszDbgHdr);
ENDobjDestruct(wtp)
@@ -186,6 +188,20 @@ wtpWakeupAllWrkr(wtp_t *pThis)
}
+/* set the bThrdStateChanged in an atomic way. Note that
+ * val may only be 0 or 1.
+ */
+void
+wtpSetThrdStateChanged(wtp_t *pThis, int val)
+{
+ if(val == 0) {
+ ATOMIC_STORE_0_TO_INT(&pThis->bThrdStateChanged, pThis->mutThrdStateChanged);
+ } else {
+ ATOMIC_STORE_1_TO_INT(&pThis->bThrdStateChanged, pThis->mutThrdStateChanged);
+ }
+}
+
+
/* check if we had any worker thread changes and, if so, act
* on them. At a minimum, terminated threads are harvested (joined).
* This function MUST NEVER block on the queue mutex!
@@ -216,7 +232,7 @@ wtpProcessThrdChanges(wtp_t *pThis)
*/
do {
/* reset the change marker */
- ATOMIC_STORE_0_TO_INT(pThis->bThrdStateChanged);
+ wtpSetThrdStateChanged(pThis, 0);
/* go through all threads */
for(i = 0 ; i < pThis->iNumWorkerThreads ; ++i) {
wtiProcessThrdChanges(pThis->pWrkr[i], LOCK_MUTEX);
@@ -421,13 +437,15 @@ wtpWrkrExecCancelCleanup(void *arg)
static void *
wtpWorker(void *arg) /* the arg is actually a wti object, even though we are in wtp! */
{
- uchar *pszDbgHdr;
- uchar thrdName[32] = "rs:";
DEFiRet;
DEFVARS_mutexProtection;
wti_t *pWti = (wti_t*) arg;
wtp_t *pThis;
sigset_t sigSet;
+# if HAVE_PRCTL && defined PR_SET_NAME
+ uchar *pszDbgHdr;
+ uchar thrdName[32] = "rs:";
+# endif
ISOBJ_TYPE_assert(pWti, wti);
pThis = pWti->pWtp;
diff --git a/runtime/wtp.h b/runtime/wtp.h
index 1ce171cc..640c3320 100644
--- a/runtime/wtp.h
+++ b/runtime/wtp.h
@@ -26,6 +26,7 @@
#include <pthread.h>
#include "obj.h"
+#include "atomic.h"
/* commands and states for worker threads. */
typedef enum {
@@ -79,6 +80,7 @@ typedef struct wtp_s {
rsRetVal (*pfOnWorkerShutdown)(void *pUsr);
/* end user objects */
uchar *pszDbgHdr; /* header string for debug messages */
+ DEF_ATOMIC_HELPER_MUT(mutThrdStateChanged);
} wtp_t;
/* some symbolic constants for easier reference */
@@ -100,6 +102,7 @@ rsRetVal wtpSetDbgHdr(wtp_t *pThis, uchar *pszMsg, size_t lenMsg);
rsRetVal wtpSignalWrkrTermination(wtp_t *pWtp);
rsRetVal wtpShutdownAll(wtp_t *pThis, wtpState_t tShutdownCmd, struct timespec *ptTimeout);
int wtpGetCurNumWrkr(wtp_t *pThis, int bLockMutex);
+void wtpSetThrdStateChanged(wtp_t *pThis, int val);
PROTOTYPEObjClassInit(wtp);
PROTOTYPEpropSetMethFP(wtp, pfChkStopWrkr, rsRetVal(*pVal)(void*, int));
PROTOTYPEpropSetMethFP(wtp, pfRateLimiter, rsRetVal(*pVal)(void*));
diff --git a/solaris/README b/solaris/README
new file mode 100644
index 00000000..3f88431d
--- /dev/null
+++ b/solaris/README
@@ -0,0 +1,38 @@
+Notes for Solaris
+
+Rsyslog will be fully supported on Solaris in the future. To build it, the GNU build
+tools (and most of the GNU environment) is needed. This software can be
+found at the excellent http://www.blastwave.org site.
+
+PREQUISITES
+It is strongly recommended to use GCC4 with support for
+atomic instructions (if available for the platform). While rsyslog can
+be built without atomic instructin support (and will work well then),
+it then falls back to POSIX semaphores, which require much more CPU
+time than atomic instructions. Note that even on intel platforms the
+(current, as of 2010-03-25) blastwave gcc4 version targets too-old
+processors by default. To change that, use "-imarch=I686" in your
+CFLAGS.
+
+CONFIGURE OPTIONS
+A number of GNU tools are renamed g* so that they not conflict with
+the native Solaris tools. As we need the GNU replacements, this
+must be specified on the ./configure line.
+Also, we must tell the linker where to find the glibc library when
+building the plugins. This is done via the LDFLAGS variable as
+shown below (based on the good information availabe at
+http://prefetch.net/articles/linkers.badldlibrary.html
+
+The working sample configure sequence I use is:
+
+export LDFLAGS="-R/opt/csw/gcc4/lib"
+./configure AR=gar ...other options...
+
+As a "quick and dirty" fix, one may set the following library
+path before executing rsyslog (may be useful to avoid recompile):
+
+export LD_LIBRARY_PATH=/opt/csw/gcc4/lib
+
+NOT YET SUPPORTED
+* local log socket
+* kernel log
diff --git a/solaris/cddllicense.txt b/solaris/cddllicense.txt
new file mode 100644
index 00000000..a10bba27
--- /dev/null
+++ b/solaris/cddllicense.txt
@@ -0,0 +1,242 @@
+ COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL)
+ Version 1.0
+
+
+1. Definitions.
+
+ 1.1. “Contributor” means each individual or entity that creates or contributes to the creation of Modifications.
+
+ 1.2. “Contributor Version” means the combination of the Original Software, prior Modifications used by a Contributor
+ (if any), and the Modifications made by that particular Contributor.
+
+ 1.3. “Covered Software” means (a) the Original Software, or (b) Modifications, or (c) the combination
+ of files containing Original Software with files containing Modifications, in each case including portions thereof.
+
+ 1.4. “Executable” means the Covered Software in any form other than Source Code.
+
+ 1.5. “Initial Developer” means the individual or entity that first makes Original Software available under this License.
+
+ 1.6. “Larger Work” means a work which combines Covered Software or portions thereof with code not governed by the terms
+ of this License.
+
+ 1.7. “License” means this document.
+
+ 1.8. “Licensable” means having the right to grant, to the maximum extent possible, whether at the time of the
+ initial grant or subsequently acquired, any and all of the rights conveyed herein.
+
+ 1.9. “Modifications” means the Source Code and Executable form of any of the following:
+ A. Any file that results from an addition to, deletion from or modification of the contents of a file
+ containing Original Software or previous Modifications;
+ B. Any new file that contains any part of the Original Software or previous Modification; or
+ C. Any new file that is contributed or otherwise made available under the terms of this License.
+
+ 1.10. “Original Software” means the Source Code and Executable form of computer software code that is originally
+ released under this License.
+
+ 1.11. “Patent Claims” means any patent claim(s), now owned or hereafter acquired, including without limitation,
+ method, process, and apparatus claims, in any patent Licensable by grantor.
+
+ 1.12. “Source Code” means (a) the common form of computer software code in which modifications are made and
+ (b) associated documentation included in or with such code.
+
+ 1.13. “You” (or “Your”) means an individual or a legal entity exercising rights under, and complying with all of
+ the terms of, this License. For legal entities, “You” includes any entity which controls, is controlled by, or is
+ under common control with You. For purposes of this definition, “control” means (a) the power, direct or indirect,
+ to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more
+ than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity.
+
+2. License Grants.
+
+ 2.1. The Initial Developer Grant.
+ Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims,
+ the Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license:
+
+ (a) under intellectual property rights (other than patent or trademark) Licensable by Initial Developer,
+ to use, reproduce, modify, display, perform, sublicense and distribute the Original Software (or portions
+ thereof), with or without Modifications, and/or as part of a Larger Work; and
+
+ (b) under Patent Claims infringed by the making, using or selling of Original Software, to make, have made,
+ use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Software (or portions thereof).
+
+ (c) The licenses granted in Sections 2.1(a) and (b) are effective on the date Initial Developer first
+ distributes or otherwise makes the Original Software available to a third party under the terms of this License.
+
+ (d) Notwithstanding Section 2.1(b) above, no patent license is granted: (1) for code that You delete from
+ the Original Software, or (2) for infringements caused by: (i) the modification of the Original Software,
+ or (ii) the combination of the Original Software with other software or devices.
+
+ 2.2. Contributor Grant.
+ Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims,
+ each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license:
+
+ (a) under intellectual property rights (other than patent or trademark) Licensable by Contributor to use,
+ reproduce, modify, display, perform, sublicense and distribute the Modifications created by such Contributor
+ (or portions thereof), either on an unmodified basis, with other Modifications, as Covered Software and/or
+ as part of a Larger Work; and
+
+ (b) under Patent Claims infringed by the making, using, or selling of Modifications made by that Contributor
+ either alone and/or in combination with its Contributor Version (or portions of such combination), to make,
+ use, sell, offer for sale, have made, and/or otherwise dispose of: (1) Modifications made by that Contributor
+ (or portions thereof); and (2) the combination of Modifications made by that Contributor with its Contributor
+ Version (or portions of such combination).
+
+ (c) The licenses granted in Sections 2.2(a) and 2.2(b) are effective on the date Contributor first distributes
+ or otherwise makes the Modifications available to a third party.
+
+ (d) Notwithstanding Section 2.2(b) above, no patent license is granted: (1) for any code that Contributor has
+ deleted from the Contributor Version; (2) for infringements caused by: (i) third party modifications of
+ Contributor Version, or (ii) the combination of Modifications made by that Contributor with other software
+ (except as part of the Contributor Version) or other devices; or (3) under Patent Claims infringed by Covered
+ Software in the absence of Modifications made by that Contributor.
+
+3. Distribution Obligations.
+
+ 3.1. Availability of Source Code.
+ Any Covered Software that You distribute or otherwise make available in Executable form must also be made available
+ in Source Code form and that Source Code form must be distributed only under the terms of this License. You must
+ include a copy of this License with every copy of the Source Code form of the Covered Software You distribute or
+ otherwise make available. You must inform recipients of any such Covered Software in Executable form as to how they
+ can obtain such Covered Software in Source Code form in a reasonable manner on or through a medium customarily used
+ for software exchange.
+
+ 3.2. Modifications.
+ The Modifications that You create or to which You contribute are governed by the terms of this License. You
+ represent that You believe Your Modifications are Your original creation(s) and/or You have sufficient rights to
+ grant the rights conveyed by this License.
+
+ 3.3. Required Notices.
+ You must include a notice in each of Your Modifications that identifies You as the Contributor of the Modification.
+ You may not remove or alter any copyright, patent or trademark notices contained within the Covered Software, or
+ any notices of licensing or any descriptive text giving attribution to any Contributor or the Initial Developer.
+
+ 3.4. Application of Additional Terms.
+ You may not offer or impose any terms on any Covered Software in Source Code form that alters or restricts the
+ applicable version of this License or the recipients’ rights hereunder. You may choose to offer, and to charge a
+ fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software.
+ However, you may do so only on Your own behalf, and not on behalf of the Initial Developer or any Contributor.
+ You must make it absolutely clear that any such warranty, support, indemnity or liability obligation is offered
+ by You alone, and You hereby agree to indemnify the Initial Developer and every Contributor for any liability
+ incurred by the Initial Developer or such Contributor as a result of warranty, support, indemnity or liability
+ terms You offer.
+
+ 3.5. Distribution of Executable Versions.
+ You may distribute the Executable form of the Covered Software under the terms of this License or under the terms
+ of a license of Your choice, which may contain terms different from this License, provided that You are in compliance
+ with the terms of this License and that the license for the Executable form does not attempt to limit or alter
+ the recipient’s rights in the Source Code form from the rights set forth in this License. If You distribute the
+ Covered Software in Executable form under a different license, You must make it absolutely clear that any terms
+ which differ from this License are offered by You alone, not by the Initial Developer or Contributor. You hereby
+ agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer
+ or such Contributor as a result of any such terms You offer.
+
+ 3.6. Larger Works.
+ You may create a Larger Work by combining Covered Software with other code not governed by the terms of this License
+ and distribute the Larger Work as a single product. In such a case, You must make sure the requirements of this
+ License are fulfilled for the Covered Software.
+
+4. Versions of the License.
+
+ 4.1. New Versions.
+ Sun Microsystems, Inc. is the initial license steward and may publish revised and/or new versions of this License
+ from time to time. Each version will be given a distinguishing version number. Except as provided in Section 4.3,
+ no one other than the license steward has the right to modify this License.
+
+ 4.2. Effect of New Versions.
+ You may always continue to use, distribute or otherwise make the Covered Software available under the terms of
+ the version of the License under which You originally received the Covered Software. If the Initial Developer
+ includes a notice in the Original Software prohibiting it from being distributed or otherwise made available under
+ any subsequent version of the License, You must distribute and make the Covered Software available under the terms
+ of the version of the License under which You originally received the Covered Software. Otherwise, You may also
+ choose to use, distribute or otherwise make the Covered Software available under the terms of any subsequent version
+ of the License published by the license steward.
+
+ 4.3. Modified Versions.
+ When You are an Initial Developer and You want to create a new license for Your Original Software, You may create
+ and use a modified version of this License if You: (a) rename the license and remove any references to the name of
+ the license steward (except to note that the license differs from this License); and (b) otherwise make it clear that
+ the license contains terms which differ from this License.
+
+5. DISCLAIMER OF WARRANTY.
+
+COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN “AS IS” BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR
+IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A
+PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU.
+SHOULD ANY COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
+COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE.
+NO USE OF ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+6. TERMINATION.
+
+ 6.1. This License and the rights granted hereunder will terminate automatically if You fail to comply with terms
+ herein and fail to cure such breach within 30 days of becoming aware of the breach. Provisions which, by their
+ nature, must remain in effect beyond the termination of this License shall survive.
+
+ 6.2. If You assert a patent infringement claim (excluding declaratory judgment actions) against Initial Developer
+ or a Contributor (the Initial Developer or Contributor against whom You assert such claim is referred to as
+ “Participant”) alleging that the Participant Software (meaning the Contributor Version where the Participant
+ is a Contributor or the Original Software where the Participant is the Initial Developer) directly or
+ indirectly infringes any patent, then any and all rights granted directly or indirectly to You by such Participant,
+ the Initial Developer (if the Initial Developer is not the Participant) and all Contributors under Sections 2.1
+ and/or 2.2 of this License shall, upon 60 days notice from Participant terminate prospectively and automatically
+ at the expiration of such 60 day notice period, unless if within such 60 day period You withdraw Your claim with
+ respect to the Participant Software against such Participant either unilaterally or pursuant to a written agreement
+ with Participant.
+
+ 6.3. If You assert a patent infringement claim against Participant alleging that the Participant Software directly
+ or indirectly infringes any patent where such claim is resolved (such as by license or settlement) prior to the
+ initiation of patent infringement litigation, then the reasonable value of the licenses granted by such Participant
+ under Sections 2.1 or 2.2 shall be taken into account in determining the amount or value of any payment or license.
+
+ 6.4. In the event of termination under Sections 6.1 or 6.2 above, all end user licenses that have been validly granted
+ by You or any distributor hereunder prior to termination (excluding licenses granted to You by any distributor)
+ shall survive termination.
+
+7. LIMITATION OF LIABILITY.
+
+UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE
+INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO
+ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR
+LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY
+SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL
+INJURY RESULTING FROM SUCH PARTY’S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
+EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
+
+8. U.S. GOVERNMENT END USERS.
+
+The Covered Software is a “commercial item,” as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of
+“commercial computer software” (as that term is defined at 48 C.F.R. § 252.227-7014(a)(1)) and “commercial computer software documentation”
+as such terms are used in 48 C.F.R. 12.212 Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
+all U.S. Government End Users acquire Covered Software with only those rights set forth herein. This U.S. Government Rights clause is in lieu of,
+and supersedes, any other FAR, DFAR, or other clause or provision that addresses Government rights in computer software under this License.
+
+9. MISCELLANEOUS.
+
+This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. This License shall be governed
+by the law of the jurisdiction specified in a notice contained within the Original Software (except to the extent applicable law, if any,
+provides otherwise), excluding such jurisdiction’s conflict-of-law provisions. Any litigation relating to this License shall be subject
+to the jurisdiction of the courts located in the jurisdiction and venue specified in a notice contained within the Original Software, with the
+losing party responsible for costs, including, without limitation, court costs and reasonable attorneys’ fees and expenses. The application of
+the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation which provides that
+the language of a contract shall be construed against the drafter shall not apply to this License. You agree that You alone are responsible for
+compliance with the United States export administration regulations (and the export control laws and regulation of any other countries) when You use,
+distribute or otherwise make available any Covered Software.
+
+10. RESPONSIBILITY FOR CLAIMS.
+
+As between Initial Developer and the Contributors, each party is responsible for claims and damages arising, directly or indirectly, out of
+its utilization of rights under this License and You agree to work with Initial Developer and Contributors to distribute such responsibility on
+an equitable basis. Nothing herein is intended or shall be deemed to constitute any admission of liability.
+
+--------
+
+NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION
+LICENSE (CDDL)
+
+The OpenSolaris code released under the CDDL shall be governed by the laws
+of the State of California (excluding conflict-of-law provisions). Any
+litigation relating to this License shall be subject to the jurisdiction of
+the Federal Courts of the Northern District of California and the state
+courts of the State of California, with venue lying in Santa Clara County,
+California.
+
diff --git a/template.c b/template.c
index 5a43cba3..68c57be1 100644
--- a/template.c
+++ b/template.c
@@ -61,7 +61,6 @@ static inline rsRetVal ExtendBuf(uchar **pBuf, size_t *pLenBuf, size_t iMinSize)
CHKmalloc(pNewBuf = (uchar*) realloc(*pBuf, iNewSize));
*pBuf = pNewBuf;
*pLenBuf = iNewSize;
-dbgprintf("extend buf to at least %ld, done %ld\n", iMinSize, iNewSize);
finalize_it:
RETiRet;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index b500bc85..ac0844e9 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,12 +1,13 @@
if ENABLE_TESTBENCH
TESTRUNS = rt_init rscript
-check_PROGRAMS = $(TESTRUNS) ourtail nettester tcpflood chkseq randomgen
+check_PROGRAMS = $(TESTRUNS) ourtail nettester tcpflood chkseq msleep randomgen diagtalker uxsockrcvr
TESTS = $(TESTRUNS) cfg.sh \
validation-run.sh \
imtcp-multiport.sh \
diskqueue.sh \
diskqueue-fsync.sh \
manytcp.sh \
+ rsf_getenv.sh \
manyptcp.sh \
imptcp_large.sh \
imptcp_conndrop.sh \
@@ -29,7 +30,8 @@ TESTS = $(TESTRUNS) cfg.sh \
dynfile_invalid2.sh \
complex1.sh \
queue-persist.sh \
- pipeaction.sh
+ pipeaction.sh \
+ uxsock_simple.sh \
execonlyonce.sh \
queue-persist.sh
@@ -48,12 +50,10 @@ if ENABLE_EXTENDED_TESTS
TESTS += random.sh
endif
-check_JAVA = DiagTalker.java
-
endif # if ENABLE_TESTBENCH
TESTS_ENVIRONMENT = RSYSLOG_MODDIR='$(abs_top_builddir)'/runtime/.libs/
-DISTCLEANFILES=rsyslog.pid '$(abs_top_builddir)'/DiagTalker.class
+DISTCLEANFILES=rsyslog.pid
test_files = testbench.h runtime-dummy.c
EXTRA_DIST= 1.rstest 2.rstest 3.rstest err1.rstest \
@@ -132,6 +132,8 @@ EXTRA_DIST= 1.rstest 2.rstest 3.rstest err1.rstest \
killrsyslog.sh \
parsertest.sh \
fieldtest.sh \
+ rsf_getenv.sh \
+ testsuites/rsf_getenv.conf \
diskqueue.sh \
testsuites/diskqueue.conf \
diskqueue-fsync.sh \
@@ -173,6 +175,8 @@ EXTRA_DIST= 1.rstest 2.rstest 3.rstest err1.rstest \
testsuites/sndrcv_gzip_rcvr.conf \
pipeaction.sh \
testsuites/pipeaction.conf \
+ uxsock_simple.sh \
+ testsuites/uxsock_simple.conf \
asynwr_simple.sh \
testsuites/asynwr_simple.conf \
asynwr_timeout.sh \
@@ -213,15 +217,19 @@ EXTRA_DIST= 1.rstest 2.rstest 3.rstest err1.rstest \
execonlyonce.sh \
testsuites/execonlyonce.conf \
testsuites/execonlyonce.data \
- DiagTalker.java \
cfg.sh
+uxsockrcvr_SOURCES = uxsockrcvr.c
ourtail_SOURCES = ourtail.c
+msleep_SOURCES = msleep.c
chkseq_SOURCES = chkseq.c
tcpflood_SOURCES = tcpflood.c
tcpflood_LDADD = $(SOL_LIBS)
+diagtalker_SOURCES = diagtalker.c
+diagtalker_LDADD = $(SOL_LIBS)
+
randomgen_SOURCES = randomgen.c
randomgen_LDADD = $(SOL_LIBS)
diff --git a/tests/complex1.sh b/tests/complex1.sh
index 954ddf6c..e138bff5 100755
--- a/tests/complex1.sh
+++ b/tests/complex1.sh
@@ -10,12 +10,13 @@ source $srcdir/diag.sh init
#export RSYSLOG_DEBUG="debug nostdout"
#export RSYSLOG_DEBUGLOG="log"
source $srcdir/diag.sh startup complex1.conf
-# send 30,000 messages of 400 bytes plus header max, via three dest ports
+# send 40,000 messages of 400 bytes plus header max, via three dest ports
source $srcdir/diag.sh tcpflood -m40000 -rd400 -P129 -f5 -n3 -c15 -i1
sleep 4 # due to large messages, we need this time for the tcp receiver to settle...
source $srcdir/diag.sh shutdown-when-empty # shut down rsyslogd when done processing messages
source $srcdir/diag.sh wait-shutdown # and wait for it to terminate
ls rsyslog.out.*.log
-zcat rsyslog.out.*.log > rsyslog.out.log
+source $srcdir/diag.sh setzcat # find out which zcat to use
+$ZCAT rsyslog.out.*.log > rsyslog.out.log
source $srcdir/diag.sh seq-check 1 40000 -E
source $srcdir/diag.sh exit
diff --git a/tests/diag.sh b/tests/diag.sh
index 8659aa17..1caf529f 100755
--- a/tests/diag.sh
+++ b/tests/diag.sh
@@ -37,25 +37,26 @@ case $1 in
$srcdir/diag.sh wait-startup $3
;;
'wait-startup') # wait for rsyslogd startup ($2 is the instance)
+ while test ! -f rsyslog$2.pid; do
+ ./msleep 100 # wait 100 milliseconds
+ done
while test ! -f rsyslogd$2.started; do
- #true
- sleep 0.1 # if this is not supported by all platforms, use above!
+ ./msleep 100 # wait 100 milliseconds
done
echo "rsyslogd$2 started with pid " `cat rsyslog$2.pid`
;;
'wait-shutdown') # actually, we wait for rsyslog.pid to be deleted. $2 is the
# instance
while test -f rsyslog$2.pid; do
- #true
- sleep 0.1 # if this is not supported by all platforms, use above!
+ ./msleep 100 # wait 100 milliseconds
done
;;
'wait-queueempty') # wait for main message queue to be empty. $2 is the instance.
if [ "$2" == "2" ]
then
- echo WaitMainQueueEmpty | java -classpath $abs_top_builddir DiagTalker
+ echo WaitMainQueueEmpty | ./diagtalker
else
- echo WaitMainQueueEmpty | java -classpath $abs_top_builddir DiagTalker 13501
+ echo WaitMainQueueEmpty | ./diagtalker
fi
;;
'shutdown-when-empty') # shut rsyslogd down when main queue is empty. $2 is the instance.
@@ -77,7 +78,7 @@ case $1 in
;;
'injectmsg') # inject messages via our inject interface (imdiag)
echo injecting $3 messages
- echo injectmsg $2 $3 $4 $5 | java -classpath $abs_top_builddir DiagTalker
+ echo injectmsg $2 $3 $4 $5 | ./diagtalker
# TODO: some return state checking? (does it really make sense here?)
;;
'check-mainq-spool') # check if mainqueue spool files exist, if not abort (we just check .qi).
@@ -131,5 +132,12 @@ case $1 in
exit 1
fi
;;
+ 'setzcat') # find out name of zcat tool
+ if [ `uname` == SunOS ]; then
+ ZCAT=gzcat
+ else
+ ZCAT=zcat
+ fi
+ ;;
*) echo "invalid argument" $1
esac
diff --git a/tests/diagtalker.c b/tests/diagtalker.c
new file mode 100644
index 00000000..6a721e47
--- /dev/null
+++ b/tests/diagtalker.c
@@ -0,0 +1,157 @@
+/* A yet very simple tool to talk to imdiag (this replaces the
+ * previous Java implementation in order to get fewer dependencies).
+ *
+ * Copyright 2010 Rainer Gerhards and Adiscon GmbH.
+ *
+ * This file is part of rsyslog.
+ *
+ * Rsyslog is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Rsyslog is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Rsyslog. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+ */
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+
+static char *targetIP = "127.0.0.1";
+static int targetPort = 13500;
+
+
+/* open a single tcp connection
+ */
+int openConn(int *fd)
+{
+ int sock;
+ struct sockaddr_in addr;
+ int port;
+ int retries = 0;
+
+ if((sock=socket(AF_INET, SOCK_STREAM, 0))==-1) {
+ perror("socket()");
+ exit(1);
+ }
+
+ port = targetPort;
+ memset((char *) &addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ if(inet_aton(targetIP, &addr.sin_addr)==0) {
+ fprintf(stderr, "inet_aton() failed\n");
+ exit(1);
+ }
+ while(1) { /* loop broken inside */
+ if(connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == 0) {
+ break;
+ } else {
+ if(retries++ == 50) {
+ perror("connect()");
+ fprintf(stderr, "connect() failed\n");
+ exit(1);
+ } else {
+ fprintf(stderr, "connect failed, retrying...\n");
+ usleep(100000); /* ms = 1000 us! */
+ }
+ }
+ }
+
+ *fd = sock;
+ return 0;
+}
+
+
+/* send a string
+ */
+static void
+sendCmd(int fd, char *buf, int len)
+{
+ int lenSend;
+
+ lenSend = send(fd, buf, len, 0);
+ if(lenSend != len) {
+ perror("sending string");
+ exit(1);
+ }
+}
+
+
+/* wait for a response from remote system
+ */
+static void
+waitRsp(int fd, char *buf, int len)
+{
+ int ret;
+
+ ret = recv(fd, buf, len - 1, 0);
+ if(ret < 0) {
+ perror("receiving response");
+ exit(1);
+ }
+ /* we assume the message was complete, it may be better to wait
+ * for a LF...
+ */
+ buf[ret] = '\0';
+}
+
+
+/* do the actual processing
+ */
+static void
+doProcessing()
+{
+ int fd;
+ int len;
+ char line[2048];
+
+ openConn(&fd);
+ while(!feof(stdin)) {
+ if(fgets(line, sizeof(line) - 1, stdin) == NULL)
+ break;
+ len = strlen(line);
+ sendCmd(fd, line, len);
+ waitRsp(fd, line, sizeof(line));
+ printf("imdiag: %s", line);
+ }
+}
+
+
+/* Run the test.
+ * rgerhards, 2009-04-03
+ */
+int main(int argc, char *argv[])
+{
+ int ret = 0;
+ int opt;
+
+ while((opt = getopt(argc, argv, "f:t:p:c:C:m:i:I:P:d:n:M:rB")) != -1) {
+ switch (opt) {
+ case 't': targetIP = optarg;
+ break;
+ case 'p': targetPort = atoi(optarg);
+ break;
+ default: printf("invalid option '%c' or value missing - terminating...\n", opt);
+ exit (1);
+ break;
+ }
+ }
+
+ doProcessing();
+
+ exit(ret);
+}
diff --git a/tests/DiagTalker.java b/tests/historical/DiagTalker.java
index 5a6f7dd5..147cec34 100644
--- a/tests/DiagTalker.java
+++ b/tests/historical/DiagTalker.java
@@ -1,3 +1,4 @@
+This tool has been replaced by ./tests/diagtalker.c in release 4.7.1
/* A yet very simple tool to talk to imdiag.
*
* Copyright 2009 Rainer Gerhards and Adiscon GmbH.
diff --git a/tests/historical/README b/tests/historical/README
new file mode 100644
index 00000000..5f10ecef
--- /dev/null
+++ b/tests/historical/README
@@ -0,0 +1,2 @@
+This directory contains tools that are currently not being used, but are
+kept because they may be used again in the future.
diff --git a/tests/msleep.c b/tests/msleep.c
new file mode 100644
index 00000000..36fa01b5
--- /dev/null
+++ b/tests/msleep.c
@@ -0,0 +1,51 @@
+/* sleeps for the specified number of MILLIseconds.
+ * Primarily meant as a portable tool available everywhere for the
+ * testbench (sleep 0.1 does not work on all platforms).
+ *
+ * Part of the testbench for rsyslog.
+ *
+ * Copyright 2010 Rainer Gerhards and Adiscon GmbH.
+ *
+ * This file is part of rsyslog.
+ *
+ * Rsyslog is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Rsyslog is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Rsyslog. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+ */
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+int main(int argc, char *argv[])
+{
+ struct timeval tvSelectTimeout;
+ long sleepTime;
+
+ if(argc != 2) {
+ fprintf(stderr, "usage: msleep <milliseconds>\n");
+ exit(1);
+ }
+
+ sleepTime = atoi(argv[1]);
+ tvSelectTimeout.tv_sec = sleepTime / 1000;
+ tvSelectTimeout.tv_usec = (sleepTime % 1000) * 1000; /* micro seconds */
+ if(select(0, NULL, NULL, NULL, &tvSelectTimeout) == -1) {
+ perror("select");
+ exit(1);
+ }
+
+ return 0;
+}
+
diff --git a/tests/nettester.c b/tests/nettester.c
index e1ecbcb5..24e20422 100644
--- a/tests/nettester.c
+++ b/tests/nettester.c
@@ -62,7 +62,7 @@ static char *testSuite = NULL; /* name of current test suite */
static int iPort = 12514; /* port which shall be used for sending data */
static char* pszCustomConf = NULL; /* custom config file, use -c conf to specify */
static int verbose = 0; /* verbose output? -v option */
-static int useDebugEnv = 0; /* activate debugging environment (for rsyslog debug log)? */
+static char **ourEnvp;
/* these two are quick hacks... */
int iFailed = 0;
@@ -117,6 +117,10 @@ void readLine(int fd, char *ln)
* We use traditional framing '\n' at EOR for this tester. It may be
* worth considering additional framing modes.
* rgerhards, 2009-04-08
+ * Note: we re-create the socket within the retry loop, because this
+ * seems to be needed under Solaris. If we do not do that, we run
+ * into troubles (maybe something wrongly initialized then?)
+ * -- rgerhards, 2010-04-12
*/
int
tcpSend(char *buf, int lenBuf)
@@ -124,30 +128,34 @@ tcpSend(char *buf, int lenBuf)
static int sock = INVALID_SOCKET;
struct sockaddr_in addr;
int retries;
+ int ret;
+ int iRet = 0; /* 0 OK, anything else error */
if(sock == INVALID_SOCKET) {
/* first time, need to connect to target */
- if((sock=socket(AF_INET, SOCK_STREAM, 0))==-1) {
- perror("socket()");
- return(1);
- }
-
- memset((char *) &addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_port = htons(iPort);
- if(inet_aton("127.0.0.1", &addr.sin_addr)==0) {
- fprintf(stderr, "inet_aton() failed\n");
- return(1);
- }
retries = 0;
while(1) { /* loop broken inside */
- if(connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == 0) {
+ /* first time, need to connect to target */
+ if((sock=socket(AF_INET, SOCK_STREAM, 0))==-1) {
+ perror("socket()");
+ iRet = 1;
+ goto finalize_it;
+ }
+ memset((char *) &addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(iPort);
+ if(inet_aton("127.0.0.1", &addr.sin_addr)==0) {
+ fprintf(stderr, "inet_aton() failed\n");
+ iRet = 1;
+ goto finalize_it;
+ }
+ if((ret = connect(sock, (struct sockaddr*)&addr, sizeof(addr))) == 0) {
break;
} else {
if(retries++ == 50) {
- ++iFailed;
fprintf(stderr, "connect() failed\n");
- return(1);
+ iRet = 1;
+ goto finalize_it;
} else {
usleep(100000); /* 0.1 sec, these are us! */
}
@@ -156,20 +164,32 @@ tcpSend(char *buf, int lenBuf)
}
/* send test data */
- if(send(sock, buf, lenBuf, 0) != lenBuf) {
+ if((ret = send(sock, buf, lenBuf, 0)) != lenBuf) {
perror("send test data");
- fprintf(stderr, "send() failed\n");
- return(1);
+ fprintf(stderr, "send() failed, sock=%d, ret=%d\n", sock, ret);
+ iRet = 1;
+ goto finalize_it;
}
/* send record terminator */
if(send(sock, "\n", 1, 0) != 1) {
perror("send record terminator");
fprintf(stderr, "send() failed\n");
- return(1);
+ iRet = 1;
+ goto finalize_it;
}
- return 0;
+finalize_it:
+ if(iRet != 0) {
+ /* need to do some (common) cleanup */
+ if(sock != INVALID_SOCKET) {
+ close(sock);
+ sock = INVALID_SOCKET;
+ }
+ ++iFailed;
+ }
+
+ return iRet;
}
@@ -218,9 +238,6 @@ int openPipe(char *configFile, pid_t *pid, int *pfd)
char *newargv[] = {"../tools/rsyslogd", "dummy", "-c4", "-u2", "-n", "-irsyslog.pid",
"-M../runtime/.libs:../.libs", NULL };
char confFile[1024];
- char *newenviron[] = { NULL };
- char *newenvironDeb[] = { "RSYSLOG_DEBUG=debug nostdout",
- "RSYSLOG_DEBUGLOG=log", NULL };
sprintf(confFile, "-f%s/testsuites/%s.conf", srcdir,
(pszCustomConf == NULL) ? configFile : pszCustomConf);
@@ -243,8 +260,9 @@ int openPipe(char *configFile, pid_t *pid, int *pfd)
close(pipefd[1]);
close(pipefd[0]);
fclose(stdin);
- execve("../tools/rsyslogd", newargv, (useDebugEnv) ? newenvironDeb : newenviron);
+ execve("../tools/rsyslogd", newargv, ourEnvp);
} else {
+ usleep(10000);
close(pipefd[1]);
*pid = cpid;
*pfd = pipefd[0];
@@ -364,6 +382,7 @@ processTestFile(int fd, char *pszFileName)
expected[strlen(expected)-1] = '\0'; /* remove \n */
/* pull response from server and then check if it meets our expectation */
+//printf("try pull pipe...\n");
readLine(fd, buf);
if(strcmp(expected, buf)) {
++iFailed;
@@ -426,7 +445,8 @@ doTests(int fd, char *files)
printf("Error: no test cases found, no tests executed.\n");
iFailed = 1;
} else {
- printf("Number of tests run: %d, number of failures: %d\n", iTests, iFailed);
+ printf("Number of tests run: %3d, number of failures: %d, test: %s/%s\n",
+ iTests, iFailed, testSuite, inputMode2Str(inputMode));
}
return(iFailed);
@@ -450,7 +470,7 @@ void doAtExit(void)
* of this file.
* rgerhards, 2009-04-03
*/
-int main(int argc, char *argv[])
+int main(int argc, char *argv[], char *envp[])
{
int fd;
int opt;
@@ -459,14 +479,12 @@ int main(int argc, char *argv[])
char buf[4096];
char testcases[4096];
+ ourEnvp = envp;
while((opt = getopt(argc, argv, "dc:i:p:t:v")) != EOF) {
switch((char)opt) {
case 'c':
pszCustomConf = optarg;
break;
- case 'd':
- useDebugEnv = 1;
- break;
case 'i':
if(!strcmp(optarg, "udp"))
inputMode = inputUDP;
@@ -520,6 +538,11 @@ int main(int argc, char *argv[])
}
fclose(fp);
+ /* make sure we do not abort if there is an issue with pipes.
+ * our code does the necessary error handling.
+ */
+ sigset(SIGPIPE, SIG_IGN);
+
/* start to be tested rsyslogd */
openPipe(testSuite, &rsyslogdPid, &fd);
readLine(fd, buf);
diff --git a/tests/rsf_getenv.sh b/tests/rsf_getenv.sh
new file mode 100755
index 00000000..fd083bce
--- /dev/null
+++ b/tests/rsf_getenv.sh
@@ -0,0 +1,17 @@
+# Test for the getenv() rainerscript function
+# this is a quick test, but it gurantees that the code path is
+# at least progressed (but we do not check for unset envvars!)
+# added 2009-11-03 by Rgerhards
+# This file is part of the rsyslog project, released under GPLv3
+# uncomment for debugging support:
+echo ===============================================================================
+echo \[rsf_getenv.sh\]: testing RainerScript getenv\(\) function
+export MSGNUM="msgnum:"
+source $srcdir/diag.sh init
+source $srcdir/diag.sh startup rsf_getenv.conf
+source $srcdir/diag.sh tcpflood -m10000
+source $srcdir/diag.sh shutdown-when-empty # shut down rsyslogd when done processing messages
+source $srcdir/diag.sh wait-shutdown
+source $srcdir/diag.sh seq-check 0 9999
+unset MSGNUM
+source $srcdir/diag.sh exit
diff --git a/tests/rt-init.c b/tests/rt-init.c
index 66a9ad32..dbe94b4a 100644
--- a/tests/rt-init.c
+++ b/tests/rt-init.c
@@ -39,6 +39,6 @@ ENDExit
BEGINTest
CODESTARTTest
-finalize_it:
+/*finalize_it:*/
/* room for custom error reporter, leave blank if not needed */
ENDTest
diff --git a/tests/tcpflood.c b/tests/tcpflood.c
index ee43449e..2d8be10f 100644
--- a/tests/tcpflood.c
+++ b/tests/tcpflood.c
@@ -64,6 +64,7 @@
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
+#include <sys/resource.h>
#define EXIT_FAILURE 1
#define INVALID_SOCKET -1
@@ -415,6 +416,20 @@ int main(int argc, char *argv[])
}
}
+ if(numConnections > 20) {
+ /* if we use many (whatever this means, 20 is randomly picked)
+ * connections, we need to make sure we have a high enough
+ * limit. -- rgerhards, 2010-03-25
+ */
+ struct rlimit maxFiles;
+ maxFiles.rlim_cur = numConnections + 20;
+ maxFiles.rlim_max = numConnections + 20;
+ if(setrlimit(RLIMIT_NOFILE, &maxFiles) < 0) {
+ perror("setrlimit to increase file handles failed");
+ exit(1);
+ }
+ }
+
if(dataFile != NULL) {
if((dataFP = fopen(dataFile, "r")) == NULL) {
perror(dataFile);
diff --git a/tests/testsuites/rsf_getenv.conf b/tests/testsuites/rsf_getenv.conf
new file mode 100644
index 00000000..2f2eb58c
--- /dev/null
+++ b/tests/testsuites/rsf_getenv.conf
@@ -0,0 +1,17 @@
+# Test for RainerScript getenv() function (see .sh file for details)
+# Note envvar MSGNUM must be set to "msgnum:"
+# rgerhards, 2009-11-03
+$IncludeConfig diag-common.conf
+
+$ModLoad ../plugins/imtcp/.libs/imtcp
+$MainMsgQueueTimeoutShutdown 10000
+$InputTCPServerRun 13514
+
+# set spool locations and switch queue to disk-only mode
+$WorkDirectory test-spool
+$MainMsgQueueFilename mainq
+$MainMsgQueueType disk
+
+$template outfmt,"%msg:F,58:2%\n"
+$template dynfile,"rsyslog.out.log" # trick to use relative path names!
+if $msg contains getenv('MSGNUM') then ?dynfile;outfmt
diff --git a/tests/testsuites/uxsock_simple.conf b/tests/testsuites/uxsock_simple.conf
new file mode 100644
index 00000000..efffdd90
--- /dev/null
+++ b/tests/testsuites/uxsock_simple.conf
@@ -0,0 +1,10 @@
+# Test for pipe output action (see .sh file for details)
+# rgerhards, 2009-11-05
+$IncludeConfig diag-common.conf
+
+$MainMsgQueueTimeoutShutdown 10000
+
+$ModLoad ../plugins/omuxsock/.libs/omuxsock
+$template outfmt,"%msg:F,58:2%\n"
+$OMUXSockSocket rsyslog-testbench-dgram-uxsock
+:msg, contains, "msgnum:" :omuxsock:;outfmt
diff --git a/tests/threadingmqaq.sh b/tests/threadingmqaq.sh
index b7764821..0104be00 100755
--- a/tests/threadingmqaq.sh
+++ b/tests/threadingmqaq.sh
@@ -12,6 +12,9 @@ source $srcdir/diag.sh startup threadingmqaq.conf
#source $srcdir/diag.sh tcpflood -c2 -m100000
#source $srcdir/diag.sh shutdown-when-empty # shut down rsyslogd when done processing messages
source $srcdir/diag.sh injectmsg 0 100000
+# we need to sleep a bit on some environments, as imdiag can not correctly
+# diagnose when the action queues are empty...
+sleep 3
source $srcdir/diag.sh shutdown-when-empty # shut down rsyslogd when done processing messages
source $srcdir/diag.sh wait-shutdown
source $srcdir/diag.sh seq-check 0 99999
diff --git a/tests/uxsock_simple.sh b/tests/uxsock_simple.sh
new file mode 100755
index 00000000..7f00f4bc
--- /dev/null
+++ b/tests/uxsock_simple.sh
@@ -0,0 +1,31 @@
+# This tests basic omuxsock functionality. A socket receiver is started which sends
+# all data to an output file, then a rsyslog instance is started which generates
+# messages and sends them to the unix socket. Datagram sockets are being used.
+# added 2010-08-06 by Rgerhards
+echo ===============================================================================
+echo \[uxsock_simple.sh\]: simple tests for omuxsock functionality
+
+# create the pipe and start a background process that copies data from
+# it to the "regular" work file
+source $srcdir/diag.sh init
+./uxsockrcvr -srsyslog-testbench-dgram-uxsock -orsyslog.out.log &
+BGPROCESS=$!
+echo background uxsockrcvr process id is $BGPROCESS
+
+# now do the usual run
+source $srcdir/diag.sh startup uxsock_simple.conf
+# 10000 messages should be enough
+source $srcdir/diag.sh injectmsg 0 10000
+source $srcdir/diag.sh shutdown-when-empty # shut down rsyslogd when done processing messages
+source $srcdir/diag.sh wait-shutdown
+
+# wait for the cp process to finish, do pipe-specific cleanup
+echo shutting down uxsockrcvr...
+# TODO: we should do this more reliable in the long run! (message counter? timeout?)
+kill $BGPROCESS
+wait $BGPROCESS
+echo background process has terminated, continue test...
+
+# and continue the usual checks
+source $srcdir/diag.sh seq-check 0 9999
+source $srcdir/diag.sh exit
diff --git a/tests/uxsockrcvr.c b/tests/uxsockrcvr.c
new file mode 100644
index 00000000..551f0ef3
--- /dev/null
+++ b/tests/uxsockrcvr.c
@@ -0,0 +1,157 @@
+/* receives messages from a specified unix sockets and writes
+ * output to specfied file.
+ *
+ * Command line options:
+ * -s name of socket (required)
+ * -o name of output file (stdout if not given)
+ * -l add newline after each message received (default: do not add anything)
+ *
+ * Part of the testbench for rsyslog.
+ *
+ * Copyright 2010 Rainer Gerhards and Adiscon GmbH.
+ *
+ * This file is part of rsyslog.
+ *
+ * Rsyslog is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Rsyslog is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Rsyslog. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+ */
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <getopt.h>
+#include <sys/un.h>
+#include <netdb.h>
+
+char *sockName = NULL;
+int sock;
+int addNL = 0;
+
+
+/* called to clean up on exit
+ */
+void
+cleanup(void)
+{
+ unlink(sockName);
+ close(sock);
+}
+
+
+void
+doTerm(int __attribute__((unused)) signum)
+{
+ exit(1);
+}
+
+
+void
+usage(void)
+{
+ fprintf(stderr, "usage: uxsockrcvr -s /socket/name -o /output/file -l\n"
+ "-l adds newline after each message received\n"
+ "-s MUST be specified\n"
+ "if -o ist not specified, stdout is used\n");
+ exit(1);
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ int opt;
+ int rlen;
+ FILE *fp = stdout;
+ unsigned char data[128*1024];
+ struct sockaddr_un addr; /* address of server */
+ struct sockaddr from;
+ socklen_t fromlen;
+
+ if(argc < 2) {
+ fprintf(stderr, "error: too few arguments!\n");
+ usage();
+ }
+
+ while((opt = getopt(argc, argv, "s:o:l")) != EOF) {
+ switch((char)opt) {
+ case 'l':
+ addNL = 1;
+ break;
+ case 's':
+ sockName = optarg;
+ break;
+ case 'o':
+ if((fp = fopen(optarg, "w")) == NULL) {
+ perror(optarg);
+ exit(1);
+ }
+ break;
+ default:usage();
+ }
+ }
+
+ if(sockName == NULL) {
+ fprintf(stderr, "error: -s /socket/name must be specified!\n");
+ exit(1);
+ }
+
+ if(signal(SIGTERM, doTerm) == SIG_ERR) {
+ perror("signal(SIGTERM, ...)");
+ exit(1);
+ }
+ if(signal(SIGINT, doTerm) == SIG_ERR) {
+ perror("signal(SIGINT, ...)");
+ exit(1);
+ }
+
+ /* Create a UNIX datagram socket for server */
+ if ((sock = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
+ perror("server: socket");
+ exit(1);
+ }
+
+ atexit(cleanup);
+
+ /* Set up address structure for server socket */
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ strcpy(addr.sun_path, sockName);
+
+ if (bind(sock, (struct sockaddr*) &addr, sizeof(addr)) < 0) {
+ close(sock);
+ perror("server: bind");
+ exit(1);
+ }
+
+ /* we now run in an endless loop. We do not check who sends us
+ * data. This should be no problem for our testbench use.
+ */
+ while(1) {
+ fromlen = sizeof(from);
+ rlen = recvfrom(sock, data, 2000, 0, &from, &fromlen);
+ if(rlen == -1) {
+ perror("uxsockrcvr : recv\n");
+ exit(1);
+ } else {
+ fwrite(data, 1, rlen, fp);
+ if(addNL)
+ fputc('\n', fp);
+ }
+ }
+
+ return 0;
+}
diff --git a/tools/omfile.c b/tools/omfile.c
index 24de052c..a45d904b 100644
--- a/tools/omfile.c
+++ b/tools/omfile.c
@@ -89,11 +89,13 @@ typedef struct s_dynaFileCacheEntry dynaFileCacheEntry;
#define USE_ASYNCWRITER_DFLT 0 /* default buffer use async writer */
#define FLUSHONTX_DFLT 1 /* default for flush on TX end */
+#define DFLT_bForceChown 0
/* globals for default values */
static int iDynaFileCacheSize = 10; /* max cache for dynamic files */
static int fCreateMode = 0644; /* mode to use when creating files */
static int fDirCreateMode = 0700; /* mode to use when creating files */
static int bFailOnChown; /* fail if chown fails? */
+static int bForceChown = DFLT_bForceChown; /* Force chown() on existing files? */
static uid_t fileUID; /* UID to be used for newly created files */
static uid_t fileGID; /* GID to be used for newly created files */
static uid_t dirUID; /* UID to be used for newly created directories */
@@ -118,6 +120,7 @@ typedef struct _instanceData {
int fDirCreateMode; /* creation mode for mkdir() */
int bCreateDirs; /* auto-create directories? */
int bSyncFile; /* should the file by sync()'ed? 1- yes, 0- no */
+ bool bForceChown; /* force chown() on existing files? */
uid_t fileUID; /* IDs for creation */
uid_t dirUID;
gid_t fileGID;
@@ -163,8 +166,9 @@ CODESTARTdbgPrintInstInfo
dbgprintf("\tflush interval=%d\n", pData->iFlushInterval);
dbgprintf("\tfile cache size=%d\n", pData->iDynaFileCacheSize);
dbgprintf("\tcreate directories: %s\n", pData->bCreateDirs ? "yes" : "no");
- dbgprintf("\tfile owner %d, group %d\n", pData->fileUID, pData->fileGID);
- dbgprintf("\tdirectory owner %d, group %d\n", pData->dirUID, pData->dirGID);
+ dbgprintf("\tfile owner %d, group %d\n", (int) pData->fileUID, (int) pData->fileGID);
+ dbgprintf("\tforce chown() for all files: %s\n", pData->bForceChown ? "yes" : "no");
+ dbgprintf("\tdirectory owner %d, group %d\n", (int) pData->dirUID, (int) pData->dirGID);
dbgprintf("\tdir create mode 0%3.3o, file create mode 0%3.3o\n",
pData->fDirCreateMode, pData->fCreateMode);
dbgprintf("\tfail if owner/group can not be set: %s\n", pData->bFailOnChown ? "yes" : "no");
@@ -351,7 +355,22 @@ prepareFile(instanceData *pData, uchar *newFileName)
int fd;
DEFiRet;
- if(access((char*)newFileName, F_OK) != 0) {
+ if(access((char*)newFileName, F_OK) == 0) {
+ if(pData->bForceChown) {
+ /* Try to fix wrong ownership set by someone else. Note that this code
+ * will no longer work once we have made the $PrivDrop code fully secure.
+ * This change is based on an idea of Michael Terry, provided as part of
+ * the effort to make rsyslogd the Ubuntu default syslogd.
+ * rgerhards, 2009-09-11
+ */
+ if(chown((char*)newFileName, pData->fileUID, pData->fileGID) != 0) {
+ if(pData->bFailOnChown) {
+ int eSave = errno;
+ errno = eSave;
+ }
+ }
+ }
+ } else {
/* file does not exist, create it (and eventually parent directories */
fd = -1;
if(pData->bCreateDirs) {
@@ -372,7 +391,7 @@ prepareFile(instanceData *pData, uchar *newFileName)
pData->fCreateMode);
if(fd != -1) {
/* check and set uid/gid */
- if(pData->fileUID != (uid_t)-1 || pData->fileGID != (gid_t) -1) {
+ if(pData->bForceChown || pData->fileUID != (uid_t)-1 || pData->fileGID != (gid_t) -1) {
/* we need to set owner/group */
if(fchown(fd, pData->fileUID, pData->fileGID) != 0) {
if(pData->bFailOnChown) {
@@ -724,6 +743,7 @@ CODESTARTparseSelectorAct
pData->fDirCreateMode = fDirCreateMode;
pData->bCreateDirs = bCreateDirs;
pData->bFailOnChown = bFailOnChown;
+ pData->bForceChown = bForceChown;
pData->fileUID = fileUID;
pData->fileGID = fileGID;
pData->dirUID = dirUID;
@@ -759,6 +779,7 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a
dirUID = -1;
dirGID = -1;
bFailOnChown = 1;
+ bForceChown = DFLT_bForceChown;
iDynaFileCacheSize = 10;
fCreateMode = 0644;
fDirCreateMode = 0700;
@@ -826,6 +847,7 @@ CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(omsdRegCFSLineHdlr((uchar *)"filecreatemode", 0, eCmdHdlrFileCreateMode, NULL, &fCreateMode, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"createdirs", 0, eCmdHdlrBinary, NULL, &bCreateDirs, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"failonchownfailure", 0, eCmdHdlrBinary, NULL, &bFailOnChown, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"omfileForceChown", 0, eCmdHdlrBinary, NULL, &bForceChown, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionfileenablesync", 0, eCmdHdlrBinary, NULL, &bEnableSync, STD_LOADABLE_MODULE_ID));
CHKiRet(regCfSysLineHdlr((uchar *)"actionfiledefaulttemplate", 0, eCmdHdlrGetWord, NULL, &pszFileDfltTplName, NULL));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
diff --git a/tools/ompipe.c b/tools/ompipe.c
index 5fb9b27e..2d621e0e 100644
--- a/tools/ompipe.c
+++ b/tools/ompipe.c
@@ -36,9 +36,11 @@
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
+#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
+#include <fcntl.h>
#include <sys/file.h>
#include "syslogd.h"
diff --git a/tools/syslogd.c b/tools/syslogd.c
index 18e0c98f..985957a3 100644
--- a/tools/syslogd.c
+++ b/tools/syslogd.c
@@ -254,11 +254,14 @@ int bDropTrailingLF = 1; /* drop trailing LF's on reception? */
int iCompatibilityMode = 0; /* version we should be compatible with; 0 means sysklogd. It is
the default, so if no -c<n> option is given, we make ourselvs
as compatible to sysklogd as possible. */
+#define DFLT_bLogStatusMsgs 1
+static int bLogStatusMsgs = DFLT_bLogStatusMsgs; /* log rsyslog start/stop/HUP messages? */
static int bDebugPrintTemplateList = 1;/* output template list in debug mode? */
static int bDebugPrintCfSysLineHandlerList = 1;/* output cfsyslinehandler list in debug mode? */
static int bDebugPrintModuleList = 1;/* output module list in debug mode? */
-uchar cCCEscapeChar = '\\';/* character to be used to start an escape sequence for control chars */
+uchar cCCEscapeChar = '#';/* character to be used to start an escape sequence for control chars */
int bEscapeCCOnRcv = 1; /* escape control characters on reception: 0 - no, 1 - yes */
+int bEscapeTab = 1; /* treat tab as escape control character: 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? */
@@ -337,12 +340,14 @@ getFIOPName(unsigned iFIOP)
static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
{
cCCEscapeChar = '#';
+ bLogStatusMsgs = DFLT_bLogStatusMsgs;
bActExecWhenPrevSusp = 0;
iActExecOnceInterval = 0;
bDebugPrintTemplateList = 1;
bDebugPrintCfSysLineHandlerList = 1;
bDebugPrintModuleList = 1;
bEscapeCCOnRcv = 1; /* default is to escape control characters */
+ bEscapeTab = 1;
bReduceRepeatMsgs = 0;
free(pszMainMsgQFName);
pszMainMsgQFName = NULL;
@@ -809,7 +814,7 @@ parseAndSubmitMessage(uchar *hname, uchar *hnameIP, uchar *msg, int len, int fla
/* log an error? Very questionable... rgerhards, 2006-11-30 */
/* decided: we do not log an error, it won't help... rger, 2007-06-21 */
++pData;
- } else if(bEscapeCCOnRcv && iscntrl((int) *pData)) {
+ } else if(bEscapeCCOnRcv && iscntrl((int) *pData) && (*pData != '\t' || bEscapeTab)) {
/* we are configured to escape control characters. Please note
* that this most probably break non-western character sets like
* Japanese, Korean or Chinese. rgerhards, 2007-07-17
@@ -906,7 +911,7 @@ logmsgInternal(int iErr, int pri, uchar *msg, int flags)
* permits us to process unmodified config files which otherwise contain a
* supressor statement.
*/
- if(((Debug || NoFork) && bErrMsgToStderr) || iConfigVerify) {
+ if(((Debug == DEBUG_FULL || NoFork) && bErrMsgToStderr) || iConfigVerify) {
if(LOG_PRI(pri) == LOG_ERR)
fprintf(stderr, "rsyslogd: %s\n", msg);
}
@@ -1652,10 +1657,10 @@ static void doDie(int sig)
# define MSG1 "DoDie called.\n"
# define MSG2 "DoDie called 5 times - unconditional exit\n"
static int iRetries = 0; /* debug aid */
- if(Debug)
+ if(Debug == DEBUG_FULL)
write(1, MSG1, sizeof(MSG1) - 1);
if(iRetries++ == 4) {
- if(Debug)
+ if(Debug == DEBUG_FULL)
write(1, MSG2, sizeof(MSG2) - 1);
abort();
}
@@ -1721,7 +1726,7 @@ die(int sig)
thrdTerminateAll();
/* and THEN send the termination log message (see long comment above) */
- if (sig) {
+ if(sig && bLogStatusMsgs) {
(void) snprintf(buf, sizeof(buf) / sizeof(char),
" [origin software=\"rsyslogd\" " "swVersion=\"" VERSION \
"\" x-pid=\"%d\" x-info=\"http://www.rsyslog.com\"]" " exiting on signal %d.",
@@ -1842,6 +1847,9 @@ static rsRetVal setMaxFiles(void __attribute__((unused)) *pVal, int iFiles)
iFiles, errStr, (long) maxFiles.rlim_max);
ABORT_FINALIZE(RS_RET_ERR_RLIM_NOFILE);
}
+#ifdef USE_UNLIMITED_SELECT
+ glbl.SetFdSetSize(howmany(iFiles, __NFDBITS) * sizeof (fd_mask));
+#endif
DBGPRINTF("Max number of files set to %d [kernel max %ld].\n", iFiles, (long) maxFiles.rlim_max);
finalize_it:
@@ -2415,11 +2423,13 @@ init()
/* we now generate the startup message. It now includes everything to
* identify this instance. -- rgerhards, 2005-08-17
*/
- snprintf(bufStartUpMsg, sizeof(bufStartUpMsg)/sizeof(char),
- " [origin software=\"rsyslogd\" " "swVersion=\"" VERSION \
- "\" x-pid=\"%d\" x-info=\"http://www.rsyslog.com\"] (re)start",
- (int) myPid);
- logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, (uchar*)bufStartUpMsg, 0);
+ if(bLogStatusMsgs) {
+ snprintf(bufStartUpMsg, sizeof(bufStartUpMsg)/sizeof(char),
+ " [origin software=\"rsyslogd\" " "swVersion=\"" VERSION \
+ "\" x-pid=\"%d\" x-info=\"http://www.rsyslog.com\"] (re)start",
+ (int) myPid);
+ logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, (uchar*)bufStartUpMsg, 0);
+ }
memset(&sigAct, 0, sizeof (sigAct));
sigemptyset(&sigAct.sa_mask);
@@ -2450,6 +2460,25 @@ finalize_it:
}
+
+/* Put the rsyslog main thread to sleep for n seconds. This was introduced as
+ * a quick and dirty workaround for a privilege drop race in regard to listener
+ * startup, which itself was a result of the not-yet-done proper coding of
+ * privilege drop code (quite some effort). It may be useful for other occasions, too.
+ * is specified).
+ * rgerhards, 2009-06-12
+ */
+static rsRetVal
+putToSleep(void __attribute__((unused)) *pVal, int iNewVal)
+{
+ DEFiRet;
+ DBGPRINTF("rsyslog main thread put to sleep via $sleep %d directive...\n", iNewVal);
+ srSleep(iNewVal, 0);
+ DBGPRINTF("rsyslog main thread continues after $sleep %d\n", iNewVal);
+ RETiRet;
+}
+
+
/* Switch to either an already existing rule set or start a new one. The
* named rule set becomes the new "current" rule set (what means that new
* actions are added to it).
@@ -2568,12 +2597,14 @@ doHUP(void)
{
char buf[512];
- snprintf(buf, sizeof(buf) / sizeof(char),
- " [origin software=\"rsyslogd\" " "swVersion=\"" VERSION
- "\" x-pid=\"%d\" x-info=\"http://www.rsyslog.com\"] rsyslogd was HUPed, type '%s'.",
- (int) myPid, glbl.GetHUPisRestart() ? "restart" : "lightweight");
- errno = 0;
- logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, (uchar*)buf, 0);
+ if(bLogStatusMsgs) {
+ snprintf(buf, sizeof(buf) / sizeof(char),
+ " [origin software=\"rsyslogd\" " "swVersion=\"" VERSION
+ "\" x-pid=\"%d\" x-info=\"http://www.rsyslog.com\"] rsyslogd was HUPed, type '%s'.",
+ (int) myPid, glbl.GetHUPisRestart() ? "restart" : "lightweight");
+ errno = 0;
+ logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, (uchar*)buf, 0);
+ }
if(glbl.GetHUPisRestart()) {
DBGPRINTF("Received SIGHUP, configured to be restart, reloading rsyslogd.\n");
@@ -2697,9 +2728,11 @@ 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 *)"logrsyslogstatusmessages", 0, eCmdHdlrBinary, NULL, &bLogStatusMsgs, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"actionresumeretrycount", 0, eCmdHdlrInt, NULL, &glbliActionResumeRetryCount, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"defaultruleset", 0, eCmdHdlrGetWord, setDefaultRuleset, NULL, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"ruleset", 0, eCmdHdlrGetWord, setCurrRuleset, NULL, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"sleep", 0, eCmdHdlrInt, putToSleep, NULL, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuefilename", 0, eCmdHdlrGetWord, NULL, &pszMainMsgQFName, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuesize", 0, eCmdHdlrInt, NULL, &iMainMsgQueueSize, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuehighwatermark", 0, eCmdHdlrInt, NULL, &iMainMsgQHighWtrMark, NULL));
@@ -2727,6 +2760,7 @@ static rsRetVal loadBuildInModules(void)
CHKiRet(regCfSysLineHdlr((uchar *)"actionresumeinterval", 0, eCmdHdlrInt, setActionResumeInterval, NULL, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"controlcharacterescapeprefix", 0, eCmdHdlrGetChar, NULL, &cCCEscapeChar, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"escapecontrolcharactersonreceive", 0, eCmdHdlrBinary, NULL, &bEscapeCCOnRcv, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"escapecontrolcharactertab", 0, eCmdHdlrBinary, NULL, &bEscapeTab, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"droptrailinglfonreception", 0, eCmdHdlrBinary, NULL, &bDropTrailingLF, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"template", 0, eCmdHdlrCustomHandler, conf.doNameLine, (void*)DIR_TEMPLATE, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"outchannel", 0, eCmdHdlrCustomHandler, conf.doNameLine, (void*)DIR_OUTCHANNEL, NULL));
@@ -2884,7 +2918,7 @@ static rsRetVal mainThread()
* is still in its infancy (and not really done), we currently accept this issue.
* rgerhards, 2009-06-29
*/
- if(!(Debug || NoFork)) {
+ if(!(Debug == DEBUG_FULL || NoFork)) {
close(1);
close(2);
bErrMsgToStderr = 0;
@@ -3075,7 +3109,7 @@ doGlblProcessInit(void)
thrdInit();
- if( !(Debug || NoFork) )
+ if( !(Debug == DEBUG_FULL || NoFork) )
{
DBGPRINTF("Checking pidfile.\n");
if (!check_pid(PidFile))
@@ -3174,6 +3208,7 @@ int realMain(int argc, char **argv)
uchar *LocalHostName;
uchar *LocalDomain;
uchar *LocalFQDNName;
+ char cwdbuf[128]; /* buffer to obtain/display current working directory */
/* first, parse the command line options. We do not carry out any actual work, just
* see what we should do. This relieves us from certain anomalies and we can process
@@ -3260,8 +3295,9 @@ int realMain(int argc, char **argv)
if ((argc -= optind))
usage();
- DBGPRINTF("rsyslogd %s startup, compatibility mode %d, module path '%s'\n",
- VERSION, iCompatibilityMode, glblModPath == NULL ? "" : (char*)glblModPath);
+ DBGPRINTF("rsyslogd %s startup, compatibility mode %d, module path '%s', cwd:%s\n",
+ VERSION, iCompatibilityMode, glblModPath == NULL ? "" : (char*)glblModPath,
+ getcwd(cwdbuf, sizeof(cwdbuf)));
/* we are done with the initial option parsing and processing. Now we init the system. */