This source file includes following definitions.
- proc_register
- proc_unregister
- make_inode_number
- proc_register_dynamic
- proc_self_followlink
- proc_self_readlink
- proc_root_init
- proc_match
- proc_lookup
- proc_root_lookup
- proc_readdir
- proc_root_readdir
1
2
3
4
5
6
7
8
9 #include <asm/segment.h>
10
11 #include <linux/errno.h>
12 #include <linux/sched.h>
13 #include <linux/proc_fs.h>
14 #include <linux/stat.h>
15 #include <linux/config.h>
16 #ifdef CONFIG_APM
17 #include <linux/apm_bios.h>
18 #endif
19 #include <asm/bitops.h>
20
21
22
23
24 #define FIRST_PROCESS_ENTRY 256
25
26 static int proc_root_readdir(struct inode *, struct file *, void *, filldir_t);
27 static int proc_root_lookup(struct inode *,const char *,int,struct inode **);
28
29 static unsigned char proc_alloc_map[PROC_NDYNAMIC / 8] = {0};
30
31
32
33
34
35
36
37
38
39 static struct file_operations proc_dir_operations = {
40 NULL,
41 NULL,
42 NULL,
43 proc_readdir,
44 NULL,
45 NULL,
46 NULL,
47 NULL,
48 NULL,
49 NULL
50 };
51
52
53
54
55 struct inode_operations proc_dir_inode_operations = {
56 &proc_dir_operations,
57 NULL,
58 proc_lookup,
59 NULL,
60 NULL,
61 NULL,
62 NULL,
63 NULL,
64 NULL,
65 NULL,
66 NULL,
67 NULL,
68 NULL,
69 NULL,
70 NULL,
71 NULL,
72 NULL
73 };
74
75
76
77
78
79
80 static struct file_operations proc_root_operations = {
81 NULL,
82 NULL,
83 NULL,
84 proc_root_readdir,
85 NULL,
86 NULL,
87 NULL,
88 NULL,
89 NULL,
90 NULL
91 };
92
93
94
95
96 static struct inode_operations proc_root_inode_operations = {
97 &proc_root_operations,
98 NULL,
99 proc_root_lookup,
100 NULL,
101 NULL,
102 NULL,
103 NULL,
104 NULL,
105 NULL,
106 NULL,
107 NULL,
108 NULL,
109 NULL,
110 NULL,
111 NULL,
112 NULL,
113 NULL
114 };
115
116
117
118
119 struct proc_dir_entry proc_root = {
120 PROC_ROOT_INO, 5, "/proc",
121 S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
122 0, &proc_root_inode_operations,
123 NULL, NULL,
124 NULL,
125 &proc_root, NULL
126 };
127
128 struct proc_dir_entry proc_net = {
129 PROC_NET, 3, "net",
130 S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
131 0, &proc_dir_inode_operations,
132 NULL, NULL,
133 NULL,
134 NULL, NULL
135 };
136
137 struct proc_dir_entry proc_scsi = {
138 PROC_SCSI, 4, "scsi",
139 S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
140 0, &proc_dir_inode_operations,
141 NULL, NULL,
142 NULL, &proc_root, NULL
143 };
144
145 struct proc_dir_entry proc_sys_root = {
146 PROC_SYS, 3, "sys",
147 S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
148 0, &proc_dir_inode_operations,
149 NULL, NULL,
150 NULL,
151 NULL, NULL
152 };
153
154 int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp)
155 {
156 dp->next = dir->subdir;
157 dp->parent = dir;
158 dir->subdir = dp;
159 if (S_ISDIR(dp->mode))
160 dir->nlink++;
161 return 0;
162 }
163
164 int proc_unregister(struct proc_dir_entry * dir, int ino)
165 {
166 struct proc_dir_entry **p = &dir->subdir, *dp;
167
168 while ((dp = *p) != NULL) {
169 if (dp->low_ino == ino) {
170 *p = dp->next;
171 dp->next = NULL;
172 if (S_ISDIR(dp->mode))
173 dir->nlink--;
174 if (ino >= PROC_DYNAMIC_FIRST &&
175 ino < PROC_DYNAMIC_FIRST+PROC_NDYNAMIC)
176 clear_bit(ino-PROC_DYNAMIC_FIRST,
177 (void *) proc_alloc_map);
178 return 0;
179 }
180 p = &dp->next;
181 }
182 return -EINVAL;
183 }
184
185 static int make_inode_number(void)
186 {
187 int i = find_first_zero_bit((void *) proc_alloc_map, PROC_NDYNAMIC);
188 if (i<0 || i>=PROC_NDYNAMIC)
189 return -1;
190 set_bit(i, (void *) proc_alloc_map);
191 return PROC_DYNAMIC_FIRST + i;
192 }
193
194 int proc_register_dynamic(struct proc_dir_entry * dir,
195 struct proc_dir_entry * dp)
196 {
197 int i = make_inode_number();
198 if (i < 0)
199 return -EAGAIN;
200 dp->low_ino = i;
201 dp->next = dir->subdir;
202 dp->parent = dir;
203 dir->subdir = dp;
204 if (S_ISDIR(dp->mode))
205 dir->nlink++;
206 return 0;
207 }
208
209
210
211
212 static int proc_self_followlink(struct inode * dir, struct inode * inode,
213 int flag, int mode, struct inode ** res_inode)
214 {
215 iput(dir);
216 *res_inode = proc_get_inode(inode->i_sb, (current->pid << 16) + PROC_PID_INO, &proc_pid);
217 iput(inode);
218 if (!*res_inode)
219 return -ENOENT;
220 return 0;
221 }
222
223 static int proc_self_readlink(struct inode * inode, char * buffer, int buflen)
224 {
225 int len;
226 char tmp[30];
227
228 iput(inode);
229 len = 1 + sprintf(tmp, "%d", current->pid);
230 if (buflen < len)
231 len = buflen;
232 memcpy_tofs(buffer, tmp, len);
233 return len;
234 }
235
236 static struct inode_operations proc_self_inode_operations = {
237 NULL,
238 NULL,
239 NULL,
240 NULL,
241 NULL,
242 NULL,
243 NULL,
244 NULL,
245 NULL,
246 NULL,
247 proc_self_readlink,
248 proc_self_followlink,
249 NULL,
250 NULL,
251 NULL,
252 NULL,
253 NULL
254 };
255
256 void proc_root_init(void)
257 {
258 static int done = 0;
259
260 if (done)
261 return;
262 done = 1;
263 proc_base_init();
264 proc_register(&proc_root, &(struct proc_dir_entry) {
265 PROC_LOADAVG, 7, "loadavg",
266 S_IFREG | S_IRUGO, 1, 0, 0,
267 });
268 proc_register(&proc_root, &(struct proc_dir_entry) {
269 PROC_UPTIME, 6, "uptime",
270 S_IFREG | S_IRUGO, 1, 0, 0,
271 });
272 proc_register(&proc_root, &(struct proc_dir_entry) {
273 PROC_MEMINFO, 7, "meminfo",
274 S_IFREG | S_IRUGO, 1, 0, 0,
275 });
276 proc_register(&proc_root, &(struct proc_dir_entry) {
277 PROC_KMSG, 4, "kmsg",
278 S_IFREG | S_IRUSR, 1, 0, 0,
279 });
280 proc_register(&proc_root, &(struct proc_dir_entry) {
281 PROC_VERSION, 7, "version",
282 S_IFREG | S_IRUGO, 1, 0, 0,
283 });
284 #ifdef CONFIG_PCI
285 proc_register(&proc_root, &(struct proc_dir_entry) {
286 PROC_PCI, 3, "pci",
287 S_IFREG | S_IRUGO, 1, 0, 0,
288 });
289 #endif
290 proc_register(&proc_root, &(struct proc_dir_entry) {
291 PROC_CPUINFO, 7, "cpuinfo",
292 S_IFREG | S_IRUGO, 1, 0, 0,
293 });
294 proc_register(&proc_root, &(struct proc_dir_entry) {
295 PROC_SELF, 4, "self",
296 S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, 1, 0, 0,
297 64, &proc_self_inode_operations,
298 });
299 proc_register(&proc_root, &proc_net);
300 proc_register(&proc_root, &proc_scsi);
301 proc_register(&proc_root, &proc_sys_root);
302
303 #ifdef CONFIG_DEBUG_MALLOC
304 proc_register(&proc_root, &(struct proc_dir_entry) {
305 PROC_MALLOC, 6, "malloc",
306 S_IFREG | S_IRUGO, 1, 0, 0,
307 });
308 #endif
309 proc_register(&proc_root, &(struct proc_dir_entry) {
310 PROC_KCORE, 5, "kcore",
311 S_IFREG | S_IRUSR, 1, 0, 0,
312 });
313
314 #ifdef CONFIG_MODULES
315 proc_register(&proc_root, &(struct proc_dir_entry) {
316 PROC_MODULES, 7, "modules",
317 S_IFREG | S_IRUGO, 1, 0, 0,
318 });
319 proc_register(&proc_root, &(struct proc_dir_entry) {
320 PROC_KSYMS, 5, "ksyms",
321 S_IFREG | S_IRUGO, 1, 0, 0,
322 });
323 #endif
324 proc_register(&proc_root, &(struct proc_dir_entry) {
325 PROC_STAT, 4, "stat",
326 S_IFREG | S_IRUGO, 1, 0, 0,
327 });
328 proc_register(&proc_root, &(struct proc_dir_entry) {
329 PROC_DEVICES, 7, "devices",
330 S_IFREG | S_IRUGO, 1, 0, 0,
331 });
332 proc_register(&proc_root, &(struct proc_dir_entry) {
333 PROC_INTERRUPTS, 10,"interrupts",
334 S_IFREG | S_IRUGO, 1, 0, 0,
335 });
336 #ifdef __SMP_PROF__
337 proc_register(&proc_root, &(struct proc_dir_entry) {
338 PROC_SMP_PROF, 3,"smp",
339 S_IFREG | S_IRUGO, 1, 0, 0,
340 });
341 #endif
342 proc_register(&proc_root, &(struct proc_dir_entry) {
343 PROC_FILESYSTEMS, 11,"filesystems",
344 S_IFREG | S_IRUGO, 1, 0, 0,
345 });
346 proc_register(&proc_root, &(struct proc_dir_entry) {
347 PROC_DMA, 3, "dma",
348 S_IFREG | S_IRUGO, 1, 0, 0,
349 });
350 proc_register(&proc_root, &(struct proc_dir_entry) {
351 PROC_IOPORTS, 7, "ioports",
352 S_IFREG | S_IRUGO, 1, 0, 0,
353 });
354 #ifdef CONFIG_APM
355 proc_register(&proc_root, &(struct proc_dir_entry) {
356 PROC_APM, 3, "apm",
357 S_IFREG | S_IRUGO, 1, 0, 0,
358 });
359 #endif
360 proc_register(&proc_root, &(struct proc_dir_entry) {
361 PROC_CMDLINE, 7, "cmdline",
362 S_IFREG | S_IRUGO, 1, 0, 0,
363 });
364
365 proc_register( &proc_root, &(struct proc_dir_entry)
366 { PROC_MTAB, 6, "mounts", S_IFREG | S_IRUGO, 1, 0, 0, } );
367
368 if (prof_shift) {
369 proc_register(&proc_root, &(struct proc_dir_entry) {
370 PROC_PROFILE, 7, "profile",
371 S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
372 });
373 }
374 }
375
376
377 int proc_match(int len,const char * name,struct proc_dir_entry * de)
378 {
379 if (!de || !de->low_ino)
380 return 0;
381
382 if (!len && (de->name[0]=='.') && (de->name[1]=='\0'))
383 return 1;
384 if (de->namelen != len)
385 return 0;
386 return !memcmp(name, de->name, len);
387 }
388
389 int proc_lookup(struct inode * dir,const char * name, int len,
390 struct inode ** result)
391 {
392 struct proc_dir_entry * de;
393 int ino;
394
395 *result = NULL;
396 if (!dir || !S_ISDIR(dir->i_mode)) {
397 iput(dir);
398 return -ENOTDIR;
399 }
400
401 de = (struct proc_dir_entry *) dir->u.generic_ip;
402 if (!de) {
403 iput(dir);
404 return -EINVAL;
405 }
406
407
408 *result = dir;
409 if (!len)
410 return 0;
411 if (name[0] == '.') {
412 if (len == 1)
413 return 0;
414 if (name[1] == '.' && len == 2) {
415 struct inode * inode;
416 inode = proc_get_inode(dir->i_sb, de->parent->low_ino, de->parent);
417 iput(dir);
418 if (!inode)
419 return -EINVAL;
420 *result = inode;
421 return 0;
422 }
423 }
424
425 *result = NULL;
426 for (de = de->subdir; de ; de = de->next) {
427 if (proc_match(len, name, de))
428 break;
429 }
430 if (!de) {
431 iput(dir);
432 return -ENOENT;
433 }
434
435 ino = de->low_ino | (dir->i_ino & ~(0xffff));
436
437 if (!(*result = proc_get_inode(dir->i_sb, ino, de))) {
438 iput(dir);
439 return -EINVAL;
440 }
441 iput(dir);
442 return 0;
443 }
444
445 static int proc_root_lookup(struct inode * dir,const char * name, int len,
446 struct inode ** result)
447 {
448 unsigned int pid, c;
449 int i, ino, retval;
450
451 dir->i_count++;
452 retval = proc_lookup(dir, name, len, result);
453 if (retval != -ENOENT) {
454 iput(dir);
455 return retval;
456 }
457
458 pid = 0;
459 while (len-- > 0) {
460 c = *name - '0';
461 name++;
462 if (c > 9) {
463 pid = 0;
464 break;
465 }
466 pid *= 10;
467 pid += c;
468 if (pid & 0xffff0000) {
469 pid = 0;
470 break;
471 }
472 }
473 for (i = 0 ; i < NR_TASKS ; i++)
474 if (task[i] && task[i]->pid == pid)
475 break;
476 if (!pid || i >= NR_TASKS) {
477 iput(dir);
478 return -ENOENT;
479 }
480 ino = (pid << 16) + PROC_PID_INO;
481 if (!(*result = proc_get_inode(dir->i_sb, ino, &proc_pid))) {
482 iput(dir);
483 return -EINVAL;
484 }
485 iput(dir);
486 return 0;
487 }
488
489
490
491
492
493
494
495
496
497
498 int proc_readdir(struct inode * inode, struct file * filp,
499 void * dirent, filldir_t filldir)
500 {
501 struct proc_dir_entry * de;
502 unsigned int ino;
503 int i;
504
505 if (!inode || !S_ISDIR(inode->i_mode))
506 return -ENOTDIR;
507 ino = inode->i_ino;
508 de = (struct proc_dir_entry *) inode->u.generic_ip;
509 if (!de)
510 return -EINVAL;
511 i = filp->f_pos;
512 switch (i) {
513 case 0:
514 if (filldir(dirent, ".", 1, i, ino) < 0)
515 return 0;
516 i++;
517 filp->f_pos++;
518
519 case 1:
520 if (filldir(dirent, "..", 2, i, de->parent->low_ino) < 0)
521 return 0;
522 i++;
523 filp->f_pos++;
524
525 default:
526 ino &= ~0xffff;
527 de = de->subdir;
528 i -= 2;
529 for (;;) {
530 if (!de)
531 return 1;
532 if (!i)
533 break;
534 de = de->next;
535 i--;
536 }
537
538 do {
539 if (filldir(dirent, de->name, de->namelen, filp->f_pos, ino | de->low_ino) < 0)
540 return 0;
541 filp->f_pos++;
542 de = de->next;
543 } while (de);
544 }
545 return 1;
546 }
547
548 #define NUMBUF 10
549
550 static int proc_root_readdir(struct inode * inode, struct file * filp,
551 void * dirent, filldir_t filldir)
552 {
553 char buf[NUMBUF];
554 unsigned int nr,pid;
555 unsigned long i,j;
556
557 nr = filp->f_pos;
558 if (nr < FIRST_PROCESS_ENTRY) {
559 int error = proc_readdir(inode, filp, dirent, filldir);
560 if (error <= 0)
561 return error;
562 filp->f_pos = nr = FIRST_PROCESS_ENTRY;
563 }
564
565 for (nr -= FIRST_PROCESS_ENTRY; nr < NR_TASKS; nr++, filp->f_pos++) {
566 struct task_struct * p = task[nr];
567
568 if (!p || !(pid = p->pid))
569 continue;
570
571 j = NUMBUF;
572 i = pid;
573 do {
574 j--;
575 buf[j] = '0' + (i % 10);
576 i /= 10;
577 } while (i);
578
579 if (filldir(dirent, buf+j, NUMBUF-j, filp->f_pos, (pid << 16) + PROC_PID_INO) < 0)
580 break;
581 }
582 return 0;
583 }