From: guy@Auspex.COM (Guy Harris)
Newsgroups: comp.unix.questions
Subject: Re: portable replacement for pty ?
Date: 9 Sep 92 07:02:20 GMT
Organization: Auspex Systems, Santa Clara
Originator: news@auspex-gw.Auspex.COM

>After some searching around various
>SVR3 and SVR4 machines, there is a "ptmx" set of devices that seems to
>parallel the ttys (like ptys would), but although they all have ptmx in place,
>ptmx doesn't show up in man pages on *any* of these.  I've looked at AT&T SVR4
>R2.1,

In the grand System V "the manual page you want is often in a manual
other than the obvious one" tradition (how many people not already aware
of that little SV peculiarity would expect the tty "ioctl"s to be
documented in the *System Administrator's* Reference Manual?), the SVR4
pseudo-tty mechanism is documented in manual pages at the back of

	UNIX(R) System V Release 4 Programmer's Guide: STREAMS

as well as in the "STREAMS-based Pseudo-Terminal Subsystem" section of
that document.

The mechanism that showed up in some SVR3 systems is a predecessor of
that mechanism; it has some of the stuff in there, but not all of it.

No, it's not portable, but then "UNIX pseudo-tty" and "portable"
generally don't belong in close proximity; here, for example, is the
"allocate a pseudo-tty" code from the Andrew Toolkit.  It doesn't yet
have support for SVR4 pseudo-ttys, but just dealing with HP-UX, various
flavors of AIX, IRIX, and some other systems has already complicated it
(and that's just the "allocate a pseudo-tty" routine; for big fun, try
checking out the "tm" application).

The moral of the story is "wrap access to pseudo-ttys in a wrapper
library, with different implementations on different UNIX flavors":

/* ********************************************************************** *\
 *         Copyright IBM Corporation 1988,1991 - All Rights Reserved      *
 *        For full copyright information see:'andrew/config/COPYRITE'     *
\* ********************************************************************** */
static char rcsid[]="$Header: /afs/andrew.cmu.edu/itc/src/projects/andrew/overhead/util/lib/RCS/getpty.c,v 1.11 1991/09/12 17:26:20 bobg Exp $";

/*
This module contains the routine getpty.  It returns file descriptors
for a pty. It takes two pointers to ints and returns the file decriptors.
It returns TRUE if it succeeds.
*/

#include <andrewos.h>

#ifdef SGI_4D_ENV
#include <sys/stat.h>
#include <sys/sysmacros.h>
#endif

#include <fcntl.h>
#include <sys/param.h>

#ifdef hpux
#include <sys/bsdtty.h>
#include <sys/ptyio.h>
#endif /* hpux */

#ifndef	SGI_4D_ENV  /* for bug in makedepend */
#if SY_AIX221
#include <sys/ioctl.h>
#include <sys/devinfo.h>
#include <sys/pty.h>
#include <sys/tty.h>
#endif /* SY_AIX221 */
#endif


#ifdef hpux
#define MASTER_PTY_PREFIX "/dev/ptym/pty"
#define SLAVE_PTY_PREFIX "/dev/pty/tty"
#define MAX_PTYS 64
#endif /* HPUX */

#if SY_AIX221
#define MASTER_PTY_PREFIX "/dev/ptc"
#define SLAVE_PTY_PREFIX "/dev/pts"
#define MAX_PTYS 256
#endif /* SY_AIX221 */

#ifndef MASTER_PTY_PREFIX
#define MASTER_PTY_PREFIX "/dev/pty"
#define SLAVE_PTY_PREFIX "/dev/tty"
#define MAX_PTYS 256
#endif

#if POSIX_ENV
#define OPEN_FLAGS O_RDWR|O_NOCTTY
#else
#define OPEN_FLAGS O_RDWR
#endif

static char *GetPtyNumberString(num)
int num;
{
static char ptyNum[10];

#if SY_AIX221 || defined (SGI_4D_ENV)
    sprintf(ptyNum, "%d", num);
#else /* SY_AIX221 */
    ptyNum[0] = 'p' + (num/16);
    ptyNum[1] = "0123456789abcdef"[num%16];
    ptyNum[2] = '\0';
#endif /* SY_AIX221 */
    return ptyNum;
}

int GetPtyandName(masterFD, slaveFD,name,len)
int *masterFD;
int *slaveFD;
char *name;
int len;
{
#if SY_AIX31
    /* AIX 3.1 lets us open a single device "/dev/ptc" which
     * finds an available pty for us.  ttyname() returns the
     * name of that device.
     */
    int master;
    int slave;
    char *ptyname;

    if ((master = open("/dev/ptc", OPEN_FLAGS)) < 0)
	return 0;	/* none left */
    if ((ptyname = ttyname(master)) == NULL) {
	/* major weirdness */
	close(master);
	return 0;
    }
    if ((slave = open(ptyname, OPEN_FLAGS)) < 0) {
	/* more weirdness */
	close(master);
	return 0;
    }
    if (name != NULL)
        strncpy(name,ptyname,len);
    if (masterFD != NULL)
	*masterFD = master;
    if (slaveFD != NULL)
	*slaveFD = slave;
    return 1;
#else
#ifdef SGI_4D_ENV
    int master;
    int slave;
    char ptyname[30];
    struct stat stBuf;

    do {
	if ((master = open("/dev/ptc", OPEN_FLAGS)) < 0)
	    return 0;	/* none left */
	if (fstat(master, &stBuf) < 0) {
	    return 0;
	}
	sprintf(ptyname, "/dev/ttyq%d", minor(stBuf.st_rdev));
	slave = open(ptyname, OPEN_FLAGS);
    } while (slave < 0);

    if (name != NULL)
        strncpy(name,ptyname,len);
    if (masterFD != NULL)
	*masterFD = master;
    if (slaveFD != NULL)
	*slaveFD = slave;
    return 1;

#else
    int PtyNumber = 0;
    char ptcname[MAXPATHLEN];
    char ptyname[MAXPATHLEN];
    char *ptyNum;
    int master;
    int slave;

    while (PtyNumber++ < MAX_PTYS) {
	ptyNum = GetPtyNumberString(PtyNumber);
	strcpy(ptcname, MASTER_PTY_PREFIX);
	strcat(ptcname, ptyNum);
	if ((master = open (ptcname, OPEN_FLAGS)) >= 0) {
#if SY_AIX221
	{
            /* Be sure this pty really is available. */
	    int value;

	    if ((value = ioctl(master, PTYSTATUS, 0)) == -1 || (value & 0xffff) != 0 || (value >> 16) != 1)  {
		close(master);
		continue;
	    }
	}
#endif /* SY_AIX221 */
	    strcpy(ptyname, SLAVE_PTY_PREFIX);
	    strcat(ptyname, ptyNum);
	    if(name != NULL) strncpy(name,ptyname,len);
	    if ((slave = open(ptyname, OPEN_FLAGS)) >= 0)  {
		if (masterFD != NULL)
		    *masterFD = master;
		if (slaveFD != NULL)
		    *slaveFD = slave;
		return 1;
	    }
	    else
		close(master);
	}
    }

    return 0;
#endif /* SGI_4D_ENV */
#endif /* SY_AIX31 */
}

int GetPty(masterFD, slaveFD)
int *masterFD;
int *slaveFD;
{
    return GetPtyandName(masterFD, slaveFD,NULL,0);
}
Newsgroups: comp.unix.questions,biz.sco.general