[comp.sources.misc] v06i048: Xenix pty driver

allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (03/05/89)

Posting-number: Volume 6, Issue 48
Submitted-by: chip@ateng.ateng.com (Chip Salzenberg)
Archive-name: ptys.sco

This driver adds Berkeley-style ptys (pseudo-ttys) to SCO Xenix/286 and
Xenix/386.  It has a long history.  It is derived from a System V version,
but is now specific to SCO Xenix.

Note that although Xenix/386 2.3 includes ptys, they are *broken*.  They are
incapable of non-blocking reads on the master side.  This bug hangs Emacs.
All Xenix users would be well advised to avoid SCO's pty driver and use this.
-- 
Chip Salzenberg                   <chip@ateng.com> or <uunet!ateng!chip>
A T Engineering                     "Designed with your mind in mind."
--
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  Makefile INSTALL MKDEVS Makefile PTYCNT README.SCO pty.c
# Wrapped by chip@ateng on Mon Feb 13 17:51:07 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(357 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X#
X# Uncomment the definition of FOR286 if you are compling for Xenix/286.
X#
X#FOR286  = -LARGE -M2em
XCFLAGS  = ${FOR286} -O -K -DM_KERNEL ${DEFS}
X
Xall:    pty.o
Xinstall: pty.o
X	./INSTALL
Xclean:
X	rm pty.o
Xclobber: clean
Xshar:   pty.sh
X
Xpty.o:  pty.c PTYCNT
X	$(CC) $(CFLAGS) -c pty.c
X
Xpty.sh:
X	shar Makefile INSTALL MKDEVS Makefile PTYCNT README.SCO pty.c >$@
END_OF_FILE
if test 357 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'INSTALL' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'INSTALL'\"
else
echo shar: Extracting \"'INSTALL'\" \(1896 characters\)
sed "s/^X//" >'INSTALL' <<'END_OF_FILE'
X: INSTALL
X# Xenix pty installation.
X
Xif [ ! -f /etc/systemid ]
Xthen
X	echo "This is not a Xenix system" 1>&2
X	exit 1
Xfi
X
Xif [ ! -f pty.o ]
Xthen
X	echo "you must make pty.o before running INSTALL" 1>&2
X	exit 1
Xfi
X
XPATH=/usr/sys/conf:$PATH; export PATH
X
Xcp pty.o /usr/sys/conf
X
X# NOTE!!!!!!!!!!!!!!
X# To change the number of ptys, change the value in PTYCNT
X
XPTYCNT=`sed -n 's/.*PTYCNT//p' PTYCNT`
XMASTERMINOR=`sed -n 's/.*MASTERMINOR//p' PTYCNT`
X
Xcd /usr/sys/conf
X
X# get the first available major number.
X
XPTYMAJOR=0
X
Xfor i in `majorsinuse`
Xdo
X   [ $i != $PTYMAJOR ] && break
X   PTYMAJOR=`expr $i + 1`
Xdone
X
Xconfigure -a ptyopen ptyclose ptyread ptywrite ptyioctl -m $PTYMAJOR -c
X
Xif [ $? -ne 0 ]
Xthen
X	echo "pty cannot be added to the master file" 1>&2
X	exit 1
Xfi
X
Xif [ $? -ne 0 ]
Xthen
X	echo "support files not updated" 1>&2
X	exit 1
Xfi
X
X# make the pty device files in /dev
X
XLETTER=p
X
Xcnt=0
Xwhile [ $cnt -lt $PTYCNT ]
Xdo
X	for y in 0 1 2 3 4 5 6 7 8 9 a b c d e f
X	do
X		i=$LETTER$y
X		if [ $cnt -ge ${PTYCNT} ] 
X		then 
X			break
X		fi
X
X		[ -c /dev/pty$i ] && rm -f /dev/pty$i
X		[ -c /dev/tty$i ] && rm -f /dev/tty$i
X
X		/etc/mknod /dev/pty$i c ${PTYMAJOR} \
X			`expr $cnt + $MASTERMINOR` &&
X		/etc/mknod /dev/tty$i c ${PTYMAJOR} $cnt ||
X		exit 1
X		chmod 666 /dev/pty$i /dev/tty$i
X		chown root /dev/pty$i /dev/tty$i
X		chgrp root /dev/pty$i /dev/tty$i
X
X		cnt=`expr $cnt + 1`
X	done
X	LETTER=`echo $LETTER | tr '[a-z][A-Y]' '[b-z][A-Z]'`
Xdone
X
X# add pty.o to the link_xenix script
X
Xif fgrep pty.o link_xenix >/dev/null
Xthen
X	: fine
Xelse
X	ed - link_xenix <<'-EOF'
X	/kid\.o/s//kid.o pty.o/
X	w
X	EOF
Xfi
X
X# relink the kernel
X
Xsh -v link_xenix || exit 1
X
X# tell the user what to do next
X
Xecho ""
Xecho "The new kernel with ptys has been linked as /usr/sys/conf/xenix."
Xecho "To make this kernel the default, type the following commands:"
Xecho "    mv /xenix /xenix.prev"
Xecho "    ln /usr/sys/conf/xenix /"
Xecho ""
END_OF_FILE
if test 1896 -ne `wc -c <'INSTALL'`; then
    echo shar: \"'INSTALL'\" unpacked with wrong size!
