[netfilter-cvslog] r3518 - in trunk/nfsim: . core kernelenv kernelenv/include tools

rusty at netfilter.org rusty at netfilter.org
Thu Dec 30 07:16:20 CET 2004


Author: rusty at netfilter.org
Date: 2004-12-30 07:16:20 +0100 (Thu, 30 Dec 2004)
New Revision: 3518

Added:
   trunk/nfsim/kernelenv/include/proc_stuff.h
   trunk/nfsim/kernelenv/proc_stuff.c
Removed:
   trunk/nfsim/core/proc.h
   trunk/nfsim/kernelenv/proc.c
Modified:
   trunk/nfsim/UNSUPPORTED
   trunk/nfsim/core/core.h
   trunk/nfsim/kernelenv/Makefile
   trunk/nfsim/kernelenv/include/kernelenv.h
   trunk/nfsim/tools/proc.c
Log:
Writable proc entries, and sysctl support.
	Remove core/proc.h, merge into kernelenv/include/proc_stuff.h
	Move proc and file-related messiness into kernelenv/proc_stuff.c.
	Add "proc write" command.
	


Modified: trunk/nfsim/UNSUPPORTED
===================================================================
--- trunk/nfsim/UNSUPPORTED	2004-12-30 03:08:14 UTC (rev 3517)
+++ trunk/nfsim/UNSUPPORTED	2004-12-30 06:16:20 UTC (rev 3518)
@@ -15,6 +15,3 @@
 
 # tasklist not yet implemented.
 CONFIG_IP_NF_MATCH_OWNER
-
-# sysctl not yet implemented
-CONFIG_SYSCTL

Modified: trunk/nfsim/core/core.h
===================================================================
--- trunk/nfsim/core/core.h	2004-12-30 03:08:14 UTC (rev 3517)
+++ trunk/nfsim/core/core.h	2004-12-30 06:16:20 UTC (rev 3518)
@@ -281,6 +281,10 @@
 extern bool suppress_failtest;
 extern unsigned int failpoints;
 
+/* Proc interface. */
+bool nfsim_proc_cat(const char *name);
+bool nfsim_proc_write(const char *name, char *argv[]);
+
 /* Root for all kernel code allocations (so we check memory leaks) */
 extern void *nfsim_tallocs;
 

Deleted: trunk/nfsim/core/proc.h
===================================================================
--- trunk/nfsim/core/proc.h	2004-12-30 03:08:14 UTC (rev 3517)
+++ trunk/nfsim/core/proc.h	2004-12-30 06:16:20 UTC (rev 3518)
@@ -1,91 +0,0 @@
-/*
-
-Copyright (c) 2003,2004 Jeremy Kerr & Rusty Russell
-
-This file is part of nfsim.
-
-nfsim is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-nfsim is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with nfsim; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-#ifndef __HAVE_PROC_H
-#define __HAVE_PROC_H
-
-#include <kernelenv.h>
-
-struct file;
-typedef int (read_proc_t)(char *page, char **start, off_t off,
-                          int count, int *eof, void *data);
-typedef	int (write_proc_t)(struct file *file, const char __user *buffer,
-			   unsigned long count, void *data);
-typedef int (get_info_t)(char *, char **, off_t, int);
-
-
-struct proc_dir_entry {
-        unsigned short namelen;
-        const char *name;
-        get_info_t *get_info;
-        struct module *owner;
-        struct proc_dir_entry *next, *parent, *subdir;
-	struct file_operations *proc_fops;
-	void *data;
-	read_proc_t *read_proc;
-	write_proc_t *write_proc;
-
-	/* all we need is the S_IFDR flag.. */
-	mode_t mode;
-};
-
-extern struct proc_dir_entry proc_root, *proc_net, *proc_net_stat;
-
-
-int proc_match(int len, const char *name, struct proc_dir_entry *de);
-struct proc_dir_entry *proc_mkdir(const char *name, struct proc_dir_entry *parent);
-
-struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
-					 struct proc_dir_entry *parent);
-
-void remove_proc_entry(const char *name, struct proc_dir_entry *parent);
-
-static inline struct proc_dir_entry *create_proc_info_entry(const char *name,
-	mode_t mode, struct proc_dir_entry *base, get_info_t *get_info)
-{
-	struct proc_dir_entry *res=create_proc_entry(name,mode,base);
-	if (res) res->get_info=get_info;
-	return res;
-}
-
-static inline struct proc_dir_entry *proc_net_create(const char *name,
-	mode_t mode, get_info_t *get_info)
-{
-	return create_proc_info_entry(name,mode,proc_net,get_info);
-}
-
-static inline struct proc_dir_entry *proc_net_fops_create(const char *name,
-	mode_t mode, struct file_operations *fops)
-{
-	struct proc_dir_entry *res = create_proc_entry(name, mode, proc_net);
-	if (res)
-		res->proc_fops = fops;
-	return res;
-}
-
-static inline void proc_net_remove(const char *name)
-{
-	remove_proc_entry(name,proc_net);
-}
-
-
-
-#endif /* __HAVE_PROC_H */

Modified: trunk/nfsim/kernelenv/Makefile
===================================================================
--- trunk/nfsim/kernelenv/Makefile	2004-12-30 03:08:14 UTC (rev 3517)
+++ trunk/nfsim/kernelenv/Makefile	2004-12-30 06:16:20 UTC (rev 3518)
@@ -1 +1 @@
-OBJS+=kernelenv/kernelenv.o kernelenv/proc.o
+OBJS+=kernelenv/kernelenv.o kernelenv/proc_stuff.o

Modified: trunk/nfsim/kernelenv/include/kernelenv.h
===================================================================
--- trunk/nfsim/kernelenv/include/kernelenv.h	2004-12-30 03:08:14 UTC (rev 3517)
+++ trunk/nfsim/kernelenv/include/kernelenv.h	2004-12-30 06:16:20 UTC (rev 3518)
@@ -1119,7 +1119,7 @@
 
 #include <core.h>
 #include <message.h>
-#include <proc.h>
+#include <proc_stuff.h>
 
 /* percpu.h */
 #define DEFINE_PER_CPU(type, name)	 __typeof__(type) per_cpu__##name
@@ -1132,62 +1132,6 @@
 #define EXPORT_PER_CPU_SYMBOL(var) EXPORT_SYMBOL(per_cpu__##var)
 #define EXPORT_PER_CPU_SYMBOL_GPL(var) EXPORT_SYMBOL_GPL(per_cpu__##var)
 
-/* fs.h */
-struct file {
-	int f_mode;
-	size_t f_pos;
-	void *private_data;
-};
-struct inode;
-
-struct file_operations
-{
-	struct module *owner;
-	loff_t (*llseek) (struct file *, loff_t, int);
-	ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
-	int (*open) (struct inode *, struct file *);
-	int (*release) (struct inode *, struct file *);
-};
-
-/* seq_file.h */
-struct seq_file {
-	char *buf;
-	size_t size;
-	size_t from;
-	size_t count;
-	loff_t index;
-	struct semaphore sem;
-	struct seq_operations *op;
-	void *private;
-};
-
-struct seq_operations {
-	void * (*start) (struct seq_file *m, loff_t *pos);
-	void (*stop) (struct seq_file *m, void *v);
-	void * (*next) (struct seq_file *m, void *v, loff_t *pos);
-	int (*show) (struct seq_file *m, void *v);
-};
-
-#define FMODE_PREAD	8
-#define FMODE_PWRITE	FMODE_PREAD	/* These go hand in hand */
-
-int seq_open(struct file *, struct seq_operations *);
-ssize_t seq_read(struct file *, char __user *, size_t, loff_t *);
-loff_t seq_lseek(struct file *, loff_t, int);
-int seq_release(struct inode *, struct file *);
-int seq_escape(struct seq_file *, const char *, const char *);
-int seq_putc(struct seq_file *m, char c);
-int seq_puts(struct seq_file *m, const char *s);
-
-int seq_printf(struct seq_file *, const char *, ...)
-	__attribute__ ((format (printf,2,3)));
-
-int single_open(struct file *, int (*)(struct seq_file *, void *), void *);
-int single_release(struct inode *, struct file *);
-int seq_release_private(struct inode *, struct file *);
-
-#define SEQ_START_TOKEN ((void *)1)
-
 /* if_ether.h */
 struct ethhdr *eth_hdr(const struct sk_buff *skb);
 

