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