diff options
author | Rainer Gerhards <rgerhards@adiscon.com> | 2007-11-21 16:34:48 +0000 |
---|---|---|
committer | Rainer Gerhards <rgerhards@adiscon.com> | 2007-11-21 16:34:48 +0000 |
commit | 3bb7ad8246bca95c89d68a8b0402b8482489c877 (patch) | |
tree | 798656b4722649346cbd43a0a328041832666237 | |
parent | bb6bfca3dfa6a5d3500e51459b38bb6d0ca6a4b2 (diff) | |
download | rsyslog-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.c | 46 | ||||
-rw-r--r-- | linkedlist.c | 120 | ||||
-rw-r--r-- | linkedlist.h | 1 | ||||
-rw-r--r-- | module-template.h | 13 | ||||
-rw-r--r-- | modules.c | 9 | ||||
-rw-r--r-- | modules.h | 3 | ||||
-rw-r--r-- | rsyslog.h | 1 | ||||
-rw-r--r-- | syslogd.c | 8 |
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;\ } @@ -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; @@ -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. */ @@ -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 */ @@ -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); |