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