/*
       * proc/fs/generic.c --- generic routines for the proc-fs
       *
       * This file contains generic proc-fs routines for handling
       * directories and files.
       * 
       * Copyright (C) 1991, 1992 Linus Torvalds.
       * Copyright (C) 1997 Theodore Ts'o
       */
      
      #include <asm/uaccess.h>
      
      #include <linux/errno.h>
      #include <linux/sched.h>
      #include <linux/proc_fs.h>
      #include <linux/stat.h>
      #define __NO_VERSION__
      #include <linux/module.h>
      #include <asm/bitops.h>
      
      static ssize_t proc_file_read(struct file * file, char * buf,
      			      size_t nbytes, loff_t *ppos);
      static ssize_t proc_file_write(struct file * file, const char * buffer,
      			       size_t count, loff_t *ppos);
      static loff_t proc_file_lseek(struct file *, loff_t, 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);
      }
      
      static struct file_operations proc_file_operations = {
      	llseek:		proc_file_lseek,
      	read:		proc_file_read,
      	write:		proc_file_write,
      };
      
      #ifndef MIN
      #define MIN(a,b) (((a) < (b)) ? (a) : (b))
      #endif
      
      /* buffer size is one page but our output routines use some slack for overruns */
      #define PROC_BLOCK_SIZE	(PAGE_SIZE - 1024)
      
      static ssize_t
  50  proc_file_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos)
      {
      	struct inode * inode = file->f_dentry->d_inode;
      	char 	*page;
      	ssize_t	retval=0;
      	int	eof=0;
      	ssize_t	n, count;
      	char	*start;
      	struct proc_dir_entry * dp;
      
      	dp = (struct proc_dir_entry *) inode->u.generic_ip;
  61  	if (!(page = (char*) __get_free_page(GFP_KERNEL)))
  62  		return -ENOMEM;
      
  64  	while ((nbytes > 0) && !eof)
      	{
      		count = MIN(PROC_BLOCK_SIZE, nbytes);
      
      		start = NULL;
  69  		if (dp->get_info) {
      			/*
      			 * Handle backwards compatibility with the old net
      			 * routines.
      			 */
      			n = dp->get_info(page, &start, *ppos, count);
  75  			if (n < count)
      				eof = 1;
  77  		} else if (dp->read_proc) {
      			n = dp->read_proc(page, &start, *ppos,
      					  count, &eof, dp->data);
  80  		} else
  81  			break;
      
  83  		if (!start) {
      			/*
      			 * For proc files that are less than 4k
      			 */
      			start = page + *ppos;
      			n -= *ppos;
  89  			if (n <= 0)
  90  				break;
  91  			if (n > count)
      				n = count;
      		}
  94  		if (n == 0)
  95  			break;	/* End of file */
  96  		if (n < 0) {
  97  			if (retval == 0)
      				retval = n;
  99  			break;
      		}
      		
      		/* This is a hack to allow mangling of file pos independent
       		 * of actual bytes read.  Simply place the data at page,
       		 * return the bytes, and set `start' to the desired offset
       		 * as an unsigned int. - Paul.Russell@rustcorp.com.au
      		 */
       		n -= copy_to_user(buf, start < page ? page : start, n);
 108  		if (n == 0) {
 109  			if (retval == 0)
      				retval = -EFAULT;
 111  			break;
      		}
      
      		*ppos += start < page ? (long)start : n; /* Move down the file */
      		nbytes -= n;
      		buf += n;
      		retval += n;
      	}
      	free_page((unsigned long) page);
 120  	return retval;
      }
      
      static ssize_t
 124  proc_file_write(struct file * file, const char * buffer,
      		size_t count, loff_t *ppos)
      {
      	struct inode *inode = file->f_dentry->d_inode;
      	struct proc_dir_entry * dp;
      	
      	dp = (struct proc_dir_entry *) inode->u.generic_ip;
      
 132  	if (!dp->write_proc)
 133  		return -EIO;
      
      	/* FIXME: does this routine need ppos?  probably... */
 136  	return dp->write_proc(file, buffer, count, dp->data);
      }
      
      
      static loff_t
 141  proc_file_lseek(struct file * file, loff_t offset, int orig)
      {
 143      switch (orig) {
 144      case 0:
 145  	if (offset < 0)
 146  	    return -EINVAL;    
      	file->f_pos = offset;
 148  	return(file->f_pos);
 149      case 1:
 150  	if (offset + file->f_pos < 0)
 151  	    return -EINVAL;    
      	file->f_pos += offset;
 153  	return(file->f_pos);
 154      case 2:
 155  	return(-EINVAL);
 156      default:
 157  	return(-EINVAL);
          }
      }
      
      /*
       * This function parses a name such as "tty/driver/serial", and
       * returns the struct proc_dir_entry for "/proc/tty/driver", and
       * returns "serial" in residual.
       */
 166  static int xlate_proc_name(const char *name,
      			   struct proc_dir_entry **ret, const char **residual)
      {
      	const char     		*cp = name, *next;
      	struct proc_dir_entry	*de;
      	int			len;
      
      	de = &proc_root;
 174  	while (1) {
      		next = strchr(cp, '/');
 176  		if (!next)
 177  			break;
      
      		len = next - cp;
 180  		for (de = de->subdir; de ; de = de->next) {
 181  			if (proc_match(len, cp, de))
 182  				break;
      		}
 184  		if (!de)
 185  			return -ENOENT;
      		cp += len + 1;
      	}
      	*residual = cp;
      	*ret = de;
 190  	return 0;
      }
      
      static unsigned char proc_alloc_map[PROC_NDYNAMIC / 8];
      
 195  static int make_inode_number(void)
      {
      	int i = find_first_zero_bit((void *) proc_alloc_map, PROC_NDYNAMIC);
 198  	if (i<0 || i>=PROC_NDYNAMIC) 
 199  		return -1;
      	set_bit(i, (void *) proc_alloc_map);
 201  	return PROC_DYNAMIC_FIRST + i;
      }
      
 204  static int proc_readlink(struct dentry *dentry, char *buffer, int buflen)
      {
      	char *s=((struct proc_dir_entry *)dentry->d_inode->u.generic_ip)->data;
 207  	return vfs_readlink(dentry, buffer, buflen, s);
      }
      
 210  static int proc_follow_link(struct dentry *dentry, struct nameidata *nd)
      {
      	char *s=((struct proc_dir_entry *)dentry->d_inode->u.generic_ip)->data;
 213  	return vfs_follow_link(nd, s);
      }
      
      static struct inode_operations proc_link_inode_operations = {
      	readlink:	proc_readlink,
      	follow_link:	proc_follow_link,
      };
      
      /*
       * As some entries in /proc are volatile, we want to 
       * get rid of unused dentries.  This could be made 
       * smarter: we could keep a "volatile" flag in the 
       * inode to indicate which ones to keep.
       */
 227  static int proc_delete_dentry(struct dentry * dentry)
      {
 229  	return 1;
      }
      
      static struct dentry_operations proc_dentry_operations =
      {
      	d_delete:	proc_delete_dentry,
      };
      
      /*
       * Don't create negative dentries here, return -ENOENT by hand
       * instead.
       */
 241  struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry)
      {
      	struct inode *inode;
      	struct proc_dir_entry * de;
      	int error;
      
      	error = -ENOENT;
      	inode = NULL;
      	de = (struct proc_dir_entry *) dir->u.generic_ip;
 250  	if (de) {
 251  		for (de = de->subdir; de ; de = de->next) {
 252  			if (!de || !de->low_ino)
 253  				continue;
 254  			if (de->namelen != dentry->d_name.len)
 255  				continue;
 256  			if (!memcmp(dentry->d_name.name, de->name, de->namelen)) {
      				int ino = de->low_ino;
      				error = -EINVAL;
      				inode = proc_get_inode(dir->i_sb, ino, de);
 260  				break;
      			}
      		}
      	}
      
 265  	if (inode) {
      		dentry->d_op = &proc_dentry_operations;
      		d_add(dentry, inode);
 268  		return NULL;
      	}
 270  	return ERR_PTR(error);
      }
      
      /*
       * 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..
       */
 282  int proc_readdir(struct file * filp,
      	void * dirent, filldir_t filldir)
      {
      	struct proc_dir_entry * de;
      	unsigned int ino;
      	int i;
      	struct inode *inode = filp->f_dentry->d_inode;
      
      	ino = inode->i_ino;
      	de = (struct proc_dir_entry *) inode->u.generic_ip;
 292  	if (!de)
 293  		return -EINVAL;
      	i = filp->f_pos;
 295  	switch (i) {
 296  		case 0:
 297  			if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
 298  				return 0;
      			i++;
      			filp->f_pos++;
      			/* fall through */
 302  		case 1:
      			if (filldir(dirent, "..", 2, i,
      				    filp->f_dentry->d_parent->d_inode->i_ino,
 305  				    DT_DIR) < 0)
 306  				return 0;
      			i++;
      			filp->f_pos++;
      			/* fall through */
 310  		default:
      			de = de->subdir;
      			i -= 2;
 313  			for (;;) {
 314  				if (!de)
 315  					return 1;
 316  				if (!i)
 317  					break;
      				de = de->next;
      				i--;
      			}
      
 322  			do {
      				if (filldir(dirent, de->name, de->namelen, filp->f_pos,
 324  					    de->low_ino, de->mode >> 12) < 0)
 325  					return 0;
      				filp->f_pos++;
      				de = de->next;
 328  			} while (de);
      	}
 330  	return 1;
      }
      
      /*
       * These are the generic /proc directory operations. They
       * use the in-memory "struct proc_dir_entry" tree to parse
       * the /proc directory.
       */
      static struct file_operations proc_dir_operations = {
      	read:			generic_read_dir,
      	readdir:		proc_readdir,
      };
      
      /*
       * proc directories can do almost nothing..
       */
      static struct inode_operations proc_dir_inode_operations = {
      	lookup:		proc_lookup,
      };
      
 350  static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp)
      {
      	int	i;
      	
      	i = make_inode_number();
 355  	if (i < 0)
 356  		return -EAGAIN;
      	dp->low_ino = i;
      	dp->next = dir->subdir;
      	dp->parent = dir;
      	dir->subdir = dp;
 361  	if (S_ISDIR(dp->mode)) {
 362  		if (dp->proc_iops == NULL) {
      			dp->proc_fops = &proc_dir_operations;
      			dp->proc_iops = &proc_dir_inode_operations;
      		}
      		dir->nlink++;
 367  	} else if (S_ISLNK(dp->mode)) {
 368  		if (dp->proc_iops == NULL)
      			dp->proc_iops = &proc_link_inode_operations;
 370  	} else if (S_ISREG(dp->mode)) {
 371  		if (dp->proc_fops == NULL)
      			dp->proc_fops = &proc_file_operations;
      	}
 374  	return 0;
      }
      
      /*
       * Kill an inode that got unregistered..
       */
 380  static void proc_kill_inodes(struct proc_dir_entry *de)
      {
      	struct list_head *p;
      	struct super_block *sb = proc_mnt->mnt_sb;
      
      	/*
      	 * Actually it's a partial revoke().
      	 */
      	file_list_lock();
 389  	for (p = sb->s_files.next; p != &sb->s_files; p = p->next) {
      		struct file * filp = list_entry(p, struct file, f_list);
      		struct dentry * dentry;
      		struct inode * inode;
      
      		dentry = filp->f_dentry;
 395  		if (!dentry)
 396  			continue;
 397  		if (dentry->d_op != &proc_dentry_operations)
 398  			continue;
      		inode = dentry->d_inode;
 400  		if (inode->u.generic_ip != de)
 401  			continue;
 402  		fops_put(filp->f_op);
      		filp->f_op = NULL;
      	}
 405  	file_list_unlock();
      }
      
 408  struct proc_dir_entry *proc_symlink(const char *name,
      		struct proc_dir_entry *parent, const char *dest)
      {
      	struct proc_dir_entry *ent = NULL;
      	const char *fn = name;
      	int len;
      
 415  	if (!parent && xlate_proc_name(name, &parent, &fn) != 0)
 416  		goto out;
      	len = strlen(fn);
      
      	ent = kmalloc(sizeof(struct proc_dir_entry) + len + 1, GFP_KERNEL);
 420  	if (!ent)
 421  		goto out;
      	memset(ent, 0, sizeof(struct proc_dir_entry));
      	memcpy(((char *) ent) + sizeof(*ent), fn, len + 1);
      	ent->name = ((char *) ent) + sizeof(*ent);
      	ent->namelen = len;
      	ent->nlink = 1;
      	ent->mode = S_IFLNK|S_IRUGO|S_IWUGO|S_IXUGO;
      	ent->data = kmalloc((ent->size=strlen(dest))+1, GFP_KERNEL);
 429  	if (!ent->data) {
      		kfree(ent);
 431  		goto out;
      	}
      	strcpy((char*)ent->data,dest);
      
      	proc_register(parent, ent);
      	
      out:
 438  	return ent;
      }
      
 441  struct proc_dir_entry *proc_mknod(const char *name, mode_t mode,
      		struct proc_dir_entry *parent, kdev_t rdev)
      {
      	struct proc_dir_entry *ent = NULL;
      	const char *fn = name;
      	int len;
      
 448  	if (!parent && xlate_proc_name(name, &parent, &fn) != 0)
 449  		goto out;
      	len = strlen(fn);
      
      	ent = kmalloc(sizeof(struct proc_dir_entry) + len + 1, GFP_KERNEL);
 453  	if (!ent)
 454  		goto out;
      	memset(ent, 0, sizeof(struct proc_dir_entry));
      	memcpy(((char *) ent) + sizeof(*ent), fn, len + 1);
      	ent->name = ((char *) ent) + sizeof(*ent);
      	ent->namelen = len;
      	ent->nlink = 1;
      	ent->mode = mode;
      	ent->rdev = rdev;
      
      	proc_register(parent, ent);
      	
      out:
 466  	return ent;
      }
      
 469  struct proc_dir_entry *proc_mkdir(const char *name, struct proc_dir_entry *parent)
      {
      	struct proc_dir_entry *ent = NULL;
      	const char *fn = name;
      	int len;
      
 475  	if (!parent && xlate_proc_name(name, &parent, &fn) != 0)
 476  		goto out;
      	len = strlen(fn);
      
      	ent = kmalloc(sizeof(struct proc_dir_entry) + len + 1, GFP_KERNEL);
 480  	if (!ent)
 481  		goto out;
      	memset(ent, 0, sizeof(struct proc_dir_entry));
      	memcpy(((char *) ent) + sizeof(*ent), fn, len + 1);
      	ent->name = ((char *) ent) + sizeof(*ent);
      	ent->namelen = len;
      	ent->proc_fops = &proc_dir_operations;
      	ent->proc_iops = &proc_dir_inode_operations;
      	ent->nlink = 2;
      	ent->mode = S_IFDIR | S_IRUGO | S_IXUGO;
      
      	proc_register(parent, ent);
      	
      out:
 494  	return ent;
      }
      
 497  struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
      					 struct proc_dir_entry *parent)
      {
      	struct proc_dir_entry *ent = NULL;
      	const char *fn = name;
      	int len;
      
 504  	if (!parent && xlate_proc_name(name, &parent, &fn) != 0)
 505  		goto out;
      	len = strlen(fn);
      
      	ent = kmalloc(sizeof(struct proc_dir_entry) + len + 1, GFP_KERNEL);
 509  	if (!ent)
 510  		goto out;
      	memset(ent, 0, sizeof(struct proc_dir_entry));
      	memcpy(((char *) ent) + sizeof(*ent), fn, len + 1);
      	ent->name = ((char *) ent) + sizeof(*ent);
      	ent->namelen = len;
      
 516  	if (S_ISDIR(mode)) {
 517  		if ((mode & S_IALLUGO) == 0)
      		mode |= S_IRUGO | S_IXUGO;
      		ent->proc_fops = &proc_dir_operations;
      		ent->proc_iops = &proc_dir_inode_operations;
      		ent->nlink = 2;
 522  	} else {
 523  		if ((mode & S_IFMT) == 0)
      			mode |= S_IFREG;
 525  		if ((mode & S_IALLUGO) == 0)
      			mode |= S_IRUGO;
      		ent->nlink = 1;
      	}
      	ent->mode = mode;
      
      	proc_register(parent, ent);
      	
      out:
 534  	return ent;
      }
      
 537  void free_proc_entry(struct proc_dir_entry *de)
      {
      	int ino = de->low_ino;
      
      	if (ino < PROC_DYNAMIC_FIRST ||
 542  	    ino >= PROC_DYNAMIC_FIRST+PROC_NDYNAMIC)
 543  		return;
 544  	if (S_ISLNK(de->mode) && de->data)
      		kfree(de->data);
      	kfree(de);
      }
      
      /*
       * Remove a /proc entry and free it if it's not currently in use.
       * If it is in use, we set the 'deleted' flag.
       */
 553  void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
      {
      	struct proc_dir_entry **p;
      	struct proc_dir_entry *de;
      	const char *fn = name;
      	int len;
      
 560  	if (!parent && xlate_proc_name(name, &parent, &fn) != 0)
 561  		goto out;
      	len = strlen(fn);
 563  	for (p = &parent->subdir; *p; p=&(*p)->next ) {
 564  		if (!proc_match(len, fn, *p))
 565  			continue;
      		de = *p;
      		*p = de->next;
      		de->next = NULL;
 569  		if (S_ISDIR(de->mode))
      			parent->nlink--;
      		clear_bit(de->low_ino-PROC_DYNAMIC_FIRST,
      				(void *) proc_alloc_map);
      		proc_kill_inodes(de);
      		de->nlink = 0;
 575  		if (!atomic_read(&de->count))
      			free_proc_entry(de);
 577  		else {
      			de->deleted = 1;
      			printk("remove_proc_entry: %s/%s busy, count=%d\n",
      				parent->name, de->name, atomic_read(&de->count));
      		}
 582  		break;
      	}
      out:
 585  	return;
      }