Import 2.3.40pre5
[davej-history.git] / kernel / sysctl.c
blobfd4970e582eb8ba4b01f186c9790c3b1d50c6248
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.
17 #include <linux/config.h>
18 #include <linux/malloc.h>
19 #include <linux/sysctl.h>
20 #include <linux/swapctl.h>
21 #include <linux/proc_fs.h>
22 #include <linux/ctype.h>
23 #include <linux/utsname.h>
24 #include <linux/capability.h>
25 #include <linux/smp_lock.h>
26 #include <linux/init.h>
27 #include <linux/sysrq.h>
28 #include <linux/highuid.h>
30 #include <asm/uaccess.h>
32 #ifdef CONFIG_ROOT_NFS
33 #include <linux/nfs_fs.h>
34 #endif
36 #if defined(CONFIG_SYSCTL)
38 /* External variables not in a header file. */
39 extern int panic_timeout;
40 extern int console_loglevel, C_A_D;
41 extern int bdf_prm[], bdflush_min[], bdflush_max[];
42 extern int sysctl_overcommit_memory;
43 extern int max_threads;
44 extern int nr_queued_signals, max_queued_signals;
46 /* this is needed for the proc_dointvec_minmax for overflow UID and GID */
47 static int maxolduid = 65535;
48 static int minolduid = 0;
50 #ifdef CONFIG_KMOD
51 extern char modprobe_path[];
52 #endif
53 #ifdef CONFIG_CHR_DEV_SG
54 extern int sg_big_buff;
55 #endif
56 #ifdef CONFIG_SYSVIPC
57 extern size_t shm_ctlmax;
58 extern int shm_ctlall;
59 extern int shm_ctlmni;
60 extern int msg_ctlmax;
61 extern int msg_ctlmnb;
62 extern int msg_ctlmni;
63 extern int sem_ctls[];
64 #endif
66 #ifdef __sparc__
67 extern char reboot_command [];
68 extern int stop_a_enabled;
69 #endif
70 #ifdef __powerpc__
71 extern unsigned long htab_reclaim_on, zero_paged_on, powersave_nap;
72 int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
73 void *buffer, size_t *lenp);
74 #endif
76 #ifdef CONFIG_BSD_PROCESS_ACCT
77 extern int acct_parm[];
78 #endif
80 extern int pgt_cache_water[];
82 static int parse_table(int *, int, void *, size_t *, void *, size_t,
83 ctl_table *, void **);
84 static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
85 void *buffer, size_t *lenp);
88 static ctl_table root_table[];
89 static struct ctl_table_header root_table_header =
90 {root_table, DNODE_SINGLE(&root_table_header)};
92 static ctl_table kern_table[];
93 static ctl_table vm_table[];
94 #ifdef CONFIG_NET
95 extern ctl_table net_table[];
96 #endif
97 static ctl_table proc_table[];
98 static ctl_table fs_table[];
99 static ctl_table debug_table[];
100 static ctl_table dev_table[];
101 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 =
114 NULL, /* lseek */
115 proc_readsys, /* read */
116 proc_writesys, /* write */
117 NULL, /* readdir */
118 NULL, /* poll */
119 NULL, /* ioctl */
120 NULL, /* mmap */
121 NULL, /* no special open code */
122 NULL, /* no special flush code */
123 NULL, /* no special release code */
124 NULL /* can't fsync */
127 struct inode_operations proc_sys_inode_operations =
129 &proc_sys_file_operations,
130 NULL, /* create */
131 NULL, /* lookup */
132 NULL, /* link */
133 NULL, /* unlink */
134 NULL, /* symlink */
135 NULL, /* mkdir */
136 NULL, /* rmdir */
137 NULL, /* mknod */
138 NULL, /* rename */
139 NULL, /* readlink */
140 NULL, /* follow_link */
141 NULL, /* get_block */
142 NULL, /* readpage */
143 NULL, /* writepage */
144 NULL, /* truncate */
145 proc_sys_permission, /* permission */
146 NULL /* revalidate */
149 extern struct proc_dir_entry *proc_sys_root;
151 static void register_proc_table(ctl_table *, struct proc_dir_entry *);
152 static void unregister_proc_table(ctl_table *, struct proc_dir_entry *);
153 #endif
154 extern int inodes_stat[];
155 extern int dentry_stat[];
157 /* The default sysctl tables: */
159 static ctl_table root_table[] = {
160 {CTL_KERN, "kernel", NULL, 0, 0555, kern_table},
161 {CTL_VM, "vm", NULL, 0, 0555, vm_table},
162 #ifdef CONFIG_NET
163 {CTL_NET, "net", NULL, 0, 0555, net_table},
164 #endif
165 {CTL_PROC, "proc", NULL, 0, 0555, proc_table},
166 {CTL_FS, "fs", NULL, 0, 0555, fs_table},
167 {CTL_DEBUG, "debug", NULL, 0, 0555, debug_table},
168 {CTL_DEV, "dev", NULL, 0, 0555, dev_table},
172 static ctl_table kern_table[] = {
173 {KERN_OSTYPE, "ostype", system_utsname.sysname, 64,
174 0444, NULL, &proc_doutsstring, &sysctl_string},
175 {KERN_OSRELEASE, "osrelease", system_utsname.release, 64,
176 0444, NULL, &proc_doutsstring, &sysctl_string},
177 {KERN_VERSION, "version", system_utsname.version, 64,
178 0444, NULL, &proc_doutsstring, &sysctl_string},
179 {KERN_NODENAME, "hostname", system_utsname.nodename, 64,
180 0644, NULL, &proc_doutsstring, &sysctl_string},
181 {KERN_DOMAINNAME, "domainname", system_utsname.domainname, 64,
182 0644, NULL, &proc_doutsstring, &sysctl_string},
183 {KERN_PANIC, "panic", &panic_timeout, sizeof(int),
184 0644, NULL, &proc_dointvec},
185 {KERN_CAP_BSET, "cap-bound", &cap_bset, sizeof(kernel_cap_t),
186 0600, NULL, &proc_dointvec_bset},
187 #ifdef CONFIG_BLK_DEV_INITRD
188 {KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(int),
189 0644, NULL, &proc_dointvec},
190 #endif
191 #ifdef __sparc__
192 {KERN_SPARC_REBOOT, "reboot-cmd", reboot_command,
193 256, 0644, NULL, &proc_dostring, &sysctl_string },
194 {KERN_SPARC_STOP_A, "stop-a", &stop_a_enabled, sizeof (int),
195 0644, NULL, &proc_dointvec},
196 #endif
197 #ifdef __powerpc__
198 {KERN_PPC_HTABRECLAIM, "htab-reclaim", &htab_reclaim_on, sizeof(int),
199 0644, NULL, &proc_dointvec},
200 {KERN_PPC_ZEROPAGED, "zero-paged", &zero_paged_on, sizeof(int),
201 0644, NULL, &proc_dointvec},
202 {KERN_PPC_POWERSAVE_NAP, "powersave-nap", &powersave_nap, sizeof(int),
203 0644, NULL, &proc_dointvec},
204 {KERN_PPC_L2CR, "l2cr", NULL, 0,
205 0644, NULL, &proc_dol2crvec},
206 #endif
207 {KERN_CTLALTDEL, "ctrl-alt-del", &C_A_D, sizeof(int),
208 0644, NULL, &proc_dointvec},
209 {KERN_PRINTK, "printk", &console_loglevel, 4*sizeof(int),
210 0644, NULL, &proc_dointvec},
211 #ifdef CONFIG_KMOD
212 {KERN_MODPROBE, "modprobe", &modprobe_path, 256,
213 0644, NULL, &proc_dostring, &sysctl_string },
214 #endif
215 #ifdef CONFIG_CHR_DEV_SG
216 {KERN_SG_BIG_BUFF, "sg-big-buff", &sg_big_buff, sizeof (int),
217 0444, NULL, &proc_dointvec},
218 #endif
219 #ifdef CONFIG_BSD_PROCESS_ACCT
220 {KERN_ACCT, "acct", &acct_parm, 3*sizeof(int),
221 0644, NULL, &proc_dointvec},
222 #endif
223 {KERN_RTSIGNR, "rtsig-nr", &nr_queued_signals, sizeof(int),
224 0444, NULL, &proc_dointvec},
225 {KERN_RTSIGMAX, "rtsig-max", &max_queued_signals, sizeof(int),
226 0644, NULL, &proc_dointvec},
227 #ifdef CONFIG_SYSVIPC
228 {KERN_SHMMAX, "shmmax", &shm_ctlmax, sizeof (size_t),
229 0644, NULL, &proc_doulongvec_minmax},
230 {KERN_SHMALL, "shmall", &shm_ctlall, sizeof (int),
231 0644, NULL, &proc_dointvec},
232 {KERN_SHMMNI, "shmmni", &shm_ctlmni, sizeof (int),
233 0644, NULL, &proc_dointvec},
234 {KERN_MSGMAX, "msgmax", &msg_ctlmax, sizeof (int),
235 0644, NULL, &proc_dointvec},
236 {KERN_MSGMNI, "msgmni", &msg_ctlmni, sizeof (int),
237 0644, NULL, &proc_dointvec},
238 {KERN_MSGMNB, "msgmnb", &msg_ctlmnb, sizeof (int),
239 0644, NULL, &proc_dointvec},
240 {KERN_SEM, "sem", &sem_ctls, 4*sizeof (int),
241 0644, NULL, &proc_dointvec},
242 #endif
243 #ifdef CONFIG_MAGIC_SYSRQ
244 {KERN_SYSRQ, "sysrq", &sysrq_enabled, sizeof (int),
245 0644, NULL, &proc_dointvec},
246 #endif
247 {KERN_MAX_THREADS, "threads-max", &max_threads, sizeof(int),
248 0644, NULL, &proc_dointvec},
249 {KERN_RANDOM, "random", NULL, 0, 0555, random_table},
250 {KERN_OVERFLOWUID, "overflowuid", &overflowuid, sizeof(int), 0644, NULL,
251 &proc_dointvec_minmax, &sysctl_intvec, NULL,
252 &minolduid, &maxolduid},
253 {KERN_OVERFLOWGID, "overflowgid", &overflowgid, sizeof(int), 0644, NULL,
254 &proc_dointvec_minmax, &sysctl_intvec, NULL,
255 &minolduid, &maxolduid},
259 static ctl_table vm_table[] = {
260 {VM_FREEPG, "freepages",
261 &freepages, sizeof(freepages_t), 0644, NULL, &proc_dointvec},
262 {VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0600, NULL,
263 &proc_dointvec_minmax, &sysctl_intvec, NULL,
264 &bdflush_min, &bdflush_max},
265 {VM_OVERCOMMIT_MEMORY, "overcommit_memory", &sysctl_overcommit_memory,
266 sizeof(sysctl_overcommit_memory), 0644, NULL, &proc_dointvec},
267 {VM_BUFFERMEM, "buffermem",
268 &buffer_mem, sizeof(buffer_mem_t), 0644, NULL, &proc_dointvec},
269 {VM_PAGECACHE, "pagecache",
270 &page_cache, sizeof(buffer_mem_t), 0644, NULL, &proc_dointvec},
271 {VM_PAGERDAEMON, "kswapd",
272 &pager_daemon, sizeof(pager_daemon_t), 0644, NULL, &proc_dointvec},
273 {VM_PGT_CACHE, "pagetable_cache",
274 &pgt_cache_water, 2*sizeof(int), 0600, NULL, &proc_dointvec},
275 {VM_PAGE_CLUSTER, "page-cluster",
276 &page_cluster, sizeof(int), 0600, NULL, &proc_dointvec},
280 static ctl_table proc_table[] = {
284 static ctl_table fs_table[] = {
285 {FS_NRINODE, "inode-nr", &inodes_stat, 2*sizeof(int),
286 0444, NULL, &proc_dointvec},
287 {FS_STATINODE, "inode-state", &inodes_stat, 7*sizeof(int),
288 0444, NULL, &proc_dointvec},
289 {FS_NRFILE, "file-nr", &nr_files, 3*sizeof(int),
290 0444, NULL, &proc_dointvec},
291 {FS_MAXFILE, "file-max", &max_files, sizeof(int),
292 0644, NULL, &proc_dointvec},
293 {FS_NRSUPER, "super-nr", &nr_super_blocks, sizeof(int),
294 0444, NULL, &proc_dointvec},
295 {FS_MAXSUPER, "super-max", &max_super_blocks, sizeof(int),
296 0644, NULL, &proc_dointvec},
297 {FS_NRDQUOT, "dquot-nr", &nr_dquots, 2*sizeof(int),
298 0444, NULL, &proc_dointvec},
299 {FS_MAXDQUOT, "dquot-max", &max_dquots, sizeof(int),
300 0644, NULL, &proc_dointvec},
301 {FS_DENTRY, "dentry-state", &dentry_stat, 6*sizeof(int),
302 0444, NULL, &proc_dointvec},
303 {FS_OVERFLOWUID, "overflowuid", &fs_overflowuid, sizeof(int), 0644, NULL,
304 &proc_dointvec_minmax, &sysctl_intvec, NULL,
305 &minolduid, &maxolduid},
306 {FS_OVERFLOWGID, "overflowgid", &fs_overflowgid, sizeof(int), 0644, NULL,
307 &proc_dointvec_minmax, &sysctl_intvec, NULL,
308 &minolduid, &maxolduid},
312 static ctl_table debug_table[] = {
316 static ctl_table dev_table[] = {
321 void __init sysctl_init(void)
323 #ifdef CONFIG_PROC_FS
324 register_proc_table(root_table, proc_sys_root);
325 #endif
329 int do_sysctl (int *name, int nlen,
330 void *oldval, size_t *oldlenp,
331 void *newval, size_t newlen)
333 int error;
334 struct ctl_table_header *tmp;
335 void *context;
337 if (nlen == 0 || nlen >= CTL_MAXNAME)
338 return -ENOTDIR;
340 if (oldval)
342 int old_len;
343 if (!oldlenp)
344 return -EFAULT;
345 if(get_user(old_len, oldlenp))
346 return -EFAULT;
348 tmp = &root_table_header;
349 do {
350 context = NULL;
351 error = parse_table(name, nlen, oldval, oldlenp,
352 newval, newlen, tmp->ctl_table, &context);
353 if (context)
354 kfree(context);
355 if (error != -ENOTDIR)
356 return error;
357 tmp = tmp->DLIST_NEXT(ctl_entry);
358 } while (tmp != &root_table_header);
359 return -ENOTDIR;
362 extern asmlinkage long sys_sysctl(struct __sysctl_args *args)
364 struct __sysctl_args tmp;
365 int error;
367 if(copy_from_user(&tmp, args, sizeof(tmp)))
368 return -EFAULT;
370 lock_kernel();
371 error = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp,
372 tmp.newval, tmp.newlen);
373 unlock_kernel();
374 return error;
377 /* Like in_group_p, but testing against egid, not fsgid */
378 int in_egroup_p(gid_t grp)
380 if (grp != current->egid) {
381 int i = current->ngroups;
382 if (i) {
383 gid_t *groups = current->groups;
384 do {
385 if (*groups == grp)
386 goto out;
387 groups++;
388 i--;
389 } while (i);
391 return 0;
393 out:
394 return 1;
397 /* ctl_perm does NOT grant the superuser all rights automatically, because
398 some sysctl variables are readonly even to root. */
400 static int test_perm(int mode, int op)
402 if (!current->euid)
403 mode >>= 6;
404 else if (in_egroup_p(0))
405 mode >>= 3;
406 if ((mode & op & 0007) == op)
407 return 0;
408 return -EACCES;
411 static inline int ctl_perm(ctl_table *table, int op)
413 return test_perm(table->mode, op);
416 static int parse_table(int *name, int nlen,
417 void *oldval, size_t *oldlenp,
418 void *newval, size_t newlen,
419 ctl_table *table, void **context)
421 int error;
422 repeat:
423 if (!nlen)
424 return -ENOTDIR;
426 for ( ; table->ctl_name; table++) {
427 int n;
428 if(get_user(n,name))
429 return -EFAULT;
430 if (n == table->ctl_name ||
431 table->ctl_name == CTL_ANY) {
432 if (table->child) {
433 if (ctl_perm(table, 001))
434 return -EPERM;
435 if (table->strategy) {
436 error = table->strategy(
437 table, name, nlen,
438 oldval, oldlenp,
439 newval, newlen, context);
440 if (error)
441 return error;
443 name++;
444 nlen--;
445 table = table->child;
446 goto repeat;
448 error = do_sysctl_strategy(table, name, nlen,
449 oldval, oldlenp,
450 newval, newlen, context);
451 return error;
454 return -ENOTDIR;
457 /* Perform the actual read/write of a sysctl table entry. */
458 int do_sysctl_strategy (ctl_table *table,
459 int *name, int nlen,
460 void *oldval, size_t *oldlenp,
461 void *newval, size_t newlen, void **context)
463 int op = 0, rc, len;
465 if (oldval)
466 op |= 004;
467 if (newval)
468 op |= 002;
469 if (ctl_perm(table, op))
470 return -EPERM;
472 if (table->strategy) {
473 rc = table->strategy(table, name, nlen, oldval, oldlenp,
474 newval, newlen, context);
475 if (rc < 0)
476 return rc;
477 if (rc > 0)
478 return 0;
481 /* If there is no strategy routine, or if the strategy returns
482 * zero, proceed with automatic r/w */
483 if (table->data && table->maxlen) {
484 if (oldval && oldlenp) {
485 get_user(len, oldlenp);
486 if (len) {
487 if (len > table->maxlen)
488 len = table->maxlen;
489 if(copy_to_user(oldval, table->data, len))
490 return -EFAULT;
491 if(put_user(len, oldlenp))
492 return -EFAULT;
495 if (newval && newlen) {
496 len = newlen;
497 if (len > table->maxlen)
498 len = table->maxlen;
499 if(copy_from_user(table->data, newval, len))
500 return -EFAULT;
503 return 0;
506 struct ctl_table_header *register_sysctl_table(ctl_table * table,
507 int insert_at_head)
509 struct ctl_table_header *tmp;
510 tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
511 if (!tmp)
512 return 0;
513 *tmp = ((struct ctl_table_header) {table, DNODE_NULL});
514 if (insert_at_head)
515 DLIST_INSERT_AFTER(&root_table_header, tmp, ctl_entry);
516 else
517 DLIST_INSERT_BEFORE(&root_table_header, tmp, ctl_entry);
518 #ifdef CONFIG_PROC_FS
519 register_proc_table(table, proc_sys_root);
520 #endif
521 return tmp;
525 * Unlink and free a ctl_table.
527 void unregister_sysctl_table(struct ctl_table_header * header)
529 DLIST_DELETE(header, ctl_entry);
530 #ifdef CONFIG_PROC_FS
531 unregister_proc_table(header->ctl_table, proc_sys_root);
532 #endif
533 kfree(header);
537 * /proc/sys support
540 #ifdef CONFIG_PROC_FS
542 /* Scan the sysctl entries in table and add them all into /proc */
543 static void register_proc_table(ctl_table * table, struct proc_dir_entry *root)
545 struct proc_dir_entry *de;
546 int len;
547 mode_t mode;
549 for (; table->ctl_name; table++) {
550 /* Can't do anything without a proc name. */
551 if (!table->procname)
552 continue;
553 /* Maybe we can't do anything with it... */
554 if (!table->proc_handler && !table->child) {
555 printk(KERN_WARNING "SYSCTL: Can't register %s\n",
556 table->procname);
557 continue;
560 len = strlen(table->procname);
561 mode = table->mode;
563 de = NULL;
564 if (table->proc_handler)
565 mode |= S_IFREG;
566 else {
567 mode |= S_IFDIR;
568 for (de = root->subdir; de; de = de->next) {
569 if (proc_match(len, table->procname, de))
570 break;
572 /* If the subdir exists already, de is non-NULL */
575 if (!de) {
576 de = create_proc_entry(table->procname, mode, root);
577 if (!de)
578 continue;
579 de->data = (void *) table;
580 if (table->proc_handler)
581 de->ops = &proc_sys_inode_operations;
584 table->de = de;
585 if (de->mode & S_IFDIR)
586 register_proc_table(table->child, de);
591 * Unregister a /proc sysctl table and any subdirectories.
593 static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root)
595 struct proc_dir_entry *de;
596 for (; table->ctl_name; table++) {
597 if (!(de = table->de))
598 continue;
599 if (de->mode & S_IFDIR) {
600 if (!table->child) {
601 printk (KERN_ALERT "Help - malformed sysctl tree on free\n");
602 continue;
604 unregister_proc_table(table->child, de);
606 /* Don't unregister directories which still have entries.. */
607 if (de->subdir)
608 continue;
611 /* Don't unregister proc entries that are still being used.. */
612 if (de->count)
613 continue;
615 table->de = NULL;
616 remove_proc_entry(table->procname, root);
620 static ssize_t do_rw_proc(int write, struct file * file, char * buf,
621 size_t count, loff_t *ppos)
623 int op;
624 struct proc_dir_entry *de;
625 struct ctl_table *table;
626 size_t res;
627 ssize_t error;
629 de = (struct proc_dir_entry*) file->f_dentry->d_inode->u.generic_ip;
630 if (!de || !de->data)
631 return -ENOTDIR;
632 table = (struct ctl_table *) de->data;
633 if (!table || !table->proc_handler)
634 return -ENOTDIR;
635 op = (write ? 002 : 004);
636 if (ctl_perm(table, op))
637 return -EPERM;
639 res = count;
642 * FIXME: we need to pass on ppos to the handler.
645 error = (*table->proc_handler) (table, write, file, buf, &res);
646 if (error)
647 return error;
648 return res;
651 static ssize_t proc_readsys(struct file * file, char * buf,
652 size_t count, loff_t *ppos)
654 return do_rw_proc(0, file, buf, count, ppos);
657 static ssize_t proc_writesys(struct file * file, const char * buf,
658 size_t count, loff_t *ppos)
660 return do_rw_proc(1, file, (char *) buf, count, ppos);
663 static int proc_sys_permission(struct inode *inode, int op)
665 return test_perm(inode->i_mode, op);
668 int proc_dostring(ctl_table *table, int write, struct file *filp,
669 void *buffer, size_t *lenp)
671 int len;
672 char *p, c;
674 if (!table->data || !table->maxlen || !*lenp ||
675 (filp->f_pos && !write)) {
676 *lenp = 0;
677 return 0;
680 if (write) {
681 len = 0;
682 p = buffer;
683 while (len < *lenp) {
684 if(get_user(c, p++))
685 return -EFAULT;
686 if (c == 0 || c == '\n')
687 break;
688 len++;
690 if (len >= table->maxlen)
691 len = table->maxlen-1;
692 if(copy_from_user(table->data, buffer, len))
693 return -EFAULT;
694 ((char *) table->data)[len] = 0;
695 filp->f_pos += *lenp;
696 } else {
697 len = strlen(table->data);
698 if (len > table->maxlen)
699 len = table->maxlen;
700 if (len > *lenp)
701 len = *lenp;
702 if (len)
703 if(copy_to_user(buffer, table->data, len))
704 return -EFAULT;
705 if (len < *lenp) {
706 if(put_user('\n', ((char *) buffer) + len))
707 return -EFAULT;
708 len++;
710 *lenp = len;
711 filp->f_pos += len;
713 return 0;
717 * Special case of dostring for the UTS structure. This has locks
718 * to observe. Should this be in kernel/sys.c ????
721 static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
722 void *buffer, size_t *lenp)
724 int r;
725 down(&uts_sem);
726 r=proc_dostring(table,write,filp,buffer,lenp);
727 up(&uts_sem);
728 return r;
731 #define OP_SET 0
732 #define OP_AND 1
733 #define OP_OR 2
734 #define OP_MAX 3
735 #define OP_MIN 4
736 static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
737 void *buffer, size_t *lenp, int conv, int op)
739 int *i, vleft, first=1, len, left, neg, val;
740 #define TMPBUFLEN 20
741 char buf[TMPBUFLEN], *p;
743 if (!table->data || !table->maxlen || !*lenp ||
744 (filp->f_pos && !write)) {
745 *lenp = 0;
746 return 0;
749 i = (int *) table->data;
750 vleft = table->maxlen / sizeof(int);
751 left = *lenp;
753 for (; left && vleft--; i++, first=0) {
754 if (write) {
755 while (left) {
756 char c;
757 if(get_user(c,(char *) buffer))
758 return -EFAULT;
759 if (!isspace(c))
760 break;
761 left--;
762 ((char *) buffer)++;
764 if (!left)
765 break;
766 neg = 0;
767 len = left;
768 if (len > TMPBUFLEN-1)
769 len = TMPBUFLEN-1;
770 if(copy_from_user(buf, buffer, len))
771 return -EFAULT;
772 buf[len] = 0;
773 p = buf;
774 if (*p == '-' && left > 1) {
775 neg = 1;
776 left--, p++;
778 if (*p < '0' || *p > '9')
779 break;
780 val = simple_strtoul(p, &p, 0) * conv;
781 len = p-buf;
782 if ((len < left) && *p && !isspace(*p))
783 break;
784 if (neg)
785 val = -val;
786 buffer += len;
787 left -= len;
788 switch(op) {
789 case OP_SET: *i = val; break;
790 case OP_AND: *i &= val; break;
791 case OP_OR: *i |= val; break;
792 case OP_MAX: if(*i < val)
793 *i = val;
794 break;
795 case OP_MIN: if(*i > val)
796 *i = val;
797 break;
799 } else {
800 p = buf;
801 if (!first)
802 *p++ = '\t';
803 sprintf(p, "%d", (*i) / conv);
804 len = strlen(buf);
805 if (len > left)
806 len = left;
807 if(copy_to_user(buffer, buf, len))
808 return -EFAULT;
809 left -= len;
810 buffer += len;
814 if (!write && !first && left) {
815 if(put_user('\n', (char *) buffer))
816 return -EFAULT;
817 left--, buffer++;
819 if (write) {
820 p = (char *) buffer;
821 while (left) {
822 char c;
823 if(get_user(c, p++))
824 return -EFAULT;
825 if (!isspace(c))
826 break;
827 left--;
830 if (write && first)
831 return -EINVAL;
832 *lenp -= left;
833 filp->f_pos += *lenp;
834 return 0;
837 int proc_dointvec(ctl_table *table, int write, struct file *filp,
838 void *buffer, size_t *lenp)
840 return do_proc_dointvec(table,write,filp,buffer,lenp,1,OP_SET);
844 * init may raise the set.
847 int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
848 void *buffer, size_t *lenp)
850 return do_proc_dointvec(table,write,filp,buffer,lenp,1,
851 (current->pid == 1) ? OP_SET : OP_AND);
855 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
856 void *buffer, size_t *lenp)
858 int *i, *min, *max, vleft, first=1, len, left, neg, val;
859 #define TMPBUFLEN 20
860 char buf[TMPBUFLEN], *p;
862 if (!table->data || !table->maxlen || !*lenp ||
863 (filp->f_pos && !write)) {
864 *lenp = 0;
865 return 0;
868 i = (int *) table->data;
869 min = (int *) table->extra1;
870 max = (int *) table->extra2;
871 vleft = table->maxlen / sizeof(int);
872 left = *lenp;
874 for (; left && vleft--; i++, first=0) {
875 if (write) {
876 while (left) {
877 char c;
878 if(get_user(c, (char *) buffer))
879 return -EFAULT;
880 if (!isspace(c))
881 break;
882 left--;
883 ((char *) buffer)++;
885 if (!left)
886 break;
887 neg = 0;
888 len = left;
889 if (len > TMPBUFLEN-1)
890 len = TMPBUFLEN-1;
891 if(copy_from_user(buf, buffer, len))
892 return -EFAULT;
893 buf[len] = 0;
894 p = buf;
895 if (*p == '-' && left > 1) {
896 neg = 1;
897 left--, p++;
899 if (*p < '0' || *p > '9')
900 break;
901 val = simple_strtoul(p, &p, 0);
902 len = p-buf;
903 if ((len < left) && *p && !isspace(*p))
904 break;
905 if (neg)
906 val = -val;
907 buffer += len;
908 left -= len;
910 if (min && val < *min++)
911 continue;
912 if (max && val > *max++)
913 continue;
914 *i = val;
915 } else {
916 p = buf;
917 if (!first)
918 *p++ = '\t';
919 sprintf(p, "%d", *i);
920 len = strlen(buf);
921 if (len > left)
922 len = left;
923 if(copy_to_user(buffer, buf, len))
924 return -EFAULT;
925 left -= len;
926 buffer += len;
930 if (!write && !first && left) {
931 if(put_user('\n', (char *) buffer))
932 return -EFAULT;
933 left--, buffer++;
935 if (write) {
936 p = (char *) buffer;
937 while (left) {
938 char c;
939 if(get_user(c, p++))
940 return -EFAULT;
941 if (!isspace(c))
942 break;
943 left--;
946 if (write && first)
947 return -EINVAL;
948 *lenp -= left;
949 filp->f_pos += *lenp;
950 return 0;
955 * an unsigned long function version
958 static int do_proc_doulongvec_minmax(ctl_table *table, int write,
959 struct file *filp,
960 void *buffer, size_t *lenp,
961 unsigned long convmul,
962 unsigned long convdiv)
964 #define TMPBUFLEN 20
965 unsigned long *i, *min, *max, val;
966 int vleft, first=1, len, left, neg;
967 char buf[TMPBUFLEN], *p;
969 if (!table->data || !table->maxlen || !*lenp ||
970 (filp->f_pos && !write)) {
971 *lenp = 0;
972 return 0;
975 i = (unsigned long *) table->data;
976 min = (unsigned long *) table->extra1;
977 max = (unsigned long *) table->extra2;
978 vleft = table->maxlen / sizeof(unsigned long);
979 left = *lenp;
981 for (; left && vleft--; i++, first=0) {
982 if (write) {
983 while (left) {
984 char c;
985 if(get_user(c, (char *) buffer))
986 return -EFAULT;
987 if (!isspace(c))
988 break;
989 left--;
990 ((char *) buffer)++;
992 if (!left)
993 break;
994 neg = 0;
995 len = left;
996 if (len > TMPBUFLEN-1)
997 len = TMPBUFLEN-1;
998 if(copy_from_user(buf, buffer, len))
999 return -EFAULT;
1000 buf[len] = 0;
1001 p = buf;
1002 if (*p == '-' && left > 1) {
1003 neg = 1;
1004 left--, p++;
1006 if (*p < '0' || *p > '9')
1007 break;
1008 val = simple_strtoul(p, &p, 0) * convmul / convdiv ;
1009 len = p-buf;
1010 if ((len < left) && *p && !isspace(*p))
1011 break;
1012 if (neg)
1013 val = -val;
1014 buffer += len;
1015 left -= len;
1017 if(neg)
1018 continue;
1019 if (min && val < *min++)
1020 continue;
1021 if (max && val > *max++)
1022 continue;
1023 *i = val;
1024 } else {
1025 p = buf;
1026 if (!first)
1027 *p++ = '\t';
1028 sprintf(p, "%lu", convdiv * (*i) / convmul);
1029 len = strlen(buf);
1030 if (len > left)
1031 len = left;
1032 if(copy_to_user(buffer, buf, len))
1033 return -EFAULT;
1034 left -= len;
1035 buffer += len;
1039 if (!write && !first && left) {
1040 if(put_user('\n', (char *) buffer))
1041 return -EFAULT;
1042 left--, buffer++;
1044 if (write) {
1045 p = (char *) buffer;
1046 while (left) {
1047 char c;
1048 if(get_user(c, p++))
1049 return -EFAULT;
1050 if (!isspace(c))
1051 break;
1052 left--;
1055 if (write && first)
1056 return -EINVAL;
1057 *lenp -= left;
1058 filp->f_pos += *lenp;
1059 return 0;
1060 #undef TMPBUFLEN
1063 int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
1064 void *buffer, size_t *lenp)
1066 return do_proc_doulongvec_minmax(table, write, filp, buffer, lenp, 1l, 1l);
1069 int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
1070 struct file *filp,
1071 void *buffer, size_t *lenp)
1073 return do_proc_doulongvec_minmax(table, write, filp, buffer,
1074 lenp, HZ, 1000l);
1078 /* Like proc_dointvec, but converts seconds to jiffies */
1079 int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1080 void *buffer, size_t *lenp)
1082 return do_proc_dointvec(table,write,filp,buffer,lenp,HZ,OP_SET);
1085 #else /* CONFIG_PROC_FS */
1087 int proc_dostring(ctl_table *table, int write, struct file *filp,
1088 void *buffer, size_t *lenp)
1090 return -ENOSYS;
1093 static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
1094 void *buffer, size_t *lenp)
1096 return -ENOSYS;
1099 int proc_dointvec(ctl_table *table, int write, struct file *filp,
1100 void *buffer, size_t *lenp)
1102 return -ENOSYS;
1105 int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
1106 void *buffer, size_t *lenp)
1108 return -ENOSYS;
1111 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
1112 void *buffer, size_t *lenp)
1114 return -ENOSYS;
1117 int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1118 void *buffer, size_t *lenp)
1120 return -ENOSYS;
1123 int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
1124 void *buffer, size_t *lenp)
1126 return -ENOSYS;
1129 int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
1130 struct file *filp,
1131 void *buffer, size_t *lenp)
1133 return -ENOSYS;
1137 #endif /* CONFIG_PROC_FS */
1141 * General sysctl support routines
1144 /* The generic string strategy routine: */
1145 int sysctl_string(ctl_table *table, int *name, int nlen,
1146 void *oldval, size_t *oldlenp,
1147 void *newval, size_t newlen, void **context)
1149 int l, len;
1151 if (!table->data || !table->maxlen)
1152 return -ENOTDIR;
1154 if (oldval && oldlenp) {
1155 if(get_user(len, oldlenp))
1156 return -EFAULT;
1157 if (len) {
1158 l = strlen(table->data);
1159 if (len > l) len = l;
1160 if (len >= table->maxlen)
1161 len = table->maxlen;
1162 if(copy_to_user(oldval, table->data, len))
1163 return -EFAULT;
1164 if(put_user(0, ((char *) oldval) + len))
1165 return -EFAULT;
1166 if(put_user(len, oldlenp))
1167 return -EFAULT;
1170 if (newval && newlen) {
1171 len = newlen;
1172 if (len > table->maxlen)
1173 len = table->maxlen;
1174 if(copy_from_user(table->data, newval, len))
1175 return -EFAULT;
1176 if (len == table->maxlen)
1177 len--;
1178 ((char *) table->data)[len] = 0;
1180 return 0;
1184 * This function makes sure that all of the integers in the vector
1185 * are between the minimum and maximum values given in the arrays
1186 * table->extra1 and table->extra2, respectively.
1188 int sysctl_intvec(ctl_table *table, int *name, int nlen,
1189 void *oldval, size_t *oldlenp,
1190 void *newval, size_t newlen, void **context)
1192 int i, length, *vec, *min, *max;
1194 if (newval && newlen) {
1195 if (newlen % sizeof(int) != 0)
1196 return -EINVAL;
1198 if (!table->extra1 && !table->extra2)
1199 return 0;
1201 if (newlen > table->maxlen)
1202 newlen = table->maxlen;
1203 length = newlen / sizeof(int);
1205 vec = (int *) newval;
1206 min = (int *) table->extra1;
1207 max = (int *) table->extra2;
1209 for (i = 0; i < length; i++) {
1210 int value;
1211 get_user(value, vec + i);
1212 if (min && value < min[i])
1213 return -EINVAL;
1214 if (max && value > max[i])
1215 return -EINVAL;
1218 return 0;
1221 /* Strategy function to convert jiffies to seconds */
1222 int sysctl_jiffies(ctl_table *table, int *name, int nlen,
1223 void *oldval, size_t *oldlenp,
1224 void *newval, size_t newlen, void **context)
1226 if (oldval) {
1227 size_t olen;
1228 if (oldlenp) {
1229 if (get_user(olen, oldlenp))
1230 return -EFAULT;
1231 if (olen!=sizeof(int))
1232 return -EINVAL;
1234 if (put_user(*(int *)(table->data) / HZ, (int *)oldval) ||
1235 (oldlenp && put_user(sizeof(int),oldlenp)))
1236 return -EFAULT;
1238 if (newval && newlen) {
1239 int new;
1240 if (newlen != sizeof(int))
1241 return -EINVAL;
1242 if (get_user(new, (int *)newval))
1243 return -EFAULT;
1244 *(int *)(table->data) = new*HZ;
1246 return 1;
1249 int do_string (
1250 void *oldval, size_t *oldlenp, void *newval, size_t newlen,
1251 int rdwr, char *data, size_t max)
1253 int l = strlen(data) + 1;
1254 if (newval && !rdwr)
1255 return -EPERM;
1256 if (newval && newlen >= max)
1257 return -EINVAL;
1258 if (oldval) {
1259 int old_l;
1260 if(get_user(old_l, oldlenp))
1261 return -EFAULT;
1262 if (l > old_l)
1263 return -ENOMEM;
1264 if(put_user(l, oldlenp) || copy_to_user(oldval, data, l))
1265 return -EFAULT;
1267 if (newval) {
1268 if(copy_from_user(data, newval, newlen))
1269 return -EFAULT;
1270 data[newlen] = 0;
1272 return 0;
1275 int do_int (
1276 void *oldval, size_t *oldlenp, void *newval, size_t newlen,
1277 int rdwr, int *data)
1279 if (newval && !rdwr)
1280 return -EPERM;
1281 if (newval && newlen != sizeof(int))
1282 return -EINVAL;
1283 if (oldval) {
1284 int old_l;
1285 if(get_user(old_l, oldlenp))
1286 return -EFAULT;
1287 if (old_l < sizeof(int))
1288 return -ENOMEM;
1289 if(put_user(sizeof(int), oldlenp)||copy_to_user(oldval, data, sizeof(int)))
1290 return -EFAULT;
1292 if (newval)
1293 if(copy_from_user(data, newval, sizeof(int)))
1294 return -EFAULT;
1295 return 0;
1298 int do_struct (
1299 void *oldval, size_t *oldlenp, void *newval, size_t newlen,
1300 int rdwr, void *data, size_t len)
1302 if (newval && !rdwr)
1303 return -EPERM;
1304 if (newval && newlen != len)
1305 return -EINVAL;
1306 if (oldval) {
1307 int old_l;
1308 if(get_user(old_l, oldlenp))
1309 return -EFAULT;
1310 if (old_l < len)
1311 return -ENOMEM;
1312 if(put_user(len, oldlenp) || copy_to_user(oldval, data, len))
1313 return -EFAULT;
1315 if (newval)
1316 if(copy_from_user(data, newval, len))
1317 return -EFAULT;
1318 return 0;
1322 #else /* CONFIG_SYSCTL */
1325 extern asmlinkage long sys_sysctl(struct __sysctl_args *args)
1327 return -ENOSYS;
1330 int sysctl_string(ctl_table *table, int *name, int nlen,
1331 void *oldval, size_t *oldlenp,
1332 void *newval, size_t newlen, void **context)
1334 return -ENOSYS;
1337 int sysctl_intvec(ctl_table *table, int *name, int nlen,
1338 void *oldval, size_t *oldlenp,
1339 void *newval, size_t newlen, void **context)
1341 return -ENOSYS;
1344 int proc_dostring(ctl_table *table, int write, struct file *filp,
1345 void *buffer, size_t *lenp)
1347 return -ENOSYS;
1350 int proc_dointvec(ctl_table *table, int write, struct file *filp,
1351 void *buffer, size_t *lenp)
1353 return -ENOSYS;
1356 int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
1357 void *buffer, size_t *lenp)
1359 return -ENOSYS;
1362 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
1363 void *buffer, size_t *lenp)
1365 return -ENOSYS;
1368 int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1369 void *buffer, size_t *lenp)
1371 return -ENOSYS;
1374 int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
1375 void *buffer, size_t *lenp)
1377 return -ENOSYS;
1380 int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
1381 struct file *filp,
1382 void *buffer, size_t *lenp)
1384 return -ENOSYS;
1387 struct ctl_table_header * register_sysctl_table(ctl_table * table,
1388 int insert_at_head)
1390 return 0;
1393 void unregister_sysctl_table(struct ctl_table_header * table)
1397 #endif /* CONFIG_SYSCTL */