tty.c revision 73929
197883Sgibbs/*- 297883Sgibbs * Copyright (c) 1982, 1986, 1990, 1991, 1993 397883Sgibbs * The Regents of the University of California. All rights reserved. 4102684Sgibbs * (c) UNIX System Laboratories, Inc. 5102684Sgibbs * All or some portions of this file are derived from material licensed 697883Sgibbs * to the University of California by American Telephone and Telegraph 797883Sgibbs * Co. or Unix System Laboratories, Inc. and are reproduced herein with 897883Sgibbs * the permission of UNIX System Laboratories, Inc. 997883Sgibbs * 1097883Sgibbs * Redistribution and use in source and binary forms, with or without 1197883Sgibbs * modification, are permitted provided that the following conditions 1297883Sgibbs * are met: 1397883Sgibbs * 1. Redistributions of source code must retain the above copyright 1497883Sgibbs * notice, this list of conditions and the following disclaimer. 1597883Sgibbs * 2. Redistributions in binary form must reproduce the above copyright 1697883Sgibbs * notice, this list of conditions and the following disclaimer in the 1797883Sgibbs * documentation and/or other materials provided with the distribution. 1897883Sgibbs * 3. All advertising materials mentioning features or use of this software 1997883Sgibbs * must display the following acknowledgement: 2097883Sgibbs * This product includes software developed by the University of 2197883Sgibbs * California, Berkeley and its contributors. 2297883Sgibbs * 4. Neither the name of the University nor the names of its contributors 2397883Sgibbs * may be used to endorse or promote products derived from this software 2497883Sgibbs * without specific prior written permission. 2597883Sgibbs * 2697883Sgibbs * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2797883Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2897883Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2997883Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3097883Sgibbs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3197883Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32111653Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3397883Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3497883Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3597883Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3697883Sgibbs * SUCH DAMAGE. 3797883Sgibbs * 3897883Sgibbs * @(#)tty.c 8.8 (Berkeley) 1/21/94 3997883Sgibbs * $FreeBSD: head/sys/kern/tty.c 73929 2001-03-07 03:37:06Z jhb $ 4097883Sgibbs */ 4197883Sgibbs 4297883Sgibbs/*- 4397883Sgibbs * TODO: 4497883Sgibbs * o Fix races for sending the start char in ttyflush(). 4597883Sgibbs * o Handle inter-byte timeout for "MIN > 0, TIME > 0" in ttyselect(). 4697883Sgibbs * With luck, there will be MIN chars before select() returns(). 4797883Sgibbs * o Handle CLOCAL consistently for ptys. Perhaps disallow setting it. 4897883Sgibbs * o Don't allow input in TS_ZOMBIE case. It would be visible through 4997883Sgibbs * FIONREAD. 5097883Sgibbs * o Do the new sio locking stuff here and use it to avoid special 5197883Sgibbs * case for EXTPROC? 5297883Sgibbs * o Lock PENDIN too? 5397883Sgibbs * o Move EXTPROC and/or PENDIN to t_state? 5497883Sgibbs * o Wrap most of ttioctl in spltty/splx. 5597883Sgibbs * o Implement TIOCNOTTY or remove it from <sys/ioctl.h>. 5697883Sgibbs * o Send STOP if IXOFF is toggled off while TS_TBLOCK is set. 5797883Sgibbs * o Don't allow certain termios flags to affect disciplines other 5897883Sgibbs * than TTYDISC. Cancel their effects before switch disciplines 5997883Sgibbs * and ignore them if they are set while we are in another 6097883Sgibbs * discipline. 6197883Sgibbs * o Now that historical speed conversions are handled here, don't 6297883Sgibbs * do them in drivers. 6397883Sgibbs * o Check for TS_CARR_ON being set while everything is closed and not 6497883Sgibbs * waiting for carrier. TS_CARR_ON isn't cleared if nothing is open, 6597883Sgibbs * so it would live until the next open even if carrier drops. 6697883Sgibbs * o Restore TS_WOPEN since it is useful in pstat. It must be cleared 6797883Sgibbs * only when _all_ openers leave open(). 6897883Sgibbs */ 6997883Sgibbs 7097883Sgibbs#include "opt_snp.h" 7197883Sgibbs#include "opt_compat.h" 7297883Sgibbs#include "opt_uconsole.h" 7397883Sgibbs 7497883Sgibbs#include <sys/param.h> 7597883Sgibbs#include <sys/systm.h> 7697883Sgibbs#include <sys/filio.h> 7797883Sgibbs#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 7897883Sgibbs#include <sys/ioctl_compat.h> 7997883Sgibbs#endif 8097883Sgibbs#include <sys/proc.h> 8197883Sgibbs#define TTYDEFCHARS 8297883Sgibbs#include <sys/tty.h> 8397883Sgibbs#undef TTYDEFCHARS 8497883Sgibbs#include <sys/fcntl.h> 8597883Sgibbs#include <sys/conf.h> 8697883Sgibbs#include <sys/dkstat.h> 8797883Sgibbs#include <sys/poll.h> 8897883Sgibbs#include <sys/kernel.h> 8997883Sgibbs#include <sys/vnode.h> 9097883Sgibbs#include <sys/signalvar.h> 9197883Sgibbs#include <sys/resourcevar.h> 9297883Sgibbs#include <sys/malloc.h> 9397883Sgibbs#include <sys/filedesc.h> 9497883Sgibbs#ifdef DEV_SNP 9597883Sgibbs#include <sys/snoop.h> 9697883Sgibbs#endif 9797883Sgibbs#include <sys/sysctl.h> 9897883Sgibbs 9997883Sgibbs#include <vm/vm.h> 10097883Sgibbs#include <sys/lock.h> 10197883Sgibbs#include <vm/pmap.h> 10297883Sgibbs#include <vm/vm_map.h> 10397883Sgibbs 10497883SgibbsMALLOC_DEFINE(M_TTYS, "ttys", "tty data structures"); 10597883Sgibbs 10697883Sgibbsstatic int proc_compare __P((struct proc *p1, struct proc *p2)); 10797883Sgibbsstatic int ttnread __P((struct tty *tp)); 10897883Sgibbsstatic void ttyecho __P((int c, struct tty *tp)); 10997883Sgibbsstatic int ttyoutput __P((int c, register struct tty *tp)); 11097883Sgibbsstatic void ttypend __P((struct tty *tp)); 11197883Sgibbsstatic void ttyretype __P((struct tty *tp)); 11297883Sgibbsstatic void ttyrub __P((int c, struct tty *tp)); 11397883Sgibbsstatic void ttyrubo __P((struct tty *tp, int cnt)); 11497883Sgibbsstatic void ttyunblock __P((struct tty *tp)); 11597883Sgibbsstatic int ttywflush __P((struct tty *tp)); 11697883Sgibbsstatic int filt_ttyread __P((struct knote *kn, long hint)); 11797883Sgibbsstatic void filt_ttyrdetach __P((struct knote *kn)); 11897883Sgibbsstatic int filt_ttywrite __P((struct knote *kn, long hint)); 11997883Sgibbsstatic void filt_ttywdetach __P((struct knote *kn)); 12097883Sgibbs 12197883Sgibbs/* 12297883Sgibbs * Table with character classes and parity. The 8th bit indicates parity, 12397883Sgibbs * the 7th bit indicates the character is an alphameric or underscore (for 12497883Sgibbs * ALTWERASE), and the low 6 bits indicate delay type. If the low 6 bits 12597883Sgibbs * are 0 then the character needs no special processing on output; classes 12697883Sgibbs * other than 0 might be translated or (not currently) require delays. 12797883Sgibbs */ 12897883Sgibbs#define E 0x00 /* Even parity. */ 12997883Sgibbs#define O 0x80 /* Odd parity. */ 13097883Sgibbs#define PARITY(c) (char_type[c] & O) 13197883Sgibbs 13297883Sgibbs#define ALPHA 0x40 /* Alpha or underscore. */ 13397883Sgibbs#define ISALPHA(c) (char_type[(c) & TTY_CHARMASK] & ALPHA) 13497883Sgibbs 13597883Sgibbs#define CCLASSMASK 0x3f 13697883Sgibbs#define CCLASS(c) (char_type[c] & CCLASSMASK) 13797883Sgibbs 13897883Sgibbs#define BS BACKSPACE 13997883Sgibbs#define CC CONTROL 14097883Sgibbs#define CR RETURN 14197883Sgibbs#define NA ORDINARY | ALPHA 14297883Sgibbs#define NL NEWLINE 14397883Sgibbs#define NO ORDINARY 14497883Sgibbs#define TB TAB 14597883Sgibbs#define VT VTAB 14697883Sgibbs 14797883Sgibbsstatic u_char const char_type[] = { 14897883Sgibbs E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* nul - bel */ 14997883Sgibbs O|BS, E|TB, E|NL, O|CC, E|VT, O|CR, O|CC, E|CC, /* bs - si */ 15097883Sgibbs O|CC, E|CC, E|CC, O|CC, E|CC, O|CC, O|CC, E|CC, /* dle - etb */ 15197883Sgibbs E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* can - us */ 15297883Sgibbs O|NO, E|NO, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* sp - ' */ 15397883Sgibbs E|NO, O|NO, O|NO, E|NO, O|NO, E|NO, E|NO, O|NO, /* ( - / */ 15497883Sgibbs E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* 0 - 7 */ 15597883Sgibbs O|NA, E|NA, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* 8 - ? */ 15697883Sgibbs O|NO, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* @ - G */ 15797883Sgibbs E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* H - O */ 15897883Sgibbs E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* P - W */ 15997883Sgibbs O|NA, E|NA, E|NA, O|NO, E|NO, O|NO, O|NO, O|NA, /* X - _ */ 16097883Sgibbs E|NO, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* ` - g */ 16197883Sgibbs O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* h - o */ 16297883Sgibbs O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* p - w */ 16397883Sgibbs E|NA, O|NA, O|NA, E|NO, O|NO, E|NO, E|NO, O|CC, /* x - del */ 16497883Sgibbs /* 16597883Sgibbs * Meta chars; should be settable per character set; 16697883Sgibbs * for now, treat them all as normal characters. 16797883Sgibbs */ 16897883Sgibbs NA, NA, NA, NA, NA, NA, NA, NA, 16997883Sgibbs NA, NA, NA, NA, NA, NA, NA, NA, 17097883Sgibbs NA, NA, NA, NA, NA, NA, NA, NA, 17197883Sgibbs NA, NA, NA, NA, NA, NA, NA, NA, 17297883Sgibbs NA, NA, NA, NA, NA, NA, NA, NA, 17397883Sgibbs NA, NA, NA, NA, NA, NA, NA, NA, 174102684Sgibbs NA, NA, NA, NA, NA, NA, NA, NA, 17597883Sgibbs NA, NA, NA, NA, NA, NA, NA, NA, 17697883Sgibbs NA, NA, NA, NA, NA, NA, NA, NA, 17797883Sgibbs NA, NA, NA, NA, NA, NA, NA, NA, 17897883Sgibbs NA, NA, NA, NA, NA, NA, NA, NA, 179102684Sgibbs NA, NA, NA, NA, NA, NA, NA, NA, 180102684Sgibbs NA, NA, NA, NA, NA, NA, NA, NA, 18197883Sgibbs NA, NA, NA, NA, NA, NA, NA, NA, 182102684Sgibbs NA, NA, NA, NA, NA, NA, NA, NA, 183102684Sgibbs NA, NA, NA, NA, NA, NA, NA, NA, 18497883Sgibbs}; 18597883Sgibbs#undef BS 18697883Sgibbs#undef CC 18797883Sgibbs#undef CR 18897883Sgibbs#undef NA 18997883Sgibbs#undef NL 19097883Sgibbs#undef NO 19197883Sgibbs#undef TB 19297883Sgibbs#undef VT 19397883Sgibbs 19497883Sgibbs/* Macros to clear/set/test flags. */ 19597883Sgibbs#define SET(t, f) (t) |= (f) 19697883Sgibbs#define CLR(t, f) (t) &= ~(f) 19797883Sgibbs#define ISSET(t, f) ((t) & (f)) 19897883Sgibbs 19997883Sgibbs#undef MAX_INPUT /* XXX wrong in <sys/syslimits.h> */ 20097883Sgibbs#define MAX_INPUT TTYHOG /* XXX limit is usually larger for !ICANON */ 20197883Sgibbs 20297883Sgibbs/* 20397883Sgibbs * list of struct tty where pstat(8) can pick it up with sysctl 20497883Sgibbs */ 20597883Sgibbsstatic SLIST_HEAD(, tty) tty_list; 20697883Sgibbs 20797883Sgibbsstatic int drainwait = 5*60; 20897883SgibbsSYSCTL_INT(_kern, OID_AUTO, drainwait, CTLFLAG_RW, &drainwait, 20997883Sgibbs 0, "Output drain timeout in seconds"); 21097883Sgibbs 21197883Sgibbs/* 21297883Sgibbs * Initial open of tty, or (re)entry to standard tty line discipline. 21397883Sgibbs */ 21497883Sgibbsint 21597883Sgibbsttyopen(device, tp) 21697883Sgibbs dev_t device; 21797883Sgibbs register struct tty *tp; 21897883Sgibbs{ 21997883Sgibbs int s; 22097883Sgibbs 22197883Sgibbs s = spltty(); 22297883Sgibbs tp->t_dev = device; 22397883Sgibbs if (!ISSET(tp->t_state, TS_ISOPEN)) { 22497883Sgibbs SET(tp->t_state, TS_ISOPEN); 22597883Sgibbs if (ISSET(tp->t_cflag, CLOCAL)) 22697883Sgibbs SET(tp->t_state, TS_CONNECTED); 22797883Sgibbs bzero(&tp->t_winsize, sizeof(tp->t_winsize)); 22897883Sgibbs } 22997883Sgibbs /* XXX don't hang forever on output */ 23097883Sgibbs if (tp->t_timeout < 0) 23197883Sgibbs tp->t_timeout = drainwait*hz; 23297883Sgibbs ttsetwater(tp); 23397883Sgibbs splx(s); 23497883Sgibbs return (0); 23597883Sgibbs} 23697883Sgibbs 23797883Sgibbs/* 23897883Sgibbs * Handle close() on a tty line: flush and set to initial state, 23997883Sgibbs * bumping generation number so that pending read/write calls 24097883Sgibbs * can detect recycling of the tty. 24197883Sgibbs * XXX our caller should have done `spltty(); l_close(); ttyclose();' 24297883Sgibbs * and l_close() should have flushed, but we repeat the spltty() and 24397883Sgibbs * the flush in case there are buggy callers. 24497883Sgibbs */ 24597883Sgibbsint 24697883Sgibbsttyclose(tp) 24797883Sgibbs register struct tty *tp; 24897883Sgibbs{ 24997883Sgibbs int s; 25097883Sgibbs 25197883Sgibbs funsetown(tp->t_sigio); 25297883Sgibbs s = spltty(); 25397883Sgibbs if (constty == tp) 25497883Sgibbs constty = NULL; 25597883Sgibbs 25697883Sgibbs ttyflush(tp, FREAD | FWRITE); 25797883Sgibbs clist_free_cblocks(&tp->t_canq); 25897883Sgibbs clist_free_cblocks(&tp->t_outq); 25997883Sgibbs clist_free_cblocks(&tp->t_rawq); 26097883Sgibbs 26197883Sgibbs#ifdef DEV_SNP 26297883Sgibbs if (ISSET(tp->t_state, TS_SNOOP) && tp->t_sc != NULL) 26397883Sgibbs snpdown((struct snoop *)tp->t_sc); 26497883Sgibbs#endif 26597883Sgibbs 26697883Sgibbs tp->t_gen++; 26797883Sgibbs tp->t_line = TTYDISC; 26897883Sgibbs tp->t_pgrp = NULL; 26997883Sgibbs tp->t_session = NULL; 27097883Sgibbs tp->t_state = 0; 27197883Sgibbs splx(s); 27297883Sgibbs return (0); 27397883Sgibbs} 27497883Sgibbs 27597883Sgibbs#define FLUSHQ(q) { \ 27697883Sgibbs if ((q)->c_cc) \ 27797883Sgibbs ndflush(q, (q)->c_cc); \ 27897883Sgibbs} 27997883Sgibbs 28097883Sgibbs/* Is 'c' a line delimiter ("break" character)? */ 28197883Sgibbs#define TTBREAKC(c, lflag) \ 28297883Sgibbs ((c) == '\n' || (((c) == cc[VEOF] || \ 28397883Sgibbs (c) == cc[VEOL] || ((c) == cc[VEOL2] && lflag & IEXTEN)) && \ 28497883Sgibbs (c) != _POSIX_VDISABLE)) 28597883Sgibbs 28697883Sgibbs/* 28797883Sgibbs * Process input of a single character received on a tty. 28897883Sgibbs */ 28997883Sgibbsint 29097883Sgibbsttyinput(c, tp) 29197883Sgibbs register int c; 29297883Sgibbs register struct tty *tp; 29397883Sgibbs{ 29497883Sgibbs register tcflag_t iflag, lflag; 29597883Sgibbs register cc_t *cc; 29697883Sgibbs int i, err; 29797883Sgibbs 29897883Sgibbs /* 29997883Sgibbs * If input is pending take it first. 30097883Sgibbs */ 30197883Sgibbs lflag = tp->t_lflag; 30297883Sgibbs if (ISSET(lflag, PENDIN)) 30397883Sgibbs ttypend(tp); 30497883Sgibbs /* 30597883Sgibbs * Gather stats. 30697883Sgibbs */ 30797883Sgibbs if (ISSET(lflag, ICANON)) { 30897883Sgibbs ++tk_cancc; 30997883Sgibbs ++tp->t_cancc; 31097883Sgibbs } else { 31197883Sgibbs ++tk_rawcc; 31297883Sgibbs ++tp->t_rawcc; 31397883Sgibbs } 31497883Sgibbs ++tk_nin; 31597883Sgibbs 31697883Sgibbs /* 31797883Sgibbs * Block further input iff: 31897883Sgibbs * current input > threshold AND input is available to user program 31997883Sgibbs * AND input flow control is enabled and not yet invoked. 32097883Sgibbs * The 3 is slop for PARMRK. 32197883Sgibbs */ 32297883Sgibbs iflag = tp->t_iflag; 32397883Sgibbs if (tp->t_rawq.c_cc + tp->t_canq.c_cc > tp->t_ihiwat - 3 && 32497883Sgibbs (!ISSET(lflag, ICANON) || tp->t_canq.c_cc != 0) && 32597883Sgibbs (ISSET(tp->t_cflag, CRTS_IFLOW) || ISSET(iflag, IXOFF)) && 32697883Sgibbs !ISSET(tp->t_state, TS_TBLOCK)) 32797883Sgibbs ttyblock(tp); 32897883Sgibbs 32997883Sgibbs /* Handle exceptional conditions (break, parity, framing). */ 33097883Sgibbs cc = tp->t_cc; 33197883Sgibbs err = (ISSET(c, TTY_ERRORMASK)); 33297883Sgibbs if (err) { 33397883Sgibbs CLR(c, TTY_ERRORMASK); 33497883Sgibbs if (ISSET(err, TTY_BI)) { 33597883Sgibbs if (ISSET(iflag, IGNBRK)) 33697883Sgibbs return (0); 33797883Sgibbs if (ISSET(iflag, BRKINT)) { 33897883Sgibbs ttyflush(tp, FREAD | FWRITE); 33997883Sgibbs pgsignal(tp->t_pgrp, SIGINT, 1); 34097883Sgibbs goto endcase; 34197883Sgibbs } 34297883Sgibbs if (ISSET(iflag, PARMRK)) 34397883Sgibbs goto parmrk; 34497883Sgibbs } else if ((ISSET(err, TTY_PE) && ISSET(iflag, INPCK)) 34597883Sgibbs || ISSET(err, TTY_FE)) { 34697883Sgibbs if (ISSET(iflag, IGNPAR)) 34797883Sgibbs return (0); 34897883Sgibbs else if (ISSET(iflag, PARMRK)) { 34997883Sgibbsparmrk: 35097883Sgibbs if (tp->t_rawq.c_cc + tp->t_canq.c_cc > 35197883Sgibbs MAX_INPUT - 3) 35297883Sgibbs goto input_overflow; 35397883Sgibbs (void)putc(0377 | TTY_QUOTE, &tp->t_rawq); 35497883Sgibbs (void)putc(0 | TTY_QUOTE, &tp->t_rawq); 35597883Sgibbs (void)putc(c | TTY_QUOTE, &tp->t_rawq); 35697883Sgibbs goto endcase; 35797883Sgibbs } else 35897883Sgibbs c = 0; 35997883Sgibbs } 36097883Sgibbs } 36197883Sgibbs 36297883Sgibbs if (!ISSET(tp->t_state, TS_TYPEN) && ISSET(iflag, ISTRIP)) 36397883Sgibbs CLR(c, 0x80); 36497883Sgibbs if (!ISSET(lflag, EXTPROC)) { 36597883Sgibbs /* 36697883Sgibbs * Check for literal nexting very first 36797883Sgibbs */ 36897883Sgibbs if (ISSET(tp->t_state, TS_LNCH)) { 36997883Sgibbs SET(c, TTY_QUOTE); 37097883Sgibbs CLR(tp->t_state, TS_LNCH); 37197883Sgibbs } 37297883Sgibbs /* 37397883Sgibbs * Scan for special characters. This code 37497883Sgibbs * is really just a big case statement with 37597883Sgibbs * non-constant cases. The bottom of the 37697883Sgibbs * case statement is labeled ``endcase'', so goto 37797883Sgibbs * it after a case match, or similar. 37897883Sgibbs */ 37997883Sgibbs 38097883Sgibbs /* 38197883Sgibbs * Control chars which aren't controlled 38297883Sgibbs * by ICANON, ISIG, or IXON. 38397883Sgibbs */ 38497883Sgibbs if (ISSET(lflag, IEXTEN)) { 38597883Sgibbs if (CCEQ(cc[VLNEXT], c)) { 38697883Sgibbs if (ISSET(lflag, ECHO)) { 38797883Sgibbs if (ISSET(lflag, ECHOE)) { 38897883Sgibbs (void)ttyoutput('^', tp); 38997883Sgibbs (void)ttyoutput('\b', tp); 39097883Sgibbs } else 39197883Sgibbs ttyecho(c, tp); 39297883Sgibbs } 39397883Sgibbs SET(tp->t_state, TS_LNCH); 39497883Sgibbs goto endcase; 39597883Sgibbs } 39697883Sgibbs if (CCEQ(cc[VDISCARD], c)) { 39797883Sgibbs if (ISSET(lflag, FLUSHO)) 39897883Sgibbs CLR(tp->t_lflag, FLUSHO); 39997883Sgibbs else { 40097883Sgibbs ttyflush(tp, FWRITE); 40197883Sgibbs ttyecho(c, tp); 40297883Sgibbs if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 40397883Sgibbs ttyretype(tp); 40497883Sgibbs SET(tp->t_lflag, FLUSHO); 40597883Sgibbs } 40697883Sgibbs goto startoutput; 40797883Sgibbs } 40897883Sgibbs } 40997883Sgibbs /* 41097883Sgibbs * Signals. 411102684Sgibbs */ 412102684Sgibbs if (ISSET(lflag, ISIG)) { 413102684Sgibbs if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) { 41497883Sgibbs if (!ISSET(lflag, NOFLSH)) 41597883Sgibbs ttyflush(tp, FREAD | FWRITE); 41697883Sgibbs ttyecho(c, tp); 41797883Sgibbs pgsignal(tp->t_pgrp, 41897883Sgibbs CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1); 41997883Sgibbs goto endcase; 42097883Sgibbs } 42197883Sgibbs if (CCEQ(cc[VSUSP], c)) { 42297883Sgibbs if (!ISSET(lflag, NOFLSH)) 42397883Sgibbs ttyflush(tp, FREAD); 42497883Sgibbs ttyecho(c, tp); 42597883Sgibbs pgsignal(tp->t_pgrp, SIGTSTP, 1); 42697883Sgibbs goto endcase; 427102684Sgibbs } 428102684Sgibbs } 429102684Sgibbs /* 430102684Sgibbs * Handle start/stop characters. 431102684Sgibbs */ 432102684Sgibbs if (ISSET(iflag, IXON)) { 433102684Sgibbs if (CCEQ(cc[VSTOP], c)) { 434102684Sgibbs if (!ISSET(tp->t_state, TS_TTSTOP)) { 435102684Sgibbs SET(tp->t_state, TS_TTSTOP); 436102684Sgibbs (*tp->t_stop)(tp, 0); 437102684Sgibbs return (0); 43897883Sgibbs } 43997883Sgibbs if (!CCEQ(cc[VSTART], c)) 44097883Sgibbs return (0); 44197883Sgibbs /* 44297883Sgibbs * if VSTART == VSTOP then toggle 44397883Sgibbs */ 44497883Sgibbs goto endcase; 44597883Sgibbs } 44697883Sgibbs if (CCEQ(cc[VSTART], c)) 44797883Sgibbs goto restartoutput; 44897883Sgibbs } 44997883Sgibbs /* 45097883Sgibbs * IGNCR, ICRNL, & INLCR 45197883Sgibbs */ 45297883Sgibbs if (c == '\r') { 45397883Sgibbs if (ISSET(iflag, IGNCR)) 45497883Sgibbs return (0); 45597883Sgibbs else if (ISSET(iflag, ICRNL)) 45697883Sgibbs c = '\n'; 45797883Sgibbs } else if (c == '\n' && ISSET(iflag, INLCR)) 45897883Sgibbs c = '\r'; 45997883Sgibbs } 46097883Sgibbs if (!ISSET(tp->t_lflag, EXTPROC) && ISSET(lflag, ICANON)) { 46197883Sgibbs /* 46297883Sgibbs * From here on down canonical mode character 46397883Sgibbs * processing takes place. 46497883Sgibbs */ 46597883Sgibbs /* 46697883Sgibbs * erase or erase2 (^H / ^?) 46797883Sgibbs */ 468109588Sgibbs if (CCEQ(cc[VERASE], c) || CCEQ(cc[VERASE2], c) ) { 46997883Sgibbs if (tp->t_rawq.c_cc) 47097883Sgibbs ttyrub(unputc(&tp->t_rawq), tp); 47197883Sgibbs goto endcase; 47297883Sgibbs } 47397883Sgibbs /* 47497883Sgibbs * kill (^U) 47597883Sgibbs */ 47697883Sgibbs if (CCEQ(cc[VKILL], c)) { 47797883Sgibbs if (ISSET(lflag, ECHOKE) && 47897883Sgibbs tp->t_rawq.c_cc == tp->t_rocount && 47997883Sgibbs !ISSET(lflag, ECHOPRT)) 48097883Sgibbs while (tp->t_rawq.c_cc) 48197883Sgibbs ttyrub(unputc(&tp->t_rawq), tp); 48297883Sgibbs else { 48397883Sgibbs ttyecho(c, tp); 48497883Sgibbs if (ISSET(lflag, ECHOK) || 48597883Sgibbs ISSET(lflag, ECHOKE)) 48697883Sgibbs ttyecho('\n', tp); 48797883Sgibbs FLUSHQ(&tp->t_rawq); 48897883Sgibbs tp->t_rocount = 0; 48997883Sgibbs } 49097883Sgibbs CLR(tp->t_state, TS_LOCAL); 49197883Sgibbs goto endcase; 492109588Sgibbs } 49397883Sgibbs /* 49497883Sgibbs * word erase (^W) 49597883Sgibbs */ 49697883Sgibbs if (CCEQ(cc[VWERASE], c) && ISSET(lflag, IEXTEN)) { 49797883Sgibbs int ctype; 49897883Sgibbs 49997883Sgibbs /* 50097883Sgibbs * erase whitespace 50197883Sgibbs */ 50297883Sgibbs while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t') 50397883Sgibbs ttyrub(c, tp); 50497883Sgibbs if (c == -1) 50597883Sgibbs goto endcase; 50697883Sgibbs /* 50797883Sgibbs * erase last char of word and remember the 50897883Sgibbs * next chars type (for ALTWERASE) 50997883Sgibbs */ 51097883Sgibbs ttyrub(c, tp); 51197883Sgibbs c = unputc(&tp->t_rawq); 51297883Sgibbs if (c == -1) 51397883Sgibbs goto endcase; 51497883Sgibbs if (c == ' ' || c == '\t') { 51597883Sgibbs (void)putc(c, &tp->t_rawq); 51697883Sgibbs goto endcase; 51797883Sgibbs } 51897883Sgibbs ctype = ISALPHA(c); 51997883Sgibbs /* 52097883Sgibbs * erase rest of word 52197883Sgibbs */ 52297883Sgibbs do { 52397883Sgibbs ttyrub(c, tp); 52497883Sgibbs c = unputc(&tp->t_rawq); 52597883Sgibbs if (c == -1) 52697883Sgibbs goto endcase; 52797883Sgibbs } while (c != ' ' && c != '\t' && 52897883Sgibbs (!ISSET(lflag, ALTWERASE) || ISALPHA(c) == ctype)); 52997883Sgibbs (void)putc(c, &tp->t_rawq); 53097883Sgibbs goto endcase; 53197883Sgibbs } 53297883Sgibbs /* 53397883Sgibbs * reprint line (^R) 53497883Sgibbs */ 53597883Sgibbs if (CCEQ(cc[VREPRINT], c) && ISSET(lflag, IEXTEN)) { 53697883Sgibbs ttyretype(tp); 53797883Sgibbs goto endcase; 53897883Sgibbs } 53997883Sgibbs /* 54097883Sgibbs * ^T - kernel info and generate SIGINFO 54197883Sgibbs */ 54297883Sgibbs if (CCEQ(cc[VSTATUS], c) && ISSET(lflag, IEXTEN)) { 54397883Sgibbs if (ISSET(lflag, ISIG)) 54497883Sgibbs pgsignal(tp->t_pgrp, SIGINFO, 1); 54597883Sgibbs if (!ISSET(lflag, NOKERNINFO)) 54697883Sgibbs ttyinfo(tp); 54797883Sgibbs goto endcase; 54897883Sgibbs } 54997883Sgibbs } 55097883Sgibbs /* 55197883Sgibbs * Check for input buffer overflow 55297883Sgibbs */ 55397883Sgibbs if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= MAX_INPUT) { 55497883Sgibbsinput_overflow: 55597883Sgibbs if (ISSET(iflag, IMAXBEL)) { 55697883Sgibbs if (tp->t_outq.c_cc < tp->t_ohiwat) 55797883Sgibbs (void)ttyoutput(CTRL('g'), tp); 55897883Sgibbs } 55997883Sgibbs goto endcase; 56097883Sgibbs } 56197883Sgibbs 56297883Sgibbs if ( c == 0377 && ISSET(iflag, PARMRK) && !ISSET(iflag, ISTRIP) 56397883Sgibbs && ISSET(iflag, IGNBRK|IGNPAR) != (IGNBRK|IGNPAR)) 56497883Sgibbs (void)putc(0377 | TTY_QUOTE, &tp->t_rawq); 56597883Sgibbs 56697883Sgibbs /* 56797883Sgibbs * Put data char in q for user and 56897883Sgibbs * wakeup on seeing a line delimiter. 56997883Sgibbs */ 57097883Sgibbs if (putc(c, &tp->t_rawq) >= 0) { 57197883Sgibbs if (!ISSET(lflag, ICANON)) { 57297883Sgibbs ttwakeup(tp); 57397883Sgibbs ttyecho(c, tp); 57497883Sgibbs goto endcase; 57597883Sgibbs } 57697883Sgibbs if (TTBREAKC(c, lflag)) { 57797883Sgibbs tp->t_rocount = 0; 57897883Sgibbs catq(&tp->t_rawq, &tp->t_canq); 57997883Sgibbs ttwakeup(tp); 58097883Sgibbs } else if (tp->t_rocount++ == 0) 58197883Sgibbs tp->t_rocol = tp->t_column; 58297883Sgibbs if (ISSET(tp->t_state, TS_ERASE)) { 58397883Sgibbs /* 58497883Sgibbs * end of prterase \.../ 58597883Sgibbs */ 58697883Sgibbs CLR(tp->t_state, TS_ERASE); 58797883Sgibbs (void)ttyoutput('/', tp); 58897883Sgibbs } 58997883Sgibbs i = tp->t_column; 59097883Sgibbs ttyecho(c, tp); 59197883Sgibbs if (CCEQ(cc[VEOF], c) && ISSET(lflag, ECHO)) { 59297883Sgibbs /* 59397883Sgibbs * Place the cursor over the '^' of the ^D. 59497883Sgibbs */ 59597883Sgibbs i = imin(2, tp->t_column - i); 59697883Sgibbs while (i > 0) { 59797883Sgibbs (void)ttyoutput('\b', tp); 59897883Sgibbs i--; 59997883Sgibbs } 60097883Sgibbs } 60197883Sgibbs } 60297883Sgibbsendcase: 60397883Sgibbs /* 60497883Sgibbs * IXANY means allow any character to restart output. 60597883Sgibbs */ 60697883Sgibbs if (ISSET(tp->t_state, TS_TTSTOP) && 60797883Sgibbs !ISSET(iflag, IXANY) && cc[VSTART] != cc[VSTOP]) 60897883Sgibbs return (0); 60997883Sgibbsrestartoutput: 61097883Sgibbs CLR(tp->t_lflag, FLUSHO); 61197883Sgibbs CLR(tp->t_state, TS_TTSTOP); 61297883Sgibbsstartoutput: 61397883Sgibbs return (ttstart(tp)); 61497883Sgibbs} 61597883Sgibbs 61697883Sgibbs/* 61797883Sgibbs * Output a single character on a tty, doing output processing 61897883Sgibbs * as needed (expanding tabs, newline processing, etc.). 61997883Sgibbs * Returns < 0 if succeeds, otherwise returns char to resend. 62097883Sgibbs * Must be recursive. 62197883Sgibbs */ 62297883Sgibbsstatic int 62397883Sgibbsttyoutput(c, tp) 62497883Sgibbs register int c; 62597883Sgibbs register struct tty *tp; 62697883Sgibbs{ 62797883Sgibbs register tcflag_t oflag; 62897883Sgibbs register int col, s; 62997883Sgibbs 63097883Sgibbs oflag = tp->t_oflag; 63197883Sgibbs if (!ISSET(oflag, OPOST)) { 63297883Sgibbs if (ISSET(tp->t_lflag, FLUSHO)) 63397883Sgibbs return (-1); 63497883Sgibbs if (putc(c, &tp->t_outq)) 63597883Sgibbs return (c); 63697883Sgibbs tk_nout++; 63797883Sgibbs tp->t_outcc++; 63897883Sgibbs return (-1); 63997883Sgibbs } 64097883Sgibbs /* 64197883Sgibbs * Do tab expansion if OXTABS is set. Special case if we external 64297883Sgibbs * processing, we don't do the tab expansion because we'll probably 64397883Sgibbs * get it wrong. If tab expansion needs to be done, let it happen 64497883Sgibbs * externally. 64597883Sgibbs */ 64697883Sgibbs CLR(c, ~TTY_CHARMASK); 64797883Sgibbs if (c == '\t' && 64897883Sgibbs ISSET(oflag, OXTABS) && !ISSET(tp->t_lflag, EXTPROC)) { 64997883Sgibbs c = 8 - (tp->t_column & 7); 65097883Sgibbs if (!ISSET(tp->t_lflag, FLUSHO)) { 65197883Sgibbs s = spltty(); /* Don't interrupt tabs. */ 65297883Sgibbs c -= b_to_q(" ", c, &tp->t_outq); 65397883Sgibbs tk_nout += c; 65497883Sgibbs tp->t_outcc += c; 65597883Sgibbs splx(s); 65697883Sgibbs } 65797883Sgibbs tp->t_column += c; 65897883Sgibbs return (c ? -1 : '\t'); 65997883Sgibbs } 66097883Sgibbs if (c == CEOT && ISSET(oflag, ONOEOT)) 66197883Sgibbs return (-1); 66297883Sgibbs 66397883Sgibbs /* 66497883Sgibbs * Newline translation: if ONLCR is set, 66597883Sgibbs * translate newline into "\r\n". 66697883Sgibbs */ 66797883Sgibbs if (c == '\n' && ISSET(tp->t_oflag, ONLCR)) { 66897883Sgibbs tk_nout++; 66997883Sgibbs tp->t_outcc++; 67097883Sgibbs if (!ISSET(tp->t_lflag, FLUSHO) && putc('\r', &tp->t_outq)) 67197883Sgibbs return (c); 67297883Sgibbs } 67397883Sgibbs /* If OCRNL is set, translate "\r" into "\n". */ 67497883Sgibbs else if (c == '\r' && ISSET(tp->t_oflag, OCRNL)) 67597883Sgibbs c = '\n'; 67697883Sgibbs /* If ONOCR is set, don't transmit CRs when on column 0. */ 67797883Sgibbs else if (c == '\r' && ISSET(tp->t_oflag, ONOCR) && tp->t_column == 0) 67897883Sgibbs return (-1); 67997883Sgibbs 68097883Sgibbs tk_nout++; 68197883Sgibbs tp->t_outcc++; 68297883Sgibbs if (!ISSET(tp->t_lflag, FLUSHO) && putc(c, &tp->t_outq)) 68397883Sgibbs return (c); 68497883Sgibbs 68597883Sgibbs col = tp->t_column; 68697883Sgibbs switch (CCLASS(c)) { 68797883Sgibbs case BACKSPACE: 68897883Sgibbs if (col > 0) 68997883Sgibbs --col; 69097883Sgibbs break; 69197883Sgibbs case CONTROL: 69297883Sgibbs break; 69397883Sgibbs case NEWLINE: 69497883Sgibbs if (ISSET(tp->t_oflag, ONLCR | ONLRET)) 69597883Sgibbs col = 0; 69697883Sgibbs break; 69797883Sgibbs case RETURN: 69897883Sgibbs col = 0; 69997883Sgibbs break; 70097883Sgibbs case ORDINARY: 70197883Sgibbs ++col; 70297883Sgibbs break; 70397883Sgibbs case TAB: 70497883Sgibbs col = (col + 8) & ~7; 70597883Sgibbs break; 70697883Sgibbs } 70797883Sgibbs tp->t_column = col; 70897883Sgibbs return (-1); 70997883Sgibbs} 71097883Sgibbs 71197883Sgibbs/* 71297883Sgibbs * Ioctls for all tty devices. Called after line-discipline specific ioctl 71397883Sgibbs * has been called to do discipline-specific functions and/or reject any 71497883Sgibbs * of these ioctl commands. 71597883Sgibbs */ 71697883Sgibbs/* ARGSUSED */ 71797883Sgibbsint 71897883Sgibbsttioctl(tp, cmd, data, flag) 71997883Sgibbs register struct tty *tp; 72097883Sgibbs u_long cmd; 72197883Sgibbs int flag; 72297883Sgibbs void *data; 72397883Sgibbs{ 72497883Sgibbs register struct proc *p; 72597883Sgibbs int s, error; 72697883Sgibbs 72797883Sgibbs p = curproc; /* XXX */ 72897883Sgibbs 72997883Sgibbs /* If the ioctl involves modification, hang if in the background. */ 73097883Sgibbs switch (cmd) { 73197883Sgibbs case TIOCCBRK: 73297883Sgibbs case TIOCCONS: 73397883Sgibbs case TIOCDRAIN: 73497883Sgibbs case TIOCEXCL: 73597883Sgibbs case TIOCFLUSH: 73697883Sgibbs#ifdef TIOCHPCL 73797883Sgibbs case TIOCHPCL: 73897883Sgibbs#endif 73997883Sgibbs case TIOCNXCL: 74097883Sgibbs case TIOCSBRK: 74197883Sgibbs case TIOCSCTTY: 74297883Sgibbs case TIOCSDRAINWAIT: 74397883Sgibbs case TIOCSETA: 74497883Sgibbs case TIOCSETAF: 74597883Sgibbs case TIOCSETAW: 74697883Sgibbs case TIOCSETD: 74797883Sgibbs case TIOCSPGRP: 74897883Sgibbs case TIOCSTART: 74997883Sgibbs case TIOCSTAT: 75097883Sgibbs case TIOCSTI: 75197883Sgibbs case TIOCSTOP: 75297883Sgibbs case TIOCSWINSZ: 75397883Sgibbs#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 75497883Sgibbs case TIOCLBIC: 75597883Sgibbs case TIOCLBIS: 75697883Sgibbs case TIOCLSET: 75797883Sgibbs case TIOCSETC: 75897883Sgibbs case OTIOCSETD: 75997883Sgibbs case TIOCSETN: 76097883Sgibbs case TIOCSETP: 76197883Sgibbs case TIOCSLTC: 76297883Sgibbs#endif 76397883Sgibbs while (isbackground(p, tp) && !(p->p_flag & P_PPWAIT) && 76497883Sgibbs !SIGISMEMBER(p->p_sigignore, SIGTTOU) && 76597883Sgibbs !SIGISMEMBER(p->p_sigmask, SIGTTOU)) { 76697883Sgibbs if (p->p_pgrp->pg_jobc == 0) 76797883Sgibbs return (EIO); 76897883Sgibbs pgsignal(p->p_pgrp, SIGTTOU, 1); 76997883Sgibbs error = ttysleep(tp, &lbolt, TTOPRI | PCATCH, "ttybg1", 77097883Sgibbs 0); 77197883Sgibbs if (error) 77297883Sgibbs return (error); 77397883Sgibbs } 77497883Sgibbs break; 77597883Sgibbs } 77697883Sgibbs 77797883Sgibbs switch (cmd) { /* Process the ioctl. */ 77897883Sgibbs case FIOASYNC: /* set/clear async i/o */ 77997883Sgibbs s = spltty(); 78097883Sgibbs if (*(int *)data) 78197883Sgibbs SET(tp->t_state, TS_ASYNC); 78297883Sgibbs else 78397883Sgibbs CLR(tp->t_state, TS_ASYNC); 78497883Sgibbs splx(s); 78597883Sgibbs break; 78697883Sgibbs case FIONBIO: /* set/clear non-blocking i/o */ 78797883Sgibbs break; /* XXX: delete. */ 78897883Sgibbs case FIONREAD: /* get # bytes to read */ 78997883Sgibbs s = spltty(); 79097883Sgibbs *(int *)data = ttnread(tp); 79197883Sgibbs splx(s); 79297883Sgibbs break; 79397883Sgibbs 79497883Sgibbs case FIOSETOWN: 79597883Sgibbs /* 79697883Sgibbs * Policy -- Don't allow FIOSETOWN on someone else's 79797883Sgibbs * controlling tty 79897883Sgibbs */ 79997883Sgibbs if (tp->t_session != NULL && !isctty(p, tp)) 80097883Sgibbs return (ENOTTY); 80197883Sgibbs 80297883Sgibbs error = fsetown(*(int *)data, &tp->t_sigio); 80397883Sgibbs if (error) 80497883Sgibbs return (error); 80597883Sgibbs break; 80697883Sgibbs case FIOGETOWN: 80797883Sgibbs if (tp->t_session != NULL && !isctty(p, tp)) 80897883Sgibbs return (ENOTTY); 80997883Sgibbs *(int *)data = fgetown(tp->t_sigio); 81097883Sgibbs break; 81197883Sgibbs 81297883Sgibbs case TIOCEXCL: /* set exclusive use of tty */ 81397883Sgibbs s = spltty(); 81497883Sgibbs SET(tp->t_state, TS_XCLUDE); 81597883Sgibbs splx(s); 81697883Sgibbs break; 81797883Sgibbs case TIOCFLUSH: { /* flush buffers */ 81897883Sgibbs register int flags = *(int *)data; 81997883Sgibbs 82097883Sgibbs if (flags == 0) 82197883Sgibbs flags = FREAD | FWRITE; 82297883Sgibbs else 82397883Sgibbs flags &= FREAD | FWRITE; 82497883Sgibbs ttyflush(tp, flags); 82597883Sgibbs break; 82697883Sgibbs } 82797883Sgibbs case TIOCCONS: /* become virtual console */ 82897883Sgibbs if (*(int *)data) { 829102684Sgibbs if (constty && constty != tp && 830102684Sgibbs ISSET(constty->t_state, TS_CONNECTED)) 831102684Sgibbs return (EBUSY); 83297883Sgibbs#ifndef UCONSOLE 83397883Sgibbs if ((error = suser(p)) != 0) 83497883Sgibbs return (error); 83597883Sgibbs#endif 83697883Sgibbs constty = tp; 83797883Sgibbs } else if (tp == constty) 83897883Sgibbs constty = NULL; 83997883Sgibbs break; 84097883Sgibbs case TIOCDRAIN: /* wait till output drained */ 84197883Sgibbs error = ttywait(tp); 84297883Sgibbs if (error) 843102684Sgibbs return (error); 844102684Sgibbs break; 845102684Sgibbs case TIOCGETA: { /* get termios struct */ 846102684Sgibbs struct termios *t = (struct termios *)data; 84797883Sgibbs 84897883Sgibbs bcopy(&tp->t_termios, t, sizeof(struct termios)); 84997883Sgibbs break; 85097883Sgibbs } 85197883Sgibbs case TIOCGETD: /* get line discipline */ 85297883Sgibbs *(int *)data = tp->t_line; 85397883Sgibbs break; 85497883Sgibbs case TIOCGWINSZ: /* get window size */ 85597883Sgibbs *(struct winsize *)data = tp->t_winsize; 85697883Sgibbs break; 85797883Sgibbs case TIOCGPGRP: /* get pgrp of tty */ 85897883Sgibbs if (!isctty(p, tp)) 85997883Sgibbs return (ENOTTY); 86097883Sgibbs *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 86197883Sgibbs break; 86297883Sgibbs#ifdef TIOCHPCL 86397883Sgibbs case TIOCHPCL: /* hang up on last close */ 86497883Sgibbs s = spltty(); 86597883Sgibbs SET(tp->t_cflag, HUPCL); 86697883Sgibbs splx(s); 86797883Sgibbs break; 86897883Sgibbs#endif 86997883Sgibbs case TIOCNXCL: /* reset exclusive use of tty */ 87097883Sgibbs s = spltty(); 87197883Sgibbs CLR(tp->t_state, TS_XCLUDE); 87297883Sgibbs splx(s); 87397883Sgibbs break; 87497883Sgibbs case TIOCOUTQ: /* output queue size */ 87597883Sgibbs *(int *)data = tp->t_outq.c_cc; 87697883Sgibbs break; 87797883Sgibbs case TIOCSETA: /* set termios struct */ 87897883Sgibbs case TIOCSETAW: /* drain output, set */ 87997883Sgibbs case TIOCSETAF: { /* drn out, fls in, set */ 88097883Sgibbs register struct termios *t = (struct termios *)data; 88197883Sgibbs 88297883Sgibbs if (t->c_ispeed == 0) 88397883Sgibbs t->c_ispeed = t->c_ospeed; 88497883Sgibbs if (t->c_ispeed == 0) 88597883Sgibbs t->c_ispeed = tp->t_ospeed; 88697883Sgibbs if (t->c_ispeed == 0) 88797883Sgibbs return (EINVAL); 88897883Sgibbs s = spltty(); 88997883Sgibbs if (cmd == TIOCSETAW || cmd == TIOCSETAF) { 89097883Sgibbs error = ttywait(tp); 89197883Sgibbs if (error) { 89297883Sgibbs splx(s); 89397883Sgibbs return (error); 89497883Sgibbs } 89597883Sgibbs if (cmd == TIOCSETAF) 89697883Sgibbs ttyflush(tp, FREAD); 89797883Sgibbs } 89897883Sgibbs if (!ISSET(t->c_cflag, CIGNORE)) { 89997883Sgibbs /* 90097883Sgibbs * Set device hardware. 90197883Sgibbs */ 90297883Sgibbs if (tp->t_param && (error = (*tp->t_param)(tp, t))) { 90397883Sgibbs splx(s); 90497883Sgibbs return (error); 90597883Sgibbs } 90697883Sgibbs if (ISSET(t->c_cflag, CLOCAL) && 90797883Sgibbs !ISSET(tp->t_cflag, CLOCAL)) { 90897883Sgibbs /* 90997883Sgibbs * XXX disconnections would be too hard to 91097883Sgibbs * get rid of without this kludge. The only 91197883Sgibbs * way to get rid of controlling terminals 91297883Sgibbs * is to exit from the session leader. 91397883Sgibbs */ 91497883Sgibbs CLR(tp->t_state, TS_ZOMBIE); 91597883Sgibbs 91697883Sgibbs wakeup(TSA_CARR_ON(tp)); 91797883Sgibbs ttwakeup(tp); 91897883Sgibbs ttwwakeup(tp); 91997883Sgibbs } 92097883Sgibbs if ((ISSET(tp->t_state, TS_CARR_ON) || 92197883Sgibbs ISSET(t->c_cflag, CLOCAL)) && 92297883Sgibbs !ISSET(tp->t_state, TS_ZOMBIE)) 92397883Sgibbs SET(tp->t_state, TS_CONNECTED); 92497883Sgibbs else 92597883Sgibbs CLR(tp->t_state, TS_CONNECTED); 92697883Sgibbs tp->t_cflag = t->c_cflag; 92797883Sgibbs tp->t_ispeed = t->c_ispeed; 92897883Sgibbs if (t->c_ospeed != 0) 92997883Sgibbs tp->t_ospeed = t->c_ospeed; 93097883Sgibbs ttsetwater(tp); 93197883Sgibbs } 93297883Sgibbs if (ISSET(t->c_lflag, ICANON) != ISSET(tp->t_lflag, ICANON) && 93397883Sgibbs cmd != TIOCSETAF) { 93497883Sgibbs if (ISSET(t->c_lflag, ICANON)) 93597883Sgibbs SET(tp->t_lflag, PENDIN); 93697883Sgibbs else { 93797883Sgibbs /* 93897883Sgibbs * XXX we really shouldn't allow toggling 93997883Sgibbs * ICANON while we're in a non-termios line 94097883Sgibbs * discipline. Now we have to worry about 94197883Sgibbs * panicing for a null queue. 94297883Sgibbs */ 94397883Sgibbs if (tp->t_canq.c_cbreserved > 0 && 94497883Sgibbs tp->t_rawq.c_cbreserved > 0) { 94597883Sgibbs catq(&tp->t_rawq, &tp->t_canq); 94697883Sgibbs /* 94797883Sgibbs * XXX the queue limits may be 94897883Sgibbs * different, so the old queue 94997883Sgibbs * swapping method no longer works. 95097883Sgibbs */ 95197883Sgibbs catq(&tp->t_canq, &tp->t_rawq); 95297883Sgibbs } 95397883Sgibbs CLR(tp->t_lflag, PENDIN); 95497883Sgibbs } 95597883Sgibbs ttwakeup(tp); 95697883Sgibbs } 95797883Sgibbs tp->t_iflag = t->c_iflag; 95897883Sgibbs tp->t_oflag = t->c_oflag; 95997883Sgibbs /* 96097883Sgibbs * Make the EXTPROC bit read only. 96197883Sgibbs */ 96297883Sgibbs if (ISSET(tp->t_lflag, EXTPROC)) 96397883Sgibbs SET(t->c_lflag, EXTPROC); 96497883Sgibbs else 96597883Sgibbs CLR(t->c_lflag, EXTPROC); 96697883Sgibbs tp->t_lflag = t->c_lflag | ISSET(tp->t_lflag, PENDIN); 96797883Sgibbs if (t->c_cc[VMIN] != tp->t_cc[VMIN] || 96897883Sgibbs t->c_cc[VTIME] != tp->t_cc[VTIME]) 96997883Sgibbs ttwakeup(tp); 97097883Sgibbs bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc)); 97197883Sgibbs splx(s); 97297883Sgibbs break; 97397883Sgibbs } 97497883Sgibbs case TIOCSETD: { /* set line discipline */ 97597883Sgibbs register int t = *(int *)data; 97697883Sgibbs dev_t device = tp->t_dev; 97797883Sgibbs 97897883Sgibbs if ((u_int)t >= nlinesw) 97997883Sgibbs return (ENXIO); 98097883Sgibbs if (t != tp->t_line) { 98197883Sgibbs s = spltty(); 98297883Sgibbs (*linesw[tp->t_line].l_close)(tp, flag); 98397883Sgibbs error = (*linesw[t].l_open)(device, tp); 98497883Sgibbs if (error) { 98597883Sgibbs (void)(*linesw[tp->t_line].l_open)(device, tp); 98697883Sgibbs splx(s); 98797883Sgibbs return (error); 98897883Sgibbs } 98997883Sgibbs tp->t_line = t; 99097883Sgibbs splx(s); 99197883Sgibbs } 99297883Sgibbs break; 99397883Sgibbs } 99497883Sgibbs case TIOCSTART: /* start output, like ^Q */ 99597883Sgibbs s = spltty(); 99697883Sgibbs if (ISSET(tp->t_state, TS_TTSTOP) || 99797883Sgibbs ISSET(tp->t_lflag, FLUSHO)) { 99897883Sgibbs CLR(tp->t_lflag, FLUSHO); 99997883Sgibbs CLR(tp->t_state, TS_TTSTOP); 100097883Sgibbs ttstart(tp); 100197883Sgibbs } 100297883Sgibbs splx(s); 100397883Sgibbs break; 100497883Sgibbs case TIOCSTI: /* simulate terminal input */ 100597883Sgibbs if ((flag & FREAD) == 0 && suser(p)) 100697883Sgibbs return (EPERM); 100797883Sgibbs if (!isctty(p, tp) && suser(p)) 100897883Sgibbs return (EACCES); 100997883Sgibbs s = spltty(); 101097883Sgibbs (*linesw[tp->t_line].l_rint)(*(u_char *)data, tp); 101197883Sgibbs splx(s); 101297883Sgibbs break; 101397883Sgibbs case TIOCSTOP: /* stop output, like ^S */ 101497883Sgibbs s = spltty(); 101597883Sgibbs if (!ISSET(tp->t_state, TS_TTSTOP)) { 101697883Sgibbs SET(tp->t_state, TS_TTSTOP); 101797883Sgibbs (*tp->t_stop)(tp, 0); 101897883Sgibbs } 101997883Sgibbs splx(s); 102097883Sgibbs break; 102197883Sgibbs case TIOCSCTTY: /* become controlling tty */ 102297883Sgibbs /* Session ctty vnode pointer set in vnode layer. */ 102397883Sgibbs if (!SESS_LEADER(p) || 102497883Sgibbs ((p->p_session->s_ttyvp || tp->t_session) && 102597883Sgibbs (tp->t_session != p->p_session))) 102697883Sgibbs return (EPERM); 102797883Sgibbs tp->t_session = p->p_session; 102897883Sgibbs tp->t_pgrp = p->p_pgrp; 102997883Sgibbs p->p_session->s_ttyp = tp; 103097883Sgibbs p->p_flag |= P_CONTROLT; 103197883Sgibbs break; 103297883Sgibbs case TIOCSPGRP: { /* set pgrp of tty */ 103397883Sgibbs register struct pgrp *pgrp = pgfind(*(int *)data); 103497883Sgibbs 103597883Sgibbs if (!isctty(p, tp)) 103697883Sgibbs return (ENOTTY); 103797883Sgibbs else if (pgrp == NULL || pgrp->pg_session != p->p_session) 103897883Sgibbs return (EPERM); 103997883Sgibbs tp->t_pgrp = pgrp; 104097883Sgibbs break; 104197883Sgibbs } 104297883Sgibbs case TIOCSTAT: /* simulate control-T */ 104397883Sgibbs s = spltty(); 104497883Sgibbs ttyinfo(tp); 104597883Sgibbs splx(s); 104697883Sgibbs break; 104797883Sgibbs case TIOCSWINSZ: /* set window size */ 104897883Sgibbs if (bcmp((caddr_t)&tp->t_winsize, data, 104997883Sgibbs sizeof (struct winsize))) { 105097883Sgibbs tp->t_winsize = *(struct winsize *)data; 105197883Sgibbs pgsignal(tp->t_pgrp, SIGWINCH, 1); 105297883Sgibbs } 105397883Sgibbs break; 105497883Sgibbs case TIOCSDRAINWAIT: 105597883Sgibbs error = suser(p); 105697883Sgibbs if (error) 105797883Sgibbs return (error); 105897883Sgibbs tp->t_timeout = *(int *)data * hz; 105997883Sgibbs wakeup(TSA_OCOMPLETE(tp)); 106097883Sgibbs wakeup(TSA_OLOWAT(tp)); 106197883Sgibbs break; 106297883Sgibbs case TIOCGDRAINWAIT: 106397883Sgibbs *(int *)data = tp->t_timeout / hz; 106497883Sgibbs break; 106597883Sgibbs default: 106697883Sgibbs#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 106797883Sgibbs return (ttcompat(tp, cmd, data, flag)); 106897883Sgibbs#else 106997883Sgibbs return (ENOIOCTL); 107097883Sgibbs#endif 107197883Sgibbs } 107297883Sgibbs return (0); 107397883Sgibbs} 107497883Sgibbs 107597883Sgibbsint 107697883Sgibbsttypoll(dev, events, p) 107797883Sgibbs dev_t dev; 107897883Sgibbs int events; 107997883Sgibbs struct proc *p; 108097883Sgibbs{ 108197883Sgibbs int s; 108297883Sgibbs int revents = 0; 108397883Sgibbs struct tty *tp; 108497883Sgibbs 108597883Sgibbs tp = dev->si_tty; 108697883Sgibbs if (tp == NULL) /* XXX used to return ENXIO, but that means true! */ 108797883Sgibbs return ((events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)) 108897883Sgibbs | POLLHUP); 108997883Sgibbs 109097883Sgibbs s = spltty(); 109197883Sgibbs if (events & (POLLIN | POLLRDNORM)) { 109297883Sgibbs if (ttnread(tp) > 0 || ISSET(tp->t_state, TS_ZOMBIE)) 109397883Sgibbs revents |= events & (POLLIN | POLLRDNORM); 109497883Sgibbs else 109597883Sgibbs selrecord(p, &tp->t_rsel); 109697883Sgibbs } 109797883Sgibbs if (events & (POLLOUT | POLLWRNORM)) { 109897883Sgibbs if ((tp->t_outq.c_cc <= tp->t_olowat && 109997883Sgibbs ISSET(tp->t_state, TS_CONNECTED)) 110097883Sgibbs || ISSET(tp->t_state, TS_ZOMBIE)) 110197883Sgibbs revents |= events & (POLLOUT | POLLWRNORM); 110297883Sgibbs else 110397883Sgibbs selrecord(p, &tp->t_wsel); 110497883Sgibbs } 110597883Sgibbs splx(s); 110697883Sgibbs return (revents); 110797883Sgibbs} 110897883Sgibbs 110997883Sgibbsstatic struct filterops ttyread_filtops = 111097883Sgibbs { 1, NULL, filt_ttyrdetach, filt_ttyread }; 111197883Sgibbsstatic struct filterops ttywrite_filtops = 111297883Sgibbs { 1, NULL, filt_ttywdetach, filt_ttywrite }; 111397883Sgibbs 111497883Sgibbsint 111597883Sgibbsttykqfilter(dev, kn) 111697883Sgibbs dev_t dev; 1117109588Sgibbs struct knote *kn; 111897883Sgibbs{ 1119109588Sgibbs struct tty *tp = dev->si_tty; 1120109588Sgibbs struct klist *klist; 1121109588Sgibbs int s; 112297883Sgibbs 112397883Sgibbs switch (kn->kn_filter) { 112497883Sgibbs case EVFILT_READ: 112597883Sgibbs klist = &tp->t_rsel.si_note; 112697883Sgibbs kn->kn_fop = &ttyread_filtops; 112797883Sgibbs break; 112897883Sgibbs case EVFILT_WRITE: 112997883Sgibbs klist = &tp->t_wsel.si_note; 113097883Sgibbs kn->kn_fop = &ttywrite_filtops; 113197883Sgibbs break; 113297883Sgibbs default: 113397883Sgibbs return (1); 113497883Sgibbs } 113597883Sgibbs 113697883Sgibbs kn->kn_hook = (caddr_t)dev; 113797883Sgibbs 113897883Sgibbs s = spltty(); 113997883Sgibbs SLIST_INSERT_HEAD(klist, kn, kn_selnext); 114097883Sgibbs splx(s); 114197883Sgibbs 114297883Sgibbs return (0); 114397883Sgibbs} 114497883Sgibbs 114597883Sgibbsstatic void 114697883Sgibbsfilt_ttyrdetach(struct knote *kn) 114797883Sgibbs{ 114897883Sgibbs struct tty *tp = ((dev_t)kn->kn_hook)->si_tty; 114997883Sgibbs int s = spltty(); 115097883Sgibbs 115197883Sgibbs SLIST_REMOVE(&tp->t_rsel.si_note, kn, knote, kn_selnext); 115297883Sgibbs splx(s); 115397883Sgibbs} 115497883Sgibbs 115597883Sgibbsstatic int 115697883Sgibbsfilt_ttyread(struct knote *kn, long hint) 115797883Sgibbs{ 115897883Sgibbs struct tty *tp = ((dev_t)kn->kn_hook)->si_tty; 115997883Sgibbs 116097883Sgibbs kn->kn_data = ttnread(tp); 116197883Sgibbs if (ISSET(tp->t_state, TS_ZOMBIE)) { 116297883Sgibbs kn->kn_flags |= EV_EOF; 116397883Sgibbs return (1); 116497883Sgibbs } 116597883Sgibbs return (kn->kn_data > 0); 116697883Sgibbs} 116797883Sgibbs 116897883Sgibbsstatic void 116997883Sgibbsfilt_ttywdetach(struct knote *kn) 117097883Sgibbs{ 117197883Sgibbs struct tty *tp = ((dev_t)kn->kn_hook)->si_tty; 117297883Sgibbs int s = spltty(); 117397883Sgibbs 117497883Sgibbs SLIST_REMOVE(&tp->t_wsel.si_note, kn, knote, kn_selnext); 117597883Sgibbs splx(s); 117697883Sgibbs} 117797883Sgibbs 117897883Sgibbsstatic int 117997883Sgibbsfilt_ttywrite(kn, hint) 118097883Sgibbs struct knote *kn; 118197883Sgibbs long hint; 118297883Sgibbs{ 118397883Sgibbs struct tty *tp = ((dev_t)kn->kn_hook)->si_tty; 118497883Sgibbs 118597883Sgibbs kn->kn_data = tp->t_outq.c_cc; 118697883Sgibbs if (ISSET(tp->t_state, TS_ZOMBIE)) 118797883Sgibbs return (1); 118897883Sgibbs return (kn->kn_data <= tp->t_olowat && 118997883Sgibbs ISSET(tp->t_state, TS_CONNECTED)); 119097883Sgibbs} 1191111653Sgibbs 1192111653Sgibbs/* 1193111653Sgibbs * Must be called at spltty(). 1194111653Sgibbs */ 1195111653Sgibbsstatic int 119697883Sgibbsttnread(tp) 119797883Sgibbs struct tty *tp; 119897883Sgibbs{ 119997883Sgibbs int nread; 120097883Sgibbs 120197883Sgibbs if (ISSET(tp->t_lflag, PENDIN)) 120297883Sgibbs ttypend(tp); 120397883Sgibbs nread = tp->t_canq.c_cc; 120497883Sgibbs if (!ISSET(tp->t_lflag, ICANON)) { 1205111653Sgibbs nread += tp->t_rawq.c_cc; 120697883Sgibbs if (nread < tp->t_cc[VMIN] && tp->t_cc[VTIME] == 0) 1207111653Sgibbs nread = 0; 1208111653Sgibbs } 1209111653Sgibbs return (nread); 121097883Sgibbs} 121197883Sgibbs 121297883Sgibbs/* 121397883Sgibbs * Wait for output to drain. 121497883Sgibbs */ 121597883Sgibbsint 121697883Sgibbsttywait(tp) 121797883Sgibbs register struct tty *tp; 121897883Sgibbs{ 121997883Sgibbs int error, s; 122097883Sgibbs 122197883Sgibbs error = 0; 122297883Sgibbs s = spltty(); 122397883Sgibbs while ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) && 122497883Sgibbs ISSET(tp->t_state, TS_CONNECTED) && tp->t_oproc) { 122597883Sgibbs (*tp->t_oproc)(tp); 122697883Sgibbs if ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) && 122797883Sgibbs ISSET(tp->t_state, TS_CONNECTED)) { 122897883Sgibbs SET(tp->t_state, TS_SO_OCOMPLETE); 122997883Sgibbs error = ttysleep(tp, TSA_OCOMPLETE(tp), 123097883Sgibbs TTOPRI | PCATCH, "ttywai", 123197883Sgibbs tp->t_timeout); 123297883Sgibbs if (error) { 123397883Sgibbs if (error == EWOULDBLOCK) 123497883Sgibbs error = EIO; 123597883Sgibbs break; 123697883Sgibbs } 123797883Sgibbs } else 123897883Sgibbs break; 123997883Sgibbs } 124097883Sgibbs if (!error && (tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY))) 124197883Sgibbs error = EIO; 124297883Sgibbs splx(s); 124397883Sgibbs return (error); 124497883Sgibbs} 124597883Sgibbs 124697883Sgibbs/* 124797883Sgibbs * Flush if successfully wait. 124897883Sgibbs */ 124997883Sgibbsstatic int 125097883Sgibbsttywflush(tp) 125197883Sgibbs struct tty *tp; 125297883Sgibbs{ 125397883Sgibbs int error; 125497883Sgibbs 125597883Sgibbs if ((error = ttywait(tp)) == 0) 125697883Sgibbs ttyflush(tp, FREAD); 125797883Sgibbs return (error); 125897883Sgibbs} 125997883Sgibbs 126097883Sgibbs/* 126197883Sgibbs * Flush tty read and/or write queues, notifying anyone waiting. 126297883Sgibbs */ 126397883Sgibbsvoid 126497883Sgibbsttyflush(tp, rw) 126597883Sgibbs register struct tty *tp; 126697883Sgibbs int rw; 126797883Sgibbs{ 1268113296Sjake register int s; 1269113296Sjake 127097883Sgibbs s = spltty(); 127197883Sgibbs#if 0 127297883Sgibbsagain: 127397883Sgibbs#endif 127497883Sgibbs if (rw & FWRITE) { 127597883Sgibbs FLUSHQ(&tp->t_outq); 127697883Sgibbs CLR(tp->t_state, TS_TTSTOP); 127797883Sgibbs } 127897883Sgibbs (*tp->t_stop)(tp, rw); 127997883Sgibbs if (rw & FREAD) { 128097883Sgibbs FLUSHQ(&tp->t_canq); 128197883Sgibbs FLUSHQ(&tp->t_rawq); 128297883Sgibbs CLR(tp->t_lflag, PENDIN); 128397883Sgibbs tp->t_rocount = 0; 128497883Sgibbs tp->t_rocol = 0; 128597883Sgibbs CLR(tp->t_state, TS_LOCAL); 128697883Sgibbs ttwakeup(tp); 128797883Sgibbs if (ISSET(tp->t_state, TS_TBLOCK)) { 128897883Sgibbs if (rw & FWRITE) 128997883Sgibbs FLUSHQ(&tp->t_outq); 129097883Sgibbs ttyunblock(tp); 129197883Sgibbs 129297883Sgibbs /* 129397883Sgibbs * Don't let leave any state that might clobber the 129497883Sgibbs * next line discipline (although we should do more 129597883Sgibbs * to send the START char). Not clearing the state 129697883Sgibbs * may have caused the "putc to a clist with no 129797883Sgibbs * reserved cblocks" panic/printf. 129897883Sgibbs */ 129997883Sgibbs CLR(tp->t_state, TS_TBLOCK); 130097883Sgibbs 130197883Sgibbs#if 0 /* forget it, sleeping isn't always safe and we don't know when it is */ 130297883Sgibbs if (ISSET(tp->t_iflag, IXOFF)) { 130397883Sgibbs /* 130497883Sgibbs * XXX wait a bit in the hope that the stop 130597883Sgibbs * character (if any) will go out. Waiting 130697883Sgibbs * isn't good since it allows races. This 130797883Sgibbs * will be fixed when the stop character is 130897883Sgibbs * put in a special queue. Don't bother with 130997883Sgibbs * the checks in ttywait() since the timeout 131097883Sgibbs * will save us. 131197883Sgibbs */ 131297883Sgibbs SET(tp->t_state, TS_SO_OCOMPLETE); 131397883Sgibbs ttysleep(tp, TSA_OCOMPLETE(tp), TTOPRI, 131497883Sgibbs "ttyfls", hz / 10); 131597883Sgibbs /* 131697883Sgibbs * Don't try sending the stop character again. 131797883Sgibbs */ 131897883Sgibbs CLR(tp->t_state, TS_TBLOCK); 131997883Sgibbs goto again; 132097883Sgibbs } 132197883Sgibbs#endif 132297883Sgibbs } 132397883Sgibbs } 132497883Sgibbs if (rw & FWRITE) { 132597883Sgibbs FLUSHQ(&tp->t_outq); 132697883Sgibbs ttwwakeup(tp); 132797883Sgibbs } 132897883Sgibbs splx(s); 132997883Sgibbs} 133097883Sgibbs 133197883Sgibbs/* 133297883Sgibbs * Copy in the default termios characters. 133397883Sgibbs */ 133497883Sgibbsvoid 133597883Sgibbstermioschars(t) 133697883Sgibbs struct termios *t; 133797883Sgibbs{ 133897883Sgibbs 133997883Sgibbs bcopy(ttydefchars, t->c_cc, sizeof t->c_cc); 134097883Sgibbs} 134197883Sgibbs 134297883Sgibbs/* 134397883Sgibbs * Old interface. 134497883Sgibbs */ 134597883Sgibbsvoid 134697883Sgibbsttychars(tp) 134797883Sgibbs struct tty *tp; 134897883Sgibbs{ 134997883Sgibbs 135097883Sgibbs termioschars(&tp->t_termios); 135197883Sgibbs} 135297883Sgibbs 135397883Sgibbs/* 135497883Sgibbs * Handle input high water. Send stop character for the IXOFF case. Turn 135597883Sgibbs * on our input flow control bit and propagate the changes to the driver. 135697883Sgibbs * XXX the stop character should be put in a special high priority queue. 135797883Sgibbs */ 135897883Sgibbsvoid 135997883Sgibbsttyblock(tp) 136097883Sgibbs struct tty *tp; 136197883Sgibbs{ 136297883Sgibbs 136397883Sgibbs SET(tp->t_state, TS_TBLOCK); 136497883Sgibbs if (ISSET(tp->t_iflag, IXOFF) && tp->t_cc[VSTOP] != _POSIX_VDISABLE && 136597883Sgibbs putc(tp->t_cc[VSTOP], &tp->t_outq) != 0) 136697883Sgibbs CLR(tp->t_state, TS_TBLOCK); /* try again later */ 136797883Sgibbs ttstart(tp); 136897883Sgibbs} 136997883Sgibbs 137097883Sgibbs/* 137197883Sgibbs * Handle input low water. Send start character for the IXOFF case. Turn 137297883Sgibbs * off our input flow control bit and propagate the changes to the driver. 137397883Sgibbs * XXX the start character should be put in a special high priority queue. 137497883Sgibbs */ 137597883Sgibbsstatic void 137697883Sgibbsttyunblock(tp) 137797883Sgibbs struct tty *tp; 137897883Sgibbs{ 137997883Sgibbs 138097883Sgibbs CLR(tp->t_state, TS_TBLOCK); 138197883Sgibbs if (ISSET(tp->t_iflag, IXOFF) && tp->t_cc[VSTART] != _POSIX_VDISABLE && 138297883Sgibbs putc(tp->t_cc[VSTART], &tp->t_outq) != 0) 138397883Sgibbs SET(tp->t_state, TS_TBLOCK); /* try again later */ 138497883Sgibbs ttstart(tp); 138597883Sgibbs} 138697883Sgibbs 138797883Sgibbs#ifdef notyet 138897883Sgibbs/* Not used by any current (i386) drivers. */ 138997883Sgibbs/* 139097883Sgibbs * Restart after an inter-char delay. 139197883Sgibbs */ 139297883Sgibbsvoid 139397883Sgibbsttrstrt(tp_arg) 139497883Sgibbs void *tp_arg; 139597883Sgibbs{ 139697883Sgibbs struct tty *tp; 139797883Sgibbs int s; 139897883Sgibbs 139997883Sgibbs KASSERT(tp_arg != NULL, ("ttrstrt")); 140097883Sgibbs 140197883Sgibbs tp = tp_arg; 140297883Sgibbs s = spltty(); 140397883Sgibbs 140497883Sgibbs CLR(tp->t_state, TS_TIMEOUT); 140597883Sgibbs ttstart(tp); 140697883Sgibbs 140797883Sgibbs splx(s); 140897883Sgibbs} 140997883Sgibbs#endif 141097883Sgibbs 141197883Sgibbsint 141297883Sgibbsttstart(tp) 141397883Sgibbs struct tty *tp; 141497883Sgibbs{ 141597883Sgibbs 141697883Sgibbs if (tp->t_oproc != NULL) /* XXX: Kludge for pty. */ 141797883Sgibbs (*tp->t_oproc)(tp); 141897883Sgibbs return (0); 141997883Sgibbs} 142097883Sgibbs 142197883Sgibbs/* 142297883Sgibbs * "close" a line discipline 142397883Sgibbs */ 142497883Sgibbsint 142597883Sgibbsttylclose(tp, flag) 142697883Sgibbs struct tty *tp; 142797883Sgibbs int flag; 142897883Sgibbs{ 142997883Sgibbs 143097883Sgibbs if (flag & FNONBLOCK || ttywflush(tp)) 143197883Sgibbs ttyflush(tp, FREAD | FWRITE); 143297883Sgibbs return (0); 143397883Sgibbs} 143497883Sgibbs 143597883Sgibbs/* 143697883Sgibbs * Handle modem control transition on a tty. 143797883Sgibbs * Flag indicates new state of carrier. 143897883Sgibbs * Returns 0 if the line should be turned off, otherwise 1. 143997883Sgibbs */ 144097883Sgibbsint 144197883Sgibbsttymodem(tp, flag) 144297883Sgibbs register struct tty *tp; 144397883Sgibbs int flag; 144497883Sgibbs{ 144597883Sgibbs 144697883Sgibbs if (ISSET(tp->t_state, TS_CARR_ON) && ISSET(tp->t_cflag, MDMBUF)) { 144797883Sgibbs /* 144897883Sgibbs * MDMBUF: do flow control according to carrier flag 144997883Sgibbs * XXX TS_CAR_OFLOW doesn't do anything yet. TS_TTSTOP 145097883Sgibbs * works if IXON and IXANY are clear. 145197883Sgibbs */ 145297883Sgibbs if (flag) { 145397883Sgibbs CLR(tp->t_state, TS_CAR_OFLOW); 145497883Sgibbs CLR(tp->t_state, TS_TTSTOP); 145597883Sgibbs ttstart(tp); 145697883Sgibbs } else if (!ISSET(tp->t_state, TS_CAR_OFLOW)) { 145797883Sgibbs SET(tp->t_state, TS_CAR_OFLOW); 145897883Sgibbs SET(tp->t_state, TS_TTSTOP); 145997883Sgibbs (*tp->t_stop)(tp, 0); 146097883Sgibbs } 146197883Sgibbs } else if (flag == 0) { 146297883Sgibbs /* 146397883Sgibbs * Lost carrier. 146497883Sgibbs */ 146597883Sgibbs CLR(tp->t_state, TS_CARR_ON); 146697883Sgibbs if (ISSET(tp->t_state, TS_ISOPEN) && 146797883Sgibbs !ISSET(tp->t_cflag, CLOCAL)) { 146897883Sgibbs SET(tp->t_state, TS_ZOMBIE); 146997883Sgibbs CLR(tp->t_state, TS_CONNECTED); 147097883Sgibbs if (tp->t_session && tp->t_session->s_leader) { 147197883Sgibbs struct proc *p; 147297883Sgibbs 147397883Sgibbs p = tp->t_session->s_leader; 147497883Sgibbs PROC_LOCK(p); 147597883Sgibbs psignal(p, SIGHUP); 147697883Sgibbs PROC_UNLOCK(p); 147797883Sgibbs } 147897883Sgibbs ttyflush(tp, FREAD | FWRITE); 147997883Sgibbs return (0); 148097883Sgibbs } 148197883Sgibbs } else { 148297883Sgibbs /* 148397883Sgibbs * Carrier now on. 148497883Sgibbs */ 148597883Sgibbs SET(tp->t_state, TS_CARR_ON); 148697883Sgibbs if (!ISSET(tp->t_state, TS_ZOMBIE)) 148797883Sgibbs SET(tp->t_state, TS_CONNECTED); 148897883Sgibbs wakeup(TSA_CARR_ON(tp)); 148997883Sgibbs ttwakeup(tp); 149097883Sgibbs ttwwakeup(tp); 149197883Sgibbs } 149297883Sgibbs return (1); 149397883Sgibbs} 149497883Sgibbs 149597883Sgibbs/* 149697883Sgibbs * Reinput pending characters after state switch 149797883Sgibbs * call at spltty(). 149897883Sgibbs */ 149997883Sgibbsstatic void 150097883Sgibbsttypend(tp) 150197883Sgibbs register struct tty *tp; 150297883Sgibbs{ 150397883Sgibbs struct clist tq; 150497883Sgibbs register int c; 150597883Sgibbs 150697883Sgibbs CLR(tp->t_lflag, PENDIN); 150797883Sgibbs SET(tp->t_state, TS_TYPEN); 150897883Sgibbs /* 150997883Sgibbs * XXX this assumes too much about clist internals. It may even 151097883Sgibbs * fail if the cblock slush pool is empty. We can't allocate more 151197883Sgibbs * cblocks here because we are called from an interrupt handler 151297883Sgibbs * and clist_alloc_cblocks() can wait. 151397883Sgibbs */ 151497883Sgibbs tq = tp->t_rawq; 151597883Sgibbs bzero(&tp->t_rawq, sizeof tp->t_rawq); 151697883Sgibbs tp->t_rawq.c_cbmax = tq.c_cbmax; 151797883Sgibbs tp->t_rawq.c_cbreserved = tq.c_cbreserved; 151897883Sgibbs while ((c = getc(&tq)) >= 0) 151997883Sgibbs ttyinput(c, tp); 152097883Sgibbs CLR(tp->t_state, TS_TYPEN); 152197883Sgibbs} 152297883Sgibbs 152397883Sgibbs/* 152497883Sgibbs * Process a read call on a tty device. 152597883Sgibbs */ 152697883Sgibbsint 152797883Sgibbsttread(tp, uio, flag) 152897883Sgibbs register struct tty *tp; 152997883Sgibbs struct uio *uio; 153097883Sgibbs int flag; 153197883Sgibbs{ 153297883Sgibbs register struct clist *qp; 153397883Sgibbs register int c; 153497883Sgibbs register tcflag_t lflag; 153597883Sgibbs register cc_t *cc = tp->t_cc; 153697883Sgibbs register struct proc *p = curproc; 153797883Sgibbs int s, first, error = 0; 153897883Sgibbs int has_stime = 0, last_cc = 0; 153997883Sgibbs long slp = 0; /* XXX this should be renamed `timo'. */ 154097883Sgibbs struct timeval stime; 154197883Sgibbs 154297883Sgibbsloop: 154397883Sgibbs s = spltty(); 154497883Sgibbs lflag = tp->t_lflag; 154597883Sgibbs /* 154697883Sgibbs * take pending input first 154797883Sgibbs */ 154897883Sgibbs if (ISSET(lflag, PENDIN)) { 154997883Sgibbs ttypend(tp); 155097883Sgibbs splx(s); /* reduce latency */ 155197883Sgibbs s = spltty(); 155297883Sgibbs lflag = tp->t_lflag; /* XXX ttypend() clobbers it */ 155397883Sgibbs } 155497883Sgibbs 155597883Sgibbs /* 155697883Sgibbs * Hang process if it's in the background. 155797883Sgibbs */ 155897883Sgibbs if (isbackground(p, tp)) { 155997883Sgibbs splx(s); 156097883Sgibbs if (SIGISMEMBER(p->p_sigignore, SIGTTIN) || 156197883Sgibbs SIGISMEMBER(p->p_sigmask, SIGTTIN) || 156297883Sgibbs (p->p_flag & P_PPWAIT) || p->p_pgrp->pg_jobc == 0) 156397883Sgibbs return (EIO); 156497883Sgibbs pgsignal(p->p_pgrp, SIGTTIN, 1); 156597883Sgibbs error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, "ttybg2", 0); 156697883Sgibbs if (error) 156797883Sgibbs return (error); 156897883Sgibbs goto loop; 156997883Sgibbs } 157097883Sgibbs 157197883Sgibbs if (ISSET(tp->t_state, TS_ZOMBIE)) { 157297883Sgibbs splx(s); 157397883Sgibbs return (0); /* EOF */ 157497883Sgibbs } 157597883Sgibbs 157697883Sgibbs /* 157797883Sgibbs * If canonical, use the canonical queue, 157897883Sgibbs * else use the raw queue. 157997883Sgibbs * 158097883Sgibbs * (should get rid of clists...) 158197883Sgibbs */ 158297883Sgibbs qp = ISSET(lflag, ICANON) ? &tp->t_canq : &tp->t_rawq; 158397883Sgibbs 158497883Sgibbs if (flag & IO_NDELAY) { 158597883Sgibbs if (qp->c_cc > 0) 158697883Sgibbs goto read; 158797883Sgibbs if (!ISSET(lflag, ICANON) && cc[VMIN] == 0) { 158897883Sgibbs splx(s); 158997883Sgibbs return (0); 159097883Sgibbs } 159197883Sgibbs splx(s); 159297883Sgibbs return (EWOULDBLOCK); 159397883Sgibbs } 159497883Sgibbs if (!ISSET(lflag, ICANON)) { 159597883Sgibbs int m = cc[VMIN]; 159697883Sgibbs long t = cc[VTIME]; 159797883Sgibbs struct timeval timecopy; 159897883Sgibbs 159997883Sgibbs /* 160097883Sgibbs * Check each of the four combinations. 160197883Sgibbs * (m > 0 && t == 0) is the normal read case. 160297883Sgibbs * It should be fairly efficient, so we check that and its 160397883Sgibbs * companion case (m == 0 && t == 0) first. 160497883Sgibbs * For the other two cases, we compute the target sleep time 160597883Sgibbs * into slp. 160697883Sgibbs */ 160797883Sgibbs if (t == 0) { 160897883Sgibbs if (qp->c_cc < m) 160997883Sgibbs goto sleep; 161097883Sgibbs if (qp->c_cc > 0) 161197883Sgibbs goto read; 161297883Sgibbs 161397883Sgibbs /* m, t and qp->c_cc are all 0. 0 is enough input. */ 161497883Sgibbs splx(s); 161597883Sgibbs return (0); 161697883Sgibbs } 161797883Sgibbs t *= 100000; /* time in us */ 161897883Sgibbs#define diff(t1, t2) (((t1).tv_sec - (t2).tv_sec) * 1000000 + \ 161997883Sgibbs ((t1).tv_usec - (t2).tv_usec)) 162097883Sgibbs if (m > 0) { 162197883Sgibbs if (qp->c_cc <= 0) 162297883Sgibbs goto sleep; 162397883Sgibbs if (qp->c_cc >= m) 162497883Sgibbs goto read; 162597883Sgibbs getmicrotime(&timecopy); 162697883Sgibbs if (!has_stime) { 162797883Sgibbs /* first character, start timer */ 162897883Sgibbs has_stime = 1; 162997883Sgibbs stime = timecopy; 163097883Sgibbs slp = t; 163197883Sgibbs } else if (qp->c_cc > last_cc) { 163297883Sgibbs /* got a character, restart timer */ 163397883Sgibbs stime = timecopy; 163497883Sgibbs slp = t; 163597883Sgibbs } else { 163697883Sgibbs /* nothing, check expiration */ 163797883Sgibbs slp = t - diff(timecopy, stime); 163897883Sgibbs if (slp <= 0) 163997883Sgibbs goto read; 164097883Sgibbs } 164197883Sgibbs last_cc = qp->c_cc; 164297883Sgibbs } else { /* m == 0 */ 164397883Sgibbs if (qp->c_cc > 0) 164497883Sgibbs goto read; 164597883Sgibbs getmicrotime(&timecopy); 164697883Sgibbs if (!has_stime) { 164797883Sgibbs has_stime = 1; 164897883Sgibbs stime = timecopy; 164997883Sgibbs slp = t; 165097883Sgibbs } else { 165197883Sgibbs slp = t - diff(timecopy, stime); 165297883Sgibbs if (slp <= 0) { 165397883Sgibbs /* Timed out, but 0 is enough input. */ 165497883Sgibbs splx(s); 165597883Sgibbs return (0); 165697883Sgibbs } 165797883Sgibbs } 165897883Sgibbs } 165997883Sgibbs#undef diff 166097883Sgibbs /* 166197883Sgibbs * Rounding down may make us wake up just short 166297883Sgibbs * of the target, so we round up. 166397883Sgibbs * The formula is ceiling(slp * hz/1000000). 166497883Sgibbs * 32-bit arithmetic is enough for hz < 169. 166597883Sgibbs * XXX see tvtohz() for how to avoid overflow if hz 166697883Sgibbs * is large (divide by `tick' and/or arrange to 166797883Sgibbs * use tvtohz() if hz is large). 166897883Sgibbs */ 166997883Sgibbs slp = (long) (((u_long)slp * hz) + 999999) / 1000000; 167097883Sgibbs goto sleep; 167197883Sgibbs } 167297883Sgibbs if (qp->c_cc <= 0) { 167397883Sgibbssleep: 167497883Sgibbs /* 167597883Sgibbs * There is no input, or not enough input and we can block. 167697883Sgibbs */ 167797883Sgibbs error = ttysleep(tp, TSA_HUP_OR_INPUT(tp), TTIPRI | PCATCH, 167897883Sgibbs ISSET(tp->t_state, TS_CONNECTED) ? 167997883Sgibbs "ttyin" : "ttyhup", (int)slp); 168097883Sgibbs splx(s); 168197883Sgibbs if (error == EWOULDBLOCK) 168297883Sgibbs error = 0; 168397883Sgibbs else if (error) 168497883Sgibbs return (error); 168597883Sgibbs /* 168697883Sgibbs * XXX what happens if another process eats some input 168797883Sgibbs * while we are asleep (not just here)? It would be 168897883Sgibbs * safest to detect changes and reset our state variables 168997883Sgibbs * (has_stime and last_cc). 169097883Sgibbs */ 169197883Sgibbs slp = 0; 169297883Sgibbs goto loop; 169397883Sgibbs } 169497883Sgibbsread: 169597883Sgibbs splx(s); 169697883Sgibbs /* 169797883Sgibbs * Input present, check for input mapping and processing. 169897883Sgibbs */ 169997883Sgibbs first = 1; 170097883Sgibbs if (ISSET(lflag, ICANON | ISIG)) 170197883Sgibbs goto slowcase; 170297883Sgibbs for (;;) { 170397883Sgibbs char ibuf[IBUFSIZ]; 170497883Sgibbs int icc; 170597883Sgibbs 170697883Sgibbs icc = imin(uio->uio_resid, IBUFSIZ); 170797883Sgibbs icc = q_to_b(qp, ibuf, icc); 170897883Sgibbs if (icc <= 0) { 170997883Sgibbs if (first) 171097883Sgibbs goto loop; 171197883Sgibbs break; 171297883Sgibbs } 171397883Sgibbs error = uiomove(ibuf, icc, uio); 171497883Sgibbs /* 171597883Sgibbs * XXX if there was an error then we should ungetc() the 171697883Sgibbs * unmoved chars and reduce icc here. 171797883Sgibbs */ 171897883Sgibbs#ifdef DEV_SNP 171997883Sgibbs if (ISSET(tp->t_lflag, ECHO) && 172097883Sgibbs ISSET(tp->t_state, TS_SNOOP) && tp->t_sc != NULL) 172197883Sgibbs snpin((struct snoop *)tp->t_sc, ibuf, icc); 172297883Sgibbs#endif 172397883Sgibbs if (error) 172497883Sgibbs break; 172597883Sgibbs if (uio->uio_resid == 0) 172697883Sgibbs break; 172797883Sgibbs first = 0; 172897883Sgibbs } 172997883Sgibbs goto out; 173097883Sgibbsslowcase: 173197883Sgibbs for (;;) { 173297883Sgibbs c = getc(qp); 173397883Sgibbs if (c < 0) { 173497883Sgibbs if (first) 173597883Sgibbs goto loop; 173697883Sgibbs break; 173797883Sgibbs } 173897883Sgibbs /* 173997883Sgibbs * delayed suspend (^Y) 174097883Sgibbs */ 174197883Sgibbs if (CCEQ(cc[VDSUSP], c) && 174297883Sgibbs ISSET(lflag, IEXTEN | ISIG) == (IEXTEN | ISIG)) { 174397883Sgibbs pgsignal(tp->t_pgrp, SIGTSTP, 1); 174497883Sgibbs if (first) { 174597883Sgibbs error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, 174697883Sgibbs "ttybg3", 0); 174797883Sgibbs if (error) 174897883Sgibbs break; 174997883Sgibbs goto loop; 175097883Sgibbs } 175197883Sgibbs break; 175297883Sgibbs } 175397883Sgibbs /* 175497883Sgibbs * Interpret EOF only in canonical mode. 175597883Sgibbs */ 175697883Sgibbs if (CCEQ(cc[VEOF], c) && ISSET(lflag, ICANON)) 175797883Sgibbs break; 175897883Sgibbs /* 175997883Sgibbs * Give user character. 176097883Sgibbs */ 176197883Sgibbs error = ureadc(c, uio); 176297883Sgibbs if (error) 176397883Sgibbs /* XXX should ungetc(c, qp). */ 176497883Sgibbs break; 176597883Sgibbs#ifdef DEV_SNP 176697883Sgibbs /* 176797883Sgibbs * Only snoop directly on input in echo mode. Non-echoed 176897883Sgibbs * input will be snooped later iff the application echoes it. 176997883Sgibbs */ 177097883Sgibbs if (ISSET(tp->t_lflag, ECHO) && 177197883Sgibbs ISSET(tp->t_state, TS_SNOOP) && tp->t_sc != NULL) 177297883Sgibbs snpinc((struct snoop *)tp->t_sc, (char)c); 177397883Sgibbs#endif 177497883Sgibbs if (uio->uio_resid == 0) 177597883Sgibbs break; 177697883Sgibbs /* 177797883Sgibbs * In canonical mode check for a "break character" 177897883Sgibbs * marking the end of a "line of input". 177997883Sgibbs */ 178097883Sgibbs if (ISSET(lflag, ICANON) && TTBREAKC(c, lflag)) 178197883Sgibbs break; 178297883Sgibbs first = 0; 178397883Sgibbs } 178497883Sgibbs 178597883Sgibbsout: 178697883Sgibbs /* 178797883Sgibbs * Look to unblock input now that (presumably) 178897883Sgibbs * the input queue has gone down. 178997883Sgibbs */ 179097883Sgibbs s = spltty(); 179197883Sgibbs if (ISSET(tp->t_state, TS_TBLOCK) && 179297883Sgibbs tp->t_rawq.c_cc + tp->t_canq.c_cc <= tp->t_ilowat) 179397883Sgibbs ttyunblock(tp); 179497883Sgibbs splx(s); 179597883Sgibbs 179697883Sgibbs return (error); 179797883Sgibbs} 179897883Sgibbs 179997883Sgibbs/* 180097883Sgibbs * Check the output queue on tp for space for a kernel message (from uprintf 180197883Sgibbs * or tprintf). Allow some space over the normal hiwater mark so we don't 180297883Sgibbs * lose messages due to normal flow control, but don't let the tty run amok. 180397883Sgibbs * Sleeps here are not interruptible, but we return prematurely if new signals 180497883Sgibbs * arrive. 180597883Sgibbs */ 180697883Sgibbsint 180797883Sgibbsttycheckoutq(tp, wait) 180897883Sgibbs register struct tty *tp; 180997883Sgibbs int wait; 181097883Sgibbs{ 181197883Sgibbs int hiwat, s; 181297883Sgibbs sigset_t oldmask; 181397883Sgibbs 181497883Sgibbs hiwat = tp->t_ohiwat; 181597883Sgibbs SIGEMPTYSET(oldmask); 181697883Sgibbs s = spltty(); 181797883Sgibbs if (wait) 181897883Sgibbs oldmask = curproc->p_siglist; 181997883Sgibbs if (tp->t_outq.c_cc > hiwat + OBUFSIZ + 100) 182097883Sgibbs while (tp->t_outq.c_cc > hiwat) { 182197883Sgibbs ttstart(tp); 182297883Sgibbs if (tp->t_outq.c_cc <= hiwat) 182397883Sgibbs break; 182497883Sgibbs if (!(wait && SIGSETEQ(curproc->p_siglist, oldmask))) { 182597883Sgibbs splx(s); 182697883Sgibbs return (0); 182797883Sgibbs } 182897883Sgibbs SET(tp->t_state, TS_SO_OLOWAT); 182997883Sgibbs tsleep(TSA_OLOWAT(tp), PZERO - 1, "ttoutq", hz); 183097883Sgibbs } 183197883Sgibbs splx(s); 183297883Sgibbs return (1); 183397883Sgibbs} 183497883Sgibbs 183597883Sgibbs/* 183697883Sgibbs * Process a write call on a tty device. 183797883Sgibbs */ 183897883Sgibbsint 183997883Sgibbsttwrite(tp, uio, flag) 184097883Sgibbs register struct tty *tp; 184197883Sgibbs register struct uio *uio; 184297883Sgibbs int flag; 184397883Sgibbs{ 184497883Sgibbs register char *cp = NULL; 184597883Sgibbs register int cc, ce; 184697883Sgibbs register struct proc *p; 184797883Sgibbs int i, hiwat, cnt, error, s; 184897883Sgibbs char obuf[OBUFSIZ]; 184997883Sgibbs 185097883Sgibbs hiwat = tp->t_ohiwat; 185197883Sgibbs cnt = uio->uio_resid; 185297883Sgibbs error = 0; 185397883Sgibbs cc = 0; 185497883Sgibbsloop: 185597883Sgibbs s = spltty(); 185697883Sgibbs if (ISSET(tp->t_state, TS_ZOMBIE)) { 185797883Sgibbs splx(s); 185897883Sgibbs if (uio->uio_resid == cnt) 185997883Sgibbs error = EIO; 186097883Sgibbs goto out; 186197883Sgibbs } 186297883Sgibbs if (!ISSET(tp->t_state, TS_CONNECTED)) { 186397883Sgibbs if (flag & IO_NDELAY) { 186497883Sgibbs splx(s); 186597883Sgibbs error = EWOULDBLOCK; 186697883Sgibbs goto out; 186797883Sgibbs } 186897883Sgibbs error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH, 186997883Sgibbs "ttydcd", 0); 187097883Sgibbs splx(s); 187197883Sgibbs if (error) 187297883Sgibbs goto out; 187397883Sgibbs goto loop; 187497883Sgibbs } 187597883Sgibbs splx(s); 187697883Sgibbs /* 187797883Sgibbs * Hang the process if it's in the background. 187897883Sgibbs */ 187997883Sgibbs p = curproc; 188097883Sgibbs if (isbackground(p, tp) && 188197883Sgibbs ISSET(tp->t_lflag, TOSTOP) && !(p->p_flag & P_PPWAIT) && 188297883Sgibbs !SIGISMEMBER(p->p_sigignore, SIGTTOU) && 188397883Sgibbs !SIGISMEMBER(p->p_sigmask, SIGTTOU)) { 188497883Sgibbs if (p->p_pgrp->pg_jobc == 0) { 188597883Sgibbs error = EIO; 188697883Sgibbs goto out; 188797883Sgibbs } 188897883Sgibbs pgsignal(p->p_pgrp, SIGTTOU, 1); 188997883Sgibbs error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, "ttybg4", 0); 189097883Sgibbs if (error) 189197883Sgibbs goto out; 189297883Sgibbs goto loop; 189397883Sgibbs } 189497883Sgibbs /* 189597883Sgibbs * Process the user's data in at most OBUFSIZ chunks. Perform any 189697883Sgibbs * output translation. Keep track of high water mark, sleep on 189797883Sgibbs * overflow awaiting device aid in acquiring new space. 189897883Sgibbs */ 189997883Sgibbs while (uio->uio_resid > 0 || cc > 0) { 190097883Sgibbs if (ISSET(tp->t_lflag, FLUSHO)) { 190197883Sgibbs uio->uio_resid = 0; 190297883Sgibbs return (0); 190397883Sgibbs } 190497883Sgibbs if (tp->t_outq.c_cc > hiwat) 190597883Sgibbs goto ovhiwat; 190697883Sgibbs /* 190797883Sgibbs * Grab a hunk of data from the user, unless we have some 190897883Sgibbs * leftover from last time. 190997883Sgibbs */ 191097883Sgibbs if (cc == 0) { 191197883Sgibbs cc = imin(uio->uio_resid, OBUFSIZ); 191297883Sgibbs cp = obuf; 191397883Sgibbs error = uiomove(cp, cc, uio); 191497883Sgibbs if (error) { 191597883Sgibbs cc = 0; 191697883Sgibbs break; 191797883Sgibbs } 191897883Sgibbs#ifdef DEV_SNP 191997883Sgibbs if (ISSET(tp->t_state, TS_SNOOP) && tp->t_sc != NULL) 192097883Sgibbs snpin((struct snoop *)tp->t_sc, cp, cc); 192197883Sgibbs#endif 192297883Sgibbs } 192397883Sgibbs /* 192497883Sgibbs * If nothing fancy need be done, grab those characters we 192597883Sgibbs * can handle without any of ttyoutput's processing and 192697883Sgibbs * just transfer them to the output q. For those chars 192797883Sgibbs * which require special processing (as indicated by the 192897883Sgibbs * bits in char_type), call ttyoutput. After processing 192997883Sgibbs * a hunk of data, look for FLUSHO so ^O's will take effect 193097883Sgibbs * immediately. 193197883Sgibbs */ 193297883Sgibbs while (cc > 0) { 193397883Sgibbs if (!ISSET(tp->t_oflag, OPOST)) 193497883Sgibbs ce = cc; 193597883Sgibbs else { 193697883Sgibbs ce = cc - scanc((u_int)cc, (u_char *)cp, 193797883Sgibbs char_type, CCLASSMASK); 193897883Sgibbs /* 193997883Sgibbs * If ce is zero, then we're processing 194097883Sgibbs * a special character through ttyoutput. 194197883Sgibbs */ 194297883Sgibbs if (ce == 0) { 194397883Sgibbs tp->t_rocount = 0; 1944107368Sscottl if (ttyoutput(*cp, tp) >= 0) { 194597883Sgibbs /* No Clists, wait a bit. */ 194697883Sgibbs ttstart(tp); 194797883Sgibbs if (flag & IO_NDELAY) { 194897883Sgibbs error = EWOULDBLOCK; 194997883Sgibbs goto out; 195097883Sgibbs } 195197883Sgibbs error = ttysleep(tp, &lbolt, 195297883Sgibbs TTOPRI|PCATCH, 195397883Sgibbs "ttybf1", 0); 195497883Sgibbs if (error) 195597883Sgibbs goto out; 195697883Sgibbs goto loop; 195797883Sgibbs } 195897883Sgibbs cp++; 195997883Sgibbs cc--; 196097883Sgibbs if (ISSET(tp->t_lflag, FLUSHO) || 196197883Sgibbs tp->t_outq.c_cc > hiwat) 196297883Sgibbs goto ovhiwat; 196397883Sgibbs continue; 196497883Sgibbs } 196597883Sgibbs } 196697883Sgibbs /* 196797883Sgibbs * A bunch of normal characters have been found. 196897883Sgibbs * Transfer them en masse to the output queue and 196997883Sgibbs * continue processing at the top of the loop. 197097883Sgibbs * If there are any further characters in this 197197883Sgibbs * <= OBUFSIZ chunk, the first should be a character 197297883Sgibbs * requiring special handling by ttyoutput. 197397883Sgibbs */ 197497883Sgibbs tp->t_rocount = 0; 197597883Sgibbs i = b_to_q(cp, ce, &tp->t_outq); 197697883Sgibbs ce -= i; 197797883Sgibbs tp->t_column += ce; 197897883Sgibbs cp += ce, cc -= ce, tk_nout += ce; 197997883Sgibbs tp->t_outcc += ce; 198097883Sgibbs if (i > 0) { 198197883Sgibbs /* No Clists, wait a bit. */ 198297883Sgibbs ttstart(tp); 198397883Sgibbs if (flag & IO_NDELAY) { 198497883Sgibbs error = EWOULDBLOCK; 198597883Sgibbs goto out; 198697883Sgibbs } 198797883Sgibbs error = ttysleep(tp, &lbolt, TTOPRI | PCATCH, 198897883Sgibbs "ttybf2", 0); 198997883Sgibbs if (error) 199097883Sgibbs goto out; 199197883Sgibbs goto loop; 199297883Sgibbs } 199397883Sgibbs if (ISSET(tp->t_lflag, FLUSHO) || 199497883Sgibbs tp->t_outq.c_cc > hiwat) 199597883Sgibbs break; 199697883Sgibbs } 199797883Sgibbs ttstart(tp); 199897883Sgibbs } 199997883Sgibbsout: 200097883Sgibbs /* 200197883Sgibbs * If cc is nonzero, we leave the uio structure inconsistent, as the 200297883Sgibbs * offset and iov pointers have moved forward, but it doesn't matter 2003107368Sscottl * (the call will either return short or restart with a new uio). 2004107368Sscottl */ 2005107368Sscottl uio->uio_resid += cc; 200697883Sgibbs return (error); 200797883Sgibbs 200897883Sgibbsovhiwat: 200997883Sgibbs ttstart(tp); 201097883Sgibbs s = spltty(); 201197883Sgibbs /* 201297883Sgibbs * This can only occur if FLUSHO is set in t_lflag, 201397883Sgibbs * or if ttstart/oproc is synchronous (or very fast). 201497883Sgibbs */ 201597883Sgibbs if (tp->t_outq.c_cc <= hiwat) { 201697883Sgibbs splx(s); 2017 goto loop; 2018 } 2019 if (flag & IO_NDELAY) { 2020 splx(s); 2021 uio->uio_resid += cc; 2022 return (uio->uio_resid == cnt ? EWOULDBLOCK : 0); 2023 } 2024 SET(tp->t_state, TS_SO_OLOWAT); 2025 error = ttysleep(tp, TSA_OLOWAT(tp), TTOPRI | PCATCH, "ttywri", 2026 tp->t_timeout); 2027 splx(s); 2028 if (error == EWOULDBLOCK) 2029 error = EIO; 2030 if (error) 2031 goto out; 2032 goto loop; 2033} 2034 2035/* 2036 * Rubout one character from the rawq of tp 2037 * as cleanly as possible. 2038 */ 2039static void 2040ttyrub(c, tp) 2041 register int c; 2042 register struct tty *tp; 2043{ 2044 register char *cp; 2045 register int savecol; 2046 int tabc, s; 2047 2048 if (!ISSET(tp->t_lflag, ECHO) || ISSET(tp->t_lflag, EXTPROC)) 2049 return; 2050 CLR(tp->t_lflag, FLUSHO); 2051 if (ISSET(tp->t_lflag, ECHOE)) { 2052 if (tp->t_rocount == 0) { 2053 /* 2054 * Screwed by ttwrite; retype 2055 */ 2056 ttyretype(tp); 2057 return; 2058 } 2059 if (c == ('\t' | TTY_QUOTE) || c == ('\n' | TTY_QUOTE)) 2060 ttyrubo(tp, 2); 2061 else { 2062 CLR(c, ~TTY_CHARMASK); 2063 switch (CCLASS(c)) { 2064 case ORDINARY: 2065 ttyrubo(tp, 1); 2066 break; 2067 case BACKSPACE: 2068 case CONTROL: 2069 case NEWLINE: 2070 case RETURN: 2071 case VTAB: 2072 if (ISSET(tp->t_lflag, ECHOCTL)) 2073 ttyrubo(tp, 2); 2074 break; 2075 case TAB: 2076 if (tp->t_rocount < tp->t_rawq.c_cc) { 2077 ttyretype(tp); 2078 return; 2079 } 2080 s = spltty(); 2081 savecol = tp->t_column; 2082 SET(tp->t_state, TS_CNTTB); 2083 SET(tp->t_lflag, FLUSHO); 2084 tp->t_column = tp->t_rocol; 2085 cp = tp->t_rawq.c_cf; 2086 if (cp) 2087 tabc = *cp; /* XXX FIX NEXTC */ 2088 for (; cp; cp = nextc(&tp->t_rawq, cp, &tabc)) 2089 ttyecho(tabc, tp); 2090 CLR(tp->t_lflag, FLUSHO); 2091 CLR(tp->t_state, TS_CNTTB); 2092 splx(s); 2093 2094 /* savecol will now be length of the tab. */ 2095 savecol -= tp->t_column; 2096 tp->t_column += savecol; 2097 if (savecol > 8) 2098 savecol = 8; /* overflow screw */ 2099 while (--savecol >= 0) 2100 (void)ttyoutput('\b', tp); 2101 break; 2102 default: /* XXX */ 2103#define PANICSTR "ttyrub: would panic c = %d, val = %d\n" 2104 (void)printf(PANICSTR, c, CCLASS(c)); 2105#ifdef notdef 2106 panic(PANICSTR, c, CCLASS(c)); 2107#endif 2108 } 2109 } 2110 } else if (ISSET(tp->t_lflag, ECHOPRT)) { 2111 if (!ISSET(tp->t_state, TS_ERASE)) { 2112 SET(tp->t_state, TS_ERASE); 2113 (void)ttyoutput('\\', tp); 2114 } 2115 ttyecho(c, tp); 2116 } else { 2117 ttyecho(tp->t_cc[VERASE], tp); 2118 /* 2119 * This code may be executed not only when an ERASE key 2120 * is pressed, but also when ^U (KILL) or ^W (WERASE) are. 2121 * So, I didn't think it was worthwhile to pass the extra 2122 * information (which would need an extra parameter, 2123 * changing every call) needed to distinguish the ERASE2 2124 * case from the ERASE. 2125 */ 2126 } 2127 --tp->t_rocount; 2128} 2129 2130/* 2131 * Back over cnt characters, erasing them. 2132 */ 2133static void 2134ttyrubo(tp, cnt) 2135 register struct tty *tp; 2136 int cnt; 2137{ 2138 2139 while (cnt-- > 0) { 2140 (void)ttyoutput('\b', tp); 2141 (void)ttyoutput(' ', tp); 2142 (void)ttyoutput('\b', tp); 2143 } 2144} 2145 2146/* 2147 * ttyretype -- 2148 * Reprint the rawq line. Note, it is assumed that c_cc has already 2149 * been checked. 2150 */ 2151static void 2152ttyretype(tp) 2153 register struct tty *tp; 2154{ 2155 register char *cp; 2156 int s, c; 2157 2158 /* Echo the reprint character. */ 2159 if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE) 2160 ttyecho(tp->t_cc[VREPRINT], tp); 2161 2162 (void)ttyoutput('\n', tp); 2163 2164 /* 2165 * XXX 2166 * FIX: NEXTC IS BROKEN - DOESN'T CHECK QUOTE 2167 * BIT OF FIRST CHAR. 2168 */ 2169 s = spltty(); 2170 for (cp = tp->t_canq.c_cf, c = (cp != NULL ? *cp : 0); 2171 cp != NULL; cp = nextc(&tp->t_canq, cp, &c)) 2172 ttyecho(c, tp); 2173 for (cp = tp->t_rawq.c_cf, c = (cp != NULL ? *cp : 0); 2174 cp != NULL; cp = nextc(&tp->t_rawq, cp, &c)) 2175 ttyecho(c, tp); 2176 CLR(tp->t_state, TS_ERASE); 2177 splx(s); 2178 2179 tp->t_rocount = tp->t_rawq.c_cc; 2180 tp->t_rocol = 0; 2181} 2182 2183/* 2184 * Echo a typed character to the terminal. 2185 */ 2186static void 2187ttyecho(c, tp) 2188 register int c; 2189 register struct tty *tp; 2190{ 2191 2192 if (!ISSET(tp->t_state, TS_CNTTB)) 2193 CLR(tp->t_lflag, FLUSHO); 2194 if ((!ISSET(tp->t_lflag, ECHO) && 2195 (c != '\n' || !ISSET(tp->t_lflag, ECHONL))) || 2196 ISSET(tp->t_lflag, EXTPROC)) 2197 return; 2198 if (ISSET(tp->t_lflag, ECHOCTL) && 2199 ((ISSET(c, TTY_CHARMASK) <= 037 && c != '\t' && c != '\n') || 2200 ISSET(c, TTY_CHARMASK) == 0177)) { 2201 (void)ttyoutput('^', tp); 2202 CLR(c, ~TTY_CHARMASK); 2203 if (c == 0177) 2204 c = '?'; 2205 else 2206 c += 'A' - 1; 2207 } 2208 (void)ttyoutput(c, tp); 2209} 2210 2211/* 2212 * Wake up any readers on a tty. 2213 */ 2214void 2215ttwakeup(tp) 2216 register struct tty *tp; 2217{ 2218 2219 if (tp->t_rsel.si_pid != 0) 2220 selwakeup(&tp->t_rsel); 2221 if (ISSET(tp->t_state, TS_ASYNC) && tp->t_sigio != NULL) 2222 pgsigio(tp->t_sigio, SIGIO, (tp->t_session != NULL)); 2223 wakeup(TSA_HUP_OR_INPUT(tp)); 2224 KNOTE(&tp->t_rsel.si_note, 0); 2225} 2226 2227/* 2228 * Wake up any writers on a tty. 2229 */ 2230void 2231ttwwakeup(tp) 2232 register struct tty *tp; 2233{ 2234 2235 if (tp->t_wsel.si_pid != 0 && tp->t_outq.c_cc <= tp->t_olowat) 2236 selwakeup(&tp->t_wsel); 2237 if (ISSET(tp->t_state, TS_ASYNC) && tp->t_sigio != NULL) 2238 pgsigio(tp->t_sigio, SIGIO, (tp->t_session != NULL)); 2239 if (ISSET(tp->t_state, TS_BUSY | TS_SO_OCOMPLETE) == 2240 TS_SO_OCOMPLETE && tp->t_outq.c_cc == 0) { 2241 CLR(tp->t_state, TS_SO_OCOMPLETE); 2242 wakeup(TSA_OCOMPLETE(tp)); 2243 } 2244 if (ISSET(tp->t_state, TS_SO_OLOWAT) && 2245 tp->t_outq.c_cc <= tp->t_olowat) { 2246 CLR(tp->t_state, TS_SO_OLOWAT); 2247 wakeup(TSA_OLOWAT(tp)); 2248 } 2249 KNOTE(&tp->t_wsel.si_note, 0); 2250} 2251 2252/* 2253 * Look up a code for a specified speed in a conversion table; 2254 * used by drivers to map software speed values to hardware parameters. 2255 */ 2256int 2257ttspeedtab(speed, table) 2258 int speed; 2259 register struct speedtab *table; 2260{ 2261 2262 for ( ; table->sp_speed != -1; table++) 2263 if (table->sp_speed == speed) 2264 return (table->sp_code); 2265 return (-1); 2266} 2267 2268/* 2269 * Set input and output watermarks and buffer sizes. For input, the 2270 * high watermark is about one second's worth of input above empty, the 2271 * low watermark is slightly below high water, and the buffer size is a 2272 * driver-dependent amount above high water. For output, the watermarks 2273 * are near the ends of the buffer, with about 1 second's worth of input 2274 * between them. All this only applies to the standard line discipline. 2275 */ 2276void 2277ttsetwater(tp) 2278 struct tty *tp; 2279{ 2280 register int cps, ttmaxhiwat, x; 2281 2282 /* Input. */ 2283 clist_alloc_cblocks(&tp->t_canq, TTYHOG, 512); 2284 switch (tp->t_ispeedwat) { 2285 case (speed_t)-1: 2286 cps = tp->t_ispeed / 10; 2287 break; 2288 case 0: 2289 /* 2290 * This case is for old drivers that don't know about 2291 * t_ispeedwat. Arrange for them to get the old buffer 2292 * sizes and watermarks. 2293 */ 2294 cps = TTYHOG - 2 * 256; 2295 tp->t_ififosize = 2 * 256; 2296 break; 2297 default: 2298 cps = tp->t_ispeedwat / 10; 2299 break; 2300 } 2301 tp->t_ihiwat = cps; 2302 tp->t_ilowat = 7 * cps / 8; 2303 x = cps + tp->t_ififosize; 2304 clist_alloc_cblocks(&tp->t_rawq, x, x); 2305 2306 /* Output. */ 2307 switch (tp->t_ospeedwat) { 2308 case (speed_t)-1: 2309 cps = tp->t_ospeed / 10; 2310 ttmaxhiwat = 2 * TTMAXHIWAT; 2311 break; 2312 case 0: 2313 cps = tp->t_ospeed / 10; 2314 ttmaxhiwat = TTMAXHIWAT; 2315 break; 2316 default: 2317 cps = tp->t_ospeedwat / 10; 2318 ttmaxhiwat = 8 * TTMAXHIWAT; 2319 break; 2320 } 2321#define CLAMP(x, h, l) ((x) > h ? h : ((x) < l) ? l : (x)) 2322 tp->t_olowat = x = CLAMP(cps / 2, TTMAXLOWAT, TTMINLOWAT); 2323 x += cps; 2324 x = CLAMP(x, ttmaxhiwat, TTMINHIWAT); /* XXX clamps are too magic */ 2325 tp->t_ohiwat = roundup(x, CBSIZE); /* XXX for compat */ 2326 x = imax(tp->t_ohiwat, TTMAXHIWAT); /* XXX for compat/safety */ 2327 x += OBUFSIZ + 100; 2328 clist_alloc_cblocks(&tp->t_outq, x, x); 2329#undef CLAMP 2330} 2331 2332/* 2333 * Report on state of foreground process group. 2334 */ 2335void 2336ttyinfo(tp) 2337 register struct tty *tp; 2338{ 2339 register struct proc *p, *pick; 2340 struct timeval utime, stime; 2341 const char *stmp; 2342 long ltmp; 2343 int tmp; 2344 2345 if (ttycheckoutq(tp,0) == 0) 2346 return; 2347 2348 /* Print load average. */ 2349 tmp = (averunnable.ldavg[0] * 100 + FSCALE / 2) >> FSHIFT; 2350 ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100); 2351 2352 if (tp->t_session == NULL) 2353 ttyprintf(tp, "not a controlling terminal\n"); 2354 else if (tp->t_pgrp == NULL) 2355 ttyprintf(tp, "no foreground process group\n"); 2356 else if ((p = LIST_FIRST(&tp->t_pgrp->pg_members)) == 0) 2357 ttyprintf(tp, "empty foreground process group\n"); 2358 else { 2359 mtx_lock_spin(&sched_lock); 2360 2361 /* Pick interesting process. */ 2362 for (pick = NULL; p != 0; p = LIST_NEXT(p, p_pglist)) 2363 if (proc_compare(pick, p)) 2364 pick = p; 2365 2366 stmp = pick->p_stat == SRUN ? "running" : 2367 pick->p_wmesg ? pick->p_wmesg : "iowait"; 2368 calcru(pick, &utime, &stime, NULL); 2369 ltmp = pick->p_stat == SIDL || pick->p_stat == SWAIT || 2370 pick->p_stat == SZOMB ? 0 : 2371 pgtok(vmspace_resident_count(pick->p_vmspace)); 2372 mtx_unlock_spin(&sched_lock); 2373 2374 ttyprintf(tp, " cmd: %s %d [%s] ", pick->p_comm, pick->p_pid, 2375 stmp); 2376 2377 /* Print user time. */ 2378 ttyprintf(tp, "%ld.%02ldu ", 2379 utime.tv_sec, utime.tv_usec / 10000); 2380 2381 /* Print system time. */ 2382 ttyprintf(tp, "%ld.%02lds ", 2383 stime.tv_sec, stime.tv_usec / 10000); 2384 2385 /* Print percentage cpu, resident set size. */ 2386 ttyprintf(tp, "%d%% %ldk\n", tmp / 100, ltmp); 2387 } 2388 tp->t_rocount = 0; /* so pending input will be retyped if BS */ 2389} 2390 2391/* 2392 * Returns 1 if p2 is "better" than p1 2393 * 2394 * The algorithm for picking the "interesting" process is thus: 2395 * 2396 * 1) Only foreground processes are eligible - implied. 2397 * 2) Runnable processes are favored over anything else. The runner 2398 * with the highest cpu utilization is picked (p_estcpu). Ties are 2399 * broken by picking the highest pid. 2400 * 3) The sleeper with the shortest sleep time is next. With ties, 2401 * we pick out just "short-term" sleepers (P_SINTR == 0). 2402 * 4) Further ties are broken by picking the highest pid. 2403 */ 2404#define ISRUN(p) (((p)->p_stat == SRUN) || ((p)->p_stat == SIDL)) 2405#define TESTAB(a, b) ((a)<<1 | (b)) 2406#define ONLYA 2 2407#define ONLYB 1 2408#define BOTH 3 2409 2410static int 2411proc_compare(p1, p2) 2412 register struct proc *p1, *p2; 2413{ 2414 2415 mtx_assert(&sched_lock, MA_OWNED); 2416 if (p1 == NULL) 2417 return (1); 2418 2419 /* 2420 * see if at least one of them is runnable 2421 */ 2422 switch (TESTAB(ISRUN(p1), ISRUN(p2))) { 2423 case ONLYA: 2424 return (0); 2425 case ONLYB: 2426 return (1); 2427 case BOTH: 2428 /* 2429 * tie - favor one with highest recent cpu utilization 2430 */ 2431 if (p2->p_estcpu > p1->p_estcpu) 2432 return (1); 2433 if (p1->p_estcpu > p2->p_estcpu) 2434 return (0); 2435 return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 2436 } 2437 /* 2438 * weed out zombies 2439 */ 2440 switch (TESTAB(p1->p_stat == SZOMB, p2->p_stat == SZOMB)) { 2441 case ONLYA: 2442 return (1); 2443 case ONLYB: 2444 return (0); 2445 case BOTH: 2446 return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 2447 } 2448 2449 /* 2450 * pick the one with the smallest sleep time 2451 */ 2452 if (p2->p_slptime > p1->p_slptime) 2453 return (0); 2454 if (p1->p_slptime > p2->p_slptime) 2455 return (1); 2456 /* 2457 * favor one sleeping in a non-interruptible sleep 2458 */ 2459 if (p1->p_sflag & PS_SINTR && (p2->p_sflag & PS_SINTR) == 0) 2460 return (1); 2461 if (p2->p_sflag & PS_SINTR && (p1->p_sflag & PS_SINTR) == 0) 2462 return (0); 2463 return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 2464} 2465 2466/* 2467 * Output char to tty; console putchar style. 2468 */ 2469int 2470tputchar(c, tp) 2471 int c; 2472 struct tty *tp; 2473{ 2474 register int s; 2475 2476 s = spltty(); 2477 if (!ISSET(tp->t_state, TS_CONNECTED)) { 2478 splx(s); 2479 return (-1); 2480 } 2481 if (c == '\n') 2482 (void)ttyoutput('\r', tp); 2483 (void)ttyoutput(c, tp); 2484 ttstart(tp); 2485 splx(s); 2486 return (0); 2487} 2488 2489/* 2490 * Sleep on chan, returning ERESTART if tty changed while we napped and 2491 * returning any errors (e.g. EINTR/EWOULDBLOCK) reported by tsleep. If 2492 * the tty is revoked, restarting a pending call will redo validation done 2493 * at the start of the call. 2494 */ 2495int 2496ttysleep(tp, chan, pri, wmesg, timo) 2497 struct tty *tp; 2498 void *chan; 2499 int pri, timo; 2500 char *wmesg; 2501{ 2502 int error; 2503 int gen; 2504 2505 gen = tp->t_gen; 2506 error = tsleep(chan, pri, wmesg, timo); 2507 if (error) 2508 return (error); 2509 return (tp->t_gen == gen ? 0 : ERESTART); 2510} 2511 2512/* 2513 * Allocate a tty struct. Clists in the struct will be allocated by 2514 * ttyopen(). 2515 */ 2516struct tty * 2517ttymalloc(tp) 2518 struct tty *tp; 2519{ 2520 2521 if (tp) 2522 return(tp); 2523 tp = malloc(sizeof *tp, M_TTYS, M_WAITOK | M_ZERO); 2524 ttyregister(tp); 2525 return (tp); 2526} 2527 2528#if 0 /* XXX not yet usable: session leader holds a ref (see kern_exit.c). */ 2529/* 2530 * Free a tty struct. Clists in the struct should have been freed by 2531 * ttyclose(). 2532 */ 2533void 2534ttyfree(tp) 2535 struct tty *tp; 2536{ 2537 free(tp, M_TTYS); 2538} 2539#endif /* 0 */ 2540 2541void 2542ttyregister(tp) 2543 struct tty *tp; 2544{ 2545 tp->t_timeout = -1; 2546 SLIST_INSERT_HEAD(&tty_list, tp, t_list); 2547} 2548 2549static int 2550sysctl_kern_ttys(SYSCTL_HANDLER_ARGS) 2551{ 2552 int error; 2553 struct tty *tp, t; 2554 SLIST_FOREACH(tp, &tty_list, t_list) { 2555 t = *tp; 2556 if (t.t_dev) 2557 t.t_dev = (dev_t)dev2udev(t.t_dev); 2558 error = SYSCTL_OUT(req, (caddr_t)&t, sizeof(t)); 2559 if (error) 2560 return (error); 2561 } 2562 return (0); 2563} 2564 2565SYSCTL_PROC(_kern, OID_AUTO, ttys, CTLTYPE_OPAQUE|CTLFLAG_RD, 2566 0, 0, sysctl_kern_ttys, "S,tty", "All struct ttys"); 2567 2568void 2569nottystop(tp, rw) 2570 struct tty *tp; 2571 int rw; 2572{ 2573 2574 return; 2575} 2576 2577int 2578ttyread(dev, uio, flag) 2579 dev_t dev; 2580 struct uio *uio; 2581 int flag; 2582{ 2583 struct tty *tp; 2584 2585 tp = dev->si_tty; 2586 if (tp == NULL) 2587 return (ENODEV); 2588 return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 2589} 2590 2591int 2592ttywrite(dev, uio, flag) 2593 dev_t dev; 2594 struct uio *uio; 2595 int flag; 2596{ 2597 struct tty *tp; 2598 2599 tp = dev->si_tty; 2600 if (tp == NULL) 2601 return (ENODEV); 2602 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 2603} 2604