diff options
author | ed <ed@FreeBSD.org> | 2008-09-23 17:12:25 +0000 |
---|---|---|
committer | ed <ed@FreeBSD.org> | 2008-09-23 17:12:25 +0000 |
commit | 94258be42159763be6d3f064301d04f129edda8b (patch) | |
tree | 7df69923e5d79867c0f1c00c015f8348964ddbf3 /sys/kern/tty_pts.c | |
parent | 081d7d9aba077c1d2fb8cc4a1a0374c0a3927cf0 (diff) | |
download | FreeBSD-src-94258be42159763be6d3f064301d04f129edda8b.zip FreeBSD-src-94258be42159763be6d3f064301d04f129edda8b.tar.gz |
Track state to determine if the associated TTY device node has been used.
It turns out our old TTY layer (and other implementations) block when
you read() on a PTY master device of which the slave device node has not
been opened yet. Our new implementation just returned 0. This caused
applications like telnetd to die in a very subtle way (when child
processes would open the TTY later than the first call to select()).
Introduce a new flag called PTS_FINISHED, which indicates whether we
should block or bail out of a read() or write() occurs.
Reported by: Claude Buisson <clbuisson orange fr>
Diffstat (limited to 'sys/kern/tty_pts.c')
-rw-r--r-- | sys/kern/tty_pts.c | 23 |
1 files changed, 19 insertions, 4 deletions
diff --git a/sys/kern/tty_pts.c b/sys/kern/tty_pts.c index 95bab99..d6f10f3 100644 --- a/sys/kern/tty_pts.c +++ b/sys/kern/tty_pts.c @@ -81,7 +81,8 @@ static MALLOC_DEFINE(M_PTS, "pts", "pseudo tty device"); struct pts_softc { int pts_unit; /* (c) Device unit number. */ unsigned int pts_flags; /* (t) Device flags. */ -#define PTS_PKT 0x1 /* Packet mode. */ +#define PTS_PKT 0x1 /* Packet mode. */ +#define PTS_FINISHED 0x2 /* Return errors on read()/write(). */ char pts_pkt; /* (t) Unread packet mode data. */ struct cv pts_inwait; /* (t) Blocking write() on master. */ @@ -156,7 +157,7 @@ ptsdev_read(struct file *fp, struct uio *uio, struct ucred *active_cred, } /* Maybe the device isn't used anyway. */ - if (tty_opened(tp) == 0) + if (psc->pts_flags & PTS_FINISHED) break; /* Wait for more data. */ @@ -224,7 +225,7 @@ ptsdev_write(struct file *fp, struct uio *uio, struct ucred *active_cred, } /* Maybe the device isn't used anyway. */ - if (tty_opened(tp) == 0) { + if (psc->pts_flags & PTS_FINISHED) { error = EIO; goto done; } @@ -380,7 +381,7 @@ ptsdev_poll(struct file *fp, int events, struct ucred *active_cred, tty_lock(tp); - if (tty_opened(tp) == 0) { + if (psc->pts_flags & PTS_FINISHED) { /* Slave device is not opened. */ tty_unlock(tp); return (events & @@ -503,13 +504,26 @@ ptsdrv_inwakeup(struct tty *tp) selwakeup(&psc->pts_inpoll); } +static int +ptsdrv_open(struct tty *tp) +{ + struct pts_softc *psc = tty_softc(tp); + + psc->pts_flags &= ~PTS_FINISHED; + + return (0); +} + static void ptsdrv_close(struct tty *tp) { + struct pts_softc *psc = tty_softc(tp); /* Wake up any blocked readers/writers. */ ptsdrv_outwakeup(tp); ptsdrv_inwakeup(tp); + + psc->pts_flags |= PTS_FINISHED; } static void @@ -565,6 +579,7 @@ static struct ttydevsw pts_class = { .tsw_flags = TF_NOPREFIX, .tsw_outwakeup = ptsdrv_outwakeup, .tsw_inwakeup = ptsdrv_inwakeup, + .tsw_open = ptsdrv_open, .tsw_close = ptsdrv_close, .tsw_pktnotify = ptsdrv_pktnotify, .tsw_free = ptsdrv_free, |