Merge with Linux 2.4.0-test6-pre2.
[linux-2.6/linux-mips.git] / kernel / sysctl.c
blobb475af7ed4f5b8eeefaacff8cdd27c17f93776c7
1 /*
2 * sysctl.c: General linux system control interface
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
21 #include <linux/config.h>
22 #include <linux/malloc.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>
34 #include <asm/uaccess.h>
36 #ifdef CONFIG_ROOT_NFS
37 #include <linux/nfs_fs.h>
38 #endif
40 #if defined(CONFIG_SYSCTL)
42 /* External variables not in a header file. */
43 extern int panic_timeout;
44 extern int console_loglevel, 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;
51 /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
52 static int maxolduid = 65535;
53 static int minolduid;
55 #ifdef CONFIG_KMOD
56 extern char modprobe_path[];
57 #ifdef CONFIG_HOTPLUG
58 extern char hotplug_path[];
59 #endif
60 #endif
61 #ifdef CONFIG_CHR_DEV_SG
62 extern int sg_big_buff;
63 #endif
64 #ifdef CONFIG_SYSVIPC
65 extern size_t shm_ctlmax;
66 extern int msg_ctlmax;
67 extern int msg_ctlmnb;
68 extern int msg_ctlmni;
69 extern int sem_ctls[];
70 #endif
72 #ifdef __sparc__
73 extern char reboot_command [];
74 extern int stop_a_enabled;
75 #endif
76 #ifdef __powerpc__
77 extern unsigned long htab_reclaim_on, zero_paged_on, powersave_nap;
78 int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
79 void *buffer, size_t *lenp);
80 #endif
82 #ifdef CONFIG_BSD_PROCESS_ACCT
83 extern int acct_parm[];
84 #endif
86 extern int pgt_cache_water[];
88 static int parse_table(int *, int, void *, size_t *, void *, size_t,
89 ctl_table *, void **);
90 static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
91 void *buffer, size_t *lenp);
93 static ctl_table root_table[];
94 static struct ctl_table_header root_table_header =
95 { root_table, LIST_HEAD_INIT(root_table_header.ctl_entry) };
97 static ctl_table kern_table[];
98 static ctl_table vm_table[];
99 #ifdef CONFIG_NET
100 extern ctl_table net_table[];
101 #endif
102 static ctl_table proc_table[];
103 static ctl_table fs_table[];
104 static ctl_table debug_table[];
105 static ctl_table dev_table[];
106 extern ctl_table random_table[];
108 /* /proc declarations: */
110 #ifdef CONFIG_PROC_FS
112 static ssize_t proc_readsys(struct file *, char *, size_t, loff_t *);
113 static ssize_t proc_writesys(struct file *, const char *, size_t, loff_t *);
114 static int proc_sys_permission(struct inode *, int);
116 struct file_operations proc_sys_file_operations = {
117 read: proc_readsys,
118 write: proc_writesys,
121 static struct inode_operations proc_sys_inode_operations = {
122 permission: proc_sys_permission,
125 extern struct proc_dir_entry *proc_sys_root;
127 static void register_proc_table(ctl_table *, struct proc_dir_entry *);
128 static void unregister_proc_table(ctl_table *, struct proc_dir_entry *);
129 #endif
131 extern int inodes_stat[];
132 extern int dentry_stat[];
134 /* The default sysctl tables: */
136 static ctl_table root_table[] = {
137 {CTL_KERN, "kernel", NULL, 0, 0555, kern_table},
138 {CTL_VM, "vm", NULL, 0, 0555, vm_table},
139 #ifdef CONFIG_NET
140 {CTL_NET, "net", NULL, 0, 0555, net_table},
141 #endif
142 {CTL_PROC, "proc", NULL, 0, 0555, proc_table},
143 {CTL_FS, "fs", NULL, 0, 0555, fs_table},
144 {CTL_DEBUG, "debug", NULL, 0, 0555, debug_table},
145 {CTL_DEV, "dev", NULL, 0, 0555, dev_table},
149 static ctl_table kern_table[] = {
150 {KERN_OSTYPE, "ostype", system_utsname.sysname, 64,
151 0444, NULL, &proc_doutsstring, &sysctl_string},
152 {KERN_OSRELEASE, "osrelease", system_utsname.release, 64,
153 0444, NULL, &proc_doutsstring, &sysctl_string},
154 {KERN_VERSION, "version", system_utsname.version, 64,
155 0444, NULL, &proc_doutsstring, &sysctl_string},
156 {KERN_NODENAME, "hostname", system_utsname.nodename, 64,
157 0644, NULL, &proc_doutsstring, &sysctl_string},
158 {KERN_DOMAINNAME, "domainname", system_utsname.domainname, 64,
159 0644, NULL, &proc_doutsstring, &sysctl_string},
160 {KERN_PANIC, "panic", &panic_timeout, sizeof(int),
161 0644, NULL, &proc_dointvec},
162 {KERN_CAP_BSET, "cap-bound", &cap_bset, sizeof(kernel_cap_t),
163 0600, NULL, &proc_dointvec_bset},
164 #ifdef CONFIG_BLK_DEV_INITRD
165 {KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(int),
166 0644, NULL, &proc_dointvec},
167 #endif
168 #ifdef __sparc__
169 {KERN_SPARC_REBOOT, "reboot-cmd", reboot_command,
170 256, 0644, NULL, &proc_dostring, &sysctl_string },
171 {KERN_SPARC_STOP_A, "stop-a", &stop_a_enabled, sizeof (int),
172 0644, NULL, &proc_dointvec},
173 #endif
174 #ifdef __powerpc__
175 {KERN_PPC_HTABRECLAIM, "htab-reclaim", &htab_reclaim_on, sizeof(int),
176 0644, NULL, &proc_dointvec},
177 {KERN_PPC_ZEROPAGED, "zero-paged", &zero_paged_on, sizeof(int),
178 0644, NULL, &proc_dointvec},
179 {KERN_PPC_POWERSAVE_NAP, "powersave-nap", &powersave_nap, sizeof(int),
180 0644, NULL, &proc_dointvec},
181 {KERN_PPC_L2CR, "l2cr", NULL, 0,
182 0644, NULL, &proc_dol2crvec},
183 #endif
184 {KERN_CTLALTDEL, "ctrl-alt-del", &C_A_D, sizeof(int),
185 0644, NULL, &proc_dointvec},
186 {KERN_PRINTK, "printk", &console_loglevel, 4*sizeof(int),
187 0644, NULL, &proc_dointvec},
188 #ifdef CONFIG_KMOD
189 {KERN_MODPROBE, "modprobe", &modprobe_path, 256,
190 0644, NULL, &proc_dostring, &sysctl_string },
191 #ifdef CONFIG_HOTPLUG
192 {KERN_HOTPLUG, "hotplug", &hotplug_path, 256,
193 0644, NULL, &proc_dostring, &sysctl_string },
194 #endif
195 #endif
196 #ifdef CONFIG_CHR_DEV_SG
197 {KERN_SG_BIG_BUFF, "sg-big-buff", &sg_big_buff, sizeof (int),
198 0444, NULL, &proc_dointvec},
199 #endif
200 #ifdef CONFIG_BSD_PROCESS_ACCT
201 {KERN_ACCT, "acct", &acct_parm, 3*sizeof(int),
202 0644, NULL, &proc_dointvec},
203 #endif
204 {KERN_RTSIGNR, "rtsig-nr", &nr_queued_signals, sizeof(int),
205 0444, NULL, &proc_dointvec},
206 {KERN_RTSIGMAX, "rtsig-max", &max_queued_signals, sizeof(int),
207 0644, NULL, &proc_dointvec},
208 #ifdef CONFIG_SYSVIPC
209 {KERN_SHMMAX, "shmmax", &shm_ctlmax, sizeof (size_t),
210 0644, NULL, &proc_doulongvec_minmax},
211 {KERN_MSGMAX, "msgmax", &msg_ctlmax, sizeof (int),
212 0644, NULL, &proc_dointvec},
213 {KERN_MSGMNI, "msgmni", &msg_ctlmni, sizeof (int),
214 0644, NULL, &proc_dointvec},
215 {KERN_MSGMNB, "msgmnb", &msg_ctlmnb, sizeof (int),
216 0644, NULL, &proc_dointvec},
217 {KERN_SEM, "sem", &sem_ctls, 4*sizeof (int),
218 0644, NULL, &proc_dointvec},
219 #endif
220 #ifdef CONFIG_MAGIC_SYSRQ
221 {KERN_SYSRQ, "sysrq", &sysrq_enabled, sizeof (int),
222 0644, NULL, &proc_dointvec},
223 #endif
224 {KERN_MAX_THREADS, "threads-max", &max_threads, sizeof(int),
225 0644, NULL, &proc_dointvec},
226 {KERN_RANDOM, "random", NULL, 0, 0555, random_table},
227 {KERN_OVERFLOWUID, "overflowuid", &overflowuid, sizeof(int), 0644, NULL,
228 &proc_dointvec_minmax, &sysctl_intvec, NULL,
229 &minolduid, &maxolduid},
230 {KERN_OVERFLOWGID, "overflowgid", &overflowgid, sizeof(int), 0644, NULL,
231 &proc_dointvec_minmax, &sysctl_intvec, NULL,
232 &minolduid, &maxolduid},
236 static ctl_table vm_table[] = {
237 {VM_FREEPG, "freepages",
238 &freepages, sizeof(freepages_t), 0644, NULL, &proc_dointvec},
239 {VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0644, NULL,
240 &proc_dointvec_minmax, &sysctl_intvec, NULL,
241 &bdflush_min, &bdflush_max},
242 {VM_OVERCOMMIT_MEMORY, "overcommit_memory", &sysctl_overcommit_memory,
243 sizeof(sysctl_overcommit_memory), 0644, NULL, &proc_dointvec},
244 {VM_BUFFERMEM, "buffermem",
245 &buffer_mem, sizeof(buffer_mem_t), 0644, NULL, &proc_dointvec},
246 {VM_PAGECACHE, "pagecache",
247 &page_cache, sizeof(buffer_mem_t), 0644, NULL, &proc_dointvec},
248 {VM_PAGERDAEMON, "kswapd",
249 &pager_daemon, sizeof(pager_daemon_t), 0644, NULL, &proc_dointvec},
250 {VM_PGT_CACHE, "pagetable_cache",
251 &pgt_cache_water, 2*sizeof(int), 0644, NULL, &proc_dointvec},
252 {VM_PAGE_CLUSTER, "page-cluster",
253 &page_cluster, sizeof(int), 0644, NULL, &proc_dointvec},
257 static ctl_table proc_table[] = {
261 static ctl_table fs_table[] = {
262 {FS_NRINODE, "inode-nr", &inodes_stat, 2*sizeof(int),
263 0444, NULL, &proc_dointvec},
264 {FS_STATINODE, "inode-state", &inodes_stat, 7*sizeof(int),
265 0444, NULL, &proc_dointvec},
266 {FS_NRFILE, "file-nr", &files_stat, 3*sizeof(int),
267 0444, NULL, &proc_dointvec},
268 {FS_MAXFILE, "file-max", &files_stat.max_files, sizeof(int),
269 0644, NULL, &proc_dointvec},
270 {FS_NRSUPER, "super-nr", &nr_super_blocks, sizeof(int),
271 0444, NULL, &proc_dointvec},
272 {FS_MAXSUPER, "super-max", &max_super_blocks, sizeof(int),
273 0644, NULL, &proc_dointvec},
274 {FS_NRDQUOT, "dquot-nr", &nr_dquots, 2*sizeof(int),
275 0444, NULL, &proc_dointvec},
276 {FS_MAXDQUOT, "dquot-max", &max_dquots, sizeof(int),
277 0644, NULL, &proc_dointvec},
278 {FS_DENTRY, "dentry-state", &dentry_stat, 6*sizeof(int),
279 0444, NULL, &proc_dointvec},
280 {FS_OVERFLOWUID, "overflowuid", &fs_overflowuid, sizeof(int), 0644, NULL,
281 &proc_dointvec_minmax, &sysctl_intvec, NULL,
282 &minolduid, &maxolduid},
283 {FS_OVERFLOWGID, "overflowgid", &fs_overflowgid, sizeof(int), 0644, NULL,
284 &proc_dointvec_minmax, &sysctl_intvec, NULL,
285 &minolduid, &maxolduid},
289 static ctl_table debug_table[] = {
293 static ctl_table dev_table[] = {
297 extern void init_irq_proc (void);
299 void __init sysctl_init(void)
301 #ifdef CONFIG_PROC_FS
302 register_proc_table(root_table, proc_sys_root);
303 init_irq_proc();
304 #endif
307 int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp,
308 void *newval, size_t newlen)
310 struct list_head *tmp;
312 if (nlen == 0 || nlen >= CTL_MAXNAME)
313 return -ENOTDIR;
314 if (oldval) {
315 int old_len;
316 if (!oldlenp || get_user(old_len, oldlenp))
317 return -EFAULT;
319 tmp = &root_table_header.ctl_entry;
320 do {
321 struct ctl_table_header *head =
322 list_entry(tmp, struct ctl_table_header, ctl_entry);
323 void *context = NULL;
324 int error = parse_table(name, nlen, oldval, oldlenp,
325 newval, newlen, head->ctl_table,
326 &context);
327 if (context)
328 kfree(context);
329 if (error != -ENOTDIR)
330 return error;
331 tmp = tmp->next;
332 } while (tmp != &root_table_header.ctl_entry);
333 return -ENOTDIR;
336 extern asmlinkage long sys_sysctl(struct __sysctl_args *args)
338 struct __sysctl_args tmp;
339 int error;
341 if (copy_from_user(&tmp, args, sizeof(tmp)))
342 return -EFAULT;
344 lock_kernel();
345 error = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp,
346 tmp.newval, tmp.newlen);
347 unlock_kernel();
348 return error;
352 * ctl_perm does NOT grant the superuser all rights automatically, because
353 * some sysctl variables are readonly even to root.
356 static int test_perm(int mode, int op)
358 if (!current->euid)
359 mode >>= 6;
360 else if (in_egroup_p(0))
361 mode >>= 3;
362 if ((mode & op & 0007) == op)
363 return 0;
364 return -EACCES;
367 static inline int ctl_perm(ctl_table *table, int op)
369 return test_perm(table->mode, op);
372 static int parse_table(int *name, int nlen,
373 void *oldval, size_t *oldlenp,
374 void *newval, size_t newlen,
375 ctl_table *table, void **context)
377 int n;
378 repeat:
379 if (!nlen)
380 return -ENOTDIR;
381 if (get_user(n, name))
382 return -EFAULT;
383 for ( ; table->ctl_name; table++) {
384 if (n == table->ctl_name || table->ctl_name == CTL_ANY) {
385 int error;
386 if (table->child) {
387 if (ctl_perm(table, 001))
388 return -EPERM;
389 if (table->strategy) {
390 error = table->strategy(
391 table, name, nlen,
392 oldval, oldlenp,
393 newval, newlen, context);
394 if (error)
395 return error;
397 name++;
398 nlen--;
399 table = table->child;
400 goto repeat;
402 error = do_sysctl_strategy(table, name, nlen,
403 oldval, oldlenp,
404 newval, newlen, context);
405 return error;
408 return -ENOTDIR;
411 /* Perform the actual read/write of a sysctl table entry. */
412 int do_sysctl_strategy (ctl_table *table,
413 int *name, int nlen,
414 void *oldval, size_t *oldlenp,
415 void *newval, size_t newlen, void **context)
417 int op = 0, rc, len;
419 if (oldval)
420 op |= 004;
421 if (newval)
422 op |= 002;
423 if (ctl_perm(table, op))
424 return -EPERM;
426 if (table->strategy) {
427 rc = table->strategy(table, name, nlen, oldval, oldlenp,
428 newval, newlen, context);
429 if (rc < 0)
430 return rc;
431 if (rc > 0)
432 return 0;
435 /* If there is no strategy routine, or if the strategy returns
436 * zero, proceed with automatic r/w */
437 if (table->data && table->maxlen) {
438 if (oldval && oldlenp) {
439 get_user(len, oldlenp);
440 if (len) {
441 if (len > table->maxlen)
442 len = table->maxlen;
443 if(copy_to_user(oldval, table->data, len))
444 return -EFAULT;
445 if(put_user(len, oldlenp))
446 return -EFAULT;
449 if (newval && newlen) {
450 len = newlen;
451 if (len > table->maxlen)
452 len = table->maxlen;
453 if(copy_from_user(table->data, newval, len))
454 return -EFAULT;
457 return 0;
460 struct ctl_table_header *register_sysctl_table(ctl_table * table,
461 int insert_at_head)
463 struct ctl_table_header *tmp;
464 tmp = kmalloc(sizeof(struct ctl_table_header), GFP_KERNEL);
465 if (!tmp)
466 return 0;
467 tmp->ctl_table = table;
468 INIT_LIST_HEAD(&tmp->ctl_entry);
469 if (insert_at_head)
470 list_add(&tmp->ctl_entry, &root_table_header.ctl_entry);
471 else
472 list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry);
473 #ifdef CONFIG_PROC_FS
474 register_proc_table(table, proc_sys_root);
475 #endif
476 return tmp;
480 * Unlink and free a ctl_table.
482 void unregister_sysctl_table(struct ctl_table_header * header)
484 list_del(&header->ctl_entry);
485 #ifdef CONFIG_PROC_FS
486 unregister_proc_table(header->ctl_table, proc_sys_root);
487 #endif
488 kfree(header);
492 * /proc/sys support
495 #ifdef CONFIG_PROC_FS
497 /* Scan the sysctl entries in table and add them all into /proc */
498 static void register_proc_table(ctl_table * table, struct proc_dir_entry *root)
500 struct proc_dir_entry *de;
501 int len;
502 mode_t mode;
504 for (; table->ctl_name; table++) {
505 /* Can't do anything without a proc name. */
506 if (!table->procname)
507 continue;
508 /* Maybe we can't do anything with it... */
509 if (!table->proc_handler && !table->child) {
510 printk(KERN_WARNING "SYSCTL: Can't register %s\n",
511 table->procname);
512 continue;
515 len = strlen(table->procname);
516 mode = table->mode;
518 de = NULL;
519 if (table->proc_handler)
520 mode |= S_IFREG;
521 else {
522 mode |= S_IFDIR;
523 for (de = root->subdir; de; de = de->next) {
524 if (proc_match(len, table->procname, de))
525 break;
527 /* If the subdir exists already, de is non-NULL */
530 if (!de) {
531 de = create_proc_entry(table->procname, mode, root);
532 if (!de)
533 continue;
534 de->data = (void *) table;
535 if (table->proc_handler) {
536 de->proc_fops = &proc_sys_file_operations;
537 de->proc_iops = &proc_sys_inode_operations;
540 table->de = de;
541 if (de->mode & S_IFDIR)
542 register_proc_table(table->child, de);
547 * Unregister a /proc sysctl table and any subdirectories.
549 static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root)
551 struct proc_dir_entry *de;
552 for (; table->ctl_name; table++) {
553 if (!(de = table->de))
554 continue;
555 if (de->mode & S_IFDIR) {
556 if (!table->child) {
557 printk (KERN_ALERT "Help - malformed sysctl tree on free\n");
558 continue;
560 unregister_proc_table(table->child, de);
562 /* Don't unregister directories which still have entries.. */
563 if (de->subdir)
564 continue;
567 /* Don't unregister proc entries that are still being used.. */
568 if (de->count)
569 continue;
571 table->de = NULL;
572 remove_proc_entry(table->procname, root);
576 static ssize_t do_rw_proc(int write, struct file * file, char * buf,
577 size_t count, loff_t *ppos)
579 int op;
580 struct proc_dir_entry *de;
581 struct ctl_table *table;
582 size_t res;
583 ssize_t error;
585 de = (struct proc_dir_entry*) file->f_dentry->d_inode->u.generic_ip;
586 if (!de || !de->data)
587 return -ENOTDIR;
588 table = (struct ctl_table *) de->data;
589 if (!table || !table->proc_handler)
590 return -ENOTDIR;
591 op = (write ? 002 : 004);
592 if (ctl_perm(table, op))
593 return -EPERM;
595 res = count;
598 * FIXME: we need to pass on ppos to the handler.
601 error = (*table->proc_handler) (table, write, file, buf, &res);
602 if (error)
603 return error;
604 return res;
607 static ssize_t proc_readsys(struct file * file, char * buf,
608 size_t count, loff_t *ppos)
610 return do_rw_proc(0, file, buf, count, ppos);
613 static ssize_t proc_writesys(struct file * file, const char * buf,
614 size_t count, loff_t *ppos)
616 return do_rw_proc(1, file, (char *) buf, count, ppos);
619 static int proc_sys_permission(struct inode *inode, int op)
621 return test_perm(inode->i_mode, op);
624 int proc_dostring(ctl_table *table, int write, struct file *filp,
625 void *buffer, size_t *lenp)
627 int len;
628 char *p, c;
630 if (!table->data || !table->maxlen || !*lenp ||
631 (filp->f_pos && !write)) {
632 *lenp = 0;
633 return 0;
636 if (write) {
637 len = 0;
638 p = buffer;
639 while (len < *lenp) {
640 if(get_user(c, p++))
641 return -EFAULT;
642 if (c == 0 || c == '\n')
643 break;
644 len++;
646 if (len >= table->maxlen)
647 len = table->maxlen-1;
648 if(copy_from_user(table->data, buffer, len))
649 return -EFAULT;
650 ((char *) table->data)[len] = 0;
651 filp->f_pos += *lenp;
652 } else {
653 len = strlen(table->data);
654 if (len > table->maxlen)
655 len = table->maxlen;
656 if (len > *lenp)
657 len = *lenp;
658 if (len)
659 if(copy_to_user(buffer, table->data, len))
660 return -EFAULT;
661 if (len < *lenp) {
662 if(put_user('\n', ((char *) buffer) + len))
663 return -EFAULT;
664 len++;
666 *lenp = len;
667 filp->f_pos += len;
669 return 0;
673 * Special case of dostring for the UTS structure. This has locks
674 * to observe. Should this be in kernel/sys.c ????
677 static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
678 void *buffer, size_t *lenp)
680 int r;
682 if (!write) {
683 down_read(&uts_sem);
684 r=proc_dostring(table,0,filp,buffer,lenp);
685 up_read(&uts_sem);
686 } else {
687 down_write(&uts_sem);
688 r=proc_dostring(table,1,filp,buffer,lenp);
689 up_write(&uts_sem);
691 return r;
694 #define OP_SET 0
695 #define OP_AND 1
696 #define OP_OR 2
697 #define OP_MAX 3
698 #define OP_MIN 4
700 static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
701 void *buffer, size_t *lenp, int conv, int op)
703 int *i, vleft, first=1, len, left, neg, val;
704 #define TMPBUFLEN 20
705 char buf[TMPBUFLEN], *p;
707 if (!table->data || !table->maxlen || !*lenp ||
708 (filp->f_pos && !write)) {
709 *lenp = 0;
710 return 0;
713 i = (int *) table->data;
714 vleft = table->maxlen / sizeof(int);
715 left = *lenp;
717 for (; left && vleft--; i++, first=0) {
718 if (write) {
719 while (left) {
720 char c;
721 if(get_user(c,(char *) buffer))
722 return -EFAULT;
723 if (!isspace(c))
724 break;
725 left--;
726 ((char *) buffer)++;
728 if (!left)
729 break;
730 neg = 0;
731 len = left;
732 if (len > TMPBUFLEN-1)
733 len = TMPBUFLEN-1;
734 if(copy_from_user(buf, buffer, len))
735 return -EFAULT;
736 buf[len] = 0;
737 p = buf;
738 if (*p == '-' && left > 1) {
739 neg = 1;
740 left--, p++;
742 if (*p < '0' || *p > '9')
743 break;
744 val = simple_strtoul(p, &p, 0) * conv;
745 len = p-buf;
746 if ((len < left) && *p && !isspace(*p))
747 break;
748 if (neg)
749 val = -val;
750 buffer += len;
751 left -= len;
752 switch(op) {
753 case OP_SET: *i = val; break;
754 case OP_AND: *i &= val; break;
755 case OP_OR: *i |= val; break;
756 case OP_MAX: if(*i < val)
757 *i = val;
758 break;
759 case OP_MIN: if(*i > val)
760 *i = val;
761 break;
763 } else {
764 p = buf;
765 if (!first)
766 *p++ = '\t';
767 sprintf(p, "%d", (*i) / conv);
768 len = strlen(buf);
769 if (len > left)
770 len = left;
771 if(copy_to_user(buffer, buf, len))
772 return -EFAULT;
773 left -= len;
774 buffer += len;
778 if (!write && !first && left) {
779 if(put_user('\n', (char *) buffer))
780 return -EFAULT;
781 left--, buffer++;
783 if (write) {
784 p = (char *) buffer;
785 while (left) {
786 char c;
787 if(get_user(c, p++))
788 return -EFAULT;
789 if (!isspace(c))
790 break;
791 left--;
794 if (write && first)
795 return -EINVAL;
796 *lenp -= left;
797 filp->f_pos += *lenp;
798 return 0;
801 int proc_dointvec(ctl_table *table, int write, struct file *filp,
802 void *buffer, size_t *lenp)
804 return do_proc_dointvec(table,write,filp,buffer,lenp,1,OP_SET);
808 * init may raise the set.
811 int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
812 void *buffer, size_t *lenp)
814 if (!capable(CAP_SYS_MODULE)) {
815 return -EPERM;
817 return do_proc_dointvec(table,write,filp,buffer,lenp,1,
818 (current->pid == 1) ? OP_SET : OP_AND);
821 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
822 void *buffer, size_t *lenp)
824 int *i, *min, *max, vleft, first=1, len, left, neg, val;
825 #define TMPBUFLEN 20
826 char buf[TMPBUFLEN], *p;
828 if (!table->data || !table->maxlen || !*lenp ||
829 (filp->f_pos && !write)) {
830 *lenp = 0;
831 return 0;
834 i = (int *) table->data;
835 min = (int *) table->extra1;
836 max = (int *) table->extra2;
837 vleft = table->maxlen / sizeof(int);
838 left = *lenp;
840 for (; left && vleft--; i++, first=0) {
841 if (write) {
842 while (left) {
843 char c;
844 if(get_user(c, (char *) buffer))
845 return -EFAULT;
846 if (!isspace(c))
847 break;
848 left--;
849 ((char *) buffer)++;
851 if (!left)
852 break;
853 neg = 0;
854 len = left;
855 if (len > TMPBUFLEN-1)
856 len = TMPBUFLEN-1;
857 if(copy_from_user(buf, buffer, len))
858 return -EFAULT;
859 buf[len] = 0;
860 p = buf;
861 if (*p == '-' && left > 1) {
862 neg = 1;
863 left--, p++;
865 if (*p < '0' || *p > '9')
866 break;
867 val = simple_strtoul(p, &p, 0);
868 len = p-buf;
869 if ((len < left) && *p && !isspace(*p))
870 break;
871 if (neg)
872 val = -val;
873 buffer += len;
874 left -= len;
876 if (min && val < *min++)
877 continue;
878 if (max && val > *max++)
879 continue;
880 *i = val;
881 } else {
882 p = buf;
883 if (!first)
884 *p++ = '\t';
885 sprintf(p, "%d", *i);
886 len = strlen(buf);
887 if (len > left)
888 len = left;
889 if(copy_to_user(buffer, buf, len))
890 return -EFAULT;
891 left -= len;
892 buffer += len;
896 if (!write && !first && left) {
897 if(put_user('\n', (char *) buffer))
898 return -EFAULT;
899 left--, buffer++;
901 if (write) {
902 p = (char *) buffer;
903 while (left) {
904 char c;
905 if(get_user(c, p++))
906 return -EFAULT;
907 if (!isspace(c))
908 break;
909 left--;
912 if (write && first)
913 return -EINVAL;
914 *lenp -= left;
915 filp->f_pos += *lenp;
916 return 0;
920 * an unsigned long function version
923 static int do_proc_doulongvec_minmax(ctl_table *table, int write,
924 struct file *filp,
925 void *buffer, size_t *lenp,
926 unsigned long convmul,
927 unsigned long convdiv)
929 #define TMPBUFLEN 20
930 unsigned long *i, *min, *max, val;
931 int vleft, first=1, len, left, neg;
932 char buf[TMPBUFLEN], *p;
934 if (!table->data || !table->maxlen || !*lenp ||
935 (filp->f_pos && !write)) {
936 *lenp = 0;
937 return 0;
940 i = (unsigned long *) table->data;
941 min = (unsigned long *) table->extra1;
942 max = (unsigned long *) table->extra2;
943 vleft = table->maxlen / sizeof(unsigned long);
944 left = *lenp;
946 for (; left && vleft--; i++, first=0) {
947 if (write) {
948 while (left) {
949 char c;
950 if(get_user(c, (char *) buffer))
951 return -EFAULT;
952 if (!isspace(c))
953 break;
954 left--;
955 ((char *) buffer)++;
957 if (!left)
958 break;
959 neg = 0;
960 len = left;
961 if (len > TMPBUFLEN-1)
962 len = TMPBUFLEN-1;
963 if(copy_from_user(buf, buffer, len))
964 return -EFAULT;
965 buf[len] = 0;
966 p = buf;
967 if (*p == '-' && left > 1) {
968 neg = 1;
969 left--, p++;
971 if (*p < '0' || *p > '9')
972 break;
973 val = simple_strtoul(p, &p, 0) * convmul / convdiv ;
974 len = p-buf;
975 if ((len < left) && *p && !isspace(*p))
976 break;
977 if (neg)
978 val = -val;
979 buffer += len;
980 left -= len;
982 if(neg)
983 continue;
984 if (min && val < *min++)
985 continue;
986 if (max && val > *max++)
987 continue;
988 *i = val;
989 } else {
990 p = buf;
991 if (!first)
992 *p++ = '\t';
993 sprintf(p, "%lu", convdiv * (*i) / convmul);
994 len = strlen(buf);
995 if (len > left)
996 len = left;
997 if(copy_to_user(buffer, buf, len))
998 return -EFAULT;
999 left -= len;
1000 buffer += len;
1004 if (!write && !first && left) {
1005 if(put_user('\n', (char *) buffer))
1006 return -EFAULT;
1007 left--, buffer++;
1009 if (write) {
1010 p = (char *) buffer;
1011 while (left) {
1012 char c;
1013 if(get_user(c, p++))
1014 return -EFAULT;
1015 if (!isspace(c))
1016 break;
1017 left--;
1020 if (write && first)
1021 return -EINVAL;
1022 *lenp -= left;
1023 filp->f_pos += *lenp;
1024 return 0;
1025 #undef TMPBUFLEN
1028 int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
1029 void *buffer, size_t *lenp)
1031 return do_proc_doulongvec_minmax(table, write, filp, buffer, lenp, 1l, 1l);
1034 int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
1035 struct file *filp,
1036 void *buffer, size_t *lenp)
1038 return do_proc_doulongvec_minmax(table, write, filp, buffer,
1039 lenp, HZ, 1000l);
1043 /* Like proc_dointvec, but converts seconds to jiffies */
1044 int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1045 void *buffer, size_t *lenp)
1047 return do_proc_dointvec(table,write,filp,buffer,lenp,HZ,OP_SET);
1050 #else /* CONFIG_PROC_FS */
1052 int proc_dostring(ctl_table *table, int write, struct file *filp,
1053 void *buffer, size_t *lenp)
1055 return -ENOSYS;
1058 static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
1059 void *buffer, size_t *lenp)
1061 return -ENOSYS;
1064 int proc_dointvec(ctl_table *table, int write, struct file *filp,
1065 void *buffer, size_t *lenp)
1067 return -ENOSYS;
1070 int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
1071 void *buffer, size_t *lenp)
1073 return -ENOSYS;
1076 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
1077 void *buffer, size_t *lenp)
1079 return -ENOSYS;
1082 int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1083 void *buffer, size_t *lenp)
1085 return -ENOSYS;
1088 int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
1089 void *buffer, size_t *lenp)
1091 return -ENOSYS;
1094 int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
1095 struct file *filp,
1096 void *buffer, size_t *lenp)
1098 return -ENOSYS;
1102 #endif /* CONFIG_PROC_FS */
1106 * General sysctl support routines
1109 /* The generic string strategy routine: */
1110 int sysctl_string(ctl_table *table, int *name, int nlen,
1111 void *oldval, size_t *oldlenp,
1112 void *newval, size_t newlen, void **context)
1114 int l, len;
1116 if (!table->data || !table->maxlen)
1117 return -ENOTDIR;
1119 if (oldval && oldlenp) {
1120 if(get_user(len, oldlenp))
1121 return -EFAULT;
1122 if (len) {
1123 l = strlen(table->data);
1124 if (len > l) len = l;
1125 if (len >= table->maxlen)
1126 len = table->maxlen;
1127 if(copy_to_user(oldval, table->data, len))
1128 return -EFAULT;
1129 if(put_user(0, ((char *) oldval) + len))
1130 return -EFAULT;
1131 if(put_user(len, oldlenp))
1132 return -EFAULT;
1135 if (newval && newlen) {
1136 len = newlen;
1137 if (len > table->maxlen)
1138 len = table->maxlen;
1139 if(copy_from_user(table->data, newval, len))
1140 return -EFAULT;
1141 if (len == table->maxlen)
1142 len--;
1143 ((char *) table->data)[len] = 0;
1145 return 0;
1149 * This function makes sure that all of the integers in the vector
1150 * are between the minimum and maximum values given in the arrays
1151 * table->extra1 and table->extra2, respectively.
1153 int sysctl_intvec(ctl_table *table, int *name, int nlen,
1154 void *oldval, size_t *oldlenp,
1155 void *newval, size_t newlen, void **context)
1157 int i, length, *vec, *min, *max;
1159 if (newval && newlen) {
1160 if (newlen % sizeof(int) != 0)
1161 return -EINVAL;
1163 if (!table->extra1 && !table->extra2)
1164 return 0;
1166 if (newlen > table->maxlen)
1167 newlen = table->maxlen;
1168 length = newlen / sizeof(int);
1170 vec = (int *) newval;
1171 min = (int *) table->extra1;
1172 max = (int *) table->extra2;
1174 for (i = 0; i < length; i++) {
1175 int value;
1176 get_user(value, vec + i);
1177 if (min && value < min[i])
1178 return -EINVAL;
1179 if (max && value > max[i])
1180 return -EINVAL;
1183 return 0;
1186 /* Strategy function to convert jiffies to seconds */
1187 int sysctl_jiffies(ctl_table *table, int *name, int nlen,
1188 void *oldval, size_t *oldlenp,
1189 void *newval, size_t newlen, void **context)
1191 if (oldval) {
1192 size_t olen;
1193 if (oldlenp) {
1194 if (get_user(olen, oldlenp))
1195 return -EFAULT;
1196 if (olen!=sizeof(int))
1197 return -EINVAL;
1199 if (put_user(*(int *)(table->data) / HZ, (int *)oldval) ||
1200 (oldlenp && put_user(sizeof(int),oldlenp)))
1201 return -EFAULT;
1203 if (newval && newlen) {
1204 int new;
1205 if (newlen != sizeof(int))
1206 return -EINVAL;
1207 if (get_user(new, (int *)newval))
1208 return -EFAULT;
1209 *(int *)(table->data) = new*HZ;
1211 return 1;
1214 int do_string (
1215 void *oldval, size_t *oldlenp, void *newval, size_t newlen,
1216 int rdwr, char *data, size_t max)
1218 int l = strlen(data) + 1;
1219 if (newval && !rdwr)
1220 return -EPERM;
1221 if (newval && newlen >= max)
1222 return -EINVAL;
1223 if (oldval) {
1224 int old_l;
1225 if(get_user(old_l, oldlenp))
1226 return -EFAULT;
1227 if (l > old_l)
1228 return -ENOMEM;
1229 if(put_user(l, oldlenp) || copy_to_user(oldval, data, l))
1230 return -EFAULT;
1232 if (newval) {
1233 if(copy_from_user(data, newval, newlen))
1234 return -EFAULT;
1235 data[newlen] = 0;
1237 return 0;
1240 int do_int (
1241 void *oldval, size_t *oldlenp, void *newval, size_t newlen,
1242 int rdwr, int *data)
1244 if (newval && !rdwr)
1245 return -EPERM;
1246 if (newval && newlen != sizeof(int))
1247 return -EINVAL;
1248 if (oldval) {
1249 int old_l;
1250 if(get_user(old_l, oldlenp))
1251 return -EFAULT;
1252 if (old_l < sizeof(int))
1253 return -ENOMEM;
1254 if(put_user(sizeof(int), oldlenp)||copy_to_user(oldval, data, sizeof(int)))
1255 return -EFAULT;
1257 if (newval)
1258 if(copy_from_user(data, newval, sizeof(int)))
1259 return -EFAULT;
1260 return 0;
1263 int do_struct (
1264 void *oldval, size_t *oldlenp, void *newval, size_t newlen,
1265 int rdwr, void *data, size_t len)
1267 if (newval && !rdwr)
1268 return -EPERM;
1269 if (newval && newlen != len)
1270 return -EINVAL;
1271 if (oldval) {
1272 int old_l;
1273 if(get_user(old_l, oldlenp))
1274 return -EFAULT;
1275 if (old_l < len)
1276 return -ENOMEM;
1277 if(put_user(len, oldlenp) || copy_to_user(oldval, data, len))
1278 return -EFAULT;
1280 if (newval)
1281 if(copy_from_user(data, newval, len))
1282 return -EFAULT;
1283 return 0;
1287 #else /* CONFIG_SYSCTL */
1290 extern asmlinkage long sys_sysctl(struct __sysctl_args *args)
1292 return -ENOSYS;
1295 int sysctl_string(ctl_table *table, int *name, int nlen,
1296 void *oldval, size_t *oldlenp,
1297 void *newval, size_t newlen, void **context)
1299 return -ENOSYS;
1302 int sysctl_intvec(ctl_table *table, int *name, int nlen,
1303 void *oldval, size_t *oldlenp,
1304 void *newval, size_t newlen, void **context)
1306 return -ENOSYS;
1309 int proc_dostring(ctl_table *table, int write, struct file *filp,
1310 void *buffer, size_t *lenp)
1312 return -ENOSYS;
1315 int proc_dointvec(ctl_table *table, int write, struct file *filp,
1316 void *buffer, size_t *lenp)
1318 return -ENOSYS;
1321 int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
1322 void *buffer, size_t *lenp)
1324 return -ENOSYS;
1327 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
1328 void *buffer, size_t *lenp)
1330 return -ENOSYS;
1333 int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1334 void *buffer, size_t *lenp)
1336 return -ENOSYS;
1339 int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
1340 void *buffer, size_t *lenp)
1342 return -ENOSYS;
1345 int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
1346 struct file *filp,
1347 void *buffer, size_t *lenp)
1349 return -ENOSYS;
1352 struct ctl_table_header * register_sysctl_table(ctl_table * table,
1353 int insert_at_head)
1355 return 0;
1358 void unregister_sysctl_table(struct ctl_table_header * table)
1362 #endif /* CONFIG_SYSCTL */