-/* tty.c 6.2 83/09/09 */
+/*
+ * Copyright (c) 1982 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ *
+ * @(#)tty.c 6.22 (Berkeley) %G%
+ */
#include "../machine/reg.h"
-#include "../h/param.h"
-#include "../h/systm.h"
-#include "../h/dir.h"
-#include "../h/user.h"
-#include "../h/ioctl.h"
-#include "../h/tty.h"
-#include "../h/proc.h"
-#include "../h/inode.h"
-#include "../h/file.h"
-#include "../h/conf.h"
-#include "../h/buf.h"
-#include "../h/dk.h"
-#include "../h/uio.h"
-#include "../h/kernel.h"
+#include "param.h"
+#include "systm.h"
+#include "dir.h"
+#include "user.h"
+#include "ioctl.h"
+#include "tty.h"
+#include "proc.h"
+#include "inode.h"
+#include "file.h"
+#include "conf.h"
+#include "buf.h"
+#include "dk.h"
+#include "uio.h"
+#include "kernel.h"
/*
* Table giving parity for characters and indicating
ttywait(tp)
register struct tty *tp;
{
- register int s = spl5();
+ register int s = spltty();
while ((tp->t_outq.c_cc || tp->t_state&TS_BUSY) &&
- tp->t_state&TS_CARR_ON && tp->t_oproc) { /* kludge for pty */
+ tp->t_state&TS_CARR_ON) {
(*tp->t_oproc)(tp);
tp->t_state |= TS_ASLEEP;
sleep((caddr_t)&tp->t_outq, TTOPRI);
{
register s;
- s = spl6();
+ s = spltty();
if (rw & FREAD) {
while (getc(&tp->t_canq) >= 0)
;
if (rw & FREAD) {
while (getc(&tp->t_rawq) >= 0)
;
- tp->t_delct = 0;
tp->t_rocount = 0;
tp->t_rocol = 0;
tp->t_state &= ~TS_LOCAL;
ttyflush(tp, FREAD|FWRITE);
tp->t_state &= ~TS_TBLOCK;
}
- if (x >= TTYHOG/2 && putc(tp->t_stopc, &tp->t_outq) == 0) {
- tp->t_state |= TS_TBLOCK;
- ttstart(tp);
+ /*
+ * Block further input iff:
+ * Current input > threshold AND input is available to user program
+ */
+ if (x >= TTYHOG/2 &&
+ ((tp->t_flags & (RAW|CBREAK)) || (tp->t_canq.c_cc > 0))) {
+ if (putc(tp->t_stopc, &tp->t_outq)==0) {
+ tp->t_state |= TS_TBLOCK;
+ ttstart(tp);
+ }
}
}
{
register s;
- s = spl5();
+ s = spltty();
if ((tp->t_state & (TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 &&
tp->t_oproc) /* kludge for pty */
(*tp->t_oproc)(tp);
/*
* If the ioctl involves modification,
- * insist on being able to write the device,
- * and hang if in the background.
+ * hang if in the background.
*/
switch (com) {
case TIOCLBIC:
case TIOCLSET:
case TIOCSTI:
+ case TIOCSWINSZ:
while (tp->t_line == NTTYDISC &&
u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
(u.u_procp->p_flag&SVFORK) == 0 &&
- u.u_signal[SIGTTOU] != SIG_IGN &&
- u.u_signal[SIGTTOU] != SIG_HOLD) {
+ !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) &&
+ !(u.u_procp->p_sigmask & sigmask(SIGTTOU))) {
gsignal(u.u_procp->p_pgrp, SIGTTOU);
sleep((caddr_t)&lbolt, TTOPRI);
}
register int t = *(int *)data;
int error = 0;
- if (t >= nldisp)
+ if ((unsigned) t >= nldisp)
return (ENXIO);
- s = spl5();
- if (tp->t_line)
- (*linesw[tp->t_line].l_close)(tp);
- if (t)
- error = (*linesw[t].l_open)(dev, tp);
- splx(s);
+ s = spltty();
+ (*linesw[tp->t_line].l_close)(tp);
+ error = (*linesw[t].l_open)(dev, tp);
if (error) {
- s = spl5();
- if (tp->t_line)
- (void) (*linesw[tp->t_line].l_open)(dev, tp);
+ (void) (*linesw[tp->t_line].l_open)(dev, tp);
splx(s);
return (error);
}
tp->t_line = t;
+ splx(s);
break;
}
break;
case TIOCSTOP:
- s = spl5();
+ s = spltty();
if ((tp->t_state&TS_TTSTOP) == 0) {
tp->t_state |= TS_TTSTOP;
(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
break;
case TIOCSTART:
- s = spl5();
+ s = spltty();
if ((tp->t_state&TS_TTSTOP) || (tp->t_flags&FLUSHO)) {
tp->t_state &= ~TS_TTSTOP;
tp->t_flags &= ~FLUSHO;
* Simulate typing of a character at the terminal.
*/
case TIOCSTI:
+ if (u.u_uid && (flag & FREAD) == 0)
+ return (EPERM);
if (u.u_uid && u.u_ttyp != tp)
return (EACCES);
(*linesw[tp->t_line].l_rint)(*(char *)data, tp);
tp->t_ispeed = sg->sg_ispeed;
tp->t_ospeed = sg->sg_ospeed;
newflags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffff);
- s = spl5();
+ s = spltty();
if (tp->t_flags&RAW || newflags&RAW || com == TIOCSETP) {
ttywait(tp);
ttyflush(tp, FREAD);
break;
case TIOCLGET:
- *(int *)data = tp->t_flags >> 16;
+ *(int *)data = ((unsigned) tp->t_flags) >> 16;
break;
- /* should allow SPGRP and GPGRP only if tty open for reading */
- case TIOCSPGRP:
- tp->t_pgrp = *(int *)data;
+ /*
+ * Allow SPGRP only if tty is open for reading.
+ * Quick check: if we can find a process in the new pgrp,
+ * this user must own that process.
+ * SHOULD VERIFY THAT PGRP IS IN USE AND IS THIS USER'S.
+ */
+ case TIOCSPGRP: {
+ struct proc *p;
+ int pgrp = *(int *)data;
+
+ if (u.u_uid && (flag & FREAD) == 0)
+ return (EPERM);
+ p = pfind(pgrp);
+ if (p && p->p_pgrp == pgrp &&
+ p->p_uid != u.u_uid && u.u_uid && !inferior(p))
+ return (EPERM);
+ tp->t_pgrp = pgrp;
break;
+ }
case TIOCGPGRP:
*(int *)data = tp->t_pgrp;
break;
+ case TIOCSWINSZ:
+ if (bcmp((caddr_t)&tp->t_winsize, data,
+ sizeof (struct winsize))) {
+ tp->t_winsize = *(struct winsize *)data;
+ gsignal(tp->t_pgrp, SIGWINCH);
+ }
+ break;
+
+ case TIOCGWINSZ:
+ *(struct winsize *)data = tp->t_winsize;
+ break;
+
default:
return (-1);
}
{
register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
int nread;
- int s = spl5();
+ int s = spltty();
switch (rw) {
case FREAD:
nread = ttnread(tp);
- if (nread > 0)
+ if ((nread > 0) || ((tp->t_state & TS_CARR_ON) == 0))
goto win;
if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
tp->t_state |= TS_RCOLL;
}
/*
+ * Initial open of tty, or (re)entry to line discipline.
* Establish a process group for distribution of
* quits and interrupts from the tty.
*/
pp->p_pgrp = tp->t_pgrp;
}
tp->t_state &= ~TS_WOPEN;
- tp->t_state |= TS_ISOPEN;
- if (tp->t_line != NTTYDISC)
- ttywflush(tp);
+ if ((tp->t_state & TS_ISOPEN) == 0) {
+ tp->t_state |= TS_ISOPEN;
+ bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize));
+ if (tp->t_line != NTTYDISC)
+ ttywflush(tp);
+ }
return (0);
}
+/*
+ * "close" a line discipline
+ */
+ttylclose(tp)
+ register struct tty *tp;
+{
+
+ ttywflush(tp);
+ tp->t_line = 0;
+}
+
/*
* clean tp on last close
*/
register struct tty *tp;
{
- if (tp->t_line) {
- ttywflush(tp);
- tp->t_line = 0;
- return;
- }
+ ttyflush(tp, FREAD|FWRITE);
tp->t_pgrp = 0;
- ttywflush(tp);
tp->t_state = 0;
}
+/*
+ * Handle modem control transition on a tty.
+ * Flag indicates new state of carrier.
+ * Returns 0 if the line should be turned off, otherwise 1.
+ */
+ttymodem(tp, flag)
+ register struct tty *tp;
+{
+
+ if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_flags & MDMBUF)) {
+ /*
+ * MDMBUF: do flow control according to carrier flag
+ */
+ if (flag) {
+ tp->t_state &= ~TS_TTSTOP;
+ ttstart(tp);
+ } else if ((tp->t_state&TS_TTSTOP) == 0) {
+ tp->t_state |= TS_TTSTOP;
+ (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
+ }
+ } else if (flag == 0) {
+ /*
+ * Lost carrier.
+ */
+ tp->t_state &= ~TS_CARR_ON;
+ if (tp->t_state & TS_ISOPEN) {
+ if ((tp->t_flags & NOHANG) == 0) {
+ gsignal(tp->t_pgrp, SIGHUP);
+ gsignal(tp->t_pgrp, SIGCONT);
+ ttyflush(tp, FREAD|FWRITE);
+ return (0);
+ }
+ }
+ } else {
+ /*
+ * Carrier now on.
+ */
+ tp->t_state |= TS_CARR_ON;
+ wakeup((caddr_t)&tp->t_rawq);
+ }
+ return (1);
+}
+
/*
* reinput pending characters after state switch
- * call at spl5().
+ * call at spltty().
*/
ttypend(tp)
register struct tty *tp;
* Ignore any high bit added during
* previous ttyinput processing.
*/
- if ((tp->t_state&TS_TYPEN) == 0)
+ if ((tp->t_state&TS_TYPEN) == 0 && (t_flags&PASS8) == 0)
c &= 0177;
/*
* Check for literal nexting very first
*/
if (tp->t_line == NTTYDISC) {
if (c == tp->t_lnextc) {
- if (tp->t_flags&ECHO)
+ if (t_flags&ECHO)
ttyout("^\b", tp);
tp->t_state |= TS_LNCH;
goto endcase;
}
if (c == tp->t_flushc) {
- if (tp->t_flags&FLUSHO)
+ if (t_flags&FLUSHO)
tp->t_flags &= ~FLUSHO;
else {
ttyflush(tp, FWRITE);
goto startoutput;
}
if (c == tp->t_suspc) {
- if ((tp->t_flags&NOFLSH) == 0)
+ if ((t_flags&NOFLSH) == 0)
ttyflush(tp, FREAD);
ttyecho(c, tp);
gsignal(tp->t_pgrp, SIGTSTP);
* Look for interrupt/quit chars.
*/
if (c == tp->t_intrc || c == tp->t_quitc) {
- if ((tp->t_flags&NOFLSH) == 0)
+ if ((t_flags&NOFLSH) == 0)
ttyflush(tp, FREAD|FWRITE);
ttyecho(c, tp);
gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT);
goto endcase;
}
+ if (tp->t_flags & LCASE && c <= 0177) {
+ if (tp->t_state&TS_BKSL) {
+ ttyrub(unputc(&tp->t_rawq), tp);
+ if (maptab[c])
+ c = maptab[c];
+ c |= 0200;
+ tp->t_state &= ~(TS_BKSL|TS_QUOT);
+ } else if (c >= 'A' && c <= 'Z')
+ c += 'a' - 'A';
+ else if (c == '\\')
+ tp->t_state |= TS_BKSL;
+ }
+
/*
* Cbreak mode, don't process line editing
* characters; check high water mark for wakeup.
goto endcase;
}
if (c == tp->t_kill) {
- if (tp->t_flags&CRTKIL &&
+ if (t_flags&CRTKIL &&
tp->t_rawq.c_cc == tp->t_rocount) {
while (tp->t_rawq.c_cc)
ttyrub(unputc(&tp->t_rawq), tp);
}
i = tp->t_col;
ttyecho(c, tp);
- if (c == tp->t_eofc && tp->t_flags&ECHO) {
+ if (c == tp->t_eofc && t_flags&ECHO) {
i = MIN(2, tp->t_col - i);
while (i > 0) {
(void) ttyoutput('\b', tp);
}
}
}
-
endcase:
/*
* If DEC-style start/stop is enabled don't restart
* output until seeing the start character.
*/
- if (tp->t_flags&DECCTQ && tp->t_state&TS_TTSTOP &&
+ if (t_flags&DECCTQ && tp->t_state&TS_TTSTOP &&
tp->t_startc != tp->t_stopc)
return;
-
restartoutput:
tp->t_state &= ~TS_TTSTOP;
tp->t_flags &= ~FLUSHO;
-
startoutput:
ttstart(tp);
}
c = 8 - (tp->t_col&7);
if ((tp->t_flags&FLUSHO) == 0) {
- s = spl5(); /* don't interrupt tabs */
+ s = spltty(); /* don't interrupt tabs */
c -= b_to_q(" ", c, &tp->t_outq);
tk_nout += c;
splx(s);
register c, t_flags;
int s, first, error = 0;
- if ((tp->t_state&TS_CARR_ON)==0)
- return (EIO);
loop:
/*
* Take any pending input first.
*/
- s = spl5();
+ s = spltty();
if (tp->t_flags&PENDIN)
ttypend(tp);
splx(s);
+ if ((tp->t_state&TS_CARR_ON)==0)
+ return (EIO);
+
/*
* Hang process if it's in the background.
*/
- while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
- if (u.u_signal[SIGTTIN] == SIG_IGN ||
- u.u_signal[SIGTTIN] == SIG_HOLD ||
-/*
- (u.u_procp->p_flag&SDETACH) ||
-*/
+ if (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
+ if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) ||
+ (u.u_procp->p_sigmask & sigmask(SIGTTIN)) ||
u.u_procp->p_flag&SVFORK)
return (EIO);
gsignal(u.u_procp->p_pgrp, SIGTTIN);
sleep((caddr_t)&lbolt, TTIPRI);
+ goto loop;
}
t_flags = tp->t_flags;
* device interrupts when interrogating rawq.
*/
if (t_flags&RAW) {
- s = spl5();
+ s = spltty();
if (tp->t_rawq.c_cc <= 0) {
if ((tp->t_state&TS_CARR_ON) == 0 ||
(tp->t_state&TS_NBIO)) {
splx(s);
- return (0);
+ return (EWOULDBLOCK);
}
sleep((caddr_t)&tp->t_rawq, TTIPRI);
splx(s);
* No input, sleep on rawq awaiting hardware
* receipt and notification.
*/
- s = spl5();
+ s = spltty();
if (qp->c_cc <= 0) {
if ((tp->t_state&TS_CARR_ON) == 0 ||
(tp->t_state&TS_NBIO)) {
while ((c = getc(qp)) >= 0) {
if (t_flags&CRMOD && c == '\r')
c = '\n';
- /*
- * Hack lower case simulation on
- * upper case only terminals.
- */
- if (t_flags&LCASE && c <= 0177)
- if (tp->t_state&TS_BKSL) {
- if (maptab[c])
- c = maptab[c];
- tp->t_state &= ~TS_BKSL;
- } else if (c >= 'A' && c <= 'Z')
- c += 'a' - 'A';
- else if (c == '\\') {
- tp->t_state |= TS_BKSL;
- continue;
- }
/*
* Check for delayed suspend character.
*/
/*
* Give user character.
*/
- error = ureadc(c & 0177, uio);
+ error = ureadc(t_flags&PASS8 ? c : c & 0177, uio);
if (error)
break;
if (uio->uio_resid == 0)
break;
first = 0;
}
- tp->t_state &= ~TS_BKSL;
checktandem:
/*
return (error);
}
+/*
+ * Check the output queue on tp for space for a kernel message
+ * (from uprintf/tprintf). Allow some space over the normal
+ * hiwater mark so we don't lose messages due to normal flow
+ * control, but don't let the tty run amok.
+ */
+ttycheckoutq(tp, wait)
+ register struct tty *tp;
+ int wait;
+{
+ int hiwat, s;
+
+ hiwat = TTHIWAT(tp);
+ s = spltty();
+ if (tp->t_outq.c_cc > hiwat + 200)
+ while (tp->t_outq.c_cc > hiwat) {
+ ttstart(tp);
+ if (wait == 0) {
+ splx(s);
+ return (0);
+ }
+ tp->t_state |= TS_ASLEEP;
+ sleep((caddr_t)&tp->t_outq, TTOPRI);
+ }
+ splx(s);
+ return (1);
+}
+
/*
* Called from the device's write routine after it has
* calculated the tty-structure given as argument.
int i, hiwat, cnt, error, s;
char obuf[OBUFSIZ];
- if ((tp->t_state&TS_CARR_ON) == 0)
- return (EIO);
hiwat = TTHIWAT(tp);
cnt = uio->uio_resid;
error = 0;
loop:
+ if ((tp->t_state&TS_CARR_ON) == 0)
+ return (EIO);
/*
* Hang the process if it's in the background.
*/
- while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
+ if (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
(tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 &&
- u.u_signal[SIGTTOU] != SIG_IGN &&
- u.u_signal[SIGTTOU] != SIG_HOLD
-/*
- &&
- (u.u_procp->p_flag&SDETACH)==0) {
-*/
- ) {
+ !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) &&
+ !(u.u_procp->p_sigmask & sigmask(SIGTTOU))) {
gsignal(u.u_procp->p_pgrp, SIGTTOU);
sleep((caddr_t)&lbolt, TTIPRI);
+ goto loop;
}
/*
if (cc == 0) {
uio->uio_iovcnt--;
uio->uio_iov++;
- if (uio->uio_iovcnt < 0)
+ if (uio->uio_iovcnt <= 0)
panic("ttwrite");
continue;
}
ttstart(tp);
sleep((caddr_t)&lbolt, TTOPRI);
tp->t_rocount = 0;
+ if (cc != 0) {
+ uio->uio_iov->iov_base -= cc;
+ uio->uio_iov->iov_len += cc;
+ uio->uio_resid += cc;
+ uio->uio_offset -= cc;
+ }
+ goto loop;
}
--cc;
if (tp->t_outq.c_cc > hiwat)
if (ce == 0) {
tp->t_rocount = 0;
if (ttyoutput(*cp, tp) >= 0) {
- /* no c-lists, wait a bit */
- ttstart(tp);
- sleep((caddr_t)&lbolt, TTOPRI);
- continue;
+ /* no c-lists, wait a bit */
+ ttstart(tp);
+ sleep((caddr_t)&lbolt, TTOPRI);
+ if (cc != 0) {
+ uio->uio_iov->iov_base -= cc;
+ uio->uio_iov->iov_len += cc;
+ uio->uio_resid += cc;
+ uio->uio_offset -= cc;
+ }
+ goto loop;
}
cp++, cc--;
if (tp->t_flags&FLUSHO ||
/* out of c-lists, wait a bit */
ttstart(tp);
sleep((caddr_t)&lbolt, TTOPRI);
+ uio->uio_iov->iov_base -= cc;
+ uio->uio_iov->iov_len += cc;
+ uio->uio_resid += cc;
+ uio->uio_offset -= cc;
+ goto loop;
}
if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat)
goto ovhiwat;
return (error);
ovhiwat:
- s = spl5();
+ s = spltty();
if (cc != 0) {
uio->uio_iov->iov_base -= cc;
uio->uio_iov->iov_len += cc;
}
ttstart(tp);
if (tp->t_state&TS_NBIO) {
+ splx(s);
if (uio->uio_resid == cnt)
return (EWOULDBLOCK);
return (0);
ttyretype(tp);
return;
}
- s = spl5();
+ s = spltty();
savecol = tp->t_col;
tp->t_state |= TS_CNTTB;
tp->t_flags |= FLUSHO;
if (tp->t_rprntc != 0377)
ttyecho(tp->t_rprntc, tp);
(void) ttyoutput('\n', tp);
- s = spl5();
+ s = spltty();
for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp))
ttyecho(*cp, tp);
for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
c += 'A' - 1;
}
}
- if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z'))
- c += 'a' - 'A';
(void) ttyoutput(c&0177, tp);
}
gsignal(tp->t_pgrp, SIGIO);
wakeup((caddr_t)&tp->t_rawq);
}
-
-#if !defined(vax)
-scanc(size, cp, table, mask)
- register int size;
- register char *cp, table[];
- register int mask;
-{
- register int i = 0;
-
- while ((table[*(u_char *)(cp + i)]&mask) == 0 && i < size)
- i++;
- return (i);
-}
-#endif