Added: trunk/nfsim/kernelenv/include/proc_stuff.h
===================================================================
--- trunk/nfsim/kernelenv/include/proc_stuff.h	2004-12-30 03:08:14 UTC (rev 3517)
+++ trunk/nfsim/kernelenv/include/proc_stuff.h	2004-12-30 06:16:20 UTC (rev 3518)
@@ -0,0 +1,357 @@
+#ifndef _NFSIM_PROC_STUFF_H
+#define _NFSIM_PROC_STUFF_H
+
+#define FMODE_READ 1
+#define FMODE_WRITE 2
+
+struct inode
+{
+	int i_mode;
+	struct proc_dir_entry *e;
+};
+
+struct dentry {
+	struct inode *d_inode;
+};
+
+struct file {
+	int f_mode;
+	struct dentry *f_dentry;
+	loff_t f_pos;
+	void *private_data;
+};
+
+/* proc_fs.h */
+struct file;
+typedef int (read_proc_t)(char *page, char **start, off_t off,
+                          int count, int *eof, void *data);
+typedef	int (write_proc_t)(struct file *file, const char *buffer,
+			   unsigned long count, void *data);
+typedef int (get_info_t)(char *, char **, off_t, int);
+
+struct proc_dir_entry {
+        unsigned short namelen;
+        const char *name;
+        get_info_t *get_info;
+        struct module *owner;
+        struct proc_dir_entry *next, *parent, *subdir;
+	struct file_operations *proc_fops;
+	void *data;
+	read_proc_t *read_proc;
+	write_proc_t *write_proc;
+
+	/* all we need is the S_IFDR flag.. */
+	mode_t mode;
+};
+
+extern struct proc_dir_entry proc_root, *proc_net, *proc_net_stat;
+
+int proc_match(int len, const char *name, struct proc_dir_entry *de);
+struct proc_dir_entry *proc_mkdir(const char *name, struct proc_dir_entry *parent);
+
+struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
+					 struct proc_dir_entry *parent);
+
+void remove_proc_entry(const char *name, struct proc_dir_entry *parent);
+
+extern struct proc_dir_entry *
+create_proc_info_entry(const char *name, mode_t mode,
+		       struct proc_dir_entry *base, get_info_t *get_info);
+
+extern struct proc_dir_entry *
+proc_net_create(const char *name, mode_t mode, get_info_t *get_info);
+
+extern struct proc_dir_entry *
+proc_net_fops_create(const char *name, mode_t mode,
+		     struct file_operations *fops);
+
+extern void proc_net_remove(const char *name);
+
+/* fs.h */
+struct file_operations
+{
+	struct module *owner;
+	loff_t (*llseek) (struct file *, loff_t, int);
+	ssize_t (*read) (struct file *, char *, size_t, loff_t *);
+	int (*open) (struct inode *, struct file *);
+	int (*release) (struct inode *, struct file *);
+	ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
+};
+
+/* seq_file.h */
+struct seq_file {
+	char *buf;
+	size_t size;
+	size_t from;
+	size_t count;
+	loff_t index;
+	struct semaphore sem;
+	struct seq_operations *op;
+	void *private;
+};
+
+struct seq_operations {
+	void * (*start) (struct seq_file *m, loff_t *pos);
+	void (*stop) (struct seq_file *m, void *v);
+	void * (*next) (struct seq_file *m, void *v, loff_t *pos);
+	int (*show) (struct seq_file *m, void *v);
+};
+
+#define FMODE_PREAD	8
+#define FMODE_PWRITE	FMODE_PREAD	/* These go hand in hand */
+
+int seq_open(struct file *, struct seq_operations *);
+ssize_t seq_read(struct file *, char *, size_t, loff_t *);
+loff_t seq_lseek(struct file *, loff_t, int);
+int seq_release(struct inode *, struct file *);
+int seq_escape(struct seq_file *, const char *, const char *);
+int seq_putc(struct seq_file *m, char c);
+int seq_puts(struct seq_file *m, const char *s);
+
+int seq_printf(struct seq_file *, const char *, ...)
+	__attribute__ ((format (printf,2,3)));
+
+int single_open(struct file *, int (*)(struct seq_file *, void *), void *);
+int single_release(struct inode *, struct file *);
+int seq_release_private(struct inode *, struct file *);
+
+#define SEQ_START_TOKEN ((void *)1)
+
+/* proc_fs.h */
+struct proc_dir_entry *PDE(const struct inode *inode);
+
+/*
+ * sysctl.h: General linux system control interface
+ *
+ * Begun 24 March 1995, Stephen Tweedie
+ *
+ ****************************************************************
+ ****************************************************************
+ **
+ **  The values in this file are exported to user space via 
+ **  the sysctl() binary interface.  However this interface
+ **  is unstable and deprecated and will be removed in the future. 
+ **  For a stable interface use /proc/sys.
+ **
+ ****************************************************************
+ ****************************************************************
+ */
+
+/* Define sysctl names first */
+
+/* Top-level names: */
+
+/* For internal pattern-matching use only: */
+#define CTL_ANY		-1	/* Matches any name */
+#define CTL_NONE	0
+
+enum
+{
+	CTL_KERN=1,		/* General kernel info and control */
+	CTL_VM=2,		/* VM management */
+	CTL_NET=3,		/* Networking */
+	CTL_PROC=4,		/* Process info */
+	CTL_FS=5,		/* Filesystems */
+	CTL_DEBUG=6,		/* Debugging */
+	CTL_DEV=7,		/* Devices */
+	CTL_BUS=8,		/* Busses */
+	CTL_ABI=9,		/* Binary emulation */
+	CTL_CPU=10		/* CPU stuff (speed scaling, etc) */
+};
+
+/* CTL_NET names: */
+enum
+{
+	NET_CORE=1,
+	NET_ETHER=2,
+	NET_802=3,
+	NET_UNIX=4,
+	NET_IPV4=5,
+	NET_IPX=6,
+	NET_ATALK=7,
+	NET_NETROM=8,
+	NET_AX25=9,
+	NET_BRIDGE=10,
+	NET_ROSE=11,
+	NET_IPV6=12,
+	NET_X25=13,
+	NET_TR=14,
+	NET_DECNET=15,
+	NET_ECONET=16,
+	NET_SCTP=17, 
+};
+
+
+/* /proc/sys/net/core */
+enum
+{
+	NET_CORE_WMEM_MAX=1,
+	NET_CORE_RMEM_MAX=2,
+	NET_CORE_WMEM_DEFAULT=3,
+	NET_CORE_RMEM_DEFAULT=4,
+/* was	NET_CORE_DESTROY_DELAY */
+	NET_CORE_MAX_BACKLOG=6,
+	NET_CORE_FASTROUTE=7,
+	NET_CORE_MSG_COST=8,
+	NET_CORE_MSG_BURST=9,
+	NET_CORE_OPTMEM_MAX=10,
+	NET_CORE_HOT_LIST_LENGTH=11,
+	NET_CORE_DIVERT_VERSION=12,
+	NET_CORE_NO_CONG_THRESH=13,
+	NET_CORE_NO_CONG=14,
+	NET_CORE_LO_CONG=15,
+	NET_CORE_MOD_CONG=16,
+	NET_CORE_DEV_WEIGHT=17,
+	NET_CORE_SOMAXCONN=18,
+};
+
+/* /proc/sys/net/ipv4 */
+enum
+{
+	/* v2.0 compatibile variables */
+	NET_IPV4_FORWARD=8,
+	NET_IPV4_DYNADDR=9,
+
+	NET_IPV4_CONF=16,
+	NET_IPV4_NEIGH=17,
+	NET_IPV4_ROUTE=18,
+	NET_IPV4_FIB_HASH=19,
+	NET_IPV4_NETFILTER=20,
+};
+
+/* /proc/sys/net/ipv4/netfilter */
+enum
+{
+	NET_IPV4_NF_CONNTRACK_MAX=1,
+	NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT=2,
+	NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV=3,
+	NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED=4,
+	NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT=5,
+	NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT=6,
+	NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK=7,
+	NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT=8,
+	NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE=9,
+	NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT=10,
+	NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT_STREAM=11,
+	NET_IPV4_NF_CONNTRACK_ICMP_TIMEOUT=12,
+	NET_IPV4_NF_CONNTRACK_GENERIC_TIMEOUT=13,
+	NET_IPV4_NF_CONNTRACK_BUCKETS=14,
+	NET_IPV4_NF_CONNTRACK_LOG_INVALID=15,
+	NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_MAX_RETRANS=16,
+	NET_IPV4_NF_CONNTRACK_TCP_LOOSE=17,
+	NET_IPV4_NF_CONNTRACK_TCP_BE_LIBERAL=18,
+	NET_IPV4_NF_CONNTRACK_TCP_MAX_RETRANS=19,
+ 	NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_CLOSED=20,
+ 	NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_WAIT=21,
+ 	NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_ECHOED=22,
+ 	NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_ESTABLISHED=23,
+ 	NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_SENT=24,
+ 	NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_RECD=25,
+ 	NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_ACK_SENT=26,
+	NET_IPV4_NF_CONNTRACK_COUNT=27,
+};
+
+/* CTL_PROC names: */
+extern void sysctl_init(void);
+
+typedef struct ctl_table ctl_table;
+
+typedef int ctl_handler (ctl_table *table, int *name, int nlen,
+			 void *oldval, size_t *oldlenp,
+			 void *newval, size_t newlen, 
+			 void **context);
+
+typedef int proc_handler (ctl_table *ctl, int write, struct file * filp,
+			  void *buffer, size_t *lenp, loff_t *ppos);
+
+extern int proc_dostring(ctl_table *, int, struct file *,
+			 void *, size_t *, loff_t *);
+extern int proc_dointvec(ctl_table *, int, struct file *,
+			 void *, size_t *, loff_t *);
+extern int proc_dointvec_bset(ctl_table *, int, struct file *,
+			      void *, size_t *, loff_t *);
+extern int proc_dointvec_minmax(ctl_table *, int, struct file *,
+				void *, size_t *, loff_t *);
+extern int proc_dointvec_jiffies(ctl_table *, int, struct file *,
+				 void *, size_t *, loff_t *);
+extern int proc_dointvec_userhz_jiffies(ctl_table *, int, struct file *,
+					void *, size_t *, loff_t *);
+extern int proc_doulongvec_minmax(ctl_table *, int, struct file *,
+				  void *, size_t *, loff_t *);
+extern int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int,
+				      struct file *, void *, size_t *, loff_t *);
+
+extern int do_sysctl (int *name, int nlen,
+		      void *oldval, size_t *oldlenp,
+		      void *newval, size_t newlen);
+
+extern int do_sysctl_strategy (ctl_table *table, 
+			       int *name, int nlen,
+			       void *oldval, size_t *oldlenp,
+			       void *newval, size_t newlen, void ** context);
+
+extern ctl_handler sysctl_string;
+extern ctl_handler sysctl_intvec;
+extern ctl_handler sysctl_jiffies;
+
+
+/*
+ * Register a set of sysctl names by calling register_sysctl_table
+ * with an initialised array of ctl_table's.  An entry with zero
+ * ctl_name terminates the table.  table->de will be set up by the
+ * registration and need not be initialised in advance.
+ *
+ * sysctl names can be mirrored automatically under /proc/sys.  The
+ * procname supplied controls /proc naming.
+ *
+ * The table's mode will be honoured both for sys_sysctl(2) and
+ * proc-fs access.
+ *
+ * Leaf nodes in the sysctl tree will be represented by a single file
+ * under /proc; non-leaf nodes will be represented by directories.  A
+ * null procname disables /proc mirroring at this node.
+ * 
+ * sysctl(2) can automatically manage read and write requests through
+ * the sysctl table.  The data and maxlen fields of the ctl_table
+ * struct enable minimal validation of the values being written to be
+ * performed, and the mode field allows minimal authentication.
+ * 
+ * More sophisticated management can be enabled by the provision of a
+ * strategy routine with the table entry.  This will be called before
+ * any automatic read or write of the data is performed.
+ * 
+ * The strategy routine may return:
+ * <0: Error occurred (error is passed to user process)
+ * 0:  OK - proceed with automatic read or write.
+ * >0: OK - read or write has been done by the strategy routine, so 
+ *     return immediately.
+ * 
+ * There must be a proc_handler routine for any terminal nodes
+ * mirrored under /proc/sys (non-terminals are handled by a built-in
+ * directory handler).  Several default handlers are available to
+ * cover common cases.
+ */
+
+/* A sysctl table is an array of struct ctl_table: */
+struct ctl_table 
+{
+	int ctl_name;			/* Binary ID */
+	const char *procname;		/* Text ID for /proc/sys, or zero */
+	void *data;
+	int maxlen;
+	mode_t mode;
+	ctl_table *child;
+	proc_handler *proc_handler;	/* Callback for text formatting */
+	ctl_handler *strategy;		/* Callback function for all r/w */
+	struct proc_dir_entry *de;	/* /proc control block */
+	void *extra1;
+	void *extra2;
+};
+
+struct ctl_table_header;
+
+struct ctl_table_header * register_sysctl_table(ctl_table * table, 
+						int insert_at_head);
+void unregister_sysctl_table(struct ctl_table_header * table);
+
+#endif /* _NFSIM_PROC_STUFF_H */

