diff -Nur linux.old/fs/proc/base.c linux.new/fs/proc/base.c
--- linux.old/fs/proc/base.c	Sat May 11 10:42:59 2002
+++ linux.new/fs/proc/base.c	Sat May 11 10:41:52 2002
@@ -11,6 +11,17 @@
  *  go into icache. We cache the reference to task_struct upon lookup too.
  *  Eventually it should become a filesystem in its own. We don't use the
  *  rest of procfs anymore.
+ *
+ *  2001, Kasper Dupont. Implemented /proc/<pid>/tty symlink. There are
+ *  two small problems. If the tty has been opened through different
+ *  filenames I always return the last in the list. The returned name is
+ *  the first opened, which is usually the correct one. In particular that
+ *  should avoid the completly unusable link to /dev/tty which I could
+ *  otherwise get. Keeping track of the correct name would be posible, but
+ *  would require changes to many other parts of the kernel. The other
+ *  problem is the anoying error messages when doing a "ls -lR /proc". One
+ *  error for each process without a controlling tty, but this just the
+ *  same as exe for kernel daemons. "ls -l /proc/2/exe"
  */
 
 #include <asm/uaccess.h>
@@ -84,6 +95,47 @@
 	return result;
 }
 
+static int proc_tty_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
+{
+	int result = -ENOENT;
+	struct task_struct *task = inode->u.proc_i.task;
+	struct tty_struct *tty;
+	struct list_head *files;
+	struct list_head *l;
+	struct file * filp = NULL;
+
+	task_lock(task);
+	tty=task->tty;
+	if (tty) {
+		file_list_lock();
+		files=&(tty->tty_files);
+		/* FIXME: Currently I just use the first file I find
+		 *        in the list, that is not necessarily the
+		 *        correct one. But the kernel does not keep
+		 *        track of the correct one. The best probably
+		 *        is to use the one that was opened first, I
+		 *        scan the list with prev instead of next to
+		 *        get that behavior ? [KD01]
+		 */
+		for (l = files->prev; l != files; l = l->prev) {
+			filp = list_entry(l, struct file, f_list);
+			if (!filp)
+				continue;
+			if (!filp->f_dentry)
+				continue;
+			if (!filp->f_op)
+				continue;
+			*mnt = mntget(filp->f_vfsmnt);
+			*dentry = dget(filp->f_dentry);
+			result=0;
+			break;
+		}
+		file_list_unlock();
+	}
+	task_unlock(task);
+	return result;
+}
+
 static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
 {
 	struct fs_struct *fs;
@@ -539,6 +591,7 @@
 	PROC_PID_STATM,
 	PROC_PID_MAPS,
 	PROC_PID_CPU,
+	PROC_PID_TTY,
 	PROC_PID_MOUNTS,
 	PROC_PID_FD_DIR = 0x8000,	/* 0x8000-0xffff */
 };
@@ -559,6 +612,7 @@
   E(PROC_PID_CWD,	"cwd",		S_IFLNK|S_IRWXUGO),
   E(PROC_PID_ROOT,	"root",		S_IFLNK|S_IRWXUGO),
   E(PROC_PID_EXE,	"exe",		S_IFLNK|S_IRWXUGO),
+  E(PROC_PID_TTY,       "tty",          S_IFLNK|S_IRWXUGO),
   E(PROC_PID_MOUNTS,	"mounts",	S_IFREG|S_IRUGO),
   {0,0,NULL,0}
 };
@@ -884,6 +938,10 @@
 			inode->i_op = &proc_pid_link_inode_operations;
 			inode->u.proc_i.op.proc_get_link = proc_exe_link;
 			break;
+		case PROC_PID_TTY:
+			inode->i_op = &proc_pid_link_inode_operations;
+                        inode->u.proc_i.op.proc_get_link = proc_tty_link;
+                        break;
 		case PROC_PID_CWD:
 			inode->i_op = &proc_pid_link_inode_operations;
 			inode->u.proc_i.op.proc_get_link = proc_cwd_link;
