#include <stdio.h> #include <errno.h> #include <dk.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/filio.h> #include <sys/ttyio.h> #include <sys/stream.h> #include <signal.h> /* * program to run a command * on another cpu on Datakit w/ transparent ioctls, * sometimes. */ #define msglen(mp) ((mp)->losize + ((mp)->hisize<<8)) int rem; /* remote file descriptor */ extern int mesg_ld; extern errno; extern char *dkerror; int nomesg; #define MAXCHARS 8192 char args[MAXCHARS]; char *bldargs(argv) register char *argv[]; { register char *s=args, *t; while(t= *argv++){ /* assignment = */ while(*s = *t++) if(s++ >= &args[MAXCHARS-1]){ fprintf(stderr, "rx: arg list too long\n"); exit(1); } *s++=' '; } s[-1]='\0'; return(args); } char * basename(s) register char *s; { register char *t; extern char *rindex(); t=rindex(s, '/'); return(t? t+1 : s); } setmsgl(mp, n) register struct mesg *mp; int n; { mp->losize = n; mp->hisize = n >> 8; } finish() { if(ioctl(0, FIOLOOKLD, 0) == mesg_ld) { ioctl(0, FIOPOPLD, 0); ioctl(0, TIOCFLUSH, 0); } exit(0); } main(argc, argv) char **argv; { char *host, *cmd; host = cmd = basename(argv[0]); if(strcmp(host, "rx")==0 || strcmp(host, "rexec")==0 || strcmp(host, "nrx")==0){ host=argv[1]; argv++; } if(host==0){ fprintf(stderr, "usage: %s host [command]\n", cmd); exit(1); } if(argv[1]==0){ execl("/usr/bin/ndcon", argv[1], argv[1], (char *)0); perror("ndcon"); exit(1); } rem = mesgexec(host, bldargs(&argv[1])); if (rem<0) { fprintf(stderr, "%s: call to %s failed: %s\n", cmd , host, dkerror); exit(1); } setmesg(); signal(SIGHUP, finish); signal(SIGPIPE, SIG_IGN); go(rem); finish(); /* NOTREACHED */ } /* * if standard input and output are the same, * try to push the message line discipline * otherwise we're in a pipeline and it's not safe */ setmesg() { struct stat st0, st1; if (fstat(0, &st0) < 0 || fstat(1, &st1) < 0 || st0.st_dev != st1.st_dev || st0.st_ino != st1.st_ino) { nomesg = 1; return; } if(ioctl(0, FIOPUSHLD, &mesg_ld) < 0) nomesg = 1; } /* * hack: * until some message comes back from the remote, * ignore local data */ go(fd) { int rbits, wbits, srbits; int n; char buf[4096+MSGHLEN]; struct mesg *mp; int first = 0; mp = (struct mesg *) buf; wbits = 0; srbits = (1<<0)|(1<<fd); while(1){ rbits = srbits; if(select(20, &rbits, &wbits, 20000) < 0){ if(errno != EINTR) return; continue; } if(rbits & 1){ n = rdmesg(0, buf, sizeof(buf)); if(n <= 0) { srbits &=~ 1; continue; } mp->magic = MSGMAGIC; /* temporary safety */ if(write(fd, buf, n) != n) return; if(mp->type == M_FLUSH) remflush(); } if(rbits & (1<<fd)){ n = read(fd, buf, sizeof(buf)); if(n <= 0) return; if(mp->type == M_HANGUP) return; if(mp->type == M_IOCTL){ doioctl(buf, n); } else { mp->magic = MSGMAGIC; /* temp safety */ if(wrmesg(1, buf, n) != n) return; } } } } #define MAXEOF 10 rdmesg(f, buf, n) char *buf; { register struct mesg *mp; static int eof = 0; if (nomesg == 0) return (read(f, buf, n)); if (eof > MAXEOF) return (0); n = read(f, buf + MSGHLEN, n - (2 * MSGHLEN)); if (n < 0) return (n); mp = (struct mesg *)buf; if (n == 0) { eof++; mp->type = M_DELIM; mp->magic = MSGMAGIC; setmsgl(mp, 0); return (MSGHLEN); } eof = 0; setmsgl(buf, n); mp->type = M_DATA; mp->magic = MSGMAGIC; mp = (struct mesg *)(buf + MSGHLEN + n); mp->type = M_DELIM; mp->magic = MSGMAGIC; setmsgl(buf, 0); return (n + 2*MSGHLEN); } wrmesg(f, buf, n) char *buf; { if (nomesg == 0) return (write(f, buf, n)); if (((struct mesg *)buf)->type != M_DATA) return (n); /* toss it */ if (write(f, buf + MSGHLEN, n - MSGHLEN) != n - MSGHLEN) return (-1); return (n); } doioctl(buf, n) char *buf; { struct mesg *mp; struct iofoo{ int cmd; union{ int i; char errno; struct insld insld; } u; } *iop; int cmd, ld; iop = (struct iofoo *)(buf + MSGHLEN); mp = (struct mesg *) buf; if (nomesg) { errno = ENOTTY; goto bad; } cmd = iop->cmd; n -= MSGHLEN; n -= sizeof(iop->cmd); switch(cmd){ case FIOLOOKLD: if(n > 0) ld = iop->u.i; else ld = 0; ld++; if(ioctl(1, FIOLOOKLD, &ld) < 0) goto bad; iop->cmd = ld; n = sizeof(iop->cmd); break; case FIOPOPLD: if(n > 0) ld = iop->u.i; else ld = 0; ld++; if(ioctl(1, FIOPOPLD, &ld) < 0) goto bad; n = 0; break; case FIOPUSHLD: iop->u.insld.level = 0; /* fall through... */ case FIOINSLD: iop->u.insld.level++; if(ioctl(1, FIOINSLD, &(iop->u.insld)) < 0) goto bad; n = 0; break; default: mp->magic = MSGMAGIC; /* safety */ write(1, buf, MSGHLEN + msglen(mp)); return; } /* locally successful */ mp->type = M_IOCACK; mp->magic = MSGMAGIC; setmsgl(mp, n); write(rem, buf, MSGHLEN + msglen(mp)); return; bad: mp->type = M_IOCNAK; mp->magic = MSGMAGIC; setmsgl(mp, sizeof(struct iofoo)); iop->u.errno = errno; n = write(rem, buf, MSGHLEN + msglen(mp)); } remflush() { char buf[5000]; struct mesg *mp; int n; mp = (struct mesg *) buf; mp->type = M_IOCTL; mp->magic = MSGMAGIC; setmsgl(mp, sizeof(int)); write(rem, buf, MSGHLEN + msglen(mp)); while((n = read(rem, buf, sizeof(buf))) > 0){ if(mp->type == M_IOCNAK || mp->type == M_IOCACK){ return; } } }