diff options
Diffstat (limited to 'freebsd/sys/kern/tty.c')
-rw-r--r-- | freebsd/sys/kern/tty.c | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/freebsd/sys/kern/tty.c b/freebsd/sys/kern/tty.c index 88b928b9..d0b5633c 100644 --- a/freebsd/sys/kern/tty.c +++ b/freebsd/sys/kern/tty.c @@ -1184,6 +1184,7 @@ void tty_rel_gone(struct tty *tp) { + tty_lock_assert(tp, MA_OWNED); MPASS(!tty_gone(tp)); /* Simulate carrier removal. */ @@ -1198,6 +1199,73 @@ tty_rel_gone(struct tty *tp) tty_rel_free(tp); } +#ifndef __rtems__ +static int +tty_drop_ctty(struct tty *tp, struct proc *p) +{ + struct session *session; + struct vnode *vp; + + /* + * This looks terrible, but it's generally safe as long as the tty + * hasn't gone away while we had the lock dropped. All of our sanity + * checking that this operation is OK happens after we've picked it back + * up, so other state changes are generally not fatal and the potential + * for this particular operation to happen out-of-order in a + * multithreaded scenario is likely a non-issue. + */ + tty_unlock(tp); + sx_xlock(&proctree_lock); + tty_lock(tp); + if (tty_gone(tp)) { + sx_xunlock(&proctree_lock); + return (ENODEV); + } + + /* + * If the session doesn't have a controlling TTY, or if we weren't + * invoked on the controlling TTY, we'll return ENOIOCTL as we've + * historically done. + */ + session = p->p_session; + if (session->s_ttyp == NULL || session->s_ttyp != tp) { + sx_xunlock(&proctree_lock); + return (ENOTTY); + } + + if (!SESS_LEADER(p)) { + sx_xunlock(&proctree_lock); + return (EPERM); + } + + PROC_LOCK(p); + SESS_LOCK(session); + vp = session->s_ttyvp; + session->s_ttyp = NULL; + session->s_ttyvp = NULL; + session->s_ttydp = NULL; + SESS_UNLOCK(session); + + tp->t_sessioncnt--; + p->p_flag &= ~P_CONTROLT; + PROC_UNLOCK(p); + sx_xunlock(&proctree_lock); + + /* + * If we did have a vnode, release our reference. Ordinarily we manage + * these at the devfs layer, but we can't necessarily know that we were + * invoked on the vnode referenced in the session (i.e. the vnode we + * hold a reference to). We explicitly don't check VBAD/VI_DOOMED here + * to avoid a vnode leak -- in circumstances elsewhere where we'd hit a + * VI_DOOMED vnode, release has been deferred until the controlling TTY + * is either changed or released. + */ + if (vp != NULL) + vrele(vp); + return (0); +} +#endif /* __rtems__ */ + /* * Exposing information about current TTY's through sysctl */ @@ -1738,6 +1806,10 @@ tty_generic_ioctl(struct tty *tp, u_long cmd, void *data, int fflag, *(int *)data = NO_PID; #endif /* __rtems__ */ return (0); +#ifndef __rtems__ + case TIOCNOTTY: + return (tty_drop_ctty(tp, td->td_proc)); +#endif /* __rtems__ */ case TIOCSCTTY: { #ifndef __rtems__ struct proc *p = td->td_proc; |