[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, ¶m);
+}
+
+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