kern_cons.c revision 62573
1/* 2 * Copyright (c) 1988 University of Utah. 3 * Copyright (c) 1991 The Regents of the University of California. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * the Systems Programming Group of the University of Utah Computer 8 * Science Department. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * from: @(#)cons.c 7.2 (Berkeley) 5/9/91 39 * $FreeBSD: head/sys/kern/tty_cons.c 62573 2000-07-04 11:25:35Z phk $ 40 */ 41 42#include <sys/param.h> 43#include <sys/systm.h> 44#include <sys/conf.h> 45#include <sys/cons.h> 46#include <sys/kernel.h> 47#include <sys/reboot.h> 48#include <sys/sysctl.h> 49#include <sys/proc.h> 50#include <sys/tty.h> 51#include <sys/uio.h> 52 53#include <machine/cpu.h> 54 55static d_open_t cnopen; 56static d_close_t cnclose; 57static d_read_t cnread; 58static d_write_t cnwrite; 59static d_ioctl_t cnioctl; 60static d_poll_t cnpoll; 61 62#define CDEV_MAJOR 0 63static struct cdevsw cn_cdevsw = { 64 /* open */ cnopen, 65 /* close */ cnclose, 66 /* read */ cnread, 67 /* write */ cnwrite, 68 /* ioctl */ cnioctl, 69 /* poll */ cnpoll, 70 /* mmap */ nommap, 71 /* strategy */ nostrategy, 72 /* name */ "console", 73 /* maj */ CDEV_MAJOR, 74 /* dump */ nodump, 75 /* psize */ nopsize, 76 /* flags */ D_TTY, 77 /* bmaj */ -1 78}; 79 80static dev_t cn_dev_t; /* seems to be never really used */ 81static udev_t cn_udev_t; 82SYSCTL_OPAQUE(_machdep, CPU_CONSDEV, consdev, CTLFLAG_RD, 83 &cn_udev_t, sizeof cn_udev_t, "T,dev_t", ""); 84 85static int cn_mute; 86 87int cons_unavail = 0; /* XXX: 88 * physical console not available for 89 * input (i.e., it is in graphics mode) 90 */ 91 92static u_char cn_is_open; /* nonzero if logical console is open */ 93static int openmode, openflag; /* how /dev/console was openned */ 94static dev_t cn_devfsdev; /* represents the device private info */ 95static u_char cn_phys_is_open; /* nonzero if physical device is open */ 96static d_close_t *cn_phys_close; /* physical device close function */ 97static d_open_t *cn_phys_open; /* physical device open function */ 98 struct consdev *cn_tab; /* physical console device info */ 99 100CONS_DRIVER(cons, NULL, NULL, NULL, NULL, NULL, NULL, NULL); 101 102void 103cninit() 104{ 105 struct consdev *best_cp, *cp, **list; 106 107 /* 108 * Find the first console with the highest priority. 109 */ 110 best_cp = NULL; 111 list = (struct consdev **)cons_set.ls_items; 112 while ((cp = *list++) != NULL) { 113 if (cp->cn_probe == NULL) 114 continue; 115 (*cp->cn_probe)(cp); 116 if (cp->cn_pri > CN_DEAD && 117 (best_cp == NULL || cp->cn_pri > best_cp->cn_pri)) 118 best_cp = cp; 119 } 120 121 /* 122 * Check if we should mute the console (for security reasons perhaps) 123 * It can be changes dynamically using sysctl kern.consmute 124 * once we are up and going. 125 * 126 */ 127 cn_mute = ((boothowto & (RB_MUTE 128 |RB_SINGLE 129 |RB_VERBOSE 130 |RB_ASKNAME 131 |RB_CONFIG)) == RB_MUTE); 132 133 /* 134 * If no console, give up. 135 */ 136 if (best_cp == NULL) { 137 if (cn_tab != NULL && cn_tab->cn_term != NULL) 138 (*cn_tab->cn_term)(cn_tab); 139 cn_tab = best_cp; 140 return; 141 } 142 143 /* 144 * Initialize console, then attach to it. This ordering allows 145 * debugging using the previous console, if any. 146 */ 147 (*best_cp->cn_init)(best_cp); 148 if (cn_tab != NULL && cn_tab != best_cp) { 149 /* Turn off the previous console. */ 150 if (cn_tab->cn_term != NULL) 151 (*cn_tab->cn_term)(cn_tab); 152 } 153 cn_tab = best_cp; 154} 155 156void 157cninit_finish() 158{ 159 struct cdevsw *cdp; 160 161 if ((cn_tab == NULL) || cn_mute) 162 return; 163 164 /* 165 * Hook the open and close functions. 166 */ 167 cdp = devsw(cn_tab->cn_dev); 168 if (cdp != NULL) { 169 cn_phys_close = cdp->d_close; 170 cdp->d_close = cnclose; 171 cn_phys_open = cdp->d_open; 172 cdp->d_open = cnopen; 173 } 174 cn_dev_t = cn_tab->cn_dev; 175 cn_udev_t = dev2udev(cn_dev_t); 176} 177 178static void 179cnuninit(void) 180{ 181 struct cdevsw *cdp; 182 183 if (cn_tab == NULL) 184 return; 185 186 /* 187 * Unhook the open and close functions. 188 */ 189 cdp = devsw(cn_tab->cn_dev); 190 if (cdp != NULL) { 191 cdp->d_close = cn_phys_close; 192 cdp->d_open = cn_phys_open; 193 } 194 cn_phys_close = NULL; 195 cn_phys_open = NULL; 196 cn_dev_t = NODEV; 197 cn_udev_t = NOUDEV; 198} 199 200/* 201 * User has changed the state of the console muting. 202 * This may require us to open or close the device in question. 203 */ 204static int 205sysctl_kern_consmute(SYSCTL_HANDLER_ARGS) 206{ 207 int error; 208 int ocn_mute; 209 210 ocn_mute = cn_mute; 211 error = sysctl_handle_int(oidp, &cn_mute, 0, req); 212 if((error == 0) && (cn_tab != NULL) && (req->newptr != NULL)) { 213 if(ocn_mute && !cn_mute) { 214 /* 215 * going from muted to unmuted.. open the physical dev 216 * if the console has been openned 217 */ 218 cninit_finish(); 219 if(cn_is_open) 220 /* XXX curproc is not what we want really */ 221 error = cnopen(cn_dev_t, openflag, 222 openmode, curproc); 223 /* if it failed, back it out */ 224 if ( error != 0) cnuninit(); 225 } else if (!ocn_mute && cn_mute) { 226 /* 227 * going from unmuted to muted.. close the physical dev 228 * if it's only open via /dev/console 229 */ 230 if(cn_is_open) 231 error = cnclose(cn_dev_t, openflag, 232 openmode, curproc); 233 if ( error == 0) cnuninit(); 234 } 235 if (error != 0) { 236 /* 237 * back out the change if there was an error 238 */ 239 cn_mute = ocn_mute; 240 } 241 } 242 return (error); 243} 244 245SYSCTL_PROC(_kern, OID_AUTO, consmute, CTLTYPE_INT|CTLFLAG_RW, 246 0, sizeof cn_mute, sysctl_kern_consmute, "I", ""); 247 248static int 249cnopen(dev, flag, mode, p) 250 dev_t dev; 251 int flag, mode; 252 struct proc *p; 253{ 254 dev_t cndev, physdev; 255 int retval = 0; 256 257 if (cn_tab == NULL || cn_phys_open == NULL) 258 return (0); 259 cndev = cn_tab->cn_dev; 260 physdev = (major(dev) == major(cndev) ? dev : cndev); 261 /* 262 * If mute is active, then non console opens don't get here 263 * so we don't need to check for that. They 264 * bypass this and go straight to the device. 265 */ 266 if(!cn_mute) 267 retval = (*cn_phys_open)(physdev, flag, mode, p); 268 if (retval == 0) { 269 /* 270 * check if we openned it via /dev/console or 271 * via the physical entry (e.g. /dev/sio0). 272 */ 273 if (dev == cndev) 274 cn_phys_is_open = 1; 275 else if (physdev == cndev) { 276 openmode = mode; 277 openflag = flag; 278 cn_is_open = 1; 279 } 280 dev->si_tty = physdev->si_tty; 281 } 282 return (retval); 283} 284 285static int 286cnclose(dev, flag, mode, p) 287 dev_t dev; 288 int flag, mode; 289 struct proc *p; 290{ 291 dev_t cndev; 292 struct tty *cn_tp; 293 294 if (cn_tab == NULL || cn_phys_open == NULL) 295 return (0); 296 cndev = cn_tab->cn_dev; 297 cn_tp = cndev->si_tty; 298 /* 299 * act appropriatly depending on whether it's /dev/console 300 * or the pysical device (e.g. /dev/sio) that's being closed. 301 * in either case, don't actually close the device unless 302 * both are closed. 303 */ 304 if (dev == cndev) { 305 /* the physical device is about to be closed */ 306 cn_phys_is_open = 0; 307 if (cn_is_open) { 308 if (cn_tp) { 309 /* perform a ttyhalfclose() */ 310 /* reset session and proc group */ 311 cn_tp->t_pgrp = NULL; 312 cn_tp->t_session = NULL; 313 } 314 return (0); 315 } 316 } else if (major(dev) != major(cndev)) { 317 /* the logical console is about to be closed */ 318 cn_is_open = 0; 319 if (cn_phys_is_open) 320 return (0); 321 dev = cndev; 322 } 323 if(cn_phys_close) 324 return ((*cn_phys_close)(dev, flag, mode, p)); 325 return (0); 326} 327 328static int 329cnread(dev, uio, flag) 330 dev_t dev; 331 struct uio *uio; 332 int flag; 333{ 334 335 if (cn_tab == NULL || cn_phys_open == NULL) 336 return (0); 337 dev = cn_tab->cn_dev; 338 return ((*devsw(dev)->d_read)(dev, uio, flag)); 339} 340 341static int 342cnwrite(dev, uio, flag) 343 dev_t dev; 344 struct uio *uio; 345 int flag; 346{ 347 348 if (cn_tab == NULL || cn_phys_open == NULL) { 349 uio->uio_resid = 0; /* dump the data */ 350 return (0); 351 } 352 if (constty) 353 dev = constty->t_dev; 354 else 355 dev = cn_tab->cn_dev; 356 return ((*devsw(dev)->d_write)(dev, uio, flag)); 357} 358 359static int 360cnioctl(dev, cmd, data, flag, p) 361 dev_t dev; 362 u_long cmd; 363 caddr_t data; 364 int flag; 365 struct proc *p; 366{ 367 int error; 368 369 if (cn_tab == NULL || cn_phys_open == NULL) 370 return (0); 371 /* 372 * Superuser can always use this to wrest control of console 373 * output from the "virtual" console. 374 */ 375 if (cmd == TIOCCONS && constty) { 376 error = suser(p); 377 if (error) 378 return (error); 379 constty = NULL; 380 return (0); 381 } 382 dev = cn_tab->cn_dev; 383 return ((*devsw(dev)->d_ioctl)(dev, cmd, data, flag, p)); 384} 385 386static int 387cnpoll(dev, events, p) 388 dev_t dev; 389 int events; 390 struct proc *p; 391{ 392 if ((cn_tab == NULL) || cn_mute) 393 return (1); 394 395 dev = cn_tab->cn_dev; 396 397 return ((*devsw(dev)->d_poll)(dev, events, p)); 398} 399 400int 401cngetc() 402{ 403 int c; 404 if ((cn_tab == NULL) || cn_mute) 405 return (-1); 406 c = (*cn_tab->cn_getc)(cn_tab->cn_dev); 407 if (c == '\r') c = '\n'; /* console input is always ICRNL */ 408 return (c); 409} 410 411int 412cncheckc() 413{ 414 if ((cn_tab == NULL) || cn_mute) 415 return (-1); 416 return ((*cn_tab->cn_checkc)(cn_tab->cn_dev)); 417} 418 419void 420cnputc(c) 421 register int c; 422{ 423 if ((cn_tab == NULL) || cn_mute) 424 return; 425 if (c) { 426 if (c == '\n') 427 (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r'); 428 (*cn_tab->cn_putc)(cn_tab->cn_dev, c); 429 } 430} 431 432void 433cndbctl(on) 434 int on; 435{ 436 static int refcount; 437 438 if (cn_tab == NULL) 439 return; 440 if (!on) 441 refcount--; 442 if (refcount == 0 && cn_tab->cn_dbctl != NULL) 443 (*cn_tab->cn_dbctl)(cn_tab->cn_dev, on); 444 if (on) 445 refcount++; 446} 447 448static void 449cn_drvinit(void *unused) 450{ 451 452 cn_devfsdev = make_dev(&cn_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, 453 "console"); 454} 455 456SYSINIT(cndev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,cn_drvinit,NULL) 457