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