From 2a494ffc41cd33124bbfea01ad41750b8967efed Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 2 Mar 2010 10:18:33 +0100 Subject: added include needed for Solaris --- tools/ompipe.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/ompipe.c b/tools/ompipe.c index 5fb9b27e..7cf61822 100644 --- a/tools/ompipe.c +++ b/tools/ompipe.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include "syslogd.h" -- cgit v1.2.3 From 396e211e5cfd195b7135947d425b089a0447fa88 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 5 Mar 2010 08:27:26 +0100 Subject: enabled compilation by using "racy" replacements for atomic instructions ... but this is not considered a real solution. For some of the uses, it may acutally be sufficient, but the implications need to be analyzed in detail. --- runtime/atomic.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/runtime/atomic.h b/runtime/atomic.h index d5aaf56b..62ceb8b3 100644 --- a/runtime/atomic.h +++ b/runtime/atomic.h @@ -66,6 +66,9 @@ # define ATOMIC_DEC_AND_FETCH(data) (--(data)) # define ATOMIC_FETCH_32BIT(data) (data) # define ATOMIC_STORE_1_TO_32BIT(data) (data) = 1 +# define ATOMIC_STORE_1_TO_INT(data) (data) = 1 +# define ATOMIC_STORE_0_TO_INT(data) (data) = 0 +# define ATOMIC_CAS_VAL(data, oldVal, newVal) (data) = (newVal) #endif #endif /* #ifndef INCLUDED_ATOMIC_H */ -- cgit v1.2.3 From e0afe5c8258d4b70ade84f1176c44ae6d593f2df Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 23 Mar 2010 08:03:21 +0100 Subject: added some diagnostics info to startup --- tests/diag.sh | 4 ++-- tools/syslogd.c | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/diag.sh b/tests/diag.sh index 27b60582..08e94548 100755 --- a/tests/diag.sh +++ b/tests/diag.sh @@ -37,8 +37,8 @@ case $1 in ;; 'wait-startup') # wait for rsyslogd startup ($2 is the instance) while test ! -f rsyslogd$2.started; do - #true - sleep 0.1 # if this is not supported by all platforms, use above! + true + #sleep 0.1 # if this is not supported by all platforms, use above! done echo "rsyslogd$2 started with pid " `cat rsyslog$2.pid` ;; diff --git a/tools/syslogd.c b/tools/syslogd.c index 64b23566..a61d1e5d 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -3174,6 +3174,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 +3261,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. */ -- cgit v1.2.3 From 072fc663a83b2050d961d1c7ec7aa16f12842c9a Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 23 Mar 2010 15:04:24 +0100 Subject: added replacements for atomic instructions on systems that do not support them. [backport of Stefen Sledz' patch for v5] --- ChangeLog | 2 + configure.ac | 4 ++ runtime/Makefile.am | 1 + runtime/atomic.h | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++ runtime/rsyslog.c | 14 +++++++ 5 files changed, 138 insertions(+) diff --git a/ChangeLog b/ChangeLog index dc12e856..b8deeb74 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,8 @@ Version 4.6.2 [v4-stable] (rgerhards), 2010-03-?? - 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) - added new property replacer option "date-rfc3164-buggyday" primarily to ease migration from syslog-ng. See property replacer doc for details. [backport from 5.5.3 because urgently needed by some] diff --git a/configure.ac b/configure.ac index b059fe75..fcd70c30 100644 --- a/configure.ac +++ b/configure.ac @@ -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, diff --git a/runtime/Makefile.am b/runtime/Makefile.am index 14abe722..e5b3ccdf 100644 --- a/runtime/Makefile.am +++ b/runtime/Makefile.am @@ -9,6 +9,7 @@ librsyslog_la_SOURCES = \ rsyslog.h \ unicode-helper.h \ atomic.h \ + atomic-posix-sem.c \ syslogd-types.h \ module-template.h \ obj-types.h \ diff --git a/runtime/atomic.h b/runtime/atomic.h index 62ceb8b3..ea3be37a 100644 --- a/runtime/atomic.h +++ b/runtime/atomic.h @@ -53,6 +53,122 @@ # 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)); #else +#ifdef HAVE_SEMAPHORE_H + /* we use POSIX semaphores instead */ + +#include "rsyslog.h" +#include + +extern sem_t atomicSem; +rsRetVal atomicSemInit(void); +void atomicSemExit(void); + +#if HAVE_TYPEOF +#define my_typeof(x) typeof(x) +#else /* sorry, can't determine types, using 'int' */ +#define my_typeof(x) int +#endif + +# define ATOMIC_SUB(data, val) \ +({ \ + my_typeof(data) tmp; \ + sem_wait(&atomicSem); \ + tmp = data; \ + data -= val; \ + sem_post(&atomicSem); \ + tmp; \ +}) + +# define ATOMIC_ADD(data, val) \ +({ \ + my_typeof(data) tmp; \ + sem_wait(&atomicSem); \ + tmp = data; \ + data += val; \ + sem_post(&atomicSem); \ + tmp; \ +}) + +# define ATOMIC_INC_AND_FETCH(data) \ +({ \ + my_typeof(data) tmp; \ + sem_wait(&atomicSem); \ + tmp = data; \ + data += 1; \ + sem_post(&atomicSem); \ + tmp; \ +}) + +# define ATOMIC_INC(data) ((void) ATOMIC_INC_AND_FETCH(data)) + +# define ATOMIC_DEC_AND_FETCH(data) \ +({ \ + sem_wait(&atomicSem); \ + data -= 1; \ + sem_post(&atomicSem); \ + data; \ +}) + +# define ATOMIC_DEC(data) ((void) ATOMIC_DEC_AND_FETCH(data)) + +# define ATOMIC_FETCH_32BIT(data) ((unsigned) ATOMIC_ADD((data), 0xffffffff)) + +# define ATOMIC_STORE_1_TO_32BIT(data) \ +({ \ + my_typeof(data) tmp; \ + sem_wait(&atomicSem); \ + tmp = data; \ + data = 1; \ + sem_post(&atomicSem); \ + tmp; \ +}) + +# define ATOMIC_STORE_0_TO_INT(data) \ +({ \ + my_typeof(data) tmp; \ + sem_wait(&atomicSem); \ + tmp = data; \ + data = 0; \ + sem_post(&atomicSem); \ + tmp; \ +}) + +# define ATOMIC_STORE_1_TO_INT(data) \ +({ \ + my_typeof(data) tmp; \ + sem_wait(&atomicSem); \ + tmp = data; \ + data = 1; \ + sem_post(&atomicSem); \ + tmp; \ +}) + +# define ATOMIC_CAS(data, oldVal, newVal) \ +({ \ + int ret; \ + sem_wait(&atomicSem); \ + if(data != oldVal) ret = 0; \ + else \ + { \ + data = newVal; \ + ret = 1; \ + } \ + sem_post(&atomicSem); \ + ret; \ +}) + +# define ATOMIC_CAS_VAL(data, oldVal, newVal) \ +({ \ + sem_wait(&atomicSem); \ + if(data == oldVal) \ + { \ + data = newVal; \ + } \ + sem_post(&atomicSem); \ + data; \ +}) + +#else /* not HAVE_SEMAPHORE_H */ /* note that we gained parctical proof that theoretical problems DO occur * if we do not properly address them. See this blog post for details: * http://blog.gerhards.net/2009/01/rsyslog-data-race-analysis.html @@ -70,5 +186,6 @@ # define ATOMIC_STORE_0_TO_INT(data) (data) = 0 # define ATOMIC_CAS_VAL(data, oldVal, newVal) (data) = (newVal) #endif +#endif #endif /* #ifndef INCLUDED_ATOMIC_H */ diff --git a/runtime/rsyslog.c b/runtime/rsyslog.c index 443d0f41..5750ca76 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); @@ -139,6 +140,12 @@ rsrtInit(char **ppErrObj, obj_if_t *pObjIF) CHKiRet(objClassInit(NULL)); /* *THIS* *MUST* always be the first class initilizer being called! */ CHKiRet(objGetObjInterface(pObjIF)); /* this provides the root pointer for all other queries */ +#ifndef HAVE_ATOMIC_BUILTINS +#ifdef HAVE_SEMAPHORE_H + CHKiRet(atomicSemInit()); +#endif /* HAVE_SEMAPHORE_H */ +#endif /* !defined(HAVE_ATOMIC_BUILTINS) */ + /* initialize core classes. We must be very careful with the order of events. Some * classes use others and if we do not initialize them in the right order, we may end * up with an invalid call. The most important thing that can happen is that an error @@ -215,6 +222,13 @@ rsrtExit(void) glblClassExit(); rulesetClassExit(); ruleClassExit(); + +#ifndef HAVE_ATOMIC_BUILTINS +#ifdef HAVE_SEMAPHORE_H + atomicSemExit(); +#endif /* HAVE_SEMAPHORE_H */ +#endif /* !defined(HAVE_ATOMIC_BUILTINS) */ + objClassExit(); /* *THIS* *MUST/SHOULD?* always be the first class initilizer being called (except debug)! */ } -- cgit v1.2.3 From 2f8b5cafd0dcc5f09b7b64f5015a2aebd1c7b31c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 23 Mar 2010 15:05:34 +0100 Subject: forgot to add file with last commit --- runtime/atomic-posix-sem.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 runtime/atomic-posix-sem.c diff --git a/runtime/atomic-posix-sem.c b/runtime/atomic-posix-sem.c new file mode 100644 index 00000000..979fae02 --- /dev/null +++ b/runtime/atomic-posix-sem.c @@ -0,0 +1,70 @@ +/* atomic_posix_sem.c: This file supplies an emulation for atomic operations using + * POSIX semaphores. + * + * Copyright 2010 DResearch Digital Media Systems 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 . + * + * 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" +#ifndef HAVE_ATOMIC_BUILTINS +#ifdef HAVE_SEMAPHORE_H +#include +#include + +#include "atomic.h" +#include "rsyslog.h" +#include "srUtils.h" + +sem_t atomicSem; + +rsRetVal +atomicSemInit(void) +{ + DEFiRet; + + dbgprintf("init posix semaphore for atomics emulation\n"); + if(sem_init(&atomicSem, 0, 1) == -1) + { + char errStr[1024]; + rs_strerror_r(errno, errStr, sizeof(errStr)); + dbgprintf("init posix semaphore for atomics emulation failed: %s\n", errStr); + iRet = RS_RET_SYS_ERR; /* the right error code ??? */ + } + + RETiRet; +} + +void +atomicSemExit(void) +{ + dbgprintf("destroy posix semaphore for atomics emulation\n"); + if(sem_destroy(&atomicSem) == -1) + { + char errStr[1024]; + rs_strerror_r(errno, errStr, sizeof(errStr)); + dbgprintf("destroy posix semaphore for atomics emulation failed: %s\n", errStr); + } +} + +#endif /* HAVE_SEMAPHORE_H */ +#endif /* !defined(HAVE_ATOMIC_BUILTINS) */ + +/* vim:set ai: + */ -- cgit v1.2.3 From 5deea302b0c594b267e0450bdbb82954d2459a61 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 25 Mar 2010 09:35:49 +0100 Subject: replaced sleep in test suite by a small self-crafted tool subsecond sleep did not work on all platforms --- tests/Makefile.am | 3 ++- tests/diag.sh | 6 ++---- tests/msleep.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 tests/msleep.c diff --git a/tests/Makefile.am b/tests/Makefile.am index 9e04ea1e..2a4213f8 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,6 +1,6 @@ if ENABLE_TESTBENCH TESTRUNS = rt_init rscript -check_PROGRAMS = $(TESTRUNS) ourtail nettester tcpflood chkseq +check_PROGRAMS = $(TESTRUNS) ourtail nettester tcpflood chkseq msleep TESTS = $(TESTRUNS) cfg.sh \ validation-run.sh \ imtcp-multiport.sh \ @@ -193,6 +193,7 @@ EXTRA_DIST= 1.rstest 2.rstest 3.rstest err1.rstest \ cfg.sh ourtail_SOURCES = ourtail.c +msleep_SOURCES = msleep.c chkseq_SOURCES = chkseq.c tcpflood_SOURCES = tcpflood.c diff --git a/tests/diag.sh b/tests/diag.sh index 08e94548..173219da 100755 --- a/tests/diag.sh +++ b/tests/diag.sh @@ -37,16 +37,14 @@ case $1 in ;; 'wait-startup') # wait for rsyslogd startup ($2 is the instance) 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. diff --git a/tests/msleep.c b/tests/msleep.c new file mode 100644 index 00000000..6fa57b79 --- /dev/null +++ b/tests/msleep.c @@ -0,0 +1,50 @@ +/* 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 . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ +#include "config.h" +#include +#include + +int main(int argc, char *argv[]) +{ + struct timeval tvSelectTimeout; + long sleepTime; + + if(argc != 2) { + fprintf(stderr, "usage: msleep \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; +} + -- cgit v1.2.3 From bdb632e6d2ed6fe86f2f6d3163932e33fc2959a9 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 25 Mar 2010 10:12:36 +0100 Subject: added some instructions for building rsyslog on Solaris --- solaris/README | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 solaris/README diff --git a/solaris/README b/solaris/README new file mode 100644 index 00000000..0700642e --- /dev/null +++ b/solaris/README @@ -0,0 +1,34 @@ +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/usr/local/lib" +./configure AR=gar ...other options... + + +NOT YET SUPPORTED +* local log socket +* kernel log -- cgit v1.2.3 From 7e1060295a63242bc22394b6873de6e6db2b4765 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 25 Mar 2010 11:21:10 +0100 Subject: manytcp test tool must tell OS to provide enough file handles On some platforms, the default is too low to carry out all test cases --- tests/tcpflood.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/tcpflood.c b/tests/tcpflood.c index 32bf959d..259b84b3 100644 --- a/tests/tcpflood.c +++ b/tests/tcpflood.c @@ -370,6 +370,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(openConnections() != 0) { printf("error opening connections\n"); exit(1); -- cgit v1.2.3 From ec883905c13920de0bc33e5bdd0a75c80535b55c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 25 Mar 2010 14:58:23 +0100 Subject: testbench improved to run on Solaris --- tests/complex1.sh | 5 +++-- tests/diag.sh | 7 +++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/complex1.sh b/tests/complex1.sh index b5dc2c9d..7395bf21 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 2 # 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 173219da..383cd818 100755 --- a/tests/diag.sh +++ b/tests/diag.sh @@ -128,5 +128,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 -- cgit v1.2.3 From b628ec633ebd8bdf2e1ddb168b7b63ea2c1bb87c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 25 Mar 2010 17:21:36 +0100 Subject: added missing header --- tests/tcpflood.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/tcpflood.c b/tests/tcpflood.c index 259b84b3..68c1c097 100644 --- a/tests/tcpflood.c +++ b/tests/tcpflood.c @@ -54,6 +54,7 @@ #include #include #include +#include #define EXIT_FAILURE 1 #define INVALID_SOCKET -1 -- cgit v1.2.3 From 92369b253c302c7be30156b69b62f5ad90369cf0 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 25 Mar 2010 18:22:14 +0100 Subject: added some starting point for a solaris imklog driver ... far from being functional at this time! --- configure.ac | 1 + plugins/imklog/Makefile.am | 4 + plugins/imklog/solaris_cddl.c | 292 ++++++++++++++++++++++++++++++++++++++++++ solaris/cddllicense.txt | 242 ++++++++++++++++++++++++++++++++++ 4 files changed, 539 insertions(+) create mode 100644 plugins/imklog/solaris_cddl.c create mode 100644 solaris/cddllicense.txt diff --git a/configure.ac b/configure.ac index fcd70c30..c24468be 100644 --- a/configure.ac +++ b/configure.ac @@ -278,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) # diff --git a/plugins/imklog/Makefile.am b/plugins/imklog/Makefile.am index 5d4d0465..85305ce3 100644 --- a/plugins/imklog/Makefile.am +++ b/plugins/imklog/Makefile.am @@ -11,6 +11,10 @@ if ENABLE_IMKLOG_LINUX imklog_la_SOURCES += linux.c module.h ksym.c ksyms.h ksym_mod.c endif +if ENABLE_IMKLOG_SOLARIS +imklog_la_SOURCES += solaris_cddl.c +endif + imklog_la_CPPFLAGS = -I$(top_srcdir) $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) imklog_la_LDFLAGS = -module -avoid-version imklog_la_LIBADD = diff --git a/plugins/imklog/solaris_cddl.c b/plugins/imklog/solaris_cddl.c new file mode 100644 index 00000000..df783c46 --- /dev/null +++ b/plugins/imklog/solaris_cddl.c @@ -0,0 +1,292 @@ +/* + * 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" + + + +/* + * Attempts to open the local log device + * and return a file descriptor. + */ +int +sun_oopenklog(char *name, int mode) +{ + int fd; + struct strioctl str; + pthread_t mythreadno; + + if (Debug) { + mythreadno = pthread_self(); + } + + if ((fd = open(name, mode)) < 0) { + logerror("cannot open %s", name); + DPRINT3(1, "openklog(%u): cannot create %s (%d)\n", + mythreadno, 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) { + logerror("cannot register to log console messages"); + DPRINT2(1, "openklog(%u): cannot register to log " + "console messages (%d)\n", mythreadno, errno); + return (-1); + } + return (fd); +} + + +/* + * Open the log device, and pull up all pending messages. + */ +void +sun_prepare_sys_poll() +{ + int nfds, funix; + + if ((funix = openklog(LogName, O_RDONLY)) < 0) { + logerror("can't open kernel log device - fatal"); + exit(1); + } + + Pfd.fd = funix; + Pfd.events = POLLIN; + + for (;;) { + nfds = poll(&Pfd, 1, 0); + if (nfds <= 0) { + if (sys_init_msg_count > 0) + flushmsg(SYNC_FILE); + break; + } + + if (Pfd.revents & POLLIN) { + getkmsg(0); + } else if (Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) { + logerror("kernel log driver poll error"); + break; + } + } + +} + +/* + * 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(void *ap) +{ + int nfds; + static int klogerrs = 0; + pthread_t mythreadno; + + if (Debug) { + mythreadno = pthread_self(); + } + + DPRINT1(1, "sys_poll(%u): sys_thread started\n", mythreadno); + + /* + * Try to process as many messages as we can without blocking on poll. + * We count such "initial" messages with sys_init_msg_count and + * enqueue them without the SYNC_FILE flag. When no more data is + * waiting on the local log device, we set timeout to INFTIM, + * clear sys_init_msg_count, and generate a flush message to sync + * the previously counted initial messages out to disk. + */ + + sys_init_msg_count = 0; + + for (;;) { + errno = 0; + t_errno = 0; + + nfds = poll(&Pfd, 1, INFTIM); + + if (nfds == 0) + continue; + + if (nfds < 0) { + if (errno != EINTR) + logerror("poll"); + continue; + } + if (Pfd.revents & POLLIN) { + getkmsg(INFTIM); + } else { + if (shutting_down) { + pthread_exit(0); + } + if (Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) { + logerror("kernel log driver poll error"); + (void) close(Pfd.fd); + Pfd.fd = -1; + } + } + + while (Pfd.fd == -1 && klogerrs++ < 10) { + Pfd.fd = openklog(LogName, O_RDONLY); + } + if (klogerrs >= 10) { + logerror("can't reopen kernel log device - fatal"); + exit(1); + } + } + /*NOTREACHED*/ + return (NULL); +} + +/* + * Pull up one message from log driver. + */ +void +sun_getkmsg(int timeout) +{ + 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]; + pthread_t mythreadno; + + if (Debug) { + mythreadno = pthread_self(); + } + + 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'; + + DPRINT2(5, "sys_poll:(%u): getmsg: dat.len = %d\n", + mythreadno, dat.len); + buflen = strlen(buf); + len = findnl_bkwd(buf, buflen); + + (void) memcpy(tmpbuf, buf, len); + tmpbuf[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. + */ + if (timeout == 0) { + formatsys(&hdr, tmpbuf, 0); + sys_init_msg_count++; + } else { + formatsys(&hdr, tmpbuf, 1); + } + sys_msg_count++; + + 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. + */ + DPRINT2(5, "getkmsg(%u): getmsg: dat.maxlen = %d\n", + mythreadno, dat.maxlen); + DPRINT2(5, "getkmsg(%u): getmsg: dat.len = %d\n", + mythreadno, dat.len); + DPRINT2(5, "getkmsg(%u): getmsg: strlen(dat.buf) = %d\n", + mythreadno, strlen(dat.buf)); + DPRINT2(5, "getkmsg(%u): getmsg: dat.buf = \"%s\"\n", + mythreadno, dat.buf); + DPRINT2(5, "getkmsg(%u): buf len = %d\n", + mythreadno, strlen(buf)); + if (timeout == 0) { + formatsys(&hdr, buf, 0); + sys_init_msg_count++; + } else { + formatsys(&hdr, buf, 1); + } + sys_msg_count++; + } else if (i < 0 && errno != EINTR) { + if (!shutting_down) { + logerror("kernel log driver read error"); + } + (void) close(Pfd.fd); + Pfd.fd = -1; + } +} 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. + -- cgit v1.2.3 From da65d88017e1824fe60574fef1ef83f1932ab0a6 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 25 Mar 2010 18:36:27 +0100 Subject: added forgotten file --- plugins/imklog/solaris.c | 545 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 545 insertions(+) create mode 100644 plugins/imklog/solaris.c diff --git a/plugins/imklog/solaris.c b/plugins/imklog/solaris.c new file mode 100644 index 00000000..97aead22 --- /dev/null +++ b/plugins/imklog/solaris.c @@ -0,0 +1,545 @@ +/* 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 . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ +#include "config.h" +#include "rsyslog.h" +#include +#include +#include +#include +#include +#include +#include "cfsysline.h" +#include "template.h" +#include "msg.h" +#include "module-template.h" +#include "imklog.h" +#include "unicode-helper.h" + + +/* Includes. */ +#include +#include +#include +#include + +#if HAVE_TIME_H +# include +#endif + +#include +#include +#include "ksyms.h" + +#define __LIBRARY__ +#include + + +#if !defined(__GLIBC__) +# define __NR_ksyslog __NR_syslog +_syscall3(int,ksyslog,int, type, char *, buf, int, len); +#else +#include +#define ksyslog klogctl +#endif + + + +#ifndef _PATH_KLOG +#define _PATH_KLOG "/proc/kmsg" +#endif + +#define LOG_BUFFER_SIZE 4096 +#define LOG_LINE_LENGTH 1000 + +static int kmsg; +static char log_buffer[LOG_BUFFER_SIZE]; + +static enum LOGSRC {none, proc, kernel} logsrc; + + +/* Function prototypes. */ +extern int ksyslog(int type, char *buf, int len); + + +static uchar *GetPath(void) +{ + return pszPath ? pszPath : UCHAR_CONSTANT(_PATH_KLOG); +} + +static void CloseLogSrc(void) +{ + /* Turn on logging of messages to console, but only if a log level was speficied */ + if(console_log_level != -1) + ksyslog(7, NULL, 0); + + /* Shutdown the log sources. */ + switch(logsrc) { + case kernel: + ksyslog(0, NULL, 0); + imklogLogIntMsg(LOG_INFO, "Kernel logging (ksyslog) stopped."); + break; + case proc: + close(kmsg); + imklogLogIntMsg(LOG_INFO, "Kernel logging (proc) stopped."); + break; + case none: + break; + } + + return; +} + + +static enum LOGSRC GetKernelLogSrc(void) +{ + auto struct stat sb; + + /* Set level of kernel console messaging.. */ + if ( (console_log_level != -1) && + (ksyslog(8, NULL, console_log_level) < 0) && + (errno == EINVAL) ) + { + /* + * An invalid arguement error probably indicates that + * a pre-0.14 kernel is being run. At this point we + * issue an error message and simply shut-off console + * logging completely. + */ + imklogLogIntMsg(LOG_WARNING, "Cannot set console log level - disabling " + "console output."); + } + + /* + * First do a stat to determine whether or not the proc based + * file system is available to get kernel messages from. + */ + if ( use_syscall || + ((stat((char*)GetPath(), &sb) < 0) && (errno == ENOENT)) ) + { + /* Initialize kernel logging. */ + ksyslog(1, NULL, 0); + imklogLogIntMsg(LOG_INFO, "imklog %s, log source = ksyslog " + "started.", VERSION); + return(kernel); + } + + if ( (kmsg = open((char*)GetPath(), O_RDONLY|O_CLOEXEC)) < 0 ) + { + imklogLogIntMsg(LOG_ERR, "imklog: Cannot open proc file system, %d.\n", errno); + ksyslog(7, NULL, 0); + return(none); + } + + imklogLogIntMsg(LOG_INFO, "imklog %s, log source = %s started.", VERSION, GetPath()); + return(proc); +} + + +/* Copy characters from ptr to line until a char in the delim + * string is encountered or until min( space, len ) chars have + * been copied. + * + * Returns the actual number of chars copied. + */ +static int copyin( uchar *line, int space, + const char *ptr, int len, + const char *delim ) +{ + auto int i; + auto int count; + + count = len < space ? len : space; + + for(i=0; i]", + * where "aaaaaa" is the address. These are replaced with + * "[symbolname+offset/size]" in the output line - symbolname, + * offset, and size come from the kernel symbol table. + * + * If a kernel symbol happens to fall at the end of a message close + * in length to LOG_LINE_LENGTH, the symbol will not be expanded. + * (This should never happen, since the kernel should never generate + * messages that long. + * + * To preserve the original addresses, lines containing kernel symbols + * are output twice. Once with the symbols converted and again with the + * original text. Just in case somebody wants to run their own Oops + * analysis on the syslog, e.g. ksymoops. + */ +static void LogLine(char *ptr, int len) +{ + enum parse_state_enum { + PARSING_TEXT, + PARSING_SYMSTART, /* at < */ + PARSING_SYMBOL, + PARSING_SYMEND /* at ] */ + }; + + static uchar line_buff[LOG_LINE_LENGTH]; + + static uchar *line =line_buff; + static enum parse_state_enum parse_state = PARSING_TEXT; + static int space = sizeof(line_buff)-1; + + static uchar *sym_start; /* points at the '<' of a symbol */ + + auto int delta = 0; /* number of chars copied */ + auto int symbols_expanded = 0; /* 1 if symbols were expanded */ + auto int skip_symbol_lookup = 0; /* skip symbol lookup on this pass */ + auto char *save_ptr = ptr; /* save start of input line */ + auto int save_len = len; /* save length at start of input line */ + + while( len > 0 ) + { + if( space == 0 ) /* line buffer is full */ + { + /* + ** Line too long. Start a new line. + */ + *line = 0; /* force null terminator */ + + //dbgprintf("Line buffer full:\n"); + //dbgprintf("\tLine: %s\n", line); + + Syslog(LOG_INFO, line_buff); + line = line_buff; + space = sizeof(line_buff)-1; + parse_state = PARSING_TEXT; + symbols_expanded = 0; + skip_symbol_lookup = 0; + save_ptr = ptr; + save_len = len; + } + + switch( parse_state ) + { + case PARSING_TEXT: + delta = copyin(line, space, ptr, len, "\n[" ); + line += delta; + ptr += delta; + space -= delta; + len -= delta; + + if( space == 0 || len == 0 ) + { + break; /* full line_buff or end of input buffer */ + } + + if( *ptr == '\0' ) /* zero byte */ + { + ptr++; /* skip zero byte */ + space -= 1; + len -= 1; + + break; + } + + if( *ptr == '\n' ) /* newline */ + { + ptr++; /* skip newline */ + space -= 1; + len -= 1; + + *line = 0; /* force null terminator */ + Syslog(LOG_INFO, line_buff); + line = line_buff; + space = sizeof(line_buff)-1; + if (symbols_twice) { + if (symbols_expanded) { + /* reprint this line without symbol lookup */ + symbols_expanded = 0; + skip_symbol_lookup = 1; + ptr = save_ptr; + len = save_len; + } + else + { + skip_symbol_lookup = 0; + save_ptr = ptr; + save_len = len; + } + } + break; + } + if( *ptr == '[' ) /* possible kernel symbol */ + { + *line++ = *ptr++; + space -= 1; + len -= 1; + if (!skip_symbol_lookup) + parse_state = PARSING_SYMSTART; /* at < */ + break; + } + /* Now that line_buff is no longer fed to *printf as format + * string, '%'s are no longer "dangerous". + */ + break; + + case PARSING_SYMSTART: + if( *ptr != '<' ) + { + parse_state = PARSING_TEXT; /* not a symbol */ + break; + } + + /* + ** Save this character for now. If this turns out to + ** be a valid symbol, this char will be replaced later. + ** If not, we'll just leave it there. + */ + + sym_start = line; /* this will point at the '<' */ + + *line++ = *ptr++; + space -= 1; + len -= 1; + parse_state = PARSING_SYMBOL; /* symbol... */ + break; + + case PARSING_SYMBOL: + delta = copyin( line, space, ptr, len, ">\n[" ); + line += delta; + ptr += delta; + space -= delta; + len -= delta; + if( space == 0 || len == 0 ) + { + break; /* full line_buff or end of input buffer */ + } + if( *ptr != '>' ) + { + parse_state = PARSING_TEXT; + break; + } + + *line++ = *ptr++; /* copy the '>' */ + space -= 1; + len -= 1; + + parse_state = PARSING_SYMEND; + + break; + + case PARSING_SYMEND: + if( *ptr != ']' ) + { + parse_state = PARSING_TEXT; /* not a symbol */ + break; + } + + /* + ** It's really a symbol! Replace address with the + ** symbol text. + */ + { + auto int sym_space; + + unsigned long value; + auto struct symbol sym; + auto char *symbol; + + *(line-1) = 0; /* null terminate the address string */ + value = strtoul((char*)(sym_start+1), (char **) 0, 16); + *(line-1) = '>'; /* put back delim */ + + if ( !symbol_lookup || (symbol = LookupSymbol(value, &sym)) == (char *)0 ) + { + parse_state = PARSING_TEXT; + break; + } + + /* + ** verify there is room in the line buffer + */ + sym_space = space + ( line - sym_start ); + if( (unsigned) sym_space < strlen(symbol) + 30 ) /*(30 should be overkill)*/ + { + parse_state = PARSING_TEXT; /* not enough space */ + break; + } + + // TODO: sprintf!!!! + delta = sprintf( (char*) sym_start, "%s+%d/%d]", + symbol, sym.offset, sym.size ); + + space = sym_space + delta; + line = sym_start + delta; + symbols_expanded = 1; + } + ptr++; + len--; + parse_state = PARSING_TEXT; + break; + + default: /* Can't get here! */ + parse_state = PARSING_TEXT; + + } + } + + return; +} + + +static void LogKernelLine(void) +{ + auto int rdcnt; + + /* + * Zero-fill the log buffer. This should cure a multitude of + * problems with klogd logging the tail end of the message buffer + * which will contain old messages. Then read the kernel log + * messages into this fresh buffer. + */ + memset(log_buffer, '\0', sizeof(log_buffer)); + if ( (rdcnt = ksyslog(2, log_buffer, sizeof(log_buffer)-1)) < 0 ) + { + if(errno == EINTR) + return; + imklogLogIntMsg(LOG_ERR, "imklog Error return from sys_sycall: %d\n", errno); + } + else + LogLine(log_buffer, rdcnt); + return; +} + + +static void LogProcLine(void) +{ + auto int rdcnt; + + /* + * Zero-fill the log buffer. This should cure a multitude of + * problems with klogd logging the tail end of the message buffer + * which will contain old messages. Then read the kernel messages + * from the message pseudo-file into this fresh buffer. + */ + memset(log_buffer, '\0', sizeof(log_buffer)); + if ( (rdcnt = read(kmsg, log_buffer, sizeof(log_buffer)-1)) < 0 ) { + if ( errno == EINTR ) + return; + imklogLogIntMsg(LOG_ERR, "Cannot read proc file system: %d - %s.", errno, strerror(errno)); + } else { + LogLine(log_buffer, rdcnt); + } + + return; +} + + +/* to be called in the module's WillRun entry point + * rgerhards, 2008-04-09 + */ +rsRetVal klogLogKMsg(void) +{ + DEFiRet; + switch(logsrc) { + case kernel: + LogKernelLine(); + break; + case proc: + LogProcLine(); + break; + case none: + /* TODO: We need to handle this case here somewhat more intelligent + * This is now at least partly done - code should never reach this point + * as willRun() already checked for the "none" status -- rgerhards, 2007-12-17 + */ + pause(); + break; + } + RETiRet; +} + + +/* to be called in the module's WillRun entry point + * rgerhards, 2008-04-09 + */ +rsRetVal klogWillRun(void) +{ + DEFiRet; + /* Initialize this module. If that fails, we tell the engine we don't like to run */ + /* Determine where kernel logging information is to come from. */ + logsrc = GetKernelLogSrc(); + if(logsrc == none) { + iRet = RS_RET_NO_KERNEL_LOGSRC; + } else { + if (symbol_lookup) { + symbol_lookup = (InitKsyms(symfile) == 1); + symbol_lookup |= InitMsyms(); + if (symbol_lookup == 0) { + imklogLogIntMsg(LOG_WARNING, "cannot find any symbols, turning off symbol lookups"); + } + } + } + + RETiRet; +} + + +/* to be called in the module's AfterRun entry point + * rgerhards, 2008-04-09 + */ +rsRetVal klogAfterRun(void) +{ + DEFiRet; + /* cleanup here */ + if(logsrc != none) + CloseLogSrc(); + + DeinitKsyms(); + DeinitMsyms(); + + RETiRet; +} + + +/* provide the (system-specific) default facility for internal messages + * rgerhards, 2008-04-14 + */ +int +klogFacilIntMsg(void) +{ + return LOG_KERN; +} + + +/* vi:set ai: + */ -- cgit v1.2.3 From ee6ce30b474c033c71f5f5e9edf7941e29ea30b6 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 26 Mar 2010 09:14:31 +0100 Subject: interim commit: imklog/solaris compiles, but does not work saving this area of work, because some further clarification is needed. Do not try to run the current imklog, it will fail. --- plugins/imklog/Makefile.am | 2 +- plugins/imklog/solaris.c | 589 ++++++++++-------------------------------- plugins/imklog/solaris_cddl.c | 402 +++++++++++++++++----------- 3 files changed, 389 insertions(+), 604 deletions(-) diff --git a/plugins/imklog/Makefile.am b/plugins/imklog/Makefile.am index 85305ce3..06d4013c 100644 --- a/plugins/imklog/Makefile.am +++ b/plugins/imklog/Makefile.am @@ -12,7 +12,7 @@ imklog_la_SOURCES += linux.c module.h ksym.c ksyms.h ksym_mod.c endif if ENABLE_IMKLOG_SOLARIS -imklog_la_SOURCES += solaris_cddl.c +imklog_la_SOURCES += solaris.c solaris_cddl.c endif imklog_la_CPPFLAGS = -I$(top_srcdir) $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) diff --git a/plugins/imklog/solaris.c b/plugins/imklog/solaris.c index 97aead22..294efa7c 100644 --- a/plugins/imklog/solaris.c +++ b/plugins/imklog/solaris.c @@ -27,507 +27,181 @@ * * A copy of the GPL can be found in the file "COPYING" in this distribution. */ -#include "config.h" -#include "rsyslog.h" -#include -#include -#include -#include -#include -#include -#include "cfsysline.h" -#include "template.h" -#include "msg.h" -#include "module-template.h" -#include "imklog.h" -#include "unicode-helper.h" - - -/* Includes. */ -#include -#include -#include -#include -#if HAVE_TIME_H -# include +#ifdef HAVE_CONFIG_H +# include "config.h" #endif - -#include -#include -#include "ksyms.h" - -#define __LIBRARY__ +#include #include +#include +#include +#include +#include -#if !defined(__GLIBC__) -# define __NR_ksyslog __NR_syslog -_syscall3(int,ksyslog,int, type, char *, buf, int, len); -#else -#include -#define ksyslog klogctl -#endif - +#include "rsyslog.h" +#include "imklog.h" +#include "unicode-helper.h" +#include "solaris_cddl.h" +/* globals */ +static int fklog; // TODO: remove #ifndef _PATH_KLOG -#define _PATH_KLOG "/proc/kmsg" +# define _PATH_KLOG "/dev/log" #endif -#define LOG_BUFFER_SIZE 4096 -#define LOG_LINE_LENGTH 1000 - -static int kmsg; -static char log_buffer[LOG_BUFFER_SIZE]; - -static enum LOGSRC {none, proc, kernel} logsrc; - - -/* Function prototypes. */ -extern int ksyslog(int type, char *buf, int len); - - -static uchar *GetPath(void) -{ - return pszPath ? pszPath : UCHAR_CONSTANT(_PATH_KLOG); -} - -static void CloseLogSrc(void) -{ - /* Turn on logging of messages to console, but only if a log level was speficied */ - if(console_log_level != -1) - ksyslog(7, NULL, 0); - - /* Shutdown the log sources. */ - switch(logsrc) { - case kernel: - ksyslog(0, NULL, 0); - imklogLogIntMsg(LOG_INFO, "Kernel logging (ksyslog) stopped."); - break; - case proc: - close(kmsg); - imklogLogIntMsg(LOG_INFO, "Kernel logging (proc) stopped."); - break; - case none: - break; - } - - return; -} - +// HELPER +/* handle some defines missing on more than one platform */ +#ifndef SUN_LEN +#define SUN_LEN(su) \ + (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path)) +#endif -static enum LOGSRC GetKernelLogSrc(void) +int solaris_create_unix_socket(const char *path) { - auto struct stat sb; - - /* Set level of kernel console messaging.. */ - if ( (console_log_level != -1) && - (ksyslog(8, NULL, console_log_level) < 0) && - (errno == EINVAL) ) - { - /* - * An invalid arguement error probably indicates that - * a pre-0.14 kernel is being run. At this point we - * issue an error message and simply shut-off console - * logging completely. - */ - imklogLogIntMsg(LOG_WARNING, "Cannot set console log level - disabling " - "console output."); - } - - /* - * First do a stat to determine whether or not the proc based - * file system is available to get kernel messages from. - */ - if ( use_syscall || - ((stat((char*)GetPath(), &sb) < 0) && (errno == ENOENT)) ) - { - /* Initialize kernel logging. */ - ksyslog(1, NULL, 0); - imklogLogIntMsg(LOG_INFO, "imklog %s, log source = ksyslog " - "started.", VERSION); - return(kernel); - } - - if ( (kmsg = open((char*)GetPath(), O_RDONLY|O_CLOEXEC)) < 0 ) - { - imklogLogIntMsg(LOG_ERR, "imklog: Cannot open proc file system, %d.\n", errno); - ksyslog(7, NULL, 0); - return(none); + struct sockaddr_un sunx; + int fd; + +return; + if (path[0] == '\0') + return -1; + + unlink(path); + + memset(&sunx, 0, sizeof(sunx)); + sunx.sun_family = AF_UNIX; + (void) strncpy(sunx.sun_path, path, sizeof(sunx.sun_path)); + fd = socket(AF_UNIX, SOCK_DGRAM, 0); + if (fd < 0 || bind(fd, (struct sockaddr *) &sunx, SUN_LEN(&sunx)) < 0 || + chmod(path, 0666) < 0) { + //errmsg.LogError(errno, NO_ERRCODE, "connot create '%s'", path); + dbgprintf("cannot create %s (%d).\n", path, errno); + close(fd); + return -1; } - - imklogLogIntMsg(LOG_INFO, "imklog %s, log source = %s started.", VERSION, GetPath()); - return(proc); + return fd; } +// END HELPER -/* Copy characters from ptr to line until a char in the delim - * string is encountered or until min( space, len ) chars have - * been copied. - * - * Returns the actual number of chars copied. - */ -static int copyin( uchar *line, int space, - const char *ptr, int len, - const char *delim ) +static uchar *GetPath(void) { - auto int i; - auto int count; - - count = len < space ? len : space; - - for(i=0; i]", - * where "aaaaaa" is the address. These are replaced with - * "[symbolname+offset/size]" in the output line - symbolname, - * offset, and size come from the kernel symbol table. - * - * If a kernel symbol happens to fall at the end of a message close - * in length to LOG_LINE_LENGTH, the symbol will not be expanded. - * (This should never happen, since the kernel should never generate - * messages that long. - * - * To preserve the original addresses, lines containing kernel symbols - * are output twice. Once with the symbols converted and again with the - * original text. Just in case somebody wants to run their own Oops - * analysis on the syslog, e.g. ksymoops. +/* open the kernel log - will be called inside the willRun() imklog + * entry point. -- rgerhards, 2008-04-09 */ -static void LogLine(char *ptr, int len) -{ - enum parse_state_enum { - PARSING_TEXT, - PARSING_SYMSTART, /* at < */ - PARSING_SYMBOL, - PARSING_SYMEND /* at ] */ - }; - - static uchar line_buff[LOG_LINE_LENGTH]; - - static uchar *line =line_buff; - static enum parse_state_enum parse_state = PARSING_TEXT; - static int space = sizeof(line_buff)-1; - - static uchar *sym_start; /* points at the '<' of a symbol */ - - auto int delta = 0; /* number of chars copied */ - auto int symbols_expanded = 0; /* 1 if symbols were expanded */ - auto int skip_symbol_lookup = 0; /* skip symbol lookup on this pass */ - auto char *save_ptr = ptr; /* save start of input line */ - auto int save_len = len; /* save length at start of input line */ - - while( len > 0 ) - { - if( space == 0 ) /* line buffer is full */ - { - /* - ** Line too long. Start a new line. - */ - *line = 0; /* force null terminator */ - - //dbgprintf("Line buffer full:\n"); - //dbgprintf("\tLine: %s\n", line); - - Syslog(LOG_INFO, line_buff); - line = line_buff; - space = sizeof(line_buff)-1; - parse_state = PARSING_TEXT; - symbols_expanded = 0; - skip_symbol_lookup = 0; - save_ptr = ptr; - save_len = len; - } - - switch( parse_state ) - { - case PARSING_TEXT: - delta = copyin(line, space, ptr, len, "\n[" ); - line += delta; - ptr += delta; - space -= delta; - len -= delta; - - if( space == 0 || len == 0 ) - { - break; /* full line_buff or end of input buffer */ - } - - if( *ptr == '\0' ) /* zero byte */ - { - ptr++; /* skip zero byte */ - space -= 1; - len -= 1; - - break; - } - - if( *ptr == '\n' ) /* newline */ - { - ptr++; /* skip newline */ - space -= 1; - len -= 1; - - *line = 0; /* force null terminator */ - Syslog(LOG_INFO, line_buff); - line = line_buff; - space = sizeof(line_buff)-1; - if (symbols_twice) { - if (symbols_expanded) { - /* reprint this line without symbol lookup */ - symbols_expanded = 0; - skip_symbol_lookup = 1; - ptr = save_ptr; - len = save_len; - } - else - { - skip_symbol_lookup = 0; - save_ptr = ptr; - save_len = len; - } - } - break; - } - if( *ptr == '[' ) /* possible kernel symbol */ - { - *line++ = *ptr++; - space -= 1; - len -= 1; - if (!skip_symbol_lookup) - parse_state = PARSING_SYMSTART; /* at < */ - break; - } - /* Now that line_buff is no longer fed to *printf as format - * string, '%'s are no longer "dangerous". - */ - break; - - case PARSING_SYMSTART: - if( *ptr != '<' ) - { - parse_state = PARSING_TEXT; /* not a symbol */ - break; - } - - /* - ** Save this character for now. If this turns out to - ** be a valid symbol, this char will be replaced later. - ** If not, we'll just leave it there. - */ - - sym_start = line; /* this will point at the '<' */ - - *line++ = *ptr++; - space -= 1; - len -= 1; - parse_state = PARSING_SYMBOL; /* symbol... */ - break; - - case PARSING_SYMBOL: - delta = copyin( line, space, ptr, len, ">\n[" ); - line += delta; - ptr += delta; - space -= delta; - len -= delta; - if( space == 0 || len == 0 ) - { - break; /* full line_buff or end of input buffer */ - } - if( *ptr != '>' ) - { - parse_state = PARSING_TEXT; - break; - } - - *line++ = *ptr++; /* copy the '>' */ - space -= 1; - len -= 1; - - parse_state = PARSING_SYMEND; - - break; - - case PARSING_SYMEND: - if( *ptr != ']' ) - { - parse_state = PARSING_TEXT; /* not a symbol */ - break; - } - - /* - ** It's really a symbol! Replace address with the - ** symbol text. - */ - { - auto int sym_space; - - unsigned long value; - auto struct symbol sym; - auto char *symbol; - - *(line-1) = 0; /* null terminate the address string */ - value = strtoul((char*)(sym_start+1), (char **) 0, 16); - *(line-1) = '>'; /* put back delim */ - - if ( !symbol_lookup || (symbol = LookupSymbol(value, &sym)) == (char *)0 ) - { - parse_state = PARSING_TEXT; - break; - } - - /* - ** verify there is room in the line buffer - */ - sym_space = space + ( line - sym_start ); - if( (unsigned) sym_space < strlen(symbol) + 30 ) /*(30 should be overkill)*/ - { - parse_state = PARSING_TEXT; /* not enough space */ - break; - } - - // TODO: sprintf!!!! - delta = sprintf( (char*) sym_start, "%s+%d/%d]", - symbol, sym.offset, sym.size ); - - space = sym_space + delta; - line = sym_start + delta; - symbols_expanded = 1; - } - ptr++; - len--; - parse_state = PARSING_TEXT; - break; - - default: /* Can't get here! */ - parse_state = PARSING_TEXT; - - } - } - - return; -} - - -static void LogKernelLine(void) +rsRetVal +klogWillRun(void) { - auto int rdcnt; - - /* - * Zero-fill the log buffer. This should cure a multitude of - * problems with klogd logging the tail end of the message buffer - * which will contain old messages. Then read the kernel log - * messages into this fresh buffer. - */ - memset(log_buffer, '\0', sizeof(log_buffer)); - if ( (rdcnt = ksyslog(2, log_buffer, sizeof(log_buffer)-1)) < 0 ) - { - if(errno == EINTR) - return; - imklogLogIntMsg(LOG_ERR, "imklog Error return from sys_sycall: %d\n", errno); + DEFiRet; + + fklog = sun_openklog((char*) GetPath(), O_RDONLY); + if (fklog < 0) { + char errStr[1024]; + int err = errno; +perror("XXX"); + rs_strerror_r(err, errStr, sizeof(errStr)); + DBGPRINTF("error %d opening log socket %s: %s\n", + GetPath(), errStr); + iRet = RS_RET_ERR; // TODO: better error code } - else - LogLine(log_buffer, rdcnt); - return; + + RETiRet; } -static void LogProcLine(void) +/* 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) { - auto int rdcnt; - - /* - * Zero-fill the log buffer. This should cure a multitude of - * problems with klogd logging the tail end of the message buffer - * which will contain old messages. Then read the kernel messages - * from the message pseudo-file into this fresh buffer. + 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 */ - memset(log_buffer, '\0', sizeof(log_buffer)); - if ( (rdcnt = read(kmsg, log_buffer, sizeof(log_buffer)-1)) < 0 ) { - if ( errno == EINTR ) - return; - imklogLogIntMsg(LOG_ERR, "Cannot read proc file system: %d - %s.", errno, strerror(errno)); + if((size_t) iMaxLine < sizeof(bufRcv) - 1) { + pRcv = bufRcv; } else { - LogLine(log_buffer, rdcnt); - } + if((pRcv = (uchar*) malloc(sizeof(uchar) * (iMaxLine + 1))) == NULL) + iMaxLine = sizeof(bufRcv) - 1; /* better this than noting */ + } - return; -} + 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); -/* to be called in the module's WillRun entry point - * rgerhards, 2008-04-09 - */ -rsRetVal klogLogKMsg(void) -{ - DEFiRet; - switch(logsrc) { - case kernel: - LogKernelLine(); - break; - case proc: - LogProcLine(); - break; - case none: - /* TODO: We need to handle this case here somewhat more intelligent - * This is now at least partly done - code should never reach this point - * as willRun() already checked for the "none" status -- rgerhards, 2007-12-17 - */ - pause(); - break; - } - RETiRet; + if(pRcv != NULL && (size_t) iMaxLine >= sizeof(bufRcv) - 1) + free(pRcv); } -/* to be called in the module's WillRun entry point +/* to be called in the module's AfterRun entry point * rgerhards, 2008-04-09 */ -rsRetVal klogWillRun(void) +rsRetVal klogAfterRun(void) { DEFiRet; - /* Initialize this module. If that fails, we tell the engine we don't like to run */ - /* Determine where kernel logging information is to come from. */ - logsrc = GetKernelLogSrc(); - if(logsrc == none) { - iRet = RS_RET_NO_KERNEL_LOGSRC; - } else { - if (symbol_lookup) { - symbol_lookup = (InitKsyms(symfile) == 1); - symbol_lookup |= InitMsyms(); - if (symbol_lookup == 0) { - imklogLogIntMsg(LOG_WARNING, "cannot find any symbols, turning off symbol lookups"); - } - } - } - + if(fklog != -1) + close(fklog); RETiRet; } -/* to be called in the module's AfterRun entry point + +/* to be called in the module's WillRun entry point, this is the main + * "message pull" mechanism. * rgerhards, 2008-04-09 */ -rsRetVal klogAfterRun(void) +rsRetVal klogLogKMsg(void) { DEFiRet; - /* cleanup here */ - if(logsrc != none) - CloseLogSrc(); - - DeinitKsyms(); - DeinitMsyms(); - - RETiRet; + sun_sys_poll(); + //readklog(); + RETiRet; } @@ -537,9 +211,6 @@ rsRetVal klogAfterRun(void) int klogFacilIntMsg(void) { - return LOG_KERN; + return LOG_SYSLOG; } - -/* vi:set ai: - */ diff --git a/plugins/imklog/solaris_cddl.c b/plugins/imklog/solaris_cddl.c index df783c46..f45c5e62 100644 --- a/plugins/imklog/solaris_cddl.c +++ b/plugins/imklog/solaris_cddl.c @@ -1,3 +1,4 @@ +#define MAXLINE 4096 /* * CDDL HEADER START * @@ -41,28 +42,153 @@ */ #include "config.h" +#include +#include +#include +#include +#include + +//--------- +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//-------- + + +#include "rsyslog.h" + +static struct pollfd Pfd; /* Pollfd for local the log device */ + /* - * Attempts to open the local log device - * and return a file descriptor. + * 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 */ -int -sun_oopenklog(char *name, int mode) +size_t +findnl_bkwd(const char *buf, const size_t len) { - int fd; - struct strioctl str; + const char *p; + size_t mb_cur_max; pthread_t mythreadno; if (Debug) { mythreadno = pthread_self(); } + 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("findnl_bkwd(%u): Invalid MB " + "sequence\n", mythreadno); + /* + * 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; + + solaris_create_unix_socket(name); if ((fd = open(name, mode)) < 0) { - logerror("cannot open %s", name); - DPRINT3(1, "openklog(%u): cannot create %s (%d)\n", - mythreadno, name, errno); + //logerror("cannot open %s", name); + dbgprintf("openklog: cannot open %s (%d)\n", + name, errno); return (-1); } str.ic_cmd = I_CONSLOG; @@ -70,15 +196,114 @@ sun_oopenklog(char *name, int mode) str.ic_len = 0; str.ic_dp = NULL; if (ioctl(fd, I_STR, &str) < 0) { - logerror("cannot register to log console messages"); - DPRINT2(1, "openklog(%u): cannot register to log " - "console messages (%d)\n", mythreadno, errno); + //logerror("cannot register to log console messages"); + dbgprintf("openklog: cannot register to log " + "console messages (%d)\n", errno); return (-1); } + Pfd.fd = fd; return (fd); } +/* + * Pull up one message from log driver. + */ +void +sun_getkmsg(int timeout) +{ + 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("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'; + + /* 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. + */ + Syslog(LOG_INFO, buf); + /*if (timeout == 0) { + formatsys(&hdr, tmpbuf, 0); + //sys_init_msg_count++; + } else { + formatsys(&hdr, tmpbuf, 1); + }*/ + + 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("getkmsg: getmsg: dat.maxlen = %d\n", dat.maxlen); + dbgprintf("getkmsg: getmsg: dat.len = %d\n", dat.len); + dbgprintf("getkmsg: getmsg: strlen(dat.buf) = %d\n", strlen(dat.buf)); + dbgprintf("getkmsg: getmsg: dat.buf = \"%s\"\n", dat.buf); + dbgprintf("getkmsg: buf len = %d\n", strlen(buf)); + //if (timeout == 0) { + //formatsys(&hdr, buf, 0); + //--sys_init_msg_count++; + //} else { + //formatsys(&hdr, buf, 1); + //} + Syslog(LOG_INFO, buf); + } else if (i < 0 && errno != EINTR) { + if(1){ // (!shutting_down) { + dbgprintf("kernel log driver read error"); + } + // TODO trigger retry logic + //(void) close(Pfd.fd); + //Pfd.fd = -1; + } +} + + /* * Open the log device, and pull up all pending messages. */ @@ -87,26 +312,30 @@ sun_prepare_sys_poll() { int nfds, funix; - if ((funix = openklog(LogName, O_RDONLY)) < 0) { +/* + if ((funix = sun_openklog(LogName, O_RDONLY)) < 0) { logerror("can't open kernel log device - fatal"); exit(1); } +*/ Pfd.fd = funix; Pfd.events = POLLIN; for (;;) { nfds = poll(&Pfd, 1, 0); + /* if (nfds <= 0) { if (sys_init_msg_count > 0) flushmsg(SYNC_FILE); break; - } + }*/ if (Pfd.revents & POLLIN) { - getkmsg(0); + sun_getkmsg(0); } else if (Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) { - logerror("kernel log driver poll error"); + //logerror("kernel log driver poll error"); + dbgprintf("kernel log driver poll error"); break; } } @@ -123,14 +352,8 @@ void * sun_sys_poll(void *ap) { int nfds; - static int klogerrs = 0; - pthread_t mythreadno; - - if (Debug) { - mythreadno = pthread_self(); - } - DPRINT1(1, "sys_poll(%u): sys_thread started\n", mythreadno); + dbgprintf("sys_poll: sys_thread started\n"); /* * Try to process as many messages as we can without blocking on poll. @@ -141,11 +364,8 @@ sun_sys_poll(void *ap) * the previously counted initial messages out to disk. */ - sys_init_msg_count = 0; - for (;;) { errno = 0; - t_errno = 0; nfds = poll(&Pfd, 1, INFTIM); @@ -154,139 +374,33 @@ sun_sys_poll(void *ap) if (nfds < 0) { if (errno != EINTR) - logerror("poll"); + dbgprintf("poll error");// logerror("poll"); continue; } if (Pfd.revents & POLLIN) { - getkmsg(INFTIM); + sun_getkmsg(INFTIM); } else { - if (shutting_down) { - pthread_exit(0); - } + // TODO: shutdown, the rsyslog way + //if (shutting_down) { + //pthread_exit(0); + //} if (Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) { - logerror("kernel log driver poll error"); + // TODO: trigger retry logic +/* logerror("kernel log driver poll error"); (void) close(Pfd.fd); Pfd.fd = -1; + */ } } - while (Pfd.fd == -1 && klogerrs++ < 10) { - Pfd.fd = openklog(LogName, O_RDONLY); +/* while (Pfd.fd == -1 && klogerrs++ < 10) { + Pfd.fd = sun_openklog(LogName, O_RDONLY); } if (klogerrs >= 10) { logerror("can't reopen kernel log device - fatal"); exit(1); - } + }*/ } /*NOTREACHED*/ return (NULL); } - -/* - * Pull up one message from log driver. - */ -void -sun_getkmsg(int timeout) -{ - 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]; - pthread_t mythreadno; - - if (Debug) { - mythreadno = pthread_self(); - } - - 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'; - - DPRINT2(5, "sys_poll:(%u): getmsg: dat.len = %d\n", - mythreadno, dat.len); - buflen = strlen(buf); - len = findnl_bkwd(buf, buflen); - - (void) memcpy(tmpbuf, buf, len); - tmpbuf[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. - */ - if (timeout == 0) { - formatsys(&hdr, tmpbuf, 0); - sys_init_msg_count++; - } else { - formatsys(&hdr, tmpbuf, 1); - } - sys_msg_count++; - - 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. - */ - DPRINT2(5, "getkmsg(%u): getmsg: dat.maxlen = %d\n", - mythreadno, dat.maxlen); - DPRINT2(5, "getkmsg(%u): getmsg: dat.len = %d\n", - mythreadno, dat.len); - DPRINT2(5, "getkmsg(%u): getmsg: strlen(dat.buf) = %d\n", - mythreadno, strlen(dat.buf)); - DPRINT2(5, "getkmsg(%u): getmsg: dat.buf = \"%s\"\n", - mythreadno, dat.buf); - DPRINT2(5, "getkmsg(%u): buf len = %d\n", - mythreadno, strlen(buf)); - if (timeout == 0) { - formatsys(&hdr, buf, 0); - sys_init_msg_count++; - } else { - formatsys(&hdr, buf, 1); - } - sys_msg_count++; - } else if (i < 0 && errno != EINTR) { - if (!shutting_down) { - logerror("kernel log driver read error"); - } - (void) close(Pfd.fd); - Pfd.fd = -1; - } -} -- cgit v1.2.3 From 91a5e176d609d77d4451d7d7b1bf00dfdac5fe50 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 26 Mar 2010 15:49:39 +0100 Subject: added initial files for door support & fixed imklog imklog now basically works, but needs quite some more work to do --- Makefile.am | 4 + configure.ac | 15 ++ plugins/imdoor/Makefile.am | 6 + plugins/imdoor/imdoor.c | 430 ++++++++++++++++++++++++++++++ plugins/imdoor/sun_cddl.c | 592 ++++++++++++++++++++++++++++++++++++++++++ plugins/imklog/solaris.c | 35 +-- plugins/imklog/solaris_cddl.c | 33 ++- 7 files changed, 1067 insertions(+), 48 deletions(-) create mode 100644 plugins/imdoor/Makefile.am create mode 100644 plugins/imdoor/imdoor.c create mode 100644 plugins/imdoor/sun_cddl.c diff --git a/Makefile.am b/Makefile.am index a050e95e..e69349d8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -59,6 +59,10 @@ if ENABLE_IMKLOG SUBDIRS += plugins/imklog endif +if ENABLE_IMDOOR +SUBDIRS += plugins/imdoor +endif + if ENABLE_GSSAPI SUBDIRS += plugins/omgssapi plugins/imgssapi endif diff --git a/configure.ac b/configure.ac index c24468be..64f4fdc8 100644 --- a/configure.ac +++ b/configure.ac @@ -715,6 +715,19 @@ 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(imdoor, + [AS_HELP_STRING([--enable-imdoor],[door input module enabled @<:@default=no@:>@])], + [case "${enableval}" in + yes) enable_imdoor="yes" ;; + no) enable_imdoor="no" ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-imdoor) ;; + esac], + [enable_imdoor=no] +) +AM_CONDITIONAL(ENABLE_IMDOOR, test x$enable_imdoor = xyes) + + # settings for the omprog output module AC_ARG_ENABLE(omprog, [AS_HELP_STRING([--enable-omprog],[Compiles omprog module @<:@default=no@:>@])], @@ -816,6 +829,7 @@ AC_CONFIG_FILES([Makefile \ plugins/omprog/Makefile \ plugins/omstdout/Makefile \ plugins/imfile/Makefile \ + plugins/imdoor/Makefile \ plugins/imrelp/Makefile \ plugins/imdiag/Makefile \ plugins/omtesting/Makefile \ @@ -847,6 +861,7 @@ echo "---{ input plugins }---" echo " Klog functionality enabled: $enable_klog ($os_type)" echo " imdiag enabled: $enable_imdiag" echo " file input module enabled: $enable_imfile" +echo " Solaris door input module enabled: $enable_imdoor" echo " input template module will be compiled: $enable_imtemplate" echo echo "---{ output plugins }---" diff --git a/plugins/imdoor/Makefile.am b/plugins/imdoor/Makefile.am new file mode 100644 index 00000000..6ad7a904 --- /dev/null +++ b/plugins/imdoor/Makefile.am @@ -0,0 +1,6 @@ +pkglib_LTLIBRARIES = imdoor.la + +imdoor_la_SOURCES = imdoor.c sun_cddl.c +imdoor_la_CPPFLAGS = -I$(top_srcdir) $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) +imdoor_la_LDFLAGS = -module -avoid-version +imdoor_la_LIBADD = diff --git a/plugins/imdoor/imdoor.c b/plugins/imdoor/imdoor.c new file mode 100644 index 00000000..83890d03 --- /dev/null +++ b/plugins/imdoor/imdoor.c @@ -0,0 +1,430 @@ +/* imdoor.c + * This input module is used to receive syslog messages via the Solaris + * door mechanism. Not surprisingly, it most probably can not be built + * on other platforms. + * + * NOTE: read comments in module-template.h to understand how this file + * works! + * + * File begun on 2010-03-26 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 . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ +#include "config.h" +#include "rsyslog.h" +#include +#include +#include +#include +#include +#include +#include +#include +#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" + +MODULE_TYPE_INPUT + +/* defines */ +#define MAXFUNIX 20 +#ifndef _PATH_LOG +#ifdef BSD +#define _PATH_LOG "/var/run/log" +#else +#define _PATH_LOG "/dev/log" +#endif +#endif + + +/* handle some defines missing on more than one platform */ +#ifndef SUN_LEN +#define SUN_LEN(su) \ + (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path)) +#endif +/* Module static data */ +DEF_IMOD_STATIC_DATA +DEFobjCurrIf(errmsg) +DEFobjCurrIf(glbl) +DEFobjCurrIf(prop) + +static prop_t *pInputName = NULL; /* our inputName currently is always "imuxsock", and this will hold it */ +static int startIndexUxLocalSockets; /* process funix from that index on (used to + * suppress local logging. rgerhards 2005-08-01 + * read-only after startup + */ +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 uchar *funixn[MAXFUNIX] = { (uchar*) _PATH_LOG }; /* read-only after startup */ +static uchar *funixHName[MAXFUNIX] = { NULL, }; /* host-name override - if set, use this instead of actual name */ +static int funixFlowCtl[MAXFUNIX] = { eFLOWCTL_NO_DELAY, }; /* flow control settings for this socket */ +static int funix[MAXFUNIX] = { -1, }; /* read-only after startup */ +static int nfunix = 1; /* number of Unix sockets open / read-only after startup */ + +/* config settings */ +static int bOmitLocalLogging = 0; +static uchar *pLogSockName = NULL; +static uchar *pLogHostName = NULL; /* host name to use with this socket */ +static int bUseFlowCtl = 0; /* use flow control or not (if yes, only LIGHT is used! */ +static int bIgnoreTimestamp = 1; /* ignore timestamps present in the incoming message? */ + + +/* set the timestamp ignore / not ignore option for the system + * log socket. This must be done separtely, as it is not added via a command + * but present by default. -- rgerhards, 2008-03-06 + */ +static rsRetVal setSystemLogTimestampIgnore(void __attribute__((unused)) *pVal, int iNewVal) +{ + DEFiRet; + funixFlags[0] = iNewVal ? IGNDATE : NOFLAG; + RETiRet; +} + +/* set flowcontrol for the system log socket + */ +static rsRetVal setSystemLogFlowControl(void __attribute__((unused)) *pVal, int iNewVal) +{ + DEFiRet; + funixFlowCtl[0] = iNewVal ? eFLOWCTL_LIGHT_DELAY : eFLOWCTL_NO_DELAY; + RETiRet; +} + +/* add an additional listen socket. Socket names are added + * until the array is filled up. It is never reset, only at + * module unload. + * TODO: we should change the array to a list so that we + * can support any number of listen socket names. + * rgerhards, 2007-12-20 + * added capability to specify hostname for socket -- rgerhards, 2008-08-01 + */ +static rsRetVal addLstnSocketName(void __attribute__((unused)) *pVal, uchar *pNewVal) +{ + if(nfunix < MAXFUNIX) { + if(*pNewVal == ':') { + funixParseHost[nfunix] = 1; + } + else { + funixParseHost[nfunix] = 0; + } + funixHName[nfunix] = pLogHostName; + pLogHostName = NULL; /* re-init for next, not freed because funixHName[] now owns it */ + funixFlowCtl[nfunix] = bUseFlowCtl ? eFLOWCTL_LIGHT_DELAY : eFLOWCTL_NO_DELAY; + funixFlags[nfunix] = bIgnoreTimestamp ? IGNDATE : NOFLAG; + funixn[nfunix++] = pNewVal; + } + else { + errmsg.LogError(0, NO_ERRCODE, "Out of unix socket name descriptors, ignoring %s\n", + pNewVal); + } + + return RS_RET_OK; +} + +/* free the funixn[] socket names - needed as cleanup on several places + * note that nfunix is NOT reset! funixn[0] is never freed, as it comes from + * the constant memory pool - and if not, it is freeed via some other pointer. + */ +static rsRetVal discardFunixn(void) +{ + int i; + + for (i = 1; i < nfunix; i++) { + if(funixn[i] != NULL) { + free(funixn[i]); + funixn[i] = NULL; + } + if(funixHName[i] != NULL) { + free(funixHName[i]); + funixHName[i] = NULL; + } + } + + return RS_RET_OK; +} + + +static int create_unix_socket(const char *path) +{ + struct sockaddr_un sunx; + int fd; + + if (path[0] == '\0') + return -1; + + unlink(path); + + memset(&sunx, 0, sizeof(sunx)); + sunx.sun_family = AF_UNIX; + (void) strncpy(sunx.sun_path, path, sizeof(sunx.sun_path)); + fd = socket(AF_UNIX, SOCK_DGRAM, 0); + if (fd < 0 || bind(fd, (struct sockaddr *) &sunx, SUN_LEN(&sunx)) < 0 || + chmod(path, 0666) < 0) { + errmsg.LogError(errno, NO_ERRCODE, "connot create '%s'", path); + dbgprintf("cannot create %s (%d).\n", path, errno); + close(fd); + return -1; + } + return fd; +} + + +/* This function receives data from a socket indicated to be ready + * to receive and submits the message received for processing. + * rgerhards, 2007-12-20 + * Interface changed so that this function is passed the array index + * of the socket which is to be processed. This eases access to the + * growing number of properties. -- rgerhards, 2008-08-01 + */ +static rsRetVal readSocket(int fd, int iSock) +{ + DEFiRet; + int iRcvd; + int iMaxLine; + uchar bufRcv[4096+1]; + uchar *pRcv = NULL; /* receive buffer */ + + assert(iSock >= 0); + + 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))); + } + + iRcvd = recv(fd, pRcv, iMaxLine, 0); + dbgprintf("Message from UNIX socket: #%d\n", fd); + if (iRcvd > 0) { + parseAndSubmitMessage(funixHName[iSock] == NULL ? glbl.GetLocalHostName() : funixHName[iSock], + (uchar*)"127.0.0.1", pRcv, + iRcvd, funixParseHost[iSock] ? (funixFlags[iSock] | PARSE_HOSTNAME) : funixFlags[iSock], + funixFlowCtl[iSock], pInputName, NULL, 0); + } else if (iRcvd < 0 && errno != EINTR) { + char errStr[1024]; + rs_strerror_r(errno, errStr, sizeof(errStr)); + dbgprintf("UNIX socket error: %d = %s.\n", errno, errStr); + errmsg.LogError(errno, NO_ERRCODE, "recvfrom UNIX"); + } + +finalize_it: + if(pRcv != NULL && (size_t) iMaxLine >= sizeof(bufRcv) - 1) + free(pRcv); + + RETiRet; +} + + +/* This function is called to gather input. */ +BEGINrunInput + int maxfds; + int nfds; + int i; + int fd; + fd_set readfds; +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. + */ + while(1) { + /* Add the Unix Domain Sockets to the list of read + * descriptors. + * rgerhards 2005-08-01: we must now check if there are + * any local sockets to listen to at all. If the -o option + * is given without -a, we do not need to listen at all.. + */ + maxfds = 0; + FD_ZERO (&readfds); + /* Copy master connections */ + for (i = startIndexUxLocalSockets; i < nfunix; i++) { + if (funix[i] != -1) { + FD_SET(funix[i], &readfds); + if (funix[i]>maxfds) maxfds=funix[i]; + } + } + + if(Debug) { + dbgprintf("--------imuxsock calling select, active file descriptors (max %d): ", maxfds); + for (nfds= 0; nfds <= maxfds; ++nfds) + if ( FD_ISSET(nfds, &readfds) ) + dbgprintf("%d ", nfds); + dbgprintf("\n"); + } + + /* wait for io to become ready */ + nfds = select(maxfds+1, (fd_set *) &readfds, NULL, NULL, NULL); + + for (i = 0; i < nfunix && nfds > 0; i++) { + if ((fd = funix[i]) != -1 && FD_ISSET(fd, &readfds)) { + readSocket(fd, i); + --nfds; /* indicate we have processed one */ + } + } + } + + RETiRet; +ENDrunInput + + +BEGINwillRun +CODESTARTwillRun + register int i; + + /* first apply some config settings */ + startIndexUxLocalSockets = bOmitLocalLogging ? 1 : 0; + 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) + dbgprintf("Opened UNIX socket '%s' (fd %d).\n", funixn[i], funix[i]); + } + + /* we need to create the inputName property (only once during our lifetime) */ + CHKiRet(prop.Construct(&pInputName)); + CHKiRet(prop.SetString(pInputName, UCHAR_CONSTANT("imuxsock"), sizeof("imuxsock") - 1)); + CHKiRet(prop.ConstructFinalize(pInputName)); + +finalize_it: +ENDwillRun + + +BEGINafterRun +CODESTARTafterRun + int i; + /* do cleanup here */ + /* Close the UNIX sockets. */ + for (i = 0; i < nfunix; i++) + if (funix[i] != -1) + close(funix[i]); + + /* Clean-up files. */ + for (i = 0; i < nfunix; i++) + if (funixn[i] && funix[i] != -1) + unlink((char*) funixn[i]); + /* free no longer needed string */ + if(pLogSockName != NULL) + free(pLogSockName); + if(pLogHostName != NULL) { + free(pLogHostName); + } + + discardFunixn(); + nfunix = 1; + + if(pInputName != NULL) + prop.Destruct(&pInputName); +ENDafterRun + + +BEGINmodExit +CODESTARTmodExit + 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) +{ + bOmitLocalLogging = 0; + if(pLogSockName != NULL) { + free(pLogSockName); + pLogSockName = NULL; + } + if(pLogHostName != NULL) { + free(pLogHostName); + pLogHostName = NULL; + } + + discardFunixn(); + nfunix = 1; + bIgnoreTimestamp = 1; + bUseFlowCtl = 0; + + return RS_RET_OK; +} + + +BEGINmodInit() + int i; +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("imuxsock version %s initializing\n", PACKAGE_VERSION); + + /* initialize funixn[] array */ + for(i = 1 ; i < MAXFUNIX ; ++i) { + funixn[i] = NULL; + funix[i] = -1; + } + + /* register config file handlers */ + CHKiRet(omsdRegCFSLineHdlr((uchar *)"omitlocallogging", 0, eCmdHdlrBinary, + NULL, &bOmitLocalLogging, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketignoremsgtimestamp", 0, eCmdHdlrBinary, + NULL, &bIgnoreTimestamp, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogsocketname", 0, eCmdHdlrGetWord, + NULL, &pLogSockName, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensockethostname", 0, eCmdHdlrGetWord, + NULL, &pLogHostName, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketflowcontrol", 0, eCmdHdlrBinary, + NULL, &bUseFlowCtl, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"addunixlistensocket", 0, eCmdHdlrGetWord, + addLstnSocketName, NULL, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, + resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID)); + /* the following one is a (dirty) trick: the system log socket is not added via + * an "addUnixListenSocket" config format. As such, it's properties can not be modified + * via $InputUnixListenSocket*". So we need to add a special directive + * for that. We should revisit all of that once we have the new config format... + * rgerhards, 2008-03-06 + */ + CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogsocketignoremsgtimestamp", 0, eCmdHdlrBinary, + setSystemLogTimestampIgnore, NULL, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogsocketflowcontrol", 0, eCmdHdlrBinary, + setSystemLogFlowControl, NULL, STD_LOADABLE_MODULE_ID)); +ENDmodInit +/* vim:set ai: + */ diff --git a/plugins/imdoor/sun_cddl.c b/plugins/imdoor/sun_cddl.c new file mode 100644 index 00000000..8e9714d9 --- /dev/null +++ b/plugins/imdoor/sun_cddl.c @@ -0,0 +1,592 @@ +#define MAXLINE 4096 +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rsyslog.h" +#include "debug.h" + +#define DOORFILE "/var/run/syslog_door" +#define RELATIVE_DOORFILE "../var/run/syslog_door" +#define OLD_DOORFILE "/etc/.syslog_door" + +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 *cookie, char *argp, size_t arg_size, + door_desc_t *dp, uint_t n) +{ + (void) door_return(NULL, 0, NULL, 0); + /* NOTREACHED */ +} + +/*ARGSUSED*/ +static void * +create_door_thr(void *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); +} + +/* + * 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 + +/* + * Manage door server thread pool. + */ +/*ARGSUSED*/ +static void +door_server_pool(door_info_t *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); +} + +static void +delete_doorfiles(void) +{ + pthread_t mythreadno; + struct stat sb; + int err; + char line[MAXLINE+1]; + + if (Debug) { + mythreadno = pthread_self(); + } + + + 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); + errno = err; + DBGPRINTF("%s", line);//logerror(line); + DBGPRINTF("delete_doorfiles(%u): error: %s, " + "errno=%d\n", mythreadno, line, err); + exit(1); + } + + DBGPRINTF("delete_doorfiles(%u): deleted %s\n", + mythreadno, 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(%u): %s\n", + mythreadno, line); + + if (err != EROFS) { + errno = err; + (void) strlcat(line, " - fatal", + sizeof (line)); + logerror(line); + DBGPRINTF("delete_doorfiles(%u): " + "error: %s, errno=%d\n", + mythreadno, line, err); + exit(1); + } + + DBGPRINTF("delete_doorfiles(%u): unlink() " + "failure OK on RO file system\n", + mythreadno); + } + + DBGPRINTF("delete_doorfiles(%u): deleted %s\n", + mythreadno, OLD_DOORFILE); + } + } + +#if 0 + if (lstat(PidFileName, &sb) == 0 && !S_ISDIR(sb.st_mode)) { + if (unlink(PidFileName) < 0) { + err = errno; + (void) snprintf(line, sizeof (line), + "unlink() of %s failed - fatal", PidFileName); + errno = err; + logerror(line); + DBGPRINTF("delete_doorfiles(%u): error: %s, " + "errno=%d\n", mythreadno, line, err); + exit(1); + } + + DBGPRINTF("delete_doorfiles(%u): deleted %s\n", mythreadno, + PidFileName); + } + + if (strcmp(PidFileName, PIDFILE) == 0) { + if (lstat(OLD_PIDFILE, &sb) == 0 && !S_ISDIR(sb.st_mode)) { + if (unlink(OLD_PIDFILE) < 0) { + err = errno; + (void) snprintf(line, sizeof (line), + "unlink() of %s failed", OLD_PIDFILE); + DBGPRINTF(5, "delete_doorfiles(%u): %s, \n", + mythreadno, line); + + if (err != EROFS) { + errno = err; + (void) strlcat(line, " - fatal", + sizeof (line)); + logerror(line); + DBGPRINTF(1, "delete_doorfiles(%u): " + "error: %s, errno=%d\n", + mythreadno, line, err); + exit(1); + } + + DBGPRINTF(5, "delete_doorfiles(%u): unlink " + "failure OK on RO file system\n", + mythreadno); + } + + DBGPRINTF(5, "delete_doorfiles(%u): deleted %s\n", + mythreadno, OLD_PIDFILE); + } + } +#endif + + if (DoorFd != -1) { + (void) door_revoke(DoorFd); + } + + DBGPRINTF("delete_doorfiles(%u): revoked door: DoorFd=%d\n", + mythreadno, DoorFd); +} + + +/* + * Create the door file and the pid file in /var/run. If the filesystem + * containing /etc is writable, create symlinks /etc/.syslog_door and + * /etc/syslog.pid to them. On systems that do not support /var/run, create + * /etc/.syslog_door and /etc/syslog.pid directly. + * + * Note: it is not considered fatal to fail to create the pid file or its + * symlink. Attempts to use them in the usual way will fail, of course, but + * syslogd will function nicely without it (not so for the door file). + */ + +static void +sun_open_door(void) +{ + struct stat buf; + door_info_t info; + char line[MAXLINE+1]; + pthread_t mythreadno; + int err; + + if (Debug) { + mythreadno = pthread_self(); + } + + /* + * first see if another syslogd is running by trying + * a door call - if it succeeds, there is already + * a syslogd process active + */ + + if (!DoorCreated) { + int door; + + if ((door = open(DoorFileName, O_RDONLY)) >= 0) { + DBGPRINTF("open_door(%u): %s opened " + "successfully\n", mythreadno, DoorFileName); + + if (door_info(door, &info) >= 0) { + DBGPRINTF("open_door(%u): " + "door_info:info.di_target = %ld\n", + mythreadno, 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(%u): error: " + "%s\n", mythreadno, line); + errno = 0; + //logerror(line); + exit(1); + } + } + + (void) close(door); + } else { + if (lstat(DoorFileName, &buf) < 0) { + err = errno; + + DBGPRINTF("open_door(%u): lstat() of %s " + "failed, errno=%d\n", + mythreadno, DoorFileName, err); + + if ((door = creat(DoorFileName, 0644)) < 0) { + err = errno; + (void) snprintf(line, sizeof (line), + "creat() of %s failed - fatal", + DoorFileName); + DBGPRINTF("open_door(%u): error: %s, " + "errno=%d\n", mythreadno, line, + err); + errno = err; + //logerror(line); + delete_doorfiles(); + exit(1); + } + + (void) fchmod(door, + S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); + + DBGPRINTF("open_door(%u): creat() of %s " + "succeeded\n", mythreadno, + DoorFileName); + + (void) close(door); + } + } + + if (strcmp(DoorFileName, DOORFILE) == 0) { + if (lstat(OLD_DOORFILE, &buf) == 0) { + DBGPRINTF("open_door(%u): lstat() of %s " + "succeeded\n", mythreadno, + OLD_DOORFILE); + + if (S_ISDIR(buf.st_mode)) { + (void) snprintf(line, sizeof (line), + "%s is a directory - fatal", + OLD_DOORFILE); + DBGPRINTF("open_door(%u): error: " + "%s\n", mythreadno, line); + errno = 0; + //logerror(line); + delete_doorfiles(); + exit(1); + } + + DBGPRINTF("open_door(%u): %s is not a " + "directory\n", + mythreadno, OLD_DOORFILE); + + if (unlink(OLD_DOORFILE) < 0) { + err = errno; + (void) snprintf(line, sizeof (line), + "unlink() of %s failed", + OLD_DOORFILE); + DBGPRINTF("open_door(%u): %s\n", + mythreadno, line); + + if (err != EROFS) { + DBGPRINTF("open_door(%u): " + "error: %s, " + "errno=%d\n", + mythreadno, line, err); + (void) strcat(line, " - fatal"); + errno = err; + //logerror(line); + delete_doorfiles(); + exit(1); + } + + DBGPRINTF("open_door(%u): unlink " + "failure OK on RO file " + "system\n", mythreadno); + } + } else { + DBGPRINTF("open_door(%u): file %s doesn't " + "exist\n", mythreadno, 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(%u): %s\n", mythreadno, + line); + + if (err != EROFS) { + DBGPRINTF("open_door(%u): error: %s, " + "errno=%d\n", mythreadno, line, + err); + errno = err; + (void) strcat(line, " - fatal"); + //logerror(line); + delete_doorfiles(); + exit(1); + } + + DBGPRINTF("open_door(%u): symlink failure OK " + "on RO file system\n", mythreadno); + } else { + DBGPRINTF("open_door(%u): symlink %s -> %s " + "succeeded\n", mythreadno, + 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(%u): error: %s, errno=%d\n", + mythreadno, line, err); + errno = err; + //logerror(line); + delete_doorfiles(); + exit(1); + } + //???? (void) door_setparam(DoorFd, DOOR_PARAM_DATA_MAX, 0); + DBGPRINTF("open_door(%u): door_create() succeeded, " + "DoorFd=%d\n", mythreadno, 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(%u): error: %s, errno=%d\n", mythreadno, + line, err); + errno = err; + //logerror(line); + delete_doorfiles(); + exit(1); + } + + DBGPRINTF("open_door(%u): attached server() to %s\n", mythreadno, + DoorFileName); + +#if 0 + /* + * create pidfile anyway, so those using it to control + * syslogd (with kill `cat /etc/syslog.pid` perhaps) + * don't get broken. + */ + + if (!PidfileCreated) { + int pidfd; + + PidfileCreated = 1; + + if ((pidfd = open(PidFileName, O_RDWR|O_CREAT|O_TRUNC, 0644)) + < 0) { + err = errno; + (void) snprintf(line, sizeof (line), + "open() of %s failed", PidFileName); + DBGPRINTF(1, "open_door(%u): warning: %s, errno=%d\n", + mythreadno, line, err); + errno = err; + //logerror(line); + return; + } + + (void) fchmod(pidfd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); + (void) sprintf(line, "%ld\n", getpid()); + + if (write(pidfd, line, strlen(line)) < 0) { + err = errno; + (void) snprintf(line, sizeof (line), + "write to %s on fd %d failed", PidFileName, pidfd); + DBGPRINTF(1, "open_door(%u): warning: %s, errno=%d\n", + mythreadno, line, err); + errno = err; + //logerror(line); + return; + } + + (void) close(pidfd); + + DBGPRINTF("open_door(%u): %s created\n", + mythreadno, PidFileName); + + if (strcmp(PidFileName, PIDFILE) == 0) { + if (lstat(OLD_PIDFILE, &buf) == 0) { + DBGPRINTF("open_door(%u): lstat() of %s " + "succeded\n", mythreadno, OLD_PIDFILE); + + if (S_ISDIR(buf.st_mode)) { + (void) snprintf(line, sizeof (line), + "file %s is a directory", + OLD_PIDFILE); + DBGPRINTF("open_door(%u): warning: " + "%s\n", mythreadno, line); + errno = 0; + //logerror(line); + return; + } + + if (unlink(OLD_PIDFILE) < 0) { + err = errno; + (void) snprintf(line, sizeof (line), + "unlink() of %s failed", + OLD_PIDFILE); + DBGPRINTF("open_door(%u): %s\n", + mythreadno, line); + + if (err != EROFS) { + DBGPRINTF(1, "open_door (%u): " + "warning: %s, " + "errno=%d\n", + mythreadno, line, err); + errno = err; + //logerror(line); + return; + } + + DBGPRINTF(5, "open_door(%u): unlink " + "failure OK on RO file " + "system\n", mythreadno); + } + } else { + DBGPRINTF("open_door(%u): file %s doesn't " + "exist\n", mythreadno, OLD_PIDFILE); + } + + if (symlink(RELATIVE_PIDFILE, OLD_PIDFILE) < 0) { + err = errno; + (void) snprintf(line, sizeof (line), + "symlink %s -> %s failed", OLD_PIDFILE, + RELATIVE_PIDFILE); + DBGPRINTF("open_door(%u): %s\n", mythreadno, + line); + + if (err != EROFS) { + DBGPRINTF(1, "open_door(%u): warning: " + "%s, errno=%d\n", mythreadno, + line, err); + errno = err; + //logerror(line); + return; + } + + DBGPRINTF(5, "open_door(%u): symlink failure OK " + "on RO file system\n", mythreadno); + return; + } + + DBGPRINTF(5, "open_door(%u): symlink %s -> %s " + "succeeded\n", mythreadno, OLD_PIDFILE, + RELATIVE_PIDFILE); + } + } +#endif +} + + diff --git a/plugins/imklog/solaris.c b/plugins/imklog/solaris.c index 294efa7c..a0e85dc7 100644 --- a/plugins/imklog/solaris.c +++ b/plugins/imklog/solaris.c @@ -51,39 +51,6 @@ static int fklog; // TODO: remove # define _PATH_KLOG "/dev/log" #endif -// HELPER -/* handle some defines missing on more than one platform */ -#ifndef SUN_LEN -#define SUN_LEN(su) \ - (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path)) -#endif - -int solaris_create_unix_socket(const char *path) -{ - struct sockaddr_un sunx; - int fd; - -return; - if (path[0] == '\0') - return -1; - - unlink(path); - - memset(&sunx, 0, sizeof(sunx)); - sunx.sun_family = AF_UNIX; - (void) strncpy(sunx.sun_path, path, sizeof(sunx.sun_path)); - fd = socket(AF_UNIX, SOCK_DGRAM, 0); - if (fd < 0 || bind(fd, (struct sockaddr *) &sunx, SUN_LEN(&sunx)) < 0 || - chmod(path, 0666) < 0) { - //errmsg.LogError(errno, NO_ERRCODE, "connot create '%s'", path); - dbgprintf("cannot create %s (%d).\n", path, errno); - close(fd); - return -1; - } - return fd; -} -// END HELPER - static uchar *GetPath(void) { @@ -104,7 +71,7 @@ klogWillRun(void) int err = errno; perror("XXX"); rs_strerror_r(err, errStr, sizeof(errStr)); - DBGPRINTF("error %d opening log socket %s: %s\n", + DBGPRINTF("error %d opening log socket: %s\n", GetPath(), errStr); iRet = RS_RET_ERR; // TODO: better error code } diff --git a/plugins/imklog/solaris_cddl.c b/plugins/imklog/solaris_cddl.c index f45c5e62..700e0ab3 100644 --- a/plugins/imklog/solaris_cddl.c +++ b/plugins/imklog/solaris_cddl.c @@ -141,7 +141,7 @@ findnl_bkwd(const char *buf, const size_t len) /* * Invalid character found. */ - dbgprintf("findnl_bkwd(%u): Invalid MB " + dbgprintf("klog:findnl_bkwd(%u): Invalid MB " "sequence\n", mythreadno); /* * handle as a single byte character. @@ -184,10 +184,9 @@ sun_openklog(char *name, int mode) int fd; struct strioctl str; - solaris_create_unix_socket(name); if ((fd = open(name, mode)) < 0) { //logerror("cannot open %s", name); - dbgprintf("openklog: cannot open %s (%d)\n", + dbgprintf("klog:openklog: cannot open %s (%d)\n", name, errno); return (-1); } @@ -197,11 +196,12 @@ sun_openklog(char *name, int mode) str.ic_dp = NULL; if (ioctl(fd, I_STR, &str) < 0) { //logerror("cannot register to log console messages"); - dbgprintf("openklog: cannot register to log " + dbgprintf("klog:openklog: cannot register to log " "console messages (%d)\n", errno); return (-1); } Pfd.fd = fd; + Pfd.events = POLLIN; return (fd); } @@ -230,7 +230,7 @@ sun_getkmsg(int timeout) lastline = &dat.buf[dat.len]; *lastline = '\0'; - dbgprintf("sys_poll: getmsg: dat.len = %d\n", dat.len); + dbgprintf("klog:sys_poll: getmsg: dat.len = %d\n", dat.len); buflen = strlen(buf); len = findnl_bkwd(buf, buflen); @@ -281,11 +281,11 @@ sun_getkmsg(int timeout) * means that we're done handling all the * initial messages ready during startup. */ - dbgprintf("getkmsg: getmsg: dat.maxlen = %d\n", dat.maxlen); - dbgprintf("getkmsg: getmsg: dat.len = %d\n", dat.len); - dbgprintf("getkmsg: getmsg: strlen(dat.buf) = %d\n", strlen(dat.buf)); - dbgprintf("getkmsg: getmsg: dat.buf = \"%s\"\n", dat.buf); - dbgprintf("getkmsg: buf len = %d\n", strlen(buf)); + 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)); //if (timeout == 0) { //formatsys(&hdr, buf, 0); //--sys_init_msg_count++; @@ -295,7 +295,7 @@ sun_getkmsg(int timeout) Syslog(LOG_INFO, buf); } else if (i < 0 && errno != EINTR) { if(1){ // (!shutting_down) { - dbgprintf("kernel log driver read error"); + dbgprintf("klog:kernel log driver read error"); } // TODO trigger retry logic //(void) close(Pfd.fd); @@ -304,6 +304,7 @@ sun_getkmsg(int timeout) } +#if 0 /* * Open the log device, and pull up all pending messages. */ @@ -335,12 +336,14 @@ sun_prepare_sys_poll() sun_getkmsg(0); } else if (Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) { //logerror("kernel log driver poll error"); - dbgprintf("kernel log driver poll error"); + dbgprintf("klog:kernel log driver poll error"); break; } } } +#endif + /* * this thread listens to the local stream log driver for log messages @@ -353,7 +356,7 @@ sun_sys_poll(void *ap) { int nfds; - dbgprintf("sys_poll: sys_thread started\n"); + dbgprintf("klog:sys_poll: sys_thread started\n"); /* * Try to process as many messages as we can without blocking on poll. @@ -366,15 +369,17 @@ sun_sys_poll(void *ap) for (;;) { errno = 0; +dbgprintf("XXX: before poll\n"); nfds = poll(&Pfd, 1, INFTIM); +dbgprintf("XXX: after poll, nfds %d\n", nfds); if (nfds == 0) continue; if (nfds < 0) { if (errno != EINTR) - dbgprintf("poll error");// logerror("poll"); + dbgprintf("klog:poll error");// logerror("poll"); continue; } if (Pfd.revents & POLLIN) { -- cgit v1.2.3 From b67b5b8f73074931285dad4cb2e6d760923a19f8 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 26 Mar 2010 16:38:34 +0100 Subject: bugfix: local unix system log socket was deleted even when it was not configured Also made sure that /dev/log will not be processed by imuxsock when running under Solaris -- otherwise, the module may had accidently deleted the log socket and cause problems. --- ChangeLog | 4 ++++ plugins/imuxsock/imuxsock.c | 13 +++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2e064b2e..26dfda48 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,8 @@ --------------------------------------------------------------------------- +Version 4.6.3 [v4-stable] (rgerhards), 2010-03-?? +- bugfix: local unix system log socket was deleted even when it was + not configured +--------------------------------------------------------------------------- Version 4.6.2 [v4-stable] (rgerhards), 2010-03-?? - new feature: "." action type added to support writing files to relative pathes (this is primarily meant as a debug aid) diff --git a/plugins/imuxsock/imuxsock.c b/plugins/imuxsock/imuxsock.c index 5567a405..1ab67826 100644 --- a/plugins/imuxsock/imuxsock.c +++ b/plugins/imuxsock/imuxsock.c @@ -300,7 +300,16 @@ 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; @@ -329,7 +338,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 */ -- cgit v1.2.3 From 3ab759c40d34f518744efa9b266640784fc3655f Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 26 Mar 2010 16:59:00 +0100 Subject: cleanup in solaris components for imklog --- plugins/imklog/solaris.c | 2 - plugins/imklog/solaris_cddl.c | 104 ++++-------------------------------------- 2 files changed, 8 insertions(+), 98 deletions(-) diff --git a/plugins/imklog/solaris.c b/plugins/imklog/solaris.c index a0e85dc7..c2aec30a 100644 --- a/plugins/imklog/solaris.c +++ b/plugins/imklog/solaris.c @@ -69,7 +69,6 @@ klogWillRun(void) if (fklog < 0) { char errStr[1024]; int err = errno; -perror("XXX"); rs_strerror_r(err, errStr, sizeof(errStr)); DBGPRINTF("error %d opening log socket: %s\n", GetPath(), errStr); @@ -167,7 +166,6 @@ rsRetVal klogLogKMsg(void) { DEFiRet; sun_sys_poll(); - //readklog(); RETiRet; } diff --git a/plugins/imklog/solaris_cddl.c b/plugins/imklog/solaris_cddl.c index 700e0ab3..1053de66 100644 --- a/plugins/imklog/solaris_cddl.c +++ b/plugins/imklog/solaris_cddl.c @@ -40,61 +40,24 @@ * software developed by the University of California, Berkeley, and its * contributors. */ - #include "config.h" #include #include #include #include #include - -//--------- -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include #include -#include - -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -//-------- - #include "rsyslog.h" static struct pollfd Pfd; /* Pollfd for local the log device */ - - -/* - * findnl_bkwd: +/* 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. @@ -174,8 +137,8 @@ findnl_bkwd(const char *buf, const size_t len) } //___ end -/* - * Attempts to open the local log device + +/* Attempts to open the local log device * and return a file descriptor. */ int @@ -210,7 +173,7 @@ sun_openklog(char *name, int mode) * Pull up one message from log driver. */ void -sun_getkmsg(int timeout) +sun_getkmsg() { int flags = 0, i; char *lastline; @@ -304,55 +267,13 @@ sun_getkmsg(int timeout) } -#if 0 -/* - * Open the log device, and pull up all pending messages. - */ -void -sun_prepare_sys_poll() -{ - int nfds, funix; - -/* - if ((funix = sun_openklog(LogName, O_RDONLY)) < 0) { - logerror("can't open kernel log device - fatal"); - exit(1); - } -*/ - - Pfd.fd = funix; - Pfd.events = POLLIN; - - for (;;) { - nfds = poll(&Pfd, 1, 0); - /* - if (nfds <= 0) { - if (sys_init_msg_count > 0) - flushmsg(SYNC_FILE); - break; - }*/ - - if (Pfd.revents & POLLIN) { - sun_getkmsg(0); - } else if (Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) { - //logerror("kernel log driver poll error"); - dbgprintf("klog:kernel log driver poll error"); - break; - } - } - -} -#endif - - -/* - * this thread listens to the local stream log driver for log messages +/* 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(void *ap) +sun_sys_poll() { int nfds; @@ -369,10 +290,8 @@ sun_sys_poll(void *ap) for (;;) { errno = 0; -dbgprintf("XXX: before poll\n"); nfds = poll(&Pfd, 1, INFTIM); -dbgprintf("XXX: after poll, nfds %d\n", nfds); if (nfds == 0) continue; @@ -383,9 +302,9 @@ dbgprintf("XXX: after poll, nfds %d\n", nfds); continue; } if (Pfd.revents & POLLIN) { - sun_getkmsg(INFTIM); + sun_getkmsg(); } else { - // TODO: shutdown, the rsyslog way + // TODO: shutdown, the rsyslog way (in v5!) //if (shutting_down) { //pthread_exit(0); //} @@ -398,13 +317,6 @@ dbgprintf("XXX: after poll, nfds %d\n", nfds); } } -/* while (Pfd.fd == -1 && klogerrs++ < 10) { - Pfd.fd = sun_openklog(LogName, O_RDONLY); - } - if (klogerrs >= 10) { - logerror("can't reopen kernel log device - fatal"); - exit(1); - }*/ } /*NOTREACHED*/ return (NULL); -- cgit v1.2.3 From cb2fe4a585d4cb78175770938ebf361d023e999d Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 29 Mar 2010 17:14:43 +0200 Subject: added some more useful info to Solaris README --- solaris/README | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/solaris/README b/solaris/README index 0700642e..3f88431d 100644 --- a/solaris/README +++ b/solaris/README @@ -25,9 +25,13 @@ http://prefetch.net/articles/linkers.badldlibrary.html The working sample configure sequence I use is: -export LDFLAGS="-R/usr/local/lib" +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 -- cgit v1.2.3 From 302ad02e7781892856c1cacaf98a87f90db9571c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 31 Mar 2010 16:21:58 +0200 Subject: temporary bugfix replaced by permanent one for... ...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. --- ChangeLog | 4 ++++ runtime/msg.c | 9 ++------- runtime/parser.c | 9 +++++++-- tests/testsuites/samples.snare_ccoff_udp2 | 18 +++++++++++------- tools/syslogd.c | 2 +- 5 files changed, 25 insertions(+), 17 deletions(-) diff --git a/ChangeLog b/ChangeLog index 66550cd7..1036e8df 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,10 @@ - bugfix: testbench failed when not executed in UTC+1 timezone accidently, the time zone information was kept inside some to-be-checked-for responses +- temporary bugfix replaced by permanent one for + 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. --------------------------------------------------------------------------- Version 4.6.2 [v4-stable] (rgerhards), 2010-03-26 - new feature: "." action type added to support writing files to relative diff --git a/runtime/msg.c b/runtime/msg.c index 2ce7843a..91057f97 100644 --- a/runtime/msg.c +++ b/runtime/msg.c @@ -2010,6 +2010,8 @@ finalize_it: /* set raw message in message object. Size of message is provided. + * The function makes sure that the stored rawmsg is properly + * terminated by '\0'. * rgerhards, 2009-06-16 */ void MsgSetRawMsg(msg_t *pThis, char* pszRawMsg, size_t lenMsg) @@ -2319,13 +2321,6 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe, *pPropLen = sizeof("**INVALID PROPERTY NAME**") - 1; return UCHAR_CONSTANT("**INVALID PROPERTY NAME**"); } - /* the following line fixes the symptom, but not the root cause -- at least MSG sometimes - * returns a size of one too less. To prevent all troubles, we recalculate the sizes based - * on what we actually got. TODO: remove once root cause is found. - * rgerhards, 2010-03-23 - */ - bufLen = ustrlen(pRes); - /* If we did not receive a template pointer, we are already done... */ if(pTpe == NULL) { diff --git a/runtime/parser.c b/runtime/parser.c index 466066e7..36e88ebd 100644 --- a/runtime/parser.c +++ b/runtime/parser.c @@ -176,7 +176,10 @@ sanitizeMessage(msg_t *pMsg) pszMsg = pMsg->pszRawMsg; lenMsg = pMsg->iLenRawMsg; - /* remove NUL character at end of message (see comment in function header) */ + /* remove NUL character at end of message (see comment in function header) + * Note that we do not need to add a NUL character in this case, because it + * is already present ;) + */ if(pszMsg[lenMsg-1] == '\0') { DBGPRINTF("dropped NUL at very end of message\n"); bUpdatedLen = TRUE; @@ -190,8 +193,9 @@ sanitizeMessage(msg_t *pMsg) */ if(bDropTrailingLF && pszMsg[lenMsg-1] == '\n') { DBGPRINTF("dropped LF at very end of message (DropTrailingLF is set)\n"); - bUpdatedLen = TRUE; lenMsg--; + pszMsg[lenMsg] = '\0'; + bUpdatedLen = TRUE; } /* it is much quicker to sweep over the message and see if it actually @@ -245,6 +249,7 @@ sanitizeMessage(msg_t *pMsg) } ++iSrc; } + pDst[iDst] = '\0'; MsgSetRawMsg(pMsg, (char*)pDst, iDst); /* save sanitized string */ diff --git a/tests/testsuites/samples.snare_ccoff_udp2 b/tests/testsuites/samples.snare_ccoff_udp2 index 7837b820..337cd97c 100644 --- a/tests/testsuites/samples.snare_ccoff_udp2 +++ b/tests/testsuites/samples.snare_ccoff_udp2 @@ -9,14 +9,18 @@ # to be adapted. We do NOT try to preserve misbehaviour on such seriously malformed # messages. # +# this is a very simple test, though not snare-based +test +insert into windows (Message, Facility,FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values ('', 1, 'test',5, '20100321185328', '20100321185328', 1, '') +# and yet another one we have seen in practice +UX=Abcd-efg-hij-klmno; XXXXX=1111111111, Z123=192.12.231.245:11111, S1234=123456789, XXXXXX=111111111 +insert into windows (Message, Facility,FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values (' XXXXX=1111111111, Z123=192.12.231.245:11111, S1234=123456789, XXXXXX=111111111', 1, 'localhost',5, '20100321185328', '20100321185328', 1, 'UX=Abcd-efg-hij-klmno;') # Sample 1 - note the absence of PRI! windowsserver MSWinEventLog 1 Security 1167 Fri Mar 19 15:33:30 2010 540 Security SYSTEM User Success Audit WINDOWSSERVER Logon/Logoff Successful Network Logon: User Name: WINDOWSSERVER$ Domain: DOMX Logon ID: (0x0,0xF88396) Logon Type: 3 Logon Process: Kerberos Authentication Package: Kerberos Workstation Name: Logon GUID: {79b6eb79-7bcc-8a2e-7dad-953c51dc00fd} Caller User Name: - Caller Domain: - Caller Logon ID: - Caller Process ID: - Transited Services: - Source Network Address: 10.11.11.3 Source Port: 3306 733\n -insert into windows (Message, Facility,FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values (' Mar 19 15:33:30 2010 540 Security SYSTEM User Success Audit WINDOWSSERVER Logon/Logoff Successful Network Logon: User Name: WINDOWSSERVER$ Domain: DOMX Logon ID: (0x0,0xF88396) Logon Type: 3 Logon Process: Kerberos Authentication Package: Kerberos Workstation Name: Logon GUID: {79b6eb79-7bcc-8a2e-7dad-953c51dc00fd} Caller User Name: - Caller Domain: - Caller Logon ID: - Caller Process ID: - Transited Services: - Source Network Address: 10.11.11.3 Source Port: 3306 733 ', 1, 'localhost',5, '20100321185328', '20100321185328', 1, 'windowsserver MSWinEventLog 1 Security 1167 Fri') +insert into windows (Message, Facility,FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values (' Mar 19 15:33:30 2010 540 Security SYSTEM User Success Audit WINDOWSSERVER Logon/Logoff Successful Network Logon: User Name: WINDOWSSERVER$ Domain: DOMX Logon ID: (0x0,0xF88396) Logon Type: 3 Logon Process: Kerberos Authentication Package: Kerberos Workstation Name: Logon GUID: {79b6eb79-7bcc-8a2e-7dad-953c51dc00fd} Caller User Name: - Caller Domain: - Caller Logon ID: - Caller Process ID: - Transited Services: - Source Network Address: 10.11.11.3 Source Port: 3306 733', 1, 'localhost',5, '20100321185328', '20100321185328', 1, 'windowsserver MSWinEventLog 1 Security 1167 Fri') # Sample 2 -# the samples below need to be disabled for the "workaround patch" for the message -# parser to work. They need to be re-enabled once a final solution has been crafted -#windowsserver MSWinEventLog 1 Security 1166 Fri Mar 19 15:33:30 2010 576 Security SYSTEM User Success Audit WINDOWSSERVER Logon/Logoff Special privileges assigned to new logon: User Name: WINDOWSSERVER$ Domain: DOMX Logon ID: (0x0,0xF88396) Privileges: SeSecurityPrivilege SeBackupPrivilege SeRestorePrivilege SeTakeOwnershipPrivilege SeDebugPrivilege SeSystemEnvironmentPrivilege SeLoadDriverPrivilege SeImpersonatePrivilege SeEnableDelegationPrivilege 732\n -#insert into windows (Message, Facility,FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values (' Mar 19 15:33:30 2010 576 Security SYSTEM User Success Audit WINDOWSSERVER Logon/Logoff Special privileges assigned to new logon: User Name: WINDOWSSERVER$ Domain: DOMX Logon ID: (0x0,0xF88396) Privileges: SeSecurityPrivilege SeBackupPrivilege SeRestorePrivilege SeTakeOwnershipPrivilege SeDebugPrivilege SeSystemEnvironmentPrivilege SeLoadDriverPrivilege SeImpersonatePrivilege SeEnableDelegationPrivilege 732', 1, 'localhost',5, '20100321185328', '20100321185328', 1, 'windowsserver MSWinEventLog 1 Security 1166 Fri') +windowsserver MSWinEventLog 1 Security 1166 Fri Mar 19 15:33:30 2010 576 Security SYSTEM User Success Audit WINDOWSSERVER Logon/Logoff Special privileges assigned to new logon: User Name: WINDOWSSERVER$ Domain: DOMX Logon ID: (0x0,0xF88396) Privileges: SeSecurityPrivilege SeBackupPrivilege SeRestorePrivilege SeTakeOwnershipPrivilege SeDebugPrivilege SeSystemEnvironmentPrivilege SeLoadDriverPrivilege SeImpersonatePrivilege SeEnableDelegationPrivilege 732\n +insert into windows (Message, Facility,FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values (' Mar 19 15:33:30 2010 576 Security SYSTEM User Success Audit WINDOWSSERVER Logon/Logoff Special privileges assigned to new logon: User Name: WINDOWSSERVER$ Domain: DOMX Logon ID: (0x0,0xF88396) Privileges: SeSecurityPrivilege SeBackupPrivilege SeRestorePrivilege SeTakeOwnershipPrivilege SeDebugPrivilege SeSystemEnvironmentPrivilege SeLoadDriverPrivilege SeImpersonatePrivilege SeEnableDelegationPrivilege 732', 1, 'localhost',5, '20100321185328', '20100321185328', 1, 'windowsserver MSWinEventLog 1 Security 1166 Fri') # Sample 3 -#windowsserver MSWinEventLog 1 Security 1165 Fri Mar 19 15:33:30 2010 538 Security SYSTEM User Success Audit WINDOWSSERVER Logon/Logoff User Logoff: User Name: WINDOWSSERVER$ Domain: DOMX Logon ID: (0x0,0xF8830B) Logon Type: 3 731\n -#insert into windows (Message, Facility,FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values (' Mar 19 15:33:30 2010 538 Security SYSTEM User Success Audit WINDOWSSERVER Logon/Logoff User Logoff: User Name: WINDOWSSERVER$ Domain: DOMX Logon ID: (0x0,0xF8830B) Logon Type: 3 731', 1, 'localhost',5, '20100321185328', '20100321185328', 1, 'windowsserver MSWinEventLog 1 Security 1165 Fri') +windowsserver MSWinEventLog 1 Security 1165 Fri Mar 19 15:33:30 2010 538 Security SYSTEM User Success Audit WINDOWSSERVER Logon/Logoff User Logoff: User Name: WINDOWSSERVER$ Domain: DOMX Logon ID: (0x0,0xF8830B) Logon Type: 3 731\n +insert into windows (Message, Facility,FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values (' Mar 19 15:33:30 2010 538 Security SYSTEM User Success Audit WINDOWSSERVER Logon/Logoff User Logoff: User Name: WINDOWSSERVER$ Domain: DOMX Logon ID: (0x0,0xF8830B) Logon Type: 3 731', 1, 'localhost',5, '20100321185328', '20100321185328', 1, 'windowsserver MSWinEventLog 1 Security 1165 Fri') diff --git a/tools/syslogd.c b/tools/syslogd.c index 64b23566..a03dcf0e 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -792,7 +792,7 @@ parseAndSubmitMessage(uchar *hname, uchar *hnameIP, uchar *msg, int len, int fla * (I couldn't do any more smart things anyway...). * rgerhards, 2007-9-20 */ - DBGPRINTF("internal error: iMsg > max msg size in printchopped()\n"); + DBGPRINTF("internal error: iMsg > max msg size in parseAndSubmitMessage()\n"); } FINALIZE; /* in this case, we are done... nothing left we can do */ } -- cgit v1.2.3 From 1cba2162201e98a4a24a3eb19d168c81adf1bbd2 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 1 Apr 2010 15:11:16 +0200 Subject: improvded testbench: added test with truly random data received via syslog to test robustness --- ChangeLog | 3 + tests/Makefile.am | 8 ++- tests/diag.sh | 4 +- tests/random.sh | 20 ++++++ tests/randomgen.c | 130 +++++++++++++++++++++++++++++++++++++++ tests/tcpflood.c | 142 +++++++++++++++++++++++++++++++++---------- tests/testsuites/random.conf | 13 ++++ 7 files changed, 284 insertions(+), 36 deletions(-) create mode 100755 tests/random.sh create mode 100644 tests/randomgen.c create mode 100644 tests/testsuites/random.conf diff --git a/ChangeLog b/ChangeLog index 1036e8df..c662d66d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +- improvded testbench + - added test with truly random data received via syslog to test + robustness - bugfix: testbench failed when not executed in UTC+1 timezone accidently, the time zone information was kept inside some to-be-checked-for responses diff --git a/tests/Makefile.am b/tests/Makefile.am index 42ef32e3..76ed694a 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,6 +1,6 @@ if ENABLE_TESTBENCH TESTRUNS = rt_init rscript -check_PROGRAMS = $(TESTRUNS) ourtail nettester tcpflood chkseq +check_PROGRAMS = $(TESTRUNS) ourtail nettester tcpflood chkseq randomgen TESTS = $(TESTRUNS) cfg.sh \ validation-run.sh \ imtcp-multiport.sh \ @@ -24,6 +24,7 @@ TESTS = $(TESTRUNS) cfg.sh \ dynfile_invld_sync.sh \ dynfile_invalid2.sh \ complex1.sh \ + random.sh \ queue-persist.sh \ pipeaction.sh execonlyonce.sh \ @@ -180,6 +181,8 @@ EXTRA_DIST= 1.rstest 2.rstest 3.rstest err1.rstest \ testsuites/gzipwr_large_dynfile.conf \ complex1.sh \ testsuites/complex1.conf \ + random.sh \ + testsuites/random.conf \ dynfile_invld_async.sh \ dynfile_invld_sync.sh \ dynfile_cachemiss.sh \ @@ -203,6 +206,9 @@ chkseq_SOURCES = chkseq.c tcpflood_SOURCES = tcpflood.c tcpflood_LDADD = $(SOL_LIBS) +randomgen_SOURCES = randomgen.c +randomgen_LDADD = $(SOL_LIBS) + nettester_SOURCES = nettester.c getline.c nettester_LDADD = $(SOL_LIBS) diff --git a/tests/diag.sh b/tests/diag.sh index 8f268a5e..2a0e2a44 100755 --- a/tests/diag.sh +++ b/tests/diag.sh @@ -17,7 +17,7 @@ case $1 in cp $srcdir/testsuites/diag-common.conf diag-common.conf cp $srcdir/testsuites/diag-common2.conf diag-common2.conf rm -f rsyslog.action.*.include - rm -f rsyslogd.started work-*.conf + rm -f rsyslogd.started work-*.conf rsyslog.random.data rm -f rsyslogd2.started work-*.conf rm -f work rsyslog.out.log rsyslog.out.log.save # common work files rm -f rsyslog.out.*.log @@ -28,7 +28,7 @@ case $1 in 'exit') rm -f rsyslogd.started work-*.conf diag-common.conf rm -f rsyslogd2.started diag-common2.conf rsyslog.action.*.include rm -f work rsyslog.out.log rsyslog.out.log.save # common work files - rm -f rsyslog.out.*.log + rm -f rsyslog.out.*.log rsyslog.random.data rm -rf test-spool ;; 'startup') # start rsyslogd with default params. $2 is the config file name to use diff --git a/tests/random.sh b/tests/random.sh new file mode 100755 index 00000000..79f704c7 --- /dev/null +++ b/tests/random.sh @@ -0,0 +1,20 @@ +# Test if rsyslog survives sending truely random data to it... +# +# added 2010-04-01 by Rgerhards +# This file is part of the rsyslog project, released under GPLv3 +echo =============================================================================== +echo TEST: \[random.sh\]: testing random data +source $srcdir/diag.sh init +# uncomment for debugging support: +#export RSYSLOG_DEBUG="debug nostdout noprintmutexaction" +#export RSYSLOG_DEBUGLOG="log" +source $srcdir/diag.sh startup random.conf +# generate random data +./randomgen -f rsyslog.random.data -s 100000 +ls -l rsyslog.random.data +source $srcdir/diag.sh tcpflood -B -I rsyslog.random.data -c5 -C10 +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 +# we do not check anything yet, the point is if rsyslog survived ;) +# TODO: check for exit message, but we'll notice an abort anyhow, so not that important +#source $srcdir/diag.sh exit diff --git a/tests/randomgen.c b/tests/randomgen.c new file mode 100644 index 00000000..9ba56954 --- /dev/null +++ b/tests/randomgen.c @@ -0,0 +1,130 @@ +/* generates random data for later use in test cases. Of course, + * we could generate random data during the testcase itself, but + * the core idea is that we record the random data so that we have + * a chance to reproduce a problem should it occur. IMHO this + * provides the best compromise, by a) having randomness but + * b) knowing what was used during the test. + * + * Params + * -f output file name (stdout if not given) + * -s size of test data, plain number is size in k, 1MB default + * -u uses /dev/urandom instead of libc random number generator + * (when available). Note that this is usually much slower. + * + * 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 . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define EXIT_FAILURE 1 + +static char *fileName = NULL; /* name of output file */ +static int tryUseURandom = 0; /* try to use /dev/urandom? */ +static long long fileSize = 1024*1024; /* file size in K, 1MB default */ + + +/* generate the random file. This code really can be improved (e.g. read /dev/urandom + * when available) + */ +static inline void +genFile() +{ + long i; + FILE *fp; + FILE *rfp = NULL; + + if(fileName == NULL) { + fp = stdout; + } else { + if((fp = fopen(fileName, "w")) == NULL) { + perror(fileName); + } + } + + /* try to use /dev/urandom, if available */ + if(tryUseURandom) + rfp = fopen("/dev/urandom", "r"); + + if(rfp == NULL) { + /* fallback, use libc random number generator */ + for(i = 0 ; i < fileSize ; ++i) { + if(fputc((char) rand(), fp) == EOF) { + perror(fileName); + exit(1); + } + } + } else { + /* use /dev/urandom */ + printf("using /dev/urandom"); + for(i = 0 ; i < fileSize ; ++i) { + if(fputc(fgetc(rfp), fp) == EOF) { + perror(fileName); + exit(1); + } + } + } + + if(fileName != NULL) + fclose(fp); +} + + +/* Run the test. + * rgerhards, 2009-04-03 + */ +int main(int argc, char *argv[]) +{ + int ret = 0; + int opt; + + srand(time(NULL)); /* seed is good enough for our needs */ + + while((opt = getopt(argc, argv, "f:s:u")) != -1) { + switch (opt) { + case 'f': fileName = optarg; + break; + case 's': fileSize = atol(optarg) * 1024; + break; + case 'u': tryUseURandom = 1; + break; + default: printf("invalid option '%c' or value missing - terminating...\n", opt); + exit (1); + break; + } + } + + printf("generating random data file '%s' of %ldkb - may take a short while...\n", + fileName, (long) (fileSize / 1024)); + genFile(); + + exit(ret); +} diff --git a/tests/tcpflood.c b/tests/tcpflood.c index 32bf959d..d8c3f038 100644 --- a/tests/tcpflood.c +++ b/tests/tcpflood.c @@ -20,6 +20,14 @@ * one field to the right. Zero (default) disables this functionality. * -M the message to be sent. Disables all message format options, as * only that exact same message is sent. + * -I read specified input file, do NOT generate own test data. The test + * completes when eof is reached. + * -B The specified file (-I) is binary. No data processing is done by + * tcpflood. If multiple connections are specified, data is read in + * chunks and spread across the connections without taking any record + * delemiters into account. + * -C when input from a file is read, this file is transmitted -C times + * (C like cycle, running out of meaningful option switches ;)) * * Part of the testbench for rsyslog. * @@ -75,6 +83,10 @@ static int *sockArray; /* array of sockets to use */ static int msgNum = 0; /* initial message number to start with */ static int bShowProgress = 1; /* show progress messages */ static char *MsgToSend = NULL; /* if non-null, this is the actual message to send */ +static int bBinaryFile = 0; /* is -I file binary */ +static char *dataFile = NULL; /* name of data file, if NULL, generate own data */ +static int numFileIterations = 1;/* how often is file data to be sent? */ +FILE *dataFP = NULL; /* file pointer for data file, if used */ /* open a single tcp connection @@ -166,8 +178,8 @@ int openConnections(void) void closeConnections(void) { int i; - char msgBuf[128]; size_t lenMsg; + char msgBuf[128]; if(bShowProgress) write(1, " close connections", sizeof(" close connections")-1); @@ -186,6 +198,62 @@ void closeConnections(void) } +/* generate the message to be sent according to program command line parameters. + * this has been moved to its own function as we now have various different ways + * of constructing test messages. -- rgerhards, 2010-03-31 + */ +static inline void +genMsg(char *buf, size_t maxBuf, int *pLenBuf) +{ + int edLen; /* actual extra data length to use */ + char extraData[MAX_EXTRADATA_LEN + 1]; + char dynFileIDBuf[128] = ""; + static int numMsgsGen = 0; + int done; + + if(dataFP != NULL) { + /* get message from file */ + do { + done = 1; + *pLenBuf = fread(buf, 1, 1024, dataFP); + if(feof(dataFP)) { + if(--numFileIterations > 0) { + rewind(dataFP); + done = 0; /* need new iteration */ + } else { + *pLenBuf = 0; + goto finalize_it; + } + } + } while(!done); /* Attention: do..while()! */ + } else if(MsgToSend == NULL) { + if(dynFileIDs > 0) { + snprintf(dynFileIDBuf, maxBuf, "%d:", rand() % dynFileIDs); + } + if(extraDataLen == 0) { + *pLenBuf = snprintf(buf, maxBuf, "<%s>Mar 1 01:00:00 172.20.245.8 tag msgnum:%s%8.8d:\n", + msgPRI, dynFileIDBuf, msgNum); + } else { + if(bRandomizeExtraData) + edLen = ((long) rand() + extraDataLen) % extraDataLen + 1; + else + edLen = extraDataLen; + memset(extraData, 'X', edLen); + extraData[edLen] = '\0'; + *pLenBuf = snprintf(buf, maxBuf, "<%s>Mar 1 01:00:00 172.20.245.8 tag msgnum:%s%8.8d:%d:%s\n", + msgPRI, dynFileIDBuf, msgNum, edLen, extraData); + } + } else { + /* use fixed message format from command line */ + *pLenBuf = snprintf(buf, maxBuf, "%s\n", MsgToSend); + } + + if(numMsgsGen++ >= numMsgsToSend) + *pLenBuf = 0; /* indicate end of run */ + +finalize_it: ; +} + /* send messages to the tcp connections we keep open. We use * a very basic format that helps identify the message * (via msgnum:: e.g. msgnum:00000001:). This format is suitable @@ -196,52 +264,42 @@ void closeConnections(void) */ int sendMessages(void) { - int i; + int i = 0; int socknum; int lenBuf; int lenSend; - int edLen; /* actual extra data length to use */ - char dynFileIDBuf[128] = ""; + char *statusText; char buf[MAX_EXTRADATA_LEN + 1024]; - char extraData[MAX_EXTRADATA_LEN + 1]; - printf("Sending %d messages.\n", numMsgsToSend); + if(dataFile == NULL) { + printf("Sending %d messages.\n", numMsgsToSend); + statusText = "messages"; + } else { + printf("Sending file '%s' %d times.\n", dataFile, numFileIterations); + statusText = "kb"; + } if(bShowProgress) - printf("\r%8.8d messages sent", 0); - for(i = 0 ; i < numMsgsToSend ; ++i) { + printf("\r%8.8d %s sent", 0, statusText); + while(1) { /* broken inside loop! */ if(i < numConnections) socknum = i; else if(i >= numMsgsToSend - numConnections) socknum = i - (numMsgsToSend - numConnections); - else - socknum = rand() % numConnections; - if(MsgToSend == NULL) { - if(dynFileIDs > 0) { - sprintf(dynFileIDBuf, "%d:", rand() % dynFileIDs); - } - if(extraDataLen == 0) { - lenBuf = sprintf(buf, "<%s>Mar 1 01:00:00 172.20.245.8 tag msgnum:%s%8.8d:\n", - msgPRI, dynFileIDBuf, msgNum); - } else { - if(bRandomizeExtraData) - edLen = ((long) rand() + extraDataLen) % extraDataLen + 1; - else - edLen = extraDataLen; - memset(extraData, 'X', edLen); - extraData[edLen] = '\0'; - lenBuf = sprintf(buf, "<%s>Mar 1 01:00:00 172.20.245.8 tag msgnum:%s%8.8d:%d:%s\n", - msgPRI, dynFileIDBuf, msgNum, edLen, extraData); - } - } else { - /* use fixed message format from command line */ - lenBuf = sprintf(buf, "%s\n", MsgToSend); + else { + int rnd = rand(); + //socknum = rand() % numConnections; + socknum = rnd % numConnections; } + genMsg(buf, sizeof(buf), &lenBuf); /* generate the message to send according to params */ + if(lenBuf == 0) + break; /* end of processing! */ lenSend = send(sockArray[socknum], buf, lenBuf, 0); if(lenSend != lenBuf) { printf("\r%5.5d\n", i); fflush(stdout); perror("send test data"); - printf("send() failed at socket %d, index %d, msgNum %d\n", socknum, i, msgNum); + printf("send() failed at socket %d, index %d, msgNum %d\n", + sockArray[socknum], i, msgNum); fflush(stderr); return(1); } @@ -250,8 +308,9 @@ int sendMessages(void) printf("\r%8.8d", i); } ++msgNum; + ++i; } - printf("\r%8.8d messages sent\n", i); + printf("\r%8.8d %s sent\n", i, statusText); return 0; } @@ -335,7 +394,7 @@ int main(int argc, char *argv[]) if(!isatty(1)) bShowProgress = 0; - while((opt = getopt(argc, argv, "f:t:p:c:m:i:P:d:n:M:r")) != -1) { + 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; @@ -345,6 +404,8 @@ int main(int argc, char *argv[]) break; case 'c': numConnections = atoi(optarg); break; + case 'C': numFileIterations = atoi(optarg); + break; case 'm': numMsgsToSend = atoi(optarg); break; case 'i': msgNum = atoi(optarg); @@ -364,12 +425,27 @@ int main(int argc, char *argv[]) break; case 'M': MsgToSend = optarg; break; + case 'I': dataFile = optarg; + /* in this mode, we do not know the num messages to send, so + * we set a (high) number to keep the code happy. + */ + numMsgsToSend = 1000000; + break; + case 'B': bBinaryFile = 1; + break; default: printf("invalid option '%c' or value missing - terminating...\n", opt); exit (1); break; } } + if(dataFile != NULL) { + if((dataFP = fopen(dataFile, "r")) == NULL) { + perror(dataFile); + exit(1); + } + } + if(openConnections() != 0) { printf("error opening connections\n"); exit(1); diff --git a/tests/testsuites/random.conf b/tests/testsuites/random.conf new file mode 100644 index 00000000..a7079df1 --- /dev/null +++ b/tests/testsuites/random.conf @@ -0,0 +1,13 @@ +# we write to /dev/null, as we have no chance to verify the output +# in any case. What we really check is that rsyslogd does not +# segfault or otherwise abort. +# rgerhards, 2010-04-01 +$IncludeConfig diag-common.conf + +$ModLoad ../plugins/imtcp/.libs/imtcp +$MainMsgQueueTimeoutShutdown 10000 +$InputTCPServerRun 13514 + +$template outfmt,"%rawmsg%\n" +$template dynfile,"rsyslog.out.log" # trick to use relative path names! +*.* /dev/null -- cgit v1.2.3 From 23a3fdb094cd992b2081db014d583b975c03ca57 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 1 Apr 2010 15:16:05 +0200 Subject: git "bugfix": added file previously forgotten --- plugins/imklog/solaris_cddl.h | 1 + 1 file changed, 1 insertion(+) create mode 100644 plugins/imklog/solaris_cddl.h diff --git a/plugins/imklog/solaris_cddl.h b/plugins/imklog/solaris_cddl.h new file mode 100644 index 00000000..22295658 --- /dev/null +++ b/plugins/imklog/solaris_cddl.h @@ -0,0 +1 @@ +int sun_openklog(char *name, int mode); -- cgit v1.2.3 From 2cd132eebb84dbcffcf0c20b9354c14f797c29cd Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 7 Apr 2010 12:42:41 +0200 Subject: enhanced nettester tool so that it re-uses it's callers environment this enables us to work with the "usual" environment tweaks (for debugging and other purposes), without the need for any special handling in nettester itself --- ChangeLog | 7 ++ runtime/msg.c | 9 +- runtime/parser.c | 9 +- tests/Makefile.am | 8 +- tests/diag.sh | 4 +- tests/nettester.c | 13 +-- tests/random.sh | 20 +++++ tests/randomgen.c | 130 +++++++++++++++++++++++++++ tests/rt-init.c | 2 +- tests/tcpflood.c | 142 +++++++++++++++++++++++------- tests/testsuites/random.conf | 13 +++ tests/testsuites/samples.snare_ccoff_udp2 | 18 ++-- tools/syslogd.c | 2 +- 13 files changed, 314 insertions(+), 63 deletions(-) create mode 100755 tests/random.sh create mode 100644 tests/randomgen.c create mode 100644 tests/testsuites/random.conf diff --git a/ChangeLog b/ChangeLog index 131539a5..dce06dfc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,13 @@ +- improvded testbench + - added test with truly random data received via syslog to test + robustness - bugfix: testbench failed when not executed in UTC+1 timezone accidently, the time zone information was kept inside some to-be-checked-for responses +- temporary bugfix replaced by permanent one for + 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. --------------------------------------------------------------------------- Version 4.6.3 [v4-stable] (rgerhards), 2010-03-?? - bugfix: local unix system log socket was deleted even when it was diff --git a/runtime/msg.c b/runtime/msg.c index 2ce7843a..91057f97 100644 --- a/runtime/msg.c +++ b/runtime/msg.c @@ -2010,6 +2010,8 @@ finalize_it: /* set raw message in message object. Size of message is provided. + * The function makes sure that the stored rawmsg is properly + * terminated by '\0'. * rgerhards, 2009-06-16 */ void MsgSetRawMsg(msg_t *pThis, char* pszRawMsg, size_t lenMsg) @@ -2319,13 +2321,6 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe, *pPropLen = sizeof("**INVALID PROPERTY NAME**") - 1; return UCHAR_CONSTANT("**INVALID PROPERTY NAME**"); } - /* the following line fixes the symptom, but not the root cause -- at least MSG sometimes - * returns a size of one too less. To prevent all troubles, we recalculate the sizes based - * on what we actually got. TODO: remove once root cause is found. - * rgerhards, 2010-03-23 - */ - bufLen = ustrlen(pRes); - /* If we did not receive a template pointer, we are already done... */ if(pTpe == NULL) { diff --git a/runtime/parser.c b/runtime/parser.c index 466066e7..36e88ebd 100644 --- a/runtime/parser.c +++ b/runtime/parser.c @@ -176,7 +176,10 @@ sanitizeMessage(msg_t *pMsg) pszMsg = pMsg->pszRawMsg; lenMsg = pMsg->iLenRawMsg; - /* remove NUL character at end of message (see comment in function header) */ + /* remove NUL character at end of message (see comment in function header) + * Note that we do not need to add a NUL character in this case, because it + * is already present ;) + */ if(pszMsg[lenMsg-1] == '\0') { DBGPRINTF("dropped NUL at very end of message\n"); bUpdatedLen = TRUE; @@ -190,8 +193,9 @@ sanitizeMessage(msg_t *pMsg) */ if(bDropTrailingLF && pszMsg[lenMsg-1] == '\n') { DBGPRINTF("dropped LF at very end of message (DropTrailingLF is set)\n"); - bUpdatedLen = TRUE; lenMsg--; + pszMsg[lenMsg] = '\0'; + bUpdatedLen = TRUE; } /* it is much quicker to sweep over the message and see if it actually @@ -245,6 +249,7 @@ sanitizeMessage(msg_t *pMsg) } ++iSrc; } + pDst[iDst] = '\0'; MsgSetRawMsg(pMsg, (char*)pDst, iDst); /* save sanitized string */ diff --git a/tests/Makefile.am b/tests/Makefile.am index 7ca40766..53ca9cb0 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,6 +1,6 @@ if ENABLE_TESTBENCH TESTRUNS = rt_init rscript -check_PROGRAMS = $(TESTRUNS) ourtail nettester tcpflood chkseq msleep +check_PROGRAMS = $(TESTRUNS) ourtail nettester tcpflood chkseq msleep randomgen TESTS = $(TESTRUNS) cfg.sh \ validation-run.sh \ imtcp-multiport.sh \ @@ -24,6 +24,7 @@ TESTS = $(TESTRUNS) cfg.sh \ dynfile_invld_sync.sh \ dynfile_invalid2.sh \ complex1.sh \ + random.sh \ queue-persist.sh \ pipeaction.sh execonlyonce.sh \ @@ -180,6 +181,8 @@ EXTRA_DIST= 1.rstest 2.rstest 3.rstest err1.rstest \ testsuites/gzipwr_large_dynfile.conf \ complex1.sh \ testsuites/complex1.conf \ + random.sh \ + testsuites/random.conf \ dynfile_invld_async.sh \ dynfile_invld_sync.sh \ dynfile_cachemiss.sh \ @@ -204,6 +207,9 @@ chkseq_SOURCES = chkseq.c tcpflood_SOURCES = tcpflood.c tcpflood_LDADD = $(SOL_LIBS) +randomgen_SOURCES = randomgen.c +randomgen_LDADD = $(SOL_LIBS) + nettester_SOURCES = nettester.c getline.c nettester_LDADD = $(SOL_LIBS) diff --git a/tests/diag.sh b/tests/diag.sh index c0f736b8..2cc652ad 100755 --- a/tests/diag.sh +++ b/tests/diag.sh @@ -17,7 +17,7 @@ case $1 in cp $srcdir/testsuites/diag-common.conf diag-common.conf cp $srcdir/testsuites/diag-common2.conf diag-common2.conf rm -f rsyslog.action.*.include - rm -f rsyslogd.started work-*.conf + rm -f rsyslogd.started work-*.conf rsyslog.random.data rm -f rsyslogd2.started work-*.conf rm -f work rsyslog.out.log rsyslog.out.log.save # common work files rm -f rsyslog.out.*.log @@ -28,7 +28,7 @@ case $1 in 'exit') rm -f rsyslogd.started work-*.conf diag-common.conf rm -f rsyslogd2.started diag-common2.conf rsyslog.action.*.include rm -f work rsyslog.out.log rsyslog.out.log.save # common work files - rm -f rsyslog.out.*.log + rm -f rsyslog.out.*.log rsyslog.random.data rm -rf test-spool ;; 'startup') # start rsyslogd with default params. $2 is the config file name to use diff --git a/tests/nettester.c b/tests/nettester.c index e1ecbcb5..eff5929b 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; @@ -218,9 +218,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,7 +240,7 @@ 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 { close(pipefd[1]); *pid = cpid; @@ -450,7 +447,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 +456,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; diff --git a/tests/random.sh b/tests/random.sh new file mode 100755 index 00000000..79f704c7 --- /dev/null +++ b/tests/random.sh @@ -0,0 +1,20 @@ +# Test if rsyslog survives sending truely random data to it... +# +# added 2010-04-01 by Rgerhards +# This file is part of the rsyslog project, released under GPLv3 +echo =============================================================================== +echo TEST: \[random.sh\]: testing random data +source $srcdir/diag.sh init +# uncomment for debugging support: +#export RSYSLOG_DEBUG="debug nostdout noprintmutexaction" +#export RSYSLOG_DEBUGLOG="log" +source $srcdir/diag.sh startup random.conf +# generate random data +./randomgen -f rsyslog.random.data -s 100000 +ls -l rsyslog.random.data +source $srcdir/diag.sh tcpflood -B -I rsyslog.random.data -c5 -C10 +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 +# we do not check anything yet, the point is if rsyslog survived ;) +# TODO: check for exit message, but we'll notice an abort anyhow, so not that important +#source $srcdir/diag.sh exit diff --git a/tests/randomgen.c b/tests/randomgen.c new file mode 100644 index 00000000..9ba56954 --- /dev/null +++ b/tests/randomgen.c @@ -0,0 +1,130 @@ +/* generates random data for later use in test cases. Of course, + * we could generate random data during the testcase itself, but + * the core idea is that we record the random data so that we have + * a chance to reproduce a problem should it occur. IMHO this + * provides the best compromise, by a) having randomness but + * b) knowing what was used during the test. + * + * Params + * -f output file name (stdout if not given) + * -s size of test data, plain number is size in k, 1MB default + * -u uses /dev/urandom instead of libc random number generator + * (when available). Note that this is usually much slower. + * + * 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 . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define EXIT_FAILURE 1 + +static char *fileName = NULL; /* name of output file */ +static int tryUseURandom = 0; /* try to use /dev/urandom? */ +static long long fileSize = 1024*1024; /* file size in K, 1MB default */ + + +/* generate the random file. This code really can be improved (e.g. read /dev/urandom + * when available) + */ +static inline void +genFile() +{ + long i; + FILE *fp; + FILE *rfp = NULL; + + if(fileName == NULL) { + fp = stdout; + } else { + if((fp = fopen(fileName, "w")) == NULL) { + perror(fileName); + } + } + + /* try to use /dev/urandom, if available */ + if(tryUseURandom) + rfp = fopen("/dev/urandom", "r"); + + if(rfp == NULL) { + /* fallback, use libc random number generator */ + for(i = 0 ; i < fileSize ; ++i) { + if(fputc((char) rand(), fp) == EOF) { + perror(fileName); + exit(1); + } + } + } else { + /* use /dev/urandom */ + printf("using /dev/urandom"); + for(i = 0 ; i < fileSize ; ++i) { + if(fputc(fgetc(rfp), fp) == EOF) { + perror(fileName); + exit(1); + } + } + } + + if(fileName != NULL) + fclose(fp); +} + + +/* Run the test. + * rgerhards, 2009-04-03 + */ +int main(int argc, char *argv[]) +{ + int ret = 0; + int opt; + + srand(time(NULL)); /* seed is good enough for our needs */ + + while((opt = getopt(argc, argv, "f:s:u")) != -1) { + switch (opt) { + case 'f': fileName = optarg; + break; + case 's': fileSize = atol(optarg) * 1024; + break; + case 'u': tryUseURandom = 1; + break; + default: printf("invalid option '%c' or value missing - terminating...\n", opt); + exit (1); + break; + } + } + + printf("generating random data file '%s' of %ldkb - may take a short while...\n", + fileName, (long) (fileSize / 1024)); + genFile(); + + exit(ret); +} 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 68c1c097..e92d1308 100644 --- a/tests/tcpflood.c +++ b/tests/tcpflood.c @@ -20,6 +20,14 @@ * one field to the right. Zero (default) disables this functionality. * -M the message to be sent. Disables all message format options, as * only that exact same message is sent. + * -I read specified input file, do NOT generate own test data. The test + * completes when eof is reached. + * -B The specified file (-I) is binary. No data processing is done by + * tcpflood. If multiple connections are specified, data is read in + * chunks and spread across the connections without taking any record + * delemiters into account. + * -C when input from a file is read, this file is transmitted -C times + * (C like cycle, running out of meaningful option switches ;)) * * Part of the testbench for rsyslog. * @@ -76,6 +84,10 @@ static int *sockArray; /* array of sockets to use */ static int msgNum = 0; /* initial message number to start with */ static int bShowProgress = 1; /* show progress messages */ static char *MsgToSend = NULL; /* if non-null, this is the actual message to send */ +static int bBinaryFile = 0; /* is -I file binary */ +static char *dataFile = NULL; /* name of data file, if NULL, generate own data */ +static int numFileIterations = 1;/* how often is file data to be sent? */ +FILE *dataFP = NULL; /* file pointer for data file, if used */ /* open a single tcp connection @@ -167,8 +179,8 @@ int openConnections(void) void closeConnections(void) { int i; - char msgBuf[128]; size_t lenMsg; + char msgBuf[128]; if(bShowProgress) write(1, " close connections", sizeof(" close connections")-1); @@ -187,6 +199,62 @@ void closeConnections(void) } +/* generate the message to be sent according to program command line parameters. + * this has been moved to its own function as we now have various different ways + * of constructing test messages. -- rgerhards, 2010-03-31 + */ +static inline void +genMsg(char *buf, size_t maxBuf, int *pLenBuf) +{ + int edLen; /* actual extra data length to use */ + char extraData[MAX_EXTRADATA_LEN + 1]; + char dynFileIDBuf[128] = ""; + static int numMsgsGen = 0; + int done; + + if(dataFP != NULL) { + /* get message from file */ + do { + done = 1; + *pLenBuf = fread(buf, 1, 1024, dataFP); + if(feof(dataFP)) { + if(--numFileIterations > 0) { + rewind(dataFP); + done = 0; /* need new iteration */ + } else { + *pLenBuf = 0; + goto finalize_it; + } + } + } while(!done); /* Attention: do..while()! */ + } else if(MsgToSend == NULL) { + if(dynFileIDs > 0) { + snprintf(dynFileIDBuf, maxBuf, "%d:", rand() % dynFileIDs); + } + if(extraDataLen == 0) { + *pLenBuf = snprintf(buf, maxBuf, "<%s>Mar 1 01:00:00 172.20.245.8 tag msgnum:%s%8.8d:\n", + msgPRI, dynFileIDBuf, msgNum); + } else { + if(bRandomizeExtraData) + edLen = ((long) rand() + extraDataLen) % extraDataLen + 1; + else + edLen = extraDataLen; + memset(extraData, 'X', edLen); + extraData[edLen] = '\0'; + *pLenBuf = snprintf(buf, maxBuf, "<%s>Mar 1 01:00:00 172.20.245.8 tag msgnum:%s%8.8d:%d:%s\n", + msgPRI, dynFileIDBuf, msgNum, edLen, extraData); + } + } else { + /* use fixed message format from command line */ + *pLenBuf = snprintf(buf, maxBuf, "%s\n", MsgToSend); + } + + if(numMsgsGen++ >= numMsgsToSend) + *pLenBuf = 0; /* indicate end of run */ + +finalize_it: ; +} + /* send messages to the tcp connections we keep open. We use * a very basic format that helps identify the message * (via msgnum:: e.g. msgnum:00000001:). This format is suitable @@ -197,52 +265,42 @@ void closeConnections(void) */ int sendMessages(void) { - int i; + int i = 0; int socknum; int lenBuf; int lenSend; - int edLen; /* actual extra data length to use */ - char dynFileIDBuf[128] = ""; + char *statusText; char buf[MAX_EXTRADATA_LEN + 1024]; - char extraData[MAX_EXTRADATA_LEN + 1]; - printf("Sending %d messages.\n", numMsgsToSend); + if(dataFile == NULL) { + printf("Sending %d messages.\n", numMsgsToSend); + statusText = "messages"; + } else { + printf("Sending file '%s' %d times.\n", dataFile, numFileIterations); + statusText = "kb"; + } if(bShowProgress) - printf("\r%8.8d messages sent", 0); - for(i = 0 ; i < numMsgsToSend ; ++i) { + printf("\r%8.8d %s sent", 0, statusText); + while(1) { /* broken inside loop! */ if(i < numConnections) socknum = i; else if(i >= numMsgsToSend - numConnections) socknum = i - (numMsgsToSend - numConnections); - else - socknum = rand() % numConnections; - if(MsgToSend == NULL) { - if(dynFileIDs > 0) { - sprintf(dynFileIDBuf, "%d:", rand() % dynFileIDs); - } - if(extraDataLen == 0) { - lenBuf = sprintf(buf, "<%s>Mar 1 01:00:00 172.20.245.8 tag msgnum:%s%8.8d:\n", - msgPRI, dynFileIDBuf, msgNum); - } else { - if(bRandomizeExtraData) - edLen = ((long) rand() + extraDataLen) % extraDataLen + 1; - else - edLen = extraDataLen; - memset(extraData, 'X', edLen); - extraData[edLen] = '\0'; - lenBuf = sprintf(buf, "<%s>Mar 1 01:00:00 172.20.245.8 tag msgnum:%s%8.8d:%d:%s\n", - msgPRI, dynFileIDBuf, msgNum, edLen, extraData); - } - } else { - /* use fixed message format from command line */ - lenBuf = sprintf(buf, "%s\n", MsgToSend); + else { + int rnd = rand(); + //socknum = rand() % numConnections; + socknum = rnd % numConnections; } + genMsg(buf, sizeof(buf), &lenBuf); /* generate the message to send according to params */ + if(lenBuf == 0) + break; /* end of processing! */ lenSend = send(sockArray[socknum], buf, lenBuf, 0); if(lenSend != lenBuf) { printf("\r%5.5d\n", i); fflush(stdout); perror("send test data"); - printf("send() failed at socket %d, index %d, msgNum %d\n", socknum, i, msgNum); + printf("send() failed at socket %d, index %d, msgNum %d\n", + sockArray[socknum], i, msgNum); fflush(stderr); return(1); } @@ -251,8 +309,9 @@ int sendMessages(void) printf("\r%8.8d", i); } ++msgNum; + ++i; } - printf("\r%8.8d messages sent\n", i); + printf("\r%8.8d %s sent\n", i, statusText); return 0; } @@ -336,7 +395,7 @@ int main(int argc, char *argv[]) if(!isatty(1)) bShowProgress = 0; - while((opt = getopt(argc, argv, "f:t:p:c:m:i:P:d:n:M:r")) != -1) { + 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; @@ -346,6 +405,8 @@ int main(int argc, char *argv[]) break; case 'c': numConnections = atoi(optarg); break; + case 'C': numFileIterations = atoi(optarg); + break; case 'm': numMsgsToSend = atoi(optarg); break; case 'i': msgNum = atoi(optarg); @@ -365,6 +426,14 @@ int main(int argc, char *argv[]) break; case 'M': MsgToSend = optarg; break; + case 'I': dataFile = optarg; + /* in this mode, we do not know the num messages to send, so + * we set a (high) number to keep the code happy. + */ + numMsgsToSend = 1000000; + break; + case 'B': bBinaryFile = 1; + break; default: printf("invalid option '%c' or value missing - terminating...\n", opt); exit (1); break; @@ -385,6 +454,13 @@ int main(int argc, char *argv[]) } } + if(dataFile != NULL) { + if((dataFP = fopen(dataFile, "r")) == NULL) { + perror(dataFile); + exit(1); + } + } + if(openConnections() != 0) { printf("error opening connections\n"); exit(1); diff --git a/tests/testsuites/random.conf b/tests/testsuites/random.conf new file mode 100644 index 00000000..a7079df1 --- /dev/null +++ b/tests/testsuites/random.conf @@ -0,0 +1,13 @@ +# we write to /dev/null, as we have no chance to verify the output +# in any case. What we really check is that rsyslogd does not +# segfault or otherwise abort. +# rgerhards, 2010-04-01 +$IncludeConfig diag-common.conf + +$ModLoad ../plugins/imtcp/.libs/imtcp +$MainMsgQueueTimeoutShutdown 10000 +$InputTCPServerRun 13514 + +$template outfmt,"%rawmsg%\n" +$template dynfile,"rsyslog.out.log" # trick to use relative path names! +*.* /dev/null diff --git a/tests/testsuites/samples.snare_ccoff_udp2 b/tests/testsuites/samples.snare_ccoff_udp2 index 7837b820..337cd97c 100644 --- a/tests/testsuites/samples.snare_ccoff_udp2 +++ b/tests/testsuites/samples.snare_ccoff_udp2 @@ -9,14 +9,18 @@ # to be adapted. We do NOT try to preserve misbehaviour on such seriously malformed # messages. # +# this is a very simple test, though not snare-based +test +insert into windows (Message, Facility,FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values ('', 1, 'test',5, '20100321185328', '20100321185328', 1, '') +# and yet another one we have seen in practice +UX=Abcd-efg-hij-klmno; XXXXX=1111111111, Z123=192.12.231.245:11111, S1234=123456789, XXXXXX=111111111 +insert into windows (Message, Facility,FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values (' XXXXX=1111111111, Z123=192.12.231.245:11111, S1234=123456789, XXXXXX=111111111', 1, 'localhost',5, '20100321185328', '20100321185328', 1, 'UX=Abcd-efg-hij-klmno;') # Sample 1 - note the absence of PRI! windowsserver MSWinEventLog 1 Security 1167 Fri Mar 19 15:33:30 2010 540 Security SYSTEM User Success Audit WINDOWSSERVER Logon/Logoff Successful Network Logon: User Name: WINDOWSSERVER$ Domain: DOMX Logon ID: (0x0,0xF88396) Logon Type: 3 Logon Process: Kerberos Authentication Package: Kerberos Workstation Name: Logon GUID: {79b6eb79-7bcc-8a2e-7dad-953c51dc00fd} Caller User Name: - Caller Domain: - Caller Logon ID: - Caller Process ID: - Transited Services: - Source Network Address: 10.11.11.3 Source Port: 3306 733\n -insert into windows (Message, Facility,FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values (' Mar 19 15:33:30 2010 540 Security SYSTEM User Success Audit WINDOWSSERVER Logon/Logoff Successful Network Logon: User Name: WINDOWSSERVER$ Domain: DOMX Logon ID: (0x0,0xF88396) Logon Type: 3 Logon Process: Kerberos Authentication Package: Kerberos Workstation Name: Logon GUID: {79b6eb79-7bcc-8a2e-7dad-953c51dc00fd} Caller User Name: - Caller Domain: - Caller Logon ID: - Caller Process ID: - Transited Services: - Source Network Address: 10.11.11.3 Source Port: 3306 733 ', 1, 'localhost',5, '20100321185328', '20100321185328', 1, 'windowsserver MSWinEventLog 1 Security 1167 Fri') +insert into windows (Message, Facility,FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values (' Mar 19 15:33:30 2010 540 Security SYSTEM User Success Audit WINDOWSSERVER Logon/Logoff Successful Network Logon: User Name: WINDOWSSERVER$ Domain: DOMX Logon ID: (0x0,0xF88396) Logon Type: 3 Logon Process: Kerberos Authentication Package: Kerberos Workstation Name: Logon GUID: {79b6eb79-7bcc-8a2e-7dad-953c51dc00fd} Caller User Name: - Caller Domain: - Caller Logon ID: - Caller Process ID: - Transited Services: - Source Network Address: 10.11.11.3 Source Port: 3306 733', 1, 'localhost',5, '20100321185328', '20100321185328', 1, 'windowsserver MSWinEventLog 1 Security 1167 Fri') # Sample 2 -# the samples below need to be disabled for the "workaround patch" for the message -# parser to work. They need to be re-enabled once a final solution has been crafted -#windowsserver MSWinEventLog 1 Security 1166 Fri Mar 19 15:33:30 2010 576 Security SYSTEM User Success Audit WINDOWSSERVER Logon/Logoff Special privileges assigned to new logon: User Name: WINDOWSSERVER$ Domain: DOMX Logon ID: (0x0,0xF88396) Privileges: SeSecurityPrivilege SeBackupPrivilege SeRestorePrivilege SeTakeOwnershipPrivilege SeDebugPrivilege SeSystemEnvironmentPrivilege SeLoadDriverPrivilege SeImpersonatePrivilege SeEnableDelegationPrivilege 732\n -#insert into windows (Message, Facility,FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values (' Mar 19 15:33:30 2010 576 Security SYSTEM User Success Audit WINDOWSSERVER Logon/Logoff Special privileges assigned to new logon: User Name: WINDOWSSERVER$ Domain: DOMX Logon ID: (0x0,0xF88396) Privileges: SeSecurityPrivilege SeBackupPrivilege SeRestorePrivilege SeTakeOwnershipPrivilege SeDebugPrivilege SeSystemEnvironmentPrivilege SeLoadDriverPrivilege SeImpersonatePrivilege SeEnableDelegationPrivilege 732', 1, 'localhost',5, '20100321185328', '20100321185328', 1, 'windowsserver MSWinEventLog 1 Security 1166 Fri') +windowsserver MSWinEventLog 1 Security 1166 Fri Mar 19 15:33:30 2010 576 Security SYSTEM User Success Audit WINDOWSSERVER Logon/Logoff Special privileges assigned to new logon: User Name: WINDOWSSERVER$ Domain: DOMX Logon ID: (0x0,0xF88396) Privileges: SeSecurityPrivilege SeBackupPrivilege SeRestorePrivilege SeTakeOwnershipPrivilege SeDebugPrivilege SeSystemEnvironmentPrivilege SeLoadDriverPrivilege SeImpersonatePrivilege SeEnableDelegationPrivilege 732\n +insert into windows (Message, Facility,FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values (' Mar 19 15:33:30 2010 576 Security SYSTEM User Success Audit WINDOWSSERVER Logon/Logoff Special privileges assigned to new logon: User Name: WINDOWSSERVER$ Domain: DOMX Logon ID: (0x0,0xF88396) Privileges: SeSecurityPrivilege SeBackupPrivilege SeRestorePrivilege SeTakeOwnershipPrivilege SeDebugPrivilege SeSystemEnvironmentPrivilege SeLoadDriverPrivilege SeImpersonatePrivilege SeEnableDelegationPrivilege 732', 1, 'localhost',5, '20100321185328', '20100321185328', 1, 'windowsserver MSWinEventLog 1 Security 1166 Fri') # Sample 3 -#windowsserver MSWinEventLog 1 Security 1165 Fri Mar 19 15:33:30 2010 538 Security SYSTEM User Success Audit WINDOWSSERVER Logon/Logoff User Logoff: User Name: WINDOWSSERVER$ Domain: DOMX Logon ID: (0x0,0xF8830B) Logon Type: 3 731\n -#insert into windows (Message, Facility,FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values (' Mar 19 15:33:30 2010 538 Security SYSTEM User Success Audit WINDOWSSERVER Logon/Logoff User Logoff: User Name: WINDOWSSERVER$ Domain: DOMX Logon ID: (0x0,0xF8830B) Logon Type: 3 731', 1, 'localhost',5, '20100321185328', '20100321185328', 1, 'windowsserver MSWinEventLog 1 Security 1165 Fri') +windowsserver MSWinEventLog 1 Security 1165 Fri Mar 19 15:33:30 2010 538 Security SYSTEM User Success Audit WINDOWSSERVER Logon/Logoff User Logoff: User Name: WINDOWSSERVER$ Domain: DOMX Logon ID: (0x0,0xF8830B) Logon Type: 3 731\n +insert into windows (Message, Facility,FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values (' Mar 19 15:33:30 2010 538 Security SYSTEM User Success Audit WINDOWSSERVER Logon/Logoff User Logoff: User Name: WINDOWSSERVER$ Domain: DOMX Logon ID: (0x0,0xF8830B) Logon Type: 3 731', 1, 'localhost',5, '20100321185328', '20100321185328', 1, 'windowsserver MSWinEventLog 1 Security 1165 Fri') diff --git a/tools/syslogd.c b/tools/syslogd.c index a61d1e5d..a93b588f 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -792,7 +792,7 @@ parseAndSubmitMessage(uchar *hname, uchar *hnameIP, uchar *msg, int len, int fla * (I couldn't do any more smart things anyway...). * rgerhards, 2007-9-20 */ - DBGPRINTF("internal error: iMsg > max msg size in printchopped()\n"); + DBGPRINTF("internal error: iMsg > max msg size in parseAndSubmitMessage()\n"); } FINALIZE; /* in this case, we are done... nothing left we can do */ } -- cgit v1.2.3 From 7db6ffbce3e2a709e77ff05782f703ec112ed84b Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 7 Apr 2010 13:57:46 +0200 Subject: bugfix: the T/P/E config size specifiers did not work properly under call 32-bit platforms --- ChangeLog | 2 ++ runtime/cfsysline.c | 8 +++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index dce06dfc..cda52c3b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,6 +8,8 @@ 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 --------------------------------------------------------------------------- Version 4.6.3 [v4-stable] (rgerhards), 2010-03-?? - bugfix: local unix system log socket was deleted even when it was 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 */ -- cgit v1.2.3 From e2ceb7247cbd9dff1bfb0efe22d6bc68e70a3fd8 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 7 Apr 2010 14:25:40 +0200 Subject: bugfix: default for $OMFileFlushOnTXEnd was wrong ("off"). This, in default mode, caused buffered writing to be used, what means that it looked like no output were written or partial lines. Thanks to Michael Biebl for pointing out this bug. --- ChangeLog | 4 ++++ tools/omfile.c | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index c662d66d..83ca5033 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,10 @@ - improvded testbench - added test with truly random data received via syslog to test robustness +- bugfix: default for $OMFileFlushOnTXEnd was wrong ("off"). + This, in default mode, caused buffered writing to be used, what + means that it looked like no output were written or partial + lines. Thanks to Michael Biebl for pointing out this bug. - bugfix: testbench failed when not executed in UTC+1 timezone accidently, the time zone information was kept inside some to-be-checked-for responses diff --git a/tools/omfile.c b/tools/omfile.c index 0f476000..24de052c 100644 --- a/tools/omfile.c +++ b/tools/omfile.c @@ -87,6 +87,7 @@ typedef struct s_dynaFileCacheEntry dynaFileCacheEntry; #define IOBUF_DFLT_SIZE 1024 /* default size for io buffers */ #define FLUSH_INTRVL_DFLT 1 /* default buffer flush interval (in seconds) */ #define USE_ASYNCWRITER_DFLT 0 /* default buffer use async writer */ +#define FLUSHONTX_DFLT 1 /* default for flush on TX end */ /* globals for default values */ static int iDynaFileCacheSize = 10; /* max cache for dynamic files */ @@ -100,7 +101,7 @@ static uid_t dirGID; /* GID to be used for newly created directories */ static int bCreateDirs = 1;/* auto-create directories for dynaFiles: 0 - no, 1 - yes */ static int bEnableSync = 0;/* enable syncing of files (no dash in front of pathname in conf): 0 - no, 1 - yes */ static int iZipLevel = 0; /* zip compression mode (0..9 as usual) */ -static bool bFlushOnTXEnd = 0;/* flush write buffers when transaction has ended? */ +static bool bFlushOnTXEnd = FLUSHONTX_DFLT;/* flush write buffers when transaction has ended? */ static int64 iIOBufSize = IOBUF_DFLT_SIZE; /* size of an io buffer */ static int iFlushInterval = FLUSH_INTRVL_DFLT; /* how often flush the output buffer on inactivity? */ static int bUseAsyncWriter = USE_ASYNCWRITER_DFLT; /* should we enable asynchronous writing? */ @@ -764,7 +765,7 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a bCreateDirs = 1; bEnableSync = 0; iZipLevel = 0; - bFlushOnTXEnd = 0; + bFlushOnTXEnd = FLUSHONTX_DFLT; iIOBufSize = IOBUF_DFLT_SIZE; iFlushInterval = FLUSH_INTRVL_DFLT; bUseAsyncWriter = USE_ASYNCWRITER_DFLT; -- cgit v1.2.3