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