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

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

unix.superglobalmegacorp.com

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