Line data Source code
1 : /* $OpenBSD: tty.c,v 1.143 2018/09/06 11:50:54 jsg Exp $ */
2 : /* $NetBSD: tty.c,v 1.68.4.2 1996/06/06 16:04:52 thorpej Exp $ */
3 :
4 : /*-
5 : * Copyright (c) 1982, 1986, 1990, 1991, 1993
6 : * The Regents of the University of California. All rights reserved.
7 : * (c) UNIX System Laboratories, Inc.
8 : * All or some portions of this file are derived from material licensed
9 : * to the University of California by American Telephone and Telegraph
10 : * Co. or Unix System Laboratories, Inc. and are reproduced herein with
11 : * the permission of UNIX System Laboratories, Inc.
12 : *
13 : * Redistribution and use in source and binary forms, with or without
14 : * modification, are permitted provided that the following conditions
15 : * are met:
16 : * 1. Redistributions of source code must retain the above copyright
17 : * notice, this list of conditions and the following disclaimer.
18 : * 2. Redistributions in binary form must reproduce the above copyright
19 : * notice, this list of conditions and the following disclaimer in the
20 : * documentation and/or other materials provided with the distribution.
21 : * 3. Neither the name of the University nor the names of its contributors
22 : * may be used to endorse or promote products derived from this software
23 : * without specific prior written permission.
24 : *
25 : * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 : * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 : * SUCH DAMAGE.
36 : *
37 : * @(#)tty.c 8.8 (Berkeley) 1/21/94
38 : */
39 :
40 : #include <sys/param.h>
41 : #include <sys/systm.h>
42 : #include <sys/ioctl.h>
43 : #include <sys/proc.h>
44 : #define TTYDEFCHARS
45 : #include <sys/tty.h>
46 : #undef TTYDEFCHARS
47 : #include <sys/fcntl.h>
48 : #include <sys/conf.h>
49 : #include <sys/uio.h>
50 : #include <sys/kernel.h>
51 : #include <sys/vnode.h>
52 : #include <sys/lock.h>
53 : #include <sys/syslog.h>
54 : #include <sys/malloc.h>
55 : #include <sys/msgbuf.h>
56 : #include <sys/signalvar.h>
57 : #include <sys/resourcevar.h>
58 : #include <sys/sysctl.h>
59 : #include <sys/pool.h>
60 : #include <sys/poll.h>
61 : #include <sys/unistd.h>
62 : #include <sys/pledge.h>
63 :
64 : #include <sys/namei.h>
65 :
66 : #include <uvm/uvm_extern.h>
67 :
68 : #include <dev/cons.h>
69 : #include <dev/rndvar.h>
70 :
71 : #include "pty.h"
72 :
73 : static int ttnread(struct tty *);
74 : static void ttyblock(struct tty *);
75 : void ttyunblock(struct tty *);
76 : static void ttyecho(int, struct tty *);
77 : static void ttyrubo(struct tty *, int);
78 : void ttkqflush(struct klist *klist);
79 : int filt_ttyread(struct knote *kn, long hint);
80 : void filt_ttyrdetach(struct knote *kn);
81 : int filt_ttywrite(struct knote *kn, long hint);
82 : void filt_ttywdetach(struct knote *kn);
83 : void ttystats_init(struct itty **, size_t *);
84 :
85 : /* Symbolic sleep message strings. */
86 : char ttclos[] = "ttycls";
87 : char ttopen[] = "ttyopn";
88 : char ttybg[] = "ttybg";
89 : char ttyin[] = "ttyin";
90 : char ttyout[] = "ttyout";
91 :
92 : /*
93 : * Table with character classes and parity. The 8th bit indicates parity,
94 : * the 7th bit indicates the character is an alphameric or underscore (for
95 : * ALTWERASE), and the low 6 bits indicate delay type. If the low 6 bits
96 : * are 0 then the character needs no special processing on output; classes
97 : * other than 0 might be translated or (not currently) require delays.
98 : */
99 : #define E 0x00 /* Even parity. */
100 : #define O 0x80 /* Odd parity. */
101 : #define PARITY(c) (char_type[c] & O)
102 :
103 : #define ALPHA 0x40 /* Alpha or underscore. */
104 : #define ISALPHA(c) (char_type[(c) & TTY_CHARMASK] & ALPHA)
105 :
106 : #define CCLASSMASK 0x3f
107 : #define CCLASS(c) (char_type[c] & CCLASSMASK)
108 :
109 : #define BS BACKSPACE
110 : #define CC CONTROL
111 : #define CR RETURN
112 : #define NA ORDINARY | ALPHA
113 : #define NL NEWLINE
114 : #define NO ORDINARY
115 : #define TB TAB
116 : #define VT VTAB
117 :
118 : u_char const char_type[] = {
119 : E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* nul - bel */
120 : O|BS, E|TB, E|NL, O|CC, E|VT, O|CR, O|CC, E|CC, /* bs - si */
121 : O|CC, E|CC, E|CC, O|CC, E|CC, O|CC, O|CC, E|CC, /* dle - etb */
122 : E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* can - us */
123 : O|NO, E|NO, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* sp - ' */
124 : E|NO, O|NO, O|NO, E|NO, O|NO, E|NO, E|NO, O|NO, /* ( - / */
125 : E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* 0 - 7 */
126 : O|NA, E|NA, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* 8 - ? */
127 : O|NO, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* @ - G */
128 : E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* H - O */
129 : E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* P - W */
130 : O|NA, E|NA, E|NA, O|NO, E|NO, O|NO, O|NO, O|NA, /* X - _ */
131 : E|NO, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* ` - g */
132 : O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* h - o */
133 : O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* p - w */
134 : E|NA, O|NA, O|NA, E|NO, O|NO, E|NO, E|NO, O|CC, /* x - del */
135 : /*
136 : * Meta chars; should be settable per character set;
137 : * for now, treat them all as normal characters.
138 : */
139 : NA, NA, NA, NA, NA, NA, NA, NA,
140 : NA, NA, NA, NA, NA, NA, NA, NA,
141 : NA, NA, NA, NA, NA, NA, NA, NA,
142 : NA, NA, NA, NA, NA, NA, NA, NA,
143 : NA, NA, NA, NA, NA, NA, NA, NA,
144 : NA, NA, NA, NA, NA, NA, NA, NA,
145 : NA, NA, NA, NA, NA, NA, NA, NA,
146 : NA, NA, NA, NA, NA, NA, NA, NA,
147 : NA, NA, NA, NA, NA, NA, NA, NA,
148 : NA, NA, NA, NA, NA, NA, NA, NA,
149 : NA, NA, NA, NA, NA, NA, NA, NA,
150 : NA, NA, NA, NA, NA, NA, NA, NA,
151 : NA, NA, NA, NA, NA, NA, NA, NA,
152 : NA, NA, NA, NA, NA, NA, NA, NA,
153 : NA, NA, NA, NA, NA, NA, NA, NA,
154 : NA, NA, NA, NA, NA, NA, NA, NA,
155 : };
156 : #undef BS
157 : #undef CC
158 : #undef CR
159 : #undef NA
160 : #undef NL
161 : #undef NO
162 : #undef TB
163 : #undef VT
164 :
165 : #define islower(c) ((c) >= 'a' && (c) <= 'z')
166 : #define isupper(c) ((c) >= 'A' && (c) <= 'Z')
167 :
168 : #define tolower(c) ((c) - 'A' + 'a')
169 : #define toupper(c) ((c) - 'a' + 'A')
170 :
171 : struct ttylist_head ttylist; /* TAILQ_HEAD */
172 : int tty_count;
173 :
174 : int64_t tk_cancc, tk_nin, tk_nout, tk_rawcc;
175 :
176 : /*
177 : * Initial open of tty, or (re)entry to standard tty line discipline.
178 : */
179 : int
180 0 : ttyopen(dev_t device, struct tty *tp, struct proc *p)
181 : {
182 : int s;
183 :
184 0 : s = spltty();
185 0 : tp->t_dev = device;
186 0 : if (!ISSET(tp->t_state, TS_ISOPEN)) {
187 0 : SET(tp->t_state, TS_ISOPEN);
188 0 : memset(&tp->t_winsize, 0, sizeof(tp->t_winsize));
189 0 : tp->t_column = 0;
190 0 : }
191 0 : CLR(tp->t_state, TS_WOPEN);
192 0 : splx(s);
193 0 : return (0);
194 : }
195 :
196 : /*
197 : * Handle close() on a tty line: flush and set to initial state,
198 : * bumping generation number so that pending read/write calls
199 : * can detect recycling of the tty.
200 : */
201 : int
202 0 : ttyclose(struct tty *tp)
203 : {
204 0 : if (constty == tp)
205 0 : constty = NULL;
206 :
207 0 : ttyflush(tp, FREAD | FWRITE);
208 :
209 0 : tp->t_gen++;
210 0 : tp->t_pgrp = NULL;
211 0 : if (tp->t_session)
212 0 : SESSRELE(tp->t_session);
213 0 : tp->t_session = NULL;
214 0 : tp->t_state = 0;
215 0 : return (0);
216 : }
217 :
218 : #define FLUSHQ(q) { \
219 : if ((q)->c_cc) \
220 : ndflush(q, (q)->c_cc); \
221 : }
222 :
223 : /* Is 'c' a line delimiter ("break" character)? */
224 : #define TTBREAKC(c, lflag) \
225 : ((c) == '\n' || (((c) == cc[VEOF] || (c) == cc[VEOL] || \
226 : ((c) == cc[VEOL2] && (lflag & IEXTEN))) && (c) != _POSIX_VDISABLE))
227 :
228 :
229 : /*
230 : * Process input of a single character received on a tty.
231 : */
232 : int
233 0 : ttyinput(int c, struct tty *tp)
234 : {
235 : int iflag, lflag;
236 : u_char *cc;
237 : int i, error;
238 : int s;
239 :
240 0 : enqueue_randomness(tp->t_dev << 8 | c);
241 : /*
242 : * If receiver is not enabled, drop it.
243 : */
244 0 : if (!ISSET(tp->t_cflag, CREAD))
245 0 : return (0);
246 :
247 : /*
248 : * If input is pending take it first.
249 : */
250 0 : lflag = tp->t_lflag;
251 0 : s = spltty();
252 0 : if (ISSET(lflag, PENDIN))
253 0 : ttypend(tp);
254 0 : splx(s);
255 : /*
256 : * Gather stats.
257 : */
258 0 : if (ISSET(lflag, ICANON)) {
259 0 : ++tk_cancc;
260 0 : ++tp->t_cancc;
261 0 : } else {
262 0 : ++tk_rawcc;
263 0 : ++tp->t_rawcc;
264 : }
265 0 : ++tk_nin;
266 :
267 : /* Handle exceptional conditions (break, parity, framing). */
268 0 : cc = tp->t_cc;
269 0 : iflag = tp->t_iflag;
270 0 : if ((error = (ISSET(c, TTY_ERRORMASK))) != 0) {
271 0 : CLR(c, TTY_ERRORMASK);
272 0 : if (ISSET(error, TTY_FE) && !c) { /* Break. */
273 0 : if (ISSET(iflag, IGNBRK))
274 0 : return (0);
275 0 : ttyflush(tp, FREAD | FWRITE);
276 0 : if (ISSET(iflag, BRKINT)) {
277 0 : pgsignal(tp->t_pgrp, SIGINT, 1);
278 0 : goto endcase;
279 : }
280 0 : else if (ISSET(iflag, PARMRK))
281 : goto parmrk;
282 0 : } else if ((ISSET(error, TTY_PE) && ISSET(iflag, INPCK)) ||
283 0 : ISSET(error, TTY_FE)) {
284 0 : if (ISSET(iflag, IGNPAR))
285 : goto endcase;
286 0 : else if (ISSET(iflag, PARMRK)) {
287 0 : parmrk: (void)putc(0377 | TTY_QUOTE, &tp->t_rawq);
288 0 : if (ISSET(iflag, ISTRIP) || c != 0377)
289 0 : (void)putc(0 | TTY_QUOTE, &tp->t_rawq);
290 0 : (void)putc(c | TTY_QUOTE, &tp->t_rawq);
291 0 : goto endcase;
292 : } else
293 : c = 0;
294 0 : }
295 : }
296 0 : if (c == 0377 && !ISSET(iflag, ISTRIP) && ISSET(iflag, PARMRK))
297 : goto parmrk;
298 :
299 : /*
300 : * In tandem mode, check high water mark.
301 : */
302 0 : if (ISSET(iflag, IXOFF) || ISSET(tp->t_cflag, CHWFLOW))
303 0 : ttyblock(tp);
304 0 : if (!ISSET(tp->t_state, TS_TYPEN) && ISSET(iflag, ISTRIP))
305 0 : CLR(c, 0x80);
306 0 : if (!ISSET(lflag, EXTPROC)) {
307 : /*
308 : * Check for literal nexting very first
309 : */
310 0 : if (ISSET(tp->t_state, TS_LNCH)) {
311 0 : SET(c, TTY_QUOTE);
312 0 : CLR(tp->t_state, TS_LNCH);
313 0 : }
314 : /*
315 : * Scan for special characters. This code
316 : * is really just a big case statement with
317 : * non-constant cases. The bottom of the
318 : * case statement is labeled ``endcase'', so goto
319 : * it after a case match, or similar.
320 : */
321 :
322 : /*
323 : * Control chars which aren't controlled
324 : * by ICANON, ISIG, or IXON.
325 : */
326 0 : if (ISSET(lflag, IEXTEN)) {
327 0 : if (CCEQ(cc[VLNEXT], c)) {
328 0 : if (ISSET(lflag, ECHO)) {
329 0 : if (ISSET(lflag, ECHOE)) {
330 0 : (void)ttyoutput('^', tp);
331 0 : (void)ttyoutput('\b', tp);
332 0 : } else
333 0 : ttyecho(c, tp);
334 : }
335 0 : SET(tp->t_state, TS_LNCH);
336 0 : goto endcase;
337 : }
338 0 : if (CCEQ(cc[VDISCARD], c)) {
339 0 : if (ISSET(lflag, FLUSHO))
340 0 : CLR(tp->t_lflag, FLUSHO);
341 : else {
342 0 : ttyflush(tp, FWRITE);
343 0 : ttyecho(c, tp);
344 0 : if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
345 0 : ttyretype(tp);
346 0 : SET(tp->t_lflag, FLUSHO);
347 : }
348 : goto startoutput;
349 : }
350 : }
351 : /*
352 : * Signals.
353 : */
354 0 : if (ISSET(lflag, ISIG)) {
355 0 : if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) {
356 0 : if (!ISSET(lflag, NOFLSH))
357 0 : ttyflush(tp, FREAD | FWRITE);
358 0 : ttyecho(c, tp);
359 0 : pgsignal(tp->t_pgrp,
360 0 : CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1);
361 0 : goto endcase;
362 : }
363 0 : if (CCEQ(cc[VSUSP], c)) {
364 0 : if (!ISSET(lflag, NOFLSH))
365 0 : ttyflush(tp, FREAD);
366 0 : ttyecho(c, tp);
367 0 : pgsignal(tp->t_pgrp, SIGTSTP, 1);
368 0 : goto endcase;
369 : }
370 : }
371 : /*
372 : * Handle start/stop characters.
373 : */
374 0 : if (ISSET(iflag, IXON)) {
375 0 : if (CCEQ(cc[VSTOP], c)) {
376 0 : if (!ISSET(tp->t_state, TS_TTSTOP)) {
377 0 : SET(tp->t_state, TS_TTSTOP);
378 0 : (*cdevsw[major(tp->t_dev)].d_stop)(tp,
379 : 0);
380 0 : return (0);
381 : }
382 0 : if (!CCEQ(cc[VSTART], c))
383 0 : return (0);
384 : /*
385 : * if VSTART == VSTOP then toggle
386 : */
387 : goto endcase;
388 : }
389 0 : if (CCEQ(cc[VSTART], c))
390 : goto restartoutput;
391 : }
392 : /*
393 : * IGNCR, ICRNL, & INLCR
394 : */
395 0 : if (c == '\r') {
396 0 : if (ISSET(iflag, IGNCR))
397 : goto endcase;
398 0 : else if (ISSET(iflag, ICRNL))
399 0 : c = '\n';
400 0 : } else if (c == '\n' && ISSET(iflag, INLCR))
401 0 : c = '\r';
402 : }
403 0 : if (!ISSET(tp->t_lflag, EXTPROC) && ISSET(lflag, ICANON)) {
404 : /*
405 : * From here on down canonical mode character
406 : * processing takes place.
407 : */
408 : /*
409 : * upper case or specials with IUCLC and XCASE
410 : */
411 0 : if (ISSET(lflag, XCASE) && ISSET(iflag, IUCLC)) {
412 0 : if (ISSET(tp->t_state, TS_BKSL)) {
413 0 : CLR(tp->t_state, TS_BKSL);
414 0 : switch (c) {
415 : case '\'':
416 : c = '`';
417 0 : break;
418 : case '!':
419 : c = '|';
420 0 : break;
421 : case '^':
422 : c = '~';
423 0 : break;
424 : case '(':
425 : c = '{';
426 0 : break;
427 : case ')':
428 : c = '}';
429 0 : break;
430 : }
431 : }
432 0 : else if (c == '\\') {
433 0 : SET(tp->t_state, TS_BKSL);
434 0 : goto endcase;
435 : }
436 0 : else if (isupper(c))
437 0 : c = tolower(c);
438 : }
439 0 : else if (ISSET(iflag, IUCLC) && isupper(c))
440 0 : c = tolower(c);
441 : /*
442 : * erase (^H / ^?)
443 : */
444 0 : if (CCEQ(cc[VERASE], c)) {
445 0 : if (tp->t_rawq.c_cc)
446 0 : ttyrub(unputc(&tp->t_rawq), tp);
447 : goto endcase;
448 : }
449 : /*
450 : * kill (^U)
451 : */
452 0 : if (CCEQ(cc[VKILL], c)) {
453 0 : if (ISSET(lflag, ECHOKE) &&
454 0 : tp->t_rawq.c_cc == tp->t_rocount &&
455 0 : !ISSET(lflag, ECHOPRT))
456 0 : while (tp->t_rawq.c_cc)
457 0 : ttyrub(unputc(&tp->t_rawq), tp);
458 : else {
459 0 : ttyecho(c, tp);
460 0 : if (ISSET(lflag, ECHOK) ||
461 : ISSET(lflag, ECHOKE))
462 0 : ttyecho('\n', tp);
463 0 : FLUSHQ(&tp->t_rawq);
464 0 : tp->t_rocount = 0;
465 : }
466 0 : CLR(tp->t_state, TS_LOCAL);
467 0 : goto endcase;
468 : }
469 : /*
470 : * word erase (^W)
471 : */
472 0 : if (CCEQ(cc[VWERASE], c) && ISSET(lflag, IEXTEN)) {
473 0 : int alt = ISSET(lflag, ALTWERASE);
474 : int ctype;
475 :
476 : /*
477 : * erase whitespace
478 : */
479 0 : while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t')
480 0 : ttyrub(c, tp);
481 0 : if (c == -1)
482 0 : goto endcase;
483 : /*
484 : * erase last char of word and remember the
485 : * next chars type (for ALTWERASE)
486 : */
487 0 : ttyrub(c, tp);
488 0 : c = unputc(&tp->t_rawq);
489 0 : if (c == -1)
490 0 : goto endcase;
491 0 : if (c == ' ' || c == '\t') {
492 0 : (void)putc(c, &tp->t_rawq);
493 0 : goto endcase;
494 : }
495 0 : ctype = ISALPHA(c);
496 : /*
497 : * erase rest of word
498 : */
499 0 : do {
500 0 : ttyrub(c, tp);
501 0 : c = unputc(&tp->t_rawq);
502 0 : if (c == -1)
503 0 : goto endcase;
504 0 : } while (c != ' ' && c != '\t' &&
505 0 : (alt == 0 || ISALPHA(c) == ctype));
506 0 : (void)putc(c, &tp->t_rawq);
507 0 : goto endcase;
508 : }
509 : /*
510 : * reprint line (^R)
511 : */
512 0 : if (CCEQ(cc[VREPRINT], c) && ISSET(lflag, IEXTEN)) {
513 0 : ttyretype(tp);
514 0 : goto endcase;
515 : }
516 : /*
517 : * ^T - kernel info and generate SIGINFO
518 : */
519 0 : if (CCEQ(cc[VSTATUS], c) && ISSET(lflag, IEXTEN)) {
520 0 : if (ISSET(lflag, ISIG))
521 0 : pgsignal(tp->t_pgrp, SIGINFO, 1);
522 0 : if (!ISSET(lflag, NOKERNINFO))
523 0 : ttyinfo(tp);
524 : goto endcase;
525 : }
526 : }
527 : /*
528 : * Check for input buffer overflow
529 : */
530 0 : if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= TTYHOG(tp)) {
531 0 : if (ISSET(iflag, IMAXBEL)) {
532 0 : if (tp->t_outq.c_cc < tp->t_hiwat)
533 0 : (void)ttyoutput(CTRL('g'), tp);
534 : } else
535 0 : ttyflush(tp, FREAD | FWRITE);
536 : goto endcase;
537 : }
538 : /*
539 : * Put data char in q for user and
540 : * wakeup on seeing a line delimiter.
541 : */
542 0 : if (putc(c, &tp->t_rawq) >= 0) {
543 0 : if (!ISSET(lflag, ICANON)) {
544 0 : ttwakeup(tp);
545 0 : ttyecho(c, tp);
546 0 : goto endcase;
547 : }
548 0 : if (TTBREAKC(c, lflag)) {
549 0 : tp->t_rocount = 0;
550 0 : catq(&tp->t_rawq, &tp->t_canq);
551 0 : ttwakeup(tp);
552 0 : } else if (tp->t_rocount++ == 0)
553 0 : tp->t_rocol = tp->t_column;
554 0 : if (ISSET(tp->t_state, TS_ERASE)) {
555 : /*
556 : * end of prterase \.../
557 : */
558 0 : CLR(tp->t_state, TS_ERASE);
559 0 : (void)ttyoutput('/', tp);
560 0 : }
561 0 : i = tp->t_column;
562 0 : ttyecho(c, tp);
563 0 : if (CCEQ(cc[VEOF], c) && ISSET(lflag, ECHO)) {
564 : /*
565 : * Place the cursor over the '^' of the ^D.
566 : */
567 0 : i = min(2, tp->t_column - i);
568 0 : while (i > 0) {
569 0 : (void)ttyoutput('\b', tp);
570 0 : i--;
571 : }
572 : }
573 : }
574 : endcase:
575 : /*
576 : * IXANY means allow any character to restart output.
577 : */
578 0 : if (ISSET(tp->t_state, TS_TTSTOP) &&
579 0 : !ISSET(iflag, IXANY) && cc[VSTART] != cc[VSTOP])
580 0 : return (0);
581 : restartoutput:
582 0 : CLR(tp->t_lflag, FLUSHO);
583 0 : CLR(tp->t_state, TS_TTSTOP);
584 : startoutput:
585 0 : return (ttstart(tp));
586 0 : }
587 :
588 : /*
589 : * Output a single character on a tty, doing output processing
590 : * as needed (expanding tabs, newline processing, etc.).
591 : * Returns < 0 if succeeds, otherwise returns char to resend.
592 : * Must be recursive.
593 : */
594 : int
595 0 : ttyoutput(int c, struct tty *tp)
596 : {
597 : long oflag;
598 : int col, notout, s, c2;
599 :
600 0 : oflag = tp->t_oflag;
601 0 : if (!ISSET(oflag, OPOST)) {
602 0 : tk_nout++;
603 0 : tp->t_outcc++;
604 0 : if (!ISSET(tp->t_lflag, FLUSHO) && putc(c, &tp->t_outq))
605 0 : return (c);
606 0 : return (-1);
607 : }
608 : /*
609 : * Do tab expansion if OXTABS is set. Special case if we external
610 : * processing, we don't do the tab expansion because we'll probably
611 : * get it wrong. If tab expansion needs to be done, let it happen
612 : * externally.
613 : */
614 0 : CLR(c, ~TTY_CHARMASK);
615 0 : if (c == '\t' &&
616 0 : ISSET(oflag, OXTABS) && !ISSET(tp->t_lflag, EXTPROC)) {
617 0 : c = 8 - (tp->t_column & 7);
618 0 : if (ISSET(tp->t_lflag, FLUSHO)) {
619 : notout = 0;
620 0 : } else {
621 0 : s = spltty(); /* Don't interrupt tabs. */
622 0 : notout = b_to_q(" ", c, &tp->t_outq);
623 0 : c -= notout;
624 0 : tk_nout += c;
625 0 : tp->t_outcc += c;
626 0 : splx(s);
627 : }
628 0 : tp->t_column += c;
629 0 : return (notout ? '\t' : -1);
630 : }
631 0 : if (c == CEOT && ISSET(oflag, ONOEOT))
632 0 : return (-1);
633 :
634 : /*
635 : * Newline translation: if ONLCR is set,
636 : * translate newline into "\r\n". If OCRNL
637 : * is set, translate '\r' into '\n'.
638 : */
639 0 : if (c == '\n' && ISSET(tp->t_oflag, ONLCR)) {
640 0 : tk_nout++;
641 0 : tp->t_outcc++;
642 0 : if (!ISSET(tp->t_lflag, FLUSHO) && putc('\r', &tp->t_outq))
643 0 : return (c);
644 0 : tp->t_column = 0;
645 0 : }
646 0 : else if (c == '\r' && ISSET(tp->t_oflag, OCRNL))
647 0 : c = '\n';
648 :
649 0 : if (ISSET(tp->t_oflag, OLCUC) && islower(c))
650 0 : c = toupper(c);
651 0 : else if (ISSET(tp->t_oflag, OLCUC) && ISSET(tp->t_lflag, XCASE)) {
652 : c2 = c;
653 0 : switch (c) {
654 : case '`':
655 : c2 = '\'';
656 0 : break;
657 : case '|':
658 : c2 = '!';
659 0 : break;
660 : case '~':
661 : c2 = '^';
662 0 : break;
663 : case '{':
664 : c2 = '(';
665 0 : break;
666 : case '}':
667 : c2 = ')';
668 0 : break;
669 : }
670 0 : if (c == '\\' || isupper(c) || c != c2) {
671 0 : tk_nout++;
672 0 : tp->t_outcc++;
673 0 : if (putc('\\', &tp->t_outq))
674 0 : return (c);
675 : c = c2;
676 0 : }
677 : }
678 0 : if (ISSET(tp->t_oflag, ONOCR) && c == '\r' && tp->t_column == 0)
679 0 : return (-1);
680 :
681 0 : tk_nout++;
682 0 : tp->t_outcc++;
683 0 : if (!ISSET(tp->t_lflag, FLUSHO) && putc(c, &tp->t_outq))
684 0 : return (c);
685 :
686 0 : col = tp->t_column;
687 0 : switch (CCLASS(c)) {
688 : case BACKSPACE:
689 0 : if (col > 0)
690 0 : --col;
691 : break;
692 : case CONTROL:
693 : break;
694 : case NEWLINE:
695 0 : if (ISSET(tp->t_oflag, ONLRET) || ISSET(tp->t_oflag, OCRNL))
696 0 : col = 0;
697 : break;
698 : case RETURN:
699 : col = 0;
700 0 : break;
701 : case ORDINARY:
702 0 : ++col;
703 0 : break;
704 : case TAB:
705 0 : col = (col + 8) & ~7;
706 0 : break;
707 : }
708 0 : tp->t_column = col;
709 0 : return (-1);
710 0 : }
711 :
712 : /*
713 : * Ioctls for all tty devices. Called after line-discipline specific ioctl
714 : * has been called to do discipline-specific functions and/or reject any
715 : * of these ioctl commands.
716 : */
717 : int
718 0 : ttioctl(struct tty *tp, u_long cmd, caddr_t data, int flag, struct proc *p)
719 : {
720 : extern int nlinesw;
721 0 : struct process *pr = p->p_p;
722 : int s, error;
723 :
724 : /* If the ioctl involves modification, hang if in the background. */
725 0 : switch (cmd) {
726 : case TIOCFLUSH:
727 : case TIOCDRAIN:
728 : case TIOCSBRK:
729 : case TIOCCBRK:
730 : case TIOCSETA:
731 : case TIOCSETD:
732 : case TIOCSETAF:
733 : case TIOCSETAW:
734 : case TIOCSPGRP:
735 : case TIOCSTAT:
736 : case TIOCSWINSZ:
737 0 : while (isbackground(pr, tp) &&
738 0 : (pr->ps_flags & PS_PPWAIT) == 0 &&
739 0 : (pr->ps_sigacts->ps_sigignore & sigmask(SIGTTOU)) == 0 &&
740 0 : (p->p_sigmask & sigmask(SIGTTOU)) == 0) {
741 0 : if (pr->ps_pgrp->pg_jobc == 0)
742 0 : return (EIO);
743 0 : pgsignal(pr->ps_pgrp, SIGTTOU, 1);
744 0 : error = ttysleep(tp, &lbolt, TTOPRI | PCATCH,
745 : ttybg, 0);
746 0 : if (error)
747 0 : return (error);
748 : }
749 : break;
750 : }
751 :
752 0 : switch (cmd) { /* Process the ioctl. */
753 : case FIOASYNC: /* set/clear async i/o */
754 0 : s = spltty();
755 0 : if (*(int *)data)
756 0 : SET(tp->t_state, TS_ASYNC);
757 : else
758 0 : CLR(tp->t_state, TS_ASYNC);
759 0 : splx(s);
760 0 : break;
761 : case FIONBIO: /* set/clear non-blocking i/o */
762 : break; /* XXX: delete. */
763 : case FIONREAD: /* get # bytes to read */
764 0 : s = spltty();
765 0 : *(int *)data = ttnread(tp);
766 0 : splx(s);
767 0 : break;
768 : case TIOCEXCL: /* set exclusive use of tty */
769 0 : s = spltty();
770 0 : SET(tp->t_state, TS_XCLUDE);
771 0 : splx(s);
772 0 : break;
773 : case TIOCFLUSH: { /* flush buffers */
774 0 : int flags = *(int *)data;
775 :
776 0 : if (flags == 0)
777 0 : flags = FREAD | FWRITE;
778 : else
779 0 : flags &= FREAD | FWRITE;
780 0 : ttyflush(tp, flags);
781 : break;
782 : }
783 : case TIOCCONS: { /* become virtual console */
784 0 : if (*(int *)data) {
785 0 : struct nameidata nid;
786 :
787 0 : if (constty != NULL && constty != tp &&
788 0 : ISSET(constty->t_state, TS_CARR_ON | TS_ISOPEN) ==
789 : (TS_CARR_ON | TS_ISOPEN))
790 0 : return (EBUSY);
791 :
792 : /* ensure user can open the real console */
793 0 : NDINIT(&nid, LOOKUP, FOLLOW, UIO_SYSSPACE, "/dev/console", p);
794 0 : nid.ni_pledge = PLEDGE_RPATH | PLEDGE_WPATH;
795 0 : nid.ni_unveil = UNVEIL_READ | UNVEIL_WRITE;
796 0 : error = namei(&nid);
797 0 : if (error)
798 0 : return (error);
799 0 : vn_lock(nid.ni_vp, LK_EXCLUSIVE | LK_RETRY);
800 0 : error = VOP_ACCESS(nid.ni_vp, VREAD, p->p_ucred, p);
801 0 : VOP_UNLOCK(nid.ni_vp);
802 0 : vrele(nid.ni_vp);
803 0 : if (error)
804 0 : return (error);
805 :
806 0 : constty = tp;
807 0 : } else if (tp == constty)
808 0 : constty = NULL;
809 : break;
810 : }
811 : case TIOCDRAIN: /* wait till output drained */
812 0 : if ((error = ttywait(tp)) != 0)
813 0 : return (error);
814 : break;
815 : case TIOCGETA: { /* get termios struct */
816 0 : struct termios *t = (struct termios *)data;
817 :
818 0 : memcpy(t, &tp->t_termios, sizeof(struct termios));
819 : break;
820 : }
821 : case TIOCGETD: /* get line discipline */
822 0 : *(int *)data = tp->t_line;
823 0 : break;
824 : case TIOCGWINSZ: /* get window size */
825 0 : *(struct winsize *)data = tp->t_winsize;
826 0 : break;
827 : case TIOCGTSTAMP:
828 0 : s = spltty();
829 0 : *(struct timeval *)data = tp->t_tv;
830 0 : splx(s);
831 0 : break;
832 : case TIOCGPGRP: /* get pgrp of tty */
833 0 : if (!isctty(pr, tp) && suser(p))
834 0 : return (ENOTTY);
835 0 : *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
836 0 : break;
837 : case TIOCGSID: /* get sid of tty */
838 0 : if (!isctty(pr, tp))
839 0 : return (ENOTTY);
840 0 : *(int *)data = tp->t_session->s_leader->ps_pid;
841 0 : break;
842 : #ifdef TIOCHPCL
843 : case TIOCHPCL: /* hang up on last close */
844 : s = spltty();
845 : SET(tp->t_cflag, HUPCL);
846 : splx(s);
847 : break;
848 : #endif
849 : case TIOCNXCL: /* reset exclusive use of tty */
850 0 : s = spltty();
851 0 : CLR(tp->t_state, TS_XCLUDE);
852 0 : splx(s);
853 0 : break;
854 : case TIOCOUTQ: /* output queue size */
855 0 : *(int *)data = tp->t_outq.c_cc;
856 0 : break;
857 : case TIOCSETA: /* set termios struct */
858 : case TIOCSETAW: /* drain output, set */
859 : case TIOCSETAF: { /* drn out, fls in, set */
860 0 : struct termios *t = (struct termios *)data;
861 :
862 0 : s = spltty();
863 0 : if (cmd == TIOCSETAW || cmd == TIOCSETAF) {
864 0 : if ((error = ttywait(tp)) != 0) {
865 0 : splx(s);
866 0 : return (error);
867 : }
868 0 : if (cmd == TIOCSETAF)
869 0 : ttyflush(tp, FREAD);
870 : }
871 0 : if (!ISSET(t->c_cflag, CIGNORE)) {
872 : /*
873 : * Some minor validation is necessary.
874 : */
875 0 : if (t->c_ispeed < 0 || t->c_ospeed < 0) {
876 0 : splx(s);
877 0 : return (EINVAL);
878 : }
879 : /*
880 : * Set device hardware.
881 : */
882 0 : if (tp->t_param && (error = (*tp->t_param)(tp, t))) {
883 0 : splx(s);
884 0 : return (error);
885 : } else {
886 0 : if (!ISSET(tp->t_state, TS_CARR_ON) &&
887 0 : ISSET(tp->t_cflag, CLOCAL) &&
888 0 : !ISSET(t->c_cflag, CLOCAL)) {
889 0 : CLR(tp->t_state, TS_ISOPEN);
890 0 : SET(tp->t_state, TS_WOPEN);
891 0 : ttwakeup(tp);
892 0 : }
893 0 : tp->t_cflag = t->c_cflag;
894 0 : tp->t_ispeed = t->c_ispeed;
895 0 : tp->t_ospeed = t->c_ospeed;
896 0 : if (t->c_ospeed == 0 && tp->t_session &&
897 0 : tp->t_session->s_leader)
898 0 : prsignal(tp->t_session->s_leader,
899 : SIGHUP);
900 : }
901 0 : ttsetwater(tp);
902 0 : }
903 0 : if (cmd != TIOCSETAF) {
904 0 : if (ISSET(t->c_lflag, ICANON) !=
905 0 : ISSET(tp->t_lflag, ICANON)) {
906 0 : if (ISSET(t->c_lflag, ICANON)) {
907 0 : SET(tp->t_lflag, PENDIN);
908 0 : ttwakeup(tp);
909 0 : } else {
910 0 : struct clist tq;
911 :
912 0 : catq(&tp->t_rawq, &tp->t_canq);
913 0 : tq = tp->t_rawq;
914 0 : tp->t_rawq = tp->t_canq;
915 0 : tp->t_canq = tq;
916 0 : CLR(tp->t_lflag, PENDIN);
917 0 : }
918 : }
919 : }
920 0 : tp->t_iflag = t->c_iflag;
921 0 : tp->t_oflag = t->c_oflag;
922 : /*
923 : * Make the EXTPROC bit read only.
924 : */
925 0 : if (ISSET(tp->t_lflag, EXTPROC))
926 0 : SET(t->c_lflag, EXTPROC);
927 : else
928 0 : CLR(t->c_lflag, EXTPROC);
929 0 : tp->t_lflag = t->c_lflag | ISSET(tp->t_lflag, PENDIN);
930 0 : memcpy(tp->t_cc, t->c_cc, sizeof(t->c_cc));
931 0 : splx(s);
932 0 : break;
933 : }
934 : case TIOCSETD: { /* set line discipline */
935 0 : int t = *(int *)data;
936 0 : dev_t device = tp->t_dev;
937 :
938 0 : if ((u_int)t >= nlinesw)
939 0 : return (ENXIO);
940 0 : if (t != tp->t_line) {
941 0 : s = spltty();
942 0 : (*linesw[tp->t_line].l_close)(tp, flag, p);
943 0 : error = (*linesw[t].l_open)(device, tp, p);
944 0 : if (error) {
945 0 : (*linesw[tp->t_line].l_open)(device, tp, p);
946 0 : splx(s);
947 0 : return (error);
948 : }
949 0 : tp->t_line = t;
950 0 : splx(s);
951 0 : }
952 0 : break;
953 : }
954 : case TIOCSTART: /* start output, like ^Q */
955 0 : s = spltty();
956 0 : if (ISSET(tp->t_state, TS_TTSTOP) ||
957 0 : ISSET(tp->t_lflag, FLUSHO)) {
958 0 : CLR(tp->t_lflag, FLUSHO);
959 0 : CLR(tp->t_state, TS_TTSTOP);
960 0 : ttstart(tp);
961 0 : }
962 0 : splx(s);
963 0 : break;
964 : case TIOCSTOP: /* stop output, like ^S */
965 0 : s = spltty();
966 0 : if (!ISSET(tp->t_state, TS_TTSTOP)) {
967 0 : SET(tp->t_state, TS_TTSTOP);
968 0 : (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
969 0 : }
970 0 : splx(s);
971 0 : break;
972 : case TIOCSCTTY: /* become controlling tty */
973 : /* Session ctty vnode pointer set in vnode layer. */
974 0 : if (!SESS_LEADER(pr) ||
975 0 : ((pr->ps_session->s_ttyvp || tp->t_session) &&
976 0 : (tp->t_session != pr->ps_session)))
977 0 : return (EPERM);
978 0 : if (tp->t_session)
979 0 : SESSRELE(tp->t_session);
980 0 : SESSHOLD(pr->ps_session);
981 0 : tp->t_session = pr->ps_session;
982 0 : tp->t_pgrp = pr->ps_pgrp;
983 0 : pr->ps_session->s_ttyp = tp;
984 0 : atomic_setbits_int(&pr->ps_flags, PS_CONTROLT);
985 0 : break;
986 : case TIOCSPGRP: { /* set pgrp of tty */
987 0 : struct pgrp *pgrp = pgfind(*(int *)data);
988 :
989 0 : if (!isctty(pr, tp))
990 0 : return (ENOTTY);
991 0 : else if (pgrp == NULL)
992 0 : return (EINVAL);
993 0 : else if (pgrp->pg_session != pr->ps_session)
994 0 : return (EPERM);
995 0 : tp->t_pgrp = pgrp;
996 0 : break;
997 : }
998 : case TIOCSTAT: /* get load avg stats */
999 0 : ttyinfo(tp);
1000 0 : break;
1001 : case TIOCSWINSZ: /* set window size */
1002 0 : if (bcmp((caddr_t)&tp->t_winsize, data,
1003 : sizeof (struct winsize))) {
1004 0 : tp->t_winsize = *(struct winsize *)data;
1005 0 : pgsignal(tp->t_pgrp, SIGWINCH, 1);
1006 0 : }
1007 : break;
1008 : case TIOCSTSTAMP: {
1009 0 : struct tstamps *ts = (struct tstamps *)data;
1010 :
1011 0 : s = spltty();
1012 0 : CLR(tp->t_flags, TS_TSTAMPDCDSET);
1013 0 : CLR(tp->t_flags, TS_TSTAMPCTSSET);
1014 0 : CLR(tp->t_flags, TS_TSTAMPDCDCLR);
1015 0 : CLR(tp->t_flags, TS_TSTAMPCTSCLR);
1016 0 : if (ISSET(ts->ts_set, TIOCM_CAR))
1017 0 : SET(tp->t_flags, TS_TSTAMPDCDSET);
1018 0 : if (ISSET(ts->ts_set, TIOCM_CTS))
1019 0 : SET(tp->t_flags, TS_TSTAMPCTSSET);
1020 0 : if (ISSET(ts->ts_clr, TIOCM_CAR))
1021 0 : SET(tp->t_flags, TS_TSTAMPDCDCLR);
1022 0 : if (ISSET(ts->ts_clr, TIOCM_CTS))
1023 0 : SET(tp->t_flags, TS_TSTAMPCTSCLR);
1024 0 : splx(s);
1025 : break;
1026 : }
1027 : default:
1028 0 : return (-1);
1029 : }
1030 0 : return (0);
1031 0 : }
1032 :
1033 : int
1034 0 : ttpoll(dev_t device, int events, struct proc *p)
1035 : {
1036 : struct tty *tp;
1037 : int revents, s;
1038 :
1039 0 : tp = (*cdevsw[major(device)].d_tty)(device);
1040 :
1041 : revents = 0;
1042 0 : s = spltty();
1043 0 : if (events & (POLLIN | POLLRDNORM)) {
1044 0 : if (ttnread(tp) > 0 || (!ISSET(tp->t_cflag, CLOCAL) &&
1045 0 : !ISSET(tp->t_state, TS_CARR_ON)))
1046 0 : revents |= events & (POLLIN | POLLRDNORM);
1047 : }
1048 : /* NOTE: POLLHUP and POLLOUT/POLLWRNORM are mutually exclusive */
1049 0 : if (!ISSET(tp->t_cflag, CLOCAL) && !ISSET(tp->t_state, TS_CARR_ON)) {
1050 0 : revents |= POLLHUP;
1051 0 : } else if (events & (POLLOUT | POLLWRNORM)) {
1052 0 : if (tp->t_outq.c_cc <= tp->t_lowat)
1053 0 : revents |= events & (POLLOUT | POLLWRNORM);
1054 : }
1055 0 : if (revents == 0) {
1056 0 : if (events & (POLLIN | POLLRDNORM))
1057 0 : selrecord(p, &tp->t_rsel);
1058 0 : if (events & (POLLOUT | POLLWRNORM))
1059 0 : selrecord(p, &tp->t_wsel);
1060 : }
1061 0 : splx(s);
1062 0 : return (revents);
1063 : }
1064 :
1065 : struct filterops ttyread_filtops =
1066 : { 1, NULL, filt_ttyrdetach, filt_ttyread };
1067 : struct filterops ttywrite_filtops =
1068 : { 1, NULL, filt_ttywdetach, filt_ttywrite };
1069 :
1070 : int
1071 0 : ttkqfilter(dev_t dev, struct knote *kn)
1072 : {
1073 0 : struct tty *tp = (*cdevsw[major(dev)].d_tty)(dev);
1074 : struct klist *klist;
1075 : int s;
1076 :
1077 0 : switch (kn->kn_filter) {
1078 : case EVFILT_READ:
1079 0 : klist = &tp->t_rsel.si_note;
1080 0 : kn->kn_fop = &ttyread_filtops;
1081 0 : break;
1082 : case EVFILT_WRITE:
1083 0 : klist = &tp->t_wsel.si_note;
1084 0 : kn->kn_fop = &ttywrite_filtops;
1085 0 : break;
1086 : default:
1087 0 : return (EINVAL);
1088 : }
1089 :
1090 0 : kn->kn_hook = (caddr_t)((u_long)dev);
1091 :
1092 0 : s = spltty();
1093 0 : SLIST_INSERT_HEAD(klist, kn, kn_selnext);
1094 0 : splx(s);
1095 :
1096 0 : return (0);
1097 0 : }
1098 :
1099 : void
1100 0 : ttkqflush(struct klist *klist)
1101 : {
1102 : struct knote *kn, *kn1;
1103 :
1104 0 : SLIST_FOREACH_SAFE(kn, klist, kn_selnext, kn1) {
1105 0 : SLIST_REMOVE(klist, kn, knote, kn_selnext);
1106 0 : kn->kn_hook = (caddr_t)((u_long)NODEV);
1107 0 : kn->kn_flags |= EV_EOF;
1108 0 : knote_activate(kn);
1109 : }
1110 0 : }
1111 :
1112 : void
1113 0 : filt_ttyrdetach(struct knote *kn)
1114 : {
1115 0 : dev_t dev = (dev_t)((u_long)kn->kn_hook);
1116 : struct tty *tp;
1117 : int s;
1118 :
1119 0 : if (dev == NODEV)
1120 0 : return;
1121 0 : tp = (*cdevsw[major(dev)].d_tty)(dev);
1122 :
1123 0 : s = spltty();
1124 0 : SLIST_REMOVE(&tp->t_rsel.si_note, kn, knote, kn_selnext);
1125 0 : splx(s);
1126 0 : }
1127 :
1128 : int
1129 0 : filt_ttyread(struct knote *kn, long hint)
1130 : {
1131 0 : dev_t dev = (dev_t)((u_long)kn->kn_hook);
1132 : struct tty *tp;
1133 : int s;
1134 :
1135 0 : if (dev == NODEV) {
1136 0 : kn->kn_flags |= EV_EOF;
1137 0 : return (1);
1138 : }
1139 0 : tp = (*cdevsw[major(dev)].d_tty)(dev);
1140 :
1141 0 : s = spltty();
1142 0 : kn->kn_data = ttnread(tp);
1143 0 : splx(s);
1144 0 : if (!ISSET(tp->t_cflag, CLOCAL) && !ISSET(tp->t_state, TS_CARR_ON)) {
1145 0 : kn->kn_flags |= EV_EOF;
1146 0 : return (1);
1147 : }
1148 0 : return (kn->kn_data > 0);
1149 0 : }
1150 :
1151 : void
1152 0 : filt_ttywdetach(struct knote *kn)
1153 : {
1154 0 : dev_t dev = (dev_t)((u_long)kn->kn_hook);
1155 : struct tty *tp;
1156 : int s;
1157 :
1158 0 : if (dev == NODEV)
1159 0 : return;
1160 0 : tp = (*cdevsw[major(dev)].d_tty)(dev);
1161 :
1162 0 : s = spltty();
1163 0 : SLIST_REMOVE(&tp->t_wsel.si_note, kn, knote, kn_selnext);
1164 0 : splx(s);
1165 0 : }
1166 :
1167 : int
1168 0 : filt_ttywrite(struct knote *kn, long hint)
1169 : {
1170 0 : dev_t dev = (dev_t)((u_long)kn->kn_hook);
1171 : struct tty *tp;
1172 : int canwrite, s;
1173 :
1174 0 : if (dev == NODEV) {
1175 0 : kn->kn_flags |= EV_EOF;
1176 0 : return (1);
1177 : }
1178 0 : tp = (*cdevsw[major(dev)].d_tty)(dev);
1179 :
1180 0 : s = spltty();
1181 0 : kn->kn_data = tp->t_outq.c_cn - tp->t_outq.c_cc;
1182 0 : canwrite = (tp->t_outq.c_cc <= tp->t_lowat);
1183 0 : splx(s);
1184 0 : return (canwrite);
1185 0 : }
1186 :
1187 : static int
1188 0 : ttnread(struct tty *tp)
1189 : {
1190 : int nread;
1191 :
1192 0 : splassert(IPL_TTY);
1193 :
1194 0 : if (ISSET(tp->t_lflag, PENDIN))
1195 0 : ttypend(tp);
1196 0 : nread = tp->t_canq.c_cc;
1197 0 : if (!ISSET(tp->t_lflag, ICANON)) {
1198 0 : nread += tp->t_rawq.c_cc;
1199 0 : if (nread < tp->t_cc[VMIN] && !tp->t_cc[VTIME])
1200 0 : nread = 0;
1201 : }
1202 0 : return (nread);
1203 : }
1204 :
1205 : /*
1206 : * Wait for output to drain.
1207 : */
1208 : int
1209 0 : ttywait(struct tty *tp)
1210 : {
1211 : int error, s;
1212 :
1213 : error = 0;
1214 0 : s = spltty();
1215 0 : while ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) &&
1216 0 : (ISSET(tp->t_state, TS_CARR_ON) || ISSET(tp->t_cflag, CLOCAL)) &&
1217 0 : tp->t_oproc) {
1218 0 : (*tp->t_oproc)(tp);
1219 0 : if ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) &&
1220 0 : (ISSET(tp->t_state, TS_CARR_ON) || ISSET(tp->t_cflag, CLOCAL))
1221 0 : && tp->t_oproc) {
1222 0 : SET(tp->t_state, TS_ASLEEP);
1223 0 : error = ttysleep(tp, &tp->t_outq, TTOPRI | PCATCH, ttyout, 0);
1224 0 : if (error)
1225 : break;
1226 : } else
1227 : break;
1228 : }
1229 0 : splx(s);
1230 0 : return (error);
1231 : }
1232 :
1233 : /*
1234 : * Flush if successfully wait.
1235 : */
1236 : int
1237 0 : ttywflush(struct tty *tp)
1238 : {
1239 : int error;
1240 :
1241 0 : if ((error = ttywait(tp)) == 0)
1242 0 : ttyflush(tp, FREAD);
1243 0 : return (error);
1244 : }
1245 :
1246 : /*
1247 : * Flush tty read and/or write queues, notifying anyone waiting.
1248 : */
1249 : void
1250 0 : ttyflush(struct tty *tp, int rw)
1251 : {
1252 : int s;
1253 :
1254 0 : s = spltty();
1255 0 : if (rw & FREAD) {
1256 0 : FLUSHQ(&tp->t_canq);
1257 0 : FLUSHQ(&tp->t_rawq);
1258 0 : tp->t_rocount = 0;
1259 0 : tp->t_rocol = 0;
1260 0 : CLR(tp->t_state, TS_LOCAL);
1261 0 : ttyunblock(tp);
1262 0 : ttwakeup(tp);
1263 0 : }
1264 0 : if (rw & FWRITE) {
1265 0 : CLR(tp->t_state, TS_TTSTOP);
1266 0 : (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
1267 0 : FLUSHQ(&tp->t_outq);
1268 0 : wakeup((caddr_t)&tp->t_outq);
1269 0 : selwakeup(&tp->t_wsel);
1270 0 : }
1271 0 : splx(s);
1272 0 : }
1273 :
1274 : /*
1275 : * Copy in the default termios characters.
1276 : */
1277 : void
1278 0 : ttychars(struct tty *tp)
1279 : {
1280 :
1281 0 : memcpy(tp->t_cc, ttydefchars, sizeof(ttydefchars));
1282 0 : }
1283 :
1284 : /*
1285 : * Send stop character on input overflow.
1286 : */
1287 : static void
1288 0 : ttyblock(struct tty *tp)
1289 : {
1290 : int total;
1291 :
1292 0 : total = tp->t_rawq.c_cc + tp->t_canq.c_cc;
1293 0 : if (tp->t_rawq.c_cc > TTYHOG(tp)) {
1294 0 : ttyflush(tp, FREAD | FWRITE);
1295 0 : CLR(tp->t_state, TS_TBLOCK);
1296 0 : }
1297 : /*
1298 : * Block further input iff: current input > threshold
1299 : * AND input is available to user program.
1300 : */
1301 0 : if ((total >= TTYHOG(tp) / 2 &&
1302 0 : !ISSET(tp->t_state, TS_TBLOCK) &&
1303 0 : !ISSET(tp->t_lflag, ICANON)) || tp->t_canq.c_cc > 0) {
1304 0 : if (ISSET(tp->t_iflag, IXOFF) &&
1305 0 : tp->t_cc[VSTOP] != _POSIX_VDISABLE &&
1306 0 : putc(tp->t_cc[VSTOP], &tp->t_outq) == 0) {
1307 0 : SET(tp->t_state, TS_TBLOCK);
1308 0 : ttstart(tp);
1309 0 : }
1310 : /* Try to block remote output via hardware flow control. */
1311 0 : if (ISSET(tp->t_cflag, CHWFLOW) && tp->t_hwiflow &&
1312 0 : (*tp->t_hwiflow)(tp, 1) != 0)
1313 0 : SET(tp->t_state, TS_TBLOCK);
1314 : }
1315 0 : }
1316 :
1317 : void
1318 0 : ttrstrt(void *tp_arg)
1319 : {
1320 : struct tty *tp;
1321 : int s;
1322 :
1323 : #ifdef DIAGNOSTIC
1324 0 : if (tp_arg == NULL)
1325 0 : panic("ttrstrt");
1326 : #endif
1327 0 : tp = tp_arg;
1328 0 : s = spltty();
1329 :
1330 0 : CLR(tp->t_state, TS_TIMEOUT);
1331 0 : ttstart(tp);
1332 :
1333 0 : splx(s);
1334 0 : }
1335 :
1336 : int
1337 0 : ttstart(struct tty *tp)
1338 : {
1339 :
1340 0 : if (tp->t_oproc != NULL) /* XXX: Kludge for pty. */
1341 0 : (*tp->t_oproc)(tp);
1342 0 : return (0);
1343 : }
1344 :
1345 : /*
1346 : * "close" a line discipline
1347 : */
1348 : int
1349 0 : ttylclose(struct tty *tp, int flag, struct proc *p)
1350 : {
1351 :
1352 0 : if (flag & FNONBLOCK)
1353 0 : ttyflush(tp, FREAD | FWRITE);
1354 : else
1355 0 : ttywflush(tp);
1356 0 : return (0);
1357 : }
1358 :
1359 : /*
1360 : * Handle modem control transition on a tty.
1361 : * Flag indicates new state of carrier.
1362 : * Returns 0 if the line should be turned off, otherwise 1.
1363 : */
1364 : int
1365 0 : ttymodem(struct tty *tp, int flag)
1366 : {
1367 :
1368 0 : if (!ISSET(tp->t_state, TS_WOPEN) && ISSET(tp->t_cflag, MDMBUF)) {
1369 : /*
1370 : * MDMBUF: do flow control according to carrier flag
1371 : */
1372 0 : if (flag) {
1373 0 : CLR(tp->t_state, TS_TTSTOP);
1374 0 : ttstart(tp);
1375 0 : } else if (!ISSET(tp->t_state, TS_TTSTOP)) {
1376 0 : SET(tp->t_state, TS_TTSTOP);
1377 0 : (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
1378 0 : }
1379 0 : } else if (flag == 0) {
1380 : /*
1381 : * Lost carrier.
1382 : */
1383 0 : CLR(tp->t_state, TS_CARR_ON);
1384 0 : if (ISSET(tp->t_state, TS_ISOPEN) &&
1385 0 : !ISSET(tp->t_cflag, CLOCAL)) {
1386 0 : if (tp->t_session && tp->t_session->s_leader)
1387 0 : prsignal(tp->t_session->s_leader, SIGHUP);
1388 0 : ttyflush(tp, FREAD | FWRITE);
1389 0 : return (0);
1390 : }
1391 : } else {
1392 : /*
1393 : * Carrier now on.
1394 : */
1395 0 : SET(tp->t_state, TS_CARR_ON);
1396 0 : ttwakeup(tp);
1397 : }
1398 0 : return (1);
1399 0 : }
1400 :
1401 : /*
1402 : * Default modem control routine (for other line disciplines).
1403 : * Return argument flag, to turn off device on carrier drop.
1404 : */
1405 : int
1406 0 : nullmodem(struct tty *tp, int flag)
1407 : {
1408 :
1409 0 : if (flag)
1410 0 : SET(tp->t_state, TS_CARR_ON);
1411 : else {
1412 0 : CLR(tp->t_state, TS_CARR_ON);
1413 0 : if (ISSET(tp->t_state, TS_ISOPEN) &&
1414 0 : !ISSET(tp->t_cflag, CLOCAL)) {
1415 0 : if (tp->t_session && tp->t_session->s_leader)
1416 0 : prsignal(tp->t_session->s_leader, SIGHUP);
1417 0 : ttyflush(tp, FREAD | FWRITE);
1418 0 : return (0);
1419 : }
1420 : }
1421 0 : return (1);
1422 0 : }
1423 :
1424 : /*
1425 : * Reinput pending characters after state switch
1426 : * call at spltty().
1427 : */
1428 : void
1429 0 : ttypend(struct tty *tp)
1430 : {
1431 0 : struct clist tq;
1432 : int c;
1433 :
1434 0 : splassert(IPL_TTY);
1435 :
1436 0 : CLR(tp->t_lflag, PENDIN);
1437 0 : SET(tp->t_state, TS_TYPEN);
1438 0 : tq = tp->t_rawq;
1439 0 : tp->t_rawq.c_cc = 0;
1440 0 : tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
1441 0 : while ((c = getc(&tq)) >= 0)
1442 0 : ttyinput(c, tp);
1443 0 : CLR(tp->t_state, TS_TYPEN);
1444 0 : }
1445 :
1446 : void ttvtimeout(void *);
1447 :
1448 : void
1449 0 : ttvtimeout(void *arg)
1450 : {
1451 0 : struct tty *tp = (struct tty *)arg;
1452 :
1453 0 : wakeup(&tp->t_rawq);
1454 0 : }
1455 :
1456 : /*
1457 : * Process a read call on a tty device.
1458 : */
1459 : int
1460 0 : ttread(struct tty *tp, struct uio *uio, int flag)
1461 : {
1462 : struct timeout *stime = NULL;
1463 0 : struct proc *p = curproc;
1464 0 : struct process *pr = p->p_p;
1465 : int s, first, error = 0;
1466 0 : u_char *cc = tp->t_cc;
1467 : struct clist *qp;
1468 : int last_cc = 0;
1469 : long lflag;
1470 0 : int c;
1471 :
1472 0 : loop: lflag = tp->t_lflag;
1473 0 : s = spltty();
1474 : /*
1475 : * take pending input first
1476 : */
1477 0 : if (ISSET(lflag, PENDIN))
1478 0 : ttypend(tp);
1479 0 : splx(s);
1480 :
1481 : /*
1482 : * Hang process if it's in the background.
1483 : */
1484 0 : if (isbackground(pr, tp)) {
1485 0 : if ((pr->ps_sigacts->ps_sigignore & sigmask(SIGTTIN)) ||
1486 0 : (p->p_sigmask & sigmask(SIGTTIN)) ||
1487 0 : pr->ps_flags & PS_PPWAIT || pr->ps_pgrp->pg_jobc == 0) {
1488 : error = EIO;
1489 0 : goto out;
1490 : }
1491 0 : pgsignal(pr->ps_pgrp, SIGTTIN, 1);
1492 0 : error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, ttybg, 0);
1493 0 : if (error)
1494 : goto out;
1495 0 : goto loop;
1496 : }
1497 :
1498 0 : s = spltty();
1499 0 : if (!ISSET(lflag, ICANON)) {
1500 0 : int m = cc[VMIN];
1501 : long t;
1502 :
1503 : /*
1504 : * Note - since cc[VTIME] is a u_char, this won't overflow
1505 : * until we have 32-bit longs and a hz > 8388608.
1506 : * Hopefully this code and 32-bit longs are obsolete by then.
1507 : */
1508 0 : t = cc[VTIME] * hz / 10;
1509 :
1510 0 : qp = &tp->t_rawq;
1511 : /*
1512 : * Check each of the four combinations.
1513 : * (m > 0 && t == 0) is the normal read case.
1514 : * It should be fairly efficient, so we check that and its
1515 : * companion case (m == 0 && t == 0) first.
1516 : */
1517 0 : if (t == 0) {
1518 0 : if (qp->c_cc < m)
1519 0 : goto sleep;
1520 0 : goto read;
1521 : }
1522 0 : if (m > 0) {
1523 0 : if (qp->c_cc <= 0)
1524 0 : goto sleep;
1525 0 : if (qp->c_cc >= m)
1526 0 : goto read;
1527 0 : if (stime == NULL) {
1528 : alloc_timer:
1529 0 : stime = malloc(sizeof(*stime), M_TEMP, M_WAITOK);
1530 0 : timeout_set(stime, ttvtimeout, tp);
1531 0 : timeout_add(stime, t);
1532 0 : } else if (qp->c_cc > last_cc) {
1533 : /* got a character, restart timer */
1534 0 : timeout_add(stime, t);
1535 0 : }
1536 : } else { /* m == 0 */
1537 0 : if (qp->c_cc > 0)
1538 0 : goto read;
1539 0 : if (stime == NULL) {
1540 : goto alloc_timer;
1541 : }
1542 : }
1543 0 : last_cc = qp->c_cc;
1544 0 : if (stime && !timeout_triggered(stime)) {
1545 0 : goto sleep;
1546 : }
1547 0 : } else if ((qp = &tp->t_canq)->c_cc <= 0) {
1548 : int carrier;
1549 :
1550 : sleep:
1551 : /*
1552 : * If there is no input, sleep on rawq
1553 : * awaiting hardware receipt and notification.
1554 : * If we have data, we don't need to check for carrier.
1555 : */
1556 0 : carrier = ISSET(tp->t_state, TS_CARR_ON) ||
1557 0 : ISSET(tp->t_cflag, CLOCAL);
1558 0 : if (!carrier && ISSET(tp->t_state, TS_ISOPEN)) {
1559 0 : splx(s);
1560 : error = 0;
1561 0 : goto out;
1562 : }
1563 0 : if (flag & IO_NDELAY) {
1564 0 : splx(s);
1565 : error = EWOULDBLOCK;
1566 0 : goto out;
1567 : }
1568 0 : error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH,
1569 0 : carrier ? ttyin : ttopen, 0);
1570 0 : splx(s);
1571 0 : if (stime && timeout_triggered(stime))
1572 0 : error = EWOULDBLOCK;
1573 0 : if (cc[VMIN] == 0 && error == EWOULDBLOCK) {
1574 : error = 0;
1575 0 : goto out;
1576 : }
1577 0 : if (error && error != EWOULDBLOCK)
1578 : goto out;
1579 : error = 0;
1580 0 : goto loop;
1581 : }
1582 : read:
1583 0 : splx(s);
1584 :
1585 : /*
1586 : * Input present, check for input mapping and processing.
1587 : */
1588 : first = 1;
1589 0 : while ((c = getc(qp)) >= 0) {
1590 : /*
1591 : * delayed suspend (^Y)
1592 : */
1593 0 : if (CCEQ(cc[VDSUSP], c) &&
1594 0 : ISSET(lflag, IEXTEN | ISIG) == (IEXTEN | ISIG)) {
1595 0 : pgsignal(tp->t_pgrp, SIGTSTP, 1);
1596 0 : if (first) {
1597 0 : error = ttysleep(tp, &lbolt, TTIPRI | PCATCH,
1598 : ttybg, 0);
1599 0 : if (error)
1600 : break;
1601 0 : goto loop;
1602 : }
1603 : break;
1604 : }
1605 : /*
1606 : * Interpret EOF only in canonical mode.
1607 : */
1608 0 : if (CCEQ(cc[VEOF], c) && ISSET(lflag, ICANON))
1609 : break;
1610 : /*
1611 : * Give user character.
1612 : */
1613 0 : error = ureadc(c, uio);
1614 0 : if (error)
1615 : break;
1616 0 : if (uio->uio_resid == 0)
1617 : break;
1618 : /*
1619 : * In canonical mode check for a "break character"
1620 : * marking the end of a "line of input".
1621 : */
1622 0 : if (ISSET(lflag, ICANON) && TTBREAKC(c, lflag))
1623 : break;
1624 : first = 0;
1625 : }
1626 : /*
1627 : * Look to unblock output now that (presumably)
1628 : * the input queue has gone down.
1629 : */
1630 0 : s = spltty();
1631 0 : if (tp->t_rawq.c_cc < TTYHOG(tp)/5)
1632 0 : ttyunblock(tp);
1633 0 : splx(s);
1634 :
1635 : out:
1636 0 : if (stime) {
1637 0 : timeout_del(stime);
1638 0 : free(stime, M_TEMP, sizeof(*stime));
1639 0 : }
1640 0 : return (error);
1641 0 : }
1642 :
1643 : /* Call at spltty */
1644 : void
1645 0 : ttyunblock(struct tty *tp)
1646 : {
1647 0 : u_char *cc = tp->t_cc;
1648 :
1649 0 : splassert(IPL_TTY);
1650 :
1651 0 : if (ISSET(tp->t_state, TS_TBLOCK)) {
1652 0 : if (ISSET(tp->t_iflag, IXOFF) &&
1653 0 : cc[VSTART] != _POSIX_VDISABLE &&
1654 0 : putc(cc[VSTART], &tp->t_outq) == 0) {
1655 0 : CLR(tp->t_state, TS_TBLOCK);
1656 0 : ttstart(tp);
1657 0 : }
1658 : /* Try to unblock remote output via hardware flow control. */
1659 0 : if (ISSET(tp->t_cflag, CHWFLOW) && tp->t_hwiflow &&
1660 0 : (*tp->t_hwiflow)(tp, 0) != 0)
1661 0 : CLR(tp->t_state, TS_TBLOCK);
1662 : }
1663 0 : }
1664 :
1665 : /*
1666 : * Check the output queue on tp for space for a kernel message (from uprintf
1667 : * or tprintf). Allow some space over the normal hiwater mark so we don't
1668 : * lose messages due to normal flow control, but don't let the tty run amok.
1669 : * Sleeps here are not interruptible, but we return prematurely if new signals
1670 : * arrive.
1671 : */
1672 : int
1673 0 : ttycheckoutq(struct tty *tp, int wait)
1674 : {
1675 : int hiwat, s, oldsig;
1676 :
1677 0 : hiwat = tp->t_hiwat;
1678 0 : s = spltty();
1679 0 : oldsig = wait ? curproc->p_siglist : 0;
1680 0 : if (tp->t_outq.c_cc > hiwat + TTHIWATMINSPACE)
1681 0 : while (tp->t_outq.c_cc > hiwat) {
1682 0 : ttstart(tp);
1683 0 : if (wait == 0 || curproc->p_siglist != oldsig) {
1684 0 : splx(s);
1685 0 : return (0);
1686 : }
1687 0 : SET(tp->t_state, TS_ASLEEP);
1688 0 : tsleep(&tp->t_outq, PZERO - 1, "ttckoutq", hz);
1689 : }
1690 0 : splx(s);
1691 0 : return (1);
1692 0 : }
1693 :
1694 : /*
1695 : * Process a write call on a tty device.
1696 : */
1697 : int
1698 0 : ttwrite(struct tty *tp, struct uio *uio, int flag)
1699 : {
1700 : u_char *cp = NULL;
1701 : int cc, ce, obufcc = 0;
1702 : struct proc *p;
1703 : struct process *pr;
1704 : int hiwat, error, s;
1705 : size_t cnt;
1706 0 : u_char obuf[OBUFSIZ];
1707 :
1708 0 : hiwat = tp->t_hiwat;
1709 0 : cnt = uio->uio_resid;
1710 : error = 0;
1711 0 : cc = 0;
1712 : loop:
1713 0 : s = spltty();
1714 0 : if (!ISSET(tp->t_state, TS_CARR_ON) &&
1715 0 : !ISSET(tp->t_cflag, CLOCAL)) {
1716 0 : if (ISSET(tp->t_state, TS_ISOPEN)) {
1717 0 : splx(s);
1718 : error = EIO;
1719 0 : goto done;
1720 0 : } else if (flag & IO_NDELAY) {
1721 0 : splx(s);
1722 : error = EWOULDBLOCK;
1723 0 : goto out;
1724 : } else {
1725 : /* Sleep awaiting carrier. */
1726 0 : error = ttysleep(tp,
1727 0 : &tp->t_rawq, TTIPRI | PCATCH, ttopen, 0);
1728 0 : splx(s);
1729 0 : if (error)
1730 : goto out;
1731 0 : goto loop;
1732 : }
1733 : }
1734 0 : splx(s);
1735 : /*
1736 : * Hang the process if it's in the background.
1737 : */
1738 0 : p = curproc;
1739 0 : pr = p->p_p;
1740 0 : if (isbackground(pr, tp) &&
1741 0 : ISSET(tp->t_lflag, TOSTOP) && (pr->ps_flags & PS_PPWAIT) == 0 &&
1742 0 : (pr->ps_sigacts->ps_sigignore & sigmask(SIGTTOU)) == 0 &&
1743 0 : (p->p_sigmask & sigmask(SIGTTOU)) == 0) {
1744 0 : if (pr->ps_pgrp->pg_jobc == 0) {
1745 : error = EIO;
1746 0 : goto out;
1747 : }
1748 0 : pgsignal(pr->ps_pgrp, SIGTTOU, 1);
1749 0 : error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, ttybg, 0);
1750 0 : if (error)
1751 : goto out;
1752 0 : goto loop;
1753 : }
1754 : /*
1755 : * Process the user's data in at most OBUFSIZ chunks. Perform any
1756 : * output translation. Keep track of high water mark, sleep on
1757 : * overflow awaiting device aid in acquiring new space.
1758 : */
1759 0 : while (uio->uio_resid > 0 || cc > 0) {
1760 0 : if (ISSET(tp->t_lflag, FLUSHO)) {
1761 0 : uio->uio_resid = 0;
1762 0 : goto done;
1763 : }
1764 0 : if (tp->t_outq.c_cc > hiwat)
1765 : goto ovhiwat;
1766 : /*
1767 : * Grab a hunk of data from the user, unless we have some
1768 : * leftover from last time.
1769 : */
1770 0 : if (cc == 0) {
1771 0 : cc = MIN(uio->uio_resid, OBUFSIZ);
1772 0 : cp = obuf;
1773 0 : error = uiomove(cp, cc, uio);
1774 0 : if (error) {
1775 : cc = 0;
1776 0 : break;
1777 : }
1778 0 : if (cc > obufcc)
1779 0 : obufcc = cc;
1780 :
1781 : /* duplicate /dev/console output into console buffer */
1782 0 : if (consbufp && cn_tab &&
1783 0 : cn_tab->cn_dev == tp->t_dev && tp->t_gen == 0) {
1784 : int i;
1785 0 : for (i = 0; i < cc; i++) {
1786 0 : char c = cp[i];
1787 0 : if (c != '\0' && c != '\r' && c != 0177)
1788 0 : msgbuf_putchar(consbufp, c);
1789 : }
1790 0 : }
1791 : }
1792 : /*
1793 : * If nothing fancy need be done, grab those characters we
1794 : * can handle without any of ttyoutput's processing and
1795 : * just transfer them to the output q. For those chars
1796 : * which require special processing (as indicated by the
1797 : * bits in char_type), call ttyoutput. After processing
1798 : * a hunk of data, look for FLUSHO so ^O's will take effect
1799 : * immediately.
1800 : */
1801 0 : while (cc > 0) {
1802 : int i;
1803 0 : if (!ISSET(tp->t_oflag, OPOST))
1804 0 : ce = cc;
1805 : else {
1806 0 : ce = cc - scanc((u_int)cc, cp, char_type,
1807 : CCLASSMASK);
1808 : /*
1809 : * If ce is zero, then we're processing
1810 : * a special character through ttyoutput.
1811 : */
1812 0 : if (ce == 0) {
1813 0 : tp->t_rocount = 0;
1814 0 : if (ttyoutput(*cp, tp) >= 0) {
1815 : /* out of space */
1816 0 : goto ovhiwat;
1817 : }
1818 0 : cp++;
1819 0 : cc--;
1820 0 : if (ISSET(tp->t_lflag, FLUSHO) ||
1821 0 : tp->t_outq.c_cc > hiwat)
1822 0 : goto ovhiwat;
1823 0 : continue;
1824 : }
1825 : }
1826 : /*
1827 : * A bunch of normal characters have been found.
1828 : * Transfer them en masse to the output queue and
1829 : * continue processing at the top of the loop.
1830 : * If there are any further characters in this
1831 : * <= OBUFSIZ chunk, the first should be a character
1832 : * requiring special handling by ttyoutput.
1833 : */
1834 0 : tp->t_rocount = 0;
1835 0 : i = b_to_q(cp, ce, &tp->t_outq);
1836 0 : ce -= i;
1837 0 : tp->t_column += ce;
1838 0 : cp += ce, cc -= ce, tk_nout += ce;
1839 0 : tp->t_outcc += ce;
1840 0 : if (i > 0) {
1841 : /* out of space */
1842 0 : goto ovhiwat;
1843 : }
1844 0 : if (ISSET(tp->t_lflag, FLUSHO) ||
1845 0 : tp->t_outq.c_cc > hiwat)
1846 0 : break;
1847 0 : }
1848 0 : ttstart(tp);
1849 : }
1850 : out:
1851 : /*
1852 : * If cc is nonzero, we leave the uio structure inconsistent, as the
1853 : * offset and iov pointers have moved forward, but it doesn't matter
1854 : * (the call will either return short or restart with a new uio).
1855 : */
1856 0 : uio->uio_resid += cc;
1857 : done:
1858 0 : if (obufcc)
1859 0 : explicit_bzero(obuf, obufcc);
1860 0 : return (error);
1861 :
1862 : ovhiwat:
1863 0 : ttstart(tp);
1864 0 : s = spltty();
1865 : /*
1866 : * This can only occur if FLUSHO is set in t_lflag,
1867 : * or if ttstart/oproc is synchronous (or very fast).
1868 : */
1869 0 : if (tp->t_outq.c_cc <= hiwat) {
1870 0 : splx(s);
1871 0 : goto loop;
1872 : }
1873 0 : if (flag & IO_NDELAY) {
1874 0 : splx(s);
1875 0 : uio->uio_resid += cc;
1876 0 : if (obufcc)
1877 0 : explicit_bzero(obuf, obufcc);
1878 0 : return (uio->uio_resid == cnt ? EWOULDBLOCK : 0);
1879 : }
1880 0 : SET(tp->t_state, TS_ASLEEP);
1881 0 : error = ttysleep(tp, &tp->t_outq, TTOPRI | PCATCH, ttyout, 0);
1882 0 : splx(s);
1883 0 : if (error)
1884 : goto out;
1885 0 : goto loop;
1886 0 : }
1887 :
1888 : /*
1889 : * Rubout one character from the rawq of tp
1890 : * as cleanly as possible.
1891 : */
1892 : void
1893 0 : ttyrub(int c, struct tty *tp)
1894 : {
1895 : u_char *cp;
1896 : int savecol;
1897 0 : int tabc, s;
1898 :
1899 0 : if (!ISSET(tp->t_lflag, ECHO) || ISSET(tp->t_lflag, EXTPROC))
1900 0 : return;
1901 0 : CLR(tp->t_lflag, FLUSHO);
1902 0 : if (ISSET(tp->t_lflag, ECHOE)) {
1903 0 : if (tp->t_rocount == 0) {
1904 : /*
1905 : * Screwed by ttwrite; retype
1906 : */
1907 0 : ttyretype(tp);
1908 0 : return;
1909 : }
1910 0 : if (c == ('\t' | TTY_QUOTE) || c == ('\n' | TTY_QUOTE))
1911 0 : ttyrubo(tp, 2);
1912 : else {
1913 0 : CLR(c, ~TTY_CHARMASK);
1914 0 : switch (CCLASS(c)) {
1915 : case ORDINARY:
1916 0 : ttyrubo(tp, 1);
1917 0 : break;
1918 : case BACKSPACE:
1919 : case CONTROL:
1920 : case NEWLINE:
1921 : case RETURN:
1922 : case VTAB:
1923 0 : if (ISSET(tp->t_lflag, ECHOCTL))
1924 0 : ttyrubo(tp, 2);
1925 : break;
1926 : case TAB:
1927 0 : if (tp->t_rocount < tp->t_rawq.c_cc) {
1928 0 : ttyretype(tp);
1929 0 : return;
1930 : }
1931 0 : s = spltty();
1932 0 : savecol = tp->t_column;
1933 0 : SET(tp->t_state, TS_CNTTB);
1934 0 : SET(tp->t_lflag, FLUSHO);
1935 0 : tp->t_column = tp->t_rocol;
1936 0 : for (cp = firstc(&tp->t_rawq, &tabc); cp;
1937 0 : cp = nextc(&tp->t_rawq, cp, &tabc))
1938 0 : ttyecho(tabc, tp);
1939 0 : CLR(tp->t_lflag, FLUSHO);
1940 0 : CLR(tp->t_state, TS_CNTTB);
1941 0 : splx(s);
1942 :
1943 : /* savecol will now be length of the tab. */
1944 0 : savecol -= tp->t_column;
1945 0 : tp->t_column += savecol;
1946 0 : if (savecol > 8)
1947 0 : savecol = 8; /* overflow screw */
1948 0 : while (--savecol >= 0)
1949 0 : (void)ttyoutput('\b', tp);
1950 : break;
1951 : default: /* XXX */
1952 : #define PANICSTR "ttyrub: would panic c = %d, val = %d\n"
1953 0 : (void)printf(PANICSTR, c, CCLASS(c));
1954 : #ifdef notdef
1955 : panic(PANICSTR, c, CCLASS(c));
1956 : #endif
1957 0 : }
1958 : }
1959 0 : } else if (ISSET(tp->t_lflag, ECHOPRT)) {
1960 0 : if (!ISSET(tp->t_state, TS_ERASE)) {
1961 0 : SET(tp->t_state, TS_ERASE);
1962 0 : (void)ttyoutput('\\', tp);
1963 0 : }
1964 0 : ttyecho(c, tp);
1965 0 : } else
1966 0 : ttyecho(tp->t_cc[VERASE], tp);
1967 0 : --tp->t_rocount;
1968 0 : }
1969 :
1970 : /*
1971 : * Back over cnt characters, erasing them.
1972 : */
1973 : static void
1974 0 : ttyrubo(struct tty *tp, int cnt)
1975 : {
1976 :
1977 0 : while (cnt-- > 0) {
1978 0 : (void)ttyoutput('\b', tp);
1979 0 : (void)ttyoutput(' ', tp);
1980 0 : (void)ttyoutput('\b', tp);
1981 : }
1982 0 : }
1983 :
1984 : /*
1985 : * ttyretype --
1986 : * Reprint the rawq line. Note, it is assumed that c_cc has already
1987 : * been checked.
1988 : */
1989 : void
1990 0 : ttyretype(struct tty *tp)
1991 : {
1992 : u_char *cp;
1993 0 : int s, c;
1994 :
1995 : /* Echo the reprint character. */
1996 0 : if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE)
1997 0 : ttyecho(tp->t_cc[VREPRINT], tp);
1998 :
1999 0 : (void)ttyoutput('\n', tp);
2000 :
2001 0 : s = spltty();
2002 0 : for (cp = firstc(&tp->t_canq, &c); cp; cp = nextc(&tp->t_canq, cp, &c))
2003 0 : ttyecho(c, tp);
2004 0 : for (cp = firstc(&tp->t_rawq, &c); cp; cp = nextc(&tp->t_rawq, cp, &c))
2005 0 : ttyecho(c, tp);
2006 0 : CLR(tp->t_state, TS_ERASE);
2007 0 : splx(s);
2008 :
2009 0 : tp->t_rocount = tp->t_rawq.c_cc;
2010 0 : tp->t_rocol = 0;
2011 0 : }
2012 :
2013 : /*
2014 : * Echo a typed character to the terminal.
2015 : */
2016 : static void
2017 0 : ttyecho(int c, struct tty *tp)
2018 : {
2019 :
2020 0 : if (!ISSET(tp->t_state, TS_CNTTB))
2021 0 : CLR(tp->t_lflag, FLUSHO);
2022 0 : if ((!ISSET(tp->t_lflag, ECHO) &&
2023 0 : (!ISSET(tp->t_lflag, ECHONL) || c != '\n')) ||
2024 0 : ISSET(tp->t_lflag, EXTPROC))
2025 : return;
2026 0 : if (((ISSET(tp->t_lflag, ECHOCTL) &&
2027 0 : (ISSET(c, TTY_CHARMASK) <= 037 && c != '\t' && c != '\n')) ||
2028 0 : ISSET(c, TTY_CHARMASK) == 0177)) {
2029 0 : (void)ttyoutput('^', tp);
2030 0 : CLR(c, ~TTY_CHARMASK);
2031 0 : if (c == 0177)
2032 0 : c = '?';
2033 : else
2034 0 : c += 'A' - 1;
2035 : }
2036 0 : (void)ttyoutput(c, tp);
2037 0 : }
2038 :
2039 : /*
2040 : * Wakeup any writers if necessary.
2041 : */
2042 : void
2043 0 : ttwakeupwr(struct tty *tp)
2044 : {
2045 :
2046 0 : if (tp->t_outq.c_cc <= tp->t_lowat) {
2047 0 : if (ISSET(tp->t_state, TS_ASLEEP)) {
2048 0 : CLR(tp->t_state, TS_ASLEEP);
2049 0 : wakeup(&tp->t_outq);
2050 0 : }
2051 0 : selwakeup(&tp->t_wsel);
2052 0 : }
2053 0 : }
2054 :
2055 : /*
2056 : * Wake up any readers on a tty.
2057 : */
2058 : void
2059 0 : ttwakeup(struct tty *tp)
2060 : {
2061 :
2062 0 : selwakeup(&tp->t_rsel);
2063 0 : if (ISSET(tp->t_state, TS_ASYNC))
2064 0 : pgsignal(tp->t_pgrp, SIGIO, 1);
2065 0 : wakeup((caddr_t)&tp->t_rawq);
2066 0 : }
2067 :
2068 : /*
2069 : * Look up a code for a specified speed in a conversion table;
2070 : * used by drivers to map software speed values to hardware parameters.
2071 : */
2072 : int
2073 0 : ttspeedtab(int speed, const struct speedtab *table)
2074 : {
2075 :
2076 0 : for ( ; table->sp_speed != -1; table++)
2077 0 : if (table->sp_speed == speed)
2078 0 : return (table->sp_code);
2079 0 : return (-1);
2080 0 : }
2081 :
2082 : /*
2083 : * Set tty hi and low water marks.
2084 : *
2085 : * Try to arrange the dynamics so there's about one second
2086 : * from hi to low water.
2087 : */
2088 : void
2089 0 : ttsetwater(struct tty *tp)
2090 : {
2091 : int cps, x;
2092 :
2093 : #define CLAMP(x, h, l) ((x) > h ? h : ((x) < l) ? l : (x))
2094 :
2095 0 : cps = tp->t_ospeed / 10;
2096 0 : tp->t_lowat = x = CLAMP(cps / 2, TTMAXLOWAT, TTMINLOWAT);
2097 0 : x += cps;
2098 0 : tp->t_hiwat = CLAMP(x, tp->t_outq.c_cn - TTHIWATMINSPACE, TTMINHIWAT);
2099 : #undef CLAMP
2100 0 : }
2101 :
2102 : /*
2103 : * Get the total estcpu for a process, summing across threads.
2104 : * Returns true if at least one thread is runnable/running.
2105 : */
2106 : static int
2107 0 : process_sum(struct process *pr, fixpt_t *estcpup)
2108 : {
2109 : struct proc *p;
2110 : fixpt_t estcpu;
2111 : int ret;
2112 :
2113 : ret = 0;
2114 : estcpu = 0;
2115 0 : TAILQ_FOREACH(p, &pr->ps_threads, p_thr_link) {
2116 0 : if (p->p_stat == SRUN || p->p_stat == SONPROC)
2117 0 : ret = 1;
2118 0 : estcpu += p->p_pctcpu;
2119 : }
2120 :
2121 0 : *estcpup = estcpu;
2122 0 : return (ret);
2123 : }
2124 :
2125 : /*
2126 : * Report on state of foreground process group.
2127 : */
2128 : void
2129 0 : ttyinfo(struct tty *tp)
2130 : {
2131 : struct process *pr, *pickpr;
2132 : struct proc *p, *pick;
2133 0 : struct timespec utime, stime;
2134 : int tmp;
2135 :
2136 0 : if (ttycheckoutq(tp,0) == 0)
2137 0 : return;
2138 :
2139 : /* Print load average. */
2140 0 : tmp = (averunnable.ldavg[0] * 100 + FSCALE / 2) >> FSHIFT;
2141 0 : ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100);
2142 :
2143 0 : if (tp->t_session == NULL)
2144 0 : ttyprintf(tp, "not a controlling terminal\n");
2145 0 : else if (tp->t_pgrp == NULL)
2146 0 : ttyprintf(tp, "no foreground process group\n");
2147 0 : else if ((pr = LIST_FIRST(&tp->t_pgrp->pg_members)) == NULL)
2148 0 : empty: ttyprintf(tp, "empty foreground process group\n");
2149 : else {
2150 : const char *state;
2151 0 : fixpt_t pctcpu, pctcpu2;
2152 : int run, run2;
2153 : int calc_pctcpu;
2154 : long rss;
2155 :
2156 : /*
2157 : * Pick the most active process:
2158 : * - prefer at least one running/runnable thread
2159 : * - prefer higher total pctcpu
2160 : * - prefer non-zombie
2161 : * Otherwise take the most recently added to this process group
2162 : */
2163 : pickpr = pr;
2164 0 : run = process_sum(pickpr, &pctcpu);
2165 0 : while ((pr = LIST_NEXT(pr, ps_pglist)) != NULL) {
2166 0 : run2 = process_sum(pr, &pctcpu2);
2167 0 : if (run) {
2168 : /*
2169 : * pick is running; is p running w/same or
2170 : * more cpu?
2171 : */
2172 0 : if (run2 && pctcpu2 >= pctcpu)
2173 : goto update_pickpr;
2174 0 : continue;
2175 : }
2176 : /* pick isn't running; is p running *or* w/more cpu? */
2177 0 : if (run2 || pctcpu2 > pctcpu)
2178 : goto update_pickpr;
2179 :
2180 : /* if p has less cpu or is zombie, then it's worse */
2181 0 : if (pctcpu2 < pctcpu || (pr->ps_flags & PS_ZOMBIE))
2182 0 : continue;
2183 : update_pickpr:
2184 : pickpr = pr;
2185 : run = run2;
2186 0 : pctcpu = pctcpu2;
2187 : }
2188 :
2189 : /* Calculate percentage cpu, resident set size. */
2190 0 : calc_pctcpu = (pctcpu * 10000 + FSCALE / 2) >> FSHIFT;
2191 0 : rss = (pickpr->ps_flags & (PS_EMBRYO | PS_ZOMBIE)) ? 0 :
2192 0 : vm_resident_count(pickpr->ps_vmspace);
2193 :
2194 0 : calctsru(&pickpr->ps_tu, &utime, &stime, NULL);
2195 :
2196 : /* Round up and print user time. */
2197 0 : utime.tv_nsec += 5000000;
2198 0 : if (utime.tv_nsec >= 1000000000) {
2199 0 : utime.tv_sec += 1;
2200 0 : utime.tv_nsec -= 1000000000;
2201 0 : }
2202 :
2203 : /* Round up and print system time. */
2204 0 : stime.tv_nsec += 5000000;
2205 0 : if (stime.tv_nsec >= 1000000000) {
2206 0 : stime.tv_sec += 1;
2207 0 : stime.tv_nsec -= 1000000000;
2208 0 : }
2209 :
2210 : /*
2211 : * Find the most active thread:
2212 : * - prefer runnable
2213 : * - prefer higher pctcpu
2214 : * - prefer living
2215 : * Otherwise take the newest thread
2216 : */
2217 0 : pick = p = TAILQ_FIRST(&pickpr->ps_threads);
2218 0 : if (p == NULL)
2219 0 : goto empty;
2220 0 : run = p->p_stat == SRUN || p->p_stat == SONPROC;
2221 0 : pctcpu = p->p_pctcpu;
2222 0 : while ((p = TAILQ_NEXT(p, p_thr_link)) != NULL) {
2223 0 : run2 = p->p_stat == SRUN || p->p_stat == SONPROC;
2224 0 : pctcpu2 = p->p_pctcpu;
2225 0 : if (run) {
2226 : /*
2227 : * pick is running; is p running w/same or
2228 : * more cpu?
2229 : */
2230 0 : if (run2 && pctcpu2 >= pctcpu)
2231 : goto update_pick;
2232 0 : continue;
2233 : }
2234 : /* pick isn't running; is p running *or* w/more cpu? */
2235 0 : if (run2 || pctcpu2 > pctcpu)
2236 : goto update_pick;
2237 :
2238 : /* if p has less cpu or is exiting, then it's worse */
2239 0 : if (pctcpu2 < pctcpu || p->p_flag & P_WEXIT)
2240 0 : continue;
2241 : update_pick:
2242 : pick = p;
2243 : run = run2;
2244 0 : pctcpu = p->p_pctcpu;
2245 : }
2246 0 : state = pick->p_stat == SONPROC ? "running" :
2247 0 : pick->p_stat == SRUN ? "runnable" :
2248 0 : pick->p_wmesg ? pick->p_wmesg : "iowait";
2249 :
2250 0 : ttyprintf(tp,
2251 : " cmd: %s %d [%s] %lld.%02ldu %lld.%02lds %d%% %ldk\n",
2252 0 : pickpr->ps_comm, pickpr->ps_pid, state,
2253 0 : (long long)utime.tv_sec, utime.tv_nsec / 10000000,
2254 0 : (long long)stime.tv_sec, stime.tv_nsec / 10000000,
2255 0 : calc_pctcpu / 100, rss);
2256 0 : }
2257 0 : tp->t_rocount = 0; /* so pending input will be retyped if BS */
2258 0 : }
2259 :
2260 : /*
2261 : * Output char to tty; console putchar style.
2262 : */
2263 : int
2264 0 : tputchar(int c, struct tty *tp)
2265 : {
2266 : int s;
2267 :
2268 0 : s = spltty();
2269 0 : if (ISSET(tp->t_state, TS_ISOPEN) == 0 ||
2270 0 : !(ISSET(tp->t_state, TS_CARR_ON) || ISSET(tp->t_cflag, CLOCAL))) {
2271 0 : splx(s);
2272 0 : return (-1);
2273 : }
2274 0 : if (c == '\n')
2275 0 : (void)ttyoutput('\r', tp);
2276 0 : (void)ttyoutput(c, tp);
2277 0 : ttstart(tp);
2278 0 : splx(s);
2279 0 : return (0);
2280 0 : }
2281 :
2282 : /*
2283 : * Sleep on chan, returning ERESTART if tty changed while we napped and
2284 : * returning any errors (e.g. EINTR/ETIMEDOUT) reported by tsleep. If
2285 : * the tty is revoked, restarting a pending call will redo validation done
2286 : * at the start of the call.
2287 : */
2288 : int
2289 0 : ttysleep(struct tty *tp, void *chan, int pri, char *wmesg, int timo)
2290 : {
2291 : int error;
2292 : short gen;
2293 :
2294 0 : gen = tp->t_gen;
2295 0 : if ((error = tsleep(chan, pri, wmesg, timo)) != 0)
2296 0 : return (error);
2297 0 : return (tp->t_gen == gen ? 0 : ERESTART);
2298 0 : }
2299 :
2300 : /*
2301 : * Initialise the global tty list.
2302 : */
2303 : void
2304 0 : tty_init(void)
2305 : {
2306 :
2307 0 : TAILQ_INIT(&ttylist);
2308 0 : tty_count = 0;
2309 0 : }
2310 :
2311 : /*
2312 : * Allocate a tty structure and its associated buffers, and attach it to the
2313 : * tty list.
2314 : */
2315 : struct tty *
2316 0 : ttymalloc(int baud)
2317 : {
2318 : struct tty *tp;
2319 :
2320 0 : tp = malloc(sizeof(struct tty), M_TTYS, M_WAITOK|M_ZERO);
2321 :
2322 0 : if (baud == 0)
2323 0 : baud = 115200;
2324 :
2325 0 : if (baud <= 9600)
2326 0 : tp->t_qlen = 1024;
2327 0 : else if (baud <= 115200)
2328 0 : tp->t_qlen = 4096;
2329 : else
2330 0 : tp->t_qlen = 8192;
2331 0 : clalloc(&tp->t_rawq, tp->t_qlen, 1);
2332 0 : clalloc(&tp->t_canq, tp->t_qlen, 1);
2333 : /* output queue doesn't need quoting */
2334 0 : clalloc(&tp->t_outq, tp->t_qlen, 0);
2335 :
2336 0 : TAILQ_INSERT_TAIL(&ttylist, tp, tty_link);
2337 0 : ++tty_count;
2338 0 : timeout_set(&tp->t_rstrt_to, ttrstrt, tp);
2339 :
2340 0 : return(tp);
2341 : }
2342 :
2343 :
2344 : /*
2345 : * Free a tty structure and its buffers, after removing it from the tty list.
2346 : */
2347 : void
2348 0 : ttyfree(struct tty *tp)
2349 : {
2350 :
2351 0 : --tty_count;
2352 : #ifdef DIAGNOSTIC
2353 0 : if (tty_count < 0)
2354 0 : panic("ttyfree: tty_count < 0");
2355 : #endif
2356 0 : TAILQ_REMOVE(&ttylist, tp, tty_link);
2357 :
2358 0 : ttkqflush(&tp->t_rsel.si_note);
2359 0 : ttkqflush(&tp->t_wsel.si_note);
2360 :
2361 0 : clfree(&tp->t_rawq);
2362 0 : clfree(&tp->t_canq);
2363 0 : clfree(&tp->t_outq);
2364 0 : free(tp, M_TTYS, sizeof(*tp));
2365 0 : }
2366 :
2367 : void
2368 0 : ttystats_init(struct itty **ttystats, size_t *ttystatssiz)
2369 : {
2370 : struct itty *itp;
2371 : struct tty *tp;
2372 :
2373 0 : *ttystatssiz = tty_count * sizeof(struct itty);
2374 0 : *ttystats = mallocarray(tty_count, sizeof(struct itty),
2375 : M_SYSCTL, M_WAITOK|M_ZERO);
2376 0 : for (tp = TAILQ_FIRST(&ttylist), itp = *ttystats; tp;
2377 0 : tp = TAILQ_NEXT(tp, tty_link), itp++) {
2378 0 : itp->t_dev = tp->t_dev;
2379 0 : itp->t_rawq_c_cc = tp->t_rawq.c_cc;
2380 0 : itp->t_canq_c_cc = tp->t_canq.c_cc;
2381 0 : itp->t_outq_c_cc = tp->t_outq.c_cc;
2382 0 : itp->t_hiwat = tp->t_hiwat;
2383 0 : itp->t_lowat = tp->t_lowat;
2384 0 : itp->t_column = tp->t_column;
2385 0 : itp->t_state = tp->t_state;
2386 0 : itp->t_session = tp->t_session;
2387 0 : if (tp->t_pgrp)
2388 0 : itp->t_pgrp_pg_id = tp->t_pgrp->pg_id;
2389 : else
2390 0 : itp->t_pgrp_pg_id = 0;
2391 0 : itp->t_line = tp->t_line;
2392 : }
2393 0 : }
2394 :
2395 : /*
2396 : * Return tty-related information.
2397 : */
2398 : int
2399 0 : sysctl_tty(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
2400 : size_t newlen)
2401 : {
2402 : int err;
2403 :
2404 0 : if (namelen != 1)
2405 0 : return (ENOTDIR);
2406 :
2407 0 : switch (name[0]) {
2408 : case KERN_TTY_TKNIN:
2409 0 : return (sysctl_rdquad(oldp, oldlenp, newp, tk_nin));
2410 : case KERN_TTY_TKNOUT:
2411 0 : return (sysctl_rdquad(oldp, oldlenp, newp, tk_nout));
2412 : case KERN_TTY_TKRAWCC:
2413 0 : return (sysctl_rdquad(oldp, oldlenp, newp, tk_rawcc));
2414 : case KERN_TTY_TKCANCC:
2415 0 : return (sysctl_rdquad(oldp, oldlenp, newp, tk_cancc));
2416 : case KERN_TTY_INFO:
2417 : {
2418 0 : struct itty *ttystats;
2419 0 : size_t ttystatssiz;
2420 :
2421 0 : ttystats_init(&ttystats, &ttystatssiz);
2422 0 : err = sysctl_rdstruct(oldp, oldlenp, newp, ttystats,
2423 0 : tty_count * sizeof(struct itty));
2424 0 : free(ttystats, M_SYSCTL, ttystatssiz);
2425 : return (err);
2426 0 : }
2427 : default:
2428 : #if NPTY > 0
2429 0 : return (sysctl_pty(name, namelen, oldp, oldlenp, newp, newlen));
2430 : #else
2431 : return (EOPNOTSUPP);
2432 : #endif
2433 : }
2434 : /* NOTREACHED */
2435 0 : }
2436 :
2437 : void
2438 0 : ttytstamp(struct tty *tp, int octs, int ncts, int odcd, int ndcd)
2439 : {
2440 : int doit = 0;
2441 :
2442 0 : if (ncts ^ octs)
2443 0 : doit |= ncts ? ISSET(tp->t_flags, TS_TSTAMPCTSSET) :
2444 0 : ISSET(tp->t_flags, TS_TSTAMPCTSCLR);
2445 0 : if (ndcd ^ odcd)
2446 0 : doit |= ndcd ? ISSET(tp->t_flags, TS_TSTAMPDCDSET) :
2447 0 : ISSET(tp->t_flags, TS_TSTAMPDCDCLR);
2448 :
2449 0 : if (doit)
2450 0 : microtime(&tp->t_tv);
2451 0 : }
|