/*----------------------------------------------------------------------- remob.c implements remote driveable objects living on an other sics server M. Zolliker July 04 ------------------------------------------------------------------------*/ #include #include #include #include #include #include "fortify.h" #include "sics.h" #include "devexec.h" #include "remob.h" #include "splitter.h" #include "status.h" #include "site.h" /*-------------------------------------------------------------------------*/ #define INTERRUPTMODE 0 #define ACCESSCODE 1 /*------------------------------------------------------------------------ */ typedef struct Remob Remob; typedef struct RemChannel { mkChannel *chan; int timeout; int incomplete; char line[1024]; } RemChannel; typedef struct RemServer { pObjectDescriptor desc; char *name; char *host; int port; RemChannel rc[2]; Remob *objList; int matchMap; int taskActive; int interestActive; int forwardMessages; SConnection *conn; } RemServer; struct Remob { pObjectDescriptor desc; char *name; pIDrivable pDrivInt; pICallBack pCall; RemServer *server; int status; Remob *next; int markForDel; }; typedef struct { float fVal; char *pName; } RemobCallback; typedef struct { char *pName; SConnection *pCon; } RemobInfo; /*-------------------------------------------------------------------------*/ static char *StartsWith(char *line, char *name) { /* if line does not start with name, return NULL else return a pointer to the next non-white space character */ char *str; int l; l = strlen(name); if (0 != strncmp(line, name, l)) return NULL; str = line + l; while (*str == ' ') { str++; } return str; } /*-------------------------------------------------------------------------*/ static int RemWrite(RemChannel * rc, char *line) { int iret; if (rc->chan) { /* printf("> %s\n", line); */ iret = NETWrite(rc->chan, line, strlen(line)); if (iret == 0) iret = -1; return iret; } else { return -1; } } /*-------------------------------------------------------------------------*/ static int RemRead(RemChannel * rc, long tmo) { int iRet; if (rc->chan == NULL) return 0; /* no data */ iRet = NETReadTillTerm(rc->chan, tmo, "\n", rc->line + rc->incomplete, sizeof(rc->line) - rc->incomplete); if (iRet == 0) { rc->incomplete = strlen(rc->line); /* number of chars already received */ return 0; /* timeout */ } else { rc->incomplete = 0; } return iRet; } /*-------------------------------------------------------------------------*/ static int RemHandle(RemServer * remserver) { char *line, *par, *str; Remob *remob; RemChannel *rc; rc = &remserver->rc[0]; /* drivstat messages appear only on the spy channel */ /* skip whitespace at the beginning */ line = rc->line; if (line[0] == '\0') return 0; /* return when line is empty */ while (*line < ' ' && *line != '\0') { line++; } memmove(rc->line, line, strlen(line)); /* handle drivstat messages */ line = rc->line; for (remob = remserver->objList; remob != NULL; remob = remob->next) { par = StartsWith(line, remob->name); if (par != NULL) { if ((str = StartsWith(par, "finished"))) { if (*str == '\0') { remob->status = HWIdle; } else { remob->status = HWFault; } line[0] = '\0'; return 1; } if ((str = StartsWith(par, "started"))) { remob->status = HWBusy; line[0] = '\0'; return 1; } } } return 0; } /*-------------------------------------------------------------------------*/ static void RemCopy(RemChannel * rc, SConnection * pCon) { if (pCon != NULL && rc->line[0] != '\0') { SCPrintf(pCon, eValue, " %s", rc->line); } } /*-------------------------------------------------------------------------*/ static void RemDisconnect(RemServer * remserver) { int isUser; RemChannel *rc; for (isUser = 0; isUser <= 1; isUser++) { rc = &remserver->rc[isUser]; if (rc->chan != NULL) { NETClosePort(rc->chan); free(rc->chan); rc->chan = NULL; /* printf("disconnected\n"); */ } } } /*-------------------------------------------------------------------------*/ static int RemSetInterest(RemChannel * rc) { int iRet; if (rc->chan != NULL) { /* already connected */ iRet = RemWrite(rc, "transact listexe interest\n"); if (iRet >= 0) { iRet = RemRead(rc, 1000); while (iRet > 0) { /* eat response */ if (StartsWith(rc->line, "TRANSACTIONFINISHED")) { return 1; } iRet = RemRead(rc, 1000); } } } return 0; } /*-------------------------------------------------------------------------*/ static void RemConnect(RemServer * remserver, int both) { /* open channel 0 or both channels, if not yet opened */ int iRet; mkChannel *chan; int i; RemChannel *rc; for (i = 0; i <= both; i++) { rc = &remserver->rc[i]; if (!rc->chan) { rc->timeout = 0; chan = NETConnect(remserver->host, remserver->port); if (!chan) { return; } rc->chan = chan; if (i != 0) { /* open the user channel */ iRet = RemWrite(rc, "remuser sesam\n"); } else { /* open spy channel */ iRet = RemWrite(rc, "Spy 007\n"); } if (iRet < 0) goto close; iRet = RemRead(rc, 1000); while (iRet > 0) { /* eat login response */ if (StartsWith(rc->line, "Login OK")) { /* printf("connected\n"); */ if (remserver->interestActive && rc == &remserver->rc[0]) { /* open the user channel */ if (!RemSetInterest(rc)) goto close; } break; } iRet = RemRead(rc, 1000); } if (iRet <= 0) goto close; } } return; close: RemDisconnect(remserver); return; } /*-------------------------------------------------------------------------*/ static int RemServerTask(void *data) { RemServer *remserver = data; int iRet; SConnection *pCon; int isUser; RemChannel *rc; if (!remserver->taskActive) return 0; /* remove task */ for (isUser = 0; isUser <= 1; isUser++) { rc = &remserver->rc[isUser]; if (RemRead(rc, 0) <= 0) continue; if (strstr(rc->line, " ") == rc->line) { Log(ERROR,"sys","%s:%s","REMOB", "infinite echo loop detected"); continue; } if (isUser == 0) { if (RemHandle(remserver)) { /* handle drivstat messages */ continue; } } if (remserver->forwardMessages) { /* forward all other messages */ if (SCisConnected(remserver->conn)) { RemCopy(rc, remserver->conn); } } } return 1; } /*-------------------------------------------------------------------------*/ static int RemTransact(RemServer * remserver, int nChan, SConnection * pCon, char *cmd, ...) { /* the variable arguments are for filtering: "" write untreated lines to pCon */ char *buffer; int bufferLen; int iRet; char *arg, *val, *endp; float *f; va_list ap; int try; int argMask; RemChannel *rc = &remserver->rc[nChan]; pDynString errorResult; try = 3; if (rc->timeout) { /* eat old responses */ while (RemRead(rc, 0) > 0) { RemHandle(remserver); } } tryagain: bufferLen = strlen(cmd) + 16; buffer = malloc(bufferLen); if (buffer == NULL) { SCPrintf(pCon, eError, "ERROR: can not get another %d bytes", bufferLen); return 0; } snprintf(buffer, bufferLen, "transact %s\n", cmd); RemConnect(remserver, nChan); iRet = RemWrite(rc, buffer); free(buffer); if (iRet < 0) goto close; iRet = RemRead(rc, 2000); if (iRet <= 0) goto close; while (!StartsWith(rc->line, "TRANSACTIONFINISHED")) { if (StartsWith(rc->line, "ERROR:")) { errorResult = CreateDynString(60, 64); do { RemHandle(remserver); DynStringConcat(errorResult, rc->line); DynStringConcat(errorResult, "\n"); iRet = RemRead(rc, 2000); } while (!StartsWith(rc->line, "TRANSACTIONFINISHED")); if (pCon != NULL) { SCPrintf(pCon, eError, "ERROR: in %s:\n%s", remserver->name, GetCharArray(errorResult)); } DeleteDynString(errorResult); return -2; } RemHandle(remserver); va_start(ap, cmd); arg = va_arg(ap, char *); argMask = 1; remserver->matchMap = 0; while (arg != NULL) { if (*arg == '>') { RemCopy(rc, pCon); } else if (*arg == '<') { f = va_arg(ap, float *); val = StartsWith(rc->line, arg + 1); if (val != NULL) { val = StartsWith(val, "="); if (val != NULL) { *f = strtod(val, &endp); break; } } } else if (*arg == '!') { if (StartsWith(rc->line, arg + 1)) { remserver->matchMap |= argMask; argMask = argMask * 2; break; } } else { printf("unknown argument in RemTransact: %s\n", arg); assert(0); } arg = va_arg(ap, char *); } va_end(ap); iRet = RemRead(rc, 2000); if (iRet <= 0) goto close; } return 1; close: if (iRet == 0) { if (try == 1) { SCPrintf(pCon, eError, "ERROR: timeout on %s", remserver->name); rc->timeout = 1; return iRet; } else { SCPrintf(pCon, eError, "WARNING: timeout on %s", remserver->name); } } RemDisconnect(remserver); try--; if (try > 0) goto tryagain; SCPrintf(pCon, eError, "ERROR: no connection to %s", remserver->name); return iRet; } /*-------------------------------------------------------------------------*/ static void *RemobGetInterface(void *pData, int iID) { Remob *self = pData; assert(self); if (iID == DRIVEID) { return self->pDrivInt; } else if (iID == CALLBACKINTERFACE) { return self->pCall; } return NULL; } /*------------------------------------------------------------------------*/ static int RemobHalt(void *self) { Remob *remob = self; RemServer *remserver = remob->server; RemChannel *rc = &remserver->rc[1]; /* Halt is only called with at least user priv. */ char buf[64]; assert(remob); RemConnect(remserver, 1); snprintf(buf, sizeof(buf), "stopexe %s\n", remob->name); remob->status = HWFault; return RemWrite(rc, buf); } /*--------------------------------------------------------------------------*/ static int RemobLimits(void *self, float fVal, char *error, int iErrLen) { float fHard; Remob *remob = self; assert(remob); /* check is done on remote server */ return 1; } /*---------------------------------------------------------------------------*/ static float RemobGetValue(void *pData, SConnection * pCon) { Remob *remob = pData; RemServer *remserver = remob->server; char buf[80]; float none, value; int iRet; assert(remob); if (remserver->conn != NULL) { SCDeleteConnection(remserver->conn); } remserver->conn = SCCopyConnection(pCon); none = -1.234e32; value = none; snprintf(buf, sizeof(buf), "<%s", remob->name); /* get value needs only spy priviledge */ iRet = RemTransact(remserver, 0, pCon, remob->name, buf, &value, ">", NULL); /* if (iRet <= 0) { return 0.0; } */ if (value != none) { return value; } snprintf(buf, sizeof(buf), "can not get %s", remob->name); SCWrite(pCon, buf, eWarning); return 0.0; } /*------------------------------------------------------------------------*/ static int RemobSaveStatus(void *pData, char *name, FILE * fil) { Remob *self = pData; assert(self); assert(fil); /* data is stored on remote server */ return 1; } /*------------------------------------------------------------------------*/ static int RemServerSaveStatus(void *pData, char *name, FILE * fil) { RemServer *remserver = pData; Remob *remob; assert(remserver); assert(fil); for (remob = remserver->objList; remob != NULL; remob = remob->next) { if (remob->pDrivInt) { fprintf(fil, "catch { remob drv %s %s }\n", remob->name, remserver->name); } else { fprintf(fil, "catch { remob obj %s %s }\n", remob->name, remserver->name); } } return 1; } /*------------------------------------------------------------------------*/ static int RemobStatus(void *pData, SConnection * pCon) { Remob *remob = pData; assert(remob); if (remob->server->conn != NULL) { SCDeleteConnection(remob->server->conn); } remob->server->conn = SCCopyConnection(pCon); return remob->status; } /*---------------------------------------------------------------------------*/ static long RemobRun(void *self, SConnection * pCon, float fNew) { Remob *remob = self; float fHard; int i, iRet, iCode; char buf[512], sBuf[64]; char pError[132]; Remob *p; RemServer *remserver; long lTime; float fDelta; int rights; RemChannel *rc; int nChan; assert(remob); assert(pCon); remserver = remob->server; if (remserver->conn != NULL) { SCDeleteConnection(remserver->conn); } remserver->conn = SCCopyConnection(pCon); rights = SCGetRights(pCon); nChan = rights <= usUser; rc = &remserver->rc[nChan]; RemConnect(remserver, 0); /* connect spy for listexe interest */ remob->status = HWIdle; snprintf(buf, sizeof(buf), "run %s %g", remob->name, fNew); iRet = RemTransact(remserver, nChan, pCon, buf, "!ERROR: somebody else", "!ERROR: cannot", ">", NULL); if (iRet <= 0) return 0; if (remserver->matchMap & 1) { /* already running, stop first */ remob->status = HWBusy; snprintf(sBuf, sizeof(sBuf), "stopexe %s", remob->name); iRet = RemTransact(remserver, nChan, pCon, sBuf, ">", NULL); if (iRet <= 0) return 0; while (remob->status == HWBusy) { iRet = RemRead(rc, 1000); if (iRet <= 0) break; if (!RemHandle(remserver)) { RemCopy(rc, pCon); } } iRet = RemTransact(remserver, nChan, pCon, buf, ">", NULL); if (iRet <= 0) return 0; } /* wait for "started" message */ while (remob->status != HWBusy) { iRet = RemRead(&remserver->rc[0], 1000); if (iRet <= 0) break; if (!RemHandle(remserver)) { RemCopy(&remserver->rc[0], pCon); } } if (remob->status != HWBusy) { return 0; } return OKOK; } /*-----------------------------------------------------------------------*/ static void KillInfo(void *pData) { RemobInfo *self = pData; assert(self); if (self->pName) { free(self->pName); } if (self->pCon) { SCDeleteConnection(self->pCon); } free(self); } /*------------------- The CallBack function for interest ------------------*/ static int InterestCallback(int iEvent, void *pEvent, void *pUser) { RemobCallback *psCall = pEvent; RemobInfo *pInfo = pUser; char buf[80]; assert(psCall); assert(pInfo); snprintf(buf, sizeof(buf), "%s.position = %g ", pInfo->pName, psCall->fVal); SCWrite(pInfo->pCon, buf, eEvent); return 1; } /*---------------------------------------------------------------------------*/ int RemobAction(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { Remob *remob = pData; RemServer *remserver = remob->server; char buf[512]; TokenList *pList = NULL; TokenList *pCurrent; TokenList *pName; int iRet; int i; int pos; float fValue; long lID; char *endp; char *cmd; /* char acce[128], inte[128]; */ int rights; int nChan; RemChannel *rc; assert(pCon); assert(pSics); assert(remob); rights = SCGetRights(pCon); nChan = (rights <= usUser); rc = &remserver->rc[nChan]; if (rights >= usUser) { if (remserver->conn != NULL) { SCDeleteConnection(remserver->conn); } remserver->conn = SCCopyConnection(pCon); } if (argc == 1) { /* filter out time stamps !=== */ iRet = RemTransact(remserver, nChan, pCon, remob->name, "!===", ">", NULL); if (iRet < 0) { iRet = 0; } else { iRet = 1; } } else if (strcasecmp(argv[1], "interest") == 0) { /* ignore interest commands, as they would not work properly */ iRet = 1; } else if (strcasecmp(argv[1], "list") == 0) { /* snprintf(acce, sizeof(acce), "!%s.accesscode", remob->name); snprintf(inte, sizeof(inte), "!%s.interruptmode", remob->name); */ cmd = Arg2Tcl0(argc - 1, argv + 1, buf, sizeof buf, remob->name); if (cmd) { /* filter out time stamps !=== */ RemTransact(remserver, nChan, pCon, cmd, "!===", ">", NULL); if (cmd != buf) free(cmd); } iRet = 1; } else { pos = snprintf(buf, sizeof(buf), "%s ", remob->name); for (i = 1; i < argc; i++) { pos += snprintf(buf + pos, sizeof(buf) - pos, "%s ", argv[i]); } iRet = RemTransact(remserver, nChan, pCon, buf, ">", NULL); } return iRet; } /*--------------------------------------------------------------------------*/ static void RemobKill(void *self) { Remob *remob = self; Remob *p, **last; assert(remob); /* remove from object list */ if (remob->server) { last = &remob->server->objList; p = *last; while (p != remob && p != NULL) { last = &p->next; p = p->next; } if (p != NULL) { *last = p->next; } remob->next = NULL; } if (remob->name) { free(remob->name); } if (remob->pDrivInt) { free(remob->pDrivInt); } if (remob->pCall) { DeleteCallBackInterface(remob->pCall); } /* kill Descriptor */ if (remob->desc) { DeleteDescriptor(remob->desc); } free(remob); } /*---------------------------------------------------------------------------*/ int RemServerAction(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { RemServer *remserver = pData; TokenList *pList = NULL; TokenList *pCurrent; TokenList *pName; int iRet; socklen_t i; int pos; float fValue; long lID; char *endp, *serverport, *thishostname; struct sockaddr_in adr; struct hostent *thishost; Remob *p, *next; int rights, nChan; RemChannel *rc; char *args; assert(pCon); assert(pSics); assert(remserver); rights = SCGetRights(pCon); nChan = (rights <= usUser); rc = &remserver->rc[nChan]; if (nChan) { if (remserver->conn != NULL) { SCDeleteConnection(remserver->conn); } remserver->conn = SCCopyConnection(pCon); } if (argc == 1) { serverport = IFindOption(pSICSOptions, "ServerPort"); i = sizeof adr; thishostname = NULL; if (rc->chan) { if (getsockname(rc->chan->sockid, (void *) &adr, &i) >= 0) { thishost = gethostbyaddr((char *) &adr.sin_addr, sizeof adr.sin_addr, AF_INET); if (thishost) { thishostname = thishost->h_name; } } } if (thishostname == NULL) thishostname = "undef"; SCPrintf(pCon, eValue, "%s = %s:%d %s:%s", argv[0], remserver->host, remserver->port, thishostname, serverport); } else if (argc > 2 && strcasecmp(argv[1], "nowait") == 0) { RemConnect(remserver, nChan); args = Arg2Tcl(argc - 2, argv + 2, NULL, 0); RemWrite(rc, args); RemWrite(rc, "\n"); free(args); } else if (argc == 2 && strcasecmp(argv[1], "markForDel") == 0) { p = remserver->objList; while (p) { p->markForDel = 1; p = p->next; } } else if (argc == 2 && strcasecmp(argv[1], "delMarked") == 0) { p = remserver->objList; while (p) { next = p->next; if (p->markForDel) { if (p->pDrivInt && pServ->pExecutor && isInRunMode(pServ->pExecutor)) { SCWrite(pCon, "ERROR: cannot delete while running", eError); return 0; } RemoveCommand(pSics, p->name); } p = next; } } else { args = Arg2Tcl(argc - 1, argv + 1, NULL, 0); iRet = RemTransact(remserver, nChan, pCon, args, ">", NULL); free(args); return iRet; } return 1; } /*--------------------------------------------------------------------------*/ static void RemServerKill(void *self) { RemServer *remserver = self; Remob *remob, *next; assert(remserver); if (remserver->taskActive) { remserver->taskActive = 0; /* let the tasker kill me */ return; } remob = remserver->objList; while (remob) { next = remob->next; RemoveCommand(pServ->pSics, remob->name); remob = next; } RemDisconnect(remserver); DeleteDescriptor(remserver->desc); if (remserver->name) free(remserver->name); if (remserver->host) free(remserver->host); if (remserver->conn != NULL) { SCDeleteConnection(remserver->conn); } free(remserver); } /*-----------------------------------------------------------------------*/ static int RemobSetDriveable(Remob * remob, int driveable) { RemChannel *rc; if (driveable) { /* initialise Drivable interface */ remob->pDrivInt = CreateDrivableInterface(); if (!remob->pDrivInt) return 0; remob->pDrivInt->SetValue = RemobRun; remob->pDrivInt->CheckLimits = RemobLimits; remob->pDrivInt->CheckStatus = RemobStatus; remob->pDrivInt->GetValue = RemobGetValue; remob->pDrivInt->Halt = RemobHalt; if (remob->server->interestActive == 0) { rc = &remob->server->rc[0]; remob->server->interestActive = 1; if (!RemSetInterest(rc)) { RemDisconnect(remob->server); /* disconnect on error, RemSetInterest will be called again on connect */ } } } else if (remob->pDrivInt) { free(remob->pDrivInt); remob->pDrivInt = NULL; } return 1; } /*-----------------------------------------------------------------------*/ static Remob *RemobInit(char *name, RemServer * remserver) { Remob *remob, *p; assert(name); /* get memory */ remob = (Remob *) calloc(1, sizeof(Remob)); if (!remob) { return NULL; } /* copy arguments */ remob->server = remserver; remob->name = strdup(name); /* initialise object descriptor */ remob->desc = CreateDescriptor("RemObject"); if (!remob->desc) goto killit; remob->desc->GetInterface = RemobGetInterface; remob->desc->SaveStatus = RemobSaveStatus; /* initialise callback interface */ remob->pCall = CreateCallBackInterface(); if (!remob->pCall) goto killit; /* check if not yet in object list */ for (p = remserver->objList; p != NULL; p = p->next) { if (p == remob) break; } if (p == NULL) { remob->next = remserver->objList; remserver->objList = remob; } remob->markForDel = 0; /* done */ return remob; killit: RemobKill(remob); return NULL; } /*-----------------------------------------------------------------------*/ static RemServer *RemServerInit(char *name, char *host, int port) { RemServer *remserver = NULL; RemChannel *rc; int isUser; assert(name); remserver = calloc(1, sizeof(RemServer)); if (!remserver) { return 0; } /* initialise object descriptor */ remserver->desc = CreateDescriptor("RemServer"); if (!remserver->desc) { free(remserver); return NULL; } remserver->desc->SaveStatus = RemServerSaveStatus; remserver->name = strdup(name); remserver->host = strdup(host); remserver->port = port; for (isUser = 0; isUser <= 1; isUser++) { rc = &remserver->rc[isUser]; rc->incomplete = 0; rc->chan = NULL; rc->timeout = 0; } remserver->objList = NULL; remserver->conn = NULL; if (!remserver->name || !remserver->host || !remserver->port) { /* no success, clean up */ RemServerKill(remserver); return NULL; } remserver->taskActive = 1; remserver->interestActive = 0; remserver->forwardMessages = 1; TaskRegisterN(pServ->pTasker,name, RemServerTask, NULL, RemServerKill, remserver, TASK_PRIO_HIGH); return remserver; } /*-------------------------------------------------------------------------- The Factory function for creating a remote driveable object. Usage: Remob server serverName host:port Remob obj remobName serverName Remob drv remobName serverName Remob del remobName Remob del serverName */ int RemobCreate(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { RemServer *remserver = NULL; Remob *remob = NULL; char host[128]; char *p; int iD, iRet; char *obj; int argf; assert(pCon); assert(pSics); argtolower(argc, argv); if (argc >= 4 && strcmp(argv[1], "server") == 0) { p = strchr(argv[3], ':'); if (p) { snprintf(host, sizeof host, "%.*s", (int)(p - argv[3]), argv[3]); remserver = RemServerInit(argv[2], host, atoi(p + 1)); argf = 4; } else { remserver = RemServerInit(argv[2], argv[3], atoi(argv[4])); argf = 5; } if (remserver && argc > argf && strcmp(argv[argf], "0") == 0) { remserver->forwardMessages = 0; } if (!remserver) { SCPrintf(pCon, eError, "ERROR: Failure to create remote server connection %s", argv[2]); return 0; } /* create the interpreter command */ iRet = AddCommand(pSics, argv[2], RemServerAction, RemServerKill, remserver); if (!iRet) { SCPrintf(pCon, eError, "ERROR: duplicate command %s not created", argv[2]); RemServerKill(remserver); return 0; } return 1; } else if (argc == 4 && (strcmp(argv[1], "obj") == 0 || strcmp(argv[1], "drv") == 0)) { remserver = FindCommandData(pServ->pSics, argv[3], "RemServer"); if (!remserver) { SCPrintf(pCon, eError, "ERROR: remote server %s not found", argv[3]); return 0; } remob = FindCommandData(pServ->pSics, argv[2], "RemObject"); if (remob) { if (remob->server == remserver) { RemobSetDriveable(remob, strcmp(argv[1], "drv") == 0); remob->markForDel = 0; return 1; /* object exists already, silent return */ } } remob = RemobInit(argv[2], remserver); if (!remob) { SCPrintf(pCon, eError, "ERROR: Failure to create remote object %s", argv[1]); return 0; } RemobSetDriveable(remob, strcmp(argv[1], "drv") == 0); /* create the interpreter command */ iRet = AddCommand(pSics, argv[2], RemobAction, RemobKill, remob); SCparChange(pCon); if (!iRet) { SCPrintf(pCon, eError, "ERROR: duplicate command %s not created", argv[2]); RemobKill(remob); return 0; } return 1; } else if (argc == 3 && strcmp(argv[1], "del") == 0) { remob = FindCommandData(pSics, argv[2], "RemObject"); if (remob) { /* its a remob */ if (remob->pDrivInt && pServ->pExecutor && isInRunMode(pServ->pExecutor)) { SCPrintf(pCon, eError, "ERROR: cannot delete %s while running", argv[2]); return 0; } return RemoveCommand(pSics, argv[2]); } if (pServ->pExecutor && isInRunMode(pServ->pExecutor)) { SCPrintf(pCon, eError, "ERROR: cannot delete %s while running", argv[2]); return 0; } remserver = FindCommandData(pSics, argv[2], "RemServer"); if (remserver) { /* its a remserver */ return RemoveCommand(pSics, argv[2]); } SCWrite(pCon, "ERROR: remob object not found", eError); return 0; } SCPrintf(pCon, eError, "ERROR: illegal arguments for command remob"); return 0; }