1 /* $OpenBSD: cons.c,v 1.14 2003/09/23 16:51:12 millert Exp $ */ 2 /* $NetBSD: cons.c,v 1.30 1996/04/08 19:57:30 jonathan Exp $ */ 3 4 /* 5 * Copyright (c) 1988 University of Utah. 6 * Copyright (c) 1990, 1993 7 * The Regents of the University of California. All rights reserved. 8 * 9 * This code is derived from software contributed to Berkeley by 10 * the Systems Programming Group of the University of Utah Computer 11 * Science Department. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * from: Utah $Hdr: cons.c 1.7 92/01/21$ 38 * 39 * @(#)cons.c 8.2 (Berkeley) 1/12/94 40 */ 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/proc.h> 45 #include <sys/user.h> 46 #include <sys/buf.h> 47 #include <sys/ioctl.h> 48 #include <sys/tty.h> 49 #include <sys/file.h> 50 #include <sys/conf.h> 51 #include <sys/vnode.h> 52 53 #include <dev/cons.h> 54 55 struct tty *constty = NULL; /* virtual console output device */ 56 struct consdev *cn_tab; /* physical console device info */ 57 struct vnode *cn_devvp; /* vnode for underlying device. */ 58 59 int 60 cnopen(dev, flag, mode, p) 61 dev_t dev; 62 int flag, mode; 63 struct proc *p; 64 { 65 dev_t cndev; 66 67 if (cn_tab == NULL) 68 return (0); 69 70 /* 71 * always open the 'real' console device, so we don't get nailed 72 * later. This follows normal device semantics; they always get 73 * open() calls. 74 */ 75 cndev = cn_tab->cn_dev; 76 if (cndev == NODEV) 77 return (ENXIO); 78 #ifdef DIAGNOSTIC 79 if (cndev == dev) 80 panic("cnopen: recursive"); 81 #endif 82 if (cn_devvp == NULLVP) { 83 /* try to get a reference on its vnode, but fail silently */ 84 cdevvp(cndev, &cn_devvp); 85 } 86 return ((*cdevsw[major(cndev)].d_open)(cndev, flag, mode, p)); 87 } 88 89 int 90 cnclose(dev, flag, mode, p) 91 dev_t dev; 92 int flag, mode; 93 struct proc *p; 94 { 95 struct vnode *vp; 96 97 if (cn_tab == NULL) 98 return (0); 99 100 /* 101 * If the real console isn't otherwise open, close it. 102 * If it's otherwise open, don't close it, because that'll 103 * screw up others who have it open. 104 */ 105 dev = cn_tab->cn_dev; 106 if (cn_devvp != NULLVP) { 107 /* release our reference to real dev's vnode */ 108 vrele(cn_devvp); 109 cn_devvp = NULLVP; 110 } 111 if (vfinddev(dev, VCHR, &vp) && vcount(vp)) 112 return (0); 113 return ((*cdevsw[major(dev)].d_close)(dev, flag, mode, p)); 114 } 115 116 int 117 cnread(dev, uio, flag) 118 dev_t dev; 119 struct uio *uio; 120 int flag; 121 { 122 123 /* 124 * If we would redirect input, punt. This will keep strange 125 * things from happening to people who are using the real 126 * console. Nothing should be using /dev/console for 127 * input (except a shell in single-user mode, but then, 128 * one wouldn't TIOCCONS then). 129 */ 130 if (constty != NULL && (cn_tab == NULL || cn_tab->cn_pri != CN_REMOTE)) 131 return 0; 132 else if (cn_tab == NULL) 133 return ENXIO; 134 135 dev = cn_tab->cn_dev; 136 return ((*cdevsw[major(dev)].d_read)(dev, uio, flag)); 137 } 138 139 int 140 cnwrite(dev, uio, flag) 141 dev_t dev; 142 struct uio *uio; 143 int flag; 144 { 145 146 /* 147 * Redirect output, if that's appropriate. 148 * If there's no real console, return ENXIO. 149 */ 150 if (constty != NULL && (cn_tab == NULL || cn_tab->cn_pri != CN_REMOTE)) 151 dev = constty->t_dev; 152 else if (cn_tab == NULL) 153 return ENXIO; 154 else 155 dev = cn_tab->cn_dev; 156 return ((*cdevsw[major(dev)].d_write)(dev, uio, flag)); 157 } 158 159 int 160 cnstop(tp, flag) 161 struct tty *tp; 162 int flag; 163 { 164 return (0); 165 } 166 167 int 168 cnioctl(dev, cmd, data, flag, p) 169 dev_t dev; 170 u_long cmd; 171 caddr_t data; 172 int flag; 173 struct proc *p; 174 { 175 int error; 176 177 /* 178 * Superuser can always use this to wrest control of console 179 * output from the "virtual" console. 180 */ 181 if (cmd == TIOCCONS && constty != NULL) { 182 error = suser(p, SUSER_NOACCT); 183 if (error) 184 return (error); 185 constty = NULL; 186 return (0); 187 } 188 189 /* 190 * Redirect the ioctl, if that's appropriate. 191 * Note that strange things can happen, if a program does 192 * ioctls on /dev/console, then the console is redirected 193 * out from under it. 194 */ 195 if (constty != NULL && (cn_tab == NULL || cn_tab->cn_pri != CN_REMOTE)) 196 dev = constty->t_dev; 197 else if (cn_tab == NULL) 198 return ENXIO; 199 else 200 dev = cn_tab->cn_dev; 201 return ((*cdevsw[major(dev)].d_ioctl)(dev, cmd, data, flag, p)); 202 } 203 204 /*ARGSUSED*/ 205 int 206 cnpoll(dev, rw, p) 207 dev_t dev; 208 int rw; 209 struct proc *p; 210 { 211 212 /* 213 * Redirect the poll, if that's appropriate. 214 * I don't want to think of the possible side effects 215 * of console redirection here. 216 */ 217 if (constty != NULL && (cn_tab == NULL || cn_tab->cn_pri != CN_REMOTE)) 218 dev = constty->t_dev; 219 else if (cn_tab == NULL) 220 return ENXIO; 221 else 222 dev = cn_tab->cn_dev; 223 return (ttpoll(cn_tab->cn_dev, rw, p)); 224 } 225 226 227 int 228 cnkqfilter(dev, kn) 229 dev_t dev; 230 struct knote *kn; 231 { 232 233 /* 234 * Redirect output, if that's appropriate. 235 * If there's no real console, return 1. 236 */ 237 if (constty != NULL && (cn_tab == NULL || cn_tab->cn_pri != CN_REMOTE)) 238 dev = constty->t_dev; 239 else if (cn_tab == NULL) 240 return (1); 241 else 242 dev = cn_tab->cn_dev; 243 if (cdevsw[major(dev)].d_type & D_KQFILTER) 244 return ((*cdevsw[major(dev)].d_kqfilter)(dev, kn)); 245 return (1); 246 } 247 248 int 249 cngetc() 250 { 251 252 if (cn_tab == NULL) 253 return (0); 254 return ((*cn_tab->cn_getc)(cn_tab->cn_dev)); 255 } 256 257 void 258 cnputc(c) 259 register int c; 260 { 261 262 if (cn_tab == NULL) 263 return; 264 265 if (c) { 266 (*cn_tab->cn_putc)(cn_tab->cn_dev, c); 267 if (c == '\n') 268 (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r'); 269 } 270 } 271 272 void 273 cnpollc(on) 274 int on; 275 { 276 static int refcount = 0; 277 278 if (cn_tab == NULL) 279 return; 280 if (!on) 281 --refcount; 282 if (refcount == 0) 283 (*cn_tab->cn_pollc)(cn_tab->cn_dev, on); 284 if (on) 285 ++refcount; 286 } 287 288 void 289 nullcnpollc(dev, on) 290 dev_t dev; 291 int on; 292 { 293 294 } 295 296 void 297 cnbell(pitch, period, volume) 298 u_int pitch, period, volume; 299 { 300 if (cn_tab == NULL || cn_tab->cn_bell == NULL) 301 return; 302 303 (*cn_tab->cn_bell)(cn_tab->cn_dev, pitch, period, volume); 304 } 305