/* r e x - remote execution control task */ #ifdef DOCUMENTATION Title rex - remote execute control task Index rex - remote execute control task Synopsis .nf rex -l .s rex -h .s rex -b .s rex -o .s rex -s .s rex -e .s .f Description REX allows logging into an running tasks on a remote system. Unlike RMT, more than one system at a time can be accessed. REX can also be run from an indirect command file and passes back exit status from remote tasks. All commands are passed to a daemon task that actually links to the remote system. REX only serves to control the daemon. Each daemon has a unique name which is also its task name. To startup a daemon and login on a remote system, use the "-l" or "-h" options. For example, the line: .s.nf rex -l hobbit devsys bilbo pasword .f.s will start a daemon named "hobbit" connected to remote node "devsys" and login using the login name "bilbo" and the password "pasword". The "-l" option is quiet; the logon message is not displayed. The "-h" option displays the message. On a login request, REX will exit with the status returned by the remotely spawned hello task. Other errors, such as an inability to connect to the remote node will return a fatal exit status. Command lines can be sent to an established daemon using the "-s" (spawn) switch. For example, to run a task build through daemon "hobbit" would use the following command: .s.nf rex -s hobbit tkb @build.tkb .f.s Upon completion, the remote TKB exit status becomes the exit status of REX. The "-e" switch is like "-s", however the rex task and daemon do not wait for the spawned task to exit. Note that there is currently no facility to run a remote interactive task. If the remote task issues a read to the daemon, the task will be aborted. The "-b" or "-o" options will log out of a remote system and shut down the associated daemon. The "-o" option is "quiet"; the logoff message is not displayed. The "-b" option displays the logoff message. Bugs No interactive remote tasks. Little or no protection. #endif #include #include #include #include #include "rex.h" #define SD_RAL 1 /* pass all offsping control blocks (for spawncmd) */ #define SPWN_EFN 30 extern int $dsw; extern int $$uic; main(argc, argv) int argc; char *argv[]; { char cmd[80]; /* created command line */ rad50 daemon[2]; /* daemon name in r50 */ switch (parse(daemon, cmd, argc, argv)) { case 'l': exits(login(argv[2], argv[3], argv[4], argv[5], QUIET)); case 'h': exits(login(argv[2], argv[3], argv[4], argv[5], VERBOSE)); case 'b': exits(bye(daemon, QUIET)); case 'o': exits(bye(daemon, VERBOSE)); case 's': exits(spwncm(SPWN_CMD, daemon, cmd)); case 'e': exits(spwncm(EXEC_CMD, daemon, cmd)); default: usage(); } } /* parse - extracts daemon name and command line from argv[]. Returns switch character. */ parse(daetsk, cmdp, argc, argv) rad50 daetsk[]; /* rad50 daemon name to return */ char *cmdp; /* pointer to rest of command line */ int argc; /* arg count */ char *argv[]; /* arg list */ { int i; int argidx; /* index of next arg in argv[] */ int rtnval; if (argc < 2) return(NULL); /* must have atleast 2 args */ if (*argv[1] == '-') { argidx = 2; rtnval = *++argv[1]; /* get switch value */ } else { argidx = 1; rtnval = ' '; /* default to data line */ } ascr50(6, argv[argidx], daetsk); /* convert daemon name */ argidx++; *cmdp = NULL; /* assume no command line */ if (argidx == argc) return(rtnval); strcpy(cmdp, argv[argidx]); for (i = argidx+1; i < argc; i++) { strcat(cmdp, " "); strcat(cmdp, argv[i]); } return(rtnval); } /* login - spawns a new copy of the REXHST task with the requested name * - The command line passed to the daemon contains login data. * - The daemon emits status which is passed to REX's parent. */ login(daemon, node, acnt, pswd, mode) char *daemon; /* desired daemon name in ascii */ char *node; /* remote node to connect to */ char *acnt; /* login name */ char *pswd; /* password */ int mode; /* quiet or verbose */ { word exit_stat[8]; /* returned exit status */ rad50 mcrtsk[2]; /* rad50 mcr... task name */ char cmdlin[80]; /* buffer for daemon command line */ sprintf(cmdlin, "run %s/task=%s/cmd=\"dmn %s %s %s %d\"\033", REX_HOST, daemon, node, acnt, pswd, mode); ascr50(6, "MCR...", mcrtsk); /* convert MCR... name */ if (spwn(&mcrtsk, $$uic, SPWN_EFN, 0, exit_stat, cmdlin, strlen(cmdlin)) != IS_SUC) { tmsg('F', "spwnx error %o\n", ($dsw & 0377)); return(EX$SEV); } wtse(SPWN_EFN); /* wait for daemon to emit status */ return(exit_stat[0]); /* return emitted status */ } bye(daetsk, mode) rad50 daetsk[]; int mode; /* quiet or verbose */ { char temp[8]; /* used for err msg */ struct $sr { /* sr buffer */ int type; } srbuf; zero(temp, sizeof temp); r50toa(temp, daetsk, 2); /* select quiet or verbose mode */ if (mode == QUIET) srbuf.type = BYE; else srbuf.type = QBYE; if (vsda(daetsk, &srbuf, sizeof (struct $sr), 0) != IS_SUC) { zero(temp, sizeof temp); r50toa(temp, daetsk, 2); tmsg('F', "can\'t send bye packet to %s, err %o\n", temp, $dsw); return(EX$SEV); } return(EX$SUC); } spwncm(code, daetsk, cmdp) int code; /* command code, SPWN_CMD or EXEC_CMD */ rad50 daetsk[]; char *cmdp; { word exit_stat[8]; /* returned exit status */ char temp[8]; /* used for err msg */ int stat; /* send status */ struct $sr { /* sr buffer */ int type; char cmdbuf[132]; /* space for command line */ } srbuf; zero(temp, sizeof temp); r50toa(temp, daetsk, 2); srbuf.type = code; strcpy(srbuf.cmdbuf, cmdp); if (code == SPWN_CMD) stat = vsrc(daetsk, &srbuf, (sizeof srbuf)/2, SPWN_EFN, 0, exit_stat); else stat = vsda(daetsk, &srbuf, (sizeof srbuf)/2, 0); if (stat != IS_SUC) { zero(temp, sizeof temp); r50toa(temp, daetsk, 2); tmsg('F', "can\'t send data packet to %s, err %o\n", temp, $dsw); return(EX$SEV); } if (code == SPWN_CMD) { wtse(SPWN_EFN); /* wait for daemon to emit status */ return(exit_stat[0]); /* return emitted status */ } else return(EX$SUC); } usage() { tmsg('F',"usage: rex [-lbse] command line\n"); exits(EX$SEV); }