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