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