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$ 35 */ 36 37 /* 38 * Indirect driver for controlling tty. 39 */ 40 41 #include "opt_mac.h" 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/conf.h> 46 #include <sys/kernel.h> 47 #include <sys/lock.h> 48 #include <sys/mac.h> 49 #include <sys/mutex.h> 50 #include <sys/sx.h> 51 #include <sys/proc.h> 52 #include <sys/ttycom.h> 53 #include <sys/vnode.h> 54 55 static d_open_t cttyopen; 56 static d_read_t cttyread; 57 static d_write_t cttywrite; 58 static d_ioctl_t cttyioctl; 59 static d_poll_t cttypoll; 60 61 #define CDEV_MAJOR 1 62 63 static struct cdevsw ctty_cdevsw = { 64 /* open */ cttyopen, 65 /* close */ nullclose, 66 /* read */ cttyread, 67 /* write */ cttywrite, 68 /* ioctl */ cttyioctl, 69 /* poll */ cttypoll, 70 /* mmap */ nommap, 71 /* strategy */ nostrategy, 72 /* name */ "ctty", 73 /* maj */ CDEV_MAJOR, 74 /* dump */ nodump, 75 /* psize */ nopsize, 76 /* flags */ D_TTY, 77 }; 78 79 #define cttyvp(td) ((td)->td_proc->p_flag & P_CONTROLT ? (td)->td_proc->p_session->s_ttyvp : NULL) 80 81 /*ARGSUSED*/ 82 static int 83 cttyopen(dev, flag, mode, td) 84 dev_t dev; 85 int flag, mode; 86 struct thread *td; 87 { 88 struct vnode *ttyvp; 89 int error; 90 91 PROC_LOCK(td->td_proc); 92 SESS_LOCK(td->td_proc->p_session); 93 ttyvp = cttyvp(td); 94 SESS_UNLOCK(td->td_proc->p_session); 95 PROC_UNLOCK(td->td_proc); 96 97 if (ttyvp == NULL) 98 return (ENXIO); 99 vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY, td); 100 #ifdef MAC 101 error = mac_check_vnode_open(td->td_ucred, ttyvp, flag); 102 if (error) { 103 VOP_UNLOCK(ttyvp, 0, td); 104 return (error); 105 } 106 #endif 107 /* XXX: Shouldn't this cred be td->td_ucred not NOCRED? */ 108 error = VOP_OPEN(ttyvp, flag, NOCRED, td); 109 VOP_UNLOCK(ttyvp, 0, td); 110 return (error); 111 } 112 113 /*ARGSUSED*/ 114 static int 115 cttyread(dev, uio, flag) 116 dev_t dev; 117 struct uio *uio; 118 int flag; 119 { 120 struct thread *td = uio->uio_td; 121 register struct vnode *ttyvp; 122 int error; 123 124 PROC_LOCK(td->td_proc); 125 SESS_LOCK(td->td_proc->p_session); 126 ttyvp = cttyvp(td); 127 SESS_UNLOCK(td->td_proc->p_session); 128 PROC_UNLOCK(td->td_proc); 129 130 if (ttyvp == NULL) 131 return (EIO); 132 vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY, td); 133 #ifdef MAC 134 error = mac_check_vnode_read(td->td_ucred, NOCRED, ttyvp); 135 if (error == 0) 136 #endif 137 /* XXX: Shouldn't this cred be td->td_ucred not NOCRED? */ 138 error = VOP_READ(ttyvp, uio, flag, NOCRED); 139 VOP_UNLOCK(ttyvp, 0, td); 140 return (error); 141 } 142 143 /*ARGSUSED*/ 144 static int 145 cttywrite(dev, uio, flag) 146 dev_t dev; 147 struct uio *uio; 148 int flag; 149 { 150 struct thread *td = uio->uio_td; 151 struct vnode *ttyvp; 152 struct mount *mp; 153 int error; 154 155 PROC_LOCK(td->td_proc); 156 SESS_LOCK(td->td_proc->p_session); 157 ttyvp = cttyvp(td); 158 SESS_UNLOCK(td->td_proc->p_session); 159 PROC_UNLOCK(td->td_proc); 160 161 if (ttyvp == NULL) 162 return (EIO); 163 mp = NULL; 164 if (ttyvp->v_type != VCHR && 165 (error = vn_start_write(ttyvp, &mp, V_WAIT | PCATCH)) != 0) 166 return (error); 167 vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY, td); 168 #ifdef MAC 169 error = mac_check_vnode_write(td->td_ucred, NOCRED, ttyvp); 170 if (error == 0) 171 #endif 172 /* XXX: shouldn't this cred be td->td_ucred not NOCRED? */ 173 error = VOP_WRITE(ttyvp, uio, flag, NOCRED); 174 VOP_UNLOCK(ttyvp, 0, td); 175 vn_finished_write(mp); 176 return (error); 177 } 178 179 /*ARGSUSED*/ 180 static int 181 cttyioctl(dev, cmd, addr, flag, td) 182 dev_t dev; 183 u_long cmd; 184 caddr_t addr; 185 int flag; 186 struct thread *td; 187 { 188 struct vnode *ttyvp; 189 int error; 190 191 PROC_LOCK(td->td_proc); 192 SESS_LOCK(td->td_proc->p_session); 193 ttyvp = cttyvp(td); 194 SESS_UNLOCK(td->td_proc->p_session); 195 PROC_UNLOCK(td->td_proc); 196 197 if (ttyvp == NULL) 198 return (EIO); 199 if (cmd == TIOCSCTTY) /* don't allow controlling tty to be set */ 200 return EINVAL; /* to controlling tty -- infinite recursion */ 201 if (cmd == TIOCNOTTY) { 202 PROC_LOCK(td->td_proc); 203 SESS_LOCK(td->td_proc->p_session); 204 error = 0; 205 if (!SESS_LEADER(td->td_proc)) 206 td->td_proc->p_flag &= ~P_CONTROLT; 207 else 208 error = EINVAL; 209 SESS_UNLOCK(td->td_proc->p_session); 210 PROC_UNLOCK(td->td_proc); 211 return (error); 212 } 213 /* XXXMAC: Should this be td->td_ucred below? */ 214 return (VOP_IOCTL(ttyvp, cmd, addr, flag, NOCRED, td)); 215 } 216 217 /*ARGSUSED*/ 218 static int 219 cttypoll(dev, events, td) 220 dev_t dev; 221 int events; 222 struct thread *td; 223 { 224 struct vnode *ttyvp; 225 #ifdef MAC 226 int error; 227 #endif 228 229 PROC_LOCK(td->td_proc); 230 SESS_LOCK(td->td_proc->p_session); 231 ttyvp = cttyvp(td); 232 SESS_UNLOCK(td->td_proc->p_session); 233 PROC_UNLOCK(td->td_proc); 234 235 if (ttyvp == NULL) 236 /* try operation to get EOF/failure */ 237 return (seltrue(dev, events, td)); 238 #ifdef MAC 239 vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY, td); 240 error = mac_check_vnode_poll(td->td_ucred, NOCRED, ttyvp); 241 VOP_UNLOCK(ttyvp, 0, td); 242 if (error) 243 return (error); 244 #endif 245 return (VOP_POLL(ttyvp, events, td->td_ucred, td)); 246 } 247 248 static void ctty_clone(void *arg, char *name, int namelen, dev_t *dev); 249 250 static dev_t ctty; 251 252 static void 253 ctty_clone(void *arg, char *name, int namelen, dev_t *dev) 254 { 255 struct vnode *vp; 256 257 if (*dev != NODEV) 258 return; 259 if (strcmp(name, "tty")) 260 return; 261 vp = cttyvp(curthread); 262 if (vp == NULL) { 263 if (ctty) 264 *dev = ctty; 265 } else 266 *dev = vp->v_rdev; 267 } 268 269 270 static void ctty_drvinit(void *unused); 271 static void 272 ctty_drvinit(unused) 273 void *unused; 274 { 275 276 if (devfs_present) { 277 EVENTHANDLER_REGISTER(dev_clone, ctty_clone, 0, 1000); 278 ctty = make_dev(&ctty_cdevsw, 0, 0, 0, 0666, "ctty"); 279 } else { 280 make_dev(&ctty_cdevsw, 0, 0, 0, 0666, "tty"); 281 } 282 } 283 284 SYSINIT(cttydev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ctty_drvinit,NULL) 285