/** * This is a set of helper functions for SICS to work with the hierarchical parameter * database hipadaba. In SICS, the calldata associated with any callback will always * be the connection object. * * copyright: GPL * * Mark Koennecke, June 2006 * * Introduced notification on tree changes, Mark Koennecke, November 2006 * * Added property functions, Mark Koennecke, January 2007 * * Added hmatchprop function. Mark Koennecke, February 2008 * * TODO: separate this into two modules: sicshipadaba proper and sicshipadabaint for the * interpreter interface. * * Refactored to new callback system, Markus Zolliker, Mark Koennecke, March 2008 * * Added start and finished messages to commands. Mark Koennecke, November 2008 */ #include #include #include #include #include #include #include "sicspoll.h" #include #include #include "protocol.h" #include "statusfile.h" #include #include "sicsobj.h" #include #include "commandlog.h" #include "arrayutil.h" #define MAX_HDB_PATH 1024 /*== there can be only one hipadaba in SICS, some globals to care for that == */ static pHdb root = NULL; static pSicsPoll poller = NULL; typedef enum { normal_protocol, json_protocol, } Protocol; char *trim(char *str); /*====================== Messages ==================================================*/ static char killID[] = { "killID" }; static char killInternalID[] = { "killInternalID" }; static char killPtr[] = { "killPtr" }; static char startID[] = { "start" }; static char stopID[] = { "stop" }; /*----------------------------------------------------------------------------------*/ pHdbIDMessage GetKillIDMessage(pHdbMessage message) { if (message->type == killID) { return (pHdbIDMessage) message; } return NULL; } /*-----------------------------------------------------------------------------------*/ pHdbIDMessage GetKillInternalIDMessage(pHdbMessage message) { if (message->type == killInternalID) { return (pHdbIDMessage) message; } return NULL; } /*-----------------------------------------------------------------------------------*/ pHdbPtrMessage GetKillPtrMessage(pHdbMessage message) { if (message->type == killPtr) { return (pHdbPtrMessage) message; } return NULL; } /*-----------------------------------------------------------------------------------*/ pHdbMessage GetHdbStartMessage(pHdbMessage message) { if (message->type == startID) { return (pHdbMessage) message; } return NULL; } /*-----------------------------------------------------------------------------------*/ pHdbMessage GetHdbStopMessage(pHdbMessage message) { if (message->type == stopID) { return (pHdbMessage) message; } return NULL; } /*-----------------------------------------------------------------------------------*/ void SendHdbStatusMessage(pHdb node, char *status) { pHdbMessage pRes = NULL; pRes = malloc(sizeof(hdbMessage)); if (pRes == NULL) { return; } if (strcmp(status, "start") == 0) { pRes->type = startID; } else if (strcmp(status, "stop") == 0) { pRes->type = stopID; } else { /* someone is trying to create an non existent message */ assert(0); } InvokeCallbackChain(node, pRes); free(pRes); } /*=============== common callback functions used for SICS ===========================*/ static hdbCallbackReturn SICSCheckPermissionCallback(pHdb node, void *userData, pHdbMessage message) { int *testPriv = NULL; SConnection *pCon = NULL; pHdbDataMessage mm = NULL; testPriv = (int *) userData; mm = GetHdbSetMessage(message); if (mm == NULL) { return hdbContinue; } pCon = (SConnection *) mm->callData; /* * If pCon is NULL, then this is an internal call from some driver * code where no permission check is necessary. However, when called * through the hipadaba tree commands and other upper level code, the * check will be honoured. */ if (pCon == NULL) { return hdbContinue; } assert(testPriv != NULL); if (SCMatchRights(pCon, *testPriv) == 1) { return hdbContinue; } else { return hdbAbort; } } /*--------------------------------------------------------------------------------------*/ pHdbCallback MakeCheckPermissionCallback(int priv) { int *testPriv = NULL; testPriv = malloc(sizeof(int)); if (testPriv == NULL) { return NULL; } *testPriv = priv; return MakeHipadabaCallback(SICSCheckPermissionCallback, testPriv, free); } /*-------------------------------------------------------------------------------------*/ static char *removeSetUpdateID = "removeSetUpdate"; void RemoveSetUpdateCallback(pHdb node) { hdbPtrMessage m; m.type = killPtr; m.pPtr = removeSetUpdateID; InvokeCallbackChain(node, (pHdbMessage) & m); } /*-------------------------------------------------------------------------------------*/ static hdbCallbackReturn SICSSetUpdateCallback(pHdb node, void *userData, pHdbMessage message) { pHdbDataMessage mm = NULL; pHdbPtrMessage pm = NULL; int status; pm = GetKillPtrMessage(message); if (pm != NULL) { if (pm->pPtr == removeSetUpdateID) { return hdbKill; } return hdbContinue; } mm = GetHdbSetMessage(message); if (mm == NULL) { return hdbContinue; } status = UpdateHipadabaPar(node, *(mm->v), mm->callData); if (status && mm->callData != NULL) { SCSendOK(mm->callData); } return hdbContinue; } /*-------------------------------------------------------------------------------------*/ pHdbCallback MakeSetUpdateCallback() { return MakeHipadabaCallback(SICSSetUpdateCallback, NULL, NULL); } /*---------------------------------------------------------------------------------------*/ static hdbCallbackReturn SICSReadOnlyCallback(pHdb node, void *userData, pHdbMessage message) { SConnection *pCon = NULL; pHdbDataMessage mm = NULL; mm = GetHdbSetMessage(message); if (mm == NULL) { return hdbContinue; } pCon = (SConnection *) mm->callData; if (pCon != NULL) { SCWrite(pCon, "ERROR: parameter is READ-ONLY", eError); } return hdbAbort; } /*-------------------------------------------------------------------------------------*/ pHdbCallback MakeReadOnlyCallback() { return MakeHipadabaCallback(SICSReadOnlyCallback, NULL, NULL); } /*-------------------------------------------------------------------------------------*/ static hdbCallbackReturn SICSDriveCallback(pHdb node, void *userData, pHdbMessage message) { SConnection *pCon = NULL; pDummy dum = NULL; char pSicsdev[80]; int status; pHdbDataMessage mm = NULL; hdbValue v; mm = GetHdbSetMessage(message); if (mm == NULL) { return hdbContinue; } pCon = (SConnection *) mm->callData; v = *(mm->v); dum = (pDummy) userData; assert(pCon != NULL && dum != NULL); if (GetHdbProperty(node, "sicsdev", pSicsdev, 79)) { status = StartDevice(pServ->pExecutor, pSicsdev, dum->pDescriptor, userData, pCon, RUNDRIVE, (float) v.v.doubleValue); } else { status = StartDevice(pServ->pExecutor, node->name, dum->pDescriptor, userData, pCon, pCon->runLevel, (float) v.v.doubleValue); } if (status == 1) { return hdbContinue; } else { return hdbAbort; } } /*---------------------------------------------------------------------------------------*/ pHdbCallback MakeSICSDriveCallback(void *sicsObject) { return MakeHipadabaCallback(SICSDriveCallback, sicsObject, NULL); } /*---------------------------------------------------------------------------------------*/ static hdbCallbackReturn SICSReadDriveCallback(pHdb node, void *userData, pHdbMessage message) { static SConnection *defCon = NULL; SConnection *pCon = NULL; pDummy dum = NULL; pIDrivable pDriv = NULL; float value; pHdbDataMessage mm = NULL; mm = GetHdbGetMessage(message); if (mm == NULL) { return hdbContinue; } pCon = (SConnection *) mm->callData; dum = (pDummy) userData; assert(dum != NULL); if (defCon == NULL) { defCon = SCCreateDummyConnection(pServ->pSics); } pDriv = dum->pDescriptor->GetInterface(dum, DRIVEID); assert(pDriv != NULL); if (pCon != NULL) { value = pDriv->GetValue(dum, pCon); node->value.v.doubleValue = (double) value; mm->v->v.doubleValue = (double) value; } else { if (defCon != NULL) { value = pDriv->GetValue(dum, defCon); node->value.v.doubleValue = (double) value; mm->v->v.doubleValue = (double) value; } } return hdbContinue; } /*--------------------------------------------------------------------------*/ static hdbCallbackReturn SICSFuncCallback(pHdb node, void *userData, pHdbMessage message) { pHdb par[64], current = NULL; int nPar = 0; SICSOBJFunc func = NULL; pHdbDataMessage mm = NULL; int status; mm = GetHdbSetMessage(message); if (mm == NULL) { return hdbContinue; } assert(node->value.dataType == HIPFUNC); if (userData == NULL || mm->callData == NULL) { printf("Great Badness in calling SICSFuncCallback\n"); return hdbAbort; } current = node->child; while (current != NULL) { par[nPar] = current; nPar++; current = current->next; } func = (SICSOBJFunc) node->value.v.func; if (func != NULL) { SendHdbStatusMessage(node, "start"); status = func((pSICSOBJ) userData, (SConnection *) mm->callData, node, par, nPar); SendHdbStatusMessage(node, "stop"); } else { printf("Great Badness in calling SICSFuncCallback\n"); return hdbAbort; } if (status == 1) { return hdbContinue; } else { return hdbAbort; } } /*---------------------------------------------------------------------------*/ pHdbCallback MakeSICSFuncCallback(void *obj) { return MakeHipadabaCallback(SICSFuncCallback, obj, NULL); } /*--------------------------------------------------------------------------------------*/ pHdbCallback MakeSICSReadDriveCallback(void *sicsObject) { return MakeHipadabaCallback(SICSReadDriveCallback, sicsObject, NULL); } /*---------------------------------------------------------------------------------------*/ typedef struct { SConnection *pCon; int ID; int internalID; } HdbCBInfo; static Protocol isJSON(SConnection * pCon, int notify) { char proName[128]; void *pData; if (notify == 0 && SCinMacro(pCon)) { return normal_protocol; } pData = FindCommandData(pServ->pSics, "protocol", "Protocol"); ProtocolGet(pCon, pData, proName, 128); if (strcmp(proName, "json") == 0) return json_protocol; else return normal_protocol; } /* Format a name,value pair according to the given protocol */ int formatNameValue(Protocol protocol, char *name, char *value, pDynString result, int hdtype) { char *char_arr, *ptr; switch (protocol) { case normal_protocol: DynStringCopy(result, name); DynStringConcat(result, " = "); DynStringConcat(result, value); break; case json_protocol: switch (hdtype) { case HIPNONE: break; case HIPINT: case HIPFLOAT: DynStringCopy(result, "{\""); DynStringConcat(result, name); DynStringConcat(result, "\": "); DynStringConcat(result, value); DynStringConcat(result, "}"); break; case HIPTEXT: DynStringCopy(result, "{\""); DynStringConcat(result, name); DynStringConcat(result, "\": \""); DynStringConcat(result, value); DynStringConcat(result, "\"}"); break; case HIPINTAR: case HIPINTVARAR: case HIPFLOATAR: case HIPFLOATVARAR: char_arr = ptr = strdup(trim(value)); while (*ptr != '\0') { if (isspace(*ptr)) *ptr = ','; ptr++; } DynStringCopy(result, "{\""); DynStringConcat(result, name); DynStringConcat(result, "\": [ "); DynStringConcat(result, char_arr); DynStringConcat(result, " ]}"); if (char_arr != NULL) free(char_arr); break; } } return protocol; } /*----------------------------------------------------------------------------*/ static int sendZippedNodeData(pHdb node, hdbValue newValue, SConnection * pCon) { int i, *iData = NULL, zip = 1; char *path = NULL; double sum = 0; char value[80]; path = GetHipadabaPath(node); if (GetHdbProperty(node, "transfer", value, 80) == 1) { if(strstr(value,"bin") != NULL) { zip = 0; } } switch (newValue.dataType) { case HIPINTAR: case HIPINTVARAR: if (newValue.v.intArray == NULL) { free(path); return 0; } iData = (int *) malloc(newValue.arrayLength * sizeof(int)); if (iData == NULL) { SCWrite(pCon, "ERROR: out of memory in sendZippedData", eError); free(path); return 0; } memset(iData, 0, newValue.arrayLength * sizeof(int)); for (i = 0; i < newValue.arrayLength; i++) { /* sum += (double)newValue.v.intArray[i]; */ iData[i] = htonl(newValue.v.intArray[i]); } if(zip == 1){ SCWriteZipped(pCon, path, iData, newValue.arrayLength * sizeof(int)); } else { SCWriteBinary(pCon, path, iData, newValue.arrayLength * sizeof(int)); } free(iData); /* printf("Wrote zipped data %s, sum %lf\n", path, sum); */ break; case HIPFLOATAR: case HIPFLOATVARAR: if (newValue.v.floatArray == NULL) { free(path); return 0; } iData = (int *) malloc(newValue.arrayLength * sizeof(int)); if (iData == NULL) { SCWrite(pCon, "ERROR: out of memory in sendZippedData", eError); free(path); return 0; } memset(iData, 0, newValue.arrayLength * sizeof(int)); for (i = 0; i < newValue.arrayLength; i++) { sum+= newValue.v.floatArray[i]; iData[i] = htonl((int) (newValue.v.floatArray[i] * 65536.)); } if(zip == 1) { SCWriteZipped(pCon, path, iData, newValue.arrayLength * sizeof(int)); /* printf("Wrote zipped data %s, sum %lf\n", path, sum); */ } else { SCWriteBinary(pCon, path, iData, newValue.arrayLength * sizeof(int)); } free(iData); break; default: SCPrintf(pCon, eError, "ERROR: zipped writing not supported for this datatype on node %s", path); free(path); return 0; } free(path); return 1; } /*----------------------------------------------------------------------------------------*/ static hdbCallbackReturn SICSNotifyCallback(pHdb node, void *userData, pHdbMessage message) { HdbCBInfo *cbInfo = NULL; pDynString printedData = NULL; pDynString result = NULL; char *pPath = NULL; Protocol protocol = normal_protocol; int outCode, macro, status; char value[80]; pHdbIDMessage idm = NULL; pHdbPtrMessage cmm = NULL; pHdbDataMessage mm = NULL; SConnection *tstCon; cbInfo = (HdbCBInfo *) userData; /* * handle kills first */ if ((idm = GetKillIDMessage(message)) != NULL) { if (idm->ID == cbInfo->ID) { return hdbKill; } else { return hdbContinue; } } if ((idm = GetKillInternalIDMessage(message)) != NULL) { if (idm->ID == cbInfo->internalID) { return hdbKill; } else { return hdbContinue; } } if ((cmm = GetKillPtrMessage(message)) != NULL) { tstCon = cmm->pPtr; if (tstCon != NULL && tstCon->ident == cbInfo->pCon->ident) { return hdbKill; } else { return hdbContinue; } } /** * handle start and stop messages */ if (GetHdbStartMessage(message) != NULL) { pPath = GetHipadabaPath(node); result = CreateDynString(128, 128); DynStringConcat(result, pPath); DynStringConcat(result, " STARTED"); SCWrite(cbInfo->pCon, GetCharArray(result), eEvent); DeleteDynString(result); free(pPath); return hdbContinue; } if (GetHdbStopMessage(message) != NULL) { pPath = GetHipadabaPath(node); result = CreateDynString(128, 128); DynStringConcat(result, pPath); DynStringConcat(result, " FINISHED"); SCWrite(cbInfo->pCon, GetCharArray(result), eEvent); DeleteDynString(result); free(pPath); return hdbContinue; } /* * Deal with update messages */ if ((mm = GetHdbUpdateMessage(message)) == NULL) { return hdbContinue; } pPath = GetHipadabaPath(node); result = CreateDynString(128, 128); if ((protocol = isJSON(cbInfo->pCon, 1)) == 1) outCode = eHdbEvent; else outCode = eEvent; /** * if transfer = zip always transfer data in zipped form */ if (GetHdbProperty(node, "transfer", value, 80) == 1) { if (strstr(value, "zip") != NULL || strstr(value,"bin") != NULL) { status = sendZippedNodeData(node, *(mm->v), cbInfo->pCon); free(pPath); DeleteDynString(result); return hdbContinue; } } if (mm->v->arrayLength < 100) { printedData = formatValue(*(mm->v), node); if (pPath == NULL || printedData == NULL || result == NULL) { SCWrite(cbInfo->pCon, "ERROR: out of memory formatting data", eEvent); /* * no need to interrupt something because writing data to a client does * not work */ return hdbContinue; } formatNameValue(protocol, pPath, GetCharArray(printedData), result, mm->v->dataType); /* SCWrite(cbInfo->pCon, GetCharArray(result), outCode); */ SCPureSockWrite(cbInfo->pCon, GetCharArray(result), outCode); DeleteDynString(printedData); } else { formatNameValue(protocol, pPath, "!!datachange!!", result, HIPTEXT); SCWrite(cbInfo->pCon, GetCharArray(result), outCode); } free(pPath); DeleteDynString(result); return hdbContinue; } /*-----------------------------------------------------------------------------------------*/ static void cbKill(void *pData) { HdbCBInfo *cbInfo = (HdbCBInfo *) pData; if (cbInfo == NULL) { return; } if (cbInfo->pCon != NULL) { SCDeleteConnection(cbInfo->pCon); } free(cbInfo); } /*-----------------------------------------------------------------------------------------*/ pHdbCallback MakeNotifyCallback(SConnection * pCon, int id) { HdbCBInfo *cbInfo = NULL; cbInfo = malloc(sizeof(HdbCBInfo)); if (cbInfo == NULL) { return NULL; } cbInfo->pCon = SCCopyConnection(pCon); if (cbInfo->pCon == NULL) { return NULL; } SCsetMacro(cbInfo->pCon, 0); cbInfo->ID = id; cbInfo->internalID = -1; return MakeHipadabaCallback(SICSNotifyCallback, cbInfo, cbKill); } /*-------------------------------------------------------------------------*/ static hdbCallbackReturn TreeChangeCallback(pHdb node, void *userData, pHdbMessage message) { char *path = NULL; char buffer[1024]; pDynString result = NULL; Protocol protocol = normal_protocol; pHdbIDMessage idm = NULL; pHdbPtrMessage cmm = NULL; int outCode; pHdbTreeChangeMessage tm = NULL; SConnection *tstCon = NULL; HdbCBInfo *cbInfo = (HdbCBInfo *) userData; /* * handle kills first */ if ((idm = GetKillIDMessage(message)) != NULL) { if (idm->ID == cbInfo->ID) { return hdbKill; } else { return hdbContinue; } } if ((idm = GetKillInternalIDMessage(message)) != NULL) { if (idm->ID == cbInfo->internalID) { return hdbKill; } else { return hdbContinue; } } if ((cmm = GetKillPtrMessage(message)) != NULL) { tstCon = cmm->pPtr; if (tstCon != NULL && tstCon->ident == cbInfo->pCon->ident) { return hdbKill; } else { return hdbContinue; } } if ((tm = GetHdbTreeChangeMessage(message)) == NULL) { return hdbContinue; } if (cbInfo != NULL && cbInfo->pCon != NULL) { result = CreateDynString(128, 128); if (result == NULL) { SCWrite(cbInfo->pCon, "ERROR: out of memory in TreeChangeCallback", eError); return hdbAbort; } path = GetHipadabaPath(node); if ((protocol = isJSON(cbInfo->pCon, 1)) == 1) outCode = eHdbEvent; else outCode = eEvent; formatNameValue(protocol, "treechange", path, result, node->value.dataType); SCWrite(cbInfo->pCon, GetCharArray(result), outCode); DeleteDynString(result); free(path); } return hdbContinue; } /*-------------------------------------------------------------------------*/ pHdbCallback MakeTreeChangeCallback(SConnection * pCon, int id) { HdbCBInfo *cbInfo = NULL; cbInfo = malloc(sizeof(HdbCBInfo)); if (cbInfo == NULL) { return NULL; } cbInfo->pCon = SCCopyConnection(pCon); if (cbInfo->pCon == NULL) { return NULL; } cbInfo->ID = id; return MakeHipadabaCallback(TreeChangeCallback, cbInfo, cbKill); } /*----------------------------------------------------------------------------------------*/ static hdbCallbackReturn SICSScriptWriteCallback(pHdb node, void *userData, pHdbMessage message) { char *command = NULL; SConnection *pCon = NULL; pDynString newVal = NULL; char error[1024]; int status; pHdbDataMessage mm = NULL; if ((mm = GetHdbSetMessage(message)) == NULL) { return hdbContinue; } command = (char *) userData; pCon = (SConnection *) mm->callData; assert(command != NULL && pCon != NULL); newVal = formatValue(*(mm->v), node); if (newVal == NULL) { SCWrite(pCon, "ERROR: out of memory setting parameter", eError); return hdbAbort; } /** * prepend command */ DynStringInsert(newVal, " ", 0); DynStringInsert(newVal, command, 0); /* * evaluate */ status = Tcl_Eval(InterpGetTcl(pServ->pSics), GetCharArray(newVal)); if (status != TCL_OK) { snprintf(error, 1023, "ERROR: tcl returned error: %s", Tcl_GetStringResult(InterpGetTcl(pServ->pSics))); SCWrite(pCon, error, eError); status = 0; } else { status = 1; } DeleteDynString(newVal); if (status == 1) { return hdbContinue; } else { return hdbAbort; } } /*---------------------------------------------------------------------------------------*/ static pHdbCallback MakeSICSWriteScriptCallback(char *script) { return MakeHipadabaCallback(SICSScriptWriteCallback, strdup(script), free); } /*----------------------------------------------------------------------------------------*/ static hdbCallbackReturn SICSScriptReadCallback(pHdb node, void *userData, pHdbMessage message) { char *command = NULL, *data = NULL, *equal = NULL; SConnection *pCon = NULL; pDynString newVal = NULL; char error[1024]; int status; pHdbDataMessage mm = NULL; if ((mm = GetHdbGetMessage(message)) == NULL) { return hdbContinue; } command = (char *) userData; pCon = (SConnection *) mm->callData; assert(command != NULL); /* * evaluate */ if (pCon != NULL) { MacroPush(pCon); } SetWriteHistory(0); status = Tcl_Eval(InterpGetTcl(pServ->pSics), command); SetWriteHistory(1); if (pCon != NULL) { MacroPop(); } if (status != TCL_OK) { snprintf(error, 1023, "ERROR: Tcl returned error: %s", Tcl_GetStringResult(InterpGetTcl(pServ->pSics))); if (pCon != NULL) { SCWrite(pCon, error, eError); } status = 0; } else { status = 1; } /* * decode result. This handles both the case of the standard SICS answer * something = anything * as well as a plain value alone */ data = (char *) Tcl_GetStringResult(InterpGetTcl(pServ->pSics)); if (data == NULL) { if (pCon != NULL) { SCWrite(pCon, "ERROR: no result returned from script", eError); } return hdbAbort; } /* * do we need to copy? */ if (strstr(data, "@@NOCOPY@@") != NULL) { return hdbContinue; } /* * we need to copy: do it */ equal = strchr(data, '='); if (equal != NULL) { data = equal + 1; } strcpy(error, "ERROR: "); status = readHdbValue(&node->value, data, error + 7, 1024 - 7); if (status != 1) { if (pCon != NULL) { SCWrite(pCon, error, eError); } return hdbAbort; } if (status == 1) { return hdbContinue; } else { return hdbAbort; } } /*----------------------------------------------------------------------------*/ static pHdbCallback MakeSICSReadScriptCallback(char *script) { return MakeHipadabaCallback(SICSScriptReadCallback, strdup(script), free); } /*---------------------------------------------------------------------------*/ typedef struct { int min; int max; } hdbIntRange, *pHdbIntRange; /*---------------------------------------------------------------------------*/ static hdbCallbackReturn SICSIntRangeCallback(pHdb node, void *userData, pHdbMessage message) { char buffer[256]; pHdbIntRange range = NULL; SConnection *pCon = NULL; int status = 1; pHdbDataMessage mm = NULL; if ((mm = GetHdbSetMessage(message)) == NULL) { return hdbContinue; } range = (pHdbIntRange) userData; pCon = (SConnection *) mm->callData; assert(range != NULL); if (mm->v->v.intValue > range->max || mm->v->v.intValue < range->min) { status = SICSCBRANGE; if (pCon != NULL) { snprintf(buffer, 255, "ERROR: %d is not within permitted range: %d to %d", (int) mm->v->v.intValue, range->min, range->max); SCWrite(pCon, buffer, eError); } return hdbAbort; } return hdbContinue; } /*---------------------------------------------------------------------------*/ pHdbCallback MakeIntRangeCallback(int min, int max) { pHdbIntRange range = NULL; range = malloc(sizeof(hdbIntRange)); if (range == NULL) { return NULL; } range->min = min; range->max = max; return MakeHipadabaCallback(SICSIntRangeCallback, range, free); } /*---------------------------------------------------------------------------*/ typedef struct { double min; double max; } hdbFloatRange, *pHdbFloatRange; /*---------------------------------------------------------------------------*/ static hdbCallbackReturn SICSFloatRangeCallback(pHdb node, void *userData, pHdbMessage message) { char buffer[256]; pHdbFloatRange range = NULL; SConnection *pCon = NULL; int status = 1; pHdbDataMessage mm = NULL; if ((mm = GetHdbSetMessage(message)) == NULL) { return hdbContinue; } range = (pHdbFloatRange) userData; pCon = (SConnection *) mm->callData; assert(range != NULL); if (mm->v->v.doubleValue > range->max || mm->v->v.doubleValue < range->min) { status = SICSCBRANGE; if (pCon != NULL) { snprintf(buffer, 255, "ERROR: %lf is not within permitted range: %lf to %lf", mm->v->v.doubleValue, range->min, range->max); SCWrite(pCon, buffer, eError); } return hdbAbort; } return hdbContinue; } /*---------------------------------------------------------------------------*/ pHdbCallback MakeFloatRangeCallback(double min, double max) { pHdbFloatRange range = NULL; range = malloc(sizeof(hdbFloatRange)); if (range == NULL) { return NULL; } range->min = min; range->max = max; return MakeHipadabaCallback(SICSFloatRangeCallback, range, free); } /*------------------------------------------------------------------------*/ static hdbCallbackReturn MemGenReadCallback(pHdb node, void *userData, pHdbMessage message) { pHdbDataMessage mm = NULL; if ((mm = GetHdbGetMessage(message)) == NULL) { return hdbContinue; } switch (node->value.dataType) { case HIPINT: node->value.v.intValue = *(int *) userData; break; case HIPFLOAT: node->value.v.doubleValue = *(double *) userData; break; case HIPTEXT: if (node->value.v.text != NULL) { free(node->value.v.text); } node->value.v.text = strdup((char *) userData); break; case HIPINTAR: memcpy(&node->value.v.intArray, userData, node->value.arrayLength * sizeof(int)); break; case HIPFLOATAR: memcpy(&node->value.v.floatArray, userData, node->value.arrayLength * sizeof(double)); break; default: assert(0); break; } return hdbContinue; } /*-------------------------------------------------------------------------*/ pHdbCallback MakeMemGenReadCallback(void *address) { return MakeHipadabaCallback(MemGenReadCallback, address, NULL); } /*-------------------------------------------------------------------------*/ static hdbCallbackReturn MemGenSetCallback(pHdb node, void *userData, pHdbMessage message) { const char *pPtr = NULL; pHdbDataMessage mm = NULL; if ((mm = GetHdbSetMessage(message)) == NULL) { return hdbContinue; } if (mm->v->dataType != node->value.dataType) { assert(0); return 0; } switch (node->value.dataType) { case HIPINT: memcpy(userData, &mm->v->v.intValue, sizeof(int)); break; case HIPFLOAT: memcpy(userData, &mm->v->v.doubleValue, sizeof(double)); break; case HIPTEXT: /* the use of strlcpy is probably buggy here (M.Z. 15.4.2010) */ strlcpy((char *) userData, (const char *) mm->v->v.text, node->value.arrayLength); break; case HIPINTAR: memcpy(userData, &mm->v->v.intArray, node->value.arrayLength * sizeof(int)); break; case HIPFLOATAR: memcpy(userData, &mm->v->v.floatArray, node->value.arrayLength * sizeof(double)); break; default: assert(0); return 0; break; } UpdateHipadabaPar(node, *(mm->v), mm->callData); return hdbContinue; } /*-------------------------------------------------------------------------*/ pHdbCallback MakeMemGenSetCallback(void *address) { return MakeHipadabaCallback(MemGenSetCallback, address, NULL); } /*--------------------------------------------------------------------------*/ static void killHdbValue(void *pData) { hdbValue *v = NULL; v = (hdbValue *) pData; if (v == NULL) { return; } ReleaseHdbValue(v); free(v); } /*--------------------------------------------------------------------------*/ static hdbCallbackReturn SICSIntFixedCallback(pHdb node, void *userData, pHdbMessage message) { hdbValue *allowed = NULL; SConnection *pCon = NULL; int i; pHdbDataMessage mm = NULL; if ((mm = GetHdbSetMessage(message)) == NULL) { return hdbContinue; } allowed = (hdbValue *) userData; pCon = (SConnection *) mm->callData; assert(allowed != NULL && allowed->dataType == HIPINTAR); for (i = 0; i < allowed->arrayLength; i++) { if (mm->v->v.intValue == allowed->v.intArray[i]) { return hdbContinue; } } if (pCon != NULL) { SCWrite(pCon, "ERROR: value is not in the list of allowed values", eError); } return hdbAbort; } /*---------------------------------------------------------------------------*/ pHdbCallback MakeIntFixedCallback(int *data, int length) { pHdbCallback result = NULL; hdbValue *v = NULL; v = malloc(sizeof(hdbValue)); if (v == NULL) { return NULL; } v->dataType = HIPINTAR; v->arrayLength = length; v->v.intArray = malloc(length * sizeof(int)); if (v->v.intArray == NULL) { return NULL; } memcpy(v->v.intArray, data, length * sizeof(int)); return MakeHipadabaCallback(SICSIntFixedCallback, v, killHdbValue); } /*============= Parameter Creation ===========================================*/ pHdb MakeSICSHdbPar(char *name, int priv, hdbValue v) { pHdb result = NULL; pHdbCallback pHcb = NULL; char pPriv[20]; result = MakeHipadabaNode(name, v.dataType, v.arrayLength); if (result == NULL) { return NULL; } copyHdbValue(&v, &result->value); pHcb = MakeCheckPermissionCallback(priv); if (pHcb == NULL) { DeleteHipadabaNode(result, NULL); return NULL; } AppendHipadabaCallback(result, pHcb); pHcb = MakeSetUpdateCallback(); if (pHcb == NULL) { DeleteHipadabaNode(result, NULL); return NULL; } AppendHipadabaCallback(result, pHcb); switch (priv) { case 0: strcpy(pPriv, "internal"); break; case 1: strcpy(pPriv, "manager"); break; case 2: strcpy(pPriv, "user"); break; case 3: strcpy(pPriv, "spy"); break; } SetHdbProperty(result, "priv", pPriv); return result; } /*----------------------------------------------------------------------------*/ pHdb MakeSICSHdbDriv(char *name, int priv, void *sicsObject, int dataType) { pHdb result = NULL; pHdbCallback pHcb = NULL; result = MakeHipadabaNode(name, dataType, 0); if (result == NULL) { return NULL; } pHcb = MakeCheckPermissionCallback(priv); if (pHcb == NULL) { DeleteHipadabaNode(result, NULL); return NULL; } AppendHipadabaCallback(result, pHcb); pHcb = MakeSICSDriveCallback(sicsObject); if (pHcb == NULL) { DeleteHipadabaNode(result, NULL); return NULL; } AppendHipadabaCallback(result, pHcb); pHcb = MakeSICSReadDriveCallback(sicsObject); if (pHcb == NULL) { DeleteHipadabaNode(result, NULL); return NULL; } AppendHipadabaCallback(result, pHcb); return result; } /*---------------------------------------------------------------------------*/ pHdb MakeSICSMemPar(char *name, int priv, float *address) { pHdb result = NULL; pHdbCallback pHcb = NULL; result = MakeHipadabaNode(name, HIPFLOAT, 1); if (result == NULL) { return NULL; } pHcb = MakeCheckPermissionCallback(priv); if (pHcb == NULL) { DeleteHipadabaNode(result, NULL); return NULL; } AppendHipadabaCallback(result, pHcb); pHcb = MakeMemGenSetCallback(address); if (pHcb == NULL) { DeleteHipadabaNode(result, NULL); return NULL; } AppendHipadabaCallback(result, pHcb); pHcb = MakeMemGenReadCallback(address); if (pHcb == NULL) { DeleteHipadabaNode(result, NULL); return NULL; } AppendHipadabaCallback(result, pHcb); return result; } /*----------------------------------------------------------------------------*/ pHdb MakeSICSROPar(char *name, hdbValue v) { pHdb result = NULL; pHdbCallback pHcb = NULL; result = MakeHipadabaNode(name, v.dataType, v.arrayLength); if (result == NULL) { return NULL; } copyHdbValue(&v, &result->value); pHcb = MakeReadOnlyCallback(); if (pHcb == NULL) { DeleteHipadabaNode(result, NULL); return NULL; } AppendHipadabaCallback(result, pHcb); return result; } /*---------------------------------------------------------------------------*/ pHdb MakeSICSScriptPar(char *name, char *setScript, char *readScript, hdbValue v) { pHdb result = NULL; pHdbCallback pHcb = NULL; result = MakeHipadabaNode(name, v.dataType, v.arrayLength); if (result == NULL) { return NULL; } copyHdbValue(&v, &result->value); pHcb = MakeSICSWriteScriptCallback(setScript); if (pHcb == NULL) { DeleteHipadabaNode(result, NULL); return NULL; } AppendHipadabaCallback(result, pHcb); pHcb = MakeSICSReadScriptCallback(readScript); if (pHcb == NULL) { DeleteHipadabaNode(result, NULL); return NULL; } AppendHipadabaCallback(result, pHcb); /** * put into the list of nodes to check with the update task */ /* LLDnodeAppend(scriptUpdate,&result); */ SetHdbProperty(result, "sicscommand", setScript); return result; } /*--------------------------------------------------------------------------*/ static void removeNodeFromUpdateList(pHdb node) { pHdb current = NULL; int status; char *objName = NULL; objName = GetHipadabaPath(node); if (objName != NULL) { removePollObject(poller, objName); free(objName); } } /*-----------------------------------------------------------------------*/ static void SICSDeleteNodeData(pHdb node) { pHdb tmp = NULL; if (node == NULL) { return; } removeNodeFromUpdateList(node); DeleteCallbackChain(node); while (node->child != NULL) { tmp = node->child; node->child = node->child->next; SICSDeleteNodeData(tmp); } if (node->properties != NULL) { DeleteStringDict(node->properties); } if (node->name != NULL) { free(node->name); } ReleaseHdbValue(&node->value); node->magic = 000000; free(node); } /*--------------------------------------------------------------------------*/ void RemoveSICSPar(pHdb node, void *callData) { pHdb current = NULL, tmp = NULL; if (node == NULL) { return; } RemoveHdbNodeFromParent(node, NULL); SICSDeleteNodeData(node); } /*===================== add functions =======================================*/ pHdb AddSICSHdbPar(pHdb parent, char *name, int priv, hdbValue v) { pHdb child = NULL; child = MakeSICSHdbPar(name, priv, v); if (child != NULL) { AddHipadabaChild(parent, child, NULL); } return child; } /*---------------------------------------------------------------------------*/ pHdb AddSICSHdbROPar(pHdb parent, char *name, hdbValue v) { pHdb child = NULL; child = MakeSICSROPar(name, v); if (child != NULL) { AddHipadabaChild(parent, child, NULL); } return child; } /*--------------------------------------------------------------------------*/ pHdb AddSICSHdbMemPar(pHdb parent, char *name, int priv, void *data, int datalength, int type, int length) { pHdb child = NULL; pHdbCallback pHcb = NULL; if (type == HIPINTVARAR || type == HIPFLOATVARAR) { assert(0); return NULL; } child = MakeHipadabaNode(name, type, length); if (child == NULL) { return NULL; } pHcb = MakeCheckPermissionCallback(priv); if (pHcb == NULL) { DeleteHipadabaNode(child, NULL); return NULL; } AppendHipadabaCallback(child, pHcb); pHcb = MakeMemGenSetCallback(data); if (pHcb == NULL) { DeleteHipadabaNode(child, NULL); return NULL; } AppendHipadabaCallback(child, pHcb); pHcb = MakeMemGenReadCallback(data); if (pHcb == NULL) { DeleteHipadabaNode(child, NULL); return NULL; } AppendHipadabaCallback(child, pHcb); AddHipadabaChild(parent, child, NULL); return child; } /*==================== access support functions ==============================*/ pHdb FindHdbParent(char *rootpath, char *relpath, char **namePtr, SConnection * pCon) { /* for namePtr == NULL, implements also "find node" */ char *element; char buffer[MAX_HDB_PATH]; pHdb node = NULL; pHdb parent = NULL; char *name; char *slash; pObjectDescriptor pDes; int iret; if (relpath[0] == '/' || rootpath == NULL) { /* absolute path */ iret = snprintf(buffer, sizeof buffer, "%s", relpath); } else { iret = snprintf(buffer, sizeof buffer, "%s/%s", rootpath, relpath); } if (iret < 0 || iret >= (int) sizeof(buffer)) { SCWrite(pCon, "ERROR: path too long", eError); return NULL; } element = buffer; if (strncmp(element, "/sics/", 6) == 0) { /* sics object case */ slash = strchr(element + 6, '/'); if (slash != NULL) *slash = '\0'; /* split off object name */ pDes = FindCommandDescriptor(pServ->pSics, element + 6); if (pDes == NULL) { SCPrintf(pCon, eError, "ERROR: object %s not found", element); return NULL; } node = pDes->parNode; if (node == NULL) { SCPrintf(pCon, eError, "ERROR: object %s does not use hipadaba", element); return NULL; } if (slash == NULL) goto nodeFound; *slash = '/'; element = slash + 1; parent = node; /* parent is sics object, path is relative to it */ } else { /* normal path */ parent = GetHipadabaRoot(); } while (1) { slash = strchr(element, '/'); if (slash != NULL) *slash = '\0'; /* split off next path element */ if (strcmp(element, "") == 0 || strcmp(element, ".") == 0) { /* cases "//" and "/./" : do not move in tree */ if (slash == NULL) { node = parent; goto nodeFound; } *slash = '/'; element = slash + 1; } else { for (node = parent->child; node != NULL; node = node->next) { if (strcasecmp(element, node->name) == 0) { break; } } if (node == NULL) { if (namePtr) { /* "find parent" case */ if (slash != NULL) { /* element is not the last in path */ *slash = '/'; SCPrintf(pCon, eError, "ERROR: parent of %s not found", buffer); return NULL; } /* the name must be taken from the end of relpath, as element is no longer valid */ *namePtr = relpath + (element - buffer); return parent; /* parent found, and node does not yet exist */ } /* "find node" case */ if (slash != NULL) *slash = '/'; SCPrintf(pCon, eError, "ERROR: node %s not found", buffer); return NULL; } /* node found */ if (slash == NULL) goto nodeFound; parent = node; *slash = '/'; element = slash + 1; } } nodeFound: if (namePtr) { /* "find parent" case */ *namePtr = node->name; SCPrintf(pCon, eError, "ERROR: node %s exists already", buffer); return NULL; } return node; /* node found */ } /*--------------------------------------------------------------------------*/ pHdb FindHdbNode(char *rootpath, char *relpath, SConnection * pCon) { return FindHdbParent(rootpath, relpath, NULL, pCon); } /*-------------------------------------------------------------------------- * This does not use strlcpy, strlcat on purpose: it caused a bug * There are so many length checks in the code anyway so that is * not necessary either. --------------------------------------------------------------------------*/ int GetHdbPath(pHdb nodeArg, char *path, size_t pathlen) { pHdb node, parent; int len, pos, l; static char *sics = "/sics"; pObjectDescriptor pDes; path[0] = '\0'; if (nodeArg == NULL) { return 0; } /* determine path length and root node */ parent = nodeArg; len = 0; for (node = nodeArg; node != NULL && node != root; node = node->mama) { len += strlen(node->name) + 1; if (len >= (int) pathlen) return 0; /* buffer overflow (recursive path?) */ parent = node; } /* check root and add prefix */ if (parent->mama != root) { /* not anchored in root */ pDes = FindCommandDescriptor(pServ->pSics, parent->name); if (!pDes) { return 0; /* not a sics object */ } if (pDes->parNode != parent) { /* node named as a sics object, but command is not related to node */ return 0; } l = strlen(sics); len += l; if (len > (int) pathlen) return 0; /* buffer overflow */ strncpy(path, sics, l); } /* build the path backwards */ path[len] = '\0'; pos = len; for (node = nodeArg; node != NULL && node != root; node = node->mama) { len = strlen(node->name); pos -= len; assert(pos > 0); strncpy(path + pos, node->name, len); pos--; path[pos] = '/'; } return 1; } /*--------------------------------------------------------------------------*/ void RemoveSICSInternalCallbackFrom(pHdb node, void *internalID) { hdbPtrMessage m; m.type = killPtr; m.pPtr = internalID; RecurseCallbackChains(node, (pHdbMessage) & m); } /*--------------------------------------------------------------------------*/ static int RemoveParNodeCallback(char *name, pDummy object, void *internalID) { if (object && object->pDescriptor->parNode) { RemoveSICSInternalCallbackFrom(object->pDescriptor->parNode, internalID); } return 1; } /*--------------------------------------------------------------------------*/ void RemoveSICSInternalCallback(void *internalID) { RemoveSICSInternalCallbackFrom(GetHipadabaRoot(), internalID); ForEachCommand(RemoveParNodeCallback, internalID); } /*--------------------------------------------------------------------------*/ int SICSHdbGetPar(void *obj, SConnection * pCon, char *path, hdbValue * v) { pHdb par = NULL; int status; char buffer[256]; pDummy pDum; pDum = (pDummy) obj; if (pDum == NULL || pDum->pDescriptor->parNode == NULL) { if (pCon != NULL) { snprintf(buffer, 255, "ERROR: parameter %s not found", path); SCWrite(pCon, buffer, eError); } return SICSNOPAR; } par = GetHipadabaNode(pDum->pDescriptor->parNode, path); if (par == NULL) { if (pCon != NULL) { snprintf(buffer, 255, "ERROR: parameter %s not found", path); SCWrite(pCon, buffer, eError); } return SICSNOPAR; } status = GetHipadabaPar(par, v, pCon); if (status < 0) { return status; } return 1; } /*--------------------------------------------------------------------------*/ int SICSHdbUpdatePar(void *obj, SConnection * pCon, char *path, hdbValue v) { pHdb par = NULL; int status; char buffer[256]; pDummy pDum; pDum = (pDummy) obj; if (pDum == NULL || pDum->pDescriptor->parNode == NULL) { if (pCon != NULL) { snprintf(buffer, 255, "ERROR: parameter %s not found", path); SCWrite(pCon, buffer, eError); } return SICSNOPAR; } par = GetHipadabaNode(pDum->pDescriptor->parNode, path); if (par == NULL) { if (pCon != NULL) { snprintf(buffer, 255, "ERROR: parameter %s not found", path); SCWrite(pCon, buffer, eError); } return SICSNOPAR; } status = UpdateHipadabaPar(par, v, pCon); if (status < 0) { return status; } return 1; } /*--------------------------------------------------------------------------*/ int SICSHdbSetPar(void *obj, SConnection * pCon, char *path, hdbValue v) { pHdb par = NULL; int status; char buffer[256]; pDummy pDum; pDum = (pDummy) obj; if (pDum == NULL || pDum->pDescriptor->parNode == NULL) { if (pCon != NULL) { snprintf(buffer, 255, "ERROR: parameter %s not found", path); SCWrite(pCon, buffer, eError); } return SICSNOPAR; } par = GetHipadabaNode(pDum->pDescriptor->parNode, path); if (par == NULL) { if (pCon != NULL) { snprintf(buffer, 255, "ERROR: parameter %s not found", path); SCWrite(pCon, buffer, eError); } return SICSNOPAR; } status = SetHipadabaPar(par, v, pCon); if (status <= 0) { return status; } return 1; } /*---------------------------------------------------------------------------*/ int InstallSICSNotify(pHdb node, SConnection * pCon, int id, int recurse) { pHdb currentChild = NULL; pHdbCallback noty = NULL; pHdbCallback treeChange = NULL; treeChange = MakeTreeChangeCallback(pCon, id); noty = MakeNotifyCallback(pCon, id); if (noty == NULL || treeChange == NULL) { SCWrite(pCon, "ERROR: out of memory installing callback", eError); return 0; } AppendHipadabaCallback(node, noty); AppendHipadabaCallback(node, treeChange); if (recurse == 1) { currentChild = node->child; while (currentChild != NULL) { InstallSICSNotify(currentChild, pCon, id, recurse); currentChild = currentChild->next; } } return 1; } /*---------------------------------------------------------------------------*/ void RemoveConnectionCallbacks(pHdb root, SConnection * pCon) { hdbPtrMessage dsm; dsm.type = killPtr; dsm.pPtr = pCon; RecurseCallbackChains(root, (pHdbMessage) & dsm); } /*---------------------------------------------------------------------------*/ int ProcessSICSHdbPar(pHdb root, SConnection * pCon, char *printPrefix, int argc, char *argv[]) { hdbValue input; pHdb parNode = NULL; pDynString parData = NULL; char error[512]; int i, status, firstValueArg; float value; assert(root != NULL && pCon != NULL); if (argc < 1) { SCWrite(pCon, "ERROR: no parameter to treat specified", eError); return -1; } /* if the single argument is a number and the type of the root is a number then we want to set the root itself to this number */ if (argc == 1 && (root->value.dataType == HIPINT || root->value.dataType == HIPFLOAT) && sscanf(argv[0], "%f", &value) == 1) { parNode = root; firstValueArg = 0; } else { parNode = GetHipadabaNode(root, argv[0]); firstValueArg = 1; } if (parNode == NULL) { /* no error reporting here, upper level code might wish to continue * processing commands after having tested for parameters. */ return -1; } if (argc > firstValueArg) { /* * setting the value is attempted. */ memset(&input, 0, sizeof(hdbValue)); input.dataType = parNode->value.dataType; copyHdbValue(&parNode->value, &input); parData = CreateDynString(64, 64); if (parData == NULL) { SCWrite(pCon, "ERROR: out of memory processing parameter", eError); return 0; } DynStringConcat(parData, argv[firstValueArg]); for (i = firstValueArg + 1; i < argc; i++) { DynStringConcat(parData, " "); DynStringConcat(parData, argv[i]); } strcpy(error, "ERROR: "); if (!readHdbValue(&input, GetCharArray(parData), error + 7, 512 - 7)) { SCWrite(pCon, error, eError); return 0; } DeleteDynString(parData); status = SetHipadabaPar(parNode, input, pCon); ReleaseHdbValue(&input); if (status == 1) { /* SCSendOK(pCon); do not send OK. this has to be done by the callback */ SCparChange(pCon); } return status; } else { /* * reading is in demand */ status = GetHipadabaPar(parNode, &input, pCon); if (status != 1) { return 0; } parData = formatValue(input, parNode); if (parData == NULL) { SCWrite(pCon, "ERROR: out of memory reading parameter data", eError); return 0; } DynStringInsert(parData, " = ", 0); DynStringInsert(parData, argv[0], 0); if (printPrefix != NULL) { DynStringInsert(parData, printPrefix, 0); } SCWrite(pCon, GetCharArray(parData), eValue); DeleteDynString(parData); ReleaseHdbValue(&input); return 1; } } /*--------------------------------------------------------------------------*/ void PrintSICSParList(pHdb node, SConnection * pCon, char *prefix) { char childPrefix[1024]; pHdb child = NULL; pDynString value = NULL; hdbValue v; child = node->child; while (child != NULL) { if (child->value.dataType != HIPNONE) { GetHipadabaPar(child, &v, pCon); value = formatValue(child->value, child); if (value != NULL) { SCPrintf(pCon, eValue, "%s%s = %s", prefix, child->name, GetCharArray(value)); DeleteDynString(value); } } if (child->child != NULL) { strlcpy(childPrefix, prefix, 1024); strlcat(childPrefix, child->name, 1024); strlcat(childPrefix, "/", 1024); PrintSICSParList(child, pCon, prefix); } child = child->next; } } /*---------------------------------------------------------------------------*/ void SaveSICSHipadaba(FILE * fd, pHdb node, char *prefix) { pHdb currentChild = NULL; pDynString data = NULL; hdbValue v; currentChild = node->child; while (currentChild != NULL) { if (currentChild->value.dataType != HIPNONE && !isSICSHdbRO(currentChild)) { data = formatValue(currentChild->value, currentChild); if (data != NULL) { fprintf(fd, "%s%s %s\n", prefix, currentChild->name, GetCharArray(data)); DeleteDynString(data); } } if (currentChild->child != NULL) { /* * build a new prefix string and recurse */ data = CreateDynString(64, 64); if (data != NULL) { DynStringCopy(data, prefix); DynStringConcat(data, currentChild->name); DynStringConcat(data, "/"); SaveSICSHipadaba(fd, currentChild, GetCharArray(data)); DeleteDynString(data); } } currentChild = currentChild->next; } } /*================ value helpers ============================================*/ pDynString formatValue(hdbValue v, pHdb node) { pDynString result = NULL; int i; char number[30]; char format[16]; result = CreateDynString(64, 64); if (result == NULL) { return NULL; } if(v.arrayLength > 65536){ DynStringCopy(result,"Data to big to format into text"); return result; } switch (v.dataType) { case HIPNONE: break; case HIPINT: snprintf(number, 30, "%d", v.v.intValue); DynStringCopy(result, number); break; case HIPFLOAT: if (GetHdbProperty(node, "fmt", format, sizeof format - 1)) { snprintf(number, 30, format, v.v.doubleValue); } else { snprintf(number, 30, "%.6g", v.v.doubleValue); } DynStringCopy(result, number); break; case HIPTEXT: DynStringCopy(result, v.v.text); break; case HIPINTAR: case HIPINTVARAR: for (i = 0; i < v.arrayLength; i++) { snprintf(number, 30, " %d", v.v.intArray[i]); DynStringConcat(result, number); } break; case HIPFLOATAR: case HIPFLOATVARAR: if (GetHdbProperty(node, "fmt", format + 1, sizeof format - 2)) { format[0] = ' '; } else { strcpy(format, " %.6g"); } for (i = 0; i < v.arrayLength; i++) { snprintf(number, 30, format, v.v.floatArray[i]); DynStringConcat(result, number); } break; case HIPFUNC: DynStringConcat(result, "FUNCTION"); break; case HIPOBJ: DynStringConcat(result, "OBJECT"); break; } return result; } /*-------------------------------------------------------------------*/ static char *getNextHdbNumber(char *pStart, char pNumber[80]) { int charCount = 0; pNumber[0] = '\0'; /* advance to first digit */ while (isspace(*pStart) && *pStart != '\0') { pStart++; } if (*pStart == '\0') { return NULL; } /* copy */ while (!isspace(*pStart) && *pStart != '\0' && charCount < 78) { pNumber[charCount] = *pStart; pStart++; charCount++; } pNumber[charCount] = '\0'; return pStart; } /*---------------------------------------------------------------------------------*/ static int adjustDataLength(hdbValue * v, char *data) { char number[80]; int count = 0; char *pPtr = NULL; pPtr = data; while ((pPtr = getNextHdbNumber(pPtr, number)) != NULL) { count++; } if (count != v->arrayLength) { v->arrayLength = count; if (v->dataType == HIPINTVARAR) { if (v->v.intArray != NULL) { free(v->v.intArray); } v->v.intArray = malloc(count * sizeof(int)); if (v->v.intArray == NULL) { return 0; } memset(v->v.intArray, 0, count * sizeof(int)); } if (v->dataType == HIPFLOATVARAR) { if (v->v.floatArray != NULL) { free(v->v.floatArray); } v->v.floatArray = malloc(count * sizeof(double)); if (v->v.floatArray == NULL) { return 0; } memset(v->v.floatArray, 0, count * sizeof(double)); } } return 1; } /*---------------------------------------------------------------------------------*/ int readHdbValue(hdbValue * v, char *data, char *error, int errlen) { int i, status; int lValue; double dValue; char number[80]; char *pPtr = NULL; void *objData; switch (v->dataType) { case HIPNONE: break; case HIPINT: getNextHdbNumber(data, number); status = sscanf(number, "%d", &v->v.intValue); if (status != 1) { snprintf(error, errlen, "Failed to convert [%.32s] to integer", data); return 0; } break; case HIPFLOAT: getNextHdbNumber(data, number); status = sscanf(number, "%lf", &v->v.doubleValue); if (status != 1) { snprintf(error, errlen, "Failed to convert [%.32s] to double", data); return 0; } break; case HIPTEXT: if (v->v.text != NULL) { free(v->v.text); } v->v.text = strdup(data); v->arrayLength = strlen(data); break; case HIPINTVARAR: if (!adjustDataLength(v, data)) { snprintf(error, errlen, "Out of memory allocating variable length data"); return 0; } case HIPINTAR: for (i = 0; i < v->arrayLength; i++) { data = getNextHdbNumber(data, number); if (data == NULL) { snprintf(error, errlen, "Not enough values to parse, current index %d", i); return 0; } status = sscanf(number, "%d", &lValue); if (status != 1) { snprintf(error, errlen, "Failed to convert [%.32s] to integer", data); return 0; } v->v.intArray[i] = lValue; } break; case HIPFLOATVARAR: if (!adjustDataLength(v, data)) { snprintf(error, errlen, "Out of memory allocating variable length data"); return 0; } case HIPFLOATAR: for (i = 0; i < v->arrayLength; i++) { data = getNextHdbNumber(data, number); if (data == NULL) { snprintf(error, errlen, "Not enough values to parse, current index %d", i); return 0; } status = sscanf(number, "%lf", &dValue); if (status != 1) { snprintf(error, errlen, "Failed to convert [%.32s] to double", data); return 0; } v->v.floatArray[i] = dValue; } break; case HIPOBJ: break; case HIPFUNC: break; default: assert(0); break; } return 1; } /*-------------------------------------------------------------------------*/ hdbValue MakeSICSFunc(SICSOBJFunc func) { return MakeHdbFunc((voidFunc *) func); } /*================ interpreter interface ==================================*/ pHdb GetHipadabaRoot() { return root; } /*-------------------------------------------------------------------------*/ static char *hdbTypes[] = { "none", "int", "float", "text", "intar", "floatar", "intvarar", "floatvarar", "object", "func", NULL }; /*-------------------------------------------------------------------------*/ int convertHdbType(char *text) { int type; type = 0; while (hdbTypes[type] != NULL) { if (strcasecmp(hdbTypes[type], text) == 0) { break; } type++; } type--; /* we start counting at -1 */ return type; } /*-------------------------------------------------------------------------*/ static char *hdbTypeToText(int type) { return hdbTypes[type + 1]; } /*--------------------------------------------------------------------------*/ static int MakeHdbNode(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { int type = 0, i, length = 0, priv = -1; char *name = NULL; pHdb parent = NULL; pHdb child = NULL; char buffer[512], buffer2[512]; hdbValue val; if (!SCMatchRights(pCon, usMugger)) { return 0; } if (argc < 4) { SCWrite(pCon, "ERROR: not enough arguments to MakeHdbNode", eError); return 0; } /* * convert privilege */ priv = decodeSICSPriv(argv[2]); /* * convert datatype */ type = convertHdbType(argv[3]); if (type > HIPFLOATVARAR) { SCWrite(pCon, "ERROR: invalid type requested: none, int, float, text, intar, floatar, intvarar, floatvarar supported", eError); return 0; } if (type >= HIPINTAR) { if (argc < 5) { SCWrite(pCon, "ERROR: array length missing for array data type", eError); return 0; } else { length = atoi(argv[4]); } } parent = FindHdbParent(NULL, argv[1], &name, pCon); if (parent == NULL) { return 0; /* error messages written inside FindHdbParent */ } if (type != HIPNONE) { val = makeHdbValue(type, length); child = MakeSICSHdbPar(name, priv, val); ReleaseHdbValue(&val); } else { child = MakeHipadabaNode(name, type, length); } if (child == NULL) { SCWrite(pCon, "ERROR: out of memory creating node", eError); return 0; } AddHipadabaChild(parent, child, pCon); SCSendOK(pCon); return 1; } /*--------------------------------------------------------------------------*/ static int MakeHdbScriptNode(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { int type = 0, i, length = 0; char *name = NULL; pHdb parent = NULL; pHdb child = NULL; pHdb current = NULL; char *urgv[] = { "5", NULL }; char driver[] = { "hdb" }; char buffer[512], buffer2[512]; if (!SCMatchRights(pCon, usMugger)) { return 0; } if (argc < 5) { SCWrite(pCon, "ERROR: not enough arguments to MakeHdbNode", eError); return 0; } /* * convert datatype */ strtolower(argv[4]); type = convertHdbType(argv[4]); if (type >= 7) { SCWrite(pCon, "ERROR: invalid type requested: none, int, float, text, intar, floatar, intvarar, floatvarar supported", eError); return 0; } if (type > 2) { if (argc < 6) { SCWrite(pCon, "ERROR: array length missing for array data type", eError); return 0; } else { length = atoi(argv[5]); } } parent = FindHdbParent(NULL, argv[1], &name, pCon); if (parent == NULL) { return 0; /* error messages written inside FindHdbParent */ } child = MakeSICSScriptPar(name, argv[3], argv[2], makeHdbValue(type, length)); if (child == NULL) { SCWrite(pCon, "ERROR: out of memory creating node", eError); return 0; } AddHipadabaChild(parent, child, pCon); /* * have it polled automatically */ addPollObject(poller, pCon, GetHipadabaPath(child), driver, 1, urgv); SCSendOK(pCon); return 1; } /*------------------------------------------------------------------------------*/ static int isNodeProtected(pHdb node) { pHdb current = NULL; if (node->protected == 1) { return 1; } current = node->child; while (current != NULL) { if (isNodeProtected(current)) { return 1; } current = current->next; } return 0; } /*-----------------------------------------------------------------------------------------*/ static int DeleteHdbNode(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { pHdb killNode = NULL; if (!SCMatchRights(pCon, usMugger)) { return 0; } if (argc < 2) { SCWrite(pCon, "ERROR: need path to node to delete", eError); return 0; } killNode = FindHdbNode(NULL, argv[1], pCon); if (killNode == NULL) { SCWrite(pCon, "ERROR: node to delete not found", eError); return 0; } if (isNodeProtected(killNode)) { SCWrite(pCon, "ERROR: this node or one of its children is protected", eError); return 0; } RemoveSICSPar(killNode, pCon); SCSendOK(pCon); return 1; } /*---------------------------------------------------------------------------*/ static int SetHdbNode(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { pHdb targetNode = NULL; hdbValue newValue; pDynString parData = NULL; char error[512], value[132]; int i, status, priv; if (argc < 3) { SCWrite(pCon, "ERROR: insufficient number of arguments to SetHdbNode", eError); return 0; } targetNode = FindHdbNode(NULL, argv[1], pCon); if (targetNode == NULL) { return 0; } status = GetHdbProperty(targetNode,"priv",value,sizeof(value)); if(status == 1){ priv = decodeSICSPriv(value); } else { priv = usUser; } if (!SCMatchRights(pCon, priv)) { return 0; } if (!cloneHdbValue(&targetNode->value, &newValue)) { SCWrite(pCon, "ERROR: out of memory cloning node", eError); return 0; } parData = CreateDynString(64, 64); if (parData == NULL) { SCWrite(pCon, "ERROR: out of memory reading parameter", eError); return 0; } DynStringConcat(parData, argv[2]); for (i = 3; i < argc; i++) { DynStringConcat(parData, " "); DynStringConcat(parData, argv[i]); } strcpy(error, "ERROR: "); if (!readHdbValue(&newValue, GetCharArray(parData), error + 7, 512 - 7)) { SCWrite(pCon, error, eError); return 0; } DeleteDynString(parData); status = SetHipadabaPar(targetNode, newValue, pCon); ReleaseHdbValue(&newValue); if (status == 1) { /* SCSendOK(pCon); sending ok has to be done by the callback. */ } return status; } /*---------------------------------------------------------------------------*/ static int UpdateHdbNode(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { pHdb targetNode = NULL; hdbValue newValue; pDynString parData = NULL; char error[512]; int i, status; /* if(!SCMatchRights(pCon,usUser)){ return 0; } */ if (argc < 2) { SCWrite(pCon, "ERROR: insufficient number of arguments to UpdateHdbNode", eError); return 0; } targetNode = FindHdbNode(NULL, argv[1], pCon); if (targetNode == NULL) { return 0; } /* SCPrintf(pCon,eWarning, "Updating %s", argv[1]); */ if (argc > 2) { if (!cloneHdbValue(&targetNode->value, &newValue)) { SCWrite(pCon, "ERROR: out of memory cloning node", eError); return 0; } parData = CreateDynString(64, 64); if (parData == NULL) { SCWrite(pCon, "ERROR: out of memory reading parameter", eError); return 0; } DynStringConcat(parData, argv[2]); for (i = 3; i < argc; i++) { DynStringConcat(parData, " "); DynStringConcat(parData, argv[i]); } strcpy(error, "ERROR: "); if (!readHdbValue(&newValue, GetCharArray(parData), error + 7, 512 - 7)) { SCWrite(pCon, error, eError); return 0; } DeleteDynString(parData); } else { memset(&newValue, 0, sizeof(hdbValue)); GetHipadabaPar(targetNode, &newValue, pCon); } status = UpdateHipadabaPar(targetNode, newValue, pCon); ReleaseHdbValue(&newValue); if (status == 1) { SCSendOK(pCon); } return status; } /*-----------------------------------------------------------------------------*/ static int ZipGetHdbNode(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { pHdb targetNode = NULL; char error[512], oriPath[512]; int status; hdbValue newValue; pDynString parData = NULL, result= NULL; Protocol protocol = normal_protocol; OutCode outCode; if (argc < 2) { SCWrite(pCon, "ERROR: need path to node", eError); return 0; } strlcpy(oriPath, argv[1], 511); targetNode = FindHdbNode(NULL, argv[1], pCon); if (targetNode == NULL) { return 0; } memset(&newValue, 0, sizeof(hdbValue)); GetHipadabaPar(targetNode, &newValue, pCon); if(newValue.dataType == HIPTEXT){ parData = formatValue(newValue, targetNode); if (parData == NULL) { SCWrite(pCon, "ERROR: out of memory formatting data", eError); return 0; } if ((protocol = isJSON(pCon, 0)) == 1) outCode = eHdbEvent; else outCode = eValue; result = CreateDynString(128, 128); formatNameValue(protocol, oriPath, GetCharArray(parData), result, newValue.dataType); SCWrite(pCon, GetCharArray(result), outCode); DeleteDynString(parData); DeleteDynString(result); } else { status = sendZippedNodeData(targetNode, newValue, pCon); } ReleaseHdbValue(&newValue); return status; } /*---------------------------------------------------------------------------*/ static int GetHdbNode(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { pHdb targetNode = NULL; hdbValue newValue; pDynString parData = NULL, result = NULL; char error[512], oriPath[512];; int i, status; Protocol protocol = normal_protocol; int outCode; char value[80]; /* if(strstr(argv[1],"values") != NULL){ printf("Found!!\n"); } */ if (argc < 2) { SCWrite(pCon, "ERROR: need path to node to print", eError); return 0; } strlcpy(oriPath, argv[1], 511); targetNode = FindHdbNode(NULL, argv[1], pCon); if (targetNode == NULL) { return 0; } /* * if transfer = zip, redirect to zip */ if (GetHdbProperty(targetNode, "transfer", value, 80) == 1) { if (strstr(value, "zip") != NULL) { return ZipGetHdbNode(pCon, pSics, pData, argc, argv); } } memset(&newValue, 0, sizeof(hdbValue)); /* ffr XXX I expect if status=0 then we don't have a valid value Original code was causing a segfault for hdb text nodes */ if (0 == GetHipadabaPar(targetNode, &newValue, pCon)) return 0; parData = formatValue(newValue, targetNode); if (parData == NULL) { SCWrite(pCon, "ERROR: out of memory formatting data", eError); return 0; } if ((protocol = isJSON(pCon, 0)) == 1) outCode = eHdbEvent; else outCode = eValue; result = CreateDynString(128, 128); formatNameValue(protocol, oriPath, GetCharArray(parData), result, newValue.dataType); SCWrite(pCon, GetCharArray(result), outCode); DeleteDynString(parData); DeleteDynString(result); ReleaseHdbValue(&newValue); return 1; } /*---------------------------------------------------------------------------*/ static int GetHdbVal(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { pHdb targetNode = NULL; hdbValue newValue; pDynString parData = NULL; char error[512], oriPath[512]; int i, status, protocol, outCode; char value[80]; if (argc < 2) { SCWrite(pCon, "ERROR: need path to node to print", eError); return 0; } strlcpy(oriPath, argv[1], 511); targetNode = FindHdbNode(NULL, argv[1], pCon); if (targetNode == NULL) { return 0; } memset(&newValue, 0, sizeof(hdbValue)); if (0 == GetHipadabaPar(targetNode, &newValue, pCon)) return 0; parData = formatValue(newValue, targetNode); if (parData == NULL) { SCWrite(pCon, "ERROR: out of memory formatting data", eError); return 0; } else { if ((protocol = isJSON(pCon, 0)) == 1) outCode = eHdbEvent; else outCode = eValue; SCWrite(pCon, GetCharArray(parData), outCode); DeleteDynString(parData); ReleaseHdbValue(&newValue); return 1; } return 1; } /*--------------------------------------------------------------------------*/ static int countChildren(pHdb node) { pHdb current = NULL; int count = 0; current = node->child; while (current != NULL) { count++; current = current->next; } return count; } /*---------------------------------------------------------------------------*/ static int HdbNodeInfo(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { pHdb targetNode = NULL; char error[512], oriPath[512], info[512]; int i, status, length; if (argc < 2) { SCWrite(pCon, "ERROR: need path to node to get info", eError); return 0; } strlcpy(oriPath, argv[1], 511); targetNode = FindHdbNode(NULL, argv[1], pCon); if (targetNode == NULL) { return 0; } length = targetNode->value.arrayLength; if (length == 0) { length = 1; } snprintf(info, 511, "%s,%d,%d", hdbTypeToText(targetNode->value.dataType), countChildren(targetNode), length); SCWrite(pCon, info, eValue); return 1; } /*---------------------------------------------------------------------------*/ static int HdbNodeVal(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { pHdb targetNode = NULL; hdbValue newValue; pDynString parData = NULL; char error[512]; int i, status; if (argc < 2) { SCWrite(pCon, "ERROR: need path to node to print", eError); return 0; } targetNode = FindHdbNode(NULL, argv[1], pCon); if (targetNode == NULL) { return 0; } memset(&newValue, 0, sizeof(hdbValue)); GetHipadabaPar(targetNode, &newValue, pCon); parData = formatValue(newValue, targetNode); if (parData == NULL) { SCWrite(pCon, "ERROR: out of memory formatting data", eError); return 0; } SCWrite(pCon, GetCharArray(parData), eHdbValue); DeleteDynString(parData); ReleaseHdbValue(&newValue); return 1; } /*---------------------------------------------------------------------------*/ int isSICSHdbRO(pHdb node) { pHdbCallback current = NULL; current = node->callBackChain; while (current != NULL) { if (current->userCallback == SICSReadOnlyCallback) { return 1; } current = current->next; } return 0; } /*---------------------------------------------------------------------------*/ static pDynString formatPlainList(pHdb node) { pHdb current; pDynString result = NULL; result = CreateDynString(128, 128); if (result == NULL) { return NULL; } current = node->child; while (current != NULL) { DynStringConcat(result, current->name); DynStringConcat(result, "\n"); current = current->next; } return result; } /*---------------------------------------------------------------------------*/ static pDynString formatJSONList(pHdb node) { pHdb current; pDynString result = NULL; pDynString data = NULL; if (node->child == NULL) return NULL; result = CreateDynString(128, 128); if (result == NULL) { return NULL; } if (node->child->value.dataType == HIPNONE) DynStringCopy(result, "["); else DynStringCopy(result, "{"); current = node->child; while (current != NULL) { DynStringConcat(result, "\""); DynStringConcat(result, current->name); DynStringConcat(result, "\""); if (current->value.dataType != HIPNONE) { data = formatValue(current->value, current); if (data != NULL) { DynStringConcat(result, ": "); DynStringConcat(result, GetCharArray(data)); DeleteDynString(data); } } if (current->next != NULL) DynStringConcat(result, ", "); current = current->next; } if (node->child->value.dataType == HIPNONE) DynStringConcat(result, "]"); else DynStringConcat(result, "}"); return result; } /*---------------------------------------------------------------------------*/ static pDynString formatListWithVal(pHdb node) { pHdb current; pDynString result = NULL; pDynString data = NULL; result = CreateDynString(128, 128); if (result == NULL) { return NULL; } current = node->child; while (current != NULL) { if (current->value.dataType != HIPNONE) { DynStringConcat(result, current->name); data = formatValue(current->value, current); if (data != NULL) { DynStringConcat(result, " = "); DynStringConcat(result, GetCharArray(data)); DeleteDynString(data); } DynStringConcat(result, "\n"); } current = current->next; } return result; } /*---------------------------------------------------------------------------*/ static pDynString formatClientList(pHdb node) { pHdb current; pDynString result = NULL; int length; int i; char number[50]; result = CreateDynString(128, 128); if (result == NULL) { return NULL; } current = node->child; while (current != NULL) { DynStringConcat(result, current->name); DynStringConcat(result, ","); DynStringConcat(result, hdbTypeToText(current->value.dataType)); DynStringConcat(result, ","); snprintf(number, 50, "%d", countChildren(current)); DynStringConcat(result, number); DynStringConcat(result, ","); if (current->value.dataType >= 3) { length = current->value.arrayLength; } else { length = 1; } snprintf(number, 50, "%d", length); DynStringConcat(result, number); DynStringConcat(result, ","); switch (current->value.dataType) { case HIPNONE: break; case HIPINT: snprintf(number, 50, "%d", current->value.v.intValue); DynStringConcat(result, number); break; case HIPFLOAT: snprintf(number, 50, "%lg", current->value.v.doubleValue); DynStringConcat(result, number); break; case HIPTEXT: DynStringConcat(result, current->value.v.text); break; case HIPINTAR: case HIPINTVARAR: for (i = 0; i < length; i++) { snprintf(number, 50, "%d", current->value.v.intArray[i]); DynStringConcat(result, number); if (i > length - 1) { DynStringConcat(result, ","); } } break; case HIPFLOATAR: case HIPFLOATVARAR: for (i = 0; i < length; i++) { snprintf(number, 50, "%lf", current->value.v.floatArray[i]); DynStringConcat(result, number); if (i > length - 1) { DynStringConcat(result, ","); } } break; } DynStringConcat(result, "\n"); current = current->next; } return result; } /*---------------------------------------------------------------------------*/ static int ListHdbNode(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { pHdb node = NULL; int pathArg = 1; pDynString listData = NULL; Protocol protocol = normal_protocol; int outCode; if (argc < 2) { SCWrite(pCon, "ERROR: need path to node to print", eError); return 0; } if (argv[1][0] == '-') { pathArg = 2; if (argc < 3) { SCWrite(pCon, "ERROR: need path to node to print", eError); return 0; } } node = FindHdbNode(NULL, argv[pathArg], pCon); if (node == NULL) { return 0; } if (pathArg == 2) { strtolower(argv[1]); } if (strcmp(argv[1], "-val") == 0) { listData = formatListWithVal(node); } else if (strcmp(argv[1], "-cli") == 0) { listData = formatClientList(node); } else { if ((protocol = isJSON(pCon, 0)) == 1) { listData = formatJSONList(node); outCode = eHdbEvent; } else { listData = formatPlainList(node); outCode = eValue; } } if (listData == NULL) { SCWrite(pCon, "ERROR: failed to format list", eError); return 0; } if ((strcmp(argv[1], "-val") == 0) || (strcmp(argv[1], "-cli") == 0)) { SCWrite(pCon, GetCharArray(listData), eValue); } else { SCWrite(pCon, GetCharArray(listData), outCode); } DeleteDynString(listData); return 1; } /*---------------------------------------------------------------------------*/ static int AutoNotifyHdbNode(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { pHdb node = NULL; int id, status, recurse = 1; if (argc < 3) { SCWrite(pCon, "ERROR: need path and id in order to add notify", eError); return 0; } node = FindHdbNode(NULL, argv[1], pCon); if (node == NULL) { return 0; } id = atoi(argv[2]); if(argc > 3) { recurse = atoi(argv[3]); } status = InstallSICSNotify(node, pCon, id, recurse); if (status == 1) { SCSendOK(pCon); } return status; } /*---------------------------------------------------------------------------*/ static int RemoveHdbCallback(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { int id; hdbIDMessage m; if (argc < 2) { SCWrite(pCon, "ERROR: need callback id to remove", eError); return 0; } id = atoi(argv[1]); m.type = killID; m.ID = id; RecurseCallbackChains(root, (pHdbMessage) & m); SCSendOK(pCon); return 1; } /*---------------------------------------------------------------------------*/ static int LinkHdbNode(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { pHdb node = NULL; char buffer[256]; pObjectDescriptor pDes = NULL; if (argc < 3) { SCWrite(pCon, "ERROR: need path and object name to link", eError); return 0; } if (!SCMatchRights(pCon, usMugger)) { return 0; } node = GetHipadabaNode(root, argv[1]); if (node == NULL) { snprintf(buffer, 255, "ERROR: path %s NOT found!", argv[1]); SCWrite(pCon, buffer, eError); return 0; } pDes = FindCommandDescriptor(pSics, argv[2]); if (pDes == NULL) { snprintf(buffer, 255, "ERROR: failed to find object %s", argv[2]); SCWrite(pCon, buffer, eError); return 0; } if (pDes->parNode == NULL) { snprintf(buffer, 255, "ERROR: Object %s does not use Hipadaba natively and thus cannot be linked", argv[2]); SCWrite(pCon, buffer, eError); return 0; } if (pDes->parNode->mama != NULL) { snprintf(buffer, 255, "ERROR: Object %s is already linked somewhere else", argv[2]); SCWrite(pCon, buffer, eError); return 0; } AddHipadabaChild(node, pDes->parNode, pCon); if (argc > 3) { if (pDes->parNode->name != NULL) { free(pDes->parNode->name); } pDes->parNode->name = strdup(argv[3]); } SCSendOK(pCon); return 1; } /*-------------------------------------------------------------------------*/ static int isArrayNode(pHdb node) { switch(node->value.dataType) { case HIPINTAR: case HIPFLOATAR: case HIPINTVARAR: case HIPFLOATVARAR: return 1; default: return 0; } return 0; } /*-------------------------------------------------------------------------*/ static int HdbArrayNode(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { pHdb node = NULL; pObjectDescriptor pDes = NULL; int length, idx, ival, i; int xstart, xend, xlength, ystart, yend, ylength; double dval; hdbValue v; long sum; if (argc < 4) { SCWrite(pCon, "ERROR: need at least three arguments to harray", eError); return 0; } if (!SCMatchRights(pCon, usUser)) { return 0; } node = FindHdbNode(NULL, argv[1], pCon); if (node == NULL) { SCPrintf(pCon, eError, "ERROR: path %s NOT found!", argv[1]); return 0; } if(!isArrayNode(node)){ SCPrintf(pCon,eError,"ERROR: %s is no array node!", argv[1]); return 0; } if(strcmp(argv[2], "resize") == 0){ length = atoi(argv[3]); v = makeHdbValue(node->value.dataType, length); UpdateHipadabaPar(node, v, pCon); ReleaseHdbValue(&v); SCSendOK(pCon); return 1; } if(strcmp(argv[2], "init") == 0){ v = makeHdbValue(node->value.dataType, node->value.arrayLength); switch(node->value.dataType){ case HIPINTAR: case HIPINTVARAR: ival = atoi(argv[3]); for(i = 0; i < v.arrayLength; i++){ v.v.intArray[i] = ival; } break; case HIPFLOATAR: case HIPFLOATVARAR: dval = atof(argv[3]); for(i = 0; i < v.arrayLength; i++){ v.v.intArray[i] = dval; } break; } UpdateHipadabaPar(node, v, pCon); ReleaseHdbValue(&v); SCSendOK(pCon); return 1; } if(strcmp(argv[2],"sum") == 0){ if(argc < 9){ SCWrite(pCon,"ERROR: not enough arguments to harray sum", eError); return 0; } xstart = atoi(argv[3]); xend = atoi(argv[4]); xlength = atoi(argv[5]); ystart = atoi(argv[6]); yend = atoi(argv[7]); ylength = atoi(argv[8]); sum = sumWindow(node->value.v.intArray,xstart,xend,xlength,ystart,yend,ylength); SCPrintf(pCon,eValue,"sum = %ld", sum); return 1; } idx = atoi(argv[2]); if(idx < 0 || idx >= node->value.arrayLength ){ SCPrintf(pCon,eError,"ERROR: %d is out of range 0 - %d", idx, node->value.arrayLength); return 0; } switch(node->value.dataType){ case HIPINTAR: case HIPINTVARAR: node->value.v.intArray[idx] = atoi(argv[3]); break; case HIPFLOATAR: case HIPFLOATVARAR: node->value.v.floatArray[idx] = atof(argv[3]); break; } NotifyHipadabaPar(node, pCon); SCSendOK(pCon); return 1; } /*-------------------------------------------------------------------------*/ static hdbCallbackReturn ChainCallback(pHdb node, void *userData, pHdbMessage message) { pHdb slave = (pHdb) userData; hdbValue vv, old; pHdbDataMessage mm = NULL; if ((mm = GetHdbUpdateMessage(message)) == NULL) { return hdbContinue; } if (slave != NULL) { /* memset(&vv, 0, sizeof(hdbValue)); GetHipadabaPar(slave, &vv, mm->callData); */ UpdateHipadabaPar(slave, *(mm->v), mm->callData); /* ReleaseHdbValue(&vv); */ } return hdbContinue; } /*--------------------------------------------------------------------------*/ static int ChainHdbNode(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { pHdb master = NULL, slave = NULL; char buffer[512]; pHdbCallback kalle = NULL; if (argc < 3) { SCWrite(pCon, "ERROR: insufficent number of arguments to hchain", eError); } if (!SCMatchRights(pCon, usMugger)) { return 0; } slave = GetHipadabaNode(root, argv[1]); if (slave == NULL) { snprintf(buffer, 511, "ERROR: slave %s not found", argv[1]); SCWrite(pCon, buffer, eError); return 0; } master = GetHipadabaNode(root, argv[2]); if (master == NULL) { snprintf(buffer, 511, "ERROR: master %s not found", argv[1]); SCWrite(pCon, buffer, eError); return 0; } kalle = MakeHipadabaCallback(ChainCallback, slave, NULL); if (kalle == NULL) { SCWrite(pCon, "ERROR: out of memory creating callback", eError); return 0; } AppendHipadabaCallback(master, kalle); SCSendOK(pCon); return 1; } /* -------------------------------------------------------------------------- * This is actually SCInvoke but without advancing the context. I think this * is only of local use. It makes sure that commands executed as Hipadaba * commands get logged properly. */ static int HDBInvoke(SConnection * self, SicsInterp * pInter, char *pCommand) { int iRet; long lLen; const char *pResult = NULL; char *pBuffer = NULL, *pFile = NULL; char pBueffel[80]; int i, iSpace; assert(pInter); /* print command to log files */ /* for( i = 0; i < self->iFiles; i++) { if(self->pFiles[i]) { fprintf(self->pFiles[i],"SICS>> %s\n",pCommand); } } */ /* print to command log if user or manager */ if (SCGetRights(self) <= usUser) { if (self->pSock != NULL) { sprintf(pBueffel, "sock %d>>", self->pSock->sockid); } } /* invoke */ self->inUse++; self->eInterrupt = eContinue; /* get first word of command */ iRet = InterpExecute(pInter, self, pCommand); StatusFileTask(NULL); /* save changed parameters */ self->inUse--; return iRet; } /*---------------------------------------------------------------------------*/ static hdbCallbackReturn CommandSetCallback(pHdb node, void *userData, pHdbMessage message) { SConnection *pCon = NULL; pDynString cmd = NULL, par = NULL; pHdb current = NULL; int status; pHdbDataMessage mm = NULL; hdbValue v; /** * TODO: this is a duplicate: resolve. It is still here because the old * Hipadaba configuration commands still work */ if ((mm = GetHdbSetMessage(message)) == NULL) { return hdbContinue; } pCon = (SConnection *) mm->callData; v = *(mm->v); if (pCon == NULL) { printf("Cannot invoke command without connection\n"); return hdbAbort; } if (v.dataType == HIPTEXT) { if (strstr(v.v.text, "start") != NULL) { cmd = CreateDynString(64, 64); if (cmd == 0) { SCWrite(pCon, "ERROR: out of memory in CommandSetCallback", eError); return 0; } DynStringCopy(cmd, node->value.v.text); DynStringConcat(cmd, " "); current = node->child; while (current != NULL) { par = formatValue(current->value, current); if (par != NULL) { DynStringConcat(cmd, GetCharArray(par)); DynStringConcat(cmd, " "); DeleteDynString(par); } current = current->next; } // SendHdbStatusMessage(node,"start"); status = HDBInvoke(pCon, pServ->pSics, GetCharArray(cmd)); // SendHdbStatusMessage(node,"stop"); DeleteDynString(cmd); if (status == 1) { return hdbContinue; } else { return hdbAbort; } } else { SCWrite(pCon, "ERROR: this node only understands start as value", eError); return hdbAbort; } } return hdbContinue; } /*---------------------------------------------------------------------------*/ static hdbCallbackReturn CommandGetCallback(pHdb node, void *userData, pHdbMessage message) { pHdbDataMessage mm = NULL; if ((mm = GetHdbGetMessage(message)) == NULL) { return hdbContinue; } hdbValue v2 = MakeHdbText("Nothing to get"); copyHdbValue(&v2, mm->v); /* MakeHdbText makes no strdup ! */ return hdbContinue; } /*--------------------------------------------------------------------------*/ static int SicsCommandNode(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { char *name = NULL; pHdbCallback kalle = NULL; pHdb parent = NULL, node = NULL; if (argc < 3) { SCWrite(pCon, "ERROR: insufficent number of arguments to hcommand", eError); return 0; } if (!SCMatchRights(pCon, usMugger)) { return 0; } parent = FindHdbParent(NULL, argv[1], &name, pCon); if (parent == NULL) { return 0; /* error message already written */ } node = MakeHipadabaNode(name, HIPTEXT, 1); if (node == NULL) { SCWrite(pCon, "ERROR: out of memory in hcommand", eError); return 0; } node->value.v.text = strdup(argv[2]); node->value.arrayLength = strlen(argv[2]); SetHdbProperty(node, "sicscommand", argv[2]); // Set privillege of the node if (argc > 3) { SetHdbProperty(node, "priv", argv[3]); } kalle = MakeHipadabaCallback(CommandSetCallback, NULL, NULL); if (kalle == NULL) { SCWrite(pCon, "ERROR: out of memory in hcommand", eError); return 0; } AppendHipadabaCallback(node, kalle); kalle = MakeHipadabaCallback(CommandGetCallback, NULL, NULL); if (kalle == NULL) { SCWrite(pCon, "ERROR: out of memory in hcommand", eError); return 0; } AppendHipadabaCallback(node, kalle); AddHipadabaChild(parent, node, pCon); SCSendOK(pCon); return 1; } /*======================= Property Functions ================================*/ static int SetSICSHdbProperty(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { pHdb targetNode = NULL; char *val; if (argc < 4) { SCWrite(pCon, "ERROR: need path key value as parameters", eError); return 0; } targetNode = FindHdbNode(NULL, argv[1], pCon); if (targetNode == NULL) { SCPrintf(pCon, eError, "ERROR: node %s not found", argv[1]); return 0; } if (argc == 4) { SetHdbProperty(targetNode, argv[2], argv[3]); } else { val = Arg2Tcl(argc - 3, &argv[3], NULL, 0); if (val) { SetHdbProperty(targetNode, argv[2], val); free(val); } } SCSendOK(pCon); return 1; } /*-------------------------------------------------------------------------------*/ static int DelSICSHdbProperty(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { pHdb targetNode = NULL; if (argc < 3) { SCWrite(pCon, "ERROR: need path and key as parameters", eError); return 0; } targetNode = FindHdbNode(NULL, argv[1], pCon); if (targetNode == NULL) { SCPrintf(pCon, eError, "ERROR: node %s not found", argv[1]); return 0; } SetHdbProperty(targetNode, argv[2], NULL); SCSendOK(pCon); return 1; } /*--------------------------------------------------------------------------*/ static int HasSICSHdbProperty(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { pHdb targetNode = NULL; if (argc < 3) { SCWrite(pCon, "ERROR: need path key as parameters", eError); return 0; } targetNode = FindHdbNode(NULL, argv[1], pCon); if (targetNode == NULL) { SCWrite(pCon, "ERROR: node not found", eError); return 0; } if (HasHdbProperty(targetNode, argv[2])) { SCPrintf(pCon, eValue, "%s", "true"); return 1; } else { SCPrintf(pCon, eValue, "%s", "false"); return 1; } } /*--------------------------------------------------------------------------*/ static int GetSICSHdbProperty(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { pHdb targetNode = NULL; char buffer[512]; int status; if (argc < 3) { SCWrite(pCon, "ERROR: need path and key as parameters", eError); return 0; } targetNode = FindHdbNode(NULL, argv[1], pCon); if (targetNode == NULL) { SCPrintf(pCon, eError, "ERROR: node %s not found", argv[1]); return 0; } status = GetHdbProperty(targetNode, argv[2], buffer, 511); if (status != 1) { SCPrintf(pCon, eError, "ERROR: %s has no property %s", argv[1], argv[2]); return 0; } SCPrintf(pCon, eValue, "%s.%s = %s", argv[1], argv[2], buffer); return 1; } /*--------------------------------------------------------------------------*/ static int GetSICSHdbPropertyVal(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { pHdb targetNode = NULL; char buffer[512]; int status; if (argc < 3) { SCWrite(pCon, "ERROR: need path and key as parameters", eError); return 0; } targetNode = FindHdbNode(NULL, argv[1], pCon); if (targetNode == NULL) { SCPrintf(pCon, eError, "ERROR: node %s not found", argv[1]); return 0; } status = GetHdbProperty(targetNode, argv[2], buffer, 511); if (status != 1) { SCPrintf(pCon, eError, "ERROR: %s has no property %s", argv[1], argv[2]); return 0; } SCPrintf(pCon, eValue, "%s", buffer); return 1; } /*--------------------------------------------------------------------------*/ static int ListSICSHdbProperty(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { pHdb targetNode = NULL; char buffer[512]; const char *pKey = NULL; pDynString data = NULL; int genTclList = 0; if (argc < 2) { SCWrite(pCon, "ERROR: need path as parameter", eError); return 0; } else if (argc == 3) { genTclList = 1; } targetNode = FindHdbNode(NULL, argv[1], pCon); if (targetNode == NULL) { SCPrintf(pCon, eError, "ERROR: node %s not found", argv[1]); return 0; } data = CreateDynString(64, 64); if (data == NULL) { SCWrite(pCon, "ERROR: out of memory in ListSICSHdbProperty", eError); return 0; } InitHdbPropertySearch(targetNode); while ((pKey = GetNextHdbProperty(targetNode, buffer, 511)) != NULL) { DynStringConcat(data, (char *) pKey); if (genTclList) { DynStringConcat(data, " "); DynStringConcat(data, "{"); DynStringConcat(data, buffer); DynStringConcat(data, "}"); DynStringConcat(data, " "); } else { DynStringConcat(data, "="); DynStringConcat(data, buffer); DynStringConcat(data, "\n"); } } SCWrite(pCon, GetCharArray(data), eValue); DeleteDynString(data); return 1; } static int ANSTO_ListSICSHdbProperty(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { pHdb targetNode = NULL; char buffer[512], *globPtr = NULL; int cmpSize = 0; const char *pKey = NULL; pDynString data = NULL; if (argc < 3) { SCWrite(pCon, "ERROR: need path and search string as parameters", eError); return 0; } targetNode = FindHdbNode(NULL, argv[1], pCon); if (targetNode == NULL) { SCWrite(pCon, "ERROR: node not found", eError); return 0; } data = CreateDynString(64, 64); if (data == NULL) { SCWrite(pCon, "ERROR: out of memory in ListSICSHdbProperty", eError); return 0; } InitHdbPropertySearch(targetNode); /* Allow simple glob matches with '*' as a suffix Eg hfindprop /hpath @* */ if ((globPtr = index(argv[2], '*')) != NULL) { *globPtr = '\0'; } cmpSize = strlen(argv[2]); while ((pKey = GetNextHdbProperty(targetNode, buffer, 511)) != NULL) { if (strncasecmp(argv[2], pKey, cmpSize) == 0) { DynStringConcat(data, (char *) pKey); DynStringConcat(data, " "); DynStringConcat(data, buffer); DynStringConcat(data, "\n"); } } SCWrite(pCon, GetCharArray(data), eValue); DeleteDynString(data); return 1; } /*---------------------------------------------------------------------------*/ static pHdb matchHdbProp(pHdb root, char *propname, char *buffer, pDynString result, int invertmatch) { char value[1024], *path = NULL; pHdb current = NULL, search; memset(value, 0, 1024); if (strcmp(buffer, "*") == 0) { if (GetHdbProperty(root, propname, value, 1023) == 1) { if (!invertmatch) { path = GetHipadabaPath(root); DynStringConcat(result, path); DynStringConcat(result, "\n"); free(path); } } else if (invertmatch) { path = GetHipadabaPath(root); DynStringConcat(result, path); DynStringConcat(result, "\n"); free(path); } } else if (GetHdbProperty(root, propname, value, 1023) == 1) { if (strstr(buffer, value) != NULL) { if (!invertmatch) { path = GetHipadabaPath(root); DynStringConcat(result, path); DynStringConcat(result, "\n"); free(path); } } else if (invertmatch) { path = GetHipadabaPath(root); DynStringConcat(result, path); DynStringConcat(result, "\n"); free(path); } } current = root->child; while (current != NULL) { search = matchHdbProp(current, propname, buffer, result, invertmatch); current = current->next; } return NULL; } /*---------------------------------------------------------------------------*/ static int MatchHdbProperty(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { pHdb root = NULL; pHdb foundNode = NULL; char buffer[1024], *path = NULL; int node = 1, prop = 2, propval = 3, invertmatch = 0; pDynString matchList = NULL; if (argc < 4) { SCWrite(pCon, "ERROR: need root, property name and target string for search", eError); return 0; } if (argc >= 5) { if (strcasecmp(argv[1], "invert") == 0) { invertmatch = 1; node++; prop++; propval++; } } memset(buffer, 0, 1024); Arg2Text(argc - propval, &argv[propval], buffer, 1023); root = GetHipadabaNode(GetHipadabaRoot(), argv[node]); if (root == NULL) { SCWrite(pCon, "ERROR: start node for search not found", eError); return 0; } strtolower(argv[prop]); strtolower(buffer); matchList = CreateDynString(128, 128); foundNode = matchHdbProp(root, argv[prop], buffer, matchList, invertmatch); SCWrite(pCon, GetCharArray(matchList), eValue); DeleteDynString(matchList); return 1; } /*======================= Factory Functions =================================*/ void killSICSHipadaba() { if (root != NULL) { DeleteHipadabaNode(root, NULL); } root = NULL; } /*---------------------------------------------------------------------------*/ extern int HdbNodeFactory(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]); /* from sicshdbfactory.c */ /*---------------------------------------------------------------------------*/ int InstallSICSHipadaba(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { root = MakeHipadabaNode("/", HIPNONE, 0); AddCommand(pSics, "hmake", MakeHdbNode, NULL, NULL); AddCommand(pSics, "hfactory", HdbNodeFactory, NULL, NULL); AddCommand(pSics, "hmakescript", MakeHdbScriptNode, NULL, NULL); AddCommand(pSics, "hattach", SICSHdbAdapter, NULL, NULL); AddCommand(pSics, "hsubsamplehm", HdbSubSample, NULL, NULL); AddCommand(pSics, "hdel", DeleteHdbNode, NULL, NULL); AddCommand(pSics, "hset", SetHdbNode, NULL, NULL); AddCommand(pSics, "hupdate", UpdateHdbNode, NULL, NULL); AddCommand(pSics, "hget", GetHdbNode, NULL, NULL); AddCommand(pSics, "hval", GetHdbVal, NULL, NULL); AddCommand(pSics, "hzipget", ZipGetHdbNode, NULL, NULL); AddCommand(pSics, "hlist", ListHdbNode, NULL, NULL); AddCommand(pSics, "hnotify", AutoNotifyHdbNode, NULL, NULL); AddCommand(pSics, "hdelcb", RemoveHdbCallback, NULL, NULL); AddCommand(pSics, "hlink", LinkHdbNode, NULL, NULL); AddCommand(pSics, "hinfo", HdbNodeInfo, NULL, NULL); AddCommand(pSics, "hval", HdbNodeVal, NULL, NULL); AddCommand(pSics, "hchain", ChainHdbNode, NULL, NULL); AddCommand(pSics, "hcommand", SicsCommandNode, NULL, NULL); AddCommand(pSics, "harray", HdbArrayNode, NULL, NULL); AddCommand(pSics, "hsetprop", SetSICSHdbProperty, NULL, NULL); AddCommand(pSics, "hdelprop", DelSICSHdbProperty, NULL, NULL); AddCommand(pSics, "hgetprop", GetSICSHdbProperty, NULL, NULL); AddCommand(pSics, "hgetpropval", GetSICSHdbPropertyVal, NULL, NULL); AddCommand(pSics, "hmatchprop", MatchHdbProperty, NULL, NULL); AddCommand(pSics, "hpropexists", HasSICSHdbProperty, NULL, NULL); AddCommand(pSics, "hlistprop", ListSICSHdbProperty, NULL, NULL); AddCommand(pSics, "hfindprop", ANSTO_ListSICSHdbProperty, NULL, NULL); InstallSICSPoll(pCon, pSics, pData, argc, argv); poller = (pSicsPoll) FindCommandData(pSics, "sicspoll", "SicsPoll"); return 1; }