Attached is a basic forkpty-aix.c that I put together from tmux and
glib projects and my own testing. I've been using it successfully for
over a month now, so it should be OK. Additional patches to come later
today in this thread.
-Ross

#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>

/* Open a pseudo-terminal. */
static int
openpty (int *amaster, int *aslave, char *name,
         struct termios const *termp, struct winsize const *winp)
{
  int master;
  char *slave_name;
  int slave;

  master = open ("/dev/ptc", O_RDWR | O_NOCTTY);
  if (master < 0)
    return -1;


  if (grantpt (master))
    goto fail;

  if (unlockpt (master))
    goto fail;

  slave_name = ptsname (master);
  if (slave_name == NULL)
    goto fail;

  slave = open (slave_name, O_RDWR | O_NOCTTY);
  if (slave == -1)
    goto fail;

  /* XXX Should we ignore errors here?  */
  if (termp)
    tcsetattr (slave, TCSAFLUSH, termp);
  if (winp)
    ioctl (slave, TIOCSWINSZ, winp);

  *amaster = master;
  *aslave = slave;
  if (name != NULL)
    strcpy (name, slave_name);

  return 0;

 fail:
  close (master);
  return -1;
}

/* Assign a given terminal as controlling terminal and as standard input,
   standard output, standard error of the current process.                */
static int
login_tty (int slave_fd)
{
  int i;

  /* Create a new session.  */
  setsid ();

  /* Make fd the controlling terminal for the current process.
     On Solaris:
       A terminal becomes the controlling terminal of a session
       if it is being open()ed, at a moment when
         1. it is not already the controlling terminal of some session, and
         2. the process that open()s it is a session leader that does not have
            a controlling terminal.
       We assume condition 1, try to ensure condition 2, and then open() it.
   */
  for (i = 0; i < 3; i++)
    if (i != slave_fd)
      close (i);

    char *slave_name;
    int dummy_fd;

    slave_name = ttyname (slave_fd);
    if (slave_name == NULL)
      return -1;
    dummy_fd = open (slave_name, O_RDWR);
    if (dummy_fd < 0)
      return -1;
    close (dummy_fd);

  /* Assign fd to the standard input, standard output, and standard error of
     the current process.  */
  for (i = 0; i < 3; i++)
    if (slave_fd != i)
      while (dup2 (slave_fd, i) == -1 && errno == EBUSY);
//      if (dup2 (slave_fd, i) < 0)
//        return -1;
  if (slave_fd >= 3)
    close (slave_fd);

  return 0;
}

/* Fork a child process attached to the slave of a pseudo-terminal. */
int
forkpty (int *amaster, char *name,
         const struct termios *termp, const struct winsize *winp)
{
  int master, slave, pid;

  if (openpty (&master, &slave, name, termp, winp) == -1)
    return -1;

  switch (pid = fork ())
    {
    case -1:
      close (master);
      close (slave);
      return -1;

    case 0:
      /* Child.  */
      close (master);
      if (login_tty (slave))
        _exit (1);
      return 0;

    default:
      /* Parent.  */
      *amaster = master;
      close (slave);
//      sleep(1);
      return pid;
    }
}

Reply via email to