
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<something> 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 <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(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 <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
 
 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.. */

_
