Commit cbac67b1 authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] large dev_t - second series (6/15)

	tty redirect handling sanitized.  Such ttys (/dev/tty and
/dev/console) get a different file_operations; its ->write() handles
redirects; checks for file->f_op == &tty_fops updated, checks for
major:minor being that of a redirector replaced with check for
->f_op->write value.  Piece of code in tty_io.c that had been #if 0
since 0.99<something> had been finally put out of its misery. kdev_val()
is gone.
parent 25a6ca89
......@@ -50,9 +50,6 @@
#include <asm/system.h>
#include <asm/bitops.h>
#define IS_CONSOLE_DEV(dev) (kdev_val(dev) == __mkdev(TTY_MAJOR,0))
#define IS_SYSCONS_DEV(dev) (kdev_val(dev) == __mkdev(TTYAUX_MAJOR,1))
/* number of characters left in xmit buffer before select has we have room */
#define WAKEUP_CHARS 256
......@@ -951,6 +948,8 @@ static inline int copy_from_read_buf(struct tty_struct *tty,
return retval;
}
extern ssize_t redirected_tty_write(struct file *,const char *,size_t,loff_t *);
static ssize_t read_chan(struct tty_struct *tty, struct file *file,
unsigned char *buf, size_t nr)
{
......@@ -975,9 +974,7 @@ static ssize_t read_chan(struct tty_struct *tty, struct file *file,
/* NOTE: not yet done after every sleep pending a thorough
check of the logic of this change. -- jlc */
/* don't stop on /dev/console */
if (!IS_CONSOLE_DEV(file->f_dentry->d_inode->i_rdev) &&
!IS_SYSCONS_DEV(file->f_dentry->d_inode->i_rdev) &&
current->tty == tty) {
if (file->f_op->write != redirected_tty_write && current->tty == tty) {
if (tty->pgrp <= 0)
printk("read_chan: tty->pgrp <= 0!\n");
else if (current->pgrp != tty->pgrp) {
......@@ -1168,9 +1165,7 @@ static ssize_t write_chan(struct tty_struct * tty, struct file * file,
ssize_t retval = 0;
/* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
if (L_TOSTOP(tty) &&
!IS_CONSOLE_DEV(file->f_dentry->d_inode->i_rdev) &&
!IS_SYSCONS_DEV(file->f_dentry->d_inode->i_rdev)) {
if (L_TOSTOP(tty) && file->f_op->write != redirected_tty_write) {
retval = tty_check_change(tty);
if (retval)
return retval;
......
......@@ -103,11 +103,6 @@
#include <linux/kmod.h>
#define IS_CONSOLE_DEV(dev) (kdev_val(dev) == __mkdev(TTY_MAJOR,0))
#define IS_TTY_DEV(dev) (kdev_val(dev) == __mkdev(TTYAUX_MAJOR,0))
#define IS_SYSCONS_DEV(dev) (kdev_val(dev) == __mkdev(TTYAUX_MAJOR,1))
#define IS_PTMX_DEV(dev) (kdev_val(dev) == __mkdev(TTYAUX_MAJOR,2))
#undef TTY_DEBUG_HANGUP
#define TTY_PARANOIA_CHECK 1
......@@ -136,6 +131,7 @@ static void initialize_tty_struct(struct tty_struct *tty);
static ssize_t tty_read(struct file *, char *, size_t, loff_t *);
static ssize_t tty_write(struct file *, const char *, size_t, loff_t *);
ssize_t redirected_tty_write(struct file *, const char *, size_t, loff_t *);
static unsigned int tty_poll(struct file *, poll_table *);
static int tty_open(struct inode *, struct file *);
static int tty_release(struct inode *, struct file *);
......@@ -382,6 +378,17 @@ static struct file_operations tty_fops = {
.fasync = tty_fasync,
};
static struct file_operations console_fops = {
.llseek = no_llseek,
.read = tty_read,
.write = redirected_tty_write,
.poll = tty_poll,
.ioctl = tty_ioctl,
.open = tty_open,
.release = tty_release,
.fasync = tty_fasync,
};
static struct file_operations hung_up_tty_fops = {
.llseek = no_llseek,
.read = hung_up_tty_read,
......@@ -425,12 +432,9 @@ void do_tty_hangup(void *data)
check_tty_count(tty, "do_tty_hangup");
file_list_lock();
list_for_each_entry(filp, &tty->tty_files, f_list) {
if (IS_CONSOLE_DEV(filp->f_dentry->d_inode->i_rdev) ||
IS_SYSCONS_DEV(filp->f_dentry->d_inode->i_rdev)) {
if (filp->f_op->write == redirected_tty_write)
cons_filp = filp;
continue;
}
if (filp->f_op != &tty_fops)
if (filp->f_op->write != tty_write)
continue;
closecount++;
tty_fasync(-1, filp, 0); /* can't block */
......@@ -650,22 +654,6 @@ static ssize_t tty_read(struct file * file, char * buf, size_t count,
if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags)))
return -EIO;
/* This check not only needs to be done before reading, but also
whenever read_chan() gets woken up after sleeping, so I've
moved it to there. This should only be done for the N_TTY
line discipline, anyway. Same goes for write_chan(). -- jlc. */
#if 0
if (!IS_CONSOLE_DEV(inode->i_rdev) && /* don't stop on /dev/console */
(tty->pgrp > 0) &&
(current->tty == tty) &&
(tty->pgrp != current->pgrp))
if (is_ignored(SIGTTIN) || is_orphaned_pgrp(current->pgrp))
return -EIO;
else {
(void) kill_pg(current->pgrp, SIGTTIN, 1);
return -ERESTARTSYS;
}
#endif
lock_kernel();
if (tty->ldisc.read)
i = (tty->ldisc.read)(tty,file,buf,count);
......@@ -730,37 +718,13 @@ static inline ssize_t do_tty_write(
static ssize_t tty_write(struct file * file, const char * buf, size_t count,
loff_t *ppos)
{
int is_console;
struct tty_struct * tty;
struct inode *inode = file->f_dentry->d_inode;
/*
* For now, we redirect writes from /dev/console as
* well as /dev/tty0.
*/
is_console = IS_SYSCONS_DEV(inode->i_rdev) ||
IS_CONSOLE_DEV(inode->i_rdev);
/* Can't seek (pwrite) on ttys. */
if (ppos != &file->f_pos)
return -ESPIPE;
if (is_console) {
struct file *p = NULL;
spin_lock(&redirect_lock);
if (redirect) {
get_file(redirect);
p = redirect;
}
spin_unlock(&redirect_lock);
if (p) {
ssize_t res = vfs_write(p, buf, count, &p->f_pos);
fput(p);
return res;
}
}
tty = (struct tty_struct *)file->private_data;
if (tty_paranoia_check(tty, inode, "tty_write"))
return -EIO;
......@@ -772,6 +736,31 @@ static ssize_t tty_write(struct file * file, const char * buf, size_t count,
(const unsigned char *)buf, count);
}
ssize_t redirected_tty_write(struct file * file, const char * buf, size_t count,
loff_t *ppos)
{
struct file *p = NULL;
spin_lock(&redirect_lock);
if (redirect) {
get_file(redirect);
p = redirect;
}
spin_unlock(&redirect_lock);
if (p) {
ssize_t res;
/* Can't seek (pwrite) on ttys. */
if (ppos != &file->f_pos)
return -ESPIPE;
res = vfs_write(p, buf, count, &p->f_pos);
fput(p);
return res;
}
return tty_write(file, buf, count, ppos);
}
/* Semaphore to protect creating and releasing a tty */
static DECLARE_MUTEX(tty_sem);
......@@ -1306,14 +1295,11 @@ static int tty_open(struct inode * inode, struct file * filp)
int noctty, retval;
struct tty_driver *driver;
int index;
kdev_t device;
unsigned short saved_flags;
saved_flags = filp->f_flags;
dev_t device = kdev_t_to_nr(inode->i_rdev);
unsigned short saved_flags = filp->f_flags;
retry_open:
noctty = filp->f_flags & O_NOCTTY;
device = inode->i_rdev;
if (IS_TTY_DEV(device)) {
if (device == MKDEV(TTYAUX_MAJOR,0)) {
if (!current->tty)
return -ENXIO;
driver = current->tty->driver;
......@@ -1323,7 +1309,7 @@ static int tty_open(struct inode * inode, struct file * filp)
goto got_driver;
}
#ifdef CONFIG_VT
if (IS_CONSOLE_DEV(device)) {
if (device == MKDEV(TTY_MAJOR,0)) {
extern int fg_console;
extern struct tty_driver *console_driver;
driver = console_driver;
......@@ -1332,7 +1318,7 @@ static int tty_open(struct inode * inode, struct file * filp)
goto got_driver;
}
#endif
if (IS_SYSCONS_DEV(device)) {
if (device == MKDEV(TTYAUX_MAJOR,1)) {
struct console *c = console_drivers;
for (c = console_drivers; c; c = c->next) {
if (!c->device)
......@@ -1348,7 +1334,7 @@ static int tty_open(struct inode * inode, struct file * filp)
return -ENODEV;
}
if (IS_PTMX_DEV(device)) {
if (device == MKDEV(TTYAUX_MAJOR,2)) {
#ifdef CONFIG_UNIX98_PTYS
/* find a device that is not in use. */
retval = -1;
......@@ -1365,7 +1351,7 @@ static int tty_open(struct inode * inode, struct file * filp)
return -ENODEV;
#endif /* CONFIG_UNIX_98_PTYS */
} else {
driver = get_tty_driver(kdev_t_to_nr(device), &index);
driver = get_tty_driver(device, &index);
if (!driver)
return -ENODEV;
got_driver:
......@@ -1407,7 +1393,8 @@ static int tty_open(struct inode * inode, struct file * filp)
/*
* Need to reset f_op in case a hangup happened.
*/
filp->f_op = &tty_fops;
if (filp->f_op == &hung_up_tty_fops)
filp->f_op = &tty_fops;
goto retry_open;
}
if (!noctty &&
......@@ -1516,10 +1503,9 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
return 0;
}
static int tioccons(struct inode *inode, struct file *file)
static int tioccons(struct file *file)
{
if (IS_SYSCONS_DEV(inode->i_rdev) ||
IS_CONSOLE_DEV(inode->i_rdev)) {
if (file->f_op->write == redirected_tty_write) {
struct file *f;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
......@@ -1786,7 +1772,7 @@ int tty_ioctl(struct inode * inode, struct file * file,
case TIOCSWINSZ:
return tiocswinsz(tty, real_tty, (struct winsize *) arg);
case TIOCCONS:
return real_tty!=tty ? -EINVAL : tioccons(inode, file);
return real_tty!=tty ? -EINVAL : tioccons(file);
case FIONBIO:
return fionbio(file, (int *) arg);
case TIOCEXCL:
......@@ -1917,8 +1903,10 @@ static void __do_SAK(void *arg)
spin_lock(&p->files->file_lock);
for (i=0; i < p->files->max_fds; i++) {
filp = fcheck_files(p->files, i);
if (filp && (filp->f_op == &tty_fops) &&
(filp->private_data == tty)) {
if (!filp)
continue;
if (filp->f_op->read == tty_read &&
filp->private_data == tty) {
printk(KERN_NOTICE "SAK: killed process %d"
" (%s): fd#%d opened to the tty\n",
p->pid, p->comm, i);
......@@ -2446,7 +2434,7 @@ void __init tty_init(void)
tty_add_class_device ("tty", MKDEV(TTYAUX_MAJOR, 0), NULL);
strcpy(console_cdev.kobj.name, "dev.console");
cdev_init(&console_cdev, &tty_fops);
cdev_init(&console_cdev, &console_fops);
if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) ||
register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0)
panic("Couldn't register /dev/console driver\n");
......@@ -2468,7 +2456,7 @@ void __init tty_init(void)
#ifdef CONFIG_VT
strcpy(vc0_cdev.kobj.name, "dev.vc0");
cdev_init(&vc0_cdev, &tty_fops);
cdev_init(&vc0_cdev, &console_fops);
if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
panic("Couldn't register /dev/tty0 driver\n");
......
......@@ -80,16 +80,6 @@ typedef struct {
#define mk_kdev(major, minor) ((kdev_t) { __mkdev(major,minor) } )
/*
* The "values" are just _cookies_, usable for
* internal equality comparisons and for things
* like NFS filehandle conversion.
*/
static inline unsigned int kdev_val(kdev_t dev)
{
return dev.value;
}
#define NODEV (mk_kdev(0,0))
/* Mask off the high bits for now.. */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment