* Copyright (c) 1982, 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
* @(#)tty.c 7.19 (Berkeley) %G%
* Table giving parity for characters and indicating
* character classes to tty driver. The 8th bit
* 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.
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 */
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 */
extern struct tty
*constty
; /* temporary virtual console */
extern char partab
[], maptab
[];
* Is 'c' a line delimiter ("break" character)?
#define ttbreakc(c) (c == '\n' || CCEQ(cc[VEOF], c) || \
CCEQ(cc[VEOL], c) || CCEQ(cc[VEOL2], c))
#define dprintf if (tp->t_trace & TTRACE_IO)printf
* Is 'c' a line delimiter ("break" character)?
#define ttbreakc(c) (c == '\n' || CCEQ(cc[VEOF], c) || \
CCEQ(cc[VEOL], c) || CCEQ(cc[VEOL2], c))
bcopy(ttydefchars
, tp
->t_cc
, sizeof(ttydefchars
));
* Wait for output to drain, then flush input waiting.
* Wait for output to drain.
* Wait for output to drain.
while ((tp
->t_outq
.c_cc
|| tp
->t_state
&TS_BUSY
) &&
(tp
->t_state
&TS_CARR_ON
|| tp
->t_cflag
&CLOCAL
) &&
tp
->t_state
|= TS_ASLEEP
;
sleep((caddr_t
)&tp
->t_outq
, TTOPRI
);
while (getc(&tp
->t_canq
) >= 0)
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)
while (getc(&tp
->t_rawq
) >= 0)
tp
->t_state
&= ~TS_LOCAL
;
* Send stop character on input overflow.
x
= tp
->t_rawq
.c_cc
+ tp
->t_canq
.c_cc
;
if (tp
->t_rawq
.c_cc
> TTYHOG
) {
ttyflush(tp
, FREAD
|FWRITE
);
tp
->t_state
&= ~TS_TBLOCK
;
* Block further input iff:
* Current input > threshold AND input is available to user program
(!(tp
->t_lflag
&ICANON
)) || (tp
->t_canq
.c_cc
> 0) &&
tp
->t_cc
[VSTOP
] != POSIX_V_DISABLE
) {
if (putc(tp
->t_cc
[VSTOP
], &tp
->t_outq
)==0) {
tp
->t_state
|= TS_TBLOCK
;
* Restart typewriter output following a delay
* The name of the routine is passed to the timeout
* subroutine and it is called during a clock interrupt.
tp
->t_state
&= ~TS_TIMEOUT
;
* 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, and after a timeout has finished.
if (tp
->t_oproc
) /* kludge for pty */
* Common code for tty ioctls.
ttioctl(tp
, com
, data
, flag
)
* If the ioctl involves modification,
* hang if in the background.
/**** these get removed ****
/***************************/
while (isbackground(u
.u_procp
, tp
) &&
u
.u_procp
->p_pgrp
->pg_jobc
&&
(u
.u_procp
->p_flag
&SVFORK
) == 0 &&
!(u
.u_procp
->p_sigignore
& sigmask(SIGTTOU
)) &&
!(u
.u_procp
->p_sigmask
& sigmask(SIGTTOU
))) {
pgsignal(u
.u_procp
->p_pgrp
, SIGTTOU
);
sleep((caddr_t
)&lbolt
, TTOPRI
);
/* get discipline number */
*(int *)data
= tp
->t_line
;
/* set line discipline */
register int t
= *(int *)data
;
if ((unsigned)t
>= nldisp
)
(*linesw
[tp
->t_line
].l_close
)(tp
);
error
= (*linesw
[t
].l_open
)(dev
, tp
);
(void)(*linesw
[tp
->t_line
].l_open
)(dev
, tp
);
if (tp
->t_trace
& TTRACE_STATE
)
/* prevent more opens on channel */
tp
->t_state
|= TS_XCLUDE
;
tp
->t_state
&= ~TS_XCLUDE
;
register int flags
= *(int *)data
;
tp
->t_state
&= ~TS_ASYNC
;
/* return number of characters immediately available */
*(off_t
*)data
= ttnread(tp
);
*(int *)data
= tp
->t_outq
.c_cc
;
if ((tp
->t_state
&TS_TTSTOP
) == 0) {
tp
->t_state
|= TS_TTSTOP
;
(*cdevsw
[major(tp
->t_dev
)].d_stop
)(tp
, 0);
if ((tp
->t_state
&TS_TTSTOP
) || (tp
->t_lflag
&FLUSHO
)) {
tp
->t_state
&= ~TS_TTSTOP
;
* Simulate typing of a character at the terminal.
if (u
.u_uid
&& (flag
& FREAD
) == 0)
if (u
.u_uid
&& !isctty(u
.u_procp
, tp
))
(*linesw
[tp
->t_line
].l_rint
)(*(char *)data
, tp
);
struct termios
*t
= (struct termios
*)data
;
bcopy(&tp
->t_termio
, t
, sizeof(struct termios
));
if (tp
->t_trace
& TTRACE_STATE
)
if (com
== TIOCSETAF
|| com
== TIOCSETAFS
)
if (com
== TIOCSETAW
|| com
== TIOCSETAWS
)
if ((t
->c_lflag
&ICANON
) != (tp
->t_lflag
&ICANON
))
catq(&tp
->t_rawq
, &tp
->t_canq
);
tp
->t_iflag
= t
->c_iflag
;
tp
->t_oflag
= t
->c_oflag
;
tp
->t_lflag
= t
->c_lflag
;
bcopy(t
->c_cc
, tp
->t_cc
, sizeof(t
->c_cc
));
tp
->t_cflag
= t
->c_cflag
;
tp
->t_ispeed
= t
->c_ispeed
;
tp
->t_ospeed
= t
->c_ospeed
;
tp
->t_iflag
= t
->c_iflag
;
tp
->t_oflag
= t
->c_oflag
;
tp
->t_lflag
= t
->c_lflag
;
bcopy(t
->c_cc
, tp
->t_cc
, sizeof(t
->c_cc
));
if (tp
->t_trace
& TTRACE_STATE
)
* Set terminal process group.
register struct proc
*p
= u
.u_procp
;
register struct pgrp
*pgrp
= pgfind(*(int *)data
);
else if (pgrp
->pg_session
!= p
->p_session
)
if (!isctty(u
.u_procp
, tp
))
*(int *)data
= tp
->t_pgrp
? tp
->t_pgrp
->pg_id
: 0;
if (bcmp((caddr_t
)&tp
->t_winsize
, data
,
sizeof (struct winsize
))) {
tp
->t_winsize
= *(struct winsize
*)data
;
pgsignal(tp
->t_pgrp
, SIGWINCH
);
*(struct winsize
*)data
= tp
->t_winsize
;
if (error
= suser(u
.u_cred
, &u
.u_acflag
))
} else if (tp
== constty
)
return(ttcompat(tp
, com
, data
, flag
));
/* allow old ioctls for now */
return(ottioctl(tp
, com
, data
, flag
));
register u_char
*cc
= tp
->t_cc
;
bcopy(u
.u_comm
, comm
, MAXCOMLEN
+1);
/* trace changes to line disciplines */
log(LOG_LOCAL4
|LOG_DEBUG
, "%s:%x:%x:%x:%x\n",
comm
, ioc
, u
.u_procp
->p_pid
, tp
->t_dev
, tp
->t_line
);
* format for the trace record is:
* u_comm:ioctl:pid:dev_t:ldisc:iflag:oflag:lflag:cflag:ispeed:
* u_comm is a string and all other values are hex. "cc's..."
* stands for control chars 0 through NCC-1. seq is a sequence #
* to force syslogd to log every entry (rather than hold them to
* print "last message repeated...".
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",
comm
, ioc
, u
.u_procp
->p_pid
, tp
->t_dev
, tp
->t_line
,
tp
->t_iflag
, tp
->t_oflag
, tp
->t_lflag
, tp
->t_cflag
,
tp
->t_ispeed
, tp
->t_ospeed
, cc
[0], cc
[1], cc
[2], cc
[3],
cc
[4], cc
[5], cc
[6], cc
[7], cc
[8], cc
[9], cc
[10], cc
[11],
cc
[12], cc
[13], cc
[14], cc
[15], cc
[16], cc
[17], cc
[18],
if (tp
->t_lflag
& PENDIN
)
if (tp
->t_lflag
& ICANON
== 0)
nread
+= tp
->t_rawq
.c_cc
;
register struct tty
*tp
= &cdevsw
[major(dev
)].d_ttys
[minor(dev
)];
(!(tp
->t_cflag
&CLOCAL
) && !(tp
->t_state
&TS_CARR_ON
)))
if (tp
->t_rsel
&& tp
->t_rsel
->p_wchan
== (caddr_t
)&selwait
)
if (tp
->t_outq
.c_cc
<= tp
->t_lowat
)
if (tp
->t_wsel
&& tp
->t_wsel
->p_wchan
== (caddr_t
)&selwait
)
* Initial open of tty, or (re)entry to line discipline.
tp
->t_state
&= ~TS_WOPEN
;
if ((tp
->t_state
& TS_ISOPEN
) == 0) {
tp
->t_state
|= TS_ISOPEN
;
bzero((caddr_t
)&tp
->t_winsize
, sizeof(tp
->t_winsize
));
* CHANGE: used to do a ttywflush() if it was the
* old (old) line discipline.
* "close" a line discipline
ttyflush(tp
, FREAD
|FWRITE
);
* Handle modem control transition on a tty.
* Flag indicates new state of carrier.
* Returns 0 if the line should be turned off, otherwise 1.
if ((tp
->t_state
&TS_WOPEN
) == 0 && (tp
->t_lflag
& MDMBUF
)) {
* MDMBUF: do flow control according to carrier flag
tp
->t_state
&= ~TS_TTSTOP
;
} else if ((tp
->t_state
&TS_TTSTOP
) == 0) {
tp
->t_state
|= TS_TTSTOP
;
(*cdevsw
[major(tp
->t_dev
)].d_stop
)(tp
, 0);
tp
->t_state
&= ~TS_CARR_ON
;
if (tp
->t_state
& TS_ISOPEN
) {
if ((tp
->t_lflag
& NOHANG
) == 0) {
pgsignal(tp
->t_pgrp
, SIGHUP
);
pgsignal(tp
->t_pgrp
, SIGCONT
);
ttyflush(tp
, FREAD
|FWRITE
);
tp
->t_state
|= TS_CARR_ON
;
* Default modem control routine (for other line disciplines).
* Return argument flag, to turn off device on carrier drop.
tp
->t_state
|= TS_CARR_ON
;
tp
->t_state
&= ~TS_CARR_ON
;
if ((tp
->t_lflag
& NOHANG
) == 0)
pgsignal(tp
->t_pgrp
, SIGHUP
);
* reinput pending characters after state switch
tp
->t_rawq
.c_cf
= tp
->t_rawq
.c_cl
= 0;
while ((c
= getc(&tq
)) >= 0)
tp
->t_state
&= ~TS_TYPEN
;
* 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.
register int iflag
= tp
->t_iflag
;
register int lflag
= tp
->t_lflag
;
register u_char
*cc
= tp
->t_cc
;
* If input is pending take it first.
* Handle exceptional conditions (break, parity, framing).
if (err
= (c
&TTY_ERRORMASK
)) {
if (err
&TTY_FE
&& !c
) { /* break */
else if (iflag
&BRKINT
&& lflag
&ISIG
&&
(cc
[VINTR
] != POSIX_V_DISABLE
))
} else if ((err
&TTY_PE
&& iflag
&INPCK
) || err
&TTY_FE
) {
* In tandem mode, check high water mark.
* In tandem mode, check high water mark.
if ((tp
->t_state
&TS_TYPEN
) == 0 && (iflag
&ISTRIP
))
* Check for literal nexting very first
if (tp
->t_state
&TS_LNCH
) {
* Scan for special characters. This code
* is really just a big case statement with
* non-constant cases. The bottom of the
* case statement is labeled ``endcase'', so goto
* it after a case match, or similar.
* Extensions to POSIX input modes which aren't controlled
* by ICANON, ISIG, or IXON.
if (CCEQ(cc
[VLNEXT
],c
) && (iflag
&ISTRIP
)) {
ttyout("^\b", tp
); /*XXX - presumes too much */
if (CCEQ(cc
[VFLUSHO
],c
)) {
if (tp
->t_rawq
.c_cc
+ tp
->t_canq
.c_cc
)
if (CCEQ(cc
[VINTR
], c
) || CCEQ(cc
[VQUIT
], c
)) {
ttyflush(tp
, FREAD
|FWRITE
);
gsignal(tp
->t_pgrp
, CCEQ(cc
[VINTR
],c
) ?
pgsignal(tp
->t_pgrp
, SIGTSTP
);
* Handle start/stop characters.
if ((tp
->t_state
&TS_TTSTOP
) == 0) {
tp
->t_state
|= TS_TTSTOP
;
(*cdevsw
[major(tp
->t_dev
)].d_stop
)(tp
, 0);
if (!CCEQ(cc
[VSTART
], c
))
* if VSTART == VSTOP we toggle
else if (c
== '\n' && iflag
&INLCR
)
else if (c
== '\n' && iflag
&INLCR
)
* Non canonical mode, don't process line editing
* characters; check high water mark for wakeup.
if (tp
->t_rawq
.c_cc
> TTYHOG
) {
if (tp
->t_outq
.c_cc
< tp
->t_hiwat
)
(void) ttyoutput(CTRL('g'), tp
);
ttyflush(tp
, FREAD
| FWRITE
);
if (putc(c
, &tp
->t_rawq
) >= 0) {
* From here on down canonical mode character
* processing takes place.
* Oldstyle quoting of erase, kill, and eof chars.
* Historically is '\' , but can be changed (read: disabled)
* with the VQUOTE subscript.
if (CCEQ(cc
[VERASE
], c
)) {
ttyrub(unputc(&tp
->t_rawq
), tp
);
if (lflag
&ECHOKE
&& tp
->t_rawq
.c_cc
== tp
->t_rocount
&&
ttyrub(unputc(&tp
->t_rawq
), tp
);
if (lflag
&ECHOK
|| lflag
&ECHOKE
)
while (getc(&tp
->t_rawq
) > 0)
tp
->t_state
&= ~TS_LOCAL
;
} while (c
!= ' ' && c
!= '\t');
(void) putc(c
, &tp
->t_rawq
);
if (CCEQ(cc
[VREPRINT
], c
)) {
if (CCEQ(cc
[VREPRINT
], c
)) {
* Check for input buffer overflow
if (tp
->t_rawq
.c_cc
+tp
->t_canq
.c_cc
>= TTYHOG
) {
if (tp
->t_outq
.c_cc
< TTHIWAT(tp
))
(void) ttyoutput(CTRL('g'), tp
);
ttyflush(tp
, FREAD
| FWRITE
);
* Put data char in q for user and
* wakeup on seeing a line delimiter.
if (putc(c
, &tp
->t_rawq
) >= 0) {
catq(&tp
->t_rawq
, &tp
->t_canq
);
} else if (tp
->t_rocount
++ == 0)
if (CCEQ(cc
[VQUOTE
], c
) && (iflag
&ISTRIP
))
tp
->t_state
|= TS_QUOT
; /* '\' escape */
if (tp
->t_state
&TS_ERASE
) {
tp
->t_state
&= ~TS_ERASE
;
(void) ttyoutput('/', tp
);
if (CCEQ(cc
[VEOF
], c
) && lflag
&ECHO
) {
* Place the cursor over the '^' of the ^D.
i
= MIN(2, tp
->t_col
- i
);
(void) ttyoutput('\b', tp
);
* IXANY means allow any character to restart output.
if (tp
->t_state
&TS_TTSTOP
&& (iflag
&IXANY
== 0)
&& cc
[VSTART
] != cc
[VSTOP
])
tp
->t_state
&= ~TS_TTSTOP
;
* 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
if (!(tp
->t_oflag
&OPOST
)) {
if (putc(c
, &tp
->t_outq
))
* Turn tabs to spaces as required
if (c
== '\t' && tp
->t_oflag
&OXTABS
) {
if ((tp
->t_lflag
&FLUSHO
) == 0) {
s
= spltty(); /* don't interrupt tabs */
c
-= b_to_q(" ", c
, &tp
->t_outq
);
if (c
== CEOT
&& oflag
&ONOEOT
)
* turn <nl> to <cr><lf> if desired.
if ((tp
->t_lflag
&FLUSHO
) == 0 && putc(c
, &tp
->t_outq
))
if ((tp
->t_lflag
&FLUSHO
) == 0 && putc(c
, &tp
->t_outq
))
* The numbers here represent clock ticks
* and are not necessarily optimal for all terminals.
* SHOULD JUST ALLOW USER TO SPECIFY DELAYS
* (actually, should THROW AWAY terminals which need delays)
* This macro is close enough to the correct thing;
* it should be replaced by real user settable delays
#define mstohz(ms) (((ms) * hz) >> 10)
ctype
= (tp
->t_flags
>> 8) & 03;
if (ctype
== 1) { /* tty 37 */
c
= (((unsigned)*colp
) >> 4) + 3;
} else if (ctype
== 2) /* vt05 */
ctype
= (tp
->t_flags
>> 10) & 03;
if (ctype
== 1) { /* tty 37 */
if (tp
->t_flags
&VTDELAY
) /* tty 37 */
ctype
= (tp
->t_flags
>> 12) & 03;
if (ctype
== 1) /* tn 300 */
else if (ctype
== 2) /* ti 700 */
else if (ctype
== 3) { /* concept 100 */
(void) putc(0177, &tp
->t_outq
);
if (c
&& (tp
->t_lflag
&FLUSHO
) == 0)
(void) putc(c
|TTY_QUOTE
, &tp
->t_outq
);
* Called from device's read routine after it has
* calculated the tty-structure given as argument.
register struct clist
*qp
;
register long lflag
= tp
->t_lflag
;
register long iflag
= tp
->t_iflag
;
register u_char
*cc
= tp
->t_cc
;
* take pending input first
if (!(tp
->t_state
&TS_CARR_ON
) && !(tp
->t_cflag
&CLOCAL
)) {
if (tp
->t_state
&TS_ISOPEN
) {
} else if (flag
& IO_NDELAY
) {
sleep((caddr_t
)&tp
->t_rawq
, TTIPRI
);
* Hang process if it's in the background.
if (isbackground(u
.u_procp
, tp
)) {
if ((u
.u_procp
->p_sigignore
& sigmask(SIGTTIN
)) ||
(u
.u_procp
->p_sigmask
& sigmask(SIGTTIN
)) ||
u
.u_procp
->p_flag
&SVFORK
|| u
.u_procp
->p_pgrp
->pg_jobc
== 0)
pgsignal(u
.u_procp
->p_pgrp
, SIGTTIN
);
sleep((caddr_t
)&lbolt
, TTIPRI
);
* If canonical, use the canonical queue,
* else use the raw queue.
qp
= lflag
&ICANON
? &tp
->t_canq
: &tp
->t_rawq
;
* No input, sleep on rawq awaiting hardware
* receipt and notification.
/** XXX ??? ask mike why TS_CARR_ON was (once) necessary here
if ((tp->t_state&TS_CARR_ON) == 0 ||
sleep((caddr_t
)&tp
->t_rawq
, TTIPRI
);
* Input present, check for input mapping and processing.
while ((c
= getc(qp
)) >= 0) {
if (CCEQ(cc
[VDSUSP
], c
) && lflag
&ISIG
) {
pgsignal(tp
->t_pgrp
, SIGTSTP
);
sleep((caddr_t
)&lbolt
, TTIPRI
);
* Interpret EOF only in canonical mode.
if (CCEQ(cc
[VEOF
], c
) && lflag
&ICANON
)
error
= ureadc(iflag
&ISTRIP
? c
& 0177 : c
, uio
);
* In canonical mode check for a "break character"
* marking the end of a "line of input".
if (lflag
&ICANON
&& ttbreakc(c
)) {
* Look to unblock output now that (presumably)
* the input queue has gone down.
if (tp
->t_state
&TS_TBLOCK
&& tp
->t_rawq
.c_cc
< TTYHOG
/5) {
if (cc
[VSTART
] != POSIX_V_DISABLE
&& putc(cc
[VSTART
], &tp
->t_outq
) == 0) {
tp
->t_state
&= ~TS_TBLOCK
;
* 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.
* Sleeps here are not interruptible, but we return prematurely
* if new signals come in.
oldsig
= u
.u_procp
->p_sig
;
if (tp
->t_outq
.c_cc
> hiwat
+ 200)
while (tp
->t_outq
.c_cc
> hiwat
) {
if (wait
== 0 || u
.u_procp
->p_sig
!= oldsig
) {
timeout(wakeup
, (caddr_t
)&tp
->t_outq
, hz
);
tp
->t_state
|= TS_ASLEEP
;
sleep((caddr_t
)&tp
->t_outq
, PZERO
- 1);
* Called from the device's write routine after it has
* calculated the tty-structure given as argument.
register struct uio
*uio
;
int i
, hiwat
, cnt
, error
, s
;
if (!(tp
->t_state
&TS_CARR_ON
) && !(tp
->t_cflag
&CLOCAL
)) {
if (tp
->t_state
&TS_ISOPEN
) {
} else if (flag
& IO_NDELAY
) {
sleep((caddr_t
)&tp
->t_rawq
, TTIPRI
);
* Hang the process if it's in the background.
(tp
->t_lflag
&TOSTOP
) && (u
.u_procp
->p_flag
&SVFORK
)==0 &&
!(u
.u_procp
->p_sigignore
& sigmask(SIGTTOU
)) &&
!(u
.u_procp
->p_sigmask
& sigmask(SIGTTOU
)) &&
u
.u_procp
->p_pgrp
->pg_jobc
) {
pgsignal(u
.u_procp
->p_pgrp
, SIGTTOU
);
sleep((caddr_t
)&lbolt
, TTIPRI
);
* Process the user's data in at most OBUFSIZ
* chunks. Perform lower case simulation and
* similar hacks. Keep track of high water
* mark, sleep on overflow awaiting device aid
* in acquiring new space.
while (uio
->uio_resid
> 0) {
if (tp
->t_outq
.c_cc
> hiwat
) {
* Grab a hunk of data from the user.
cc
= uio
->uio_iov
->iov_len
;
if (uio
->uio_iovcnt
<= 0)
error
= uiomove(cp
, cc
, uio
);
* If nothing fancy need be done, grab those characters we
* can handle without any of ttyoutput's processing and
* just transfer them to the output q. For those chars
* which require special processing (as indicated by the
* bits in partab), call ttyoutput. After processing
* a hunk of data, look for FLUSHO so ^O's will take effect
if (!(tp
->t_oflag
&OPOST
))
ce
= cc
- scanc((unsigned)cc
, (u_char
*)cp
,
* If ce is zero, then we're processing
* a special character through ttyoutput.
if (ttyoutput(*cp
, tp
) >= 0) {
/* no c-lists, wait a bit */
sleep((caddr_t
)&lbolt
, TTOPRI
);
uio
->uio_iov
->iov_base
-= cc
;
uio
->uio_iov
->iov_len
+= cc
;
if (tp
->t_lflag
&FLUSHO
||
* A bunch of normal characters have been found,
* transfer them en masse to the output queue and
* continue processing at the top of the loop.
* If there are any further characters in this
* <= OBUFSIZ chunk, the first should be a character
* requiring special handling by ttyoutput.
i
= b_to_q(cp
, ce
, &tp
->t_outq
);
cp
+= ce
, cc
-= ce
, tk_nout
+= ce
;
/* out of c-lists, wait a bit */
sleep((caddr_t
)&lbolt
, TTOPRI
);
uio
->uio_iov
->iov_base
-= cc
;
uio
->uio_iov
->iov_len
+= cc
;
if (tp
->t_lflag
&FLUSHO
|| tp
->t_outq
.c_cc
> hiwat
)
uio
->uio_iov
->iov_base
-= cc
;
uio
->uio_iov
->iov_len
+= cc
;
* This can only occur if FLUSHO is set in t_lflag,
* or if ttstart/oproc is synchronous (or very fast).
if (tp
->t_outq
.c_cc
<= hiwat
) {
if (uio
->uio_resid
== cnt
)
tp
->t_state
|= TS_ASLEEP
;
sleep((caddr_t
)&tp
->t_outq
, TTOPRI
);
* Rubout one character from the rawq of tp
* as cleanly as possible.
if ((tp
->t_lflag
&ECHO
) == 0)
if (tp
->t_rocount
== 0) {
* Screwed by ttwrite; retype
/* if tab or newline was escaped - XXX - not 8bit */
if (c
== ('\t'|TTY_QUOTE
) || c
== ('\n'|TTY_QUOTE
))
else switch (partab
[c
&=0377]&077) {
if (tp
->t_rocount
< tp
->t_rawq
.c_cc
) {
tp
->t_state
&= ~TS_CNTTB
;
* savecol will now be length of the tab
savecol
= 8; /* overflow screw */
(void) ttyoutput('\b', tp
);
printf("ttyrub: would panic c = %d, val = %d\n",
} else if (tp
->t_lflag
&ECHOPRT
) {
if ((tp
->t_state
&TS_ERASE
) == 0) {
(void) ttyoutput('\\', tp
);
ttyecho(tp
->t_cc
[VERASE
], tp
);
* Crt back over cnt chars perhaps
register char *rubostring
= tp
->t_lflag
&ECHOE
? "\b \b" : "\b";
* We assume c_cc has already been checked.
if (tp
->t_cc
[VREPRINT
] != POSIX_V_DISABLE
)
ttyecho(tp
->t_cc
[VREPRINT
], tp
);
(void) ttyoutput('\n', tp
);
/*** XXX *** FIX *** NEXTC IS BROKEN - DOESN'T CHECK QUOTE
for (cp
= tp
->t_canq
.c_cf
, c
=(cp
?*cp
:0); cp
; cp
= nextc(&tp
->t_canq
, cp
, &c
)) {
for (cp
= tp
->t_rawq
.c_cf
, c
=(cp
?*cp
:0); cp
; cp
= nextc(&tp
->t_rawq
, cp
, &c
)) {
tp
->t_state
&= ~TS_ERASE
;
tp
->t_rocount
= tp
->t_rawq
.c_cc
;
* Echo a typed character to the terminal.
if ((tp
->t_state
&TS_CNTTB
) == 0)
if ((tp
->t_lflag
&ECHO
) == 0 && !(tp
->t_lflag
&ECHONL
&& c
== '\n'))
if (tp
->t_lflag
&ECHOCTL
) {
if ((c
&TTY_CHARMASK
)<=037 && c
!='\t' && c
!='\n' || c
==0177) {
(void) ttyoutput('^', tp
);
selwakeup(tp
->t_rsel
, tp
->t_state
&TS_RCOLL
);
tp
->t_state
&= ~TS_RCOLL
;
if (tp
->t_state
& TS_ASYNC
)
pgsignal(tp
->t_pgrp
, SIGIO
);
wakeup((caddr_t
)&tp
->t_rawq
);
* set tty hi and low water marks
* Try to arrange the dynamics so there's about one second
register cps
= tp
->t_ospeed
/ 10;
#define clamp(x, h, l) ((x)>h ? h : ((x)<l) ? l : (x))
tp
->t_lowat
= x
= clamp(cps
/2, TTMAXLOWAT
, TTMINLOWAT
);
x
= clamp(x
, TTMAXHIWAT
, TTMINHIWAT
);
tp
->t_hiwat
= roundup(x
, CBSIZE
);
for (i
= 0; table
[i
].sp_speed
!= -1; i
++)
if (table
[i
].sp_speed
== speed
)
return(table
[i
].sp_code
);
* Report on state of foreground process group.
if (ttycheckoutq(tp
,0) == 0)
if (tp
->t_session
== NULL
)
ttyprintf(tp
, "kernel: not a controlling terminal\n");
else if (tp
->t_pgrp
== NULL
||
(p
= tp
->t_pgrp
->pg_mem
) == NULL
)
ttyprintf(tp
, "kernel: no foreground process group\n");
for (; p
!= NULL
; p
= p
->p_pgrpnxt
) {
"kernel: pid: %d state: %x wchan: %x ticks: %d\n",
p
->p_pid
, p
->p_stat
, p
->p_wchan
, p
->p_cpticks
);
ttyprintf(tp
, "kernel: more...\n");
#define TOTTY 0x2 /* XXX should be in header */
prf(fmt
, &x1
, TOTTY
, (caddr_t
)tp
);
* Output char to tty; console putchar style.
if ((tp
->t_state
& (TS_CARR_ON
| TS_ISOPEN
))
== (TS_CARR_ON
| TS_ISOPEN
)) {
(void) ttyoutput('\r', tp
);