kernel - Major signal path adjustments to fix races, tsleep race fixes, +more
[dragonfly.git] / sys / kern / tty.c
CommitLineData
984263bc 1/*-
22ff886e
AH
2 * (MPSAFE)
3 *
984263bc
MD
4 * Copyright (c) 1982, 1986, 1990, 1991, 1993
5 * The Regents of the University of California. All rights reserved.
6 * (c) UNIX System Laboratories, Inc.
7 * All or some portions of this file are derived from material licensed
8 * to the University of California by American Telephone and Telegraph
9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10 * the permission of UNIX System Laboratories, Inc.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the University of
23 * California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 *
40 * @(#)tty.c 8.8 (Berkeley) 1/21/94
41 * $FreeBSD: src/sys/kern/tty.c,v 1.129.2.5 2002/03/11 01:32:31 dd Exp $
62c46e45 42 * $DragonFly: src/sys/kern/tty.c,v 1.46 2008/09/10 09:50:09 y0netan1 Exp $
984263bc
MD
43 */
44
22ff886e
AH
45/*
46 * MPSAFE NOTE:
47 * Almost all functions in this file are acquiring the tty token due to their
48 * access and modifications of the 'tp' (struct tty) objects.
49 */
50
984263bc
MD
51/*-
52 * TODO:
53 * o Fix races for sending the start char in ttyflush().
54 * o Handle inter-byte timeout for "MIN > 0, TIME > 0" in ttyselect().
55 * With luck, there will be MIN chars before select() returns().
56 * o Handle CLOCAL consistently for ptys. Perhaps disallow setting it.
57 * o Don't allow input in TS_ZOMBIE case. It would be visible through
58 * FIONREAD.
59 * o Do the new sio locking stuff here and use it to avoid special
60 * case for EXTPROC?
61 * o Lock PENDIN too?
62 * o Move EXTPROC and/or PENDIN to t_state?
63 * o Wrap most of ttioctl in spltty/splx.
64 * o Implement TIOCNOTTY or remove it from <sys/ioctl.h>.
65 * o Send STOP if IXOFF is toggled off while TS_TBLOCK is set.
66 * o Don't allow certain termios flags to affect disciplines other
67 * than TTYDISC. Cancel their effects before switch disciplines
68 * and ignore them if they are set while we are in another
69 * discipline.
70 * o Now that historical speed conversions are handled here, don't
71 * do them in drivers.
72 * o Check for TS_CARR_ON being set while everything is closed and not
73 * waiting for carrier. TS_CARR_ON isn't cleared if nothing is open,
74 * so it would live until the next open even if carrier drops.
75 * o Restore TS_WOPEN since it is useful in pstat. It must be cleared
76 * only when _all_ openers leave open().
77 */
78
79#include "opt_compat.h"
80#include "opt_uconsole.h"
81
82#include <sys/param.h>
83#include <sys/systm.h>
84#include <sys/filio.h>
85#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
86#include <sys/ioctl_compat.h>
87#endif
88#include <sys/proc.h>
895c1f85 89#include <sys/priv.h>
984263bc
MD
90#define TTYDEFCHARS
91#include <sys/tty.h>
a38e57d5 92#include <sys/clist.h>
984263bc
MD
93#undef TTYDEFCHARS
94#include <sys/fcntl.h>
95#include <sys/conf.h>
96#include <sys/dkstat.h>
984263bc
MD
97#include <sys/kernel.h>
98#include <sys/vnode.h>
99#include <sys/signalvar.h>
b1b4e5a6 100#include <sys/signal2.h>
984263bc
MD
101#include <sys/resourcevar.h>
102#include <sys/malloc.h>
103#include <sys/filedesc.h>
104#include <sys/sysctl.h>
8dda877a 105#include <sys/thread2.h>
984263bc
MD
106
107#include <vm/vm.h>
108#include <sys/lock.h>
109#include <vm/pmap.h>
110#include <vm/vm_map.h>
111
112MALLOC_DEFINE(M_TTYS, "ttys", "tty data structures");
113
402ed7e1
RG
114static int proc_compare (struct proc *p1, struct proc *p2);
115static int ttnread (struct tty *tp);
116static void ttyecho (int c, struct tty *tp);
117static int ttyoutput (int c, struct tty *tp);
118static void ttypend (struct tty *tp);
119static void ttyretype (struct tty *tp);
120static void ttyrub (int c, struct tty *tp);
121static void ttyrubo (struct tty *tp, int cnt);
122static void ttyunblock (struct tty *tp);
123static int ttywflush (struct tty *tp);
124static int filt_ttyread (struct knote *kn, long hint);
125static void filt_ttyrdetach (struct knote *kn);
126static int filt_ttywrite (struct knote *kn, long hint);
127static void filt_ttywdetach (struct knote *kn);
984263bc
MD
128
129/*
130 * Table with character classes and parity. The 8th bit indicates parity,
131 * the 7th bit indicates the character is an alphameric or underscore (for
132 * ALTWERASE), and the low 6 bits indicate delay type. If the low 6 bits
133 * are 0 then the character needs no special processing on output; classes
134 * other than 0 might be translated or (not currently) require delays.
135 */
136#define E 0x00 /* Even parity. */
137#define O 0x80 /* Odd parity. */
138#define PARITY(c) (char_type[c] & O)
139
140#define ALPHA 0x40 /* Alpha or underscore. */
141#define ISALPHA(c) (char_type[(c) & TTY_CHARMASK] & ALPHA)
142
143#define CCLASSMASK 0x3f
144#define CCLASS(c) (char_type[c] & CCLASSMASK)
145
146#define BS BACKSPACE
147#define CC CONTROL
148#define CR RETURN
149#define NA ORDINARY | ALPHA
150#define NL NEWLINE
151#define NO ORDINARY
152#define TB TAB
153#define VT VTAB
154
155static u_char const char_type[] = {
156 E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* nul - bel */
157 O|BS, E|TB, E|NL, O|CC, E|VT, O|CR, O|CC, E|CC, /* bs - si */
158 O|CC, E|CC, E|CC, O|CC, E|CC, O|CC, O|CC, E|CC, /* dle - etb */
159 E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* can - us */
160 O|NO, E|NO, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* sp - ' */
161 E|NO, O|NO, O|NO, E|NO, O|NO, E|NO, E|NO, O|NO, /* ( - / */
162 E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* 0 - 7 */
163 O|NA, E|NA, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* 8 - ? */
164 O|NO, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* @ - G */
165 E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* H - O */
166 E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* P - W */
167 O|NA, E|NA, E|NA, O|NO, E|NO, O|NO, O|NO, O|NA, /* X - _ */
168 E|NO, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* ` - g */
169 O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* h - o */
170 O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* p - w */
171 E|NA, O|NA, O|NA, E|NO, O|NO, E|NO, E|NO, O|CC, /* x - del */
172 /*
173 * Meta chars; should be settable per character set;
174 * for now, treat them all as normal characters.
175 */
176 NA, NA, NA, NA, NA, NA, NA, NA,
177 NA, NA, NA, NA, NA, NA, NA, NA,
178 NA, NA, NA, NA, NA, NA, NA, NA,
179 NA, NA, NA, NA, NA, NA, NA, NA,
180 NA, NA, NA, NA, NA, NA, NA, NA,
181 NA, NA, NA, NA, NA, NA, NA, NA,
182 NA, NA, NA, NA, NA, NA, NA, NA,
183 NA, NA, NA, NA, NA, NA, NA, NA,
184 NA, NA, NA, NA, NA, NA, NA, NA,
185 NA, NA, NA, NA, NA, NA, NA, NA,
186 NA, NA, NA, NA, NA, NA, NA, NA,
187 NA, NA, NA, NA, NA, NA, NA, NA,
188 NA, NA, NA, NA, NA, NA, NA, NA,
189 NA, NA, NA, NA, NA, NA, NA, NA,
190 NA, NA, NA, NA, NA, NA, NA, NA,
191 NA, NA, NA, NA, NA, NA, NA, NA,
192};
193#undef BS
194#undef CC
195#undef CR
196#undef NA
197#undef NL
198#undef NO
199#undef TB
200#undef VT
201
202/* Macros to clear/set/test flags. */
203#define SET(t, f) (t) |= (f)
204#define CLR(t, f) (t) &= ~(f)
205#define ISSET(t, f) ((t) & (f))
206
207#undef MAX_INPUT /* XXX wrong in <sys/syslimits.h> */
208#define MAX_INPUT TTYHOG /* XXX limit is usually larger for !ICANON */
209
f5d21610
JS
210uint64_t tk_nin;
211SYSCTL_OPAQUE(_kern, OID_AUTO, tk_nin, CTLFLAG_RD, &tk_nin, sizeof(tk_nin),
212 "LU", "TTY input statistic");
213uint64_t tk_nout;
214SYSCTL_OPAQUE(_kern, OID_AUTO, tk_nout, CTLFLAG_RD, &tk_nout, sizeof(tk_nout),
215 "LU", "TTY output statistic");
216uint64_t tk_rawcc;
217
984263bc
MD
218/*
219 * list of struct tty where pstat(8) can pick it up with sysctl
220 */
ddac2002 221static TAILQ_HEAD(, tty) tty_list = TAILQ_HEAD_INITIALIZER(tty_list);
984263bc
MD
222
223/*
224 * Initial open of tty, or (re)entry to standard tty line discipline.
225 */
226int
c972a82f 227ttyopen(cdev_t device, struct tty *tp)
984263bc 228{
e43a034f 229 crit_enter();
22ff886e 230 lwkt_gettoken(&tty_token);
984263bc
MD
231 tp->t_dev = device;
232 if (!ISSET(tp->t_state, TS_ISOPEN)) {
233 SET(tp->t_state, TS_ISOPEN);
cd29885a 234 if (ISSET(tp->t_cflag, CLOCAL)) {
984263bc 235 SET(tp->t_state, TS_CONNECTED);
cd29885a 236 }
984263bc
MD
237 bzero(&tp->t_winsize, sizeof(tp->t_winsize));
238 }
239 ttsetwater(tp);
22ff886e 240 lwkt_reltoken(&tty_token);
e43a034f 241 crit_exit();
984263bc
MD
242 return (0);
243}
244
245/*
246 * Handle close() on a tty line: flush and set to initial state,
247 * bumping generation number so that pending read/write calls
248 * can detect recycling of the tty.
8b90699b 249 *
984263bc
MD
250 * XXX our caller should have done `spltty(); l_close(); ttyclose();'
251 * and l_close() should have flushed, but we repeat the spltty() and
252 * the flush in case there are buggy callers.
253 */
254int
c972a82f 255ttyclose(struct tty *tp)
984263bc 256{
e43a034f 257 crit_enter();
22ff886e 258 lwkt_gettoken(&tty_token);
58c2553a 259 funsetown(&tp->t_sigio);
984263bc
MD
260 if (constty == tp)
261 constty = NULL;
262
263 ttyflush(tp, FREAD | FWRITE);
264 clist_free_cblocks(&tp->t_canq);
265 clist_free_cblocks(&tp->t_outq);
266 clist_free_cblocks(&tp->t_rawq);
267
268 tp->t_gen++;
269 tp->t_line = TTYDISC;
8b90699b 270 ttyclearsession(tp);
ddac2002 271 tp->t_state &= TS_REGISTERED; /* clear all bits except */
22ff886e 272 lwkt_reltoken(&tty_token);
e43a034f 273 crit_exit();
984263bc
MD
274 return (0);
275}
276
8b90699b
MD
277/*
278 * Disassociate the tty from its session. Traditionally this has only been
279 * a half-close, meaning that the session was still allowed to point at the
280 * tty (resulting in the tty in the ps command showing something like 'p0-'),
281 * even though the tty is no longer pointing at the session.
282 *
283 * The half close seems to be useful only for 'ps' output but there is as
284 * yet no reason to remove the feature. The full-close code is currently
285 * #if 0'd out. See also sess_rele() in kern/kern_proc.c.
286 */
287void
288ttyclearsession(struct tty *tp)
289{
290 struct session *sp;
58c2553a 291 struct pgrp *opgrp;
8b90699b 292
22ff886e 293 lwkt_gettoken(&tty_token);
58c2553a 294 opgrp = tp->t_pgrp;
8b90699b 295 tp->t_pgrp = NULL;
58c2553a
MD
296 if (opgrp) {
297 pgrel(opgrp);
298 opgrp = NULL;
299 }
300
8b90699b
MD
301 if ((sp = tp->t_session) != NULL) {
302 tp->t_session = NULL;
303#ifdef TTY_DO_FULL_CLOSE
304 /* FULL CLOSE (not yet) */
305 if (sp->s_ttyp == tp) {
306 sp->s_ttyp = NULL;
94a6eea8 307 ttyunhold(tp);
8b90699b 308 } else {
6ea70f76 309 kprintf("ttyclearsession: warning: sp->s_ttyp != tp "
8b90699b
MD
310 "%p/%p\n", sp->s_ttyp, tp);
311 }
312#endif
313 }
22ff886e 314 lwkt_reltoken(&tty_token);
8b90699b
MD
315}
316
5fd012e0 317/*
f1aeb0c0 318 * Release the tty vnode association for a session. This is the
84cca6ec
MD
319 * 'other half' of the close. Because multiple opens of /dev/tty
320 * only generate a single open to the actual tty, the file modes
321 * are locked to FREAD|FWRITE.
f1aeb0c0
MD
322 *
323 * If dorevoke is non-zero, the session is also revoked. We have to
324 * close the vnode if VCTTYISOPEN is set.
5fd012e0
MD
325 */
326void
f1aeb0c0 327ttyclosesession(struct session *sp, int dorevoke)
5fd012e0
MD
328{
329 struct vnode *vp;
5fd012e0 330
22ff886e 331 lwkt_gettoken(&tty_token);
f1aeb0c0
MD
332retry:
333 /*
334 * There may not be a controlling terminal or it may have been closed
335 * out from under us.
336 */
22ff886e
AH
337 if ((vp = sp->s_ttyvp) == NULL) {
338 lwkt_reltoken(&tty_token);
5fd012e0 339 return;
22ff886e 340 }
f1aeb0c0
MD
341
342 /*
343 * We need a lock if we have to close or revoke.
344 */
345 if ((vp->v_flag & VCTTYISOPEN) || dorevoke) {
346 vhold(vp);
347 if (vn_lock(vp, LK_EXCLUSIVE|LK_RETRY)) {
348 vdrop(vp);
349 goto retry;
350 }
351
352 /*
353 * Retry if the vnode was ripped out from under us
354 */
355 if (vp != sp->s_ttyvp) {
356 vn_unlock(vp);
357 vdrop(vp);
358 goto retry;
359 }
360
361 /*
362 * Close and revoke as needed
363 */
364 sp->s_ttyvp = NULL;
365 if (vp->v_flag & VCTTYISOPEN) {
5fd012e0 366 vclrflags(vp, VCTTYISOPEN);
87de5057 367 VOP_CLOSE(vp, FREAD|FWRITE);
5fd012e0 368 }
f1aeb0c0 369 vn_unlock(vp);
b8477cda
MD
370 if (dorevoke)
371 vrevoke(vp, proc0.p_ucred);
f1aeb0c0
MD
372 vdrop(vp);
373 } else {
374 sp->s_ttyvp = NULL;
5fd012e0 375 }
f1aeb0c0 376 vrele(vp);
22ff886e 377 lwkt_reltoken(&tty_token);
5fd012e0
MD
378}
379
984263bc
MD
380#define FLUSHQ(q) { \
381 if ((q)->c_cc) \
382 ndflush(q, (q)->c_cc); \
383}
384
385/* Is 'c' a line delimiter ("break" character)? */
386#define TTBREAKC(c, lflag) \
387 ((c) == '\n' || (((c) == cc[VEOF] || \
388 (c) == cc[VEOL] || ((c) == cc[VEOL2] && lflag & IEXTEN)) && \
389 (c) != _POSIX_VDISABLE))
390
391/*
392 * Process input of a single character received on a tty.
393 */
394int
c972a82f 395ttyinput(int c, struct tty *tp)
984263bc 396{
1fd87d54
RG
397 tcflag_t iflag, lflag;
398 cc_t *cc;
984263bc
MD
399 int i, err;
400
22ff886e 401 lwkt_gettoken(&tty_token);
984263bc
MD
402 /*
403 * If input is pending take it first.
404 */
405 lflag = tp->t_lflag;
406 if (ISSET(lflag, PENDIN))
407 ttypend(tp);
408 /*
409 * Gather stats.
410 */
f5d21610 411 if (ISSET(lflag, ICANON))
984263bc 412 ++tp->t_cancc;
f5d21610 413 else
984263bc 414 ++tp->t_rawcc;
984263bc
MD
415 ++tk_nin;
416
417 /*
418 * Block further input iff:
419 * current input > threshold AND input is available to user program
420 * AND input flow control is enabled and not yet invoked.
421 * The 3 is slop for PARMRK.
422 */
423 iflag = tp->t_iflag;
424 if (tp->t_rawq.c_cc + tp->t_canq.c_cc > tp->t_ihiwat - 3 &&
425 (!ISSET(lflag, ICANON) || tp->t_canq.c_cc != 0) &&
426 (ISSET(tp->t_cflag, CRTS_IFLOW) || ISSET(iflag, IXOFF)) &&
427 !ISSET(tp->t_state, TS_TBLOCK))
428 ttyblock(tp);
429
430 /* Handle exceptional conditions (break, parity, framing). */
431 cc = tp->t_cc;
432 err = (ISSET(c, TTY_ERRORMASK));
433 if (err) {
434 CLR(c, TTY_ERRORMASK);
435 if (ISSET(err, TTY_BI)) {
22ff886e
AH
436 if (ISSET(iflag, IGNBRK)) {
437 lwkt_reltoken(&tty_token);
984263bc 438 return (0);
22ff886e 439 }
984263bc
MD
440 if (ISSET(iflag, BRKINT)) {
441 ttyflush(tp, FREAD | FWRITE);
442 pgsignal(tp->t_pgrp, SIGINT, 1);
443 goto endcase;
444 }
445 if (ISSET(iflag, PARMRK))
446 goto parmrk;
447 } else if ((ISSET(err, TTY_PE) && ISSET(iflag, INPCK))
448 || ISSET(err, TTY_FE)) {
22ff886e
AH
449 if (ISSET(iflag, IGNPAR)) {
450 lwkt_reltoken(&tty_token);
984263bc 451 return (0);
22ff886e 452 }
984263bc
MD
453 else if (ISSET(iflag, PARMRK)) {
454parmrk:
455 if (tp->t_rawq.c_cc + tp->t_canq.c_cc >
456 MAX_INPUT - 3)
457 goto input_overflow;
0ced1954
MD
458 clist_putc(0377 | TTY_QUOTE, &tp->t_rawq);
459 clist_putc(0 | TTY_QUOTE, &tp->t_rawq);
460 clist_putc(c | TTY_QUOTE, &tp->t_rawq);
984263bc
MD
461 goto endcase;
462 } else
463 c = 0;
464 }
465 }
466
467 if (!ISSET(tp->t_state, TS_TYPEN) && ISSET(iflag, ISTRIP))
468 CLR(c, 0x80);
469 if (!ISSET(lflag, EXTPROC)) {
470 /*
471 * Check for literal nexting very first
472 */
473 if (ISSET(tp->t_state, TS_LNCH)) {
474 SET(c, TTY_QUOTE);
475 CLR(tp->t_state, TS_LNCH);
476 }
477 /*
478 * Scan for special characters. This code
479 * is really just a big case statement with
480 * non-constant cases. The bottom of the
481 * case statement is labeled ``endcase'', so goto
482 * it after a case match, or similar.
483 */
484
485 /*
486 * Control chars which aren't controlled
487 * by ICANON, ISIG, or IXON.
488 */
489 if (ISSET(lflag, IEXTEN)) {
490 if (CCEQ(cc[VLNEXT], c)) {
491 if (ISSET(lflag, ECHO)) {
492 if (ISSET(lflag, ECHOE)) {
493 (void)ttyoutput('^', tp);
494 (void)ttyoutput('\b', tp);
495 } else
496 ttyecho(c, tp);
497 }
498 SET(tp->t_state, TS_LNCH);
499 goto endcase;
500 }
501 if (CCEQ(cc[VDISCARD], c)) {
502 if (ISSET(lflag, FLUSHO))
503 CLR(tp->t_lflag, FLUSHO);
504 else {
505 ttyflush(tp, FWRITE);
506 ttyecho(c, tp);
507 if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
508 ttyretype(tp);
509 SET(tp->t_lflag, FLUSHO);
510 }
511 goto startoutput;
512 }
513 }
514 /*
515 * Signals.
516 */
517 if (ISSET(lflag, ISIG)) {
518 if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) {
519 if (!ISSET(lflag, NOFLSH))
520 ttyflush(tp, FREAD | FWRITE);
521 ttyecho(c, tp);
522 pgsignal(tp->t_pgrp,
523 CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1);
524 goto endcase;
525 }
526 if (CCEQ(cc[VSUSP], c)) {
527 if (!ISSET(lflag, NOFLSH))
528 ttyflush(tp, FREAD);
529 ttyecho(c, tp);
530 pgsignal(tp->t_pgrp, SIGTSTP, 1);
531 goto endcase;
532 }
533 }
534 /*
535 * Handle start/stop characters.
536 */
537 if (ISSET(iflag, IXON)) {
538 if (CCEQ(cc[VSTOP], c)) {
539 if (!ISSET(tp->t_state, TS_TTSTOP)) {
540 SET(tp->t_state, TS_TTSTOP);
541 (*tp->t_stop)(tp, 0);
22ff886e 542 lwkt_reltoken(&tty_token);
984263bc
MD
543 return (0);
544 }
22ff886e
AH
545 if (!CCEQ(cc[VSTART], c)) {
546 lwkt_reltoken(&tty_token);
984263bc 547 return (0);
22ff886e 548 }
984263bc
MD
549 /*
550 * if VSTART == VSTOP then toggle
551 */
552 goto endcase;
553 }
554 if (CCEQ(cc[VSTART], c))
555 goto restartoutput;
556 }
557 /*
558 * IGNCR, ICRNL, & INLCR
559 */
560 if (c == '\r') {
22ff886e
AH
561 if (ISSET(iflag, IGNCR)) {
562 lwkt_reltoken(&tty_token);
984263bc 563 return (0);
22ff886e 564 }
984263bc
MD
565 else if (ISSET(iflag, ICRNL))
566 c = '\n';
567 } else if (c == '\n' && ISSET(iflag, INLCR))
568 c = '\r';
569 }
570 if (!ISSET(tp->t_lflag, EXTPROC) && ISSET(lflag, ICANON)) {
571 /*
572 * From here on down canonical mode character
573 * processing takes place.
574 */
575 /*
576 * erase or erase2 (^H / ^?)
577 */
578 if (CCEQ(cc[VERASE], c) || CCEQ(cc[VERASE2], c) ) {
579 if (tp->t_rawq.c_cc)
0ced1954 580 ttyrub(clist_unputc(&tp->t_rawq), tp);
984263bc
MD
581 goto endcase;
582 }
583 /*
584 * kill (^U)
585 */
586 if (CCEQ(cc[VKILL], c)) {
587 if (ISSET(lflag, ECHOKE) &&
588 tp->t_rawq.c_cc == tp->t_rocount &&
589 !ISSET(lflag, ECHOPRT))
590 while (tp->t_rawq.c_cc)
0ced1954 591 ttyrub(clist_unputc(&tp->t_rawq), tp);
984263bc
MD
592 else {
593 ttyecho(c, tp);
594 if (ISSET(lflag, ECHOK) ||
595 ISSET(lflag, ECHOKE))
596 ttyecho('\n', tp);
597 FLUSHQ(&tp->t_rawq);
598 tp->t_rocount = 0;
599 }
600 CLR(tp->t_state, TS_LOCAL);
601 goto endcase;
602 }
603 /*
604 * word erase (^W)
605 */
606 if (CCEQ(cc[VWERASE], c) && ISSET(lflag, IEXTEN)) {
607 int ctype;
608
609 /*
610 * erase whitespace
611 */
0ced1954 612 while ((c = clist_unputc(&tp->t_rawq)) == ' ' || c == '\t')
984263bc
MD
613 ttyrub(c, tp);
614 if (c == -1)
615 goto endcase;
616 /*
617 * erase last char of word and remember the
618 * next chars type (for ALTWERASE)
619 */
620 ttyrub(c, tp);
0ced1954 621 c = clist_unputc(&tp->t_rawq);
984263bc
MD
622 if (c == -1)
623 goto endcase;
624 if (c == ' ' || c == '\t') {
0ced1954 625 clist_putc(c, &tp->t_rawq);
984263bc
MD
626 goto endcase;
627 }
628 ctype = ISALPHA(c);
629 /*
630 * erase rest of word
631 */
632 do {
633 ttyrub(c, tp);
0ced1954 634 c = clist_unputc(&tp->t_rawq);
984263bc
MD
635 if (c == -1)
636 goto endcase;
637 } while (c != ' ' && c != '\t' &&
638 (!ISSET(lflag, ALTWERASE) || ISALPHA(c) == ctype));
0ced1954 639 clist_putc(c, &tp->t_rawq);
984263bc
MD
640 goto endcase;
641 }
642 /*
643 * reprint line (^R)
644 */
645 if (CCEQ(cc[VREPRINT], c) && ISSET(lflag, IEXTEN)) {
646 ttyretype(tp);
647 goto endcase;
648 }
649 /*
650 * ^T - kernel info and generate SIGINFO
651 */
652 if (CCEQ(cc[VSTATUS], c) && ISSET(lflag, IEXTEN)) {
653 if (ISSET(lflag, ISIG))
654 pgsignal(tp->t_pgrp, SIGINFO, 1);
655 if (!ISSET(lflag, NOKERNINFO))
656 ttyinfo(tp);
657 goto endcase;
658 }
dcf5aa01
MD
659 if (CCEQ(cc[VCHECKPT], c) && ISSET(lflag, IEXTEN)) {
660 if (ISSET(lflag, ISIG))
661 pgsignal(tp->t_pgrp, SIGCKPT, 1);
662 goto endcase;
663 }
984263bc
MD
664 }
665 /*
666 * Check for input buffer overflow
667 */
668 if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= MAX_INPUT) {
669input_overflow:
670 if (ISSET(iflag, IMAXBEL)) {
671 if (tp->t_outq.c_cc < tp->t_ohiwat)
672 (void)ttyoutput(CTRL('g'), tp);
673 }
674 goto endcase;
675 }
676
677 if ( c == 0377 && ISSET(iflag, PARMRK) && !ISSET(iflag, ISTRIP)
678 && ISSET(iflag, IGNBRK|IGNPAR) != (IGNBRK|IGNPAR))
0ced1954 679 clist_putc(0377 | TTY_QUOTE, &tp->t_rawq);
984263bc
MD
680
681 /*
682 * Put data char in q for user and
683 * wakeup on seeing a line delimiter.
684 */
0ced1954 685 if (clist_putc(c, &tp->t_rawq) >= 0) {
984263bc
MD
686 if (!ISSET(lflag, ICANON)) {
687 ttwakeup(tp);
688 ttyecho(c, tp);
689 goto endcase;
690 }
691 if (TTBREAKC(c, lflag)) {
692 tp->t_rocount = 0;
693 catq(&tp->t_rawq, &tp->t_canq);
694 ttwakeup(tp);
695 } else if (tp->t_rocount++ == 0)
696 tp->t_rocol = tp->t_column;
697 if (ISSET(tp->t_state, TS_ERASE)) {
698 /*
699 * end of prterase \.../
700 */
701 CLR(tp->t_state, TS_ERASE);
702 (void)ttyoutput('/', tp);
703 }
704 i = tp->t_column;
705 ttyecho(c, tp);
706 if (CCEQ(cc[VEOF], c) && ISSET(lflag, ECHO)) {
707 /*
708 * Place the cursor over the '^' of the ^D.
709 */
710 i = imin(2, tp->t_column - i);
711 while (i > 0) {
712 (void)ttyoutput('\b', tp);
713 i--;
714 }
715 }
716 }
717endcase:
718 /*
719 * IXANY means allow any character to restart output.
720 */
721 if (ISSET(tp->t_state, TS_TTSTOP) &&
22ff886e
AH
722 !ISSET(iflag, IXANY) && cc[VSTART] != cc[VSTOP]) {
723 lwkt_reltoken(&tty_token);
984263bc 724 return (0);
22ff886e 725 }
984263bc
MD
726restartoutput:
727 CLR(tp->t_lflag, FLUSHO);
728 CLR(tp->t_state, TS_TTSTOP);
729startoutput:
22ff886e 730 lwkt_reltoken(&tty_token);
984263bc
MD
731 return (ttstart(tp));
732}
733
734/*
735 * Output a single character on a tty, doing output processing
736 * as needed (expanding tabs, newline processing, etc.).
737 * Returns < 0 if succeeds, otherwise returns char to resend.
738 * Must be recursive.
739 */
740static int
c972a82f 741ttyoutput(int c, struct tty *tp)
984263bc 742{
1fd87d54 743 tcflag_t oflag;
e43a034f 744 int col;
984263bc 745
22ff886e 746 lwkt_gettoken(&tty_token);
984263bc
MD
747 oflag = tp->t_oflag;
748 if (!ISSET(oflag, OPOST)) {
22ff886e
AH
749 if (ISSET(tp->t_lflag, FLUSHO)) {
750 lwkt_reltoken(&tty_token);
984263bc 751 return (-1);
22ff886e
AH
752 }
753 if (clist_putc(c, &tp->t_outq)) {
754 lwkt_reltoken(&tty_token);
984263bc 755 return (c);
22ff886e 756 }
984263bc
MD
757 tk_nout++;
758 tp->t_outcc++;
22ff886e 759 lwkt_reltoken(&tty_token);
984263bc
MD
760 return (-1);
761 }
762 /*
763 * Do tab expansion if OXTABS is set. Special case if we external
764 * processing, we don't do the tab expansion because we'll probably
765 * get it wrong. If tab expansion needs to be done, let it happen
766 * externally.
767 */
768 CLR(c, ~TTY_CHARMASK);
769 if (c == '\t' &&
770 ISSET(oflag, OXTABS) && !ISSET(tp->t_lflag, EXTPROC)) {
771 c = 8 - (tp->t_column & 7);
772 if (!ISSET(tp->t_lflag, FLUSHO)) {
e43a034f 773 crit_enter(); /* Don't interrupt tabs. */
984263bc
MD
774 c -= b_to_q(" ", c, &tp->t_outq);
775 tk_nout += c;
776 tp->t_outcc += c;
e43a034f 777 crit_exit();
984263bc
MD
778 }
779 tp->t_column += c;
22ff886e 780 lwkt_reltoken(&tty_token);
984263bc
MD
781 return (c ? -1 : '\t');
782 }
22ff886e
AH
783 if (c == CEOT && ISSET(oflag, ONOEOT)) {
784 lwkt_reltoken(&tty_token);
984263bc 785 return (-1);
22ff886e 786 }
984263bc
MD
787
788 /*
789 * Newline translation: if ONLCR is set,
790 * translate newline into "\r\n".
791 */
792 if (c == '\n' && ISSET(tp->t_oflag, ONLCR)) {
793 tk_nout++;
794 tp->t_outcc++;
22ff886e
AH
795 if (!ISSET(tp->t_lflag, FLUSHO) && clist_putc('\r', &tp->t_outq)) {
796 lwkt_reltoken(&tty_token);
984263bc 797 return (c);
22ff886e 798 }
984263bc
MD
799 }
800 /* If OCRNL is set, translate "\r" into "\n". */
801 else if (c == '\r' && ISSET(tp->t_oflag, OCRNL))
802 c = '\n';
803 /* If ONOCR is set, don't transmit CRs when on column 0. */
22ff886e
AH
804 else if (c == '\r' && ISSET(tp->t_oflag, ONOCR) && tp->t_column == 0) {
805 lwkt_reltoken(&tty_token);
984263bc 806 return (-1);
22ff886e 807 }
984263bc
MD
808
809 tk_nout++;
810 tp->t_outcc++;
22ff886e
AH
811 if (!ISSET(tp->t_lflag, FLUSHO) && clist_putc(c, &tp->t_outq)) {
812 lwkt_reltoken(&tty_token);
984263bc 813 return (c);
22ff886e 814 }
984263bc
MD
815
816 col = tp->t_column;
817 switch (CCLASS(c)) {
818 case BACKSPACE:
819 if (col > 0)
820 --col;
821 break;
822 case CONTROL:
823 break;
824 case NEWLINE:
825 if (ISSET(tp->t_oflag, ONLCR | ONLRET))
826 col = 0;
827 break;
828 case RETURN:
829 col = 0;
830 break;
831 case ORDINARY:
832 ++col;
833 break;
834 case TAB:
835 col = (col + 8) & ~7;
836 break;
837 }
838 tp->t_column = col;
22ff886e 839 lwkt_reltoken(&tty_token);
984263bc
MD
840 return (-1);
841}
842
843/*
844 * Ioctls for all tty devices. Called after line-discipline specific ioctl
845 * has been called to do discipline-specific functions and/or reject any
846 * of these ioctl commands.
847 */
848/* ARGSUSED */
849int
dadab5e9 850ttioctl(struct tty *tp, u_long cmd, void *data, int flag)
984263bc 851{
dadab5e9 852 struct thread *td = curthread;
08f2f1bb 853 struct lwp *lp = td->td_lwp;
dadab5e9 854 struct proc *p = td->td_proc;
58c2553a 855 struct pgrp *opgrp;
94a6eea8 856 struct tty *otp;
e43a034f 857 int error;
984263bc 858
dadab5e9 859 KKASSERT(p);
22ff886e
AH
860 lwkt_gettoken(&tty_token);
861 lwkt_gettoken(&proc_token);
616516c8 862 lwkt_gettoken(&p->p_token);
dadab5e9 863
984263bc
MD
864 /* If the ioctl involves modification, hang if in the background. */
865 switch (cmd) {
866 case TIOCCBRK:
867 case TIOCCONS:
868 case TIOCDRAIN:
869 case TIOCEXCL:
870 case TIOCFLUSH:
871#ifdef TIOCHPCL
872 case TIOCHPCL:
873#endif
874 case TIOCNXCL:
875 case TIOCSBRK:
876 case TIOCSCTTY:
877 case TIOCSDRAINWAIT:
878 case TIOCSETA:
879 case TIOCSETAF:
880 case TIOCSETAW:
881 case TIOCSETD:
882 case TIOCSPGRP:
883 case TIOCSTART:
884 case TIOCSTAT:
885 case TIOCSTI:
886 case TIOCSTOP:
887 case TIOCSWINSZ:
888#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
889 case TIOCLBIC:
890 case TIOCLBIS:
891 case TIOCLSET:
892 case TIOCSETC:
893 case OTIOCSETD:
894 case TIOCSETN:
895 case TIOCSETP:
896 case TIOCSLTC:
897#endif
4643740a 898 while (isbackground(p, tp) && !(p->p_flags & P_PPWAIT) &&
984263bc 899 !SIGISMEMBER(p->p_sigignore, SIGTTOU) &&
08f2f1bb 900 !SIGISMEMBER(lp->lwp_sigmask, SIGTTOU)) {
22ff886e 901 if (p->p_pgrp->pg_jobc == 0) {
616516c8 902 lwkt_reltoken(&p->p_token);
22ff886e
AH
903 lwkt_reltoken(&proc_token);
904 lwkt_reltoken(&tty_token);
984263bc 905 return (EIO);
22ff886e 906 }
984263bc 907 pgsignal(p->p_pgrp, SIGTTOU, 1);
377d4740 908 error = ttysleep(tp, &lbolt, PCATCH, "ttybg1",
984263bc 909 0);
22ff886e 910 if (error) {
616516c8 911 lwkt_reltoken(&p->p_token);
22ff886e
AH
912 lwkt_reltoken(&proc_token);
913 lwkt_reltoken(&tty_token);
984263bc 914 return (error);
22ff886e 915 }
984263bc
MD
916 }
917 break;
918 }
919
920 switch (cmd) { /* Process the ioctl. */
921 case FIOASYNC: /* set/clear async i/o */
e43a034f 922 crit_enter();
984263bc
MD
923 if (*(int *)data)
924 SET(tp->t_state, TS_ASYNC);
925 else
926 CLR(tp->t_state, TS_ASYNC);
e43a034f 927 crit_exit();
984263bc 928 break;
984263bc 929 case FIONREAD: /* get # bytes to read */
e43a034f 930 crit_enter();
984263bc 931 *(int *)data = ttnread(tp);
e43a034f 932 crit_exit();
984263bc
MD
933 break;
934
935 case FIOSETOWN:
936 /*
937 * Policy -- Don't allow FIOSETOWN on someone else's
938 * controlling tty
939 */
22ff886e 940 if (tp->t_session != NULL && !isctty(p, tp)) {
616516c8 941 lwkt_reltoken(&p->p_token);
22ff886e
AH
942 lwkt_reltoken(&proc_token);
943 lwkt_reltoken(&tty_token);
984263bc 944 return (ENOTTY);
22ff886e 945 }
984263bc
MD
946
947 error = fsetown(*(int *)data, &tp->t_sigio);
22ff886e 948 if (error) {
616516c8 949 lwkt_reltoken(&p->p_token);
22ff886e
AH
950 lwkt_reltoken(&proc_token);
951 lwkt_reltoken(&tty_token);
984263bc 952 return (error);
22ff886e 953 }
984263bc
MD
954 break;
955 case FIOGETOWN:
22ff886e 956 if (tp->t_session != NULL && !isctty(p, tp)) {
616516c8 957 lwkt_reltoken(&p->p_token);
22ff886e
AH
958 lwkt_reltoken(&proc_token);
959 lwkt_reltoken(&tty_token);
984263bc 960 return (ENOTTY);
22ff886e 961 }
b5c4d81f 962 *(int *)data = fgetown(&tp->t_sigio);
984263bc
MD
963 break;
964
965 case TIOCEXCL: /* set exclusive use of tty */
e43a034f 966 crit_enter();
984263bc 967 SET(tp->t_state, TS_XCLUDE);
e43a034f 968 crit_exit();
984263bc
MD
969 break;
970 case TIOCFLUSH: { /* flush buffers */
1fd87d54 971 int flags = *(int *)data;
984263bc
MD
972
973 if (flags == 0)
974 flags = FREAD | FWRITE;
975 else
976 flags &= FREAD | FWRITE;
977 ttyflush(tp, flags);
978 break;
979 }
980 case TIOCCONS: /* become virtual console */
981 if (*(int *)data) {
982 if (constty && constty != tp &&
22ff886e 983 ISSET(constty->t_state, TS_CONNECTED)) {
616516c8 984 lwkt_reltoken(&p->p_token);
22ff886e
AH
985 lwkt_reltoken(&proc_token);
986 lwkt_reltoken(&tty_token);
984263bc 987 return (EBUSY);
22ff886e 988 }
984263bc 989#ifndef UCONSOLE
22ff886e 990 if ((error = priv_check(td, PRIV_ROOT)) != 0) {
616516c8 991 lwkt_reltoken(&p->p_token);
22ff886e
AH
992 lwkt_reltoken(&proc_token);
993 lwkt_reltoken(&tty_token);
984263bc 994 return (error);
22ff886e 995 }
984263bc
MD
996#endif
997 constty = tp;
998 } else if (tp == constty)
999 constty = NULL;
1000 break;
1001 case TIOCDRAIN: /* wait till output drained */
1002 error = ttywait(tp);
22ff886e 1003 if (error) {
616516c8 1004 lwkt_reltoken(&p->p_token);
22ff886e
AH
1005 lwkt_reltoken(&proc_token);
1006 lwkt_reltoken(&tty_token);
984263bc 1007 return (error);
22ff886e 1008 }
984263bc
MD
1009 break;
1010 case TIOCGETA: { /* get termios struct */
1011 struct termios *t = (struct termios *)data;
1012
1013 bcopy(&tp->t_termios, t, sizeof(struct termios));
1014 break;
1015 }
1016 case TIOCGETD: /* get line discipline */
1017 *(int *)data = tp->t_line;
1018 break;
1019 case TIOCGWINSZ: /* get window size */
1020 *(struct winsize *)data = tp->t_winsize;
1021 break;
1022 case TIOCGPGRP: /* get pgrp of tty */
22ff886e 1023 if (!isctty(p, tp)) {
616516c8 1024 lwkt_reltoken(&p->p_token);
22ff886e
AH
1025 lwkt_reltoken(&proc_token);
1026 lwkt_reltoken(&tty_token);
984263bc 1027 return (ENOTTY);
22ff886e 1028 }
984263bc
MD
1029 *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
1030 break;
fa94d286 1031 case TIOCGSID: /* get sid of tty */
22ff886e 1032 if (!isctty(p, tp)) {
616516c8 1033 lwkt_reltoken(&p->p_token);
22ff886e
AH
1034 lwkt_reltoken(&proc_token);
1035 lwkt_reltoken(&tty_token);
fa94d286 1036 return (ENOTTY);
22ff886e 1037 }
fa94d286
PA
1038 *(int *)data = tp->t_session->s_sid;
1039 break;
984263bc
MD
1040#ifdef TIOCHPCL
1041 case TIOCHPCL: /* hang up on last close */
e43a034f 1042 crit_enter();
984263bc 1043 SET(tp->t_cflag, HUPCL);
e43a034f 1044 crit_exit();
984263bc
MD
1045 break;
1046#endif
1047 case TIOCNXCL: /* reset exclusive use of tty */
e43a034f 1048 crit_enter();
984263bc 1049 CLR(tp->t_state, TS_XCLUDE);
e43a034f 1050 crit_exit();
984263bc
MD
1051 break;
1052 case TIOCOUTQ: /* output queue size */
1053 *(int *)data = tp->t_outq.c_cc;
1054 break;
1055 case TIOCSETA: /* set termios struct */
1056 case TIOCSETAW: /* drain output, set */
1057 case TIOCSETAF: { /* drn out, fls in, set */
1fd87d54 1058 struct termios *t = (struct termios *)data;
984263bc
MD
1059
1060 if (t->c_ispeed == 0)
1061 t->c_ispeed = t->c_ospeed;
1062 if (t->c_ispeed == 0)
1063 t->c_ispeed = tp->t_ospeed;
22ff886e 1064 if (t->c_ispeed == 0) {
616516c8 1065 lwkt_reltoken(&p->p_token);
22ff886e
AH
1066 lwkt_reltoken(&proc_token);
1067 lwkt_reltoken(&tty_token);
984263bc 1068 return (EINVAL);
22ff886e 1069 }
e43a034f 1070 crit_enter();
984263bc
MD
1071 if (cmd == TIOCSETAW || cmd == TIOCSETAF) {
1072 error = ttywait(tp);
1073 if (error) {
e43a034f 1074 crit_exit();
616516c8 1075 lwkt_reltoken(&p->p_token);
22ff886e
AH
1076 lwkt_reltoken(&proc_token);
1077 lwkt_reltoken(&tty_token);
984263bc
MD
1078 return (error);
1079 }
1080 if (cmd == TIOCSETAF)
1081 ttyflush(tp, FREAD);
1082 }
1083 if (!ISSET(t->c_cflag, CIGNORE)) {
1084 /*
1085 * Set device hardware.
1086 */
1087 if (tp->t_param && (error = (*tp->t_param)(tp, t))) {
e43a034f 1088 crit_exit();
616516c8 1089 lwkt_reltoken(&p->p_token);
22ff886e
AH
1090 lwkt_reltoken(&proc_token);
1091 lwkt_reltoken(&tty_token);
984263bc
MD
1092 return (error);
1093 }
1094 if (ISSET(t->c_cflag, CLOCAL) &&
1095 !ISSET(tp->t_cflag, CLOCAL)) {
1096 /*
1097 * XXX disconnections would be too hard to
1098 * get rid of without this kludge. The only
1099 * way to get rid of controlling terminals
1100 * is to exit from the session leader.
1101 */
1102 CLR(tp->t_state, TS_ZOMBIE);
1103
1104 wakeup(TSA_CARR_ON(tp));
1105 ttwakeup(tp);
1106 ttwwakeup(tp);
1107 }
1108 if ((ISSET(tp->t_state, TS_CARR_ON) ||
1109 ISSET(t->c_cflag, CLOCAL)) &&
1110 !ISSET(tp->t_state, TS_ZOMBIE))
1111 SET(tp->t_state, TS_CONNECTED);
1112 else
1113 CLR(tp->t_state, TS_CONNECTED);
1114 tp->t_cflag = t->c_cflag;
1115 tp->t_ispeed = t->c_ispeed;
1116 if (t->c_ospeed != 0)
1117 tp->t_ospeed = t->c_ospeed;
1118 ttsetwater(tp);
1119 }
1120 if (ISSET(t->c_lflag, ICANON) != ISSET(tp->t_lflag, ICANON) &&
1121 cmd != TIOCSETAF) {
1122 if (ISSET(t->c_lflag, ICANON))
1123 SET(tp->t_lflag, PENDIN);
1124 else {
1125 /*
1126 * XXX we really shouldn't allow toggling
1127 * ICANON while we're in a non-termios line
1128 * discipline. Now we have to worry about
1129 * panicing for a null queue.
1130 */
1131 if (tp->t_canq.c_cbreserved > 0 &&
1132 tp->t_rawq.c_cbreserved > 0) {
1133 catq(&tp->t_rawq, &tp->t_canq);
1134 /*
1135 * XXX the queue limits may be
1136 * different, so the old queue
1137 * swapping method no longer works.
1138 */
1139 catq(&tp->t_canq, &tp->t_rawq);
1140 }
1141 CLR(tp->t_lflag, PENDIN);
1142 }
1143 ttwakeup(tp);
1144 }
1145 tp->t_iflag = t->c_iflag;
1146 tp->t_oflag = t->c_oflag;
1147 /*
1148 * Make the EXTPROC bit read only.
1149 */
1150 if (ISSET(tp->t_lflag, EXTPROC))
1151 SET(t->c_lflag, EXTPROC);
1152 else
1153 CLR(t->c_lflag, EXTPROC);
1154 tp->t_lflag = t->c_lflag | ISSET(tp->t_lflag, PENDIN);
1155 if (t->c_cc[VMIN] != tp->t_cc[VMIN] ||
1156 t->c_cc[VTIME] != tp->t_cc[VTIME])
1157 ttwakeup(tp);
1158 bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc));
e43a034f 1159 crit_exit();
984263bc
MD
1160 break;
1161 }
1162 case TIOCSETD: { /* set line discipline */
1fd87d54 1163 int t = *(int *)data;
b13267a5 1164 cdev_t device = tp->t_dev;
984263bc 1165
22ff886e 1166 if ((u_int)t >= nlinesw) {
616516c8 1167 lwkt_reltoken(&p->p_token);
22ff886e
AH
1168 lwkt_reltoken(&proc_token);
1169 lwkt_reltoken(&tty_token);
984263bc 1170 return (ENXIO);
22ff886e 1171 }
984263bc 1172 if (t != tp->t_line) {
e43a034f 1173 crit_enter();
984263bc
MD
1174 (*linesw[tp->t_line].l_close)(tp, flag);
1175 error = (*linesw[t].l_open)(device, tp);
1176 if (error) {
1177 (void)(*linesw[tp->t_line].l_open)(device, tp);
e43a034f 1178 crit_exit();
616516c8 1179 lwkt_reltoken(&p->p_token);
22ff886e
AH
1180 lwkt_reltoken(&proc_token);
1181 lwkt_reltoken(&tty_token);
984263bc
MD
1182 return (error);
1183 }
1184 tp->t_line = t;
e43a034f 1185 crit_exit();
984263bc
MD
1186 }
1187 break;
1188 }
1189 case TIOCSTART: /* start output, like ^Q */
e43a034f 1190 crit_enter();
984263bc
MD
1191 if (ISSET(tp->t_state, TS_TTSTOP) ||
1192 ISSET(tp->t_lflag, FLUSHO)) {
1193 CLR(tp->t_lflag, FLUSHO);
1194 CLR(tp->t_state, TS_TTSTOP);
1195 ttstart(tp);
1196 }
e43a034f 1197 crit_exit();
984263bc
MD
1198 break;
1199 case TIOCSTI: /* simulate terminal input */
22ff886e 1200 if ((flag & FREAD) == 0 && priv_check(td, PRIV_ROOT)) {
616516c8 1201 lwkt_reltoken(&p->p_token);
22ff886e
AH
1202 lwkt_reltoken(&proc_token);
1203 lwkt_reltoken(&tty_token);
984263bc 1204 return (EPERM);
22ff886e
AH
1205 }
1206 if (!isctty(p, tp) && priv_check(td, PRIV_ROOT)) {
616516c8 1207 lwkt_reltoken(&p->p_token);
22ff886e
AH
1208 lwkt_reltoken(&proc_token);
1209 lwkt_reltoken(&tty_token);
984263bc 1210 return (EACCES);
22ff886e 1211 }
e43a034f 1212 crit_enter();
984263bc 1213 (*linesw[tp->t_line].l_rint)(*(u_char *)data, tp);
e43a034f 1214 crit_exit();
984263bc
MD
1215 break;
1216 case TIOCSTOP: /* stop output, like ^S */
e43a034f 1217 crit_enter();
984263bc
MD
1218 if (!ISSET(tp->t_state, TS_TTSTOP)) {
1219 SET(tp->t_state, TS_TTSTOP);
1220 (*tp->t_stop)(tp, 0);
1221 }
e43a034f 1222 crit_exit();
984263bc
MD
1223 break;
1224 case TIOCSCTTY: /* become controlling tty */
1225 /* Session ctty vnode pointer set in vnode layer. */
1226 if (!SESS_LEADER(p) ||
1227 ((p->p_session->s_ttyvp || tp->t_session) &&
94a6eea8 1228 (tp->t_session != p->p_session))) {
616516c8 1229 lwkt_reltoken(&p->p_token);
22ff886e
AH
1230 lwkt_reltoken(&proc_token);
1231 lwkt_reltoken(&tty_token);
984263bc 1232 return (EPERM);
94a6eea8
MD
1233 }
1234 ttyhold(tp);
984263bc 1235 tp->t_session = p->p_session;
58c2553a
MD
1236 opgrp = tp->t_pgrp;
1237 pgref(p->p_pgrp);
984263bc 1238 tp->t_pgrp = p->p_pgrp;
94a6eea8 1239 otp = p->p_session->s_ttyp;
984263bc 1240 p->p_session->s_ttyp = tp;
4643740a 1241 p->p_flags |= P_CONTROLT;
94a6eea8
MD
1242 if (otp)
1243 ttyunhold(otp);
58c2553a
MD
1244 if (opgrp) {
1245 pgrel(opgrp);
1246 opgrp = NULL;
1247 }
984263bc
MD
1248 break;
1249 case TIOCSPGRP: { /* set pgrp of tty */
3e28fb5c 1250 pid_t pgid = *(int *)data;
984263bc 1251
22ff886e 1252 if (!isctty(p, tp)) {
616516c8 1253 lwkt_reltoken(&p->p_token);
22ff886e
AH
1254 lwkt_reltoken(&proc_token);
1255 lwkt_reltoken(&tty_token);
984263bc 1256 return (ENOTTY);
22ff886e
AH
1257 }
1258 else if (pgid < 1 || pgid > PID_MAX) {
616516c8 1259 lwkt_reltoken(&p->p_token);
22ff886e
AH
1260 lwkt_reltoken(&proc_token);
1261 lwkt_reltoken(&tty_token);
3e28fb5c 1262 return (EINVAL);
22ff886e 1263 } else {
3e28fb5c 1264 struct pgrp *pgrp = pgfind(pgid);
22ff886e 1265 if (pgrp == NULL || pgrp->pg_session != p->p_session) {
58c2553a
MD
1266 if (pgrp)
1267 pgrel(pgrp);
616516c8 1268 lwkt_reltoken(&p->p_token);
22ff886e
AH
1269 lwkt_reltoken(&proc_token);
1270 lwkt_reltoken(&tty_token);
3e28fb5c 1271 return (EPERM);
22ff886e 1272 }
58c2553a 1273 opgrp = tp->t_pgrp;
3e28fb5c 1274 tp->t_pgrp = pgrp;
58c2553a
MD
1275 if (opgrp) {
1276 pgrel(opgrp);
1277 opgrp = NULL;
1278 }
3e28fb5c 1279 }
984263bc
MD
1280 break;
1281 }
1282 case TIOCSTAT: /* simulate control-T */
e43a034f 1283 crit_enter();
984263bc 1284 ttyinfo(tp);
e43a034f 1285 crit_exit();
984263bc
MD
1286 break;
1287 case TIOCSWINSZ: /* set window size */
1288 if (bcmp((caddr_t)&tp->t_winsize, data,
1289 sizeof (struct winsize))) {
1290 tp->t_winsize = *(struct winsize *)data;
1291 pgsignal(tp->t_pgrp, SIGWINCH, 1);
1292 }
1293 break;
1294 case TIOCSDRAINWAIT:
895c1f85 1295 error = priv_check(td, PRIV_ROOT);
22ff886e 1296 if (error) {
616516c8 1297 lwkt_reltoken(&p->p_token);
22ff886e
AH
1298 lwkt_reltoken(&proc_token);
1299 lwkt_reltoken(&tty_token);
984263bc 1300 return (error);
22ff886e 1301 }
984263bc
MD
1302 tp->t_timeout = *(int *)data * hz;
1303 wakeup(TSA_OCOMPLETE(tp));
1304 wakeup(TSA_OLOWAT(tp));
1305 break;
1306 case TIOCGDRAINWAIT:
1307 *(int *)data = tp->t_timeout / hz;
1308 break;
1309 default:
1310#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
616516c8 1311 lwkt_reltoken(&p->p_token);
22ff886e
AH
1312 lwkt_reltoken(&proc_token);
1313 lwkt_reltoken(&tty_token);
984263bc
MD
1314 return (ttcompat(tp, cmd, data, flag));
1315#else
616516c8 1316 lwkt_reltoken(&p->p_token);
22ff886e
AH
1317 lwkt_reltoken(&proc_token);
1318 lwkt_reltoken(&tty_token);
984263bc
MD
1319 return (ENOIOCTL);
1320#endif
1321 }
616516c8 1322 lwkt_reltoken(&p->p_token);
22ff886e
AH
1323 lwkt_reltoken(&proc_token);
1324 lwkt_reltoken(&tty_token);
984263bc
MD
1325 return (0);
1326}
1327
984263bc 1328static struct filterops ttyread_filtops =
a081e067 1329 { FILTEROP_ISFD|FILTEROP_MPSAFE, NULL, filt_ttyrdetach, filt_ttyread };
984263bc 1330static struct filterops ttywrite_filtops =
a081e067 1331 { FILTEROP_ISFD|FILTEROP_MPSAFE, NULL, filt_ttywdetach, filt_ttywrite };
984263bc
MD
1332
1333int
fef8985e 1334ttykqfilter(struct dev_kqfilter_args *ap)
984263bc 1335{
b13267a5 1336 cdev_t dev = ap->a_head.a_dev;
fef8985e 1337 struct knote *kn = ap->a_kn;
984263bc
MD
1338 struct tty *tp = dev->si_tty;
1339 struct klist *klist;
984263bc 1340
fef8985e 1341 ap->a_result = 0;
22ff886e
AH
1342
1343 lwkt_gettoken(&tty_token);
984263bc
MD
1344 switch (kn->kn_filter) {
1345 case EVFILT_READ:
5b22f1a7 1346 klist = &tp->t_rkq.ki_note;
984263bc
MD
1347 kn->kn_fop = &ttyread_filtops;
1348 break;
1349 case EVFILT_WRITE:
5b22f1a7 1350 klist = &tp->t_wkq.ki_note;
984263bc
MD
1351 kn->kn_fop = &ttywrite_filtops;
1352 break;
1353 default:
b287d649 1354 ap->a_result = EOPNOTSUPP;
22ff886e 1355 lwkt_reltoken(&tty_token);
fef8985e 1356 return (0);
984263bc 1357 }
22ff886e 1358 lwkt_reltoken(&tty_token);
984263bc 1359 kn->kn_hook = (caddr_t)dev;
5b22f1a7 1360 knote_insert(klist, kn);
984263bc
MD
1361
1362 return (0);
1363}
1364
1365static void
1366filt_ttyrdetach(struct knote *kn)
1367{
b13267a5 1368 struct tty *tp = ((cdev_t)kn->kn_hook)->si_tty;
984263bc 1369
22ff886e 1370 lwkt_gettoken(&tty_token);
5b22f1a7 1371 knote_remove(&tp->t_rkq.ki_note, kn);
22ff886e 1372 lwkt_reltoken(&tty_token);
984263bc
MD
1373}
1374
1375static int
1376filt_ttyread(struct knote *kn, long hint)
1377{
b13267a5 1378 struct tty *tp = ((cdev_t)kn->kn_hook)->si_tty;
984263bc 1379
22ff886e 1380 lwkt_gettoken(&tty_token);
984263bc
MD
1381 kn->kn_data = ttnread(tp);
1382 if (ISSET(tp->t_state, TS_ZOMBIE)) {
3bcb6e5e 1383 kn->kn_flags |= (EV_EOF | EV_NODATA);
22ff886e 1384 lwkt_reltoken(&tty_token);
984263bc
MD
1385 return (1);
1386 }
22ff886e 1387 lwkt_reltoken(&tty_token);
984263bc
MD
1388 return (kn->kn_data > 0);
1389}
1390
1391static void
1392filt_ttywdetach(struct knote *kn)
1393{
b13267a5 1394 struct tty *tp = ((cdev_t)kn->kn_hook)->si_tty;
984263bc 1395
22ff886e 1396 lwkt_gettoken(&tty_token);
5b22f1a7 1397 knote_remove(&tp->t_wkq.ki_note, kn);
22ff886e 1398 lwkt_reltoken(&tty_token);
984263bc
MD
1399}
1400
1401static int
c972a82f 1402filt_ttywrite(struct knote *kn, long hint)
984263bc 1403{
b13267a5 1404 struct tty *tp = ((cdev_t)kn->kn_hook)->si_tty;
22ff886e 1405 int ret;
984263bc 1406
22ff886e 1407 lwkt_gettoken(&tty_token);
984263bc 1408 kn->kn_data = tp->t_outq.c_cc;
22ff886e
AH
1409 if (ISSET(tp->t_state, TS_ZOMBIE)) {
1410 lwkt_reltoken(&tty_token);
984263bc 1411 return (1);
22ff886e
AH
1412 }
1413 ret = (kn->kn_data <= tp->t_olowat &&
984263bc 1414 ISSET(tp->t_state, TS_CONNECTED));
22ff886e
AH
1415 lwkt_reltoken(&tty_token);
1416 return ret;
984263bc
MD
1417}
1418
1419/*
e43a034f 1420 * Must be called while in a critical section.
22ff886e 1421 * NOTE: tty_token must be held.
984263bc
MD
1422 */
1423static int
c972a82f 1424ttnread(struct tty *tp)
984263bc
MD
1425{
1426 int nread;
1427
22ff886e 1428 ASSERT_LWKT_TOKEN_HELD(&tty_token);
984263bc
MD
1429 if (ISSET(tp->t_lflag, PENDIN))
1430 ttypend(tp);
1431 nread = tp->t_canq.c_cc;
1432 if (!ISSET(tp->t_lflag, ICANON)) {
1433 nread += tp->t_rawq.c_cc;
1434 if (nread < tp->t_cc[VMIN] && tp->t_cc[VTIME] == 0)
1435 nread = 0;
1436 }
1437 return (nread);
1438}
1439
1440/*
1441 * Wait for output to drain.
1442 */
1443int
c972a82f 1444ttywait(struct tty *tp)
984263bc 1445{
e43a034f 1446 int error;
984263bc
MD
1447
1448 error = 0;
e43a034f 1449 crit_enter();
22ff886e 1450 lwkt_gettoken(&tty_token);
984263bc
MD
1451 while ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) &&
1452 ISSET(tp->t_state, TS_CONNECTED) && tp->t_oproc) {
1453 (*tp->t_oproc)(tp);
1454 if ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) &&
1455 ISSET(tp->t_state, TS_CONNECTED)) {
1456 SET(tp->t_state, TS_SO_OCOMPLETE);
1457 error = ttysleep(tp, TSA_OCOMPLETE(tp),
377d4740 1458 PCATCH, "ttywai",
984263bc
MD
1459 tp->t_timeout);
1460 if (error) {
1461 if (error == EWOULDBLOCK)
1462 error = EIO;
1463 break;
1464 }
1465 } else
1466 break;
1467 }
1468 if (!error && (tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)))
1469 error = EIO;
22ff886e 1470 lwkt_reltoken(&tty_token);
e43a034f 1471 crit_exit();
984263bc
MD
1472 return (error);
1473}
1474
1475/*
1476 * Flush if successfully wait.
1477 */
1478static int
c972a82f 1479ttywflush(struct tty *tp)
984263bc
MD
1480{
1481 int error;
1482
1483 if ((error = ttywait(tp)) == 0)
1484 ttyflush(tp, FREAD);
1485 return (error);
1486}
1487
1488/*
1489 * Flush tty read and/or write queues, notifying anyone waiting.
1490 */
1491void
c972a82f 1492ttyflush(struct tty *tp, int rw)
984263bc 1493{
e43a034f 1494 crit_enter();
22ff886e 1495 lwkt_gettoken(&tty_token);
984263bc
MD
1496#if 0
1497again:
1498#endif
1499 if (rw & FWRITE) {
1500 FLUSHQ(&tp->t_outq);
1501 CLR(tp->t_state, TS_TTSTOP);
1502 }
1503 (*tp->t_stop)(tp, rw);
1504 if (rw & FREAD) {
1505 FLUSHQ(&tp->t_canq);
1506 FLUSHQ(&tp->t_rawq);
1507 CLR(tp->t_lflag, PENDIN);
1508 tp->t_rocount = 0;
1509 tp->t_rocol = 0;
1510 CLR(tp->t_state, TS_LOCAL);
1511 ttwakeup(tp);
1512 if (ISSET(tp->t_state, TS_TBLOCK)) {
1513 if (rw & FWRITE)
1514 FLUSHQ(&tp->t_outq);
1515 ttyunblock(tp);
1516
1517 /*
1518 * Don't let leave any state that might clobber the
1519 * next line discipline (although we should do more
1520 * to send the START char). Not clearing the state
1521 * may have caused the "putc to a clist with no
6ea70f76 1522 * reserved cblocks" panic/kprintf.
984263bc
MD
1523 */
1524 CLR(tp->t_state, TS_TBLOCK);
1525
1526#if 0 /* forget it, sleeping isn't always safe and we don't know when it is */
1527 if (ISSET(tp->t_iflag, IXOFF)) {
1528 /*
1529 * XXX wait a bit in the hope that the stop
1530 * character (if any) will go out. Waiting
1531 * isn't good since it allows races. This
1532 * will be fixed when the stop character is
1533 * put in a special queue. Don't bother with
1534 * the checks in ttywait() since the timeout
1535 * will save us.
1536 */
1537 SET(tp->t_state, TS_SO_OCOMPLETE);
377d4740 1538 ttysleep(tp, TSA_OCOMPLETE(tp), 0,
984263bc
MD
1539 "ttyfls", hz / 10);
1540 /*
1541 * Don't try sending the stop character again.
1542 */
1543 CLR(tp->t_state, TS_TBLOCK);
1544 goto again;
1545 }
1546#endif
1547 }
1548 }
1549 if (rw & FWRITE) {
1550 FLUSHQ(&tp->t_outq);
1551 ttwwakeup(tp);
1552 }
22ff886e 1553 lwkt_reltoken(&tty_token);
e43a034f 1554 crit_exit();
984263bc
MD
1555}
1556
1557/*
1558 * Copy in the default termios characters.
1559 */
1560void
c972a82f 1561termioschars(struct termios *t)
984263bc 1562{
22ff886e 1563 lwkt_gettoken(&tty_token);
984263bc 1564 bcopy(ttydefchars, t->c_cc, sizeof t->c_cc);
22ff886e 1565 lwkt_reltoken(&tty_token);
984263bc
MD
1566}
1567
1568/*
1569 * Old interface.
1570 */
1571void
c972a82f 1572ttychars(struct tty *tp)
984263bc 1573{
22ff886e 1574 lwkt_gettoken(&tty_token);
984263bc 1575 termioschars(&tp->t_termios);
22ff886e 1576 lwkt_reltoken(&tty_token);
984263bc
MD
1577}
1578
1579/*
1580 * Handle input high water. Send stop character for the IXOFF case. Turn
1581 * on our input flow control bit and propagate the changes to the driver.
1582 * XXX the stop character should be put in a special high priority queue.
1583 */
1584void
c972a82f 1585ttyblock(struct tty *tp)
984263bc 1586{
22ff886e 1587 lwkt_gettoken(&tty_token);
984263bc
MD
1588 SET(tp->t_state, TS_TBLOCK);
1589 if (ISSET(tp->t_iflag, IXOFF) && tp->t_cc[VSTOP] != _POSIX_VDISABLE &&
0ced1954 1590 clist_putc(tp->t_cc[VSTOP], &tp->t_outq) != 0)
984263bc
MD
1591 CLR(tp->t_state, TS_TBLOCK); /* try again later */
1592 ttstart(tp);
22ff886e 1593 lwkt_reltoken(&tty_token);
984263bc
MD
1594}
1595
1596/*
1597 * Handle input low water. Send start character for the IXOFF case. Turn
1598 * off our input flow control bit and propagate the changes to the driver.
1599 * XXX the start character should be put in a special high priority queue.
1600 */
1601static void
c972a82f 1602ttyunblock(struct tty *tp)
984263bc 1603{
22ff886e 1604 lwkt_gettoken(&tty_token);
984263bc
MD
1605 CLR(tp->t_state, TS_TBLOCK);
1606 if (ISSET(tp->t_iflag, IXOFF) && tp->t_cc[VSTART] != _POSIX_VDISABLE &&
0ced1954 1607 clist_putc(tp->t_cc[VSTART], &tp->t_outq) != 0)
984263bc
MD
1608 SET(tp->t_state, TS_TBLOCK); /* try again later */
1609 ttstart(tp);
22ff886e 1610 lwkt_reltoken(&tty_token);
984263bc
MD
1611}
1612
1613#ifdef notyet
1614/* Not used by any current (i386) drivers. */
1615/*
1616 * Restart after an inter-char delay.
1617 */
1618void
c972a82f 1619ttrstrt(void *tp_arg)
984263bc
MD
1620{
1621 struct tty *tp;
984263bc
MD
1622
1623 KASSERT(tp_arg != NULL, ("ttrstrt"));
1624
1625 tp = tp_arg;
e43a034f 1626 crit_enter();
22ff886e 1627 lwkt_gettoken(&tty_token);
984263bc
MD
1628 CLR(tp->t_state, TS_TIMEOUT);
1629 ttstart(tp);
22ff886e 1630 lwkt_reltoken(&tty_token);
e43a034f 1631 crit_exit();
984263bc
MD
1632}
1633#endif
1634
1635int
c972a82f 1636ttstart(struct tty *tp)
984263bc 1637{
22ff886e 1638 lwkt_gettoken(&tty_token);
984263bc
MD
1639 if (tp->t_oproc != NULL) /* XXX: Kludge for pty. */
1640 (*tp->t_oproc)(tp);
22ff886e 1641 lwkt_reltoken(&tty_token);
984263bc
MD
1642 return (0);
1643}
1644
1645/*
1646 * "close" a line discipline
1647 */
1648int
c972a82f 1649ttylclose(struct tty *tp, int flag)
984263bc 1650{
22ff886e 1651 lwkt_gettoken(&tty_token);
984263bc
MD
1652 if (flag & FNONBLOCK || ttywflush(tp))
1653 ttyflush(tp, FREAD | FWRITE);
22ff886e 1654 lwkt_reltoken(&tty_token);
984263bc
MD
1655 return (0);
1656}
1657
94a6eea8
MD
1658void
1659ttyhold(struct tty *tp)
1660{
1661 ++tp->t_refs;
1662}
1663
1664void
1665ttyunhold(struct tty *tp)
1666{
f5f1bbd4
MD
1667 if (tp->t_unhold)
1668 tp->t_unhold(tp);
1669 else
1670 --tp->t_refs;
94a6eea8
MD
1671}
1672
984263bc
MD
1673/*
1674 * Handle modem control transition on a tty.
1675 * Flag indicates new state of carrier.
1676 * Returns 0 if the line should be turned off, otherwise 1.
1677 */
1678int
c972a82f 1679ttymodem(struct tty *tp, int flag)
984263bc 1680{
22ff886e 1681 lwkt_gettoken(&tty_token);
984263bc
MD
1682 if (ISSET(tp->t_state, TS_CARR_ON) && ISSET(tp->t_cflag, MDMBUF)) {
1683 /*
1684 * MDMBUF: do flow control according to carrier flag
1685 * XXX TS_CAR_OFLOW doesn't do anything yet. TS_TTSTOP
1686 * works if IXON and IXANY are clear.
1687 */
1688 if (flag) {
1689 CLR(tp->t_state, TS_CAR_OFLOW);
1690 CLR(tp->t_state, TS_TTSTOP);
1691 ttstart(tp);
1692 } else if (!ISSET(tp->t_state, TS_CAR_OFLOW)) {
1693 SET(tp->t_state, TS_CAR_OFLOW);
1694 SET(tp->t_state, TS_TTSTOP);
1695 (*tp->t_stop)(tp, 0);
1696 }
1697 } else if (flag == 0) {
1698 /*
1699 * Lost carrier.
1700 */
1701 CLR(tp->t_state, TS_CARR_ON);
1702 if (ISSET(tp->t_state, TS_ISOPEN) &&
1703 !ISSET(tp->t_cflag, CLOCAL)) {
1704 SET(tp->t_state, TS_ZOMBIE);
1705 CLR(tp->t_state, TS_CONNECTED);
1706 if (tp->t_session && tp->t_session->s_leader)
84204577 1707 ksignal(tp->t_session->s_leader, SIGHUP);
984263bc 1708 ttyflush(tp, FREAD | FWRITE);
22ff886e 1709 lwkt_reltoken(&tty_token);
984263bc
MD
1710 return (0);
1711 }
1712 } else {
1713 /*
1714 * Carrier now on.
1715 */
1716 SET(tp->t_state, TS_CARR_ON);
1717 if (!ISSET(tp->t_state, TS_ZOMBIE))
1718 SET(tp->t_state, TS_CONNECTED);
1719 wakeup(TSA_CARR_ON(tp));
1720 ttwakeup(tp);
1721 ttwwakeup(tp);
1722 }
22ff886e 1723 lwkt_reltoken(&tty_token);
984263bc
MD
1724 return (1);
1725}
1726
1727/*
1728 * Reinput pending characters after state switch
e43a034f 1729 * call from a critical section.
984263bc
MD
1730 */
1731static void
c972a82f 1732ttypend(struct tty *tp)
984263bc
MD
1733{
1734 struct clist tq;
1fd87d54 1735 int c;
984263bc 1736
22ff886e 1737 lwkt_gettoken(&tty_token);
984263bc
MD
1738 CLR(tp->t_lflag, PENDIN);
1739 SET(tp->t_state, TS_TYPEN);
1740 /*
1741 * XXX this assumes too much about clist internals. It may even
1742 * fail if the cblock slush pool is empty. We can't allocate more
1743 * cblocks here because we are called from an interrupt handler
1744 * and clist_alloc_cblocks() can wait.
1745 */
1746 tq = tp->t_rawq;
1747 bzero(&tp->t_rawq, sizeof tp->t_rawq);
1748 tp->t_rawq.c_cbmax = tq.c_cbmax;
1749 tp->t_rawq.c_cbreserved = tq.c_cbreserved;
0ced1954 1750 while ((c = clist_getc(&tq)) >= 0)
984263bc
MD
1751 ttyinput(c, tp);
1752 CLR(tp->t_state, TS_TYPEN);
22ff886e 1753 lwkt_reltoken(&tty_token);
984263bc
MD
1754}
1755
1756/*
1757 * Process a read call on a tty device.
1758 */
1759int
c972a82f 1760ttread(struct tty *tp, struct uio *uio, int flag)
984263bc 1761{
1fd87d54
RG
1762 struct clist *qp;
1763 int c;
1764 tcflag_t lflag;
1765 cc_t *cc = tp->t_cc;
142dd704 1766 struct proc *pp;
08f2f1bb 1767 struct lwp *lp;
e43a034f 1768 int first, error = 0;
984263bc
MD
1769 int has_stime = 0, last_cc = 0;
1770 long slp = 0; /* XXX this should be renamed `timo'. */
1771 struct timeval stime;
1772
08f2f1bb 1773 lp = curthread->td_lwp;
d557216f
MD
1774 stime.tv_sec = 0; /* fix compiler warnings */
1775 stime.tv_usec = 0;
08f2f1bb 1776
22ff886e 1777 lwkt_gettoken(&tty_token);
984263bc 1778loop:
e43a034f 1779 crit_enter();
984263bc
MD
1780 lflag = tp->t_lflag;
1781 /*
1782 * take pending input first
1783 */
1784 if (ISSET(lflag, PENDIN)) {
1785 ttypend(tp);
e43a034f 1786 splz(); /* reduce latency */
984263bc
MD
1787 lflag = tp->t_lflag; /* XXX ttypend() clobbers it */
1788 }
1789
1790 /*
1791 * Hang process if it's in the background.
1792 */
22ff886e 1793 lwkt_gettoken(&proc_token);
142dd704 1794 if ((pp = curproc) && isbackground(pp, tp)) {
e43a034f 1795 crit_exit();
142dd704 1796 if (SIGISMEMBER(pp->p_sigignore, SIGTTIN) ||
08f2f1bb 1797 SIGISMEMBER(lp->lwp_sigmask, SIGTTIN) ||
4643740a 1798 (pp->p_flags & P_PPWAIT) || pp->p_pgrp->pg_jobc == 0) {
22ff886e
AH
1799 lwkt_reltoken(&proc_token);
1800 lwkt_reltoken(&tty_token);
984263bc 1801 return (EIO);
22ff886e 1802 }
142dd704 1803 pgsignal(pp->p_pgrp, SIGTTIN, 1);
377d4740 1804 error = ttysleep(tp, &lbolt, PCATCH, "ttybg2", 0);
22ff886e
AH
1805 if (error) {
1806 lwkt_reltoken(&proc_token);
1807 lwkt_reltoken(&tty_token);
984263bc 1808 return (error);
22ff886e
AH
1809 }
1810 lwkt_reltoken(&proc_token);
984263bc
MD
1811 goto loop;
1812 }
22ff886e 1813 lwkt_reltoken(&proc_token);
984263bc
MD
1814
1815 if (ISSET(tp->t_state, TS_ZOMBIE)) {
e43a034f 1816 crit_exit();
22ff886e 1817 lwkt_reltoken(&tty_token);
984263bc
MD
1818 return (0); /* EOF */
1819 }
1820
1821 /*
1822 * If canonical, use the canonical queue,
1823 * else use the raw queue.
1824 *
1825 * (should get rid of clists...)
1826 */
1827 qp = ISSET(lflag, ICANON) ? &tp->t_canq : &tp->t_rawq;
1828
1829 if (flag & IO_NDELAY) {
1830 if (qp->c_cc > 0)
1831 goto read;
1832 if (!ISSET(lflag, ICANON) && cc[VMIN] == 0) {
e43a034f 1833 crit_exit();
22ff886e 1834 lwkt_reltoken(&tty_token);
984263bc
MD
1835 return (0);
1836 }
e43a034f 1837 crit_exit();
22ff886e 1838 lwkt_reltoken(&tty_token);
984263bc
MD
1839 return (EWOULDBLOCK);
1840 }
1841 if (!ISSET(lflag, ICANON)) {
1842 int m = cc[VMIN];
1843 long t = cc[VTIME];
1844 struct timeval timecopy;
1845
1846 /*
1847 * Check each of the four combinations.
1848 * (m > 0 && t == 0) is the normal read case.
1849 * It should be fairly efficient, so we check that and its
1850 * companion case (m == 0 && t == 0) first.
1851 * For the other two cases, we compute the target sleep time
1852 * into slp.
1853 */
1854 if (t == 0) {
1855 if (qp->c_cc < m)
1856 goto sleep;
1857 if (qp->c_cc > 0)
1858 goto read;
1859
1860 /* m, t and qp->c_cc are all 0. 0 is enough input. */
e43a034f 1861 crit_exit();
22ff886e 1862 lwkt_reltoken(&tty_token);
984263bc
MD
1863 return (0);
1864 }
1865 t *= 100000; /* time in us */
1866#define diff(t1, t2) (((t1).tv_sec - (t2).tv_sec) * 1000000 + \
1867 ((t1).tv_usec - (t2).tv_usec))
1868 if (m > 0) {
1869 if (qp->c_cc <= 0)
1870 goto sleep;
1871 if (qp->c_cc >= m)
1872 goto read;
1873 getmicrotime(&timecopy);
d557216f 1874 if (has_stime == 0) {
984263bc
MD
1875 /* first character, start timer */
1876 has_stime = 1;
1877 stime = timecopy;
1878 slp = t;
1879 } else if (qp->c_cc > last_cc) {
1880 /* got a character, restart timer */
1881 stime = timecopy;
1882 slp = t;
1883 } else {
1884 /* nothing, check expiration */
1885 slp = t - diff(timecopy, stime);
1886 if (slp <= 0)
1887 goto read;
1888 }
1889 last_cc = qp->c_cc;
1890 } else { /* m == 0 */
1891 if (qp->c_cc > 0)
1892 goto read;
1893 getmicrotime(&timecopy);
d557216f 1894 if (has_stime == 0) {
984263bc
MD
1895 has_stime = 1;
1896 stime = timecopy;
1897 slp = t;
1898 } else {
1899 slp = t - diff(timecopy, stime);
1900 if (slp <= 0) {
1901 /* Timed out, but 0 is enough input. */
e43a034f 1902 crit_exit();
22ff886e 1903 lwkt_reltoken(&tty_token);
984263bc
MD
1904 return (0);
1905 }
1906 }
1907 }
1908#undef diff
1909 /*
1910 * Rounding down may make us wake up just short
1911 * of the target, so we round up.
1912 * The formula is ceiling(slp * hz/1000000).
1913 * 32-bit arithmetic is enough for hz < 169.
1914 * XXX see tvtohz() for how to avoid overflow if hz
1915 * is large (divide by `tick' and/or arrange to
1916 * use tvtohz() if hz is large).
1917 */
1918 slp = (long) (((u_long)slp * hz) + 999999) / 1000000;
1919 goto sleep;
1920 }
1921 if (qp->c_cc <= 0) {
1922sleep:
1923 /*
1924 * There is no input, or not enough input and we can block.
1925 */
377d4740 1926 error = ttysleep(tp, TSA_HUP_OR_INPUT(tp), PCATCH,
984263bc
MD
1927 ISSET(tp->t_state, TS_CONNECTED) ?
1928 "ttyin" : "ttyhup", (int)slp);
e43a034f 1929 crit_exit();
984263bc
MD
1930 if (error == EWOULDBLOCK)
1931 error = 0;
22ff886e
AH
1932 else if (error) {
1933 lwkt_reltoken(&tty_token);
984263bc 1934 return (error);
22ff886e 1935 }
984263bc
MD
1936 /*
1937 * XXX what happens if another process eats some input
1938 * while we are asleep (not just here)? It would be
1939 * safest to detect changes and reset our state variables
1940 * (has_stime and last_cc).
1941 */
1942 slp = 0;
1943 goto loop;
1944 }
1945read:
e43a034f 1946 crit_exit();
984263bc
MD
1947 /*
1948 * Input present, check for input mapping and processing.
1949 */
1950 first = 1;
1951 if (ISSET(lflag, ICANON | ISIG))
1952 goto slowcase;
1953 for (;;) {
1954 char ibuf[IBUFSIZ];
1955 int icc;
1956
e54488bb 1957 icc = (int)szmin(uio->uio_resid, IBUFSIZ);
984263bc
MD
1958 icc = q_to_b(qp, ibuf, icc);
1959 if (icc <= 0) {
1960 if (first)
1961 goto loop;
1962 break;
1963 }
e54488bb 1964 error = uiomove(ibuf, (size_t)icc, uio);
984263bc
MD
1965 /*
1966 * XXX if there was an error then we should ungetc() the
1967 * unmoved chars and reduce icc here.
1968 */
1969 if (error)
1970 break;
1971 if (uio->uio_resid == 0)
1972 break;
1973 first = 0;
1974 }
1975 goto out;
1976slowcase:
1977 for (;;) {
0ced1954 1978 c = clist_getc(qp);
984263bc
MD
1979 if (c < 0) {
1980 if (first)
1981 goto loop;
1982 break;
1983 }
1984 /*
1985 * delayed suspend (^Y)
1986 */
1987 if (CCEQ(cc[VDSUSP], c) &&
1988 ISSET(lflag, IEXTEN | ISIG) == (IEXTEN | ISIG)) {
1989 pgsignal(tp->t_pgrp, SIGTSTP, 1);
1990 if (first) {
377d4740 1991 error = ttysleep(tp, &lbolt, PCATCH,
984263bc
MD
1992 "ttybg3", 0);
1993 if (error)
1994 break;
1995 goto loop;
1996 }
1997 break;
1998 }
1999 /*
2000 * Interpret EOF only in canonical mode.
2001 */
2002 if (CCEQ(cc[VEOF], c) && ISSET(lflag, ICANON))
2003 break;
2004 /*
2005 * Give user character.
2006 */
2007 error = ureadc(c, uio);
2008 if (error)
2009 /* XXX should ungetc(c, qp). */
2010 break;
2011 if (uio->uio_resid == 0)
2012 break;
2013 /*
2014 * In canonical mode check for a "break character"
2015 * marking the end of a "line of input".
2016 */
2017 if (ISSET(lflag, ICANON) && TTBREAKC(c, lflag))
2018 break;
2019 first = 0;
2020 }
2021
2022out:
2023 /*
2024 * Look to unblock input now that (presumably)
2025 * the input queue has gone down.
2026 */
e43a034f 2027 crit_enter();
984263bc
MD
2028 if (ISSET(tp->t_state, TS_TBLOCK) &&
2029 tp->t_rawq.c_cc + tp->t_canq.c_cc <= tp->t_ilowat)
2030 ttyunblock(tp);
e43a034f 2031 crit_exit();
984263bc 2032
22ff886e 2033 lwkt_reltoken(&tty_token);
984263bc
MD
2034 return (error);
2035}
2036
2037/*
2038 * Check the output queue on tp for space for a kernel message (from uprintf
2039 * or tprintf). Allow some space over the normal hiwater mark so we don't
2040 * lose messages due to normal flow control, but don't let the tty run amok.
2041 * Sleeps here are not interruptible, but we return prematurely if new signals
2042 * arrive.
2043 */
2044int
c972a82f 2045ttycheckoutq(struct tty *tp, int wait)
984263bc 2046{
aa6c3de6 2047 struct lwp *lp = curthread->td_lwp;
e43a034f 2048 int hiwat;
aa6c3de6 2049 sigset_t oldset, newset;
984263bc 2050
22ff886e 2051 lwkt_gettoken(&tty_token);
984263bc 2052 hiwat = tp->t_ohiwat;
aa6c3de6
SS
2053 SIGEMPTYSET(oldset);
2054 SIGEMPTYSET(newset);
e43a034f 2055 crit_enter();
984263bc 2056 if (wait)
aa6c3de6 2057 oldset = lwp_sigpend(lp);
e43a034f 2058 if (tp->t_outq.c_cc > hiwat + OBUFSIZ + 100) {
984263bc
MD
2059 while (tp->t_outq.c_cc > hiwat) {
2060 ttstart(tp);
2061 if (tp->t_outq.c_cc <= hiwat)
2062 break;
aa6c3de6
SS
2063 if (wait)
2064 newset = lwp_sigpend(lp);
2065 if (!wait || SIGSETNEQ(oldset, newset)) {
e43a034f 2066 crit_exit();
22ff886e 2067 lwkt_reltoken(&tty_token);
984263bc
MD
2068 return (0);
2069 }
2070 SET(tp->t_state, TS_SO_OLOWAT);
377d4740 2071 tsleep(TSA_OLOWAT(tp), 0, "ttoutq", hz);
984263bc 2072 }
e43a034f
MD
2073 }
2074 crit_exit();
22ff886e 2075 lwkt_reltoken(&tty_token);
984263bc
MD
2076 return (1);
2077}
2078
2079/*
2080 * Process a write call on a tty device.
2081 */
2082int
c972a82f 2083ttwrite(struct tty *tp, struct uio *uio, int flag)
984263bc 2084{
1fd87d54
RG
2085 char *cp = NULL;
2086 int cc, ce;
142dd704 2087 struct proc *pp;
08f2f1bb 2088 struct lwp *lp;
e54488bb
MD
2089 int i, hiwat, error;
2090 size_t cnt;
2091
984263bc
MD
2092 char obuf[OBUFSIZ];
2093
22ff886e 2094 lwkt_gettoken(&tty_token);
08f2f1bb 2095 lp = curthread->td_lwp;
984263bc
MD
2096 hiwat = tp->t_ohiwat;
2097 cnt = uio->uio_resid;
2098 error = 0;
2099 cc = 0;
2100loop:
e43a034f 2101 crit_enter();
984263bc 2102 if (ISSET(tp->t_state, TS_ZOMBIE)) {
e43a034f 2103 crit_exit();
984263bc
MD
2104 if (uio->uio_resid == cnt)
2105 error = EIO;
2106 goto out;
2107 }
2108 if (!ISSET(tp->t_state, TS_CONNECTED)) {
2109 if (flag & IO_NDELAY) {
e43a034f 2110 crit_exit();
984263bc
MD
2111 error = EWOULDBLOCK;
2112 goto out;
2113 }
377d4740 2114 error = ttysleep(tp, TSA_CARR_ON(tp), PCATCH, "ttydcd", 0);
e43a034f 2115 crit_exit();
984263bc
MD
2116 if (error)
2117 goto out;
2118 goto loop;
2119 }
e43a034f 2120 crit_exit();
142dd704 2121
984263bc
MD
2122 /*
2123 * Hang the process if it's in the background.
2124 */
22ff886e 2125 lwkt_gettoken(&proc_token);
142dd704 2126 if ((pp = curproc) && isbackground(pp, tp) &&
4643740a 2127 ISSET(tp->t_lflag, TOSTOP) && !(pp->p_flags & P_PPWAIT) &&
142dd704 2128 !SIGISMEMBER(pp->p_sigignore, SIGTTOU) &&
08f2f1bb 2129 !SIGISMEMBER(lp->lwp_sigmask, SIGTTOU)) {
142dd704 2130 if (pp->p_pgrp->pg_jobc == 0) {
984263bc 2131 error = EIO;
22ff886e 2132 lwkt_reltoken(&proc_token);
984263bc
MD
2133 goto out;
2134 }
142dd704 2135 pgsignal(pp->p_pgrp, SIGTTOU, 1);
22ff886e 2136 lwkt_reltoken(&proc_token);
377d4740 2137 error = ttysleep(tp, &lbolt, PCATCH, "ttybg4", 0);
984263bc
MD
2138 if (error)
2139 goto out;
2140 goto loop;
2141 }
22ff886e 2142 lwkt_reltoken(&proc_token);
984263bc
MD
2143 /*
2144 * Process the user's data in at most OBUFSIZ chunks. Perform any
2145 * output translation. Keep track of high water mark, sleep on
2146 * overflow awaiting device aid in acquiring new space.
2147 */
2148 while (uio->uio_resid > 0 || cc > 0) {
2149 if (ISSET(tp->t_lflag, FLUSHO)) {
2150 uio->uio_resid = 0;
22ff886e 2151 lwkt_reltoken(&tty_token);
984263bc
MD
2152 return (0);
2153 }
2154 if (tp->t_outq.c_cc > hiwat)
2155 goto ovhiwat;
2156 /*
2157 * Grab a hunk of data from the user, unless we have some
2158 * leftover from last time.
2159 */
2160 if (cc == 0) {
e54488bb 2161 cc = szmin(uio->uio_resid, OBUFSIZ);
984263bc 2162 cp = obuf;
e54488bb 2163 error = uiomove(cp, (size_t)cc, uio);
984263bc
MD
2164 if (error) {
2165 cc = 0;
2166 break;
2167 }
2168 }
2169 /*
2170 * If nothing fancy need be done, grab those characters we
2171 * can handle without any of ttyoutput's processing and
2172 * just transfer them to the output q. For those chars
2173 * which require special processing (as indicated by the
2174 * bits in char_type), call ttyoutput. After processing
2175 * a hunk of data, look for FLUSHO so ^O's will take effect
2176 * immediately.
2177 */
2178 while (cc > 0) {
2179 if (!ISSET(tp->t_oflag, OPOST))
2180 ce = cc;
2181 else {
2182 ce = cc - scanc((u_int)cc, (u_char *)cp,
2183 char_type, CCLASSMASK);
2184 /*
2185 * If ce is zero, then we're processing
2186 * a special character through ttyoutput.
2187 */
2188 if (ce == 0) {
2189 tp->t_rocount = 0;
2190 if (ttyoutput(*cp, tp) >= 0) {
2191 /* No Clists, wait a bit. */
2192 ttstart(tp);
2193 if (flag & IO_NDELAY) {
2194 error = EWOULDBLOCK;
2195 goto out;
2196 }
2197 error = ttysleep(tp, &lbolt,
377d4740 2198 PCATCH,
984263bc
MD
2199 "ttybf1", 0);
2200 if (error)
2201 goto out;
2202 goto loop;
2203 }
2204 cp++;
2205 cc--;
2206 if (ISSET(tp->t_lflag, FLUSHO) ||
2207 tp->t_outq.c_cc > hiwat)
2208 goto ovhiwat;
2209 continue;
2210 }
2211 }
2212 /*
2213 * A bunch of normal characters have been found.
2214 * Transfer them en masse to the output queue and
2215 * continue processing at the top of the loop.
2216 * If there are any further characters in this
2217 * <= OBUFSIZ chunk, the first should be a character
2218 * requiring special handling by ttyoutput.
2219 */
2220 tp->t_rocount = 0;
2221 i = b_to_q(cp, ce, &tp->t_outq);
2222 ce -= i;
2223 tp->t_column += ce;
2224 cp += ce, cc -= ce, tk_nout += ce;
2225 tp->t_outcc += ce;
2226 if (i > 0) {
2227 /* No Clists, wait a bit. */
2228 ttstart(tp);
2229 if (flag & IO_NDELAY) {
2230 error = EWOULDBLOCK;
2231 goto out;
2232 }
377d4740 2233 error = ttysleep(tp, &lbolt, PCATCH,
984263bc
MD
2234 "ttybf2", 0);
2235 if (error)
2236 goto out;
2237 goto loop;
2238 }
2239 if (ISSET(tp->t_lflag, FLUSHO) ||
2240 tp->t_outq.c_cc > hiwat)
2241 break;
2242 }
2243 ttstart(tp);
2244 }
2245out:
2246 /*
2247 * If cc is nonzero, we leave the uio structure inconsistent, as the
2248 * offset and iov pointers have moved forward, but it doesn't matter
2249 * (the call will either return short or restart with a new uio).
2250 */
2251 uio->uio_resid += cc;
22ff886e 2252 lwkt_reltoken(&tty_token);
984263bc
MD
2253 return (error);
2254
2255ovhiwat:
2256 ttstart(tp);
e43a034f 2257 crit_enter();
984263bc
MD
2258 /*
2259 * This can only occur if FLUSHO is set in t_lflag,
2260 * or if ttstart/oproc is synchronous (or very fast).
2261 */
2262 if (tp->t_outq.c_cc <= hiwat) {
e43a034f 2263 crit_exit();
984263bc
MD
2264 goto loop;
2265 }
2266 if (flag & IO_NDELAY) {
e43a034f 2267 crit_exit();
984263bc 2268 uio->uio_resid += cc;
22ff886e 2269 lwkt_reltoken(&tty_token);
984263bc
MD
2270 return (uio->uio_resid == cnt ? EWOULDBLOCK : 0);
2271 }
2272 SET(tp->t_state, TS_SO_OLOWAT);
377d4740 2273 error = ttysleep(tp, TSA_OLOWAT(tp), PCATCH, "ttywri", tp->t_timeout);
e43a034f 2274 crit_exit();
984263bc
MD
2275 if (error == EWOULDBLOCK)
2276 error = EIO;
2277 if (error)
2278 goto out;
2279 goto loop;
2280}
2281
2282/*
2283 * Rubout one character from the rawq of tp
2284 * as cleanly as possible.
22ff886e 2285 * NOTE: Must be called with tty_token held
984263bc
MD
2286 */
2287static void
c972a82f 2288ttyrub(int c, struct tty *tp)
984263bc 2289{
1fd87d54
RG
2290 char *cp;
2291 int savecol;
e43a034f 2292 int tabc;
984263bc 2293
22ff886e 2294 ASSERT_LWKT_TOKEN_HELD(&tty_token);
984263bc
MD
2295 if (!ISSET(tp->t_lflag, ECHO) || ISSET(tp->t_lflag, EXTPROC))
2296 return;
2297 CLR(tp->t_lflag, FLUSHO);
2298 if (ISSET(tp->t_lflag, ECHOE)) {
2299 if (tp->t_rocount == 0) {
2300 /*
2301 * Screwed by ttwrite; retype
2302 */
2303 ttyretype(tp);
2304 return;
2305 }
2306 if (c == ('\t' | TTY_QUOTE) || c == ('\n' | TTY_QUOTE))
2307 ttyrubo(tp, 2);
2308 else {
2309 CLR(c, ~TTY_CHARMASK);
2310 switch (CCLASS(c)) {
2311 case ORDINARY:
2312 ttyrubo(tp, 1);
2313 break;
2314 case BACKSPACE:
2315 case CONTROL:
2316 case NEWLINE:
2317 case RETURN:
2318 case VTAB:
2319 if (ISSET(tp->t_lflag, ECHOCTL))
2320 ttyrubo(tp, 2);
2321 break;
2322 case TAB:
2323 if (tp->t_rocount < tp->t_rawq.c_cc) {
2324 ttyretype(tp);
2325 return;
2326 }
e43a034f 2327 crit_enter();
984263bc
MD
2328 savecol = tp->t_column;
2329 SET(tp->t_state, TS_CNTTB);
2330 SET(tp->t_lflag, FLUSHO);
2331 tp->t_column = tp->t_rocol;
2332 cp = tp->t_rawq.c_cf;
2333 if (cp)
2334 tabc = *cp; /* XXX FIX NEXTC */
2335 for (; cp; cp = nextc(&tp->t_rawq, cp, &tabc))
2336 ttyecho(tabc, tp);
2337 CLR(tp->t_lflag, FLUSHO);
2338 CLR(tp->t_state, TS_CNTTB);
e43a034f 2339 crit_exit();
984263bc
MD
2340
2341 /* savecol will now be length of the tab. */
2342 savecol -= tp->t_column;
2343 tp->t_column += savecol;
2344 if (savecol > 8)
2345 savecol = 8; /* overflow screw */
2346 while (--savecol >= 0)
2347 (void)ttyoutput('\b', tp);
2348 break;
2349 default: /* XXX */
2350#define PANICSTR "ttyrub: would panic c = %d, val = %d\n"
6ea70f76 2351 (void)kprintf(PANICSTR, c, CCLASS(c));
984263bc
MD
2352#ifdef notdef
2353 panic(PANICSTR, c, CCLASS(c));
2354#endif
2355 }
2356 }
2357 } else if (ISSET(tp->t_lflag, ECHOPRT)) {
2358 if (!ISSET(tp->t_state, TS_ERASE)) {
2359 SET(tp->t_state, TS_ERASE);
2360 (void)ttyoutput('\\', tp);
2361 }
2362 ttyecho(c, tp);
2363 } else {
2364 ttyecho(tp->t_cc[VERASE], tp);
2365 /*
2366 * This code may be executed not only when an ERASE key
2367 * is pressed, but also when ^U (KILL) or ^W (WERASE) are.
2368 * So, I didn't think it was worthwhile to pass the extra
2369 * information (which would need an extra parameter,
2370 * changing every call) needed to distinguish the ERASE2
2371 * case from the ERASE.
2372 */
2373 }
2374 --tp->t_rocount;
2375}
2376
2377/*
2378 * Back over cnt characters, erasing them.
22ff886e 2379 * NOTE: Must be called with tty_token held
984263bc
MD
2380 */
2381static void
c972a82f 2382ttyrubo(struct tty *tp, int cnt)
984263bc 2383{
22ff886e 2384 ASSERT_LWKT_TOKEN_HELD(&tty_token);
984263bc
MD
2385 while (cnt-- > 0) {
2386 (void)ttyoutput('\b', tp);
2387 (void)ttyoutput(' ', tp);
2388 (void)ttyoutput('\b', tp);
2389 }
2390}
2391
2392/*
2393 * ttyretype --
2394 * Reprint the rawq line. Note, it is assumed that c_cc has already
2395 * been checked.
22ff886e 2396 * NOTE: Must be called with tty_token held
984263bc
MD
2397 */
2398static void
c972a82f 2399ttyretype(struct tty *tp)
984263bc 2400{
1fd87d54 2401 char *cp;
e43a034f 2402 int c;
984263bc 2403
22ff886e 2404 ASSERT_LWKT_TOKEN_HELD(&tty_token);
984263bc
MD
2405 /* Echo the reprint character. */
2406 if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE)
2407 ttyecho(tp->t_cc[VREPRINT], tp);
2408
2409 (void)ttyoutput('\n', tp);
2410
2411 /*
2412 * XXX
2413 * FIX: NEXTC IS BROKEN - DOESN'T CHECK QUOTE
2414 * BIT OF FIRST CHAR.
2415 */
e43a034f 2416 crit_enter();
984263bc
MD
2417 for (cp = tp->t_canq.c_cf, c = (cp != NULL ? *cp : 0);
2418 cp != NULL; cp = nextc(&tp->t_canq, cp, &c))
2419 ttyecho(c, tp);
2420 for (cp = tp->t_rawq.c_cf, c = (cp != NULL ? *cp : 0);
2421 cp != NULL; cp = nextc(&tp->t_rawq, cp, &c))
2422 ttyecho(c, tp);
2423 CLR(tp->t_state, TS_ERASE);
e43a034f 2424 crit_exit();
984263bc
MD
2425
2426 tp->t_rocount = tp->t_rawq.c_cc;
2427 tp->t_rocol = 0;
2428}
2429
2430/*
2431 * Echo a typed character to the terminal.
22ff886e 2432 * NOTE: Must be called with tty_token held
984263bc
MD
2433 */
2434static void
c972a82f 2435ttyecho(int c, struct tty *tp)
984263bc 2436{
22ff886e 2437 ASSERT_LWKT_TOKEN_HELD(&tty_token);
984263bc
MD
2438
2439 if (!ISSET(tp->t_state, TS_CNTTB))
2440 CLR(tp->t_lflag, FLUSHO);
2441 if ((!ISSET(tp->t_lflag, ECHO) &&
2442 (c != '\n' || !ISSET(tp->t_lflag, ECHONL))) ||
2443 ISSET(tp->t_lflag, EXTPROC))
2444 return;
2445 if (ISSET(tp->t_lflag, ECHOCTL) &&
2446 ((ISSET(c, TTY_CHARMASK) <= 037 && c != '\t' && c != '\n') ||
2447 ISSET(c, TTY_CHARMASK) == 0177)) {
2448 (void)ttyoutput('^', tp);
2449 CLR(c, ~TTY_CHARMASK);
2450 if (c == 0177)
2451 c = '?';
2452 else
2453 c += 'A' - 1;
2454 }
2455 (void)ttyoutput(c, tp);
2456}
2457
2458/*
2459 * Wake up any readers on a tty.
2460 */
2461void
c972a82f 2462ttwakeup(struct tty *tp)
984263bc 2463{
22ff886e 2464 lwkt_gettoken(&tty_token);
984263bc
MD
2465 if (ISSET(tp->t_state, TS_ASYNC) && tp->t_sigio != NULL)
2466 pgsigio(tp->t_sigio, SIGIO, (tp->t_session != NULL));
2467 wakeup(TSA_HUP_OR_INPUT(tp));
5b22f1a7 2468 KNOTE(&tp->t_rkq.ki_note, 0);
22ff886e 2469 lwkt_reltoken(&tty_token);
984263bc
MD
2470}
2471
2472/*
2473 * Wake up any writers on a tty.
2474 */
2475void
c972a82f 2476ttwwakeup(struct tty *tp)
984263bc 2477{
22ff886e 2478 lwkt_gettoken(&tty_token);
984263bc
MD
2479 if (ISSET(tp->t_state, TS_ASYNC) && tp->t_sigio != NULL)
2480 pgsigio(tp->t_sigio, SIGIO, (tp->t_session != NULL));
2481 if (ISSET(tp->t_state, TS_BUSY | TS_SO_OCOMPLETE) ==
2482 TS_SO_OCOMPLETE && tp->t_outq.c_cc == 0) {
2483 CLR(tp->t_state, TS_SO_OCOMPLETE);
2484 wakeup(TSA_OCOMPLETE(tp));
2485 }
2486 if (ISSET(tp->t_state, TS_SO_OLOWAT) &&
2487 tp->t_outq.c_cc <= tp->t_olowat) {
2488 CLR(tp->t_state, TS_SO_OLOWAT);
2489 wakeup(TSA_OLOWAT(tp));
2490 }
5b22f1a7 2491 KNOTE(&tp->t_wkq.ki_note, 0);
22ff886e 2492 lwkt_reltoken(&tty_token);
984263bc
MD
2493}
2494
2495/*
2496 * Look up a code for a specified speed in a conversion table;
2497 * used by drivers to map software speed values to hardware parameters.
22ff886e 2498 * No requirements
984263bc
MD
2499 */
2500int
c972a82f 2501ttspeedtab(int speed, struct speedtab *table)
984263bc
MD
2502{
2503
2504 for ( ; table->sp_speed != -1; table++)
2505 if (table->sp_speed == speed)
2506 return (table->sp_code);
2507 return (-1);
2508}
2509
2510/*
2511 * Set input and output watermarks and buffer sizes. For input, the
2512 * high watermark is about one second's worth of input above empty, the
2513 * low watermark is slightly below high water, and the buffer size is a
2514 * driver-dependent amount above high water. For output, the watermarks
2515 * are near the ends of the buffer, with about 1 second's worth of input
2516 * between them. All this only applies to the standard line discipline.
2517 */
2518void
c972a82f 2519ttsetwater(struct tty *tp)
984263bc 2520{
1fd87d54 2521 int cps, ttmaxhiwat, x;
984263bc 2522
22ff886e 2523 lwkt_gettoken(&tty_token);
984263bc
MD
2524 /* Input. */
2525 clist_alloc_cblocks(&tp->t_canq, TTYHOG, 512);
2526 switch (tp->t_ispeedwat) {
2527 case (speed_t)-1:
2528 cps = tp->t_ispeed / 10;
2529 break;
2530 case 0:
2531 /*
2532 * This case is for old drivers that don't know about
2533 * t_ispeedwat. Arrange for them to get the old buffer
2534 * sizes and watermarks.
2535 */
2536 cps = TTYHOG - 2 * 256;
2849f1e5 2537 tp->t_ififosize = 2 * 2048;
984263bc
MD
2538 break;
2539 default:
2540 cps = tp->t_ispeedwat / 10;
2541 break;
2542 }
2543 tp->t_ihiwat = cps;
2544 tp->t_ilowat = 7 * cps / 8;
2545 x = cps + tp->t_ififosize;
2546 clist_alloc_cblocks(&tp->t_rawq, x, x);
2547
2548 /* Output. */
2549 switch (tp->t_ospeedwat) {
2550 case (speed_t)-1:
2551 cps = tp->t_ospeed / 10;
2552 ttmaxhiwat = 2 * TTMAXHIWAT;
2553 break;
2554 case 0:
2555 cps = tp->t_ospeed / 10;
2556 ttmaxhiwat = TTMAXHIWAT;
2557 break;
2558 default:
2559 cps = tp->t_ospeedwat / 10;
2560 ttmaxhiwat = 8 * TTMAXHIWAT;
2561 break;
2562 }
2563#define CLAMP(x, h, l) ((x) > h ? h : ((x) < l) ? l : (x))
2564 tp->t_olowat = x = CLAMP(cps / 2, TTMAXLOWAT, TTMINLOWAT);
2565 x += cps;
2566 x = CLAMP(x, ttmaxhiwat, TTMINHIWAT); /* XXX clamps are too magic */
2567 tp->t_ohiwat = roundup(x, CBSIZE); /* XXX for compat */
2568 x = imax(tp->t_ohiwat, TTMAXHIWAT); /* XXX for compat/safety */
2569 x += OBUFSIZ + 100;
2570 clist_alloc_cblocks(&tp->t_outq, x, x);
2571#undef CLAMP
22ff886e 2572 lwkt_reltoken(&tty_token);
984263bc
MD
2573}
2574
2575/*
2576 * Report on state of foreground process group.
2577 */
2578void
c972a82f 2579ttyinfo(struct tty *tp)
984263bc 2580{
1fd87d54 2581 struct proc *p, *pick;
08f2f1bb 2582 struct lwp *lp;
fde7ac71 2583 struct rusage ru;
984263bc
MD
2584 int tmp;
2585
2586 if (ttycheckoutq(tp,0) == 0)
2587 return;
2588
22ff886e
AH
2589 lwkt_gettoken(&tty_token);
2590 lwkt_gettoken(&proc_token);
5daa25b0
MD
2591 /*
2592 * We always print the load average, then figure out what else to
2593 * print based on the state of the current process group.
2594 */
984263bc
MD
2595 tmp = (averunnable.ldavg[0] * 100 + FSCALE / 2) >> FSHIFT;
2596 ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100);
2597
5daa25b0 2598 if (tp->t_session == NULL) {
984263bc 2599 ttyprintf(tp, "not a controlling terminal\n");
5daa25b0 2600 } else if (tp->t_pgrp == NULL) {
984263bc 2601 ttyprintf(tp, "no foreground process group\n");
58c2553a 2602 } else if ((p = LIST_FIRST(&tp->t_pgrp->pg_members)) == NULL) {
984263bc 2603 ttyprintf(tp, "empty foreground process group\n");
5daa25b0 2604 } else {
8dda877a 2605 /*
5daa25b0
MD
2606 * Pick an interesting process. Note that certain elements,
2607 * in particular the wmesg, require a critical section for
2608 * safe access (YYY and we are still not MP safe).
8dda877a 2609 *
08f2f1bb 2610 * NOTE: lwp_wmesg is lwp_thread->td_wmesg.
8dda877a 2611 */
5daa25b0 2612 char buf[64];
8dda877a 2613 const char *str;
5daa25b0
MD
2614 long vmsz;
2615 int pctcpu;
8dda877a
MD
2616
2617 crit_enter();
5daa25b0 2618
bb3cd951
SS
2619 /* XXX lwp should compare lwps */
2620
58c2553a 2621 for (pick = NULL; p != NULL; p = LIST_NEXT(p, p_pglist)) {
984263bc
MD
2622 if (proc_compare(pick, p))
2623 pick = p;
8dda877a 2624 }
5daa25b0 2625
08f2f1bb
SS
2626 /* XXX lwp */
2627 lp = FIRST_LWP_IN_PROC(pick);
2628 if (lp == NULL) {
2629 ttyprintf(tp, "foreground process without lwp\n");
2630 tp->t_rocount = 0;
62c46e45 2631 crit_exit();
22ff886e
AH
2632 lwkt_reltoken(&proc_token);
2633 lwkt_reltoken(&tty_token);
08f2f1bb
SS
2634 return;
2635 }
2636
5daa25b0
MD
2637 /*
2638 * Figure out what wait/process-state message, and command
2639 * buffer to present
2640 */
08f2f1bb
SS
2641 /*
2642 * XXX lwp This is a horrible mixture. We need to rework this
2643 * as soon as lwps have their own runnable status.
2644 */
4643740a 2645 if (pick->p_flags & P_WEXIT)
8dda877a 2646 str = "exiting";
164b8401 2647 else if (lp->lwp_stat == LSRUN)
8dda877a 2648 str = "running";
bb3cd951
SS
2649 else if (pick->p_stat == SIDL)
2650 str = "spawning";
08f2f1bb
SS
2651 else if (lp->lwp_wmesg) /* lwp_thread must not be NULL */
2652 str = lp->lwp_wmesg;
8dda877a
MD
2653 else
2654 str = "iowait";
984263bc 2655
f8c7a42d 2656 ksnprintf(buf, sizeof(buf), "cmd: %s %d [%s]",
bb3cd951 2657 pick->p_comm, pick->p_pid, str);
984263bc 2658
5daa25b0
MD
2659 /*
2660 * Calculate cpu usage, percent cpu, and cmsz. Note that
2661 * 'pick' becomes invalid the moment we exit the critical
2662 * section.
2663 */
4643740a 2664 if (lp->lwp_thread && (pick->p_flags & P_SWAPPEDOUT) == 0)
fde7ac71 2665 calcru_proc(pick, &ru);
984263bc 2666
08f2f1bb 2667 pctcpu = (lp->lwp_pctcpu * 10000 + FSCALE / 2) >> FSHIFT;
5daa25b0 2668
b12defdc 2669 if (pick->p_stat == SIDL || pick->p_stat == SZOMB) {
5daa25b0 2670 vmsz = 0;
b12defdc
MD
2671 } else {
2672 lwkt_gettoken(&pick->p_vmspace->vm_map.token);
5daa25b0 2673 vmsz = pgtok(vmspace_resident_count(pick->p_vmspace));
b12defdc
MD
2674 lwkt_reltoken(&pick->p_vmspace->vm_map.token);
2675 }
5daa25b0
MD
2676
2677 crit_exit();
984263bc 2678
5daa25b0
MD
2679 /*
2680 * Dump the output
2681 */
2682 ttyprintf(tp, " %s ", buf);
fde7ac71
SS
2683 ttyprintf(tp, "%ld.%02ldu ",
2684 ru.ru_utime.tv_sec, ru.ru_utime.tv_usec / 10000);
2685 ttyprintf(tp, "%ld.%02lds ",
2686 ru.ru_stime.tv_sec, ru.ru_stime.tv_usec / 10000);
5daa25b0 2687 ttyprintf(tp, "%d%% %ldk\n", pctcpu / 100, vmsz);
984263bc
MD
2688 }
2689 tp->t_rocount = 0; /* so pending input will be retyped if BS */
22ff886e
AH
2690 lwkt_reltoken(&proc_token);
2691 lwkt_reltoken(&tty_token);
984263bc
MD
2692}
2693
2694/*
2695 * Returns 1 if p2 is "better" than p1
2696 *
2697 * The algorithm for picking the "interesting" process is thus:
2698 *
2699 * 1) Only foreground processes are eligible - implied.
2700 * 2) Runnable processes are favored over anything else. The runner
dcc99b62 2701 * with the highest cpu utilization is picked (p_cpticks). Ties are
984263bc
MD
2702 * broken by picking the highest pid.
2703 * 3) The sleeper with the shortest sleep time is next. With ties,
9a379a4a 2704 * we pick out just "short-term" sleepers (LWP_SINTR == 0).
984263bc 2705 * 4) Further ties are broken by picking the highest pid.
22ff886e
AH
2706 *
2707 * NOTE: must be called with proc_token held.
984263bc 2708 */
164b8401 2709#define ISRUN(lp) ((lp)->lwp_stat == LSRUN)
984263bc
MD
2710#define TESTAB(a, b) ((a)<<1 | (b))
2711#define ONLYA 2
2712#define ONLYB 1
2713#define BOTH 3
2714
2715static int
c972a82f 2716proc_compare(struct proc *p1, struct proc *p2)
984263bc 2717{
08f2f1bb 2718 struct lwp *lp1, *lp2;
22ff886e
AH
2719
2720 ASSERT_LWKT_TOKEN_HELD(&proc_token);
2721
984263bc
MD
2722 if (p1 == NULL)
2723 return (1);
08f2f1bb 2724
93e5e2ea
MD
2725 /*
2726 * weed out zombies
2727 */
2728 switch (TESTAB(p1->p_stat == SZOMB, p2->p_stat == SZOMB)) {
2729 case ONLYA:
2730 return (1);
2731 case ONLYB:
2732 return (0);
2733 case BOTH:
2734 return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
2735 }
2736
08f2f1bb
SS
2737 /* XXX lwp */
2738 lp1 = FIRST_LWP_IN_PROC(p1);
2739 lp2 = FIRST_LWP_IN_PROC(p2);
2740
984263bc
MD
2741 /*
2742 * see if at least one of them is runnable
2743 */
164b8401 2744 switch (TESTAB(ISRUN(lp1), ISRUN(lp2))) {
984263bc
MD
2745 case ONLYA:
2746 return (0);
2747 case ONLYB:
2748 return (1);
2749 case BOTH:
2750 /*
2751 * tie - favor one with highest recent cpu utilization
2752 */
08f2f1bb 2753 if (lp2->lwp_cpticks > lp1->lwp_cpticks)
984263bc 2754 return (1);
08f2f1bb 2755 if (lp1->lwp_cpticks > lp2->lwp_cpticks)
984263bc
MD
2756 return (0);
2757 return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
2758 }
2759 /*
984263bc
MD
2760 * pick the one with the smallest sleep time
2761 */
08f2f1bb 2762 if (lp2->lwp_slptime > lp1->lwp_slptime)
984263bc 2763 return (0);
08f2f1bb 2764 if (lp1->lwp_slptime > lp2->lwp_slptime)
984263bc
MD
2765 return (1);
2766 /*
2767 * favor one sleeping in a non-interruptible sleep
2768 */
4643740a 2769 if (lp1->lwp_flags & LWP_SINTR && (lp2->lwp_flags & LWP_SINTR) == 0)
984263bc 2770 return (1);
4643740a 2771 if (lp2->lwp_flags & LWP_SINTR && (lp1->lwp_flags & LWP_SINTR) == 0)
984263bc
MD
2772 return (0);
2773 return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
2774}
2775
2776/*
2777 * Output char to tty; console putchar style.
2778 */
2779int
c972a82f 2780tputchar(int c, struct tty *tp)
984263bc 2781{
e43a034f 2782 crit_enter();
22ff886e 2783 lwkt_gettoken(&tty_token);
984263bc 2784 if (!ISSET(tp->t_state, TS_CONNECTED)) {
22ff886e 2785 lwkt_reltoken(&tty_token);
e43a034f 2786 crit_exit();
984263bc
MD
2787 return (-1);
2788 }
2789 if (c == '\n')
2790 (void)ttyoutput('\r', tp);
2791 (void)ttyoutput(c, tp);
2792 ttstart(tp);
22ff886e 2793 lwkt_reltoken(&tty_token);
e43a034f 2794 crit_exit();
984263bc
MD
2795 return (0);
2796}
2797
2798/*
2799 * Sleep on chan, returning ERESTART if tty changed while we napped and
2800 * returning any errors (e.g. EINTR/EWOULDBLOCK) reported by tsleep. If
2801 * the tty is revoked, restarting a pending call will redo validation done
2802 * at the start of the call.
2803 */
2804int
c972a82f 2805ttysleep(struct tty *tp, void *chan, int slpflags, char *wmesg, int timo)
984263bc
MD
2806{
2807 int error;
2808 int gen;
2809
2810 gen = tp->t_gen;
377d4740 2811 error = tsleep(chan, slpflags, wmesg, timo);
984263bc
MD
2812 if (error)
2813 return (error);
2814 return (tp->t_gen == gen ? 0 : ERESTART);
2815}
2816
2817/*
a32446b7
MD
2818 * Revoke a tty.
2819 *
2820 * We bump the gen to force any ttysleep()'s to return with ERESTART
2821 * and flush the tty. The related fp's should already have been
2822 * replaced so the tty will close when the last references on the
2823 * original fp's go away.
2824 */
2825int
2826ttyrevoke(struct dev_revoke_args *ap)
2827{
2828 struct tty *tp;
2829
22ff886e 2830 lwkt_gettoken(&tty_token);
a32446b7
MD
2831 tp = ap->a_head.a_dev->si_tty;
2832 tp->t_gen++;
2833 ttyflush(tp, FREAD | FWRITE);
2834 wakeup(TSA_CARR_ON(tp));
2835 ttwakeup(tp);
2836 ttwwakeup(tp);
22ff886e 2837 lwkt_reltoken(&tty_token);
a32446b7
MD
2838 return (0);
2839}
2840
2841/*
984263bc
MD
2842 * Allocate a tty struct. Clists in the struct will be allocated by
2843 * ttyopen().
2844 */
2845struct tty *
c972a82f 2846ttymalloc(struct tty *tp)
984263bc
MD
2847{
2848
cd29885a 2849 if (tp) {
984263bc 2850 return(tp);
cd29885a
MD
2851 }
2852 tp = kmalloc(sizeof *tp, M_TTYS, M_WAITOK|M_ZERO);
984263bc
MD
2853 ttyregister(tp);
2854 return (tp);
2855}
2856
984263bc 2857void
ddac2002 2858ttyunregister(struct tty *tp)
984263bc 2859{
22ff886e 2860 lwkt_gettoken(&tty_token);
ddac2002
MD
2861 KKASSERT(ISSET(tp->t_state, TS_REGISTERED));
2862 CLR(tp->t_state, TS_REGISTERED);
2863 TAILQ_REMOVE(&tty_list, tp, t_list);
22ff886e 2864 lwkt_reltoken(&tty_token);
984263bc 2865}
984263bc
MD
2866
2867void
c972a82f 2868ttyregister(struct tty *tp)
984263bc 2869{
22ff886e 2870 lwkt_gettoken(&tty_token);
ddac2002
MD
2871 KKASSERT(!ISSET(tp->t_state, TS_REGISTERED));
2872 SET(tp->t_state, TS_REGISTERED);
2873 TAILQ_INSERT_HEAD(&tty_list, tp, t_list);
22ff886e 2874 lwkt_reltoken(&tty_token);
984263bc
MD
2875}
2876
2877static int
2878sysctl_kern_ttys(SYSCTL_HANDLER_ARGS)
2879{
2880 int error;
ddac2002
MD
2881 struct tty *tp;
2882 struct tty t;
2883 struct tty marker;
2884
2885 bzero(&marker, sizeof(marker));
2886 marker.t_state = TS_MARKER;
2887 error = 0;
2888
22ff886e
AH
2889 lwkt_gettoken(&tty_token);
2890
ddac2002
MD
2891 TAILQ_INSERT_HEAD(&tty_list, &marker, t_list);
2892 while ((tp = TAILQ_NEXT(&marker, t_list)) != NULL) {
2893 TAILQ_REMOVE(&tty_list, &marker, t_list);
2894 TAILQ_INSERT_AFTER(&tty_list, tp, &marker, t_list);
2895 if (tp->t_state & TS_MARKER)
2896 continue;
984263bc
MD
2897 t = *tp;
2898 if (t.t_dev)
973c11b9 2899 t.t_dev = (cdev_t)(uintptr_t)dev2udev(t.t_dev);
984263bc
MD
2900 error = SYSCTL_OUT(req, (caddr_t)&t, sizeof(t));
2901 if (error)
ddac2002 2902 break;
984263bc 2903 }
ddac2002 2904 TAILQ_REMOVE(&tty_list, &marker, t_list);
22ff886e 2905 lwkt_reltoken(&tty_token);
ddac2002 2906 return (error);
984263bc
MD
2907}
2908
2909SYSCTL_PROC(_kern, OID_AUTO, ttys, CTLTYPE_OPAQUE|CTLFLAG_RD,
2910 0, 0, sysctl_kern_ttys, "S,tty", "All struct ttys");
2911
2912void
c972a82f 2913nottystop(struct tty *tp, int rw)
984263bc 2914{
984263bc
MD
2915 return;
2916}
2917
2918int
fef8985e 2919ttyread(struct dev_read_args *ap)
984263bc
MD
2920{
2921 struct tty *tp;
22ff886e 2922 int ret;
984263bc 2923
fef8985e 2924 tp = ap->a_head.a_dev->si_tty;
984263bc
MD
2925 if (tp == NULL)
2926 return (ENODEV);
22ff886e
AH
2927 lwkt_gettoken(&tty_token);
2928 ret = ((*linesw[tp->t_line].l_read)(tp, ap->a_uio, ap->a_ioflag));
2929 lwkt_reltoken(&tty_token);
2930
2931 return ret;
984263bc
MD
2932}
2933
2934int
fef8985e 2935ttywrite(struct dev_write_args *ap)
984263bc
MD
2936{
2937 struct tty *tp;
22ff886e 2938 int ret;
984263bc 2939
fef8985e 2940 tp = ap->a_head.a_dev->si_tty;
984263bc
MD
2941 if (tp == NULL)
2942 return (ENODEV);
22ff886e
AH
2943 lwkt_gettoken(&tty_token);
2944 ret = ((*linesw[tp->t_line].l_write)(tp, ap->a_uio, ap->a_ioflag));
2945 lwkt_reltoken(&tty_token);
2946
2947 return ret;
984263bc 2948}