The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/tty_cons.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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$
   40  */
   41 
   42 #include "opt_ddb.h"
   43 
   44 #include <sys/param.h>
   45 #include <sys/systm.h>
   46 #include <sys/conf.h>
   47 #include <sys/cons.h>
   48 #include <sys/kernel.h>
   49 #include <sys/proc.h>
   50 #include <sys/reboot.h>
   51 #include <sys/sysctl.h>
   52 #include <sys/tty.h>
   53 #include <sys/uio.h>
   54 
   55 #include <ddb/ddb.h>
   56 
   57 #include <machine/cpu.h>
   58 
   59 static  d_open_t        cnopen;
   60 static  d_close_t       cnclose;
   61 static  d_read_t        cnread;
   62 static  d_write_t       cnwrite;
   63 static  d_ioctl_t       cnioctl;
   64 static  d_poll_t        cnpoll;
   65 static  d_kqfilter_t    cnkqfilter;
   66 
   67 #define CDEV_MAJOR      0
   68 static struct cdevsw cn_cdevsw = {
   69         /* open */      cnopen,
   70         /* close */     cnclose,
   71         /* read */      cnread,
   72         /* write */     cnwrite,
   73         /* ioctl */     cnioctl,
   74         /* poll */      cnpoll,
   75         /* mmap */      nommap,
   76         /* strategy */  nostrategy,
   77         /* name */      "console",
   78         /* maj */       CDEV_MAJOR,
   79         /* dump */      nodump,
   80         /* psize */     nopsize,
   81         /* flags */     D_TTY | D_KQFILTER,
   82         /* bmaj */      -1,
   83         /* kqfilter */  cnkqfilter,
   84 };
   85 
   86 static dev_t    cn_dev_t;       /* seems to be never really used */
   87 static udev_t   cn_udev_t;
   88 SYSCTL_OPAQUE(_machdep, CPU_CONSDEV, consdev, CTLFLAG_RD,
   89         &cn_udev_t, sizeof cn_udev_t, "T,dev_t", "");
   90 
   91 static int cn_mute;
   92 
   93 int     cons_unavail = 0;       /* XXX:
   94                                  * physical console not available for
   95                                  * input (i.e., it is in graphics mode)
   96                                  */
   97 
   98 static u_char cn_is_open;               /* nonzero if logical console is open */
   99 static int openmode, openflag;          /* how /dev/console was openned */
  100 static dev_t cn_devfsdev;               /* represents the device private info */
  101 static u_char cn_phys_is_open;          /* nonzero if physical device is open */
  102 static d_close_t *cn_phys_close;        /* physical device close function */
  103 static d_open_t *cn_phys_open;          /* physical device open function */
  104        struct consdev *cn_tab;          /* physical console device info */
  105 static u_char console_pausing;          /* pause after each line during probe */
  106 static char *console_pausestr=
  107 "<pause; press any key to proceed to next line or '.' to end pause mode>";
  108 
  109 CONS_DRIVER(cons, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
  110 
  111 void
  112 cninit()
  113 {
  114         struct consdev *best_cp, *cp, **list;
  115 
  116         /*
  117          * Find the first console with the highest priority.
  118          */
  119         best_cp = NULL;
  120         list = (struct consdev **)cons_set.ls_items;
  121         while ((cp = *list++) != NULL) {
  122                 if (cp->cn_probe == NULL)
  123                         continue;
  124                 (*cp->cn_probe)(cp);
  125                 if (cp->cn_pri > CN_DEAD &&
  126                     (best_cp == NULL || cp->cn_pri > best_cp->cn_pri))
  127                         best_cp = cp;
  128         }
  129 
  130         /*
  131          * Check if we should mute the console (for security reasons perhaps)
  132          * It can be changes dynamically using sysctl kern.consmute
  133          * once we are up and going.
  134          * 
  135          */
  136         cn_mute = ((boothowto & (RB_MUTE
  137                         |RB_SINGLE
  138                         |RB_VERBOSE
  139                         |RB_ASKNAME
  140                         |RB_CONFIG)) == RB_MUTE);
  141         
  142         /*
  143          * If no console, give up.
  144          */
  145         if (best_cp == NULL) {
  146                 if (cn_tab != NULL && cn_tab->cn_term != NULL)
  147                         (*cn_tab->cn_term)(cn_tab);
  148                 cn_tab = best_cp;
  149                 return;
  150         }
  151 
  152         /*
  153          * Initialize console, then attach to it.  This ordering allows
  154          * debugging using the previous console, if any.
  155          */
  156         (*best_cp->cn_init)(best_cp);
  157         if (cn_tab != NULL && cn_tab != best_cp) {
  158                 /* Turn off the previous console.  */
  159                 if (cn_tab->cn_term != NULL)
  160                         (*cn_tab->cn_term)(cn_tab);
  161         }
  162         if (boothowto & RB_PAUSE)
  163                 console_pausing = 1;
  164         cn_tab = best_cp;
  165 }
  166 
  167 void
  168 cninit_finish()
  169 {
  170         struct cdevsw *cdp;
  171 
  172         if ((cn_tab == NULL) || cn_mute)
  173                 return;
  174 
  175         /*
  176          * Hook the open and close functions.
  177          */
  178         cdp = devsw(cn_tab->cn_dev);
  179         if (cdp != NULL) {
  180                 cn_phys_close = cdp->d_close;
  181                 cdp->d_close = cnclose;
  182                 cn_phys_open = cdp->d_open;
  183                 cdp->d_open = cnopen;
  184         }
  185         cn_dev_t = cn_tab->cn_dev;
  186         cn_udev_t = dev2udev(cn_dev_t);
  187         console_pausing = 0;
  188 }
  189 
  190 static void
  191 cnuninit(void)
  192 {
  193         struct cdevsw *cdp;
  194 
  195         if (cn_tab == NULL)
  196                 return;
  197 
  198         /*
  199          * Unhook the open and close functions.
  200          */
  201         cdp = devsw(cn_tab->cn_dev);
  202         if (cdp != NULL) {
  203                 cdp->d_close = cn_phys_close;
  204                 cdp->d_open = cn_phys_open;
  205         }
  206         cn_phys_close = NULL;
  207         cn_phys_open = NULL;
  208         cn_dev_t = NODEV;
  209         cn_udev_t = NOUDEV;
  210 }
  211 
  212 /*
  213  * User has changed the state of the console muting.
  214  * This may require us to open or close the device in question.
  215  */
  216 static int
  217 sysctl_kern_consmute(SYSCTL_HANDLER_ARGS)
  218 {
  219         int error;
  220         int ocn_mute;
  221 
  222         ocn_mute = cn_mute;
  223         error = sysctl_handle_int(oidp, &cn_mute, 0, req);
  224         if((error == 0) && (cn_tab != NULL) && (req->newptr != NULL)) {
  225                 if(ocn_mute && !cn_mute) {
  226                         /*
  227                          * going from muted to unmuted.. open the physical dev 
  228                          * if the console has been openned
  229                          */
  230                         cninit_finish();
  231                         if(cn_is_open)
  232                                 /* XXX curproc is not what we want really */
  233                                 error = cnopen(cn_dev_t, openflag,
  234                                         openmode, curproc);
  235                         /* if it failed, back it out */
  236                         if ( error != 0) cnuninit();
  237                 } else if (!ocn_mute && cn_mute) {
  238                         /*
  239                          * going from unmuted to muted.. close the physical dev 
  240                          * if it's only open via /dev/console
  241                          */
  242                         if(cn_is_open)
  243                                 error = cnclose(cn_dev_t, openflag,
  244                                         openmode, curproc);
  245                         if ( error == 0) cnuninit();
  246                 }
  247                 if (error != 0) {
  248                         /* 
  249                          * back out the change if there was an error
  250                          */
  251                         cn_mute = ocn_mute;
  252                 }
  253         }
  254         return (error);
  255 }
  256 
  257 SYSCTL_PROC(_kern, OID_AUTO, consmute, CTLTYPE_INT|CTLFLAG_RW,
  258         0, sizeof cn_mute, sysctl_kern_consmute, "I", "");
  259 
  260 static int
  261 cnopen(dev, flag, mode, p)
  262         dev_t dev;
  263         int flag, mode;
  264         struct proc *p;
  265 {
  266         dev_t cndev, physdev;
  267         int retval = 0;
  268 
  269         if (cn_tab == NULL || cn_phys_open == NULL)
  270                 return (0);
  271         cndev = cn_tab->cn_dev;
  272         physdev = (major(dev) == major(cndev) ? dev : cndev);
  273         /*
  274          * If mute is active, then non console opens don't get here
  275          * so we don't need to check for that. They 
  276          * bypass this and go straight to the device.
  277          */
  278         if(!cn_mute)
  279                 retval = (*cn_phys_open)(physdev, flag, mode, p);
  280         if (retval == 0) {
  281                 /* 
  282                  * check if we openned it via /dev/console or 
  283                  * via the physical entry (e.g. /dev/sio0).
  284                  */
  285                 if (dev == cndev)
  286                         cn_phys_is_open = 1;
  287                 else if (physdev == cndev) {
  288                         openmode = mode;
  289                         openflag = flag;
  290                         cn_is_open = 1;
  291                 }
  292                 dev->si_tty = physdev->si_tty;
  293         }
  294         return (retval);
  295 }
  296 
  297 static int
  298 cnclose(dev, flag, mode, p)
  299         dev_t dev;
  300         int flag, mode;
  301         struct proc *p;
  302 {
  303         dev_t cndev;
  304         struct tty *cn_tp;
  305 
  306         if (cn_tab == NULL || cn_phys_open == NULL)
  307                 return (0);
  308         cndev = cn_tab->cn_dev;
  309         cn_tp = cndev->si_tty;
  310         /*
  311          * act appropriatly depending on whether it's /dev/console
  312          * or the pysical device (e.g. /dev/sio) that's being closed.
  313          * in either case, don't actually close the device unless
  314          * both are closed.
  315          */
  316         if (dev == cndev) {
  317                 /* the physical device is about to be closed */
  318                 cn_phys_is_open = 0;
  319                 if (cn_is_open) {
  320                         if (cn_tp) {
  321                                 /* perform a ttyhalfclose() */
  322                                 /* reset session and proc group */
  323                                 cn_tp->t_pgrp = NULL;
  324                                 cn_tp->t_session = NULL;
  325                         }
  326                         return (0);
  327                 }
  328         } else if (major(dev) != major(cndev)) {
  329                 /* the logical console is about to be closed */
  330                 cn_is_open = 0;
  331                 if (cn_phys_is_open)
  332                         return (0);
  333                 dev = cndev;
  334         }
  335         if(cn_phys_close)
  336                 return ((*cn_phys_close)(dev, flag, mode, p));
  337         return (0);
  338 }
  339 
  340 static int
  341 cnread(dev, uio, flag)
  342         dev_t dev;
  343         struct uio *uio;
  344         int flag;
  345 {
  346 
  347         if (cn_tab == NULL || cn_phys_open == NULL)
  348                 return (0);
  349         dev = cn_tab->cn_dev;
  350         return ((*devsw(dev)->d_read)(dev, uio, flag));
  351 }
  352 
  353 static int
  354 cnwrite(dev, uio, flag)
  355         dev_t dev;
  356         struct uio *uio;
  357         int flag;
  358 {
  359 
  360         if (cn_tab == NULL || cn_phys_open == NULL) {
  361                 uio->uio_resid = 0; /* dump the data */
  362                 return (0);
  363         }
  364         if (constty)
  365                 dev = constty->t_dev;
  366         else
  367                 dev = cn_tab->cn_dev;
  368         log_console(uio);
  369         return ((*devsw(dev)->d_write)(dev, uio, flag));
  370 }
  371 
  372 static int
  373 cnioctl(dev, cmd, data, flag, p)
  374         dev_t dev;
  375         u_long cmd;
  376         caddr_t data;
  377         int flag;
  378         struct proc *p;
  379 {
  380         int error;
  381 
  382         if (cn_tab == NULL || cn_phys_open == NULL)
  383                 return (0);
  384         /*
  385          * Superuser can always use this to wrest control of console
  386          * output from the "virtual" console.
  387          */
  388         if (cmd == TIOCCONS && constty) {
  389                 error = suser(p);
  390                 if (error)
  391                         return (error);
  392                 constty = NULL;
  393                 return (0);
  394         }
  395         dev = cn_tab->cn_dev;
  396         return ((*devsw(dev)->d_ioctl)(dev, cmd, data, flag, p));
  397 }
  398 
  399 static int
  400 cnpoll(dev, events, p)
  401         dev_t dev;
  402         int events;
  403         struct proc *p;
  404 {
  405         if ((cn_tab == NULL) || cn_mute)
  406                 return (1);
  407 
  408         dev = cn_tab->cn_dev;
  409 
  410         return ((*devsw(dev)->d_poll)(dev, events, p));
  411 }
  412 
  413 static int
  414 cnkqfilter(dev, kn)
  415         dev_t dev;
  416         struct knote *kn;
  417 {
  418         if ((cn_tab == NULL) || cn_mute)
  419                 return (1);
  420 
  421         dev = cn_tab->cn_dev;
  422         if (devsw(dev)->d_flags & D_KQFILTER)
  423                 return ((*devsw(dev)->d_kqfilter)(dev, kn));
  424         return (1);
  425 }
  426 
  427 int
  428 cngetc()
  429 {
  430         int c;
  431         if ((cn_tab == NULL) || cn_mute)
  432                 return (-1);
  433         c = (*cn_tab->cn_getc)(cn_tab->cn_dev);
  434         if (c == '\r') c = '\n'; /* console input is always ICRNL */
  435         return (c);
  436 }
  437 
  438 int
  439 cncheckc()
  440 {
  441         if ((cn_tab == NULL) || cn_mute)
  442                 return (-1);
  443         return ((*cn_tab->cn_checkc)(cn_tab->cn_dev));
  444 }
  445 
  446 void
  447 cnputc(c)
  448         register int c;
  449 {
  450         char *cp;
  451 
  452         if ((cn_tab == NULL) || cn_mute)
  453                 return;
  454         if (c) {
  455                 if (c == '\n')
  456                         (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
  457                 (*cn_tab->cn_putc)(cn_tab->cn_dev, c);
  458 #ifdef DDB
  459                 if (console_pausing && !db_active && (c == '\n')) {
  460 #else
  461                 if (console_pausing && (c == '\n')) {
  462 #endif
  463                         for(cp=console_pausestr; *cp != '\0'; cp++)
  464                             (*cn_tab->cn_putc)(cn_tab->cn_dev, *cp);
  465                         if (cngetc() == '.')
  466                                 console_pausing = 0;
  467                         (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
  468                         for(cp=console_pausestr; *cp != '\0'; cp++)
  469                             (*cn_tab->cn_putc)(cn_tab->cn_dev, ' ');
  470                         (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
  471                 }
  472         }
  473 }
  474 
  475 void
  476 cndbctl(on)
  477         int on;
  478 {
  479         static int refcount;
  480 
  481         if (cn_tab == NULL)
  482                 return;
  483         if (!on)
  484                 refcount--;
  485         if (refcount == 0 && cn_tab->cn_dbctl != NULL)
  486                 (*cn_tab->cn_dbctl)(cn_tab->cn_dev, on);
  487         if (on)
  488                 refcount++;
  489 }
  490 
  491 static void
  492 cn_drvinit(void *unused)
  493 {
  494 
  495         cn_devfsdev = make_dev(&cn_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
  496             "console");
  497 }
  498 
  499 SYSINIT(cndev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,cn_drvinit,NULL)

Cache object: 7e922ffae240acd2ef471d222db2fe74


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.