612 lines
17 KiB
C
612 lines
17 KiB
C
/**
|
|
* This is the header file for the new (as of 2007) style SICS objects
|
|
*
|
|
* copyright: see file COPYRIGHT
|
|
*
|
|
* Mark Koennecke, July 2007
|
|
*/
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <sics.h>
|
|
#include <tcl.h>
|
|
#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 saveSICSNode(pHdb node, char *prefix, char separator, FILE * fd)
|
|
{
|
|
/*
|
|
nodes with the property __save are saved
|
|
special case:
|
|
__save=update: a hupdate command is used instead of a set command
|
|
*/
|
|
char val[20];
|
|
char p[MAX_HDB_PATH];
|
|
pHdb child;
|
|
hdbValue v;
|
|
pDynString data = NULL;
|
|
char *cmd;
|
|
char *str = NULL;
|
|
char *value;
|
|
|
|
cmd = GetHdbProp(node, "creationCmd");
|
|
if (cmd != NULL) {
|
|
fprintf(fd, "%s\n", cmd);
|
|
}
|
|
if (GetHdbProperty(node, "__save", val, 20) == 1) {
|
|
GetHipadabaPar(node, &v, NULL);
|
|
if (v.dataType == HIPFUNC) {
|
|
fprintf(fd, "%s", prefix);
|
|
child = node->child;
|
|
while (child != NULL) {
|
|
GetHipadabaPar(child, &v, NULL);
|
|
data = formatValue(v, child);
|
|
if (data != NULL) {
|
|
value = GetCharArray(data);
|
|
str = Arg2Tcl(1, &value, NULL, 0);
|
|
fprintf(fd, " %s", str);
|
|
}
|
|
DeleteDynString(data);
|
|
free(str);
|
|
child = child->next;
|
|
}
|
|
fprintf(fd, "\n");
|
|
} else {
|
|
data = formatValue(v, node);
|
|
if (data != NULL) {
|
|
value = GetCharArray(data);
|
|
str = Arg2Tcl(1, &value, NULL, 0);
|
|
if (strcasecmp(val, "update") == 0) {
|
|
GetHdbPath(node, p, sizeof p);
|
|
fprintf(fd, "hupdate %s %s\n", p, str);
|
|
} else {
|
|
fprintf(fd, "%s %s\n", prefix, str);
|
|
}
|
|
DeleteDynString(data);
|
|
free(str);
|
|
}
|
|
}
|
|
ReleaseHdbValue(&v);
|
|
}
|
|
child = node->child;
|
|
while (child != NULL) {
|
|
/* the separator is blank for the first subnode and slash further down */
|
|
snprintf(p, sizeof p, "%s%c%s", prefix, separator, child->name);
|
|
saveSICSNode(child, p, '/', fd);
|
|
child = child->next;
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
int SaveSICSOBJ(void *data, char *name, FILE * fd)
|
|
{
|
|
pSICSOBJ self = (pSICSOBJ) data;
|
|
|
|
if (self != NULL && self->objectNode != NULL) {
|
|
saveSICSNode(self->objectNode, name, ' ', fd);
|
|
fprintf(fd, "\n"); /* make a blank line between objects for prettiness */
|
|
}
|
|
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 = GetHdbProperty(parNode,"geterror",buffer,sizeof(buffer));
|
|
if (status == 1 && strstr(buffer,"none") == NULL){
|
|
SCPrintf(pCon,eValue,"ERROR: %s on last read of %s", buffer, argv[0]);
|
|
return 0;
|
|
}
|
|
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");
|
|
SCparChange(pCon);
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|