X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/0c530ab8987f0ae6a1a3d9284f40182b88852816..0a7de7458d150b5d4dffc935ba399be265ef0a1a:/bsd/kern/tty_tty.c

diff --git a/bsd/kern/tty_tty.c b/bsd/kern/tty_tty.c
index fa2a62135..8cbdfaf62 100644
--- a/bsd/kern/tty_tty.c
+++ b/bsd/kern/tty_tty.c
@@ -1,25 +1,30 @@
 /*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1997-2013 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License").  You may not use this file except in compliance with the
- * License.  Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
- * 
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
- * License for the specific language governing rights and limitations
- * under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  */
-/* Copyright (c) 1997 Apple Computer, Inc. All Rights Reserved */
 /*-
  * Copyright (c) 1982, 1986, 1991, 1993
  *      The Regents of the University of California.  All rights reserved.
@@ -66,174 +71,217 @@
 #include <sys/tty.h>
 #include <sys/vnode_internal.h>
 #include <sys/file_internal.h>
-#ifndef NeXT
-#include <sys/kernel.h>
-#ifdef DEVFS
-#include <sys/devfsext.h>
-#endif /*DEVFS*/
-
-static	d_open_t	cttyopen;
-static	d_read_t	cttyread;
-static	d_write_t	cttywrite;
-static	d_ioctl_t	cttyioctl;
-static	d_select_t	cttyselect;
-
-#endif /* !NeXT */
+#include <sys/kauth.h>
 
 /* Forward declarations for cdevsw[] entry */
 /* XXX we should consider making these static */
-int cttyopen(dev_t dev, int flag, int mode, struct proc *p);
+int cttyopen(dev_t dev, int flag, int mode, proc_t p);
 int cttyread(dev_t dev, struct uio *uio, int flag);
 int cttywrite(dev_t dev, struct uio *uio, int flag);
-int cttyioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p);
-int cttyselect(dev_t dev, int flag, void* wql, struct proc *p);
-
-#ifndef NeXT
+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);
 
-#define CDEV_MAJOR 1
-/* Don't make static, fdesc_vnops uses this. */
-struct cdevsw ctty_cdevsw = 
-	{ cttyopen,	nullclose,	cttyread,	cttywrite,	/*1*/
-	  cttyioctl,	nullstop,	nullreset,	nodevtotty,/* tty */
-	  cttyselect,	nommap,		NULL,	"ctty",	NULL,	-1 };
-
-#endif /* !NeXT */
-
-#define cttyvp(p) ((p)->p_flag & P_CONTROLT ? (p)->p_session->s_ttyvp : NULL)
-
-/*ARGSUSED*/
 int
-cttyopen(__unused dev_t dev, int flag, __unused int mode, struct proc *p)
+cttyopen(dev_t dev, int flag, __unused int mode, proc_t p)
 {
-	struct vnode *ttyvp = cttyvp(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);
+	if (ttyvp == NULL) {
+		return ENXIO;
+	}
 
-	context.vc_proc = 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);
 
-	return (error);
+	return error;
 }
 
-/*ARGSUSED*/
 int
 cttyread(__unused dev_t dev, struct uio *uio, int flag)
 {
-	struct proc *p = current_proc();
-	register struct vnode *ttyvp = cttyvp(p);
+	vnode_t ttyvp = cttyvp(current_proc());
 	struct vfs_context context;
 	int error;
 
-	if (ttyvp == NULL)
-		return (EIO);
+	if (ttyvp == NULL) {
+		return EIO;
+	}
 
-	context.vc_proc = p;
+	context.vc_thread = current_thread();
 	context.vc_ucred = NOCRED;
 
 	error = VNOP_READ(ttyvp, uio, flag, &context);
+	vnode_put(ttyvp);
 
-	return (error);
+	return error;
 }
 
-/*ARGSUSED*/
 int
 cttywrite(__unused dev_t dev, struct uio *uio, int flag)
 {
-	struct proc *p = current_proc();
-	register struct vnode *ttyvp = cttyvp(p);
+	vnode_t ttyvp = cttyvp(current_proc());
 	struct vfs_context context;
 	int error;
 
-	if (ttyvp == NULL)
-		return (EIO);
+	if (ttyvp == NULL) {
+		return EIO;
+	}
 
-	context.vc_proc = p;
+	context.vc_thread = current_thread();
 	context.vc_ucred = NOCRED;
 
 	error = VNOP_WRITE(ttyvp, uio, flag, &context);
+	vnode_put(ttyvp);
 
-	return (error);
+	return error;
 }
 
