home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume16 / pcomm2 / part05 / port.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-09-14  |  9.2 KB  |  395 lines

  1. /*
  2.  * Routines to get or release a TTY port.
  3.  */
  4.  
  5. #define MAX_PID 30000
  6.  
  7. #include <stdio.h>
  8. #include <fcntl.h>
  9. #include <termio.h>
  10. #include <errno.h>
  11. #include "config.h"
  12. #ifdef UNIXPC
  13. #include <sys/phone.h>
  14. #endif /* UNIXPC */
  15. #include "dial_dir.h"
  16. #include "modem.h"
  17.  
  18. static int getty_status;
  19. static char *lock_path = NULL;
  20. /*
  21.  * Finds a free (or requested) serial port.  Creates a lock file to hold
  22.  * for our use.  Loads the modem database.  A return code of 1 means
  23.  * all ports (or the requested port) are busy.
  24.  */
  25.  
  26. int
  27. get_port()
  28. {
  29.     extern int fd;
  30.     register int i;
  31.     int j, k, lfd, list[NUM_TTY], cmask, tbaud;
  32.     char file[80], buf[80], message[80], *strdup();
  33.     unsigned int sleep();
  34.     void error_win(), line_set(), release_port(), send_str();
  35.     void free_ptr();
  36. #ifndef ASCII_PID
  37.     int progpid;
  38. #endif /* ASCII_PID */
  39.  
  40.     /*
  41.      * If we already have a port, see if it is good enough for the
  42.      * current request.
  43.      */
  44. #ifdef KEEP_PORT
  45.     if (fd != -1) {
  46.         if (!strcmp(dir->index[dir->d_cur], modem->tty[modem->t_cur]) ||
  47.          ck_speed(modem->t_cur, dir->baud[dir->d_cur])) {
  48.             /*
  49.              * Reset the line because the baud rate (or other
  50.              * parameters) may have changed.
  51.              */
  52.             line_set();
  53.             return(0);
  54.         }
  55.     }
  56. #endif /* KEEP_PORT */
  57.     release_port(1);
  58.  
  59.     list[0] = -1;
  60.     /*
  61.      * See if you want a specific TTY port.  If the index field in the
  62.      * dialing directory is a valid device name, then use that TTY.
  63.      */
  64.     if (*dir->index[dir->d_cur] != NULL) {
  65.         sprintf(buf, "/dev/%s", dir->index[dir->d_cur]);
  66.                     /* if index is a valid device */
  67.         if (!access(buf, 0)) {
  68.             for (i=0; i<modem->t_entries; i++) {
  69.                     /* and it exists in modem database */
  70.                 if (!strcmp(dir->index[dir->d_cur], modem->tty[i])) {
  71.                     list[0] = i;
  72.                     list[1] = -1;
  73.                     break;
  74.                 }
  75.             }
  76.         }
  77.     }
  78.  
  79.     /*
  80.      * Create a list of acceptable TTYs.  It searches the modem database
  81.      * for the requested baud rate.
  82.      */
  83.     k = 0;
  84.     if (list[0] == -1) {
  85.         for (i=0; i<modem->t_entries; i++) {
  86.                     /* skip ports with no modems */
  87.             if (!strcmp(modem->tname[i], "DIRECT"))
  88.                 continue;
  89.  
  90.                     /* can handle requested baud rate? */
  91.             if (ck_speed(i, dir->baud[dir->d_cur]))
  92.                 list[k++] = i;
  93.         }
  94.                     /* the end of list marker */
  95.         list[k] = -1;
  96.     }
  97.                     /* empty list? */
  98.     if (list[0] == -1) {
  99.         sprintf(message, "No modem at a %d baud rating exists in the", dir->baud[dir->d_cur]);
  100.         sprintf(buf, "modem database '%s'", modem->m_path);
  101.         error_win(0, message, buf);
  102.         return(1);
  103.     }
  104.                     /* check the list for a free port */
  105.     i = 0;
  106.     while (list[i] != -1) {
  107.                     /* create a lock file name */
  108.         sprintf(file, "%s/LCK..%s", LOCK_DIR, modem->tty[list[i]]);
  109. #ifdef DEBUG
  110.         fprintf(stderr, "get_port: checking '/dev/%s'\n", modem->tty[list[i]]);
  111. #endif /* DEBUG */
  112.  
  113.                     /* does it exist or is it dead? */
  114.         if (checklock(file)) {
  115.             getty_status = set_getty(modem->tty[list[i]], 0);
  116.  
  117.             cmask = umask(0);
  118.             if ((lfd = open(file, O_CREAT|O_EXCL|O_WRONLY, 0666)) < 0) {
  119.                 if (getty_status)
  120.                     set_getty(modem->tty[list[i]], 1);
  121.                 sprintf(buf, "'%s'", file);
  122.                 error_win(1, "Can't create the lockfile", buf);
  123.             }
  124.             umask(cmask);
  125. #ifdef ASCII_PID
  126.             sprintf(buf, "%10d\n", getpid());
  127.             write(lfd, buf, 11);
  128. #else /* ASCII_PID */
  129.             progpid = getpid();
  130.             write(lfd, (char *) &progpid, sizeof(int));
  131. #endif /* ASCII_PID */
  132.             close(lfd);
  133.                     /* store the new values */
  134.             free_ptr(lock_path);
  135.             lock_path = strdup(file);
  136.             modem->t_cur = list[i];
  137.  
  138.                     /* open the device (ignore DCD) */
  139.             sprintf(buf, "/dev/%s", modem->tty[modem->t_cur]);
  140.             if ((fd = open(buf, O_RDWR|O_NDELAY)) < 0) {
  141.                 if (getty_status)
  142.                     set_getty(modem->tty[modem->t_cur], 1);
  143.                 sprintf(file, "Can't open port '%s' for read and write", buf);
  144.                 error_win(1, file, "");
  145.             }
  146.                     /* turn off the "no delay" mode */
  147.             fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NDELAY);
  148.                     /* change line settings */
  149.             line_set();
  150.                     /* load the modem data base */
  151.             modem->m_cur = -1;
  152.             for (j=0; j<modem->m_entries; j++) {
  153.                 if (!strcmp(modem->tname[modem->t_cur], modem->mname[j])) {
  154.                     modem->m_cur = j;
  155.                     break;
  156.                 }
  157.             }
  158.             if (modem->m_cur == -1) {
  159.                 sprintf(buf, "Modem name '%s' in TTY database",
  160.                  modem->tname[modem->t_cur]);
  161.                 error_win(1, buf, "does not exist in modem database");
  162.             }
  163.                     /* initialize the modem */
  164.             if (modem->init_sp[modem->t_cur]) {
  165.                 tbaud = dir->baud[dir->d_cur];
  166.                 dir->baud[dir->d_cur] = modem->init_sp[modem->t_cur];
  167.                 line_set();
  168.                 send_str(modem->init[modem->m_cur]);
  169.                 dir->baud[dir->d_cur] = tbaud;
  170.             }
  171.             else
  172.                 send_str(modem->init[modem->m_cur]);
  173.             sleep(1);
  174.             return(0);
  175.         }
  176.         i++;
  177.     }
  178.     error_win(0, "All ports are busy now, try again later", "");
  179.     return(1);
  180. }
  181.  
  182. /*
  183.  * Release the port.  Closes the file descriptor and removes the
  184.  * lock file
  185.  */
  186.  
  187. void
  188. release_port(verbose)
  189. int verbose;
  190. {
  191.     extern int fd;
  192.     extern char *null_ptr;
  193.     char buf[80];
  194.     void free_ptr(), hang_up();
  195.  
  196.     /*
  197.      * The modem structure can't be guaranteed to exist yet.  For example,
  198.      * an error in reading one of the other support files would cause
  199.      * this routine to be used before the MODEM structure gets allocated.
  200.      */
  201.     if (modem == NULL)
  202.         return;
  203.                     /* close the port */
  204.     if (fd != -1) {
  205.         ioctl(fd, TCFLSH, 2);
  206.         /*
  207.          * Since HUPCL is set, the close() should drop the DTR and
  208.          * hang up the modem (provided you've got the modem to
  209.          * respond to DTR).  Since this is not guaranteed, we send
  210.          * the hang_up string first.
  211.          */
  212.         hang_up(verbose);
  213.         close(fd);
  214.     }
  215.                     /* remove the lock */
  216.     if (*lock_path != NULL && lock_path != NULL) {
  217.         if (unlink(lock_path)) {
  218.             sprintf(buf, "'%s'", lock_path);
  219.             error_win(0, "Can't remove the lock file", buf);
  220.         }
  221.         free_ptr(lock_path);
  222.         lock_path = null_ptr;
  223.     }
  224.                     /* turn the getty back on? */
  225.     if (getty_status)
  226.         set_getty(modem->tty[modem->t_cur], 1);
  227.                     /* clean up the structure */
  228.     fd = -1;
  229.     modem->m_cur = -1;
  230.     modem->t_cur = -1;
  231.     return;
  232. }
  233.  
  234. /*
  235.  * Turn the /etc/getty on or off for the specified port.  A return code
  236.  * of 1 means that the getty was on.  Systems with uugetty() or dedicated
  237.  * dialout ports won't need this routine.
  238.  */
  239.  
  240. /*ARGSUSED*/
  241. static int
  242. set_getty(tty, on)
  243. char *tty;
  244. int on;
  245. {
  246. #ifdef UNIXPC
  247.     int i, ret_code;
  248.     char buf[40];
  249.     unsigned int sleep();
  250.                     /* the last three characters */
  251.     i = strlen(tty) -3;
  252.  
  253.     ret_code = 0;
  254.     if (on) {
  255.         sprintf(buf, "setgetty %s 1", tty+i);
  256.         system(buf);
  257.     }
  258.     else {
  259.         sprintf(buf, "setgetty %s 0", tty+i);
  260.         if (system(buf) == 512)
  261.             ret_code++;
  262.         sleep(1);
  263.     }
  264.     return(ret_code);
  265. #else /* UNIXPC */
  266.     /*
  267.      * If you don't have one of these cute little routines, you
  268.      * might wanna write one.  It should check for an existing lock
  269.      * file, edit the /etc/inittab file, and issue an init -q.
  270.      * The return code should tell if there was a getty or not.
  271.      * Obviously the program would be suid to root.
  272.      */
  273.     return(0);
  274. #endif /* UNIXPC */
  275. }
  276.  
  277. /*
  278.  * Check the lock file for a valid pid value.  Error conditions such
  279.  * as not being able to open the lock file or not being able to interpret
  280.  * the contents of the lock file cause the code to assume that the lock
  281.  * file is valid.  Let the user worry about weird special cases.  A return
  282.  * code of 1 means the lock is dead or doesn't exist.
  283.  */
  284.  
  285. static int
  286. checklock(lockfile)
  287. char *lockfile;
  288. {
  289.     extern int errno;
  290.     int lfd, lckpid;
  291. #ifdef ASCII_PID
  292.     int n;
  293.     char buf[40];
  294. #endif /* ASCII_PID */
  295.                     /* doesn't exist */
  296.     if (access(lockfile, 0))
  297.         return(1);
  298.                     /* can't open the lock file */
  299.     if ((lfd = open(lockfile, 0)) < 0)
  300.         return(0);
  301.  
  302. #ifdef ASCII_PID
  303.     if ((n = read(lfd, buf, 40)) <= 0) {
  304.         close(lfd);
  305.         return(0);
  306.     }
  307.     close(lfd);
  308.     buf[n--] = '\0';
  309.     lckpid = atoi(buf);
  310. #else /* ASCII_PID */
  311.     if (read(lfd, (char *) &lckpid, sizeof(int)) != sizeof(int)) {
  312.         close(lfd);
  313.         return(0);
  314.     }
  315.     close(lfd);
  316. #endif /* ASCII_PID */
  317.                     /* invalid pid? */
  318.     if (lckpid <= 0 || lckpid > MAX_PID)
  319.         return(0);
  320.  
  321.     if ((kill(lckpid, 0) == -1) && (errno == ESRCH)) {
  322.         /*
  323.          * If the kill was unsuccessful due to an ESRCH error,
  324.          * that means the process is no longer active and the
  325.          * lock file can be safely removed.
  326.          */
  327.         unlink(lockfile);
  328.         sleep(1);
  329.         return(1);
  330.     }
  331.     /*
  332.      * If the kill() was successful, that means the process must
  333.      * still active.
  334.      */
  335.     return(0);
  336. }
  337.  
  338. /*
  339.  * Check to see if the desired baud rate can be handled by the modem.
  340.  * Uses the connect strings to make this determination.  The first
  341.  * argument is the index into the TTY database.  A return code of 1
  342.  * means yes.
  343.  */
  344.  
  345. static int
  346. ck_speed(tty, baud)
  347. int tty, baud;
  348. {
  349.     int i, mod;
  350.     char buf[60];
  351.                     /* find the modem database */
  352.     mod = -1;
  353.     for (i=0; i<modem->m_entries; i++) {
  354.         if (!strcmp(modem->mname[i], modem->tname[tty])) {
  355.             mod = i;
  356.             break;
  357.         }
  358.     }
  359.     if (mod == -1) {
  360.         sprintf(buf, "Modem name '%s' in TTY database", modem->tname[tty]);
  361.         error_win(1, buf, "does not exist in modem database");
  362.     }
  363. #ifdef DEBUG
  364.     fprintf(stderr, "ck_speed: checking modem '%s' for %d buad\n", modem->mname[mod], baud);
  365. #endif /* DEBUG */
  366.  
  367.     switch (baud) {
  368.         case 300:
  369.             if (*modem->con_3[mod] != NULL)
  370.                 return(1);
  371.             break;
  372.         case 1200:
  373.             if (*modem->con_12[mod] != NULL)
  374.                 return(1);
  375.             break;
  376.         case 2400:
  377.             if (*modem->con_24[mod] != NULL)
  378.                 return(1);
  379.             break;
  380.         case 4800:
  381.             if (*modem->con_48[mod] != NULL)
  382.                 return(1);
  383.             break;
  384.         case 9600:
  385.             if (*modem->con_96[mod] != NULL)
  386.                 return(1);
  387.             break;
  388.         case 19200:
  389.             if (*modem->con_192[mod] != NULL)
  390.                 return(1);
  391.             break;
  392.     }
  393.     return(0);
  394. }
  395.