[comp.emacs] Fixes enclosed for public domain System V pty driver.

mb@ttidca.TTI.COM (Michael Bloom) (02/22/88)

Index:	Public Domain Pty Driver Bugs and Fixes

Note: This is being cross posted to comp.emacs because of the usefulness
of pty's to emacs.  Please, no flames.

Description:
	There were several problems with the previously posted public domain
	pty driver. 

	First, it was trying to use "unused bits" in t_state. Unfortunately,
	the existence of these unused bits assumes that t_state is long.
	On most 5r3 systems (I don't know about 5r2), however, it is a short.

	Second, the driver was assuming that only the minor device
	gets passed. While perhaps true on the tower, this is again
	not true on other ports. (In fact it can be a *pain* on the
	tower if you have drivers that use extra major devices to
	simulate minors > 255). 

	Finally, there was a bug in which a read on the master device
	could hang in ttywait. This would happen if the slave had written
	some data and then closed his side before the master could read it.
	The fix for this is in the beginning of ptmread.

Repeat-by:
	Don't bother.  The original code could not have worked at all
	on most systems.
Fix:
	The changes I made to the original posted code are entirely
	within ifdefs.  This clearly marks the changes I have made (so
	as to comply with the author's request to do so).  Because of
	this, the diff file is a little bigger than the original
	(pretty small) source 	file. So instead of diffs, I'm sending
	out the replacement in it's entirety.

	Clip out the following shar file and run it through sh to get
	a replacement for pty.c.  In conf.c, declate pts_state to have the
	same number of elements as pts_tty. pts_cnt should also be
	initialized to the same number.	

------- CUT HERE ----
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	pty.c
# This archive created: Sun Feb 21 16:43:44 1988
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'pty.c'" '(9410 characters)'
if test -f 'pty.c'
then
	echo shar: "will not over-write existing file 'pty.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'pty.c'
	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#define TTI			/* comment this define out for the original
	X				 * posted code
	X				 */
	X#ifndef TTI
	X/*
	X * the following are arbitrary 3 unused bits from t_state
	X * in sys/tty.h
	X */
	X#endif TTI
	X
	X#ifndef TTI
	X#define MRWAIT	01000000	/* master waiting in read */
	X#else TTI
	X#define MRWAIT	01		/* master waiting in read */
	X#endif TTI
	X#define t_rloc	t_cc[0]		/* rchannel */
	X
	X#ifndef TTI
	X#define MWWAIT	02000000	/* master waiting in write */
	X#else TTI
	X#define MWWAIT	02		/* master waiting in write */
	X#endif TTI
	X#define t_wloc	t_cc[1]		/* wchannel */
	X
	X#ifndef TTI
	X#define MOPEN	04000000	/* master is open */
	X#else TTI
	X#define MOPEN	04		/* master is open */
	X#endif TTI
	X
	X#include "sys/param.h"
	X#include "sys/types.h"
	X#include "sys/sysmacros.h"
	X#include "sys/seg.h"
	X#include "sys/page.h"
	X#include "sys/systm.h"
	X#include "sys/file.h"
	X#include "sys/conf.h"
	X
	X#ifndef tower
	X#ifdef TTI
	X#include "sys/immu.h"
	X#endif TTI
	X#include "sys/region.h"
	X#endif
	X
	X#include "sys/proc.h"
	X#include "sys/dir.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"
	X#include "sys/ttold.h"
	X
	X/*
	X * from config
	X */
	Xextern struct tty pts_tty[];
	X
	X#ifdef TTI
	Xextern int pts_state[];
	X#endif TTI
	Xextern int pts_cnt;
	X
	X/*
	X * slave side is a fairly standard system V tty driver
	X */
	X#ifndef TTI
	Xptsopen(dev, flag)
	X#else TTI
	Xptsopen(fdev, flag)
	X#endif TTI
	X{
	X#ifdef TTI
	X	register dev = minor(fdev);
	X#endif TTI
	X	register struct tty *tp = &pts_tty[dev];
	X	extern int ptsproc();
	X
	X	if (dev >= pts_cnt) {
	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#ifndef TTI
	X	if (tp->t_state & MOPEN)
	X#else TTI
	X	if (pts_state[dev] & MOPEN)
	X#endif TTI
	X		tp->t_state |= CARR_ON;
	X	if (!(flag & FNDELAY)) {
	X		while ((tp->t_state & CARR_ON) == 0) {
	X			tp->t_state |= WOPEN;
	X			sleep((caddr_t)&tp->t_canq, TTIPRI);
	X		}
	X	}
	X	(*linesw[tp->t_line].l_open)(tp);
	X}
	X
	X#ifndef TTI
	Xptswrite(dev)
	X#else TTI
	Xptswrite(fdev)
	X#endif TTI
	X{
	X#ifdef TTI
	X	register dev = minor(fdev);
	X#endif TTI
	X	register struct tty *tp = &pts_tty[dev];
	X
	X#ifdef TTI
	X#ifdef DEBUG
	X		printf("T_TIME\n");
	X#endif
	X
	X#endif TTI
	X	(*linesw[tp->t_line].l_write)(tp);
	X}
	X
	X#ifndef TTI
	Xptsread(dev)
	X#else TTI
	Xptsread(fdev)
	X#endif TTI
	X{
	X#ifdef TTI
	X	register dev = minor(fdev);
	X#endif TTI
	X	register struct tty *tp = &pts_tty[dev];
	X
	X	(*linesw[tp->t_line].l_read)(tp);
	X}
	X
	X#ifndef TTI
	Xptsclose(dev)
	X#else TTI
	Xptsclose(fdev)
	X#endif TTI
	X{
	X#ifdef TTI
	X	register dev = minor(fdev);
	X#endif TTI
	X	register struct tty *tp = &pts_tty[dev];
	X	
	X	(*linesw[tp->t_line].l_close)(tp);
	X	tp->t_state &= ~CARR_ON;
	X}
	X
	X#ifndef TTI
	Xptsioctl(dev, cmd, arg, mode)
	X#else TTI
	Xptsioctl(fdev, cmd, arg, mode)
	X#endif TTI
	X{
	X#ifdef TTI
	X	register dev = minor(fdev);
	X#endif TTI
	X	register struct tty *tp = &pts_tty[dev];
	X
	X	ttiocom(tp, cmd, arg, mode);
	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		printf("T_TIME\n");
	X#endif
	X		tp->t_state &= ~TIMEOUT;
	X		goto start;
	X	case T_WFLUSH:
	X#ifdef DEBUG
	X		printf("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		printf("T_RESUME\n");
	X#endif
	X		tp->t_state &= ~TTSTOP;
	X		/* fall through */
	X	case T_OUTPUT:
	X#ifdef DEBUG
	X		printf("T_OUTPUT\n");
	X#endif
	Xstart:
	X		if (tp->t_state & (TTSTOP|TIMEOUT))
	X			break;
	X		tbuf = &tp->t_tbuf;
	X		if (tbuf->c_ptr == NULL || tbuf->c_count == 0) {
	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#ifndef TTI
	X		if (tbuf->c_count && (tp->t_state & MRWAIT)) {
	X			tp->t_state &= ~MRWAIT;
	X#else TTI
	X		if (tbuf->c_count && (pts_state[tp-pts_tty] & MRWAIT)) {
	X			pts_state[tp-pts_tty] &= ~MRWAIT;
	X#endif TTI
	X			wakeup((caddr_t)&tp->t_rloc);
	X		}
	X		break;
	X	case T_SUSPEND:
	X#ifdef DEBUG
	X		printf("T_SUSPEND\n");
	X#endif
	X		tp->t_state |= TTSTOP;
	X		break;
	X	case T_BLOCK:
	X#ifdef DEBUG
	X		printf("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		printf("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#ifdef DEBUG
	X		printf("T_LOG_FLUSH\n");
	X#endif
	X#endif
	X	case T_RFLUSH:
	X#ifdef DEBUG
	X		printf("T_RFLUSH\n");
	X#endif
	X		if (!(tp->t_state & TBLOCK))
	X			break;
	X		/* fall through */
	X	case T_UNBLOCK:
	X#ifdef DEBUG
	X		printf("T_UNBLOCK\n");
	X#endif
	X		tp->t_state &= ~(TTXOFF|TBLOCK);
	X		/* fall through */
	X	case T_INPUT:
	X#ifdef DEBUG
	X		printf("T_INPUT\n");
	X#endif
	X#ifndef TTI
	X		if (tp->t_state & MWWAIT) {
	X			tp->t_state &= ~MWWAIT;
	X#else TTI
	X		if (pts_state[tp-pts_tty] & MWWAIT) {
	X			pts_state[tp-pts_tty] &= ~MWWAIT;
	X#endif TTI
	X			wakeup((caddr_t)&tp->t_wloc);
	X		}
	X		break;
	X#ifdef DEBUG
	X	default:
	X		printf("ptsproc: cmd %d\n",cmd);
	X#endif
	X	}
	X}
	X
	X/*
	X * master part - not actually like a tty
	X */
	X
	X#ifndef TTI
	Xptmopen(dev, flag)
	X#else TTI
	Xptmopen(fdev, flag)
	X#endif TTI
	X{
	X#ifdef TTI
	X	register dev = minor(fdev);
	X#endif TTI
	X	register struct tty *tp = &pts_tty[dev];
	X
	X#ifdef DEBUG
	X	printf("ptmopen(%d)\n",dev);
	X#endif
	X	if (dev >= pts_cnt) {
	X		u.u_error = ENXIO;
	X		return;
	X	}
	X	/*
	X	 * allow only one controlling process
	X	 */
	X#ifndef TTI
	X	if (tp->t_state & MOPEN) {
	X#else TTI
	X	if (pts_state[dev] & MOPEN) {
	X#endif TTI
	X		u.u_error = EBUSY;
	X		return;
	X	}
	X	if (tp->t_state & WOPEN)
	X		wakeup((caddr_t)&tp->t_canq);
	X#ifndef TTI
	X	tp->t_state |= CARR_ON|MOPEN;
	X#else TTI
	X	tp->t_state |= CARR_ON;
	X	pts_state[dev] |= MOPEN;
	X#endif TTI
	X}
	X
	X#ifndef TTI
	Xptmread(dev)
	X#else TTI
	Xptmread(fdev)
	X#endif TTI
	X{
	X#ifdef TTI
	X	register dev = minor(fdev);
	X#endif TTI
	X	register struct tty *tp = &pts_tty[dev];
	X	register n;
	X
	X#ifndef TTI
	X	if ((tp->t_state & ISOPEN) == 0) {
	X#else TTI
	X	if ((tp->t_state & (ISOPEN|TTIOW)) == 0) {
	X#ifdef DEBUG
	X	printf("ptmread(%d) EIO\n",dev);
	X#endif
	X#endif TTI
	X		u.u_error = EIO;
	X		return;
	X	}
	X#ifdef DEBUG
	X	printf("ptmread(%d)\n",dev);
	X#endif
	X#ifndef TTI
	X	while (u.u_count) {
	X#else TTI
	X	while (u.u_count>0) {
	X#endif TTI
	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 (u.u_fmode & FNDELAY)
	X				break;
	X#ifndef TTI
	X			tp->t_state |= MRWAIT;
	X#else TTI
	X			pts_state[dev] |= MRWAIT;
	X#endif TTI
	X			sleep((caddr_t)&tp->t_rloc, TTIPRI);
	X			continue;
	X		}
	X		n = min(u.u_count, tp->t_tbuf.c_count);
	X		if (n) {
	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}
	X
	X#ifndef TTI
	Xptmwrite(dev)
	X#else TTI
	Xptmwrite(fdev)
	X#endif TTI
	X{
	X#ifdef TTI
	X	register dev = minor(fdev);
	X#endif TTI
	X	register struct tty *tp = &pts_tty[dev];
	X	register n;
	X
	X	if ((tp->t_state & ISOPEN) == 0) {
	X		u.u_error = EIO;
	X		return;
	X	}
	X#ifdef DEBUG
	X	printf("ptmwrite(%d)\n",dev);
	X#endif
	X#ifndef TTI
	X	while (u.u_count) {
	X#else TTI
	X	while (u.u_count>0) {
	X#endif TTI
	X		if ((tp->t_state & TBLOCK) || tp->t_rbuf.c_ptr == NULL) {
	X			if (u.u_fmode & FNDELAY)
	X				break;
	X#ifndef TTI
	X			tp->t_state |= MWWAIT;
	X#else TTI
	X			pts_state[dev] |= MWWAIT;
	X#endif TTI
	X			sleep((caddr_t)&tp->t_wloc, TTOPRI);
	X			continue;
	X		}
	X		n = min(u.u_count, tp->t_rbuf.c_count);
	X		if (n) {
	X			if (copyin(u.u_base,tp->t_rbuf.c_ptr, n)) {
	X				u.u_error = EFAULT;
	X				break;
	X			}
	X			tp->t_rbuf.c_count -= n;
	X			u.u_base += n;
	X			u.u_count -= n;
	X		}
	X#ifndef TTI
	X#ifdef vax
	X#else TTI
	X#ifdef vax || m68k
	X#endif TTI
	X		/*
	X		 * somebody told me this is necessary on the vax
	X		 */
	X		(*linesw[tp->t_line].l_input)(tp, L_BUF);
	X#else
	X		(*linesw[tp->t_line].l_input)(tp);
	X#endif
	X	}
	X}
	X
	X#ifndef TTI
	Xptmclose(dev)
	X#else TTI
	Xptmclose(fdev)
	X#endif TTI
	X{
	X#ifdef TTI
	X	register dev = minor(fdev);
	X#endif TTI
	X	register struct tty *tp = &pts_tty[dev];
	X
	X#ifdef DEBUG
	X	printf("ptmclose(%d)\n",dev);
	X#endif
	X	if (tp->t_state & ISOPEN) {
	X		signal(tp->t_pgrp, SIGHUP);
	X		ttyflush(tp, FREAD|FWRITE);
	X	}
	X	/*
	X	 * virtual carrier gone
	X	 */
	X#ifndef TTI
	X	tp->t_state &= ~(CARR_ON|MOPEN);
	X#else TTI
	X	tp->t_state &= ~CARR_ON;
	X	pts_state[dev] &= ~MOPEN;
	X#endif TTI
	X}
	X
	X#ifndef TTI
	Xptmioctl(dev, cmd, arg, mode)
	X#else TTI
	Xptmioctl(fdev, cmd, arg, mode)
	X#endif TTI
	X{
	X#ifdef TTI
	X	register dev = minor(fdev);
	X#endif TTI
	X	register struct tty *tp = &pts_tty[dev];
	X
	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 ==  NULL) {
	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 || cmd == TCSBRK
	X			    || cmd == TIOCSETP)
	X				ttyflush(FWRITE);
	X			ttiocom(tp, cmd, arg, mode);
	X		}
	X	}
	X}
SHAR_EOF
if test 9410 -ne "`wc -c < 'pty.c'`"
then
	echo shar: "error transmitting 'pty.c'" '(should have been 9410 characters)'
fi
fi
exit 0
#	End of shell archive