Print this page
14249 pseudo-terminal nomenclature should reflect POSIX
Change-Id: Ib4a3cef899ff4c71b09cb0dc6878863c5e8357bc

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/enhance/enhance.c
          +++ new/usr/src/cmd/enhance/enhance.c
↓ open down ↓ 16 lines elided ↑ open up ↑
  17   17   * fields enclosed by brackets "[]" replaced with your own identifying
  18   18   * information: Portions Copyright [yyyy] [name of copyright owner]
  19   19   *
  20   20   * CDDL HEADER END
  21   21   */
  22   22  /*
  23   23   * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
  24   24   * Use is subject to license terms.
  25   25   */
  26   26  
  27      -#pragma ident   "%Z%%M% %I%     %E% SMI"
  28      -
  29   27  #include <stdio.h>
  30   28  #include <stdlib.h>
  31   29  #include <string.h>
  32   30  #include <errno.h>
  33   31  #include <signal.h>
  34   32  #include <locale.h>
  35   33  
  36   34  #include <unistd.h>
  37   35  #include <termios.h>
  38   36  
↓ open down ↓ 23 lines elided ↑ open up ↑
  62   60   */
  63   61  #define PTY_DEV_DIR "/dev/"
  64   62  
  65   63  /*
  66   64   * Pseudo-terminal controller device file names start with the following
  67   65   * prefix.
  68   66   */
  69   67  #define PTY_CNTRL "pty"
  70   68  
  71   69  /*
  72      - * Pseudo-terminal slave device file names start with the following
       70 + * Pseudo-terminal subsidiary device file names start with the following
  73   71   * prefix.
  74   72   */
  75      -#define PTY_SLAVE "tty"
       73 +#define PTY_SUBSID "tty"
  76   74  
  77   75  /*
  78      - * Specify the maximum suffix length for the control and slave device
       76 + * Specify the maximum suffix length for the control and subsidiary device
  79   77   * names.
  80   78   */
  81   79  #define PTY_MAX_SUFFIX 10
  82   80  
  83   81  /*
  84      - * Set the maximum length of the master and slave terminal device filenames,
  85      - * including space for a terminating '\0'.
       82 + * Set the maximum length of the manager and subsidiary terminal device
       83 + * filenames, including space for a terminating '\0'.
  86   84   */
  87   85  #define PTY_MAX_NAME (sizeof(PTY_DEV_DIR)-1 + \
  88      -                      (sizeof(PTY_SLAVE) > sizeof(PTY_CNTRL) ? \
  89      -                       sizeof(PTY_SLAVE) : sizeof(PTY_CNTRL))-1 \
       86 +                      (sizeof(PTY_SUBSID) > sizeof(PTY_CNTRL) ? \
       87 +                       sizeof(PTY_SUBSID) : sizeof(PTY_CNTRL))-1 \
  90   88                        + PTY_MAX_SUFFIX + 1)
  91   89  /*
  92   90   * Set the maximum length of an input line.
  93   91   */
  94   92  #define PTY_MAX_LINE 4096
  95   93  
  96   94  /*
  97   95   * Set the size of the buffer used for accumulating bytes written by the
  98   96   * user's terminal to its stdout.
  99   97   */
