[comp.sys.hp] PTY/TTY pseudo terminal

kloo@csws13.ic.sunysb.edu (Kwok L Loo) (12/19/90)

I am working on a program using pty/tty pseudo terminal 
driver. I have read some similar programs implemented on
SUN. However, my program will be run on HP 7.0 and many
functions are different from those on SUN.
 
When I try to run my program, it does not work properly,
if anyone can give me suggestions, or even examples will
be greatly appreciated.

The program is that I need to open a pseudo terminal
and fork a process, which the child process will invoked 
'execv' system call to apply a system function, e,g,
csh, or jove. Then the communication will be connected
through the pseudo terminal. 

There is some concept and functions I do not understand. It 
seems like I need to get the controlling terminal to the 
calling process, then my program will be able to do I/O. 
Could anyone tell me the concept of controlling terminal 
and how to get a controlling terminal to a process? also 
I need to know about process group id and terminal id, 
since they are useful to get a controlling terminal.
Beside, I need to use a CBREAK mode to read data in blocks 
size. 

The following is one of my testing program implmented on 
mailx. I am looking forward to answering.

p.s.	(NO BSD UNIX & SUN functions)


/***				Use PTY					 ***/	

#include <stdio.h>
#include <string.h>
#include <sgtty.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/file.h>
#include <sys/ioctl.h>

#define NEWSIZE 20

int    	    	master_tty_id;		/* parent process, master tty id    */
FILE   	    	*master_fp = NULL;	/* file pointer of master tty	    */
int    	    	fork_pid;		/* process id thru fork system call */

static char 	*pty = "/dev/pty??";	/* master side of pseudo-terminal   */
static char 	*tty = "/dev/tty??";	/* slave side of pseudo-terminal    */

static int openMaster()
{
 int  i, master; 
 char c;

 for (c='p'; c<='s'; c++) {
     pty[8] = c;
     for (i=0; i<16; i++) {
         pty[9] = "0123456789abcdef"[i];
         if ((master = open(pty, O_RDWR)) != -1) 
            return (master); 
     }
 }
 fprintf(stderr, "xmail: all ptys in use\n");
 exit(1);
} /* openMaster */


static int openSlave()
{
 int slave;

 tty[8] = pty[8];
 tty[9] = pty[9];
 if ((slave = open(tty, O_RDWR)) != -1) {
    return (slave);
 } else {
     fprintf(stderr, "open: cannot open slave pty %s", tty);
     exit(1);
   }
} /* openSlave */

/****************************************************************/
/*								*/
/*  function for implementing mailx				*/
/*								*/
/****************************************************************/
int check_for_mail()
{
   char *mbox;
   struct stat buf;
   
   if ((mbox = (char *) getenv("MAIL")) == NULL)
    {
      fprintf(stderr, "Mailbox not found!. Please set $MAIL"); 
      return 1;
    } 
     
   if (stat(mbox, &buf) == -1)
    {
      fprintf(stderr, "No mail for %s\n",getlogin());
      return 1;
    }

   return 0;
 }

void app_pty(argc, argv)
int argc;
char *argv[];
{
 struct sgttyb Sgtty;
 int	       pid, pgrp;
 int	       fd;
 int           master;			/* file descriptor of master pty    */
 int           slave;			/* file descriptor to slave pty	    */
 char          buf[NEWSIZE], ch;
 int	       size, remaining;

		/* open pty, tty */
 master = openMaster();
 slave = openSlave();

 fork_pid = fork();
 if (fork_pid == -1) {		/* fork fail */
    fprintf(stderr,"Cannot fork mail process");
    exit(1);
 } else if (fork_pid) { 
             /* 
              * Parent : ->close the slave side of pty,
              *          ->close stdin and stdout,
              *          ->set the file descriptor to nonblocking mode,
              *          ->open file pointer with read/write access to child process,
              *          ->set unbuffered mode.
              */
             close(slave);
             if (master != 0)		/* if we're restarting, master is 0 */
                close(0);
             close(1);
					/* set nonblocking mode		    */
             fcntl(master, F_SETFL, O_NDELAY);
             master_tty_id = master;	/* use descriptor for reads	    */
             master_fp = fdopen(master, "r+");	/* need master_fp for fputs */

             setvbuf(master_fp, buf, _IOFBF, NEWSIZE);
             for (;;)
	     {
                while ((size = read(master_tty_id, buf, NEWSIZE)) == -1);
                if (size != 0) 
                {
		  buf[size] = '\0';
                  write(2, buf, strlen(buf));
                  write(1, "1\n", 2);
                  ioctl(master_tty_id, FIONREAD, &remaining);
                }
		write(0, "h\n", 2);
		write(1, "h\n", 2);
              }
   } else { 
             /* 
              * Child : ->close master side of pty,
              *         ->redirect stdin, stdout, stderr of child process to pty,
              *         ->unbuffer output data from child process,
              *         ->exec sytem called with arguments.
              */
	      
             close(master);

             ioctl(slave, TIOCGETP, &Sgtty);
             Sgtty.sg_flags &= ~(ECHO|CRMOD);	/* no echo, no NL to CR */
             ioctl(slave, TIOCSETP, &Sgtty);
			    /* redirect stdin, stdout, stderr */
             dup2(slave, 0);
             dup2(slave, 1);
             dup2(slave, 2);
	     
             if (slave > 2)
                 close(slave);
		 
             fcntl(1, F_SETFL, FAPPEND);
             setbuf(stdout, NULL);
	     
	     tcgetpgrp(0, &pgrp);
	     setpgrp(0, pgrp);
	     pid = getpid();
	     tcsetpgrp(0, pid);
	     setpgrp(0, pid);
	     
             execl("/usr/bin/mailx", "mailx", (char *) 0);
             exit(1);
            }
}	/* app_pty */


main()
{
  if (check_for_mail() == 0)
     app_pty();
}