From 5a74f403f040e0ca4bab4551aa5dde1b4bcba109 Mon Sep 17 00:00:00 2001 From: visa Date: Wed, 15 Dec 2021 15:30:47 +0000 Subject: [PATCH] Adjust pty and tty event filters * Implement EVFILT_EXCEPT for ttys for HUP condition detection. This filter is used when pollfd.events has no read/write events. * Add HUP condition detection to filt_ptcwrite() and filt_ttywrite() to reflect ptcpoll() and ttpoll(). Only poll(2) and select(2) can utilize the code; kevent(2) should behave as before with EVFILT_WRITE. * Clear EV_EOF and __EV_HUP if the EOF/HUP condition ends. OK mpi@ --- sys/kern/tty.c | 62 +++++++++++++++++++++++++++++++++++++++++++--- sys/kern/tty_pty.c | 26 ++++++++++++++++--- 2 files changed, 80 insertions(+), 8 deletions(-) diff --git a/sys/kern/tty.c b/sys/kern/tty.c index 37e9ab5efbd..ae6cffb56ed 100644 --- a/sys/kern/tty.c +++ b/sys/kern/tty.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tty.c,v 1.172 2021/12/14 15:32:20 visa Exp $ */ +/* $OpenBSD: tty.c,v 1.173 2021/12/15 15:30:47 visa Exp $ */ /* $NetBSD: tty.c,v 1.68.4.2 1996/06/06 16:04:52 thorpej Exp $ */ /*- @@ -78,6 +78,7 @@ int filt_ttyread(struct knote *kn, long hint); void filt_ttyrdetach(struct knote *kn); int filt_ttywrite(struct knote *kn, long hint); void filt_ttywdetach(struct knote *kn); +int filt_ttyexcept(struct knote *kn, long hint); void ttystats_init(struct itty **, int *, size_t *); int ttywait_nsec(struct tty *, uint64_t); int ttysleep_nsec(struct tty *, void *, int, char *, uint64_t); @@ -1110,6 +1111,13 @@ const struct filterops ttywrite_filtops = { .f_event = filt_ttywrite, }; +const struct filterops ttyexcept_filtops = { + .f_flags = FILTEROP_ISFD, + .f_attach = NULL, + .f_detach = filt_ttyrdetach, + .f_event = filt_ttyexcept, +}; + int ttkqfilter(dev_t dev, struct knote *kn) { @@ -1126,6 +1134,18 @@ ttkqfilter(dev_t dev, struct knote *kn) klist = &tp->t_wsel.si_note; kn->kn_fop = &ttywrite_filtops; break; + case EVFILT_EXCEPT: + if (kn->kn_flags & __EV_SELECT) { + /* Prevent triggering exceptfds. */ + return (EPERM); + } + if ((kn->kn_flags & __EV_POLL) == 0) { + /* Disallow usage through kevent(2). */ + return (EINVAL); + } + klist = &tp->t_rsel.si_note; + kn->kn_fop = &ttyexcept_filtops; + break; default: return (EINVAL); } @@ -1164,6 +1184,8 @@ filt_ttyread(struct knote *kn, long hint) if (kn->kn_flags & __EV_POLL) kn->kn_flags |= __EV_HUP; active = 1; + } else { + kn->kn_flags &= ~(EV_EOF | __EV_HUP); } splx(s); return (active); @@ -1184,13 +1206,45 @@ int filt_ttywrite(struct knote *kn, long hint) { struct tty *tp = kn->kn_hook; - int canwrite, s; + int active, s; s = spltty(); kn->kn_data = tp->t_outq.c_cn - tp->t_outq.c_cc; - canwrite = (tp->t_outq.c_cc <= tp->t_lowat); + active = (tp->t_outq.c_cc <= tp->t_lowat); + + /* Write-side HUP condition is only for poll(2) and select(2). */ + if (kn->kn_flags & (__EV_POLL | __EV_SELECT)) { + if (!ISSET(tp->t_cflag, CLOCAL) && + !ISSET(tp->t_state, TS_CARR_ON)) { + kn->kn_flags |= __EV_HUP; + active = 1; + } else { + kn->kn_flags &= ~__EV_HUP; + } + } + splx(s); + return (active); +} + +int +filt_ttyexcept(struct knote *kn, long hint) +{ + struct tty *tp = kn->kn_hook; + int active = 0; + int s; + + s = spltty(); + if (kn->kn_flags & __EV_POLL) { + if (!ISSET(tp->t_cflag, CLOCAL) && + !ISSET(tp->t_state, TS_CARR_ON)) { + kn->kn_flags |= __EV_HUP; + active = 1; + } else { + kn->kn_flags &= ~__EV_HUP; + } + } splx(s); - return (canwrite); + return (active); } static int diff --git a/sys/kern/tty_pty.c b/sys/kern/tty_pty.c index f719155fa85..684b5402a3c 100644 --- a/sys/kern/tty_pty.c +++ b/sys/kern/tty_pty.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tty_pty.c,v 1.111 2021/12/13 14:56:55 visa Exp $ */ +/* $OpenBSD: tty_pty.c,v 1.112 2021/12/15 15:30:47 visa Exp $ */ /* $NetBSD: tty_pty.c,v 1.33.4.1 1996/06/02 09:08:11 mrg Exp $ */ /* @@ -667,6 +667,7 @@ filt_ptcread(struct knote *kn, long hint) { struct pt_softc *pti = (struct pt_softc *)kn->kn_hook; struct tty *tp; + int active; tp = pti->pt_tty; kn->kn_data = 0; @@ -678,15 +679,18 @@ filt_ptcread(struct knote *kn, long hint) ((pti->pt_flags & PF_UCNTL) && pti->pt_ucntl)) kn->kn_data++; } + active = (kn->kn_data > 0); if (!ISSET(tp->t_state, TS_CARR_ON)) { kn->kn_flags |= EV_EOF; if (kn->kn_flags & __EV_POLL) kn->kn_flags |= __EV_HUP; - return (1); + active = 1; + } else { + kn->kn_flags &= ~(EV_EOF | __EV_HUP); } - return (kn->kn_data > 0); + return (active); } void @@ -705,6 +709,7 @@ filt_ptcwrite(struct knote *kn, long hint) { struct pt_softc *pti = (struct pt_softc *)kn->kn_hook; struct tty *tp; + int active; tp = pti->pt_tty; kn->kn_data = 0; @@ -718,8 +723,19 @@ filt_ptcwrite(struct knote *kn, long hint) kn->kn_data = tp->t_canq.c_cn - (tp->t_rawq.c_cc + tp->t_canq.c_cc); } + active = (kn->kn_data > 0); - return (kn->kn_data > 0); + /* Write-side HUP condition is only for poll(2) and select(2). */ + if (kn->kn_flags & (__EV_POLL | __EV_SELECT)) { + if (!ISSET(tp->t_state, TS_CARR_ON)) { + kn->kn_flags |= __EV_HUP; + active = 1; + } else { + kn->kn_flags &= ~__EV_HUP; + } + } + + return (active); } int @@ -745,6 +761,8 @@ filt_ptcexcept(struct knote *kn, long hint) if (!ISSET(tp->t_state, TS_CARR_ON)) { kn->kn_flags |= __EV_HUP; active = 1; + } else { + kn->kn_flags &= ~__EV_HUP; } } -- 2.20.1