diff options
author | Rainer Gerhards <rgerhards@adiscon.com> | 2007-08-03 14:58:24 +0000 |
---|---|---|
committer | Rainer Gerhards <rgerhards@adiscon.com> | 2007-08-03 14:58:24 +0000 |
commit | 51971302280a9789b794e6c0c534a6e02767a39e (patch) | |
tree | 39234fe7dab5a0ac5ff51f0d55b5e1a19e159c43 | |
parent | adbf55ece666c71e882c370a74efa0bbf3239226 (diff) | |
download | rsyslog-51971302280a9789b794e6c0c534a6e02767a39e.tar.gz rsyslog-51971302280a9789b794e6c0c534a6e02767a39e.tar.xz rsyslog-51971302280a9789b794e6c0c534a6e02767a39e.zip |
- I found out that we finally have problems with the (somewhat recursive)
call to logerror() that many of the modules do. I have not tried it,
but I think things will become wild when we compile without pthread
support. Threading prevents full recursion, so we have not seen any bad
effects so far. However, the problems that I experienced in ommysl
(that caused me to re-structure startWorker()) are actually rooted in
this issue. I first thought to fix it via a module interace, but I now
came to the conclusion that it is not more effort and much cleaner to
do an internal error buffering class. This is implemented in
errbuf.c/h.
- I just noticed that this is not actually an error buf, but the core of an
input module for all internal messages. As such, I implement it now as
iminternal.c/h. Of course, there is no input module interface yet
designed, but that doesn't matter. Worst-case, I need to re-write the
im, best case I can use the im (at least partly) to define the
interface.
- added a few functions to the linkedlist class
- error messages during startup are now buffered - so we do no longer need
to think about how emergency logging might work. Actually, these are
logged to whatever is instatiated in the log file. This enhances the
chance that we will be able to drop the error message somewhere it is
seen.
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | iminternal.c | 189 | ||||
-rw-r--r-- | iminternal.h | 48 | ||||
-rw-r--r-- | linkedlist.c | 59 | ||||
-rw-r--r-- | linkedlist.h | 1 | ||||
-rw-r--r-- | module-template.h | 1 | ||||
-rw-r--r-- | msg.h | 1 | ||||
-rw-r--r-- | ommysql.c | 21 | ||||
-rw-r--r-- | rsyslog.h | 1 | ||||
-rw-r--r-- | syslogd.c | 90 | ||||
-rw-r--r-- | template.h | 2 |
12 files changed, 386 insertions, 33 deletions
diff --git a/Makefile.am b/Makefile.am index 95aac156..a51173bf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -7,7 +7,7 @@ rfc3195d_SOURCES=rfc3195d.c rsyslog.h man_MANS = rfc3195d.8 rklogd.8 rsyslogd.8 rsyslog.conf.5 -rsyslogd_SOURCES=syslogd.c pidfile.c template.c outchannel.c stringbuf.c srUtils.c parse.c syslogd-types.h template.h outchannel.h syslogd.h stringbuf.h parse.h srUtils.h liblogging-stub.h net.c net.h msg.c msg.h omshell.c omshell.h omusrmsg.c omusrmsg.h ommysql.c ommysql.h omfwd.c omfwd.h tcpsyslog.c tcpsyslog.h omfile.h omfile.c omdiscard.c omdiscard.h modules.c modules.h module-template.h objomsr.c objomsr.h cfsysline.c cfsysline.h linkedlist.c linkedlist.h +rsyslogd_SOURCES=syslogd.c pidfile.c template.c outchannel.c stringbuf.c srUtils.c parse.c syslogd-types.h template.h outchannel.h syslogd.h stringbuf.h parse.h srUtils.h liblogging-stub.h net.c net.h msg.c msg.h omshell.c omshell.h omusrmsg.c omusrmsg.h ommysql.c ommysql.h omfwd.c omfwd.h tcpsyslog.c tcpsyslog.h omfile.h omfile.c omdiscard.c omdiscard.h modules.c modules.h module-template.h objomsr.c objomsr.h cfsysline.c cfsysline.h linkedlist.c linkedlist.h iminternal.c iminternal.h rsyslogd_CPPFLAGS=$(mysql_includes) rsyslogd_LDADD=$(mysql_libs) $(zlib_libs) $(pthreads_libs) diff --git a/configure.ac b/configure.ac index 34104d32..a8c46b67 100644 --- a/configure.ac +++ b/configure.ac @@ -2,8 +2,8 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.61) -AC_INIT(rsyslog, 1.17.7, rsyslog@lists.adiscon.com.) -AM_INIT_AUTOMAKE(rsyslog, 1.17.7) +AC_INIT(rsyslog, 1.18.0, rsyslog@lists.adiscon.com.) +AM_INIT_AUTOMAKE(rsyslog, 1.18.0) AC_CONFIG_SRCDIR([syslogd.c]) AC_CONFIG_HEADER([config.h]) diff --git a/iminternal.c b/iminternal.c new file mode 100644 index 00000000..2f898e46 --- /dev/null +++ b/iminternal.c @@ -0,0 +1,189 @@ +/* iminternal.c + * This file set implements the internal messages input module for rsyslog. + * Note: we currently do not have an input module spec, but + * we will have one in the future. This module needs then to be + * adapted. + * + * File begun on 2007-08-03 by RGerhards + * + * Copyright 2007 Rainer Gerhards and Adiscon GmbH. + * + * This program 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 2 + * of the License, or (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include "rsyslog.h" +#include "syslogd.h" +#include "linkedlist.h" +#include "iminternal.h" + +static linkedList_t llMsgs; + + +/* destructs an iminternal object + */ +static rsRetVal iminternalDestruct(iminternal_t *pThis) +{ + DEFiRet; + + assert(pThis != NULL); + + if(pThis->pMsg != NULL) + MsgDestruct(pThis->pMsg); + + free(pThis); + + return iRet; +} + + +/* Construct an iminternal object + */ +static rsRetVal iminternalConstruct(iminternal_t **ppThis) +{ + DEFiRet; + iminternal_t *pThis; + + assert(ppThis != NULL); + + if((pThis = (iminternal_t*) calloc(1, sizeof(iminternal_t))) == NULL) { + ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY); + } + +finalize_it: + if(iRet != RS_RET_OK) { + if(pThis != NULL) + iminternalDestruct(pThis); + } + + *ppThis = pThis; + + return iRet; +}; + + +/* add a message to the linked list + * Note: the pMsg reference counter is not incremented. Consequently, + * the caller must NOT decrement it. The caller actually hands over + * full ownership of the pMsg object. + * The interface of this function is modelled after syslogd/logmsg(), + * for which it is an "replacement". + */ +rsRetVal iminternalAddMsg(int pri, msg_t *pMsg, int flags) +{ + DEFiRet; + iminternal_t *pThis; + + assert(pMsg != NULL); + + CHKiRet(iminternalConstruct(&pThis)); + + pThis->pri = pri; + pThis->pMsg = pMsg; + pThis->flags = flags; + + CHKiRet(llAppend(&llMsgs, NULL, (void*) pThis)); + +finalize_it: + if(iRet != RS_RET_OK) { + dprintf("iminternalAddMsg() error %d - can not otherwise report this error, message lost\n", iRet); + if(pThis != NULL) + iminternalDestruct(pThis); + } + + return iRet; +} + + +/* pull the first error message from the linked list, remove it + * from the list and return it to the caller. The caller is + * responsible for freeing the message! + */ +rsRetVal iminternalRemoveMsg(int *pPri, msg_t **ppMsg, int *pFlags) +{ + DEFiRet; + iminternal_t *pThis; + linkedListCookie_t llCookie = NULL; + + assert(pPri != NULL); + assert(ppMsg != NULL); + assert(pFlags != NULL); + + CHKiRet(llGetNextElt(&llMsgs, &llCookie, (void**) &pThis)); + *pPri = pThis->pri; + *pFlags = pThis->flags; + *ppMsg = pThis->pMsg; + pThis->pMsg = NULL; /* we do no longer own it - important for destructor */ + + if(llDestroyRootElt(&llMsgs) != RS_RET_OK) { + dprintf("Root element of iminternal linked list could not be destroyed - there is " + "nothing we can do against it, we ignore it for now. Things may go wild " + "from here on. This is most probably a program logic error.\n"); + } + +finalize_it: + return iRet; +} + +/* tell the caller if we have any messages ready for processing. + * 0 means we have none, everything else means there is at least + * one message ready. + */ +rsRetVal iminternalHaveMsgReady(int* pbHaveOne) +{ + assert(pbHaveOne != NULL); + + return llGetNumElts(&llMsgs, pbHaveOne); +} + + +/* initialize the iminternal subsystem + * must be called once at the start of the program + */ +rsRetVal modInitIminternal(void) +{ + DEFiRet; + + iRet = llInit(&llMsgs, iminternalDestruct, NULL, NULL); + + return iRet; +} + + +/* de-initialize the iminternal subsystem + * must be called once at the end of the program + * Note: the error list must have been pulled first. We do + * NOT care if there are any errors left - we simply destroy + * them. + */ +rsRetVal modExitIminternal(void) +{ + DEFiRet; + + iRet = llDestroy(&llMsgs); + + return iRet; +} + +/* + * vi:set ai: + */ diff --git a/iminternal.h b/iminternal.h new file mode 100644 index 00000000..0677f814 --- /dev/null +++ b/iminternal.h @@ -0,0 +1,48 @@ +/* Definition of the internal messages input module. + * + * Note: we currently do not have an input module spec, but + * we will have one in the future. This module needs then to be + * adapted. + * + * Copyright 2007 Rainer Gerhards and Adiscon GmbH. + * + * This program 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 2 + * of the License, or (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ + +#ifndef IMINTERNAL_H_INCLUDED +#define IMINTERNAL_H_INCLUDED +#include "template.h" + +/* this is a single entry for a parse routine. It describes exactly + * one entry point/handler. + * The short name is cslch (Configfile SysLine CommandHandler) + */ +struct iminternal_s { /* config file sysline parse entry */ + int pri; + msg_t *pMsg; /* the message (in all its glory) */ + int flags; +}; +typedef struct iminternal_s iminternal_t; + +/* prototypes */ +rsRetVal modInitIminternal(void); +rsRetVal modExitIminternal(void); +rsRetVal iminternalAddMsg(int pri, msg_t *pMsg, int flags); +rsRetVal iminternalHaveMsgReady(int* pbHaveOne); +rsRetVal iminternalRemoveMsg(int *pPri, msg_t **ppMsg, int *pFlags); + +#endif /* #ifndef IMINTERNAL_H_INCLUDED */ diff --git a/linkedlist.c b/linkedlist.c index 4037193b..7ebadf5a 100644 --- a/linkedlist.c +++ b/linkedlist.c @@ -59,6 +59,31 @@ rsRetVal llInit(linkedList_t *pThis, rsRetVal (*pEltDestructor)(), rsRetVal (*pK }; +/* llDestroyEltData - destroys a list element + * It is a separate function as the + * functionality is needed in multiple code-pathes. + */ +static rsRetVal llDestroyElt(linkedList_t *pList, llElt_t *pElt) +{ + DEFiRet; + + assert(pList != NULL); + assert(pElt != NULL); + + /* we ignore errors during destruction, as we need to try + * free the element in any case. + */ + if(pElt->pData != NULL) + pList->pEltDestruct(pElt->pData); + if(pElt->pKey != NULL) + pList->pKeyDestruct(pElt->pKey); + free(pElt); + pList->iNumElts--; /* one less */ + + return iRet; +} + + /* llDestroy - destroys a COMPLETE linkedList */ rsRetVal llDestroy(linkedList_t *pThis) @@ -76,13 +101,37 @@ rsRetVal llDestroy(linkedList_t *pThis) /* we ignore errors during destruction, as we need to try * finish the linked list in any case. */ - if(pEltPrev->pData != NULL) - pThis->pEltDestruct(pEltPrev->pData); - if(pEltPrev->pKey != NULL) - pThis->pKeyDestruct(pEltPrev->pKey); - free(pEltPrev); + llDestroyElt(pThis, pEltPrev); + } + + return iRet; +} + +/* llDestroyRootElt - destroy the root element but otherwise + * keeps this list intact. -- rgerhards, 2007-08-03 + */ +rsRetVal llDestroyRootElt(linkedList_t *pThis) +{ + DEFiRet; + llElt_t *pPrev; + + if(pThis->pRoot == NULL) { + ABORT_FINALIZE(RS_RET_EMPTY_LIST); + } + + pPrev = pThis->pRoot; + if(pPrev->pNext == NULL) { + /* it was the only list element */ + pThis->pLast = NULL; + pThis->pRoot = NULL; + } else { + /* there are other list elements */ + pThis->pRoot = pPrev->pNext; } + CHKiRet(llDestroyElt(pThis, pPrev)); + +finalize_it: return iRet; } diff --git a/linkedlist.h b/linkedlist.h index ac67a01b..0b5b36e9 100644 --- a/linkedlist.h +++ b/linkedlist.h @@ -54,6 +54,7 @@ typedef llElt_t* linkedListCookie_t; /* this type avoids exposing internals and /* prototypes */ rsRetVal llInit(linkedList_t *pThis, rsRetVal (*pEltDestructor)(), rsRetVal (*pKeyDestructor)(void*), int (*pCmpOp)()); rsRetVal llDestroy(linkedList_t *pThis); +rsRetVal llDestroyRootElt(linkedList_t *pThis); rsRetVal llGetNextElt(linkedList_t *pThis, linkedListCookie_t *ppElt, void **ppUsr); rsRetVal llAppend(linkedList_t *pThis, void *pKey, void *pData); rsRetVal llFind(linkedList_t *pThis, void *pKey, void **ppData); diff --git a/module-template.h b/module-template.h index 54f18cfa..ce13bce6 100644 --- a/module-template.h +++ b/module-template.h @@ -333,6 +333,7 @@ finalize_it:\ return iRet;\ } + /* definitions for host API queries */ #define CODEmodInit_QueryRegCFSLineHdlr \ CHKiRet(pHostQueryEtryPt((uchar*)"regCfSysLineHdlr", &omsdRegCFSLineHdlr)); @@ -24,6 +24,7 @@ #ifndef MSG_H_INCLUDED #define MSG_H_INCLUDED 1 +#include "syslogd-types.h" #include "template.h" /* rgerhards 2004-11-08: The following structure represents a @@ -1,4 +1,4 @@ -/* omusrmsg.c +/* ommysql.c * This is the implementation of the build-in output module for MySQL. * * NOTE: read comments in module-template.h to understand how this file @@ -115,7 +115,7 @@ ENDgetWriteFDForSelect * We check if we have a valid MySQL handle. If not, we simply * report an error, but can not be specific. RGerhards, 2007-01-30 */ -static void reportDBError(instanceData *pData) +static void reportDBError(instanceData *pData, int bSilent) { char errMsg[512]; @@ -128,7 +128,10 @@ static void reportDBError(instanceData *pData) } else { /* we can ask mysql for the error description... */ snprintf(errMsg, sizeof(errMsg)/sizeof(char), "db error (%d): %s\n", mysql_errno(pData->f_hmysql), mysql_error(pData->f_hmysql)); - logerror(errMsg); + if(bSilent) + dprintf("mysql, DBError(silent): %s\n", errMsg); + else + logerror(errMsg); } return; @@ -139,7 +142,7 @@ static void reportDBError(instanceData *pData) * MySQL connection. * Initially added 2004-10-28 mmeckelein */ -static rsRetVal initMySQL(instanceData *pData) +static rsRetVal initMySQL(instanceData *pData, int bSilent) { DEFiRet; @@ -154,7 +157,7 @@ static rsRetVal initMySQL(instanceData *pData) /* Connect to database */ if(mysql_real_connect(pData->f_hmysql, pData->f_dbsrv, pData->f_dbuid, pData->f_dbpwd, pData->f_dbname, 0, NULL, 0) == NULL) { - reportDBError(pData); + reportDBError(pData, bSilent); closeMySQL(pData); /* ignore any error we may get */ iRet = RS_RET_SUSPENDED; } @@ -179,10 +182,10 @@ rsRetVal writeMySQL(uchar *psz, instanceData *pData) if(mysql_query(pData->f_hmysql, (char*)psz)) { /* error occured, try to re-init connection and retry */ closeMySQL(pData); /* close the current handle */ - CHKiRet(initMySQL(pData)); /* try to re-open */ + CHKiRet(initMySQL(pData, 0)); /* try to re-open */ if(mysql_query(pData->f_hmysql, (char*)psz)) { /* re-try insert */ /* we failed, giving up for now */ - reportDBError(pData); + reportDBError(pData, 0); closeMySQL(pData); /* free ressources */ ABORT_FINALIZE(RS_RET_SUSPENDED); } @@ -196,7 +199,7 @@ finalize_it: BEGINtryResume CODESTARTtryResume if(pData->f_hmysql == NULL) { - iRet = initMySQL(pData); + iRet = initMySQL(pData, 1); } ENDtryResume @@ -273,7 +276,7 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1) logerror("Trouble with MySQL connection properties. -MySQL logging disabled"); ABORT_FINALIZE(RS_RET_INVALID_PARAMS); } else { - CHKiRet(initMySQL(pData)); + CHKiRet(initMySQL(pData, 0)); } #endif /* #ifdef WITH_DB */ @@ -68,6 +68,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_END_OF_LINKEDLIST = -2014, /**< end of linked list, not an error, but a status */ RS_RET_CHAIN_NOT_PERMITTED = -2015, /**< chaining (e.g. of config command handlers) not permitted */ RS_RET_INVALID_PARAMS = -2016,/**< supplied parameters are invalid */ + RS_RET_EMPTY_LIST = -2017, /**< linked list is empty */ RS_RET_OK = 0 /**< operation successful */ }; typedef enum rsRetVal_ rsRetVal; /**< friendly type for global return value */ @@ -211,6 +211,7 @@ #include "msg.h" #include "modules.h" #include "tcpsyslog.h" +#include "iminternal.h" #include "cfsysline.h" #include "omshell.h" #include "omusrmsg.h" @@ -715,6 +716,7 @@ static void freeSelectors(void); static rsRetVal processConfFile(uchar *pConfFile); static rsRetVal actionDestruct(action_t *pThis); static rsRetVal selectorAddList(selector_t *f); +static void processImInternal(void); /* Access functions for the selector_t. These functions are primarily * necessary to make things thread-safe. Consequently, they are slim @@ -2377,7 +2379,7 @@ time_t now; * function here probably is only an interim solution and that we need to * think on the best way to do this. */ -static void logmsgInternal(int pri, char * msg, int flags) +static void logmsgInternal(int pri, char *msg, int flags) { msg_t *pMsg; @@ -2407,9 +2409,17 @@ static void logmsgInternal(int pri, char * msg, int flags) pMsg->iSeverity = LOG_PRI(pri); pMsg->bParseHOSTNAME = 0; getCurrTime(&(pMsg->tTIMESTAMP)); /* use the current time! */ + flags |= INTERNAL_MSG; - logmsg(pri, pMsg, flags | INTERNAL_MSG); - MsgDestruct(pMsg); + if(bRunningMultithreaded == 0) { /* not yet in queued mode */ + iminternalAddMsg(pri, pMsg, flags); + } else { + /* we have the queue, so we can simply provide the + * message to the queue engine. + */ + logmsg(pri, pMsg, flags); + MsgDestruct(pMsg); + } } /* @@ -2539,9 +2549,12 @@ int shouldProcessThisMessage(selector_t *f, msg_t *pMsg) /* doEmergencyLoggin() * ... does exactly do that. It logs messages when the subsystem has not yet * been initialized. This almost always happens during initial startup or - * during HUPing. - * rgerhards, 2007-07-25 - * TODO: add logging to system console + * during HUPing. -- rgerhards, 2007-07-25 + * rgerhards, 2007-08-03: as of now, this can normally no longer happen. All + * startup messages are now buffered until the system is ready to run. I leave + * this minimal implementation here in in the very remote case that it might + * be needed in the future or due to a program bug. Do *not* excpect this + * code to be called. */ static void doEmergencyLogging(msg_t *pMsg) { @@ -2651,6 +2664,8 @@ DEFFUNC_llExecFunc(processMsgDoActions) } else if(iRetMod == RS_RET_SUSPENDED) { /* indicate suspension for next module to be called */ pDoActData->bPrevWasSuspended = 1; + } else { + pDoActData->bPrevWasSuspended = 0; } finalize_it: @@ -3651,7 +3666,7 @@ static void die(int sig) errno = 0; logmsgInternal(LOG_SYSLOG|LOG_INFO, buf, ADDDATE); } - + /* Free ressources and close connections */ freeSelectors(); @@ -4057,6 +4072,12 @@ static void freeSelectors(void) if(Files != NULL) { dprintf("Freeing log structures.\n"); + /* just in case, we flush the emergency log. If error messages occur after + * this stage, we loose them, but that's ok. With multi-threading, this can + * never happen. -- rgerhards, 2007-08-03 + */ + processImInternal(); + /* we need first to flush, then wait for all messages to be processed * (stopWoker() does that), then we can free the structures. */ @@ -5012,9 +5033,7 @@ finalize_it: /* do not overwrite error state! */ OMSRdestruct(pOMSR); if(pAction != NULL) - actionDestruct(pAction); /* this line should take care of the TODO's below */ - /* TODO: free pMod instance data, potential mem leak */ - /* TODO: better said - where is the selector_t AND its elements destroyed? */ + actionDestruct(pAction); } return iRet; @@ -5428,6 +5447,25 @@ static void debugListenInfo(int fd, char *type) } +/* this function pulls all internal messages from the buffer + * and puts them into the processing engine. + * We can only do limited error handling, as this would not + * really help us. TODO: add error messages? + * rgerhards, 2007-08-03 + */ +static void processImInternal(void) +{ + int iPri; + int iFlags; + msg_t *pMsg; + + while(iminternalRemoveMsg(&iPri, &pMsg, &iFlags) == RS_RET_OK) { + logmsg(iPri, pMsg, iFlags); + MsgDestruct(pMsg); + } +} + + /* helper function for mainloop(). This is used to add all module * writeFDsfor Select via llExecFunc(). * rgerhards, 2007-08-02 @@ -5490,6 +5528,10 @@ static void mainloop(void) int fd; char line[MAXLINE +1]; int maxfds; + int nfds; + errno = 0; + FD_ZERO(&readfds); + maxfds = 0; #ifdef SYSLOG_INET mainloopWriteFDSInfo_t writeFDSInfo; fd_set writefds; @@ -5507,13 +5549,10 @@ static void mainloop(void) #endif #endif - - /* --------------------- Main loop begins here. ----------------------------------------- */ while(!bFinished){ - int nfds; - errno = 0; - FD_ZERO(&readfds); - maxfds = 0; + /* first check if we have any internal messages queued and spit them out */ + processImInternal(); + #ifdef SYSLOG_UNIXAF /* Add the Unix Domain Sockets to the list of read * descriptors. @@ -5926,6 +5965,11 @@ int main(int argc, char **argv) } /* doing some core initializations */ + if((iRet = modInitIminternal()) != RS_RET_OK) { + fprintf(stderr, "fatal error: could not initialize errbuf object (error code %d).\n", + iRet); + exit(1); /* "good" exit, leaving at init for fatal error */ + } #ifdef USE_PTHREADS /* create message queue */ @@ -6208,6 +6252,20 @@ int main(int argc, char **argv) */ mainloop(); + + /* de-init some modules */ + modExitIminternal(); + + /* TODO: this would also be the right place to de-init the builtin output modules. We + * do not currently do that, because the module interface does not allow for + * it. This will come some time later (it's essential with loadable modules). + * For the time being, this is a memory leak on exit, but as the process is + * terminated, we do not really bother about it. + * rgerhards, 2007-08-03 + */ + + /* end de-init's */ + die(bFinished); return 0; } @@ -8,6 +8,8 @@ #define TEMPLATE_H_INCLUDED 1 +#include "stringbuf.h" + #ifdef FEATURE_REGEXP /* Include regular expressions */ #include <regex.h> |