fi
chmod +x 'INSTALL'
# end of 'INSTALL'
fi
if test -f 'MKDEVS' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MKDEVS'\"
else
echo shar: Extracting \"'MKDEVS'\" \(697 characters\)
sed "s/^X//" >'MKDEVS' <<'END_OF_FILE'
X# make the pty device files in /dev
X
XPTYCNT=`sed -n 's/.*PTYCNT//p' PTYCNT`
XMASTERMINOR=`sed -n 's/.*MASTERMINOR//p' PTYCNT`
X
XPTYMAJOR=10
XLETTER=p
X
Xcnt=0
Xwhile [ $cnt -lt $PTYCNT ]
Xdo
X	for y in 0 1 2 3 4 5 6 7 8 9 a b c d e f
X	do
X		i=$LETTER$y
X		if [ $cnt -ge ${PTYCNT} ] 
X		then 
X			break
X		fi
X
X		[ -c /dev/pty$i ] && rm -f /dev/pty$i
X		[ -c /dev/tty$i ] && rm -f /dev/tty$i
X
X		/etc/mknod /dev/pty$i c ${PTYMAJOR} \
X			`expr $cnt + $MASTERMINOR` &&
X		/etc/mknod /dev/tty$i c ${PTYMAJOR} $cnt ||
X		exit 1
X		chmod 666 /dev/pty$i /dev/tty$i
X		chown root /dev/pty$i /dev/tty$i
X		chgrp root /dev/pty$i /dev/tty$i
X
X		cnt=`expr $cnt + 1`
X	done
X	LETTER=`echo $LETTER | tr '[a-z][A-Y]' '[b-z][A-Z]'`
Xdone
END_OF_FILE
if test 697 -ne `wc -c <'MKDEVS'`; then
    echo shar: \"'MKDEVS'\" unpacked with wrong size!
fi
chmod +x 'MKDEVS'
# end of 'MKDEVS'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(357 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X#
X# Uncomment the definition of FOR286 if you are compling for Xenix/286.
X#
X#FOR286  = -LARGE -M2em
XCFLAGS  = ${FOR286} -O -K -DM_KERNEL ${DEFS}
X
Xall:    pty.o
Xinstall: pty.o
X	./INSTALL
Xclean:
X	rm pty.o
Xclobber: clean
Xshar:   pty.sh
X
Xpty.o:  pty.c PTYCNT
X	$(CC) $(CFLAGS) -c pty.c
X
Xpty.sh:
X	shar Makefile INSTALL MKDEVS Makefile PTYCNT README.SCO pty.c >$@
END_OF_FILE
if test 357 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'PTYCNT' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'PTYCNT'\"
else
echo shar: Extracting \"'PTYCNT'\" \(131 characters\)
sed "s/^X//" >'PTYCNT' <<'END_OF_FILE'
X/* be careful; this file is read and used by the INSTALL script */
X#define PTYCNT 32
X#define MASTERMINOR 128
X#define MASTERBIT 128
END_OF_FILE
if test 131 -ne `wc -c <'PTYCNT'`; then
    echo shar: \"'PTYCNT'\" unpacked with wrong size!
