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


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

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

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

    1 /*-
    2  * (MPSAFE)
    3  *
    4  * Copyright (c) 1982, 1986, 1990, 1991, 1993
    5  *      The Regents of the University of California.  All rights reserved.
    6  * (c) UNIX System Laboratories, Inc.
    7  * All or some portions of this file are derived from material licensed
    8  * to the University of California by American Telephone and Telegraph
    9  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
   10  * the permission of UNIX System Laboratories, Inc.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  * 3. Neither the name of the University nor the names of its contributors
   21  *    may be used to endorse or promote products derived from this software
   22  *    without specific prior written permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   34  * SUCH DAMAGE.
   35  *
   36  *      @(#)tty.c       8.8 (Berkeley) 1/21/94
   37  * $FreeBSD: src/sys/kern/tty.c,v 1.129.2.5 2002/03/11 01:32:31 dd Exp $
   38  */
   39 
   40 /*
   41  * MPSAFE NOTE:
   42  * Almost all functions in this file are acquiring the tty token due to their
   43  * access and modifications of the 'tp' (struct tty) objects.
   44  */
   45 
   46 /*-
   47  * TODO:
   48  *      o Fix races for sending the start char in ttyflush().
   49  *      o Handle inter-byte timeout for "MIN > 0, TIME > 0" in ttyselect().
   50  *        With luck, there will be MIN chars before select() returns().
   51  *      o Handle CLOCAL consistently for ptys.  Perhaps disallow setting it.
   52  *      o Don't allow input in TS_ZOMBIE case.  It would be visible through
   53  *        FIONREAD.
   54  *      o Do the new sio locking stuff here and use it to avoid special
   55  *        case for EXTPROC?
   56  *      o Lock PENDIN too?
   57  *      o Move EXTPROC and/or PENDIN to t_state?
   58  *      o Wrap most of ttioctl in spltty/splx.
   59  *      o Implement TIOCNOTTY or remove it from <sys/ioctl.h>.
   60  *      o Send STOP if IXOFF is toggled off while TS_TBLOCK is set.
   61  *      o Don't allow certain termios flags to affect disciplines other
   62  *        than TTYDISC.  Cancel their effects before switch disciplines
   63  *        and ignore them if they are set while we are in another
   64  *        discipline.
   65  *      o Now that historical speed conversions are handled here, don't
   66  *        do them in drivers.
   67  *      o Check for TS_CARR_ON being set while everything is closed and not
   68  *        waiting for carrier.  TS_CARR_ON isn't cleared if nothing is open,
   69  *        so it would live until the next open even if carrier drops.
   70  *      o Restore TS_WOPEN since it is useful in pstat.  It must be cleared
   71  *        only when _all_ openers leave open().
   72  */
   73 
   74 #include "opt_compat.h"
   75 #include "opt_uconsole.h"
   76 
   77 #include <sys/param.h>
   78 #include <sys/systm.h>
   79 #include <sys/filio.h>
   80 #if defined(COMPAT_43)
   81 #include <sys/ioctl_compat.h>
   82 #endif
   83 #include <sys/proc.h>
   84 #include <sys/priv.h>
   85 #define TTYDEFCHARS
   86 #include <sys/tty.h>
   87 #include <sys/clist.h>
   88 #undef  TTYDEFCHARS
   89 #include <sys/fcntl.h>
   90 #include <sys/conf.h>
   91 #include <sys/dkstat.h>
   92 #include <sys/kernel.h>
   93 #include <sys/vnode.h>
   94 #include <sys/signalvar.h>
   95 #include <sys/signal2.h>
   96 #include <sys/resourcevar.h>
   97 #include <sys/malloc.h>
   98 #include <sys/filedesc.h>
   99 #include <sys/sysctl.h>
  100 #include <sys/thread2.h>
  101 
  102 #include <vm/vm.h>
  103 #include <sys/lock.h>
  104 #include <vm/pmap.h>
  105 #include <vm/vm_map.h>
  106 #include <vm/vm_extern.h>
  107 
  108 MALLOC_DEFINE(M_TTYS, "ttys", "tty data structures");
  109 
  110 static int      proc_compare (struct proc *p1, struct proc *p2);
  111 static int      ttnread (struct tty *tp);
  112 static void     ttyecho (int c, struct tty *tp);
  113 static int      ttyoutput (int c, struct tty *tp);
  114 static void     ttypend (struct tty *tp);
  115 static void     ttyretype (struct tty *tp);
  116 static void     ttyrub (int c, struct tty *tp);
  117 static void     ttyrubo (struct tty *tp, int cnt);
  118 static void     ttyunblock (struct tty *tp);
  119 static int      ttywflush (struct tty *tp);
  120 static int      filt_ttyread (struct knote *kn, long hint);
  121 static void     filt_ttyrdetach (struct knote *kn);
  122 static int      filt_ttywrite (struct knote *kn, long hint);
  123 static void     filt_ttywdetach (struct knote *kn);
  124 
  125 /*
  126  * Table with character classes and parity. The 8th bit indicates parity,
  127  * the 7th bit indicates the character is an alphameric or underscore (for
  128  * ALTWERASE), and the low 6 bits indicate delay type.  If the low 6 bits
  129  * are 0 then the character needs no special processing on output; classes
  130  * other than 0 might be translated or (not currently) require delays.
  131  */
  132 #define E       0x00    /* Even parity. */
  133 #define O       0x80    /* Odd parity. */
  134 #define PARITY(c)       (char_type[c] & O)
  135 
  136 #define ALPHA   0x40    /* Alpha or underscore. */
  137 #define ISALPHA(c)      (char_type[(c) & TTY_CHARMASK] & ALPHA)
  138 
  139 #define CCLASSMASK      0x3f
  140 #define CCLASS(c)       (char_type[c] & CCLASSMASK)
  141 
  142 #define BS      BACKSPACE
  143 #define CC      CONTROL
  144 #define CR      RETURN
  145 #define NA      ORDINARY | ALPHA
  146 #define NL      NEWLINE
  147 #define NO      ORDINARY
  148 #define TB      TAB
  149 #define VT      VTAB
  150 
  151 static u_char const char_type[] = {
  152         E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* nul - bel */
  153         O|BS, E|TB, E|NL, O|CC, E|VT, O|CR, O|CC, E|CC, /* bs - si */
  154         O|CC, E|CC, E|CC, O|CC, E|CC, O|CC, O|CC, E|CC, /* dle - etb */
  155         E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* can - us */
  156         O|NO, E|NO, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* sp - ' */
  157         E|NO, O|NO, O|NO, E|NO, O|NO, E|NO, E|NO, O|NO, /* ( - / */
  158         E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* 0 - 7 */
  159         O|NA, E|NA, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* 8 - ? */
  160         O|NO, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* @ - G */
  161         E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* H - O */
  162         E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* P - W */
  163         O|NA, E|NA, E|NA, O|NO, E|NO, O|NO, O|NO, O|NA, /* X - _ */
  164         E|NO, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* ` - g */
  165         O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* h - o */
  166         O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* p - w */
  167         E|NA, O|NA, O|NA, E|NO, O|NO, E|NO, E|NO, O|CC, /* x - del */
  168         /*
  169          * Meta chars; should be settable per character set;
  170          * for now, treat them all as normal characters.
  171          */
  172         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  173         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  174         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  175         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  176         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  177         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  178         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  179         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  180         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  181         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  182         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  183         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  184         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  185         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  186         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  187         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  188 };
  189 #undef  BS
  190 #undef  CC
  191 #undef  CR
  192 #undef  NA
  193 #undef  NL
  194 #undef  NO
  195 #undef  TB
  196 #undef  VT
  197 
  198 /* Macros to clear/set/test flags. */
  199 #define SET(t, f)       (t) |= (f)
  200 #define CLR(t, f)       (t) &= ~(f)
  201 #define ISSET(t, f)     ((t) & (f))
  202 
  203 #undef MAX_INPUT                /* XXX wrong in <sys/syslimits.h> */
  204 #define MAX_INPUT       TTYHOG  /* XXX limit is usually larger for !ICANON */
  205 
  206 uint64_t tk_nin;
  207 SYSCTL_OPAQUE(_kern, OID_AUTO, tk_nin, CTLFLAG_RD, &tk_nin, sizeof(tk_nin),
  208     "LU", "TTY input statistic");
  209 uint64_t tk_nout;
  210 SYSCTL_OPAQUE(_kern, OID_AUTO, tk_nout, CTLFLAG_RD, &tk_nout, sizeof(tk_nout),
  211     "LU", "TTY output statistic");
  212 uint64_t tk_rawcc;
  213 
  214 /*
  215  * list of struct tty where pstat(8) can pick it up with sysctl
  216  */
  217 static TAILQ_HEAD(, tty) tty_list = TAILQ_HEAD_INITIALIZER(tty_list);
  218 
  219 /*
  220  * Initial open of tty, or (re)entry to standard tty line discipline.
  221  */
  222 int
  223 ttyopen(cdev_t device, struct tty *tp)
  224 {
  225         crit_enter();
  226         lwkt_gettoken(&tty_token);
  227         tp->t_dev = device;
  228         if (!ISSET(tp->t_state, TS_ISOPEN)) {
  229                 SET(tp->t_state, TS_ISOPEN);
  230                 if (ISSET(tp->t_cflag, CLOCAL)) {
  231                         SET(tp->t_state, TS_CONNECTED);
  232                 }
  233                 bzero(&tp->t_winsize, sizeof(tp->t_winsize));
  234         }
  235         ttsetwater(tp);
  236         lwkt_reltoken(&tty_token);
  237         crit_exit();
  238         return (0);
  239 }
  240 
  241 /*
  242  * Handle close() on a tty line: flush and set to initial state,
  243  * bumping generation number so that pending read/write calls
  244  * can detect recycling of the tty.
  245  *
  246  * XXX our caller should have done `spltty(); l_close(); ttyclose();'
  247  * and l_close() should have flushed, but we repeat the spltty() and
  248  * the flush in case there are buggy callers.
  249  */
  250 int
  251 ttyclose(struct tty *tp)
  252 {
  253         crit_enter();
  254         lwkt_gettoken(&tty_token);
  255         funsetown(&tp->t_sigio);
  256         if (constty == tp)
  257                 constty = NULL;
  258 
  259         ttyflush(tp, FREAD | FWRITE);
  260         clist_free_cblocks(&tp->t_canq);
  261         clist_free_cblocks(&tp->t_outq);
  262         clist_free_cblocks(&tp->t_rawq);
  263 
  264         tp->t_gen++;
  265         tp->t_line = TTYDISC;
  266         ttyclearsession(tp);
  267         tp->t_state &= TS_REGISTERED;   /* clear all bits except */
  268         lwkt_reltoken(&tty_token);
  269         crit_exit();
  270         return (0);
  271 }
  272 
  273 /*
  274  * Disassociate the tty from its session.  Traditionally this has only been
  275  * a half-close, meaning that the session was still allowed to point at the
  276  * tty (resulting in the tty in the ps command showing something like 'p0-'),
  277  * even though the tty is no longer pointing at the session.
  278  *
  279  * The half close seems to be useful only for 'ps' output but there is as
  280  * yet no reason to remove the feature.  The full-close code is currently
  281  * #if 0'd out.  See also sess_rele() in kern/kern_proc.c.
  282  */
  283 void
  284 ttyclearsession(struct tty *tp)
  285 {
  286         struct session *sp;
  287         struct pgrp *opgrp;
  288 
  289         lwkt_gettoken(&tty_token);
  290         opgrp = tp->t_pgrp;
  291         tp->t_pgrp = NULL;
  292         if (opgrp) {
  293                 pgrel(opgrp);
  294                 opgrp = NULL;
  295         }
  296 
  297         if ((sp = tp->t_session) != NULL) {
  298                 tp->t_session = NULL;
  299 #ifdef TTY_DO_FULL_CLOSE
  300                 /* FULL CLOSE (not yet) */
  301                 if (sp->s_ttyp == tp) {
  302                         sp->s_ttyp = NULL;
  303                         ttyunhold(tp);
  304                 } else {
  305                         kprintf("ttyclearsession: warning: sp->s_ttyp != tp "
  306                                 "%p/%p\n", sp->s_ttyp, tp);
  307                 }
  308 #endif
  309         }
  310         lwkt_reltoken(&tty_token);
  311 }
  312 
  313 /*
  314  * Release the tty vnode association for a session.  This is the 
  315  * 'other half' of the close.  Because multiple opens of /dev/tty
  316  * only generate a single open to the actual tty, the file modes
  317  * are locked to FREAD|FWRITE.
  318  *
  319  * If dorevoke is non-zero, the session is also revoked.  We have to
  320  * close the vnode if VCTTYISOPEN is set.
  321  */
  322 void
  323 ttyclosesession(struct session *sp, int dorevoke)
  324 {
  325         struct vnode *vp;
  326 
  327         lwkt_gettoken(&tty_token);
  328 retry:
  329         /*
  330          * There may not be a controlling terminal or it may have been closed
  331          * out from under us.
  332          */
  333         if ((vp = sp->s_ttyvp) == NULL) {
  334                 lwkt_reltoken(&tty_token);
  335                 return;
  336         }
  337 
  338         /*
  339          * We need a lock if we have to close or revoke.
  340          */
  341         if ((vp->v_flag & VCTTYISOPEN) || dorevoke) {
  342                 vhold(vp);
  343                 if (vn_lock(vp, LK_EXCLUSIVE | LK_RETRY | LK_FAILRECLAIM)) {
  344                         vdrop(vp);
  345                         goto retry;
  346                 }
  347 
  348                 /*
  349                  * Retry if the vnode was ripped out from under us
  350                  */
  351                 if (vp != sp->s_ttyvp) {
  352                         vn_unlock(vp);
  353                         vdrop(vp);
  354                         goto retry;
  355                 }
  356 
  357                 /*
  358                  * Close and revoke as needed
  359                  */
  360                 sp->s_ttyvp = NULL;
  361                 if (vp->v_flag & VCTTYISOPEN) {
  362                         vclrflags(vp, VCTTYISOPEN);
  363                         VOP_CLOSE(vp, FREAD|FWRITE);
  364                 }
  365                 vn_unlock(vp);
  366                 if (dorevoke)
  367                         vrevoke(vp, proc0.p_ucred);
  368                 vdrop(vp);
  369         } else {
  370                 sp->s_ttyvp = NULL;
  371         }
  372         vrele(vp);
  373         lwkt_reltoken(&tty_token);
  374 }
  375 
  376 #define FLUSHQ(q) {                                                     \
  377         if ((q)->c_cc)                                                  \
  378                 ndflush(q, (q)->c_cc);                                  \
  379 }
  380 
  381 /* Is 'c' a line delimiter ("break" character)? */
  382 #define TTBREAKC(c, lflag)                                                      \
  383         ((c) == '\n' || (((c) == cc[VEOF] ||                            \
  384           (c) == cc[VEOL] || ((c) == cc[VEOL2] && lflag & IEXTEN)) &&   \
  385          (c) != _POSIX_VDISABLE))
  386 
  387 /*
  388  * Process input of a single character received on a tty.
  389  */
  390 int
  391 ttyinput(int c, struct tty *tp)
  392 {
  393         tcflag_t iflag, lflag;
  394         cc_t *cc;
  395         int i, err;
  396 
  397         lwkt_gettoken(&tty_token);
  398         /*
  399          * If input is pending take it first.
  400          */
  401         lflag = tp->t_lflag;
  402         if (ISSET(lflag, PENDIN))
  403                 ttypend(tp);
  404         /*
  405          * Gather stats.
  406          */
  407         if (ISSET(lflag, ICANON))
  408                 ++tp->t_cancc;
  409         else
  410                 ++tp->t_rawcc;
  411         ++tk_nin;
  412 
  413         /*
  414          * Block further input iff:
  415          * current input > threshold AND input is available to user program
  416          * AND input flow control is enabled and not yet invoked.
  417          * The 3 is slop for PARMRK.
  418          */
  419         iflag = tp->t_iflag;
  420         if (tp->t_rawq.c_cc + tp->t_canq.c_cc > tp->t_ihiwat - 3 &&
  421             (!ISSET(lflag, ICANON) || tp->t_canq.c_cc != 0) &&
  422             (ISSET(tp->t_cflag, CRTS_IFLOW) || ISSET(iflag, IXOFF)) &&
  423             !ISSET(tp->t_state, TS_TBLOCK))
  424                 ttyblock(tp);
  425 
  426         /* Handle exceptional conditions (break, parity, framing). */
  427         cc = tp->t_cc;
  428         err = (ISSET(c, TTY_ERRORMASK));
  429         if (err) {
  430                 CLR(c, TTY_ERRORMASK);
  431                 if (ISSET(err, TTY_BI)) {
  432                         if (ISSET(iflag, IGNBRK)) {
  433                                 lwkt_reltoken(&tty_token);
  434                                 return (0);
  435                         }
  436                         if (ISSET(iflag, BRKINT)) {
  437                                 ttyflush(tp, FREAD | FWRITE);
  438                                 pgsignal(tp->t_pgrp, SIGINT, 1);
  439                                 goto endcase;
  440                         }
  441                         if (ISSET(iflag, PARMRK))
  442                                 goto parmrk;
  443                 } else if ((ISSET(err, TTY_PE) && ISSET(iflag, INPCK))
  444                         || ISSET(err, TTY_FE)) {
  445                         if (ISSET(iflag, IGNPAR)) {
  446                                 lwkt_reltoken(&tty_token);
  447                                 return (0);
  448                         }
  449                         else if (ISSET(iflag, PARMRK)) {
  450 parmrk:
  451                                 if (tp->t_rawq.c_cc + tp->t_canq.c_cc >
  452                                     MAX_INPUT - 3)
  453                                         goto input_overflow;
  454                                 clist_putc(0377 | TTY_QUOTE, &tp->t_rawq);
  455                                 clist_putc(0 | TTY_QUOTE, &tp->t_rawq);
  456                                 clist_putc(c | TTY_QUOTE, &tp->t_rawq);
  457                                 goto endcase;
  458                         } else
  459                                 c = 0;
  460                 }
  461         }
  462 
  463         if (!ISSET(tp->t_state, TS_TYPEN) && ISSET(iflag, ISTRIP))
  464                 CLR(c, 0x80);
  465         if (!ISSET(lflag, EXTPROC)) {
  466                 /*
  467                  * Check for literal nexting very first
  468                  */
  469                 if (ISSET(tp->t_state, TS_LNCH)) {
  470                         SET(c, TTY_QUOTE);
  471                         CLR(tp->t_state, TS_LNCH);
  472                 }
  473                 /*
  474                  * Scan for special characters.  This code
  475                  * is really just a big case statement with
  476                  * non-constant cases.  The bottom of the
  477                  * case statement is labeled ``endcase'', so goto
  478                  * it after a case match, or similar.
  479                  */
  480 
  481                 /*
  482                  * Control chars which aren't controlled
  483                  * by ICANON, ISIG, or IXON.
  484                  */
  485                 if (ISSET(lflag, IEXTEN)) {
  486                         if (CCEQ(cc[VLNEXT], c)) {
  487                                 if (ISSET(lflag, ECHO)) {
  488                                         if (ISSET(lflag, ECHOE)) {
  489                                                 (void)ttyoutput('^', tp);
  490                                                 (void)ttyoutput('\b', tp);
  491                                         } else
  492                                                 ttyecho(c, tp);
  493                                 }
  494                                 SET(tp->t_state, TS_LNCH);
  495                                 goto endcase;
  496                         }
  497                         if (CCEQ(cc[VDISCARD], c)) {
  498                                 if (ISSET(lflag, FLUSHO))
  499                                         CLR(tp->t_lflag, FLUSHO);
  500                                 else {
  501                                         ttyflush(tp, FWRITE);
  502                                         ttyecho(c, tp);
  503                                         if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
  504                                                 ttyretype(tp);
  505                                         SET(tp->t_lflag, FLUSHO);
  506                                 }
  507                                 goto startoutput;
  508                         }
  509                 }
  510                 /*
  511                  * Signals.
  512                  */
  513                 if (ISSET(lflag, ISIG)) {
  514                         if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) {
  515                                 if (!ISSET(lflag, NOFLSH))
  516                                         ttyflush(tp, FREAD | FWRITE);
  517                                 ttyecho(c, tp);
  518                                 pgsignal(tp->t_pgrp,
  519                                     CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1);
  520                                 goto endcase;
  521                         }
  522                         if (CCEQ(cc[VSUSP], c)) {
  523                                 if (!ISSET(lflag, NOFLSH))
  524                                         ttyflush(tp, FREAD);
  525                                 ttyecho(c, tp);
  526                                 pgsignal(tp->t_pgrp, SIGTSTP, 1);
  527                                 goto endcase;
  528                         }
  529                 }
  530                 /*
  531                  * Handle start/stop characters.
  532                  */
  533                 if (ISSET(iflag, IXON)) {
  534                         if (CCEQ(cc[VSTOP], c)) {
  535                                 if (!ISSET(tp->t_state, TS_TTSTOP)) {
  536                                         SET(tp->t_state, TS_TTSTOP);
  537                                         (*tp->t_stop)(tp, 0);
  538                                         lwkt_reltoken(&tty_token);
  539                                         return (0);
  540                                 }
  541                                 if (!CCEQ(cc[VSTART], c)) {
  542                                         lwkt_reltoken(&tty_token);
  543                                         return (0);
  544                                 }
  545                                 /*
  546                                  * if VSTART == VSTOP then toggle
  547                                  */
  548                                 goto endcase;
  549                         }
  550                         if (CCEQ(cc[VSTART], c))
  551                                 goto restartoutput;
  552                 }
  553                 /*
  554                  * IGNCR, ICRNL, & INLCR
  555                  */
  556                 if (c == '\r') {
  557                         if (ISSET(iflag, IGNCR)) {
  558                                 lwkt_reltoken(&tty_token);
  559                                 return (0);
  560                         }
  561                         else if (ISSET(iflag, ICRNL))
  562                                 c = '\n';
  563                 } else if (c == '\n' && ISSET(iflag, INLCR))
  564                         c = '\r';
  565         }
  566         if (!ISSET(tp->t_lflag, EXTPROC) && ISSET(lflag, ICANON)) {
  567                 /*
  568                  * From here on down canonical mode character
  569                  * processing takes place.
  570                  */
  571                 /*
  572                  * erase or erase2 (^H / ^?)
  573                  */
  574                 if (CCEQ(cc[VERASE], c) || CCEQ(cc[VERASE2], c) ) {
  575                         if (tp->t_rawq.c_cc)
  576                                 ttyrub(clist_unputc(&tp->t_rawq), tp);
  577                         goto endcase;
  578                 }
  579                 /*
  580                  * kill (^U)
  581                  */
  582                 if (CCEQ(cc[VKILL], c)) {
  583                         if (ISSET(lflag, ECHOKE) &&
  584                             tp->t_rawq.c_cc == tp->t_rocount &&
  585                             !ISSET(lflag, ECHOPRT))
  586                                 while (tp->t_rawq.c_cc)
  587                                         ttyrub(clist_unputc(&tp->t_rawq), tp);
  588                         else {
  589                                 ttyecho(c, tp);
  590                                 if (ISSET(lflag, ECHOK) ||
  591                                     ISSET(lflag, ECHOKE))
  592                                         ttyecho('\n', tp);
  593                                 FLUSHQ(&tp->t_rawq);
  594                                 tp->t_rocount = 0;
  595                         }
  596                         CLR(tp->t_state, TS_LOCAL);
  597                         goto endcase;
  598                 }
  599                 /*
  600                  * word erase (^W)
  601                  */
  602                 if (CCEQ(cc[VWERASE], c) && ISSET(lflag, IEXTEN)) {
  603                         int ctype;
  604 
  605                         /*
  606                          * erase whitespace
  607                          */
  608                         while ((c = clist_unputc(&tp->t_rawq)) == ' ' || c == '\t')
  609                                 ttyrub(c, tp);
  610                         if (c == -1)
  611                                 goto endcase;
  612                         /*
  613                          * erase last char of word and remember the
  614                          * next chars type (for ALTWERASE)
  615                          */
  616                         ttyrub(c, tp);
  617                         c = clist_unputc(&tp->t_rawq);
  618                         if (c == -1)
  619                                 goto endcase;
  620                         if (c == ' ' || c == '\t') {
  621                                 clist_putc(c, &tp->t_rawq);
  622                                 goto endcase;
  623                         }
  624                         ctype = ISALPHA(c);
  625                         /*
  626                          * erase rest of word
  627                          */
  628                         do {
  629                                 ttyrub(c, tp);
  630                                 c = clist_unputc(&tp->t_rawq);
  631                                 if (c == -1)
  632                                         goto endcase;
  633                         } while (c != ' ' && c != '\t' &&
  634                             (!ISSET(lflag, ALTWERASE) || ISALPHA(c) == ctype));
  635                         clist_putc(c, &tp->t_rawq);
  636                         goto endcase;
  637                 }
  638                 /*
  639                  * reprint line (^R)
  640                  */
  641                 if (CCEQ(cc[VREPRINT], c) && ISSET(lflag, IEXTEN)) {
  642                         ttyretype(tp);
  643                         goto endcase;
  644                 }
  645                 /*
  646                  * ^T - kernel info and generate SIGINFO
  647                  */
  648                 if (CCEQ(cc[VSTATUS], c) && ISSET(lflag, IEXTEN)) {
  649                         if (ISSET(lflag, ISIG))
  650                                 pgsignal(tp->t_pgrp, SIGINFO, 1);
  651                         if (!ISSET(lflag, NOKERNINFO))
  652                                 ttyinfo(tp);
  653                         goto endcase;
  654                 }
  655                 if (CCEQ(cc[VCHECKPT], c) && ISSET(lflag, IEXTEN)) {
  656                         if (ISSET(lflag, ISIG))
  657                                 pgsignal(tp->t_pgrp, SIGCKPT, 1);
  658                         goto endcase;
  659                 }
  660         }
  661         /*
  662          * Check for input buffer overflow
  663          */
  664         if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= MAX_INPUT) {
  665 input_overflow:
  666                 if (ISSET(iflag, IMAXBEL)) {
  667                         if (tp->t_outq.c_cc < tp->t_ohiwat)
  668                                 (void)ttyoutput(CTRL('g'), tp);
  669                 }
  670                 goto endcase;
  671         }
  672 
  673         if (   c == 0377 && ISSET(iflag, PARMRK) && !ISSET(iflag, ISTRIP)
  674              && ISSET(iflag, IGNBRK|IGNPAR) != (IGNBRK|IGNPAR))
  675                 clist_putc(0377 | TTY_QUOTE, &tp->t_rawq);
  676 
  677         /*
  678          * Put data char in q for user and
  679          * wakeup on seeing a line delimiter.
  680          */
  681         if (clist_putc(c, &tp->t_rawq) >= 0) {
  682                 if (!ISSET(lflag, ICANON)) {
  683                         ttwakeup(tp);
  684                         ttyecho(c, tp);
  685                         goto endcase;
  686                 }
  687                 if (TTBREAKC(c, lflag)) {
  688                         tp->t_rocount = 0;
  689                         catq(&tp->t_rawq, &tp->t_canq);
  690                         ttwakeup(tp);
  691                 } else if (tp->t_rocount++ == 0)
  692                         tp->t_rocol = tp->t_column;
  693                 if (ISSET(tp->t_state, TS_ERASE)) {
  694                         /*
  695                          * end of prterase \.../
  696                          */
  697                         CLR(tp->t_state, TS_ERASE);
  698                         (void)ttyoutput('/', tp);
  699                 }
  700                 i = tp->t_column;
  701                 ttyecho(c, tp);
  702                 if (CCEQ(cc[VEOF], c) && ISSET(lflag, ECHO)) {
  703                         /*
  704                          * Place the cursor over the '^' of the ^D.
  705                          */
  706                         i = imin(2, tp->t_column - i);
  707                         while (i > 0) {
  708                                 (void)ttyoutput('\b', tp);
  709                                 i--;
  710                         }
  711                 }
  712         }
  713 endcase:
  714         /*
  715          * IXANY means allow any character to restart output.
  716          */
  717         if (ISSET(tp->t_state, TS_TTSTOP) &&
  718             !ISSET(iflag, IXANY) && cc[VSTART] != cc[VSTOP]) {
  719                 lwkt_reltoken(&tty_token);
  720                 return (0);
  721         }
  722 restartoutput:
  723         CLR(tp->t_lflag, FLUSHO);
  724         CLR(tp->t_state, TS_TTSTOP);
  725 startoutput:
  726         lwkt_reltoken(&tty_token);
  727         return (ttstart(tp));
  728 }
  729 
  730 /*
  731  * Output a single character on a tty, doing output processing
  732  * as needed (expanding tabs, newline processing, etc.).
  733  * Returns < 0 if succeeds, otherwise returns char to resend.
  734  * Must be recursive.
  735  */
  736 static int
  737 ttyoutput(int c, struct tty *tp)
  738 {
  739         tcflag_t oflag;
  740         int col;
  741 
  742         lwkt_gettoken(&tty_token);
  743         oflag = tp->t_oflag;
  744         if (!ISSET(oflag, OPOST)) {
  745                 if (ISSET(tp->t_lflag, FLUSHO)) {
  746                         lwkt_reltoken(&tty_token);
  747                         return (-1);
  748                 }
  749                 if (clist_putc(c, &tp->t_outq)) {
  750                         lwkt_reltoken(&tty_token);
  751                         return (c);
  752                 }
  753                 tk_nout++;
  754                 tp->t_outcc++;
  755                 lwkt_reltoken(&tty_token);
  756                 return (-1);
  757         }
  758         /*
  759          * Do tab expansion if OXTABS is set.  Special case if we external
  760          * processing, we don't do the tab expansion because we'll probably
  761          * get it wrong.  If tab expansion needs to be done, let it happen
  762          * externally.
  763          */
  764         CLR(c, ~TTY_CHARMASK);
  765         if (c == '\t' &&
  766             ISSET(oflag, OXTABS) && !ISSET(tp->t_lflag, EXTPROC)) {
  767                 c = 8 - (tp->t_column & 7);
  768                 if (!ISSET(tp->t_lflag, FLUSHO)) {
  769                         crit_enter();           /* Don't interrupt tabs. */
  770                         c -= b_to_q("        ", c, &tp->t_outq);
  771                         tk_nout += c;
  772                         tp->t_outcc += c;
  773                         crit_exit();
  774                 }
  775                 tp->t_column += c;
  776                 lwkt_reltoken(&tty_token);
  777                 return (c ? -1 : '\t');
  778         }
  779         if (c == CEOT && ISSET(oflag, ONOEOT)) {
  780                 lwkt_reltoken(&tty_token);
  781                 return (-1);
  782         }
  783 
  784         /*
  785          * Newline translation: if ONLCR is set,
  786          * translate newline into "\r\n".
  787          */
  788         if (c == '\n' && ISSET(tp->t_oflag, ONLCR)) {
  789                 tk_nout++;
  790                 tp->t_outcc++;
  791                 if (!ISSET(tp->t_lflag, FLUSHO) && clist_putc('\r', &tp->t_outq)) {
  792                         lwkt_reltoken(&tty_token);
  793                         return (c);
  794                 }
  795         }
  796         /* If OCRNL is set, translate "\r" into "\n". */
  797         else if (c == '\r' && ISSET(tp->t_oflag, OCRNL))
  798                 c = '\n';
  799         /* If ONOCR is set, don't transmit CRs when on column 0. */
  800         else if (c == '\r' && ISSET(tp->t_oflag, ONOCR) && tp->t_column == 0) {
  801                 lwkt_reltoken(&tty_token);
  802                 return (-1);
  803         }
  804 
  805         tk_nout++;
  806         tp->t_outcc++;
  807         if (!ISSET(tp->t_lflag, FLUSHO) && clist_putc(c, &tp->t_outq)) {
  808                 lwkt_reltoken(&tty_token);
  809                 return (c);
  810         }
  811 
  812         col = tp->t_column;
  813         switch (CCLASS(c)) {
  814         case BACKSPACE:
  815                 if (col > 0)
  816                         --col;
  817                 break;
  818         case CONTROL:
  819                 break;
  820         case NEWLINE:
  821                 if (ISSET(tp->t_oflag, ONLCR | ONLRET))
  822                         col = 0;
  823                 break;
  824         case RETURN:
  825                 col = 0;
  826                 break;
  827         case ORDINARY:
  828                 ++col;
  829                 break;
  830         case TAB:
  831                 col = (col + 8) & ~7;
  832                 break;
  833         }
  834         tp->t_column = col;
  835         lwkt_reltoken(&tty_token);
  836         return (-1);
  837 }
  838 
  839 /*
  840  * Ioctls for all tty devices.  Called after line-discipline specific ioctl
  841  * has been called to do discipline-specific functions and/or reject any
  842  * of these ioctl commands.
  843  */
  844 /* ARGSUSED */
  845 int
  846 ttioctl(struct tty *tp, u_long cmd, void *data, int flag)
  847 {
  848         struct thread *td = curthread;
  849         struct lwp *lp = td->td_lwp;
  850         struct proc *p = td->td_proc;
  851         struct pgrp *opgrp;
  852         struct tty *otp;
  853         int error;
  854 
  855         KKASSERT(p);
  856         lwkt_gettoken(&tty_token);
  857         lwkt_gettoken(&p->p_token);
  858 
  859         /* If the ioctl involves modification, hang if in the background. */
  860         switch (cmd) {
  861         case  TIOCCBRK:
  862         case  TIOCCONS:
  863         case  TIOCDRAIN:
  864         case  TIOCEXCL:
  865         case  TIOCFLUSH:
  866 #ifdef TIOCHPCL
  867         case  TIOCHPCL:
  868 #endif
  869         case  TIOCNXCL:
  870         case  TIOCSBRK:
  871         case  TIOCSCTTY:
  872         case  TIOCSDRAINWAIT:
  873         case  TIOCSETA:
  874         case  TIOCSETAF:
  875         case  TIOCSETAW:
  876         case  TIOCSETD:
  877         case  TIOCSPGRP:
  878         case  TIOCSTART:
  879         case  TIOCSTAT:
  880         case  TIOCSTI:
  881         case  TIOCSTOP:
  882         case  TIOCSWINSZ:
  883 #if defined(COMPAT_43)
  884         case  TIOCLBIC:
  885         case  TIOCLBIS:
  886         case  TIOCLSET:
  887         case  TIOCSETC:
  888         case OTIOCSETD:
  889         case  TIOCSETN:
  890         case  TIOCSETP:
  891         case  TIOCSLTC:
  892 #endif
  893                 while (isbackground(p, tp) && !(p->p_flags & P_PPWAIT) &&
  894                     !SIGISMEMBER(p->p_sigignore, SIGTTOU) &&
  895                     !SIGISMEMBER(lp->lwp_sigmask, SIGTTOU)) {
  896                         if (p->p_pgrp->pg_jobc == 0) {
  897                                 lwkt_reltoken(&p->p_token);
  898                                 lwkt_reltoken(&tty_token);
  899                                 return (EIO);
  900                         }
  901                         pgsignal(p->p_pgrp, SIGTTOU, 1);
  902                         error = ttysleep(tp, &lbolt, PCATCH, "ttybg1",
  903                                          0);
  904                         if (error) {
  905                                 lwkt_reltoken(&p->p_token);
  906                                 lwkt_reltoken(&tty_token);
  907                                 return (error);
  908                         }
  909                 }
  910                 break;
  911         }
  912 
  913         switch (cmd) {                  /* Process the ioctl. */
  914         case FIOASYNC:                  /* set/clear async i/o */
  915                 crit_enter();
  916                 if (*(int *)data)
  917                         SET(tp->t_state, TS_ASYNC);
  918                 else
  919                         CLR(tp->t_state, TS_ASYNC);
  920                 crit_exit();
  921                 break;
  922         case FIONREAD:                  /* get # bytes to read */
  923                 crit_enter();
  924                 *(int *)data = ttnread(tp);
  925                 crit_exit();
  926                 break;
  927 
  928         case FIOSETOWN:
  929                 /*
  930                  * Policy -- Don't allow FIOSETOWN on someone else's 
  931                  *           controlling tty
  932                  */
  933                 if (tp->t_session != NULL && !isctty(p, tp)) {
  934                         lwkt_reltoken(&p->p_token);
  935                         lwkt_reltoken(&tty_token);
  936                         return (ENOTTY);
  937                 }
  938 
  939                 error = fsetown(*(int *)data, &tp->t_sigio);
  940                 if (error) {
  941                         lwkt_reltoken(&p->p_token);
  942                         lwkt_reltoken(&tty_token);
  943                         return (error);
  944                 }
  945                 break;
  946         case FIOGETOWN:
  947                 if (tp->t_session != NULL && !isctty(p, tp)) {
  948                         lwkt_reltoken(&p->p_token);
  949                         lwkt_reltoken(&tty_token);
  950                         return (ENOTTY);
  951                 }
  952                 *(int *)data = fgetown(&tp->t_sigio);
  953                 break;
  954 
  955         case TIOCEXCL:                  /* set exclusive use of tty */
  956                 crit_enter();
  957                 SET(tp->t_state, TS_XCLUDE);
  958                 crit_exit();
  959                 break;
  960         case TIOCFLUSH: {               /* flush buffers */
  961                 int flags = *(int *)data;
  962 
  963                 if (flags == 0)
  964                         flags = FREAD | FWRITE;
  965                 else
  966                         flags &= FREAD | FWRITE;
  967                 ttyflush(tp, flags);
  968                 break;
  969         }
  970         case TIOCCONS:                  /* become virtual console */
  971                 if (*(int *)data) {
  972                         if (constty && constty != tp &&
  973                             ISSET(constty->t_state, TS_CONNECTED)) {
  974                                 lwkt_reltoken(&p->p_token);
  975                                 lwkt_reltoken(&tty_token);
  976                                 return (EBUSY);
  977                         }
  978 #ifndef UCONSOLE
  979                         if ((error = priv_check(td, PRIV_ROOT)) != 0) {
  980                                 lwkt_reltoken(&p->p_token);
  981                                 lwkt_reltoken(&tty_token);
  982                                 return (error);
  983                         }
  984 #endif
  985                         constty = tp;
  986                 } else if (tp == constty)
  987                         constty = NULL;
  988                 break;
  989         case TIOCDRAIN:                 /* wait till output drained */
  990                 error = ttywait(tp);
  991                 if (error) {
  992                         lwkt_reltoken(&p->p_token);
  993                         lwkt_reltoken(&tty_token);
  994                         return (error);
  995                 }
  996                 break;
  997         case TIOCGETA: {                /* get termios struct */
  998                 struct termios *t = (struct termios *)data;
  999 
 1000                 bcopy(&tp->t_termios, t, sizeof(struct termios));
 1001                 break;
 1002         }
 1003         case TIOCGETD:                  /* get line discipline */
 1004                 *(int *)data = tp->t_line;
 1005                 break;
 1006         case TIOCGWINSZ:                /* get window size */
 1007                 *(struct winsize *)data = tp->t_winsize;
 1008                 break;
 1009         case TIOCGPGRP:                 /* get pgrp of tty */
 1010                 if (!isctty(p, tp)) {
 1011                         lwkt_reltoken(&p->p_token);
 1012                         lwkt_reltoken(&tty_token);
 1013                         return (ENOTTY);
 1014                 }
 1015                 *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
 1016                 break;
 1017         case TIOCGSID:                  /* get sid of tty */
 1018                 if (!isctty(p, tp)) {
 1019                         lwkt_reltoken(&p->p_token);
 1020                         lwkt_reltoken(&tty_token);
 1021                         return (ENOTTY);
 1022                 }
 1023                 *(int *)data = tp->t_session->s_sid;
 1024                 break;
 1025 #ifdef TIOCHPCL
 1026         case TIOCHPCL:                  /* hang up on last close */
 1027                 crit_enter();
 1028                 SET(tp->t_cflag, HUPCL);
 1029                 crit_exit();
 1030                 break;
 1031 #endif
 1032         case TIOCNXCL:                  /* reset exclusive use of tty */
 1033                 crit_enter();
 1034                 CLR(tp->t_state, TS_XCLUDE);
 1035                 crit_exit();
 1036                 break;
 1037         case TIOCOUTQ:                  /* output queue size */
 1038                 *(int *)data = tp->t_outq.c_cc;
 1039                 break;
 1040         case TIOCSETA:                  /* set termios struct */
 1041         case TIOCSETAW:                 /* drain output, set */
 1042         case TIOCSETAF: {               /* drn out, fls in, set */
 1043                 struct termios *t = (struct termios *)data;
 1044 
 1045                 if (t->c_ispeed == 0)
 1046                         t->c_ispeed = t->c_ospeed;
 1047                 if (t->c_ispeed == 0)
 1048                         t->c_ispeed = tp->t_ospeed;
 1049                 if (t->c_ispeed == 0) {
 1050                         lwkt_reltoken(&p->p_token);
 1051                         lwkt_reltoken(&tty_token);
 1052                         return (EINVAL);
 1053                 }
 1054                 crit_enter();
 1055                 if (cmd == TIOCSETAW || cmd == TIOCSETAF) {
 1056                         error = ttywait(tp);
 1057                         if (error) {
 1058                                 crit_exit();
 1059                                 lwkt_reltoken(&p->p_token);
 1060                                 lwkt_reltoken(&tty_token);
 1061                                 return (error);
 1062                         }
 1063                         if (cmd == TIOCSETAF)
 1064                                 ttyflush(tp, FREAD);
 1065                 }
 1066                 if (!ISSET(t->c_cflag, CIGNORE)) {
 1067                         /*
 1068                          * Set device hardware.
 1069                          */
 1070                         if (tp->t_param && (error = (*tp->t_param)(tp, t))) {
 1071                                 crit_exit();
 1072                                 lwkt_reltoken(&p->p_token);
 1073                                 lwkt_reltoken(&tty_token);
 1074                                 return (error);
 1075                         }
 1076                         if (ISSET(t->c_cflag, CLOCAL) &&
 1077                             !ISSET(tp->t_cflag, CLOCAL)) {
 1078                                 /*
 1079                                  * XXX disconnections would be too hard to
 1080                                  * get rid of without this kludge.  The only
 1081                                  * way to get rid of controlling terminals
 1082                                  * is to exit from the session leader.
 1083                                  */
 1084                                 CLR(tp->t_state, TS_ZOMBIE);
 1085 
 1086                                 wakeup(TSA_CARR_ON(tp));
 1087                                 ttwakeup(tp);
 1088                                 ttwwakeup(tp);
 1089                         }
 1090                         if ((ISSET(tp->t_state, TS_CARR_ON) ||
 1091                              ISSET(t->c_cflag, CLOCAL)) &&
 1092                             !ISSET(tp->t_state, TS_ZOMBIE))
 1093                                 SET(tp->t_state, TS_CONNECTED);
 1094                         else
 1095                                 CLR(tp->t_state, TS_CONNECTED);
 1096                         tp->t_cflag = t->c_cflag;
 1097                         tp->t_ispeed = t->c_ispeed;
 1098                         if (t->c_ospeed != 0)
 1099                                 tp->t_ospeed = t->c_ospeed;
 1100                         ttsetwater(tp);
 1101                 }
 1102                 if (ISSET(t->c_lflag, ICANON) != ISSET(tp->t_lflag, ICANON) &&
 1103                     cmd != TIOCSETAF) {
 1104                         if (ISSET(t->c_lflag, ICANON))
 1105                                 SET(tp->t_lflag, PENDIN);
 1106                         else {
 1107                                 /*
 1108                                  * XXX we really shouldn't allow toggling
 1109                                  * ICANON while we're in a non-termios line
 1110                                  * discipline.  Now we have to worry about
 1111                                  * panicing for a null queue.
 1112                                  */
 1113                                 if (tp->t_canq.c_cbreserved > 0 &&
 1114                                     tp->t_rawq.c_cbreserved > 0) {
 1115                                         catq(&tp->t_rawq, &tp->t_canq);
 1116                                         /*
 1117                                          * XXX the queue limits may be
 1118                                          * different, so the old queue
 1119                                          * swapping method no longer works.
 1120                                          */
 1121                                         catq(&tp->t_canq, &tp->t_rawq);
 1122                                 }
 1123                                 CLR(tp->t_lflag, PENDIN);
 1124                         }
 1125                         ttwakeup(tp);
 1126                 }
 1127                 tp->t_iflag = t->c_iflag;
 1128                 tp->t_oflag = t->c_oflag;
 1129                 /*
 1130                  * Make the EXTPROC bit read only.
 1131                  */
 1132                 if (ISSET(tp->t_lflag, EXTPROC))
 1133                         SET(t->c_lflag, EXTPROC);
 1134                 else
 1135                         CLR(t->c_lflag, EXTPROC);
 1136                 tp->t_lflag = t->c_lflag | ISSET(tp->t_lflag, PENDIN);
 1137                 if (t->c_cc[VMIN] != tp->t_cc[VMIN] ||
 1138                     t->c_cc[VTIME] != tp->t_cc[VTIME])
 1139                         ttwakeup(tp);
 1140                 bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc));
 1141                 crit_exit();
 1142                 break;
 1143         }
 1144         case TIOCSETD: {                /* set line discipline */
 1145                 int t = *(int *)data;
 1146                 cdev_t device = tp->t_dev;
 1147 
 1148                 if ((u_int)t >= nlinesw) {
 1149                         lwkt_reltoken(&p->p_token);
 1150                         lwkt_reltoken(&tty_token);
 1151                         return (ENXIO);
 1152                 }
 1153                 if (t != tp->t_line) {
 1154                         crit_enter();
 1155                         (*linesw[tp->t_line].l_close)(tp, flag);
 1156                         error = (*linesw[t].l_open)(device, tp);
 1157                         if (error) {
 1158                                 (void)(*linesw[tp->t_line].l_open)(device, tp);
 1159                                 crit_exit();
 1160                                 lwkt_reltoken(&p->p_token);
 1161                                 lwkt_reltoken(&tty_token);
 1162                                 return (error);
 1163                         }
 1164                         tp->t_line = t;
 1165                         crit_exit();
 1166                 }
 1167                 break;
 1168         }
 1169         case TIOCSTART:                 /* start output, like ^Q */
 1170                 crit_enter();
 1171                 if (ISSET(tp->t_state, TS_TTSTOP) ||
 1172                     ISSET(tp->t_lflag, FLUSHO)) {
 1173                         CLR(tp->t_lflag, FLUSHO);
 1174                         CLR(tp->t_state, TS_TTSTOP);
 1175                         ttstart(tp);
 1176                 }
 1177                 crit_exit();
 1178                 break;
 1179         case TIOCSTI:                   /* simulate terminal input */
 1180                 if ((flag & FREAD) == 0 && priv_check(td, PRIV_ROOT)) {
 1181                         lwkt_reltoken(&p->p_token);
 1182                         lwkt_reltoken(&tty_token);
 1183                         return (EPERM);
 1184                 }
 1185                 if (!isctty(p, tp) && priv_check(td, PRIV_ROOT)) {
 1186                         lwkt_reltoken(&p->p_token);
 1187                         lwkt_reltoken(&tty_token);
 1188                         return (EACCES);
 1189                 }
 1190                 crit_enter();
 1191                 (*linesw[tp->t_line].l_rint)(*(u_char *)data, tp);
 1192                 crit_exit();
 1193                 break;
 1194         case TIOCSTOP:                  /* stop output, like ^S */
 1195                 crit_enter();
 1196                 if (!ISSET(tp->t_state, TS_TTSTOP)) {
 1197                         SET(tp->t_state, TS_TTSTOP);
 1198                         (*tp->t_stop)(tp, 0);
 1199                 }
 1200                 crit_exit();
 1201                 break;
 1202         case TIOCSCTTY:                 /* become controlling tty */
 1203                 /* Session ctty vnode pointer set in vnode layer. */
 1204                 if (!SESS_LEADER(p) ||
 1205                     ((p->p_session->s_ttyvp || tp->t_session) &&
 1206                     (tp->t_session != p->p_session))) {
 1207                         lwkt_reltoken(&p->p_token);
 1208                         lwkt_reltoken(&tty_token);
 1209                         return (EPERM);
 1210                 }
 1211                 ttyhold(tp);
 1212                 tp->t_session = p->p_session;
 1213                 opgrp = tp->t_pgrp;
 1214                 pgref(p->p_pgrp);
 1215                 tp->t_pgrp = p->p_pgrp;
 1216                 otp = p->p_session->s_ttyp;
 1217                 p->p_session->s_ttyp = tp;
 1218                 p->p_flags |= P_CONTROLT;
 1219                 if (otp)
 1220                         ttyunhold(otp);
 1221                 if (opgrp) {
 1222                         pgrel(opgrp);
 1223                         opgrp = NULL;
 1224                 }
 1225                 break;
 1226         case TIOCSPGRP: {               /* set pgrp of tty */
 1227                 pid_t pgid = *(int *)data;
 1228 
 1229                 if (!isctty(p, tp)) {
 1230                         lwkt_reltoken(&p->p_token);
 1231                         lwkt_reltoken(&tty_token);
 1232                         return (ENOTTY);
 1233                 }
 1234                 else if (pgid < 1 || pgid > PID_MAX) {
 1235                         lwkt_reltoken(&p->p_token);
 1236                         lwkt_reltoken(&tty_token);
 1237                         return (EINVAL);
 1238                 } else {
 1239                         struct pgrp *pgrp = pgfind(pgid);
 1240                         if (pgrp == NULL || pgrp->pg_session != p->p_session) {
 1241                                 if (pgrp)
 1242                                         pgrel(pgrp);
 1243                                 lwkt_reltoken(&p->p_token);
 1244                                 lwkt_reltoken(&tty_token);
 1245                                 return (EPERM);
 1246                         }
 1247                         opgrp = tp->t_pgrp;
 1248                         tp->t_pgrp = pgrp;
 1249                         if (opgrp) {
 1250                                 pgrel(opgrp);
 1251                                 opgrp = NULL;
 1252                         }
 1253                 }
 1254                 break;
 1255         }
 1256         case TIOCSTAT:                  /* simulate control-T */
 1257                 crit_enter();
 1258                 ttyinfo(tp);
 1259                 crit_exit();
 1260                 break;
 1261         case TIOCSWINSZ:                /* set window size */
 1262                 if (bcmp((caddr_t)&tp->t_winsize, data,
 1263                     sizeof (struct winsize))) {
 1264                         tp->t_winsize = *(struct winsize *)data;
 1265                         pgsignal(tp->t_pgrp, SIGWINCH, 1);
 1266                 }
 1267                 break;
 1268         case TIOCSDRAINWAIT:
 1269                 error = priv_check(td, PRIV_ROOT);
 1270                 if (error) {
 1271                         lwkt_reltoken(&p->p_token);
 1272                         lwkt_reltoken(&tty_token);
 1273                         return (error);
 1274                 }
 1275                 tp->t_timeout = *(int *)data * hz;
 1276                 wakeup(TSA_OCOMPLETE(tp));
 1277                 wakeup(TSA_OLOWAT(tp));
 1278                 break;
 1279         case TIOCGDRAINWAIT:
 1280                 *(int *)data = tp->t_timeout / hz;
 1281                 break;
 1282         default:
 1283                 lwkt_reltoken(&p->p_token);
 1284                 lwkt_reltoken(&tty_token);
 1285 #if defined(COMPAT_43)
 1286                 return (ttcompat(tp, cmd, data, flag));
 1287 #else
 1288                 return (ENOIOCTL);
 1289 #endif
 1290         }
 1291         lwkt_reltoken(&p->p_token);
 1292         lwkt_reltoken(&tty_token);
 1293         return (0);
 1294 }
 1295 
 1296 static struct filterops ttyread_filtops =
 1297         { FILTEROP_ISFD|FILTEROP_MPSAFE, NULL, filt_ttyrdetach, filt_ttyread };
 1298 static struct filterops ttywrite_filtops =
 1299         { FILTEROP_ISFD|FILTEROP_MPSAFE, NULL, filt_ttywdetach, filt_ttywrite };
 1300 
 1301 int
 1302 ttykqfilter(struct dev_kqfilter_args *ap)
 1303 {
 1304         cdev_t dev = ap->a_head.a_dev;
 1305         struct knote *kn = ap->a_kn;
 1306         struct tty *tp = dev->si_tty;
 1307         struct klist *klist;
 1308 
 1309         ap->a_result = 0;
 1310 
 1311         lwkt_gettoken(&tty_token);
 1312         switch (kn->kn_filter) {
 1313         case EVFILT_READ:
 1314                 klist = &tp->t_rkq.ki_note;
 1315                 kn->kn_fop = &ttyread_filtops;
 1316                 break;
 1317         case EVFILT_WRITE:
 1318                 klist = &tp->t_wkq.ki_note;
 1319                 kn->kn_fop = &ttywrite_filtops;
 1320                 break;
 1321         default:
 1322                 ap->a_result = EOPNOTSUPP;
 1323                 lwkt_reltoken(&tty_token);
 1324                 return (0);
 1325         }
 1326         lwkt_reltoken(&tty_token);
 1327         kn->kn_hook = (caddr_t)dev;
 1328         knote_insert(klist, kn);
 1329 
 1330         return (0);
 1331 }
 1332 
 1333 static void
 1334 filt_ttyrdetach(struct knote *kn)
 1335 {
 1336         struct tty *tp = ((cdev_t)kn->kn_hook)->si_tty;
 1337 
 1338         lwkt_gettoken(&tty_token);
 1339         knote_remove(&tp->t_rkq.ki_note, kn);
 1340         lwkt_reltoken(&tty_token);
 1341 }
 1342 
 1343 static int
 1344 filt_ttyread(struct knote *kn, long hint)
 1345 {
 1346         struct tty *tp = ((cdev_t)kn->kn_hook)->si_tty;
 1347 
 1348         lwkt_gettoken(&tty_token);
 1349         kn->kn_data = ttnread(tp);
 1350         if (ISSET(tp->t_state, TS_ZOMBIE)) {
 1351                 kn->kn_flags |= (EV_EOF | EV_NODATA);
 1352                 lwkt_reltoken(&tty_token);
 1353                 return (1);
 1354         }
 1355         lwkt_reltoken(&tty_token);
 1356         return (kn->kn_data > 0);
 1357 }
 1358 
 1359 static void
 1360 filt_ttywdetach(struct knote *kn)
 1361 {
 1362         struct tty *tp = ((cdev_t)kn->kn_hook)->si_tty;
 1363 
 1364         lwkt_gettoken(&tty_token);
 1365         knote_remove(&tp->t_wkq.ki_note, kn);
 1366         lwkt_reltoken(&tty_token);
 1367 }
 1368 
 1369 static int
 1370 filt_ttywrite(struct knote *kn, long hint)
 1371 {
 1372         struct tty *tp = ((cdev_t)kn->kn_hook)->si_tty;
 1373         int ret;
 1374 
 1375         lwkt_gettoken(&tty_token);
 1376         kn->kn_data = tp->t_outq.c_cc;
 1377         if (ISSET(tp->t_state, TS_ZOMBIE)) {
 1378                 lwkt_reltoken(&tty_token);
 1379                 return (1);
 1380         }
 1381         ret = (kn->kn_data <= tp->t_olowat &&
 1382             ISSET(tp->t_state, TS_CONNECTED));
 1383         lwkt_reltoken(&tty_token);
 1384         return ret;
 1385 }
 1386 
 1387 /*
 1388  * Must be called while in a critical section.
 1389  * NOTE: tty_token must be held.
 1390  */
 1391 static int
 1392 ttnread(struct tty *tp)
 1393 {
 1394         int nread;
 1395 
 1396         ASSERT_LWKT_TOKEN_HELD(&tty_token);
 1397         if (ISSET(tp->t_lflag, PENDIN))
 1398                 ttypend(tp);
 1399         nread = tp->t_canq.c_cc;
 1400         if (!ISSET(tp->t_lflag, ICANON)) {
 1401                 nread += tp->t_rawq.c_cc;
 1402                 if (nread < tp->t_cc[VMIN] && tp->t_cc[VTIME] == 0)
 1403                         nread = 0;
 1404         }
 1405         return (nread);
 1406 }
 1407 
 1408 /*
 1409  * Wait for output to drain.
 1410  */
 1411 int
 1412 ttywait(struct tty *tp)
 1413 {
 1414         int error;
 1415 
 1416         error = 0;
 1417         crit_enter();
 1418         lwkt_gettoken(&tty_token);
 1419         while ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) &&
 1420                ISSET(tp->t_state, TS_CONNECTED) && tp->t_oproc) {
 1421                 (*tp->t_oproc)(tp);
 1422                 if ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) &&
 1423                     ISSET(tp->t_state, TS_CONNECTED)) {
 1424                         SET(tp->t_state, TS_SO_OCOMPLETE);
 1425                         error = ttysleep(tp, TSA_OCOMPLETE(tp),
 1426                                          PCATCH, "ttywai",
 1427                                          tp->t_timeout);
 1428                         if (error) {
 1429                                 if (error == EWOULDBLOCK)
 1430                                         error = EIO;
 1431                                 break;
 1432                         }
 1433                 } else
 1434                         break;
 1435         }
 1436         if (!error && (tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)))
 1437                 error = EIO;
 1438         lwkt_reltoken(&tty_token);
 1439         crit_exit();
 1440         return (error);
 1441 }
 1442 
 1443 /*
 1444  * Flush if successfully wait.
 1445  */
 1446 static int
 1447 ttywflush(struct tty *tp)
 1448 {
 1449         int error;
 1450 
 1451         if ((error = ttywait(tp)) == 0)
 1452                 ttyflush(tp, FREAD);
 1453         return (error);
 1454 }
 1455 
 1456 /*
 1457  * Flush tty read and/or write queues, notifying anyone waiting.
 1458  */
 1459 void
 1460 ttyflush(struct tty *tp, int rw)
 1461 {
 1462         crit_enter();
 1463         lwkt_gettoken(&tty_token);
 1464 #if 0
 1465 again:
 1466 #endif
 1467         if (rw & FWRITE) {
 1468                 FLUSHQ(&tp->t_outq);
 1469                 CLR(tp->t_state, TS_TTSTOP);
 1470         }
 1471         (*tp->t_stop)(tp, rw);
 1472         if (rw & FREAD) {
 1473                 FLUSHQ(&tp->t_canq);
 1474                 FLUSHQ(&tp->t_rawq);
 1475                 CLR(tp->t_lflag, PENDIN);
 1476                 tp->t_rocount = 0;
 1477                 tp->t_rocol = 0;
 1478                 CLR(tp->t_state, TS_LOCAL);
 1479                 ttwakeup(tp);
 1480                 if (ISSET(tp->t_state, TS_TBLOCK)) {
 1481                         if (rw & FWRITE)
 1482                                 FLUSHQ(&tp->t_outq);
 1483                         ttyunblock(tp);
 1484 
 1485                         /*
 1486                          * Don't let leave any state that might clobber the
 1487                          * next line discipline (although we should do more
 1488                          * to send the START char).  Not clearing the state
 1489                          * may have caused the "putc to a clist with no
 1490                          * reserved cblocks" panic/kprintf.
 1491                          */
 1492                         CLR(tp->t_state, TS_TBLOCK);
 1493 
 1494 #if 0 /* forget it, sleeping isn't always safe and we don't know when it is */
 1495                         if (ISSET(tp->t_iflag, IXOFF)) {
 1496                                 /*
 1497                                  * XXX wait a bit in the hope that the stop
 1498                                  * character (if any) will go out.  Waiting
 1499                                  * isn't good since it allows races.  This
 1500                                  * will be fixed when the stop character is
 1501                                  * put in a special queue.  Don't bother with
 1502                                  * the checks in ttywait() since the timeout
 1503                                  * will save us.
 1504                                  */
 1505                                 SET(tp->t_state, TS_SO_OCOMPLETE);
 1506                                 ttysleep(tp, TSA_OCOMPLETE(tp), 0,
 1507                                          "ttyfls", hz / 10);
 1508                                 /*
 1509                                  * Don't try sending the stop character again.
 1510                                  */
 1511                                 CLR(tp->t_state, TS_TBLOCK);
 1512                                 goto again;
 1513                         }
 1514 #endif
 1515                 }
 1516         }
 1517         if (rw & FWRITE) {
 1518                 FLUSHQ(&tp->t_outq);
 1519                 ttwwakeup(tp);
 1520         }
 1521         lwkt_reltoken(&tty_token);
 1522         crit_exit();
 1523 }
 1524 
 1525 /*
 1526  * Copy in the default termios characters.
 1527  */
 1528 void
 1529 termioschars(struct termios *t)
 1530 {
 1531         lwkt_gettoken(&tty_token);
 1532         bcopy(ttydefchars, t->c_cc, sizeof t->c_cc);
 1533         lwkt_reltoken(&tty_token);
 1534 }
 1535 
 1536 /*
 1537  * Old interface.
 1538  */
 1539 void
 1540 ttychars(struct tty *tp)
 1541 {
 1542         lwkt_gettoken(&tty_token);
 1543         termioschars(&tp->t_termios);
 1544         lwkt_reltoken(&tty_token);
 1545 }
 1546 
 1547 /*
 1548  * Handle input high water.  Send stop character for the IXOFF case.  Turn
 1549  * on our input flow control bit and propagate the changes to the driver.
 1550  * XXX the stop character should be put in a special high priority queue.
 1551  */
 1552 void
 1553 ttyblock(struct tty *tp)
 1554 {
 1555         lwkt_gettoken(&tty_token);
 1556         SET(tp->t_state, TS_TBLOCK);
 1557         if (ISSET(tp->t_iflag, IXOFF) && tp->t_cc[VSTOP] != _POSIX_VDISABLE &&
 1558             clist_putc(tp->t_cc[VSTOP], &tp->t_outq) != 0)
 1559                 CLR(tp->t_state, TS_TBLOCK);    /* try again later */
 1560         ttstart(tp);
 1561         lwkt_reltoken(&tty_token);
 1562 }
 1563 
 1564 /*
 1565  * Handle input low water.  Send start character for the IXOFF case.  Turn
 1566  * off our input flow control bit and propagate the changes to the driver.
 1567  * XXX the start character should be put in a special high priority queue.
 1568  */
 1569 static void
 1570 ttyunblock(struct tty *tp)
 1571 {
 1572         lwkt_gettoken(&tty_token);
 1573         CLR(tp->t_state, TS_TBLOCK);
 1574         if (ISSET(tp->t_iflag, IXOFF) && tp->t_cc[VSTART] != _POSIX_VDISABLE &&
 1575             clist_putc(tp->t_cc[VSTART], &tp->t_outq) != 0)
 1576                 SET(tp->t_state, TS_TBLOCK);    /* try again later */
 1577         ttstart(tp);
 1578         lwkt_reltoken(&tty_token);
 1579 }
 1580 
 1581 #ifdef notyet
 1582 /* Not used by any current (i386) drivers. */
 1583 /*
 1584  * Restart after an inter-char delay.
 1585  */
 1586 void
 1587 ttrstrt(void *tp_arg)
 1588 {
 1589         struct tty *tp;
 1590 
 1591         KASSERT(tp_arg != NULL, ("ttrstrt"));
 1592 
 1593         tp = tp_arg;
 1594         crit_enter();
 1595         lwkt_gettoken(&tty_token);
 1596         CLR(tp->t_state, TS_TIMEOUT);
 1597         ttstart(tp);
 1598         lwkt_reltoken(&tty_token);
 1599         crit_exit();
 1600 }
 1601 #endif
 1602 
 1603 int
 1604 ttstart(struct tty *tp)
 1605 {
 1606         lwkt_gettoken(&tty_token);
 1607         if (tp->t_oproc != NULL)        /* XXX: Kludge for pty. */
 1608                 (*tp->t_oproc)(tp);
 1609         lwkt_reltoken(&tty_token);
 1610         return (0);
 1611 }
 1612 
 1613 /*
 1614  * "close" a line discipline
 1615  */
 1616 int
 1617 ttylclose(struct tty *tp, int flag)
 1618 {
 1619         lwkt_gettoken(&tty_token);
 1620         if (flag & FNONBLOCK || ttywflush(tp))
 1621                 ttyflush(tp, FREAD | FWRITE);
 1622         lwkt_reltoken(&tty_token);
 1623         return (0);
 1624 }
 1625 
 1626 void
 1627 ttyhold(struct tty *tp)
 1628 {
 1629         ++tp->t_refs;
 1630 }
 1631 
 1632 void
 1633 ttyunhold(struct tty *tp)
 1634 {
 1635         if (tp->t_unhold)
 1636                 tp->t_unhold(tp);
 1637         else
 1638                 --tp->t_refs;
 1639 }
 1640 
 1641 /*
 1642  * Handle modem control transition on a tty.
 1643  * Flag indicates new state of carrier.
 1644  * Returns 0 if the line should be turned off, otherwise 1.
 1645  */
 1646 int
 1647 ttymodem(struct tty *tp, int flag)
 1648 {
 1649         lwkt_gettoken(&tty_token);
 1650         if (ISSET(tp->t_state, TS_CARR_ON) && ISSET(tp->t_cflag, MDMBUF)) {
 1651                 /*
 1652                  * MDMBUF: do flow control according to carrier flag
 1653                  * XXX TS_CAR_OFLOW doesn't do anything yet.  TS_TTSTOP
 1654                  * works if IXON and IXANY are clear.
 1655                  */
 1656                 if (flag) {
 1657                         CLR(tp->t_state, TS_CAR_OFLOW);
 1658                         CLR(tp->t_state, TS_TTSTOP);
 1659                         ttstart(tp);
 1660                 } else if (!ISSET(tp->t_state, TS_CAR_OFLOW)) {
 1661                         SET(tp->t_state, TS_CAR_OFLOW);
 1662                         SET(tp->t_state, TS_TTSTOP);
 1663                         (*tp->t_stop)(tp, 0);
 1664                 }
 1665         } else if (flag == 0) {
 1666                 /*
 1667                  * Lost carrier.
 1668                  */
 1669                 CLR(tp->t_state, TS_CARR_ON);
 1670                 if (ISSET(tp->t_state, TS_ISOPEN) &&
 1671                     !ISSET(tp->t_cflag, CLOCAL)) {
 1672                         SET(tp->t_state, TS_ZOMBIE);
 1673                         CLR(tp->t_state, TS_CONNECTED);
 1674                         if (tp->t_session && tp->t_session->s_leader)
 1675                                 ksignal(tp->t_session->s_leader, SIGHUP);
 1676                         ttyflush(tp, FREAD | FWRITE);
 1677                         lwkt_reltoken(&tty_token);
 1678                         return (0);
 1679                 }
 1680         } else {
 1681                 /*
 1682                  * Carrier now on.
 1683                  */
 1684                 SET(tp->t_state, TS_CARR_ON);
 1685                 if (!ISSET(tp->t_state, TS_ZOMBIE))
 1686                         SET(tp->t_state, TS_CONNECTED);
 1687                 wakeup(TSA_CARR_ON(tp));
 1688                 ttwakeup(tp);
 1689                 ttwwakeup(tp);
 1690         }
 1691         lwkt_reltoken(&tty_token);
 1692         return (1);
 1693 }
 1694 
 1695 /*
 1696  * Reinput pending characters after state switch
 1697  * call from a critical section.
 1698  */
 1699 static void
 1700 ttypend(struct tty *tp)
 1701 {
 1702         struct clist tq;
 1703         int c;
 1704 
 1705         lwkt_gettoken(&tty_token);
 1706         CLR(tp->t_lflag, PENDIN);
 1707         SET(tp->t_state, TS_TYPEN);
 1708         /*
 1709          * XXX this assumes too much about clist internals.  It may even
 1710          * fail if the cblock slush pool is empty.  We can't allocate more
 1711          * cblocks here because we are called from an interrupt handler
 1712          * and clist_alloc_cblocks() can wait.
 1713          */
 1714         tq = tp->t_rawq;
 1715         bzero(&tp->t_rawq, sizeof tp->t_rawq);
 1716         tp->t_rawq.c_cbmax = tq.c_cbmax;
 1717         tp->t_rawq.c_cbreserved = tq.c_cbreserved;
 1718         while ((c = clist_getc(&tq)) >= 0)
 1719                 ttyinput(c, tp);
 1720         CLR(tp->t_state, TS_TYPEN);
 1721         lwkt_reltoken(&tty_token);
 1722 }
 1723 
 1724 /*
 1725  * Process a read call on a tty device.
 1726  */
 1727 int
 1728 ttread(struct tty *tp, struct uio *uio, int flag)
 1729 {
 1730         struct clist *qp;
 1731         int c;
 1732         tcflag_t lflag;
 1733         cc_t *cc = tp->t_cc;
 1734         struct proc *pp;
 1735         struct lwp *lp;
 1736         int first, error = 0;
 1737         int has_stime = 0, last_cc = 0;
 1738         long slp = 0;           /* XXX this should be renamed `timo'. */
 1739         struct timeval stime;
 1740 
 1741         lp = curthread->td_lwp;
 1742         stime.tv_sec = 0;       /* fix compiler warnings */
 1743         stime.tv_usec = 0;
 1744 
 1745         lwkt_gettoken(&tty_token);
 1746 loop:
 1747         crit_enter();
 1748         lflag = tp->t_lflag;
 1749         /*
 1750          * take pending input first
 1751          */
 1752         if (ISSET(lflag, PENDIN)) {
 1753                 ttypend(tp);
 1754                 splz();         /* reduce latency */
 1755                 lflag = tp->t_lflag;    /* XXX ttypend() clobbers it */
 1756         }
 1757 
 1758         /*
 1759          * Hang process if it's in the background.
 1760          */
 1761         if ((pp = curproc) != NULL)
 1762                 lwkt_gettoken(&pp->p_token);
 1763         if (pp && isbackground(pp, tp)) {
 1764                 crit_exit();
 1765                 if (SIGISMEMBER(pp->p_sigignore, SIGTTIN) ||
 1766                     SIGISMEMBER(lp->lwp_sigmask, SIGTTIN) ||
 1767                     (pp->p_flags & P_PPWAIT) || pp->p_pgrp->pg_jobc == 0) {
 1768                         lwkt_reltoken(&pp->p_token);
 1769                         lwkt_reltoken(&tty_token);
 1770                         return (EIO);
 1771                 }
 1772                 pgsignal(pp->p_pgrp, SIGTTIN, 1);
 1773                 error = ttysleep(tp, &lbolt, PCATCH, "ttybg2", 0);
 1774                 if (error) {
 1775                         lwkt_reltoken(&pp->p_token);
 1776                         lwkt_reltoken(&tty_token);
 1777                         return (error);
 1778                 }
 1779                 lwkt_reltoken(&pp->p_token);
 1780                 goto loop;
 1781         }
 1782         if (pp)
 1783                 lwkt_reltoken(&pp->p_token);
 1784 
 1785         if (ISSET(tp->t_state, TS_ZOMBIE)) {
 1786                 crit_exit();
 1787                 lwkt_reltoken(&tty_token);
 1788                 return (0);     /* EOF */
 1789         }
 1790 
 1791         /*
 1792          * If canonical, use the canonical queue,
 1793          * else use the raw queue.
 1794          *
 1795          * (should get rid of clists...)
 1796          */
 1797         qp = ISSET(lflag, ICANON) ? &tp->t_canq : &tp->t_rawq;
 1798 
 1799         if (flag & IO_NDELAY) {
 1800                 if (qp->c_cc > 0)
 1801                         goto read;
 1802                 if (!ISSET(lflag, ICANON) && cc[VMIN] == 0) {
 1803                         crit_exit();
 1804                         lwkt_reltoken(&tty_token);
 1805                         return (0);
 1806                 }
 1807                 crit_exit();
 1808                 lwkt_reltoken(&tty_token);
 1809                 return (EWOULDBLOCK);
 1810         }
 1811         if (!ISSET(lflag, ICANON)) {
 1812                 int m = cc[VMIN];
 1813                 long t = cc[VTIME];
 1814                 struct timeval timecopy;
 1815 
 1816                 /*
 1817                  * Check each of the four combinations.
 1818                  * (m > 0 && t == 0) is the normal read case.
 1819                  * It should be fairly efficient, so we check that and its
 1820                  * companion case (m == 0 && t == 0) first.
 1821                  * For the other two cases, we compute the target sleep time
 1822                  * into slp.
 1823                  */
 1824                 if (t == 0) {
 1825                         if (qp->c_cc < m)
 1826                                 goto sleep;
 1827                         if (qp->c_cc > 0)
 1828                                 goto read;
 1829 
 1830                         /* m, t and qp->c_cc are all 0.  0 is enough input. */
 1831                         crit_exit();
 1832                         lwkt_reltoken(&tty_token);
 1833                         return (0);
 1834                 }
 1835                 t *= 100000;            /* time in us */
 1836 #define diff(t1, t2) (((t1).tv_sec - (t2).tv_sec) * 1000000 + \
 1837                          ((t1).tv_usec - (t2).tv_usec))
 1838                 if (m > 0) {
 1839                         if (qp->c_cc <= 0)
 1840                                 goto sleep;
 1841                         if (qp->c_cc >= m)
 1842                                 goto read;
 1843                         getmicrotime(&timecopy);
 1844                         if (has_stime == 0) {
 1845                                 /* first character, start timer */
 1846                                 has_stime = 1;
 1847                                 stime = timecopy;
 1848                                 slp = t;
 1849                         } else if (qp->c_cc > last_cc) {
 1850                                 /* got a character, restart timer */
 1851                                 stime = timecopy;
 1852                                 slp = t;
 1853                         } else {
 1854                                 /* nothing, check expiration */
 1855                                 slp = t - diff(timecopy, stime);
 1856                                 if (slp <= 0)
 1857                                         goto read;
 1858                         }
 1859                         last_cc = qp->c_cc;
 1860                 } else {        /* m == 0 */
 1861                         if (qp->c_cc > 0)
 1862                                 goto read;
 1863                         getmicrotime(&timecopy);
 1864                         if (has_stime == 0) {
 1865                                 has_stime = 1;
 1866                                 stime = timecopy;
 1867                                 slp = t;
 1868                         } else {
 1869                                 slp = t - diff(timecopy, stime);
 1870                                 if (slp <= 0) {
 1871                                         /* Timed out, but 0 is enough input. */
 1872                                         crit_exit();
 1873                                         lwkt_reltoken(&tty_token);
 1874                                         return (0);
 1875                                 }
 1876                         }
 1877                 }
 1878 #undef diff
 1879                 /*
 1880                  * Rounding down may make us wake up just short
 1881                  * of the target, so we round up.
 1882                  * The formula is ceiling(slp * hz/1000000).
 1883                  * 32-bit arithmetic is enough for hz < 169.
 1884                  * XXX see tvtohz() for how to avoid overflow if hz
 1885                  * is large (divide by `tick' and/or arrange to
 1886                  * use tvtohz() if hz is large).
 1887                  */
 1888                 slp = (long) (((u_long)slp * hz) + 999999) / 1000000;
 1889                 goto sleep;
 1890         }
 1891         if (qp->c_cc <= 0) {
 1892 sleep:
 1893                 /*
 1894                  * There is no input, or not enough input and we can block.
 1895                  */
 1896                 error = ttysleep(tp, TSA_HUP_OR_INPUT(tp), PCATCH,
 1897                                  ISSET(tp->t_state, TS_CONNECTED) ?
 1898                                  "ttyin" : "ttyhup", (int)slp);
 1899                 crit_exit();
 1900                 if (error == EWOULDBLOCK)
 1901                         error = 0;
 1902                 else if (error) {
 1903                         lwkt_reltoken(&tty_token);
 1904                         return (error);
 1905                 }
 1906                 /*
 1907                  * XXX what happens if another process eats some input
 1908                  * while we are asleep (not just here)?  It would be
 1909                  * safest to detect changes and reset our state variables
 1910                  * (has_stime and last_cc).
 1911                  */
 1912                 slp = 0;
 1913                 goto loop;
 1914         }
 1915 read:
 1916         crit_exit();
 1917         /*
 1918          * Input present, check for input mapping and processing.
 1919          */
 1920         first = 1;
 1921         if (ISSET(lflag, ICANON | ISIG))
 1922                 goto slowcase;
 1923         for (;;) {
 1924                 char ibuf[IBUFSIZ];
 1925                 int icc;
 1926 
 1927                 icc = (int)szmin(uio->uio_resid, IBUFSIZ);
 1928                 icc = q_to_b(qp, ibuf, icc);
 1929                 if (icc <= 0) {
 1930                         if (first)
 1931                                 goto loop;
 1932                         break;
 1933                 }
 1934                 error = uiomove(ibuf, (size_t)icc, uio);
 1935                 /*
 1936                  * XXX if there was an error then we should ungetc() the
 1937                  * unmoved chars and reduce icc here.
 1938                  */
 1939                 if (error)
 1940                         break;
 1941                 if (uio->uio_resid == 0)
 1942                         break;
 1943                 first = 0;
 1944         }
 1945         goto out;
 1946 slowcase:
 1947         for (;;) {
 1948                 c = clist_getc(qp);
 1949                 if (c < 0) {
 1950                         if (first)
 1951                                 goto loop;
 1952                         break;
 1953                 }
 1954                 /*
 1955                  * delayed suspend (^Y)
 1956                  */
 1957                 if (CCEQ(cc[VDSUSP], c) &&
 1958                     ISSET(lflag, IEXTEN | ISIG) == (IEXTEN | ISIG)) {
 1959                         pgsignal(tp->t_pgrp, SIGTSTP, 1);
 1960                         if (first) {
 1961                                 error = ttysleep(tp, &lbolt, PCATCH,
 1962                                                  "ttybg3", 0);
 1963                                 if (error)
 1964                                         break;
 1965                                 goto loop;
 1966                         }
 1967                         break;
 1968                 }
 1969                 /*
 1970                  * Interpret EOF only in canonical mode.
 1971                  */
 1972                 if (CCEQ(cc[VEOF], c) && ISSET(lflag, ICANON))
 1973                         break;
 1974                 /*
 1975                  * Give user character.
 1976                  */
 1977                 error = ureadc(c, uio);
 1978                 if (error)
 1979                         /* XXX should ungetc(c, qp). */
 1980                         break;
 1981                 if (uio->uio_resid == 0)
 1982                         break;
 1983                 /*
 1984                  * In canonical mode check for a "break character"
 1985                  * marking the end of a "line of input".
 1986                  */
 1987                 if (ISSET(lflag, ICANON) && TTBREAKC(c, lflag))
 1988                         break;
 1989                 first = 0;
 1990         }
 1991 
 1992 out:
 1993         /*
 1994          * Look to unblock input now that (presumably)
 1995          * the input queue has gone down.
 1996          */
 1997         crit_enter();
 1998         if (ISSET(tp->t_state, TS_TBLOCK) &&
 1999             tp->t_rawq.c_cc + tp->t_canq.c_cc <= tp->t_ilowat)
 2000                 ttyunblock(tp);
 2001         crit_exit();
 2002 
 2003         lwkt_reltoken(&tty_token);
 2004         return (error);
 2005 }
 2006 
 2007 /*
 2008  * Check the output queue on tp for space for a kernel message (from uprintf
 2009  * or tprintf).  Allow some space over the normal hiwater mark so we don't
 2010  * lose messages due to normal flow control, but don't let the tty run amok.
 2011  * Sleeps here are not interruptible, but we return prematurely if new signals
 2012  * arrive.
 2013  */
 2014 int
 2015 ttycheckoutq(struct tty *tp, int wait)
 2016 {
 2017         struct lwp *lp = curthread->td_lwp;
 2018         int hiwat;
 2019         sigset_t oldset, newset;
 2020 
 2021         lwkt_gettoken(&tty_token);
 2022         hiwat = tp->t_ohiwat;
 2023         SIGEMPTYSET(oldset);
 2024         SIGEMPTYSET(newset);
 2025         crit_enter();
 2026         if (wait)
 2027                 oldset = lwp_sigpend(lp);
 2028         if (tp->t_outq.c_cc > hiwat + OBUFSIZ + 100) {
 2029                 while (tp->t_outq.c_cc > hiwat) {
 2030                         ttstart(tp);
 2031                         if (tp->t_outq.c_cc <= hiwat)
 2032                                 break;
 2033                         if (wait)
 2034                                 newset = lwp_sigpend(lp);
 2035                         if (!wait || SIGSETNEQ(oldset, newset)) {
 2036                                 crit_exit();
 2037                                 lwkt_reltoken(&tty_token);
 2038                                 return (0);
 2039                         }
 2040                         SET(tp->t_state, TS_SO_OLOWAT);
 2041                         tsleep(TSA_OLOWAT(tp), 0, "ttoutq", hz);
 2042                 }
 2043         }
 2044         crit_exit();
 2045         lwkt_reltoken(&tty_token);
 2046         return (1);
 2047 }
 2048 
 2049 /*
 2050  * Process a write call on a tty device.
 2051  */
 2052 int
 2053 ttwrite(struct tty *tp, struct uio *uio, int flag)
 2054 {
 2055         char *cp = NULL;
 2056         int cc, ce;
 2057         struct proc *pp;
 2058         struct lwp *lp;
 2059         int i, hiwat, error;
 2060         size_t cnt;
 2061 
 2062         char obuf[OBUFSIZ];
 2063 
 2064         lwkt_gettoken(&tty_token);
 2065         lp = curthread->td_lwp;
 2066         hiwat = tp->t_ohiwat;
 2067         cnt = uio->uio_resid;
 2068         error = 0;
 2069         cc = 0;
 2070 loop:
 2071         crit_enter();
 2072         if (ISSET(tp->t_state, TS_ZOMBIE)) {
 2073                 crit_exit();
 2074                 if (uio->uio_resid == cnt)
 2075                         error = EIO;
 2076                 goto out;
 2077         }
 2078         if (!ISSET(tp->t_state, TS_CONNECTED)) {
 2079                 if (flag & IO_NDELAY) {
 2080                         crit_exit();
 2081                         error = EWOULDBLOCK;
 2082                         goto out;
 2083                 }
 2084                 error = ttysleep(tp, TSA_CARR_ON(tp), PCATCH, "ttydcd", 0);
 2085                 crit_exit();
 2086                 if (error)
 2087                         goto out;
 2088                 goto loop;
 2089         }
 2090         crit_exit();
 2091 
 2092         /*
 2093          * Hang the process if it's in the background.
 2094          */
 2095         if ((pp = curproc) != NULL)
 2096                 lwkt_gettoken(&pp->p_token);
 2097         if (pp && isbackground(pp, tp) &&
 2098             ISSET(tp->t_lflag, TOSTOP) && !(pp->p_flags & P_PPWAIT) &&
 2099             !SIGISMEMBER(pp->p_sigignore, SIGTTOU) &&
 2100             !SIGISMEMBER(lp->lwp_sigmask, SIGTTOU)) {
 2101                 if (pp->p_pgrp->pg_jobc == 0) {
 2102                         error = EIO;
 2103                         lwkt_reltoken(&pp->p_token);
 2104                         goto out;
 2105                 }
 2106                 pgsignal(pp->p_pgrp, SIGTTOU, 1);
 2107                 lwkt_reltoken(&pp->p_token);
 2108                 error = ttysleep(tp, &lbolt, PCATCH, "ttybg4", 0);
 2109                 if (error)
 2110                         goto out;
 2111                 goto loop;
 2112         }
 2113         if (pp)
 2114                 lwkt_reltoken(&pp->p_token);
 2115         /*
 2116          * Process the user's data in at most OBUFSIZ chunks.  Perform any
 2117          * output translation.  Keep track of high water mark, sleep on
 2118          * overflow awaiting device aid in acquiring new space.
 2119          */
 2120         while (uio->uio_resid > 0 || cc > 0) {
 2121                 if (ISSET(tp->t_lflag, FLUSHO)) {
 2122                         uio->uio_resid = 0;
 2123                         lwkt_reltoken(&tty_token);
 2124                         return (0);
 2125                 }
 2126                 if (tp->t_outq.c_cc > hiwat)
 2127                         goto ovhiwat;
 2128                 /*
 2129                  * Grab a hunk of data from the user, unless we have some
 2130                  * leftover from last time.
 2131                  */
 2132                 if (cc == 0) {
 2133                         cc = szmin(uio->uio_resid, OBUFSIZ);
 2134                         cp = obuf;
 2135                         error = uiomove(cp, (size_t)cc, uio);
 2136                         if (error) {
 2137                                 cc = 0;
 2138                                 break;
 2139                         }
 2140                 }
 2141                 /*
 2142                  * If nothing fancy need be done, grab those characters we
 2143                  * can handle without any of ttyoutput's processing and
 2144                  * just transfer them to the output q.  For those chars
 2145                  * which require special processing (as indicated by the
 2146                  * bits in char_type), call ttyoutput.  After processing
 2147                  * a hunk of data, look for FLUSHO so ^O's will take effect
 2148                  * immediately.
 2149                  */
 2150                 while (cc > 0) {
 2151                         if (!ISSET(tp->t_oflag, OPOST))
 2152                                 ce = cc;
 2153                         else {
 2154                                 ce = cc - scanc((u_int)cc, (u_char *)cp,
 2155                                                 char_type, CCLASSMASK);
 2156                                 /*
 2157                                  * If ce is zero, then we're processing
 2158                                  * a special character through ttyoutput.
 2159                                  */
 2160                                 if (ce == 0) {
 2161                                         tp->t_rocount = 0;
 2162                                         if (ttyoutput(*cp, tp) >= 0) {
 2163                                                 /* No Clists, wait a bit. */
 2164                                                 ttstart(tp);
 2165                                                 if (flag & IO_NDELAY) {
 2166                                                         error = EWOULDBLOCK;
 2167                                                         goto out;
 2168                                                 }
 2169                                                 error = ttysleep(tp, &lbolt,
 2170                                                                  PCATCH,
 2171                                                                  "ttybf1", 0);
 2172                                                 if (error)
 2173                                                         goto out;
 2174                                                 goto loop;
 2175                                         }
 2176                                         cp++;
 2177                                         cc--;
 2178                                         if (ISSET(tp->t_lflag, FLUSHO) ||
 2179                                             tp->t_outq.c_cc > hiwat)
 2180                                                 goto ovhiwat;
 2181                                         continue;
 2182                                 }
 2183                         }
 2184                         /*
 2185                          * A bunch of normal characters have been found.
 2186                          * Transfer them en masse to the output queue and
 2187                          * continue processing at the top of the loop.
 2188                          * If there are any further characters in this
 2189                          * <= OBUFSIZ chunk, the first should be a character
 2190                          * requiring special handling by ttyoutput.
 2191                          */
 2192                         tp->t_rocount = 0;
 2193                         i = b_to_q(cp, ce, &tp->t_outq);
 2194                         ce -= i;
 2195                         tp->t_column += ce;
 2196                         cp += ce, cc -= ce, tk_nout += ce;
 2197                         tp->t_outcc += ce;
 2198                         if (i > 0) {
 2199                                 /* No Clists, wait a bit. */
 2200                                 ttstart(tp);
 2201                                 if (flag & IO_NDELAY) {
 2202                                         error = EWOULDBLOCK;
 2203                                         goto out;
 2204                                 }
 2205                                 error = ttysleep(tp, &lbolt, PCATCH,
 2206                                                  "ttybf2", 0);
 2207                                 if (error)
 2208                                         goto out;
 2209                                 goto loop;
 2210                         }
 2211                         if (ISSET(tp->t_lflag, FLUSHO) ||
 2212                             tp->t_outq.c_cc > hiwat)
 2213                                 break;
 2214                 }
 2215                 ttstart(tp);
 2216         }
 2217 out:
 2218         /*
 2219          * If cc is nonzero, we leave the uio structure inconsistent, as the
 2220          * offset and iov pointers have moved forward, but it doesn't matter
 2221          * (the call will either return short or restart with a new uio).
 2222          */
 2223         uio->uio_resid += cc;
 2224         lwkt_reltoken(&tty_token);
 2225         return (error);
 2226 
 2227 ovhiwat:
 2228         ttstart(tp);
 2229         crit_enter();
 2230         /*
 2231          * This can only occur if FLUSHO is set in t_lflag,
 2232          * or if ttstart/oproc is synchronous (or very fast).
 2233          */
 2234         if (tp->t_outq.c_cc <= hiwat) {
 2235                 crit_exit();
 2236                 goto loop;
 2237         }
 2238         if (flag & IO_NDELAY) {
 2239                 crit_exit();
 2240                 uio->uio_resid += cc;
 2241                 lwkt_reltoken(&tty_token);
 2242                 return (uio->uio_resid == cnt ? EWOULDBLOCK : 0);
 2243         }
 2244         SET(tp->t_state, TS_SO_OLOWAT);
 2245         error = ttysleep(tp, TSA_OLOWAT(tp), PCATCH, "ttywri", tp->t_timeout);
 2246         crit_exit();
 2247         if (error == EWOULDBLOCK)
 2248                 error = EIO;
 2249         if (error)
 2250                 goto out;
 2251         goto loop;
 2252 }
 2253 
 2254 /*
 2255  * Rubout one character from the rawq of tp
 2256  * as cleanly as possible.
 2257  * NOTE: Must be called with tty_token held
 2258  */
 2259 static void
 2260 ttyrub(int c, struct tty *tp)
 2261 {
 2262         char *cp;
 2263         int savecol;
 2264         int tabc;
 2265 
 2266         ASSERT_LWKT_TOKEN_HELD(&tty_token);
 2267         if (!ISSET(tp->t_lflag, ECHO) || ISSET(tp->t_lflag, EXTPROC))
 2268                 return;
 2269         CLR(tp->t_lflag, FLUSHO);
 2270         if (ISSET(tp->t_lflag, ECHOE)) {
 2271                 if (tp->t_rocount == 0) {
 2272                         /*
 2273                          * Screwed by ttwrite; retype
 2274                          */
 2275                         ttyretype(tp);
 2276                         return;
 2277                 }
 2278                 if (c == ('\t' | TTY_QUOTE) || c == ('\n' | TTY_QUOTE))
 2279                         ttyrubo(tp, 2);
 2280                 else {
 2281                         CLR(c, ~TTY_CHARMASK);
 2282                         switch (CCLASS(c)) {
 2283                         case ORDINARY:
 2284                                 ttyrubo(tp, 1);
 2285                                 break;
 2286                         case BACKSPACE:
 2287                         case CONTROL:
 2288                         case NEWLINE:
 2289                         case RETURN:
 2290                         case VTAB:
 2291                                 if (ISSET(tp->t_lflag, ECHOCTL))
 2292                                         ttyrubo(tp, 2);
 2293                                 break;
 2294                         case TAB:
 2295                                 if (tp->t_rocount < tp->t_rawq.c_cc) {
 2296                                         ttyretype(tp);
 2297                                         return;
 2298                                 }
 2299                                 crit_enter();
 2300                                 savecol = tp->t_column;
 2301                                 SET(tp->t_state, TS_CNTTB);
 2302                                 SET(tp->t_lflag, FLUSHO);
 2303                                 tp->t_column = tp->t_rocol;
 2304                                 cp = tp->t_rawq.c_cf;
 2305                                 if (cp)
 2306                                         tabc = *cp;     /* XXX FIX NEXTC */
 2307                                 for (; cp; cp = nextc(&tp->t_rawq, cp, &tabc))
 2308                                         ttyecho(tabc, tp);
 2309                                 CLR(tp->t_lflag, FLUSHO);
 2310                                 CLR(tp->t_state, TS_CNTTB);
 2311                                 crit_exit();
 2312 
 2313                                 /* savecol will now be length of the tab. */
 2314                                 savecol -= tp->t_column;
 2315                                 tp->t_column += savecol;
 2316                                 if (savecol > 8)
 2317                                         savecol = 8;    /* overflow screw */
 2318                                 while (--savecol >= 0)
 2319                                         (void)ttyoutput('\b', tp);
 2320                                 break;
 2321                         default:                        /* XXX */
 2322 #define PANICSTR        "ttyrub: would panic c = %d, val = %d\n"
 2323                                 (void)kprintf(PANICSTR, c, CCLASS(c));
 2324 #ifdef notdef
 2325                                 panic(PANICSTR, c, CCLASS(c));
 2326 #endif
 2327                         }
 2328                 }
 2329         } else if (ISSET(tp->t_lflag, ECHOPRT)) {
 2330                 if (!ISSET(tp->t_state, TS_ERASE)) {
 2331                         SET(tp->t_state, TS_ERASE);
 2332                         (void)ttyoutput('\\', tp);
 2333                 }
 2334                 ttyecho(c, tp);
 2335         } else {
 2336                 ttyecho(tp->t_cc[VERASE], tp);
 2337                 /*
 2338                  * This code may be executed not only when an ERASE key
 2339                  * is pressed, but also when ^U (KILL) or ^W (WERASE) are.
 2340                  * So, I didn't think it was worthwhile to pass the extra
 2341                  * information (which would need an extra parameter,
 2342                  * changing every call) needed to distinguish the ERASE2
 2343                  * case from the ERASE.
 2344                  */
 2345         }
 2346         --tp->t_rocount;
 2347 }
 2348 
 2349 /*
 2350  * Back over cnt characters, erasing them.
 2351  * NOTE: Must be called with tty_token held
 2352  */
 2353 static void
 2354 ttyrubo(struct tty *tp, int cnt)
 2355 {
 2356         ASSERT_LWKT_TOKEN_HELD(&tty_token);
 2357         while (cnt-- > 0) {
 2358                 (void)ttyoutput('\b', tp);
 2359                 (void)ttyoutput(' ', tp);
 2360                 (void)ttyoutput('\b', tp);
 2361         }
 2362 }
 2363 
 2364 /*
 2365  * ttyretype --
 2366  *      Reprint the rawq line.  Note, it is assumed that c_cc has already
 2367  *      been checked.
 2368  * NOTE: Must be called with tty_token held
 2369  */
 2370 static void
 2371 ttyretype(struct tty *tp)
 2372 {
 2373         char *cp;
 2374         int c;
 2375 
 2376         ASSERT_LWKT_TOKEN_HELD(&tty_token);
 2377         /* Echo the reprint character. */
 2378         if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE)
 2379                 ttyecho(tp->t_cc[VREPRINT], tp);
 2380 
 2381         (void)ttyoutput('\n', tp);
 2382 
 2383         /*
 2384          * XXX
 2385          * FIX: NEXTC IS BROKEN - DOESN'T CHECK QUOTE
 2386          * BIT OF FIRST CHAR.
 2387          */
 2388         crit_enter();
 2389         for (cp = tp->t_canq.c_cf, c = (cp != NULL ? *cp : 0);
 2390             cp != NULL; cp = nextc(&tp->t_canq, cp, &c))
 2391                 ttyecho(c, tp);
 2392         for (cp = tp->t_rawq.c_cf, c = (cp != NULL ? *cp : 0);
 2393             cp != NULL; cp = nextc(&tp->t_rawq, cp, &c))
 2394                 ttyecho(c, tp);
 2395         CLR(tp->t_state, TS_ERASE);
 2396         crit_exit();
 2397 
 2398         tp->t_rocount = tp->t_rawq.c_cc;
 2399         tp->t_rocol = 0;
 2400 }
 2401 
 2402 /*
 2403  * Echo a typed character to the terminal.
 2404  * NOTE: Must be called with tty_token held
 2405  */
 2406 static void
 2407 ttyecho(int c, struct tty *tp)
 2408 {
 2409         ASSERT_LWKT_TOKEN_HELD(&tty_token);
 2410 
 2411         if (!ISSET(tp->t_state, TS_CNTTB))
 2412                 CLR(tp->t_lflag, FLUSHO);
 2413         if ((!ISSET(tp->t_lflag, ECHO) &&
 2414              (c != '\n' || !ISSET(tp->t_lflag, ECHONL))) ||
 2415             ISSET(tp->t_lflag, EXTPROC))
 2416                 return;
 2417         if (ISSET(tp->t_lflag, ECHOCTL) &&
 2418             ((ISSET(c, TTY_CHARMASK) <= 037 && c != '\t' && c != '\n') ||
 2419             ISSET(c, TTY_CHARMASK) == 0177)) {
 2420                 (void)ttyoutput('^', tp);
 2421                 CLR(c, ~TTY_CHARMASK);
 2422                 if (c == 0177)
 2423                         c = '?';
 2424                 else
 2425                         c += 'A' - 1;
 2426         }
 2427         (void)ttyoutput(c, tp);
 2428 }
 2429 
 2430 /*
 2431  * Wake up any readers on a tty.
 2432  */
 2433 void
 2434 ttwakeup(struct tty *tp)
 2435 {
 2436         lwkt_gettoken(&tty_token);
 2437         if (ISSET(tp->t_state, TS_ASYNC) && tp->t_sigio != NULL)
 2438                 pgsigio(tp->t_sigio, SIGIO, (tp->t_session != NULL));
 2439         wakeup(TSA_HUP_OR_INPUT(tp));
 2440         KNOTE(&tp->t_rkq.ki_note, 0);
 2441         lwkt_reltoken(&tty_token);
 2442 }
 2443 
 2444 /*
 2445  * Wake up any writers on a tty.
 2446  */
 2447 void
 2448 ttwwakeup(struct tty *tp)
 2449 {
 2450         lwkt_gettoken(&tty_token);
 2451         if (ISSET(tp->t_state, TS_ASYNC) && tp->t_sigio != NULL)
 2452                 pgsigio(tp->t_sigio, SIGIO, (tp->t_session != NULL));
 2453         if (ISSET(tp->t_state, TS_BUSY | TS_SO_OCOMPLETE) ==
 2454             TS_SO_OCOMPLETE && tp->t_outq.c_cc == 0) {
 2455                 CLR(tp->t_state, TS_SO_OCOMPLETE);
 2456                 wakeup(TSA_OCOMPLETE(tp));
 2457         }
 2458         if (ISSET(tp->t_state, TS_SO_OLOWAT) &&
 2459             tp->t_outq.c_cc <= tp->t_olowat) {
 2460                 CLR(tp->t_state, TS_SO_OLOWAT);
 2461                 wakeup(TSA_OLOWAT(tp));
 2462         }
 2463         KNOTE(&tp->t_wkq.ki_note, 0);
 2464         lwkt_reltoken(&tty_token);
 2465 }
 2466 
 2467 /*
 2468  * Look up a code for a specified speed in a conversion table;
 2469  * used by drivers to map software speed values to hardware parameters.
 2470  * No requirements
 2471  */
 2472 int
 2473 ttspeedtab(int speed, struct speedtab *table)
 2474 {
 2475 
 2476         for ( ; table->sp_speed != -1; table++)
 2477                 if (table->sp_speed == speed)
 2478                         return (table->sp_code);
 2479         return (-1);
 2480 }
 2481 
 2482 /*
 2483  * Set input and output watermarks and buffer sizes.  For input, the
 2484  * high watermark is about one second's worth of input above empty, the
 2485  * low watermark is slightly below high water, and the buffer size is a
 2486  * driver-dependent amount above high water.  For output, the watermarks
 2487  * are near the ends of the buffer, with about 1 second's worth of input
 2488  * between them.  All this only applies to the standard line discipline.
 2489  */
 2490 void
 2491 ttsetwater(struct tty *tp)
 2492 {
 2493         int cps, ttmaxhiwat, x;
 2494 
 2495         lwkt_gettoken(&tty_token);
 2496         /* Input. */
 2497         clist_alloc_cblocks(&tp->t_canq, TTYHOG, 512);
 2498         switch (tp->t_ispeedwat) {
 2499         case (speed_t)-1:
 2500                 cps = tp->t_ispeed / 10;
 2501                 break;
 2502         case 0:
 2503                 /*
 2504                  * This case is for old drivers that don't know about
 2505                  * t_ispeedwat.  Arrange for them to get the old buffer
 2506                  * sizes and watermarks.
 2507                  */
 2508                 cps = TTYHOG - 2 * 256;
 2509                 tp->t_ififosize = 2 * 2048;
 2510                 break;
 2511         default:
 2512                 cps = tp->t_ispeedwat / 10;
 2513                 break;
 2514         }
 2515         tp->t_ihiwat = cps;
 2516         tp->t_ilowat = 7 * cps / 8;
 2517         x = cps + tp->t_ififosize;
 2518         clist_alloc_cblocks(&tp->t_rawq, x, x);
 2519 
 2520         /* Output. */
 2521         switch (tp->t_ospeedwat) {
 2522         case (speed_t)-1:
 2523                 cps = tp->t_ospeed / 10;
 2524                 ttmaxhiwat = 2 * TTMAXHIWAT;
 2525                 break;
 2526         case 0:
 2527                 cps = tp->t_ospeed / 10;
 2528                 ttmaxhiwat = TTMAXHIWAT;
 2529                 break;
 2530         default:
 2531                 cps = tp->t_ospeedwat / 10;
 2532                 ttmaxhiwat = 8 * TTMAXHIWAT;
 2533                 break;
 2534         }
 2535 #define CLAMP(x, h, l)  ((x) > h ? h : ((x) < l) ? l : (x))
 2536         tp->t_olowat = x = CLAMP(cps / 2, TTMAXLOWAT, TTMINLOWAT);
 2537         x += cps;
 2538         x = CLAMP(x, ttmaxhiwat, TTMINHIWAT);   /* XXX clamps are too magic */
 2539         tp->t_ohiwat = roundup(x, CBSIZE);      /* XXX for compat */
 2540         x = imax(tp->t_ohiwat, TTMAXHIWAT);     /* XXX for compat/safety */
 2541         x += OBUFSIZ + 100;
 2542         clist_alloc_cblocks(&tp->t_outq, x, x);
 2543 #undef  CLAMP
 2544         lwkt_reltoken(&tty_token);
 2545 }
 2546 
 2547 /*
 2548  * Report on state of foreground process group.
 2549  */
 2550 void
 2551 ttyinfo(struct tty *tp)
 2552 {
 2553         struct pgrp *pgrp;
 2554         struct proc *p, *pick;
 2555         struct lwp *lp;
 2556         struct rusage ru;
 2557         char buf[64];
 2558         const char *str;
 2559         struct vmspace *vm;
 2560         long vmsz;
 2561         int pctcpu;
 2562         int tmp;
 2563 
 2564         if (ttycheckoutq(tp,0) == 0)
 2565                 return;
 2566 
 2567         lwkt_gettoken(&tty_token);
 2568 
 2569         /*
 2570          * We always print the load average, then figure out what else to
 2571          * print based on the state of the current process group.
 2572          */
 2573         tmp = (averunnable.ldavg[0] * 100 + FSCALE / 2) >> FSHIFT;
 2574         ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100);
 2575 
 2576         if (tp->t_session == NULL) {
 2577                 ttyprintf(tp, "not a controlling terminal\n");
 2578                 goto done2;
 2579         }
 2580         if ((pgrp = tp->t_pgrp) == NULL) {
 2581                 ttyprintf(tp, "no foreground process group\n");
 2582                 goto done2;
 2583         }
 2584 
 2585         /*
 2586          * Pick an interesting process.  Note that certain elements,
 2587          * in particular the wmesg, require a critical section for
 2588          * safe access (YYY and we are still not MP safe).
 2589          *
 2590          * NOTE: lwp_wmesg is lwp_thread->td_wmesg.
 2591          */
 2592         pgref(pgrp);
 2593         lwkt_gettoken(&pgrp->pg_token);
 2594 
 2595         pick = NULL;
 2596         for (p = LIST_FIRST(&pgrp->pg_members);
 2597              p != NULL;
 2598              p = LIST_NEXT(p, p_pglist)) {
 2599                 PHOLD(p);
 2600                 if (proc_compare(pick, p)) {
 2601                         if (pick)
 2602                                 PRELE(pick);
 2603                         pick = p;
 2604                 } else {
 2605                         PRELE(p);
 2606                 }
 2607         }
 2608         if (pick == NULL) {
 2609                 ttyprintf(tp, "empty foreground process group\n");
 2610                 goto done1;
 2611         }
 2612 
 2613         /*
 2614          * Pick an interesting LWP (XXX)
 2615          *
 2616          * pick is held.
 2617          */
 2618         lp = FIRST_LWP_IN_PROC(pick);
 2619         if (lp == NULL) {
 2620                 PRELE(pick);
 2621                 ttyprintf(tp, "foreground process without lwp\n");
 2622                 goto done1;
 2623         }
 2624 
 2625         /*
 2626          * Figure out what wait/process-state message, and command
 2627          * buffer to present
 2628          */
 2629         /*
 2630          * XXX lwp This is a horrible mixture.  We need to rework this
 2631          * as soon as lwps have their own runnable status.
 2632          */
 2633         LWPHOLD(lp);
 2634         if (pick->p_flags & P_WEXIT)
 2635                 str = "exiting";
 2636         else if (lp->lwp_stat == LSRUN)
 2637                 str = "running";
 2638         else if (pick->p_stat == SIDL)
 2639                 str = "spawning";
 2640         else if (lp->lwp_wmesg) /* lwp_thread must not be NULL */
 2641                                 str = lp->lwp_wmesg;
 2642         else
 2643                 str = "iowait";
 2644 
 2645         ksnprintf(buf, sizeof(buf), "cmd: %s %d [%s]",
 2646                   pick->p_comm, pick->p_pid, str);
 2647 
 2648         /*
 2649          * Calculate cpu usage, percent cpu, and cmsz.  Note that
 2650          * 'pick' becomes invalid the moment we exit the critical
 2651          * section.
 2652          */
 2653         if (lp->lwp_thread && (pick->p_flags & P_SWAPPEDOUT) == 0)
 2654                 calcru_proc(pick, &ru);
 2655 
 2656         pctcpu = (lp->lwp_pctcpu * 10000 + FSCALE / 2) >> FSHIFT;
 2657 
 2658         LWPRELE(lp);
 2659 
 2660         if (pick->p_stat == SIDL || pick->p_stat == SZOMB) {
 2661                 vmsz = 0;
 2662         } else if ((vm = pick->p_vmspace) == NULL) {
 2663                 vmsz = 0;
 2664         } else {
 2665                 vmspace_hold(vm);
 2666                 vmsz = pgtok(vmspace_resident_count(vm));
 2667                 vmspace_drop(vm);
 2668         }
 2669         PRELE(pick);
 2670 
 2671         /*
 2672          * Dump the output
 2673          */
 2674         ttyprintf(tp, " %s ",
 2675                   buf);
 2676         ttyprintf(tp, "%ld.%02ldu ",
 2677                   ru.ru_utime.tv_sec, ru.ru_utime.tv_usec / 10000);
 2678         ttyprintf(tp, "%ld.%02lds ",
 2679                   ru.ru_stime.tv_sec, ru.ru_stime.tv_usec / 10000);
 2680         ttyprintf(tp, "%d%% %ldk\n",
 2681                   pctcpu / 100, vmsz);
 2682 
 2683 done1:
 2684         lwkt_reltoken(&pgrp->pg_token);
 2685         pgrel(pgrp);
 2686 done2:
 2687         tp->t_rocount = 0;      /* so pending input will be retyped if BS */
 2688         lwkt_reltoken(&tty_token);
 2689 }
 2690 
 2691 /*
 2692  * Returns 1 if p2 is "better" than p1
 2693  *
 2694  * The algorithm for picking the "interesting" process is thus:
 2695  *
 2696  *      1) Only foreground processes are eligible - implied.
 2697  *      2) Runnable processes are favored over anything else.  The runner
 2698  *         with the highest cpu utilization is picked (p_cpticks).  Ties are
 2699  *         broken by picking the highest pid.
 2700  *      3) The sleeper with the shortest sleep time is next.  With ties,
 2701  *         we pick out just "short-term" sleepers (LWP_SINTR == 0).
 2702  *      4) Further ties are broken by picking the highest pid.
 2703  *
 2704  * NOTE: must be called with p1 and p2 held.
 2705  */
 2706 #define ISRUN(lp)       ((lp)->lwp_stat == LSRUN)
 2707 #define TESTAB(a, b)    ((a)<<1 | (b))
 2708 #define ONLYA   2
 2709 #define ONLYB   1
 2710 #define BOTH    3
 2711 
 2712 static int
 2713 proc_compare(struct proc *p1, struct proc *p2)
 2714 {
 2715         struct lwp *lp1, *lp2;
 2716         int res;
 2717 
 2718         if (p1 == NULL)
 2719                 return (1);
 2720         if (lwkt_trytoken(&p1->p_token) == 0)
 2721                 return (1);
 2722         if (lwkt_trytoken(&p2->p_token) == 0) {
 2723                 lwkt_reltoken(&p1->p_token);
 2724                 return (0);
 2725         }
 2726 
 2727         /*
 2728          * weed out zombies
 2729          */
 2730         switch (TESTAB(p1->p_stat == SZOMB, p2->p_stat == SZOMB)) {
 2731         case ONLYA:
 2732                 res = 1;
 2733                 goto done;
 2734         case ONLYB:
 2735                 res = 0;
 2736                 goto done;
 2737         case BOTH:
 2738                 res = (p2->p_pid > p1->p_pid);  /* tie - return highest pid */
 2739                 goto done;
 2740         default:
 2741                 break;
 2742         }
 2743 
 2744         /* XXX choose the best lwp? */
 2745         lp1 = FIRST_LWP_IN_PROC(p1);
 2746         lp2 = FIRST_LWP_IN_PROC(p2);
 2747 
 2748         /*
 2749          * Favor one with LWPs verses one that has none (is exiting).
 2750          */
 2751         if (lp1 == NULL) {
 2752                 res = 1;
 2753                 goto done;
 2754         }
 2755         if (lp2 == NULL) {
 2756                 res = 0;
 2757                 goto done;
 2758         }
 2759 
 2760         /*
 2761          * see if at least one of them is runnable
 2762          */
 2763         switch (TESTAB(ISRUN(lp1), ISRUN(lp2))) {
 2764         case ONLYA:
 2765                 res = 0;
 2766                 goto done;
 2767         case ONLYB:
 2768                 res = 1;
 2769                 goto done;
 2770         case BOTH:
 2771                 /*
 2772                  * tie - favor one with highest recent cpu utilization
 2773                  */
 2774                 if (lp2->lwp_cpticks > lp1->lwp_cpticks)
 2775                         res = 1;
 2776                 else if (lp1->lwp_cpticks > lp2->lwp_cpticks)
 2777                         res = 0;
 2778                 else
 2779                         res = (p2->p_pid > p1->p_pid); /* tie - ret highest */
 2780                 goto done;
 2781         default:
 2782                 break;
 2783         }
 2784 
 2785         /*
 2786          * Pick the one with the smallest sleep time
 2787          */
 2788         if (lp2->lwp_slptime > lp1->lwp_slptime) {
 2789                 res = 0;
 2790                 goto done;
 2791         }
 2792         if (lp1->lwp_slptime > lp2->lwp_slptime) {
 2793                 res = 1;
 2794                 goto done;
 2795         }
 2796 
 2797         /*
 2798          * Favor one sleeping in a non-interruptible sleep
 2799          */
 2800         if ((lp1->lwp_flags & LWP_SINTR) && (lp2->lwp_flags & LWP_SINTR) == 0)
 2801                 res = 1;
 2802         else
 2803         if ((lp2->lwp_flags & LWP_SINTR) && (lp1->lwp_flags & LWP_SINTR) == 0)
 2804                 res = 0;
 2805         else
 2806                 res = (p2->p_pid > p1->p_pid);  /* tie - return highest pid */
 2807         /* fall through */
 2808 
 2809 done:
 2810         lwkt_reltoken(&p2->p_token);
 2811         lwkt_reltoken(&p1->p_token);
 2812         return (res);
 2813 }
 2814 
 2815 /*
 2816  * Output char to tty; console putchar style.
 2817  */
 2818 int
 2819 tputchar(int c, struct tty *tp)
 2820 {
 2821         crit_enter();
 2822         lwkt_gettoken(&tty_token);
 2823         if (!ISSET(tp->t_state, TS_CONNECTED)) {
 2824                 lwkt_reltoken(&tty_token);
 2825                 crit_exit();
 2826                 return (-1);
 2827         }
 2828         if (c == '\n')
 2829                 (void)ttyoutput('\r', tp);
 2830         (void)ttyoutput(c, tp);
 2831         ttstart(tp);
 2832         lwkt_reltoken(&tty_token);
 2833         crit_exit();
 2834         return (0);
 2835 }
 2836 
 2837 /*
 2838  * Sleep on chan, returning ERESTART if tty changed while we napped and
 2839  * returning any errors (e.g. EINTR/EWOULDBLOCK) reported by tsleep.  If
 2840  * the tty is revoked, restarting a pending call will redo validation done
 2841  * at the start of the call.
 2842  */
 2843 int
 2844 ttysleep(struct tty *tp, void *chan, int slpflags, char *wmesg, int timo)
 2845 {
 2846         int error;
 2847         int gen;
 2848 
 2849         gen = tp->t_gen;
 2850         error = tsleep(chan, slpflags, wmesg, timo);
 2851         if (error)
 2852                 return (error);
 2853         return (tp->t_gen == gen ? 0 : ERESTART);
 2854 }
 2855 
 2856 /*
 2857  * Revoke a tty.
 2858  *
 2859  * We bump the gen to force any ttysleep()'s to return with ERESTART
 2860  * and flush the tty.  The related fp's should already have been
 2861  * replaced so the tty will close when the last references on the
 2862  * original fp's go away.
 2863  */
 2864 int
 2865 ttyrevoke(struct dev_revoke_args *ap)
 2866 {
 2867         struct tty *tp;
 2868 
 2869         lwkt_gettoken(&tty_token);
 2870         tp = ap->a_head.a_dev->si_tty;
 2871         tp->t_gen++;
 2872         ttyflush(tp, FREAD | FWRITE);
 2873         wakeup(TSA_CARR_ON(tp));
 2874         ttwakeup(tp);
 2875         ttwwakeup(tp);
 2876         lwkt_reltoken(&tty_token);
 2877         return (0);
 2878 }
 2879 
 2880 /*
 2881  * Allocate a tty struct.  Clists in the struct will be allocated by
 2882  * ttyopen().
 2883  */
 2884 struct tty *
 2885 ttymalloc(struct tty *tp)
 2886 {
 2887 
 2888         if (tp) {
 2889                 return(tp);
 2890         }
 2891         tp = kmalloc(sizeof *tp, M_TTYS, M_WAITOK|M_ZERO);
 2892         ttyregister(tp);
 2893         return (tp);
 2894 }
 2895 
 2896 void
 2897 ttyunregister(struct tty *tp)
 2898 {
 2899         lwkt_gettoken(&tty_token);
 2900         KKASSERT(ISSET(tp->t_state, TS_REGISTERED));
 2901         CLR(tp->t_state, TS_REGISTERED);
 2902         TAILQ_REMOVE(&tty_list, tp, t_list);
 2903         lwkt_reltoken(&tty_token);
 2904 }
 2905 
 2906 void
 2907 ttyregister(struct tty *tp)
 2908 {
 2909         lwkt_gettoken(&tty_token);
 2910         KKASSERT(!ISSET(tp->t_state, TS_REGISTERED));
 2911         SET(tp->t_state, TS_REGISTERED);
 2912         TAILQ_INSERT_HEAD(&tty_list, tp, t_list);
 2913         lwkt_reltoken(&tty_token);
 2914 }
 2915 
 2916 static int
 2917 sysctl_kern_ttys(SYSCTL_HANDLER_ARGS)
 2918 {
 2919         int error;
 2920         struct tty *tp;
 2921         struct tty t;
 2922         struct tty marker;
 2923 
 2924         bzero(&marker, sizeof(marker));
 2925         marker.t_state = TS_MARKER;
 2926         error = 0;
 2927 
 2928         lwkt_gettoken(&tty_token);
 2929 
 2930         TAILQ_INSERT_HEAD(&tty_list, &marker, t_list);
 2931         while ((tp = TAILQ_NEXT(&marker, t_list)) != NULL) {
 2932                 TAILQ_REMOVE(&tty_list, &marker, t_list);
 2933                 TAILQ_INSERT_AFTER(&tty_list, tp, &marker, t_list);
 2934                 if (tp->t_state & TS_MARKER)
 2935                         continue;
 2936                 t = *tp;
 2937                 if (t.t_dev)
 2938                         t.t_dev = (cdev_t)(uintptr_t)dev2udev(t.t_dev);
 2939                 error = SYSCTL_OUT(req, (caddr_t)&t, sizeof(t));
 2940                 if (error)
 2941                         break;
 2942         }
 2943         TAILQ_REMOVE(&tty_list, &marker, t_list);
 2944         lwkt_reltoken(&tty_token);
 2945         return (error);
 2946 }
 2947 
 2948 SYSCTL_PROC(_kern, OID_AUTO, ttys, CTLTYPE_OPAQUE|CTLFLAG_RD,
 2949         0, 0, sysctl_kern_ttys, "S,tty", "All struct ttys");
 2950 
 2951 void
 2952 nottystop(struct tty *tp, int rw)
 2953 {
 2954         return;
 2955 }
 2956 
 2957 int
 2958 ttyread(struct dev_read_args *ap)
 2959 {
 2960         struct tty *tp;
 2961         int ret;
 2962 
 2963         tp = ap->a_head.a_dev->si_tty;
 2964         if (tp == NULL)
 2965                 return (ENODEV);
 2966         lwkt_gettoken(&tty_token);
 2967         ret = ((*linesw[tp->t_line].l_read)(tp, ap->a_uio, ap->a_ioflag));
 2968         lwkt_reltoken(&tty_token);
 2969 
 2970         return ret;
 2971 }
 2972 
 2973 int
 2974 ttywrite(struct dev_write_args *ap)
 2975 {
 2976         struct tty *tp;
 2977         int ret;
 2978 
 2979         tp = ap->a_head.a_dev->si_tty;
 2980         if (tp == NULL)
 2981                 return (ENODEV);
 2982         lwkt_gettoken(&tty_token);
 2983         ret = ((*linesw[tp->t_line].l_write)(tp, ap->a_uio, ap->a_ioflag));
 2984         lwkt_reltoken(&tty_token);
 2985 
 2986         return ret;
 2987 }

Cache object: 96727701f5efaba4e654a9a509012539


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


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