|
|
1.1 root 1: static char *sccsid = "@(#)cu.c 4.1 (Berkeley) 10/1/80";
2: #include <stdio.h>
3: #include <signal.h>
4: #include <sgtty.h>
5: /*
6: * cu telno [-t] [-s speed] [-l line] [-a acu]
7: *
8: * -t is for dial-out to terminal.
9: * speeds are: 110, 134, 150, 300, 1200. 300 is default.
10: *
11: * Escape with `~' at beginning of line.
12: * Ordinary diversions are ~<, ~> and ~>>.
13: * Silent output diversions are ~>: and ~>>:.
14: * Terminate output diversion with ~> alone.
15: * Quit is ~. and ~! gives local command or shell.
16: * Also ~$ for canned procedure pumping remote.
17: * ~%put from [to] and ~%take from [to] invoke builtins
18: */
19:
20: #define CRLF "\r\n"
21: #define wrc(ds) write(ds,&c,1)
22:
23:
24: char *devcul = "/dev/cul0";
25: char *devcua = "/dev/cua0";
26: char *lspeed = "300";
27:
28: int ln; /* fd for comm line */
29: char tkill, terase; /* current input kill & erase */
30: int efk; /* process of id of listener */
31: char c;
32: char oc;
33:
34: char *connmsg[] = {
35: "",
36: "line busy",
37: "call dropped",
38: "no carrier",
39: "can't fork",
40: "acu access",
41: "tty access",
42: "tty hung",
43: "usage: cu telno [-t] [-s speed] [-l line] [-a acu]"
44: };
45:
46: rdc(ds) {
47:
48: ds=read(ds,&c,1);
49: oc = c;
50: c &= 0177;
51: return (ds);
52: }
53:
54: int intr;
55:
56: sig2()
57: {
58: signal(SIGINT, SIG_IGN);
59: intr = 1;
60: }
61:
62: int set14;
63:
64: xsleep(n)
65: {
66: xalarm(n);
67: pause();
68: xalarm(0);
69: }
70:
71: xalarm(n)
72: {
73: set14=n;
74: alarm(n);
75: }
76:
77: sig14()
78: {
79: signal(SIGALRM, sig14);
80: if (set14) alarm(1);
81: }
82:
83: int dout;
84: int nhup;
85: int dbflag;
86:
87: /*
88: * main: get connection, set speed for line.
89: * spawn child to invoke rd to read from line, output to fd 1
90: * main line invokes wr to read tty, write to line
91: */
92: main(ac,av)
93: char *av[];
94: {
95: int fk;
96: int speed;
97: char *telno;
98: struct sgttyb stbuf;
99:
100: signal(SIGALRM, sig14);
101: if (ac < 2) {
102: prf(connmsg[8]);
103: exit(8);
104: }
105: for (; ac > 1; av++,ac--) {
106: if (av[1][0] != '-')
107: telno = av[1];
108: else switch(av[1][1]) {
109: case 't':
110: dout = 1;
111: --ac;
112: continue;
113: case 'd':
114: dbflag++;
115: continue;
116: case 's':
117: lspeed = av[2]; ++av; --ac;
118: break;
119: case 'l':
120: devcul = av[2]; ++av; --ac;
121: break;
122: case 'a':
123: devcua = av[2]; ++av; --ac;
124: break;
125: case '0': case '1': case '2': case '3': case '4':
126: case '5': case '6': case '7': case '8': case '9':
127: devcua[strlen(devcua)-1] = av[1][1];
128: devcul[strlen(devcul)-1] = av[1][1];
129: break;
130: default:
131: prf("Bad flag %s", av[1]);
132: break;
133: }
134: }
135: if (!exists(devcua) || !exists(devcul))
136: exit(9);
137: ln = conn(devcul, devcua, telno);
138: if (ln < 0) {
139: prf("Connect failed: %s",connmsg[-ln]);
140: exit(-ln);
141: }
142: switch(atoi(lspeed)) {
143: case 110:
144: speed = B110;break;
145: case 150:
146: speed = B150;break;
147: default:
148: case 300:
149: speed = B300;break;
150: case 1200:
151: speed = B1200;break;
152: }
153: stbuf.sg_ispeed = speed;
154: stbuf.sg_ospeed = speed;
155: stbuf.sg_flags = EVENP|ODDP;
156: if (!dout) {
157: stbuf.sg_flags |= RAW;
158: stbuf.sg_flags &= ~ECHO;
159: }
160: ioctl(ln, TIOCSETP, &stbuf);
161: ioctl(ln, TIOCEXCL, (struct sgttyb *)NULL);
162: ioctl(ln, TIOCHPCL, (struct sgttyb *)NULL);
163: prf("Connected");
164: if (dout)
165: fk = -1;
166: else
167: fk = fork();
168: nhup = (int)signal(SIGINT, SIG_IGN);
169: if (fk == 0) {
170: chwrsig();
171: rd();
172: prf("\007Lost carrier");
173: exit(3);
174: }
175: mode(1);
176: efk = fk;
177: wr();
178: mode(0);
179: kill(fk, SIGKILL);
180: wait((int *)NULL);
181: stbuf.sg_ispeed = 0;
182: stbuf.sg_ospeed = 0;
183: ioctl(ln, TIOCSETP, &stbuf);
184: prf("Disconnected");
185: exit(0);
186: }
187:
188: /*
189: * conn: establish dial-out connection.
190: * Example: fd = conn("/dev/ttyh","/dev/dn1","4500");
191: * Returns descriptor open to tty for reading and writing.
192: * Negative values (-1...-7) denote errors in connmsg.
193: * Uses alarm and fork/wait; requires sig14 handler.
194: * Be sure to disconnect tty when done, via HUPCL or stty 0.
195: */
196:
197: conn(dev,acu,telno)
198: char *dev, *acu, *telno;
199: {
200: struct sgttyb stbuf;
201: extern errno;
202: char *p, *q, b[30];
203: int er, fk, dn, dh, t;
204: er=0;
205: fk=(-1);
206: if ((dn=open(acu,1))<0) {
207: er=(errno == 6? 1:5);
208: goto X;
209: }
210: if ((fk=fork()) == (-1)) {
211: er=4;
212: goto X;
213: }
214: if (fk == 0) {
215: open(dev,2);
216: for (;;) pause();
217: }
218: xsleep(2);
219: /*
220: * copy phone #, assure EON
221: */
222: p=b;
223: q=telno;
224: while (*p++=(*q++))
225: ;
226: p--;
227: if (*(p-1)!='<') {
228: /*if (*(p-1)!='-') *p++='-';*/
229: *p++='<';
230: }
231: t=p-b;
232: xalarm(5*t);
233: t=write(dn,b,t);
234: xalarm(0);
235: if (t<0) {
236: er=2;
237: goto X;
238: }
239: /* close(dn) */
240: xalarm(40); /* was 5; sometimes missed carrier */
241: dh = open(dev,2);
242: xalarm(0);
243: if (dh<0) {
244: er=(errno == 4? 3:6);
245: goto X;
246: }
247: ioctl(ln, TIOCGETP, &stbuf);
248: stbuf.sg_flags &= ~ECHO;
249: xalarm(10);
250: ioctl(dh, TIOCSETP, &stbuf);
251: ioctl(dh, TIOCHPCL, (struct sgttyb *)NULL);
252: xalarm(0);
253: X:
254: if (er) close(dn);
255: if (fk!=(-1)) {
256: kill(fk, SIGKILL);
257: xalarm(10);
258: while ((t=wait((int *)NULL))!=(-1) && t!=fk);
259: xalarm(0);
260: }
261: return (er? -er:dh);
262: }
263:
264: /*
265: * wr: write to remote: 0 -> line.
266: * ~. terminate
267: * ~<file send file
268: * ~! local login-style shell
269: * ~!cmd execute cmd locally
270: * ~$proc execute proc locally, send output to line
271: * ~%cmd execute builtin cmd (put and take)
272: * ~# send 1-sec break
273: */
274:
275: wr()
276: {
277: int ds,fk,lcl,x;
278: char *p,b[600];
279: for (;;) {
280: p=b;
281: while (rdc(0) == 1) {
282: if (p == b) lcl=(c == '~');
283: if (p == b+1 && b[0] == '~') lcl=(c!='~');
284: /* if (c == 0) oc=c=0177; fake break kludge */
285: if (!lcl) {
286: c = oc;
287: if (wrc(ln) == 0) {
288: prf("line gone"); return;
289: }
290: c &= 0177;
291: }
292: if (lcl) {
293: if (c == 0177) c=tkill;
294: if (c == '\r' || c == '\n') goto A;
295: if (!dout) wrc(0);
296: }
297: *p++=c;
298: if (c == terase) {
299: p=p-2;
300: if (p<b) p=b;
301: }
302: if (c == tkill || c == 0177 || c == '\4' || c == '\r' || c == '\n') p=b;
303: }
304: return;
305: A:
306: if (!dout) echo("");
307: *p=0;
308: switch (b[1]) {
309: case '.':
310: case '\004':
311: return;
312: case '#':
313: ioctl(ln, TIOCSBRK, 0);
314: sleep(1);
315: ioctl(ln, TIOCCBRK, 0);
316: continue;
317: case '!':
318: case '$':
319: fk = fork();
320: if (fk == 0) {
321: char *getenv();
322: char *shell = getenv("SHELL");
323: if (shell == 0) shell = "/bin/sh";
324: close(1);
325: dup(b[1] == '$'? ln:2);
326: close(ln);
327: mode(0);
328: if (!nhup) signal(SIGINT, SIG_DFL);
329: if (b[2] == 0) execl(shell,shell,0);
330: /* if (b[2] == 0) execl(shell,"-",0); */
331: else execl(shell,"sh","-c",b+2,0);
332: prf("Can't execute shell");
333: exit(~0);
334: }
335: if (fk!=(-1)) {
336: while (wait(&x)!=fk);
337: }
338: mode(1);
339: if (b[1] == '!') echo("!");
340: else {
341: if (dout) echo("$");
342: }
343: break;
344: case '<':
345: if (b[2] == 0) break;
346: if ((ds=open(b+2,0))<0) {
347: prf("Can't divert %s",b+1);
348: break;
349: }
350: intr=x=0;
351: mode(2);
352: if (!nhup) signal(SIGINT, sig2);
353: while (!intr && rdc(ds) == 1) {
354: if (wrc(ln) == 0) {
355: x=1;
356: break;
357: }
358: }
359: signal(SIGINT, SIG_IGN);
360: close(ds);
361: mode(1);
362: if (x) return;
363: if (dout) echo("<");
364: break;
365: case '>':
366: case ':':
367: {
368: FILE *fp; char tbuff[128]; register char *q;
369: sprintf(tbuff,"/tmp/cu%d",efk);
370: if(NULL==(fp = fopen(tbuff,"w"))) {
371: prf("Can't tell other demon to divert");
372: break;
373: }
374: fprintf(fp,"%s\n",(b[1]=='>'?&b[2]: &b[1] ));
375: if(dbflag) prf("name to be written in temporary:"),prf(&b[2]);
376: fclose(fp);
377: kill(efk,SIGEMT);
378: }
379: break;
380: #ifdef SIGTSTP
381: #define CTRLZ 26
382: case CTRLZ:
383: mode(0);
384: kill(getpid(), SIGTSTP);
385: mode(1);
386: break;
387: #endif
388: case '%':
389: dopercen(&b[2]);
390: break;
391: default:
392: prf("Use `~~' to start line with `~'");
393: }
394: continue;
395: }
396: }
397:
398: dopercen(line)
399: register char *line;
400: {
401: char *args[10];
402: register narg, f;
403: int rcount;
404: for (narg = 0; narg < 10;) {
405: while(*line == ' ' || *line == '\t')
406: line++;
407: if (*line == '\0')
408: break;
409: args[narg++] = line;
410: while(*line != '\0' && *line != ' ' && *line != '\t')
411: line++;
412: if (*line == '\0')
413: break;
414: *line++ = '\0';
415: }
416: if (equal(args[0], "take")) {
417: if (narg < 2) {
418: prf("usage: ~%%take from [to]");
419: return;
420: }
421: if (narg < 3)
422: args[2] = args[1];
423: wrln("echo '~>:'");
424: wrln(args[2]);
425: wrln(";tee /dev/null <");
426: wrln(args[1]);
427: wrln(";echo '~>'\n");
428: return;
429: } else if (equal(args[0], "put")) {
430: if (narg < 2) {
431: prf("usage: ~%%put from [to]");
432: return;
433: }
434: if (narg < 3)
435: args[2] = args[1];
436: if ((f = open(args[1], 0)) < 0) {
437: prf("cannot open: %s", args[1]);
438: return;
439: }
440: wrln("stty -echo;cat >");
441: wrln(args[2]);
442: wrln(";stty echo\n");
443: xsleep(5);
444: intr = 0;
445: if (!nhup)
446: signal(SIGINT, sig2);
447: mode(2);
448: rcount = 0;
449: while(!intr && rdc(f) == 1) {
450: rcount++;
451: if (c == tkill || c == terase)
452: wrln("\\");
453: if (wrc(ln) != 1) {
454: xsleep(2);
455: if (wrc(ln) != 1) {
456: prf("character missed");
457: intr = 1;
458: break;
459: }
460: }
461: }
462: signal(SIGINT, SIG_IGN);
463: close(f);
464: if (intr) {
465: wrln("\n");
466: prf("stopped after %d bytes", rcount);
467: }
468: wrln("\004");
469: xsleep(5);
470: mode(1);
471: return;
472: }
473: prf("~%%%s unknown\n", args[0]);
474: }
475:
476: equal(s1, s2)
477: register char *s1, *s2;
478: {
479: while (*s1++ == *s2)
480: if (*s2++ == '\0')
481: return(1);
482: return(0);
483: }
484:
485: wrln(s)
486: register char *s;
487: {
488: while (*s)
489: write(ln, s++, 1);
490: }
491: /* chwrsig: Catch orders from wr process
492: * to instigate diversion
493: */
494: int whoami;
495: chwrsig(){
496: int dodiver();
497: whoami = getpid();
498: signal(SIGEMT,dodiver);
499: }
500: int ds,slnt;
501: int justrung;
502: dodiver(){
503: static char dobuff[128], morejunk[256]; register char *cp;
504: FILE *fp;
505: justrung = 1;
506: signal(SIGEMT,dodiver);
507: sprintf(dobuff,"/tmp/cu%d",whoami);
508: fp = fopen(dobuff,"r");
509: if(fp==NULL) prf("Couldn't open temporary");
510: unlink(dobuff);
511: if(dbflag) {
512: prf("Name of temporary:");
513: prf(dobuff);
514: }
515: fgets(dobuff,128,fp); fclose(fp);
516: if(dbflag) {
517: prf("Name of target file:");
518: prf(dobuff);
519: }
520: for(cp = dobuff-1; *++cp; ) /* squash newline */
521: if(*cp=='\n') *cp=0;
522: cp = dobuff;
523: if (*cp=='>') cp++;
524: if (*cp==':') {
525: cp++;
526: if(*cp==0) {
527: slnt ^= 1;
528: return;
529: } else {
530: slnt = 1;
531: }
532: }
533: if (ds >= 0) close(ds);
534: if (*cp==0) {
535: slnt = 0;
536: ds = -1;
537: return;
538: }
539: if (*dobuff!='>' || (ds=open(cp,1))<0) ds=creat(cp,0644);
540: lseek(ds, (long)0, 2);
541: if(ds < 0) prf("Creat failed:"), prf(cp);
542: if (ds<0) prf("Can't divert %s",cp+1);
543: }
544:
545:
546: /*
547: * rd: read from remote: line -> 1
548: * catch:
549: * ~>[>][:][file]
550: * stuff from file...
551: * ~> (ends diversion)
552: */
553:
554: rd()
555: {
556: extern int ds,slnt;
557: char *p,*q,b[600];
558: p=b;
559: ds=(-1);
560: agin:
561: while (rdc(ln) == 1) {
562: if (!slnt) wrc(1);
563: *p++=c;
564: if (c!='\n') continue;
565: q=p;
566: p=b;
567: if (b[0]!='~' || b[1]!='>') {
568: if (*(q-2) == '\r') {
569: q--;
570: *(q-1)=(*q);
571: }
572: if (ds>=0) write(ds,b,q-b);
573: continue;
574: }
575: if (ds>=0) close(ds);
576: if (slnt) {
577: write(1, b, q - b);
578: write(1, CRLF, sizeof(CRLF));
579: }
580: if (*(q-2) == '\r') q--;
581: *(q-1)=0;
582: slnt=0;
583: q=b+2;
584: if (*q == '>') q++;
585: if (*q == ':') {
586: slnt=1;
587: q++;
588: }
589: if (*q == 0) {
590: ds=(-1);
591: continue;
592: }
593: if (b[2]!='>' || (ds=open(q,1))<0) ds=creat(q,0644);
594: lseek(ds, (long)0, 2);
595: if (ds<0) prf("Can't divert %s",b+1);
596: }
597: if(justrung) {
598: justrung = 0;
599: goto agin;
600: }
601: }
602:
603: struct {char lobyte; char hibyte;};
604: mode(f)
605: {
606: struct sgttyb stbuf;
607: if (dout) return;
608: ioctl(0, TIOCGETP, &stbuf);
609: tkill = stbuf.sg_kill;
610: terase = stbuf.sg_erase;
611: if (f == 0) {
612: stbuf.sg_flags &= ~RAW;
613: stbuf.sg_flags |= ECHO|CRMOD;
614: }
615: if (f == 1) {
616: stbuf.sg_flags |= RAW;
617: stbuf.sg_flags &= ~(ECHO|CRMOD);
618: }
619: if (f == 2) {
620: stbuf.sg_flags &= ~RAW;
621: stbuf.sg_flags &= ~(ECHO|CRMOD);
622: }
623: ioctl(0, TIOCSETP, &stbuf);
624: }
625:
626: echo(s)
627: char *s;
628: {
629: char *p;
630: for (p=s;*p;p++);
631: if (p>s) write(0,s,p-s);
632: write(0,CRLF, sizeof(CRLF));
633: }
634:
635: prf(f, s)
636: char *f;
637: char *s;
638: {
639: fprintf(stderr, f, s);
640: fprintf(stderr, CRLF);
641: }
642:
643: exists(devname)
644: char *devname;
645: {
646: if (access(devname, 0)==0)
647: return(1);
648: prf("%s does not exist", devname);
649: return(0);
650: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.