1 /* $NetBSD: cons.c,v 1.67 2010/06/24 13:03:08 hannken 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.67 2010/06/24 13:03:08 hannken Exp $"); 82 83 #include <sys/param.h> 84 #include <sys/proc.h> 85 #include <sys/systm.h> 86 #include <sys/buf.h> 87 #include <sys/ioctl.h> 88 #include <sys/poll.h> 89 #include <sys/tty.h> 90 #include <sys/file.h> 91 #include <sys/conf.h> 92 #include <sys/vnode.h> 93 #include <sys/kauth.h> 94 #include <sys/mutex.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 bool 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 dev_t cndev; 121 int unit, error; 122 123 unit = minor(dev); 124 if (unit > 1) 125 return ENODEV; 126 127 if (cn_tab == NULL) 128 return (0); 129 130 /* 131 * always open the 'real' console device, so we don't get nailed 132 * later. This follows normal device semantics; they always get 133 * open() calls. 134 */ 135 cndev = cn_tab->cn_dev; 136 if (cndev == NODEV) { 137 /* 138 * This is most likely an error in the console attach 139 * code. Panicking looks better than jumping into nowhere 140 * through cdevsw below.... 141 */ 142 panic("cnopen: no console device"); 143 } 144 if (dev == cndev) { 145 /* 146 * This causes cnopen() to be called recursively, which 147 * is generally a bad thing. It is often caused when 148 * dev == 0 and cn_dev has not been set, but was probably 149 * initialised to 0. 150 */ 151 panic("cnopen: cn_tab->cn_dev == dev"); 152 } 153 if (cn_devvp[unit] != NULLVP) 154 return 0; 155 if ((error = cdevvp(cndev, &cn_devvp[unit])) != 0) 156 printf("cnopen: unable to get vnode reference\n"); 157 error = vn_lock(cn_devvp[unit], LK_EXCLUSIVE | LK_RETRY); 158 if (error == 0) { 159 error = VOP_OPEN(cn_devvp[unit], flag, kauth_cred_get()); 160 VOP_UNLOCK(cn_devvp[unit]); 161 } 162 return error; 163 } 164 165 int 166 cnclose(dev_t dev, int flag, int mode, struct lwp *l) 167 { 168 struct vnode *vp; 169 int unit, error; 170 171 unit = minor(dev); 172 173 if (cn_tab == NULL) 174 return (0); 175 176 vp = cn_devvp[unit]; 177 cn_devvp[unit] = NULL; 178 error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 179 if (error == 0) { 180 error = VOP_CLOSE(vp, flag, kauth_cred_get()); 181 VOP_UNLOCK(vp); 182 } 183 return error; 184 } 185 186 int 187 cnread(dev_t dev, struct uio *uio, int flag) 188 { 189 int error; 190 191 /* 192 * If we would redirect input, punt. This will keep strange 193 * things from happening to people who are using the real 194 * console. Nothing should be using /dev/console for 195 * input (except a shell in single-user mode, but then, 196 * one wouldn't TIOCCONS then). 197 */ 198 if (!cn_redirect(&dev, 1, &error)) 199 return error; 200 return cdev_read(dev, uio, flag); 201 } 202 203 int 204 cnwrite(dev_t dev, struct uio *uio, int flag) 205 { 206 int error; 207 208 /* Redirect output, if that's appropriate. */ 209 if (!cn_redirect(&dev, 0, &error)) 210 return error; 211 return cdev_write(dev, uio, flag); 212 } 213 214 int 215 cnioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 216 { 217 int error; 218 219 error = 0; 220 221 /* 222 * Superuser can always use this to wrest control of console 223 * output from the "virtual" console. 224 */ 225 if (cmd == TIOCCONS && constty != NULL) { 226 error = kauth_authorize_generic(l->l_cred, 227 KAUTH_GENERIC_ISSUSER, NULL); 228 if (!error) 229 constty = NULL; 230 return (error); 231 } 232 233 /* 234 * Redirect the ioctl, if that's appropriate. 235 * Note that strange things can happen, if a program does 236 * ioctls on /dev/console, then the console is redirected 237 * out from under it. 238 */ 239 if (!cn_redirect(&dev, 0, &error)) 240 return error; 241 return cdev_ioctl(dev, cmd, data, flag, l); 242 } 243 244 /*ARGSUSED*/ 245 int 246 cnpoll(dev_t dev, int events, struct lwp *l) 247 { 248 int error; 249 250 /* 251 * Redirect the poll, if that's appropriate. 252 * I don't want to think of the possible side effects 253 * of console redirection here. 254 */ 255 if (!cn_redirect(&dev, 0, &error)) 256 return POLLHUP; 257 return cdev_poll(dev, events, l); 258 } 259 260 /*ARGSUSED*/ 261 int 262 cnkqfilter(dev_t dev, struct knote *kn) 263 { 264 int error; 265 266 /* 267 * Redirect the kqfilter, if that's appropriate. 268 * I don't want to think of the possible side effects 269 * of console redirection here. 270 */ 271 if (!cn_redirect(&dev, 0, &error)) 272 return error; 273 return cdev_kqfilter(dev, kn); 274 } 275 276 int 277 cngetc(void) 278 { 279 if (cn_tab == NULL) 280 return (0); 281 return ((*cn_tab->cn_getc)(cn_tab->cn_dev)); 282 } 283 284 int 285 cngetsn(char *cp, int size) 286 { 287 char *lp; 288 int c, len; 289 290 cnpollc(1); 291 292 lp = cp; 293 len = 0; 294 for (;;) { 295 c = cngetc(); 296 switch (c) { 297 case '\n': 298 case '\r': 299 printf("\n"); 300 *lp++ = '\0'; 301 cnpollc(0); 302 return (len); 303 case '\b': 304 case '\177': 305 case '#': 306 if (len) { 307 --len; 308 --lp; 309 printf("\b \b"); 310 } 311 continue; 312 case '@': 313 case 'u'&037: /* CTRL-u */ 314 len = 0; 315 lp = cp; 316 printf("\n"); 317 continue; 318 default: 319 if (len + 1 >= size || c < ' ') { 320 printf("\007"); 321 continue; 322 } 323 printf("%c", c); 324 ++len; 325 *lp++ = c; 326 } 327 } 328 } 329 330 void 331 cnputc(int c) 332 { 333 334 if (cn_tab == NULL) 335 return; 336 337 if (c) { 338 (*cn_tab->cn_putc)(cn_tab->cn_dev, c); 339 if (c == '\n') 340 (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r'); 341 } 342 } 343 344 void 345 cnpollc(int on) 346 { 347 static int refcount = 0; 348 349 if (cn_tab == NULL) 350 return; 351 if (!on) 352 --refcount; 353 if (refcount == 0) 354 (*cn_tab->cn_pollc)(cn_tab->cn_dev, on); 355 if (on) 356 ++refcount; 357 } 358 359 void 360 nullcnpollc(dev_t dev, int on) 361 { 362 363 } 364 365 void 366 cnbell(u_int pitch, u_int period, u_int volume) 367 { 368 369 if (cn_tab == NULL || cn_tab->cn_bell == NULL) 370 return; 371 (*cn_tab->cn_bell)(cn_tab->cn_dev, pitch, period, volume); 372 } 373 374 void 375 cnflush(void) 376 { 377 if (cn_tab == NULL || cn_tab->cn_flush == NULL) 378 return; 379 (*cn_tab->cn_flush)(cn_tab->cn_dev); 380 } 381 382 void 383 cnhalt(void) 384 { 385 if (cn_tab == NULL || cn_tab->cn_halt == NULL) 386 return; 387 (*cn_tab->cn_halt)(cn_tab->cn_dev); 388 } 389 390 /* 391 * Redirect output, if that's appropriate. If there's no real console, 392 * return ENXIO. 393 * 394 * Call with tty_mutex held. 395 */ 396 static bool 397 cn_redirect(dev_t *devp, int is_read, int *error) 398 { 399 dev_t dev = *devp; 400 401 *error = ENXIO; 402 if (constty != NULL && minor(dev) == 0 && 403 (cn_tab == NULL || (cn_tab->cn_pri != CN_REMOTE))) { 404 if (is_read) { 405 *error = 0; 406 return false; 407 } 408 dev = constty->t_dev; 409 } else if (cn_tab == NULL) 410 return false; 411 else 412 dev = cn_tab->cn_dev; 413 *devp = dev; 414 return true; 415 } 416