X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/2d21ac55c334faf3a56e5634905ed6987fc787d4..d9a64523371fa019c4575bb400cbbc3a50ac9903:/bsd/kern/tty_tty.c diff --git a/bsd/kern/tty_tty.c b/bsd/kern/tty_tty.c index 1c9882d96..84960728d 100644 --- a/bsd/kern/tty_tty.c +++ b/bsd/kern/tty_tty.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997-2006 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1997-2013 Apple Computer, Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -82,13 +82,14 @@ int cttyioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, proc_t p); int cttyselect(dev_t dev, int flag, void* wql, proc_t p); static vnode_t cttyvp(proc_t p); - int -cttyopen(__unused dev_t dev, int flag, __unused int mode, proc_t p) +cttyopen(dev_t dev, int flag, __unused int mode, proc_t p) { vnode_t ttyvp = cttyvp(p); struct vfs_context context; - int error; + int error = 0; + int cttyflag, doclose = 0; + struct session *sessp; if (ttyvp == NULL) return (ENXIO); @@ -96,7 +97,61 @@ cttyopen(__unused dev_t dev, int flag, __unused int mode, proc_t p) context.vc_thread = current_thread(); context.vc_ucred = kauth_cred_proc_ref(p); - error = VNOP_OPEN(ttyvp, flag, &context); + sessp = proc_session(p); + session_lock(sessp); + cttyflag = sessp->s_flags & S_CTTYREF; + session_unlock(sessp); + + /* + * A little hack--this device, used by many processes, + * happens to do an open on another device, which can + * cause unhappiness if the second-level open blocks indefinitely + * (as could be the case if the master side has hung up). Since + * we know that this driver doesn't care about the serializing + * opens and closes, we can drop the lock. To avoid opencount leak, + * open the vnode only for the first time. + */ + if (cttyflag == 0) { + devsw_unlock(dev, S_IFCHR); + error = VNOP_OPEN(ttyvp, flag, &context); + devsw_lock(dev, S_IFCHR); + + if (error) + goto out; + + /* + * If S_CTTYREF is set, some other thread did an open + * and was able to set the flag, now perform a close, else + * set the flag. + */ + session_lock(sessp); + if (cttyflag == (sessp->s_flags & S_CTTYREF)) + sessp->s_flags |= S_CTTYREF; + else + doclose = 1; + session_unlock(sessp); + + /* + * We have to take a reference here to make sure a close + * gets called during revoke. Note that once a controlling + * tty gets opened by this driver, the only way close will + * get called is when the session leader , whose controlling + * tty is ttyvp, exits and vnode is revoked. We cannot + * redirect close from this driver because underlying controlling + * terminal might change and close may get redirected to a + * wrong vnode causing panic. + */ + if (doclose) { + devsw_unlock(dev, S_IFCHR); + VNOP_CLOSE(ttyvp, flag, &context); + devsw_lock(dev, S_IFCHR); + } else { + error = vnode_ref(ttyvp); + } + } +out: + session_rele(sessp); + vnode_put(ttyvp); kauth_cred_unref(&context.vc_ucred); @@ -158,7 +213,7 @@ cttyioctl(__unused dev_t dev, u_long cmd, caddr_t addr, int flag, proc_t p) if (cmd == TIOCNOTTY) { sessp = proc_session(p); if (!SESS_LEADER(p, sessp)) { - OSBitAndAtomic(~((uint32_t)P_CONTROLT), (UInt32 *)&p->p_flag); + OSBitAndAtomic(~((uint32_t)P_CONTROLT), &p->p_flag); if (sessp != SESSION_NULL) session_rele(sessp); error = 0;