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