Import 2.3.26pre2
[davej-history.git] / fs / proc / generic.c
blob5ef59004cdb9de3330c78b471c1b9959e794ceab
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, /* get_block */
64 NULL, /* readpage */
65 NULL, /* writepage */
66 NULL, /* flushpage */
67 NULL, /* truncate */
68 NULL, /* permission */
69 NULL, /* smap */
70 NULL /* revalidate */
73 #ifndef MIN
74 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
75 #endif
77 /* 4K page size but our output routines use some slack for overruns */
78 #define PROC_BLOCK_SIZE (3*1024)
80 static ssize_t
81 proc_file_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos)
83 struct inode * inode = file->f_dentry->d_inode;
84 char *page;
85 ssize_t retval=0;
86 int eof=0;
87 ssize_t n, count;
88 char *start;
89 struct proc_dir_entry * dp;
91 dp = (struct proc_dir_entry *) inode->u.generic_ip;
92 if (!(page = (char*) __get_free_page(GFP_KERNEL)))
93 return -ENOMEM;
95 while ((nbytes > 0) && !eof)
97 count = MIN(PROC_BLOCK_SIZE, nbytes);
99 start = NULL;
100 if (dp->get_info) {
102 * Handle backwards compatibility with the old net
103 * routines.
105 * XXX What gives with the file->f_flags & O_ACCMODE
106 * test? Seems stupid to me....
108 n = dp->get_info(page, &start, *ppos, count,
109 (file->f_flags & O_ACCMODE) == O_RDWR);
110 if (n < count)
111 eof = 1;
112 } else if (dp->read_proc) {
113 n = dp->read_proc(page, &start, *ppos,
114 count, &eof, dp->data);
115 } else
116 break;
118 if (!start) {
120 * For proc files that are less than 4k
122 start = page + *ppos;
123 n -= *ppos;
124 if (n <= 0)
125 break;
126 if (n > count)
127 n = count;
129 if (n == 0)
130 break; /* End of file */
131 if (n < 0) {
132 if (retval == 0)
133 retval = n;
134 break;
137 /* This is a hack to allow mangling of file pos independent
138 * of actual bytes read. Simply place the data at page,
139 * return the bytes, and set `start' to the desired offset
140 * as an unsigned int. - Paul.Russell@rustcorp.com.au
142 n -= copy_to_user(buf, start < page ? page : start, n);
143 if (n == 0) {
144 if (retval == 0)
145 retval = -EFAULT;
146 break;
149 *ppos += start < page ? (long)start : n; /* Move down the file */
150 nbytes -= n;
151 buf += n;
152 retval += n;
154 free_page((unsigned long) page);
155 return retval;
158 static ssize_t
159 proc_file_write(struct file * file, const char * buffer,
160 size_t count, loff_t *ppos)
162 struct inode *inode = file->f_dentry->d_inode;
163 struct proc_dir_entry * dp;
165 dp = (struct proc_dir_entry *) inode->u.generic_ip;
167 if (!dp->write_proc)
168 return -EIO;
170 /* FIXME: does this routine need ppos? probably... */
171 return dp->write_proc(file, buffer, count, dp->data);
175 static long long
176 proc_file_lseek(struct file * file, long long offset, int orig)
178 switch (orig) {
179 case 0:
180 file->f_pos = offset;
181 return(file->f_pos);
182 case 1:
183 file->f_pos += offset;
184 return(file->f_pos);
185 case 2:
186 return(-EINVAL);
187 default:
188 return(-EINVAL);
193 * This function parses a name such as "tty/driver/serial", and
194 * returns the struct proc_dir_entry for "/proc/tty/driver", and
195 * returns "serial" in residual.
197 static int xlate_proc_name(const char *name,
198 struct proc_dir_entry **ret, const char **residual)
200 const char *cp = name, *next;
201 struct proc_dir_entry *de;
202 int len;
204 de = &proc_root;
205 while (1) {
206 next = strchr(cp, '/');
207 if (!next)
208 break;
210 len = next - cp;
211 for (de = de->subdir; de ; de = de->next) {
212 if (proc_match(len, cp, de))
213 break;
215 if (!de)
216 return -ENOENT;
217 cp += len + 1;
219 *residual = cp;
220 *ret = de;
221 return 0;
224 struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
225 struct proc_dir_entry *parent)
227 struct proc_dir_entry *ent = NULL;
228 const char *fn = name;
229 int len;
231 if (!parent && xlate_proc_name(name, &parent, &fn) != 0)
232 goto out;
233 len = strlen(fn);
235 ent = kmalloc(sizeof(struct proc_dir_entry) + len + 1, GFP_KERNEL);
236 if (!ent)
237 goto out;
238 memset(ent, 0, sizeof(struct proc_dir_entry));
239 memcpy(((char *) ent) + sizeof(*ent), fn, len + 1);
240 ent->name = ((char *) ent) + sizeof(*ent);
241 ent->namelen = len;
243 if (S_ISDIR(mode)) {
244 if ((mode & S_IALLUGO) == 0)
245 mode |= S_IRUGO | S_IXUGO;
246 ent->ops = &proc_dyna_dir_inode_operations;
247 ent->nlink = 2;
248 } else {
249 if ((mode & S_IFMT) == 0)
250 mode |= S_IFREG;
251 if ((mode & S_IALLUGO) == 0)
252 mode |= S_IRUGO;
253 ent->nlink = 1;
255 ent->mode = mode;
257 proc_register(parent, ent);
259 out:
260 return ent;
263 extern void free_proc_entry(struct proc_dir_entry *);
264 void free_proc_entry(struct proc_dir_entry *de)
266 int ino = de->low_ino;
268 if (ino >= PROC_DYNAMIC_FIRST &&
269 ino < PROC_DYNAMIC_FIRST+PROC_NDYNAMIC)
270 kfree(de);
274 * Remove a /proc entry and free it if it's not currently in use.
275 * If it is in use, we set the 'deleted' flag.
277 void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
279 struct proc_dir_entry *de;
280 const char *fn = name;
281 int len;
283 if (!parent && xlate_proc_name(name, &parent, &fn) != 0)
284 goto out;
285 len = strlen(fn);
287 for (de = parent->subdir; de ; de = de->next) {
288 if (proc_match(len, fn, de))
289 break;
292 if (de) {
293 proc_unregister(parent, de->low_ino);
294 de->nlink = 0;
295 de->deleted = 1;
296 if (!de->count)
297 free_proc_entry(de);
298 else {
299 printk("remove_proc_entry: %s/%s busy, count=%d\n",
300 parent->name, de->name, de->count);
303 out:
304 return;