Linux-2.3.7.. Let's be careful out there..
[davej-history.git] / fs / proc / link.c
blob3a563982512a5b5148572b68d455b124ae3399aa
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 *, unsigned int);
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, /* bmap */
53 NULL, /* readpage */
54 NULL, /* writepage */
55 NULL, /* flushpage */
56 NULL, /* truncate */
57 proc_permission, /* permission */
58 NULL, /* smap */
59 NULL /* revalidate */
62 static struct dentry * proc_follow_link(struct dentry *dentry,
63 struct dentry *base,
64 unsigned int follow)
66 struct inode *inode = dentry->d_inode;
67 struct task_struct *p;
68 struct dentry * result;
69 int ino, pid;
70 int error;
72 /* We don't need a base pointer in the /proc filesystem */
73 dput(base);
75 error = permission(inode, MAY_EXEC);
76 result = ERR_PTR(error);
77 if (error)
78 goto out;
80 ino = inode->i_ino;
81 pid = ino >> 16;
82 ino &= 0x0000ffff;
84 result = ERR_PTR(-ENOENT);
85 read_lock(&tasklist_lock);
86 p = find_task_by_pid(pid);
87 if (!p)
88 goto out_unlock;
90 switch (ino) {
91 case PROC_PID_CWD:
92 if (!p->fs || !p->fs->pwd)
93 goto out_unlock;
94 result = p->fs->pwd;
95 goto out_dget;
97 case PROC_PID_ROOT:
98 if (!p->fs || !p->fs->root)
99 goto out_unlock;
100 result = p->fs->root;
101 goto out_dget;
103 case PROC_PID_EXE: {
104 struct vm_area_struct * vma;
105 if (!p->mm)
106 goto out_unlock;
107 vma = p->mm->mmap;
108 while (vma) {
109 if ((vma->vm_flags & VM_EXECUTABLE) &&
110 vma->vm_file) {
111 result = vma->vm_file->f_dentry;
112 goto out_dget;
114 vma = vma->vm_next;
116 goto out_unlock;
118 default:
119 if (ino & PROC_PID_FD_DIR) {
120 struct file * file;
121 ino &= 0x7fff;
122 file = fcheck_task(p, ino);
123 if (!file || !file->f_dentry)
124 goto out_unlock;
125 result = file->f_dentry;
126 goto out_dget;
129 out_dget:
130 result = dget(result);
132 out_unlock:
133 read_unlock(&tasklist_lock);
135 out:
136 return result;
140 * This pretty-prints the pathname of a dentry,
141 * clarifying sockets etc.
143 static int do_proc_readlink(struct dentry *dentry, char * buffer, int buflen)
145 struct inode * inode;
146 char * tmp = (char*)__get_free_page(GFP_KERNEL), *path, *pattern;
147 int len;
149 /* Check for special dentries.. */
150 pattern = NULL;
151 inode = dentry->d_inode;
152 if (inode && IS_ROOT(dentry)) {
153 if (S_ISSOCK(inode->i_mode))
154 pattern = "socket:[%lu]";
155 if (S_ISFIFO(inode->i_mode))
156 pattern = "pipe:[%lu]";
159 if (pattern) {
160 len = sprintf(tmp, pattern, inode->i_ino);
161 path = tmp;
162 } else {
163 path = d_path(dentry, tmp, PAGE_SIZE);
164 len = tmp + PAGE_SIZE - 1 - path;
167 if (len < buflen)
168 buflen = len;
169 dput(dentry);
170 copy_to_user(buffer, path, buflen);
171 free_page((unsigned long)tmp);
172 return buflen;
175 static int proc_readlink(struct dentry * dentry, char * buffer, int buflen)
177 int error;
179 dentry = proc_follow_link(dentry, NULL, 1);
180 error = PTR_ERR(dentry);
181 if (!IS_ERR(dentry)) {
182 error = -ENOENT;
183 if (dentry) {
184 error = do_proc_readlink(dentry, buffer, buflen);
187 return error;