Import 2.3.99pre10-1
[davej-history.git] / kernel / sysctl.c
blob4dd683997311ec04af8afd5e2b9de34cd03b5086
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;
50 /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
51 static int maxolduid = 65535;
52 static int minolduid;
54 #ifdef CONFIG_KMOD
55 extern char modprobe_path[];
56 #endif
57 #ifdef CONFIG_CHR_DEV_SG
58 extern int sg_big_buff;
59 #endif
60 #ifdef CONFIG_SYSVIPC
61 extern size_t shm_ctlmax;
62 extern int msg_ctlmax;
63 extern int msg_ctlmnb;
64 extern int msg_ctlmni;
65 extern int sem_ctls[];
66 #endif
68 #ifdef __sparc__
69 extern char reboot_command [];
70 extern int stop_a_enabled;
71 #endif
72 #ifdef __powerpc__
73 extern unsigned long htab_reclaim_on, zero_paged_on, powersave_nap;
74 int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
75 void *buffer, size_t *lenp);
76 #endif
78 #ifdef CONFIG_BSD_PROCESS_ACCT
79 extern int acct_parm[];
80 #endif
82 extern int pgt_cache_water[];
84 static int parse_table(int *, int, void *, size_t *, void *, size_t,
85 ctl_table *, void **);
86 static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
87 void *buffer, size_t *lenp);
89 static ctl_table root_table[];
90 static struct ctl_table_header root_table_header =
91 { root_table, LIST_HEAD_INIT(root_table_header.ctl_entry) };
93 static ctl_table kern_table[];
94 static ctl_table vm_table[];
95 #ifdef CONFIG_NET
96 extern ctl_table net_table[];
97 #endif
98 static ctl_table proc_table[];
99 static ctl_table fs_table[];
100 static ctl_table debug_table[];
101 static ctl_table dev_table[];
102 extern ctl_table random_table[];
104 /* /proc declarations: */
106 #ifdef CONFIG_PROC_FS
108 static ssize_t proc_readsys(struct file *, char *, size_t, loff_t *);
109 static ssize_t proc_writesys(struct file *, const char *, size_t, loff_t *);
110 static int proc_sys_permission(struct inode *, int);
112 struct file_operations proc_sys_file_operations = {
113 read: proc_readsys,
114 write: proc_writesys,
117 static struct inode_operations proc_sys_inode_operations = {
118 permission: proc_sys_permission,
121 extern struct proc_dir_entry *proc_sys_root;
123 static void register_proc_table(ctl_table *, struct proc_dir_entry *);
124 static void unregister_proc_table(ctl_table *, struct proc_dir_entry *);
125 #endif
127 extern int inodes_stat[];
128 extern int dentry_stat[];
130 /* The default sysctl tables: */
132 static ctl_table root_table[] = {
133 {CTL_KERN, "kernel", NULL, 0, 0555, kern_table},
134 {CTL_VM, "vm", NULL, 0, 0555, vm_table},
135 #ifdef CONFIG_NET
136 {CTL_NET, "net", NULL, 0, 0555, net_table},
137 #endif
138 {CTL_PROC, "proc", NULL, 0, 0555, proc_table},
139 {CTL_FS, "fs", NULL, 0, 0555, fs_table},
140 {CTL_DEBUG, "debug", NULL, 0, 0555, debug_table},
141 {CTL_DEV, "dev", NULL, 0, 0555, dev_table},
145 static ctl_table kern_table[] = {
146 {KERN_OSTYPE, "ostype", system_utsname.sysname, 64,
147 0444, NULL, &proc_doutsstring, &sysctl_string},
148 {KERN_OSRELEASE, "osrelease", system_utsname.release, 64,
149 0444, NULL, &proc_doutsstring, &sysctl_string},
150 {KERN_VERSION, "version", system_utsname.version, 64,
151 0444, NULL, &proc_doutsstring, &sysctl_string},
152 {KERN_NODENAME, "hostname", system_utsname.nodename, 64,
153 0644, NULL, &proc_doutsstring, &sysctl_string},
154 {KERN_DOMAINNAME, "domainname", system_utsname.domainname, 64,
155 0644, NULL, &proc_doutsstring, &sysctl_string},
156 {KERN_PANIC, "panic", &panic_timeout, sizeof(int),
157 0644, NULL, &proc_dointvec},
158 {KERN_CAP_BSET, "cap-bound", &cap_bset, sizeof(kernel_cap_t),
159 0600, NULL, &proc_dointvec_bset},
160 #ifdef CONFIG_BLK_DEV_INITRD
161 {KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(int),
162 0644, NULL, &proc_dointvec},
163 #endif
164 #ifdef __sparc__
165 {KERN_SPARC_REBOOT, "reboot-cmd", reboot_command,
166 256, 0644, NULL, &proc_dostring, &sysctl_string },
167 {KERN_SPARC_STOP_A, "stop-a", &stop_a_enabled, sizeof (int),
168 0644, NULL, &proc_dointvec},
169 #endif
170 #ifdef __powerpc__
171 {KERN_PPC_HTABRECLAIM, "htab-reclaim", &htab_reclaim_on, sizeof(int),
172 0644, NULL, &proc_dointvec},
173 {KERN_PPC_ZEROPAGED, "zero-paged", &zero_paged_on, sizeof(int),
174 0644, NULL, &proc_dointvec},
175 {KERN_PPC_POWERSAVE_NAP, "powersave-nap", &powersave_nap, sizeof(int),
176 0644, NULL, &proc_dointvec},
177 {KERN_PPC_L2CR, "l2cr", NULL, 0,
178 0644, NULL, &proc_dol2crvec},
179 #endif
180 {KERN_CTLALTDEL, "ctrl-alt-del", &C_A_D, sizeof(int),
181 0644, NULL, &proc_dointvec},
182 {KERN_PRINTK, "printk", &console_loglevel, 4*sizeof(int),
183 0644, NULL, &proc_dointvec},
184 #ifdef CONFIG_KMOD
185 {KERN_MODPROBE, "modprobe", &modprobe_path, 256,
186 0644, NULL, &proc_dostring, &sysctl_string },
187 #endif
188 #ifdef CONFIG_CHR_DEV_SG
189 {KERN_SG_BIG_BUFF, "sg-big-buff", &sg_big_buff, sizeof (int),
190 0444, NULL, &proc_dointvec},
191 #endif
192 #ifdef CONFIG_BSD_PROCESS_ACCT
193 {KERN_ACCT, "acct", &acct_parm, 3*sizeof(int),
194 0644, NULL, &proc_dointvec},
195 #endif
196 {KERN_RTSIGNR, "rtsig-nr", &nr_queued_signals, sizeof(int),
197 0444, NULL, &proc_dointvec},
198 {KERN_RTSIGMAX, "rtsig-max", &max_queued_signals, sizeof(int),
199 0644, NULL, &proc_dointvec},
200 #ifdef CONFIG_SYSVIPC
201 {KERN_SHMMAX, "shmmax", &shm_ctlmax, sizeof (size_t),
202 0644, NULL, &proc_doulongvec_minmax},
203 {KERN_MSGMAX, "msgmax", &msg_ctlmax, sizeof (int),
204 0644, NULL, &proc_dointvec},
205 {KERN_MSGMNI, "msgmni", &msg_ctlmni, sizeof (int),
206 0644, NULL, &proc_dointvec},
207 {KERN_MSGMNB, "msgmnb", &msg_ctlmnb, sizeof (int),
208 0644, NULL, &proc_dointvec},
209 {KERN_SEM, "sem", &sem_ctls, 4*sizeof (int),
210 0644, NULL, &proc_dointvec},
211 #endif
212 #ifdef CONFIG_MAGIC_SYSRQ
213 {KERN_SYSRQ, "sysrq", &sysrq_enabled, sizeof (int),
214 0644, NULL, &proc_dointvec},
215 #endif
216 {KERN_MAX_THREADS, "threads-max", &max_threads, sizeof(int),
217 0644, NULL, &proc_dointvec},
218 {KERN_RANDOM, "random", NULL, 0, 0555, random_table},
219 {KERN_OVERFLOWUID, "overflowuid", &overflowuid, sizeof(int), 0644, NULL,
220 &proc_dointvec_minmax, &sysctl_intvec, NULL,
221 &minolduid, &maxolduid},
222 {KERN_OVERFLOWGID, "overflowgid", &overflowgid, sizeof(int), 0644, NULL,
223 &proc_dointvec_minmax, &sysctl_intvec, NULL,
224 &minolduid, &maxolduid},
228 static ctl_table vm_table[] = {
229 {VM_FREEPG, "freepages",
230 &freepages, sizeof(freepages_t), 0644, NULL, &proc_dointvec},
231 {VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0644, NULL,
232 &proc_dointvec_minmax, &sysctl_intvec, NULL,
233 &bdflush_min, &bdflush_max},
234 {VM_OVERCOMMIT_MEMORY, "overcommit_memory", &sysctl_overcommit_memory,
235 sizeof(sysctl_overcommit_memory), 0644, NULL, &proc_dointvec},
236 {VM_BUFFERMEM, "buffermem",
237 &buffer_mem, sizeof(buffer_mem_t), 0644, NULL, &proc_dointvec},
238 {VM_PAGECACHE, "pagecache",
239 &page_cache, sizeof(buffer_mem_t), 0644, NULL, &proc_dointvec},
240 {VM_PAGERDAEMON, "kswapd",
241 &pager_daemon, sizeof(pager_daemon_t), 0644, NULL, &proc_dointvec},
242 {VM_PGT_CACHE, "pagetable_cache",
243 &pgt_cache_water, 2*sizeof(int), 0644, NULL, &proc_dointvec},
244 {VM_PAGE_CLUSTER, "page-cluster",
245 &page_cluster, sizeof(int), 0644, NULL, &proc_dointvec},
249 static ctl_table proc_table[] = {
253 static ctl_table fs_table[] = {
254 {FS_NRINODE, "inode-nr", &inodes_stat, 2*sizeof(int),
255 0444, NULL, &proc_dointvec},
256 {FS_STATINODE, "inode-state", &inodes_stat, 7*sizeof(int),
257 0444, NULL, &proc_dointvec},
258 {FS_NRFILE, "file-nr", &nr_files, 3*sizeof(int),
259 0444, NULL, &proc_dointvec},
260 {FS_MAXFILE, "file-max", &max_files, sizeof(int),
261 0644, NULL, &proc_dointvec},
262 {FS_NRSUPER, "super-nr", &nr_super_blocks, sizeof(int),
263 0444, NULL, &proc_dointvec},
264 {FS_MAXSUPER, "super-max", &max_super_blocks, sizeof(int),
265 0644, NULL, &proc_dointvec},
266 {FS_NRDQUOT, "dquot-nr", &nr_dquots, 2*sizeof(int),
267 0444, NULL, &proc_dointvec},
268 {FS_MAXDQUOT, "dquot-max", &max_dquots, sizeof(int),
269 0644, NULL, &proc_dointvec},
270 {FS_DENTRY, "dentry-state", &dentry_stat, 6*sizeof(int),
271 0444, NULL, &proc_dointvec},
272 {FS_OVERFLOWUID, "overflowuid", &fs_overflowuid, sizeof(int), 0644, NULL,
273 &proc_dointvec_minmax, &sysctl_intvec, NULL,
274 &minolduid, &maxolduid},
275 {FS_OVERFLOWGID, "overflowgid", &fs_overflowgid, sizeof(int), 0644, NULL,
276 &proc_dointvec_minmax, &sysctl_intvec, NULL,
277 &minolduid, &maxolduid},
281 static ctl_table debug_table[] = {
285 static ctl_table dev_table[] = {
289 extern void init_irq_proc (void);
291 void __init sysctl_init(void)
293 #ifdef CONFIG_PROC_FS
294 register_proc_table(root_table, proc_sys_root);
295 init_irq_proc();
296 #endif
299 int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp,
300 void *newval, size_t newlen)
302 struct list_head *tmp;
304 if (nlen == 0 || nlen >= CTL_MAXNAME)
305 return -ENOTDIR;
306 if (oldval) {
307 int old_len;
308 if (!oldlenp || get_user(old_len, oldlenp))
309 return -EFAULT;
311 tmp = &root_table_header.ctl_entry;
312 do {
313 struct ctl_table_header *head =
314 list_entry(tmp, struct ctl_table_header, ctl_entry);
315 void *context = NULL;
316 int error = parse_table(name, nlen, oldval, oldlenp,
317 newval, newlen, head->ctl_table,
318 &context);
319 if (context)
320 kfree(context);
321 if (error != -ENOTDIR)
322 return error;
323 tmp = tmp->next;
324 } while (tmp != &root_table_header.ctl_entry);
325 return -ENOTDIR;
328 extern asmlinkage long sys_sysctl(struct __sysctl_args *args)
330 struct __sysctl_args tmp;
331 int error;
333 if (copy_from_user(&tmp, args, sizeof(tmp)))
334 return -EFAULT;
336 lock_kernel();
337 error = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp,
338 tmp.newval, tmp.newlen);
339 unlock_kernel();
340 return error;
344 * ctl_perm does NOT grant the superuser all rights automatically, because
345 * some sysctl variables are readonly even to root.
348 static int test_perm(int mode, int op)
350 if (!current->euid)
351 mode >>= 6;
352 else if (in_egroup_p(0))
353 mode >>= 3;
354 if ((mode & op & 0007) == op)
355 return 0;
356 return -EACCES;
359 static inline int ctl_perm(ctl_table *table, int op)
361 return test_perm(table->mode, op);
364 static int parse_table(int *name, int nlen,
365 void *oldval, size_t *oldlenp,
366 void *newval, size_t newlen,
367 ctl_table *table, void **context)
369 int n;
370 repeat:
371 if (!nlen)
372 return -ENOTDIR;
373 if (get_user(n, name))
374 return -EFAULT;
375 for ( ; table->ctl_name; table++) {
376 if (n == table->ctl_name || table->ctl_name == CTL_ANY) {
377 int error;
378 if (table->child) {
379 if (ctl_perm(table, 001))
380 return -EPERM;
381 if (table->strategy) {
382 error = table->strategy(
383 table, name, nlen,
384 oldval, oldlenp,
385 newval, newlen, context);
386 if (error)
387 return error;
389 name++;
390 nlen--;
391 table = table->child;
392 goto repeat;
394 error = do_sysctl_strategy(table, name, nlen,
395 oldval, oldlenp,
396 newval, newlen, context);
397 return error;
400 return -ENOTDIR;
403 /* Perform the actual read/write of a sysctl table entry. */
404 int do_sysctl_strategy (ctl_table *table,
405 int *name, int nlen,
406 void *oldval, size_t *oldlenp,
407 void *newval, size_t newlen, void **context)
409 int op = 0, rc, len;
411 if (oldval)
412 op |= 004;
413 if (newval)
414 op |= 002;
415 if (ctl_perm(table, op))
416 return -EPERM;
418 if (table->strategy) {
419 rc = table->strategy(table, name, nlen, oldval, oldlenp,
420 newval, newlen, context);
421 if (rc < 0)
422 return rc;
423 if (rc > 0)
424 return 0;
427 /* If there is no strategy routine, or if the strategy returns
428 * zero, proceed with automatic r/w */
429 if (table->data && table->maxlen) {
430 if (oldval && oldlenp) {
431 get_user(len, oldlenp);
432 if (len) {
433 if (len > table->maxlen)
434 len = table->maxlen;
435 if(copy_to_user(oldval, table->data, len))
436 return -EFAULT;
437 if(put_user(len, oldlenp))
438 return -EFAULT;
441 if (newval && newlen) {
442 len = newlen;
443 if (len > table->maxlen)
444 len = table->maxlen;
445 if(copy_from_user(table->data, newval, len))
446 return -EFAULT;
449 return 0;
452 struct ctl_table_header *register_sysctl_table(ctl_table * table,
453 int insert_at_head)
455 struct ctl_table_header *tmp;
456 tmp = kmalloc(sizeof(struct ctl_table_header), GFP_KERNEL);
457 if (!tmp)
458 return 0;
459 tmp->ctl_table = table;
460 INIT_LIST_HEAD(&tmp->ctl_entry);
461 if (insert_at_head)
462 list_add(&tmp->ctl_entry, &root_table_header.ctl_entry);
463 else
464 list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry);
465 #ifdef CONFIG_PROC_FS
466 register_proc_table(table, proc_sys_root);
467 #endif
468 return tmp;
472 * Unlink and free a ctl_table.
474 void unregister_sysctl_table(struct ctl_table_header * header)
476 list_del(&header->ctl_entry);
477 #ifdef CONFIG_PROC_FS
478 unregister_proc_table(header->ctl_table, proc_sys_root);
479 #endif
480 kfree(header);
484 * /proc/sys support
487 #ifdef CONFIG_PROC_FS
489 /* Scan the sysctl entries in table and add them all into /proc */
490 static void register_proc_table(ctl_table * table, struct proc_dir_entry *root)
492 struct proc_dir_entry *de;
493 int len;
494 mode_t mode;
496 for (; table->ctl_name; table++) {
497 /* Can't do anything without a proc name. */
498 if (!table->procname)
499 continue;
500 /* Maybe we can't do anything with it... */
501 if (!table->proc_handler && !table->child) {
502 printk(KERN_WARNING "SYSCTL: Can't register %s\n",
503 table->procname);
504 continue;
507 len = strlen(table->procname);
508 mode = table->mode;
510 de = NULL;
511 if (table->proc_handler)
512 mode |= S_IFREG;
513 else {
514 mode |= S_IFDIR;
515 for (de = root->subdir; de; de = de->next) {
516 if (proc_match(len, table->procname, de))
517 break;
519 /* If the subdir exists already, de is non-NULL */
522 if (!de) {
523 de = create_proc_entry(table->procname, mode, root);
524 if (!de)
525 continue;
526 de->data = (void *) table;
527 if (table->proc_handler) {
528 de->proc_fops = &proc_sys_file_operations;
529 de->proc_iops = &proc_sys_inode_operations;
532 table->de = de;
533 if (de->mode & S_IFDIR)
534 register_proc_table(table->child, de);
539 * Unregister a /proc sysctl table and any subdirectories.
541 static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root)
543 struct proc_dir_entry *de;
544 for (; table->ctl_name; table++) {
545 if (!(de = table->de))
546 continue;
547 if (de->mode & S_IFDIR) {
548 if (!table->child) {
549 printk (KERN_ALERT "Help - malformed sysctl tree on free\n");
550 continue;
552 unregister_proc_table(table->child, de);
554 /* Don't unregister directories which still have entries.. */
555 if (de->subdir)
556 continue;
559 /* Don't unregister proc entries that are still being used.. */
560 if (de->count)
561 continue;
563 table->de = NULL;
564 remove_proc_entry(table->procname, root);
568 static ssize_t do_rw_proc(int write, struct file * file, char * buf,
569 size_t count, loff_t *ppos)
571 int op;
572 struct proc_dir_entry *de;
573 struct ctl_table *table;
574 size_t res;
575 ssize_t error;
577 de = (struct proc_dir_entry*) file->f_dentry->d_inode->u.generic_ip;
578 if (!de || !de->data)
579 return -ENOTDIR;
580 table = (struct ctl_table *) de->data;
581 if (!table || !table->proc_handler)
582 return -ENOTDIR;
583 op = (write ? 002 : 004);
584 if (ctl_perm(table, op))
585 return -EPERM;
587 res = count;
590 * FIXME: we need to pass on ppos to the handler.
593 error = (*table->proc_handler) (table, write, file, buf, &res);
594 if (error)
595 return error;
596 return res;
599 static ssize_t proc_readsys(struct file * file, char * buf,
600 size_t count, loff_t *ppos)
602 return do_rw_proc(0, file, buf, count, ppos);
605 static ssize_t proc_writesys(struct file * file, const char * buf,
606 size_t count, loff_t *ppos)
608 return do_rw_proc(1, file, (char *) buf, count, ppos);
611 static int proc_sys_permission(struct inode *inode, int op)
613 return test_perm(inode->i_mode, op);
616 int proc_dostring(ctl_table *table, int write, struct file *filp,
617 void *buffer, size_t *lenp)
619 int len;
620 char *p, c;
622 if (!table->data || !table->maxlen || !*lenp ||
623 (filp->f_pos && !write)) {
624 *lenp = 0;
625 return 0;
628 if (write) {
629 len = 0;
630 p = buffer;
631 while (len < *lenp) {
632 if(get_user(c, p++))
633 return -EFAULT;
634 if (c == 0 || c == '\n')
635 break;
636 len++;
638 if (len >= table->maxlen)
639 len = table->maxlen-1;
640 if(copy_from_user(table->data, buffer, len))
641 return -EFAULT;
642 ((char *) table->data)[len] = 0;
643 filp->f_pos += *lenp;
644 } else {
645 len = strlen(table->data);
646 if (len > table->maxlen)
647 len = table->maxlen;
648 if (len > *lenp)
649 len = *lenp;
650 if (len)
651 if(copy_to_user(buffer, table->data, len))
652 return -EFAULT;
653 if (len < *lenp) {
654 if(put_user('\n', ((char *) buffer) + len))
655 return -EFAULT;
656 len++;
658 *lenp = len;
659 filp->f_pos += len;
661 return 0;
665 * Special case of dostring for the UTS structure. This has locks
666 * to observe. Should this be in kernel/sys.c ????
669 static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
670 void *buffer, size_t *lenp)
672 int r;
674 if (!write) {
675 down_read(&uts_sem);
676 r=proc_dostring(table,0,filp,buffer,lenp);
677 up_read(&uts_sem);
678 } else {
679 down_write(&uts_sem);
680 r=proc_dostring(table,1,filp,buffer,lenp);
681 up_write(&uts_sem);
683 return r;
686 #define OP_SET 0
687 #define OP_AND 1
688 #define OP_OR 2
689 #define OP_MAX 3
690 #define OP_MIN 4
692 static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
693 void *buffer, size_t *lenp, int conv, int op)
695 int *i, vleft, first=1, len, left, neg, val;
696 #define TMPBUFLEN 20
697 char buf[TMPBUFLEN], *p;
699 if (!table->data || !table->maxlen || !*lenp ||
700 (filp->f_pos && !write)) {
701 *lenp = 0;
702 return 0;
705 i = (int *) table->data;
706 vleft = table->maxlen / sizeof(int);
707 left = *lenp;
709 for (; left && vleft--; i++, first=0) {
710 if (write) {
711 while (left) {
712 char c;
713 if(get_user(c,(char *) buffer))
714 return -EFAULT;
715 if (!isspace(c))
716 break;
717 left--;
718 ((char *) buffer)++;
720 if (!left)
721 break;
722 neg = 0;
723 len = left;
724 if (len > TMPBUFLEN-1)
725 len = TMPBUFLEN-1;
726 if(copy_from_user(buf, buffer, len))
727 return -EFAULT;
728 buf[len] = 0;
729 p = buf;
730 if (*p == '-' && left > 1) {
731 neg = 1;
732 left--, p++;
734 if (*p < '0' || *p > '9')
735 break;
736 val = simple_strtoul(p, &p, 0) * conv;
737 len = p-buf;
738 if ((len < left) && *p && !isspace(*p))
739 break;
740 if (neg)
741 val = -val;
742 buffer += len;
743 left -= len;
744 switch(op) {
745 case OP_SET: *i = val; break;
746 case OP_AND: *i &= val; break;
747 case OP_OR: *i |= val; break;
748 case OP_MAX: if(*i < val)
749 *i = val;
750 break;
751 case OP_MIN: if(*i > val)
752 *i = val;
753 break;
755 } else {
756 p = buf;
757 if (!first)
758 *p++ = '\t';
759 sprintf(p, "%d", (*i) / conv);
760 len = strlen(buf);
761 if (len > left)
762 len = left;
763 if(copy_to_user(buffer, buf, len))
764 return -EFAULT;
765 left -= len;
766 buffer += len;
770 if (!write && !first && left) {
771 if(put_user('\n', (char *) buffer))
772 return -EFAULT;
773 left--, buffer++;
775 if (write) {
776 p = (char *) buffer;
777 while (left) {
778 char c;
779 if(get_user(c, p++))
780 return -EFAULT;
781 if (!isspace(c))
782 break;
783 left--;
786 if (write && first)
787 return -EINVAL;
788 *lenp -= left;
789 filp->f_pos += *lenp;
790 return 0;
793 int proc_dointvec(ctl_table *table, int write, struct file *filp,
794 void *buffer, size_t *lenp)
796 return do_proc_dointvec(table,write,filp,buffer,lenp,1,OP_SET);
800 * init may raise the set.
803 int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
804 void *buffer, size_t *lenp)
806 return do_proc_dointvec(table,write,filp,buffer,lenp,1,
807 (current->pid == 1) ? OP_SET : OP_AND);
810 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
811 void *buffer, size_t *lenp)
813 int *i, *min, *max, vleft, first=1, len, left, neg, val;
814 #define TMPBUFLEN 20
815 char buf[TMPBUFLEN], *p;
817 if (!table->data || !table->maxlen || !*lenp ||
818 (filp->f_pos && !write)) {
819 *lenp = 0;
820 return 0;
823 i = (int *) table->data;
824 min = (int *) table->extra1;
825 max = (int *) table->extra2;
826 vleft = table->maxlen / sizeof(int);
827 left = *lenp;
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)++;
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++;
854 if (*p < '0' || *p > '9')
855 break;
856 val = simple_strtoul(p, &p, 0);
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;
865 if (min && val < *min++)
866 continue;
867 if (max && val > *max++)
868 continue;
869 *i = val;
870 } else {
871 p = buf;
872 if (!first)
873 *p++ = '\t';
874 sprintf(p, "%d", *i);
875 len = strlen(buf);
876 if (len > left)
877 len = left;
878 if(copy_to_user(buffer, buf, len))
879 return -EFAULT;
880 left -= len;
881 buffer += len;
885 if (!write && !first && left) {
886 if(put_user('\n', (char *) buffer))
887 return -EFAULT;
888 left--, buffer++;
890 if (write) {
891 p = (char *) buffer;
892 while (left) {
893 char c;
894 if(get_user(c, p++))
895 return -EFAULT;
896 if (!isspace(c))
897 break;
898 left--;
901 if (write && first)
902 return -EINVAL;
903 *lenp -= left;
904 filp->f_pos += *lenp;
905 return 0;
909 * an unsigned long function version
912 static int do_proc_doulongvec_minmax(ctl_table *table, int write,
913 struct file *filp,
914 void *buffer, size_t *lenp,
915 unsigned long convmul,
916 unsigned long convdiv)
918 #define TMPBUFLEN 20
919 unsigned long *i, *min, *max, val;
920 int vleft, first=1, len, left, neg;
921 char buf[TMPBUFLEN], *p;
923 if (!table->data || !table->maxlen || !*lenp ||
924 (filp->f_pos && !write)) {
925 *lenp = 0;
926 return 0;
929 i = (unsigned long *) table->data;
930 min = (unsigned long *) table->extra1;
931 max = (unsigned long *) table->extra2;
932 vleft = table->maxlen / sizeof(unsigned long);
933 left = *lenp;
935 for (; left && vleft--; i++, first=0) {
936 if (write) {
937 while (left) {
938 char c;
939 if(get_user(c, (char *) buffer))
940 return -EFAULT;
941 if (!isspace(c))
942 break;
943 left--;
944 ((char *) buffer)++;
946 if (!left)
947 break;
948 neg = 0;
949 len = left;
950 if (len > TMPBUFLEN-1)
951 len = TMPBUFLEN-1;
952 if(copy_from_user(buf, buffer, len))
953 return -EFAULT;
954 buf[len] = 0;
955 p = buf;
956 if (*p == '-' && left > 1) {
957 neg = 1;
958 left--, p++;
960 if (*p < '0' || *p > '9')
961 break;
962 val = simple_strtoul(p, &p, 0) * convmul / convdiv ;
963 len = p-buf;
964 if ((len < left) && *p && !isspace(*p))
965 break;
966 if (neg)
967 val = -val;
968 buffer += len;
969 left -= len;
971 if(neg)
972 continue;
973 if (min && val < *min++)
974 continue;
975 if (max && val > *max++)
976 continue;
977 *i = val;
978 } else {
979 p = buf;
980 if (!first)
981 *p++ = '\t';
982 sprintf(p, "%lu", convdiv * (*i) / convmul);
983 len = strlen(buf);
984 if (len > left)
985 len = left;
986 if(copy_to_user(buffer, buf, len))
987 return -EFAULT;
988 left -= len;
989 buffer += len;
993 if (!write && !first && left) {
994 if(put_user('\n', (char *) buffer))
995 return -EFAULT;
996 left--, buffer++;
998 if (write) {
999 p = (char *) buffer;
1000 while (left) {
1001 char c;
1002 if(get_user(c, p++))
1003 return -EFAULT;
1004 if (!isspace(c))
1005 break;
1006 left--;
1009 if (write && first)
1010 return -EINVAL;
1011 *lenp -= left;
1012 filp->f_pos += *lenp;
1013 return 0;
1014 #undef TMPBUFLEN
1017 int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
1018 void *buffer, size_t *lenp)
1020 return do_proc_doulongvec_minmax(table, write, filp, buffer, lenp, 1l, 1l);
1023 int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
1024 struct file *filp,
1025 void *buffer, size_t *lenp)
1027 return do_proc_doulongvec_minmax(table, write, filp, buffer,
1028 lenp, HZ, 1000l);
1032 /* Like proc_dointvec, but converts seconds to jiffies */
1033 int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1034 void *buffer, size_t *lenp)
1036 return do_proc_dointvec(table,write,filp,buffer,lenp,HZ,OP_SET);
1039 #else /* CONFIG_PROC_FS */
1041 int proc_dostring(ctl_table *table, int write, struct file *filp,
1042 void *buffer, size_t *lenp)
1044 return -ENOSYS;
1047 static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
1048 void *buffer, size_t *lenp)
1050 return -ENOSYS;
1053 int proc_dointvec(ctl_table *table, int write, struct file *filp,
1054 void *buffer, size_t *lenp)
1056 return -ENOSYS;
1059 int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
1060 void *buffer, size_t *lenp)
1062 return -ENOSYS;
1065 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
1066 void *buffer, size_t *lenp)
1068 return -ENOSYS;
1071 int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1072 void *buffer, size_t *lenp)
1074 return -ENOSYS;
1077 int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
1078 void *buffer, size_t *lenp)
1080 return -ENOSYS;
1083 int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
1084 struct file *filp,
1085 void *buffer, size_t *lenp)
1087 return -ENOSYS;
1091 #endif /* CONFIG_PROC_FS */
1095 * General sysctl support routines
1098 /* The generic string strategy routine: */
1099 int sysctl_string(ctl_table *table, int *name, int nlen,
1100 void *oldval, size_t *oldlenp,
1101 void *newval, size_t newlen, void **context)
1103 int l, len;
1105 if (!table->data || !table->maxlen)
1106 return -ENOTDIR;
1108 if (oldval && oldlenp) {
1109 if(get_user(len, oldlenp))
1110 return -EFAULT;
1111 if (len) {
1112 l = strlen(table->data);
1113 if (len > l) len = l;
1114 if (len >= table->maxlen)
1115 len = table->maxlen;
1116 if(copy_to_user(oldval, table->data, len))
1117 return -EFAULT;
1118 if(put_user(0, ((char *) oldval) + len))
1119 return -EFAULT;
1120 if(put_user(len, oldlenp))
1121 return -EFAULT;
1124 if (newval && newlen) {
1125 len = newlen;
1126 if (len > table->maxlen)
1127 len = table->maxlen;
1128 if(copy_from_user(table->data, newval, len))
1129 return -EFAULT;
1130 if (len == table->maxlen)
1131 len--;
1132 ((char *) table->data)[len] = 0;
1134 return 0;
1138 * This function makes sure that all of the integers in the vector
1139 * are between the minimum and maximum values given in the arrays
1140 * table->extra1 and table->extra2, respectively.
1142 int sysctl_intvec(ctl_table *table, int *name, int nlen,
1143 void *oldval, size_t *oldlenp,
1144 void *newval, size_t newlen, void **context)
1146 int i, length, *vec, *min, *max;
1148 if (newval && newlen) {
1149 if (newlen % sizeof(int) != 0)
1150 return -EINVAL;
1152 if (!table->extra1 && !table->extra2)
1153 return 0;
1155 if (newlen > table->maxlen)
1156 newlen = table->maxlen;
1157 length = newlen / sizeof(int);
1159 vec = (int *) newval;
1160 min = (int *) table->extra1;
1161 max = (int *) table->extra2;
1163 for (i = 0; i < length; i++) {
1164 int value;
1165 get_user(value, vec + i);
1166 if (min && value < min[i])
1167 return -EINVAL;
1168 if (max && value > max[i])
1169 return -EINVAL;
1172 return 0;
1175 /* Strategy function to convert jiffies to seconds */
1176 int sysctl_jiffies(ctl_table *table, int *name, int nlen,
1177 void *oldval, size_t *oldlenp,
1178 void *newval, size_t newlen, void **context)
1180 if (oldval) {
1181 size_t olen;
1182 if (oldlenp) {
1183 if (get_user(olen, oldlenp))
1184 return -EFAULT;
1185 if (olen!=sizeof(int))
1186 return -EINVAL;
1188 if (put_user(*(int *)(table->data) / HZ, (int *)oldval) ||
1189 (oldlenp && put_user(sizeof(int),oldlenp)))
1190 return -EFAULT;
1192 if (newval && newlen) {
1193 int new;
1194 if (newlen != sizeof(int))
1195 return -EINVAL;
1196 if (get_user(new, (int *)newval))
1197 return -EFAULT;
1198 *(int *)(table->data) = new*HZ;
1200 return 1;
1203 int do_string (
1204 void *oldval, size_t *oldlenp, void *newval, size_t newlen,
1205 int rdwr, char *data, size_t max)
1207 int l = strlen(data) + 1;
1208 if (newval && !rdwr)
1209 return -EPERM;
1210 if (newval && newlen >= max)
1211 return -EINVAL;
1212 if (oldval) {
1213 int old_l;
1214 if(get_user(old_l, oldlenp))
1215 return -EFAULT;
1216 if (l > old_l)
1217 return -ENOMEM;
1218 if(put_user(l, oldlenp) || copy_to_user(oldval, data, l))
1219 return -EFAULT;
1221 if (newval) {
1222 if(copy_from_user(data, newval, newlen))
1223 return -EFAULT;
1224 data[newlen] = 0;
1226 return 0;
1229 int do_int (
1230 void *oldval, size_t *oldlenp, void *newval, size_t newlen,
1231 int rdwr, int *data)
1233 if (newval && !rdwr)
1234 return -EPERM;
1235 if (newval && newlen != sizeof(int))
1236 return -EINVAL;
1237 if (oldval) {
1238 int old_l;
1239 if(get_user(old_l, oldlenp))
1240 return -EFAULT;
1241 if (old_l < sizeof(int))
1242 return -ENOMEM;
1243 if(put_user(sizeof(int), oldlenp)||copy_to_user(oldval, data, sizeof(int)))
1244 return -EFAULT;
1246 if (newval)
1247 if(copy_from_user(data, newval, sizeof(int)))
1248 return -EFAULT;
1249 return 0;
1252 int do_struct (
1253 void *oldval, size_t *oldlenp, void *newval, size_t newlen,
1254 int rdwr, void *data, size_t len)
1256 if (newval && !rdwr)
1257 return -EPERM;
1258 if (newval && newlen != len)
1259 return -EINVAL;
1260 if (oldval) {
1261 int old_l;
1262 if(get_user(old_l, oldlenp))
1263 return -EFAULT;
1264 if (old_l < len)
1265 return -ENOMEM;
1266 if(put_user(len, oldlenp) || copy_to_user(oldval, data, len))
1267 return -EFAULT;
1269 if (newval)
1270 if(copy_from_user(data, newval, len))
1271 return -EFAULT;
1272 return 0;
1276 #else /* CONFIG_SYSCTL */
1279 extern asmlinkage long sys_sysctl(struct __sysctl_args *args)
1281 return -ENOSYS;
1284 int sysctl_string(ctl_table *table, int *name, int nlen,
1285 void *oldval, size_t *oldlenp,
1286 void *newval, size_t newlen, void **context)
1288 return -ENOSYS;
1291 int sysctl_intvec(ctl_table *table, int *name, int nlen,
1292 void *oldval, size_t *oldlenp,
1293 void *newval, size_t newlen, void **context)
1295 return -ENOSYS;
1298 int proc_dostring(ctl_table *table, int write, struct file *filp,
1299 void *buffer, size_t *lenp)
1301 return -ENOSYS;
1304 int proc_dointvec(ctl_table *table, int write, struct file *filp,
1305 void *buffer, size_t *lenp)
1307 return -ENOSYS;
1310 int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
1311 void *buffer, size_t *lenp)
1313 return -ENOSYS;
1316 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
1317 void *buffer, size_t *lenp)
1319 return -ENOSYS;
1322 int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1323 void *buffer, size_t *lenp)
1325 return -ENOSYS;
1328 int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
1329 void *buffer, size_t *lenp)
1331 return -ENOSYS;
1334 int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
1335 struct file *filp,
1336 void *buffer, size_t *lenp)
1338 return -ENOSYS;
1341 struct ctl_table_header * register_sysctl_table(ctl_table * table,
1342 int insert_at_head)
1344 return 0;
1347 void unregister_sysctl_table(struct ctl_table_header * table)
1351 #endif /* CONFIG_SYSCTL */