Linux-2.4.0-test2
[davej-history.git] / kernel / sysctl.c
blob5fc0418f966c0a91c3969d91400d2441723578ee
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 if (!capable(CAP_SYS_MODULE)) {
807 return -EPERM;
809 return do_proc_dointvec(table,write,filp,buffer,lenp,1,
810 (current->pid == 1) ? OP_SET : OP_AND);
813 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
814 void *buffer, size_t *lenp)
816 int *i, *min, *max, vleft, first=1, len, left, neg, val;
817 #define TMPBUFLEN 20
818 char buf[TMPBUFLEN], *p;
820 if (!table->data || !table->maxlen || !*lenp ||
821 (filp->f_pos && !write)) {
822 *lenp = 0;
823 return 0;
826 i = (int *) table->data;
827 min = (int *) table->extra1;
828 max = (int *) table->extra2;
829 vleft = table->maxlen / sizeof(int);
830 left = *lenp;
832 for (; left && vleft--; i++, first=0) {
833 if (write) {
834 while (left) {
835 char c;
836 if(get_user(c, (char *) buffer))
837 return -EFAULT;
838 if (!isspace(c))
839 break;
840 left--;
841 ((char *) buffer)++;
843 if (!left)
844 break;
845 neg = 0;
846 len = left;
847 if (len > TMPBUFLEN-1)
848 len = TMPBUFLEN-1;
849 if(copy_from_user(buf, buffer, len))
850 return -EFAULT;
851 buf[len] = 0;
852 p = buf;
853 if (*p == '-' && left > 1) {
854 neg = 1;
855 left--, p++;
857 if (*p < '0' || *p > '9')
858 break;
859 val = simple_strtoul(p, &p, 0);
860 len = p-buf;
861 if ((len < left) && *p && !isspace(*p))
862 break;
863 if (neg)
864 val = -val;
865 buffer += len;
866 left -= len;
868 if (min && val < *min++)
869 continue;
870 if (max && val > *max++)
871 continue;
872 *i = val;
873 } else {
874 p = buf;
875 if (!first)
876 *p++ = '\t';
877 sprintf(p, "%d", *i);
878 len = strlen(buf);
879 if (len > left)
880 len = left;
881 if(copy_to_user(buffer, buf, len))
882 return -EFAULT;
883 left -= len;
884 buffer += len;
888 if (!write && !first && left) {
889 if(put_user('\n', (char *) buffer))
890 return -EFAULT;
891 left--, buffer++;
893 if (write) {
894 p = (char *) buffer;
895 while (left) {
896 char c;
897 if(get_user(c, p++))
898 return -EFAULT;
899 if (!isspace(c))
900 break;
901 left--;
904 if (write && first)
905 return -EINVAL;
906 *lenp -= left;
907 filp->f_pos += *lenp;
908 return 0;
912 * an unsigned long function version
915 static int do_proc_doulongvec_minmax(ctl_table *table, int write,
916 struct file *filp,
917 void *buffer, size_t *lenp,
918 unsigned long convmul,
919 unsigned long convdiv)
921 #define TMPBUFLEN 20
922 unsigned long *i, *min, *max, val;
923 int vleft, first=1, len, left, neg;
924 char buf[TMPBUFLEN], *p;
926 if (!table->data || !table->maxlen || !*lenp ||
927 (filp->f_pos && !write)) {
928 *lenp = 0;
929 return 0;
932 i = (unsigned long *) table->data;
933 min = (unsigned long *) table->extra1;
934 max = (unsigned long *) table->extra2;
935 vleft = table->maxlen / sizeof(unsigned long);
936 left = *lenp;
938 for (; left && vleft--; i++, first=0) {
939 if (write) {
940 while (left) {
941 char c;
942 if(get_user(c, (char *) buffer))
943 return -EFAULT;
944 if (!isspace(c))
945 break;
946 left--;
947 ((char *) buffer)++;
949 if (!left)
950 break;
951 neg = 0;
952 len = left;
953 if (len > TMPBUFLEN-1)
954 len = TMPBUFLEN-1;
955 if(copy_from_user(buf, buffer, len))
956 return -EFAULT;
957 buf[len] = 0;
958 p = buf;
959 if (*p == '-' && left > 1) {
960 neg = 1;
961 left--, p++;
963 if (*p < '0' || *p > '9')
964 break;
965 val = simple_strtoul(p, &p, 0) * convmul / convdiv ;
966 len = p-buf;
967 if ((len < left) && *p && !isspace(*p))
968 break;
969 if (neg)
970 val = -val;
971 buffer += len;
972 left -= len;
974 if(neg)
975 continue;
976 if (min && val < *min++)
977 continue;
978 if (max && val > *max++)
979 continue;
980 *i = val;
981 } else {
982 p = buf;
983 if (!first)
984 *p++ = '\t';
985 sprintf(p, "%lu", convdiv * (*i) / convmul);
986 len = strlen(buf);
987 if (len > left)
988 len = left;
989 if(copy_to_user(buffer, buf, len))
990 return -EFAULT;
991 left -= len;
992 buffer += len;
996 if (!write && !first && left) {
997 if(put_user('\n', (char *) buffer))
998 return -EFAULT;
999 left--, buffer++;
1001 if (write) {
1002 p = (char *) buffer;
1003 while (left) {
1004 char c;
1005 if(get_user(c, p++))
1006 return -EFAULT;
1007 if (!isspace(c))
1008 break;
1009 left--;
1012 if (write && first)
1013 return -EINVAL;
1014 *lenp -= left;
1015 filp->f_pos += *lenp;
1016 return 0;
1017 #undef TMPBUFLEN
1020 int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
1021 void *buffer, size_t *lenp)
1023 return do_proc_doulongvec_minmax(table, write, filp, buffer, lenp, 1l, 1l);
1026 int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
1027 struct file *filp,
1028 void *buffer, size_t *lenp)
1030 return do_proc_doulongvec_minmax(table, write, filp, buffer,
1031 lenp, HZ, 1000l);
1035 /* Like proc_dointvec, but converts seconds to jiffies */
1036 int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1037 void *buffer, size_t *lenp)
1039 return do_proc_dointvec(table,write,filp,buffer,lenp,HZ,OP_SET);
1042 #else /* CONFIG_PROC_FS */
1044 int proc_dostring(ctl_table *table, int write, struct file *filp,
1045 void *buffer, size_t *lenp)
1047 return -ENOSYS;
1050 static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
1051 void *buffer, size_t *lenp)
1053 return -ENOSYS;
1056 int proc_dointvec(ctl_table *table, int write, struct file *filp,
1057 void *buffer, size_t *lenp)
1059 return -ENOSYS;
1062 int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
1063 void *buffer, size_t *lenp)
1065 return -ENOSYS;
1068 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
1069 void *buffer, size_t *lenp)
1071 return -ENOSYS;
1074 int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1075 void *buffer, size_t *lenp)
1077 return -ENOSYS;
1080 int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
1081 void *buffer, size_t *lenp)
1083 return -ENOSYS;
1086 int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
1087 struct file *filp,
1088 void *buffer, size_t *lenp)
1090 return -ENOSYS;
1094 #endif /* CONFIG_PROC_FS */
1098 * General sysctl support routines
1101 /* The generic string strategy routine: */
1102 int sysctl_string(ctl_table *table, int *name, int nlen,
1103 void *oldval, size_t *oldlenp,
1104 void *newval, size_t newlen, void **context)
1106 int l, len;
1108 if (!table->data || !table->maxlen)
1109 return -ENOTDIR;
1111 if (oldval && oldlenp) {
1112 if(get_user(len, oldlenp))
1113 return -EFAULT;
1114 if (len) {
1115 l = strlen(table->data);
1116 if (len > l) len = l;
1117 if (len >= table->maxlen)
1118 len = table->maxlen;
1119 if(copy_to_user(oldval, table->data, len))
1120 return -EFAULT;
1121 if(put_user(0, ((char *) oldval) + len))
1122 return -EFAULT;
1123 if(put_user(len, oldlenp))
1124 return -EFAULT;
1127 if (newval && newlen) {
1128 len = newlen;
1129 if (len > table->maxlen)
1130 len = table->maxlen;
1131 if(copy_from_user(table->data, newval, len))
1132 return -EFAULT;
1133 if (len == table->maxlen)
1134 len--;
1135 ((char *) table->data)[len] = 0;
1137 return 0;
1141 * This function makes sure that all of the integers in the vector
1142 * are between the minimum and maximum values given in the arrays
1143 * table->extra1 and table->extra2, respectively.
1145 int sysctl_intvec(ctl_table *table, int *name, int nlen,
1146 void *oldval, size_t *oldlenp,
1147 void *newval, size_t newlen, void **context)
1149 int i, length, *vec, *min, *max;
1151 if (newval && newlen) {
1152 if (newlen % sizeof(int) != 0)
1153 return -EINVAL;
1155 if (!table->extra1 && !table->extra2)
1156 return 0;
1158 if (newlen > table->maxlen)
1159 newlen = table->maxlen;
1160 length = newlen / sizeof(int);
1162 vec = (int *) newval;
1163 min = (int *) table->extra1;
1164 max = (int *) table->extra2;
1166 for (i = 0; i < length; i++) {
1167 int value;
1168 get_user(value, vec + i);
1169 if (min && value < min[i])
1170 return -EINVAL;
1171 if (max && value > max[i])
1172 return -EINVAL;
1175 return 0;
1178 /* Strategy function to convert jiffies to seconds */
1179 int sysctl_jiffies(ctl_table *table, int *name, int nlen,
1180 void *oldval, size_t *oldlenp,
1181 void *newval, size_t newlen, void **context)
1183 if (oldval) {
1184 size_t olen;
1185 if (oldlenp) {
1186 if (get_user(olen, oldlenp))
1187 return -EFAULT;
1188 if (olen!=sizeof(int))
1189 return -EINVAL;
1191 if (put_user(*(int *)(table->data) / HZ, (int *)oldval) ||
1192 (oldlenp && put_user(sizeof(int),oldlenp)))
1193 return -EFAULT;
1195 if (newval && newlen) {
1196 int new;
1197 if (newlen != sizeof(int))
1198 return -EINVAL;
1199 if (get_user(new, (int *)newval))
1200 return -EFAULT;
1201 *(int *)(table->data) = new*HZ;
1203 return 1;
1206 int do_string (
1207 void *oldval, size_t *oldlenp, void *newval, size_t newlen,
1208 int rdwr, char *data, size_t max)
1210 int l = strlen(data) + 1;
1211 if (newval && !rdwr)
1212 return -EPERM;
1213 if (newval && newlen >= max)
1214 return -EINVAL;
1215 if (oldval) {
1216 int old_l;
1217 if(get_user(old_l, oldlenp))
1218 return -EFAULT;
1219 if (l > old_l)
1220 return -ENOMEM;
1221 if(put_user(l, oldlenp) || copy_to_user(oldval, data, l))
1222 return -EFAULT;
1224 if (newval) {
1225 if(copy_from_user(data, newval, newlen))
1226 return -EFAULT;
1227 data[newlen] = 0;
1229 return 0;
1232 int do_int (
1233 void *oldval, size_t *oldlenp, void *newval, size_t newlen,
1234 int rdwr, int *data)
1236 if (newval && !rdwr)
1237 return -EPERM;
1238 if (newval && newlen != sizeof(int))
1239 return -EINVAL;
1240 if (oldval) {
1241 int old_l;
1242 if(get_user(old_l, oldlenp))
1243 return -EFAULT;
1244 if (old_l < sizeof(int))
1245 return -ENOMEM;
1246 if(put_user(sizeof(int), oldlenp)||copy_to_user(oldval, data, sizeof(int)))
1247 return -EFAULT;
1249 if (newval)
1250 if(copy_from_user(data, newval, sizeof(int)))
1251 return -EFAULT;
1252 return 0;
1255 int do_struct (
1256 void *oldval, size_t *oldlenp, void *newval, size_t newlen,
1257 int rdwr, void *data, size_t len)
1259 if (newval && !rdwr)
1260 return -EPERM;
1261 if (newval && newlen != len)
1262 return -EINVAL;
1263 if (oldval) {
1264 int old_l;
1265 if(get_user(old_l, oldlenp))
1266 return -EFAULT;
1267 if (old_l < len)
1268 return -ENOMEM;
1269 if(put_user(len, oldlenp) || copy_to_user(oldval, data, len))
1270 return -EFAULT;
1272 if (newval)
1273 if(copy_from_user(data, newval, len))
1274 return -EFAULT;
1275 return 0;
1279 #else /* CONFIG_SYSCTL */
1282 extern asmlinkage long sys_sysctl(struct __sysctl_args *args)
1284 return -ENOSYS;
1287 int sysctl_string(ctl_table *table, int *name, int nlen,
1288 void *oldval, size_t *oldlenp,
1289 void *newval, size_t newlen, void **context)
1291 return -ENOSYS;
1294 int sysctl_intvec(ctl_table *table, int *name, int nlen,
1295 void *oldval, size_t *oldlenp,
1296 void *newval, size_t newlen, void **context)
1298 return -ENOSYS;
1301 int proc_dostring(ctl_table *table, int write, struct file *filp,
1302 void *buffer, size_t *lenp)
1304 return -ENOSYS;
1307 int proc_dointvec(ctl_table *table, int write, struct file *filp,
1308 void *buffer, size_t *lenp)
1310 return -ENOSYS;
1313 int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
1314 void *buffer, size_t *lenp)
1316 return -ENOSYS;
1319 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
1320 void *buffer, size_t *lenp)
1322 return -ENOSYS;
1325 int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1326 void *buffer, size_t *lenp)
1328 return -ENOSYS;
1331 int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
1332 void *buffer, size_t *lenp)
1334 return -ENOSYS;
1337 int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
1338 struct file *filp,
1339 void *buffer, size_t *lenp)
1341 return -ENOSYS;
1344 struct ctl_table_header * register_sysctl_table(ctl_table * table,
1345 int insert_at_head)
1347 return 0;
1350 void unregister_sysctl_table(struct ctl_table_header * table)
1354 #endif /* CONFIG_SYSCTL */