home *** CD-ROM | disk | FTP | other *** search
/ Carousel Volume 2 #1 / carousel.iso / mactosh / unix / uw_term.sha / openpty.c < prev    next >
C/C++ Source or Header  |  1985-11-12  |  4KB  |  152 lines

  1. /*
  2.  *    openpty - open a pseudo-terminal
  3.  *
  4.  * The first time that the routine is called, the device directory is
  5.  * searched and a list of all candidate pseudo-terminals is compiled.
  6.  * Candidates are defined to be those entries in "/dev" whose names
  7.  * (1) are the same length as PTY_PROTO and (2) start with the
  8.  * initial string PTY_PREFIX.  Further, the master and slave sides
  9.  * must both exist.
  10.  *
  11.  * openpty() attempts to find an unused pseudo-terminal from the list
  12.  * of candidates.  If one is found, the master and slave sides are
  13.  * opened and the file descriptors and names of these two devices are
  14.  * returned in a "ptydesc" structure.  (The address of this structure
  15.  * is supplied by the caller.  Zero is returned if openpty() was
  16.  * successful, -1 is returned if no pty could be found.
  17.  */
  18.  
  19. #include <sys/types.h>
  20. #include <sys/dir.h>
  21. #include <fcntl.h>
  22. #include <strings.h>
  23. #include "openpty.h"
  24.  
  25. #define    DEV_DIR        "/dev"        /* directory where devices live */
  26. #define    PT_INDEX    (sizeof DEV_DIR)    /* location of 'p' in "pty" */
  27.  
  28. #define    PTY_PROTO    "ptyp0"        /* prototype for pty names */
  29. #define    PTY_PREFIX    "pty"        /* prefix required for name of pty */
  30.  
  31. struct ptyinfo {
  32.     struct ptyinfo    *pi_next;
  33.     char        *pi_pty;
  34.     char        *pi_tty;
  35. };
  36.  
  37. static struct ptyinfo *ptylist;
  38.  
  39. extern char *malloc();
  40.  
  41. static
  42. char *
  43. devname(name)
  44. char *name;
  45. {
  46.     register char *fullname;
  47.  
  48.     /*
  49.      * Construct the full name of a device in DEV_DIR.  Returns
  50.      * NULL if it failed (because malloc() failed).
  51.      */
  52.  
  53.     fullname = malloc((unsigned)(sizeof DEV_DIR + 1 + strlen(name)));
  54.     if (fullname != NULL) {
  55.         (void)strcpy(fullname, DEV_DIR);
  56.         (void)strcat(fullname, "/");
  57.         (void)strcat(fullname, name);
  58.     }
  59.     return(fullname);
  60. }
  61.  
  62. static
  63. isapty(dp)
  64. struct direct *dp;
  65. {
  66.     static struct ptyinfo *pi;
  67.  
  68.     /*
  69.      * We don't care about the gory details of the directory entry.
  70.      * Instead, what we really want is an array of pointers to
  71.      * device names (with DEV_DIR prepended).  Therefore, we create
  72.      * this array ourselves and tell scandir() to ignore every
  73.      * directory entry.
  74.      *
  75.      * If malloc() fails, the current directory entry is ignored.
  76.      */
  77.  
  78.     if (pi == NULL &&
  79.         (pi = (struct ptyinfo *)malloc((unsigned)sizeof *pi)) == NULL)
  80.         return(0);
  81.         
  82.     if (strlen(dp->d_name) == sizeof PTY_PROTO - 1 &&
  83.         strncmp(dp->d_name, PTY_PREFIX, sizeof PTY_PREFIX - 1) == 0) {
  84.         pi->pi_pty = devname(dp->d_name);
  85.         if (pi->pi_pty == NULL)
  86.             return(0);
  87.         pi->pi_tty = malloc((unsigned)(strlen(pi->pi_pty) + 1));
  88.         if (pi->pi_tty == NULL) {
  89.             free(pi->pi_pty);
  90.             return(0);
  91.         }
  92.         (void)strcpy(pi->pi_tty, pi->pi_pty);
  93.         pi->pi_tty[PT_INDEX] = 't';
  94.         if (access(pi->pi_pty, 0) == 0 && access(pi->pi_tty, 0) == 0) {
  95.             pi->pi_next = ptylist;
  96.             ptylist = pi;
  97.             pi = NULL;
  98.         } else {
  99.             free(pi->pi_pty);
  100.             free(pi->pi_tty);
  101.         }
  102.     }
  103.     return(0);
  104. }
  105.  
  106. openpty(pt)
  107. struct ptydesc *pt;
  108. {
  109.     register struct ptyinfo *pi;
  110.     static int fail;
  111.     auto struct direct **dirlist;
  112.     extern char *re_comp();
  113.     extern int alphasort();
  114.  
  115.     /*
  116.      * If the regular expression PTY_PROTO is bad, scandir() fails, or
  117.      * no possible pty's are found, then "fail" is set non-zero.  If
  118.      * "fail" is non-zero then the routine bombs out immediately.
  119.      * Otherwise, the list of candidates is examined starting with the
  120.      * entry following the last one chosen.
  121.      */
  122.  
  123.     if (fail)
  124.         return(-1);
  125.  
  126.     if (!ptylist) {        /* first time */
  127.         if (scandir(DEV_DIR, &dirlist, isapty, alphasort) < 0 ||
  128.             ptylist == NULL) {
  129.             fail = 1;
  130.             return(-1);
  131.         }
  132.         for (pi=ptylist; pi->pi_next; pi=pi->pi_next)
  133.             ;
  134.         pi->pi_next = ptylist;    /* make the list circular */
  135.     }
  136.  
  137.     pi = ptylist;
  138.     do {
  139.         if ((pt->pt_pfd = open(pi->pi_pty, O_RDWR)) >= 0) {
  140.             if ((pt->pt_tfd = open(pi->pi_tty, O_RDWR)) >= 0) {
  141.                 ptylist = pi->pi_next;
  142.                 pt->pt_pname = pi->pi_pty;
  143.                 pt->pt_tname = pi->pi_tty;
  144.                 return(0);
  145.             } else
  146.                 (void)close(pt->pt_pfd);
  147.         }
  148.         pi = pi->pi_next;
  149.     } while (pi != ptylist);
  150.     return(-1);
  151. }
  152.