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