1*2370Smark static char *sccsid = "@(#)cu.c 4.2 (Berkeley) 02/07/81"; 2996Sbill #include <stdio.h> 3996Sbill #include <signal.h> 4996Sbill #include <sgtty.h> 5*2370Smark 6996Sbill /* 7*2370Smark * defs that come from uucp.h 8*2370Smark */ 9*2370Smark #define NAMESIZE 15 10*2370Smark #define FAIL -1 11*2370Smark #define SAME 0 12*2370Smark #define SLCKTIME 5400 /* system/device timeout (LCK.. files) in seconds */ 13*2370Smark #define ASSERT(e, f, v) if (!(e)) {\ 14*2370Smark fprintf(stderr, "AERROR - (%s) ", "e");\ 15*2370Smark fprintf(stderr, f, v);\ 16*2370Smark cleanup(FAIL);\ 17*2370Smark } 18*2370Smark 19*2370Smark /* 20996Sbill * cu telno [-t] [-s speed] [-l line] [-a acu] 21996Sbill * 22996Sbill * -t is for dial-out to terminal. 23996Sbill * speeds are: 110, 134, 150, 300, 1200. 300 is default. 24996Sbill * 25996Sbill * Escape with `~' at beginning of line. 26996Sbill * Ordinary diversions are ~<, ~> and ~>>. 27996Sbill * Silent output diversions are ~>: and ~>>:. 28996Sbill * Terminate output diversion with ~> alone. 29996Sbill * Quit is ~. and ~! gives local command or shell. 30996Sbill * Also ~$ for canned procedure pumping remote. 31996Sbill * ~%put from [to] and ~%take from [to] invoke builtins 32996Sbill */ 33996Sbill 34996Sbill #define CRLF "\r\n" 35996Sbill #define wrc(ds) write(ds,&c,1) 36996Sbill 37996Sbill 38996Sbill char *devcul = "/dev/cul0"; 39996Sbill char *devcua = "/dev/cua0"; 40996Sbill char *lspeed = "300"; 41996Sbill 42996Sbill int ln; /* fd for comm line */ 43996Sbill char tkill, terase; /* current input kill & erase */ 44996Sbill int efk; /* process of id of listener */ 45996Sbill char c; 46996Sbill char oc; 47996Sbill 48996Sbill char *connmsg[] = { 49996Sbill "", 50996Sbill "line busy", 51996Sbill "call dropped", 52996Sbill "no carrier", 53996Sbill "can't fork", 54996Sbill "acu access", 55996Sbill "tty access", 56996Sbill "tty hung", 57*2370Smark "usage: cu telno [-t] [-s speed] [-l line] [-a acu]", 58*2370Smark "lock failed: line busy" 59996Sbill }; 60996Sbill 61996Sbill rdc(ds) { 62996Sbill 63996Sbill ds=read(ds,&c,1); 64996Sbill oc = c; 65996Sbill c &= 0177; 66996Sbill return (ds); 67996Sbill } 68996Sbill 69996Sbill int intr; 70996Sbill 71996Sbill sig2() 72996Sbill { 73996Sbill signal(SIGINT, SIG_IGN); 74996Sbill intr = 1; 75996Sbill } 76996Sbill 77996Sbill int set14; 78996Sbill 79996Sbill xsleep(n) 80996Sbill { 81996Sbill xalarm(n); 82996Sbill pause(); 83996Sbill xalarm(0); 84996Sbill } 85996Sbill 86996Sbill xalarm(n) 87996Sbill { 88996Sbill set14=n; 89996Sbill alarm(n); 90996Sbill } 91996Sbill 92996Sbill sig14() 93996Sbill { 94996Sbill signal(SIGALRM, sig14); 95996Sbill if (set14) alarm(1); 96996Sbill } 97996Sbill 98996Sbill int dout; 99996Sbill int nhup; 100996Sbill int dbflag; 101*2370Smark int nullbrk; /* turn breaks (nulls) into dels */ 102996Sbill 103996Sbill /* 104996Sbill * main: get connection, set speed for line. 105996Sbill * spawn child to invoke rd to read from line, output to fd 1 106996Sbill * main line invokes wr to read tty, write to line 107996Sbill */ 108996Sbill main(ac,av) 109996Sbill char *av[]; 110996Sbill { 111996Sbill int fk; 112996Sbill int speed; 113996Sbill char *telno; 114996Sbill struct sgttyb stbuf; 115996Sbill 116996Sbill signal(SIGALRM, sig14); 117996Sbill if (ac < 2) { 118996Sbill prf(connmsg[8]); 119996Sbill exit(8); 120996Sbill } 121996Sbill for (; ac > 1; av++,ac--) { 122996Sbill if (av[1][0] != '-') 123996Sbill telno = av[1]; 124996Sbill else switch(av[1][1]) { 125996Sbill case 't': 126996Sbill dout = 1; 127996Sbill --ac; 128996Sbill continue; 129*2370Smark case 'b': 130*2370Smark nullbrk++; 131*2370Smark continue; 132996Sbill case 'd': 133996Sbill dbflag++; 134996Sbill continue; 135996Sbill case 's': 136996Sbill lspeed = av[2]; ++av; --ac; 137996Sbill break; 138996Sbill case 'l': 139996Sbill devcul = av[2]; ++av; --ac; 140996Sbill break; 141996Sbill case 'a': 142996Sbill devcua = av[2]; ++av; --ac; 143996Sbill break; 144996Sbill case '0': case '1': case '2': case '3': case '4': 145996Sbill case '5': case '6': case '7': case '8': case '9': 146996Sbill devcua[strlen(devcua)-1] = av[1][1]; 147996Sbill devcul[strlen(devcul)-1] = av[1][1]; 148996Sbill break; 149996Sbill default: 150996Sbill prf("Bad flag %s", av[1]); 151996Sbill break; 152996Sbill } 153996Sbill } 154996Sbill if (!exists(devcua) || !exists(devcul)) 155996Sbill exit(9); 156996Sbill ln = conn(devcul, devcua, telno); 157996Sbill if (ln < 0) { 158996Sbill prf("Connect failed: %s",connmsg[-ln]); 159*2370Smark cleanup(-ln); 160996Sbill } 161996Sbill switch(atoi(lspeed)) { 162996Sbill case 110: 163996Sbill speed = B110;break; 164996Sbill case 150: 165996Sbill speed = B150;break; 166996Sbill default: 167996Sbill case 300: 168996Sbill speed = B300;break; 169996Sbill case 1200: 170996Sbill speed = B1200;break; 171996Sbill } 172996Sbill stbuf.sg_ispeed = speed; 173996Sbill stbuf.sg_ospeed = speed; 174996Sbill stbuf.sg_flags = EVENP|ODDP; 175996Sbill if (!dout) { 176996Sbill stbuf.sg_flags |= RAW; 177996Sbill stbuf.sg_flags &= ~ECHO; 178996Sbill } 179996Sbill ioctl(ln, TIOCSETP, &stbuf); 180996Sbill ioctl(ln, TIOCEXCL, (struct sgttyb *)NULL); 181996Sbill ioctl(ln, TIOCHPCL, (struct sgttyb *)NULL); 182996Sbill prf("Connected"); 183996Sbill if (dout) 184996Sbill fk = -1; 185996Sbill else 186996Sbill fk = fork(); 187996Sbill nhup = (int)signal(SIGINT, SIG_IGN); 188996Sbill if (fk == 0) { 189996Sbill chwrsig(); 190996Sbill rd(); 191996Sbill prf("\007Lost carrier"); 192*2370Smark cleanup(3); 193996Sbill } 194996Sbill mode(1); 195996Sbill efk = fk; 196996Sbill wr(); 197996Sbill mode(0); 198996Sbill kill(fk, SIGKILL); 199996Sbill wait((int *)NULL); 200996Sbill stbuf.sg_ispeed = 0; 201996Sbill stbuf.sg_ospeed = 0; 202996Sbill ioctl(ln, TIOCSETP, &stbuf); 203996Sbill prf("Disconnected"); 204*2370Smark cleanup(0); 205996Sbill } 206996Sbill 207996Sbill /* 208996Sbill * conn: establish dial-out connection. 209996Sbill * Example: fd = conn("/dev/ttyh","/dev/dn1","4500"); 210996Sbill * Returns descriptor open to tty for reading and writing. 211996Sbill * Negative values (-1...-7) denote errors in connmsg. 212996Sbill * Uses alarm and fork/wait; requires sig14 handler. 213996Sbill * Be sure to disconnect tty when done, via HUPCL or stty 0. 214996Sbill */ 215996Sbill 216996Sbill conn(dev,acu,telno) 217996Sbill char *dev, *acu, *telno; 218996Sbill { 219996Sbill struct sgttyb stbuf; 220996Sbill extern errno; 221996Sbill char *p, *q, b[30]; 222*2370Smark char *ltail, *atail; 223*2370Smark char *rindex(); 224996Sbill int er, fk, dn, dh, t; 225996Sbill er=0; 226996Sbill fk=(-1); 227*2370Smark atail = rindex(acu, '/')+1; 228*2370Smark if (mlock(atail) == FAIL) { 229*2370Smark er = 9; 230*2370Smark goto X; 231*2370Smark } 232*2370Smark ltail = rindex(dev, '/')+1; 233*2370Smark if (mlock(ltail) == FAIL) { 234*2370Smark er = 9; 235*2370Smark delock(atail); 236*2370Smark goto X; 237*2370Smark } 238996Sbill if ((dn=open(acu,1))<0) { 239996Sbill er=(errno == 6? 1:5); 240996Sbill goto X; 241996Sbill } 242996Sbill if ((fk=fork()) == (-1)) { 243996Sbill er=4; 244996Sbill goto X; 245996Sbill } 246996Sbill if (fk == 0) { 247996Sbill open(dev,2); 248996Sbill for (;;) pause(); 249996Sbill } 250996Sbill xsleep(2); 251996Sbill /* 252996Sbill * copy phone #, assure EON 253996Sbill */ 254996Sbill p=b; 255996Sbill q=telno; 256996Sbill while (*p++=(*q++)) 257996Sbill ; 258996Sbill p--; 259996Sbill if (*(p-1)!='<') { 260996Sbill /*if (*(p-1)!='-') *p++='-';*/ 261996Sbill *p++='<'; 262996Sbill } 263996Sbill t=p-b; 264996Sbill xalarm(5*t); 265996Sbill t=write(dn,b,t); 266996Sbill xalarm(0); 267996Sbill if (t<0) { 268996Sbill er=2; 269996Sbill goto X; 270996Sbill } 271996Sbill /* close(dn) */ 272996Sbill xalarm(40); /* was 5; sometimes missed carrier */ 273996Sbill dh = open(dev,2); 274996Sbill xalarm(0); 275996Sbill if (dh<0) { 276996Sbill er=(errno == 4? 3:6); 277996Sbill goto X; 278996Sbill } 279*2370Smark ioctl(dh, TIOCGETP, &stbuf); 280996Sbill stbuf.sg_flags &= ~ECHO; 281996Sbill xalarm(10); 282996Sbill ioctl(dh, TIOCSETP, &stbuf); 283996Sbill ioctl(dh, TIOCHPCL, (struct sgttyb *)NULL); 284996Sbill xalarm(0); 285996Sbill X: 286996Sbill if (er) close(dn); 287*2370Smark delock(atail); 288996Sbill if (fk!=(-1)) { 289996Sbill kill(fk, SIGKILL); 290996Sbill xalarm(10); 291996Sbill while ((t=wait((int *)NULL))!=(-1) && t!=fk); 292996Sbill xalarm(0); 293996Sbill } 294996Sbill return (er? -er:dh); 295996Sbill } 296996Sbill 297996Sbill /* 298996Sbill * wr: write to remote: 0 -> line. 299996Sbill * ~. terminate 300996Sbill * ~<file send file 301996Sbill * ~! local login-style shell 302996Sbill * ~!cmd execute cmd locally 303996Sbill * ~$proc execute proc locally, send output to line 304996Sbill * ~%cmd execute builtin cmd (put and take) 305996Sbill * ~# send 1-sec break 306*2370Smark * ~^Z suspend cu process. 307996Sbill */ 308996Sbill 309996Sbill wr() 310996Sbill { 311996Sbill int ds,fk,lcl,x; 312996Sbill char *p,b[600]; 313996Sbill for (;;) { 314996Sbill p=b; 315996Sbill while (rdc(0) == 1) { 316996Sbill if (p == b) lcl=(c == '~'); 317996Sbill if (p == b+1 && b[0] == '~') lcl=(c!='~'); 318*2370Smark if (nullbrk && c == 0) oc=c=0177; /* fake break kludge */ 319996Sbill if (!lcl) { 320996Sbill c = oc; 321996Sbill if (wrc(ln) == 0) { 322996Sbill prf("line gone"); return; 323996Sbill } 324996Sbill c &= 0177; 325996Sbill } 326996Sbill if (lcl) { 327996Sbill if (c == 0177) c=tkill; 328996Sbill if (c == '\r' || c == '\n') goto A; 329996Sbill if (!dout) wrc(0); 330996Sbill } 331996Sbill *p++=c; 332996Sbill if (c == terase) { 333996Sbill p=p-2; 334996Sbill if (p<b) p=b; 335996Sbill } 336996Sbill if (c == tkill || c == 0177 || c == '\4' || c == '\r' || c == '\n') p=b; 337996Sbill } 338996Sbill return; 339996Sbill A: 340996Sbill if (!dout) echo(""); 341996Sbill *p=0; 342996Sbill switch (b[1]) { 343996Sbill case '.': 344996Sbill case '\004': 345996Sbill return; 346996Sbill case '#': 347996Sbill ioctl(ln, TIOCSBRK, 0); 348996Sbill sleep(1); 349996Sbill ioctl(ln, TIOCCBRK, 0); 350996Sbill continue; 351996Sbill case '!': 352996Sbill case '$': 353996Sbill fk = fork(); 354996Sbill if (fk == 0) { 355996Sbill char *getenv(); 356996Sbill char *shell = getenv("SHELL"); 357996Sbill if (shell == 0) shell = "/bin/sh"; 358996Sbill close(1); 359996Sbill dup(b[1] == '$'? ln:2); 360996Sbill close(ln); 361996Sbill mode(0); 362996Sbill if (!nhup) signal(SIGINT, SIG_DFL); 363996Sbill if (b[2] == 0) execl(shell,shell,0); 364996Sbill /* if (b[2] == 0) execl(shell,"-",0); */ 365996Sbill else execl(shell,"sh","-c",b+2,0); 366996Sbill prf("Can't execute shell"); 367996Sbill exit(~0); 368996Sbill } 369996Sbill if (fk!=(-1)) { 370996Sbill while (wait(&x)!=fk); 371996Sbill } 372996Sbill mode(1); 373996Sbill if (b[1] == '!') echo("!"); 374996Sbill else { 375996Sbill if (dout) echo("$"); 376996Sbill } 377996Sbill break; 378996Sbill case '<': 379996Sbill if (b[2] == 0) break; 380996Sbill if ((ds=open(b+2,0))<0) { 381996Sbill prf("Can't divert %s",b+1); 382996Sbill break; 383996Sbill } 384996Sbill intr=x=0; 385996Sbill mode(2); 386996Sbill if (!nhup) signal(SIGINT, sig2); 387996Sbill while (!intr && rdc(ds) == 1) { 388996Sbill if (wrc(ln) == 0) { 389996Sbill x=1; 390996Sbill break; 391996Sbill } 392996Sbill } 393996Sbill signal(SIGINT, SIG_IGN); 394996Sbill close(ds); 395996Sbill mode(1); 396996Sbill if (x) return; 397996Sbill if (dout) echo("<"); 398996Sbill break; 399996Sbill case '>': 400996Sbill case ':': 401996Sbill { 402996Sbill FILE *fp; char tbuff[128]; register char *q; 403996Sbill sprintf(tbuff,"/tmp/cu%d",efk); 404996Sbill if(NULL==(fp = fopen(tbuff,"w"))) { 405996Sbill prf("Can't tell other demon to divert"); 406996Sbill break; 407996Sbill } 408996Sbill fprintf(fp,"%s\n",(b[1]=='>'?&b[2]: &b[1] )); 409996Sbill if(dbflag) prf("name to be written in temporary:"),prf(&b[2]); 410996Sbill fclose(fp); 411996Sbill kill(efk,SIGEMT); 412996Sbill } 413996Sbill break; 414996Sbill #ifdef SIGTSTP 415996Sbill #define CTRLZ 26 416996Sbill case CTRLZ: 417996Sbill mode(0); 418996Sbill kill(getpid(), SIGTSTP); 419996Sbill mode(1); 420996Sbill break; 421996Sbill #endif 422996Sbill case '%': 423996Sbill dopercen(&b[2]); 424996Sbill break; 425996Sbill default: 426996Sbill prf("Use `~~' to start line with `~'"); 427996Sbill } 428996Sbill continue; 429996Sbill } 430996Sbill } 431996Sbill 432996Sbill dopercen(line) 433996Sbill register char *line; 434996Sbill { 435996Sbill char *args[10]; 436996Sbill register narg, f; 437996Sbill int rcount; 438996Sbill for (narg = 0; narg < 10;) { 439996Sbill while(*line == ' ' || *line == '\t') 440996Sbill line++; 441996Sbill if (*line == '\0') 442996Sbill break; 443996Sbill args[narg++] = line; 444996Sbill while(*line != '\0' && *line != ' ' && *line != '\t') 445996Sbill line++; 446996Sbill if (*line == '\0') 447996Sbill break; 448996Sbill *line++ = '\0'; 449996Sbill } 450996Sbill if (equal(args[0], "take")) { 451996Sbill if (narg < 2) { 452996Sbill prf("usage: ~%%take from [to]"); 453996Sbill return; 454996Sbill } 455996Sbill if (narg < 3) 456996Sbill args[2] = args[1]; 457996Sbill wrln("echo '~>:'"); 458996Sbill wrln(args[2]); 459996Sbill wrln(";tee /dev/null <"); 460996Sbill wrln(args[1]); 461996Sbill wrln(";echo '~>'\n"); 462996Sbill return; 463996Sbill } else if (equal(args[0], "put")) { 464996Sbill if (narg < 2) { 465996Sbill prf("usage: ~%%put from [to]"); 466996Sbill return; 467996Sbill } 468996Sbill if (narg < 3) 469996Sbill args[2] = args[1]; 470996Sbill if ((f = open(args[1], 0)) < 0) { 471996Sbill prf("cannot open: %s", args[1]); 472996Sbill return; 473996Sbill } 474996Sbill wrln("stty -echo;cat >"); 475996Sbill wrln(args[2]); 476996Sbill wrln(";stty echo\n"); 477996Sbill xsleep(5); 478996Sbill intr = 0; 479996Sbill if (!nhup) 480996Sbill signal(SIGINT, sig2); 481996Sbill mode(2); 482996Sbill rcount = 0; 483996Sbill while(!intr && rdc(f) == 1) { 484996Sbill rcount++; 485996Sbill if (c == tkill || c == terase) 486996Sbill wrln("\\"); 487996Sbill if (wrc(ln) != 1) { 488996Sbill xsleep(2); 489996Sbill if (wrc(ln) != 1) { 490996Sbill prf("character missed"); 491996Sbill intr = 1; 492996Sbill break; 493996Sbill } 494996Sbill } 495996Sbill } 496996Sbill signal(SIGINT, SIG_IGN); 497996Sbill close(f); 498996Sbill if (intr) { 499996Sbill wrln("\n"); 500996Sbill prf("stopped after %d bytes", rcount); 501996Sbill } 502996Sbill wrln("\004"); 503996Sbill xsleep(5); 504996Sbill mode(1); 505996Sbill return; 506996Sbill } 507996Sbill prf("~%%%s unknown\n", args[0]); 508996Sbill } 509996Sbill 510996Sbill equal(s1, s2) 511996Sbill register char *s1, *s2; 512996Sbill { 513996Sbill while (*s1++ == *s2) 514996Sbill if (*s2++ == '\0') 515996Sbill return(1); 516996Sbill return(0); 517996Sbill } 518996Sbill 519996Sbill wrln(s) 520996Sbill register char *s; 521996Sbill { 522996Sbill while (*s) 523996Sbill write(ln, s++, 1); 524996Sbill } 525996Sbill /* chwrsig: Catch orders from wr process 526996Sbill * to instigate diversion 527996Sbill */ 528996Sbill int whoami; 529996Sbill chwrsig(){ 530996Sbill int dodiver(); 531996Sbill whoami = getpid(); 532996Sbill signal(SIGEMT,dodiver); 533996Sbill } 534996Sbill int ds,slnt; 535996Sbill int justrung; 536996Sbill dodiver(){ 537996Sbill static char dobuff[128], morejunk[256]; register char *cp; 538996Sbill FILE *fp; 539996Sbill justrung = 1; 540996Sbill signal(SIGEMT,dodiver); 541996Sbill sprintf(dobuff,"/tmp/cu%d",whoami); 542996Sbill fp = fopen(dobuff,"r"); 543996Sbill if(fp==NULL) prf("Couldn't open temporary"); 544996Sbill unlink(dobuff); 545996Sbill if(dbflag) { 546996Sbill prf("Name of temporary:"); 547996Sbill prf(dobuff); 548996Sbill } 549996Sbill fgets(dobuff,128,fp); fclose(fp); 550996Sbill if(dbflag) { 551996Sbill prf("Name of target file:"); 552996Sbill prf(dobuff); 553996Sbill } 554996Sbill for(cp = dobuff-1; *++cp; ) /* squash newline */ 555996Sbill if(*cp=='\n') *cp=0; 556996Sbill cp = dobuff; 557996Sbill if (*cp=='>') cp++; 558996Sbill if (*cp==':') { 559996Sbill cp++; 560996Sbill if(*cp==0) { 561996Sbill slnt ^= 1; 562996Sbill return; 563996Sbill } else { 564996Sbill slnt = 1; 565996Sbill } 566996Sbill } 567996Sbill if (ds >= 0) close(ds); 568996Sbill if (*cp==0) { 569996Sbill slnt = 0; 570996Sbill ds = -1; 571996Sbill return; 572996Sbill } 573996Sbill if (*dobuff!='>' || (ds=open(cp,1))<0) ds=creat(cp,0644); 574996Sbill lseek(ds, (long)0, 2); 575996Sbill if(ds < 0) prf("Creat failed:"), prf(cp); 576996Sbill if (ds<0) prf("Can't divert %s",cp+1); 577996Sbill } 578996Sbill 579996Sbill 580996Sbill /* 581996Sbill * rd: read from remote: line -> 1 582996Sbill * catch: 583996Sbill * ~>[>][:][file] 584996Sbill * stuff from file... 585996Sbill * ~> (ends diversion) 586996Sbill */ 587996Sbill 588996Sbill rd() 589996Sbill { 590996Sbill extern int ds,slnt; 591996Sbill char *p,*q,b[600]; 592996Sbill p=b; 593996Sbill ds=(-1); 594996Sbill agin: 595996Sbill while (rdc(ln) == 1) { 596996Sbill if (!slnt) wrc(1); 597996Sbill *p++=c; 598996Sbill if (c!='\n') continue; 599996Sbill q=p; 600996Sbill p=b; 601996Sbill if (b[0]!='~' || b[1]!='>') { 602996Sbill if (*(q-2) == '\r') { 603996Sbill q--; 604996Sbill *(q-1)=(*q); 605996Sbill } 606996Sbill if (ds>=0) write(ds,b,q-b); 607996Sbill continue; 608996Sbill } 609996Sbill if (ds>=0) close(ds); 610996Sbill if (slnt) { 611996Sbill write(1, b, q - b); 612996Sbill write(1, CRLF, sizeof(CRLF)); 613996Sbill } 614996Sbill if (*(q-2) == '\r') q--; 615996Sbill *(q-1)=0; 616996Sbill slnt=0; 617996Sbill q=b+2; 618996Sbill if (*q == '>') q++; 619996Sbill if (*q == ':') { 620996Sbill slnt=1; 621996Sbill q++; 622996Sbill } 623996Sbill if (*q == 0) { 624996Sbill ds=(-1); 625996Sbill continue; 626996Sbill } 627996Sbill if (b[2]!='>' || (ds=open(q,1))<0) ds=creat(q,0644); 628996Sbill lseek(ds, (long)0, 2); 629996Sbill if (ds<0) prf("Can't divert %s",b+1); 630996Sbill } 631996Sbill if(justrung) { 632996Sbill justrung = 0; 633996Sbill goto agin; 634996Sbill } 635996Sbill } 636996Sbill 637996Sbill struct {char lobyte; char hibyte;}; 638996Sbill mode(f) 639996Sbill { 640996Sbill struct sgttyb stbuf; 641996Sbill if (dout) return; 642996Sbill ioctl(0, TIOCGETP, &stbuf); 643996Sbill tkill = stbuf.sg_kill; 644996Sbill terase = stbuf.sg_erase; 645996Sbill if (f == 0) { 646996Sbill stbuf.sg_flags &= ~RAW; 647996Sbill stbuf.sg_flags |= ECHO|CRMOD; 648996Sbill } 649996Sbill if (f == 1) { 650996Sbill stbuf.sg_flags |= RAW; 651996Sbill stbuf.sg_flags &= ~(ECHO|CRMOD); 652996Sbill } 653996Sbill if (f == 2) { 654996Sbill stbuf.sg_flags &= ~RAW; 655996Sbill stbuf.sg_flags &= ~(ECHO|CRMOD); 656996Sbill } 657996Sbill ioctl(0, TIOCSETP, &stbuf); 658996Sbill } 659996Sbill 660996Sbill echo(s) 661996Sbill char *s; 662996Sbill { 663996Sbill char *p; 664996Sbill for (p=s;*p;p++); 665996Sbill if (p>s) write(0,s,p-s); 666996Sbill write(0,CRLF, sizeof(CRLF)); 667996Sbill } 668996Sbill 669996Sbill prf(f, s) 670996Sbill char *f; 671996Sbill char *s; 672996Sbill { 673996Sbill fprintf(stderr, f, s); 674996Sbill fprintf(stderr, CRLF); 675996Sbill } 676996Sbill 677996Sbill exists(devname) 678996Sbill char *devname; 679996Sbill { 680996Sbill if (access(devname, 0)==0) 681996Sbill return(1); 682996Sbill prf("%s does not exist", devname); 683996Sbill return(0); 684996Sbill } 685*2370Smark 686*2370Smark cleanup(code) 687*2370Smark { 688*2370Smark rmlock(NULL); 689*2370Smark exit(code); 690*2370Smark } 691*2370Smark 692*2370Smark /* 693*2370Smark * This code is taken directly from uucp and follows the same 694*2370Smark * conventions. This is important since uucp and cu should 695*2370Smark * respect each others locks. 696*2370Smark */ 697*2370Smark 698*2370Smark /* ulockf 3.2 10/26/79 11:40:29 */ 699*2370Smark /* #include "uucp.h" */ 700*2370Smark #include <sys/types.h> 701*2370Smark #include <sys/stat.h> 702*2370Smark 703*2370Smark 704*2370Smark 705*2370Smark /******* 706*2370Smark * ulockf(file, atime) 707*2370Smark * char *file; 708*2370Smark * time_t atime; 709*2370Smark * 710*2370Smark * ulockf - this routine will create a lock file (file). 711*2370Smark * If one already exists, the create time is checked for 712*2370Smark * older than the age time (atime). 713*2370Smark * If it is older, an attempt will be made to unlink it 714*2370Smark * and create a new one. 715*2370Smark * 716*2370Smark * return codes: 0 | FAIL 717*2370Smark */ 718*2370Smark 719*2370Smark ulockf(file, atime) 720*2370Smark char *file; 721*2370Smark time_t atime; 722*2370Smark { 723*2370Smark struct stat stbuf; 724*2370Smark time_t ptime; 725*2370Smark int ret; 726*2370Smark static int pid = -1; 727*2370Smark static char tempfile[NAMESIZE]; 728*2370Smark 729*2370Smark if (pid < 0) { 730*2370Smark pid = getpid(); 731*2370Smark sprintf(tempfile, "/usr/spool/uucp/LTMP.%d", pid); 732*2370Smark } 733*2370Smark if (onelock(pid, tempfile, file) == -1) { 734*2370Smark /* lock file exists */ 735*2370Smark /* get status to check age of the lock file */ 736*2370Smark ret = stat(file, &stbuf); 737*2370Smark if (ret != -1) { 738*2370Smark time(&ptime); 739*2370Smark if ((ptime - stbuf.st_ctime) < atime) { 740*2370Smark /* file not old enough to delete */ 741*2370Smark return(FAIL); 742*2370Smark } 743*2370Smark } 744*2370Smark ret = unlink(file); 745*2370Smark ret = onelock(pid, tempfile, file); 746*2370Smark if (ret != 0) 747*2370Smark return(FAIL); 748*2370Smark } 749*2370Smark stlock(file); 750*2370Smark return(0); 751*2370Smark } 752*2370Smark 753*2370Smark 754*2370Smark #define MAXLOCKS 10 /* maximum number of lock files */ 755*2370Smark char *Lockfile[MAXLOCKS]; 756*2370Smark int Nlocks = 0; 757*2370Smark 758*2370Smark /*** 759*2370Smark * stlock(name) put name in list of lock files 760*2370Smark * char *name; 761*2370Smark * 762*2370Smark * return codes: none 763*2370Smark */ 764*2370Smark 765*2370Smark stlock(name) 766*2370Smark char *name; 767*2370Smark { 768*2370Smark char *p; 769*2370Smark extern char *calloc(); 770*2370Smark int i; 771*2370Smark 772*2370Smark for (i = 0; i < Nlocks; i++) { 773*2370Smark if (Lockfile[i] == NULL) 774*2370Smark break; 775*2370Smark } 776*2370Smark ASSERT(i < MAXLOCKS, "TOO MANY LOCKS %d", i); 777*2370Smark if (i >= Nlocks) 778*2370Smark i = Nlocks++; 779*2370Smark p = calloc(strlen(name) + 1, sizeof (char)); 780*2370Smark ASSERT(p != NULL, "CAN NOT ALLOCATE FOR %s", name); 781*2370Smark strcpy(p, name); 782*2370Smark Lockfile[i] = p; 783*2370Smark return; 784*2370Smark } 785*2370Smark 786*2370Smark 787*2370Smark /*** 788*2370Smark * rmlock(name) remove all lock files in list 789*2370Smark * char *name; or name 790*2370Smark * 791*2370Smark * return codes: none 792*2370Smark */ 793*2370Smark 794*2370Smark rmlock(name) 795*2370Smark char *name; 796*2370Smark { 797*2370Smark int i; 798*2370Smark 799*2370Smark for (i = 0; i < Nlocks; i++) { 800*2370Smark if (Lockfile[i] == NULL) 801*2370Smark continue; 802*2370Smark if (name == NULL 803*2370Smark || strcmp(name, Lockfile[i]) == SAME) { 804*2370Smark unlink(Lockfile[i]); 805*2370Smark free(Lockfile[i]); 806*2370Smark Lockfile[i] = NULL; 807*2370Smark } 808*2370Smark } 809*2370Smark return; 810*2370Smark } 811*2370Smark 812*2370Smark 813*2370Smark /* this stuff from pjw */ 814*2370Smark /* /usr/pjw/bin/recover - check pids to remove unnecessary locks */ 815*2370Smark /* isalock(name) returns 0 if the name is a lock */ 816*2370Smark /* unlock(name) unlocks name if it is a lock*/ 817*2370Smark /* onelock(pid,tempfile,name) makes lock a name 818*2370Smark on behalf of pid. Tempfile must be in the same 819*2370Smark file system as name. */ 820*2370Smark /* lock(pid,tempfile,names) either locks all the 821*2370Smark names or none of them */ 822*2370Smark isalock(name) char *name; 823*2370Smark { 824*2370Smark struct stat xstat; 825*2370Smark if(stat(name,&xstat)<0) return(0); 826*2370Smark if(xstat.st_size!=sizeof(int)) return(0); 827*2370Smark return(1); 828*2370Smark } 829*2370Smark unlock(name) char *name; 830*2370Smark { 831*2370Smark if(isalock(name)) return(unlink(name)); 832*2370Smark else return(-1); 833*2370Smark } 834*2370Smark onelock(pid,tempfile,name) char *tempfile,*name; 835*2370Smark { int fd; 836*2370Smark fd=creat(tempfile,0444); 837*2370Smark if(fd<0) return(-1); 838*2370Smark write(fd,(char *) &pid,sizeof(int)); 839*2370Smark close(fd); 840*2370Smark if(link(tempfile,name)<0) 841*2370Smark { unlink(tempfile); 842*2370Smark return(-1); 843*2370Smark } 844*2370Smark unlink(tempfile); 845*2370Smark return(0); 846*2370Smark } 847*2370Smark lock(pid,tempfile,names) char *tempfile,**names; 848*2370Smark { int i,j; 849*2370Smark for(i=0;names[i]!=0;i++) 850*2370Smark { if(onelock(pid,tempfile,names[i])==0) continue; 851*2370Smark for(j=0;j<i;j++) unlink(names[j]); 852*2370Smark return(-1); 853*2370Smark } 854*2370Smark return(0); 855*2370Smark } 856*2370Smark 857*2370Smark #define LOCKPRE "/usr/spool/uucp/LCK." 858*2370Smark 859*2370Smark /*** 860*2370Smark * delock(s) remove a lock file 861*2370Smark * char *s; 862*2370Smark * 863*2370Smark * return codes: 0 | FAIL 864*2370Smark */ 865*2370Smark 866*2370Smark delock(s) 867*2370Smark char *s; 868*2370Smark { 869*2370Smark char ln[30]; 870*2370Smark 871*2370Smark sprintf(ln, "%s.%s", LOCKPRE, s); 872*2370Smark rmlock(ln); 873*2370Smark } 874*2370Smark 875*2370Smark 876*2370Smark /*** 877*2370Smark * mlock(sys) create system lock 878*2370Smark * char *sys; 879*2370Smark * 880*2370Smark * return codes: 0 | FAIL 881*2370Smark */ 882*2370Smark 883*2370Smark mlock(sys) 884*2370Smark char *sys; 885*2370Smark { 886*2370Smark char lname[30]; 887*2370Smark sprintf(lname, "%s.%s", LOCKPRE, sys); 888*2370Smark return(ulockf(lname, (time_t) SLCKTIME ) < 0 ? FAIL : 0); 889*2370Smark } 890*2370Smark 891*2370Smark 892*2370Smark 893*2370Smark /*** 894*2370Smark * ultouch() update access and modify times for lock files 895*2370Smark * 896*2370Smark * return code - none 897*2370Smark */ 898*2370Smark 899*2370Smark ultouch() 900*2370Smark { 901*2370Smark time_t time(); 902*2370Smark int i; 903*2370Smark struct ut { 904*2370Smark time_t actime; 905*2370Smark time_t modtime; 906*2370Smark } ut; 907*2370Smark 908*2370Smark ut.actime = time(&ut.modtime); 909*2370Smark for (i = 0; i < Nlocks; i++) { 910*2370Smark if (Lockfile[i] == NULL) 911*2370Smark continue; 912*2370Smark utime(Lockfile[i], &ut); 913*2370Smark } 914*2370Smark return; 915*2370Smark } 916