diff -u -p -r rsyslog-3.21.11.orig/ChangeLog rsyslog-3.21.11/ChangeLog --- rsyslog-3.21.11.orig/ChangeLog 2009-04-13 11:50:41.000000000 +0200 +++ rsyslog-3.21.11/ChangeLog 2009-04-13 11:53:46.000000000 +0200 @@ -1,3 +1,6 @@ +- added configuration directive "HUPisRestart" which enables to configure + HUP to be either a full restart or "just" a leightweight way to + close open files. --------------------------------------------------------------------------- Version 3.21.11 [BETA] (rgerhards), 2009-04-03 - build system improvements contributed by Michael Biebl - thx! Only in rsyslog-3.21.11: ChangeLog.orig diff -u -p -r rsyslog-3.21.11.orig/action.c rsyslog-3.21.11/action.c --- rsyslog-3.21.11.orig/action.c 2009-04-13 11:50:41.000000000 +0200 +++ rsyslog-3.21.11/action.c 2009-04-13 11:53:46.000000000 +0200 @@ -498,6 +498,39 @@ finalize_it: } #pragma GCC diagnostic warning "-Wempty-body" + +/* call the HUP handler for a given action, if such a handler is defined. The + * action mutex is locked, because the HUP handler most probably needs to modify + * some internal state information. + * rgerhards, 2008-10-22 + */ +#pragma GCC diagnostic ignored "-Wempty-body" +rsRetVal +actionCallHUPHdlr(action_t *pAction) +{ + DEFiRet; + int iCancelStateSave; + + ASSERT(pAction != NULL); + dbgprintf("Action %p checks HUP hdlr: %p\n", pAction, pAction->pMod->doHUP); + + if(pAction->pMod->doHUP == NULL) { + FINALIZE; /* no HUP handler, so we are done ;) */ + } + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &iCancelStateSave); + d_pthread_mutex_lock(&pAction->mutActExec); + pthread_cleanup_push(mutexCancelCleanup, &pAction->mutActExec); + pthread_setcancelstate(iCancelStateSave, NULL); + CHKiRet(pAction->pMod->doHUP(pAction->pModData)); + pthread_cleanup_pop(1); /* unlock mutex */ + +finalize_it: + RETiRet; +} +#pragma GCC diagnostic warning "-Wempty-body" + + /* set the action message queue mode * TODO: probably move this into queue object, merge with MainMsgQueue! * rgerhards, 2008-01-28 diff -u -p -r rsyslog-3.21.11.orig/action.h rsyslog-3.21.11/action.h --- rsyslog-3.21.11.orig/action.h 2009-04-13 11:50:41.000000000 +0200 +++ rsyslog-3.21.11/action.h 2009-04-13 11:53:46.000000000 +0200 @@ -85,6 +85,7 @@ rsRetVal actionSetGlobalResumeInterval(i rsRetVal actionDoAction(action_t *pAction); rsRetVal actionCallAction(action_t *pAction, msg_t *pMsg); rsRetVal actionWriteToAction(action_t *pAction); +rsRetVal actionCallHUPHdlr(action_t *pAction); rsRetVal actionClassInit(void); rsRetVal addAction(action_t **ppAction, modInfo_t *pMod, void *pModData, omodStringRequest_t *pOMSR, int bSuspended); diff -u -p -r rsyslog-3.21.11.orig/doc/rsyslog_conf.html rsyslog-3.21.11/doc/rsyslog_conf.html --- rsyslog-3.21.11.orig/doc/rsyslog_conf.html 2009-04-13 11:50:41.000000000 +0200 +++ rsyslog-3.21.11/doc/rsyslog_conf.html 2009-04-13 11:53:46.000000000 +0200 @@ -175,6 +175,11 @@ default 60000 (1 minute)]
  • $GssForwardServiceName
  • $GssListenServiceName
  • $GssMode
  • +
  • $HUPisRestart [on/off] - if set to on, a HUP is a full daemon restart. This means any queued messages are discarded (depending +on queue configuration, of course) all modules are unloaded and reloaded. This mode keeps compatible with sysklogd, but is +not recommended for use with rsyslog. To do a full restart, simply stop and start the daemon. The default is "on" for +compatibility reasons. If it is set to "off", a HUP will only close open files. This is a much quicker action and usually +the only one that is needed e.g. for log rotation. It is recommended to set the setting to "off".
  • $IncludeConfig
  • MainMsgQueueCheckpointInterval <number>
  • $MainMsgQueueDequeueSlowdown <number> [number is timeout in microseconds (1000000us is 1sec!), diff -u -p -r rsyslog-3.21.11.orig/runtime/glbl.c rsyslog-3.21.11/runtime/glbl.c --- rsyslog-3.21.11.orig/runtime/glbl.c 2009-04-13 11:50:41.000000000 +0200 +++ rsyslog-3.21.11/runtime/glbl.c 2009-04-13 11:53:46.000000000 +0200 @@ -52,6 +52,7 @@ DEFobjStaticHelpers */ static uchar *pszWorkDir = NULL; static int iMaxLine = 2048; /* maximum length of a syslog message */ +static int bHUPisRestart = 1; /* should SIGHUP cause a full system restart? */ static int iDefPFFamily = PF_UNSPEC; /* protocol family (IPv4, IPv6 or both) */ static int bDropMalPTRMsgs = 0;/* Drop messages which have malicious PTR records during DNS lookup */ static int option_DisallowWarning = 1; /* complain if message from disallowed sender is received */ @@ -86,6 +87,7 @@ static dataType Get##nameFunc(void) \ } SIMP_PROP(MaxLine, iMaxLine, int) +SIMP_PROP(HUPisRestart, bHUPisRestart, int) SIMP_PROP(DefPFFamily, iDefPFFamily, int) /* note that in the future we may check the family argument */ SIMP_PROP(DropMalPTRMsgs, bDropMalPTRMsgs, int) SIMP_PROP(Option_DisallowWarning, option_DisallowWarning, int) @@ -173,6 +175,7 @@ CODESTARTobjQueryInterface(glbl) pIf->Get##name = Get##name; \ pIf->Set##name = Set##name; SIMP_PROP(MaxLine); + SIMP_PROP(HUPisRestart); SIMP_PROP(DefPFFamily); SIMP_PROP(DropMalPTRMsgs); SIMP_PROP(Option_DisallowWarning); @@ -216,6 +219,7 @@ static rsRetVal resetConfigVariables(uch pszWorkDir = NULL; } bDropMalPTRMsgs = 0; + bHUPisRestart = 1; return RS_RET_OK; } @@ -235,6 +239,7 @@ BEGINAbstractObjClassInit(glbl, 1, OBJ_I CHKiRet(regCfSysLineHdlr((uchar *)"defaultnetstreamdrivercafile", 0, eCmdHdlrGetWord, NULL, &pszDfltNetstrmDrvrCAF, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"defaultnetstreamdriverkeyfile", 0, eCmdHdlrGetWord, NULL, &pszDfltNetstrmDrvrKeyFile, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"defaultnetstreamdrivercertfile", 0, eCmdHdlrGetWord, NULL, &pszDfltNetstrmDrvrCertFile, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"hupisrestart", 0, eCmdHdlrBinary, NULL, &bHUPisRestart, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, NULL)); ENDObjClassInit(glbl) diff -u -p -r rsyslog-3.21.11.orig/runtime/glbl.h rsyslog-3.21.11/runtime/glbl.h --- rsyslog-3.21.11.orig/runtime/glbl.h 2009-04-13 11:50:41.000000000 +0200 +++ rsyslog-3.21.11/runtime/glbl.h 2009-04-13 11:53:46.000000000 +0200 @@ -41,6 +41,7 @@ BEGINinterface(glbl) /* name must also b dataType (*Get##name)(void); \ rsRetVal (*Set##name)(dataType); SIMP_PROP(MaxLine, int) + SIMP_PROP(HUPisRestart, int) SIMP_PROP(DefPFFamily, int) SIMP_PROP(DropMalPTRMsgs, int) SIMP_PROP(Option_DisallowWarning, int) diff -u -p -r rsyslog-3.21.11.orig/runtime/module-template.h rsyslog-3.21.11/runtime/module-template.h --- rsyslog-3.21.11.orig/runtime/module-template.h 2009-04-13 11:50:41.000000000 +0200 +++ rsyslog-3.21.11/runtime/module-template.h 2009-04-13 11:53:46.000000000 +0200 @@ -481,6 +481,33 @@ static rsRetVal afterRun(void)\ } -/* - * vi:set ai: +/* doHUP() + * This function is optional. Currently, it is available to output plugins + * only, but may be made available to other types of plugins in the future. + * A plugin does not need to define this entry point. If if does, it gets + * called when a non-restart type of HUP is done. A plugin should register + * this function so that it can close files, connection or other ressources + * on HUP - if it can be assume the user wanted to do this as a part of HUP + * processing. Note that the name "HUP" has historical reasons, it stems back + * to the infamous SIGHUP which was sent to restart a syslogd. We still retain + * that legacy, but may move this to a different signal. + * rgerhards, 2008-10-22 + */ +#define CODEqueryEtryPt_doHUP \ + else if(!strcmp((char*) name, "doHUP")) {\ + *pEtryPoint = doHUP;\ + } +#define BEGINdoHUP \ +static rsRetVal doHUP(instanceData __attribute__((unused)) *pData)\ +{\ + DEFiRet; + +#define CODESTARTdoHUP + +#define ENDdoHUP \ + RETiRet;\ +} + + +/* vim:set ai: */ diff -u -p -r rsyslog-3.21.11.orig/runtime/modules.c rsyslog-3.21.11/runtime/modules.c --- rsyslog-3.21.11.orig/runtime/modules.c 2009-04-13 11:50:41.000000000 +0200 +++ rsyslog-3.21.11/runtime/modules.c 2009-04-13 11:53:46.000000000 +0200 @@ -347,6 +347,7 @@ static rsRetVal doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_t*), uchar *name, void *pModHdlr) { DEFiRet; + rsRetVal localRet; modInfo_t *pNew = NULL; rsRetVal (*modGetType)(eModType_t *pType); @@ -391,6 +392,10 @@ doModInit(rsRetVal (*modInit)(int, int*, CHKiRet((*pNew->modQueryEtryPt)((uchar*)"parseSelectorAct", &pNew->mod.om.parseSelectorAct)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"isCompatibleWithFeature", &pNew->isCompatibleWithFeature)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"tryResume", &pNew->tryResume)); + /* try load optional interfaces */ + localRet = (*pNew->modQueryEtryPt)((uchar*)"doHUP", &pNew->doHUP); + if(localRet != RS_RET_OK && localRet != RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) + ABORT_FINALIZE(localRet); break; case eMOD_LIB: break; diff -u -p -r rsyslog-3.21.11.orig/runtime/modules.h rsyslog-3.21.11/runtime/modules.h --- rsyslog-3.21.11.orig/runtime/modules.h 2009-04-13 11:50:41.000000000 +0200 +++ rsyslog-3.21.11/runtime/modules.h 2009-04-13 11:53:46.000000000 +0200 @@ -88,6 +88,7 @@ typedef struct modInfo_s { rsRetVal (*tryResume)(void*);/* called to see if module actin can be resumed now */ rsRetVal (*modExit)(void); /* called before termination or module unload */ rsRetVal (*modGetID)(void **); /* get its unique ID from module */ + rsRetVal (*doHUP)(void *); /* non-restart type HUP handler */ /* below: parse a configuration line - return if processed * or not. If not, must be parsed to next module. */ diff -u -p -r rsyslog-3.21.11.orig/tools/omfile.c rsyslog-3.21.11/tools/omfile.c --- rsyslog-3.21.11.orig/tools/omfile.c 2009-04-13 11:50:41.000000000 +0200 +++ rsyslog-3.21.11/tools/omfile.c 2009-04-13 11:53:46.000000000 +0200 @@ -244,7 +244,6 @@ static rsRetVal cflineParseOutchannel(in */ pData->f_sizeLimitCmd = (char*) pOch->cmdOnSizeLimit; -RUNLOG_VAR("%p", pszTplName); iRet = cflineParseTemplateName(&p, pOMSR, iEntry, iTplOpts, (pszTplName == NULL) ? (uchar*)"RSYSLOG_FileFormat" : pszTplName); @@ -349,9 +348,11 @@ finalize_it: } -/* This function frees the dynamic file name cache. +/* This function frees all dynamic file name cache entries and closes the + * relevant files. Part of Shutdown and HUP processing. + * rgerhards, 2008-10-23 */ -static void dynaFileFreeCache(instanceData *pData) +static inline void dynaFileFreeCacheEntries(instanceData *pData) { register int i; ASSERT(pData != NULL); @@ -360,17 +361,36 @@ static void dynaFileFreeCache(instanceDa for(i = 0 ; i < pData->iCurrCacheSize ; ++i) { dynaFileDelCacheEntry(pData->dynCache, i, 1); } + ENDfunc; +} + + +/* This function frees the dynamic file name cache. + */ +static void dynaFileFreeCache(instanceData *pData) +{ + ASSERT(pData != NULL); + BEGINfunc; + dynaFileFreeCacheEntries(pData); if(pData->dynCache != NULL) d_free(pData->dynCache); ENDfunc; } -/* This is a shared code for both static and dynamic files. +/* This is now shared code for all types of files. It simply prepares + * file access, which, among others, means the the file wil be opened + * and any directories in between will be created (based on config, of + * course). -- rgerhards, 2008-10-22 */ static void prepareFile(instanceData *pData, uchar *newFileName) { + if(pData->fileType == eTypePIPE) { + pData->fd = open((char*) pData->f_fname, O_RDWR|O_NONBLOCK); + FINALIZE; /* we are done in this case */ + } + if(access((char*)newFileName, F_OK) == 0) { /* file already exists */ pData->fd = open((char*) newFileName, O_WRONLY|O_APPEND|O_CREAT|O_NOCTTY, @@ -413,6 +433,12 @@ static void prepareFile(instanceData *pD } } } +finalize_it: + if((pData->fd) != 0 && isatty(pData->fd)) { + dbgprintf("file %d is a tty file\n", pData->fd); + pData->fileType = eTypeTTY; + untty(); + } } @@ -537,6 +563,8 @@ static rsRetVal writeFile(uchar **ppStri if(pData->bDynamicName) { if(prepareDynFile(pData, ppString[1], iMsgOpts) != 0) ABORT_FINALIZE(RS_RET_ERR); + } else if(pData->fd == -1) { + prepareFile(pData, pData->f_fname); } /* create the message based on format specified */ @@ -642,12 +670,7 @@ ENDtryResume BEGINdoAction CODESTARTdoAction dbgprintf(" (%s)\n", pData->f_fname); - /* pData->fd == -1 is an indicator that the we couldn't - * open the file at startup. For dynaFiles, this is ok, - * all others are doomed. - */ - if(pData->bDynamicName || (pData->fd != -1)) - iRet = writeFile(ppString, iMsgOpts, pData); + iRet = writeFile(ppString, iMsgOpts, pData); ENDdoAction @@ -764,11 +787,7 @@ CODESTARTparseSelectorAct pData->dirUID = dirUID; pData->dirGID = dirGID; - if(pData->fileType == eTypePIPE) { - pData->fd = open((char*) pData->f_fname, O_RDWR|O_NONBLOCK); - } else { - prepareFile(pData, pData->f_fname); - } + prepareFile(pData, pData->f_fname); if ( pData->fd < 0 ){ pData->fd = -1; @@ -776,10 +795,6 @@ CODESTARTparseSelectorAct errmsg.LogError(0, NO_ERRCODE, "%s", pData->f_fname); break; } - if (isatty(pData->fd)) { - pData->fileType = eTypeTTY; - untty(); - } if (strcmp((char*) p, _PATH_CONSOLE) == 0) pData->fileType = eTypeCONSOLE; break; @@ -815,6 +830,20 @@ static rsRetVal resetConfigVariables(uch } +BEGINdoHUP +CODESTARTdoHUP + if(pData->bDynamicName) { + dynaFileFreeCacheEntries(pData); + pData->iCurrElt = -1; /* invalidate current element */ + } else { + if(pData->fd != -1) { + close(pData->fd); + pData->fd = -1; + } + } +ENDdoHUP + + BEGINmodExit CODESTARTmodExit if(pszTplName != NULL) @@ -825,6 +854,7 @@ ENDmodExit BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_OMOD_QUERIES +CODEqueryEtryPt_doHUP ENDqueryEtryPt diff -u -p -r rsyslog-3.21.11.orig/tools/syslogd.c rsyslog-3.21.11/tools/syslogd.c --- rsyslog-3.21.11.orig/tools/syslogd.c 2009-04-13 11:50:41.000000000 +0200 +++ rsyslog-3.21.11/tools/syslogd.c 2009-04-13 11:53:46.000000000 +0200 @@ -219,7 +219,7 @@ static char *PidFile = _PATH_LOGPID; /* static pid_t myPid; /* our pid for use in self-generated messages, e.g. on startup */ /* mypid is read-only after the initial fork() */ -static int restart = 0; /* do restart (config read) - multithread safe */ +static int bHadHUP = 0; /* did we have a HUP? */ static int bParseHOSTNAMEandTAG = 1; /* global config var: should the hostname and tag be * parsed inside message - rgerhards, 2006-03-13 */ @@ -2525,13 +2525,13 @@ static rsRetVal setMainMsgQueType(void _ * The following function is resposible for handling a SIGHUP signal. Since * we are now doing mallocs/free as part of init we had better not being * doing this during a signal handler. Instead this function simply sets - * a flag variable which will tell the main loop to go through a restart. + * a flag variable which will tells the main loop to do "the right thing". */ void sighup_handler() { struct sigaction sigAct; - restart = 1; + bHadHUP = 1; memset(&sigAct, 0, sizeof (sigAct)); sigemptyset(&sigAct.sa_mask); @@ -2560,6 +2560,49 @@ static void processImInternal(void) } +/* 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 + */ +static inline void +doHUP(void) +{ + selector_t *f; + char buf[512]; + + snprintf(buf, sizeof(buf) / sizeof(char), + " [origin software=\"rsyslogd\" " "swVersion=\"" VERSION + "\" x-pid=\"%d\" x-info=\"http://www.rsyslog.com\"] rsyslogd was HUPed, type '%s'.", + (int) myPid, glbl.GetHUPisRestart() ? "restart" : "lightweight"); + errno = 0; + logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, (uchar*)buf, 0); + + if(glbl.GetHUPisRestart()) { + dbgprintf("Received SIGHUP, configured to be restart, reloading rsyslogd.\n"); + init(); /* main queue is stopped as part of init() */ + } else { + dbgprintf("Received SIGHUP, configured to be a non-restart type of HUP - notifying actions.\n"); + for(f = Files; f != NULL ; f = f->f_next) { + llExecFunc(&f->llActList, doHUPActions, NULL); + } + } +} + + /* 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 @@ -2616,11 +2659,9 @@ mainloop(void) if(bReduceRepeatMsgs == 1) doFlushRptdMsgs(); - if(restart) { - dbgprintf("\nReceived SIGHUP, reloading rsyslogd.\n"); - /* main queue is stopped as part of init() */ - init(); - restart = 0; + if(bHadHUP) { + doHUP(); + bHadHUP = 0; continue; } }