#define VERSION	"1.0.6"
#define I_IOCTL
#define I_ERRNO
#define I_SYS
#include "includes.h"

#include <signal.h>
#include <sys/stat.h>
#include <pwd.h>

#ifdef USE_TIOCNOTTY
#include <sys/ioctl.h>
#endif

#ifdef SYSV
#include <stropts.h>
#ifdef SVR4
int grantpt(int);
char *ptsname(int);
int unlockpt(int);
#endif
#endif

int pty_pid;

/* Moved these strings here for compilers which can't handle 
   aggregate auto initialization.  Makes open_pty() non-reentrant.
   HSW 93-01-29
   */
#ifdef __hpux
static  char masterline[]="/dev/ptym/ptyXY";
static  char slaveline[]="/dev/pty/ttyXY";
static  char *first ="pqrstuv";
#else				/*  not hpux, and not sgi. */
static  char masterline[]="/dev/ptyXY";
static  char *first ="pqrstuvwzyz";
static  char slaveline[]="/dev/ttyXY";
#endif

int open_pty(char *prog) {
  int masterfd = -1,
  slavefd,
  i,
  pid;
  int pip[2];
#if !defined(sgi) && !defined(SYSV)
#define	SFIRST	(sizeof (slaveline) - 3)
#define	SSECOND	(sizeof (slaveline) - 2)

				/* Ok. Stuff for not sgi. */
#define	MFIRST	(sizeof (masterline) - 3)
#define	MSECOND	(sizeof (masterline) - 2)
  char *ptr = first;
  int c;
#else /* sgi || SYSV */
#ifdef SYSV
				/* Stuff for SYSV */
  void (*savesig)(int);
  char *slaveline;
#else /* SYSV */
				/* And then finally, sgi stuff. */
  char *linetmp;
  char slaveline[20];
#endif /* SYSV */
#endif /* sgi || SYSV */
  
#if !defined(sgi) && !defined(SYSV)
  /* get a pseudo tty */
  ptr = first;
  for (c = *ptr; (c = *ptr); ++ptr) {
    struct stat statbuff;
    
    masterline[MFIRST] = c;
    masterline[MSECOND] = '0';
    
    if (stat (masterline, &statbuff) < 0)
      continue; /* no pty's on this bank availiable */

    for (i = 0; i < 16; ++i) {
      masterline[MSECOND] = "0123456789abcdef"[i];
      if ((masterfd = open (masterline, O_RDWR)) > 0)
	break;
    }
    if (i != 16) {
				/* Ok. now check to make sure we can */
				/* open the slave as well. */
      slaveline[SFIRST] = masterline[MFIRST];
      slaveline[SSECOND] = masterline[MSECOND];
      
      if ((slavefd = open (slaveline, O_RDWR)) < 0) {
	close(masterfd);
	continue;			/* unable to open slave pty */
      }
      break;
    }
    
  }

  if (!c)
    return -1;
  
#ifdef SUIDROOT
  if (fchmod (slavefd, 0622))
    return -2;
#endif
  
  close(slavefd);

#else /* sgi || SYSV */

#ifdef SYSV
  if ((masterfd = open("/dev/ptmx", O_RDWR)) < 0)
    return -1;
  savesig = signal(SIGCHLD, SIG_DFL);
  if (grantpt(masterfd) < 0) {
    close(masterfd);
    sigset(SIGCHLD, savesig);
    return -1;
  }
  sigset(SIGCHLD, savesig);
  if (unlockpt(masterfd) < 0) {
    close(masterfd);
    return -1;
  }
  slaveline = ptsname(masterfd);
  if (slaveline == NULL) {
    close(masterfd);
    return -1;
  }
#else /* SYSV */
  
  linetmp = _getpty(&masterfd, O_RDWR, 0600, 0);
  
  if (linetmp == NULL)
    return -1; /* no pty's available */
  
  strcpy(slaveline, linetmp);
  
  /* Don't check slave - have to assume it's going to work */
  
#endif /* SYSV */
#endif /* sgi */

  pipe(pip);
  if ((pid = fork ()) < 0)
    return -3; /* unable to fork */
  
  if (pid == 0) { /* child. */
/*    char  ** a, *b[2] = {0, }; Ultrix MIPS compiler chokes */
      char  ** a, *b[2];
      b[0]=b[1]=NULL;
    close(0);
    close(1);
    close(2);

    lose_ctty();
    
    if ((slavefd = open (slaveline, O_RDWR)) < 0) {
      /* make it control tty */
      exit(1);
    }
#ifdef USE_VHANGUP
    signal (SIGHUP, SIG_IGN);
    vhangup ();
    signal (SIGHUP, SIG_DFL);
    
    if ((slavefd = open (slaveline, O_RDWR)) < 0) {
      exit(1);
    }
#endif

#ifdef SYSV
    if (ioctl(slavefd, I_PUSH, "ptem") < 0) {
      exit(1);
    }
    if (ioctl(slavefd, I_PUSH, "ldterm") < 0) {
      exit(1);
    }
#ifdef SVR4
    if (ioctl(slavefd, I_PUSH, "ttcompat") < 0) {
      exit(1);
    }
#endif /* SVR4 */
#endif /* SYSV */

    /*
     **	do a term setup here.
     */
    dup2 (slavefd, 0);
    dup2 (slavefd, 1);
    dup2 (slavefd, 2);
    for (slavefd = 3; slavefd < 64;++slavefd)
      close(slavefd);
#ifndef SVR4
    terminal_restore(0);
#endif

    /* find out what shell to run. */
    /* note: technically we should free a, but as we are 
     * in the child who will either exec or exit, we can 
     * neglect this.  croutons.
     */
    a = rebuild_arg(prog);
    if ( !a ) {
      a = b; 
    }
    if ( !a[0] )
      a[0] = getenv("SHELL");
    if (!a[0]) a[0] = "/bin/sh";

    printf ("Running on line %s\r\n", slaveline);
    printf ("Term %s running. about to exec %s...\r\n", VERSION, a[0]);
    close(pip[0]);
    write(pip[1],"a",1);
    close(pip[1]);
    execvp(a[0], a);
    
    printf ("Unable to exec %s.\n", a[0]);
    exit(1);
  }
				/* Wait for exec.. */
  close(pip[1]);
  read(pip[0], (char *) &i, 1);
  close(pip[0]);

  set_nonblock(masterfd);
  /*	ioctl(masterfd, TIOCPKY, &one); BSD pty packet mode. */
  pty_pid = pid;
  
  return masterfd;
}
