Fixes enclosed for public domain System V pty driver.
Michael Bloom
mb at ttidca.TTI.COM
Mon Feb 22 11:43:45 AEST 1988
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
More information about the Comp.sources.bugs
mailing list