home *** CD-ROM | disk | FTP | other *** search
/ minnie.tuhs.org / unixen.tar / unixen / PDP-11 / Trees / V7 / usr / src / cmd / cu.c < prev    next >
Encoding:
C/C++ Source or Header  |  1979-01-10  |  8.9 KB  |  540 lines

  1. #include <stdio.h>
  2. #include <signal.h>
  3. #include <sgtty.h>
  4. /*
  5.  *    cu telno [-t] [-s speed] [-l line] [-a acu]
  6.  *
  7.  *    -t is for dial-out to terminal.
  8.  *    speeds are: 110, 134, 150, 300, 1200. 300 is default.
  9.  *
  10.  *    Escape with `~' at beginning of line.
  11.  *    Ordinary diversions are ~<, ~> and ~>>.
  12.  *    Silent output diversions are ~>: and ~>>:.
  13.  *    Terminate output diversion with ~> alone.
  14.  *    Quit is ~. and ~! gives local command or shell.
  15.  *    Also ~$ for canned procedure pumping remote.
  16.  *    ~%put from [to]  and  ~%take from [to] invoke builtins
  17.  */
  18.  
  19. #define CRLF "\r\n"
  20. #define wrc(ds) write(ds,&c,1)
  21.  
  22.  
  23. char    *devcul    = "/dev/cul0";
  24. char    *devcua    = "/dev/cua0";
  25. char    *lspeed    = "300";
  26.  
  27. int    ln;    /* fd for comm line */
  28. char    tkill, terase;    /* current input kill & erase */
  29. char    c;
  30.  
  31. char    *connmsg[] = {
  32.     "",
  33.     "line busy",
  34.     "call dropped",
  35.     "no carrier",
  36.     "can't fork",
  37.     "acu access",
  38.     "tty access",
  39.     "tty hung",
  40.     "usage: cu telno [-t] [-s speed] [-l line] [-a acu]"
  41. };
  42.  
  43. rdc(ds) {
  44.  
  45.     ds=read(ds,&c,1); 
  46.     c&= 0177; 
  47.     return (ds);
  48. }
  49.  
  50. int intr;
  51.  
  52. sig2()
  53. {
  54.     signal(SIGINT, SIG_IGN); 
  55.     intr = 1;
  56. }
  57.  
  58. int set14;
  59.  
  60. xsleep(n)
  61. {
  62.     xalarm(n);
  63.     pause();
  64.     xalarm(0);
  65. }
  66.  
  67. xalarm(n)
  68. {
  69.     set14=n; 
  70.     alarm(n);
  71. }
  72.  
  73. sig14()
  74. {
  75.     signal(SIGALRM, sig14); 
  76.     if (set14) alarm(1);
  77. }
  78.  
  79. int    dout;
  80. int    nhup;
  81.  
  82. /*
  83.  *    main: get connection, set speed for line.
  84.  *    spawn child to invoke rd to read from line, output to fd 1
  85.  *    main line invokes wr to read tty, write to line
  86.  */
  87. main(ac,av)
  88. char *av[];
  89. {
  90.     int fk;
  91.     int speed;
  92.     char *telno;
  93.     struct sgttyb stbuf;
  94.  
  95.     signal(SIGALRM, sig14);
  96.     if (ac < 2) {
  97.         prf(connmsg[8]);
  98.         exit(8);
  99.     }
  100.     telno = av[1];
  101.     av += 2;
  102.     ac -= 2;
  103.     for (; ac > 0; av++) {
  104.         if (equal(*av, "-t")) {
  105.             dout = 1;
  106.             --ac;
  107.             continue;
  108.         }
  109.         if (ac < 2)
  110.             break;
  111.         if (equal(*av, "-s"))
  112.             lspeed = *++av;
  113.         else if (equal(*av, "-l"))
  114.             devcul = *++av;
  115.         else if (equal(*av, "-a"))
  116.             devcua = *++av;
  117.         else
  118.             break;
  119.         ac -= 2;
  120.     }
  121.     if (!exists(devcua) || !exists(devcul))
  122.         exit(9);
  123.     ln = conn(devcul, devcua, telno);
  124.     if (ln < 0) {
  125.         prf("Connect failed: %s",connmsg[-ln]);
  126.         exit(-ln);
  127.     }
  128.     switch(atoi(lspeed)) {
  129.     case 110:
  130.         speed = B110;break;
  131.     case 150:
  132.         speed = B150;break;
  133.     default:
  134.     case 300:
  135.         speed = B300;break;
  136.     case 1200:
  137.         speed = B1200;break;
  138.     }
  139.     stbuf.sg_ispeed = speed;
  140.     stbuf.sg_ospeed = speed;
  141.     stbuf.sg_flags = EVENP|ODDP;
  142.     if (!dout)
  143.         stbuf.sg_flags |= RAW;
  144.     ioctl(TIOCSETP, ln, &stbuf);
  145.     ioctl(TIOCEXCL, ln, (struct sgttyb *)NULL);
  146.     ioctl(TIOCHPCL, ln, (struct sgttyb *)NULL);
  147.     prf("Connected");
  148.     if (dout)
  149.         fk = -1;
  150.     else
  151.         fk = fork();
  152.     nhup = (int)signal(SIGINT, SIG_IGN);
  153.     if (fk == 0) {
  154.         rd();
  155.         prf("\007Lost carrier");
  156.         exit(3);
  157.     }
  158.     mode(1);
  159.     wr();
  160.     mode(0);
  161.     kill(fk, SIGKILL);
  162.     wait((int *)NULL);
  163.     stbuf.sg_ispeed = 0;
  164.     stbuf.sg_ospeed = 0;
  165.     ioctl(TIOCSETP, ln, &stbuf);
  166.     prf("Disconnected");
  167.     exit(0);
  168. }
  169.  
  170. /*
  171.  *    conn: establish dial-out connection.
  172.  *    Example:  fd = conn("/dev/ttyh","/dev/dn1","4500");
  173.  *    Returns descriptor open to tty for reading and writing.
  174.  *    Negative values (-1...-7) denote errors in connmsg.
  175.  *    Uses alarm and fork/wait; requires sig14 handler.
  176.  *    Be sure to disconnect tty when done, via HUPCL or stty 0.
  177.  */
  178.  
  179. conn(dev,acu,telno)
  180. char *dev, *acu, *telno;
  181. {
  182.     struct sgttyb stbuf;
  183.     extern errno;
  184.     char *p, *q, b[30];
  185.     int er, fk, dn, dh, t;
  186.     er=0; 
  187.     fk=(-1);
  188.     if ((dn=open(acu,1))<0) {
  189.         er=(errno == 6? 1:5); 
  190.         goto X;
  191.     }
  192.     if ((fk=fork()) == (-1)) {
  193.         er=4; 
  194.         goto X;
  195.     }
  196.     if (fk == 0) {
  197.         open(dev,2); 
  198.         for (;;) pause();
  199.     }
  200.     xsleep(2);
  201.     /*
  202.      *    copy phone #, assure EON
  203.      */
  204.     p=b; 
  205.     q=telno;
  206.     while (*p++=(*q++))
  207.         ;
  208.     p--;
  209.     if (*(p-1)!='<') {
  210.         if (*(p-1)!='-') *p++='-';
  211.         *p++='<';
  212.     }
  213.     t=p-b;
  214.     xalarm(5*t);
  215.     t=write(dn,b,t);
  216.     xalarm(0);
  217.     if (t<0) {
  218.         er=2; 
  219.         goto X;
  220.     }
  221.     /* close(dn) */
  222.     xalarm(40);        /* was 5; sometimes missed carrier */
  223.     dh = open(dev,2);
  224.     xalarm(0);
  225.     if (dh<0) {
  226.         er=(errno == 4? 3:6); 
  227.         goto X;
  228.     }
  229.     ioctl(TIOCGETP, ln, &stbuf);
  230.     stbuf.sg_flags &= ~ECHO;
  231.     xalarm(10);
  232.     ioctl(TIOCSETP, dh, &stbuf);
  233.     ioctl(TIOCHPCL, dh, (struct sgttyb *)NULL);
  234.     xalarm(0);
  235. X: 
  236.     if (er) close(dn);
  237.     if (fk!=(-1)) {
  238.         kill(fk, SIGKILL);
  239.         xalarm(10);
  240.         while ((t=wait((int *)NULL))!=(-1) && t!=fk);
  241.         xalarm(0);
  242.     }
  243.     return (er? -er:dh);
  244. }
  245.  
  246. /*
  247.  *    wr: write to remote: 0 -> line.
  248.  *    ~.    terminate
  249.  *    ~<file    send file
  250.  *    ~!    local login-style shell
  251.  *    ~!cmd    execute cmd locally
  252.  *    ~$proc    execute proc locally, send output to line
  253.  *    ~%cmd    execute builtin cmd (put and take)
  254.  */
  255.  
  256. wr()
  257. {
  258.     int ds,fk,lcl,x;
  259.     char *p,b[600];
  260.     for (;;) {
  261.         p=b;
  262.         while (rdc(0) == 1) {
  263.             if (p == b) lcl=(c == '~');
  264.             if (p == b+1 && b[0] == '~') lcl=(c!='~');
  265.             if (c == 0) c=0177;
  266.             if (!lcl) {
  267.                 if (wrc(ln) == 0) {
  268.                     prf("line gone"); return;
  269.                 }
  270.             }
  271.             if (lcl) {
  272.                 if (c == 0177) c=tkill;
  273.                 if (c == '\r' || c == '\n') goto A;
  274.                 if (!dout) wrc(0);
  275.             }
  276.             *p++=c;
  277.             if (c == terase) {
  278.                 p=p-2; 
  279.                 if (p<b) p=b;
  280.             }
  281.             if (c == tkill || c == 0177 || c == '\r' || c == '\n') p=b;
  282.         }
  283.         return;
  284. A: 
  285.         if (!dout) echo("");
  286.         *p=0;
  287.         switch (b[1]) {
  288.         case '.':
  289.         case '\004':
  290.             return;
  291.         case '!':
  292.         case '$':
  293.             fk = fork();
  294.             if (fk == 0) {
  295.                 close(1);
  296.                 dup(b[1] == '$'? ln:2);
  297.                 close(ln);
  298.                 mode(0);
  299.                 if (!nhup) signal(SIGINT, SIG_DFL);
  300.                 if (b[2] == 0) execl("/bin/sh","-",0);
  301.                 else execl("/bin/sh","sh","-c",b+2,0);
  302.                 prf("Can't execute shell");
  303.                 exit(~0);
  304.             }
  305.             if (fk!=(-1)) {
  306.                 while (wait(&x)!=fk);
  307.             }
  308.             mode(1);
  309.             if (b[1] == '!') echo("!");
  310.             else {
  311.                 if (dout) echo("$");
  312.             }
  313.             break;
  314.         case '<':
  315.             if (b[2] == 0) break;
  316.             if ((ds=open(b+2,0))<0) {
  317.                 prf("Can't divert %s",b+1); 
  318.                 break;
  319.             }
  320.             intr=x=0;
  321.             mode(2);
  322.             if (!nhup) signal(SIGINT, sig2);
  323.             while (!intr && rdc(ds) == 1) {
  324.                 if (wrc(ln) == 0) {
  325.                     x=1; 
  326.                     break;
  327.                 }
  328.             }
  329.             signal(SIGINT, SIG_IGN);
  330.             close(ds);
  331.             mode(1);
  332.             if (x) return;
  333.             if (dout) echo("<");
  334.             break;
  335.         case '%':
  336.             dopercen(&b[2]);
  337.             break;
  338.         default:
  339.             prf("Use `~~' to start line with `~'");
  340.         }
  341.         continue;
  342.     }
  343. }
  344.  
  345. dopercen(line)
  346. register char *line;
  347. {
  348.     char *args[10];
  349.     register narg, f;
  350.     int rcount;
  351.     for (narg = 0; narg < 10;) {
  352.         while(*line == ' ' || *line == '\t')
  353.             line++;
  354.         if (*line == '\0')
  355.             break;
  356.         args[narg++] = line;
  357.         while(*line != '\0' && *line != ' ' && *line != '\t')
  358.             line++;
  359.         if (*line == '\0')
  360.             break;
  361.         *line++ = '\0';
  362.     }
  363.     if (equal(args[0], "take")) {
  364.         if (narg < 2) {
  365.             prf("usage: ~%%take from [to]");
  366.             return;
  367.         }
  368.         if (narg < 3)
  369.             args[2] = args[1];
  370.         wrln("echo '~>:'");
  371.         wrln(args[2]);
  372.         wrln(";tee /dev/null <");
  373.         wrln(args[1]);
  374.         wrln(";echo '~>'\n");
  375.         return;
  376.     } else if (equal(args[0], "put")) {
  377.         if (narg < 2) {
  378.             prf("usage: ~%%put from [to]");
  379.             return;
  380.         }
  381.         if (narg < 3)
  382.             args[2] = args[1];
  383.         if ((f = open(args[1], 0)) < 0) {
  384.             prf("cannot open: %s", args[1]);
  385.             return;
  386.         }
  387.         wrln("stty -echo;cat >");
  388.         wrln(args[2]);
  389.         wrln(";stty echo\n");
  390.         xsleep(5);
  391.         intr = 0;
  392.         if (!nhup)
  393.             signal(SIGINT, sig2);
  394.         mode(2);
  395.         rcount = 0;
  396.         while(!intr && rdc(f) == 1) {
  397.             rcount++;
  398.             if (c == tkill || c == terase)
  399.                 wrln("\\");
  400.             if (wrc(ln) != 1) {
  401.                 xsleep(2);
  402.                 if (wrc(ln) != 1) {
  403.                     prf("character missed");
  404.                     intr = 1;
  405.                     break;
  406.                 }
  407.             }
  408.         }
  409.         signal(SIGINT, SIG_IGN);
  410.         close(f);
  411.         if (intr) {
  412.             wrln("\n");
  413.             prf("stopped after %d bytes", rcount);
  414.         }
  415.         wrln("\004");
  416.         xsleep(5);
  417.         mode(1);
  418.         return;
  419.     }
  420.     prf("~%%%s unknown\n", args[0]);
  421. }
  422.  
  423. equal(s1, s2)
  424. register char *s1, *s2;
  425. {
  426.     while (*s1++ == *s2)
  427.         if (*s2++ == '\0')
  428.             return(1);
  429.     return(0);
  430. }
  431.  
  432. wrln(s)
  433. register char *s;
  434. {
  435.     while (*s)
  436.         write(ln, s++, 1);
  437. }
  438.  
  439. /*
  440.  *    rd: read from remote: line -> 1
  441.  *    catch:
  442.  *    ~>[>][:][file]
  443.  *    stuff from file...
  444.  *    ~>    (ends diversion)
  445.  */
  446.  
  447. rd()
  448. {
  449.     int ds,slnt;
  450.     char *p,*q,b[600];
  451.     p=b;
  452.     ds=(-1);
  453.     while (rdc(ln) == 1) {
  454.         if (ds<0) slnt=0;
  455.         if (!slnt) wrc(1);
  456.         *p++=c;
  457.         if (c!='\n') continue;
  458.         q=p; 
  459.         p=b;
  460.         if (b[0]!='~' || b[1]!='>') {
  461.             if (*(q-2) == '\r') {
  462.                 q--; 
  463.                 *(q-1)=(*q);
  464.             }
  465.             if (ds>=0) write(ds,b,q-b);
  466.             continue;
  467.         }
  468.         if (ds>=0) close(ds);
  469.         if (slnt) {
  470.             write(1, b, q - b);
  471.             write(1, CRLF, sizeof(CRLF));
  472.         }
  473.         if (*(q-2) == '\r') q--;
  474.         *(q-1)=0;
  475.         slnt=0;
  476.         q=b+2;
  477.         if (*q == '>') q++;
  478.         if (*q == ':') {
  479.             slnt=1; 
  480.             q++;
  481.         }
  482.         if (*q == 0) {
  483.             ds=(-1); 
  484.             continue;
  485.         }
  486.         if (b[2]!='>' || (ds=open(q,1))<0) ds=creat(q,0644);
  487.         lseek(ds, (long)0, 2);
  488.         if (ds<0) prf("Can't divert %s",b+1);
  489.     }
  490. }
  491.  
  492. struct {char lobyte; char hibyte;};
  493. mode(f)
  494. {
  495.     struct sgttyb stbuf;
  496.     if (dout) return;
  497.     ioctl(TIOCGETP, 0, &stbuf);
  498.     tkill = stbuf.sg_kill;
  499.     terase = stbuf.sg_erase;
  500.     if (f == 0) {
  501.         stbuf.sg_flags &= ~RAW;
  502.         stbuf.sg_flags |= ECHO|CRMOD;
  503.     }
  504.     if (f == 1) {
  505.         stbuf.sg_flags |= RAW;
  506.         stbuf.sg_flags &= ECHO|CRMOD;
  507.     }
  508.     if (f == 2) {
  509.         stbuf.sg_flags &= ~RAW;
  510.         stbuf.sg_flags &= ~(ECHO|CRMOD);
  511.     }
  512.     ioctl(TIOCSETP, 0, &stbuf);
  513. }
  514.  
  515. echo(s)
  516. char *s;
  517. {
  518.     char *p;
  519.     for (p=s;*p;p++);
  520.     if (p>s) write(0,s,p-s);
  521.     write(0,CRLF, sizeof(CRLF));
  522. }
  523.  
  524. prf(f, s)
  525. char *f;
  526. char *s;
  527. {
  528.     fprintf(stderr, f, s);
  529.     fprintf(stderr, CRLF);
  530. }
  531.  
  532. exists(devname)
  533. char *devname;
  534. {
  535.     if (access(devname, 0)==0)
  536.         return(1);
  537.     prf("%s does not exist", devname);
  538.     return(0);
  539. }
  540.