aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorhyc@symas.com <hyc@symas.com>2010-06-22 13:14:49 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-08-10 16:47:39 -0400
commit26df6d13406d1a53b0bda08bd712f1924affd7cd (patch)
treedb17328acbd7cac9dc20bc854509527c1c89ca01 /drivers
parenta3c8ed693da9782f924223f65da9261da796e49b (diff)
tty: Add EXTPROC support for LINEMODE
This patch is against the 2.6.34 source. Paraphrased from the 1989 BSD patch by David Borman @ cray.com: These are the changes needed for the kernel to support LINEMODE in the server. There is a new bit in the termios local flag word, EXTPROC. When this bit is set, several aspects of the terminal driver are disabled. Input line editing, character echo, and mapping of signals are all disabled. This allows the telnetd to turn off these functions when in linemode, but still keep track of what state the user wants the terminal to be in. New ioctl: TIOCSIG Generate a signal to processes in the current process group of the pty. There is a new mode for packet driver, the TIOCPKT_IOCTL bit. When packet mode is turned on in the pty, and the EXTPROC bit is set, then whenever the state of the pty is changed, the next read on the master side of the pty will have the TIOCPKT_IOCTL bit set. This allows the process on the server side of the pty to know when the state of the terminal has changed; it can then issue the appropriate ioctl to retrieve the new state. Since the original BSD patches accompanied the source code for telnet I've left that reference here, but obviously the feature is useful for any remote terminal protocol, including ssh. The corresponding feature has existed in the BSD tty driver since 1989. For historical reference, a good copy of the relevant files can be found here: http://anonsvn.mit.edu/viewvc/krb5/trunk/src/appl/telnet/?pathrev=17741 Signed-off-by: Howard Chu <hyc@symas.com> Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/char/n_tty.c17
-rw-r--r--drivers/char/pty.c21
-rw-r--r--drivers/char/tty_ioctl.c18
3 files changed, 47 insertions, 9 deletions
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index bdae8327143c..428f4fe0b5f7 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -1102,6 +1102,11 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
1102 if (I_IUCLC(tty) && L_IEXTEN(tty)) 1102 if (I_IUCLC(tty) && L_IEXTEN(tty))
1103 c = tolower(c); 1103 c = tolower(c);
1104 1104
1105 if (L_EXTPROC(tty)) {
1106 put_tty_queue(c, tty);
1107 return;
1108 }
1109
1105 if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && 1110 if (tty->stopped && !tty->flow_stopped && I_IXON(tty) &&
1106 I_IXANY(tty) && c != START_CHAR(tty) && c != STOP_CHAR(tty) && 1111 I_IXANY(tty) && c != START_CHAR(tty) && c != STOP_CHAR(tty) &&
1107 c != INTR_CHAR(tty) && c != QUIT_CHAR(tty) && c != SUSP_CHAR(tty)) { 1112 c != INTR_CHAR(tty) && c != QUIT_CHAR(tty) && c != SUSP_CHAR(tty)) {
@@ -1409,7 +1414,8 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
1409 1414
1410 n_tty_set_room(tty); 1415 n_tty_set_room(tty);
1411 1416
1412 if (!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) { 1417 if ((!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) ||
1418 L_EXTPROC(tty)) {
1413 kill_fasync(&tty->fasync, SIGIO, POLL_IN); 1419 kill_fasync(&tty->fasync, SIGIO, POLL_IN);
1414 if (waitqueue_active(&tty->read_wait)) 1420 if (waitqueue_active(&tty->read_wait))
1415 wake_up_interruptible(&tty->read_wait); 1421 wake_up_interruptible(&tty->read_wait);
@@ -1585,7 +1591,7 @@ static int n_tty_open(struct tty_struct *tty)
1585static inline int input_available_p(struct tty_struct *tty, int amt) 1591static inline int input_available_p(struct tty_struct *tty, int amt)
1586{ 1592{
1587 tty_flush_to_ldisc(tty); 1593 tty_flush_to_ldisc(tty);
1588 if (tty->icanon) { 1594 if (tty->icanon && !L_EXTPROC(tty)) {
1589 if (tty->canon_data) 1595 if (tty->canon_data)
1590 return 1; 1596 return 1;
1591 } else if (tty->read_cnt >= (amt ? amt : 1)) 1597 } else if (tty->read_cnt >= (amt ? amt : 1))
@@ -1632,6 +1638,11 @@ static int copy_from_read_buf(struct tty_struct *tty,
1632 spin_lock_irqsave(&tty->read_lock, flags); 1638 spin_lock_irqsave(&tty->read_lock, flags);
1633 tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1); 1639 tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
1634 tty->read_cnt -= n; 1640 tty->read_cnt -= n;
1641 /* Turn single EOF into zero-length read */
1642 if (L_EXTPROC(tty) && tty->icanon && n == 1) {
1643 if (!tty->read_cnt && (*b)[n-1] == EOF_CHAR(tty))
1644 n--;
1645 }
1635 spin_unlock_irqrestore(&tty->read_lock, flags); 1646 spin_unlock_irqrestore(&tty->read_lock, flags);
1636 *b += n; 1647 *b += n;
1637 *nr -= n; 1648 *nr -= n;
@@ -1812,7 +1823,7 @@ do_it_again:
1812 nr--; 1823 nr--;
1813 } 1824 }
1814 1825
1815 if (tty->icanon) { 1826 if (tty->icanon && !L_EXTPROC(tty)) {
1816 /* N.B. avoid overrun if nr == 0 */ 1827 /* N.B. avoid overrun if nr == 0 */
1817 while (nr && tty->read_cnt) { 1828 while (nr && tty->read_cnt) {
1818 int eol; 1829 int eol;
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index d83a43130df4..b640ef29be1c 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -171,6 +171,23 @@ static int pty_set_lock(struct tty_struct *tty, int __user *arg)
171 return 0; 171 return 0;
172} 172}
173 173
174/* Send a signal to the slave */
175static int pty_signal(struct tty_struct *tty, int sig)
176{
177 unsigned long flags;
178 struct pid *pgrp;
179
180 if (tty->link) {
181 spin_lock_irqsave(&tty->link->ctrl_lock, flags);
182 pgrp = get_pid(tty->link->pgrp);
183 spin_unlock_irqrestore(&tty->link->ctrl_lock, flags);
184
185 kill_pgrp(pgrp, sig, 1);
186 put_pid(pgrp);
187 }
188 return 0;
189}
190
174static void pty_flush_buffer(struct tty_struct *tty) 191static void pty_flush_buffer(struct tty_struct *tty)
175{ 192{
176 struct tty_struct *to = tty->link; 193 struct tty_struct *to = tty->link;
@@ -321,6 +338,8 @@ static int pty_bsd_ioctl(struct tty_struct *tty, struct file *file,
321 switch (cmd) { 338 switch (cmd) {
322 case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */ 339 case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */
323 return pty_set_lock(tty, (int __user *) arg); 340 return pty_set_lock(tty, (int __user *) arg);
341 case TIOCSIG: /* Send signal to other side of pty */
342 return pty_signal(tty, (int) arg);
324 } 343 }
325 return -ENOIOCTLCMD; 344 return -ENOIOCTLCMD;
326} 345}
@@ -476,6 +495,8 @@ static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file,
476 return pty_set_lock(tty, (int __user *)arg); 495 return pty_set_lock(tty, (int __user *)arg);
477 case TIOCGPTN: /* Get PT Number */ 496 case TIOCGPTN: /* Get PT Number */
478 return put_user(tty->index, (unsigned int __user *)arg); 497 return put_user(tty->index, (unsigned int __user *)arg);
498 case TIOCSIG: /* Send signal to other side of pty */
499 return pty_signal(tty, (int) arg);
479 } 500 }
480 501
481 return -ENOIOCTLCMD; 502 return -ENOIOCTLCMD;
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index 6bd5f8866c74..0c1889971459 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -517,19 +517,25 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
517 517
518 /* See if packet mode change of state. */ 518 /* See if packet mode change of state. */
519 if (tty->link && tty->link->packet) { 519 if (tty->link && tty->link->packet) {
520 int extproc = (old_termios.c_lflag & EXTPROC) |
521 (tty->termios->c_lflag & EXTPROC);
520 int old_flow = ((old_termios.c_iflag & IXON) && 522 int old_flow = ((old_termios.c_iflag & IXON) &&
521 (old_termios.c_cc[VSTOP] == '\023') && 523 (old_termios.c_cc[VSTOP] == '\023') &&
522 (old_termios.c_cc[VSTART] == '\021')); 524 (old_termios.c_cc[VSTART] == '\021'));
523 int new_flow = (I_IXON(tty) && 525 int new_flow = (I_IXON(tty) &&
524 STOP_CHAR(tty) == '\023' && 526 STOP_CHAR(tty) == '\023' &&
525 START_CHAR(tty) == '\021'); 527 START_CHAR(tty) == '\021');
526 if (old_flow != new_flow) { 528 if ((old_flow != new_flow) || extproc) {
527 spin_lock_irqsave(&tty->ctrl_lock, flags); 529 spin_lock_irqsave(&tty->ctrl_lock, flags);
528 tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP); 530 if (old_flow != new_flow) {
529 if (new_flow) 531 tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
530 tty->ctrl_status |= TIOCPKT_DOSTOP; 532 if (new_flow)
531 else 533 tty->ctrl_status |= TIOCPKT_DOSTOP;
532 tty->ctrl_status |= TIOCPKT_NOSTOP; 534 else
535 tty->ctrl_status |= TIOCPKT_NOSTOP;
536 }
537 if (extproc)
538 tty->ctrl_status |= TIOCPKT_IOCTL;
533 spin_unlock_irqrestore(&tty->ctrl_lock, flags); 539 spin_unlock_irqrestore(&tty->ctrl_lock, flags);
534 wake_up_interruptible(&tty->link->read_wait); 540 wake_up_interruptible(&tty->link->read_wait);
535 } 541 }