Deleted: trunk/nfsim/kernelenv/proc.c
===================================================================
--- trunk/nfsim/kernelenv/proc.c	2004-12-30 03:08:14 UTC (rev 3517)
+++ trunk/nfsim/kernelenv/proc.c	2004-12-30 06:16:20 UTC (rev 3518)
@@ -1,162 +0,0 @@
-/*
-
-Copyright (c) 2003,2004 Jeremy Kerr & Rusty Russell
-
-This file is part of nfsim.
-
-nfsim is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-nfsim is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with nfsim; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-#include "proc.h"
-#include <kernelenv.h>
-
-struct proc_dir_entry proc_root, *proc_net, *proc_net_stat;
-
-
-int proc_match(int len, const char *name, struct proc_dir_entry *de)
-{
-	if (de->namelen != len)
-		return 0;
-	return !memcmp(name, de->name, len);
-}
-
-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;
-	while (1) {
-		next = strchr(cp, '/');
-		if (!next)
-			break;
-
-		len = next - cp;
-		for (de = de->subdir; de ; de = de->next) {
-			if (proc_match(len, cp, de))
-				break;
-		}
-		if (!de)
-			return -ENOENT;
-		cp += len + 1;
-	}
-	*residual = cp;
-	*ret = de;
-	return 0;
-}
-
-
-static struct proc_dir_entry *proc_create(struct proc_dir_entry **parent,
-					  const char *name,
-					  mode_t mode,
-					  nlink_t nlink)
-{
-	struct proc_dir_entry *ent = NULL;
-	const char *fn = name;
-	int len;
-
-	/* make sure name is valid */
-	if (!name || !strlen(name)) goto out;
-
-	if (!(*parent) && xlate_proc_name(name, parent, &fn) != 0)
-		goto out;
-	len = strlen(fn);
-
-	if (should_i_fail(__func__))
-		goto out;
-
-	ent = talloc_size(NULL, sizeof(struct proc_dir_entry) + len + 1);
-	if (!ent) goto out;
-
-	memset(ent, 0, sizeof(struct proc_dir_entry));
-	memcpy(((char *) ent) + sizeof(struct proc_dir_entry), fn, len + 1);
-	ent->name = ((char *) ent) + sizeof(*ent);
-	ent->namelen = len;
-	ent->mode = mode;
-out:
-	return ent;
-}
-
-static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp)
-{
-	dp->next = dir->subdir;
-	dp->parent = dir;
-	dir->subdir = dp;
-	return 0;
-}
-
-struct proc_dir_entry *proc_mkdir(const char *name, struct proc_dir_entry *parent)
-{
-	struct proc_dir_entry *ent;
-
-	ent = proc_create(&parent,name,
-			  (S_IFDIR | S_IRUGO | S_IXUGO),2);
-
-	if (ent && proc_register(parent, ent) < 0) {
-		talloc_free(ent);
-		ent = NULL;
-	}
-	return ent;
-}
-
-struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
-					 struct proc_dir_entry *parent)
-{
-	struct proc_dir_entry *ent;
-
-	ent = proc_create(&parent,name,mode, 0);
-	if (ent && proc_register(parent, ent) < 0) {
-		talloc_free(ent);
-		ent = NULL;
-	}
-	return ent;
-}
-
-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;
-
-	if (!parent && xlate_proc_name(name, &parent, &fn) != 0)
-		goto out;
-	len = strlen(fn);
-	for (p = &parent->subdir; *p; p=&(*p)->next ) {
-		if (!proc_match(len, fn, *p))
-			continue;
-		de = *p;
-		*p = de->next;
-		de->next = NULL;
-		break;
-	}
-out:
-	return;
-}
-
-static void proc_init(void)
-{
-	proc_root.namelen = 5;
-	proc_root.name = "/proc";
-	proc_root.owner = THIS_MODULE;
-
-	proc_net = proc_mkdir("net", 0);
-	proc_net_stat = proc_mkdir("stat", proc_net);
-}
-
-init_call(proc_init);
-

