1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29
30 #pragma ident "%Z%%M% %I% %E% SMI"
31
32 #include <sys/types.h>
33 #include <sys/sysmacros.h>
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/file.h>
37 #include <sys/vnode.h>
38 #include <sys/errno.h>
39 #include <sys/signal.h>
40 #include <sys/cred.h>
41 #include <sys/policy.h>
42 #include <sys/conf.h>
43 #include <sys/debug.h>
44 #include <sys/proc.h>
45 #include <sys/session.h>
46 #include <sys/kmem.h>
47 #include <sys/cmn_err.h>
48 #include <sys/strsubr.h>
49 #include <sys/fs/snode.h>
50
51 sess_t session0 = {
52 &pid0, /* s_sidp */
53 {0}, /* s_lock */
54 1, /* s_ref */
55 B_FALSE, /* s_sighuped */
56 B_FALSE, /* s_exit */
57 0, /* s_exit_cv */
58 0, /* s_cnt */
59 0, /* s_cnt_cv */
60 NODEV, /* s_dev */
61 NULL, /* s_vp */
62 NULL /* s_cred */
63 };
64
65 void
sess_hold(proc_t * p)66 sess_hold(proc_t *p)
67 {
68 ASSERT(MUTEX_HELD(&pidlock) || MUTEX_HELD(&p->p_splock));
69 mutex_enter(&p->p_sessp->s_lock);
70 p->p_sessp->s_ref++;
71 mutex_exit(&p->p_sessp->s_lock);
72 }
73
74 void
sess_rele(sess_t * sp,boolean_t pidlock_held)75 sess_rele(sess_t *sp, boolean_t pidlock_held)
76 {
77 ASSERT(MUTEX_HELD(&pidlock) || !pidlock_held);
78
79 mutex_enter(&sp->s_lock);
80
81 ASSERT(sp->s_ref != 0);
82 if (--sp->s_ref > 0) {
83 mutex_exit(&sp->s_lock);
84 return;
85 }
86 ASSERT(sp->s_ref == 0);
87
88 /*
89 * It's ok to free this session structure now because we know
90 * that no one else can have a pointer to it. We know this
91 * to be true because the only time that s_ref can possibly
92 * be incremented is when pidlock or p_splock is held AND there
93 * is a proc_t that points to that session structure. In that
94 * case we are guaranteed that the s_ref is at least 1 since there
95 * is a proc_t that points to it. So when s_ref finally drops to
96 * zero then no one else has a reference (and hence pointer) to
97 * this session structure and there is no valid proc_t pointing
98 * to this session structure anymore so, no one can acquire a
99 * reference (and pointer) to this session structure so it's
100 * ok to free it here.
101 */
102
103 if (sp == &session0)
104 panic("sp == &session0");
105
106 /* make sure there are no outstanding holds */
107 ASSERT(sp->s_cnt == 0);
108
109 /* make sure there is no exit in progress */
110 ASSERT(!sp->s_exit);
111
112 /* make sure someone already freed any ctty */
113 ASSERT(sp->s_vp == NULL);
114 ASSERT(sp->s_dev == NODEV);
115
116 if (!pidlock_held)
117 mutex_enter(&pidlock);
118 PID_RELE(sp->s_sidp);
119 if (!pidlock_held)
120 mutex_exit(&pidlock);
121
122 mutex_destroy(&sp->s_lock);
123 cv_destroy(&sp->s_cnt_cv);
124 kmem_free(sp, sizeof (sess_t));
125 }
126
127 sess_t *
tty_hold(void)128 tty_hold(void)
129 {
130 proc_t *p = curproc;
131 sess_t *sp;
132 boolean_t got_sig = B_FALSE;
133
134 /* make sure the caller isn't holding locks they shouldn't */
135 ASSERT(MUTEX_NOT_HELD(&pidlock));
136
137 for (;;) {
138 mutex_enter(&p->p_splock); /* protect p->p_sessp */
139 sp = p->p_sessp;
140 mutex_enter(&sp->s_lock); /* protect sp->* */
141
142 /* make sure the caller isn't holding locks they shouldn't */
143 ASSERT((sp->s_vp == NULL) ||
144 MUTEX_NOT_HELD(&sp->s_vp->v_stream->sd_lock));
145
146 /*
147 * If the session leader process is not exiting (and hence
148 * not trying to release the session's ctty) then we can
149 * safely grab a hold on the current session structure
150 * and return it. If on the other hand the session leader
151 * process is exiting and clearing the ctty then we'll
152 * wait till it's done before we loop around and grab a
153 * hold on the session structure.
154 */
155 if (!sp->s_exit)
156 break;
157
158 /* need to hold the session so it can't be freed */
159 sp->s_ref++;
160 mutex_exit(&p->p_splock);
161
162 /* Wait till the session leader is done */
163 if (!cv_wait_sig(&sp->s_exit_cv, &sp->s_lock))
164 got_sig = B_TRUE;
165
166 /*
167 * Now we need to drop our hold on the session structure,
168 * but we can't hold any locks when we do this because
169 * sess_rele() may need to acquire pidlock.
170 */
171 mutex_exit(&sp->s_lock);
172 sess_rele(sp, B_FALSE);
173
174 if (got_sig)
175 return (NULL);
176 }
177
178 /* whew, we finally got a hold */
179 sp->s_cnt++;
180 sp->s_ref++;
181 mutex_exit(&sp->s_lock);
182 mutex_exit(&p->p_splock);
183 return (sp);
184 }
185
186 void
tty_rele(sess_t * sp)187 tty_rele(sess_t *sp)
188 {
189 /* make sure the caller isn't holding locks they shouldn't */
190 ASSERT(MUTEX_NOT_HELD(&pidlock));
191
192 mutex_enter(&sp->s_lock);
193 if ((--sp->s_cnt) == 0)
194 cv_broadcast(&sp->s_cnt_cv);
195 mutex_exit(&sp->s_lock);
196
197 sess_rele(sp, B_FALSE);
198 }
199
200 void
sess_create(void)201 sess_create(void)
202 {
203 proc_t *p = curproc;
204 sess_t *sp, *old_sp;
205
206 sp = kmem_zalloc(sizeof (sess_t), KM_SLEEP);
207
208 mutex_init(&sp->s_lock, NULL, MUTEX_DEFAULT, NULL);
209 cv_init(&sp->s_cnt_cv, NULL, CV_DEFAULT, NULL);
210
211 /*
212 * we need to grap p_lock to protect p_pgidp because
213 * /proc looks at p_pgidp while holding only p_lock.
214 *
215 * we don't need to hold p->p_sessp->s_lock or get a hold on the
216 * session structure since we're not actually updating any of
217 * the contents of the old session structure.
218 */
219 mutex_enter(&pidlock);
220 mutex_enter(&p->p_lock);
221 mutex_enter(&p->p_splock);
222
223 pgexit(p);
224
225 sp->s_sidp = p->p_pidp;
226 sp->s_ref = 1;
227 sp->s_dev = NODEV;
228
229 old_sp = p->p_sessp;
230 p->p_sessp = sp;
231
232 pgjoin(p, p->p_pidp);
233 PID_HOLD(p->p_pidp);
234
235 mutex_exit(&p->p_splock);
236 mutex_exit(&p->p_lock);
237 mutex_exit(&pidlock);
238
239 sess_rele(old_sp, B_FALSE);
240 }
241
242 /*
243 * Note that sess_ctty_clear() resets all the fields in the session
244 * structure but doesn't release any holds or free any objects
245 * that the session structure might currently point to. it is the
246 * callers responsibility to do this.
247 */
248 static void
sess_ctty_clear(sess_t * sp,stdata_t * stp)249 sess_ctty_clear(sess_t *sp, stdata_t *stp)
250 {
251 /*
252 * Assert that we hold all the necessary locks. We also need
253 * to be holding proc_t->p_splock for the process associated
254 * with this session, but since we don't have a proc pointer
255 * passed in we can't assert this here.
256 */
257 ASSERT(MUTEX_HELD(&stp->sd_lock) && MUTEX_HELD(&pidlock) &&
258 MUTEX_HELD(&sp->s_lock));
259
260 /* reset the session structure members to defaults */
261 sp->s_sighuped = B_FALSE;
262 sp->s_dev = NODEV;
263 sp->s_vp = NULL;
264 sp->s_cred = NULL;
265
266 /* reset the stream session and group pointers */
267 stp->sd_pgidp = NULL;
268 stp->sd_sidp = NULL;
269 }
270
271 static void
sess_ctty_set(proc_t * p,sess_t * sp,stdata_t * stp)272 sess_ctty_set(proc_t *p, sess_t *sp, stdata_t *stp)
273 {
274 cred_t *crp;
275
276 /* Assert that we hold all the necessary locks. */
277 ASSERT(MUTEX_HELD(&stp->sd_lock) && MUTEX_HELD(&pidlock) &&
278 MUTEX_HELD(&p->p_splock) && MUTEX_HELD(&sp->s_lock));
279
280 /* get holds on structures */
281 mutex_enter(&p->p_crlock);
282 crhold(crp = p->p_cred);
283 mutex_exit(&p->p_crlock);
284 PID_HOLD(sp->s_sidp); /* requires pidlock */
285 PID_HOLD(sp->s_sidp); /* requires pidlock */
286
287 /* update the session structure members */
288 sp->s_vp = makectty(stp->sd_vnode);
289 sp->s_dev = sp->s_vp->v_rdev;
290 sp->s_cred = crp;
291
292 /* update the stream emebers */
293 stp->sd_flag |= STRISTTY; /* just to be sure */
294 stp->sd_sidp = sp->s_sidp;
295 stp->sd_pgidp = sp->s_sidp;
296 }
297
298 int
strctty(stdata_t * stp)299 strctty(stdata_t *stp)
300 {
301 sess_t *sp;
302 proc_t *p = curproc;
303 boolean_t got_sig = B_FALSE;
304
305 /*
306 * We are going to try to make stp the default ctty for the session
307 * associated with curproc. Not only does this require holding a
308 * bunch of locks but it also requires waiting for any outstanding
309 * holds on the session structure (acquired via tty_hold()) to be
310 * released. Hence, we have the following for(;;) loop that will
311 * acquire our locks, do some sanity checks, and wait for the hold
312 * count on the session structure to hit zero. If we get a signal
313 * while waiting for outstanding holds to be released then we abort
314 * the operation and return.
315 */
316 for (;;) {
317 mutex_enter(&stp->sd_lock); /* protects sd_pgidp/sd_sidp */
318 mutex_enter(&pidlock); /* protects p_pidp */
319 mutex_enter(&p->p_splock); /* protects p_sessp */
320 sp = p->p_sessp;
321 mutex_enter(&sp->s_lock); /* protects sp->* */
322
323 if (((stp->sd_flag & (STRHUP|STRDERR|STWRERR|STPLEX)) != 0) ||
324 (stp->sd_sidp != NULL) || /* stp already ctty? */
325 (p->p_pidp != sp->s_sidp) || /* we're not leader? */
326 (sp->s_vp != NULL)) { /* session has ctty? */
327 mutex_exit(&sp->s_lock);
328 mutex_exit(&p->p_splock);
329 mutex_exit(&pidlock);
330 mutex_exit(&stp->sd_lock);
331 return (ENOTTY);
332 }
333
334 /* sanity check. we can't be exiting right now */
335 ASSERT(!sp->s_exit);
336
337 /*
338 * If no one else has a hold on this session structure
339 * then we now have exclusive access to it, so break out
340 * of this loop and update the session structure.
341 */
342 if (sp->s_cnt == 0)
343 break;
344
345 /* need to hold the session so it can't be freed */
346 sp->s_ref++;
347
348 /* ain't locking order fun? */
349 mutex_exit(&p->p_splock);
350 mutex_exit(&pidlock);
351 mutex_exit(&stp->sd_lock);
352
353 if (!cv_wait_sig(&sp->s_cnt_cv, &sp->s_lock))
354 got_sig = B_TRUE;
355 mutex_exit(&sp->s_lock);
356 sess_rele(sp, B_FALSE);
357
358 if (got_sig)
359 return (EINTR);
360 }
361
362 /* set the session ctty bindings */
363 sess_ctty_set(p, sp, stp);
364
365 mutex_exit(&sp->s_lock);
366 mutex_exit(&p->p_splock);
367 mutex_exit(&pidlock);
368 mutex_exit(&stp->sd_lock);
369 return (0);
370 }
371
372 /*
373 * freectty_lock() attempts to acquire the army of locks required to free
374 * the ctty associated with a given session leader process. If it returns
375 * successfully the following locks will be held:
376 * sd_lock, pidlock, p_splock, s_lock
377 *
378 * as a secondary bit of convenience, freectty_lock() will also return
379 * pointers to the session, ctty, and ctty stream associated with the
380 * specified session leader process.
381 */
382 static boolean_t
freectty_lock(proc_t * p,sess_t ** spp,vnode_t ** vpp,stdata_t ** stpp,boolean_t at_exit)383 freectty_lock(proc_t *p, sess_t **spp, vnode_t **vpp, stdata_t **stpp,
384 boolean_t at_exit)
385 {
386 sess_t *sp;
387 vnode_t *vp;
388 stdata_t *stp;
389
390 mutex_enter(&pidlock); /* protect p_pidp */
391 mutex_enter(&p->p_splock); /* protect p->p_sessp */
392 sp = p->p_sessp;
393 mutex_enter(&sp->s_lock); /* protect sp->* */
394
395 if ((sp->s_sidp != p->p_pidp) || /* we're not leader? */
396 (sp->s_vp == NULL)) { /* no ctty? */
397 mutex_exit(&sp->s_lock);
398 mutex_exit(&p->p_splock);
399 mutex_exit(&pidlock);
400 return (B_FALSE);
401 }
402
403 vp = sp->s_vp;
404 stp = sp->s_vp->v_stream;
405
406 if (at_exit) {
407 /* stop anyone else calling tty_hold() */
408 sp->s_exit = B_TRUE;
409 } else {
410 /*
411 * due to locking order we have to grab stp->sd_lock before
412 * grabbing all the other proc/session locks. but after we
413 * drop all our current locks it's possible that someone
414 * could come in and change our current session or close
415 * the current ctty (vp) there by making sp or stp invalid.
416 * (a VN_HOLD on vp won't protect stp because that only
417 * prevents the vnode from being freed not closed.) so
418 * to prevent this we bump s_ref and s_cnt here.
419 *
420 * course this doesn't matter if we're the last thread in
421 * an exiting process that is the session leader, since no
422 * one else can change our session or free our ctty.
423 */
424 sp->s_ref++; /* hold the session structure */
425 sp->s_cnt++; /* protect vp and stp */
426 }
427
428 /* drop our session locks */
429 mutex_exit(&sp->s_lock);
430 mutex_exit(&p->p_splock);
431 mutex_exit(&pidlock);
432
433 /* grab locks in the right order */
434 mutex_enter(&stp->sd_lock); /* protects sd_pgidp/sd_sidp */
435 mutex_enter(&pidlock); /* protect p_pidp */
436 mutex_enter(&p->p_splock); /* protects p->p_sessp */
437 mutex_enter(&sp->s_lock); /* protects sp->* */
438
439 /* if the session has changed, abort mission */
440 if (sp != p->p_sessp) {
441 /*
442 * this can't happen during process exit since we're the
443 * only thread in the process and we sure didn't change
444 * our own session at this point.
445 */
446 ASSERT(!at_exit);
447
448 /* release our locks and holds */
449 mutex_exit(&sp->s_lock);
450 mutex_exit(&p->p_splock);
451 mutex_exit(&pidlock);
452 mutex_exit(&stp->sd_lock);
453 tty_rele(sp);
454 return (B_FALSE);
455 }
456
457 /*
458 * sanity checks. none of this should have changed since we had
459 * holds on the current ctty.
460 */
461 ASSERT(sp->s_sidp == p->p_pidp); /* we're the leader */
462 ASSERT(sp->s_vp != NULL); /* a ctty exists */
463 ASSERT(vp == sp->s_vp);
464 ASSERT(stp == sp->s_vp->v_stream);
465
466 /* release our holds */
467 if (!at_exit) {
468 if ((--(sp)->s_cnt) == 0)
469 cv_broadcast(&sp->s_cnt_cv);
470 sp->s_ref--;
471 ASSERT(sp->s_ref > 0);
472 }
473
474 /* return our pointers */
475 *spp = sp;
476 *vpp = vp;
477 *stpp = stp;
478
479 return (B_TRUE);
480 }
481
482 /*
483 * Returns B_FALSE if no signal is sent to the process group associated with
484 * this ctty. Returns B_TRUE if a signal is sent to the process group.
485 * If it return B_TRUE it also means that all the locks we were holding
486 * were dropped so that we could send the signal.
487 */
488 static boolean_t
freectty_signal(proc_t * p,sess_t * sp,stdata_t * stp,boolean_t at_exit)489 freectty_signal(proc_t *p, sess_t *sp, stdata_t *stp, boolean_t at_exit)
490 {
491 /* Assert that we hold all the necessary locks. */
492 ASSERT(MUTEX_HELD(&stp->sd_lock) && MUTEX_HELD(&pidlock) &&
493 MUTEX_HELD(&p->p_splock) && MUTEX_HELD(&sp->s_lock));
494
495 /* check if we already signaled this group */
496 if (sp->s_sighuped)
497 return (B_FALSE);
498
499 sp->s_sighuped = B_TRUE;
500
501 if (!at_exit) {
502 /*
503 * once again, we're about to drop our army of locks and we
504 * don't want sp or stp to be freed. (see the comment in
505 * freectty_lock())
506 */
507 sp->s_ref++; /* hold the session structure */
508 sp->s_cnt++; /* protect vp and stp */
509 }
510
511 /* can't hold these locks while calling pgsignal() */
512 mutex_exit(&sp->s_lock);
513 mutex_exit(&p->p_splock);
514 mutex_exit(&pidlock);
515
516 /* signal anyone in the foreground process group */
517 pgsignal(stp->sd_pgidp, SIGHUP);
518
519 /* signal anyone blocked in poll on this stream */
520 if (!(stp->sd_flag & STRHUP))
521 strhup(stp);
522
523 mutex_exit(&stp->sd_lock);
524
525 /* release our holds */
526 if (!at_exit)
527 tty_rele(sp);
528
529 return (B_TRUE);
530 }
531
532 int
freectty(boolean_t at_exit)533 freectty(boolean_t at_exit)
534 {
535 proc_t *p = curproc;
536 stdata_t *stp;
537 vnode_t *vp;
538 cred_t *cred;
539 sess_t *sp;
540 struct pid *pgidp, *sidp;
541 boolean_t got_sig = B_FALSE;
542
543 /*
544 * If the current process is a session leader we are going to
545 * try to release the ctty associated our current session. To
546 * do this we need to acquire a bunch of locks, signal any
547 * processes in the forground that are associated with the ctty,
548 * and make sure no one has any outstanding holds on the current
549 * session * structure (acquired via tty_hold()). Hence, we have
550 * the following for(;;) loop that will do all this work for
551 * us and break out when the hold count on the session structure
552 * hits zero.
553 */
554 for (;;) {
555 if (!freectty_lock(p, &sp, &vp, &stp, at_exit))
556 return (EIO);
557
558 if (freectty_signal(p, sp, stp, at_exit)) {
559 /* loop around to re-acquire locks */
560 continue;
561 }
562
563 /*
564 * Only a session leader process can free a ctty. So if
565 * we've made it here we know we're a session leader and
566 * if we're not actively exiting it impossible for another
567 * thread in this process to be exiting. (Because that
568 * thread would have already stopped all other threads
569 * in the current process.)
570 */
571 ASSERT(at_exit || !sp->s_exit);
572
573 /*
574 * If no one else has a hold on this session structure
575 * then we now have exclusive access to it, so break out
576 * of this loop and update the session structure.
577 */
578 if (sp->s_cnt == 0)
579 break;
580
581 if (!at_exit) {
582 /* need to hold the session so it can't be freed */
583 sp->s_ref++;
584 }
585
586 /* ain't locking order fun? */
587 mutex_exit(&p->p_splock);
588 mutex_exit(&pidlock);
589 mutex_exit(&stp->sd_lock);
590
591 if (at_exit) {
592 /*
593 * if we're exiting then we can't allow this operation
594 * to fail so we do a cw_wait() instead of a
595 * cv_wait_sig(). if there are threads with active
596 * holds on this ctty that are blocked, then
597 * they should only be blocked in a cv_wait_sig()
598 * and hopefully they were in the foreground process
599 * group and recieved the SIGHUP we sent above. of
600 * course it's possible that they weren't in the
601 * foreground process group and didn't get our
602 * signal (or they could be stopped by job control
603 * in which case our signal wouldn't matter until
604 * they are restarted). in this case we won't
605 * exit until someone else sends them a signal.
606 */
607 cv_wait(&sp->s_cnt_cv, &sp->s_lock);
608 mutex_exit(&sp->s_lock);
609 continue;
610 }
611
612 if (!cv_wait_sig(&sp->s_cnt_cv, &sp->s_lock)) {
613 got_sig = B_TRUE;
614 }
615
616 mutex_exit(&sp->s_lock);
617 sess_rele(sp, B_FALSE);
618
619 if (got_sig)
620 return (EINTR);
621 }
622 ASSERT(sp->s_cnt == 0);
623
624 /* save some pointers for later */
625 cred = sp->s_cred;
626 pgidp = stp->sd_pgidp;
627 sidp = stp->sd_sidp;
628
629 /* clear the session ctty bindings */
630 sess_ctty_clear(sp, stp);
631
632 /* wake up anyone blocked in tty_hold() */
633 if (at_exit) {
634 ASSERT(sp->s_exit);
635 sp->s_exit = B_FALSE;
636 cv_broadcast(&sp->s_exit_cv);
637 }
638
639 /* we can drop these locks now */
640 mutex_exit(&sp->s_lock);
641 mutex_exit(&p->p_splock);
642 mutex_exit(&pidlock);
643 mutex_exit(&stp->sd_lock);
644
645 /* This is the only remaining thread with access to this vnode */
646 (void) VOP_CLOSE(vp, 0, 1, (offset_t)0, cred, NULL);
647 VN_RELE(vp);
648 crfree(cred);
649
650 /* release our holds on assorted structures and return */
651 mutex_enter(&pidlock);
652 PID_RELE(pgidp);
653 PID_RELE(sidp);
654 mutex_exit(&pidlock);
655
656 return (1);
657 }
658
659 /*
660 * ++++++++++++++++++++++++
661 * ++ SunOS4.1 Buyback ++
662 * ++++++++++++++++++++++++
663 *
664 * vhangup: Revoke access of the current tty by all processes
665 * Used by privileged users to give a "clean" terminal at login
666 */
667 int
vhangup(void)668 vhangup(void)
669 {
670 if (secpolicy_sys_config(CRED(), B_FALSE) != 0)
671 return (set_errno(EPERM));
672 /*
673 * This routine used to call freectty() under a condition that
674 * could never happen. So this code has never actually done
675 * anything, and evidently nobody has ever noticed.
676 */
677 return (0);
678 }
679
680 dev_t
cttydev(proc_t * pp)681 cttydev(proc_t *pp)
682 {
683 sess_t *sp;
684 dev_t dev;
685
686 mutex_enter(&pp->p_splock); /* protects p->p_sessp */
687 sp = pp->p_sessp;
688
689 #ifdef DEBUG
690 mutex_enter(&sp->s_lock); /* protects sp->* */
691 if (sp->s_vp == NULL)
692 ASSERT(sp->s_dev == NODEV);
693 else
694 ASSERT(sp->s_dev != NODEV);
695 mutex_exit(&sp->s_lock);
696 #endif /* DEBUG */
697
698 dev = sp->s_dev;
699 mutex_exit(&pp->p_splock);
700 return (dev);
701 }
702
703 void
ctty_clear_sighuped(void)704 ctty_clear_sighuped(void)
705 {
706 ASSERT(MUTEX_HELD(&pidlock) || MUTEX_HELD(&curproc->p_splock));
707 curproc->p_sessp->s_sighuped = B_FALSE;
708 }
709