1 /*- 2 * (MPSAFE) 3 * 4 * Copyright (c) 1982, 1986, 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * @(#)tty_tty.c 8.2 (Berkeley) 9/23/93 36 * $FreeBSD: src/sys/kern/tty_tty.c,v 1.30 1999/09/25 18:24:24 phk Exp $ 37 * $DragonFly: src/sys/kern/tty_tty.c,v 1.19 2007/07/03 17:22:14 dillon Exp $ 38 */ 39 40 /* 41 * Indirect driver for controlling tty. 42 */ 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/conf.h> 47 #include <sys/device.h> 48 #include <sys/lock.h> 49 #include <sys/fcntl.h> 50 #include <sys/proc.h> 51 #include <sys/ttycom.h> 52 #include <sys/vnode.h> 53 #include <sys/kernel.h> 54 #include <sys/poll.h> /* XXX: poll args used in KQ filters */ 55 #include <sys/event.h> 56 57 static d_open_t cttyopen; 58 static d_close_t cttyclose; 59 static d_read_t cttyread; 60 static d_write_t cttywrite; 61 static d_ioctl_t cttyioctl; 62 static d_kqfilter_t cttykqfilter; 63 64 static void cttyfilt_detach(struct knote *); 65 static int cttyfilt_read(struct knote *, long); 66 static int cttyfilt_write(struct knote *, long); 67 68 #define CDEV_MAJOR 1 69 /* Don't make this static, since fdesc_vnops uses it. */ 70 struct dev_ops ctty_ops = { 71 { "ctty", CDEV_MAJOR, D_TTY }, 72 .d_open = cttyopen, 73 .d_close = cttyclose, 74 .d_read = cttyread, 75 .d_write = cttywrite, 76 .d_ioctl = cttyioctl, 77 .d_kqfilter = cttykqfilter 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(struct dev_open_args *ap) 89 { 90 struct proc *p = curproc; 91 struct vnode *ttyvp; 92 int error; 93 94 KKASSERT(p); 95 retry: 96 if ((ttyvp = cttyvp(p)) == NULL) 97 return (ENXIO); 98 if (ttyvp->v_flag & VCTTYISOPEN) 99 return (0); 100 101 /* 102 * Messy interlock, don't let the vnode go away while we try to 103 * lock it and check for race after we might have blocked. 104 */ 105 vhold(ttyvp); 106 vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY); 107 if (ttyvp != cttyvp(p) || (ttyvp->v_flag & VCTTYISOPEN)) { 108 kprintf("Warning: cttyopen: race avoided\n"); 109 vn_unlock(ttyvp); 110 vdrop(ttyvp); 111 goto retry; 112 } 113 vsetflags(ttyvp, VCTTYISOPEN); 114 error = VOP_OPEN(ttyvp, FREAD|FWRITE, ap->a_cred, NULL); 115 if (error) 116 vclrflags(ttyvp, VCTTYISOPEN); 117 vn_unlock(ttyvp); 118 vdrop(ttyvp); 119 return(error); 120 } 121 122 /* 123 * This closes /dev/tty. Because multiple opens of /dev/tty only 124 * generate a single open to the actual tty, the file modes are 125 * locked to FREAD|FWRITE. 126 */ 127 static int 128 cttyclose(struct dev_close_args *ap) 129 { 130 struct proc *p = curproc; 131 struct vnode *ttyvp; 132 int error; 133 134 KKASSERT(p); 135 retry: 136 /* 137 * The tty may have been TIOCNOTTY'd, don't return an 138 * error on close. We just have nothing to do. 139 */ 140 if ((ttyvp = cttyvp(p)) == NULL) 141 return(0); 142 if (ttyvp->v_flag & VCTTYISOPEN) { 143 /* 144 * Avoid a nasty race if we block while getting the lock. 145 */ 146 vref(ttyvp); 147 error = vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY); 148 if (error) { 149 vrele(ttyvp); 150 goto retry; 151 } 152 if (ttyvp != cttyvp(p) || (ttyvp->v_flag & VCTTYISOPEN) == 0) { 153 kprintf("Warning: cttyclose: race avoided\n"); 154 vn_unlock(ttyvp); 155 vrele(ttyvp); 156 goto retry; 157 } 158 vclrflags(ttyvp, VCTTYISOPEN); 159 error = VOP_CLOSE(ttyvp, FREAD|FWRITE); 160 vn_unlock(ttyvp); 161 vrele(ttyvp); 162 } else { 163 error = 0; 164 } 165 return(error); 166 } 167 168 /* 169 * Read from the controlling terminal (/dev/tty). The tty is refed as 170 * of the cttyvp(), but the ref can get ripped out from under us if 171 * the controlling terminal is revoked while we are blocked on the lock, 172 * so use vget() instead of vn_lock(). 173 */ 174 static int 175 cttyread(struct dev_read_args *ap) 176 { 177 struct proc *p = curproc; 178 struct vnode *ttyvp; 179 int error; 180 181 KKASSERT(p); 182 ttyvp = cttyvp(p); 183 if (ttyvp == NULL) 184 return (EIO); 185 if ((error = vget(ttyvp, LK_EXCLUSIVE | LK_RETRY)) == 0) { 186 error = VOP_READ(ttyvp, ap->a_uio, ap->a_ioflag, NOCRED); 187 vput(ttyvp); 188 } 189 return (error); 190 } 191 192 /* 193 * Read from the controlling terminal (/dev/tty). The tty is refed as 194 * of the cttyvp(), but the ref can get ripped out from under us if 195 * the controlling terminal is revoked while we are blocked on the lock, 196 * so use vget() instead of vn_lock(). 197 */ 198 static int 199 cttywrite(struct dev_write_args *ap) 200 { 201 struct proc *p = curproc; 202 struct vnode *ttyvp; 203 int error; 204 205 KKASSERT(p); 206 ttyvp = cttyvp(p); 207 if (ttyvp == NULL) 208 return (EIO); 209 if ((error = vget(ttyvp, LK_EXCLUSIVE | LK_RETRY)) == 0) { 210 error = VOP_WRITE(ttyvp, ap->a_uio, ap->a_ioflag, NOCRED); 211 vput(ttyvp); 212 } 213 return (error); 214 } 215 216 /*ARGSUSED*/ 217 static int 218 cttyioctl(struct dev_ioctl_args *ap) 219 { 220 struct vnode *ttyvp; 221 struct proc *p = curproc; 222 223 KKASSERT(p); 224 lwkt_gettoken(&proc_token); 225 ttyvp = cttyvp(p); 226 if (ttyvp == NULL) { 227 lwkt_reltoken(&proc_token); 228 return (EIO); 229 } 230 /* 231 * Don't allow controlling tty to be set to the controlling tty 232 * (infinite recursion). 233 */ 234 if (ap->a_cmd == TIOCSCTTY) { 235 lwkt_reltoken(&proc_token); 236 return EINVAL; 237 } 238 if (ap->a_cmd == TIOCNOTTY) { 239 if (!SESS_LEADER(p)) { 240 p->p_flag &= ~P_CONTROLT; 241 lwkt_reltoken(&proc_token); 242 return (0); 243 } else { 244 lwkt_reltoken(&proc_token); 245 return (EINVAL); 246 } 247 } 248 lwkt_reltoken(&proc_token); 249 250 return (VOP_IOCTL(ttyvp, ap->a_cmd, ap->a_data, ap->a_fflag, 251 ap->a_cred, ap->a_sysmsg)); 252 } 253 254 static struct filterops cttyfiltops_read = 255 { FILTEROP_ISFD, NULL, cttyfilt_detach, cttyfilt_read }; 256 static struct filterops cttyfiltops_write = 257 { FILTEROP_ISFD, NULL, cttyfilt_detach, cttyfilt_write }; 258 259 static int 260 cttykqfilter(struct dev_kqfilter_args *ap) 261 { 262 cdev_t dev = ap->a_head.a_dev; 263 struct proc *p = curproc; 264 struct knote *kn = ap->a_kn; 265 struct vnode *ttyvp; 266 267 KKASSERT(p); 268 ttyvp = cttyvp(p); 269 270 if (ttyvp != NULL) 271 return (VOP_KQFILTER(ttyvp, kn)); 272 273 ap->a_result = 0; 274 275 switch (kn->kn_filter) { 276 case EVFILT_READ: 277 kn->kn_fop = &cttyfiltops_read; 278 kn->kn_hook = (caddr_t)dev; 279 break; 280 case EVFILT_WRITE: 281 kn->kn_fop = &cttyfiltops_write; 282 kn->kn_hook = (caddr_t)dev; 283 break; 284 default: 285 ap->a_result = EOPNOTSUPP; 286 return (0); 287 } 288 289 return (0); 290 } 291 292 static void 293 cttyfilt_detach(struct knote *kn) {} 294 295 static int 296 cttyfilt_read(struct knote *kn, long hint) 297 { 298 cdev_t dev = (cdev_t)kn->kn_hook; 299 300 if (seltrue(dev, POLLIN | POLLRDNORM)) 301 return (1); 302 303 return (0); 304 } 305 306 static int 307 cttyfilt_write(struct knote *kn, long hint) 308 { 309 cdev_t dev = (cdev_t)kn->kn_hook; 310 311 if (seltrue(dev, POLLOUT | POLLWRNORM)) 312 return (1); 313 314 return (0); 315 } 316 317 static void 318 ctty_drvinit(void *unused __unused) 319 { 320 make_dev(&ctty_ops, 0, 0, 0, 0666, "tty"); 321 } 322 323 SYSINIT(cttydev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ctty_drvinit,NULL) 324