text: /*************************************************************************\
  *                  Copyright (C) Michael Kerrisk, 2014.                   *
  *                                                                         *
  * This program is free software. You may use, modify, and redistribute it *
  * under the terms of the GNU Affero General Public License as published   *
  * by the Free Software Foundation, either version 3 or (at your option)   *
  * any later version. This program is distributed without any warranty.    *
  * See the file COPYING.agpl-v3 for details.                               *
  \*************************************************************************/
  
  /* Listing 64-4 */
  
  #include <fcntl.h>
  #include "pty_master_open.h"            /* Declares ptyMasterOpen() */
  #include "tlpi_hdr.h"
  
  #define PTYM_PREFIX     "/dev/pty"
  #define PTYS_PREFIX     "/dev/tty"
  #define PTY_PREFIX_LEN  (sizeof(PTYM_PREFIX) - 1)
  #define PTY_NAME_LEN    (PTY_PREFIX_LEN + sizeof("XY"))
  #define X_RANGE         "pqrstuvwxyzabcde"
  #define Y_RANGE         "0123456789abcdef"
  
  int
  ptyMasterOpen(char *slaveName, size_t snLen)
  {
      int masterFd, n;
      char *x, *y;
      char masterName[PTY_NAME_LEN];
  
      if (PTY_NAME_LEN > snLen) {
          errno = EOVERFLOW;
          return -1;
      }
  
      memset(masterName, 0, PTY_NAME_LEN);
      strncpy(masterName, PTYM_PREFIX, PTY_PREFIX_LEN);
  
      for (x = X_RANGE; *x != '\0'; x++) {
          masterName[PTY_PREFIX_LEN] = *x;
  
          for (y = Y_RANGE; *y != '\0'; y++) {
              masterName[PTY_PREFIX_LEN + 1] = *y;
  
              masterFd = open(masterName, O_RDWR);
  
              if (masterFd == -1) {
                  if (errno == ENOENT)    /* No such file */
                      return -1;          /* Probably no more pty devices */
                  else                    /* Other error (e.g., pty busy) */
                      continue;
  
              } else {            /* Return slave name corresponding to master */
                  n = snprintf(slaveName, snLen, "%s%c%c", PTYS_PREFIX, *x, *y);
                  if (n >= snLen) {
                      errno = EOVERFLOW;
                      return -1;
                  } else if (n == -1) {
                      return -1;
                  }
  
                  return masterFd;
              }
          }
      }
  
      return -1;                  /* Tried all ptys without success */
  }
  