home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume26 / xc-4.1 / part02 / xcport.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-13  |  11.4 KB  |  572 lines

  1. /*    xcport.c -- modem interface routines for XC
  2.     This file uses 4-character tabstops
  3. */
  4.  
  5. #include <stdio.h>
  6. #include <string.h>
  7. #include <sys/types.h>
  8. #include <fcntl.h>
  9. #include <signal.h>
  10. #include <termio.h>
  11. #include <sys/ioctl.h>
  12. #include <errno.h>
  13. #include "xc.h"
  14.  
  15. /* define this if you need to send SIGUSR1/SIGUSR2 to
  16.    handle an active getty process, or use ungetty.
  17. */
  18. /*#define GETTY_HANDLER /**/
  19.  
  20. # if DIDO == 2            /* SCO Xenix 2.2 uses ungetty */
  21. #    define UNGETTY "/usr/lib/uucp/ungetty"
  22. #    define UG_NOTENAB    0
  23. #    define UG_ENAB        1
  24. #    define UG_FAIL        2
  25. #    define LOCKDIR "/usr/spool/uucp"
  26. #    define SIZEOFLOCKFILE sizeof(short)
  27.     static    int    code, retcode, errflag;
  28. #    ifndef GETTY_HANDLER
  29. #        define GETTY_HANDLER
  30. #    endif
  31. # endif /*DIDO==2*/
  32.  
  33. # if DIDO == 3            /* SCO Xenix 2.3, SCO Unix */
  34. #    include <utmp.h>
  35. #    define LOCKDIR "/usr/spool/uucp"
  36. #    ifndef ASCII_PID
  37. #     define ASCII_PID
  38. #     define PIDSIZE 10
  39. #    endif
  40.     static pid_t gettypid = -1;
  41. # endif /*DIDO==3*/
  42.  
  43. # if DIDO == 4            /* System V Release 4 */
  44. #    include <utmp.h>
  45. #    include <sys/stat.h>
  46. #    include <sys/mkdev.h>
  47. #    define LOCKDIR "/var/spool/locks"
  48. #    ifndef ASCII_PID
  49. #     define ASCII_PID
  50. #     define PIDSIZE 10
  51. #    endif
  52.     static pid_t gettypid = -1;
  53. # endif /*DIDO==4*/
  54.  
  55. #ifndef SIZEOFLOCKFILE
  56. #define SIZEOFLOCKFILE sizeof(int)
  57. #endif
  58.  
  59. static pid_t pid;
  60. int cbaud = B2400;            /* default bps */
  61. short flowflag;                /* modem port i/o data mask */
  62. static int mfd = -1;        /* modem port file descriptor */
  63. static struct termio pmode;    /* modem device control string */
  64. static char port[SM_BUFF],    /* modem port device file string */
  65.         lckname[SM_BUFF];    /* lockfile string */
  66. unsigned mrate ();
  67. char protocol[] = "8N1";    /* default modem protocol */
  68. extern int errno;
  69.  
  70. struct {
  71.     char *proto;
  72.     int  clear;
  73.     int  set;
  74. } prot_tbl[] = {
  75.     "8N1",        ~(CSIZE | PARENB | CSTOPB),    CS8,
  76.     "7E2",        ~(CSIZE | PARODD),            CS7 | PARENB | CSTOPB,
  77.     "7O2",        ~CSIZE,                        CS7 | PARENB | PARODD | CSTOPB,
  78.     NIL(char),    0,                            0
  79. };
  80.  
  81. struct {
  82.     char     *bps;
  83.     unsigned rate;
  84.     int         cbaud;
  85. } bps_tbl[] = {
  86.     "300",    300,    B300,
  87.     "600",    600,    B600,
  88.     "1200",    1200,    B1200,
  89.     "2400",    2400,    B2400,
  90.     "4800",    4800,    B4800,
  91.     "9600",    9600,    B9600,
  92. #ifdef B19200
  93.     "19200",19200,    B19200,
  94. #endif
  95. #ifdef B38400
  96.     "38400",38400,    B38400,
  97.     "57600",57600,    B50,
  98. #endif
  99.     "0",    0,        B0
  100. };
  101.  
  102. void
  103. xc_setflow(flow)
  104. short flow;
  105. {
  106.     if (flow)
  107.         pmode.c_iflag |= IXON | IXOFF | IXANY;
  108.     else
  109.         pmode.c_iflag &= ~(IXON | IXOFF | IXANY);
  110.  
  111.     ioctl(mfd, TCSETAF, &pmode);
  112. }
  113.  
  114. /* get/set character size and parity on the port */
  115. char *
  116. xc_setproto(p)
  117. char *p;
  118. {
  119.     register i;
  120.  
  121.     if (!p)
  122.         return protocol;
  123.  
  124.     for (i=0; prot_tbl[i].proto; i++){
  125.         if (!strcmp(p,prot_tbl[i].proto)){
  126.             pmode.c_cflag &= prot_tbl[i].clear;
  127.             pmode.c_cflag |= prot_tbl[i].set;
  128.             ioctl(mfd, TCSETAF, &pmode);
  129.             strcpy(protocol,p);
  130.             return protocol;
  131.         }
  132.     }
  133.     return NIL(char);
  134. }
  135.  
  136. /* get/set port string */
  137. char *
  138. mport(s)
  139. char *s;
  140. {
  141.     if (s && mfd == -1)
  142.         if (strncmp("/dev/", s, 5))
  143.             strcpy(port, "/dev/"),
  144.             strcat(port, s);
  145.         else
  146.             strcpy(port, s);
  147.  
  148.     return(port);
  149. }
  150.  
  151. /*    Get/set the bps of the modem port; set the terminal rate to correspond. */
  152. unsigned
  153. mrate(s)
  154. char *s;
  155. {
  156.     register i;
  157.  
  158.     if (s){
  159.         for (i=0; bps_tbl[i].cbaud; i++){
  160.             if (!strcmp(s,bps_tbl[i].bps)){
  161.                 cbaud = bps_tbl[i].cbaud;
  162.                 pmode.c_cflag &= ~CBAUD;
  163.                 pmode.c_cflag |= cbaud;
  164.                 ioctl(mfd, TCSETAF, &pmode);
  165.                 return (bps_tbl[i].rate);
  166.             }
  167.         }
  168.         return FAILURE;
  169.     }
  170.  
  171.     for (i=0; bps_tbl[i].cbaud; i++)
  172.         if ((pmode.c_cflag & CBAUD) == bps_tbl[i].cbaud)
  173.             return (bps_tbl[i].rate);
  174.         
  175.     return FAILURE;
  176. }
  177.  
  178. /*    The following routine is used to hang up the modem. This is accomplished
  179.     by setting bps to 0. According to my documentation on termio, setting bps
  180.     to zero will result in DTR not being asserted. This hangs up some (most?)
  181.     modems. If not, the second part of the routine sends the Hayes modem
  182.     "escape" and then a hangup command.
  183. */
  184. hangup()
  185. {
  186.     S1("<< HANGUP >>");
  187.  
  188. #if DTR_DROPS_CARRIER
  189.     pmode.c_cflag &= ~CBAUD;
  190.     pmode.c_cflag |= B0;        /* set cbaud 0 (drop DTR) */
  191.     ioctl(mfd, TCSETAF, &pmode);
  192.  
  193.     sleep(1);                    /* wait a second */
  194.  
  195.     pmode.c_cflag &= ~CBAUD;    /* reset bps */
  196.     pmode.c_cflag |= cbaud;
  197.     ioctl(mfd, TCSETAF, &pmode);
  198. #else /* use Hayes command */
  199.     sleep(2);                    /* Allow for "escape guard time" */
  200.     send_string(ATTEN);            /* Send modem escape command */
  201.     sleep(3);                    /* More "escape guard time" */
  202.     send_string(HANGUP);        /* Send hangup command */
  203. #endif
  204.     return SUCCESS;
  205. }
  206.  
  207. #ifdef GETTY_HANDLER
  208. # if DIDO >= 2
  209. /*    suspend() sends signal to a running getty
  210.              sets:    gettypid, process number of running getty, if DIDO > 2
  211.                     retcode, exit value of 'ungetty', if DIDO = 2
  212.     restart(): restarts getty if it had been running before
  213. */
  214. #  if DIDO >= 3
  215. static void
  216. suspend()
  217. {
  218.     struct    utmp *t, *getutent();
  219.     char buf[12];
  220.     void endutent();
  221.  
  222.     strcpy(buf, strrchr(port, '/') +1);
  223.     while ((t = getutent())){
  224.         if (t->ut_type == LOGIN_PROCESS && (!strcmp(buf, t->ut_line))){
  225.             gettypid = t->ut_pid;    /* get getty PID */
  226.             if (kill(gettypid, SIGUSR1) == -1 && errno != EPERM)
  227.                 S1("Can't signal getty");
  228.         }
  229.     }
  230.     endutent();
  231. }
  232.  
  233. static void
  234. restart()
  235. {
  236.     if (gettypid != -1)
  237.         kill(gettypid, SIGUSR2);
  238. }
  239. #  endif /*DIDO>=3*/
  240. #  if DIDO == 2
  241. static void
  242. suspend()
  243. {
  244.     code=errflag=pid=retcode=0;
  245.     if ((pid = fork()) == 0){
  246.         execl(UNGETTY, "ungetty", port, NIL(char));
  247.         S1("ungetty exec error");
  248.         exit(8);
  249.         }
  250.     while (((code = wait(&errflag)) != pid) && code != -1);
  251.     switch ((errflag>>8) & 0xff){
  252.     case UG_NOTENAB:    /* line acquired: not enabled */
  253.         retcode = UG_NOTENAB;
  254.         break;
  255.     case UG_ENAB:    /* line acquired: need ungetty -r when done */
  256.         retcode = UG_ENAB;
  257.         break;
  258.     case UG_FAIL:        /* could not acquire line */
  259.     case 255:
  260.         exit(8);
  261.     }
  262. }
  263.  
  264. static void
  265. restart()
  266. {
  267.     code=errflag=pid=0;
  268.     if(retcode == UG_ENAB){
  269.         if ((pid = fork()) == 0){
  270.             execl(UNGETTY, "ungetty", "-r", port, NIL(char));
  271.             exit(8);
  272.         }
  273.     while (((code = wait(&errflag)) != pid) && code != -1)
  274.         ;
  275.     }
  276. }
  277. #  endif /*DIDO==2*/
  278. # endif /*DIDO>=2*/
  279. #endif /*GETTY_HANDLER*/
  280.  
  281. /*    Attach standard input and output to the modem port. This only gets called
  282.     after a fork by the child process, which then exec's a program that uses
  283.     standard i/o for some data transfer protocol. (To put this here is actually
  284.     a kludge, but I wanted to keep the modem-specific stuff in a black box.)
  285. */
  286. void
  287. mattach()
  288. {
  289.     dup2(mfd, 0);    /* close local stdin and connect to port */
  290.     dup2(mfd, 1);    /* close local stdout and connect to port */
  291.  
  292.     close(mfd);        /* close the old port descriptor */
  293. }
  294.  
  295. static void
  296. alrm(junk)
  297. int junk;
  298. { /* do nothing */
  299. }
  300.  
  301. /*    Get a byte from the modem port within 'seconds' or return -1.
  302.     All data read from the modem are input through this routine.
  303. */
  304. readbyte(seconds)
  305. unsigned seconds;
  306. {
  307.     static int count = 0;
  308.     static char *p, rxbuf[SM_BUFF];
  309.     unsigned alarm();
  310.  
  311.     if (count > 0){
  312.         count--;
  313.         return(*p++ & 0xff);
  314.     }
  315.     if (seconds){
  316.         signal(SIGALRM, alrm);
  317.         alarm(seconds);
  318.     }
  319.     if ((count = read(mfd, p = rxbuf, SM_BUFF)) < 1)
  320.         return(-1);
  321.     if (seconds)
  322.         alarm(0);
  323.  
  324.     count--;
  325.     return(*p++ & 0xff);
  326. }
  327.  
  328. /*    Output a byte to the modem port.
  329.     All data sent to the modem are output through this routine.
  330. */
  331. void
  332. sendbyte(ch)
  333. int ch;
  334. {
  335.     char c = ch & 0xff;
  336.  
  337.     if(write(mfd, &c, 1)<0)
  338.         S1("sendbyte: write error!");
  339. }
  340.  
  341. void
  342. send_string(s)
  343. char *s;
  344. {
  345.     while (*s){
  346.         sendbyte(*s++);
  347.         /* msecs(35);         /* season to taste ... */
  348.     }
  349. }
  350.  
  351. /* send a modem break */
  352. xmitbrk()
  353. {
  354.     S1("<< BREAK >>");
  355.     ioctl(mfd, TCSBRK, 0);
  356.     return SUCCESS;
  357. }
  358.  
  359. /*    lock_tty() returns FAILURE if the lock file exists (and XC will not run).
  360.  
  361.     unlock_tty() deletes the lock file.
  362.  
  363.     SCOXENIX 2.3 mods: Steve Manes
  364.     Check for active LCK file and try to delete it
  365.  
  366.     SCOXENIX 2.2 mods: Jean-Pierre Radley
  367.     As above, using 'ungetty'
  368.  
  369.     Tandy 6000 mods: Fred Buck
  370.       SVR4 mods: Larry Rosenman
  371. */
  372.  
  373. static
  374. lock_tty()
  375. {
  376. #if DIDO >= 2
  377.     int lckfd;
  378.     char *s, buf[12];
  379. #ifdef ASCII_PID
  380.     static char apid[PIDSIZE+2] = { '\0' };
  381. #else
  382.     pid = -1;
  383. #endif
  384.  
  385.     strcpy(buf, strrchr(port, '/') +1);
  386.     s = buf + strlen(buf) - 1;
  387.  
  388. #if DIDO == 2
  389.     *s = toupper(*s);
  390. #endif
  391. #if DIDO >= 3
  392.     *s = tolower(*s);
  393. #endif
  394.  
  395. #if DIDO == 4
  396.     struct stat stat_buf;
  397.     if(stat(port,&stat_buf)==0){
  398.         sprintf(lckname,"%s/LK.%03d.%03d.%03d",LOCKDIR,
  399.             major(stat_buf.st_dev),
  400.             major(stat_buf.st_rdev),
  401.             minor(stat_buf.st_rdev));
  402.     }
  403. #else
  404.     sprintf(lckname, "%s/LCK..%s", LOCKDIR, buf);
  405. #endif  /*DIDO==4*/
  406.  
  407.     if (!checkLCK())    /* check LCK file */
  408.         return FAILURE;    /* can't unlock it */
  409.  
  410.     if ((lckfd = creat(lckname, 0666)) < 0){
  411.         sprintf(Msg,"Can't create '%s'", lckname);
  412.         S;
  413.         return FAILURE;
  414.     }
  415.  
  416. #ifdef ASCII_PID
  417.     sprintf(apid, "%*d\n", PIDSIZE, getpid());
  418.     write(lckfd, apid, PIDSIZE+1);
  419. #else
  420.     pid = getpid();
  421.     write(lckfd, (char *)&pid, SIZEOFLOCKFILE);
  422. #endif
  423.  
  424.     close(lckfd);
  425. #endif /*DIDO*/
  426.     return SUCCESS;
  427. }
  428.  
  429. void
  430. unlock_tty()
  431. {
  432.     static char byettyxx[50], *byeptr;
  433.     extern char *ttyname();
  434.  
  435.     sprintf(byettyxx,"BYE%s", strrchr(ttyname(mfd),'/')+1);
  436.     byeptr = getenv(byettyxx);
  437.     if (byeptr && *byeptr)
  438.         S1("Sending BYE string to modem"),
  439.         send_string("\r"),
  440.         send_string(byeptr),
  441.         send_string("\r");
  442.  
  443.     pmode.c_cflag &= ~CLOCAL;
  444.     pmode.c_cflag |= B0 | HUPCL;
  445.     ioctl(mfd, TCSETAF, &pmode);
  446.     close(mfd);
  447.  
  448. #if DIDO >= 2
  449.     setuid(geteuid());
  450.     setgid(getegid());
  451.     unlink(lckname);
  452. # ifdef GETTY_HANDLER
  453.     restart();
  454. # endif
  455. #endif
  456.     S1("Exiting XC");
  457. }
  458.  
  459. /*    check to see if lock file exists and is still active.
  460.     kill(pid, 0) only works on ATTSV, some BSDs and Xenix
  461.     returns: SUCCESS, or
  462.             FAILURE if lock file active
  463.     added: Steve Manes 7/29/88
  464. */
  465. checkLCK()
  466. {
  467.     int rc, fd;
  468. #ifdef ASCII_PID
  469.     char alckpid[PIDSIZE+2];
  470. #endif
  471. #if DIDO == 2
  472.     short lckpid = -1;
  473. #else
  474.     pid_t lckpid = -1;
  475. #endif
  476.  
  477.     if ((fd = open(lckname, O_RDONLY)) == -1){
  478.         if (errno == ENOENT)
  479.             return SUCCESS;    /* lock file doesn't exist */
  480.         goto unlock;
  481.     }
  482. #ifdef ASCII_PID
  483.     rc = read(fd, (char *)alckpid, PIDSIZE+1);
  484.     close(fd);
  485.     lckpid = atoi(alckpid);
  486.     if (rc != 11)
  487. #else
  488.     rc = read(fd, (char *)&lckpid, SIZEOFLOCKFILE);
  489.     close(fd);
  490.     if (rc != SIZEOFLOCKFILE)
  491. #endif
  492.     {
  493.         S1("Lock file has bad format");
  494.         goto unlock;
  495.     }
  496.  
  497.     /* now, send a bogus 'kill' and check the results */
  498.     if (kill(lckpid, 0) == 0 || errno == EPERM){
  499.         sprintf(Msg,"Lock file process %d on %s is still active - try later",
  500.             lckpid, port);
  501.         S;
  502.         return FAILURE;
  503.     }
  504.  
  505. unlock:
  506.     if (unlink(lckname) != 0){
  507.         sprintf(Msg,"Can't unlink %s file", lckname);
  508.         S;
  509.         return FAILURE;
  510.     }
  511.     return SUCCESS;
  512. }
  513.  
  514. /*    Opens the modem port and configures it. If the port string is
  515.     already defined it will use that as the modem port; otherwise it
  516.     gets the environment variable MODEM. Returns SUCCESS or FAILURE.
  517. */
  518. mopen()
  519. {
  520.     int c;
  521.     char *p;
  522.  
  523.     if (port[0] == '\0'){
  524.         if (!(p = getenv("MODEM"))){
  525.             S1("Exiting: no modem port specified or present in environment");
  526.             exit(3);
  527.         }
  528.         mport(p);
  529.     }
  530.     if (!lock_tty())
  531.         exit(4);
  532.  
  533. #if DIDO
  534.     p = port +strlen(port) -1;
  535.     *p = toupper(*p);
  536. # ifdef GETTY_HANDLER
  537.     suspend();
  538. # endif
  539. #endif
  540.  
  541.     if ((mfd = open(port, O_RDWR | O_NDELAY)) < 0){
  542.         sprintf(Msg,"Can't open modem port %s",port);
  543.         S;
  544.         exit(5);
  545.     }
  546.  
  547.     ioctl(mfd, TCGETA, &pmode);
  548.  
  549.     pmode.c_cflag &= ~(CBAUD | HUPCL);
  550.     pmode.c_cflag |= CLOCAL | cbaud;
  551. #if DIDO >= 3 & defined(CTSFLOW) & defined(RTSFLOW)
  552.     pmode.c_cflag |= CTSFLOW | RTSFLOW ;
  553.     /* pmode.c_cflag |= CRTSFL ; */
  554. #endif
  555.     pmode.c_iflag = IGNBRK ;
  556.     pmode.c_oflag = pmode.c_lflag = 0;
  557.     pmode.c_cc[VMIN] = 1;     /* This many chars satisfies reads */
  558.     pmode.c_cc[VTIME] = 0;    /* or in this many tenths of seconds */
  559.  
  560.     xc_setflow(flowflag);
  561.  
  562.     c = mfd;
  563.     if ((mfd = open(port, O_RDWR)) < 0){    /* Reopen line with CLOCAL */
  564.         sprintf(Msg,"Can't re-open modem port %s",port);
  565.         S;
  566.         return FAILURE;
  567.     }
  568.     close(c);
  569.  
  570.     return SUCCESS;
  571. }
  572.