Annotation of Net2/kern/tty.c, revision 1.1

1.1     ! root        1: /*-
        !             2:  * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
        !             3:  * Copyright (c) 1991 The Regents of the University of California.
        !             4:  * All rights reserved.
        !             5:  *
        !             6:  * Redistribution and use in source and binary forms, with or without
        !             7:  * modification, are permitted provided that the following conditions
        !             8:  * are met:
        !             9:  * 1. Redistributions of source code must retain the above copyright
        !            10:  *    notice, this list of conditions and the following disclaimer.
        !            11:  * 2. Redistributions in binary form must reproduce the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer in the
        !            13:  *    documentation and/or other materials provided with the distribution.
        !            14:  * 3. All advertising materials mentioning features or use of this software
        !            15:  *    must display the following acknowledgement:
        !            16:  *     This product includes software developed by the University of
        !            17:  *     California, Berkeley and its contributors.
        !            18:  * 4. Neither the name of the University nor the names of its contributors
        !            19:  *    may be used to endorse or promote products derived from this software
        !            20:  *    without specific prior written permission.
        !            21:  *
        !            22:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            23:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            24:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            25:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            26:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            27:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            28:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            29:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            30:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            31:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            32:  * SUCH DAMAGE.
        !            33:  *
        !            34:  *     @(#)tty.c       7.44 (Berkeley) 5/28/91
        !            35:  */
        !            36: 
        !            37: #include "param.h"
        !            38: #include "systm.h"
        !            39: #include "ioctl.h"
        !            40: #define TTYDEFCHARS
        !            41: #include "tty.h"
        !            42: #undef TTYDEFCHARS
        !            43: #include "proc.h"
        !            44: #include "file.h"
        !            45: #include "conf.h"
        !            46: #include "dkstat.h"
        !            47: #include "uio.h"
        !            48: #include "kernel.h"
        !            49: #include "vnode.h"
        !            50: #include "syslog.h"
        !            51: 
        !            52: #include "vm/vm.h"
        !            53: 
        !            54: static int proc_compare __P((struct proc *p1, struct proc *p2));
        !            55: 
        !            56: /* symbolic sleep message strings */
        !            57: char ttyin[] = "ttyin";
        !            58: char ttyout[] = "ttyout";
        !            59: char ttopen[] = "ttyopn";
        !            60: char ttclos[] = "ttycls";
        !            61: char ttybg[] = "ttybg";
        !            62: char ttybuf[] = "ttybuf";
        !            63: 
        !            64: /*
        !            65:  * Table giving parity for characters and indicating
        !            66:  * character classes to tty driver. The 8th bit
        !            67:  * indicates parity, the 7th bit indicates the character
        !            68:  * is an alphameric or underscore (for ALTWERASE), and the 
        !            69:  * low 6 bits indicate delay type.  If the low 6 bits are 0
        !            70:  * then the character needs no special processing on output;
        !            71:  * classes other than 0 might be translated or (not currently)
        !            72:  * require delays.
        !            73:  */
        !            74: #define        PARITY(c)       (partab[c] & 0x80)
        !            75: #define        ISALPHA(c)      (partab[(c)&TTY_CHARMASK] & 0x40)
        !            76: #define        CCLASSMASK      0x3f
        !            77: #define        CCLASS(c)       (partab[c] & CCLASSMASK)
        !            78: 
        !            79: #define        E       0x00    /* even parity */
        !            80: #define        O       0x80    /* odd parity */
        !            81: #define        ALPHA   0x40    /* alpha or underscore */
        !            82: 
        !            83: #define        NO      ORDINARY
        !            84: #define        NA      ORDINARY|ALPHA
        !            85: #define        CC      CONTROL
        !            86: #define        BS      BACKSPACE
        !            87: #define        NL      NEWLINE
        !            88: #define        TB      TAB
        !            89: #define        VT      VTAB
        !            90: #define        CR      RETURN
        !            91: 
        !            92: char partab[] = {
        !            93:        E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* nul - bel */
        !            94:        O|BS, E|TB, E|NL, O|CC, E|VT, O|CR, O|CC, E|CC, /* bs - si */
        !            95:        O|CC, E|CC, E|CC, O|CC, E|CC, O|CC, O|CC, E|CC, /* dle - etb */
        !            96:        E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* can - us */
        !            97:        O|NO, E|NO, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* sp - ' */
        !            98:        E|NO, O|NO, O|NO, E|NO, O|NO, E|NO, E|NO, O|NO, /* ( - / */
        !            99:        E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* 0 - 7 */
        !           100:        O|NA, E|NA, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* 8 - ? */
        !           101:        O|NO, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* @ - G */
        !           102:        E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* H - O */
        !           103:        E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* P - W */
        !           104:        O|NA, E|NA, E|NA, O|NO, E|NO, O|NO, O|NO, O|NA, /* X - _ */
        !           105:        E|NO, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* ` - g */
        !           106:        O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* h - o */
        !           107:        O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* p - w */
        !           108:        E|NA, O|NA, O|NA, E|NO, O|NO, E|NO, E|NO, O|CC, /* x - del */
        !           109:        /*
        !           110:         * "meta" chars; should be settable per charset.
        !           111:         * For now, treat all as normal characters.
        !           112:         */
        !           113:        NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
        !           114:        NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
        !           115:        NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
        !           116:        NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
        !           117:        NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
        !           118:        NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
        !           119:        NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
        !           120:        NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
        !           121:        NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
        !           122:        NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
        !           123:        NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
        !           124:        NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
        !           125:        NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
        !           126:        NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
        !           127:        NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
        !           128:        NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
        !           129: };
        !           130: #undef NO
        !           131: #undef NA
        !           132: #undef CC
        !           133: #undef BS
        !           134: #undef NL
        !           135: #undef TB
        !           136: #undef VT
        !           137: #undef CR
        !           138: 
        !           139: extern struct tty *constty;            /* temporary virtual console */
        !           140: 
        !           141: /*
        !           142:  * Is 'c' a line delimiter ("break" character)?
        !           143:  */
        !           144: #define ttbreakc(c) ((c) == '\n' || ((c) == cc[VEOF] || \
        !           145:        (c) == cc[VEOL] || (c) == cc[VEOL2]) && (c) != _POSIX_VDISABLE)
        !           146: 
        !           147: ttychars(tp)
        !           148:        struct tty *tp;
        !           149: {
        !           150: 
        !           151:        bcopy(ttydefchars, tp->t_cc, sizeof(ttydefchars));
        !           152: }
        !           153: 
        !           154: /*
        !           155:  * Flush tty after output has drained.
        !           156:  */
        !           157: ttywflush(tp)
        !           158:        struct tty *tp;
        !           159: {
        !           160:        int error;
        !           161: 
        !           162:        if ((error = ttywait(tp)) == 0)
        !           163:                ttyflush(tp, FREAD);
        !           164:        return (error);
        !           165: }
        !           166: 
        !           167: /*
        !           168:  * Wait for output to drain.
        !           169:  */
        !           170: ttywait(tp)
        !           171:        register struct tty *tp;
        !           172: {
        !           173:        int error = 0, s = spltty();
        !           174: 
        !           175:        while ((tp->t_outq.c_cc || tp->t_state&TS_BUSY) &&
        !           176:            (tp->t_state&TS_CARR_ON || tp->t_cflag&CLOCAL) && 
        !           177:            tp->t_oproc) {
        !           178:                (*tp->t_oproc)(tp);
        !           179:                tp->t_state |= TS_ASLEEP;
        !           180:                if (error = ttysleep(tp, (caddr_t)&tp->t_outq, 
        !           181:                    TTOPRI | PCATCH, ttyout, 0))
        !           182:                        break;
        !           183:        }
        !           184:        splx(s);
        !           185:        return (error);
        !           186: }
        !           187: 
        !           188: #define        flushq(qq) { \
        !           189:        register struct clist *q = qq; \
        !           190:        if (q->c_cc) \
        !           191:                ndflush(q, q->c_cc); \
        !           192: }
        !           193: 
        !           194: /*
        !           195:  * Flush TTY read and/or write queues,
        !           196:  * notifying anyone waiting.
        !           197:  */
        !           198: ttyflush(tp, rw)
        !           199:        register struct tty *tp;
        !           200: {
        !           201:        register s;
        !           202: 
        !           203:        s = spltty();
        !           204:        if (rw & FREAD) {
        !           205:                flushq(&tp->t_canq);
        !           206:                flushq(&tp->t_rawq);
        !           207:                tp->t_rocount = 0;
        !           208:                tp->t_rocol = 0;
        !           209:                tp->t_state &= ~TS_LOCAL;
        !           210:                ttwakeup(tp);
        !           211:        }
        !           212:        if (rw & FWRITE) {
        !           213:                tp->t_state &= ~TS_TTSTOP;
        !           214:                (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
        !           215:                flushq(&tp->t_outq);
        !           216:                wakeup((caddr_t)&tp->t_outq);
        !           217:                if (tp->t_wsel) {
        !           218:                        selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
        !           219:                        tp->t_wsel = 0;
        !           220:                        tp->t_state &= ~TS_WCOLL;
        !           221:                }
        !           222:        }
        !           223:        splx(s);
        !           224: }
        !           225: 
        !           226: /*
        !           227:  * Send stop character on input overflow.
        !           228:  */
        !           229: ttyblock(tp)
        !           230:        register struct tty *tp;
        !           231: {
        !           232:        register x;
        !           233: 
        !           234:        x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
        !           235:        if (tp->t_rawq.c_cc > TTYHOG) {
        !           236:                ttyflush(tp, FREAD|FWRITE);
        !           237:                tp->t_state &= ~TS_TBLOCK;
        !           238:        }
        !           239:        /*
        !           240:         * Block further input iff:
        !           241:         * Current input > threshold AND input is available to user program
        !           242:         */
        !           243:        if (x >= TTYHOG/2 && (tp->t_state & TS_TBLOCK) == 0 &&
        !           244:            ((tp->t_lflag&ICANON) == 0) || (tp->t_canq.c_cc > 0) &&
        !           245:            tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
        !           246:                if (putc(tp->t_cc[VSTOP], &tp->t_outq) == 0) {
        !           247:                        tp->t_state |= TS_TBLOCK;
        !           248:                        ttstart(tp);
        !           249:                }
        !           250:        }
        !           251: }
        !           252: 
        !           253: ttstart(tp)
        !           254:        struct tty *tp;
        !           255: {
        !           256: 
        !           257:        if (tp->t_oproc)                /* kludge for pty */
        !           258:                (*tp->t_oproc)(tp);
        !           259: }
        !           260: 
        !           261: ttrstrt(tp)                            /* XXX */
        !           262:        struct tty *tp;
        !           263: {
        !           264: 
        !           265: #ifdef DIAGNOSTIC
        !           266:        if (tp == 0)
        !           267:                panic("ttrstrt");
        !           268: #endif
        !           269:        tp->t_state &= ~TS_TIMEOUT;
        !           270:        ttstart(tp);
        !           271: }
        !           272: 
        !           273: 
        !           274: /*
        !           275:  * Common code for ioctls on tty devices.
        !           276:  * Called after line-discipline-specific ioctl
        !           277:  * has been called to do discipline-specific functions
        !           278:  * and/or reject any of these ioctl commands.
        !           279:  */
        !           280: /*ARGSUSED*/
        !           281: ttioctl(tp, com, data, flag)
        !           282:        register struct tty *tp;
        !           283:        caddr_t data;
        !           284: {
        !           285:        register struct proc *p = curproc;              /* XXX */
        !           286:        extern int nldisp;
        !           287:        int s, error;
        !           288: 
        !           289:        /*
        !           290:         * If the ioctl involves modification,
        !           291:         * hang if in the background.
        !           292:         */
        !           293:        switch (com) {
        !           294: 
        !           295:        case TIOCSETD: 
        !           296:        case TIOCFLUSH:
        !           297:        /*case TIOCSPGRP:*/
        !           298:        case TIOCSTI:
        !           299:        case TIOCSWINSZ:
        !           300:        case TIOCSETA:
        !           301:        case TIOCSETAW:
        !           302:        case TIOCSETAF:
        !           303: #ifdef COMPAT_43
        !           304:        case TIOCSETP:
        !           305:        case TIOCSETN:
        !           306:        case TIOCSETC:
        !           307:        case TIOCSLTC:
        !           308:        case TIOCLBIS:
        !           309:        case TIOCLBIC:
        !           310:        case TIOCLSET:
        !           311:        case OTIOCSETD:
        !           312: #endif
        !           313:                while (isbackground(curproc, tp) && 
        !           314:                   p->p_pgrp->pg_jobc && (p->p_flag&SPPWAIT) == 0 &&
        !           315:                   (p->p_sigignore & sigmask(SIGTTOU)) == 0 &&
        !           316:                   (p->p_sigmask & sigmask(SIGTTOU)) == 0) {
        !           317:                        pgsignal(p->p_pgrp, SIGTTOU, 1);
        !           318:                        if (error = ttysleep(tp, (caddr_t)&lbolt, 
        !           319:                            TTOPRI | PCATCH, ttybg, 0)) 
        !           320:                                return (error);
        !           321:                }
        !           322:                break;
        !           323:        }
        !           324: 
        !           325:        /*
        !           326:         * Process the ioctl.
        !           327:         */
        !           328:        switch (com) {
        !           329: 
        !           330:        /* get discipline number */
        !           331:        case TIOCGETD:
        !           332:                *(int *)data = tp->t_line;
        !           333:                break;
        !           334: 
        !           335:        /* set line discipline */
        !           336:        case TIOCSETD: {
        !           337:                register int t = *(int *)data;
        !           338:                dev_t dev = tp->t_dev;
        !           339: 
        !           340:                if ((unsigned)t >= nldisp)
        !           341:                        return (ENXIO);
        !           342:                if (t != tp->t_line) {
        !           343:                        s = spltty();
        !           344:                        (*linesw[tp->t_line].l_close)(tp, flag);
        !           345:                        error = (*linesw[t].l_open)(dev, tp);
        !           346:                        if (error) {
        !           347:                                (void)(*linesw[tp->t_line].l_open)(dev, tp);
        !           348:                                splx(s);
        !           349:                                return (error);
        !           350:                        }
        !           351:                        tp->t_line = t;
        !           352:                        splx(s);
        !           353:                }
        !           354:                break;
        !           355:        }
        !           356: 
        !           357:        /* prevent more opens on channel */
        !           358:        case TIOCEXCL:
        !           359:                tp->t_state |= TS_XCLUDE;
        !           360:                break;
        !           361: 
        !           362:        case TIOCNXCL:
        !           363:                tp->t_state &= ~TS_XCLUDE;
        !           364:                break;
        !           365: 
        !           366:        case TIOCHPCL:
        !           367:                tp->t_cflag |= HUPCL;
        !           368:                break;
        !           369: 
        !           370:        case TIOCFLUSH: {
        !           371:                register int flags = *(int *)data;
        !           372: 
        !           373:                if (flags == 0)
        !           374:                        flags = FREAD|FWRITE;
        !           375:                else
        !           376:                        flags &= FREAD|FWRITE;
        !           377:                ttyflush(tp, flags);
        !           378:                break;
        !           379:        }
        !           380: 
        !           381:        case FIOASYNC:
        !           382:                if (*(int *)data)
        !           383:                        tp->t_state |= TS_ASYNC;
        !           384:                else
        !           385:                        tp->t_state &= ~TS_ASYNC;
        !           386:                break;
        !           387: 
        !           388:        case FIONBIO:
        !           389:                break;  /* XXX remove */
        !           390: 
        !           391:        /* return number of characters immediately available */
        !           392:        case FIONREAD:
        !           393:                *(off_t *)data = ttnread(tp);
        !           394:                break;
        !           395: 
        !           396:        case TIOCOUTQ:
        !           397:                *(int *)data = tp->t_outq.c_cc;
        !           398:                break;
        !           399: 
        !           400:        case TIOCSTOP:
        !           401:                s = spltty();
        !           402:                if ((tp->t_state&TS_TTSTOP) == 0) {
        !           403:                        tp->t_state |= TS_TTSTOP;
        !           404:                        (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
        !           405:                }
        !           406:                splx(s);
        !           407:                break;
        !           408: 
        !           409:        case TIOCSTART:
        !           410:                s = spltty();
        !           411:                if ((tp->t_state&TS_TTSTOP) || (tp->t_lflag&FLUSHO)) {
        !           412:                        tp->t_state &= ~TS_TTSTOP;
        !           413:                        tp->t_lflag &= ~FLUSHO;
        !           414:                        ttstart(tp);
        !           415:                }
        !           416:                splx(s);
        !           417:                break;
        !           418: 
        !           419:        /*
        !           420:         * Simulate typing of a character at the terminal.
        !           421:         */
        !           422:        case TIOCSTI:
        !           423:                if (p->p_ucred->cr_uid && (flag & FREAD) == 0)
        !           424:                        return (EPERM);
        !           425:                if (p->p_ucred->cr_uid && !isctty(p, tp))
        !           426:                        return (EACCES);
        !           427:                (*linesw[tp->t_line].l_rint)(*(char *)data, tp);
        !           428:                break;
        !           429: 
        !           430:        case TIOCGETA: {
        !           431:                struct termios *t = (struct termios *)data;
        !           432: 
        !           433:                bcopy(&tp->t_termios, t, sizeof(struct termios));
        !           434:                break;
        !           435:        }
        !           436: 
        !           437:        case TIOCSETA:
        !           438:        case TIOCSETAW:
        !           439:        case TIOCSETAF: {
        !           440:                register struct termios *t = (struct termios *)data;
        !           441: 
        !           442:                s = spltty();
        !           443:                if (com == TIOCSETAW || com == TIOCSETAF) {
        !           444:                        if (error = ttywait(tp)) {
        !           445:                                splx(s);
        !           446:                                return (error);
        !           447:                        }
        !           448:                        if (com == TIOCSETAF)
        !           449:                                ttyflush(tp, FREAD);
        !           450:                }
        !           451:                if ((t->c_cflag&CIGNORE) == 0) {
        !           452:                        /*
        !           453:                         * set device hardware
        !           454:                         */
        !           455:                        if (tp->t_param && (error = (*tp->t_param)(tp, t))) {
        !           456:                                splx(s);
        !           457:                                return (error);
        !           458:                        } else {
        !           459:                                if ((tp->t_state&TS_CARR_ON) == 0 &&
        !           460:                                    (tp->t_cflag&CLOCAL) &&
        !           461:                                    (t->c_cflag&CLOCAL) == 0) {
        !           462:                                        tp->t_state &= ~TS_ISOPEN;
        !           463:                                        tp->t_state |= TS_WOPEN;
        !           464:                                        ttwakeup(tp);
        !           465:                                }
        !           466:                                tp->t_cflag = t->c_cflag;
        !           467:                                tp->t_ispeed = t->c_ispeed;
        !           468:                                tp->t_ospeed = t->c_ospeed;
        !           469:                        }
        !           470:                        ttsetwater(tp);
        !           471:                }
        !           472:                if (com != TIOCSETAF) {
        !           473:                        if ((t->c_lflag&ICANON) != (tp->t_lflag&ICANON))
        !           474:                                if (t->c_lflag&ICANON) {        
        !           475:                                        tp->t_lflag |= PENDIN;
        !           476:                                        ttwakeup(tp);
        !           477:                                }
        !           478:                                else {
        !           479:                                        struct clist tq;
        !           480: 
        !           481:                                        catq(&tp->t_rawq, &tp->t_canq);
        !           482:                                        tq = tp->t_rawq;
        !           483:                                        tp->t_rawq = tp->t_canq;
        !           484:                                        tp->t_canq = tq;
        !           485:                                }
        !           486:                }
        !           487:                tp->t_iflag = t->c_iflag;
        !           488:                tp->t_oflag = t->c_oflag;
        !           489:                /*
        !           490:                 * Make the EXTPROC bit read only.
        !           491:                 */
        !           492:                if (tp->t_lflag&EXTPROC)
        !           493:                        t->c_lflag |= EXTPROC;
        !           494:                else
        !           495:                        t->c_lflag &= ~EXTPROC;
        !           496:                tp->t_lflag = t->c_lflag;
        !           497:                bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc));
        !           498:                splx(s);
        !           499:                break;
        !           500:        }
        !           501: 
        !           502:        /*
        !           503:         * Set controlling terminal.
        !           504:         * Session ctty vnode pointer set in vnode layer.
        !           505:         */
        !           506:        case TIOCSCTTY:
        !           507:                if (!SESS_LEADER(p) || 
        !           508:                   (p->p_session->s_ttyvp || tp->t_session) &&
        !           509:                   (tp->t_session != p->p_session))
        !           510:                        return (EPERM);
        !           511:                tp->t_session = p->p_session;
        !           512:                tp->t_pgrp = p->p_pgrp;
        !           513:                p->p_session->s_ttyp = tp;
        !           514:                p->p_flag |= SCTTY;
        !           515:                break;
        !           516:                
        !           517:        /*
        !           518:         * Set terminal process group.
        !           519:         */
        !           520:        case TIOCSPGRP: {
        !           521:                register struct pgrp *pgrp = pgfind(*(int *)data);
        !           522: 
        !           523:                if (!isctty(p, tp))
        !           524:                        return (ENOTTY);
        !           525:                else if (pgrp == NULL || pgrp->pg_session != p->p_session)
        !           526:                        return (EPERM);
        !           527:                tp->t_pgrp = pgrp;
        !           528:                break;
        !           529:        }
        !           530: 
        !           531:        case TIOCGPGRP:
        !           532:                if (!isctty(p, tp))
        !           533:                        return (ENOTTY);
        !           534:                *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
        !           535:                break;
        !           536: 
        !           537:        case TIOCSWINSZ:
        !           538:                if (bcmp((caddr_t)&tp->t_winsize, data,
        !           539:                    sizeof (struct winsize))) {
        !           540:                        tp->t_winsize = *(struct winsize *)data;
        !           541:                        pgsignal(tp->t_pgrp, SIGWINCH, 1);
        !           542:                }
        !           543:                break;
        !           544: 
        !           545:        case TIOCGWINSZ:
        !           546:                *(struct winsize *)data = tp->t_winsize;
        !           547:                break;
        !           548: 
        !           549:        case TIOCCONS:
        !           550:                if (*(int *)data) {
        !           551:                        if (constty && constty != tp &&
        !           552:                            (constty->t_state & (TS_CARR_ON|TS_ISOPEN)) ==
        !           553:                            (TS_CARR_ON|TS_ISOPEN))
        !           554:                                return (EBUSY);
        !           555: #ifndef        UCONSOLE
        !           556:                        if (error = suser(p->p_ucred, &p->p_acflag))
        !           557:                                return (error);
        !           558: #endif
        !           559:                        constty = tp;
        !           560:                } else if (tp == constty)
        !           561:                        constty = NULL;
        !           562:                break;
        !           563: 
        !           564:        case TIOCDRAIN:
        !           565:                if (error = ttywait(tp))
        !           566:                        return (error);
        !           567:                break;
        !           568: 
        !           569:        default:
        !           570: #ifdef COMPAT_43
        !           571:                return (ttcompat(tp, com, data, flag));
        !           572: #else
        !           573:                return (-1);
        !           574: #endif
        !           575:        }
        !           576:        return (0);
        !           577: }
        !           578: 
        !           579: ttnread(tp)
        !           580:        struct tty *tp;
        !           581: {
        !           582:        int nread = 0;
        !           583: 
        !           584:        if (tp->t_lflag & PENDIN)
        !           585:                ttypend(tp);
        !           586:        nread = tp->t_canq.c_cc;
        !           587:        if ((tp->t_lflag & ICANON) == 0)
        !           588:                nread += tp->t_rawq.c_cc;
        !           589:        return (nread);
        !           590: }
        !           591: 
        !           592: ttselect(dev, rw)
        !           593:        dev_t dev;
        !           594:        int rw;
        !           595: {
        !           596:        register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
        !           597:        int nread;
        !           598:        int s = spltty();
        !           599: 
        !           600:        switch (rw) {
        !           601: 
        !           602:        case FREAD:
        !           603:                nread = ttnread(tp);
        !           604:                if (nread > 0 || 
        !           605:                   ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0))
        !           606:                        goto win;
        !           607:                if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
        !           608:                        tp->t_state |= TS_RCOLL;
        !           609:                else
        !           610:                        tp->t_rsel = curproc;
        !           611:                break;
        !           612: 
        !           613:        case FWRITE:
        !           614:                if (tp->t_outq.c_cc <= tp->t_lowat)
        !           615:                        goto win;
        !           616:                if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
        !           617:                        tp->t_state |= TS_WCOLL;
        !           618:                else
        !           619:                        tp->t_wsel = curproc;
        !           620:                break;
        !           621:        }
        !           622:        splx(s);
        !           623:        return (0);
        !           624: win:
        !           625:        splx(s);
        !           626:        return (1);
        !           627: }
        !           628: 
        !           629: /*
        !           630:  * Initial open of tty, or (re)entry to standard tty line discipline.
        !           631:  */
        !           632: ttyopen(dev, tp)
        !           633:        dev_t dev;
        !           634:        register struct tty *tp;
        !           635: {
        !           636: 
        !           637:        tp->t_dev = dev;
        !           638: 
        !           639:        tp->t_state &= ~TS_WOPEN;
        !           640:        if ((tp->t_state & TS_ISOPEN) == 0) {
        !           641:                tp->t_state |= TS_ISOPEN;
        !           642:                bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize));
        !           643:        }
        !           644:        return (0);
        !           645: }
        !           646: 
        !           647: /*
        !           648:  * "close" a line discipline
        !           649:  */
        !           650: ttylclose(tp, flag)
        !           651:        struct tty *tp;
        !           652:        int flag;
        !           653: {
        !           654: 
        !           655:        if (flag&IO_NDELAY)
        !           656:                ttyflush(tp, FREAD|FWRITE);
        !           657:        else
        !           658:                ttywflush(tp);
        !           659: }
        !           660: 
        !           661: /*
        !           662:  * Handle close() on a tty line: flush and set to initial state,
        !           663:  * bumping generation number so that pending read/write calls
        !           664:  * can detect recycling of the tty.
        !           665:  */
        !           666: ttyclose(tp)
        !           667:        register struct tty *tp;
        !           668: {
        !           669:        if (constty == tp)
        !           670:                constty = NULL;
        !           671:        ttyflush(tp, FREAD|FWRITE);
        !           672:        tp->t_session = NULL;
        !           673:        tp->t_pgrp = NULL;
        !           674:        tp->t_state = 0;
        !           675:        tp->t_gen++;
        !           676:        return (0);
        !           677: }
        !           678: 
        !           679: /*
        !           680:  * Handle modem control transition on a tty.
        !           681:  * Flag indicates new state of carrier.
        !           682:  * Returns 0 if the line should be turned off, otherwise 1.
        !           683:  */
        !           684: ttymodem(tp, flag)
        !           685:        register struct tty *tp;
        !           686: {
        !           687: 
        !           688:        if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_lflag&MDMBUF)) {
        !           689:                /*
        !           690:                 * MDMBUF: do flow control according to carrier flag
        !           691:                 */
        !           692:                if (flag) {
        !           693:                        tp->t_state &= ~TS_TTSTOP;
        !           694:                        ttstart(tp);
        !           695:                } else if ((tp->t_state&TS_TTSTOP) == 0) {
        !           696:                        tp->t_state |= TS_TTSTOP;
        !           697:                        (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
        !           698:                }
        !           699:        } else if (flag == 0) {
        !           700:                /*
        !           701:                 * Lost carrier.
        !           702:                 */
        !           703:                tp->t_state &= ~TS_CARR_ON;
        !           704:                if (tp->t_state&TS_ISOPEN && (tp->t_cflag&CLOCAL) == 0) {
        !           705:                        if (tp->t_session && tp->t_session->s_leader)
        !           706:                                psignal(tp->t_session->s_leader, SIGHUP);
        !           707:                        ttyflush(tp, FREAD|FWRITE);
        !           708:                        return (0);
        !           709:                }
        !           710:        } else {
        !           711:                /*
        !           712:                 * Carrier now on.
        !           713:                 */
        !           714:                tp->t_state |= TS_CARR_ON;
        !           715:                ttwakeup(tp);
        !           716:        }
        !           717:        return (1);
        !           718: }
        !           719: 
        !           720: /*
        !           721:  * Default modem control routine (for other line disciplines).
        !           722:  * Return argument flag, to turn off device on carrier drop.
        !           723:  */
        !           724: nullmodem(tp, flag)
        !           725:        register struct tty *tp;
        !           726:        int flag;
        !           727: {
        !           728:        
        !           729:        if (flag)
        !           730:                tp->t_state |= TS_CARR_ON;
        !           731:        else {
        !           732:                tp->t_state &= ~TS_CARR_ON;
        !           733:                if ((tp->t_cflag&CLOCAL) == 0) {
        !           734:                        if (tp->t_session && tp->t_session->s_leader)
        !           735:                                psignal(tp->t_session->s_leader, SIGHUP);
        !           736:                        return (0);
        !           737:                }
        !           738:        }
        !           739:        return (1);
        !           740: }
        !           741: 
        !           742: /*
        !           743:  * reinput pending characters after state switch
        !           744:  * call at spltty().
        !           745:  */
        !           746: ttypend(tp)
        !           747:        register struct tty *tp;
        !           748: {
        !           749:        struct clist tq;
        !           750:        register c;
        !           751: 
        !           752:        tp->t_lflag &= ~PENDIN;
        !           753:        tp->t_state |= TS_TYPEN;
        !           754:        tq = tp->t_rawq;
        !           755:        tp->t_rawq.c_cc = 0;
        !           756:        tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
        !           757:        while ((c = getc(&tq)) >= 0)
        !           758:                ttyinput(c, tp);
        !           759:        tp->t_state &= ~TS_TYPEN;
        !           760: }
        !           761: 
        !           762: /*
        !           763:  * Process input of a single character received on a tty.
        !           764:  */
        !           765: ttyinput(c, tp)
        !           766:        register c;
        !           767:        register struct tty *tp;
        !           768: {
        !           769:        register int iflag = tp->t_iflag;
        !           770:        register int lflag = tp->t_lflag;
        !           771:        register u_char *cc = tp->t_cc;
        !           772:        int i, err;
        !           773: 
        !           774:        /*
        !           775:         * If input is pending take it first.
        !           776:         */
        !           777:        if (lflag&PENDIN)
        !           778:                ttypend(tp);
        !           779:        /*
        !           780:         * Gather stats.
        !           781:         */
        !           782:        tk_nin++;
        !           783:        if (lflag&ICANON) {
        !           784:                tk_cancc++;
        !           785:                tp->t_cancc++;
        !           786:        } else {
        !           787:                tk_rawcc++;
        !           788:                tp->t_rawcc++;
        !           789:        }
        !           790:        /*
        !           791:         * Handle exceptional conditions (break, parity, framing).
        !           792:         */
        !           793:        if (err = (c&TTY_ERRORMASK)) {
        !           794:                c &= ~TTY_ERRORMASK;
        !           795:                if (err&TTY_FE && !c) {         /* break */
        !           796:                        if (iflag&IGNBRK)
        !           797:                                goto endcase;
        !           798:                        else if (iflag&BRKINT && lflag&ISIG && 
        !           799:                                (cc[VINTR] != _POSIX_VDISABLE))
        !           800:                                c = cc[VINTR];
        !           801:                        else if (iflag&PARMRK)
        !           802:                                goto parmrk;
        !           803:                } else if ((err&TTY_PE && iflag&INPCK) || err&TTY_FE) {
        !           804:                        if (iflag&IGNPAR)
        !           805:                                goto endcase;
        !           806:                        else if (iflag&PARMRK) {
        !           807: parmrk:
        !           808:                                putc(0377|TTY_QUOTE, &tp->t_rawq);
        !           809:                                putc(0|TTY_QUOTE, &tp->t_rawq);
        !           810:                                putc(c|TTY_QUOTE, &tp->t_rawq);
        !           811:                                goto endcase;
        !           812:                        } else
        !           813:                                c = 0;
        !           814:                }
        !           815:        }
        !           816:        /*
        !           817:         * In tandem mode, check high water mark.
        !           818:         */
        !           819:        if (iflag&IXOFF)
        !           820:                ttyblock(tp);
        !           821:        if ((tp->t_state&TS_TYPEN) == 0 && (iflag&ISTRIP))
        !           822:                c &= ~0x80;
        !           823:        if ((tp->t_lflag&EXTPROC) == 0) {
        !           824:                /*
        !           825:                 * Check for literal nexting very first
        !           826:                 */
        !           827:                if (tp->t_state&TS_LNCH) {
        !           828:                        c |= TTY_QUOTE;
        !           829:                        tp->t_state &= ~TS_LNCH;
        !           830:                }
        !           831:                /*
        !           832:                 * Scan for special characters.  This code
        !           833:                 * is really just a big case statement with
        !           834:                 * non-constant cases.  The bottom of the
        !           835:                 * case statement is labeled ``endcase'', so goto
        !           836:                 * it after a case match, or similar.
        !           837:                 */
        !           838: 
        !           839:                /*
        !           840:                 * Control chars which aren't controlled
        !           841:                 * by ICANON, ISIG, or IXON.
        !           842:                 */
        !           843:                if (lflag&IEXTEN) {
        !           844:                        if (CCEQ(cc[VLNEXT], c)) {
        !           845:                                if (lflag&ECHO) {
        !           846:                                        if (lflag&ECHOE)
        !           847:                                                ttyoutstr("^\b", tp);
        !           848:                                        else
        !           849:                                                ttyecho(c, tp);
        !           850:                                }
        !           851:                                tp->t_state |= TS_LNCH;
        !           852:                                goto endcase;
        !           853:                        }
        !           854:                        if (CCEQ(cc[VDISCARD], c)) {
        !           855:                                if (lflag&FLUSHO)
        !           856:                                        tp->t_lflag &= ~FLUSHO;
        !           857:                                else {
        !           858:                                        ttyflush(tp, FWRITE);
        !           859:                                        ttyecho(c, tp);
        !           860:                                        if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
        !           861:                                                ttyretype(tp);
        !           862:                                        tp->t_lflag |= FLUSHO;
        !           863:                                }
        !           864:                                goto startoutput;
        !           865:                        }
        !           866:                }
        !           867:                /*
        !           868:                 * Signals.
        !           869:                 */
        !           870:                if (lflag&ISIG) {
        !           871:                        if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) {
        !           872:                                if ((lflag&NOFLSH) == 0)
        !           873:                                        ttyflush(tp, FREAD|FWRITE);
        !           874:                                ttyecho(c, tp);
        !           875:                                pgsignal(tp->t_pgrp,
        !           876:                                    CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1);
        !           877:                                goto endcase;
        !           878:                        }
        !           879:                        if (CCEQ(cc[VSUSP], c)) {
        !           880:                                if ((lflag&NOFLSH) == 0)
        !           881:                                        ttyflush(tp, FREAD);
        !           882:                                ttyecho(c, tp);
        !           883:                                pgsignal(tp->t_pgrp, SIGTSTP, 1);
        !           884:                                goto endcase;
        !           885:                        }
        !           886:                }
        !           887:                /*
        !           888:                 * Handle start/stop characters.
        !           889:                 */
        !           890:                if (iflag&IXON) {
        !           891:                        if (CCEQ(cc[VSTOP], c)) {
        !           892:                                if ((tp->t_state&TS_TTSTOP) == 0) {
        !           893:                                        tp->t_state |= TS_TTSTOP;
        !           894:                                        (*cdevsw[major(tp->t_dev)].d_stop)(tp,
        !           895:                                           0);
        !           896:                                        return;
        !           897:                                }
        !           898:                                if (!CCEQ(cc[VSTART], c))
        !           899:                                        return;
        !           900:                                /* 
        !           901:                                 * if VSTART == VSTOP then toggle 
        !           902:                                 */
        !           903:                                goto endcase;
        !           904:                        }
        !           905:                        if (CCEQ(cc[VSTART], c))
        !           906:                                goto restartoutput;
        !           907:                }
        !           908:                /*
        !           909:                 * IGNCR, ICRNL, & INLCR
        !           910:                 */
        !           911:                if (c == '\r') {
        !           912:                        if (iflag&IGNCR)
        !           913:                                goto endcase;
        !           914:                        else if (iflag&ICRNL)
        !           915:                                c = '\n';
        !           916:                } else if (c == '\n' && iflag&INLCR)
        !           917:                        c = '\r';
        !           918:        }
        !           919:        if ((tp->t_lflag&EXTPROC) == 0 && lflag&ICANON) {
        !           920:                /*
        !           921:                 * From here on down canonical mode character
        !           922:                 * processing takes place.
        !           923:                 */
        !           924:                /*
        !           925:                 * erase (^H / ^?)
        !           926:                 */
        !           927:                if (CCEQ(cc[VERASE], c)) {
        !           928:                        if (tp->t_rawq.c_cc)
        !           929:                                ttyrub(unputc(&tp->t_rawq), tp);
        !           930:                        goto endcase;
        !           931:                }
        !           932:                /*
        !           933:                 * kill (^U)
        !           934:                 */
        !           935:                if (CCEQ(cc[VKILL], c)) {
        !           936:                        if (lflag&ECHOKE && tp->t_rawq.c_cc == tp->t_rocount &&
        !           937:                            (lflag&ECHOPRT) == 0) {
        !           938:                                while (tp->t_rawq.c_cc)
        !           939:                                        ttyrub(unputc(&tp->t_rawq), tp);
        !           940:                        } else {
        !           941:                                ttyecho(c, tp);
        !           942:                                if (lflag&ECHOK || lflag&ECHOKE)
        !           943:                                        ttyecho('\n', tp);
        !           944:                                while (getc(&tp->t_rawq) > 0)
        !           945:                                        ;
        !           946:                                tp->t_rocount = 0;
        !           947:                        }
        !           948:                        tp->t_state &= ~TS_LOCAL;
        !           949:                        goto endcase;
        !           950:                }
        !           951:                /*
        !           952:                 * word erase (^W)
        !           953:                 */
        !           954:                if (CCEQ(cc[VWERASE], c)) {     
        !           955:                        int ctype;
        !           956:                        int alt = lflag&ALTWERASE;
        !           957: 
        !           958:                        /* 
        !           959:                         * erase whitespace 
        !           960:                         */
        !           961:                        while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t')
        !           962:                                ttyrub(c, tp);
        !           963:                        if (c == -1)
        !           964:                                goto endcase;
        !           965:                        /*
        !           966:                         * erase last char of word and remember the
        !           967:                         * next chars type (for ALTWERASE)
        !           968:                         */
        !           969:                        ttyrub(c, tp);
        !           970:                        c = unputc(&tp->t_rawq);
        !           971:                        if (c == -1)
        !           972:                                goto endcase;
        !           973:                        ctype = ISALPHA(c);
        !           974:                        /*
        !           975:                         * erase rest of word
        !           976:                         */
        !           977:                        do {
        !           978:                                ttyrub(c, tp);
        !           979:                                c = unputc(&tp->t_rawq);
        !           980:                                if (c == -1)
        !           981:                                        goto endcase;
        !           982:                        } while (c != ' ' && c != '\t' && 
        !           983:                                (alt == 0 || ISALPHA(c) == ctype));
        !           984:                        (void) putc(c, &tp->t_rawq);
        !           985:                        goto endcase;
        !           986:                }
        !           987:                /*
        !           988:                 * reprint line (^R)
        !           989:                 */
        !           990:                if (CCEQ(cc[VREPRINT], c)) {
        !           991:                        ttyretype(tp);
        !           992:                        goto endcase;
        !           993:                }
        !           994:                /*
        !           995:                 * ^T - kernel info and generate SIGINFO
        !           996:                 */
        !           997:                if (CCEQ(cc[VSTATUS], c)) {
        !           998:                        pgsignal(tp->t_pgrp, SIGINFO, 1);
        !           999:                        if ((lflag&NOKERNINFO) == 0)
        !          1000:                                ttyinfo(tp);
        !          1001:                        goto endcase;
        !          1002:                }
        !          1003:        }
        !          1004:        /*
        !          1005:         * Check for input buffer overflow
        !          1006:         */
        !          1007:        if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= TTYHOG) {
        !          1008:                if (iflag&IMAXBEL) {
        !          1009:                        if (tp->t_outq.c_cc < tp->t_hiwat)
        !          1010:                                (void) ttyoutput(CTRL('g'), tp);
        !          1011:                } else
        !          1012:                        ttyflush(tp, FREAD | FWRITE);
        !          1013:                goto endcase;
        !          1014:        }
        !          1015:        /*
        !          1016:         * Put data char in q for user and
        !          1017:         * wakeup on seeing a line delimiter.
        !          1018:         */
        !          1019:        if (putc(c, &tp->t_rawq) >= 0) {
        !          1020:                if ((lflag&ICANON) == 0) {
        !          1021:                        ttwakeup(tp);
        !          1022:                        ttyecho(c, tp);
        !          1023:                        goto endcase;
        !          1024:                }
        !          1025:                if (ttbreakc(c)) {
        !          1026:                        tp->t_rocount = 0;
        !          1027:                        catq(&tp->t_rawq, &tp->t_canq);
        !          1028:                        ttwakeup(tp);
        !          1029:                } else if (tp->t_rocount++ == 0)
        !          1030:                        tp->t_rocol = tp->t_col;
        !          1031:                if (tp->t_state&TS_ERASE) {
        !          1032:                        /*
        !          1033:                         * end of prterase \.../
        !          1034:                         */
        !          1035:                        tp->t_state &= ~TS_ERASE;
        !          1036:                        (void) ttyoutput('/', tp);
        !          1037:                }
        !          1038:                i = tp->t_col;
        !          1039:                ttyecho(c, tp);
        !          1040:                if (CCEQ(cc[VEOF], c) && lflag&ECHO) {
        !          1041:                        /*
        !          1042:                         * Place the cursor over the '^' of the ^D.
        !          1043:                         */
        !          1044:                        i = MIN(2, tp->t_col - i);
        !          1045:                        while (i > 0) {
        !          1046:                                (void) ttyoutput('\b', tp);
        !          1047:                                i--;
        !          1048:                        }
        !          1049:                }
        !          1050:        }
        !          1051: endcase:
        !          1052:        /*
        !          1053:         * IXANY means allow any character to restart output.
        !          1054:         */
        !          1055:        if ((tp->t_state&TS_TTSTOP) && (iflag&IXANY) == 0 && 
        !          1056:            cc[VSTART] != cc[VSTOP])
        !          1057:                return;
        !          1058: restartoutput:
        !          1059:        tp->t_state &= ~TS_TTSTOP;
        !          1060:        tp->t_lflag &= ~FLUSHO;
        !          1061: startoutput:
        !          1062:        ttstart(tp);
        !          1063: }
        !          1064: 
        !          1065: /*
        !          1066:  * Output a single character on a tty, doing output processing
        !          1067:  * as needed (expanding tabs, newline processing, etc.).
        !          1068:  * Returns < 0 if putc succeeds, otherwise returns char to resend.
        !          1069:  * Must be recursive.
        !          1070:  */
        !          1071: ttyoutput(c, tp)
        !          1072:        register c;
        !          1073:        register struct tty *tp;
        !          1074: {
        !          1075:        register int col;
        !          1076:        register long oflag = tp->t_oflag;
        !          1077:        
        !          1078:        if ((oflag&OPOST) == 0) {
        !          1079:                if (tp->t_lflag&FLUSHO) 
        !          1080:                        return (-1);
        !          1081:                if (putc(c, &tp->t_outq))
        !          1082:                        return (c);
        !          1083:                tk_nout++;
        !          1084:                tp->t_outcc++;
        !          1085:                return (-1);
        !          1086:        }
        !          1087:        c &= TTY_CHARMASK;
        !          1088:        /*
        !          1089:         * Do tab expansion if OXTABS is set.
        !          1090:         * Special case if we have external processing, we don't
        !          1091:         * do the tab expansion because we'll probably get it
        !          1092:         * wrong.  If tab expansion needs to be done, let it
        !          1093:         * happen externally.
        !          1094:         */
        !          1095:        if (c == '\t' && oflag&OXTABS && (tp->t_lflag&EXTPROC) == 0) {
        !          1096:                register int s;
        !          1097: 
        !          1098:                c = 8 - (tp->t_col&7);
        !          1099:                if ((tp->t_lflag&FLUSHO) == 0) {
        !          1100:                        s = spltty();           /* don't interrupt tabs */
        !          1101:                        c -= b_to_q("        ", c, &tp->t_outq);
        !          1102:                        tk_nout += c;
        !          1103:                        tp->t_outcc += c;
        !          1104:                        splx(s);
        !          1105:                }
        !          1106:                tp->t_col += c;
        !          1107:                return (c ? -1 : '\t');
        !          1108:        }
        !          1109:        if (c == CEOT && oflag&ONOEOT)
        !          1110:                return (-1);
        !          1111:        tk_nout++;
        !          1112:        tp->t_outcc++;
        !          1113:        /*
        !          1114:         * Newline translation: if ONLCR is set,
        !          1115:         * translate newline into "\r\n".
        !          1116:         */
        !          1117:        if (c == '\n' && (tp->t_oflag&ONLCR) && ttyoutput('\r', tp) >= 0)
        !          1118:                return (c);
        !          1119:        if ((tp->t_lflag&FLUSHO) == 0 && putc(c, &tp->t_outq))
        !          1120:                return (c);
        !          1121: 
        !          1122:        col = tp->t_col;
        !          1123:        switch (CCLASS(c)) {
        !          1124: 
        !          1125:        case ORDINARY:
        !          1126:                col++;
        !          1127: 
        !          1128:        case CONTROL:
        !          1129:                break;
        !          1130: 
        !          1131:        case BACKSPACE:
        !          1132:                if (col > 0)
        !          1133:                        col--;
        !          1134:                break;
        !          1135: 
        !          1136:        case NEWLINE:
        !          1137:                col = 0;
        !          1138:                break;
        !          1139: 
        !          1140:        case TAB:
        !          1141:                col = (col + 8) &~ 0x7;
        !          1142:                break;
        !          1143: 
        !          1144:        case RETURN:
        !          1145:                col = 0;
        !          1146:        }
        !          1147:        tp->t_col = col;
        !          1148:        return (-1);
        !          1149: }
        !          1150: 
        !          1151: /*
        !          1152:  * Process a read call on a tty device.
        !          1153:  */
        !          1154: ttread(tp, uio, flag)
        !          1155:        register struct tty *tp;
        !          1156:        struct uio *uio;
        !          1157: {
        !          1158:        register struct clist *qp;
        !          1159:        register int c;
        !          1160:        register long lflag;
        !          1161:        register u_char *cc = tp->t_cc;
        !          1162:        register struct proc *p = curproc;
        !          1163:        int s, first, error = 0;
        !          1164: 
        !          1165: loop:
        !          1166:        lflag = tp->t_lflag;
        !          1167:        s = spltty();
        !          1168:        /*
        !          1169:         * take pending input first 
        !          1170:         */
        !          1171:        if (lflag&PENDIN)
        !          1172:                ttypend(tp);
        !          1173:        splx(s);
        !          1174: 
        !          1175:        /*
        !          1176:         * Hang process if it's in the background.
        !          1177:         */
        !          1178:        if (isbackground(p, tp)) {
        !          1179:                if ((p->p_sigignore & sigmask(SIGTTIN)) ||
        !          1180:                   (p->p_sigmask & sigmask(SIGTTIN)) ||
        !          1181:                    p->p_flag&SPPWAIT || p->p_pgrp->pg_jobc == 0)
        !          1182:                        return (EIO);
        !          1183:                pgsignal(p->p_pgrp, SIGTTIN, 1);
        !          1184:                if (error = ttysleep(tp, (caddr_t)&lbolt, TTIPRI | PCATCH, 
        !          1185:                    ttybg, 0)) 
        !          1186:                        return (error);
        !          1187:                goto loop;
        !          1188:        }
        !          1189: 
        !          1190:        /*
        !          1191:         * If canonical, use the canonical queue,
        !          1192:         * else use the raw queue.
        !          1193:         *
        !          1194:         * (should get rid of clists...)
        !          1195:         */
        !          1196:        qp = lflag&ICANON ? &tp->t_canq : &tp->t_rawq;
        !          1197: 
        !          1198:        /*
        !          1199:         * If there is no input, sleep on rawq
        !          1200:         * awaiting hardware receipt and notification.
        !          1201:         * If we have data, we don't need to check for carrier.
        !          1202:         */
        !          1203:        s = spltty();
        !          1204:        if (qp->c_cc <= 0) {
        !          1205:                int carrier;
        !          1206: 
        !          1207:                carrier = (tp->t_state&TS_CARR_ON) || (tp->t_cflag&CLOCAL);
        !          1208:                if (!carrier && tp->t_state&TS_ISOPEN) {
        !          1209:                        splx(s);
        !          1210:                        return (0);     /* EOF */
        !          1211:                }
        !          1212:                if (flag & IO_NDELAY) {
        !          1213:                        splx(s);
        !          1214:                        return (EWOULDBLOCK);
        !          1215:                }
        !          1216:                error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
        !          1217:                    carrier ? ttyin : ttopen, 0);
        !          1218:                splx(s);
        !          1219:                if (error)
        !          1220:                        return (error);
        !          1221:                goto loop;
        !          1222:        }
        !          1223:        splx(s);
        !          1224: 
        !          1225:        /*
        !          1226:         * Input present, check for input mapping and processing.
        !          1227:         */
        !          1228:        first = 1;
        !          1229:        while ((c = getc(qp)) >= 0) {
        !          1230:                /*
        !          1231:                 * delayed suspend (^Y)
        !          1232:                 */
        !          1233:                if (CCEQ(cc[VDSUSP], c) && lflag&ISIG) {
        !          1234:                        pgsignal(tp->t_pgrp, SIGTSTP, 1);
        !          1235:                        if (first) {
        !          1236:                                if (error = ttysleep(tp, (caddr_t)&lbolt,
        !          1237:                                    TTIPRI | PCATCH, ttybg, 0))
        !          1238:                                        break;
        !          1239:                                goto loop;
        !          1240:                        }
        !          1241:                        break;
        !          1242:                }
        !          1243:                /*
        !          1244:                 * Interpret EOF only in canonical mode.
        !          1245:                 */
        !          1246:                if (CCEQ(cc[VEOF], c) && lflag&ICANON)
        !          1247:                        break;
        !          1248:                /*
        !          1249:                 * Give user character.
        !          1250:                 */
        !          1251:                error = ureadc(c, uio);
        !          1252:                if (error)
        !          1253:                        break;
        !          1254:                if (uio->uio_resid == 0)
        !          1255:                        break;
        !          1256:                /*
        !          1257:                 * In canonical mode check for a "break character"
        !          1258:                 * marking the end of a "line of input".
        !          1259:                 */
        !          1260:                if (lflag&ICANON && ttbreakc(c))
        !          1261:                        break;
        !          1262:                first = 0;
        !          1263:        }
        !          1264:        /*
        !          1265:         * Look to unblock output now that (presumably)
        !          1266:         * the input queue has gone down.
        !          1267:         */
        !          1268:        if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
        !          1269:                if (cc[VSTART] != _POSIX_VDISABLE &&
        !          1270:                    putc(cc[VSTART], &tp->t_outq) == 0) {
        !          1271:                        tp->t_state &= ~TS_TBLOCK;
        !          1272:                        ttstart(tp);
        !          1273:                }
        !          1274:        }
        !          1275:        return (error);
        !          1276: }
        !          1277: 
        !          1278: /*
        !          1279:  * Check the output queue on tp for space for a kernel message
        !          1280:  * (from uprintf/tprintf).  Allow some space over the normal
        !          1281:  * hiwater mark so we don't lose messages due to normal flow
        !          1282:  * control, but don't let the tty run amok.
        !          1283:  * Sleeps here are not interruptible, but we return prematurely
        !          1284:  * if new signals come in.
        !          1285:  */
        !          1286: ttycheckoutq(tp, wait)
        !          1287:        register struct tty *tp;
        !          1288:        int wait;
        !          1289: {
        !          1290:        int hiwat, s, oldsig;
        !          1291:        extern int wakeup();
        !          1292: 
        !          1293:        hiwat = tp->t_hiwat;
        !          1294:        s = spltty();
        !          1295:        oldsig = curproc->p_sig;
        !          1296:        if (tp->t_outq.c_cc > hiwat + 200)
        !          1297:                while (tp->t_outq.c_cc > hiwat) {
        !          1298:                        ttstart(tp);
        !          1299:                        if (wait == 0 || curproc->p_sig != oldsig) {
        !          1300:                                splx(s);
        !          1301:                                return (0);
        !          1302:                        }
        !          1303:                        timeout(wakeup, (caddr_t)&tp->t_outq, hz);
        !          1304:                        tp->t_state |= TS_ASLEEP;
        !          1305:                        sleep((caddr_t)&tp->t_outq, PZERO - 1);
        !          1306:                }
        !          1307:        splx(s);
        !          1308:        return (1);
        !          1309: }
        !          1310: 
        !          1311: /*
        !          1312:  * Process a write call on a tty device.
        !          1313:  */
        !          1314: ttwrite(tp, uio, flag)
        !          1315:        register struct tty *tp;
        !          1316:        register struct uio *uio;
        !          1317: {
        !          1318:        register char *cp;
        !          1319:        register int cc = 0, ce;
        !          1320:        register struct proc *p = curproc;
        !          1321:        int i, hiwat, cnt, error, s;
        !          1322:        char obuf[OBUFSIZ];
        !          1323: 
        !          1324:        hiwat = tp->t_hiwat;
        !          1325:        cnt = uio->uio_resid;
        !          1326:        error = 0;
        !          1327: loop:
        !          1328:        s = spltty();
        !          1329:        if ((tp->t_state&TS_CARR_ON) == 0 && (tp->t_cflag&CLOCAL) == 0) {
        !          1330:                if (tp->t_state&TS_ISOPEN) {
        !          1331:                        splx(s);
        !          1332:                        return (EIO);
        !          1333:                } else if (flag & IO_NDELAY) {
        !          1334:                        splx(s);
        !          1335:                        error = EWOULDBLOCK;
        !          1336:                        goto out;
        !          1337:                } else {
        !          1338:                        /*
        !          1339:                         * sleep awaiting carrier
        !          1340:                         */
        !          1341:                        error = ttysleep(tp, (caddr_t)&tp->t_rawq, 
        !          1342:                                        TTIPRI | PCATCH,ttopen, 0);
        !          1343:                        splx(s);
        !          1344:                        if (error)
        !          1345:                                goto out;
        !          1346:                        goto loop;
        !          1347:                }
        !          1348:        }
        !          1349:        splx(s);
        !          1350:        /*
        !          1351:         * Hang the process if it's in the background.
        !          1352:         */
        !          1353:        if (isbackground(p, tp) && 
        !          1354:            tp->t_lflag&TOSTOP && (p->p_flag&SPPWAIT) == 0 &&
        !          1355:            (p->p_sigignore & sigmask(SIGTTOU)) == 0 &&
        !          1356:            (p->p_sigmask & sigmask(SIGTTOU)) == 0 &&
        !          1357:             p->p_pgrp->pg_jobc) {
        !          1358:                pgsignal(p->p_pgrp, SIGTTOU, 1);
        !          1359:                if (error = ttysleep(tp, (caddr_t)&lbolt, TTIPRI | PCATCH, 
        !          1360:                    ttybg, 0))
        !          1361:                        goto out;
        !          1362:                goto loop;
        !          1363:        }
        !          1364:        /*
        !          1365:         * Process the user's data in at most OBUFSIZ
        !          1366:         * chunks.  Perform any output translation.
        !          1367:         * Keep track of high water mark, sleep on overflow
        !          1368:         * awaiting device aid in acquiring new space.
        !          1369:         */
        !          1370:        while (uio->uio_resid > 0 || cc > 0) {
        !          1371:                if (tp->t_lflag&FLUSHO) {
        !          1372:                        uio->uio_resid = 0;
        !          1373:                        return (0);
        !          1374:                }
        !          1375:                if (tp->t_outq.c_cc > hiwat)
        !          1376:                        goto ovhiwat;
        !          1377:                /*
        !          1378:                 * Grab a hunk of data from the user,
        !          1379:                 * unless we have some leftover from last time.
        !          1380:                 */
        !          1381:                if (cc == 0) {
        !          1382:                        cc = min(uio->uio_resid, OBUFSIZ);
        !          1383:                        cp = obuf;
        !          1384:                        error = uiomove(cp, cc, uio);
        !          1385:                        if (error) {
        !          1386:                                cc = 0;
        !          1387:                                break;
        !          1388:                        }
        !          1389:                }
        !          1390:                /*
        !          1391:                 * If nothing fancy need be done, grab those characters we
        !          1392:                 * can handle without any of ttyoutput's processing and
        !          1393:                 * just transfer them to the output q.  For those chars
        !          1394:                 * which require special processing (as indicated by the
        !          1395:                 * bits in partab), call ttyoutput.  After processing
        !          1396:                 * a hunk of data, look for FLUSHO so ^O's will take effect
        !          1397:                 * immediately.
        !          1398:                 */
        !          1399:                while (cc > 0) {
        !          1400:                        if ((tp->t_oflag&OPOST) == 0)
        !          1401:                                ce = cc;
        !          1402:                        else {
        !          1403:                                ce = cc - scanc((unsigned)cc, (u_char *)cp,
        !          1404:                                   (u_char *)partab, CCLASSMASK);
        !          1405:                                /*
        !          1406:                                 * If ce is zero, then we're processing
        !          1407:                                 * a special character through ttyoutput.
        !          1408:                                 */
        !          1409:                                if (ce == 0) {
        !          1410:                                        tp->t_rocount = 0;
        !          1411:                                        if (ttyoutput(*cp, tp) >= 0) {
        !          1412:                                            /* no c-lists, wait a bit */
        !          1413:                                            ttstart(tp);
        !          1414:                                            if (error = ttysleep(tp, 
        !          1415:                                                (caddr_t)&lbolt,
        !          1416:                                                 TTOPRI | PCATCH, ttybuf, 0))
        !          1417:                                                    break;
        !          1418:                                            goto loop;
        !          1419:                                        }
        !          1420:                                        cp++, cc--;
        !          1421:                                        if ((tp->t_lflag&FLUSHO) ||
        !          1422:                                            tp->t_outq.c_cc > hiwat)
        !          1423:                                                goto ovhiwat;
        !          1424:                                        continue;
        !          1425:                                }
        !          1426:                        }
        !          1427:                        /*
        !          1428:                         * A bunch of normal characters have been found,
        !          1429:                         * transfer them en masse to the output queue and
        !          1430:                         * continue processing at the top of the loop.
        !          1431:                         * If there are any further characters in this
        !          1432:                         * <= OBUFSIZ chunk, the first should be a character
        !          1433:                         * requiring special handling by ttyoutput.
        !          1434:                         */
        !          1435:                        tp->t_rocount = 0;
        !          1436:                        i = b_to_q(cp, ce, &tp->t_outq);
        !          1437:                        ce -= i;
        !          1438:                        tp->t_col += ce;
        !          1439:                        cp += ce, cc -= ce, tk_nout += ce;
        !          1440:                        tp->t_outcc += ce;
        !          1441:                        if (i > 0) {
        !          1442:                                /* out of c-lists, wait a bit */
        !          1443:                                ttstart(tp);
        !          1444:                                if (error = ttysleep(tp, (caddr_t)&lbolt,
        !          1445:                                            TTOPRI | PCATCH, ttybuf, 0))
        !          1446:                                        break;
        !          1447:                                goto loop;
        !          1448:                        }
        !          1449:                        if (tp->t_lflag&FLUSHO || tp->t_outq.c_cc > hiwat)
        !          1450:                                break;
        !          1451:                }
        !          1452:                ttstart(tp);
        !          1453:        }
        !          1454: out:
        !          1455:        /*
        !          1456:         * If cc is nonzero, we leave the uio structure inconsistent,
        !          1457:         * as the offset and iov pointers have moved forward,
        !          1458:         * but it doesn't matter (the call will either return short
        !          1459:         * or restart with a new uio).
        !          1460:         */
        !          1461:        uio->uio_resid += cc;
        !          1462:        return (error);
        !          1463: 
        !          1464: ovhiwat:
        !          1465:        ttstart(tp);
        !          1466:        s = spltty();
        !          1467:        /*
        !          1468:         * This can only occur if FLUSHO is set in t_lflag,
        !          1469:         * or if ttstart/oproc is synchronous (or very fast).
        !          1470:         */
        !          1471:        if (tp->t_outq.c_cc <= hiwat) {
        !          1472:                splx(s);
        !          1473:                goto loop;
        !          1474:        }
        !          1475:        if (flag & IO_NDELAY) {
        !          1476:                splx(s);
        !          1477:                uio->uio_resid += cc;
        !          1478:                if (uio->uio_resid == cnt)
        !          1479:                        return (EWOULDBLOCK);
        !          1480:                return (0);
        !          1481:        }
        !          1482:        tp->t_state |= TS_ASLEEP;
        !          1483:        error = ttysleep(tp, (caddr_t)&tp->t_outq, TTOPRI | PCATCH, ttyout, 0);
        !          1484:        splx(s);
        !          1485:        if (error)
        !          1486:                goto out;
        !          1487:        goto loop;
        !          1488: }
        !          1489: 
        !          1490: /*
        !          1491:  * Rubout one character from the rawq of tp
        !          1492:  * as cleanly as possible.
        !          1493:  */
        !          1494: ttyrub(c, tp)
        !          1495:        register c;
        !          1496:        register struct tty *tp;
        !          1497: {
        !          1498:        register char *cp;
        !          1499:        register int savecol;
        !          1500:        int s;
        !          1501:        char *nextc();
        !          1502: 
        !          1503:        if ((tp->t_lflag&ECHO) == 0 || (tp->t_lflag&EXTPROC))
        !          1504:                return;
        !          1505:        tp->t_lflag &= ~FLUSHO; 
        !          1506:        if (tp->t_lflag&ECHOE) {
        !          1507:                if (tp->t_rocount == 0) {
        !          1508:                        /*
        !          1509:                         * Screwed by ttwrite; retype
        !          1510:                         */
        !          1511:                        ttyretype(tp);
        !          1512:                        return;
        !          1513:                }
        !          1514:                if (c == ('\t'|TTY_QUOTE) || c == ('\n'|TTY_QUOTE))
        !          1515:                        ttyrubo(tp, 2);
        !          1516:                else switch (CCLASS(c &= TTY_CHARMASK)) {
        !          1517: 
        !          1518:                case ORDINARY:
        !          1519:                        ttyrubo(tp, 1);
        !          1520:                        break;
        !          1521: 
        !          1522:                case VTAB:
        !          1523:                case BACKSPACE:
        !          1524:                case CONTROL:
        !          1525:                case RETURN:
        !          1526:                case NEWLINE:
        !          1527:                        if (tp->t_lflag&ECHOCTL)
        !          1528:                                ttyrubo(tp, 2);
        !          1529:                        break;
        !          1530: 
        !          1531:                case TAB: {
        !          1532:                        int c;
        !          1533: 
        !          1534:                        if (tp->t_rocount < tp->t_rawq.c_cc) {
        !          1535:                                ttyretype(tp);
        !          1536:                                return;
        !          1537:                        }
        !          1538:                        s = spltty();
        !          1539:                        savecol = tp->t_col;
        !          1540:                        tp->t_state |= TS_CNTTB;
        !          1541:                        tp->t_lflag |= FLUSHO;
        !          1542:                        tp->t_col = tp->t_rocol;
        !          1543:                        cp = tp->t_rawq.c_cf;
        !          1544:                        if (cp)
        !          1545:                                c = *cp;        /* XXX FIX NEXTC */
        !          1546:                        for (; cp; cp = nextc(&tp->t_rawq, cp, &c))
        !          1547:                                ttyecho(c, tp);
        !          1548:                        tp->t_lflag &= ~FLUSHO;
        !          1549:                        tp->t_state &= ~TS_CNTTB;
        !          1550:                        splx(s);
        !          1551:                        /*
        !          1552:                         * savecol will now be length of the tab
        !          1553:                         */
        !          1554:                        savecol -= tp->t_col;
        !          1555:                        tp->t_col += savecol;
        !          1556:                        if (savecol > 8)
        !          1557:                                savecol = 8;            /* overflow screw */
        !          1558:                        while (--savecol >= 0)
        !          1559:                                (void) ttyoutput('\b', tp);
        !          1560:                        break;
        !          1561:                }
        !          1562: 
        !          1563:                default:
        !          1564:                        /* XXX */
        !          1565:                        printf("ttyrub: would panic c = %d, val = %d\n",
        !          1566:                                c, CCLASS(c));
        !          1567:                        /*panic("ttyrub");*/
        !          1568:                }
        !          1569:        } else if (tp->t_lflag&ECHOPRT) {
        !          1570:                if ((tp->t_state&TS_ERASE) == 0) {
        !          1571:                        (void) ttyoutput('\\', tp);
        !          1572:                        tp->t_state |= TS_ERASE;
        !          1573:                }
        !          1574:                ttyecho(c, tp);
        !          1575:        } else
        !          1576:                ttyecho(tp->t_cc[VERASE], tp);
        !          1577:        tp->t_rocount--;
        !          1578: }
        !          1579: 
        !          1580: /*
        !          1581:  * Crt back over cnt chars perhaps
        !          1582:  * erasing them.
        !          1583:  */
        !          1584: ttyrubo(tp, cnt)
        !          1585:        register struct tty *tp;
        !          1586:        int cnt;
        !          1587: {
        !          1588: 
        !          1589:        while (--cnt >= 0)
        !          1590:                ttyoutstr("\b \b", tp);
        !          1591: }
        !          1592: 
        !          1593: /*
        !          1594:  * Reprint the rawq line.
        !          1595:  * We assume c_cc has already been checked.
        !          1596:  */
        !          1597: ttyretype(tp)
        !          1598:        register struct tty *tp;
        !          1599: {
        !          1600:        register char *cp;
        !          1601:        char *nextc();
        !          1602:        int s, c;
        !          1603: 
        !          1604:        if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE)
        !          1605:                ttyecho(tp->t_cc[VREPRINT], tp);
        !          1606:        (void) ttyoutput('\n', tp);
        !          1607:        s = spltty();
        !          1608:        /*** XXX *** FIX *** NEXTC IS BROKEN - DOESN'T CHECK QUOTE
        !          1609:          BIT OF FIRST CHAR ****/
        !          1610:        for (cp = tp->t_canq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_canq, cp, &c)) {
        !          1611:                ttyecho(c, tp);
        !          1612:        }
        !          1613:        for (cp = tp->t_rawq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_rawq, cp, &c)) {
        !          1614:                ttyecho(c, tp);
        !          1615:        }
        !          1616:        tp->t_state &= ~TS_ERASE;
        !          1617:        splx(s);
        !          1618:        tp->t_rocount = tp->t_rawq.c_cc;
        !          1619:        tp->t_rocol = 0;
        !          1620: }
        !          1621: 
        !          1622: /*
        !          1623:  * Echo a typed character to the terminal.
        !          1624:  */
        !          1625: ttyecho(c, tp)
        !          1626:        register c;
        !          1627:        register struct tty *tp;
        !          1628: {
        !          1629:        if ((tp->t_state&TS_CNTTB) == 0)
        !          1630:                tp->t_lflag &= ~FLUSHO;
        !          1631:        if (((tp->t_lflag&ECHO) == 0 &&
        !          1632:            ((tp->t_lflag&ECHONL) == 0 || c == '\n')) || (tp->t_lflag&EXTPROC))
        !          1633:                return;
        !          1634:        if (tp->t_lflag&ECHOCTL) {
        !          1635:                if ((c&TTY_CHARMASK) <= 037 && c != '\t' && c != '\n' ||
        !          1636:                    c == 0177) {
        !          1637:                        (void) ttyoutput('^', tp);
        !          1638:                        c &= TTY_CHARMASK;
        !          1639:                        if (c == 0177)
        !          1640:                                c = '?';
        !          1641:                        else
        !          1642:                                c += 'A' - 1;
        !          1643:                }
        !          1644:        }
        !          1645:        (void) ttyoutput(c, tp);
        !          1646: }
        !          1647: 
        !          1648: /*
        !          1649:  * send string cp to tp
        !          1650:  */
        !          1651: ttyoutstr(cp, tp)
        !          1652:        register char *cp;
        !          1653:        register struct tty *tp;
        !          1654: {
        !          1655:        register char c;
        !          1656: 
        !          1657:        while (c = *cp++)
        !          1658:                (void) ttyoutput(c, tp);
        !          1659: }
        !          1660: 
        !          1661: /*
        !          1662:  * Wake up any readers on a tty.
        !          1663:  */
        !          1664: ttwakeup(tp)
        !          1665:        register struct tty *tp;
        !          1666: {
        !          1667: 
        !          1668:        if (tp->t_rsel) {
        !          1669:                selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL);
        !          1670:                tp->t_state &= ~TS_RCOLL;
        !          1671:                tp->t_rsel = 0;
        !          1672:        }
        !          1673:        if (tp->t_state & TS_ASYNC)
        !          1674:                pgsignal(tp->t_pgrp, SIGIO, 1); 
        !          1675:        wakeup((caddr_t)&tp->t_rawq);
        !          1676: }
        !          1677: 
        !          1678: /*
        !          1679:  * Look up a code for a specified speed in a conversion table;
        !          1680:  * used by drivers to map software speed values to hardware parameters.
        !          1681:  */
        !          1682: ttspeedtab(speed, table)
        !          1683:        register struct speedtab *table;
        !          1684: {
        !          1685: 
        !          1686:        for ( ; table->sp_speed != -1; table++)
        !          1687:                if (table->sp_speed == speed)
        !          1688:                        return (table->sp_code);
        !          1689:        return (-1);
        !          1690: }
        !          1691: 
        !          1692: /*
        !          1693:  * set tty hi and low water marks
        !          1694:  *
        !          1695:  * Try to arrange the dynamics so there's about one second
        !          1696:  * from hi to low water.
        !          1697:  * 
        !          1698:  */
        !          1699: ttsetwater(tp)
        !          1700:        struct tty *tp;
        !          1701: {
        !          1702:        register cps = tp->t_ospeed / 10;
        !          1703:        register x;
        !          1704: 
        !          1705: #define clamp(x, h, l) ((x)>h ? h : ((x)<l) ? l : (x))
        !          1706:        tp->t_lowat = x = clamp(cps/2, TTMAXLOWAT, TTMINLOWAT);
        !          1707:        x += cps;
        !          1708:        x = clamp(x, TTMAXHIWAT, TTMINHIWAT);
        !          1709:        tp->t_hiwat = roundup(x, CBSIZE);
        !          1710: #undef clamp
        !          1711: }
        !          1712: 
        !          1713: /*
        !          1714:  * Report on state of foreground process group.
        !          1715:  */
        !          1716: ttyinfo(tp)
        !          1717:        register struct tty *tp;
        !          1718: {
        !          1719:        register struct proc *p, *pick;
        !          1720:        struct timeval utime, stime;
        !          1721:        int tmp;
        !          1722: 
        !          1723:        if (ttycheckoutq(tp,0) == 0) 
        !          1724:                return;
        !          1725: 
        !          1726:        /* Print load average. */
        !          1727:        tmp = (averunnable[0] * 100 + FSCALE / 2) >> FSHIFT;
        !          1728:        ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100);
        !          1729: 
        !          1730:        if (tp->t_session == NULL)
        !          1731:                ttyprintf(tp, "not a controlling terminal\n");
        !          1732:        else if (tp->t_pgrp == NULL)
        !          1733:                ttyprintf(tp, "no foreground process group\n");
        !          1734:        else if ((p = tp->t_pgrp->pg_mem) == NULL)
        !          1735:                ttyprintf(tp, "empty foreground process group\n");
        !          1736:        else {
        !          1737:                /* Pick interesting process. */
        !          1738:                for (pick = NULL; p != NULL; p = p->p_pgrpnxt)
        !          1739:                        if (proc_compare(pick, p))
        !          1740:                                pick = p;
        !          1741: 
        !          1742:                ttyprintf(tp, " cmd: %s %d [%s] ", pick->p_comm, pick->p_pid,
        !          1743:                    pick->p_stat == SRUN ? "running" :
        !          1744:                    pick->p_wmesg ? pick->p_wmesg : "iowait");
        !          1745: 
        !          1746:                /*
        !          1747:                 * Lock out clock if process is running; get user/system
        !          1748:                 * cpu time.
        !          1749:                 */
        !          1750:                if (curproc == pick)
        !          1751:                        tmp = splclock();
        !          1752:                utime = pick->p_utime;
        !          1753:                stime = pick->p_stime;
        !          1754:                if (curproc == pick)
        !          1755:                        splx(tmp);
        !          1756: 
        !          1757:                /* Print user time. */
        !          1758:                ttyprintf(tp, "%d.%02du ",
        !          1759:                    utime.tv_sec, (utime.tv_usec + 5000) / 10000);
        !          1760: 
        !          1761:                /* Print system time. */
        !          1762:                ttyprintf(tp, "%d.%02ds ",
        !          1763:                    stime.tv_sec, (stime.tv_usec + 5000) / 10000);
        !          1764: 
        !          1765: #define        pgtok(a)        (((a) * NBPG) / 1024)
        !          1766:                /* Print percentage cpu, resident set size. */
        !          1767:                tmp = pick->p_pctcpu * 10000 + FSCALE / 2 >> FSHIFT;
        !          1768:                ttyprintf(tp, "%d%% %dk\n",
        !          1769:                   tmp / 100, pgtok(pick->p_vmspace->vm_rssize));
        !          1770:        }
        !          1771:        tp->t_rocount = 0;      /* so pending input will be retyped if BS */
        !          1772: }
        !          1773: 
        !          1774: /*
        !          1775:  * Returns 1 if p2 is "better" than p1
        !          1776:  *
        !          1777:  * The algorithm for picking the "interesting" process is thus:
        !          1778:  *
        !          1779:  *     1) (Only foreground processes are eligable - implied)
        !          1780:  *     2) Runnable processes are favored over anything
        !          1781:  *        else.  The runner with the highest cpu
        !          1782:  *        utilization is picked (p_cpu).  Ties are
        !          1783:  *        broken by picking the highest pid.
        !          1784:  *     3  Next, the sleeper with the shortest sleep
        !          1785:  *        time is favored.  With ties, we pick out
        !          1786:  *        just "short-term" sleepers (SSINTR == 0).
        !          1787:  *        Further ties are broken by picking the highest
        !          1788:  *        pid.
        !          1789:  *
        !          1790:  */
        !          1791: #define isrun(p)       (((p)->p_stat == SRUN) || ((p)->p_stat == SIDL))
        !          1792: #define TESTAB(a, b)    ((a)<<1 | (b))
        !          1793: #define ONLYA   2
        !          1794: #define ONLYB   1
        !          1795: #define BOTH    3
        !          1796: 
        !          1797: static int
        !          1798: proc_compare(p1, p2)
        !          1799:        register struct proc *p1, *p2;
        !          1800: {
        !          1801: 
        !          1802:        if (p1 == NULL)
        !          1803:                return (1);
        !          1804:        /*
        !          1805:         * see if at least one of them is runnable
        !          1806:         */
        !          1807:        switch (TESTAB(isrun(p1), isrun(p2))) {
        !          1808:        case ONLYA:
        !          1809:                return (0);
        !          1810:        case ONLYB:
        !          1811:                return (1);
        !          1812:        case BOTH:
        !          1813:                /*
        !          1814:                 * tie - favor one with highest recent cpu utilization
        !          1815:                 */
        !          1816:                if (p2->p_cpu > p1->p_cpu)
        !          1817:                        return (1);
        !          1818:                if (p1->p_cpu > p2->p_cpu)
        !          1819:                        return (0);
        !          1820:                return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
        !          1821:        }
        !          1822:        /*
        !          1823:         * weed out zombies
        !          1824:         */
        !          1825:        switch (TESTAB(p1->p_stat == SZOMB, p2->p_stat == SZOMB)) {
        !          1826:        case ONLYA:
        !          1827:                return (1);
        !          1828:        case ONLYB:
        !          1829:                return (0);
        !          1830:        case BOTH:
        !          1831:                return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
        !          1832:        }
        !          1833:        /* 
        !          1834:         * pick the one with the smallest sleep time
        !          1835:         */
        !          1836:        if (p2->p_slptime > p1->p_slptime)
        !          1837:                return (0);
        !          1838:        if (p1->p_slptime > p2->p_slptime)
        !          1839:                return (1);
        !          1840:        /*
        !          1841:         * favor one sleeping in a non-interruptible sleep
        !          1842:         */
        !          1843:        if (p1->p_flag&SSINTR && (p2->p_flag&SSINTR) == 0)
        !          1844:                return (1);
        !          1845:        if (p2->p_flag&SSINTR && (p1->p_flag&SSINTR) == 0)
        !          1846:                return (0);
        !          1847:        return (p2->p_pid > p1->p_pid);         /* tie - return highest pid */
        !          1848: }
        !          1849: 
        !          1850: /*
        !          1851:  * Output char to tty; console putchar style.
        !          1852:  */
        !          1853: tputchar(c, tp)
        !          1854:        int c;
        !          1855:        struct tty *tp;
        !          1856: {
        !          1857:        register s = spltty();
        !          1858: 
        !          1859:        if ((tp->t_state & (TS_CARR_ON|TS_ISOPEN)) == (TS_CARR_ON|TS_ISOPEN)) {
        !          1860:                if (c == '\n')
        !          1861:                        (void) ttyoutput('\r', tp);
        !          1862:                (void) ttyoutput(c, tp);
        !          1863:                ttstart(tp);
        !          1864:                splx(s);
        !          1865:                return (0);
        !          1866:        }
        !          1867:        splx(s);
        !          1868:        return (-1);
        !          1869: }
        !          1870: 
        !          1871: /*
        !          1872:  * Sleep on chan, returning ERESTART if tty changed
        !          1873:  * while we napped and returning any errors (e.g. EINTR/ETIMEDOUT)
        !          1874:  * reported by tsleep.  If the tty is revoked, restarting a pending
        !          1875:  * call will redo validation done at the start of the call.
        !          1876:  */
        !          1877: ttysleep(tp, chan, pri, wmesg, timo)
        !          1878:        struct tty *tp;
        !          1879:        caddr_t chan;
        !          1880:        int pri;
        !          1881:        char *wmesg;
        !          1882:        int timo;
        !          1883: {
        !          1884:        int error;
        !          1885:        short gen = tp->t_gen;
        !          1886: 
        !          1887:        if (error = tsleep(chan, pri, wmesg, timo))
        !          1888:                return (error);
        !          1889:        if (tp->t_gen != gen)
        !          1890:                return (ERESTART);
        !          1891:        return (0);
        !          1892: }

unix.superglobalmegacorp.com

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