tty.c revision 1.1.1.3 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.3 fvdl * @(#)tty.c 8.13 (Berkeley) 1/9/95
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.3 fvdl register int notout, 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.3 fvdl if (ISSET(tp->t_lflag, FLUSHO)) {
557 1.1.1.3 fvdl notout = 0;
558 1.1.1.3 fvdl } else {
559 1.1.1.2 fvdl s = spltty(); /* Don't interrupt tabs. */
560 1.1.1.3 fvdl notout = b_to_q(" ", c, &tp->t_outq);
561 1.1.1.3 fvdl c -= notout;
562 1.1.1.2 fvdl tk_nout += c;
563 1.1.1.2 fvdl tp->t_outcc += c;
564 1.1.1.2 fvdl splx(s);
565 1.1.1.2 fvdl }
566 1.1.1.2 fvdl tp->t_column += c;
567 1.1.1.3 fvdl return (notout ? '\t' : -1);
568 1.1.1.2 fvdl }
569 1.1.1.2 fvdl if (c == CEOT && ISSET(oflag, ONOEOT))
570 1.1.1.2 fvdl return (-1);
571 1.1.1.2 fvdl
572 1.1.1.2 fvdl /*
573 1.1.1.2 fvdl * Newline translation: if ONLCR is set,
574 1.1.1.2 fvdl * translate newline into "\r\n".
575 1.1.1.2 fvdl */
576 1.1.1.2 fvdl if (c == '\n' && ISSET(tp->t_oflag, ONLCR)) {
577 1.1.1.2 fvdl tk_nout++;
578 1.1.1.2 fvdl tp->t_outcc++;
579 1.1.1.2 fvdl if (putc('\r', &tp->t_outq))
580 1.1.1.2 fvdl return (c);
581 1.1.1.2 fvdl }
582 1.1.1.2 fvdl tk_nout++;
583 1.1.1.2 fvdl tp->t_outcc++;
584 1.1.1.2 fvdl if (!ISSET(tp->t_lflag, FLUSHO) && putc(c, &tp->t_outq))
585 1.1.1.2 fvdl return (c);
586 1.1.1.2 fvdl
587 1.1.1.2 fvdl col = tp->t_column;
588 1.1.1.2 fvdl switch (CCLASS(c)) {
589 1.1.1.2 fvdl case BACKSPACE:
590 1.1.1.2 fvdl if (col > 0)
591 1.1.1.2 fvdl --col;
592 1.1.1.2 fvdl break;
593 1.1.1.2 fvdl case CONTROL:
594 1.1.1.2 fvdl break;
595 1.1.1.2 fvdl case NEWLINE:
596 1.1.1.2 fvdl case RETURN:
597 1.1.1.2 fvdl col = 0;
598 1.1.1.2 fvdl break;
599 1.1.1.2 fvdl case ORDINARY:
600 1.1.1.2 fvdl ++col;
601 1.1.1.2 fvdl break;
602 1.1.1.2 fvdl case TAB:
603 1.1.1.2 fvdl col = (col + 8) & ~7;
604 1.1.1.2 fvdl break;
605 1.1.1.2 fvdl }
606 1.1.1.2 fvdl tp->t_column = col;
607 1.1.1.2 fvdl return (-1);
608 1.1.1.2 fvdl }
609 1.1.1.2 fvdl
610 1.1.1.2 fvdl /*
611 1.1.1.2 fvdl * Ioctls for all tty devices. Called after line-discipline specific ioctl
612 1.1.1.2 fvdl * has been called to do discipline-specific functions and/or reject any
613 1.1.1.2 fvdl * of these ioctl commands.
614 1.1.1.2 fvdl */
615 1.1.1.2 fvdl /* ARGSUSED */
616 1.1.1.2 fvdl int
617 1.1.1.2 fvdl ttioctl(tp, cmd, data, flag)
618 1.1.1.2 fvdl register struct tty *tp;
619 1.1.1.3 fvdl u_long cmd;
620 1.1.1.2 fvdl void *data;
621 1.1.1.3 fvdl int flag;
622 1.1.1.2 fvdl {
623 1.1.1.2 fvdl extern struct tty *constty; /* Temporary virtual console. */
624 1.1.1.2 fvdl extern int nlinesw;
625 1.1.1.2 fvdl register struct proc *p;
626 1.1.1.2 fvdl int s, error;
627 1.1.1.2 fvdl
628 1.1.1.2 fvdl p = curproc; /* XXX */
629 1.1.1.2 fvdl
630 1.1.1.2 fvdl /* If the ioctl involves modification, hang if in the background. */
631 1.1.1.2 fvdl switch (cmd) {
632 1.1.1.2 fvdl case TIOCFLUSH:
633 1.1.1.2 fvdl case TIOCSETA:
634 1.1.1.2 fvdl case TIOCSETD:
635 1.1.1.2 fvdl case TIOCSETAF:
636 1.1.1.2 fvdl case TIOCSETAW:
637 1.1.1.2 fvdl #ifdef notdef
638 1.1.1.2 fvdl case TIOCSPGRP:
639 1.1.1.2 fvdl #endif
640 1.1.1.2 fvdl case TIOCSTI:
641 1.1.1.2 fvdl case TIOCSWINSZ:
642 1.1.1.2 fvdl #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
643 1.1.1.2 fvdl case TIOCLBIC:
644 1.1.1.2 fvdl case TIOCLBIS:
645 1.1.1.2 fvdl case TIOCLSET:
646 1.1.1.2 fvdl case TIOCSETC:
647 1.1.1.2 fvdl case OTIOCSETD:
648 1.1.1.2 fvdl case TIOCSETN:
649 1.1.1.2 fvdl case TIOCSETP:
650 1.1.1.2 fvdl case TIOCSLTC:
651 1.1.1.2 fvdl #endif
652 1.1.1.2 fvdl while (isbackground(curproc, tp) &&
653 1.1.1.2 fvdl p->p_pgrp->pg_jobc && (p->p_flag & P_PPWAIT) == 0 &&
654 1.1.1.2 fvdl (p->p_sigignore & sigmask(SIGTTOU)) == 0 &&
655 1.1.1.2 fvdl (p->p_sigmask & sigmask(SIGTTOU)) == 0) {
656 1.1.1.2 fvdl pgsignal(p->p_pgrp, SIGTTOU, 1);
657 1.1.1.2 fvdl if (error = ttysleep(tp,
658 1.1.1.2 fvdl &lbolt, TTOPRI | PCATCH, ttybg, 0))
659 1.1.1.2 fvdl return (error);
660 1.1.1.2 fvdl }
661 1.1.1.2 fvdl break;
662 1.1.1.2 fvdl }
663 1.1.1.2 fvdl
664 1.1.1.2 fvdl switch (cmd) { /* Process the ioctl. */
665 1.1.1.2 fvdl case FIOASYNC: /* set/clear async i/o */
666 1.1.1.2 fvdl s = spltty();
667 1.1.1.2 fvdl if (*(int *)data)
668 1.1.1.2 fvdl SET(tp->t_state, TS_ASYNC);
669 1.1.1.2 fvdl else
670 1.1.1.2 fvdl CLR(tp->t_state, TS_ASYNC);
671 1.1.1.2 fvdl splx(s);
672 1.1.1.2 fvdl break;
673 1.1.1.2 fvdl case FIONBIO: /* set/clear non-blocking i/o */
674 1.1.1.2 fvdl break; /* XXX: delete. */
675 1.1.1.2 fvdl case FIONREAD: /* get # bytes to read */
676 1.1.1.2 fvdl *(int *)data = ttnread(tp);
677 1.1.1.2 fvdl break;
678 1.1.1.2 fvdl case TIOCEXCL: /* set exclusive use of tty */
679 1.1.1.2 fvdl s = spltty();
680 1.1.1.2 fvdl SET(tp->t_state, TS_XCLUDE);
681 1.1.1.2 fvdl splx(s);
682 1.1.1.2 fvdl break;
683 1.1.1.2 fvdl case TIOCFLUSH: { /* flush buffers */
684 1.1.1.2 fvdl register int flags = *(int *)data;
685 1.1.1.2 fvdl
686 1.1.1.2 fvdl if (flags == 0)
687 1.1.1.2 fvdl flags = FREAD | FWRITE;
688 1.1.1.2 fvdl else
689 1.1.1.2 fvdl flags &= FREAD | FWRITE;
690 1.1.1.2 fvdl ttyflush(tp, flags);
691 1.1.1.2 fvdl break;
692 1.1.1.2 fvdl }
693 1.1.1.2 fvdl case TIOCCONS: /* become virtual console */
694 1.1.1.2 fvdl if (*(int *)data) {
695 1.1.1.2 fvdl if (constty && constty != tp &&
696 1.1.1.2 fvdl ISSET(constty->t_state, TS_CARR_ON | TS_ISOPEN) ==
697 1.1.1.2 fvdl (TS_CARR_ON | TS_ISOPEN))
698 1.1.1.2 fvdl return (EBUSY);
699 1.1.1.2 fvdl #ifndef UCONSOLE
700 1.1.1.2 fvdl if (error = suser(p->p_ucred, &p->p_acflag))
701 1.1.1.2 fvdl return (error);
702 1.1.1.2 fvdl #endif
703 1.1.1.2 fvdl constty = tp;
704 1.1.1.2 fvdl } else if (tp == constty)
705 1.1.1.2 fvdl constty = NULL;
706 1.1.1.2 fvdl break;
707 1.1.1.2 fvdl case TIOCDRAIN: /* wait till output drained */
708 1.1.1.2 fvdl if (error = ttywait(tp))
709 1.1.1.2 fvdl return (error);
710 1.1.1.2 fvdl break;
711 1.1.1.2 fvdl case TIOCGETA: { /* get termios struct */
712 1.1.1.2 fvdl struct termios *t = (struct termios *)data;
713 1.1.1.2 fvdl
714 1.1.1.2 fvdl bcopy(&tp->t_termios, t, sizeof(struct termios));
715 1.1.1.2 fvdl break;
716 1.1.1.2 fvdl }
717 1.1.1.2 fvdl case TIOCGETD: /* get line discipline */
718 1.1.1.2 fvdl *(int *)data = tp->t_line;
719 1.1.1.2 fvdl break;
720 1.1.1.2 fvdl case TIOCGWINSZ: /* get window size */
721 1.1.1.2 fvdl *(struct winsize *)data = tp->t_winsize;
722 1.1.1.2 fvdl break;
723 1.1.1.2 fvdl case TIOCGPGRP: /* get pgrp of tty */
724 1.1.1.2 fvdl if (!isctty(p, tp))
725 1.1.1.2 fvdl return (ENOTTY);
726 1.1.1.2 fvdl *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
727 1.1.1.2 fvdl break;
728 1.1.1.2 fvdl #ifdef TIOCHPCL
729 1.1.1.2 fvdl case TIOCHPCL: /* hang up on last close */
730 1.1.1.2 fvdl s = spltty();
731 1.1.1.2 fvdl SET(tp->t_cflag, HUPCL);
732 1.1.1.2 fvdl splx(s);
733 1.1.1.2 fvdl break;
734 1.1.1.2 fvdl #endif
735 1.1.1.2 fvdl case TIOCNXCL: /* reset exclusive use of tty */
736 1.1.1.2 fvdl s = spltty();
737 1.1.1.2 fvdl CLR(tp->t_state, TS_XCLUDE);
738 1.1.1.2 fvdl splx(s);
739 1.1.1.2 fvdl break;
740 1.1.1.2 fvdl case TIOCOUTQ: /* output queue size */
741 1.1.1.2 fvdl *(int *)data = tp->t_outq.c_cc;
742 1.1.1.2 fvdl break;
743 1.1.1.2 fvdl case TIOCSETA: /* set termios struct */
744 1.1.1.2 fvdl case TIOCSETAW: /* drain output, set */
745 1.1.1.2 fvdl case TIOCSETAF: { /* drn out, fls in, set */
746 1.1.1.2 fvdl register struct termios *t = (struct termios *)data;
747 1.1.1.2 fvdl
748 1.1.1.2 fvdl s = spltty();
749 1.1.1.2 fvdl if (cmd == TIOCSETAW || cmd == TIOCSETAF) {
750 1.1.1.2 fvdl if (error = ttywait(tp)) {
751 1.1.1.2 fvdl splx(s);
752 1.1.1.2 fvdl return (error);
753 1.1.1.2 fvdl }
754 1.1.1.2 fvdl if (cmd == TIOCSETAF)
755 1.1.1.2 fvdl ttyflush(tp, FREAD);
756 1.1.1.2 fvdl }
757 1.1.1.2 fvdl if (!ISSET(t->c_cflag, CIGNORE)) {
758 1.1.1.2 fvdl /*
759 1.1.1.2 fvdl * Set device hardware.
760 1.1.1.2 fvdl */
761 1.1.1.2 fvdl if (tp->t_param && (error = (*tp->t_param)(tp, t))) {
762 1.1.1.2 fvdl splx(s);
763 1.1.1.2 fvdl return (error);
764 1.1.1.2 fvdl } else {
765 1.1.1.2 fvdl if (!ISSET(tp->t_state, TS_CARR_ON) &&
766 1.1.1.2 fvdl ISSET(tp->t_cflag, CLOCAL) &&
767 1.1.1.2 fvdl !ISSET(t->c_cflag, CLOCAL)) {
768 1.1.1.2 fvdl CLR(tp->t_state, TS_ISOPEN);
769 1.1.1.2 fvdl SET(tp->t_state, TS_WOPEN);
770 1.1.1.2 fvdl ttwakeup(tp);
771 1.1.1.2 fvdl }
772 1.1.1.2 fvdl tp->t_cflag = t->c_cflag;
773 1.1.1.2 fvdl tp->t_ispeed = t->c_ispeed;
774 1.1.1.2 fvdl tp->t_ospeed = t->c_ospeed;
775 1.1.1.2 fvdl }
776 1.1.1.2 fvdl ttsetwater(tp);
777 1.1.1.2 fvdl }
778 1.1.1.2 fvdl if (cmd != TIOCSETAF) {
779 1.1.1.2 fvdl if (ISSET(t->c_lflag, ICANON) !=
780 1.1.1.2 fvdl ISSET(tp->t_lflag, ICANON))
781 1.1.1.2 fvdl if (ISSET(t->c_lflag, ICANON)) {
782 1.1.1.2 fvdl SET(tp->t_lflag, PENDIN);
783 1.1.1.2 fvdl ttwakeup(tp);
784 1.1.1.2 fvdl } else {
785 1.1.1.2 fvdl struct clist tq;
786 1.1.1.2 fvdl
787 1.1.1.2 fvdl catq(&tp->t_rawq, &tp->t_canq);
788 1.1.1.2 fvdl tq = tp->t_rawq;
789 1.1.1.2 fvdl tp->t_rawq = tp->t_canq;
790 1.1.1.2 fvdl tp->t_canq = tq;
791 1.1.1.2 fvdl CLR(tp->t_lflag, PENDIN);
792 1.1.1.2 fvdl }
793 1.1.1.2 fvdl }
794 1.1.1.2 fvdl tp->t_iflag = t->c_iflag;
795 1.1.1.2 fvdl tp->t_oflag = t->c_oflag;
796 1.1.1.2 fvdl /*
797 1.1.1.2 fvdl * Make the EXTPROC bit read only.
798 1.1.1.2 fvdl */
799 1.1.1.2 fvdl if (ISSET(tp->t_lflag, EXTPROC))
800 1.1.1.2 fvdl SET(t->c_lflag, EXTPROC);
801 1.1.1.2 fvdl else
802 1.1.1.2 fvdl CLR(t->c_lflag, EXTPROC);
803 1.1.1.2 fvdl tp->t_lflag = t->c_lflag | ISSET(tp->t_lflag, PENDIN);
804 1.1.1.2 fvdl bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc));
805 1.1.1.2 fvdl splx(s);
806 1.1.1.2 fvdl break;
807 1.1.1.2 fvdl }
808 1.1.1.2 fvdl case TIOCSETD: { /* set line discipline */
809 1.1.1.2 fvdl register int t = *(int *)data;
810 1.1.1.2 fvdl dev_t device = tp->t_dev;
811 1.1.1.2 fvdl
812 1.1.1.2 fvdl if ((u_int)t >= nlinesw)
813 1.1.1.2 fvdl return (ENXIO);
814 1.1.1.2 fvdl if (t != tp->t_line) {
815 1.1.1.2 fvdl s = spltty();
816 1.1.1.2 fvdl (*linesw[tp->t_line].l_close)(tp, flag);
817 1.1.1.2 fvdl error = (*linesw[t].l_open)(device, tp);
818 1.1.1.2 fvdl if (error) {
819 1.1.1.2 fvdl (void)(*linesw[tp->t_line].l_open)(device, tp);
820 1.1.1.2 fvdl splx(s);
821 1.1.1.2 fvdl return (error);
822 1.1.1.2 fvdl }
823 1.1.1.2 fvdl tp->t_line = t;
824 1.1.1.2 fvdl splx(s);
825 1.1.1.2 fvdl }
826 1.1.1.2 fvdl break;
827 1.1.1.2 fvdl }
828 1.1.1.2 fvdl case TIOCSTART: /* start output, like ^Q */
829 1.1.1.2 fvdl s = spltty();
830 1.1.1.2 fvdl if (ISSET(tp->t_state, TS_TTSTOP) ||
831 1.1.1.2 fvdl ISSET(tp->t_lflag, FLUSHO)) {
832 1.1.1.2 fvdl CLR(tp->t_lflag, FLUSHO);
833 1.1.1.2 fvdl CLR(tp->t_state, TS_TTSTOP);
834 1.1.1.2 fvdl ttstart(tp);
835 1.1.1.2 fvdl }
836 1.1.1.2 fvdl splx(s);
837 1.1.1.2 fvdl break;
838 1.1.1.2 fvdl case TIOCSTI: /* simulate terminal input */
839 1.1.1.2 fvdl if (p->p_ucred->cr_uid && (flag & FREAD) == 0)
840 1.1.1.2 fvdl return (EPERM);
841 1.1.1.2 fvdl if (p->p_ucred->cr_uid && !isctty(p, tp))
842 1.1.1.2 fvdl return (EACCES);
843 1.1.1.2 fvdl (*linesw[tp->t_line].l_rint)(*(u_char *)data, tp);
844 1.1.1.2 fvdl break;
845 1.1.1.2 fvdl case TIOCSTOP: /* stop output, like ^S */
846 1.1.1.2 fvdl s = spltty();
847 1.1.1.2 fvdl if (!ISSET(tp->t_state, TS_TTSTOP)) {
848 1.1.1.2 fvdl SET(tp->t_state, TS_TTSTOP);
849 1.1.1.2 fvdl #ifdef sun4c /* XXX */
850 1.1.1.2 fvdl (*tp->t_stop)(tp, 0);
851 1.1.1.2 fvdl #else
852 1.1.1.2 fvdl (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
853 1.1.1.2 fvdl #endif
854 1.1.1.2 fvdl }
855 1.1.1.2 fvdl splx(s);
856 1.1.1.2 fvdl break;
857 1.1.1.2 fvdl case TIOCSCTTY: /* become controlling tty */
858 1.1.1.2 fvdl /* Session ctty vnode pointer set in vnode layer. */
859 1.1.1.2 fvdl if (!SESS_LEADER(p) ||
860 1.1.1.2 fvdl (p->p_session->s_ttyvp || tp->t_session) &&
861 1.1.1.2 fvdl (tp->t_session != p->p_session))
862 1.1.1.2 fvdl return (EPERM);
863 1.1.1.2 fvdl tp->t_session = p->p_session;
864 1.1.1.2 fvdl tp->t_pgrp = p->p_pgrp;
865 1.1.1.2 fvdl p->p_session->s_ttyp = tp;
866 1.1.1.2 fvdl p->p_flag |= P_CONTROLT;
867 1.1.1.2 fvdl break;
868 1.1.1.2 fvdl case TIOCSPGRP: { /* set pgrp of tty */
869 1.1.1.2 fvdl register struct pgrp *pgrp = pgfind(*(int *)data);
870 1.1.1.2 fvdl
871 1.1.1.2 fvdl if (!isctty(p, tp))
872 1.1.1.2 fvdl return (ENOTTY);
873 1.1.1.2 fvdl else if (pgrp == NULL || pgrp->pg_session != p->p_session)
874 1.1.1.2 fvdl return (EPERM);
875 1.1.1.2 fvdl tp->t_pgrp = pgrp;
876 1.1.1.2 fvdl break;
877 1.1.1.2 fvdl }
878 1.1.1.2 fvdl case TIOCSWINSZ: /* set window size */
879 1.1.1.2 fvdl if (bcmp((caddr_t)&tp->t_winsize, data,
880 1.1.1.2 fvdl sizeof (struct winsize))) {
881 1.1.1.2 fvdl tp->t_winsize = *(struct winsize *)data;
882 1.1.1.2 fvdl pgsignal(tp->t_pgrp, SIGWINCH, 1);
883 1.1.1.2 fvdl }
884 1.1.1.2 fvdl break;
885 1.1.1.2 fvdl default:
886 1.1.1.2 fvdl #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
887 1.1.1.2 fvdl return (ttcompat(tp, cmd, data, flag));
888 1.1.1.2 fvdl #else
889 1.1.1.2 fvdl return (-1);
890 1.1.1.2 fvdl #endif
891 1.1.1.2 fvdl }
892 1.1.1.2 fvdl return (0);
893 1.1.1.2 fvdl }
894 1.1.1.2 fvdl
895 1.1.1.2 fvdl int
896 1.1.1.2 fvdl ttselect(device, rw, p)
897 1.1.1.2 fvdl dev_t device;
898 1.1.1.2 fvdl int rw;
899 1.1.1.2 fvdl struct proc *p;
900 1.1.1.2 fvdl {
901 1.1.1.2 fvdl register struct tty *tp;
902 1.1.1.2 fvdl int nread, s;
903 1.1.1.2 fvdl
904 1.1.1.2 fvdl tp = &cdevsw[major(device)].d_ttys[minor(device)];
905 1.1.1.2 fvdl
906 1.1.1.2 fvdl s = spltty();
907 1.1.1.2 fvdl switch (rw) {
908 1.1.1.2 fvdl case FREAD:
909 1.1.1.2 fvdl nread = ttnread(tp);
910 1.1.1.2 fvdl if (nread > 0 || !ISSET(tp->t_cflag, CLOCAL) &&
911 1.1.1.2 fvdl !ISSET(tp->t_state, TS_CARR_ON))
912 1.1.1.2 fvdl goto win;
913 1.1.1.2 fvdl selrecord(p, &tp->t_rsel);
914 1.1.1.2 fvdl break;
915 1.1.1.2 fvdl case FWRITE:
916 1.1.1.2 fvdl if (tp->t_outq.c_cc <= tp->t_lowat) {
917 1.1.1.2 fvdl win: splx(s);
918 1.1.1.2 fvdl return (1);
919 1.1.1.2 fvdl }
920 1.1.1.2 fvdl selrecord(p, &tp->t_wsel);
921 1.1.1.2 fvdl break;
922 1.1.1.2 fvdl }
923 1.1.1.2 fvdl splx(s);
924 1.1.1.2 fvdl return (0);
925 1.1.1.2 fvdl }
926 1.1.1.2 fvdl
927 1.1.1.2 fvdl static int
928 1.1.1.2 fvdl ttnread(tp)
929 1.1.1.2 fvdl struct tty *tp;
930 1.1.1.2 fvdl {
931 1.1.1.2 fvdl int nread;
932 1.1.1.2 fvdl
933 1.1.1.2 fvdl if (ISSET(tp->t_lflag, PENDIN))
934 1.1.1.2 fvdl ttypend(tp);
935 1.1.1.2 fvdl nread = tp->t_canq.c_cc;
936 1.1.1.2 fvdl if (!ISSET(tp->t_lflag, ICANON))
937 1.1.1.2 fvdl nread += tp->t_rawq.c_cc;
938 1.1.1.2 fvdl return (nread);
939 1.1.1.2 fvdl }
940 1.1.1.2 fvdl
941 1.1.1.2 fvdl /*
942 1.1.1.2 fvdl * Wait for output to drain.
943 1.1.1.2 fvdl */
944 1.1.1.2 fvdl int
945 1.1.1.2 fvdl ttywait(tp)
946 1.1.1.2 fvdl register struct tty *tp;
947 1.1.1.2 fvdl {
948 1.1.1.2 fvdl int error, s;
949 1.1.1.2 fvdl
950 1.1.1.2 fvdl error = 0;
951 1.1.1.2 fvdl s = spltty();
952 1.1.1.2 fvdl while ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) &&
953 1.1.1.2 fvdl (ISSET(tp->t_state, TS_CARR_ON) || ISSET(tp->t_cflag, CLOCAL))
954 1.1.1.2 fvdl && tp->t_oproc) {
955 1.1.1.2 fvdl (*tp->t_oproc)(tp);
956 1.1.1.2 fvdl SET(tp->t_state, TS_ASLEEP);
957 1.1.1.2 fvdl if (error = ttysleep(tp,
958 1.1.1.2 fvdl &tp->t_outq, TTOPRI | PCATCH, ttyout, 0))
959 1.1.1.2 fvdl break;
960 1.1.1.2 fvdl }
961 1.1.1.2 fvdl splx(s);
962 1.1.1.2 fvdl return (error);
963 1.1.1.2 fvdl }
964 1.1.1.2 fvdl
965 1.1.1.2 fvdl /*
966 1.1.1.2 fvdl * Flush if successfully wait.
967 1.1.1.2 fvdl */
968 1.1.1.2 fvdl int
969 1.1.1.2 fvdl ttywflush(tp)
970 1.1.1.2 fvdl struct tty *tp;
971 1.1.1.2 fvdl {
972 1.1.1.2 fvdl int error;
973 1.1.1.2 fvdl
974 1.1.1.2 fvdl if ((error = ttywait(tp)) == 0)
975 1.1.1.2 fvdl ttyflush(tp, FREAD);
976 1.1.1.2 fvdl return (error);
977 1.1.1.2 fvdl }
978 1.1.1.2 fvdl
979 1.1.1.2 fvdl /*
980 1.1.1.2 fvdl * Flush tty read and/or write queues, notifying anyone waiting.
981 1.1.1.2 fvdl */
982 1.1.1.2 fvdl void
983 1.1.1.2 fvdl ttyflush(tp, rw)
984 1.1.1.2 fvdl register struct tty *tp;
985 1.1.1.2 fvdl int rw;
986 1.1.1.2 fvdl {
987 1.1.1.2 fvdl register int s;
988 1.1.1.2 fvdl
989 1.1.1.2 fvdl s = spltty();
990 1.1.1.2 fvdl if (rw & FREAD) {
991 1.1.1.2 fvdl FLUSHQ(&tp->t_canq);
992 1.1.1.2 fvdl FLUSHQ(&tp->t_rawq);
993 1.1.1.2 fvdl tp->t_rocount = 0;
994 1.1.1.2 fvdl tp->t_rocol = 0;
995 1.1.1.2 fvdl CLR(tp->t_state, TS_LOCAL);
996 1.1.1.2 fvdl ttwakeup(tp);
997 1.1.1.2 fvdl }
998 1.1.1.2 fvdl if (rw & FWRITE) {
999 1.1.1.2 fvdl CLR(tp->t_state, TS_TTSTOP);
1000 1.1.1.2 fvdl #ifdef sun4c /* XXX */
1001 1.1.1.2 fvdl (*tp->t_stop)(tp, rw);
1002 1.1.1.2 fvdl #else
1003 1.1.1.2 fvdl (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
1004 1.1.1.2 fvdl #endif
1005 1.1.1.2 fvdl FLUSHQ(&tp->t_outq);
1006 1.1.1.2 fvdl wakeup((caddr_t)&tp->t_outq);
1007 1.1.1.2 fvdl selwakeup(&tp->t_wsel);
1008 1.1.1.2 fvdl }
1009 1.1.1.2 fvdl splx(s);
1010 1.1.1.2 fvdl }
1011 1.1.1.2 fvdl
1012 1.1.1.2 fvdl /*
1013 1.1.1.2 fvdl * Copy in the default termios characters.
1014 1.1.1.2 fvdl */
1015 1.1.1.2 fvdl void
1016 1.1.1.2 fvdl ttychars(tp)
1017 1.1.1.2 fvdl struct tty *tp;
1018 1.1.1.2 fvdl {
1019 1.1.1.2 fvdl
1020 1.1.1.2 fvdl bcopy(ttydefchars, tp->t_cc, sizeof(ttydefchars));
1021 1.1.1.2 fvdl }
1022 1.1.1.2 fvdl
1023 1.1.1.2 fvdl /*
1024 1.1.1.2 fvdl * Send stop character on input overflow.
1025 1.1.1.2 fvdl */
1026 1.1.1.2 fvdl static void
1027 1.1.1.2 fvdl ttyblock(tp)
1028 1.1.1.2 fvdl register struct tty *tp;
1029 1.1.1.2 fvdl {
1030 1.1.1.2 fvdl register int total;
1031 1.1.1.2 fvdl
1032 1.1.1.2 fvdl total = tp->t_rawq.c_cc + tp->t_canq.c_cc;
1033 1.1.1.2 fvdl if (tp->t_rawq.c_cc > TTYHOG) {
1034 1.1.1.2 fvdl ttyflush(tp, FREAD | FWRITE);
1035 1.1.1.2 fvdl CLR(tp->t_state, TS_TBLOCK);
1036 1.1.1.2 fvdl }
1037 1.1.1.2 fvdl /*
1038 1.1.1.2 fvdl * Block further input iff: current input > threshold
1039 1.1.1.2 fvdl * AND input is available to user program.
1040 1.1.1.2 fvdl */
1041 1.1.1.2 fvdl if (total >= TTYHOG / 2 &&
1042 1.1.1.2 fvdl !ISSET(tp->t_state, TS_TBLOCK) &&
1043 1.1.1.2 fvdl !ISSET(tp->t_lflag, ICANON) || tp->t_canq.c_cc > 0 &&
1044 1.1.1.2 fvdl tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
1045 1.1.1.2 fvdl if (putc(tp->t_cc[VSTOP], &tp->t_outq) == 0) {
1046 1.1.1.2 fvdl SET(tp->t_state, TS_TBLOCK);
1047 1.1.1.2 fvdl ttstart(tp);
1048 1.1.1.2 fvdl }
1049 1.1.1.2 fvdl }
1050 1.1.1.2 fvdl }
1051 1.1.1.2 fvdl
1052 1.1.1.2 fvdl void
1053 1.1.1.2 fvdl ttrstrt(tp_arg)
1054 1.1.1.2 fvdl void *tp_arg;
1055 1.1.1.2 fvdl {
1056 1.1.1.2 fvdl struct tty *tp;
1057 1.1.1.2 fvdl int s;
1058 1.1.1.2 fvdl
1059 1.1.1.2 fvdl #ifdef DIAGNOSTIC
1060 1.1.1.2 fvdl if (tp_arg == NULL)
1061 1.1.1.2 fvdl panic("ttrstrt");
1062 1.1.1.2 fvdl #endif
1063 1.1.1.2 fvdl tp = tp_arg;
1064 1.1.1.2 fvdl s = spltty();
1065 1.1.1.2 fvdl
1066 1.1.1.2 fvdl CLR(tp->t_state, TS_TIMEOUT);
1067 1.1.1.2 fvdl ttstart(tp);
1068 1.1.1.2 fvdl
1069 1.1.1.2 fvdl splx(s);
1070 1.1.1.2 fvdl }
1071 1.1.1.2 fvdl
1072 1.1.1.2 fvdl int
1073 1.1.1.2 fvdl ttstart(tp)
1074 1.1.1.2 fvdl struct tty *tp;
1075 1.1.1.2 fvdl {
1076 1.1.1.2 fvdl
1077 1.1.1.2 fvdl if (tp->t_oproc != NULL) /* XXX: Kludge for pty. */
1078 1.1.1.2 fvdl (*tp->t_oproc)(tp);
1079 1.1.1.2 fvdl return (0);
1080 1.1.1.2 fvdl }
1081 1.1.1.2 fvdl
1082 1.1.1.2 fvdl /*
1083 1.1.1.2 fvdl * "close" a line discipline
1084 1.1.1.2 fvdl */
1085 1.1.1.2 fvdl int
1086 1.1.1.2 fvdl ttylclose(tp, flag)
1087 1.1.1.2 fvdl struct tty *tp;
1088 1.1.1.2 fvdl int flag;
1089 1.1.1.2 fvdl {
1090 1.1.1.2 fvdl
1091 1.1.1.2 fvdl if (flag & IO_NDELAY)
1092 1.1.1.2 fvdl ttyflush(tp, FREAD | FWRITE);
1093 1.1.1.2 fvdl else
1094 1.1.1.2 fvdl ttywflush(tp);
1095 1.1.1.2 fvdl return (0);
1096 1.1.1.2 fvdl }
1097 1.1.1.2 fvdl
1098 1.1.1.2 fvdl /*
1099 1.1.1.2 fvdl * Handle modem control transition on a tty.
1100 1.1.1.2 fvdl * Flag indicates new state of carrier.
1101 1.1.1.2 fvdl * Returns 0 if the line should be turned off, otherwise 1.
1102 1.1.1.2 fvdl */
1103 1.1.1.2 fvdl int
1104 1.1.1.2 fvdl ttymodem(tp, flag)
1105 1.1.1.2 fvdl register struct tty *tp;
1106 1.1.1.2 fvdl int flag;
1107 1.1.1.2 fvdl {
1108 1.1.1.2 fvdl
1109 1.1.1.2 fvdl if (!ISSET(tp->t_state, TS_WOPEN) && ISSET(tp->t_cflag, MDMBUF)) {
1110 1.1.1.2 fvdl /*
1111 1.1.1.2 fvdl * MDMBUF: do flow control according to carrier flag
1112 1.1.1.2 fvdl */
1113 1.1.1.2 fvdl if (flag) {
1114 1.1.1.2 fvdl CLR(tp->t_state, TS_TTSTOP);
1115 1.1.1.2 fvdl ttstart(tp);
1116 1.1.1.2 fvdl } else if (!ISSET(tp->t_state, TS_TTSTOP)) {
1117 1.1.1.2 fvdl SET(tp->t_state, TS_TTSTOP);
1118 1.1.1.2 fvdl #ifdef sun4c /* XXX */
1119 1.1.1.2 fvdl (*tp->t_stop)(tp, 0);
1120 1.1.1.2 fvdl #else
1121 1.1.1.2 fvdl (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
1122 1.1.1.2 fvdl #endif
1123 1.1.1.2 fvdl }
1124 1.1.1.2 fvdl } else if (flag == 0) {
1125 1.1.1.2 fvdl /*
1126 1.1.1.2 fvdl * Lost carrier.
1127 1.1.1.2 fvdl */
1128 1.1.1.2 fvdl CLR(tp->t_state, TS_CARR_ON);
1129 1.1.1.2 fvdl if (ISSET(tp->t_state, TS_ISOPEN) &&
1130 1.1.1.2 fvdl !ISSET(tp->t_cflag, CLOCAL)) {
1131 1.1.1.2 fvdl if (tp->t_session && tp->t_session->s_leader)
1132 1.1.1.2 fvdl psignal(tp->t_session->s_leader, SIGHUP);
1133 1.1.1.2 fvdl ttyflush(tp, FREAD | FWRITE);
1134 1.1.1.2 fvdl return (0);
1135 1.1.1.2 fvdl }
1136 1.1.1.2 fvdl } else {
1137 1.1.1.2 fvdl /*
1138 1.1.1.2 fvdl * Carrier now on.
1139 1.1.1.2 fvdl */
1140 1.1.1.2 fvdl SET(tp->t_state, TS_CARR_ON);
1141 1.1.1.2 fvdl ttwakeup(tp);
1142 1.1.1.2 fvdl }
1143 1.1.1.2 fvdl return (1);
1144 1.1.1.2 fvdl }
1145 1.1.1.2 fvdl
1146 1.1.1.2 fvdl /*
1147 1.1.1.2 fvdl * Default modem control routine (for other line disciplines).
1148 1.1.1.2 fvdl * Return argument flag, to turn off device on carrier drop.
1149 1.1.1.2 fvdl */
1150 1.1.1.2 fvdl int
1151 1.1.1.2 fvdl nullmodem(tp, flag)
1152 1.1.1.2 fvdl register struct tty *tp;
1153 1.1.1.2 fvdl int flag;
1154 1.1.1.2 fvdl {
1155 1.1.1.2 fvdl
1156 1.1.1.2 fvdl if (flag)
1157 1.1.1.2 fvdl SET(tp->t_state, TS_CARR_ON);
1158 1.1.1.2 fvdl else {
1159 1.1.1.2 fvdl CLR(tp->t_state, TS_CARR_ON);
1160 1.1.1.2 fvdl if (!ISSET(tp->t_cflag, CLOCAL)) {
1161 1.1.1.2 fvdl if (tp->t_session && tp->t_session->s_leader)
1162 1.1.1.2 fvdl psignal(tp->t_session->s_leader, SIGHUP);
1163 1.1.1.2 fvdl return (0);
1164 1.1.1.2 fvdl }
1165 1.1.1.2 fvdl }
1166 1.1.1.2 fvdl return (1);
1167 1.1.1.2 fvdl }
1168 1.1.1.2 fvdl
1169 1.1.1.2 fvdl /*
1170 1.1.1.2 fvdl * Reinput pending characters after state switch
1171 1.1.1.2 fvdl * call at spltty().
1172 1.1.1.2 fvdl */
1173 1.1.1.2 fvdl void
1174 1.1.1.2 fvdl ttypend(tp)
1175 1.1.1.2 fvdl register struct tty *tp;
1176 1.1.1.2 fvdl {
1177 1.1.1.2 fvdl struct clist tq;
1178 1.1.1.2 fvdl register c;
1179 1.1.1.2 fvdl
1180 1.1.1.2 fvdl CLR(tp->t_lflag, PENDIN);
1181 1.1.1.2 fvdl SET(tp->t_state, TS_TYPEN);
1182 1.1.1.2 fvdl tq = tp->t_rawq;
1183 1.1.1.2 fvdl tp->t_rawq.c_cc = 0;
1184 1.1.1.2 fvdl tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
1185 1.1.1.2 fvdl while ((c = getc(&tq)) >= 0)
1186 1.1.1.2 fvdl ttyinput(c, tp);
1187 1.1.1.2 fvdl CLR(tp->t_state, TS_TYPEN);
1188 1.1.1.2 fvdl }
1189 1.1.1.2 fvdl
1190 1.1.1.2 fvdl /*
1191 1.1.1.2 fvdl * Process a read call on a tty device.
1192 1.1.1.2 fvdl */
1193 1.1.1.2 fvdl int
1194 1.1.1.2 fvdl ttread(tp, uio, flag)
1195 1.1.1.2 fvdl register struct tty *tp;
1196 1.1.1.2 fvdl struct uio *uio;
1197 1.1.1.2 fvdl int flag;
1198 1.1.1.2 fvdl {
1199 1.1.1.2 fvdl register struct clist *qp;
1200 1.1.1.2 fvdl register int c;
1201 1.1.1.2 fvdl register long lflag;
1202 1.1.1.2 fvdl register u_char *cc = tp->t_cc;
1203 1.1.1.2 fvdl register struct proc *p = curproc;
1204 1.1.1.2 fvdl int s, first, error = 0;
1205 1.1.1.2 fvdl
1206 1.1.1.2 fvdl loop: lflag = tp->t_lflag;
1207 1.1.1.2 fvdl s = spltty();
1208 1.1.1.2 fvdl /*
1209 1.1.1.2 fvdl * take pending input first
1210 1.1.1.2 fvdl */
1211 1.1.1.2 fvdl if (ISSET(lflag, PENDIN))
1212 1.1.1.2 fvdl ttypend(tp);
1213 1.1.1.2 fvdl splx(s);
1214 1.1.1.2 fvdl
1215 1.1.1.2 fvdl /*
1216 1.1.1.2 fvdl * Hang process if it's in the background.
1217 1.1.1.2 fvdl */
1218 1.1.1.2 fvdl if (isbackground(p, tp)) {
1219 1.1.1.2 fvdl if ((p->p_sigignore & sigmask(SIGTTIN)) ||
1220 1.1.1.2 fvdl (p->p_sigmask & sigmask(SIGTTIN)) ||
1221 1.1.1.2 fvdl p->p_flag & P_PPWAIT || p->p_pgrp->pg_jobc == 0)
1222 1.1.1.2 fvdl return (EIO);
1223 1.1.1.2 fvdl pgsignal(p->p_pgrp, SIGTTIN, 1);
1224 1.1.1.2 fvdl if (error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, ttybg, 0))
1225 1.1.1.2 fvdl return (error);
1226 1.1.1.2 fvdl goto loop;
1227 1.1.1.2 fvdl }
1228 1.1.1.2 fvdl
1229 1.1.1.2 fvdl /*
1230 1.1.1.2 fvdl * If canonical, use the canonical queue,
1231 1.1.1.2 fvdl * else use the raw queue.
1232 1.1.1.2 fvdl *
1233 1.1.1.2 fvdl * (should get rid of clists...)
1234 1.1.1.2 fvdl */
1235 1.1.1.2 fvdl qp = ISSET(lflag, ICANON) ? &tp->t_canq : &tp->t_rawq;
1236 1.1.1.2 fvdl
1237 1.1.1.2 fvdl /*
1238 1.1.1.2 fvdl * If there is no input, sleep on rawq
1239 1.1.1.2 fvdl * awaiting hardware receipt and notification.
1240 1.1.1.2 fvdl * If we have data, we don't need to check for carrier.
1241 1.1.1.2 fvdl */
1242 1.1.1.2 fvdl s = spltty();
1243 1.1.1.2 fvdl if (qp->c_cc <= 0) {
1244 1.1.1.2 fvdl int carrier;
1245 1.1.1.2 fvdl
1246 1.1.1.2 fvdl carrier = ISSET(tp->t_state, TS_CARR_ON) ||
1247 1.1.1.2 fvdl ISSET(tp->t_cflag, CLOCAL);
1248 1.1.1.2 fvdl if (!carrier && ISSET(tp->t_state, TS_ISOPEN)) {
1249 1.1.1.2 fvdl splx(s);
1250 1.1.1.2 fvdl return (0); /* EOF */
1251 1.1.1.2 fvdl }
1252 1.1.1.2 fvdl if (flag & IO_NDELAY) {
1253 1.1.1.2 fvdl splx(s);
1254 1.1.1.2 fvdl return (EWOULDBLOCK);
1255 1.1.1.2 fvdl }
1256 1.1.1.2 fvdl error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH,
1257 1.1.1.2 fvdl carrier ? ttyin : ttopen, 0);
1258 1.1.1.2 fvdl splx(s);
1259 1.1.1.2 fvdl if (error)
1260 1.1.1.2 fvdl return (error);
1261 1.1.1.2 fvdl goto loop;
1262 1.1.1.2 fvdl }
1263 1.1.1.2 fvdl splx(s);
1264 1.1.1.2 fvdl
1265 1.1.1.2 fvdl /*
1266 1.1.1.2 fvdl * Input present, check for input mapping and processing.
1267 1.1.1.2 fvdl */
1268 1.1.1.2 fvdl first = 1;
1269 1.1.1.2 fvdl while ((c = getc(qp)) >= 0) {
1270 1.1.1.2 fvdl /*
1271 1.1.1.2 fvdl * delayed suspend (^Y)
1272 1.1.1.2 fvdl */
1273 1.1.1.2 fvdl if (CCEQ(cc[VDSUSP], c) && ISSET(lflag, ISIG)) {
1274 1.1.1.2 fvdl pgsignal(tp->t_pgrp, SIGTSTP, 1);
1275 1.1.1.2 fvdl if (first) {
1276 1.1.1.2 fvdl if (error = ttysleep(tp,
1277 1.1.1.2 fvdl &lbolt, TTIPRI | PCATCH, ttybg, 0))
1278 1.1.1.2 fvdl break;
1279 1.1.1.2 fvdl goto loop;
1280 1.1.1.2 fvdl }
1281 1.1.1.2 fvdl break;
1282 1.1.1.2 fvdl }
1283 1.1.1.2 fvdl /*
1284 1.1.1.2 fvdl * Interpret EOF only in canonical mode.
1285 1.1.1.2 fvdl */
1286 1.1.1.2 fvdl if (CCEQ(cc[VEOF], c) && ISSET(lflag, ICANON))
1287 1.1.1.2 fvdl break;
1288 1.1.1.2 fvdl /*
1289 1.1.1.2 fvdl * Give user character.
1290 1.1.1.2 fvdl */
1291 1.1.1.2 fvdl error = ureadc(c, uio);
1292 1.1.1.2 fvdl if (error)
1293 1.1.1.2 fvdl break;
1294 1.1.1.2 fvdl if (uio->uio_resid == 0)
1295 1.1.1.2 fvdl break;
1296 1.1.1.2 fvdl /*
1297 1.1.1.2 fvdl * In canonical mode check for a "break character"
1298 1.1.1.2 fvdl * marking the end of a "line of input".
1299 1.1.1.2 fvdl */
1300 1.1.1.2 fvdl if (ISSET(lflag, ICANON) && TTBREAKC(c))
1301 1.1.1.2 fvdl break;
1302 1.1.1.2 fvdl first = 0;
1303 1.1.1.2 fvdl }
1304 1.1.1.2 fvdl /*
1305 1.1.1.2 fvdl * Look to unblock output now that (presumably)
1306 1.1.1.2 fvdl * the input queue has gone down.
1307 1.1.1.2 fvdl */
1308 1.1.1.2 fvdl s = spltty();
1309 1.1.1.2 fvdl if (ISSET(tp->t_state, TS_TBLOCK) && tp->t_rawq.c_cc < TTYHOG/5) {
1310 1.1.1.2 fvdl if (cc[VSTART] != _POSIX_VDISABLE &&
1311 1.1.1.2 fvdl putc(cc[VSTART], &tp->t_outq) == 0) {
1312 1.1.1.2 fvdl CLR(tp->t_state, TS_TBLOCK);
1313 1.1.1.2 fvdl ttstart(tp);
1314 1.1.1.2 fvdl }
1315 1.1.1.2 fvdl }
1316 1.1.1.2 fvdl splx(s);
1317 1.1.1.2 fvdl return (error);
1318 1.1.1.2 fvdl }
1319 1.1.1.2 fvdl
1320 1.1.1.2 fvdl /*
1321 1.1.1.2 fvdl * Check the output queue on tp for space for a kernel message (from uprintf
1322 1.1.1.2 fvdl * or tprintf). Allow some space over the normal hiwater mark so we don't
1323 1.1.1.2 fvdl * lose messages due to normal flow control, but don't let the tty run amok.
1324 1.1.1.2 fvdl * Sleeps here are not interruptible, but we return prematurely if new signals
1325 1.1.1.2 fvdl * arrive.
1326 1.1.1.2 fvdl */
1327 1.1.1.2 fvdl int
1328 1.1.1.2 fvdl ttycheckoutq(tp, wait)
1329 1.1.1.2 fvdl register struct tty *tp;
1330 1.1.1.2 fvdl int wait;
1331 1.1.1.2 fvdl {
1332 1.1.1.2 fvdl int hiwat, s, oldsig;
1333 1.1.1.2 fvdl
1334 1.1.1.2 fvdl hiwat = tp->t_hiwat;
1335 1.1.1.2 fvdl s = spltty();
1336 1.1.1.2 fvdl oldsig = wait ? curproc->p_siglist : 0;
1337 1.1.1.2 fvdl if (tp->t_outq.c_cc > hiwat + 200)
1338 1.1.1.2 fvdl while (tp->t_outq.c_cc > hiwat) {
1339 1.1.1.2 fvdl ttstart(tp);
1340 1.1.1.2 fvdl if (wait == 0 || curproc->p_siglist != oldsig) {
1341 1.1.1.2 fvdl splx(s);
1342 1.1.1.2 fvdl return (0);
1343 1.1.1.2 fvdl }
1344 1.1.1.2 fvdl timeout((void (*)__P((void *)))wakeup,
1345 1.1.1.2 fvdl (void *)&tp->t_outq, hz);
1346 1.1.1.2 fvdl SET(tp->t_state, TS_ASLEEP);
1347 1.1.1.2 fvdl sleep((caddr_t)&tp->t_outq, PZERO - 1);
1348 1.1.1.2 fvdl }
1349 1.1.1.2 fvdl splx(s);
1350 1.1.1.2 fvdl return (1);
1351 1.1.1.2 fvdl }
1352 1.1.1.2 fvdl
1353 1.1.1.2 fvdl /*
1354 1.1.1.2 fvdl * Process a write call on a tty device.
1355 1.1.1.2 fvdl */
1356 1.1.1.2 fvdl int
1357 1.1.1.2 fvdl ttwrite(tp, uio, flag)
1358 1.1.1.2 fvdl register struct tty *tp;
1359 1.1.1.2 fvdl register struct uio *uio;
1360 1.1.1.2 fvdl int flag;
1361 1.1.1.2 fvdl {
1362 1.1.1.2 fvdl register char *cp;
1363 1.1.1.2 fvdl register int cc, ce;
1364 1.1.1.2 fvdl register struct proc *p;
1365 1.1.1.2 fvdl int i, hiwat, cnt, error, s;
1366 1.1.1.2 fvdl char obuf[OBUFSIZ];
1367 1.1.1.2 fvdl
1368 1.1.1.2 fvdl hiwat = tp->t_hiwat;
1369 1.1.1.2 fvdl cnt = uio->uio_resid;
1370 1.1.1.2 fvdl error = 0;
1371 1.1.1.2 fvdl cc = 0;
1372 1.1.1.2 fvdl loop:
1373 1.1.1.2 fvdl s = spltty();
1374 1.1.1.2 fvdl if (!ISSET(tp->t_state, TS_CARR_ON) &&
1375 1.1.1.2 fvdl !ISSET(tp->t_cflag, CLOCAL)) {
1376 1.1.1.2 fvdl if (ISSET(tp->t_state, TS_ISOPEN)) {
1377 1.1.1.2 fvdl splx(s);
1378 1.1.1.2 fvdl return (EIO);
1379 1.1.1.2 fvdl } else if (flag & IO_NDELAY) {
1380 1.1.1.2 fvdl splx(s);
1381 1.1.1.2 fvdl error = EWOULDBLOCK;
1382 1.1.1.2 fvdl goto out;
1383 1.1.1.2 fvdl } else {
1384 1.1.1.2 fvdl /* Sleep awaiting carrier. */
1385 1.1.1.2 fvdl error = ttysleep(tp,
1386 1.1.1.2 fvdl &tp->t_rawq, TTIPRI | PCATCH,ttopen, 0);
1387 1.1.1.2 fvdl splx(s);
1388 1.1.1.2 fvdl if (error)
1389 1.1.1.2 fvdl goto out;
1390 1.1.1.2 fvdl goto loop;
1391 1.1.1.2 fvdl }
1392 1.1.1.2 fvdl }
1393 1.1.1.2 fvdl splx(s);
1394 1.1.1.2 fvdl /*
1395 1.1.1.2 fvdl * Hang the process if it's in the background.
1396 1.1.1.2 fvdl */
1397 1.1.1.2 fvdl p = curproc;
1398 1.1.1.2 fvdl if (isbackground(p, tp) &&
1399 1.1.1.2 fvdl ISSET(tp->t_lflag, TOSTOP) && (p->p_flag & P_PPWAIT) == 0 &&
1400 1.1.1.2 fvdl (p->p_sigignore & sigmask(SIGTTOU)) == 0 &&
1401 1.1.1.2 fvdl (p->p_sigmask & sigmask(SIGTTOU)) == 0 &&
1402 1.1.1.2 fvdl p->p_pgrp->pg_jobc) {
1403 1.1.1.2 fvdl pgsignal(p->p_pgrp, SIGTTOU, 1);
1404 1.1.1.2 fvdl if (error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, ttybg, 0))
1405 1.1.1.2 fvdl goto out;
1406 1.1.1.2 fvdl goto loop;
1407 1.1.1.2 fvdl }
1408 1.1.1.2 fvdl /*
1409 1.1.1.2 fvdl * Process the user's data in at most OBUFSIZ chunks. Perform any
1410 1.1.1.2 fvdl * output translation. Keep track of high water mark, sleep on
1411 1.1.1.2 fvdl * overflow awaiting device aid in acquiring new space.
1412 1.1.1.2 fvdl */
1413 1.1.1.2 fvdl while (uio->uio_resid > 0 || cc > 0) {
1414 1.1.1.2 fvdl if (ISSET(tp->t_lflag, FLUSHO)) {
1415 1.1.1.2 fvdl uio->uio_resid = 0;
1416 1.1.1.2 fvdl return (0);
1417 1.1.1.2 fvdl }
1418 1.1.1.2 fvdl if (tp->t_outq.c_cc > hiwat)
1419 1.1.1.2 fvdl goto ovhiwat;
1420 1.1.1.2 fvdl /*
1421 1.1.1.2 fvdl * Grab a hunk of data from the user, unless we have some
1422 1.1.1.2 fvdl * leftover from last time.
1423 1.1.1.2 fvdl */
1424 1.1.1.2 fvdl if (cc == 0) {
1425 1.1.1.2 fvdl cc = min(uio->uio_resid, OBUFSIZ);
1426 1.1.1.2 fvdl cp = obuf;
1427 1.1.1.2 fvdl error = uiomove(cp, cc, uio);
1428 1.1.1.2 fvdl if (error) {
1429 1.1.1.2 fvdl cc = 0;
1430 1.1.1.2 fvdl break;
1431 1.1.1.2 fvdl }
1432 1.1.1.2 fvdl }
1433 1.1.1.2 fvdl /*
1434 1.1.1.2 fvdl * If nothing fancy need be done, grab those characters we
1435 1.1.1.2 fvdl * can handle without any of ttyoutput's processing and
1436 1.1.1.2 fvdl * just transfer them to the output q. For those chars
1437 1.1.1.2 fvdl * which require special processing (as indicated by the
1438 1.1.1.2 fvdl * bits in char_type), call ttyoutput. After processing
1439 1.1.1.2 fvdl * a hunk of data, look for FLUSHO so ^O's will take effect
1440 1.1.1.2 fvdl * immediately.
1441 1.1.1.2 fvdl */
1442 1.1.1.2 fvdl while (cc > 0) {
1443 1.1.1.2 fvdl if (!ISSET(tp->t_oflag, OPOST))
1444 1.1.1.2 fvdl ce = cc;
1445 1.1.1.2 fvdl else {
1446 1.1.1.2 fvdl ce = cc - scanc((u_int)cc, (u_char *)cp,
1447 1.1.1.2 fvdl (u_char *)char_type, CCLASSMASK);
1448 1.1.1.2 fvdl /*
1449 1.1.1.2 fvdl * If ce is zero, then we're processing
1450 1.1.1.2 fvdl * a special character through ttyoutput.
1451 1.1.1.2 fvdl */
1452 1.1.1.2 fvdl if (ce == 0) {
1453 1.1.1.2 fvdl tp->t_rocount = 0;
1454 1.1.1.2 fvdl if (ttyoutput(*cp, tp) >= 0) {
1455 1.1.1.2 fvdl /* No Clists, wait a bit. */
1456 1.1.1.2 fvdl ttstart(tp);
1457 1.1.1.2 fvdl if (error = ttysleep(tp, &lbolt,
1458 1.1.1.2 fvdl TTOPRI | PCATCH, ttybuf, 0))
1459 1.1.1.2 fvdl break;
1460 1.1.1.2 fvdl goto loop;
1461 1.1.1.2 fvdl }
1462 1.1.1.2 fvdl cp++;
1463 1.1.1.2 fvdl cc--;
1464 1.1.1.2 fvdl if (ISSET(tp->t_lflag, FLUSHO) ||
1465 1.1.1.2 fvdl tp->t_outq.c_cc > hiwat)
1466 1.1.1.2 fvdl goto ovhiwat;
1467 1.1.1.2 fvdl continue;
1468 1.1.1.2 fvdl }
1469 1.1.1.2 fvdl }
1470 1.1.1.2 fvdl /*
1471 1.1.1.2 fvdl * A bunch of normal characters have been found.
1472 1.1.1.2 fvdl * Transfer them en masse to the output queue and
1473 1.1.1.2 fvdl * continue processing at the top of the loop.
1474 1.1.1.2 fvdl * If there are any further characters in this
1475 1.1.1.2 fvdl * <= OBUFSIZ chunk, the first should be a character
1476 1.1.1.2 fvdl * requiring special handling by ttyoutput.
1477 1.1.1.2 fvdl */
1478 1.1.1.2 fvdl tp->t_rocount = 0;
1479 1.1.1.2 fvdl i = b_to_q(cp, ce, &tp->t_outq);
1480 1.1.1.2 fvdl ce -= i;
1481 1.1.1.2 fvdl tp->t_column += ce;
1482 1.1.1.2 fvdl cp += ce, cc -= ce, tk_nout += ce;
1483 1.1.1.2 fvdl tp->t_outcc += ce;
1484 1.1.1.2 fvdl if (i > 0) {
1485 1.1.1.2 fvdl /* No Clists, wait a bit. */
1486 1.1.1.2 fvdl ttstart(tp);
1487 1.1.1.2 fvdl if (error = ttysleep(tp,
1488 1.1.1.2 fvdl &lbolt, TTOPRI | PCATCH, ttybuf, 0))
1489 1.1.1.2 fvdl break;
1490 1.1.1.2 fvdl goto loop;
1491 1.1.1.2 fvdl }
1492 1.1.1.2 fvdl if (ISSET(tp->t_lflag, FLUSHO) ||
1493 1.1.1.2 fvdl tp->t_outq.c_cc > hiwat)
1494 1.1.1.2 fvdl break;
1495 1.1.1.2 fvdl }
1496 1.1.1.2 fvdl ttstart(tp);
1497 1.1.1.2 fvdl }
1498 1.1.1.2 fvdl out:
1499 1.1.1.2 fvdl /*
1500 1.1.1.2 fvdl * If cc is nonzero, we leave the uio structure inconsistent, as the
1501 1.1.1.2 fvdl * offset and iov pointers have moved forward, but it doesn't matter
1502 1.1.1.2 fvdl * (the call will either return short or restart with a new uio).
1503 1.1.1.2 fvdl */
1504 1.1.1.2 fvdl uio->uio_resid += cc;
1505 1.1.1.2 fvdl return (error);
1506 1.1.1.2 fvdl
1507 1.1.1.2 fvdl ovhiwat:
1508 1.1.1.2 fvdl ttstart(tp);
1509 1.1.1.2 fvdl s = spltty();
1510 1.1.1.2 fvdl /*
1511 1.1.1.2 fvdl * This can only occur if FLUSHO is set in t_lflag,
1512 1.1.1.2 fvdl * or if ttstart/oproc is synchronous (or very fast).
1513 1.1.1.2 fvdl */
1514 1.1.1.2 fvdl if (tp->t_outq.c_cc <= hiwat) {
1515 1.1.1.2 fvdl splx(s);
1516 1.1.1.2 fvdl goto loop;
1517 1.1.1.2 fvdl }
1518 1.1.1.2 fvdl if (flag & IO_NDELAY) {
1519 1.1.1.2 fvdl splx(s);
1520 1.1.1.2 fvdl uio->uio_resid += cc;
1521 1.1.1.2 fvdl return (uio->uio_resid == cnt ? EWOULDBLOCK : 0);
1522 1.1.1.2 fvdl }
1523 1.1.1.2 fvdl SET(tp->t_state, TS_ASLEEP);
1524 1.1.1.2 fvdl error = ttysleep(tp, &tp->t_outq, TTOPRI | PCATCH, ttyout, 0);
1525 1.1.1.2 fvdl splx(s);
1526 1.1.1.2 fvdl if (error)
1527 1.1.1.2 fvdl goto out;
1528 1.1.1.2 fvdl goto loop;
1529 1.1.1.2 fvdl }
1530 1.1.1.2 fvdl
1531 1.1.1.2 fvdl /*
1532 1.1.1.2 fvdl * Rubout one character from the rawq of tp
1533 1.1.1.2 fvdl * as cleanly as possible.
1534 1.1.1.2 fvdl */
1535 1.1.1.2 fvdl void
1536 1.1.1.2 fvdl ttyrub(c, tp)
1537 1.1.1.2 fvdl register int c;
1538 1.1.1.2 fvdl register struct tty *tp;
1539 1.1.1.2 fvdl {
1540 1.1.1.2 fvdl register char *cp;
1541 1.1.1.2 fvdl register int savecol;
1542 1.1.1.2 fvdl int tabc, s;
1543 1.1.1.2 fvdl
1544 1.1.1.2 fvdl if (!ISSET(tp->t_lflag, ECHO) || ISSET(tp->t_lflag, EXTPROC))
1545 1.1.1.2 fvdl return;
1546 1.1.1.2 fvdl CLR(tp->t_lflag, FLUSHO);
1547 1.1.1.2 fvdl if (ISSET(tp->t_lflag, ECHOE)) {
1548 1.1.1.2 fvdl if (tp->t_rocount == 0) {
1549 1.1.1.2 fvdl /*
1550 1.1.1.2 fvdl * Screwed by ttwrite; retype
1551 1.1.1.2 fvdl */
1552 1.1.1.2 fvdl ttyretype(tp);
1553 1.1.1.2 fvdl return;
1554 1.1.1.2 fvdl }
1555 1.1.1.2 fvdl if (c == ('\t' | TTY_QUOTE) || c == ('\n' | TTY_QUOTE))
1556 1.1.1.2 fvdl ttyrubo(tp, 2);
1557 1.1.1.2 fvdl else {
1558 1.1.1.2 fvdl CLR(c, ~TTY_CHARMASK);
1559 1.1.1.2 fvdl switch (CCLASS(c)) {
1560 1.1.1.2 fvdl case ORDINARY:
1561 1.1.1.2 fvdl ttyrubo(tp, 1);
1562 1.1.1.2 fvdl break;
1563 1.1.1.2 fvdl case BACKSPACE:
1564 1.1.1.2 fvdl case CONTROL:
1565 1.1.1.2 fvdl case NEWLINE:
1566 1.1.1.2 fvdl case RETURN:
1567 1.1.1.2 fvdl case VTAB:
1568 1.1.1.2 fvdl if (ISSET(tp->t_lflag, ECHOCTL))
1569 1.1.1.2 fvdl ttyrubo(tp, 2);
1570 1.1.1.2 fvdl break;
1571 1.1.1.2 fvdl case TAB:
1572 1.1.1.2 fvdl if (tp->t_rocount < tp->t_rawq.c_cc) {
1573 1.1.1.2 fvdl ttyretype(tp);
1574 1.1.1.2 fvdl return;
1575 1.1.1.2 fvdl }
1576 1.1.1.2 fvdl s = spltty();
1577 1.1.1.2 fvdl savecol = tp->t_column;
1578 1.1.1.2 fvdl SET(tp->t_state, TS_CNTTB);
1579 1.1.1.2 fvdl SET(tp->t_lflag, FLUSHO);
1580 1.1.1.2 fvdl tp->t_column = tp->t_rocol;
1581 1.1.1.2 fvdl cp = tp->t_rawq.c_cf;
1582 1.1.1.2 fvdl if (cp)
1583 1.1.1.2 fvdl tabc = *cp; /* XXX FIX NEXTC */
1584 1.1.1.2 fvdl for (; cp; cp = nextc(&tp->t_rawq, cp, &tabc))
1585 1.1.1.2 fvdl ttyecho(tabc, tp);
1586 1.1.1.2 fvdl CLR(tp->t_lflag, FLUSHO);
1587 1.1.1.2 fvdl CLR(tp->t_state, TS_CNTTB);
1588 1.1.1.2 fvdl splx(s);
1589 1.1.1.2 fvdl
1590 1.1.1.2 fvdl /* savecol will now be length of the tab. */
1591 1.1.1.2 fvdl savecol -= tp->t_column;
1592 1.1.1.2 fvdl tp->t_column += savecol;
1593 1.1.1.2 fvdl if (savecol > 8)
1594 1.1.1.2 fvdl savecol = 8; /* overflow screw */
1595 1.1.1.2 fvdl while (--savecol >= 0)
1596 1.1.1.2 fvdl (void)ttyoutput('\b', tp);
1597 1.1.1.2 fvdl break;
1598 1.1.1.2 fvdl default: /* XXX */
1599 1.1.1.2 fvdl #define PANICSTR "ttyrub: would panic c = %d, val = %d\n"
1600 1.1.1.2 fvdl (void)printf(PANICSTR, c, CCLASS(c));
1601 1.1.1.2 fvdl #ifdef notdef
1602 1.1.1.2 fvdl panic(PANICSTR, c, CCLASS(c));
1603 1.1.1.2 fvdl #endif
1604 1.1.1.2 fvdl }
1605 1.1.1.2 fvdl }
1606 1.1.1.2 fvdl } else if (ISSET(tp->t_lflag, ECHOPRT)) {
1607 1.1.1.2 fvdl if (!ISSET(tp->t_state, TS_ERASE)) {
1608 1.1.1.2 fvdl SET(tp->t_state, TS_ERASE);
1609 1.1.1.2 fvdl (void)ttyoutput('\\', tp);
1610 1.1.1.2 fvdl }
1611 1.1.1.2 fvdl ttyecho(c, tp);
1612 1.1.1.2 fvdl } else
1613 1.1.1.2 fvdl ttyecho(tp->t_cc[VERASE], tp);
1614 1.1.1.2 fvdl --tp->t_rocount;
1615 1.1.1.2 fvdl }
1616 1.1.1.2 fvdl
1617 1.1.1.2 fvdl /*
1618 1.1.1.2 fvdl * Back over cnt characters, erasing them.
1619 1.1.1.2 fvdl */
1620 1.1.1.2 fvdl static void
1621 1.1.1.2 fvdl ttyrubo(tp, cnt)
1622 1.1.1.2 fvdl register struct tty *tp;
1623 1.1.1.2 fvdl int cnt;
1624 1.1.1.2 fvdl {
1625 1.1.1.2 fvdl
1626 1.1.1.2 fvdl while (cnt-- > 0) {
1627 1.1.1.2 fvdl (void)ttyoutput('\b', tp);
1628 1.1.1.2 fvdl (void)ttyoutput(' ', tp);
1629 1.1.1.2 fvdl (void)ttyoutput('\b', tp);
1630 1.1.1.2 fvdl }
1631 1.1.1.2 fvdl }
1632 1.1.1.2 fvdl
1633 1.1.1.2 fvdl /*
1634 1.1.1.2 fvdl * ttyretype --
1635 1.1.1.2 fvdl * Reprint the rawq line. Note, it is assumed that c_cc has already
1636 1.1.1.2 fvdl * been checked.
1637 1.1.1.2 fvdl */
1638 1.1.1.2 fvdl void
1639 1.1.1.2 fvdl ttyretype(tp)
1640 1.1.1.2 fvdl register struct tty *tp;
1641 1.1.1.2 fvdl {
1642 1.1.1.2 fvdl register char *cp;
1643 1.1.1.2 fvdl int s, c;
1644 1.1.1.2 fvdl
1645 1.1.1.2 fvdl /* Echo the reprint character. */
1646 1.1.1.2 fvdl if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE)
1647 1.1.1.2 fvdl ttyecho(tp->t_cc[VREPRINT], tp);
1648 1.1.1.2 fvdl
1649 1.1.1.2 fvdl (void)ttyoutput('\n', tp);
1650 1.1.1.2 fvdl
1651 1.1.1.2 fvdl /*
1652 1.1.1.2 fvdl * XXX
1653 1.1.1.2 fvdl * FIX: NEXTC IS BROKEN - DOESN'T CHECK QUOTE
1654 1.1.1.2 fvdl * BIT OF FIRST CHAR.
1655 1.1.1.2 fvdl */
1656 1.1.1.2 fvdl s = spltty();
1657 1.1.1.2 fvdl for (cp = tp->t_canq.c_cf, c = (cp != NULL ? *cp : 0);
1658 1.1.1.2 fvdl cp != NULL; cp = nextc(&tp->t_canq, cp, &c))
1659 1.1.1.2 fvdl ttyecho(c, tp);
1660 1.1.1.2 fvdl for (cp = tp->t_rawq.c_cf, c = (cp != NULL ? *cp : 0);
1661 1.1.1.2 fvdl cp != NULL; cp = nextc(&tp->t_rawq, cp, &c))
1662 1.1.1.2 fvdl ttyecho(c, tp);
1663 1.1.1.2 fvdl CLR(tp->t_state, TS_ERASE);
1664 1.1.1.2 fvdl splx(s);
1665 1.1.1.2 fvdl
1666 1.1.1.2 fvdl tp->t_rocount = tp->t_rawq.c_cc;
1667 1.1.1.2 fvdl tp->t_rocol = 0;
1668 1.1.1.2 fvdl }
1669 1.1.1.2 fvdl
1670 1.1.1.2 fvdl /*
1671 1.1.1.2 fvdl * Echo a typed character to the terminal.
1672 1.1.1.2 fvdl */
1673 1.1.1.2 fvdl static void
1674 1.1.1.2 fvdl ttyecho(c, tp)
1675 1.1.1.2 fvdl register int c;
1676 1.1.1.2 fvdl register struct tty *tp;
1677 1.1.1.2 fvdl {
1678 1.1.1.2 fvdl
1679 1.1.1.2 fvdl if (!ISSET(tp->t_state, TS_CNTTB))
1680 1.1.1.2 fvdl CLR(tp->t_lflag, FLUSHO);
1681 1.1.1.2 fvdl if ((!ISSET(tp->t_lflag, ECHO) &&
1682 1.1.1.2 fvdl (!ISSET(tp->t_lflag, ECHONL) || c == '\n')) ||
1683 1.1.1.2 fvdl ISSET(tp->t_lflag, EXTPROC))
1684 1.1.1.2 fvdl return;
1685 1.1.1.2 fvdl if (ISSET(tp->t_lflag, ECHOCTL) &&
1686 1.1.1.2 fvdl (ISSET(c, TTY_CHARMASK) <= 037 && c != '\t' && c != '\n' ||
1687 1.1.1.2 fvdl ISSET(c, TTY_CHARMASK) == 0177)) {
1688 1.1.1.2 fvdl (void)ttyoutput('^', tp);
1689 1.1.1.2 fvdl CLR(c, ~TTY_CHARMASK);
1690 1.1.1.2 fvdl if (c == 0177)
1691 1.1.1.2 fvdl c = '?';
1692 1.1.1.2 fvdl else
1693 1.1.1.2 fvdl c += 'A' - 1;
1694 1.1.1.2 fvdl }
1695 1.1.1.2 fvdl (void)ttyoutput(c, tp);
1696 1.1.1.2 fvdl }
1697 1.1.1.2 fvdl
1698 1.1.1.2 fvdl /*
1699 1.1.1.2 fvdl * Wake up any readers on a tty.
1700 1.1.1.2 fvdl */
1701 1.1.1.2 fvdl void
1702 1.1.1.2 fvdl ttwakeup(tp)
1703 1.1.1.2 fvdl register struct tty *tp;
1704 1.1.1.2 fvdl {
1705 1.1.1.2 fvdl
1706 1.1.1.2 fvdl selwakeup(&tp->t_rsel);
1707 1.1.1.2 fvdl if (ISSET(tp->t_state, TS_ASYNC))
1708 1.1.1.2 fvdl pgsignal(tp->t_pgrp, SIGIO, 1);
1709 1.1.1.2 fvdl wakeup((caddr_t)&tp->t_rawq);
1710 1.1.1.2 fvdl }
1711 1.1.1.2 fvdl
1712 1.1.1.2 fvdl /*
1713 1.1.1.2 fvdl * Look up a code for a specified speed in a conversion table;
1714 1.1.1.2 fvdl * used by drivers to map software speed values to hardware parameters.
1715 1.1.1.2 fvdl */
1716 1.1.1.2 fvdl int
1717 1.1.1.2 fvdl ttspeedtab(speed, table)
1718 1.1.1.2 fvdl int speed;
1719 1.1.1.2 fvdl register struct speedtab *table;
1720 1.1.1.2 fvdl {
1721 1.1.1.2 fvdl
1722 1.1.1.2 fvdl for ( ; table->sp_speed != -1; table++)
1723 1.1.1.2 fvdl if (table->sp_speed == speed)
1724 1.1.1.2 fvdl return (table->sp_code);
1725 1.1.1.2 fvdl return (-1);
1726 1.1.1.2 fvdl }
1727 1.1.1.2 fvdl
1728 1.1.1.2 fvdl /*
1729 1.1.1.2 fvdl * Set tty hi and low water marks.
1730 1.1.1.2 fvdl *
1731 1.1.1.2 fvdl * Try to arrange the dynamics so there's about one second
1732 1.1.1.2 fvdl * from hi to low water.
1733 1.1.1.2 fvdl *
1734 1.1.1.2 fvdl */
1735 1.1.1.2 fvdl void
1736 1.1.1.2 fvdl ttsetwater(tp)
1737 1.1.1.2 fvdl struct tty *tp;
1738 1.1.1.2 fvdl {
1739 1.1.1.2 fvdl register int cps, x;
1740 1.1.1.2 fvdl
1741 1.1.1.2 fvdl #define CLAMP(x, h, l) ((x) > h ? h : ((x) < l) ? l : (x))
1742 1.1.1.2 fvdl
1743 1.1.1.2 fvdl cps = tp->t_ospeed / 10;
1744 1.1.1.2 fvdl tp->t_lowat = x = CLAMP(cps / 2, TTMAXLOWAT, TTMINLOWAT);
1745 1.1.1.2 fvdl x += cps;
1746 1.1.1.2 fvdl x = CLAMP(x, TTMAXHIWAT, TTMINHIWAT);
1747 1.1.1.2 fvdl tp->t_hiwat = roundup(x, CBSIZE);
1748 1.1.1.2 fvdl #undef CLAMP
1749 1.1.1.2 fvdl }
1750 1.1.1.2 fvdl
1751 1.1.1.2 fvdl /*
1752 1.1.1.2 fvdl * Report on state of foreground process group.
1753 1.1.1.2 fvdl */
1754 1.1.1.2 fvdl void
1755 1.1.1.2 fvdl ttyinfo(tp)
1756 1.1.1.2 fvdl register struct tty *tp;
1757 1.1.1.2 fvdl {
1758 1.1.1.2 fvdl register struct proc *p, *pick;
1759 1.1.1.2 fvdl struct timeval utime, stime;
1760 1.1.1.2 fvdl int tmp;
1761 1.1.1.2 fvdl
1762 1.1.1.2 fvdl if (ttycheckoutq(tp,0) == 0)
1763 1.1.1.2 fvdl return;
1764 1.1.1.2 fvdl
1765 1.1.1.2 fvdl /* Print load average. */
1766 1.1.1.2 fvdl tmp = (averunnable.ldavg[0] * 100 + FSCALE / 2) >> FSHIFT;
1767 1.1.1.2 fvdl ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100);
1768 1.1.1.2 fvdl
1769 1.1.1.2 fvdl if (tp->t_session == NULL)
1770 1.1.1.2 fvdl ttyprintf(tp, "not a controlling terminal\n");
1771 1.1.1.2 fvdl else if (tp->t_pgrp == NULL)
1772 1.1.1.2 fvdl ttyprintf(tp, "no foreground process group\n");
1773 1.1.1.3 fvdl else if ((p = tp->t_pgrp->pg_members.lh_first) == 0)
1774 1.1.1.2 fvdl ttyprintf(tp, "empty foreground process group\n");
1775 1.1.1.2 fvdl else {
1776 1.1.1.2 fvdl /* Pick interesting process. */
1777 1.1.1.3 fvdl for (pick = NULL; p != 0; p = p->p_pglist.le_next)
1778 1.1.1.2 fvdl if (proc_compare(pick, p))
1779 1.1.1.2 fvdl pick = p;
1780 1.1.1.2 fvdl
1781 1.1.1.2 fvdl ttyprintf(tp, " cmd: %s %d [%s] ", pick->p_comm, pick->p_pid,
1782 1.1.1.2 fvdl pick->p_stat == SRUN ? "running" :
1783 1.1.1.2 fvdl pick->p_wmesg ? pick->p_wmesg : "iowait");
1784 1.1.1.2 fvdl
1785 1.1.1.2 fvdl calcru(pick, &utime, &stime, NULL);
1786 1.1.1.2 fvdl
1787 1.1.1.2 fvdl /* Print user time. */
1788 1.1.1.2 fvdl ttyprintf(tp, "%d.%02du ",
1789 1.1.1.2 fvdl utime.tv_sec, (utime.tv_usec + 5000) / 10000);
1790 1.1.1.2 fvdl
1791 1.1.1.2 fvdl /* Print system time. */
1792 1.1.1.2 fvdl ttyprintf(tp, "%d.%02ds ",
1793 1.1.1.2 fvdl stime.tv_sec, (stime.tv_usec + 5000) / 10000);
1794 1.1.1.2 fvdl
1795 1.1.1.2 fvdl #define pgtok(a) (((a) * NBPG) / 1024)
1796 1.1.1.2 fvdl /* Print percentage cpu, resident set size. */
1797 1.1.1.2 fvdl tmp = pick->p_pctcpu * 10000 + FSCALE / 2 >> FSHIFT;
1798 1.1.1.2 fvdl ttyprintf(tp, "%d%% %dk\n",
1799 1.1.1.2 fvdl tmp / 100,
1800 1.1.1.2 fvdl pick->p_stat == SIDL || pick->p_stat == SZOMB ? 0 :
1801 1.1.1.2 fvdl #ifdef pmap_resident_count
1802 1.1.1.2 fvdl pgtok(pmap_resident_count(&pick->p_vmspace->vm_pmap))
1803 1.1.1.2 fvdl #else
1804 1.1.1.2 fvdl pgtok(pick->p_vmspace->vm_rssize)
1805 1.1.1.2 fvdl #endif
1806 1.1.1.2 fvdl );
1807 1.1.1.2 fvdl }
1808 1.1.1.2 fvdl tp->t_rocount = 0; /* so pending input will be retyped if BS */
1809 1.1.1.2 fvdl }
1810 1.1.1.2 fvdl
1811 1.1.1.2 fvdl /*
1812 1.1.1.2 fvdl * Returns 1 if p2 is "better" than p1
1813 1.1.1.2 fvdl *
1814 1.1.1.2 fvdl * The algorithm for picking the "interesting" process is thus:
1815 1.1.1.2 fvdl *
1816 1.1.1.2 fvdl * 1) Only foreground processes are eligible - implied.
1817 1.1.1.2 fvdl * 2) Runnable processes are favored over anything else. The runner
1818 1.1.1.2 fvdl * with the highest cpu utilization is picked (p_estcpu). Ties are
1819 1.1.1.2 fvdl * broken by picking the highest pid.
1820 1.1.1.2 fvdl * 3) The sleeper with the shortest sleep time is next. With ties,
1821 1.1.1.2 fvdl * we pick out just "short-term" sleepers (P_SINTR == 0).
1822 1.1.1.2 fvdl * 4) Further ties are broken by picking the highest pid.
1823 1.1.1.2 fvdl */
1824 1.1.1.2 fvdl #define ISRUN(p) (((p)->p_stat == SRUN) || ((p)->p_stat == SIDL))
1825 1.1.1.2 fvdl #define TESTAB(a, b) ((a)<<1 | (b))
1826 1.1.1.2 fvdl #define ONLYA 2
1827 1.1.1.2 fvdl #define ONLYB 1
1828 1.1.1.2 fvdl #define BOTH 3
1829 1.1.1.2 fvdl
1830 1.1.1.2 fvdl static int
1831 1.1.1.2 fvdl proc_compare(p1, p2)
1832 1.1.1.2 fvdl register struct proc *p1, *p2;
1833 1.1.1.2 fvdl {
1834 1.1.1.2 fvdl
1835 1.1.1.2 fvdl if (p1 == NULL)
1836 1.1.1.2 fvdl return (1);
1837 1.1.1.2 fvdl /*
1838 1.1.1.2 fvdl * see if at least one of them is runnable
1839 1.1.1.2 fvdl */
1840 1.1.1.2 fvdl switch (TESTAB(ISRUN(p1), ISRUN(p2))) {
1841 1.1.1.2 fvdl case ONLYA:
1842 1.1.1.2 fvdl return (0);
1843 1.1.1.2 fvdl case ONLYB:
1844 1.1.1.2 fvdl return (1);
1845 1.1.1.2 fvdl case BOTH:
1846 1.1.1.2 fvdl /*
1847 1.1.1.2 fvdl * tie - favor one with highest recent cpu utilization
1848 1.1.1.2 fvdl */
1849 1.1.1.2 fvdl if (p2->p_estcpu > p1->p_estcpu)
1850 1.1.1.2 fvdl return (1);
1851 1.1.1.2 fvdl if (p1->p_estcpu > p2->p_estcpu)
1852 1.1.1.2 fvdl return (0);
1853 1.1.1.2 fvdl return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
1854 1.1.1.2 fvdl }
1855 1.1.1.2 fvdl /*
1856 1.1.1.2 fvdl * weed out zombies
1857 1.1.1.2 fvdl */
1858 1.1.1.2 fvdl switch (TESTAB(p1->p_stat == SZOMB, p2->p_stat == SZOMB)) {
1859 1.1.1.2 fvdl case ONLYA:
1860 1.1.1.2 fvdl return (1);
1861 1.1.1.2 fvdl case ONLYB:
1862 1.1.1.2 fvdl return (0);
1863 1.1.1.2 fvdl case BOTH:
1864 1.1.1.2 fvdl return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
1865 1.1.1.2 fvdl }
1866 1.1.1.2 fvdl /*
1867 1.1.1.2 fvdl * pick the one with the smallest sleep time
1868 1.1.1.2 fvdl */
1869 1.1.1.2 fvdl if (p2->p_slptime > p1->p_slptime)
1870 1.1.1.2 fvdl return (0);
1871 1.1.1.2 fvdl if (p1->p_slptime > p2->p_slptime)
1872 1.1.1.2 fvdl return (1);
1873 1.1.1.2 fvdl /*
1874 1.1.1.2 fvdl * favor one sleeping in a non-interruptible sleep
1875 1.1.1.2 fvdl */
1876 1.1.1.2 fvdl if (p1->p_flag & P_SINTR && (p2->p_flag & P_SINTR) == 0)
1877 1.1.1.2 fvdl return (1);
1878 1.1.1.2 fvdl if (p2->p_flag & P_SINTR && (p1->p_flag & P_SINTR) == 0)
1879 1.1.1.2 fvdl return (0);
1880 1.1.1.2 fvdl return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
1881 1.1.1.2 fvdl }
1882 1.1.1.2 fvdl
1883 1.1.1.2 fvdl /*
1884 1.1.1.2 fvdl * Output char to tty; console putchar style.
1885 1.1.1.2 fvdl */
1886 1.1.1.2 fvdl int
1887 1.1.1.2 fvdl tputchar(c, tp)
1888 1.1.1.2 fvdl int c;
1889 1.1.1.2 fvdl struct tty *tp;
1890 1.1.1.2 fvdl {
1891 1.1.1.2 fvdl register int s;
1892 1.1.1.2 fvdl
1893 1.1.1.2 fvdl s = spltty();
1894 1.1.1.2 fvdl if (ISSET(tp->t_state,
1895 1.1.1.2 fvdl TS_CARR_ON | TS_ISOPEN) != (TS_CARR_ON | TS_ISOPEN)) {
1896 1.1.1.2 fvdl splx(s);
1897 1.1.1.2 fvdl return (-1);
1898 1.1.1.2 fvdl }
1899 1.1.1.2 fvdl if (c == '\n')
1900 1.1.1.2 fvdl (void)ttyoutput('\r', tp);
1901 1.1.1.2 fvdl (void)ttyoutput(c, tp);
1902 1.1.1.2 fvdl ttstart(tp);
1903 1.1.1.2 fvdl splx(s);
1904 1.1.1.2 fvdl return (0);
1905 1.1.1.2 fvdl }
1906 1.1.1.2 fvdl
1907 1.1.1.2 fvdl /*
1908 1.1.1.2 fvdl * Sleep on chan, returning ERESTART if tty changed while we napped and
1909 1.1.1.2 fvdl * returning any errors (e.g. EINTR/ETIMEDOUT) reported by tsleep. If
1910 1.1.1.2 fvdl * the tty is revoked, restarting a pending call will redo validation done
1911 1.1.1.2 fvdl * at the start of the call.
1912 1.1.1.2 fvdl */
1913 1.1.1.2 fvdl int
1914 1.1.1.2 fvdl ttysleep(tp, chan, pri, wmesg, timo)
1915 1.1.1.2 fvdl struct tty *tp;
1916 1.1.1.2 fvdl void *chan;
1917 1.1.1.2 fvdl int pri, timo;
1918 1.1.1.2 fvdl char *wmesg;
1919 1.1.1.2 fvdl {
1920 1.1.1.2 fvdl int error;
1921 1.1.1.2 fvdl short gen;
1922 1.1.1.2 fvdl
1923 1.1.1.2 fvdl gen = tp->t_gen;
1924 1.1.1.2 fvdl if (error = tsleep(chan, pri, wmesg, timo))
1925 1.1.1.2 fvdl return (error);
1926 1.1.1.2 fvdl return (tp->t_gen == gen ? 0 : ERESTART);
1927 1.1.1.2 fvdl }
1928