📄 tty_ioctl.c
字号:
/*
* linux/kernel/drivers/char/tty_ioctl.c
*
* Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
*
* Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
* which can be dynamically activated and de-activated by the line
* discipline handling modules (like SLIP).
*/
#include <linux/types.h>
#include <linux/termios.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/tty.h>
#include <linux/fcntl.h>
#include <linux/string.h>
#include <asm/io.h>
#include <asm/bitops.h>
#include <asm/segment.h>
#include <asm/system.h>
#undef DEBUG
#ifdef DEBUG
# define PRINTK(x) printk (x)
#else
# define PRINTK(x) /**/
#endif
extern int session_of_pgrp(int pgrp);
extern int do_screendump(int arg);
extern int kill_pg(int pgrp, int sig, int priv);
#ifdef CONFIG_SELECTION
extern int set_selection(const int arg);
extern int paste_selection(struct tty_struct *tty);
#endif /* CONFIG_SELECTION */
static int tty_set_ldisc(struct tty_struct *tty, int ldisc);
void flush_input(struct tty_struct * tty)
{
cli();
tty->read_q.head = tty->read_q.tail = 0;
tty->secondary.head = tty->secondary.tail = 0;
tty->canon_head = tty->canon_data = tty->erasing = 0;
memset(&tty->readq_flags, 0, sizeof tty->readq_flags);
memset(&tty->secondary_flags, 0, sizeof tty->secondary_flags);
sti();
if (!tty->link)
return;
/* No cli() since ptys don't use interrupts. */
tty->link->write_q.head = tty->link->write_q.tail = 0;
wake_up_interruptible(&tty->link->write_q.proc_list);
if (tty->link->packet) {
tty->ctrl_status |= TIOCPKT_FLUSHREAD;
wake_up_interruptible(&tty->link->secondary.proc_list);
}
}
void flush_output(struct tty_struct * tty)
{
cli();
tty->write_q.head = tty->write_q.tail = 0;
sti();
wake_up_interruptible(&tty->write_q.proc_list);
if (!tty->link)
return;
/* No cli() since ptys don't use interrupts. */
tty->link->read_q.head = tty->link->read_q.tail = 0;
tty->link->secondary.head = tty->link->secondary.tail = 0;
tty->link->canon_head = tty->link->canon_data = tty->link->erasing = 0;
memset(&tty->link->readq_flags, 0, sizeof tty->readq_flags);
memset(&tty->link->secondary_flags, 0, sizeof tty->secondary_flags);
if (tty->link->packet) {
tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
wake_up_interruptible(&tty->link->secondary.proc_list);
}
}
void wait_until_sent(struct tty_struct * tty, int timeout)
{
struct wait_queue wait = { current, NULL };
TTY_WRITE_FLUSH(tty);
if (EMPTY(&tty->write_q))
return;
add_wait_queue(&tty->write_q.proc_list, &wait);
current->counter = 0; /* make us low-priority */
if (timeout)
current->timeout = timeout + jiffies;
else
current->timeout = (unsigned) -1;
do {
current->state = TASK_INTERRUPTIBLE;
if (current->signal & ~current->blocked)
break;
TTY_WRITE_FLUSH(tty);
if (EMPTY(&tty->write_q))
break;
schedule();
} while (current->timeout);
current->state = TASK_RUNNING;
remove_wait_queue(&tty->write_q.proc_list, &wait);
}
static int do_get_ps_info(int arg)
{
struct tstruct {
int flag;
int present[NR_TASKS];
struct task_struct tasks[NR_TASKS];
};
struct tstruct *ts = (struct tstruct *)arg;
struct task_struct **p;
char *c, *d;
int i, n = 0;
i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct tstruct));
if (i)
return i;
for (p = &FIRST_TASK ; p <= &LAST_TASK ; p++, n++)
if (*p)
{
c = (char *)(*p);
d = (char *)(ts->tasks+n);
for (i=0 ; i<sizeof(struct task_struct) ; i++)
put_fs_byte(*c++, d++);
put_fs_long(1, (unsigned long *)(ts->present+n));
}
else
put_fs_long(0, (unsigned long *)(ts->present+n));
return(0);
}
static void unset_locked_termios(struct termios *termios,
struct termios *old,
struct termios *locked)
{
int i;
#define NOSET_MASK(x,y,z) (x = ((x) & ~(z)) | ((y) & (z)))
if (!locked) {
printk("Warning?!? termios_locked is NULL.\n");
return;
}
NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
termios->c_line = locked->c_line ? old->c_line : termios->c_line;
for (i=0; i < NCCS; i++)
termios->c_cc[i] = locked->c_cc[i] ?
old->c_cc[i] : termios->c_cc[i];
}
int check_change(struct tty_struct * tty, int channel)
{
/* If we try to set the state of terminal and we're not in the
foreground, send a SIGTTOU. If the signal is blocked or
ignored, go ahead and perform the operation. POSIX 7.2) */
if (current->tty != channel)
return 0;
if (tty->pgrp <= 0) {
printk("check_change: tty->pgrp <= 0!\n");
return 0;
}
if (current->pgrp == tty->pgrp)
return 0;
if (is_ignored(SIGTTOU))
return 0;
if (is_orphaned_pgrp(current->pgrp))
return -EIO;
(void) kill_pg(current->pgrp,SIGTTOU,1);
return -ERESTARTSYS;
}
static int set_termios_2(struct tty_struct * tty, struct termios * termios)
{
struct termios old_termios = *tty->termios;
int canon_change;
canon_change = (old_termios.c_lflag ^ termios->c_lflag) & ICANON;
cli();
*tty->termios = *termios;
if (canon_change) {
memset(&tty->secondary_flags, 0, sizeof tty->secondary_flags);
tty->canon_head = tty->secondary.tail;
tty->canon_data = 0;
tty->erasing = 0;
}
sti();
if (canon_change && !L_ICANON(tty) && !EMPTY(&tty->secondary))
/* Get characters left over from canonical mode. */
wake_up_interruptible(&tty->secondary.proc_list);
/* see if packet mode change of state */
if (tty->link && tty->link->packet) {
int old_flow = ((old_termios.c_iflag & IXON) &&
(old_termios.c_cc[VSTOP] == '\023') &&
(old_termios.c_cc[VSTART] == '\021'));
int new_flow = (I_IXON(tty) &&
STOP_CHAR(tty) == '\023' &&
START_CHAR(tty) == '\021');
if (old_flow != new_flow) {
tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
if (new_flow)
tty->ctrl_status |= TIOCPKT_DOSTOP;
else
tty->ctrl_status |= TIOCPKT_NOSTOP;
wake_up_interruptible(&tty->link->secondary.proc_list);
}
}
unset_locked_termios(tty->termios, &old_termios,
termios_locked[tty->line]);
if (tty->set_termios)
(*tty->set_termios)(tty, &old_termios);
return 0;
}
static int set_termios(struct tty_struct * tty, struct termios * termios,
int channel)
{
struct termios tmp_termios;
memcpy_fromfs(&tmp_termios, termios, sizeof (struct termios));
return set_termios_2(tty, &tmp_termios);
}
static int get_termio(struct tty_struct * tty, struct termio * termio)
{
int i;
struct termio tmp_termio;
i = verify_area(VERIFY_WRITE, termio, sizeof (struct termio));
if (i)
return i;
tmp_termio.c_iflag = tty->termios->c_iflag;
tmp_termio.c_oflag = tty->termios->c_oflag;
tmp_termio.c_cflag = tty->termios->c_cflag;
tmp_termio.c_lflag = tty->termios->c_lflag;
tmp_termio.c_line = tty->termios->c_line;
for(i=0 ; i < NCC ; i++)
tmp_termio.c_cc[i] = tty->termios->c_cc[i];
memcpy_tofs(termio, &tmp_termio, sizeof (struct termio));
return 0;
}
static int set_termio(struct tty_struct * tty, struct termio * termio,
int channel)
{
struct termio tmp_termio;
struct termios tmp_termios;
tmp_termios = *tty->termios;
memcpy_fromfs(&tmp_termio, termio, sizeof (struct termio));
#define SET_LOW_BITS(x,y) ((x) = (0xffff0000 & (x)) | (y))
SET_LOW_BITS(tmp_termios.c_iflag, tmp_termio.c_iflag);
SET_LOW_BITS(tmp_termios.c_oflag, tmp_termio.c_oflag);
SET_LOW_BITS(tmp_termios.c_cflag, tmp_termio.c_cflag);
SET_LOW_BITS(tmp_termios.c_lflag, tmp_termio.c_lflag);
memcpy(&tmp_termios.c_cc, &tmp_termio.c_cc, NCC);
#undef SET_LOW_BITS
return set_termios_2(tty, &tmp_termios);
}
static int set_window_size(struct tty_struct * tty, struct winsize * ws)
{
struct winsize tmp_ws;
memcpy_fromfs(&tmp_ws, ws, sizeof (struct winsize));
if (memcmp(&tmp_ws, &tty->winsize, sizeof (struct winsize)) &&
tty->pgrp > 0)
kill_pg(tty->pgrp, SIGWINCH, 1);
tty->winsize = tmp_ws;
return 0;
}
/* Set the discipline of a tty line. */
static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
{
if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS) ||
!(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED))
return -EINVAL;
if (tty->disc == ldisc)
return 0; /* We are already in the desired discipline */
/* Shutdown the current discipline. */
wait_until_sent(tty, 0);
flush_input(tty);
if (ldiscs[tty->disc].close)
ldiscs[tty->disc].close(tty);
/* Now set up the new line discipline. */
tty->disc = ldisc;
tty->termios->c_line = ldisc;
if (ldiscs[tty->disc].open)
return(ldiscs[tty->disc].open(tty));
else
return 0;
}
static unsigned long inq_canon(struct tty_struct * tty)
{
int nr, head, tail;
if (!tty->canon_data)
return 0;
head = tty->canon_head;
tail = tty->secondary.tail;
nr = (head - tail) & (TTY_BUF_SIZE-1);
/* Skip EOF-chars.. */
while (head != tail) {
if (test_bit(tail, &tty->secondary_flags) &&
tty->secondary.buf[tail] == __DISABLED_CHAR)
nr--;
INC(tail);
}
return nr;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -