-/*
- * Copyright (c) 1982, 1986, 1990 Regents of the University of California.
- * All rights reserved. The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+/*-
+ * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.redist.c%
*
- * @(#)tty.c 7.39 (Berkeley) %G%
+ * @(#)tty.c 7.45 (Berkeley) %G%
*/
#include "param.h"
#include "vm/vm.h"
#include "syslog.h"
+static int proc_compare __P((struct proc *p1, struct proc *p2));
+
/* symbolic sleep message strings */
char ttyin[] = "ttyin";
char ttyout[] = "ttyout";
* indicates parity, the 7th bit indicates the character
* is an alphameric or underscore (for ALTWERASE), and the
* low 6 bits indicate delay type. If the low 6 bits are 0
- * then the character needs no special processing on output.
+ * then the character needs no special processing on output;
+ * classes other than 0 might be translated or (not currently)
+ * require delays.
*/
+#define PARITY(c) (partab[c] & 0x80)
+#define ISALPHA(c) (partab[(c)&TTY_CHARMASK] & 0x40)
+#define CCLASSMASK 0x3f
+#define CCLASS(c) (partab[c] & CCLASSMASK)
+
+#define E 0x00 /* even parity */
+#define O 0x80 /* odd parity */
+#define ALPHA 0x40 /* alpha or underscore */
+
+#define NO ORDINARY
+#define NA ORDINARY|ALPHA
+#define CC CONTROL
+#define BS BACKSPACE
+#define NL NEWLINE
+#define TB TAB
+#define VT VTAB
+#define CR RETURN
char partab[] = {
- 0001,0201,0201,0001,0201,0001,0001,0201, /* nul - bel */
- 0202,0004,0003,0201,0005,0206,0201,0001, /* bs - si */
- 0201,0001,0001,0201,0001,0201,0201,0001, /* dle - etb */
- 0001,0201,0201,0001,0201,0001,0001,0201, /* can - us */
- 0200,0000,0000,0200,0000,0200,0200,0000, /* sp - ' */
- 0000,0200,0200,0000,0200,0000,0000,0200, /* ( - / */
- 0100,0300,0300,0100,0300,0100,0100,0300, /* 0 - 7 */
- 0300,0100,0000,0200,0000,0200,0200,0000, /* 8 - ? */
- 0200,0100,0100,0300,0100,0300,0300,0100, /* @ - G */
- 0100,0300,0300,0100,0300,0100,0100,0300, /* H - O */
- 0100,0300,0300,0100,0300,0100,0100,0300, /* P - W */
- 0300,0100,0100,0200,0000,0200,0200,0300, /* X - _ */
- 0000,0300,0300,0100,0300,0100,0100,0300, /* ` - g */
- 0300,0100,0100,0300,0100,0300,0300,0100, /* h - o */
- 0300,0100,0100,0300,0100,0300,0300,0100, /* p - w */
- 0100,0300,0300,0000,0200,0000,0000,0201, /* x - del */
+ E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* nul - bel */
+ O|BS, E|TB, E|NL, O|CC, E|VT, O|CR, O|CC, E|CC, /* bs - si */
+ O|CC, E|CC, E|CC, O|CC, E|CC, O|CC, O|CC, E|CC, /* dle - etb */
+ E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* can - us */
+ O|NO, E|NO, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* sp - ' */
+ E|NO, O|NO, O|NO, E|NO, O|NO, E|NO, E|NO, O|NO, /* ( - / */
+ E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* 0 - 7 */
+ O|NA, E|NA, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* 8 - ? */
+ O|NO, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* @ - G */
+ E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* H - O */
+ E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* P - W */
+ O|NA, E|NA, E|NA, O|NO, E|NO, O|NO, O|NO, O|NA, /* X - _ */
+ E|NO, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* ` - g */
+ O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* h - o */
+ O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* p - w */
+ E|NA, O|NA, O|NA, E|NO, O|NO, E|NO, E|NO, O|CC, /* x - del */
/*
- * meta chars
+ * "meta" chars; should be settable per charset.
+ * For now, treat all as normal characters.
*/
- 0001,0201,0201,0001,0201,0001,0001,0201, /* nul - bel */
- 0202,0004,0003,0201,0005,0206,0201,0001, /* bs - si */
- 0201,0001,0001,0201,0001,0201,0201,0001, /* dle - etb */
- 0001,0201,0201,0001,0201,0001,0001,0201, /* can - us */
- 0200,0000,0000,0200,0000,0200,0200,0000, /* sp - ' */
- 0000,0200,0200,0000,0200,0000,0000,0200, /* ( - / */
- 0100,0300,0300,0100,0300,0100,0100,0300, /* 0 - 7 */
- 0300,0100,0000,0200,0000,0200,0200,0000, /* 8 - ? */
- 0200,0100,0100,0300,0100,0300,0300,0100, /* @ - G */
- 0100,0300,0300,0100,0300,0100,0100,0300, /* H - O */
- 0100,0300,0300,0100,0300,0100,0100,0300, /* P - W */
- 0300,0100,0100,0200,0000,0200,0200,0300, /* X - _ */
- 0000,0300,0300,0100,0300,0100,0100,0300, /* ` - g */
- 0300,0100,0100,0300,0100,0300,0300,0100, /* h - o */
- 0300,0100,0100,0300,0100,0300,0300,0100, /* p - w */
- 0100,0300,0300,0000,0200,0000,0000,0201, /* x - del */
+ NA, NA, NA, NA, NA, NA, NA, NA,
+ NA, NA, NA, NA, NA, NA, NA, NA,
+ NA, NA, NA, NA, NA, NA, NA, NA,
+ NA, NA, NA, NA, NA, NA, NA, NA,
+ NA, NA, NA, NA, NA, NA, NA, NA,
+ NA, NA, NA, NA, NA, NA, NA, NA,
+ NA, NA, NA, NA, NA, NA, NA, NA,
+ NA, NA, NA, NA, NA, NA, NA, NA,
+ NA, NA, NA, NA, NA, NA, NA, NA,
+ NA, NA, NA, NA, NA, NA, NA, NA,
+ NA, NA, NA, NA, NA, NA, NA, NA,
+ NA, NA, NA, NA, NA, NA, NA, NA,
+ NA, NA, NA, NA, NA, NA, NA, NA,
+ NA, NA, NA, NA, NA, NA, NA, NA,
+ NA, NA, NA, NA, NA, NA, NA, NA,
+ NA, NA, NA, NA, NA, NA, NA, NA,
};
+#undef NO
+#undef NA
+#undef CC
+#undef BS
+#undef NL
+#undef TB
+#undef VT
+#undef CR
extern struct tty *constty; /* temporary virtual console */
/*
*
- * Wait for output to drain, then flush input waiting.
+ * Flush tty after output has drained.
*/
ttywflush(tp)
struct tty *tp;
return (error);
}
+#define flushq(qq) { \
+ register struct clist *q = qq; \
+ if (q->c_cc) \
+ ndflush(q, q->c_cc); \
+}
+
/*
- * Flush all TTY queues
+ * Flush TTY read and/or write queues,
+ * notifying anyone waiting.
*/
ttyflush(tp, rw)
register struct tty *tp;
s = spltty();
if (rw & FREAD) {
- while (getc(&tp->t_canq) >= 0)
- ;
+ flushq(&tp->t_canq);
+ flushq(&tp->t_rawq);
+ tp->t_rocount = 0;
+ tp->t_rocol = 0;
+ tp->t_state &= ~TS_LOCAL;
ttwakeup(tp);
}
if (rw & FWRITE) {
- wakeup((caddr_t)&tp->t_outq); /* XXX? what about selwakeup? */
tp->t_state &= ~TS_TTSTOP;
(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
- while (getc(&tp->t_outq) >= 0)
- ;
- }
- if (rw & FREAD) {
- while (getc(&tp->t_rawq) >= 0)
- ;
- tp->t_rocount = 0;
- tp->t_rocol = 0;
- tp->t_state &= ~TS_LOCAL;
+ flushq(&tp->t_outq);
+ wakeup((caddr_t)&tp->t_outq);
+ if (tp->t_wsel) {
+ selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
+ tp->t_wsel = 0;
+ tp->t_state &= ~TS_WCOLL;
+ }
}
splx(s);
}
}
}
-/*
- * Start output on the typewriter. It is used from the top half
- * after some characters have been put on the output queue,
- * from the interrupt routine to transmit the next
- * character.
- */
ttstart(tp)
struct tty *tp;
{
/*
- * Common code for tty ioctls.
+ * Common code for ioctls on tty devices.
+ * Called after line-discipline-specific ioctl
+ * has been called to do discipline-specific functions
+ * and/or reject any of these ioctl commands.
*/
/*ARGSUSED*/
ttioctl(tp, com, data, flag)
return (ENXIO);
if (t != tp->t_line) {
s = spltty();
- (*linesw[tp->t_line].l_close)(tp);
+ (*linesw[tp->t_line].l_close)(tp, flag);
error = (*linesw[t].l_open)(dev, tp);
if (error) {
(void)(*linesw[tp->t_line].l_open)(dev, tp);
}
/*
- * Initial open of tty, or (re)entry to line discipline.
+ * Initial open of tty, or (re)entry to standard tty line discipline.
*/
ttyopen(dev, tp)
dev_t dev;
/*
* "close" a line discipline
*/
-ttylclose(tp)
- register struct tty *tp;
+ttylclose(tp, flag)
+ struct tty *tp;
+ int flag;
{
- ttywflush(tp);
+ if (flag&IO_NDELAY)
+ ttyflush(tp, FREAD|FWRITE);
+ else
+ ttywflush(tp);
}
/*
- * clean tp on last close
+ * Handle close() on a tty line: flush and set to initial state,
+ * bumping generation number so that pending read/write calls
+ * can detect recycling of the tty.
*/
ttyclose(tp)
register struct tty *tp;
}
/*
- *
- *
- * Place a character on raw TTY input queue,
- * putting in delimiters and waking up top
- * half as needed. Also echo if required.
- * The arguments are the character and the
- * appropriate tty structure.
+ * Process input of a single character received on a tty.
*/
ttyinput(c, tp)
register c;
* In tandem mode, check high water mark.
*/
if ((tp->t_state&TS_TYPEN) == 0 && (iflag&ISTRIP))
- c &= 0177;
+ c &= ~0x80;
/*
* Extensions to POSIX input modes which aren't controlled
}
/*
- * Put character on TTY output queue, adding delays,
- * expanding tabs, and handling the CR/NL bit.
- * This is called both from the top half for output,
- * and from interrupt level for echoing.
- * The arguments are the character and the tty structure.
- * Returns < 0 if putc succeeds, otherwise returns char to resend
+ * Output a single character on a tty, doing output processing
+ * as needed (expanding tabs, newline processing, etc.).
+ * Returns < 0 if putc succeeds, otherwise returns char to resend.
* Must be recursive.
*/
ttyoutput(c, tp)
register c;
register struct tty *tp;
{
- register short *colp;
- register ctype;
+ register int col;
if (!(tp->t_oflag&OPOST)) {
if (tp->t_lflag&FLUSHO)
return (-1);
}
c &= 0377;
/*
- * Turn tabs to spaces as required
- *
+ * Do tab expansion if OXTABS is set.
* Special case if we have external processing, we don't
* do the tab expansion because we'll probably get it
* wrong. If tab expansion needs to be done, let it
tp->t_outcc++;
#ifdef notdef
/*
- * turn <nl> to <cr><lf> if desired.
+ * Newline translation: if ONLCR is set,
+ * translate newline into "\r\n".
*/
#endif
if ((tp->t_lflag&FLUSHO) == 0 && putc(c, &tp->t_outq))
if ((tp->t_lflag&FLUSHO) == 0 && putc(c, &tp->t_outq))
return (c);
- colp = &tp->t_col;
- ctype = partab[c];
- switch (ctype&077) {
+ col = tp->t_col;
+ switch (CCLASS(c)) {
case ORDINARY:
- (*colp)++;
+ col++;
case CONTROL:
break;
case BACKSPACE:
- if (*colp)
- (*colp)--;
+ if (col > 0)
+ col--;
break;
case NEWLINE:
- *colp = 0;
+ col = 0;
break;
case TAB:
- *colp |= 07;
- (*colp)++;
+ col = (col + 8) &~ 0x7;
break;
case RETURN:
- *colp = 0;
+ col = 0;
}
+ tp->t_col = col;
return (-1);
}
/*
- * Called from device's read routine after it has
- * calculated the tty-structure given as argument.
+ * Process a read call on a tty device.
*/
ttread(tp, uio, flag)
register struct tty *tp;
hiwat = tp->t_hiwat;
s = spltty();
- oldsig = curproc->p_sig;
+ if (wait)
+ oldsig = curproc->p_sig;
if (tp->t_outq.c_cc > hiwat + 200)
while (tp->t_outq.c_cc > hiwat) {
ttstart(tp);
}
/*
- * Called from the device's write routine after it has
- * calculated the tty-structure given as argument.
+ * Process a write call on a tty device.
*/
ttwrite(tp, uio, flag)
register struct tty *tp;
ce = cc;
else {
ce = cc - scanc((unsigned)cc, (u_char *)cp,
- (u_char *)partab, 077);
+ (u_char *)partab, CCLASSMASK);
/*
* If ce is zero, then we're processing
* a special character through ttyoutput.
/* if tab or newline was escaped - XXX - not 8bit */
if (c == ('\t'|TTY_QUOTE) || c == ('\n'|TTY_QUOTE))
ttyrubo(tp, 2);
- else switch (partab[c&=0377]&077) {
+ else switch (CCLASS(c &= TTY_CHARMASK)) {
case ORDINARY:
#ifdef notdef
default:
/* XXX */
printf("ttyrub: would panic c = %d, val = %d\n",
- c, partab[c&=0377]&077);
+ c, CCLASS(c));
/*panic("ttyrub");*/
}
} else if (tp->t_lflag&ECHOPRT) {
(void) ttyoutput(c, tp);
}
+/*
+ * Wake up any readers on a tty.
+ */
ttwakeup(tp)
register struct tty *tp;
{
}
/*
- * (^T)
* Report on state of foreground process group.
*/
ttyinfo(tp)
- struct tty *tp;
+ register struct tty *tp;
{
- register struct proc *p, *pick = NULL;
- int x, s;
+ register struct proc *p, *pick;
struct timeval utime, stime;
-#define pgtok(a) (((a)*NBPG)/1024)
+ int tmp;
if (ttycheckoutq(tp,0) == 0)
return;
- /*
- * load average
- */
- x = (averunnable[0] * 100 + FSCALE/2) >> FSHIFT;
- ttyprintf(tp, "load: %d.", x/100);
- ttyoutint(x%100, 10, 2, tp);
+
+ /* Print load average. */
+ tmp = (averunnable[0] * 100 + FSCALE / 2) >> FSHIFT;
+ ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100);
+
if (tp->t_session == NULL)
- ttyprintf(tp, " not a controlling terminal\n");
+ ttyprintf(tp, "not a controlling terminal\n");
else if (tp->t_pgrp == NULL)
- ttyprintf(tp, " no foreground process group\n");
+ ttyprintf(tp, "no foreground process group\n");
else if ((p = tp->t_pgrp->pg_mem) == NULL)
- ttyprintf(tp, " empty foreground process group\n");
+ ttyprintf(tp, "empty foreground process group\n");
else {
- /* pick interesting process */
- for (; p != NULL; p = p->p_pgrpnxt) {
+ /* Pick interesting process. */
+ for (pick = NULL; p != NULL; p = p->p_pgrpnxt)
if (proc_compare(pick, p))
pick = p;
- }
- ttyprintf(tp, " cmd: %s %d [%s] ",
- pick->p_comm, pick->p_pid,
- pick->p_stat == SRUN ? "running" :
- pick->p_wmesg ? pick->p_wmesg : "iowait");
- /*
- * cpu time
+
+ ttyprintf(tp, " cmd: %s %d [%s] ", pick->p_comm, pick->p_pid,
+ pick->p_stat == SRUN ? "running" :
+ pick->p_wmesg ? pick->p_wmesg : "iowait");
+
+ /*
+ * Lock out clock if process is running; get user/system
+ * cpu time.
*/
if (curproc == pick)
- s = splclock();
+ tmp = splclock();
utime = pick->p_utime;
stime = pick->p_stime;
if (curproc == pick)
- splx(s);
- /* user time */
- x = (utime.tv_usec + 5000) / 10000; /* scale to 100's */
- ttyoutint(utime.tv_sec, 10, 1, tp);
- tputchar('.', tp);
- ttyoutint(x, 10, 2, tp);
- tputchar('u', tp);
- tputchar(' ', tp);
- /* system time */
- x = (stime.tv_usec + 5000) / 10000; /* scale to 100's */
- ttyoutint(stime.tv_sec, 10, 1, tp);
- tputchar('.', tp);
- ttyoutint(x, 10, 2, tp);
- tputchar('s', tp);
- tputchar(' ', tp);
- /*
- * pctcpu
- */
- x = pick->p_pctcpu * 10000 + FSCALE/2 >> FSHIFT;
- ttyoutint(x/100, 10, 1, tp);
-#ifdef notdef /* do we really want this ??? */
- tputchar('.', tp);
- ttyoutint(x%100, 10, 2, tp);
-#endif
- ttyprintf(tp, "%% %dk\n", pgtok(pick->p_vmspace->vm_rssize));
- }
- tp->t_rocount = 0; /* so pending input will be retyped if BS */
-}
+ splx(tmp);
-ttyoutint(n, base, min, tp)
- register int n, base, min;
- register struct tty *tp;
-{
- char info[16];
- register char *p = info;
+ /* Print user time. */
+ ttyprintf(tp, "%d.%02du ",
+ utime.tv_sec, (utime.tv_usec + 5000) / 10000);
+
+ /* Print system time. */
+ ttyprintf(tp, "%d.%02ds ",
+ stime.tv_sec, (stime.tv_usec + 5000) / 10000);
- while (--min >= 0 || n) {
- *p++ = "0123456789abcdef"[n%base];
- n /= base;
+#define pgtok(a) (((a) * NBPG) / 1024)
+ /* Print percentage cpu, resident set size. */
+ tmp = pick->p_pctcpu * 10000 + FSCALE / 2 >> FSHIFT;
+ ttyprintf(tp, "%d%% %dk\n",
+ tmp / 100, pgtok(pick->p_vmspace->vm_rssize));
}
- while (p > info)
- ttyoutput(*--p, tp);
+ tp->t_rocount = 0; /* so pending input will be retyped if BS */
}
/*
#define ONLYB 1
#define BOTH 3
+static int
proc_compare(p1, p2)
register struct proc *p1, *p2;
{
return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
}
-/* XXX move to subr_prf.c */
-#define TOTTY 0x2 /* XXX should be in header */
-/*VARARGS2*/
-ttyprintf(tp, fmt, x1)
- struct tty *tp;
- char *fmt;
- unsigned x1;
-{
- prf(fmt, &x1, TOTTY, (caddr_t)tp);
-}
-
/*
* Output char to tty; console putchar style.
*/
}
/*
- * Sleep on chan.
- *
- * Return ERESTART if tty changed while we napped.
+ * Sleep on chan, returning ERESTART if tty changed
+ * while we napped and returning any errors (e.g. EINTR/ETIMEDOUT)
+ * reported by tsleep. If the tty is revoked, restarting a pending
+ * call will redo validation done at the start of the call.
*/
ttysleep(tp, chan, pri, wmesg, timo)
struct tty *tp;