From: viro@www.linux.org.uk 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 had been finally put out of its misery. kdev_val() is gone. drivers/char/n_tty.c | 13 +---- drivers/char/tty_io.c | 126 ++++++++++++++++++++++--------------------------- include/linux/kdev_t.h | 10 --- 3 files changed, 61 insertions(+), 88 deletions(-) diff -puN drivers/char/n_tty.c~large-dev_t-2nd-06 drivers/char/n_tty.c --- 25/drivers/char/n_tty.c~large-dev_t-2nd-06 2003-09-05 00:49:37.000000000 -0700 +++ 25-akpm/drivers/char/n_tty.c 2003-09-05 00:49:37.000000000 -0700 @@ -50,9 +50,6 @@ #include #include -#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(str 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 @@ do_it_again: /* 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_str 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; diff -puN drivers/char/tty_io.c~large-dev_t-2nd-06 drivers/char/tty_io.c --- 25/drivers/char/tty_io.c~large-dev_t-2nd-06 2003-09-05 00:49:37.000000000 -0700 +++ 25-akpm/drivers/char/tty_io.c 2003-09-05 00:49:37.000000000 -0700 @@ -103,11 +103,6 @@ #include -#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 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 * fi 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 * f (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 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 @@ retry_open: 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 @@ retry_open: 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 @@ retry_open: return -ENODEV; } - if (IS_PTMX_DEV(device)) { + if (device == MKDEV(TTY_MAJOR,2)) { #ifdef CONFIG_UNIX98_PTYS /* find a device that is not in use. */ retval = -1; @@ -1365,7 +1351,7 @@ retry_open: 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 @@ got_driver: /* * 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 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, stru 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"); diff -puN include/linux/kdev_t.h~large-dev_t-2nd-06 include/linux/kdev_t.h --- 25/include/linux/kdev_t.h~large-dev_t-2nd-06 2003-09-05 00:49:37.000000000 -0700 +++ 25-akpm/include/linux/kdev_t.h 2003-09-05 00:49:37.000000000 -0700 @@ -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.. */ _