1 /* $NetBSD: cons.c,v 1.65 2008/01/24 17:32:52 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.65 2008/01/24 17:32:52 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 dev_t cndev; 122 int unit, error; 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 if (cn_devvp[unit] != NULLVP) 155 return 0; 156 if ((error = cdevvp(cndev, &cn_devvp[unit])) != 0) 157 printf("cnopen: unable to get vnode reference\n"); 158 error = vn_lock(cn_devvp[unit], LK_EXCLUSIVE | LK_RETRY); 159 if (error == 0) { 160 error = VOP_OPEN(cn_devvp[unit], flag, kauth_cred_get()); 161 VOP_UNLOCK(cn_devvp[unit], 0); 162 } 163 return error; 164 } 165 166 int 167 cnclose(dev_t dev, int flag, int mode, struct lwp *l) 168 { 169 struct vnode *vp; 170 int unit, error; 171 172 unit = minor(dev); 173 174 if (cn_tab == NULL) 175 return (0); 176 177 vp = cn_devvp[unit]; 178 cn_devvp[unit] = NULL; 179 error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 180 if (error == 0) { 181 error = VOP_CLOSE(vp, flag, kauth_cred_get()); 182 VOP_UNLOCK(vp, 0); 183 } 184 return error; 185 } 186 187 int 188 cnread(dev_t dev, struct uio *uio, int flag) 189 { 190 int error; 191 192 /* 193 * If we would redirect input, punt. This will keep strange 194 * things from happening to people who are using the real 195 * console. Nothing should be using /dev/console for 196 * input (except a shell in single-user mode, but then, 197 * one wouldn't TIOCCONS then). 198 */ 199 if (!cn_redirect(&dev, 1, &error)) 200 return error; 201 return cdev_read(dev, uio, flag); 202 } 203 204 int 205 cnwrite(dev_t dev, struct uio *uio, int flag) 206 { 207 int error; 208 209 /* Redirect output, if that's appropriate. */ 210 if (!cn_redirect(&dev, 0, &error)) 211 return error; 212 return cdev_write(dev, uio, flag); 213 } 214 215 int 216 cnioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 217 { 218 int error; 219 220 error = 0; 221 222 /* 223 * Superuser can always use this to wrest control of console 224 * output from the "virtual" console. 225 */ 226 if (cmd == TIOCCONS && constty != NULL) { 227 error = kauth_authorize_generic(l->l_cred, 228 KAUTH_GENERIC_ISSUSER, NULL); 229 if (!error) 230 constty = NULL; 231 return (error); 232 } 233 234 /* 235 * Redirect the ioctl, if that's appropriate. 236 * Note that strange things can happen, if a program does 237 * ioctls on /dev/console, then the console is redirected 238 * out from under it. 239 */ 240 if (!cn_redirect(&dev, 0, &error)) 241 return error; 242 return cdev_ioctl(dev, cmd, data, flag, l); 243 } 244 245 /*ARGSUSED*/ 246 int 247 cnpoll(dev_t dev, int events, struct lwp *l) 248 { 249 int error; 250 251 /* 252 * Redirect the poll, if that's appropriate. 253 * I don't want to think of the possible side effects 254 * of console redirection here. 255 */ 256 if (!cn_redirect(&dev, 0, &error)) 257 return POLLHUP; 258 return cdev_poll(dev, events, l); 259 } 260 261 /*ARGSUSED*/ 262 int 263 cnkqfilter(dev_t dev, struct knote *kn) 264 { 265 int error; 266 267 /* 268 * Redirect the kqfilter, if that's appropriate. 269 * I don't want to think of the possible side effects 270 * of console redirection here. 271 */ 272 if (!cn_redirect(&dev, 0, &error)) 273 return error; 274 return cdev_kqfilter(dev, kn); 275 } 276 277 int 278 cngetc(void) 279 { 280 if (cn_tab == NULL) 281 return (0); 282 return ((*cn_tab->cn_getc)(cn_tab->cn_dev)); 283 } 284 285 int 286 cngetsn(char *cp, int size) 287 { 288 char *lp; 289 int c, len; 290 291 cnpollc(1); 292 293 lp = cp; 294 len = 0; 295 for (;;) { 296 c = cngetc(); 297 switch (c) { 298 case '\n': 299 case '\r': 300 printf("\n"); 301 *lp++ = '\0'; 302 cnpollc(0); 303 return (len); 304 case '\b': 305 case '\177': 306 case '#': 307 if (len) { 308 --len; 309 --lp; 310 printf("\b \b"); 311 } 312 continue; 313 case '@': 314 case 'u'&037: /* CTRL-u */ 315 len = 0; 316 lp = cp; 317 printf("\n"); 318 continue; 319 default: 320 if (len + 1 >= size || c < ' ') { 321 printf("\007"); 322 continue; 323 } 324 printf("%c", c); 325 ++len; 326 *lp++ = c; 327 } 328 } 329 } 330 331 void 332 cnputc(int c) 333 { 334 335 if (cn_tab == NULL) 336 return; 337 338 if (c) { 339 (*cn_tab->cn_putc)(cn_tab->cn_dev, c); 340 if (c == '\n') 341 (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r'); 342 } 343 } 344 345 void 346 cnpollc(int on) 347 { 348 static int refcount = 0; 349 350 if (cn_tab == NULL) 351 return; 352 if (!on) 353 --refcount; 354 if (refcount == 0) 355 (*cn_tab->cn_pollc)(cn_tab->cn_dev, on); 356 if (on) 357 ++refcount; 358 } 359 360 void 361 nullcnpollc(dev_t dev, int on) 362 { 363 364 } 365 366 void 367 cnbell(u_int pitch, u_int period, u_int volume) 368 { 369 370 if (cn_tab == NULL || cn_tab->cn_bell == NULL) 371 return; 372 (*cn_tab->cn_bell)(cn_tab->cn_dev, pitch, period, volume); 373 } 374 375 void 376 cnflush(void) 377 { 378 if (cn_tab == NULL || cn_tab->cn_flush == NULL) 379 return; 380 (*cn_tab->cn_flush)(cn_tab->cn_dev); 381 } 382 383 void 384 cnhalt(void) 385 { 386 if (cn_tab == NULL || cn_tab->cn_halt == NULL) 387 return; 388 (*cn_tab->cn_halt)(cn_tab->cn_dev); 389 } 390 391 /* 392 * Redirect output, if that's appropriate. If there's no real console, 393 * return ENXIO. 394 * 395 * Call with tty_mutex held. 396 */ 397 static bool 398 cn_redirect(dev_t *devp, int is_read, int *error) 399 { 400 dev_t dev = *devp; 401 402 *error = ENXIO; 403 if (constty != NULL && minor(dev) == 0 && 404 (cn_tab == NULL || (cn_tab->cn_pri != CN_REMOTE))) { 405 if (is_read) { 406 *error = 0; 407 return false; 408 } 409 dev = constty->t_dev; 410 } else if (cn_tab == NULL) 411 return false; 412 else 413 dev = cn_tab->cn_dev; 414 *devp = dev; 415 return true; 416 } 417