/*
 *  linux/fs/proc/foo.c
 *
 *  Copyright (C) 1993 Linus Torvalds, Michael K. Johnson, and Your N. Here
 *
 *  proc foo directory handling functions
 *
 *  inode numbers 200 - 256 are reserved for this directory
 *  (/proc/foo/ and its subdirectories)
 */

#include <asm/segment.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>

static int proc_readfoo(struct inode *, struct file *, struct dirent *, int);
static int proc_lookupfoo(struct inode *,const char *,int,struct inode **);
static int proc_read(struct inode * inode, struct file * file,
		     char * buf, int count);

static struct file_operations proc_foo_operations = {
	NULL,			/* lseek - default */
	proc_read,		/* read */
	NULL,			/* write - bad */
	proc_readfoo,		/* readdir */
	NULL,			/* select - default */
	NULL,			/* ioctl - default */
	NULL,			/* mmap */
	NULL,			/* no special open code */
	NULL			/* no special release code */
};

/*
 * proc directories can do almost nothing..
 */
struct inode_operations proc_foo_inode_operations = {
	&proc_foo_operations,	/* default foo directory file-ops */
	NULL,			/* create */
	proc_lookupfoo,		/* 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 foo_dir[] = {
	{ 1,2,".." },
	{ 9,1,"." },
	{ 200,3,"bar" },
	{ 201,4,"suds" },
	{ 202,5,"xyzzy" },
	{ 203,3,"baz" },
	{ 204,4,"dir1" },
	{ 205,4,"dir2" },
	{ 206,8,"rootfile" }
};

#define NR_FOO_DIRENTRY ((sizeof (foo_dir))/(sizeof (foo_dir[0])))

unsigned int get_bar(char * buffer);
unsigned int get_suds(char * buffer);
unsigned int get_xyzzy(char * buffer);
unsigned int get_baz(char * buffer);
unsigned int get_rootfile(char * buffer);


static int proc_read(struct inode * inode, struct file * file,
		     char * buf, int count)
{
	char * page;
	int length;
	int end;
	unsigned int ino;

	if (count < 0)
		return -EINVAL;
	page = (char *) get_free_page(GFP_KERNEL);
	if (!page)
		return -ENOMEM;
	ino = inode->i_ino;
	switch (ino) {
		case 200:
			length = get_bar(page);
			break;
		case 201:
			length = get_suds(page);
			break;
		case 202:
			length = get_xyzzy(page);
			break;
		case 203:
			length = get_baz(page);
			break;
		case 206:
			length = get_rootfile(page);
			break;
		default:
			free_page((unsigned long) page);
			return -EBADF;
	}
	if (file->f_pos >= length) {
		free_page((unsigned long) page);
		return 0;
	}
	if (count + file->f_pos > length)
		count = length - file->f_pos;
	end = count + file->f_pos;
	memcpy_tofs(buf, page + file->f_pos, count);
	free_page((unsigned long) page);
	file->f_pos = end;
	return count;

}

static int proc_lookupfoo(struct inode * dir,const char * name, int len,
	struct inode ** result)
{
	unsigned int pid, ino;
	int i;

	*result = NULL;
	if (!dir)
		return -ENOENT;
	if (!S_ISDIR(dir->i_mode)) {
		iput(dir);
		return -ENOENT;
	}
	ino = dir->i_ino;
	i = NR_FOO_DIRENTRY;
	while (i-- > 0 && !proc_match(len,name,foo_dir+i))
		/* nothing */;
	if (i < 0) {
		iput(dir);
		return -ENOENT;
	}
	if (!(*result = iget(dir->i_sb,ino))) {
		iput(dir);
		return -ENOENT;
	}
	iput(dir);
	return 0;
}

static int proc_readfoo(struct inode * inode, struct file * filp,
	struct dirent * dirent, int count)
{
	struct proc_dir_entry * de;
	unsigned int pid, ino;
	int i,j;

	if (!inode || !S_ISDIR(inode->i_mode))
		return -EBADF;
	ino = inode->i_ino;
	if (((unsigned) filp->f_pos) < NR_FOO_DIRENTRY) {
		de = foo_dir + filp->f_pos;
		filp->f_pos++;
		i = de->namelen;
		ino = de->low_ino;
		put_fs_long(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;
	}
	return 0;
}


unsigned int get_foo(char * buffer)
{

/* code to find everything goes here */

	return sprintf(buffer, "format string", variables);
}


unsigned int get_suds(char * buffer)
{

/* code to find everything goes here */

	return sprintf(buffer, "format string", variables);
}


unsigned int get_xyzzy(char * buffer)
{

/* code to find everything goes here */

	return sprintf(buffer, "format string", variables);
}


unsigned int get_baz(char * buffer)
{

/* code to find everything goes here */

	return sprintf(buffer, "format string", variables);
}


unsigned int get_rootfile(char * buffer)
{

/* code to find everything goes here */

	return sprintf(buffer, "format string", variables);
}
