1 /*- 2 * Copyright (c) 1982, 1986, 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * @(#)tty_tty.c 8.2 (Berkeley) 9/23/93 34 * $FreeBSD: src/sys/kern/tty_tty.c,v 1.30 1999/09/25 18:24:24 phk Exp $ 35 * $DragonFly: src/sys/kern/tty_tty.c,v 1.15 2006/05/06 02:43:12 dillon Exp $ 36 */ 37 38 /* 39 * Indirect driver for controlling tty. 40 */ 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/conf.h> 45 #include <sys/lock.h> 46 #include <sys/fcntl.h> 47 #include <sys/proc.h> 48 #include <sys/ttycom.h> 49 #include <sys/vnode.h> 50 #include <sys/kernel.h> 51 52 static d_open_t cttyopen; 53 static d_close_t cttyclose; 54 static d_read_t cttyread; 55 static d_write_t cttywrite; 56 static d_ioctl_t cttyioctl; 57 static d_poll_t cttypoll; 58 59 #define CDEV_MAJOR 1 60 /* Don't make this static, since fdesc_vnops uses it. */ 61 struct cdevsw ctty_cdevsw = { 62 /* name */ "ctty", 63 /* maj */ CDEV_MAJOR, 64 /* flags */ D_TTY, 65 /* port */ NULL, 66 /* clone */ NULL, 67 68 /* open */ cttyopen, 69 /* close */ cttyclose, 70 /* read */ cttyread, 71 /* write */ cttywrite, 72 /* ioctl */ cttyioctl, 73 /* poll */ cttypoll, 74 /* mmap */ nommap, 75 /* strategy */ nostrategy, 76 /* dump */ nodump, 77 /* psize */ nopsize 78 }; 79 80 #define cttyvp(p) ((p)->p_flag & P_CONTROLT ? (p)->p_session->s_ttyvp : NULL) 81 82 /* 83 * This opens /dev/tty. Because multiple opens of /dev/tty only 84 * generate a single open to the actual tty, the file modes are 85 * locked to FREAD|FWRITE. 86 */ 87 static int 88 cttyopen(dev_t dev, int flag, int mode, struct thread *td) 89 { 90 struct proc *p = td->td_proc; 91 struct vnode *ttyvp; 92 int error; 93 94 KKASSERT(p); 95 ttyvp = cttyvp(p); 96 if (ttyvp) { 97 if (ttyvp->v_flag & VCTTYISOPEN) { 98 error = 0; 99 } else { 100 vsetflags(ttyvp, VCTTYISOPEN); 101 vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY); 102 error = VOP_OPEN(ttyvp, FREAD|FWRITE, NOCRED, NULL); 103 if (error) 104 vclrflags(ttyvp, VCTTYISOPEN); 105 VOP_UNLOCK(ttyvp, 0); 106 } 107 } else { 108 error = ENXIO; 109 } 110 return (error); 111 } 112 113 /* 114 * This closes /dev/tty. Because multiple opens of /dev/tty only 115 * generate a single open to the actual tty, the file modes are 116 * locked to FREAD|FWRITE. 117 */ 118 static int 119 cttyclose(dev_t dev, int fflag, int devtype, struct thread *td) 120 { 121 struct proc *p = td->td_proc; 122 struct vnode *ttyvp; 123 int error; 124 125 KKASSERT(p); 126 ttyvp = cttyvp(p); 127 if (ttyvp == NULL) { 128 /* 129 * The tty may have been TIOCNOTTY'd, don't return an 130 * error on close. We just have nothing to do. 131 */ 132 /* error = EIO; */ 133 error = 0; 134 } else if (ttyvp->v_flag & VCTTYISOPEN) { 135 vclrflags(ttyvp, VCTTYISOPEN); 136 error = vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY); 137 if (error == 0) { 138 error = VOP_CLOSE(ttyvp, FREAD|FWRITE); 139 VOP_UNLOCK(ttyvp, 0); 140 } 141 } else { 142 error = 0; 143 } 144 return(error); 145 } 146 147 /* 148 * Read from the controlling terminal (/dev/tty). The tty is refed as 149 * of the cttyvp(), but the ref can get ripped out from under us if 150 * the controlling terminal is revoked while we are blocked on the lock, 151 * so use vget() instead of VOP_LOCK. 152 */ 153 static int 154 cttyread(dev, uio, flag) 155 dev_t dev; 156 struct uio *uio; 157 int flag; 158 { 159 struct thread *td = uio->uio_td; 160 struct proc *p = td->td_proc; 161 struct vnode *ttyvp; 162 int error; 163 164 KKASSERT(p); 165 ttyvp = cttyvp(p); 166 if (ttyvp == NULL) 167 return (EIO); 168 if ((error = vget(ttyvp, LK_EXCLUSIVE | LK_RETRY)) == 0) { 169 error = VOP_READ(ttyvp, uio, flag, NOCRED); 170 vput(ttyvp); 171 } 172 return (error); 173 } 174 175 /* 176 * Read from the controlling terminal (/dev/tty). The tty is refed as 177 * of the cttyvp(), but the ref can get ripped out from under us if 178 * the controlling terminal is revoked while we are blocked on the lock, 179 * so use vget() instead of VOP_LOCK. 180 */ 181 static int 182 cttywrite(dev, uio, flag) 183 dev_t dev; 184 struct uio *uio; 185 int flag; 186 { 187 struct thread *td = uio->uio_td; 188 struct proc *p = td->td_proc; 189 struct vnode *ttyvp; 190 int error; 191 192 KKASSERT(p); 193 ttyvp = cttyvp(p); 194 if (ttyvp == NULL) 195 return (EIO); 196 if ((error = vget(ttyvp, LK_EXCLUSIVE | LK_RETRY)) == 0) { 197 error = VOP_WRITE(ttyvp, uio, flag, NOCRED); 198 vput(ttyvp); 199 } 200 return (error); 201 } 202 203 /*ARGSUSED*/ 204 static int 205 cttyioctl(dev, cmd, addr, flag, td) 206 dev_t dev; 207 u_long cmd; 208 caddr_t addr; 209 int flag; 210 struct thread *td; 211 { 212 struct vnode *ttyvp; 213 struct proc *p = td->td_proc; 214 215 KKASSERT(p); 216 ttyvp = cttyvp(p); 217 if (ttyvp == NULL) 218 return (EIO); 219 if (cmd == TIOCSCTTY) /* don't allow controlling tty to be set */ 220 return EINVAL; /* to controlling tty -- infinite recursion */ 221 if (cmd == TIOCNOTTY) { 222 if (!SESS_LEADER(p)) { 223 p->p_flag &= ~P_CONTROLT; 224 return (0); 225 } else 226 return (EINVAL); 227 } 228 return (VOP_IOCTL(ttyvp, cmd, addr, flag, NOCRED)); 229 } 230 231 /*ARGSUSED*/ 232 static int 233 cttypoll(dev_t dev, int events, struct thread *td) 234 { 235 struct vnode *ttyvp; 236 struct proc *p = td->td_proc; 237 238 KKASSERT(p); 239 ttyvp = cttyvp(p); 240 if (ttyvp == NULL) 241 /* try operation to get EOF/failure */ 242 return (seltrue(dev, events, td)); 243 return (VOP_POLL(ttyvp, events, p->p_ucred)); 244 } 245 246 static void ctty_drvinit (void *unused); 247 static void 248 ctty_drvinit(unused) 249 void *unused; 250 { 251 cdevsw_add(&ctty_cdevsw, 0, 0); 252 make_dev(&ctty_cdevsw, 0, 0, 0, 0666, "tty"); 253 } 254 255 SYSINIT(cttydev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ctty_drvinit,NULL) 256