1459 lines
38 KiB
C
1459 lines
38 KiB
C
#include <strings.h>
|
|
#include <tcl.h>
|
|
#include <time.h>
|
|
#include <math.h>
|
|
#include "sics.h"
|
|
#include "sicsobj.h"
|
|
#include "initializer.h"
|
|
#include "commandlog.h"
|
|
#include "hipadaba.h"
|
|
#include "sicshipadaba.h"
|
|
#include "dynstring.h"
|
|
#include "ascon.h"
|
|
#include "errormsg.h"
|
|
|
|
/** \file
|
|
* \brief script context implementation (Sct)
|
|
*/
|
|
|
|
/** \brief the maximum hdb path length */
|
|
#define MAX_HDB_PATH 1024
|
|
|
|
typedef enum {
|
|
sct_send_keyword,
|
|
sct_result_keyword,
|
|
sct_command_keyword,
|
|
sct_path_keyword,
|
|
sct_update_keyword,
|
|
sct_take_keyword,
|
|
sct_complete_keyword,
|
|
sct_chain_keyword,
|
|
sct_next_keyword,
|
|
sct_steplist_keyword,
|
|
sct_no_keyword
|
|
} SctKeyword;
|
|
|
|
/* keywords must have the same order as SctKeyword */
|
|
static char *sctKeywords[]={
|
|
"send",
|
|
"result",
|
|
"command",
|
|
"path",
|
|
"update",
|
|
"take",
|
|
"complete",
|
|
"chain",
|
|
"next",
|
|
"steplist",
|
|
NULL
|
|
};
|
|
|
|
static char *reset_type="";
|
|
|
|
typedef struct SctList SctList;
|
|
|
|
typedef struct SctChain {
|
|
struct SctChain *next;
|
|
char *command;
|
|
SctList *scriptList;
|
|
pHdb relatedNode;
|
|
ErrMsg *msg;
|
|
int doit;
|
|
char *dynamic;
|
|
} SctChain;
|
|
|
|
/* define SctChainList and their functions */
|
|
#define MC_NAME(T) SctChain##T
|
|
#include "mclist.c"
|
|
|
|
typedef enum {set_type, timed_type, manual_type, no_type} SctScriptListType;
|
|
static char *slTypes[]={"set", "timed", "manual", NULL};
|
|
|
|
struct SctList {
|
|
struct SctList *next;
|
|
char *name;
|
|
SctChain *beginScript;
|
|
SctChain *endScript;
|
|
SctScriptListType type;
|
|
int dirty;
|
|
double interval;
|
|
double lastPeriod;
|
|
SctChain *lastScript;
|
|
SctChainList chains;
|
|
};
|
|
|
|
/* define SctListList and their functions */
|
|
#define MC_NAME(T) SctList##T
|
|
#include "mclist.c"
|
|
|
|
typedef struct Sct Sct;
|
|
|
|
typedef struct SctParData {
|
|
struct SctParData *next;
|
|
Sct *sct;
|
|
SctChain *scriptChain;
|
|
int pending, inprogress;
|
|
int refCnt;
|
|
hdbValue target;
|
|
SCStore conCtx;
|
|
} SctParData;
|
|
|
|
typedef struct SctObjectName {
|
|
struct SctObjectName *next;
|
|
char *name;
|
|
} SctObjectName;
|
|
|
|
/* define SctObjectNameList and their functions */
|
|
#define MC_NAME(T) SctObjectName##T
|
|
#include "mclist.c"
|
|
|
|
struct Sct {
|
|
pObjectDescriptor desc;
|
|
char *name;
|
|
SctListList scriptLists;
|
|
SctObjectNameList names; /* created with the "object" command, needed for kill only */
|
|
AsconPtr ascon;
|
|
pHdb currentNode;
|
|
SctParData *foundData;
|
|
char *cmd;
|
|
char *result;
|
|
char *nextScript;
|
|
SctChain *runningChain;
|
|
SCStore debugConn;
|
|
char *debugCommand;
|
|
int sent;
|
|
SctKeyword operation;
|
|
int killTask;
|
|
int killObj;
|
|
int verbose;
|
|
int taskSteps;
|
|
};
|
|
|
|
static Sct *sct = NULL;
|
|
|
|
static void SctFreeParData(void *d) {
|
|
SctParData *data=d;
|
|
data->refCnt--;
|
|
if (data->refCnt == 0) {
|
|
if (data->conCtx) SCStoreFree(data->conCtx);
|
|
free(data);
|
|
}
|
|
}
|
|
|
|
pHdb SctFindObjNode(char *name) {
|
|
CommandList *cmd;
|
|
pDummy obj;
|
|
|
|
cmd = FindCommand(pServ->pSics, name);
|
|
if (cmd == NULL) return NULL;
|
|
obj = (void *)cmd->pData;
|
|
if (obj == NULL || obj->pDescriptor->parNode==NULL) return NULL;
|
|
return obj->pDescriptor->parNode;
|
|
}
|
|
|
|
/** \brief find the node with the relative path relpath
|
|
* \param node the root node (where to start)
|
|
* \param relpath an absolute or relative path
|
|
* \param parentPtr a pointer to the found parent (may be NULL if not used)
|
|
* \param nodePtr a pointer to the found node
|
|
* \return the name of the node
|
|
*
|
|
* An abolute path starts with a slash, a relative path equal to "."
|
|
* means that the input node is returned. A syntax like "..", "../down"
|
|
* is also allowed, but the double dots must appear at the start of the path.
|
|
*
|
|
* This routine may also be used in order to find the parent node of
|
|
* a node not yet existing. In this case the nodePtr will point
|
|
* to a NULL pointer on return, and a pointer to the last element
|
|
* in the path is returned.
|
|
*
|
|
* Nodes anchored in the sics object list are also found when
|
|
* the path starts with "/sics/"
|
|
*/
|
|
char *SctFindNode(pHdb node, char *relpath, pHdb *parentPtr, pHdb *nodePtr) {
|
|
char *path;
|
|
char buffer[MAX_HDB_PATH];
|
|
pHdb root = NULL;
|
|
char *name;
|
|
char *slash;
|
|
|
|
if (strlen(relpath) >= sizeof(buffer)) {
|
|
*nodePtr = NULL;
|
|
return NULL; /* relpath too long */
|
|
}
|
|
strcpy(buffer, relpath);
|
|
path = buffer;
|
|
if (path[0] == '/') {
|
|
if (strncmp(path, "/sics/", 6) == 0) {
|
|
/* sics object case */
|
|
slash = strchr(path+6, '/');
|
|
if (slash != NULL) {
|
|
*slash = '\0';
|
|
}
|
|
node = SctFindObjNode(path);
|
|
if (node == NULL) goto notFound;
|
|
if (slash == NULL) goto nodeFound;
|
|
path = slash+1;
|
|
/* root node is sics object, path is relative to it */
|
|
} else {
|
|
/* absolute path */
|
|
node = GetHipadabaRoot();
|
|
/* strip off first slash, root node is sics root */
|
|
path++;
|
|
}
|
|
} else if (path[0] == '.') {
|
|
if (path[1] == '\0') {
|
|
/* this path */
|
|
goto nodeFound;
|
|
}
|
|
/* upper node */
|
|
while (strncmp(path, "..", 2) == 0 && node != NULL) {
|
|
node = node->mama;
|
|
if (path[2] == '\0') goto nodeFound;
|
|
path += 3;
|
|
}
|
|
if (node == NULL) goto notFound;
|
|
}
|
|
|
|
/* now go down in path */
|
|
while (node != NULL) {
|
|
root = node;
|
|
slash = strchr(path, '/');
|
|
if (slash != NULL) *slash='\0';
|
|
for (node = root->child; node != NULL; node = node->next) {
|
|
if (strcasecmp(node->name, path) == 0) {
|
|
if (slash == NULL) goto nodeFound;
|
|
path = slash + 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (slash == NULL) {
|
|
if (parentPtr != NULL) {
|
|
*parentPtr = root;
|
|
}
|
|
*nodePtr = NULL;
|
|
/* the returned name must be taken from the end of relpath, as path is no longer valid */
|
|
name = relpath + (path - buffer);
|
|
goto finish;
|
|
}
|
|
notFound:
|
|
node = NULL;
|
|
nodeFound:
|
|
*nodePtr = node;
|
|
if (node) {
|
|
if (parentPtr != NULL) {
|
|
*parentPtr = node->mama;
|
|
}
|
|
name = node->name;
|
|
} else {
|
|
if (parentPtr != NULL) {
|
|
*parentPtr = NULL;
|
|
}
|
|
name = NULL;
|
|
}
|
|
finish:
|
|
return name;
|
|
}
|
|
|
|
/** \brief get the absolute path of a node anchored in the
|
|
* Hipadaba root or in a sics object
|
|
* \param nodeArg the input node
|
|
* \param path the result
|
|
* \param pathlen length of the result
|
|
* \return 1 on success, 0 on failure
|
|
*/
|
|
int SctGetPath(pHdb nodeArg, char *path, size_t pathlen) {
|
|
pHdb node, root;
|
|
int len, pos, l;
|
|
static char *sics="/sics";
|
|
|
|
/* determine path length and root node */
|
|
root = nodeArg;
|
|
len = 0;
|
|
for (node = nodeArg; node != NULL; node = node->mama) {
|
|
len += strlen(node->name) + 1;
|
|
if (len >= pathlen) return 0; /* buffer overflow (may be recursize path?) */
|
|
root = node;
|
|
}
|
|
|
|
/* check root and add prefix */
|
|
path[0]='\0';
|
|
if (root != GetHipadabaRoot()) { /* not anchored in root */
|
|
if (!FindCommand(pServ->pSics, root->name)) {
|
|
/* not a sicsobject, give up */
|
|
path[0]='\0';
|
|
return 0;
|
|
}
|
|
/* sics object case */
|
|
l = strlen(sics);
|
|
len += l;
|
|
if (len >= pathlen) return 0;
|
|
strncpy(path, sics, l);
|
|
}
|
|
|
|
/* build the path backwards */
|
|
path[len]='\0';
|
|
pos = len;
|
|
for (node = nodeArg; node != NULL; node = node->mama) {
|
|
len = strlen(node->name);
|
|
pos -= len;
|
|
assert(pos>0);
|
|
strncpy(path+pos, node->name, len);
|
|
pos--;
|
|
path[pos]='/';
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int UpdateNode(SConnection *con, ErrMsgList *e, pHdb node, int argc, char *argv[]) {
|
|
hdbValue newValue;
|
|
static char errtxt[512];
|
|
char *str;
|
|
int status;
|
|
|
|
if (!cloneHdbValue(&node->value, &newValue)) {
|
|
ErrPutMsg(e, NULL, "no memory");
|
|
return 0;
|
|
}
|
|
str = ConcatArgs(argc, argv);
|
|
if (str == NULL) {
|
|
ErrPutMsg(e, NULL, "no memory");
|
|
return 0;
|
|
}
|
|
if (!readHdbValue(&newValue, str, errtxt, sizeof errtxt)) {
|
|
ErrPutMsg(e, errtxt, "conversion failure");
|
|
return 0;
|
|
}
|
|
free(str);
|
|
status = UpdateHipadabaPar(node, newValue, con);
|
|
ReleaseHdbValue(&newValue);
|
|
return status;
|
|
}
|
|
|
|
static int SctFindKeyword(char *name, char *keywords[]) {
|
|
int i;
|
|
for (i=0; keywords[i]!=NULL; i++) {
|
|
if (strcasecmp(name, keywords[i]) == 0) return i;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
static SctChain *SctMakeChain(char *command) {
|
|
SctChain *sc;
|
|
|
|
sc = calloc(1, sizeof(*sc));
|
|
if (sc == NULL) return NULL;
|
|
sc->doit = 0;
|
|
sc->dynamic = NULL;
|
|
sc->command = command;
|
|
sc->scriptList = NULL;
|
|
sc->msg = NULL;
|
|
return sc;
|
|
}
|
|
|
|
static void SctSetListDirty(SctList *sl) {
|
|
if (!sl->dirty) {
|
|
sl->dirty = 1;
|
|
if (sl->beginScript) {
|
|
sl->beginScript->doit = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void SctSetDirty(SctChain *sc) {
|
|
SctSetListDirty(sc->scriptList);
|
|
sc->doit = 1;
|
|
}
|
|
|
|
static int SctUpdateCallback(void *user, void *conn, pHdb node, hdbValue value) {
|
|
SctParData *data = user;
|
|
SConnection *con;
|
|
char path[MAX_HDB_PATH];
|
|
pDynString str;
|
|
|
|
if (data->inprogress) {
|
|
if (data->sct->operation == sct_complete_keyword) {
|
|
data->inprogress = 0;
|
|
SctGetPath(node, path, sizeof path);
|
|
con = SCStorePush(data->conCtx);
|
|
str = formatValue(value, node);
|
|
SCPrintf(con, eStatus, "%s = %s", path,
|
|
GetCharArray(str));
|
|
DeleteDynString(str);
|
|
SCStorePop(data->conCtx);
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int SctSetCallback(void *user, void *conn, pHdb node, hdbValue value) {
|
|
SctParData *data = user;
|
|
SConnection *oldCon;
|
|
char path[MAX_HDB_PATH];
|
|
pDynString str;
|
|
|
|
if (data->scriptChain) {
|
|
if (data->pending) {
|
|
SctGetPath(node, path, sizeof path);
|
|
oldCon = SCStorePush(data->conCtx);
|
|
str = formatValue(value, node);
|
|
SCPrintf(oldCon, eStatus, "target of %s changed to %s", path,
|
|
GetCharArray(str));
|
|
DeleteDynString(str);
|
|
SCStorePop(data->conCtx);
|
|
}
|
|
data->conCtx = SCSave(conn, data->conCtx);
|
|
data->pending = 1;
|
|
SctSetDirty(data->scriptChain);
|
|
copyHdbValue(&value, &data->target);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int SctReadCallback(void *user, void *conn, pHdb node, hdbValue value) {
|
|
SctParData *data = user;
|
|
|
|
data->sct->foundData = data;
|
|
if (data->sct->operation == sct_take_keyword && data->pending) {
|
|
data->pending = 0;
|
|
data->inprogress = 1;
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int SctExec(SConnection *con, SicsInterp *sics, void *object, int argc, char *argv[]) {
|
|
SctKeyword keyword;
|
|
SctList *sl;
|
|
SctChain *sc;
|
|
pHdb node;
|
|
hdbValue newValue;
|
|
pDynString result;
|
|
char *args;
|
|
char path[MAX_HDB_PATH];
|
|
SConnection *dcon;
|
|
|
|
if (sct == NULL) {
|
|
SCPrintf(con, eError, "ERROR: %s may be called only in proper context", argv[0]);
|
|
return 0;
|
|
};
|
|
if (argc < 2) {
|
|
SCPrintf(con, eInError, "ERROR: missing %s subcommand", argv[0]);
|
|
goto quit;
|
|
};
|
|
if (sct->verbose != 0) {
|
|
args = ConcatArgs(argc, argv);
|
|
dcon = SCStorePush(sct->debugConn);
|
|
SCPrintf(dcon, eWarning, "commnd: %s", args);
|
|
SCStorePop(sct->debugConn);
|
|
free(args);
|
|
args = NULL;
|
|
}
|
|
keyword = SctFindKeyword(argv[1], sctKeywords);
|
|
sct->operation = keyword;
|
|
switch (keyword) {
|
|
case sct_send_keyword:
|
|
if (argc < 4) {
|
|
SCPrintf(con, eInError, "ERROR: should be: %s send <cmd> <script ...>", argv[0]);
|
|
goto quit;
|
|
}
|
|
if (sct->cmd != NULL || sct->nextScript != NULL) {
|
|
SCPrintf(con, eInError, "ERROR: %s busy", argv[0]);
|
|
sct->taskSteps = 0;
|
|
goto quit;
|
|
}
|
|
if (sct->ascon == 0) {
|
|
SCPrintf(con, eInError, "ERROR: %s has no connection", argv[0]);
|
|
goto quit;
|
|
}
|
|
sct->cmd = strdup(argv[2]);
|
|
if (sct->verbose != 0) {
|
|
dcon = SCStorePush(sct->debugConn);
|
|
SCPrintf(dcon, eWarning, "send : %s", sct->cmd);
|
|
SCStorePop(sct->debugConn);
|
|
}
|
|
AsconWrite(sct->ascon, sct->cmd, 0);
|
|
sct->nextScript = ConcatArgs(argc-3, argv+3);
|
|
if (sct->result) free(sct->result);
|
|
sct->result = NULL;
|
|
break;
|
|
case sct_result_keyword:
|
|
if (!sct->result) {
|
|
SCPrintf(con, eInError, "ERROR: no result available");
|
|
goto quit;
|
|
}
|
|
SCWrite(con, sct->result, eValue);
|
|
goto success;
|
|
case sct_command_keyword:
|
|
if (!sct->cmd) {
|
|
SCPrintf(con, eInError, "ERROR: no command available");
|
|
goto quit;
|
|
}
|
|
SCWrite(con, sct->cmd, eValue);
|
|
goto success;
|
|
case sct_path_keyword:
|
|
if (SctGetPath(sct->currentNode, path, sizeof path)) {
|
|
SCWrite(con, path, eValue);
|
|
} else {
|
|
SCWrite(con, "ERROR: node not anchored or path name too long", eInError);
|
|
}
|
|
goto success;
|
|
case sct_complete_keyword:
|
|
/* fall through */
|
|
case sct_update_keyword:
|
|
if (argc < 4) {
|
|
SCPrintf(con, eInError, "ERROR: should be: %s %s <par> <value>", argv[0], argv[1]);
|
|
goto quit;
|
|
}
|
|
SctFindNode(sct->currentNode, argv[2], NULL, &node);
|
|
if (node == NULL) {
|
|
goto missingPar;
|
|
}
|
|
return UpdateNode(con, AsconGetErrList(sct->ascon), node, argc-3, argv+3);
|
|
case sct_take_keyword:
|
|
if (argc < 3) {
|
|
SCPrintf(con, eInError, "ERROR: should be: %s take <par>", argv[0]);
|
|
goto quit;
|
|
}
|
|
SctFindNode(sct->currentNode, argv[2], NULL, &node);
|
|
if (node == NULL) {
|
|
goto missingPar;
|
|
}
|
|
memset(&newValue,0,sizeof(hdbValue));
|
|
sct->foundData = NULL;
|
|
GetHipadabaPar(node, &newValue, con);
|
|
if (sct->foundData) {
|
|
cloneHdbValue(&sct->foundData->target, &newValue);
|
|
}
|
|
result = formatValue(newValue, node);
|
|
ReleaseHdbValue(&newValue);
|
|
if (result == NULL) goto noMemory;
|
|
if (sct->verbose != 0) {
|
|
dcon = SCStorePush(sct->debugConn);
|
|
SCPrintf(dcon, eWarning, "result: %s", GetCharArray(result));
|
|
SCStorePop(sct->debugConn);
|
|
}
|
|
SCWrite(con, GetCharArray(result), eValue);
|
|
DeleteDynString(result);
|
|
goto success;
|
|
case sct_steplist_keyword:
|
|
if (argc != 3) {
|
|
SCPrintf(con, eInError, "ERROR: should be: %s stepList <list>", argv[0]);
|
|
goto quit;
|
|
}
|
|
for (sl = sct->scriptLists.head; sl != NULL; sl = sl->next) {
|
|
if (strcasecmp(sl->name, argv[2]) == 0) {
|
|
SctSetListDirty(sl);
|
|
goto success;
|
|
}
|
|
|
|
}
|
|
goto missingScriptList;
|
|
case sct_chain_keyword:
|
|
if (argc < 4) {
|
|
SCPrintf(con, eInError, "ERROR: should be: %s chain <name> <script>", argv[0]);
|
|
goto quit;
|
|
}
|
|
for (sl = sct->scriptLists.head; sl != NULL; sl = sl->next) {
|
|
for (sc = sl->chains.head; sc != NULL; sc = sc->next) { /* don't touch the list pos */
|
|
if (sc->dynamic && strcasecmp(argv[2], sc->dynamic) == 0) {
|
|
if (sc->command) free(sc->command);
|
|
sc->command = ConcatArgs(argc - 3, argv + 3);
|
|
goto success;
|
|
}
|
|
}
|
|
}
|
|
SCPrintf(con, eInError, "ERROR: dynamic script %s not found", argv[2]);
|
|
goto quit;
|
|
case sct_next_keyword:
|
|
if (argc < 3) {
|
|
SCPrintf(con, eInError, "ERROR: should be: %s next <script>", argv[0]);
|
|
goto quit;
|
|
}
|
|
sc = sct->runningChain;
|
|
if (sc == NULL || sc->dynamic == NULL) goto notDynamic;
|
|
if (sc->command) free(sc->command);
|
|
sc->command = ConcatArgs(argc - 2, argv + 2);
|
|
sc->doit = 1;
|
|
break;
|
|
case sct_no_keyword:
|
|
SCPrintf(con, eInError, "ERROR: %s %s: unknown keyword", argv[0], argv[1]);
|
|
goto quit;
|
|
default:
|
|
SCPrintf(con, eInError, "ERROR: %s %s: untreated keyword", argv[0], argv[1]);
|
|
goto quit;
|
|
}
|
|
/* no OK message needed, as this command will never be called from a client */
|
|
success:
|
|
sct->operation = sct_no_keyword;
|
|
return 1;
|
|
noMemory:
|
|
SCWrite(con, "ERROR: no memory", eInError);
|
|
goto quit;
|
|
missingPar:
|
|
SCPrintf(con, eInError, "ERROR: parameter %s not found", argv[2]);
|
|
goto quit;
|
|
notDynamic:
|
|
SCPrintf(con, eInError, "ERROR: script is not dynamic");
|
|
goto quit;
|
|
missingScriptList:
|
|
SCPrintf(con, eInError, "ERROR: script list %s not found", argv[2]);
|
|
goto quit;
|
|
quit:
|
|
sct->operation = sct_no_keyword;
|
|
return 0;
|
|
}
|
|
|
|
static int SctWrapper(SConnection *con, SicsInterp *sics, void *object, int argc, char *argv[]) {
|
|
Sct *sct;
|
|
SctParData *data;
|
|
hdbValue val;
|
|
char *mode;
|
|
pDynString dyn;
|
|
pHdb node;
|
|
ErrMsg *msg;
|
|
|
|
typedef enum {
|
|
target_keywd,
|
|
no_keywd
|
|
} Keyword;
|
|
/* keywds must have the same order as Keyword */
|
|
static char *keywds[]={
|
|
"-t", /* show state and target value */
|
|
NULL
|
|
};
|
|
Keyword keywd;
|
|
|
|
if (argc < 2) {
|
|
return InvokeSICSOBJ(con, sics, object, argc, argv);
|
|
};
|
|
keywd = SctFindKeyword(argv[1], keywds);
|
|
sct = ((pSICSOBJ)object)->pPrivate;
|
|
switch (keywd) {
|
|
case no_keywd: return InvokeSICSOBJ(con, sics, object, argc, argv);
|
|
case target_keywd:
|
|
if (argc < 3) {
|
|
SCWrite(con, "ERROR: missing par", eInError);
|
|
return 0;
|
|
}
|
|
SctFindNode(sct->currentNode, argv[2], NULL, &node);
|
|
if (node == NULL) {
|
|
SCPrintf(con, eInError, "ERROR: %s %s not found", argv[0], argv[2]);
|
|
return 0;
|
|
}
|
|
sct->foundData = NULL;
|
|
GetHipadabaPar(node, &val, con);
|
|
data = sct->foundData;
|
|
if (data) {
|
|
if (data->pending) {
|
|
if (data->inprogress) {
|
|
mode = "inprogress pending";
|
|
} else {
|
|
mode = "pending";
|
|
}
|
|
cloneHdbValue(&data->target, &val);
|
|
} else {
|
|
if (data->inprogress) {
|
|
mode = "inprogress";
|
|
cloneHdbValue(&data->target, &val);
|
|
} else {
|
|
mode = "idle";
|
|
}
|
|
}
|
|
if (data->scriptChain && data->scriptChain->msg) {
|
|
msg = data->scriptChain->msg;
|
|
if (msg->data) {
|
|
SCPrintf(con, eInError, "ERROR:\n%s (%s)\n", msg->text, msg->data);
|
|
} else {
|
|
SCPrintf(con, eInError, "ERROR:\n%s\n", msg->text);
|
|
}
|
|
}
|
|
} else {
|
|
mode = "rdonly";
|
|
}
|
|
dyn = formatValue(val, node);
|
|
ReleaseHdbValue(&val);
|
|
SCPrintf(con, eValue, "%s %s", mode, GetCharArray(dyn));
|
|
DeleteDynString(dyn);
|
|
break;
|
|
default:
|
|
SCPrintf(con, eInError, "ERROR: %s %s: untreated keyword", argv[0], argv[1]);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static char *SctChainCmd(char *cmd) {
|
|
static char buf[512];
|
|
|
|
if (sct->runningChain && strcmp(sct->runningChain->command, cmd) != 0) {
|
|
snprintf(buf, sizeof buf, "chain: %s\ncmd : %s\n", sct->runningChain->command, cmd);
|
|
} else {
|
|
snprintf(buf, sizeof buf, "cmd : %s\n", cmd);
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
static char *SctCall(char *command) {
|
|
char *error;
|
|
Tcl_Interp *pTcl = InterpGetTcl(pServ->pSics);
|
|
int ret, l;
|
|
ErrMsg *msg;
|
|
SConnection *dcon;
|
|
|
|
if (sct->verbose != 0) {
|
|
dcon = SCStorePush(sct->debugConn);
|
|
SCPrintf(dcon, eInError, "script: %s\n", command);
|
|
SCStorePop(sct->debugConn);
|
|
}
|
|
l = strlen(command);
|
|
ret = Tcl_EvalEx(pTcl, command, l, 0);
|
|
error = (char *)Tcl_GetStringResult(pTcl);
|
|
if (ret != TCL_OK && error[0]!='\0') {
|
|
msg = ErrPutMsg(AsconGetErrList(sct->ascon), NULL,
|
|
"%serror: %s", SctChainCmd(command), error);
|
|
if (sct->runningChain) {
|
|
sct->runningChain->msg = msg;
|
|
}
|
|
return error;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static char *SctCallChain(SctChain *sc) {
|
|
sct->runningChain = sc;
|
|
sct->currentNode = sc->relatedNode;
|
|
sc->msg = NULL;
|
|
return SctCall(sc->command);
|
|
}
|
|
|
|
static void SctCallNext(void) {
|
|
char *cmd = sct->nextScript;
|
|
|
|
sct->nextScript = NULL;
|
|
if (SctCall(cmd) != NULL) {
|
|
if (sct->cmd) {
|
|
free(sct->cmd);
|
|
sct->cmd = NULL;
|
|
}
|
|
}
|
|
free(cmd);
|
|
}
|
|
|
|
static int SctTask(void *object) {
|
|
AsconStatus status;
|
|
char *response;
|
|
double period;
|
|
SctList *sl;
|
|
SctChain *sc;
|
|
SConnection *dcon = NULL;
|
|
|
|
if (sct) {
|
|
WriteToCommandLog("SCT>", "forbidden command (like wait) called in script");
|
|
goto quit;
|
|
}
|
|
sct = object;
|
|
if (sct->killObj) {
|
|
sct->taskSteps = 0;
|
|
sct = NULL;
|
|
return 0;
|
|
}
|
|
if (!sct->ascon) { /* no connection */
|
|
goto quit;
|
|
}
|
|
if (sct->taskSteps == 0) {
|
|
goto quit;
|
|
}
|
|
recycle:
|
|
status = AsconTask(sct->ascon);
|
|
if (status == AsconFailure) {
|
|
/* decide what to do on failure */
|
|
} else if (status != AsconReady) {
|
|
goto quit;
|
|
}
|
|
if (sct->taskSteps > 0) {
|
|
if (sct->taskSteps == 0) {
|
|
goto quit;
|
|
}
|
|
sct->taskSteps--;
|
|
}
|
|
response = AsconRead(sct->ascon);
|
|
if (response != NULL) {
|
|
if (sct->verbose != 0) {
|
|
if (dcon == NULL) dcon = SCStorePush(sct->debugConn);
|
|
SCPrintf(dcon, eWarning, "answer: %s", response);
|
|
}
|
|
if (sct->cmd) free(sct->cmd);
|
|
sct->cmd = NULL;
|
|
if (sct->sent) {
|
|
sct->sent = 0;
|
|
if (dcon == NULL) dcon = SCStorePush(sct->debugConn);
|
|
SCPrintf(dcon, eWarning, "response> %s", response);
|
|
free(sct->debugCommand);
|
|
sct->debugCommand = NULL;
|
|
goto recycle;
|
|
} else if (sct->nextScript) {
|
|
sct->result = strdup(response);
|
|
}
|
|
}
|
|
if (sct->debugCommand) {
|
|
if (sct->sent) {
|
|
if (dcon == NULL) dcon = SCStorePush(sct->debugConn);
|
|
SCPrintf(dcon, eWarning, "state %d", status);
|
|
goto quit;
|
|
}
|
|
sct->sent = 1;
|
|
if (sct->verbose != 0) {
|
|
if (dcon == NULL) dcon = SCStorePush(sct->debugConn);
|
|
SCPrintf(dcon, eWarning, "sent : %s", sct->debugCommand);
|
|
}
|
|
AsconWrite(sct->ascon, sct->debugCommand, 0);
|
|
goto recycle;
|
|
}
|
|
if (sct->nextScript) {
|
|
SctCallNext();
|
|
goto recycle;
|
|
}
|
|
for (sl = sct->scriptLists.head; sl != NULL; sl = sl->next) {
|
|
if (sl->type == set_type) {
|
|
if (sl->dirty) {
|
|
if (sl->beginScript && sl->beginScript->doit) {
|
|
sl->beginScript->doit = 0;
|
|
SctCallChain(sl->beginScript);
|
|
goto recycle;
|
|
}
|
|
sc = SctChainThis(&sl->chains);
|
|
if (sc != NULL) {
|
|
SctChainNext(&sl->chains);
|
|
SctCallChain(sc);
|
|
goto recycle;
|
|
}
|
|
/* look for pending scripts */
|
|
for (sc = SctChainFirst(&sl->chains); sc != NULL; sc = SctChainNext(&sl->chains)) {
|
|
if (sc->doit) break;
|
|
}
|
|
if (sc != NULL) {
|
|
SctChainNext(&sl->chains);
|
|
if (sl->type == set_type || sc->dynamic) sc->doit = 0;
|
|
SctCallChain(sc);
|
|
goto recycle; /* there are still pending scripts */
|
|
}
|
|
sl->dirty = 0;
|
|
SctChainFirst(&sl->chains);
|
|
if (sl->endScript) {
|
|
SctCallChain(sl->endScript);
|
|
goto recycle;
|
|
}
|
|
/* go to next scriptlist */
|
|
}
|
|
} else {
|
|
if (sl->type == timed_type) {
|
|
if (!sl->dirty) {
|
|
period = floor(DoubleTime() / sl->interval);
|
|
if (period != sl->lastPeriod) {
|
|
sl->lastPeriod = period;
|
|
SctSetListDirty(sl);
|
|
}
|
|
}
|
|
}
|
|
if (sl->dirty) {
|
|
if (sl->beginScript && sl->beginScript->doit) {
|
|
SctCallChain(sl->beginScript);
|
|
goto recycle;
|
|
}
|
|
sc = SctChainThis(&sl->chains);
|
|
if (sc != NULL) {
|
|
if (SctChainNext(&sl->chains) == NULL || sl->type == manual_type) {
|
|
sl->dirty = 0;
|
|
}
|
|
SctCallChain(sc);
|
|
goto recycle;
|
|
}
|
|
SctChainFirst(&sl->chains);
|
|
}
|
|
/* go to next scriptlist */
|
|
}
|
|
}
|
|
quit:
|
|
if (sct->debugConn) {
|
|
SCStorePop(sct->debugConn);
|
|
}
|
|
sct = NULL;
|
|
return 1;
|
|
}
|
|
|
|
static void SctKillChain(SctChain *sc) {
|
|
if (sc->command) free(sc->command);
|
|
if (sc->dynamic) free(sc->dynamic);
|
|
free(sc);
|
|
}
|
|
|
|
static void SctKillSL(SctList *sl) {
|
|
if (sl->name) free(sl->name);
|
|
if (sl->beginScript) SctKillChain(sl->beginScript);
|
|
if (sl->endScript) SctKillChain(sl->endScript);
|
|
SctChainDelete(&sl->chains, SctKillChain);
|
|
free(sl);
|
|
}
|
|
|
|
static void SctObjectNameKill(SctObjectName *onam) {
|
|
RemoveCommand(pServ->pSics, onam->name);
|
|
free(onam->name);
|
|
free(onam);
|
|
}
|
|
|
|
static void SctKill(Sct *sct) {
|
|
SctObjectNameDelete(&sct->names, SctObjectNameKill);
|
|
SctListDelete(&sct->scriptLists, SctKillSL);
|
|
if (sct->ascon) AsconKill(sct->ascon);
|
|
if (sct->name) free(sct->name);
|
|
if (sct->cmd) free(sct->cmd);
|
|
if (sct->result) free(sct->result);
|
|
if (sct->nextScript) free(sct->nextScript);
|
|
if (sct->debugCommand) free(sct->debugCommand);
|
|
if (sct->debugConn) SCStoreFree(sct->debugConn);
|
|
if (sct->desc) DeleteDescriptor(sct->desc);
|
|
free(sct);
|
|
}
|
|
|
|
/* kill sct only after SctKillTask _and_ SctKillObj were invoked */
|
|
|
|
static void SctKillTask(void *object) {
|
|
Sct *sct = object;
|
|
if (sct->killObj) {
|
|
SctKill(sct);
|
|
} else {
|
|
sct->killTask = 1;
|
|
}
|
|
}
|
|
|
|
static void SctKillObj(void *object) {
|
|
Sct *sct = object;
|
|
|
|
if (sct->killTask) {
|
|
SctKill(sct);
|
|
} else {
|
|
sct->killObj = 1;
|
|
}
|
|
}
|
|
|
|
int SctAddNode2Script(Sct *sct, SctChain *sc, pHdb node, SConnection *con) {
|
|
hdbValue val;
|
|
char path[MAX_HDB_PATH];
|
|
|
|
memset(&val,0,sizeof(hdbValue));
|
|
GetHipadabaPar(node, &val, con);
|
|
ReleaseHdbValue(&val);
|
|
if (!sct->foundData) {
|
|
SctGetPath(node, path, sizeof path);
|
|
SCPrintf(con, eError, "ERROR: %s has no script context data", path);
|
|
return 0;
|
|
}
|
|
if (sc->scriptList->type == set_type) {
|
|
sct->foundData->scriptChain = sc;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int SctAction(SConnection *con, SicsInterp *sics, void *object, int argc, char *argv[]) {
|
|
Sct *sct = object;
|
|
SctList *sl, *slItem;
|
|
SctChain *sc;
|
|
int type = 0, priv = -1;
|
|
SctParData *data;
|
|
pHdb node, parent;
|
|
pHdbCallback cb;
|
|
char *fmt;
|
|
char *name;
|
|
char path[MAX_HDB_PATH];
|
|
pSICSOBJ sicsobj;
|
|
int i;
|
|
ErrMsgList *list;
|
|
ErrMsg *msg;
|
|
time_t age;
|
|
char timetext[8];
|
|
double interval;
|
|
SctObjectName *objname;
|
|
hdbValue val;
|
|
|
|
typedef enum {
|
|
connect_keyword,
|
|
object_keyword,
|
|
make_keyword,
|
|
path_keyword,
|
|
addscript_keyword,
|
|
addmultiscript_keyword,
|
|
addnode_keyword,
|
|
dynscript_keyword,
|
|
scriptlist_keyword,
|
|
beginscript_keyword,
|
|
endscript_keyword,
|
|
interval_keyword,
|
|
debug_keyword,
|
|
send_keyword,
|
|
error_keyword,
|
|
no_keyword
|
|
} Keyword;
|
|
/* keywords must have the same order as Keyword */
|
|
static char *keywords[]={
|
|
"connect",
|
|
"object",
|
|
"make",
|
|
"path",
|
|
"addscript",
|
|
"addmultiscript",
|
|
"addnode",
|
|
"dynscript",
|
|
"scriptlist",
|
|
"beginscript",
|
|
"endscript",
|
|
"interval",
|
|
"debug",
|
|
"send",
|
|
"error",
|
|
NULL
|
|
};
|
|
Keyword keyword;
|
|
|
|
assert(sct);
|
|
if (argc < 2) {
|
|
SCPrintf(con, eError, "ERROR: missing %s subcommand", argv[0]);
|
|
goto quit;
|
|
};
|
|
keyword = SctFindKeyword(argv[1], keywords);
|
|
sct->operation = keyword;
|
|
switch (keyword) {
|
|
|
|
case object_keyword:
|
|
if (argc < 5) {
|
|
SCPrintf(con, eError, "ERROR: should be %s object <name> <priv> <type> [<fmt>]", argv[0]);
|
|
goto quit;
|
|
}
|
|
sicsobj = MakeSICSOBJ(argv[2], "SctSicsObject");
|
|
if (!sicsobj) goto noMemory;
|
|
sicsobj->pPrivate = sct;
|
|
sct->currentNode = sicsobj->pDes->parNode;
|
|
sicsobj->KillPrivate = NULL;
|
|
/*
|
|
sicsobj->pDes->saveStatus = SctSave;
|
|
dynamic?
|
|
*/
|
|
if (!AddCommand(pServ->pSics, argv[2], SctWrapper, KillSICSOBJ, sicsobj)) {
|
|
SCPrintf(con, eError, "%s already exists", argv[2]);
|
|
goto quit;
|
|
}
|
|
objname = calloc(1, sizeof(*objname));
|
|
objname->name = strdup(argv[2]);
|
|
SctObjectNameAdd(&sct->names, objname);
|
|
/* fall through */
|
|
|
|
case make_keyword:
|
|
if (argc < 5) {
|
|
SCPrintf(con, eError, "ERROR: should be %s make <par> <priv> <type> [<fmt>]", argv[0]);
|
|
goto quit;
|
|
}
|
|
|
|
fmt = NULL;
|
|
priv = decodeSICSPriv(argv[3]);
|
|
if (strcasecmp(argv[4], "int") == 0) {
|
|
type = HIPINT;
|
|
} else if (strcasecmp(argv[4], "float") == 0) {
|
|
type = HIPFLOAT;
|
|
if (argc == 6) {
|
|
fmt = argv[5];
|
|
} else {
|
|
fmt = "%.5g";
|
|
}
|
|
} else if (strcasecmp(argv[4], "text") == 0) {
|
|
type = HIPTEXT;
|
|
} else if (strcasecmp(argv[4], "none") == 0) {
|
|
type = HIPNONE;
|
|
} else {
|
|
SCWrite(con,
|
|
"ERROR: invalid type requested: none, int, float, text supported", eError);
|
|
goto quit;
|
|
}
|
|
|
|
if (keyword == make_keyword) { /* make parameter case */
|
|
name = SctFindNode(sct->currentNode, argv[2], &parent, &node);
|
|
if (node != NULL) goto nodeExists;
|
|
if (name == NULL) goto quit;
|
|
if (type != HIPNONE){
|
|
val = makeHdbValue(type,0);
|
|
node = MakeSICSHdbPar(name, priv, val);
|
|
ReleaseHdbValue(&val);
|
|
} else {
|
|
node = MakeHipadabaNode(name, type, 0);
|
|
}
|
|
if (node == NULL) goto noMemory;
|
|
AddHipadabaChild(parent, node, con);
|
|
} else { /* make object case */
|
|
name = argv[2];
|
|
node = sct->currentNode;
|
|
}
|
|
|
|
data = calloc(1, sizeof(*data));
|
|
if (node == NULL || data == NULL) goto noMemory;
|
|
data->pending = 0;
|
|
data->inprogress = 0;
|
|
data->sct = sct;
|
|
data->scriptChain = NULL;
|
|
data->conCtx = NULL;
|
|
data->refCnt = 3; /* insert 3 times */
|
|
cloneHdbValue(&node->value, &data->target);
|
|
if (fmt) {
|
|
SetHdbProperty(node, "fmt", fmt);
|
|
}
|
|
|
|
cb = MakeHipadabaCallback(SctUpdateCallback, data, SctFreeParData, -1, sct);
|
|
if (cb == NULL) goto noMemory;
|
|
AppendHipadabaCallback(node, HCBUPDATE, cb);
|
|
|
|
cb = MakeHipadabaCallback(SctSetCallback, data, SctFreeParData, -1, sct);
|
|
if (cb == NULL) goto noMemory;
|
|
AppendHipadabaCallback(node, HCBSET, cb);
|
|
|
|
cb = MakeHipadabaCallback(SctReadCallback, data, SctFreeParData, -1, sct);
|
|
if (cb == NULL) goto noMemory;
|
|
AppendHipadabaCallback(node, HCBREAD, cb);
|
|
|
|
break;
|
|
|
|
case dynscript_keyword:
|
|
if (argc < 4) {
|
|
SCPrintf(con, eError, "ERROR: should be %s %s <list> <name>", argv[0], argv[1]);
|
|
goto quit;
|
|
}
|
|
/* fall through */
|
|
|
|
case addmultiscript_keyword:
|
|
|
|
case addscript_keyword:
|
|
if (argc < 5) {
|
|
SCPrintf(con, eError, "ERROR: should be %s %s <list> <par> <script ...>", argv[0], argv[1]);
|
|
goto quit;
|
|
}
|
|
if (keyword == dynscript_keyword) {
|
|
node = NULL;
|
|
} else {
|
|
SctFindNode(sct->currentNode, argv[3], &parent, &node);
|
|
if (node == NULL) {
|
|
name = argv[3];
|
|
goto nodeNotFound;
|
|
}
|
|
}
|
|
for (sl = SctListFirst(&sct->scriptLists); sl != NULL; sl = SctListNext(&sct->scriptLists)) {
|
|
if (strcasecmp(sl->name, argv[2]) == 0) {
|
|
if (keyword == dynscript_keyword) {
|
|
if (sl->type == set_type) {
|
|
SCPrintf(con, eError, "ERROR: dynscripts may not be added to a set type list");
|
|
goto quit;
|
|
}
|
|
node = sct->currentNode;
|
|
}
|
|
if (argc == 4) { /* take last script */
|
|
sc = SctChainThis(&sl->chains);
|
|
if (sc == NULL) {
|
|
SCPrintf(con, eError, "ERROR: script list is empty");
|
|
goto quit;
|
|
}
|
|
} else {
|
|
sc = SctMakeChain(ConcatArgs(argc-4, argv+4));
|
|
if (sc == NULL) goto noMemory;
|
|
if (node) {
|
|
sc->relatedNode = node;
|
|
} else {
|
|
sc->relatedNode = sct->currentNode;
|
|
}
|
|
sc->scriptList = sl;
|
|
if (keyword == dynscript_keyword) {
|
|
sc->dynamic = strdup(argv[3]);
|
|
}
|
|
SctChainAdd(&sl->chains, sc);
|
|
}
|
|
sct->foundData = NULL;
|
|
if (node && keyword == addscript_keyword) {
|
|
if (!SctAddNode2Script(sct, sc, node, con)) goto quit;
|
|
}
|
|
if (sl->type != set_type) {
|
|
sc->doit = 1;
|
|
}
|
|
/* the current script chain and script list is stored in the position of the Lists,
|
|
this is important for the addnode command */
|
|
goto success;
|
|
}
|
|
}
|
|
goto missingScriptList;
|
|
|
|
case addnode_keyword:
|
|
if (argc != 3) {
|
|
SCPrintf(con, eError, "ERROR: should be %s %s <par>", argv[0], argv[1]);
|
|
goto quit;
|
|
}
|
|
sl = SctListThis(&sct->scriptLists);
|
|
if (sl == NULL) {
|
|
sc = NULL;
|
|
} else {
|
|
sc = SctChainThis(&sl->chains);
|
|
}
|
|
if (sc == NULL) {
|
|
SCPrintf(con, eError, "ERROR: no script was specified");
|
|
goto quit;
|
|
}
|
|
SctFindNode(sct->currentNode, argv[2], &parent, &node);
|
|
if (node == NULL) {
|
|
name = argv[2];
|
|
goto nodeNotFound;
|
|
}
|
|
if (!SctAddNode2Script(sct, sc, node, con)) goto quit;
|
|
goto success;
|
|
|
|
case scriptlist_keyword:
|
|
if (argc < 4) {
|
|
type == no_type;
|
|
} else {
|
|
type = SctFindKeyword(argv[2], slTypes);
|
|
}
|
|
if (type == no_type) {
|
|
SCPrintf(con, eError, "ERROR: should be %s scriptList [set|timed|manual] <list>", argv[0]);
|
|
goto quit;
|
|
}
|
|
|
|
for (sl = sct->scriptLists.head; sl != NULL; sl = sl->next) {
|
|
if (strcasecmp(sl->name, argv[2]) == 0) goto scriptListExists;
|
|
}
|
|
sl = calloc(1, sizeof(*sl));
|
|
if (sl == NULL) goto noMemory;
|
|
sl->name = strdup(argv[3]);
|
|
sl->type = type;
|
|
sl->beginScript = NULL;
|
|
sl->endScript = NULL;
|
|
sl->lastPeriod = 0.0;
|
|
sl->lastScript = NULL;
|
|
sl->chains.head = NULL;
|
|
sl->interval = 1e-6;
|
|
sl->dirty = (type == timed_type);
|
|
SctListAdd(&sct->scriptLists, sl);
|
|
break;
|
|
|
|
case interval_keyword:
|
|
if (argc < 3) {
|
|
SCPrintf(con, eError, "ERROR: should be %s interval <list> [<value>]", argv[0]);
|
|
goto quit;
|
|
}
|
|
for (sl = sct->scriptLists.head; sl != NULL; sl = sl->next) {
|
|
if (strcasecmp(sl->name, argv[2]) == 0) break;
|
|
}
|
|
if (sl == NULL) goto scriptListNotFound;
|
|
if (argc > 3) {
|
|
interval = atof(argv[3]);
|
|
if (interval < 1e-6) {
|
|
sl->interval = 1e-6;
|
|
interval = 0;
|
|
} else {
|
|
sl->interval = interval;
|
|
}
|
|
} else {
|
|
interval = sl->interval;
|
|
if (interval <= 1.001e-6) {
|
|
interval = 0;
|
|
}
|
|
}
|
|
SCPrintf(con, eValue, "%s %s = %.5g (sec)", argv[0], argv[1], sl->interval);
|
|
return 1;
|
|
|
|
case beginscript_keyword:
|
|
|
|
case endscript_keyword:
|
|
if (argc < 4) {
|
|
SCPrintf(con, eError, "ERROR: should be %s %s <list> <script>", argv[0], argv[1]);
|
|
goto quit;
|
|
}
|
|
for (sl = sct->scriptLists.head; sl != NULL; sl = sl->next) {
|
|
if (strcasecmp(sl->name, argv[2]) == 0) break;
|
|
}
|
|
if (sl == NULL) goto scriptListNotFound;
|
|
sc = SctMakeChain(ConcatArgs(argc-3, argv+3));
|
|
sc->relatedNode = sct->currentNode;
|
|
sc->scriptList = sl;
|
|
if (keyword == beginscript_keyword) {
|
|
sl->beginScript = sc;
|
|
} else {
|
|
sl->endScript = sc;
|
|
}
|
|
break;
|
|
|
|
case connect_keyword:
|
|
if (argc < 3) {
|
|
SCPrintf(con, eError, "ERROR: should be %s connect <protocol> <host:port> ...", argv[0]);
|
|
goto quit;
|
|
}
|
|
if (sct->ascon) AsconKill(sct->ascon);
|
|
sct->ascon = AsconMake(con, argc - 2, argv + 2);
|
|
if (!sct->ascon) goto quit;
|
|
break;
|
|
|
|
case path_keyword:
|
|
if (argc > 3) {
|
|
SCPrintf(con, eError, "ERROR: should be %s path [<path>]", argv[0]);
|
|
goto quit;
|
|
}
|
|
if (argc == 3) {
|
|
SctFindNode(sct->currentNode, argv[2], &parent, &node);
|
|
if (node == NULL) {
|
|
name = argv[2];
|
|
goto nodeNotFound;
|
|
}
|
|
}
|
|
if (!SctGetPath(sct->currentNode, path, sizeof path)) {
|
|
SCWrite(con, "ERROR: node not anchored or path name too long", eError);
|
|
goto quit;
|
|
}
|
|
SCWrite(con, path, eValue);
|
|
goto success;
|
|
|
|
case debug_keyword:
|
|
if (argc < 2) {
|
|
SCPrintf(con, eError, "ERROR: should be %s debug [0 | <steps>]", argv[0]);
|
|
goto quit;
|
|
}
|
|
if (argc < 3) {
|
|
i = 1;
|
|
} else {
|
|
i = atoi(argv[2]);
|
|
}
|
|
if (i != 0) {
|
|
sct->taskSteps = i;
|
|
sct->debugConn = SCSave(con, sct->debugConn);
|
|
sct->verbose = 1;
|
|
while (sct->taskSteps > 0) {
|
|
SctTask(sct);
|
|
}
|
|
return 1;
|
|
} else {
|
|
sct->taskSteps = -1;
|
|
sct->verbose = 0;
|
|
}
|
|
break;
|
|
|
|
case error_keyword:
|
|
list = AsconGetErrList(sct->ascon);
|
|
for (msg = ErrMsgFirst(list); msg != NULL; msg = msg->next) {
|
|
age = time(NULL) - msg->last;
|
|
if (age < 3600) {
|
|
snprintf(timetext, sizeof timetext, "%2ldm%2.2lds", age/60, age % 60);
|
|
} else if (age < 99*3600) {
|
|
age = age / 60;
|
|
snprintf(timetext, sizeof timetext, "%2ldh%2.2ldm", age/60, age % 60);
|
|
} else {
|
|
snprintf(timetext, sizeof timetext, "%5ldh", age/(24*3600));
|
|
}
|
|
if (msg->data) {
|
|
SCPrintf(con, eError, "--- %s ago, cnt %5d %s", timetext, msg->cnt, msg->data);
|
|
} else {
|
|
SCPrintf(con, eError, "--- %s ago, cnt %5d", timetext, msg->cnt, msg->data);
|
|
}
|
|
SCWrite(con, msg->text, eError);
|
|
}
|
|
return 1;
|
|
|
|
case send_keyword:
|
|
if (argc < 3) {
|
|
SCPrintf(con, eError, "ERROR: should be %s send <command>", argv[0]);
|
|
goto quit;
|
|
}
|
|
if (sct->debugCommand != NULL) {
|
|
SCPrintf(con, eError, "ERROR: busy");
|
|
goto quit;
|
|
}
|
|
sct->sent = 0;
|
|
sct->debugConn = SCSave(con, sct->debugConn);
|
|
sct->debugCommand = ConcatArgs(argc - 2, argv + 2);
|
|
goto success;
|
|
|
|
case no_keyword:
|
|
SCPrintf(con, eError, "ERROR: %s %s: unknown keyword", argv[0], argv[1]);
|
|
goto quit;
|
|
|
|
default:
|
|
SCPrintf(con, eError, "ERROR: %s %s: untreated keyword", argv[0], argv[1]);
|
|
goto quit;
|
|
}
|
|
SCSendOK(con);
|
|
success:
|
|
sct->operation = sct_no_keyword;
|
|
return 1;
|
|
noMemory:
|
|
SCWrite(con, "ERROR: no memory", eError);
|
|
goto quit;
|
|
missingScriptList:
|
|
SCPrintf(con, eError, "ERROR: script list %s not found", argv[2]);
|
|
goto quit;
|
|
scriptListExists:
|
|
SCWrite(con, "ERROR: script list exists", eError);
|
|
goto quit;
|
|
nodeExists:
|
|
SCPrintf(con, eError, "ERROR: node %s exists", argv[2]);
|
|
goto quit;
|
|
nodeNotFound:
|
|
SCPrintf(con, eError, "ERROR: node %s not found", name);
|
|
goto quit;
|
|
scriptListNotFound:
|
|
SCPrintf(con, eError, "ERROR: script list %s not found", argv[2]);
|
|
goto quit;
|
|
quit:
|
|
sct->operation = sct_no_keyword;
|
|
return 0;
|
|
}
|
|
|
|
static int SctInit(SConnection *con, int argc, char *argv[], int dynamic) {
|
|
/* syntax: makeobject <name> sct */
|
|
|
|
if (sct) {
|
|
SCPrintf(con, eError, "ERROR: script context busy");
|
|
return 0;
|
|
}
|
|
|
|
if (argc != 3) {
|
|
SCPrintf(con, eError, "ERROR: should be: makeobject <name> sct");
|
|
return 0;
|
|
}
|
|
|
|
sct = calloc(1,sizeof(*sct));
|
|
assert(sct);
|
|
sct->desc = CreateDescriptor("sct");
|
|
assert(sct->desc);
|
|
sct->scriptLists.head = NULL;
|
|
sct->cmd = NULL;
|
|
sct->result = NULL;
|
|
sct->nextScript = NULL;
|
|
sct->runningChain = NULL;
|
|
sct->debugConn = NULL;
|
|
sct->debugCommand = NULL;
|
|
sct->verbose = 0;
|
|
sct->taskSteps = -1;
|
|
sct->name = strdup(argv[1]);
|
|
if (!AddCommand(pServ->pSics, argv[1], SctAction, SctKillObj, sct)) {
|
|
SCPrintf(con, eError, "%s already exists", argv[1]);
|
|
SctKill(sct);
|
|
goto quit;
|
|
}
|
|
TaskRegister(pServ->pTasker, SctTask, NULL, SctKillTask, sct, 0);
|
|
sct->killObj = 0;
|
|
sct->killTask = 0;
|
|
sct = NULL;
|
|
return 1;
|
|
quit:
|
|
sct = NULL;
|
|
return 0;
|
|
}
|
|
|
|
/** \brief the startup routine */
|
|
void SctStartup(void) {
|
|
MakeDriver("sct", SctInit, 0, "Script Context Driver");
|
|
AddCmd("sct", SctExec);
|
|
}
|