|
|
1.1 root 1: #include <stdio.h>
2: #include <signal.h>
3: #include <sys/ttyio.h>
4: #include <sys/filio.h>
5: #include <ctype.h>
6: /*
7: * cu telno [ class ]
8: * Escape with `~' at beginning of line.
9: * Ordinary diversions are ~<, ~> and ~>>.
10: * Silent output diversions are ~>: and ~>>:.
11: * Terminate output diversion with ~> alone.
12: * Output command requests are ~! and ~:! (silent).
13: * Quit is ~. and ~! gives local command or shell.
14: * Also ~$ for canned procedure pumping remote.
15: * ~%put from [to] and ~%take from [to] invoke builtins
16: */
17:
18: char CRLF[2] = {'\r', '\n'};
19: #define equal(s1,s2) (strcmp(s1, s2)==0)
20: char *cunfile;
21: int ln; /* fd for comm line */
22: char tkill, terase; /* current input kill & erase */
23: char c;
24: int intr;
25: int nhup;
26: int nflag;
27: int tandm;
28: int hduplx;
29: int errflg;
30: int speed = B9600; /* used only for direct */
31: int parity = 0;
32: extern int optind, opterr;
33: extern char *optarg;
34: struct sgttyb realtty;
35: struct tchars realtch;
36: int sig2();
37:
38: char *connmsg[] = {
39: "",
40: "ACU busy",
41: "call dropped",
42: "no carrier",
43: "can't fork",
44: "acu access",
45: "tty access",
46: "tty hung",
47: "usage: cu [-hnt] telno [ class ]",
48: "unknown service class",
49: "stuff dk error message here", /* hack */
50: };
51:
52: struct dial {
53: char *telno;
54: char *dialtype;
55: char *comment;
56: };
57:
58: char partab[] = {
59: 0001,0201,0201,0001,0201,0001,0001,0201,
60: 0202,0004,0003,0201,0005,0206,0201,0001,
61: 0201,0001,0001,0201,0001,0201,0201,0001,
62: 0001,0201,0201,0001,0201,0001,0001,0201,
63: 0200,0000,0000,0200,0000,0200,0200,0000,
64: 0000,0200,0200,0000,0200,0000,0000,0200,
65: 0000,0200,0200,0000,0200,0000,0000,0200,
66: 0200,0000,0000,0200,0000,0200,0200,0000,
67: 0200,0000,0000,0200,0000,0200,0200,0000,
68: 0000,0200,0200,0000,0200,0000,0000,0200,
69: 0000,0200,0200,0000,0200,0000,0000,0200,
70: 0200,0000,0000,0200,0000,0200,0200,0000,
71: 0000,0200,0200,0000,0200,0000,0000,0200,
72: 0200,0000,0000,0200,0000,0200,0200,0000,
73: 0200,0000,0000,0200,0000,0200,0200,0000,
74: 0000,0200,0200,0000,0200,0000,0000,0201
75: };
76:
77: /*
78: * spawn child to invoke rd to read from line, output to fd 1
79: * main line invokes wr to read tty, write to line
80: */
81:
82: main(ac, av)
83: char *av[];
84: {
85: int fk;
86: struct sgttyb stbuf;
87: struct ttydevb tdbuf;
88: struct dial d;
89:
90: signal(SIGPIPE, SIG_IGN);
91: d.telno = NULL;
92: d.dialtype = NULL;
93: d.comment = "";
94: options(ac, av);
95: if (optind >= ac || errflg) {
96: prf(connmsg[8]);
97: exit(8);
98: }
99: ioctl(0, TIOCGETP, &realtty);
100: ioctl(0, TIOCGETC, &realtch);
101: gettelno(av[optind], &d);
102: if (optind+1 < ac)
103: d.dialtype = av[optind+1];
104: if (d.dialtype==NULL || *d.dialtype=='\0')
105: d.dialtype = "D1200";
106: if (nflag) {
107: printf("%s %s %s\n", d.telno, d.dialtype, d.comment);
108: exit(0);
109: }
110: if (equal(d.dialtype, "direct")) {
111: ln = open(d.telno, 2);
112: if (ln>=0) {
113: struct tchars tcr;
114:
115: ioctl(ln, TIOCGETP, &stbuf);
116: stbuf.sg_flags &= ~ECHO;
117: stbuf.sg_flags |= RAW|EVENP|ODDP;
118: stbuf.sg_ispeed = speed; /* obsolete */
119: stbuf.sg_ospeed = speed; /* obsolete */
120: ioctl(ln, TIOCGETC, &tcr);
121: tcr.t_stopc = '\027';
122: tcr.t_startc = '\031';
123: ioctl(ln, TIOCGDEV, &tdbuf);
124: tdbuf.ispeed = tdbuf.ospeed = speed;
125: tdbuf.flags |= F8BIT|EVENP|ODDP;
126: ioctl(ln, TIOCSETP, &stbuf);
127: ioctl(ln, TIOCSETC, &tcr);
128: ioctl(ln, TIOCSDEV, &tdbuf);
129: ioctl(ln, TIOCHPCL, 0);
130: ioctl(ln, TIOCEXCL, 0);
131: }
132: } else{
133: ln = -1;
134: }
135: if (ln < 0) {
136: prf("Connect failed: %s",connmsg[-ln]);
137: exit(-ln);
138: }
139: ioctl(ln, TIOCGETP, &stbuf);
140: prf("Connected");
141: if (d.comment && *d.comment && *d.comment!='\n')
142: prf(d.comment);
143: if (tandm) {
144: ioctl(ln, TIOCGETP, &stbuf);
145: stbuf.sg_flags = ODDP+EVENP+TANDEM+CBREAK;
146: ioctl(ln, TIOCSETN, &stbuf);
147: }
148: fk = fork();
149: nhup = (int)signal(SIGINT, SIG_IGN);
150: if (fk == 0) {
151: rd();
152: prf("\007Lost carrier");
153: exit(3);
154: }
155: mode(1);
156: wr();
157: mode(0);
158: kill(fk, SIGKILL);
159: stbuf.sg_ispeed = 0;
160: stbuf.sg_ospeed = 0;
161: ioctl(ln, TIOCSETN, &stbuf);
162: tdbuf.ispeed = tdbuf.ospeed = 0;
163: ioctl(ln, TIOCSDEV, &tdbuf);
164: prf("Disconnected");
165: exit(0);
166: }
167:
168: /*
169: * wr: write to remote: 0 -> line.
170: * ~. terminate
171: * ~<file send file
172: * ~! local login-style shell
173: * ~!cmd execute cmd locally
174: * ~$proc execute proc locally, send output to line
175: * ~%cmd execute builtin cmd (put and take)
176: */
177:
178: wr()
179: {
180: int ds, fk, lcl, x, nc;
181: char *p, b[600];
182:
183: for (;;) {
184: p = b;
185: while (rdc(0) >= 1) {
186: if (p == b)
187: lcl=(c == '~');
188: if (p == b+1 && b[0] == '~')
189: lcl=(c!='~');
190: if (c == 0)
191: c = 0177;
192: if (!lcl) {
193: if (c==0177)
194: ioctl(ln, TIOCFLUSH, 0);
195: if (wrc(ln, c, 1) <= 0) {
196: prf("line gone");
197: return;
198: }
199: if (c==0177)
200: ioctl(0, TIOCFLUSH, 0);
201: }
202: if (lcl) {
203: if (c == 0177)
204: c = tkill;
205: if (c == '\r' || c == '\n')
206: goto A;
207: if (!hduplx)
208: wrc(1, c, 1);
209: }
210: *p++ = c;
211: if (c == terase) {
212: p = p-2;
213: if (p<b)
214: p = b;
215: }
216: if (c == tkill || c == 0177 || c == '\r' || c == '\n')
217: p = b;
218: }
219: return;
220: A:
221: if (!hduplx || realtty.sg_flags&CRMOD)
222: echo("");
223: *p = 0;
224: switch (b[1]) {
225: case '.':
226: case '\004':
227: return;
228: case 'b':
229: sendbreak();
230: break;
231:
232: case '!':
233: case '$':
234: fk = fork();
235: if (fk == 0) {
236: close(1);
237: dup(b[1] == '$'? ln:2);
238: close(ln);
239: mode(0);
240: if (!nhup)
241: signal(SIGINT, SIG_DFL);
242: if (b[2] == 0)
243: execl("/bin/sh","sh",0);
244: else
245: execl("/bin/sh","sh","-c",b+2,(char *)0);
246: prf("Can't execute shell");
247: exit(1);
248: }
249: if (fk!=(-1)) {
250: while (wait((int *)0)!=fk)
251: ;
252: }
253: mode(1);
254: if (b[1] == '!')
255: echo("!");
256: break;
257: case '<':
258: if (b[2] == 0) break;
259: if ((ds = open(b+2,0))<0) {
260: prf("Can't divert %s",b+1);
261: break;
262: }
263: intr = x = 0;
264: mode(2);
265: if (!nhup)
266: signal(SIGINT, sig2);
267: while (!intr && (nc = rdc(ds)) >= 1) {
268: if (wrc(ln, c, nc==1) <= 0) {
269: x = 1;
270: break;
271: }
272: }
273: signal(SIGINT, SIG_IGN);
274: close(ds);
275: mode(1);
276: if (x)
277: return;
278: break;
279: case '%':
280: dopercen(&b[2]);
281: break;
282: default:
283: prf("Use `~~' to start line with `~'");
284: }
285: continue;
286: }
287: }
288:
289: dopercen(line)
290: register char *line;
291: {
292: char *args[10];
293: register narg, f;
294: int rcount, nc;
295:
296: for (narg = 0; narg < 10;) {
297: while(*line == ' ' || *line == '\t')
298: line++;
299: if (*line == '\0')
300: break;
301: args[narg++] = line;
302: while(*line != '\0' && *line != ' ' && *line != '\t')
303: line++;
304: if (*line == '\0')
305: break;
306: *line++ = '\0';
307: }
308: if (equal(args[0], "break")) {
309: sendbreak();
310: return;
311: } else if (equal(args[0], "take")) {
312: if (narg < 2) {
313: prf("usage: ~%%take from [to]");
314: return;
315: }
316: if (narg < 3)
317: args[2] = args[1];
318: wrln("echo '~>:'");
319: wrln(args[2]);
320: wrln(";tee /dev/null <");
321: wrln(args[1]);
322: wrln(";echo '~>'\n");
323: return;
324: } else if (equal(args[0], "put")) {
325: if (narg < 2) {
326: prf("usage: ~%%put from [to]");
327: return;
328: }
329: if (narg < 3)
330: args[2] = args[1];
331: if ((f = open(args[1], 0)) < 0) {
332: prf("cannot open: %s", args[1]);
333: return;
334: }
335: wrln("stty -echo;cat >");
336: wrln(args[2]);
337: wrln(";stty echo\n");
338: sleep(5);
339: intr = 0;
340: if (!nhup)
341: signal(SIGINT, sig2);
342: mode(2);
343: rcount = 0;
344: while(!intr && (nc = rdc(f)) >= 1) {
345: rcount++;
346: if (c == tkill || c == terase)
347: wrc(ln, '\\', 0);
348: if (wrc(ln, c, nc == 1) <= 0)
349: intr = 1;
350: }
351: signal(SIGINT, SIG_IGN);
352: close(f);
353: if (intr) {
354: wrc(ln, '\n', 1);
355: prf("stopped after %d bytes", rcount);
356: }
357: wrc(ln, '\004', 1);
358: sleep(5);
359: mode(1);
360: return;
361: }
362: prf("~%%%s unknown\n", args[0]);
363: }
364:
365: wrln(s)
366: register char *s;
367: {
368: register n = strlen(s);
369:
370: write(ln, s, n);
371: }
372:
373: /*
374: * rd: read from remote: line -> 1
375: * catch:
376: * ~>[>][:][file]
377: * stuff from file...
378: * ~> (ends diversion)
379: * ways for remote to run local command:
380: * ~!command (run command locally)
381: * ~:!command (run silently locally)
382: */
383:
384: rd()
385: {
386: int ds, slnt, pid, hold=0, nc;
387: char *p, *q, b[600];
388:
389: p = b;
390: ds = -1;
391: while ((nc = rdc(ln)) >= 1) {
392: if (ds < 0 && hold==0)
393: slnt = 0;
394: if (p==b && c=='~')
395: hold= ++slnt;
396: if (hold && slnt && p==b+1 && c!=':') {
397: wrc(1, '~', 1);
398: slnt--;
399: hold = 0;
400: }
401: if (!slnt)
402: wrc(1, c, nc==1);
403: *p++ = c;
404: if (c!='\n' && p < &b[599])
405: continue;
406: q = p;
407: p = b;
408: hold = 0;
409: if (strncmp(b, "~:!",3)==0||strncmp(b, "~!", 2)==0) {
410: *--q= '\0';
411: if (*--q == '\r')
412: *q= '\0';
413: mode(0);
414: if ((pid=fork())==0) {
415: p = b+2;
416: if (*p=='!')
417: p++;
418: execl("/bin/sh", "sh", "-c", p, (char *)0);
419: exit(0);
420: }
421: while (wait((int *)0)!=pid)
422: ;
423: mode(1);
424: continue;
425: }
426: if (b[0]!='~' || b[1]!='>') {
427: if (*(q-2) == '\r') {
428: q--;
429: *(q-1)=(*q);
430: }
431: if (ds>=0)
432: write(ds, b, q-b);
433: continue;
434: }
435: if (ds>=0)
436: close(ds);
437: if (slnt) {
438: write(1, b, q - b);
439: write(1, CRLF, sizeof(CRLF));
440: }
441: if (*(q-2) == '\r')
442: q--;
443: *(q-1) = 0;
444: slnt = 0;
445: q = b+2;
446: if (*q == '>')
447: q++;
448: if (*q == ':') {
449: slnt = 1;
450: q++;
451: }
452: if (*q == 0) {
453: ds = -1;
454: continue;
455: }
456: if (b[2]!='>' || (ds = open(q,1))<0)
457: ds = creat(q, 0644);
458: lseek(ds, (long)0, 2);
459: if (ds<0)
460: prf("Can't divert %s",b+1);
461: }
462: }
463:
464: mode(f)
465: {
466: struct sgttyb stbuf;
467: static struct tchars nochars = { -1, -1, -1, -1, -1, -1};
468:
469: ioctl(0, TIOCGETP, &stbuf);
470: tkill = stbuf.sg_kill;
471: terase = stbuf.sg_erase;
472: if (f == 0) {
473: ioctl(0, TIOCSETP, &realtty);
474: ioctl(0, TIOCSETC, &realtch);
475: return;
476: }
477: if (f == 1) {
478: stbuf.sg_flags |= CBREAK;
479: stbuf.sg_flags &= ~CRMOD;
480: if (!hduplx)
481: stbuf.sg_flags &= ~ECHO;
482: ioctl(0, TIOCSETP, &stbuf);
483: ioctl(0, TIOCSETC, &nochars);
484: return;
485: }
486: if (f == 2) {
487: stbuf.sg_flags &= ~(ECHO|CRMOD);
488: ioctl(0, TIOCSETP, &stbuf);
489: ioctl(0, TIOCSETC, &realtch);
490: return;
491: }
492: }
493:
494: echo(s)
495: char *s;
496: {
497: register n = strlen(s);
498:
499: if (n>0)
500: write(1, s, n);
501: write(1, CRLF, sizeof(CRLF));
502: }
503:
504: /* VARARGS1 */
505: prf(f, s)
506: char *f;
507: char *s;
508: {
509: printf(f, s);
510: printf(CRLF);
511: }
512:
513: sendbreak()
514: {
515: struct sgttyb b;
516: int olds;
517:
518: #ifdef TIOCSBRK
519: ioctl(ln, TIOCSBRK, 0);
520: #else TIOCSBRK
521: ioctl(ln, TIOCGETP, &b);
522: olds = b.sg_ispeed;
523: b.sg_ispeed = B50;
524: b.sg_ospeed = B50;
525: ioctl(ln, TIOCSETP, &b);
526: write(ln, "\0\0\0", 3);
527: b.sg_ispeed = olds;
528: b.sg_ospeed = olds;
529: ioctl(ln, TIOCSETP, &b);
530: #endif TIOCSBRK
531: }
532:
533: /*
534: * Symbolic phone numbers
535: */
536: gettelno(np, dp)
537: char *np;
538: register struct dial *dp;
539: {
540: char cunumber[128];
541: char *hp;
542: register char *xnp;
543: char *getenv();
544:
545: if (cunfile) {
546: if (look(np, dp, cunfile))
547: return;
548: } else {
549: hp = getenv("HOME");
550: if (hp) {
551: strcpy(cunumber, hp);
552: strcat(cunumber, "/lib/cunumber");
553: if (look(np, dp, cunumber))
554: return;
555: }
556: if (look(np, dp, "/usr/lib/cunumber"))
557: return;
558: }
559: xnp = np;
560: if (*np != '/')
561: while (*xnp) {
562: if (*xnp!=';' && *xnp!=':' && *xnp!='-' && *xnp!='*'
563: && *xnp!='#' && !isdigit(*xnp)) {
564: prf("Symbolic number not found");
565: exit(1);
566: }
567: xnp++;
568: }
569: dp->telno = np;
570: }
571:
572: look(np, dp, fnp)
573: register char *np;
574: register struct dial *dp;
575: char *fnp;
576: {
577: FILE *fp;
578: static char line[128];
579: register char *lp;
580: register i;
581: char *opts[8];
582: register char **optp;
583: char *w[4];
584:
585: if ((fp = fopen(fnp, "r")) == NULL)
586: return(0);
587: while (fgets(line, sizeof(line), fp)) {
588: lp = line;
589: optp = opts;
590: for (i = 0; i<4; i++) {
591: while (isspace(*lp))
592: lp++;
593: if (i==1 && *lp=='-') {
594: *optp++ = lp;
595: i--;
596: } else
597: w[i] = lp;
598: while ((!isspace(*lp) || i==3) && *lp)
599: lp++;
600: if (*lp)
601: *lp++ = '\0';
602: }
603: if (strcmp(w[0], np))
604: continue;
605: i = optind;
606: optind = 0;
607: options(optp-opts, opts);
608: optind = i;
609: dp->telno = w[1];
610: dp->dialtype = w[2];
611: dp->comment = w[3];
612: fclose(fp);
613: return(1);
614: }
615: fclose(fp);
616: return(0);
617: }
618:
619: options(ac, av)
620: char **av;
621: {
622: register o;
623:
624: opterr = 0;
625: while ((o = getopt(ac, av, "hntf:s:p:")) != EOF) {
626: switch(o) {
627:
628: case '?':
629: errflg++;
630: continue;
631:
632: case 'h':
633: hduplx++;
634: continue;
635:
636: case 'f':
637: cunfile = optarg;
638: continue;
639:
640: case 't':
641: tandm++;
642: continue;
643:
644: case 'n':
645: nflag++;
646: continue;
647:
648: case 's':
649: if ((speed = getspeed(optarg)) < 0) {
650: fprintf(stderr, "-s %s: illegal speed\n");
651: errflg++;
652: }
653: continue;
654:
655: case 'p':
656: if ((parity = getpar(optarg)) < 0) {
657: fprintf(stderr, "-p %s: illegal parity\n");
658: errflg++;
659: }
660: continue;
661: }
662: }
663: }
664:
665: struct speeds{
666: char *s_name;
667: int s_define;
668: } speeds[] = {
669: "0", B0,
670: "50", B50,
671: "75", B75,
672: "110", B110,
673: "134", B134,
674: "150", B150,
675: "200", B200,
676: "300", B300,
677: "600", B600,
678: "1200", B1200,
679: "1800", B1800,
680: "2400", B2400,
681: "4800", B4800,
682: "9600", B9600,
683: "exta", EXTA,
684: "extb", EXTB,
685: "19200", EXTA,
686: 0
687: };
688:
689: getspeed(s)
690: char *s;
691: {
692: register struct speeds *sp;
693:
694: for (sp = speeds; sp->s_name; sp++)
695: if (strcmp(sp->s_name, s) == 0)
696: return (sp->s_define);
697: return (-1);
698: }
699:
700: getpar(s)
701: char *s;
702: {
703: switch (s[0]) {
704: case '0':
705: return (0);
706: case '1':
707: return (EVENP|ODDP);
708: case 'e':
709: return (EVENP);
710: case 'o':
711: return (ODDP);
712: }
713: return (-1);
714: }
715:
716: wrc(f, c, flush)
717: register c;
718: {
719: static char buf[64];
720: static char *bp = buf;
721: register r;
722:
723: c &= 0177;
724: if (f==ln) {
725: switch (parity) {
726: case EVENP:
727: c |= (partab[c] & 0200);
728: break;
729: case ODDP:
730: c |= (partab[c] & 0200) ^ 0200;
731: break;
732: case EVENP|ODDP:
733: c |= 0200;
734: break;
735: }
736: }
737: *bp++ = c;
738: r = 1;
739: if (flush || bp >= &buf[64]) {
740: r = write(f, buf, bp-buf);
741: bp = buf;
742: }
743: return(r);
744: }
745:
746: rdc(ds)
747: {
748: static char buf[64];
749: static nc = 0;
750: static char *bp;
751:
752: if (nc <= 0) {
753: nc = read(ds, buf, 64);
754: bp = buf;
755: }
756: if (nc <= 0)
757: return(nc);
758: nc--;
759: c = *bp++ & 0177;
760: return(nc+1);
761: }
762:
763: sig2()
764: {
765: signal(SIGINT, SIG_IGN);
766: intr = 1;
767: }
768:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.