↓ open down ↓ 3 lines elided ↑ open up ↑
 103  101   * Set the amount of memory used to record history.
 104  102   */
 105  103  #define PTY_HIST_SIZE 10000
 106  104  
 107  105  /*
 108  106   * Set the timeout delay used to check for quickly arriving
 109  107   * sequential output from the application.
 110  108   */
 111  109  #define PTY_READ_TIMEOUT 100000    /* micro-seconds */
 112  110  
 113      -static int pty_open_master(const char *prog, int *cntrl, char *slave_name);
 114      -static int pty_open_slave(const char *prog, char *slave_name);
 115      -static int pty_child(const char *prog, int slave, char *argv[]);
      111 +static int pty_open_manager(const char *prog, int *cntrl, char *subsid_name);
      112 +static int pty_open_subsid(const char *prog, char *subsid_name);
      113 +static int pty_child(const char *prog, int subsid, char *argv[]);
 116  114  static int pty_parent(const char *prog, int cntrl);
 117  115  static int pty_stop_parent(int waserr, int cntrl, GetLine *gl, char *rbuff);
 118  116  static GL_FD_EVENT_FN(pty_read_from_program);
 119  117  static int pty_write_to_fd(int fd, const char *string, int n);
 120  118  static void pty_child_exited(int sig);
 121      -static int pty_master_readable(int fd, long usec);
      119 +static int pty_manager_readable(int fd, long usec);
 122  120  
 123  121  /*.......................................................................
 124  122   * Run a program with enhanced terminal editing facilities.
 125  123   *
 126  124   * Usage:
 127  125   *  enhance program [args...]
 128  126   */
 129  127  int main(int argc, char *argv[])
 130  128  {
 131  129    int cntrl = -1;  /* The fd of the pseudo-terminal controller device */
 132      -  int slave = -1;  /* The fd of the pseudo-terminal slave device */
      130 +  int subsid = -1;  /* The fd of the pseudo-terminal subsidiary device */
 133  131    pid_t pid;       /* The return value of fork() */
 134  132    int status;      /* The return statuses of the parent and child functions */
 135      -  char slave_name[PTY_MAX_NAME]; /* The filename of the slave end of the */
 136      -                                 /*  pseudo-terminal. */
      133 +  char subsid_name[PTY_MAX_NAME]; /* The filename of the subsidiary end of */
      134 +                                 /*  the pseudo-terminal. */
 137  135    char *prog;      /* The name of the program (ie. argv[0]) */
 138  136  /*
 139  137   * Check the arguments.
 140  138   */
 141  139    if(argc < 2) {
 142  140      fprintf(stderr, "Usage: %s <program> [arguments...]\n", argv[0]);
 143  141      return 1;
 144  142    };
 145  143  /*
 146  144   * Get the name of the program.
↓ open down ↓ 11 lines elided ↑ open up ↑
 158  156   */
 159  157    if(!isatty(STDIN_FILENO) || !isatty(STDOUT_FILENO)) {
 160  158      if(execvp(argv[1], argv + 1) < 0) {
 161  159        fprintf(stderr, "%s: Unable to execute %s (%s).\n", prog, argv[1],
 162  160                strerror(errno));
 163  161        fflush(stderr);
 164  162        _exit(1);
 165  163      };
 166  164    };
 167  165  /*
 168      - * Open the master side of a pseudo-terminal pair, and return
      166 + * Open the manager side of a pseudo-terminal pair, and return
 169  167   * the corresponding file descriptor and the filename of the
 170      - * slave end of the pseudo-terminal.
      168 + * subsidiary end of the pseudo-terminal.
 171  169   */
 172      -  if(pty_open_master(prog, &cntrl, slave_name))
      170 +  if(pty_open_manager(prog, &cntrl, subsid_name))
 173  171      return 1;
 174  172  /*
 175  173   * Set up a signal handler to watch for the child process exiting.
 176  174   */
 177  175    signal(SIGCHLD, pty_child_exited);
 178  176  /*
 179  177   * The above signal handler sends the parent process a SIGINT signal.
 180  178   * This signal is caught by gl_get_line(), which resets the terminal
 181  179   * settings, and if the application signal handler for this signal
 182  180   * doesn't abort the process, gl_get_line() returns NULL with errno
↓ open down ↓ 11 lines elided ↑ open up ↑
 194  192              strerror(errno));
 195  193      return 1;
 196  194    };
 197  195  /*
 198  196   * Are we the parent?
 199  197   */
 200  198    if(pid!=0) {
 201  199      status = pty_parent(prog, cntrl);
 202  200      close(cntrl);
 203  201    } else {
 204      -    close(cntrl); /* The child doesn't use the slave device */
      202 +    close(cntrl); /* The child doesn't use the subsidiary device */
 205  203      signal(SIGCHLD, pty_child_exited);
 206      -    if((slave = pty_open_slave(prog, slave_name)) >= 0) {
 207      -      status = pty_child(prog, slave, argv + 1);
 208      -      close(slave);
      204 +    if((subsid = pty_open_subsid(prog, subsid_name)) >= 0) {
      205 +      status = pty_child(prog, subsid, argv + 1);
      206 +      close(subsid);
 209  207      } else {
 210  208        status = 1;
 211  209      };
 212  210    };
 213  211    return status;
 214  212  }
 215  213  
 216  214  /*.......................................................................
 217      - * Open the master side of a pseudo-terminal pair, and return
      215 + * Open the manager side of a pseudo-terminal pair, and return
 218  216   * the corresponding file descriptor and the filename of the
 219      - * slave end of the pseudo-terminal.
      217 + * subsidiary end of the pseudo-terminal.
 220  218   *
 221  219   * Input/Output:
 222  220   *  prog  const char *  The name of this program.
 223  221   *  cntrl        int *  The file descriptor of the pseudo-terminal
 224  222   *                      controller device will be assigned tp *cntrl.
 225      - *  slave_name  char *  The file-name of the pseudo-terminal slave device
 226      - *                      will be recorded in slave_name[], which must have
      223 + *  subsid_name  char *  The file-name of the pseudo-terminal subsidiary device
      224 + *                      will be recorded in subsid_name[], which must have
 227  225   *                      at least PTY_MAX_NAME elements.
 228  226   * Output:
 229  227   *  return       int    0 - OK.
 230  228   *                      1 - Error.
 231  229   */
 232      -static int pty_open_master(const char *prog, int *cntrl, char *slave_name)
      230 +static int pty_open_manager(const char *prog, int *cntrl, char *subsid_name)
 233  231  {
 234      -  char master_name[PTY_MAX_NAME]; /* The filename of the master device */
      232 +  char manager_name[PTY_MAX_NAME]; /* The filename of the manager device */
 235  233    DIR *dir;                       /* The directory iterator */
 236  234    struct dirent *file;            /* A file in "/dev" */
 237  235  /*
 238  236   * Mark the controller device as not opened yet.
 239  237   */
 240  238    *cntrl = -1;
 241  239  /*
 242  240   * On systems with the Sys-V pseudo-terminal interface, we don't
 243      - * have to search for a free master terminal. We just open /dev/ptmx,
 244      - * and if there is a free master terminal device, we are given a file
      241 + * have to search for a free manager terminal. We just open /dev/ptmx,
      242 + * and if there is a free manager terminal device, we are given a file
 245  243   * descriptor connected to it.
 246  244   */
 247  245  #if HAVE_SYSV_PTY
 248  246    *cntrl = open("/dev/ptmx", O_RDWR);
 249  247    if(*cntrl >= 0) {
 250  248  /*
 251      - * Get the filename of the slave side of the pseudo-terminal.
      249 + * Get the filename of the subsidiary side of the pseudo-terminal.
 252  250   */
 253  251      char *name = ptsname(*cntrl);
 254  252      if(name) {
 255  253        if(strlen(name)+1 > PTY_MAX_NAME) {
 256      -        fprintf(stderr, "%s: Slave pty filename too long.\n", prog);
      254 +        fprintf(stderr, "%s: Subsidiary pty filename too long.\n", prog);
 257  255          return 1;
 258  256        };
 259      -      strlcpy(slave_name, name, PTY_MAX_NAME);
      257 +      strlcpy(subsid_name, name, PTY_MAX_NAME);
 260  258  /*
 261      - * If unable to get the slave name, discard the controller file descriptor,
 262      - * ready to try a search instead.
      259 + * If unable to get the subsidiary name, discard the controller file
      260 + * descriptor, ready to try a search instead.
 263  261   */
 264  262      } else {
 265  263        close(*cntrl);
 266  264        *cntrl = -1;
 267  265      };
 268  266    } else {
 269  267  #endif
 270  268  /*
 271  269   * On systems without /dev/ptmx, or if opening /dev/ptmx failed,
 272      - * we open one master terminal after another, until one that isn't
      270 + * we open one manager terminal after another, until one that isn't
 273  271   * in use by another program is found.
 274  272   *
 275  273   * Open the devices directory.
 276  274   */
 277  275      dir = opendir(PTY_DEV_DIR);
 278  276      if(!dir) {
 279  277        fprintf(stderr, "%s: Couldn't open %s (%s)\n", prog, PTY_DEV_DIR,
 280  278                strerror(errno));
 281  279        return 1;
 282  280      };
 283  281  /*
 284  282   * Look for pseudo-terminal controller device files in the devices
 285  283   * directory.
 286  284   */
 287  285      while(*cntrl < 0 && (file = readdir(dir))) {
 288  286        if(strncmp(file->d_name, PTY_CNTRL, sizeof(PTY_CNTRL)-1) == 0) {
 289  287  /*
 290      - * Get the common extension of the control and slave filenames.
      288 + * Get the common extension of the control and subsidiary filenames.
 291  289   */
 292  290          const char *ext = file->d_name + sizeof(PTY_CNTRL)-1;
 293  291          if(strlen(ext) > PTY_MAX_SUFFIX)
 294  292            continue;
 295  293  /*
 296  294   * Attempt to open the control file.
 297  295   */
 298      -        strlcpy(master_name, PTY_DEV_DIR, sizeof(master_name));
 299      -        strlcat(master_name, PTY_CNTRL, sizeof(master_name));
 300      -        strlcat(master_name, ext, sizeof(master_name));
 301      -        *cntrl = open(master_name, O_RDWR);
      296 +        strlcpy(manager_name, PTY_DEV_DIR, sizeof(manager_name));
      297 +        strlcat(manager_name, PTY_CNTRL, sizeof(manager_name));
      298 +        strlcat(manager_name, ext, sizeof(manager_name));
      299 +        *cntrl = open(manager_name, O_RDWR);
 302  300          if(*cntrl < 0)
 303  301            continue;
 304  302  /*
 305      - * Attempt to open the matching slave file.
      303 + * Attempt to open the matching subsidiary file.
 306  304   */
 307      -        strlcpy(slave_name, PTY_DEV_DIR, PTY_MAX_NAME);
 308      -        strlcat(slave_name, PTY_SLAVE, PTY_MAX_NAME);
 309      -        strlcat(slave_name, ext, PTY_MAX_NAME);
      305 +        strlcpy(subsid_name, PTY_DEV_DIR, PTY_MAX_NAME);
      306 +        strlcat(subsid_name, PTY_SUBSID, PTY_MAX_NAME);
      307 +        strlcat(subsid_name, ext, PTY_MAX_NAME);
 310  308        };
 311  309      };
 312  310      closedir(dir);
 313  311  #if HAVE_SYSV_PTY
 314  312    };
 315  313  #endif
 316  314  /*
 317  315   * Did we fail to find a pseudo-terminal pair that we could open?
 318  316   */
 319  317    if(*cntrl < 0) {
 320  318      fprintf(stderr, "%s: Unable to find a free pseudo-terminal.\n", prog);
 321  319      return 1;
 322  320    };
 323  321  /*
 324      - * System V systems require the program that opens the master to
 325      - * grant access to the slave side of the pseudo-terminal.
      322 + * System V systems require the program that opens the manager to
      323 + * grant access to the subsidiary side of the pseudo-terminal.
 326  324   */
 327  325  #ifdef HAVE_SYSV_PTY
 328  326    if(grantpt(*cntrl) < 0 ||
 329  327       unlockpt(*cntrl) < 0) {
 330  328      fprintf(stderr, "%s: Unable to unlock terminal (%s).\n", prog,
 331  329              strerror(errno));
 332  330      return 1;
 333  331    };
 334  332  #endif
 335  333  /*
 336  334   * Success.
 337  335   */
 338  336    return 0;
 339  337  }
 340  338  
 341  339  /*.......................................................................
 342      - * Open the slave end of a pseudo-terminal.
      340 + * Open the subsidiary end of a pseudo-terminal.
 343  341   *
 344  342   * Input:
 345  343   *  prog   const char *  The name of this program.
 346      - *  slave_name   char *  The filename of the slave device.
      344 + *  subsid_name   char *  The filename of the subsidiary device.
 347  345   * Output:
 348  346   *  return        int    The file descriptor of the successfully opened
 349      - *                       slave device, or < 0 on error.
      347 + *                       subsidiary device, or < 0 on error.
 350  348   */
 351      -static int pty_open_slave(const char *prog, char *slave_name)
      349 +static int pty_open_subsid(const char *prog, char *subsid_name)
 352  350  {
 353      -  int fd;  /* The file descriptor of the slave device */
      351 +  int fd;  /* The file descriptor of the subsidiary device */
 354  352  /*
 355  353   * Place the process in its own process group. In system-V based
 356  354   * OS's, this ensures that when the pseudo-terminal is opened, it
 357  355   * becomes the controlling terminal of the process.
 358  356   */
 359  357    if(setsid() < 0) {
 360  358      fprintf(stderr, "%s: Unable to form new process group (%s).\n", prog,
 361  359              strerror(errno));
 362  360      return -1;
 363  361    };
 364  362  /*
 365  363   * Attempt to open the specified device.
 366  364   */
 367      -  fd = open(slave_name, O_RDWR);
      365 +  fd = open(subsid_name, O_RDWR);
 368  366    if(fd < 0) {
 369      -    fprintf(stderr, "%s: Unable to open pseudo-terminal slave device (%s).\n",
      367 +    fprintf(stderr, "%s: Unable to open pty subsidiary device (%s).\n",
 370  368              prog, strerror(errno));
 371  369      return -1;
 372  370    };
 373  371  /*
 374  372   * On system-V streams based systems, we need to push the stream modules
 375  373   * that implement pseudo-terminal and termio interfaces. At least on
 376      - * Solaris, which pushes these automatically when a slave is opened,
      374 + * Solaris, which pushes these automatically when a subsidiary is opened,
 377  375   * this is redundant, so ignore errors when pushing the modules.
 378  376   */
 379  377  #if HAVE_SYSV_PTY
 380  378    (void) ioctl(fd, I_PUSH, "ptem");
 381  379    (void) ioctl(fd, I_PUSH, "ldterm");
 382  380  /*
 383  381   * On BSD based systems other than SunOS 4.x, the following makes the
 384  382   * pseudo-terminal the controlling terminal of the child process.
 385  383   * According to the pseudo-terminal example code in Steven's
 386  384   * Advanced programming in the unix environment, the !defined(CIBAUD)
↓ open down ↓ 104 lines elided ↑ open up ↑
 491  489    (void) wait(&status);
 492  490  /*
 493  491   * Return either our error status, or the return status of the child
 494  492   * program.
 495  493   */
 496  494    return waserr ? 1 : status;
 497  495  }
 498  496  
 499  497  /*.......................................................................
 500  498   * Run the user's program, with its stdin and stdout connected to the
 501      - * slave end of the psuedo-terminal.
      499 + * subsidiary end of the psuedo-terminal.
 502  500   *
 503  501   * Input:
 504  502   *  prog  const char *   The name of this program.
 505      - *  slave        int     The file descriptor of the slave end of the
      503 + *  subsid        int     The file descriptor of the subsidiary end of the
 506  504   *                       pseudo terminal.
 507  505   *  argv        char *[] The argument vector to pass to the user's program,
 508  506   *                       where argv[0] is the name of the user's program,
 509  507   *                       and the last argument is followed by a pointer
 510  508   *                       to NULL.
 511  509   * Output:
 512  510   *  return   int         If this function returns at all, an error must
 513  511   *                       have occured when trying to overlay the process
 514  512   *                       with the user's program. In this case 1 is
 515  513   *                       returned.
 516  514   */
 517      -static int pty_child(const char *prog, int slave, char *argv[])
      515 +static int pty_child(const char *prog, int subsid, char *argv[])
 518  516  {
 519  517    struct termios attr; /* The terminal attributes */
 520  518  /*
 521  519   * We need to stop the pseudo-terminal from echoing everything that we send it.
 522  520   */
 523      -  if(tcgetattr(slave, &attr)) {
      521 +  if(tcgetattr(subsid, &attr)) {
 524  522      fprintf(stderr, "%s: Can't get pseudo-terminal attributes (%s).\n", prog,
 525  523              strerror(errno));
 526  524      return 1;
 527  525    };
 528  526    attr.c_lflag &= ~(ECHO);
 529      -  while(tcsetattr(slave, TCSADRAIN, &attr)) {
      527 +  while(tcsetattr(subsid, TCSADRAIN, &attr)) {
 530  528      if(errno != EINTR) {
 531  529        fprintf(stderr, "%s: tcsetattr error: %s\n", prog, strerror(errno));
 532  530        return 1;
 533  531      };
 534  532    };
 535  533  /*
 536      - * Arrange for stdin, stdout and stderr to be connected to the slave device,
 537      - * ignoring errors that imply that either stdin or stdout is closed.
      534 + * Arrange for stdin, stdout and stderr to be connected to the subsidiary
      535 + * device, ignoring errors that imply that either stdin or stdout is closed.
 538  536   */
 539      -  while(dup2(slave, STDIN_FILENO) < 0 && errno==EINTR)
      537 +  while(dup2(subsid, STDIN_FILENO) < 0 && errno==EINTR)
 540  538      ;
 541      -  while(dup2(slave, STDOUT_FILENO) < 0 && errno==EINTR)
      539 +  while(dup2(subsid, STDOUT_FILENO) < 0 && errno==EINTR)
 542  540      ;
 543      -  while(dup2(slave, STDERR_FILENO) < 0 && errno==EINTR)
      541 +  while(dup2(subsid, STDERR_FILENO) < 0 && errno==EINTR)
 544  542      ;
 545  543  /*
 546  544   * Run the user's program.
 547  545   */
 548  546    if(execvp(argv[0], argv) < 0) {
 549  547      fprintf(stderr, "%s: Unable to execute %s (%s).\n", prog, argv[0],
 550  548              strerror(errno));
 551  549      fflush(stderr);
 552  550      _exit(1);
 553  551    };
↓ open down ↓ 87 lines elided ↑ open up ↑
 641  639   * Skip trailing carriage returns and newlines.
 642  640   */
 643  641        while(*nextp=='\n' || *nextp=='\r')
 644  642          nextp++;
 645  643  /*
 646  644   * Move any unwritten text following the newline, to the start of the
 647  645   * buffer.
 648  646   */
 649  647        memmove(rbuff, nextp, len - (nextp - rbuff) + 1);
 650  648      };
 651      -  } while(pty_master_readable(fd, PTY_READ_TIMEOUT));
      649 +  } while(pty_manager_readable(fd, PTY_READ_TIMEOUT));
 652  650  /*
 653  651   * Make the incomplete line in the output buffer the current prompt.
 654  652   */
 655  653    gl_replace_prompt(gl, rbuff);
 656  654    return GLFD_REFRESH;
 657  655  }
 658  656  
 659  657  /*.......................................................................
 660  658   * Write a given string to a specified file descriptor.
 661  659   *
↓ open down ↓ 17 lines elided ↑ open up ↑
 679  677        ndone += nnew;
 680  678      else if(errno != EINTR)
 681  679        return 1;
 682  680    };
 683  681    return 0;
 684  682  }
 685  683  
 686  684  /*.......................................................................
 687  685   * This is the signal handler that is called when the child process
 688  686   * that is running the user's program exits for any reason. It closes
 689      - * the slave end of the terminal, so that gl_get_line() in the parent
      687 + * the subsidiary end of the terminal, so that gl_get_line() in the parent
 690  688   * process sees an end of file.
 691  689   */
 692  690  static void pty_child_exited(int sig)
 693  691  {
 694  692    raise(SIGINT);
 695  693  }
 696  694  
 697  695  /*.......................................................................
 698  696   * Return non-zero after a given amount of time if there is data waiting
 699  697   * to be read from a given file descriptor.
 700  698   *
 701  699   * Input:
 702  700   *  fd        int  The descriptor to watch.
 703  701   *  usec     long  The number of micro-seconds to wait for input to
 704  702   *                 arrive before giving up.
 705  703   * Output:
 706  704   *  return    int  0 - No data is waiting to be read (or select isn't
 707  705   *                     available).
 708  706   *                 1 - Data is waiting to be read.
 709  707   */
 710      -static int pty_master_readable(int fd, long usec)
      708 +static int pty_manager_readable(int fd, long usec)
 711  709  {
 712  710  #if HAVE_SELECT
 713  711    fd_set rfds;             /* The set of file descriptors to check */
 714  712    struct timeval timeout;  /* The timeout */
 715  713    FD_ZERO(&rfds);
 716  714    FD_SET(fd, &rfds);
 717  715    timeout.tv_sec = 0;
 718  716    timeout.tv_usec = usec;
 719  717    return select(fd+1, &rfds, NULL, NULL, &timeout) == 1;
 720  718  #else
 721  719    return 0;
 722  720  #endif
 723  721  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX