/** * This is a state monitor. It collects all the start and stop messages * from the device executor and from scan and batch commands. Clients can * listen to this in order to figure out what is actually going on in a * given SICS installation. This might in the end supersede the status code * management in status.c * * copyright: see file COPYRIGHT * * Mark Koennecke, January 2007 */ #include #include "exeman.h" #include "scan.h" #include "scan.i" #include "stptok.h" #include "statemon.h" #include "sicshipadaba.h" /*==========================================================================*/ typedef struct __STATEMON { pObjectDescriptor pDes; pICallBack pCall; } StateMon; /*============================ Callbacks =================================*/ static int DevexecCallback(int iEvent, void *text, void *pData) { char pDevice[132]; int eventCode; pStateMon self = (pStateMon) pData; memset(pDevice, 0, 132); if (iEvent == DRIVSTAT) { stptok(text, pDevice, 131, " "); if (strstr(text, "started") != NULL) { eventCode = STSTART; } else if (strstr(text, "finished") != NULL) { eventCode = STEND; } else { printf("Unrecognized event text from devexec in statemon.c: %s\n", (char *) text); return 0; } if (self != NULL) { InvokeCallBack(self->pCall, eventCode, pDevice); } } return 1; } /*---------------------------------------------------------------------------*/ static int StateMonScanInterest(int iEvent, void *pEventData, void *pUser) { pScanData pScan = NULL; pStateMon self = (pStateMon) pUser; pScan = (pScanData) pEventData; if (pScan == NULL || self == NULL) { printf("Bad StateMonScanInterst in statemon\n"); return 0; } if (iEvent == SCANSTART) { InvokeCallBack(self->pCall, STSTART, pScan->objectName); return 1; } else if (iEvent == SCANEND) { InvokeCallBack(self->pCall, STEND, pScan->objectName); return 1; } return 1; } /*--------------------------------------------------------------------------*/ static int ExeCallback(int iEvent, void *pEvent, void *pUser) { pStateMon self = (pStateMon) pUser; char *name = (char *) pEvent; char pBueffel[131]; if (self == NULL || name == NULL) { printf("Bad ExeCallback in statemon\n"); return 0; } if (iEvent == BATCHSTART) { snprintf(pBueffel, 131, "exe %s", name); InvokeCallBack(self->pCall, STSTART, pBueffel); return 1; } if (iEvent == BATCHEND) { snprintf(pBueffel, 131, "exe %s", name); InvokeCallBack(self->pCall, STEND, pBueffel); return 1; } return 0; } /*=============== user callbacks ============================================*/ static int StateInterest(int iEvent, void *pEvent, void *pUser) { SConnection *pCon = (SConnection *) pUser; char *device = (char *) pEvent; char buffer[256]; if (pCon == NULL || !SCisConnected(pCon)) { return -1; } if (pCon == NULL || device == NULL) { printf("Bad StateInterest in statemon\n"); return 0; } if (iEvent == STSTART) { snprintf(buffer, 255, "STARTED = %s", device); SCWrite(pCon, buffer, eEvent); } if (iEvent == STEND) { snprintf(buffer, 255, "FINISH = %s", device); SCWrite(pCon, buffer, eEvent); } return 1; } /*--------------------------------------------------------------------------*/ static pHdb recurseInterestNode(pHdb current, char *pDevice) { char pSicsdev[132], pAlias[132]; pHdb result = NULL; char *alias = NULL, *pPtr = NULL; memset(pSicsdev, 0, 132); memset(pAlias, 0, 132); if (current != NULL) { if (GetHdbProperty(current, "sicsdev", pSicsdev, 131) != 0) { strtolower(pSicsdev); if (strcmp(pSicsdev, pDevice) == 0) { return current; } /* * try to look for aliases, too */ alias = FindAliases(pServ->pSics, pSicsdev); pPtr = alias; if (pPtr != NULL) { while ((pPtr = stptok(pPtr, pAlias, 131, ",")) != NULL) { if (strcmp(pAlias, pDevice) == 0) { return current; } } if (alias != NULL) { free(alias); } } } current = current->child; while (current != NULL) { result = recurseInterestNode(current, pDevice); if (result != NULL) { return result; } current = current->next; } } return NULL; } /*--------------------------------------------------------------------------*/ static pHdb locateInterestNode(char *device) { char pDevice[132], pSicsdev[132]; pHdb current = NULL, result = NULL; memset(pDevice, 0, 132); memset(pSicsdev, 0, 132); /* * this is to strip off exes batch file name */ stptok(device, pDevice, 131, " "); strtolower(pDevice); current = GetHipadabaRoot(); return recurseInterestNode(current, pDevice); } /*--------------------------------------------------------------------------*/ static int StateHdbInterest(int iEvent, void *pEvent, void *pUser) { SConnection *pCon = (SConnection *) pUser; char *device = (char *) pEvent, *path = NULL; char buffer[1024]; pHdb node = NULL; if (pCon == NULL || !SCisConnected(pCon)) { return -1; } if (device == NULL) { printf("Bad StateHdbInterest in statemon\n"); return 0; } node = locateInterestNode(device); if (node != NULL) { path = GetHipadabaPath(node); if (iEvent == STSTART) { snprintf(buffer, 1024, "%s STARTED", path); SCWrite(pCon, buffer, eEvent); } if (iEvent == STEND) { snprintf(buffer, 1024, "%s FINISH", path); SCWrite(pCon, buffer, eEvent); } if (path != NULL) { free(path); } } return 1; } /*====================== interpreter interface ==============================*/ static void killStateMon(void *pData) { pStateMon self = NULL; self = (pStateMon) pData; if (self != NULL) { if (self->pDes != NULL) { DeleteDescriptor(self->pDes); } if (self->pCall != NULL) { DeleteCallBackInterface(self->pCall); } free(self); } } /*---------------------------------------------------------------------------*/ int StateMonFactory(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { pStateMon pNew = NULL; commandContext cc; pICallBack target = NULL; void *pPtr = NULL, *exe = NULL, *pDevexec = NULL; exe = FindCommandData(pSics, "exe", "ExeManager"); pDevexec = FindCommandData(pSics, "stopexe", "DeviceExecutor"); if (exe == NULL || pDevexec == NULL) { SCWrite(pCon, "ERROR: both the device executor and the batch file module must be installed before initialising statemon", eError); return 0; } /* * generate data structures */ strcpy(cc.deviceID, "statemon"); cc.transID = -120; pNew = (pStateMon) malloc(sizeof(StateMon)); if (pNew == NULL) { SCWrite(pCon, "ERROR: out of memory creating StateMon", eError); return 0; } memset(pNew, 0, sizeof(StateMon)); pNew->pDes = CreateDescriptor("statemon"); pNew->pCall = CreateCallBackInterface(); if (pNew->pDes == NULL || pNew->pCall == NULL) { SCWrite(pCon, "ERROR: out of memory creating StateMon", eError); return 0; } /* * register callbacks */ target = GetCallbackInterface(pDevexec); assert(target != NULL); RegisterCallback(target, DRIVSTAT, DevexecCallback, pNew, NULL); target = GetCallbackInterface(exe); assert(target != NULL); RegisterCallback(target, BATCHSTART, ExeCallback, pNew, NULL); RegisterCallback(target, BATCHEND, ExeCallback, pNew, NULL); if (argc > 1) { pPtr = FindCommandData(pSics, argv[1], "ScanObject"); if (pPtr == NULL) { SCWrite(pCon, "ERROR: failed to locate scan object", eError); } else { target = GetCallbackInterface(pPtr); assert(target != NULL); RegisterCallback(target, SCANSTART, StateMonScanInterest, pNew, NULL); RegisterCallback(target, SCANEND, StateMonScanInterest, pNew, NULL); } } AddCommand(pSics, "statemon", StateMonAction, killStateMon, pNew); return 1; } /* * Context test function for callback removal */ int CheckConMatch(const void* context, const void* pUserData) { SConnection *pKon = (SConnection*) pUserData; SConnection *pCon = (SConnection*) context; if (VerifyConnection(pCon) && VerifyConnection(pKon)) { if (SCGetIdent(pCon) == SCGetIdent(pKon)) return 0; } return 1; } /*---------------------------------------------------------------------------*/ int StateMonAction(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { long lID; int i; pStateMon self = NULL; SConnection *callCon = NULL; self = (pStateMon) pData; assert(self != NULL); if (argc < 2) { SCWrite(pCon, "ERROR: not enough arguments to statemon", eError); return 0; } strtolower(argv[1]); if (strcmp(argv[1], "interest") == 0) { RemoveCallbackUsr(self->pCall, StateInterest, CheckConMatch, pCon); /* only this one */ callCon = SCCopyConnection(pCon); if (callCon == NULL) { SCWrite(pCon, "ERROR: out of memory registering interest", eError); return 0; } lID = RegisterCallback(self->pCall, STSTART, StateInterest, callCon, SCDeleteConnection); SCRegister(pCon, pSics, self->pCall, lID); lID = RegisterCallback(self->pCall, STEND, StateInterest, callCon, NULL); SCSendOK(pCon); return 1; } else if (strcmp(argv[1], "uninterest") == 0) { RemoveCallbackUsr(self->pCall, StateInterest, CheckConMatch, pCon); /* only this one */ SCSendOK(pCon); return 1; } else if (strcmp(argv[1], "hdbuninterest") == 0) { RemoveCallbackUsr(self->pCall, StateHdbInterest, CheckConMatch, pCon); /* only this one */ SCSendOK(pCon); return 1; } else if (strcmp(argv[1], "hdbinterest") == 0) { RemoveCallbackUsr(self->pCall, StateHdbInterest, CheckConMatch, pCon); /* only this one */ callCon = SCCopyConnection(pCon); if (callCon == NULL) { SCWrite(pCon, "ERROR: out of memory registering interest", eError); return 0; } lID = RegisterCallback(self->pCall, STSTART, StateHdbInterest, callCon, SCDeleteConnection); lID = RegisterCallback(self->pCall, STEND, StateHdbInterest, callCon, NULL); SCSendOK(pCon); return 1; } else if (strcmp(argv[1], "start") == 0) { if (argc > 2) { InvokeCallBack(self->pCall, STSTART, argv[2]); SCSendOK(pCon); return 1; } return 0; } else if (strcmp(argv[1], "stop") == 0) { if (argc > 2) { InvokeCallBack(self->pCall, STEND, argv[2]); SCSendOK(pCon); return 1; } return 0; } SCWrite(pCon, "ERROR: keyword not recognized", eError); return 0; }