summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRainer Gerhards <rgerhards@adiscon.com>2007-11-21 16:34:48 +0000
committerRainer Gerhards <rgerhards@adiscon.com>2007-11-21 16:34:48 +0000
commit3bb7ad8246bca95c89d68a8b0402b8482489c877 (patch)
tree798656b4722649346cbd43a0a328041832666237
parentbb6bfca3dfa6a5d3500e51459b38bb6d0ca6a4b2 (diff)
downloadrsyslog-3bb7ad8246bca95c89d68a8b0402b8482489c877.tar.gz
rsyslog-3bb7ad8246bca95c89d68a8b0402b8482489c877.tar.xz
rsyslog-3bb7ad8246bca95c89d68a8b0402b8482489c877.zip
- added an identifier to command handler table - need to identify which
command handler entries need to be removed when module is unloaded - added support so that linkedlist key can be used for owner handle - enhanced llExecFunc to support deletion of list elements (on behalf of user function being called, slight interface change) - enhanced linkedlist class so that list elements can now be deleted based on the key value they have - created entry point so that CfSysLine handlers are removed on modExit()
-rw-r--r--cfsysline.c46
-rw-r--r--linkedlist.c120
-rw-r--r--linkedlist.h1
-rw-r--r--module-template.h13
-rw-r--r--modules.c9
-rw-r--r--modules.h3
-rw-r--r--rsyslog.h1
-rw-r--r--syslogd.c8
8 files changed, 188 insertions, 13 deletions
diff --git a/cfsysline.c b/cfsysline.c
index 96a2c396..196dc254 100644
--- a/cfsysline.c
+++ b/cfsysline.c
@@ -662,6 +662,50 @@ rsRetVal unregCfSysLineHdlrs(void)
}
+/* helper function for unregCfSysLineHdlrs4Owner(). This is used to see if there is
+ * a handler of this owner inside the element and, if so, remove it. Please note that
+ * it keeps track of a pointer to the last linked list entry, as this is needed to
+ * remove an entry from the list.
+ * rgerhards, 2007-11-21
+ */
+DEFFUNC_llExecFunc(unregHdlrsHeadExec)
+{
+ DEFiRet;
+ cslCmd_t *pListHdr = (cslCmd_t*) pData;
+ int iNumElts;
+
+ /* first find element */
+ iRet = llFindAndDelete(&(pListHdr->llCmdHdlrs), pParam);
+
+ /* now go back and check how many elements are left */
+ CHKiRet(llGetNumElts(&(pListHdr->llCmdHdlrs), &iNumElts));
+
+ if(iNumElts == 0) {
+ /* nothing left in header, so request to delete it */
+ iRet = RS_RET_OK_DELETE_LISTENTRY;
+ }
+
+finalize_it:
+ return iRet;
+}
+/* unregister and destroy cfSysLineHandlers for a specific owner. This method is
+ * most importantly used before unloading a loadable module providing some handlers.
+ * The full list of handlers is searched. If the to-be removed handler was the only
+ * handler for a directive name, the directive header, too, is deleted.
+ * rgerhards, 2007-11-21
+ */
+rsRetVal unregCfSysLineHdlrs4Owner(void *pOwnerCookie)
+{
+ DEFiRet;
+ /* we need to walk through all directive names, as the linked list
+ * class does not provide a way to just search the lower-level handlers.
+ */
+ iRet = llExecFunc(&llCmdList, unregHdlrsHeadExec, pOwnerCookie);
+
+ return iRet;
+}
+
+
/* process a cfsysline command (based on handler structure)
* param "p" is a pointer to the command line after the command. Should be
* updated.
@@ -738,7 +782,7 @@ void dbgPrintCfSysLineHandlers(void)
printf("\t\ttype : %d\n", pCmdHdlr->eType);
printf("\t\tpData: 0x%x\n", (unsigned) pCmdHdlr->pData);
printf("\t\tHdlr : 0x%x\n", (unsigned) pCmdHdlr->cslCmdHdlr);
- printf("\t\tOwner: 0x%x\n", (unsigned) llCookieCmd->pKey);
+ printf("\t\tOwner: 0x%x\n", (unsigned) llCookieCmdHdlr->pKey);
printf("\n");
}
}
diff --git a/linkedlist.c b/linkedlist.c
index b9239b48..bea2cb90 100644
--- a/linkedlist.c
+++ b/linkedlist.c
@@ -229,36 +229,124 @@ finalize_it:
}
-/* find a user element based on the provided key
+/* unlink a requested element. As we have singly-linked lists, the
+ * caller also needs to pass in the previous element (or NULL, if it is the
+ * root element).
+ * rgerhards, 2007-11-21
*/
-rsRetVal llFind(linkedList_t *pThis, void *pKey, void **ppData)
+static rsRetVal llUnlinkElt(linkedList_t *pThis, llElt_t *pElt, llElt_t *pEltPrev)
+{
+ assert(pElt != NULL);
+
+ if(pEltPrev == NULL) { /* root element? */
+ pThis->pRoot = pElt->pNext;
+ } else { /* regular element */
+ pEltPrev->pNext = pElt->pNext;
+ }
+
+ if(pElt == pThis->pLast)
+ pThis->pLast = pEltPrev;
+
+ return RS_RET_OK;
+}
+
+
+/* unlinks and immediately deletes an element. Previous element must
+ * be given (or zero if the root element is to be deleted).
+ * rgerhards, 2007-11-21
+ */
+static rsRetVal llUnlinkAndDelteElt(linkedList_t *pThis, llElt_t *pElt, llElt_t *pEltPrev)
+{
+ DEFiRet;
+
+ assert(pElt != NULL);
+
+ CHKiRet(llUnlinkElt(pThis, pElt, pEltPrev));
+ CHKiRet(llDestroyElt(pThis, pElt));
+
+finalize_it:
+ return iRet;
+}
+
+/* find a user element based on the provided key - this is the
+ * internal variant, which also tracks the last element pointer
+ * before the found element. This is necessary to delete elements.
+ * NULL means there is no element in front of it, aka the found elt
+ * is the root elt.
+ * rgerhards, 2007-11-21
+ */
+static rsRetVal llFindElt(linkedList_t *pThis, void *pKey, llElt_t **ppElt, llElt_t **ppEltPrev)
{
DEFiRet;
llElt_t *pElt;
+ llElt_t *pEltPrev = NULL;
int bFound = 0;
assert(pThis != NULL);
assert(pKey != NULL);
- assert(ppData != NULL);
+ assert(ppElt != NULL);
+ assert(ppEltPrev != NULL);
pElt = pThis->pRoot;
while(pElt != NULL && bFound == 0) {
if(pThis->cmpOp(pKey, pElt->pKey) == 0)
bFound = 1;
- else
+ else {
+ pEltPrev = pElt;
pElt = pElt->pNext;
+ }
}
if(bFound == 1) {
- *ppData = pElt->pData;
- } else {
+ *ppElt = pElt;
+ *ppEltPrev = pEltPrev;
+ } else
iRet = RS_RET_NOT_FOUND;
- }
return iRet;
}
+/* find a user element based on the provided key
+ */
+rsRetVal llFind(linkedList_t *pThis, void *pKey, void **ppData)
+{
+ DEFiRet;
+ llElt_t *pElt;
+ llElt_t *pEltPrev;
+
+ CHKiRet(llFindElt(pThis, pKey, &pElt, &pEltPrev));
+
+ /* if we reach this point, we have found the element */
+ *ppData = pElt->pData;
+
+finalize_it:
+ return iRet;
+}
+
+
+/* find a delete an element based on user-provided key. The element is
+ * delete, the caller does not receive anything. If we need to receive
+ * the element before destruction, we may implement an llFindAndUnlink()
+ * at that time.
+ * rgerhards, 2007-11-21
+ */
+rsRetVal llFindAndDelete(linkedList_t *pThis, void *pKey)
+{
+ DEFiRet;
+ llElt_t *pElt;
+ llElt_t *pEltPrev;
+
+ CHKiRet(llFindElt(pThis, pKey, &pElt, &pEltPrev));
+
+ /* if we reach this point, we have found an element */
+ CHKiRet(llUnlinkAndDelteElt(pThis, pElt, pEltPrev));
+
+finalize_it:
+ return iRet;
+}
+
+
/* provide the count of linked list elements
*/
rsRetVal llGetNumElts(linkedList_t *pThis, int *piCnt)
@@ -279,6 +367,9 @@ rsRetVal llGetNumElts(linkedList_t *pThis, int *piCnt)
* or a pointer to a structure with more data. If the user-supplied
* function does not return RS_RET_OK, this function here terminates.
* rgerhards, 2007-08-02
+ * rgerhards, 2007-11-21: added functionality to delete a list element.
+ * If the called user function returns RS_RET_OK_DELETE_LISTENTRY the current element
+ * is deleted.
*/
rsRetVal llExecFunc(linkedList_t *pThis, rsRetVal (*pFunc)(void*, void*), void* pParam)
{
@@ -286,12 +377,25 @@ rsRetVal llExecFunc(linkedList_t *pThis, rsRetVal (*pFunc)(void*, void*), void*
rsRetVal iRetLL;
void *pData;
linkedListCookie_t llCookie = NULL;
+ linkedListCookie_t llCookiePrev = NULL; /* previous list element (needed for deletion, NULL = at root) */
assert(pThis != NULL);
assert(pFunc != NULL);
while((iRetLL = llGetNextElt(pThis, &llCookie, (void**)&pData)) == RS_RET_OK) {
- CHKiRet(pFunc(pData, pParam));
+ iRet = pFunc(pData, pParam);
+ if(iRet == RS_RET_OK_DELETE_LISTENTRY) {
+ /* delete element */
+ CHKiRet(llUnlinkAndDelteElt(pThis, llCookie, llCookiePrev));
+ /* we need to revert back, as we have just deleted the current element.
+ * So the actual current element is the one before it, which happens to be
+ * stored in llCookiePrev. -- rgerhards, 2007-11-21
+ */
+ llCookie = llCookiePrev;
+ } else if (iRet != RS_RET_OK) {
+ goto finalize_it;
+ }
+ llCookiePrev = llCookie;
}
if(iRetLL != RS_RET_END_OF_LINKEDLIST)
diff --git a/linkedlist.h b/linkedlist.h
index aafbcf88..e4de9c1c 100644
--- a/linkedlist.h
+++ b/linkedlist.h
@@ -61,6 +61,7 @@ rsRetVal llFind(linkedList_t *pThis, void *pKey, void **ppData);
rsRetVal llGetKey(llElt_t *pThis, void *ppData);
rsRetVal llGetNumElts(linkedList_t *pThis, int *piCnt);
rsRetVal llExecFunc(linkedList_t *pThis, rsRetVal (*pFunc)(void*, void*), void* pParam);
+rsRetVal llFindAndDelete(linkedList_t *pThis, void *pKey);
/* use the macro below to define a function that will be executed by
* llExecFunc()
*/
diff --git a/module-template.h b/module-template.h
index 9521d08f..13ae4b86 100644
--- a/module-template.h
+++ b/module-template.h
@@ -44,6 +44,16 @@
#define STD_LOADABLE_MODULE_ID ((void*) modExit)
+/* macro to implement the "modGetID()" interface function
+ * rgerhards 2007-11-21
+ */
+#define DEFmodGetID \
+static rsRetVal modGetID(void **pID) \
+ { \
+ *pID = STD_LOADABLE_MODULE_ID;\
+ return RS_RET_OK;\
+ }
+
/* to following macros are used to generate function headers and standard
* functionality. It works as follows (described on the sample case of
* createInstance()):
@@ -284,6 +294,7 @@ static rsRetVal tryResume(instanceData __attribute__((unused)) *pData)\
/* queryEtryPt()
*/
#define BEGINqueryEtryPt \
+DEFmodGetID \
static rsRetVal queryEtryPt(uchar *name, rsRetVal (**pEtryPoint)())\
{\
DEFiRet;
@@ -324,6 +335,8 @@ static rsRetVal queryEtryPt(uchar *name, rsRetVal (**pEtryPoint)())\
*pEtryPoint = needUDPSocket;\
} else if(!strcmp((char*) name, "tryResume")) {\
*pEtryPoint = tryResume;\
+ } else if(!strcmp((char*) name, "modGetID")) {\
+ *pEtryPoint = modGetID;\
}
diff --git a/modules.c b/modules.c
index e997eb40..b7ba6dd8 100644
--- a/modules.c
+++ b/modules.c
@@ -184,6 +184,7 @@ modInfo_t *omodGetNxt(modInfo_t *pThis)
static rsRetVal modUnload(modInfo_t *pThis)
{
DEFiRet;
+ void *pModCookie;
assert(pThis != NULL);
@@ -192,7 +193,9 @@ static rsRetVal modUnload(modInfo_t *pThis)
* CVS snapshot, be aware of this limitation. For now, you can just remove everything up to
* (but not including) the END DEVEL comment. That will do the trick. rgerhards, 2007-11-21
*/
-dbgprintf("we are now calling modExit()\n");
+ CHKiRet(pThis->modGetID(&pModCookie));
+dbgprintf("we are now calling modExit(), module id %x\n", pModCookie);
+ CHKiRet(unregCfSysLineHdlrs4Owner(pModCookie));
/* END DEVEL */
@@ -283,6 +286,10 @@ rsRetVal doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)())
moduleDestruct(pNew);
return iRet;
}
+ if((iRet = (*pNew->modQueryEtryPt)((uchar*)"modGetID", &pNew->modGetID)) != RS_RET_OK) {
+ moduleDestruct(pNew);
+ return iRet;
+ }
if((iRet = (*pNew->modQueryEtryPt)((uchar*)"modExit", &pNew->modExit)) != RS_RET_OK) {
moduleDestruct(pNew);
return iRet;
diff --git a/modules.h b/modules.h
index 3f008a6a..4782d319 100644
--- a/modules.h
+++ b/modules.h
@@ -62,7 +62,8 @@ typedef struct moduleInfo {
rsRetVal (*needUDPSocket)(void*);/* called when fd is writeable after select() */
rsRetVal (*dbgPrintInstInfo)(void*);/* called before termination or module unload */
rsRetVal (*tryResume)(void*);/* called to see if module actin can be resumed now */
- rsRetVal (*modExit)(); /* called before termination or module unload */
+ rsRetVal (*modExit)(void); /* called before termination or module unload */
+ rsRetVal (*modGetID)(void **); /* get its unique ID from module */
/* below: parse a configuration line - return if processed
* or not. If not, must be parsed to next module.
*/
diff --git a/rsyslog.h b/rsyslog.h
index 00f8fad4..b6e17d55 100644
--- a/rsyslog.h
+++ b/rsyslog.h
@@ -73,6 +73,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth
RS_RET_INVALID_SOURCE = -2019, /**< source (address) invalid for some reason */
RS_RET_ADDRESS_UNKNOWN = -2020, /**< an address is unknown - not necessarily an error */
RS_RET_MALICIOUS_ENTITY = -2021, /**< there is an malicious entity involved */
+ RS_RET_OK_DELETE_LISTENTRY = 1, /**< operation successful, but callee requested the deletion of an entry (special state) */
RS_RET_OK = 0 /**< operation successful */
};
typedef enum rsRetVal_ rsRetVal; /**< friendly type for global return value */
diff --git a/syslogd.c b/syslogd.c
index 70d68df2..5a087839 100644
--- a/syslogd.c
+++ b/syslogd.c
@@ -3644,8 +3644,6 @@ static void die(int sig)
/* de-init some modules */
modExitIminternal();
- unregCfSysLineHdlrs(); /* TODO: this needs to go away when the module de-init works */
-
/* 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).
@@ -3658,6 +3656,12 @@ static void die(int sig)
*/
modUnloadAndDestructAll();
+ /* the following line cleans up CfSysLineHandlers that were not based on loadable
+ * modules. As such, they are not yet cleared.
+ */
+ unregCfSysLineHdlrs();
+
+
/* clean up auxiliary data */
if(pModDir != NULL)
free(pModDir);