extractedLnx/linux/drivers/char/tty_ioctl.c_tty_ioctl.c
int tty_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned long arg)
{
struct tty_struct * tty;
struct tty_struct * other_tty;
struct tty_struct * termios_tty;
pid_t pgrp;
int dev;
int termios_dev;
int retval;
if (MAJOR(file->f_rdev) != TTY_MAJOR) {
printk("tty_ioctl: tty pseudo-major != TTY_MAJOR\n");
return -EINVAL;
}
dev = MINOR(file->f_rdev);
tty = TTY_TABLE(dev);
if (!tty)
return -EINVAL;
if (IS_A_PTY(dev))
other_tty = tty_table[PTY_OTHER(dev)];
else
other_tty = NULL;
if (IS_A_PTY_MASTER(dev)) {
termios_tty = other_tty;
termios_dev = PTY_OTHER(dev);
} else {
termios_tty = tty;
termios_dev = dev;
}
switch (cmd) {
case TCGETS:
retval = verify_area(VERIFY_WRITE, (void *) arg,
sizeof (struct termios));
if (retval)
return retval;
memcpy_tofs((struct termios *) arg,
termios_tty->termios,
sizeof (struct termios));
return 0;
case TCSETSF:
case TCSETSW:
case TCSETS:
retval = check_change(termios_tty, termios_dev);
if (retval)
return retval;
if (cmd == TCSETSF || cmd == TCSETSW) {
if (cmd == TCSETSF)
flush_input(termios_tty);
wait_until_sent(termios_tty, 0);
}
return set_termios(termios_tty, (struct termios *) arg,
termios_dev);
case TCGETA:
return get_termio(termios_tty,(struct termio *) arg);
case TCSETAF:
case TCSETAW:
case TCSETA:
retval = check_change(termios_tty, termios_dev);
if (retval)
return retval;
if (cmd == TCSETAF || cmd == TCSETAW) {
if (cmd == TCSETAF)
flush_input(termios_tty);
wait_until_sent(termios_tty, 0);
}
return set_termio(termios_tty, (struct termio *) arg,
termios_dev);
case TCXONC:
retval = check_change(tty, dev);
if (retval)
return retval;
switch (arg) {
case TCOOFF:
stop_tty(tty);
break;
case TCOON:
start_tty(tty);
break;
case TCIOFF:
if (STOP_CHAR(tty) != __DISABLED_CHAR)
put_tty_queue(STOP_CHAR(tty),
&tty->write_q);
break;
case TCION:
if (START_CHAR(tty) != __DISABLED_CHAR)
put_tty_queue(START_CHAR(tty),
&tty->write_q);
break;
default:
return -EINVAL;
}
return 0;
case TCFLSH:
retval = check_change(tty, dev);
if (retval)
return retval;
switch (arg) {
case TCIFLUSH:
flush_input(tty);
break;
case TCIOFLUSH:
flush_input(tty);
/* fall through */
case TCOFLUSH:
flush_output(tty);
break;
default:
return -EINVAL;
}
return 0;
case TIOCEXCL:
set_bit(TTY_EXCLUSIVE, &tty->flags);
return 0;
case TIOCNXCL:
clear_bit(TTY_EXCLUSIVE, &tty->flags);
return 0;
case TIOCSCTTY:
if (current->leader &&
(current->session == tty->session))
return 0;
/*
* The process must be a session leader and
* not have a controlling tty already.
*/
if (!current->leader || (current->tty >= 0))
return -EPERM;
if (tty->session > 0) {
/*
* This tty is already the controlling
* tty for another session group!
*/
if ((arg == 1) && suser()) {
/*
* Steal it away
*/
struct task_struct *p;
for_each_task(p)
if (p->tty == dev)
p->tty = -1;
} else
return -EPERM;
}
current->tty = dev;
tty->session = current->session;
tty->pgrp = current->pgrp;
return 0;
case TIOCGPGRP:
retval = verify_area(VERIFY_WRITE, (void *) arg,
sizeof (pid_t));
if (retval)
return retval;
if (current->tty != termios_dev)
return -ENOTTY;
put_fs_long(termios_tty->pgrp, (pid_t *) arg);
return 0;
case TIOCSPGRP:
retval = check_change(termios_tty, termios_dev);
if (retval)
return retval;
if ((current->tty < 0) ||
(current->tty != termios_dev) ||
(termios_tty->session != current->session))
return -ENOTTY;
pgrp = get_fs_long((pid_t *) arg);
if (pgrp < 0)
return -EINVAL;
if (session_of_pgrp(pgrp) != current->session)
return -EPERM;
termios_tty->pgrp = pgrp;
return 0;
case TIOCOUTQ:
retval = verify_area(VERIFY_WRITE, (void *) arg,
sizeof (unsigned long));
if (retval)
return retval;
put_fs_long(CHARS(&tty->write_q),
(unsigned long *) arg);
return 0;
case TIOCINQ:
retval = verify_area(VERIFY_WRITE, (void *) arg,
sizeof (unsigned long));
if (retval)
return retval;
if (L_ICANON(tty))
put_fs_long(inq_canon(tty),
(unsigned long *) arg);
else
put_fs_long(CHARS(&tty->secondary),
(unsigned long *) arg);
return 0;
case TIOCSTI:
if ((current->tty != dev) && !suser())
return -EPERM;
retval = verify_area(VERIFY_READ, (void *) arg, 1);
if (retval)
return retval;
put_tty_queue(get_fs_byte((char *) arg), &tty->read_q);
TTY_READ_FLUSH(tty);
return 0;
case TIOCGWINSZ:
retval = verify_area(VERIFY_WRITE, (void *) arg,
sizeof (struct winsize));
if (retval)
return retval;
memcpy_tofs((struct winsize *) arg, &tty->winsize,
sizeof (struct winsize));
return 0;
case TIOCSWINSZ:
if (IS_A_PTY_MASTER(dev))
set_window_size(other_tty,(struct winsize *) arg);
return set_window_size(tty,(struct winsize *) arg);
case TIOCLINUX:
switch (get_fs_byte((char *)arg))
{
case 0:
return do_screendump(arg);
case 1:
return do_get_ps_info(arg);
#ifdef CONFIG_SELECTION
case 2:
return set_selection(arg);
case 3:
return paste_selection(tty);
case 4:
unblank_screen();
return 0;
#endif /* CONFIG_SELECTION */
default:
return -EINVAL;
}
case TIOCCONS:
if (IS_A_CONSOLE(dev)) {
if (!suser())
return -EPERM;
redirect = NULL;
return 0;
}
if (redirect)
return -EBUSY;
if (!suser())
return -EPERM;
if (IS_A_PTY_MASTER(dev))
redirect = other_tty;
else if (IS_A_PTY_SLAVE(dev))
redirect = tty;
else
return -ENOTTY;
return 0;
case FIONBIO:
arg = get_fs_long((unsigned long *) arg);
if (arg)
file->f_flags |= O_NONBLOCK;
else
file->f_flags &= ~O_NONBLOCK;
return 0;
case TIOCNOTTY:
if (current->tty != dev)
return -ENOTTY;
if (current->leader)
disassociate_ctty(0);
current->tty = -1;
return 0;
case TIOCGETD:
retval = verify_area(VERIFY_WRITE, (void *) arg,
sizeof (unsigned long));
if (retval)
return retval;
put_fs_long(tty->disc, (unsigned long *) arg);
return 0;
case TIOCSETD:
retval = check_change(tty, dev);
if (retval)
return retval;
arg = get_fs_long((unsigned long *) arg);
return tty_set_ldisc(tty, arg);
case TIOCGLCKTRMIOS:
arg = get_fs_long((unsigned long *) arg);
retval = verify_area(VERIFY_WRITE, (void *) arg,
sizeof (struct termios));
if (retval)
return retval;
memcpy_tofs((struct termios *) arg,
&termios_locked[termios_dev],
sizeof (struct termios));
return 0;
case TIOCSLCKTRMIOS:
if (!suser())
return -EPERM;
arg = get_fs_long((unsigned long *) arg);
memcpy_fromfs(&termios_locked[termios_dev],
(struct termios *) arg,
sizeof (struct termios));
return 0;
case TIOCPKT:
if (!IS_A_PTY_MASTER(dev))
return -ENOTTY;
retval = verify_area(VERIFY_READ, (void *) arg,
sizeof (unsigned long));
if (retval)
return retval;
if (get_fs_long(arg)) {
if (!tty->packet) {
tty->packet = 1;
tty->link->ctrl_status = 0;
}
} else
tty->packet = 0;
return 0;
case TCSBRK: case TCSBRKP:
retval = check_change(tty, dev);
if (retval)
return retval;
wait_until_sent(tty, 0);
if (!tty->ioctl)
return 0;
tty->ioctl(tty, file, cmd, arg);
return 0;
default:
if (tty->ioctl) {
retval = (tty->ioctl)(tty, file, cmd, arg);
if (retval != -EINVAL)
return retval;
}
if (ldiscs[tty->disc].ioctl) {
retval = (ldiscs[tty->disc].ioctl)
(tty, file, cmd, arg);
return retval;
}
return -EINVAL;
}
}
Generated by GNU enscript 1.6.4.