Annotation of src/sys/kern/tty.c, Revision 1.125.2.2
1.125.2.2! nathanw 1: /* $NetBSD: tty.c,v 1.127 2001/03/31 00:35:23 enami Exp $ */
1.49 cgd 2:
3: /*-
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: *
1.105 fvdl 40: * @(#)tty.c 8.13 (Berkeley) 1/9/95
1.49 cgd 41: */
1.100 thorpej 42:
43: #include "opt_uconsole.h"
1.49 cgd 44:
45: #include <sys/param.h>
46: #include <sys/systm.h>
47: #include <sys/ioctl.h>
1.125.2.1 nathanw 48: #include <sys/lwp.h>
1.49 cgd 49: #include <sys/proc.h>
50: #define TTYDEFCHARS
51: #include <sys/tty.h>
52: #undef TTYDEFCHARS
53: #include <sys/file.h>
54: #include <sys/conf.h>
55: #include <sys/dkstat.h>
56: #include <sys/uio.h>
57: #include <sys/kernel.h>
58: #include <sys/vnode.h>
59: #include <sys/syslog.h>
60: #include <sys/malloc.h>
1.111 thorpej 61: #include <sys/pool.h>
1.65 christos 62: #include <sys/signalvar.h>
63: #include <sys/resourcevar.h>
1.74 mycroft 64: #include <sys/poll.h>
1.49 cgd 65:
1.125.2.2! nathanw 66: static int ttnread(struct tty *);
! 67: static void ttyblock(struct tty *);
! 68: static void ttyecho(int, struct tty *);
! 69: static void ttyrubo(struct tty *, int);
! 70: static int proc_compare(struct proc *, struct proc *);
1.49 cgd 71:
72: /* Symbolic sleep message strings. */
1.98 mycroft 73: const char ttclos[] = "ttycls";
74: const char ttopen[] = "ttyopn";
75: const char ttybg[] = "ttybg";
76: const char ttyin[] = "ttyin";
77: const char ttyout[] = "ttyout";
1.49 cgd 78:
79: /*
1.83 mycroft 80: * Used to determine whether we still have a connection. This is true in
81: * one of 3 cases:
82: * 1) We have carrier.
83: * 2) It's a locally attached terminal, and we are therefore ignoring carrier.
84: * 3) We're using a flow control mechanism that overloads the carrier signal.
85: */
86: #define CONNECTED(tp) (ISSET(tp->t_state, TS_CARR_ON) || \
87: ISSET(tp->t_cflag, CLOCAL | MDMBUF))
88:
89: /*
1.49 cgd 90: * Table with character classes and parity. The 8th bit indicates parity,
91: * the 7th bit indicates the character is an alphameric or underscore (for
92: * ALTWERASE), and the low 6 bits indicate delay type. If the low 6 bits
93: * are 0 then the character needs no special processing on output; classes
94: * other than 0 might be translated or (not currently) require delays.
95: */
96: #define E 0x00 /* Even parity. */
97: #define O 0x80 /* Odd parity. */
98: #define PARITY(c) (char_type[c] & O)
99:
100: #define ALPHA 0x40 /* Alpha or underscore. */
101: #define ISALPHA(c) (char_type[(c) & TTY_CHARMASK] & ALPHA)
102:
103: #define CCLASSMASK 0x3f
104: #define CCLASS(c) (char_type[c] & CCLASSMASK)
105:
106: #define BS BACKSPACE
107: #define CC CONTROL
108: #define CR RETURN
109: #define NA ORDINARY | ALPHA
110: #define NL NEWLINE
111: #define NO ORDINARY
112: #define TB TAB
113: #define VT VTAB
114:
115: char const char_type[] = {
116: E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* nul - bel */
117: O|BS, E|TB, E|NL, O|CC, E|VT, O|CR, O|CC, E|CC, /* bs - si */
118: O|CC, E|CC, E|CC, O|CC, E|CC, O|CC, O|CC, E|CC, /* dle - etb */
119: E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* can - us */
120: O|NO, E|NO, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* sp - ' */
121: E|NO, O|NO, O|NO, E|NO, O|NO, E|NO, E|NO, O|NO, /* ( - / */
122: E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* 0 - 7 */
123: O|NA, E|NA, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* 8 - ? */
124: O|NO, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* @ - G */
125: E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* H - O */
126: E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* P - W */
127: O|NA, E|NA, E|NA, O|NO, E|NO, O|NO, O|NO, O|NA, /* X - _ */
128: E|NO, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* ` - g */
129: O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* h - o */
130: O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* p - w */
131: E|NA, O|NA, O|NA, E|NO, O|NO, E|NO, E|NO, O|CC, /* x - del */
132: /*
133: * Meta chars; should be settable per character set;
134: * for now, treat them all as normal characters.
135: */
136: NA, NA, NA, NA, NA, NA, NA, NA,
137: NA, NA, NA, NA, NA, NA, NA, NA,
138: NA, NA, NA, NA, NA, NA, NA, NA,
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: };
153: #undef BS
154: #undef CC
155: #undef CR
156: #undef NA
157: #undef NL
158: #undef NO
159: #undef TB
160: #undef VT
161:
162: /* Macros to clear/set/test flags. */
163: #define SET(t, f) (t) |= (f)
1.65 christos 164: #define CLR(t, f) (t) &= ~((unsigned)(f))
1.49 cgd 165: #define ISSET(t, f) ((t) & (f))
166:
1.69 mrg 167: struct ttylist_head ttylist; /* TAILQ_HEAD */
168: int tty_count;
169:
1.111 thorpej 170: struct pool tty_pool;
171:
1.107 mycroft 172: int
1.125.2.2! nathanw 173: ttyopen(struct tty *tp, int dialout, int nonblock)
1.107 mycroft 174: {
1.125.2.2! nathanw 175: int s, error;
1.107 mycroft 176:
177: s = spltty();
178:
179: if (dialout) {
180: /*
181: * If the device is already open for non-dialout, fail.
182: * Otherwise, set TS_DIALOUT to block any pending non-dialout
183: * opens.
184: */
185: if (ISSET(tp->t_state, TS_ISOPEN) &&
186: !ISSET(tp->t_state, TS_DIALOUT)) {
187: splx(s);
188: return (EBUSY);
189: }
190: SET(tp->t_state, TS_DIALOUT);
191: } else {
192: if (!nonblock) {
193: /*
194: * Wait for carrier. Also wait for any dialout
195: * processes to close the tty first.
196: */
197: while (ISSET(tp->t_state, TS_DIALOUT) ||
198: (!ISSET(tp->t_state, TS_CARR_ON) &&
199: !ISSET(tp->t_cflag, CLOCAL | MDMBUF))) {
200: tp->t_wopen++;
201: error = ttysleep(tp, &tp->t_rawq,
202: TTIPRI | PCATCH, ttopen, 0);
203: tp->t_wopen--;
204: if (error) {
205: splx(s);
206: return (error);
207: }
208: }
209: } else {
210: /*
211: * Don't allow a non-blocking non-dialout open if the
212: * device is already open for dialout.
213: */
214: if (ISSET(tp->t_state, TS_DIALOUT)) {
215: splx(s);
216: return (EBUSY);
217: }
218: }
219: }
220:
221: splx(s);
222: return (0);
223: }
224:
1.49 cgd 225: /*
226: * Initial open of tty, or (re)entry to standard tty line discipline.
227: */
228: int
1.125.2.2! nathanw 229: ttylopen(dev_t device, struct tty *tp)
1.49 cgd 230: {
1.125.2.2! nathanw 231: int s;
1.49 cgd 232:
233: s = spltty();
234: tp->t_dev = device;
235: if (!ISSET(tp->t_state, TS_ISOPEN)) {
236: SET(tp->t_state, TS_ISOPEN);
1.109 perry 237: memset(&tp->t_winsize, 0, sizeof(tp->t_winsize));
1.66 christos 238: #ifdef COMPAT_OLDTTY
1.50 mycroft 239: tp->t_flags = 0;
240: #endif
1.49 cgd 241: }
242: splx(s);
243: return (0);
244: }
245:
246: /*
247: * Handle close() on a tty line: flush and set to initial state,
248: * bumping generation number so that pending read/write calls
249: * can detect recycling of the tty.
250: */
251: int
1.125.2.2! nathanw 252: ttyclose(struct tty *tp)
1.49 cgd 253: {
254: extern struct tty *constty; /* Temporary virtual console. */
255:
256: if (constty == tp)
257: constty = NULL;
258:
259: ttyflush(tp, FREAD | FWRITE);
260:
261: tp->t_gen++;
262: tp->t_pgrp = NULL;
263: tp->t_session = NULL;
264: tp->t_state = 0;
265: return (0);
266: }
267:
268: #define FLUSHQ(q) { \
269: if ((q)->c_cc) \
270: ndflush(q, (q)->c_cc); \
271: }
272:
1.88 kleink 273: /*
274: * This macro is used in canonical mode input processing, where a read
275: * request shall not return unless a 'line delimiter' ('\n') or 'break'
276: * (EOF, EOL, EOL2) character (or a signal) has been received. As EOL2
277: * is an extension to the POSIX.1 defined set of special characters,
278: * recognize it only if IEXTEN is set in the set of local flags.
279: */
1.85 kleink 280: #define TTBREAKC(c, lflg) \
1.87 cgd 281: ((c) == '\n' || (((c) == cc[VEOF] || (c) == cc[VEOL] || \
1.85 kleink 282: ((c) == cc[VEOL2] && ISSET(lflg, IEXTEN))) && (c) != _POSIX_VDISABLE))
1.49 cgd 283:
284:
285: /*
286: * Process input of a single character received on a tty.
287: */
288: int
1.125.2.2! nathanw 289: ttyinput(int c, struct tty *tp)
1.49 cgd 290: {
1.125.2.2! nathanw 291: int iflag, lflag, i, error;
! 292: u_char *cc;
1.78 christos 293:
294: /*
295: * Unless the receiver is enabled, drop incoming data.
296: */
297: if (!ISSET(tp->t_cflag, CREAD))
298: return (0);
1.49 cgd 299:
300: /*
301: * If input is pending take it first.
302: */
303: lflag = tp->t_lflag;
304: if (ISSET(lflag, PENDIN))
305: ttypend(tp);
306: /*
307: * Gather stats.
308: */
309: if (ISSET(lflag, ICANON)) {
310: ++tk_cancc;
311: ++tp->t_cancc;
312: } else {
313: ++tk_rawcc;
314: ++tp->t_rawcc;
315: }
316: ++tk_nin;
317:
318: cc = tp->t_cc;
1.94 kleink 319:
320: /*
321: * Handle exceptional conditions (break, parity, framing).
322: */
1.49 cgd 323: iflag = tp->t_iflag;
1.65 christos 324: if ((error = (ISSET(c, TTY_ERRORMASK))) != 0) {
1.49 cgd 325: CLR(c, TTY_ERRORMASK);
1.94 kleink 326: if (ISSET(error, TTY_FE) && c == 0) { /* Break. */
1.49 cgd 327: if (ISSET(iflag, IGNBRK))
1.94 kleink 328: return (0);
329: else if (ISSET(iflag, BRKINT)) {
330: ttyflush(tp, FREAD | FWRITE);
331: pgsignal(tp->t_pgrp, SIGINT, 1);
332: return (0);
333: }
1.49 cgd 334: else if (ISSET(iflag, PARMRK))
335: goto parmrk;
1.94 kleink 336: }
337: else if ((ISSET(error, TTY_PE) && ISSET(iflag, INPCK)) ||
338: ISSET(error, TTY_FE)) {
1.49 cgd 339: if (ISSET(iflag, IGNPAR))
1.94 kleink 340: return (0);
1.49 cgd 341: else if (ISSET(iflag, PARMRK)) {
1.125.2.2! nathanw 342: parmrk: (void)putc(0377 | TTY_QUOTE, &tp->t_rawq);
1.94 kleink 343: (void)putc(0 | TTY_QUOTE, &tp->t_rawq);
344: (void)putc(c | TTY_QUOTE, &tp->t_rawq);
345: return (0);
346: }
347: else
1.49 cgd 348: c = 0;
349: }
350: }
1.94 kleink 351: else if (c == 0377 &&
352: ISSET(iflag, ISTRIP|IGNPAR|INPCK|PARMRK) == (INPCK|PARMRK)) {
353: /* "Escape" a valid character of '\377'. */
354: (void)putc(0377 | TTY_QUOTE, &tp->t_rawq);
355: (void)putc(0377 | TTY_QUOTE, &tp->t_rawq);
356: goto endcase;
357: }
358:
1.49 cgd 359: /*
360: * In tandem mode, check high water mark.
361: */
362: if (ISSET(iflag, IXOFF) || ISSET(tp->t_cflag, CHWFLOW))
363: ttyblock(tp);
364: if (!ISSET(tp->t_state, TS_TYPEN) && ISSET(iflag, ISTRIP))
365: CLR(c, 0x80);
366: if (!ISSET(lflag, EXTPROC)) {
367: /*
368: * Check for literal nexting very first
369: */
370: if (ISSET(tp->t_state, TS_LNCH)) {
371: SET(c, TTY_QUOTE);
372: CLR(tp->t_state, TS_LNCH);
373: }
374: /*
375: * Scan for special characters. This code
376: * is really just a big case statement with
377: * non-constant cases. The bottom of the
378: * case statement is labeled ``endcase'', so goto
379: * it after a case match, or similar.
380: */
381:
382: /*
383: * Control chars which aren't controlled
384: * by ICANON, ISIG, or IXON.
385: */
386: if (ISSET(lflag, IEXTEN)) {
387: if (CCEQ(cc[VLNEXT], c)) {
388: if (ISSET(lflag, ECHO)) {
389: if (ISSET(lflag, ECHOE)) {
390: (void)ttyoutput('^', tp);
391: (void)ttyoutput('\b', tp);
392: } else
393: ttyecho(c, tp);
394: }
395: SET(tp->t_state, TS_LNCH);
396: goto endcase;
397: }
398: if (CCEQ(cc[VDISCARD], c)) {
399: if (ISSET(lflag, FLUSHO))
400: CLR(tp->t_lflag, FLUSHO);
401: else {
402: ttyflush(tp, FWRITE);
403: ttyecho(c, tp);
404: if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
405: ttyretype(tp);
406: SET(tp->t_lflag, FLUSHO);
407: }
408: goto startoutput;
409: }
410: }
411: /*
412: * Signals.
413: */
414: if (ISSET(lflag, ISIG)) {
415: if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) {
416: if (!ISSET(lflag, NOFLSH))
417: ttyflush(tp, FREAD | FWRITE);
418: ttyecho(c, tp);
419: pgsignal(tp->t_pgrp,
420: CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1);
421: goto endcase;
422: }
423: if (CCEQ(cc[VSUSP], c)) {
424: if (!ISSET(lflag, NOFLSH))
425: ttyflush(tp, FREAD);
426: ttyecho(c, tp);
427: pgsignal(tp->t_pgrp, SIGTSTP, 1);
428: goto endcase;
429: }
430: }
431: /*
432: * Handle start/stop characters.
433: */
434: if (ISSET(iflag, IXON)) {
435: if (CCEQ(cc[VSTOP], c)) {
436: if (!ISSET(tp->t_state, TS_TTSTOP)) {
437: SET(tp->t_state, TS_TTSTOP);
438: (*cdevsw[major(tp->t_dev)].d_stop)(tp,
439: 0);
440: return (0);
441: }
442: if (!CCEQ(cc[VSTART], c))
443: return (0);
444: /*
445: * if VSTART == VSTOP then toggle
446: */
447: goto endcase;
448: }
449: if (CCEQ(cc[VSTART], c))
450: goto restartoutput;
451: }
452: /*
453: * IGNCR, ICRNL, & INLCR
454: */
455: if (c == '\r') {
456: if (ISSET(iflag, IGNCR))
457: goto endcase;
458: else if (ISSET(iflag, ICRNL))
459: c = '\n';
460: } else if (c == '\n' && ISSET(iflag, INLCR))
461: c = '\r';
462: }
463: if (!ISSET(tp->t_lflag, EXTPROC) && ISSET(lflag, ICANON)) {
464: /*
465: * From here on down canonical mode character
466: * processing takes place.
467: */
468: /*
469: * erase (^H / ^?)
470: */
471: if (CCEQ(cc[VERASE], c)) {
472: if (tp->t_rawq.c_cc)
473: ttyrub(unputc(&tp->t_rawq), tp);
474: goto endcase;
475: }
476: /*
477: * kill (^U)
478: */
479: if (CCEQ(cc[VKILL], c)) {
480: if (ISSET(lflag, ECHOKE) &&
481: tp->t_rawq.c_cc == tp->t_rocount &&
482: !ISSET(lflag, ECHOPRT))
483: while (tp->t_rawq.c_cc)
484: ttyrub(unputc(&tp->t_rawq), tp);
485: else {
486: ttyecho(c, tp);
487: if (ISSET(lflag, ECHOK) ||
488: ISSET(lflag, ECHOKE))
489: ttyecho('\n', tp);
490: FLUSHQ(&tp->t_rawq);
491: tp->t_rocount = 0;
492: }
493: CLR(tp->t_state, TS_LOCAL);
494: goto endcase;
495: }
496: /*
1.81 kleink 497: * Extensions to the POSIX.1 GTI set of functions.
1.49 cgd 498: */
1.81 kleink 499: if (ISSET(lflag, IEXTEN)) {
1.49 cgd 500: /*
1.81 kleink 501: * word erase (^W)
1.49 cgd 502: */
1.81 kleink 503: if (CCEQ(cc[VWERASE], c)) {
504: int alt = ISSET(lflag, ALTWERASE);
505: int ctype;
506:
507: /*
508: * erase whitespace
509: */
510: while ((c = unputc(&tp->t_rawq)) == ' ' ||
511: c == '\t')
512: ttyrub(c, tp);
513: if (c == -1)
514: goto endcase;
515: /*
516: * erase last char of word and remember the
517: * next chars type (for ALTWERASE)
518: */
1.49 cgd 519: ttyrub(c, tp);
1.81 kleink 520: c = unputc(&tp->t_rawq);
521: if (c == -1)
522: goto endcase;
523: if (c == ' ' || c == '\t') {
524: (void)putc(c, &tp->t_rawq);
525: goto endcase;
526: }
527: ctype = ISALPHA(c);
528: /*
529: * erase rest of word
530: */
531: do {
532: ttyrub(c, tp);
533: c = unputc(&tp->t_rawq);
534: if (c == -1)
535: goto endcase;
536: } while (c != ' ' && c != '\t' &&
537: (alt == 0 || ISALPHA(c) == ctype));
538: (void)putc(c, &tp->t_rawq);
1.49 cgd 539: goto endcase;
1.81 kleink 540: }
1.49 cgd 541: /*
1.81 kleink 542: * reprint line (^R)
1.49 cgd 543: */
1.81 kleink 544: if (CCEQ(cc[VREPRINT], c)) {
545: ttyretype(tp);
1.49 cgd 546: goto endcase;
547: }
548: /*
1.81 kleink 549: * ^T - kernel info and generate SIGINFO
1.49 cgd 550: */
1.81 kleink 551: if (CCEQ(cc[VSTATUS], c)) {
552: if (ISSET(lflag, ISIG))
553: pgsignal(tp->t_pgrp, SIGINFO, 1);
554: if (!ISSET(lflag, NOKERNINFO))
555: ttyinfo(tp);
556: goto endcase;
557: }
1.49 cgd 558: }
559: }
560: /*
561: * Check for input buffer overflow
562: */
563: if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= TTYHOG) {
564: if (ISSET(iflag, IMAXBEL)) {
565: if (tp->t_outq.c_cc < tp->t_hiwat)
566: (void)ttyoutput(CTRL('g'), tp);
567: } else
568: ttyflush(tp, FREAD | FWRITE);
569: goto endcase;
570: }
571: /*
572: * Put data char in q for user and
573: * wakeup on seeing a line delimiter.
574: */
575: if (putc(c, &tp->t_rawq) >= 0) {
576: if (!ISSET(lflag, ICANON)) {
577: ttwakeup(tp);
578: ttyecho(c, tp);
579: goto endcase;
580: }
1.85 kleink 581: if (TTBREAKC(c, lflag)) {
1.49 cgd 582: tp->t_rocount = 0;
583: catq(&tp->t_rawq, &tp->t_canq);
584: ttwakeup(tp);
585: } else if (tp->t_rocount++ == 0)
586: tp->t_rocol = tp->t_column;
587: if (ISSET(tp->t_state, TS_ERASE)) {
588: /*
589: * end of prterase \.../
590: */
591: CLR(tp->t_state, TS_ERASE);
592: (void)ttyoutput('/', tp);
593: }
594: i = tp->t_column;
595: ttyecho(c, tp);
596: if (CCEQ(cc[VEOF], c) && ISSET(lflag, ECHO)) {
597: /*
598: * Place the cursor over the '^' of the ^D.
599: */
600: i = min(2, tp->t_column - i);
601: while (i > 0) {
602: (void)ttyoutput('\b', tp);
603: i--;
604: }
605: }
606: }
1.125.2.2! nathanw 607: endcase:
1.49 cgd 608: /*
609: * IXANY means allow any character to restart output.
610: */
611: if (ISSET(tp->t_state, TS_TTSTOP) &&
612: !ISSET(iflag, IXANY) && cc[VSTART] != cc[VSTOP])
613: return (0);
1.125.2.2! nathanw 614: restartoutput:
1.49 cgd 615: CLR(tp->t_lflag, FLUSHO);
616: CLR(tp->t_state, TS_TTSTOP);
1.125.2.2! nathanw 617: startoutput:
1.49 cgd 618: return (ttstart(tp));
619: }
620:
621: /*
622: * Output a single character on a tty, doing output processing
623: * as needed (expanding tabs, newline processing, etc.).
624: * Returns < 0 if succeeds, otherwise returns char to resend.
625: * Must be recursive.
626: */
627: int
1.125.2.2! nathanw 628: ttyoutput(int c, struct tty *tp)
1.49 cgd 629: {
1.125.2.2! nathanw 630: long oflag;
! 631: int col, notout, s;
1.49 cgd 632:
633: oflag = tp->t_oflag;
634: if (!ISSET(oflag, OPOST)) {
635: tk_nout++;
636: tp->t_outcc++;
1.99 mycroft 637: if (!ISSET(tp->t_lflag, FLUSHO) && putc(c, &tp->t_outq))
638: return (c);
1.49 cgd 639: return (-1);
640: }
641: /*
1.103 kleink 642: * Do tab expansion if OXTABS is set. Special case if we do external
1.49 cgd 643: * processing, we don't do the tab expansion because we'll probably
644: * get it wrong. If tab expansion needs to be done, let it happen
645: * externally.
646: */
647: CLR(c, ~TTY_CHARMASK);
648: if (c == '\t' &&
649: ISSET(oflag, OXTABS) && !ISSET(tp->t_lflag, EXTPROC)) {
650: c = 8 - (tp->t_column & 7);
651: if (ISSET(tp->t_lflag, FLUSHO)) {
652: notout = 0;
653: } else {
654: s = spltty(); /* Don't interrupt tabs. */
655: notout = b_to_q(" ", c, &tp->t_outq);
656: c -= notout;
657: tk_nout += c;
658: tp->t_outcc += c;
659: splx(s);
660: }
661: tp->t_column += c;
662: return (notout ? '\t' : -1);
663: }
664: if (c == CEOT && ISSET(oflag, ONOEOT))
665: return (-1);
666:
667: /*
668: * Newline translation: if ONLCR is set,
669: * translate newline into "\r\n".
670: */
671: if (c == '\n' && ISSET(tp->t_oflag, ONLCR)) {
672: tk_nout++;
673: tp->t_outcc++;
1.99 mycroft 674: if (!ISSET(tp->t_lflag, FLUSHO) && putc('\r', &tp->t_outq))
1.49 cgd 675: return (c);
676: }
1.103 kleink 677: /* If OCRNL is set, translate "\r" into "\n". */
1.79 kleink 678: else if (c == '\r' && ISSET(tp->t_oflag, OCRNL))
679: c = '\n';
1.103 kleink 680: /* If ONOCR is set, don't transmit CRs when on column 0. */
681: else if (c == '\r' && ISSET(tp->t_oflag, ONOCR) && tp->t_column == 0)
682: return (-1);
1.79 kleink 683:
1.49 cgd 684: tk_nout++;
685: tp->t_outcc++;
686: if (!ISSET(tp->t_lflag, FLUSHO) && putc(c, &tp->t_outq))
687: return (c);
688:
689: col = tp->t_column;
690: switch (CCLASS(c)) {
691: case BACKSPACE:
692: if (col > 0)
693: --col;
694: break;
695: case CONTROL:
696: break;
697: case NEWLINE:
1.103 kleink 698: if (ISSET(tp->t_oflag, ONLCR | ONLRET))
1.79 kleink 699: col = 0;
700: break;
1.49 cgd 701: case RETURN:
702: col = 0;
703: break;
704: case ORDINARY:
705: ++col;
706: break;
707: case TAB:
708: col = (col + 8) & ~7;
709: break;
710: }
711: tp->t_column = col;
712: return (-1);
713: }
714:
715: /*
716: * Ioctls for all tty devices. Called after line-discipline specific ioctl
717: * has been called to do discipline-specific functions and/or reject any
718: * of these ioctl commands.
719: */
720: /* ARGSUSED */
721: int
1.125.2.2! nathanw 722: ttioctl(struct tty *tp, u_long cmd, caddr_t data, int flag, struct proc *p)
1.49 cgd 723: {
724: extern struct tty *constty; /* Temporary virtual console. */
1.125.2.2! nathanw 725: extern int nlinesw;
! 726: struct linesw *lp;
! 727: int s, error;
1.49 cgd 728:
729: /* If the ioctl involves modification, hang if in the background. */
730: switch (cmd) {
731: case TIOCFLUSH:
1.92 kleink 732: case TIOCDRAIN:
1.95 kleink 733: case TIOCSBRK:
734: case TIOCCBRK:
735: case TIOCSTART:
1.49 cgd 736: case TIOCSETA:
737: case TIOCSETD:
1.121 eeh 738: case TIOCSLINED:
1.49 cgd 739: case TIOCSETAF:
740: case TIOCSETAW:
741: #ifdef notdef
742: case TIOCSPGRP:
743: #endif
744: case TIOCSTAT:
745: case TIOCSTI:
746: case TIOCSWINSZ:
1.66 christos 747: #ifdef COMPAT_OLDTTY
1.49 cgd 748: case TIOCLBIC:
749: case TIOCLBIS:
750: case TIOCLSET:
751: case TIOCSETC:
752: case OTIOCSETD:
753: case TIOCSETN:
754: case TIOCSETP:
755: case TIOCSLTC:
756: #endif
1.125.2.1 nathanw 757: while (isbackground(curproc->l_proc, tp) &&
1.49 cgd 758: p->p_pgrp->pg_jobc && (p->p_flag & P_PPWAIT) == 0 &&
1.122 jdolecek 759: !sigismasked(p, SIGTTOU)) {
1.49 cgd 760: pgsignal(p->p_pgrp, SIGTTOU, 1);
1.112 mycroft 761: error = ttysleep(tp, &lbolt, TTOPRI | PCATCH, ttybg, 0);
1.65 christos 762: if (error)
1.49 cgd 763: return (error);
764: }
765: break;
766: }
767:
768: switch (cmd) { /* Process the ioctl. */
769: case FIOASYNC: /* set/clear async i/o */
770: s = spltty();
771: if (*(int *)data)
772: SET(tp->t_state, TS_ASYNC);
773: else
774: CLR(tp->t_state, TS_ASYNC);
775: splx(s);
776: break;
777: case FIONBIO: /* set/clear non-blocking i/o */
778: break; /* XXX: delete. */
779: case FIONREAD: /* get # bytes to read */
780: *(int *)data = ttnread(tp);
781: break;
782: case TIOCEXCL: /* set exclusive use of tty */
783: s = spltty();
784: SET(tp->t_state, TS_XCLUDE);
785: splx(s);
786: break;
787: case TIOCFLUSH: { /* flush buffers */
1.118 augustss 788: int flags = *(int *)data;
1.49 cgd 789:
790: if (flags == 0)
791: flags = FREAD | FWRITE;
792: else
793: flags &= FREAD | FWRITE;
794: ttyflush(tp, flags);
795: break;
796: }
797: case TIOCCONS: /* become virtual console */
798: if (*(int *)data) {
799: if (constty && constty != tp &&
800: ISSET(constty->t_state, TS_CARR_ON | TS_ISOPEN) ==
801: (TS_CARR_ON | TS_ISOPEN))
802: return (EBUSY);
803: #ifndef UCONSOLE
1.65 christos 804: if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
1.49 cgd 805: return (error);
806: #endif
807: constty = tp;
808: } else if (tp == constty)
809: constty = NULL;
810: break;
811: case TIOCDRAIN: /* wait till output drained */
1.65 christos 812: if ((error = ttywait(tp)) != 0)
1.49 cgd 813: return (error);
814: break;
815: case TIOCGETA: { /* get termios struct */
816: struct termios *t = (struct termios *)data;
817:
1.109 perry 818: memcpy(t, &tp->t_termios, sizeof(struct termios));
1.49 cgd 819: break;
820: }
821: case TIOCGETD: /* get line discipline */
1.125.2.2! nathanw 822: *(int *)data = tp->t_linesw->l_no;
1.121 eeh 823: break;
824: case TIOCGLINED:
825: strncpy((char *)data, tp->t_linesw->l_name,
826: TTLINEDNAMELEN);
1.49 cgd 827: break;
828: case TIOCGWINSZ: /* get window size */
829: *(struct winsize *)data = tp->t_winsize;
830: break;
831: case TIOCGPGRP: /* get pgrp of tty */
832: if (!isctty(p, tp))
833: return (ENOTTY);
834: *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
1.104 thorpej 835: break;
836: case TIOCGSID: /* get sid of tty */
837: if (!isctty(p, tp))
838: return (ENOTTY);
839: *(int *)data = tp->t_session->s_sid;
1.49 cgd 840: break;
841: #ifdef TIOCHPCL
842: case TIOCHPCL: /* hang up on last close */
843: s = spltty();
844: SET(tp->t_cflag, HUPCL);
845: splx(s);
846: break;
847: #endif
848: case TIOCNXCL: /* reset exclusive use of tty */
849: s = spltty();
850: CLR(tp->t_state, TS_XCLUDE);
851: splx(s);
852: break;
853: case TIOCOUTQ: /* output queue size */
854: *(int *)data = tp->t_outq.c_cc;
855: break;
856: case TIOCSETA: /* set termios struct */
857: case TIOCSETAW: /* drain output, set */
858: case TIOCSETAF: { /* drn out, fls in, set */
1.118 augustss 859: struct termios *t = (struct termios *)data;
1.49 cgd 860:
861: s = spltty();
862: if (cmd == TIOCSETAW || cmd == TIOCSETAF) {
1.65 christos 863: if ((error = ttywait(tp)) != 0) {
1.49 cgd 864: splx(s);
865: return (error);
866: }
867: if (cmd == TIOCSETAF)
868: ttyflush(tp, FREAD);
869: }
870: if (!ISSET(t->c_cflag, CIGNORE)) {
871: /*
872: * Set device hardware.
873: */
874: if (tp->t_param && (error = (*tp->t_param)(tp, t))) {
875: splx(s);
876: return (error);
877: } else {
878: tp->t_cflag = t->c_cflag;
879: tp->t_ispeed = t->c_ispeed;
880: tp->t_ospeed = t->c_ospeed;
881: if (t->c_ospeed == 0 && tp->t_session &&
882: tp->t_session->s_leader)
883: psignal(tp->t_session->s_leader,
884: SIGHUP);
885: }
886: ttsetwater(tp);
887: }
888: if (cmd != TIOCSETAF) {
889: if (ISSET(t->c_lflag, ICANON) !=
1.110 thorpej 890: ISSET(tp->t_lflag, ICANON)) {
1.49 cgd 891: if (ISSET(t->c_lflag, ICANON)) {
892: SET(tp->t_lflag, PENDIN);
893: ttwakeup(tp);
894: } else {
895: struct clist tq;
896:
897: catq(&tp->t_rawq, &tp->t_canq);
898: tq = tp->t_rawq;
899: tp->t_rawq = tp->t_canq;
900: tp->t_canq = tq;
901: CLR(tp->t_lflag, PENDIN);
902: }
1.110 thorpej 903: }
1.49 cgd 904: }
905: tp->t_iflag = t->c_iflag;
906: tp->t_oflag = t->c_oflag;
907: /*
908: * Make the EXTPROC bit read only.
909: */
910: if (ISSET(tp->t_lflag, EXTPROC))
911: SET(t->c_lflag, EXTPROC);
912: else
913: CLR(t->c_lflag, EXTPROC);
914: tp->t_lflag = t->c_lflag | ISSET(tp->t_lflag, PENDIN);
1.109 perry 915: memcpy(tp->t_cc, t->c_cc, sizeof(t->c_cc));
1.49 cgd 916: splx(s);
917: break;
918: }
919: case TIOCSETD: { /* set line discipline */
1.118 augustss 920: int t = *(int *)data;
1.49 cgd 921:
922: if ((u_int)t >= nlinesw)
923: return (ENXIO);
1.121 eeh 924: lp = linesw[t];
1.124 enami 925: goto setldisc;
1.121 eeh 926: }
927: case TIOCSLINED: { /* set line discipline */
928: char *name = (char *)data;
1.124 enami 929: dev_t device;
1.121 eeh 930:
931: /* Null terminate to prevent buffer overflow */
1.124 enami 932: name[TTLINEDNAMELEN] = 0;
1.121 eeh 933: lp = ttyldisc_lookup(name);
934:
1.125.2.2! nathanw 935: setldisc:
1.124 enami 936: if (lp == NULL)
1.121 eeh 937: return (ENXIO);
938:
939: if (lp != tp->t_linesw) {
1.124 enami 940: device = tp->t_dev;
1.49 cgd 941: s = spltty();
1.124 enami 942: (*tp->t_linesw->l_close)(tp, flag);
1.121 eeh 943: error = (*lp->l_open)(device, tp);
1.49 cgd 944: if (error) {
1.121 eeh 945: (void)(*tp->t_linesw->l_open)(device, tp);
1.49 cgd 946: splx(s);
947: return (error);
948: }
1.121 eeh 949: tp->t_linesw = lp;
1.49 cgd 950: splx(s);
951: }
952: break;
953: }
954: case TIOCSTART: /* start output, like ^Q */
955: s = spltty();
956: if (ISSET(tp->t_state, TS_TTSTOP) ||
957: ISSET(tp->t_lflag, FLUSHO)) {
958: CLR(tp->t_lflag, FLUSHO);
959: CLR(tp->t_state, TS_TTSTOP);
960: ttstart(tp);
961: }
962: splx(s);
963: break;
964: case TIOCSTI: /* simulate terminal input */
965: if (p->p_ucred->cr_uid && (flag & FREAD) == 0)
966: return (EPERM);
967: if (p->p_ucred->cr_uid && !isctty(p, tp))
968: return (EACCES);
1.121 eeh 969: (*tp->t_linesw->l_rint)(*(u_char *)data, tp);
1.49 cgd 970: break;
971: case TIOCSTOP: /* stop output, like ^S */
972: s = spltty();
973: if (!ISSET(tp->t_state, TS_TTSTOP)) {
974: SET(tp->t_state, TS_TTSTOP);
975: (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
976: }
977: splx(s);
978: break;
979: case TIOCSCTTY: /* become controlling tty */
980: /* Session ctty vnode pointer set in vnode layer. */
981: if (!SESS_LEADER(p) ||
1.65 christos 982: ((p->p_session->s_ttyvp || tp->t_session) &&
983: (tp->t_session != p->p_session)))
1.49 cgd 984: return (EPERM);
985: tp->t_session = p->p_session;
986: tp->t_pgrp = p->p_pgrp;
987: p->p_session->s_ttyp = tp;
988: p->p_flag |= P_CONTROLT;
989: break;
990: case TIOCSPGRP: { /* set pgrp of tty */
1.118 augustss 991: struct pgrp *pgrp = pgfind(*(int *)data);
1.49 cgd 992:
993: if (!isctty(p, tp))
994: return (ENOTTY);
1.93 kleink 995: else if (pgrp == NULL)
996: return (EINVAL);
997: else if (pgrp->pg_session != p->p_session)
1.49 cgd 998: return (EPERM);
999: tp->t_pgrp = pgrp;
1000: break;
1001: }
1002: case TIOCSTAT: /* get load avg stats */
1003: ttyinfo(tp);
1004: break;
1005: case TIOCSWINSZ: /* set window size */
1.109 perry 1006: if (memcmp((caddr_t)&tp->t_winsize, data,
1.108 perry 1007: sizeof(struct winsize))) {
1.49 cgd 1008: tp->t_winsize = *(struct winsize *)data;
1009: pgsignal(tp->t_pgrp, SIGWINCH, 1);
1010: }
1011: break;
1012: default:
1.66 christos 1013: #ifdef COMPAT_OLDTTY
1.49 cgd 1014: return (ttcompat(tp, cmd, data, flag, p));
1015: #else
1016: return (-1);
1017: #endif
1018: }
1019: return (0);
1020: }
1021:
1022: int
1.125.2.2! nathanw 1023: ttpoll(dev_t dev, int events, struct proc *p)
! 1024: {
! 1025: struct tty *tp;
! 1026: int revents, s;
1.74 mycroft 1027:
1.125.2.2! nathanw 1028: tp = (*cdevsw[major(dev)].d_tty)(dev);
! 1029: revents = 0;
! 1030: s = spltty();
1.74 mycroft 1031: if (events & (POLLIN | POLLRDNORM))
1032: if (ttnread(tp) > 0)
1033: revents |= events & (POLLIN | POLLRDNORM);
1034:
1035: if (events & (POLLOUT | POLLWRNORM))
1036: if (tp->t_outq.c_cc <= tp->t_lowat)
1037: revents |= events & (POLLOUT | POLLWRNORM);
1038:
1039: if (events & POLLHUP)
1.83 mycroft 1040: if (!CONNECTED(tp))
1.74 mycroft 1041: revents |= POLLHUP;
1042:
1043: if (revents == 0) {
1044: if (events & (POLLIN | POLLHUP | POLLRDNORM))
1045: selrecord(p, &tp->t_rsel);
1.49 cgd 1046:
1.74 mycroft 1047: if (events & (POLLOUT | POLLWRNORM))
1048: selrecord(p, &tp->t_wsel);
1049: }
1.49 cgd 1050:
1051: splx(s);
1.74 mycroft 1052: return (revents);
1.49 cgd 1053: }
1054:
1055: static int
1.125.2.2! nathanw 1056: ttnread(struct tty *tp)
1.49 cgd 1057: {
1.125.2.2! nathanw 1058: int nread;
1.49 cgd 1059:
1060: if (ISSET(tp->t_lflag, PENDIN))
1061: ttypend(tp);
1062: nread = tp->t_canq.c_cc;
1063: if (!ISSET(tp->t_lflag, ICANON)) {
1064: nread += tp->t_rawq.c_cc;
1065: if (nread < tp->t_cc[VMIN] && !tp->t_cc[VTIME])
1066: nread = 0;
1067: }
1068: return (nread);
1069: }
1070:
1071: /*
1072: * Wait for output to drain.
1073: */
1074: int
1075: ttywait(tp)
1.118 augustss 1076: struct tty *tp;
1.49 cgd 1077: {
1.125.2.2! nathanw 1078: int error, s;
1.49 cgd 1079:
1080: error = 0;
1081: s = spltty();
1082: while ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) &&
1.83 mycroft 1083: CONNECTED(tp) && tp->t_oproc) {
1.49 cgd 1084: (*tp->t_oproc)(tp);
1085: SET(tp->t_state, TS_ASLEEP);
1.65 christos 1086: error = ttysleep(tp, &tp->t_outq, TTOPRI | PCATCH, ttyout, 0);
1087: if (error)
1.49 cgd 1088: break;
1089: }
1090: splx(s);
1091: return (error);
1092: }
1093:
1094: /*
1095: * Flush if successfully wait.
1096: */
1097: int
1.125.2.2! nathanw 1098: ttywflush(struct tty *tp)
1.49 cgd 1099: {
1.125.2.2! nathanw 1100: int error;
1.49 cgd 1101:
1102: if ((error = ttywait(tp)) == 0)
1103: ttyflush(tp, FREAD);
1104: return (error);
1105: }
1106:
1107: /*
1108: * Flush tty read and/or write queues, notifying anyone waiting.
1109: */
1110: void
1.125.2.2! nathanw 1111: ttyflush(struct tty *tp, int rw)
1.49 cgd 1112: {
1.125.2.2! nathanw 1113: int s;
1.49 cgd 1114:
1115: s = spltty();
1116: if (rw & FREAD) {
1117: FLUSHQ(&tp->t_canq);
1118: FLUSHQ(&tp->t_rawq);
1119: tp->t_rocount = 0;
1120: tp->t_rocol = 0;
1121: CLR(tp->t_state, TS_LOCAL);
1122: ttwakeup(tp);
1123: }
1124: if (rw & FWRITE) {
1125: CLR(tp->t_state, TS_TTSTOP);
1126: (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
1127: FLUSHQ(&tp->t_outq);
1128: wakeup((caddr_t)&tp->t_outq);
1129: selwakeup(&tp->t_wsel);
1130: }
1131: splx(s);
1132: }
1133:
1134: /*
1135: * Copy in the default termios characters.
1136: */
1137: void
1.125.2.2! nathanw 1138: ttychars(struct tty *tp)
1.49 cgd 1139: {
1140:
1.109 perry 1141: memcpy(tp->t_cc, ttydefchars, sizeof(ttydefchars));
1.49 cgd 1142: }
1143:
1144: /*
1145: * Send stop character on input overflow.
1146: */
1147: static void
1.125.2.2! nathanw 1148: ttyblock(struct tty *tp)
1.49 cgd 1149: {
1.125.2.2! nathanw 1150: int total;
1.49 cgd 1151:
1152: total = tp->t_rawq.c_cc + tp->t_canq.c_cc;
1153: if (tp->t_rawq.c_cc > TTYHOG) {
1154: ttyflush(tp, FREAD | FWRITE);
1155: CLR(tp->t_state, TS_TBLOCK);
1156: }
1157: /*
1158: * Block further input iff: current input > threshold
1159: * AND input is available to user program.
1160: */
1.101 drochner 1161: if (total >= TTYHOG / 2 &&
1162: !ISSET(tp->t_state, TS_TBLOCK) &&
1163: (!ISSET(tp->t_lflag, ICANON) || tp->t_canq.c_cc > 0)) {
1.60 mycroft 1164: if (ISSET(tp->t_iflag, IXOFF) &&
1165: tp->t_cc[VSTOP] != _POSIX_VDISABLE &&
1166: putc(tp->t_cc[VSTOP], &tp->t_outq) == 0) {
1.49 cgd 1167: SET(tp->t_state, TS_TBLOCK);
1168: ttstart(tp);
1169: }
1.59 mycroft 1170: /* Try to block remote output via hardware flow control. */
1.49 cgd 1171: if (ISSET(tp->t_cflag, CHWFLOW) && tp->t_hwiflow &&
1172: (*tp->t_hwiflow)(tp, 1) != 0)
1173: SET(tp->t_state, TS_TBLOCK);
1174: }
1175: }
1176:
1177: void
1.125.2.2! nathanw 1178: ttrstrt(void *tp_arg)
1.49 cgd 1179: {
1.125.2.2! nathanw 1180: struct tty *tp;
! 1181: int s;
1.49 cgd 1182:
1183: #ifdef DIAGNOSTIC
1184: if (tp_arg == NULL)
1185: panic("ttrstrt");
1186: #endif
1187: tp = tp_arg;
1188: s = spltty();
1189:
1190: CLR(tp->t_state, TS_TIMEOUT);
1191: ttstart(tp);
1192:
1193: splx(s);
1194: }
1195:
1196: int
1.125.2.2! nathanw 1197: ttstart(struct tty *tp)
1.49 cgd 1198: {
1199:
1200: if (tp->t_oproc != NULL) /* XXX: Kludge for pty. */
1201: (*tp->t_oproc)(tp);
1202: return (0);
1203: }
1204:
1205: /*
1206: * "close" a line discipline
1207: */
1208: int
1.125.2.2! nathanw 1209: ttylclose(struct tty *tp, int flag)
1.49 cgd 1210: {
1211:
1.61 mycroft 1212: if (flag & FNONBLOCK)
1.49 cgd 1213: ttyflush(tp, FREAD | FWRITE);
1214: else
1215: ttywflush(tp);
1216: return (0);
1217: }
1218:
1219: /*
1220: * Handle modem control transition on a tty.
1221: * Flag indicates new state of carrier.
1222: * Returns 0 if the line should be turned off, otherwise 1.
1223: */
1224: int
1.125.2.2! nathanw 1225: ttymodem(struct tty *tp, int flag)
1.49 cgd 1226: {
1227:
1.83 mycroft 1228: if (flag == 0) {
1.96 kleink 1229: if (ISSET(tp->t_state, TS_CARR_ON)) {
1230: /*
1231: * Lost carrier.
1232: */
1233: CLR(tp->t_state, TS_CARR_ON);
1234: if (ISSET(tp->t_state, TS_ISOPEN) && !CONNECTED(tp)) {
1235: if (tp->t_session && tp->t_session->s_leader)
1236: psignal(tp->t_session->s_leader, SIGHUP);
1237: ttyflush(tp, FREAD | FWRITE);
1238: return (0);
1239: }
1.49 cgd 1240: }
1241: } else {
1.96 kleink 1242: if (!ISSET(tp->t_state, TS_CARR_ON)) {
1243: /*
1244: * Carrier now on.
1245: */
1246: SET(tp->t_state, TS_CARR_ON);
1247: ttwakeup(tp);
1248: }
1.49 cgd 1249: }
1250: return (1);
1251: }
1252:
1253: /*
1254: * Default modem control routine (for other line disciplines).
1255: * Return argument flag, to turn off device on carrier drop.
1256: */
1257: int
1.125.2.2! nathanw 1258: nullmodem(struct tty *tp, int flag)
1.49 cgd 1259: {
1260:
1261: if (flag)
1262: SET(tp->t_state, TS_CARR_ON);
1263: else {
1264: CLR(tp->t_state, TS_CARR_ON);
1.83 mycroft 1265: if (!CONNECTED(tp)) {
1.49 cgd 1266: if (tp->t_session && tp->t_session->s_leader)
1267: psignal(tp->t_session->s_leader, SIGHUP);
1268: return (0);
1269: }
1270: }
1271: return (1);
1272: }
1273:
1274: /*
1275: * Reinput pending characters after state switch
1276: * call at spltty().
1277: */
1278: void
1.125.2.2! nathanw 1279: ttypend(struct tty *tp)
1.49 cgd 1280: {
1.125.2.2! nathanw 1281: struct clist tq;
! 1282: int c;
1.49 cgd 1283:
1284: CLR(tp->t_lflag, PENDIN);
1285: SET(tp->t_state, TS_TYPEN);
1286: tq = tp->t_rawq;
1287: tp->t_rawq.c_cc = 0;
1288: tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
1289: while ((c = getc(&tq)) >= 0)
1290: ttyinput(c, tp);
1291: CLR(tp->t_state, TS_TYPEN);
1292: }
1293:
1294: /*
1295: * Process a read call on a tty device.
1296: */
1297: int
1.125.2.2! nathanw 1298: ttread(struct tty *tp, struct uio *uio, int flag)
1.49 cgd 1299: {
1.125.2.2! nathanw 1300: struct clist *qp;
! 1301: u_char *cc;
! 1302: struct proc *p;
! 1303: int c, s, first, error, has_stime, last_cc;
! 1304: long lflag, slp;
! 1305: struct timeval stime;
1.49 cgd 1306:
1.125.2.2! nathanw 1307: cc = tp->t_cc;
! 1308: p = curproc->l_proc;
! 1309: error = 0;
! 1310: has_stime = 0;
! 1311: last_cc = 0;
! 1312: slp = 0;
! 1313:
! 1314: loop:
! 1315: lflag = tp->t_lflag;
1.49 cgd 1316: s = spltty();
1317: /*
1318: * take pending input first
1319: */
1320: if (ISSET(lflag, PENDIN))
1321: ttypend(tp);
1322: splx(s);
1323:
1324: /*
1325: * Hang process if it's in the background.
1326: */
1327: if (isbackground(p, tp)) {
1.125 jdolecek 1328: if (sigismember(&p->p_sigctx.ps_sigignore, SIGTTIN) ||
1329: sigismember(&p->p_sigctx.ps_sigmask, SIGTTIN) ||
1.49 cgd 1330: p->p_flag & P_PPWAIT || p->p_pgrp->pg_jobc == 0)
1331: return (EIO);
1332: pgsignal(p->p_pgrp, SIGTTIN, 1);
1.65 christos 1333: error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, ttybg, 0);
1334: if (error)
1.49 cgd 1335: return (error);
1336: goto loop;
1337: }
1338:
1339: s = spltty();
1340: if (!ISSET(lflag, ICANON)) {
1341: int m = cc[VMIN];
1342: long t = cc[VTIME];
1343:
1344: qp = &tp->t_rawq;
1345: /*
1346: * Check each of the four combinations.
1347: * (m > 0 && t == 0) is the normal read case.
1348: * It should be fairly efficient, so we check that and its
1349: * companion case (m == 0 && t == 0) first.
1350: * For the other two cases, we compute the target sleep time
1351: * into slp.
1352: */
1353: if (t == 0) {
1354: if (qp->c_cc < m)
1355: goto sleep;
1356: goto read;
1357: }
1358: t *= 100000; /* time in us */
1.125.2.2! nathanw 1359: #define diff(t1, t2) (((t1).tv_sec - (t2).tv_sec) * 1000000 + \
1.49 cgd 1360: ((t1).tv_usec - (t2).tv_usec))
1361: if (m > 0) {
1362: if (qp->c_cc <= 0)
1363: goto sleep;
1364: if (qp->c_cc >= m)
1365: goto read;
1366: if (!has_stime) {
1367: /* first character, start timer */
1368: has_stime = 1;
1369: stime = time;
1370: slp = t;
1371: } else if (qp->c_cc > last_cc) {
1372: /* got a character, restart timer */
1373: stime = time;
1374: slp = t;
1375: } else {
1376: /* nothing, check expiration */
1377: slp = t - diff(time, stime);
1378: }
1379: } else { /* m == 0 */
1380: if (qp->c_cc > 0)
1381: goto read;
1382: if (!has_stime) {
1383: has_stime = 1;
1384: stime = time;
1385: slp = t;
1386: } else
1387: slp = t - diff(time, stime);
1388: }
1.54 mycroft 1389: last_cc = qp->c_cc;
1.49 cgd 1390: #undef diff
1391: if (slp > 0) {
1392: /*
1393: * Rounding down may make us wake up just short
1394: * of the target, so we round up.
1395: * The formula is ceiling(slp * hz/1000000).
1396: * 32-bit arithmetic is enough for hz < 169.
1397: *
1398: * Also, use plain wakeup() not ttwakeup().
1399: */
1400: slp = (long) (((u_long)slp * hz) + 999999) / 1000000;
1401: goto sleep;
1402: }
1403: } else if ((qp = &tp->t_canq)->c_cc <= 0) {
1.125.2.2! nathanw 1404: int carrier;
1.49 cgd 1405:
1.125.2.2! nathanw 1406: sleep:
1.49 cgd 1407: /*
1408: * If there is no input, sleep on rawq
1409: * awaiting hardware receipt and notification.
1410: * If we have data, we don't need to check for carrier.
1411: */
1.83 mycroft 1412: carrier = CONNECTED(tp);
1.49 cgd 1413: if (!carrier && ISSET(tp->t_state, TS_ISOPEN)) {
1414: splx(s);
1415: return (0); /* EOF */
1416: }
1417: if (flag & IO_NDELAY) {
1418: splx(s);
1419: return (EWOULDBLOCK);
1420: }
1421: error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH,
1.53 mycroft 1422: carrier ? ttyin : ttopen, slp);
1.49 cgd 1423: splx(s);
1.82 kleink 1424: /* VMIN == 0: any quantity read satisfies */
1425: if (cc[VMIN] == 0 && error == EWOULDBLOCK)
1426: return (0);
1.54 mycroft 1427: if (error && error != EWOULDBLOCK)
1.49 cgd 1428: return (error);
1429: goto loop;
1430: }
1.125.2.2! nathanw 1431: read:
1.49 cgd 1432: splx(s);
1433:
1434: /*
1435: * Input present, check for input mapping and processing.
1436: */
1437: first = 1;
1438: while ((c = getc(qp)) >= 0) {
1439: /*
1440: * delayed suspend (^Y)
1441: */
1.81 kleink 1442: if (CCEQ(cc[VDSUSP], c) &&
1443: ISSET(lflag, IEXTEN|ISIG) == (IEXTEN|ISIG)) {
1.49 cgd 1444: pgsignal(tp->t_pgrp, SIGTSTP, 1);
1445: if (first) {
1.65 christos 1446: error = ttysleep(tp, &lbolt,
1447: TTIPRI | PCATCH, ttybg, 0);
1448: if (error)
1.49 cgd 1449: break;
1450: goto loop;
1451: }
1452: break;
1453: }
1454: /*
1455: * Interpret EOF only in canonical mode.
1456: */
1457: if (CCEQ(cc[VEOF], c) && ISSET(lflag, ICANON))
1458: break;
1459: /*
1460: * Give user character.
1461: */
1462: error = ureadc(c, uio);
1463: if (error)
1464: break;
1465: if (uio->uio_resid == 0)
1466: break;
1467: /*
1468: * In canonical mode check for a "break character"
1469: * marking the end of a "line of input".
1470: */
1.85 kleink 1471: if (ISSET(lflag, ICANON) && TTBREAKC(c, lflag))
1.49 cgd 1472: break;
1473: first = 0;
1474: }
1475: /*
1476: * Look to unblock output now that (presumably)
1477: * the input queue has gone down.
1478: */
1479: s = spltty();
1480: if (ISSET(tp->t_state, TS_TBLOCK) && tp->t_rawq.c_cc < TTYHOG/5) {
1.60 mycroft 1481: if (ISSET(tp->t_iflag, IXOFF) &&
1482: cc[VSTART] != _POSIX_VDISABLE &&
1.49 cgd 1483: putc(cc[VSTART], &tp->t_outq) == 0) {
1484: CLR(tp->t_state, TS_TBLOCK);
1485: ttstart(tp);
1486: }
1.59 mycroft 1487: /* Try to unblock remote output via hardware flow control. */
1488: if (ISSET(tp->t_cflag, CHWFLOW) && tp->t_hwiflow &&
1.49 cgd 1489: (*tp->t_hwiflow)(tp, 0) != 0)
1.59 mycroft 1490: CLR(tp->t_state, TS_TBLOCK);
1.49 cgd 1491: }
1492: splx(s);
1493: return (error);
1494: }
1495:
1496: /*
1497: * Check the output queue on tp for space for a kernel message (from uprintf
1498: * or tprintf). Allow some space over the normal hiwater mark so we don't
1499: * lose messages due to normal flow control, but don't let the tty run amok.
1500: * Sleeps here are not interruptible, but we return prematurely if new signals
1501: * arrive.
1502: */
1503: int
1.125.2.2! nathanw 1504: ttycheckoutq(struct tty *tp, int wait)
1.49 cgd 1505: {
1.125.2.2! nathanw 1506: int hiwat, s, error;
1.49 cgd 1507:
1508: hiwat = tp->t_hiwat;
1509: s = spltty();
1510: if (tp->t_outq.c_cc > hiwat + 200)
1511: while (tp->t_outq.c_cc > hiwat) {
1512: ttstart(tp);
1.112 mycroft 1513: if (wait == 0) {
1.49 cgd 1514: splx(s);
1515: return (0);
1516: }
1.116 thorpej 1517: callout_reset(&tp->t_outq_ch, hz,
1518: (void (*)__P((void *)))wakeup, &tp->t_outq);
1.49 cgd 1519: SET(tp->t_state, TS_ASLEEP);
1.112 mycroft 1520: error = tsleep(&tp->t_outq, (PZERO - 1) | PCATCH,
1521: "ttckoutq", 0);
1522: if (error == EINTR)
1523: wait = 0;
1.49 cgd 1524: }
1525: splx(s);
1526: return (1);
1527: }
1528:
1529: /*
1530: * Process a write call on a tty device.
1531: */
1532: int
1.125.2.2! nathanw 1533: ttwrite(struct tty *tp, struct uio *uio, int flag)
1.49 cgd 1534: {
1.125.2.2! nathanw 1535: u_char *cp;
! 1536: struct proc *p;
! 1537: int cc, ce, i, hiwat, cnt, error, s;
! 1538: u_char obuf[OBUFSIZ];
1.49 cgd 1539:
1.125.2.2! nathanw 1540: cp = NULL;
1.49 cgd 1541: hiwat = tp->t_hiwat;
1542: cnt = uio->uio_resid;
1543: error = 0;
1544: cc = 0;
1.125.2.2! nathanw 1545: loop:
1.49 cgd 1546: s = spltty();
1.83 mycroft 1547: if (!CONNECTED(tp)) {
1.49 cgd 1548: if (ISSET(tp->t_state, TS_ISOPEN)) {
1549: splx(s);
1550: return (EIO);
1551: } else if (flag & IO_NDELAY) {
1552: splx(s);
1553: error = EWOULDBLOCK;
1554: goto out;
1555: } else {
1556: /* Sleep awaiting carrier. */
1557: error = ttysleep(tp,
1558: &tp->t_rawq, TTIPRI | PCATCH, ttopen, 0);
1559: splx(s);
1560: if (error)
1561: goto out;
1562: goto loop;
1563: }
1564: }
1565: splx(s);
1566: /*
1567: * Hang the process if it's in the background.
1568: */
1.125.2.1 nathanw 1569: p = curproc->l_proc;
1.49 cgd 1570: if (isbackground(p, tp) &&
1571: ISSET(tp->t_lflag, TOSTOP) && (p->p_flag & P_PPWAIT) == 0 &&
1.125 jdolecek 1572: !sigismember(&p->p_sigctx.ps_sigignore, SIGTTOU) &&
1573: !sigismember(&p->p_sigctx.ps_sigmask, SIGTTOU)) {
1.86 kleink 1574: if (p->p_pgrp->pg_jobc == 0) {
1575: error = EIO;
1576: goto out;
1577: }
1.49 cgd 1578: pgsignal(p->p_pgrp, SIGTTOU, 1);
1.65 christos 1579: error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, ttybg, 0);
1580: if (error)
1.49 cgd 1581: goto out;
1582: goto loop;
1583: }
1584: /*
1585: * Process the user's data in at most OBUFSIZ chunks. Perform any
1586: * output translation. Keep track of high water mark, sleep on
1587: * overflow awaiting device aid in acquiring new space.
1588: */
1589: while (uio->uio_resid > 0 || cc > 0) {
1590: if (ISSET(tp->t_lflag, FLUSHO)) {
1591: uio->uio_resid = 0;
1592: return (0);
1593: }
1594: if (tp->t_outq.c_cc > hiwat)
1595: goto ovhiwat;
1596: /*
1597: * Grab a hunk of data from the user, unless we have some
1598: * leftover from last time.
1599: */
1600: if (cc == 0) {
1601: cc = min(uio->uio_resid, OBUFSIZ);
1602: cp = obuf;
1603: error = uiomove(cp, cc, uio);
1604: if (error) {
1605: cc = 0;
1606: break;
1607: }
1608: }
1609: /*
1610: * If nothing fancy need be done, grab those characters we
1611: * can handle without any of ttyoutput's processing and
1612: * just transfer them to the output q. For those chars
1613: * which require special processing (as indicated by the
1614: * bits in char_type), call ttyoutput. After processing
1615: * a hunk of data, look for FLUSHO so ^O's will take effect
1616: * immediately.
1617: */
1618: while (cc > 0) {
1619: if (!ISSET(tp->t_oflag, OPOST))
1620: ce = cc;
1621: else {
1.77 cgd 1622: ce = cc - scanc((u_int)cc, cp, char_type,
1623: CCLASSMASK);
1.49 cgd 1624: /*
1625: * If ce is zero, then we're processing
1626: * a special character through ttyoutput.
1627: */
1628: if (ce == 0) {
1629: tp->t_rocount = 0;
1630: if (ttyoutput(*cp, tp) >= 0) {
1631: /* out of space */
1632: goto overfull;
1633: }
1634: cp++;
1635: cc--;
1636: if (ISSET(tp->t_lflag, FLUSHO) ||
1637: tp->t_outq.c_cc > hiwat)
1638: goto ovhiwat;
1639: continue;
1640: }
1641: }
1642: /*
1643: * A bunch of normal characters have been found.
1644: * Transfer them en masse to the output queue and
1645: * continue processing at the top of the loop.
1646: * If there are any further characters in this
1647: * <= OBUFSIZ chunk, the first should be a character
1648: * requiring special handling by ttyoutput.
1649: */
1650: tp->t_rocount = 0;
1651: i = b_to_q(cp, ce, &tp->t_outq);
1652: ce -= i;
1653: tp->t_column += ce;
1654: cp += ce, cc -= ce, tk_nout += ce;
1655: tp->t_outcc += ce;
1656: if (i > 0) {
1657: /* out of space */
1658: goto overfull;
1659: }
1660: if (ISSET(tp->t_lflag, FLUSHO) ||
1661: tp->t_outq.c_cc > hiwat)
1662: break;
1663: }
1664: ttstart(tp);
1665: }
1.125.2.2! nathanw 1666: out:
1.49 cgd 1667: /*
1668: * If cc is nonzero, we leave the uio structure inconsistent, as the
1669: * offset and iov pointers have moved forward, but it doesn't matter
1670: * (the call will either return short or restart with a new uio).
1671: */
1672: uio->uio_resid += cc;
1673: return (error);
1674:
1.125.2.2! nathanw 1675: overfull:
1.49 cgd 1676: /*
1677: * Since we are using ring buffers, if we can't insert any more into
1678: * the output queue, we can assume the ring is full and that someone
1679: * forgot to set the high water mark correctly. We set it and then
1680: * proceed as normal.
1681: */
1682: hiwat = tp->t_outq.c_cc - 1;
1683:
1.125.2.2! nathanw 1684: ovhiwat:
1.49 cgd 1685: ttstart(tp);
1686: s = spltty();
1687: /*
1688: * This can only occur if FLUSHO is set in t_lflag,
1689: * or if ttstart/oproc is synchronous (or very fast).
1690: */
1691: if (tp->t_outq.c_cc <= hiwat) {
1692: splx(s);
1693: goto loop;
1694: }
1695: if (flag & IO_NDELAY) {
1696: splx(s);
1697: uio->uio_resid += cc;
1698: return (uio->uio_resid == cnt ? EWOULDBLOCK : 0);
1699: }
1700: SET(tp->t_state, TS_ASLEEP);
1701: error = ttysleep(tp, &tp->t_outq, TTOPRI | PCATCH, ttyout, 0);
1702: splx(s);
1703: if (error)
1704: goto out;
1705: goto loop;
1706: }
1707:
1708: /*
1709: * Rubout one character from the rawq of tp
1710: * as cleanly as possible.
1711: */
1712: void
1.125.2.2! nathanw 1713: ttyrub(int c, struct tty *tp)
1.49 cgd 1714: {
1.125.2.2! nathanw 1715: u_char *cp;
! 1716: int savecol, tabc, s;
1.49 cgd 1717:
1718: if (!ISSET(tp->t_lflag, ECHO) || ISSET(tp->t_lflag, EXTPROC))
1719: return;
1720: CLR(tp->t_lflag, FLUSHO);
1721: if (ISSET(tp->t_lflag, ECHOE)) {
1722: if (tp->t_rocount == 0) {
1723: /*
1724: * Screwed by ttwrite; retype
1725: */
1726: ttyretype(tp);
1727: return;
1728: }
1729: if (c == ('\t' | TTY_QUOTE) || c == ('\n' | TTY_QUOTE))
1730: ttyrubo(tp, 2);
1731: else {
1732: CLR(c, ~TTY_CHARMASK);
1733: switch (CCLASS(c)) {
1734: case ORDINARY:
1735: ttyrubo(tp, 1);
1736: break;
1737: case BACKSPACE:
1738: case CONTROL:
1739: case NEWLINE:
1740: case RETURN:
1741: case VTAB:
1742: if (ISSET(tp->t_lflag, ECHOCTL))
1743: ttyrubo(tp, 2);
1744: break;
1745: case TAB:
1746: if (tp->t_rocount < tp->t_rawq.c_cc) {
1747: ttyretype(tp);
1748: return;
1749: }
1750: s = spltty();
1751: savecol = tp->t_column;
1752: SET(tp->t_state, TS_CNTTB);
1753: SET(tp->t_lflag, FLUSHO);
1754: tp->t_column = tp->t_rocol;
1.52 deraadt 1755: for (cp = firstc(&tp->t_rawq, &tabc); cp;
1.49 cgd 1756: cp = nextc(&tp->t_rawq, cp, &tabc))
1757: ttyecho(tabc, tp);
1758: CLR(tp->t_lflag, FLUSHO);
1759: CLR(tp->t_state, TS_CNTTB);
1760: splx(s);
1761:
1762: /* savecol will now be length of the tab. */
1763: savecol -= tp->t_column;
1764: tp->t_column += savecol;
1765: if (savecol > 8)
1766: savecol = 8; /* overflow screw */
1767: while (--savecol >= 0)
1768: (void)ttyoutput('\b', tp);
1769: break;
1770: default: /* XXX */
1771: #define PANICSTR "ttyrub: would panic c = %d, val = %d\n"
1.76 christos 1772: (void)printf(PANICSTR, c, CCLASS(c));
1.49 cgd 1773: #ifdef notdef
1774: panic(PANICSTR, c, CCLASS(c));
1775: #endif
1776: }
1777: }
1778: } else if (ISSET(tp->t_lflag, ECHOPRT)) {
1779: if (!ISSET(tp->t_state, TS_ERASE)) {
1780: SET(tp->t_state, TS_ERASE);
1781: (void)ttyoutput('\\', tp);
1782: }
1783: ttyecho(c, tp);
1784: } else
1785: ttyecho(tp->t_cc[VERASE], tp);
1786: --tp->t_rocount;
1787: }
1788:
1789: /*
1790: * Back over cnt characters, erasing them.
1791: */
1792: static void
1.125.2.2! nathanw 1793: ttyrubo(struct tty *tp, int cnt)
1.49 cgd 1794: {
1795:
1796: while (cnt-- > 0) {
1797: (void)ttyoutput('\b', tp);
1798: (void)ttyoutput(' ', tp);
1799: (void)ttyoutput('\b', tp);
1800: }
1801: }
1802:
1803: /*
1804: * ttyretype --
1805: * Reprint the rawq line. Note, it is assumed that c_cc has already
1806: * been checked.
1807: */
1808: void
1.125.2.2! nathanw 1809: ttyretype(struct tty *tp)
1.49 cgd 1810: {
1.125.2.2! nathanw 1811: u_char *cp;
! 1812: int s, c;
1.49 cgd 1813:
1814: /* Echo the reprint character. */
1815: if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE)
1816: ttyecho(tp->t_cc[VREPRINT], tp);
1817:
1818: (void)ttyoutput('\n', tp);
1819:
1820: s = spltty();
1821: for (cp = firstc(&tp->t_canq, &c); cp; cp = nextc(&tp->t_canq, cp, &c))
1822: ttyecho(c, tp);
1823: for (cp = firstc(&tp->t_rawq, &c); cp; cp = nextc(&tp->t_rawq, cp, &c))
1824: ttyecho(c, tp);
1825: CLR(tp->t_state, TS_ERASE);
1826: splx(s);
1827:
1828: tp->t_rocount = tp->t_rawq.c_cc;
1829: tp->t_rocol = 0;
1830: }
1831:
1832: /*
1833: * Echo a typed character to the terminal.
1834: */
1835: static void
1.125.2.2! nathanw 1836: ttyecho(int c, struct tty *tp)
1.49 cgd 1837: {
1838:
1839: if (!ISSET(tp->t_state, TS_CNTTB))
1840: CLR(tp->t_lflag, FLUSHO);
1841: if ((!ISSET(tp->t_lflag, ECHO) &&
1.64 pk 1842: (!ISSET(tp->t_lflag, ECHONL) || c != '\n')) ||
1.49 cgd 1843: ISSET(tp->t_lflag, EXTPROC))
1844: return;
1.65 christos 1845: if (((ISSET(tp->t_lflag, ECHOCTL) &&
1846: (ISSET(c, TTY_CHARMASK) <= 037 && c != '\t' && c != '\n')) ||
1.49 cgd 1847: ISSET(c, TTY_CHARMASK) == 0177)) {
1848: (void)ttyoutput('^', tp);
1849: CLR(c, ~TTY_CHARMASK);
1850: if (c == 0177)
1851: c = '?';
1852: else
1853: c += 'A' - 1;
1854: }
1855: (void)ttyoutput(c, tp);
1856: }
1857:
1858: /*
1859: * Wake up any readers on a tty.
1860: */
1861: void
1.125.2.2! nathanw 1862: ttwakeup(struct tty *tp)
1.49 cgd 1863: {
1864:
1865: selwakeup(&tp->t_rsel);
1866: if (ISSET(tp->t_state, TS_ASYNC))
1867: pgsignal(tp->t_pgrp, SIGIO, 1);
1868: wakeup((caddr_t)&tp->t_rawq);
1869: }
1870:
1871: /*
1872: * Look up a code for a specified speed in a conversion table;
1873: * used by drivers to map software speed values to hardware parameters.
1874: */
1875: int
1.125.2.2! nathanw 1876: ttspeedtab(int speed, struct speedtab *table)
1.49 cgd 1877: {
1878:
1879: for ( ; table->sp_speed != -1; table++)
1880: if (table->sp_speed == speed)
1881: return (table->sp_code);
1882: return (-1);
1883: }
1884:
1885: /*
1886: * Set tty hi and low water marks.
1887: *
1888: * Try to arrange the dynamics so there's about one second
1889: * from hi to low water.
1890: */
1891: void
1.125.2.2! nathanw 1892: ttsetwater(struct tty *tp)
1.49 cgd 1893: {
1.125.2.2! nathanw 1894: int cps, x;
1.49 cgd 1895:
1.125.2.2! nathanw 1896: #define CLAMP(x, h, l) ((x) > h ? h : ((x) < l) ? l : (x))
1.49 cgd 1897:
1898: cps = tp->t_ospeed / 10;
1899: tp->t_lowat = x = CLAMP(cps / 2, TTMAXLOWAT, TTMINLOWAT);
1900: x += cps;
1901: x = CLAMP(x, TTMAXHIWAT, TTMINHIWAT);
1902: tp->t_hiwat = roundup(x, CBSIZE);
1903: #undef CLAMP
1904: }
1905:
1906: /*
1907: * Report on state of foreground process group.
1908: */
1909: void
1.125.2.2! nathanw 1910: ttyinfo(struct tty *tp)
1.49 cgd 1911: {
1.125.2.2! nathanw 1912: struct lwp *l;
! 1913: struct proc *p, *pick;
! 1914: struct timeval utime, stime;
! 1915: int tmp;
1.49 cgd 1916:
1917: if (ttycheckoutq(tp,0) == 0)
1918: return;
1919:
1920: /* Print load average. */
1921: tmp = (averunnable.ldavg[0] * 100 + FSCALE / 2) >> FSHIFT;
1922: ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100);
1923:
1924: if (tp->t_session == NULL)
1925: ttyprintf(tp, "not a controlling terminal\n");
1926: else if (tp->t_pgrp == NULL)
1927: ttyprintf(tp, "no foreground process group\n");
1.51 mycroft 1928: else if ((p = tp->t_pgrp->pg_members.lh_first) == 0)
1.49 cgd 1929: ttyprintf(tp, "empty foreground process group\n");
1930: else {
1931: /* Pick interesting process. */
1.115 tron 1932: for (pick = NULL; p != NULL; p = p->p_pglist.le_next)
1.49 cgd 1933: if (proc_compare(pick, p))
1934: pick = p;
1935:
1.125.2.1 nathanw 1936: ttyprintf(tp, " cmd: %s %d [", pick->p_comm, pick->p_pid);
1937: LIST_FOREACH(l, &p->p_lwps, l_sibling)
1938: ttyprintf(tp, "%s%s",
1939: l->l_stat == LSONPROC ? "running" :
1940: l->l_stat == LSRUN ? "runnable" :
1941: l->l_wmesg ? l->l_wmesg : "iowait",
1942: (LIST_NEXT(l, l_sibling) != NULL) ? " " : "] ");
1.49 cgd 1943:
1944: calcru(pick, &utime, &stime, NULL);
1945:
1.62 cgd 1946: /* Round up and print user time. */
1947: utime.tv_usec += 5000;
1948: if (utime.tv_usec >= 1000000) {
1949: utime.tv_sec += 1;
1950: utime.tv_usec -= 1000000;
1951: }
1.117 kleink 1952: ttyprintf(tp, "%ld.%02ldu ", (long int)utime.tv_sec,
1953: (long int)utime.tv_usec / 10000);
1.62 cgd 1954:
1955: /* Round up and print system time. */
1956: stime.tv_usec += 5000;
1957: if (stime.tv_usec >= 1000000) {
1958: stime.tv_sec += 1;
1959: stime.tv_usec -= 1000000;
1960: }
1.117 kleink 1961: ttyprintf(tp, "%ld.%02lds ", (long int)stime.tv_sec,
1962: (long int)stime.tv_usec / 10000);
1.49 cgd 1963:
1.123 thorpej 1964: #define pgtok(a) (((u_long) ((a) * PAGE_SIZE) / 1024))
1.90 gwr 1965: /* Print percentage cpu. */
1.66 christos 1966: tmp = (pick->p_pctcpu * 10000 + FSCALE / 2) >> FSHIFT;
1.90 gwr 1967: ttyprintf(tp, "%d%% ", tmp / 100);
1968:
1969: /* Print resident set size. */
1.115 tron 1970: if (pick->p_stat == SIDL || P_ZOMBIE(pick))
1.90 gwr 1971: tmp = 0;
1972: else {
1.118 augustss 1973: struct vmspace *vm = pick->p_vmspace;
1.90 gwr 1974: tmp = pgtok(vm_resident_count(vm));
1975: }
1.91 thorpej 1976: ttyprintf(tp, "%dk\n", tmp);
1.49 cgd 1977: }
1978: tp->t_rocount = 0; /* so pending input will be retyped if BS */
1979: }
1980:
1981: /*
1982: * Returns 1 if p2 is "better" than p1
1983: *
1984: * The algorithm for picking the "interesting" process is thus:
1985: *
1986: * 1) Only foreground processes are eligible - implied.
1987: * 2) Runnable processes are favored over anything else. The runner
1988: * with the highest cpu utilization is picked (p_estcpu). Ties are
1989: * broken by picking the highest pid.
1990: * 3) The sleeper with the shortest sleep time is next. With ties,
1991: * we pick out just "short-term" sleepers (P_SINTR == 0).
1992: * 4) Further ties are broken by picking the highest pid.
1993: */
1.125.2.1 nathanw 1994: #define ISRUN(p) ((p)->p_nrlwps > 0)
1.125.2.2! nathanw 1995: #define TESTAB(a, b) ((a)<<1 | (b))
! 1996: #define ONLYA 2
! 1997: #define ONLYB 1
! 1998: #define BOTH 3
1.49 cgd 1999:
2000: static int
1.125.2.2! nathanw 2001: proc_compare(struct proc *p1, struct proc *p2)
1.49 cgd 2002: {
2003:
2004: if (p1 == NULL)
2005: return (1);
2006: /*
2007: * see if at least one of them is runnable
2008: */
2009: switch (TESTAB(ISRUN(p1), ISRUN(p2))) {
2010: case ONLYA:
2011: return (0);
2012: case ONLYB:
2013: return (1);
2014: case BOTH:
2015: /*
2016: * tie - favor one with highest recent cpu utilization
2017: */
2018: if (p2->p_estcpu > p1->p_estcpu)
2019: return (1);
2020: if (p1->p_estcpu > p2->p_estcpu)
2021: return (0);
2022: return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
2023: }
2024: /*
2025: * weed out zombies
2026: */
1.114 thorpej 2027: switch (TESTAB(P_ZOMBIE(p1), P_ZOMBIE(p2))) {
1.49 cgd 2028: case ONLYA:
2029: return (1);
2030: case ONLYB:
2031: return (0);
2032: case BOTH:
2033: return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
2034: }
1.125.2.1 nathanw 2035: #if 0 /* XXX NJWLWP */
1.49 cgd 2036: /*
2037: * pick the one with the smallest sleep time
2038: */
2039: if (p2->p_slptime > p1->p_slptime)
2040: return (0);
2041: if (p1->p_slptime > p2->p_slptime)
2042: return (1);
2043: /*
2044: * favor one sleeping in a non-interruptible sleep
2045: */
2046: if (p1->p_flag & P_SINTR && (p2->p_flag & P_SINTR) == 0)
2047: return (1);
2048: if (p2->p_flag & P_SINTR && (p1->p_flag & P_SINTR) == 0)
2049: return (0);
1.125.2.1 nathanw 2050: #endif
1.49 cgd 2051: return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
2052: }
2053:
2054: /*
2055: * Output char to tty; console putchar style.
2056: */
2057: int
1.125.2.2! nathanw 2058: tputchar(int c, struct tty *tp)
1.49 cgd 2059: {
1.125.2.2! nathanw 2060: int s;
1.49 cgd 2061:
2062: s = spltty();
2063: if (ISSET(tp->t_state,
2064: TS_CARR_ON | TS_ISOPEN) != (TS_CARR_ON | TS_ISOPEN)) {
2065: splx(s);
2066: return (-1);
2067: }
2068: if (c == '\n')
2069: (void)ttyoutput('\r', tp);
2070: (void)ttyoutput(c, tp);
2071: ttstart(tp);
2072: splx(s);
2073: return (0);
2074: }
2075:
2076: /*
2077: * Sleep on chan, returning ERESTART if tty changed while we napped and
2078: * returning any errors (e.g. EINTR/ETIMEDOUT) reported by tsleep. If
2079: * the tty is revoked, restarting a pending call will redo validation done
2080: * at the start of the call.
2081: */
2082: int
1.125.2.2! nathanw 2083: ttysleep(struct tty *tp, void *chan, int pri, const char *wmesg, int timo)
1.49 cgd 2084: {
1.125.2.2! nathanw 2085: int error;
! 2086: short gen;
1.49 cgd 2087:
2088: gen = tp->t_gen;
1.65 christos 2089: if ((error = tsleep(chan, pri, wmesg, timo)) != 0)
1.49 cgd 2090: return (error);
2091: return (tp->t_gen == gen ? 0 : ERESTART);
2092: }
2093:
2094: /*
1.69 mrg 2095: * Initialise the global tty list.
2096: */
2097: void
1.125.2.2! nathanw 2098: tty_init(void)
1.69 mrg 2099: {
1.121 eeh 2100: ttyldisc_init();
1.71 cgd 2101:
1.69 mrg 2102: TAILQ_INIT(&ttylist);
2103: tty_count = 0;
1.111 thorpej 2104:
2105: pool_init(&tty_pool, sizeof(struct tty), 0, 0, 0, "ttypl",
2106: 0, pool_page_alloc_nointr, pool_page_free_nointr, M_TTYS);
1.69 mrg 2107: }
2108:
2109: /*
2110: * Attach a tty to the tty list.
1.72 mrg 2111: *
2112: * This should be called ONLY once per real tty (including pty's).
2113: * eg, on the sparc, the keyboard and mouse have struct tty's that are
2114: * distinctly NOT usable as tty's, and thus should not be attached to
2115: * the ttylist. This is why this call is not done from ttymalloc().
2116: *
2117: * Device drivers should attach tty's at a similar time that they are
2118: * ttymalloc()'ed, or, for the case of statically allocated struct tty's
2119: * either in the attach or (first) open routine.
1.69 mrg 2120: */
2121: void
1.125.2.2! nathanw 2122: tty_attach(struct tty *tp)
1.69 mrg 2123: {
1.71 cgd 2124:
1.69 mrg 2125: TAILQ_INSERT_TAIL(&ttylist, tp, tty_link);
2126: ++tty_count;
2127: }
2128:
2129: /*
2130: * Remove a tty from the tty list.
2131: */
2132: void
1.125.2.2! nathanw 2133: tty_detach(struct tty *tp)
1.69 mrg 2134: {
1.71 cgd 2135:
1.69 mrg 2136: --tty_count;
2137: #ifdef DIAGNOSTIC
2138: if (tty_count < 0)
2139: panic("tty_detach: tty_count < 0");
2140: #endif
1.70 mrg 2141: TAILQ_REMOVE(&ttylist, tp, tty_link);
1.69 mrg 2142: }
2143:
2144: /*
1.49 cgd 2145: * Allocate a tty structure and its associated buffers.
2146: */
2147: struct tty *
1.125.2.2! nathanw 2148: ttymalloc(void)
1.49 cgd 2149: {
1.125.2.2! nathanw 2150: struct tty *tp;
1.49 cgd 2151:
1.111 thorpej 2152: tp = pool_get(&tty_pool, PR_WAITOK);
1.109 perry 2153: memset(tp, 0, sizeof(*tp));
1.116 thorpej 2154: callout_init(&tp->t_outq_ch);
2155: callout_init(&tp->t_rstrt_ch);
1.84 mycroft 2156: /* XXX: default to 1024 chars for now */
2157: clalloc(&tp->t_rawq, 1024, 1);
2158: clalloc(&tp->t_canq, 1024, 1);
1.49 cgd 2159: /* output queue doesn't need quoting */
1.84 mycroft 2160: clalloc(&tp->t_outq, 1024, 0);
1.121 eeh 2161: /* Set default line discipline. */
2162: tp->t_linesw = linesw[0];
1.49 cgd 2163: return(tp);
2164: }
2165:
2166: /*
2167: * Free a tty structure and its buffers.
1.73 mrg 2168: *
2169: * Be sure to call tty_detach() for any tty that has been
2170: * tty_attach()ed.
1.49 cgd 2171: */
2172: void
1.125.2.2! nathanw 2173: ttyfree(struct tty *tp)
1.49 cgd 2174: {
1.71 cgd 2175:
1.116 thorpej 2176: callout_stop(&tp->t_outq_ch);
2177: callout_stop(&tp->t_rstrt_ch);
1.49 cgd 2178: clfree(&tp->t_rawq);
2179: clfree(&tp->t_canq);
2180: clfree(&tp->t_outq);
1.111 thorpej 2181: pool_put(&tty_pool, tp);
1.49 cgd 2182: }
CVSweb <webmaster@jp.NetBSD.org>