kern_cons.c revision 56525
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 56525 2000-01-24 11:48:11Z bde $ 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 cn_phys_close = cdp->d_close; 169 cdp->d_close = cnclose; 170 cn_phys_open = cdp->d_open; 171 cdp->d_open = cnopen; 172 cn_dev_t = cn_tab->cn_dev; 173 cn_udev_t = dev2udev(cn_dev_t); 174} 175 176static void 177cnuninit(void) 178{ 179 struct cdevsw *cdp; 180 181 if (cn_tab == NULL) 182 return; 183 184 /* 185 * Unhook the open and close functions. 186 */ 187 cdp = devsw(cn_tab->cn_dev); 188 cdp->d_close = cn_phys_close; 189 cn_phys_close = NULL; 190 cdp->d_open = cn_phys_open; 191 cn_phys_open = NULL; 192 cn_dev_t = NODEV; 193 cn_udev_t = NOUDEV; 194} 195 196/* 197 * User has changed the state of the console muting. 198 * This may require us to open or close the device in question. 199 */ 200static int 201sysctl_kern_consmute SYSCTL_HANDLER_ARGS 202{ 203 int error; 204 int ocn_mute; 205 206 ocn_mute = cn_mute; 207 error = sysctl_handle_int(oidp, &cn_mute, 0, req); 208 if((error == 0) && (cn_tab != NULL) && (req->newptr != NULL)) { 209 if(ocn_mute && !cn_mute) { 210 /* 211 * going from muted to unmuted.. open the physical dev 212 * if the console has been openned 213 */ 214 cninit_finish(); 215 if(cn_is_open) 216 /* XXX curproc is not what we want really */ 217 error = cnopen(cn_dev_t, openflag, 218 openmode, curproc); 219 /* if it failed, back it out */ 220 if ( error != 0) cnuninit(); 221 } else if (!ocn_mute && cn_mute) { 222 /* 223 * going from unmuted to muted.. close the physical dev 224 * if it's only open via /dev/console 225 */ 226 if(cn_is_open) 227 error = cnclose(cn_dev_t, openflag, 228 openmode, curproc); 229 if ( error == 0) cnuninit(); 230 } 231 if (error != 0) { 232 /* 233 * back out the change if there was an error 234 */ 235 cn_mute = ocn_mute; 236 } 237 } 238 return (error); 239} 240 241SYSCTL_PROC(_kern, OID_AUTO, consmute, CTLTYPE_INT|CTLFLAG_RW, 242 0, sizeof cn_mute, sysctl_kern_consmute, "I", ""); 243 244static int 245cnopen(dev, flag, mode, p) 246 dev_t dev; 247 int flag, mode; 248 struct proc *p; 249{ 250 dev_t cndev, physdev; 251 int retval = 0; 252 253 if (cn_tab == NULL) 254 return (0); 255 cndev = cn_tab->cn_dev; 256 physdev = (major(dev) == major(cndev) ? dev : cndev); 257 /* 258 * If mute is active, then non console opens don't get here 259 * so we don't need to check for that. They 260 * bypass this and go straight to the device. 261 */ 262 if(!cn_mute) 263 retval = (*cn_phys_open)(physdev, flag, mode, p); 264 if (retval == 0) { 265 /* 266 * check if we openned it via /dev/console or 267 * via the physical entry (e.g. /dev/sio0). 268 */ 269 if (dev == cndev) 270 cn_phys_is_open = 1; 271 else if (physdev == cndev) { 272 openmode = mode; 273 openflag = flag; 274 cn_is_open = 1; 275 } 276 dev->si_tty = physdev->si_tty; 277 } 278 return (retval); 279} 280 281static int 282cnclose(dev, flag, mode, p) 283 dev_t dev; 284 int flag, mode; 285 struct proc *p; 286{ 287 dev_t cndev; 288 struct tty *cn_tp; 289 290 if (cn_tab == NULL) 291 return (0); 292 cndev = cn_tab->cn_dev; 293 cn_tp = cndev->si_tty; 294 /* 295 * act appropriatly depending on whether it's /dev/console 296 * or the pysical device (e.g. /dev/sio) that's being closed. 297 * in either case, don't actually close the device unless 298 * both are closed. 299 */ 300 if (dev == cndev) { 301 /* the physical device is about to be closed */ 302 cn_phys_is_open = 0; 303 if (cn_is_open) { 304 if (cn_tp) { 305 /* perform a ttyhalfclose() */ 306 /* reset session and proc group */ 307 cn_tp->t_pgrp = NULL; 308 cn_tp->t_session = NULL; 309 } 310 return (0); 311 } 312 } else if (major(dev) != major(cndev)) { 313 /* the logical console is about to be closed */ 314 cn_is_open = 0; 315 if (cn_phys_is_open) 316 return (0); 317 dev = cndev; 318 } 319 if(cn_phys_close) 320 return ((*cn_phys_close)(dev, flag, mode, p)); 321 return (0); 322} 323 324static int 325cnread(dev, uio, flag) 326 dev_t dev; 327 struct uio *uio; 328 int flag; 329{ 330 if ((cn_tab == NULL) || cn_mute) 331 return (0); 332 dev = cn_tab->cn_dev; 333 return ((*devsw(dev)->d_read)(dev, uio, flag)); 334} 335 336static int 337cnwrite(dev, uio, flag) 338 dev_t dev; 339 struct uio *uio; 340 int flag; 341{ 342 if ((cn_tab == NULL) || cn_mute) { 343 uio->uio_resid = 0; /* dump the data */ 344 return (0); 345 } 346 if (constty) 347 dev = constty->t_dev; 348 else 349 dev = cn_tab->cn_dev; 350 return ((*devsw(dev)->d_write)(dev, uio, flag)); 351} 352 353static int 354cnioctl(dev, cmd, data, flag, p) 355 dev_t dev; 356 u_long cmd; 357 caddr_t data; 358 int flag; 359 struct proc *p; 360{ 361 int error; 362 363 if ((cn_tab == NULL) || cn_mute) 364 return (0); 365 /* 366 * Superuser can always use this to wrest control of console 367 * output from the "virtual" console. 368 */ 369 if (cmd == TIOCCONS && constty) { 370 error = suser(p); 371 if (error) 372 return (error); 373 constty = NULL; 374 return (0); 375 } 376 dev = cn_tab->cn_dev; 377 return ((*devsw(dev)->d_ioctl)(dev, cmd, data, flag, p)); 378} 379 380static int 381cnpoll(dev, events, p) 382 dev_t dev; 383 int events; 384 struct proc *p; 385{ 386 if ((cn_tab == NULL) || cn_mute) 387 return (1); 388 389 dev = cn_tab->cn_dev; 390 391 return ((*devsw(dev)->d_poll)(dev, events, p)); 392} 393 394int 395cngetc() 396{ 397 int c; 398 if ((cn_tab == NULL) || cn_mute) 399 return (-1); 400 c = (*cn_tab->cn_getc)(cn_tab->cn_dev); 401 if (c == '\r') c = '\n'; /* console input is always ICRNL */ 402 return (c); 403} 404 405int 406cncheckc() 407{ 408 if ((cn_tab == NULL) || cn_mute) 409 return (-1); 410 return ((*cn_tab->cn_checkc)(cn_tab->cn_dev)); 411} 412 413void 414cnputc(c) 415 register int c; 416{ 417 if ((cn_tab == NULL) || cn_mute) 418 return; 419 if (c) { 420 if (c == '\n') 421 (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r'); 422 (*cn_tab->cn_putc)(cn_tab->cn_dev, c); 423 } 424} 425 426void 427cndbctl(on) 428 int on; 429{ 430 static int refcount; 431 432 if (cn_tab == NULL) 433 return; 434 if (!on) 435 refcount--; 436 if (refcount == 0 && cn_tab->cn_dbctl != NULL) 437 (*cn_tab->cn_dbctl)(cn_tab->cn_dev, on); 438 if (on) 439 refcount++; 440} 441 442static void 443cn_drvinit(void *unused) 444{ 445 446 cn_devfsdev = make_dev(&cn_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, 447 "console"); 448} 449 450SYSINIT(cndev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,cn_drvinit,NULL) 451