/* r e x r m t -- rex remote server */ #ifdef DOCUMENTATION title rexrmt remote object for rex (Remote EXecute) system index rexrmt remote object for rex (Remote EXecute) system synopsis ins rexrmt/task=rex$$$ ncp set object 129 name rex$$$ copies 4 description Remote side of REX facility. Provides a VT: to run tasks for a daemon on another node. bugs edit history .s.nf 06 01/13/86 hjj Allocated fixed buffer for vt: qio's rather than malloc(). May cure parent aborts on child aborts. 05 1/3/85 brake out rex.h stuff and eliminated protocol version check 04 1/2/86 gwm added QUIET and VERBOSE modes for login/logout 03 11/26/85 hjj changed to quiet logout 02 11/26/85 hjj changed to quiet login 01 11/17/85 hjj moved esb's off stack for spawn requests .s.f #endif #include #include #include #include #include #include #include "rex.h" #define IE_DAO 0363 /* transfer rejected */ #define IE_REJ 0250 /* transfer rejected */ #define IE_DSQ 0246 /* disk quota exceed, tried to put too much */ #define IE_EOF 0366 /* end of file */ #define SIG_EFN 29 /* efn used to signal packet availible */ #define SPW_EFN 28 /* efn used for spawn */ #define EXE_EFN 27 /* efn used for execute spawn */ #define AST_EFN 26 /* efn used during ast's for net fcns */ #define VTB_LEN 255 /* vt buffer len */ static struct $RX_SPAWN net_pkt; /* host receive packet */ extern int $dsw; extern int $$nerr; extern int $$nlun; /* number of luns available */ static NIOV *np; static NIOV ast_niov; /* niov for ast state calls */ static NIOV *ast_np; /* niov pointer for ast's */ static struct timbuf timstamp; extern char $$task[]; static int vt_lun; /* lun for vt */ static int vt_unit; /* unit number to use */ static word vt = 052126; /* "VT" */ static word stopper = 0; static word spwn_stat[8]; /* est for RXSPWN */ static word exe_stat[8]; /* esb for RXEXEC */ static int tty_on = QUIET; /* set to VERBOSE when vt output allowed */ static char vt_buf[VTB_LEN]; /* buffer for vt qio's */ int $$nargs = 1; main() { int netmsg(); int len; if(!opn_net(netmsg)) { tmsg('F', "open net failed nerr %d\n", $$nerr); exits(4); } wtse(10); /* wait for attach from other task */ while ((len = get_net(&net_pkt, sizeof net_pkt, np)) != NULL) { switch(net_pkt.type) { /* whats the message code */ case RXQHELLO: hello(&net_pkt, QUIET); break; case RXHELLO: hello(&net_pkt, VERBOSE); break; case RXSPAWN: spwn_cmd(1, &net_pkt); break; case RXBYE: bye(VERBOSE); break; case RXQBYE: bye(QUIET); break; case RXEXEC: spwn_cmd(0, &net_pkt); break; default: badmsg(net_pkt.type); } zero(&net_pkt, sizeof net_pkt); $$nerr = 0; len = 1; } finish(1); } static hello(hel_p, mode) struct $RX_HELLO *hel_p; int mode; /* quiet or verbose */ { char cmd[132]; int i; /* log in */ tty_on = mode; sprintf(cmd, "HELLO %s/%s\n", hel_p->acnt, hel_p->pswd); for (i = 0; i < strlen(cmd); i++) cmd[i] = toupper(cmd[i]); if (vtlogin("...HEL", cmd) != IS_SUC) { hostmsg('F', "couldn\'t log in\n"); r_emst(EX$SEV); /* tell host login failed */ finish(EX$SEV); } r_emst(EX$SUC); /* tell host login ok */ tty_on = VERBOSE; } static spwn_cmd(wait_flag, spw_p) int wait_flag; /* if 1, wait for task to emit status */ struct $RX_SPAWN *spw_p; { rad50 tname[2]; /* name of task to spawn */ int status; char tasknm[8]; /* task name to spawn */ /* spawn command line */ strcpy(tasknm, spw_p->task); ascr50(6, "MCR...", tname); /* convert to rad50 */ if (wait_flag) status = spwnx(&tname, 0, SPW_EFN, 0, spwn_stat, spw_p->cmdlin, strlen(spw_p->cmdlin), vt_unit, vt); else status = spwnx(&tname, 0, EXE_EFN, 0, exe_stat, spw_p->cmdlin, strlen(spw_p->cmdlin), vt_unit, vt); if (status != IS_SUC) { /* should be good */ hostmsg('F', "spwnx error %o task %s cmd <%s>\n", (status & 0377), tasknm, spw_p->cmdlin); r_emst(EX$SEV); } if (wait_flag) { wtse(SPW_EFN); r_emst(spwn_stat[0]); } else r_emst(EX$SUC); return; } static bye(mode) int mode; /* quiet or verbose */ { struct $RX_SPAWN bye_p; /* log out */ strcpy(bye_p.task, "BYE"); sprintf(bye_p.cmdlin, "BYE"); tty_on = mode; /* turn off logout messages if quiet */ spwn_cmd(1, &bye_p); finish(EX$SUC); } /* VT stuff ------------------------------------------------------ */ static vtlogin(task, cmdlin) char *task; /* task name to execute */ char *cmdlin; /* command line for task */ { word tname[2]; int status; if (cre_vt() != 1) { /* create a virtual terminal */ hostmsg('F', "cre_vt error %o\n", $dsw); finish(EX$SEV); } ascr50(6, task, tname); status = spwnx(&tname, 0, SPW_EFN, 0, spwn_stat, cmdlin, strlen(cmdlin), vt_unit, vt); if (status != IS_SUC) { hostmsg('F', "spwnx error %o\n", (status & 0377)); finish(EX$SEV); } status = wtse(SPW_EFN); return(spwn_stat[0]); } static cre_vt() /* create a virtual terminal */ { int status; unsigned *lp, *a_lun(); int in_ast(), out_ast(), at_ast(); if ((lp = a_lun(&vt_lun)) != NULL) *lp = stdin; /* mark in use */ else { $dsw = IE_ILU; return(NULL); } if ((vt_unit = crvt(&in_ast, &out_ast, 0, VTB_LEN)) <= 0) { tmsg('F', "error %o creating virtual terminal\n", (vt_unit & 0377)); return(0); } if ((status = alun(vt_lun, vt, vt_unit)) != IS_SUC) { tmsg('F', "alun failed for %s%o:, dsw = %o\n", &vt, vt_unit, (status & 0377)); return(0); } return(1); } static int out_ast() { int status; word vtr_parms[6]; int vt_iosb[2]; astset(); vtr_parms[1] = gtdp(1); /* get VT requested byte count */ if (vtr_parms[1] <= 0) { hostmsg('E', "VT req byte count %o\n", vtr_parms[1]); /* finish(EX$SEV); */ astx(3); } if (vtr_parms[1] > 0) { /* allocate a buffer */ if (vtr_parms[1] > VTB_LEN) { hostmsg('F', "vt req. larger than buffer, %o bytes requested\n", vtr_parms[1]); vtr_parms[1] = VTB_LEN - 1; } vtr_parms[0] = vt_buf; } vtr_parms[2] = IS_SUC; /* say xfr is sucessfull */ vtr_parms[3] = vtr_parms[4] = vtr_parms[5] = 0; /* issue write request to controlling terminal */ status = qiow(IO_RVB, vt_lun, vt_lun, &vt_iosb, 0, &vtr_parms); if (status != IS_SUC) { hostmsg('F', "VT read QIOW failed with error %o\n", (status & 0377)); /* finish(EX$SEV); */ astx(3); } if (vt_iosb[0] < 0) { hostmsg ('F', "I/O error %o reading VT:\n", (vt_iosb[0] & 0377)); /* finish(EX$SEV); */ astx(3); } if ((tty_on == VERBOSE) && (vt_iosb[1] > 0)) ttynet(vt_buf, vt_iosb[1], gtdp(2)); /* send to host */ astx(3); } static int at_ast() { astset(); astx(3); } static int in_ast() /* vt wants input. get buffer and transfer down */ { int status; word in_parms[6]; /* in_ast qio param block */ int vt_iosb[2]; /* io status block */ astset(); in_parms[0] = 1; /* cb = 1, return read status */ in_parms[1] = 0; /* sw2, 0 byte count */ in_parms[2] = IE_EOF; /* say ^z to VT */ status = qiow(IO_STC, vt_lun, vt_lun, &vt_iosb, 0, &in_parms); if (status != IS_SUC) { tmsg('F', "VT STC QIOW failed with error %o\n", (status & 0377)); finish(EX$SEV); } if (vt_iosb[0] < 0) { tmsg ('F', "I/O error %o writing VT:\n", (vt_iosb[0] & 0377)); finish(EX$SEV); } astx(3); } static unsigned *a_lun(lnum) int *lnum; { unsigned *lp; /* lun address pointer */ int lcnt; lp = $$luns; for (lcnt = 0; lcnt < $$nlun; lcnt++, lp++) if (*lp == NULL) { *lnum = lcnt + 2; /* free luns start at lun 2 */ return(lp); } return(NULL); } /* Network stuff ---------------------------------------------------- */ static r_emst(exstat) /* retrun exit stat to host */ int exstat; { struct $RX_EXSTAT exst_p; /* initial packet */ dsar(); exst_p.vers = RXVERSN; exst_p.type = RXEMIT; exst_p.ex_stat = exstat; if (put_net(&exst_p, sizeof exst_p, np) == NULL) { tmsg('F', "couldn\'t send exst packet err %o\n", $$nerr); finish(EX$SEV); } enar(); } static hostmsg(svr, argl) int svr; /* severity char */ { char outbuf[132]; $$rtime(&timstamp); sprintf(outbuf, "\n%02d:%02d:%02d %s-%c-%r", timstamp.g_tihr, timstamp.g_timi, timstamp.g_tisc, $$task, svr, &argl); ttynet(outbuf, strlen(outbuf), " "); /* return message to host */ } static ttynet(tbuf, len, vfc) /* return tty buf to host */ char *tbuf; int len; char vfc; { struct $RX_TTYO ttyo_p; /* initial packet */ dsar(); /* let code finish */ ttyo_p.vers = RXVERSN; ttyo_p.type = RXTTYO; ttyo_p.buflen = len; ttyo_p.vfc = vfc; if (put_net(&ttyo_p, sizeof ttyo_p, ast_np) == NULL) { tmsg('F', "couldn\'t send ttyo packet err %o\n", ast_np->iosb[0]); finish(EX$SEV); } if (put_net(tbuf, len, ast_np) == NULL) { tmsg('F', "couldn\'t send tbuf packet err %o\n", ast_np->iosb[0]); finish(EX$SEV); } enar(); /* let asts in */ } badmsg(p) int *p; { tmsg('M', "bad message code %o \n", *p); } netmsg(code, acp) char code[4]; /* message type code */ struct a_conblk *acp; /* pointer to received message */ { switch (code[1]) { case NT_CON: { accept(acp); setf(10); break; } case NT_INT: { break; } case NT_DSC: { finish(4); } case NT_ABT: { finish(4); } case NT_ABO: { finish(4); } default: { tmsg('W', "unexpected msg %d msglen %d lun %d\n", code[1], code[2], code[3]); } } return(1); } accept(ap) struct a_conblk *ap; /* pointer to received message */ { NIOV *acc_net(); if ((np = acc_net(ap)) == NULL) { tmsg('E', "accnt failed, err %o\n", $$nerr); return(0); } ast_np = &ast_niov; /* set up alternate pointer */ copy(ast_np, np, sizeof (struct niov)); ast_np->efn = AST_EFN; } finish(stat) /* close everything and exit with status = stat */ int stat; { dsc_net(np); cls_net(); exits(stat); }