Import 2.3.1
[davej-history.git] / kernel / sysctl.c
blobed98241366b979f112e7a649e215af402ad7031d
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 Horn.
14 #include <linux/config.h>
15 #include <linux/malloc.h>
16 #include <linux/sysctl.h>
17 #include <linux/swapctl.h>
18 #include <linux/proc_fs.h>
19 #include <linux/ctype.h>
20 #include <linux/utsname.h>
21 #include <linux/swapctl.h>
22 #include <linux/smp_lock.h>
23 #include <linux/init.h>
25 #include <asm/uaccess.h>
27 #ifdef CONFIG_ROOT_NFS
28 #include <linux/nfs_fs.h>
29 #endif
31 #if defined(CONFIG_SYSCTL)
33 /* External variables not in a header file. */
34 extern int panic_timeout;
35 extern int console_loglevel, C_A_D;
36 extern int bdf_prm[], bdflush_min[], bdflush_max[];
37 extern char binfmt_java_interpreter[], binfmt_java_appletviewer[];
38 extern int sysctl_overcommit_memory;
39 extern int nr_queued_signals, max_queued_signals;
41 #ifdef CONFIG_KMOD
42 extern char modprobe_path[];
43 #endif
44 #ifdef CONFIG_CHR_DEV_SG
45 extern int sg_big_buff;
46 #endif
47 #ifdef CONFIG_SYSVIPC
48 extern int shmmax;
49 #endif
51 #ifdef __sparc__
52 extern char reboot_command [];
53 #endif
54 #ifdef __powerpc__
55 extern unsigned long htab_reclaim_on, zero_paged_on, powersave_nap;
56 int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
57 void *buffer, size_t *lenp);
58 #endif
60 #ifdef CONFIG_BSD_PROCESS_ACCT
61 extern int acct_parm[];
62 #endif
64 extern int pgt_cache_water[];
66 static int parse_table(int *, int, void *, size_t *, void *, size_t,
67 ctl_table *, void **);
68 static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
69 void *buffer, size_t *lenp);
72 static ctl_table root_table[];
73 static struct ctl_table_header root_table_header =
74 {root_table, DNODE_SINGLE(&root_table_header)};
76 static ctl_table kern_table[];
77 static ctl_table vm_table[];
78 #ifdef CONFIG_NET
79 extern ctl_table net_table[];
80 #endif
81 static ctl_table proc_table[];
82 static ctl_table fs_table[];
83 static ctl_table debug_table[];
84 static ctl_table dev_table[];
87 /* /proc declarations: */
89 #ifdef CONFIG_PROC_FS
91 static ssize_t proc_readsys(struct file *, char *, size_t, loff_t *);
92 static ssize_t proc_writesys(struct file *, const char *, size_t, loff_t *);
93 static int proc_sys_permission(struct inode *, int);
95 struct file_operations proc_sys_file_operations =
97 NULL, /* lseek */
98 proc_readsys, /* read */
99 proc_writesys, /* write */
100 NULL, /* readdir */
101 NULL, /* poll */
102 NULL, /* ioctl */
103 NULL, /* mmap */
104 NULL, /* no special open code */
105 NULL, /* no special flush code */
106 NULL, /* no special release code */
107 NULL /* can't fsync */
110 struct inode_operations proc_sys_inode_operations =
112 &proc_sys_file_operations,
113 NULL, /* create */
114 NULL, /* lookup */
115 NULL, /* link */
116 NULL, /* unlink */
117 NULL, /* symlink */
118 NULL, /* mkdir */
119 NULL, /* rmdir */
120 NULL, /* mknod */
121 NULL, /* rename */
122 NULL, /* readlink */
123 NULL, /* follow_link */
124 NULL, /* readpage */
125 NULL, /* writepage */
126 NULL, /* bmap */
127 NULL, /* truncate */
128 proc_sys_permission
131 extern struct proc_dir_entry proc_sys_root;
133 static void register_proc_table(ctl_table *, struct proc_dir_entry *);
134 static void unregister_proc_table(ctl_table *, struct proc_dir_entry *);
135 #endif
136 extern int inodes_stat[];
137 extern int dentry_stat[];
139 /* The default sysctl tables: */
141 static ctl_table root_table[] = {
142 {CTL_KERN, "kernel", NULL, 0, 0555, kern_table},
143 {CTL_VM, "vm", NULL, 0, 0555, vm_table},
144 #ifdef CONFIG_NET
145 {CTL_NET, "net", NULL, 0, 0555, net_table},
146 #endif
147 {CTL_PROC, "proc", NULL, 0, 0555, proc_table},
148 {CTL_FS, "fs", NULL, 0, 0555, fs_table},
149 {CTL_DEBUG, "debug", NULL, 0, 0555, debug_table},
150 {CTL_DEV, "dev", NULL, 0, 0555, dev_table},
154 static ctl_table kern_table[] = {
155 {KERN_OSTYPE, "ostype", system_utsname.sysname, 64,
156 0444, NULL, &proc_doutsstring, &sysctl_string},
157 {KERN_OSRELEASE, "osrelease", system_utsname.release, 64,
158 0444, NULL, &proc_doutsstring, &sysctl_string},
159 {KERN_VERSION, "version", system_utsname.version, 64,
160 0444, NULL, &proc_doutsstring, &sysctl_string},
161 {KERN_NODENAME, "hostname", system_utsname.nodename, 64,
162 0644, NULL, &proc_doutsstring, &sysctl_string},
163 {KERN_DOMAINNAME, "domainname", system_utsname.domainname, 64,
164 0644, NULL, &proc_doutsstring, &sysctl_string},
165 {KERN_PANIC, "panic", &panic_timeout, sizeof(int),
166 0644, NULL, &proc_dointvec},
167 #ifdef CONFIG_BLK_DEV_INITRD
168 {KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(int),
169 0644, NULL, &proc_dointvec},
170 #endif
171 #ifdef CONFIG_BINFMT_JAVA
172 {KERN_JAVA_INTERPRETER, "java-interpreter", binfmt_java_interpreter,
173 64, 0644, NULL, &proc_dostring, &sysctl_string },
174 {KERN_JAVA_APPLETVIEWER, "java-appletviewer", binfmt_java_appletviewer,
175 64, 0644, NULL, &proc_dostring, &sysctl_string },
176 #endif
177 #ifdef __sparc__
178 {KERN_SPARC_REBOOT, "reboot-cmd", reboot_command,
179 256, 0644, NULL, &proc_dostring, &sysctl_string },
180 #endif
181 #ifdef __powerpc__
182 {KERN_PPC_HTABRECLAIM, "htab-reclaim", &htab_reclaim_on, sizeof(int),
183 0644, NULL, &proc_dointvec},
184 {KERN_PPC_ZEROPAGED, "zero-paged", &zero_paged_on, sizeof(int),
185 0644, NULL, &proc_dointvec},
186 {KERN_PPC_POWERSAVE_NAP, "powersave-nap", &powersave_nap, sizeof(int),
187 0644, NULL, &proc_dointvec},
188 {KERN_PPC_L2CR, "l2cr", NULL, 0,
189 0644, NULL, &proc_dol2crvec},
190 #endif
191 {KERN_CTLALTDEL, "ctrl-alt-del", &C_A_D, sizeof(int),
192 0644, NULL, &proc_dointvec},
193 {KERN_PRINTK, "printk", &console_loglevel, 4*sizeof(int),
194 0644, NULL, &proc_dointvec},
195 #ifdef CONFIG_KMOD
196 {KERN_MODPROBE, "modprobe", &modprobe_path, 256,
197 0644, NULL, &proc_dostring, &sysctl_string },
198 #endif
199 #ifdef CONFIG_CHR_DEV_SG
200 {KERN_SG_BIG_BUFF, "sg-big-buff", &sg_big_buff, sizeof (int),
201 0444, NULL, &proc_dointvec},
202 #endif
203 #ifdef CONFIG_BSD_PROCESS_ACCT
204 {KERN_ACCT, "acct", &acct_parm, 3*sizeof(int),
205 0644, NULL, &proc_dointvec},
206 #endif
207 {KERN_RTSIGNR, "rtsig-nr", &nr_queued_signals, sizeof(int),
208 0444, NULL, &proc_dointvec},
209 {KERN_RTSIGMAX, "rtsig-max", &max_queued_signals, sizeof(int),
210 0644, NULL, &proc_dointvec},
211 #ifdef CONFIG_SYSVIPC
212 {KERN_SHMMAX, "shmmax", &shmmax, sizeof (int),
213 0644, NULL, &proc_dointvec},
214 #endif
218 static ctl_table vm_table[] = {
219 {VM_FREEPG, "freepages",
220 &freepages, sizeof(freepages_t), 0644, NULL, &proc_dointvec},
221 {VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0600, NULL,
222 &proc_dointvec_minmax, &sysctl_intvec, NULL,
223 &bdflush_min, &bdflush_max},
224 {VM_OVERCOMMIT_MEMORY, "overcommit_memory", &sysctl_overcommit_memory,
225 sizeof(sysctl_overcommit_memory), 0644, NULL, &proc_dointvec},
226 {VM_BUFFERMEM, "buffermem",
227 &buffer_mem, sizeof(buffer_mem_t), 0644, NULL, &proc_dointvec},
228 {VM_PAGECACHE, "pagecache",
229 &page_cache, sizeof(buffer_mem_t), 0644, NULL, &proc_dointvec},
230 {VM_PAGERDAEMON, "kswapd",
231 &pager_daemon, sizeof(pager_daemon_t), 0644, NULL, &proc_dointvec},
232 {VM_PGT_CACHE, "pagetable_cache",
233 &pgt_cache_water, 2*sizeof(int), 0600, NULL, &proc_dointvec},
234 {VM_PAGE_CLUSTER, "page-cluster",
235 &page_cluster, sizeof(int), 0600, NULL, &proc_dointvec},
239 static ctl_table proc_table[] = {
243 static ctl_table fs_table[] = {
244 {FS_NRINODE, "inode-nr", &inodes_stat, 2*sizeof(int),
245 0444, NULL, &proc_dointvec},
246 {FS_STATINODE, "inode-state", &inodes_stat, 7*sizeof(int),
247 0444, NULL, &proc_dointvec},
248 {FS_MAXINODE, "inode-max", &max_inodes, sizeof(int),
249 0644, NULL, &proc_dointvec},
250 {FS_NRFILE, "file-nr", &nr_files, 3*sizeof(int),
251 0444, NULL, &proc_dointvec},
252 {FS_MAXFILE, "file-max", &max_files, sizeof(int),
253 0644, NULL, &proc_dointvec},
254 {FS_NRSUPER, "super-nr", &nr_super_blocks, sizeof(int),
255 0444, NULL, &proc_dointvec},
256 {FS_MAXSUPER, "super-max", &max_super_blocks, sizeof(int),
257 0644, NULL, &proc_dointvec},
258 {FS_NRDQUOT, "dquot-nr", &nr_dquots, 2*sizeof(int),
259 0444, NULL, &proc_dointvec},
260 {FS_MAXDQUOT, "dquot-max", &max_dquots, sizeof(int),
261 0644, NULL, &proc_dointvec},
262 {FS_DENTRY, "dentry-state", &dentry_stat, 6*sizeof(int),
263 0444, NULL, &proc_dointvec},
267 static ctl_table debug_table[] = {
271 static ctl_table dev_table[] = {
276 void __init sysctl_init(void)
278 #ifdef CONFIG_PROC_FS
279 register_proc_table(root_table, &proc_sys_root);
280 #endif
284 int do_sysctl (int *name, int nlen,
285 void *oldval, size_t *oldlenp,
286 void *newval, size_t newlen)
288 int error;
289 struct ctl_table_header *tmp;
290 void *context;
292 if (nlen == 0 || nlen >= CTL_MAXNAME)
293 return -ENOTDIR;
295 if (oldval)
297 int old_len;
298 if (!oldlenp)
299 return -EFAULT;
300 if(get_user(old_len, oldlenp))
301 return -EFAULT;
303 tmp = &root_table_header;
304 do {
305 context = NULL;
306 error = parse_table(name, nlen, oldval, oldlenp,
307 newval, newlen, tmp->ctl_table, &context);
308 if (context)
309 kfree(context);
310 if (error != -ENOTDIR)
311 return error;
312 tmp = tmp->DLIST_NEXT(ctl_entry);
313 } while (tmp != &root_table_header);
314 return -ENOTDIR;
317 extern asmlinkage int sys_sysctl(struct __sysctl_args *args)
319 struct __sysctl_args tmp;
320 int error;
322 if(copy_from_user(&tmp, args, sizeof(tmp)))
323 return -EFAULT;
325 lock_kernel();
326 error = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp,
327 tmp.newval, tmp.newlen);
328 unlock_kernel();
329 return error;
332 /* Like in_group_p, but testing against egid, not fsgid */
333 static int in_egroup_p(gid_t grp)
335 if (grp != current->egid) {
336 int i = current->ngroups;
337 if (i) {
338 gid_t *groups = current->groups;
339 do {
340 if (*groups == grp)
341 goto out;
342 groups++;
343 i--;
344 } while (i);
346 return 0;
348 out:
349 return 1;
352 /* ctl_perm does NOT grant the superuser all rights automatically, because
353 some sysctl variables are readonly even to root. */
355 static int test_perm(int mode, int op)
357 if (!current->euid)
358 mode >>= 6;
359 else if (in_egroup_p(0))
360 mode >>= 3;
361 if ((mode & op & 0007) == op)
362 return 0;
363 return -EACCES;
366 static inline int ctl_perm(ctl_table *table, int op)
368 return test_perm(table->mode, op);
371 static int parse_table(int *name, int nlen,
372 void *oldval, size_t *oldlenp,
373 void *newval, size_t newlen,
374 ctl_table *table, void **context)
376 int error;
377 repeat:
378 if (!nlen)
379 return -ENOTDIR;
381 for ( ; table->ctl_name; table++) {
382 int n;
383 if(get_user(n,name))
384 return -EFAULT;
385 if (n == table->ctl_name ||
386 table->ctl_name == CTL_ANY) {
387 if (table->child) {
388 if (ctl_perm(table, 001))
389 return -EPERM;
390 if (table->strategy) {
391 error = table->strategy(
392 table, name, nlen,
393 oldval, oldlenp,
394 newval, newlen, context);
395 if (error)
396 return error;
398 name++;
399 nlen--;
400 table = table->child;
401 goto repeat;
403 error = do_sysctl_strategy(table, name, nlen,
404 oldval, oldlenp,
405 newval, newlen, context);
406 return error;
409 return -ENOTDIR;
412 /* Perform the actual read/write of a sysctl table entry. */
413 int do_sysctl_strategy (ctl_table *table,
414 int *name, int nlen,
415 void *oldval, size_t *oldlenp,
416 void *newval, size_t newlen, void **context)
418 int op = 0, rc, len;
420 if (oldval)
421 op |= 004;
422 if (newval)
423 op |= 002;
424 if (ctl_perm(table, op))
425 return -EPERM;
427 if (table->strategy) {
428 rc = table->strategy(table, name, nlen, oldval, oldlenp,
429 newval, newlen, context);
430 if (rc < 0)
431 return rc;
432 if (rc > 0)
433 return 0;
436 /* If there is no strategy routine, or if the strategy returns
437 * zero, proceed with automatic r/w */
438 if (table->data && table->maxlen) {
439 if (oldval && oldlenp) {
440 get_user(len, oldlenp);
441 if (len) {
442 if (len > table->maxlen)
443 len = table->maxlen;
444 if(copy_to_user(oldval, table->data, len))
445 return -EFAULT;
446 if(put_user(len, oldlenp))
447 return -EFAULT;
450 if (newval && newlen) {
451 len = newlen;
452 if (len > table->maxlen)
453 len = table->maxlen;
454 if(copy_from_user(table->data, newval, len))
455 return -EFAULT;
458 return 0;
461 struct ctl_table_header *register_sysctl_table(ctl_table * table,
462 int insert_at_head)
464 struct ctl_table_header *tmp;
465 tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
466 if (!tmp)
467 return 0;
468 *tmp = ((struct ctl_table_header) {table, DNODE_NULL});
469 if (insert_at_head)
470 DLIST_INSERT_AFTER(&root_table_header, tmp, ctl_entry);
471 else
472 DLIST_INSERT_BEFORE(&root_table_header, tmp, 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 DLIST_DELETE(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->ops = &proc_sys_inode_operations;
539 table->de = de;
540 if (de->mode & S_IFDIR)
541 register_proc_table(table->child, de);
546 * Unregister a /proc sysctl table and any subdirectories.
548 static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root)
550 struct proc_dir_entry *de;
551 for (; table->ctl_name; table++) {
552 if (!(de = table->de))
553 continue;
554 if (de->mode & S_IFDIR) {
555 if (!table->child) {
556 printk (KERN_ALERT "Help - malformed sysctl tree on free\n");
557 continue;
559 unregister_proc_table(table->child, de);
561 /* Don't unregister directories which still have entries.. */
562 if (de->subdir)
563 continue;
566 /* Don't unregoster proc entries that are still being used.. */
567 if (de->count)
568 continue;
570 proc_unregister(root, de->low_ino);
571 table->de = NULL;
572 kfree(de);
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;
681 down(&uts_sem);
682 r=proc_dostring(table,write,filp,buffer,lenp);
683 up(&uts_sem);
684 return r;
687 static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
688 void *buffer, size_t *lenp, int conv)
690 int *i, vleft, first=1, len, left, neg, val;
691 #define TMPBUFLEN 20
692 char buf[TMPBUFLEN], *p;
694 if (!table->data || !table->maxlen || !*lenp ||
695 (filp->f_pos && !write)) {
696 *lenp = 0;
697 return 0;
700 i = (int *) table->data;
701 vleft = table->maxlen / sizeof(int);
702 left = *lenp;
704 for (; left && vleft--; i++, first=0) {
705 if (write) {
706 while (left) {
707 char c;
708 if(get_user(c,(char *) buffer))
709 return -EFAULT;
710 if (!isspace(c))
711 break;
712 left--;
713 ((char *) buffer)++;
715 if (!left)
716 break;
717 neg = 0;
718 len = left;
719 if (len > TMPBUFLEN-1)
720 len = TMPBUFLEN-1;
721 if(copy_from_user(buf, buffer, len))
722 return -EFAULT;
723 buf[len] = 0;
724 p = buf;
725 if (*p == '-' && left > 1) {
726 neg = 1;
727 left--, p++;
729 if (*p < '0' || *p > '9')
730 break;
731 val = simple_strtoul(p, &p, 0) * conv;
732 len = p-buf;
733 if ((len < left) && *p && !isspace(*p))
734 break;
735 if (neg)
736 val = -val;
737 buffer += len;
738 left -= len;
739 *i = val;
740 } else {
741 p = buf;
742 if (!first)
743 *p++ = '\t';
744 sprintf(p, "%d", (*i) / conv);
745 len = strlen(buf);
746 if (len > left)
747 len = left;
748 if(copy_to_user(buffer, buf, len))
749 return -EFAULT;
750 left -= len;
751 buffer += len;
755 if (!write && !first && left) {
756 if(put_user('\n', (char *) buffer))
757 return -EFAULT;
758 left--, buffer++;
760 if (write) {
761 p = (char *) buffer;
762 while (left) {
763 char c;
764 if(get_user(c, p++))
765 return -EFAULT;
766 if (!isspace(c))
767 break;
768 left--;
771 if (write && first)
772 return -EINVAL;
773 *lenp -= left;
774 filp->f_pos += *lenp;
775 return 0;
778 int proc_dointvec(ctl_table *table, int write, struct file *filp,
779 void *buffer, size_t *lenp)
781 return do_proc_dointvec(table,write,filp,buffer,lenp,1);
784 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
785 void *buffer, size_t *lenp)
787 int *i, *min, *max, vleft, first=1, len, left, neg, val;
788 #define TMPBUFLEN 20
789 char buf[TMPBUFLEN], *p;
791 if (!table->data || !table->maxlen || !*lenp ||
792 (filp->f_pos && !write)) {
793 *lenp = 0;
794 return 0;
797 i = (int *) table->data;
798 min = (int *) table->extra1;
799 max = (int *) table->extra2;
800 vleft = table->maxlen / sizeof(int);
801 left = *lenp;
803 for (; left && vleft--; i++, first=0) {
804 if (write) {
805 while (left) {
806 char c;
807 if(get_user(c, (char *) buffer))
808 return -EFAULT;
809 if (!isspace(c))
810 break;
811 left--;
812 ((char *) buffer)++;
814 if (!left)
815 break;
816 neg = 0;
817 len = left;
818 if (len > TMPBUFLEN-1)
819 len = TMPBUFLEN-1;
820 if(copy_from_user(buf, buffer, len))
821 return -EFAULT;
822 buf[len] = 0;
823 p = buf;
824 if (*p == '-' && left > 1) {
825 neg = 1;
826 left--, p++;
828 if (*p < '0' || *p > '9')
829 break;
830 val = simple_strtoul(p, &p, 0);
831 len = p-buf;
832 if ((len < left) && *p && !isspace(*p))
833 break;
834 if (neg)
835 val = -val;
836 buffer += len;
837 left -= len;
839 if (min && val < *min++)
840 continue;
841 if (max && val > *max++)
842 continue;
843 *i = val;
844 } else {
845 p = buf;
846 if (!first)
847 *p++ = '\t';
848 sprintf(p, "%d", *i);
849 len = strlen(buf);
850 if (len > left)
851 len = left;
852 if(copy_to_user(buffer, buf, len))
853 return -EFAULT;
854 left -= len;
855 buffer += len;
859 if (!write && !first && left) {
860 if(put_user('\n', (char *) buffer))
861 return -EFAULT;
862 left--, buffer++;
864 if (write) {
865 p = (char *) buffer;
866 while (left) {
867 char c;
868 if(get_user(c, p++))
869 return -EFAULT;
870 if (!isspace(c))
871 break;
872 left--;
875 if (write && first)
876 return -EINVAL;
877 *lenp -= left;
878 filp->f_pos += *lenp;
879 return 0;
882 /* Like proc_dointvec, but converts seconds to jiffies */
883 int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
884 void *buffer, size_t *lenp)
886 return do_proc_dointvec(table,write,filp,buffer,lenp,HZ);
889 #else /* CONFIG_PROC_FS */
891 int proc_dostring(ctl_table *table, int write, struct file *filp,
892 void *buffer, size_t *lenp)
894 return -ENOSYS;
897 static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
898 void *buffer, size_t *lenp)
900 return -ENOSYS;
903 int proc_dointvec(ctl_table *table, int write, struct file *filp,
904 void *buffer, size_t *lenp)
906 return -ENOSYS;
909 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
910 void *buffer, size_t *lenp)
912 return -ENOSYS;
915 int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
916 void *buffer, size_t *lenp)
918 return -ENOSYS;
921 #endif /* CONFIG_PROC_FS */
925 * General sysctl support routines
928 /* The generic string strategy routine: */
929 int sysctl_string(ctl_table *table, int *name, int nlen,
930 void *oldval, size_t *oldlenp,
931 void *newval, size_t newlen, void **context)
933 int l, len;
935 if (!table->data || !table->maxlen)
936 return -ENOTDIR;
938 if (oldval && oldlenp) {
939 if(get_user(len, oldlenp))
940 return -EFAULT;
941 if (len) {
942 l = strlen(table->data);
943 if (len > l) len = l;
944 if (len >= table->maxlen)
945 len = table->maxlen;
946 if(copy_to_user(oldval, table->data, len))
947 return -EFAULT;
948 if(put_user(0, ((char *) oldval) + len))
949 return -EFAULT;
950 if(put_user(len, oldlenp))
951 return -EFAULT;
954 if (newval && newlen) {
955 len = newlen;
956 if (len > table->maxlen)
957 len = table->maxlen;
958 if(copy_from_user(table->data, newval, len))
959 return -EFAULT;
960 if (len == table->maxlen)
961 len--;
962 ((char *) table->data)[len] = 0;
964 return 0;
968 * This function makes sure that all of the integers in the vector
969 * are between the minimum and maximum values given in the arrays
970 * table->extra1 and table->extra2, respectively.
972 int sysctl_intvec(ctl_table *table, int *name, int nlen,
973 void *oldval, size_t *oldlenp,
974 void *newval, size_t newlen, void **context)
976 int i, length, *vec, *min, *max;
978 if (newval && newlen) {
979 if (newlen % sizeof(int) != 0)
980 return -EINVAL;
982 if (!table->extra1 && !table->extra2)
983 return 0;
985 if (newlen > table->maxlen)
986 newlen = table->maxlen;
987 length = newlen / sizeof(int);
989 vec = (int *) newval;
990 min = (int *) table->extra1;
991 max = (int *) table->extra2;
993 for (i = 0; i < length; i++) {
994 int value;
995 get_user(value, vec + i);
996 if (min && value < min[i])
997 return -EINVAL;
998 if (max && value > max[i])
999 return -EINVAL;
1002 return 0;
1005 int do_string (
1006 void *oldval, size_t *oldlenp, void *newval, size_t newlen,
1007 int rdwr, char *data, size_t max)
1009 int l = strlen(data) + 1;
1010 if (newval && !rdwr)
1011 return -EPERM;
1012 if (newval && newlen >= max)
1013 return -EINVAL;
1014 if (oldval) {
1015 int old_l;
1016 if(get_user(old_l, oldlenp))
1017 return -EFAULT;
1018 if (l > old_l)
1019 return -ENOMEM;
1020 if(put_user(l, oldlenp) || copy_to_user(oldval, data, l))
1021 return -EFAULT;
1023 if (newval) {
1024 if(copy_from_user(data, newval, newlen))
1025 return -EFAULT;
1026 data[newlen] = 0;
1028 return 0;
1031 int do_int (
1032 void *oldval, size_t *oldlenp, void *newval, size_t newlen,
1033 int rdwr, int *data)
1035 if (newval && !rdwr)
1036 return -EPERM;
1037 if (newval && newlen != sizeof(int))
1038 return -EINVAL;
1039 if (oldval) {
1040 int old_l;
1041 if(get_user(old_l, oldlenp))
1042 return -EFAULT;
1043 if (old_l < sizeof(int))
1044 return -ENOMEM;
1045 if(put_user(sizeof(int), oldlenp)||copy_to_user(oldval, data, sizeof(int)))
1046 return -EFAULT;
1048 if (newval)
1049 if(copy_from_user(data, newval, sizeof(int)))
1050 return -EFAULT;
1051 return 0;
1054 int do_struct (
1055 void *oldval, size_t *oldlenp, void *newval, size_t newlen,
1056 int rdwr, void *data, size_t len)
1058 if (newval && !rdwr)
1059 return -EPERM;
1060 if (newval && newlen != len)
1061 return -EINVAL;
1062 if (oldval) {
1063 int old_l;
1064 if(get_user(old_l, oldlenp))
1065 return -EFAULT;
1066 if (old_l < len)
1067 return -ENOMEM;
1068 if(put_user(len, oldlenp) || copy_to_user(oldval, data, len))
1069 return -EFAULT;
1071 if (newval)
1072 if(copy_from_user(data, newval, len))
1073 return -EFAULT;
1074 return 0;
1078 #else /* CONFIG_SYSCTL */
1081 extern asmlinkage int sys_sysctl(struct __sysctl_args *args)
1083 return -ENOSYS;
1086 int sysctl_string(ctl_table *table, int *name, int nlen,
1087 void *oldval, size_t *oldlenp,
1088 void *newval, size_t newlen, void **context)
1090 return -ENOSYS;
1093 int sysctl_intvec(ctl_table *table, int *name, int nlen,
1094 void *oldval, size_t *oldlenp,
1095 void *newval, size_t newlen, void **context)
1097 return -ENOSYS;
1100 int proc_dostring(ctl_table *table, int write, struct file *filp,
1101 void *buffer, size_t *lenp)
1103 return -ENOSYS;
1106 int proc_dointvec(ctl_table *table, int write, struct file *filp,
1107 void *buffer, size_t *lenp)
1109 return -ENOSYS;
1112 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
1113 void *buffer, size_t *lenp)
1115 return -ENOSYS;
1118 int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1119 void *buffer, size_t *lenp)
1121 return -ENOSYS;
1124 struct ctl_table_header * register_sysctl_table(ctl_table * table,
1125 int insert_at_head)
1127 return 0;
1130 void unregister_sysctl_table(struct ctl_table_header * table)
1134 #endif /* CONFIG_SYSCTL */