fi
# end of 'PTYCNT'
fi
if test -f 'README.SCO' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README.SCO'\"
else
echo shar: Extracting \"'README.SCO'\" \(1521 characters\)
sed "s/^X//" >'README.SCO' <<'END_OF_FILE'
XPublic domain pty driver originally written by:
X
XCopyright (c) 1987, Jens-Uwe Mager, FOCUS Computer GmbH
X
XMods (for 3b1) by:
X
X	Eric H. Herrin II
X	University of Kentucky Mathematical Sciences Laboratories
X 	915 Patterson Office Tower
X	University of Kentucky
X	Lexington, KY 40506
X	eric@ms.uky.edu, eric@ms.uky.csnet, !cbosgd!ukma!eric
X
X	Also modified by:
X	Mike "Ford" Ditto
X	Chief Executive Hacker, Omnicron Data Systems
X	P.O. Box 1721
X	Bonita, CA 92002
X	(619) 421-1055
X	kenobi!ford@crash.CTS.COM, ...!crash!kenobi!ford
X
X	Modifications for SCO XENIX {2,3}86 by:
X	Keith Gabryelski
X	UUCP: {cbosgd, hplabs!hp-sdd, sdcsvax, nosc}!crash!portnoy!ag
X	INET: ag@portnoy.cts.com
X	ARPA: crash!portnoy!ag@nosc.mil
X
X	Further modifications to Xenix installation by:
X	Chip Salzenberg
X	A T Engineering
X	<chip@ateng.com> or <uunet!ateng!chip>
X
X
XPick a directory for this software to reside.  Mine was /usr/sys/conf/pty.
Xuntar and uncompress (if need be) and look at the Makefile.  Uncomment
Xthe definition of FOR286 if you are using a 286 machine.
X
X	make
X
XIf that worked, try:
X
X	make install
X
XThen, if that worked, follow the displayed directions.  When you reboot your
Xmachine, you should have pty's.
X
XTo test:
X	compile emacs with:
X
X		#define FIRST_PTY_LETTER 'p'
X		#define HAVE_PTYS
X		#define subprocesses
X
X	and try:
X		M-x shell
X
X	When you get a shell prompt try:
X		tty	(and)
X		stty -a
X
X	You should be on a tty named "ttyp0" or something real similar.
X
XOr:
X	cat /dev/ttyp0 &
X	date > /dev/ptyp0
X
X		(This should print the date)
X
XPax, Keith
END_OF_FILE
if test 1521 -ne `wc -c <'README.SCO'`; then
    echo shar: \"'README.SCO'\" unpacked with wrong size!
