/* * These are the generic /proc directory operations. They * use the in-memory "struct proc_dir_entry" tree to parse * the /proc directory. * * NOTE! The /proc/scsi directory currently does not correctly * build up the proc_dir_entry tree, and will show up empty. */ static struct file_operations proc_dir_operations = { NULL, /* lseek - default */ NULL, /* read - bad */ NULL, /* write - bad */ proc_readdir, /* readdir */ NULL, /* select - default */ NULL, /* ioctl - default */ NULL, /* mmap */ NULL, /* no special open code */ NULL, /* no special release code */ NULL /* can't fsync */ };
de = (struct proc_dir_entry *) dir->u.generic_ip; if (!de) { iput(dir); return -EINVAL; }
/* Special case "." and "..": they aren't on the directory list */ *result = dir; if (!len) return 0; if (name[0] == '.') { if (len == 1) return 0; if (name[1] == '.' && len == 2) { struct inode * inode; inode = proc_get_inode(dir->i_sb, de->parent->low_ino, de->parent); iput(dir); if (!inode) return -EINVAL; *result = inode; return 0; } }
*result = NULL; for (de = de->subdir; de ; de = de->next) { if (proc_match(len, name, de)) break; } if (!de) { iput(dir); return -ENOENT; }
pid = 0; while (len-- > 0) { c = *name - '0'; name++; if (c > 9) { pid = 0; break; } pid *= 10; pid += c; if (pid & 0xffff0000) { pid = 0; break; } } for (i = 0 ; i < NR_TASKS ; i++) if (task[i] && task[i]->pid == pid) break; if (!pid || i >= NR_TASKS) { iput(dir); return -ENOENT; } ino = (pid << 16) + PROC_PID_INO; if (!(*result = proc_get_inode(dir->i_sb, ino, &proc_pid))) { iput(dir); return -EINVAL; } iput(dir); return 0; }
/* * This returns non-zero if at EOF, so that the /proc * root directory can use this and check if it should * continue with the <pid> entries.. * * Note that the VFS-layer doesn't care about the return * value of the readdir() call, as long as it's non-negative * for success.. */ int proc_readdir(struct inode * inode, struct file * filp, void * dirent, filldir_t filldir) { struct proc_dir_entry * de; unsigned int ino; int i;
if (!inode || !S_ISDIR(inode->i_mode)) return -ENOTDIR; ino = inode->i_ino; de = (struct proc_dir_entry *) inode->u.generic_ip; if (!de) return -EINVAL; i = filp->f_pos; switch (i) { case 0: if (filldir(dirent, ".", 1, i, ino) < 0) return 0; i++; filp->f_pos++; /* fall through */ case 1: if (filldir(dirent, "..", 2, i, de->parent->low_ino) < 0) return 0; i++; filp->f_pos++; /* fall through */ default: ino &= ~0xffff; de = de->subdir; i -= 2; for (;;) { if (!de) return 1; if (!i) break; de = de->next; i--; }
do { if (filldir(dirent, de->name, de->namelen, filp->f_pos, ino | de->low_ino) < 0) return 0; filp->f_pos++; de = de->next; } while (de); } return 1; }
#define NUMBUF 10
static int proc_root_readdir(struct inode * inode, struct file * filp, void * dirent, filldir_t filldir) { char buf[NUMBUF]; unsigned int nr,pid; unsigned long i,j;
nr = filp->f_pos; if (nr < FIRST_PROCESS_ENTRY) { int error = proc_readdir(inode, filp, dirent, filldir); if (error <= 0) return error; filp->f_pos = nr = FIRST_PROCESS_ENTRY; }
for (nr -= FIRST_PROCESS_ENTRY; nr < NR_TASKS; nr++, filp->f_pos++) { struct task_struct * p = task[nr];
if (!p || !(pid = p->pid)) continue;
j = NUMBUF; i = pid; do { j--; buf[j] = '0' + (i % 10); i /= 10; } while (i);