/** * This is the header file for the new (as of 2007) style SICS objects * * copyright: see file COPYRIGHT * * Mark Koennecke, July 2007 */ #include #include #include #include #include "assert.h" #include "ifile.h" #include "sicsobj.h" #include "dynstring.h" #include "macro.h" #include "sicshipadaba.h" #include "initializer.h" #include "splitter.h" typedef struct { char *name; char *class; } NameClass; /*--------------------------------------------------------------------------*/ void DefaultKill(void *data) { return; } /*--------------------------------------------------------------------------*/ void DefaultFree(void *data) { if (data != NULL) { free(data); } } /*---------------------------------------------------------------------------*/ static void saveSICSNodeBroken(pHdb node, char *prefix, FILE * fd) { /* nodes with the property __save are saved special cases: __save=update: a hupdate command is used instead of a set command __save=kids: save kids, but not the value of this node */ char newprefix[1024], val[20]; char path[MAX_HDB_PATH]; pHdb child; hdbValue v; pDynString data = NULL; char *cmd; char *str, *value; cmd = GetHdbProp(node, "creationCmd"); if (cmd != NULL) { GetHdbPath(node, path, sizeof path); fprintf(fd, cmd, prefix, path); fprintf(fd, "\n"); } if (GetHdbProperty(node, "__save", val, 20) == 1) { if (strcasecmp(val, "kids") != 0) { GetHipadabaPar(node, &v, NULL); data = formatValue(v, node); if (data != NULL) { value = GetCharArray(data); str = Arg2Tcl(1, &value, NULL, 0); if (strcasecmp(val, "update") == 0) { GetHdbPath(node, path, sizeof path); fprintf(fd, "hupdate %s %s\n", path, str); } else { fprintf(fd, "%s %s\n", prefix, str); } DeleteDynString(data); free(str); } ReleaseHdbValue(&v); } } child = node->child; while (child != NULL) { snprintf(newprefix, 1024, "%s/%s", prefix, child->name); saveSICSNodeBroken(child, newprefix, fd); child = child->next; } } /*---------------------------------------------------------------------------*/ static void saveSICSNode(pHdb node, char *prefix, FILE * fd) { char newprefix[1024], val[20]; char path[MAX_HDB_PATH]; pHdb child; hdbValue v; pDynString data = NULL; char *cmd; cmd = GetHdbProp(node, "creationCmd"); if (cmd != NULL) { GetHdbPath(node, path, sizeof path); fprintf(fd, cmd, prefix, path); fprintf(fd, "\n"); } if (GetHdbProperty(node, "__save", val, 20) == 1) { GetHipadabaPar(node, &v, NULL); data = formatValue(v, node); if (data != NULL) { fprintf(fd, "%s %s\n", prefix, GetCharArray(data)); DeleteDynString(data); } ReleaseHdbValue(&v); child = node->child; while (child != NULL) { snprintf(newprefix, 1024, "%s/%s", prefix, child->name); saveSICSNode(child, newprefix, fd); child = child->next; } } } /*---------------------------------------------------------------------------*/ int SaveSICSOBJ(void *data, char *name, FILE * fd) { pSICSOBJ self = (pSICSOBJ) data; char prefix[1024]; char path[MAX_HDB_PATH]; pHdb node; char *cmd; if (self != NULL && self->objectNode != NULL) { node = self->objectNode->child; cmd = GetHdbProp(self->objectNode, "creationCmd"); if (cmd != NULL) { GetHdbPath(self->objectNode, path, sizeof path); fprintf(fd, cmd, name, path); fprintf(fd, "\n"); } while (node != NULL) { snprintf(prefix, 1024, "%s %s", name, node->name); saveSICSNode(node, prefix, fd); node = node->next; } } return 1; } /*---------------------------------------------------------------------------*/ int SaveSICSOBJBroken(void *data, char *name, FILE * fd) { pSICSOBJ self = (pSICSOBJ) data; char prefix[1024]; char path[MAX_HDB_PATH]; pHdb node; char *cmd; if (self != NULL && self->objectNode != NULL) { /* node = self->objectNode->child; cmd = GetHdbProp(self->objectNode, "creationCmd"); if (cmd != NULL) { GetHdbPath(self->objectNode, path, sizeof path); fprintf(fd, cmd, name, path); fprintf(fd, "\n"); } while (node != NULL) { snprintf(prefix, 1024, "%s %s", name, node->name); saveSICSNode(node, prefix, fd); node = node->next; } */ node = self->objectNode; snprintf(prefix, 1024, "%s %s", name, node->name); saveSICSNode(node, prefix, fd); fprintf(fd, "\n"); } return 1; } /*---------------------------------------------------------------------------*/ static void KillSICSOBJfromNode(void *userData) { NameClass *nameClass = userData; SICSOBJ *sicsobj; if (pServ->pSics != NULL) { sicsobj = FindCommandData(pServ->pSics, nameClass->name, nameClass->class); if (sicsobj) { sicsobj->objectNode = NULL; /* do not call RemoveHdbNodeFromParent in KillSICSOBJ */ sicsobj->pDes->parNode = NULL; /* do not free the node twice in KillSICSOBJ/DeleteDescriptor */ RemoveCommand(pServ->pSics, nameClass->name); } } free(nameClass->name); free(nameClass->class); free(nameClass); } /*---------------------------------------------------------------------------*/ static hdbCallbackReturn DummyCallback(Hdb *node, void *userData, hdbMessage *msg) { return hdbContinue; } /*---------------------------------------------------------------------------*/ void RegisterSICSOBJKillCmd(pSICSOBJ sicsobj, char *name) { hdbCallback *cb; NameClass *nameClass; nameClass = calloc(1, sizeof(*nameClass)); nameClass->name = strdup(name); nameClass->class = strdup(sicsobj->pDes->name); /* use only the kill function */ cb = MakeHipadabaCallback(DummyCallback, nameClass, KillSICSOBJfromNode); assert(cb); AppendHipadabaCallback(sicsobj->objectNode, cb); } /*---------------------------------------------------------------------------*/ pSICSOBJ MakeSICSOBJv(char *name, char *class, int type, int priv) { pSICSOBJ pNew = NULL; hdbValue val; pNew = (pSICSOBJ) malloc(sizeof(SICSOBJ)); if (pNew == NULL) { return NULL; } memset(pNew, 0, sizeof(SICSOBJ)); pNew->pDes = CreateDescriptor(class); pNew->pDes->SaveStatus = SaveSICSOBJ; if (type == HIPNONE) { pNew->objectNode = MakeHipadabaNode(name, HIPNONE, 1); } else { val = makeHdbValue(type, 0); pNew->objectNode = MakeSICSHdbPar(name, priv, val); ReleaseHdbValue(&val); } SetHdbProperty(pNew->objectNode, "sicscommand", name); if (pNew->pDes == NULL || pNew->objectNode == NULL) { free(pNew); return (NULL); } pNew->pDes->parNode = pNew->objectNode; pNew->KillPrivate = DefaultKill; return pNew; } /*---------------------------------------------------------------------------*/ pSICSOBJ MakeSICSOBJ(char *name, char *class) { return MakeSICSOBJv(name, class, HIPNONE, 0); } /*---------------------------------------------------------------------------*/ void KillSICSOBJ(void *data) { pSICSOBJ self = (pSICSOBJ) data; if (self == NULL) { return; } if (self->KillPrivate != NULL && self->pPrivate != NULL) { self->KillPrivate(self->pPrivate); } if (self->objectNode != NULL && pServ->pTasker != NULL) { /* not on rundown */ RemoveHdbNodeFromParent(self->objectNode, pServ->dummyCon); } if (self->pDes != NULL) { self->objectNode = NULL; /* inhibit SICSOBJcallback from deleting twice */ DeleteDescriptor(self->pDes); /* kill descriptor including node */ } free(self); } /*===========================================================================*/ static int assignPar(pHdb node, SConnection * pCon, char *data) { char error[132], buffer[256]; int status; status = readHdbValue(&node->value, data, error, 132); if (status != 1) { snprintf(buffer, 255, "ERROR: error parsing %s: %s", node->name, error); SCWrite(pCon, buffer, eError); return 0; } return 1; } /*---------------------------------------------------------------------------*/ int runObjFunction(pSICSOBJ object, SConnection *pCon, pHdb commandNode) { pHdb parArray[64], child; int status, count = 0; SICSOBJFunc pFunc = NULL; assert(commandNode != NULL); child = commandNode->child; while(child != NULL){ parArray[count] = child; count++; child = child->next; } pFunc = (SICSOBJFunc)commandNode->value.v.func; assert(pFunc != NULL); status = pFunc(object, pCon, commandNode, parArray, count); return status; } /*---------------------------------------------------------------------------*/ static int invokeOBJFunction(pSICSOBJ object, pHdb commandNode, SConnection * pCon, int argc, char *argv[]) { int status, i, count = 0; pHdb currentPar = NULL; SICSOBJFunc pFunc = NULL; pHdb parArray[64]; char buffer[1024]; /* * If the first argument has the special name args, concatenate all arguments * and put the result as text into this parameter. This allows for the * object function to parse and interpret the arguments itself. */ if (commandNode->child != NULL && strcmp(commandNode->child->name, "args") == 0) { Arg2Text(argc, argv, buffer, 1024); assignPar(commandNode->child, pCon, buffer); parArray[0] = commandNode->child; count = 1; goto invoke; } /* * assign parameters and fill parameter array for function at the same * time. Be lenient about missing parameters: Then the old values will * be used. */ for (i = 0, currentPar = commandNode->child; i < argc && currentPar != NULL; i++, currentPar = currentPar->next) { if (argv[i] != NULL) { status = assignPar(currentPar, pCon, argv[i]); if (status != 1) { return status; } } parArray[i] = currentPar; count++; } invoke:pFunc = (SICSOBJFunc) commandNode->value.v.func; if (pFunc == NULL) { SCWrite(pCon, "ERROR: internal error, function not found", eError); return 0; } SendHdbStatusMessage(commandNode, "start"); status = pFunc(object, pCon, commandNode, parArray, count); SendHdbStatusMessage(commandNode, "stop"); return status; } /*---------------------------------------------------------------------------*/ static int ScriptObjFunc(pSICSOBJ obj, SConnection * pCon, pHdb commandNode, pHdb par[], int nCount) { int status, i; Tcl_Interp *pTcl = NULL; Tcl_DString com; char value[256]; pDynString val = NULL; char *pPtr = NULL; memset(value, 0, 256); GetHdbProperty(commandNode, "priv", value, 256); status = decodeSICSPriv(value); if (!SCMatchRights(pCon, status)) { return 0; } if (GetHdbProperty(commandNode, "script", value, 256) != 1) { SCWrite(pCon, "ERROR: script property not configured on this node", eError); return 0; } Tcl_DStringInit(&com); Tcl_DStringAppend(&com, value, strlen(value)); for (i = 0; i < nCount; i++) { val = formatValue(par[i]->value, par[i]); if (val != NULL) { Tcl_DStringAppend(&com, " ", 1); pPtr = GetCharArray(val); Tcl_DStringAppend(&com, pPtr, strlen(pPtr)); DeleteDynString(val); } } MacroPush(pCon); pTcl = InterpGetTcl(pServ->pSics); status = Tcl_Eval(pTcl, Tcl_DStringValue(&com)); Tcl_DStringFree(&com); MacroPop(); if (status == TCL_OK) { SCWrite(pCon, Tcl_GetStringResult(pTcl), eValue); return 1; } else { SCWrite(pCon, Tcl_GetStringResult(pTcl), eError); return 0; } return 1; } /*--------------------------------------------------------------------------*/ static int MakeScriptFunc(pSICSOBJ self, SConnection * pCon, int argc, char *argv[]) { char path[512], *pPtr = NULL; pHdb parent = NULL, node = NULL; hdbValue func; if (argc < 5) { SCWrite(pCon, "ERROR: not enough arguments: obj makescriptfunc path script priv", eError); return 0; } if (!SCMatchRights(pCon, usMugger)) { return 0; } strlcpy(path, argv[2], 511); pPtr = strrchr(path, '/'); if (pPtr == NULL) { /* no hierarchy */ parent = self->objectNode; node = MakeHipadabaNode(path, HIPFUNC, 1); } else { /* hierarchy */ *pPtr = '\0'; parent = GetHipadabaNode(self->objectNode, path); pPtr++; node = MakeHipadabaNode(pPtr, HIPFUNC, 1); } if (parent == NULL || node == NULL) { SCWrite(pCon, "ERROR: root path error or out of memory", eError); return 0; } node->value = MakeSICSFunc(ScriptObjFunc); SetHdbProperty(node, "script", argv[3]); SetHdbProperty(node, "priv", argv[4]); AppendHipadabaCallback(node, MakeSICSFuncCallback(self)); AddHipadabaChild(parent, node, pCon); SCSendOK(pCon); return 1; } /*---------------------------------------------------------------------------*/ static int isNodePrintable(pHdb node) { switch (node->value.dataType) { case HIPNONE: case HIPFUNC: return 0; default: return 1; } } /*---------------------------------------------------------------------------*/ static void objFormatNode(pHdb node, char separator, char *prefix, pDynString data) { char par[128], buffer[256]; pDynString dyn = NULL; int i; pHdb child; char *vis; snprintf(par, sizeof par, "%-20s = ", prefix); DynStringConcat(data, par); dyn = formatValue(node->value, node); if (dyn != NULL) { if(GetDynStringLength(dyn) < 256){ DynStringConcat(data, GetCharArray(dyn)); } else { strlcpy(buffer,GetCharArray(dyn),255); DynStringConcat(data, buffer); DynStringConcat(data,"......"); } } else { dyn = CreateDynString(60, 63); } DynStringConcatChar(data, '\n'); for (child = node->child; child != NULL; child = child->next) { DynStringCopy(dyn, prefix); DynStringConcatChar(dyn, separator); DynStringConcat(dyn, child->name); objFormatNode(child, '/', GetCharArray(dyn), data); } DeleteDynString(dyn); } /*---------------------------------------------------------------------------*/ static int ListObj(pSICSOBJ self, SConnection * pCon, int argc, char *argv[]) { pDynString data; data = CreateDynString(128, 128); if (data == NULL) { return 0; } if (self->pDes->parNode != NULL) { objFormatNode(self->pDes->parNode, ' ', argv[0], data); } SCWrite(pCon, GetCharArray(data), eValue); DeleteDynString(data); return 1; } /*---------------------------------------------------------------------------*/ int InvokeSICSOBJ(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { pSICSOBJ self = NULL; int status; pHdb parNode; char buffer[132]; hdbValue data; pDynString parData; self = (pSICSOBJ) pData; assert(self != NULL); if (argc == 1) { parNode = self->objectNode; if (parNode != NULL && isNodePrintable(parNode)) { status = GetHipadabaPar(parNode, &data, pCon); if (status != 1) { return 0; } parData = formatValue(data, parNode); if (parData == NULL) { SCWrite(pCon, "ERROR: failed to format data", eError); return 0; } SCPrintf(pCon, eValue, "%s = %s", argv[0], GetCharArray(parData)); DeleteDynString(parData); return 1; } else { SCWrite(pCon, "ERROR: nothing to print", eError); return 0; } } else { parNode = GetHipadabaNode(self->objectNode, argv[1]); if(parNode == NULL){ strtolower(argv[1]); parNode = GetHipadabaNode(self->objectNode,argv[1]); } } if (parNode != NULL && parNode->value.dataType == HIPFUNC) { status = invokeOBJFunction(self, parNode, pCon, argc - 2, &argv[2]); } else { snprintf(buffer, sizeof buffer, "%s ", argv[0]); status = ProcessSICSHdbPar(self->objectNode, pCon, buffer, argc - 1, &argv[1]); } if (status == -1) { if (strcmp(argv[1], "makescriptfunc") == 0) { return MakeScriptFunc(self, pCon, argc, argv); } else if (strcmp(argv[1], "list") == 0) { return ListObj(self, pCon, argc, argv); } /* error message written by the caller */ } return status; } /*---------------------------------------------------------------------------*/ int InterInvokeSICSOBJ(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { int status; char buffer[132]; status = InvokeSICSOBJ(pCon, pSics, pData, argc, argv); if (status == -1) { status = 0; if (argc > 1) { snprintf(buffer, sizeof buffer, "ERROR: %s %s not found", argv[0], argv[1]); } else { snprintf(buffer, sizeof buffer, "ERROR: no argument found"); } SCWrite(pCon, buffer, eError); status = 0; } return status; } /*---------------------------------------------------------------------------*/ pSICSOBJ SetupSICSOBJ(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { pSICSOBJ pNew = NULL; int status; int type; int priv; if (argc < 3) { SCWrite(pCon, "ERROR: not enough arguments to InstallSICSOBJ", eError); return NULL; } if (argc < 5) { type = HIPNONE; priv = usInternal; } else { /* convert privilege */ priv = decodeSICSPriv(argv[3]); /* convert datatype */ type = convertHdbType(argv[4]); if (type > HIPTEXT) { SCWrite(pCon, "ERROR: invalid type requested: none, int, float supported", eError); return 0; } } pNew = MakeSICSOBJv(argv[1], argv[2], type, priv); if (pNew == NULL) { SCWrite(pCon, "ERROR: out of memory creating new SICS object", eError); return NULL; } if (strcasecmp(argv[0], "DynSicsObj") == 0) { /* make object dynamic by defining a creation command */ SetDescriptorKey(pNew->pDes, "creationCommand", "0"); } SetHdbProperty(pNew->objectNode, "sicsdev", argv[1]); status = AddCommand(pSics, argv[1], InterInvokeSICSOBJ, KillSICSOBJ, pNew); if (status != 1) { KillSICSOBJ(pNew); SCPrintf(pCon, eError, "ERROR: failed create duplicate command %s", argv[1]); return NULL; } return pNew; } /*---------------------------------------------------------------------------*/ int InstallSICSOBJ(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { pSICSOBJ pNew = NULL; pNew = SetupSICSOBJ(pCon, pSics, pData, argc, argv); if (pNew == NULL) { return 0; } else { return 1; } }