blob: 691f5f97b55efc9e142012f89aa929f7e052b01e [file] [log] [blame]
/*
* linux/fs/proc/root.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* proc root directory handling functions
*/
#include <asm/segment.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/config.h>
static int proc_readroot(struct inode *, struct file *, struct dirent *, int);
static int proc_lookuproot(struct inode *,const char *,int,struct inode **);
static struct file_operations proc_root_operations = {
NULL, /* lseek - default */
NULL, /* read - bad */
NULL, /* write - bad */
proc_readroot, /* readdir */
NULL, /* select - default */
NULL, /* ioctl - default */
NULL, /* mmap */
NULL, /* no special open code */
NULL, /* no special release code */
NULL /* no fsync */
};
/*
* proc directories can do almost nothing..
*/
struct inode_operations proc_root_inode_operations = {
&proc_root_operations, /* default base directory file-ops */
NULL, /* create */
proc_lookuproot, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
NULL, /* truncate */
NULL /* permission */
};
static struct proc_dir_entry root_dir[] = {
{ 1,1,"." },
{ 1,2,".." },
{ 2,7,"loadavg" },
{ 3,6,"uptime" },
{ 4,7,"meminfo" },
{ 5,4,"kmsg" },
{ 6,7,"version" },
{ 7,4,"self" }, /* will change inode # */
{ 8,3,"net" },
#ifdef CONFIG_DEBUG_MALLOC
{13,6,"malloc" },
#endif
};
#define NR_ROOT_DIRENTRY ((sizeof (root_dir))/(sizeof (root_dir[0])))
static int proc_lookuproot(struct inode * dir,const char * name, int len,
struct inode ** result)
{
unsigned int pid, c;
int i, ino;
*result = NULL;
if (!dir)
return -ENOENT;
if (!S_ISDIR(dir->i_mode)) {
iput(dir);
return -ENOENT;
}
i = NR_ROOT_DIRENTRY;
while (i-- > 0 && !proc_match(len,name,root_dir+i))
/* nothing */;
if (i >= 0) {
ino = root_dir[i].low_ino;
if (ino == 1) {
*result = dir;
return 0;
}
if (ino == 7) /* self modifying inode ... */
ino = (current->pid << 16) + 2;
} else {
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) + 2;
}
if (!(*result = iget(dir->i_sb,ino))) {
iput(dir);
return -ENOENT;
}
iput(dir);
return 0;
}
static int proc_readroot(struct inode * inode, struct file * filp,
struct dirent * dirent, int count)
{
struct task_struct * p;
unsigned int nr,pid;
int i,j;
if (!inode || !S_ISDIR(inode->i_mode))
return -EBADF;
repeat:
nr = filp->f_pos;
if (nr < NR_ROOT_DIRENTRY) {
struct proc_dir_entry * de = root_dir + nr;
filp->f_pos++;
i = de->namelen;
put_fs_long(de->low_ino, &dirent->d_ino);
put_fs_word(i,&dirent->d_reclen);
put_fs_byte(0,i+dirent->d_name);
j = i;
while (i--)
put_fs_byte(de->name[i], i+dirent->d_name);
return j;
}
nr -= NR_ROOT_DIRENTRY;
if (nr >= NR_TASKS)
return 0;
filp->f_pos++;
p = task[nr];
if (!p || !(pid = p->pid))
goto repeat;
if (pid & 0xffff0000)
goto repeat;
j = 10;
i = 1;
while (pid >= j) {
j *= 10;
i++;
}
j = i;
put_fs_long((pid << 16)+2, &dirent->d_ino);
put_fs_word(i, &dirent->d_reclen);
put_fs_byte(0, i+dirent->d_name);
while (i--) {
put_fs_byte('0'+(pid % 10), i+dirent->d_name);
pid /= 10;
}
return j;
}