1: /*
   2:  * cu-- call Unix
   3:  * Modified to use Vadic 3451A modem, escape-code autodialer
   4:  */
   5: #define DIALUP      /* line is a dialup, must tell init it's in use. */
   6: /*
   7:  *  If defining DIALUP, and you have job control, compile this with
   8:  *	cc -n -O -o cu cu.c -lc -ljobs
   9:  *  because only wait2 and not signal() should come from libjobs.a.
  10:  */
  11: #include <whoami.h>
  12: #include <stdio.h>
  13: #include <signal.h>
  14: #include <sgtty.h>
  15: #if defined(SIGTSTP) && defined(DIALUP)
  16: #include <wait.h>
  17: #endif
  18: /*
  19:  * defs that come from uucp.h
  20:  */
  21: #define NAMESIZE 35
  22: #define FAIL -1
  23: #define SAME 0
  24: #define SLCKTIME 5400   /* system/device timeout (LCK.. files) in seconds */
  25: #define ASSERT(e, f, v) if (!(e)) {\
  26:     fprintf(stderr, "AERROR - (%s) ", "e");\
  27:     fprintf(stderr, f, v);\
  28:     cleanup(FAIL);\
  29: }
  30: 
  31: /*
  32:  *	cu telno [-t] [-s speed] [-l line] [-a acu] [-p]
  33:  *
  34:  *	-t is for dial-out to terminal.
  35:  *	speeds are: 110, 134, 150, 300, 1200, 2400. 300 is default.
  36:  *
  37:  *	-p says strip parity of characters transmitted.  (to compensate
  38:  *	for c100's)
  39:  *
  40:  *	Escape with `~' at beginning of line.
  41:  *	Ordinary diversions are ~<, ~> and ~>>.
  42:  *	Silent output diversions are ~>: and ~>>:.
  43:  *	Terminate output diversion with ~> alone.
  44:  *	Quit is ~. and ~! gives local command or shell.
  45:  *	Also ~$ for canned procedure pumping remote.
  46:  *	~%put from [to]  and  ~%take from [to] invoke builtins
  47:  */
  48: 
  49: #define CRLF "\r\n"
  50: #define wrc(ds) write(ds,&c,1)
  51: 
  52: 
  53: char    *devcul = "/dev/ttyd0";
  54: char    *devcua = "/dev/dialout0"; /* same minor number + 200 set */
  55: char    *lspeed = "1200";
  56: 
  57: int ln;     /* fd for comm line */
  58: char    tkill, terase;  /* current input kill & erase */
  59: int notabs;     /* terminal doesn't expand tabs */
  60: int efk;        /* process of id of listener  */
  61: char    c;
  62: char    oc;
  63: 
  64: char    *connmsg[] = {
  65:     "",
  66:     "line busy",
  67:     "call dropped",
  68:     "no carrier",
  69:     "can't fork",
  70:     "acu access",
  71:     "tty access",
  72:     "tty hung",
  73: "usage: cu telno [-t] [-p] [-n] [-h] [-b] [-acu#] [-s speed] [-l line] [-a acu]",
  74:     "lock failed: line busy"
  75: };
  76: 
  77: rdc(ds) {
  78: 
  79:     ds=read(ds,&oc,1);
  80:     c = oc & 0177;
  81:     return (ds);
  82: }
  83: 
  84: int intr;
  85: 
  86: sig2()
  87: {
  88:     signal(SIGINT, SIG_IGN);
  89:     intr = 1;
  90: }
  91: 
  92: int set14;
  93: 
  94: xsleep(n)
  95: {
  96:     xalarm(n);
  97:     pause();
  98:     xalarm(0);
  99: }
 100: 
 101: xalarm(n)
 102: {
 103:     set14=n;
 104:     alarm(n);
 105: }
 106: 
 107: sig14()
 108: {
 109:     signal(SIGALRM, sig14);
 110:     if (set14) alarm(1);
 111: }
 112: 
 113: int dout;
 114: int nhup;
 115: int dbflag;
 116: int nodial;     /* don't do autodial sequence on modem */
 117: int pflag;      /* strip parity on chars sent to remote */
 118: int hdplx;      /* set to emulate half-duplex terminal */
 119: int nullbrk;    /* turn breaks (nulls) into dels */
 120: int pipes[2] = { -1, -1 };
 121: int speed;
 122: #ifdef  DIALUP
 123: int child;      /* not suid root, let parent do cleanup */
 124: #endif
 125: 
 126: /*
 127:  *	main: get connection, set speed for line.
 128:  *	spawn child to invoke rd to read from line, output to fd 1
 129:  *	main line invokes wr to read tty, write to line
 130:  */
 131: main(ac,av)
 132: char *av[];
 133: {
 134:     int fk;
 135:     char *telno = NULL;
 136:     struct sgttyb stbuf;
 137:     int cleanup();
 138: #ifdef  DIALUP
 139: #   ifdef   SIGTSTP
 140:     union wait w;
 141: #   else
 142:     int status;
 143: #   endif
 144: #endif
 145: 
 146:     signal(SIGALRM, sig14);
 147:     nhup = (int)signal(SIGINT, cleanup);
 148:     signal(SIGHUP, cleanup);
 149:     signal(SIGQUIT, cleanup);
 150:     if (ac < 2) {
 151:         prf(connmsg[8]);
 152:         exit(8);
 153:     }
 154:     for (; ac > 1; av++,ac--) {
 155:         if (av[1][0] != '-')
 156:             telno = av[1];
 157:         else switch(av[1][1]) {
 158:         case 't':
 159:             dout = 1;
 160:             continue;
 161:         case 'b':
 162:             nullbrk++;
 163:             continue;
 164:         case 'd':
 165:             dbflag++;
 166:             continue;
 167:         case 'n':
 168:             nodial++;
 169:             continue;
 170:         case 'h':
 171:             hdplx++;
 172:             continue;
 173:         case 'p':
 174:             pflag++;
 175:             continue;
 176:         case 's':
 177:             lspeed = av[2]; ++av; --ac;
 178:             break;
 179:         case 'l':
 180:             devcul = av[2]; ++av; --ac;
 181:             break;
 182:         case 'a':
 183:             devcua = av[2]; ++av; --ac;
 184:             break;
 185:         case '0': case '1': case '2': case '3': case '4':
 186:         case '5': case '6': case '7': case '8': case '9':
 187:             devcua[strlen(devcua)-1] = av[1][1];
 188:             devcul[strlen(devcul)-1] = av[1][1];
 189:             break;
 190:         default:
 191:             prf("Bad flag %s", av[1]);
 192:             break;
 193:         }
 194:     }
 195:     if (telno == NULL && !nodial) {
 196:         prf(connmsg[8]);
 197:         exit(8);
 198:     }
 199:     if (!exists(devcua) || !exists(devcul))
 200:         exit(9);
 201:     switch(atoi(lspeed)) {
 202:     case 110:
 203:         speed = B110;break;
 204:     case 150:
 205:         speed = B150;break;
 206:     case 300:
 207:         speed = B300;break;
 208:     default:
 209:     case 1200:
 210:         speed = B1200;break;
 211:     case 2400:
 212:         speed = B2400;break;
 213:     }
 214:     ln = conn(devcul, devcua, telno);
 215:     if (ln < 0) {
 216:         prf("Connect failed: %s",connmsg[-ln]);
 217:         cleanup(-ln);
 218:     }
 219:     ioctl(0, TIOCGETP, &stbuf);
 220:     notabs = stbuf.sg_flags & XTABS;
 221:     ioctl(ln, TIOCEXCL, (struct sgttyb *)NULL);
 222:     ioctl(ln, TIOCHPCL, (struct sgttyb *)NULL);
 223:     prf("Connected");
 224: #ifdef  DIALUP
 225:     if ((fk=fork()) == 0) {
 226:         setuid(getuid());
 227:         child++;
 228:     } else {
 229:         signal(SIGINT, SIG_IGN);
 230:         signal(SIGHUP, SIG_IGN);
 231:         signal(SIGQUIT, SIG_IGN);
 232:         signal(SIGTERM,SIG_IGN);
 233: #ifndef SIGTSTP
 234:         wait(&status);
 235:         cleanup(status);
 236: #else
 237:         do {
 238:             wait2(&w.w_status, WUNTRACED);
 239:             if (WIFSTOPPED(w))
 240:                 kill(getpid(), SIGTSTP);
 241:         } while (WIFSTOPPED(w));
 242:         cleanup(w.w_status);
 243: #endif
 244:     }
 245: #endif
 246:     pipe(pipes);
 247:     if (dout)
 248:         fk = -1;
 249:     else
 250:         fk = fork();
 251:     signal(SIGINT, SIG_IGN);
 252:     if (fk == 0) {
 253:         chwrsig();
 254:         rd();
 255:         prf("\007Lost carrier");
 256:         cleanup(3);
 257:     }
 258:     mode(1);
 259:     efk = fk;
 260:     wr();
 261:     mode(0);
 262:     if (fk != -1) kill(fk, SIGKILL);
 263:     wait((int *)NULL);
 264:     stbuf.sg_ispeed = 0;
 265:     stbuf.sg_ospeed = 0;
 266:     ioctl(ln, TIOCSETP, &stbuf);
 267:     prf("Disconnected");
 268:     cleanup(0);
 269: }
 270: 
 271: /*
 272:  *	conn: establish dial-out connection.
 273:  *	Example:  fd = conn("/dev/ttyh","/dev/dn1","4500");
 274:  *	Returns descriptor open to tty for reading and writing.
 275:  *	Negative values (-1...-7) denote errors in connmsg.
 276:  *	Uses alarm and fork/wait; requires sig14 handler.
 277:  *	Be sure to disconnect tty when done, via HUPCL or stty 0.
 278:  */
 279: 
 280: #include <setjmp.h>
 281: jmp_buf timbuf;
 282: int dn;
 283: 
 284: conn(dev,acu,telno)
 285: char *dev, *acu, *telno;
 286: {
 287:     struct sgttyb stbuf;
 288:     int timeout();
 289:     int (*old_sig14)();
 290:     int (*old_sig2)();
 291:     extern errno;
 292:     char *ltail, *atail;
 293:     char *s, buf[20];
 294:     char *rindex();
 295:     int er, timerr, dh, tryagain;
 296: 
 297:     er=0;
 298:     atail = rindex(acu, '/')+1;
 299:     if (!nodial && mlock(atail) == FAIL) {
 300:         er = 9;
 301:         goto X;
 302:     }
 303:     ltail = rindex(dev, '/')+1;
 304: #ifdef  DIALUP
 305:     if (inuse(ltail)) {
 306:         er = 9;
 307:         goto X;
 308:     }
 309:     if ((mlock(ltail) == FAIL) || (untty(ltail) < 0)) {
 310: #else
 311:     if (mlock(ltail) == FAIL) {
 312: #endif
 313:         er = 9;
 314:         delock(atail);
 315:         goto X;
 316:     }
 317:     if ((dn=open(nodial? dev: acu,2))<0) {
 318:         er=(errno == 6? 1:5);
 319:         goto X;
 320:     }
 321:     stbuf.sg_ispeed = speed;
 322:     stbuf.sg_ospeed = speed;
 323:     stbuf.sg_flags = EVENP|ODDP;
 324:     if (!dout)
 325:         stbuf.sg_flags |= RAW | TANDEM;
 326:     stbuf.sg_erase = stbuf.sg_kill = 0377;
 327:     ioctl(dn, TIOCSETP, &stbuf);
 328:     old_sig14 = signal(SIGALRM,timeout);
 329:     old_sig2 = signal(SIGINT,timeout);
 330:     if (nodial) {
 331:         dh = dn;
 332:         goto X;
 333:     }
 334:     for (s=telno; *s; s++)
 335:         if (*s == '-')
 336:             *s = 'K';       /* delay char for 3451A */
 337:     tryagain = 1;       /* allow second try to get autodial mode */
 338:     intr = 0;
 339:     if (setjmp(timbuf)) {
 340:         if (!tryagain || intr) {
 341:             er = timerr;
 342:             goto X;
 343:         }
 344:         tryagain = 0;
 345:     }
 346:     timerr = 2;
 347:     alarm(30);
 348:     type(dn,"\005\r",2);            /* enter autodial mode */
 349:     waitfor(dn,"READY");
 350:     waitfor(dn,"*");
 351:     tryagain = 0;
 352:     alarm(35);
 353:     type(dn,"D\r",2);           /* Dial */
 354:     waitfor(dn,"NUMBER?\r\n");
 355:     type(dn,telno,strlen(telno));       /* the number */
 356:     type(dn,"\r",1);
 357:     alarm(30);
 358:     waitfor(dn,telno);
 359:     waitfor(dn, "\r\n");
 360:     write(dn,"\r",1);           /* and confirm it */
 361:     timerr = 3;
 362:     alarm(120);
 363:     waitfor(dn, "DIALING:  ");
 364:     for (s=buf; ; s++) {
 365:         if (read(dn, s, 1) < 1)
 366:             timeout(0);
 367:         if (dbflag)
 368:             write(1, s, 1);
 369:         if (*s == '\n')
 370:             break;
 371:     }
 372:     *s = 0;
 373:     if (strncmp(buf, "ON LINE", 7)) {
 374:         waitfor(dn, "*");
 375:         timeout(0);
 376:     }
 377:     alarm(0);
 378:     dh = open(dev,2);
 379:     if (dh<0)
 380:         er=6;
 381: X:
 382:     if (er) {
 383:         ioctl(dn, TIOCHPCL, (struct sgttyb *)NULL);
 384:         close(dn);
 385:     }
 386:     delock(atail);
 387:     signal(SIGALRM,old_sig14);
 388:     signal(SIGINT,old_sig2);
 389:     return (er? -er:dh);
 390: }
 391: /*
 392:  *  wait for string str from line fn.
 393:  *  The caller must time out if we don't get it.
 394:  */
 395: waitfor(fn, str)
 396: int fn;
 397: char *str;
 398: {
 399:     int nextch = 0;
 400:     char *rp = str;
 401: 
 402:     if (dbflag) {
 403:         write(1, "expected ", 9);
 404:         prf(str);
 405:         write(1, "got ", 4);
 406:     }
 407:     while (*rp) {
 408:         if (read(fn, &nextch, 1) < 1)
 409:             timeout(0);
 410:         if (dbflag)
 411:             write(1,&nextch,1);
 412:         if (*rp == (nextch & 0177))
 413:             rp++;
 414:         else
 415:             rp = str;
 416:     }
 417:     if (dbflag)
 418:         write(1,"\n",1);
 419: }
 420: timeout(sig){
 421:     signal(sig, timeout);
 422:     if (sig == SIGINT)
 423:         intr++;
 424:     type(dn, "I\r", 2);     /* try to get back to Idle mode */
 425:     longjmp(timbuf,1);
 426: }
 427: /*
 428:  *  Type a string to the modem.
 429:  */
 430: type(fd,s,ct)
 431: char *s;
 432: {
 433:     for (; *s; s++) {
 434:         if (*s == '\r')
 435:             sleep(1);
 436:         write(fd,s,1);
 437:     }
 438: }
 439: 
 440: /*
 441:  *	wr: write to remote: 0 -> line.
 442:  *	~.	terminate
 443:  *	~<file	send file
 444:  *	~!	local login-style shell
 445:  *	~!cmd	execute cmd locally
 446:  *	~$proc	execute proc locally, send output to line
 447:  *	~%cmd	execute builtin cmd (put and take)
 448:  *	~#	send 1-sec break
 449:  *	~^Z	suspend cu process.
 450:  */
 451: 
 452: wr()
 453: {
 454:     int ds,fk,lcl,x;
 455:     char *p,b[600];
 456:     for (;;) {
 457:         p=b;
 458:         while (rdc(0) == 1) {
 459:             if (p == b) lcl=(c == '~');
 460:             if (p == b+1 && b[0] == '~') lcl=(c!='~');
 461:             if (nullbrk && c == 0) oc=c=0177; /* fake break kludge */
 462:             if (!lcl) {
 463:                 if(!pflag)c = oc;
 464:                 if (wrc(ln) == 0) {
 465:                     prf("line gone"); return;
 466:                 }
 467:                 if (hdplx) wrc(0);
 468:                 c &= 0177;
 469:             }
 470:             if (lcl) {
 471:                 if (c == 0177) c=tkill;
 472:                 if (c == '\r' || c == '\n') goto A;
 473:                 if (!dout) wrc(0);
 474:             }
 475:             *p++=c;
 476:             if (c == terase) {
 477:                 p=p-2;
 478:                 if (p<b) p=b;
 479:             }
 480:             if (c == tkill || c == 0177 || c == '\4' || c == '\r' || c == '\n') p=b;
 481:         }
 482:         return;
 483: A:
 484:         if (!dout) echo("");
 485:         *p=0;
 486:         switch (b[1]) {
 487:         case '.':
 488:         case '\004':
 489:             return;
 490: #ifdef  TIOCSBRK
 491:         case '#':
 492:             if (ioctl(ln, TIOCSBRK, 0) < 0)
 493:                 prf("can't send break");
 494:             else {
 495:                 sleep(1);
 496:                 ioctl(ln, TIOCCBRK, 0);
 497:                 continue;
 498:             }
 499: #endif
 500:         case '!':
 501:         case '$':
 502:             fk = fork();
 503:             if (fk == 0) {
 504:                 char *getenv();
 505:                 char *shell = getenv("SHELL");
 506:                 if (shell == 0) shell = "/bin/sh";
 507:                 close(1);
 508:                 dup(b[1] == '$'? ln:2);
 509:                 close(ln);
 510:                 mode(0);
 511:                 if (!nhup) signal(SIGINT, SIG_DFL);
 512:                 if (b[2] == 0) execl(shell,shell,0);
 513:                 /* if (b[2] == 0) execl(shell,"-",0); */
 514:                 else execl(shell,"sh","-c",b+2,0);
 515:                 prf("Can't execute shell");
 516:                 exit(~0);
 517:             }
 518:             if (fk!=(-1)) {
 519:                 while (wait(&x)!=fk);
 520:             }
 521:             mode(1);
 522:             if (b[1] == '!') echo("!");
 523:             else {
 524:                 if (dout) echo("$");
 525:             }
 526:             break;
 527:         case '<':
 528:             if (b[2] == 0) break;
 529:             if ((ds=open(b+2,0))<0) {
 530:                 prf("Can't divert %s",b+1);
 531:                 break;
 532:             }
 533:             intr=x=0;
 534:             mode(2);
 535:             if (!nhup) signal(SIGINT, sig2);
 536:             while (!intr && rdc(ds) == 1) {
 537:                 if (wrc(ln) == 0) {
 538:                     x=1;
 539:                     break;
 540:                 }
 541:             }
 542:             signal(SIGINT, SIG_IGN);
 543:             close(ds);
 544:             mode(1);
 545:             if (x) return;
 546:             if (dout) echo("<");
 547:             break;
 548:         case '>':
 549:         case ':':
 550:             {
 551:             register char *q;
 552: 
 553:             if(pipes[1]==-1) {
 554:                 prf("Can't tell other demon to divert");
 555:                 break;
 556:             }
 557:             q = b+1;
 558:             if(*q=='>') q++;
 559:             write(pipes[1],q,strlen(q)+1);
 560:             if(dbflag) prf("msg to be delivered:"),prf(q);
 561:             if (efk != -1) kill(efk,SIGEMT);
 562:             }
 563:             break;
 564: #ifdef SIGTSTP
 565: #define CTRLZ   26
 566:         case CTRLZ:
 567:             mode(0);
 568:             kill(getpid(), SIGTSTP);
 569:             mode(1);
 570:             break;
 571: #endif
 572:         case '%':
 573:             dopercen(&b[2]);
 574:             break;
 575:         default:
 576:             prf("Use `~~' to start line with `~'");
 577:         }
 578:         continue;
 579:     }
 580: }
 581: 
 582: dopercen(line)
 583: register char *line;
 584: {
 585:     char *args[10];
 586:     register narg, f;
 587:     int rcount;
 588:     for (narg = 0; narg < 10;) {
 589:         while(*line == ' ' || *line == '\t')
 590:             line++;
 591:         if (*line == '\0')
 592:             break;
 593:         args[narg++] = line;
 594:         while(*line != '\0' && *line != ' ' && *line != '\t')
 595:             line++;
 596:         if (*line == '\0')
 597:             break;
 598:         *line++ = '\0';
 599:     }
 600:     if (equal(args[0], "take")) {
 601:         if (narg < 2) {
 602:             prf("usage: ~%%take from [to]");
 603:             return;
 604:         }
 605:         if (narg < 3)
 606:             args[2] = args[1];
 607:         write(pipes[1], ">/dev/null",sizeof(">/dev/null"));
 608:         if(dbflag) prf("sending take message");
 609:         if (efk != -1) kill(efk,SIGEMT);
 610:         xsleep(5);
 611:         if (notabs)
 612:             wrln("stty tabs;");
 613:         wrln("echo '~>:");
 614:         wrln(args[2]);
 615:         wrln("'; tee /dev/null <");
 616:         wrln(args[1]);
 617:         wrln(";echo '~>'");
 618:         if (notabs)
 619:             wrln(";stty -tabs");
 620:         wrln("\n");
 621:         return;
 622:     } else if (equal(args[0], "put")) {
 623:         if (narg < 2) {
 624:             prf("usage: ~%%put from [to]");
 625:             return;
 626:         }
 627:         if (narg < 3)
 628:             args[2] = args[1];
 629:         if ((f = open(args[1], 0)) < 0) {
 630:             prf("cannot open: %s", args[1]);
 631:             return;
 632:         }
 633:         wrln("stty -echo;cat >");
 634:         wrln(args[2]);
 635:         wrln(";stty echo\n");
 636:         xsleep(5);
 637:         intr = 0;
 638:         if (!nhup)
 639:             signal(SIGINT, sig2);
 640:         mode(2);
 641:         rcount = 0;
 642:         while(!intr && rdc(f) == 1) {
 643:             rcount++;
 644:             if (c == tkill || c == terase)
 645:                 wrln("\\");
 646:             if (wrc(ln) != 1) {
 647:                 xsleep(2);
 648:                 if (wrc(ln) != 1) {
 649:                     prf("character missed");
 650:                     intr = 1;
 651:                     break;
 652:                 }
 653:             }
 654:         }
 655:         signal(SIGINT, SIG_IGN);
 656:         close(f);
 657:         if (intr) {
 658:             wrln("\n");
 659:             prf("stopped after %d bytes", rcount);
 660:         }
 661:         wrln("\004");
 662:         xsleep(5);
 663:         mode(1);
 664:         return;
 665:     }
 666:     prf("~%%%s unknown\n", args[0]);
 667: }
 668: 
 669: equal(s1, s2)
 670: register char *s1, *s2;
 671: {
 672:     while (*s1++ == *s2)
 673:         if (*s2++ == '\0')
 674:             return(1);
 675:     return(0);
 676: }
 677: 
 678: wrln(s)
 679: register char *s;
 680: {
 681:     while (*s)
 682:         write(ln, s++, 1);
 683: }
 684: /*	chwrsig:  Catch orders from wr process
 685:  *	to instigate diversion
 686:  */
 687: int whoami;
 688: chwrsig(){
 689:     int readmsg();
 690:     whoami = getpid();
 691:     signal(SIGEMT,readmsg);
 692: }
 693: int ds,slnt,taking;
 694: int justrung;
 695: readmsg(){
 696:     static char dobuff[128], morejunk[256];
 697:     int n;
 698:     justrung = 1;
 699:     signal(SIGEMT,readmsg);
 700:     if(dbflag) {
 701:         prf("About to read from pipe");
 702:     }
 703:     n = read(pipes[0],morejunk,256);
 704:     if(dbflag) {
 705:         prf("diversion mesg recieved is");
 706:         prf(morejunk);
 707:         prf(CRLF);
 708:     }
 709:     dodiver(morejunk);
 710: }
 711: dodiver(msg)
 712: char *msg;
 713: {
 714:     register char *cp = msg;
 715: 
 716:     if (*cp=='>') cp++;
 717:     if (*cp==':') {
 718:         cp++;
 719:         if(*cp==0) {
 720:             slnt ^= 1;
 721:             return;
 722:         } else  {
 723:             slnt = 1;
 724:         }
 725:     }
 726:     if (ds >= 0) close(ds);
 727:     if (*cp==0) {
 728:         slnt = 0;
 729:         ds = -1;
 730:         return;
 731:     }
 732:     if (*msg!='>' || (ds=open(cp,1))<0) ds=creat(cp,0644);
 733:     lseek(ds, (long)0, 2);
 734:     if(ds < 0) prf("Creat failed:"), prf(cp);
 735:     if (ds<0) prf("Can't divert %s",cp+1);
 736: }
 737: 
 738: 
 739: /*
 740:  *	rd: read from remote: line -> 1
 741:  *	catch: diversion caught by interrupt routine
 742:  */
 743: 
 744: #define ORDIN 0
 745: #define SAWCR 1
 746: #define EOL   2
 747: #define SAWTL 3
 748: #define DIVER 4
 749: 
 750: rd()
 751: {
 752:     extern int ds,slnt;
 753:     char rb[600], lb[600], *rlim, *llim, c;
 754:     register char *p,*q;
 755:     int cnt, state = ORDIN, mustecho, oldslnt;
 756: 
 757:     ds=(-1);
 758:     p = lb; llim = lb+600;
 759: agin:
 760:     while((cnt = read(ln,rb,600)) > 0) {
 761:         if(!slnt) {
 762:             if (pflag)
 763:                 for (q=rb, rlim = rb + cnt - 1; q <= rlim; )
 764:                     *q++ &= 0177;
 765:             write(1,rb,cnt);
 766:         }
 767:         if(ds < 0) continue;
 768:         oldslnt = slnt;
 769:         for( q=rb, rlim = rb + cnt - 1; q <= rlim; ) {
 770:             c = *q++ & 0177;
 771:             if(p < llim) *p++ = c;
 772:             switch(state) {
 773:             case ORDIN:
 774:                 if(c=='\r') state = SAWCR;
 775:                 break;
 776:             case SAWCR:
 777:                 if(c=='\n') {
 778:                     state = EOL;
 779:                     p--;
 780:                     p[-1] = '\n';
 781:                 } else state = ORDIN;
 782:                 break;
 783:             case EOL:
 784:                 state = (c=='~' ? SAWTL :
 785:                      (c=='\r' ? SAWCR : ORDIN));
 786:                 break;
 787:             case SAWTL:
 788:                 state = (c=='>' ? DIVER :
 789:                      (c=='\r' ? SAWCR : ORDIN));
 790:                 break;
 791:             case DIVER:
 792:                 if(c=='\r') {
 793:                     p--;
 794:                 } else if (c=='\n') {
 795:                     state = ORDIN;
 796:                     p[-1] = 0;
 797:                     dodiver(lb+2);
 798:                     c = 0; p = lb;
 799:                 }
 800:             }
 801:             if(slnt==0 && oldslnt) {
 802:                 if(c=='\n') {
 803:                     write(1,lb,p-lb-1);
 804:                     write(1,CRLF,sizeof(CRLF));
 805:                 } else if(q==rlim) {
 806:                     write(1,lb,p-lb);
 807:                     c = '\n';  /*force flush to file*/
 808:                 }
 809:             }
 810:             if(c=='\n') {
 811:                 if(ds >= 0)
 812:                     write(ds,lb,p-lb);
 813:                 p = lb;
 814:             }
 815:         }
 816:     }
 817:     if(justrung) {
 818:         justrung = 0;
 819:         goto agin;
 820:     }
 821: }
 822: 
 823: struct {char lobyte; char hibyte;};
 824: 
 825: mode(f)
 826: {
 827:     struct sgttyb stbuf;
 828:     if (dout) return;
 829:     ioctl(0, TIOCGETP, &stbuf);
 830:     tkill = stbuf.sg_kill;
 831:     terase = stbuf.sg_erase;
 832:     if (f == 0) {
 833:         stbuf.sg_flags &= ~RAW;
 834:         stbuf.sg_flags |= ECHO|CRMOD;
 835:     }
 836:     if (f == 1) {
 837:         stbuf.sg_flags |= RAW;
 838:         stbuf.sg_flags &= ~(ECHO|CRMOD);
 839:     }
 840:     if (f == 2) {
 841:         stbuf.sg_flags &= ~RAW;
 842:         stbuf.sg_flags &= ~(ECHO|CRMOD);
 843:     }
 844:     ioctl(0, TIOCSETN, &stbuf);
 845: }
 846: 
 847: echo(s)
 848: char *s;
 849: {
 850:     char *p;
 851:     for (p=s;*p;p++);
 852:     if (p>s) write(0,s,p-s);
 853:     write(0,CRLF, sizeof(CRLF));
 854: }
 855: 
 856: prf(f, s)
 857: char *f;
 858: char *s;
 859: {
 860:     fprintf(stderr, f, s);
 861:     fprintf(stderr, CRLF);
 862: }
 863: 
 864: exists(devname)
 865: char *devname;
 866: {
 867:     if (access(devname, 0)==0)
 868:         return(1);
 869:     prf("%s does not exist", devname);
 870:     return(0);
 871: }
 872: 
 873: cleanup(code)
 874: {
 875: #ifdef  DIALUP
 876:     /*
 877: 	 * Let the parent do the cleanup.
 878: 	 */
 879:     if (child)
 880:         exit(code);
 881: #endif
 882:     rmlock(NULL);
 883:     ioctl(ln, TIOCNXCL, (struct sgttyb *)NULL);
 884:     close(ln);
 885:     close(dn);
 886: 
 887: #ifdef  DIALUP
 888:     ttyrlse();
 889: #endif
 890:     exit(code);
 891: }
 892: 
 893: /*
 894:  * This code is taken directly from uucp and follows the same
 895:  * conventions.  This is important since uucp and cu should
 896:  * respect each others locks.
 897:  */
 898: 
 899:     /*  ulockf 3.2  10/26/79  11:40:29  */
 900: /* #include "uucp.h" */
 901: #include <sys/types.h>
 902: #include <sys/stat.h>
 903: 
 904: 
 905: 
 906: /*******
 907:  *	ulockf(file, atime)
 908:  *	char *file;
 909:  *	time_t atime;
 910:  *
 911:  *	ulockf  -  this routine will create a lock file (file).
 912:  *	If one already exists, the create time is checked for
 913:  *	older than the age time (atime).
 914:  *	If it is older, an attempt will be made to unlink it
 915:  *	and create a new one.
 916:  *
 917:  *	return codes:  0  |  FAIL
 918:  */
 919: 
 920: ulockf(file, atime)
 921: char *file;
 922: time_t atime;
 923: {
 924:     struct stat stbuf;
 925:     time_t ptime;
 926:     int ret;
 927:     static int pid = -1;
 928:     static char tempfile[NAMESIZE];
 929: 
 930:     if (pid < 0) {
 931:         pid = getpid();
 932:         sprintf(tempfile, "/usr/spool/uucp/LTMP.%d", pid);
 933:     }
 934:     if (onelock(pid, tempfile, file) == -1) {
 935:         /* lock file exists */
 936:         /* get status to check age of the lock file */
 937:         ret = stat(file, &stbuf);
 938:         if (ret != -1) {
 939:             time(&ptime);
 940:             if ((ptime - stbuf.st_ctime) < atime) {
 941:                 /* file not old enough to delete */
 942:                 return(FAIL);
 943:             }
 944:         }
 945:         ret = unlink(file);
 946:         ret = onelock(pid, tempfile, file);
 947:         if (ret != 0)
 948:             return(FAIL);
 949:     }
 950:     stlock(file);
 951:     return(0);
 952: }
 953: 
 954: 
 955: #define MAXLOCKS 10 /* maximum number of lock files */
 956: char *Lockfile[MAXLOCKS];
 957: int Nlocks = 0;
 958: 
 959: /***
 960:  *	stlock(name)	put name in list of lock files
 961:  *	char *name;
 962:  *
 963:  *	return codes:  none
 964:  */
 965: 
 966: stlock(name)
 967: char *name;
 968: {
 969:     char *p;
 970:     extern char *calloc();
 971:     int i;
 972: 
 973:     for (i = 0; i < Nlocks; i++) {
 974:         if (Lockfile[i] == NULL)
 975:             break;
 976:     }
 977:     ASSERT(i < MAXLOCKS, "TOO MANY LOCKS %d", i);
 978:     if (i >= Nlocks)
 979:         i = Nlocks++;
 980:     p = calloc(strlen(name) + 1, sizeof (char));
 981:     ASSERT(p != NULL, "CAN NOT ALLOCATE FOR %s", name);
 982:     strcpy(p, name);
 983:     Lockfile[i] = p;
 984:     return;
 985: }
 986: 
 987: 
 988: /***
 989:  *	rmlock(name)	remove all lock files in list
 990:  *	char *name;	or name
 991:  *
 992:  *	return codes: none
 993:  */
 994: 
 995: rmlock(name)
 996: char *name;
 997: {
 998:     int i;
 999: 
1000:     for (i = 0; i < Nlocks; i++) {
1001:         if (Lockfile[i] == NULL)
1002:             continue;
1003:         if (name == NULL
1004:         || strcmp(name, Lockfile[i]) == SAME) {
1005:             unlink(Lockfile[i]);
1006:             free(Lockfile[i]);
1007:             Lockfile[i] = NULL;
1008:         }
1009:     }
1010:     return;
1011: }
1012: 
1013: 
1014: /*  this stuff from pjw  */
1015: /*  /usr/pjw/bin/recover - check pids to remove unnecessary locks */
1016: /*	isalock(name) returns 0 if the name is a lock */
1017: /*	unlock(name)  unlocks name if it is a lock*/
1018: /*	onelock(pid,tempfile,name) makes lock a name
1019: 	on behalf of pid.  Tempfile must be in the same
1020: 	file system as name. */
1021: /*	lock(pid,tempfile,names) either locks all the
1022: 	names or none of them */
1023: isalock(name) char *name;
1024: {
1025:     struct stat xstat;
1026:     if(stat(name,&xstat)<0) return(0);
1027:     if(xstat.st_size!=sizeof(int)) return(0);
1028:     return(1);
1029: }
1030: unlock(name) char *name;
1031: {
1032:     if(isalock(name)) return(unlink(name));
1033:     else return(-1);
1034: }
1035: onelock(pid,tempfile,name) char *tempfile,*name;
1036: {   int fd;
1037:     fd=creat(tempfile,0444);
1038:     if(fd<0) return(-1);
1039:     write(fd,(char *) &pid,sizeof(int));
1040:     close(fd);
1041:     if(link(tempfile,name)<0)
1042:     {   unlink(tempfile);
1043:         return(-1);
1044:     }
1045:     unlink(tempfile);
1046:     return(0);
1047: }
1048: lock(pid,tempfile,names) char *tempfile,**names;
1049: {   int i,j;
1050:     for(i=0;names[i]!=0;i++)
1051:     {   if(onelock(pid,tempfile,names[i])==0) continue;
1052:         for(j=0;j<i;j++) unlink(names[j]);
1053:         return(-1);
1054:     }
1055:     return(0);
1056: }
1057: 
1058: #define LOCKPRE "/usr/spool/uucp/LCK."
1059: 
1060: /***
1061:  *	delock(s)	remove a lock file
1062:  *	char *s;
1063:  *
1064:  *	return codes:  0  |  FAIL
1065:  */
1066: 
1067: delock(s)
1068: char *s;
1069: {
1070:     char ln[30];
1071: 
1072:     sprintf(ln, "%s.%s", LOCKPRE, s);
1073:     rmlock(ln);
1074: }
1075: 
1076: 
1077: /***
1078:  *	mlock(sys)	create system lock
1079:  *	char *sys;
1080:  *
1081:  *	return codes:  0  |  FAIL
1082:  */
1083: 
1084: mlock(sys)
1085: char *sys;
1086: {
1087:     char lname[30];
1088:     sprintf(lname, "%s.%s", LOCKPRE, sys);
1089:     return(ulockf(lname, (time_t) SLCKTIME ) < 0 ? FAIL : 0);
1090: }
1091: 
1092: 
1093: 
1094: /***
1095:  *	ultouch()	update access and modify times for lock files
1096:  *
1097:  *	return code - none
1098:  */
1099: 
1100: ultouch()
1101: {
1102:     time_t time();
1103:     int i;
1104:     struct ut {
1105:         time_t actime;
1106:         time_t modtime;
1107:     } ut;
1108: 
1109:     ut.actime = time(&ut.modtime);
1110:     for (i = 0; i < Nlocks; i++) {
1111:         if (Lockfile[i] == NULL)
1112:             continue;
1113:         utime(Lockfile[i], &ut);
1114:     }
1115:     return;
1116: }
1117: 
1118: #ifdef  DIALUP
1119: /*
1120:  * Routines to allow cu to use a dialup line to call out.
1121:  */
1122: #include <utmp.h>
1123: #define UTMP    "/etc/utmp"
1124: #define TTYS    "/etc/ttys"
1125: #define MAXLINE 80      /* maximum line length in TTYS */
1126: 
1127: static char WasOn;      /* first char of line's entry in ttys */
1128: static char *tty;       /* last part of tty device pathname */
1129: char    *rindex();
1130: 
1131: /*
1132:  * Check whether anyone is logged in on devcul.
1133:  */
1134: inuse(devcul)
1135: char *devcul;
1136: {
1137:     register fi;
1138:     struct utmp utmpb;
1139:     char *tmp;
1140: 
1141:     if ((tmp=rindex(devcul,'/')) != NULL)
1142:         devcul = tmp+1;
1143:     fi=open(UTMP,0);
1144:     while(read(fi,&utmpb,sizeof(utmpb)) == sizeof(utmpb))
1145:         if (strcmp(utmpb.ut_line,devcul) == 0) {
1146:             if ( *utmpb.ut_name != 0 ) {
1147:                 fprintf(stderr,"%s is in use\n",devcul);
1148:                 return(-1);
1149:             }
1150:             break;
1151:         }
1152:     close(fi);
1153:     return(0);
1154: }
1155: 
1156: #ifdef  DIALUP
1157: /*
1158:  *  Remove devcul from TTYS file, notify init that line is
1159:  *  no longer available.
1160:  */
1161: untty(devcul)
1162: char *devcul;
1163: {
1164:     register fi, ret;
1165:     char    line[MAXLINE];
1166: 
1167:     if ((tty=rindex(devcul,'/')) != NULL)
1168:         tty++;
1169:     else
1170:         tty = devcul;
1171:     fi = open(TTYS,2);
1172:     if (fi < 0) {
1173:         fprintf(stderr,"can't modify %s\n",TTYS);
1174:         return (-1);
1175:     }
1176:     WasOn = '0';
1177:     while (ret=getline(fi,line)) {
1178:         if (equal(line+2,tty)) {
1179:             WasOn = line[0];
1180:             break;
1181:         }
1182:     }
1183:     if (ret == 0)
1184:         return(0);
1185:     if (WasOn != '0') {
1186:         lseek(fi,-(long)(ret+1),1);
1187:         write(fi,"0",1);
1188:     }
1189:     close(fi);
1190:     if (WasOn != '0') {
1191:         kill(1,1);
1192:         sleep(2);   /* wait for init/getty to go away */
1193:     }
1194:     return(0);
1195: }
1196: 
1197: /*
1198:  *  Restore line to dialup service (removed from service by untty).
1199:  *  Uses pointer to name saved by untty.
1200:  */
1201: ttyrlse()
1202: {
1203:     register fi, ct;
1204:     char *tmp;
1205:     char    line[MAXLINE];
1206: 
1207:     if (tty == NULL || WasOn == '0')
1208:         return;
1209:     fi = open(TTYS,2);
1210:     if (fi < 0) {
1211:         fprintf(stderr,"can't modify %s\n",TTYS);
1212:         return (-1);
1213:     }
1214:     while (ct=getline(fi,line)) {
1215:         if (equal(line+2,tty)) {
1216:             lseek(fi,-(long)(ct+1),1);
1217:             write(fi,&WasOn,1);
1218:             close(fi);
1219:             kill(1,1);
1220:             return(0);
1221:         }
1222:     }
1223:     fprintf(stderr,"%s not in %s now\n",tty,TTYS);
1224:     return(-1);
1225: }
1226: #endif	DIALUP
1227: 
1228: /*
1229:  * Read a line from the ttys file.  Null terminate at the end
1230:  * of the name.
1231:  */
1232: getline(fd,buf)
1233: char *buf;
1234: {
1235:     char c;
1236:     register char *p, *lim = buf+MAXLINE-1;
1237:     register count = 0;
1238: 
1239:     p = buf;
1240:     while (read(fd,&c,1) && c!='\n') {
1241:         count++;
1242:         if (p<lim)
1243:             *p++ = c;
1244:     }
1245:     *p = 0;
1246:     for (p=buf; *p; p++)
1247:         if (*p==' ' || *p=='\t')
1248:             break;
1249:     *p = 0;
1250:     return(count);
1251: }
1252: #endif

Defined functions

chwrsig defined in line 688; used 1 times
cleanup defined in line 873; used 10 times
conn defined in line 284; used 1 times
delock defined in line 1067; used 2 times
dodiver defined in line 711; used 2 times
dopercen defined in line 582; used 1 times
echo defined in line 847; used 4 times
equal defined in line 669; used 4 times
exists defined in line 864; used 2 times
  • in line 199(2)
getline defined in line 1232; used 2 times
inuse defined in line 1134; used 1 times
isalock defined in line 1023; used 1 times
lock defined in line 1048; never used
main defined in line 131; never used
mlock defined in line 1084; used 3 times
mode defined in line 825; used 10 times
onelock defined in line 1035; used 3 times
prf defined in line 856; used 31 times
rd defined in line 750; used 1 times
rdc defined in line 77; used 3 times
readmsg defined in line 695; used 3 times
rindex defined in line 303; used 4 times
rmlock defined in line 995; used 2 times
sig14 defined in line 107; used 2 times
sig2 defined in line 86; used 2 times
stlock defined in line 966; used 1 times
timeout defined in line 420; used 7 times
ttyrlse defined in line 1201; used 1 times
type defined in line 430; used 5 times
ulockf defined in line 920; used 1 times
ultouch defined in line 1100; never used
unlock defined in line 1030; never used
untty defined in line 1161; used 1 times
waitfor defined in line 395; used 7 times
wr defined in line 452; used 1 times
wrln defined in line 678; used 14 times
xalarm defined in line 101; used 2 times
xsleep defined in line 94; used 4 times

Defined variables

Lockfile defined in line 956; used 9 times
Nlocks defined in line 957; used 5 times
WasOn defined in line 1127; used 6 times
c defined in line 61; used 40 times
child defined in line 123; used 2 times
connmsg defined in line 64; used 3 times
dbflag defined in line 115; used 9 times
devcua defined in line 54; used 5 times
devcul defined in line 53; used 15 times
dn defined in line 282; used 20 times
dout defined in line 113; used 8 times
ds defined in line 693; used 23 times
efk defined in line 60; used 5 times
hdplx defined in line 118; used 2 times
intr defined in line 84; used 10 times
justrung defined in line 694; used 3 times
ln defined in line 57; used 22 times
lspeed defined in line 55; used 2 times
nhup defined in line 114; used 4 times
nodial defined in line 116; used 5 times
notabs defined in line 59; used 3 times
nullbrk defined in line 119; used 2 times
oc defined in line 62; used 4 times
pflag defined in line 117; used 3 times
pipes defined in line 120; used 5 times
set14 defined in line 92; used 2 times
slnt defined in line 693; used 7 times
speed defined in line 121; used 7 times
taking defined in line 693; never used
terase defined in line 58; used 3 times
timbuf defined in line 281; used 2 times
tkill defined in line 58; used 4 times
tty defined in line 1128; used 7 times
whoami defined in line 687; used 1 times

Defined struct's

ut defined in line 1104; never used

Defined macros

ASSERT defined in line 25; used 2 times
CRLF defined in line 49; used 6 times
CTRLZ defined in line 565; never used
DIALUP defined in line 5; used 9 times
DIVER defined in line 748; used 1 times
EOL defined in line 746; used 1 times
FAIL defined in line 22; used 7 times
LOCKPRE defined in line 1058; used 2 times
MAXLINE defined in line 1125; used 3 times
MAXLOCKS defined in line 955; used 2 times
NAMESIZE defined in line 21; used 1 times
ORDIN defined in line 744; used 5 times
SAME defined in line 23; used 1 times
SAWCR defined in line 745; used 3 times
SAWTL defined in line 747; used 1 times
SLCKTIME defined in line 24; used 1 times
TTYS defined in line 1124; used 5 times
UTMP defined in line 1123; used 1 times
wrc defined in line 50; used 6 times
Last modified: 1983-12-22
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3471
Valid CSS Valid XHTML 1.0 Strict