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/mutex.h> 49 #include <sys/mac.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 error = VOP_OPEN(ttyvp, flag, NOCRED, td); 108 VOP_UNLOCK(ttyvp, 0, td); 109 return (error); 110 } 111 112 /*ARGSUSED*/ 113 static int 114 cttyread(dev, uio, flag) 115 dev_t dev; 116 struct uio *uio; 117 int flag; 118 { 119 struct thread *td = uio->uio_td; 120 register struct vnode *ttyvp; 121 int error; 122 123 PROC_LOCK(td->td_proc); 124 SESS_LOCK(td->td_proc->p_session); 125 ttyvp = cttyvp(td); 126 SESS_UNLOCK(td->td_proc->p_session); 127 PROC_UNLOCK(td->td_proc); 128 129 if (ttyvp == NULL) 130 return (EIO); 131 vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY, td); 132 error = VOP_READ(ttyvp, uio, flag, NOCRED); 133 VOP_UNLOCK(ttyvp, 0, td); 134 return (error); 135 } 136 137 /*ARGSUSED*/ 138 static int 139 cttywrite(dev, uio, flag) 140 dev_t dev; 141 struct uio *uio; 142 int flag; 143 { 144 struct thread *td = uio->uio_td; 145 struct vnode *ttyvp; 146 struct mount *mp; 147 int error; 148 149 PROC_LOCK(td->td_proc); 150 SESS_LOCK(td->td_proc->p_session); 151 ttyvp = cttyvp(td); 152 SESS_UNLOCK(td->td_proc->p_session); 153 PROC_UNLOCK(td->td_proc); 154 155 if (ttyvp == NULL) 156 return (EIO); 157 mp = NULL; 158 if (ttyvp->v_type != VCHR && 159 (error = vn_start_write(ttyvp, &mp, V_WAIT | PCATCH)) != 0) 160 return (error); 161 vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY, td); 162 #ifdef MAC 163 /* XXX: shouldn't the cred below be td->td_ucred not NOCRED? */ 164 error = mac_check_vnode_op(td->td_ucred, ttyvp, MAC_OP_VNODE_WRITE); 165 if (error == 0) 166 #endif 167 error = VOP_WRITE(ttyvp, uio, flag, NOCRED); 168 VOP_UNLOCK(ttyvp, 0, td); 169 vn_finished_write(mp); 170 return (error); 171 } 172 173 /*ARGSUSED*/ 174 static int 175 cttyioctl(dev, cmd, addr, flag, td) 176 dev_t dev; 177 u_long cmd; 178 caddr_t addr; 179 int flag; 180 struct thread *td; 181 { 182 struct vnode *ttyvp; 183 int error; 184 185 PROC_LOCK(td->td_proc); 186 SESS_LOCK(td->td_proc->p_session); 187 ttyvp = cttyvp(td); 188 SESS_UNLOCK(td->td_proc->p_session); 189 PROC_UNLOCK(td->td_proc); 190 191 if (ttyvp == NULL) 192 return (EIO); 193 if (cmd == TIOCSCTTY) /* don't allow controlling tty to be set */ 194 return EINVAL; /* to controlling tty -- infinite recursion */ 195 if (cmd == TIOCNOTTY) { 196 PROC_LOCK(td->td_proc); 197 SESS_LOCK(td->td_proc->p_session); 198 error = 0; 199 if (!SESS_LEADER(td->td_proc)) 200 td->td_proc->p_flag &= ~P_CONTROLT; 201 else 202 error = EINVAL; 203 SESS_UNLOCK(td->td_proc->p_session); 204 PROC_UNLOCK(td->td_proc); 205 return (error); 206 } 207 /* XXXMAC: Should this be td->td_ucred below? */ 208 return (VOP_IOCTL(ttyvp, cmd, addr, flag, NOCRED, td)); 209 } 210 211 /*ARGSUSED*/ 212 static int 213 cttypoll(dev, events, td) 214 dev_t dev; 215 int events; 216 struct thread *td; 217 { 218 struct vnode *ttyvp; 219 #ifdef MAC 220 int error; 221 #endif 222 223 PROC_LOCK(td->td_proc); 224 SESS_LOCK(td->td_proc->p_session); 225 ttyvp = cttyvp(td); 226 SESS_UNLOCK(td->td_proc->p_session); 227 PROC_UNLOCK(td->td_proc); 228 229 if (ttyvp == NULL) 230 /* try operation to get EOF/failure */ 231 return (seltrue(dev, events, td)); 232 #ifdef MAC 233 vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY, td); 234 error = mac_check_vnode_op(td->td_ucred, ttyvp, MAC_OP_VNODE_POLL); 235 VOP_UNLOCK(ttyvp, 0, td); 236 if (error) 237 return (error); 238 #endif 239 return (VOP_POLL(ttyvp, events, td->td_ucred, td)); 240 } 241 242 static void ctty_clone(void *arg, char *name, int namelen, dev_t *dev); 243 244 static dev_t ctty; 245 246 static void 247 ctty_clone(void *arg, char *name, int namelen, dev_t *dev) 248 { 249 struct vnode *vp; 250 251 if (*dev != NODEV) 252 return; 253 if (strcmp(name, "tty")) 254 return; 255 vp = cttyvp(curthread); 256 if (vp == NULL) { 257 if (ctty) 258 *dev = ctty; 259 } else 260 *dev = vp->v_rdev; 261 } 262 263 264 static void ctty_drvinit(void *unused); 265 static void 266 ctty_drvinit(unused) 267 void *unused; 268 { 269 270 if (devfs_present) { 271 EVENTHANDLER_REGISTER(dev_clone, ctty_clone, 0, 1000); 272 ctty = make_dev(&ctty_cdevsw, 0, 0, 0, 0666, "ctty"); 273 } else { 274 make_dev(&ctty_cdevsw, 0, 0, 0, 0666, "tty"); 275 } 276 } 277 278 SYSINIT(cttydev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ctty_drvinit,NULL) 279