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