Copied: trunk/nfsim/kernelenv/proc_stuff.c (from rev 3515, trunk/nfsim/kernelenv/proc.c)
===================================================================
--- trunk/nfsim/kernelenv/proc.c	2004-12-30 02:39:31 UTC (rev 3515)
+++ trunk/nfsim/kernelenv/proc_stuff.c	2004-12-30 06:16:20 UTC (rev 3518)
@@ -0,0 +1,928 @@
+/*
+
+Copyright (c) 2003,2004 Jeremy Kerr & Rusty Russell
+
+This file is part of nfsim.
+
+nfsim is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+nfsim is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with nfsim; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <kernelenv.h>
+
+struct proc_dir_entry proc_root, *proc_net, *proc_net_stat, *proc_sys_root;
+static void *__proc_ctx;
+
+int proc_match(int len, const char *name, struct proc_dir_entry *de)
+{
+	if (de->namelen != len)
+		return 0;
+	return !memcmp(name, de->name, len);
+}
+
+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;
+	while (1) {
+		next = strchr(cp, '/');
+		if (!next)
+			break;
+
+		len = next - cp;
+		for (de = de->subdir; de ; de = de->next) {
+			if (proc_match(len, cp, de))
+				break;
+		}
+		if (!de)
+			return -ENOENT;
+		cp += len + 1;
+	}
+	*residual = cp;
+	*ret = de;
+	return 0;
+}
+
+/* Stolen straight from kernel's fs/proc/base.c,
+ *  Copyright (C) 1991, 1992 Linus Torvalds
+ */
+/* buffer size is one page but our output routines use some slack for overruns */
+#define PROC_BLOCK_SIZE	(PAGE_SIZE - 1024)
+
+static ssize_t
+proc_file_read(struct file *file, char *buf, size_t nbytes,
+	       loff_t *ppos)
+{
+	struct inode * inode = file->f_dentry->d_inode;
+	ssize_t	retval=0;
+	int	eof=0;
+	ssize_t	n, count;
+	char	*start;
+	char page[PAGE_SIZE];
+	struct proc_dir_entry * dp;
+
+	dp = PDE(inode);
+	while ((nbytes > 0) && !eof) {
+		count = min_t(ssize_t, PROC_BLOCK_SIZE, nbytes);
+
+		start = NULL;
+		if (dp->get_info) {
+			/* Handle old net routines */
+			n = dp->get_info(page, &start, *ppos, count);
+			if (n < count)
+				eof = 1;
+		} else if (dp->read_proc) {
+			/*
+			 * How to be a proc read function
+			 * ------------------------------
+			 * Prototype:
+			 *    int f(char *buffer, char **start, off_t offset,
+			 *          int count, int *peof, void *dat)
+			 *
+			 * Assume that the buffer is "count" bytes in size.
+			 *
+			 * If you know you have supplied all the data you
+			 * have, set *peof.
+			 *
+			 * You have three ways to return data:
+			 * 0) Leave *start = NULL.  (This is the default.)
+			 *    Put the data of the requested offset at that
+			 *    offset within the buffer.  Return the number (n)
+			 *    of bytes there are from the beginning of the
+			 *    buffer up to the last byte of data.  If the
+			 *    number of supplied bytes (= n - offset) is 
+			 *    greater than zero and you didn't signal eof
+			 *    and the reader is prepared to take more data
+			 *    you will be called again with the requested
+			 *    offset advanced by the number of bytes 
+			 *    absorbed.  This interface is useful for files
+			 *    no larger than the buffer.
+			 * 1) Set *start = an unsigned long value less than
+			 *    the buffer address but greater than zero.
+			 *    Put the data of the requested offset at the
+			 *    beginning of the buffer.  Return the number of
+			 *    bytes of data placed there.  If this number is
+			 *    greater than zero and you didn't signal eof
+			 *    and the reader is prepared to take more data
+			 *    you will be called again with the requested
+			 *    offset advanced by *start.  This interface is
+			 *    useful when you have a large file consisting
+			 *    of a series of blocks which you want to count
+			 *    and return as wholes.
+			 *    (Hack by Paul.Russell at rustcorp.com.au)
+			 * 2) Set *start = an address within the buffer.
+			 *    Put the data of the requested offset at *start.
+			 *    Return the number of bytes of data placed there.
+			 *    If this number is greater than zero and you
+			 *    didn't signal eof and the reader is prepared to
+			 *    take more data you will be called again with the
+			 *    requested offset advanced by the number of bytes
+			 *    absorbed.
+			 */
+			n = dp->read_proc(page, &start, *ppos,
+					  count, &eof, dp->data);
+		} else
+			break;
+
+		if (n == 0)   /* end of file */
+			break;
+		if (n < 0) {  /* error */
+			if (retval == 0)
+				retval = n;
+			break;
+		}
+
+		if (start == NULL) {
+			if (n > PAGE_SIZE) {
+				printk(KERN_ERR
+				       "proc_file_read: Apparent buffer overflow!\n");
+				n = PAGE_SIZE;
+			}
+			n -= *ppos;
+			if (n <= 0)
+				break;
+			if (n > count)
+				n = count;
+			start = page + *ppos;
+		} else if (start < page) {
+			if (n > PAGE_SIZE) {
+				printk(KERN_ERR
+				       "proc_file_read: Apparent buffer overflow!\n");
+				n = PAGE_SIZE;
+			}
+			if (n > count) {
+				/*
+				 * Don't reduce n because doing so might
+				 * cut off part of a data block.
+				 */
+				printk(KERN_WARNING
+				       "proc_file_read: Read count exceeded\n");
+			}
+		} else /* start >= page */ {
+			unsigned long startoff = (unsigned long)(start - page);
+			if (n > (PAGE_SIZE - startoff)) {
+				printk(KERN_ERR
+				       "proc_file_read: Apparent buffer overflow!\n");
+				n = PAGE_SIZE - startoff;
+			}
+			if (n > count)
+				n = count;
+		}
+
+		memcpy(buf, start < page ? page : start, n);
+
+		*ppos += start < page ? (unsigned long)start : n;
+		nbytes -= n;
+		buf += n;
+		retval += n;
+	}
+	return retval;
+}
+
+static ssize_t
+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 = PDE(inode);
+
+	if (!dp->write_proc)
+		return -EIO;
+
+	/* FIXME: does this routine need ppos?  probably... */
+	return dp->write_proc(file, buffer, count, dp->data);
+}
+
+static struct file_operations proc_file_operations = {
+	.read		= proc_file_read,
+	.write		= proc_file_write,
+};
+
+static struct proc_dir_entry *proc_create(struct proc_dir_entry **parent,
+					  const char *name,
+					  mode_t mode,
+					  nlink_t nlink)
+{
+	struct proc_dir_entry *ent = NULL;
+	const char *fn = name;
+	int len;
+
+	/* make sure name is valid */
+	if (!name || !strlen(name)) goto out;
+
+	if (!(*parent) && xlate_proc_name(name, parent, &fn) != 0)
+		goto out;
+	len = strlen(fn);
+
+	if (should_i_fail(__func__))
+		goto out;
+
+	ent = talloc(__proc_ctx, struct proc_dir_entry);
+	ent->name = talloc_strdup(ent, name);
+	ent->namelen = len;
+	ent->get_info = NULL;
+	ent->owner = NULL;
+	ent->data = NULL;
+	ent->mode = mode;
+	ent->proc_fops = &proc_file_operations;
+	ent->read_proc = NULL;
+	ent->write_proc = NULL;
+	ent->subdir = NULL;
+out:
+	return ent;
+}
+
+static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp)
+{
+	dp->next = dir->subdir;
+	dp->parent = dir;
+	dir->subdir = dp;
+	return 0;
+}
+
+struct proc_dir_entry *proc_mkdir(const char *name, struct proc_dir_entry *parent)
+{
+	struct proc_dir_entry *ent;
+
+	ent = proc_create(&parent,name,
+			  (S_IFDIR | S_IRUGO | S_IXUGO),2);
+
+	if (ent && proc_register(parent, ent) < 0) {
+		talloc_free(ent);
+		ent = NULL;
+	}
+	return ent;
+}
+
+struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
+					 struct proc_dir_entry *parent)
+{
+	struct proc_dir_entry *ent;
+
+	ent = proc_create(&parent,name,mode, 0);
+	if (ent && proc_register(parent, ent) < 0) {
+		talloc_free(ent);
+		ent = NULL;
+	}
+	return ent;
+}
+
+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;
+
+	if (!parent && xlate_proc_name(name, &parent, &fn) != 0)
+		goto out;
+	len = strlen(fn);
+	for (p = &parent->subdir; *p; p=&(*p)->next ) {
+		if (!proc_match(len, fn, *p))
+			continue;
+		de = *p;
+		*p = de->next;
+		de->next = NULL;
+		break;
+	}
+out:
+	return;
+}
+
+struct proc_dir_entry *create_proc_info_entry(const char *name,
+					      mode_t mode,
+					      struct proc_dir_entry *base,
+					      get_info_t *get_info)
+{
+	struct proc_dir_entry *res=create_proc_entry(name,mode,base);
+	if (res) res->get_info=get_info;
+	return res;
+}
+
+struct proc_dir_entry *proc_net_create(const char *name,
+				       mode_t mode, get_info_t *get_info)
+{
+	return create_proc_info_entry(name,mode,proc_net,get_info);
+}
+
+struct proc_dir_entry *proc_net_fops_create(const char *name,
+					    mode_t mode,
+					    struct file_operations *fops)
+{
+	struct proc_dir_entry *res = create_proc_entry(name, mode, proc_net);
+	if (res)
+		res->proc_fops = fops;
+	return res;
+}
+
+void proc_net_remove(const char *name)
+{
+	remove_proc_entry(name,proc_net);
+}
+
+static int test_perm(int mode, int op)
+{
+	mode >>= 6;
+	if ((mode & op & 0007) == op)
+		return 0;
+	return -EACCES;
+}
+
+static inline int ctl_perm(ctl_table *table, int op)
+{
+	return test_perm(table->mode, op);
+}
+
+static ssize_t do_rw_proc(int write, struct file * file, char * buf,
+			  size_t count, loff_t *ppos)
+{
+	int op;
+	struct proc_dir_entry *de;
+	struct ctl_table *table;
+	size_t res;
+	ssize_t error;
+	
+	de = PDE(file->f_dentry->d_inode);
+	if (!de || !de->data)
+		return -ENOTDIR;
+	table = (struct ctl_table *) de->data;
+	if (!table || !table->proc_handler)
+		return -ENOTDIR;
+	op = (write ? 002 : 004);
+	if (ctl_perm(table, op))
+		return -EPERM;
+	
+	res = count;
+
+	error = (*table->proc_handler) (table, write, file, buf, &res, ppos);
+	if (error)
+		return error;
+	return res;
+}
+
+static int proc_opensys(struct inode *inode, struct file *file)
+{
+	if (file->f_mode & FMODE_WRITE) {
+		/*
+		 * sysctl entries that are not writable,
+		 * are _NOT_ writable, capabilities or not.
+		 */
+		if (!(inode->i_mode & S_IWUSR))
+			return -EPERM;
+	}
+
+	return 0;
+}
+
+static ssize_t proc_readsys(struct file * file, char * buf,
+			    size_t count, loff_t *ppos)
+{
+	return do_rw_proc(0, file, buf, count, ppos);
+}
+
+static ssize_t proc_writesys(struct file * file, const char * buf,
+			     size_t count, loff_t *ppos)
+{
+	return do_rw_proc(1, file, (char *) buf, count, ppos);
+}
+
+struct file_operations proc_sys_file_operations = {
+	.open		= proc_opensys,
+	.read		= proc_readsys,
+	.write		= proc_writesys,
+};
+
+/* Scan the sysctl entries in table and add them all into /proc */
+static void register_proc_table(ctl_table * table, struct proc_dir_entry *root)
+{
+	struct proc_dir_entry *de;
+	int len;
+	mode_t mode;
+	
+	for (; table->ctl_name; table++) {
+		/* Can't do anything without a proc name. */
+		if (!table->procname)
+			continue;
+		/* Maybe we can't do anything with it... */
+		if (!table->proc_handler && !table->child)
+			barf("SYSCTL: Can't register %s\n", table->procname);
+
+		len = strlen(table->procname);
+		mode = table->mode;
+
+		de = NULL;
+		if (table->proc_handler)
+			mode |= S_IFREG;
+		else {
+			mode |= S_IFDIR;
+			for (de = root->subdir; de; de = de->next) {
+				if (proc_match(len, table->procname, de))
+					break;
+			}
+			/* If the subdir exists already, de is non-NULL */
+		}
+
+		if (!de) {
+			de = create_proc_entry(table->procname, mode, root);
+			if (!de)
+				continue;
+			de->data = (void *) table;
+			if (table->proc_handler)
+				de->proc_fops = &proc_sys_file_operations;
+		}
+		table->de = de;
+		if (de->mode & S_IFDIR)
+			register_proc_table(table->child, de);
+	}
+}
+
+/*
+ * Unregister a /proc sysctl table and any subdirectories.
+ */
+static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root)
+{
+	struct proc_dir_entry *de;
+	for (; table->ctl_name; table++) {
+		if (!(de = table->de))
+			continue;
+		if (de->mode & S_IFDIR) {
+			if (!table->child) {
+				printk (KERN_ALERT "Help - malformed sysctl tree on free\n");
+				continue;
+			}
+			unregister_proc_table(table->child, de);
+
+			/* Don't unregister directories which still have entries.. */
+			if (de->subdir)
+				continue;
+		}
+
+		table->de = NULL;
+		remove_proc_entry(table->procname, root);
+	}
+}
+
+struct ctl_table_header
+{
+	struct ctl_table *ctl_table;
+};
+
+struct ctl_table_header *register_sysctl_table(ctl_table* table,
+					       int insert_at_head)
+{
+	struct ctl_table_header *ret;
+
+	if (should_i_fail(__func__))
+		return NULL;
+
+	ret = talloc(__proc_ctx, struct ctl_table_header);
+	ret->ctl_table = table;
+
+	register_proc_table(table, proc_sys_root);
+	return ret;
+}
+
+void unregister_sysctl_table(struct ctl_table_header * header)
+{
+	unregister_proc_table(header->ctl_table, proc_sys_root);
+	talloc_free(header);
+}
+
+struct proc_dir_entry *PDE(const struct inode *inode)
+{
+	return ((struct inode *)inode)->e;
+}
+
+static int do_proc_dointvec_conv(int *negp, unsigned long *lvalp,
+				 int *valp,
+				 int write, void *data)
+{
+	if (write) {
+		*valp = *negp ? -*lvalp : *lvalp;
+	} else {
+		int val = *valp;
+		if (val < 0) {
+			*negp = -1;
+			*lvalp = (unsigned long)-val;
+		} else {
+			*negp = 0;
+			*lvalp = (unsigned long)val;
+		}
+	}
+	return 0;
+}
+
+static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
+		  void *buffer, size_t *lenp, loff_t *ppos,
+		  int (*conv)(int *negp, unsigned long *lvalp, int *valp,
+			      int write, void *data),
+		  void *data)
+{
+#define TMPBUFLEN 21
+	int *i, vleft, first=1, neg, val;
+	unsigned long lval;
+	size_t left, len;
+	
+	char buf[TMPBUFLEN], *p;
+	char *s = buffer;
+	
+	if (!table->data || !table->maxlen || !*lenp ||
+	    (*ppos && !write)) {
+		*lenp = 0;
+		return 0;
+	}
+	
+	i = (int *) table->data;
+	vleft = table->maxlen / sizeof(*i);
+	left = *lenp;
+
+	if (!conv)
+		conv = do_proc_dointvec_conv;
+
+	for (; left && vleft--; i++, first=0) {
+		if (write) {
+			while (left) {
+				char c;
+				c = *s;
+				if (!isspace(c))
+					break;
+				left--;
+				s++;
+			}
+			if (!left)
+				break;
+			neg = 0;
+			len = left;
+			if (len > sizeof(buf) - 1)
+				len = sizeof(buf) - 1;
+			memcpy(buf, s, len);
+			buf[len] = 0;
+			p = buf;
+			if (*p == '-' && left > 1) {
+				neg = 1;
+				left--, p++;
+			}
+			if (*p < '0' || *p > '9')
+				break;
+
+			lval = simple_strtoul(p, &p, 0);
+
+			len = p-buf;
+			if ((len < left) && *p && !isspace(*p))
+				break;
+			if (neg)
+				val = -val;
+			s += len;
+			left -= len;
+
+			if (conv(&neg, &lval, i, 1, data))
+				break;
+		} else {
+			p = buf;
+			if (!first)
+				*p++ = '\t';
+	
+			if (conv(&neg, &lval, i, 0, data))
+				break;
+
+			sprintf(p, "%s%lu", neg ? "-" : "", lval);
+			len = strlen(buf);
+			if (len > left)
+				len = left;
+			memcpy(s, buf, len);
+			left -= len;
+			s += len;
+		}
+	}
+
+	if (!write && !first && left) {
+		*s = '\n';
+		left--, s++;
+	}
+	if (write) {
+		while (left) {
+			char c;
+			c = *(s++);
+			if (!isspace(c))
+				break;
+			left--;
+		}
+	}
+	if (write && first)
+		return -EINVAL;
+	*lenp -= left;
+	*ppos += *lenp;
+	return 0;
+#undef TMPBUFLEN
+}
+
+/**
+ * proc_dointvec - read a vector of integers
+ * @table: the sysctl table
+ * @write: %TRUE if this is a write to the sysctl file
+ * @filp: the file structure
+ * @buffer: the user buffer
+ * @lenp: the size of the user buffer
+ *
+ * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
+ * values from/to the user buffer, treated as an ASCII string. 
+ *
+ * Returns 0 on success.
+ */
+int proc_dointvec(ctl_table *table, int write, struct file *filp,
+		     void *buffer, size_t *lenp, loff_t *ppos)
+{
+    return do_proc_dointvec(table,write,filp,buffer,lenp,ppos,
+		    	    NULL,NULL);
+}
+
+static int do_proc_dointvec_jiffies_conv(int *negp, unsigned long *lvalp,
+					 int *valp,
+					 int write, void *data)
+{
+	if (write) {
+		*valp = *negp ? -(*lvalp*HZ) : (*lvalp*HZ);
+	} else {
+		int val = *valp;
+		unsigned long lval;
+		if (val < 0) {
+			*negp = -1;
+			lval = (unsigned long)-val;
+		} else {
+			*negp = 0;
+			lval = (unsigned long)val;
+		}
+		*lvalp = lval / HZ;
+	}
+	return 0;
+}
+
+int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
+			  void *buffer, size_t *lenp, loff_t *ppos)
+{
+    return do_proc_dointvec(table,write,filp,buffer,lenp,ppos,
+		    	    do_proc_dointvec_jiffies_conv,NULL);
+}
+
+struct do_proc_dointvec_minmax_conv_param {
+	int *min;
+	int *max;
+};
+
+static int do_proc_dointvec_minmax_conv(int *negp, unsigned long *lvalp, 
+					int *valp, 
+					int write, void *data)
+{
+	struct do_proc_dointvec_minmax_conv_param *param = data;
+	if (write) {
+		int val = *negp ? -*lvalp : *lvalp;
+		if ((param->min && *param->min > val) ||
+		    (param->max && *param->max < val))
+			return -EINVAL;
+		*valp = val;
+	} else {
+		int val = *valp;
+		if (val < 0) {
+			*negp = -1;
+			*lvalp = (unsigned long)-val;
+		} else {
+			*negp = 0;
+			*lvalp = (unsigned long)val;
+		}
+	}
+	return 0;
+}
+
+/**
+ * proc_dointvec_minmax - read a vector of integers with min/max values
+ * @table: the sysctl table
+ * @write: %TRUE if this is a write to the sysctl file
+ * @filp: the file structure
+ * @buffer: the user buffer
+ * @lenp: the size of the user buffer
+ *
+ * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
+ * values from/to the user buffer, treated as an ASCII string.
+ *
+ * This routine will ensure the values are within the range specified by
+ * table->extra1 (min) and table->extra2 (max).
+ *
+ * Returns 0 on success.
+ */
+int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
+		  void *buffer, size_t *lenp, loff_t *ppos)
+{
+	struct do_proc_dointvec_minmax_conv_param param = {
+		.min = (int *) table->extra1,
+		.max = (int *) table->extra2,
+	};
+	return do_proc_dointvec(table, write, filp, buffer, lenp, ppos,
+				do_proc_dointvec_minmax_conv, &param);
+}
+
+int sysctl_intvec(ctl_table *table, int *name, int nlen,
+		void *oldval, size_t *oldlenp,
+		void *newval, size_t newlen, void **context)
+{
+
+	if (newval && newlen) {
+		int *vec = (int *) newval;
+		int *min = (int *) table->extra1;
+		int *max = (int *) table->extra2;
+		size_t length;
+		int i;
+
+		if (newlen % sizeof(int) != 0)
+			return -EINVAL;
+
+		if (!table->extra1 && !table->extra2)
+			return 0;
+
+		if (newlen > table->maxlen)
+			newlen = table->maxlen;
+		length = newlen / sizeof(int);
+
+		for (i = 0; i < length; i++) {
+			int value = vec[i];
+			if (min && value < min[i])
+				return -EINVAL;
+			if (max && value > max[i])
+				return -EINVAL;
+		}
+	}
+	return 0;
+}
+
+static struct proc_dir_entry *find_proc_entry(const char *name)
+{
+	struct proc_dir_entry *ent;
+	const char *next;
+	int len, last;
+
+	/* strip the /proc/ */
+	name += 6;
+
+	ent = &proc_root;
+
+	last = 0;
+
+	while (!last) {
+		if ((next = strchr(name, '/'))) {
+			len = next - name;
+		} else {
+			len = strlen(name);
+			last = 1;
+		}
+
+		for (ent = ent->subdir; ent; ent = ent->next) {
+			if (proc_match(len, name, ent))
+				break;
+		}
+		if (!ent)
+			return 0;
+		name += len + 1;
+
+	}
+
+	return ent;
+
+}
+
+static struct proc_dir_entry *nfsim_proc_open(const char *name,
+					      struct file **f,
+					      int mode)
+{
+	struct proc_dir_entry *dir;
+	struct inode *inode;
+	struct dentry *dentry;
+	int ret;
+
+	dir = find_proc_entry(name);
+
+	if (!dir) {
+		nfsim_log(LOG_ALWAYS, "proc file not found: %s", name);
+		return NULL;
+	}
+
+	if (S_ISDIR(dir->mode)) {
+		nfsim_log(LOG_ALWAYS, "proc entry %s is a directory", name);
+		return NULL;
+	}
+
+	if (mode == FMODE_WRITE && !(dir->mode & 0200)) {
+		nfsim_log(LOG_ALWAYS, "proc entry %s not writable", name);
+		return NULL;
+	}
+
+	*f = talloc(NULL, struct file);
+	inode = talloc(*f, struct inode);
+	dentry = talloc(*f, struct dentry);
+
+	inode->i_mode = dir->mode;
+	inode->e = dir;
+	dentry->d_inode = inode;
+
+	(*f)->f_mode = mode;
+	(*f)->f_dentry = dentry;
+	(*f)->f_pos = 0;
+
+	if (dir->proc_fops->open && dir->proc_fops->open(inode, *f) < 0) {
+		nfsim_log(LOG_ALWAYS, "proc entry %s open failed %i!",
+			  name, ret);
+		talloc_free(*f);
+		return NULL;
+	}
+	return dir;
+}
+
+static void nfsim_proc_close(struct proc_dir_entry *dir, struct file *f)
+{
+	if (dir->proc_fops->release)
+		dir->proc_fops->release(f->f_dentry->d_inode, f);
+	talloc_free(f);
+}
+
+bool nfsim_proc_cat(const char *name)
+{
+	struct file *f;
+	struct proc_dir_entry *dir;
+	int ret;
+	char buf[16384];
+
+	dir = nfsim_proc_open(name, &f, FMODE_READ);
+	if (!dir)
+		return false;
+
+	ret = dir->proc_fops->read(f, buf, sizeof(buf)-1, &f->f_pos);
+	nfsim_proc_close(dir, f);
+	if (ret < 0) {
+		nfsim_log(LOG_ALWAYS, "proc entry %s read failed %i!",
+			  name, ret);
+		return false;
+	}
+	printk("%s", buf);
+	return true;
+}
+
+bool nfsim_proc_write(const char *name, char *argv[])
+{
+	char *str = NULL;
+	struct file *f;
+	struct proc_dir_entry *dir;
+	int ret;
+
+	dir = nfsim_proc_open(name, &f, FMODE_WRITE);
+	if (!dir)
+		return false;
+
+	while (*argv) {
+		str = talloc_asprintf_append(str, "%s%s",
+					     *argv, argv[1] ? " " : "");
+		argv++;
+	}
+
+	ret = dir->proc_fops->write(f, str, strlen(str), &f->f_pos);
+	nfsim_proc_close(dir, f);
+	talloc_free(str);
+
+	if (ret < 0) {
+		nfsim_log(LOG_ALWAYS, "proc entry %s write failed %i!",
+			  name, ret);
+		return false;
+	}
+	return true;
+}
+
+static void proc_init(void)
+{
+	__proc_ctx = talloc_named_const(nfsim_tallocs, 1, "proc entries");
+
+	proc_root.namelen = 5;
+	proc_root.name = "/proc";
+	proc_root.owner = THIS_MODULE;
+
+	proc_net = proc_mkdir("net", NULL);
+	proc_net_stat = proc_mkdir("stat", proc_net);
+
+	proc_sys_root = proc_mkdir("sys", NULL);
+}
+
+init_call(proc_init);
+

