Import 2.1.118
[davej-history.git] / fs / proc / link.c
blobdf5ea85e6f164e1f7fd92df2718a202d378cf271
1 /*
2 * linux/fs/proc/link.c
4 * Copyright (C) 1991, 1992 Linus Torvalds
6 * /proc link-file handling code
7 */
9 #include <asm/uaccess.h>
11 #include <linux/errno.h>
12 #include <linux/sched.h>
13 #include <linux/mm.h>
14 #include <linux/fs.h>
15 #include <linux/file.h>
16 #include <linux/proc_fs.h>
17 #include <linux/stat.h>
19 static int proc_readlink(struct dentry *, char *, int);
20 static struct dentry * proc_follow_link(struct dentry *, struct dentry *);
23 * links can't do much...
25 static struct file_operations proc_fd_link_operations = {
26 NULL, /* lseek - default */
27 NULL, /* read - bad */
28 NULL, /* write - bad */
29 NULL, /* readdir - bad */
30 NULL, /* poll - default */
31 NULL, /* ioctl - default */
32 NULL, /* mmap */
33 NULL, /* very special open code */
34 NULL, /* flush */
35 NULL, /* no special release code */
36 NULL /* can't fsync */
39 struct inode_operations proc_link_inode_operations = {
40 &proc_fd_link_operations,/* file-operations */
41 NULL, /* create */
42 NULL, /* lookup */
43 NULL, /* link */
44 NULL, /* unlink */
45 NULL, /* symlink */
46 NULL, /* mkdir */
47 NULL, /* rmdir */
48 NULL, /* mknod */
49 NULL, /* rename */
50 proc_readlink, /* readlink */
51 proc_follow_link, /* follow_link */
52 NULL, /* readpage */
53 NULL, /* writepage */
54 NULL, /* bmap */
55 NULL, /* truncate */
56 proc_permission /* permission */
59 static struct dentry * proc_follow_link(struct dentry *dentry,
60 struct dentry *base)
62 struct inode *inode = dentry->d_inode;
63 struct task_struct *p;
64 struct dentry * result;
65 int ino, pid;
66 int error;
68 /* We don't need a base pointer in the /proc filesystem */
69 dput(base);
71 error = permission(inode, MAY_EXEC);
72 result = ERR_PTR(error);
73 if (error)
74 goto out;
76 ino = inode->i_ino;
77 pid = ino >> 16;
78 ino &= 0x0000ffff;
80 result = ERR_PTR(-ENOENT);
81 read_lock(&tasklist_lock);
82 p = find_task_by_pid(pid);
83 if (!p)
84 goto out_unlock;
86 switch (ino) {
87 case PROC_PID_CWD:
88 if (!p->fs || !p->fs->pwd)
89 goto out_unlock;
90 result = p->fs->pwd;
91 goto out_dget;
93 case PROC_PID_ROOT:
94 if (!p->fs || !p->fs->root)
95 goto out_unlock;
96 result = p->fs->root;
97 goto out_dget;
99 case PROC_PID_EXE: {
100 struct vm_area_struct * vma;
101 if (!p->mm)
102 goto out_unlock;
103 vma = p->mm->mmap;
104 while (vma) {
105 if ((vma->vm_flags & VM_EXECUTABLE) &&
106 vma->vm_file) {
107 result = vma->vm_file->f_dentry;
108 goto out_dget;
110 vma = vma->vm_next;
112 goto out_unlock;
114 default:
115 if (ino & PROC_PID_FD_DIR) {
116 struct file * file;
117 ino &= 0x7fff;
118 file = fcheck_task(p, ino);
119 if (!file || !file->f_dentry)
120 goto out_unlock;
121 result = file->f_dentry;
122 goto out_dget;
125 out_dget:
126 result = dget(result);
128 out_unlock:
129 read_unlock(&tasklist_lock);
131 out:
132 return result;
136 * This pretty-prints the pathname of a dentry,
137 * clarifying sockets etc.
139 static int do_proc_readlink(struct dentry *dentry, char * buffer, int buflen)
141 struct inode * inode;
142 char * tmp = (char*)__get_free_page(GFP_KERNEL), *path, *pattern;
143 int len;
145 /* Check for special dentries.. */
146 pattern = NULL;
147 inode = dentry->d_inode;
148 if (inode && dentry->d_parent == dentry) {
149 if (S_ISSOCK(inode->i_mode))
150 pattern = "socket:[%lu]";
151 if (S_ISFIFO(inode->i_mode))
152 pattern = "pipe:[%lu]";
155 if (pattern) {
156 len = sprintf(tmp, pattern, inode->i_ino);
157 path = tmp;
158 } else {
159 path = d_path(dentry, tmp, PAGE_SIZE);
160 len = tmp + PAGE_SIZE - path;
163 if (len < buflen)
164 buflen = len;
165 dput(dentry);
166 copy_to_user(buffer, path, buflen);
167 free_page((unsigned long)tmp);
168 return buflen;
171 static int proc_readlink(struct dentry * dentry, char * buffer, int buflen)
173 int error;
175 dentry = proc_follow_link(dentry, NULL);
176 error = PTR_ERR(dentry);
177 if (!IS_ERR(dentry)) {
178 error = -ENOENT;
179 if (dentry) {
180 error = do_proc_readlink(dentry, buffer, buflen);
183 return error;