summaryrefslogtreecommitdiffstats
path: root/sys/kern/tty_pts.c
diff options
context:
space:
mode:
authored <ed@FreeBSD.org>2008-09-23 17:12:25 +0000
committered <ed@FreeBSD.org>2008-09-23 17:12:25 +0000
commit94258be42159763be6d3f064301d04f129edda8b (patch)
tree7df69923e5d79867c0f1c00c015f8348964ddbf3 /sys/kern/tty_pts.c
parent081d7d9aba077c1d2fb8cc4a1a0374c0a3927cf0 (diff)
downloadFreeBSD-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.c23
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,
OpenPOWER on IntegriCloud