10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
52712Snn35248 * Common Development and Distribution License (the "License").
62712Snn35248 * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*5331Samw * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
270Sstevel@tonic-gate /* All Rights Reserved */
280Sstevel@tonic-gate
290Sstevel@tonic-gate
300Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
310Sstevel@tonic-gate
320Sstevel@tonic-gate #include <sys/types.h>
330Sstevel@tonic-gate #include <sys/sysmacros.h>
340Sstevel@tonic-gate #include <sys/param.h>
350Sstevel@tonic-gate #include <sys/systm.h>
360Sstevel@tonic-gate #include <sys/file.h>
370Sstevel@tonic-gate #include <sys/vnode.h>
380Sstevel@tonic-gate #include <sys/errno.h>
390Sstevel@tonic-gate #include <sys/signal.h>
400Sstevel@tonic-gate #include <sys/cred.h>
410Sstevel@tonic-gate #include <sys/policy.h>
420Sstevel@tonic-gate #include <sys/conf.h>
430Sstevel@tonic-gate #include <sys/debug.h>
440Sstevel@tonic-gate #include <sys/proc.h>
450Sstevel@tonic-gate #include <sys/session.h>
460Sstevel@tonic-gate #include <sys/kmem.h>
470Sstevel@tonic-gate #include <sys/cmn_err.h>
480Sstevel@tonic-gate #include <sys/strsubr.h>
492712Snn35248 #include <sys/fs/snode.h>
500Sstevel@tonic-gate
510Sstevel@tonic-gate sess_t session0 = {
522712Snn35248 &pid0, /* s_sidp */
532712Snn35248 {0}, /* s_lock */
542712Snn35248 1, /* s_ref */
552712Snn35248 B_FALSE, /* s_sighuped */
562712Snn35248 B_FALSE, /* s_exit */
572712Snn35248 0, /* s_exit_cv */
582712Snn35248 0, /* s_cnt */
592712Snn35248 0, /* s_cnt_cv */
602712Snn35248 NODEV, /* s_dev */
612712Snn35248 NULL, /* s_vp */
622712Snn35248 NULL /* s_cred */
630Sstevel@tonic-gate };
640Sstevel@tonic-gate
650Sstevel@tonic-gate void
sess_hold(proc_t * p)662712Snn35248 sess_hold(proc_t *p)
670Sstevel@tonic-gate {
682712Snn35248 ASSERT(MUTEX_HELD(&pidlock) || MUTEX_HELD(&p->p_splock));
692712Snn35248 mutex_enter(&p->p_sessp->s_lock);
702712Snn35248 p->p_sessp->s_ref++;
712712Snn35248 mutex_exit(&p->p_sessp->s_lock);
722712Snn35248 }
732712Snn35248
742712Snn35248 void
sess_rele(sess_t * sp,boolean_t pidlock_held)752712Snn35248 sess_rele(sess_t *sp, boolean_t pidlock_held)
762712Snn35248 {
772712Snn35248 ASSERT(MUTEX_HELD(&pidlock) || !pidlock_held);
782712Snn35248
792712Snn35248 mutex_enter(&sp->s_lock);
800Sstevel@tonic-gate
810Sstevel@tonic-gate ASSERT(sp->s_ref != 0);
822712Snn35248 if (--sp->s_ref > 0) {
832712Snn35248 mutex_exit(&sp->s_lock);
842712Snn35248 return;
850Sstevel@tonic-gate }
862712Snn35248 ASSERT(sp->s_ref == 0);
872712Snn35248
882712Snn35248 /*
892712Snn35248 * It's ok to free this session structure now because we know
902712Snn35248 * that no one else can have a pointer to it. We know this
912712Snn35248 * to be true because the only time that s_ref can possibly
922712Snn35248 * be incremented is when pidlock or p_splock is held AND there
932712Snn35248 * is a proc_t that points to that session structure. In that
942712Snn35248 * case we are guaranteed that the s_ref is at least 1 since there
952712Snn35248 * is a proc_t that points to it. So when s_ref finally drops to
962712Snn35248 * zero then no one else has a reference (and hence pointer) to
972712Snn35248 * this session structure and there is no valid proc_t pointing
982712Snn35248 * to this session structure anymore so, no one can acquire a
992712Snn35248 * reference (and pointer) to this session structure so it's
1002712Snn35248 * ok to free it here.
1012712Snn35248 */
1022712Snn35248
1032712Snn35248 if (sp == &session0)
1042712Snn35248 panic("sp == &session0");
1052712Snn35248
1062712Snn35248 /* make sure there are no outstanding holds */
1072712Snn35248 ASSERT(sp->s_cnt == 0);
1082712Snn35248
1092712Snn35248 /* make sure there is no exit in progress */
1102712Snn35248 ASSERT(!sp->s_exit);
1112712Snn35248
1122712Snn35248 /* make sure someone already freed any ctty */
1132712Snn35248 ASSERT(sp->s_vp == NULL);
1142712Snn35248 ASSERT(sp->s_dev == NODEV);
1152712Snn35248
1162712Snn35248 if (!pidlock_held)
1172712Snn35248 mutex_enter(&pidlock);
1182712Snn35248 PID_RELE(sp->s_sidp);
1192712Snn35248 if (!pidlock_held)
1202712Snn35248 mutex_exit(&pidlock);
1212712Snn35248
1222712Snn35248 mutex_destroy(&sp->s_lock);
1232712Snn35248 cv_destroy(&sp->s_cnt_cv);
1242712Snn35248 kmem_free(sp, sizeof (sess_t));
1252712Snn35248 }
1262712Snn35248
1272712Snn35248 sess_t *
tty_hold(void)1282712Snn35248 tty_hold(void)
1292712Snn35248 {
1302712Snn35248 proc_t *p = curproc;
1312712Snn35248 sess_t *sp;
1322712Snn35248 boolean_t got_sig = B_FALSE;
1332712Snn35248
1342712Snn35248 /* make sure the caller isn't holding locks they shouldn't */
1352712Snn35248 ASSERT(MUTEX_NOT_HELD(&pidlock));
1362712Snn35248
1372712Snn35248 for (;;) {
1382712Snn35248 mutex_enter(&p->p_splock); /* protect p->p_sessp */
1392712Snn35248 sp = p->p_sessp;
1402712Snn35248 mutex_enter(&sp->s_lock); /* protect sp->* */
1412712Snn35248
1422712Snn35248 /* make sure the caller isn't holding locks they shouldn't */
1432712Snn35248 ASSERT((sp->s_vp == NULL) ||
1442712Snn35248 MUTEX_NOT_HELD(&sp->s_vp->v_stream->sd_lock));
1452712Snn35248
1462712Snn35248 /*
1472712Snn35248 * If the session leader process is not exiting (and hence
1482712Snn35248 * not trying to release the session's ctty) then we can
1492712Snn35248 * safely grab a hold on the current session structure
1502712Snn35248 * and return it. If on the other hand the session leader
1512712Snn35248 * process is exiting and clearing the ctty then we'll
1522712Snn35248 * wait till it's done before we loop around and grab a
1532712Snn35248 * hold on the session structure.
1542712Snn35248 */
1552712Snn35248 if (!sp->s_exit)
1562712Snn35248 break;
1572712Snn35248
1582712Snn35248 /* need to hold the session so it can't be freed */
1592712Snn35248 sp->s_ref++;
1602712Snn35248 mutex_exit(&p->p_splock);
1612712Snn35248
1622712Snn35248 /* Wait till the session leader is done */
1632712Snn35248 if (!cv_wait_sig(&sp->s_exit_cv, &sp->s_lock))
1642712Snn35248 got_sig = B_TRUE;
1652712Snn35248
1662712Snn35248 /*
1672712Snn35248 * Now we need to drop our hold on the session structure,
1682712Snn35248 * but we can't hold any locks when we do this because
169*5331Samw * sess_rele() may need to acquire pidlock.
1702712Snn35248 */
1712712Snn35248 mutex_exit(&sp->s_lock);
1722712Snn35248 sess_rele(sp, B_FALSE);
1732712Snn35248
1742712Snn35248 if (got_sig)
1752712Snn35248 return (NULL);
1762712Snn35248 }
1772712Snn35248
1782712Snn35248 /* whew, we finally got a hold */
1792712Snn35248 sp->s_cnt++;
1802712Snn35248 sp->s_ref++;
1812712Snn35248 mutex_exit(&sp->s_lock);
1822712Snn35248 mutex_exit(&p->p_splock);
1832712Snn35248 return (sp);
1842712Snn35248 }
1852712Snn35248
1862712Snn35248 void
tty_rele(sess_t * sp)1872712Snn35248 tty_rele(sess_t *sp)
1882712Snn35248 {
1892712Snn35248 /* make sure the caller isn't holding locks they shouldn't */
1902712Snn35248 ASSERT(MUTEX_NOT_HELD(&pidlock));
1912712Snn35248
1922712Snn35248 mutex_enter(&sp->s_lock);
1932712Snn35248 if ((--sp->s_cnt) == 0)
1942712Snn35248 cv_broadcast(&sp->s_cnt_cv);
1952712Snn35248 mutex_exit(&sp->s_lock);
1962712Snn35248
1972712Snn35248 sess_rele(sp, B_FALSE);
1980Sstevel@tonic-gate }
1990Sstevel@tonic-gate
2000Sstevel@tonic-gate void
sess_create(void)2010Sstevel@tonic-gate sess_create(void)
2020Sstevel@tonic-gate {
2032712Snn35248 proc_t *p = curproc;
2042712Snn35248 sess_t *sp, *old_sp;
2050Sstevel@tonic-gate
2060Sstevel@tonic-gate sp = kmem_zalloc(sizeof (sess_t), KM_SLEEP);
2070Sstevel@tonic-gate
2080Sstevel@tonic-gate mutex_init(&sp->s_lock, NULL, MUTEX_DEFAULT, NULL);
2092712Snn35248 cv_init(&sp->s_cnt_cv, NULL, CV_DEFAULT, NULL);
2100Sstevel@tonic-gate
2110Sstevel@tonic-gate /*
2122712Snn35248 * we need to grap p_lock to protect p_pgidp because
2132712Snn35248 * /proc looks at p_pgidp while holding only p_lock.
2142712Snn35248 *
2152712Snn35248 * we don't need to hold p->p_sessp->s_lock or get a hold on the
2162712Snn35248 * session structure since we're not actually updating any of
2172712Snn35248 * the contents of the old session structure.
2180Sstevel@tonic-gate */
2192712Snn35248 mutex_enter(&pidlock);
2202712Snn35248 mutex_enter(&p->p_lock);
2212712Snn35248 mutex_enter(&p->p_splock);
2220Sstevel@tonic-gate
2232712Snn35248 pgexit(p);
2242712Snn35248
2252712Snn35248 sp->s_sidp = p->p_pidp;
2260Sstevel@tonic-gate sp->s_ref = 1;
2270Sstevel@tonic-gate sp->s_dev = NODEV;
2280Sstevel@tonic-gate
2292712Snn35248 old_sp = p->p_sessp;
2302712Snn35248 p->p_sessp = sp;
2312712Snn35248
2322712Snn35248 pgjoin(p, p->p_pidp);
2332712Snn35248 PID_HOLD(p->p_pidp);
2340Sstevel@tonic-gate
2352712Snn35248 mutex_exit(&p->p_splock);
2362712Snn35248 mutex_exit(&p->p_lock);
2372712Snn35248 mutex_exit(&pidlock);
2380Sstevel@tonic-gate
2392712Snn35248 sess_rele(old_sp, B_FALSE);
2400Sstevel@tonic-gate }
2410Sstevel@tonic-gate
2422712Snn35248 /*
2432712Snn35248 * Note that sess_ctty_clear() resets all the fields in the session
2442712Snn35248 * structure but doesn't release any holds or free any objects
2452712Snn35248 * that the session structure might currently point to. it is the
2462712Snn35248 * callers responsibility to do this.
2472712Snn35248 */
2482712Snn35248 static void
sess_ctty_clear(sess_t * sp,stdata_t * stp)2492712Snn35248 sess_ctty_clear(sess_t *sp, stdata_t *stp)
2500Sstevel@tonic-gate {
2512712Snn35248 /*
2522712Snn35248 * Assert that we hold all the necessary locks. We also need
2532712Snn35248 * to be holding proc_t->p_splock for the process associated
2542712Snn35248 * with this session, but since we don't have a proc pointer
2552712Snn35248 * passed in we can't assert this here.
2562712Snn35248 */
2572712Snn35248 ASSERT(MUTEX_HELD(&stp->sd_lock) && MUTEX_HELD(&pidlock) &&
2582712Snn35248 MUTEX_HELD(&sp->s_lock));
2590Sstevel@tonic-gate
2602712Snn35248 /* reset the session structure members to defaults */
2612712Snn35248 sp->s_sighuped = B_FALSE;
2622712Snn35248 sp->s_dev = NODEV;
2630Sstevel@tonic-gate sp->s_vp = NULL;
264560Smeem sp->s_cred = NULL;
2650Sstevel@tonic-gate
2662712Snn35248 /* reset the stream session and group pointers */
2672712Snn35248 stp->sd_pgidp = NULL;
2682712Snn35248 stp->sd_sidp = NULL;
2692712Snn35248 }
2702712Snn35248
2712712Snn35248 static void
sess_ctty_set(proc_t * p,sess_t * sp,stdata_t * stp)2722712Snn35248 sess_ctty_set(proc_t *p, sess_t *sp, stdata_t *stp)
2732712Snn35248 {
2742712Snn35248 cred_t *crp;
2752712Snn35248
2762712Snn35248 /* Assert that we hold all the necessary locks. */
2772712Snn35248 ASSERT(MUTEX_HELD(&stp->sd_lock) && MUTEX_HELD(&pidlock) &&
2782712Snn35248 MUTEX_HELD(&p->p_splock) && MUTEX_HELD(&sp->s_lock));
2792712Snn35248
2802712Snn35248 /* get holds on structures */
2812712Snn35248 mutex_enter(&p->p_crlock);
2822712Snn35248 crhold(crp = p->p_cred);
2832712Snn35248 mutex_exit(&p->p_crlock);
2842712Snn35248 PID_HOLD(sp->s_sidp); /* requires pidlock */
2852712Snn35248 PID_HOLD(sp->s_sidp); /* requires pidlock */
2862712Snn35248
2872712Snn35248 /* update the session structure members */
2882712Snn35248 sp->s_vp = makectty(stp->sd_vnode);
2892712Snn35248 sp->s_dev = sp->s_vp->v_rdev;
2902712Snn35248 sp->s_cred = crp;
2912712Snn35248
2922712Snn35248 /* update the stream emebers */
2932712Snn35248 stp->sd_flag |= STRISTTY; /* just to be sure */
2942712Snn35248 stp->sd_sidp = sp->s_sidp;
2952712Snn35248 stp->sd_pgidp = sp->s_sidp;
2962712Snn35248 }
2972712Snn35248
2982712Snn35248 int
strctty(stdata_t * stp)2992712Snn35248 strctty(stdata_t *stp)
3002712Snn35248 {
3012712Snn35248 sess_t *sp;
3022712Snn35248 proc_t *p = curproc;
3032712Snn35248 boolean_t got_sig = B_FALSE;
3042712Snn35248
3050Sstevel@tonic-gate /*
3062712Snn35248 * We are going to try to make stp the default ctty for the session
3072712Snn35248 * associated with curproc. Not only does this require holding a
3082712Snn35248 * bunch of locks but it also requires waiting for any outstanding
309*5331Samw * holds on the session structure (acquired via tty_hold()) to be
3102712Snn35248 * released. Hence, we have the following for(;;) loop that will
311*5331Samw * acquire our locks, do some sanity checks, and wait for the hold
3122712Snn35248 * count on the session structure to hit zero. If we get a signal
3132712Snn35248 * while waiting for outstanding holds to be released then we abort
3142712Snn35248 * the operation and return.
3150Sstevel@tonic-gate */
3162712Snn35248 for (;;) {
3172712Snn35248 mutex_enter(&stp->sd_lock); /* protects sd_pgidp/sd_sidp */
3182712Snn35248 mutex_enter(&pidlock); /* protects p_pidp */
3192712Snn35248 mutex_enter(&p->p_splock); /* protects p_sessp */
3202712Snn35248 sp = p->p_sessp;
3212712Snn35248 mutex_enter(&sp->s_lock); /* protects sp->* */
3220Sstevel@tonic-gate
3232712Snn35248 if (((stp->sd_flag & (STRHUP|STRDERR|STWRERR|STPLEX)) != 0) ||
3242712Snn35248 (stp->sd_sidp != NULL) || /* stp already ctty? */
3252712Snn35248 (p->p_pidp != sp->s_sidp) || /* we're not leader? */
3262712Snn35248 (sp->s_vp != NULL)) { /* session has ctty? */
3272712Snn35248 mutex_exit(&sp->s_lock);
3282712Snn35248 mutex_exit(&p->p_splock);
3292712Snn35248 mutex_exit(&pidlock);
3302712Snn35248 mutex_exit(&stp->sd_lock);
3312712Snn35248 return (ENOTTY);
3322712Snn35248 }
3332712Snn35248
3342712Snn35248 /* sanity check. we can't be exiting right now */
3352712Snn35248 ASSERT(!sp->s_exit);
3362712Snn35248
3372712Snn35248 /*
3382712Snn35248 * If no one else has a hold on this session structure
3392712Snn35248 * then we now have exclusive access to it, so break out
3402712Snn35248 * of this loop and update the session structure.
3412712Snn35248 */
3422712Snn35248 if (sp->s_cnt == 0)
3432712Snn35248 break;
3442712Snn35248
3452712Snn35248 /* need to hold the session so it can't be freed */
3462712Snn35248 sp->s_ref++;
3472712Snn35248
3482712Snn35248 /* ain't locking order fun? */
3492712Snn35248 mutex_exit(&p->p_splock);
3502712Snn35248 mutex_exit(&pidlock);
3512712Snn35248 mutex_exit(&stp->sd_lock);
3522712Snn35248
3532712Snn35248 if (!cv_wait_sig(&sp->s_cnt_cv, &sp->s_lock))
3542712Snn35248 got_sig = B_TRUE;
3552712Snn35248 mutex_exit(&sp->s_lock);
3562712Snn35248 sess_rele(sp, B_FALSE);
3572712Snn35248
3582712Snn35248 if (got_sig)
3592712Snn35248 return (EINTR);
3602712Snn35248 }
3612712Snn35248
3622712Snn35248 /* set the session ctty bindings */
3632712Snn35248 sess_ctty_set(p, sp, stp);
3642712Snn35248
3650Sstevel@tonic-gate mutex_exit(&sp->s_lock);
3662712Snn35248 mutex_exit(&p->p_splock);
3672712Snn35248 mutex_exit(&pidlock);
3682712Snn35248 mutex_exit(&stp->sd_lock);
3692712Snn35248 return (0);
3702712Snn35248 }
3712712Snn35248
3722712Snn35248 /*
373*5331Samw * freectty_lock() attempts to acquire the army of locks required to free
3742712Snn35248 * the ctty associated with a given session leader process. If it returns
3752712Snn35248 * successfully the following locks will be held:
3762712Snn35248 * sd_lock, pidlock, p_splock, s_lock
3772712Snn35248 *
378*5331Samw * as a secondary bit of convenience, freectty_lock() will also return
3792712Snn35248 * pointers to the session, ctty, and ctty stream associated with the
3802712Snn35248 * specified session leader process.
3812712Snn35248 */
3822712Snn35248 static boolean_t
freectty_lock(proc_t * p,sess_t ** spp,vnode_t ** vpp,stdata_t ** stpp,boolean_t at_exit)3832712Snn35248 freectty_lock(proc_t *p, sess_t **spp, vnode_t **vpp, stdata_t **stpp,
3842712Snn35248 boolean_t at_exit)
3852712Snn35248 {
3862712Snn35248 sess_t *sp;
3872712Snn35248 vnode_t *vp;
3882712Snn35248 stdata_t *stp;
3892712Snn35248
3902712Snn35248 mutex_enter(&pidlock); /* protect p_pidp */
3912712Snn35248 mutex_enter(&p->p_splock); /* protect p->p_sessp */
3922712Snn35248 sp = p->p_sessp;
3932712Snn35248 mutex_enter(&sp->s_lock); /* protect sp->* */
3942712Snn35248
3952712Snn35248 if ((sp->s_sidp != p->p_pidp) || /* we're not leader? */
3962712Snn35248 (sp->s_vp == NULL)) { /* no ctty? */
3972712Snn35248 mutex_exit(&sp->s_lock);
3982712Snn35248 mutex_exit(&p->p_splock);
3992712Snn35248 mutex_exit(&pidlock);
4002712Snn35248 return (B_FALSE);
4012712Snn35248 }
4022712Snn35248
4032712Snn35248 vp = sp->s_vp;
4042712Snn35248 stp = sp->s_vp->v_stream;
4052712Snn35248
4062712Snn35248 if (at_exit) {
4072712Snn35248 /* stop anyone else calling tty_hold() */
4082712Snn35248 sp->s_exit = B_TRUE;
4092712Snn35248 } else {
4102712Snn35248 /*
4112712Snn35248 * due to locking order we have to grab stp->sd_lock before
4122712Snn35248 * grabbing all the other proc/session locks. but after we
4132712Snn35248 * drop all our current locks it's possible that someone
4142712Snn35248 * could come in and change our current session or close
4152712Snn35248 * the current ctty (vp) there by making sp or stp invalid.
4162712Snn35248 * (a VN_HOLD on vp won't protect stp because that only
4172712Snn35248 * prevents the vnode from being freed not closed.) so
4182712Snn35248 * to prevent this we bump s_ref and s_cnt here.
4192712Snn35248 *
4202712Snn35248 * course this doesn't matter if we're the last thread in
4212712Snn35248 * an exiting process that is the session leader, since no
4222712Snn35248 * one else can change our session or free our ctty.
4232712Snn35248 */
4242712Snn35248 sp->s_ref++; /* hold the session structure */
4252712Snn35248 sp->s_cnt++; /* protect vp and stp */
4262712Snn35248 }
4272712Snn35248
4282712Snn35248 /* drop our session locks */
4292712Snn35248 mutex_exit(&sp->s_lock);
4302712Snn35248 mutex_exit(&p->p_splock);
4312712Snn35248 mutex_exit(&pidlock);
4322712Snn35248
4332712Snn35248 /* grab locks in the right order */
4342712Snn35248 mutex_enter(&stp->sd_lock); /* protects sd_pgidp/sd_sidp */
4352712Snn35248 mutex_enter(&pidlock); /* protect p_pidp */
4362712Snn35248 mutex_enter(&p->p_splock); /* protects p->p_sessp */
4372712Snn35248 mutex_enter(&sp->s_lock); /* protects sp->* */
4382712Snn35248
4392712Snn35248 /* if the session has changed, abort mission */
4402712Snn35248 if (sp != p->p_sessp) {
4412712Snn35248 /*
4422712Snn35248 * this can't happen during process exit since we're the
4432712Snn35248 * only thread in the process and we sure didn't change
4442712Snn35248 * our own session at this point.
4452712Snn35248 */
4462712Snn35248 ASSERT(!at_exit);
4472712Snn35248
4482712Snn35248 /* release our locks and holds */
4492712Snn35248 mutex_exit(&sp->s_lock);
4502712Snn35248 mutex_exit(&p->p_splock);
4512712Snn35248 mutex_exit(&pidlock);
4522712Snn35248 mutex_exit(&stp->sd_lock);
4532712Snn35248 tty_rele(sp);
4542712Snn35248 return (B_FALSE);
4552712Snn35248 }
4560Sstevel@tonic-gate
4570Sstevel@tonic-gate /*
4582712Snn35248 * sanity checks. none of this should have changed since we had
4592712Snn35248 * holds on the current ctty.
4600Sstevel@tonic-gate */
4612712Snn35248 ASSERT(sp->s_sidp == p->p_pidp); /* we're the leader */
4622712Snn35248 ASSERT(sp->s_vp != NULL); /* a ctty exists */
4632712Snn35248 ASSERT(vp == sp->s_vp);
4642712Snn35248 ASSERT(stp == sp->s_vp->v_stream);
4650Sstevel@tonic-gate
4662712Snn35248 /* release our holds */
4672712Snn35248 if (!at_exit) {
4682712Snn35248 if ((--(sp)->s_cnt) == 0)
4692712Snn35248 cv_broadcast(&sp->s_cnt_cv);
4702712Snn35248 sp->s_ref--;
4712712Snn35248 ASSERT(sp->s_ref > 0);
4722712Snn35248 }
4732712Snn35248
4742712Snn35248 /* return our pointers */
4752712Snn35248 *spp = sp;
4762712Snn35248 *vpp = vp;
4772712Snn35248 *stpp = stp;
4782712Snn35248
4792712Snn35248 return (B_TRUE);
4802712Snn35248 }
4812712Snn35248
4822712Snn35248 /*
4832712Snn35248 * Returns B_FALSE if no signal is sent to the process group associated with
4842712Snn35248 * this ctty. Returns B_TRUE if a signal is sent to the process group.
4852712Snn35248 * If it return B_TRUE it also means that all the locks we were holding
4862712Snn35248 * were dropped so that we could send the signal.
4872712Snn35248 */
4882712Snn35248 static boolean_t
freectty_signal(proc_t * p,sess_t * sp,stdata_t * stp,boolean_t at_exit)4892712Snn35248 freectty_signal(proc_t *p, sess_t *sp, stdata_t *stp, boolean_t at_exit)
4902712Snn35248 {
4912712Snn35248 /* Assert that we hold all the necessary locks. */
4922712Snn35248 ASSERT(MUTEX_HELD(&stp->sd_lock) && MUTEX_HELD(&pidlock) &&
4932712Snn35248 MUTEX_HELD(&p->p_splock) && MUTEX_HELD(&sp->s_lock));
4942712Snn35248
4952712Snn35248 /* check if we already signaled this group */
4962712Snn35248 if (sp->s_sighuped)
4972712Snn35248 return (B_FALSE);
4982712Snn35248
4992712Snn35248 sp->s_sighuped = B_TRUE;
5002712Snn35248
5012712Snn35248 if (!at_exit) {
5022712Snn35248 /*
5032712Snn35248 * once again, we're about to drop our army of locks and we
5042712Snn35248 * don't want sp or stp to be freed. (see the comment in
5052712Snn35248 * freectty_lock())
5062712Snn35248 */
5072712Snn35248 sp->s_ref++; /* hold the session structure */
5082712Snn35248 sp->s_cnt++; /* protect vp and stp */
5092712Snn35248 }
5102712Snn35248
5112712Snn35248 /* can't hold these locks while calling pgsignal() */
5122712Snn35248 mutex_exit(&sp->s_lock);
5132712Snn35248 mutex_exit(&p->p_splock);
5142712Snn35248 mutex_exit(&pidlock);
5152712Snn35248
5162712Snn35248 /* signal anyone in the foreground process group */
5172712Snn35248 pgsignal(stp->sd_pgidp, SIGHUP);
5182712Snn35248
5192712Snn35248 /* signal anyone blocked in poll on this stream */
5202712Snn35248 if (!(stp->sd_flag & STRHUP))
5212712Snn35248 strhup(stp);
5222712Snn35248
5232712Snn35248 mutex_exit(&stp->sd_lock);
5242712Snn35248
5252712Snn35248 /* release our holds */
5262712Snn35248 if (!at_exit)
5272712Snn35248 tty_rele(sp);
5282712Snn35248
5292712Snn35248 return (B_TRUE);
5302712Snn35248 }
5312712Snn35248
5322712Snn35248 int
freectty(boolean_t at_exit)5332712Snn35248 freectty(boolean_t at_exit)
5342712Snn35248 {
5352712Snn35248 proc_t *p = curproc;
5362712Snn35248 stdata_t *stp;
5372712Snn35248 vnode_t *vp;
5382712Snn35248 cred_t *cred;
5392712Snn35248 sess_t *sp;
5402712Snn35248 struct pid *pgidp, *sidp;
5412712Snn35248 boolean_t got_sig = B_FALSE;
5422712Snn35248
5432712Snn35248 /*
5442712Snn35248 * If the current process is a session leader we are going to
5452712Snn35248 * try to release the ctty associated our current session. To
546*5331Samw * do this we need to acquire a bunch of locks, signal any
5472712Snn35248 * processes in the forground that are associated with the ctty,
5482712Snn35248 * and make sure no one has any outstanding holds on the current
549*5331Samw * session * structure (acquired via tty_hold()). Hence, we have
5502712Snn35248 * the following for(;;) loop that will do all this work for
5512712Snn35248 * us and break out when the hold count on the session structure
5522712Snn35248 * hits zero.
5532712Snn35248 */
5542712Snn35248 for (;;) {
5552712Snn35248 if (!freectty_lock(p, &sp, &vp, &stp, at_exit))
5562712Snn35248 return (EIO);
5572712Snn35248
5582712Snn35248 if (freectty_signal(p, sp, stp, at_exit)) {
559*5331Samw /* loop around to re-acquire locks */
5602712Snn35248 continue;
5612712Snn35248 }
5622712Snn35248
5632712Snn35248 /*
5642712Snn35248 * Only a session leader process can free a ctty. So if
5652712Snn35248 * we've made it here we know we're a session leader and
5662712Snn35248 * if we're not actively exiting it impossible for another
5672712Snn35248 * thread in this process to be exiting. (Because that
5682712Snn35248 * thread would have already stopped all other threads
5692712Snn35248 * in the current process.)
5702712Snn35248 */
5712712Snn35248 ASSERT(at_exit || !sp->s_exit);
5722712Snn35248
5732712Snn35248 /*
5742712Snn35248 * If no one else has a hold on this session structure
5752712Snn35248 * then we now have exclusive access to it, so break out
5762712Snn35248 * of this loop and update the session structure.
5772712Snn35248 */
5782712Snn35248 if (sp->s_cnt == 0)
5792712Snn35248 break;
5802712Snn35248
5812712Snn35248 if (!at_exit) {
5822712Snn35248 /* need to hold the session so it can't be freed */
5832712Snn35248 sp->s_ref++;
5842712Snn35248 }
5852712Snn35248
5862712Snn35248 /* ain't locking order fun? */
5872712Snn35248 mutex_exit(&p->p_splock);
5882712Snn35248 mutex_exit(&pidlock);
5892712Snn35248 mutex_exit(&stp->sd_lock);
5902712Snn35248
5912712Snn35248 if (at_exit) {
5922712Snn35248 /*
5932712Snn35248 * if we're exiting then we can't allow this operation
5942712Snn35248 * to fail so we do a cw_wait() instead of a
5952712Snn35248 * cv_wait_sig(). if there are threads with active
5962712Snn35248 * holds on this ctty that are blocked, then
5972712Snn35248 * they should only be blocked in a cv_wait_sig()
5982712Snn35248 * and hopefully they were in the foreground process
5992712Snn35248 * group and recieved the SIGHUP we sent above. of
6002712Snn35248 * course it's possible that they weren't in the
6012712Snn35248 * foreground process group and didn't get our
6022712Snn35248 * signal (or they could be stopped by job control
6032712Snn35248 * in which case our signal wouldn't matter until
6042712Snn35248 * they are restarted). in this case we won't
6052712Snn35248 * exit until someone else sends them a signal.
6062712Snn35248 */
6072712Snn35248 cv_wait(&sp->s_cnt_cv, &sp->s_lock);
6082712Snn35248 mutex_exit(&sp->s_lock);
6092712Snn35248 continue;
6102712Snn35248 }
6112712Snn35248
6122712Snn35248 if (!cv_wait_sig(&sp->s_cnt_cv, &sp->s_lock)) {
6132712Snn35248 got_sig = B_TRUE;
6142712Snn35248 }
6152712Snn35248
6162712Snn35248 mutex_exit(&sp->s_lock);
6172712Snn35248 sess_rele(sp, B_FALSE);
6182712Snn35248
6192712Snn35248 if (got_sig)
6202712Snn35248 return (EINTR);
6212712Snn35248 }
6222712Snn35248 ASSERT(sp->s_cnt == 0);
6232712Snn35248
6242712Snn35248 /* save some pointers for later */
6252712Snn35248 cred = sp->s_cred;
6262712Snn35248 pgidp = stp->sd_pgidp;
6272712Snn35248 sidp = stp->sd_sidp;
6282712Snn35248
6292712Snn35248 /* clear the session ctty bindings */
6302712Snn35248 sess_ctty_clear(sp, stp);
6312712Snn35248
6322712Snn35248 /* wake up anyone blocked in tty_hold() */
6332712Snn35248 if (at_exit) {
6342712Snn35248 ASSERT(sp->s_exit);
6352712Snn35248 sp->s_exit = B_FALSE;
6362712Snn35248 cv_broadcast(&sp->s_exit_cv);
6372712Snn35248 }
6382712Snn35248
6392712Snn35248 /* we can drop these locks now */
6402712Snn35248 mutex_exit(&sp->s_lock);
6412712Snn35248 mutex_exit(&p->p_splock);
6422712Snn35248 mutex_exit(&pidlock);
6432712Snn35248 mutex_exit(&stp->sd_lock);
6442712Snn35248
6452712Snn35248 /* This is the only remaining thread with access to this vnode */
646*5331Samw (void) VOP_CLOSE(vp, 0, 1, (offset_t)0, cred, NULL);
6470Sstevel@tonic-gate VN_RELE(vp);
6482712Snn35248 crfree(cred);
6490Sstevel@tonic-gate
6502712Snn35248 /* release our holds on assorted structures and return */
6512712Snn35248 mutex_enter(&pidlock);
6522712Snn35248 PID_RELE(pgidp);
6532712Snn35248 PID_RELE(sidp);
6542712Snn35248 mutex_exit(&pidlock);
6552712Snn35248
6562712Snn35248 return (1);
6570Sstevel@tonic-gate }
6580Sstevel@tonic-gate
6590Sstevel@tonic-gate /*
6600Sstevel@tonic-gate * ++++++++++++++++++++++++
6610Sstevel@tonic-gate * ++ SunOS4.1 Buyback ++
6620Sstevel@tonic-gate * ++++++++++++++++++++++++
6630Sstevel@tonic-gate *
6640Sstevel@tonic-gate * vhangup: Revoke access of the current tty by all processes
6650Sstevel@tonic-gate * Used by privileged users to give a "clean" terminal at login
6660Sstevel@tonic-gate */
6670Sstevel@tonic-gate int
vhangup(void)668560Smeem vhangup(void)
6690Sstevel@tonic-gate {
6700Sstevel@tonic-gate if (secpolicy_sys_config(CRED(), B_FALSE) != 0)
6710Sstevel@tonic-gate return (set_errno(EPERM));
6720Sstevel@tonic-gate /*
6730Sstevel@tonic-gate * This routine used to call freectty() under a condition that
6740Sstevel@tonic-gate * could never happen. So this code has never actually done
675560Smeem * anything, and evidently nobody has ever noticed.
6760Sstevel@tonic-gate */
6770Sstevel@tonic-gate return (0);
6780Sstevel@tonic-gate }
6790Sstevel@tonic-gate
6800Sstevel@tonic-gate dev_t
cttydev(proc_t * pp)6810Sstevel@tonic-gate cttydev(proc_t *pp)
6820Sstevel@tonic-gate {
6832712Snn35248 sess_t *sp;
6842712Snn35248 dev_t dev;
6852712Snn35248
6862712Snn35248 mutex_enter(&pp->p_splock); /* protects p->p_sessp */
6872712Snn35248 sp = pp->p_sessp;
6882712Snn35248
6892712Snn35248 #ifdef DEBUG
6902712Snn35248 mutex_enter(&sp->s_lock); /* protects sp->* */
6910Sstevel@tonic-gate if (sp->s_vp == NULL)
6922712Snn35248 ASSERT(sp->s_dev == NODEV);
6932712Snn35248 else
6942712Snn35248 ASSERT(sp->s_dev != NODEV);
6952712Snn35248 mutex_exit(&sp->s_lock);
6962712Snn35248 #endif /* DEBUG */
6972712Snn35248
6982712Snn35248 dev = sp->s_dev;
6992712Snn35248 mutex_exit(&pp->p_splock);
7002712Snn35248 return (dev);
7010Sstevel@tonic-gate }
7020Sstevel@tonic-gate
7030Sstevel@tonic-gate void
ctty_clear_sighuped(void)7042712Snn35248 ctty_clear_sighuped(void)
7050Sstevel@tonic-gate {
7062712Snn35248 ASSERT(MUTEX_HELD(&pidlock) || MUTEX_HELD(&curproc->p_splock));
7072712Snn35248 curproc->p_sessp->s_sighuped = B_FALSE;
7080Sstevel@tonic-gate }
709