home *** CD-ROM | disk | FTP | other *** search
/ minnie.tuhs.org / unixen.tar / unixen / PDP-11 / Distributions / ucb / 2.9-derivatives / 2.9-pro350 / misc / cu.c next >
Encoding:
C/C++ Source or Header  |  1985-02-28  |  17.4 KB  |  998 lines

  1. #include <stdio.h>
  2. #include <signal.h>
  3. #include <sgtty.h>
  4. /*
  5.  * defs that come from uucp.h
  6.  */
  7. #define NAMESIZE 35
  8. #define FAIL -1
  9. #define SAME 0
  10. #define SLCKTIME 5400    /* system/device timeout (LCK.. files) in seconds */
  11. #define ASSERT(e, f, v) if (!(e)) {\
  12.     fprintf(stderr, "AERROR - (%s) ", "e");\
  13.     fprintf(stderr, f, v);\
  14.     cleanup(FAIL);\
  15. }
  16.  
  17. /*
  18.  *    cu telno [-t] [-s speed] [-l line] [-a acu] [-p]
  19.  *
  20.  *    -t is for dial-out to terminal.
  21.  *    speeds are: 110, 134, 150, 300, 1200, 2400. 300 is default.
  22.  *
  23.  *    -p says strip parity of characters transmitted.  (to compensate
  24.  *    for c100's)
  25.  *
  26.  *    Escape with `~' at beginning of line.
  27.  *    Ordinary diversions are ~<, ~> and ~>>.
  28.  *    Silent output diversions are ~>: and ~>>:.
  29.  *    Terminate output diversion with ~> alone.
  30.  *    Quit is ~. and ~! gives local command or shell.
  31.  *    Also ~$ for canned procedure pumping remote.
  32.  *    ~%put from [to]  and  ~%take from [to] invoke builtins
  33.  */
  34.  
  35. #define CRLF "\r\n"
  36. #define wrc(ds) write(ds,&c,1)
  37.  
  38.  
  39. char    *devcul    = "/dev/tty01";
  40. char    *devcua    = "/dev/cua0";
  41. char    *lspeed    = "1200";
  42.  
  43. int    ln;        /* fd for comm line */
  44. char    tkill, terase;    /* current input kill & erase */
  45. int    notabs;        /* terminal doesn't expand tabs */
  46. int    efk;        /* process of id of listener  */
  47. char    c;
  48. char    oc;
  49.  
  50. char    *connmsg[] = {
  51.     "",
  52.     "line busy",
  53.     "call dropped",
  54.     "no carrier",
  55.     "can't fork",
  56.     "acu access",
  57.     "tty access",
  58.     "tty hung",
  59. "usage: cu telno [-t] [-p] [-h] [-b] [-acu#] [-s speed] [-l line] [-a acu]",
  60.     "lock failed: line busy"
  61. };
  62.  
  63. rdc(ds) {
  64.  
  65.     ds=read(ds,&oc,1); 
  66.     c = oc & 0177;
  67.     return (ds);
  68. }
  69.  
  70. int intr;
  71.  
  72. sig2()
  73. {
  74.     signal(SIGINT, SIG_IGN); 
  75.     intr = 1;
  76. }
  77.  
  78. int set14;
  79.  
  80. xsleep(n)
  81. {
  82.     xalarm(n);
  83.     pause();
  84.     xalarm(0);
  85. }
  86.  
  87. xalarm(n)
  88. {
  89.     set14=n; 
  90.     alarm(n);
  91. }
  92.  
  93. sig14()
  94. {
  95.     signal(SIGALRM, sig14); 
  96.     if (set14) alarm(1);
  97. }
  98.  
  99. int    dout;
  100. int    nhup;
  101. int    dbflag;
  102. int    pflag;        /* strip parity on chars sent to remote */
  103. int    hdplx;        /* set to emulate half-duplex terminal */
  104. int    nullbrk;    /* turn breaks (nulls) into dels */
  105. int    pipes[2] = { -1, -1 };
  106. int    speed;
  107.  
  108. /*
  109.  *    main: get connection, set speed for line.
  110.  *    spawn child to invoke rd to read from line, output to fd 1
  111.  *    main line invokes wr to read tty, write to line
  112.  */
  113. main(ac,av)
  114. char *av[];
  115. {
  116.     int fk;
  117.     char *telno = NULL;
  118.     struct sgttyb stbuf;
  119.     int cleanup();
  120.  
  121.     signal(SIGALRM, sig14);
  122.     nhup = (int)signal(SIGINT, cleanup);
  123.     signal(SIGHUP, cleanup);
  124.     signal(SIGQUIT, cleanup);
  125. #ifndef GOO
  126.     if (ac < 2) {
  127.         prf(connmsg[8]);
  128.         exit(8);
  129.     }
  130. #endif
  131.     for (; ac > 1; av++,ac--) {
  132.         if (av[1][0] != '-')
  133.             telno = av[1];
  134.         else switch(av[1][1]) {
  135.         case 't':
  136.             dout = 1;
  137.             continue;
  138.         case 'b':
  139.             nullbrk++;
  140.             continue;
  141.         case 'd':
  142.             dbflag++;
  143.             continue;
  144.         case 'h':
  145.             hdplx++;
  146.             continue;
  147.         case 'p':
  148.             pflag++;
  149.             continue;
  150.         case 's':
  151.             lspeed = av[2]; ++av; --ac;
  152.             break;
  153.         case 'l':
  154.             devcul = av[2]; ++av; --ac;
  155.             break;
  156.         case 'a':
  157.             devcua = av[2]; ++av; --ac;
  158.             break;
  159.         case '0': case '1': case '2': case '3': case '4':
  160.         case '5': case '6': case '7': case '8': case '9':
  161.             devcua[strlen(devcua)-1] = av[1][1];
  162.             devcul[strlen(devcul)-1] = av[1][1];
  163.             break;
  164.         default:
  165.             prf("Bad flag %s", av[1]);
  166.             break;
  167.         }
  168.     }
  169. #ifndef GOO
  170.     if (telno == NULL) {
  171.         prf(connmsg[8]);
  172.         exit(8);
  173.     }
  174. #endif
  175. #ifdef    GOO
  176.     if (!exists(devcul))
  177. #else
  178.     if (!exists(devcua) || !exists(devcul))
  179. #endif
  180.         exit(9);
  181.     switch(atoi(lspeed)) {
  182.     case 110:
  183.         speed = B110;break;
  184.     case 150:
  185.         speed = B150;break;
  186.     case 300:
  187.         speed = B300;break;
  188.     case 1200:
  189.     default:
  190.         speed = B1200;break;
  191.     case 2400:
  192.         speed = B2400;break;
  193.     case 4800:
  194.         speed = B4800;break;
  195.     case 9600:
  196.         speed = B9600;break;
  197.     }
  198.     ln = conn(devcul, devcua, telno);
  199.     if (ln < 0) {
  200.         prf("Connect failed: %s",connmsg[-ln]);
  201.         cleanup(-ln);
  202.     }
  203.     ioctl(0, TIOCGETP, &stbuf);
  204.     notabs = stbuf.sg_flags & XTABS;
  205.     stbuf.sg_ispeed = speed;
  206.     stbuf.sg_ospeed = speed;
  207.     stbuf.sg_flags = EVENP|ODDP;
  208.     if (!dout)
  209.         stbuf.sg_flags |= RAW | TANDEM;
  210.     ioctl(ln, TIOCSETP, &stbuf);
  211.     ioctl(ln, TIOCEXCL, (struct sgttyb *)NULL);
  212.     ioctl(ln, TIOCHPCL, (struct sgttyb *)NULL);
  213.     prf("Connected");
  214.     pipe(pipes);
  215.     if (dout)
  216.         fk = -1;
  217.     else
  218.         fk = fork();
  219.     signal(SIGINT, SIG_IGN);
  220.     if (fk == 0) {
  221.         chwrsig();
  222.         rd();
  223.         prf("\007Lost carrier");
  224.         cleanup(3);
  225.     }
  226.     mode(1);
  227.     efk = fk;
  228.     wr();
  229.     mode(0);
  230.     if (fk != -1) kill(fk, SIGKILL);
  231.     wait((int *)NULL);
  232.     stbuf.sg_ispeed = 0;
  233.     stbuf.sg_ospeed = 0;
  234.     ioctl(ln, TIOCSETP, &stbuf);
  235.     prf("Disconnected");
  236.     cleanup(0);
  237. }
  238.  
  239. /*
  240.  *    conn: establish dial-out connection.
  241.  *    Example:  fd = conn("/dev/ttyh","/dev/dn1","4500");
  242.  *    Returns descriptor open to tty for reading and writing.
  243.  *    Negative values (-1...-7) denote errors in connmsg.
  244.  *    Uses alarm and fork/wait; requires sig14 handler.
  245.  *    Be sure to disconnect tty when done, via HUPCL or stty 0.
  246.  */
  247. conn(dev,acu,telno)
  248. char *dev, *acu, *telno;
  249. {
  250.     struct sgttyb stbuf;
  251.     extern errno;
  252.     char *p, *q, b[30];
  253.     char *ltail, *atail;
  254.     char *rindex();
  255.     int er, fk, dn, dh, t;
  256.     er=0; 
  257.     fk=(-1);
  258. #ifndef GOO
  259.     atail = rindex(acu, '/')+1;
  260.     if (mlock(atail) == FAIL) {
  261.         er = 9;
  262.         goto X;
  263.     }
  264.     ltail = rindex(dev, '/')+1;
  265.     if (mlock(ltail) == FAIL) {
  266.         er = 9;
  267.         delock(atail);
  268.         goto X;
  269.     }
  270.     if ((dn=open(acu,1))<0) {
  271.         er=(errno == 6? 1:5); 
  272.         goto X;
  273.     }
  274. #endif
  275.     if ((fk=fork()) == (-1)) {
  276.         er=4; 
  277.         goto X;
  278.     }
  279.     if (fk == 0) {
  280.         open(dev,2); 
  281.         for (;;) pause();
  282.     }
  283.     xsleep(2);
  284.     /*
  285.      *    copy phone #, assure EON
  286.      */
  287. #ifndef GOO
  288.     p=b; 
  289.     q=telno;
  290.     while (*p++=(*q++))
  291.         ;
  292.     p--;
  293.     if (*(p-1)!='<') {
  294.         /*if (*(p-1)!='-') *p++='-';*/
  295.         *p++='<';
  296.     }
  297.     t=p-b;
  298.     xalarm(5*t);
  299.     t=write(dn,b,t);
  300.     xalarm(0);
  301.     if (t<0) {
  302.         er=2; 
  303.         goto X;
  304.     }
  305.     /* close(dn) */
  306. #endif
  307.     xalarm(40);        /* was 5; sometimes missed carrier */
  308.     dh = open(dev,2);
  309.     xalarm(0);
  310.     if (dh<0) {
  311.         er=(errno == 4? 3:6); 
  312.         goto X;
  313.     }
  314.     ioctl(dh, TIOCGETP, &stbuf);
  315.     stbuf.sg_flags &= ~ECHO;
  316.     xalarm(10);
  317.     ioctl(dh, TIOCSETP, &stbuf);
  318.     ioctl(dh, TIOCHPCL, (struct sgttyb *)NULL);
  319.     xalarm(0);
  320. X: 
  321.     if (er) close(dn);
  322. #ifndef GOO
  323.     delock(atail);
  324. #endif
  325.     if (fk!=(-1)) {
  326.         kill(fk, SIGKILL);
  327.         xalarm(10);
  328.         while ((t=wait((int *)NULL))!=(-1) && t!=fk);
  329.         xalarm(0);
  330.     }
  331.     return (er? -er:dh);
  332. }
  333.  
  334. /*
  335.  *    wr: write to remote: 0 -> line.
  336.  *    ~.    terminate
  337.  *    ~<file    send file
  338.  *    ~!    local login-style shell
  339.  *    ~!cmd    execute cmd locally
  340.  *    ~$proc    execute proc locally, send output to line
  341.  *    ~%cmd    execute builtin cmd (put and take)
  342.  *    ~#    send 1-sec break
  343.  *    ~^Z    suspend cu process.
  344.  */
  345.  
  346. wr()
  347. {
  348.     int ds,fk,lcl,x;
  349.     char *p,b[600];
  350.     for (;;) {
  351.         p=b;
  352.         while (rdc(0) == 1) {
  353.             if (p == b) lcl=(c == '~');
  354.             if (p == b+1 && b[0] == '~') lcl=(c!='~');
  355.             if (nullbrk && c == 0) oc=c=0177; /* fake break kludge */
  356.             if (!lcl) {
  357.                 if(!pflag)c = oc;
  358.                 if (wrc(ln) == 0) {
  359.                     prf("line gone"); return;
  360.                 }
  361.                 if (hdplx) wrc(0);
  362.                 c &= 0177;
  363.             }
  364.             if (lcl) {
  365.                 if (c == 0177) c=tkill;
  366.                 if (c == '\r' || c == '\n') goto A;
  367.                 if (!dout) wrc(0);
  368.             }
  369.             *p++=c;
  370.             if (c == terase) {
  371.                 p=p-2; 
  372.                 if (p<b) p=b;
  373.             }
  374.             if (c == tkill || c == 0177 || c == '\4' || c == '\r' || c == '\n') p=b;
  375.         }
  376.         return;
  377. A: 
  378.         if (!dout) echo("");
  379.         *p=0;
  380.         switch (b[1]) {
  381.         case '.':
  382.         case '\004':
  383.             return;
  384. #ifdef    TIOCSBRK
  385.         case '#':
  386.             if (ioctl(ln, TIOCSBRK, 0) < 0)
  387.                 prf("can't send break");
  388.             else {
  389.                 sleep(1);
  390.                 ioctl(ln, TIOCCBRK, 0);
  391.                 continue;
  392.             }
  393. #endif
  394.         case '!':
  395.         case '$':
  396.             fk = fork();
  397.             if (fk == 0) {
  398.                 char *getenv();
  399.                 char *shell = getenv("SHELL");
  400.                 if (shell == 0) shell = "/bin/sh";
  401.                 close(1);
  402.                 dup(b[1] == '$'? ln:2);
  403.                 close(ln);
  404.                 mode(0);
  405.                 if (!nhup) signal(SIGINT, SIG_DFL);
  406.                 if (b[2] == 0) execl(shell,shell,0);
  407.                 /* if (b[2] == 0) execl(shell,"-",0); */
  408.                 else execl(shell,"sh","-c",b+2,0);
  409.                 prf("Can't execute shell");
  410.                 exit(~0);
  411.             }
  412.             if (fk!=(-1)) {
  413.                 while (wait(&x)!=fk);
  414.             }
  415.             mode(1);
  416.             if (b[1] == '!') echo("!");
  417.             else {
  418.                 if (dout) echo("$");
  419.             }
  420.             break;
  421.         case '<':
  422.             if (b[2] == 0) break;
  423.             if ((ds=open(b+2,0))<0) {
  424.                 prf("Can't divert %s",b+1); 
  425.                 break;
  426.             }
  427.             intr=x=0;
  428.             mode(2);
  429.             if (!nhup) signal(SIGINT, sig2);
  430.             while (!intr && rdc(ds) == 1) {
  431.                 if (wrc(ln) == 0) {
  432.                     x=1; 
  433.                     break;
  434.                 }
  435.             }
  436.             signal(SIGINT, SIG_IGN);
  437.             close(ds);
  438.             mode(1);
  439.             if (x) return;
  440.             if (dout) echo("<");
  441.             break;
  442.         case '>':
  443.         case ':':
  444.             {
  445.             register char *q;
  446.  
  447.             if(pipes[1]==-1) {
  448.                 prf("Can't tell other demon to divert");
  449.                 break;
  450.             }
  451.             q = b+1;
  452.             if(*q=='>') q++;
  453.             write(pipes[1],q,strlen(q)+1);
  454.             if(dbflag) prf("msg to be delivered:"),prf(q);
  455.             if (efk != -1) kill(efk,SIGEMT);
  456.             }
  457.             break;
  458. #ifdef SIGTSTP
  459. #define CTRLZ    26
  460.         case CTRLZ:
  461.             mode(0);
  462.             kill(getpid(), SIGTSTP);
  463.             mode(1);
  464.             break;
  465. #endif
  466.         case '%':
  467.             dopercen(&b[2]);
  468.             break;
  469.         default:
  470.             prf("Use `~~' to start line with `~'");
  471.         }
  472.         continue;
  473.     }
  474. }
  475.  
  476. dopercen(line)
  477. register char *line;
  478. {
  479.     char *args[10];
  480.     register narg, f;
  481.     int rcount;
  482.     for (narg = 0; narg < 10;) {
  483.         while(*line == ' ' || *line == '\t')
  484.             line++;
  485.         if (*line == '\0')
  486.             break;
  487.         args[narg++] = line;
  488.         while(*line != '\0' && *line != ' ' && *line != '\t')
  489.             line++;
  490.         if (*line == '\0')
  491.             break;
  492.         *line++ = '\0';
  493.     }
  494.     if (equal(args[0], "take")) {
  495.         if (narg < 2) {
  496.             prf("usage: ~%%take from [to]");
  497.             return;
  498.         }
  499.         if (narg < 3)
  500.             args[2] = args[1];
  501.         write(pipes[1], ">/dev/null",sizeof(">/dev/null"));
  502.         if(dbflag) prf("sending take message");
  503.         if (efk != -1) kill(efk,SIGEMT);
  504.         xsleep(5);
  505.         if (notabs)
  506.             wrln("stty tabs;");
  507.         wrln("echo '~>:");
  508.         wrln(args[2]);
  509.         wrln("'; tee /dev/null <");
  510.         wrln(args[1]);
  511.         wrln(";echo '~>'");
  512.         if (notabs)
  513.             wrln(";stty -tabs");
  514.         wrln("\n");
  515.         return;
  516.     } else if (equal(args[0], "put")) {
  517.         if (narg < 2) {
  518.             prf("usage: ~%%put from [to]");
  519.             return;
  520.         }
  521.         if (narg < 3)
  522.             args[2] = args[1];
  523.         if ((f = open(args[1], 0)) < 0) {
  524.             prf("cannot open: %s", args[1]);
  525.             return;
  526.         }
  527.         wrln("stty -echo;cat >");
  528.         wrln(args[2]);
  529.         wrln(";stty echo\n");
  530.         xsleep(5);
  531.         intr = 0;
  532.         if (!nhup)
  533.             signal(SIGINT, sig2);
  534.         mode(2);
  535.         rcount = 0;
  536.         while(!intr && rdc(f) == 1) {
  537.             rcount++;
  538.             if (c == tkill || c == terase)
  539.                 wrln("\\");
  540.             if (wrc(ln) != 1) {
  541.                 xsleep(2);
  542.                 if (wrc(ln) != 1) {
  543.                     prf("character missed");
  544.                     intr = 1;
  545.                     break;
  546.                 }
  547.             }
  548.         }
  549.         signal(SIGINT, SIG_IGN);
  550.         close(f);
  551.         if (intr) {
  552.             wrln("\n");
  553.             prf("stopped after %d bytes", rcount);
  554.         }
  555.         wrln("\004");
  556.         xsleep(5);
  557.         mode(1);
  558.         return;
  559.     }
  560.     prf("~%%%s unknown\n", args[0]);
  561. }
  562.  
  563. equal(s1, s2)
  564. register char *s1, *s2;
  565. {
  566.     while (*s1++ == *s2)
  567.         if (*s2++ == '\0')
  568.             return(1);
  569.     return(0);
  570. }
  571.  
  572. wrln(s)
  573. register char *s;
  574. {
  575.     while (*s)
  576.         write(ln, s++, 1);
  577. }
  578. /*    chwrsig:  Catch orders from wr process 
  579.  *    to instigate diversion
  580.  */
  581. int whoami;
  582. chwrsig(){
  583.     int readmsg(); 
  584.     whoami = getpid();
  585.     signal(SIGEMT,readmsg);
  586. }
  587. int ds,slnt,taking;
  588. int justrung;
  589. readmsg(){
  590.     static char dobuff[128], morejunk[256];
  591.     int n;
  592.     justrung = 1;
  593.     signal(SIGEMT,readmsg);
  594.     if(dbflag) {
  595.         prf("About to read from pipe");
  596.     }
  597.     n = read(pipes[0],morejunk,256);
  598.     if(dbflag) {
  599.         prf("diversion mesg recieved is");
  600.         prf(morejunk);
  601.         prf(CRLF);
  602.     }
  603.     dodiver(morejunk);
  604. }
  605. dodiver(msg)
  606. char *msg;
  607. {
  608.     register char *cp = msg; 
  609.  
  610.     if (*cp=='>') cp++;
  611.     if (*cp==':') {
  612.         cp++;
  613.         if(*cp==0) {
  614.             slnt ^= 1;
  615.             return;
  616.         } else  {
  617.             slnt = 1;
  618.         }
  619.     }
  620.     if (ds >= 0) close(ds);
  621.     if (*cp==0) {
  622.         slnt = 0;
  623.         ds = -1;
  624.         return;
  625.     }
  626.     if (*msg!='>' || (ds=open(cp,1))<0) ds=creat(cp,0644);
  627.     lseek(ds, (long)0, 2);
  628.     if(ds < 0) prf("Creat failed:"), prf(cp);
  629.     if (ds<0) prf("Can't divert %s",cp+1);
  630. }
  631.  
  632.  
  633. /*
  634.  *    rd: read from remote: line -> 1
  635.  *    catch: diversion caught by interrupt routine
  636.  */
  637.  
  638. #define ORDIN 0
  639. #define SAWCR 1
  640. #define EOL   2
  641. #define SAWTL 3
  642. #define DIVER 4
  643.  
  644. rd()
  645. {
  646.     extern int ds,slnt;
  647.     char rb[600], lb[600], *rlim, *llim, c;
  648.     register char *p,*q;
  649.     int cnt, state = ORDIN, mustecho, oldslnt;
  650.  
  651.     ds=(-1);
  652.     p = lb; llim = lb+600;
  653. agin:
  654.     while((cnt = read(ln,rb,600)) > 0) {
  655.         if(!slnt) {
  656.             if (pflag)
  657.                 for (q=rb, rlim = rb + cnt - 1; q <= rlim; )
  658.                     *q++ &= 0177;
  659.             write(1,rb,cnt);
  660.         }
  661.         if(ds < 0) continue;
  662.         oldslnt = slnt;
  663.         for( q=rb, rlim = rb + cnt - 1; q <= rlim; ) {
  664.             c = *q++ & 0177;
  665.             if(p < llim) *p++ = c;
  666.             switch(state) {
  667.             case ORDIN:
  668.                 if(c=='\r') state = SAWCR;
  669.                 break;
  670.             case SAWCR:
  671.                 if(c=='\n') {
  672.                     state = EOL;
  673.                     p--;
  674.                     p[-1] = '\n';
  675.                 } else state = ORDIN;
  676.                 break;
  677.             case EOL:
  678.                 state = (c=='~' ? SAWTL : 
  679.                      (c=='\r' ? SAWCR : ORDIN));
  680.                 break;
  681.             case SAWTL:
  682.                 state = (c=='>' ? DIVER : 
  683.                      (c=='\r' ? SAWCR : ORDIN));
  684.                 break;
  685.             case DIVER:
  686.                 if(c=='\r') {
  687.                     p--;
  688.                 } else if (c=='\n') {
  689.                     state = ORDIN;
  690.                     p[-1] = 0;
  691.                     dodiver(lb+2);
  692.                     c = 0; p = lb;
  693.                 }
  694.             }
  695.             if(slnt==0 && oldslnt) {
  696.                 if(c=='\n') {
  697.                     write(1,lb,p-lb-1);
  698.                     write(1,CRLF,sizeof(CRLF));
  699.                 } else if(q==rlim) {
  700.                     write(1,lb,p-lb);
  701.                     c = '\n';  /*force flush to file*/
  702.                 }
  703.             }
  704.             if(c=='\n') {
  705.                 if(ds >= 0)
  706.                     write(ds,lb,p-lb);
  707.                 p = lb;
  708.             }
  709.         }
  710.     }
  711.     if(justrung) {
  712.         justrung = 0;
  713.         goto agin;
  714.     }
  715. }
  716.  
  717. struct {char lobyte; char hibyte;};
  718. mode(f)
  719. {
  720.     struct sgttyb stbuf;
  721.     if (dout) return;
  722.     ioctl(0, TIOCGETP, &stbuf);
  723.     tkill = stbuf.sg_kill;
  724.     terase = stbuf.sg_erase;
  725.     if (f == 0) {
  726.         stbuf.sg_flags &= ~RAW;
  727.         stbuf.sg_flags |= ECHO|CRMOD;
  728.     }
  729.     if (f == 1) {
  730.         stbuf.sg_flags |= RAW;
  731.         stbuf.sg_flags &= ~(ECHO|CRMOD);
  732.     }
  733.     if (f == 2) {
  734.         stbuf.sg_flags &= ~RAW;
  735.         stbuf.sg_flags &= ~(ECHO|CRMOD);
  736.     }
  737.     ioctl(0, TIOCSETP, &stbuf);
  738. }
  739.  
  740. echo(s)
  741. char *s;
  742. {
  743.     char *p;
  744.     for (p=s;*p;p++);
  745.     if (p>s) write(0,s,p-s);
  746.     write(0,CRLF, sizeof(CRLF));
  747. }
  748.  
  749. prf(f, s)
  750. char *f;
  751. char *s;
  752. {
  753.     fprintf(stderr, f, s);
  754.     fprintf(stderr, CRLF);
  755. }
  756.  
  757. exists(devname)
  758. char *devname;
  759. {
  760.     if (access(devname, 0)==0)
  761.         return(1);
  762.     prf("%s does not exist", devname);
  763.     return(0);
  764. }
  765.  
  766. cleanup(code)
  767. {
  768.     rmlock(NULL);
  769.     ioctl(ln, TIOCNXCL, (struct sgttyb *)NULL);
  770.     exit(code);
  771. }
  772.  
  773. /*
  774.  * This code is taken directly from uucp and follows the same
  775.  * conventions.  This is important since uucp and cu should
  776.  * respect each others locks.
  777.  */
  778.  
  779.     /*  ulockf 3.2  10/26/79  11:40:29  */
  780. /* #include "uucp.h" */
  781. #include <sys/types.h>
  782. #include <sys/stat.h>
  783.  
  784.  
  785.  
  786. /*******
  787.  *    ulockf(file, atime)
  788.  *    char *file;
  789.  *    time_t atime;
  790.  *
  791.  *    ulockf  -  this routine will create a lock file (file).
  792.  *    If one already exists, the create time is checked for
  793.  *    older than the age time (atime).
  794.  *    If it is older, an attempt will be made to unlink it
  795.  *    and create a new one.
  796.  *
  797.  *    return codes:  0  |  FAIL
  798.  */
  799.  
  800. ulockf(file, atime)
  801. char *file;
  802. time_t atime;
  803. {
  804.     struct stat stbuf;
  805.     time_t ptime;
  806.     int ret;
  807.     static int pid = -1;
  808.     static char tempfile[NAMESIZE];
  809.  
  810.     if (pid < 0) {
  811.         pid = getpid();
  812.         sprintf(tempfile, "/usr/spool/uucp/LTMP.%d", pid);
  813.     }
  814.     if (onelock(pid, tempfile, file) == -1) {
  815.         /* lock file exists */
  816.         /* get status to check age of the lock file */
  817.         ret = stat(file, &stbuf);
  818.         if (ret != -1) {
  819.             time(&ptime);
  820.             if ((ptime - stbuf.st_ctime) < atime) {
  821.                 /* file not old enough to delete */
  822.                 return(FAIL);
  823.             }
  824.         }
  825.         ret = unlink(file);
  826.         ret = onelock(pid, tempfile, file);
  827.         if (ret != 0)
  828.             return(FAIL);
  829.     }
  830.     stlock(file);
  831.     return(0);
  832. }
  833.  
  834.  
  835. #define MAXLOCKS 10    /* maximum number of lock files */
  836. char *Lockfile[MAXLOCKS];
  837. int Nlocks = 0;
  838.  
  839. /***
  840.  *    stlock(name)    put name in list of lock files
  841.  *    char *name;
  842.  *
  843.  *    return codes:  none
  844.  */
  845.  
  846. stlock(name)
  847. char *name;
  848. {
  849.     char *p;
  850.     extern char *calloc();
  851.     int i;
  852.  
  853.     for (i = 0; i < Nlocks; i++) {
  854.         if (Lockfile[i] == NULL)
  855.             break;
  856.     }
  857.     ASSERT(i < MAXLOCKS, "TOO MANY LOCKS %d", i);
  858.     if (i >= Nlocks)
  859.         i = Nlocks++;
  860.     p = calloc(strlen(name) + 1, sizeof (char));
  861.     ASSERT(p != NULL, "CAN NOT ALLOCATE FOR %s", name);
  862.     strcpy(p, name);
  863.     Lockfile[i] = p;
  864.     return;
  865. }
  866.  
  867.  
  868. /***
  869.  *    rmlock(name)    remove all lock files in list
  870.  *    char *name;    or name
  871.  *
  872.  *    return codes: none
  873.  */
  874.  
  875. rmlock(name)
  876. char *name;
  877. {
  878.     int i;
  879.  
  880.     for (i = 0; i < Nlocks; i++) {
  881.         if (Lockfile[i] == NULL)
  882.             continue;
  883.         if (name == NULL
  884.         || strcmp(name, Lockfile[i]) == SAME) {
  885.             unlink(Lockfile[i]);
  886.             free(Lockfile[i]);
  887.             Lockfile[i] = NULL;
  888.         }
  889.     }
  890.     return;
  891. }
  892.  
  893.  
  894. /*  this stuff from pjw  */
  895. /*  /usr/pjw/bin/recover - check pids to remove unnecessary locks */
  896. /*    isalock(name) returns 0 if the name is a lock */
  897. /*    unlock(name)  unlocks name if it is a lock*/
  898. /*    onelock(pid,tempfile,name) makes lock a name
  899.     on behalf of pid.  Tempfile must be in the same
  900.     file system as name. */
  901. /*    lock(pid,tempfile,names) either locks all the
  902.     names or none of them */
  903. isalock(name) char *name;
  904. {
  905.     struct stat xstat;
  906.     if(stat(name,&xstat)<0) return(0);
  907.     if(xstat.st_size!=sizeof(int)) return(0);
  908.     return(1);
  909. }
  910. unlock(name) char *name;
  911. {
  912.     if(isalock(name)) return(unlink(name));
  913.     else return(-1);
  914. }
  915. onelock(pid,tempfile,name) char *tempfile,*name;
  916. {    int fd;
  917.     fd=creat(tempfile,0444);
  918.     if(fd<0) return(-1);
  919.     write(fd,(char *) &pid,sizeof(int));
  920.     close(fd);
  921.     if(link(tempfile,name)<0)
  922.     {    unlink(tempfile);
  923.         return(-1);
  924.     }
  925.     unlink(tempfile);
  926.     return(0);
  927. }
  928. lock(pid,tempfile,names) char *tempfile,**names;
  929. {    int i,j;
  930.     for(i=0;names[i]!=0;i++)
  931.     {    if(onelock(pid,tempfile,names[i])==0) continue;
  932.         for(j=0;j<i;j++) unlink(names[j]);
  933.         return(-1);
  934.     }
  935.     return(0);
  936. }
  937.  
  938. #define LOCKPRE "/usr/spool/uucp/LCK."
  939.  
  940. /***
  941.  *    delock(s)    remove a lock file
  942.  *    char *s;
  943.  *
  944.  *    return codes:  0  |  FAIL
  945.  */
  946.  
  947. delock(s)
  948. char *s;
  949. {
  950.     char ln[30];
  951.  
  952.     sprintf(ln, "%s.%s", LOCKPRE, s);
  953.     rmlock(ln);
  954. }
  955.  
  956.  
  957. /***
  958.  *    mlock(sys)    create system lock
  959.  *    char *sys;
  960.  *
  961.  *    return codes:  0  |  FAIL
  962.  */
  963.  
  964. mlock(sys)
  965. char *sys;
  966. {
  967.     char lname[30];
  968.     sprintf(lname, "%s.%s", LOCKPRE, sys);
  969.     return(ulockf(lname, (time_t) SLCKTIME ) < 0 ? FAIL : 0);
  970. }
  971.  
  972.  
  973.  
  974. /***
  975.  *    ultouch()    update access and modify times for lock files
  976.  *
  977.  *    return code - none
  978.  */
  979.  
  980. ultouch()
  981. {
  982.     time_t time();
  983.     int i;
  984.     struct ut {
  985.         time_t actime;
  986.         time_t modtime;
  987.     } ut;
  988.  
  989.     ut.actime = time(&ut.modtime);
  990.     for (i = 0; i < Nlocks; i++) {
  991.         if (Lockfile[i] == NULL)
  992.             continue;
  993.         utime(Lockfile[i], &ut);
  994.     }
  995.     return;
  996. }
  997.  
  998.