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