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//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 @@ -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;