1 /* $NetBSD: cons.c,v 1.60 2006/10/12 01:30:50 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * the Systems Programming Group of the University of Utah Computer 9 * Science Department. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. 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 * from: Utah $Hdr: cons.c 1.7 92/01/21$ 36 * 37 * @(#)cons.c 8.2 (Berkeley) 1/12/94 38 */ 39 40 /* 41 * Copyright (c) 1988 University of Utah. 42 * 43 * This code is derived from software contributed to Berkeley by 44 * the Systems Programming Group of the University of Utah Computer 45 * Science Department. 46 * 47 * Redistribution and use in source and binary forms, with or without 48 * modification, are permitted provided that the following conditions 49 * are met: 50 * 1. Redistributions of source code must retain the above copyright 51 * notice, this list of conditions and the following disclaimer. 52 * 2. Redistributions in binary form must reproduce the above copyright 53 * notice, this list of conditions and the following disclaimer in the 54 * documentation and/or other materials provided with the distribution. 55 * 3. All advertising materials mentioning features or use of this software 56 * must display the following acknowledgement: 57 * This product includes software developed by the University of 58 * California, Berkeley and its contributors. 59 * 4. Neither the name of the University nor the names of its contributors 60 * may be used to endorse or promote products derived from this software 61 * without specific prior written permission. 62 * 63 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 64 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 65 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 66 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 67 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 68 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 69 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 70 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 71 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 72 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 73 * SUCH DAMAGE. 74 * 75 * from: Utah $Hdr: cons.c 1.7 92/01/21$ 76 * 77 * @(#)cons.c 8.2 (Berkeley) 1/12/94 78 */ 79 80 #include <sys/cdefs.h> 81 __KERNEL_RCSID(0, "$NetBSD: cons.c,v 1.60 2006/10/12 01:30:50 christos Exp $"); 82 83 #include <sys/param.h> 84 #include <sys/proc.h> 85 #include <sys/user.h> 86 #include <sys/systm.h> 87 #include <sys/buf.h> 88 #include <sys/ioctl.h> 89 #include <sys/poll.h> 90 #include <sys/tty.h> 91 #include <sys/file.h> 92 #include <sys/conf.h> 93 #include <sys/vnode.h> 94 #include <sys/kauth.h> 95 96 #include <dev/cons.h> 97 98 dev_type_open(cnopen); 99 dev_type_close(cnclose); 100 dev_type_read(cnread); 101 dev_type_write(cnwrite); 102 dev_type_ioctl(cnioctl); 103 dev_type_poll(cnpoll); 104 dev_type_kqfilter(cnkqfilter); 105 106 static const struct cdevsw *cn_redirect(dev_t *, int, int *); 107 108 const struct cdevsw cons_cdevsw = { 109 cnopen, cnclose, cnread, cnwrite, cnioctl, 110 nostop, notty, cnpoll, nommap, cnkqfilter, D_TTY 111 }; 112 113 struct tty *constty = NULL; /* virtual console output device */ 114 struct consdev *cn_tab; /* physical console device info */ 115 struct vnode *cn_devvp[2]; /* vnode for underlying device. */ 116 117 int 118 cnopen(dev_t dev, int flag, int mode, struct lwp *l) 119 { 120 const struct cdevsw *cdev; 121 dev_t cndev; 122 int unit; 123 124 unit = minor(dev); 125 if (unit > 1) 126 return ENODEV; 127 128 if (cn_tab == NULL) 129 return (0); 130 131 /* 132 * always open the 'real' console device, so we don't get nailed 133 * later. This follows normal device semantics; they always get 134 * open() calls. 135 */ 136 cndev = cn_tab->cn_dev; 137 if (cndev == NODEV) { 138 /* 139 * This is most likely an error in the console attach 140 * code. Panicking looks better than jumping into nowhere 141 * through cdevsw below.... 142 */ 143 panic("cnopen: no console device"); 144 } 145 if (dev == cndev) { 146 /* 147 * This causes cnopen() to be called recursively, which 148 * is generally a bad thing. It is often caused when 149 * dev == 0 and cn_dev has not been set, but was probably 150 * initialised to 0. 151 */ 152 panic("cnopen: cn_tab->cn_dev == dev"); 153 } 154 cdev = cdevsw_lookup(cndev); 155 if (cdev == NULL) 156 return (ENXIO); 157 158 if (cn_devvp[unit] == NULLVP) { 159 /* try to get a reference on its vnode, but fail silently */ 160 cdevvp(cndev, &cn_devvp[unit]); 161 } 162 return ((*cdev->d_open)(cndev, flag, mode, l)); 163 } 164 165 int 166 cnclose(dev_t dev, int flag, int mode, struct lwp *l) 167 { 168 const struct cdevsw *cdev; 169 struct vnode *vp; 170 int unit; 171 172 unit = minor(dev); 173 174 if (cn_tab == NULL) 175 return (0); 176 177 /* 178 * If the real console isn't otherwise open, close it. 179 * If it's otherwise open, don't close it, because that'll 180 * screw up others who have it open. 181 */ 182 dev = cn_tab->cn_dev; 183 cdev = cdevsw_lookup(dev); 184 if (cdev == NULL) 185 return (ENXIO); 186 if (cn_devvp[unit] != NULLVP) { 187 /* release our reference to real dev's vnode */ 188 vrele(cn_devvp[unit]); 189 cn_devvp[unit] = NULLVP; 190 } 191 if (vfinddev(dev, VCHR, &vp) && vcount(vp)) 192 return (0); 193 return ((*cdev->d_close)(dev, flag, mode, l)); 194 } 195 196 int 197 cnread(dev_t dev, struct uio *uio, int flag) 198 { 199 const struct cdevsw *cdev; 200 int error; 201 202 /* 203 * If we would redirect input, punt. This will keep strange 204 * things from happening to people who are using the real 205 * console. Nothing should be using /dev/console for 206 * input (except a shell in single-user mode, but then, 207 * one wouldn't TIOCCONS then). 208 */ 209 cdev = cn_redirect(&dev, 1, &error); 210 if (cdev == NULL) 211 return error; 212 return ((*cdev->d_read)(dev, uio, flag)); 213 } 214 215 int 216 cnwrite(dev_t dev, struct uio *uio, int flag) 217 { 218 const struct cdevsw *cdev; 219 int error; 220 221 /* Redirect output, if that's appropriate. */ 222 cdev = cn_redirect(&dev, 0, &error); 223 if (cdev == NULL) 224 return error; 225 226 return ((*cdev->d_write)(dev, uio, flag)); 227 } 228 229 int 230 cnioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct lwp *l) 231 { 232 const struct cdevsw *cdev; 233 int error; 234 235 /* 236 * Superuser can always use this to wrest control of console 237 * output from the "virtual" console. 238 */ 239 if (cmd == TIOCCONS && constty != NULL) { 240 error = kauth_authorize_generic(l->l_cred, 241 KAUTH_GENERIC_ISSUSER, NULL); 242 if (error) 243 return (error); 244 constty = NULL; 245 return (0); 246 } 247 248 /* 249 * Redirect the ioctl, if that's appropriate. 250 * Note that strange things can happen, if a program does 251 * ioctls on /dev/console, then the console is redirected 252 * out from under it. 253 */ 254 cdev = cn_redirect(&dev, 0, &error); 255 if (cdev == NULL) 256 return error; 257 return ((*cdev->d_ioctl)(dev, cmd, data, flag, l)); 258 } 259 260 /*ARGSUSED*/ 261 int 262 cnpoll(dev_t dev, int events, struct lwp *l) 263 { 264 const struct cdevsw *cdev; 265 int error; 266 267 /* 268 * Redirect the poll, if that's appropriate. 269 * I don't want to think of the possible side effects 270 * of console redirection here. 271 */ 272 cdev = cn_redirect(&dev, 0, &error); 273 if (cdev == NULL) 274 return POLLHUP; 275 return ((*cdev->d_poll)(dev, events, l)); 276 } 277 278 /*ARGSUSED*/ 279 int 280 cnkqfilter(dev_t dev, struct knote *kn) 281 { 282 const struct cdevsw *cdev; 283 int error; 284 285 /* 286 * Redirect the kqfilter, if that's appropriate. 287 * I don't want to think of the possible side effects 288 * of console redirection here. 289 */ 290 cdev = cn_redirect(&dev, 0, &error); 291 if (cdev == NULL) 292 return error; 293 return ((*cdev->d_kqfilter)(dev, kn)); 294 } 295 296 int 297 cngetc(void) 298 { 299 if (cn_tab == NULL) 300 return (0); 301 return ((*cn_tab->cn_getc)(cn_tab->cn_dev)); 302 } 303 304 int 305 cngetsn(char *cp, int size) 306 { 307 char *lp; 308 int c, len; 309 310 cnpollc(1); 311 312 lp = cp; 313 len = 0; 314 for (;;) { 315 c = cngetc(); 316 switch (c) { 317 case '\n': 318 case '\r': 319 printf("\n"); 320 *lp++ = '\0'; 321 cnpollc(0); 322 return (len); 323 case '\b': 324 case '\177': 325 case '#': 326 if (len) { 327 --len; 328 --lp; 329 printf("\b \b"); 330 } 331 continue; 332 case '@': 333 case 'u'&037: /* CTRL-u */ 334 len = 0; 335 lp = cp; 336 printf("\n"); 337 continue; 338 default: 339 if (len + 1 >= size || c < ' ') { 340 printf("\007"); 341 continue; 342 } 343 printf("%c", c); 344 ++len; 345 *lp++ = c; 346 } 347 } 348 } 349 350 void 351 cnputc(int c) 352 { 353 354 if (cn_tab == NULL) 355 return; 356 357 if (c) { 358 (*cn_tab->cn_putc)(cn_tab->cn_dev, c); 359 if (c == '\n') 360 (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r'); 361 } 362 } 363 364 void 365 cnpollc(int on) 366 { 367 static int refcount = 0; 368 369 if (cn_tab == NULL) 370 return; 371 if (!on) 372 --refcount; 373 if (refcount == 0) 374 (*cn_tab->cn_pollc)(cn_tab->cn_dev, on); 375 if (on) 376 ++refcount; 377 } 378 379 void 380 nullcnpollc(dev_t dev __unused, int on __unused) 381 { 382 383 } 384 385 void 386 cnbell(u_int pitch, u_int period, u_int volume) 387 { 388 389 if (cn_tab == NULL || cn_tab->cn_bell == NULL) 390 return; 391 (*cn_tab->cn_bell)(cn_tab->cn_dev, pitch, period, volume); 392 } 393 394 void 395 cnflush(void) 396 { 397 if (cn_tab == NULL || cn_tab->cn_flush == NULL) 398 return; 399 (*cn_tab->cn_flush)(cn_tab->cn_dev); 400 } 401 402 void 403 cnhalt(void) 404 { 405 if (cn_tab == NULL || cn_tab->cn_halt == NULL) 406 return; 407 (*cn_tab->cn_halt)(cn_tab->cn_dev); 408 } 409 410 static const struct cdevsw * 411 cn_redirect(dev_t *devp, int is_read, int *error) 412 { 413 dev_t dev = *devp; 414 415 /* 416 * Redirect output, if that's appropriate. 417 * If there's no real console, return ENXIO. 418 */ 419 *error = ENXIO; 420 if (constty != NULL && minor(dev) == 0 && 421 (cn_tab == NULL || (cn_tab->cn_pri != CN_REMOTE))) { 422 if (is_read) { 423 *error = 0; 424 return NULL; 425 } 426 dev = constty->t_dev; 427 } else if (cn_tab == NULL) 428 return NULL; 429 else 430 dev = cn_tab->cn_dev; 431 *devp = dev; 432 return cdevsw_lookup(dev); 433 } 434