Modified: trunk/nfsim/tools/proc.c
===================================================================
--- trunk/nfsim/tools/proc.c	2004-12-30 03:08:14 UTC (rev 3517)
+++ trunk/nfsim/tools/proc.c	2004-12-30 06:16:20 UTC (rev 3518)
@@ -21,12 +21,11 @@
 
 #include <tui.h>
 #include <core.h>
+#include <utils.h>
 
+#include <sys/types.h>
 #include <unistd.h>
 
-#include <proc.h>
-
-
 static int proc_tree(struct proc_dir_entry *dir, int i) {
 	char indent[80];
 	struct proc_dir_entry *child;
@@ -46,250 +45,32 @@
 	return 0;
 }
 
-static struct proc_dir_entry *find_proc_entry(const char *name)
-{
-	struct proc_dir_entry *ent;
-	const char *next;
-	int len, last;
-
-	/* strip the /proc/ */
-	name += 6;
-
-	ent = &proc_root;
-
-	last = 0;
-
-	while (!last) {
-		if ((next = strchr(name, '/'))) {
-			len = next - name;
-		} else {
-			len = strlen(name);
-			last = 1;
-		}
-
-		for (ent = ent->subdir; ent; ent = ent->next) {
-			if (proc_match(len, name, ent))
-				break;
-		}
-		if (!ent)
-			return 0;
-		name += len + 1;
-
-	}
-
-	return ent;
-
-}
-
-/* Stolen straight from kernel's fs/proc/base.c,
- *  Copyright (C) 1991, 1992 Linus Torvalds
- */
-/* buffer size is one page but our output routines use some slack for overruns */
-#define PROC_BLOCK_SIZE	(PAGE_SIZE - 1024)
-
-static ssize_t
-proc_file_read(struct proc_dir_entry *dp, char *buf, size_t nbytes,
-	       loff_t *ppos)
-{
-	ssize_t	retval=0;
-	int	eof=0;
-	ssize_t	n, count;
-	char	*start;
-	char page[PAGE_SIZE];
-
-	while ((nbytes > 0) && !eof) {
-		count = min_t(ssize_t, PROC_BLOCK_SIZE, nbytes);
-
-		start = NULL;
-		if (dp->get_info) {
-			/* Handle old net routines */
-			n = dp->get_info(page, &start, *ppos, count);
-			if (n < count)
-				eof = 1;
-		} else if (dp->read_proc) {
-			/*
-			 * How to be a proc read function
-			 * ------------------------------
-			 * Prototype:
-			 *    int f(char *buffer, char **start, off_t offset,
-			 *          int count, int *peof, void *dat)
-			 *
-			 * Assume that the buffer is "count" bytes in size.
-			 *
-			 * If you know you have supplied all the data you
-			 * have, set *peof.
-			 *
-			 * You have three ways to return data:
-			 * 0) Leave *start = NULL.  (This is the default.)
-			 *    Put the data of the requested offset at that
-			 *    offset within the buffer.  Return the number (n)
-			 *    of bytes there are from the beginning of the
-			 *    buffer up to the last byte of data.  If the
-			 *    number of supplied bytes (= n - offset) is 
-			 *    greater than zero and you didn't signal eof
-			 *    and the reader is prepared to take more data
-			 *    you will be called again with the requested
-			 *    offset advanced by the number of bytes 
-			 *    absorbed.  This interface is useful for files
-			 *    no larger than the buffer.
-			 * 1) Set *start = an unsigned long value less than
-			 *    the buffer address but greater than zero.
-			 *    Put the data of the requested offset at the
-			 *    beginning of the buffer.  Return the number of
-			 *    bytes of data placed there.  If this number is
-			 *    greater than zero and you didn't signal eof
-			 *    and the reader is prepared to take more data
-			 *    you will be called again with the requested
-			 *    offset advanced by *start.  This interface is
-			 *    useful when you have a large file consisting
-			 *    of a series of blocks which you want to count
-			 *    and return as wholes.
-			 *    (Hack by Paul.Russell at rustcorp.com.au)
-			 * 2) Set *start = an address within the buffer.
-			 *    Put the data of the requested offset at *start.
-			 *    Return the number of bytes of data placed there.
-			 *    If this number is greater than zero and you
-			 *    didn't signal eof and the reader is prepared to
-			 *    take more data you will be called again with the
-			 *    requested offset advanced by the number of bytes
-			 *    absorbed.
-			 */
-			n = dp->read_proc(page, &start, *ppos,
-					  count, &eof, dp->data);
-		} else
-			break;
-
-		if (n == 0)   /* end of file */
-			break;
-		if (n < 0) {  /* error */
-			if (retval == 0)
-				retval = n;
-			break;
-		}
-
-		if (start == NULL) {
-			if (n > PAGE_SIZE) {
-				printk(KERN_ERR
-				       "proc_file_read: Apparent buffer overflow!\n");
-				n = PAGE_SIZE;
-			}
-			n -= *ppos;
-			if (n <= 0)
-				break;
-			if (n > count)
-				n = count;
-			start = page + *ppos;
-		} else if (start < page) {
-			if (n > PAGE_SIZE) {
-				printk(KERN_ERR
-				       "proc_file_read: Apparent buffer overflow!\n");
-				n = PAGE_SIZE;
-			}
-			if (n > count) {
-				/*
-				 * Don't reduce n because doing so might
-				 * cut off part of a data block.
-				 */
-				printk(KERN_WARNING
-				       "proc_file_read: Read count exceeded\n");
-			}
-		} else /* start >= page */ {
-			unsigned long startoff = (unsigned long)(start - page);
-			if (n > (PAGE_SIZE - startoff)) {
-				printk(KERN_ERR
-				       "proc_file_read: Apparent buffer overflow!\n");
-				n = PAGE_SIZE - startoff;
-			}
-			if (n > count)
-				n = count;
-		}
-
-		memcpy(buf, start < page ? page : start, n);
-
-		*ppos += start < page ? (unsigned long)start : n;
-		nbytes -= n;
-		buf += n;
-		retval += n;
-	}
-	return retval;
-}
-
-static int proc_cat(const char *name)
-{
-	struct proc_dir_entry *dir;
-	char buf[4096];
-	char *start;
-	loff_t offset;
-	
-	dir = find_proc_entry(name);
-
-	if (!dir) {
-		nfsim_log(LOG_ALWAYS, "proc file not found: %s", name);
-		return 1;
-	}
-
-	if (S_ISDIR(dir->mode)) {
-		nfsim_log(LOG_ALWAYS, "proc entry %s is a directory", name);
-		return 1;
-	}
-
-	start = 0;
-	offset = 0;
-	memset(buf, 0, 4096);
-	if (!dir->proc_fops) {
-		int len;
-
-		offset = 0;
-		len = proc_file_read(dir, buf, 4096, &offset);
-		if (len < 0)
-			nfsim_log(LOG_ALWAYS, "proc entry %s read failed %i!",
-				  name, len);
-		else
-			printk("%.*s", len, buf);
-		return 0;
-	} else  {
-		struct file file;
-		int ret;
-
-		ret = dir->proc_fops->open(NULL, &file);
-		if (ret < 0) {
-			nfsim_log(LOG_ALWAYS, "proc entry %s open failed %i!",
-				  name, ret);
-			return -1;
-		}
-		ret = dir->proc_fops->read(&file, buf, sizeof(buf)-1, &offset);
-		if (ret < 0)
-			nfsim_log(LOG_ALWAYS, "proc entry %s read failed %i!",
-				  name, ret);
-		dir->proc_fops->release(NULL, &file);
-		if (ret < 0)
-			return -1;
-		printk("%s", buf);
-		return 0;
-	}
-
-	nfsim_log(LOG_ALWAYS, "no way to read from %s!", name);
-	return -1;
-}
-	
 static void proc_help(int argc, char **argv)
 {
 #include "proc-help:proc"
 /*** XML Help:
     <section id="c:proc">
      <title><command>proc</command></title>
-     <para>Displays <filename>/proc</filename> filesystem information</para>
+     <para>Displays and set <filename>/proc</filename> filesystem information</para>
      <cmdsynopsis>
       <command>proc</command>
-      <sbr/>
+     </cmdsynopsis>
+     <cmdsynopsis>
       <command>proc</command>
       <arg choice="req">cat</arg>
       <arg choice="req"><replaceable>file</replaceable></arg>
      </cmdsynopsis>
+     <cmdsynopsis>
+      <command>proc</command>
+      <arg choice="req">write</arg>
+      <arg choice="req"><replaceable>file</replaceable></arg>
+      <arg choice="req"><replaceable>args...</replaceable></arg>
+     </cmdsynopsis>
      <para><command>proc</command> with no arguments will print the heirachy of
       the currently-registered proc files.</para>
      <para><command>proc cat <replaceable>file</replaceable></command> will
       display the contents of the proc file specified.</para>
+     <para><command>proc write <replaceable>file</replaceable> <replaceable>args..</replaceable> </command> will write args to the proc file.</para>
     </section>
 */
 }
@@ -302,12 +83,18 @@
 		return true;
 	}
 
-	if (!strcmp(argv[1], "cat")) {
+	if (streq(argv[1], "cat")) {
 		if (argc != 3) {
 			proc_help(argc, argv);
 			return false;
 		}
-		proc_cat(argv[2]);
+		return nfsim_proc_cat(argv[2]);
+	} else if (streq(argv[1], "write")) {
+		if (argc < 4) {
+			proc_help(argc, argv);
+			return false;
+		}
+		return nfsim_proc_write(argv[2], argv+3);
 	}
 
 	return true;




More information about the netfilter-cvslog mailing list