diff options
author | Michael Biebl <biebl@debian.org> | 2014-06-04 22:22:48 +0200 |
---|---|---|
committer | Michael Biebl <biebl@debian.org> | 2014-06-04 22:22:48 +0200 |
commit | 7e740a53d3c2eeab4045d55b215a8c1a545203c9 (patch) | |
tree | 83db8224788a9fd57e998a645445a59d5d642345 /tools/syslogd.c | |
parent | 7693d4302df6ac2ffef2e085857f44530f8d9705 (diff) | |
parent | daeb0d03d4a65fa118ad25b34958fb9cacbbd6f4 (diff) | |
download | rsyslog-7e740a53d3c2eeab4045d55b215a8c1a545203c9.tar.gz |
Merge tag 'upstream/8.2.2' into experimental
Upstream version 8.2.2
Diffstat (limited to 'tools/syslogd.c')
-rw-r--r-- | tools/syslogd.c | 1624 |
1 files changed, 82 insertions, 1542 deletions
diff --git a/tools/syslogd.c b/tools/syslogd.c index 94ec71e..ec0beb7 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -1,10 +1,16 @@ /** - * \brief This is the main file of the rsyslogd daemon. + * main rsyslog file with GPLv3 content. * - * Please visit the rsyslog project at + * *********************** NOTE ************************ + * * Do no longer patch this file. If there is hard * + * * need to, talk to Rainer as to how we can make any * + * * patch be licensed under ASL 2.0. * + * * THIS FILE WILL GO AWAY. The new main file is * + * * rsyslogd.c. * + * ***************************************************** * + * Please visit the rsyslog project at * http://www.rsyslog.com - * * to learn more about it and discuss any questions you may have. * * rsyslog had initially been forked from the sysklogd project. @@ -18,8 +24,6 @@ * This Project was intiated and is maintained by * Rainer Gerhards <rgerhards@hq.adiscon.com>. * - * For further information, please see http://www.rsyslog.com - * * rsyslog - An Enhanced syslogd Replacement. * Copyright 2003-2014 Rainer Gerhards and Adiscon GmbH. * @@ -43,8 +47,6 @@ #include "config.h" #include "rsyslog.h" -#define DEFUPRI (LOG_USER|LOG_NOTICE) - #include <unistd.h> #include <stdlib.h> #include <stdio.h> @@ -82,18 +84,11 @@ #endif #include <signal.h> -#include <liblogging/stdlog.h> #if HAVE_PATHS_H #include <paths.h> #endif -#ifdef USE_NETZIP -#include <zlib.h> -#endif - -extern int yydebug; /* interface to flex */ - #include <netdb.h> #include "pidfile.h" @@ -105,179 +100,82 @@ extern int yydebug; /* interface to flex */ #include "syslogd.h" #include "msg.h" -#include "modules.h" -#include "action.h" #include "iminternal.h" -#include "cfsysline.h" #include "threads.h" -#include "wti.h" -#include "queue.h" -#include "stream.h" -#include "conf.h" -#include "errmsg.h" -#include "datetime.h" #include "parser.h" -#include "batch.h" #include "unicode-helper.h" -#include "ruleset.h" #include "net.h" -#include "prop.h" -#include "rsconf.h" #include "dnscache.h" #include "sd-daemon.h" -#include "rainerscript.h" #include "ratelimit.h" /* definitions for objects we access */ DEFobjCurrIf(obj) DEFobjCurrIf(glbl) -DEFobjCurrIf(datetime) /* TODO: make go away! */ -DEFobjCurrIf(conf) -DEFobjCurrIf(module) -DEFobjCurrIf(errmsg) -DEFobjCurrIf(ruleset) -DEFobjCurrIf(prop) -DEFobjCurrIf(parser) -DEFobjCurrIf(rsconf) DEFobjCurrIf(net) /* TODO: make go away! */ /* forward definitions */ -static rsRetVal GlobalClassExit(void); -static rsRetVal queryLocalHostname(void); +rsRetVal queryLocalHostname(void); + +/* forward defintions from rsyslogd.c (ASL 2.0 code) */ +extern ratelimit_t *internalMsg_ratelimiter; +extern uchar *ConfFile; +extern ratelimit_t *dflt_ratelimiter; +extern void rsyslogd_usage(void); +extern rsRetVal rsyslogdInit(void); +extern void rsyslogd_destructAllActions(void); +extern void rsyslogd_sigttin_handler(); +void rsyslogd_submitErrMsg(const int severity, const int iErr, const uchar *msg); +rsRetVal rsyslogd_InitGlobalClasses(void); +rsRetVal rsyslogd_InitStdRatelimiters(void); +rsRetVal rsyslogdInit(void); +void rsyslogdDebugSwitch(); +void rsyslogdDoDie(int sig); -#ifndef _PATH_LOGCONF -#define _PATH_LOGCONF "/etc/rsyslog.conf" -#endif - -#ifndef _PATH_MODDIR -# if defined(__FreeBSD__) -# define _PATH_MODDIR "/usr/local/lib/rsyslog/" -# else -# define _PATH_MODDIR "/lib/rsyslog/" -# endif -#endif - #if defined(SYSLOGD_PIDNAME) # undef _PATH_LOGPID -# if defined(FSSTND) -# ifdef OS_BSD -# define _PATH_VARRUN "/var/run/" -# endif -# if defined(__sun) || defined(__hpux) -# define _PATH_VARRUN "/var/run/" -# endif -# define _PATH_LOGPID _PATH_VARRUN SYSLOGD_PIDNAME -# else -# define _PATH_LOGPID "/etc/" SYSLOGD_PIDNAME -# endif +# define _PATH_LOGPID "/etc/" SYSLOGD_PIDNAME #else # ifndef _PATH_LOGPID -# if defined(__sun) || defined(__hpux) -# define _PATH_VARRUN "/var/run/" -# endif -# if defined(FSSTND) -# define _PATH_LOGPID _PATH_VARRUN "rsyslogd.pid" -# else -# define _PATH_LOGPID "/etc/rsyslogd.pid" -# endif +# define _PATH_LOGPID "/etc/rsyslogd.pid" # endif #endif #ifndef _PATH_TTY # define _PATH_TTY "/dev/tty" #endif +char *PidFile = _PATH_LOGPID; /* read-only after startup */ -rsconf_t *ourConf; /* our config object */ - -static prop_t *pInternalInputName = NULL; /* there is only one global inputName for all internally-generated messages */ -static uchar *ConfFile = (uchar*) _PATH_LOGCONF; /* read-only after startup */ -static char *PidFile = _PATH_LOGPID; /* read-only after startup */ - -/* mypid is read-only after the initial fork() */ -static int bHadHUP = 0; /* did we have a HUP? */ - -static int bFinished = 0; /* used by termination signal handler, read-only except there - * is either 0 or the number of the signal that requested the - * termination. - */ +int bHadHUP = 0; /* did we have a HUP? */ +int bFinished = 0; /* used by termination signal handler, read-only except there + * is either 0 or the number of the signal that requested the + * termination. + */ int iConfigVerify = 0; /* is this just a config verify run? */ - -#define LIST_DELIMITER ':' /* delimiter between two hosts */ - -static pid_t ppid; /* This is a quick and dirty hack used for spliting main/startup thread */ - -struct queuefilenames_s { - struct queuefilenames_s *next; - uchar *name; -} *queuefilenames = NULL; - - -static ratelimit_t *dflt_ratelimiter = NULL; /* ratelimiter for submits without explicit one */ -static ratelimit_t *internalMsg_ratelimiter = NULL; /* ratelimiter for rsyslog-own messages */ -int MarkInterval = 20 * 60; /* interval between marks in seconds - read-only after startup */ -int send_to_all = 0; /* send message to all IPv4/IPv6 addresses */ -static int doFork = 1; /* fork - run in daemon mode - read-only after startup */ -int bHaveMainQueue = 0;/* set to 1 if the main queue - in queueing mode - is available - * If the main queue is either not yet ready or not running in - * queueing mode (mode DIRECT!), then this is set to 0. - */ - -extern int errno; - -/* main message queue and its configuration parameters */ -qqueue_t *pMsgQueue = NULL; /* the main message queue */ +pid_t ppid; /* This is a quick and dirty hack used for spliting main/startup thread */ +int doFork = 1; /* fork - run in daemon mode - read-only after startup */ /* up to the next comment, prototypes that should be removed by reordering */ /* Function prototypes. */ -static char **crunch_list(char *list); static void reapchild(); -static void debug_switch(); -static void sighup_handler(); - - -static int usage(void) -{ - fprintf(stderr, "usage: rsyslogd [-46AdnqQvwx] [-l<hostlist>] [-s<domainlist>]\n" - " [-f<conffile>] [-i<pidfile>] [-N<level>] [-M<module load path>]\n" - " [-u<number>]\n" - "For further information see http://www.rsyslog.com/doc\n"); - exit(1); /* "good" exit - done to terminate usage() */ -} - - -/* ------------------------------ some support functions for imdiag ------------------------------ * - * This is a bit dirty, but the only way to do it, at least with reasonable effort. - * rgerhards, 2009-05-25 - */ - -/* return back the approximate current number of messages in the main message queue - * This number includes the messages that reside in an associated DA queue (if - * it exists) -- rgerhards, 2009-10-14 - */ -rsRetVal -diagGetMainMsgQSize(int *piSize) -{ - DEFiRet; - assert(piSize != NULL); - *piSize = (pMsgQueue->pqDA != NULL) ? pMsgQueue->pqDA->iQueueSize : 0; - *piSize += pMsgQueue->iQueueSize; - RETiRet; -} - - -/* ------------------------------ end support functions for imdiag ------------------------------ */ +#define LIST_DELIMITER ':' /* delimiter between two hosts */ /* rgerhards, 2005-10-24: crunch_list is called only during option processing. So * it is never called once rsyslogd is running. This code * contains some exits, but they are considered safe because they only happen * during startup. Anyhow, when we review the code here, we might want to * reconsider the exit()s. + * Note: this stems back to sysklogd, so we cannot put it under ASL 2.0. But + * we may want to check if the code inside the BSD sources is exactly the same + * (remember that sysklogd forked the BSD sources). If so, the BSD license applies + * and permits us to move to ASL 2.0 (but we need to check the fine details). + * Probably it is best just to rewrite this code. */ -static char **crunch_list(char *list) +char **syslogd_crunch_list(char *list) { int count, i; char *p, *q; @@ -330,15 +228,11 @@ static char **crunch_list(char *list) strcpy(result[count],p); result[++count] = NULL; -#if 0 - count=0; - while (result[count]) - DBGPRINTF("#%d: %s\n", count, StripDomains[count++]); -#endif return result; } +/* also stems back to sysklogd in whole */ void untty(void) #ifdef HAVE_SETSID { @@ -353,11 +247,13 @@ void untty(void) pid_t pid; if(!Debug) { + /* Peng Haitao <penght@cn.fujitsu.com> contribution */ pid = getpid(); if (setpgid(pid, pid) < 0) { perror("setpgid"); exit(1); } + /* end Peng Haitao <penght@cn.fujitsu.com> contribution */ i = open(_PATH_TTY, O_RDWR|O_CLOEXEC); if (i >= 0) { @@ -375,324 +271,7 @@ void untty(void) } #endif - -/* This takes a received message that must be decoded and submits it to - * the main message queue. This is a legacy function which is being provided - * to aid older input plugins that do not support message creation via - * the new interfaces themselves. It is not recommended to use this - * function for new plugins. -- rgerhards, 2009-10-12 - */ -rsRetVal -parseAndSubmitMessage(uchar *hname, uchar *hnameIP, uchar *msg, int len, int flags, flowControl_t flowCtlType, - prop_t *pInputName, struct syslogTime *stTime, time_t ttGenTime, ruleset_t *pRuleset) -{ - prop_t *pProp = NULL; - msg_t *pMsg; - DEFiRet; - - /* we now create our own message object and submit it to the queue */ - if(stTime == NULL) { - CHKiRet(msgConstruct(&pMsg)); - } else { - CHKiRet(msgConstructWithTime(&pMsg, stTime, ttGenTime)); - } - if(pInputName != NULL) - MsgSetInputName(pMsg, pInputName); - MsgSetRawMsg(pMsg, (char*)msg, len); - MsgSetFlowControlType(pMsg, flowCtlType); - MsgSetRuleset(pMsg, pRuleset); - pMsg->msgFlags = flags | NEEDS_PARSING; - - MsgSetRcvFromStr(pMsg, hname, ustrlen(hname), &pProp); - CHKiRet(prop.Destruct(&pProp)); - CHKiRet(MsgSetRcvFromIPStr(pMsg, hnameIP, ustrlen(hnameIP), &pProp)); - CHKiRet(prop.Destruct(&pProp)); - CHKiRet(submitMsg2(pMsg)); - -finalize_it: - RETiRet; -} - - -/* this is a special function used to submit an error message. This - * function is also passed to the runtime library as the generic error - * message handler. -- rgerhards, 2008-04-17 - */ -void -submitErrMsg(const int severity, const int iErr, const uchar *msg) -{ - logmsgInternal(iErr, LOG_SYSLOG|(severity & 0x07), msg, 0); -} - - -static inline rsRetVal -submitMsgWithDfltRatelimiter(msg_t *pMsg) -{ - return ratelimitAddMsg(dflt_ratelimiter, NULL, pMsg); -} - -/* This function logs a message to rsyslog itself, using its own - * internal structures. This means external programs (like the - * system journal) will never see this message. - */ -static rsRetVal -logmsgInternalSelf(const int iErr, const int pri, const size_t lenMsg, - const char *__restrict__ const msg, int flags) -{ - uchar pszTag[33]; - msg_t *pMsg; - DEFiRet; - - CHKiRet(msgConstruct(&pMsg)); - MsgSetInputName(pMsg, pInternalInputName); - MsgSetRawMsg(pMsg, (char*)msg, lenMsg); - MsgSetHOSTNAME(pMsg, glbl.GetLocalHostName(), ustrlen(glbl.GetLocalHostName())); - MsgSetRcvFrom(pMsg, glbl.GetLocalHostNameProp()); - MsgSetRcvFromIP(pMsg, glbl.GetLocalHostIP()); - MsgSetMSGoffs(pMsg, 0); - /* check if we have an error code associated and, if so, - * adjust the tag. -- rgerhards, 2008-06-27 - */ - if(iErr == NO_ERRCODE) { - MsgSetTAG(pMsg, UCHAR_CONSTANT("rsyslogd:"), sizeof("rsyslogd:") - 1); - } else { - size_t len = snprintf((char*)pszTag, sizeof(pszTag), "rsyslogd%d:", iErr); - pszTag[32] = '\0'; /* just to make sure... */ - MsgSetTAG(pMsg, pszTag, len); - } - pMsg->iFacility = LOG_FAC(pri); - pMsg->iSeverity = LOG_PRI(pri); - flags |= INTERNAL_MSG; - pMsg->msgFlags = flags; - - if(bHaveMainQueue == 0) { /* not yet in queued mode */ - iminternalAddMsg(pMsg); - } else { - /* we have the queue, so we can simply provide the - * message to the queue engine. - */ - ratelimitAddMsg(internalMsg_ratelimiter, NULL, pMsg); - } -finalize_it: - RETiRet; -} - - -/* rgerhards 2004-11-09: the following is a function that can be used - * to log a message orginating from the syslogd itself. - */ -rsRetVal -logmsgInternal(int iErr, int pri, const uchar *const msg, int flags) -{ - size_t lenMsg; - unsigned i; - char *bufModMsg = NULL; /* buffer for modified message, should we need to modify */ - DEFiRet; - - /* we first do a path the remove control characters that may have accidently - * introduced (program error!). This costs performance, but we do not expect - * to be called very frequently in any case ;) -- rgerhards, 2013-12-19. - */ - lenMsg = ustrlen(msg); - for(i = 0 ; i < lenMsg ; ++i) { - if(msg[i] < 0x20 || msg[i] == 0x7f) { - if(bufModMsg == NULL) { - CHKmalloc(bufModMsg = strdup((char*) msg)); - } - bufModMsg[i] = ' '; - } - } - - if(bProcessInternalMessages) { - CHKiRet(logmsgInternalSelf(iErr, pri, lenMsg, - (bufModMsg == NULL) ? (char*)msg : bufModMsg, - flags)); - } else { - stdlog_log(stdlog_hdl, LOG_PRI(pri), "%s", - (bufModMsg == NULL) ? (char*)msg : bufModMsg); - } - - /* we now check if we should print internal messages out to stderr. This was - * suggested by HKS as a way to help people troubleshoot rsyslog configuration - * (by running it interactively. This makes an awful lot of sense, so I add - * it here. -- rgerhards, 2008-07-28 - * Note that error messages can not be disabled during a config verify. This - * permits us to process unmodified config files which otherwise contain a - * supressor statement. - */ - if(((Debug == DEBUG_FULL || !doFork) && ourConf->globals.bErrMsgToStderr) || iConfigVerify) { - if(LOG_PRI(pri) == LOG_ERR) - fprintf(stderr, "rsyslogd: %s\n", (bufModMsg == NULL) ? (char*)msg : bufModMsg); - } - -finalize_it: - free(bufModMsg); - RETiRet; -} - - -/* preprocess a batch of messages, that is ready them for actual processing. This is done - * as a first stage and totally in parallel to any other worker active in the system. So - * it helps us keep up the overall concurrency level. - * rgerhards, 2010-06-09 - */ -static inline rsRetVal -preprocessBatch(batch_t *pBatch, int *pbShutdownImmediate) { - prop_t *ip; - prop_t *fqdn; - prop_t *localName; - prop_t *propFromHost = NULL; - prop_t *propFromHostIP = NULL; - int bIsPermitted; - msg_t *pMsg; - int i; - rsRetVal localRet; - DEFiRet; - - for(i = 0 ; i < pBatch->nElem && !*pbShutdownImmediate ; i++) { - pMsg = pBatch->pElem[i].pMsg; - if((pMsg->msgFlags & NEEDS_ACLCHK_U) != 0) { - DBGPRINTF("msgConsumer: UDP ACL must be checked for message (hostname-based)\n"); - if(net.cvthname(pMsg->rcvFrom.pfrominet, &localName, &fqdn, &ip) != RS_RET_OK) - continue; - bIsPermitted = net.isAllowedSender2((uchar*)"UDP", - (struct sockaddr *)pMsg->rcvFrom.pfrominet, (char*)propGetSzStr(fqdn), 1); - if(!bIsPermitted) { - DBGPRINTF("Message from '%s' discarded, not a permitted sender host\n", - propGetSzStr(fqdn)); - pBatch->eltState[i] = BATCH_STATE_DISC; - } else { - /* save some of the info we obtained */ - MsgSetRcvFrom(pMsg, localName); - CHKiRet(MsgSetRcvFromIP(pMsg, ip)); - pMsg->msgFlags &= ~NEEDS_ACLCHK_U; - } - } - if((pMsg->msgFlags & NEEDS_PARSING) != 0) { - if((localRet = parser.ParseMsg(pMsg)) != RS_RET_OK) { - DBGPRINTF("Message discarded, parsing error %d\n", localRet); - pBatch->eltState[i] = BATCH_STATE_DISC; - } - } - } - -finalize_it: - if(propFromHost != NULL) - prop.Destruct(&propFromHost); - if(propFromHostIP != NULL) - prop.Destruct(&propFromHostIP); - RETiRet; -} - -/* The consumer of dequeued messages. This function is called by the - * queue engine on dequeueing of a message. It runs on a SEPARATE - * THREAD. It receives an array of pointers, which it must iterate - * over. We do not do any further batching, as this is of no benefit - * for the main queue. - */ -static rsRetVal -msgConsumer(void __attribute__((unused)) *notNeeded, batch_t *pBatch, wti_t *pWti) -{ - DEFiRet; - assert(pBatch != NULL); - preprocessBatch(pBatch, pWti->pbShutdownImmediate); - ruleset.ProcessBatch(pBatch, pWti); -//TODO: the BATCH_STATE_COMM must be set somewhere down the road, but we -//do not have this yet and so we emulate -- 2010-06-10 -int i; - for(i = 0 ; i < pBatch->nElem && !*pWti->pbShutdownImmediate ; i++) { - pBatch->eltState[i] = BATCH_STATE_COMM; - } - RETiRet; -} - - -/* submit a message to the main message queue. This is primarily - * a hook to prevent the need for callers to know about the main message queue - * rgerhards, 2008-02-13 - */ -rsRetVal -submitMsg2(msg_t *pMsg) -{ - qqueue_t *pQueue; - ruleset_t *pRuleset; - DEFiRet; - - ISOBJ_TYPE_assert(pMsg, msg); - - pRuleset = MsgGetRuleset(pMsg); - pQueue = (pRuleset == NULL) ? pMsgQueue : ruleset.GetRulesetQueue(pRuleset); - - /* if a plugin logs a message during shutdown, the queue may no longer exist */ - if(pQueue == NULL) { - DBGPRINTF("submitMsg2() could not submit message - " - "queue does (no longer?) exist - ignored\n"); - FINALIZE; - } - - qqueueEnqMsg(pQueue, pMsg->flowCtlType, pMsg); - -finalize_it: - RETiRet; -} - -rsRetVal -submitMsg(msg_t *pMsg) -{ - return submitMsgWithDfltRatelimiter(pMsg); -} - - -/* submit multiple messages at once, very similar to submitMsg, just - * for multi_submit_t. All messages need to go into the SAME queue! - * rgerhards, 2009-06-16 - */ -rsRetVal -multiSubmitMsg2(multi_submit_t *pMultiSub) -{ - qqueue_t *pQueue; - ruleset_t *pRuleset; - DEFiRet; - assert(pMultiSub != NULL); - - if(pMultiSub->nElem == 0) - FINALIZE; - - pRuleset = MsgGetRuleset(pMultiSub->ppMsgs[0]); - pQueue = (pRuleset == NULL) ? pMsgQueue : ruleset.GetRulesetQueue(pRuleset); - - /* if a plugin logs a message during shutdown, the queue may no longer exist */ - if(pQueue == NULL) { - DBGPRINTF("multiSubmitMsg() could not submit message - " - "queue does (no longer?) exist - ignored\n"); - FINALIZE; - } - - iRet = pQueue->MultiEnq(pQueue, pMultiSub); - pMultiSub->nElem = 0; - -finalize_it: - RETiRet; -} -rsRetVal -multiSubmitMsg(multi_submit_t *pMultiSub) /* backward compat. level */ -{ - return multiSubmitMsg2(pMultiSub); -} - - -/* flush multiSubmit, e.g. at end of read records */ -rsRetVal -multiSubmitFlush(multi_submit_t *pMultiSub) -{ - DEFiRet; - if(pMultiSub->nElem > 0) { - iRet = multiSubmitMsg2(pMultiSub); - } - RETiRet; -} - - +/* function stems back to sysklogd */ static void reapchild() { @@ -709,185 +288,12 @@ reapchild() } -static void debug_switch() -{ - time_t tTime; - struct tm tp; - struct sigaction sigAct; - - datetime.GetTime(&tTime); - localtime_r(&tTime, &tp); - if(debugging_on == 0) { - debugging_on = 1; - dbgprintf("\n"); - dbgprintf("\n"); - dbgprintf("********************************************************************************\n"); - dbgprintf("Switching debugging_on to true at %2.2d:%2.2d:%2.2d\n", - tp.tm_hour, tp.tm_min, tp.tm_sec); - dbgprintf("********************************************************************************\n"); - } else { - dbgprintf("********************************************************************************\n"); - dbgprintf("Switching debugging_on to false at %2.2d:%2.2d:%2.2d\n", - tp.tm_hour, tp.tm_min, tp.tm_sec); - dbgprintf("********************************************************************************\n"); - dbgprintf("\n"); - dbgprintf("\n"); - debugging_on = 0; - } - memset(&sigAct, 0, sizeof (sigAct)); - sigemptyset(&sigAct.sa_mask); - sigAct.sa_handler = debug_switch; - sigaction(SIGUSR1, &sigAct, NULL); -} - - -/* doDie() is a signal handler. If called, it sets the bFinished variable - * to indicate the program should terminate. However, it does not terminate - * it itself, because that causes issues with multi-threading. The actual - * termination is then done on the main thread. This solution might introduce - * a minimal delay, but it is much cleaner than the approach of doing everything - * inside the signal handler. - * rgerhards, 2005-10-26 - * Note: - * - we do not call DBGPRINTF() as this may cause us to block in case something - * with the threading is wrong. - * - we do not really care about the return state of write(), but we need this - * strange check we do to silence compiler warnings (thanks, Ubuntu!) - */ -static void doDie(int sig) -{ -# define MSG1 "DoDie called.\n" -# define MSG2 "DoDie called 5 times - unconditional exit\n" - static int iRetries = 0; /* debug aid */ - dbgprintf(MSG1); - if(Debug == DEBUG_FULL) { - if(write(1, MSG1, sizeof(MSG1) - 1)) {} - } - if(iRetries++ == 4) { - if(Debug == DEBUG_FULL) { - if(write(1, MSG2, sizeof(MSG2) - 1)) {} - } - abort(); - } - bFinished = sig; - if(glblDebugOnShutdown) { - /* kind of hackish - set to 0, so that debug_swith will enable - * and AND emit the "start debug log" message. - */ - debugging_on = 0; - debug_switch(); - } -# undef MSG1 -# undef MSG2 -} - - -/* Finalize and destruct all actions. - */ -static inline void -destructAllActions(void) -{ - ruleset.DestructAllActions(runConf); - bHaveMainQueue = 0; // flag that internal messages need to be temporarily stored -} - - -/* die() is called when the program shall end. This typically only occurs - * during sigterm or during the initialization. - * As die() is intended to shutdown rsyslogd, it is - * safe to call exit() here. Just make sure that die() itself is not called - * at inapropriate places. As a general rule of thumb, it is a bad idea to add - * any calls to die() in new code! - * rgerhards, 2005-10-24 - */ -static void -die(int sig) +/* GPL code - maybe check BSD sources? */ +void +syslogd_die(void) { - char buf[256]; - - DBGPRINTF("exiting on signal %d\n", sig); - - /* IMPORTANT: we should close the inputs first, and THEN send our termination - * message. If we do it the other way around, logmsgInternal() may block on - * a full queue and the inputs still fill up that queue. Depending on the - * scheduling order, we may end up with logmsgInternal being held for a quite - * long time. When the inputs are terminated first, that should not happen - * because the queue is drained in parallel. The situation could only become - * an issue with extremely long running actions in a queue full environment. - * However, such actions are at least considered poorly written, if not - * outright wrong. So we do not care about this very remote problem. - * rgerhards, 2008-01-11 - */ - - /* close the inputs */ - DBGPRINTF("Terminating input threads...\n"); - glbl.SetGlobalInputTermination(); - thrdTerminateAll(); - - /* and THEN send the termination log message (see long comment above) */ - if(sig && runConf->globals.bLogStatusMsgs) { - (void) snprintf(buf, sizeof(buf) / sizeof(char), - " [origin software=\"rsyslogd\" " "swVersion=\"" VERSION \ - "\" x-pid=\"%d\" x-info=\"http://www.rsyslog.com\"]" " exiting on signal %d.", - (int) glblGetOurPid(), sig); - errno = 0; - logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, (uchar*)buf, 0); - } - /* we sleep for 50ms to give the queue a chance to pick up the exit message; - * otherwise we have seen cases where the message did not make it to log - * files, even on idle systems. - */ - srSleep(0, 50); - - /* drain queue (if configured so) and stop main queue worker thread pool */ - DBGPRINTF("Terminating main queue...\n"); - qqueueDestruct(&pMsgQueue); - pMsgQueue = NULL; - - /* Free ressources and close connections. This includes flushing any remaining - * repeated msgs. - */ - DBGPRINTF("Terminating outputs...\n"); - destructAllActions(); - - DBGPRINTF("all primary multi-thread sources have been terminated - now doing aux cleanup...\n"); - - DBGPRINTF("destructing current config...\n"); - rsconf.Destruct(&runConf); - - /* rger 2005-02-22 - * now clean up the in-memory structures. OK, the OS - * would also take care of that, but if we do it - * ourselfs, this makes finding memory leaks a lot - * easier. - */ - /* de-init some modules */ - modExitIminternal(); - - /*dbgPrintAllDebugInfo(); / * this is the last spot where this can be done - below output modules are unloaded! */ - - /* the following line cleans up CfSysLineHandlers that were not based on loadable - * modules. As such, they are not yet cleared. - */ - unregCfSysLineHdlrs(); - - /* destruct our global properties */ - if(pInternalInputName != NULL) - prop.Destruct(&pInternalInputName); - - /* terminate the remaining classes */ - GlobalClassExit(); - - module.UnloadAndDestructAll(eMOD_LINK_ALL); - - DBGPRINTF("Clean shutdown completed, bye\n"); - /* dbgClassExit MUST be the last one, because it de-inits the debug system */ - dbgClassExit(); - - /* NO CODE HERE - dbgClassExit() must be the last thing before exit()! */ remove_pid(PidFile); - exit(0); /* "good" exit, this is the terminator function for rsyslog [die()] */ } /* @@ -900,323 +306,6 @@ static void doexit() exit(0); /* "good" exit, only during child-creation */ } -#if 0 /* TODO: re-enable, currently not used */ -/* helper to generateConfigDAG, to print out all actions via - * the llExecFunc() facility. - * rgerhards, 2007-08-02 - */ -struct dag_info { - FILE *fp; /* output file */ - int iActUnit; /* current action unit number */ - int iAct; /* current action in unit */ - int bDiscarded; /* message discarded (config error) */ - }; -DEFFUNC_llExecFunc(generateConfigDAGAction) -{ - action_t *pAction; - uchar *pszModName; - uchar *pszVertexName; - struct dag_info *pDagInfo; - DEFiRet; - - pDagInfo = (struct dag_info*) pParam; - pAction = (action_t*) pData; - - pszModName = module.GetStateName(pAction->pMod); - - /* vertex */ - if(pAction->pszName == NULL) { - if(!strcmp((char*)pszModName, "builtin-discard")) - pszVertexName = (uchar*)"discard"; - else - pszVertexName = pszModName; - } else { - pszVertexName = pAction->pszName; - } - - fprintf(pDagInfo->fp, "\tact%d_%d\t\t[label=\"%s\"%s%s]\n", - pDagInfo->iActUnit, pDagInfo->iAct, pszVertexName, - pDagInfo->bDiscarded ? " style=dotted color=red" : "", - (pAction->pQueue->qType == QUEUETYPE_DIRECT) ? "" : " shape=hexagon" - ); - - /* edge */ - if(pDagInfo->iAct == 0) { - } else { - fprintf(pDagInfo->fp, "\tact%d_%d -> act%d_%d[%s%s]\n", - pDagInfo->iActUnit, pDagInfo->iAct - 1, - pDagInfo->iActUnit, pDagInfo->iAct, - pDagInfo->bDiscarded ? " style=dotted color=red" : "", - pAction->bExecWhenPrevSusp ? " label=\"only if\\nsuspended\"" : "" ); - } - - /* check for discard */ - if(!strcmp((char*) pszModName, "builtin-discard")) { - fprintf(pDagInfo->fp, "\tact%d_%d\t\t[shape=box]\n", - pDagInfo->iActUnit, pDagInfo->iAct); - pDagInfo->bDiscarded = 1; - } - - - ++pDagInfo->iAct; - - RETiRet; -} - - -/* create config DAG - * This functions takes a rsyslog config and produces a .dot file for use - * with graphviz (http://www.graphviz.org). This is done in an effort to - * document, and also potentially troubleshoot, configurations. Plus, I - * consider it a nice feature to explain some concepts. Note that the - * current version only produces a graph with relatively little information. - * This is a foundation that may be later expanded (if it turns out to be - * useful enough). - * rgerhards, 2009-05-11 - */ -static rsRetVal -generateConfigDAG(uchar *pszDAGFile) -{ - //rule_t *f; - FILE *fp; - int iActUnit = 1; - //int bHasFilter = 0; /* filter associated with this action unit? */ - //int bHadFilter; - //int i; - struct dag_info dagInfo; - //char *pszFilterName; - char szConnectingNode[64]; - DEFiRet; - - assert(pszDAGFile != NULL); - - logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, (uchar*) - "Configuration graph generation is unfortunately disabled " - "in the current code base.", 0); - ABORT_FINALIZE(RS_RET_FILENAME_INVALID); - - if((fp = fopen((char*) pszDAGFile, "w")) == NULL) { - logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, (uchar*) - "configuraton graph output file could not be opened, none generated", 0); - ABORT_FINALIZE(RS_RET_FILENAME_INVALID); - } - - dagInfo.fp = fp; - - /* from here on, we assume writes go well. This here is a really - * unimportant utility function and if something goes wrong, it has - * almost no effect. So let's not overdo this... - */ - fprintf(fp, "# graph created by rsyslog " VERSION "\n\n" - "# use the dot tool from http://www.graphviz.org to visualize!\n" - "digraph rsyslogConfig {\n" - "\tinputs [shape=tripleoctagon]\n" - "\tinputs -> act0_0\n" - "\tact0_0 [label=\"main\\nqueue\" shape=hexagon]\n" - /*"\tmainq -> act1_0\n"*/ - ); - strcpy(szConnectingNode, "act0_0"); - dagInfo.bDiscarded = 0; - -/* TODO: re-enable! */ -#if 0 - for(f = Files; f != NULL ; f = f->f_next) { - /* BSD-Style filters are currently ignored */ - bHadFilter = bHasFilter; - if(f->f_filter_type == FILTER_PRI) { - bHasFilter = 0; - for (i = 0; i <= LOG_NFACILITIES; i++) - if (f->f_filterData.f_pmask[i] != 0xff) { - bHasFilter = 1; - break; - } - } else { - bHasFilter = 1; - } - - /* we know we have a filter, so it can be false */ - switch(f->f_filter_type) { - case FILTER_PRI: - pszFilterName = "pri filter"; - break; - case FILTER_PROP: - pszFilterName = "property filter"; - break; - case FILTER_EXPR: - pszFilterName = "script filter"; - break; - } - - /* write action unit node */ - if(bHasFilter) { - fprintf(fp, "\t%s -> act%d_end\t[label=\"%s:\\nfalse\"]\n", - szConnectingNode, iActUnit, pszFilterName); - fprintf(fp, "\t%s -> act%d_0\t[label=\"%s:\\ntrue\"]\n", - szConnectingNode, iActUnit, pszFilterName); - fprintf(fp, "\tact%d_end\t\t\t\t[shape=point]\n", iActUnit); - snprintf(szConnectingNode, sizeof(szConnectingNode), "act%d_end", iActUnit); - } else { - fprintf(fp, "\t%s -> act%d_0\t[label=\"no filter\"]\n", - szConnectingNode, iActUnit); - snprintf(szConnectingNode, sizeof(szConnectingNode), "act%d_0", iActUnit); - } - - /* draw individual nodes */ - dagInfo.iActUnit = iActUnit; - dagInfo.iAct = 0; - dagInfo.bDiscarded = 0; - llExecFunc(&f->llActList, generateConfigDAGAction, &dagInfo); /* actions */ - - /* finish up */ - if(bHasFilter && !dagInfo.bDiscarded) { - fprintf(fp, "\tact%d_%d -> %s\n", - iActUnit, dagInfo.iAct - 1, szConnectingNode); - } - - ++iActUnit; - } -#endif - - fprintf(fp, "\t%s -> act%d_0\n", szConnectingNode, iActUnit); - fprintf(fp, "\tact%d_0\t\t[label=discard shape=box]\n" - "}\n", iActUnit); - fclose(fp); - -finalize_it: - RETiRet; -} -#endif - - -/* create a main message queue, now also used for ruleset queues. This function - * needs to be moved to some other module, but it is considered acceptable for - * the time being (remember that we want to restructure config processing at large!). - * rgerhards, 2009-10-27 - */ -rsRetVal createMainQueue(qqueue_t **ppQueue, uchar *pszQueueName, struct nvlst *lst) -{ - struct queuefilenames_s *qfn; - uchar *qfname = NULL; - static int qfn_renamenum = 0; - uchar qfrenamebuf[1024]; - DEFiRet; - - /* create message queue */ - CHKiRet_Hdlr(qqueueConstruct(ppQueue, ourConf->globals.mainQ.MainMsgQueType, ourConf->globals.mainQ.iMainMsgQueueNumWorkers, ourConf->globals.mainQ.iMainMsgQueueSize, msgConsumer)) { - /* no queue is fatal, we need to give up in that case... */ - errmsg.LogError(0, iRet, "could not create (ruleset) main message queue"); \ - } - /* name our main queue object (it's not fatal if it fails...) */ - obj.SetName((obj_t*) (*ppQueue), pszQueueName); - - if(lst == NULL) { /* use legacy parameters? */ - /* ... set some properties ... */ - # define setQPROP(func, directive, data) \ - CHKiRet_Hdlr(func(*ppQueue, data)) { \ - errmsg.LogError(0, NO_ERRCODE, "Invalid " #directive ", error %d. Ignored, running with default setting", iRet); \ - } - # define setQPROPstr(func, directive, data) \ - CHKiRet_Hdlr(func(*ppQueue, data, (data == NULL)? 0 : strlen((char*) data))) { \ - errmsg.LogError(0, NO_ERRCODE, "Invalid " #directive ", error %d. Ignored, running with default setting", iRet); \ - } - - if(ourConf->globals.mainQ.pszMainMsgQFName != NULL) { - /* check if the queue file name is unique, else emit an error */ - for(qfn = queuefilenames ; qfn != NULL ; qfn = qfn->next) { - dbgprintf("check queue file name '%s' vs '%s'\n", qfn->name, ourConf->globals.mainQ.pszMainMsgQFName ); - if(!ustrcmp(qfn->name, ourConf->globals.mainQ.pszMainMsgQFName)) { - snprintf((char*)qfrenamebuf, sizeof(qfrenamebuf), "%d-%s-%s", - ++qfn_renamenum, ourConf->globals.mainQ.pszMainMsgQFName, - (pszQueueName == NULL) ? "NONAME" : (char*)pszQueueName); - qfname = ustrdup(qfrenamebuf); - errmsg.LogError(0, NO_ERRCODE, "Error: queue file name '%s' already in use " - " - using '%s' instead", ourConf->globals.mainQ.pszMainMsgQFName, qfname); - break; - } - } - if(qfname == NULL) - qfname = ustrdup(ourConf->globals.mainQ.pszMainMsgQFName); - qfn = malloc(sizeof(struct queuefilenames_s)); - qfn->name = qfname; - qfn->next = queuefilenames; - queuefilenames = qfn; - } - - setQPROP(qqueueSetMaxFileSize, "$MainMsgQueueFileSize", ourConf->globals.mainQ.iMainMsgQueMaxFileSize); - setQPROP(qqueueSetsizeOnDiskMax, "$MainMsgQueueMaxDiskSpace", ourConf->globals.mainQ.iMainMsgQueMaxDiskSpace); - setQPROP(qqueueSetiDeqBatchSize, "$MainMsgQueueDequeueBatchSize", ourConf->globals.mainQ.iMainMsgQueDeqBatchSize); - setQPROPstr(qqueueSetFilePrefix, "$MainMsgQueueFileName", qfname); - setQPROP(qqueueSetiPersistUpdCnt, "$MainMsgQueueCheckpointInterval", ourConf->globals.mainQ.iMainMsgQPersistUpdCnt); - setQPROP(qqueueSetbSyncQueueFiles, "$MainMsgQueueSyncQueueFiles", ourConf->globals.mainQ.bMainMsgQSyncQeueFiles); - setQPROP(qqueueSettoQShutdown, "$MainMsgQueueTimeoutShutdown", ourConf->globals.mainQ.iMainMsgQtoQShutdown ); - setQPROP(qqueueSettoActShutdown, "$MainMsgQueueTimeoutActionCompletion", ourConf->globals.mainQ.iMainMsgQtoActShutdown); - setQPROP(qqueueSettoWrkShutdown, "$MainMsgQueueWorkerTimeoutThreadShutdown", ourConf->globals.mainQ.iMainMsgQtoWrkShutdown); - setQPROP(qqueueSettoEnq, "$MainMsgQueueTimeoutEnqueue", ourConf->globals.mainQ.iMainMsgQtoEnq); - setQPROP(qqueueSetiHighWtrMrk, "$MainMsgQueueHighWaterMark", ourConf->globals.mainQ.iMainMsgQHighWtrMark); - setQPROP(qqueueSetiLowWtrMrk, "$MainMsgQueueLowWaterMark", ourConf->globals.mainQ.iMainMsgQLowWtrMark); - setQPROP(qqueueSetiDiscardMrk, "$MainMsgQueueDiscardMark", ourConf->globals.mainQ.iMainMsgQDiscardMark); - setQPROP(qqueueSetiDiscardSeverity, "$MainMsgQueueDiscardSeverity", ourConf->globals.mainQ.iMainMsgQDiscardSeverity); - setQPROP(qqueueSetiMinMsgsPerWrkr, "$MainMsgQueueWorkerThreadMinimumMessages", ourConf->globals.mainQ.iMainMsgQWrkMinMsgs); - setQPROP(qqueueSetbSaveOnShutdown, "$MainMsgQueueSaveOnShutdown", ourConf->globals.mainQ.bMainMsgQSaveOnShutdown); - setQPROP(qqueueSetiDeqSlowdown, "$MainMsgQueueDequeueSlowdown", ourConf->globals.mainQ.iMainMsgQDeqSlowdown); - setQPROP(qqueueSetiDeqtWinFromHr, "$MainMsgQueueDequeueTimeBegin", ourConf->globals.mainQ.iMainMsgQueueDeqtWinFromHr); - setQPROP(qqueueSetiDeqtWinToHr, "$MainMsgQueueDequeueTimeEnd", ourConf->globals.mainQ.iMainMsgQueueDeqtWinToHr); - - # undef setQPROP - # undef setQPROPstr - } else { /* use new style config! */ - qqueueSetDefaultsRulesetQueue(*ppQueue); - qqueueApplyCnfParam(*ppQueue, lst); - } - RETiRet; -} - -rsRetVal -startMainQueue(qqueue_t *pQueue) -{ - DEFiRet; - CHKiRet_Hdlr(qqueueStart(pQueue)) { - /* no queue is fatal, we need to give up in that case... */ - errmsg.LogError(0, iRet, "could not start (ruleset) main message queue"); \ - } - RETiRet; -} - - -/* INIT -- Initialize syslogd - * Note that if iConfigVerify is set, only the config file is verified but nothing - * else happens. -- rgerhards, 2008-07-28 - */ -static rsRetVal -init(void) -{ - char bufStartUpMsg[512]; - struct sigaction sigAct; - DEFiRet; - - memset(&sigAct, 0, sizeof (sigAct)); - sigemptyset(&sigAct.sa_mask); - sigAct.sa_handler = sighup_handler; - sigaction(SIGHUP, &sigAct, NULL); - - CHKiRet(rsconf.Activate(ourConf)); - DBGPRINTF(" started.\n"); - - /* we now generate the startup message. It now includes everything to - * identify this instance. -- rgerhards, 2005-08-17 - */ - if(ourConf->globals.bLogStatusMsgs) { - snprintf(bufStartUpMsg, sizeof(bufStartUpMsg)/sizeof(char), - " [origin software=\"rsyslogd\" " "swVersion=\"" VERSION \ - "\" x-pid=\"%d\" x-info=\"http://www.rsyslog.com\"] start", - (int) glblGetOurPid()); - logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, (uchar*)bufStartUpMsg, 0); - } - -finalize_it: - RETiRet; -} - /* * The following function is resposible for handling a SIGHUP signal. Since @@ -1224,7 +313,7 @@ finalize_it: * doing this during a signal handler. Instead this function simply sets * a flag variable which will tells the main loop to do "the right thing". */ -void sighup_handler() +void syslogd_sighup_handler() { struct sigaction sigAct; @@ -1232,116 +321,13 @@ void sighup_handler() memset(&sigAct, 0, sizeof (sigAct)); sigemptyset(&sigAct.sa_mask); - sigAct.sa_handler = sighup_handler; + sigAct.sa_handler = syslogd_sighup_handler; sigaction(SIGHUP, &sigAct, NULL); } -void sigttin_handler() -{ -} - -/* 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 inline void processImInternal(void) -{ - msg_t *pMsg; - - while(iminternalRemoveMsg(&pMsg) == RS_RET_OK) { - submitMsgWithDfltRatelimiter(pMsg); - } -} - - -/* helper to doHUP(), this "HUPs" each action. The necessary locking - * is done inside the action class and nothing we need to take care of. - * rgerhards, 2008-10-22 - */ -DEFFUNC_llExecFunc(doHUPActions) -{ - BEGINfunc - actionCallHUPHdlr((action_t*) pData); - ENDfunc - return RS_RET_OK; /* we ignore errors, we can not do anything either way */ -} - - -/* This function processes a HUP after one has been detected. Note that this - * is *NOT* the sighup handler. The signal is recorded by the handler, that record - * detected inside the mainloop and then this function is called to do the - * real work. -- rgerhards, 2008-10-22 - * Note: there is a VERY slim chance of a data race when the hostname is reset. - * We prefer to take this risk rather than sync all accesses, because to the best - * of my analysis it can not really hurt (the actual property is reference-counted) - * but the sync would require some extra CPU for *each* message processed. - * rgerhards, 2012-04-11 - */ -static inline void -doHUP(void) -{ - char buf[512]; - - if(ourConf->globals.bLogStatusMsgs) { - snprintf(buf, sizeof(buf) / sizeof(char), - " [origin software=\"rsyslogd\" " "swVersion=\"" VERSION - "\" x-pid=\"%d\" x-info=\"http://www.rsyslog.com\"] rsyslogd was HUPed", - (int) glblGetOurPid()); - errno = 0; - logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, (uchar*)buf, 0); - } - - queryLocalHostname(); /* re-read our name */ - ruleset.IterateAllActions(ourConf, doHUPActions, NULL); - lookupDoHUP(); -} - - -/* This is the main processing loop. It is called after successful initialization. - * When it returns, the syslogd terminates. - * Its sole function is to provide some housekeeping things. The real work is done - * by the other threads spawned. - */ -static void -mainloop(void) -{ - struct timeval tvSelectTimeout; - - BEGINfunc - /* first check if we have any internal messages queued and spit them out. We used - * to do that on any loop iteration, but that is no longer necessry. The reason - * is that once we reach this point here, we always run on multiple threads and - * thus the main queue is properly initialized. -- rgerhards, 2008-06-09 - */ - processImInternal(); - - while(!bFinished){ - /* this is now just a wait - please note that we do use a near-"eternal" - * timeout of 1 day. This enables us to help safe the environment - * by not unnecessarily awaking rsyslog on a regular tick (just think - * powertop, for example). In that case, we primarily wait for a signal, - * but a once-a-day wakeup should be quite acceptable. -- rgerhards, 2008-06-09 - */ - tvSelectTimeout.tv_sec = 86400 /*1 day*/; - tvSelectTimeout.tv_usec = 0; - select(1, NULL, NULL, NULL, &tvSelectTimeout); - if(bFinished) - break; /* exit as quickly as possible */ - - if(bHadHUP) { - doHUP(); - bHadHUP = 0; - continue; - } - } - ENDfunc -} - /* print version and compile-time setting information. */ -static void printVersion(void) +void syslogd_printVersion(void) { printf("rsyslogd %s, ", VERSION); printf("compiled with:\n"); @@ -1350,7 +336,9 @@ static void printVersion(void) #else printf("\tFEATURE_REGEXP:\t\t\t\tNo\n"); #endif +/* Yann Droneaud <yann@droneaud.fr> contribution */ #if defined(_LARGE_FILES) || (defined (_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS >= 64) +/* end Yann Droneaud <yann@droneaud.fr> contribution */ printf("\tFEATURE_LARGEFILE:\t\t\tYes\n"); #else printf("\tFEATURE_LARGEFILE:\t\t\tNo\n"); @@ -1370,7 +358,9 @@ static void printVersion(void) #else printf("\t32bit Atomic operations supported:\tNo\n"); #endif +/* mono_matsuko <aiueov@hotmail.co.jp> contribution */ #ifdef HAVE_ATOMIC_BUILTINS_64BIT +/* end mono_matsuko <aiueov@hotmail.co.jp> contribution */ printf("\t64bit Atomic operations supported:\tYes\n"); #else printf("\t64bit Atomic operations supported:\tNo\n"); @@ -1399,110 +389,46 @@ static void printVersion(void) } -/* Method to initialize all global classes and use the objects that we need. - * rgerhards, 2008-01-04 - * rgerhards, 2008-04-16: the actual initialization is now carried out by the runtime - */ -static rsRetVal -InitGlobalClasses(void) +/* obtain ptrs to all clases we need. */ +rsRetVal +syslogd_obtainClassPointers(void) { DEFiRet; char *pErrObj; /* tells us which object failed if that happens (useful for troubleshooting!) */ - /* Intialize the runtime system */ - pErrObj = "rsyslog runtime"; /* set in case the runtime errors before setting an object */ - CHKiRet(rsrtInit(&pErrObj, &obj)); - rsrtSetErrLogger(submitErrMsg); + CHKiRet(objGetObjInterface(&obj)); /* this provides the root pointer for all other queries */ /* Now tell the system which classes we need ourselfs */ pErrObj = "glbl"; CHKiRet(objUse(glbl, CORE_COMPONENT)); - pErrObj = "errmsg"; - CHKiRet(objUse(errmsg, CORE_COMPONENT)); - pErrObj = "module"; - CHKiRet(objUse(module, CORE_COMPONENT)); - pErrObj = "datetime"; - CHKiRet(objUse(datetime, CORE_COMPONENT)); - pErrObj = "ruleset"; - CHKiRet(objUse(ruleset, CORE_COMPONENT)); - pErrObj = "conf"; - CHKiRet(objUse(conf, CORE_COMPONENT)); - pErrObj = "prop"; - CHKiRet(objUse(prop, CORE_COMPONENT)); - pErrObj = "parser"; - CHKiRet(objUse(parser, CORE_COMPONENT)); - pErrObj = "rsconf"; - CHKiRet(objUse(rsconf, CORE_COMPONENT)); - - /* intialize some dummy classes that are not part of the runtime */ - pErrObj = "action"; - CHKiRet(actionClassInit()); - pErrObj = "template"; - CHKiRet(templateInit()); /* TODO: the dependency on net shall go away! -- rgerhards, 2008-03-07 */ pErrObj = "net"; CHKiRet(objUse(net, LM_NET_FILENAME)); - dnscacheInit(); - initRainerscript(); - ratelimitModInit(); finalize_it: if(iRet != RS_RET_OK) { /* we know we are inside the init sequence, so we can safely emit * messages to stderr. -- rgerhards, 2008-04-02 */ - fprintf(stderr, "Error during class init for object '%s' - failing...\n", pErrObj); + fprintf(stderr, "Error obtaining object '%s' - failing...\n", pErrObj); } RETiRet; } -/* Method to exit all global classes. We do not do any error checking here, - * because that wouldn't help us at all. So better try to deinit blindly - * as much as succeeds (which usually means everything will). We just must - * be careful to do the de-init in the opposite order of the init, because - * of the dependencies. However, its not as important this time, because - * we have reference counting. - * rgerhards, 2008-03-10 - */ -static rsRetVal -GlobalClassExit(void) +void +syslogd_releaseClassPointers(void) { - DEFiRet; - - /* first, release everything we used ourself */ objRelease(net, LM_NET_FILENAME);/* TODO: the dependency on net shall go away! -- rgerhards, 2008-03-07 */ - objRelease(prop, CORE_COMPONENT); - objRelease(conf, CORE_COMPONENT); - objRelease(ruleset, CORE_COMPONENT); - parserClassExit(); /* this is hack, currently core_modules do not get this automatically called */ - rsconfClassExit(); /* this is hack, currently core_modules do not get this automatically called */ - objRelease(datetime, CORE_COMPONENT); - - /* TODO: implement the rest of the deinit */ - /* dummy "classes */ - strExit(); - ratelimitModExit(); - -#if 0 - CHKiRet(objGetObjInterface(&obj)); /* this provides the root pointer for all other queries */ - /* the following classes were intialized by objClassInit() */ - CHKiRet(objUse(errmsg, CORE_COMPONENT)); - CHKiRet(objUse(module, CORE_COMPONENT)); -#endif - dnscacheDeinit(); - rsrtExit(); /* *THIS* *MUST/SHOULD?* always be the first class initilizer being called (except debug)! */ - - RETiRet; } /* query our host and domain names - we need to do this early as we may emit * rgerhards, 2012-04-11 */ -static rsRetVal +rsRetVal queryLocalHostname(void) { uchar *LocalHostName; @@ -1567,8 +493,10 @@ queryLocalHostname(void) } } + /* Marius Tomaschewski <mt@suse.com> contribution */ /* LocalDomain is "" or part of LocalHostName, allocate a new string */ CHKmalloc(LocalDomain = (uchar*)strdup((char*)LocalDomain)); + /* Marius Tomaschewski <mt@suse.com> contribution */ /* Convert to lower case to recognize the correct domain laterly */ for(p = LocalDomain ; *p ; p++) @@ -1581,90 +509,24 @@ queryLocalHostname(void) glbl.SetLocalHostName(LocalHostName); glbl.SetLocalDomain(LocalDomain); + /* Canonical contribution - ASL 2.0 fine (email exchange 2014-05-27) */ if ( strlen((char*)LocalDomain) ) { CHKmalloc(LocalFQDNName = (uchar*)malloc(strlen((char*)LocalDomain)+strlen((char*)LocalHostName)+2));/* one for dot, one for NUL! */ if ( sprintf((char*)LocalFQDNName,"%s.%s",(char*)LocalHostName,(char*)LocalDomain) ) glbl.SetLocalFQDNName(LocalFQDNName); } + /* end canonical contrib */ glbl.GenerateLocalHostNameProperty(); /* must be redone after conf processing, FQDN setting may have changed */ finalize_it: RETiRet; } - -/* some support for command line option parsing. Any non-trivial options must be - * buffered until the complete command line has been parsed. This is necessary to - * prevent dependencies between the options. That, in turn, means we need to have - * something that is capable of buffering options and there values. The follwing - * functions handle that. - * rgerhards, 2008-04-04 - */ -typedef struct bufOpt { - struct bufOpt *pNext; - char optchar; - char *arg; -} bufOpt_t; -static bufOpt_t *bufOptRoot = NULL; -static bufOpt_t *bufOptLast = NULL; - -/* add option buffer */ -static rsRetVal -bufOptAdd(char opt, char *arg) -{ - DEFiRet; - bufOpt_t *pBuf; - - if((pBuf = MALLOC(sizeof(bufOpt_t))) == NULL) - ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY); - - pBuf->optchar = opt; - pBuf->arg = arg; - pBuf->pNext = NULL; - - if(bufOptLast == NULL) { - bufOptRoot = pBuf; /* then there is also no root! */ - } else { - bufOptLast->pNext = pBuf; - } - bufOptLast = pBuf; - -finalize_it: - RETiRet; -} - - - -/* remove option buffer from top of list, return values and destruct buffer itself. - * returns RS_RET_END_OF_LINKEDLIST when no more options are present. - * (we use int *opt instead of char *opt to keep consistent with getopt()) - */ -static rsRetVal -bufOptRemove(int *opt, char **arg) -{ - DEFiRet; - bufOpt_t *pBuf; - - if(bufOptRoot == NULL) - ABORT_FINALIZE(RS_RET_END_OF_LINKEDLIST); - pBuf = bufOptRoot; - - *opt = pBuf->optchar; - *arg = pBuf->arg; - - bufOptRoot = pBuf->pNext; - free(pBuf); - -finalize_it: - RETiRet; -} - - /* global initialization, to be done only once and before the mainloop is started. * rgerhards, 2008-07-28 (extracted from realMain()) */ -static rsRetVal -doGlblProcessInit(void) +rsRetVal +syslogd_doGlblProcessInit(void) { struct sigaction sigAct; int num_fds; @@ -1682,8 +544,10 @@ doGlblProcessInit(void) sigAct.sa_handler = doexit; sigaction(SIGTERM, &sigAct, NULL); + /* RH contribution */ /* stop writing debug messages to stdout (if debugging is on) */ stddbg = -1; + /* end RH contribution */ dbgprintf("ready for forking\n"); if (fork()) { @@ -1767,7 +631,8 @@ doGlblProcessInit(void) } else { - fputs("Pidfile (and pid) already exist.\n", stderr); + fprintf(stderr, "rsyslogd: pidfile '%s' and pid %d already exist.\n", + PidFile, getpid()); exit(1); /* exit during startup - questionable */ } glblSetOurPid(getpid()); @@ -1779,16 +644,16 @@ doGlblProcessInit(void) sigaction(SIGSEGV, &sigAct, NULL); sigAct.sa_handler = sigsegvHdlr; sigaction(SIGABRT, &sigAct, NULL); - sigAct.sa_handler = doDie; + sigAct.sa_handler = rsyslogdDoDie; sigaction(SIGTERM, &sigAct, NULL); - sigAct.sa_handler = Debug ? doDie : SIG_IGN; + sigAct.sa_handler = Debug ? rsyslogdDoDie : SIG_IGN; sigaction(SIGINT, &sigAct, NULL); sigaction(SIGQUIT, &sigAct, NULL); sigAct.sa_handler = reapchild; sigaction(SIGCHLD, &sigAct, NULL); - sigAct.sa_handler = Debug ? debug_switch : SIG_IGN; + sigAct.sa_handler = Debug ? rsyslogdDebugSwitch : SIG_IGN; sigaction(SIGUSR1, &sigAct, NULL); - sigAct.sa_handler = sigttin_handler; + sigAct.sa_handler = rsyslogd_sigttin_handler; sigaction(SIGTTIN, &sigAct, NULL); /* (ab)used to interrupt input threads */ sigAct.sa_handler = SIG_IGN; sigaction(SIGPIPE, &sigAct, NULL); @@ -1798,335 +663,10 @@ doGlblProcessInit(void) } -/* This is the main entry point into rsyslogd. Over time, we should try to - * modularize it a bit more... - */ -int realMain(int argc, char **argv) +void +syslogdInit(void) { - rsRetVal localRet; - int ch; - extern int optind; - extern char *optarg; - int bEOptionWasGiven = 0; - int iHelperUOpt; - int bChDirRoot = 1; /* change the current working directory to "/"? */ - char *arg; /* for command line option processing */ - char cwdbuf[128]; /* buffer to obtain/display current working directory */ - DEFiRet; - - /* 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 - * the parameters down below in the correct order. For example, we must know the - * value of -M before we can do the init, but at the same time we need to have - * the base classes init before we can process most of the options. Now, with the - * split of functionality, this is no longer a problem. Thanks to varmofekoj for - * suggesting this algo. - * Note: where we just need to set some flags and can do so without knowledge - * of other options, we do this during the inital option processing. - * rgerhards, 2008-04-04 - */ - while((ch = getopt(argc, argv, "46a:Ac:dDef:g:hi:l:m:M:nN:op:qQr::s:S:t:T:u:vwx")) != EOF) { - switch((char)ch) { - case '4': - case '6': - case 'A': - case 'a': - case 'f': /* configuration file */ - case 'h': - case 'i': /* pid file name */ - case 'l': - case 'm': /* mark interval */ - case 'n': /* don't fork */ - case 'N': /* enable config verify mode */ - case 'o': - case 'p': - case 'q': /* add hostname if DNS resolving has failed */ - case 'Q': /* dont resolve hostnames in ACL to IPs */ - case 's': - case 'S': /* Source IP for local client to be used on multihomed host */ - case 'T': /* chroot on startup (primarily for testing) */ - case 'u': /* misc user settings */ - case 'w': /* disable disallowed host warnings */ - case 'x': /* disable dns for remote messages */ - case 'g': /* enable tcp gssapi logging */ - case 'r': /* accept remote messages */ - case 't': /* enable tcp logging */ - CHKiRet(bufOptAdd(ch, optarg)); - break; - case 'c': /* compatibility mode */ - fprintf(stderr, "rsyslogd: error: option -c is no longer supported - ignored\n"); - break; - case 'd': /* debug - must be handled now, so that debug is active during init! */ - debugging_on = 1; - Debug = 1; - yydebug = 1; - break; - case 'D': /* BISON debug */ - yydebug = 1; - break; - case 'e': /* log every message (no repeat message supression) */ - bEOptionWasGiven = 1; - break; - case 'M': /* default module load path -- this MUST be carried out immediately! */ - glblModPath = (uchar*) optarg; - break; - case 'v': /* MUST be carried out immediately! */ - printVersion(); - exit(0); /* exit for -v option - so this is a "good one" */ - case '?': - default: - usage(); - } - } - - if(argc - optind) - usage(); - - DBGPRINTF("rsyslogd %s startup, module path '%s', cwd:%s\n", - VERSION, glblModPath == NULL ? "" : (char*)glblModPath, - getcwd(cwdbuf, sizeof(cwdbuf))); - - /* we are done with the initial option parsing and processing. Now we init the system. */ - - ppid = getpid(); - - CHKiRet_Hdlr(InitGlobalClasses()) { - fprintf(stderr, "rsyslogd initializiation failed - global classes could not be initialized.\n" - "Did you do a \"make install\"?\n" - "Suggested action: run rsyslogd with -d -n options to see what exactly " - "fails.\n"); - FINALIZE; - } - - /* doing some core initializations */ - - /* we need to create the inputName property (only once during our lifetime) */ - CHKiRet(prop.Construct(&pInternalInputName)); - CHKiRet(prop.SetString(pInternalInputName, UCHAR_CONSTANT("rsyslogd"), sizeof("rsyslogd") - 1)); - CHKiRet(prop.ConstructFinalize(pInternalInputName)); - - /* get our host and domain names - we need to do this early as we may emit - * error log messages, which need the correct hostname. -- rgerhards, 2008-04-04 - */ - queryLocalHostname(); - - /* initialize the objects */ - 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 */ - } - - - /* END core initializations - we now come back to carrying out command line options*/ - - while((iRet = bufOptRemove(&ch, &arg)) == RS_RET_OK) { - DBGPRINTF("deque option %c, optarg '%s'\n", ch, (arg == NULL) ? "" : arg); - switch((char)ch) { - case '4': - glbl.SetDefPFFamily(PF_INET); - break; - case '6': - glbl.SetDefPFFamily(PF_INET6); - break; - case 'A': - send_to_all++; - break; - case 'a': - fprintf(stderr, "rsyslogd: error -a is no longer supported, use module imuxsock instead"); - break; - case 'S': /* Source IP for local client to be used on multihomed host */ - if(glbl.GetSourceIPofLocalClient() != NULL) { - fprintf (stderr, "rsyslogd: Only one -S argument allowed, the first one is taken.\n"); - } else { - glbl.SetSourceIPofLocalClient((uchar*)arg); - } - break; - case 'f': /* configuration file */ - ConfFile = (uchar*) arg; - break; - case 'g': /* enable tcp gssapi logging */ - fprintf(stderr, "rsyslogd: -g option no longer supported - ignored\n"); - case 'h': - fprintf(stderr, "rsyslogd: error -h is no longer supported - ignored"); - break; - case 'i': /* pid file name */ - PidFile = arg; - break; - case 'l': - if(glbl.GetLocalHosts() != NULL) { - fprintf (stderr, "rsyslogd: Only one -l argument allowed, the first one is taken.\n"); - } else { - glbl.SetLocalHosts(crunch_list(arg)); - } - break; - case 'm': /* mark interval */ - fprintf(stderr, "rsyslogd: error -m is no longer supported - use immark instead"); - break; - case 'n': /* don't fork */ - doFork = 0; - break; - case 'N': /* enable config verify mode */ - iConfigVerify = atoi(arg); - break; - case 'o': - fprintf(stderr, "error -o is no longer supported, use module imuxsock instead"); - break; - case 'p': - fprintf(stderr, "error -p is no longer supported, use module imuxsock instead"); - break; - case 'q': /* add hostname if DNS resolving has failed */ - *(net.pACLAddHostnameOnFail) = 1; - break; - case 'Q': /* dont resolve hostnames in ACL to IPs */ - *(net.pACLDontResolve) = 1; - break; - case 'r': /* accept remote messages */ - fprintf(stderr, "rsyslogd: error option -r is no longer supported - ignored"); - break; - case 's': - if(glbl.GetStripDomains() != NULL) { - fprintf (stderr, "rsyslogd: Only one -s argument allowed, the first one is taken.\n"); - } else { - glbl.SetStripDomains(crunch_list(arg)); - } - break; - case 't': /* enable tcp logging */ - fprintf(stderr, "rsyslogd: error option -t is no longer supported - ignored"); - break; - case 'T':/* chroot() immediately at program startup, but only for testing, NOT security yet */ - if(chroot(arg) != 0) { - perror("chroot"); - exit(1); - } - break; - case 'u': /* misc user settings */ - iHelperUOpt = atoi(arg); - if(iHelperUOpt & 0x01) - glbl.SetParseHOSTNAMEandTAG(0); - if(iHelperUOpt & 0x02) - bChDirRoot = 0; - break; - case 'w': /* disable disallowed host warnigs */ - glbl.SetOption_DisallowWarning(0); - break; - case 'x': /* disable dns for remote messages */ - glbl.SetDisableDNS(1); - break; - case '?': - default: - usage(); - } - } - - if(iRet != RS_RET_END_OF_LINKEDLIST) - FINALIZE; - - if(iConfigVerify) { - fprintf(stderr, "rsyslogd: version %s, config validation run (level %d), master config %s\n", - VERSION, iConfigVerify, ConfFile); - } - - localRet = rsconf.Load(&ourConf, ConfFile); + /* oxpa <iippolitov@gmail.com> contribution, need to check ASL 2.0 */ queryLocalHostname(); /* need to re-query to pick up a changed hostname due to config */ - - if(localRet == RS_RET_NONFATAL_CONFIG_ERR) { - if(loadConf->globals.bAbortOnUncleanConfig) { - fprintf(stderr, "rsyslogd: $AbortOnUncleanConfig is set, and config is not clean.\n" - "Check error log for details, fix errors and restart. As a last\n" - "resort, you may want to remove $AbortOnUncleanConfig to permit a\n" - "startup with a dirty config.\n"); - exit(2); - } - if(iConfigVerify) { - /* a bit dirty, but useful... */ - exit(1); - } - localRet = RS_RET_OK; - } - CHKiRet(localRet); - - CHKiRet(ratelimitNew(&dflt_ratelimiter, "rsyslogd", "dflt")); - /* TODO: add linux-type limiting capability */ - CHKiRet(ratelimitNew(&internalMsg_ratelimiter, "rsyslogd", "internal_messages")); - ratelimitSetLinuxLike(internalMsg_ratelimiter, 5, 500); - /* TODO: make internalMsg ratelimit settings configurable */ - - if(bChDirRoot) { - if(chdir("/") != 0) - fprintf(stderr, "Can not do 'cd /' - still trying to run\n"); - } - - /* process compatibility mode settings */ - if(bEOptionWasGiven) { - errmsg.LogError(0, NO_ERRCODE, "WARNING: \"message repeated n times\" feature MUST be turned on in " - "rsyslog.conf - CURRENTLY EVERY MESSAGE WILL BE LOGGED. Visit " - "http://www.rsyslog.com/rptdmsgreduction to learn " - "more and cast your vote if you want us to keep this feature."); - } - - if(!iConfigVerify) - CHKiRet(doGlblProcessInit()); - - /* Send a signal to the parent so it can terminate. */ - if(glblGetOurPid() != ppid) - kill(ppid, SIGTERM); - - CHKiRet(init()); - - if(Debug && debugging_on) { - dbgprintf("Debugging enabled, SIGUSR1 to turn off debugging.\n"); - } - - /* END OF INTIALIZATION */ - DBGPRINTF("initialization completed, transitioning to regular run mode\n"); - - /* close stderr and stdout if they are kept open during a fork. Note that this - * may introduce subtle security issues: if we are in a jail, one may break out of - * it via these descriptors. But if I close them earlier, error messages will (once - * again) not be emitted to the user that starts the daemon. As root jail support - * is still in its infancy (and not really done), we currently accept this issue. - * rgerhards, 2009-06-29 - */ - if(doFork) { - close(1); - close(2); - ourConf->globals.bErrMsgToStderr = 0; - } - - sd_notify(0, "READY=1"); - - mainloop(); - - /* do any de-init's that need to be done AFTER this comment */ - - die(bFinished); - - thrdExit(); - -finalize_it: - if(iRet == RS_RET_VALIDATION_RUN) { - fprintf(stderr, "rsyslogd: End of config validation run. Bye.\n"); - } else if(iRet != RS_RET_OK) { - fprintf(stderr, "rsyslogd: run failed with error %d (see rsyslog.h " - "or try http://www.rsyslog.com/e/%d to learn what that number means)\n", iRet, iRet*-1); - exit(1); - } - - ENDfunc - return 0; + /* end oxpa */ } - - -/* This is the main entry point into rsyslogd. This must be a function in its own - * right in order to intialize the debug system in a portable way (otherwise we would - * need to have a statement before variable definitions. - * rgerhards, 20080-01-28 - */ -int main(int argc, char **argv) -{ - dbgClassInit(); - return realMain(argc, argv); -} -/* vim:set ai: - */ |