/*
*      SCCS:   @(#)install/userintf/gen_termios	1.1 (01/21/97)  VSXgen release 1.4
*
*	UniSoft Ltd., London, England
*/
/***********************************************************************

NAME:		gen_termios - user-modifiable terminal interface routines
PROJECT:	VSX (X/OPEN Validation Suite)
AUTHOR:		Geoff Clare, UniSoft Ltd.
DATE CREATED:	December 1996
MODIFICATIONS:

************************************************************************/

/*
 *	Openctl() opens the terminal device "spec" with the specified flags.
 *	This then becomes the controlling terminal for the current process.
 *	If it cannot become the controlling terminal, openctl() must still
 *	open the device as an ordinary terminal.
 *	Openctl() returns the open file descriptor to the terminal,
 *	or -1 on failure.
 */
		
public int
openctl(spec, oflag)
char *spec;
int  oflag;
{
	/* Note: setsid() will have been called before this routine */

	int fd;

	/* allow for modem line delay if there has just been a close() */
	(void) sleep(1);

	fd = open(spec, oflag, 0);

	/* Make sure failure is not just because the device cannot
	   become the controlling terminal */
	
	if (fd < 0 && errno != EINTR)
		fd = open(spec, oflag|O_NOCTTY, 0);

	return fd;
}

/*
 *	Openpty() opens the master and slave sides of a pseudo-terminal.
 *	Both device names are supplied, but if master pty's are obtained
 *	from a clone device the slave name is a dummy which must be
 *	overwritten with the real device name.  If cntrl is true
 *	the slave must be opened as a controlling terminal by calling
 *	openctl() instead of plain open().  Both devices must be opened
 *	for reading and writing.  On many systems master devices can
 *	only be opened once, giving EBUSY for example on subsequent
 *	opens.  If openpty() encounters a busy master device, it must
 *	simply open the slave.
 *
 *	The open file descriptors are returned via the pointers mfdp and
 *	sfdp.  Openpty() returns 0 for success or -1 for failure.
 *
 *	This routine is only called if the VSX_MASTER_TTY and
 *	VSX_MASTER_LOOP parameters are set.
 */

/* #define CLONE_MPTY	/* uncomment if master pty's are obtained from a
		 	   clone device (e.g. /dev/ptmx) */
/* #define STREAMS_PTY	/* uncomment if pty's use STREAMS */

#ifdef STREAMS_PTY
#include <sys/stropts.h>
#endif

public int
openpty(master, slave, mfdp, sfdp, cntrl)
char *master;
char *slave;
int *mfdp;
int *sfdp;
int cntrl;
{
	*mfdp = open(master, O_RDWR|O_NOCTTY);
	if (*mfdp < 0 && errno != EBUSY)
		return -1;

#ifdef CLONE_MPTY
	if (*mfdp >= 0)
	{
		char *newslave;
		size_t len;
		static struct { char *ptr; size_t len; } slavelen[2];
		extern char *ptsname();

		(void) grantpt(*mfdp);   /* change permission of slave */
		(void) unlockpt(*mfdp);  /* unlock slave */
		newslave=ptsname(*mfdp); /* get a slave */
		if (slavelen[0].ptr == NULL)
		{
			/* remember length of original dummy name
			   to be used if called again */
			slavelen[0].ptr = slave;
			slavelen[0].len = strlen(slave);
		}
		else if (slave != slavelen[0].ptr && slavelen[1].ptr == NULL)
		{
			/* remember length of original dummy name
			   to be used if called again */
			slavelen[1].ptr = slave;
			slavelen[1].len = strlen(slave);
		}
		if (slave == slavelen[0].ptr)
			len = slavelen[0].len;
		else
			len = slavelen[1].len;
		if (strlen(newslave) > len)
		{
			(void) fprintf(stderr,
				"Error in vport/userintf: dummy slave name too short to take \"%s\" in openpty()\n",
				newslave);
			return -1;
		}
		(void) strcpy(slave, newslave);
	}
#endif

	if (cntrl)
		*sfdp = openctl(slave, O_RDWR);
	else
		*sfdp = open(slave, O_RDWR|O_NOCTTY);

	if (*sfdp < 0)
		return -1;

#ifdef STREAMS_PTY
	if (*mfdp >= 0)
	{
		(void) ioctl(*sfdp, I_PUSH, "ptem");   /* pseudo tty emulator */
		(void) ioctl(*sfdp, I_PUSH, "ldterm"); /* line discipline */
	}
#endif
	
	return 0;
}

/*
 *	Ptygetattr() obtains terminal attributes for the slave pseudo-
 *	terminal corresponding to the master device addressed by mfd.
 *	It returns 0 for success, -1 for failure.
 */

public int
ptygetattr(mfd, termios_p)
int mfd;
struct termios *termios_p;
{
#ifdef STREAMS_PTY
	extern char *ptsname();
	char *slave;
	int ret, sfd = -1;
	
	/* Obtain slave device name and call tcgetattr() on the slave */
	slave = ptsname(mfd);
	if (slave && (sfd = open(slave, O_RDWR)) >= 0)
		ret = tcgetattr(sfd, termios_p);
	else
		ret = -1;
	if (sfd >= 0)
		(void) close(sfd);
	return ret;
#else
	/* This code assumes tcgetattr() on the master returns the
	   settings of the slave (true for BSD-style pseudo-terminals) */
	return tcgetattr(mfd, termios_p);
#endif
}

