1*3924Sroot static char *sccsid = "@(#)cu.c 4.5 (Berkeley) 81/07/02"; 2996Sbill #include <stdio.h> 3996Sbill #include <signal.h> 4996Sbill #include <sgtty.h> 52370Smark 6996Sbill /* 72370Smark * defs that come from uucp.h 82370Smark */ 92370Smark #define NAMESIZE 15 102370Smark #define FAIL -1 112370Smark #define SAME 0 122370Smark #define SLCKTIME 5400 /* system/device timeout (LCK.. files) in seconds */ 132370Smark #define ASSERT(e, f, v) if (!(e)) {\ 142370Smark fprintf(stderr, "AERROR - (%s) ", "e");\ 152370Smark fprintf(stderr, f, v);\ 162370Smark cleanup(FAIL);\ 172370Smark } 182370Smark 192370Smark /* 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", 572370Smark "usage: cu telno [-t] [-s speed] [-l line] [-a acu]", 582370Smark "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; 1012370Smark 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; 1152791Swnj int cleanup(); 116996Sbill 117996Sbill signal(SIGALRM, sig14); 1182791Swnj signal(SIGINT, cleanup); 1192791Swnj signal(SIGHUP, cleanup); 1202791Swnj signal(SIGQUIT, cleanup); 121996Sbill if (ac < 2) { 122996Sbill prf(connmsg[8]); 123996Sbill exit(8); 124996Sbill } 125996Sbill for (; ac > 1; av++,ac--) { 126996Sbill if (av[1][0] != '-') 127996Sbill telno = av[1]; 128996Sbill else switch(av[1][1]) { 129996Sbill case 't': 130996Sbill dout = 1; 131996Sbill --ac; 132996Sbill continue; 1332370Smark case 'b': 1342370Smark nullbrk++; 1352370Smark continue; 136996Sbill case 'd': 137996Sbill dbflag++; 138996Sbill continue; 139996Sbill case 's': 140996Sbill lspeed = av[2]; ++av; --ac; 141996Sbill break; 142996Sbill case 'l': 143996Sbill devcul = av[2]; ++av; --ac; 144996Sbill break; 145996Sbill case 'a': 146996Sbill devcua = av[2]; ++av; --ac; 147996Sbill break; 148996Sbill case '0': case '1': case '2': case '3': case '4': 149996Sbill case '5': case '6': case '7': case '8': case '9': 150996Sbill devcua[strlen(devcua)-1] = av[1][1]; 151996Sbill devcul[strlen(devcul)-1] = av[1][1]; 152996Sbill break; 153996Sbill default: 154996Sbill prf("Bad flag %s", av[1]); 155996Sbill break; 156996Sbill } 157996Sbill } 158996Sbill if (!exists(devcua) || !exists(devcul)) 159996Sbill exit(9); 160996Sbill ln = conn(devcul, devcua, telno); 161996Sbill if (ln < 0) { 162996Sbill prf("Connect failed: %s",connmsg[-ln]); 1632370Smark cleanup(-ln); 164996Sbill } 165996Sbill switch(atoi(lspeed)) { 166996Sbill case 110: 167996Sbill speed = B110;break; 168996Sbill case 150: 169996Sbill speed = B150;break; 170996Sbill default: 171996Sbill case 300: 172996Sbill speed = B300;break; 173996Sbill case 1200: 174996Sbill speed = B1200;break; 175996Sbill } 176996Sbill stbuf.sg_ispeed = speed; 177996Sbill stbuf.sg_ospeed = speed; 178996Sbill stbuf.sg_flags = EVENP|ODDP; 179996Sbill if (!dout) { 180996Sbill stbuf.sg_flags |= RAW; 181996Sbill stbuf.sg_flags &= ~ECHO; 182996Sbill } 183996Sbill ioctl(ln, TIOCSETP, &stbuf); 184996Sbill ioctl(ln, TIOCEXCL, (struct sgttyb *)NULL); 185996Sbill ioctl(ln, TIOCHPCL, (struct sgttyb *)NULL); 186996Sbill prf("Connected"); 187996Sbill if (dout) 1883923Sroot fk = -12345; 189996Sbill else 190996Sbill fk = fork(); 191996Sbill nhup = (int)signal(SIGINT, SIG_IGN); 192996Sbill if (fk == 0) { 193996Sbill chwrsig(); 194996Sbill rd(); 195996Sbill prf("\007Lost carrier"); 1962370Smark cleanup(3); 197996Sbill } 198996Sbill mode(1); 199996Sbill efk = fk; 200996Sbill wr(); 201996Sbill mode(0); 202*3924Sroot if (fk != -1) kill(fk, SIGKILL); 203996Sbill wait((int *)NULL); 204996Sbill stbuf.sg_ispeed = 0; 205996Sbill stbuf.sg_ospeed = 0; 206996Sbill ioctl(ln, TIOCSETP, &stbuf); 207996Sbill prf("Disconnected"); 2082370Smark cleanup(0); 209996Sbill } 210996Sbill 211996Sbill /* 212996Sbill * conn: establish dial-out connection. 213996Sbill * Example: fd = conn("/dev/ttyh","/dev/dn1","4500"); 214996Sbill * Returns descriptor open to tty for reading and writing. 215996Sbill * Negative values (-1...-7) denote errors in connmsg. 216996Sbill * Uses alarm and fork/wait; requires sig14 handler. 217996Sbill * Be sure to disconnect tty when done, via HUPCL or stty 0. 218996Sbill */ 219996Sbill 220996Sbill conn(dev,acu,telno) 221996Sbill char *dev, *acu, *telno; 222996Sbill { 223996Sbill struct sgttyb stbuf; 224996Sbill extern errno; 225996Sbill char *p, *q, b[30]; 2262370Smark char *ltail, *atail; 2272370Smark char *rindex(); 228996Sbill int er, fk, dn, dh, t; 229996Sbill er=0; 230996Sbill fk=(-1); 2312370Smark atail = rindex(acu, '/')+1; 2322370Smark if (mlock(atail) == FAIL) { 2332370Smark er = 9; 2342370Smark goto X; 2352370Smark } 2362370Smark ltail = rindex(dev, '/')+1; 2372370Smark if (mlock(ltail) == FAIL) { 2382370Smark er = 9; 2392370Smark delock(atail); 2402370Smark goto X; 2412370Smark } 242996Sbill if ((dn=open(acu,1))<0) { 243996Sbill er=(errno == 6? 1:5); 244996Sbill goto X; 245996Sbill } 246996Sbill if ((fk=fork()) == (-1)) { 247996Sbill er=4; 248996Sbill goto X; 249996Sbill } 250996Sbill if (fk == 0) { 251996Sbill open(dev,2); 252996Sbill for (;;) pause(); 253996Sbill } 254996Sbill xsleep(2); 255996Sbill /* 256996Sbill * copy phone #, assure EON 257996Sbill */ 258996Sbill p=b; 259996Sbill q=telno; 260996Sbill while (*p++=(*q++)) 261996Sbill ; 262996Sbill p--; 263996Sbill if (*(p-1)!='<') { 264996Sbill /*if (*(p-1)!='-') *p++='-';*/ 265996Sbill *p++='<'; 266996Sbill } 267996Sbill t=p-b; 268996Sbill xalarm(5*t); 269996Sbill t=write(dn,b,t); 270996Sbill xalarm(0); 271996Sbill if (t<0) { 272996Sbill er=2; 273996Sbill goto X; 274996Sbill } 275996Sbill /* close(dn) */ 276996Sbill xalarm(40); /* was 5; sometimes missed carrier */ 277996Sbill dh = open(dev,2); 278996Sbill xalarm(0); 279996Sbill if (dh<0) { 280996Sbill er=(errno == 4? 3:6); 281996Sbill goto X; 282996Sbill } 2832370Smark ioctl(dh, TIOCGETP, &stbuf); 284996Sbill stbuf.sg_flags &= ~ECHO; 285996Sbill xalarm(10); 286996Sbill ioctl(dh, TIOCSETP, &stbuf); 287996Sbill ioctl(dh, TIOCHPCL, (struct sgttyb *)NULL); 288996Sbill xalarm(0); 289996Sbill X: 290996Sbill if (er) close(dn); 2912370Smark delock(atail); 292996Sbill if (fk!=(-1)) { 293996Sbill kill(fk, SIGKILL); 294996Sbill xalarm(10); 295996Sbill while ((t=wait((int *)NULL))!=(-1) && t!=fk); 296996Sbill xalarm(0); 297996Sbill } 298996Sbill return (er? -er:dh); 299996Sbill } 300996Sbill 301996Sbill /* 302996Sbill * wr: write to remote: 0 -> line. 303996Sbill * ~. terminate 304996Sbill * ~<file send file 305996Sbill * ~! local login-style shell 306996Sbill * ~!cmd execute cmd locally 307996Sbill * ~$proc execute proc locally, send output to line 308996Sbill * ~%cmd execute builtin cmd (put and take) 309996Sbill * ~# send 1-sec break 3102370Smark * ~^Z suspend cu process. 311996Sbill */ 312996Sbill 313996Sbill wr() 314996Sbill { 315996Sbill int ds,fk,lcl,x; 316996Sbill char *p,b[600]; 317996Sbill for (;;) { 318996Sbill p=b; 319996Sbill while (rdc(0) == 1) { 320996Sbill if (p == b) lcl=(c == '~'); 321996Sbill if (p == b+1 && b[0] == '~') lcl=(c!='~'); 3222370Smark if (nullbrk && c == 0) oc=c=0177; /* fake break kludge */ 323996Sbill if (!lcl) { 324996Sbill c = oc; 325996Sbill if (wrc(ln) == 0) { 326996Sbill prf("line gone"); return; 327996Sbill } 328996Sbill c &= 0177; 329996Sbill } 330996Sbill if (lcl) { 331996Sbill if (c == 0177) c=tkill; 332996Sbill if (c == '\r' || c == '\n') goto A; 333996Sbill if (!dout) wrc(0); 334996Sbill } 335996Sbill *p++=c; 336996Sbill if (c == terase) { 337996Sbill p=p-2; 338996Sbill if (p<b) p=b; 339996Sbill } 340996Sbill if (c == tkill || c == 0177 || c == '\4' || c == '\r' || c == '\n') p=b; 341996Sbill } 342996Sbill return; 343996Sbill A: 344996Sbill if (!dout) echo(""); 345996Sbill *p=0; 346996Sbill switch (b[1]) { 347996Sbill case '.': 348996Sbill case '\004': 349996Sbill return; 350996Sbill case '#': 351996Sbill ioctl(ln, TIOCSBRK, 0); 352996Sbill sleep(1); 353996Sbill ioctl(ln, TIOCCBRK, 0); 354996Sbill continue; 355996Sbill case '!': 356996Sbill case '$': 357996Sbill fk = fork(); 358996Sbill if (fk == 0) { 359996Sbill char *getenv(); 360996Sbill char *shell = getenv("SHELL"); 361996Sbill if (shell == 0) shell = "/bin/sh"; 362996Sbill close(1); 363996Sbill dup(b[1] == '$'? ln:2); 364996Sbill close(ln); 365996Sbill mode(0); 366996Sbill if (!nhup) signal(SIGINT, SIG_DFL); 367996Sbill if (b[2] == 0) execl(shell,shell,0); 368996Sbill /* if (b[2] == 0) execl(shell,"-",0); */ 369996Sbill else execl(shell,"sh","-c",b+2,0); 370996Sbill prf("Can't execute shell"); 371996Sbill exit(~0); 372996Sbill } 373996Sbill if (fk!=(-1)) { 374996Sbill while (wait(&x)!=fk); 375996Sbill } 376996Sbill mode(1); 377996Sbill if (b[1] == '!') echo("!"); 378996Sbill else { 379996Sbill if (dout) echo("$"); 380996Sbill } 381996Sbill break; 382996Sbill case '<': 383996Sbill if (b[2] == 0) break; 384996Sbill if ((ds=open(b+2,0))<0) { 385996Sbill prf("Can't divert %s",b+1); 386996Sbill break; 387996Sbill } 388996Sbill intr=x=0; 389996Sbill mode(2); 390996Sbill if (!nhup) signal(SIGINT, sig2); 391996Sbill while (!intr && rdc(ds) == 1) { 392996Sbill if (wrc(ln) == 0) { 393996Sbill x=1; 394996Sbill break; 395996Sbill } 396996Sbill } 397996Sbill signal(SIGINT, SIG_IGN); 398996Sbill close(ds); 399996Sbill mode(1); 400996Sbill if (x) return; 401996Sbill if (dout) echo("<"); 402996Sbill break; 403996Sbill case '>': 404996Sbill case ':': 405996Sbill { 406996Sbill FILE *fp; char tbuff[128]; register char *q; 407996Sbill sprintf(tbuff,"/tmp/cu%d",efk); 408996Sbill if(NULL==(fp = fopen(tbuff,"w"))) { 409996Sbill prf("Can't tell other demon to divert"); 410996Sbill break; 411996Sbill } 412996Sbill fprintf(fp,"%s\n",(b[1]=='>'?&b[2]: &b[1] )); 413996Sbill if(dbflag) prf("name to be written in temporary:"),prf(&b[2]); 414996Sbill fclose(fp); 415*3924Sroot if (efk != -1) kill(efk,SIGEMT); 416996Sbill } 417996Sbill break; 418996Sbill #ifdef SIGTSTP 419996Sbill #define CTRLZ 26 420996Sbill case CTRLZ: 421996Sbill mode(0); 422996Sbill kill(getpid(), SIGTSTP); 423996Sbill mode(1); 424996Sbill break; 425996Sbill #endif 426996Sbill case '%': 427996Sbill dopercen(&b[2]); 428996Sbill break; 429996Sbill default: 430996Sbill prf("Use `~~' to start line with `~'"); 431996Sbill } 432996Sbill continue; 433996Sbill } 434996Sbill } 435996Sbill 436996Sbill dopercen(line) 437996Sbill register char *line; 438996Sbill { 439996Sbill char *args[10]; 440996Sbill register narg, f; 441996Sbill int rcount; 442996Sbill for (narg = 0; narg < 10;) { 443996Sbill while(*line == ' ' || *line == '\t') 444996Sbill line++; 445996Sbill if (*line == '\0') 446996Sbill break; 447996Sbill args[narg++] = line; 448996Sbill while(*line != '\0' && *line != ' ' && *line != '\t') 449996Sbill line++; 450996Sbill if (*line == '\0') 451996Sbill break; 452996Sbill *line++ = '\0'; 453996Sbill } 454996Sbill if (equal(args[0], "take")) { 455996Sbill if (narg < 2) { 456996Sbill prf("usage: ~%%take from [to]"); 457996Sbill return; 458996Sbill } 459996Sbill if (narg < 3) 460996Sbill args[2] = args[1]; 461996Sbill wrln("echo '~>:'"); 462996Sbill wrln(args[2]); 463996Sbill wrln(";tee /dev/null <"); 464996Sbill wrln(args[1]); 465996Sbill wrln(";echo '~>'\n"); 466996Sbill return; 467996Sbill } else if (equal(args[0], "put")) { 468996Sbill if (narg < 2) { 469996Sbill prf("usage: ~%%put from [to]"); 470996Sbill return; 471996Sbill } 472996Sbill if (narg < 3) 473996Sbill args[2] = args[1]; 474996Sbill if ((f = open(args[1], 0)) < 0) { 475996Sbill prf("cannot open: %s", args[1]); 476996Sbill return; 477996Sbill } 478996Sbill wrln("stty -echo;cat >"); 479996Sbill wrln(args[2]); 480996Sbill wrln(";stty echo\n"); 481996Sbill xsleep(5); 482996Sbill intr = 0; 483996Sbill if (!nhup) 484996Sbill signal(SIGINT, sig2); 485996Sbill mode(2); 486996Sbill rcount = 0; 487996Sbill while(!intr && rdc(f) == 1) { 488996Sbill rcount++; 489996Sbill if (c == tkill || c == terase) 490996Sbill wrln("\\"); 491996Sbill if (wrc(ln) != 1) { 492996Sbill xsleep(2); 493996Sbill if (wrc(ln) != 1) { 494996Sbill prf("character missed"); 495996Sbill intr = 1; 496996Sbill break; 497996Sbill } 498996Sbill } 499996Sbill } 500996Sbill signal(SIGINT, SIG_IGN); 501996Sbill close(f); 502996Sbill if (intr) { 503996Sbill wrln("\n"); 504996Sbill prf("stopped after %d bytes", rcount); 505996Sbill } 506996Sbill wrln("\004"); 507996Sbill xsleep(5); 508996Sbill mode(1); 509996Sbill return; 510996Sbill } 511996Sbill prf("~%%%s unknown\n", args[0]); 512996Sbill } 513996Sbill 514996Sbill equal(s1, s2) 515996Sbill register char *s1, *s2; 516996Sbill { 517996Sbill while (*s1++ == *s2) 518996Sbill if (*s2++ == '\0') 519996Sbill return(1); 520996Sbill return(0); 521996Sbill } 522996Sbill 523996Sbill wrln(s) 524996Sbill register char *s; 525996Sbill { 526996Sbill while (*s) 527996Sbill write(ln, s++, 1); 528996Sbill } 529996Sbill /* chwrsig: Catch orders from wr process 530996Sbill * to instigate diversion 531996Sbill */ 532996Sbill int whoami; 533996Sbill chwrsig(){ 534996Sbill int dodiver(); 535996Sbill whoami = getpid(); 536996Sbill signal(SIGEMT,dodiver); 537996Sbill } 538996Sbill int ds,slnt; 539996Sbill int justrung; 540996Sbill dodiver(){ 541996Sbill static char dobuff[128], morejunk[256]; register char *cp; 542996Sbill FILE *fp; 543996Sbill justrung = 1; 544996Sbill signal(SIGEMT,dodiver); 545996Sbill sprintf(dobuff,"/tmp/cu%d",whoami); 546996Sbill fp = fopen(dobuff,"r"); 547996Sbill if(fp==NULL) prf("Couldn't open temporary"); 548996Sbill unlink(dobuff); 549996Sbill if(dbflag) { 550996Sbill prf("Name of temporary:"); 551996Sbill prf(dobuff); 552996Sbill } 553996Sbill fgets(dobuff,128,fp); fclose(fp); 554996Sbill if(dbflag) { 555996Sbill prf("Name of target file:"); 556996Sbill prf(dobuff); 557996Sbill } 558996Sbill for(cp = dobuff-1; *++cp; ) /* squash newline */ 559996Sbill if(*cp=='\n') *cp=0; 560996Sbill cp = dobuff; 561996Sbill if (*cp=='>') cp++; 562996Sbill if (*cp==':') { 563996Sbill cp++; 564996Sbill if(*cp==0) { 565996Sbill slnt ^= 1; 566996Sbill return; 567996Sbill } else { 568996Sbill slnt = 1; 569996Sbill } 570996Sbill } 571996Sbill if (ds >= 0) close(ds); 572996Sbill if (*cp==0) { 573996Sbill slnt = 0; 574996Sbill ds = -1; 575996Sbill return; 576996Sbill } 577996Sbill if (*dobuff!='>' || (ds=open(cp,1))<0) ds=creat(cp,0644); 578996Sbill lseek(ds, (long)0, 2); 579996Sbill if(ds < 0) prf("Creat failed:"), prf(cp); 580996Sbill if (ds<0) prf("Can't divert %s",cp+1); 581996Sbill } 582996Sbill 583996Sbill 584996Sbill /* 585996Sbill * rd: read from remote: line -> 1 586996Sbill * catch: 587996Sbill * ~>[>][:][file] 588996Sbill * stuff from file... 589996Sbill * ~> (ends diversion) 590996Sbill */ 591996Sbill 592996Sbill rd() 593996Sbill { 594996Sbill extern int ds,slnt; 595996Sbill char *p,*q,b[600]; 596996Sbill p=b; 597996Sbill ds=(-1); 598996Sbill agin: 599996Sbill while (rdc(ln) == 1) { 600996Sbill if (!slnt) wrc(1); 6012791Swnj if (p < &b[600]) 6022791Swnj *p++=c; 603996Sbill if (c!='\n') continue; 604996Sbill q=p; 605996Sbill p=b; 606996Sbill if (b[0]!='~' || b[1]!='>') { 607996Sbill if (*(q-2) == '\r') { 608996Sbill q--; 609996Sbill *(q-1)=(*q); 610996Sbill } 611996Sbill if (ds>=0) write(ds,b,q-b); 612996Sbill continue; 613996Sbill } 614996Sbill if (ds>=0) close(ds); 615996Sbill if (slnt) { 616996Sbill write(1, b, q - b); 617996Sbill write(1, CRLF, sizeof(CRLF)); 618996Sbill } 619996Sbill if (*(q-2) == '\r') q--; 620996Sbill *(q-1)=0; 621996Sbill slnt=0; 622996Sbill q=b+2; 623996Sbill if (*q == '>') q++; 624996Sbill if (*q == ':') { 625996Sbill slnt=1; 626996Sbill q++; 627996Sbill } 628996Sbill if (*q == 0) { 629996Sbill ds=(-1); 630996Sbill continue; 631996Sbill } 632996Sbill if (b[2]!='>' || (ds=open(q,1))<0) ds=creat(q,0644); 633996Sbill lseek(ds, (long)0, 2); 634996Sbill if (ds<0) prf("Can't divert %s",b+1); 635996Sbill } 636996Sbill if(justrung) { 637996Sbill justrung = 0; 638996Sbill goto agin; 639996Sbill } 640996Sbill } 641996Sbill 642996Sbill struct {char lobyte; char hibyte;}; 643996Sbill mode(f) 644996Sbill { 645996Sbill struct sgttyb stbuf; 646996Sbill if (dout) return; 647996Sbill ioctl(0, TIOCGETP, &stbuf); 648996Sbill tkill = stbuf.sg_kill; 649996Sbill terase = stbuf.sg_erase; 650996Sbill if (f == 0) { 651996Sbill stbuf.sg_flags &= ~RAW; 652996Sbill stbuf.sg_flags |= ECHO|CRMOD; 653996Sbill } 654996Sbill if (f == 1) { 655996Sbill stbuf.sg_flags |= RAW; 656996Sbill stbuf.sg_flags &= ~(ECHO|CRMOD); 657996Sbill } 658996Sbill if (f == 2) { 659996Sbill stbuf.sg_flags &= ~RAW; 660996Sbill stbuf.sg_flags &= ~(ECHO|CRMOD); 661996Sbill } 662996Sbill ioctl(0, TIOCSETP, &stbuf); 663996Sbill } 664996Sbill 665996Sbill echo(s) 666996Sbill char *s; 667996Sbill { 668996Sbill char *p; 669996Sbill for (p=s;*p;p++); 670996Sbill if (p>s) write(0,s,p-s); 671996Sbill write(0,CRLF, sizeof(CRLF)); 672996Sbill } 673996Sbill 674996Sbill prf(f, s) 675996Sbill char *f; 676996Sbill char *s; 677996Sbill { 678996Sbill fprintf(stderr, f, s); 679996Sbill fprintf(stderr, CRLF); 680996Sbill } 681996Sbill 682996Sbill exists(devname) 683996Sbill char *devname; 684996Sbill { 685996Sbill if (access(devname, 0)==0) 686996Sbill return(1); 687996Sbill prf("%s does not exist", devname); 688996Sbill return(0); 689996Sbill } 6902370Smark 6912370Smark cleanup(code) 6922370Smark { 6932370Smark rmlock(NULL); 6942370Smark exit(code); 6952370Smark } 6962370Smark 6972370Smark /* 6982370Smark * This code is taken directly from uucp and follows the same 6992370Smark * conventions. This is important since uucp and cu should 7002370Smark * respect each others locks. 7012370Smark */ 7022370Smark 7032370Smark /* ulockf 3.2 10/26/79 11:40:29 */ 7042370Smark /* #include "uucp.h" */ 7052370Smark #include <sys/types.h> 7062370Smark #include <sys/stat.h> 7072370Smark 7082370Smark 7092370Smark 7102370Smark /******* 7112370Smark * ulockf(file, atime) 7122370Smark * char *file; 7132370Smark * time_t atime; 7142370Smark * 7152370Smark * ulockf - this routine will create a lock file (file). 7162370Smark * If one already exists, the create time is checked for 7172370Smark * older than the age time (atime). 7182370Smark * If it is older, an attempt will be made to unlink it 7192370Smark * and create a new one. 7202370Smark * 7212370Smark * return codes: 0 | FAIL 7222370Smark */ 7232370Smark 7242370Smark ulockf(file, atime) 7252370Smark char *file; 7262370Smark time_t atime; 7272370Smark { 7282370Smark struct stat stbuf; 7292370Smark time_t ptime; 7302370Smark int ret; 7312370Smark static int pid = -1; 7322370Smark static char tempfile[NAMESIZE]; 7332370Smark 7342370Smark if (pid < 0) { 7352370Smark pid = getpid(); 7362370Smark sprintf(tempfile, "/usr/spool/uucp/LTMP.%d", pid); 7372370Smark } 7382370Smark if (onelock(pid, tempfile, file) == -1) { 7392370Smark /* lock file exists */ 7402370Smark /* get status to check age of the lock file */ 7412370Smark ret = stat(file, &stbuf); 7422370Smark if (ret != -1) { 7432370Smark time(&ptime); 7442370Smark if ((ptime - stbuf.st_ctime) < atime) { 7452370Smark /* file not old enough to delete */ 7462370Smark return(FAIL); 7472370Smark } 7482370Smark } 7492370Smark ret = unlink(file); 7502370Smark ret = onelock(pid, tempfile, file); 7512370Smark if (ret != 0) 7522370Smark return(FAIL); 7532370Smark } 7542370Smark stlock(file); 7552370Smark return(0); 7562370Smark } 7572370Smark 7582370Smark 7592370Smark #define MAXLOCKS 10 /* maximum number of lock files */ 7602370Smark char *Lockfile[MAXLOCKS]; 7612370Smark int Nlocks = 0; 7622370Smark 7632370Smark /*** 7642370Smark * stlock(name) put name in list of lock files 7652370Smark * char *name; 7662370Smark * 7672370Smark * return codes: none 7682370Smark */ 7692370Smark 7702370Smark stlock(name) 7712370Smark char *name; 7722370Smark { 7732370Smark char *p; 7742370Smark extern char *calloc(); 7752370Smark int i; 7762370Smark 7772370Smark for (i = 0; i < Nlocks; i++) { 7782370Smark if (Lockfile[i] == NULL) 7792370Smark break; 7802370Smark } 7812370Smark ASSERT(i < MAXLOCKS, "TOO MANY LOCKS %d", i); 7822370Smark if (i >= Nlocks) 7832370Smark i = Nlocks++; 7842370Smark p = calloc(strlen(name) + 1, sizeof (char)); 7852370Smark ASSERT(p != NULL, "CAN NOT ALLOCATE FOR %s", name); 7862370Smark strcpy(p, name); 7872370Smark Lockfile[i] = p; 7882370Smark return; 7892370Smark } 7902370Smark 7912370Smark 7922370Smark /*** 7932370Smark * rmlock(name) remove all lock files in list 7942370Smark * char *name; or name 7952370Smark * 7962370Smark * return codes: none 7972370Smark */ 7982370Smark 7992370Smark rmlock(name) 8002370Smark char *name; 8012370Smark { 8022370Smark int i; 8032370Smark 8042370Smark for (i = 0; i < Nlocks; i++) { 8052370Smark if (Lockfile[i] == NULL) 8062370Smark continue; 8072370Smark if (name == NULL 8082370Smark || strcmp(name, Lockfile[i]) == SAME) { 8092370Smark unlink(Lockfile[i]); 8102370Smark free(Lockfile[i]); 8112370Smark Lockfile[i] = NULL; 8122370Smark } 8132370Smark } 8142370Smark return; 8152370Smark } 8162370Smark 8172370Smark 8182370Smark /* this stuff from pjw */ 8192370Smark /* /usr/pjw/bin/recover - check pids to remove unnecessary locks */ 8202370Smark /* isalock(name) returns 0 if the name is a lock */ 8212370Smark /* unlock(name) unlocks name if it is a lock*/ 8222370Smark /* onelock(pid,tempfile,name) makes lock a name 8232370Smark on behalf of pid. Tempfile must be in the same 8242370Smark file system as name. */ 8252370Smark /* lock(pid,tempfile,names) either locks all the 8262370Smark names or none of them */ 8272370Smark isalock(name) char *name; 8282370Smark { 8292370Smark struct stat xstat; 8302370Smark if(stat(name,&xstat)<0) return(0); 8312370Smark if(xstat.st_size!=sizeof(int)) return(0); 8322370Smark return(1); 8332370Smark } 8342370Smark unlock(name) char *name; 8352370Smark { 8362370Smark if(isalock(name)) return(unlink(name)); 8372370Smark else return(-1); 8382370Smark } 8392370Smark onelock(pid,tempfile,name) char *tempfile,*name; 8402370Smark { int fd; 8412370Smark fd=creat(tempfile,0444); 8422370Smark if(fd<0) return(-1); 8432370Smark write(fd,(char *) &pid,sizeof(int)); 8442370Smark close(fd); 8452370Smark if(link(tempfile,name)<0) 8462370Smark { unlink(tempfile); 8472370Smark return(-1); 8482370Smark } 8492370Smark unlink(tempfile); 8502370Smark return(0); 8512370Smark } 8522370Smark lock(pid,tempfile,names) char *tempfile,**names; 8532370Smark { int i,j; 8542370Smark for(i=0;names[i]!=0;i++) 8552370Smark { if(onelock(pid,tempfile,names[i])==0) continue; 8562370Smark for(j=0;j<i;j++) unlink(names[j]); 8572370Smark return(-1); 8582370Smark } 8592370Smark return(0); 8602370Smark } 8612370Smark 8622370Smark #define LOCKPRE "/usr/spool/uucp/LCK." 8632370Smark 8642370Smark /*** 8652370Smark * delock(s) remove a lock file 8662370Smark * char *s; 8672370Smark * 8682370Smark * return codes: 0 | FAIL 8692370Smark */ 8702370Smark 8712370Smark delock(s) 8722370Smark char *s; 8732370Smark { 8742370Smark char ln[30]; 8752370Smark 8762370Smark sprintf(ln, "%s.%s", LOCKPRE, s); 8772370Smark rmlock(ln); 8782370Smark } 8792370Smark 8802370Smark 8812370Smark /*** 8822370Smark * mlock(sys) create system lock 8832370Smark * char *sys; 8842370Smark * 8852370Smark * return codes: 0 | FAIL 8862370Smark */ 8872370Smark 8882370Smark mlock(sys) 8892370Smark char *sys; 8902370Smark { 8912370Smark char lname[30]; 8922370Smark sprintf(lname, "%s.%s", LOCKPRE, sys); 8932370Smark return(ulockf(lname, (time_t) SLCKTIME ) < 0 ? FAIL : 0); 8942370Smark } 8952370Smark 8962370Smark 8972370Smark 8982370Smark /*** 8992370Smark * ultouch() update access and modify times for lock files 9002370Smark * 9012370Smark * return code - none 9022370Smark */ 9032370Smark 9042370Smark ultouch() 9052370Smark { 9062370Smark time_t time(); 9072370Smark int i; 9082370Smark struct ut { 9092370Smark time_t actime; 9102370Smark time_t modtime; 9112370Smark } ut; 9122370Smark 9132370Smark ut.actime = time(&ut.modtime); 9142370Smark for (i = 0; i < Nlocks; i++) { 9152370Smark if (Lockfile[i] == NULL) 9162370Smark continue; 9172370Smark utime(Lockfile[i], &ut); 9182370Smark } 9192370Smark return; 9202370Smark } 921