winkler@harvard.ARPA (Dan Winkler) (11/07/84)
From ihnp4!bradley!brad Sat Nov 3 09:41:52 1984 Date: 3 Nov 84 06:26:33 CST (Sat) Received: by ihnp4.ATT.UUCP; id AA25822; 3 Nov 84 06:26:33 CST (Sat) Subject: Re: Hayes driver for cu? In-Reply-To: Your message of Fri, 2 Nov 84 10:29:44 cst To: ihnp4!ut-sally!harvard!winkler Status: R I am glad to see you got the message, I got somthing that says it didn't go through. But anyways, here is the program. I run 2.9 on a 11/44, and the /dev/ttyhayes (/dev/ttyie) on my machine is active because other computers call me on that line. I have a shell script that I run to disable the line, run the program and when done, enable the program. If you want the enable & disable program (written in 'C') which works with 2.9 let me know. Bradley Smith UUCP: {cepu,ihnp4,noao,uiucdcs}!bradley!brad Text Processing ARPA: cepu!bradley!brad@UCLA-LOCUS Bradley University PH: (309) 676-7611 Ext. 446 Peoria, IL 61625 ===================================cut here with laser gun ==================== #include <whoami.h> #include <stdio.h> #include <signal.h> #include <sgtty.h> /* * defs that come from uucp.h */ #define NAMESIZE 35 #define FAIL -1 #define SAME 0 #define SLCKTIME 5400 /* system/device timeout (LCK.. files) in seconds */ #define ASSERT(e, f, v) if (!(e)) {\ fprintf(stderr, "AERROR - (%s) ", "e");\ fprintf(stderr, f, v);\ cleanup(FAIL);\ } /* * cu telno [-t] [-s speed] [-l line] [-a acu] [-p] * * -t is for dial-out to terminal. * speeds are: 110, 134, 150, 300, 1200, 2400. 300 is default. * * -p says strip parity of characters transmitted. (to compensate * for c100's) * * Escape with `~' at beginning of line. * Ordinary diversions are ~<, ~> and ~>>. * Silent output diversions are ~>: and ~>>:. * Terminate output diversion with ~> alone. * Quit is ~. and ~! gives local command or shell. * Also ~$ for canned procedure pumping remote. * ~%put from [to] and ~%take from [to] invoke builtins */ #define CRLF "\r\n" #define wrc(ds) write(ds,&c,1) char *devcul = "/dev/ttyhayes"; char *devcua = "/dev/ttyhayes"; char *lspeed = "300"; int ln; /* fd for comm line */ char tkill, terase; /* current input kill & erase */ int notabs; /* terminal doesn't expand tabs */ int efk; /* process of id of listener */ char c; char oc; char *connmsg[] = { "", "line busy", "call dropped", "no carrier", "can't fork", "acu access", "tty access", "tty hung", "usage: cu telno [-t] [-p] [-h] [-b] [-acu#] [-s speed] [-l line] [-a acu]", "lock failed: line busy" }; rdc(ds) { ds=read(ds,&oc,1); c = oc & 0177; return (ds); } int intr; sig2() { signal(SIGINT, SIG_IGN); intr = 1; } int set14; xsleep(n) { xalarm(n); pause(); xalarm(0); } xalarm(n) { set14=n; alarm(n); } sig14() { signal(SIGALRM, sig14); if (set14) alarm(1); } int dout; int nhup; int dbflag; int pflag; /* strip parity on chars sent to remote */ int hdplx; /* set to emulate half-duplex terminal */ int nullbrk; /* turn breaks (nulls) into dels */ int pipes[2] = { -1, -1 }; int speed; /* * main: get connection, set speed for line. * spawn child to invoke rd to read from line, output to fd 1 * main line invokes wr to read tty, write to line */ main(ac,av) char *av[]; { int fk; char *telno = NULL; struct sgttyb stbuf; char hayesret[3]; int cleanup(); signal(SIGALRM, sig14); nhup = (int)signal(SIGINT, cleanup); signal(SIGHUP, cleanup); signal(SIGQUIT, cleanup); if (ac < 2) { prf(connmsg[8]); exit(8); } for (; ac > 1; av++,ac--) { if (av[1][0] != '-') telno = av[1]; else switch(av[1][1]) { case 't': dout = 1; continue; case 'b': nullbrk++; continue; case 'd': dbflag++; continue; case 'h': hdplx++; continue; case 'p': pflag++; continue; case 's': lspeed = av[2]; ++av; --ac; break; case 'l': devcul = av[2]; ++av; --ac; break; case 'a': devcua = av[2]; ++av; --ac; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': devcua[strlen(devcua)-1] = av[1][1]; devcul[strlen(devcul)-1] = av[1][1]; break; default: prf("Bad flag %s", av[1]); break; } } if (telno == NULL) { prf(connmsg[8]); exit(8); } if (!exists(devcua) || !exists(devcul)) exit(9); switch(atoi(lspeed)) { case 110: speed = B110;break; case 150: speed = B150;break; default: case 300: speed = B300;break; case 1200: speed = B1200;break; case 2400: speed = B2400;break; } ln = open(devcul, 2); if (ln < 0) { prf("Connect failed:"); cleanup(-ln); } ioctl(0, TIOCGETP, &stbuf); notabs = stbuf.sg_flags & XTABS; stbuf.sg_ispeed = speed; stbuf.sg_ospeed = speed; stbuf.sg_flags = EVENP|ODDP; if (!dout) stbuf.sg_flags |= RAW | TANDEM; ioctl(ln, TIOCSETP, &stbuf); ioctl(ln, TIOCEXCL, (struct sgttyb *)NULL); ioctl(ln, TIOCHPCL, (struct sgttyb *)NULL); write(ln,"\rAT DT ", 7); write(ln,telno, strlen(telno)); write(ln,"\r", 1); read(ln,hayesret,2); switch(hayesret[0]) { case '2': case '4': case '3': printf("Hayes Returned %c\n", hayesret[0]); printf("Connect failed\n"); cleanup(3); } prf("Connected"); pipe(pipes); if (dout) fk = -1; else fk = fork(); signal(SIGINT, SIG_IGN); if (fk == 0) { chwrsig(); rd(); prf("\007Lost carrier"); cleanup(3); } mode(1); efk = fk; wr(); mode(0); /* hang up hayes */ if (fk != -1) kill(fk, SIGKILL); wait((int *)NULL); write(ln,"+++",3); sleep(3); write(ln,"ATH\r",4); stbuf.sg_ispeed = 0; stbuf.sg_ospeed = 0; ioctl(ln, TIOCSETP, &stbuf); prf("Disconnected"); cleanup(0); } /* * wr: write to remote: 0 -> line. * ~. terminate * ~<file send file * ~! local login-style shell * ~!cmd execute cmd locally * ~$proc execute proc locally, send output to line * ~%cmd execute builtin cmd (put and take) * ~# send 1-sec break * ~^Z suspend cu process. */ wr() { int ds,fk,lcl,x; char *p,b[600]; for (;;) { p=b; while (rdc(0) == 1) { if (p == b) lcl=(c == '~'); if (p == b+1 && b[0] == '~') lcl=(c!='~'); if (nullbrk && c == 0) oc=c=0177; /* fake break kludge */ if (!lcl) { if(!pflag)c = oc; if (wrc(ln) == 0) { prf("line gone"); return; } if (hdplx) wrc(0); c &= 0177; } if (lcl) { if (c == 0177) c=tkill; if (c == '\r' || c == '\n') goto A; if (!dout) wrc(0); } *p++=c; if (c == terase) { p=p-2; if (p<b) p=b; } if (c == tkill || c == 0177 || c == '\4' || c == '\r' || c == '\n') p=b; } return; A: if (!dout) echo(""); *p=0; switch (b[1]) { case '.': case '\004': return; #ifdef TIOCSBRK case '#': if (ioctl(ln, TIOCSBRK, 0) < 0) prf("can't send break"); else { sleep(1); ioctl(ln, TIOCCBRK, 0); continue; } #endif case '!': case '$': fk = fork(); if (fk == 0) { char *getenv(); char *shell = getenv("SHELL"); if (shell == 0) shell = "/bin/sh"; close(1); dup(b[1] == '$'? ln:2); close(ln); mode(0); if (!nhup) signal(SIGINT, SIG_DFL); if (b[2] == 0) execl(shell,shell,0); /* if (b[2] == 0) execl(shell,"-",0); */ else execl(shell,"sh","-c",b+2,0); prf("Can't execute shell"); exit(~0); } if (fk!=(-1)) { while (wait(&x)!=fk); } mode(1); if (b[1] == '!') echo("!"); else { if (dout) echo("$"); } break; case '<': if (b[2] == 0) break; if ((ds=open(b+2,0))<0) { prf("Can't divert %s",b+1); break; } intr=x=0; mode(2); if (!nhup) signal(SIGINT, sig2); while (!intr && rdc(ds) == 1) { if (wrc(ln) == 0) { x=1; break; } } signal(SIGINT, SIG_IGN); close(ds); mode(1); if (x) return; if (dout) echo("<"); break; case '>': case ':': { register char *q; if(pipes[1]==-1) { prf("Can't tell other demon to divert"); break; } q = b+1; if(*q=='>') q++; write(pipes[1],q,strlen(q)+1); if(dbflag) prf("msg to be delivered:"),prf(q); if (efk != -1) kill(efk,SIGEMT); } break; #ifdef SIGTSTP #define CTRLZ 26 case CTRLZ: mode(0); kill(getpid(), SIGTSTP); mode(1); break; #endif case '%': dopercen(&b[2]); break; default: prf("Use `~~' to start line with `~'"); } continue; } } dopercen(line) register char *line; { char *args[10]; register narg, f; int rcount; for (narg = 0; narg < 10;) { while(*line == ' ' || *line == '\t') line++; if (*line == '\0') break; args[narg++] = line; while(*line != '\0' && *line != ' ' && *line != '\t') line++; if (*line == '\0') break; *line++ = '\0'; } if (equal(args[0], "take")) { if (narg < 2) { prf("usage: ~%%take from [to]"); return; } if (narg < 3) args[2] = args[1]; write(pipes[1], ">/dev/null",sizeof(">/dev/null")); if(dbflag) prf("sending take message"); if (efk != -1) kill(efk,SIGEMT); xsleep(5); if (notabs) wrln("stty tabs;"); wrln("echo '~>:"); wrln(args[2]); wrln("'; tee /dev/null <"); wrln(args[1]); wrln(";echo '~>'"); if (notabs) wrln(";stty -tabs"); wrln("\n"); return; } else if (equal(args[0], "put")) { if (narg < 2) { prf("usage: ~%%put from [to]"); return; } if (narg < 3) args[2] = args[1]; if ((f = open(args[1], 0)) < 0) { prf("cannot open: %s", args[1]); return; } wrln("stty -echo;cat >"); wrln(args[2]); wrln(";stty echo\n"); xsleep(5); intr = 0; if (!nhup) signal(SIGINT, sig2); mode(2); rcount = 0; while(!intr && rdc(f) == 1) { rcount++; if (c == tkill || c == terase) wrln("\\"); if (wrc(ln) != 1) { xsleep(2); if (wrc(ln) != 1) { prf("character missed"); intr = 1; break; } } } signal(SIGINT, SIG_IGN); close(f); if (intr) { wrln("\n"); prf("stopped after %d bytes", rcount); } wrln("\004"); xsleep(5); mode(1); return; } prf("~%%%s unknown\n", args[0]); } equal(s1, s2) register char *s1, *s2; { while (*s1++ == *s2) if (*s2++ == '\0') return(1); return(0); } wrln(s) register char *s; { while (*s) write(ln, s++, 1); } /* chwrsig: Catch orders from wr process * to instigate diversion */ int whoami; chwrsig(){ int readmsg(); whoami = getpid(); signal(SIGEMT,readmsg); } int ds,slnt,taking; int justrung; readmsg(){ static char dobuff[128], morejunk[256]; int n; justrung = 1; signal(SIGEMT,readmsg); if(dbflag) { prf("About to read from pipe"); } n = read(pipes[0],morejunk,256); if(dbflag) { prf("diversion mesg recieved is"); prf(morejunk); prf(CRLF); } dodiver(morejunk); } dodiver(msg) char *msg; { register char *cp = msg; if (*cp=='>') cp++; if (*cp==':') { cp++; if(*cp==0) { slnt ^= 1; return; } else { slnt = 1; } } if (ds >= 0) close(ds); if (*cp==0) { slnt = 0; ds = -1; return; } if (*msg!='>' || (ds=open(cp,1))<0) ds=creat(cp,0644); lseek(ds, (long)0, 2); if(ds < 0) prf("Creat failed:"), prf(cp); if (ds<0) prf("Can't divert %s",cp+1); } /* * rd: read from remote: line -> 1 * catch: diversion caught by interrupt routine */ #define ORDIN 0 #define SAWCR 1 #define EOL 2 #define SAWTL 3 #define DIVER 4 rd() { extern int ds,slnt; char rb[600], lb[600], *rlim, *llim, c; register char *p,*q; int cnt, state = ORDIN, mustecho, oldslnt; ds=(-1); p = lb; llim = lb+600; agin: while((cnt = read(ln,rb,600)) > 0) { if(!slnt) { if (pflag) for (q=rb, rlim = rb + cnt - 1; q <= rlim; ) *q++ &= 0177; write(1,rb,cnt); } if(ds < 0) continue; oldslnt = slnt; for( q=rb, rlim = rb + cnt - 1; q <= rlim; ) { c = *q++ & 0177; if(p < llim) *p++ = c; switch(state) { case ORDIN: if(c=='\r') state = SAWCR; break; case SAWCR: if(c=='\n') { state = EOL; p--; p[-1] = '\n'; } else state = ORDIN; break; case EOL: state = (c=='~' ? SAWTL : (c=='\r' ? SAWCR : ORDIN)); break; case SAWTL: state = (c=='>' ? DIVER : (c=='\r' ? SAWCR : ORDIN)); break; case DIVER: if(c=='\r') { p--; } else if (c=='\n') { state = ORDIN; p[-1] = 0; dodiver(lb+2); c = 0; p = lb; } } if(slnt==0 && oldslnt) { if(c=='\n') { write(1,lb,p-lb-1); write(1,CRLF,sizeof(CRLF)); } else if(q==rlim) { write(1,lb,p-lb); c = '\n'; /*force flush to file*/ } } if(c=='\n') { if(ds >= 0) write(ds,lb,p-lb); p = lb; } } } goto agin; } struct {char lobyte; char hibyte;}; mode(f) { struct sgttyb stbuf; if (dout) return; ioctl(0, TIOCGETP, &stbuf); tkill = stbuf.sg_kill; terase = stbuf.sg_erase; if (f == 0) { stbuf.sg_flags &= ~RAW; stbuf.sg_flags |= ECHO|CRMOD; } if (f == 1) { stbuf.sg_flags |= RAW; stbuf.sg_flags &= ~(ECHO|CRMOD); } if (f == 2) { stbuf.sg_flags &= ~RAW; stbuf.sg_flags &= ~(ECHO|CRMOD); } ioctl(0, TIOCSETP, &stbuf); } echo(s) char *s; { char *p; for (p=s;*p;p++); if (p>s) write(0,s,p-s); write(0,CRLF, sizeof(CRLF)); } prf(f, s) char *f; char *s; { fprintf(stderr, f, s); fprintf(stderr, CRLF); } exists(devname) char *devname; { if (access(devname, 0)==0) return(1); prf("%s does not exist", devname); return(0); } cleanup(code) { rmlock(NULL); ioctl(ln, TIOCNXCL, (struct sgttyb *)NULL); exit(code); } /* * This code is taken directly from uucp and follows the same * conventions. This is important since uucp and cu should * respect each others locks. */ /* ulockf 3.2 10/26/79 11:40:29 */ /* #include "uucp.h" */ #include <sys/types.h> #include <sys/stat.h> /******* * ulockf(file, atime) * char *file; * time_t atime; * * ulockf - this routine will create a lock file (file). * If one already exists, the create time is checked for * older than the age time (atime). * If it is older, an attempt will be made to unlink it * and create a new one. * * return codes: 0 | FAIL */ ulockf(file, atime) char *file; time_t atime; { struct stat stbuf; time_t ptime; int ret; static int pid = -1; static char tempfile[NAMESIZE]; if (pid < 0) { pid = getpid(); sprintf(tempfile, "/usr/spool/uucp/LTMP.%d", pid); } if (onelock(pid, tempfile, file) == -1) { /* lock file exists */ /* get status to check age of the lock file */ ret = stat(file, &stbuf); if (ret != -1) { time(&ptime); if ((ptime - stbuf.st_ctime) < atime) { /* file not old enough to delete */ return(FAIL); } } ret = unlink(file); ret = onelock(pid, tempfile, file); if (ret != 0) return(FAIL); } stlock(file); return(0); } #define MAXLOCKS 10 /* maximum number of lock files */ char *Lockfile[MAXLOCKS]; int Nlocks = 0; /*** * stlock(name) put name in list of lock files * char *name; * * return codes: none */ stlock(name) char *name; { char *p; extern char *calloc(); int i; for (i = 0; i < Nlocks; i++) { if (Lockfile[i] == NULL) break; } ASSERT(i < MAXLOCKS, "TOO MANY LOCKS %d", i); if (i >= Nlocks) i = Nlocks++; p = calloc(strlen(name) + 1, sizeof (char)); ASSERT(p != NULL, "CAN NOT ALLOCATE FOR %s", name); strcpy(p, name); Lockfile[i] = p; return; } /*** * rmlock(name) remove all lock files in list * char *name; or name * * return codes: none */ rmlock(name) char *name; { int i; for (i = 0; i < Nlocks; i++) { if (Lockfile[i] == NULL) continue; if (name == NULL || strcmp(name, Lockfile[i]) == SAME) { unlink(Lockfile[i]); free(Lockfile[i]); Lockfile[i] = NULL; } } return; } /* this stuff from pjw */ /* /usr/pjw/bin/recover - check pids to remove unnecessary locks */ /* isalock(name) returns 0 if the name is a lock */ /* unlock(name) unlocks name if it is a lock*/ /* onelock(pid,tempfile,name) makes lock a name on behalf of pid. Tempfile must be in the same file system as name. */ /* lock(pid,tempfile,names) either locks all the names or none of them */ isalock(name) char *name; { struct stat xstat; if(stat(name,&xstat)<0) return(0); if(xstat.st_size!=sizeof(int)) return(0); return(1); } unlock(name) char *name; { if(isalock(name)) return(unlink(name)); else return(-1); } onelock(pid,tempfile,name) char *tempfile,*name; { int fd; fd=creat(tempfile,0444); if(fd<0) return(-1); write(fd,(char *) &pid,sizeof(int)); close(fd); if(link(tempfile,name)<0) { unlink(tempfile); return(-1); } unlink(tempfile); return(0); } lock(pid,tempfile,names) char *tempfile,**names; { int i,j; for(i=0;names[i]!=0;i++) { if(onelock(pid,tempfile,names[i])==0) continue; for(j=0;j<i;j++) unlink(names[j]); return(-1); } return(0); } #define LOCKPRE "/usr/spool/uucp/LCK." /*** * delock(s) remove a lock file * char *s; * * return codes: 0 | FAIL */ delock(s) char *s; { char ln[30]; sprintf(ln, "%s.%s", LOCKPRE, s); rmlock(ln); } /*** * mlock(sys) create system lock * char *sys; * * return codes: 0 | FAIL */ mlock(sys) char *sys; { char lname[30]; sprintf(lname, "%s.%s", LOCKPRE, sys); return(ulockf(lname, (time_t) SLCKTIME ) < 0 ? FAIL : 0); } /*** * ultouch() update access and modify times for lock files * * return code - none */ ultouch() { time_t time(); int i; struct ut { time_t actime; time_t modtime; } ut; ut.actime = time(&ut.modtime); for (i = 0; i < Nlocks; i++) { if (Lockfile[i] == NULL) continue; utime(Lockfile[i], &ut); } return; }
karsh@geowhiz.UUCP (Bruce Karsh) (11/11/84)
> Subject: Re: Hayes driver for cu?
This program does not put out a lock file for uucp.
--
Bruce Karsh ---------------------------
Univ. Wisconsin Dept. of Geology and Geophysics | |
1215 W Dayton, Madison, WI 53706 | THIS SPACE FOR RENT |
(608) 262-1697 | |
{ihnp4,seismo}!uwvax!geowhiz!karsh ---------------------------