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 5*2712Snn35248 * Common Development and Distribution License (the "License"). 6*2712Snn35248 * 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*2712Snn35248 * Copyright 2006 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> 49*2712Snn35248 #include <sys/fs/snode.h> 500Sstevel@tonic-gate 510Sstevel@tonic-gate sess_t session0 = { 52*2712Snn35248 &pid0, /* s_sidp */ 53*2712Snn35248 {0}, /* s_lock */ 54*2712Snn35248 1, /* s_ref */ 55*2712Snn35248 B_FALSE, /* s_sighuped */ 56*2712Snn35248 B_FALSE, /* s_exit */ 57*2712Snn35248 0, /* s_exit_cv */ 58*2712Snn35248 0, /* s_cnt */ 59*2712Snn35248 0, /* s_cnt_cv */ 60*2712Snn35248 NODEV, /* s_dev */ 61*2712Snn35248 NULL, /* s_vp */ 62*2712Snn35248 NULL /* s_cred */ 630Sstevel@tonic-gate }; 640Sstevel@tonic-gate 650Sstevel@tonic-gate void 66*2712Snn35248 sess_hold(proc_t *p) 670Sstevel@tonic-gate { 68*2712Snn35248 ASSERT(MUTEX_HELD(&pidlock) || MUTEX_HELD(&p->p_splock)); 69*2712Snn35248 mutex_enter(&p->p_sessp->s_lock); 70*2712Snn35248 p->p_sessp->s_ref++; 71*2712Snn35248 mutex_exit(&p->p_sessp->s_lock); 72*2712Snn35248 } 73*2712Snn35248 74*2712Snn35248 void 75*2712Snn35248 sess_rele(sess_t *sp, boolean_t pidlock_held) 76*2712Snn35248 { 77*2712Snn35248 ASSERT(MUTEX_HELD(&pidlock) || !pidlock_held); 78*2712Snn35248 79*2712Snn35248 mutex_enter(&sp->s_lock); 800Sstevel@tonic-gate 810Sstevel@tonic-gate ASSERT(sp->s_ref != 0); 82*2712Snn35248 if (--sp->s_ref > 0) { 83*2712Snn35248 mutex_exit(&sp->s_lock); 84*2712Snn35248 return; 850Sstevel@tonic-gate } 86*2712Snn35248 ASSERT(sp->s_ref == 0); 87*2712Snn35248 88*2712Snn35248 /* 89*2712Snn35248 * It's ok to free this session structure now because we know 90*2712Snn35248 * that no one else can have a pointer to it. We know this 91*2712Snn35248 * to be true because the only time that s_ref can possibly 92*2712Snn35248 * be incremented is when pidlock or p_splock is held AND there 93*2712Snn35248 * is a proc_t that points to that session structure. In that 94*2712Snn35248 * case we are guaranteed that the s_ref is at least 1 since there 95*2712Snn35248 * is a proc_t that points to it. So when s_ref finally drops to 96*2712Snn35248 * zero then no one else has a reference (and hence pointer) to 97*2712Snn35248 * this session structure and there is no valid proc_t pointing 98*2712Snn35248 * to this session structure anymore so, no one can acquire a 99*2712Snn35248 * reference (and pointer) to this session structure so it's 100*2712Snn35248 * ok to free it here. 101*2712Snn35248 */ 102*2712Snn35248 103*2712Snn35248 if (sp == &session0) 104*2712Snn35248 panic("sp == &session0"); 105*2712Snn35248 106*2712Snn35248 /* make sure there are no outstanding holds */ 107*2712Snn35248 ASSERT(sp->s_cnt == 0); 108*2712Snn35248 109*2712Snn35248 /* make sure there is no exit in progress */ 110*2712Snn35248 ASSERT(!sp->s_exit); 111*2712Snn35248 112*2712Snn35248 /* make sure someone already freed any ctty */ 113*2712Snn35248 ASSERT(sp->s_vp == NULL); 114*2712Snn35248 ASSERT(sp->s_dev == NODEV); 115*2712Snn35248 116*2712Snn35248 if (!pidlock_held) 117*2712Snn35248 mutex_enter(&pidlock); 118*2712Snn35248 PID_RELE(sp->s_sidp); 119*2712Snn35248 if (!pidlock_held) 120*2712Snn35248 mutex_exit(&pidlock); 121*2712Snn35248 122*2712Snn35248 mutex_destroy(&sp->s_lock); 123*2712Snn35248 cv_destroy(&sp->s_cnt_cv); 124*2712Snn35248 kmem_free(sp, sizeof (sess_t)); 125*2712Snn35248 } 126*2712Snn35248 127*2712Snn35248 sess_t * 128*2712Snn35248 tty_hold(void) 129*2712Snn35248 { 130*2712Snn35248 proc_t *p = curproc; 131*2712Snn35248 sess_t *sp; 132*2712Snn35248 boolean_t got_sig = B_FALSE; 133*2712Snn35248 134*2712Snn35248 /* make sure the caller isn't holding locks they shouldn't */ 135*2712Snn35248 ASSERT(MUTEX_NOT_HELD(&pidlock)); 136*2712Snn35248 137*2712Snn35248 for (;;) { 138*2712Snn35248 mutex_enter(&p->p_splock); /* protect p->p_sessp */ 139*2712Snn35248 sp = p->p_sessp; 140*2712Snn35248 mutex_enter(&sp->s_lock); /* protect sp->* */ 141*2712Snn35248 142*2712Snn35248 /* make sure the caller isn't holding locks they shouldn't */ 143*2712Snn35248 ASSERT((sp->s_vp == NULL) || 144*2712Snn35248 MUTEX_NOT_HELD(&sp->s_vp->v_stream->sd_lock)); 145*2712Snn35248 146*2712Snn35248 /* 147*2712Snn35248 * If the session leader process is not exiting (and hence 148*2712Snn35248 * not trying to release the session's ctty) then we can 149*2712Snn35248 * safely grab a hold on the current session structure 150*2712Snn35248 * and return it. If on the other hand the session leader 151*2712Snn35248 * process is exiting and clearing the ctty then we'll 152*2712Snn35248 * wait till it's done before we loop around and grab a 153*2712Snn35248 * hold on the session structure. 154*2712Snn35248 */ 155*2712Snn35248 if (!sp->s_exit) 156*2712Snn35248 break; 157*2712Snn35248 158*2712Snn35248 /* need to hold the session so it can't be freed */ 159*2712Snn35248 sp->s_ref++; 160*2712Snn35248 mutex_exit(&p->p_splock); 161*2712Snn35248 162*2712Snn35248 /* Wait till the session leader is done */ 163*2712Snn35248 if (!cv_wait_sig(&sp->s_exit_cv, &sp->s_lock)) 164*2712Snn35248 got_sig = B_TRUE; 165*2712Snn35248 166*2712Snn35248 /* 167*2712Snn35248 * Now we need to drop our hold on the session structure, 168*2712Snn35248 * but we can't hold any locks when we do this because 169*2712Snn35248 * sess_rele() may need to aquire pidlock. 170*2712Snn35248 */ 171*2712Snn35248 mutex_exit(&sp->s_lock); 172*2712Snn35248 sess_rele(sp, B_FALSE); 173*2712Snn35248 174*2712Snn35248 if (got_sig) 175*2712Snn35248 return (NULL); 176*2712Snn35248 } 177*2712Snn35248 178*2712Snn35248 /* whew, we finally got a hold */ 179*2712Snn35248 sp->s_cnt++; 180*2712Snn35248 sp->s_ref++; 181*2712Snn35248 mutex_exit(&sp->s_lock); 182*2712Snn35248 mutex_exit(&p->p_splock); 183*2712Snn35248 return (sp); 184*2712Snn35248 } 185*2712Snn35248 186*2712Snn35248 void 187*2712Snn35248 tty_rele(sess_t *sp) 188*2712Snn35248 { 189*2712Snn35248 /* make sure the caller isn't holding locks they shouldn't */ 190*2712Snn35248 ASSERT(MUTEX_NOT_HELD(&pidlock)); 191*2712Snn35248 192*2712Snn35248 mutex_enter(&sp->s_lock); 193*2712Snn35248 if ((--sp->s_cnt) == 0) 194*2712Snn35248 cv_broadcast(&sp->s_cnt_cv); 195*2712Snn35248 mutex_exit(&sp->s_lock); 196*2712Snn35248 197*2712Snn35248 sess_rele(sp, B_FALSE); 1980Sstevel@tonic-gate } 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate void 2010Sstevel@tonic-gate sess_create(void) 2020Sstevel@tonic-gate { 203*2712Snn35248 proc_t *p = curproc; 204*2712Snn35248 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); 209*2712Snn35248 cv_init(&sp->s_cnt_cv, NULL, CV_DEFAULT, NULL); 2100Sstevel@tonic-gate 2110Sstevel@tonic-gate /* 212*2712Snn35248 * we need to grap p_lock to protect p_pgidp because 213*2712Snn35248 * /proc looks at p_pgidp while holding only p_lock. 214*2712Snn35248 * 215*2712Snn35248 * we don't need to hold p->p_sessp->s_lock or get a hold on the 216*2712Snn35248 * session structure since we're not actually updating any of 217*2712Snn35248 * the contents of the old session structure. 2180Sstevel@tonic-gate */ 219*2712Snn35248 mutex_enter(&pidlock); 220*2712Snn35248 mutex_enter(&p->p_lock); 221*2712Snn35248 mutex_enter(&p->p_splock); 2220Sstevel@tonic-gate 223*2712Snn35248 pgexit(p); 224*2712Snn35248 225*2712Snn35248 sp->s_sidp = p->p_pidp; 2260Sstevel@tonic-gate sp->s_ref = 1; 2270Sstevel@tonic-gate sp->s_dev = NODEV; 2280Sstevel@tonic-gate 229*2712Snn35248 old_sp = p->p_sessp; 230*2712Snn35248 p->p_sessp = sp; 231*2712Snn35248 232*2712Snn35248 pgjoin(p, p->p_pidp); 233*2712Snn35248 PID_HOLD(p->p_pidp); 2340Sstevel@tonic-gate 235*2712Snn35248 mutex_exit(&p->p_splock); 236*2712Snn35248 mutex_exit(&p->p_lock); 237*2712Snn35248 mutex_exit(&pidlock); 2380Sstevel@tonic-gate 239*2712Snn35248 sess_rele(old_sp, B_FALSE); 2400Sstevel@tonic-gate } 2410Sstevel@tonic-gate 242*2712Snn35248 /* 243*2712Snn35248 * Note that sess_ctty_clear() resets all the fields in the session 244*2712Snn35248 * structure but doesn't release any holds or free any objects 245*2712Snn35248 * that the session structure might currently point to. it is the 246*2712Snn35248 * callers responsibility to do this. 247*2712Snn35248 */ 248*2712Snn35248 static void 249*2712Snn35248 sess_ctty_clear(sess_t *sp, stdata_t *stp) 2500Sstevel@tonic-gate { 251*2712Snn35248 /* 252*2712Snn35248 * Assert that we hold all the necessary locks. We also need 253*2712Snn35248 * to be holding proc_t->p_splock for the process associated 254*2712Snn35248 * with this session, but since we don't have a proc pointer 255*2712Snn35248 * passed in we can't assert this here. 256*2712Snn35248 */ 257*2712Snn35248 ASSERT(MUTEX_HELD(&stp->sd_lock) && MUTEX_HELD(&pidlock) && 258*2712Snn35248 MUTEX_HELD(&sp->s_lock)); 2590Sstevel@tonic-gate 260*2712Snn35248 /* reset the session structure members to defaults */ 261*2712Snn35248 sp->s_sighuped = B_FALSE; 262*2712Snn35248 sp->s_dev = NODEV; 2630Sstevel@tonic-gate sp->s_vp = NULL; 264560Smeem sp->s_cred = NULL; 2650Sstevel@tonic-gate 266*2712Snn35248 /* reset the stream session and group pointers */ 267*2712Snn35248 stp->sd_pgidp = NULL; 268*2712Snn35248 stp->sd_sidp = NULL; 269*2712Snn35248 } 270*2712Snn35248 271*2712Snn35248 static void 272*2712Snn35248 sess_ctty_set(proc_t *p, sess_t *sp, stdata_t *stp) 273*2712Snn35248 { 274*2712Snn35248 cred_t *crp; 275*2712Snn35248 276*2712Snn35248 /* Assert that we hold all the necessary locks. */ 277*2712Snn35248 ASSERT(MUTEX_HELD(&stp->sd_lock) && MUTEX_HELD(&pidlock) && 278*2712Snn35248 MUTEX_HELD(&p->p_splock) && MUTEX_HELD(&sp->s_lock)); 279*2712Snn35248 280*2712Snn35248 /* get holds on structures */ 281*2712Snn35248 mutex_enter(&p->p_crlock); 282*2712Snn35248 crhold(crp = p->p_cred); 283*2712Snn35248 mutex_exit(&p->p_crlock); 284*2712Snn35248 PID_HOLD(sp->s_sidp); /* requires pidlock */ 285*2712Snn35248 PID_HOLD(sp->s_sidp); /* requires pidlock */ 286*2712Snn35248 287*2712Snn35248 /* update the session structure members */ 288*2712Snn35248 sp->s_vp = makectty(stp->sd_vnode); 289*2712Snn35248 sp->s_dev = sp->s_vp->v_rdev; 290*2712Snn35248 sp->s_cred = crp; 291*2712Snn35248 292*2712Snn35248 /* update the stream emebers */ 293*2712Snn35248 stp->sd_flag |= STRISTTY; /* just to be sure */ 294*2712Snn35248 stp->sd_sidp = sp->s_sidp; 295*2712Snn35248 stp->sd_pgidp = sp->s_sidp; 296*2712Snn35248 } 297*2712Snn35248 298*2712Snn35248 int 299*2712Snn35248 strctty(stdata_t *stp) 300*2712Snn35248 { 301*2712Snn35248 sess_t *sp; 302*2712Snn35248 proc_t *p = curproc; 303*2712Snn35248 boolean_t got_sig = B_FALSE; 304*2712Snn35248 3050Sstevel@tonic-gate /* 306*2712Snn35248 * We are going to try to make stp the default ctty for the session 307*2712Snn35248 * associated with curproc. Not only does this require holding a 308*2712Snn35248 * bunch of locks but it also requires waiting for any outstanding 309*2712Snn35248 * holds on the session structure (aquired via tty_hold()) to be 310*2712Snn35248 * released. Hence, we have the following for(;;) loop that will 311*2712Snn35248 * aquire our locks, do some sanity checks, and wait for the hold 312*2712Snn35248 * count on the session structure to hit zero. If we get a signal 313*2712Snn35248 * while waiting for outstanding holds to be released then we abort 314*2712Snn35248 * the operation and return. 3150Sstevel@tonic-gate */ 316*2712Snn35248 for (;;) { 317*2712Snn35248 mutex_enter(&stp->sd_lock); /* protects sd_pgidp/sd_sidp */ 318*2712Snn35248 mutex_enter(&pidlock); /* protects p_pidp */ 319*2712Snn35248 mutex_enter(&p->p_splock); /* protects p_sessp */ 320*2712Snn35248 sp = p->p_sessp; 321*2712Snn35248 mutex_enter(&sp->s_lock); /* protects sp->* */ 3220Sstevel@tonic-gate 323*2712Snn35248 if (((stp->sd_flag & (STRHUP|STRDERR|STWRERR|STPLEX)) != 0) || 324*2712Snn35248 (stp->sd_sidp != NULL) || /* stp already ctty? */ 325*2712Snn35248 (p->p_pidp != sp->s_sidp) || /* we're not leader? */ 326*2712Snn35248 (sp->s_vp != NULL)) { /* session has ctty? */ 327*2712Snn35248 mutex_exit(&sp->s_lock); 328*2712Snn35248 mutex_exit(&p->p_splock); 329*2712Snn35248 mutex_exit(&pidlock); 330*2712Snn35248 mutex_exit(&stp->sd_lock); 331*2712Snn35248 return (ENOTTY); 332*2712Snn35248 } 333*2712Snn35248 334*2712Snn35248 /* sanity check. we can't be exiting right now */ 335*2712Snn35248 ASSERT(!sp->s_exit); 336*2712Snn35248 337*2712Snn35248 /* 338*2712Snn35248 * If no one else has a hold on this session structure 339*2712Snn35248 * then we now have exclusive access to it, so break out 340*2712Snn35248 * of this loop and update the session structure. 341*2712Snn35248 */ 342*2712Snn35248 if (sp->s_cnt == 0) 343*2712Snn35248 break; 344*2712Snn35248 345*2712Snn35248 /* need to hold the session so it can't be freed */ 346*2712Snn35248 sp->s_ref++; 347*2712Snn35248 348*2712Snn35248 /* ain't locking order fun? */ 349*2712Snn35248 mutex_exit(&p->p_splock); 350*2712Snn35248 mutex_exit(&pidlock); 351*2712Snn35248 mutex_exit(&stp->sd_lock); 352*2712Snn35248 353*2712Snn35248 if (!cv_wait_sig(&sp->s_cnt_cv, &sp->s_lock)) 354*2712Snn35248 got_sig = B_TRUE; 355*2712Snn35248 mutex_exit(&sp->s_lock); 356*2712Snn35248 sess_rele(sp, B_FALSE); 357*2712Snn35248 358*2712Snn35248 if (got_sig) 359*2712Snn35248 return (EINTR); 360*2712Snn35248 } 361*2712Snn35248 362*2712Snn35248 /* set the session ctty bindings */ 363*2712Snn35248 sess_ctty_set(p, sp, stp); 364*2712Snn35248 3650Sstevel@tonic-gate mutex_exit(&sp->s_lock); 366*2712Snn35248 mutex_exit(&p->p_splock); 367*2712Snn35248 mutex_exit(&pidlock); 368*2712Snn35248 mutex_exit(&stp->sd_lock); 369*2712Snn35248 return (0); 370*2712Snn35248 } 371*2712Snn35248 372*2712Snn35248 /* 373*2712Snn35248 * freectty_lock() attempts to aquire the army of locks required to free 374*2712Snn35248 * the ctty associated with a given session leader process. If it returns 375*2712Snn35248 * successfully the following locks will be held: 376*2712Snn35248 * sd_lock, pidlock, p_splock, s_lock 377*2712Snn35248 * 378*2712Snn35248 * as a secondary bit of convience, freectty_lock() will also return 379*2712Snn35248 * pointers to the session, ctty, and ctty stream associated with the 380*2712Snn35248 * specified session leader process. 381*2712Snn35248 */ 382*2712Snn35248 static boolean_t 383*2712Snn35248 freectty_lock(proc_t *p, sess_t **spp, vnode_t **vpp, stdata_t **stpp, 384*2712Snn35248 boolean_t at_exit) 385*2712Snn35248 { 386*2712Snn35248 sess_t *sp; 387*2712Snn35248 vnode_t *vp; 388*2712Snn35248 stdata_t *stp; 389*2712Snn35248 390*2712Snn35248 mutex_enter(&pidlock); /* protect p_pidp */ 391*2712Snn35248 mutex_enter(&p->p_splock); /* protect p->p_sessp */ 392*2712Snn35248 sp = p->p_sessp; 393*2712Snn35248 mutex_enter(&sp->s_lock); /* protect sp->* */ 394*2712Snn35248 395*2712Snn35248 if ((sp->s_sidp != p->p_pidp) || /* we're not leader? */ 396*2712Snn35248 (sp->s_vp == NULL)) { /* no ctty? */ 397*2712Snn35248 mutex_exit(&sp->s_lock); 398*2712Snn35248 mutex_exit(&p->p_splock); 399*2712Snn35248 mutex_exit(&pidlock); 400*2712Snn35248 return (B_FALSE); 401*2712Snn35248 } 402*2712Snn35248 403*2712Snn35248 vp = sp->s_vp; 404*2712Snn35248 stp = sp->s_vp->v_stream; 405*2712Snn35248 406*2712Snn35248 if (at_exit) { 407*2712Snn35248 /* stop anyone else calling tty_hold() */ 408*2712Snn35248 sp->s_exit = B_TRUE; 409*2712Snn35248 } else { 410*2712Snn35248 /* 411*2712Snn35248 * due to locking order we have to grab stp->sd_lock before 412*2712Snn35248 * grabbing all the other proc/session locks. but after we 413*2712Snn35248 * drop all our current locks it's possible that someone 414*2712Snn35248 * could come in and change our current session or close 415*2712Snn35248 * the current ctty (vp) there by making sp or stp invalid. 416*2712Snn35248 * (a VN_HOLD on vp won't protect stp because that only 417*2712Snn35248 * prevents the vnode from being freed not closed.) so 418*2712Snn35248 * to prevent this we bump s_ref and s_cnt here. 419*2712Snn35248 * 420*2712Snn35248 * course this doesn't matter if we're the last thread in 421*2712Snn35248 * an exiting process that is the session leader, since no 422*2712Snn35248 * one else can change our session or free our ctty. 423*2712Snn35248 */ 424*2712Snn35248 sp->s_ref++; /* hold the session structure */ 425*2712Snn35248 sp->s_cnt++; /* protect vp and stp */ 426*2712Snn35248 } 427*2712Snn35248 428*2712Snn35248 /* drop our session locks */ 429*2712Snn35248 mutex_exit(&sp->s_lock); 430*2712Snn35248 mutex_exit(&p->p_splock); 431*2712Snn35248 mutex_exit(&pidlock); 432*2712Snn35248 433*2712Snn35248 /* grab locks in the right order */ 434*2712Snn35248 mutex_enter(&stp->sd_lock); /* protects sd_pgidp/sd_sidp */ 435*2712Snn35248 mutex_enter(&pidlock); /* protect p_pidp */ 436*2712Snn35248 mutex_enter(&p->p_splock); /* protects p->p_sessp */ 437*2712Snn35248 mutex_enter(&sp->s_lock); /* protects sp->* */ 438*2712Snn35248 439*2712Snn35248 /* if the session has changed, abort mission */ 440*2712Snn35248 if (sp != p->p_sessp) { 441*2712Snn35248 /* 442*2712Snn35248 * this can't happen during process exit since we're the 443*2712Snn35248 * only thread in the process and we sure didn't change 444*2712Snn35248 * our own session at this point. 445*2712Snn35248 */ 446*2712Snn35248 ASSERT(!at_exit); 447*2712Snn35248 448*2712Snn35248 /* release our locks and holds */ 449*2712Snn35248 mutex_exit(&sp->s_lock); 450*2712Snn35248 mutex_exit(&p->p_splock); 451*2712Snn35248 mutex_exit(&pidlock); 452*2712Snn35248 mutex_exit(&stp->sd_lock); 453*2712Snn35248 tty_rele(sp); 454*2712Snn35248 return (B_FALSE); 455*2712Snn35248 } 4560Sstevel@tonic-gate 4570Sstevel@tonic-gate /* 458*2712Snn35248 * sanity checks. none of this should have changed since we had 459*2712Snn35248 * holds on the current ctty. 4600Sstevel@tonic-gate */ 461*2712Snn35248 ASSERT(sp->s_sidp == p->p_pidp); /* we're the leader */ 462*2712Snn35248 ASSERT(sp->s_vp != NULL); /* a ctty exists */ 463*2712Snn35248 ASSERT(vp == sp->s_vp); 464*2712Snn35248 ASSERT(stp == sp->s_vp->v_stream); 4650Sstevel@tonic-gate 466*2712Snn35248 /* release our holds */ 467*2712Snn35248 if (!at_exit) { 468*2712Snn35248 if ((--(sp)->s_cnt) == 0) 469*2712Snn35248 cv_broadcast(&sp->s_cnt_cv); 470*2712Snn35248 sp->s_ref--; 471*2712Snn35248 ASSERT(sp->s_ref > 0); 472*2712Snn35248 } 473*2712Snn35248 474*2712Snn35248 /* return our pointers */ 475*2712Snn35248 *spp = sp; 476*2712Snn35248 *vpp = vp; 477*2712Snn35248 *stpp = stp; 478*2712Snn35248 479*2712Snn35248 return (B_TRUE); 480*2712Snn35248 } 481*2712Snn35248 482*2712Snn35248 /* 483*2712Snn35248 * Returns B_FALSE if no signal is sent to the process group associated with 484*2712Snn35248 * this ctty. Returns B_TRUE if a signal is sent to the process group. 485*2712Snn35248 * If it return B_TRUE it also means that all the locks we were holding 486*2712Snn35248 * were dropped so that we could send the signal. 487*2712Snn35248 */ 488*2712Snn35248 static boolean_t 489*2712Snn35248 freectty_signal(proc_t *p, sess_t *sp, stdata_t *stp, boolean_t at_exit) 490*2712Snn35248 { 491*2712Snn35248 /* Assert that we hold all the necessary locks. */ 492*2712Snn35248 ASSERT(MUTEX_HELD(&stp->sd_lock) && MUTEX_HELD(&pidlock) && 493*2712Snn35248 MUTEX_HELD(&p->p_splock) && MUTEX_HELD(&sp->s_lock)); 494*2712Snn35248 495*2712Snn35248 /* check if we already signaled this group */ 496*2712Snn35248 if (sp->s_sighuped) 497*2712Snn35248 return (B_FALSE); 498*2712Snn35248 499*2712Snn35248 sp->s_sighuped = B_TRUE; 500*2712Snn35248 501*2712Snn35248 if (!at_exit) { 502*2712Snn35248 /* 503*2712Snn35248 * once again, we're about to drop our army of locks and we 504*2712Snn35248 * don't want sp or stp to be freed. (see the comment in 505*2712Snn35248 * freectty_lock()) 506*2712Snn35248 */ 507*2712Snn35248 sp->s_ref++; /* hold the session structure */ 508*2712Snn35248 sp->s_cnt++; /* protect vp and stp */ 509*2712Snn35248 } 510*2712Snn35248 511*2712Snn35248 /* can't hold these locks while calling pgsignal() */ 512*2712Snn35248 mutex_exit(&sp->s_lock); 513*2712Snn35248 mutex_exit(&p->p_splock); 514*2712Snn35248 mutex_exit(&pidlock); 515*2712Snn35248 516*2712Snn35248 /* signal anyone in the foreground process group */ 517*2712Snn35248 pgsignal(stp->sd_pgidp, SIGHUP); 518*2712Snn35248 519*2712Snn35248 /* signal anyone blocked in poll on this stream */ 520*2712Snn35248 if (!(stp->sd_flag & STRHUP)) 521*2712Snn35248 strhup(stp); 522*2712Snn35248 523*2712Snn35248 mutex_exit(&stp->sd_lock); 524*2712Snn35248 525*2712Snn35248 /* release our holds */ 526*2712Snn35248 if (!at_exit) 527*2712Snn35248 tty_rele(sp); 528*2712Snn35248 529*2712Snn35248 return (B_TRUE); 530*2712Snn35248 } 531*2712Snn35248 532*2712Snn35248 int 533*2712Snn35248 freectty(boolean_t at_exit) 534*2712Snn35248 { 535*2712Snn35248 proc_t *p = curproc; 536*2712Snn35248 stdata_t *stp; 537*2712Snn35248 vnode_t *vp; 538*2712Snn35248 cred_t *cred; 539*2712Snn35248 sess_t *sp; 540*2712Snn35248 struct pid *pgidp, *sidp; 541*2712Snn35248 boolean_t got_sig = B_FALSE; 542*2712Snn35248 543*2712Snn35248 /* 544*2712Snn35248 * If the current process is a session leader we are going to 545*2712Snn35248 * try to release the ctty associated our current session. To 546*2712Snn35248 * do this we need to aquire a bunch of locks, signal any 547*2712Snn35248 * processes in the forground that are associated with the ctty, 548*2712Snn35248 * and make sure no one has any outstanding holds on the current 549*2712Snn35248 * session * structure (aquired via tty_hold()). Hence, we have 550*2712Snn35248 * the following for(;;) loop that will do all this work for 551*2712Snn35248 * us and break out when the hold count on the session structure 552*2712Snn35248 * hits zero. 553*2712Snn35248 */ 554*2712Snn35248 for (;;) { 555*2712Snn35248 if (!freectty_lock(p, &sp, &vp, &stp, at_exit)) 556*2712Snn35248 return (EIO); 557*2712Snn35248 558*2712Snn35248 if (freectty_signal(p, sp, stp, at_exit)) { 559*2712Snn35248 /* loop around to re-aquire locks */ 560*2712Snn35248 continue; 561*2712Snn35248 } 562*2712Snn35248 563*2712Snn35248 /* 564*2712Snn35248 * Only a session leader process can free a ctty. So if 565*2712Snn35248 * we've made it here we know we're a session leader and 566*2712Snn35248 * if we're not actively exiting it impossible for another 567*2712Snn35248 * thread in this process to be exiting. (Because that 568*2712Snn35248 * thread would have already stopped all other threads 569*2712Snn35248 * in the current process.) 570*2712Snn35248 */ 571*2712Snn35248 ASSERT(at_exit || !sp->s_exit); 572*2712Snn35248 573*2712Snn35248 /* 574*2712Snn35248 * If no one else has a hold on this session structure 575*2712Snn35248 * then we now have exclusive access to it, so break out 576*2712Snn35248 * of this loop and update the session structure. 577*2712Snn35248 */ 578*2712Snn35248 if (sp->s_cnt == 0) 579*2712Snn35248 break; 580*2712Snn35248 581*2712Snn35248 if (!at_exit) { 582*2712Snn35248 /* need to hold the session so it can't be freed */ 583*2712Snn35248 sp->s_ref++; 584*2712Snn35248 } 585*2712Snn35248 586*2712Snn35248 /* ain't locking order fun? */ 587*2712Snn35248 mutex_exit(&p->p_splock); 588*2712Snn35248 mutex_exit(&pidlock); 589*2712Snn35248 mutex_exit(&stp->sd_lock); 590*2712Snn35248 591*2712Snn35248 if (at_exit) { 592*2712Snn35248 /* 593*2712Snn35248 * if we're exiting then we can't allow this operation 594*2712Snn35248 * to fail so we do a cw_wait() instead of a 595*2712Snn35248 * cv_wait_sig(). if there are threads with active 596*2712Snn35248 * holds on this ctty that are blocked, then 597*2712Snn35248 * they should only be blocked in a cv_wait_sig() 598*2712Snn35248 * and hopefully they were in the foreground process 599*2712Snn35248 * group and recieved the SIGHUP we sent above. of 600*2712Snn35248 * course it's possible that they weren't in the 601*2712Snn35248 * foreground process group and didn't get our 602*2712Snn35248 * signal (or they could be stopped by job control 603*2712Snn35248 * in which case our signal wouldn't matter until 604*2712Snn35248 * they are restarted). in this case we won't 605*2712Snn35248 * exit until someone else sends them a signal. 606*2712Snn35248 */ 607*2712Snn35248 cv_wait(&sp->s_cnt_cv, &sp->s_lock); 608*2712Snn35248 mutex_exit(&sp->s_lock); 609*2712Snn35248 continue; 610*2712Snn35248 } 611*2712Snn35248 612*2712Snn35248 if (!cv_wait_sig(&sp->s_cnt_cv, &sp->s_lock)) { 613*2712Snn35248 got_sig = B_TRUE; 614*2712Snn35248 } 615*2712Snn35248 616*2712Snn35248 mutex_exit(&sp->s_lock); 617*2712Snn35248 sess_rele(sp, B_FALSE); 618*2712Snn35248 619*2712Snn35248 if (got_sig) 620*2712Snn35248 return (EINTR); 621*2712Snn35248 } 622*2712Snn35248 ASSERT(sp->s_cnt == 0); 623*2712Snn35248 624*2712Snn35248 /* save some pointers for later */ 625*2712Snn35248 cred = sp->s_cred; 626*2712Snn35248 pgidp = stp->sd_pgidp; 627*2712Snn35248 sidp = stp->sd_sidp; 628*2712Snn35248 629*2712Snn35248 /* clear the session ctty bindings */ 630*2712Snn35248 sess_ctty_clear(sp, stp); 631*2712Snn35248 632*2712Snn35248 /* wake up anyone blocked in tty_hold() */ 633*2712Snn35248 if (at_exit) { 634*2712Snn35248 ASSERT(sp->s_exit); 635*2712Snn35248 sp->s_exit = B_FALSE; 636*2712Snn35248 cv_broadcast(&sp->s_exit_cv); 637*2712Snn35248 } 638*2712Snn35248 639*2712Snn35248 /* we can drop these locks now */ 640*2712Snn35248 mutex_exit(&sp->s_lock); 641*2712Snn35248 mutex_exit(&p->p_splock); 642*2712Snn35248 mutex_exit(&pidlock); 643*2712Snn35248 mutex_exit(&stp->sd_lock); 644*2712Snn35248 645*2712Snn35248 /* This is the only remaining thread with access to this vnode */ 6460Sstevel@tonic-gate (void) VOP_CLOSE(vp, 0, 1, (offset_t)0, cred); 6470Sstevel@tonic-gate VN_RELE(vp); 648*2712Snn35248 crfree(cred); 6490Sstevel@tonic-gate 650*2712Snn35248 /* release our holds on assorted structures and return */ 651*2712Snn35248 mutex_enter(&pidlock); 652*2712Snn35248 PID_RELE(pgidp); 653*2712Snn35248 PID_RELE(sidp); 654*2712Snn35248 mutex_exit(&pidlock); 655*2712Snn35248 656*2712Snn35248 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 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 6810Sstevel@tonic-gate cttydev(proc_t *pp) 6820Sstevel@tonic-gate { 683*2712Snn35248 sess_t *sp; 684*2712Snn35248 dev_t dev; 685*2712Snn35248 686*2712Snn35248 mutex_enter(&pp->p_splock); /* protects p->p_sessp */ 687*2712Snn35248 sp = pp->p_sessp; 688*2712Snn35248 689*2712Snn35248 #ifdef DEBUG 690*2712Snn35248 mutex_enter(&sp->s_lock); /* protects sp->* */ 6910Sstevel@tonic-gate if (sp->s_vp == NULL) 692*2712Snn35248 ASSERT(sp->s_dev == NODEV); 693*2712Snn35248 else 694*2712Snn35248 ASSERT(sp->s_dev != NODEV); 695*2712Snn35248 mutex_exit(&sp->s_lock); 696*2712Snn35248 #endif /* DEBUG */ 697*2712Snn35248 698*2712Snn35248 dev = sp->s_dev; 699*2712Snn35248 mutex_exit(&pp->p_splock); 700*2712Snn35248 return (dev); 7010Sstevel@tonic-gate } 7020Sstevel@tonic-gate 7030Sstevel@tonic-gate void 704*2712Snn35248 ctty_clear_sighuped(void) 7050Sstevel@tonic-gate { 706*2712Snn35248 ASSERT(MUTEX_HELD(&pidlock) || MUTEX_HELD(&curproc->p_splock)); 707*2712Snn35248 curproc->p_sessp->s_sighuped = B_FALSE; 7080Sstevel@tonic-gate } 709