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.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 /*      $OpenBSD: tty.c,v 1.176 2022/08/14 01:58:28 jsg Exp $   */
    2 /*      $NetBSD: tty.c,v 1.68.4.2 1996/06/06 16:04:52 thorpej Exp $     */
    3 
    4 /*-
    5  * Copyright (c) 1982, 1986, 1990, 1991, 1993
    6  *      The Regents of the University of California.  All rights reserved.
    7  * (c) UNIX System Laboratories, Inc.
    8  * All or some portions of this file are derived from material licensed
    9  * to the University of California by American Telephone and Telegraph
   10  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
   11  * the permission of UNIX System Laboratories, Inc.
   12  *
   13  * Redistribution and use in source and binary forms, with or without
   14  * modification, are permitted provided that the following conditions
   15  * are met:
   16  * 1. Redistributions of source code must retain the above copyright
   17  *    notice, this list of conditions and the following disclaimer.
   18  * 2. Redistributions in binary form must reproduce the above copyright
   19  *    notice, this list of conditions and the following disclaimer in the
   20  *    documentation and/or other materials provided with the distribution.
   21  * 3. Neither the name of the University nor the names of its contributors
   22  *    may be used to endorse or promote products derived from this software
   23  *    without specific prior written permission.
   24  *
   25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   35  * SUCH DAMAGE.
   36  *
   37  *      @(#)tty.c       8.8 (Berkeley) 1/21/94
   38  */
   39 
   40 #include <sys/param.h>
   41 #include <sys/systm.h>
   42 #include <sys/ioctl.h>
   43 #include <sys/proc.h>
   44 #define TTYDEFCHARS
   45 #include <sys/tty.h>
   46 #undef  TTYDEFCHARS
   47 #include <sys/fcntl.h>
   48 #include <sys/conf.h>
   49 #include <sys/uio.h>
   50 #include <sys/kernel.h>
   51 #include <sys/vnode.h>
   52 #include <sys/lock.h>
   53 #include <sys/malloc.h>
   54 #include <sys/msgbuf.h>
   55 #include <sys/signalvar.h>
   56 #include <sys/resourcevar.h>
   57 #include <sys/sysctl.h>
   58 #include <sys/pool.h>
   59 #include <sys/unistd.h>
   60 #include <sys/pledge.h>
   61 
   62 #include <sys/namei.h>
   63 
   64 #include <uvm/uvm_extern.h>
   65 
   66 #include <dev/cons.h>
   67 
   68 #include "pty.h"
   69 
   70 static int ttnread(struct tty *);
   71 static void ttyblock(struct tty *);
   72 void ttyunblock(struct tty *);
   73 static void ttyecho(int, struct tty *);
   74 static void ttyrubo(struct tty *, int);
   75 int     filt_ttyread(struct knote *kn, long hint);
   76 void    filt_ttyrdetach(struct knote *kn);
   77 int     filt_ttywrite(struct knote *kn, long hint);
   78 void    filt_ttywdetach(struct knote *kn);
   79 int     filt_ttyexcept(struct knote *kn, long hint);
   80 void    ttystats_init(struct itty **, int *, size_t *);
   81 int     ttywait_nsec(struct tty *, uint64_t);
   82 int     ttysleep_nsec(struct tty *, void *, int, char *, uint64_t);
   83 
   84 /* Symbolic sleep message strings. */
   85 char ttclos[]   = "ttycls";
   86 char ttopen[]   = "ttyopn";
   87 char ttybg[]    = "ttybg";
   88 char ttyin[]    = "ttyin";
   89 char ttyout[]   = "ttyout";
   90 
   91 /*
   92  * Table with character classes and parity. The 8th bit indicates parity,
   93  * the 7th bit indicates the character is an alphameric or underscore (for
   94  * ALTWERASE), and the low 6 bits indicate delay type.  If the low 6 bits
   95  * are 0 then the character needs no special processing on output; classes
   96  * other than 0 might be translated or (not currently) require delays.
   97  */
   98 #define E       0x00    /* Even parity. */
   99 #define O       0x80    /* Odd parity. */
  100 #define PARITY(c)       (char_type[c] & O)
  101 
  102 #define ALPHA   0x40    /* Alpha or underscore. */
  103 #define ISALPHA(c)      (char_type[(c) & TTY_CHARMASK] & ALPHA)
  104 
  105 #define CCLASSMASK      0x3f
  106 #define CCLASS(c)       (char_type[c] & CCLASSMASK)
  107 
  108 #define BS      BACKSPACE
  109 #define CC      CONTROL
  110 #define CR      RETURN
  111 #define NA      ORDINARY | ALPHA
  112 #define NL      NEWLINE
  113 #define NO      ORDINARY
  114 #define TB      TAB
  115 #define VT      VTAB
  116 
  117 u_char const char_type[] = {
  118         E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* nul - bel */
  119         O|BS, E|TB, E|NL, O|CC, E|VT, O|CR, O|CC, E|CC, /* bs - si */
  120         O|CC, E|CC, E|CC, O|CC, E|CC, O|CC, O|CC, E|CC, /* dle - etb */
  121         E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* can - us */
  122         O|NO, E|NO, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* sp - ' */
  123         E|NO, O|NO, O|NO, E|NO, O|NO, E|NO, E|NO, O|NO, /* ( - / */
  124         E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* 0 - 7 */
  125         O|NA, E|NA, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* 8 - ? */
  126         O|NO, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* @ - G */
  127         E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* H - O */
  128         E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* P - W */
  129         O|NA, E|NA, E|NA, O|NO, E|NO, O|NO, O|NO, O|NA, /* X - _ */
  130         E|NO, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* ` - g */
  131         O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* h - o */
  132         O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* p - w */
  133         E|NA, O|NA, O|NA, E|NO, O|NO, E|NO, E|NO, O|CC, /* x - del */
  134         /*
  135          * Meta chars; should be settable per character set;
  136          * for now, treat them all as normal characters.
  137          */
  138         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  139         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  140         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  141         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  142         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  143         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  144         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  145         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  146         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  147         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  148         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  149         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  150         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  151         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  152         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  153         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  154 };
  155 #undef  BS
  156 #undef  CC
  157 #undef  CR
  158 #undef  NA
  159 #undef  NL
  160 #undef  NO
  161 #undef  TB
  162 #undef  VT
  163 
  164 #define islower(c)      ((c) >= 'a' && (c) <= 'z')
  165 #define isupper(c)      ((c) >= 'A' && (c) <= 'Z')
  166 
  167 #define tolower(c)      ((c) - 'A' + 'a')
  168 #define toupper(c)      ((c) - 'a' + 'A')
  169 
  170 struct ttylist_head ttylist;    /* TAILQ_HEAD */
  171 int tty_count;
  172 struct rwlock ttylist_lock = RWLOCK_INITIALIZER("ttylist");
  173 
  174 int64_t tk_cancc, tk_nin, tk_nout, tk_rawcc;
  175 
  176 /*
  177  * Initial open of tty, or (re)entry to standard tty line discipline.
  178  */
  179 int
  180 ttyopen(dev_t device, struct tty *tp, struct proc *p)
  181 {
  182         int s;
  183 
  184         s = spltty();
  185         tp->t_dev = device;
  186         if (!ISSET(tp->t_state, TS_ISOPEN)) {
  187                 SET(tp->t_state, TS_ISOPEN);
  188                 memset(&tp->t_winsize, 0, sizeof(tp->t_winsize));
  189                 tp->t_column = 0;
  190         }
  191         CLR(tp->t_state, TS_WOPEN);
  192         splx(s);
  193         return (0);
  194 }
  195 
  196 /*
  197  * Handle close() on a tty line: flush and set to initial state,
  198  * bumping generation number so that pending read/write calls
  199  * can detect recycling of the tty.
  200  */
  201 int
  202 ttyclose(struct tty *tp)
  203 {
  204         if (constty == tp)
  205                 constty = NULL;
  206 
  207         ttyflush(tp, FREAD | FWRITE);
  208 
  209         tp->t_gen++;
  210         tp->t_pgrp = NULL;
  211         if (tp->t_session)
  212                 SESSRELE(tp->t_session);
  213         tp->t_session = NULL;
  214         tp->t_state = 0;
  215         return (0);
  216 }
  217 
  218 #define FLUSHQ(q) {                                                     \
  219         if ((q)->c_cc)                                                  \
  220                 ndflush(q, (q)->c_cc);                                  \
  221 }
  222 
  223 /* Is 'c' a line delimiter ("break" character)? */
  224 #define TTBREAKC(c, lflag)                                              \
  225         ((c) == '\n' || (((c) == cc[VEOF] || (c) == cc[VEOL] ||         \
  226         ((c) == cc[VEOL2] && (lflag & IEXTEN))) && (c) != _POSIX_VDISABLE))
  227 
  228 
  229 /*
  230  * Process input of a single character received on a tty.  Returns 0 normally,
  231  * 1 if a costly operation was reached.
  232  */
  233 int
  234 ttyinput(int c, struct tty *tp)
  235 {
  236         int iflag, lflag;
  237         u_char *cc;
  238         int i, error, ret = 0;
  239         int s;
  240 
  241         enqueue_randomness(tp->t_dev << 8 | c);
  242         /*
  243          * If receiver is not enabled, drop it.
  244          */
  245         if (!ISSET(tp->t_cflag, CREAD))
  246                 return (0);
  247 
  248         /*
  249          * If input is pending take it first.
  250          */
  251         lflag = tp->t_lflag;
  252         s = spltty();
  253         if (ISSET(lflag, PENDIN))
  254                 ttypend(tp);
  255         splx(s);
  256         /*
  257          * Gather stats.
  258          */
  259         if (ISSET(lflag, ICANON)) {
  260                 ++tk_cancc;
  261                 ++tp->t_cancc;
  262         } else {
  263                 ++tk_rawcc;
  264                 ++tp->t_rawcc;
  265         }
  266         ++tk_nin;
  267 
  268         /* Handle exceptional conditions (break, parity, framing). */
  269         cc = tp->t_cc;
  270         iflag = tp->t_iflag;
  271         if ((error = (ISSET(c, TTY_ERRORMASK))) != 0) {
  272                 CLR(c, TTY_ERRORMASK);
  273                 if (ISSET(error, TTY_FE) && !c) {       /* Break. */
  274                         if (ISSET(iflag, IGNBRK))
  275                                 return (0);
  276                         ttyflush(tp, FREAD | FWRITE);
  277                         if (ISSET(iflag, BRKINT)) {
  278                             pgsignal(tp->t_pgrp, SIGINT, 1);
  279                             goto endcase;
  280                         }
  281                         else if (ISSET(iflag, PARMRK))
  282                                 goto parmrk;
  283                 } else if ((ISSET(error, TTY_PE) && ISSET(iflag, INPCK)) ||
  284                     ISSET(error, TTY_FE)) {
  285                         if (ISSET(iflag, IGNPAR))
  286                                 goto endcase;
  287                         else if (ISSET(iflag, PARMRK)) {
  288 parmrk:                         (void)putc(0377 | TTY_QUOTE, &tp->t_rawq);
  289                                 if (ISSET(iflag, ISTRIP) || c != 0377)
  290                                         (void)putc(0 | TTY_QUOTE, &tp->t_rawq);
  291                                 (void)putc(c | TTY_QUOTE, &tp->t_rawq);
  292                                 goto endcase;
  293                         } else
  294                                 c = 0;
  295                 }
  296         }
  297         if (c == 0377 && !ISSET(iflag, ISTRIP) && ISSET(iflag, PARMRK))
  298                 goto parmrk;
  299 
  300         /*
  301          * In tandem mode, check high water mark.
  302          */
  303         if (ISSET(iflag, IXOFF) || ISSET(tp->t_cflag, CHWFLOW))
  304                 ttyblock(tp);
  305         if (!ISSET(tp->t_state, TS_TYPEN) && ISSET(iflag, ISTRIP))
  306                 CLR(c, 0x80);
  307         if (!ISSET(lflag, EXTPROC)) {
  308                 /*
  309                  * Check for literal nexting very first
  310                  */
  311                 if (ISSET(tp->t_state, TS_LNCH)) {
  312                         SET(c, TTY_QUOTE);
  313                         CLR(tp->t_state, TS_LNCH);
  314                 }
  315                 /*
  316                  * Scan for special characters.  This code
  317                  * is really just a big case statement with
  318                  * non-constant cases.  The bottom of the
  319                  * case statement is labeled ``endcase'', so goto
  320                  * it after a case match, or similar.
  321                  */
  322 
  323                 /*
  324                  * Control chars which aren't controlled
  325                  * by ICANON, ISIG, or IXON.
  326                  */
  327                 if (ISSET(lflag, IEXTEN)) {
  328                         if (CCEQ(cc[VLNEXT], c)) {
  329                                 if (ISSET(lflag, ECHO)) {
  330                                         if (ISSET(lflag, ECHOE)) {
  331                                                 (void)ttyoutput('^', tp);
  332                                                 (void)ttyoutput('\b', tp);
  333                                         } else
  334                                                 ttyecho(c, tp);
  335                                 }
  336                                 SET(tp->t_state, TS_LNCH);
  337                                 goto endcase;
  338                         }
  339                         if (CCEQ(cc[VDISCARD], c)) {
  340                                 if (ISSET(lflag, FLUSHO))
  341                                         CLR(tp->t_lflag, FLUSHO);
  342                                 else {
  343                                         ttyflush(tp, FWRITE);
  344                                         ttyecho(c, tp);
  345                                         if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
  346                                                 ret = ttyretype(tp);
  347                                         SET(tp->t_lflag, FLUSHO);
  348                                 }
  349                                 goto startoutput;
  350                         }
  351                 }
  352                 /*
  353                  * Signals.
  354                  */
  355                 if (ISSET(lflag, ISIG)) {
  356                         if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) {
  357                                 if (!ISSET(lflag, NOFLSH))
  358                                         ttyflush(tp, FREAD | FWRITE);
  359                                 ttyecho(c, tp);
  360                                 pgsignal(tp->t_pgrp,
  361                                     CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1);
  362                                 goto endcase;
  363                         }
  364                         if (CCEQ(cc[VSUSP], c)) {
  365                                 if (!ISSET(lflag, NOFLSH))
  366                                         ttyflush(tp, FREAD);
  367                                 ttyecho(c, tp);
  368                                 pgsignal(tp->t_pgrp, SIGTSTP, 1);
  369                                 goto endcase;
  370                         }
  371                 }
  372                 /*
  373                  * Handle start/stop characters.
  374                  */
  375                 if (ISSET(iflag, IXON)) {
  376                         if (CCEQ(cc[VSTOP], c)) {
  377                                 if (!ISSET(tp->t_state, TS_TTSTOP)) {
  378                                         SET(tp->t_state, TS_TTSTOP);
  379                                         (*cdevsw[major(tp->t_dev)].d_stop)(tp,
  380                                            0);
  381                                         return (0);
  382                                 }
  383                                 if (!CCEQ(cc[VSTART], c))
  384                                         return (0);
  385                                 /*
  386                                  * if VSTART == VSTOP then toggle
  387                                  */
  388                                 goto endcase;
  389                         }
  390                         if (CCEQ(cc[VSTART], c))
  391                                 goto restartoutput;
  392                 }
  393                 /*
  394                  * IGNCR, ICRNL, & INLCR
  395                  */
  396                 if (c == '\r') {
  397                         if (ISSET(iflag, IGNCR))
  398                                 goto endcase;
  399                         else if (ISSET(iflag, ICRNL))
  400                                 c = '\n';
  401                 } else if (c == '\n' && ISSET(iflag, INLCR))
  402                         c = '\r';
  403         }
  404         if (!ISSET(tp->t_lflag, EXTPROC) && ISSET(lflag, ICANON)) {
  405                 /*
  406                  * From here on down canonical mode character
  407                  * processing takes place.
  408                  */
  409                 /*
  410                  * upper case or specials with IUCLC and XCASE
  411                  */
  412                 if (ISSET(lflag, XCASE) && ISSET(iflag, IUCLC)) {
  413                         if (ISSET(tp->t_state, TS_BKSL)) {
  414                                 CLR(tp->t_state, TS_BKSL);
  415                                 switch (c) {
  416                                 case '\'':
  417                                         c = '`';
  418                                         break;
  419                                 case '!':
  420                                         c = '|';
  421                                         break;
  422                                 case '^':
  423                                         c = '~';
  424                                         break;
  425                                 case '(':
  426                                         c = '{';
  427                                         break;
  428                                 case ')':
  429                                         c = '}';
  430                                         break;
  431                                 }
  432                         }
  433                         else if (c == '\\') {
  434                                 SET(tp->t_state, TS_BKSL);
  435                                 goto endcase;
  436                         }
  437                         else if (isupper(c))
  438                                 c = tolower(c);
  439                 }
  440                 else if (ISSET(iflag, IUCLC) && isupper(c))
  441                         c = tolower(c);
  442                 /*
  443                  * erase (^H / ^?)
  444                  */
  445                 if (CCEQ(cc[VERASE], c)) {
  446                         if (tp->t_rawq.c_cc)
  447                                 ret = ttyrub(unputc(&tp->t_rawq), tp);
  448                         goto endcase;
  449                 }
  450                 /*
  451                  * kill (^U)
  452                  */
  453                 if (CCEQ(cc[VKILL], c)) {
  454                         if (ISSET(lflag, ECHOKE) &&
  455                             tp->t_rawq.c_cc == tp->t_rocount &&
  456                             !ISSET(lflag, ECHOPRT)) {
  457                                 while (tp->t_rawq.c_cc)
  458                                         if (ttyrub(unputc(&tp->t_rawq), tp))
  459                                                 ret = 1;
  460                         } else {
  461                                 ttyecho(c, tp);
  462                                 if (ISSET(lflag, ECHOK) ||
  463                                     ISSET(lflag, ECHOKE))
  464                                         ttyecho('\n', tp);
  465                                 FLUSHQ(&tp->t_rawq);
  466                                 tp->t_rocount = 0;
  467                         }
  468                         CLR(tp->t_state, TS_LOCAL);
  469                         goto endcase;
  470                 }
  471                 /*
  472                  * word erase (^W)
  473                  */
  474                 if (CCEQ(cc[VWERASE], c) && ISSET(lflag, IEXTEN)) {
  475                         int alt = ISSET(lflag, ALTWERASE);
  476                         int ctype;
  477 
  478                         /*
  479                          * erase whitespace
  480                          */
  481                         while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t')
  482                                 if (ttyrub(c, tp))
  483                                         ret = 1;
  484                         if (c == -1)
  485                                 goto endcase;
  486                         /*
  487                          * erase last char of word and remember the
  488                          * next chars type (for ALTWERASE)
  489                          */
  490                         if (ttyrub(c, tp))
  491                                 ret = 1;
  492                         c = unputc(&tp->t_rawq);
  493                         if (c == -1)
  494                                 goto endcase;
  495                         if (c == ' ' || c == '\t') {
  496                                 (void)putc(c, &tp->t_rawq);
  497                                 goto endcase;
  498                         }
  499                         ctype = ISALPHA(c);
  500                         /*
  501                          * erase rest of word
  502                          */
  503                         do {
  504                                 if (ttyrub(c, tp))
  505                                         ret = 1;
  506                                 c = unputc(&tp->t_rawq);
  507                                 if (c == -1)
  508                                         goto endcase;
  509                         } while (c != ' ' && c != '\t' &&
  510                             (alt == 0 || ISALPHA(c) == ctype));
  511                         (void)putc(c, &tp->t_rawq);
  512                         goto endcase;
  513                 }
  514                 /*
  515                  * reprint line (^R)
  516                  */
  517                 if (CCEQ(cc[VREPRINT], c) && ISSET(lflag, IEXTEN)) {
  518                         ret = ttyretype(tp);
  519                         goto endcase;
  520                 }
  521                 /*
  522                  * ^T - kernel info and generate SIGINFO
  523                  */
  524                 if (CCEQ(cc[VSTATUS], c) && ISSET(lflag, IEXTEN)) {
  525                         if (ISSET(lflag, ISIG))
  526                                 pgsignal(tp->t_pgrp, SIGINFO, 1);
  527                         if (!ISSET(lflag, NOKERNINFO))
  528                                 ttyinfo(tp);
  529                         goto endcase;
  530                 }
  531         }
  532         /*
  533          * Check for input buffer overflow
  534          */
  535         if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= TTYHOG(tp)) {
  536                 if (ISSET(iflag, IMAXBEL)) {
  537                         if (tp->t_outq.c_cc < tp->t_hiwat)
  538                                 (void)ttyoutput(CTRL('g'), tp);
  539                 } else
  540                         ttyflush(tp, FREAD | FWRITE);
  541                 goto endcase;
  542         }
  543         /*
  544          * Put data char in q for user and
  545          * wakeup on seeing a line delimiter.
  546          */
  547         if (putc(c, &tp->t_rawq) >= 0) {
  548                 if (!ISSET(lflag, ICANON)) {
  549                         ttwakeup(tp);
  550                         ttyecho(c, tp);
  551                         goto endcase;
  552                 }
  553                 if (TTBREAKC(c, lflag)) {
  554                         tp->t_rocount = 0;
  555                         catq(&tp->t_rawq, &tp->t_canq);
  556                         ttwakeup(tp);
  557                 } else if (tp->t_rocount++ == 0)
  558                         tp->t_rocol = tp->t_column;
  559                 if (ISSET(tp->t_state, TS_ERASE)) {
  560                         /*
  561                          * end of prterase \.../
  562                          */
  563                         CLR(tp->t_state, TS_ERASE);
  564                         (void)ttyoutput('/', tp);
  565                 }
  566                 i = tp->t_column;
  567                 ttyecho(c, tp);
  568                 if (CCEQ(cc[VEOF], c) && ISSET(lflag, ECHO)) {
  569                         /*
  570                          * Place the cursor over the '^' of the ^D.
  571                          */
  572                         i = min(2, tp->t_column - i);
  573                         while (i > 0) {
  574                                 (void)ttyoutput('\b', tp);
  575                                 i--;
  576                         }
  577                 }
  578         }
  579 endcase:
  580         /*
  581          * IXANY means allow any character to restart output.
  582          */
  583         if (ISSET(tp->t_state, TS_TTSTOP) &&
  584             !ISSET(iflag, IXANY) && cc[VSTART] != cc[VSTOP])
  585                 return (ret);
  586 restartoutput:
  587         CLR(tp->t_lflag, FLUSHO);
  588         CLR(tp->t_state, TS_TTSTOP);
  589 startoutput:
  590         ttstart(tp);
  591         return (ret);
  592 }
  593 
  594 /*
  595  * Output a single character on a tty, doing output processing
  596  * as needed (expanding tabs, newline processing, etc.).
  597  * Returns < 0 if succeeds, otherwise returns char to resend.
  598  * Must be recursive.
  599  */
  600 int
  601 ttyoutput(int c, struct tty *tp)
  602 {
  603         long oflag;
  604         int col, notout, s, c2;
  605 
  606         oflag = tp->t_oflag;
  607         if (!ISSET(oflag, OPOST)) {
  608                 tk_nout++;
  609                 tp->t_outcc++;
  610                 if (!ISSET(tp->t_lflag, FLUSHO) && putc(c, &tp->t_outq))
  611                         return (c);
  612                 return (-1);
  613         }
  614         /*
  615          * Do tab expansion if OXTABS is set.  Special case if we external
  616          * processing, we don't do the tab expansion because we'll probably
  617          * get it wrong.  If tab expansion needs to be done, let it happen
  618          * externally.
  619          */
  620         CLR(c, ~TTY_CHARMASK);
  621         if (c == '\t' &&
  622             ISSET(oflag, OXTABS) && !ISSET(tp->t_lflag, EXTPROC)) {
  623                 c = 8 - (tp->t_column & 7);
  624                 if (ISSET(tp->t_lflag, FLUSHO)) {
  625                         notout = 0;
  626                 } else {
  627                         s = spltty();           /* Don't interrupt tabs. */
  628                         notout = b_to_q("        ", c, &tp->t_outq);
  629                         c -= notout;
  630                         tk_nout += c;
  631                         tp->t_outcc += c;
  632                         splx(s);
  633                 }
  634                 tp->t_column += c;
  635                 return (notout ? '\t' : -1);
  636         }
  637         if (c == CEOT && ISSET(oflag, ONOEOT))
  638                 return (-1);
  639 
  640         /*
  641          * Newline translation: if ONLCR is set,
  642          * translate newline into "\r\n".  If OCRNL
  643          * is set, translate '\r' into '\n'.
  644          */
  645         if (c == '\n' && ISSET(tp->t_oflag, ONLCR)) {
  646                 tk_nout++;
  647                 tp->t_outcc++;
  648                 if (!ISSET(tp->t_lflag, FLUSHO) && putc('\r', &tp->t_outq))
  649                         return (c);
  650                 tp->t_column = 0;
  651         }
  652         else if (c == '\r' && ISSET(tp->t_oflag, OCRNL))
  653                 c = '\n';
  654 
  655         if (ISSET(tp->t_oflag, OLCUC) && islower(c))
  656                 c = toupper(c);
  657         else if (ISSET(tp->t_oflag, OLCUC) && ISSET(tp->t_lflag, XCASE)) {
  658                 c2 = c;
  659                 switch (c) {
  660                 case '`':
  661                         c2 = '\'';
  662                         break;
  663                 case '|':
  664                         c2 = '!';
  665                         break;
  666                 case '~':
  667                         c2 = '^';
  668                         break;
  669                 case '{':
  670                         c2 = '(';
  671                         break;
  672                 case '}':
  673                         c2 = ')';
  674                         break;
  675                 }
  676                 if (c == '\\' || isupper(c) || c != c2) {
  677                         tk_nout++;
  678                         tp->t_outcc++;
  679                         if (putc('\\', &tp->t_outq))
  680                                 return (c);
  681                         c = c2;
  682                 }
  683         }
  684         if (ISSET(tp->t_oflag, ONOCR) && c == '\r' && tp->t_column == 0)
  685                 return (-1);
  686 
  687         tk_nout++;
  688         tp->t_outcc++;
  689         if (!ISSET(tp->t_lflag, FLUSHO) && putc(c, &tp->t_outq))
  690                 return (c);
  691 
  692         col = tp->t_column;
  693         switch (CCLASS(c)) {
  694         case BACKSPACE:
  695                 if (col > 0)
  696                         --col;
  697                 break;
  698         case CONTROL:
  699                 break;
  700         case NEWLINE:
  701                 if (ISSET(tp->t_oflag, ONLRET) || ISSET(tp->t_oflag, OCRNL))
  702                         col = 0;
  703                 break;
  704         case RETURN:
  705                 col = 0;
  706                 break;
  707         case ORDINARY:
  708                 ++col;
  709                 break;
  710         case TAB:
  711                 col = (col + 8) & ~7;
  712                 break;
  713         }
  714         tp->t_column = col;
  715         return (-1);
  716 }
  717 
  718 /*
  719  * Ioctls for all tty devices.  Called after line-discipline specific ioctl
  720  * has been called to do discipline-specific functions and/or reject any
  721  * of these ioctl commands.
  722  */
  723 int
  724 ttioctl(struct tty *tp, u_long cmd, caddr_t data, int flag, struct proc *p)
  725 {
  726         extern int nlinesw;
  727         struct process *pr = p->p_p;
  728         int s, error;
  729 
  730         /* If the ioctl involves modification, hang if in the background. */
  731         switch (cmd) {
  732         case  FIOSETOWN:
  733         case  TIOCFLUSH:
  734         case  TIOCDRAIN:
  735         case  TIOCSBRK:
  736         case  TIOCCBRK:
  737         case  TIOCSETA:
  738         case  TIOCSETD:
  739         case  TIOCSETAF:
  740         case  TIOCSETAW:
  741         case  TIOCSPGRP:
  742         case  TIOCSTAT:
  743         case  TIOCSWINSZ:
  744                 while (isbackground(pr, tp) &&
  745                     (pr->ps_flags & PS_PPWAIT) == 0 &&
  746                     !sigismasked(p, SIGTTOU)) {
  747                         if (pr->ps_pgrp->pg_jobc == 0)
  748                                 return (EIO);
  749                         pgsignal(pr->ps_pgrp, SIGTTOU, 1);
  750                         error = ttysleep(tp, &lbolt, TTOPRI | PCATCH,
  751                             ttybg);
  752                         if (error)
  753                                 return (error);
  754                 }
  755                 break;
  756         }
  757 
  758         switch (cmd) {                  /* Process the ioctl. */
  759         case FIOASYNC:                  /* set/clear async i/o */
  760                 s = spltty();
  761                 if (*(int *)data)
  762                         SET(tp->t_state, TS_ASYNC);
  763                 else
  764                         CLR(tp->t_state, TS_ASYNC);
  765                 splx(s);
  766                 break;
  767         case FIONBIO:                   /* set/clear non-blocking i/o */
  768                 break;                  /* XXX: delete. */
  769         case FIONREAD:                  /* get # bytes to read */
  770                 s = spltty();
  771                 *(int *)data = ttnread(tp);
  772                 splx(s);
  773                 break;
  774         case TIOCEXCL:                  /* set exclusive use of tty */
  775                 s = spltty();
  776                 SET(tp->t_state, TS_XCLUDE);
  777                 splx(s);
  778                 break;
  779         case TIOCFLUSH: {               /* flush buffers */
  780                 int flags = *(int *)data;
  781 
  782                 if (flags == 0)
  783                         flags = FREAD | FWRITE;
  784                 else
  785                         flags &= FREAD | FWRITE;
  786                 ttyflush(tp, flags);
  787                 break;
  788         }
  789         case TIOCCONS: {                /* become virtual console */
  790                 if (*(int *)data) {
  791                         struct nameidata nid;
  792 
  793                         if (constty != NULL && constty != tp &&
  794                             ISSET(constty->t_state, TS_CARR_ON | TS_ISOPEN) ==
  795                             (TS_CARR_ON | TS_ISOPEN))
  796                                 return (EBUSY);
  797 
  798                         /* ensure user can open the real console */
  799                         NDINIT(&nid, LOOKUP, FOLLOW, UIO_SYSSPACE, "/dev/console", p);
  800                         nid.ni_pledge = PLEDGE_RPATH | PLEDGE_WPATH;
  801                         nid.ni_unveil = UNVEIL_READ | UNVEIL_WRITE;
  802                         error = namei(&nid);
  803                         if (error)
  804                                 return (error);
  805                         vn_lock(nid.ni_vp, LK_EXCLUSIVE | LK_RETRY);
  806                         error = VOP_ACCESS(nid.ni_vp, VREAD, p->p_ucred, p);
  807                         VOP_UNLOCK(nid.ni_vp);
  808                         vrele(nid.ni_vp);
  809                         if (error)
  810                                 return (error);
  811 
  812                         constty = tp;
  813                 } else if (tp == constty)
  814                         constty = NULL;
  815                 break;
  816         }
  817         case TIOCDRAIN:                 /* wait till output drained */
  818                 if ((error = ttywait(tp)) != 0)
  819                         return (error);
  820                 break;
  821         case TIOCGETA: {                /* get termios struct */
  822                 struct termios *t = (struct termios *)data;
  823 
  824                 memcpy(t, &tp->t_termios, sizeof(struct termios));
  825                 break;
  826         }
  827         case TIOCGETD:                  /* get line discipline */
  828                 *(int *)data = tp->t_line;
  829                 break;
  830         case TIOCGWINSZ:                /* get window size */
  831                 *(struct winsize *)data = tp->t_winsize;
  832                 break;
  833         case TIOCGTSTAMP:
  834                 s = spltty();
  835                 *(struct timeval *)data = tp->t_tv;
  836                 splx(s);
  837                 break;
  838         case FIOGETOWN:                 /* get pgrp of tty */
  839                 if (!isctty(pr, tp) && suser(p))
  840                         return (ENOTTY);
  841                 *(int *)data = tp->t_pgrp ? -tp->t_pgrp->pg_id : 0;
  842                 break;
  843         case TIOCGPGRP:                 /* get pgrp of tty */
  844                 if (!isctty(pr, tp) && suser(p))
  845                         return (ENOTTY);
  846                 *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
  847                 break;
  848         case TIOCGSID:                  /* get sid of tty */
  849                 if (!isctty(pr, tp))
  850                         return (ENOTTY);
  851                 *(int *)data = tp->t_session->s_leader->ps_pid;
  852                 break;
  853         case TIOCNXCL:                  /* reset exclusive use of tty */
  854                 s = spltty();
  855                 CLR(tp->t_state, TS_XCLUDE);
  856                 splx(s);
  857                 break;
  858         case TIOCOUTQ:                  /* output queue size */
  859                 *(int *)data = tp->t_outq.c_cc;
  860                 break;
  861         case TIOCSETA:                  /* set termios struct */
  862         case TIOCSETAW:                 /* drain output, set */
  863         case TIOCSETAF: {               /* drn out, fls in, set */
  864                 struct termios *t = (struct termios *)data;
  865 
  866                 s = spltty();
  867                 if (cmd == TIOCSETAW || cmd == TIOCSETAF) {
  868                         if ((error = ttywait(tp)) != 0) {
  869                                 splx(s);
  870                                 return (error);
  871                         }
  872                         if (cmd == TIOCSETAF)
  873                                 ttyflush(tp, FREAD);
  874                 }
  875                 if (!ISSET(t->c_cflag, CIGNORE)) {
  876                         /*
  877                          * Some minor validation is necessary.
  878                          */
  879                         if (t->c_ispeed < 0 || t->c_ospeed < 0) {
  880                                 splx(s);
  881                                 return (EINVAL);
  882                         }
  883                         /*
  884                          * Set device hardware.
  885                          */
  886                         if (tp->t_param && (error = (*tp->t_param)(tp, t))) {
  887                                 splx(s);
  888                                 return (error);
  889                         } else {
  890                                 if (!ISSET(tp->t_state, TS_CARR_ON) &&
  891                                     ISSET(tp->t_cflag, CLOCAL) &&
  892                                     !ISSET(t->c_cflag, CLOCAL)) {
  893                                         CLR(tp->t_state, TS_ISOPEN);
  894                                         SET(tp->t_state, TS_WOPEN);
  895                                         ttwakeup(tp);
  896                                 }
  897                                 tp->t_cflag = t->c_cflag;
  898                                 tp->t_ispeed = t->c_ispeed;
  899                                 tp->t_ospeed = t->c_ospeed;
  900                                 if (t->c_ospeed == 0 && tp->t_session &&
  901                                     tp->t_session->s_leader)
  902                                         prsignal(tp->t_session->s_leader,
  903                                             SIGHUP);
  904                         }
  905                         ttsetwater(tp);
  906                 }
  907                 if (cmd != TIOCSETAF) {
  908                         if (ISSET(t->c_lflag, ICANON) !=
  909                             ISSET(tp->t_lflag, ICANON)) {
  910                                 if (ISSET(t->c_lflag, ICANON)) {
  911                                         SET(tp->t_lflag, PENDIN);
  912                                         ttwakeup(tp);
  913                                 } else {
  914                                         struct clist tq;
  915 
  916                                         catq(&tp->t_rawq, &tp->t_canq);
  917                                         tq = tp->t_rawq;
  918                                         tp->t_rawq = tp->t_canq;
  919                                         tp->t_canq = tq;
  920                                         CLR(tp->t_lflag, PENDIN);
  921                                 }
  922                         }
  923                 }
  924                 tp->t_iflag = t->c_iflag;
  925                 tp->t_oflag = t->c_oflag;
  926                 /*
  927                  * Make the EXTPROC bit read only.
  928                  */
  929                 if (ISSET(tp->t_lflag, EXTPROC))
  930                         SET(t->c_lflag, EXTPROC);
  931                 else
  932                         CLR(t->c_lflag, EXTPROC);
  933                 tp->t_lflag = t->c_lflag | ISSET(tp->t_lflag, PENDIN);
  934                 memcpy(tp->t_cc, t->c_cc, sizeof(t->c_cc));
  935                 splx(s);
  936                 break;
  937         }
  938         case TIOCSETD: {                /* set line discipline */
  939                 int t = *(int *)data;
  940                 dev_t device = tp->t_dev;
  941 
  942                 if ((u_int)t >= nlinesw)
  943                         return (ENXIO);
  944                 if (t != tp->t_line) {
  945                         s = spltty();
  946                         (*linesw[tp->t_line].l_close)(tp, flag, p);
  947                         error = (*linesw[t].l_open)(device, tp, p);
  948                         if (error) {
  949                                 (*linesw[tp->t_line].l_open)(device, tp, p);
  950                                 splx(s);
  951                                 return (error);
  952                         }
  953                         tp->t_line = t;
  954                         splx(s);
  955                 }
  956                 break;
  957         }
  958         case TIOCSTART:                 /* start output, like ^Q */
  959                 s = spltty();
  960                 if (ISSET(tp->t_state, TS_TTSTOP) ||
  961                     ISSET(tp->t_lflag, FLUSHO)) {
  962                         CLR(tp->t_lflag, FLUSHO);
  963                         CLR(tp->t_state, TS_TTSTOP);
  964                         ttstart(tp);
  965                 }
  966                 splx(s);
  967                 break;
  968         case TIOCSTOP:                  /* stop output, like ^S */
  969                 s = spltty();
  970                 if (!ISSET(tp->t_state, TS_TTSTOP)) {
  971                         SET(tp->t_state, TS_TTSTOP);
  972                         (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
  973                 }
  974                 splx(s);
  975                 break;
  976         case TIOCSCTTY:                 /* become controlling tty */
  977                 /* Session ctty vnode pointer set in vnode layer. */
  978                 if (!SESS_LEADER(pr) ||
  979                     ((pr->ps_session->s_ttyvp || tp->t_session) &&
  980                      (tp->t_session != pr->ps_session)))
  981                         return (EPERM);
  982                 if (tp->t_session)
  983                         SESSRELE(tp->t_session);
  984                 SESSHOLD(pr->ps_session);
  985                 tp->t_session = pr->ps_session;
  986                 tp->t_pgrp = pr->ps_pgrp;
  987                 pr->ps_session->s_ttyp = tp;
  988                 atomic_setbits_int(&pr->ps_flags, PS_CONTROLT);
  989                 break;
  990         case FIOSETOWN: {               /* set pgrp of tty */
  991                 struct pgrp *pgrp;
  992                 struct process *pr1;
  993                 pid_t pgid = *(int *)data;
  994 
  995                 if (!isctty(pr, tp))
  996                         return (ENOTTY);
  997                 if (pgid < 0) {
  998                         pgrp = pgfind(-pgid);
  999                 } else {
 1000                         pr1 = prfind(pgid);
 1001                         if (pr1 == NULL)
 1002                                 return (ESRCH);
 1003                         pgrp = pr1->ps_pgrp;
 1004                 }
 1005                 if (pgrp == NULL)
 1006                         return (EINVAL);
 1007                 else if (pgrp->pg_session != pr->ps_session)
 1008                         return (EPERM);
 1009                 tp->t_pgrp = pgrp;
 1010                 break;
 1011         }
 1012         case TIOCSPGRP: {               /* set pgrp of tty */
 1013                 struct pgrp *pgrp = pgfind(*(int *)data);
 1014 
 1015                 if (!isctty(pr, tp))
 1016                         return (ENOTTY);
 1017                 else if (pgrp == NULL)
 1018                         return (EINVAL);
 1019                 else if (pgrp->pg_session != pr->ps_session)
 1020                         return (EPERM);
 1021                 tp->t_pgrp = pgrp;
 1022                 break;
 1023         }
 1024         case TIOCSTAT:                  /* get load avg stats */
 1025                 ttyinfo(tp);
 1026                 break;
 1027         case TIOCSWINSZ:                /* set window size */
 1028                 if (bcmp((caddr_t)&tp->t_winsize, data,
 1029                     sizeof (struct winsize))) {
 1030                         tp->t_winsize = *(struct winsize *)data;
 1031                         pgsignal(tp->t_pgrp, SIGWINCH, 1);
 1032                 }
 1033                 break;
 1034         case TIOCSTSTAMP: {
 1035                 struct tstamps *ts = (struct tstamps *)data;
 1036 
 1037                 s = spltty();
 1038                 CLR(tp->t_flags, TS_TSTAMPDCDSET);
 1039                 CLR(tp->t_flags, TS_TSTAMPCTSSET);
 1040                 CLR(tp->t_flags, TS_TSTAMPDCDCLR);
 1041                 CLR(tp->t_flags, TS_TSTAMPCTSCLR);
 1042                 if (ISSET(ts->ts_set, TIOCM_CAR))
 1043                         SET(tp->t_flags, TS_TSTAMPDCDSET);
 1044                 if (ISSET(ts->ts_set, TIOCM_CTS))
 1045                         SET(tp->t_flags, TS_TSTAMPCTSSET);
 1046                 if (ISSET(ts->ts_clr, TIOCM_CAR))
 1047                         SET(tp->t_flags, TS_TSTAMPDCDCLR);
 1048                 if (ISSET(ts->ts_clr, TIOCM_CTS))
 1049                         SET(tp->t_flags, TS_TSTAMPCTSCLR);
 1050                 splx(s);
 1051                 break;
 1052         }
 1053         default:
 1054                 return (-1);
 1055         }
 1056         return (0);
 1057 }
 1058 
 1059 const struct filterops ttyread_filtops = {
 1060         .f_flags        = FILTEROP_ISFD,
 1061         .f_attach       = NULL,
 1062         .f_detach       = filt_ttyrdetach,
 1063         .f_event        = filt_ttyread,
 1064 };
 1065 
 1066 const struct filterops ttywrite_filtops = {
 1067         .f_flags        = FILTEROP_ISFD,
 1068         .f_attach       = NULL,
 1069         .f_detach       = filt_ttywdetach,
 1070         .f_event        = filt_ttywrite,
 1071 };
 1072 
 1073 const struct filterops ttyexcept_filtops = {
 1074         .f_flags        = FILTEROP_ISFD,
 1075         .f_attach       = NULL,
 1076         .f_detach       = filt_ttyrdetach,
 1077         .f_event        = filt_ttyexcept,
 1078 };
 1079 
 1080 int
 1081 ttkqfilter(dev_t dev, struct knote *kn)
 1082 {
 1083         struct tty *tp = (*cdevsw[major(dev)].d_tty)(dev);
 1084         struct klist *klist;
 1085         int s;
 1086 
 1087         switch (kn->kn_filter) {
 1088         case EVFILT_READ:
 1089                 klist = &tp->t_rsel.si_note;
 1090                 kn->kn_fop = &ttyread_filtops;
 1091                 break;
 1092         case EVFILT_WRITE:
 1093                 klist = &tp->t_wsel.si_note;
 1094                 kn->kn_fop = &ttywrite_filtops;
 1095                 break;
 1096         case EVFILT_EXCEPT:
 1097                 if (kn->kn_flags & __EV_SELECT) {
 1098                         /* Prevent triggering exceptfds. */
 1099                         return (EPERM);
 1100                 }
 1101                 if ((kn->kn_flags & __EV_POLL) == 0) {
 1102                         /* Disallow usage through kevent(2). */
 1103                         return (EINVAL);
 1104                 }
 1105                 klist = &tp->t_rsel.si_note;
 1106                 kn->kn_fop = &ttyexcept_filtops;
 1107                 break;
 1108         default:
 1109                 return (EINVAL);
 1110         }
 1111 
 1112         kn->kn_hook = tp;
 1113 
 1114         s = spltty();
 1115         klist_insert_locked(klist, kn);
 1116         splx(s);
 1117 
 1118         return (0);
 1119 }
 1120 
 1121 void
 1122 filt_ttyrdetach(struct knote *kn)
 1123 {
 1124         struct tty *tp = kn->kn_hook;
 1125         int s;
 1126 
 1127         s = spltty();
 1128         klist_remove_locked(&tp->t_rsel.si_note, kn);
 1129         splx(s);
 1130 }
 1131 
 1132 int
 1133 filt_ttyread(struct knote *kn, long hint)
 1134 {
 1135         struct tty *tp = kn->kn_hook;
 1136         int active, s;
 1137 
 1138         s = spltty();
 1139         kn->kn_data = ttnread(tp);
 1140         active = (kn->kn_data > 0);
 1141         if (!ISSET(tp->t_cflag, CLOCAL) && !ISSET(tp->t_state, TS_CARR_ON)) {
 1142                 kn->kn_flags |= EV_EOF;
 1143                 if (kn->kn_flags & __EV_POLL)
 1144                         kn->kn_flags |= __EV_HUP;
 1145                 active = 1;
 1146         } else {
 1147                 kn->kn_flags &= ~(EV_EOF | __EV_HUP);
 1148         }
 1149         splx(s);
 1150         return (active);
 1151 }
 1152 
 1153 void
 1154 filt_ttywdetach(struct knote *kn)
 1155 {
 1156         struct tty *tp = kn->kn_hook;
 1157         int s;
 1158 
 1159         s = spltty();
 1160         klist_remove_locked(&tp->t_wsel.si_note, kn);
 1161         splx(s);
 1162 }
 1163 
 1164 int
 1165 filt_ttywrite(struct knote *kn, long hint)
 1166 {
 1167         struct tty *tp = kn->kn_hook;
 1168         int active, s;
 1169 
 1170         s = spltty();
 1171         kn->kn_data = tp->t_outq.c_cn - tp->t_outq.c_cc;
 1172         active = (tp->t_outq.c_cc <= tp->t_lowat);
 1173 
 1174         /* Write-side HUP condition is only for poll(2) and select(2). */
 1175         if (kn->kn_flags & (__EV_POLL | __EV_SELECT)) {
 1176                 if (!ISSET(tp->t_cflag, CLOCAL) &&
 1177                     !ISSET(tp->t_state, TS_CARR_ON)) {
 1178                         kn->kn_flags |= __EV_HUP;
 1179                         active = 1;
 1180                 } else {
 1181                         kn->kn_flags &= ~__EV_HUP;
 1182                 }
 1183         }
 1184         splx(s);
 1185         return (active);
 1186 }
 1187 
 1188 int
 1189 filt_ttyexcept(struct knote *kn, long hint)
 1190 {
 1191         struct tty *tp = kn->kn_hook;
 1192         int active = 0;
 1193         int s;
 1194 
 1195         s = spltty();
 1196         if (kn->kn_flags & __EV_POLL) {
 1197                 if (!ISSET(tp->t_cflag, CLOCAL) &&
 1198                     !ISSET(tp->t_state, TS_CARR_ON)) {
 1199                         kn->kn_flags |= __EV_HUP;
 1200                         active = 1;
 1201                 } else {
 1202                         kn->kn_flags &= ~__EV_HUP;
 1203                 }
 1204         }
 1205         splx(s);
 1206         return (active);
 1207 }
 1208 
 1209 static int
 1210 ttnread(struct tty *tp)
 1211 {
 1212         int nread;
 1213 
 1214         splassert(IPL_TTY);
 1215 
 1216         if (ISSET(tp->t_lflag, PENDIN))
 1217                 ttypend(tp);
 1218         nread = tp->t_canq.c_cc;
 1219         if (!ISSET(tp->t_lflag, ICANON)) {
 1220                 nread += tp->t_rawq.c_cc;
 1221                 if (nread < tp->t_cc[VMIN] && !tp->t_cc[VTIME])
 1222                         nread = 0;
 1223         }
 1224         return (nread);
 1225 }
 1226 
 1227 /*
 1228  * Wait for output to drain, or if this times out, flush it.
 1229  */
 1230 int
 1231 ttywait_nsec(struct tty *tp, uint64_t nsecs)
 1232 {
 1233         int error, s;
 1234 
 1235         error = 0;
 1236         s = spltty();
 1237         while ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) &&
 1238             (ISSET(tp->t_state, TS_CARR_ON) || ISSET(tp->t_cflag, CLOCAL)) &&
 1239             tp->t_oproc) {
 1240                 (*tp->t_oproc)(tp);
 1241                 if ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) &&
 1242                     (ISSET(tp->t_state, TS_CARR_ON) || ISSET(tp->t_cflag, CLOCAL))
 1243                     && tp->t_oproc) {
 1244                         SET(tp->t_state, TS_ASLEEP);
 1245                         error = ttysleep_nsec(tp, &tp->t_outq, TTOPRI | PCATCH,
 1246                             ttyout, nsecs);
 1247                         if (error == EWOULDBLOCK)
 1248                                 ttyflush(tp, FWRITE);
 1249                         if (error)
 1250                                 break;
 1251                 } else
 1252                         break;
 1253         }
 1254         splx(s);
 1255         return (error);
 1256 }
 1257 
 1258 int
 1259 ttywait(struct tty *tp)
 1260 {
 1261         return (ttywait_nsec(tp, INFSLP));
 1262 }
 1263 
 1264 /*
 1265  * Flush if successfully wait.
 1266  */
 1267 int
 1268 ttywflush(struct tty *tp)
 1269 {
 1270         int error;
 1271 
 1272         error = ttywait_nsec(tp, SEC_TO_NSEC(5));
 1273         if (error == 0 || error == EWOULDBLOCK)
 1274                 ttyflush(tp, FREAD);
 1275         return (error);
 1276 }
 1277 
 1278 /*
 1279  * Flush tty read and/or write queues, notifying anyone waiting.
 1280  */
 1281 void
 1282 ttyflush(struct tty *tp, int rw)
 1283 {
 1284         int s;
 1285 
 1286         s = spltty();
 1287         if (rw & FREAD) {
 1288                 FLUSHQ(&tp->t_canq);
 1289                 FLUSHQ(&tp->t_rawq);
 1290                 tp->t_rocount = 0;
 1291                 tp->t_rocol = 0;
 1292                 CLR(tp->t_state, TS_LOCAL);
 1293                 ttyunblock(tp);
 1294                 ttwakeup(tp);
 1295         }
 1296         if (rw & FWRITE) {
 1297                 CLR(tp->t_state, TS_TTSTOP);
 1298                 (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
 1299                 FLUSHQ(&tp->t_outq);
 1300                 wakeup((caddr_t)&tp->t_outq);
 1301                 selwakeup(&tp->t_wsel);
 1302         }
 1303         splx(s);
 1304 }
 1305 
 1306 /*
 1307  * Copy in the default termios characters.
 1308  */
 1309 void
 1310 ttychars(struct tty *tp)
 1311 {
 1312 
 1313         memcpy(tp->t_cc, ttydefchars, sizeof(ttydefchars));
 1314 }
 1315 
 1316 /*
 1317  * Send stop character on input overflow.
 1318  */
 1319 static void
 1320 ttyblock(struct tty *tp)
 1321 {
 1322         int total;
 1323 
 1324         total = tp->t_rawq.c_cc + tp->t_canq.c_cc;
 1325         if (tp->t_rawq.c_cc > TTYHOG(tp)) {
 1326                 ttyflush(tp, FREAD | FWRITE);
 1327                 CLR(tp->t_state, TS_TBLOCK);
 1328         }
 1329         /*
 1330          * Block further input iff: current input > threshold
 1331          * AND input is available to user program.
 1332          */
 1333         if ((total >= TTYHOG(tp) / 2 &&
 1334              !ISSET(tp->t_state, TS_TBLOCK) &&
 1335              !ISSET(tp->t_lflag, ICANON)) || tp->t_canq.c_cc > 0) {
 1336                 if (ISSET(tp->t_iflag, IXOFF) &&
 1337                     tp->t_cc[VSTOP] != _POSIX_VDISABLE &&
 1338                     putc(tp->t_cc[VSTOP], &tp->t_outq) == 0) {
 1339                         SET(tp->t_state, TS_TBLOCK);
 1340                         ttstart(tp);
 1341                 }
 1342                 /* Try to block remote output via hardware flow control. */
 1343                 if (ISSET(tp->t_cflag, CHWFLOW) && tp->t_hwiflow &&
 1344                     (*tp->t_hwiflow)(tp, 1) != 0)
 1345                         SET(tp->t_state, TS_TBLOCK);
 1346         }
 1347 }
 1348 
 1349 void
 1350 ttrstrt(void *arg)
 1351 {
 1352         struct tty *tp = (struct tty *)arg;
 1353         int s;
 1354 
 1355 #ifdef DIAGNOSTIC
 1356         if (tp == NULL)
 1357                 panic("ttrstrt");
 1358 #endif
 1359         s = spltty();
 1360         CLR(tp->t_state, TS_TIMEOUT);
 1361         ttstart(tp);
 1362         splx(s);
 1363 }
 1364 
 1365 int
 1366 ttstart(struct tty *tp)
 1367 {
 1368 
 1369         if (tp->t_oproc != NULL)        /* XXX: Kludge for pty. */
 1370                 (*tp->t_oproc)(tp);
 1371         return (0);
 1372 }
 1373 
 1374 /*
 1375  * "close" a line discipline
 1376  */
 1377 int
 1378 ttylclose(struct tty *tp, int flag, struct proc *p)
 1379 {
 1380 
 1381         if (flag & FNONBLOCK)
 1382                 ttyflush(tp, FREAD | FWRITE);
 1383         else
 1384                 ttywflush(tp);
 1385         return (0);
 1386 }
 1387 
 1388 /*
 1389  * Handle modem control transition on a tty.
 1390  * Flag indicates new state of carrier.
 1391  * Returns 0 if the line should be turned off, otherwise 1.
 1392  */
 1393 int
 1394 ttymodem(struct tty *tp, int flag)
 1395 {
 1396 
 1397         if (!ISSET(tp->t_state, TS_WOPEN) && ISSET(tp->t_cflag, MDMBUF)) {
 1398                 /*
 1399                  * MDMBUF: do flow control according to carrier flag
 1400                  */
 1401                 if (flag) {
 1402                         CLR(tp->t_state, TS_TTSTOP);
 1403                         ttstart(tp);
 1404                 } else if (!ISSET(tp->t_state, TS_TTSTOP)) {
 1405                         SET(tp->t_state, TS_TTSTOP);
 1406                         (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
 1407                 }
 1408         } else if (flag == 0) {
 1409                 /*
 1410                  * Lost carrier.
 1411                  */
 1412                 CLR(tp->t_state, TS_CARR_ON);
 1413                 if (ISSET(tp->t_state, TS_ISOPEN) &&
 1414                     !ISSET(tp->t_cflag, CLOCAL)) {
 1415                         if (tp->t_session && tp->t_session->s_leader)
 1416                                 prsignal(tp->t_session->s_leader, SIGHUP);
 1417                         ttyflush(tp, FREAD | FWRITE);
 1418                         return (0);
 1419                 }
 1420         } else {
 1421                 /*
 1422                  * Carrier now on.
 1423                  */
 1424                 SET(tp->t_state, TS_CARR_ON);
 1425                 ttwakeup(tp);
 1426         }
 1427         return (1);
 1428 }
 1429 
 1430 /*
 1431  * Default modem control routine (for other line disciplines).
 1432  * Return argument flag, to turn off device on carrier drop.
 1433  */
 1434 int
 1435 nullmodem(struct tty *tp, int flag)
 1436 {
 1437 
 1438         if (flag)
 1439                 SET(tp->t_state, TS_CARR_ON);
 1440         else {
 1441                 CLR(tp->t_state, TS_CARR_ON);
 1442                 if (ISSET(tp->t_state, TS_ISOPEN) &&
 1443                     !ISSET(tp->t_cflag, CLOCAL)) {
 1444                         if (tp->t_session && tp->t_session->s_leader)
 1445                                 prsignal(tp->t_session->s_leader, SIGHUP);
 1446                         ttyflush(tp, FREAD | FWRITE);
 1447                         return (0);
 1448                 }
 1449         }
 1450         return (1);
 1451 }
 1452 
 1453 /*
 1454  * Reinput pending characters after state switch
 1455  * call at spltty().
 1456  */
 1457 void
 1458 ttypend(struct tty *tp)
 1459 {
 1460         struct clist tq;
 1461         int c;
 1462 
 1463         splassert(IPL_TTY);
 1464 
 1465         CLR(tp->t_lflag, PENDIN);
 1466         SET(tp->t_state, TS_TYPEN);
 1467         tq = tp->t_rawq;
 1468         tp->t_rawq.c_cc = 0;
 1469         tp->t_rawq.c_cf = tp->t_rawq.c_cl = NULL;
 1470         while ((c = getc(&tq)) >= 0)
 1471                 ttyinput(c, tp);
 1472         CLR(tp->t_state, TS_TYPEN);
 1473 }
 1474 
 1475 void ttvtimeout(void *);
 1476 
 1477 void
 1478 ttvtimeout(void *arg)
 1479 {
 1480         struct tty *tp = (struct tty *)arg;
 1481 
 1482         wakeup(&tp->t_rawq);
 1483 }
 1484 
 1485 /*
 1486  * Process a read call on a tty device.
 1487  */
 1488 int
 1489 ttread(struct tty *tp, struct uio *uio, int flag)
 1490 {
 1491         struct timeout *stime = NULL;
 1492         struct proc *p = curproc;
 1493         struct process *pr = p->p_p;
 1494         int s, first, error = 0;
 1495         u_char *cc = tp->t_cc;
 1496         struct clist *qp;
 1497         int last_cc = 0;
 1498         long lflag;
 1499         int c;
 1500 
 1501 loop:   lflag = tp->t_lflag;
 1502         s = spltty();
 1503         /*
 1504          * take pending input first
 1505          */
 1506         if (ISSET(lflag, PENDIN))
 1507                 ttypend(tp);
 1508         splx(s);
 1509 
 1510         /*
 1511          * Hang process if it's in the background.
 1512          */
 1513         if (isbackground(pr, tp)) {
 1514                 if (sigismasked(p, SIGTTIN) ||
 1515                     pr->ps_flags & PS_PPWAIT || pr->ps_pgrp->pg_jobc == 0) {
 1516                         error = EIO;
 1517                         goto out;
 1518                 }
 1519                 pgsignal(pr->ps_pgrp, SIGTTIN, 1);
 1520                 error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, ttybg);
 1521                 if (error)
 1522                         goto out;
 1523                 goto loop;
 1524         }
 1525 
 1526         s = spltty();
 1527         if (!ISSET(lflag, ICANON)) {
 1528                 int min = cc[VMIN];
 1529                 int time = cc[VTIME] * 100;     /* tenths of a second (ms) */
 1530 
 1531                 qp = &tp->t_rawq;
 1532                 /*
 1533                  * Check each of the four combinations.
 1534                  * (min > 0 && time == 0) is the normal read case.
 1535                  * It should be fairly efficient, so we check that and its
 1536                  * companion case (min == 0 && time == 0) first.
 1537                  */
 1538                 if (time == 0) {
 1539                         if (qp->c_cc < min)
 1540                                 goto sleep;
 1541                         goto read;
 1542                 }
 1543                 if (min > 0) {
 1544                         if (qp->c_cc <= 0)
 1545                                 goto sleep;
 1546                         if (qp->c_cc >= min)
 1547                                 goto read;
 1548                         if (stime == NULL) {
 1549 alloc_timer:
 1550                                 stime = malloc(sizeof(*stime), M_TEMP, M_WAITOK);
 1551                                 timeout_set(stime, ttvtimeout, tp);
 1552                                 timeout_add_msec(stime, time);
 1553                         } else if (qp->c_cc > last_cc) {
 1554                                 /* got a character, restart timer */
 1555                                 timeout_add_msec(stime, time);
 1556                         }
 1557                 } else {        /* min == 0 */
 1558                         if (qp->c_cc > 0)
 1559                                 goto read;
 1560                         if (stime == NULL) {
 1561                                 goto alloc_timer;
 1562                         }
 1563                 }
 1564                 last_cc = qp->c_cc;
 1565                 if (stime && !timeout_triggered(stime)) {
 1566                         goto sleep;
 1567                 }
 1568         } else if ((qp = &tp->t_canq)->c_cc <= 0) {
 1569                 int carrier;
 1570 
 1571 sleep:
 1572                 /*
 1573                  * If there is no input, sleep on rawq
 1574                  * awaiting hardware receipt and notification.
 1575                  * If we have data, we don't need to check for carrier.
 1576                  */
 1577                 carrier = ISSET(tp->t_state, TS_CARR_ON) ||
 1578                     ISSET(tp->t_cflag, CLOCAL);
 1579                 if (!carrier && ISSET(tp->t_state, TS_ISOPEN)) {
 1580                         splx(s);
 1581                         error = 0;
 1582                         goto out;
 1583                 }
 1584                 if (flag & IO_NDELAY) {
 1585                         splx(s);
 1586                         error = EWOULDBLOCK;
 1587                         goto out;
 1588                 }
 1589                 error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH,
 1590                     carrier ? ttyin : ttopen);
 1591                 splx(s);
 1592                 if (stime && timeout_triggered(stime))
 1593                         error = EWOULDBLOCK;
 1594                 if (cc[VMIN] == 0 && error == EWOULDBLOCK) {
 1595                         error = 0;
 1596                         goto out;
 1597                 }
 1598                 if (error && error != EWOULDBLOCK)
 1599                         goto out;
 1600                 error = 0;
 1601                 goto loop;
 1602         }
 1603 read:
 1604         splx(s);
 1605 
 1606         /*
 1607          * Input present, check for input mapping and processing.
 1608          */
 1609         first = 1;
 1610         while ((c = getc(qp)) >= 0) {
 1611                 /*
 1612                  * delayed suspend (^Y)
 1613                  */
 1614                 if (CCEQ(cc[VDSUSP], c) &&
 1615                     ISSET(lflag, IEXTEN | ISIG) == (IEXTEN | ISIG)) {
 1616                         pgsignal(tp->t_pgrp, SIGTSTP, 1);
 1617                         if (first) {
 1618                                 error = ttysleep(tp, &lbolt, TTIPRI | PCATCH,
 1619                                     ttybg);
 1620                                 if (error)
 1621                                         break;
 1622                                 goto loop;
 1623                         }
 1624                         break;
 1625                 }
 1626                 /*
 1627                  * Interpret EOF only in canonical mode.
 1628                  */
 1629                 if (CCEQ(cc[VEOF], c) && ISSET(lflag, ICANON))
 1630                         break;
 1631                 /*
 1632                  * Give user character.
 1633                  */
 1634                 error = ureadc(c, uio);
 1635                 if (error)
 1636                         break;
 1637                 if (uio->uio_resid == 0)
 1638                         break;
 1639                 /*
 1640                  * In canonical mode check for a "break character"
 1641                  * marking the end of a "line of input".
 1642                  */
 1643                 if (ISSET(lflag, ICANON) && TTBREAKC(c, lflag))
 1644                         break;
 1645                 first = 0;
 1646         }
 1647         /*
 1648          * Look to unblock output now that (presumably)
 1649          * the input queue has gone down.
 1650          */
 1651         s = spltty();
 1652         if (tp->t_rawq.c_cc < TTYHOG(tp)/5)
 1653                 ttyunblock(tp);
 1654         splx(s);
 1655 
 1656 out:
 1657         if (stime) {
 1658                 timeout_del(stime);
 1659                 free(stime, M_TEMP, sizeof(*stime));
 1660         }
 1661         return (error);
 1662 }
 1663 
 1664 /* Call at spltty */
 1665 void
 1666 ttyunblock(struct tty *tp)
 1667 {
 1668         u_char *cc = tp->t_cc;
 1669 
 1670         splassert(IPL_TTY);
 1671 
 1672         if (ISSET(tp->t_state, TS_TBLOCK)) {
 1673                 if (ISSET(tp->t_iflag, IXOFF) &&
 1674                     cc[VSTART] != _POSIX_VDISABLE &&
 1675                     putc(cc[VSTART], &tp->t_outq) == 0) {
 1676                         CLR(tp->t_state, TS_TBLOCK);
 1677                         ttstart(tp);
 1678                 }
 1679                 /* Try to unblock remote output via hardware flow control. */
 1680                 if (ISSET(tp->t_cflag, CHWFLOW) && tp->t_hwiflow &&
 1681                     (*tp->t_hwiflow)(tp, 0) != 0)
 1682                         CLR(tp->t_state, TS_TBLOCK);
 1683         }
 1684 }
 1685 
 1686 /*
 1687  * Check the output queue on tp for space for a kernel message (from uprintf
 1688  * or tprintf).  Allow some space over the normal hiwater mark so we don't
 1689  * lose messages due to normal flow control, but don't let the tty run amok.
 1690  * Sleeps here are not interruptible, but we return prematurely if new signals
 1691  * arrive.
 1692  */
 1693 int
 1694 ttycheckoutq(struct tty *tp, int wait)
 1695 {
 1696         int hiwat, s, oldsig;
 1697 
 1698         hiwat = tp->t_hiwat;
 1699         s = spltty();
 1700         oldsig = wait ? SIGPENDING(curproc) : 0;
 1701         if (tp->t_outq.c_cc > hiwat + TTHIWATMINSPACE)
 1702                 while (tp->t_outq.c_cc > hiwat) {
 1703                         ttstart(tp);
 1704                         if (wait == 0 || SIGPENDING(curproc) != oldsig) {
 1705                                 splx(s);
 1706                                 return (0);
 1707                         }
 1708                         SET(tp->t_state, TS_ASLEEP);
 1709                         tsleep_nsec(&tp->t_outq, PZERO - 1, "ttckoutq",
 1710                             SEC_TO_NSEC(1));
 1711                 }
 1712         splx(s);
 1713         return (1);
 1714 }
 1715 
 1716 /*
 1717  * Process a write call on a tty device.
 1718  */
 1719 int
 1720 ttwrite(struct tty *tp, struct uio *uio, int flag)
 1721 {
 1722         u_char *cp = NULL;
 1723         int cc, ce, obufcc = 0;
 1724         struct proc *p;
 1725         struct process *pr;
 1726         int hiwat, error, s;
 1727         size_t cnt;
 1728         u_char obuf[OBUFSIZ];
 1729 
 1730         hiwat = tp->t_hiwat;
 1731         cnt = uio->uio_resid;
 1732         error = 0;
 1733         cc = 0;
 1734 loop:
 1735         s = spltty();
 1736         if (!ISSET(tp->t_state, TS_CARR_ON) &&
 1737             !ISSET(tp->t_cflag, CLOCAL)) {
 1738                 if (ISSET(tp->t_state, TS_ISOPEN)) {
 1739                         splx(s);
 1740                         error = EIO;
 1741                         goto done;
 1742                 } else if (flag & IO_NDELAY) {
 1743                         splx(s);
 1744                         error = EWOULDBLOCK;
 1745                         goto out;
 1746                 } else {
 1747                         /* Sleep awaiting carrier. */
 1748                         error = ttysleep(tp,
 1749                             &tp->t_rawq, TTIPRI | PCATCH, ttopen);
 1750                         splx(s);
 1751                         if (error)
 1752                                 goto out;
 1753                         goto loop;
 1754                 }
 1755         }
 1756         splx(s);
 1757         /*
 1758          * Hang the process if it's in the background.
 1759          */
 1760         p = curproc;
 1761         pr = p->p_p;
 1762         if (isbackground(pr, tp) &&
 1763             ISSET(tp->t_lflag, TOSTOP) && (pr->ps_flags & PS_PPWAIT) == 0 &&
 1764             !sigismasked(p, SIGTTOU)) {
 1765                 if (pr->ps_pgrp->pg_jobc == 0) {
 1766                         error = EIO;
 1767                         goto out;
 1768                 }
 1769                 pgsignal(pr->ps_pgrp, SIGTTOU, 1);
 1770                 error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, ttybg);
 1771                 if (error)
 1772                         goto out;
 1773                 goto loop;
 1774         }
 1775         /*
 1776          * Process the user's data in at most OBUFSIZ chunks.  Perform any
 1777          * output translation.  Keep track of high water mark, sleep on
 1778          * overflow awaiting device aid in acquiring new space.
 1779          */
 1780         while (uio->uio_resid > 0 || cc > 0) {
 1781                 if (ISSET(tp->t_lflag, FLUSHO)) {
 1782                         uio->uio_resid = 0;
 1783                         goto done;
 1784                 }
 1785                 if (tp->t_outq.c_cc > hiwat)
 1786                         goto ovhiwat;
 1787                 /*
 1788                  * Grab a hunk of data from the user, unless we have some
 1789                  * leftover from last time.
 1790                  */
 1791                 if (cc == 0) {
 1792                         cc = MIN(uio->uio_resid, OBUFSIZ);
 1793                         cp = obuf;
 1794                         error = uiomove(cp, cc, uio);
 1795                         if (error) {
 1796                                 cc = 0;
 1797                                 break;
 1798                         }
 1799                         if (cc > obufcc)
 1800                                 obufcc = cc;
 1801 
 1802                         /* duplicate /dev/console output into console buffer */
 1803                         if (consbufp && cn_tab &&
 1804                             cn_tab->cn_dev == tp->t_dev && tp->t_gen == 0) {
 1805                                 int i;
 1806                                 for (i = 0; i < cc; i++) {
 1807                                         char c = cp[i];
 1808                                         if (c != '\0' && c != '\r' && c != 0177)
 1809                                                 msgbuf_putchar(consbufp, c);
 1810                                 }
 1811                         }
 1812                 }
 1813                 /*
 1814                  * If nothing fancy need be done, grab those characters we
 1815                  * can handle without any of ttyoutput's processing and
 1816                  * just transfer them to the output q.  For those chars
 1817                  * which require special processing (as indicated by the
 1818                  * bits in char_type), call ttyoutput.  After processing
 1819                  * a hunk of data, look for FLUSHO so ^O's will take effect
 1820                  * immediately.
 1821                  */
 1822                 while (cc > 0) {
 1823                         int i;
 1824                         if (!ISSET(tp->t_oflag, OPOST))
 1825                                 ce = cc;
 1826                         else {
 1827                                 ce = cc - scanc((u_int)cc, cp, char_type,
 1828                                     CCLASSMASK);
 1829                                 /*
 1830                                  * If ce is zero, then we're processing
 1831                                  * a special character through ttyoutput.
 1832                                  */
 1833                                 if (ce == 0) {
 1834                                         tp->t_rocount = 0;
 1835                                         if (ttyoutput(*cp, tp) >= 0) {
 1836                                                 /* out of space */
 1837                                                 goto ovhiwat;
 1838                                         }
 1839                                         cp++;
 1840                                         cc--;
 1841                                         if (ISSET(tp->t_lflag, FLUSHO) ||
 1842                                             tp->t_outq.c_cc > hiwat)
 1843                                                 goto ovhiwat;
 1844                                         continue;
 1845                                 }
 1846                         }
 1847                         /*
 1848                          * A bunch of normal characters have been found.
 1849                          * Transfer them en masse to the output queue and
 1850                          * continue processing at the top of the loop.
 1851                          * If there are any further characters in this
 1852                          * <= OBUFSIZ chunk, the first should be a character
 1853                          * requiring special handling by ttyoutput.
 1854                          */
 1855                         tp->t_rocount = 0;
 1856                         i = b_to_q(cp, ce, &tp->t_outq);
 1857                         ce -= i;
 1858                         tp->t_column += ce;
 1859                         cp += ce, cc -= ce, tk_nout += ce;
 1860                         tp->t_outcc += ce;
 1861                         if (i > 0) {
 1862                                 /* out of space */
 1863                                 goto ovhiwat;
 1864                         }
 1865                         if (ISSET(tp->t_lflag, FLUSHO) ||
 1866                             tp->t_outq.c_cc > hiwat)
 1867                                 break;
 1868                 }
 1869                 ttstart(tp);
 1870         }
 1871 out:
 1872         /*
 1873          * If cc is nonzero, we leave the uio structure inconsistent, as the
 1874          * offset and iov pointers have moved forward, but it doesn't matter
 1875          * (the call will either return short or restart with a new uio).
 1876          */
 1877         uio->uio_resid += cc;
 1878 done:
 1879         if (obufcc)
 1880                 explicit_bzero(obuf, obufcc);
 1881         return (error);
 1882 
 1883 ovhiwat:
 1884         ttstart(tp);
 1885         s = spltty();
 1886         /*
 1887          * This can only occur if FLUSHO is set in t_lflag,
 1888          * or if ttstart/oproc is synchronous (or very fast).
 1889          */
 1890         if (tp->t_outq.c_cc <= hiwat) {
 1891                 splx(s);
 1892                 goto loop;
 1893         }
 1894         if (flag & IO_NDELAY) {
 1895                 splx(s);
 1896                 uio->uio_resid += cc;
 1897                 if (obufcc)
 1898                         explicit_bzero(obuf, obufcc);
 1899                 return (uio->uio_resid == cnt ? EWOULDBLOCK : 0);
 1900         }
 1901         SET(tp->t_state, TS_ASLEEP);
 1902         error = ttysleep(tp, &tp->t_outq, TTOPRI | PCATCH, ttyout);
 1903         splx(s);
 1904         if (error)
 1905                 goto out;
 1906         goto loop;
 1907 }
 1908 
 1909 /*
 1910  * Rubout one character from the rawq of tp
 1911  * as cleanly as possible.
 1912  */
 1913 int
 1914 ttyrub(int c, struct tty *tp)
 1915 {
 1916         u_char *cp;
 1917         int savecol;
 1918         int tabc, s, cc;
 1919 
 1920         if (!ISSET(tp->t_lflag, ECHO) || ISSET(tp->t_lflag, EXTPROC))
 1921                 return 0;
 1922         CLR(tp->t_lflag, FLUSHO);
 1923         if (ISSET(tp->t_lflag, ECHOE)) {
 1924                 if (tp->t_rocount == 0) {
 1925                         /*
 1926                          * Screwed by ttwrite; retype
 1927                          */
 1928                         return ttyretype(tp);
 1929                 }
 1930                 if (c == ('\t' | TTY_QUOTE) || c == ('\n' | TTY_QUOTE))
 1931                         ttyrubo(tp, 2);
 1932                 else {
 1933                         CLR(c, ~TTY_CHARMASK);
 1934                         switch (CCLASS(c)) {
 1935                         case ORDINARY:
 1936                                 ttyrubo(tp, 1);
 1937                                 break;
 1938                         case BACKSPACE:
 1939                         case CONTROL:
 1940                         case NEWLINE:
 1941                         case RETURN:
 1942                         case VTAB:
 1943                                 if (ISSET(tp->t_lflag, ECHOCTL))
 1944                                         ttyrubo(tp, 2);
 1945                                 break;
 1946                         case TAB:
 1947                                 if (tp->t_rocount < tp->t_rawq.c_cc)
 1948                                         return ttyretype(tp);
 1949                                 s = spltty();
 1950                                 savecol = tp->t_column;
 1951                                 SET(tp->t_state, TS_CNTTB);
 1952                                 SET(tp->t_lflag, FLUSHO);
 1953                                 tp->t_column = tp->t_rocol;
 1954                                 for (cp = firstc(&tp->t_rawq, &tabc, &cc); cp;
 1955                                     cp = nextc(&tp->t_rawq, cp, &tabc, &cc))
 1956                                         ttyecho(tabc, tp);
 1957                                 CLR(tp->t_lflag, FLUSHO);
 1958                                 CLR(tp->t_state, TS_CNTTB);
 1959                                 splx(s);
 1960 
 1961                                 /* savecol will now be length of the tab. */
 1962                                 savecol -= tp->t_column;
 1963                                 tp->t_column += savecol;
 1964                                 if (savecol > 8)
 1965                                         savecol = 8;    /* overflow screw */
 1966                                 while (--savecol >= 0)
 1967                                         (void)ttyoutput('\b', tp);
 1968                                 break;
 1969                         default:                        /* XXX */
 1970 #define PANICSTR        "ttyrub: would panic c = %d, val = %d"
 1971                                 (void)printf(PANICSTR "\n", c, CCLASS(c));
 1972 #ifdef notdef
 1973                                 panic(PANICSTR, c, CCLASS(c));
 1974 #endif
 1975                         }
 1976                 }
 1977         } else if (ISSET(tp->t_lflag, ECHOPRT)) {
 1978                 if (!ISSET(tp->t_state, TS_ERASE)) {
 1979                         SET(tp->t_state, TS_ERASE);
 1980                         (void)ttyoutput('\\', tp);
 1981                 }
 1982                 ttyecho(c, tp);
 1983         } else
 1984                 ttyecho(tp->t_cc[VERASE], tp);
 1985         --tp->t_rocount;
 1986         return 0;
 1987 }
 1988 
 1989 /*
 1990  * Back over cnt characters, erasing them.
 1991  */
 1992 static void
 1993 ttyrubo(struct tty *tp, int cnt)
 1994 {
 1995 
 1996         while (cnt-- > 0) {
 1997                 (void)ttyoutput('\b', tp);
 1998                 (void)ttyoutput(' ', tp);
 1999                 (void)ttyoutput('\b', tp);
 2000         }
 2001 }
 2002 
 2003 /*
 2004  * ttyretype --
 2005  *      Reprint the rawq line.  Note, it is assumed that c_cc has already
 2006  *      been checked.
 2007  */
 2008 int
 2009 ttyretype(struct tty *tp)
 2010 {
 2011         u_char *cp;
 2012         int s, c, cc;
 2013 
 2014         /* Echo the reprint character. */
 2015         if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE)
 2016                 ttyecho(tp->t_cc[VREPRINT], tp);
 2017 
 2018         (void)ttyoutput('\n', tp);
 2019 
 2020         s = spltty();
 2021         for (cp = firstc(&tp->t_canq, &c, &cc); cp;
 2022             cp = nextc(&tp->t_canq, cp, &c, &cc))
 2023                 ttyecho(c, tp);
 2024         for (cp = firstc(&tp->t_rawq, &c, &cc); cp;
 2025             cp = nextc(&tp->t_rawq, cp, &c, &cc))
 2026                 ttyecho(c, tp);
 2027         CLR(tp->t_state, TS_ERASE);
 2028         splx(s);
 2029 
 2030         tp->t_rocount = tp->t_rawq.c_cc;
 2031         tp->t_rocol = 0;
 2032         return (1);
 2033 }
 2034 
 2035 /*
 2036  * Echo a typed character to the terminal.
 2037  */
 2038 static void
 2039 ttyecho(int c, struct tty *tp)
 2040 {
 2041 
 2042         if (!ISSET(tp->t_state, TS_CNTTB))
 2043                 CLR(tp->t_lflag, FLUSHO);
 2044         if ((!ISSET(tp->t_lflag, ECHO) &&
 2045             (!ISSET(tp->t_lflag, ECHONL) || c != '\n')) ||
 2046             ISSET(tp->t_lflag, EXTPROC))
 2047                 return;
 2048         if (((ISSET(tp->t_lflag, ECHOCTL) &&
 2049              (ISSET(c, TTY_CHARMASK) <= 037 && c != '\t' && c != '\n')) ||
 2050             ISSET(c, TTY_CHARMASK) == 0177)) {
 2051                 (void)ttyoutput('^', tp);
 2052                 CLR(c, ~TTY_CHARMASK);
 2053                 if (c == 0177)
 2054                         c = '?';
 2055                 else
 2056                         c += 'A' - 1;
 2057         }
 2058         (void)ttyoutput(c, tp);
 2059 }
 2060 
 2061 /*
 2062  * Wakeup any writers if necessary.
 2063  */
 2064 void
 2065 ttwakeupwr(struct tty *tp)
 2066 {
 2067 
 2068         if (tp->t_outq.c_cc <= tp->t_lowat) {
 2069                 if (ISSET(tp->t_state, TS_ASLEEP)) {
 2070                         CLR(tp->t_state, TS_ASLEEP);
 2071                         wakeup(&tp->t_outq);
 2072                 }
 2073                 selwakeup(&tp->t_wsel);
 2074         }
 2075 }
 2076 
 2077 /*
 2078  * Wake up any readers on a tty.
 2079  */
 2080 void
 2081 ttwakeup(struct tty *tp)
 2082 {
 2083 
 2084         selwakeup(&tp->t_rsel);
 2085         if (ISSET(tp->t_state, TS_ASYNC))
 2086                 pgsignal(tp->t_pgrp, SIGIO, 1);
 2087         wakeup((caddr_t)&tp->t_rawq);
 2088 }
 2089 
 2090 /*
 2091  * Look up a code for a specified speed in a conversion table;
 2092  * used by drivers to map software speed values to hardware parameters.
 2093  */
 2094 int
 2095 ttspeedtab(int speed, const struct speedtab *table)
 2096 {
 2097 
 2098         for ( ; table->sp_speed != -1; table++)
 2099                 if (table->sp_speed == speed)
 2100                         return (table->sp_code);
 2101         return (-1);
 2102 }
 2103 
 2104 /*
 2105  * Set tty hi and low water marks.
 2106  *
 2107  * Try to arrange the dynamics so there's about one second
 2108  * from hi to low water.
 2109  */
 2110 void
 2111 ttsetwater(struct tty *tp)
 2112 {
 2113         int cps, x;
 2114 
 2115 #define CLAMP(x, h, l)  ((x) > h ? h : ((x) < l) ? l : (x))
 2116 
 2117         cps = tp->t_ospeed / 10;
 2118         tp->t_lowat = x = CLAMP(cps / 2, TTMAXLOWAT, TTMINLOWAT);
 2119         x += cps;
 2120         tp->t_hiwat = CLAMP(x, tp->t_outq.c_cn - TTHIWATMINSPACE, TTMINHIWAT);
 2121 #undef  CLAMP
 2122 }
 2123 
 2124 /*
 2125  * Get the total estcpu for a process, summing across threads.
 2126  * Returns true if at least one thread is runnable/running.
 2127  */
 2128 static int
 2129 process_sum(struct process *pr, fixpt_t *estcpup)
 2130 {
 2131         struct proc *p;
 2132         fixpt_t estcpu;
 2133         int ret;
 2134 
 2135         ret = 0;
 2136         estcpu = 0;
 2137         TAILQ_FOREACH(p, &pr->ps_threads, p_thr_link) {
 2138                 if (p->p_stat == SRUN || p->p_stat == SONPROC)
 2139                         ret = 1;
 2140                 estcpu += p->p_pctcpu;
 2141         }
 2142 
 2143         *estcpup = estcpu;
 2144         return (ret);
 2145 }
 2146 
 2147 /*
 2148  * Report on state of foreground process group.
 2149  */
 2150 void
 2151 ttyinfo(struct tty *tp)
 2152 {
 2153         struct process *pr, *pickpr;
 2154         struct proc *p, *pick;
 2155         struct timespec utime, stime;
 2156         int tmp;
 2157 
 2158         if (ttycheckoutq(tp,0) == 0)
 2159                 return;
 2160 
 2161         /* Print load average. */
 2162         tmp = (averunnable.ldavg[0] * 100 + FSCALE / 2) >> FSHIFT;
 2163         ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100);
 2164 
 2165         if (tp->t_session == NULL)
 2166                 ttyprintf(tp, "not a controlling terminal\n");
 2167         else if (tp->t_pgrp == NULL)
 2168                 ttyprintf(tp, "no foreground process group\n");
 2169         else if ((pr = LIST_FIRST(&tp->t_pgrp->pg_members)) == NULL)
 2170 empty:          ttyprintf(tp, "empty foreground process group\n");
 2171         else {
 2172                 const char *state;
 2173                 fixpt_t pctcpu, pctcpu2;
 2174                 int run, run2;
 2175                 int calc_pctcpu;
 2176                 long rss = 0;
 2177 
 2178                 /*
 2179                  * Pick the most active process:
 2180                  *  - prefer at least one running/runnable thread
 2181                  *  - prefer higher total pctcpu
 2182                  *  - prefer non-zombie
 2183                  * Otherwise take the most recently added to this process group
 2184                  */
 2185                 pickpr = pr;
 2186                 run = process_sum(pickpr, &pctcpu);
 2187                 while ((pr = LIST_NEXT(pr, ps_pglist)) != NULL) {
 2188                         run2 = process_sum(pr, &pctcpu2);
 2189                         if (run) {
 2190                                 /*
 2191                                  * pick is running; is p running w/same or
 2192                                  * more cpu?
 2193                                  */
 2194                                 if (run2 && pctcpu2 >= pctcpu)
 2195                                         goto update_pickpr;
 2196                                 continue;
 2197                         }
 2198                         /* pick isn't running; is p running *or* w/more cpu? */
 2199                         if (run2 || pctcpu2 > pctcpu)
 2200                                 goto update_pickpr;
 2201 
 2202                         /* if p has less cpu or is zombie, then it's worse */
 2203                         if (pctcpu2 < pctcpu || (pr->ps_flags & PS_ZOMBIE))
 2204                                 continue;
 2205 update_pickpr:
 2206                         pickpr = pr;
 2207                         run = run2;
 2208                         pctcpu = pctcpu2;
 2209                 }
 2210 
 2211                 /* Calculate percentage cpu, resident set size. */
 2212                 calc_pctcpu = (pctcpu * 10000 + FSCALE / 2) >> FSHIFT;
 2213                 if ((pickpr->ps_flags & (PS_EMBRYO | PS_ZOMBIE)) == 0 &&
 2214                     pickpr->ps_vmspace != NULL)
 2215                         rss = vm_resident_count(pickpr->ps_vmspace);
 2216 
 2217                 calctsru(&pickpr->ps_tu, &utime, &stime, NULL);
 2218 
 2219                 /* Round up and print user time. */
 2220                 utime.tv_nsec += 5000000;
 2221                 if (utime.tv_nsec >= 1000000000) {
 2222                         utime.tv_sec += 1;
 2223                         utime.tv_nsec -= 1000000000;
 2224                 }
 2225 
 2226                 /* Round up and print system time. */
 2227                 stime.tv_nsec += 5000000;
 2228                 if (stime.tv_nsec >= 1000000000) {
 2229                         stime.tv_sec += 1;
 2230                         stime.tv_nsec -= 1000000000;
 2231                 }
 2232 
 2233                 /*
 2234                  * Find the most active thread:
 2235                  *  - prefer runnable
 2236                  *  - prefer higher pctcpu
 2237                  *  - prefer living
 2238                  * Otherwise take the newest thread
 2239                  */
 2240                 pick = p = TAILQ_FIRST(&pickpr->ps_threads);
 2241                 if (p == NULL)
 2242                         goto empty;
 2243                 run = p->p_stat == SRUN || p->p_stat == SONPROC;
 2244                 pctcpu = p->p_pctcpu;
 2245                 while ((p = TAILQ_NEXT(p, p_thr_link)) != NULL) {
 2246                         run2 = p->p_stat == SRUN || p->p_stat == SONPROC;
 2247                         pctcpu2 = p->p_pctcpu;
 2248                         if (run) {
 2249                                 /*
 2250                                  * pick is running; is p running w/same or
 2251                                  * more cpu?
 2252                                  */
 2253                                 if (run2 && pctcpu2 >= pctcpu)
 2254                                         goto update_pick;
 2255                                 continue;
 2256                         }
 2257                         /* pick isn't running; is p running *or* w/more cpu? */
 2258                         if (run2 || pctcpu2 > pctcpu)
 2259                                 goto update_pick;
 2260 
 2261                         /* if p has less cpu or is exiting, then it's worse */
 2262                         if (pctcpu2 < pctcpu || p->p_flag & P_WEXIT)
 2263                                 continue;
 2264 update_pick:
 2265                         pick = p;
 2266                         run = run2;
 2267                         pctcpu = p->p_pctcpu;
 2268                 }
 2269                 state = pick->p_stat == SONPROC ? "running" :
 2270                         pick->p_stat == SRUN ? "runnable" :
 2271                         pick->p_wmesg ? pick->p_wmesg : "iowait";
 2272 
 2273                 ttyprintf(tp,
 2274                     " cmd: %s %d [%s] %lld.%02ldu %lld.%02lds %d%% %ldk\n",
 2275                     pickpr->ps_comm, pickpr->ps_pid, state,
 2276                     (long long)utime.tv_sec, utime.tv_nsec / 10000000,
 2277                     (long long)stime.tv_sec, stime.tv_nsec / 10000000,
 2278                     calc_pctcpu / 100, rss);
 2279         }
 2280         tp->t_rocount = 0;      /* so pending input will be retyped if BS */
 2281 }
 2282 
 2283 /*
 2284  * Output char to tty; console putchar style.
 2285  */
 2286 int
 2287 tputchar(int c, struct tty *tp)
 2288 {
 2289         int s;
 2290 
 2291         s = spltty();
 2292         if (ISSET(tp->t_state, TS_ISOPEN) == 0 ||
 2293             !(ISSET(tp->t_state, TS_CARR_ON) || ISSET(tp->t_cflag, CLOCAL))) {
 2294                 splx(s);
 2295                 return (-1);
 2296         }
 2297         if (c == '\n')
 2298                 (void)ttyoutput('\r', tp);
 2299         (void)ttyoutput(c, tp);
 2300         ttstart(tp);
 2301         splx(s);
 2302         return (0);
 2303 }
 2304 
 2305 /*
 2306  * Sleep on chan, returning ERESTART if tty changed while we napped and
 2307  * returning any errors (e.g. EINTR/ETIMEDOUT) reported by tsleep.  If
 2308  * the tty is revoked, restarting a pending call will redo validation done
 2309  * at the start of the call.
 2310  */
 2311 int
 2312 ttysleep(struct tty *tp, void *chan, int pri, char *wmesg)
 2313 {
 2314         return (ttysleep_nsec(tp, chan, pri, wmesg, INFSLP));
 2315 }
 2316 
 2317 int
 2318 ttysleep_nsec(struct tty *tp, void *chan, int pri, char *wmesg, uint64_t nsecs)
 2319 {
 2320         int error;
 2321         short gen;
 2322 
 2323         gen = tp->t_gen;
 2324         if ((error = tsleep_nsec(chan, pri, wmesg, nsecs)) != 0)
 2325                 return (error);
 2326         return (tp->t_gen == gen ? 0 : ERESTART);
 2327 }
 2328 
 2329 /*
 2330  * Initialise the global tty list.
 2331  */
 2332 void
 2333 tty_init(void)
 2334 {
 2335 
 2336         TAILQ_INIT(&ttylist);
 2337         tty_count = 0;
 2338 }
 2339 
 2340 /*
 2341  * Allocate a tty structure and its associated buffers, and attach it to the
 2342  * tty list.
 2343  */
 2344 struct tty *
 2345 ttymalloc(int baud)
 2346 {
 2347         struct tty *tp;
 2348 
 2349         tp = malloc(sizeof(struct tty), M_TTYS, M_WAITOK|M_ZERO);
 2350 
 2351         if (baud == 0)
 2352                 baud = 115200;
 2353 
 2354         if (baud <= 9600)
 2355                 tp->t_qlen = 1024;
 2356         else if (baud <= 115200)
 2357                 tp->t_qlen = 4096;
 2358         else
 2359                 tp->t_qlen = 8192;
 2360         clalloc(&tp->t_rawq, tp->t_qlen, 1);
 2361         clalloc(&tp->t_canq, tp->t_qlen, 1);
 2362         /* output queue doesn't need quoting */
 2363         clalloc(&tp->t_outq, tp->t_qlen, 0);
 2364 
 2365         rw_enter_write(&ttylist_lock);
 2366         TAILQ_INSERT_TAIL(&ttylist, tp, tty_link);
 2367         ++tty_count;
 2368         rw_exit_write(&ttylist_lock);
 2369 
 2370         timeout_set(&tp->t_rstrt_to, ttrstrt, tp);
 2371 
 2372         return(tp);
 2373 }
 2374 
 2375 
 2376 /*
 2377  * Free a tty structure and its buffers, after removing it from the tty list.
 2378  */
 2379 void
 2380 ttyfree(struct tty *tp)
 2381 {
 2382         int s;
 2383 
 2384         rw_enter_write(&ttylist_lock);
 2385         --tty_count;
 2386 #ifdef DIAGNOSTIC
 2387         if (tty_count < 0)
 2388                 panic("ttyfree: tty_count < 0");
 2389 #endif
 2390         TAILQ_REMOVE(&ttylist, tp, tty_link);
 2391         rw_exit_write(&ttylist_lock);
 2392 
 2393         s = spltty();
 2394         klist_invalidate(&tp->t_rsel.si_note);
 2395         klist_invalidate(&tp->t_wsel.si_note);
 2396         splx(s);
 2397 
 2398         clfree(&tp->t_rawq);
 2399         clfree(&tp->t_canq);
 2400         clfree(&tp->t_outq);
 2401         free(tp, M_TTYS, sizeof(*tp));
 2402 }
 2403 
 2404 void
 2405 ttystats_init(struct itty **ttystats, int *ttycp, size_t *ttystatssiz)
 2406 {
 2407         int ntty = 0, ttyc;
 2408         struct itty *itp;
 2409         struct tty *tp;
 2410 
 2411         ttyc = tty_count;
 2412         *ttystatssiz = ttyc * sizeof(struct itty);
 2413         *ttystats = mallocarray(ttyc, sizeof(struct itty),
 2414             M_SYSCTL, M_WAITOK|M_ZERO);
 2415 
 2416         rw_enter_write(&ttylist_lock);
 2417         for (tp = TAILQ_FIRST(&ttylist), itp = *ttystats; tp && ntty++ < ttyc;
 2418             tp = TAILQ_NEXT(tp, tty_link), itp++) {
 2419                 itp->t_dev = tp->t_dev;
 2420                 itp->t_rawq_c_cc = tp->t_rawq.c_cc;
 2421                 itp->t_canq_c_cc = tp->t_canq.c_cc;
 2422                 itp->t_outq_c_cc = tp->t_outq.c_cc;
 2423                 itp->t_hiwat = tp->t_hiwat;
 2424                 itp->t_lowat = tp->t_lowat;
 2425                 if (ISSET(tp->t_oflag, OPOST))
 2426                         itp->t_column = tp->t_column;
 2427                 itp->t_state = tp->t_state;
 2428                 itp->t_session = tp->t_session;
 2429                 if (tp->t_pgrp)
 2430                         itp->t_pgrp_pg_id = tp->t_pgrp->pg_id;
 2431                 else
 2432                         itp->t_pgrp_pg_id = 0;
 2433                 itp->t_line = tp->t_line;
 2434         }
 2435         rw_exit_write(&ttylist_lock);
 2436         *ttycp = ntty;
 2437 }
 2438 
 2439 /*
 2440  * Return tty-related information.
 2441  */
 2442 int
 2443 sysctl_tty(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
 2444     size_t newlen)
 2445 {
 2446         int err;
 2447 
 2448         if (namelen != 1)
 2449                 return (ENOTDIR);
 2450 
 2451         switch (name[0]) {
 2452         case KERN_TTY_TKNIN:
 2453                 return (sysctl_rdquad(oldp, oldlenp, newp, tk_nin));
 2454         case KERN_TTY_TKNOUT:
 2455                 return (sysctl_rdquad(oldp, oldlenp, newp, tk_nout));
 2456         case KERN_TTY_TKRAWCC:
 2457                 return (sysctl_rdquad(oldp, oldlenp, newp, tk_rawcc));
 2458         case KERN_TTY_TKCANCC:
 2459                 return (sysctl_rdquad(oldp, oldlenp, newp, tk_cancc));
 2460         case KERN_TTY_INFO:
 2461             {
 2462                 struct itty *ttystats;
 2463                 size_t ttystatssiz;
 2464                 int ttyc;
 2465 
 2466                 ttystats_init(&ttystats, &ttyc, &ttystatssiz);
 2467                 err = sysctl_rdstruct(oldp, oldlenp, newp, ttystats,
 2468                     ttyc * sizeof(struct itty));
 2469                 free(ttystats, M_SYSCTL, ttystatssiz);
 2470                 return (err);
 2471             }
 2472         default:
 2473 #if NPTY > 0
 2474                 return (sysctl_pty(name, namelen, oldp, oldlenp, newp, newlen));
 2475 #else
 2476                 return (EOPNOTSUPP);
 2477 #endif
 2478         }
 2479         /* NOTREACHED */
 2480 }
 2481 
 2482 void
 2483 ttytstamp(struct tty *tp, int octs, int ncts, int odcd, int ndcd)
 2484 {
 2485         int doit = 0;
 2486 
 2487         if (ncts ^ octs)
 2488                 doit |= ncts ? ISSET(tp->t_flags, TS_TSTAMPCTSSET) :
 2489                     ISSET(tp->t_flags, TS_TSTAMPCTSCLR);
 2490         if (ndcd ^ odcd)
 2491                 doit |= ndcd ? ISSET(tp->t_flags, TS_TSTAMPDCDSET) :
 2492                     ISSET(tp->t_flags, TS_TSTAMPDCDCLR);
 2493 
 2494         if (doit)
 2495                 microtime(&tp->t_tv);
 2496 }

Cache object: 0b625d2a80081dba7874ffef906f9307


[ 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.