/***********************************************************************/ /* Open Visualization Data Explorer */ /* (C) Copyright IBM Corp. 1989,1999 */ /* ALL RIGHTS RESERVED */ /* This code licensed under the */ /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */ /***********************************************************************/ #include #include #include #include #if DXD_HAS_UNIX_SYS_INCLUDES #include #endif #include #include #ifndef DXD_HAS_WINSOCKETS #include #endif #include "cache.h" #include "compile.h" #include "d.h" #include "exobject.h" #include "utils.h" #include "_variable.h" #include "_macro.h" #include "version.h" #include "parse.h" #include "distp.h" #include "config.h" #include "context.h" #ifdef DXD_WIN #define strcasecmp stricmp #endif #ifdef DXD_LICENSED_VERSION #include "license.h" extern int _dxd_ExHasLicense; static char _dxd_LicenseKey[5]; #endif #define MAXOBJECTS 21 /* must match mdf-c generated dx.mdf file */ /* dummy entry for master host */ static dpgraphstat masterentry = {NULL, NULL, -1, 0, 0, 0, 0}; static int *update_dptable = NULL; extern LIST(PGassign) _dxd_pgassign; extern LIST(SlavePeers) _dxd_slavepeers; extern LIST(dpgraphstat) _dxd_dpgraphstat; extern int _dxd_exParseAhead; extern int _dxd_exSParseAhead; extern Error m__badfunc(Object *, Object *); typedef struct _EXTab *EXTab; typedef struct _EXTab { char *name; /* string to match */ PFI func; /* function to call on match */ EXTab table; /* table to search on match */ int size; /* size of the table */ } _EXTab; static Error CmdProc (Object *in); static Error MustRunOnMaster (Object in0); #if DXD_OS2_SYSCALL static int _Optlink Compare (EXTab a, EXTab b); #else static int Compare (EXTab a, EXTab b); #endif static Error ProcessTable (char *cmd, Object *in, EXTab table, int len); static Error Assign (char *c, Object *in); static Error AssignNoExec (char *c, Object *in); static Error Describe (char *c, Object *in); static Error FlushCache (char *c, Object *in); static Error FlushGlobal (char *c, Object *in); static Error FlushMacro (char *c, Object *in); static Error Getenv (char *c, Object *in); static Error GetKey (char *c, Object *in); static Error GroupAttach (char *c, Object *in); static Error GroupDetach (char *c, Object *in); static Error HostDisconnect (char *c, Object *in); static Error KillGraph (char *c, Object *in); static Error License (char *c, Object *in); static Error LoadObjFile (char *c, Object *in); static Error LoadInteractors (char *c, Object *in); static Error MdfLoadFile (char *c, Object *in); static Error MdfLoadString (char *c, Object *in); static Error OutboardKill (char *c, Object *in); static Error Pfsmgr (char *c, Object *in); static Error PrintCache (char *c, Object *in); static Error PrintExObjects (char *c, Object *in); static Error PrintFunction (char *c, Object *in); static Error PrintGlobal (char *c, Object *in); static Error PrintGroups (char *c, Object *in); static Error PrintHosts (char *c, Object *in); static Error ProductVersion (char *c, Object *in); static Error Reclaim (char *c, Object *in); static Error Terminate (char *c, Object *in); static Error Version (char *c, Object *in); static Error SyncGraph (char *c, Object *in); static Error UnLoadObjFile (char *c, Object *in); static int UpdateWorkers (char *host, char *options, int add); #define FCALL(_n,_f) {_n, _f, NULL, 0} #define TABLE(_n,_t) {_n, NULL, _t, sizeof (_t)} #define FANDT(_n,_f,_t) {_n, _f, _t, sizeof (_t)} static _EXTab AssignTable[] = { FCALL ("", Assign), FCALL ("noexecute", AssignNoExec) }; static _EXTab FlushTable[] = { FCALL ("cache", FlushCache), FCALL ("dictionary", FlushGlobal), FCALL ("macro", FlushMacro), FCALL ("macros", FlushMacro) }; static _EXTab GroupTable[] = { FCALL ("attach", GroupAttach), FCALL ("detach", GroupDetach) }; static _EXTab HostTable[] = { FCALL ("disconnect", HostDisconnect) }; static _EXTab MdfTable[] = { FCALL ("describe", Describe), FCALL ("file", MdfLoadFile), FCALL ("print", Describe), FCALL ("string", MdfLoadString) }; static _EXTab OutboardTable[] = { FCALL ("delete", OutboardKill), }; static _EXTab PrintTable[] = { FCALL ("cache", PrintCache), FCALL ("dictionary", PrintGlobal), FCALL ("env", Getenv), FCALL ("exobjects", PrintExObjects), FCALL ("functions", PrintFunction), FCALL ("global", PrintGlobal), FCALL ("globals", PrintGlobal), FCALL ("groups", PrintGroups), FCALL ("hosts", PrintHosts), FCALL ("mdf", Describe), FCALL ("version", Version) }; static _EXTab ProductTable[] = { FCALL ("version", ProductVersion), }; /* * The top level command table */ static _EXTab TopLevel[] = { TABLE ("assign", AssignTable), FCALL ("describe", Describe), FCALL ("exit", Terminate), TABLE ("flush", FlushTable), FCALL ("getenv", Getenv), FCALL ("getkey", GetKey), TABLE ("group", GroupTable), TABLE ("host", HostTable), FCALL ("kill", KillGraph), FCALL ("license", License), FCALL ("load", LoadObjFile), FCALL ("loadinteractors", LoadInteractors), TABLE ("mdf", MdfTable), TABLE ("nop", NULL), TABLE ("outboard", OutboardTable), FCALL ("pfsmgr", Pfsmgr), TABLE ("print", PrintTable), TABLE ("product", ProductTable), FCALL ("quit", Terminate), FCALL ("reclaim", Reclaim), FCALL ("sync", SyncGraph), FCALL ("version", Version) #if 0 FCALL ("unload", UnLoadObjFile), #endif }; /* * The top level command interface */ Error _dxf_ExExecCommand (Object *in) { Error ret, i; for (i=0; i < (MAXOBJECTS + 1) && in[i]; i++) ; if (MustRunOnMaster (in[0])) ret = _dxf_ExRunOn (1, CmdProc, in, ((i+1) * sizeof(Object))); else ret = CmdProc (in); return (ret); } Error _dxf_ExExecCommandStr (char *cmd) { Object in[MAXOBJECTS + 1]; int ret, i; in[0] = (Object)DXNewString(cmd); if(!in[0]) return(ERROR); for(i = 1; i < MAXOBJECTS + 1; i++) in[1] = NULL; ret = _dxf_ExExecCommand(in); DXDelete(in[0]); return(ret); } void _dxf_ExDeletePeer(SlavePeers *sp, int closepeer) { /* if name is NULL but we still have a valid file descrip then */ /* we are effectively marking this to be deleted when the socket */ /* closes. */ if(closepeer) DXRegisterInputHandler(NULL, sp->sfd, NULL); if(sp->peername) { DXFree(sp->peername); sp->peername = NULL; } sp->SlaveId = -1; sp->wait_on_ack = FALSE; sp->pending_req = FALSE; sp->sendq.head = NULL; sp->sendq.tail = NULL; if(closepeer) { close(sp->sfd); sp->sfd = -99; /* reuse */ } } void _dxf_ExDeletePeerByName(char *host, int closepeer) { int i, limit; SlavePeers *sp; for (i = 0, limit = SIZE_LIST(_dxd_slavepeers); i < limit; ++i) { sp = FETCH_LIST(_dxd_slavepeers, i); if(sp->sfd == -99) continue; if (!strcmp(sp->peername,host)) { _dxf_ExDeletePeer(sp, closepeer); break; } } } void _dxf_ExAddPeer(SlavePeers *sp) { int k, limit; SlavePeers *index; for (k = 0, limit = SIZE_LIST(_dxd_slavepeers); k < limit; ++k) { index = FETCH_LIST(_dxd_slavepeers, k); if(index->sfd == -99) { /* reuse entry */ UPDATE_LIST(_dxd_slavepeers, *sp, k); return; } } /* we didn't find an entry to reuse */ APPEND_LIST(SlavePeers, _dxd_slavepeers, *sp); } void _dxf_ExDeleteHost(char *host, int err, int closepeer) { dpgraphstat *index, *hostentry; PGassign pgassign, *pgindex; int i, j, limit, limit2; char savehost[MAXHOSTNAMELEN]; strcpy(savehost, host); _dxf_ExDeletePeerByName(savehost, closepeer); /* entry 0 is a dummy for the master so skip it */ for (i = 1, limit = SIZE_LIST(_dxd_dpgraphstat); i < limit; ++i) { index = FETCH_LIST(_dxd_dpgraphstat, i); /* entry not used */ if(index->procfd == -99) continue; if (!strcmp(index->prochostname,savehost)) { if(err) DXUIMessage("ERROR", "PEER ABORT - Connection to peer %s has been broken.",savehost); else if(index->procfd >= 0) { int peerwait = 1; _dxf_ExDistMsgfd(DM_EXIT, (Pointer)&peerwait, index->procfd); _dxf_ExDistributeMsg(DM_DELETEPEER, (Pointer)savehost, strlen(savehost)+1, TOSLAVES); } for (j = 0, limit2 = SIZE_LIST(_dxd_pgassign); j < limit2; ++j) { pgindex = FETCH_LIST(_dxd_pgassign, j); if(pgindex->hostindex < 0) continue; /* no host assignment */ hostentry = FETCH_LIST(_dxd_dpgraphstat, pgindex->hostindex); if(!strcmp(hostentry->prochostname, savehost)) { pgindex->hostindex = -1; _dxf_ExGVariableSetStr(pgindex->pgname, NULL); } } DXFree(index->prochostname); DXFree(index->options); index->prochostname = NULL; index->options = NULL; if(index->procfd >= 0) { close(index->procfd); (*_dxd_exNSlaves)--; /* If we have to, wait for the child. */ if (!_dxd_exDebugConnect) wait(0); } index->procfd = -99; /* reuse this entry */ index->numpgrps = 0; /* set error to TRUE so we won't try to restart this entry */ index->error = TRUE; break; } } } /* * update a global variable without causing a graph execution. */ Error _dxf_ExStealthUpdate (char *name, Object obj) { return _dxf_ExUpdateGlobalDict (name, obj, 0); } void _dxf_InitDPtableflag() { update_dptable = (int *)DXAllocate(sizeof(int *)); if(update_dptable == NULL) _dxf_ExDie("Unable to allocate space for distributed flag"); *update_dptable = FALSE; INIT_LIST(_dxd_dpgraphstat); masterentry.prochostname = _dxd_exHostName; APPEND_LIST(dpgraphstat, _dxd_dpgraphstat, masterentry); } /* if a new host was added to the table return true */ _dxf_NewDPTableEntry() { if(*update_dptable) { *update_dptable = FALSE; return(TRUE); } else return(FALSE); } /* host string is in the form "hostname -options". * This will update the list of slave hosts, for a delete command * the entry will not be removed from the table and the sockets will * not be closed. */ static int UpdateWorkers(char *host, char *options, int add) { int k, limit; dpgraphstat *index; dpgraphstat dpentry; int optlen = 0; int opterr = FALSE; if(add) { if(options && *options != '-') { /* print error but add to table anyway */ DXSetError(ERROR_BAD_PARAMETER,"bad option string %s", options); opterr = TRUE; } if(options) optlen = strlen(options) + 1; } /* if new worker is the master don't add it to table of workers */ if(_dxfHostIsLocal(host)) { if(add) { if(options != NULL) DXWarning("%s is already connected, host arguments ignored.", _dxd_exHostName); DXFree(host); return(0); } else return(-1); } /* entry 0 is a dummy for the master, skip it */ for (k = 1, limit = SIZE_LIST(_dxd_dpgraphstat); k < limit; ++k) { index = FETCH_LIST(_dxd_dpgraphstat, k); /* entry not used */ if(index->procfd == -99) continue; if (!strcmp(index->prochostname, host)) { ExDebug("*1","Current host %s already in dpgraphstat", host); /* not adding new host to table */ if(add) { DXFree(host); if(index->procfd >= 0) { if(options != NULL) { if(index->options != NULL && !strcmp(index->options, options)) { index->error = opterr; if(!opterr) index->numpgrps++; return(k); } } else { if(index->options == NULL) { index->error = FALSE; index->numpgrps++; return(k); } } /* new options differ from old options */ if(index->numpgrps == 0) { int peerwait = 0; _dxf_ExDistMsgfd(DM_EXIT, (Pointer)&peerwait, index->procfd); if(index->procfd >= 0) { close(index->procfd); /* If we have to, wait for the child. */ if (!_dxd_exDebugConnect) wait(0); } index->procfd = -1; index->error = opterr; if(!opterr) index->numpgrps++; if(index->options) { if(optlen > (strlen(index->options) + 1)); index->options = DXReAllocate(index->options, optlen); } else index->options = DXAllocateLocal(optlen); if(!index->options) { index->error = TRUE; DXSetError(ERROR_NO_MEMORY, "Cannot allocate memory for host table entry"); return(k); } if(optlen > 0) strcpy(index->options, options); else { DXFree(index->options); index->options = NULL; } *update_dptable = TRUE; ExDebug("*7", "Set Flag to Update distributed table"); return(k); } else { DXSetError(ERROR_BAD_PARAMETER, "Host already connected, cannot specify new options"); index->error = TRUE; return(k); } } else { /* host not connected */ if(optlen > 0) { if(index->options) { if(optlen > (strlen(index->options) + 1)) index->options = DXReAllocate(index->options, optlen); } else index->options = DXAllocateLocal(optlen); if(!index->options) { index->error = TRUE; DXSetError(ERROR_NO_MEMORY, "Cannot allocate memory for host table entry"); return(k); } strcpy(index->options, options); } else { /* no options to add, free old ones */ if(index->options) { DXFree(index->options); index->options = NULL; } } index->error = opterr; if(!opterr) index->numpgrps++; *update_dptable = TRUE; ExDebug("*7", "Set Flag to Update distributed table"); return(k); } } else { /* not adding a host */ index->numpgrps--; if(index->numpgrps == 0) _dxf_ExDeleteHost(host, 0, 0); return(-1); } } } if(add) { /* if we got here we did not find host name in list */ dpentry.error = opterr; dpentry.prochostname = host; if(optlen > 0) { dpentry.options = (char *) DXAllocateLocal (optlen); if(!dpentry.options) { dpentry.error = TRUE; DXSetError(ERROR_NO_MEMORY, "Could not allocate memory for remote host table entry"); } else strcpy(dpentry.options, options); } else dpentry.options = NULL; dpentry.procfd = -1; dpentry.SlaveId = -1; if(!opterr) dpentry.numpgrps = 1; else dpentry.numpgrps = 0; /* entry 0 is a dummy for the master */ for (k = 1, limit = SIZE_LIST(_dxd_dpgraphstat); k < limit; ++k) { index = FETCH_LIST(_dxd_dpgraphstat, k); if(index->procfd == -99) { /* reuse entry */ UPDATE_LIST(_dxd_dpgraphstat, dpentry, k); *update_dptable = TRUE; ExDebug("*7", "Set Flag to Update distributed table"); return(k); } } /* we didn't find an entry to reuse */ APPEND_LIST(dpgraphstat, _dxd_dpgraphstat, dpentry); *update_dptable = TRUE; ExDebug("*7", "Set Flag to Update distributed table"); limit = SIZE_LIST(_dxd_dpgraphstat); return(limit-1); } else return(-1); } Error _dxf_ExPrintGroups() { int i, limit; PGassign *index; dpgraphstat *hostentry; DXMessage("Group Attach Table"); DXMessage("%-25s %s", "Groupname", "Hostname"); for (i = 0, limit = SIZE_LIST(_dxd_pgassign); i < limit; ++i) { index = FETCH_LIST(_dxd_pgassign, i); if(index->hostindex >= 0) { hostentry = FETCH_LIST(_dxd_dpgraphstat, index->hostindex); DXMessage("%-25s %s", index->pgname, hostentry->prochostname); } else DXMessage("%-25s", index->pgname); } } Error _dxf_ExPrintHosts() { int i, limit; dpgraphstat *index; DXMessage("Number of Slaves %d", *_dxd_exNSlaves); DXMessage("Host Connection Table"); DXMessage("%-25s %s", "Hostname", "Status"); /* entry 0 is a dummy for the master */ for (i = 1, limit = SIZE_LIST(_dxd_dpgraphstat); i < limit; ++i) { index = FETCH_LIST(_dxd_dpgraphstat, i); if(index->procfd == -99) continue; if(index->procfd < 0) { if(index->error) { if(index->prochostname) DXMessage("%-25s %s", index->prochostname, "connect error"); } else DXMessage("%-25s %s", index->prochostname, "not connected"); } else { if(index->numpgrps == 1) DXMessage("%-25s %s: %d group attached", index->prochostname, "connected", index->numpgrps); else DXMessage("%-25s %s: %d groups attached", index->prochostname, "connected", index->numpgrps); } } } /* * hack for now. the mdf commands CAN'T be started with * the subroutine which is used to be sure the executive * commands run on processor 0, so start implementing a layer * which eventually could be used to run executive commands * which are not dependent on running on proc 0 from whichever * processor picked up the executive module in the first place. */ static Error MustRunOnMaster (Object in0) { Error ret; char *cmd; if (!in0 || ! DXExtractString (in0, &cmd)) return ERROR; if (strncmp(cmd, "mdf", 3)) return OK; return ERROR; } static Error CmdProc (Object *in) { Error ret; char *cmd; if (!in[0] || ! DXExtractString (in[0], &cmd)) { DXSetError (ERROR_BAD_PARAMETER, "#10200", "command input"); return (ERROR); } ret = ProcessTable (cmd, &in[1], TopLevel, sizeof (TopLevel)); return (ret); } #if DXD_OS2_SYSCALL static int _Optlink #else static int #endif Compare (EXTab a, EXTab b) { return (strcmp (a->name, b->name)); } static Error ProcessTable (char *cmd, Object *in, EXTab table, int len) { char *next; char buf[1024]; _EXTab dummy; EXTab tab; Error fret = OK; Error tret = OK; for (next = cmd; next && *next && isspace (*next); next++) continue; buf[0] = '\0'; sscanf (next, "%s", buf); dummy.name = buf; tab = (EXTab) bsearch ((char *) &dummy, (char *) table, len / sizeof (_EXTab), sizeof (_EXTab), Compare); if (! tab) { DXSetError (ERROR_BAD_PARAMETER, "#8310", cmd); return (ERROR); } for (next = next + strlen (buf); next && *next && isspace (*next); next++) continue; if (tab->func) fret = (* tab->func) (next, in); if (tab->table) { if(strcmp(next, "") == 0) { DXSetError(ERROR_BAD_PARAMETER, "#8312", cmd); return (ERROR); } tret = ProcessTable (next, in, tab->table, tab->size); } return (fret == OK && tret == OK ? OK : ERROR); } /* * Functions executed by the tables. */ static int Assign(char *c, Object *in) { return(ERROR); } static int AssignNoExec(char *c, Object *in) { char *name; if (!in[0] || ! DXExtractString (in[0], &name)) { DXSetError (ERROR_BAD_PARAMETER, "#10200", "variable name"); return (ERROR); } return (_dxf_ExStealthUpdate(name, in[1])); } static int Describe (char *c, Object *in) { char *str; int i, j, k, n; char *key; node *func; node *minn; int mini; node **funcs = NULL; char help[1024]; char *hp; extern char *_dxf_ExHelpFunction (); if ((c == NULL || *c == '\000') && (in == NULL || in[0] == NULL)) { _dxf_ExDictionaryBeginIterate (_dxd_exMacroDict); for (n = 0; _dxf_ExDictionaryIterate (_dxd_exMacroDict, &key) != NULL; n++) ; _dxf_ExDictionaryEndIterate (_dxd_exMacroDict); funcs = (node **) DXAllocateLocal (n * sizeof (node *)); DXBeginLongMessage (); _dxf_ExDictionaryBeginIterate (_dxd_exMacroDict); for (i = 0, k = 0; i < n; i++) { func = (node *) _dxf_ExDictionaryIterate (_dxd_exMacroDict, &key); /* skip over dummy function definitions */ if (func->v.module.def.func == m__badfunc) continue; if (funcs != NULL) funcs[k] = func; else DXMessage ("%-25s %s\n", func->v.module.id->v.id.id, func->type == NT_MACRO ? "macro" : "module"); k++; } _dxf_ExDictionaryEndIterate (_dxd_exMacroDict); for (i = 0; i < k; i++) { minn = funcs[i]; mini = i; for (j = i; j < k; j++) { if (strcasecmp (minn->v.function.id->v.id.id, funcs[j]->v.function.id->v.id.id) > 0) { minn = funcs[j]; mini = j; } } func = funcs[i]; funcs[i] = funcs[mini]; funcs[mini] = func; } if (funcs != NULL) { for (i = 0; i < k; i++) DXMessage ("%-25s %s\n", funcs[i]->v.module.id->v.id.id, funcs[i]->type == NT_MACRO ? "macro" : "module"); } DXEndLongMessage (); DXFree ((Pointer) funcs); return (OK); } if (c && *c) { while (*c) { help[0] = '\000'; sscanf (c, "%s", help); if (help[0] == '\000') break; str = _dxf_ExHelpFunction (help); if (str) { DXBeginLongMessage (); DXMessage (str); DXEndLongMessage (); DXFree ((Pointer) str); } for (c = c + strlen (help); *c && isspace (*c); c++) continue; } } else { for (i = 0; DXExtractString (in[i], &hp); i++) { str = _dxf_ExHelpFunction (hp); if (str) { DXBeginLongMessage (); DXMessage (str); DXEndLongMessage (); DXFree ((Pointer) str); } } } return (OK); } static int FlushCache (char *c, Object *in) { _dxf_ExCacheFlush (FALSE); return (OK); } void _dxf_ExFlushGlobal (void) { char *dummy; Object *in; FlushGlobal(dummy, in); } static int FlushGlobal (char *c, Object *in) { if(!_dxd_exRemoteSlave) { /* _dxf_ExCacheFlush and _dxf_ExDictionaryPurge will send msgs * to slaves and slaves will call each of these routines * seperately */ _dxf_ExCacheFlush (TRUE); DXDebug ("1", "flushing dictionary"); _dxf_ExDictionaryPurge (_dxd_exGlobalDict); _dxf_ExDistributeMsg(DM_FLUSHGLOBAL, NULL, 0, TOSLAVES); } _dxf_ExInitSystemVars (); ExResetGroupAssign (); return (OK); } void _dxf_ExFlushMacro (void) { char *dummy; Object *in; FlushMacro(dummy, in); } static int FlushMacro (char *c, Object *in) { if(!_dxd_exRemoteSlave) { /* _dxf_ExDictionaryPurge will send msg to slaves and cause * the slaves to call this routine seperately */ _dxf_ExDictionaryPurge (_dxd_exMacroDict); _dxf_ExDistributeMsg(DM_FLUSHMACRO, NULL, 0, TOSLAVES); } _dxf_user_modules (); _dxf_private_modules (); _dxf_ExFunctionDone (); return (OK); } static int Getenv (char *c, Object *in) { char *env; char **envp; DXBeginLongMessage (); if (c && *c) { env = (char *) getenv (c); if (env) DXMessage ("%s=%s", c, env); else DXMessage ("%s is not in the environment", c); } else { envp = (char **) _dxf_ExEnvp (); for ( ;envp && *envp; envp++) DXMessage ("%s\n", *envp); } DXEndLongMessage (); return (OK); } /* Insert a group to hostname assignment in table. This will not make the * connection to the remote host until the current graph has finished * executing. If this is updated in the middle of a graph evaluation we * have a slave that is started but is not executing the current graph. * The master will see the new slave and try to wait for it to execute * the current graph which is doesn't have. * This takes a string list with each string element being: * "group1, group2, group3:hostname -options" */ static int GroupAttach(char *c, Object *in) { int n, k, limit, grouplen, found; dpgraphstat *hostentry; char *str, *delimiter; char *hoststr; PGassign pgassign, *index; int cerror = FALSE; char *hostname; char *optr; int hostlen; if(_dxd_exRemoteSlave) return(OK); if(!in[0]) { DXSetError (ERROR_BAD_PARAMETER, "#10200", "group assignment"); return (ERROR); } n = 0; while(DXExtractNthString(in[0], n, &str)) { hoststr = strchr(str, ':'); if(hoststr == NULL) { DXSetError(ERROR_BAD_PARAMETER, "no host assignment"); return(ERROR); } hoststr++; while(*hoststr == ' ') hoststr++; if(*hoststr == '\0') { DXSetError(ERROR_BAD_PARAMETER, "no host assignment"); return(ERROR); } optr = hoststr; while(*optr && *optr != ' ') optr++; if(*optr) hostlen = optr - hoststr; else hostlen = strlen(hoststr); while(*optr && *optr == ' ') optr++; if(*optr == '\0') optr = NULL; while(*str == ' ') str++; if(*str == ':' || *str == ',') { DXSetError(ERROR_BAD_PARAMETER, "no group name"); return(ERROR); } while(*str) { hostname = (char *)DXAllocateLocal(hostlen + 1); if(hostname == NULL) DXSetError(ERROR_NO_MEMORY, "Cannot allocate memory for host table entry"); strncpy(hostname, hoststr, hostlen); hostname[hostlen] = '\0'; delimiter = str; while(*delimiter && *delimiter != ',' && *delimiter != ' ' && *delimiter != ':') delimiter++; grouplen = delimiter - str; pgassign.pgname = (char *)DXAllocateLocal(grouplen + 1); if(pgassign.pgname == NULL) DXSetError(ERROR_NO_MEMORY, "Cannot allocate memory for group table entry"); strncpy(pgassign.pgname, str, grouplen); pgassign.pgname[grouplen] = '\0'; found = FALSE; /* search table to see if process group is already assigned */ for (k = 0, limit = SIZE_LIST(_dxd_pgassign); k < limit; ++k) { index = FETCH_LIST(_dxd_pgassign, k); if(!strcmp(index->pgname, pgassign.pgname)) { found = TRUE; break; } } if(found) { /* see if it is already attached */ if(index->hostindex >= 0) hostentry = FETCH_LIST(_dxd_dpgraphstat, index->hostindex); else hostentry = NULL; if(hostentry && (hostentry->error == FALSE) && !strcmp(hostentry->prochostname, hostname)) { if(optr != NULL) { if(hostentry->options != NULL && !strcmp(hostentry->options, optr)) { DXFree(pgassign.pgname); goto next_string; } } else { if(hostentry->options == NULL) { DXFree(pgassign.pgname); goto next_string; } } } /* replace host assignment in table */ index->hostindex = UpdateWorkers(hostname, optr, 1); hostentry = FETCH_LIST(_dxd_dpgraphstat, index->hostindex); DXFree(pgassign.pgname); if(!hostentry->error) { _dxf_ExGVariableSetStr(index->pgname, hostentry->prochostname); if(_dxd_exDebug) printf("reassigning %s to %s\n",index->pgname, hostentry->prochostname); } else cerror = hostentry->error; } else { /* adding new process group assignment */ pgassign.hostindex = UpdateWorkers(hostname, optr, 1); hostentry = FETCH_LIST(_dxd_dpgraphstat, pgassign.hostindex); APPEND_LIST(PGassign, _dxd_pgassign, pgassign); if(!hostentry->error) { _dxf_ExGVariableSetStr(pgassign.pgname, hostentry->prochostname); if(_dxd_exDebug) printf("assigning %s to %s\n", pgassign.pgname, hostentry->prochostname); } else cerror = hostentry->error; } next_string: str = delimiter; while(*str == ' ' || *str == ',') str++; if(*str == ':') break; } n++; } if(cerror) return(ERROR); else return(OK); } ExResetGroupAssign () { int k, limit; PGassign *index; dpgraphstat *hostentry; for (k = 0, limit = SIZE_LIST(_dxd_pgassign); k < limit; ++k) { index = FETCH_LIST(_dxd_pgassign, k); hostentry = FETCH_LIST(_dxd_dpgraphstat, index->hostindex); if(!hostentry->error) _dxf_ExGVariableSetStr(index->pgname, hostentry->prochostname); } } /* This routine does not close the sockets associated with a host. * This routine takes a string list of group names to be removed from the * process assignment table. */ static int GroupDetach(char *c, Object *in) { char *groupname; int n, k, limit; PGassign *index; dpgraphstat *hostentry; if(_dxd_exRemoteSlave) return(OK); if(!in[0]) { DXSetError (ERROR_BAD_PARAMETER, "#10200", "group name"); return (ERROR); } n = 0; while(DXExtractNthString(in[0], n, &groupname)) { for (k = 0, limit = SIZE_LIST(_dxd_pgassign); k < limit; ++k) { index = FETCH_LIST(_dxd_pgassign, k); if(!strcmp(index->pgname, groupname)) { hostentry = FETCH_LIST(_dxd_dpgraphstat, index->hostindex); if(hostentry) { if(!hostentry->error) index->hostindex = UpdateWorkers( hostentry->prochostname, NULL, 0); } _dxf_ExGVariableSetStr(index->pgname, NULL); _dxf_ExCacheFlush(FALSE); DXFree(index->pgname); DELETE_LIST(PGassign, _dxd_pgassign, k); break; } } n++; } return(OK); } static int HostDisconnect(char *c, Object *in) { int n; char *hostname; n = 0; while(DXExtractNthString(in[0], n, &hostname)) { _dxf_ExDeleteHost(hostname, 0, 0); n++; } return(OK); } static int KillGraph (char *c, Object *in) { extern int *_dxd_exKillGraph; if (!_dxf_ExGQAllDone ()) { *_dxd_exKillGraph = TRUE; _dxf_ExDistributeMsg(DM_KILLEXECGRAPH, (Pointer)_dxd_exContext->graphId, 0, TOPEERS); } return (OK); } static int LoadObjFile(char *c, Object *in) { char *str; if (!in[0] || ! DXExtractString (in[0], &str)) { DXSetError (ERROR_BAD_PARAMETER, "#10200", "object filename"); return (ERROR); } return DXLoadObjFile(str, "DXMODULES"); } extern _dxfLoadUserInteractors(char *); static int LoadInteractors(char *c, Object *in) { return _dxf_ExRunOn (1, _dxfLoadUserInteractors, (Pointer)c, strlen(c)+1); } static int MdfLoadFile(char *c, Object *in) { char *str; if (!in[0] || ! DXExtractString (in[0], &str)) { DXSetError (ERROR_BAD_PARAMETER, "#10200", "mdf filename"); return (ERROR); } return DXLoadMDFFile(str); } static int MdfLoadString(char *c, Object *in) { char *str; if (!in[0] || ! DXExtractString (in[0], &str)) { DXSetError (ERROR_BAD_PARAMETER, "#10200", "mdf definition"); return (ERROR); } return DXLoadMDFString(str); } /* disconnect the pipe between the exec and a specific outboard module. * args are: module name, instance number (may be omitted - defaults to 0), * and process group name (may be null - defaults to localhost). */ static int OutboardKill (char *c, Object *in) { extern Error *_dxd_ExDeleteRemote(char *, int); char *module; int instance; char *procgroup; if (!in[0] || ! DXExtractString (in[0], &module)) { DXSetError (ERROR_BAD_PARAMETER, "#10200", "outboard module name"); return (ERROR); } if (!in[1]) instance = 0; else if (! DXExtractInteger (in[1], &instance)) { DXSetError (ERROR_BAD_PARAMETER, "#10010", "outboard instance number"); return (ERROR); } if (!in[2]) procgroup = NULL; else if (! DXExtractString (in[2], &procgroup)) { DXSetError (ERROR_BAD_PARAMETER, "#10200", "outboard process group"); return (ERROR); } if (procgroup) { if (!_dxf_ExDeleteReallyRemote (procgroup, module, instance)) return ERROR; } else if (!_dxf_ExDeleteRemote (module, instance)) return ERROR; return (OK); } static int Pfsmgr (char *c, Object *in) { int argc = 0; char *argv[1024]; char *buf = NULL; char *b; int len; Error ret = ERROR; if (! c) { ret = OK; goto cleanup; } len = strlen (c) + 1; b = buf = (char *) DXAllocateLocal (len); if (buf == NULL) goto cleanup; memcpy (buf, c, len); while (*b) { argv[argc++] = b; while (*b && ! isspace (*b)) b++; while (*b && isspace (*b)) b++; } for (b = buf; *b; b++) if (isspace (*b)) *b = (char) NULL; ret = _dxf_pfsmgr (argc, argv); cleanup: DXFree ((Pointer) buf); return (ret); } static int PrintCache (char *c, Object *in) { _dxf_ExDictPrint (_dxd_exCacheDict); return (OK); } static int PrintExObjects (char *c, Object *in) { #ifdef LEAK_DEBUG PrintEXObj (); #else DXMessage ("#1280"); #endif return (OK); } static int PrintFunction (char *c, Object *in) { _dxf_ExDictPrint (_dxd_exMacroDict); return (OK); } static int PrintGlobal (char *c, Object *in) { _dxf_ExDictPrint (_dxd_exGlobalDict); return (OK); } static int PrintGroups (char *c, Object *in) { _dxf_ExPrintGroups(); return (OK); } static int PrintHosts (char *c, Object *in) { _dxf_ExPrintHosts(); return (OK); } static int Reclaim (char *c, Object *in) { DXTraceTime (1); _dxf_ExReclaimMemory (atoi (c)); DXTraceTime (0); DXPrintTimes (); return (OK); } static int SyncGraph (char *c, Object *in) { _dxd_exParseAhead = FALSE; return(OK); } static int Terminate (char *c, Object *in) { exit (0); /* not reached */ return (OK); } static int License (char *c, Object *in) { #ifdef DXD_LICENSED_VERSION static int license_tried = FALSE; int i; char keybuf[14]; char typebuf[5]; char key[9]; char salt[3]; /* decode and check license string here */ if (license_tried) exit(0); /* our UI will never call $license twice */ else license_tried = TRUE; for(i=0;i<13;i++) keybuf[i] = c[i]; keybuf[13] = '\0'; for(i=0;i<4;i++) typebuf[i] = c[i+13]; typebuf[4] = '\0'; for(i=0;i<4;i++) key[i*2] = _dxd_LicenseKey[i]; key[1] = 'g'; key[3] = '3'; key[5] = '$'; key[7] = 'Q'; key[8] = '\0'; salt[0] = '4'; salt[1] = '.'; salt[2] = '\0'; if(strcmp(keybuf,(const char *)crypt(key,salt))){ DXMessage("License Error: Invalid license Message\n"); DXUIMessage("LICENSE","UNAUTHORIZED"); return (OK); } sscanf(typebuf,"%04x",&i); /* This junk below is to preserve byte order, beware ! */ switch(i^(*((ubyte *)&keybuf[4])<<8)+(*((ubyte *)&keybuf[5]))) { case GOT_NODELOCKED: if (!ExGetPrimaryLicense()) DXMessage("Exec could not get a license (UI has nodelocked)\n"); else DXUIMessage("LICENSE", "AUTHORIZED"); break; case GOT_CONCURRENT: _dxd_ExHasLicense = TRUE; DXUIMessage("LICENSE", "AUTHORIZED"); DXMessage("Running under UI's concurrent license\n"); break; default: DXMessage("License Error: Invalid license Message\n"); break; } if (_dxd_ExHasLicense == FALSE) DXUIMessage("LICENSE","UNAUTHORIZED"); if (_dxd_ExHasLicense && _dxd_exRemote) _dxf_ExReadDXRCFiles(); #else /* DXD_LICENSED_VERSION */ if (_dxd_exRemote) _dxf_ExReadDXRCFiles(); DXUIMessage("LICENSE", "AUTHORIZED"); #endif /* !DXD_LICENSED_VERSION */ return (OK); } static int GetKey (char *c, Object *in) { #ifdef DXD_LICENSED_VERSION int i; srand(time(NULL)); i = rand(); i = (i<4096) ? (i+4096) : (i); /* forces to be 4 0x chars */ sprintf(_dxd_LicenseKey, "%x\n", i); DXUIMessage("LICENSE", _dxd_LicenseKey); #else /* DXD_LICENSED_VERSION */ DXUIMessage("LICENSE","ffff"); /* write key ffff in case UI tries */ /* to use license protocol */ #endif /* !DXD_LICENSED_VERSION */ return (OK); } static int Version (char *c, Object *in) { int n; int m0, m1, m2; char buf[256]; int err = TRUE; char *b; if (c == NULL || *c == '\000') { DXBeginLongMessage (); DXMessage ("Executive version: %d %d %d\n", DXD_VERSION, DXD_RELEASE, DXD_MODIFICATION); DXMessage ("Executive/UI interface: %d %d %d\n", UI_MAJOR, UI_MINOR, UI_MICRO); DXMessage ("Creation date: %s\n", EX_COM_DATE); DXMessage ("Creation host: %s\n", EX_COM_HOST); DXEndLongMessage (); return (OK); } #if DXD_PRINTF_RETURNS_COUNT n = sprintf (buf, "Executive/UI version mismatch: %d %d %d vs ", UI_MAJOR, UI_MINOR, UI_MICRO); #else { sprintf (buf, "Executive/UI version mismatch: %d %d %d vs ", UI_MAJOR, UI_MINOR, UI_MICRO); n = strlen(buf); } #endif b = buf + n; n = sscanf (c, "%d%d%d", &m0, &m1, &m2); if (n == 3 && m0 == UI_MAJOR && m1 == UI_MINOR && m2 == UI_MICRO) err = FALSE; else sprintf (b, "%s", *c ? c : ""); if (err) DXUIMessage ("ERROR", buf); return (OK); } static int ProductVersion (char *c, Object *in) { int n; int m0, m1, m2; if (c == NULL || *c == '\000') { DXSetError(ERROR_BAD_PARAMETER, "Product Version string required for version check"); return ERROR; } n = sscanf (c, "%d%d%d", &m0, &m1, &m2); #define VERSION_ID(a,b,c) (((a) << 16) + ((b) << 8) + (c)) if (n != 3 || (VERSION_ID(m0,m1,m2) > VERSION_ID(DXD_VERSION,DXD_RELEASE,DXD_MODIFICATION))) { DXWarning("User Interface or .net file version is newer than Executive version"); } return (OK); } static int UnLoadObjFile(char *c, Object *in) { char *str; if (!in[0] || ! DXExtractString (in[0], &str)) { DXSetError (ERROR_BAD_PARAMETER, "#10200", "object filename"); return (ERROR); } return DXUnloadObjFile(str); }