Annotation of kernel/bsd/kern/tty.c, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.