Import 2.1.118
[davej-history.git] / fs / proc / generic.c
blob54b16f84bdb9ef37fc2d93d667cbfd672c38ed61
1 /*
2 * proc/fs/generic.c --- generic routines for the proc-fs
4 * This file contains generic proc-fs routines for handling
5 * directories and files.
6 *
7 * Copyright (C) 1991, 1992 Linus Torvalds.
8 * Copyright (C) 1997 Theodore Ts'o
9 */
11 #include <asm/uaccess.h>
13 #include <linux/errno.h>
14 #include <linux/sched.h>
15 #include <linux/proc_fs.h>
16 #include <linux/stat.h>
17 #include <asm/bitops.h>
19 extern struct inode_operations proc_dyna_dir_inode_operations;
21 static ssize_t proc_file_read(struct file * file, char * buf,
22 size_t nbytes, loff_t *ppos);
23 static ssize_t proc_file_write(struct file * file, const char * buffer,
24 size_t count, loff_t *ppos);
25 static long long proc_file_lseek(struct file *, long long, int);
27 int proc_match(int len, const char *name,struct proc_dir_entry * de)
29 if (!de || !de->low_ino)
30 return 0;
31 if (de->namelen != len)
32 return 0;
33 return !memcmp(name, de->name, len);
36 static struct file_operations proc_file_operations = {
37 proc_file_lseek, /* lseek */
38 proc_file_read, /* read */
39 proc_file_write, /* write */
40 NULL, /* readdir */
41 NULL, /* poll */
42 NULL, /* ioctl */
43 NULL, /* mmap */
44 NULL, /* no special open code */
45 NULL, /* flush */
46 NULL, /* no special release code */
47 NULL /* can't fsync */
50 struct inode_operations proc_file_inode_operations = {
51 &proc_file_operations, /* default proc file-ops */
52 NULL, /* create */
53 NULL, /* lookup */
54 NULL, /* link */
55 NULL, /* unlink */
56 NULL, /* symlink */
57 NULL, /* mkdir */
58 NULL, /* rmdir */
59 NULL, /* mknod */
60 NULL, /* rename */
61 NULL, /* readlink */
62 NULL, /* follow_link */
63 NULL, /* readpage */
64 NULL, /* writepage */
65 NULL, /* bmap */
66 NULL, /* truncate */
67 NULL /* permission */
71 * compatibility to replace fs/proc/net.c
73 struct inode_operations proc_net_inode_operations = {
74 &proc_file_operations, /* default net file-ops */
75 NULL, /* create */
76 NULL, /* lookup */
77 NULL, /* link */
78 NULL, /* unlink */
79 NULL, /* symlink */
80 NULL, /* mkdir */
81 NULL, /* rmdir */
82 NULL, /* mknod */
83 NULL, /* rename */
84 NULL, /* readlink */
85 NULL, /* follow_link */
86 NULL, /* readpage */
87 NULL, /* writepage */
88 NULL, /* bmap */
89 NULL, /* truncate */
90 NULL /* permission */
94 #ifndef MIN
95 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
96 #endif
98 /* 4K page size but our output routines use some slack for overruns */
99 #define PROC_BLOCK_SIZE (3*1024)
101 static ssize_t
102 proc_file_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos)
104 struct inode * inode = file->f_dentry->d_inode;
105 char *page;
106 ssize_t retval=0;
107 int eof=0;
108 ssize_t n, count;
109 char *start;
110 struct proc_dir_entry * dp;
112 dp = (struct proc_dir_entry *) inode->u.generic_ip;
113 if (!(page = (char*) __get_free_page(GFP_KERNEL)))
114 return -ENOMEM;
116 while ((nbytes > 0) && !eof)
118 count = MIN(PROC_BLOCK_SIZE, nbytes);
120 start = NULL;
121 if (dp->get_info) {
123 * Handle backwards compatibility with the old net
124 * routines.
126 * XXX What gives with the file->f_flags & O_ACCMODE
127 * test? Seems stupid to me....
129 n = dp->get_info(page, &start, *ppos, count,
130 (file->f_flags & O_ACCMODE) == O_RDWR);
131 if (n < count)
132 eof = 1;
133 } else if (dp->read_proc) {
134 n = dp->read_proc(page, &start, *ppos,
135 count, &eof, dp->data);
136 } else
137 break;
139 if (!start) {
141 * For proc files that are less than 4k
143 start = page + *ppos;
144 n -= *ppos;
145 if (n <= 0)
146 break;
147 if (n > count)
148 n = count;
150 if (n == 0)
151 break; /* End of file */
152 if (n < 0) {
153 if (retval == 0)
154 retval = n;
155 break;
158 /* This is a hack to allow mangling of file pos independent
159 * of actual bytes read. Simply place the data at page,
160 * return the bytes, and set `start' to the desired offset
161 * as an unsigned int. - Paul.Russell@rustcorp.com.au
163 n -= copy_to_user(buf, start < page ? page : start, n);
164 if (n == 0) {
165 if (retval == 0)
166 retval = -EFAULT;
167 break;
170 *ppos += start < page ? (long)start : n; /* Move down the file */
171 nbytes -= n;
172 buf += n;
173 retval += n;
175 free_page((unsigned long) page);
176 return retval;
179 static ssize_t
180 proc_file_write(struct file * file, const char * buffer,
181 size_t count, loff_t *ppos)
183 struct inode *inode = file->f_dentry->d_inode;
184 struct proc_dir_entry * dp;
186 dp = (struct proc_dir_entry *) inode->u.generic_ip;
188 if (!dp->write_proc)
189 return -EIO;
191 /* FIXME: does this routine need ppos? probably... */
192 return dp->write_proc(file, buffer, count, dp->data);
196 static long long
197 proc_file_lseek(struct file * file, long long offset, int orig)
199 switch (orig) {
200 case 0:
201 file->f_pos = offset;
202 return(file->f_pos);
203 case 1:
204 file->f_pos += offset;
205 return(file->f_pos);
206 case 2:
207 return(-EINVAL);
208 default:
209 return(-EINVAL);
214 * This function parses a name such as "tty/driver/serial", and
215 * returns the struct proc_dir_entry for "/proc/tty/driver", and
216 * returns "serial" in residual.
218 static int xlate_proc_name(const char *name,
219 struct proc_dir_entry **ret, const char **residual)
221 const char *cp = name, *next;
222 struct proc_dir_entry *de;
223 int len;
225 de = &proc_root;
226 while (1) {
227 next = strchr(cp, '/');
228 if (!next)
229 break;
231 len = next - cp;
232 for (de = de->subdir; de ; de = de->next) {
233 if (proc_match(len, cp, de))
234 break;
236 if (!de)
237 return -ENOENT;
238 cp += len + 1;
240 *residual = cp;
241 *ret = de;
242 return 0;
245 struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
246 struct proc_dir_entry *parent)
248 struct proc_dir_entry *ent = NULL;
249 const char *fn = name;
250 int len;
252 if (!parent && xlate_proc_name(name, &parent, &fn) != 0)
253 goto out;
254 len = strlen(fn);
256 ent = kmalloc(sizeof(struct proc_dir_entry) + len + 1, GFP_KERNEL);
257 if (!ent)
258 goto out;
259 memset(ent, 0, sizeof(struct proc_dir_entry));
260 memcpy(((char *) ent) + sizeof(*ent), fn, len + 1);
261 ent->name = ((char *) ent) + sizeof(*ent);
262 ent->namelen = len;
264 if (S_ISDIR(mode)) {
265 if ((mode & S_IALLUGO) == 0)
266 mode |= S_IRUGO | S_IXUGO;
267 ent->ops = &proc_dyna_dir_inode_operations;
268 ent->nlink = 2;
269 } else {
270 if ((mode & S_IFMT) == 0)
271 mode |= S_IFREG;
272 if ((mode & S_IALLUGO) == 0)
273 mode |= S_IRUGO;
274 ent->nlink = 1;
276 ent->mode = mode;
278 proc_register(parent, ent);
280 out:
281 return ent;
284 extern void free_proc_entry(struct proc_dir_entry *);
285 void free_proc_entry(struct proc_dir_entry *de)
287 int ino = de->low_ino;
289 if (ino >= PROC_DYNAMIC_FIRST &&
290 ino < PROC_DYNAMIC_FIRST+PROC_NDYNAMIC)
291 kfree(de);
295 * Remove a /proc entry and free it if it's not currently in use.
296 * If it is in use, we set the 'deleted' flag.
298 void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
300 struct proc_dir_entry *de;
301 const char *fn = name;
302 int len;
304 if (!parent && xlate_proc_name(name, &parent, &fn) != 0)
305 goto out;
306 len = strlen(fn);
308 for (de = parent->subdir; de ; de = de->next) {
309 if (proc_match(len, fn, de))
310 break;
313 if (de) {
314 proc_unregister(parent, de->low_ino);
315 de->nlink = 0;
316 de->deleted = 1;
317 if (!de->count)
318 free_proc_entry(de);
319 else {
320 printk("remove_proc_entry: %s/%s busy, count=%d\n",
321 parent->name, de->name, de->count);
324 out:
325 return;