1 static char *sccsid = "@(#)cu.c 4.1 (Berkeley) 10/01/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 } 651