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