fi
# end of 'README.SCO'
fi
if test -f 'pty.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'pty.c'\"
else
echo shar: Extracting \"'pty.c'\" \(12061 characters\)
sed "s/^X//" >'pty.c' <<'END_OF_FILE'
X
X
X/*
X * pty.c - Berkeley style pseudo tty driver for system V
X *
X * Copyright (c) 1987, Jens-Uwe Mager, FOCUS Computer GmbH
X * Not derived from licensed software.
X *
X * Permission is granted to freely use, copy, modify, and redistribute
X * this software, provided that no attempt is made to gain profit from it,
X * the author is not construed to be liable for any results of using the
X * software, alterations are clearly marked as such, and this notice is
X * not modified.
X */
X
X/*
X * Modified for use on the UnixPC by:
X * Eric H. Herrin II
X * University of Kentucky Mathematical Sciences Laboratories
X * eric@ms.uky.edu, eric@ms.uky.csnet, !cbosgd!ukma!eric
X *
X * Further modified and improved by:
X * Mike "Ford" Ditto
X * Chief Executive Hacker, Omnicron Data Systems
X * kenobi!ford@crash.CTS.COM, ...!crash!kenobi!ford
X *
X * See README.3b1 for details of port and installation.
X */
X
X/*
X * Yet more geefing done by:
X * Keith M. Gabryelski
X * Random
X * ...crash!portnoy!ag, ag@portnoy.cts.com
X *
X * See README.SCO for detials of port and installation.
X */
X /* XON, XOFF control flow added by Bob Best (bob@dhw68k.cts.com)
X    6/13/88
X*/
X
X/* The UnixPC does not have any extra bits in t_state, thus
X * we provide other means of storing the state.
X */
X#define MRWAIT	0x01				/* master waiting in read */
X#define t_rloc	t_cc[0]				/* wchannel for MRWAIT */
X#define MWWAIT	0x02				/* master waiting in write */
X#define t_wloc	t_cc[1]				/* wchannel for MWWAIT */
X#define MOPEN	0x04				/* master is open */
X#define SOPEN	0x08				/* slave is open */
X
X#define KERNEL		1
X#define defined_io	1
X
X#include "sys/param.h"
X#include "sys/types.h"
X#include "sys/sysmacros.h"
X#include "sys/systm.h"
X#include "sys/file.h"
X#include "sys/conf.h"
X#include "sys/page.h"		/* structure defs --kmg */
X#include "sys/dir.h"		/* structure defs --kmg */
X#include "sys/seg.h"		/* structure defs --kmg */
X#include "sys/proc.h"
X#include "sys/tty.h"
X#include "sys/signal.h"
X#include "sys/user.h"
X#include "sys/errno.h"
X/* #include "sys/termio.h"	/* included in sys/tty.h --kmg */
X#include "sys/ttold.h"
X
X#define	eprintf	printf		/* So what do ya want, whicker? */
X
X#include "PTYCNT"		/* find out about PTYCNT and MASTERMINOR */
X
X/* PTYCNT is the maximum number of master/slave pairs that will work */
X#ifndef PTYCNT
X#define PTYCNT 32
X#endif
X
X/* MASTERMINOR is the lowest minor device number for master devices */
X#ifndef MASTERMINOR
X#define MASTERMINOR ((minor(0xFFFF)+1)/2)
X#endif
X
X/* This macro is true if the device number passed corresponds to */
X/* the MASTER side of a pty */
X#ifdef MASTERBIT
X#define Master(dev)	((dev)&MASTERBIT)
X#else
X#define Master(dev)	(minor((dev)) >= MASTERMINOR)
X#endif MASTERBIT
X
X/* The tty structures must be local to this driver, since there
X * is no conf.c
X */
X
Xstruct tty pty_tty[PTYCNT];
Xint ptystate[PTYCNT];
X
Xint ptsproc();
X
X
Xptyopen(dev, flag)
X	dev_t		dev;
X	int		flag;
X{
X	register struct tty *tp;
X
X	dev = minor(dev);
X	if (Master(dev)) {
X#		ifdef DEBUG
X		eprintf("pty: open(master): \n");
X#		endif
X		dev -= MASTERMINOR;
X		tp = &pty_tty[dev];
X		if (dev >= PTYCNT) {
X			u.u_error = ENXIO;
X			return;
X		}
X		/*
X		* allow only one controlling process
X		*/
X		if (ptystate[dev] & MOPEN) {
X			u.u_error = EBUSY;
X			return;
X		}
X		ptystate[dev] |= MOPEN;
X		tp->t_state |= CARR_ON;
X		if (tp->t_state & WOPEN)
X		{
X			tp->t_state &= ~WOPEN;
X			wakeup((caddr_t)&tp->t_canq);
X		}
X	} else {
X#		ifdef DEBUG
X		eprintf("pty: open(slave): \n");
X#		endif
X		tp = &pty_tty[dev];
X		if (dev >= PTYCNT) {
X			u.u_error = ENXIO;
X			return;
X		}
X		if ((tp->t_state & (ISOPEN|WOPEN)) == 0) {
X			ttinit(tp);
X			tp->t_proc = ptsproc;
X		}
X		/*
X		 * if master is still open, don't wait for carrier
X		 */
X		if (!(flag & FNDELAY)) {
X			while ((tp->t_state & CARR_ON) == 0) {
X				/* eprintf("slave_open going to sleep!"); */
X				tp->t_state |= WOPEN;
X				if (sleep((caddr_t)&tp->t_canq, TTIPRI|PCATCH)) {
X					tp->t_state &= ~WOPEN;
X					wakeup((caddr_t)&tp->t_canq);
X					/* eprintf("slave open: interrupted"); */
X					u.u_error = EINTR;
X					return;
X				}
X				/* eprintf("slave_open woke up! %x %x",
X					tp->t_state, u.u_procp->p_sig); */
X			}
X		}
X		ptystate[dev] |= SOPEN;
X		(*linesw[tp->t_line].l_open)(tp);
X	}
X}
X
Xptyclose(dev, flag)
X	dev_t		dev;
X	int		flag;
X{
X	register struct tty *tp;
X
X	dev = minor(dev);
X	if (Master(dev)) {
X#		ifdef DEBUG
X		eprintf("pty: close(master): \n");
X#		endif
X		dev -= MASTERMINOR;
X		tp = &pty_tty[dev];
X		if (!(ptystate[dev] & SOPEN)) {
X			tp->t_tbuf.c_size  -= tp->t_tbuf.c_count;
X			tp->t_tbuf.c_count = 0;
X			tp->t_rbuf.c_size  -= tp->t_rbuf.c_count;
X			tp->t_rbuf.c_count = 0;
X			(*linesw[tp->t_line].l_close)(tp);
X		} else {
X			signal(tp->t_pgrp, SIGHUP);
X			ttyflush(tp, FREAD|FWRITE);
X		}
X		/*
X		 * virtual carrier gone
X		 */
X		tp->t_state &= ~(CARR_ON);
X		ptystate[dev] &= ~MOPEN;
X	} else {
X#		ifdef DEBUG
X		eprintf("pty: close(slave): \n");
X#		endif
X		tp = &pty_tty[dev];
X		if (!(ptystate[dev] & MOPEN)) {
X			tp->t_tbuf.c_size  -= tp->t_tbuf.c_count;
X			tp->t_tbuf.c_count = 0;
X			tp->t_rbuf.c_size  -= tp->t_rbuf.c_count;
X			tp->t_rbuf.c_count = 0;
X			(*linesw[tp->t_line].l_close)(tp);
X		}
X		ptystate[dev] &= ~SOPEN;
X		if (ptystate[dev] & MRWAIT)
X		{
X			ptystate[dev] &= ~MRWAIT;
X			wakeup((caddr_t)&tp->t_rloc);
X		}
X		if (ptystate[dev] & MWWAIT)
X		{
X			ptystate[dev] &= ~MRWAIT;
X			wakeup((caddr_t)&tp->t_wloc);
X		}
X	}
X}
X
Xptyread(dev)
X	dev_t		dev;
X{
X	register struct tty *tp;
X	register n;
X
X	dev = minor(dev);
X	if (Master(dev)) {
X		int didsome=0;
X#		ifdef DEBUG
X		eprintf("pty: read(master): \n");
X#		endif
X		dev -= MASTERMINOR;
X		tp = &pty_tty[dev];
X		while (u.u_count) {
X			ptsproc(tp, T_OUTPUT);
X			if ((tp->t_state & (TTSTOP|TIMEOUT))
X			    || tp->t_tbuf.c_ptr == NULL || tp->t_tbuf.c_count == 0) {
X				if (didsome)
X					break;
X				if ((ptystate[dev] & SOPEN) == 0) {
X					u.u_error = EIO;
X					return;
X				}
X				if (u.u_fmode & FNDELAY)
X					break;
X#				ifdef DEBUG
X				eprintf("pty: read(master): master going to sleep\n");
X#				endif
X				ptystate[dev] |= MRWAIT;
X				sleep((caddr_t)&tp->t_rloc, TTIPRI);
X#				ifdef DEBUG
X				eprintf("pty: read(master): master woke up\n");
X#				endif
X
X				continue;
X			}
X			n = min(u.u_count, tp->t_tbuf.c_count);
X			if (n) {
X#				ifdef DEBUG
X				eprintf("pty: read(master): got some stuff\n");
X#				endif
X				++didsome;
X				if (copyout(tp->t_tbuf.c_ptr, u.u_base, n)) {
X					u.u_error = EFAULT;
X					break;
X				}
X				tp->t_tbuf.c_count -= n;
X				tp->t_tbuf.c_ptr += n;
X				u.u_base += n;
X				u.u_count -= n;
X			}
X		}
X	} else {
X#		ifdef DEBUG
X		eprintf("pty: read(slave): \n");
X#		endif
X		tp = &pty_tty[dev];
X#		ifdef DEBUG
X		eprintf("pty: read(slave): got some stuff\n");
X#		endif
X		(*linesw[tp->t_line].l_read)(tp);
X	}
X}
X
Xptywrite(dev)
X	dev_t		dev;
X{
X	register struct tty *tp;
X	register n;
X	int flg;
X
X	dev = minor(dev);
X	if (Master(dev)) {
X#		ifdef DEBUG
X		eprintf("pty: write(master): \n");
X#		endif
X		dev -= MASTERMINOR;
X		tp = &pty_tty[dev];
X		while (u.u_count) {
X			if ((tp->t_state & TBLOCK)
X			    || tp->t_rbuf.c_ptr == NULL) {
X				if ((ptystate[dev] & SOPEN) == 0) {
X					u.u_error = EIO;
X					return;
X				}
X				if (u.u_fmode & FNDELAY)
X					break;
X				ptystate[dev] |= MWWAIT;
X#				ifdef DEBUG
X				eprintf("pty: write(master): going to sleep\n");
X#				endif
X
X				sleep((caddr_t)&tp->t_wloc, TTOPRI);
X
X#				ifdef DEBUG
X				eprintf("pty: write: waking up\n");
X#				endif
X
X				continue;
X			}
X			n = min(u.u_count, tp->t_rbuf.c_count);
X			if (n) {
X#				ifdef DEBUG
X				eprintf("pty: write(master): sending some stuff\n");
X#				endif
X				flg=tp->t_iflag;
X				if(flg & IXON) {
X					char ctmp;
X					copyin(u.u_base, &ctmp, 1);
X					ctmp &= 0177;
X					if(tp->t_state & TTSTOP) {
X						if(ctmp==CSTART || flg & IXANY)
X						(*tp->t_proc)(tp,T_RESUME);
X					} else if(ctmp==CSTOP) {
X						(*tp->t_proc)(tp,T_SUSPEND);
X					}
X					if(ctmp==CSTART || ctmp==CSTOP) {
X						u.u_base++;
X						u.u_count--;
X						continue;
X					}
X				}
X				if (copyin(u.u_base,tp->t_rbuf.c_ptr, 1)) {
X					u.u_error = EFAULT;
X					break;
X				}
X				tp->t_rbuf.c_count--;
X				u.u_base++;
X				u.u_count--;
X			}
X			(*linesw[tp->t_line].l_input)(tp);
X		}
X	} else {
X#		ifdef DEBUG
X		eprintf("pty: write(slave): \n");
X#		endif
X		tp = &pty_tty[dev];
X#		ifdef DEBUG
X		eprintf("pty: write(slave): sending some stuff\n");
X#		endif
X		(*linesw[tp->t_line].l_write)(tp);
X	}
X}
X
Xptyioctl(dev, cmd, arg, mode)
X	dev_t		dev;
X	int		cmd, arg, mode;
X{
X	register struct tty *tp;
X
X	dev = minor(dev);
X	if (Master(dev)) {
X#		ifdef DEBUG
X		eprintf("pty: ioctl(master): \n");
X#		endif
X		dev -= MASTERMINOR;
X		tp = &pty_tty[dev];
X		/*
X		 * sorry, but we can't fiddle with the tty struct without
X		 * having done LDOPEN
X		 */
X		if (tp->t_state & ISOPEN) {
X			if (cmd == TCSBRK && arg == 0) {	/* 0 was NULL
X								   --kmg */
X				signal(tp->t_pgrp, SIGINT);
X				if ((tp->t_iflag & NOFLSH) == 0)
X					ttyflush(tp, FREAD|FWRITE);
X			} else {
X				/*
X				 * we must flush output to avoid hang in ttywait
X				 */
X				if (cmd == TCSETAW || cmd == TCSETAF ||
X				   cmd == TCSBRK || cmd == TIOCSETP)
X					ttyflush(tp, FWRITE);
X				ttiocom(tp, cmd, arg, mode);
X			}
X		} else
X			u.u_error = EINVAL;
X	} else {
X#		ifdef DEBUG
X		eprintf("pty: ioctl(slave): \n");
X#		endif
X		tp = &pty_tty[dev];
X		ttiocom(tp, cmd, arg, mode);
X	}
X}
X
Xptsproc(tp, cmd)
Xregister struct tty *tp;
X{
X	register struct ccblock *tbuf;
X	extern ttrstrt();
X
X	switch (cmd) {
X	case T_TIME:
X#		ifdef DEBUG
X		eprintf("pty: ptsproc: T_TIME:\n");
X#		endif
X		tp->t_state &= ~TIMEOUT;
X		goto start;
X	case T_WFLUSH:
X#		ifdef DEBUG
X		eprintf("pty: ptsproc: T_WFLUSH:\n");
X#		endif
X		tp->t_tbuf.c_size  -= tp->t_tbuf.c_count;
X		tp->t_tbuf.c_count = 0;
X		/* fall through */
X	case T_RESUME:
X#		ifdef DEBUG
X		eprintf("pty: ptsproc: T_RESUME:\n");
X#		endif
X		tp->t_state &= ~TTSTOP;
X		/* fall through */
X	case T_OUTPUT:
Xstart:
X#		ifdef DEBUG
X		eprintf("pty: ptsproc: T_OUTPUT:\n");
X#		endif
X		if (tp->t_state & (TTSTOP|TIMEOUT))
X			break;
X#		ifdef DEBUG
X		eprintf("pty: ptsproc: T_OUTPUT: past(TTSTOP|TIMEOUT)");
X#		endif
X		tbuf = &tp->t_tbuf;
X		if (tbuf->c_ptr == NULL || tbuf->c_count == 0) {
X#		ifdef DEBUG
X		eprintf("pty: ptsproc: T_OUTPUT: tbuf empty, may break\n");
X#		endif
X			if (tbuf->c_ptr)
X				tbuf->c_ptr -= tbuf->c_size;
X			if (!(CPRES & (*linesw[tp->t_line].l_output)(tp)))
X				break;
X		}
X		if (tbuf->c_count && (ptystate[tp-pty_tty] & MRWAIT)) {
X#		ifdef DEBUG
X		eprintf("pty: ptsproc: T_OUTPUT: waking up master\n");
X#		endif
X			ptystate[tp-pty_tty] &= ~MRWAIT;
X			wakeup((caddr_t)&tp->t_rloc);
X		}
X#		ifdef DEBUG
X		eprintf("pty: ptsproc: T_OUTPUT: leaving end\n");
X#		endif
X		break;
X	case T_SUSPEND:
X#		ifdef DEBUG
X		eprintf("pty: ptsproc: T_SUSPEND:\n");
X#		endif
X		tp->t_state |= TTSTOP;
X		break;
X	case T_BLOCK:
X#		ifdef DEBUG
X		eprintf("pty: ptsproc: T_BLOCK:\n");
X#		endif
X		/*
X		 * the check for ICANON appears to be neccessary
X		 * to avoid a hang when overflowing input
X		 */
X		if ((tp->t_iflag & ICANON) == 0)
X			tp->t_state |= TBLOCK;
X		break;
X	case T_BREAK:
X#		ifdef DEBUG
X		eprintf("pty: ptsproc: T_BREAK:\n");
X#		endif
X		tp->t_state |= TIMEOUT;
X		timeout(ttrstrt, tp, HZ/4);
X		break;
X#ifdef T_LOG_FLUSH
X	case T_LOG_FLUSH:
X#endif
X	case T_RFLUSH:
X#		ifdef DEBUG
X		eprintf("pty: ptsproc: T_RFLUSH:\n");
X#		endif
X		if (!(tp->t_state & TBLOCK))
X			break;
X		/* fall through */
X	case T_UNBLOCK:
X#		ifdef DEBUG
X		eprintf("pty: ptsproc: T_UNBLOCK:\n");
X#		endif
X		tp->t_state &= ~(TTXOFF|TBLOCK);
X		/* fall through */
X	case T_INPUT:
X#		ifdef DEBUG
X		eprintf("pty: ptsproc: T_INPUT:\n");
X#		endif
X		if (ptystate[tp-pty_tty] & MWWAIT) {
X			ptystate[tp-pty_tty] &= ~MWWAIT;
X#			ifdef DEBUG
X			eprintf("pty: ptsproc: T_INPUT: waking up master\n");
X#			endif
X			wakeup((caddr_t)&tp->t_wloc);
X		}
X		break;
X	default:
X#		ifdef DEBUG
X		eprintf("pty: ptsproc: default:\n");
X#		else
X		;
X#		endif
X	}
X}
X
X/*	PTYRELEASE is a 3b1ism.
X *
X * ptyrelease()
X * {
X *	register i;
X * #	ifdef DEBUG
X *	eprintf("pty: ptyrelease:\n");
X * #	endif
X *	for ( i=0 ; i<PTYCNT ; ++i )
X *		if ( (ptystate[i] & (SOPEN|MOPEN))
X *		   || (pty_tty[i].t_state & WOPEN) )
X *		{
X *			u.u_error = EBUSY;
X *			return;
X *		}
X *	return;
X * }
X */
END_OF_FILE
if test 12061 -ne `wc -c <'pty.c'`; then
    echo shar: \"'pty.c'\" unpacked with wrong size!
fi
# end of 'pty.c'
fi
echo shar: End of shell archive.
exit 0