tty.c revision 116663
1202375Srdivacky/*- 2202375Srdivacky * Copyright (c) 1982, 1986, 1990, 1991, 1993 3202375Srdivacky * The Regents of the University of California. All rights reserved. 4202375Srdivacky * (c) UNIX System Laboratories, Inc. 5202375Srdivacky * All or some portions of this file are derived from material licensed 6202375Srdivacky * to the University of California by American Telephone and Telegraph 7202375Srdivacky * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8202375Srdivacky * the permission of UNIX System Laboratories, Inc. 9202375Srdivacky * 10202375Srdivacky * Copyright (c) 2002 Networks Associates Technologies, Inc. 11202375Srdivacky * All rights reserved. 12202375Srdivacky * 13202375Srdivacky * Portions of this software were developed for the FreeBSD Project by 14202375Srdivacky * ThinkSec AS and NAI Labs, the Security Research Division of Network 15288943Sdim * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 16288943Sdim * ("CBOSS"), as part of the DARPA CHATS research program. 17249423Sdim * 18276479Sdim * Redistribution and use in source and binary forms, with or without 19202375Srdivacky * modification, are permitted provided that the following conditions 20202375Srdivacky * are met: 21249423Sdim * 1. Redistributions of source code must retain the above copyright 22202375Srdivacky * notice, this list of conditions and the following disclaimer. 23276479Sdim * 2. Redistributions in binary form must reproduce the above copyright 24276479Sdim * notice, this list of conditions and the following disclaimer in the 25249423Sdim * documentation and/or other materials provided with the distribution. 26202375Srdivacky * 3. All advertising materials mentioning features or use of this software 27202375Srdivacky * must display the following acknowledgement: 28202375Srdivacky * This product includes software developed by the University of 29249423Sdim * California, Berkeley and its contributors. 30202375Srdivacky * 4. Neither the name of the University nor the names of its contributors 31202375Srdivacky * may be used to endorse or promote products derived from this software 32202375Srdivacky * without specific prior written permission. 33202375Srdivacky * 34202375Srdivacky * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 35202375Srdivacky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 36202375Srdivacky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 37202375Srdivacky * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 38202375Srdivacky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 39218893Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 40202375Srdivacky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 41202375Srdivacky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 42202375Srdivacky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 43202375Srdivacky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 44202375Srdivacky * SUCH DAMAGE. 45202375Srdivacky * 46280031Sdim * @(#)tty.c 8.8 (Berkeley) 1/21/94 47202375Srdivacky */ 48202375Srdivacky 49202375Srdivacky/*- 50202375Srdivacky * TODO: 51202375Srdivacky * o Fix races for sending the start char in ttyflush(). 52202375Srdivacky * o Handle inter-byte timeout for "MIN > 0, TIME > 0" in ttyselect(). 53202375Srdivacky * With luck, there will be MIN chars before select() returns(). 54202375Srdivacky * o Handle CLOCAL consistently for ptys. Perhaps disallow setting it. 55202375Srdivacky * o Don't allow input in TS_ZOMBIE case. It would be visible through 56202375Srdivacky * FIONREAD. 57202375Srdivacky * o Do the new sio locking stuff here and use it to avoid special 58202375Srdivacky * case for EXTPROC? 59249423Sdim * o Lock PENDIN too? 60288943Sdim * o Move EXTPROC and/or PENDIN to t_state? 61288943Sdim * o Wrap most of ttioctl in spltty/splx. 62276479Sdim * o Implement TIOCNOTTY or remove it from <sys/ioctl.h>. 63202375Srdivacky * o Send STOP if IXOFF is toggled off while TS_TBLOCK is set. 64202375Srdivacky * o Don't allow certain termios flags to affect disciplines other 65202375Srdivacky * than TTYDISC. Cancel their effects before switch disciplines 66202375Srdivacky * and ignore them if they are set while we are in another 67202375Srdivacky * discipline. 68202375Srdivacky * o Now that historical speed conversions are handled here, don't 69202375Srdivacky * do them in drivers. 70202375Srdivacky * o Check for TS_CARR_ON being set while everything is closed and not 71249423Sdim * waiting for carrier. TS_CARR_ON isn't cleared if nothing is open, 72202375Srdivacky * so it would live until the next open even if carrier drops. 73202375Srdivacky * o Restore TS_WOPEN since it is useful in pstat. It must be cleared 74288943Sdim * only when _all_ openers leave open(). 75288943Sdim */ 76288943Sdim 77276479Sdim#include <sys/cdefs.h> 78202375Srdivacky__FBSDID("$FreeBSD: head/sys/kern/tty.c 116663 2003-06-22 02:54:33Z iedowse $"); 79202375Srdivacky 80202375Srdivacky#include "opt_compat.h" 81202375Srdivacky#include "opt_tty.h" 82202375Srdivacky 83202375Srdivacky#include <sys/param.h> 84202375Srdivacky#include <sys/systm.h> 85202375Srdivacky#include <sys/filio.h> 86202375Srdivacky#include <sys/lock.h> 87202375Srdivacky#include <sys/mutex.h> 88202375Srdivacky#include <sys/namei.h> 89202375Srdivacky#include <sys/sx.h> 90202375Srdivacky#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 91202375Srdivacky#include <sys/ioctl_compat.h> 92202375Srdivacky#endif 93249423Sdim#include <sys/proc.h> 94202375Srdivacky#define TTYDEFCHARS 95202375Srdivacky#include <sys/tty.h> 96202375Srdivacky#undef TTYDEFCHARS 97202375Srdivacky#include <sys/fcntl.h> 98202375Srdivacky#include <sys/conf.h> 99202375Srdivacky#include <sys/poll.h> 100202375Srdivacky#include <sys/kernel.h> 101202375Srdivacky#include <sys/vnode.h> 102202375Srdivacky#include <sys/signalvar.h> 103202375Srdivacky#include <sys/resourcevar.h> 104202375Srdivacky#include <sys/malloc.h> 105202375Srdivacky#include <sys/filedesc.h> 106280031Sdim#include <sys/sysctl.h> 107280031Sdim 108276479Sdim#include <vm/vm.h> 109202375Srdivacky#include <vm/pmap.h> 110202375Srdivacky#include <vm/vm_map.h> 111226633Sdim 112288943SdimMALLOC_DEFINE(M_TTYS, "ttys", "tty data structures"); 113288943Sdim 114288943Sdimlong tk_cancc; 115288943Sdimlong tk_nin; 116288943Sdimlong tk_nout; 117288943Sdimlong tk_rawcc; 118202375Srdivacky 119202375Srdivackystatic int proc_compare(struct proc *p1, struct proc *p2); 120202375Srdivackystatic int ttnread(struct tty *tp); 121202375Srdivackystatic void ttyecho(int c, struct tty *tp); 122276479Sdimstatic int ttyoutput(int c, struct tty *tp); 123202375Srdivackystatic void ttypend(struct tty *tp); 124202375Srdivackystatic void ttyretype(struct tty *tp); 125202375Srdivackystatic void ttyrub(int c, struct tty *tp); 126218893Sdimstatic void ttyrubo(struct tty *tp, int cnt); 127202375Srdivackystatic void ttyunblock(struct tty *tp); 128276479Sdimstatic int ttywflush(struct tty *tp); 129202375Srdivackystatic int filt_ttyread(struct knote *kn, long hint); 130202375Srdivackystatic void filt_ttyrdetach(struct knote *kn); 131218893Sdimstatic int filt_ttywrite(struct knote *kn, long hint); 132218893Sdimstatic void filt_ttywdetach(struct knote *kn); 133202375Srdivacky 134202375Srdivacky/* 135276479Sdim * Table with character classes and parity. The 8th bit indicates parity, 136202375Srdivacky * the 7th bit indicates the character is an alphameric or underscore (for 137202375Srdivacky * ALTWERASE), and the low 6 bits indicate delay type. If the low 6 bits 138249423Sdim * are 0 then the character needs no special processing on output; classes 139202375Srdivacky * other than 0 might be translated or (not currently) require delays. 140276479Sdim */ 141249423Sdim#define E 0x00 /* Even parity. */ 142202375Srdivacky#define O 0x80 /* Odd parity. */ 143203954Srdivacky#define PARITY(c) (char_type[c] & O) 144202375Srdivacky 145202375Srdivacky#define ALPHA 0x40 /* Alpha or underscore. */ 146202375Srdivacky#define ISALPHA(c) (char_type[(c) & TTY_CHARMASK] & ALPHA) 147280031Sdim 148276479Sdim#define CCLASSMASK 0x3f 149202375Srdivacky#define CCLASS(c) (char_type[c] & CCLASSMASK) 150202375Srdivacky 151202375Srdivacky#define BS BACKSPACE 152202375Srdivacky#define CC CONTROL 153202375Srdivacky#define CR RETURN 154202375Srdivacky#define NA ORDINARY | ALPHA 155202375Srdivacky#define NL NEWLINE 156202375Srdivacky#define NO ORDINARY 157202375Srdivacky#define TB TAB 158202375Srdivacky#define VT VTAB 159202375Srdivacky 160202375Srdivackystatic u_char const char_type[] = { 161288943Sdim E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* nul - bel */ 162280031Sdim O|BS, E|TB, E|NL, O|CC, E|VT, O|CR, O|CC, E|CC, /* bs - si */ 163288943Sdim O|CC, E|CC, E|CC, O|CC, E|CC, O|CC, O|CC, E|CC, /* dle - etb */ 164280031Sdim E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* can - us */ 165249423Sdim O|NO, E|NO, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* sp - ' */ 166202375Srdivacky E|NO, O|NO, O|NO, E|NO, O|NO, E|NO, E|NO, O|NO, /* ( - / */ 167202375Srdivacky E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* 0 - 7 */ 168202375Srdivacky O|NA, E|NA, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* 8 - ? */ 169249423Sdim O|NO, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* @ - G */ 170202375Srdivacky E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* H - O */ 171202375Srdivacky E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* P - W */ 172249423Sdim O|NA, E|NA, E|NA, O|NO, E|NO, O|NO, O|NO, O|NA, /* X - _ */ 173202375Srdivacky E|NO, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* ` - g */ 174202375Srdivacky O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* h - o */ 175249423Sdim O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* p - w */ 176202375Srdivacky E|NA, O|NA, O|NA, E|NO, O|NO, E|NO, E|NO, O|CC, /* x - del */ 177202375Srdivacky /* 178202375Srdivacky * Meta chars; should be settable per character set; 179249423Sdim * for now, treat them all as normal characters. 180202375Srdivacky */ 181202375Srdivacky NA, NA, NA, NA, NA, NA, NA, NA, 182202375Srdivacky NA, NA, NA, NA, NA, NA, NA, NA, 183249423Sdim NA, NA, NA, NA, NA, NA, NA, NA, 184202375Srdivacky NA, NA, NA, NA, NA, NA, NA, NA, 185288943Sdim NA, NA, NA, NA, NA, NA, NA, NA, 186280031Sdim NA, NA, NA, NA, NA, NA, NA, NA, 187288943Sdim NA, NA, NA, NA, NA, NA, NA, NA, 188280031Sdim NA, NA, NA, NA, NA, NA, NA, NA, 189249423Sdim NA, NA, NA, NA, NA, NA, NA, NA, 190202375Srdivacky NA, NA, NA, NA, NA, NA, NA, NA, 191202375Srdivacky NA, NA, NA, NA, NA, NA, NA, NA, 192202375Srdivacky NA, NA, NA, NA, NA, NA, NA, NA, 193249423Sdim NA, NA, NA, NA, NA, NA, NA, NA, 194202375Srdivacky NA, NA, NA, NA, NA, NA, NA, NA, 195202375Srdivacky NA, NA, NA, NA, NA, NA, NA, NA, 196249423Sdim NA, NA, NA, NA, NA, NA, NA, NA, 197202375Srdivacky}; 198202375Srdivacky#undef BS 199249423Sdim#undef CC 200202375Srdivacky#undef CR 201202375Srdivacky#undef NA 202249423Sdim#undef NL 203202375Srdivacky#undef NO 204202375Srdivacky#undef TB 205249423Sdim#undef VT 206202375Srdivacky 207202375Srdivacky/* Macros to clear/set/test flags. */ 208249423Sdim#define SET(t, f) (t) |= (f) 209249423Sdim#define CLR(t, f) (t) &= ~(f) 210249423Sdim#define ISSET(t, f) ((t) & (f)) 211249423Sdim 212288943Sdim#undef MAX_INPUT /* XXX wrong in <sys/syslimits.h> */ 213280031Sdim#define MAX_INPUT TTYHOG /* XXX limit is usually larger for !ICANON */ 214288943Sdim 215280031Sdim/* 216249423Sdim * list of struct tty where pstat(8) can pick it up with sysctl 217249423Sdim */ 218249423Sdimstatic SLIST_HEAD(, tty) tty_list; 219249423Sdim 220249423Sdimstatic int drainwait = 5*60; 221249423SdimSYSCTL_INT(_kern, OID_AUTO, drainwait, CTLFLAG_RW, &drainwait, 222249423Sdim 0, "Output drain timeout in seconds"); 223202375Srdivacky 224249423Sdim/* 225202375Srdivacky * Initial open of tty, or (re)entry to standard tty line discipline. 226280031Sdim */ 227276479Sdimint 228202375Srdivackyttyopen(dev_t device, struct tty *tp) 229249423Sdim{ 230202375Srdivacky int s; 231202375Srdivacky 232202375Srdivacky s = spltty(); 233202375Srdivacky tp->t_dev = device; 234202375Srdivacky if (!ISSET(tp->t_state, TS_ISOPEN)) { 235202375Srdivacky SET(tp->t_state, TS_ISOPEN); 236249423Sdim if (ISSET(tp->t_cflag, CLOCAL)) 237202375Srdivacky SET(tp->t_state, TS_CONNECTED); 238202375Srdivacky bzero(&tp->t_winsize, sizeof(tp->t_winsize)); 239280031Sdim } 240202375Srdivacky /* XXX don't hang forever on output */ 241202375Srdivacky if (tp->t_timeout < 0) 242202375Srdivacky tp->t_timeout = drainwait*hz; 243288943Sdim ttsetwater(tp); 244288943Sdim splx(s); 245202375Srdivacky return (0); 246288943Sdim} 247202375Srdivacky 248249423Sdim/* 249249423Sdim * Handle close() on a tty line: flush and set to initial state, 250202375Srdivacky * bumping generation number so that pending read/write calls 251280031Sdim * can detect recycling of the tty. 252280031Sdim * XXX our caller should have done `spltty(); l_close(); ttyclose();' 253280031Sdim * and l_close() should have flushed, but we repeat the spltty() and 254280031Sdim * the flush in case there are buggy callers. 255280031Sdim */ 256280031Sdimint 257202375Srdivackyttyclose(struct tty *tp) 258202375Srdivacky{ 259249423Sdim int s; 260202375Srdivacky 261202375Srdivacky funsetown(&tp->t_sigio); 262249423Sdim s = spltty(); 263202375Srdivacky if (constty == tp) 264202375Srdivacky constty_clear(); 265249423Sdim 266202375Srdivacky ttyflush(tp, FREAD | FWRITE); 267202375Srdivacky clist_free_cblocks(&tp->t_canq); 268202375Srdivacky clist_free_cblocks(&tp->t_outq); 269249423Sdim clist_free_cblocks(&tp->t_rawq); 270202375Srdivacky 271202375Srdivacky tp->t_gen++; 272202375Srdivacky tp->t_line = TTYDISC; 273249423Sdim tp->t_pgrp = NULL; 274202375Srdivacky tp->t_session = NULL; 275203954Srdivacky tp->t_state = 0; 276202375Srdivacky splx(s); 277203954Srdivacky return (0); 278202375Srdivacky} 279202375Srdivacky 280202375Srdivacky#define FLUSHQ(q) { \ 281288943Sdim if ((q)->c_cc) \ 282288943Sdim ndflush(q, (q)->c_cc); \ 283249423Sdim} 284288943Sdim 285202375Srdivacky/* Is 'c' a line delimiter ("break" character)? */ 286249423Sdim#define TTBREAKC(c, lflag) \ 287249423Sdim ((c) == '\n' || (((c) == cc[VEOF] || \ 288249423Sdim (c) == cc[VEOL] || ((c) == cc[VEOL2] && lflag & IEXTEN)) && \ 289280031Sdim (c) != _POSIX_VDISABLE)) 290280031Sdim 291280031Sdim/* 292280031Sdim * Process input of a single character received on a tty. 293280031Sdim */ 294280031Sdimint 295202375Srdivackyttyinput(int c, struct tty *tp) 296202375Srdivacky{ 297249423Sdim tcflag_t iflag, lflag; 298202375Srdivacky cc_t *cc; 299202375Srdivacky int i, err; 300249423Sdim 301202375Srdivacky /* 302202375Srdivacky * If input is pending take it first. 303202375Srdivacky */ 304202375Srdivacky lflag = tp->t_lflag; 305202375Srdivacky if (ISSET(lflag, PENDIN)) 306249423Sdim ttypend(tp); 307202375Srdivacky /* 308202375Srdivacky * Gather stats. 309249423Sdim */ 310202375Srdivacky if (ISSET(lflag, ICANON)) { 311202375Srdivacky ++tk_cancc; 312249423Sdim ++tp->t_cancc; 313202375Srdivacky } else { 314202375Srdivacky ++tk_rawcc; 315202375Srdivacky ++tp->t_rawcc; 316249423Sdim } 317202375Srdivacky ++tk_nin; 318203954Srdivacky 319202375Srdivacky /* 320203954Srdivacky * Block further input iff: 321202375Srdivacky * current input > threshold AND input is available to user program 322202375Srdivacky * AND input flow control is enabled and not yet invoked. 323288943Sdim * The 3 is slop for PARMRK. 324288943Sdim */ 325288943Sdim iflag = tp->t_iflag; 326288943Sdim if (tp->t_rawq.c_cc + tp->t_canq.c_cc > tp->t_ihiwat - 3 && 327202375Srdivacky (!ISSET(lflag, ICANON) || tp->t_canq.c_cc != 0) && 328249423Sdim (ISSET(tp->t_cflag, CRTS_IFLOW) || ISSET(iflag, IXOFF)) && 329249423Sdim !ISSET(tp->t_state, TS_TBLOCK)) 330249423Sdim ttyblock(tp); 331280031Sdim 332280031Sdim /* Handle exceptional conditions (break, parity, framing). */ 333280031Sdim cc = tp->t_cc; 334280031Sdim err = (ISSET(c, TTY_ERRORMASK)); 335280031Sdim if (err) { 336280031Sdim CLR(c, TTY_ERRORMASK); 337280031Sdim if (ISSET(err, TTY_BI)) { 338280031Sdim if (ISSET(iflag, IGNBRK)) 339280031Sdim return (0); 340280031Sdim if (ISSET(iflag, BRKINT)) { 341280031Sdim ttyflush(tp, FREAD | FWRITE); 342280031Sdim if (tp->t_pgrp != NULL) { 343202375Srdivacky PGRP_LOCK(tp->t_pgrp); 344202375Srdivacky pgsignal(tp->t_pgrp, SIGINT, 1); 345202375Srdivacky PGRP_UNLOCK(tp->t_pgrp); 346202375Srdivacky } 347202375Srdivacky goto endcase; 348202375Srdivacky } 349249423Sdim if (ISSET(iflag, PARMRK)) 350202375Srdivacky goto parmrk; 351202375Srdivacky } else if ((ISSET(err, TTY_PE) && ISSET(iflag, INPCK)) 352202375Srdivacky || ISSET(err, TTY_FE)) { 353202375Srdivacky if (ISSET(iflag, IGNPAR)) 354249423Sdim return (0); 355202375Srdivacky else if (ISSET(iflag, PARMRK)) { 356202375Srdivackyparmrk: 357223017Sdim if (tp->t_rawq.c_cc + tp->t_canq.c_cc > 358202375Srdivacky MAX_INPUT - 3) 359249423Sdim goto input_overflow; 360202375Srdivacky (void)putc(0377 | TTY_QUOTE, &tp->t_rawq); 361202375Srdivacky (void)putc(0 | TTY_QUOTE, &tp->t_rawq); 362202375Srdivacky (void)putc(c | TTY_QUOTE, &tp->t_rawq); 363202375Srdivacky goto endcase; 364249423Sdim } else 365202375Srdivacky c = 0; 366202375Srdivacky } 367202375Srdivacky } 368202375Srdivacky 369226633Sdim if (!ISSET(tp->t_state, TS_TYPEN) && ISSET(iflag, ISTRIP)) 370223017Sdim CLR(c, 0x80); 371202375Srdivacky if (!ISSET(lflag, EXTPROC)) { 372202375Srdivacky /* 373249423Sdim * Check for literal nexting very first 374202375Srdivacky */ 375202375Srdivacky if (ISSET(tp->t_state, TS_LNCH)) { 376202375Srdivacky SET(c, TTY_QUOTE); 377202375Srdivacky CLR(tp->t_state, TS_LNCH); 378249423Sdim } 379202375Srdivacky /* 380202375Srdivacky * Scan for special characters. This code 381202375Srdivacky * is really just a big case statement with 382202375Srdivacky * non-constant cases. The bottom of the 383202375Srdivacky * case statement is labeled ``endcase'', so goto 384202375Srdivacky * it after a case match, or similar. 385202375Srdivacky */ 386202375Srdivacky 387202375Srdivacky /* 388202375Srdivacky * Control chars which aren't controlled 389202375Srdivacky * by ICANON, ISIG, or IXON. 390202375Srdivacky */ 391249423Sdim if (ISSET(lflag, IEXTEN)) { 392202375Srdivacky if (CCEQ(cc[VLNEXT], c)) { 393202375Srdivacky if (ISSET(lflag, ECHO)) { 394226633Sdim if (ISSET(lflag, ECHOE)) { 395223017Sdim (void)ttyoutput('^', tp); 396249423Sdim (void)ttyoutput('\b', tp); 397202375Srdivacky } else 398202375Srdivacky ttyecho(c, tp); 399226633Sdim } 400223017Sdim SET(tp->t_state, TS_LNCH); 401202375Srdivacky goto endcase; 402203954Srdivacky } 403203954Srdivacky if (CCEQ(cc[VDISCARD], c)) { 404203954Srdivacky if (ISSET(lflag, FLUSHO)) 405203954Srdivacky CLR(tp->t_lflag, FLUSHO); 406203954Srdivacky else { 407202375Srdivacky ttyflush(tp, FWRITE); 408202375Srdivacky ttyecho(c, tp); 409202375Srdivacky if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 410288943Sdim ttyretype(tp); 411288943Sdim SET(tp->t_lflag, FLUSHO); 412288943Sdim } 413296417Sdim goto startoutput; 414288943Sdim } 415296417Sdim } 416288943Sdim /* 417288943Sdim * Signals. 418288943Sdim */ 419288943Sdim if (ISSET(lflag, ISIG)) { 420202375Srdivacky if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) { 421249423Sdim if (!ISSET(lflag, NOFLSH)) 422249423Sdim ttyflush(tp, FREAD | FWRITE); 423249423Sdim ttyecho(c, tp); 424202375Srdivacky if (tp->t_pgrp != NULL) { 425202375Srdivacky PGRP_LOCK(tp->t_pgrp); 426202375Srdivacky pgsignal(tp->t_pgrp, 427202375Srdivacky CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1); 428249423Sdim PGRP_UNLOCK(tp->t_pgrp); 429202375Srdivacky } 430203954Srdivacky goto endcase; 431203954Srdivacky } 432202375Srdivacky if (CCEQ(cc[VSUSP], c)) { 433202375Srdivacky if (!ISSET(lflag, NOFLSH)) 434202375Srdivacky ttyflush(tp, FREAD); 435218893Sdim ttyecho(c, tp); 436218893Sdim if (tp->t_pgrp != NULL) { 437218893Sdim PGRP_LOCK(tp->t_pgrp); 438288943Sdim pgsignal(tp->t_pgrp, SIGTSTP, 1); 439288943Sdim PGRP_UNLOCK(tp->t_pgrp); 440202375Srdivacky } 441218893Sdim goto endcase; 442218893Sdim } 443218893Sdim } 444249423Sdim /* 445202375Srdivacky * Handle start/stop characters. 446202375Srdivacky */ 447202375Srdivacky if (ISSET(iflag, IXON)) { 448203954Srdivacky if (CCEQ(cc[VSTOP], c)) { 449276479Sdim if (!ISSET(tp->t_state, TS_TTSTOP)) { 450202375Srdivacky SET(tp->t_state, TS_TTSTOP); 451226633Sdim (*tp->t_stop)(tp, 0); 452226633Sdim return (0); 453202375Srdivacky } 454202375Srdivacky if (!CCEQ(cc[VSTART], c)) 455202375Srdivacky return (0); 456276479Sdim /* 457202375Srdivacky * if VSTART == VSTOP then toggle 458202375Srdivacky */ 459276479Sdim goto endcase; 460204642Srdivacky } 461202375Srdivacky if (CCEQ(cc[VSTART], c)) 462276479Sdim goto restartoutput; 463202375Srdivacky } 464288943Sdim /* 465288943Sdim * IGNCR, ICRNL, & INLCR 466202375Srdivacky */ 467249423Sdim if (c == '\r') { 468202375Srdivacky if (ISSET(iflag, IGNCR)) 469202375Srdivacky return (0); 470202375Srdivacky else if (ISSET(iflag, ICRNL)) 471202375Srdivacky c = '\n'; 472249423Sdim } else if (c == '\n' && ISSET(iflag, INLCR)) 473218893Sdim c = '\r'; 474218893Sdim } 475218893Sdim if (!ISSET(tp->t_lflag, EXTPROC) && ISSET(lflag, ICANON)) { 476288943Sdim /* 477288943Sdim * From here on down canonical mode character 478202375Srdivacky * processing takes place. 479218893Sdim */ 480218893Sdim /* 481218893Sdim * erase or erase2 (^H / ^?) 482249423Sdim */ 483202375Srdivacky if (CCEQ(cc[VERASE], c) || CCEQ(cc[VERASE2], c) ) { 484203954Srdivacky if (tp->t_rawq.c_cc) 485202375Srdivacky ttyrub(unputc(&tp->t_rawq), tp); 486202375Srdivacky goto endcase; 487202375Srdivacky } 488202375Srdivacky /* 489202375Srdivacky * kill (^U) 490249423Sdim */ 491249423Sdim if (CCEQ(cc[VKILL], c)) { 492202375Srdivacky if (ISSET(lflag, ECHOKE) && 493202375Srdivacky tp->t_rawq.c_cc == tp->t_rocount && 494202375Srdivacky !ISSET(lflag, ECHOPRT)) 495202375Srdivacky while (tp->t_rawq.c_cc) 496202375Srdivacky ttyrub(unputc(&tp->t_rawq), tp); 497202375Srdivacky else { 498218893Sdim ttyecho(c, tp); 499249423Sdim if (ISSET(lflag, ECHOK) || 500218893Sdim ISSET(lflag, ECHOKE)) 501218893Sdim ttyecho('\n', tp); 502218893Sdim FLUSHQ(&tp->t_rawq); 503288943Sdim tp->t_rocount = 0; 504288943Sdim } 505202375Srdivacky CLR(tp->t_state, TS_LOCAL); 506218893Sdim goto endcase; 507218893Sdim } 508218893Sdim /* 509249423Sdim * word erase (^W) 510249423Sdim */ 511202375Srdivacky if (CCEQ(cc[VWERASE], c) && ISSET(lflag, IEXTEN)) { 512202375Srdivacky int ctype; 513202375Srdivacky 514202375Srdivacky /* 515202375Srdivacky * erase whitespace 516203954Srdivacky */ 517202375Srdivacky while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t') 518202375Srdivacky ttyrub(c, tp); 519223017Sdim if (c == -1) 520203954Srdivacky goto endcase; 521203954Srdivacky /* 522202375Srdivacky * erase last char of word and remember the 523202375Srdivacky * next chars type (for ALTWERASE) 524202375Srdivacky */ 525288943Sdim ttyrub(c, tp); 526288943Sdim c = unputc(&tp->t_rawq); 527288943Sdim if (c == -1) 528288943Sdim goto endcase; 529202375Srdivacky if (c == ' ' || c == '\t') { 530288943Sdim (void)putc(c, &tp->t_rawq); 531288943Sdim goto endcase; 532202375Srdivacky } 533202375Srdivacky ctype = ISALPHA(c); 534202375Srdivacky /* 535288943Sdim * erase rest of word 536288943Sdim */ 537202375Srdivacky do { 538288943Sdim ttyrub(c, tp); 539288943Sdim c = unputc(&tp->t_rawq); 540288943Sdim if (c == -1) 541288943Sdim goto endcase; 542288943Sdim } while (c != ' ' && c != '\t' && 543288943Sdim (!ISSET(lflag, ALTWERASE) || ISALPHA(c) == ctype)); 544288943Sdim (void)putc(c, &tp->t_rawq); 545202375Srdivacky goto endcase; 546288943Sdim } 547202375Srdivacky /* 548234353Sdim * reprint line (^R) 549288943Sdim */ 550202375Srdivacky if (CCEQ(cc[VREPRINT], c) && ISSET(lflag, IEXTEN)) { 551280031Sdim ttyretype(tp); 552202375Srdivacky goto endcase; 553288943Sdim } 554202375Srdivacky /* 555202375Srdivacky * ^T - kernel info and generate SIGINFO 556249423Sdim */ 557249423Sdim if (CCEQ(cc[VSTATUS], c) && ISSET(lflag, IEXTEN)) { 558249423Sdim if (ISSET(lflag, ISIG) && tp->t_pgrp != NULL) { 559249423Sdim PGRP_LOCK(tp->t_pgrp); 560249423Sdim pgsignal(tp->t_pgrp, SIGINFO, 1); 561249423Sdim PGRP_UNLOCK(tp->t_pgrp); 562249423Sdim } 563249423Sdim if (!ISSET(lflag, NOKERNINFO)) 564249423Sdim ttyinfo(tp); 565249423Sdim goto endcase; 566249423Sdim } 567218893Sdim } 568202375Srdivacky /* 569249423Sdim * Check for input buffer overflow 570218893Sdim */ 571218893Sdim if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= MAX_INPUT) { 572218893Sdiminput_overflow: 573218893Sdim if (ISSET(iflag, IMAXBEL)) { 574218893Sdim if (tp->t_outq.c_cc < tp->t_ohiwat) 575218893Sdim (void)ttyoutput(CTRL('g'), tp); 576249423Sdim } 577288943Sdim goto endcase; 578288943Sdim } 579202375Srdivacky 580203954Srdivacky if ( c == 0377 && ISSET(iflag, PARMRK) && !ISSET(iflag, ISTRIP) 581203954Srdivacky && ISSET(iflag, IGNBRK|IGNPAR) != (IGNBRK|IGNPAR)) 582203954Srdivacky (void)putc(0377 | TTY_QUOTE, &tp->t_rawq); 583202375Srdivacky 584202375Srdivacky /* 585203954Srdivacky * Put data char in q for user and 586202375Srdivacky * wakeup on seeing a line delimiter. 587202375Srdivacky */ 588202375Srdivacky if (putc(c, &tp->t_rawq) >= 0) { 589202375Srdivacky if (!ISSET(lflag, ICANON)) { 590202375Srdivacky ttwakeup(tp); 591218893Sdim ttyecho(c, tp); 592249423Sdim goto endcase; 593202375Srdivacky } 594202375Srdivacky if (TTBREAKC(c, lflag)) { 595249423Sdim tp->t_rocount = 0; 596218893Sdim catq(&tp->t_rawq, &tp->t_canq); 597218893Sdim ttwakeup(tp); 598218893Sdim } else if (tp->t_rocount++ == 0) 599218893Sdim tp->t_rocol = tp->t_column; 600249423Sdim if (ISSET(tp->t_state, TS_ERASE)) { 601288943Sdim /* 602288943Sdim * end of prterase \.../ 603202375Srdivacky */ 604203954Srdivacky CLR(tp->t_state, TS_ERASE); 605203954Srdivacky (void)ttyoutput('/', tp); 606203954Srdivacky } 607202375Srdivacky i = tp->t_column; 608202375Srdivacky ttyecho(c, tp); 609202375Srdivacky if (CCEQ(cc[VEOF], c) && ISSET(lflag, ECHO)) { 610203954Srdivacky /* 611202375Srdivacky * Place the cursor over the '^' of the ^D. 612202375Srdivacky */ 613202375Srdivacky i = imin(2, tp->t_column - i); 614202375Srdivacky while (i > 0) { 615202375Srdivacky (void)ttyoutput('\b', tp); 616202375Srdivacky i--; 617202375Srdivacky } 618202375Srdivacky } 619202375Srdivacky } 620202375Srdivackyendcase: 621202375Srdivacky /* 622202375Srdivacky * IXANY means allow any character to restart output. 623223017Sdim */ 624249423Sdim if (ISSET(tp->t_state, TS_TTSTOP) && 625202375Srdivacky !ISSET(iflag, IXANY) && cc[VSTART] != cc[VSTOP]) 626202375Srdivacky return (0); 627202375Srdivackyrestartoutput: 628202375Srdivacky CLR(tp->t_lflag, FLUSHO); 629202375Srdivacky CLR(tp->t_state, TS_TTSTOP); 630249423Sdimstartoutput: 631202375Srdivacky return (ttstart(tp)); 632218893Sdim} 633249423Sdim 634202375Srdivacky/* 635202375Srdivacky * Output a single character on a tty, doing output processing 636202375Srdivacky * as needed (expanding tabs, newline processing, etc.). 637202375Srdivacky * Returns < 0 if succeeds, otherwise returns char to resend. 638202375Srdivacky * Must be recursive. 639218893Sdim */ 640249423Sdimstatic int 641218893Sdimttyoutput(int c, struct tty *tp) 642218893Sdim{ 643218893Sdim tcflag_t oflag; 644218893Sdim int col, s; 645249423Sdim 646288943Sdim oflag = tp->t_oflag; 647288943Sdim if (!ISSET(oflag, OPOST)) { 648202375Srdivacky if (ISSET(tp->t_lflag, FLUSHO)) 649203954Srdivacky return (-1); 650202375Srdivacky if (putc(c, &tp->t_outq)) 651202375Srdivacky return (c); 652203954Srdivacky tk_nout++; 653203954Srdivacky tp->t_outcc++; 654249423Sdim return (-1); 655202375Srdivacky } 656202375Srdivacky /* 657202375Srdivacky * Do tab expansion if OXTABS is set. Special case if we external 658249423Sdim * processing, we don't do the tab expansion because we'll probably 659249423Sdim * get it wrong. If tab expansion needs to be done, let it happen 660202375Srdivacky * externally. 661202375Srdivacky */ 662249423Sdim CLR(c, ~TTY_CHARMASK); 663202375Srdivacky if (c == '\t' && 664202375Srdivacky ISSET(oflag, OXTABS) && !ISSET(tp->t_lflag, EXTPROC)) { 665234353Sdim c = 8 - (tp->t_column & 7); 666234353Sdim if (!ISSET(tp->t_lflag, FLUSHO)) { 667234353Sdim s = spltty(); /* Don't interrupt tabs. */ 668223017Sdim c -= b_to_q(" ", c, &tp->t_outq); 669203954Srdivacky tk_nout += c; 670203954Srdivacky tp->t_outcc += c; 671202375Srdivacky splx(s); 672202375Srdivacky } 673202375Srdivacky tp->t_column += c; 674202375Srdivacky return (c ? -1 : '\t'); 675202375Srdivacky } 676221345Sdim if (c == CEOT && ISSET(oflag, ONOEOT)) 677221345Sdim return (-1); 678221345Sdim 679221345Sdim /* 680202375Srdivacky * Newline translation: if ONLCR is set, 681202375Srdivacky * translate newline into "\r\n". 682202375Srdivacky */ 683202375Srdivacky if (c == '\n' && ISSET(tp->t_oflag, ONLCR)) { 684202375Srdivacky tk_nout++; 685202375Srdivacky tp->t_outcc++; 686202375Srdivacky if (!ISSET(tp->t_lflag, FLUSHO) && putc('\r', &tp->t_outq)) 687288943Sdim return (c); 688288943Sdim } 689202375Srdivacky /* If OCRNL is set, translate "\r" into "\n". */ 690202375Srdivacky else if (c == '\r' && ISSET(tp->t_oflag, OCRNL)) 691203954Srdivacky c = '\n'; 692203954Srdivacky /* If ONOCR is set, don't transmit CRs when on column 0. */ 693203954Srdivacky else if (c == '\r' && ISSET(tp->t_oflag, ONOCR) && tp->t_column == 0) 694203954Srdivacky return (-1); 695203954Srdivacky 696203954Srdivacky tk_nout++; 697202375Srdivacky tp->t_outcc++; 698203954Srdivacky if (!ISSET(tp->t_lflag, FLUSHO) && putc(c, &tp->t_outq)) 699202375Srdivacky return (c); 700203954Srdivacky 701203954Srdivacky col = tp->t_column; 702203954Srdivacky switch (CCLASS(c)) { 703203954Srdivacky case BACKSPACE: 704202375Srdivacky if (col > 0) 705249423Sdim --col; 706202375Srdivacky break; 707202375Srdivacky case CONTROL: 708221345Sdim break; 709221345Sdim case NEWLINE: 710221345Sdim if (ISSET(tp->t_oflag, ONLCR | ONLRET)) 711221345Sdim col = 0; 712221345Sdim break; 713288943Sdim case RETURN: 714280031Sdim col = 0; 715221345Sdim break; 716221345Sdim case ORDINARY: 717261991Sdim ++col; 718221345Sdim break; 719202375Srdivacky case TAB: 720202375Srdivacky col = (col + 8) & ~7; 721202375Srdivacky break; 722202375Srdivacky } 723288943Sdim tp->t_column = col; 724288943Sdim return (-1); 725288943Sdim} 726288943Sdim 727202375Srdivacky/* 728202375Srdivacky * Ioctls for all tty devices. Called after line-discipline specific ioctl 729202375Srdivacky * has been called to do discipline-specific functions and/or reject any 730202375Srdivacky * of these ioctl commands. 731202375Srdivacky */ 732202375Srdivacky/* ARGSUSED */ 733202375Srdivackyint 734202375Srdivackyttioctl(struct tty *tp, u_long cmd, void *data, int flag) 735202375Srdivacky{ 736202375Srdivacky struct proc *p; 737202375Srdivacky struct thread *td; 738202375Srdivacky struct pgrp *pgrp; 739202375Srdivacky int s, error; 740202375Srdivacky 741202375Srdivacky td = curthread; /* XXX */ 742202375Srdivacky p = td->td_proc; 743202375Srdivacky 744249423Sdim /* If the ioctl involves modification, hang if in the background. */ 745202375Srdivacky switch (cmd) { 746202375Srdivacky case TIOCCBRK: 747202375Srdivacky case TIOCCONS: 748202375Srdivacky case TIOCDRAIN: 749202375Srdivacky case TIOCEXCL: 750202375Srdivacky case TIOCFLUSH: 751202375Srdivacky#ifdef TIOCHPCL 752202375Srdivacky case TIOCHPCL: 753202375Srdivacky#endif 754249423Sdim case TIOCNXCL: 755202375Srdivacky case TIOCSBRK: 756202375Srdivacky case TIOCSCTTY: 757202375Srdivacky case TIOCSDRAINWAIT: 758202375Srdivacky case TIOCSETA: 759210299Sed case TIOCSETAF: 760202375Srdivacky case TIOCSETAW: 761202375Srdivacky case TIOCSETD: 762210299Sed case TIOCSPGRP: 763202375Srdivacky case TIOCSTART: 764202375Srdivacky case TIOCSTAT: 765223017Sdim case TIOCSTI: 766202375Srdivacky case TIOCSTOP: 767249423Sdim case TIOCSWINSZ: 768202375Srdivacky#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 769202375Srdivacky case TIOCLBIC: 770202375Srdivacky case TIOCLBIS: 771223017Sdim case TIOCLSET: 772223017Sdim case TIOCSETC: 773276479Sdim case OTIOCSETD: 774202375Srdivacky case TIOCSETN: 775202375Srdivacky case TIOCSETP: 776280031Sdim case TIOCSLTC: 777202375Srdivacky#endif 778202375Srdivacky sx_slock(&proctree_lock); 779249423Sdim PROC_LOCK(p); 780202375Srdivacky while (isbackground(p, tp) && !(p->p_flag & P_PPWAIT) && 781202375Srdivacky !SIGISMEMBER(p->p_sigacts->ps_sigignore, SIGTTOU) && 782203954Srdivacky !SIGISMEMBER(td->td_sigmask, SIGTTOU)) { 783203954Srdivacky pgrp = p->p_pgrp; 784276479Sdim PROC_UNLOCK(p); 785202375Srdivacky if (pgrp->pg_jobc == 0) { 786202375Srdivacky sx_sunlock(&proctree_lock); 787249423Sdim return (EIO); 788249423Sdim } 789249423Sdim PGRP_LOCK(pgrp); 790249423Sdim sx_sunlock(&proctree_lock); 791249423Sdim pgsignal(pgrp, SIGTTOU, 1); 792249423Sdim PGRP_UNLOCK(pgrp); 793249423Sdim error = ttysleep(tp, &lbolt, TTOPRI | PCATCH, "ttybg1", 794249423Sdim 0); 795249423Sdim if (error) 796249423Sdim return (error); 797249423Sdim sx_slock(&proctree_lock); 798249423Sdim PROC_LOCK(p); 799249423Sdim } 800249423Sdim PROC_UNLOCK(p); 801249423Sdim sx_sunlock(&proctree_lock); 802249423Sdim break; 803249423Sdim } 804249423Sdim 805249423Sdim switch (cmd) { /* Process the ioctl. */ 806202375Srdivacky case FIOASYNC: /* set/clear async i/o */ 807255076Sdim s = spltty(); 808255076Sdim if (*(int *)data) 809255076Sdim SET(tp->t_state, TS_ASYNC); 810276479Sdim else 811249423Sdim CLR(tp->t_state, TS_ASYNC); 812255076Sdim splx(s); 813255076Sdim break; 814255076Sdim case FIONBIO: /* set/clear non-blocking i/o */ 815255076Sdim break; /* XXX: delete. */ 816276479Sdim case FIONREAD: /* get # bytes to read */ 817255076Sdim s = spltty(); 818255076Sdim *(int *)data = ttnread(tp); 819255076Sdim splx(s); 820255076Sdim break; 821249423Sdim 822249423Sdim case FIOSETOWN: 823249423Sdim /* 824249423Sdim * Policy -- Don't allow FIOSETOWN on someone else's 825255076Sdim * controlling tty 826255076Sdim */ 827249423Sdim if (tp->t_session != NULL && !isctty(p, tp)) 828249423Sdim return (ENOTTY); 829249423Sdim 830249423Sdim error = fsetown(*(int *)data, &tp->t_sigio); 831249423Sdim if (error) 832249423Sdim return (error); 833249423Sdim break; 834249423Sdim case FIOGETOWN: 835249423Sdim if (tp->t_session != NULL && !isctty(p, tp)) 836249423Sdim return (ENOTTY); 837249423Sdim *(int *)data = fgetown(&tp->t_sigio); 838249423Sdim break; 839249423Sdim 840249423Sdim case TIOCEXCL: /* set exclusive use of tty */ 841249423Sdim s = spltty(); 842249423Sdim SET(tp->t_state, TS_XCLUDE); 843249423Sdim splx(s); 844249423Sdim break; 845276479Sdim case TIOCFLUSH: { /* flush buffers */ 846249423Sdim int flags = *(int *)data; 847249423Sdim 848249423Sdim if (flags == 0) 849249423Sdim flags = FREAD | FWRITE; 850249423Sdim else 851249423Sdim flags &= FREAD | FWRITE; 852249423Sdim ttyflush(tp, flags); 853249423Sdim break; 854249423Sdim } 855249423Sdim case TIOCCONS: /* become virtual console */ 856249423Sdim if (*(int *)data) { 857249423Sdim struct nameidata nid; 858249423Sdim 859249423Sdim if (constty && constty != tp && 860249423Sdim ISSET(constty->t_state, TS_CONNECTED)) 861249423Sdim return (EBUSY); 862249423Sdim 863249423Sdim /* Ensure user can open the real console. */ 864249423Sdim NDINIT(&nid, LOOKUP, LOCKLEAF | FOLLOW, UIO_SYSSPACE, 865276479Sdim "/dev/console", td); 866249423Sdim if ((error = namei(&nid)) != 0) 867249423Sdim return (error); 868202375Srdivacky NDFREE(&nid, NDF_ONLY_PNBUF); 869202375Srdivacky error = VOP_ACCESS(nid.ni_vp, VREAD, td->td_ucred, td); 870202375Srdivacky vput(nid.ni_vp); 871202375Srdivacky if (error) 872202375Srdivacky return (error); 873202375Srdivacky 874202375Srdivacky constty_set(tp); 875202375Srdivacky } else if (tp == constty) 876202375Srdivacky constty_clear(); 877203954Srdivacky break; 878202375Srdivacky case TIOCDRAIN: /* wait till output drained */ 879202375Srdivacky error = ttywait(tp); 880202375Srdivacky if (error) 881202375Srdivacky return (error); 882202375Srdivacky break; 883202375Srdivacky case TIOCGETA: { /* get termios struct */ 884202375Srdivacky struct termios *t = (struct termios *)data; 885202375Srdivacky 886276479Sdim bcopy(&tp->t_termios, t, sizeof(struct termios)); 887203954Srdivacky break; 888249423Sdim } 889203954Srdivacky case TIOCGETD: /* get line discipline */ 890202375Srdivacky *(int *)data = tp->t_line; 891202375Srdivacky break; 892202375Srdivacky case TIOCGWINSZ: /* get window size */ 893202375Srdivacky *(struct winsize *)data = tp->t_winsize; 894202375Srdivacky break; 895249423Sdim case TIOCGPGRP: /* get pgrp of tty */ 896234353Sdim if (!isctty(p, tp)) 897234353Sdim return (ENOTTY); 898234353Sdim *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 899234353Sdim break; 900234353Sdim#ifdef TIOCHPCL 901276479Sdim case TIOCHPCL: /* hang up on last close */ 902234353Sdim s = spltty(); 903226633Sdim SET(tp->t_cflag, HUPCL); 904202375Srdivacky splx(s); 905249423Sdim break; 906234353Sdim#endif 907234353Sdim case TIOCNXCL: /* reset exclusive use of tty */ 908202375Srdivacky s = spltty(); 909202375Srdivacky CLR(tp->t_state, TS_XCLUDE); 910218893Sdim splx(s); 911234353Sdim break; 912234353Sdim case TIOCOUTQ: /* output queue size */ 913249423Sdim *(int *)data = tp->t_outq.c_cc; 914234353Sdim break; 915276479Sdim case TIOCSETA: /* set termios struct */ 916249423Sdim case TIOCSETAW: /* drain output, set */ 917234353Sdim case TIOCSETAF: { /* drn out, fls in, set */ 918202375Srdivacky struct termios *t = (struct termios *)data; 919218893Sdim 920202375Srdivacky if (t->c_ispeed == 0) 921234353Sdim t->c_ispeed = t->c_ospeed; 922202375Srdivacky if (t->c_ispeed == 0) 923234353Sdim t->c_ispeed = tp->t_ospeed; 924249423Sdim if (t->c_ispeed == 0) 925202375Srdivacky return (EINVAL); 926234353Sdim s = spltty(); 927276479Sdim if (cmd == TIOCSETAW || cmd == TIOCSETAF) { 928203954Srdivacky error = ttywait(tp); 929249423Sdim if (error) { 930202375Srdivacky splx(s); 931202375Srdivacky return (error); 932276479Sdim } 933202375Srdivacky if (cmd == TIOCSETAF) 934223017Sdim ttyflush(tp, FREAD); 935202375Srdivacky } 936202375Srdivacky if (!ISSET(t->c_cflag, CIGNORE)) { 937202375Srdivacky /* 938202375Srdivacky * Set device hardware. 939202375Srdivacky */ 940202375Srdivacky if (tp->t_param && (error = (*tp->t_param)(tp, t))) { 941202375Srdivacky splx(s); 942202375Srdivacky return (error); 943276479Sdim } 944202375Srdivacky if (ISSET(t->c_cflag, CLOCAL) && 945202375Srdivacky !ISSET(tp->t_cflag, CLOCAL)) { 946202375Srdivacky /* 947202375Srdivacky * XXX disconnections would be too hard to 948249423Sdim * get rid of without this kludge. The only 949202375Srdivacky * way to get rid of controlling terminals 950276479Sdim * is to exit from the session leader. 951249423Sdim */ 952202375Srdivacky CLR(tp->t_state, TS_ZOMBIE); 953202375Srdivacky 954202375Srdivacky wakeup(TSA_CARR_ON(tp)); 955202375Srdivacky ttwakeup(tp); 956202375Srdivacky ttwwakeup(tp); 957249423Sdim } 958202375Srdivacky if ((ISSET(tp->t_state, TS_CARR_ON) || 959202375Srdivacky ISSET(t->c_cflag, CLOCAL)) && 960202375Srdivacky !ISSET(tp->t_state, TS_ZOMBIE)) 961202375Srdivacky SET(tp->t_state, TS_CONNECTED); 962276479Sdim else 963202375Srdivacky CLR(tp->t_state, TS_CONNECTED); 964202375Srdivacky tp->t_cflag = t->c_cflag; 965202375Srdivacky tp->t_ispeed = t->c_ispeed; 966288943Sdim if (t->c_ospeed != 0) 967202375Srdivacky tp->t_ospeed = t->c_ospeed; 968202375Srdivacky ttsetwater(tp); 969202375Srdivacky } 970249423Sdim if (ISSET(t->c_lflag, ICANON) != ISSET(tp->t_lflag, ICANON) && 971202375Srdivacky cmd != TIOCSETAF) { 972202375Srdivacky if (ISSET(t->c_lflag, ICANON)) 973202375Srdivacky SET(tp->t_lflag, PENDIN); 974202375Srdivacky else { 975202375Srdivacky /* 976202375Srdivacky * XXX we really shouldn't allow toggling 977202375Srdivacky * ICANON while we're in a non-termios line 978249423Sdim * discipline. Now we have to worry about 979202375Srdivacky * panicing for a null queue. 980202375Srdivacky */ 981202375Srdivacky if (tp->t_canq.c_cbreserved > 0 && 982218893Sdim tp->t_rawq.c_cbreserved > 0) { 983202375Srdivacky catq(&tp->t_rawq, &tp->t_canq); 984288943Sdim /* 985202375Srdivacky * XXX the queue limits may be 986202375Srdivacky * different, so the old queue 987202375Srdivacky * swapping method no longer works. 988218893Sdim */ 989202375Srdivacky catq(&tp->t_canq, &tp->t_rawq); 990202375Srdivacky } 991202375Srdivacky CLR(tp->t_lflag, PENDIN); 992202375Srdivacky } 993202375Srdivacky ttwakeup(tp); 994202375Srdivacky } 995202375Srdivacky tp->t_iflag = t->c_iflag; 996202375Srdivacky tp->t_oflag = t->c_oflag; 997202375Srdivacky /* 998202375Srdivacky * Make the EXTPROC bit read only. 999202375Srdivacky */ 1000202375Srdivacky if (ISSET(tp->t_lflag, EXTPROC)) 1001202375Srdivacky SET(t->c_lflag, EXTPROC); 1002202375Srdivacky else 1003218893Sdim CLR(t->c_lflag, EXTPROC); 1004202375Srdivacky tp->t_lflag = t->c_lflag | ISSET(tp->t_lflag, PENDIN); 1005218893Sdim if (t->c_cc[VMIN] != tp->t_cc[VMIN] || 1006202375Srdivacky t->c_cc[VTIME] != tp->t_cc[VTIME]) 1007202375Srdivacky ttwakeup(tp); 1008202375Srdivacky bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc)); 1009202375Srdivacky splx(s); 1010202375Srdivacky break; 1011202375Srdivacky } 1012288943Sdim case TIOCSETD: { /* set line discipline */ 1013202375Srdivacky int t = *(int *)data; 1014202375Srdivacky dev_t device = tp->t_dev; 1015202375Srdivacky 1016202375Srdivacky if ((u_int)t >= nlinesw) 1017288943Sdim return (ENXIO); 1018202375Srdivacky if (t != tp->t_line) { 1019202375Srdivacky s = spltty(); 1020202375Srdivacky (*linesw[tp->t_line].l_close)(tp, flag); 1021202375Srdivacky error = (*linesw[t].l_open)(device, tp); 1022202375Srdivacky if (error) { 1023202375Srdivacky (void)(*linesw[tp->t_line].l_open)(device, tp); 1024218893Sdim splx(s); 1025226633Sdim return (error); 1026226633Sdim } 1027226633Sdim tp->t_line = t; 1028202375Srdivacky splx(s); 1029202375Srdivacky } 1030202375Srdivacky break; 1031218893Sdim } 1032202375Srdivacky case TIOCSTART: /* start output, like ^Q */ 1033202375Srdivacky s = spltty(); 1034202375Srdivacky if (ISSET(tp->t_state, TS_TTSTOP) || 1035202375Srdivacky ISSET(tp->t_lflag, FLUSHO)) { 1036218893Sdim CLR(tp->t_lflag, FLUSHO); 1037202375Srdivacky CLR(tp->t_state, TS_TTSTOP); 1038202375Srdivacky ttstart(tp); 1039202375Srdivacky } 1040202375Srdivacky splx(s); 1041202375Srdivacky break; 1042202375Srdivacky case TIOCSTI: /* simulate terminal input */ 1043234353Sdim if ((flag & FREAD) == 0 && suser(td)) 1044202375Srdivacky return (EPERM); 1045202375Srdivacky if (!isctty(p, tp) && suser(td)) 1046202375Srdivacky return (EACCES); 1047202375Srdivacky s = spltty(); 1048202375Srdivacky (*linesw[tp->t_line].l_rint)(*(u_char *)data, tp); 1049202375Srdivacky splx(s); 1050202375Srdivacky break; 1051202375Srdivacky case TIOCSTOP: /* stop output, like ^S */ 1052202375Srdivacky s = spltty(); 1053202375Srdivacky if (!ISSET(tp->t_state, TS_TTSTOP)) { 1054202375Srdivacky SET(tp->t_state, TS_TTSTOP); 1055202375Srdivacky (*tp->t_stop)(tp, 0); 1056239462Sdim } 1057239462Sdim splx(s); 1058239462Sdim break; 1059239462Sdim case TIOCSCTTY: /* become controlling tty */ 1060296417Sdim /* Session ctty vnode pointer set in vnode layer. */ 1061296417Sdim sx_slock(&proctree_lock); 1062296417Sdim if (!SESS_LEADER(p) || 1063296417Sdim ((p->p_session->s_ttyvp || tp->t_session) && 1064296417Sdim (tp->t_session != p->p_session))) { 1065296417Sdim sx_sunlock(&proctree_lock); 1066296417Sdim return (EPERM); 1067239462Sdim } 1068239462Sdim tp->t_session = p->p_session; 1069239462Sdim tp->t_pgrp = p->p_pgrp; 1070239462Sdim SESS_LOCK(p->p_session); 1071239462Sdim p->p_session->s_ttyp = tp; 1072239462Sdim SESS_UNLOCK(p->p_session); 1073288943Sdim PROC_LOCK(p); 1074288943Sdim p->p_flag |= P_CONTROLT; 1075239462Sdim PROC_UNLOCK(p); 1076239462Sdim sx_sunlock(&proctree_lock); 1077239462Sdim break; 1078288943Sdim case TIOCSPGRP: { /* set pgrp of tty */ 1079239462Sdim sx_slock(&proctree_lock); 1080249423Sdim pgrp = pgfind(*(int *)data); 1081239462Sdim if (!isctty(p, tp)) { 1082239462Sdim if (pgrp != NULL) 1083239462Sdim PGRP_UNLOCK(pgrp); 1084239462Sdim sx_sunlock(&proctree_lock); 1085202375Srdivacky return (ENOTTY); 1086202375Srdivacky } 1087226633Sdim if (pgrp == NULL) { 1088202375Srdivacky sx_sunlock(&proctree_lock); 1089202375Srdivacky return (EPERM); 1090202375Srdivacky } 1091296417Sdim PGRP_UNLOCK(pgrp); 1092202375Srdivacky if (pgrp->pg_session != p->p_session) { 1093202375Srdivacky sx_sunlock(&proctree_lock); 1094202375Srdivacky return (EPERM); 1095202375Srdivacky } 1096202375Srdivacky sx_sunlock(&proctree_lock); 1097202375Srdivacky tp->t_pgrp = pgrp; 1098202375Srdivacky break; 1099296417Sdim } 1100296417Sdim case TIOCSTAT: /* simulate control-T */ 1101296417Sdim s = spltty(); 1102296417Sdim ttyinfo(tp); 1103296417Sdim splx(s); 1104296417Sdim break; 1105202375Srdivacky case TIOCSWINSZ: /* set window size */ 1106296417Sdim if (bcmp((caddr_t)&tp->t_winsize, data, 1107296417Sdim sizeof (struct winsize))) { 1108296417Sdim tp->t_winsize = *(struct winsize *)data; 1109296417Sdim if (tp->t_pgrp != NULL) { 1110296417Sdim PGRP_LOCK(tp->t_pgrp); 1111296417Sdim pgsignal(tp->t_pgrp, SIGWINCH, 1); 1112296417Sdim PGRP_UNLOCK(tp->t_pgrp); 1113296417Sdim } 1114296417Sdim } 1115202375Srdivacky break; 1116296417Sdim case TIOCSDRAINWAIT: 1117202375Srdivacky error = suser(td); 1118202375Srdivacky if (error) 1119249423Sdim return (error); 1120202375Srdivacky tp->t_timeout = *(int *)data * hz; 1121202375Srdivacky wakeup(TSA_OCOMPLETE(tp)); 1122288943Sdim wakeup(TSA_OLOWAT(tp)); 1123202375Srdivacky break; 1124202375Srdivacky case TIOCGDRAINWAIT: 1125202375Srdivacky *(int *)data = tp->t_timeout / hz; 1126202375Srdivacky break; 1127249423Sdim default: 1128296417Sdim#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 1129296417Sdim return (ttcompat(tp, cmd, data, flag)); 1130296417Sdim#else 1131296417Sdim return (ENOIOCTL); 1132296417Sdim#endif 1133296417Sdim } 1134202375Srdivacky return (0); 1135296417Sdim} 1136218893Sdim 1137296417Sdimint 1138296417Sdimttypoll(dev_t dev, int events, struct thread *td) 1139296417Sdim{ 1140296417Sdim int s; 1141296417Sdim int revents = 0; 1142296417Sdim struct tty *tp; 1143296417Sdim 1144296417Sdim tp = dev->si_tty; 1145296417Sdim if (tp == NULL) /* XXX used to return ENXIO, but that means true! */ 1146296417Sdim return ((events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)) 1147202375Srdivacky | POLLHUP); 1148202375Srdivacky 1149202375Srdivacky s = spltty(); 1150202375Srdivacky if (events & (POLLIN | POLLRDNORM)) { 1151202375Srdivacky if (ttnread(tp) > 0 || ISSET(tp->t_state, TS_ZOMBIE)) 1152202375Srdivacky revents |= events & (POLLIN | POLLRDNORM); 1153202375Srdivacky else 1154202375Srdivacky selrecord(td, &tp->t_rsel); 1155202375Srdivacky } 1156202375Srdivacky if (events & (POLLOUT | POLLWRNORM)) { 1157202375Srdivacky if ((tp->t_outq.c_cc <= tp->t_olowat && 1158288943Sdim ISSET(tp->t_state, TS_CONNECTED)) 1159288943Sdim || ISSET(tp->t_state, TS_ZOMBIE)) 1160202375Srdivacky revents |= events & (POLLOUT | POLLWRNORM); 1161202375Srdivacky else 1162288943Sdim selrecord(td, &tp->t_wsel); 1163202375Srdivacky } 1164249423Sdim splx(s); 1165202375Srdivacky return (revents); 1166202375Srdivacky} 1167202375Srdivacky 1168202375Srdivackystatic struct filterops ttyread_filtops = 1169239462Sdim { 1, NULL, filt_ttyrdetach, filt_ttyread }; 1170239462Sdimstatic struct filterops ttywrite_filtops = 1171288943Sdim { 1, NULL, filt_ttywdetach, filt_ttywrite }; 1172288943Sdim 1173239462Sdimint 1174239462Sdimttykqfilter(dev_t dev, struct knote *kn) 1175249423Sdim{ 1176202375Srdivacky struct tty *tp = dev->si_tty; 1177202375Srdivacky struct klist *klist; 1178202375Srdivacky int s; 1179202375Srdivacky 1180202375Srdivacky switch (kn->kn_filter) { 1181249423Sdim case EVFILT_READ: 1182202375Srdivacky klist = &tp->t_rsel.si_note; 1183202375Srdivacky kn->kn_fop = &ttyread_filtops; 1184202375Srdivacky break; 1185202375Srdivacky case EVFILT_WRITE: 1186202375Srdivacky klist = &tp->t_wsel.si_note; 1187202375Srdivacky kn->kn_fop = &ttywrite_filtops; 1188202375Srdivacky break; 1189202375Srdivacky default: 1190202375Srdivacky return (1); 1191202375Srdivacky } 1192210299Sed 1193288943Sdim kn->kn_hook = (caddr_t)dev; 1194210299Sed 1195210299Sed s = spltty(); 1196288943Sdim SLIST_INSERT_HEAD(klist, kn, kn_selnext); 1197210299Sed splx(s); 1198202375Srdivacky 1199202375Srdivacky return (0); 1200202375Srdivacky} 1201202375Srdivacky 1202202375Srdivackystatic void 1203202375Srdivackyfilt_ttyrdetach(struct knote *kn) 1204202375Srdivacky{ 1205202375Srdivacky struct tty *tp = ((dev_t)kn->kn_hook)->si_tty; 1206202375Srdivacky int s = spltty(); 1207202375Srdivacky 1208202375Srdivacky SLIST_REMOVE(&tp->t_rsel.si_note, kn, knote, kn_selnext); 1209210299Sed splx(s); 1210210299Sed} 1211202375Srdivacky 1212249423Sdimstatic int 1213202375Srdivackyfilt_ttyread(struct knote *kn, long hint) 1214223017Sdim{ 1215202375Srdivacky struct tty *tp = ((dev_t)kn->kn_hook)->si_tty; 1216249423Sdim 1217202375Srdivacky kn->kn_data = ttnread(tp); 1218202375Srdivacky if (ISSET(tp->t_state, TS_ZOMBIE)) { 1219202375Srdivacky kn->kn_flags |= EV_EOF; 1220202375Srdivacky return (1); 1221223017Sdim } 1222202375Srdivacky return (kn->kn_data > 0); 1223202375Srdivacky} 1224202375Srdivacky 1225202375Srdivackystatic void 1226223017Sdimfilt_ttywdetach(struct knote *kn) 1227202375Srdivacky{ 1228202375Srdivacky struct tty *tp = ((dev_t)kn->kn_hook)->si_tty; 1229202375Srdivacky int s = spltty(); 1230249423Sdim 1231202375Srdivacky SLIST_REMOVE(&tp->t_wsel.si_note, kn, knote, kn_selnext); 1232202375Srdivacky splx(s); 1233202375Srdivacky} 1234202375Srdivacky 1235202375Srdivackystatic int 1236223017Sdimfilt_ttywrite(struct knote *kn, long hint) 1237202375Srdivacky{ 1238249423Sdim struct tty *tp = ((dev_t)kn->kn_hook)->si_tty; 1239202375Srdivacky 1240249423Sdim kn->kn_data = tp->t_outq.c_cc; 1241202375Srdivacky if (ISSET(tp->t_state, TS_ZOMBIE)) 1242202375Srdivacky return (1); 1243202375Srdivacky return (kn->kn_data <= tp->t_olowat && 1244202375Srdivacky ISSET(tp->t_state, TS_CONNECTED)); 1245296417Sdim} 1246296417Sdim 1247296417Sdim/* 1248296417Sdim * Must be called at spltty(). 1249296417Sdim */ 1250296417Sdimstatic int 1251296417Sdimttnread(struct tty *tp) 1252296417Sdim{ 1253296417Sdim int nread; 1254202375Srdivacky 1255202375Srdivacky if (ISSET(tp->t_lflag, PENDIN)) 1256202375Srdivacky ttypend(tp); 1257202375Srdivacky nread = tp->t_canq.c_cc; 1258276479Sdim if (!ISSET(tp->t_lflag, ICANON)) { 1259202375Srdivacky nread += tp->t_rawq.c_cc; 1260 if (nread < tp->t_cc[VMIN] && tp->t_cc[VTIME] == 0) 1261 nread = 0; 1262 } 1263 return (nread); 1264} 1265 1266/* 1267 * Wait for output to drain. 1268 */ 1269int 1270ttywait(struct tty *tp) 1271{ 1272 int error, s; 1273 1274 error = 0; 1275 s = spltty(); 1276 while ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) && 1277 ISSET(tp->t_state, TS_CONNECTED) && tp->t_oproc) { 1278 (*tp->t_oproc)(tp); 1279 if ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) && 1280 ISSET(tp->t_state, TS_CONNECTED)) { 1281 SET(tp->t_state, TS_SO_OCOMPLETE); 1282 error = ttysleep(tp, TSA_OCOMPLETE(tp), 1283 TTOPRI | PCATCH, "ttywai", 1284 tp->t_timeout); 1285 if (error) { 1286 if (error == EWOULDBLOCK) 1287 error = EIO; 1288 break; 1289 } 1290 } else 1291 break; 1292 } 1293 if (!error && (tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY))) 1294 error = EIO; 1295 splx(s); 1296 return (error); 1297} 1298 1299/* 1300 * Flush if successfully wait. 1301 */ 1302static int 1303ttywflush(struct tty *tp) 1304{ 1305 int error; 1306 1307 if ((error = ttywait(tp)) == 0) 1308 ttyflush(tp, FREAD); 1309 return (error); 1310} 1311 1312/* 1313 * Flush tty read and/or write queues, notifying anyone waiting. 1314 */ 1315void 1316ttyflush(struct tty *tp, int rw) 1317{ 1318 int s; 1319 1320 s = spltty(); 1321#if 0 1322again: 1323#endif 1324 if (rw & FWRITE) { 1325 FLUSHQ(&tp->t_outq); 1326 CLR(tp->t_state, TS_TTSTOP); 1327 } 1328 (*tp->t_stop)(tp, rw); 1329 if (rw & FREAD) { 1330 FLUSHQ(&tp->t_canq); 1331 FLUSHQ(&tp->t_rawq); 1332 CLR(tp->t_lflag, PENDIN); 1333 tp->t_rocount = 0; 1334 tp->t_rocol = 0; 1335 CLR(tp->t_state, TS_LOCAL); 1336 ttwakeup(tp); 1337 if (ISSET(tp->t_state, TS_TBLOCK)) { 1338 if (rw & FWRITE) 1339 FLUSHQ(&tp->t_outq); 1340 ttyunblock(tp); 1341 1342 /* 1343 * Don't let leave any state that might clobber the 1344 * next line discipline (although we should do more 1345 * to send the START char). Not clearing the state 1346 * may have caused the "putc to a clist with no 1347 * reserved cblocks" panic/printf. 1348 */ 1349 CLR(tp->t_state, TS_TBLOCK); 1350 1351#if 0 /* forget it, sleeping isn't always safe and we don't know when it is */ 1352 if (ISSET(tp->t_iflag, IXOFF)) { 1353 /* 1354 * XXX wait a bit in the hope that the stop 1355 * character (if any) will go out. Waiting 1356 * isn't good since it allows races. This 1357 * will be fixed when the stop character is 1358 * put in a special queue. Don't bother with 1359 * the checks in ttywait() since the timeout 1360 * will save us. 1361 */ 1362 SET(tp->t_state, TS_SO_OCOMPLETE); 1363 ttysleep(tp, TSA_OCOMPLETE(tp), TTOPRI, 1364 "ttyfls", hz / 10); 1365 /* 1366 * Don't try sending the stop character again. 1367 */ 1368 CLR(tp->t_state, TS_TBLOCK); 1369 goto again; 1370 } 1371#endif 1372 } 1373 } 1374 if (rw & FWRITE) { 1375 FLUSHQ(&tp->t_outq); 1376 ttwwakeup(tp); 1377 } 1378 splx(s); 1379} 1380 1381/* 1382 * Copy in the default termios characters. 1383 */ 1384void 1385termioschars(struct termios *t) 1386{ 1387 1388 bcopy(ttydefchars, t->c_cc, sizeof t->c_cc); 1389} 1390 1391/* 1392 * Old interface. 1393 */ 1394void 1395ttychars(struct tty *tp) 1396{ 1397 1398 termioschars(&tp->t_termios); 1399} 1400 1401/* 1402 * Handle input high water. Send stop character for the IXOFF case. Turn 1403 * on our input flow control bit and propagate the changes to the driver. 1404 * XXX the stop character should be put in a special high priority queue. 1405 */ 1406void 1407ttyblock(struct tty *tp) 1408{ 1409 1410 SET(tp->t_state, TS_TBLOCK); 1411 if (ISSET(tp->t_iflag, IXOFF) && tp->t_cc[VSTOP] != _POSIX_VDISABLE && 1412 putc(tp->t_cc[VSTOP], &tp->t_outq) != 0) 1413 CLR(tp->t_state, TS_TBLOCK); /* try again later */ 1414 ttstart(tp); 1415} 1416 1417/* 1418 * Handle input low water. Send start character for the IXOFF case. Turn 1419 * off our input flow control bit and propagate the changes to the driver. 1420 * XXX the start character should be put in a special high priority queue. 1421 */ 1422static void 1423ttyunblock(struct tty *tp) 1424{ 1425 1426 CLR(tp->t_state, TS_TBLOCK); 1427 if (ISSET(tp->t_iflag, IXOFF) && tp->t_cc[VSTART] != _POSIX_VDISABLE && 1428 putc(tp->t_cc[VSTART], &tp->t_outq) != 0) 1429 SET(tp->t_state, TS_TBLOCK); /* try again later */ 1430 ttstart(tp); 1431} 1432 1433#ifdef notyet 1434/* Not used by any current (i386) drivers. */ 1435/* 1436 * Restart after an inter-char delay. 1437 */ 1438void 1439ttrstrt(void *tp_arg) 1440{ 1441 struct tty *tp; 1442 int s; 1443 1444 KASSERT(tp_arg != NULL, ("ttrstrt")); 1445 1446 tp = tp_arg; 1447 s = spltty(); 1448 1449 CLR(tp->t_state, TS_TIMEOUT); 1450 ttstart(tp); 1451 1452 splx(s); 1453} 1454#endif 1455 1456int 1457ttstart(struct tty *tp) 1458{ 1459 1460 if (tp->t_oproc != NULL) /* XXX: Kludge for pty. */ 1461 (*tp->t_oproc)(tp); 1462 return (0); 1463} 1464 1465/* 1466 * "close" a line discipline 1467 */ 1468int 1469ttylclose(struct tty *tp, int flag) 1470{ 1471 1472 if (flag & FNONBLOCK || ttywflush(tp)) 1473 ttyflush(tp, FREAD | FWRITE); 1474 return (0); 1475} 1476 1477/* 1478 * Handle modem control transition on a tty. 1479 * Flag indicates new state of carrier. 1480 * Returns 0 if the line should be turned off, otherwise 1. 1481 */ 1482int 1483ttymodem(struct tty *tp, int flag) 1484{ 1485 1486 if (ISSET(tp->t_state, TS_CARR_ON) && ISSET(tp->t_cflag, MDMBUF)) { 1487 /* 1488 * MDMBUF: do flow control according to carrier flag 1489 * XXX TS_CAR_OFLOW doesn't do anything yet. TS_TTSTOP 1490 * works if IXON and IXANY are clear. 1491 */ 1492 if (flag) { 1493 CLR(tp->t_state, TS_CAR_OFLOW); 1494 CLR(tp->t_state, TS_TTSTOP); 1495 ttstart(tp); 1496 } else if (!ISSET(tp->t_state, TS_CAR_OFLOW)) { 1497 SET(tp->t_state, TS_CAR_OFLOW); 1498 SET(tp->t_state, TS_TTSTOP); 1499 (*tp->t_stop)(tp, 0); 1500 } 1501 } else if (flag == 0) { 1502 /* 1503 * Lost carrier. 1504 */ 1505 CLR(tp->t_state, TS_CARR_ON); 1506 if (ISSET(tp->t_state, TS_ISOPEN) && 1507 !ISSET(tp->t_cflag, CLOCAL)) { 1508 SET(tp->t_state, TS_ZOMBIE); 1509 CLR(tp->t_state, TS_CONNECTED); 1510 if (tp->t_session) { 1511 sx_slock(&proctree_lock); 1512 if (tp->t_session->s_leader) { 1513 struct proc *p; 1514 1515 p = tp->t_session->s_leader; 1516 PROC_LOCK(p); 1517 psignal(p, SIGHUP); 1518 PROC_UNLOCK(p); 1519 } 1520 sx_sunlock(&proctree_lock); 1521 } 1522 ttyflush(tp, FREAD | FWRITE); 1523 return (0); 1524 } 1525 } else { 1526 /* 1527 * Carrier now on. 1528 */ 1529 SET(tp->t_state, TS_CARR_ON); 1530 if (!ISSET(tp->t_state, TS_ZOMBIE)) 1531 SET(tp->t_state, TS_CONNECTED); 1532 wakeup(TSA_CARR_ON(tp)); 1533 ttwakeup(tp); 1534 ttwwakeup(tp); 1535 } 1536 return (1); 1537} 1538 1539/* 1540 * Reinput pending characters after state switch 1541 * call at spltty(). 1542 */ 1543static void 1544ttypend(struct tty *tp) 1545{ 1546 struct clist tq; 1547 int c; 1548 1549 CLR(tp->t_lflag, PENDIN); 1550 SET(tp->t_state, TS_TYPEN); 1551 /* 1552 * XXX this assumes too much about clist internals. It may even 1553 * fail if the cblock slush pool is empty. We can't allocate more 1554 * cblocks here because we are called from an interrupt handler 1555 * and clist_alloc_cblocks() can wait. 1556 */ 1557 tq = tp->t_rawq; 1558 bzero(&tp->t_rawq, sizeof tp->t_rawq); 1559 tp->t_rawq.c_cbmax = tq.c_cbmax; 1560 tp->t_rawq.c_cbreserved = tq.c_cbreserved; 1561 while ((c = getc(&tq)) >= 0) 1562 ttyinput(c, tp); 1563 CLR(tp->t_state, TS_TYPEN); 1564} 1565 1566/* 1567 * Process a read call on a tty device. 1568 */ 1569int 1570ttread(struct tty *tp, struct uio *uio, int flag) 1571{ 1572 struct clist *qp; 1573 int c; 1574 tcflag_t lflag; 1575 cc_t *cc = tp->t_cc; 1576 struct thread *td; 1577 struct proc *p; 1578 int s, first, error = 0; 1579 int has_stime = 0, last_cc = 0; 1580 long slp = 0; /* XXX this should be renamed `timo'. */ 1581 struct timeval stime; 1582 struct pgrp *pg; 1583 1584 td = curthread; 1585 p = td->td_proc; 1586loop: 1587 s = spltty(); 1588 lflag = tp->t_lflag; 1589 /* 1590 * take pending input first 1591 */ 1592 if (ISSET(lflag, PENDIN)) { 1593 ttypend(tp); 1594 splx(s); /* reduce latency */ 1595 s = spltty(); 1596 lflag = tp->t_lflag; /* XXX ttypend() clobbers it */ 1597 } 1598 1599 /* 1600 * Hang process if it's in the background. 1601 */ 1602 if (isbackground(p, tp)) { 1603 splx(s); 1604 sx_slock(&proctree_lock); 1605 PROC_LOCK(p); 1606 if (SIGISMEMBER(p->p_sigacts->ps_sigignore, SIGTTIN) || 1607 SIGISMEMBER(td->td_sigmask, SIGTTIN) || 1608 (p->p_flag & P_PPWAIT) || p->p_pgrp->pg_jobc == 0) { 1609 PROC_UNLOCK(p); 1610 sx_sunlock(&proctree_lock); 1611 return (EIO); 1612 } 1613 pg = p->p_pgrp; 1614 PROC_UNLOCK(p); 1615 PGRP_LOCK(pg); 1616 sx_sunlock(&proctree_lock); 1617 pgsignal(pg, SIGTTIN, 1); 1618 PGRP_UNLOCK(pg); 1619 error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, "ttybg2", 0); 1620 if (error) 1621 return (error); 1622 goto loop; 1623 } 1624 1625 if (ISSET(tp->t_state, TS_ZOMBIE)) { 1626 splx(s); 1627 return (0); /* EOF */ 1628 } 1629 1630 /* 1631 * If canonical, use the canonical queue, 1632 * else use the raw queue. 1633 * 1634 * (should get rid of clists...) 1635 */ 1636 qp = ISSET(lflag, ICANON) ? &tp->t_canq : &tp->t_rawq; 1637 1638 if (flag & IO_NDELAY) { 1639 if (qp->c_cc > 0) 1640 goto read; 1641 if (!ISSET(lflag, ICANON) && cc[VMIN] == 0) { 1642 splx(s); 1643 return (0); 1644 } 1645 splx(s); 1646 return (EWOULDBLOCK); 1647 } 1648 if (!ISSET(lflag, ICANON)) { 1649 int m = cc[VMIN]; 1650 long t = cc[VTIME]; 1651 struct timeval timecopy; 1652 1653 /* 1654 * Check each of the four combinations. 1655 * (m > 0 && t == 0) is the normal read case. 1656 * It should be fairly efficient, so we check that and its 1657 * companion case (m == 0 && t == 0) first. 1658 * For the other two cases, we compute the target sleep time 1659 * into slp. 1660 */ 1661 if (t == 0) { 1662 if (qp->c_cc < m) 1663 goto sleep; 1664 if (qp->c_cc > 0) 1665 goto read; 1666 1667 /* m, t and qp->c_cc are all 0. 0 is enough input. */ 1668 splx(s); 1669 return (0); 1670 } 1671 t *= 100000; /* time in us */ 1672#define diff(t1, t2) (((t1).tv_sec - (t2).tv_sec) * 1000000 + \ 1673 ((t1).tv_usec - (t2).tv_usec)) 1674 if (m > 0) { 1675 if (qp->c_cc <= 0) 1676 goto sleep; 1677 if (qp->c_cc >= m) 1678 goto read; 1679 getmicrotime(&timecopy); 1680 if (!has_stime) { 1681 /* first character, start timer */ 1682 has_stime = 1; 1683 stime = timecopy; 1684 slp = t; 1685 } else if (qp->c_cc > last_cc) { 1686 /* got a character, restart timer */ 1687 stime = timecopy; 1688 slp = t; 1689 } else { 1690 /* nothing, check expiration */ 1691 slp = t - diff(timecopy, stime); 1692 if (slp <= 0) 1693 goto read; 1694 } 1695 last_cc = qp->c_cc; 1696 } else { /* m == 0 */ 1697 if (qp->c_cc > 0) 1698 goto read; 1699 getmicrotime(&timecopy); 1700 if (!has_stime) { 1701 has_stime = 1; 1702 stime = timecopy; 1703 slp = t; 1704 } else { 1705 slp = t - diff(timecopy, stime); 1706 if (slp <= 0) { 1707 /* Timed out, but 0 is enough input. */ 1708 splx(s); 1709 return (0); 1710 } 1711 } 1712 } 1713#undef diff 1714 /* 1715 * Rounding down may make us wake up just short 1716 * of the target, so we round up. 1717 * The formula is ceiling(slp * hz/1000000). 1718 * 32-bit arithmetic is enough for hz < 169. 1719 * XXX see tvtohz() for how to avoid overflow if hz 1720 * is large (divide by `tick' and/or arrange to 1721 * use tvtohz() if hz is large). 1722 */ 1723 slp = (long) (((u_long)slp * hz) + 999999) / 1000000; 1724 goto sleep; 1725 } 1726 if (qp->c_cc <= 0) { 1727sleep: 1728 /* 1729 * There is no input, or not enough input and we can block. 1730 */ 1731 error = ttysleep(tp, TSA_HUP_OR_INPUT(tp), TTIPRI | PCATCH, 1732 ISSET(tp->t_state, TS_CONNECTED) ? 1733 "ttyin" : "ttyhup", (int)slp); 1734 splx(s); 1735 if (error == EWOULDBLOCK) 1736 error = 0; 1737 else if (error) 1738 return (error); 1739 /* 1740 * XXX what happens if another process eats some input 1741 * while we are asleep (not just here)? It would be 1742 * safest to detect changes and reset our state variables 1743 * (has_stime and last_cc). 1744 */ 1745 slp = 0; 1746 goto loop; 1747 } 1748read: 1749 splx(s); 1750 /* 1751 * Input present, check for input mapping and processing. 1752 */ 1753 first = 1; 1754 if (ISSET(lflag, ICANON | ISIG)) 1755 goto slowcase; 1756 for (;;) { 1757 char ibuf[IBUFSIZ]; 1758 int icc; 1759 1760 icc = imin(uio->uio_resid, IBUFSIZ); 1761 icc = q_to_b(qp, ibuf, icc); 1762 if (icc <= 0) { 1763 if (first) 1764 goto loop; 1765 break; 1766 } 1767 error = uiomove(ibuf, icc, uio); 1768 /* 1769 * XXX if there was an error then we should ungetc() the 1770 * unmoved chars and reduce icc here. 1771 */ 1772 if (error) 1773 break; 1774 if (uio->uio_resid == 0) 1775 break; 1776 first = 0; 1777 } 1778 goto out; 1779slowcase: 1780 for (;;) { 1781 c = getc(qp); 1782 if (c < 0) { 1783 if (first) 1784 goto loop; 1785 break; 1786 } 1787 /* 1788 * delayed suspend (^Y) 1789 */ 1790 if (CCEQ(cc[VDSUSP], c) && 1791 ISSET(lflag, IEXTEN | ISIG) == (IEXTEN | ISIG)) { 1792 if (tp->t_pgrp != NULL) { 1793 PGRP_LOCK(tp->t_pgrp); 1794 pgsignal(tp->t_pgrp, SIGTSTP, 1); 1795 PGRP_UNLOCK(tp->t_pgrp); 1796 } 1797 if (first) { 1798 error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, 1799 "ttybg3", 0); 1800 if (error) 1801 break; 1802 goto loop; 1803 } 1804 break; 1805 } 1806 /* 1807 * Interpret EOF only in canonical mode. 1808 */ 1809 if (CCEQ(cc[VEOF], c) && ISSET(lflag, ICANON)) 1810 break; 1811 /* 1812 * Give user character. 1813 */ 1814 error = ureadc(c, uio); 1815 if (error) 1816 /* XXX should ungetc(c, qp). */ 1817 break; 1818 if (uio->uio_resid == 0) 1819 break; 1820 /* 1821 * In canonical mode check for a "break character" 1822 * marking the end of a "line of input". 1823 */ 1824 if (ISSET(lflag, ICANON) && TTBREAKC(c, lflag)) 1825 break; 1826 first = 0; 1827 } 1828 1829out: 1830 /* 1831 * Look to unblock input now that (presumably) 1832 * the input queue has gone down. 1833 */ 1834 s = spltty(); 1835 if (ISSET(tp->t_state, TS_TBLOCK) && 1836 tp->t_rawq.c_cc + tp->t_canq.c_cc <= tp->t_ilowat) 1837 ttyunblock(tp); 1838 splx(s); 1839 1840 return (error); 1841} 1842 1843/* 1844 * Check the output queue on tp for space for a kernel message (from uprintf 1845 * or tprintf). Allow some space over the normal hiwater mark so we don't 1846 * lose messages due to normal flow control, but don't let the tty run amok. 1847 * Sleeps here are not interruptible, but we return prematurely if new signals 1848 * arrive. 1849 */ 1850int 1851ttycheckoutq(struct tty *tp, int wait) 1852{ 1853 int hiwat, s; 1854 sigset_t oldmask; 1855 struct thread *td; 1856 struct proc *p; 1857 1858 td = curthread; 1859 p = td->td_proc; 1860 hiwat = tp->t_ohiwat; 1861 SIGEMPTYSET(oldmask); 1862 s = spltty(); 1863 if (wait) { 1864 PROC_LOCK(p); 1865 oldmask = td->td_siglist; 1866 PROC_UNLOCK(p); 1867 } 1868 if (tp->t_outq.c_cc > hiwat + OBUFSIZ + 100) 1869 while (tp->t_outq.c_cc > hiwat) { 1870 ttstart(tp); 1871 if (tp->t_outq.c_cc <= hiwat) 1872 break; 1873 if (!wait) { 1874 splx(s); 1875 return (0); 1876 } 1877 PROC_LOCK(p); 1878 if (!SIGSETEQ(td->td_siglist, oldmask)) { 1879 PROC_UNLOCK(p); 1880 splx(s); 1881 return (0); 1882 } 1883 PROC_UNLOCK(p); 1884 SET(tp->t_state, TS_SO_OLOWAT); 1885 tsleep(TSA_OLOWAT(tp), PZERO - 1, "ttoutq", hz); 1886 } 1887 splx(s); 1888 return (1); 1889} 1890 1891/* 1892 * Process a write call on a tty device. 1893 */ 1894int 1895ttwrite(struct tty *tp, struct uio *uio, int flag) 1896{ 1897 char *cp = NULL; 1898 int cc, ce; 1899 struct thread *td; 1900 struct proc *p; 1901 int i, hiwat, cnt, error, s; 1902 char obuf[OBUFSIZ]; 1903 1904 hiwat = tp->t_ohiwat; 1905 cnt = uio->uio_resid; 1906 error = 0; 1907 cc = 0; 1908 td = curthread; 1909 p = td->td_proc; 1910loop: 1911 s = spltty(); 1912 if (ISSET(tp->t_state, TS_ZOMBIE)) { 1913 splx(s); 1914 if (uio->uio_resid == cnt) 1915 error = EIO; 1916 goto out; 1917 } 1918 if (!ISSET(tp->t_state, TS_CONNECTED)) { 1919 if (flag & IO_NDELAY) { 1920 splx(s); 1921 error = EWOULDBLOCK; 1922 goto out; 1923 } 1924 error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH, 1925 "ttydcd", 0); 1926 splx(s); 1927 if (error) 1928 goto out; 1929 goto loop; 1930 } 1931 splx(s); 1932 /* 1933 * Hang the process if it's in the background. 1934 */ 1935 sx_slock(&proctree_lock); 1936 PROC_LOCK(p); 1937 if (isbackground(p, tp) && 1938 ISSET(tp->t_lflag, TOSTOP) && !(p->p_flag & P_PPWAIT) && 1939 !SIGISMEMBER(p->p_sigacts->ps_sigignore, SIGTTOU) && 1940 !SIGISMEMBER(td->td_sigmask, SIGTTOU)) { 1941 if (p->p_pgrp->pg_jobc == 0) { 1942 PROC_UNLOCK(p); 1943 sx_sunlock(&proctree_lock); 1944 error = EIO; 1945 goto out; 1946 } 1947 PROC_UNLOCK(p); 1948 PGRP_LOCK(p->p_pgrp); 1949 sx_sunlock(&proctree_lock); 1950 pgsignal(p->p_pgrp, SIGTTOU, 1); 1951 PGRP_UNLOCK(p->p_pgrp); 1952 error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, "ttybg4", 0); 1953 if (error) 1954 goto out; 1955 goto loop; 1956 } else { 1957 PROC_UNLOCK(p); 1958 sx_sunlock(&proctree_lock); 1959 } 1960 /* 1961 * Process the user's data in at most OBUFSIZ chunks. Perform any 1962 * output translation. Keep track of high water mark, sleep on 1963 * overflow awaiting device aid in acquiring new space. 1964 */ 1965 while (uio->uio_resid > 0 || cc > 0) { 1966 if (ISSET(tp->t_lflag, FLUSHO)) { 1967 uio->uio_resid = 0; 1968 return (0); 1969 } 1970 if (tp->t_outq.c_cc > hiwat) 1971 goto ovhiwat; 1972 /* 1973 * Grab a hunk of data from the user, unless we have some 1974 * leftover from last time. 1975 */ 1976 if (cc == 0) { 1977 cc = imin(uio->uio_resid, OBUFSIZ); 1978 cp = obuf; 1979 error = uiomove(cp, cc, uio); 1980 if (error) { 1981 cc = 0; 1982 break; 1983 } 1984 } 1985 /* 1986 * If nothing fancy need be done, grab those characters we 1987 * can handle without any of ttyoutput's processing and 1988 * just transfer them to the output q. For those chars 1989 * which require special processing (as indicated by the 1990 * bits in char_type), call ttyoutput. After processing 1991 * a hunk of data, look for FLUSHO so ^O's will take effect 1992 * immediately. 1993 */ 1994 while (cc > 0) { 1995 if (!ISSET(tp->t_oflag, OPOST)) 1996 ce = cc; 1997 else { 1998 ce = cc - scanc((u_int)cc, (u_char *)cp, 1999 char_type, CCLASSMASK); 2000 /* 2001 * If ce is zero, then we're processing 2002 * a special character through ttyoutput. 2003 */ 2004 if (ce == 0) { 2005 tp->t_rocount = 0; 2006 if (ttyoutput(*cp, tp) >= 0) { 2007 /* No Clists, wait a bit. */ 2008 ttstart(tp); 2009 if (flag & IO_NDELAY) { 2010 error = EWOULDBLOCK; 2011 goto out; 2012 } 2013 error = ttysleep(tp, &lbolt, 2014 TTOPRI|PCATCH, 2015 "ttybf1", 0); 2016 if (error) 2017 goto out; 2018 goto loop; 2019 } 2020 cp++; 2021 cc--; 2022 if (ISSET(tp->t_lflag, FLUSHO) || 2023 tp->t_outq.c_cc > hiwat) 2024 goto ovhiwat; 2025 continue; 2026 } 2027 } 2028 /* 2029 * A bunch of normal characters have been found. 2030 * Transfer them en masse to the output queue and 2031 * continue processing at the top of the loop. 2032 * If there are any further characters in this 2033 * <= OBUFSIZ chunk, the first should be a character 2034 * requiring special handling by ttyoutput. 2035 */ 2036 tp->t_rocount = 0; 2037 i = b_to_q(cp, ce, &tp->t_outq); 2038 ce -= i; 2039 tp->t_column += ce; 2040 cp += ce, cc -= ce, tk_nout += ce; 2041 tp->t_outcc += ce; 2042 if (i > 0) { 2043 /* No Clists, wait a bit. */ 2044 ttstart(tp); 2045 if (flag & IO_NDELAY) { 2046 error = EWOULDBLOCK; 2047 goto out; 2048 } 2049 error = ttysleep(tp, &lbolt, TTOPRI | PCATCH, 2050 "ttybf2", 0); 2051 if (error) 2052 goto out; 2053 goto loop; 2054 } 2055 if (ISSET(tp->t_lflag, FLUSHO) || 2056 tp->t_outq.c_cc > hiwat) 2057 break; 2058 } 2059 ttstart(tp); 2060 } 2061out: 2062 /* 2063 * If cc is nonzero, we leave the uio structure inconsistent, as the 2064 * offset and iov pointers have moved forward, but it doesn't matter 2065 * (the call will either return short or restart with a new uio). 2066 */ 2067 uio->uio_resid += cc; 2068 return (error); 2069 2070ovhiwat: 2071 ttstart(tp); 2072 s = spltty(); 2073 /* 2074 * This can only occur if FLUSHO is set in t_lflag, 2075 * or if ttstart/oproc is synchronous (or very fast). 2076 */ 2077 if (tp->t_outq.c_cc <= hiwat) { 2078 splx(s); 2079 goto loop; 2080 } 2081 if (flag & IO_NDELAY) { 2082 splx(s); 2083 uio->uio_resid += cc; 2084 return (uio->uio_resid == cnt ? EWOULDBLOCK : 0); 2085 } 2086 SET(tp->t_state, TS_SO_OLOWAT); 2087 error = ttysleep(tp, TSA_OLOWAT(tp), TTOPRI | PCATCH, "ttywri", 2088 tp->t_timeout); 2089 splx(s); 2090 if (error == EWOULDBLOCK) 2091 error = EIO; 2092 if (error) 2093 goto out; 2094 goto loop; 2095} 2096 2097/* 2098 * Rubout one character from the rawq of tp 2099 * as cleanly as possible. 2100 */ 2101static void 2102ttyrub(int c, struct tty *tp) 2103{ 2104 char *cp; 2105 int savecol; 2106 int tabc, s; 2107 2108 if (!ISSET(tp->t_lflag, ECHO) || ISSET(tp->t_lflag, EXTPROC)) 2109 return; 2110 CLR(tp->t_lflag, FLUSHO); 2111 if (ISSET(tp->t_lflag, ECHOE)) { 2112 if (tp->t_rocount == 0) { 2113 /* 2114 * Screwed by ttwrite; retype 2115 */ 2116 ttyretype(tp); 2117 return; 2118 } 2119 if (c == ('\t' | TTY_QUOTE) || c == ('\n' | TTY_QUOTE)) 2120 ttyrubo(tp, 2); 2121 else { 2122 CLR(c, ~TTY_CHARMASK); 2123 switch (CCLASS(c)) { 2124 case ORDINARY: 2125 ttyrubo(tp, 1); 2126 break; 2127 case BACKSPACE: 2128 case CONTROL: 2129 case NEWLINE: 2130 case RETURN: 2131 case VTAB: 2132 if (ISSET(tp->t_lflag, ECHOCTL)) 2133 ttyrubo(tp, 2); 2134 break; 2135 case TAB: 2136 if (tp->t_rocount < tp->t_rawq.c_cc) { 2137 ttyretype(tp); 2138 return; 2139 } 2140 s = spltty(); 2141 savecol = tp->t_column; 2142 SET(tp->t_state, TS_CNTTB); 2143 SET(tp->t_lflag, FLUSHO); 2144 tp->t_column = tp->t_rocol; 2145 cp = tp->t_rawq.c_cf; 2146 if (cp) 2147 tabc = *cp; /* XXX FIX NEXTC */ 2148 for (; cp; cp = nextc(&tp->t_rawq, cp, &tabc)) 2149 ttyecho(tabc, tp); 2150 CLR(tp->t_lflag, FLUSHO); 2151 CLR(tp->t_state, TS_CNTTB); 2152 splx(s); 2153 2154 /* savecol will now be length of the tab. */ 2155 savecol -= tp->t_column; 2156 tp->t_column += savecol; 2157 if (savecol > 8) 2158 savecol = 8; /* overflow screw */ 2159 while (--savecol >= 0) 2160 (void)ttyoutput('\b', tp); 2161 break; 2162 default: /* XXX */ 2163#define PANICSTR "ttyrub: would panic c = %d, val = %d\n" 2164 (void)printf(PANICSTR, c, CCLASS(c)); 2165#ifdef notdef 2166 panic(PANICSTR, c, CCLASS(c)); 2167#endif 2168 } 2169 } 2170 } else if (ISSET(tp->t_lflag, ECHOPRT)) { 2171 if (!ISSET(tp->t_state, TS_ERASE)) { 2172 SET(tp->t_state, TS_ERASE); 2173 (void)ttyoutput('\\', tp); 2174 } 2175 ttyecho(c, tp); 2176 } else { 2177 ttyecho(tp->t_cc[VERASE], tp); 2178 /* 2179 * This code may be executed not only when an ERASE key 2180 * is pressed, but also when ^U (KILL) or ^W (WERASE) are. 2181 * So, I didn't think it was worthwhile to pass the extra 2182 * information (which would need an extra parameter, 2183 * changing every call) needed to distinguish the ERASE2 2184 * case from the ERASE. 2185 */ 2186 } 2187 --tp->t_rocount; 2188} 2189 2190/* 2191 * Back over cnt characters, erasing them. 2192 */ 2193static void 2194ttyrubo(struct tty *tp, int cnt) 2195{ 2196 2197 while (cnt-- > 0) { 2198 (void)ttyoutput('\b', tp); 2199 (void)ttyoutput(' ', tp); 2200 (void)ttyoutput('\b', tp); 2201 } 2202} 2203 2204/* 2205 * ttyretype -- 2206 * Reprint the rawq line. Note, it is assumed that c_cc has already 2207 * been checked. 2208 */ 2209static void 2210ttyretype(struct tty *tp) 2211{ 2212 char *cp; 2213 int s, c; 2214 2215 /* Echo the reprint character. */ 2216 if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE) 2217 ttyecho(tp->t_cc[VREPRINT], tp); 2218 2219 (void)ttyoutput('\n', tp); 2220 2221 /* 2222 * XXX 2223 * FIX: NEXTC IS BROKEN - DOESN'T CHECK QUOTE 2224 * BIT OF FIRST CHAR. 2225 */ 2226 s = spltty(); 2227 for (cp = tp->t_canq.c_cf, c = (cp != NULL ? *cp : 0); 2228 cp != NULL; cp = nextc(&tp->t_canq, cp, &c)) 2229 ttyecho(c, tp); 2230 for (cp = tp->t_rawq.c_cf, c = (cp != NULL ? *cp : 0); 2231 cp != NULL; cp = nextc(&tp->t_rawq, cp, &c)) 2232 ttyecho(c, tp); 2233 CLR(tp->t_state, TS_ERASE); 2234 splx(s); 2235 2236 tp->t_rocount = tp->t_rawq.c_cc; 2237 tp->t_rocol = 0; 2238} 2239 2240/* 2241 * Echo a typed character to the terminal. 2242 */ 2243static void 2244ttyecho(int c, struct tty *tp) 2245{ 2246 2247 if (!ISSET(tp->t_state, TS_CNTTB)) 2248 CLR(tp->t_lflag, FLUSHO); 2249 if ((!ISSET(tp->t_lflag, ECHO) && 2250 (c != '\n' || !ISSET(tp->t_lflag, ECHONL))) || 2251 ISSET(tp->t_lflag, EXTPROC)) 2252 return; 2253 if (ISSET(tp->t_lflag, ECHOCTL) && 2254 ((ISSET(c, TTY_CHARMASK) <= 037 && c != '\t' && c != '\n') || 2255 ISSET(c, TTY_CHARMASK) == 0177)) { 2256 (void)ttyoutput('^', tp); 2257 CLR(c, ~TTY_CHARMASK); 2258 if (c == 0177) 2259 c = '?'; 2260 else 2261 c += 'A' - 1; 2262 } 2263 (void)ttyoutput(c, tp); 2264} 2265 2266/* 2267 * Wake up any readers on a tty. 2268 */ 2269void 2270ttwakeup(struct tty *tp) 2271{ 2272 2273 if (SEL_WAITING(&tp->t_rsel)) 2274 selwakeup(&tp->t_rsel); 2275 if (ISSET(tp->t_state, TS_ASYNC) && tp->t_sigio != NULL) 2276 pgsigio(&tp->t_sigio, SIGIO, (tp->t_session != NULL)); 2277 wakeup(TSA_HUP_OR_INPUT(tp)); 2278 KNOTE(&tp->t_rsel.si_note, 0); 2279} 2280 2281/* 2282 * Wake up any writers on a tty. 2283 */ 2284void 2285ttwwakeup(struct tty *tp) 2286{ 2287 2288 if (SEL_WAITING(&tp->t_wsel) && tp->t_outq.c_cc <= tp->t_olowat) 2289 selwakeup(&tp->t_wsel); 2290 if (ISSET(tp->t_state, TS_ASYNC) && tp->t_sigio != NULL) 2291 pgsigio(&tp->t_sigio, SIGIO, (tp->t_session != NULL)); 2292 if (ISSET(tp->t_state, TS_BUSY | TS_SO_OCOMPLETE) == 2293 TS_SO_OCOMPLETE && tp->t_outq.c_cc == 0) { 2294 CLR(tp->t_state, TS_SO_OCOMPLETE); 2295 wakeup(TSA_OCOMPLETE(tp)); 2296 } 2297 if (ISSET(tp->t_state, TS_SO_OLOWAT) && 2298 tp->t_outq.c_cc <= tp->t_olowat) { 2299 CLR(tp->t_state, TS_SO_OLOWAT); 2300 wakeup(TSA_OLOWAT(tp)); 2301 } 2302 KNOTE(&tp->t_wsel.si_note, 0); 2303} 2304 2305/* 2306 * Look up a code for a specified speed in a conversion table; 2307 * used by drivers to map software speed values to hardware parameters. 2308 */ 2309int 2310ttspeedtab(int speed, struct speedtab *table) 2311{ 2312 2313 for ( ; table->sp_speed != -1; table++) 2314 if (table->sp_speed == speed) 2315 return (table->sp_code); 2316 return (-1); 2317} 2318 2319/* 2320 * Set input and output watermarks and buffer sizes. For input, the 2321 * high watermark is about one second's worth of input above empty, the 2322 * low watermark is slightly below high water, and the buffer size is a 2323 * driver-dependent amount above high water. For output, the watermarks 2324 * are near the ends of the buffer, with about 1 second's worth of input 2325 * between them. All this only applies to the standard line discipline. 2326 */ 2327void 2328ttsetwater(struct tty *tp) 2329{ 2330 int cps, ttmaxhiwat, x; 2331 2332 /* Input. */ 2333 clist_alloc_cblocks(&tp->t_canq, TTYHOG, 512); 2334 switch (tp->t_ispeedwat) { 2335 case (speed_t)-1: 2336 cps = tp->t_ispeed / 10; 2337 break; 2338 case 0: 2339 /* 2340 * This case is for old drivers that don't know about 2341 * t_ispeedwat. Arrange for them to get the old buffer 2342 * sizes and watermarks. 2343 */ 2344 cps = TTYHOG - 2 * 256; 2345 tp->t_ififosize = 2 * 256; 2346 break; 2347 default: 2348 cps = tp->t_ispeedwat / 10; 2349 break; 2350 } 2351 tp->t_ihiwat = cps; 2352 tp->t_ilowat = 7 * cps / 8; 2353 x = cps + tp->t_ififosize; 2354 clist_alloc_cblocks(&tp->t_rawq, x, x); 2355 2356 /* Output. */ 2357 switch (tp->t_ospeedwat) { 2358 case (speed_t)-1: 2359 cps = tp->t_ospeed / 10; 2360 ttmaxhiwat = 2 * TTMAXHIWAT; 2361 break; 2362 case 0: 2363 cps = tp->t_ospeed / 10; 2364 ttmaxhiwat = TTMAXHIWAT; 2365 break; 2366 default: 2367 cps = tp->t_ospeedwat / 10; 2368 ttmaxhiwat = 8 * TTMAXHIWAT; 2369 break; 2370 } 2371#define CLAMP(x, h, l) ((x) > h ? h : ((x) < l) ? l : (x)) 2372 tp->t_olowat = x = CLAMP(cps / 2, TTMAXLOWAT, TTMINLOWAT); 2373 x += cps; 2374 x = CLAMP(x, ttmaxhiwat, TTMINHIWAT); /* XXX clamps are too magic */ 2375 tp->t_ohiwat = roundup(x, CBSIZE); /* XXX for compat */ 2376 x = imax(tp->t_ohiwat, TTMAXHIWAT); /* XXX for compat/safety */ 2377 x += OBUFSIZ + 100; 2378 clist_alloc_cblocks(&tp->t_outq, x, x); 2379#undef CLAMP 2380} 2381 2382/* 2383 * Report on state of foreground process group. 2384 */ 2385void 2386ttyinfo(struct tty *tp) 2387{ 2388 struct proc *p, *pick; 2389 struct timeval utime, stime; 2390 const char *stmp, *sprefix; 2391 long ltmp; 2392 int tmp; 2393 struct thread *td; 2394 2395 if (ttycheckoutq(tp,0) == 0) 2396 return; 2397 2398 /* Print load average. */ 2399 tmp = (averunnable.ldavg[0] * 100 + FSCALE / 2) >> FSHIFT; 2400 ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100); 2401 2402 if (tp->t_session == NULL) 2403 ttyprintf(tp, "not a controlling terminal\n"); 2404 else if (tp->t_pgrp == NULL) 2405 ttyprintf(tp, "no foreground process group\n"); 2406 else { 2407 PGRP_LOCK(tp->t_pgrp); 2408 if ((p = LIST_FIRST(&tp->t_pgrp->pg_members)) == 0) { 2409 PGRP_UNLOCK(tp->t_pgrp); 2410 ttyprintf(tp, "empty foreground process group\n"); 2411 } else { 2412 mtx_lock_spin(&sched_lock); 2413 2414 /* Pick interesting process. */ 2415 for (pick = NULL; p != 0; p = LIST_NEXT(p, p_pglist)) 2416 if (proc_compare(pick, p)) 2417 pick = p; 2418 PGRP_UNLOCK(tp->t_pgrp); 2419 2420 td = FIRST_THREAD_IN_PROC(pick); 2421 sprefix = ""; 2422 if (pick->p_flag & P_SA) { 2423 stmp = "KSE" ; /* XXXKSE */ 2424 } else { 2425 if (td) { 2426 if (TD_ON_RUNQ(td) || 2427 (TD_IS_RUNNING(td))) { 2428 stmp = "running"; 2429 } else if (TD_ON_LOCK(td)) { 2430 stmp = td->td_lockname; 2431 sprefix = "*"; 2432 } else if (td->td_wmesg) { 2433 stmp = td->td_wmesg; 2434 } else { 2435 stmp = "iowait"; 2436 } 2437 } else { 2438 stmp = "threadless"; 2439 panic("ttyinfo: no thread!?"); 2440 } 2441 } 2442 calcru(pick, &utime, &stime, NULL); 2443 if (pick->p_state == PRS_NEW || 2444 pick->p_state == PRS_ZOMBIE) { 2445 ltmp = 0; 2446 } else { 2447 ltmp = pgtok( 2448 vmspace_resident_count(pick->p_vmspace)); 2449 } 2450 mtx_unlock_spin(&sched_lock); 2451 2452 ttyprintf(tp, " cmd: %s %d [%s%s] ", pick->p_comm, 2453 pick->p_pid, sprefix, stmp); 2454 2455 /* Print user time. */ 2456 ttyprintf(tp, "%ld.%02ldu ", 2457 utime.tv_sec, utime.tv_usec / 10000); 2458 2459 /* Print system time. */ 2460 ttyprintf(tp, "%ld.%02lds ", 2461 (long)stime.tv_sec, stime.tv_usec / 10000); 2462 2463 /* Print percentage cpu, resident set size. */ 2464 ttyprintf(tp, "%d%% %ldk\n", tmp / 100, ltmp); 2465 2466 } 2467 } 2468 tp->t_rocount = 0; /* so pending input will be retyped if BS */ 2469} 2470 2471/* 2472 * Returns 1 if p2 is "better" than p1 2473 * 2474 * The algorithm for picking the "interesting" process is thus: 2475 * 2476 * 1) Only foreground processes are eligible - implied. 2477 * 2) Runnable processes are favored over anything else. The runner 2478 * with the highest cpu utilization is picked (p_estcpu). Ties are 2479 * broken by picking the highest pid. 2480 * 3) The sleeper with the shortest sleep time is next. With ties, 2481 * we pick out just "short-term" sleepers (P_SINTR == 0). 2482 * 4) Further ties are broken by picking the highest pid. 2483 */ 2484#define ISRUN(p, val) \ 2485do { \ 2486 struct thread *td; \ 2487 val = 0; \ 2488 FOREACH_THREAD_IN_PROC(p, td) { \ 2489 if (TD_ON_RUNQ(td) || \ 2490 TD_IS_RUNNING(td)) { \ 2491 val = 1; \ 2492 break; \ 2493 } \ 2494 } \ 2495} while (0) 2496 2497#define TESTAB(a, b) ((a)<<1 | (b)) 2498#define ONLYA 2 2499#define ONLYB 1 2500#define BOTH 3 2501 2502static int 2503proc_compare(struct proc *p1, struct proc *p2) 2504{ 2505 2506 int esta, estb; 2507 struct ksegrp *kg; 2508 mtx_assert(&sched_lock, MA_OWNED); 2509 if (p1 == NULL) 2510 return (1); 2511 2512 ISRUN(p1, esta); 2513 ISRUN(p2, estb); 2514 2515 /* 2516 * see if at least one of them is runnable 2517 */ 2518 switch (TESTAB(esta, estb)) { 2519 case ONLYA: 2520 return (0); 2521 case ONLYB: 2522 return (1); 2523 case BOTH: 2524 /* 2525 * tie - favor one with highest recent cpu utilization 2526 */ 2527 esta = estb = 0; 2528 FOREACH_KSEGRP_IN_PROC(p1,kg) { 2529 esta += kg->kg_estcpu; 2530 } 2531 FOREACH_KSEGRP_IN_PROC(p2,kg) { 2532 estb += kg->kg_estcpu; 2533 } 2534 if (estb > esta) 2535 return (1); 2536 if (esta > estb) 2537 return (0); 2538 return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 2539 } 2540 /* 2541 * weed out zombies 2542 */ 2543 switch (TESTAB(p1->p_state == PRS_ZOMBIE, p2->p_state == PRS_ZOMBIE)) { 2544 case ONLYA: 2545 return (1); 2546 case ONLYB: 2547 return (0); 2548 case BOTH: 2549 return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 2550 } 2551 2552#if 0 /* XXXKSE */ 2553 /* 2554 * pick the one with the smallest sleep time 2555 */ 2556 if (p2->p_slptime > p1->p_slptime) 2557 return (0); 2558 if (p1->p_slptime > p2->p_slptime) 2559 return (1); 2560 /* 2561 * favor one sleeping in a non-interruptible sleep 2562 */ 2563 if (p1->p_sflag & PS_SINTR && (p2->p_sflag & PS_SINTR) == 0) 2564 return (1); 2565 if (p2->p_sflag & PS_SINTR && (p1->p_sflag & PS_SINTR) == 0) 2566 return (0); 2567#endif 2568 return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 2569} 2570 2571/* 2572 * Output char to tty; console putchar style. 2573 */ 2574int 2575tputchar(int c, struct tty *tp) 2576{ 2577 int s; 2578 2579 s = spltty(); 2580 if (!ISSET(tp->t_state, TS_CONNECTED)) { 2581 splx(s); 2582 return (-1); 2583 } 2584 if (c == '\n') 2585 (void)ttyoutput('\r', tp); 2586 (void)ttyoutput(c, tp); 2587 ttstart(tp); 2588 splx(s); 2589 return (0); 2590} 2591 2592/* 2593 * Sleep on chan, returning ERESTART if tty changed while we napped and 2594 * returning any errors (e.g. EINTR/EWOULDBLOCK) reported by tsleep. If 2595 * the tty is revoked, restarting a pending call will redo validation done 2596 * at the start of the call. 2597 */ 2598int 2599ttysleep(struct tty *tp, void *chan, int pri, char *wmesg, int timo) 2600{ 2601 int error; 2602 int gen; 2603 2604 gen = tp->t_gen; 2605 error = tsleep(chan, pri, wmesg, timo); 2606 if (error) 2607 return (error); 2608 return (tp->t_gen == gen ? 0 : ERESTART); 2609} 2610 2611/* 2612 * Allocate a tty struct. Clists in the struct will be allocated by 2613 * ttyopen(). 2614 */ 2615struct tty * 2616ttymalloc(struct tty *tp) 2617{ 2618 2619 if (tp) 2620 return(tp); 2621 tp = malloc(sizeof *tp, M_TTYS, M_WAITOK | M_ZERO); 2622 ttyregister(tp); 2623 return (tp); 2624} 2625 2626#if 0 /* XXX not yet usable: session leader holds a ref (see kern_exit.c). */ 2627/* 2628 * Free a tty struct. Clists in the struct should have been freed by 2629 * ttyclose(). 2630 */ 2631void 2632ttyfree(struct tty *tp) 2633{ 2634 free(tp, M_TTYS); 2635} 2636#endif /* 0 */ 2637 2638void 2639ttyregister(struct tty *tp) 2640{ 2641 tp->t_timeout = -1; 2642 SLIST_INSERT_HEAD(&tty_list, tp, t_list); 2643} 2644 2645static int 2646sysctl_kern_ttys(SYSCTL_HANDLER_ARGS) 2647{ 2648 struct tty *tp; 2649 struct xtty xt; 2650 int error; 2651 2652 SLIST_FOREACH(tp, &tty_list, t_list) { 2653 bzero(&xt, sizeof xt); 2654 xt.xt_size = sizeof xt; 2655#define XT_COPY(field) xt.xt_##field = tp->t_##field 2656 xt.xt_rawcc = tp->t_rawq.c_cc; 2657 xt.xt_cancc = tp->t_canq.c_cc; 2658 xt.xt_outcc = tp->t_outq.c_cc; 2659 XT_COPY(line); 2660 if (tp->t_dev) 2661 xt.xt_dev = dev2udev(tp->t_dev); 2662 XT_COPY(state); 2663 XT_COPY(flags); 2664 XT_COPY(timeout); 2665 if (tp->t_pgrp) 2666 xt.xt_pgid = tp->t_pgrp->pg_id; 2667 if (tp->t_session) 2668 xt.xt_sid = tp->t_session->s_sid; 2669 XT_COPY(termios); 2670 XT_COPY(winsize); 2671 XT_COPY(column); 2672 XT_COPY(rocount); 2673 XT_COPY(rocol); 2674 XT_COPY(ififosize); 2675 XT_COPY(ihiwat); 2676 XT_COPY(ilowat); 2677 XT_COPY(ispeedwat); 2678 XT_COPY(ohiwat); 2679 XT_COPY(olowat); 2680 XT_COPY(ospeedwat); 2681#undef XT_COPY 2682 error = SYSCTL_OUT(req, &xt, sizeof xt); 2683 if (error) 2684 return (error); 2685 } 2686 return (0); 2687} 2688 2689SYSCTL_PROC(_kern, OID_AUTO, ttys, CTLTYPE_OPAQUE|CTLFLAG_RD, 2690 0, 0, sysctl_kern_ttys, "S,xtty", "All ttys"); 2691SYSCTL_LONG(_kern, OID_AUTO, tty_nin, CTLFLAG_RD, 2692 &tk_nin, 0, "Total TTY in characters"); 2693SYSCTL_LONG(_kern, OID_AUTO, tty_nout, CTLFLAG_RD, 2694 &tk_nout, 0, "Total TTY out characters"); 2695 2696void 2697nottystop(struct tty *tp, int rw) 2698{ 2699 2700 return; 2701} 2702 2703int 2704ttyread(dev_t dev, struct uio *uio, int flag) 2705{ 2706 struct tty *tp; 2707 2708 tp = dev->si_tty; 2709 if (tp == NULL) 2710 return (ENODEV); 2711 return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 2712} 2713 2714int 2715ttywrite(dev_t dev, struct uio *uio, int flag) 2716{ 2717 struct tty *tp; 2718 2719 tp = dev->si_tty; 2720 if (tp == NULL) 2721 return (ENODEV); 2722 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 2723} 2724