-/*ARGSUSED*/
-#ifndef NeXT
-static	int
-cttyioctl(dev, cmd, addr, flag, p)
-	dev_t dev;
-	int cmd;
-	caddr_t addr;
-	int flag;
-	struct proc *p;
-#else
 int
-cttyioctl(__unused dev_t dev, u_long cmd, caddr_t addr, int flag,
-	struct proc *p)
-#endif /* !NeXT */
+cttyioctl(__unused dev_t dev, u_long cmd, caddr_t addr, int flag, proc_t p)
 {
-	struct vnode *ttyvp = cttyvp(p);
+	vnode_t ttyvp = cttyvp(current_proc());
 	struct vfs_context context;
+	struct session *sessp;
+	int error = 0;
 
-	if (ttyvp == NULL)
-		return (EIO);
-	if (cmd == TIOCSCTTY)  /* don't allow controlling tty to be set    */
-		return EINVAL; /* to controlling tty -- infinite recursion */
+	if (ttyvp == NULL) {
+		return EIO;
+	}
+	if (cmd == TIOCSCTTY) {  /* don't allow controlling tty to be set    */
+		error = EINVAL; /* to controlling tty -- infinite recursion */
+		goto out;
+	}
 	if (cmd == TIOCNOTTY) {
-		if (!SESS_LEADER(p)) {
-			p->p_flag &= ~P_CONTROLT;
-			return (0);
-		} else
-			return (EINVAL);
+		sessp = proc_session(p);
+		if (!SESS_LEADER(p, sessp)) {
+			OSBitAndAtomic(~((uint32_t)P_CONTROLT), &p->p_flag);
+			if (sessp != SESSION_NULL) {
+				session_rele(sessp);
+			}
+			error = 0;
+			goto out;
+		} else {
+			if (sessp != SESSION_NULL) {
+				session_rele(sessp);
+			}
+			error = EINVAL;
+			goto out;
+		}
 	}
-	context.vc_proc = p;
+	context.vc_thread = current_thread();
 	context.vc_ucred = NOCRED;
 
-	return (VNOP_IOCTL(ttyvp, cmd, addr, flag, &context));
+	error = VNOP_IOCTL(ttyvp, cmd, addr, flag, &context);
+out:
+	vnode_put(ttyvp);
+	return error;
 }
 
-/*ARGSUSED*/
 int
-cttyselect(__unused dev_t dev, int flag, void* wql, struct proc *p)
+cttyselect(__unused dev_t dev, int flag, void* wql, __unused proc_t p)
 {
-	struct vnode *ttyvp = cttyvp(p);
+	vnode_t ttyvp = cttyvp(current_proc());
 	struct vfs_context context;
+	int error;
 
-	context.vc_proc = p;
+	context.vc_thread = current_thread();
 	context.vc_ucred = NOCRED;
 
-	if (ttyvp == NULL)
-		return (1);	/* try operation to get EOF/failure */
-	return (VNOP_SELECT(ttyvp, flag, FREAD|FWRITE, wql, &context));
+	if (ttyvp == NULL) {
+		return 1;     /* try operation to get EOF/failure */
+	}
+	error = VNOP_SELECT(ttyvp, flag, FREAD | FWRITE, wql, &context);
+	vnode_put(ttyvp);
+	return error;
 }
 
-#ifndef NeXT
-static ctty_devsw_installed = 0;
-#ifdef DEVFS
-static 	void	*ctty_devfs_token;
-#endif
-
-static void
-ctty_drvinit(void *unused)
+/* This returns vnode with ioref */
+static vnode_t
+cttyvp(proc_t p)
 {
-	dev_t dev;
-
-	if( ! ctty_devsw_installed ) {
-		dev = makedev(CDEV_MAJOR,0);
-		cdevsw_add(&dev,&ctty_cdevsw,NULL);
-		ctty_devsw_installed = 1;
-#ifdef DEVFS
-		ctty_devfs_token = 
-			devfs_add_devswf(&ctty_cdevsw, 0, DV_CHR, 0, 0, 
-					0666, "tty");
-#endif
-    	}
-}
+	vnode_t vp;
+	int vid;
+	struct session *sessp;
 
-SYSINIT(cttydev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ctty_drvinit,NULL)
+	sessp = proc_session(p);
 
+	session_lock(sessp);
+	vp = (p->p_flag & P_CONTROLT ? sessp->s_ttyvp : NULLVP);
+	vid = sessp->s_ttyvid;
+	session_unlock(sessp);
 
-#endif /* !NeXT */
+	session_rele(sessp);
+
+	if (vp != NULLVP) {
+		/* cannot get an IO reference, return NULLVP */
+		if (vnode_getwithvid(vp, vid) != 0) {
+			vp = NULLVP;
+		}
+	}
+	return vp;
+}