LCOV - code coverage report
Current view: top level - kern - tty.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 1212 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 47 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13