File: /usr/src/linux/kernel/sysctl.c

1     /*
2      * sysctl.c: General linux system control interface
3      *
4      * Begun 24 March 1995, Stephen Tweedie
5      * Added /proc support, Dec 1995
6      * Added bdflush entry and intvec min/max checking, 2/23/96, Tom Dyas.
7      * Added hooks for /proc/sys/net (minor, minor patch), 96/4/1, Mike Shaver.
8      * Added kernel/java-{interpreter,appletviewer}, 96/5/10, Mike Shaver.
9      * Dynamic registration fixes, Stephen Tweedie.
10      * Added kswapd-interval, ctrl-alt-del, printk stuff, 1/8/97, Chris Horn.
11      * Made sysctl support optional via CONFIG_SYSCTL, 1/10/97, Chris
12      *  Horn.
13      * Added proc_doulongvec_ms_jiffies_minmax, 09/08/99, Carlos H. Bauer.
14      * Added proc_doulongvec_minmax, 09/08/99, Carlos H. Bauer.
15      * Changed linked lists to use list.h instead of lists.h, 02/24/00, Bill
16      *  Wendling.
17      * The list_for_each() macro wasn't appropriate for the sysctl loop.
18      *  Removed it and replaced it with older style, 03/23/00, Bill Wendling
19      */
20     
21     #include <linux/config.h>
22     #include <linux/slab.h>
23     #include <linux/sysctl.h>
24     #include <linux/swapctl.h>
25     #include <linux/proc_fs.h>
26     #include <linux/ctype.h>
27     #include <linux/utsname.h>
28     #include <linux/capability.h>
29     #include <linux/smp_lock.h>
30     #include <linux/init.h>
31     #include <linux/sysrq.h>
32     #include <linux/highuid.h>
33     
34     #include <asm/uaccess.h>
35     
36     #ifdef CONFIG_ROOT_NFS
37     #include <linux/nfs_fs.h>
38     #endif
39     
40     #if defined(CONFIG_SYSCTL)
41     
42     /* External variables not in a header file. */
43     extern int panic_timeout;
44     extern int C_A_D;
45     extern int bdf_prm[], bdflush_min[], bdflush_max[];
46     extern int sysctl_overcommit_memory;
47     extern int max_threads;
48     extern int nr_queued_signals, max_queued_signals;
49     extern int sysrq_enabled;
50     extern int core_uses_pid;
51     extern int cad_pid;
52     
53     /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
54     static int maxolduid = 65535;
55     static int minolduid;
56     
57     #ifdef CONFIG_KMOD
58     extern char modprobe_path[];
59     #endif
60     #ifdef CONFIG_HOTPLUG
61     extern char hotplug_path[];
62     #endif
63     #ifdef CONFIG_CHR_DEV_SG
64     extern int sg_big_buff;
65     #endif
66     #ifdef CONFIG_SYSVIPC
67     extern size_t shm_ctlmax;
68     extern size_t shm_ctlall;
69     extern int shm_ctlmni;
70     extern int msg_ctlmax;
71     extern int msg_ctlmnb;
72     extern int msg_ctlmni;
73     extern int sem_ctls[];
74     #endif
75     
76     #ifdef __sparc__
77     extern char reboot_command [];
78     extern int stop_a_enabled;
79     #endif
80     
81     #ifdef CONFIG_ARCH_S390
82     #ifdef CONFIG_MATHEMU
83     extern int sysctl_ieee_emulation_warnings;
84     #endif
85     extern int sysctl_userprocess_debug;
86     #endif
87     
88     #ifdef CONFIG_PPC32
89     extern unsigned long zero_paged_on, powersave_nap;
90     int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
91     		  void *buffer, size_t *lenp);
92     #endif
93     
94     #ifdef CONFIG_BSD_PROCESS_ACCT
95     extern int acct_parm[];
96     #endif
97     
98     extern int pgt_cache_water[];
99     
100     static int parse_table(int *, int, void *, size_t *, void *, size_t,
101     		       ctl_table *, void **);
102     static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
103     		  void *buffer, size_t *lenp);
104     
105     static ctl_table root_table[];
106     static struct ctl_table_header root_table_header =
107     	{ root_table, LIST_HEAD_INIT(root_table_header.ctl_entry) };
108     
109     static ctl_table kern_table[];
110     static ctl_table vm_table[];
111     #ifdef CONFIG_NET
112     extern ctl_table net_table[];
113     #endif
114     static ctl_table proc_table[];
115     static ctl_table fs_table[];
116     static ctl_table debug_table[];
117     static ctl_table dev_table[];
118     extern ctl_table random_table[];
119     
120     /* /proc declarations: */
121     
122     #ifdef CONFIG_PROC_FS
123     
124     static ssize_t proc_readsys(struct file *, char *, size_t, loff_t *);
125     static ssize_t proc_writesys(struct file *, const char *, size_t, loff_t *);
126     static int proc_sys_permission(struct inode *, int);
127     
128     struct file_operations proc_sys_file_operations = {
129     	read:		proc_readsys,
130     	write:		proc_writesys,
131     };
132     
133     static struct inode_operations proc_sys_inode_operations = {
134     	permission:	proc_sys_permission,
135     };
136     
137     extern struct proc_dir_entry *proc_sys_root;
138     
139     static void register_proc_table(ctl_table *, struct proc_dir_entry *);
140     static void unregister_proc_table(ctl_table *, struct proc_dir_entry *);
141     #endif
142     
143     /* The default sysctl tables: */
144     
145     static ctl_table root_table[] = {
146     	{CTL_KERN, "kernel", NULL, 0, 0555, kern_table},
147     	{CTL_VM, "vm", NULL, 0, 0555, vm_table},
148     #ifdef CONFIG_NET
149     	{CTL_NET, "net", NULL, 0, 0555, net_table},
150     #endif
151     	{CTL_PROC, "proc", NULL, 0, 0555, proc_table},
152     	{CTL_FS, "fs", NULL, 0, 0555, fs_table},
153     	{CTL_DEBUG, "debug", NULL, 0, 0555, debug_table},
154             {CTL_DEV, "dev", NULL, 0, 0555, dev_table},
155     	{0}
156     };
157     
158     static ctl_table kern_table[] = {
159     	{KERN_OSTYPE, "ostype", system_utsname.sysname, 64,
160     	 0444, NULL, &proc_doutsstring, &sysctl_string},
161     	{KERN_OSRELEASE, "osrelease", system_utsname.release, 64,
162     	 0444, NULL, &proc_doutsstring, &sysctl_string},
163     	{KERN_VERSION, "version", system_utsname.version, 64,
164     	 0444, NULL, &proc_doutsstring, &sysctl_string},
165     	{KERN_NODENAME, "hostname", system_utsname.nodename, 64,
166     	 0644, NULL, &proc_doutsstring, &sysctl_string},
167     	{KERN_DOMAINNAME, "domainname", system_utsname.domainname, 64,
168     	 0644, NULL, &proc_doutsstring, &sysctl_string},
169     	{KERN_PANIC, "panic", &panic_timeout, sizeof(int),
170     	 0644, NULL, &proc_dointvec},
171     	{KERN_CORE_USES_PID, "core_uses_pid", &core_uses_pid, sizeof(int),
172     	 0644, NULL, &proc_dointvec},
173     	{KERN_CAP_BSET, "cap-bound", &cap_bset, sizeof(kernel_cap_t),
174     	 0600, NULL, &proc_dointvec_bset},
175     #ifdef CONFIG_BLK_DEV_INITRD
176     	{KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(int),
177     	 0644, NULL, &proc_dointvec},
178     #endif
179     #ifdef __sparc__
180     	{KERN_SPARC_REBOOT, "reboot-cmd", reboot_command,
181     	 256, 0644, NULL, &proc_dostring, &sysctl_string },
182     	{KERN_SPARC_STOP_A, "stop-a", &stop_a_enabled, sizeof (int),
183     	 0644, NULL, &proc_dointvec},
184     #endif
185     #ifdef CONFIG_PPC32
186     	{KERN_PPC_ZEROPAGED, "zero-paged", &zero_paged_on, sizeof(int),
187     	 0644, NULL, &proc_dointvec},
188     	{KERN_PPC_POWERSAVE_NAP, "powersave-nap", &powersave_nap, sizeof(int),
189     	 0644, NULL, &proc_dointvec},
190     	{KERN_PPC_L2CR, "l2cr", NULL, 0,
191     	 0644, NULL, &proc_dol2crvec},
192     #endif
193     	{KERN_CTLALTDEL, "ctrl-alt-del", &C_A_D, sizeof(int),
194     	 0644, NULL, &proc_dointvec},
195     	{KERN_PRINTK, "printk", &console_loglevel, 4*sizeof(int),
196     	 0644, NULL, &proc_dointvec},
197     #ifdef CONFIG_KMOD
198     	{KERN_MODPROBE, "modprobe", &modprobe_path, 256,
199     	 0644, NULL, &proc_dostring, &sysctl_string },
200     #endif
201     #ifdef CONFIG_HOTPLUG
202     	{KERN_HOTPLUG, "hotplug", &hotplug_path, 256,
203     	 0644, NULL, &proc_dostring, &sysctl_string },
204     #endif
205     #ifdef CONFIG_CHR_DEV_SG
206     	{KERN_SG_BIG_BUFF, "sg-big-buff", &sg_big_buff, sizeof (int),
207     	 0444, NULL, &proc_dointvec},
208     #endif
209     #ifdef CONFIG_BSD_PROCESS_ACCT
210     	{KERN_ACCT, "acct", &acct_parm, 3*sizeof(int),
211     	0644, NULL, &proc_dointvec},
212     #endif
213     	{KERN_RTSIGNR, "rtsig-nr", &nr_queued_signals, sizeof(int),
214     	 0444, NULL, &proc_dointvec},
215     	{KERN_RTSIGMAX, "rtsig-max", &max_queued_signals, sizeof(int),
216     	 0644, NULL, &proc_dointvec},
217     #ifdef CONFIG_SYSVIPC
218     	{KERN_SHMMAX, "shmmax", &shm_ctlmax, sizeof (size_t),
219     	 0644, NULL, &proc_doulongvec_minmax},
220     	{KERN_SHMALL, "shmall", &shm_ctlall, sizeof (size_t),
221     	 0644, NULL, &proc_doulongvec_minmax},
222     	{KERN_SHMMNI, "shmmni", &shm_ctlmni, sizeof (int),
223     	 0644, NULL, &proc_dointvec},
224     	{KERN_MSGMAX, "msgmax", &msg_ctlmax, sizeof (int),
225     	 0644, NULL, &proc_dointvec},
226     	{KERN_MSGMNI, "msgmni", &msg_ctlmni, sizeof (int),
227     	 0644, NULL, &proc_dointvec},
228     	{KERN_MSGMNB, "msgmnb", &msg_ctlmnb, sizeof (int),
229     	 0644, NULL, &proc_dointvec},
230     	{KERN_SEM, "sem", &sem_ctls, 4*sizeof (int),
231     	 0644, NULL, &proc_dointvec},
232     #endif
233     #ifdef CONFIG_MAGIC_SYSRQ
234     	{KERN_SYSRQ, "sysrq", &sysrq_enabled, sizeof (int),
235     	 0644, NULL, &proc_dointvec},
236     #endif	 
237     	{KERN_CADPID, "cad_pid", &cad_pid, sizeof (int),
238     	 0600, NULL, &proc_dointvec},
239     	{KERN_MAX_THREADS, "threads-max", &max_threads, sizeof(int),
240     	 0644, NULL, &proc_dointvec},
241     	{KERN_RANDOM, "random", NULL, 0, 0555, random_table},
242     	{KERN_OVERFLOWUID, "overflowuid", &overflowuid, sizeof(int), 0644, NULL,
243     	 &proc_dointvec_minmax, &sysctl_intvec, NULL,
244     	 &minolduid, &maxolduid},
245     	{KERN_OVERFLOWGID, "overflowgid", &overflowgid, sizeof(int), 0644, NULL,
246     	 &proc_dointvec_minmax, &sysctl_intvec, NULL,
247     	 &minolduid, &maxolduid},
248     #ifdef CONFIG_ARCH_S390
249     #ifdef CONFIG_MATHEMU
250     	{KERN_IEEE_EMULATION_WARNINGS,"ieee_emulation_warnings",
251     	 &sysctl_ieee_emulation_warnings,sizeof(int),0644,NULL,&proc_dointvec},
252     #endif
253     	{KERN_S390_USER_DEBUG_LOGGING,"userprocess_debug",
254     	 &sysctl_userprocess_debug,sizeof(int),0644,NULL,&proc_dointvec},
255     #endif
256     	{0}
257     };
258     
259     static ctl_table vm_table[] = {
260     	{VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0644, NULL,
261     	 &proc_dointvec_minmax, &sysctl_intvec, NULL,
262     	 &bdflush_min, &bdflush_max},
263     	{VM_OVERCOMMIT_MEMORY, "overcommit_memory", &sysctl_overcommit_memory,
264     	 sizeof(sysctl_overcommit_memory), 0644, NULL, &proc_dointvec},
265     	{VM_PAGERDAEMON, "kswapd",
266     	 &pager_daemon, sizeof(pager_daemon_t), 0644, NULL, &proc_dointvec},
267     	{VM_PGT_CACHE, "pagetable_cache", 
268     	 &pgt_cache_water, 2*sizeof(int), 0644, NULL, &proc_dointvec},
269     	{VM_PAGE_CLUSTER, "page-cluster", 
270     	 &page_cluster, sizeof(int), 0644, NULL, &proc_dointvec},
271     	{0}
272     };
273     
274     static ctl_table proc_table[] = {
275     	{0}
276     };
277     
278     static ctl_table fs_table[] = {
279     	{FS_NRINODE, "inode-nr", &inodes_stat, 2*sizeof(int),
280     	 0444, NULL, &proc_dointvec},
281     	{FS_STATINODE, "inode-state", &inodes_stat, 7*sizeof(int),
282     	 0444, NULL, &proc_dointvec},
283     	{FS_NRFILE, "file-nr", &files_stat, 3*sizeof(int),
284     	 0444, NULL, &proc_dointvec},
285     	{FS_MAXFILE, "file-max", &files_stat.max_files, sizeof(int),
286     	 0644, NULL, &proc_dointvec},
287     	{FS_NRDQUOT, "dquot-nr", &nr_dquots, 2*sizeof(int),
288     	 0444, NULL, &proc_dointvec},
289     	{FS_MAXDQUOT, "dquot-max", &max_dquots, sizeof(int),
290     	 0644, NULL, &proc_dointvec},
291     	{FS_DENTRY, "dentry-state", &dentry_stat, 6*sizeof(int),
292     	 0444, NULL, &proc_dointvec},
293     	{FS_OVERFLOWUID, "overflowuid", &fs_overflowuid, sizeof(int), 0644, NULL,
294     	 &proc_dointvec_minmax, &sysctl_intvec, NULL,
295     	 &minolduid, &maxolduid},
296     	{FS_OVERFLOWGID, "overflowgid", &fs_overflowgid, sizeof(int), 0644, NULL,
297     	 &proc_dointvec_minmax, &sysctl_intvec, NULL,
298     	 &minolduid, &maxolduid},
299     	{FS_LEASES, "leases-enable", &leases_enable, sizeof(int),
300     	 0644, NULL, &proc_dointvec},
301     	{FS_DIR_NOTIFY, "dir-notify-enable", &dir_notify_enable,
302     	 sizeof(int), 0644, NULL, &proc_dointvec},
303     	{FS_LEASE_TIME, "lease-break-time", &lease_break_time, sizeof(int),
304     	 0644, NULL, &proc_dointvec},
305     	{0}
306     };
307     
308     static ctl_table debug_table[] = {
309     	{0}
310     };
311     
312     static ctl_table dev_table[] = {
313     	{0}
314     };  
315     
316     extern void init_irq_proc (void);
317     
318     void __init sysctl_init(void)
319     {
320     #ifdef CONFIG_PROC_FS
321     	register_proc_table(root_table, proc_sys_root);
322     	init_irq_proc();
323     #endif
324     }
325     
326     int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp,
327     	       void *newval, size_t newlen)
328     {
329     	struct list_head *tmp;
330     
331     	if (nlen <= 0 || nlen >= CTL_MAXNAME)
332     		return -ENOTDIR;
333     	if (oldval) {
334     		int old_len;
335     		if (!oldlenp || get_user(old_len, oldlenp))
336     			return -EFAULT;
337     	}
338     	tmp = &root_table_header.ctl_entry;
339     	do {
340     		struct ctl_table_header *head =
341     			list_entry(tmp, struct ctl_table_header, ctl_entry);
342     		void *context = NULL;
343     		int error = parse_table(name, nlen, oldval, oldlenp, 
344     					newval, newlen, head->ctl_table,
345     					&context);
346     		if (context)
347     			kfree(context);
348     		if (error != -ENOTDIR)
349     			return error;
350     		tmp = tmp->next;
351     	} while (tmp != &root_table_header.ctl_entry);
352     	return -ENOTDIR;
353     }
354     
355     extern asmlinkage long sys_sysctl(struct __sysctl_args *args)
356     {
357     	struct __sysctl_args tmp;
358     	int error;
359     
360     	if (copy_from_user(&tmp, args, sizeof(tmp)))
361     		return -EFAULT;
362     		
363     	lock_kernel();
364     	error = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp,
365     			  tmp.newval, tmp.newlen);
366     	unlock_kernel();
367     	return error;
368     }
369     
370     /*
371      * ctl_perm does NOT grant the superuser all rights automatically, because
372      * some sysctl variables are readonly even to root.
373      */
374     
375     static int test_perm(int mode, int op)
376     {
377     	if (!current->euid)
378     		mode >>= 6;
379     	else if (in_egroup_p(0))
380     		mode >>= 3;
381     	if ((mode & op & 0007) == op)
382     		return 0;
383     	return -EACCES;
384     }
385     
386     static inline int ctl_perm(ctl_table *table, int op)
387     {
388     	return test_perm(table->mode, op);
389     }
390     
391     static int parse_table(int *name, int nlen,
392     		       void *oldval, size_t *oldlenp,
393     		       void *newval, size_t newlen,
394     		       ctl_table *table, void **context)
395     {
396     	int n;
397     repeat:
398     	if (!nlen)
399     		return -ENOTDIR;
400     	if (get_user(n, name))
401     		return -EFAULT;
402     	for ( ; table->ctl_name; table++) {
403     		if (n == table->ctl_name || table->ctl_name == CTL_ANY) {
404     			int error;
405     			if (table->child) {
406     				if (ctl_perm(table, 001))
407     					return -EPERM;
408     				if (table->strategy) {
409     					error = table->strategy(
410     						table, name, nlen,
411     						oldval, oldlenp,
412     						newval, newlen, context);
413     					if (error)
414     						return error;
415     				}
416     				name++;
417     				nlen--;
418     				table = table->child;
419     				goto repeat;
420     			}
421     			error = do_sysctl_strategy(table, name, nlen,
422     						   oldval, oldlenp,
423     						   newval, newlen, context);
424     			return error;
425     		}
426     	}
427     	return -ENOTDIR;
428     }
429     
430     /* Perform the actual read/write of a sysctl table entry. */
431     int do_sysctl_strategy (ctl_table *table, 
432     			int *name, int nlen,
433     			void *oldval, size_t *oldlenp,
434     			void *newval, size_t newlen, void **context)
435     {
436     	int op = 0, rc;
437     	size_t len;
438     
439     	if (oldval)
440     		op |= 004;
441     	if (newval) 
442     		op |= 002;
443     	if (ctl_perm(table, op))
444     		return -EPERM;
445     
446     	if (table->strategy) {
447     		rc = table->strategy(table, name, nlen, oldval, oldlenp,
448     				     newval, newlen, context);
449     		if (rc < 0)
450     			return rc;
451     		if (rc > 0)
452     			return 0;
453     	}
454     
455     	/* If there is no strategy routine, or if the strategy returns
456     	 * zero, proceed with automatic r/w */
457     	if (table->data && table->maxlen) {
458     		if (oldval && oldlenp) {
459     			get_user(len, oldlenp);
460     			if (len) {
461     				if (len > table->maxlen)
462     					len = table->maxlen;
463     				if(copy_to_user(oldval, table->data, len))
464     					return -EFAULT;
465     				if(put_user(len, oldlenp))
466     					return -EFAULT;
467     			}
468     		}
469     		if (newval && newlen) {
470     			len = newlen;
471     			if (len > table->maxlen)
472     				len = table->maxlen;
473     			if(copy_from_user(table->data, newval, len))
474     				return -EFAULT;
475     		}
476     	}
477     	return 0;
478     }
479     
480     /**
481      * register_sysctl_table - register a sysctl heirarchy
482      * @table: the top-level table structure
483      * @insert_at_head: whether the entry should be inserted in front or at the end
484      *
485      * Register a sysctl table heirarchy. @table should be a filled in ctl_table
486      * array. An entry with a ctl_name of 0 terminates the table. 
487      *
488      * The members of the &ctl_table structure are used as follows:
489      *
490      * ctl_name - This is the numeric sysctl value used by sysctl(2). The number
491      *            must be unique within that level of sysctl
492      *
493      * procname - the name of the sysctl file under /proc/sys. Set to %NULL to not
494      *            enter a sysctl file
495      *
496      * data - a pointer to data for use by proc_handler
497      *
498      * maxlen - the maximum size in bytes of the data
499      *
500      * mode - the file permissions for the /proc/sys file, and for sysctl(2)
501      *
502      * child - a pointer to the child sysctl table if this entry is a directory, or
503      *         %NULL.
504      *
505      * proc_handler - the text handler routine (described below)
506      *
507      * strategy - the strategy routine (described below)
508      *
509      * de - for internal use by the sysctl routines
510      *
511      * extra1, extra2 - extra pointers usable by the proc handler routines
512      *
513      * Leaf nodes in the sysctl tree will be represented by a single file
514      * under /proc; non-leaf nodes will be represented by directories.
515      *
516      * sysctl(2) can automatically manage read and write requests through
517      * the sysctl table.  The data and maxlen fields of the ctl_table
518      * struct enable minimal validation of the values being written to be
519      * performed, and the mode field allows minimal authentication.
520      *
521      * More sophisticated management can be enabled by the provision of a
522      * strategy routine with the table entry.  This will be called before
523      * any automatic read or write of the data is performed.
524      *
525      * The strategy routine may return
526      *
527      * < 0 - Error occurred (error is passed to user process)
528      *
529      * 0   - OK - proceed with automatic read or write.
530      *
531      * > 0 - OK - read or write has been done by the strategy routine, so
532      *       return immediately.
533      *
534      * There must be a proc_handler routine for any terminal nodes
535      * mirrored under /proc/sys (non-terminals are handled by a built-in
536      * directory handler).  Several default handlers are available to
537      * cover common cases -
538      *
539      * proc_dostring(), proc_dointvec(), proc_dointvec_jiffies(),
540      * proc_dointvec_minmax(), proc_doulongvec_ms_jiffies_minmax(),
541      * proc_doulongvec_minmax()
542      *
543      * It is the handler's job to read the input buffer from user memory
544      * and process it. The handler should return 0 on success.
545      *
546      * This routine returns %NULL on a failure to register, and a pointer
547      * to the table header on success.
548      */
549     struct ctl_table_header *register_sysctl_table(ctl_table * table, 
550     					       int insert_at_head)
551     {
552     	struct ctl_table_header *tmp;
553     	tmp = kmalloc(sizeof(struct ctl_table_header), GFP_KERNEL);
554     	if (!tmp)
555     		return NULL;
556     	tmp->ctl_table = table;
557     	INIT_LIST_HEAD(&tmp->ctl_entry);
558     	if (insert_at_head)
559     		list_add(&tmp->ctl_entry, &root_table_header.ctl_entry);
560     	else
561     		list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry);
562     #ifdef CONFIG_PROC_FS
563     	register_proc_table(table, proc_sys_root);
564     #endif
565     	return tmp;
566     }
567     
568     /**
569      * unregister_sysctl_table - unregister a sysctl table heirarchy
570      * @header: the header returned from register_sysctl_table
571      *
572      * Unregisters the sysctl table and all children. proc entries may not
573      * actually be removed until they are no longer used by anyone.
574      */
575     void unregister_sysctl_table(struct ctl_table_header * header)
576     {
577     	list_del(&header->ctl_entry);
578     #ifdef CONFIG_PROC_FS
579     	unregister_proc_table(header->ctl_table, proc_sys_root);
580     #endif
581     	kfree(header);
582     }
583     
584     /*
585      * /proc/sys support
586      */
587     
588     #ifdef CONFIG_PROC_FS
589     
590     /* Scan the sysctl entries in table and add them all into /proc */
591     static void register_proc_table(ctl_table * table, struct proc_dir_entry *root)
592     {
593     	struct proc_dir_entry *de;
594     	int len;
595     	mode_t mode;
596     	
597     	for (; table->ctl_name; table++) {
598     		/* Can't do anything without a proc name. */
599     		if (!table->procname)
600     			continue;
601     		/* Maybe we can't do anything with it... */
602     		if (!table->proc_handler && !table->child) {
603     			printk(KERN_WARNING "SYSCTL: Can't register %s\n",
604     				table->procname);
605     			continue;
606     		}
607     
608     		len = strlen(table->procname);
609     		mode = table->mode;
610     
611     		de = NULL;
612     		if (table->proc_handler)
613     			mode |= S_IFREG;
614     		else {
615     			mode |= S_IFDIR;
616     			for (de = root->subdir; de; de = de->next) {
617     				if (proc_match(len, table->procname, de))
618     					break;
619     			}
620     			/* If the subdir exists already, de is non-NULL */
621     		}
622     
623     		if (!de) {
624     			de = create_proc_entry(table->procname, mode, root);
625     			if (!de)
626     				continue;
627     			de->data = (void *) table;
628     			if (table->proc_handler) {
629     				de->proc_fops = &proc_sys_file_operations;
630     				de->proc_iops = &proc_sys_inode_operations;
631     			}
632     		}
633     		table->de = de;
634     		if (de->mode & S_IFDIR)
635     			register_proc_table(table->child, de);
636     	}
637     }
638     
639     /*
640      * Unregister a /proc sysctl table and any subdirectories.
641      */
642     static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root)
643     {
644     	struct proc_dir_entry *de;
645     	for (; table->ctl_name; table++) {
646     		if (!(de = table->de))
647     			continue;
648     		if (de->mode & S_IFDIR) {
649     			if (!table->child) {
650     				printk (KERN_ALERT "Help - malformed sysctl tree on free\n");
651     				continue;
652     			}
653     			unregister_proc_table(table->child, de);
654     
655     			/* Don't unregister directories which still have entries.. */
656     			if (de->subdir)
657     				continue;
658     		}
659     
660     		/* Don't unregister proc entries that are still being used.. */
661     		if (atomic_read(&de->count))
662     			continue;
663     
664     		table->de = NULL;
665     		remove_proc_entry(table->procname, root);
666     	}
667     }
668     
669     static ssize_t do_rw_proc(int write, struct file * file, char * buf,
670     			  size_t count, loff_t *ppos)
671     {
672     	int op;
673     	struct proc_dir_entry *de;
674     	struct ctl_table *table;
675     	size_t res;
676     	ssize_t error;
677     	
678     	de = (struct proc_dir_entry*) file->f_dentry->d_inode->u.generic_ip;
679     	if (!de || !de->data)
680     		return -ENOTDIR;
681     	table = (struct ctl_table *) de->data;
682     	if (!table || !table->proc_handler)
683     		return -ENOTDIR;
684     	op = (write ? 002 : 004);
685     	if (ctl_perm(table, op))
686     		return -EPERM;
687     	
688     	res = count;
689     
690     	/*
691     	 * FIXME: we need to pass on ppos to the handler.
692     	 */
693     
694     	error = (*table->proc_handler) (table, write, file, buf, &res);
695     	if (error)
696     		return error;
697     	return res;
698     }
699     
700     static ssize_t proc_readsys(struct file * file, char * buf,
701     			    size_t count, loff_t *ppos)
702     {
703     	return do_rw_proc(0, file, buf, count, ppos);
704     }
705     
706     static ssize_t proc_writesys(struct file * file, const char * buf,
707     			     size_t count, loff_t *ppos)
708     {
709     	return do_rw_proc(1, file, (char *) buf, count, ppos);
710     }
711     
712     static int proc_sys_permission(struct inode *inode, int op)
713     {
714     	return test_perm(inode->i_mode, op);
715     }
716     
717     /**
718      * proc_dostring - read a string sysctl
719      * @table: the sysctl table
720      * @write: %TRUE if this is a write to the sysctl file
721      * @filp: the file structure
722      * @buffer: the user buffer
723      * @lenp: the size of the user buffer
724      *
725      * Reads/writes a string from/to the user buffer. If the kernel
726      * buffer provided is not large enough to hold the string, the
727      * string is truncated. The copied string is %NULL-terminated.
728      * If the string is being read by the user process, it is copied
729      * and a newline '\n' is added. It is truncated if the buffer is
730      * not large enough.
731      *
732      * Returns 0 on success.
733      */
734     int proc_dostring(ctl_table *table, int write, struct file *filp,
735     		  void *buffer, size_t *lenp)
736     {
737     	size_t len;
738     	char *p, c;
739     	
740     	if (!table->data || !table->maxlen || !*lenp ||
741     	    (filp->f_pos && !write)) {
742     		*lenp = 0;
743     		return 0;
744     	}
745     	
746     	if (write) {
747     		len = 0;
748     		p = buffer;
749     		while (len < *lenp) {
750     			if(get_user(c, p++))
751     				return -EFAULT;
752     			if (c == 0 || c == '\n')
753     				break;
754     			len++;
755     		}
756     		if (len >= table->maxlen)
757     			len = table->maxlen-1;
758     		if(copy_from_user(table->data, buffer, len))
759     			return -EFAULT;
760     		((char *) table->data)[len] = 0;
761     		filp->f_pos += *lenp;
762     	} else {
763     		len = strlen(table->data);
764     		if (len > table->maxlen)
765     			len = table->maxlen;
766     		if (len > *lenp)
767     			len = *lenp;
768     		if (len)
769     			if(copy_to_user(buffer, table->data, len))
770     				return -EFAULT;
771     		if (len < *lenp) {
772     			if(put_user('\n', ((char *) buffer) + len))
773     				return -EFAULT;
774     			len++;
775     		}
776     		*lenp = len;
777     		filp->f_pos += len;
778     	}
779     	return 0;
780     }
781     
782     /*
783      *	Special case of dostring for the UTS structure. This has locks
784      *	to observe. Should this be in kernel/sys.c ????
785      */
786      
787     static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
788     		  void *buffer, size_t *lenp)
789     {
790     	int r;
791     
792     	if (!write) {
793     		down_read(&uts_sem);
794     		r=proc_dostring(table,0,filp,buffer,lenp);
795     		up_read(&uts_sem);
796     	} else {
797     		down_write(&uts_sem);
798     		r=proc_dostring(table,1,filp,buffer,lenp);
799     		up_write(&uts_sem);
800     	}
801     	return r;
802     }
803     
804     #define OP_SET	0
805     #define OP_AND	1
806     #define OP_OR	2
807     #define OP_MAX	3
808     #define OP_MIN	4
809     
810     static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
811     		  void *buffer, size_t *lenp, int conv, int op)
812     {
813     	int *i, vleft, first=1, neg, val;
814     	size_t left, len;
815     	
816     	#define TMPBUFLEN 20
817     	char buf[TMPBUFLEN], *p;
818     	
819     	if (!table->data || !table->maxlen || !*lenp ||
820     	    (filp->f_pos && !write)) {
821     		*lenp = 0;
822     		return 0;
823     	}
824     	
825     	i = (int *) table->data;
826     	vleft = table->maxlen / sizeof(int);
827     	left = *lenp;
828     	
829     	for (; left && vleft--; i++, first=0) {
830     		if (write) {
831     			while (left) {
832     				char c;
833     				if(get_user(c,(char *) buffer))
834     					return -EFAULT;
835     				if (!isspace(c))
836     					break;
837     				left--;
838     				((char *) buffer)++;
839     			}
840     			if (!left)
841     				break;
842     			neg = 0;
843     			len = left;
844     			if (len > TMPBUFLEN-1)
845     				len = TMPBUFLEN-1;
846     			if(copy_from_user(buf, buffer, len))
847     				return -EFAULT;
848     			buf[len] = 0;
849     			p = buf;
850     			if (*p == '-' && left > 1) {
851     				neg = 1;
852     				left--, p++;
853     			}
854     			if (*p < '0' || *p > '9')
855     				break;
856     			val = simple_strtoul(p, &p, 0) * conv;
857     			len = p-buf;
858     			if ((len < left) && *p && !isspace(*p))
859     				break;
860     			if (neg)
861     				val = -val;
862     			buffer += len;
863     			left -= len;
864     			switch(op) {
865     			case OP_SET:	*i = val; break;
866     			case OP_AND:	*i &= val; break;
867     			case OP_OR:	*i |= val; break;
868     			case OP_MAX:	if(*i < val)
869     						*i = val;
870     					break;
871     			case OP_MIN:	if(*i > val)
872     						*i = val;
873     					break;
874     			}
875     		} else {
876     			p = buf;
877     			if (!first)
878     				*p++ = '\t';
879     			sprintf(p, "%d", (*i) / conv);
880     			len = strlen(buf);
881     			if (len > left)
882     				len = left;
883     			if(copy_to_user(buffer, buf, len))
884     				return -EFAULT;
885     			left -= len;
886     			buffer += len;
887     		}
888     	}
889     
890     	if (!write && !first && left) {
891     		if(put_user('\n', (char *) buffer))
892     			return -EFAULT;
893     		left--, buffer++;
894     	}
895     	if (write) {
896     		p = (char *) buffer;
897     		while (left) {
898     			char c;
899     			if(get_user(c, p++))
900     				return -EFAULT;
901     			if (!isspace(c))
902     				break;
903     			left--;
904     		}
905     	}
906     	if (write && first)
907     		return -EINVAL;
908     	*lenp -= left;
909     	filp->f_pos += *lenp;
910     	return 0;
911     }
912     
913     /**
914      * proc_dointvec - read a vector of integers
915      * @table: the sysctl table
916      * @write: %TRUE if this is a write to the sysctl file
917      * @filp: the file structure
918      * @buffer: the user buffer
919      * @lenp: the size of the user buffer
920      *
921      * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
922      * values from/to the user buffer, treated as an ASCII string. 
923      *
924      * Returns 0 on success.
925      */
926     int proc_dointvec(ctl_table *table, int write, struct file *filp,
927     		     void *buffer, size_t *lenp)
928     {
929         return do_proc_dointvec(table,write,filp,buffer,lenp,1,OP_SET);
930     }
931     
932     /*
933      *	init may raise the set.
934      */
935      
936     int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
937     			void *buffer, size_t *lenp)
938     {
939     	if (!capable(CAP_SYS_MODULE)) {
940     		return -EPERM;
941     	}
942     	return do_proc_dointvec(table,write,filp,buffer,lenp,1,
943     				(current->pid == 1) ? OP_SET : OP_AND);
944     }
945     
946     /**
947      * proc_dointvec_minmax - read a vector of integers with min/max values
948      * @table: the sysctl table
949      * @write: %TRUE if this is a write to the sysctl file
950      * @filp: the file structure
951      * @buffer: the user buffer
952      * @lenp: the size of the user buffer
953      *
954      * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
955      * values from/to the user buffer, treated as an ASCII string.
956      *
957      * This routine will ensure the values are within the range specified by
958      * table->extra1 (min) and table->extra2 (max).
959      *
960      * Returns 0 on success.
961      */
962     int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
963     		  void *buffer, size_t *lenp)
964     {
965     	int *i, *min, *max, vleft, first=1, neg, val;
966     	size_t len, left;
967     	#define TMPBUFLEN 20
968     	char buf[TMPBUFLEN], *p;
969     	
970     	if (!table->data || !table->maxlen || !*lenp ||
971     	    (filp->f_pos && !write)) {
972     		*lenp = 0;
973     		return 0;
974     	}
975     	
976     	i = (int *) table->data;
977     	min = (int *) table->extra1;
978     	max = (int *) table->extra2;
979     	vleft = table->maxlen / sizeof(int);
980     	left = *lenp;
981     	
982     	for (; left && vleft--; i++, first=0) {
983     		if (write) {
984     			while (left) {
985     				char c;
986     				if(get_user(c, (char *) buffer))
987     					return -EFAULT;
988     				if (!isspace(c))
989     					break;
990     				left--;
991     				((char *) buffer)++;
992     			}
993     			if (!left)
994     				break;
995     			neg = 0;
996     			len = left;
997     			if (len > TMPBUFLEN-1)
998     				len = TMPBUFLEN-1;
999     			if(copy_from_user(buf, buffer, len))
1000     				return -EFAULT;
1001     			buf[len] = 0;
1002     			p = buf;
1003     			if (*p == '-' && left > 1) {
1004     				neg = 1;
1005     				left--, p++;
1006     			}
1007     			if (*p < '0' || *p > '9')
1008     				break;
1009     			val = simple_strtoul(p, &p, 0);
1010     			len = p-buf;
1011     			if ((len < left) && *p && !isspace(*p))
1012     				break;
1013     			if (neg)
1014     				val = -val;
1015     			buffer += len;
1016     			left -= len;
1017     
1018     			if (min && val < *min++)
1019     				continue;
1020     			if (max && val > *max++)
1021     				continue;
1022     			*i = val;
1023     		} else {
1024     			p = buf;
1025     			if (!first)
1026     				*p++ = '\t';
1027     			sprintf(p, "%d", *i);
1028     			len = strlen(buf);
1029     			if (len > left)
1030     				len = left;
1031     			if(copy_to_user(buffer, buf, len))
1032     				return -EFAULT;
1033     			left -= len;
1034     			buffer += len;
1035     		}
1036     	}
1037     
1038     	if (!write && !first && left) {
1039     		if(put_user('\n', (char *) buffer))
1040     			return -EFAULT;
1041     		left--, buffer++;
1042     	}
1043     	if (write) {
1044     		p = (char *) buffer;
1045     		while (left) {
1046     			char c;
1047     			if(get_user(c, p++))
1048     				return -EFAULT;
1049     			if (!isspace(c))
1050     				break;
1051     			left--;
1052     		}
1053     	}
1054     	if (write && first)
1055     		return -EINVAL;
1056     	*lenp -= left;
1057     	filp->f_pos += *lenp;
1058     	return 0;
1059     }
1060     
1061     static int do_proc_doulongvec_minmax(ctl_table *table, int write,
1062     				     struct file *filp,
1063     				     void *buffer, size_t *lenp,
1064     				     unsigned long convmul,
1065     				     unsigned long convdiv)
1066     {
1067     #define TMPBUFLEN 20
1068     	unsigned long *i, *min, *max, val;
1069     	int vleft, first=1, neg;
1070     	size_t len, left;
1071     	char buf[TMPBUFLEN], *p;
1072     	
1073     	if (!table->data || !table->maxlen || !*lenp ||
1074     	    (filp->f_pos && !write)) {
1075     		*lenp = 0;
1076     		return 0;
1077     	}
1078     	
1079     	i = (unsigned long *) table->data;
1080     	min = (unsigned long *) table->extra1;
1081     	max = (unsigned long *) table->extra2;
1082     	vleft = table->maxlen / sizeof(unsigned long);
1083     	left = *lenp;
1084     	
1085     	for (; left && vleft--; i++, first=0) {
1086     		if (write) {
1087     			while (left) {
1088     				char c;
1089     				if(get_user(c, (char *) buffer))
1090     					return -EFAULT;
1091     				if (!isspace(c))
1092     					break;
1093     				left--;
1094     				((char *) buffer)++;
1095     			}
1096     			if (!left)
1097     				break;
1098     			neg = 0;
1099     			len = left;
1100     			if (len > TMPBUFLEN-1)
1101     				len = TMPBUFLEN-1;
1102     			if(copy_from_user(buf, buffer, len))
1103     				return -EFAULT;
1104     			buf[len] = 0;
1105     			p = buf;
1106     			if (*p == '-' && left > 1) {
1107     				neg = 1;
1108     				left--, p++;
1109     			}
1110     			if (*p < '0' || *p > '9')
1111     				break;
1112     			val = simple_strtoul(p, &p, 0) * convmul / convdiv ;
1113     			len = p-buf;
1114     			if ((len < left) && *p && !isspace(*p))
1115     				break;
1116     			if (neg)
1117     				val = -val;
1118     			buffer += len;
1119     			left -= len;
1120     
1121     			if(neg)
1122     				continue;
1123     			if (min && val < *min++)
1124     				continue;
1125     			if (max && val > *max++)
1126     				continue;
1127     			*i = val;
1128     		} else {
1129     			p = buf;
1130     			if (!first)
1131     				*p++ = '\t';
1132     			sprintf(p, "%lu", convdiv * (*i) / convmul);
1133     			len = strlen(buf);
1134     			if (len > left)
1135     				len = left;
1136     			if(copy_to_user(buffer, buf, len))
1137     				return -EFAULT;
1138     			left -= len;
1139     			buffer += len;
1140     		}
1141     	}
1142     
1143     	if (!write && !first && left) {
1144     		if(put_user('\n', (char *) buffer))
1145     			return -EFAULT;
1146     		left--, buffer++;
1147     	}
1148     	if (write) {
1149     		p = (char *) buffer;
1150     		while (left) {
1151     			char c;
1152     			if(get_user(c, p++))
1153     				return -EFAULT;
1154     			if (!isspace(c))
1155     				break;
1156     			left--;
1157     		}
1158     	}
1159     	if (write && first)
1160     		return -EINVAL;
1161     	*lenp -= left;
1162     	filp->f_pos += *lenp;
1163     	return 0;
1164     #undef TMPBUFLEN
1165     }
1166     
1167     /**
1168      * proc_doulongvec_minmax - read a vector of long integers with min/max values
1169      * @table: the sysctl table
1170      * @write: %TRUE if this is a write to the sysctl file
1171      * @filp: the file structure
1172      * @buffer: the user buffer
1173      * @lenp: the size of the user buffer
1174      *
1175      * Reads/writes up to table->maxlen/sizeof(unsigned long) unsigned long
1176      * values from/to the user buffer, treated as an ASCII string.
1177      *
1178      * This routine will ensure the values are within the range specified by
1179      * table->extra1 (min) and table->extra2 (max).
1180      *
1181      * Returns 0 on success.
1182      */
1183     int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
1184     			   void *buffer, size_t *lenp)
1185     {
1186         return do_proc_doulongvec_minmax(table, write, filp, buffer, lenp, 1l, 1l);
1187     }
1188     
1189     /**
1190      * proc_doulongvec_ms_jiffies_minmax - read a vector of millisecond values with min/max values
1191      * @table: the sysctl table
1192      * @write: %TRUE if this is a write to the sysctl file
1193      * @filp: the file structure
1194      * @buffer: the user buffer
1195      * @lenp: the size of the user buffer
1196      *
1197      * Reads/writes up to table->maxlen/sizeof(unsigned long) unsigned long
1198      * values from/to the user buffer, treated as an ASCII string. The values
1199      * are treated as milliseconds, and converted to jiffies when they are stored.
1200      *
1201      * This routine will ensure the values are within the range specified by
1202      * table->extra1 (min) and table->extra2 (max).
1203      *
1204      * Returns 0 on success.
1205      */
1206     int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
1207     				      struct file *filp,
1208     				      void *buffer, size_t *lenp)
1209     {
1210         return do_proc_doulongvec_minmax(table, write, filp, buffer,
1211     				     lenp, HZ, 1000l);
1212     }
1213     
1214     
1215     /**
1216      * proc_dointvec_jiffies - read a vector of integers as seconds
1217      * @table: the sysctl table
1218      * @write: %TRUE if this is a write to the sysctl file
1219      * @filp: the file structure
1220      * @buffer: the user buffer
1221      * @lenp: the size of the user buffer
1222      *
1223      * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
1224      * values from/to the user buffer, treated as an ASCII string. 
1225      * The values read are assumed to be in seconds, and are converted into
1226      * jiffies.
1227      *
1228      * Returns 0 on success.
1229      */
1230     int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1231     			  void *buffer, size_t *lenp)
1232     {
1233         return do_proc_dointvec(table,write,filp,buffer,lenp,HZ,OP_SET);
1234     }
1235     
1236     #else /* CONFIG_PROC_FS */
1237     
1238     int proc_dostring(ctl_table *table, int write, struct file *filp,
1239     		  void *buffer, size_t *lenp)
1240     {
1241     	return -ENOSYS;
1242     }
1243     
1244     static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
1245     			    void *buffer, size_t *lenp)
1246     {
1247     	return -ENOSYS;
1248     }
1249     
1250     int proc_dointvec(ctl_table *table, int write, struct file *filp,
1251     		  void *buffer, size_t *lenp)
1252     {
1253     	return -ENOSYS;
1254     }
1255     
1256     int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
1257     			void *buffer, size_t *lenp)
1258     {
1259     	return -ENOSYS;
1260     }
1261     
1262     int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
1263     		    void *buffer, size_t *lenp)
1264     {
1265     	return -ENOSYS;
1266     }
1267     
1268     int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1269     		    void *buffer, size_t *lenp)
1270     {
1271     	return -ENOSYS;
1272     }
1273     
1274     int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
1275     		    void *buffer, size_t *lenp)
1276     {
1277     	return -ENOSYS;
1278     }
1279     
1280     int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
1281     				      struct file *filp,
1282     				      void *buffer, size_t *lenp)
1283     {
1284         return -ENOSYS;
1285     }
1286     
1287     
1288     #endif /* CONFIG_PROC_FS */
1289     
1290     
1291     /*
1292      * General sysctl support routines 
1293      */
1294     
1295     /* The generic string strategy routine: */
1296     int sysctl_string(ctl_table *table, int *name, int nlen,
1297     		  void *oldval, size_t *oldlenp,
1298     		  void *newval, size_t newlen, void **context)
1299     {
1300     	size_t l, len;
1301     	
1302     	if (!table->data || !table->maxlen) 
1303     		return -ENOTDIR;
1304     	
1305     	if (oldval && oldlenp) {
1306     		if(get_user(len, oldlenp))
1307     			return -EFAULT;
1308     		if (len) {
1309     			l = strlen(table->data);
1310     			if (len > l) len = l;
1311     			if (len >= table->maxlen)
1312     				len = table->maxlen;
1313     			if(copy_to_user(oldval, table->data, len))
1314     				return -EFAULT;
1315     			if(put_user(0, ((char *) oldval) + len))
1316     				return -EFAULT;
1317     			if(put_user(len, oldlenp))
1318     				return -EFAULT;
1319     		}
1320     	}
1321     	if (newval && newlen) {
1322     		len = newlen;
1323     		if (len > table->maxlen)
1324     			len = table->maxlen;
1325     		if(copy_from_user(table->data, newval, len))
1326     			return -EFAULT;
1327     		if (len == table->maxlen)
1328     			len--;
1329     		((char *) table->data)[len] = 0;
1330     	}
1331     	return 0;
1332     }
1333     
1334     /*
1335      * This function makes sure that all of the integers in the vector
1336      * are between the minimum and maximum values given in the arrays
1337      * table->extra1 and table->extra2, respectively.
1338      */
1339     int sysctl_intvec(ctl_table *table, int *name, int nlen,
1340     		void *oldval, size_t *oldlenp,
1341     		void *newval, size_t newlen, void **context)
1342     {
1343     	int i, *vec, *min, *max;
1344     	size_t length;
1345     
1346     	if (newval && newlen) {
1347     		if (newlen % sizeof(int) != 0)
1348     			return -EINVAL;
1349     
1350     		if (!table->extra1 && !table->extra2)
1351     			return 0;
1352     
1353     		if (newlen > table->maxlen)
1354     			newlen = table->maxlen;
1355     		length = newlen / sizeof(int);
1356     
1357     		vec = (int *) newval;
1358     		min = (int *) table->extra1;
1359     		max = (int *) table->extra2;
1360     
1361     		for (i = 0; i < length; i++) {
1362     			int value;
1363     			get_user(value, vec + i);
1364     			if (min && value < min[i])
1365     				return -EINVAL;
1366     			if (max && value > max[i])
1367     				return -EINVAL;
1368     		}
1369     	}
1370     	return 0;
1371     }
1372     
1373     /* Strategy function to convert jiffies to seconds */ 
1374     int sysctl_jiffies(ctl_table *table, int *name, int nlen,
1375     		void *oldval, size_t *oldlenp,
1376     		void *newval, size_t newlen, void **context)
1377     {
1378     	if (oldval) {
1379     		size_t olen;
1380     		if (oldlenp) { 
1381     			if (get_user(olen, oldlenp))
1382     				return -EFAULT;
1383     			if (olen!=sizeof(int))
1384     				return -EINVAL; 
1385     		}
1386     		if (put_user(*(int *)(table->data) / HZ, (int *)oldval) || 
1387     		    (oldlenp && put_user(sizeof(int),oldlenp)))
1388     			return -EFAULT;
1389     	}
1390     	if (newval && newlen) { 
1391     		int new;
1392     		if (newlen != sizeof(int))
1393     			return -EINVAL; 
1394     		if (get_user(new, (int *)newval))
1395     			return -EFAULT;
1396     		*(int *)(table->data) = new*HZ; 
1397     	}
1398     	return 1;
1399     }
1400     
1401     
1402     #else /* CONFIG_SYSCTL */
1403     
1404     
1405     extern asmlinkage long sys_sysctl(struct __sysctl_args *args)
1406     {
1407     	return -ENOSYS;
1408     }
1409     
1410     int sysctl_string(ctl_table *table, int *name, int nlen,
1411     		  void *oldval, size_t *oldlenp,
1412     		  void *newval, size_t newlen, void **context)
1413     {
1414     	return -ENOSYS;
1415     }
1416     
1417     int sysctl_intvec(ctl_table *table, int *name, int nlen,
1418     		void *oldval, size_t *oldlenp,
1419     		void *newval, size_t newlen, void **context)
1420     {
1421     	return -ENOSYS;
1422     }
1423     
1424     int sysctl_jiffies(ctl_table *table, int *name, int nlen,
1425     		void *oldval, size_t *oldlenp,
1426     		void *newval, size_t newlen, void **context)
1427     {
1428     	return -ENOSYS;
1429     }
1430     
1431     int proc_dostring(ctl_table *table, int write, struct file *filp,
1432     		  void *buffer, size_t *lenp)
1433     {
1434     	return -ENOSYS;
1435     }
1436     
1437     int proc_dointvec(ctl_table *table, int write, struct file *filp,
1438     		  void *buffer, size_t *lenp)
1439     {
1440     	return -ENOSYS;
1441     }
1442     
1443     int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
1444     			void *buffer, size_t *lenp)
1445     {
1446     	return -ENOSYS;
1447     }
1448     
1449     int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
1450     		    void *buffer, size_t *lenp)
1451     {
1452     	return -ENOSYS;
1453     }
1454     
1455     int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1456     			  void *buffer, size_t *lenp)
1457     {
1458     	return -ENOSYS;
1459     }
1460     
1461     int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
1462     		    void *buffer, size_t *lenp)
1463     {
1464     	return -ENOSYS;
1465     }
1466     
1467     int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
1468     				      struct file *filp,
1469     				      void *buffer, size_t *lenp)
1470     {
1471         return -ENOSYS;
1472     }
1473     
1474     struct ctl_table_header * register_sysctl_table(ctl_table * table, 
1475     						int insert_at_head)
1476     {
1477     	return 0;
1478     }
1479     
1480     void unregister_sysctl_table(struct ctl_table_header * table)
1481     {
1482     }
1483     
1484     #endif /* CONFIG_SYSCTL */
1485