1 /* $NetBSD: cons.c,v 1.64 2007/07/09 21:00:28 ad 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.64 2007/07/09 21:00:28 ad 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 #include <sys/mutex.h> 96 97 #include <dev/cons.h> 98 99 dev_type_open(cnopen); 100 dev_type_close(cnclose); 101 dev_type_read(cnread); 102 dev_type_write(cnwrite); 103 dev_type_ioctl(cnioctl); 104 dev_type_poll(cnpoll); 105 dev_type_kqfilter(cnkqfilter); 106 107 static bool cn_redirect(dev_t *, int, int *); 108 109 const struct cdevsw cons_cdevsw = { 110 cnopen, cnclose, cnread, cnwrite, cnioctl, 111 nostop, notty, cnpoll, nommap, cnkqfilter, D_TTY 112 }; 113 114 struct tty *constty = NULL; /* virtual console output device */ 115 struct consdev *cn_tab; /* physical console device info */ 116 struct vnode *cn_devvp[2]; /* vnode for underlying device. */ 117 118 int 119 cnopen(dev_t dev, int flag, int mode, struct lwp *l) 120 { 121 const struct cdevsw *cdev; 122 dev_t cndev; 123 int unit; 124 125 unit = minor(dev); 126 if (unit > 1) 127 return ENODEV; 128 129 if (cn_tab == NULL) 130 return (0); 131 132 /* 133 * always open the 'real' console device, so we don't get nailed 134 * later. This follows normal device semantics; they always get 135 * open() calls. 136 */ 137 cndev = cn_tab->cn_dev; 138 if (cndev == NODEV) { 139 /* 140 * This is most likely an error in the console attach 141 * code. Panicking looks better than jumping into nowhere 142 * through cdevsw below.... 143 */ 144 panic("cnopen: no console device"); 145 } 146 if (dev == cndev) { 147 /* 148 * This causes cnopen() to be called recursively, which 149 * is generally a bad thing. It is often caused when 150 * dev == 0 and cn_dev has not been set, but was probably 151 * initialised to 0. 152 */ 153 panic("cnopen: cn_tab->cn_dev == dev"); 154 } 155 cdev = cdevsw_lookup(cndev); 156 if (cdev == NULL) 157 return (ENXIO); 158 159 if (cn_devvp[unit] == NULLVP) { 160 /* try to get a reference on its vnode, but fail silently */ 161 cdevvp(cndev, &cn_devvp[unit]); 162 } 163 return cdev_open(cndev, flag, mode, l); 164 } 165 166 int 167 cnclose(dev_t dev, int flag, int mode, struct lwp *l) 168 { 169 const struct cdevsw *cdev; 170 struct vnode *vp; 171 int unit; 172 173 unit = minor(dev); 174 175 if (cn_tab == NULL) 176 return (0); 177 178 /* 179 * If the real console isn't otherwise open, close it. 180 * If it's otherwise open, don't close it, because that'll 181 * screw up others who have it open. 182 */ 183 dev = cn_tab->cn_dev; 184 cdev = cdevsw_lookup(dev); 185 if (cdev == NULL) 186 return (ENXIO); 187 if (cn_devvp[unit] != NULLVP) { 188 /* release our reference to real dev's vnode */ 189 vrele(cn_devvp[unit]); 190 cn_devvp[unit] = NULLVP; 191 } 192 if (vfinddev(dev, VCHR, &vp) && vcount(vp)) 193 return (0); 194 return cdev_close(dev, flag, mode, l); 195 } 196 197 int 198 cnread(dev_t dev, struct uio *uio, int flag) 199 { 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 if (!cn_redirect(&dev, 1, &error)) 210 return error; 211 return cdev_read(dev, uio, flag); 212 } 213 214 int 215 cnwrite(dev_t dev, struct uio *uio, int flag) 216 { 217 int error; 218 219 /* Redirect output, if that's appropriate. */ 220 if (!cn_redirect(&dev, 0, &error)) 221 return error; 222 return cdev_write(dev, uio, flag); 223 } 224 225 int 226 cnioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 227 { 228 int error; 229 230 error = 0; 231 232 /* 233 * Superuser can always use this to wrest control of console 234 * output from the "virtual" console. 235 */ 236 if (cmd == TIOCCONS && constty != NULL) { 237 error = kauth_authorize_generic(l->l_cred, 238 KAUTH_GENERIC_ISSUSER, NULL); 239 if (!error) 240 constty = NULL; 241 return (error); 242 } 243 244 /* 245 * Redirect the ioctl, if that's appropriate. 246 * Note that strange things can happen, if a program does 247 * ioctls on /dev/console, then the console is redirected 248 * out from under it. 249 */ 250 if (!cn_redirect(&dev, 0, &error)) 251 return error; 252 return cdev_ioctl(dev, cmd, data, flag, l); 253 } 254 255 /*ARGSUSED*/ 256 int 257 cnpoll(dev_t dev, int events, struct lwp *l) 258 { 259 int error; 260 261 /* 262 * Redirect the poll, if that's appropriate. 263 * I don't want to think of the possible side effects 264 * of console redirection here. 265 */ 266 if (!cn_redirect(&dev, 0, &error)) 267 return POLLHUP; 268 return cdev_poll(dev, events, l); 269 } 270 271 /*ARGSUSED*/ 272 int 273 cnkqfilter(dev_t dev, struct knote *kn) 274 { 275 int error; 276 277 /* 278 * Redirect the kqfilter, if that's appropriate. 279 * I don't want to think of the possible side effects 280 * of console redirection here. 281 */ 282 if (!cn_redirect(&dev, 0, &error)) 283 return error; 284 return cdev_kqfilter(dev, kn); 285 } 286 287 int 288 cngetc(void) 289 { 290 if (cn_tab == NULL) 291 return (0); 292 return ((*cn_tab->cn_getc)(cn_tab->cn_dev)); 293 } 294 295 int 296 cngetsn(char *cp, int size) 297 { 298 char *lp; 299 int c, len; 300 301 cnpollc(1); 302 303 lp = cp; 304 len = 0; 305 for (;;) { 306 c = cngetc(); 307 switch (c) { 308 case '\n': 309 case '\r': 310 printf("\n"); 311 *lp++ = '\0'; 312 cnpollc(0); 313 return (len); 314 case '\b': 315 case '\177': 316 case '#': 317 if (len) { 318 --len; 319 --lp; 320 printf("\b \b"); 321 } 322 continue; 323 case '@': 324 case 'u'&037: /* CTRL-u */ 325 len = 0; 326 lp = cp; 327 printf("\n"); 328 continue; 329 default: 330 if (len + 1 >= size || c < ' ') { 331 printf("\007"); 332 continue; 333 } 334 printf("%c", c); 335 ++len; 336 *lp++ = c; 337 } 338 } 339 } 340 341 void 342 cnputc(int c) 343 { 344 345 if (cn_tab == NULL) 346 return; 347 348 if (c) { 349 (*cn_tab->cn_putc)(cn_tab->cn_dev, c); 350 if (c == '\n') 351 (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r'); 352 } 353 } 354 355 void 356 cnpollc(int on) 357 { 358 static int refcount = 0; 359 360 if (cn_tab == NULL) 361 return; 362 if (!on) 363 --refcount; 364 if (refcount == 0) 365 (*cn_tab->cn_pollc)(cn_tab->cn_dev, on); 366 if (on) 367 ++refcount; 368 } 369 370 void 371 nullcnpollc(dev_t dev, int on) 372 { 373 374 } 375 376 void 377 cnbell(u_int pitch, u_int period, u_int volume) 378 { 379 380 if (cn_tab == NULL || cn_tab->cn_bell == NULL) 381 return; 382 (*cn_tab->cn_bell)(cn_tab->cn_dev, pitch, period, volume); 383 } 384 385 void 386 cnflush(void) 387 { 388 if (cn_tab == NULL || cn_tab->cn_flush == NULL) 389 return; 390 (*cn_tab->cn_flush)(cn_tab->cn_dev); 391 } 392 393 void 394 cnhalt(void) 395 { 396 if (cn_tab == NULL || cn_tab->cn_halt == NULL) 397 return; 398 (*cn_tab->cn_halt)(cn_tab->cn_dev); 399 } 400 401 /* 402 * Redirect output, if that's appropriate. If there's no real console, 403 * return ENXIO. 404 * 405 * Call with tty_mutex held. 406 */ 407 static bool 408 cn_redirect(dev_t *devp, int is_read, int *error) 409 { 410 dev_t dev = *devp; 411 412 *error = ENXIO; 413 if (constty != NULL && minor(dev) == 0 && 414 (cn_tab == NULL || (cn_tab->cn_pri != CN_REMOTE))) { 415 if (is_read) { 416 *error = 0; 417 return false; 418 } 419 dev = constty->t_dev; 420 } else if (cn_tab == NULL) 421 return false; 422 else 423 dev = cn_tab->cn_dev; 424 *devp = dev; 425 return true; 426 } 427