summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2012-03-15 13:34:05 +0100
committerMichael Biebl <biebl@debian.org>2012-03-15 13:34:05 +0100
commitc1860fd74db97b8311e5d8f018ded8145fb0b0f5 (patch)
tree7119c56e0aedd8aeda0e4f84a761d79ede01a724
parent4b6db682f04b13a031bc48d240266b2fbd670ae7 (diff)
downloadrsyslog-c1860fd74db97b8311e5d8f018ded8145fb0b0f5.tar.gz
Imported Upstream version 5.8.9upstream/5.8.9
-rw-r--r--ChangeLog9
-rwxr-xr-xconfigure20
-rw-r--r--configure.ac2
-rw-r--r--doc/manual.html2
-rw-r--r--plugins/imuxsock/imuxsock.c5
-rw-r--r--runtime/queue.c10
-rw-r--r--runtime/queue.h2
-rw-r--r--runtime/statsobj.c36
-rw-r--r--runtime/statsobj.h55
-rw-r--r--runtime/wti.c2
-rw-r--r--runtime/wtp.c2
-rw-r--r--tools/Makefile.am3
-rw-r--r--tools/Makefile.in4
-rw-r--r--tools/recover_qi.pl207
14 files changed, 306 insertions, 53 deletions
diff --git a/ChangeLog b/ChangeLog
index 56a1277..98a1e28 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,13 @@
---------------------------------------------------------------------------
+Version 5.8.9 [V5-stable] 2012-03-15
+- added tool to recover disk queue if .qi file is missing (recover_qi.pl)
+ Thanks to Kaiwang Chen for contributing this tool
+- bugfix: stopped DA queue was never processed after a restart due to a
+ regression from statistics module
+- added better doc for statsobj interface
+ Thanks to Kaiwang Chen for his suggestions and analysis in regard to the
+ stats subsystem.
+---------------------------------------------------------------------------
Version 5.8.8 [V5-stable] 2012-03-05
- bugfix: omprog made rsyslog abort on startup if not binary to
execute was configured
diff --git a/configure b/configure
index eb7b2de..8da684d 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.66 for rsyslog 5.8.8.
+# Generated by GNU Autoconf 2.66 for rsyslog 5.8.9.
#
# Report bugs to <rsyslog@lists.adiscon.com>.
#
@@ -562,8 +562,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='rsyslog'
PACKAGE_TARNAME='rsyslog'
-PACKAGE_VERSION='5.8.8'
-PACKAGE_STRING='rsyslog 5.8.8'
+PACKAGE_VERSION='5.8.9'
+PACKAGE_STRING='rsyslog 5.8.9'
PACKAGE_BUGREPORT='rsyslog@lists.adiscon.com'
PACKAGE_URL=''
@@ -1475,7 +1475,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures rsyslog 5.8.8 to adapt to many kinds of systems.
+\`configure' configures rsyslog 5.8.9 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1545,7 +1545,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of rsyslog 5.8.8:";;
+ short | recursive ) echo "Configuration of rsyslog 5.8.9:";;
esac
cat <<\_ACEOF
@@ -1720,7 +1720,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-rsyslog configure 5.8.8
+rsyslog configure 5.8.9
generated by GNU Autoconf 2.66
Copyright (C) 2010 Free Software Foundation, Inc.
@@ -2299,7 +2299,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by rsyslog $as_me 5.8.8, which was
+It was created by rsyslog $as_me 5.8.9, which was
generated by GNU Autoconf 2.66. Invocation command line was
$ $0 $@
@@ -3114,7 +3114,7 @@ fi
# Define the identity of the package.
PACKAGE='rsyslog'
- VERSION='5.8.8'
+ VERSION='5.8.9'
cat >>confdefs.h <<_ACEOF
@@ -17336,7 +17336,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by rsyslog $as_me 5.8.8, which was
+This file was extended by rsyslog $as_me 5.8.9, which was
generated by GNU Autoconf 2.66. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -17402,7 +17402,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-rsyslog config.status 5.8.8
+rsyslog config.status 5.8.9
configured by $0, generated by GNU Autoconf 2.66,
with options \\"\$ac_cs_config\\"
diff --git a/configure.ac b/configure.ac
index 3cb623d..1f72bcc 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],[5.8.8],[rsyslog@lists.adiscon.com])
+AC_INIT([rsyslog],[5.8.9],[rsyslog@lists.adiscon.com])
AM_INIT_AUTOMAKE
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
diff --git a/doc/manual.html b/doc/manual.html
index 54a04f8..690143d 100644
--- a/doc/manual.html
+++ b/doc/manual.html
@@ -19,7 +19,7 @@ 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 5.8.8 (v5-stable branch) of rsyslog.</b>
+<p><b>This documentation is for version 5.8.9 (v5-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><p><b>If you like rsyslog, you might
diff --git a/plugins/imuxsock/imuxsock.c b/plugins/imuxsock/imuxsock.c
index 4523798..5867f1c 100644
--- a/plugins/imuxsock/imuxsock.c
+++ b/plugins/imuxsock/imuxsock.c
@@ -784,7 +784,7 @@ CODESTARTwillRun
else if(sd_booted()) {
struct stat st;
if(stat(SYSTEMD_JOURNAL, &st) != -1 && S_ISDIR(st.st_mode)) {
- listeners[0].sockName = SYSTEMD_PATH_LOG;
+ listeners[0].sockName = (uchar*) SYSTEMD_PATH_LOG;
}
}
if(ratelimitIntervalSysSock > 0) {
@@ -1010,10 +1010,13 @@ CODEmodInit_QueryRegCFSLineHdlr
/* support statistics gathering */
CHKiRet(statsobj.Construct(&modStats));
CHKiRet(statsobj.SetName(modStats, UCHAR_CONSTANT("imuxsock")));
+ STATSCOUNTER_INIT(ctrSubmit, mutCtrSubmit);
CHKiRet(statsobj.AddCounter(modStats, UCHAR_CONSTANT("submitted"),
ctrType_IntCtr, &ctrSubmit));
+ STATSCOUNTER_INIT(ctrLostRatelimit, mutCtrLostRatelimit);
CHKiRet(statsobj.AddCounter(modStats, UCHAR_CONSTANT("ratelimit.discarded"),
ctrType_IntCtr, &ctrLostRatelimit));
+ STATSCOUNTER_INIT(ctrNumRatelimiters, mutCtrNumRatelimiters);
CHKiRet(statsobj.AddCounter(modStats, UCHAR_CONSTANT("ratelimit.numratelimiters"),
ctrType_IntCtr, &ctrNumRatelimiters));
CHKiRet(statsobj.ConstructFinalize(modStats));
diff --git a/runtime/queue.c b/runtime/queue.c
index 9012abe..621a4ee 100644
--- a/runtime/queue.c
+++ b/runtime/queue.c
@@ -1787,7 +1787,8 @@ qqueueChkStopWrkrDA(qqueue_t *pThis)
{
DEFiRet;
-//DBGPRINTF("XXXX: chkStopWrkrDA called, low watermark %d, phys Size %d\n", pThis->iLowWtrMrk, getPhysicalQueueSize(pThis));
+ /*DBGPRINTF("XXXX: chkStopWrkrDA called, low watermark %d, log Size %d, phys Size %d, bEnqOnly %d\n",
+ pThis->iLowWtrMrk, getLogicalQueueSize(pThis), getPhysicalQueueSize(pThis), pThis->bEnqOnly);*/
if(pThis->bEnqOnly) {
iRet = RS_RET_TERMINATE_WHEN_IDLE;
}
@@ -1808,6 +1809,8 @@ static rsRetVal
ChkStopWrkrReg(qqueue_t *pThis)
{
DEFiRet;
+ /*DBGPRINTF("XXXX: chkStopWrkrReg called, low watermark %d, log Size %d, phys Size %d, bEnqOnly %d\n",
+ pThis->iLowWtrMrk, getLogicalQueueSize(pThis), getPhysicalQueueSize(pThis), pThis->bEnqOnly);*/
if(pThis->bEnqOnly) {
iRet = RS_RET_TERMINATE_NOW;
} else if(pThis->pqParent != NULL) {
@@ -1844,6 +1847,7 @@ qqueueStart(qqueue_t *pThis) /* this is the ConstructionFinalizer */
int wrk;
uchar *qName;
size_t lenBuf;
+ int iQueueSizeSave;
ASSERT(pThis != NULL);
@@ -1925,6 +1929,8 @@ qqueueStart(qqueue_t *pThis) /* this is the ConstructionFinalizer */
qName = obj.GetName((obj_t*)pThis);
CHKiRet(statsobj.Construct(&pThis->statsobj));
CHKiRet(statsobj.SetName(pThis->statsobj, qName));
+ /* we need to save the queue size, as the stats module initializes it to 0! */
+ /* iQueueSize is a dual-use counter: no init, no mutex! */
CHKiRet(statsobj.AddCounter(pThis->statsobj, UCHAR_CONSTANT("size"),
ctrType_Int, &pThis->iQueueSize));
@@ -1936,7 +1942,7 @@ qqueueStart(qqueue_t *pThis) /* this is the ConstructionFinalizer */
CHKiRet(statsobj.AddCounter(pThis->statsobj, UCHAR_CONSTANT("full"),
ctrType_IntCtr, &pThis->ctrFull));
- pThis->ctrMaxqsize = 0;
+ pThis->ctrMaxqsize = 0; /* no mutex needed, thus no init call */
CHKiRet(statsobj.AddCounter(pThis->statsobj, UCHAR_CONSTANT("maxqsize"),
ctrType_Int, &pThis->ctrMaxqsize));
diff --git a/runtime/queue.h b/runtime/queue.h
index 9705718..7ef5673 100644
--- a/runtime/queue.h
+++ b/runtime/queue.h
@@ -169,7 +169,7 @@ struct queue_s {
statsobj_t *statsobj;
STATSCOUNTER_DEF(ctrEnqueued, mutCtrEnqueued);
STATSCOUNTER_DEF(ctrFull, mutCtrFull);
- int ctrMaxqsize;
+ int ctrMaxqsize; /* NOT guarded by a mutex */
};
diff --git a/runtime/statsobj.c b/runtime/statsobj.c
index 131605e..367ddb1 100644
--- a/runtime/statsobj.c
+++ b/runtime/statsobj.c
@@ -3,25 +3,23 @@
* This object provides a statistics-gathering facility inside rsyslog. This
* functionality will be pragmatically implemented and extended.
*
- * Copyright 2010 Rainer Gerhards and Adiscon GmbH.
+ * Copyright 2010-2012 Adiscon GmbH.
*
* This file is part of the rsyslog runtime library.
*
- * The rsyslog runtime library is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * The rsyslog runtime library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with the rsyslog runtime library. If not, see <http://www.gnu.org/licenses/>.
- *
- * 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.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * -or-
+ * see COPYING.ASL20 in the source distribution
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
#include "config.h"
@@ -139,6 +137,10 @@ finalize_it:
/* add a counter to an object
* ctrName is duplicated, caller must free it if requried
+ * NOTE: The counter is READ-ONLY and MUST NOT be modified (most
+ * importantly, it must not be initialized, so the caller must
+ * ensure the counter is properly initialized before AddCounter()
+ * is called.
*/
static rsRetVal
addCounter(statsobj_t *pThis, uchar *ctrName, statsCtrType_t ctrType, void *pCtr)
@@ -154,11 +156,9 @@ addCounter(statsobj_t *pThis, uchar *ctrName, statsCtrType_t ctrType, void *pCtr
switch(ctrType) {
case ctrType_IntCtr:
ctr->val.pIntCtr = (intctr_t*) pCtr;
- *(ctr->val.pIntCtr) = 0;
break;
case ctrType_Int:
ctr->val.pInt = (int*) pCtr;
- *(ctr->val.pInt) = 0;
break;
}
addCtrToList(pThis, ctr);
diff --git a/runtime/statsobj.h b/runtime/statsobj.h
index 44c26be..9027988 100644
--- a/runtime/statsobj.h
+++ b/runtime/statsobj.h
@@ -1,24 +1,22 @@
/* The statsobj object.
*
- * Copyright 2010 Rainer Gerhards and Adiscon GmbH.
+ * Copyright 2010-2012 Rainer Gerhards and Adiscon GmbH.
*
* This file is part of the rsyslog runtime library.
*
- * The rsyslog runtime library is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * The rsyslog runtime library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with the rsyslog runtime library. If not, see <http://www.gnu.org/licenses/>.
- *
- * 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.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * -or-
+ * see COPYING.ASL20 in the source distribution
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
#ifndef INCLUDED_STATSOBJ_H
#define INCLUDED_STATSOBJ_H
@@ -96,6 +94,31 @@ PROTOTYPEObj(statsobj);
* Unfortunately, this does not work if counter is e.g. "pThis->ctr".
* So we decided, for clarity, to always insist on specifying the mutex
* name (after all, it's just a few more keystrokes...).
+ * --------------------------------------------------------------------
+ * NOTE WELL
+ * --------------------------------------------------------------------
+ * There are actually two types of stats counters: "regular" counters,
+ * which are only used for stats purposes and "dual" counters, which
+ * are primarily used for other purposes but can be included in stats
+ * as well. ALL regular counters MUST be initialized with
+ * STATSCOUNTER_INIT and only be modified by STATSCOUNTER_* functions.
+ * They MUST NOT be used for any other purpose (if this seems to make
+ * sense, consider changing it to a dual counter).
+ * Dual counters are somewhat dangerous in that a single variable is
+ * used for two purposes: the actual application need and stats
+ * counting. However, this is supported for performance reasons, as it
+ * provides insight into the inner engine workings without need for
+ * additional counters (and their maintenance code). Dual counters
+ * MUST NOT be modified by STATSCOUNTER_* functions. Most importantly,
+ * it is expected that the actua application code provides proper
+ * (enough) synchronized access to these counters. Most importantly,
+ * this means they have NO stats-system mutex associated to them.
+ *
+ * The interface function AddCounter() is a read-only function. It
+ * only provides the stats subsystem with a reference to a counter.
+ * It is irrelevant if the counter is a regular or dual one. For that
+ * reason, AddCounter() must not modify the counter contents, as in
+ * the case of a dual counter application code may be broken.
*/
#define STATSCOUNTER_DEF(ctr, mut) \
intctr_t ctr; \
diff --git a/runtime/wti.c b/runtime/wti.c
index 0b85c36..69da2e9 100644
--- a/runtime/wti.c
+++ b/runtime/wti.c
@@ -315,6 +315,8 @@ wtiWorker(wti_t *pThis)
if(localRet == RS_RET_IDLE) {
if(terminateRet == RS_RET_TERMINATE_WHEN_IDLE || bInactivityTOOccured) {
d_pthread_mutex_unlock(pWtp->pmutUsr);
+ dbgoprint((obj_t*) pThis, "terminating worker terminateRet=%d, bInactivityTOOccured=%d\n",
+ terminateRet, bInactivityTOOccured);
break; /* end of loop */
}
doIdleProcessing(pThis, pWtp, &bInactivityTOOccured);
diff --git a/runtime/wtp.c b/runtime/wtp.c
index e615fb1..a53a988 100644
--- a/runtime/wtp.c
+++ b/runtime/wtp.c
@@ -309,7 +309,7 @@ wtpWrkrExecCleanup(wti_t *pWti)
wtiSetState(pWti, WRKTHRD_STOPPED);
ATOMIC_DEC(&pThis->iCurNumWrkThrd, &pThis->mutCurNumWrkThrd);
- DBGPRINTF("%s: Worker thread %lx, terminated, um workers now %d\n",
+ DBGPRINTF("%s: Worker thread %lx, terminated, num workers now %d\n",
wtpGetDbgHdr(pThis), (unsigned long) pWti,
ATOMIC_FETCH_32BIT(&pThis->iCurNumWrkThrd, &pThis->mutCurNumWrkThrd));
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 96657ad..962ae50 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -47,4 +47,5 @@ zpipe_LDADD = -lz
msggen_SOURCES = msggen.c
endif
-EXTRA_DIST = $(man_MANS)
+EXTRA_DIST = $(man_MANS) \
+ recover_qi.pl
diff --git a/tools/Makefile.in b/tools/Makefile.in
index b4532e4..5faadd4 100644
--- a/tools/Makefile.in
+++ b/tools/Makefile.in
@@ -336,7 +336,9 @@ rsyslogd_LDFLAGS = -export-dynamic
@ENABLE_DIAGTOOLS_TRUE@zpipe_SOURCES = zpipe.c
@ENABLE_DIAGTOOLS_TRUE@zpipe_LDADD = -lz
@ENABLE_DIAGTOOLS_TRUE@msggen_SOURCES = msggen.c
-EXTRA_DIST = $(man_MANS)
+EXTRA_DIST = $(man_MANS) \
+ recover_qi.pl
+
all: all-am
.SUFFIXES:
diff --git a/tools/recover_qi.pl b/tools/recover_qi.pl
new file mode 100644
index 0000000..4e2cf9d
--- /dev/null
+++ b/tools/recover_qi.pl
@@ -0,0 +1,207 @@
+#!/usr/bin/perl -w
+# recover rsyslog disk queue index (.qi) from queue files (.nnnnnnnn).
+#
+# See:
+# runtime/queue.c: qqueuePersist()
+# runtime/queue.c: qqueueTryLoadPersistedInfo()
+#
+# kaiwang.chen@gmail.com 2012-03-14
+#
+use strict;
+use Getopt::Long;
+
+my %opt = ();
+GetOptions(\%opt,"spool|w=s","basename|f=s","digits|d=i","help!");
+if ($opt{help}) {
+ print "Usage:
+\t$0 -w WorkDirectory -f QueueFileName -d 8 > QueueFileName.qi
+";
+ exit;
+}
+
+# runtime/queue.c: qConstructDisk()
+my $iMaxFiles = 10000000; # 0+"1".( "0"x($opt{digits} - 1));
+
+# get the list of queue files, spool directory excluded
+my $re = qr/^\Q$opt{basename}\E\.\d{$opt{digits}}$/;
+opendir(DIR, $opt{spool}) or die "can’t open spool: $!";
+my @qf = grep { /$re/ && -f "$opt{spool}/$_" } readdir(DIR);
+closedir DIR;
+
+# ensure order and continuity
+@qf = sort @qf;
+my ($head) = ($qf[0] =~ /(\d+)$/);
+my ($tail) = ($qf[-1] =~ /(\d+)$/);
+$head += 0;
+$tail += 0;
+if ($tail-$head+1 != @qf || $tail > $iMaxFiles) {
+ die "broken queue: missing file(s) or wrong tail\n";
+}
+
+# collect some counters about the queue, assuming all are unprocessed entries.
+my $sizeOnDisk = 0;
+my $iQueueSize = 0;
+chdir($opt{spool}) or die "can't chdir to spool: $!";
+print STDERR "traversing ". @qf ." files, please wait...\n";
+for (@qf) {
+ open FH, "<", $_ or die "can't read queue file $_\n";
+ $sizeOnDisk += (stat FH)[7];
+ while (<FH>) {
+ $iQueueSize++ if /^<Obj/; # runtime/msg.c: MsgSerialize()
+ }
+ close FH;
+}
+# happen to reuse last stat
+my $iCurrOffs_Write = (stat(_))[7];
+
+# runtime/queue.c: qqueuePersist()
+my $qqueue = Rsyslog::OPB->new("qqueue",1);
+$qqueue->property("iQueueSize", "INT", $iQueueSize);
+$qqueue->property("tVars.disk.sizeOnDisk", "INT64", $sizeOnDisk);
+$qqueue->property("tVars.disk.bytesRead", "INT64", 0);
+
+# runtime/stream.h: strmType_t
+my $STREAMTYPE_FILE_CIRCULAR = 1;
+# runtime/stream.h: strmMode_t
+my $STREAMMODE_READ = 1;
+my $STREAMMODE_WRITE_APPEND = 4;
+
+# runtime/stream.c: strmSerialize()
+# write to end
+my $strm_Write = Rsyslog::Obj->new("strm",1);
+$strm_Write->property( "iCurrFNum", "INT", $tail);
+$strm_Write->property( "pszFName", "PSZ", $opt{basename});
+$strm_Write->property( "iMaxFiles", "INT", $iMaxFiles);
+$strm_Write->property( "bDeleteOnClose", "INT", 0);
+$strm_Write->property( "sType", "INT", $STREAMTYPE_FILE_CIRCULAR);
+$strm_Write->property("tOperationsMode", "INT", $STREAMMODE_WRITE_APPEND);
+$strm_Write->property( "tOpenMode", "INT", 0600);
+$strm_Write->property( "iCurrOffs","INT64", $iCurrOffs_Write);
+# read from head
+my $strm_ReadDel = Rsyslog::Obj->new("strm",1);
+$strm_ReadDel->property( "iCurrFNum", "INT", $head);
+$strm_ReadDel->property( "pszFName", "PSZ", $opt{basename});
+$strm_ReadDel->property( "iMaxFiles", "INT", $iMaxFiles);
+$strm_ReadDel->property( "bDeleteOnClose", "INT", 1);
+$strm_ReadDel->property( "sType", "INT", $STREAMTYPE_FILE_CIRCULAR);
+$strm_ReadDel->property("tOperationsMode", "INT", $STREAMMODE_READ);
+$strm_ReadDel->property( "tOpenMode", "INT", 0600);
+$strm_ReadDel->property( "iCurrOffs","INT64", 0);
+
+# .qi
+print $qqueue->serialize();
+print $strm_Write->serialize();
+print $strm_ReadDel->serialize();
+
+exit;
+#-----------------------------------------------------------------------------
+
+package Rsyslog::Serializable;
+# runtime/obj.c
+sub COOKIE_OBJLINE { '<' }
+sub COOKIE_PROPLINE { '+' }
+sub COOKIE_ENDLINE { '>' }
+sub COOKIE_BLANKLINE { '.' }
+# VARTYPE(short_ptype)
+sub VARTYPE {
+ my ($t) = @_;
+ # runtime/obj-types.h: propType_t
+ my $ptype = "PROPTYPE_".$t;
+ # runtime/var.h: varType_t
+ my %vm = (
+ VARTYPE_NONE => 0,
+ VARTYPE_STR => 1,
+ VARTYPE_NUMBER => 2,
+ VARTYPE_SYSLOGTIME => 3,
+ );
+ # runtime/obj.c: SerializeProp()
+ my %p2v = (
+ #PROPTYPE_NONE => "",
+ PROPTYPE_PSZ => "VARTYPE_STR",
+ PROPTYPE_SHORT => "VARTYPE_NUMBER",
+ PROPTYPE_INT => "VARTYPE_NUMBER",
+ PROPTYPE_LONG => "VARTYPE_NUMBER",
+ PROPTYPE_INT64 => "VARTYPE_NUMBER",
+ PROPTYPE_CSTR => "VARTYPE_STR",
+ #PROPTYPE_SYSLOGTIME => "VARTYPE_SYSLOGTIME",
+ );
+ my $vtype = $p2v{$ptype};
+ unless ($vtype) {
+ die "property type $t is not supported!\n";
+ }
+ return $vm{$vtype};
+}
+sub serialize {
+ my $self = shift;
+ # runtime/obj.c: objSerializeHeader()
+ my $x = COOKIE_OBJLINE();
+ $x .= join(":", $self->type(), $self->cver(), $self->id(), $self->version());
+ $x .= ":\n";
+ for ( values %{$self->{props}} ) {
+ # runtime/obj.c: SerializeProp()
+ $x .= COOKIE_PROPLINE();
+ $x .= join(":",
+ $_->{name},
+ VARTYPE($_->{type}),
+ length($_->{value}),
+ $_->{value});
+ $x .= ":\n";
+ }
+ # runtime/obj.c: EndSerialize()
+ $x .= COOKIE_ENDLINE() . "End\n";
+ $x .= COOKIE_BLANKLINE() . "\n";
+}
+# constructor: new(id,version)
+sub new {
+ my ($class, $id, $version) = @_;
+ $class = ref $class if ref $class;
+ bless {
+ id => $id,
+ version => $version,
+ props => {},
+ }, $class;
+}
+sub id {
+ my $self = shift;
+ if (@_) {
+ my $x = $self->{id};
+ $self->{id} = shift;
+ return $x;
+ }
+ return $self->{id};
+}
+sub version {
+ my $self = shift;
+ if (@_) {
+ my $x = $self->{version};
+ $self->{version} = shift;
+ return $x;
+ }
+ return $self->{version};
+}
+# property(name, type, value)
+sub property {
+ my $self = shift;
+ my $name = shift;
+ if (@_) {
+ my $x = $self->{props}{$name};
+ $self->{props}{$name}{name} = $name;
+ $self->{props}{$name}{type} = shift;
+ $self->{props}{$name}{value} = shift;
+ return $x;
+ }
+ return $self->{props}{$name};
+}
+1;
+package Rsyslog::OPB;
+use base qw(Rsyslog::Serializable);
+sub type { 'OPB' }
+sub cver { 1 }
+sub new { shift->SUPER::new(@_) }
+1;
+package Rsyslog::Obj;
+use base qw(Rsyslog::Serializable);
+sub type { 'Obj' }
+sub cver { 1 }
+sub new { shift->SUPER::new(@_) }
+1;