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