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