X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/0b4c1975fb5e4eccf1012a35081f7e7799b81046..c18c124eaa464aaaa5549e99e5a70fc9cbb50944:/bsd/kern/tty.c?ds=sidebyside diff --git a/bsd/kern/tty.c b/bsd/kern/tty.c index 841781612..2586c482f 100644 --- a/bsd/kern/tty.c +++ b/bsd/kern/tty.c @@ -130,7 +130,7 @@ static lck_grp_t *tty_lck_grp; static lck_grp_attr_t *tty_lck_grp_attr; static lck_attr_t *tty_lck_attr; -static int ttnread(struct tty *tp); +__private_extern__ int ttnread(struct tty *tp); static void ttyecho(int c, struct tty *tp); static int ttyoutput(int c, struct tty *tp); static void ttypend(struct tty *tp); @@ -142,6 +142,9 @@ static void ttyunblock(struct tty *tp); static int ttywflush(struct tty *tp); static int proc_compare(proc_t p1, proc_t p2); +static void ttyhold(struct tty *tp); +static void ttydeallocate(struct tty *tp); + static int isctty(proc_t p, struct tty *tp); static int isctty_sp(proc_t p, struct tty *tp, struct session *sessp); @@ -339,8 +342,9 @@ int ttyopen(dev_t device, struct tty *tp) { proc_t p = current_proc(); - struct pgrp * pg, * oldpg; + struct pgrp *pg, *oldpg; struct session *sessp, *oldsess; + struct tty *oldtp; TTY_LOCK_OWNED(tp); /* debug assert */ @@ -359,15 +363,15 @@ ttyopen(dev_t device, struct tty *tp) /* * First tty open affter setsid() call makes this tty its controlling * tty, if the tty does not already have a session associated with it. - * Only do this if the process */ - if (SESS_LEADER(p, sessp) && /* process is session leader */ + if (SESS_LEADER(p, sessp) && /* the process is the session leader */ sessp->s_ttyvp == NULL && /* but has no controlling tty */ - tp->t_session == NULL ) { /* and tty not controlling */ + tp->t_session == NULL ) { /* and tty not controlling */ session_lock(sessp); if ((sessp->s_flags & S_NOCTTY) == 0) { /* and no O_NOCTTY */ - /* Hold on to the reference */ - sessp->s_ttyp = tp; /* XXX NOT A REFERENCE */ + oldtp = sessp->s_ttyp; + ttyhold(tp); + sessp->s_ttyp = tp; OSBitOrAtomic(P_CONTROLT, &p->p_flag); session_unlock(sessp); proc_list_lock(); @@ -385,6 +389,8 @@ ttyopen(dev_t device, struct tty *tp) pg_rele(oldpg); if (oldsess != SESSION_NULL) session_rele(oldsess); + if (NULL != oldtp) + ttyfree(oldtp); tty_lock(tp); goto out; } @@ -954,6 +960,29 @@ ttyoutput(int c, struct tty *tp) return (-1); } +/* + * Sets the tty state to not allow any more changes of foreground process + * group. This is required to be done so that a subsequent revoke on a vnode + * is able to always successfully complete. + * + * Locks : Assumes tty_lock held on entry + */ +void +ttysetpgrphup(struct tty *tp) +{ + TTY_LOCK_OWNED(tp); /* debug assert */ + SET(tp->t_state, TS_PGRPHUP); +} + +/* + * Locks : Assumes tty lock held on entry + */ +void +ttyclrpgrphup(struct tty *tp) +{ + TTY_LOCK_OWNED(tp); /* debug assert */ + CLR(tp->t_state, TS_PGRPHUP); +} /* * ttioctl @@ -1047,8 +1076,9 @@ ttioctl_locked(struct tty *tp, u_long cmd, caddr_t data, int flag, proc_t p) { int error = 0; struct uthread *ut; - struct pgrp * pg, *oldpg; - struct session *sessp, * oldsessp; + struct pgrp *pg, *oldpg; + struct session *sessp, *oldsessp; + struct tty *oldtp; TTY_LOCK_OWNED(tp); /* debug assert */ @@ -1404,7 +1434,9 @@ ttioctl_locked(struct tty *tp, u_long cmd, caddr_t data, int flag, proc_t p) tp->t_pgrp = pg; proc_list_unlock(); session_lock(sessp); - sessp->s_ttyp = tp; /* XXX NOT A REFERENCE */ + oldtp = sessp->s_ttyp; + ttyhold(tp); + sessp->s_ttyp = tp; session_unlock(sessp); OSBitOrAtomic(P_CONTROLT, &p->p_flag); /* SAFE: All callers drop the lock on return */ @@ -1414,6 +1446,8 @@ ttioctl_locked(struct tty *tp, u_long cmd, caddr_t data, int flag, proc_t p) session_rele(oldsessp); if (oldpg != PGRP_NULL) pg_rele(oldpg); + if (NULL != oldtp) + ttyfree(oldtp); tty_lock(tp); break; @@ -1442,6 +1476,15 @@ ttioctl_locked(struct tty *tp, u_long cmd, caddr_t data, int flag, proc_t p) error = EPERM; goto out; } + /* + * The session leader is going away and is possibly going to revoke + * the terminal, we can't change the process group when that is the + * case. + */ + if (ISSET(tp->t_state, TS_PGRPHUP)) { + error = EPERM; + goto out; + } proc_list_lock(); oldpg = tp->t_pgrp; tp->t_pgrp = pgrp; @@ -1498,6 +1541,8 @@ out: int ttyselect(struct tty *tp, int rw, void *wql, proc_t p) { + int retval = 0; + if (tp == NULL) return (ENXIO); @@ -1505,20 +1550,32 @@ ttyselect(struct tty *tp, int rw, void *wql, proc_t p) switch (rw) { case FREAD: - if (ttnread(tp) > 0 || ISSET(tp->t_state, TS_ZOMBIE)) + if (ISSET(tp->t_state, TS_ZOMBIE)) { return(1); + } + + retval = ttnread(tp); + if (retval > 0) { + break; + } + selrecord(p, &tp->t_rsel, wql); break; case FWRITE: - if ((tp->t_outq.c_cc <= tp->t_lowat && - ISSET(tp->t_state, TS_CONNECTED)) - || ISSET(tp->t_state, TS_ZOMBIE)) { - return (1); + if (ISSET(tp->t_state, TS_ZOMBIE)) { + return(1); + } + + if ((tp->t_outq.c_cc <= tp->t_lowat) && + ISSET(tp->t_state, TS_CONNECTED)) { + retval = tp->t_hiwat - tp->t_outq.c_cc; + break; } + selrecord(p, &tp->t_wsel, wql); break; } - return (0); + return retval; } @@ -1545,7 +1602,7 @@ ttselect(dev_t dev, int rw, void *wql, proc_t p) /* * Locks: Assumes tp is locked on entry, remains locked on exit */ -static int +__private_extern__ int ttnread(struct tty *tp) { int nread; @@ -2120,7 +2177,7 @@ read: char ibuf[IBUFSIZ]; int icc; - icc = min(uio_resid(uio), IBUFSIZ); + icc = MIN(uio_resid(uio), IBUFSIZ); icc = q_to_b(qp, (u_char *)ibuf, icc); if (icc <= 0) { if (first) @@ -2161,8 +2218,8 @@ slowcase: tty_pgsignal(tp, SIGTSTP, 1); tty_lock(tp); if (first) { - error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, - "ttybg3", 0); + error = ttysleep(tp, &ttread, TTIPRI | PCATCH, + "ttybg3", hz); if (error) break; goto loop; @@ -2341,7 +2398,7 @@ loop: * leftover from last time. */ if (cc == 0) { - cc = min(uio_resid(uio), OBUFSIZ); + cc = MIN(uio_resid(uio), OBUFSIZ); cp = obuf; error = uiomove(cp, cc, uio); if (error) { @@ -3024,22 +3081,57 @@ ttymalloc(void) lck_mtx_init(&tp->t_lock, tty_lck_grp, tty_lck_attr); klist_init(&tp->t_rsel.si_note); klist_init(&tp->t_wsel.si_note); + tp->t_refcnt = 1; } - return(tp); + return (tp); } +/* + * Increment the reference count on a tty. + */ +static void +ttyhold(struct tty *tp) +{ + TTY_LOCK_OWNED(tp); + tp->t_refcnt++; +} /* - * Free a tty structure and its buffers. - * - * Locks: The tty_lock() is assumed to not be held at the time of - * the free; this functions destroys the mutex. + * Drops a reference count on a tty structure; if the reference count reaches + * zero, then also frees the structure and associated buffers. */ void ttyfree(struct tty *tp) +{ + TTY_LOCK_NOTOWNED(tp); + + tty_lock(tp); + if (--tp->t_refcnt == 0) { + tty_unlock(tp); + ttydeallocate(tp); + } else if (tp->t_refcnt < 0) { + panic("%s: freeing free tty %p", __func__, tp); + } else + tty_unlock(tp); +} + +/* + * Deallocate a tty structure and its buffers. + * + * Locks: The tty_lock() is assumed to not be held at the time of + * the free; this function destroys the mutex. + */ +static void +ttydeallocate(struct tty *tp) { TTY_LOCK_NOTOWNED(tp); /* debug assert */ +#if DEBUG + if (!(SLIST_EMPTY(&tp->t_rsel.si_note) && SLIST_EMPTY(&tp->t_wsel.si_note))) { + panic("knotes hooked into a tty when the tty is freed.\n"); + } +#endif /* DEBUG */ + clfree(&tp->t_rawq); clfree(&tp->t_canq); clfree(&tp->t_outq); @@ -3077,4 +3169,3 @@ isctty_sp(proc_t p, struct tty *tp, struct session *sessp) return(sessp == tp->t_session && p->p_flag & P_CONTROLT); } -