home *** CD-ROM | disk | FTP | other *** search
- /* WARNING - this program typed in by hand from DECUS source, so beware typos
- such as extra/missing ;'s and what not. (/ \ | & =) */
- /* Note - the first two arguments to "ioctl" reversed. */
- #include <stdio.h>
- #include <signal.h>
- #include <sgtty.h>
- #include <errno.h>
- /*
- * cu telno [-t] [-s speed] [-l line] [-a acu]
- *
- * -t is for dial-out to terminal.
- * speeds are: 110, 134, 150, 300, 1200. 300 is default.
- *
- * 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)
- int errno;
- int rd_pid, wt_pid;
- int sig16cnt;
- char *devcul = "/dev/cul0";
- char *devcua = "/dev/cua0";
- char *lspeed = "300";
- int ln; /* fd for comm line */
- char tkill, terase; /* current input kill & erase */
- char c;
- char *connmsg[] = {
- "",
- "line busy",
- "call dropped",
- "no carrier",
- "can't fork",
- "acu access",
- "tty access",
- "tty hung",
- "usage: cu telno [-t] [-s speed] [-l line] [-a acu]"
- };
- char prompt[16], tk_tmplt[128], pt_tmplt[128];
- int pipefd[2];
- FILE *pipefp, *fdopen();
- int intr;
- int dout;
- int nhup;
-
- sig16()
- {
- signal(16, sig16);
- sig16cnt++;
- }
-
- sig2()
- {
- signal(SIGINT, SIG_IGN);
- intr = 1;
- }
-
- do_macro(string, f) /* processes system macros for take and put -cwg */
- /* Note - Probably the better way to handle "escape" sequences
- is to use something like "~" rather than "^" as a lead-in.
- This would allow ^ to stand for caret (circumflex) itself,
- ~~ would represent tilde, with lowercase equivalents for the
- specific functions below (e.g., ~v for sync and ~{ for EOF escape).
- Then, ALL control characters could be represented as ~@ ~A ... ~^ ~_. */
- char *string; /* pointer to the macro command string */
- int f; /* fd of input file, used if this is ~%put */
- {
- int rcount;
- int sync; /* whether we have to wait for prompt for ea out ln */
- char *strptr; /* roving pointer into macro string */
-
- strptr = string; /* begin at the beginning... */
- sig16cnt = 0; /* make sure no prev syncs to mess up */
- while (c = *(strptr++)) { /* while there is more to do... */
- if (c != '~') { /* if just part of normal string... */
- wrc(ln); /* send it out,... */
- continue; /* and do next character */
- }
- if (!(c = *(strptr++))) /* if premature end of string... */
- break; /* just ignore trailing '~' */
- if (c == '~') { /* if "~~", send single ~ */
- wrc(ln);
- continue;
- }
- if (c == 'v') { /* if "~v" (SYN) - synchronize with */
- while (!sig16cnt) /* rd() process on nxt prompt */
- sleep(2);
- sig16cnt = 0; /* reset for next sync */
- continue;
- }
- if (c == '{') { /* if "~{" (ESC) - divert rd() proc */
- kill(rd_pid, 16); /* send signal 16 to rd()
- process to read pipe and divert read */
- strptr += 2; /* skip over this token */
- while (*(strptr - 2) != '~' && *(strptr - 1) != '}')
- strptr++; /* skip to end of EOF */
- continue;
- }
- if (c == 'l') { /* if "~l" - send lines of in fl */
- strptr++; /* skip following "~" (we trust) */
- if ((c = *(strptr++)) == 'v') /* if we must sync */
- sync = 1; /* with incoming prompts */
- else
- sync = 0;
- /*/*/
- intr = 0;
- if (!nhup)
- signal(SIGINT, sig2);
- mode(2); /* no raw (catch interrupt) */
- rcount = 0;
- while(!intr && rdc(f) == 1) {
- rcount++; /* copy file to line */
- if (c == tkill || c == terase)
- wrln("\\"); /* write string to ln */
- if (wrc(ln) != 1) {
- xsleep(2);
- if (wrc(ln) != 1) { /* write c to ln */
- prf("character missed");
- intr = 1;
- break;
- }
- }
- if ((c == '\n') && sync) { /* if we must wait */
- while (!sig16cnt) /* for prompt */
- sleep(1);
- sig16cnt = 0; /* next time */
- }
- }
- signal(SIGINT, SIG_IGN);
- close(f);
- if (intr) {
- wrln("\n");
- prf("stopped after %d bytes", rcount);
- }
- mode(1); /* raw (do not catch interrupt) */
- /*/*/
- continue;
- }
- if (c > '/' && c < ':') { /* delay spec. 0 - 9 sec's */
- sleep(c - '0'); /* calculate binary integer interval */
- continue;
- }
- if (c == '?') { /* "~?" (DEL) - send DEL character */
- c = '\177'; /* construct a DEL character */
- wrc(ln);
- continue;
- }
- /* other control characters - interpret and send them. */
- if (c > '?' && c < '`') { /* if legitimate control ch */
- c -= '@'; /* adjust to the control character */
- wrc(ln); /* and send it out. */
- continue;
- }
- } /* end of while loop */
- }
- rdc(ds) {
- ds = read(ds, &c, 1);
- c &= 0177;
- return(ds);
- }
- int set14;
- xsleep(n)
- {
- xalarm(n);
- pause();
- xalarm(0);
- }
- xalarm(n)
- {
- set14 = n;
- alarm(n);
- }
- sig14()
- {
- signal(SIGALRM, sig14);
- if (set14) alarm(1); /* Set alarm to go off in one second. */
- }
- /*
- * main: get connection, set speed for line.
- * spawn child to invoke rd to read from line, output to fd 1 (stdout).
- * main line invokes wr to read tty, write to line.
- */
- main(ac, av)
- char *av[];
- {
- static char *sysdesfl = "/etc/unix.cs";
- /* system description filename string */
- FILE *sdf; /* pointer to system description file */
- int fk;
- int speed;
- char *telno;
- struct sgttyb stbuf;
-
- if (pipe(pipefd)) /* if cannot construct pipe */
- puts("Cannot construct pipe.");
- signal(16, sig16);
- sig16cnt = 0;
- signal(SIGALRM, sig14);
- if (ac < 2) { /* must at least have telno arg */
- prf(connmsg[8]); /* usage message */
- exit(8);
- }
- telno = av[1];
- av += 2;
- ac -= 2;
- for (; ac > 0; av++) {
- if (equal(*av, "-t")) { /* dialout to terminal (direct?) */
- dout = 1;
- --ac;
- continue;
- }
- if (ac < 2) /* just one remaining argument is meaningless */
- break;
- if (equal(*av, "-s")) /* speed (baud rate) */
- lspeed = *++av;
- else if (equal(*av, "-l")) /* comm line override */
- devcul = *++av;
- else if (equal(*av, "-a")) /* ACU override */
- devcua = *++av;
- else if (equal(*av, "-d")) /* system description file */
- sysdesfl = *++av;
- else
- break;
- ac -= 2;
- }
- if ((sdf = fopen(sysdesfl, "r")) == NULL)
- printf("Cannot open system description file \"%s\".", sysdesfl);
- fgets(prompt, 16, sdf); /* read the system prompt string */
- prompt[strlen(prompt) - 1] = '\0';
- fgets(pt_tmplt, 128, sdf); /* get the ~%put template string */
- pt_tmplt[strlen(pt_tmplt) - 1] = '\0';
- fgets(tk_tmplt, 128, sdf); /* get the ~%take template string */
- tk_tmplt[strlen(tk_tmplt) - 1] = '\0';
- fclose(sdf);
-
- if (!exists(devcua) || !exists(devcul))
- exit(9);
- ln = conn(devcul, devcua, telno); /* make the connection */
- if (ln < 0) {
- prf("Connect failed: %s", connmsg[-ln]);
- exit(-ln);
- }
- switch (atoi(lspeed)) {
- case 110:
- speed = B110; break;
- case 150:
- speed = B150; break;
- default:
- case 300:
- speed = B300; break;
- case 1200:
- speed = B1200; break;
- }
- stbuf.sg_ispeed = speed;
- stbuf.sg_ospeed = speed;
- stbuf.sg_flags = EVENP|ODDP;
- if (!dout) /* if not dialout to terminal */
- stbuf.sg_flags |= RAW;
- ioctl(ln, TIOCSETP, &stbuf); /* set parameters */
- ioctl(ln, TIOCEXCL, (struct sgttyb *) NULL); /* exclusive use mode */
- ioctl(ln, TIOCHPCL, (struct sgttyb *) NULL); /* hangup on close */
- prf("Connected");
- wt_pid = getpid(); /* make note of write process id */
- if (dout) /* if dialout to terminal */
- fk = -1;
- else
- fk = fork();
- rd_pid = fk; /* make note of read process ID */
- nhup = (int) signal(SIGINT, SIG_IGN);
- if (fk == 0) { /* if this is the child of above fork */
- rd(); /* read from this line */
- prf("/007Lost carrier");
- exit(3);
- }
- mode(1);
- wr(); /* this is parent process - write to line */
- mode(0);
- kill(fk, SIGKILL); /* done - kill child reader */
- wait((int *) NULL); /* wait for it to die */
- stbuf.sg_ispeed = 0;
- stbuf.sg_ospeed = 0;
- ioctl(ln, TIOCSETP, &stbuf); /* set parameters */
- prf("Disconnected");
- exit(0);
- }
- /*
- * conn: establish dial-out connection.
- * Example: fd = conn("/dev/ttyh", "/dev/dn1", "4500");
- * Returns descriptor open to tty for reading and writing.
- * Negative values (-1 ... -7) denote errors in connmsg.
- * Uses alarm and fork/wait; requires sig14 handler.
- * Be sure to disconnect tty when done, via HUPCL or stty 0.
- */
- conn(dev, acu, telno)
- char *dev, *acu, *telno;
- {
- struct sgttyb stbuf;
- extern errno;
- char *p, *q, b[30];
- int er, fk, dn, dh, t;
-
- er = 0;
- fk = (-1);
- if ((dn = open(acu, 1)) < 0) {
- er = (errno == 6 ? 1 : 5); /* "line busy" or "acu access"*/
- goto X;
- }
- if ((fk = fork()) == (-1)) { /* if couldn't spawn child process */
- er = 4; /* "can't fork" */
- goto X;
- }
- if (fk == 0) { /* if this is child process */
- open (dev, 2); /* open line for read and write */
- for (;;) pause();
- }
- xsleep(2);
- /*
- * copy phone #, assure EON
- */
- p = b;
- q = telno;
- while (*p++ = (*q++))
- ; /* copy telno string to b[] */
- p--;
- if (*(p - 1) != '<') { /* "<" is end-of-number */
- if (*(p - 1) != '-') *p++ = '-'; /* "-" await dialtone */
- *p++ = '<';
- }
- t = p - b; /* get length of string */
- xalarm(5 * t); /* set watchdog timer */
- t = write(dn, b, t); /* write telno to ACU */
- xalarm(0);
- if (t < 0) {
- er = 2; /* "call dropped" */
- goto X;
- }
- /* close(dn) */
- xalarm(40); /* was 5; sometimes missed carrier */
- dh = open(dev, 2); /* open line for read/write */
- xalarm(0);
- if (dh < 0) {
- er = (errno == 4 ? 3 : 6); /* "no carrier"or"tty access" */
- goto X;
- }
- /* ?!? ioctl(TIOCGETP, ln, &stbuf); /* get parameters */
- ioctl(dh, TIOCGETP, &stbuf);
- stbuf.sg_flags &= ~ECHO;
- xalarm(10);
- ioctl(dh, TIOCSETP, &stbuf); /* set parameters */
- ioctl(dh, TIOCHPCL, (struct sgttyb *) NULL); /* hangup on close */
- xalarm(0);
- X:
- if (er) close(dn);
- if (fk != (-1)) { /* if there is a child process */
- kill (fk, SIGKILL);
- xalarm(10);
- while ((t = wait((int *) NULL)) != (-1) && t != fk)
- ; /* wait for child to die */
- xalarm(0);
- }
- return (er ? -er : dh);
- }
- /*
- * wr: write to remote: 0 -> line (0 = stdin)
- * ~. 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)
- */
- wr()
- {
- int ds, fk, lcl, x;
- char *p, b[600];
-
- pipefp = fdopen(pipefd[1], "w"); /* open write strm into pipe */
- for (;;) {
- p = b;
- while (rdc(0) == 1 || (errno == EINTR && rdc(0) == 1)) {
- /* reads into c from stdin */
- if (p == b) lcl = (c == '~'); /* line "~..." local */
- if (p == b + 1 && b[0] == '~') lcl = (c != '~');
- /* ...unless starts with "~~..." */
- if (c == 0) c = 0177; /* map NUL to DEL */
- if (!lcl) {
- if (wrc(ln) == 0) { /* write char to line */
- prf("line gone"); return;
- }
- }
- if (lcl) {
- if (c == 0177) c = tkill; /* line kill */
- if (c == '\r' || c == '\n') goto A;
- /* break out of transmit loop */
- if (!dout) wrc(0);
- /* if not dialout, echo char to stdin */
- }
- *p++ = c;
- if (c == terase) { /* if erase character */
- p = p - 2; /* back up one space */
- if (p < b) p = b;
- }
- if (c == tkill || c == 0177 || c == '\r' || c == '\n')
- p = b; /* reuse line */
- }
- return;
- A:
- if (!dout) echo("");
- *p = 0;
- switch (b[1]) {
- case '.':
- case '\004': /* ^D is EOF */
- return; /* finished with call */
- case '!': /* escape to shell */
- case '$': /* transmit stdout of foll. cmd */
- fk = fork();
- if (fk == 0) { /* if this is child... */
- close(1);
- dup(b[1] == '$' ? ln : 2);
- close(ln);
- mode(0);
- if (!nhup) signal(SIGINT, SIG_DFL);
- if (b[2] == 0) execl("/bin/sh", "-", 0);
- else execl("/bin/sh", "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 '<': /* read file out the line */
- 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 '%': /* put and take commands */
- dopercen(&b[2]);
- break;
- default:
- prf("Use `~~' to start line with `~'");
- }
- continue;
- }
- }
- dopercen(line)
- register char *line;
- {
- char cmd_line[256];
- char *args[10];
- register narg, f;
-
- for (narg = 0; narg < 10;) { /* collect arguments */
- while (*line == ' ' || *line == '\t')
- line++; /* scan past white space */
- if (*line == '\0')
- break;
- args[narg++] = line; /* there is an argument here */
- while (*line != '\0' && *line != ' ' && *line != '\t')
- line++; /* find end of argument */
- if (*line == '\0')
- break;
- *line++ = '\0'; /* terminate argument string */
- }
- if (equal(args[0], "take")) {
- if (narg < 2) {
- prf("usage: ~%%take from [to]");
- return;
- }
- if (narg < 3)
- args[2] = args[1];
- fprintf(pipefp, "~>:%s\n", args[2]); /* put filnam in pipe */
- fflush(pipefp); /* and make sure rd() sees it */
- sprintf(cmd_line, tk_tmplt, args[1], args[1], args[1], args[1]);
- /* substitute "from" filname for all "%s" in template */
- do_macro(cmd_line, f); /* process ~%take command mac */
- 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) { /* open "from" file */
- prf("cannot open: %s", args[1]); /* for read */
- return;
- }
- sprintf(cmd_line, pt_tmplt, args[2], args[2], args[2], args[2]);
- /* substitute "to" filename for all "%s" in template */
- do_macro(cmd_line, f); /* process ~%put macro string */
- 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);
- }
- /*
- * rd: read from remote: line -> 1 (1 = stdout).
- * catch:
- * ~>[>][:][file]
- * stuff from file...
- * ~> (ends diversion)
- */
- rd()
- {
- int ds, slnt;
- char *p, *q, b[600];
- char eofstr[32]; /* array of EOF identifier character string */
- int i, j; /* indices used to pick out EOF string */
-
- pipefp = fdopen(pipefd[0], "r"); /* open pipe end for reading */
- for (i = 2; (tk_tmplt[i - 2] != '~') && (tk_tmplt[i - 1] != '{'); i++)
- ; /* find start of EOF definition string */
- for (j = i; (tk_tmplt[j] != '~') && (tk_tmplt[j + 1] != '}'); j++)
- ; /* find end of EOF definition string */
- strncpy(eofstr, tk_tmplt + i, j - i); /* copy EOF string from tmplt */
- eofstr[j - i] = '\0'; /* terminate the EOF string */
-
- p = b;
- ds = (-1);
- while (rdc(ln) == 1 || (errno == EINTR && rdc(ln) == 1)) {
- /* for each character... */
- if (ds < 0) slnt = 0;
- if (!slnt) wrc(1); /* if not silent, write to stdout */
- *p++ = c;
- *p = '\0'; /* make sure legitimate string */
- if (!strcmp(prompt, b)) /* if this looks like a prompt... */
- kill (wt_pid, 16); /* send signal 16 to wr() */
- if (c != '\n') continue;
- /*** Complete lines ***/
- q = p;
- p = b; /* if newline, reset line */
-
- if (*(q - 2) == '\r') { /* get rid of CR, if there */
- q--;
- *(q - 1) = (*q);
- }
- if (ds >= 0) { /* if we are currently redirecting input... */
- if (strncmp(eofstr, b, strlen(eofstr))){/* if not EOF */
- write(ds, b, q - b); /* write ths ln to fl */
- continue; /* gt nxt lin */
- }
- /*** Hit EOF ***/
- close(ds);
- ds = (-1); /* remember that we are not redirectn */
- write(1, b, q - b); /* might as well echo EOF ln. */
- /* write(1, CRLF, sizeof(CRLF)); /* seems too much */
- write(1, "\r", 1);
- slnt = 0;
- }
- else { /* we are not redirecting now - see if we should start*/
- if (!sig16cnt) /* if we have not received signal to */
- continue; /* read pipe & redirect, done */
- sig16cnt = 0; /* reset for next time around */
- /*** Start redirection ***/
- fgets(b, 64, pipefp); /* get local command */
- b[strlen(b) - 1] = '\0'; /* end string w/o \n */
-
- slnt = 0;
- q = b + 2;
- if (*q == '>') q++;
- if (*q == ':') {
- slnt = 1;
- q++;
- }
- if (*q == 0) {
- ds = (-1);
- continue;
- }
- if (b[2] != '>' || (ds = open(q, 1)) < 0)
- ds = creat(q, 0644);
- lseek(ds, (long) 0, 2);
- if (ds < 0)
- prf("Can't divert %s", b + 1);
- }
- }
- perror("read perror");
- }
- struct {char lobyte; char hibyte; }; /* sic - but why??? */
- mode(f)
- {
- struct sgttyb stbuf;
-
- if (dout) return;
- ioctl(0, TIOCGETP, &stbuf); /* Get parameters */
- 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; /* sic, but isn't it wrong? */
- stbuf.sg_flags &= ~(ECHO | CRMOD);
- }
- if (f == 2) {
- stbuf.sg_flags &= ~RAW;
- stbuf.sg_flags &= ~(ECHO | CRMOD);
- }
- ioctl(0, TIOCSETP, &stbuf); /* set parameters */
- }
- 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);
- }
-